[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/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) |
|
||||
| `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) |
|
||||
| `dcl/` | DCL-Dialogdefinitionen |
|
||||
| `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) |
|
||||
| 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 |
|
||||
| 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) |
|
||||
| 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 |
|
||||
@@ -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` |
|
||||
| `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) |
|
||||
| `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
|
||||
| `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` |
|
||||
| `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/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. |
|
||||
| `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` |
|
||||
| (`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 ...]` |
|
||||
| `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 |
|
||||
|
||||
### Entwickler-Tools (`lib/`) - kein ezdxf, reine Text-/AutoLISP-Verarbeitung
|
||||
|
||||
+566
-143
@@ -2,8 +2,8 @@
|
||||
;; LagerInsert.lsp - Lagerplanung GOH-Buehnenlager (Phase 1: Mengen, 2D)
|
||||
;;
|
||||
;; Erzeugt parametrische Attributbloecke fuer ein mehrgeschossiges
|
||||
;; Haengewarenlager und sammelt daraus die Mengen fuer die RFQ-YAML
|
||||
;; (Overlay, siehe doc/plan/lager_rfq.md):
|
||||
;; Haengewarenlager und exportiert daraus die technischen Daten als JSON
|
||||
;; fuer die RFQ-Dokumentation (LAGER_EXPORT, siehe doc/plan/lager_rfq.md):
|
||||
;;
|
||||
;; LG_GESCHOSS Geschoss-Kopfsymbol, verknuepft mit seiner Belagskontur
|
||||
;; LG_BEREICH Lagerbereich (Kontur + Parameter), fuellt sich selbst
|
||||
@@ -13,7 +13,7 @@
|
||||
;; je Belag aus lager.json belag_schraffur)
|
||||
;;
|
||||
;; 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):
|
||||
;; - Alle Werte selbstbeschreibend in mm/Grad, keine Index-Codes.
|
||||
@@ -379,6 +379,7 @@
|
||||
("SCHIENEN_JE_GANG" . "") ("QUERGANG_ABSTAND_mm" . "") ("QUERGANG_BREITE_mm" . "")
|
||||
("RICHTUNG" . "") ("HAENGEEBENEN" . "") ("BELAG" . "")
|
||||
("RANDGANG_N_mm" . "0") ("RANDGANG_O_mm" . "0") ("RANDGANG_S_mm" . "0") ("RANDGANG_W_mm" . "0")
|
||||
("UNTER_REIHE" . "") ("GITTERKORB_HOEHE_mm" . "")
|
||||
("RESTBREITE_mm" . "")))
|
||||
|
||||
(setq *lg-schema-reihe*
|
||||
@@ -621,6 +622,8 @@
|
||||
("richtung" "RICHTUNG" "grad" nil)
|
||||
("ebenen" "HAENGEEBENEN" "ebenen" nil)
|
||||
("belag" "BELAG" "wahl" belag)
|
||||
("unter" "UNTER_REIHE" "wahl" unter)
|
||||
("korbhoehe" "GITTERKORB_HOEHE_mm" "mm" nil)
|
||||
("rand_n" "RANDGANG_N_mm" "mm" nil)
|
||||
("rand_o" "RANDGANG_O_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 'reihen) '("1" "2"))
|
||||
((eq sym 'gangart) '("gang" "randgang" "quergang"))
|
||||
((eq sym 'unter) *lg-unter-reihe-werte*)
|
||||
((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 "HAENGEEBENEN" (lg-vorgabe '("reihe" "haengeebenen") "2300/1200;1100/1100"))
|
||||
(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_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_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.
|
||||
;; Fehlt ein Attribut (Altbestand), gilt 0.
|
||||
(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) ---
|
||||
;; 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)
|
||||
(setq s (rtos w 2 3))
|
||||
(if (vl-string-search "." s)
|
||||
@@ -2025,141 +2063,564 @@
|
||||
(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)
|
||||
(cond
|
||||
((null v) "null")
|
||||
((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) 'REAL) (lg-json-zahl 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)
|
||||
(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-arr (texte einrueckung)
|
||||
(if texte
|
||||
(strcat "[\n" einrueckung (ssg-join texte (strcat ",\n" einrueckung)) "\n" (substr einrueckung 3) "]")
|
||||
"[]")
|
||||
(defun lg-json-container-p (v)
|
||||
(and v (listp v) (member (car v) '(OBJ ARR)))
|
||||
)
|
||||
|
||||
(defun lg-json-zahlen (zahlen)
|
||||
(list 'ROH (strcat "[" (ssg-join (mapcar 'lg-json-wert zahlen) ", ") "]"))
|
||||
;; Anzahl Blattwerte eines Werts (Mass fuer "passt in eine Zeile").
|
||||
(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)
|
||||
(list 'ROH
|
||||
(strcat "["
|
||||
(ssg-join (mapcar '(lambda (e) (lg-json-obj (list (cons "schienenhoehe_mm" (car e))
|
||||
(cons "warenlaenge_mm" (cadr e)))))
|
||||
(lg-haengeebenen-parse s))
|
||||
", ")
|
||||
"]"))
|
||||
;; Zahl, null oder Array nur daraus (Punkte, Punktlisten, bbox).
|
||||
(defun lg-json-zahlen-p (v)
|
||||
(cond
|
||||
((or (null v) (numberp v)) T)
|
||||
((and (listp v) (eq (car v) 'ARR)) (vl-every 'lg-json-zahlen-p (cdr v)))
|
||||
(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).
|
||||
(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-export-geschoss (g / a k pts bb)
|
||||
(setq a (caddr g) pts (cadddr g) bb (ssg-poly-bbox pts)
|
||||
k (lg-xdata-wert (car g) "kontur"))
|
||||
(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)))
|
||||
;; Buehne = Belag vorhanden und kein Hallenboden. Rein.
|
||||
(defun lg-buehne-p (belag)
|
||||
(and (= (type belag) 'STR) (/= belag "") (/= (strcase belag T) "hallenboden"))
|
||||
)
|
||||
|
||||
(defun lg-export-bereich (e / a k pts bb)
|
||||
(setq a (ssg-attrib-read e)
|
||||
k (lg-ent-aus-handle (lg-xdata-wert e "kontur"))
|
||||
pts (if k (ssg-lwpoly-punkte k))
|
||||
bb (ssg-poly-bbox pts))
|
||||
(lg-json-obj
|
||||
(list (cons "nr" (lg-a-int a "NR"))
|
||||
(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-json-ebenen (cdr (assoc "HAENGEEBENEN" a))))
|
||||
(cons "belag" (cdr (assoc "BELAG" a)))
|
||||
(cons "randgang_mm" (list 'ROH (lg-json-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 "kontur_flaeche_mm2" (if pts (ssg-poly-flaeche pts)))
|
||||
(cons "kontur_bbox" (if bb (lg-json-zahlen (append (car bb) (cadr bb)))))
|
||||
(cons "handle" (lg-handle e))))
|
||||
;; --- Reine Kerne der Kennwerte (getestet) ---
|
||||
|
||||
;; Regallaenge je Haengeebene. reihen = Reihen-Records mit laenge_mm und
|
||||
;; haengeebenen; jede Reihe traegt ihre Laenge in jede ihrer Ebenen ein.
|
||||
;; Rueckgabe (ARR (OBJ schienenhoehe_mm warenlaenge_mm reihen regallaenge_mm)
|
||||
;; ...), nach Schienenhoehe absteigend.
|
||||
(defun lg-haengeebenen-summen (reihen / erg key alt l)
|
||||
(setq erg nil)
|
||||
(foreach r reihen
|
||||
(setq l (lg-n (lg-j r "laenge_mm")))
|
||||
(foreach e (cdr (lg-j r "haengeebenen"))
|
||||
(setq key (list (lg-n (lg-j e "schienenhoehe_mm")) (lg-n (lg-j e "warenlaenge_mm")))
|
||||
alt (assoc key erg))
|
||||
(setq erg (if alt
|
||||
(subst (list key (1+ (cadr alt)) (+ (caddr alt) l)) alt erg)
|
||||
(cons (list key 1 l) erg)))))
|
||||
(cons 'ARR
|
||||
(mapcar '(lambda (x) (list 'OBJ (cons "schienenhoehe_mm" (car (car x)))
|
||||
(cons "warenlaenge_mm" (cadr (car x)))
|
||||
(cons "reihen" (cadr x))
|
||||
(cons "regallaenge_mm" (caddr x))))
|
||||
(vl-sort erg '(lambda (a b) (if (equal (car (car a)) (car (car b)) 1e-6)
|
||||
(> (cadr (car a)) (cadr (car b)))
|
||||
(> (car (car a)) (car (car b))))))))
|
||||
)
|
||||
|
||||
(defun lg-export-linie (e art / a ed)
|
||||
(setq a (ssg-attrib-read e) ed (entget e))
|
||||
(lg-json-obj
|
||||
;; Gaenge je ART: (OBJ ("gang" . (OBJ anzahl laenge_mm flaeche_mm2)) ...),
|
||||
;; gang/quergang/randgang immer vorhanden, weitere Arten dahinter.
|
||||
(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
|
||||
(list (cons "geschoss" (lg-a-int a "GESCHOSS"))
|
||||
(cons "laenge_mm" (lg-a-zahl a "LAENGE")))
|
||||
(list (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 "bereich" (lg-a-int a "BEREICH"))
|
||||
(cons "bereich_handle" (lg-xdata-wert e "bereich"))
|
||||
(cons "quelle" quelle)
|
||||
(cons "laenge_mm" l))
|
||||
(if (= art "reihe")
|
||||
(list (cons "tiefe_mm" (lg-a-zahl a "TIEFE_mm"))
|
||||
(cons "haengeebenen" (lg-json-ebenen (cdr (assoc "HAENGEEBENEN" a))))
|
||||
(list (cons "tiefe_mm" b)
|
||||
(cons "schienen" (lg-a-int a "SCHIENEN"))
|
||||
(cons "quelle" (cdr (assoc "QUELLE" a))))
|
||||
(list (cons "breite_mm" (lg-a-zahl a "BREITE_mm"))
|
||||
(cons "haengeebenen" (lg-j-ebenen (cdr (assoc "HAENGEEBENEN" a)))))
|
||||
(list (cons "breite_mm" b)
|
||||
(cons "art" (cdr (assoc "ART" a)))
|
||||
(cons "belag" (cdr (assoc "BELAG" a)))
|
||||
(cons "quelle" (if (member (cdr (assoc "QUELLE" a)) '(nil "")) "auto"
|
||||
(cdr (assoc "QUELLE" a))))))
|
||||
(list (cons "bereich" (lg-a-int a "BEREICH"))
|
||||
(cons "start" (lg-json-zahlen (cdr (assoc 10 ed))))
|
||||
(cons "winkel_grad" (* (/ (cond ((cdr (assoc 50 ed))) (0.0)) pi) 180.0))
|
||||
(cons "handle" (lg-handle e)))))
|
||||
(cons "belag" (cdr (assoc "BELAG" a)))))
|
||||
(list (cons "start" (list 'ARR (car p1) (cadr p1) z))
|
||||
(cons "ende" (list 'ARR (car p2) (cadr p2) z))
|
||||
(cons "mitte" (list 'ARR (/ (+ (car p1) (car p2)) 2.0) (/ (+ (cadr p1) (cadr p2)) 2.0) z))
|
||||
(cons "winkel_grad" (* (/ rot pi) 180.0))
|
||||
(cons "ecken" (lg-j-pkte (lg-linie-polygon e)))
|
||||
(cons "flaeche_mm2" (* (lg-n l) (lg-n b))))))
|
||||
)
|
||||
|
||||
;; Alle Daten als JSON-Text.
|
||||
(defun lg-export-json ( / gs warn)
|
||||
(setq gs (lg-geschosse) warn nil)
|
||||
;; unter_reihe je Reihe aus ihrem Bereich (sonst Vorgabe), auf Hallenboden
|
||||
;; "keine"; Reihen mit Gitterkorb bekommen (OBJ hoehe_mm) als Startwert.
|
||||
(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)))
|
||||
(foreach g gs
|
||||
(if (null (cadddr g))
|
||||
(setq warn (cons (ssg-textf "lg-exp-geschoss-ohne-kontur" (list (itoa (cadr g)))) warn))))
|
||||
(strcat
|
||||
"{\n"
|
||||
" \"version\": 1,\n"
|
||||
" \"zeichnung\": " (lg-json-wert (strcat (getvar "DWGPREFIX") (getvar "DWGNAME"))) ",\n"
|
||||
" \"erzeugt\": " (lg-json-wert (ssg-timestamp)) ",\n"
|
||||
" \"einheit\": \"mm\",\n"
|
||||
" \"land\": " (lg-json-wert (lg-land)) ",\n"
|
||||
" \"belag_yaml\": " (lg-json-obj (vl-remove-if '(lambda (p) (or (/= (type (cdr p)) 'STR)
|
||||
(= (car p) "beschreibung")))
|
||||
(lg-vorgabe '("belag_yaml") nil))) ",\n"
|
||||
" \"reihen_als_gitterrost\": " (lg-json-wert (if (lg-vorgabe '("flaechen" "reihen_als_gitterrost") nil) T nil)) ",\n"
|
||||
" \"geschosse\": " (lg-json-arr (mapcar 'lg-export-geschoss gs) " ") ",\n"
|
||||
" \"bereiche\": " (lg-json-arr (mapcar 'lg-export-bereich (lg-alle-bloecke "LG_BEREICH")) " ") ",\n"
|
||||
" \"reihen\": " (lg-json-arr (mapcar '(lambda (e) (lg-export-linie e "reihe")) (lg-alle-bloecke "LG_REIHE_*")) " ") ",\n"
|
||||
" \"gaenge\": " (lg-json-arr (mapcar '(lambda (e) (lg-export-linie e "gang")) (lg-alle-bloecke "LG_GANG_*")) " ") ",\n"
|
||||
" \"warnungen\": " (lg-json-arr (mapcar 'lg-json-wert warn) " ") "\n"
|
||||
"}\n")
|
||||
(setq bereiche (mapcar 'lg-export-bereich-rec (lg-alle-bloecke "LG_BEREICH"))
|
||||
reihen (mapcar '(lambda (e) (lg-export-linie-rec e "reihe")) (lg-alle-bloecke "LG_REIHE_*"))
|
||||
gaenge (mapcar '(lambda (e) (lg-export-linie-rec e "gang")) (lg-alle-bloecke "LG_GANG_*"))
|
||||
;; Geschosse von unten nach oben (Belagshoehe, dann Nr)
|
||||
g-recs (vl-sort (mapcar 'lg-export-geschoss-rec gs)
|
||||
'(lambda (a b / ha hb)
|
||||
(setq ha (lg-n (lg-j a "hoehe_belag_mm")) hb (lg-n (lg-j b "hoehe_belag_mm")))
|
||||
(if (equal ha hb 1e-6) (< (lg-j a "nr") (lg-j b "nr")) (< ha hb)))))
|
||||
(setq reihen (lg-reihen-unter-setzen reihen bereiche g-recs vorgabe))
|
||||
(setq g-neu nil r-neu nil r-gs nil g-gs nil i 0)
|
||||
(foreach g g-recs
|
||||
(setq nr (lg-j g "nr")
|
||||
nx (nth (1+ i) g-recs)
|
||||
r-gs (lg-reihen-gitterkorb-berechnen
|
||||
(vl-remove-if-not '(lambda (r) (equal (lg-j r "geschoss") nr)) reihen) 1.0)
|
||||
g-gs (vl-remove-if-not '(lambda (x) (equal (lg-j x "geschoss") nr)) gaenge)
|
||||
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)
|
||||
@@ -2180,49 +2641,11 @@
|
||||
(progn (princ (ssg-textf "lg-exp-datei-fehler" (list pfad))) nil))
|
||||
)
|
||||
|
||||
;; Python-Skript lager_yaml_export.py aufrufen (nutzt die Interpreter-
|
||||
;; Ermittlung aus export.lsp). Rueckgabe: Exitcode oder nil.
|
||||
(defun lg-python-aufrufen (raw yaml html / skript hand log args rc)
|
||||
(cond
|
||||
((not (car (atoms-family 1 '("EXPORT:RUN-PYTHON"))))
|
||||
(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 "-"))))
|
||||
;; Technische Daten des Lagers als <dwg>_lager.json nach DXFM_RESULTS.
|
||||
(defun c:LAGER_EXPORT ( / pfad)
|
||||
(setq pfad (strcat (lg-ausgabe-verzeichnis) "/" (lg-dwg-basis) "_lager.json"))
|
||||
(if (lg-export-schreiben pfad)
|
||||
(princ (ssg-textf "lg-exp-json" (list pfad))))
|
||||
(princ)
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
;; ============================================================
|
||||
;; 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,
|
||||
;; deren Bedingung zutrifft - mit Protokoll, welche Quelle gewonnen hat.
|
||||
;; Jede Pruefregel der Lagerplanung wird genau einmal hier implementiert
|
||||
@@ -35,7 +35,7 @@
|
||||
(setq cfg (getenv "DXFM_CFG"))
|
||||
(if 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
|
||||
|
||||
+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
|
||||
Mengen gehen ueber `LAGER_EXPORT` als Overlay-YAML an das RFQ-Programm
|
||||
(`lib/lager_yaml_export.py`). Konzept, Datenmodell und YAML-Zuordnung:
|
||||
[`doc/plan/lager_rfq.md`](../doc/plan/lager_rfq.md). Stand: Phase 0 + 1
|
||||
(Mengen, 2D).
|
||||
Parametrische Attributbloecke fuer ein mehrgeschossiges Haengewarenlager;
|
||||
`LAGER_EXPORT` schreibt die technischen Daten als eine JSON-Datei fuer die
|
||||
RFQ-Dokumentation (eigenes Projekt). Konzept, Datenmodell, JSON-Schema und
|
||||
Kennwert-Formeln: [`doc/plan/lager_rfq.md`](../doc/plan/lager_rfq.md). Stand:
|
||||
Phase 0 + 1 (Mengen, 2D).
|
||||
|
||||
| Befehl | Beschreibung |
|
||||
| --- | --- |
|
||||
| `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_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_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_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_HAND_YAML` | Hand-YAML fuer den Abgleich (Konfliktliste) festlegen |
|
||||
| `c:LG_REGELN` | Regelprofil (`cfg/regelwerk/<Land>.json`) mit aufgeloesten Werten und Quellen anzeigen |
|
||||
| `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:LG_REGELN` | Regelprofil (`cfg/stahlbau/regelwerk/<Land>.json`) mit aufgeloesten Werten und Quellen anzeigen |
|
||||
|
||||
Gangflaechen sind je Belag schraffiert (Schraffur in der Blockdefinition, Muster aus
|
||||
`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_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"],
|
||||
|
||||
"bereich": {
|
||||
@@ -31,7 +24,13 @@
|
||||
"min_ganglaenge_mm": 100,
|
||||
"richtung_grad": 0,
|
||||
"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": {
|
||||
@@ -45,10 +44,5 @@
|
||||
"beschreibung": "haengeebenen = Schienenhoehe ueber Belag / max. Warenlaenge je Haengeebene, durch Semikolon getrennt, oberste zuerst.",
|
||||
"haengeebenen": "2300/1200;1100/1100",
|
||||
"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; }
|
||||
: 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;
|
||||
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
|
||||
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,
|
||||
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 ==
|
||||
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`:
|
||||
|
||||
|
||||
+6
-6
@@ -1215,6 +1215,8 @@
|
||||
"lg-feld-rand_w": "\nRandgang West (mm, 0 = keiner)",
|
||||
"lg-feld-breite": "\nGangbreite (mm)",
|
||||
"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-prompt-gang-start": "\nStartpunkt der Gangmitte oder [%1] <Enter = Ende>: ",
|
||||
"lg-key-rechteck": "Rechteck",
|
||||
@@ -1245,7 +1247,6 @@
|
||||
"lg-titel-bereich": "Lager: Lagerbereich anlegen",
|
||||
"lg-titel-reihe": "Lager: Regalreihen einfuegen",
|
||||
"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-bereich": "\nKontur des Lagerbereichs waehlen (geschlossene Polylinie) <Enter = zeichnen>: ",
|
||||
"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-geschoss-ohne-kontur": "Geschoss %1 hat keine Belagskontur mehr.",
|
||||
"lg-exp-datei-fehler": "\n[Lager] Datei nicht schreibbar: %1",
|
||||
"lg-exp-raw": "\n[Lager] Rohdaten: %1",
|
||||
"lg-exp-yaml": "\n[Lager] Overlay-YAML: %1\n[Lager] Nachweis: %2",
|
||||
"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-python-fehler": "\n[Lager] lager_yaml_export.py endete mit Code %1 - siehe %2",
|
||||
"lg-hand-yaml": "\nHand-YAML fuer den Abgleich: %1",
|
||||
"lg-exp-json": "\n[Lager] Technische Daten: %1",
|
||||
"lg-exp-lichte-hoehe-oben": "Geschoss %1 (oberstes): lichte Hoehe nicht berechenbar - LICHTE_HOEHE_mm setzen.",
|
||||
"lg-exp-korb-hallenboden": "Bereich %1 hat Gitterkorb unter den Reihen, Geschoss %2 ist aber Hallenboden - nicht gezaehlt.",
|
||||
"lg-exp-reihen-ohne-geschoss": "%1 Regalreihe(n) ohne bekanntes Geschoss - nicht in den Kennwerten enthalten.",
|
||||
"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-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-breite": "\nAisle width (mm)",
|
||||
"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-prompt-gang-start": "\nStart point of the aisle centre line or [%1] <Enter = finish>: ",
|
||||
"lg-key-rechteck": "Rectangle",
|
||||
@@ -1245,7 +1247,6 @@
|
||||
"lg-titel-bereich": "Storage: create storage area",
|
||||
"lg-titel-reihe": "Storage: insert rack rows",
|
||||
"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-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).",
|
||||
@@ -1270,11 +1271,10 @@
|
||||
"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-datei-fehler": "\n[Storage] File not writable: %1",
|
||||
"lg-exp-raw": "\n[Storage] Raw data: %1",
|
||||
"lg-exp-yaml": "\n[Storage] Overlay YAML: %1\n[Storage] Report: %2",
|
||||
"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-python-fehler": "\n[Storage] lager_yaml_export.py ended with code %1 - see %2",
|
||||
"lg-hand-yaml": "\nManual YAML for comparison: %1",
|
||||
"lg-exp-json": "\n[Storage] Technical data: %1",
|
||||
"lg-exp-lichte-hoehe-oben": "Level %1 (top): clear height cannot be calculated - set LICHTE_HOEHE_mm.",
|
||||
"lg-exp-korb-hallenboden": "Area %1 has a mesh basket below the rows, but level %2 is a hall floor - not counted.",
|
||||
"lg-exp-reihen-ohne-geschoss": "%1 rack row(s) without a known level - not included in the key figures.",
|
||||
"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-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>
|
||||
</Macro>
|
||||
</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">
|
||||
<Macro>
|
||||
<Name>Export RFQ-YAML</Name>
|
||||
<Name>Export Lager-JSON</Name>
|
||||
<Command>^C^C(ssg-ensure "LagerInsert") LAGER_EXPORT</Command>
|
||||
</Macro>
|
||||
</MenuMacro>
|
||||
@@ -1773,13 +1767,7 @@
|
||||
</MenuItem>
|
||||
</PopMenuItem>
|
||||
<PopMenuItem>
|
||||
<NameRef>Hand-YAML fuer Abgleich</NameRef>
|
||||
<MenuItem>
|
||||
<MacroRef MenuMacroID="MM_00152"/>
|
||||
</MenuItem>
|
||||
</PopMenuItem>
|
||||
<PopMenuItem>
|
||||
<NameRef>Export RFQ-YAML</NameRef>
|
||||
<NameRef>Export Lager-JSON</NameRef>
|
||||
<MenuItem>
|
||||
<MacroRef MenuMacroID="MM_00153"/>
|
||||
</MenuItem>
|
||||
|
||||
+1
-1
@@ -174,7 +174,7 @@
|
||||
(ssg-ensure "ssg_blocktools")
|
||||
(ssg-ensure "ssg_texttools")
|
||||
(ssg-ensure "ssg_stueckliste")
|
||||
;; Lagerplanung (RFQ-YAML): Regelprofile vor LagerInsert
|
||||
;; Lagerplanung (Export Lager-JSON): Regelprofile vor LagerInsert
|
||||
(ssg-ensure "LagerPruefung")
|
||||
(ssg-ensure "LagerInsert")
|
||||
|
||||
|
||||
+1
-2
@@ -145,8 +145,7 @@
|
||||
[--]
|
||||
[Regale zaehlen]^C^C(ssg-ensure "LagerInsert") LG_REGALE
|
||||
[Regelprofil anzeigen]^C^C(ssg-ensure "LagerPruefung") LG_REGELN
|
||||
[Hand-YAML fuer Abgleich]^C^C(ssg-ensure "LagerInsert") LAGER_HAND_YAML
|
||||
[<-Export RFQ-YAML]^C^C(ssg-ensure "LagerInsert") LAGER_EXPORT
|
||||
[<-Export Lager-JSON]^C^C(ssg-ensure "LagerInsert") LAGER_EXPORT
|
||||
[->HW Planung]
|
||||
[Materialfluss erzeugen]^C^C(ssg-ensure "HwPlanung") HW_MATERIALFLUSS
|
||||
[<-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
|
||||
# auf das Raster (omniflo_zellgroesse_mm) zurueck.
|
||||
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)
|
||||
;; - einen Lagerbereich 10000 x 6000 im OG mit Auto-Fuellung
|
||||
;; und prueft Bloecke, Attribute, Layer, Neuberechnung (keine Verdopplung),
|
||||
;; den Neuaufbau einer geaenderten Reihe, die Rohdaten von LAGER_EXPORT und
|
||||
;; die Zaehlung von LG_REGALE.
|
||||
;; den Neuaufbau einer geaenderten Reihe, die JSON-Daten von LAGER_EXPORT
|
||||
;; (inkl. Kennwerte und Gitterkorb) und die Zaehlung von LG_REGALE.
|
||||
;;
|
||||
;; Aufruf in BricsCAD:
|
||||
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_lager.lsp"))
|
||||
;; TEST_LAGER
|
||||
;;
|
||||
;; Speichert tests/output/lager_results.json (Konvention test_run_all)
|
||||
;; und tests/output/lager_tests_lager_raw.json (Eingabe fuer
|
||||
;; lib/lager_yaml_export.py).
|
||||
;; und tests/output/lager_tests_lager.json (Beispiel der Export-Datei).
|
||||
;; ============================================================
|
||||
|
||||
(setq *tlg-pass* 0 *tlg-fail* 0 *tlg-fails* '())
|
||||
@@ -80,7 +79,11 @@
|
||||
(mapcar '(lambda (ed) (cons (cdr (assoc 2 ed)) T))
|
||||
(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
|
||||
r1 gg1 n-alt g2 r2 gg2 ids b2k n-kinder bb rg rk zl
|
||||
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 "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 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 bereiche" 1 (length (ssg-json-get daten "bereiche")))
|
||||
(tlg-eq "export reihen" 8 (length (ssg-json-get daten "reihen")))
|
||||
(tlg-eq "export land" "DE" (ssg-json-get daten "land"))
|
||||
(tlg-eq "export konturflaeche" 6.0e7
|
||||
(ssg-json-get (car (vl-remove-if-not '(lambda (g) (= (ssg-json-get g "nr") 1))
|
||||
(ssg-json-get daten "geschosse")))
|
||||
"kontur_flaeche_mm2"))
|
||||
(setq eg1 (tlg-export-geschoss daten 1) eg0 (tlg-export-geschoss daten 0))
|
||||
(tlg-eq "export konturflaeche" 6.0e7 (ssg-json-get (ssg-json-get eg1 "kontur") "flaeche_mm2"))
|
||||
(tlg-eq "export konturpunkte" 4 (length (ssg-json-get (ssg-json-get eg1 "kontur") "punkte")))
|
||||
(tlg-eq "export haengeebenen"
|
||||
'((("schienenhoehe_mm" . 2300) ("warenlaenge_mm" . 1200))
|
||||
(("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 daten "reihen"))
|
||||
"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 ---
|
||||
(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"))
|
||||
(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)))
|
||||
|
||||
;; --- 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: bereich belag" T
|
||||
(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
|
||||
(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)))
|
||||
|
||||
@@ -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/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/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-ebenen" "[{\"schienenhoehe_mm\": 2300, \"warenlaenge_mm\": 1200}]"
|
||||
(cadr (lg-json-ebenen "2300/1200")))
|
||||
(tu-eq "lg-json-wert/obj-arr" "{\"p\": [1, 2.5], \"o\": {\"x\": null}}"
|
||||
(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 ---
|
||||
(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")
|
||||
'(("absturzhoehe" . 3100)))))
|
||||
(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