[CHANGE] Lager-Export nur noch als JSON mit Kennwerten, Gitterkorb unter Regalreihen
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
3c729ea604
commit
d2729140ff
22 files changed
+1068
-1089
No files matched your search
@@ -25,7 +25,7 @@ AutoLISP-Makros (SSG_LIB) fuer BricsCAD Pro zur automatisierten Erstellung von F
|
|||||||
| `data/ils/` | DWG-Bloecke fuer ILS-Kreisel/Eckrad (AN8, SP8, AP-Typen) |
|
| `data/ils/` | DWG-Bloecke fuer ILS-Kreisel/Eckrad (AN8, SP8, AP-Typen) |
|
||||||
| `data/json/` | Komponentendaten (Masse, Sivas-IDs); Geruest: `geruest.json` (GERUEST-Dialog) und `geruest_traeger.json` (Traeger mit Linien-Logik); `omniflo_fahrstrecke.json` (Omniflo-Fahrstrecke, gleiche Linien-Logik); `lager.json` (Vorgaben der Lagerplanung) |
|
| `data/json/` | Komponentendaten (Masse, Sivas-IDs); Geruest: `geruest.json` (GERUEST-Dialog) und `geruest_traeger.json` (Traeger mit Linien-Logik); `omniflo_fahrstrecke.json` (Omniflo-Fahrstrecke, gleiche Linien-Logik); `lager.json` (Vorgaben der Lagerplanung) |
|
||||||
| `data/block_libraries/` | DXF Block-Libraries (ils_library.dxf) |
|
| `data/block_libraries/` | DXF Block-Libraries (ils_library.dxf) |
|
||||||
| `cfg/regelwerk/` | Regelprofile der Lagerplanung je Land (`DE.json`, `SK.json`/`PL.json` erben DE), gelesen von `LagerPruefung.lsp` |
|
| `cfg/stahlbau/regelwerk/` | Regelprofile der Lagerplanung je Land (`DE.json`, `SK.json`/`PL.json` erben DE), gelesen von `LagerPruefung.lsp` |
|
||||||
| `cfg/rahmen/` | DIN-Rahmen + Schriftkopf-DWGs (A0-A4, Kopf11 DE/EN/FR/IT), kopiert aus `\\infor-ln\SSG_Tools\ACADSST\KOEPFE`, fuer `DIN_FORMATE` (DinFormate.lsp) |
|
| `cfg/rahmen/` | DIN-Rahmen + Schriftkopf-DWGs (A0-A4, Kopf11 DE/EN/FR/IT), kopiert aus `\\infor-ln\SSG_Tools\ACADSST\KOEPFE`, fuer `DIN_FORMATE` (DinFormate.lsp) |
|
||||||
| `dcl/` | DCL-Dialogdefinitionen |
|
| `dcl/` | DCL-Dialogdefinitionen |
|
||||||
| `doc/` | Dokumentation, Entwicklungsplan |
|
| `doc/` | Dokumentation, Entwicklungsplan |
|
||||||
@@ -81,7 +81,7 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD.
|
|||||||
| Omniflo (komplett) | `OmniModulInsert` + `GeruestInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_TEF_*, OMNI_TV_*, OMNI_LADESCHLEIFE_*, OMNI_EDIT; OMNI_FAHRSTRECKE / OMNI_FAHRSTRECKE_BESCHRIFTEN (GeruestInsert, Linien-Logik wie GERUEST_TRAEGER) |
|
| Omniflo (komplett) | `OmniModulInsert` + `GeruestInsert` | OMNI_APB_*, OMNI_W*_*, OMNI_TEF_*, OMNI_TV_*, OMNI_LADESCHLEIFE_*, OMNI_EDIT; OMNI_FAHRSTRECKE / OMNI_FAHRSTRECKE_BESCHRIFTEN (GeruestInsert, Linien-Logik wie GERUEST_TRAEGER) |
|
||||||
| Geruest | `GeruestInsert` | GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG (je eigener Dialog aus der Vorlage geruest.dcl, keine Umschaltung), GERUEST_TRAEGER (eigener Dialog), GERUEST_TRAEGER_BESCHRIFTEN (Untermenue Geruest -> Funktionen -> Traeger beschriften; alle Traeger der Zeichnung neu beschriften); Gattertraeger noch Platzhalter auf GERUEST (zeigt nur einen Hinweis) |
|
| Geruest | `GeruestInsert` | GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG (je eigener Dialog aus der Vorlage geruest.dcl, keine Umschaltung), GERUEST_TRAEGER (eigener Dialog), GERUEST_TRAEGER_BESCHRIFTEN (Untermenue Geruest -> Funktionen -> Traeger beschriften; alle Traeger der Zeichnung neu beschriften); Gattertraeger noch Platzhalter auf GERUEST (zeigt nur einen Hinweis) |
|
||||||
| Connections | `Connection_Edit` + `SSG_LIB_Commands` | CONNECTION_INSERT, CONNECTION_EDIT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT |
|
| Connections | `Connection_Edit` + `SSG_LIB_Commands` | CONNECTION_INSERT, CONNECTION_EDIT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT |
|
||||||
| Lager | `LagerInsert` + `LagerPruefung` | LG_GESCHOSS, LG_GESCHOSS_AKTIV, LG_GESCHOSS_KOPIEREN, LG_BEREICH, LG_REIHE, LG_GANG, LG_EDIT, LG_REGALE, LAGER_HAND_YAML, LAGER_EXPORT, LG_REGELN |
|
| Lager | `LagerInsert` + `LagerPruefung` | LG_GESCHOSS, LG_GESCHOSS_AKTIV, LG_GESCHOSS_KOPIEREN, LG_BEREICH, LG_REIHE, LG_GANG, LG_EDIT, LG_REGALE, LAGER_EXPORT, LG_REGELN |
|
||||||
| HW Planung | `HwPlanung` | HW_MATERIALFLUSS (Materialfluss erzeugen), HW_SYMBOLE (Symbole erzeugen, noch Platzhalter) |
|
| HW Planung | `HwPlanung` | HW_MATERIALFLUSS (Materialfluss erzeugen), HW_SYMBOLE (Symbole erzeugen, noch Platzhalter) |
|
||||||
| Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON |
|
| Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON |
|
||||||
| Werkzeuge | `ssg_blocktools`, `ssg_texttools`, `ssg_stueckliste`, `DinFormate` | SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN, SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL, SSG_FAEHNCHEN_STUECKLISTE, DIN_FORMATE |
|
| Werkzeuge | `ssg_blocktools`, `ssg_texttools`, `ssg_stueckliste`, `DinFormate` | SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN, SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL, SSG_FAEHNCHEN_STUECKLISTE, DIN_FORMATE |
|
||||||
@@ -125,8 +125,8 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`.
|
|||||||
| `KettenFoerderer.lsp` | KETTENFOERDERER, KF_EDIT, KF_KS_PRUEFEN | Kettenfoerderer/Schraegfoerderer Stahl: baut aus `KF_UM_<winkel>` -> `KF_LAENGE` -> `KF_AN_<winkel>` (je KS_AUS auf KS_EIN) plus der Draufsicht `KF_2D` EINEN Block `KF_<n>`. Daten `data/json/kettenfoerderer.json`, Dialog `dcl/kettenfoerderer.dcl`. **Geometrie**: SEITENANSICHT in der XY-Ebene (Hoehe = Y), ungedreht und nicht aufgerichtet, Einfuegepunkt = KS_EIN der Umlenkung; jeder Baustein bekommt nur den aus den KS gemessenen Verkettungswinkel (`insert-block-by-ks`/`insert-block-ks-skaliert`). Die Neigung (26/30 Grad) ist KEIN Rechenparameter: sie steckt in den Varianten-Bloecken, der Einbauwinkel jedes Folgebausteins wird zur Laufzeit aus der RICHTUNG des KS_AUS seines Vorgaengers gemessen (`ks-xy-winkel`/`kf-hz-folge`) - keine gepflegte Winkeltabelle. `KF_LAENGE` wird in X skaliert, die Einbauhoehe H bestimmt seine Laenge ueber die Hoehenbilanz (`kf-laenge-berechnen`). **Hauptblock + Hilfsblock**: `KF_<n>` traegt Beschriftung (`KF_1 26 Grad H=..mm L_horizontal=..mm`, Layer `kettenfoerderer_beschriftung`) und ein Hoehenmass (ActiveX `AddDimRotated`, scheitert es, wird ohne Mass gebaut) und ist der EINZIGE exportierte Block. Die Draufsicht `KF_2D` ist ein getrennter Hilfsblock `KF2D_<n>` (kein Objekt, nur zum Anschliessen von Schienen): flach, auf die PROJIZIERTE Laenge skaliert (`kf-waagerecht-laenge`), beim ersten Einfuegen `ansicht_2d.versatz_y` (-1000) mm unter dem Hauptblock, danach frei verschieb- und loeschbar, gleiche Beschriftung. Beide Bloecke tragen denselben Schluessel als XDATA `SSG_KF_EDIT` (`kf-xdata-key`); KF_EDIT findet damit den - auch verschobenen - Hilfsblock (`kf-hilfsblock-finden`), behaelt dessen Lage und erzeugt ihn bei jedem Edit neu (auch wenn er geloescht war). Der Hilfsblock passt nicht aufs Export-Muster `KF_*`; `export_sivas.py` nimmt ausserdem nur `KF_<Ziffern>`. Eine von Hand gesetzte Drehung des Hauptblocks (DXF 50) wird beim Edit wieder aufgesetzt. **Attribut-Schema** `*kf-attrib-defs-liste*` ist EIGENSTAENDIG und bewusst NICHT von `ssg-strecke-attrib-defs` abgeleitet (sonst ~24 geerbte VF-Tags am Block); die Reihenfolge folgt dem Sivas-Merkmalstamm. FOERDERERTYP = Bauart im Klartext, WINKEL = nackte Zahl 26/30 (der Klartext mit Gradzeichen entsteht erst ueber `[kf_typ_anzeige]` in cfg/sivas.cfg, damit Attributwerte ASCII bleiben); kein TEILEART (Festwert `KF_TEILEART` im Export). `L_KF_mm` ist die WAAGERECHTE Laenge des ganzen Foerderers (der Draufsicht `KF_2D`, `kf-waagerecht-laenge`), nicht die Laenge des schraegen Mittelstuecks; sie geht NICHT in die Sivas-Zeile (Spalte Laenge bleibt leer) - Sivas berechnet ZL, EL und Kettenlaenge selbst, uebernommen wird nur die Hoehe (360). Alle Auswahllisten stehen mit ihren Sivas-Optionstexten in der JSON. **Das `KF_`-Praefix ist wie `GR_` nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, darum steht ein `KF_*`-Zweig VOR dem Omniflo-Zweig (Doppelklick -> KF_EDIT, der die vorgewaehlte Auswahl nutzt und nur echte `KF_<n>` zulaesst - die Bausteine `KF_UM_26`, `KF_2D` usw. tragen dasselbe Praefix). **Die Blocknummer wird ueber die Blocktabelle vergeben** (`kf-naechste-nummer` ueberspringt jede Nummer mit vorhandener Block-DEFINITION, wie bei `GF_n`/`VF_n`): nur ueber die Referenzen im Modell zu zaehlen war ein realer Fehler - `KF_EDIT` loescht den alten Block, die Definition lebt aber weiter, `_.-BLOCK` traf auf den vorhandenen Namen, die "Neu definieren?"-Abfrage verschluckte die Folge-Eingaben, und die Einzelteile blieben lose liegen ("Block aufgeloest"). **Sivas-Export** (`[kettenfoerderer]` in cfg/sivas.cfg, `build_kettenfoerderer_details` in export_sivas.py): baugleiche Foerderer werden zu EINER Zeile zusammengefasst (`kettenfoerderer_signature`), die Gruppengroesse traegt Merkmal 353 (entsteht erst aus der Gruppierung, daher Code); Farbe (354) und Antriebsmotor (355) sind ZWEI Merkmale, und jedes merkmalbildende Attribut steht auch in der Signatur, sonst verschmelzen unterschiedlich ausgefuehrte Foerderer. Reine Kerne in `tests/test_unit.lsp` (`tu-tests-kf`); das Modul wird in der MNL vorgeladen, Laufzeit-Messung ueber den dbg-Schalter `kf-zeit` |
|
| `KettenFoerderer.lsp` | KETTENFOERDERER, KF_EDIT, KF_KS_PRUEFEN | Kettenfoerderer/Schraegfoerderer Stahl: baut aus `KF_UM_<winkel>` -> `KF_LAENGE` -> `KF_AN_<winkel>` (je KS_AUS auf KS_EIN) plus der Draufsicht `KF_2D` EINEN Block `KF_<n>`. Daten `data/json/kettenfoerderer.json`, Dialog `dcl/kettenfoerderer.dcl`. **Geometrie**: SEITENANSICHT in der XY-Ebene (Hoehe = Y), ungedreht und nicht aufgerichtet, Einfuegepunkt = KS_EIN der Umlenkung; jeder Baustein bekommt nur den aus den KS gemessenen Verkettungswinkel (`insert-block-by-ks`/`insert-block-ks-skaliert`). Die Neigung (26/30 Grad) ist KEIN Rechenparameter: sie steckt in den Varianten-Bloecken, der Einbauwinkel jedes Folgebausteins wird zur Laufzeit aus der RICHTUNG des KS_AUS seines Vorgaengers gemessen (`ks-xy-winkel`/`kf-hz-folge`) - keine gepflegte Winkeltabelle. `KF_LAENGE` wird in X skaliert, die Einbauhoehe H bestimmt seine Laenge ueber die Hoehenbilanz (`kf-laenge-berechnen`). **Hauptblock + Hilfsblock**: `KF_<n>` traegt Beschriftung (`KF_1 26 Grad H=..mm L_horizontal=..mm`, Layer `kettenfoerderer_beschriftung`) und ein Hoehenmass (ActiveX `AddDimRotated`, scheitert es, wird ohne Mass gebaut) und ist der EINZIGE exportierte Block. Die Draufsicht `KF_2D` ist ein getrennter Hilfsblock `KF2D_<n>` (kein Objekt, nur zum Anschliessen von Schienen): flach, auf die PROJIZIERTE Laenge skaliert (`kf-waagerecht-laenge`), beim ersten Einfuegen `ansicht_2d.versatz_y` (-1000) mm unter dem Hauptblock, danach frei verschieb- und loeschbar, gleiche Beschriftung. Beide Bloecke tragen denselben Schluessel als XDATA `SSG_KF_EDIT` (`kf-xdata-key`); KF_EDIT findet damit den - auch verschobenen - Hilfsblock (`kf-hilfsblock-finden`), behaelt dessen Lage und erzeugt ihn bei jedem Edit neu (auch wenn er geloescht war). Der Hilfsblock passt nicht aufs Export-Muster `KF_*`; `export_sivas.py` nimmt ausserdem nur `KF_<Ziffern>`. Eine von Hand gesetzte Drehung des Hauptblocks (DXF 50) wird beim Edit wieder aufgesetzt. **Attribut-Schema** `*kf-attrib-defs-liste*` ist EIGENSTAENDIG und bewusst NICHT von `ssg-strecke-attrib-defs` abgeleitet (sonst ~24 geerbte VF-Tags am Block); die Reihenfolge folgt dem Sivas-Merkmalstamm. FOERDERERTYP = Bauart im Klartext, WINKEL = nackte Zahl 26/30 (der Klartext mit Gradzeichen entsteht erst ueber `[kf_typ_anzeige]` in cfg/sivas.cfg, damit Attributwerte ASCII bleiben); kein TEILEART (Festwert `KF_TEILEART` im Export). `L_KF_mm` ist die WAAGERECHTE Laenge des ganzen Foerderers (der Draufsicht `KF_2D`, `kf-waagerecht-laenge`), nicht die Laenge des schraegen Mittelstuecks; sie geht NICHT in die Sivas-Zeile (Spalte Laenge bleibt leer) - Sivas berechnet ZL, EL und Kettenlaenge selbst, uebernommen wird nur die Hoehe (360). Alle Auswahllisten stehen mit ihren Sivas-Optionstexten in der JSON. **Das `KF_`-Praefix ist wie `GR_` nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, darum steht ein `KF_*`-Zweig VOR dem Omniflo-Zweig (Doppelklick -> KF_EDIT, der die vorgewaehlte Auswahl nutzt und nur echte `KF_<n>` zulaesst - die Bausteine `KF_UM_26`, `KF_2D` usw. tragen dasselbe Praefix). **Die Blocknummer wird ueber die Blocktabelle vergeben** (`kf-naechste-nummer` ueberspringt jede Nummer mit vorhandener Block-DEFINITION, wie bei `GF_n`/`VF_n`): nur ueber die Referenzen im Modell zu zaehlen war ein realer Fehler - `KF_EDIT` loescht den alten Block, die Definition lebt aber weiter, `_.-BLOCK` traf auf den vorhandenen Namen, die "Neu definieren?"-Abfrage verschluckte die Folge-Eingaben, und die Einzelteile blieben lose liegen ("Block aufgeloest"). **Sivas-Export** (`[kettenfoerderer]` in cfg/sivas.cfg, `build_kettenfoerderer_details` in export_sivas.py): baugleiche Foerderer werden zu EINER Zeile zusammengefasst (`kettenfoerderer_signature`), die Gruppengroesse traegt Merkmal 353 (entsteht erst aus der Gruppierung, daher Code); Farbe (354) und Antriebsmotor (355) sind ZWEI Merkmale, und jedes merkmalbildende Attribut steht auch in der Signatur, sonst verschmelzen unterschiedlich ausgefuehrte Foerderer. Reine Kerne in `tests/test_unit.lsp` (`tu-tests-kf`); das Modul wird in der MNL vorgeladen, Laufzeit-Messung ueber den dbg-Schalter `kf-zeit` |
|
||||||
| `HwPlanung.lsp` | HW_MATERIALFLUSS, HW_SYMBOLE | Menue "HW Planung" (zwischen Lager und SPS). HW_MATERIALFLUSS ruft EXPORTCSV auf (alte `<dwg>_export.csv` wird vorher geloescht, damit kein veralteter Stand gezeichnet wird) und danach `lib/hw_materialfluss.py` ueber `export:run-python` (Log `DXFM_LOG/hw_materialfluss.log`); Ergebnis ist eine NEUE Datei `DXFM_RESULTS/<dwg>_HW.dxf` (`hw-dxf-name`, getestet), die offene Zeichnung bleibt unveraendert. HW_SYMBOLE ist noch ein Platzhalter (Hinweis) |
|
| `HwPlanung.lsp` | HW_MATERIALFLUSS, HW_SYMBOLE | Menue "HW Planung" (zwischen Lager und SPS). HW_MATERIALFLUSS ruft EXPORTCSV auf (alte `<dwg>_export.csv` wird vorher geloescht, damit kein veralteter Stand gezeichnet wird) und danach `lib/hw_materialfluss.py` ueber `export:run-python` (Log `DXFM_LOG/hw_materialfluss.log`); Ergebnis ist eine NEUE Datei `DXFM_RESULTS/<dwg>_HW.dxf` (`hw-dxf-name`, getestet), die offene Zeichnung bleibt unveraendert. HW_SYMBOLE ist noch ein Platzhalter (Hinweis) |
|
||||||
| `menu-inventory.lsp` | MenuInventory | BricsCAD Diagnostik (Menuegruppen, Plugins, Startdateien) |
|
| `menu-inventory.lsp` | MenuInventory | BricsCAD Diagnostik (Menuegruppen, Plugins, Startdateien) |
|
||||||
| `LagerInsert.lsp` | LG_GESCHOSS, LG_GESCHOSS_AKTIV, LG_GESCHOSS_KOPIEREN, LG_BEREICH, LG_REIHE, LG_GANG, LG_EDIT, LG_REGALE, LAGER_EXPORT, LAGER_HAND_YAML | Lagerplanung GOH-Buehnenlager -> RFQ-YAML (Phase 0+1: Mengen, 2D; Konzept/Schema/YAML-Zuordnung in `doc/plan/lager_rfq.md`). Bloecke `LG_GESCHOSS` (Kopfsymbol, XDATA `SSG_LG` `kontur` -> Belagskontur), `LG_BEREICH` (Kontur + Parameter, fuellt sich selbst), `LG_REIHE_<L>_<T>`/`LG_GANG_<L>_<B>_<BELAG>` (Definition je Geometrie wiederverwendet, Werte in den Attributen der Referenz; Kinder tragen XDATA `bereich`; der Belag steht im Gang-Blocknamen, weil die Definition seine Schraffur enthaelt - Muster aus `lager.json belag_schraffur`, per `vla-AddHatch` auf Layer 0/VONBLOCK, `hallenboden` ohne; BricsCAD-`iso.pat` kennt kein `NET`, Gitterrost = `GRID`). Alle tragen `ID`, `GESCHOSS`, `LAYER`. Blockdefinitionen per `entmake` (BLOCK...ENDBLK), Einfuegen per `vla-InsertBlock` in WCS - kein `_.-BLOCK`/`_.INSERT`. **Attribut-Tags haben gemischte Schreibweise** (`HOEHE_BELAG_mm`) - beim Setzen ueber `vla-get-TagString` daher case-insensitiv zuordnen (`lg-wert-fuer-tag`), sonst bleiben diese Attribute still leer (realer Fehler beim Bau). Layer je Geschoss = Basis aus `cfg/layer.cfg [lager]` + `_G<nr>`; `LG_GESCHOSS_AKTIV` friert die uebrigen (2D-Grundrisse liegen uebereinander), aktives Geschoss als `vlax-ldata` (Dictionary `SSG_LAGER`). Geschosszuordnung `lg-geschoss-fuer-punkt-kern`: eine Kontur -> eindeutig, mehrere nur ueber Z unterscheidbar, wenn die Konturen auf verschiedenen Hoehen liegen (3D), sonst nil. Jede Kontur gehoert genau einem Block (vergebene Kontur wird kopiert). Auto-Fuellung `lg-fuellung-berechnen` (reiner Kern, Muster Reihe|Gang|Reihe Ruecken an Ruecken bzw. Reihe|Gang, nur volle Module, Streifen an Unter-/Mittel-/Oberkante gegen die Kontur geschnitten, Quergaenge ausgerichtet und nicht am Reihenende); Bereichs-Edit = Neuaufbau aller Kinder. **Randgaenge** `RANDGANG_N/O/S/W_mm` (Nord = +Y Welt) laufen entlang der echten Konturkanten (`lg-randgang-streifen`, Himmelsrichtung der Aussennormale ueber `lg-kompass`, auch L-Form; Ecken: N/S besitzen sie - konvex O/W kuerzen, einspringend N/S verlaengern) und werden wie manuelle Gaenge (`LG_GANG`, `QUELLE=manuell`, Kern `lg-gang-einfuegen`; per Linie oder Option `Rechteck` = Flaeche mit dem echten BricsCAD-Befehl RECHTECK gezeichnet, inkl. aller seiner Optionen (`lg-rechteck-zeichnen`: `_.RECTANG` + `(command pause)`-Schleife bei CMDECHO 1, Polylinie danach ueber `lg-rechteck-ecken-aus-poly` gelesen und geloescht; nur 4 Ecken ohne Boegen, sonst Meldung), Breite/Lage aus dem Rechteck ueber `lg-gang-aus-ecken`, Schleife `lg-linien-schleife` mit `rechteck-fn`) als **Sperrflaechen** aus Reihen/Haupt-/Quergaengen ausgeschnitten (`ssg-poly-band-x`). **Von Hand Gesetztes loest KEINE Neuberechnung aus**: `LG_REIHE`/`LG_GANG` (`lg-manuell-einfuegen`) und das Bearbeiten einer Reihe/eines Gangs (`lg-linie-neu-aufbauen-sperre`) schneiden nur die eigene Flaeche aus den rangniedrigeren Objekten heraus (`lg-sperre-anwenden`, reiner Kern `lg-linie-zuschnitt`; Rang `lg-quelle-rang`: auto < auto_geaendert < manuell) - frueher fuellte ein manueller Gang den ganzen Bereich neu, dabei kamen geloeschte Objekte zurueck und geaenderte wurden ersetzt. Die ausdrueckliche Neuberechnung (`lg-bereich-fuellen`, Bereich bearbeiten) entfernt nur `QUELLE=auto`; `manuell`/`auto_geaendert`-Kinder und unverknuepfte manuelle Objekte in der Kontur (`lg-manuelle-in-kontur`) bleiben und sperren ihre Flaeche. `lg-blockdef` ergaenzt bei Altbestand fehlende ATTDEFs (Neudefinition + `_.ATTSYNC`). `LAGER_EXPORT` schreibt `<dwg>_lager_raw.json` (eigener JSON-Schreiber `lg-json-*`; Geschosse, Bereiche, Reihen, Gaenge) und ruft `lib/lager_yaml_export.py` ueber `export:run-python`. Befehl `LG_REGALE` (Menue Lager -> Regale zaehlen) zaehlt die Regalreihen `LG_REIHE_*` (Anzahl, Laenge, Laenge x Haengeebenen je Geschoss aus den Attributen GESCHOSS/LAENGE/HAENGEEBENEN, reine Kerne `lg-reihe-eintrag`/`lg-reihen-auswerten`). **Der parametrische BricsCAD-Block `goh_rack` wird nicht mehr unterstuetzt** (veraltet, 2026-10-30 aus Zaehlung, Export und Geschoss-Kopie entfernt). Vorgaben aus `data/json/lager.json`. Dialoge `dcl/lager.dcl` ueber den generischen Treiber `lg-dialog` (Feldlisten `*lg-felder-*`, Konsolen-Rueckfall `lg-konsole`, ohne GUI Vorgaben). **Geschoss kopieren** (`LG_GESCHOSS_KOPIEREN`, Dialog `lg_geschoss_kopie`, Kern `lg-geschosse-kopieren`): Quelle (Vorgabe oberstes Geschoss, Erweitern G3 -> G4), Anzahl, Geschosshoehe je Kopie, Belag, Versatz X/Y je Kopie (0 = deckungsgleich; 3D-Zeichnung zusaetzlich +Z). Kein BricsCAD-KOPIEREN (XDATA-Verweise zeigten aufs Original): jedes Objekt entsteht ueber die normalen Einfuegefunktionen neu (`lg-geschoss-anlegen`, `lg-bereich-block-anlegen` = Bereich ohne Fuellung, `lg-linie-einfuegen`), Kinder 1:1 inkl. `auto_geaendert`/manuell, kein Neufuellen; Belaege gleich dem Quell-Geschossbelag folgen dem neuLine truncated
|
| `LagerInsert.lsp` | LG_GESCHOSS, LG_GESCHOSS_AKTIV, LG_GESCHOSS_KOPIEREN, LG_BEREICH, LG_REIHE, LG_GANG, LG_EDIT, LG_REGALE, LAGER_EXPORT | Lagerplanung GOH-Buehnenlager -> technische Daten als JSON fuer die RFQ-Dokumentation (Phase 0+1: Mengen, 2D; Konzept/Schema/Kennwerte in `doc/plan/lager_rfq.md`). Bloecke `LG_GESCHOSS` (Kopfsymbol, XDATA `SSG_LG` `kontur` -> Belagskontur), `LG_BEREICH` (Kontur + Parameter, fuellt sich selbst), `LG_REIHE_<L>_<T>`/`LG_GANG_<L>_<B>_<BELAG>` (Definition je Geometrie wiederverwendet, Werte in den Attributen der Referenz; Kinder tragen XDATA `bereich`; der Belag steht im Gang-Blocknamen, weil die Definition seine Schraffur enthaelt - Muster aus `lager.json belag_schraffur`, per `vla-AddHatch` auf Layer 0/VONBLOCK, `hallenboden` ohne; BricsCAD-`iso.pat` kennt kein `NET`, Gitterrost = `GRID`). Alle tragen `ID`, `GESCHOSS`, `LAYER`. Blockdefinitionen per `entmake` (BLOCK...ENDBLK), Einfuegen per `vla-InsertBlock` in WCS - kein `_.-BLOCK`/`_.INSERT`. **Attribut-Tags haben gemischte Schreibweise** (`HOEHE_BELAG_mm`) - beim Setzen ueber `vla-get-TagString` daher case-insensitiv zuordnen (`lg-wert-fuer-tag`), sonst bleiben diese Attribute still leer (realer Fehler beim Bau). Layer je Geschoss = Basis aus `cfg/layer.cfg [lager]` + `_G<nr>`; `LG_GESCHOSS_AKTIV` friert die uebrigen (2D-Grundrisse liegen uebereinander), aktives Geschoss als `vlax-ldata` (Dictionary `SSG_LAGER`). Geschosszuordnung `lg-geschoss-fuer-punkt-kern`: eine Kontur -> eindeutig, mehrere nur ueber Z unterscheidbar, wenn die Konturen auf verschiedenen Hoehen liegen (3D), sonst nil. Jede Kontur gehoert genau einem Block (vergebene Kontur wird kopiert). Auto-Fuellung `lg-fuellung-berechnen` (reiner Kern, Muster Reihe|Gang|Reihe Ruecken an Ruecken bzw. Reihe|Gang, nur volle Module, Streifen an Unter-/Mittel-/Oberkante gegen die Kontur geschnitten, Quergaenge ausgerichtet und nicht am Reihenende); Bereichs-Edit = Neuaufbau aller Kinder. **Randgaenge** `RANDGANG_N/O/S/W_mm` (Nord = +Y Welt) laufen entlang der echten Konturkanten (`lg-randgang-streifen`, Himmelsrichtung der Aussennormale ueber `lg-kompass`, auch L-Form; Ecken: N/S besitzen sie - konvex O/W kuerzen, einspringend N/S verlaengern) und werden wie manuelle Gaenge (`LG_GANG`, `QUELLE=manuell`, Kern `lg-gang-einfuegen`; per Linie oder Option `Rechteck` = Flaeche mit dem echten BricsCAD-Befehl RECHTECK gezeichnet, inkl. aller seiner Optionen (`lg-rechteck-zeichnen`: `_.RECTANG` + `(command pause)`-Schleife bei CMDECHO 1, Polylinie danach ueber `lg-rechteck-ecken-aus-poly` gelesen und geloescht; nur 4 Ecken ohne Boegen, sonst Meldung), Breite/Lage aus dem Rechteck ueber `lg-gang-aus-ecken`, Schleife `lg-linien-schleife` mit `rechteck-fn`) als **Sperrflaechen** aus Reihen/Haupt-/Quergaengen ausgeschnitten (`ssg-poly-band-x`). **Von Hand Gesetztes loest KEINE Neuberechnung aus**: `LG_REIHE`/`LG_GANG` (`lg-manuell-einfuegen`) und das Bearbeiten einer Reihe/eines Gangs (`lg-linie-neu-aufbauen-sperre`) schneiden nur die eigene Flaeche aus den rangniedrigeren Objekten heraus (`lg-sperre-anwenden`, reiner Kern `lg-linie-zuschnitt`; Rang `lg-quelle-rang`: auto < auto_geaendert < manuell) - frueher fuellte ein manueller Gang den ganzen Bereich neu, dabei kamen geloeschte Objekte zurueck und geaenderte wurden ersetzt. Die ausdrueckliche Neuberechnung (`lg-bereich-fuellen`, Bereich bearbeiten) entfernt nur `QUELLE=auto`; `manuell`/`auto_geaendert`-Kinder und unverknuepfte manuelle Objekte in der Kontur (`lg-manuelle-in-kontur`) bleiben und sperren ihre Flaeche. `lg-blockdef` ergaenzt bei Altbestand fehlende ATTDEFs (Neudefinition + `_.ATTSYNC`). `LAGER_EXPORT` schreibt NUR `<dwg>_lager.json` nach `DXFM_RESULTS` (Format `ssg-lager` Version 2, kein Python-Schritt; das RFQ-Projekt uebernimmt Mapping und Hand-Abgleich): alle Geschosse, Bereiche, Reihen und Gaenge mit Attributen und voller Geometrie (Konturpunkte, Start/Ende/Mitte, 4 Ecken) plus `kennwerte` je Geschoss und `lager` gesamt (lichte Hoehe, Regal-/Schienenlaenge, Haengeebenen, Gaenge je Art, Belags-/Gitterrostflaeche, Gitterkorb), je Geschoss-Kennwert `herkunft` (Formel + Quelle). Eigener JSON-Schreiber `lg-json-*` ueber getaggte Werte `(OBJ ...)`/`(ARR ...)` (`lg-json-text` rueckt ein, Nicht-ASCII als `\uXXXX`), Kennwerte in reinen Kernen (`lg-kennwerte-geschoss`/`-lager`, `lg-haengeebenen-summen`, `lg-gaenge-je-art`, `lg-reihen-offene-kanten`, `lg-reihen-gitterkorb-berechnen`). **Absturzsicherung unter den Reihen** je Bereich (`UNTER_REIHE` = `gitterrost`/`gitterkorb`/`keine`, Vorgabe `lager.json bereich.unter_reihe`, nur auf Buehnen wirksam): Gitterrost zaehlt die Reihengrundflaeche zur Gitterrostflaeche, Gitterkorb liefert Boden (Laenge x Tiefe) und Seitenflaeche = OFFENE Kantenlaenge x `GITTERKORB_HOEHE_mm` (Kanten an einer direkt anliegenden Nachbarreihe desselben Geschosses, z.B. Ruecken an Ruecken, zaehlen nicht; die Korbhoehe soll spaeter aus den Attributen berechnet werden). Regelwerk-Werte stehen noch Line truncated
|
||||||
| `LagerPruefung.lsp` | LG_REGELN | Regelprofile der Lagerplanung: `cfg/regelwerk/<LAND>.json` laden, `erbt_von` aufloesen (`lg-profil-mischen`), je Regel den STRENGSTEN Wert aller zutreffenden Quellen (`lg-regel-aufloesen`: `art` min/max/wert, `bedingung` gegen einen Kontext - fehlt der Schluessel, konservativ einbezogen -, `tabelle` + `tabellen_schluessel`) mit Protokoll. Jede Pruefregel der Lagerplanung wird genau hier implementiert (Python rendert nur). Alle Startwerte `verifiziert: false` |
|
| `LagerPruefung.lsp` | LG_REGELN | Regelprofile der Lagerplanung: `cfg/stahlbau/regelwerk/<LAND>.json` laden, `erbt_von` aufloesen (`lg-profil-mischen`), je Regel den STRENGSTEN Wert aller zutreffenden Quellen (`lg-regel-aufloesen`: `art` min/max/wert, `bedingung` gegen einen Kontext - fehlt der Schluessel, konservativ einbezogen -, `tabelle` + `tabellen_schluessel`) mit Protokoll. Jede Pruefregel der Lagerplanung wird genau hier implementiert (Python rendert nur). Alle Startwerte `verifiziert: false` |
|
||||||
| `DinFormate.lsp` | DIN_FORMATE | Ersatz fuer das alte ACADSST-Makro `DINFORM.LSP`/`.DCL` (SSG2-Menue "DIN-FORMATE..."): fuegt einen DIN-Rahmen (A0-A3, A4 quer/hoch) und optional einen Schriftkopf (KOPF11, Sprachen DE/EN/FR/IT) per Dialog (`dcl/dinformate.dcl`) ein. Block-DWGs liegen flach in `cfg/rahmen/` (kopiert aus `\\infor-ln\SSG_Tools\ACADSST\KOEPFE` - nur die von DINFORM.LSP tatsaechlich referenzierten Dateien: `A0`/`A1`/`A2`/`A3`/`A4Q`/`A4H.DWG` + `Kopf11`/`Kopf11e`/`Kopf11f`/`Kopf11i.dwg`). Rahmen wird im Zeichenmassstab-Faktor eingefuegt, der Kopf im Faktor/100 (Kopf-DWG ist 100x groesser als die Rahmen-DWGs angelegt) - unveraendert aus dem Original-Massstabsschema uebernommen. Blockdefinitionen werden einmalig per `_.-INSERT ... _X 0` nachgeladen (`dinformate-block-laden`), falls noch nicht in der Zeichnung vorhanden. Lazy geladen ueber `(ssg-ensure "DinFormate")`, Menue: Werkzeuge > Din Formate. |
|
| `DinFormate.lsp` | DIN_FORMATE | Ersatz fuer das alte ACADSST-Makro `DINFORM.LSP`/`.DCL` (SSG2-Menue "DIN-FORMATE..."): fuegt einen DIN-Rahmen (A0-A3, A4 quer/hoch) und optional einen Schriftkopf (KOPF11, Sprachen DE/EN/FR/IT) per Dialog (`dcl/dinformate.dcl`) ein. Block-DWGs liegen flach in `cfg/rahmen/` (kopiert aus `\\infor-ln\SSG_Tools\ACADSST\KOEPFE` - nur die von DINFORM.LSP tatsaechlich referenzierten Dateien: `A0`/`A1`/`A2`/`A3`/`A4Q`/`A4H.DWG` + `Kopf11`/`Kopf11e`/`Kopf11f`/`Kopf11i.dwg`). Rahmen wird im Zeichenmassstab-Faktor eingefuegt, der Kopf im Faktor/100 (Kopf-DWG ist 100x groesser als die Rahmen-DWGs angelegt) - unveraendert aus dem Original-Massstabsschema uebernommen. Blockdefinitionen werden einmalig per `_.-INSERT ... _X 0` nachgeladen (`dinformate-block-laden`), falls noch nicht in der Zeichnung vorhanden. Lazy geladen ueber `(ssg-ensure "DinFormate")`, Menue: Werkzeuge > Din Formate. |
|
||||||
| `DrawPlanquadrate.lsp` | DRAW_PLANQUADRATE, DELETE_PLANQUADRATE, PLANQUADRATE_TOGGLE | Zeichnet auf Z=0 ein Planquadrat-Linienraster (senkrecht/waagerecht), im Abstand/Zaehlschema der aktiven `[Planquadrate]`-Konfiguration aus `cfg/export.cfg` (dieselbe Quelle wie `lib/export_planquadrat.py` fuer den CSV-Export). Bereich kommt NICHT aus den Zeichnungs-Extents, sondern aus derselben Blockmenge wie EXPORTCSV (`csv:collect-export-blocks`, export.lsp; siehe `plq-export-bbox`): Ursprung (Index 1) UND obere Grenze kommen BEIDE aus der tatsaechlichen Bounding-Box jedes Blocks (`csv:get-bbox`, wie `bbox_columns()`/`planquadrat_column()`/`_bbox_min()` in `lib/export_csv.py` bzw. `lib/export_planquadrat.py`), NICHT aus dem reinen Einfuegepunkt - bei einem gedrehten/exzentrisch eingefuegten Block (z.B. ein um 90 Grad gedrehter Kreisel) kann das Bounding-Box-Zentrum weit vom Einfuegepunkt abweichen; Ursprung und Zellzuordnung muessen auf derselben Referenz beruhen, sonst driften sie auseinander (realer Bug, behoben). Reine Hilfsgeometrie (Kreisel-Umfahrungsboegen als eigene Linien, Texte) zaehlt bewusst nicht mit, sonst weicht das Raster vom CSV-Export ab. `x_origin`/`y_origin` ueberschreiben den Ursprung, Fallback auf EXTMIN/EXTMAX falls keine Export-Bloecke vorhanden sind bzw. `csv:get-bbox` fuer einen Block scheitert. Spalten-/Zeilenzahl wird IMMER aufgerundet auf volle Rasterschritte, damit alle senkrechten Linien auf der letzten waagerechten enden und umgekehrt - das Raster bildet immer ein geschlossenes Rechteck. Zaehlung (alphabetisch/numerisch je Achse) als Text am linken/unteren Rand. Das fertige Raster (Linien+Texte) wird per `_.-BLOCK`/`_.INSERT` zu einem einzigen Block `ZZ_PLANQUADRATE` bei (0,0,0) zusammengefasst. Layer aus `cfg/layer.cfg` (`[allgemein]` Key `planquadrate`, Fallback `ZZ_Planquadrate`). DRAW_PLANQUADRATE entfernt vor dem Neuaufbau zuerst einen evtl. vorhandenen Block (`plq-block-entfernen`: INSERTs loeschen + `_-PURGE _B`), DELETE_PLANQUADRATE ruft nur diese Entfernung auf. PLANQUADRATE_TOGGLE ("Planquadrate an/aus", Menue: Konfiguration) prueft per `tblsearch`/`ssget "X"`, ob der Block existiert, und dispatcht auf Zeichnen bzw. Loeschen. Lazy geladen ueber `(ssg-ensure "DrawPlanquadrate")`, nicht in der Core-Ladereihenfolge. Die Planquadrat-SPALTE im CSV-Export (`export_csv.py::planquadrat_column`/`resolve_origins`, `lib/export_planquadrat.py::compute_planquadrat`/`_bbox_min`) rechnet ebenfalls durchgaengig auf Bounding-Box-Basis (nicht nur Einfuegepunkt) und liefert eine SPANNE ("A/1-J/1") statt nur einer Zelle, wenn ein Element mehr als eine Zelle ueberdeckt (Kreisel, lange VF-/GF-Ketten). |
|
| `DrawPlanquadrate.lsp` | DRAW_PLANQUADRATE, DELETE_PLANQUADRATE, PLANQUADRATE_TOGGLE | Zeichnet auf Z=0 ein Planquadrat-Linienraster (senkrecht/waagerecht), im Abstand/Zaehlschema der aktiven `[Planquadrate]`-Konfiguration aus `cfg/export.cfg` (dieselbe Quelle wie `lib/export_planquadrat.py` fuer den CSV-Export). Bereich kommt NICHT aus den Zeichnungs-Extents, sondern aus derselben Blockmenge wie EXPORTCSV (`csv:collect-export-blocks`, export.lsp; siehe `plq-export-bbox`): Ursprung (Index 1) UND obere Grenze kommen BEIDE aus der tatsaechlichen Bounding-Box jedes Blocks (`csv:get-bbox`, wie `bbox_columns()`/`planquadrat_column()`/`_bbox_min()` in `lib/export_csv.py` bzw. `lib/export_planquadrat.py`), NICHT aus dem reinen Einfuegepunkt - bei einem gedrehten/exzentrisch eingefuegten Block (z.B. ein um 90 Grad gedrehter Kreisel) kann das Bounding-Box-Zentrum weit vom Einfuegepunkt abweichen; Ursprung und Zellzuordnung muessen auf derselben Referenz beruhen, sonst driften sie auseinander (realer Bug, behoben). Reine Hilfsgeometrie (Kreisel-Umfahrungsboegen als eigene Linien, Texte) zaehlt bewusst nicht mit, sonst weicht das Raster vom CSV-Export ab. `x_origin`/`y_origin` ueberschreiben den Ursprung, Fallback auf EXTMIN/EXTMAX falls keine Export-Bloecke vorhanden sind bzw. `csv:get-bbox` fuer einen Block scheitert. Spalten-/Zeilenzahl wird IMMER aufgerundet auf volle Rasterschritte, damit alle senkrechten Linien auf der letzten waagerechten enden und umgekehrt - das Raster bildet immer ein geschlossenes Rechteck. Zaehlung (alphabetisch/numerisch je Achse) als Text am linken/unteren Rand. Das fertige Raster (Linien+Texte) wird per `_.-BLOCK`/`_.INSERT` zu einem einzigen Block `ZZ_PLANQUADRATE` bei (0,0,0) zusammengefasst. Layer aus `cfg/layer.cfg` (`[allgemein]` Key `planquadrate`, Fallback `ZZ_Planquadrate`). DRAW_PLANQUADRATE entfernt vor dem Neuaufbau zuerst einen evtl. vorhandenen Block (`plq-block-entfernen`: INSERTs loeschen + `_-PURGE _B`), DELETE_PLANQUADRATE ruft nur diese Entfernung auf. PLANQUADRATE_TOGGLE ("Planquadrate an/aus", Menue: Konfiguration) prueft per `tblsearch`/`ssget "X"`, ob der Block existiert, und dispatcht auf Zeichnen bzw. Loeschen. Lazy geladen ueber `(ssg-ensure "DrawPlanquadrate")`, nicht in der Core-Ladereihenfolge. Die Planquadrat-SPALTE im CSV-Export (`export_csv.py::planquadrat_column`/`resolve_origins`, `lib/export_planquadrat.py::compute_planquadrat`/`_bbox_min`) rechnet ebenfalls durchgaengig auf Bounding-Box-Basis (nicht nur Einfuegepunkt) und liefert eine SPANNE ("A/1-J/1") statt nur einer Zelle, wenn ein Element mehr als eine Zelle ueberdeckt (Kreisel, lange VF-/GF-Ketten). |
|
||||||
|
|
||||||
@@ -223,7 +223,6 @@ Abhaengigkeiten: `ezdxf`, Standard-Library. Benoetigen Umgebungsvariablen (`DXFM
|
|||||||
| `dxf_anlage_export.py` | Gegenstueck zum Scanner: liest eine mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten - je Wrapper genau die Parameter, die auch dessen Edit-Befehl liest (KREISEL_n: Einfuegepunkt, `abstand` exakt aus der Blockdefinition, `drehrichtung` aus DREHRICHTUNG; GF_n: SSG_GF_EDIT + SEITE_AS/ES, endet die GF auf einer Kreisel-Kette, wird dessen Hoehe `hoehe_ende_mm`; VF_n `standard`/`etage`: mubea-Schema wie `vfs-edit-basis-lesen`; VF_n `linienzug`: Journal UNVERAENDERT als `"typ": "linienzug_journal"` - bewusst keine Spec, weil der Bau-Dialog neuer ist als die Spec-Grammatik; uebrige Bloecke als Einzel-Insert ohne `_2D`/`_3D`-Suffix). Reihenfolge Kreisel, VF, GF, Einzelbloecke (VF vor GF wie mubea). Aufruf: `python dxf_anlage_export.py <dxf> <output.json> [--projekt NAME]` — erzeugt `tests/testdata/dematic_arvato.json` aus `Dematic_TST.dxf`. Test `tests/test_dxf_anlage_export.py` |
|
| `dxf_anlage_export.py` | Gegenstueck zum Scanner: liest eine mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten - je Wrapper genau die Parameter, die auch dessen Edit-Befehl liest (KREISEL_n: Einfuegepunkt, `abstand` exakt aus der Blockdefinition, `drehrichtung` aus DREHRICHTUNG; GF_n: SSG_GF_EDIT + SEITE_AS/ES, endet die GF auf einer Kreisel-Kette, wird dessen Hoehe `hoehe_ende_mm`; VF_n `standard`/`etage`: mubea-Schema wie `vfs-edit-basis-lesen`; VF_n `linienzug`: Journal UNVERAENDERT als `"typ": "linienzug_journal"` - bewusst keine Spec, weil der Bau-Dialog neuer ist als die Spec-Grammatik; uebrige Bloecke als Einzel-Insert ohne `_2D`/`_3D`-Suffix). Reihenfolge Kreisel, VF, GF, Einzelbloecke (VF vor GF wie mubea). Aufruf: `python dxf_anlage_export.py <dxf> <output.json> [--projekt NAME]` — erzeugt `tests/testdata/dematic_arvato.json` aus `Dematic_TST.dxf`. Test `tests/test_dxf_anlage_export.py` |
|
||||||
| (`io_zuordnung_pruefen.py`) | **Nicht hier**: die Zuordnung E-Geraete (Sensoren/Aktoren/Motoren) -> Anlagenbauteile (Separator, AS, Kreisel AN8/SP8, Vario-Stationen, Scanner) liegt im Kabeltool-Repo `kabellaengen`: Pruefskript `lib/io_zuordnung_pruefen.py` (`bin\io_zuordnung_pruefen.bat`), Konverter alter `io`-Symbole `lib/altZuNeu.py` (`bin\altZuNeu.bat`), gemeinsames Regelwerk `cfg/io_regeln.json`, Doku `doc/Anwenderdoku_altZuNeu.md`. Die dort erkannten Mechanik-Bloecke sind die dxfmakros-Bloecke (`Separator_SP*`, `AS_Element*`, `AN8_*`/`SP8_*`, `Vario_Motorstation*`/`Vario_Umlenkstation*`, `Scanner*`) - wer sie umbenennt, muss `bauteile` in `io_regeln.json` mitziehen |
|
| (`io_zuordnung_pruefen.py`) | **Nicht hier**: die Zuordnung E-Geraete (Sensoren/Aktoren/Motoren) -> Anlagenbauteile (Separator, AS, Kreisel AN8/SP8, Vario-Stationen, Scanner) liegt im Kabeltool-Repo `kabellaengen`: Pruefskript `lib/io_zuordnung_pruefen.py` (`bin\io_zuordnung_pruefen.bat`), Konverter alter `io`-Symbole `lib/altZuNeu.py` (`bin\altZuNeu.bat`), gemeinsames Regelwerk `cfg/io_regeln.json`, Doku `doc/Anwenderdoku_altZuNeu.md`. Die dort erkannten Mechanik-Bloecke sind die dxfmakros-Bloecke (`Separator_SP*`, `AS_Element*`, `AN8_*`/`SP8_*`, `Vario_Motorstation*`/`Vario_Umlenkstation*`, `Scanner*`) - wer sie umbenennt, muss `bauteile` in `io_regeln.json` mitziehen |
|
||||||
| `hw_materialfluss.py` | HW-Planung: Materialfluss-Skizze aus dem CSV-Export (EXPORTCSV) als neue DXF, flach in XY. Kreisel/Eckrad = geschlossenes Rechteck (Position/Boundingbox, Merkmal `Drehung`; schraeg: Abstand + 800 mm), Punktfolge in Drehrichtung (UZS = Uhrzeigersinn) plus Pfeile; Strecke/GF = Polylinie AS -> Separatoren -> ES ueber `TrackIds` (ES vorn -> umgedreht) plus Endpfeil; `ILS Weiche` = kleiner Kreis; BTMT Beladung = grosser Kreis K1 + kleiner Kreis K2 + Linie, Entladung = kleiner Kreis K1 + grosser Kreis K2 + Linie (K1/K2 per `decode_trans` aus `export_graph.py`, dessen `load_elements` auch die CSV liest). Layer/Farben aus `cfg/layer.cfg` `[hw_planung]` (eigener Mini-Parser, Vorgaben im Code). Test `tests/test_hw_materialfluss.py`. Aufruf: `python hw_materialfluss.py <export.csv> <out_HW.dxf> [--layer-cfg ...]` |
|
| `hw_materialfluss.py` | HW-Planung: Materialfluss-Skizze aus dem CSV-Export (EXPORTCSV) als neue DXF, flach in XY. Kreisel/Eckrad = geschlossenes Rechteck (Position/Boundingbox, Merkmal `Drehung`; schraeg: Abstand + 800 mm), Punktfolge in Drehrichtung (UZS = Uhrzeigersinn) plus Pfeile; Strecke/GF = Polylinie AS -> Separatoren -> ES ueber `TrackIds` (ES vorn -> umgedreht) plus Endpfeil; `ILS Weiche` = kleiner Kreis; BTMT Beladung = grosser Kreis K1 + kleiner Kreis K2 + Linie, Entladung = kleiner Kreis K1 + grosser Kreis K2 + Linie (K1/K2 per `decode_trans` aus `export_graph.py`, dessen `load_elements` auch die CSV liest). Layer/Farben aus `cfg/layer.cfg` `[hw_planung]` (eigener Mini-Parser, Vorgaben im Code). Test `tests/test_hw_materialfluss.py`. Aufruf: `python hw_materialfluss.py <export.csv> <out_HW.dxf> [--layer-cfg ...]` |
|
||||||
| `lager_yaml_export.py` | Lagerplanung: `<dwg>_lager_raw.json` (LAGER_EXPORT) -> `<dwg>_drawing.yaml` (Overlay im Schema der RFQ-Hand-YAML, nur Zeichnungsfelder, plus `_provenance`/`_conflicts`/`_warnings`) und optional `--nachweis` HTML. `--hand <yaml>` gleicht ab (Hand gewinnt; Konflikte bei > 1 % bzw. 0,005). Aggregiert nur, Regeln leben in LISP. Braucht `pyyaml`. Test `tests/test_lager_yaml.py`. Aufruf: `python lager_yaml_export.py <raw.json> <out.yaml> [--hand ...] [--nachweis ...]` |
|
|
||||||
| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `doc/json-input-lisp.md` (Nachfolger des geloeschten `tests/testdata/object_data.md`) — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Gefaellestrecken, die als 3D-LINE auf einem Staustrecken-Layer gezeichnet sind (`GF_LINIE_LAYER`, z.B. `6-SP`), werden in einem zweiten Lesedurchgang zu Modus-1-Eintraegen: Start/Ende werden auf die Ketten der anschliessenden Kreisel verlaengert (gezeichnet ist nur die Staustrecke; `deltaL` reicht von AS- bis ES-Ursprung), AS-Seite aus dem Ausschleuselement am oberen Ende; dieses und Separatoren auf der Achse entfallen als Einzel-Insert (die GF baut beide selbst). Sitzt der AS am UNTEREN Ende, ist es ein Steigfoerderer und wird nur gemeldet (`gf_eintraege_aus_linien`, Test `tests/test_dxf_scan_gf.py`). `--ohne-hoehen` setzt alle Z auf 0, `--kreisel-hoehe X Y Z` gibt einem Kreisel seine Hoehe - die daran haengenden GF bekommen daraus `start_mm.z`/`hoehe_ende_mm`, den Winkel rechnet der Treiber (`dematic_arvato:gf-geometrie`: atan ueber die HORIZONTALE Laenge, ES-Laenge UND -Abfall bei der Einlaufneigung gemessen und iteriert, Staustrecke daraus - die flache ES-Laenge liess steile GF ~144 mm vor der Kette enden - NICHT `gf-winkel-berechnen`, dessen asin bei steilen GF wie im Showroom ~50 statt ~37 Grad liefert; `dematic_arvato:gf-endhoehe-pruefen` meldet `warnung` bei > 5 mm Abweichung von HOEHE_BIS). Flache 2D-Plaene: `--flach` (waagrechte Staustrecke mit AS an genau einem Ende = GF, zerstueckelte Linien werden vereint, ES am unteren Ende wird verbraucht, AS/ES-Seite ohne Namensangabe aus der Lage zur Fahrtrichtung), `--kreisel-achse X1 Y1 X2 Y2` (Kreisel ohne AN8/SP8), Einzelteile auf einer Kreisel-Kette erben dessen Anwender-Hoehe (`sensor_hoehen_von_kreiseln`). Kreisel-Paarung mit Tausch-Nachbesserung auf minimale Abstandssumme (zwei Kreisel auf einer Achse). Genutzt fuer `tests/testdata/showroom_ils.json` (`TEST_SHOWROOM_ILS`). Aufruf: `python dxf_scan_components.py <dxf> <data_dir> <output.json> [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf |
|
| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `doc/json-input-lisp.md` (Nachfolger des geloeschten `tests/testdata/object_data.md`) — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Gefaellestrecken, die als 3D-LINE auf einem Staustrecken-Layer gezeichnet sind (`GF_LINIE_LAYER`, z.B. `6-SP`), werden in einem zweiten Lesedurchgang zu Modus-1-Eintraegen: Start/Ende werden auf die Ketten der anschliessenden Kreisel verlaengert (gezeichnet ist nur die Staustrecke; `deltaL` reicht von AS- bis ES-Ursprung), AS-Seite aus dem Ausschleuselement am oberen Ende; dieses und Separatoren auf der Achse entfallen als Einzel-Insert (die GF baut beide selbst). Sitzt der AS am UNTEREN Ende, ist es ein Steigfoerderer und wird nur gemeldet (`gf_eintraege_aus_linien`, Test `tests/test_dxf_scan_gf.py`). `--ohne-hoehen` setzt alle Z auf 0, `--kreisel-hoehe X Y Z` gibt einem Kreisel seine Hoehe - die daran haengenden GF bekommen daraus `start_mm.z`/`hoehe_ende_mm`, den Winkel rechnet der Treiber (`dematic_arvato:gf-geometrie`: atan ueber die HORIZONTALE Laenge, ES-Laenge UND -Abfall bei der Einlaufneigung gemessen und iteriert, Staustrecke daraus - die flache ES-Laenge liess steile GF ~144 mm vor der Kette enden - NICHT `gf-winkel-berechnen`, dessen asin bei steilen GF wie im Showroom ~50 statt ~37 Grad liefert; `dematic_arvato:gf-endhoehe-pruefen` meldet `warnung` bei > 5 mm Abweichung von HOEHE_BIS). Flache 2D-Plaene: `--flach` (waagrechte Staustrecke mit AS an genau einem Ende = GF, zerstueckelte Linien werden vereint, ES am unteren Ende wird verbraucht, AS/ES-Seite ohne Namensangabe aus der Lage zur Fahrtrichtung), `--kreisel-achse X1 Y1 X2 Y2` (Kreisel ohne AN8/SP8), Einzelteile auf einer Kreisel-Kette erben dessen Anwender-Hoehe (`sensor_hoehen_von_kreiseln`). Kreisel-Paarung mit Tausch-Nachbesserung auf minimale Abstandssumme (zwei Kreisel auf einer Achse). Genutzt fuer `tests/testdata/showroom_ils.json` (`TEST_SHOWROOM_ILS`). Aufruf: `python dxf_scan_components.py <dxf> <data_dir> <output.json> [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf |
|
||||||
|
|
||||||
### Entwickler-Tools (`lib/`) - kein ezdxf, reine Text-/AutoLISP-Verarbeitung
|
### Entwickler-Tools (`lib/`) - kein ezdxf, reine Text-/AutoLISP-Verarbeitung
|
||||||
|
|||||||
+566
-143
@@ -2,8 +2,8 @@
|
|||||||
;; LagerInsert.lsp - Lagerplanung GOH-Buehnenlager (Phase 1: Mengen, 2D)
|
;; LagerInsert.lsp - Lagerplanung GOH-Buehnenlager (Phase 1: Mengen, 2D)
|
||||||
;;
|
;;
|
||||||
;; Erzeugt parametrische Attributbloecke fuer ein mehrgeschossiges
|
;; Erzeugt parametrische Attributbloecke fuer ein mehrgeschossiges
|
||||||
;; Haengewarenlager und sammelt daraus die Mengen fuer die RFQ-YAML
|
;; Haengewarenlager und exportiert daraus die technischen Daten als JSON
|
||||||
;; (Overlay, siehe doc/plan/lager_rfq.md):
|
;; fuer die RFQ-Dokumentation (LAGER_EXPORT, siehe doc/plan/lager_rfq.md):
|
||||||
;;
|
;;
|
||||||
;; LG_GESCHOSS Geschoss-Kopfsymbol, verknuepft mit seiner Belagskontur
|
;; LG_GESCHOSS Geschoss-Kopfsymbol, verknuepft mit seiner Belagskontur
|
||||||
;; LG_BEREICH Lagerbereich (Kontur + Parameter), fuellt sich selbst
|
;; LG_BEREICH Lagerbereich (Kontur + Parameter), fuellt sich selbst
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
;; je Belag aus lager.json belag_schraffur)
|
;; je Belag aus lager.json belag_schraffur)
|
||||||
;;
|
;;
|
||||||
;; Befehle: LG_GESCHOSS, LG_GESCHOSS_AKTIV, LG_GESCHOSS_KOPIEREN, LG_BEREICH,
|
;; Befehle: LG_GESCHOSS, LG_GESCHOSS_AKTIV, LG_GESCHOSS_KOPIEREN, LG_BEREICH,
|
||||||
;; LG_REIHE, LG_GANG, LG_EDIT, LG_REGALE, LAGER_EXPORT, LAGER_HAND_YAML
|
;; LG_REIHE, LG_GANG, LG_EDIT, LG_REGALE, LAGER_EXPORT
|
||||||
;;
|
;;
|
||||||
;; Grundsaetze (CLAUDE.md):
|
;; Grundsaetze (CLAUDE.md):
|
||||||
;; - Alle Werte selbstbeschreibend in mm/Grad, keine Index-Codes.
|
;; - Alle Werte selbstbeschreibend in mm/Grad, keine Index-Codes.
|
||||||
@@ -379,6 +379,7 @@
|
|||||||
("SCHIENEN_JE_GANG" . "") ("QUERGANG_ABSTAND_mm" . "") ("QUERGANG_BREITE_mm" . "")
|
("SCHIENEN_JE_GANG" . "") ("QUERGANG_ABSTAND_mm" . "") ("QUERGANG_BREITE_mm" . "")
|
||||||
("RICHTUNG" . "") ("HAENGEEBENEN" . "") ("BELAG" . "")
|
("RICHTUNG" . "") ("HAENGEEBENEN" . "") ("BELAG" . "")
|
||||||
("RANDGANG_N_mm" . "0") ("RANDGANG_O_mm" . "0") ("RANDGANG_S_mm" . "0") ("RANDGANG_W_mm" . "0")
|
("RANDGANG_N_mm" . "0") ("RANDGANG_O_mm" . "0") ("RANDGANG_S_mm" . "0") ("RANDGANG_W_mm" . "0")
|
||||||
|
("UNTER_REIHE" . "") ("GITTERKORB_HOEHE_mm" . "")
|
||||||
("RESTBREITE_mm" . "")))
|
("RESTBREITE_mm" . "")))
|
||||||
|
|
||||||
(setq *lg-schema-reihe*
|
(setq *lg-schema-reihe*
|
||||||
@@ -621,6 +622,8 @@
|
|||||||
("richtung" "RICHTUNG" "grad" nil)
|
("richtung" "RICHTUNG" "grad" nil)
|
||||||
("ebenen" "HAENGEEBENEN" "ebenen" nil)
|
("ebenen" "HAENGEEBENEN" "ebenen" nil)
|
||||||
("belag" "BELAG" "wahl" belag)
|
("belag" "BELAG" "wahl" belag)
|
||||||
|
("unter" "UNTER_REIHE" "wahl" unter)
|
||||||
|
("korbhoehe" "GITTERKORB_HOEHE_mm" "mm" nil)
|
||||||
("rand_n" "RANDGANG_N_mm" "mm" nil)
|
("rand_n" "RANDGANG_N_mm" "mm" nil)
|
||||||
("rand_o" "RANDGANG_O_mm" "mm" nil)
|
("rand_o" "RANDGANG_O_mm" "mm" nil)
|
||||||
("rand_s" "RANDGANG_S_mm" "mm" nil)
|
("rand_s" "RANDGANG_S_mm" "mm" nil)
|
||||||
@@ -653,6 +656,7 @@
|
|||||||
((eq sym 'brand) (lg-vorgabe '("brandgefaehrdungen") '("normal" "erhoeht_mit_loeschanlage" "erhoeht_ohne_loeschanlage")))
|
((eq sym 'brand) (lg-vorgabe '("brandgefaehrdungen") '("normal" "erhoeht_mit_loeschanlage" "erhoeht_ohne_loeschanlage")))
|
||||||
((eq sym 'reihen) '("1" "2"))
|
((eq sym 'reihen) '("1" "2"))
|
||||||
((eq sym 'gangart) '("gang" "randgang" "quergang"))
|
((eq sym 'gangart) '("gang" "randgang" "quergang"))
|
||||||
|
((eq sym 'unter) *lg-unter-reihe-werte*)
|
||||||
((eq sym 'geschosse) (mapcar '(lambda (g) (itoa (cadr g))) (lg-geschosse)))
|
((eq sym 'geschosse) (mapcar '(lambda (g) (itoa (cadr g))) (lg-geschosse)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -1174,12 +1178,36 @@
|
|||||||
(cons "RICHTUNG" (lg-mm-str (if pts (lg-kontur-richtung pts) 0.0)))
|
(cons "RICHTUNG" (lg-mm-str (if pts (lg-kontur-richtung pts) 0.0)))
|
||||||
(cons "HAENGEEBENEN" (lg-vorgabe '("reihe" "haengeebenen") "2300/1200;1100/1100"))
|
(cons "HAENGEEBENEN" (lg-vorgabe '("reihe" "haengeebenen") "2300/1200;1100/1100"))
|
||||||
(cons "BELAG" (lg-vorgabe '("bereich" "belag") "spanplatte"))
|
(cons "BELAG" (lg-vorgabe '("bereich" "belag") "spanplatte"))
|
||||||
|
(cons "UNTER_REIHE" (lg-unter-reihe-vorgabe))
|
||||||
|
(cons "GITTERKORB_HOEHE_mm" (lg-mm-str (lg-zahl (lg-vorgabe '("bereich" "gitterkorb_hoehe_mm") 500))))
|
||||||
(cons "RANDGANG_N_mm" (lg-mm-str (lg-zahl (lg-vorgabe '("bereich" "randgang_mm" "n") 0))))
|
(cons "RANDGANG_N_mm" (lg-mm-str (lg-zahl (lg-vorgabe '("bereich" "randgang_mm" "n") 0))))
|
||||||
(cons "RANDGANG_O_mm" (lg-mm-str (lg-zahl (lg-vorgabe '("bereich" "randgang_mm" "o") 0))))
|
(cons "RANDGANG_O_mm" (lg-mm-str (lg-zahl (lg-vorgabe '("bereich" "randgang_mm" "o") 0))))
|
||||||
(cons "RANDGANG_S_mm" (lg-mm-str (lg-zahl (lg-vorgabe '("bereich" "randgang_mm" "s") 0))))
|
(cons "RANDGANG_S_mm" (lg-mm-str (lg-zahl (lg-vorgabe '("bereich" "randgang_mm" "s") 0))))
|
||||||
(cons "RANDGANG_W_mm" (lg-mm-str (lg-zahl (lg-vorgabe '("bereich" "randgang_mm" "w") 0)))))
|
(cons "RANDGANG_W_mm" (lg-mm-str (lg-zahl (lg-vorgabe '("bereich" "randgang_mm" "w") 0)))))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
;; Absturzsicherung unter den Regalreihen (Attribut UNTER_REIHE am Bereich):
|
||||||
|
;; gitterrost = Grundflaeche der Reihe als Gitterrost, gitterkorb = Korb mit
|
||||||
|
;; Boden UND Seitenwaenden zum Geschoss darunter, keine = offen.
|
||||||
|
(setq *lg-unter-reihe-werte* '("gitterrost" "gitterkorb" "keine"))
|
||||||
|
|
||||||
|
(defun lg-unter-reihe-vorgabe ( / v)
|
||||||
|
(setq v (lg-vorgabe '("bereich" "unter_reihe") "gitterrost"))
|
||||||
|
(if (member v *lg-unter-reihe-werte*) v "gitterrost")
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Reiner Kern: wirksamer Wert unter einer Reihe. wert = UNTER_REIHE des
|
||||||
|
;; Bereichs (nil/leer/unbekannt -> vorgabe), buehne-p = nil auf Hallenboden
|
||||||
|
;; (dort gibt es nichts abzusichern -> "keine").
|
||||||
|
(defun lg-unter-reihe-wert (wert vorgabe buehne-p)
|
||||||
|
(cond
|
||||||
|
((not buehne-p) "keine")
|
||||||
|
((member wert *lg-unter-reihe-werte*) wert)
|
||||||
|
((member vorgabe *lg-unter-reihe-werte*) vorgabe)
|
||||||
|
(T "gitterrost")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
;; Randgang-Breiten eines Bereichs (Attribute) fuer lg-fuellung-berechnen.
|
;; Randgang-Breiten eines Bereichs (Attribute) fuer lg-fuellung-berechnen.
|
||||||
;; Fehlt ein Attribut (Altbestand), gilt 0.
|
;; Fehlt ein Attribut (Altbestand), gilt 0.
|
||||||
(defun lg-bereich-rand (a)
|
(defun lg-bereich-rand (a)
|
||||||
@@ -2011,11 +2039,21 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
;; ============================================================
|
;; ============================================================
|
||||||
;; EXPORT (lager_raw.json)
|
;; EXPORT (<dwg>_lager.json)
|
||||||
;; ============================================================
|
;; ============================================================
|
||||||
|
;; Eine JSON-Datei mit den technischen Daten des Lagers fuer die
|
||||||
|
;; RFQ-Dokumentation (eigenes Projekt): alle Objekte mit Attributen und
|
||||||
|
;; voller Geometrie (WCS, mm) plus Kennwerte je Geschoss und fuer das ganze
|
||||||
|
;; Lager, jeder Geschoss-Kennwert mit Formel und Quelle (herkunft).
|
||||||
|
;; Schema und Formeln: doc/plan/lager_rfq.md. Die Kennwerte entstehen hier
|
||||||
|
;; in reinen Kernen (getestet) - fachliche Regeln leben in LISP.
|
||||||
|
;;
|
||||||
|
;; Datenform: Objekte als (OBJ (schluessel . wert) ...), Arrays als
|
||||||
|
;; (ARR wert ...); lg-j liest ein Feld, lg-j-setzen setzt es.
|
||||||
|
|
||||||
;; --- JSON-Schreiber (rein, getestet) ---
|
;; --- JSON-Schreiber (rein, getestet) ---
|
||||||
;; Werte: nil -> null, T -> true, String, Ganz-/Fliesszahl, (ROH "json").
|
;; Werte: nil -> null, T -> true, FALSE -> false, String, Ganz-/Fliesszahl,
|
||||||
|
;; (ROH "json"), (OBJ ...) -> Objekt, (ARR ...) -> Array.
|
||||||
(defun lg-json-zahl (w / s)
|
(defun lg-json-zahl (w / s)
|
||||||
(setq s (rtos w 2 3))
|
(setq s (rtos w 2 3))
|
||||||
(if (vl-string-search "." s)
|
(if (vl-string-search "." s)
|
||||||
@@ -2025,141 +2063,564 @@
|
|||||||
(if (= s "-0") "0" s)
|
(if (= s "-0") "0" s)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(defun lg-hex4 (n / h erg)
|
||||||
|
(setq h "0123456789abcdef" erg "")
|
||||||
|
(repeat 4
|
||||||
|
(setq erg (strcat (substr h (1+ (rem n 16)) 1) erg) n (/ n 16)))
|
||||||
|
erg
|
||||||
|
)
|
||||||
|
|
||||||
|
;; String als JSON-Text. Zeichen ausserhalb ASCII (Umlaute in einer
|
||||||
|
;; Bezeichnung) als \uXXXX, damit die Datei unabhaengig von der Codepage
|
||||||
|
;; gueltiges UTF-8 bleibt.
|
||||||
|
(defun lg-json-str (s / roh i c erg)
|
||||||
|
(setq roh (ssg-json-escape s) erg "" i 1)
|
||||||
|
(while (<= i (strlen roh))
|
||||||
|
(setq c (substr roh i 1))
|
||||||
|
(setq erg (strcat erg (if (> (ascii c) 127) (strcat "\\u" (lg-hex4 (ascii c))) c))
|
||||||
|
i (1+ i)))
|
||||||
|
(strcat "\"" erg "\"")
|
||||||
|
)
|
||||||
|
|
||||||
(defun lg-json-wert (v)
|
(defun lg-json-wert (v)
|
||||||
(cond
|
(cond
|
||||||
((null v) "null")
|
((null v) "null")
|
||||||
((eq v T) "true")
|
((eq v T) "true")
|
||||||
((= (type v) 'STR) (strcat "\"" (ssg-json-escape v) "\""))
|
((eq v 'FALSE) "false")
|
||||||
|
((= (type v) 'STR) (lg-json-str v))
|
||||||
((= (type v) 'INT) (itoa v))
|
((= (type v) 'INT) (itoa v))
|
||||||
((= (type v) 'REAL) (lg-json-zahl v))
|
((= (type v) 'REAL) (lg-json-zahl v))
|
||||||
((and (listp v) (eq (car v) 'ROH)) (cadr v))
|
((and (listp v) (eq (car v) 'ROH)) (cadr v))
|
||||||
(T (strcat "\"" (ssg-json-escape (vl-princ-to-string v)) "\""))
|
((and (listp v) (eq (car v) 'OBJ)) (lg-json-obj (cdr v)))
|
||||||
|
((and (listp v) (eq (car v) 'ARR))
|
||||||
|
(strcat "[" (ssg-join (mapcar 'lg-json-wert (cdr v)) ", ") "]"))
|
||||||
|
(T (lg-json-str (vl-princ-to-string v)))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
(defun lg-json-obj (paare)
|
(defun lg-json-obj (paare)
|
||||||
(strcat "{"
|
(strcat "{"
|
||||||
(ssg-join (mapcar '(lambda (p) (strcat "\"" (car p) "\": " (lg-json-wert (cdr p)))) paare)
|
(ssg-join (mapcar '(lambda (p) (strcat (lg-json-str (car p)) ": " (lg-json-wert (cdr p)))) paare)
|
||||||
", ")
|
", ")
|
||||||
"}")
|
"}")
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Liste bereits gerenderter JSON-Texte als Array (ein Element je Zeile).
|
(defun lg-json-container-p (v)
|
||||||
(defun lg-json-arr (texte einrueckung)
|
(and v (listp v) (member (car v) '(OBJ ARR)))
|
||||||
(if texte
|
|
||||||
(strcat "[\n" einrueckung (ssg-join texte (strcat ",\n" einrueckung)) "\n" (substr einrueckung 3) "]")
|
|
||||||
"[]")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
(defun lg-json-zahlen (zahlen)
|
;; Anzahl Blattwerte eines Werts (Mass fuer "passt in eine Zeile").
|
||||||
(list 'ROH (strcat "[" (ssg-join (mapcar 'lg-json-wert zahlen) ", ") "]"))
|
(defun lg-json-blaetter (v)
|
||||||
|
(cond
|
||||||
|
((not (lg-json-container-p v)) 1)
|
||||||
|
((eq (car v) 'OBJ) (apply '+ (cons 0 (mapcar '(lambda (p) (lg-json-blaetter (cdr p))) (cdr v)))))
|
||||||
|
(T (apply '+ (cons 0 (mapcar 'lg-json-blaetter (cdr v)))))
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
(defun lg-json-ebenen (s)
|
;; Zahl, null oder Array nur daraus (Punkte, Punktlisten, bbox).
|
||||||
(list 'ROH
|
(defun lg-json-zahlen-p (v)
|
||||||
(strcat "["
|
(cond
|
||||||
(ssg-join (mapcar '(lambda (e) (lg-json-obj (list (cons "schienenhoehe_mm" (car e))
|
((or (null v) (numberp v)) T)
|
||||||
(cons "warenlaenge_mm" (cadr e)))))
|
((and (listp v) (eq (car v) 'ARR)) (vl-every 'lg-json-zahlen-p (cdr v)))
|
||||||
(lg-haengeebenen-parse s))
|
(T nil)
|
||||||
", ")
|
)
|
||||||
"]"))
|
)
|
||||||
|
|
||||||
|
;; Eingerueckter JSON-Text. Zahlenreihen (Punkte, Konturen) und kleine
|
||||||
|
;; Container (bis *lg-json-inline-max* Blattwerte) bleiben einzeilig, alles
|
||||||
|
;; andere bekommt je Eintrag eine Zeile.
|
||||||
|
(setq *lg-json-inline-max* 12)
|
||||||
|
|
||||||
|
(defun lg-json-text (v einr / innen zeilen obj-p)
|
||||||
|
(if (or (not (lg-json-container-p v))
|
||||||
|
(lg-json-zahlen-p v)
|
||||||
|
(<= (lg-json-blaetter v) *lg-json-inline-max*))
|
||||||
|
(lg-json-wert v)
|
||||||
|
(progn
|
||||||
|
(setq innen (strcat einr " ") obj-p (eq (car v) 'OBJ))
|
||||||
|
(setq zeilen
|
||||||
|
(if obj-p
|
||||||
|
(mapcar '(lambda (p) (strcat innen (lg-json-str (car p)) ": " (lg-json-text (cdr p) innen))) (cdr v))
|
||||||
|
(mapcar '(lambda (x) (strcat innen (lg-json-text x innen))) (cdr v))))
|
||||||
|
(if zeilen
|
||||||
|
(strcat (if obj-p "{" "[") "\n" (ssg-join zeilen ",\n") "\n" einr (if obj-p "}" "]"))
|
||||||
|
(if obj-p "{}" "[]")))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; --- Zugriff auf OBJ-Records ---
|
||||||
|
(defun lg-j (obj key) (cdr (assoc key (cdr obj))))
|
||||||
|
|
||||||
|
(defun lg-j-setzen (obj key wert / alt)
|
||||||
|
(if (setq alt (assoc key (cdr obj)))
|
||||||
|
(cons 'OBJ (subst (cons key wert) alt (cdr obj)))
|
||||||
|
(cons 'OBJ (append (cdr obj) (list (cons key wert)))))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun lg-j-pkte (pts) (cons 'ARR (mapcar '(lambda (p) (cons 'ARR p)) pts)))
|
||||||
|
(defun lg-j-bbox (bb) (if bb (cons 'ARR (append (car bb) (cadr bb)))))
|
||||||
|
(defun lg-n (v) (if (numberp v) (float v) 0.0))
|
||||||
|
|
||||||
|
(defun lg-j-ebenen (s)
|
||||||
|
(cons 'ARR
|
||||||
|
(mapcar '(lambda (e) (list 'OBJ (cons "schienenhoehe_mm" (car e)) (cons "warenlaenge_mm" (cadr e))))
|
||||||
|
(lg-haengeebenen-parse s)))
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Attributwert als Zahl bzw. Ganzzahl (nil, wenn leer).
|
;; Attributwert als Zahl bzw. Ganzzahl (nil, wenn leer).
|
||||||
(defun lg-a-zahl (a tag) (lg-zahl (cdr (assoc tag a))))
|
(defun lg-a-zahl (a tag) (lg-zahl (cdr (assoc tag a))))
|
||||||
(defun lg-a-int (a tag / w) (if (setq w (lg-zahl (cdr (assoc tag a)))) (fix w)))
|
(defun lg-a-int (a tag / w) (if (setq w (lg-zahl (cdr (assoc tag a)))) (fix w)))
|
||||||
|
|
||||||
(defun lg-export-geschoss (g / a k pts bb)
|
;; Buehne = Belag vorhanden und kein Hallenboden. Rein.
|
||||||
(setq a (caddr g) pts (cadddr g) bb (ssg-poly-bbox pts)
|
(defun lg-buehne-p (belag)
|
||||||
k (lg-xdata-wert (car g) "kontur"))
|
(and (= (type belag) 'STR) (/= belag "") (/= (strcase belag T) "hallenboden"))
|
||||||
(lg-json-obj
|
|
||||||
(list (cons "nr" (cadr g))
|
|
||||||
(cons "bezeichnung" (cdr (assoc "BEZEICHNUNG" a)))
|
|
||||||
(cons "hoehe_belag_mm" (lg-a-zahl a "HOEHE_BELAG_mm"))
|
|
||||||
(cons "konstr_hoehe_mm" (lg-a-zahl a "KONSTR_HOEHE_mm"))
|
|
||||||
(cons "lichte_hoehe_mm" (lg-a-zahl a "LICHTE_HOEHE_mm"))
|
|
||||||
(cons "belag_art" (cdr (assoc "BELAG_ART" a)))
|
|
||||||
(cons "personen" (lg-a-int a "PERSONEN"))
|
|
||||||
(cons "brandgefaehrdung" (cdr (assoc "BRANDGEFAEHRDUNG" a)))
|
|
||||||
(cons "kontur_flaeche_mm2" (if pts (ssg-poly-flaeche pts)))
|
|
||||||
(cons "kontur_umfang_mm" (if pts (ssg-poly-umfang pts)))
|
|
||||||
(cons "kontur_bbox" (if bb (lg-json-zahlen (append (car bb) (cadr bb)))))
|
|
||||||
(cons "handle" (lg-handle (car g)))
|
|
||||||
(cons "kontur_handle" k)))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
(defun lg-export-bereich (e / a k pts bb)
|
;; --- Reine Kerne der Kennwerte (getestet) ---
|
||||||
(setq a (ssg-attrib-read e)
|
|
||||||
k (lg-ent-aus-handle (lg-xdata-wert e "kontur"))
|
;; Regallaenge je Haengeebene. reihen = Reihen-Records mit laenge_mm und
|
||||||
pts (if k (ssg-lwpoly-punkte k))
|
;; haengeebenen; jede Reihe traegt ihre Laenge in jede ihrer Ebenen ein.
|
||||||
bb (ssg-poly-bbox pts))
|
;; Rueckgabe (ARR (OBJ schienenhoehe_mm warenlaenge_mm reihen regallaenge_mm)
|
||||||
(lg-json-obj
|
;; ...), nach Schienenhoehe absteigend.
|
||||||
(list (cons "nr" (lg-a-int a "NR"))
|
(defun lg-haengeebenen-summen (reihen / erg key alt l)
|
||||||
(cons "geschoss" (lg-a-int a "GESCHOSS"))
|
(setq erg nil)
|
||||||
(cons "gangbreite_mm" (lg-a-zahl a "GANGBREITE_mm"))
|
(foreach r reihen
|
||||||
(cons "regaltiefe_mm" (lg-a-zahl a "REGALTIEFE_mm"))
|
(setq l (lg-n (lg-j r "laenge_mm")))
|
||||||
(cons "reihen_je_gang" (lg-a-int a "REIHEN_JE_GANG"))
|
(foreach e (cdr (lg-j r "haengeebenen"))
|
||||||
(cons "schienen_je_gang" (lg-a-int a "SCHIENEN_JE_GANG"))
|
(setq key (list (lg-n (lg-j e "schienenhoehe_mm")) (lg-n (lg-j e "warenlaenge_mm")))
|
||||||
(cons "quergang_abstand_mm" (lg-a-zahl a "QUERGANG_ABSTAND_mm"))
|
alt (assoc key erg))
|
||||||
(cons "quergang_breite_mm" (lg-a-zahl a "QUERGANG_BREITE_mm"))
|
(setq erg (if alt
|
||||||
(cons "richtung_grad" (lg-a-zahl a "RICHTUNG"))
|
(subst (list key (1+ (cadr alt)) (+ (caddr alt) l)) alt erg)
|
||||||
(cons "haengeebenen" (lg-json-ebenen (cdr (assoc "HAENGEEBENEN" a))))
|
(cons (list key 1 l) erg)))))
|
||||||
(cons "belag" (cdr (assoc "BELAG" a)))
|
(cons 'ARR
|
||||||
(cons "randgang_mm" (list 'ROH (lg-json-obj
|
(mapcar '(lambda (x) (list 'OBJ (cons "schienenhoehe_mm" (car (car x)))
|
||||||
(mapcar '(lambda (r) (cons (strcase (car r) T) (cdr r)))
|
(cons "warenlaenge_mm" (cadr (car x)))
|
||||||
(lg-bereich-rand a)))))
|
(cons "reihen" (cadr x))
|
||||||
(cons "restbreite_mm" (lg-a-zahl a "RESTBREITE_mm"))
|
(cons "regallaenge_mm" (caddr x))))
|
||||||
(cons "kontur_flaeche_mm2" (if pts (ssg-poly-flaeche pts)))
|
(vl-sort erg '(lambda (a b) (if (equal (car (car a)) (car (car b)) 1e-6)
|
||||||
(cons "kontur_bbox" (if bb (lg-json-zahlen (append (car bb) (cadr bb)))))
|
(> (cadr (car a)) (cadr (car b)))
|
||||||
(cons "handle" (lg-handle e))))
|
(> (car (car a)) (car (car b))))))))
|
||||||
)
|
)
|
||||||
|
|
||||||
(defun lg-export-linie (e art / a ed)
|
;; Gaenge je ART: (OBJ ("gang" . (OBJ anzahl laenge_mm flaeche_mm2)) ...),
|
||||||
(setq a (ssg-attrib-read e) ed (entget e))
|
;; gang/quergang/randgang immer vorhanden, weitere Arten dahinter.
|
||||||
(lg-json-obj
|
(defun lg-gaenge-je-art (gaenge / erg art x l f)
|
||||||
|
(setq erg (mapcar '(lambda (a) (list a 0 0.0 0.0)) '("gang" "quergang" "randgang")))
|
||||||
|
(foreach g gaenge
|
||||||
|
(setq art (cond ((lg-j g "art")) ("unbekannt"))
|
||||||
|
x (assoc art erg)
|
||||||
|
l (lg-n (lg-j g "laenge_mm"))
|
||||||
|
f (* l (lg-n (lg-j g "breite_mm"))))
|
||||||
|
(setq erg (if x
|
||||||
|
(subst (list art (1+ (cadr x)) (+ (caddr x) l) (+ (cadddr x) f)) x erg)
|
||||||
|
(append erg (list (list art 1 l f))))))
|
||||||
|
(cons 'OBJ
|
||||||
|
(mapcar '(lambda (x) (cons (car x) (list 'OBJ (cons "anzahl" (cadr x))
|
||||||
|
(cons "laenge_mm" (caddr x))
|
||||||
|
(cons "flaeche_mm2" (cadddr x)))))
|
||||||
|
erg))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Die vier Kanten eines Rechtecks aus lg-linie-polygon, in fester
|
||||||
|
;; Reihenfolge: 1-2 laengs, 2-3 stirn, 3-4 laengs, 4-1 stirn.
|
||||||
|
(defun lg-rechteck-kanten (ecken)
|
||||||
|
(list (list (nth 0 ecken) (nth 1 ecken)) (list (nth 1 ecken) (nth 2 ecken))
|
||||||
|
(list (nth 2 ecken) (nth 3 ecken)) (list (nth 3 ecken) (nth 0 ecken)))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun lg-bbox-beruehrt-p (a b tol)
|
||||||
|
(and a b
|
||||||
|
(<= (car (car b)) (+ (car (cadr a)) tol)) (<= (car (car a)) (+ (car (cadr b)) tol))
|
||||||
|
(<= (cadr (car b)) (+ (cadr (cadr a)) tol)) (<= (cadr (car a)) (+ (cadr (cadr b)) tol)))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Offener Teil der Kante (p q): Laenge minus die Abschnitte, auf denen eine
|
||||||
|
;; Kante eines Nachbar-Rechtecks kollinear (Abstand < tol) aufliegt.
|
||||||
|
(defun lg-kante-offen (kante nachbarn tol / p q len ux uy zu c d dx dy dl t1 t2 lo hi)
|
||||||
|
(setq p (car kante) q (cadr kante) zu nil
|
||||||
|
len (distance (list (car p) (cadr p)) (list (car q) (cadr q))))
|
||||||
|
(if (< len 1e-9)
|
||||||
|
0.0
|
||||||
|
(progn
|
||||||
|
(setq ux (/ (- (car q) (car p)) len) uy (/ (- (cadr q) (cadr p)) len))
|
||||||
|
(foreach f nachbarn
|
||||||
|
(foreach k (lg-rechteck-kanten f)
|
||||||
|
(setq c (car k) d (cadr k)
|
||||||
|
dx (- (car d) (car c)) dy (- (cadr d) (cadr c))
|
||||||
|
dl (sqrt (+ (* dx dx) (* dy dy))))
|
||||||
|
(if (and (> dl 1e-9)
|
||||||
|
(< (abs (- (* ux dy) (* uy dx))) (* 1e-4 dl)) ; parallel
|
||||||
|
(< (abs (- (* ux (- (cadr c) (cadr p))) (* uy (- (car c) (car p))))) tol)) ; gleiche Linie
|
||||||
|
(progn
|
||||||
|
(setq t1 (+ (* ux (- (car c) (car p))) (* uy (- (cadr c) (cadr p))))
|
||||||
|
t2 (+ (* ux (- (car d) (car p))) (* uy (- (cadr d) (cadr p))))
|
||||||
|
lo (max 0.0 (min t1 t2))
|
||||||
|
hi (min len (max t1 t2)))
|
||||||
|
(if (> (- hi lo) tol) (setq zu (cons (list lo hi) zu)))))))
|
||||||
|
(apply '+ (cons 0.0 (mapcar '(lambda (i) (- (cadr i) (car i)))
|
||||||
|
(ssg-intervalle-minus (list (list 0.0 len)) zu))))))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Offene Kantenlaenge je Reihe. ecken-liste = je Reihe die 4 Ecken (2D)
|
||||||
|
;; aus lg-linie-polygon. Eine Kante ist dort zu, wo eine Kante einer ANDEREN
|
||||||
|
;; Reihe kollinear darauf liegt (z.B. Ruecken an Ruecken). Rueckgabe je
|
||||||
|
;; Reihe (offen-laengs offen-stirn) in mm.
|
||||||
|
(defun lg-reihen-offene-kanten (ecken-liste tol / bbs erg i j k bb nachbarn l s o)
|
||||||
|
(setq bbs (mapcar 'ssg-poly-bbox ecken-liste) erg nil i 0)
|
||||||
|
(foreach e ecken-liste
|
||||||
|
(setq bb (nth i bbs) nachbarn nil j 0 l 0.0 s 0.0 k 0)
|
||||||
|
(foreach f ecken-liste
|
||||||
|
(if (and (/= i j) (lg-bbox-beruehrt-p bb (nth j bbs) tol))
|
||||||
|
(setq nachbarn (cons f nachbarn)))
|
||||||
|
(setq j (1+ j)))
|
||||||
|
(foreach kante (lg-rechteck-kanten e)
|
||||||
|
(setq o (lg-kante-offen kante nachbarn tol))
|
||||||
|
(if (= 0 (rem k 2)) (setq l (+ l o)) (setq s (+ s o)))
|
||||||
|
(setq k (1+ k)))
|
||||||
|
(setq erg (cons (list l s) erg) i (1+ i)))
|
||||||
|
(reverse erg)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Gitterkorb der Reihen EINES Geschosses vervollstaendigen: Reihen mit
|
||||||
|
;; gitterkorb (OBJ hoehe_mm) bekommen Boden (Laenge x Tiefe), offene Kanten
|
||||||
|
;; (gegen alle Reihen des Geschosses) und Seitenflaeche (offen x Hoehe).
|
||||||
|
(defun lg-reihen-gitterkorb-berechnen (reihen tol / offen)
|
||||||
|
(if (vl-some '(lambda (r) (lg-j r "gitterkorb")) reihen)
|
||||||
|
(progn
|
||||||
|
(setq offen (lg-reihen-offene-kanten
|
||||||
|
(mapcar '(lambda (r) (mapcar 'cdr (cdr (lg-j r "ecken")))) reihen) tol))
|
||||||
|
(mapcar '(lambda (r o / gk h l b)
|
||||||
|
(if (setq gk (lg-j r "gitterkorb"))
|
||||||
|
(progn
|
||||||
|
(setq h (lg-n (lg-j gk "hoehe_mm"))
|
||||||
|
l (lg-n (lg-j r "laenge_mm"))
|
||||||
|
b (lg-n (lg-j r "tiefe_mm")))
|
||||||
|
(lg-j-setzen r "gitterkorb"
|
||||||
|
(list 'OBJ (cons "hoehe_mm" (lg-j gk "hoehe_mm"))
|
||||||
|
(cons "bodenflaeche_mm2" (* l b))
|
||||||
|
(cons "offen_laengs_mm" (car o))
|
||||||
|
(cons "offen_stirn_mm" (cadr o))
|
||||||
|
(cons "seitenflaeche_mm2" (* h (+ (car o) (cadr o)))))))
|
||||||
|
r))
|
||||||
|
reihen offen))
|
||||||
|
reihen)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun lg-herkunft (key formel quelle)
|
||||||
|
(cons key (list 'OBJ (cons "formel" formel) (cons "quelle" quelle)))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Kennwerte eines Geschosses. g = Geschoss-Record, nx = Record des
|
||||||
|
;; naechsthoeheren Geschosses (nil = oberstes), reihen/gaenge = Records
|
||||||
|
;; dieses Geschosses (Reihen mit unter_reihe/gitterkorb), n-bereiche =
|
||||||
|
;; Anzahl Bereiche. Rueckgabe (kennwerte herkunft), beide OBJ.
|
||||||
|
(defun lg-kennwerte-geschoss (g nx reihen gaenge n-bereiche / nrs q qr buehne hk lichte regal grund
|
||||||
|
schienen gitter-r korb gk l f belag-g gitter-g belag gitter)
|
||||||
|
(setq nrs (vl-princ-to-string (lg-j g "nr"))
|
||||||
|
q (strcat "LG_GESCHOSS " nrs)
|
||||||
|
qr (strcat (itoa (length reihen)) " Regalreihe(n) LG_REIHE_* Geschoss " nrs)
|
||||||
|
buehne (lg-buehne-p (lg-j g "belag_art"))
|
||||||
|
hk nil)
|
||||||
|
;; lichte Hoehe: Vorgabe am Geschoss, sonst aus dem Geschoss darueber
|
||||||
|
(cond
|
||||||
|
((numberp (lg-j g "lichte_hoehe_mm"))
|
||||||
|
(setq lichte (lg-j g "lichte_hoehe_mm")
|
||||||
|
hk (cons (lg-herkunft "lichte_hoehe_mm" "LICHTE_HOEHE_mm (Vorgabe am Geschoss)" q) hk)))
|
||||||
|
(nx
|
||||||
|
(setq lichte (- (lg-n (lg-j nx "hoehe_belag_mm")) (lg-n (lg-j nx "konstr_hoehe_mm"))
|
||||||
|
(lg-n (lg-j g "hoehe_belag_mm")))
|
||||||
|
hk (cons (lg-herkunft "lichte_hoehe_mm"
|
||||||
|
"HOEHE_BELAG_mm darueber - KONSTR_HOEHE_mm darueber - eigene HOEHE_BELAG_mm"
|
||||||
|
(strcat q " / " (vl-princ-to-string (lg-j nx "nr"))))
|
||||||
|
hk)))
|
||||||
|
(T (setq lichte nil))
|
||||||
|
)
|
||||||
|
;; Regalreihen
|
||||||
|
(setq regal 0.0 grund 0.0 schienen 0.0 gitter-r 0.0 korb (list 0 0.0 0.0 0.0 0.0))
|
||||||
|
(foreach r reihen
|
||||||
|
(setq l (lg-n (lg-j r "laenge_mm"))
|
||||||
|
f (* l (lg-n (lg-j r "tiefe_mm"))))
|
||||||
|
(setq regal (+ regal l) grund (+ grund f)
|
||||||
|
schienen (+ schienen (* l (if (numberp (lg-j r "schienen")) (lg-j r "schienen") 1))))
|
||||||
|
(cond
|
||||||
|
((equal (lg-j r "unter_reihe") "gitterrost") (setq gitter-r (+ gitter-r f)))
|
||||||
|
((setq gk (lg-j r "gitterkorb"))
|
||||||
|
(setq korb (list (1+ (nth 0 korb))
|
||||||
|
(+ (nth 1 korb) (lg-n (lg-j gk "bodenflaeche_mm2")))
|
||||||
|
(+ (nth 2 korb) (lg-n (lg-j gk "seitenflaeche_mm2")))
|
||||||
|
(+ (nth 3 korb) (lg-n (lg-j gk "offen_laengs_mm")))
|
||||||
|
(+ (nth 4 korb) (lg-n (lg-j gk "offen_stirn_mm")))))))
|
||||||
|
)
|
||||||
|
(setq hk (append (reverse
|
||||||
|
(list (lg-herkunft "regallaenge_mm" "Summe LAENGE der Regalreihen" qr)
|
||||||
|
(lg-herkunft "regalgrundflaeche_mm2" "Summe LAENGE x TIEFE_mm der Regalreihen" qr)
|
||||||
|
(lg-herkunft "schienenlaenge_mm" "Summe LAENGE x SCHIENEN der Regalreihen" qr)
|
||||||
|
(lg-herkunft "haengeebenen" "je Schienenhoehe/Warenlaenge: Summe LAENGE aller Reihen mit dieser Haengeebene" qr)
|
||||||
|
(lg-herkunft "gaenge" "je ART: Anzahl, Summe LAENGE, Summe LAENGE x BREITE_mm"
|
||||||
|
(strcat (itoa (length gaenge)) " Flaeche(n) LG_GANG_* Geschoss " nrs))))
|
||||||
|
hk))
|
||||||
|
;; Belag und Gitterrost (nur Buehne)
|
||||||
|
(setq belag-g 0.0 gitter-g 0.0)
|
||||||
|
(foreach x gaenge
|
||||||
|
(setq f (* (lg-n (lg-j x "laenge_mm")) (lg-n (lg-j x "breite_mm"))))
|
||||||
|
(if (equal (lg-j x "belag") "gitterrost")
|
||||||
|
(setq gitter-g (+ gitter-g f))
|
||||||
|
(setq belag-g (+ belag-g f))))
|
||||||
|
(if buehne
|
||||||
|
(progn
|
||||||
|
(if gaenge
|
||||||
|
(setq belag belag-g
|
||||||
|
hk (cons (lg-herkunft "belagsflaeche_mm2"
|
||||||
|
"Summe LAENGE x BREITE_mm der Gaenge mit BELAG ungleich gitterrost"
|
||||||
|
(strcat "LG_GANG_* Geschoss " nrs)) hk))
|
||||||
|
(setq belag (- (lg-n (lg-j (lg-j g "kontur") "flaeche_mm2")) grund)
|
||||||
|
hk (cons (lg-herkunft "belagsflaeche_mm2"
|
||||||
|
"Konturflaeche - Grundflaeche der Regalreihen (keine LG_GANG-Flaechen)"
|
||||||
|
(strcat "Belagskontur Geschoss " nrs)) hk)))
|
||||||
|
(setq gitter (+ gitter-g gitter-r)
|
||||||
|
hk (cons (lg-herkunft "gitterrostflaeche_mm2"
|
||||||
|
(strcat "Summe LAENGE x BREITE_mm der Gaenge mit BELAG gitterrost"
|
||||||
|
" + LAENGE x TIEFE_mm der Reihen mit UNTER_REIHE gitterrost")
|
||||||
|
(strcat "LG_GANG_*/LG_REIHE_* Geschoss " nrs)) hk))
|
||||||
|
(setq hk (cons (lg-herkunft "gitterkorb"
|
||||||
|
(strcat "Reihen mit UNTER_REIHE gitterkorb: Boden = LAENGE x TIEFE_mm,"
|
||||||
|
" Seiten = offene Kantenlaenge x GITTERKORB_HOEHE_mm"
|
||||||
|
" (Kanten an einer direkt anliegenden Nachbarreihe zaehlen nicht)")
|
||||||
|
qr) hk)))
|
||||||
|
(setq belag nil gitter nil
|
||||||
|
hk (cons (lg-herkunft "buehne" "BELAG_ART hallenboden (oder leer): keine Buehne, kein Belag/Gitterrost/Gitterkorb" q) hk))
|
||||||
|
)
|
||||||
|
(list
|
||||||
|
(list 'OBJ
|
||||||
|
(cons "lichte_hoehe_mm" lichte)
|
||||||
|
(cons "buehne" (if buehne T 'FALSE))
|
||||||
|
(cons "bereiche" n-bereiche)
|
||||||
|
(cons "reihen" (length reihen))
|
||||||
|
(cons "regallaenge_mm" regal)
|
||||||
|
(cons "regalgrundflaeche_mm2" grund)
|
||||||
|
(cons "schienenlaenge_mm" schienen)
|
||||||
|
(cons "haengeebenen" (lg-haengeebenen-summen reihen))
|
||||||
|
(cons "gaenge" (lg-gaenge-je-art gaenge))
|
||||||
|
(cons "belagsflaeche_mm2" belag)
|
||||||
|
(cons "gitterrostflaeche_mm2" gitter)
|
||||||
|
(cons "gitterkorb" (list 'OBJ (cons "reihen" (nth 0 korb))
|
||||||
|
(cons "bodenflaeche_mm2" (nth 1 korb))
|
||||||
|
(cons "seitenflaeche_mm2" (nth 2 korb))
|
||||||
|
(cons "offen_laengs_mm" (nth 3 korb))
|
||||||
|
(cons "offen_stirn_mm" (nth 4 korb)))))
|
||||||
|
(cons 'OBJ (reverse hk)))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun lg-summe-feld (objs key)
|
||||||
|
(apply '+ (cons 0.0 (mapcar '(lambda (o) (lg-n (lg-j o key))) objs)))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Kennwerte des ganzen Lagers. geschosse = Geschoss-Records mit kennwerte
|
||||||
|
;; und kontur, reihen/gaenge = alle einem Geschoss zugeordneten Records.
|
||||||
|
(defun lg-kennwerte-lager (geschosse reihen gaenge n-bereiche / kws korb bbs xmin ymin xmax ymax dx dy)
|
||||||
|
(setq kws (mapcar '(lambda (g) (lg-j g "kennwerte")) geschosse)
|
||||||
|
korb (mapcar '(lambda (k) (lg-j k "gitterkorb")) kws)
|
||||||
|
bbs (vl-remove nil (mapcar '(lambda (g) (cdr (lg-j (lg-j g "kontur") "bbox"))) geschosse)))
|
||||||
|
(if bbs
|
||||||
|
(setq xmin (apply 'min (mapcar 'car bbs)) ymin (apply 'min (mapcar 'cadr bbs))
|
||||||
|
xmax (apply 'max (mapcar 'caddr bbs)) ymax (apply 'max (mapcar 'cadddr bbs))
|
||||||
|
dx (- xmax xmin) dy (- ymax ymin)))
|
||||||
|
(list 'OBJ
|
||||||
|
(cons "geschosse" (length geschosse))
|
||||||
|
(cons "bereiche" n-bereiche)
|
||||||
|
(cons "reihen" (length reihen))
|
||||||
|
(cons "regallaenge_mm" (lg-summe-feld kws "regallaenge_mm"))
|
||||||
|
(cons "regalgrundflaeche_mm2" (lg-summe-feld kws "regalgrundflaeche_mm2"))
|
||||||
|
(cons "schienenlaenge_mm" (lg-summe-feld kws "schienenlaenge_mm"))
|
||||||
|
(cons "haengeebenen" (lg-haengeebenen-summen reihen))
|
||||||
|
(cons "gaenge" (lg-gaenge-je-art gaenge))
|
||||||
|
(cons "belagsflaeche_mm2" (lg-summe-feld kws "belagsflaeche_mm2"))
|
||||||
|
(cons "gitterrostflaeche_mm2" (lg-summe-feld kws "gitterrostflaeche_mm2"))
|
||||||
|
(cons "gitterkorb" (list 'OBJ (cons "reihen" (fix (lg-summe-feld korb "reihen")))
|
||||||
|
(cons "bodenflaeche_mm2" (lg-summe-feld korb "bodenflaeche_mm2"))
|
||||||
|
(cons "seitenflaeche_mm2" (lg-summe-feld korb "seitenflaeche_mm2"))
|
||||||
|
(cons "offen_laengs_mm" (lg-summe-feld korb "offen_laengs_mm"))
|
||||||
|
(cons "offen_stirn_mm" (lg-summe-feld korb "offen_stirn_mm"))))
|
||||||
|
(cons "huelle" (if bbs
|
||||||
|
(list 'OBJ (cons "bbox" (list 'ARR xmin ymin xmax ymax))
|
||||||
|
(cons "laenge_mm" (max dx dy))
|
||||||
|
(cons "breite_mm" (min dx dy))))))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; --- Records aus der Zeichnung ---
|
||||||
|
|
||||||
|
(defun lg-ent-layer (e) (cdr (assoc 8 (entget e))))
|
||||||
|
|
||||||
|
(defun lg-export-kontur (k / pts)
|
||||||
|
(if (and k (setq pts (ssg-lwpoly-punkte k)))
|
||||||
|
(list 'OBJ
|
||||||
|
(cons "handle" (lg-handle k))
|
||||||
|
(cons "z" (cond ((caddr (car pts))) (0.0)))
|
||||||
|
(cons "punkte" (lg-j-pkte (mapcar '(lambda (p) (list (car p) (cadr p))) pts)))
|
||||||
|
(cons "flaeche_mm2" (ssg-poly-flaeche pts))
|
||||||
|
(cons "umfang_mm" (ssg-poly-umfang pts))
|
||||||
|
(cons "bbox" (lg-j-bbox (ssg-poly-bbox pts)))))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun lg-export-geschoss-rec (g / a)
|
||||||
|
(setq a (caddr g))
|
||||||
|
(list 'OBJ
|
||||||
|
(cons "nr" (cadr g))
|
||||||
|
(cons "bezeichnung" (cdr (assoc "BEZEICHNUNG" a)))
|
||||||
|
(cons "id" (cdr (assoc "ID" a)))
|
||||||
|
(cons "handle" (lg-handle (car g)))
|
||||||
|
(cons "layer" (lg-ent-layer (car g)))
|
||||||
|
(cons "hoehe_belag_mm" (lg-a-zahl a "HOEHE_BELAG_mm"))
|
||||||
|
(cons "konstr_hoehe_mm" (lg-a-zahl a "KONSTR_HOEHE_mm"))
|
||||||
|
(cons "lichte_hoehe_mm" (lg-a-zahl a "LICHTE_HOEHE_mm"))
|
||||||
|
(cons "belag_art" (cdr (assoc "BELAG_ART" a)))
|
||||||
|
(cons "personen" (lg-a-int a "PERSONEN"))
|
||||||
|
(cons "brandgefaehrdung" (cdr (assoc "BRANDGEFAEHRDUNG" a)))
|
||||||
|
(cons "kontur" (lg-export-kontur (lg-ent-aus-handle (lg-xdata-wert (car g) "kontur"))))))
|
||||||
|
|
||||||
|
(defun lg-export-bereich-rec (e / a kinder)
|
||||||
|
(setq a (ssg-attrib-read e) kinder (lg-bereich-kinder e))
|
||||||
|
(list 'OBJ
|
||||||
|
(cons "nr" (lg-a-int a "NR"))
|
||||||
|
(cons "id" (cdr (assoc "ID" a)))
|
||||||
|
(cons "handle" (lg-handle e))
|
||||||
|
(cons "layer" (lg-ent-layer e))
|
||||||
|
(cons "geschoss" (lg-a-int a "GESCHOSS"))
|
||||||
|
(cons "gangbreite_mm" (lg-a-zahl a "GANGBREITE_mm"))
|
||||||
|
(cons "regaltiefe_mm" (lg-a-zahl a "REGALTIEFE_mm"))
|
||||||
|
(cons "reihen_je_gang" (lg-a-int a "REIHEN_JE_GANG"))
|
||||||
|
(cons "schienen_je_gang" (lg-a-int a "SCHIENEN_JE_GANG"))
|
||||||
|
(cons "quergang_abstand_mm" (lg-a-zahl a "QUERGANG_ABSTAND_mm"))
|
||||||
|
(cons "quergang_breite_mm" (lg-a-zahl a "QUERGANG_BREITE_mm"))
|
||||||
|
(cons "richtung_grad" (lg-a-zahl a "RICHTUNG"))
|
||||||
|
(cons "haengeebenen" (lg-j-ebenen (cdr (assoc "HAENGEEBENEN" a))))
|
||||||
|
(cons "belag" (cdr (assoc "BELAG" a)))
|
||||||
|
(cons "unter_reihe" (lg-unter-reihe-wert (cdr (assoc "UNTER_REIHE" a)) (lg-unter-reihe-vorgabe) T))
|
||||||
|
(cons "gitterkorb_hoehe_mm" (cond ((lg-a-zahl a "GITTERKORB_HOEHE_mm"))
|
||||||
|
((lg-zahl (lg-vorgabe '("bereich" "gitterkorb_hoehe_mm") nil)))))
|
||||||
|
(cons "randgang_mm" (cons 'OBJ (mapcar '(lambda (r) (cons (strcase (car r) T) (cdr r)))
|
||||||
|
(lg-bereich-rand a))))
|
||||||
|
(cons "restbreite_mm" (lg-a-zahl a "RESTBREITE_mm"))
|
||||||
|
(cons "anzahl_reihen" (length (vl-remove-if-not '(lambda (k) (wcmatch (strcase (lg-blockname k)) "LG_REIHE_*")) kinder)))
|
||||||
|
(cons "anzahl_gaenge" (length (vl-remove-if-not '(lambda (k) (wcmatch (strcase (lg-blockname k)) "LG_GANG_*")) kinder)))
|
||||||
|
(cons "kontur" (lg-export-kontur (lg-ent-aus-handle (lg-xdata-wert e "kontur"))))))
|
||||||
|
|
||||||
|
;; Reihe oder Gang: Attribute plus Geometrie (Start/Ende/Mitte in WCS mit Z,
|
||||||
|
;; Ecken des Grundrisses 2D aus lg-linie-polygon).
|
||||||
|
(defun lg-export-linie-rec (e art / a ed p1 z rot l b p2 quelle)
|
||||||
|
(setq a (ssg-attrib-read e) ed (entget e)
|
||||||
|
p1 (cdr (assoc 10 ed)) z (cond ((caddr p1)) (0.0))
|
||||||
|
rot (cond ((cdr (assoc 50 ed))) (0.0))
|
||||||
|
l (lg-a-zahl a "LAENGE")
|
||||||
|
b (lg-a-zahl a (if (= art "reihe") "TIEFE_mm" "BREITE_mm"))
|
||||||
|
p2 (polar (list (car p1) (cadr p1)) rot (lg-n l))
|
||||||
|
quelle (cdr (assoc "QUELLE" a)))
|
||||||
|
(if (member quelle '(nil "")) (setq quelle "auto"))
|
||||||
|
(cons 'OBJ
|
||||||
(append
|
(append
|
||||||
(list (cons "geschoss" (lg-a-int a "GESCHOSS"))
|
(list (cons "id" (cdr (assoc "ID" a)))
|
||||||
(cons "laenge_mm" (lg-a-zahl a "LAENGE")))
|
(cons "handle" (lg-handle e))
|
||||||
|
(cons "layer" (lg-ent-layer e))
|
||||||
|
(cons "geschoss" (lg-a-int a "GESCHOSS"))
|
||||||
|
(cons "bereich" (lg-a-int a "BEREICH"))
|
||||||
|
(cons "bereich_handle" (lg-xdata-wert e "bereich"))
|
||||||
|
(cons "quelle" quelle)
|
||||||
|
(cons "laenge_mm" l))
|
||||||
(if (= art "reihe")
|
(if (= art "reihe")
|
||||||
(list (cons "tiefe_mm" (lg-a-zahl a "TIEFE_mm"))
|
(list (cons "tiefe_mm" b)
|
||||||
(cons "haengeebenen" (lg-json-ebenen (cdr (assoc "HAENGEEBENEN" a))))
|
|
||||||
(cons "schienen" (lg-a-int a "SCHIENEN"))
|
(cons "schienen" (lg-a-int a "SCHIENEN"))
|
||||||
(cons "quelle" (cdr (assoc "QUELLE" a))))
|
(cons "haengeebenen" (lg-j-ebenen (cdr (assoc "HAENGEEBENEN" a)))))
|
||||||
(list (cons "breite_mm" (lg-a-zahl a "BREITE_mm"))
|
(list (cons "breite_mm" b)
|
||||||
(cons "art" (cdr (assoc "ART" a)))
|
(cons "art" (cdr (assoc "ART" a)))
|
||||||
(cons "belag" (cdr (assoc "BELAG" a)))
|
(cons "belag" (cdr (assoc "BELAG" a)))))
|
||||||
(cons "quelle" (if (member (cdr (assoc "QUELLE" a)) '(nil "")) "auto"
|
(list (cons "start" (list 'ARR (car p1) (cadr p1) z))
|
||||||
(cdr (assoc "QUELLE" a))))))
|
(cons "ende" (list 'ARR (car p2) (cadr p2) z))
|
||||||
(list (cons "bereich" (lg-a-int a "BEREICH"))
|
(cons "mitte" (list 'ARR (/ (+ (car p1) (car p2)) 2.0) (/ (+ (cadr p1) (cadr p2)) 2.0) z))
|
||||||
(cons "start" (lg-json-zahlen (cdr (assoc 10 ed))))
|
(cons "winkel_grad" (* (/ rot pi) 180.0))
|
||||||
(cons "winkel_grad" (* (/ (cond ((cdr (assoc 50 ed))) (0.0)) pi) 180.0))
|
(cons "ecken" (lg-j-pkte (lg-linie-polygon e)))
|
||||||
(cons "handle" (lg-handle e)))))
|
(cons "flaeche_mm2" (* (lg-n l) (lg-n b))))))
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Alle Daten als JSON-Text.
|
;; unter_reihe je Reihe aus ihrem Bereich (sonst Vorgabe), auf Hallenboden
|
||||||
(defun lg-export-json ( / gs warn)
|
;; "keine"; Reihen mit Gitterkorb bekommen (OBJ hoehe_mm) als Startwert.
|
||||||
(setq gs (lg-geschosse) warn nil)
|
(defun lg-reihen-unter-setzen (reihen bereiche geschosse vorgabe / br gr u)
|
||||||
|
(mapcar
|
||||||
|
'(lambda (r / br gr u)
|
||||||
|
(setq br (if (lg-j r "bereich_handle")
|
||||||
|
(vl-some '(lambda (b) (if (equal (lg-j b "handle") (lg-j r "bereich_handle")) b)) bereiche))
|
||||||
|
gr (vl-some '(lambda (g) (if (equal (lg-j g "nr") (lg-j r "geschoss")) g)) geschosse)
|
||||||
|
u (lg-unter-reihe-wert (lg-j br "unter_reihe") vorgabe (lg-buehne-p (lg-j gr "belag_art"))))
|
||||||
|
(lg-j-setzen
|
||||||
|
(lg-j-setzen r "unter_reihe" u)
|
||||||
|
"gitterkorb"
|
||||||
|
(if (= u "gitterkorb")
|
||||||
|
(list 'OBJ (cons "hoehe_mm" (cond ((lg-j br "gitterkorb_hoehe_mm"))
|
||||||
|
((lg-zahl (lg-vorgabe '("bereich" "gitterkorb_hoehe_mm") nil)))))))))
|
||||||
|
reihen)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Alle Daten des Lagers als OBJ (Grundlage von lg-export-json).
|
||||||
|
(defun lg-export-daten ( / warn gs bereiche reihen gaenge g-recs vorgabe g-neu r-neu r-gs g-gs i g nx nr nrs kw)
|
||||||
|
(setq gs (lg-geschosse) warn nil vorgabe (lg-unter-reihe-vorgabe))
|
||||||
(if (null gs) (setq warn (cons (ssg-text "lg-exp-keine-geschosse") warn)))
|
(if (null gs) (setq warn (cons (ssg-text "lg-exp-keine-geschosse") warn)))
|
||||||
(foreach g gs
|
(foreach g gs
|
||||||
(if (null (cadddr g))
|
(if (null (cadddr g))
|
||||||
(setq warn (cons (ssg-textf "lg-exp-geschoss-ohne-kontur" (list (itoa (cadr g)))) warn))))
|
(setq warn (cons (ssg-textf "lg-exp-geschoss-ohne-kontur" (list (itoa (cadr g)))) warn))))
|
||||||
(strcat
|
(setq bereiche (mapcar 'lg-export-bereich-rec (lg-alle-bloecke "LG_BEREICH"))
|
||||||
"{\n"
|
reihen (mapcar '(lambda (e) (lg-export-linie-rec e "reihe")) (lg-alle-bloecke "LG_REIHE_*"))
|
||||||
" \"version\": 1,\n"
|
gaenge (mapcar '(lambda (e) (lg-export-linie-rec e "gang")) (lg-alle-bloecke "LG_GANG_*"))
|
||||||
" \"zeichnung\": " (lg-json-wert (strcat (getvar "DWGPREFIX") (getvar "DWGNAME"))) ",\n"
|
;; Geschosse von unten nach oben (Belagshoehe, dann Nr)
|
||||||
" \"erzeugt\": " (lg-json-wert (ssg-timestamp)) ",\n"
|
g-recs (vl-sort (mapcar 'lg-export-geschoss-rec gs)
|
||||||
" \"einheit\": \"mm\",\n"
|
'(lambda (a b / ha hb)
|
||||||
" \"land\": " (lg-json-wert (lg-land)) ",\n"
|
(setq ha (lg-n (lg-j a "hoehe_belag_mm")) hb (lg-n (lg-j b "hoehe_belag_mm")))
|
||||||
" \"belag_yaml\": " (lg-json-obj (vl-remove-if '(lambda (p) (or (/= (type (cdr p)) 'STR)
|
(if (equal ha hb 1e-6) (< (lg-j a "nr") (lg-j b "nr")) (< ha hb)))))
|
||||||
(= (car p) "beschreibung")))
|
(setq reihen (lg-reihen-unter-setzen reihen bereiche g-recs vorgabe))
|
||||||
(lg-vorgabe '("belag_yaml") nil))) ",\n"
|
(setq g-neu nil r-neu nil r-gs nil g-gs nil i 0)
|
||||||
" \"reihen_als_gitterrost\": " (lg-json-wert (if (lg-vorgabe '("flaechen" "reihen_als_gitterrost") nil) T nil)) ",\n"
|
(foreach g g-recs
|
||||||
" \"geschosse\": " (lg-json-arr (mapcar 'lg-export-geschoss gs) " ") ",\n"
|
(setq nr (lg-j g "nr")
|
||||||
" \"bereiche\": " (lg-json-arr (mapcar 'lg-export-bereich (lg-alle-bloecke "LG_BEREICH")) " ") ",\n"
|
nx (nth (1+ i) g-recs)
|
||||||
" \"reihen\": " (lg-json-arr (mapcar '(lambda (e) (lg-export-linie e "reihe")) (lg-alle-bloecke "LG_REIHE_*")) " ") ",\n"
|
r-gs (lg-reihen-gitterkorb-berechnen
|
||||||
" \"gaenge\": " (lg-json-arr (mapcar '(lambda (e) (lg-export-linie e "gang")) (lg-alle-bloecke "LG_GANG_*")) " ") ",\n"
|
(vl-remove-if-not '(lambda (r) (equal (lg-j r "geschoss") nr)) reihen) 1.0)
|
||||||
" \"warnungen\": " (lg-json-arr (mapcar 'lg-json-wert warn) " ") "\n"
|
g-gs (vl-remove-if-not '(lambda (x) (equal (lg-j x "geschoss") nr)) gaenge)
|
||||||
"}\n")
|
kw (lg-kennwerte-geschoss g nx r-gs g-gs
|
||||||
|
(length (vl-remove-if-not '(lambda (b) (equal (lg-j b "geschoss") nr)) bereiche))))
|
||||||
|
(if (null (lg-j (car kw) "lichte_hoehe_mm"))
|
||||||
|
(setq warn (cons (ssg-textf "lg-exp-lichte-hoehe-oben" (list (itoa nr))) warn)))
|
||||||
|
(if (not (lg-buehne-p (lg-j g "belag_art")))
|
||||||
|
(foreach b bereiche
|
||||||
|
(if (and (equal (lg-j b "geschoss") nr) (= (lg-j b "unter_reihe") "gitterkorb"))
|
||||||
|
(setq warn (cons (ssg-textf "lg-exp-korb-hallenboden"
|
||||||
|
(list (vl-princ-to-string (lg-j b "nr")) (itoa nr))) warn)))))
|
||||||
|
(setq g-neu (cons (lg-j-setzen (lg-j-setzen g "kennwerte" (car kw)) "herkunft" (cadr kw)) g-neu)
|
||||||
|
r-neu (append r-neu r-gs)
|
||||||
|
i (1+ i)))
|
||||||
|
(setq g-neu (reverse g-neu)
|
||||||
|
nrs (mapcar '(lambda (g) (lg-j g "nr")) g-recs)
|
||||||
|
r-gs (vl-remove-if '(lambda (r) (member (lg-j r "geschoss") nrs)) reihen))
|
||||||
|
(if r-gs
|
||||||
|
(setq warn (cons (ssg-textf "lg-exp-reihen-ohne-geschoss" (list (itoa (length r-gs)))) warn)))
|
||||||
|
(list 'OBJ
|
||||||
|
(cons "format" "ssg-lager")
|
||||||
|
(cons "version" 2)
|
||||||
|
(cons "zeichnung" (strcat (getvar "DWGPREFIX") (getvar "DWGNAME")))
|
||||||
|
(cons "erzeugt" (ssg-timestamp))
|
||||||
|
(cons "land" (lg-land))
|
||||||
|
(cons "einheiten" (list 'OBJ (cons "laenge" "mm") (cons "flaeche" "mm2") (cons "winkel" "grad")))
|
||||||
|
(cons "koordinaten" "WCS, Nord = +Y")
|
||||||
|
(cons "lager" (lg-kennwerte-lager g-neu r-neu
|
||||||
|
(vl-remove-if-not '(lambda (x) (member (lg-j x "geschoss") nrs)) gaenge)
|
||||||
|
(length bereiche)))
|
||||||
|
(cons "geschosse" (cons 'ARR g-neu))
|
||||||
|
(cons "bereiche" (cons 'ARR bereiche))
|
||||||
|
(cons "reihen" (cons 'ARR (append r-neu r-gs)))
|
||||||
|
(cons "gaenge" (cons 'ARR gaenge))
|
||||||
|
(cons "warnungen" (cons 'ARR (reverse warn))))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Alle Daten als JSON-Text.
|
||||||
|
(defun lg-export-json ( / )
|
||||||
|
(strcat (lg-json-text (lg-export-daten) "") "\n")
|
||||||
)
|
)
|
||||||
|
|
||||||
(defun lg-ausgabe-verzeichnis ( / d)
|
(defun lg-ausgabe-verzeichnis ( / d)
|
||||||
@@ -2180,49 +2641,11 @@
|
|||||||
(progn (princ (ssg-textf "lg-exp-datei-fehler" (list pfad))) nil))
|
(progn (princ (ssg-textf "lg-exp-datei-fehler" (list pfad))) nil))
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Python-Skript lager_yaml_export.py aufrufen (nutzt die Interpreter-
|
;; Technische Daten des Lagers als <dwg>_lager.json nach DXFM_RESULTS.
|
||||||
;; Ermittlung aus export.lsp). Rueckgabe: Exitcode oder nil.
|
(defun c:LAGER_EXPORT ( / pfad)
|
||||||
(defun lg-python-aufrufen (raw yaml html / skript hand log args rc)
|
(setq pfad (strcat (lg-ausgabe-verzeichnis) "/" (lg-dwg-basis) "_lager.json"))
|
||||||
(cond
|
(if (lg-export-schreiben pfad)
|
||||||
((not (car (atoms-family 1 '("EXPORT:RUN-PYTHON"))))
|
(princ (ssg-textf "lg-exp-json" (list pfad))))
|
||||||
(princ (ssg-text "lg-exp-ohne-python")) nil)
|
|
||||||
((null (getenv "DXFM_LIB")) (princ (ssg-text "lg-exp-ohne-python")) nil)
|
|
||||||
(T
|
|
||||||
(setq skript (strcat (vl-string-translate "\\" "/" (getenv "DXFM_LIB")) "/lager_yaml_export.py")
|
|
||||||
hand (lg-ldata-lesen "HAND_YAML")
|
|
||||||
log (strcat (lg-ausgabe-verzeichnis) "/lager_export_python.log"))
|
|
||||||
(setq args (list raw yaml "--nachweis" html))
|
|
||||||
(if (and hand (= (type hand) 'STR) (findfile hand))
|
|
||||||
(setq args (append args (list "--hand" hand))))
|
|
||||||
(setq rc (export:run-python (export:python-exe) skript args log))
|
|
||||||
(if (and rc (/= rc 0))
|
|
||||||
(princ (ssg-textf "lg-exp-python-fehler" (list (vl-princ-to-string rc) log))))
|
|
||||||
rc)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
(defun c:LAGER_EXPORT ( / dir basis raw yaml html rc)
|
|
||||||
(setq dir (lg-ausgabe-verzeichnis) basis (lg-dwg-basis))
|
|
||||||
(setq raw (strcat dir "/" basis "_lager_raw.json")
|
|
||||||
yaml (strcat dir "/" basis "_drawing.yaml")
|
|
||||||
html (strcat dir "/" basis "_nachweis.html"))
|
|
||||||
(if (lg-export-schreiben raw)
|
|
||||||
(progn
|
|
||||||
(princ (ssg-textf "lg-exp-raw" (list raw)))
|
|
||||||
(setq rc (lg-python-aufrufen raw yaml html))
|
|
||||||
(if (and rc (= rc 0))
|
|
||||||
(princ (ssg-textf "lg-exp-yaml" (list yaml html))))))
|
|
||||||
(princ)
|
|
||||||
)
|
|
||||||
|
|
||||||
;; Hand-YAML fuer den Abgleich (Konfliktliste) festlegen; leer = keiner.
|
|
||||||
(defun c:LAGER_HAND_YAML ( / alt neu)
|
|
||||||
(setq alt (lg-ldata-lesen "HAND_YAML"))
|
|
||||||
(setq neu (if (ssg-gui-p)
|
|
||||||
(getfiled (ssg-text "lg-titel-hand-yaml") (if (= (type alt) 'STR) alt "") "yaml" 0)
|
|
||||||
(ssg-in-string (ssg-text "lg-titel-hand-yaml") (if (= (type alt) 'STR) alt ""))))
|
|
||||||
(lg-ldata-setzen "HAND_YAML" (if neu neu ""))
|
|
||||||
(princ (ssg-textf "lg-hand-yaml" (list (if (and neu (/= neu "")) neu "-"))))
|
|
||||||
(princ)
|
(princ)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
;; ============================================================
|
;; ============================================================
|
||||||
;; LagerPruefung.lsp - Regelprofile der Lagerplanung (Phase 0)
|
;; LagerPruefung.lsp - Regelprofile der Lagerplanung (Phase 0)
|
||||||
;;
|
;;
|
||||||
;; Laedt das Laenderprofil cfg/regelwerk/<LAND>.json, loest die Vererbung
|
;; Laedt das Laenderprofil cfg/stahlbau/regelwerk/<LAND>.json, loest die Vererbung
|
||||||
;; (erbt_von) auf und liefert je Regel den STRENGSTEN Wert aller Quellen,
|
;; (erbt_von) auf und liefert je Regel den STRENGSTEN Wert aller Quellen,
|
||||||
;; deren Bedingung zutrifft - mit Protokoll, welche Quelle gewonnen hat.
|
;; deren Bedingung zutrifft - mit Protokoll, welche Quelle gewonnen hat.
|
||||||
;; Jede Pruefregel der Lagerplanung wird genau einmal hier implementiert
|
;; Jede Pruefregel der Lagerplanung wird genau einmal hier implementiert
|
||||||
@@ -35,7 +35,7 @@
|
|||||||
(setq cfg (getenv "DXFM_CFG"))
|
(setq cfg (getenv "DXFM_CFG"))
|
||||||
(if cfg
|
(if cfg
|
||||||
(strcat (vl-string-right-trim "/\\" (vl-string-translate "\\" "/" cfg))
|
(strcat (vl-string-right-trim "/\\" (vl-string-translate "\\" "/" cfg))
|
||||||
"/regelwerk/" (strcase land) ".json"))
|
"/stahlbau/regelwerk/" (strcase land) ".json"))
|
||||||
)
|
)
|
||||||
|
|
||||||
;; Zwei Profile mischen: Regeln von kind ersetzen gleichnamige (id) von
|
;; Zwei Profile mischen: Regeln von kind ersetzen gleichnamige (id) von
|
||||||
|
|||||||
+9
-10
@@ -867,27 +867,26 @@ Das fertige Raster (Linien + Zaehl-Texte) wird zu einem einzigen Block
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### `LagerInsert.lsp` / `LagerPruefung.lsp` – Lagerplanung (GOH-Buehnenlager -> RFQ-YAML)
|
### `LagerInsert.lsp` / `LagerPruefung.lsp` – Lagerplanung (GOH-Buehnenlager -> Lager-JSON)
|
||||||
|
|
||||||
Parametrische Attributbloecke fuer ein mehrgeschossiges Haengewarenlager; die
|
Parametrische Attributbloecke fuer ein mehrgeschossiges Haengewarenlager;
|
||||||
Mengen gehen ueber `LAGER_EXPORT` als Overlay-YAML an das RFQ-Programm
|
`LAGER_EXPORT` schreibt die technischen Daten als eine JSON-Datei fuer die
|
||||||
(`lib/lager_yaml_export.py`). Konzept, Datenmodell und YAML-Zuordnung:
|
RFQ-Dokumentation (eigenes Projekt). Konzept, Datenmodell, JSON-Schema und
|
||||||
[`doc/plan/lager_rfq.md`](../doc/plan/lager_rfq.md). Stand: Phase 0 + 1
|
Kennwert-Formeln: [`doc/plan/lager_rfq.md`](../doc/plan/lager_rfq.md). Stand:
|
||||||
(Mengen, 2D).
|
Phase 0 + 1 (Mengen, 2D).
|
||||||
|
|
||||||
| Befehl | Beschreibung |
|
| Befehl | Beschreibung |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `c:LG_GESCHOSS` | Belagskontur waehlen/zeichnen, Dialog `lg_geschoss` (`dcl/lager.dcl`), Block `LG_GESCHOSS` + XDATA-Verknuepfung zur Kontur |
|
| `c:LG_GESCHOSS` | Belagskontur waehlen/zeichnen, Dialog `lg_geschoss` (`dcl/lager.dcl`), Block `LG_GESCHOSS` + XDATA-Verknuepfung zur Kontur |
|
||||||
| `c:LG_GESCHOSS_AKTIV` | Aktives Geschoss setzen, Layer `LG_*_G<n>` der anderen Geschosse frieren (0 = alle zeigen) |
|
| `c:LG_GESCHOSS_AKTIV` | Aktives Geschoss setzen, Layer `LG_*_G<n>` der anderen Geschosse frieren (0 = alle zeigen) |
|
||||||
| `c:LG_GESCHOSS_KOPIEREN` | Geschoss mit Belagskontur, Bereichen, Reihen und Gaengen 1:1 in ein oder mehrere neue Geschosse kopieren (Dialog `lg_geschoss_kopie`: Quelle - Vorgabe oberstes Geschoss -, Anzahl, Geschosshoehe je Kopie, Belag, Versatz X/Y je Kopie, 0 = deckungsgleich). Belaege gleich dem Quell-Geschossbelag folgen dem neuen Belag; Verknuepfungen, Layer `_G<n>` und IDs sind neu |
|
| `c:LG_GESCHOSS_KOPIEREN` | Geschoss mit Belagskontur, Bereichen, Reihen und Gaengen 1:1 in ein oder mehrere neue Geschosse kopieren (Dialog `lg_geschoss_kopie`: Quelle - Vorgabe oberstes Geschoss -, Anzahl, Geschosshoehe je Kopie, Belag, Versatz X/Y je Kopie, 0 = deckungsgleich). Belaege gleich dem Quell-Geschossbelag folgen dem neuen Belag; Verknuepfungen, Layer `_G<n>` und IDs sind neu |
|
||||||
| `c:LG_BEREICH` | Lagerbereich-Kontur + Dialog `lg_bereich`; Auto-Fuellung mit `LG_REIHE_<L>_<T>` / `LG_GANG_<L>_<B>_<BELAG>`, optional Randgaenge Nord/Ost/Sued/West entlang der Konturkanten (auch L-Form) |
|
| `c:LG_BEREICH` | Lagerbereich-Kontur + Dialog `lg_bereich`; Auto-Fuellung mit `LG_REIHE_<L>_<T>` / `LG_GANG_<L>_<B>_<BELAG>`, optional Randgaenge Nord/Ost/Sued/West entlang der Konturkanten (auch L-Form) und Absturzsicherung unter den Reihen (`UNTER_REIHE` gitterrost/gitterkorb/keine, `GITTERKORB_HOEHE_mm`) |
|
||||||
| `c:LG_REIHE` | Einzelne Regalreihen per Start/Ende oder getippter Laenge; wie bei `LG_GANG` mit dem Bereich verknuepft und ausgeschnitten statt neu berechnet (`lg-manuell-einfuegen`) |
|
| `c:LG_REIHE` | Einzelne Regalreihen per Start/Ende oder getippter Laenge; wie bei `LG_GANG` mit dem Bereich verknuepft und ausgeschnitten statt neu berechnet (`lg-manuell-einfuegen`) |
|
||||||
| `c:LG_GANG` | Einzelne Gaenge (Dialog `lg_gang`: Breite, Art gang/randgang/quergang, Belag), mittig auf der Linie - oder ueber die Option `Rechteck` als Flaeche, gezeichnet mit dem BricsCAD-Befehl RECHTECK samt aller seiner Optionen (Abmessungen, Flaeche, Drehung ...; `lg-rechteck-zeichnen`, Auswertung `lg-rechteck-ecken-aus-poly`, Fase/Rundung wird abgelehnt) (Lage und Breite aus dem Rechteck, laengere Seite = Gangrichtung; Kern `lg-gang-aus-ecken`, `lg-gang-rechteck-einfuegen`, `Linie` schaltet zurueck); liegt die Mitte in einem Bereich, wird der Gang mit ihm verknuepft. Der Gang schneidet seine Flaeche aus den automatisch erzeugten Reihen/Gaengen heraus (`lg-sperre-anwenden`), OHNE den Bereich neu zu berechnen - von Hand geloeschte oder geaenderte Objekte bleiben, wie sie sind; bei jeder Neuberechnung bleibt er stehen (Sperrflaeche) |
|
| `c:LG_GANG` | Einzelne Gaenge (Dialog `lg_gang`: Breite, Art gang/randgang/quergang, Belag), mittig auf der Linie - oder ueber die Option `Rechteck` als Flaeche, gezeichnet mit dem BricsCAD-Befehl RECHTECK samt aller seiner Optionen (Abmessungen, Flaeche, Drehung ...; `lg-rechteck-zeichnen`, Auswertung `lg-rechteck-ecken-aus-poly`, Fase/Rundung wird abgelehnt) (Lage und Breite aus dem Rechteck, laengere Seite = Gangrichtung; Kern `lg-gang-aus-ecken`, `lg-gang-rechteck-einfuegen`, `Linie` schaltet zurueck); liegt die Mitte in einem Bereich, wird der Gang mit ihm verknuepft. Der Gang schneidet seine Flaeche aus den automatisch erzeugten Reihen/Gaengen heraus (`lg-sperre-anwenden`), OHNE den Bereich neu zu berechnen - von Hand geloeschte oder geaenderte Objekte bleiben, wie sie sind; bei jeder Neuberechnung bleibt er stehen (Sperrflaeche) |
|
||||||
| `c:LG_EDIT` | Bearbeiten (auch per Doppelklick ueber `SSG_BLOCKEDIT`, Zweig `LG_*`): Bereich -> Neuberechnung (von Hand eingefuegte und geaenderte Reihen/Gaenge bleiben stehen und werden ausgespart), Reihe/Gang -> Neuaufbau, danach Zuschnitt der rangniedrigeren Objekte (`auto` < `auto_geaendert` < `manuell`, `lg-quelle-rang`) statt Neuberechnung des Bereichs |
|
| `c:LG_EDIT` | Bearbeiten (auch per Doppelklick ueber `SSG_BLOCKEDIT`, Zweig `LG_*`): Bereich -> Neuberechnung (von Hand eingefuegte und geaenderte Reihen/Gaenge bleiben stehen und werden ausgespart), Reihe/Gang -> Neuaufbau, danach Zuschnitt der rangniedrigeren Objekte (`auto` < `auto_geaendert` < `manuell`, `lg-quelle-rang`) statt Neuberechnung des Bereichs |
|
||||||
| `c:LG_REGALE` | Regalreihen `LG_REIHE_*` zaehlen (`lg-reihe-eintrag` + `lg-reihen-auswerten`): Anzahl, Laenge und Laenge x Haengeebenen je Geschoss plus Gesamtsumme in der Befehlszeile |
|
| `c:LG_REGALE` | Regalreihen `LG_REIHE_*` zaehlen (`lg-reihe-eintrag` + `lg-reihen-auswerten`): Anzahl, Laenge und Laenge x Haengeebenen je Geschoss plus Gesamtsumme in der Befehlszeile |
|
||||||
| `c:LAGER_EXPORT` | `<dwg>_lager_raw.json` + Python -> `<dwg>_drawing.yaml` und `<dwg>_nachweis.html` in `DXFM_RESULTS` |
|
| `c:LAGER_EXPORT` | `<dwg>_lager.json` in `DXFM_RESULTS`: alle Geschosse, Bereiche, Reihen und Gaenge mit Attributen und Geometrie, Kennwerte je Geschoss und gesamt (inkl. Gitterkorb mit offenen Kanten), Herkunft je Kennwert, Warnungen. Kein Python-Schritt |
|
||||||
| `c:LAGER_HAND_YAML` | Hand-YAML fuer den Abgleich (Konfliktliste) festlegen |
|
| `c:LG_REGELN` | Regelprofil (`cfg/stahlbau/regelwerk/<Land>.json`) mit aufgeloesten Werten und Quellen anzeigen |
|
||||||
| `c:LG_REGELN` | Regelprofil (`cfg/regelwerk/<Land>.json`) mit aufgeloesten Werten und Quellen anzeigen |
|
|
||||||
|
|
||||||
Gangflaechen sind je Belag schraffiert (Schraffur in der Blockdefinition, Muster aus
|
Gangflaechen sind je Belag schraffiert (Schraffur in der Blockdefinition, Muster aus
|
||||||
`data/json/lager.json` `belag_schraffur`: Spanplatte ANSI31, Gitterrost GRID,
|
`data/json/lager.json` `belag_schraffur`: Spanplatte ANSI31, Gitterrost GRID,
|
||||||
|
|||||||
@@ -1,230 +0,0 @@
|
|||||||
# =====================================================================================
|
|
||||||
# GOH-Regal-Ausschreibung – Projektdaten (Schema v2)
|
|
||||||
# =====================================================================================
|
|
||||||
# Regeln:
|
|
||||||
# * Feld weglassen -> nicht relevant, erscheint nicht im Dokument
|
|
||||||
# * Feld = null -> OFFENER PUNKT: erscheint als "to be clarified" (rot, kursiv) und
|
|
||||||
# zusätzlich in der Tabelle "Open points" am Ende des Dokuments
|
|
||||||
# * Felder ohne Angabe verwenden die Standardwerte/-texte aus rfq/model.py
|
|
||||||
# * Zahlen mit Punkt als Dezimaltrennzeichen eingeben (3.10), Ausgabe erfolgt deutsch (3,1)
|
|
||||||
# * In Freitexten (remarks, scope, ...) sind {floors} und {floors_word} erlaubt
|
|
||||||
# * "# BSP" = Beispielwert, im Original-Dokument nicht enthalten -> prüfen/ersetzen
|
|
||||||
# =====================================================================================
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Anfrage / Dokument
|
|
||||||
doc:
|
|
||||||
title: Budget request for steel racking scaffolding/platform
|
|
||||||
subtitle: Steel structure for a four-level garment-on-hanger (GOH) rack # BSP
|
|
||||||
request_type: budget # budget | binding
|
|
||||||
reference: RFQ-GOH-Storage-2026 # z. B. RFQ-2026-017
|
|
||||||
date: 07.10.2026 # Ausgabedatum, z. B. 07.10.2026
|
|
||||||
revision: "0"
|
|
||||||
contact:
|
|
||||||
name: Max Mustermann
|
|
||||||
function: Project Engineering # BSP
|
|
||||||
phone: +49 xxx xxx
|
|
||||||
email: xxx@schoenenberger.de
|
|
||||||
# output_name: SSG_RFP_GOH_racking_Projekt-X
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Projekt
|
|
||||||
project:
|
|
||||||
name: goh-slo_pol # Projektname, wie er dem Anbieter genannt werden darf
|
|
||||||
# project_no: P-12345
|
|
||||||
# end_customer: ... # weglassen, wenn vertraulich
|
|
||||||
building_type: a new warehouse
|
|
||||||
industry: textile logistics
|
|
||||||
rack_type: static hanging goods rack
|
|
||||||
additional_purpose: The scaffolding is also used to suspend the conveyor technology.
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Termine
|
|
||||||
deadlines:
|
|
||||||
questions: 10.10.2026 # Frist für technische Rückfragen
|
|
||||||
offer: End of October 2026 # Angebotsabgabe
|
|
||||||
# award: Q1/2027
|
|
||||||
approval_drawings: null # Freigabepläne des Anbieters
|
|
||||||
delivery: null
|
|
||||||
assembly_start: Mid of 2027 (expected)
|
|
||||||
assembly_end: null
|
|
||||||
# handover: ...
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Baustelle
|
|
||||||
site:
|
|
||||||
location: Slovakia or Poland
|
|
||||||
address: null
|
|
||||||
#access_notes: null # Zufahrt, Anlieferung, Entladung, Kranstellfläche
|
|
||||||
#working_hours: null
|
|
||||||
hall_available_from: Mid of 2027 # Halle geschlossen/beheizt verfügbar ab
|
|
||||||
#provided_by_client: # Beistellungen des Auftraggebers
|
|
||||||
# - Electricity (230/400 V) at one connection point in the hall # BSP
|
|
||||||
# - Sanitary facilities # BSP
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Gebäude / Halle
|
|
||||||
building:
|
|
||||||
hall_clear_height_m: 12 # Unterkante Dachtragwerk
|
|
||||||
sprinkler_clearance_m: null # erforderlicher Freiraum unter Deckensprinklern
|
|
||||||
column_grid: 12 x 24 m # z. B. "12,0 x 24,0 m"
|
|
||||||
climate: null # z. B. "closed, heated hall, +5 … +30 °C"
|
|
||||||
corrosivity_category: C1 # BSP – beheizte Halle
|
|
||||||
floor_slab:
|
|
||||||
thickness_mm: null
|
|
||||||
concrete_class: null
|
|
||||||
permissible_load_kn_m2: null # bisher "Permissible soil load still to be clarified"
|
|
||||||
permissible_point_load_kn: null
|
|
||||||
floor_heating: null # true -> Dübel-Einschränkungen
|
|
||||||
# anchoring_notes: max. drilling depth 120 mm (sealing layer)
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Erdbeben
|
|
||||||
seismic:
|
|
||||||
ag_ms2: 0.63 # Bemessungswert der Bodenbeschleunigung (Original: a_b)
|
|
||||||
ground_type: null # Baugrundklasse A–E
|
|
||||||
importance_class: null
|
|
||||||
code: EN 1998-1 | STN EN 1998-1 # BSP
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Bemessung / Ausführung
|
|
||||||
design:
|
|
||||||
standards: [EN 1990, EN 1991-1-1, EN 1993-1-1, EN 1090-2] # BSP
|
|
||||||
execution_class: EXC2 # BSP
|
|
||||||
deflection_general: L/300 # BSP
|
|
||||||
#deflection_rail_beams: null # wichtig für Trolley-Betrieb, z. B. "L/500, max. 5 mm"
|
|
||||||
# tolerances: ...
|
|
||||||
#surface_protection: null # z. B. hot-dip galvanized / powder-coated
|
|
||||||
# colour: RAL 5010
|
|
||||||
fire_protection: null # z. B. "Sprinkler system acc. to FM Global"
|
|
||||||
#max_escape_route_m: null
|
|
||||||
# extra: [Further requirement ...]
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Konfiguration / Layout
|
|
||||||
layout:
|
|
||||||
block_length_m: null
|
|
||||||
block_width_m: null
|
|
||||||
# aisles: 40
|
|
||||||
# aisle_length_m: 2938.9 # Summe aller Ganglängen je Ebene; sonst aus rack_length_m berechnet
|
|
||||||
aisle_width_m: 1.00
|
|
||||||
rack_rows_per_aisle: 2
|
|
||||||
rack_depth_m: 0.7 # Tiefe einer Regalreihe (Bügelbreite)
|
|
||||||
trolley_rails_per_aisle: 1
|
|
||||||
#max_column_spacing_m: null # Vorgabe, falls Gänge/Durchfahrten frei bleiben müssen
|
|
||||||
storey_height_m: 3.1 # nur Vorgabe, wenn floor_elevation_m fehlt
|
|
||||||
# column_height_m: 11.85 # sonst berechnet: oberste Belagshöhe + lichte Höhe oben
|
|
||||||
rail:
|
|
||||||
type: null # Schienentyp/-profil des Auftraggebers
|
|
||||||
fixation_spacing_m: 2
|
|
||||||
supplied_by: client # client | supplier
|
|
||||||
suspended_by: client # client | supplier
|
|
||||||
interface: null # z. B. "threaded rod M12 through cross beam"
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Ebenen (von unten nach oben)
|
|
||||||
# rack_length_m = Laufmeter Hängeschiene je Hängeebene, SUMME ALLER REIHEN der Ebene.
|
|
||||||
# rail_height_m = Oberkante Schiene über Belag der Ebene, goods_length_m = max. Warenlänge.
|
|
||||||
# Treppen/Leitern (stairs_down/ladders_down) führen zur Ebene darunter.
|
|
||||||
levels:
|
|
||||||
- remark: ground floor
|
|
||||||
floor_elevation_m: 0.00
|
|
||||||
clear_height_m: 2.43 # BSP
|
|
||||||
hanging_levels:
|
|
||||||
- {rail_height_m: 2.30, rack_length_m: 5877.8, goods_length_m: 1.20} # Höhen BSP
|
|
||||||
- {rail_height_m: 1.10, rack_length_m: 5877.8, goods_length_m: 1.10}
|
|
||||||
|
|
||||||
- floor_elevation_m: 3.10
|
|
||||||
clear_height_m: 2.95 # BSP
|
|
||||||
hanging_levels:
|
|
||||||
- {rail_height_m: 2.80, rack_length_m: 5877.8, goods_length_m: 1.20}
|
|
||||||
- {rail_height_m: 1.40, rack_length_m: 5877.8, goods_length_m: 1.20}
|
|
||||||
walkway: {area_m2: 4286, spec: chipboard}
|
|
||||||
grating: null # Fläche Gitterrost (Absturzsicherung) noch offen
|
|
||||||
railing_m: 380
|
|
||||||
kickplate_m: null
|
|
||||||
stairs_down: 1 # oder: [{qty: 1, width_m: 1.0, note: straight stair}]
|
|
||||||
ladders_down: 7
|
|
||||||
# openings: [{qty: 4, size: "1,2 x 1,0 m", purpose: conveyor passage}]
|
|
||||||
# pallet_gates: 2
|
|
||||||
# loads: {platform_imposed_kg_m2: 300, conveyor_kg_m: 40} # überschreibt globale Lasten
|
|
||||||
|
|
||||||
- floor_elevation_m: 6.20
|
|
||||||
clear_height_m: 2.95 # BSP
|
|
||||||
hanging_levels:
|
|
||||||
- {rail_height_m: 2.80, rack_length_m: 5877.8, goods_length_m: 1.20}
|
|
||||||
- {rail_height_m: 1.40, rack_length_m: 5877.8, goods_length_m: 1.20}
|
|
||||||
walkway: {area_m2: 4286, spec: chipboard}
|
|
||||||
grating: null
|
|
||||||
railing_m: 380
|
|
||||||
kickplate_m: null
|
|
||||||
stairs_down: 1
|
|
||||||
ladders_down: 7
|
|
||||||
|
|
||||||
- floor_elevation_m: 9.30
|
|
||||||
clear_height_m: 2.55 # bis Stützenkopf -> Stützenhöhe 11,85 m
|
|
||||||
hanging_levels:
|
|
||||||
- {rail_height_m: 2.40, rack_length_m: 5877.8, goods_length_m: 1.10} # BSP
|
|
||||||
- {rail_height_m: 1.20, rack_length_m: 5877.8, goods_length_m: 1.10}
|
|
||||||
walkway: {area_m2: 4286, spec: chipboard}
|
|
||||||
grating: null
|
|
||||||
railing_m: 380
|
|
||||||
kickplate_m: null
|
|
||||||
stairs_down: 1
|
|
||||||
ladders_down: 7
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Beläge und Absturzsicherung
|
|
||||||
flooring:
|
|
||||||
walkway:
|
|
||||||
material: chipboard
|
|
||||||
thickness_mm: null
|
|
||||||
fire_class: null
|
|
||||||
grating:
|
|
||||||
purpose: fall protection within the rack rows
|
|
||||||
type: null
|
|
||||||
mesh: null
|
|
||||||
sprinkler_permeable: null
|
|
||||||
kickplate_height_mm: 100 # ersetzt das widersprüchliche "skirting boards min. 5 cm"
|
|
||||||
railing:
|
|
||||||
height_m: 1.0
|
|
||||||
knee_rail: true
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Treppen und Leitern
|
|
||||||
access:
|
|
||||||
stairs:
|
|
||||||
standard: EN ISO 14122-3
|
|
||||||
width_m: null
|
|
||||||
handrails: both sides
|
|
||||||
ladders:
|
|
||||||
type: emergency ladder
|
|
||||||
standard: EN ISO 14122-4
|
|
||||||
cage: null
|
|
||||||
gate: self-closing safety gate at each ladder opening
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Lastannahmen (global, je Ebene überschreibbar)
|
|
||||||
loads:
|
|
||||||
platform_imposed_kg_m2: 250
|
|
||||||
imposed_category: null # Nutzungskategorie nach EN 1991-1-1 / NA SK
|
|
||||||
point_load_kn: null
|
|
||||||
railing_horizontal_kn_m: null # z. B. 0,5 kN/m
|
|
||||||
rail_dead_kg_m: 10 # Trolley-Schiene inkl. Abhängung (ständig)
|
|
||||||
rail_goods_kg_m: 80 # Trolleys und Hängeware (veränderlich)
|
|
||||||
hanging_per_level_kg_m: 60 # Hängeware je m Hängeschiene je Hängeebene
|
|
||||||
grating_kg_m2: 100
|
|
||||||
building_services_kg_m2: 25
|
|
||||||
conveyor_kg_m: null # abgehängte Fördertechnik (siehe project.additional_purpose)
|
|
||||||
# conveyor_horizontal_kn: 2
|
|
||||||
collision_protection: null # Anfahrschutz im EG, falls Flurförderzeuge verkehren
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Kaufmännisches
|
|
||||||
commercial:
|
|
||||||
currency: EUR
|
|
||||||
incoterms: DAP site (Incoterms 2020) # BSP
|
|
||||||
payment_terms: null
|
|
||||||
warranty_months: null
|
|
||||||
offer_validity: 3 months # BSP
|
|
||||||
offer_language: English
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------- Anlagen
|
|
||||||
attachments:
|
|
||||||
- {ref: "1", title: Layout drawing rack block, revision: null} # BSP
|
|
||||||
- {ref: "2", title: Sections with level heights, revision: null} # BSP
|
|
||||||
|
|
||||||
# Optional überschreibbare Standardtexte (siehe rfq/model.py):
|
|
||||||
# remarks: [...]
|
|
||||||
# scope: [...]
|
|
||||||
# exclusions: [...]
|
|
||||||
# documentation: [...]
|
|
||||||
# requested_info: [...]
|
|
||||||
# client: {description: [...]}
|
|
||||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+7
-13
@@ -11,13 +11,6 @@
|
|||||||
"belag_arten": ["spanplatte", "gitterrost", "hallenboden"]
|
"belag_arten": ["spanplatte", "gitterrost", "hallenboden"]
|
||||||
},
|
},
|
||||||
|
|
||||||
"belag_yaml": {
|
|
||||||
"beschreibung": "Belagsart (Attribut BELAG_ART/BELAG) -> Wert fuer walkway.spec der RFQ-YAML. hallenboden = keine Buehne (kein walkway/grating/railing).",
|
|
||||||
"spanplatte": "chipboard",
|
|
||||||
"gitterrost": "grating",
|
|
||||||
"hallenboden": ""
|
|
||||||
},
|
|
||||||
|
|
||||||
"brandgefaehrdungen": ["normal", "erhoeht_mit_loeschanlage", "erhoeht_ohne_loeschanlage"],
|
"brandgefaehrdungen": ["normal", "erhoeht_mit_loeschanlage", "erhoeht_ohne_loeschanlage"],
|
||||||
|
|
||||||
"bereich": {
|
"bereich": {
|
||||||
@@ -31,7 +24,13 @@
|
|||||||
"min_ganglaenge_mm": 100,
|
"min_ganglaenge_mm": 100,
|
||||||
"richtung_grad": 0,
|
"richtung_grad": 0,
|
||||||
"belag": "spanplatte",
|
"belag": "spanplatte",
|
||||||
"randgang_mm": {"n": 0, "o": 0, "s": 0, "w": 0}
|
"randgang_mm": {"n": 0, "o": 0, "s": 0, "w": 0},
|
||||||
|
"unter_reihe": "gitterrost",
|
||||||
|
"gitterkorb_hoehe_mm": 500
|
||||||
|
},
|
||||||
|
|
||||||
|
"unter_reihe": {
|
||||||
|
"beschreibung": "Absturzsicherung unter den Regalreihen auf Buehnen (Attribut UNTER_REIHE am Bereich, Vorgabe bereich.unter_reihe): gitterrost = Grundflaeche der Reihe (Laenge x Tiefe) zaehlt als Gitterrost; gitterkorb = Korb mit Boden (Laenge x Tiefe) und Seitenwaenden (offene Kantenlaenge x GITTERKORB_HOEHE_mm), Kanten an einer direkt anliegenden Nachbarreihe zaehlen nicht; keine = offen. Auf hallenboden wirkt der Wert nicht. gitterkorb_hoehe_mm ist ein Platzhalter, bis die Hoehe aus den Attributen berechnet wird."
|
||||||
},
|
},
|
||||||
|
|
||||||
"belag_schraffur": {
|
"belag_schraffur": {
|
||||||
@@ -45,10 +44,5 @@
|
|||||||
"beschreibung": "haengeebenen = Schienenhoehe ueber Belag / max. Warenlaenge je Haengeebene, durch Semikolon getrennt, oberste zuerst.",
|
"beschreibung": "haengeebenen = Schienenhoehe ueber Belag / max. Warenlaenge je Haengeebene, durch Semikolon getrennt, oberste zuerst.",
|
||||||
"haengeebenen": "2300/1200;1100/1100",
|
"haengeebenen": "2300/1200;1100/1100",
|
||||||
"schienen": 1
|
"schienen": 1
|
||||||
},
|
|
||||||
|
|
||||||
"flaechen": {
|
|
||||||
"beschreibung": "reihen_als_gitterrost: Grundflaeche der Regalreihen (Laenge x Tiefe) auf Buehnen zaehlt als Gitterrost (Absturzsicherung in den Reihen).",
|
|
||||||
"reihen_als_gitterrost": true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,6 +63,11 @@ lg_bereich : dialog {
|
|||||||
: edit_box { key = "ebenen"; label = "Haengeebenen (Schiene/Ware;...):"; edit_width = 24; }
|
: edit_box { key = "ebenen"; label = "Haengeebenen (Schiene/Ware;...):"; edit_width = 24; }
|
||||||
: popup_list { key = "belag"; label = "Belag der Gaenge:"; width = 30; }
|
: popup_list { key = "belag"; label = "Belag der Gaenge:"; width = 30; }
|
||||||
}
|
}
|
||||||
|
: boxed_column {
|
||||||
|
label = "Absturzsicherung unter den Reihen (nur auf Buehnen)";
|
||||||
|
: popup_list { key = "unter"; label = "Unter den Reihen:"; width = 30; }
|
||||||
|
: edit_box { key = "korbhoehe"; label = "Gitterkorb-Hoehe (mm):"; edit_width = 10; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ok_cancel;
|
ok_cancel;
|
||||||
errtile;
|
errtile;
|
||||||
|
|||||||
@@ -0,0 +1,274 @@
|
|||||||
|
# Lagerplanung in BricsCAD -> Lager-JSON (GOH-Buehnenlager)
|
||||||
|
|
||||||
|
Schema und Schnittstelle der Lagerplanung. Code: `Lisp/LagerInsert.lsp`,
|
||||||
|
`Lisp/LagerPruefung.lsp`. Daten: `data/json/lager.json`,
|
||||||
|
`cfg/stahlbau/regelwerk/*.json`, `cfg/layer.cfg` Abschnitt `[lager]`, Dialoge `dcl/lager.dcl`.
|
||||||
|
|
||||||
|
## Ziel und Datenfluss
|
||||||
|
|
||||||
|
Das RFQ-Programm (eigenes Repo) erzeugt das Ausschreibungsdokument. Die Makros
|
||||||
|
liefern ihm die technischen Daten des Lagers aus der Zeichnung, als EINE
|
||||||
|
JSON-Datei. Mapping auf das RFQ-Schema, Abgleich mit Handwerten und Darstellung
|
||||||
|
sind Sache des RFQ-Projekts.
|
||||||
|
|
||||||
|
```
|
||||||
|
BricsCAD (LISP) RFQ-Repo
|
||||||
|
LG_GESCHOSS / LG_BEREICH / LG_REIHE / LG_GANG
|
||||||
|
--LAGER_EXPORT--> DXFM_RESULTS/<dwg>_lager.json --> Dokument
|
||||||
|
^ Regelprofil cfg/stahlbau/regelwerk/<Land>.json (LagerPruefung.lsp, noch nicht im Export)
|
||||||
|
```
|
||||||
|
|
||||||
|
Grundsatz: jede fachliche Regel und jeder Kennwert wird genau einmal
|
||||||
|
implementiert, in LISP (`LagerInsert.lsp` Abschnitt EXPORT, Regeln in
|
||||||
|
`LagerPruefung.lsp`). Es gibt keinen Python-Schritt mehr (die fruehere
|
||||||
|
Overlay-YAML `lib/lager_yaml_export.py` und `LAGER_HAND_YAML` sind entfernt).
|
||||||
|
|
||||||
|
## JSON-Schnittstelle (`format` = `ssg-lager`, `version` = 2)
|
||||||
|
|
||||||
|
Einheiten mm, mm2, Grad; Koordinaten WCS, Nord = +Y. Werte stehen
|
||||||
|
selbstbeschreibend drin (`"belag_art": "spanplatte"`, keine Index-Codes). Fehlende
|
||||||
|
Werte sind `null`. Nicht-ASCII-Zeichen in Texten werden als `\uXXXX` geschrieben.
|
||||||
|
|
||||||
|
```
|
||||||
|
{
|
||||||
|
"format": "ssg-lager", "version": 2, "zeichnung", "erzeugt", "land",
|
||||||
|
"einheiten": {"laenge": "mm", "flaeche": "mm2", "winkel": "grad"},
|
||||||
|
"koordinaten": "WCS, Nord = +Y",
|
||||||
|
"lager": { geschosse, bereiche, reihen, regallaenge_mm, regalgrundflaeche_mm2,
|
||||||
|
schienenlaenge_mm, haengeebenen[], gaenge{}, belagsflaeche_mm2,
|
||||||
|
gitterrostflaeche_mm2, gitterkorb{}, huelle{bbox, laenge_mm, breite_mm} },
|
||||||
|
"geschosse": [ { nr, bezeichnung, id, handle, layer, hoehe_belag_mm, konstr_hoehe_mm,
|
||||||
|
lichte_hoehe_mm (Attribut), belag_art, personen, brandgefaehrdung,
|
||||||
|
kontur{handle, z, punkte[[x,y]...], flaeche_mm2, umfang_mm, bbox},
|
||||||
|
kennwerte{...}, herkunft{<kennwert>: {formel, quelle}} } ],
|
||||||
|
"bereiche": [ { nr, id, handle, layer, geschoss, gangbreite_mm, regaltiefe_mm,
|
||||||
|
reihen_je_gang, schienen_je_gang, quergang_abstand_mm, quergang_breite_mm,
|
||||||
|
richtung_grad, haengeebenen[], belag, unter_reihe, gitterkorb_hoehe_mm,
|
||||||
|
randgang_mm{n,o,s,w}, restbreite_mm, anzahl_reihen, anzahl_gaenge, kontur{} } ],
|
||||||
|
"reihen": [ { id, handle, layer, geschoss, bereich, bereich_handle, quelle, laenge_mm,
|
||||||
|
tiefe_mm, schienen, haengeebenen[], start, ende, mitte, winkel_grad,
|
||||||
|
ecken[4], flaeche_mm2, unter_reihe,
|
||||||
|
gitterkorb{hoehe_mm, bodenflaeche_mm2, offen_laengs_mm, offen_stirn_mm,
|
||||||
|
seitenflaeche_mm2} | null } ],
|
||||||
|
"gaenge": [ { id, handle, layer, geschoss, bereich, bereich_handle, quelle, laenge_mm,
|
||||||
|
breite_mm, art, belag, start, ende, mitte, winkel_grad, ecken[4], flaeche_mm2 } ],
|
||||||
|
"warnungen": [ ... ]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`geschosse` ist nach Belagshoehe sortiert (von unten nach oben). `start`/`ende`/
|
||||||
|
`mitte` sind 3D (Z der Einfuegung), `ecken` sind die vier Ecken des Grundrisses
|
||||||
|
(2D), Kante 1-2 und 3-4 laengs, 2-3 und 4-1 an den Stirnseiten.
|
||||||
|
`kennwerte` je Geschoss: `lichte_hoehe_mm`, `buehne` (true/false), `bereiche`,
|
||||||
|
`reihen`, `regallaenge_mm`, `regalgrundflaeche_mm2`, `schienenlaenge_mm`,
|
||||||
|
`haengeebenen` (je Schienenhoehe/Warenlaenge: `reihen`, `regallaenge_mm`),
|
||||||
|
`gaenge` (je Art gang/quergang/randgang: `anzahl`, `laenge_mm`, `flaeche_mm2`),
|
||||||
|
`belagsflaeche_mm2`, `gitterrostflaeche_mm2`, `gitterkorb` (Summen). Formeln:
|
||||||
|
Abschnitt "Kennwerte <- Zeichnung".
|
||||||
|
|
||||||
|
Erzeugt von `LAGER_EXPORT` (Menue Lager -> Export Lager-JSON), Beispiel:
|
||||||
|
`tests/output/lager_tests_lager.json` nach `TEST_LAGER`.
|
||||||
|
|
||||||
|
## Bloecke und Attribute
|
||||||
|
|
||||||
|
Alle Bloecke tragen `ID`, `GESCHOSS`, `LAYER`. Masse in mm, Winkel in Grad,
|
||||||
|
Werte selbstbeschreibend (keine Index-Codes). Verknuepfungen als XDATA
|
||||||
|
(App `SSG_LG`, Paare `1000 schluessel` + `1005 handle`/`1000 text`).
|
||||||
|
|
||||||
|
| Block | Geometrie | Attribute | XDATA |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `LG_GESCHOSS` | Kopfsymbol unten links an der Belagskontur | `NR`, `BEZEICHNUNG`, `HOEHE_BELAG_mm`, `KONSTR_HOEHE_mm`, `LICHTE_HOEHE_mm` (leer = berechnet), `BELAG_ART` (`spanplatte`/`gitterrost`/`hallenboden`), `PERSONEN`, `BRANDGEFAEHRDUNG` | `kontur` -> Polylinie; Kontur: `besitzer`, `rolle` |
|
||||||
|
| `LG_BEREICH` | Symbol mit Pfeil in Reihenrichtung | `NR`, `GANGBREITE_mm`, `REGALTIEFE_mm`, `REIHEN_JE_GANG` (1/2), `SCHIENEN_JE_GANG`, `QUERGANG_ABSTAND_mm` (0 = keine), `QUERGANG_BREITE_mm`, `RICHTUNG`, `HAENGEEBENEN`, `BELAG`, `RANDGANG_N_mm`/`_O_`/`_S_`/`_W_` (0 = keiner), `UNTER_REIHE` (`gitterrost`/`gitterkorb`/`keine`, Absturzsicherung unter den Reihen, nur auf Buehnen), `GITTERKORB_HOEHE_mm`, `RESTBREITE_mm` (Ergebnis) | `kontur` -> Polylinie |
|
||||||
|
| `LG_REIHE_<L>_<T>` | Rechteck L x T um die Schienenlinie, Einfuegepunkt = Reihenanfang | `LAENGE`, `TIEFE_mm`, `HAENGEEBENEN`, `SCHIENEN`, `BEREICH`, `QUELLE` (`auto`/`auto_geaendert`/`manuell`) | `bereich` -> LG_BEREICH (nur Auto-Fuellung) |
|
||||||
|
| `LG_GANG_<L>_<B>_<BELAG>` | Rechteck L x B um die Gangachse + Schraffur je Belag (`lager.json belag_schraffur`, Layer 0/VONBLOCK; `hallenboden` ohne) | `LAENGE`, `BREITE_mm`, `ART` (`gang`/`quergang`/`randgang`), `BELAG`, `BEREICH`, `QUELLE` (`auto`/`auto_geaendert`/`manuell`) | `bereich` (Auto-Fuellung und manuelle Gaenge im Bereich) |
|
||||||
|
|
||||||
|
`HAENGEEBENEN` = `Schienenhoehe/Warenlaenge;...` ueber Belag, oberste zuerst,
|
||||||
|
z.B. `2300/1200;1100/1100`. Die Definitionen `LG_REIHE_*`/`LG_GANG_*` werden je
|
||||||
|
Geometrie wiederverwendet; die Werte stehen in den Attributen der Referenz.
|
||||||
|
|
||||||
|
### Geschosse und Layer
|
||||||
|
|
||||||
|
Layer je Geschoss: Basis aus `cfg/layer.cfg [lager]` + `_G<nr>`
|
||||||
|
(`LG_Reihe_G2`). `LG_GESCHOSS_AKTIV` friert die Layer der uebrigen Geschosse,
|
||||||
|
weil die 2D-Grundrisse uebereinander liegen. Neue Objekte bekommen das aktive
|
||||||
|
Geschoss; ohne aktives Geschoss entscheidet die Kontur, in der sie liegen. In
|
||||||
|
2D (alle Konturen auf Z = 0) ist eine Lage in mehreren Konturen nicht
|
||||||
|
eindeutig -> Rueckfrage bzw. Export-Warnung; in 3D entscheidet Z.
|
||||||
|
|
||||||
|
Jede Kontur gehoert genau einem Block. Wird eine schon vergebene Kontur
|
||||||
|
gewaehlt (z.B. dieselbe Halle fuer mehrere Geschosse), wird sie kopiert.
|
||||||
|
|
||||||
|
Der parametrische BricsCAD-Block `goh_rack` (frueher als Bestand mitgezaehlt)
|
||||||
|
wird nicht mehr unterstuetzt: Regale gibt es nur noch als `LG_REIHE_*`.
|
||||||
|
|
||||||
|
### Geschoss kopieren (`LG_GESCHOSS_KOPIEREN`)
|
||||||
|
|
||||||
|
Obergeschosse gleichen meist dem Geschoss darunter. Dialog `lg_geschoss_kopie`:
|
||||||
|
|
||||||
|
- Quelle: Vorgabe ist das oberste Geschoss. Damit wird ein weiteres Geschoss
|
||||||
|
nachtraeglich angehaengt, z.B. G3 -> G4.
|
||||||
|
- Anzahl.
|
||||||
|
- Geschosshoehe je Kopie: Vorgabe ist der Abstand zum Geschoss darunter, sonst
|
||||||
|
lichte Hoehe + Konstruktion.
|
||||||
|
- Belag.
|
||||||
|
- Versatz X/Y je Kopie: 0 = deckungsgleich. In einer 3D-Zeichnung (Konturen auf
|
||||||
|
Belagshoehe) wandert die Kopie zusaetzlich in Z.
|
||||||
|
|
||||||
|
Ein BricsCAD-KOPIEREN taugt nicht. Die XDATA-Verweise `kontur`/`besitzer`/`bereich`
|
||||||
|
zeigten dann weiter auf die Originale, und GESCHOSS, Layer und IDs blieben die alten.
|
||||||
|
Stattdessen entsteht jedes Objekt ueber die normalen Einfuegefunktionen neu:
|
||||||
|
|
||||||
|
- Geschoss und Bereiche mit kopierter Kontur; die Bereiche ohne Fuellung
|
||||||
|
(`lg-bereich-block-anlegen`).
|
||||||
|
- Reihen und Gaenge 1:1 aus der Quelle (`lg-linie-einfuegen`). Es wird nicht neu
|
||||||
|
gefuellt, damit Handaenderungen (`auto_geaendert`, manuelle Reihen/Gaenge) erhalten
|
||||||
|
bleiben.
|
||||||
|
- Belaege, die dem Geschossbelag der Quelle entsprachen, folgen dem neuen Belag,
|
||||||
|
inklusive Schraffur. Bewusst abweichende bleiben.
|
||||||
|
|
||||||
|
### Auto-Fuellung (`lg-fuellung-berechnen`)
|
||||||
|
|
||||||
|
Die Kontur wird in ein lokales System gedreht (Reihen entlang +X, `RICHTUNG`;
|
||||||
|
Vorgabe = Richtung der laengsten Konturkante). Quer dazu wird ab Unterkante ein
|
||||||
|
Modul nach dem anderen gelegt, nur volle Module:
|
||||||
|
|
||||||
|
- 2 Reihen je Gang: `Reihe | Gang | Reihe`, benachbarte Module Ruecken an Ruecken
|
||||||
|
- 1 Reihe je Gang: `Reihe | Gang`
|
||||||
|
|
||||||
|
Ein Streifen ist dort belegbar, wo Unter-, Mittel- und Oberkante in der Kontur
|
||||||
|
liegen (konkave Konturen werden korrekt beschnitten). Quergaenge: Luecken der
|
||||||
|
Breite `QUERGANG_BREITE_mm` nach je `QUERGANG_ABSTAND_mm`, ueber alle Reihen
|
||||||
|
ausgerichtet; keine Luecke am Reihenende, wenn dahinter kein Mindeststueck mehr
|
||||||
|
passt. Hauptgaenge laufen durch. Der Rest quer zu den Reihen steht in
|
||||||
|
`RESTBREITE_mm`. Edit des Bereichs = Neuaufbau aller Kinder (Sektions-Neuaufbau,
|
||||||
|
kein Feld-Splice) - aber nur der automatisch erzeugten (`QUELLE=auto`). Von Hand
|
||||||
|
eingefuegte (`manuell`) und von Hand geaenderte (`auto_geaendert`) Reihen und Gaenge
|
||||||
|
bleiben stehen und werden ausgespart, ebenso unverknuepfte manuelle Objekte, deren
|
||||||
|
Mitte in der Kontur liegt; die Anzahl wird gemeldet. Von Hand geloeschte
|
||||||
|
automatische Objekte entstehen bei dieser ausdruecklichen Neuberechnung neu.
|
||||||
|
|
||||||
|
**Randgaenge** (`RANDGANG_N/O/S/W_mm`, Nord = +Y Welt): jede Konturkante bekommt
|
||||||
|
den Randgang ihrer Himmelsrichtung (Aussennormale, auf N/O/S/W eingerastet,
|
||||||
|
45 Grad zaehlt zu N/S) als Rechteck von der Kante nach innen - auch bei L-Form
|
||||||
|
entlang der echten Kanten (dort bekommt z.B. auch die Stufenkante den
|
||||||
|
Nord-Randgang; Ausnahmen per `LG_GANG`). Ecken: N/S-Randgaenge besitzen sie;
|
||||||
|
an konvexen Ecken wird der O/W-Randgang gekuerzt, an einspringenden Ecken der
|
||||||
|
N/S-Randgang verlaengert (sonst bliebe ein freies Quadrat). Randgaenge an der
|
||||||
|
Unter-/Oberkante der Huelle verschieben den Modulstapel, an der linken/rechten
|
||||||
|
den Bezug der Quergaenge; Stufenkanten mitten im Stapel kappen nur die
|
||||||
|
betroffenen Reihen. Nicht rechtwinklige Ecken sind eine Naeherung.
|
||||||
|
|
||||||
|
**Sperrflaechen**: Randgaenge sowie von Hand eingefuegte und geaenderte Reihen und
|
||||||
|
Gaenge werden aus Reihen, Haupt- und Quergaengen ausgeschnitten - exakt ueber den
|
||||||
|
Band-Clip des Streifens (`ssg-poly-band-x`), Reststuecke unter der
|
||||||
|
Mindestlaenge fallen weg. Eine von Hand eingefuegte Reihe (`LG_REIHE`) oder ein
|
||||||
|
Gang (`LG_GANG`), dessen Mitte in einem Bereich liegt, wird mit ihm verknuepft.
|
||||||
|
|
||||||
|
**Von Hand Gesetztes loest KEINE Neuberechnung aus.** Beim Einfuegen und
|
||||||
|
Bearbeiten (`LG_REIHE`, `LG_GANG`, `LG_EDIT` einer Reihe/eines Gangs) schneidet das
|
||||||
|
Objekt nur seine Flaeche aus den ueberdeckten Objekten heraus
|
||||||
|
(`lg-sperre-anwenden`, Kern `lg-linie-zuschnitt`); die Reste behalten ihre Attribute.
|
||||||
|
Geschnitten wird nur, was rangniedriger ist (`lg-quelle-rang`: `auto` <
|
||||||
|
`auto_geaendert` < `manuell`) - ein manuelles Objekt schneidet aus automatischen und
|
||||||
|
geaenderten, ein geaendertes nur aus automatischen, manuelle untereinander nie. Alles
|
||||||
|
andere bleibt, wie der Anwender es hinterlassen hat: von Hand geloeschte Objekte
|
||||||
|
kommen nicht zurueck. Wird ein manueller Gang verkleinert oder geloescht, bleibt die
|
||||||
|
Luecke bis zur naechsten ausdruecklichen Neuberechnung (Doppelklick auf den
|
||||||
|
Bereich, OK).
|
||||||
|
|
||||||
|
`LG_GANG` zeichnet einen Gang entweder als Linie (Gangmitte, Breite aus dem
|
||||||
|
Dialog) oder ueber die Option `Rechteck` als Flaeche. Beim Rechteck
|
||||||
|
ergeben sich Lage und Breite aus der Flaeche, man muss sie also vorher nicht
|
||||||
|
kennen: die laengere Seite ist die Gangrichtung, die kuerzere die Breite (auf
|
||||||
|
ganze mm). Die Rundung verschiebt nur die Laengsseite gegenueber der ersten
|
||||||
|
gezeichneten Ecke - die Kante, an der man ansetzt (z.B. buendig an einer
|
||||||
|
Regalreihe), bleibt exakt liegen, sonst wuerde der Gang die Reihe um Bruchteile
|
||||||
|
eines mm ueberdecken und sie beim Zuschnitt entfernen; ebenso beginnt der Gang an
|
||||||
|
der Querseite der ersten Ecke (`lg-gang-aus-ecken`). Gezeichnet wird mit dem echten BricsCAD-Befehl RECHTECK
|
||||||
|
(`lg-rechteck-zeichnen`) - mit allen seinen Optionen (Abmessungen, Flaeche,
|
||||||
|
Drehung, Objektfang); ein gedrehtes Rechteck ergibt einen schraeg liegenden Gang.
|
||||||
|
Die gezeichnete Polylinie wird ausgewertet (`lg-rechteck-ecken-aus-poly`) und
|
||||||
|
wieder geloescht; mit Fase oder Rundung gezeichnete Flaechen werden abgelehnt.
|
||||||
|
Nach jedem Rechteck startet RECHTECK erneut, Enter ohne Rechteck beendet. Im Block
|
||||||
|
entsteht derselbe `LG_GANG_*` wie bei der Linie.
|
||||||
|
|
||||||
|
**Schraffur**: steckt in der Gang-Blockdefinition (Belag im Blocknamen), Muster
|
||||||
|
aus `lager.json belag_schraffur` - `spanplatte` ANSI31, `gitterrost` GRID,
|
||||||
|
`hallenboden` keine. Unbekannter Belag/Muster -> Meldung, Gang ohne Schraffur.
|
||||||
|
Reihen bleiben unschraffiert. Altbestand: fehlen einer vorhandenen
|
||||||
|
Blockdefinition ATTDEFs des Schemas, definiert `lg-blockdef` sie neu und
|
||||||
|
uebertraegt sie per `_.ATTSYNC` auf die Referenzen.
|
||||||
|
|
||||||
|
## Kennwerte <- Zeichnung
|
||||||
|
|
||||||
|
Reine Kerne in `LagerInsert.lsp` (getestet in `tu-tests-lager`). Jeder
|
||||||
|
Geschoss-Kennwert steht mit Formel und Quelle unter `herkunft`.
|
||||||
|
|
||||||
|
| Kennwert | Quelle / Formel |
|
||||||
|
|---|---|
|
||||||
|
| `lichte_hoehe_mm` | `LICHTE_HOEHE_mm`, sonst Belag darueber - Konstruktionshoehe darueber - eigener Belag; oberstes Geschoss nur mit Vorgabe (sonst `null` + Warnung) |
|
||||||
|
| `buehne` | `BELAG_ART` gesetzt und nicht `hallenboden`. Ohne Buehne: kein Belag, kein Gitterrost, kein Gitterkorb |
|
||||||
|
| `regallaenge_mm`, `regalgrundflaeche_mm2`, `schienenlaenge_mm` | Summe `LAENGE`, `LAENGE x TIEFE_mm`, `LAENGE x SCHIENEN` der Reihen des Geschosses |
|
||||||
|
| `haengeebenen[]` | je (Schienenhoehe, Warenlaenge): Anzahl Reihen und Summe `LAENGE`, nach Schienenhoehe absteigend (`lg-haengeebenen-summen`) |
|
||||||
|
| `gaenge` | je `ART` (gang/quergang/randgang, auch manuelle): Anzahl, Summe `LAENGE`, Summe `LAENGE x BREITE_mm` (`lg-gaenge-je-art`) |
|
||||||
|
| `belagsflaeche_mm2` | Summe `LAENGE x BREITE_mm` der Gaenge mit Belag != gitterrost; ohne Gangflaechen: Konturflaeche - Reihengrundflaeche |
|
||||||
|
| `gitterrostflaeche_mm2` | Gaenge mit Belag gitterrost + Grundflaeche der Reihen mit `UNTER_REIHE = gitterrost` |
|
||||||
|
| `gitterkorb` (je Reihe und Summe) | Reihen mit `UNTER_REIHE = gitterkorb`: Boden = `LAENGE x TIEFE_mm`; Seiten = offene Kantenlaenge x `GITTERKORB_HOEHE_mm`, getrennt nach Laengs- und Stirnseiten. Offen ist eine Kante, soweit keine Kante einer ANDEREN Reihe desselben Geschosses kollinear darauf liegt (Abstand < 1 mm, z.B. Ruecken an Ruecken; `lg-reihen-offene-kanten`) |
|
||||||
|
| `lager.huelle` | achsparallele Huelle aller Geschosskonturen, `laenge_mm` = laengere Seite |
|
||||||
|
| `lager.*` sonst | Summen der Geschoss-Kennwerte; `haengeebenen`/`gaenge` ueber alle zugeordneten Reihen/Gaenge |
|
||||||
|
|
||||||
|
`UNTER_REIHE` kommt aus dem verknuepften Bereich; Reihen ohne Bereich (und
|
||||||
|
Bereiche ohne Attribut, Altbestand) nehmen die Vorgabe `lager.json
|
||||||
|
bereich.unter_reihe`. `GITTERKORB_HOEHE_mm` ist vorerst ein Attribut am Bereich
|
||||||
|
und soll spaeter aus den Attributen berechnet werden.
|
||||||
|
|
||||||
|
Spaetere Phasen: Gelaender/Bordbrett, Oeffnungen, Treppen, Leitern, Zugaenge
|
||||||
|
(Phase 2), Schnitte (Phase 3), Fluchtwege (Phase 4/5), Regelwerk-Werte je
|
||||||
|
Geschoss im Export.
|
||||||
|
|
||||||
|
## Regelprofil
|
||||||
|
|
||||||
|
`cfg/stahlbau/regelwerk/<LAND>.json`, aufgeloest von `LagerPruefung.lsp`:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{"id": "treppe.schrittmass_min", "art": "min", "einheit": "mm",
|
||||||
|
"werte": [{"wert": 590, "quelle": "ASR A1.8", "abschnitt": "4.5", "fassung": "...", "verifiziert": false},
|
||||||
|
{"wert": 600, "quelle": "EN ISO 14122-3", "abschnitt": "5", "fassung": "...", "verifiziert": false}]}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `art`: `min` (strengster = groesster), `max` (strengster = kleinster), `wert`.
|
||||||
|
- `bedingung`: `<schluessel> <op> <wert>` (`=`, `<=`, `>=`, `<`, `>`) gegen einen
|
||||||
|
Kontext (z.B. `brandgefaehrdung`, `absturzhoehe`, `personen`). Fehlt der
|
||||||
|
Schluessel im Kontext, wird der Eintrag konservativ einbezogen.
|
||||||
|
- `tabelle` + `tabellen_schluessel`: Wert der ersten Zeile `[bis, wert]`, die den
|
||||||
|
Kontextwert abdeckt (Fluchtwegbreite nach Personen).
|
||||||
|
- `erbt_von`: Laenderprofil erbt alle Regeln, eigene Records mit gleicher `id`
|
||||||
|
ersetzen sie. `SK.json`/`PL.json` sind Gerueste (`gepflegt: false` -> Warnung).
|
||||||
|
- `LG_REGELN` zeigt alle Regeln mit Ergebnis und Protokoll (welche Quelle gewann).
|
||||||
|
|
||||||
|
**Alle Startwerte stehen auf `verifiziert: false`.** Wert, Abschnitt und
|
||||||
|
Fassung muessen gegen die Originaltexte (ASR A1.8, A2.1, A2.3, DGUV Regel
|
||||||
|
108-007, EN ISO 14122-3/-4) geprueft werden; besonders unsicher sind die
|
||||||
|
DGUV-Gangbreiten und die Abschnittsnummern.
|
||||||
|
|
||||||
|
## Stand
|
||||||
|
|
||||||
|
| Phase | Inhalt | Stand |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 | Regelprofil + Resolver, Schema (dieses Dokument), Layer, Sprach-Keys, Menue, Laden | erledigt, Regelwerte unverifiziert |
|
||||||
|
| 1 | Geschoss, aktives Geschoss, Bereich + Auto-Fuellung, Einzelreihe, Edit, `LAGER_EXPORT` als Lager-JSON mit Kennwerten und Herkunft, Gitterkorb/Gitterrost unter den Reihen | erledigt (2D) |
|
||||||
|
| 1a | Regelwerk-Werte (aufgeloest je Geschoss) im Lager-JSON; Gitterkorb-Hoehe aus den Attributen berechnen | offen |
|
||||||
|
| 2 | Gelaender/Bordbrett aus Kontur, Kanten-Ausnahmen, Oeffnungen, Treppe (Auslegung nach Profil), Leiter | offen |
|
||||||
|
| 3 | Schema-Schnitt, 3D-Varianten | offen |
|
||||||
|
| 4 | `LAGER_PRUEFEN`, Fluchtweg (gezeichnet), Verstoss-Marker, Nachweis mit Regelpruefung | offen |
|
||||||
|
| 5 | automatische Fluchtweganalyse | offen |
|
||||||
|
| 6 | SK/PL-Profile, Kapazitaet, Kopplung Geruest, Stuecklisten-Klassen | offen |
|
||||||
|
|
||||||
|
## Tests
|
||||||
|
|
||||||
|
- `tests/test_unit.lsp`: `tu-tests-poly` (Polygon-Helfer in `ssg_core.lsp`),
|
||||||
|
`tu-tests-lager` (Fuellung, Geschosszuordnung, JSON-Schreiber, Kennwerte,
|
||||||
|
offene Kanten/Gitterkorb, Feldpruefung, Regelprofil).
|
||||||
|
- `tests/test_lager.lsp` (`TEST_LAGER`, `alltests.json`): Ablauf in einer
|
||||||
|
Zeichnung inkl. Neuberechnung, Reihen-Edit, Export (Schema, Geometrie,
|
||||||
|
Kennwerte, Gitterkorb), Geschoss-Kopie und `LG_REGALE`.
|
||||||
+14
-2
@@ -47,7 +47,19 @@ Stand: 2026-10-26. Wird woechentlich (freitags) mit der Doku geprueft, siehe
|
|||||||
innerhalb der Streckengruppe (Vario-Kurve, GF-Bogen); die frueheren
|
innerhalb der Streckengruppe (Vario-Kurve, GF-Bogen); die frueheren
|
||||||
Dummy-Befehle `ILS_K*` sind entfernt.
|
Dummy-Befehle `ILS_K*` sind entfernt.
|
||||||
|
|
||||||
## 6. Tests
|
## 6. Lager
|
||||||
|
|
||||||
|
- **Regelwerk-Werte im Lager-JSON-Export**: die aufgeloesten Regeln aus
|
||||||
|
`cfg/stahlbau/regelwerk/<LAND>.json` je Geschoss (Kontext Brandgefaehrdung,
|
||||||
|
Personen, Absturzhoehe) mit Quelle und `verifiziert` in `<dwg>_lager.json`
|
||||||
|
aufnehmen (`LagerPruefung.lsp`, `lg-regel-aufloesen`).
|
||||||
|
- **Gitterkorb-Hoehe berechnen**: `GITTERKORB_HOEHE_mm` steht bisher als
|
||||||
|
Attribut am Bereich (Vorgabe `lager.json bereich.gitterkorb_hoehe_mm`,
|
||||||
|
Platzhalter 500); spaeter aus den Attributen ableiten.
|
||||||
|
- Weitere Phasen (Gelaender, Treppen, Fluchtweg ...): `doc/plan/lager_rfq.md`
|
||||||
|
Abschnitt "Stand".
|
||||||
|
|
||||||
|
## 7. Tests
|
||||||
|
|
||||||
- **`tests/test_vf_geometrie.py`** braucht BricsCAD-erzeugte DXF-Referenzdaten,
|
- **`tests/test_vf_geometrie.py`** braucht BricsCAD-erzeugte DXF-Referenzdaten,
|
||||||
die headless fehlen -> schlaegt ohne vorherigen CAD-Lauf fehl.
|
die headless fehlen -> schlaegt ohne vorherigen CAD-Lauf fehl.
|
||||||
@@ -55,7 +67,7 @@ Stand: 2026-10-26. Wird woechentlich (freitags) mit der Doku geprueft, siehe
|
|||||||
gegen `tests/output/hundm05_results.json` (Beweis "Spec-Pfad ==
|
gegen `tests/output/hundm05_results.json` (Beweis "Spec-Pfad ==
|
||||||
Journal-Pfad" auf Geometrie-Ebene). -> `doc/todo/plan-vf-interactive.md`
|
Journal-Pfad" auf Geometrie-Ebene). -> `doc/todo/plan-vf-interactive.md`
|
||||||
|
|
||||||
## 7. Spaetere Meilensteine (Entwicklungsplan)
|
## 8. Spaetere Meilensteine (Entwicklungsplan)
|
||||||
|
|
||||||
Nur Ueberschriften, Details in `doc/plan/Entwicklungsplan.md`:
|
Nur Ueberschriften, Details in `doc/plan/Entwicklungsplan.md`:
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -1215,6 +1215,8 @@
|
|||||||
"lg-feld-rand_w": "\nRandgang West (mm, 0 = keiner)",
|
"lg-feld-rand_w": "\nRandgang West (mm, 0 = keiner)",
|
||||||
"lg-feld-breite": "\nGangbreite (mm)",
|
"lg-feld-breite": "\nGangbreite (mm)",
|
||||||
"lg-feld-art": "\nArt des Gangs",
|
"lg-feld-art": "\nArt des Gangs",
|
||||||
|
"lg-feld-unter": "\nUnter den Reihen (gitterrost/gitterkorb/keine)",
|
||||||
|
"lg-feld-korbhoehe": "\nGitterkorb-Hoehe (mm)",
|
||||||
"lg-titel-gang": "Lager: Gaenge einfuegen",
|
"lg-titel-gang": "Lager: Gaenge einfuegen",
|
||||||
"lg-prompt-gang-start": "\nStartpunkt der Gangmitte oder [%1] <Enter = Ende>: ",
|
"lg-prompt-gang-start": "\nStartpunkt der Gangmitte oder [%1] <Enter = Ende>: ",
|
||||||
"lg-key-rechteck": "Rechteck",
|
"lg-key-rechteck": "Rechteck",
|
||||||
@@ -1245,7 +1247,6 @@
|
|||||||
"lg-titel-bereich": "Lager: Lagerbereich anlegen",
|
"lg-titel-bereich": "Lager: Lagerbereich anlegen",
|
||||||
"lg-titel-reihe": "Lager: Regalreihen einfuegen",
|
"lg-titel-reihe": "Lager: Regalreihen einfuegen",
|
||||||
"lg-titel-edit": "Lager: bearbeiten",
|
"lg-titel-edit": "Lager: bearbeiten",
|
||||||
"lg-titel-hand-yaml": "Hand-YAML fuer den Abgleich (leer = keiner)",
|
|
||||||
"lg-prompt-kontur-geschoss": "\nBelagskontur des Geschosses waehlen (geschlossene Polylinie) <Enter = zeichnen>: ",
|
"lg-prompt-kontur-geschoss": "\nBelagskontur des Geschosses waehlen (geschlossene Polylinie) <Enter = zeichnen>: ",
|
||||||
"lg-prompt-kontur-bereich": "\nKontur des Lagerbereichs waehlen (geschlossene Polylinie) <Enter = zeichnen>: ",
|
"lg-prompt-kontur-bereich": "\nKontur des Lagerbereichs waehlen (geschlossene Polylinie) <Enter = zeichnen>: ",
|
||||||
"lg-kontur-zeichnen": "\nKontur als Polylinie zeichnen (Enter beendet, wird geschlossen).",
|
"lg-kontur-zeichnen": "\nKontur als Polylinie zeichnen (Enter beendet, wird geschlossen).",
|
||||||
@@ -1270,11 +1271,10 @@
|
|||||||
"lg-exp-keine-geschosse": "Keine Geschosse (LG_GESCHOSS) in der Zeichnung - levels bleiben leer.",
|
"lg-exp-keine-geschosse": "Keine Geschosse (LG_GESCHOSS) in der Zeichnung - levels bleiben leer.",
|
||||||
"lg-exp-geschoss-ohne-kontur": "Geschoss %1 hat keine Belagskontur mehr.",
|
"lg-exp-geschoss-ohne-kontur": "Geschoss %1 hat keine Belagskontur mehr.",
|
||||||
"lg-exp-datei-fehler": "\n[Lager] Datei nicht schreibbar: %1",
|
"lg-exp-datei-fehler": "\n[Lager] Datei nicht schreibbar: %1",
|
||||||
"lg-exp-raw": "\n[Lager] Rohdaten: %1",
|
"lg-exp-json": "\n[Lager] Technische Daten: %1",
|
||||||
"lg-exp-yaml": "\n[Lager] Overlay-YAML: %1\n[Lager] Nachweis: %2",
|
"lg-exp-lichte-hoehe-oben": "Geschoss %1 (oberstes): lichte Hoehe nicht berechenbar - LICHTE_HOEHE_mm setzen.",
|
||||||
"lg-exp-ohne-python": "\n[Lager] Python-Aufruf nicht moeglich (export.lsp/DXFM_LIB fehlt) - YAML von Hand erzeugen: python lib/lager_yaml_export.py <raw.json> <out.yaml>",
|
"lg-exp-korb-hallenboden": "Bereich %1 hat Gitterkorb unter den Reihen, Geschoss %2 ist aber Hallenboden - nicht gezaehlt.",
|
||||||
"lg-exp-python-fehler": "\n[Lager] lager_yaml_export.py endete mit Code %1 - siehe %2",
|
"lg-exp-reihen-ohne-geschoss": "%1 Regalreihe(n) ohne bekanntes Geschoss - nicht in den Kennwerten enthalten.",
|
||||||
"lg-hand-yaml": "\nHand-YAML fuer den Abgleich: %1",
|
|
||||||
"lg-regel-profil-fehlt": "\n[Lager] Regelprofil %1 nicht gefunden (%2).",
|
"lg-regel-profil-fehlt": "\n[Lager] Regelprofil %1 nicht gefunden (%2).",
|
||||||
"lg-regel-profil-ungepflegt": "\n[Lager] WARNUNG: Regelprofil %1 ist nicht gepflegt - es gelten die geerbten Werte.",
|
"lg-regel-profil-ungepflegt": "\n[Lager] WARNUNG: Regelprofil %1 ist nicht gepflegt - es gelten die geerbten Werte.",
|
||||||
"lg-regel-unbekannt": "\n[Lager] Regel %1 nicht im Profil.",
|
"lg-regel-unbekannt": "\n[Lager] Regel %1 nicht im Profil.",
|
||||||
|
|||||||
+6
-6
@@ -1215,6 +1215,8 @@
|
|||||||
"lg-feld-rand_w": "\nPerimeter aisle west (mm, 0 = none)",
|
"lg-feld-rand_w": "\nPerimeter aisle west (mm, 0 = none)",
|
||||||
"lg-feld-breite": "\nAisle width (mm)",
|
"lg-feld-breite": "\nAisle width (mm)",
|
||||||
"lg-feld-art": "\nAisle type",
|
"lg-feld-art": "\nAisle type",
|
||||||
|
"lg-feld-unter": "\nBelow the rows (gitterrost/gitterkorb/keine)",
|
||||||
|
"lg-feld-korbhoehe": "\nMesh basket height (mm)",
|
||||||
"lg-titel-gang": "Storage: insert aisles",
|
"lg-titel-gang": "Storage: insert aisles",
|
||||||
"lg-prompt-gang-start": "\nStart point of the aisle centre line or [%1] <Enter = finish>: ",
|
"lg-prompt-gang-start": "\nStart point of the aisle centre line or [%1] <Enter = finish>: ",
|
||||||
"lg-key-rechteck": "Rectangle",
|
"lg-key-rechteck": "Rectangle",
|
||||||
@@ -1245,7 +1247,6 @@
|
|||||||
"lg-titel-bereich": "Storage: create storage area",
|
"lg-titel-bereich": "Storage: create storage area",
|
||||||
"lg-titel-reihe": "Storage: insert rack rows",
|
"lg-titel-reihe": "Storage: insert rack rows",
|
||||||
"lg-titel-edit": "Storage: edit",
|
"lg-titel-edit": "Storage: edit",
|
||||||
"lg-titel-hand-yaml": "Manual YAML for comparison (empty = none)",
|
|
||||||
"lg-prompt-kontur-geschoss": "\nSelect floor contour of the level (closed polyline) <Enter = draw>: ",
|
"lg-prompt-kontur-geschoss": "\nSelect floor contour of the level (closed polyline) <Enter = draw>: ",
|
||||||
"lg-prompt-kontur-bereich": "\nSelect contour of the storage area (closed polyline) <Enter = draw>: ",
|
"lg-prompt-kontur-bereich": "\nSelect contour of the storage area (closed polyline) <Enter = draw>: ",
|
||||||
"lg-kontur-zeichnen": "\nDraw the contour as polyline (Enter finishes, it will be closed).",
|
"lg-kontur-zeichnen": "\nDraw the contour as polyline (Enter finishes, it will be closed).",
|
||||||
@@ -1270,11 +1271,10 @@
|
|||||||
"lg-exp-keine-geschosse": "No levels (LG_GESCHOSS) in the drawing - levels stay empty.",
|
"lg-exp-keine-geschosse": "No levels (LG_GESCHOSS) in the drawing - levels stay empty.",
|
||||||
"lg-exp-geschoss-ohne-kontur": "Level %1 has no floor contour any more.",
|
"lg-exp-geschoss-ohne-kontur": "Level %1 has no floor contour any more.",
|
||||||
"lg-exp-datei-fehler": "\n[Storage] File not writable: %1",
|
"lg-exp-datei-fehler": "\n[Storage] File not writable: %1",
|
||||||
"lg-exp-raw": "\n[Storage] Raw data: %1",
|
"lg-exp-json": "\n[Storage] Technical data: %1",
|
||||||
"lg-exp-yaml": "\n[Storage] Overlay YAML: %1\n[Storage] Report: %2",
|
"lg-exp-lichte-hoehe-oben": "Level %1 (top): clear height cannot be calculated - set LICHTE_HOEHE_mm.",
|
||||||
"lg-exp-ohne-python": "\n[Storage] Cannot call Python (export.lsp/DXFM_LIB missing) - create the YAML manually: python lib/lager_yaml_export.py <raw.json> <out.yaml>",
|
"lg-exp-korb-hallenboden": "Area %1 has a mesh basket below the rows, but level %2 is a hall floor - not counted.",
|
||||||
"lg-exp-python-fehler": "\n[Storage] lager_yaml_export.py ended with code %1 - see %2",
|
"lg-exp-reihen-ohne-geschoss": "%1 rack row(s) without a known level - not included in the key figures.",
|
||||||
"lg-hand-yaml": "\nManual YAML for comparison: %1",
|
|
||||||
"lg-regel-profil-fehlt": "\n[Storage] Rule profile %1 not found (%2).",
|
"lg-regel-profil-fehlt": "\n[Storage] Rule profile %1 not found (%2).",
|
||||||
"lg-regel-profil-ungepflegt": "\n[Storage] WARNING: rule profile %1 is not maintained - inherited values apply.",
|
"lg-regel-profil-ungepflegt": "\n[Storage] WARNING: rule profile %1 is not maintained - inherited values apply.",
|
||||||
"lg-regel-unbekannt": "\n[Storage] Rule %1 not in profile.",
|
"lg-regel-unbekannt": "\n[Storage] Rule %1 not in profile.",
|
||||||
|
|||||||
@@ -1,433 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
lager_yaml_export.py - Lagerplanung aus BricsCAD -> Overlay-YAML fuer das RFQ-Programm.
|
|
||||||
|
|
||||||
Liest die von LAGER_EXPORT (Lisp/LagerInsert.lsp) geschriebene Rohdatei
|
|
||||||
<zeichnung>_lager_raw.json und erzeugt daraus
|
|
||||||
|
|
||||||
<projekt>_drawing.yaml gleiches Schema wie die Hand-YAML (z.B.
|
|
||||||
cfg/example_goh_storage.yaml), aber NUR mit den
|
|
||||||
Feldern, die die Zeichnung liefert, plus
|
|
||||||
_provenance (Herkunft/Formel je Wert),
|
|
||||||
_conflicts (Abweichungen zur Hand-YAML) und
|
|
||||||
_warnings.
|
|
||||||
<projekt>_nachweis.html interner Mengen-Nachweis (optional, --nachweis)
|
|
||||||
|
|
||||||
Merge-Vertrag (umgesetzt im RFQ-Repo): Hand-Wert vorhanden und nicht null ->
|
|
||||||
Hand gewinnt; sonst Zeichnungswert. Abweichungen erscheinen in _conflicts.
|
|
||||||
|
|
||||||
Python aggregiert nur - jede fachliche Regel lebt in LISP
|
|
||||||
(Lisp/LagerPruefung.lsp, siehe doc/plan/lager_rfq.md).
|
|
||||||
|
|
||||||
Aufruf:
|
|
||||||
python lager_yaml_export.py <lager_raw.json> <out_drawing.yaml>
|
|
||||||
[--hand <hand.yaml>] [--nachweis <out.html>]
|
|
||||||
"""
|
|
||||||
|
|
||||||
import argparse
|
|
||||||
import html
|
|
||||||
import json
|
|
||||||
import sys
|
|
||||||
from collections import Counter, OrderedDict
|
|
||||||
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
# Vergleichstoleranz Hand <-> Zeichnung: relativ 1 % ODER absolut 0,005
|
|
||||||
REL_TOL = 0.01
|
|
||||||
ABS_TOL = 0.005
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------ Einlesen
|
|
||||||
|
|
||||||
def lade_raw(pfad):
|
|
||||||
"""Rohdaten laden. AutoLISP schreibt im ANSI-Codepage -> cp1252-Rueckfall."""
|
|
||||||
with open(pfad, "rb") as f:
|
|
||||||
roh = f.read()
|
|
||||||
try:
|
|
||||||
text = roh.decode("utf-8")
|
|
||||||
except UnicodeDecodeError:
|
|
||||||
text = roh.decode("cp1252")
|
|
||||||
return json.loads(text)
|
|
||||||
|
|
||||||
|
|
||||||
def _zahl(v, vorgabe=0.0):
|
|
||||||
return float(v) if isinstance(v, (int, float)) else vorgabe
|
|
||||||
|
|
||||||
|
|
||||||
def _m(mm, stellen=3):
|
|
||||||
return round(_zahl(mm) / 1000.0, stellen)
|
|
||||||
|
|
||||||
|
|
||||||
def _m2(mm2, stellen=1):
|
|
||||||
return round(_zahl(mm2) / 1e6, stellen)
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------ Aggregation
|
|
||||||
|
|
||||||
class Sammler:
|
|
||||||
"""Werte mit Herkunft sammeln: setze() schreibt in das Overlay und die Provenienz."""
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
self.provenance = OrderedDict()
|
|
||||||
self.warnungen = []
|
|
||||||
|
|
||||||
def herkunft(self, pfad, wert, quelle, formel):
|
|
||||||
self.provenance[pfad] = {"wert": wert, "quelle": quelle, "formel": formel}
|
|
||||||
return wert
|
|
||||||
|
|
||||||
def warnung(self, text):
|
|
||||||
if text not in self.warnungen:
|
|
||||||
self.warnungen.append(text)
|
|
||||||
|
|
||||||
|
|
||||||
def _haeufigster(werte, pfad, s):
|
|
||||||
"""Haeufigster Wert; bei mehreren verschiedenen Werten eine Warnung."""
|
|
||||||
werte = [w for w in werte if w is not None]
|
|
||||||
if not werte:
|
|
||||||
return None
|
|
||||||
zaehlung = Counter(werte)
|
|
||||||
wert, _ = zaehlung.most_common(1)[0]
|
|
||||||
if len(zaehlung) > 1:
|
|
||||||
s.warnung("%s: Bereiche mit unterschiedlichen Werten %s - haeufigster Wert %s uebernommen"
|
|
||||||
% (pfad, sorted(zaehlung), wert))
|
|
||||||
return wert
|
|
||||||
|
|
||||||
|
|
||||||
def _haengeebenen(reihen):
|
|
||||||
"""Laenge je Haengeebene (Schienenhoehe, Warenlaenge) summieren.
|
|
||||||
|
|
||||||
Jede Reihe traegt ihre Laenge in jede ihrer Haengeebenen ein -
|
|
||||||
rack_length_m ist die Summe aller Reihen der Ebene.
|
|
||||||
"""
|
|
||||||
summen = OrderedDict()
|
|
||||||
for r in reihen:
|
|
||||||
for e in r.get("haengeebenen") or []:
|
|
||||||
key = (_zahl(e.get("schienenhoehe_mm")), _zahl(e.get("warenlaenge_mm")))
|
|
||||||
summen[key] = summen.get(key, 0.0) + _zahl(r.get("laenge_mm"))
|
|
||||||
return [{"rail_height_m": _m(h), "rack_length_m": round(l / 1000.0, 1), "goods_length_m": _m(w)}
|
|
||||||
for (h, w), l in sorted(summen.items(), key=lambda kv: -kv[0][0])]
|
|
||||||
|
|
||||||
|
|
||||||
def aggregiere(raw):
|
|
||||||
"""Rohdaten -> (overlay, sammler). overlay enthaelt nur Zeichnungswerte."""
|
|
||||||
s = Sammler()
|
|
||||||
for w in raw.get("warnungen") or []:
|
|
||||||
s.warnung(w)
|
|
||||||
|
|
||||||
belag_yaml = raw.get("belag_yaml") or {}
|
|
||||||
reihen_als_gitter = bool(raw.get("reihen_als_gitterrost"))
|
|
||||||
geschosse = sorted(raw.get("geschosse") or [],
|
|
||||||
key=lambda g: (_zahl(g.get("hoehe_belag_mm")), g.get("nr") or 0))
|
|
||||||
bereiche = raw.get("bereiche") or []
|
|
||||||
alle_reihen = list(raw.get("reihen") or [])
|
|
||||||
gaenge = raw.get("gaenge") or []
|
|
||||||
|
|
||||||
ohne_geschoss = [r for r in alle_reihen if r.get("geschoss") is None]
|
|
||||||
if ohne_geschoss and geschosse:
|
|
||||||
s.warnung("%d Regalreihe(n) ohne Geschoss - nicht in levels enthalten" % len(ohne_geschoss))
|
|
||||||
|
|
||||||
overlay = OrderedDict()
|
|
||||||
|
|
||||||
# ---------------------------------------------------------- layout
|
|
||||||
layout = OrderedDict()
|
|
||||||
if bereiche:
|
|
||||||
quelle = "LG_BEREICH (%d Bereich(e))" % len(bereiche)
|
|
||||||
felder = [
|
|
||||||
("aisle_width_m", "gangbreite_mm", lambda v: _m(v), "GANGBREITE_mm / 1000"),
|
|
||||||
("rack_rows_per_aisle", "reihen_je_gang", int, "REIHEN_JE_GANG"),
|
|
||||||
("rack_depth_m", "regaltiefe_mm", lambda v: _m(v), "REGALTIEFE_mm / 1000"),
|
|
||||||
("trolley_rails_per_aisle", "schienen_je_gang", int, "SCHIENEN_JE_GANG"),
|
|
||||||
]
|
|
||||||
for feld, key, conv, formel in felder:
|
|
||||||
w = _haeufigster([conv(b[key]) for b in bereiche if b.get(key) is not None],
|
|
||||||
"layout." + feld, s)
|
|
||||||
if w is not None:
|
|
||||||
layout[feld] = s.herkunft("layout." + feld, w, quelle, formel)
|
|
||||||
elif alle_reihen:
|
|
||||||
w = _haeufigster([_m(r["tiefe_mm"]) for r in alle_reihen if r.get("tiefe_mm") is not None],
|
|
||||||
"layout.rack_depth_m", s)
|
|
||||||
if w is not None:
|
|
||||||
layout["rack_depth_m"] = s.herkunft("layout.rack_depth_m", w,
|
|
||||||
"Regalreihen (Tiefe)", "haeufigste Reihentiefe")
|
|
||||||
|
|
||||||
# Gaenge je Geschoss: Anzahl und Summe der Laengen (nur Gaenge zwischen den
|
|
||||||
# Reihen, ART=gang - auch manuelle). Randgaenge entlang der Kontur zaehlen
|
|
||||||
# nicht als aisle, stecken aber im Belag (walkway) und werden im Detail genannt.
|
|
||||||
gang_je_gs = {}
|
|
||||||
rand_je_gs = {}
|
|
||||||
for g in gaenge:
|
|
||||||
if g.get("art") == "gang":
|
|
||||||
n, l = gang_je_gs.get(g.get("geschoss"), (0, 0.0))
|
|
||||||
gang_je_gs[g.get("geschoss")] = (n + 1, l + _zahl(g.get("laenge_mm")))
|
|
||||||
elif g.get("art") == "randgang":
|
|
||||||
rand_je_gs[g.get("geschoss")] = rand_je_gs.get(g.get("geschoss"), 0.0) + _zahl(g.get("laenge_mm"))
|
|
||||||
if gang_je_gs:
|
|
||||||
gs_max = max(gang_je_gs, key=lambda k: gang_je_gs[k][1])
|
|
||||||
detail = ", ".join("G%s: %d / %.1f m" % (k, v[0], v[1] / 1000.0)
|
|
||||||
for k, v in sorted(gang_je_gs.items(), key=lambda kv: str(kv[0])))
|
|
||||||
if rand_je_gs:
|
|
||||||
detail += "; ohne Randgaenge " + ", ".join(
|
|
||||||
"G%s: %.1f m" % (k, v / 1000.0)
|
|
||||||
for k, v in sorted(rand_je_gs.items(), key=lambda kv: str(kv[0])))
|
|
||||||
layout["aisles"] = s.herkunft("layout.aisles", gang_je_gs[gs_max][0],
|
|
||||||
"LG_GANG_* (ART=gang)",
|
|
||||||
"Anzahl Hauptgaenge, Geschoss mit der groessten Ganglaenge (%s)" % detail)
|
|
||||||
layout["aisle_length_m"] = s.herkunft("layout.aisle_length_m",
|
|
||||||
round(gang_je_gs[gs_max][1] / 1000.0, 1),
|
|
||||||
"LG_GANG_* (ART=gang)",
|
|
||||||
"Summe Hauptganglaengen je Ebene, groesste (%s)" % detail)
|
|
||||||
|
|
||||||
bboxen = [g["kontur_bbox"] for g in geschosse if g.get("kontur_bbox")]
|
|
||||||
if bboxen:
|
|
||||||
xmin = min(b[0] for b in bboxen)
|
|
||||||
ymin = min(b[1] for b in bboxen)
|
|
||||||
xmax = max(b[2] for b in bboxen)
|
|
||||||
ymax = max(b[3] for b in bboxen)
|
|
||||||
dx, dy = xmax - xmin, ymax - ymin
|
|
||||||
layout["block_length_m"] = s.herkunft("layout.block_length_m", round(max(dx, dy) / 1000.0, 2),
|
|
||||||
"Belagskonturen LG_GESCHOSS",
|
|
||||||
"achsparallele Huelle aller Konturen, laengere Seite")
|
|
||||||
layout["block_width_m"] = s.herkunft("layout.block_width_m", round(min(dx, dy) / 1000.0, 2),
|
|
||||||
"Belagskonturen LG_GESCHOSS",
|
|
||||||
"achsparallele Huelle aller Konturen, kuerzere Seite")
|
|
||||||
if layout:
|
|
||||||
overlay["layout"] = layout
|
|
||||||
|
|
||||||
# ---------------------------------------------------------- levels
|
|
||||||
levels = []
|
|
||||||
for i, g in enumerate(geschosse):
|
|
||||||
p = "levels[%d]" % i
|
|
||||||
nr = g.get("nr")
|
|
||||||
lv = OrderedDict()
|
|
||||||
if g.get("bezeichnung"):
|
|
||||||
lv["remark"] = s.herkunft(p + ".remark", g["bezeichnung"], "LG_GESCHOSS %s" % nr, "BEZEICHNUNG")
|
|
||||||
lv["floor_elevation_m"] = s.herkunft(p + ".floor_elevation_m", _m(g.get("hoehe_belag_mm")),
|
|
||||||
"LG_GESCHOSS %s" % nr, "HOEHE_BELAG_mm / 1000")
|
|
||||||
if g.get("lichte_hoehe_mm") is not None:
|
|
||||||
lv["clear_height_m"] = s.herkunft(p + ".clear_height_m", _m(g["lichte_hoehe_mm"]),
|
|
||||||
"LG_GESCHOSS %s" % nr, "LICHTE_HOEHE_mm (Vorgabe)")
|
|
||||||
elif i + 1 < len(geschosse):
|
|
||||||
nx = geschosse[i + 1]
|
|
||||||
lichte = _zahl(nx.get("hoehe_belag_mm")) - _zahl(nx.get("konstr_hoehe_mm")) \
|
|
||||||
- _zahl(g.get("hoehe_belag_mm"))
|
|
||||||
lv["clear_height_m"] = s.herkunft(
|
|
||||||
p + ".clear_height_m", _m(lichte), "LG_GESCHOSS %s / %s" % (nr, nx.get("nr")),
|
|
||||||
"Belag darueber (%s) - Konstruktionshoehe darueber (%s) - eigener Belag (%s), mm"
|
|
||||||
% (nx.get("hoehe_belag_mm"), nx.get("konstr_hoehe_mm"), g.get("hoehe_belag_mm")))
|
|
||||||
else:
|
|
||||||
s.warnung("Geschoss %s (oberstes): clear_height_m nicht berechenbar - LICHTE_HOEHE_mm setzen" % nr)
|
|
||||||
|
|
||||||
reihen = [r for r in alle_reihen if r.get("geschoss") == nr]
|
|
||||||
hl = _haengeebenen(reihen)
|
|
||||||
if hl:
|
|
||||||
lv["hanging_levels"] = hl
|
|
||||||
for j, e in enumerate(hl):
|
|
||||||
s.herkunft("%s.hanging_levels[%d].rack_length_m" % (p, j), e["rack_length_m"],
|
|
||||||
"%d Regalreihe(n) Geschoss %s" % (len(reihen), nr),
|
|
||||||
"Summe LAENGE aller Reihen mit Schienenhoehe %s / Warenlaenge %s"
|
|
||||||
% (e["rail_height_m"], e["goods_length_m"]))
|
|
||||||
|
|
||||||
spec = belag_yaml.get(g.get("belag_art") or "", g.get("belag_art"))
|
|
||||||
if spec: # Buehne (kein Hallenboden)
|
|
||||||
gs_gaenge = [x for x in gaenge if x.get("geschoss") == nr]
|
|
||||||
belag = sum(_zahl(x.get("laenge_mm")) * _zahl(x.get("breite_mm"))
|
|
||||||
for x in gs_gaenge if x.get("belag") != "gitterrost")
|
|
||||||
gitter = sum(_zahl(x.get("laenge_mm")) * _zahl(x.get("breite_mm"))
|
|
||||||
for x in gs_gaenge if x.get("belag") == "gitterrost")
|
|
||||||
reihen_fl = sum(_zahl(r.get("laenge_mm")) * _zahl(r.get("tiefe_mm")) for r in reihen)
|
|
||||||
if reihen_als_gitter:
|
|
||||||
gitter += reihen_fl
|
|
||||||
if gs_gaenge:
|
|
||||||
formel = "Summe LAENGE x BREITE der Gaenge/Quergaenge mit Belag"
|
|
||||||
quelle = "LG_GANG_* Geschoss %s, %d Flaeche(n)" % (nr, len(gs_gaenge))
|
|
||||||
else:
|
|
||||||
# Ohne Gangflaechen: Belag = Kontur minus Reihengrundflaeche
|
|
||||||
belag = _zahl(g.get("kontur_flaeche_mm2")) - reihen_fl
|
|
||||||
formel = "Konturflaeche - Grundflaeche der Regalreihen (keine LG_GANG-Flaechen)"
|
|
||||||
quelle = "Belagskontur Geschoss %s" % nr
|
|
||||||
lv["walkway"] = OrderedDict([
|
|
||||||
("area_m2", s.herkunft(p + ".walkway.area_m2", _m2(belag), quelle, formel)),
|
|
||||||
("spec", s.herkunft(p + ".walkway.spec", spec, "LG_GESCHOSS %s" % nr, "BELAG_ART")),
|
|
||||||
])
|
|
||||||
lv["grating"] = s.herkunft(
|
|
||||||
p + ".grating", _m2(gitter), "Geschoss %s" % nr,
|
|
||||||
"Gaenge mit Belag gitterrost" + (" + Grundflaeche der Regalreihen (Laenge x Tiefe)"
|
|
||||||
if reihen_als_gitter else ""))
|
|
||||||
levels.append(lv)
|
|
||||||
if levels:
|
|
||||||
overlay["levels"] = levels
|
|
||||||
return overlay, s
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------ Abgleich
|
|
||||||
|
|
||||||
def _gleich(a, b):
|
|
||||||
if isinstance(a, bool) or isinstance(b, bool):
|
|
||||||
return a == b
|
|
||||||
if isinstance(a, (int, float)) and isinstance(b, (int, float)):
|
|
||||||
return abs(a - b) <= max(ABS_TOL, REL_TOL * max(abs(a), abs(b)))
|
|
||||||
return str(a).strip() == str(b).strip()
|
|
||||||
|
|
||||||
|
|
||||||
def _blaetter(obj, pfad=""):
|
|
||||||
"""(pfad, wert) aller Blattwerte; Listen per Index, _-Schluessel ausgenommen."""
|
|
||||||
if isinstance(obj, dict):
|
|
||||||
for k, v in obj.items():
|
|
||||||
if str(k).startswith("_"):
|
|
||||||
continue
|
|
||||||
yield from _blaetter(v, "%s.%s" % (pfad, k) if pfad else str(k))
|
|
||||||
elif isinstance(obj, list):
|
|
||||||
for i, v in enumerate(obj):
|
|
||||||
yield from _blaetter(v, "%s[%d]" % (pfad, i))
|
|
||||||
else:
|
|
||||||
yield pfad, obj
|
|
||||||
|
|
||||||
|
|
||||||
def _hole(obj, pfad):
|
|
||||||
"""Wert unter pfad ("levels[1].walkway.area_m2"); (gefunden, wert)."""
|
|
||||||
teile = []
|
|
||||||
for t in pfad.split("."):
|
|
||||||
while "[" in t:
|
|
||||||
name, rest = t.split("[", 1)
|
|
||||||
if name:
|
|
||||||
teile.append(name)
|
|
||||||
idx, t = rest.split("]", 1)
|
|
||||||
teile.append(int(idx))
|
|
||||||
if t:
|
|
||||||
teile.append(t)
|
|
||||||
cur = obj
|
|
||||||
for t in teile:
|
|
||||||
if isinstance(t, int):
|
|
||||||
if not isinstance(cur, list) or t >= len(cur):
|
|
||||||
return False, None
|
|
||||||
cur = cur[t]
|
|
||||||
else:
|
|
||||||
if not isinstance(cur, dict) or t not in cur:
|
|
||||||
return False, None
|
|
||||||
cur = cur[t]
|
|
||||||
return True, cur
|
|
||||||
|
|
||||||
|
|
||||||
def abgleich(overlay, hand):
|
|
||||||
"""Overlay gegen Hand-YAML: (konflikte, fuellt).
|
|
||||||
|
|
||||||
konflikte = Hand hat einen anderen Wert (Hand gewinnt beim Merge),
|
|
||||||
fuellt = Hand-Feld fehlt oder ist null (Zeichnung fuellt es).
|
|
||||||
"""
|
|
||||||
konflikte, fuellt = [], []
|
|
||||||
for pfad, wert in _blaetter(overlay):
|
|
||||||
gefunden, h = _hole(hand, pfad)
|
|
||||||
if not gefunden or h is None:
|
|
||||||
fuellt.append({"pfad": pfad, "zeichnung": wert})
|
|
||||||
elif not isinstance(h, (dict, list)) and not _gleich(h, wert):
|
|
||||||
k = {"pfad": pfad, "hand": h, "zeichnung": wert}
|
|
||||||
if isinstance(h, (int, float)) and isinstance(wert, (int, float)) and h:
|
|
||||||
k["abweichung_prozent"] = round((wert - h) / abs(h) * 100.0, 1)
|
|
||||||
konflikte.append(k)
|
|
||||||
n_hand = len(hand.get("levels") or []) if isinstance(hand, dict) else 0
|
|
||||||
n_zg = len(overlay.get("levels") or [])
|
|
||||||
if n_hand and n_zg and n_hand != n_zg:
|
|
||||||
konflikte.append({"pfad": "levels", "hand": "%d Ebenen" % n_hand,
|
|
||||||
"zeichnung": "%d Ebenen" % n_zg})
|
|
||||||
return konflikte, fuellt
|
|
||||||
|
|
||||||
|
|
||||||
# ------------------------------------------------------------------ Ausgabe
|
|
||||||
|
|
||||||
def _yaml_text(daten):
|
|
||||||
def _dict_repr(dumper, d):
|
|
||||||
return dumper.represent_mapping("tag:yaml.org,2002:map", d.items())
|
|
||||||
yaml.SafeDumper.add_representer(OrderedDict, _dict_repr)
|
|
||||||
return yaml.safe_dump(daten, sort_keys=False, allow_unicode=True,
|
|
||||||
default_flow_style=False, width=120)
|
|
||||||
|
|
||||||
|
|
||||||
def baue_ausgabe(raw, hand=None):
|
|
||||||
overlay, s = aggregiere(raw)
|
|
||||||
ausgabe = OrderedDict(overlay)
|
|
||||||
ausgabe["_provenance"] = s.provenance
|
|
||||||
konflikte, fuellt = abgleich(overlay, hand) if hand is not None else ([], [])
|
|
||||||
ausgabe["_conflicts"] = konflikte
|
|
||||||
ausgabe["_warnings"] = s.warnungen
|
|
||||||
return ausgabe, fuellt
|
|
||||||
|
|
||||||
|
|
||||||
def schreibe_yaml(pfad, ausgabe, raw):
|
|
||||||
kopf = ("# Overlay aus der Zeichnung - erzeugt von lib/lager_yaml_export.py\n"
|
|
||||||
"# Zeichnung: %s (%s)\n"
|
|
||||||
"# Merge im RFQ-Programm: Hand-YAML gewinnt, diese Werte fuellen nur fehlende/null-Felder.\n"
|
|
||||||
"# _provenance/_conflicts/_warnings sind Zusatzinformation und kein Teil des RFQ-Schemas.\n"
|
|
||||||
% (raw.get("zeichnung", "?"), raw.get("erzeugt", "?")))
|
|
||||||
with open(pfad, "w", encoding="utf-8", newline="\n") as f:
|
|
||||||
f.write(kopf)
|
|
||||||
f.write(_yaml_text(ausgabe))
|
|
||||||
|
|
||||||
|
|
||||||
def schreibe_nachweis(pfad, ausgabe, fuellt, raw):
|
|
||||||
e = html.escape
|
|
||||||
|
|
||||||
def tabelle(kopf, zeilen):
|
|
||||||
z = "".join("<tr>%s</tr>" % "".join("<td>%s</td>" % e(str(c)) for c in r) for r in zeilen)
|
|
||||||
return "<table><thead><tr>%s</tr></thead><tbody>%s</tbody></table>" % (
|
|
||||||
"".join("<th>%s</th>" % e(k) for k in kopf), z or "<tr><td colspan=9>-</td></tr>")
|
|
||||||
|
|
||||||
teile = [
|
|
||||||
"<!doctype html><html lang='de'><head><meta charset='utf-8'><title>Lager-Nachweis</title>",
|
|
||||||
"<style>body{font-family:Segoe UI,Arial,sans-serif;margin:24px;color:#222}"
|
|
||||||
"table{border-collapse:collapse;margin:8px 0 24px}td,th{border:1px solid #bbb;padding:4px 8px;"
|
|
||||||
"text-align:left;vertical-align:top}th{background:#eee}.w{color:#a40}</style></head><body>",
|
|
||||||
"<h1>Lager-Nachweis (Mengen)</h1>",
|
|
||||||
"<p>Zeichnung: %s<br>Erzeugt: %s<br>Regelprofil: %s</p>" % (
|
|
||||||
e(str(raw.get("zeichnung"))), e(str(raw.get("erzeugt"))), e(str(raw.get("land")))),
|
|
||||||
"<p class='w'>Interner Nachweis - die Pruefung gegen ASR/DGUV/EN ISO 14122 folgt in Phase 4.</p>",
|
|
||||||
"<h2>Warnungen</h2>",
|
|
||||||
"<ul>%s</ul>" % ("".join("<li class='w'>%s</li>" % e(w) for w in ausgabe["_warnings"]) or "<li>keine</li>"),
|
|
||||||
"<h2>Werte aus der Zeichnung</h2>",
|
|
||||||
tabelle(["Feld", "Wert", "Quelle", "Formel"],
|
|
||||||
[(k, v["wert"], v["quelle"], v["formel"]) for k, v in ausgabe["_provenance"].items()]),
|
|
||||||
"<h2>Konflikte mit der Hand-YAML (Hand gewinnt)</h2>",
|
|
||||||
tabelle(["Feld", "Hand", "Zeichnung", "Abweichung %"],
|
|
||||||
[(k["pfad"], k["hand"], k["zeichnung"], k.get("abweichung_prozent", ""))
|
|
||||||
for k in ausgabe["_conflicts"]]),
|
|
||||||
"<h2>Von der Zeichnung gefuellte Felder (Hand leer/null)</h2>",
|
|
||||||
tabelle(["Feld", "Zeichnung"], [(f["pfad"], f["zeichnung"]) for f in fuellt]),
|
|
||||||
"</body></html>",
|
|
||||||
]
|
|
||||||
with open(pfad, "w", encoding="utf-8", newline="\n") as f:
|
|
||||||
f.write("\n".join(teile))
|
|
||||||
|
|
||||||
|
|
||||||
def main(argv=None):
|
|
||||||
ap = argparse.ArgumentParser(description="Lager-Rohdaten -> RFQ-Overlay-YAML")
|
|
||||||
ap.add_argument("raw", help="<zeichnung>_lager_raw.json aus LAGER_EXPORT")
|
|
||||||
ap.add_argument("yaml", help="Ziel: <projekt>_drawing.yaml")
|
|
||||||
ap.add_argument("--hand", help="Hand-YAML fuer den Abgleich (Konfliktliste)")
|
|
||||||
ap.add_argument("--nachweis", help="Ziel: interner Nachweis als HTML")
|
|
||||||
a = ap.parse_args(argv)
|
|
||||||
|
|
||||||
try:
|
|
||||||
raw = lade_raw(a.raw)
|
|
||||||
except (OSError, ValueError) as ex:
|
|
||||||
print("FEHLER: Rohdaten nicht lesbar: %s" % ex, file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
hand = None
|
|
||||||
if a.hand:
|
|
||||||
try:
|
|
||||||
with open(a.hand, encoding="utf-8") as f:
|
|
||||||
hand = yaml.safe_load(f) or {}
|
|
||||||
except (OSError, yaml.YAMLError) as ex:
|
|
||||||
print("FEHLER: Hand-YAML nicht lesbar: %s" % ex, file=sys.stderr)
|
|
||||||
return 2
|
|
||||||
|
|
||||||
ausgabe, fuellt = baue_ausgabe(raw, hand)
|
|
||||||
schreibe_yaml(a.yaml, ausgabe, raw)
|
|
||||||
if a.nachweis:
|
|
||||||
schreibe_nachweis(a.nachweis, ausgabe, fuellt, raw)
|
|
||||||
print("Overlay: %s (%d Werte, %d Konflikt(e), %d Warnung(en))"
|
|
||||||
% (a.yaml, len(ausgabe["_provenance"]), len(ausgabe["_conflicts"]), len(ausgabe["_warnings"])))
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
sys.exit(main())
|
|
||||||
+2
-14
@@ -680,15 +680,9 @@
|
|||||||
<Command>^C^C(ssg-ensure "LagerPruefung") LG_REGELN</Command>
|
<Command>^C^C(ssg-ensure "LagerPruefung") LG_REGELN</Command>
|
||||||
</Macro>
|
</Macro>
|
||||||
</MenuMacro>
|
</MenuMacro>
|
||||||
<MenuMacro UID="MM_00152">
|
|
||||||
<Macro>
|
|
||||||
<Name>Hand-YAML fuer Abgleich</Name>
|
|
||||||
<Command>^C^C(ssg-ensure "LagerInsert") LAGER_HAND_YAML</Command>
|
|
||||||
</Macro>
|
|
||||||
</MenuMacro>
|
|
||||||
<MenuMacro UID="MM_00153">
|
<MenuMacro UID="MM_00153">
|
||||||
<Macro>
|
<Macro>
|
||||||
<Name>Export RFQ-YAML</Name>
|
<Name>Export Lager-JSON</Name>
|
||||||
<Command>^C^C(ssg-ensure "LagerInsert") LAGER_EXPORT</Command>
|
<Command>^C^C(ssg-ensure "LagerInsert") LAGER_EXPORT</Command>
|
||||||
</Macro>
|
</Macro>
|
||||||
</MenuMacro>
|
</MenuMacro>
|
||||||
@@ -1773,13 +1767,7 @@
|
|||||||
</MenuItem>
|
</MenuItem>
|
||||||
</PopMenuItem>
|
</PopMenuItem>
|
||||||
<PopMenuItem>
|
<PopMenuItem>
|
||||||
<NameRef>Hand-YAML fuer Abgleich</NameRef>
|
<NameRef>Export Lager-JSON</NameRef>
|
||||||
<MenuItem>
|
|
||||||
<MacroRef MenuMacroID="MM_00152"/>
|
|
||||||
</MenuItem>
|
|
||||||
</PopMenuItem>
|
|
||||||
<PopMenuItem>
|
|
||||||
<NameRef>Export RFQ-YAML</NameRef>
|
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<MacroRef MenuMacroID="MM_00153"/>
|
<MacroRef MenuMacroID="MM_00153"/>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|||||||
+1
-1
@@ -174,7 +174,7 @@
|
|||||||
(ssg-ensure "ssg_blocktools")
|
(ssg-ensure "ssg_blocktools")
|
||||||
(ssg-ensure "ssg_texttools")
|
(ssg-ensure "ssg_texttools")
|
||||||
(ssg-ensure "ssg_stueckliste")
|
(ssg-ensure "ssg_stueckliste")
|
||||||
;; Lagerplanung (RFQ-YAML): Regelprofile vor LagerInsert
|
;; Lagerplanung (Export Lager-JSON): Regelprofile vor LagerInsert
|
||||||
(ssg-ensure "LagerPruefung")
|
(ssg-ensure "LagerPruefung")
|
||||||
(ssg-ensure "LagerInsert")
|
(ssg-ensure "LagerInsert")
|
||||||
|
|
||||||
|
|||||||
+1
-2
@@ -145,8 +145,7 @@
|
|||||||
[--]
|
[--]
|
||||||
[Regale zaehlen]^C^C(ssg-ensure "LagerInsert") LG_REGALE
|
[Regale zaehlen]^C^C(ssg-ensure "LagerInsert") LG_REGALE
|
||||||
[Regelprofil anzeigen]^C^C(ssg-ensure "LagerPruefung") LG_REGELN
|
[Regelprofil anzeigen]^C^C(ssg-ensure "LagerPruefung") LG_REGELN
|
||||||
[Hand-YAML fuer Abgleich]^C^C(ssg-ensure "LagerInsert") LAGER_HAND_YAML
|
[<-Export Lager-JSON]^C^C(ssg-ensure "LagerInsert") LAGER_EXPORT
|
||||||
[<-Export RFQ-YAML]^C^C(ssg-ensure "LagerInsert") LAGER_EXPORT
|
|
||||||
[->HW Planung]
|
[->HW Planung]
|
||||||
[Materialfluss erzeugen]^C^C(ssg-ensure "HwPlanung") HW_MATERIALFLUSS
|
[Materialfluss erzeugen]^C^C(ssg-ensure "HwPlanung") HW_MATERIALFLUSS
|
||||||
[<-Symbole erzeugen]^C^C(ssg-ensure "HwPlanung") HW_SYMBOLE
|
[<-Symbole erzeugen]^C^C(ssg-ensure "HwPlanung") HW_SYMBOLE
|
||||||
|
|||||||
@@ -7,5 +7,3 @@ pytest==9.0.2
|
|||||||
# (lib/export_neighbors.py). Fehlt shapely, faellt die Broad-Phase automatisch
|
# (lib/export_neighbors.py). Fehlt shapely, faellt die Broad-Phase automatisch
|
||||||
# auf das Raster (omniflo_zellgroesse_mm) zurueck.
|
# auf das Raster (omniflo_zellgroesse_mm) zurueck.
|
||||||
shapely==2.1.2
|
shapely==2.1.2
|
||||||
# pyyaml: Overlay-YAML der Lagerplanung (lib/lager_yaml_export.py)
|
|
||||||
pyyaml==6.0.3
|
|
||||||
+50
-11
@@ -5,16 +5,15 @@
|
|||||||
;; - zwei Geschosse auf derselben 2D-Kontur (EG Hallenboden, OG 3100 mm)
|
;; - zwei Geschosse auf derselben 2D-Kontur (EG Hallenboden, OG 3100 mm)
|
||||||
;; - einen Lagerbereich 10000 x 6000 im OG mit Auto-Fuellung
|
;; - einen Lagerbereich 10000 x 6000 im OG mit Auto-Fuellung
|
||||||
;; und prueft Bloecke, Attribute, Layer, Neuberechnung (keine Verdopplung),
|
;; und prueft Bloecke, Attribute, Layer, Neuberechnung (keine Verdopplung),
|
||||||
;; den Neuaufbau einer geaenderten Reihe, die Rohdaten von LAGER_EXPORT und
|
;; den Neuaufbau einer geaenderten Reihe, die JSON-Daten von LAGER_EXPORT
|
||||||
;; die Zaehlung von LG_REGALE.
|
;; (inkl. Kennwerte und Gitterkorb) und die Zaehlung von LG_REGALE.
|
||||||
;;
|
;;
|
||||||
;; Aufruf in BricsCAD:
|
;; Aufruf in BricsCAD:
|
||||||
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_lager.lsp"))
|
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_lager.lsp"))
|
||||||
;; TEST_LAGER
|
;; TEST_LAGER
|
||||||
;;
|
;;
|
||||||
;; Speichert tests/output/lager_results.json (Konvention test_run_all)
|
;; Speichert tests/output/lager_results.json (Konvention test_run_all)
|
||||||
;; und tests/output/lager_tests_lager_raw.json (Eingabe fuer
|
;; und tests/output/lager_tests_lager.json (Beispiel der Export-Datei).
|
||||||
;; lib/lager_yaml_export.py).
|
|
||||||
;; ============================================================
|
;; ============================================================
|
||||||
|
|
||||||
(setq *tlg-pass* 0 *tlg-fail* 0 *tlg-fails* '())
|
(setq *tlg-pass* 0 *tlg-fail* 0 *tlg-fails* '())
|
||||||
@@ -80,7 +79,11 @@
|
|||||||
(mapcar '(lambda (ed) (cons (cdr (assoc 2 ed)) T))
|
(mapcar '(lambda (ed) (cons (cdr (assoc 2 ed)) T))
|
||||||
(vl-remove-if-not '(lambda (ed) (= (cdr (assoc 0 ed)) "ATTDEF")) (lg-blockdef-objekte bname))))
|
(vl-remove-if-not '(lambda (ed) (= (cdr (assoc 0 ed)) "ATTDEF")) (lg-blockdef-objekte bname))))
|
||||||
|
|
||||||
(defun lager:tests ( / k0 k1 g0 g1 kb bereich reihen gaenge r0 neu raw daten pfad f
|
;; Geschoss-Objekt Nr. nr aus den geparsten Export-Daten.
|
||||||
|
(defun tlg-export-geschoss (daten nr)
|
||||||
|
(vl-some '(lambda (g) (if (= (ssg-json-get g "nr") nr) g)) (ssg-json-get daten "geschosse")))
|
||||||
|
|
||||||
|
(defun lager:tests ( / k0 k1 g0 g1 kb bereich reihen gaenge r0 neu raw daten pfad f eg0 eg1 kr
|
||||||
kb2 b2 kinder mg mg2 hg alt eb
|
kb2 b2 kinder mg mg2 hg alt eb
|
||||||
r1 gg1 n-alt g2 r2 gg2 ids b2k n-kinder bb rg rk zl
|
r1 gg1 n-alt g2 r2 gg2 ids b2k n-kinder bb rg rk zl
|
||||||
b3 rh3 mg3 ge3 ag3 n3 mr3 alt3)
|
b3 rh3 mg3 ge3 ag3 n3 mr3 alt3)
|
||||||
@@ -159,23 +162,36 @@
|
|||||||
(tlg-eq "reihenzahl gleich" 8 (length (lg-alle-bloecke "LG_REIHE_*")))
|
(tlg-eq "reihenzahl gleich" 8 (length (lg-alle-bloecke "LG_REIHE_*")))
|
||||||
(tlg-eq "geaenderte reihe bleibt kind" T (if (member neu (lg-bereich-kinder bereich)) T nil))
|
(tlg-eq "geaenderte reihe bleibt kind" T (if (member neu (lg-bereich-kinder bereich)) T nil))
|
||||||
|
|
||||||
;; --- Rohdaten fuer LAGER_EXPORT ---
|
;; --- JSON-Daten von LAGER_EXPORT ---
|
||||||
(setq raw (lg-export-json))
|
(setq raw (lg-export-json))
|
||||||
(setq daten (ssg-json-parse raw))
|
(setq daten (ssg-json-parse raw))
|
||||||
|
(tlg-eq "export format" '("ssg-lager" 2) (list (ssg-json-get daten "format") (ssg-json-get daten "version")))
|
||||||
(tlg-eq "export geschosse" 2 (length (ssg-json-get daten "geschosse")))
|
(tlg-eq "export geschosse" 2 (length (ssg-json-get daten "geschosse")))
|
||||||
(tlg-eq "export bereiche" 1 (length (ssg-json-get daten "bereiche")))
|
(tlg-eq "export bereiche" 1 (length (ssg-json-get daten "bereiche")))
|
||||||
(tlg-eq "export reihen" 8 (length (ssg-json-get daten "reihen")))
|
(tlg-eq "export reihen" 8 (length (ssg-json-get daten "reihen")))
|
||||||
(tlg-eq "export land" "DE" (ssg-json-get daten "land"))
|
(tlg-eq "export land" "DE" (ssg-json-get daten "land"))
|
||||||
(tlg-eq "export konturflaeche" 6.0e7
|
(setq eg1 (tlg-export-geschoss daten 1) eg0 (tlg-export-geschoss daten 0))
|
||||||
(ssg-json-get (car (vl-remove-if-not '(lambda (g) (= (ssg-json-get g "nr") 1))
|
(tlg-eq "export konturflaeche" 6.0e7 (ssg-json-get (ssg-json-get eg1 "kontur") "flaeche_mm2"))
|
||||||
(ssg-json-get daten "geschosse")))
|
(tlg-eq "export konturpunkte" 4 (length (ssg-json-get (ssg-json-get eg1 "kontur") "punkte")))
|
||||||
"kontur_flaeche_mm2"))
|
|
||||||
(tlg-eq "export haengeebenen"
|
(tlg-eq "export haengeebenen"
|
||||||
'((("schienenhoehe_mm" . 2300) ("warenlaenge_mm" . 1200))
|
'((("schienenhoehe_mm" . 2300) ("warenlaenge_mm" . 1200))
|
||||||
(("schienenhoehe_mm" . 1100) ("warenlaenge_mm" . 1100)))
|
(("schienenhoehe_mm" . 1100) ("warenlaenge_mm" . 1100)))
|
||||||
(ssg-json-get (vl-some '(lambda (r) (if (= (ssg-json-get r "laenge_mm") 4000) r))
|
(ssg-json-get (vl-some '(lambda (r) (if (= (ssg-json-get r "laenge_mm") 4000) r))
|
||||||
(ssg-json-get daten "reihen"))
|
(ssg-json-get daten "reihen"))
|
||||||
"haengeebenen"))
|
"haengeebenen"))
|
||||||
|
(tlg-eq "export ecken" 4 (length (ssg-json-get (car (ssg-json-get daten "reihen")) "ecken")))
|
||||||
|
(tlg-eq "export ende" T (if (ssg-json-get (car (ssg-json-get daten "reihen")) "ende") T))
|
||||||
|
;; Kennwerte: Regallaenge = Summe der Reihen, lichte Hoehe EG = 3100 - 150 - 0
|
||||||
|
(tlg-eq "export regallaenge G1" (tlg-summe-attr (tlg-gs "LG_REIHE_*" 1) "LAENGE")
|
||||||
|
(ssg-json-get (ssg-json-get eg1 "kennwerte") "regallaenge_mm"))
|
||||||
|
(tlg-eq "export haengeebenen G1" 2 (length (ssg-json-get (ssg-json-get eg1 "kennwerte") "haengeebenen")))
|
||||||
|
(tlg-eq "export lichte G0" 2950 (ssg-json-get (ssg-json-get eg0 "kennwerte") "lichte_hoehe_mm"))
|
||||||
|
(tlg-eq "export G0 keine buehne" nil (ssg-json-get (ssg-json-get eg0 "kennwerte") "buehne"))
|
||||||
|
(tlg-eq "export G1 herkunft" T (if (ssg-json-get (ssg-json-get eg1 "herkunft") "gitterrostflaeche_mm2") T))
|
||||||
|
(tlg-eq "export G1 unter gitterrost" T
|
||||||
|
(vl-every '(lambda (r) (= (ssg-json-get r "unter_reihe") "gitterrost")) (ssg-json-get daten "reihen")))
|
||||||
|
(tlg-eq "export lager regallaenge" (ssg-json-get (ssg-json-get eg1 "kennwerte") "regallaenge_mm")
|
||||||
|
(ssg-json-get (ssg-json-get daten "lager") "regallaenge_mm"))
|
||||||
|
|
||||||
;; --- Randgaenge Nord + Sued, Schraffur je Belag ---
|
;; --- Randgaenge Nord + Sued, Schraffur je Belag ---
|
||||||
(setq kb2 (tlg-rechteck 20000.0 0.0 30000.0 6000.0))
|
(setq kb2 (tlg-rechteck 20000.0 0.0 30000.0 6000.0))
|
||||||
@@ -243,7 +259,29 @@
|
|||||||
(length (vl-remove-if-not '(lambda (g) (= (ssg-json-get g "quelle") "manuell"))
|
(length (vl-remove-if-not '(lambda (g) (= (ssg-json-get g "quelle") "manuell"))
|
||||||
(ssg-json-get daten "gaenge"))))
|
(ssg-json-get daten "gaenge"))))
|
||||||
|
|
||||||
(setq pfad (strcat (getenv "DXFMAKRO") "/tests/output/lager_tests_lager_raw.json"))
|
;; --- Gitterkorb unter den Reihen des ersten Bereichs (G1) ---
|
||||||
|
(lg-attribute-setzen bereich (list (cons "UNTER_REIHE" "gitterkorb") (cons "GITTERKORB_HOEHE_mm" "500")))
|
||||||
|
(setq raw (lg-export-json) daten (ssg-json-parse raw))
|
||||||
|
(setq kr (vl-remove-if-not '(lambda (r) (= (ssg-json-get r "unter_reihe") "gitterkorb"))
|
||||||
|
(ssg-json-get daten "reihen")))
|
||||||
|
(tlg-eq "gitterkorb: reihen" (length (vl-remove-if-not '(lambda (k) (wcmatch (cdr (assoc 2 (entget k))) "LG_REIHE_*"))
|
||||||
|
(lg-bereich-kinder bereich)))
|
||||||
|
(length kr))
|
||||||
|
(tlg-eq "gitterkorb: seitenflaeche > 0" T
|
||||||
|
(vl-every '(lambda (r) (> (ssg-json-get (ssg-json-get r "gitterkorb") "seitenflaeche_mm2") 0)) kr))
|
||||||
|
;; Ruecken an Ruecken: es sind nicht alle Laengsseiten offen
|
||||||
|
(tlg-eq "gitterkorb: anliegende kanten zu" T
|
||||||
|
(< (apply '+ (mapcar '(lambda (r) (ssg-json-get (ssg-json-get r "gitterkorb") "offen_laengs_mm")) kr))
|
||||||
|
(* 2.0 (apply '+ (mapcar '(lambda (r) (ssg-json-get r "laenge_mm")) kr)))))
|
||||||
|
(setq eg1 (tlg-export-geschoss daten 1))
|
||||||
|
(tlg-eq "gitterkorb: kennwerte G1" (length kr)
|
||||||
|
(ssg-json-get (ssg-json-get (ssg-json-get eg1 "kennwerte") "gitterkorb") "reihen"))
|
||||||
|
(tlg-eq "gitterkorb: bereich" "gitterkorb"
|
||||||
|
(ssg-json-get (vl-some '(lambda (b) (if (= (ssg-json-get b "nr") (atoi (tlg-attr bereich "NR"))) b))
|
||||||
|
(ssg-json-get daten "bereiche"))
|
||||||
|
"unter_reihe"))
|
||||||
|
|
||||||
|
(setq pfad (strcat (getenv "DXFMAKRO") "/tests/output/lager_tests_lager.json"))
|
||||||
(if (setq f (open pfad "w")) (progn (princ raw f) (close f)))
|
(if (setq f (open pfad "w")) (progn (princ raw f) (close f)))
|
||||||
|
|
||||||
;; --- Geschoss kopieren: G1 (3100, Spanplatte) -> G2, G3 mit Gitterrost ---
|
;; --- Geschoss kopieren: G1 (3100, Spanplatte) -> G2, G3 mit Gitterrost ---
|
||||||
@@ -296,6 +334,7 @@
|
|||||||
(tlg-eq "kopie: hallenboden bleibt" 1 (length (tlg-nur gg2 "LG_GANG_2000_1500_HALLENBODEN")))
|
(tlg-eq "kopie: hallenboden bleibt" 1 (length (tlg-nur gg2 "LG_GANG_2000_1500_HALLENBODEN")))
|
||||||
(tlg-eq "kopie: bereich belag" T
|
(tlg-eq "kopie: bereich belag" T
|
||||||
(vl-every '(lambda (b) (= (tlg-attr b "BELAG") "gitterrost")) (tlg-gs "LG_BEREICH" 2)))
|
(vl-every '(lambda (b) (= (tlg-attr b "BELAG") "gitterrost")) (tlg-gs "LG_BEREICH" 2)))
|
||||||
|
(tlg-eq "kopie: unter_reihe gitterkorb" 1 (tlg-anzahl-attr (tlg-gs "LG_BEREICH" 2) "UNTER_REIHE" "gitterkorb"))
|
||||||
;; Neufuellen einer Kopie laesst die Quelle in Ruhe, manueller Gang bleibt
|
;; Neufuellen einer Kopie laesst die Quelle in Ruhe, manueller Gang bleibt
|
||||||
(setq b2k (vl-some '(lambda (b) (if (= (tlg-attr b "RANDGANG_N_mm") "1000") b)) (tlg-gs "LG_BEREICH" 2)))
|
(setq b2k (vl-some '(lambda (b) (if (= (tlg-attr b "RANDGANG_N_mm") "1000") b)) (tlg-gs "LG_BEREICH" 2)))
|
||||||
(setq n-kinder (length (lg-bereich-kinder b2k)))
|
(setq n-kinder (length (lg-bereich-kinder b2k)))
|
||||||
|
|||||||
@@ -1,206 +0,0 @@
|
|||||||
#!/usr/bin/env python3
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
|
||||||
test_lager_yaml.py - lib/lager_yaml_export.py (Lagerplanung -> RFQ-Overlay-YAML).
|
|
||||||
|
|
||||||
Laeuft ohne BricsCAD: die Rohdaten sind von Hand nachgestellt, im Format von
|
|
||||||
LAGER_EXPORT (Lisp/LagerInsert.lsp, lg-export-json). Geprueft wird:
|
|
||||||
|
|
||||||
1. levels: Belagshoehen, lichte Hoehe aus dem Geschoss darueber,
|
|
||||||
Haengeebenen (Summe aller Reihen je Schienenhoehe/Warenlaenge),
|
|
||||||
Belag/Gitterrost nur auf Buehnen.
|
|
||||||
2. layout: Bereichsparameter, Ganganzahl/-laenge, Huelle.
|
|
||||||
3. Provenienz: jeder Overlay-Wert hat einen Herkunfts-Eintrag.
|
|
||||||
4. Abgleich gegen cfg/example_goh_storage.yaml: Abweichungen -> Konflikte,
|
|
||||||
null/fehlend -> gefuellt.
|
|
||||||
5. CLI schreibt YAML (wieder einlesbar) und Nachweis-HTML.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import pytest
|
|
||||||
import yaml
|
|
||||||
|
|
||||||
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "lib"))
|
|
||||||
import lager_yaml_export as lye # noqa: E402
|
|
||||||
|
|
||||||
BEISPIEL_YAML = os.path.join(os.path.dirname(os.path.abspath(__file__)),
|
|
||||||
"..", "cfg", "example_goh_storage.yaml")
|
|
||||||
|
|
||||||
EBENEN_EG = [{"schienenhoehe_mm": 2300, "warenlaenge_mm": 1200},
|
|
||||||
{"schienenhoehe_mm": 1100, "warenlaenge_mm": 1100}]
|
|
||||||
EBENEN_OG = [{"schienenhoehe_mm": 2800, "warenlaenge_mm": 1200},
|
|
||||||
{"schienenhoehe_mm": 1400, "warenlaenge_mm": 1200}]
|
|
||||||
|
|
||||||
|
|
||||||
def _reihe(gs, laenge, ebenen, tiefe=700):
|
|
||||||
return {"geschoss": gs, "laenge_mm": laenge, "tiefe_mm": tiefe, "haengeebenen": ebenen,
|
|
||||||
"schienen": 1, "quelle": "auto", "bereich": 1}
|
|
||||||
|
|
||||||
|
|
||||||
def _gang(gs, laenge, breite=1000, art="gang", belag="spanplatte"):
|
|
||||||
return {"geschoss": gs, "laenge_mm": laenge, "breite_mm": breite, "art": art,
|
|
||||||
"belag": belag, "bereich": 1}
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def raw():
|
|
||||||
"""Zwei Geschosse: Hallenboden (EG) + Buehne auf 3100 mm, je ein 2-Reihen-Modul."""
|
|
||||||
return {
|
|
||||||
"version": 1, "zeichnung": "test.dwg", "erzeugt": "20261021120000", "einheit": "mm",
|
|
||||||
"land": "DE",
|
|
||||||
"belag_yaml": {"spanplatte": "chipboard", "gitterrost": "grating", "hallenboden": ""},
|
|
||||||
"reihen_als_gitterrost": True,
|
|
||||||
"geschosse": [
|
|
||||||
# bewusst nicht nach Hoehe sortiert - der Export sortiert selbst
|
|
||||||
{"nr": 1, "bezeichnung": "Level 1", "hoehe_belag_mm": 3100, "konstr_hoehe_mm": 150,
|
|
||||||
"lichte_hoehe_mm": None, "belag_art": "spanplatte", "personen": 20,
|
|
||||||
"kontur_flaeche_mm2": 60e6, "kontur_bbox": [0, 0, 10000, 6000]},
|
|
||||||
{"nr": 0, "bezeichnung": "ground floor", "hoehe_belag_mm": 0, "konstr_hoehe_mm": 0,
|
|
||||||
"lichte_hoehe_mm": None, "belag_art": "hallenboden", "personen": 20,
|
|
||||||
"kontur_flaeche_mm2": 60e6, "kontur_bbox": [0, 0, 10000, 6000]},
|
|
||||||
],
|
|
||||||
"bereiche": [
|
|
||||||
{"nr": 1, "geschoss": 0, "gangbreite_mm": 1000, "regaltiefe_mm": 700,
|
|
||||||
"reihen_je_gang": 2, "schienen_je_gang": 1},
|
|
||||||
{"nr": 2, "geschoss": 1, "gangbreite_mm": 1000, "regaltiefe_mm": 700,
|
|
||||||
"reihen_je_gang": 2, "schienen_je_gang": 1},
|
|
||||||
],
|
|
||||||
"reihen": [_reihe(0, 10000, EBENEN_EG), _reihe(0, 10000, EBENEN_EG),
|
|
||||||
_reihe(1, 10000, EBENEN_OG), _reihe(1, 10000, EBENEN_OG)],
|
|
||||||
"gaenge": [_gang(0, 10000), _gang(1, 10000),
|
|
||||||
_gang(1, 700, breite=1200, art="quergang"),
|
|
||||||
_gang(1, 500, breite=1200, art="quergang", belag="gitterrost")],
|
|
||||||
"warnungen": ["Testwarnung"],
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def test_levels_sortiert_und_hoehen(raw):
|
|
||||||
overlay, _ = lye.aggregiere(raw)
|
|
||||||
lv = overlay["levels"]
|
|
||||||
assert [l["floor_elevation_m"] for l in lv] == [0.0, 3.1]
|
|
||||||
assert lv[0]["remark"] == "ground floor"
|
|
||||||
# lichte Hoehe EG = 3100 - 150 (Konstruktion darueber) - 0
|
|
||||||
assert lv[0]["clear_height_m"] == pytest.approx(2.95)
|
|
||||||
# oberstes Geschoss ohne LICHTE_HOEHE_mm -> nicht berechenbar
|
|
||||||
assert "clear_height_m" not in lv[1]
|
|
||||||
|
|
||||||
|
|
||||||
def test_haengeebenen_summe(raw):
|
|
||||||
overlay, _ = lye.aggregiere(raw)
|
|
||||||
eg, og = overlay["levels"]
|
|
||||||
assert eg["hanging_levels"] == [
|
|
||||||
{"rail_height_m": 2.3, "rack_length_m": 20.0, "goods_length_m": 1.2},
|
|
||||||
{"rail_height_m": 1.1, "rack_length_m": 20.0, "goods_length_m": 1.1},
|
|
||||||
]
|
|
||||||
# 2 Reihen a 10 m, oberste Schiene zuerst
|
|
||||||
assert [h["rack_length_m"] for h in og["hanging_levels"]] == [20.0, 20.0]
|
|
||||||
assert og["hanging_levels"][0]["rail_height_m"] == 2.8
|
|
||||||
|
|
||||||
|
|
||||||
def test_belag_nur_auf_buehne(raw):
|
|
||||||
overlay, _ = lye.aggregiere(raw)
|
|
||||||
eg, og = overlay["levels"]
|
|
||||||
assert "walkway" not in eg and "grating" not in eg
|
|
||||||
# Belag: Hauptgang 10 m2 + Quergang Spanplatte 0,84 m2
|
|
||||||
assert og["walkway"]["area_m2"] == pytest.approx(10.8)
|
|
||||||
assert og["walkway"]["spec"] == "chipboard"
|
|
||||||
# Gitterrost: Quergang 0,6 m2 + Reihen 2 x 7 m2
|
|
||||||
assert og["grating"] == pytest.approx(14.6)
|
|
||||||
|
|
||||||
|
|
||||||
def test_belag_ohne_gaenge_aus_kontur(raw):
|
|
||||||
raw["gaenge"] = []
|
|
||||||
overlay, s = lye.aggregiere(raw)
|
|
||||||
og = overlay["levels"][1]
|
|
||||||
# 60 m2 Kontur - 2 x 7 m2 Reihen
|
|
||||||
assert og["walkway"]["area_m2"] == pytest.approx(46.0)
|
|
||||||
assert "Konturflaeche" in s.provenance["levels[1].walkway.area_m2"]["formel"]
|
|
||||||
|
|
||||||
|
|
||||||
def test_layout(raw):
|
|
||||||
overlay, _ = lye.aggregiere(raw)
|
|
||||||
lay = overlay["layout"]
|
|
||||||
assert lay["aisle_width_m"] == 1.0
|
|
||||||
assert lay["rack_rows_per_aisle"] == 2
|
|
||||||
assert lay["rack_depth_m"] == 0.7
|
|
||||||
assert lay["trolley_rails_per_aisle"] == 1
|
|
||||||
assert lay["aisles"] == 1 # Quergaenge zaehlen nicht
|
|
||||||
assert lay["aisle_length_m"] == 10.0
|
|
||||||
assert lay["block_length_m"] == 10.0
|
|
||||||
assert lay["block_width_m"] == 6.0
|
|
||||||
|
|
||||||
|
|
||||||
def test_randgang_im_belag_nicht_in_aisles(raw):
|
|
||||||
# Randgang 10 m x 1 m (Spanplatte) im OG: Belag waechst, aisles bleibt
|
|
||||||
raw["gaenge"].append(_gang(1, 10000, art="randgang"))
|
|
||||||
overlay, s = lye.aggregiere(raw)
|
|
||||||
og = overlay["levels"][1]
|
|
||||||
assert og["walkway"]["area_m2"] == pytest.approx(20.8)
|
|
||||||
assert overlay["layout"]["aisles"] == 1
|
|
||||||
assert overlay["layout"]["aisle_length_m"] == 10.0
|
|
||||||
assert "Randgaenge G1: 10.0 m" in s.provenance["layout.aisles"]["formel"]
|
|
||||||
|
|
||||||
|
|
||||||
def test_unterschiedliche_bereiche_warnen(raw):
|
|
||||||
raw["bereiche"][1]["gangbreite_mm"] = 1200
|
|
||||||
raw["bereiche"].append(dict(raw["bereiche"][1]))
|
|
||||||
overlay, s = lye.aggregiere(raw)
|
|
||||||
assert overlay["layout"]["aisle_width_m"] == 1.2
|
|
||||||
assert any("aisle_width_m" in w for w in s.warnungen)
|
|
||||||
|
|
||||||
|
|
||||||
def test_provenienz_vollstaendig(raw):
|
|
||||||
ausgabe, _ = lye.baue_ausgabe(raw)
|
|
||||||
# hanging_levels: Provenienz je rack_length_m; Schienenhoehe/Warenlaenge
|
|
||||||
# sind der Gruppenschluessel derselben Zeile und stehen in deren Formel.
|
|
||||||
fehlend = [p for p, _ in lye._blaetter(ausgabe)
|
|
||||||
if p not in ausgabe["_provenance"]
|
|
||||||
and not (".hanging_levels[" in p and not p.endswith(".rack_length_m"))]
|
|
||||||
assert fehlend == []
|
|
||||||
assert ausgabe["_warnings"][0] == "Testwarnung"
|
|
||||||
|
|
||||||
|
|
||||||
def test_abgleich_mit_beispiel_yaml(raw):
|
|
||||||
with open(BEISPIEL_YAML, encoding="utf-8") as f:
|
|
||||||
hand = yaml.safe_load(f)
|
|
||||||
konflikte, fuellt = lye.abgleich(lye.aggregiere(raw)[0], hand)
|
|
||||||
pfade = {k["pfad"]: k for k in konflikte}
|
|
||||||
# Hand 4 Ebenen, Zeichnung 2
|
|
||||||
assert "levels" in pfade
|
|
||||||
# Hand 1,0 m Gangbreite = Zeichnung -> kein Konflikt
|
|
||||||
assert "layout.aisle_width_m" not in pfade
|
|
||||||
# Hand 4286 m2, Zeichnung 10,8 m2
|
|
||||||
assert pfade["levels[1].walkway.area_m2"]["hand"] == 4286
|
|
||||||
assert pfade["levels[1].walkway.area_m2"]["abweichung_prozent"] < -99
|
|
||||||
# Hand null -> Zeichnung fuellt
|
|
||||||
gef = {f["pfad"] for f in fuellt}
|
|
||||||
assert "layout.block_length_m" in gef
|
|
||||||
assert "levels[1].grating" in gef
|
|
||||||
|
|
||||||
|
|
||||||
def test_hole_pfad():
|
|
||||||
obj = {"levels": [{"a": 1}, {"walkway": {"area_m2": 5}}]}
|
|
||||||
assert lye._hole(obj, "levels[1].walkway.area_m2") == (True, 5)
|
|
||||||
assert lye._hole(obj, "levels[2].walkway") == (False, None)
|
|
||||||
assert lye._hole(obj, "layout.x") == (False, None)
|
|
||||||
|
|
||||||
|
|
||||||
def test_cli(raw, tmp_path):
|
|
||||||
rp = tmp_path / "x_lager_raw.json"
|
|
||||||
rp.write_text(json.dumps(raw), encoding="cp1252")
|
|
||||||
yp = tmp_path / "x_drawing.yaml"
|
|
||||||
hp = tmp_path / "x_nachweis.html"
|
|
||||||
rc = lye.main([str(rp), str(yp), "--hand", BEISPIEL_YAML, "--nachweis", str(hp)])
|
|
||||||
assert rc == 0
|
|
||||||
daten = yaml.safe_load(yp.read_text(encoding="utf-8"))
|
|
||||||
assert daten["levels"][1]["floor_elevation_m"] == 3.1
|
|
||||||
assert daten["_conflicts"]
|
|
||||||
assert "levels[0].floor_elevation_m" in daten["_provenance"]
|
|
||||||
assert "Lager-Nachweis" in hp.read_text(encoding="utf-8")
|
|
||||||
|
|
||||||
|
|
||||||
def test_cli_fehlende_datei(tmp_path):
|
|
||||||
assert lye.main([str(tmp_path / "fehlt.json"), str(tmp_path / "o.yaml")]) == 2
|
|
||||||
+121
-3
@@ -3409,9 +3409,127 @@
|
|||||||
(tu-eq "lg-json-wert/rund" "1000" (lg-json-wert 1000.0))
|
(tu-eq "lg-json-wert/rund" "1000" (lg-json-wert 1000.0))
|
||||||
(tu-eq "lg-json-wert/str" "\"a\\\"b\"" (lg-json-wert "a\"b"))
|
(tu-eq "lg-json-wert/str" "\"a\\\"b\"" (lg-json-wert "a\"b"))
|
||||||
(tu-eq "lg-json-wert/roh" "[1]" (lg-json-wert (list 'ROH "[1]")))
|
(tu-eq "lg-json-wert/roh" "[1]" (lg-json-wert (list 'ROH "[1]")))
|
||||||
|
(tu-eq "lg-json-wert/false" "false" (lg-json-wert 'FALSE))
|
||||||
|
(tu-eq "lg-json-wert/umlaut" "\"G\\u00e4\"" (lg-json-wert (strcat "G" (chr 228))))
|
||||||
(tu-eq "lg-json-obj" "{\"a\": 1, \"b\": \"x\"}" (lg-json-obj '(("a" . 1) ("b" . "x"))))
|
(tu-eq "lg-json-obj" "{\"a\": 1, \"b\": \"x\"}" (lg-json-obj '(("a" . 1) ("b" . "x"))))
|
||||||
(tu-eq "lg-json-ebenen" "[{\"schienenhoehe_mm\": 2300, \"warenlaenge_mm\": 1200}]"
|
(tu-eq "lg-json-wert/obj-arr" "{\"p\": [1, 2.5], \"o\": {\"x\": null}}"
|
||||||
(cadr (lg-json-ebenen "2300/1200")))
|
(lg-json-wert (list 'OBJ (cons "p" (list 'ARR 1 2.5)) (cons "o" (list 'OBJ (cons "x" nil))))))
|
||||||
|
(tu-eq "lg-json-wert/leer" "[]" (lg-json-wert (list 'ARR)))
|
||||||
|
(tu-eq "lg-j-ebenen" "[{\"schienenhoehe_mm\": 2300, \"warenlaenge_mm\": 1200}]"
|
||||||
|
(lg-json-wert (lg-j-ebenen "2300/1200")))
|
||||||
|
;; kleine Container einzeilig, grosse je Eintrag eine Zeile
|
||||||
|
(tu-eq "lg-json-text/klein" "{\"a\": 1}" (lg-json-text (list 'OBJ (cons "a" 1)) ""))
|
||||||
|
(setq _gross (cons 'OBJ (mapcar '(lambda (i) (cons (itoa i) i)) '(1 2 3 4 5 6 7 8 9 10 11 12 13))))
|
||||||
|
(tu-eq "lg-json-text/gross-zeilen" 15
|
||||||
|
(length (ssg-sepliste-split-feld (lg-json-text _gross "") "\n")))
|
||||||
|
(tu-eq "lg-json-text/punkte-einzeilig" 1
|
||||||
|
(length (ssg-sepliste-split-feld
|
||||||
|
(lg-json-text (lg-j-pkte '((0 0) (1 0) (1 1) (0 1) (0 2) (2 2) (2 0))) "") "\n")))
|
||||||
|
(tu-eq "lg-j-setzen/neu" 2 (lg-j (lg-j-setzen (list 'OBJ (cons "a" 1)) "b" 2) "b"))
|
||||||
|
(tu-eq "lg-j-setzen/ersetzen" '(OBJ ("a" . 3)) (lg-j-setzen (list 'OBJ (cons "a" 1)) "a" 3))
|
||||||
|
|
||||||
|
;; --- Kennwerte (Export) ---
|
||||||
|
(tu-eq "lg-buehne-p" '(T nil nil nil)
|
||||||
|
(mapcar 'lg-buehne-p '("spanplatte" "hallenboden" "" nil)))
|
||||||
|
(tu-eq "lg-unter-reihe-wert" '("gitterkorb" "gitterrost" "keine" "keine" "gitterrost")
|
||||||
|
(list (lg-unter-reihe-wert "gitterkorb" "gitterrost" T)
|
||||||
|
(lg-unter-reihe-wert "" "gitterrost" T)
|
||||||
|
(lg-unter-reihe-wert "keine" "gitterrost" T)
|
||||||
|
(lg-unter-reihe-wert "gitterkorb" "gitterrost" nil)
|
||||||
|
(lg-unter-reihe-wert "quatsch" "unbekannt" T)))
|
||||||
|
(setq _r1 (list 'OBJ (cons "laenge_mm" 4000.0) (cons "tiefe_mm" 700.0) (cons "schienen" 1)
|
||||||
|
(cons "haengeebenen" (lg-j-ebenen "2300/1200;1100/1100"))
|
||||||
|
(cons "unter_reihe" "gitterrost"))
|
||||||
|
_r2 (list 'OBJ (cons "laenge_mm" 2000.0) (cons "tiefe_mm" 700.0) (cons "schienen" 2)
|
||||||
|
(cons "haengeebenen" (lg-j-ebenen "2300/1200"))
|
||||||
|
(cons "unter_reihe" "gitterrost")))
|
||||||
|
(tu-eqf "lg-haengeebenen-summen"
|
||||||
|
'(ARR (OBJ ("schienenhoehe_mm" . 2300.0) ("warenlaenge_mm" . 1200.0) ("reihen" . 2) ("regallaenge_mm" . 6000.0))
|
||||||
|
(OBJ ("schienenhoehe_mm" . 1100.0) ("warenlaenge_mm" . 1100.0) ("reihen" . 1) ("regallaenge_mm" . 4000.0)))
|
||||||
|
(lg-haengeebenen-summen (list _r1 _r2)))
|
||||||
|
(setq _ga (list (list 'OBJ (cons "art" "gang") (cons "belag" "spanplatte") (cons "laenge_mm" 10000.0) (cons "breite_mm" 1000.0))
|
||||||
|
(list 'OBJ (cons "art" "randgang") (cons "belag" "gitterrost") (cons "laenge_mm" 5000.0) (cons "breite_mm" 800.0))
|
||||||
|
(list 'OBJ (cons "art" "gang") (cons "belag" "spanplatte") (cons "laenge_mm" 2000.0) (cons "breite_mm" 1000.0))))
|
||||||
|
(tu-eqf "lg-gaenge-je-art"
|
||||||
|
'(OBJ ("gang" OBJ ("anzahl" . 2) ("laenge_mm" . 12000.0) ("flaeche_mm2" . 1.2e7))
|
||||||
|
("quergang" OBJ ("anzahl" . 0) ("laenge_mm" . 0.0) ("flaeche_mm2" . 0.0))
|
||||||
|
("randgang" OBJ ("anzahl" . 1) ("laenge_mm" . 5000.0) ("flaeche_mm2" . 4.0e6)))
|
||||||
|
(lg-gaenge-je-art _ga))
|
||||||
|
;; Geschoss 1 (Spanplatte, 3100) unter Geschoss 2 (6100, Konstr. 250)
|
||||||
|
(setq _g1 (list 'OBJ (cons "nr" 1) (cons "hoehe_belag_mm" 3100.0) (cons "konstr_hoehe_mm" 250.0)
|
||||||
|
(cons "lichte_hoehe_mm" nil) (cons "belag_art" "spanplatte")
|
||||||
|
(cons "kontur" (list 'OBJ (cons "flaeche_mm2" 6.0e7))))
|
||||||
|
_g2 (list 'OBJ (cons "nr" 2) (cons "hoehe_belag_mm" 6100.0) (cons "konstr_hoehe_mm" 250.0)
|
||||||
|
(cons "lichte_hoehe_mm" nil) (cons "belag_art" "spanplatte")))
|
||||||
|
(setq _kw (car (lg-kennwerte-geschoss _g1 _g2 (list _r1 _r2) _ga 1)))
|
||||||
|
(tu-eqf "lg-kennwerte/lichte-berechnet" 2750.0 (lg-j _kw "lichte_hoehe_mm"))
|
||||||
|
(tu-eqf "lg-kennwerte/regallaenge" 6000.0 (lg-j _kw "regallaenge_mm"))
|
||||||
|
(tu-eqf "lg-kennwerte/grundflaeche" 4.2e6 (lg-j _kw "regalgrundflaeche_mm2"))
|
||||||
|
(tu-eqf "lg-kennwerte/schienen" 8000.0 (lg-j _kw "schienenlaenge_mm"))
|
||||||
|
(tu-eqf "lg-kennwerte/belag-gaenge" 1.2e7 (lg-j _kw "belagsflaeche_mm2"))
|
||||||
|
;; Gitterrost = Randgang gitterrost 4e6 + Reihen 4.2e6
|
||||||
|
(tu-eqf "lg-kennwerte/gitterrost" 8.2e6 (lg-j _kw "gitterrostflaeche_mm2"))
|
||||||
|
(tu-eq "lg-kennwerte/buehne" T (lg-j _kw "buehne"))
|
||||||
|
(tu-eq "lg-kennwerte/herkunft" T
|
||||||
|
(if (lg-j (cadr (lg-kennwerte-geschoss _g1 _g2 (list _r1 _r2) _ga 1)) "belagsflaeche_mm2") T))
|
||||||
|
;; ohne Gaenge: Konturflaeche - Reihengrundflaeche; oberstes ohne Vorgabe -> nil
|
||||||
|
(setq _kw (car (lg-kennwerte-geschoss _g1 nil (list _r1 _r2) nil 1)))
|
||||||
|
(tu-eqf "lg-kennwerte/belag-kontur" (- 6.0e7 4.2e6) (lg-j _kw "belagsflaeche_mm2"))
|
||||||
|
(tu-nil "lg-kennwerte/lichte-oben" (lg-j _kw "lichte_hoehe_mm"))
|
||||||
|
(tu-eqf "lg-kennwerte/lichte-vorgabe" 2800.0
|
||||||
|
(lg-j (car (lg-kennwerte-geschoss (lg-j-setzen _g1 "lichte_hoehe_mm" 2800.0) _g2 nil nil 0))
|
||||||
|
"lichte_hoehe_mm"))
|
||||||
|
;; Hallenboden: keine Buehne, keine Flaechen
|
||||||
|
(setq _kw (car (lg-kennwerte-geschoss (lg-j-setzen _g1 "belag_art" "hallenboden") _g2 (list _r1) _ga 1)))
|
||||||
|
(tu-eq "lg-kennwerte/hallenboden" 'FALSE (lg-j _kw "buehne"))
|
||||||
|
(tu-nil "lg-kennwerte/hallenboden-belag" (lg-j _kw "belagsflaeche_mm2"))
|
||||||
|
(tu-nil "lg-kennwerte/hallenboden-gitter" (lg-j _kw "gitterrostflaeche_mm2"))
|
||||||
|
|
||||||
|
;; --- Gitterkorb: offene Kanten ---
|
||||||
|
;; Einzelreihe 4000 x 700: alles offen
|
||||||
|
(setq _e1 '((0.0 -350.0) (4000.0 -350.0) (4000.0 350.0) (0.0 350.0))
|
||||||
|
_e2 '((0.0 350.0) (4000.0 350.0) (4000.0 1050.0) (0.0 1050.0))
|
||||||
|
_e3 '((2000.0 1050.0) (6000.0 1050.0) (6000.0 1750.0) (2000.0 1750.0)))
|
||||||
|
(tu-eqf "lg-offene-kanten/einzeln" '((8000.0 1400.0)) (lg-reihen-offene-kanten (list _e1) 1.0))
|
||||||
|
;; Ruecken an Ruecken: je eine Laengsseite zu
|
||||||
|
(tu-eqf "lg-offene-kanten/ruecken" '((4000.0 1400.0) (4000.0 1400.0))
|
||||||
|
(lg-reihen-offene-kanten (list _e1 _e2) 1.0))
|
||||||
|
;; Teilueberlappung: _e3 liegt nur auf 2000 mm an _e2 an (_e2 unten ganz an _e1)
|
||||||
|
(tu-eqf "lg-offene-kanten/teilweise" '((2000.0 1400.0) (6000.0 1400.0))
|
||||||
|
(cdr (lg-reihen-offene-kanten (list _e1 _e2 _e3) 1.0)))
|
||||||
|
;; Abstand > Toleranz: nicht anliegend
|
||||||
|
(tu-eqf "lg-offene-kanten/abstand" '((8000.0 1400.0) (8000.0 1400.0))
|
||||||
|
(lg-reihen-offene-kanten
|
||||||
|
(list _e1 '((0.0 360.0) (4000.0 360.0) (4000.0 1060.0) (0.0 1060.0))) 1.0))
|
||||||
|
;; Gitterkorb vervollstaendigen: Boden, offene Kanten, Seitenflaeche
|
||||||
|
(setq _rk (lg-reihen-gitterkorb-berechnen
|
||||||
|
(list (list 'OBJ (cons "laenge_mm" 4000.0) (cons "tiefe_mm" 700.0)
|
||||||
|
(cons "ecken" (lg-j-pkte _e1))
|
||||||
|
(cons "gitterkorb" (list 'OBJ (cons "hoehe_mm" 500.0))))
|
||||||
|
(list 'OBJ (cons "laenge_mm" 4000.0) (cons "tiefe_mm" 700.0)
|
||||||
|
(cons "ecken" (lg-j-pkte _e2)) (cons "gitterkorb" nil)))
|
||||||
|
1.0))
|
||||||
|
(setq _gk (lg-j (car _rk) "gitterkorb"))
|
||||||
|
(tu-eqf "lg-gitterkorb/boden" 2.8e6 (lg-j _gk "bodenflaeche_mm2"))
|
||||||
|
(tu-eqf "lg-gitterkorb/laengs" 4000.0 (lg-j _gk "offen_laengs_mm"))
|
||||||
|
(tu-eqf "lg-gitterkorb/seite" (* 500.0 5400.0) (lg-j _gk "seitenflaeche_mm2"))
|
||||||
|
(tu-nil "lg-gitterkorb/ohne" (lg-j (cadr _rk) "gitterkorb"))
|
||||||
|
;; Kennwerte summieren den Korb, Grundflaeche zaehlt dann nicht als Gitterrost
|
||||||
|
(setq _kw (car (lg-kennwerte-geschoss _g1 _g2
|
||||||
|
(list (lg-j-setzen (car _rk) "unter_reihe" "gitterkorb")) nil 1)))
|
||||||
|
(tu-eqf "lg-kennwerte/korb-seite" (* 500.0 5400.0) (lg-j (lg-j _kw "gitterkorb") "seitenflaeche_mm2"))
|
||||||
|
(tu-eq "lg-kennwerte/korb-reihen" 1 (lg-j (lg-j _kw "gitterkorb") "reihen"))
|
||||||
|
(tu-eqf "lg-kennwerte/korb-kein-gitterrost" 0.0 (lg-j _kw "gitterrostflaeche_mm2"))
|
||||||
|
;; Lager-Summen ueber zwei Geschosse
|
||||||
|
(setq _kl (lg-kennwerte-lager
|
||||||
|
(list (lg-j-setzen (lg-j-setzen _g1 "kennwerte" (car (lg-kennwerte-geschoss _g1 _g2 (list _r1) nil 1)))
|
||||||
|
"kontur" (list 'OBJ (cons "bbox" (list 'ARR 0.0 0.0 10000.0 6000.0))))
|
||||||
|
(lg-j-setzen (lg-j-setzen _g2 "kennwerte" (car (lg-kennwerte-geschoss _g2 nil (list _r2) nil 1)))
|
||||||
|
"kontur" (list 'OBJ (cons "bbox" (list 'ARR 0.0 0.0 12000.0 5000.0)))))
|
||||||
|
(list _r1 _r2) nil 2))
|
||||||
|
(tu-eqf "lg-kennwerte-lager/regal" 6000.0 (lg-j _kl "regallaenge_mm"))
|
||||||
|
(tu-eqf "lg-kennwerte-lager/huelle" '(12000.0 6000.0)
|
||||||
|
(list (lg-j (lg-j _kl "huelle") "laenge_mm") (lg-j (lg-j _kl "huelle") "breite_mm")))
|
||||||
|
|
||||||
;; --- Regelprofil-Aufloesung ---
|
;; --- Regelprofil-Aufloesung ---
|
||||||
(tu-eq "lg-bedingung/leer" 'ja (lg-bedingung-pruefen nil nil))
|
(tu-eq "lg-bedingung/leer" 'ja (lg-bedingung-pruefen nil nil))
|
||||||
@@ -3472,7 +3590,7 @@
|
|||||||
(car (lg-regel-aufloesen (lg-regel-finden _prof "gelaender.hoehe_min")
|
(car (lg-regel-aufloesen (lg-regel-finden _prof "gelaender.hoehe_min")
|
||||||
'(("absturzhoehe" . 3100)))))
|
'(("absturzhoehe" . 3100)))))
|
||||||
(tu-nil "lg-profil/sk-ungepflegt" (ssg-json-get _prof "gepflegt")))
|
(tu-nil "lg-profil/sk-ungepflegt" (ssg-json-get _prof "gepflegt")))
|
||||||
(tu-record nil "lg-profil/dateien" "cfg/regelwerk/SK.json nicht gefunden (DXFM_CFG?)"))
|
(tu-record nil "lg-profil/dateien" "cfg/stahlbau/regelwerk/SK.json nicht gefunden (DXFM_CFG?)"))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in new issue
Block a user