diff --git a/CLAUDE.md b/CLAUDE.md index 5f2af40..ff07507 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -82,7 +82,7 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD. | 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 | | HW Planung | `HwPlanung` | HW_MATERIALFLUSS (Materialfluss erzeugen), HW_SYMBOLE (Symbole erzeugen, noch Platzhalter) | -| 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, LG_DARSTELLUNG, LAGER_EXPORT, LG_REGELN | | HW Planung | `HwPlanung` | HW_MATERIALFLUSS (Materialfluss erzeugen), HW_SYMBOLE (Symbole erzeugen), HW_NUMMERIEREN (Symbole nummerieren). Einzelbefehle HW_SYM_VENTILE/_SENSOREN/_MOTOREN/_MOTORSCHUTZ/_ENCODER/_SCANNER und HW_SYM_LOESCHEN bewusst NICHT im Menue. Ablauf: `doc/hw_planung.md` | | 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 | @@ -126,7 +126,7 @@ 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_` -> `KF_LAENGE` -> `KF_AN_` (je KS_AUS auf KS_EIN) plus der Draufsicht `KF_2D` EINEN Block `KF_`. 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_` 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_` (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_`. 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_` 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, HW_SYM_VENTILE, HW_SYM_SENSOREN, HW_SYM_MOTOREN, HW_SYM_MOTORSCHUTZ, HW_SYM_ENCODER, HW_SYM_SCANNER, HW_SYM_LOESCHEN, HW_NUMMERIEREN | Menue "HW Planung" (zwischen Lager und SPS), Ablauf und Renamer-Regeln in `doc/hw_planung.md`. **Ausgabeziel per Dialog** `dcl/hw_ausgabe.dcl` vor jedem Erzeugungsbefehl (`hw-ausgabe-waehlen`, letzte Wahl je Sitzung in `*hw-ausgabe-letzt*`, ohne GUI Standarddatei `_HW.dxf`): **aktuelle Zeichnung** (Python schreibt eine EINHEITENLOSE Zwischendatei `_HW_tmp.dxf` (`--einheitenlos`, sonst skaliert BricsCAD beim Einfuegen), `hw-in-aktuelle-zeichnung` fuegt sie per `vla-InsertBlock` bei 0,0 ein, loest sie per `vla-Explode` auf und loescht ERST DANACH die fruehere Ausgabe - `hw-alte-ausgabe` ueber XDATA `SSG_HW_MF` (Materialfluss) bzw. `SSG_HW_SYM` je Praefix), **bestehende Datei ergaenzen** (getfiled ueber `done_dialog 2`, da getfiled aus einem action_tile nicht geht) oder **neue Datei** (Name, Ordner DXFM_RESULTS; existiert sie, bleibt der Dialog mit Hinweis offen). Reine Kerne `hw-name-ohne-dxf`/`hw-name-gueltig-p`/`hw-neu-pfad`/`hw-ausgabe-pruefen` getestet. In einer Datei ersetzt jeder Befehl nur seinen eigenen Anteil (Materialfluss = XDATA `SSG_HW_MF` bzw. HW_*-Layer, Symbole = XDATA `SSG_HW_SYM` je Praefix) - vom Anwender Gezeichnetes (Renamer-Bereiche) bleibt; die Ursprungsdatei auf der Platte wird nie geaendert. Python-Aufrufe zentral ueber `hw-python` (Log je Befehl in DXFM_LOG, `ok-codes` fuer create_numbers' Exit 1 bei Planungsfehlern). HW_MATERIALFLUSS: EXPORTCSV (alte CSV vorher geloescht) -> `lib/hw_materialfluss.py`. **Symbole**: Regelwerk `cfg/io_regeln.json` (reduzierte Kopie aus kabellaengen: Rollen mit Praefix/Symbolblock, Bauteile, `io_vorlage`; Erkennungs-Regex/Radien/Nummernpaare/altZuNeu entfernt). **Aussehen und Attribute der Symbole stehen in `cfg/hw_symbole.json`** (Vorlagen mit Rahmen/Schraffur + Attribut-Lage/-Hoehe/-Stil, je Symbol Layer/Farbe/`versatz`/Abweichungen je Tag/Werte) - es gibt KEINE Symbol-Bibliothek als Referenzdokument. Die Symbole tragen DIESELBEN Blocknamen wie die ILS-Katalogsymbole in kabellaengen und sind ihnen exakt nachgebaut (inkl. Einfuegepunkt: Eingaenge/Motoren haengen nach unten) - `test_symbole_gleichen_dem_katalog` prueft das gegen `kabellaengen/doc/Symbole/ILS-Symbole.dxf`; aendert sich dort ein Symbol, faellt der Test und die Konfiguration wird nachgezogen. `hw-sym-bauteile-sammeln` findet die Mechanik-Bloecke der Ursprungszeichnung top-level UND verschachtelt in VF_n/GF_n/KREISEL_n (Weltlage ueber `csv:wrapper-welt-records`), `hw-sym-plan` legt je Rolle Symbolblock, flachen ZIELPUNKT (Bauteil-Einfuegepunkt, `hw-sym-ziel`) und ID-VORLAGE (`hw-sym-io-vorlage`, z.B. `MB1@@@`) fest; bei Alternativen in `benoetigt` die erste. `hw-sym-plan->json` (Zahlen ueber `hw-json-zahl`, DIMZIN-unabhaengig) -> `_hw_symbole.json` -> `lib/hw_symbole.py`; der Plan ist IMMER vollstaendig (alle Praefixe), `praefixe` sagt nur, was eingefuegt wird - so haengt die Lage nicht vom Einzelbefehl ab. Die LAGE rechnet Python (kennt die Symbolgeometrie), nicht LISP. Die Nummern vergibt NICHT das Erzeugen, sondern HW_NUMMERIEREN in der geoeffneten _HW.dxf: QSAVE, `lib/create_numbers.py --dryrun --info`, dann `hw-num-anwenden` (Zuordnung je Attribut mit `@` ueber Wert + Einfuegepunkt, `hw-num-eintrag-p`) in die offene Zeichnung. Reine Kerne in `tu-tests-hw` | | `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 | 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__`/`LG_GANG___` (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`; `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 `_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 und Breite, Belags-/Gitterrostflaeche, Gitterkorb, Regalrohr = Laenge x Haengeebenen), je Geschoss-Kennwert `herkunft` (Formel + Quelle). **`null` = fehlt (offener Punkt), nicht Zutreffendes wird weggelassen** (Marker `'ENTFAELLT`, `lg-json-ohne-entfallend`). Plausibilitaetswarnungen je Geschoss (`lg-plausibilitaet`, Grenzwerte aus dem Regelprofil). Das Reihen-Attribut `SCHIENEN` ist entfallen; `SCHIENEN_JE_GANG` am Bereich (Trolley) wird noch nicht ausgewertet. 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 nicht im Export (`doc/todo.md`). 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 neuen (`lg-kopie-belag`). Tests: `tu-tests-lager` (test_unit) und `tests/test_lager.lsp` | +| `LagerInsert.lsp` | LG_GESCHOSS, LG_GESCHOSS_AKTIV, LG_GESCHOSS_KOPIEREN, LG_BEREICH, LG_REIHE, LG_GANG, LG_EDIT, LG_REGALE, LG_DARSTELLUNG, 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__`/`LG_GANG___` (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`; `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 `_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 und Breite, Belags-/Gitterrostflaeche, Gitterkorb, Regalrohr = Laenge x Haengeebenen), je Geschoss-Kennwert `herkunft` (Formel + Quelle). **`null` = fehlt (offener Punkt), nicht Zutreffendes wird weggelassen** (Marker `'ENTFAELLT`, `lg-json-ohne-entfallend`). Plausibilitaetswarnungen je Geschoss (`lg-plausibilitaet`, Grenzwerte aus dem Regelprofil). Das Reihen-Attribut `SCHIENEN` ist entfallen; `SCHIENEN_JE_GANG` am Bereich (Trolley) wird noch nicht ausgewertet. 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 nicht im Export (`doc/todo.md`). **Darstellung der Absturzsicherung** (`lg-darstellung-geschoss`): auf Buehnen je Reihe eine Schraffur fuer gitterrost bzw. gitterkorb, beim Gitterkorb zusaetzlich die seitliche Abgrenzung als dicke Polylinie NUR an offenen Kanten (reiner Kern `lg-sicherung-geometrie` ueber `lg-kante-offen-intervalle`, gleiche Regel wie der Export). Lose Objekte auf `LG_Sicherung_G` mit XDATA `rolle=sicherung`, bei jedem Neuaufbau komplett ersetzt; automatisch nach Bereich fuellen, Reihe/Gang/Geschoss bearbeiten, `LG_REIHE`/`LG_GANG` und Geschoss kopieren. Farben/Muster aus `lager.json` (`darstellung.reihe.farbe`, `darstellung.unter_reihe.*`, `belag_schraffur..farbe`; ACI oder "r,g,b", `lg-farbe-dxf`/`lg-farbe-setzen`). `LG_DARSTELLUNG` (Menue Lager -> Darstellung aktualisieren) liest lager.json neu, frischt die Definitionen `LG_REIHE_*`/`LG_GANG_*` auf (`lg-darstellung-definitionen`) und zeichnet alle Geschosse neu. 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 neuen (`lg-kopie-belag`). Tests: `tu-tests-lager` (test_unit) und `tests/test_lager.lsp` | | `LagerPruefung.lsp` | LG_REGELN | Regelprofile der Lagerplanung: `cfg/stahlbau/regelwerk/.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). | diff --git a/Lisp/LagerInsert.lsp b/Lisp/LagerInsert.lsp index 4ccc536..a59df1f 100644 --- a/Lisp/LagerInsert.lsp +++ b/Lisp/LagerInsert.lsp @@ -768,12 +768,51 @@ "")) ) -;; Reihe: Rechteck L x T um die Schienenlinie (0,0)-(L,0). -(defun lg-reihe-blockdef (laenge tiefe / h) - (setq h (/ tiefe 2.0)) +;; ------------------------------------------------------------ +;; Farben (lager.json: ACI-Nummer 1..255 oder RGB-Text "r,g,b") +;; ------------------------------------------------------------ + +;; "r,g,b" -> (r g b), sonst nil. Rein, getestet. +(defun lg-farbe-rgb (farbe / teile) + (if (= (type farbe) 'STR) + (progn + (setq teile (mapcar '(lambda (s) (atoi (vl-string-trim " " s))) + (ssg-sepliste-split-feld farbe ","))) + (if (and (= (length teile) 3) (vl-every '(lambda (x) (<= 0 x 255)) teile)) teile))) +) + +;; Farbe als DXF-Gruppen fuer entmake: ACI -> ((62 . n)), RGB -> ((420 . rgb)), +;; nil/ungueltig -> nil (VONLAYER). Rein, getestet. +(defun lg-farbe-dxf (farbe / rgb) + (cond + ((and (numberp farbe) (<= 1 (fix farbe) 255)) (list (cons 62 (fix farbe)))) + ((setq rgb (lg-farbe-rgb farbe)) + (list (cons 420 (+ (* 65536 (car rgb)) (* 256 (cadr rgb)) (caddr rgb))))) + (T nil) + ) +) + +;; Farbe auf ein ActiveX-Objekt setzen; ohne gueltige Farbe -> sonst +;; (ACI-Nummer, z.B. 0 = VONBLOCK, 256 = VONLAYER). +(defun lg-farbe-setzen (obj farbe sonst / rgb c) + (cond + ((and (numberp farbe) (<= 1 (fix farbe) 255)) (vla-put-Color obj (fix farbe))) + ((setq rgb (lg-farbe-rgb farbe)) + (setq c (vla-get-TrueColor obj)) + (vla-SetRGB c (car rgb) (cadr rgb) (caddr rgb)) + (vla-put-TrueColor obj c)) + (T (vla-put-Color obj sonst)) + ) +) + +;; Reihe: Rechteck L x T um die Schienenlinie (0,0)-(L,0), Farbe aus +;; lager.json darstellung.reihe.farbe (sonst VONLAYER). +(defun lg-reihe-blockdef (laenge tiefe / h f) + (setq h (/ tiefe 2.0) + f (lg-farbe-dxf (lg-vorgabe '("darstellung" "reihe" "farbe") nil))) (lg-blockdef (lg-reihe-blockname laenge tiefe) - (append (list (lg-geom-rechteck 0.0 (- h) laenge h) - (lg-geom-linie '(0.0 0.0 0.0) (list laenge 0.0 0.0))) + (append (list (append (lg-geom-rechteck 0.0 (- h) laenge h) f) + (append (lg-geom-linie '(0.0 0.0 0.0) (list laenge 0.0 0.0)) f)) (lg-attdefs-unsichtbar *lg-schema-reihe*))) ) @@ -795,33 +834,53 @@ (if (not (boundp '*lg-schraffur-gemeldet*)) (setq *lg-schraffur-gemeldet* nil)) -;; Schraffur in eine vorhandene Blockdefinition einsetzen: umrandet die -;; erste Polylinie der Definition, Layer 0 + Farbe VONBLOCK (erbt den -;; Geschoss-Layer der Referenz). vorgabe = (muster massstab winkel-grad). -;; Rueckgabe: T oder nil (Muster unbekannt o.ae., Meldung). -(defun lg-schraffur-einsetzen (bname vorgabe / blk pl h res) +;; Schraffur anlegen (Block oder Modellbereich): owner = Block-/Bereichs- +;; objekt, pl = geschlossene Polylinie (vla) als Umgrenzung, vorgabe = +;; (muster massstab winkel-grad), farbe aus lager.json, sonst-farbe wie bei +;; lg-farbe-setzen, z = Erhebung. Rueckgabe: Hatch-Objekt oder nil (Meldung). +(defun lg-schraffur-anlegen (owner pl vorgabe farbe sonst-farbe layer z wo / h res) (setq res (vl-catch-all-apply '(lambda () - (setq blk (vla-Item (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-acad-object))) bname)) - (vlax-for o blk - (if (and (null pl) (= (vla-get-ObjectName o) "AcDbPolyline")) (setq pl o))) - (setq h (vla-AddHatch blk 1 (car vorgabe) :vlax-false)) ; 1 = vordefiniert - (vla-put-Layer h "0") - (vla-put-Color h 0) ; 0 = VONBLOCK + (setq h (vla-AddHatch owner 1 (car vorgabe) :vlax-false)) ; 1 = vordefiniert + (vla-put-Layer h layer) + (lg-farbe-setzen h farbe sonst-farbe) (vla-put-PatternScale h (cadr vorgabe)) (vla-put-PatternAngle h (* (/ (caddr vorgabe) 180.0) pi)) + (if (and z (/= z 0.0)) (vla-put-Elevation h z)) (vlax-invoke h 'AppendOuterLoop (list pl)) (vla-Evaluate h) - T))) + h))) (if (vl-catch-all-error-p res) (progn (if h (vl-catch-all-apply 'vla-Delete (list h))) - (princ (ssg-textf "lg-schraffur-fehler" (list (car vorgabe) bname (vl-catch-all-error-message res)))) + (princ (ssg-textf "lg-schraffur-fehler" (list (car vorgabe) wo (vl-catch-all-error-message res)))) nil) res) ) +(defun lg-bloecke () + (vla-get-Blocks (vla-get-ActiveDocument (vlax-get-acad-object))) +) + +;; Schraffur in eine vorhandene Blockdefinition einsetzen: umrandet die +;; erste Polylinie der Definition, Layer 0; ohne farbe VONBLOCK (erbt den +;; Geschoss-Layer der Referenz). Rueckgabe: T oder nil. +(defun lg-schraffur-einsetzen (bname vorgabe farbe / blk pl) + (setq blk (vl-catch-all-apply 'vla-Item (list (lg-bloecke) bname))) + (if (not (vl-catch-all-error-p blk)) + (progn + (vlax-for o blk + (if (and (null pl) (= (vla-get-ObjectName o) "AcDbPolyline")) (setq pl o))) + (if (and pl (lg-schraffur-anlegen blk pl vorgabe farbe 0 "0" nil bname)) T))) +) + +;; Farbe der Gangschraffur eines Belags (belag_schraffur..farbe). +(defun lg-schraffur-farbe (belag tabelle / e) + (if (and belag (= (type belag) 'STR) (setq e (ssg-json-get tabelle belag)) (listp e)) + (ssg-json-get e "farbe")) +) + (defun lg-gang-blockdef (laenge breite belag / h bname tab vorgabe) (setq h (/ breite 2.0) bname (lg-gang-blockname laenge breite belag) @@ -838,7 +897,7 @@ ;; Schraffur nur einmal je Definition (auch nach einer Neudefinition) (if (and vorgabe (not (vl-some '(lambda (ed) (= (cdr (assoc 0 ed)) "HATCH")) (lg-blockdef-objekte bname)))) - (lg-schraffur-einsetzen bname vorgabe)) + (lg-schraffur-einsetzen bname vorgabe (lg-schraffur-farbe belag tab))) bname ) @@ -873,7 +932,9 @@ ;; anwenden) - fuer das Bearbeiten von Hand. Rueckgabe: neuer ename. (defun lg-linie-neu-aufbauen-sperre (ent werte / neu) (if (setq neu (lg-linie-neu-aufbauen ent werte)) - (lg-sperre-anwenden neu)) + (progn + (lg-sperre-anwenden neu) + (lg-darstellung-geschoss (atoi (cond ((cdr (assoc "GESCHOSS" (ssg-attrib-read neu)))) ("0")))))) neu ) @@ -1398,6 +1459,7 @@ (lg-attribute-setzen bereich-ent (list (cons "RESTBREITE_mm" (lg-mm-str (cadr erg))))) (princ (ssg-textf "lg-bereich-gefuellt" (list (cdr (assoc "NR" a)) (itoa n-reihen) (itoa n-gaenge) (lg-mm-str (cadr erg))))) + (lg-darstellung-geschoss (atoi gs)) (list n-reihen n-gaenge (cadr erg)) ) ) @@ -1696,14 +1758,146 @@ (progn (lg-ldata-setzen "GESCHOSS_AKTIV" (car erg)) (princ (ssg-text "lg-kopie-hinweis-aktiv")))) + (foreach nr erg (lg-darstellung-geschoss nr)) (reverse erg)) ) ) +;; ============================================================ +;; DARSTELLUNG (Absturzsicherung unter den Reihen, Farben) +;; ============================================================ +;; Unter den Reihen einer Buehne wird die Sicherung je UNTER_REIHE gezeigt: +;; gitterrost / gitterkorb als Schraffur (Muster/Farbe aus lager.json +;; darstellung.unter_reihe), der Gitterkorb zusaetzlich mit seiner +;; seitlichen Abgrenzung als dicke Linie - aber nur an den OFFENEN Kanten: +;; wo eine andere Reihe anliegt (Ruecken an Ruecken), gibt es keine +;; Abgrenzung (lg-sicherung-geometrie, gleiche Regel wie der Export). +;; Die Objekte sind lose (Layer LG_Sicherung_G, XDATA rolle=sicherung) +;; und werden bei jedem Neuaufbau des Geschosses komplett ersetzt. + +;; wirksames UNTER_REIHE einer Reihe (Bereich ueber XDATA, sonst Vorgabe). +(defun lg-reihe-unter-ent (ent buehne-p / b) + (setq b (lg-ent-aus-handle (lg-xdata-wert ent "bereich"))) + (lg-unter-reihe-wert (if b (cdr (assoc "UNTER_REIHE" (ssg-attrib-read b)))) + (lg-unter-reihe-vorgabe) buehne-p) +) + +;; Alle Sicherungs-Objekte auf layer loeschen. Rueckgabe: Anzahl. +(defun lg-sicherung-loeschen (layer / ss i) + (setq i 0) + (if (setq ss (ssget "_X" (list (cons 8 layer) (list -3 (list *lg-app*))))) + (repeat (sslength ss) + (if (= (lg-xdata-wert (ssname ss i) "rolle") "sicherung") (entdel (ssname ss i))) + (setq i (1+ i)))) + i +) + +(defun lg-sicherung-markieren (ent) + (lg-xdata-setzen ent (list (cons "rolle" (cons 1000 "sicherung")))) + ent +) + +;; LWPOLYLINE in WCS (2D-Punkte + Erhebung z) per entmake. Rueckgabe: ename. +(defun lg-lwpoly-make (pts z layer geschlossen breite farbe / ) + (entmakex + (append + (list '(0 . "LWPOLYLINE") '(100 . "AcDbEntity") (cons 8 layer)) + (lg-farbe-dxf farbe) + (list '(100 . "AcDbPolyline") (cons 90 (length pts)) (cons 70 (if geschlossen 1 0)) (cons 38 z)) + (if breite (list (cons 43 breite))) + (mapcar '(lambda (p) (list 10 (car p) (cadr p))) pts))) +) + +;; Sicherung unter den Reihen eines Geschosses neu zeichnen. Auf +;; Hallenboden wird nur geloescht. Rueckgabe: Anzahl neuer Objekte. +(defun lg-darstellung-geschoss (nr / g lay buehne ents reihen zs tab vorgabe rand-farbe breite n pl h ent) + (setq n 0) + (if (setq g (lg-geschoss-finden nr)) + (progn + (setq lay (lg-layer "sicherung" nr)) + (lg-sicherung-loeschen lay) + (setq buehne (lg-buehne-p (cdr (assoc "BELAG_ART" (caddr g))))) + (if buehne + (progn + (setq ents (vl-remove-if-not '(lambda (e) (= (cdr (assoc "GESCHOSS" (ssg-attrib-read e))) (itoa nr))) + (lg-alle-bloecke "LG_REIHE_*")) + reihen (mapcar '(lambda (e) (list (lg-linie-polygon e) (lg-reihe-unter-ent e T))) ents) + zs (mapcar '(lambda (e) (cond ((caddr (cdr (assoc 10 (entget e))))) (0.0))) ents) + tab (lg-vorgabe '("darstellung" "unter_reihe") nil) + rand-farbe (lg-vorgabe '("darstellung" "unter_reihe" "gitterkorb" "rand" "farbe") nil) + breite (lg-zahl (lg-vorgabe '("darstellung" "unter_reihe" "gitterkorb" "rand" "breite_mm") 50))) + (foreach x (lg-sicherung-geometrie reihen 1.0) + (if (= (car x) "flaeche") + (if (setq vorgabe (lg-schraffur-vorgabe (cadr x) tab)) + (progn + (setq pl (lg-lwpoly-make (caddr x) (nth (cadddr x) zs) lay T nil nil) + h (lg-schraffur-anlegen (lg-modelspace) (vlax-ename->vla-object pl) vorgabe + (lg-schraffur-farbe (cadr x) tab) 256 lay + (nth (cadddr x) zs) lay)) + (entdel pl) + (if h (progn (lg-sicherung-markieren (vlax-vla-object->ename h)) (setq n (1+ n)))))) + (if (setq ent (lg-lwpoly-make (list (cadr x) (caddr x)) (nth (cadddr x) zs) lay nil breite rand-farbe)) + (progn (lg-sicherung-markieren ent) (setq n (1+ n))))))))) + ) + n +) + +;; Belag einer Gang-Blockdefinition aus ihrem Namen LG_GANG___. +;; Rein, getestet. +(defun lg-gang-belag-aus-name (bname / teile) + (setq teile (ssg-sepliste-split-feld bname "_")) + (if (> (length teile) 4) (strcase (ssg-join (cddddr teile) "_") T)) +) + +;; Vorhandene Blockdefinitionen an die Farben/Schraffuren aus lager.json +;; anpassen: LG_REIHE_* bekommen die Reihenfarbe, LG_GANG_* ihre Schraffur +;; neu (Muster und Farbe je Belag). +(defun lg-darstellung-definitionen ( / rf tab nm hs belag vorgabe) + (setq rf (lg-vorgabe '("darstellung" "reihe" "farbe") nil) + tab (lg-vorgabe '("belag_schraffur") nil)) + (vlax-for b (lg-bloecke) + (setq nm (strcase (vla-get-Name b))) + (cond + ((wcmatch nm "LG_REIHE_*") + (vlax-for o b + (if (member (vla-get-ObjectName o) '("AcDbPolyline" "AcDbLine")) + (lg-farbe-setzen o rf 256)))) + ((wcmatch nm "LG_GANG_*") + (setq hs nil) + (vlax-for o b (if (= (vla-get-ObjectName o) "AcDbHatch") (setq hs (cons o hs)))) + (foreach h hs (vla-Delete h)) + (setq belag (lg-gang-belag-aus-name nm)) + (if (setq vorgabe (lg-schraffur-vorgabe belag tab)) + (lg-schraffur-einsetzen (vla-get-Name b) vorgabe (lg-schraffur-farbe belag tab)))) + ) + ) +) + +;; Alles neu: Definitionen und die Sicherung aller Geschosse. +(defun lg-darstellung-alle ( / n) + (lg-darstellung-definitionen) + (setq n 0) + (foreach g (lg-geschosse) (setq n (+ n (lg-darstellung-geschoss (cadr g))))) + n +) + ;; ============================================================ ;; BEFEHLE ;; ============================================================ +;; Darstellung aktualisieren: Farben/Schraffuren aus lager.json auf alle +;; Reihen-/Gang-Definitionen, Sicherung unter den Reihen aller Geschosse +;; neu (z.B. nach Loeschen von Hand oder Aenderung von lager.json). +(defun c:LG_DARSTELLUNG ( / n) + (ssg-start (ssg-text "lg-titel-darstellung") nil) + (setq *lg-daten* nil) ; lager.json neu lesen + (setq n (lg-darstellung-alle)) + (command "_.REGEN") + (princ (ssg-textf "lg-darstellung-fertig" (list (itoa n)))) + (ssg-end) + (princ) +) + (defun c:LG_GESCHOSS ( / kontur nr werte blk) (ssg-start (ssg-text "lg-titel-geschoss") nil) (setq kontur (lg-kontur-waehlen (ssg-text "lg-prompt-kontur-geschoss"))) @@ -1923,6 +2117,7 @@ (setq n (lg-linien-schleife (ssg-text "lg-prompt-reihe-start") '(lambda (p1 p2) (lg-manuell-einfuegen "reihe" p1 p2 werte)) nil)) + (if (> n 0) (lg-darstellung-geschoss gs)) (princ (ssg-textf "lg-reihen-eingefuegt" (list (itoa n)))))))) (ssg-end) (princ) @@ -1984,6 +2179,8 @@ (setq n (lg-linien-schleife (ssg-text "lg-prompt-gang-start") '(lambda (p1 p2) (lg-gang-einfuegen p1 p2 werte)) '(lambda (ecken) (lg-gang-rechteck-einfuegen ecken werte)))) + ;; ein Gang kann Reihen zerschneiden -> neue offene Kanten + (if (> n 0) (lg-darstellung-geschoss gs)) (princ (ssg-textf "lg-gaenge-eingefuegt" (list (itoa n)))))))) (ssg-end) (princ) @@ -1997,7 +2194,10 @@ ((= name "LG_GESCHOSS") ;; Nummer bleibt fest - an ihr haengen Layer und GESCHOSS der Kinder (if (setq neu (lg-dialog "lg_geschoss" *lg-felder-geschoss* a '("nr"))) - (progn (lg-attribute-setzen ent neu) (princ (ssg-text "lg-geaendert"))))) + (progn (lg-attribute-setzen ent neu) + ;; Belag kann zwischen Buehne und Hallenboden wechseln + (lg-darstellung-geschoss (atoi (cond ((cdr (assoc "NR" a))) ("0")))) + (princ (ssg-text "lg-geaendert"))))) ((= name "LG_BEREICH") (if (setq neu (lg-dialog "lg_bereich" *lg-felder-bereich* a nil)) (progn @@ -2290,13 +2490,13 @@ (<= (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) +;; Offene Abschnitte der Kante (p q) als ((t0 t1) ...) in mm ab p: die +;; Kante ohne die Abschnitte, auf denen eine Kante eines Nachbar-Rechtecks +;; kollinear (Abstand < tol) aufliegt. Stuecke bis tol fallen weg. +(defun lg-kante-offen-intervalle (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 + (if (>= len 1e-9) (progn (setq ux (/ (- (car q) (car p)) len) uy (/ (- (cadr q) (cadr p)) len)) (foreach f nachbarn @@ -2313,22 +2513,35 @@ 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)))))) + (vl-remove-if '(lambda (i) (<= (- (cadr i) (car i)) tol)) + (ssg-intervalle-minus (list (list 0.0 len)) zu)))) +) + +;; Offene Laenge der Kante (Summe von lg-kante-offen-intervalle). +(defun lg-kante-offen (kante nachbarn tol) + (apply '+ (cons 0.0 (mapcar '(lambda (i) (- (cadr i) (car i))) + (lg-kante-offen-intervalle kante nachbarn tol)))) +) + +;; Ecken der Rechtecke aus ecken-liste, deren Huelle die von Nr. i beruehrt +;; (ohne i selbst). bbs = Huellen in derselben Reihenfolge. +(defun lg-nachbarn (i ecken-liste bbs tol / j erg) + (setq j 0 erg nil) + (foreach f ecken-liste + (if (and (/= i j) (lg-bbox-beruehrt-p (nth i bbs) (nth j bbs) tol)) + (setq erg (cons f erg))) + (setq j (1+ j))) + erg ) ;; 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) +(defun lg-reihen-offene-kanten (ecken-liste tol / bbs erg i k 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))) + (setq nachbarn (lg-nachbarn i ecken-liste bbs tol) l 0.0 s 0.0 k 0) (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))) @@ -2337,6 +2550,39 @@ (reverse erg) ) +;; Geometrie der Absturzsicherung unter den Reihen EINES Geschosses (rein, +;; getestet). reihen = ((ecken unter) ...), ecken 2D aus lg-linie-polygon, +;; unter = gitterrost/gitterkorb/keine. Rueckgabe: +;; ("flaeche" unter ecken i) je Reihe mit gitterrost oder gitterkorb +;; ("rand" p1 p2 i) je OFFENEM Kantenabschnitt einer Gitterkorb- +;; Reihe - wo eine andere Reihe (gleich welche +;; Sicherung) anliegt, gibt es keine Abgrenzung +;; i = Index der Reihe (fuer Z und Zuordnung). +(defun lg-sicherung-geometrie (reihen tol / alle bbs erg i e u nachbarn p q len ux uy) + (setq alle (mapcar 'car reihen) bbs (mapcar 'ssg-poly-bbox alle) erg nil i 0) + (foreach r reihen + (setq e (car r) u (cadr r)) + (if (member u '("gitterrost" "gitterkorb")) + (setq erg (cons (list "flaeche" u e i) erg))) + (if (= u "gitterkorb") + (progn + (setq nachbarn (lg-nachbarn i alle bbs tol)) + (foreach k (lg-rechteck-kanten e) + (setq p (car k) q (cadr k) + len (distance (list (car p) (cadr p)) (list (car q) (cadr q)))) + (if (> len 1e-9) + (progn + (setq ux (/ (- (car q) (car p)) len) uy (/ (- (cadr q) (cadr p)) len)) + (foreach iv (lg-kante-offen-intervalle k nachbarn tol) + (setq erg (cons (list "rand" + (list (+ (car p) (* ux (car iv))) (+ (cadr p) (* uy (car iv)))) + (list (+ (car p) (* ux (cadr iv))) (+ (cadr p) (* uy (cadr iv)))) + i) + erg)))))))) + (setq 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). diff --git a/Lisp/README.md b/Lisp/README.md index d6383a8..74e3270 100644 --- a/Lisp/README.md +++ b/Lisp/README.md @@ -885,6 +885,7 @@ Phase 0 + 1 (Mengen, 2D). | `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:LG_DARSTELLUNG` | Darstellung aktualisieren: Farben/Schraffuren aus `lager.json` (`darstellung`, `belag_schraffur`) auf die Reihen-/Gang-Definitionen, Absturzsicherung unter den Reihen aller Geschosse neu zeichnen (Gitterrost/Gitterkorb als Schraffur, Gitterkorb-Abgrenzung nur an offenen Kanten, Layer `LG_Sicherung_G`). Geschieht nach Aenderungen automatisch fuer das betroffene Geschoss | | `c:LAGER_EXPORT` | `_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/.json`) mit aufgeloesten Werten und Quellen anzeigen | diff --git a/cfg/layer.cfg b/cfg/layer.cfg index 6f1f6bc..01e9110 100644 --- a/cfg/layer.cfg +++ b/cfg/layer.cfg @@ -190,6 +190,7 @@ geschoss = LG_Geschoss, 7 bereich = LG_Bereich, 4 reihe = LG_Reihe, 3 gang = LG_Gang, 8 +sicherung = LG_Sicherung, 30 # ============================================================ diff --git a/data/json/lager.json b/data/json/lager.json index b89f2c3..cdbc064 100644 --- a/data/json/lager.json +++ b/data/json/lager.json @@ -34,14 +34,24 @@ }, "belag_schraffur": { - "beschreibung": "Schraffur der Gangflaechen (LG_GANG_*) je Belag: muster = Schraffurmuster aus der BricsCAD-Musterdatei (metrisch: iso.pat), massstab, winkel in Grad; null = keine Schraffur. ANSI31 x 50 = Linien alle ca. 160 mm, GRID x 8 = Raster ca. 200 mm.", - "spanplatte": {"muster": "ANSI31", "massstab": 50, "winkel": 0}, - "gitterrost": {"muster": "GRID", "massstab": 8, "winkel": 0}, + "beschreibung": "Schraffur der Gangflaechen (LG_GANG_*) je Belag: muster = Schraffurmuster aus der BricsCAD-Musterdatei (metrisch: iso.pat), massstab, winkel in Grad, farbe (siehe darstellung); null = keine Schraffur. ANSI31 x 50 = Linien alle ca. 160 mm, GRID x 8 = Raster ca. 200 mm.", + "spanplatte": {"muster": "ANSI31", "massstab": 50, "winkel": 0, "farbe": null}, + "gitterrost": {"muster": "GRID", "massstab": 8, "winkel": 0, "farbe": null}, "hallenboden": null }, "reihe": { "beschreibung": "haengeebenen = Schienenhoehe ueber Belag / max. Warenlaenge je Haengeebene, durch Semikolon getrennt, oberste zuerst. Jede Haengeebene ist ein Regalrohr ueber die Reihenlaenge.", "haengeebenen": "2300/1200;1100/1100" + }, + + "darstellung": { + "beschreibung": "Farben und Schraffuren in der Zeichnung. farbe = ACI-Nummer (1..255) oder RGB-Text \"r,g,b\"; null = VONLAYER (Reihe) bzw. VONBLOCK (Gangschraffur). unter_reihe: Darstellung der Absturzsicherung unter den Regalreihen auf Buehnen (Layer LG_Sicherung_G), gitterkorb.rand = dicke Linie an den OFFENEN Kanten (an anliegenden Nachbarreihen keine). Aenderungen wirken auf den Bestand nach LG_DARSTELLUNG (Menue Lager -> Darstellung aktualisieren).", + "reihe": {"farbe": null}, + "unter_reihe": { + "gitterrost": {"muster": "ANSI37", "massstab": 30, "winkel": 45, "farbe": 8}, + "gitterkorb": {"muster": "ANSI38", "massstab": 30, "winkel": 0, "farbe": 30, + "rand": {"farbe": 30, "breite_mm": 50}} + } } } diff --git a/doc/plan/lager_rfq.md b/doc/plan/lager_rfq.md index 749b250..e9d782f 100644 --- a/doc/plan/lager_rfq.md +++ b/doc/plan/lager_rfq.md @@ -221,6 +221,26 @@ Reihen bleiben unschraffiert. Altbestand: fehlen einer vorhandenen Blockdefinition ATTDEFs des Schemas, definiert `lg-blockdef` sie neu und uebertraegt sie per `_.ATTSYNC` auf die Referenzen. +## Darstellung in der Zeichnung + +- **Absturzsicherung unter den Reihen** (nur Buehnen): je Reihe eine + Schraffur nach `UNTER_REIHE` - `gitterrost` und `gitterkorb` mit eigenem + Muster und eigener Farbe (`lager.json darstellung.unter_reihe`). Der + Gitterkorb bekommt zusaetzlich seine seitliche Abgrenzung als dicke Linie + (`rand.farbe`, `rand.breite_mm`), und zwar NUR an den offenen Kanten: wo eine + andere Reihe anliegt (z.B. Ruecken an Ruecken), wird keine Abgrenzung + gezeichnet (`lg-sicherung-geometrie`, gleiche Regel wie `offen_laengs_mm`). +- Die Objekte liegen lose auf `LG_Sicherung_G` (XDATA `rolle=sicherung`, + wird mit dem Geschoss gefroren) und werden bei jedem Neuaufbau des Geschosses + komplett ersetzt - automatisch nach Bereich fuellen/bearbeiten (Doppelklick), + Reihe/Gang bearbeiten, `LG_REIHE`/`LG_GANG`, Geschoss bearbeiten/kopieren. +- **Farben**: `darstellung.reihe.farbe` (Regalreihen), `belag_schraffur..farbe` + (Gangschraffur); ACI-Nummer oder `"r,g,b"`, `null` = VONLAYER/VONBLOCK. +- **`LG_DARSTELLUNG`** (Menue Lager -> Darstellung aktualisieren): liest + `lager.json` neu, passt alle vorhandenen `LG_REIHE_*`/`LG_GANG_*`-Definitionen + an und zeichnet die Sicherung aller Geschosse neu - noetig nach Loeschen von + Hand oder nach Aenderungen in `lager.json`. + ## Kennwerte <- Zeichnung Reine Kerne in `LagerInsert.lsp` (getestet in `tu-tests-lager`). Jeder diff --git a/lang/de_DE.json b/lang/de_DE.json index 432f4da..079c758 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -1240,7 +1240,9 @@ "lg-rechteck-zu-klein": "\n[Lager] Rechteck zu klein (Seite unter 1 mm) - kein Gang eingefuegt.", "lg-gaenge-eingefuegt": "\n%1 Gang/Gaenge eingefuegt.", "lg-schraffur-unbekannt": "\n[Lager] Belag %1 hat keinen Eintrag in belag_schraffur (lager.json) - Gaenge ohne Schraffur.", - "lg-schraffur-fehler": "\n[Lager] Schraffur %1 fuer %2 nicht moeglich (%3) - Gang ohne Schraffur.", + "lg-schraffur-fehler": "\n[Lager] Schraffur %1 fuer %2 nicht moeglich (%3) - ohne Schraffur.", + "lg-darstellung-fertig": "\n[Lager] Darstellung aktualisiert: %1 Objekt(e) Absturzsicherung unter den Reihen.", + "lg-titel-darstellung": "Lager - Darstellung aktualisieren", "lg-blockdef-ergaenzt": "\n[Lager] Blockdefinition %1 um %2 ergaenzt (Altbestand).", "lg-titel-kopie": "Lager: Geschoss kopieren", "lg-feld-quelle": "\nQuellgeschoss (Nr.)", diff --git a/lang/en_GB.json b/lang/en_GB.json index 75e2036..7926687 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -1240,7 +1240,9 @@ "lg-rechteck-zu-klein": "\n[Storage] Rectangle too small (side below 1 mm) - no aisle inserted.", "lg-gaenge-eingefuegt": "\n%1 aisle(s) inserted.", "lg-schraffur-unbekannt": "\n[Storage] Floor type %1 has no entry in belag_schraffur (lager.json) - aisles without hatch.", - "lg-schraffur-fehler": "\n[Storage] Hatch %1 for %2 not possible (%3) - aisle without hatch.", + "lg-schraffur-fehler": "\n[Storage] Hatch %1 for %2 not possible (%3) - without hatch.", + "lg-darstellung-fertig": "\n[Storage] Display updated: %1 fall protection object(s) below the rows.", + "lg-titel-darstellung": "Storage - update display", "lg-blockdef-ergaenzt": "\n[Storage] Block definition %1 extended by %2 (existing drawing).", "lg-titel-kopie": "Storage: copy level", "lg-feld-quelle": "\nSource level (no.)", diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 20cda01..030cad2 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -668,6 +668,12 @@ ^C^C(ssg-ensure "LagerInsert") LG_EDIT + + + Darstellung aktualisieren + ^C^C(ssg-ensure "LagerInsert") LG_DARSTELLUNG + + Regale zaehlen @@ -1760,6 +1766,12 @@ + + Darstellung aktualisieren + + + + Regale zaehlen diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 874672e..1be04ae 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -143,6 +143,7 @@ [Gaenge einzeln]^C^C(ssg-ensure "LagerInsert") LG_GANG [Bearbeiten]^C^C(ssg-ensure "LagerInsert") LG_EDIT [--] +[Darstellung aktualisieren]^C^C(ssg-ensure "LagerInsert") LG_DARSTELLUNG [Regale zaehlen]^C^C(ssg-ensure "LagerInsert") LG_REGALE [Regelprofil anzeigen]^C^C(ssg-ensure "LagerPruefung") LG_REGELN [<-Export Lager-JSON]^C^C(ssg-ensure "LagerInsert") LAGER_EXPORT diff --git a/tests/test_lager.lsp b/tests/test_lager.lsp index a5b64c9..e6f97dd 100644 --- a/tests/test_lager.lsp +++ b/tests/test_lager.lsp @@ -79,11 +79,27 @@ (mapcar '(lambda (ed) (cons (cdr (assoc 2 ed)) T)) (vl-remove-if-not '(lambda (ed) (= (cdr (assoc 0 ed)) "ATTDEF")) (lg-blockdef-objekte bname)))) +;; Objekte eines Typs (Wildcard) auf einem Layer. +(defun tlg-auf-layer (typ layer / ss i erg) + (setq erg nil) + (if (setq ss (ssget "_X" (list (cons 0 typ) (cons 8 layer)))) + (progn (setq i 0) + (repeat (sslength ss) (setq erg (cons (ssname ss i) erg) i (1+ i))))) + erg) + +;; Laenge einer offenen Polylinie (Punktliste). +(defun tlg-linienlaenge (pts / s) + (setq s 0.0) + (while (cdr pts) + (setq s (+ s (distance (list (car (car pts)) (cadr (car pts))) (list (car (cadr pts)) (cadr (cadr pts))))) + pts (cdr pts))) + s) + ;; 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 +(defun lager:tests ( / k0 k1 g0 g1 kb bereich reihen gaenge r0 neu raw daten pfad f eg0 eg1 kr sl 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) @@ -281,6 +297,26 @@ (ssg-json-get daten "bereiche")) "unter_reihe")) + ;; --- Darstellung der Sicherung (G1): Schraffur je Reihe, Rand nur an offenen Kanten --- + (lg-darstellung-geschoss 1) + (setq sl (lg-layer-name (car (lg-layer-basis "sicherung")) 1)) + (tlg-eq "darstellung: korb-schraffuren" (length kr) + (length (vl-remove-if-not '(lambda (e) (= (cdr (assoc 2 (entget e))) "ANSI38")) + (tlg-auf-layer "HATCH" sl)))) + (tlg-eq "darstellung: alle reihen schraffiert" (length (tlg-gs "LG_REIHE_*" 1)) + (length (tlg-auf-layer "HATCH" sl))) + (tlg-eq "darstellung: randlaenge = offene kanten" + (apply '+ (mapcar '(lambda (r) (+ (ssg-json-get (ssg-json-get r "gitterkorb") "offen_laengs_mm") + (ssg-json-get (ssg-json-get r "gitterkorb") "offen_stirn_mm"))) + kr)) + (apply '+ (mapcar '(lambda (e) (tlg-linienlaenge (ssg-lwpoly-punkte e))) + (tlg-auf-layer "LWPOLYLINE" sl)))) + (setq n3 (length (tlg-auf-layer "*" sl))) + (lg-darstellung-geschoss 1) + (tlg-eq "darstellung: kein doppeltes zeichnen" n3 (length (tlg-auf-layer "*" sl))) + (tlg-eq "darstellung: hallenboden ohne" 0 + (lg-darstellung-geschoss 0)) + (setq pfad (strcat (getenv "DXFMAKRO") "/tests/output/lager_tests_lager.json")) (if (setq f (open pfad "w")) (progn (princ raw f) (close f))) diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index 0edc9d3..d4c06f5 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -3537,6 +3537,43 @@ (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)) + ;; offene Abschnitte einer Kante + (tu-eqf "lg-kante-offen-intervalle/frei" '((0.0 4000.0)) + (lg-kante-offen-intervalle '((4000.0 350.0) (0.0 350.0)) nil 1.0)) + (tu-nil "lg-kante-offen-intervalle/ganz-zu" + (lg-kante-offen-intervalle '((4000.0 350.0) (0.0 350.0)) (list _e2) 1.0)) + ;; _e3 liegt auf x 2000..6000 an; Kante laeuft von x 4000 nach 0 + (tu-eqf "lg-kante-offen-intervalle/halb" '((2000.0 4000.0)) + (lg-kante-offen-intervalle '((4000.0 1050.0) (0.0 1050.0)) (list _e3) 1.0)) + ;; Darstellung der Sicherung: Ruecken an Ruecken -> keine Abgrenzung dazwischen + (setq _sg (lg-sicherung-geometrie (list (list _e1 "gitterkorb") (list _e2 "gitterkorb")) 1.0)) + (tu-eq "lg-sicherung/flaechen" 2 (length (vl-remove-if-not '(lambda (x) (= (car x) "flaeche")) _sg))) + (tu-eq "lg-sicherung/raender" 6 (length (vl-remove-if-not '(lambda (x) (= (car x) "rand")) _sg))) + (tu-eqf "lg-sicherung/randlaenge = offene kanten" + (apply '+ (mapcar '(lambda (o) (+ (car o) (cadr o))) (lg-reihen-offene-kanten (list _e1 _e2) 1.0))) + (apply '+ (mapcar '(lambda (x) (distance (cadr x) (caddr x))) + (vl-remove-if-not '(lambda (x) (= (car x) "rand")) _sg)))) + (tu-eq "lg-sicherung/keine-abgrenzung-auf-beruehrlinie" T + (not (vl-some '(lambda (x) (and (= (car x) "rand") + (equal (cadr (cadr x)) 350.0 1e-6) + (equal (cadr (caddr x)) 350.0 1e-6))) + _sg))) + ;; Gitterrost ohne Rand, "keine" ohne alles - schliesst aber die Kante des Korbs + (tu-eq "lg-sicherung/gitterrost-keine" + '(("flaeche" . "gitterrost")) + (mapcar '(lambda (x) (cons (car x) (cadr x))) + (lg-sicherung-geometrie (list (list _e1 "gitterrost") (list _e2 "keine")) 1.0))) + (tu-eq "lg-sicherung/nachbar-ohne-sicherung" 3 + (length (vl-remove-if-not '(lambda (x) (= (car x) "rand")) + (lg-sicherung-geometrie (list (list _e1 "gitterkorb") (list _e2 "keine")) 1.0)))) + ;; Farben und Gang-Belag + (tu-eq "lg-farbe-dxf/aci" '((62 . 3)) (lg-farbe-dxf 3)) + (tu-eq "lg-farbe-dxf/rgb" '((420 . 16744448)) (lg-farbe-dxf "255,128,0")) + (tu-nil "lg-farbe-dxf/nil" (lg-farbe-dxf nil)) + (tu-nil "lg-farbe-dxf/0" (lg-farbe-dxf 0)) + (tu-nil "lg-farbe-dxf/kaputt" (lg-farbe-dxf "1,2")) + (tu-eq "lg-gang-belag-aus-name" "gitterrost" (lg-gang-belag-aus-name "LG_GANG_4000_1000_GITTERROST")) + (tu-nil "lg-gang-belag-aus-name/ohne" (lg-gang-belag-aus-name "LG_GANG_4000_1000")) ;; 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)