Files
Rozpisky/Rozpisky/Dxf/KodPrilohy.cs
T
marekandClaude Opus 5 a6377ab583 Baseline: současný stav projektu Rozpisky
První commit — WPF aplikace pro generování výkresových rohových razítek
(.NET 10, SkiaSharp, ACadSharp, ClosedXML) včetně xUnit testů, DXF šablony,
log a dokumentace. Build výstupy (bin/, obj/, .vs/) jsou ignorovány.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 09:45:49 +02:00

132 lines
8.0 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Text;
using Rozpisky.Models;
namespace Rozpisky.Dxf;
/// <summary>
/// Generátor strojově čitelného <b>47-pozičního kódu</b> přílohy („kód pod rozpiskou", manuál SŽ
/// kap. 3.1.5 a 3.2.13.2.8). Kód má pevnou délku 47 znaků složenou ze 6 skupin oddělených znakem
/// <c>_</c> na pevných pozicích. Skládá se ze strukturovaných polí přílohy a projektu; každá pozice,
/// pro kterou není podklad, se vyplní znakem <c>X</c> žádná pozice nezůstává prázdná.
/// <para>Rozložení (1-based pozice → obsah):</para>
/// <list type="bullet">
/// <item>111 Označení investora (S-kód), 12 = <c>_</c></item>
/// <item>1316 Stupeň dokumentace, 17 = <c>_</c></item>
/// <item>1821 Část (CAST) + řada = číslice z dílčí části (DILCI_CAST bez písmen a teček);
/// např. CAST <c>B</c> + DILCI_CAST <c>B.7</c> → <c>B7</c>, CAST <c>D</c> + <c>D110</c> → <c>D110</c>, 22 = <c>_</c></item>
/// <item>2324 předpona objektu (SO/PS) + 2531 číslo objektu (řada+úsek+řazení), 32 = <c>_</c></item>
/// <item>3334 podobjekt, 35 = <c>_</c></item>
/// <item>3637 typ přílohy (D1…), 38 = <c>_</c>, 39 část přílohy, 40 = <c>_</c></item>
/// <item>4143 číslo přílohy, 44 = <c>_</c></item>
/// <item>45 typ revize (P/0/V) + 4647 pořadí revize</item>
/// </list>
/// Sdružené objekty (SK/PK, kap. 3.3) a další okrajové případy zatím nejsou řešené kód se skládá
/// přímočaře z dostupných hodnot.
/// </summary>
public static class KodPrilohy
{
/// <summary>Pevná délka kódu (počet pozic / buněk K1K47).</summary>
public const int Delka = 47;
private const char Vypln = 'X';
/// <summary>Sestaví 47-znakový kód přílohy z údajů projektu a řádku přílohy.</summary>
public static string Sestav(Projekt p, Priloha r)
{
var obj = ObjektOznaceni.Rozpad(r.CisloObjektu);
var (revTyp, revCislo) = RozpadRevize(r.R1);
var sb = new StringBuilder(Delka);
Pole(sb, p.Skod, 11); // 111 investor / S-kód
sb.Append('_'); // 12
Pole(sb, p.StupenDokumentace, 4); // 1316 stupeň dokumentace
sb.Append('_'); // 17
Pole(sb, ObjektOznaceni.Alfanum(r.OznaceniCasti) + Cislice(r.OznaceniDilciCasti), 4); // 1821 část (CAST) + řada z DILCI_CAST bez písmen/teček
sb.Append('_'); // 22
Pole(sb, obj.Prefix, 2); // 2324 SO/PS
Pole(sb, obj.Cislo + obj.Usek + obj.Razeni, 7); // 2531 číslo objektu
sb.Append('_'); // 32
Pole(sb, obj.Podobjekt, 2); // 3334 podobjekt
sb.Append('_'); // 35
Pole(sb, ObjektOznaceni.Alfanum(r.TypPrilohy), 2); // 3637 typ přílohy (D1…)
sb.Append('_'); // 38
Pole(sb, r.DilciPriloha, 1); // 39 část přílohy
sb.Append('_'); // 40
Pole(sb, r.PoradiPrilohy, 3); // 4143 číslo přílohy
sb.Append('_'); // 44
sb.Append(revTyp); // 45 typ revize
Pole(sb, revCislo, 2); // 4647 pořadí revize
return sb.ToString();
}
/// <summary>Kód „seznamu příloh“ objektu (manuál SŽ kap. 5.1.11): pozice 134 jsou shodné s kódem
/// rozpisky objektu (S-kód, stupeň, část/řada, objekt, podobjekt), pozice 3543 nahrazeny pevně
/// <c>_XX_X_001</c> (seznam = „příloha 001“ bez typu/dokumentu) a zbytek (4447) je revize.
/// <paramref name="reprezentant"/> = libovolná příloha objektu (pozice 134 jsou objektové).
/// <paramref name="revizeKod"/> = zvolená revize seznamu (např. „V00“); null → revize z reprezentanta.</summary>
public static string SestavSeznam(Projekt p, Priloha reprezentant, string? revizeKod = null)
=> SestavObjektovy(p, reprezentant, "_XX_X_001", revizeKod);
/// <summary>Kód „rozpisky na spisové desky objektu“ (manuál SŽ): pozice 134 shodné s kódem
/// rozpisky objektu, pozice 3543 nahrazeny pevně <c>_XX_X_000</c> (desky = „příloha 000“ bez
/// typu/dokumentu) a zbytek (4447) je revize. Shoduje se s názvem souboru/rozvržení desek
/// (<c>objekt_[podobjekt]_XX_X_000</c>, viz <see cref="Models.Priloha.JmenoRozvrzeniAuto"/>)
/// typ <c>XX</c> je literální placeholder a zůstává v obou.
/// <paramref name="reprezentant"/> = libovolná příloha objektu; <paramref name="revizeKod"/> =
/// zvolená revize, null → revize z reprezentanta.</summary>
public static string SestavDesky(Projekt p, Priloha reprezentant, string? revizeKod = null)
=> SestavObjektovy(p, reprezentant, "_XX_X_000", revizeKod);
/// <summary>Sdílený základ objektových kódů (seznam/desky): vezme 47-znakový kód reprezentanta
/// (pozice 134 = objektové, 4447 = revize) a nahradí prostřední segment 3543 hodnotou
/// <paramref name="stred"/> (např. <c>_XX_X_001</c> / <c>_XX_X_000</c>). <paramref name="revizeKod"/>
/// null → revize zůstane z reprezentanta, jinak se přepočítá přes <see cref="RozpadRevize"/>.</summary>
private static string SestavObjektovy(Projekt p, Priloha reprezentant, string stred, string? revizeKod)
{
var full = Sestav(p, reprezentant); // 47 znaků (revize z reprezentanta)
if (revizeKod is null)
return full[..34] + stred + full[43..]; // 134 | stred | 4447 revize
var (typ, cislo) = RozpadRevize(revizeKod);
var sb = new StringBuilder(full[..34]); // 134
sb.Append(stred); // 3543
sb.Append('_'); // 44
sb.Append(typ); // 45
Pole(sb, cislo, 2); // 4647
return sb.ToString();
}
/// <summary>Ponechá jen číslice (zahodí písmena, tečky i další znaky) použití pro řadu z pole
/// DILCI_CAST do kódu K18K21: <c>B.7</c> → <c>7</c>, <c>D110</c> → <c>110</c>.</summary>
private static string Cislice(string? s)
=> string.IsNullOrEmpty(s) ? "" : new string(s.Where(char.IsDigit).ToArray());
/// <summary>Vloží hodnotu do pole pevné šířky: ořízne přebytek, chybějící pozice doplní <c>X</c>.</summary>
private static void Pole(StringBuilder sb, string? hodnota, int sirka)
{
var s = (hodnota ?? "").Trim();
if (s.Length > sirka) s = s[..sirka];
sb.Append(s);
for (int i = s.Length; i < sirka; i++) sb.Append(Vypln);
}
/// <summary>Z kódu revize (např. <c>R1</c>) odvodí typ verze (P/0/V) a její pořadí.
/// První znak je typ, zbytek je číslo revize. Bez revize → <c>X</c> a prázdné číslo.
/// Např. <c>V00</c> → (<c>V</c>, <c>00</c>), <c>002</c> → (<c>0</c>, <c>02</c>).</summary>
private static (char Typ, string Cislo) RozpadRevize(string? revKod)
{
string rev = (revKod ?? "").Trim();
if (rev.Length == 0) return (Vypln, "");
char typ = rev[0] switch
{
'P' or 'V' or '0' => rev[0],
_ when char.IsDigit(rev[0]) => '0',
_ => char.ToUpperInvariant(rev[0]),
};
// Číslo revize = číslice ZA typovým znakem (vedoucí znak je typ, ne součást čísla).
string cislo = new string(rev.Skip(1).Where(char.IsDigit).ToArray());
return (typ, cislo);
}
}