Restrukturalizace složky podle účelu podkladů

Kořen mísil tři nesouvisející věci. Nově:
- docs/            – podklady jen pro tvorbu programu (ROZPISKY, ROZHRANI,
                     PODKLAD_CAD, manuál SŽ v .md)
- Rozpisky/Podklady/ – podklady nutné k běhu, dodávané vedle .exe
                     (Rozpiska.dxf, SEZNAM.xlsx, manuál .pdf, ciselniky.json,
                     mapovani.json, loga/)
- vzorky/          – cizí vstupy pro ruční zkoušení (schema.dxf)

Mění se jen zdrojový strom. Rozvržení vedle .exe zůstává ploché (+ loga\)
přes metadata Link v .csproj, takže všechny resolvery nad AppContext.BaseDirectory
fungují beze změny. Konec odkazů přes ..\ ven z projektu.

Doprovodně: cesty v TestData.Logo, odkazy v dokumentaci, CLAUDE.md a v promptech
subagentů.

Build 0 chyb / 0 varování, 36 testů zelených.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-07 10:35:50 +02:00
co-authored by Claude Opus 5
parent d733d7dd6b
commit d4eb3f2102
25 changed files with 60 additions and 44 deletions
+224
View File
@@ -0,0 +1,224 @@
# Podklad: Práce s CADem, rozvržení a tisk
> Výcuc funkcionality (bez kódu) pro převod VBA verze 1.0.8 do C#.
> Zaměřeno **čistě na práci s CADem, rozvržení (layouty) a tisk** bez rozpisek.
> Popisuje funkcionalitu + použité ActiveX/COM API, které se bude převádět.
---
## 1. Připojení na CAD (`clsCadLink`)
Centrální objekt pro veškerou komunikaci s CADem. Vše ostatní jde přes něj (`cad.Doc.*`).
**Funkcionalita:**
- **Late-binding** přes `GetObject(, ProgID)` připojuje se POUZE na **již běžící** CAD, nic nespouští.
- Zkouší v pořadí: `AutoCAD.Application``ZWCAD.Application``BricscadApp.AcadApplication`. První, který běží, vyhraje.
- Po napojení na aplikaci si vezme `mApp.ActiveDocument`. Když CAD běží, ale není otevřený výkres → chyba.
- Drží: `App` (aplikace), `Doc` (aktivní dokument), `Engine` (který ProgID se chytil), `LastError`, `IsConnected`.
**Pomocné metody nad dokumentem (volitelné, používá je generování):**
- `CheckLayer(name)` → existuje hladina? (`Doc.Layers(name)`)
- `AddLayer(name, color, lineWeight)``Doc.Layers.Add`
- `CheckBlock(name)` → existuje definice bloku? (`Doc.Blocks(name)`)
- `AddBlock(path)` → vloží blok ze souboru do ModelSpace (`InsertBlock`) jen kvůli načtení definice a hned referenci smaže.
**Pro C#:** V .NET přes COM Interop (`Marshal.GetActiveObject("AutoCAD.Application")`) nebo silně typované `Autodesk.AutoCAD.Interop` (`AcadApplication`, `AcadDocument`). Pozor `GetActiveObject` je v moderním .NET potřeba volat ručně přes `Marshal`. Pořadí ProgID zachovej jako fallback řetězec.
---
## 2. Datové nosiče (čtení dat z Excelu, bez CADu)
### `Layout` (data jednoho rozvržení)
Načítá řádek z listu **SEZNAM** + pojmenovanou buňku `stavba`. Drží metadata jednoho výkresu:
- `JmenoZakazka` (z named range `stavba`), `JmenoObjekt`, `JmenoRozvrzeni` (= název layoutu, sl. 28), `NazevPrilohy`, `MeritkoPrilohy` (sl. 23), `PocetPapiru`, `Ctb` (název CTB stylu, sl. 30).
- `InicializaceDat(radek)` načte tyto hodnoty z konkrétního řádku.
- Spojování hodnot oddělovačem (název + dílčí část) přes pomocnou funkci.
### `NastaveniTiskarny` (držák tiskových hodnot)
Defaultní hodnoty tisku převedené z ActiveX konstant na **číselné literály** (kvůli late-bindingu):
- `Tiskarna` = `"DWG to PDF.pc5"`, `StyleSheet` = `"zwcad.ctb"`
- `PaperUnits = 1` (mm), `PlotRotation = 0`, `PlotType = 5` (Layout), `StandardScale = 16` (ac1_1, tj. 1:1 pozor, AcPlotScale je enum, hodnota 1 by byla ac1_128in_1ft = 1:1536), `PlotViewportFirst = True`, `PlotOrigin = (0,0)`.
- `NastavRozmerPapiru(sirka, vyska)` → sestaví `CanonicalMediaName` jako `"420x297"` (z reálných rozměrů rámečku).
**Pro C#:** Tohle jsou jednoduché DTO/POCO třídy. V C# můžeš vrátit silně typované enumy (`AcPlotType.acLayout` atd.) místo magických čísel, ale zachovej mapování:
| Konstanta | Hodnota | Význam |
|---|---|---|
| PaperUnits mm | 1 | acMillimeters |
| Rotation 0° | 0 | ac0degrees |
| PlotType Layout | 5 | acLayout |
| PlotType Window | 4 | acWindow |
| Scale 1:1 | 1 | ac1_1 |
| Scale ToFit | 0 | acScaleToFit |
---
## 3. Konfigurace tiskárny a papíru (`modPlotConfig`)
**Funkcionalita:**
- **Cache do skrytého listu `_Plot`** (xlSheetVeryHidden): ukládá poslední zvolenou tiskárnu (`ConfigName`, B1) a papír (`MediaName`, B2). Při portu nahradíš nějakým config souborem / settings.
- **`TiskarnyZCad(cad)`** → seznam dostupných tiskáren: `cad.Doc.ActiveLayout.GetPlotDeviceNames`.
- **`PapiryZCad(cad, device)`** → seznam papírů pro danou tiskárnu. Trik: vytvoří dočasnou plot konfiguraci `Doc.PlotConfigurations.Add("__tmpQ", True)`, nastaví `configName = device`, zavolá `RefreshPlotDeviceInfo`, načte `GetCanonicalMediaNames` a dočasnou konfiguraci zase smaže.
- **`OveritKonfiguraci(...)`** → před tiskem ověří, že uložená tiskárna i papír reálně existují v aktuálním CADu (stejnou technikou). Vrací popis chyby.
- **`ZobrazPlotConfig`** → modální formulář pro výběr (UI nahradíš WinForms/WPF dialogem).
**Klíčové API:** `Layout.GetPlotDeviceNames`, `PlotConfigurations.Add/Item/Delete`, `PlotConfiguration.configName`, `.RefreshPlotDeviceInfo`, `.GetCanonicalMediaNames`.
---
## 4. Aktualizace / úprava rozvržení (`modAktualizace`) — JÁDRO
Hlavní procedura `TestAktualizace`. Podle vybraného rozsahu řádků na listu SEZNAM upraví odpovídající layouty ve výkresu.
**Tok funkcionality:**
1. **Ochranné podmínky:** musí běžet na listu SEZNAM, výběr musí začínat řádkem ≥ 2.
2. Načte pole `Layout` objektů z vybraných řádků.
3. Připojí se na CAD (`clsCadLink`).
4. **Sestaví seznam všech layoutů** ve výkresu (`Doc.Layouts`), pro každý `Name` a `TabOrder`, a **seřadí podle TabOrder** (bubble sort). Pozn.: `Layouts.Count - 1` = počet rozvržení bez modelového prostoru.
5. **Kontroly počtu:** rozsah nesmí být větší než počet layoutů ani než počet zbývajících layoutů od aktivního.
6. **Aktivní layout nesmí být "Model"** jinak vyzve uživatele aby aktivoval rozvržení. Začíná se od `ActiveLayout.TabOrder`.
7. **Dvoufázové přejmenování (kvůli konfliktům jmen):** nejdřív přejmenuje cílové layouty na **dočasné náhodné názvy** (`GenerateSecureAlphaNumeric(15) & i`), aby se předešlo kolizi při finálním přejmenování.
8. **Hlavní smyčka** přes layouty podle TabOrder (s progress formulářem + možnost zrušit):
- Přejmenuje layout na cílový `JmenoRozvrzeni` (chráněno error handlerem).
- **Automatické vyhodnocení měřítka** (pokud zapnuto named range `MERITKOAUTOMATICKY`) viz níže.
- **Projde všechny entity v `Layout.Block`** a hledá blokové reference (`blk.ObjectName = "AcDbBlockReference"`):
- **Blok `vykres_hlavicka`** → pokud `HasAttributes`, projde `GetAttributes` a podle `TagString` zapíše hodnoty: `STAVBA`, `OBJEKT`, `PRILOHA`, `MERITKO` (formátuje jako `"M 1:500"` jen když obsahuje `"1:"`). Po změně `TextString` zavolá `AttList(k).Update`.
- **Blok `ramecek`** → pokud je dynamický (`IsDynamicBlock`), `GetBoundingBox Poc, Kon` → z rozměrů spočítá **počet papírů**: `delka = RoundUp(Kon(0)/210)`, `vyska = RoundUp(Kon(1)/297)`, `PocetPapiru = delka*vyska`, a nastaví formát papíru (`NastavRozmerPapiru`).
- **Nastavení tiskárny na layout** (pokud zapnuto named range `NASTAVENITISKARNY = 1`): zapíše do layoutu `ConfigName, CanonicalMediaName, PaperUnits, PlotOrigin, PlotRotation, PlotType, StandardScale, PlotViewportsFirst, StyleSheet`. Pokud je vyplněn vlastní CTB, použije `Ctb & ".ctb"`.
9. **Zápis zpět do Excelu:** počet papírů (sl. 24) a měřítka (sl. 23) zpět do listu SEZNAM.
### Vyhodnocení měřítka z výřezů (`VyhodnotMeritka`)
- Projde entity layoutu a hledá **viewporty** (`ObjectName = "AcDbViewport"`) v hladině **`!!NOPRINT`**.
- Z `viewport.CustomScale` spočítá jmenovatel měřítka: `jmenovatel = Round((1/CustomScale) * jednotkyFaktor)`.
- `jednotkyFaktor` podle systémové proměnné `INSUNITS` (`Doc.GetVariable("INSUNITS")`): 4 = mm (1), 6 = m (1000).
- Sesbírá unikátní měřítka, seřadí vzestupně, vrátí např. `"1:500, 1:1000"`.
- **Pozor (zjištěno při portu):** blok layoutu obsahuje kromě nakreslených výřezů i neviditelný
pseudoviewport „pohledu na papír“ (DXF VIEWPORT id 1; vzniká při aktivaci layoutu a kopíruje se
s layoutem, může ležet i v hladině `!!NOPRINT` a kdekoliv v pořadí bloku). Jeho `CustomScale`
je aktuální zoom → falešná měřítka (u výkresů v metrech typicky 1:1000). Jednoznačná identifikace:
aktivovat layout, vypnout `MSpace` a přečíst `Doc.ActivePViewport.Handle` to je on (ověřeno na
AutoCADu). Nouzová heuristika bez aktivace: pseudoviewport má `StandardScale = 2` (`acVp1_1`)
trvale zamrzlé; skutečné výřezy s měřítkem ze seznamu mají `1` (`acVpCustomScale`) heuristika
by ale zahodila i skutečný výřez nastavený přes enum na 1:1.
**Pro C# nejdůležitější API této části:**
- `Doc.Layouts` (kolekce), `Layout.Name`, `.TabOrder`, `.Block` (iterace entit).
- Entita: `.ObjectName` (`"AcDbBlockReference"`, `"AcDbViewport"`), `.Name`, `.IsDynamicBlock`, `.HasAttributes`, `.GetAttributes()`, `.GetBoundingBox(out min, out max)`, `.Layer`, `.CustomScale`.
- Atribut: `.TagString`, `.TextString`, `.Update()`.
- Layout plot props: `.ConfigName, .CanonicalMediaName, .PaperUnits, .PlotOrigin, .PlotRotation, .PlotType, .StandardScale, .PlotViewportsFirst, .StyleSheet`.
- `Doc.GetVariable("INSUNITS")`.
- **Pozor na late-bound rozdíl:** ve verzi 1.0.7 (ZWCAD) se typ poznával přes `TypeName(x)="IZcadBlockReference"`. Tady se to dělá robustněji přes `x.ObjectName`. V C# se silně typovaným interopem můžeš použít `is AcadBlockReference` / `is AcadPViewport`, ale `ObjectName` je univerzálnější napříč enginy.
---
## 5. Tisk rozvržení do PDF (`modTiskPriloh`)
`TiskPrilohyDoPdf` hromadný tisk vybraných layoutů do PDF souborů.
**Tok:**
1. Ochranné podmínky (list SEZNAM, řádek ≥ 2), připojení CAD.
2. **Připraví cílovou složku** exportu.
3. Sestaví seznam názvů layoutů k tisku (sl. 28), prázdné přeskočí.
4. **Zazálohuje a přenastaví systémové proměnné** výkresu:
- `BACKGROUNDPLOT` → 0 (tisk na popředí = čeká se na dokončení důležité pro spolehlivost!).
- `PLOTTRANSPARENCYOVERRIDE` → 2 (ignorovat průhlednost).
- `LTSCALE` ukládá originál, volitelně přenastaví dle named range `LTSCALE` a hodnoty z buňky (sl. 29) per řádek (s validací: prázdné/nečíselné/≤0 → 1).
5. **Smyčka tisku** (progress + cancel):
- Cesta PDF = `složka & nazev & ".pdf"`.
- **Kontrola, zda PDF není otevřené** (`IsFileOpen`) → dialog Abort/Retry/Ignore.
- Najde layout `Doc.Layouts(nazev)`, neexistuje → přeskočí.
- Nastaví LTSCALE.
- **Aktivuje layout** (`Doc.ActiveLayout = Layout`) a **vytiskne** (`Doc.Plot.PlotToFile cesta`).
- Error handling per soubor, počítá vytisknuto/přeskočeno.
6. **Obnoví** původní systémové proměnné.
**Klíčové API:** `Doc.GetVariable/SetVariable`, `Doc.Layouts(name)`, `Doc.ActiveLayout = layout`, `Doc.Plot.PlotToFile(path)`.
---
## 6. Tisk bloku oknem (`modPrint`)
Dvě varianty tisku jednotlivého bloku podle jeho bounding boxu (window plot):
- **`VytiskniRozpisku`** → `Doc.Plot.PlotToDevice` (na zařízení).
- **`VytiskniRozpiskuDoSouboru`** → `Doc.Plot.PlotToFile(cesta)` (do souboru, nastaví `BACKGROUNDPLOT=0`).
**Postup nastavení layoutu pro window-plot:**
1. `blk.GetBoundingBox(min, max)` → rohy okna.
2. Na `ActiveLayout`: `ConfigName`, `RefreshPlotDeviceInfo`, `CanonicalMediaName`, `PlotRotation = 0`, `PlotType = 4` (acWindow), `SetWindowToPlot(ll, ur)`, `CenterPlot = True`, `UseStandardScale = True`, `StandardScale = 0` (acScaleToFit), `PlotWithPlotStyles = True`, `StyleSheet = ""`, `PlotViewportBorders = False`, `PlotHidden = False`.
3. Tisk.
**Pro C#:** `SetWindowToPlot` bere dvě 2-prvková `double[]` pole (lower-left, upper-right). Pozor na předávání polí přes COM (varianty).
---
## 7. Čtení dat / atributů z CADu
### Vyhledání bloků v ModelSpace (`modRozpisky.NajdiRozpisky`)
Obecný vzor procházení výkresu (použitelný i mimo rozpisky):
- `cad.Doc.ModelSpace` → iterace `For Each ent In ms`.
- Filtr: `ent.ObjectName = "AcDbBlockReference"` a porovnání názvu.
- **Název bloku včetně dynamických:** zkusí `EffectiveName`, fallback `Name` (`NazevBloku`).
- Čte `insertionPoint` (pole `[x,y,z]`), filtruje X > 0, sbírá do kolekce.
- **Seřazení podle X** (index sort) vzestupně.
- Progress každých 50 entit + možnost zrušit (vyhozením vlastní chyby `vbObjectError + 100`).
### Výpis atributů (`modVypisAtributu`)
Diagnostika pro daný blok:
- `blk.insertionPoint`.
- `blk.HasAttributes``blk.GetAttributes` (proměnné/vyplnitelné) → `TagString` + `TextString`.
- `blk.GetConstantAttributes` (konstantní, jen pro info).
**Klíčové API:** `Doc.ModelSpace` (iterovatelná kolekce), `entity.ObjectName`, `.EffectiveName/.Name`, `.InsertionPoint`, `.HasAttributes`, `.GetAttributes()`, `.GetConstantAttributes()`.
---
## 8. Pomocné funkce (`Funkce`) — bez CADu
- `TurnOffStuff` / `TurnOnStuff` vypnutí/zapnutí přepočtu, událostí, překreslování Excelu (zrychlení). V C# přes Excel interop nebo to vynecháš.
- `VratZnakNeboX` ořez/doplnění textu na pevnou délku.
- `GetValueFromTable` vyhledávání v Excel ListObject tabulce dle klíče (jako VLOOKUP).
- **`IsFileOpen`** zjistí, zda je soubor zamčený jiným procesem (otevře `Binary Access Read Lock Read`, chyba 70 = otevřeno). V C# → `try` na `FileStream` s `FileShare.None`.
- **`VybratCestuKeSlozce`** dialog výběru složky. V C# → `FolderBrowserDialog`/`OpenFolderDialog`.
---
## 9. Poznámky pro převod do C#
1. **Late-binding → typed interop:** VBA tu používá `As Object` + late-binding kvůli podpoře více CADů (AutoCAD/ZWCAD/BricsCAD). V C# zvážit: buď `dynamic` (zachová multi-engine flexibilitu), nebo `Autodesk.AutoCAD.Interop` (typová bezpečnost, ale váže tě na AutoCAD). Detekce typu entit přes `.ObjectName` (string) funguje univerzálně napříč enginy doporučuji ponechat.
2. **Magická čísla** plot konstant (viz tabulka v sekci 2) v C# nahraď enumy z interopu, ale ověř hodnoty proti cílovému CADu (komentář v `NastaveniTiskarny` na to upozorňuje).
3. **Pole přes COM:** `GetBoundingBox`, `GetAttributes`, `InsertionPoint`, `PlotOrigin`, `SetWindowToPlot` pracují s `object`/`Variant` poli `double[]`. V C# je třeba je správně boxovat/castovat (`(double[])`, `out object`).
4. **Systémové proměnné** se čtou/zapisují přes `Doc.GetVariable/SetVariable` stejné názvy (`BACKGROUNDPLOT`, `PLOTTRANSPARENCYOVERRIDE`, `LTSCALE`, `INSUNITS`). Vždy zazálohovat a obnovit.
5. **`BACKGROUNDPLOT = 0`** je nutný pro synchronní tisk (jinak `PlotToFile` nečeká na dokončení a soubory mohou být nedokončené).
6. **Plot konfigurace** se vytváří/maže jako dočasné objekty (`__tmpQ`) v C# obal do `try/finally`, ať se vždy uklidí.
7. **Iterace `Layout.Block`** vrací modelspace/paperspace entity daného layoutu v typed interopu `AcadLayout.Block` je `AcadBlock`.
8. Zdroj dat (list SEZNAM, named ranges `stavba`, `MERITKOAUTOMATICKY`, `NASTAVENITISKARNY`, `LTSCALE`) je dnes Excel při portu rozhodni, odkud je vezme nová appka (DB/JSON/UI).
9. **Celočíselné systémové proměnné přes `SetVariable` posílat jako `short` (VT_I2):** VBA `Integer`
je 16bitový, .NET `int` se přes COM marshaluje jako VT_I4 a AutoCAD na
`SetVariable("PLOTTRANSPARENCYOVERRIDE", 2)` s VT_I4 **spadl nativně** (fatal error bez výjimky,
bez error.log; lokalizováno breadcrumb logem `tisk_diag.log`, 2026-07-05). V C# proto `(short)0`,
`(short)2` apod.; `LTSCALE` je RTREAL → `double` je správně. Navíc: zápis PLOTTRANSPARENCYOVERRIDE
se přeskočí, když už cílovou hodnotu má, selhání téhle kosmetické proměnné tisk nezastaví (vlastní
try/catch) a při obnově se vrací jen proměnné, které se skutečně změnily
(`CadTiskService.VytiskniRozvrzeni`). **Stejná třída problému: `Doc.Layouts.Item(neexistující
jméno)`** místo chytatelné výjimky nativní pád aplikace (2026-07-05). Layout se proto hledá
výčtem kolekce `Layouts` a porovnáním `Name` (`CadTiskService.NajdiLayout`); obecně na COM
rozhraní CADu **nestavět control flow na vyhazujících voláních** tam, kde jde výsledek zjistit
výčtem/porovnáním, udělat to tak.
10. **Odchylka od VBA rozměr rámečku:** originál (§4, bod `ramecek`) čte rozměr přes `GetBoundingBox`. C# port to **záměrně nedělá** bounding box je nespolehlivý (závisí na tom, co je v bloku zrovna vykreslené/viditelné). Blok `ramecek` je dynamický se dvěma viditelnostmi (`Benefit`/`Libovolný`); port čte rozměr přímo z dynamických parametrů `GetDynamicBlockProperties()` dvojice `VzdálenostBx`/`VzdálenostBy` pro viditelnost `Benefit`, `VzdálenostLx`/`VzdálenostLy` pro `Libovolný`. Aktivní viditelnost se pozná podle toho, která vlastnost má aktuální hodnotu rovnou `"Benefit"`/`"Libovolný"` (viz `CadLayoutService.NajdiViditelnost`), ne podle názvu vlastnosti viditelnosti samotné (ten nemusí být `Visibility1`).
---
## 10. Mapa souborů (kde co hledat)
| Soubor | Odpovídá za |
|---|---|
| `clsCadLink.cls` | Připojení k CADu, helpery pro hladiny a bloky |
| `Layout.cls` | Data jednoho rozvržení (čtení ze SEZNAM) |
| `NastaveniTiskarny.cls` | Default hodnoty tisku (DTO) |
| `modPlotConfig.bas` | Seznam tiskáren/papírů, ověření, cache `_Plot` |
| `modAktualizace.bas` | **Jádro** úprava layoutů, atributů, měřítka, počtu papírů |
| `modTiskPriloh.bas` | Hromadný tisk layoutů do PDF |
| `modPrint.bas` | Window-plot jednoho bloku (na device / do souboru) |
| `modRozpisky.bas` | Vyhledávání bloků v ModelSpace |
| `modVypisAtributu.bas` | Diagnostický výpis atributů bloku |
| `Funkce.bas` | Sdílené pomocné funkce (Excel/IO, bez CADu) |
+408
View File
@@ -0,0 +1,408 @@
# Rozpisky rozhraní aplikace, datový model a budoucí funkcionality
Tento dokument popisuje **standalone aplikaci Rozpisky** z pohledu uživatele a dat: jaké má
obrazovky, co se v nich vyplňuje, jaké akce nabízí a jak je vnitřně uspořádaný datový model.
Navazuje na [`ROZPISKY.md`](ROZPISKY.md), který popisuje **vykreslovací/exportní jádro**
(kreslicí rozhraní `IProfileRenderer`, čtečka DXF šablony `DxfTemplate`, exporty PNG/PDF/DXF).
Aplikace je **standalone náhrada za původní excelový nástroj „Rozpisky 1.0.8"**. Z něj vychází
veškerá logika rozhraní i datový model. Tento dokument je proto současně i **přepisem původního
excelu** do podoby specifikace pro samostatnou aplikaci.
> **Styl WPF se zde neřeší** popisujeme rozhraní funkčně (obrazovky, pole, akce, tok dat).
> Vizuální styl bude dodán samostatně.
---
## 1. Účel a vztah k `ROZPISKY.md`
| Dokument | Co popisuje |
|---|---|
| [`ROZPISKY.md`](ROZPISKY.md) | **Jádro** jak se kreslí a exportuje (DXF → obrazovka / PNG / PDF / DXF). |
| `ROZHRANI.md` (tento) | **Aplikace** uživatelské rozhraní, datový model (projekt + seznam příloh), akce a roadmapa. |
| [`SZ_SM011_P10_Manual_v6.md`](SZ_SM011_P10_Manual_v6.md) | **Závazný manuál SŽ** (v06, 26. 1. 2026) struktura dokumentace, **kódové označení** (kap. 3) a **popisové pole / pravidla vyplnění** (kap. 4). Autoritativní zdroj pro význam polí a kódu. |
**Princip:** Uživatel jednou vyplní **údaje projektu** (společné všem výkresům) a postupně plní
**seznam příloh** (jeden řádek = jeden výkres = jedna rozpiska). Aplikace každý řádek spojí
s údaji projektu, naplní pole DXF šablony a umí jej zobrazit (náhled) a vyexportovat/vytisknout.
**Standalone-first:** aplikace nevyžaduje AutoCAD. Vstup je **DXF šablona + data**, výstup
**PNG / PDF / DXF** (engine z `ROZPISKY.md`). Integrace s AutoCADem (interop do `.dwg`, rozvržení,
CTB, tisk plotterem) je vedena **jen jako budoucí rozšíření** viz [sekce 8](#8-roadmapa-budoucích-funkcionalit).
---
## 2. Slovník pojmů
| Pojem | Význam |
|---|---|
| **Rozpiska** | Rohové razítko výkresu tabulka s údaji o projektu, příloze, autorech a revizích. |
| **Příloha** | Jeden výkres / list dokumentace. V seznamu = jeden řádek. |
| **Seznam příloh** | Tabulka všech příloh projektu (původní list `SEZNAM`). |
| **Rozvržení (layout)** | Pojmenované rozvržení výkresu (v AutoCADu paper-space layout). Jméno se generuje z identifikace přílohy. |
| **Orientační schéma** | Malé schéma v rozpisce naznačující polohu listu v rámci stavby (buňky `K1``K47`). |
| **Placeholder loga** | Vyhrazené místo v šabloně pro logo (objednatele/zhotovitele). Leží na netisknutelné hladině. |
| **Číselník** | Předvyplněný seznam hodnot (organizace, firmy, jména, profese, …) pro výběr v polích. |
| **Projektové pole** | Hodnota společná celému projektu (z údajů projektu). |
| **Řádkové pole** | Hodnota specifická pro jednu přílohu (ze seznamu příloh). |
---
## 3. Datový model
Model 1:1 odpovídá listům původního excelu. Entity:
### 3.1 Projekt (původní list `ÚDAJE`)
Údaje společné všem rozpiskám projektu. Část polí se **automaticky dohledává z číselníků**
(v excelu přes `VLOOKUP`).
| Pole | Popis | Zdroj |
|---|---|---|
| `stavba` | Název stavby / akce | ruční |
| `HIP` | Hlavní inženýr projektu | ruční |
| `investor` | Objednatel zakázky | číselník Organizace |
| `investorAdresa` | Adresa objednatele | **auto** z č. Organizace |
| `slozkaSZ` | Složka SŽ (zástupce objednatele) | ruční / číselník |
| `slozkaSZAdresa` | Adresa složky SŽ | **auto** z č. Organizace |
| `skod` | S-kód (číslo smlouvy dle SoD) | ruční |
| `cisloZakazky` | Číslo zakázky | ruční |
| `stupenDokumentace` | Stupeň dokumentace (např. DOS) | číselník Verze dokumentace |
| `smluvniDatumZpracovani` | Smluvní datum zpracování | ruční (datum) |
| `zhotovitelSOD` | Zhotovitel díla dle SoD | číselník Firmy |
| `adresaSOD` | Adresa zhotovitele | **auto** z č. Firmy |
| `telSOD` | Telefon zhotovitele | **auto** z č. Firmy |
| `emailSOD` | E-mail zhotovitele | **auto** z č. Firmy |
### 3.2 Příloha (řádek v seznamu, původní list `SEZNAM`)
Sloupce AAD; jeden řádek = jedna rozpiska. Souhrn:
| Sl. | Obsah | Sl. | Obsah |
|---|---|---|---|
| A | Označení části | O | Kontroloval (R1) |
| B | Označení dílčí části / řady | PU | R2R4 + kdo revidoval |
| C | Název objektu / dílčí části | V | Zhotovitel části |
| D | Číslo objektu / komplexu | W | Měřítko |
| E | Číslo přílohy typ | X | Formát × A4 |
| F | Číslo přílohy dílčí | Y | Kraj |
| G | Číslo přílohy pořadí | Z | Katastrální území |
| H | Název přílohy | AA | TUDU |
| I | Název dílčí části přílohy | AB | **Jméno rozvržení** (generováno) |
| J | Zkratka přílohy | AC | LTSCALE |
| K | Vypracoval | AD | CTB (styl tisku) |
| L | Odpovědný projektant | | |
| M | Specialista | | |
| N | Revize 1 (R1) | | |
> **Jméno rozvržení** (`AB`) je **poloautomatické**, řízené zaškrtávacím polem **Příloha objektu**
> (první sloupec seznamu, výchozí = zaškrtnuto):
> - **zaškrtnuto** → jméno se generuje dle manuálu SŽ **kap. 2.7.7.9** (číslo objektu bez teček,
> mezer a pomlček; složky podobjekt / typ / dílčí / pořadí přílohy oddělené `_`):
> `SO131.45.01` + `D1` + `1` + `001` = `SO1314501_D1_1_001`; u podobjektu `SO1314501_01_D1_1_001`;
> u skupiny `SK11311_D1_1_001`. Needituje se;
> - **odškrtnuto** → uživatel zadá jméno ručně (při přepnutí se předvyplní vygenerovanou hodnotou).
>
> Slouží jako jméno layoutu / základ názvu exportovaného souboru. Řádky se shodným jménem rozvržení
> (kolize názvu exportu) se v seznamu zvýrazní.
>
> Samostatné zaškrtávací pole **Rozpiska** (výchozí = zaškrtnuto) řídí, zda název PDF při exportu
> dostane příponu `_rozpiska` (např. `SO1314501_D1_1_001_rozpiska.pdf`). Je nezávislé na polích
> **Příloha objektu** a **Desky objektu** i rozpiska na spisové desky objektu může příponu dostat,
> pokud je pole zaškrtnuté.
### 3.3 Revize (původní list `REVIZE`)
Tabulka revizí: **REVIZE** (kód/číslo verze, např. `000`), **DATUM**, **POPIS**, **KONTROLOVAL**.
Na revize se odkazují řádkové revizní sloupce přílohy (R1R4) a revizní pole v rozpisce.
> **Revize jsou interní data projektu** patří vždy ke **konkrétní zakázce**, ukládají se spolu
> s projektem (ne do externí číselníkové databáze, viz [3.4](#34-číselníky)). Pravidla vyplnění
> revizí popisuje manuál SŽ, kap. 4.3.4 (viz [3.7](#37-kódové-označení-přílohy-47-pozic-pole-k1k47)).
### 3.4 Číselníky
| Číselník | Sloupce | Použití |
|---|---|---|
| **Organizace** | název, adresa | objednatel + složka SŽ (auto adresy) |
| **Firmy / zhotovitelé** | firma, adresa, telefon, e-mail | zhotovitel díla i objektu (auto kontakty) |
| **Jména** | jméno | vypracoval / odpovědný / specialista / kontroloval |
| **Profese** | profese | profesní zařazení |
| **Verze dokumentace** | verze | stupeň dokumentace |
| **Části** | označení, název části | části/objekty v seznamu |
> **Číselníky jsou sdílená data napříč projekty a žijí v samostatné databázi vedle `.exe`.**
> V původním Excelu šlo o samostatné listy s daty (označení dokumentace, data firem apod.).
> Ve standalone aplikaci se z nich stane **externí databázový soubor uložený vedle spustitelného
> souboru** (např. `cisleniky.db` / `.json` ve složce aplikace), aby ho šlo **průběžně doplňovat
> a sdílet** mezi projekty bez zásahu do aplikace. (Na rozdíl od revizí, které jsou interní
> k zakázce viz [3.3](#33-revize-původní-list-revize).)
### 3.5 Konfigurace
| Položka | Popis |
|---|---|
| `CestaExportu` | Kořenová cesta pro export (např. `C:\temp`). |
| `SlozkaExportu` | Podsložka exportu. |
| `MERITKOAUTOMATICKY` | Automatické měřítko. |
| `LTSCALE` | Měřítko typů čar (per výkres). |
| CTB | Styl tisku (per výkres). |
| Nastavení tiskárny | Pro tiskové akce. |
> Tato konfigurace **nejsou pole rozpisky** řídí export/tisk a generování rozvržení.
### 3.6 Mapování `pole aplikace ↔ DXF ATTDEF tag`
Šablona [`Rozpiska.dxf`](../Rozpisky/Podklady/Rozpiska.dxf) obsahuje **101 polí (`ATTDEF`)**. Tag pole = klíč do
`values` při vyplnění (viz `DxfTemplate.Replay(g, values)` v `ROZPISKY.md`). Mapování na zdroj dat:
**Projektová pole (z údajů projektu):**
| DXF tag | Zdroj |
|---|---|
| `NAZEV_AKCE` | `stavba` |
| `SO_HIP` | `HIP` |
| `OBJEDNATEL_NAZEV` | `investor` |
| `OBJEDNATEL_ADRESA` | `investorAdresa` |
| `OBJEDNATEL_ZASTUPCE_NAZEV` | `slozkaSZ` |
| `OBJEDNATEL_ZASTUPCE_ADRESA` | `slozkaSZAdresa` |
| `S_KOD` | `skod` |
| `ZAK_CISLO` | `cisloZakazky` |
| `STUP_DOK` | `stupenDokumentace` |
| `DATUM` | `smluvniDatumZpracovani` |
| `ZHOTOVITEL_DILA_NAZEV` | `zhotovitelSOD` |
| `ZHOTOVITEL_DILA_ADRESA` | `adresaSOD` |
| `ZHOTOVITEL_DILA_TELEFON` | `telSOD` |
| `ZHOTOVITEL_DILA_EMAIL` | `emailSOD` |
**Řádková pole (z přílohy / seznamu).** Význam upřesněn dle grafické podoby popisového pole
(manuál SŽ, kap. 4.2.1 a 4.3.7):
| DXF tag | Význam / zdroj |
|---|---|
| `CAST` | Označení části dokumentace (např. `D`) SEZNAM A |
| `CAST_NAZEV` | Název části / profesní skupina (např. „Dokumentace objektů") |
| `OBJEKT_NAZEV` | Název objektu / dílčí části SEZNAM C |
| `RADA` | **řada** objektu (např. `SO131`) SEZNAM B |
| `USEK` | **úsek** složka označení objektu (kap. 2.5 / 3.2.4) |
| `RAZENI` | **řazení** složka označení objektu (kap. 2.5 / 3.2.4) |
| `PODOBJEKT` | **podobjekt** (např. `01`) kap. 3.2.5 |
| `DILCI_CAST` | dílčí část / řada přílohy (např. `D130`) |
| `TYP` | typ přílohy (např. `D.1`) SEZNAM E |
| `CISLO_PRILOHY` | číslo přílohy (3 cifry, např. `003`) SEZNAM G |
| `PRILOHA` | Název přílohy SEZNAM H |
| `PRILOHA_CAST` | Název dílčí části přílohy SEZNAM I |
| `SO_VYPRACOVAL_PRILOHA` | Zpracovatel přílohy SEZNAM K |
| `SO_ZODP_PROJEKTANT` | Odpovědný projektant SEZNAM L |
| `SO_SPECIALISTA` | Specialista SEZNAM M |
| `MERITKO` | Měřítko SEZNAM W |
| `FORMATY` | Formáty (× A4) SEZNAM X |
| `KRAJ` | Kraj SEZNAM Y |
| `KATASTRALNI_UZEMI` | Katastrální území SEZNAM Z |
| `TUDU` | TUDU SEZNAM AA |
| `ZHOTOVITEL_OBJEKTU_NAZEV` | Zhotovitel části / objektu SEZNAM V |
| `ZHOTOVITEL_OBJEKTU_ADRESA/TELEFON/EMAIL` | **auto** z č. Firmy podle `V` |
> Čtveřice `RADA` / `USEK` / `RAZENI` / `PODOBJEKT` tvoří dohromady **označení objektu**
> (např. `SO131 .15 .12 .01`); přesné rozčlenění čísla objektu řeší manuál kap. 2.5 a 3.2.4.
**Revizní pole (z přílohy R1R4 + list `REVIZE`):**
**4 revizní řádky** (sloupce *Revize / Datum / Popis / Kontroloval*, manuál kap. 4.3.4),
plněné z interní tabulky revizí ([3.3](#33-revize-původní-list-revize)):
| DXF tag | Zdroj |
|---|---|
| `REVIZE1CISLO`..`4CISLO` | číslo / kód verze revize (např. `000`) |
| `REVIZE1DAT`..`4DAT` | datum revize |
| `REVIZE1`..`REVIZE4` | popis revize |
| `SO_KONTROLOVAL1`..`4` | kdo kontroloval |
**Strojově čitelný kód:** `K1``K47` = **47 pozic kódového označení přílohy** (manuál kap. 3.1.5),
zobrazených znak po znaku v popisovém poli. **Negenerují se ručně aplikace je sestaví** z ostatních
polí (S-kód, stupeň dokumentace, část, objekt, podobjekt, typ, příloha, revize) viz
[3.7](#37-kódové-označení-přílohy-47-pozic-pole-k1k47).
**Orientační schéma:** samostatné **grafické pole** (pole 2, manuál kap. 4.3.2) schéma stavby
s barevným zvýrazněním polohy objektu; **není to `ATTDEF`**, ale obrazová oblast.
**Loga:** `Rozpiska_logo1``Rozpiska_logo5` **nejsou `ATTDEF`**, ale geometrické placeholdery
na netisknutelných hladinách (viz [sekce 6](#6-loga-a-orientační-schéma)).
> **Pozn. k mapování:** Význam polí byl upřesněn dle **manuálu SŽ** (kap. 3 a 4) původní excelová
> makra (VBA) se v `.xlsx` nedochovala, ale grafická podoba a pravidla vyplnění popisového pole jsou
> v manuálu závazné. Skupiny hladin `Rozpiska_pole_1``8` odpovídají různým stylům (velikost/zarovnání)
> textu polí viz [sekce 7](#7-metadata-polí-zalamování-styl-víceřádkovost).
### 3.7 Kódové označení přílohy (47 pozic, pole `K1``K47`)
Strojově čitelný kód (manuál SŽ kap. 3) má **pevných 47 pozic** rozdělených do 6 skupin; v rozpisce
se zobrazuje znak po znaku v polích `K1``K47`. **Aplikace ho generuje** z ostatních polí, ručně se
neopravuje. Neobsazená alfanumerická pozice = `X`, oddělovač = `_`.
| Skupina | Pozice | Význam | Zdroj polí |
|---|---|---|---|
| 1 | 111 | Identifikace stavby (S-kód / označení investora) | `S_KOD` |
| 2 | 1316 | Stupeň dokumentace (4 znaky, např. `DPSX`) | `STUP_DOK` |
| 3 | 1821 | Část / číselná řada (`D` + řada) | `CAST`, `RADA` |
| 4 | 2334 | Objekt + podobjekt (`SO`/`PS` + číslo + podobjekt) | `RADA`,`USEK`,`RAZENI`,`PODOBJEKT` |
| 5 | 3643 | Typ přílohy + číslo přílohy (`D1``_YYY`) | `TYP`, `CISLO_PRILOHY` |
| 6 | 4547 | Verze / revize (`P`/`0`/`V` + pořadí) | `REVIZEnCISLO` |
Příklad (manuál kap. 4.2.1):
`S123456789X _ DPSX _ D130 _ SO131_15_12 _ 01 _ D1 _ 2 _ 003 _ 000`
(v rozpisce bez mezer, každý znak v jedné buňce `K1``K47`).
> Detailní pravidla pozic jsou v manuálu kap. 3.2.13.2.8; generátor kódu je proto vlastní
> funkční blok aplikace (vstup = strukturovaná pole přílohy, výstup = 47 znaků).
---
## 4. Uživatelské rozhraní
Popsáno funkčně (bez vizuálního stylu).
### 4.1 Hlavní okno
Sekce odpovídající původním listům excelu + panel akcí:
- **Údaje projektu** formulář (viz 4.2).
- **Seznam příloh** mřížka (viz 4.3). Hlavní pracovní plocha.
- **Revize** tabulka revizí projektu.
- **Číselníky** správa hodnot (organizace, firmy, jména, profese, verze, části).
- **Nastavení** cesty exportu, šablona, tisk/konfigurace.
### 4.2 Formulář „Údaje projektu"
Pole dle [sekce 3.1](#31-projekt-původní-list-údaje). Výběr objednatele / zhotovitele z číselníku
**automaticky doplní** adresu a kontakty (náhrada excelového `VLOOKUP`).
### 4.3 Mřížka „Seznam příloh"
- Tabulka (DataGrid), kde **jeden řádek = jedna rozpiska**; sloupce dle [sekce 3.2](#32-příloha-řádek-v-seznamu-původní-list-seznam).
- Vybraná pole nabízejí výběr z **číselníků** (jména, firmy, kraj, části…).
- **Editace dat probíhá přímo v mřížce.**
- Sloupec **Jméno rozvržení** je poloautomatický viz [sekce 3.2](#32-příloha-řádek-v-seznamu-původní-list-seznam)
(řízeno polem **Příloha objektu**); duplicitní jména se zvýrazní.
### 4.4 Náhled rozpisky
- **Náhled se otevírá dvojklikem na řádek** seznamu → otevře se **samostatné okno** s náhledem
dané rozpisky.
- Náhled vykresluje engine z `ROZPISKY.md` (`IProfileRenderer` / `SkiaProfileRenderer`)
živě, ve výkresových milimetrech.
- Okno umožní přepnout: **vyplněné hodnoty** (`Replay(g, values)`) ↔ **předpis / názvy polí**
(`Replay(g)`).
- Z okna náhledu lze danou rozpisku rovnou vyexportovat / vytisknout.
---
## 5. Funkcionality / akce
Přehled vychází z ribbonu původního excelu; sloupec „Standalone chování" popisuje ekvivalent
v samostatné aplikaci.
| Akce (původně) | Standalone chování | Stav |
|---|---|---|
| **Uprav rozpisku** | Editace dat řádku v mřížce; **náhled dvojklikem na řádek** (samostatné okno, [4.4](#44-náhled-rozpisky)). Tlačítko „uprav" odpadá. | plán |
| **Uprav rozpisky** | Hromadné přegenerování / kontrola všech rozpisek (např. po změně údajů projektu). | plán |
| **Vytiskni rozpisku** | Export / tisk **jedné** rozpisky (PDF/PNG) přes `Exporters` (`PdfA4`, `PngA4`). | plán |
| **Vytiskni rozpisky** | **Dávkový** export/tisk všech rozpisek do `CestaExportu\SlozkaExportu`, název dle „Jména rozvržení". | plán |
| **Aktualizuj rozvržení** | Standalone ekvivalent: vygenerování/aktualizace výstupů (DXF/PDF) per rozvržení. (AutoCAD varianta → [roadmapa](#8-roadmapa-budoucích-funkcionalit).) | plán |
| **Vytiskni rozvržení** | Tisk rozvržení (přes vlastní engine / PrintDialog). (AutoCAD varianta → roadmapa.) | plán |
| **Tisk seznamu** | Tisk přehledu seznamu příloh. | plán |
| **Export seznamu (Otevřená verze)** | Export seznamu příloh do otevřeného `.xlsx`. | plán |
| **Navigace (Předchozí/Další)** | Navigace mezi sekcemi / řádky. | volitelné |
| **O programu** | Informace o aplikaci a verzi. | plán |
---
## 6. Loga a orientační schéma
- Šablona má **5 placeholderů na loga** (`Rozpiska_logo1``Rozpiska_logo5`).
- Placeholdery leží na **netisknutelných hladinách** (`!!NOPRINT`): jejich geometrie se **nevykresluje**,
ale aplikace o nich **musí vědět** (z dat šablony), aby do nich uměla posadit logo viz
`RectForLayer` / `g.Image(...)` v `ROZPISKY.md`.
- Logo se přiřazuje podle role: **loga institucí financujících stavbu** (pole 1, manuál kap. 4.3.1
nepovinné), **objednatel/investor**, **zhotovitel díla**, **zhotovitel části/objektu** (manuál
kap. 4.3.5/4.3.6). Načítá se ze souboru (`File.ReadAllBytes("logo.png")`).
- **Orientační schéma** je **samostatné grafické pole** (pole 2, manuál kap. 4.3.2) schéma stavby
s červeným zvýrazněním polohy dotčeného objektu (u liniových staveb klad listů). Nepovinné u malých
staveb. **Není to** pole `K1``K47` (to je strojový kód, viz [§ 3.7](#37-kódové-označení-přílohy-47-pozic-pole-k1k47)).
- Pole pro **otisk razítek** / razítko oprávněné osoby (pole 3, kap. 4.3.3) zůstává v elektronické
verzi obvykle prázdné.
---
## 7. Metadata polí (zalamování, styl, víceřádkovost)
Pole rozpisky nejsou jen „text na souřadnici". Aby výstup odpovídal šabloně, je třeba u každého
pole znát (viz požadavek v [`ROZPISKY.md`](ROZPISKY.md)):
- **velikost textu** (výška) daná stylem/atributem,
- **styl** atributu,
- **víceřádkovost** zda byl atribut víceřádkový,
- **šířku** pole pro **zalamování** dlouhého textu (adresy, dlouhé názvy),
- **zarovnání** (H/V).
Skupiny hladin `Rozpiska_pole_1``8` zřejmě odpovídají různým stylům polí. Tato metadata se mají
číst ze šablony (z `ATTDEF`) a nést spolu s hodnotou.
> **Dopad do jádra:** současná signatura `IProfileRenderer.Text(...)` v `ROZPISKY.md` nenese šířku
> ani příznak víceřádkovosti. Navrhuje se ji **rozšířit o šířku pole + zalamování** (resp. nést
> metadata pole z `DxfTemplate`), aby šlo dlouhé hodnoty správně zalomit. Tím se zároveň řeší
> rozpor mezi požadavkem na víceřádková pole a stávajícím omezením „jen jednořádkový `TEXT`".
---
## 8. Roadmapa budoucích funkcionalit
Orientační fázování (priorita shora dolů):
**Fáze 1 MVP (standalone):**
- Načtení DXF šablony a zjištění polí/placeholderů.
- Datový model: projekt + seznam příloh (v paměti).
- Mřížka seznamu, formulář údajů projektu.
- Náhled rozpisky dvojklikem na řádek.
- Export **jedné** rozpisky do PNG/PDF.
**Fáze 2 data a produktivita:**
- Číselníky + automatické doplnění adres/kontaktů (VLOOKUP).
- Revize.
- **Uložení/načtení projektu** (formát viz [otevřené otázky](#9-otevřené-otázky)).
- Import z původního `.xlsx` (přemostění starých dat).
- **Dávkový export** všech rozpisek.
**Fáze 3 výstupy:**
- Tisk (PrintDialog) jednotlivě i dávkově.
- Tisk / export **seznamu příloh** (i „Otevřená verze" do `.xlsx`).
- Loga ze souborů, orientační schéma.
**Fáze 4 kvalita výstupu:**
- **Víceřádková pole a zalamování** (viz [sekce 7](#7-metadata-polí-zalamování-styl-víceřádkovost)).
- Podpora více DXF šablon.
- Nastavení (cesty, měřítko, CTB, tiskárna).
**Budoucí blok AutoCAD integrace (interop):**
- Vyplnění a tisk rozpisek **přímo ve výkresech `.dwg`**.
- Práce s **rozvrženími (layouty)**, **CTB** styly, **LTSCALE**, tisk plotterem.
- Výstup zpět do `.dwg`.
- *(Mimo standalone jádro aktivuje se jen při dostupném AutoCADu.)*
---
## 9. Otevřené otázky
- **Formát uložení** rozdělené úložiště:
- **Projekt** (údaje + seznam příloh + **revize**) = interní data jedné zakázky → formát k rozhodnutí
(JSON / SQLite / vlastní).
- **Číselníky** (organizace, firmy, jména, profese, verze, části) = **externí databáze vedle `.exe`**,
sdílená a doplňovatelná napříč projekty ([3.4](#34-číselníky)) → formát k rozhodnutí.
- **Generátor 47-pozičního kódu** doimplementovat dle manuálu kap. 3.2.13.2.8 vč. okrajových případů
(sdružené objekty `SK`/`PK`, kap. 3.3; pracovní vs. definitivní verze).
- **Orientační schéma** jak se obrázek schématu získá/přiřadí k příloze (vstup uživatele vs. generování).
- **WPF styl** dodá uživatel samostatně; zde neřešen.
- **Import z původního `.xlsx`** mapování listů `ÚDAJE`/`SEZNAM`/`REVIZE` + číselníků do modelu.
- **Více DXF šablon** jedna pevná vs. volitelné šablony (základní pole / pole celé stavby / vložená
příloha, manuál kap. 4.2.14.2.3).
- **Lokalizace** zatím čeština.
+222
View File
@@ -0,0 +1,222 @@
# Rozpisky generátor výkresových rohových razítek (C# / .NET)
Standalone WPF aplikace (náhrada původního excelového nástroje „Rozpisky 1.0.8"). Spravuje projekt,
seznam příloh, revize a číselníky, a z **DXF šablony rozpisky** generuje **náhled**, **PDF na A4**,
**hromadný DXF** (pole jako `TEXT`/`MTEXT` entity), **seznam příloh do XLSX** a přes připojený CAD
i **tisk rozvržení**.
Celé kreslení stojí na jedné myšlence: existuje jedno **kreslicí rozhraní**
([`IProfileRenderer`](../Rozpisky/Rendering/IProfileRenderer.cs) „kam se kreslí") a několik jeho
implementací. Tatáž kresba teče na obrazovku (náhled), do PNG, do PDF i do DXF. Čtečka šablony
([`DxfTemplate`](../Rozpisky/Dxf/DxfTemplate.cs)) jen čte DXF a „přehrává" ho do tohoto rozhraní.
---
## 1. NuGet balíčky
Cílový framework: **`net10.0-windows`**, `UseWPF=true`, platforma **AnyCPU**. Připojení na běžící CAD
a MS Excel jde přes COM (pozdní vazba přes `dynamic`) bitness běhového procesu se řídí hostitelem,
zvláštní `PlatformTarget` se nenastavuje.
| Balíček | Verze | K čemu | Klíčové API |
|---|---|---|---|
| **SkiaSharp** | `2.88.8` | 2D rasterizace + **PDF**. Kreslení geometrie/textu/obrázků; export PNG i PDF. | `SKCanvas`, `SKPaint`, `SKPath`, `SKBitmap`, `SKImage`, `SKTypeface`, `SKDocument.CreatePdf`, `SKFileWStream` |
| **SkiaSharp.Views.WPF** | `2.88.8` | WPF plátno pro živý náhled (zoom/posun). **Jen pro GUI** headless export ho nepotřebuje. | `SKElement`, `OnPaintSurface(SKPaintSurfaceEventArgs)` |
| **ACadSharp** | `3.6.29` | Čtení i **zápis** DXF (novější verze, výplně HATCH, XRecord metadata atributů). Nahradilo dřívější netDxf. | `DxfReader.Read`, `DxfWriter.Write`, `CadDocument`, `ACadSharp.Entities.*`, `ACadSharp.Tables.TextStyle` |
| **ClosedXML** | `0.105.0` | Vyplnění mustru „Seznam příloh" (`SEZNAM.xlsx`) při exportu seznamu. | `XLWorkbook`, `IXLWorksheet`, `Cell(...).Value`, `SaveAs` |
> **Pozn. k ACadSharp:** na rozdíl od netDxf vystaví font ze stylu i box-šířku víceřádkových atributů
> (XRecord, group 41), takže jde dlouhý text v poli správně zalomit. DXF se zapisuje **binárně**
> (`DxfWriter.Write(..., binary: true)`) výrazně menší soubor. Převod XLSX → PDF (tisk seznamu) jde
> přes **nainstalovaný MS Excel** (COM), ne přes ACadSharp/ClosedXML.
### Zápis DXF co je potřeba vědět
- **Tloušťka čáry** = `Layer.LineWeight` (enum, hodnota v 1/100 mm standardní hodnoty:
`0,5,9,13,15,18,20,25,30,35,40,50,53,60,70,80,90,100,106,120,140,158,200,211`).
- **Diakritika** se do DXF ukládá jako Unicode escape `\U+XXXX` (např. `š``\U+0161`) AutoCAD
i ostatní čtečky to čtou správně.
- Pole, která byla v šabloně `ATTDEF`, se při vyplnění zapisují jako obyčejné `TEXT`/`MTEXT` entity
(žádné atributy bloku).
- Objekty v netisknutelných hladinách (`PlotFlag=0`) se **nevykreslují**, ale ví se o nich kvůli
místům pro loga (viz [`DxfTemplate.PlaceholderHladiny`](../Rozpisky/Dxf/DxfTemplate.cs)).
---
## 2. Struktura kódu
Aplikace je členěná dle vrstev (MVVM + služby):
```
Rozpisky/
├─ Rendering/ ← kreslicí vrstva (nezávislá na cíli)
│ ├─ IProfileRenderer.cs ← kreslicí rozhraní + HAlign/VAlign + TextStyle
│ ├─ SkiaProfileRenderer.cs ← výstup přes SkiaSharp (obrazovka / PNG / PDF)
│ ├─ DxfProfileRenderer.cs ← výstup do DXF (ACadSharp)
│ ├─ BoundsRenderer.cs ← spočítá bbox kresby (fit / umístění na A4)
│ └─ TransformRenderer.cs ← dekorátor: měřítko + posun (fit fragmentů/loga)
├─ Dxf/ ← čtení šablony, mapování hodnot, kódy
│ ├─ DxfTemplate.cs ← načte DXF šablonu a přehraje ji do IProfileRenderer
│ ├─ RozpiskaRenderer.cs ← spojuje šablonu + hodnoty + exportéry (fasáda pro UI)
│ ├─ RozpiskaValues.cs ← „tag DXF → hodnota" z projektu/přílohy/číselníků (reflexí dle mapovani.json)
│ ├─ MapovaniStore.cs ← načtení mapování z mapovani.json (config vedle .exe)
│ ├─ KodPrilohy.cs ← 47-poziční strojový kód přílohy (manuál SŽ kap. 3)
│ ├─ Exporters.cs ← PngA4 / PdfA4 / RenderView (kreslí libovolný Action<IProfileRenderer>)
│ └─ LogaResolver.cs ← dohledání DXF log/schémat k příloze
├─ Cad/ ← připojení na běžící CAD (COM) + aktualizace/tisk rozvržení
├─ Xlsx/ ← export seznamu příloh (ClosedXML) + XLSX→PDF (Excel COM)
├─ Data/ ← persistence: .rzp projekt, číselníky, atomický zápis configů
├─ Models/ ← datový model (Projekt, Priloha, Revize, Ciselniky, Nastaveni…)
├─ ViewModels/ ← MainViewModel (stav, akce, dirty-flag, export)
├─ Views/ + Themes/ + Theming/ + Behaviors/ ← WPF UI (dark theme, grid chování)
├─ App.xaml(.cs) ← vstupní bod + globální záchytná síť výjimek (error.log)
└─ MainWindow.xaml(.cs) ← hlavní okno
```
Vedle .exe se dodávají editovatelné soubory: `Rozpiska.dxf` (šablona), `SEZNAM.xlsx` (mustr seznamu),
`ciselniky.json`, `mapovani.json`, `cad.json`, `layout.json`, `loga/` a manuál SŽ (PDF).
---
## 3. Kreslicí rozhraní
Vše se kreslí ve **výkresových milimetrech**, osa **Y nahoru** (jako v CAD/DXF).
```csharp
public enum HAlign { Left, Center, Right }
public enum VAlign { Baseline, Bottom, Middle, Top }
public readonly record struct TextStyle(string? FontFamily = null, bool Bold = false,
bool Italic = false, string? FontFile = null);
public interface IProfileRenderer
{
void Layer(string name, int rgb, double lineWeightMm = 0.25); // barva 0xRRGGBB, tloušťka ByLayer
void Line(double x1, double y1, double x2, double y2);
void Polyline(IReadOnlyList<(double X, double Y)> pts, bool closed = false);
void Circle(double cx, double cy, double r);
void Text(double x, double y, string text, double heightMm,
HAlign h = HAlign.Left, VAlign v = VAlign.Baseline, double rotationDeg = 0,
TextStyle style = default, double widthFactor = 1, double maxWidthMm = 0);
void Fill(IReadOnlyList<IReadOnlyList<(double X, double Y)>> loops); // HATCH výplně (even-odd)
}
```
- `rgb` je barva `0xRRGGBB` rozbalená z DXF (ByLayer i index/true-color). Bílá se kreslí černě
(bílá na bílém papíře by zmizela).
- `widthFactor` = horizontální měřítko písma (DXF width factor). `maxWidthMm` = šířka pro zalomení
víceřádkového textu (0 = jen explicitní zlomy).
Implementace:
- **`SkiaProfileRenderer`** kreslí na `SKCanvas`. Dostane funkci `Map(mmX, mmY) → bod plátna`
a `pxPerMm`. Text vzpřímeně (rotace opačně, plátno má Y dolů), fonty ze stylu/souboru s fallbackem.
Je `IDisposable` (uvolní typefaces) používat přes `using`.
- **`DxfProfileRenderer`** pro každou hladinu založí `Layer` (barva + tloušťka), entity přidává do
`Document`. Výsledek zapíše `DxfWriter.Write(path, renderer.Document, binary: true)`.
- **`BoundsRenderer`** nic nekreslí, jen sčítá min/max souřadnic (fit / vystředění na A4).
- **`TransformRenderer`** dekorátor: na souřadnice aplikuje uniformní měřítko + posun. Slouží
k umístění vkládaného DXF fragmentu (logo / schéma) do vymezeného rámečku.
---
## 4. Čtečka šablony a fasáda pro UI
Nízkoúrovňová čtečka [`DxfTemplate`](../Rozpisky/Dxf/DxfTemplate.cs):
```csharp
var tpl = new DxfTemplate("Rozpiska.dxf");
tpl.Replay(g); // NÁHLED: pole se vykreslí jako jejich názvy (tagy)
tpl.Replay(g, values); // VYPLNĚNÍ: pole = hodnota; nevyplněné = prázdné
tpl.Replay(g, values, includeNoPrint); // + volitelně A4 rámeček !!NOPRINT (pro DXF export/tisk)
```
`Replay` přehraje statickou geometrii (`Line`/`Polyline`), popisky (`Text`/`MText`) a pole
(`ATTDEF` z model space) do rozhraní. `SheetFrame` vrací A4 rámeček šablony (referenční obdélník pro
vystředění), `Placeholders` vrací rámečky pro loga/schéma podle vyhrazených hladin, `Bounds` bbox
kresby (pro fit vkládaného fragmentu).
Fasáda pro UI [`RozpiskaRenderer`](../Rozpisky/Dxf/RozpiskaRenderer.cs) spojuje šablonu, mapování hodnot
a exportéry na jedno místo (šablona se cachuje):
```csharp
var r = new RozpiskaRenderer(Nastaveni.SablonaDxf);
Action<IProfileRenderer> draw = r.BuildDraw(projekt, priloha, revize, ciselniky,
vyplnene: true, loga, ramecekA4: false);
r.ExportPdf(projekt, priloha, revize, ciselniky, "rozpiska.pdf", loga); // A4 PDF vč. log
r.ExportPng(projekt, priloha, revize, ciselniky, "nahled.png", loga); // A4 PNG
```
Hodnoty polí sestavuje [`RozpiskaValues`](../Rozpisky/Dxf/RozpiskaValues.cs): mapování „pole programu →
DXF atribut" **není v kódu**, čte se z `mapovani.json` a hodnoty se dotahují reflexí. K tomu se
algoritmicky doplní 47-poziční strojový kód (`K1``K47`, viz
[`KodPrilohy`](../Rozpisky/Dxf/KodPrilohy.cs)).
---
## 5. Export na A4 (`Exporters`)
[`Exporters`](../Rozpisky/Dxf/Exporters.cs) vykreslí **libovolný** `Action<IProfileRenderer>`:
```csharp
Exporters.PngA4(draw, "rozpiska.png", dpi: 200, frame: sheetFrame); // A4 raster
Exporters.PdfA4(draw, "rozpiska.pdf", frame: sheetFrame); // A4 vektor (PDF, 1:1)
Exporters.RenderView(canvas, wpx, hpx, draw, frame, zoom, panX, panY); // živý náhled na SKElement
```
Princip A4: referenční obdélník (`frame` = A4 rámeček šablony, jinak `BoundsRenderer`) se mapuje
**1:1** a vystředí na papír; zmenší se jen tehdy, když se do tisknutelné plochy nevejde. PDF se kreslí
přes `SKDocument.CreatePdf` (1 mm = 72/25,4 bodu; text vektorový, tloušťky v reálných mm).
---
## 6. Demo data (`DemoData`)
[`DemoData`](../Rozpisky/Data/DemoData.cs) naplní úvodní stav při startu:
`SeedProjekt(vm)` (ukázkový projekt + přílohy), `SeedCiselniky(c)` a `SeedKraje(c)` (výchozí
číselníky, pokud `ciselniky.json` chybí).
---
## 7. Toky exportu (přehled)
| Akce | Vstup | Výstup | Přes |
|---|---|---|---|
| Náhled rozpisky | příloha | okno se SKElement | `RozpiskaRenderer.BuildDraw``Exporters.RenderView` |
| Export do PDF (výběr/vše) | přílohy | `Rozpisky\*.pdf` | `RozpiskaRenderer.ExportPdf` (per-item, chyby se sbírají) |
| Export do DXF (hromadně) | přílohy | `__ Otevřená\_rozpisky.dxf` | dlaždicová mřížka do `DxfProfileRenderer``DxfWriter.Write` |
| Export seznamu | objekt | `SEZNAM_<objekt>.xlsx` vedle .rzp | `SeznamExporter` (ClosedXML mustr) |
| Tisk seznamu | dřív exportovaný XLSX | `Přílohy\*.pdf` | `ExcelToPdf` (MS Excel COM) |
| Aktualizace/tisk rozvržení | přílohy | přejmenování/tisk v CADu | `Cad/CadLayoutService`, `Cad/CadTiskService` (COM) |
Aplikace **nemá CLI režim** vše jede z GUI. Neočekávané výjimky zachytává globální síť v
[`App.xaml.cs`](../Rozpisky/App.xaml.cs) a zapisuje je do `error.log` vedle .exe.
---
## 8. Persistence a robustnost
- **Projekt `.rzp`** ([`ProjektStore`](../Rozpisky/Data/ProjektStore.cs)) JSON s exkluzivním zámkem
drženým po dobu otevření (ostatní procesy smí jen číst). Zápis serializuje **před** useknutím
souboru, aby pád nezanechal prázdný soubor.
- **Configy vedle .exe** (`ciselniky.json`, `cad.json`, `layout.json`, `mapovani.json`) jdou přes
[`JsonConfigFile`](../Rozpisky/Data/JsonConfigFile.cs): **atomický zápis** (přes `.tmp`) a při
poškozeném souboru **záloha do `.bak` + upozornění** (místo tichého přepsání výchozími daty).
- **Zamčený cíl exportu** před zápisem PDF/XLSX/DXF se ověří, zda soubor nedrží jiný program
(Excel, prohlížeč PDF), a nabídne Pokračovat/Přerušit.
---
## 9. Závislost na šabloně
Šablona je libovolný DXF, kde:
- rám a mřížku tvoří `LINE` / `LWPOLYLINE`,
- pevné popisky jsou `TEXT` / `MTEXT`,
- **vyplňovaná pole jsou `ATTDEF`** v model space (jejich `Tag` = klíč do hodnot),
- placeholdery pro loga jsou uzavřené polylinie na vyhrazených netisknutelných hladinách
(`Rozpiska_logo1`…, `Rozpiska_Orientační schéma`) logo/schéma se fitne do jejich ohraničení,
samotný placeholder se nekreslí (`PlotFlag=0`),
- A4 hranici papíru vymezuje rámeček na hladině `!!NOPRINT`.
Tím je celý vzhled rozpisky daný **datovým souborem a mapováním** (`Rozpiska.dxf` + `mapovani.json`),
ne kódem pro jinou rozpisku stačí jiný DXF a mapování.
File diff suppressed because one or more lines are too long