diff --git a/CLAUDE.md b/CLAUDE.md index 3318d89..31a4c59 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -123,7 +123,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `GeruestInsert.lsp` | GERUEST, GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG, GERUEST_TRAEGER, GERUEST_TRAEGER_BESCHRIFTEN, OMNI_FAHRSTRECKE, OMNI_FAHRSTRECKE_BESCHRIFTEN | Geruest-Baugruppen aus `data/json/geruest.json` konfigurieren und einfuegen. **Ein Dialog je Bereich**: Rohrabhaenger / Saeulen / Wandbefestigung oeffnen NUR ueber ihren eigenen Menuebefehl (`geruest-starten id`, Dialogtitel aus dem ASCII-Feld `titel`); eine Umschaltung im Dialog gibt es nicht (DCL hat kein Reiter-Tile), `GERUEST` ohne Bereich zeigt nur einen Hinweis. Der Dialogstand beginnt je Aufruf frisch. 1"- und 2"-Saeulen liegen in EINER Baugruppe `Saeulen` mit gemeinsamer Anbauteil-Liste; **`teileart` und `dummy` duerfen je Geometrie-Variante ueberschrieben werden** (`geruest-variante-wert`, Variante gewinnt vor Baugruppe; fuer `dummy` ueber `geruest-dummy-wahl`: fehlt die DWG der Variante, Meldung + Rueckfall auf den Baugruppen-Dummy; ist der Dummy zugleich eine Teile-DWG, wird er per `geruest-ohne-pfad` nicht doppelt eingefuegt) - so liefert `R 1"` weiterhin TEILEART `Geruest Saeule 1 Zoll` und die `R 2"`-Varianten `Geruest Saeule 2 Zoll`, die Groessen bleiben im Export also unterscheidbar. **Das Layout steht als Vorlage in `dcl/geruest.dcl`** (bzw. `dcl/geruest_traeger.dcl`); nur die datenabhaengigen Bloecke - ein `radio_button` je Variante (Key `v`, `geruest-radio-key`/`-index`), Mengenfeld + Ankreuzfeld je Anbauteil - werden zur Laufzeit an Markerzeilen `//@NAME@` eingesetzt (`geruest-dcl-ersetzungen` -> `ssg-dcl-vorlage-fuellen` in ssg_core, Temp-Datei, nach `unload_dialog` geloescht). Grund: DCL kann Tiles weder zur Laufzeit erzeugen noch ausblenden, Radiobutton-Labels lassen sich per `set_tile` nicht aendern, und eine `list_box` kann keine Eingabefelder enthalten. Varianten bewusst als Radiobuttons statt `list_box`: BricsCAD zeichnet die Listenspalte nur halb so breit, und ein `tabs`-Wert passt nur schrift-/skalierungsabhaengig. Inhalt: Basis-Variante aus `geometrie_varianten` (Radiobuttons, siehe oben), **Winkel Platte** (0/90 Grad, `*geruest-winkel-werte*`): Ausrichtung der Anbauteile zur Basis - die Teile-DWGs aus oben/unten/sonstiges werden um diesen Winkel um Z gedreht in den Block eingefuegt, Basis und Dummy bleiben ungedreht (`geruest-teile-dwgs-rot`; in Konfigurationen als echter Wert `winkel_platte`, kein Block-Attribut), Laenge (gegen `attribute.Laenge` min/max geprueft, Retry-Schleife), Farbe (`attribute.Teilefarbe`, Freitext bei `frei_option`) und **eine Befestigungsspalte** "Befestigung oben und unten" mit allen `anbaugruppen.befestigung` - die Anzahl ist die GESAMTanzahl je Teil (oben und unten zusammen; Tile-Keys `b`/`bm`, Zustand `*geruest-dlg-bef*`). Unter jedem Teil (auch in Sonstiges) zeigt eine Textzeile "Art.-Nr. ..." die Artikelnummer(n) (`geruest-artnr-anzeige`: Einzelteil -> `sivas_id`, Gruppe -> eindeutige Nummern der Teile; DCL kennt keine Schriftgroesse, darum normale Groesse in eigener Zeile). `anbaugruppen` ist ein Objekt mit zwei Listen: `befestigung` (Befestigungsspalte) und `sonstiges` (Teile, die weder oben noch unten sitzen, z.B. die Saeulen-Haltearme) - letztere bekommen eine eigene Zeile darunter (nur wenn nicht leer), in ARTINR/BEZEICHNUNG nach "unten" als "sonstiges" (`geruest-anbau-liste`; ein altes flaches Array gilt als `befestigung`). **Zwei Mengenfelder im JSON, bewusst verschieden benannt**: `stueckzahl` = wie oft ein Teil TATSAECHLICH geschrieben wird (je Variante bzw. je Satz/Anbauteil, fehlt = 1), `anzahl_vorgabe` = NUR die Vorbelegung des Anzahl-Feldes im Dialog (Anbaugruppen, fehlt = 1); ein Anbauteil wird Anzahl x `stueckzahl` mal geschrieben, bei einer Gruppe (`teile`) zaehlt die Anzahl die Saetze (`geruest-stueckzahl`/`geruest-anzahl-vorgabe`). In Konfigurationen (`befestigung`/`sonstiges`, dazu `winkel_platte`) heisst der gespeicherte Dialogwert `anzahl`. Aeltere Konfigurationen mit getrennten `oben`/`unten`-Listen laden weiter: deren Mengen werden zur Gesamtanzahl addiert (`geruest-konfig-befestigung`), Sonstiges-Teile darin still in die Sonstiges-Zeile umgehaengt (`geruest-konfig-sonstiges`); beim naechsten Speichern steht alles im neuen Format. Baugruppen ohne `attribute`-Block (Wandbefestigung) bekommen Laenge/Farbe gesperrt, Baugruppen ohne Anbauteile bekommen gar keine Spalten (ein leerer DCL-Cluster ist unzulaessig). Im generierten Label wird `"` zu `''` ersetzt (`geruest-dcl-label`) - fuenf Artikelnamen enthalten ein Anfuehrungszeichen, das das DCL-Label sonst vorzeitig beendet und die Datei zerstoert. **Konfigurationen**: gepflegte Bibliothek je Baugruppe unter `konfigurationen` in `geruest.json` (schreibgeschuetzt) plus eigene in `cfg/geruest_user.json` (gitignored, `geruest-user-schreiben`; getrennte Datei, damit Benutzerdaten und versionierte Bibliothek nicht kollidieren). Eigene Eintraege sind in der Liste mit `*` markiert und nur diese loeschbar. **Geaenderte Konfiguration**: beim Anwenden wird der Dialogstand als Vergleichsbasis gemerkt (`*geruest-dlg-konfig-basis*`); jede Eingabe vergleicht den aktuellen Record damit (`geruest-dlg-aenderung-pruefen`, Vergleich statt Flag - Zuruecknehmen hebt die Markierung wieder auf) und kennzeichnet den Listeneintrag mit "(geaendert)" plus Statuszeile `kstatus`. Speichern bietet bei einer gewaehlten EIGENEN Konfiguration deren Namen als Vorgabe an (Enter = ueberschreiben, `geruest-konfig-name-vorgabe`); Bibliotheks-Konfigurationen brauchen einen neuen Namen. Konfigurationen verweisen ueber den ANZEIGENAMEN auf Variante und Anbauteile; ein unbekannter Name wird gemeldet und uebersprungen, statt die Konfiguration scheitern zu lassen. Speichern/Loeschen laufen ueber `done_dialog 2`/`3` (Dialog schliessen, Aktion, neu zeigen) - `getstring` funktioniert aus einem `action_tile`-Rueckruf heraus nicht. Der Block wird - wie KREISEL_n/VF_n - SELBST zusammengebaut: Dummy-DWG aus `data/geruest` liefert nur Geometrie, das Attribut-Schema kommt aus `*geruest-attrib-defs*` (ID, ARTINR, LAENGE, BEZEICHNUNG, TEILEART, TEILEFARBE, LAYER) und wird per `ssg-attrib-merge` mit den Dummy-Tags zusammengefuehrt - sonst verschluckt `ssg-attrib-set-on` stillschweigend jeden Tag, den die Dummy-DWG nicht als ATTDEF kennt. **Teile-Geometrie**: jede ausgewaehlte Artikelnummer (Basis/oben/unten inkl. aufgeloester Gruppen), fuer die `data/geruest/.dwg` existiert, wird zusaetzlich einmal bei 0,0,0 mit in den Block eingefuegt (`geruest-teile-dwgs`, dedupliziert, fehlende DWGs still uebergangen) - reine visuelle Rueckmeldung, die Attribut-Logik bleibt davon unberuehrt. **TEILEFARBE** ist eine kommagetrennte Liste parallel zu ARTINR (z.B. `,,RAL7030,,RAL7030`): Teile mit `"farbig": true` in `geruest.json` (je Artikel; eine Gruppe vererbt es an ihre Teile, fehlend = false) bekommen die im Dialog gewaehlte Baugruppenfarbe, alle anderen einen leeren Eintrag. ARTINR und TEILEFARBE entstehen aus demselben Durchlauf (`geruest-teile-paare`/`-paare-n`, `geruest-farbliste`), sind also garantiert gleich lang. `export_sivas.py` schreibt daraus je Artikelnummer das Merkmal `{"108": ""}` in `details` (Nummer aus `cfg/export.cfg` `[Sivas] merkmal_teilefarbe`). Blockname `GR__` (Kollisionszaehler wie in OmniModulInsert). **Das `GR_`-Praefix ist nicht kosmetisch**: `SSG_BLOCKEDIT` haelt JEDEN Block mit TEILEART-Attribut fuer ein Omniflo-Element, deshalb steht in `SSG_LIB_Commands.lsp` ein `GR_*`-Zweig VOR dem Omniflo-Zweig. ARTINR listet jede Sivas-ID so oft, wie Anzahl x `stueckzahl` es vorgeben - erst Basis, dann Befestigung, dann Sonstiges; bei einer benannten Gruppe (`teile`) wird das ganze Set n-mal wiederholt, die Mengen INNERHALB des Sets bleiben dabei erhalten (`geruest-artikelnummern-n`). BEZEICHNUNG nennt Position und Menge je Teil ("Befestigung 4x ...", "sonstiges 1x ...") und verkettet mit `" + "`, NICHT mit Komma - die Artikelbezeichnungen enthalten selbst Kommas ("ROHR R 1\" 33,7 x 2,6"). Zuordnung Menue -> JSON laeuft ueber das ASCII-Feld `id`, weil die aeusseren JSON-Schluessel Umlaute bzw. Anfuehrungszeichen tragen. CSV-/Sivas-Export: `pattern_geruest = GR_*` (cfg/export.cfg), `csv:collect-export-blocks`/`ssg-id-collect-blocks` sammeln GR_-Bloecke wie BTMT eigenstaendig; `*geruest-attrib-defs*` traegt zusaetzlich ein leeres `ID`-ATTDEF (Voraussetzung fuer `ssg-id-check-all`, das nur bestehende ATTRIBs beschreiben kann). ARTINR/BEZEICHNUNG/TEILEART/LAENGE landen in export_csv.py/export_sivas.py in festen Spalten, TEILEFARBE/LAYER (+ ARTINR bei export_csv.py) im Merkmale-/details-JSON. **Attribut-Keys in `geruest.json` sind GROSS** (`LAENGE`, `TEILEFARBE`, ...) = die Block-Attribut-Tags; `ssg-json-get` unterscheidet Gross/Klein. **Rohr-Geruest-Traeger** (`GERUEST_TRAEGER`): Traeger-Baugruppen mit Linien-Logik liegen in einer EIGENEN Datei `data/json/geruest_traeger.json` (gleicher Aufbau wie geruest.json, eigener Lader/Cache `geruest-traeger-daten`, Suche `geruest-baugruppe id daten`; gemeinsamer Lader `geruest-json-laden-cache`) - sie tauchen darum nicht im Bereichs-Dropdown von GERUEST auf; dort kann spaeter auch der Gattertraeger hin. eigener Dialog aus der Vorlage `dcl/geruest_traeger.dcl` (Variante als Radiobuttons, JEDE Variante - auch die mit Muffe - mit eigenem Button, Beschriftung "Name (Artikelnummern)" ueber `geruest-varianten-label`; Varianten mit `"disabled": true` erscheinen in allen drei Geruest-Dialogen ausgegraut und nicht waehlbar (`geruest-variante-gesperrt-p`, `geruest-varianten-sperren` per `mode_tile`; Vorauswahl ueber `geruest-variante-waehlbar`/`-erste-freie-variante`; eine Konfiguration mit gesperrter Variante laesst die Auswahl unveraendert und meldet `gr-konfig-variante-gesperrt`) - bleiben aber in den Daten, damit Konfigurationen und Neubeschriften sie weiter ueber den Namen finden; eine Muffen-Checkbox gab es zwischenzeitlich, sie wurde wieder entfernt, weil die Artikelnummer der Muffen-Variante dann im Dialog nicht sichtbar war; Farbe, je eine Checkbox + Feld fuer `LAENGENABZUGANFANG`/`LAENGENABZUGENDE`, Vorgabe `vorgabe`/`aktiv` aus dem attribute-Block, je Variante ueberschreibbar via `geruest-attr-feld`); danach Einfuege-Schleife bis ESC/Enter: Startpunkt, dann Endpunkt ODER getippte Laenge (+ Richtung). Aktive Abzuege ruecken die Linie beidseitig ein (Strecke 1000, Abzug Anfang 20/Ende 35 -> Start 20 mm hinter dem Klick, Linie 945 mm); `LAENGE` = Netto-Laenge, gegen `LAENGE.min/max` geprueft. KEINE Dummy-DWG: die Geometrie ist eine per `entmake` erzeugte LINE (0,0,0)-(L,0,0) auf dem `layer` der Variante, eingefuegt mit dem Richtungswinkel (ANGBASE/ANGDIR/AUNITS dafuer kurz auf 0). **Querstreben + Muffe** als verschachtelte Dummy-DWGs im selben Block, reine Grafik ohne Export: `querstrebe.dummy` (`data/geruest/dummy_Strebe_30x4.dwg`, Basispunkt Strebenmitte, 30 mm laengs X) an jeder Strebenposition, NUR bei Varianten mit ausdruecklichem `"mit_querstrebe": true` (z.B. nicht beim `Rohr 1"`); fehlt die DWG, Rueckfall auf je eine 25-mm-Querlinie an Strebenanfang/-ende (`laenge`/`querlinie`, Standard 30/25 nur im Code). `muffe.dummy` (`dummy_Muffe_1zoll.dwg`, Basispunkt Muffenmitte) am Linienende, NUR bei Varianten mit ausdruecklichem `"mit_muffe": true` (nicht aus dem Namen geraten; bei "mit 2 Muffen" trotzdem nur eine am Ende); `querstrebe`/`muffe` per Variante ueberschreibbar (`geruest-variante-wert`). Dummys werden ohne Drehung eingefuegt (Traeger laeuft im Block entlang +X), ab dem zweiten Mal per Blockname (`geruest-dummy-einfuegen`). Verteilungs-Konfiguration `querstrebe` (`abstand`/`rand_min`/`rand_max`, Variante vor Baugruppe), Plan `geruest-traeger-streben-plan` -> (rand positionen): der Abstand zwischen zwei Streben ist IMMER genau `abstand`, beide Raender gleich (netto = k*abstand + 2*rand); gewaehlt wird die Strebenzahl, deren Rand am naechsten an `rand_min`..`rand_max` liegt (Gleichstand -> weniger Streben). Mit 500/100..250 geht das nur auf, wenn netto mod 500 = 0 oder in [200, 500) liegt (z.B. 1300 -> 150|500|500|150); sonst (1001..1199, unter 200 mm) liegt der Rand ausserhalb (1100 -> 300|500|300) - `geruest-traeger-rand-pruefen` zeigt dann eine Messagebox (ohne GUI: Konsole), der Traeger wird trotzdem eingefuegt. Schema `*geruest-traeger-attrib-defs*` = `*geruest-attrib-defs*` + die zwei Abzug-Tags; gemeinsamer Block-Schluss mit den anderen Bereichen in `geruest-block-abschliessen`. Reine Berechnung (`geruest-traeger-laenge`/`-start`/`-pruefen`, `geruest-mm-zahl`) in `tests/test_unit.lsp`. **Traeger-Beschriftung** (Checkbox im Dialog, Standard an; z.B. `RT 80/80 L=2650`): EIGENES TEXT-Objekt neben dem Block, abgeleitet NUR aus dem fertigen Block (Einfuegepunkt, DXF 50, Attribute `LAENGE` + `VARIANTE`) - darum nutzen Einfuegen und `GERUEST_TRAEGER_BESCHRIFTEN` dieselbe Funktion `geruest-traeger-beschriften`, und ein von Hand verschobener/gedrehter Traeger wird beim Neubeschriften korrekt erfasst. Verknuepfung Text -> Block per XDATA `SSG_GR_BESCHR` (1005 = Block-Handle): Neubeschriften ersetzt statt verdoppelt, der Sammelbefehl entfernt verwaiste Texte. JSON `beschriftung` (je FELD Variante vor Baugruppe, `geruest-obj-feld`): Inhalt `format` (`%1` Text, `%2` Laenge auf ganze mm) + `text` (fehlt -> Variantenname) und `layer` (je Variante verschieden, darum in JEDER Variante gepflegt - keine Baugruppen-Vorgabe; fehlt er doch, aktueller Layer); Formatierung NUR `stil`/`ausrichtung`/`hoehe` - alles andere regelt der Textstil ausserhalb, es wird kein Stil angelegt (fehlt er: Meldung, aktueller TEXTSTYLE). `ausrichtung` = Codes von TEXT "Ausrichten" (T/M/B + L/C/R), Bezugspunkt auf der Traegerlinie, L/R in LESErichtung. Textwinkel entlang des Traegers, DIN: fuer 90 < w <= 270 Grad um 180 gedreht (`geruest-text-winkel`). **Omniflo-Fahrstrecke** (`OMNI_FAHRSTRECKE`, Daten `data/json/omniflo_fahrstrecke.json`, Vorlage `dcl/fahrstrecke.dcl`): dieselbe Linien-Logik wie der Traeger, Code geteilt - `geruest-linien-starten id daten dcl-datei dlg-name` (Dialog `geruest-traeger-dialog` mit Vorlage + Dialogname als Argument, Einfuegen `geruest-traeger-einfuegen`), Beschriftung `geruest-traeger-beschriften blockEnt bg` mit der Baugruppe als Argument, Sammelbefehle je Typ ueber `geruest-linien-beschriften id daten` (Bloecke `GR__*`; verwaiste Texte werden typunabhaengig entfernt). Unterschiede stehen nur in den Daten: keine Querstreben (kein `mit_querstrebe`), Muffen-Dummy wie beim Traeger ueber den `muffe`-Block der Baugruppe (nur Varianten mit `"mit_muffe": true`), `farbig` nur bei ST/STL, Muffen-Varianten nur fuer ST/STL. Der Dialogstand bleibt je Baugruppe erhalten (`*geruest-tr-id*`; Wechsel Traeger <-> Fahrstrecke setzt ihn zurueck). Meldungstexte `gr-tr-*` nennen den Bauteilnamen aus `titel` als Platzhalter. In der Stueckliste eigene Klasse `fahrstrecke` (`GR_Fahrstrecke_*` vor dem allgemeinen `GR_*`). Noch NICHT enthalten: Edit-Pfad (GERUEST_EDIT) | | `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**: die Bausteine sind in der XY-Ebene gezeichnet (Hoehe = Y), werden aber AUFGERICHTET eingebaut `Rz(basis)*Rx(90)*Rz(eigen)` (`kf-matrix-aufrecht`) - die Hoehe laeuft in **Z**; dafuer `insert-block-ks-matrix` (freie 3x3-Rotation) in ssg_ks_insert.lsp. 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`). `KF_2D` liegt DECKUNGSGLEICH mit der Kette (KS_EIN/KS_AUS auf denen von Umlenkung/Antrieb), ist flach gezeichnet, nur um die Steigung geneigt und auf die Schraeglaenge skaliert. **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). 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` | | `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__`/`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 `_lager_raw.json` (eigener JSON-Schreiber `lg-json-*`), zaehlt `goh_rack` ueber die eigene Erkennung `lg-racks-sammeln`/`lg-racks-finden` mit (parametrischer BricsCAD-Block: Name ueber `getpropertyvalue "EffectiveName"`, Parameter `Laenge`/`Ebenen` als MCAD-Eigenschaft `~MCAD` vor dynamischer Eigenschaft vor Attribut vor ATTDEF-Vorgabe, Einheit -> mm per `lg-zahl-einheit`; auch in assoziativen Arrays, MINSERT-Rastern und verschachtelten Bloecken, Transformationen `lg-insert-tf`/`lg-tf-verketten`; Ergebnis je Rack `(name laenge ebenen mitte top-ent)`, Zugriff `lg-rk-*`; Befehl `LG_REGALE` (Menue Lager -> Regale zaehlen) zeigt Anzahl, Laenge und Laenge x Ebenen je Geschoss in der Befehlszeile, reiner Kern `lg-racks-auswerten`) und ruft `lib/lager_yaml_export.py` ueber `export:run-python`. 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`). goh_rack per `vla-Copy` auf `lg-layer "goh_rack" `; Originale ohne `_G`-Layer werden auf den Regal-Layer der Quelle gelegt. Export ordnet goh_racks zuerst ueber den Layer `LG_*_G` des obersten INSERTs zu (`lg-rack-geschoss`, `lg-rk-top`), erst dann ueber die Kontur - damit eindeutig auch bei 2D-Geschossen uebereinander. 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, 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__`/`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 `_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 neuen (`lg-kopie-belag`). Tests: `tu-tests-lager` (test_unit) und `tests/test_lager.lsp` | | `LagerPruefung.lsp` | LG_REGELN | Regelprofile der Lagerplanung: `cfg/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 14cc7cd..1f0ab3c 100644 --- a/Lisp/LagerInsert.lsp +++ b/Lisp/LagerInsert.lsp @@ -11,8 +11,6 @@ ;; LG_REIHE__ Regalreihe (Rechteck L x T + Schienenlinie) ;; LG_GANG___ Gang/Quergang/Randgang (Rechteck L x B, Schraffur ;; je Belag aus lager.json belag_schraffur) -;; goh_rack parametrischer BricsCAD-Block (Bestand), wird als -;; Regalreihe mitgezaehlt (lg-racks-sammeln) ;; ;; Befehle: LG_GESCHOSS, LG_GESCHOSS_AKTIV, LG_GESCHOSS_KOPIEREN, LG_BEREICH, ;; LG_REIHE, LG_GANG, LG_EDIT, LG_REGALE, LAGER_EXPORT, LAGER_HAND_YAML @@ -132,16 +130,6 @@ ";") ) -;; Haengeebenen auf n Ebenen begrenzen (goh_rack kennt nur die Anzahl): -;; die obersten n der Vorgabe. Fehlen Ebenen in der Vorgabe, bleibt es bei -;; dem, was da ist. -(defun lg-haengeebenen-n (s n / ebenen erg i) - (setq ebenen (lg-haengeebenen-parse s) erg nil i 0) - (while (and ebenen (< i n)) - (setq erg (cons (car ebenen) erg) ebenen (cdr ebenen) i (1+ i))) - (lg-haengeebenen-string (reverse erg)) -) - ;; Feldwert pruefen/normalisieren. art: "mm" (Zahl >= 0), "mm_leer" (wie mm, ;; leer erlaubt), "int" (ganze Zahl >= 1), "int0" (>= 0), "grad" (beliebige ;; Zahl), "mm_vz" (mm mit Vorzeichen, z.B. Versatz), "text", "ebenen" @@ -1427,261 +1415,14 @@ ) ;; ============================================================ -;; GOH_RACK-ERKENNUNG (lg-racks-sammeln, Befehl LG_REGALE) +;; REGALE ZAEHLEN (LG_REGALE) ;; ============================================================ -;; goh_rack ist ein parametrischer BricsCAD-Block (MCAD-Parametrik), KEIN -;; AutoCAD-Dynamikblock: seine Referenzen tragen einen anonymen Namen -;; ("*U29"), IsDynamicBlock ist FALSE, und der echte Name sowie die -;; Parameter stehen nur in den Objekteigenschaften: -;; (getpropertyvalue ent "EffectiveName") -> "goh_rack" -;; (getpropertyvalue ent "Laenge~MCAD") -> "7187.52 mm" -;; Gefunden werden Racks direkt im Modellbereich, in assoziativen Arrays -;; (anonymer Block mit Referenzen), in MINSERT-Rastern und in beliebig -;; verschachtelten Bloecken (bis *lg-rack-max-tiefe*). Blockname und -;; Parameternamen aus lager.json "goh_rack". -;; Ergebnis je Rack: (name laenge-mm ebenen mitte top-ent), Zugriff ueber -;; lg-rk-*. top-ent = oberstes INSERT im Modellbereich, in dem das Rack -;; steckt (bei einem direkt eingefuegten Rack es selbst) - ueber dessen -;; Layer _G ordnet lg-rack-geschoss das Geschoss zu. -(setq *lg-rack-max-tiefe* 8) - -(defun lg-rk-name (r) (nth 0 r)) -(defun lg-rk-laenge (r) (nth 1 r)) -(defun lg-rk-ebenen (r) (nth 2 r)) -(defun lg-rk-mitte (r) (nth 3 r)) -(defun lg-rk-top (r) (nth 4 r)) - -;; Reiner Kern: Zahl aus einem Parameterwert. MCAD-Parameter kommen als -;; Text mit Einheit ("700 mm", "71.8752 cm", "12.9 m") - auf mm umgerechnet; -;; ohne Einheit unveraendert. Unbekannte Einheit/kein Zahlanfang -> nil. -(defun lg-zahl-einheit (v / s i c ziffern zahl rest faktor) - (cond - ((numberp v) (float v)) - ((= (type v) 'STR) - (setq s (vl-string-translate "," "." (vl-string-trim " \t\r\n" v)) - i 1 ziffern "") - (while (and (<= i (strlen s)) - (setq c (substr s i 1)) - (or (wcmatch c "#") (member c '("." "-" "+")))) - (setq ziffern (strcat ziffern c) i (1+ i))) - (setq zahl (if (/= ziffern "") (distof ziffern 2)) - rest (strcase (vl-string-trim " \t" (substr s i))) - faktor (cdr (assoc rest '(("" . 1.0) ("MM" . 1.0) ("CM" . 10.0) ("DM" . 100.0) ("M" . 1000.0))))) - (if (and zahl faktor) (* zahl faktor))) - (T nil)) -) - -;; Reiner Kern: ein echter Blockname (nicht leer, nicht anonym "*U.."). -(defun lg-name-brauchbar-p (s) - (if (and (= (type s) 'STR) (/= s "") (/= (substr s 1 1) "*")) T) -) - -;; Objekteigenschaft lesen, nil wenn es sie nicht gibt. -(defun lg-prop (ent name / r) - (setq r (vl-catch-all-apply 'getpropertyvalue (list ent name))) - (if (vl-catch-all-error-p r) nil r) -) - -;; Name, unter dem eine Referenz gefuehrt wird: Objekteigenschaft -;; EffectiveName (auch fuer MCAD-Bloecke), sonst ActiveX-EffectiveName, -;; sonst DXF-Blockname. -(defun lg-rack-name (ent / n) - (cond - ((lg-name-brauchbar-p (setq n (lg-prop ent "EffectiveName"))) n) - (T (lg-blockname ent))) -) - -(defun lg-rack-p (ent / n) - (setq n (lg-rack-name ent)) - (and n (= (strcase n) (strcase *lg-rack-suchname*))) -) - -;; MCAD-Parameter (Kennung "~MCAD" in listallproperties, Gross-/ -;; Kleinschreibung egal). -(defun lg-mcad-param (ent name / props id soll) - (setq props (vl-catch-all-apply 'listallproperties (list ent)) - soll (strcase (strcat name "~MCAD"))) - (if (and (not (vl-catch-all-error-p props)) (listp props) - (setq id (vl-some '(lambda (p / s) - (setq s (vl-princ-to-string p)) - (if (= (strcase s) soll) s)) - props))) - (lg-prop ent id)) -) - -;; Dynamische Blockeigenschaft (AutoCAD-Dynamikbloecke). -(defun lg-dyn-param (ent name / r) - (setq r (vl-catch-all-apply - '(lambda ( / obj) - (setq obj (vlax-ename->vla-object ent)) - (if (and (vlax-property-available-p obj 'IsDynamicBlock) - (= :vlax-true (vla-get-IsDynamicBlock obj))) - (vl-some '(lambda (p) - (if (= (strcase (vla-get-PropertyName p)) (strcase name)) - (vlax-variant-value (vla-get-Value p)))) - (vlax-invoke obj 'GetDynamicBlockProperties)))))) - (if (vl-catch-all-error-p r) nil r) -) - -;; Parameterwert einer Referenz: MCAD-Parameter vor dynamischer -;; Eigenschaft vor Attribut vor konstanter ATTDEF-Vorgabe. -(defun lg-rack-param (ent name / w) - (cond - ((setq w (lg-mcad-param ent name)) w) - ((setq w (lg-dyn-param ent name)) w) - ((setq w (lg-wert-fuer-tag name (ssg-attrib-read ent))) w) - ((lg-wert-fuer-tag name - (mapcar '(lambda (ed) (cons (cdr (assoc 2 ed)) (cdr (assoc 1 ed)))) - (vl-remove-if-not '(lambda (ed) (= (cdr (assoc 0 ed)) "ATTDEF")) - (lg-blockdef-objekte (cdr (assoc 2 (entget ent)))))))) - ) -) - -;; --- Transformationen: tf = (ursprung x-achse y-achse z-achse), Achsen -;; mit Skalierung; p' = o + px*ax + py*ay + pz*az (rein, getestet) --- -(defun lg-v3 (p) (list (float (car p)) (float (cadr p)) (if (caddr p) (float (caddr p)) 0.0))) -(defun lg-v+ (a b) (mapcar '+ a b)) -(defun lg-v* (v k) (mapcar '(lambda (x) (* x k)) v)) -(defun lg-tf-id () '((0.0 0.0 0.0) (1.0 0.0 0.0) (0.0 1.0 0.0) (0.0 0.0 1.0))) -(defun lg-tf-vek (tf v / v3) - (setq v3 (lg-v3 v)) - (lg-v+ (lg-v* (nth 1 tf) (car v3)) (lg-v+ (lg-v* (nth 2 tf) (cadr v3)) (lg-v* (nth 3 tf) (caddr v3)))) -) -(defun lg-tf-pkt (tf p) (lg-v+ (car tf) (lg-tf-vek tf p))) -;; innen ist im System von aussen beschrieben -> Gesamttransformation -(defun lg-tf-verketten (aussen innen) - (list (lg-tf-pkt aussen (car innen)) (lg-tf-vek aussen (nth 1 innen)) - (lg-tf-vek aussen (nth 2 innen)) (lg-tf-vek aussen (nth 3 innen))) -) - -(defun lg-skal (s) (if (and s (not (equal s 0.0 1e-12))) s 1.0)) - -;; Transformation einer INSERT (entget-Liste) im System ihres Containers. -;; sp/zl = MINSERT-Spalte/-Zeile (0/0 = Basis). Beruecksichtigt Extrusion -;; (210), Drehung, Skalierung, Rasterabstaende (44/45, entlang der -;; gedrehten Achsen) und den Basispunkt der Blockdefinition. -(defun lg-insert-tf (ed sp zl / nor rot ax ay az xr yr o bp) - (setq nor (lg-v3 (cond ((cdr (assoc 210 ed))) ('(0.0 0.0 1.0)))) - rot (cond ((cdr (assoc 50 ed))) (0.0))) - (if (equal nor '(0.0 0.0 1.0) 1e-12) - (setq ax '(1.0 0.0 0.0) ay '(0.0 1.0 0.0) az '(0.0 0.0 1.0)) - (setq ax (lg-v3 (trans '(1.0 0.0 0.0) nor 0 T)) - ay (lg-v3 (trans '(0.0 1.0 0.0) nor 0 T)) - az (lg-v3 (trans '(0.0 0.0 1.0) nor 0 T)))) - (setq xr (lg-v+ (lg-v* ax (cos rot)) (lg-v* ay (sin rot))) - yr (lg-v+ (lg-v* ax (- (sin rot))) (lg-v* ay (cos rot))) - o (lg-tf-pkt (list '(0.0 0.0 0.0) ax ay az) (cdr (assoc 10 ed))) - o (lg-v+ o (lg-v+ (lg-v* xr (* sp (cond ((cdr (assoc 44 ed))) (0.0)))) - (lg-v* yr (* zl (cond ((cdr (assoc 45 ed))) (0.0))))))) - (setq xr (lg-v* xr (lg-skal (cdr (assoc 41 ed)))) - yr (lg-v* yr (lg-skal (cdr (assoc 42 ed)))) - az (lg-v* az (lg-skal (cdr (assoc 43 ed)))) - bp (lg-v3 (cond ((cdr (assoc 10 (tblsearch "BLOCK" (cdr (assoc 2 ed)))))) ('(0.0 0.0 0.0))))) - ;; der Basispunkt der Definition liegt auf dem Einfuegepunkt - (list (lg-v+ o (lg-v* (lg-tf-vek (list nil xr yr az) bp) -1.0)) xr yr az) -) - -;; Bounding-Box (min max) eines Objekts in den Koordinaten seines -;; Containers, nil wenn nicht ermittelbar. -(defun lg-bbox (ent / r) - (setq r (vl-catch-all-apply - '(lambda ( / ll ur) - (vla-GetBoundingBox (vlax-ename->vla-object ent) 'll 'ur) - (list (lg-v3 (vlax-safearray->list ll)) (lg-v3 (vlax-safearray->list ur)))))) - (if (vl-catch-all-error-p r) nil r) -) - -;; Enthaelt die Blockdefinition (rekursiv) ein Rack? Gemerkt in -;; *lg-rack-cache*, Zirkelschutz ueber *lg-rack-pfad*, XRefs ausgenommen. -(defun lg-rack-enthaelt-p (bname tiefe / k vorh def res) - (setq k (strcase bname)) - (cond - ((setq vorh (assoc k *lg-rack-cache*)) (cdr vorh)) - ((or (>= tiefe *lg-rack-max-tiefe*) (member k *lg-rack-pfad*)) nil) - (T - (setq def (tblsearch "BLOCK" bname) res nil) - (if (and def (= 0 (logand (cond ((cdr (assoc 70 def))) (0)) 4))) - (progn - (setq *lg-rack-pfad* (cons k *lg-rack-pfad*)) - (setq res (vl-some '(lambda (ed) - (if (= (cdr (assoc 0 ed)) "INSERT") - (or (lg-rack-p (cdr (assoc -1 ed))) - (lg-rack-enthaelt-p (cdr (assoc 2 ed)) (1+ tiefe))))) - (lg-blockdef-objekte bname))) - (setq *lg-rack-pfad* (cdr *lg-rack-pfad*)))) - (setq *lg-rack-cache* (cons (cons k res) *lg-rack-cache*)) - res)) -) - -;; Eine INSERT pruefen (inkl. MINSERT-Raster) bzw. in ihre Definition -;; absteigen. ptf = Transformation des Containers nach Welt. -(defun lg-rack-insert (ent ptf tiefe top / ed spalten zeilen raster sp zl ctf bb name laenge ebenen) - (setq ed (entget ent) - spalten (max 1 (cond ((cdr (assoc 70 ed))) (1))) - zeilen (max 1 (cond ((cdr (assoc 71 ed))) (1))) - raster (> (* spalten zeilen) 1)) - (cond - ((lg-rack-p ent) - (setq name (lg-rack-name ent) - laenge (lg-zahl-einheit (lg-rack-param ent *lg-rack-param-laenge*)) - ebenen (lg-zahl-einheit (lg-rack-param ent *lg-rack-param-ebenen*)) - bb (if (not raster) (lg-bbox ent)) - sp 0) - (repeat spalten - (setq zl 0) - (repeat zeilen - (setq *lg-racks* - (cons (list name laenge ebenen - (if bb - (lg-tf-pkt ptf (mapcar '(lambda (a b) (/ (+ a b) 2.0)) (car bb) (cadr bb))) - (car (lg-tf-verketten ptf (lg-insert-tf ed sp zl)))) - top) - *lg-racks*) - zl (1+ zl))) - (setq sp (1+ sp)))) - ((and (< tiefe *lg-rack-max-tiefe*) (lg-rack-enthaelt-p (cdr (assoc 2 ed)) 0)) - (setq sp 0) - (repeat spalten - (setq zl 0) - (repeat zeilen - (setq ctf (lg-tf-verketten ptf (lg-insert-tf ed sp zl))) - (foreach sub (lg-blockdef-objekte (cdr (assoc 2 ed))) - (if (= (cdr (assoc 0 sub)) "INSERT") - (lg-rack-insert (cdr (assoc -1 sub)) ctf (1+ tiefe) top))) - (setq zl (1+ zl))) - (setq sp (1+ sp)))) - ) -) - -;; Alle goh_racks im Modellbereich (Blockname/Parameter aus lager.json). -;; Rueckgabe: Liste (name laenge-mm ebenen mitte top-ent), Fundreihenfolge. -(defun lg-racks-sammeln ( / ) - (lg-racks-finden (lg-vorgabe '("goh_rack" "blockname") "goh_rack") - (lg-vorgabe '("goh_rack" "param_laenge") "Laenge") - (lg-vorgabe '("goh_rack" "param_ebenen") "Ebenen")) -) - -;; Wie lg-racks-sammeln, Blockname und Parameternamen als Argument. -(defun lg-racks-finden (name p-laenge p-ebenen / ss i) - (setq *lg-rack-suchname* name - *lg-rack-param-laenge* p-laenge - *lg-rack-param-ebenen* p-ebenen - *lg-racks* nil *lg-rack-cache* nil *lg-rack-pfad* nil) - (if (setq ss (ssget "_X" '((0 . "INSERT") (410 . "Model")))) - (progn - (setq i 0) - (repeat (sslength ss) - (lg-rack-insert (ssname ss i) (lg-tf-id) 0 (ssname ss i)) - (setq i (1+ i))))) - (reverse *lg-racks*) -) - -;; Reiner Kern: Racks je Geschoss zusammenfassen. eintraege = ((geschoss +;; Reiner Kern: Regalreihen je Geschoss zusammenfassen. eintraege = ((geschoss ;; laenge-mm ebenen) ...), geschoss nil = nicht zuordenbar, fehlende Laenge/ ;; Ebenen zaehlen 0. Rueckgabe ((geschoss anzahl summe-laenge ;; summe-laenge-x-ebenen) ...), nach Geschoss sortiert, nil zuletzt. -(defun lg-racks-auswerten (eintraege / erg vorh l k) +(defun lg-reihen-auswerten (eintraege / erg vorh l k) (setq erg nil) (foreach x eintraege (setq l (cond ((cadr x)) (0.0)) @@ -1693,30 +1434,39 @@ (vl-sort erg '(lambda (a b) (cond ((null (car a)) nil) ((null (car b)) T) (T (< (car a) (car b)))))) ) -;; Befehl LG_REGALE: goh_racks zaehlen, Anzahl, Laenge und Laenge x Ebenen -;; (Haengekapazitaet) je Geschoss in der Befehlszeile. -(defun c:LG_REGALE ( / kand racks zeilen ohne-laenge) - (setq kand (lg-geschoss-kandidaten) - racks (lg-racks-sammeln)) - (if (null racks) - (princ (ssg-textf "lg-regale-keine" (list (lg-vorgabe '("goh_rack" "blockname") "goh_rack")))) - (progn - (setq zeilen (lg-racks-auswerten - (mapcar '(lambda (r) (list (lg-rack-geschoss (lg-ent-layer (lg-rk-top r)) (lg-rk-mitte r) kand) - (lg-rk-laenge r) (lg-rk-ebenen r))) - racks)) - ohne-laenge (length (vl-remove-if 'lg-rk-laenge racks))) - (princ (ssg-text "lg-regale-kopf")) - (foreach z zeilen - (princ (ssg-textf "lg-regale-zeile" - (list (if (car z) (ssg-textf "lg-regale-geschoss" (list (itoa (car z)))) - (ssg-text "lg-regale-ohne-geschoss")) - (itoa (cadr z)) (rtos (/ (caddr z) 1000.0) 2 2) (rtos (/ (cadddr z) 1000.0) 2 2))))) - (princ (ssg-textf "lg-regale-zeile" - (list (ssg-text "lg-regale-summe") (itoa (length racks)) - (rtos (/ (apply '+ (mapcar 'caddr zeilen)) 1000.0) 2 2) - (rtos (/ (apply '+ (mapcar 'cadddr zeilen)) 1000.0) 2 2)))) - (if (> ohne-laenge 0) (princ (ssg-textf "lg-regale-ohne-laenge" (list (itoa ohne-laenge))))))) +;; Reiner Kern: Eintrag (geschoss laenge-mm ebenen) einer Regalreihe +;; (LG_REIHE_*) fuer lg-reihen-auswerten, aus ihren Attributen. Ebenen = +;; Anzahl der Haengeebenen in HAENGEEBENEN, Geschoss nil wenn nicht lesbar. +(defun lg-reihe-eintrag (a / gs) + (setq gs (lg-zahl (cdr (assoc "GESCHOSS" a)))) + (list (if gs (fix gs)) + (lg-zahl (cdr (assoc "LAENGE" a))) + (float (length (lg-haengeebenen-parse (cdr (assoc "HAENGEEBENEN" a)))))) +) + +;; Zeilen von lg-reihen-auswerten in der Befehlszeile ausgeben (Kopf, je +;; Geschoss eine Zeile, Summe). zeile-key: Textschluessel mit %1..%4. +(defun lg-regale-ausgeben (kopf-key zeile-key zeilen) + (princ (ssg-text kopf-key)) + (foreach z zeilen + (princ (ssg-textf zeile-key + (list (if (car z) (ssg-textf "lg-regale-geschoss" (list (itoa (car z)))) + (ssg-text "lg-regale-ohne-geschoss")) + (itoa (cadr z)) (rtos (/ (caddr z) 1000.0) 2 2) (rtos (/ (cadddr z) 1000.0) 2 2))))) + (princ (ssg-textf zeile-key + (list (ssg-text "lg-regale-summe") (itoa (apply '+ (mapcar 'cadr zeilen))) + (rtos (/ (apply '+ (mapcar 'caddr zeilen)) 1000.0) 2 2) + (rtos (/ (apply '+ (mapcar 'cadddr zeilen)) 1000.0) 2 2)))) +) + +;; Befehl LG_REGALE: Regalreihen (LG_REIHE_* aus LG_BEREICH/LG_REIHE) +;; zaehlen - je Geschoss Anzahl, Laenge und Laenge x Ebenen +;; (Haengekapazitaet) in der Befehlszeile. +(defun c:LG_REGALE ( / reihen) + (if (setq reihen (lg-alle-bloecke "LG_REIHE_*")) + (lg-regale-ausgeben "lg-regale-kopf" "lg-regale-zeile" + (lg-reihen-auswerten (mapcar '(lambda (e) (lg-reihe-eintrag (ssg-attrib-read e))) reihen))) + (princ (ssg-text "lg-regale-keine"))) (princ) ) @@ -1730,40 +1480,11 @@ ;; normalen Einfuegefunktionen NEU erzeugt (Layer, ID, Verknuepfung, ;; Blockname/Schraffur, ATTSYNC kommen von dort) - die Kinder 1:1 aus der ;; Quelle, ohne Neufuellen, damit Handaenderungen (auto_geaendert, manuelle -;; Reihen/Gaenge) erhalten bleiben. goh_rack-Bloecke (parametrisch) werden -;; per vla-Copy kopiert und auf den Regal-Layer des Zielgeschosses gelegt. +;; Reihen/Gaenge) erhalten bleiben. ;; Die Kopie liegt deckungsgleich (2D uebereinander), optional je Kopie um ;; (dx dy) versetzt; in einer 3D-Zeichnung (Konturen auf Belagshoehe) ;; zusaetzlich in Z um den Hoehenabstand. -;; Layer eines Objekts oder nil. -(defun lg-ent-layer (ent / ed) - (if (and ent (setq ed (entget ent))) (cdr (assoc 8 ed))) -) - -;; Reiner Kern: Geschossnummer aus einem Lager-Layer "LG__G" -;; (Muster wie lg-geschoss-aktivieren), sonst nil. -(defun lg-geschoss-aus-layer (name / s p rest) - (if (and (= (type name) 'STR) (wcmatch (setq s (strcase name)) "LG_*_G#*")) - (progn - (setq p (vl-string-position (ascii "_") s nil T) - rest (substr s (+ p 2))) - (if (and (> (strlen rest) 1) (= (substr rest 1 1) "G") - (vl-every '(lambda (c) (<= 48 c 57)) (vl-string->list (substr rest 2)))) - (atoi (substr rest 2))))) -) - -;; Reiner Kern: Geschoss eines goh_rack. Ein Lager-Layer _G eines -;; vorhandenen Geschosses entscheidet (eindeutig auch bei 2D-Geschossen -;; uebereinander), sonst die Kontur (lg-geschoss-fuer-punkt-kern). -;; kandidaten = ((nr hoehe-mm kontur-punkte) ...) -(defun lg-rack-geschoss (layer pt kandidaten / n) - (setq n (lg-geschoss-aus-layer layer)) - (if (and n (assoc n kandidaten)) - n - (lg-geschoss-fuer-punkt-kern pt kandidaten)) -) - ;; Reiner Kern: Belag eines kopierten Bereichs/Gangs. Entsprach er dem ;; Geschossbelag der Quelle, folgt er dem neuen Geschossbelag; bewusst ;; abweichende (z.B. Gitterrost-Gang auf Spanplatte-Buehne) bleiben. @@ -1847,59 +1568,9 @@ (if (setq neu (lg-kontur-kopieren ent)) (lg-ent-verschieben neu v)) ) -;; goh_rack-Bloecke des Geschosses src als oberste INSERTs im Modellbereich -;; (ein Array mit Racks zaehlt als ein Objekt). Vor der ersten Kopie -;; aufrufen: danach waere die Kontur-Zuordnung deckungsgleicher Geschosse -;; mehrdeutig. Rueckgabe: (racks anzahl-mehrdeutig) -(defun lg-racks-der-quelle (src kandidaten / src-pts racks mehrdeutig top gs) - (setq racks nil mehrdeutig nil - src-pts (caddr (assoc src kandidaten))) - (foreach r (lg-racks-sammeln) - (setq top (lg-rk-top r) - gs (lg-rack-geschoss (lg-ent-layer top) (lg-rk-mitte r) kandidaten)) - (cond - ((and gs (= gs src)) - (if (not (member top racks)) (setq racks (cons top racks)))) - ((and (null gs) src-pts (ssg-punkt-in-poly-p (lg-rk-mitte r) src-pts)) - (if (not (member top mehrdeutig)) (setq mehrdeutig (cons top mehrdeutig)))))) - (list (reverse racks) - (length (vl-remove-if '(lambda (m) (member m racks)) mehrdeutig))) -) - -;; Racks der Quelle ohne Lager-Layer auf den Regal-Layer der Quelle legen - -;; nach der Kopie liegen sie deckungsgleich mit den Kopien, nur der Layer -;; trennt sie dann (Export, LG_GESCHOSS_AKTIV). Rueckgabe: Anzahl. -(defun lg-racks-umhaengen (racks src / lay n) - (setq n 0) - (foreach r racks - (if (null (lg-geschoss-aus-layer (lg-ent-layer r))) - (progn - (if (null lay) (setq lay (lg-layer "goh_rack" src))) - (vla-put-Layer (vlax-ename->vla-object r) lay) - (setq n (1+ n))))) - n -) - -;; Racks per vla-Copy (MCAD-Parameter bleiben) um v versetzt ins Geschoss -;; nr kopieren. Rueckgabe: Anzahl. -(defun lg-racks-kopieren (racks nr v / lay n res) - (setq n 0 lay (if racks (lg-layer "goh_rack" nr))) - (foreach r racks - (setq res (vl-catch-all-apply - '(lambda ( / obj) - (setq obj (vla-Copy (vlax-ename->vla-object r))) - (vla-Move obj (vlax-3d-point '(0.0 0.0 0.0)) (vlax-3d-point v)) - (vla-put-Layer obj lay) - T))) - (if (vl-catch-all-error-p res) - (princ (ssg-textf "lg-einfuegen-fehler" (list (lg-blockname r) (vl-catch-all-error-message res)))) - (setq n (1+ n)))) - n -) - ;; Eine Kopie des Geschosses src-nr als Geschoss nr auf hoehe, um v versetzt. -;; Rueckgabe: (geschoss-ent reihen gaenge racks) oder nil. -(defun lg-geschoss-kopieren (src-nr nr hoehe belag-neu v racks +;; Rueckgabe: (geschoss-ent reihen gaenge) oder nil. +(defun lg-geschoss-kopieren (src-nr nr hoehe belag-neu v / src a belag-alt k werte blk zuordnung kk nb ab ed p1 p2 rot laenge nb-h art n-reihen n-gaenge s-gs) (setq src (lg-geschoss-finden src-nr) @@ -1961,8 +1632,7 @@ belag-alt belag-neu) nb) (if (= art "reihe") (setq n-reihen (1+ n-reihen)) (setq n-gaenge (1+ n-gaenge))))))) - ;; 4. goh_rack - (list blk n-reihen n-gaenge (lg-racks-kopieren racks nr v)))) + (list blk n-reihen n-gaenge))) ) ) ) @@ -1971,7 +1641,7 @@ ;; VERSATZ_X_mm VERSATZ_Y_mm), nicht interaktiv - auch fuer Tests. ;; Rueckgabe: Liste der neuen Geschossnummern oder nil. (defun lg-geschosse-kopieren (werte / src-nr src n abstand belag dx dy kandidaten - rq racks nr erg neu) + nr erg neu) (setq src-nr (atoi (cond ((cdr (assoc "QUELLE" werte))) ("0"))) src (lg-geschoss-finden src-nr) n (atoi (cond ((cdr (assoc "ANZAHL" werte))) ("1"))) @@ -1985,23 +1655,17 @@ ((< n 1) nil) (T (setq kandidaten (lg-geschoss-kandidaten)) - ;; Racks VOR der ersten Kopie bestimmen (danach waere die Kontur mehrdeutig) - (setq rq (lg-racks-der-quelle src-nr kandidaten) - racks (car rq)) - (if (> (cadr rq) 0) (princ (ssg-textf "lg-kopie-racks-mehrdeutig" (list (itoa (cadr rq)))))) - (if (> (setq neu (lg-racks-umhaengen racks src-nr)) 0) - (princ (ssg-textf "lg-kopie-racks-umgehaengt" (list (itoa neu) (itoa src-nr))))) (setq erg nil) (foreach p (lg-kopie-plan (lg-geschoss-hoehe src) abstand n dx dy (lg-kopie-3d-p kandidaten)) (if (vl-some '(lambda (k) (equal (cadr k) (cadr p) 1.0)) (lg-geschoss-kandidaten)) (princ (ssg-textf "lg-kopie-hoehe-belegt" (list (lg-mm-str (cadr p)))))) (setq nr (lg-geschoss-naechste-nr)) - (if (setq neu (lg-geschoss-kopieren src-nr nr (cadr p) belag (caddr p) racks)) + (if (setq neu (lg-geschoss-kopieren src-nr nr (cadr p) belag (caddr p))) (progn (setq erg (cons nr erg)) (princ (ssg-textf "lg-kopie-fertig" (list (itoa src-nr) (itoa nr) (lg-mm-str (cadr p)) - (itoa (cadr neu)) (itoa (caddr neu)) (itoa (cadddr neu)))))))) + (itoa (cadr neu)) (itoa (caddr neu)))))))) (if erg (progn (lg-ldata-setzen "GESCHOSS_AKTIV" (car erg)) @@ -2061,7 +1725,7 @@ (entmod (subst (cons 70 f) (assoc 70 ed) ed)))) ) -;; Geschoss mit Belag, Bereichen, Reihen, Gaengen und goh_racks in ein oder +;; Geschoss mit Belag, Bereichen, Reihen und Gaengen in ein oder ;; mehrere neue Geschosse kopieren (siehe lg-geschosse-kopieren). (defun c:LG_GESCHOSS_KOPIEREN ( / werte) (ssg-start (ssg-text "lg-titel-kopie") nil) @@ -2472,41 +2136,9 @@ (cons "handle" (lg-handle e))))) ) -;; goh_rack-Bloecke sammeln (lg-racks-sammeln). Geschoss ueber den Layer -;; des obersten INSERTs (_G), sonst ueber die Kontur (lg-rack-geschoss). -;; Rueckgabe: (json-texte warnungen) -(defun lg-export-goh-racks (kandidaten / texte warn gs ebenen vorgabe) - (setq texte nil warn nil - vorgabe (lg-vorgabe '("reihe" "haengeebenen") "2300/1200;1100/1100")) - (foreach r (lg-racks-sammeln) - (setq gs (lg-rack-geschoss (lg-ent-layer (lg-rk-top r)) (lg-rk-mitte r) kandidaten)) - (if (and (null gs) kandidaten) - (setq warn (cons (ssg-textf "lg-exp-rack-ohne-geschoss" - (list (rtos (car (lg-rk-mitte r)) 2 0) (rtos (cadr (lg-rk-mitte r)) 2 0))) - warn))) - (setq ebenen (if (lg-rk-ebenen r) (fix (lg-rk-ebenen r)))) - (if (null (lg-rk-laenge r)) - (setq warn (cons (ssg-textf "lg-exp-rack-ohne-laenge" (list (lg-rk-name r))) warn))) - (setq texte (cons - (lg-json-obj - (list (cons "geschoss" gs) - (cons "name" (lg-rk-name r)) - (cons "laenge_mm" (lg-rk-laenge r)) - (cons "ebenen" ebenen) - (cons "tiefe_mm" (lg-zahl (lg-vorgabe '("goh_rack" "tiefe_mm") 700))) - (cons "haengeebenen" (lg-json-ebenen (if ebenen (lg-haengeebenen-n vorgabe ebenen) vorgabe))) - (cons "haengeebenen_quelle" "vorgabe") - (cons "position" (lg-json-zahlen (lg-rk-mitte r))))) - texte))) - (list (reverse texte) (reverse warn)) -) - ;; Alle Daten als JSON-Text. -(defun lg-export-json ( / gs kandidaten racks warn gs-ohne) - (setq gs (lg-geschosse) - kandidaten (lg-geschoss-kandidaten) - racks (lg-export-goh-racks kandidaten) - warn (cadr racks)) +(defun lg-export-json ( / gs warn) + (setq gs (lg-geschosse) warn nil) (if (null gs) (setq warn (cons (ssg-text "lg-exp-keine-geschosse") warn))) (foreach g gs (if (null (cadddr g)) @@ -2526,7 +2158,6 @@ " \"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" - " \"goh_racks\": " (lg-json-arr (car racks) " ") ",\n" " \"warnungen\": " (lg-json-arr (mapcar 'lg-json-wert warn) " ") "\n" "}\n") ) diff --git a/Lisp/README.md b/Lisp/README.md index 2438660..8a5d093 100644 --- a/Lisp/README.md +++ b/Lisp/README.md @@ -879,12 +879,12 @@ Mengen gehen ueber `LAGER_EXPORT` als Overlay-YAML an das RFQ-Programm | --- | --- | | `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` der anderen Geschosse frieren (0 = alle zeigen) | -| `c:LG_GESCHOSS_KOPIEREN` | Geschoss mit Belagskontur, Bereichen, Reihen, Gaengen und goh_racks 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` und IDs sind neu | +| `c:LG_GESCHOSS_KOPIEREN` | Geschoss mit Belagskontur, Bereichen, Reihen und Gaengen 1:1 in ein oder mehrere neue Geschosse kopieren (Dialog `lg_geschoss_kopie`: Quelle - Vorgabe oberstes Geschoss -, Anzahl, Geschosshoehe je Kopie, Belag, Versatz X/Y je Kopie, 0 = deckungsgleich). Belaege gleich dem Quell-Geschossbelag folgen dem neuen Belag; Verknuepfungen, Layer `_G` und IDs sind neu | | `c:LG_BEREICH` | Lagerbereich-Kontur + Dialog `lg_bereich`; Auto-Fuellung mit `LG_REIHE__` / `LG_GANG___`, optional Randgaenge Nord/Ost/Sued/West entlang der Konturkanten (auch L-Form) | | `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` | goh_racks zaehlen (`lg-racks-sammeln`): Anzahl, Laenge und Laenge x Ebenen je Geschoss (Zuordnung wie beim Export) plus Gesamtsumme in der Befehlszeile | +| `c:LG_REGALE` | Regalreihen `LG_REIHE_*` zaehlen (`lg-reihe-eintrag` + `lg-reihen-auswerten`): Anzahl, Laenge und Laenge x Haengeebenen je Geschoss plus Gesamtsumme in der Befehlszeile | | `c:LAGER_EXPORT` | `_lager_raw.json` + Python -> `_drawing.yaml` und `_nachweis.html` in `DXFM_RESULTS` | | `c:LAGER_HAND_YAML` | Hand-YAML fuer den Abgleich (Konfliktliste) festlegen | | `c:LG_REGELN` | Regelprofil (`cfg/regelwerk/.json`) mit aufgeloesten Werten und Quellen anzeigen | @@ -894,21 +894,13 @@ Gangflaechen sind je Belag schraffiert (Schraffur in der Blockdefinition, Muster Hallenboden keine). Reine Kerne (`lg-fuellung-berechnen`, `lg-randgang-streifen`, `lg-kompass`, -`lg-schraffur-vorgabe`, `lg-geschoss-fuer-punkt-kern`, `lg-geschoss-aus-layer`, -`lg-rack-geschoss`, `lg-kopie-*`, `lg-zahl-einheit`, `lg-insert-tf`/`lg-tf-verketten`, -`lg-regel-aufloesen`, `lg-profil-mischen`, JSON-Schreiber, Feldpruefung) in +`lg-schraffur-vorgabe`, `lg-geschoss-fuer-punkt-kern`, `lg-kopie-*`, +`lg-reihe-eintrag`/`lg-reihen-auswerten`, `lg-regel-aufloesen`, `lg-profil-mischen`, JSON-Schreiber, Feldpruefung) in `tests/test_unit.lsp` (`tu-tests-lager`); Zeichnungsablauf in -`tests/test_lager.lsp` (`TEST_LAGER`, inkl. Rack-Erkennung mit Verschachtelung und -MINSERT sowie goh_rack-Regression gegen `tests/testdata/goh_storage_test.dwg`). +`tests/test_lager.lsp` (`TEST_LAGER`). -`goh_rack`-Bloecke (parametrischer BricsCAD-Block) erkennt und zaehlt `LagerInsert.lsp` -selbst (`lg-racks-sammeln`): Name ueber die Objekteigenschaft `EffectiveName`, -Parameter `Laenge`/`Ebenen` (`lager.json` `goh_rack`) als MCAD-Eigenschaft, dynamische -Eigenschaft, Attribut oder ATTDEF-Vorgabe, Einheiten auf mm umgerechnet; gefunden auch -in assoziativen Arrays, MINSERT-Rastern und verschachtelten Bloecken. `LAGER_EXPORT` -ordnet jedes goh_rack zuerst ueber den Layer `LG_*_G` seines obersten INSERTs -(`lg-rk-top`), erst dann ueber die Geschosskontur zu. `LG_REGALE` zeigt die Zaehlung -je Geschoss in der Befehlszeile. +Der parametrische BricsCAD-Block `goh_rack` wird nicht mehr unterstuetzt (veraltet): +Regale entstehen nur noch als `LG_REIHE_*` ueber `LG_BEREICH`/`LG_REIHE`. --- diff --git a/cfg/layer.cfg b/cfg/layer.cfg index a90399b..da7db81 100644 --- a/cfg/layer.cfg +++ b/cfg/layer.cfg @@ -188,7 +188,6 @@ geschoss = LG_Geschoss, 7 bereich = LG_Bereich, 4 reihe = LG_Reihe, 3 gang = LG_Gang, 8 -goh_rack = LG_Regal, 3 # ============================================================ diff --git a/data/json/lager.json b/data/json/lager.json index 80b1492..31ced3a 100644 --- a/data/json/lager.json +++ b/data/json/lager.json @@ -3,14 +3,6 @@ "beschreibung": "Vorgaben fuer die Lagerplanung (LagerInsert.lsp). Alle Masse in mm, Winkel in Grad. Die Werte belegen die Dialoge vor; was im Dialog bzw. am Block steht, gewinnt.", "land": "DE", - "goh_rack": { - "beschreibung": "Parametrischer BricsCAD-Block, der als Regalreihe mitgezaehlt wird (lg-racks-sammeln in LagerInsert.lsp). param_laenge/param_ebenen = Namen der MCAD-Parameter.", - "blockname": "goh_rack", - "param_laenge": "Laenge", - "param_ebenen": "Ebenen", - "tiefe_mm": 700 - }, - "geschoss": { "konstr_hoehe_mm": 250, "personen": 20, diff --git a/dcl/lager.dcl b/dcl/lager.dcl index df05e72..f21d286 100644 --- a/dcl/lager.dcl +++ b/dcl/lager.dcl @@ -96,7 +96,7 @@ lg_geschoss_kopie : dialog { : edit_box { key = "versatz_y"; label = "Y:"; edit_width = 10; } } } - : text { label = "Kopiert Belag, Bereiche, Reihen, Gaenge und goh_rack 1:1."; } + : text { label = "Kopiert Belag, Bereiche, Reihen und Gaenge 1:1."; } : text { label = "Belaege gleich dem Quell-Geschossbelag folgen dem neuen Belag."; } } ok_cancel; diff --git a/lang/de_DE.json b/lang/de_DE.json index e56e22b..a233cc6 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -1236,17 +1236,14 @@ "lg-feld-versatz_y": "\nVersatz Y je Kopie (mm, 0 = deckungsgleich)", "lg-kopie-abstand-ungueltig": "\n[Lager] Geschosshoehe je Kopie muss groesser 0 sein - nichts kopiert.", "lg-kopie-hoehe-belegt": "\n[Lager] Auf Belagshoehe %1 mm liegt bereits ein Geschoss - Kopie wird trotzdem angelegt.", - "lg-kopie-racks-mehrdeutig": "\n[Lager] %1 goh_rack ohne eindeutiges Geschoss (Konturen uebereinander, kein Layer _G) - nicht kopiert.", - "lg-kopie-racks-umgehaengt": "\n%1 goh_rack auf den Regal-Layer von Geschoss %2 gelegt (Zuordnung bei deckungsgleichen Geschossen).", - "lg-kopie-fertig": "\nGeschoss %1 kopiert -> Geschoss %2 auf %3 mm: %4 Regalreihe(n), %5 Gang-/Quergangflaeche(n), %6 goh_rack.", + "lg-kopie-fertig": "\nGeschoss %1 kopiert -> Geschoss %2 auf %3 mm: %4 Regalreihe(n), %5 Gang-/Quergangflaeche(n).", "lg-kopie-hinweis-aktiv": "\nLetzte Kopie ist aktives Geschoss. Anzeige umschalten mit LG_GESCHOSS_AKTIV.", - "lg-regale-keine": "\n[Lager] Keine Bloecke %1 im Modellbereich gefunden.", - "lg-regale-kopf": "\nRegale (goh_rack) je Geschoss: Anzahl, Laenge, Laenge x Ebenen", - "lg-regale-zeile": "\n %1: %2 Regal(e), %3 m, %4 m", + "lg-regale-keine": "\n[Lager] Keine Regalreihen (LG_REIHE) in der Zeichnung gefunden.", + "lg-regale-kopf": "\nRegalreihen (LG_REIHE) je Geschoss: Anzahl, Laenge, Laenge x Ebenen", + "lg-regale-zeile": "\n %1: %2 Reihe(n), %3 m, %4 m", "lg-regale-geschoss": "Geschoss %1", "lg-regale-ohne-geschoss": "ohne Geschoss", "lg-regale-summe": "Gesamt", - "lg-regale-ohne-laenge": "\n[Lager] %1 Regal(e) ohne lesbare Laenge - mit 0 gezaehlt.", "lg-titel-geschoss": "Lager: Geschoss anlegen", "lg-titel-bereich": "Lager: Lagerbereich anlegen", "lg-titel-reihe": "Lager: Regalreihen einfuegen", @@ -1275,8 +1272,6 @@ "lg-reihen-eingefuegt": "\n%1 Regalreihe(n) eingefuegt.", "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-rack-ohne-geschoss": "goh_rack bei X=%1 Y=%2 keinem Geschoss eindeutig zuzuordnen.", - "lg-exp-rack-ohne-laenge": "goh_rack %1 ohne lesbare Laenge.", "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", diff --git a/lang/en_GB.json b/lang/en_GB.json index 9497ff7..624ec78 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -1236,17 +1236,14 @@ "lg-feld-versatz_y": "\nOffset Y per copy (mm, 0 = congruent)", "lg-kopie-abstand-ungueltig": "\n[Storage] Level height per copy must be greater than 0 - nothing copied.", "lg-kopie-hoehe-belegt": "\n[Storage] A level already exists at floor height %1 mm - copy is created anyway.", - "lg-kopie-racks-mehrdeutig": "\n[Storage] %1 goh_rack without a unique level (stacked contours, no layer _G) - not copied.", - "lg-kopie-racks-umgehaengt": "\n%1 goh_rack moved to the rack layer of level %2 (assignment for congruent levels).", - "lg-kopie-fertig": "\nLevel %1 copied -> level %2 at %3 mm: %4 rack row(s), %5 aisle/cross aisle area(s), %6 goh_rack.", + "lg-kopie-fertig": "\nLevel %1 copied -> level %2 at %3 mm: %4 rack row(s), %5 aisle/cross aisle area(s).", "lg-kopie-hinweis-aktiv": "\nLast copy is the active level. Switch the display with LG_GESCHOSS_AKTIV.", - "lg-regale-keine": "\n[Storage] No %1 blocks found in model space.", - "lg-regale-kopf": "\nRacks (goh_rack) per level: count, length, length x levels", - "lg-regale-zeile": "\n %1: %2 rack(s), %3 m, %4 m", + "lg-regale-keine": "\n[Storage] No rack rows (LG_REIHE) found in the drawing.", + "lg-regale-kopf": "\nRack rows (LG_REIHE) per level: count, length, length x levels", + "lg-regale-zeile": "\n %1: %2 row(s), %3 m, %4 m", "lg-regale-geschoss": "Level %1", "lg-regale-ohne-geschoss": "no level", "lg-regale-summe": "Total", - "lg-regale-ohne-laenge": "\n[Storage] %1 rack(s) without readable length - counted as 0.", "lg-titel-geschoss": "Storage: create level", "lg-titel-bereich": "Storage: create storage area", "lg-titel-reihe": "Storage: insert rack rows", @@ -1275,8 +1272,6 @@ "lg-reihen-eingefuegt": "\n%1 rack row(s) inserted.", "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-rack-ohne-geschoss": "goh_rack at X=%1 Y=%2 cannot be assigned to a level.", - "lg-exp-rack-ohne-laenge": "goh_rack %1 without readable length.", "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", diff --git a/lib/lager_yaml_export.py b/lib/lager_yaml_export.py index 2543dc1..8f5a2a3 100644 --- a/lib/lager_yaml_export.py +++ b/lib/lager_yaml_export.py @@ -121,12 +121,8 @@ def aggregiere(raw): 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 []) - racks = raw.get("goh_racks") or [] gaenge = raw.get("gaenge") or [] - # goh_rack-Bloecke zaehlen wie Regalreihen (Herkunft wird mitgefuehrt) - for r in racks: - alle_reihen.append(dict(r, quelle="goh_rack")) 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)) @@ -226,11 +222,9 @@ def aggregiere(raw): hl = _haengeebenen(reihen) if hl: lv["hanging_levels"] = hl - n_rack = sum(1 for r in reihen if r.get("quelle") == "goh_rack") 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 (davon %d goh_rack, Haengeebenen aus Vorgabe)" - % (len(reihen), nr, n_rack), + "%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"])) diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index dcc5ea0..bd3f31b 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -688,7 +688,7 @@ - Regale zaehlen (goh_rack) + Regale zaehlen ^C^C(ssg-ensure "LagerInsert") LG_REGALE @@ -1782,7 +1782,7 @@ - Regale zaehlen (goh_rack) + Regale zaehlen diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 6bd94a5..896026e 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -147,7 +147,7 @@ [Gaenge einzeln]^C^C(ssg-ensure "LagerInsert") LG_GANG [Bearbeiten]^C^C(ssg-ensure "LagerInsert") LG_EDIT [--] -[Regale zaehlen (goh_rack)]^C^C(ssg-ensure "LagerInsert") LG_REGALE +[Regale zaehlen]^C^C(ssg-ensure "LagerInsert") LG_REGALE [Regelprofil anzeigen]^C^C(ssg-ensure "LagerPruefung") LG_REGELN [Hand-YAML fuer Abgleich]^C^C(ssg-ensure "LagerInsert") LAGER_HAND_YAML [<-Export RFQ-YAML]^C^C(ssg-ensure "LagerInsert") LAGER_EXPORT diff --git a/tests/test_lager.lsp b/tests/test_lager.lsp index 81ecb27..cd3923b 100644 --- a/tests/test_lager.lsp +++ b/tests/test_lager.lsp @@ -5,10 +5,8 @@ ;; - 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 und die Rohdaten von LAGER_EXPORT. -;; Zum Schluss Regression der goh_rack-Erkennung (lg-racks-sammeln) gegen -;; tests/testdata/goh_storage_test.dwg (Referenzwerte aus -;; goh_storage_test_regal_report.txt: 38946.39 mm / 77892.78 mm). +;; den Neuaufbau einer geaenderten Reihe, die Rohdaten von LAGER_EXPORT und +;; die Zaehlung von LG_REGALE. ;; ;; Aufruf in BricsCAD: ;; (load (strcat (getenv "DXFMAKRO") "/tests/test_lager.lsp")) @@ -83,8 +81,8 @@ (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 - racks laengen kap tr kb2 b2 kinder mg mg2 hg alt eb - r1 gg1 n-alt g2 r2 gg2 ids b2k n-kinder bb gr rg grp rk kand zl + 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) (setvar "CMDECHO" 0) (ssg-gui-aus) @@ -366,88 +364,14 @@ (tlg-eq "rechteck-befehl: fase abgelehnt" 'kein-rechteck (lg-rechteck-ecken-aus-poly (entlast))) (entdel (entlast)) - ;; --- Rack-Erkennung: direkt, verschachtelt + gedreht, MINSERT --- - ;; eigener Testblock (Parameter als Attribut bzw. ATTDEF-Vorgabe), damit - ;; die Suche nach goh_rack davon unberuehrt bleibt - (lg-blockdef "TLG_RACK" (list (lg-geom-linie '(0.0 0.0 0.0) '(1000.0 0.0 0.0)) - (lg-geom-attdef "Laenge" "500" '(0.0 0.0 0.0) 50.0 nil) - (lg-geom-attdef "Ebenen" "3" '(0.0 0.0 0.0) 50.0 nil))) - (lg-blockdef "TLG_GRUPPE" (list '((0 . "INSERT") (8 . "0") (2 . "TLG_RACK") (10 0.0 0.0 0.0)) - '((0 . "INSERT") (8 . "0") (2 . "TLG_RACK") (10 0.0 2000.0 0.0)))) - (lg-block-einfuegen "TLG_RACK" '(-100000.0 0.0 0.0) 0.0 "0" '(("Laenge" . "100 cm") ("Ebenen" . "2"))) - (setq grp (lg-block-einfuegen "TLG_GRUPPE" '(-200000.0 0.0 0.0) (/ pi 2.0) "0" nil)) - (vla-AddMInsertBlock (lg-modelspace) (vlax-3d-point '(-300000.0 0.0 0.0)) "TLG_RACK" - 1.0 1.0 1.0 0.0 1 3 1000.0 3000.0) - (setq rk (lg-racks-finden "TLG_RACK" "Laenge" "Ebenen")) - (tlg-eq "racks: anzahl" 6 (length rk)) - (tlg-eq "racks: laenge (attribut mit einheit + vorgaben)" 3500.0 - (apply '+ (mapcar '(lambda (r) (cond ((lg-rk-laenge r)) (0.0))) rk))) - (tlg-eq "racks: ebenen" 17.0 (apply '+ (mapcar '(lambda (r) (cond ((lg-rk-ebenen r)) (0.0))) rk))) - (tlg-eq "racks: verschachtelt top" 2 - (length (vl-remove-if-not '(lambda (r) (equal (lg-rk-top r) grp)) rk))) - ;; Gruppe um 90 Grad gedreht: zweites Rack (lokal y = 2000) liegt bei x = -202000 - (tlg-eq "racks: verschachtelt gedreht" T - (equal (vl-sort (mapcar '(lambda (r) (car (lg-rk-mitte r))) - (vl-remove-if-not '(lambda (r) (equal (lg-rk-top r) grp)) rk)) - '<) - '(-202000.0 -200000.0) 100.0)) - ;; MINSERT 1 Zeile x 3 Spalten, Abstand 3000: Mitten = Einfuegepunkte - (tlg-eq "racks: minsert" '(-300000.0 -297000.0 -294000.0) - (vl-sort (mapcar '(lambda (r) (car (lg-rk-mitte r))) - (vl-remove-if-not '(lambda (r) (< (car (lg-rk-mitte r)) -250000.0)) rk)) - '<)) - - ;; --- goh_rack-Regression (Referenzwerte goh_storage_test_regal_report.txt) --- - (setq pfad (strcat (getenv "DXFMAKRO") "/tests/testdata/goh_storage_test.dwg")) - (if (findfile pfad) - (progn - ;; "*" = aufgeloest einfuegen: die goh_rack-Bloecke liegen danach - ;; direkt im Modellbereich wie in der Originalzeichnung - (command "_.-INSERT" (strcat "*" pfad) '(50000.0 0.0 0.0) 1 0) - (setq racks (lg-export-goh-racks nil)) - (tlg-eq "goh_rack anzahl" 4 (length (car racks))) - (setq laengen (tlg-summe (car racks) "laenge_mm")) - (setq kap 0.0) - (foreach t1 (car racks) - (setq tr (ssg-json-parse t1)) - (setq kap (+ kap (* (ssg-json-get tr "laenge_mm") (ssg-json-get tr "ebenen"))))) - (tlg-eq "goh_rack laenge gesamt" T (equal laengen 38946.39 0.1)) - (tlg-eq "goh_rack laenge x ebenen" T (equal kap 77892.78 0.1)) - (princ (strcat "\n goh_rack: " (rtos laengen 2 2) " mm / " (rtos kap 2 2) " mm")) - - ;; --- Geschoss mit goh_racks kopieren (deckungsgleich, 2D) --- - ;; Geschosskontur um die Racks legen (Mitten aus lg-racks-sammeln + Rand) - (setq bb (ssg-poly-bbox (mapcar '(lambda (p) (list (car p) (cadr p))) - (mapcar 'lg-rk-mitte (lg-racks-sammeln))))) - (setq gr (lg-geschoss-naechste-nr)) - (lg-geschoss-anlegen (tlg-rechteck (- (car (car bb)) 20000.0) (- (cadr (car bb)) 20000.0) - (+ (car (cadr bb)) 20000.0) (+ (cadr (cadr bb)) 20000.0)) - (append (list (cons "HOEHE_BELAG_mm" "20000")) (lg-geschoss-vorgaben gr))) - (setq neu (lg-geschosse-kopieren (list (cons "QUELLE" (itoa gr)) (cons "ANZAHL" "1") - (cons "ABSTAND_mm" "3000") (cons "BELAG_ART" "spanplatte")))) - (setq racks (lg-export-goh-racks (lg-geschoss-kandidaten))) - (tlg-eq "rack-kopie: anzahl" 8 (length (car racks))) - (tlg-eq "rack-kopie: quelle" 4 - (length (vl-remove-if-not '(lambda (t1) (equal (ssg-json-get (ssg-json-parse t1) "geschoss") gr)) - (car racks)))) - (tlg-eq "rack-kopie: kopie" 4 - (length (vl-remove-if-not '(lambda (t1) (equal (ssg-json-get (ssg-json-parse t1) "geschoss") (car neu))) - (car racks)))) - (tlg-eq "rack-kopie: keine warnung" nil (cadr racks)) - (tlg-eq "rack-kopie: laenge kopie" T - (equal (tlg-summe (car racks) "laenge_mm") (* 2 38946.39) 0.2)) - (tlg-eq "rack-kopie: layer" T (if (tblsearch "LAYER" (strcat "LG_Regal_G" (itoa (car neu)))) T nil)) - ;; Auswertung je Geschoss wie LG_REGALE: je 4 Racks in Quelle und Kopie - (setq kand (lg-geschoss-kandidaten)) - (setq zl (lg-racks-auswerten - (mapcar '(lambda (r) (list (lg-rack-geschoss (lg-ent-layer (lg-rk-top r)) (lg-rk-mitte r) kand) - (lg-rk-laenge r) (lg-rk-ebenen r))) - (lg-racks-sammeln)))) - (tlg-eq "lg_regale: geschosse" (list gr (car neu)) (mapcar 'car zl)) - (tlg-eq "lg_regale: anzahl" '(4 4) (mapcar 'cadr zl)) - (tlg-eq "lg_regale: laenge x ebenen" T (equal (cadddr (car zl)) 77892.78 0.2)) - (tlg-eq "lg_regale: befehl laeuft" nil (vl-catch-all-error-p (vl-catch-all-apply 'c:LG_REGALE nil)))) - (tlg-eq "goh_storage_test.dwg vorhanden" T nil)) + ;; --- LG_REGALE: zaehlt die Regalreihen aus den Makros (LG_REIHE_*) je Geschoss --- + (setq zl (lg-reihen-auswerten (mapcar '(lambda (e) (lg-reihe-eintrag (ssg-attrib-read e))) + (lg-alle-bloecke "LG_REIHE_*")))) + (tlg-eq "lg_regale: reihen gezaehlt" (length (lg-alle-bloecke "LG_REIHE_*")) + (apply '+ (mapcar 'cadr zl))) + (tlg-eq "lg_regale: reihen vorhanden" T (> (apply '+ (mapcar 'cadr zl)) 0)) + (tlg-eq "lg_regale: reihen mit geschoss" nil (assoc nil zl)) + (tlg-eq "lg_regale: befehl laeuft (reihen)" nil (vl-catch-all-error-p (vl-catch-all-apply 'c:LG_REGALE nil))) ;; --- Von Hand Gesetztes bleibt: Einfuegen loest keine Neuberechnung aus --- (setq kb (tlg-rechteck 600000.0 0.0 610000.0 6000.0)) diff --git a/tests/test_lager_yaml.py b/tests/test_lager_yaml.py index d13364c..254b936 100644 --- a/tests/test_lager_yaml.py +++ b/tests/test_lager_yaml.py @@ -7,8 +7,8 @@ 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, inkl. - goh_rack-Bloecke), Belag/Gitterrost nur auf Buehnen. + 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, @@ -73,8 +73,6 @@ def raw(): "gaenge": [_gang(0, 10000), _gang(1, 10000), _gang(1, 700, breite=1200, art="quergang"), _gang(1, 500, breite=1200, art="quergang", belag="gitterrost")], - "goh_racks": [{"geschoss": 1, "name": "goh_rack", "laenge_mm": 5000, "ebenen": 2, - "tiefe_mm": 700, "haengeebenen": EBENEN_OG, "haengeebenen_quelle": "vorgabe"}], "warnungen": ["Testwarnung"], } @@ -90,15 +88,15 @@ def test_levels_sortiert_und_hoehen(raw): assert "clear_height_m" not in lv[1] -def test_haengeebenen_summe_inkl_goh_rack(raw): +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 + goh_rack 5 m, oberste Schiene zuerst - assert [h["rack_length_m"] for h in og["hanging_levels"]] == [25.0, 25.0] + # 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 @@ -109,16 +107,16 @@ def test_belag_nur_auf_buehne(raw): # 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 + goh_rack 3,5 m2 - assert og["grating"] == pytest.approx(18.1) + # 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 + 3,5) m2 Reihen - assert og["walkway"]["area_m2"] == pytest.approx(42.5) + # 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"] diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index c948006..3390559 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -3145,8 +3145,6 @@ (tu-nil "lg-haengeebenen-parse/ungueltig" (lg-haengeebenen-parse "x")) (tu-eq "lg-haengeebenen-string" "2300/1200;1100/1100" (lg-haengeebenen-string '((2300.0 1200.0) (1100.0 1100.0)))) - (tu-eq "lg-haengeebenen-n/1" "2300/1200" (lg-haengeebenen-n "2300/1200;1100/1100" 1)) - (tu-eq "lg-haengeebenen-n/zuviel" "2300/1200;1100/1100" (lg-haengeebenen-n "2300/1200;1100/1100" 5)) (tu-eq "lg-feld-pruefen/mm" "1000" (lg-feld-pruefen "mm" " 1000 ")) (tu-nil "lg-feld-pruefen/mm-neg" (lg-feld-pruefen "mm" "-5")) (tu-nil "lg-feld-pruefen/mm-leer" (lg-feld-pruefen "mm" "")) @@ -3300,19 +3298,7 @@ (tu-eq "lg-geschoss-punkt/3d-unten" 1 (lg-geschoss-fuer-punkt-kern '(50.0 50.0 100.0) _kand)) ;; --- Geschoss kopieren --- - (tu-eq "lg-geschoss-aus-layer/regal" 2 (lg-geschoss-aus-layer "LG_Regal_G2")) - (tu-eq "lg-geschoss-aus-layer/12" 12 (lg-geschoss-aus-layer "LG_Reihe_G12")) - (tu-nil "lg-geschoss-aus-layer/ohne" (lg-geschoss-aus-layer "LG_Reihe")) - (tu-nil "lg-geschoss-aus-layer/0" (lg-geschoss-aus-layer "0")) - (tu-nil "lg-geschoss-aus-layer/suffix" (lg-geschoss-aus-layer "LG_X_G2a")) - (tu-nil "lg-geschoss-aus-layer/nil" (lg-geschoss-aus-layer nil)) - ;; 2D uebereinander: Kontur mehrdeutig, Layer entscheidet (setq _kand2 (list (list 1 0.0 _sq0) (list 2 3100.0 _sq0))) - (tu-eq "lg-rack-geschoss/layer" 2 (lg-rack-geschoss "LG_Regal_G2" '(50.0 50.0 0.0) _kand2)) - (tu-nil "lg-rack-geschoss/mehrdeutig" (lg-rack-geschoss "0" '(50.0 50.0 0.0) _kand2)) - (tu-eq "lg-rack-geschoss/kontur" 1 (lg-rack-geschoss "0" '(50.0 50.0 0.0) (list (list 1 0.0 _sq0)))) - ;; Layer eines nicht vorhandenen Geschosses zaehlt nicht - (tu-eq "lg-rack-geschoss/layer-fremd" 1 (lg-rack-geschoss "LG_Regal_G7" '(50.0 50.0 0.0) (list (list 1 0.0 _sq0)))) (tu-eq "lg-kopie-belag/folgt" "spanplatte" (lg-kopie-belag "hallenboden" "hallenboden" "spanplatte")) (tu-eq "lg-kopie-belag/eigen" "gitterrost" (lg-kopie-belag "gitterrost" "hallenboden" "spanplatte")) (tu-nil "lg-kopie-belag/nil" (lg-kopie-belag nil "hallenboden" "spanplatte")) @@ -3387,41 +3373,18 @@ '(((300.0 -500.0) (10000.0 -500.0) (10000.0 500.0) (300.0 500.0))) 500.0)) (tu-eq "lg-quelle-rang" '(2 1 0 0) (mapcar 'lg-quelle-rang '("manuell" "auto_geaendert" "auto" nil))) - ;; --- goh_rack-Erkennung: Parameterwerte, Namen, Transformationen --- - (tu-eqf "lg-zahl-einheit/mm" 700.0 (lg-zahl-einheit "700 mm")) - (tu-eqf "lg-zahl-einheit/cm" 718.752 (lg-zahl-einheit "71.8752 cm")) - (tu-eqf "lg-zahl-einheit/m" 12900.0 (lg-zahl-einheit "12,9 m")) - (tu-eqf "lg-zahl-einheit/ohne" 2.0 (lg-zahl-einheit "2")) - (tu-eqf "lg-zahl-einheit/zahl" 3.0 (lg-zahl-einheit 3)) - (tu-nil "lg-zahl-einheit/km" (lg-zahl-einheit "5 km")) - (tu-nil "lg-zahl-einheit/text" (lg-zahl-einheit "abc")) - (tu-nil "lg-zahl-einheit/leer" (lg-zahl-einheit "")) - (tu-nil "lg-zahl-einheit/nil" (lg-zahl-einheit nil)) - (tu-eqf "lg-racks-auswerten" + (tu-eqf "lg-reihen-auswerten" '((1 2 3000.0 6000.0) (2 1 500.0 1500.0) (nil 2 700.0 1400.0)) - (lg-racks-auswerten '((2 500.0 3.0) (nil 700.0 2.0) (1 1000.0 2.0) + (lg-reihen-auswerten '((2 500.0 3.0) (nil 700.0 2.0) (1 1000.0 2.0) (1 2000.0 2.0) (nil nil 2.0)))) - (tu-nil "lg-racks-auswerten/leer" (lg-racks-auswerten nil)) - (tu-eq "lg-name-brauchbar-p/name" T (lg-name-brauchbar-p "goh_rack")) - (tu-nil "lg-name-brauchbar-p/anonym" (lg-name-brauchbar-p "*U29")) - (tu-nil "lg-name-brauchbar-p/leer" (lg-name-brauchbar-p "")) - ;; Einfuegung bei (100,0), 90 Grad, x-Skalierung 2: lokales (1,0,0) -> (100,2,0) - (tu-eqf "lg-insert-tf/drehung-skalierung" '(100.0 2.0 0.0) - (lg-tf-pkt (lg-insert-tf (list '(2 . "TU_KEIN_BLOCK") '(10 100.0 0.0 0.0) - (cons 50 (/ pi 2.0)) '(41 . 2.0)) - 0 0) - '(1.0 0.0 0.0))) - ;; MINSERT-Spalte 2 bei Spaltenabstand 3000, gedreht um 90 Grad -> entlang +Y - (tu-eqf "lg-insert-tf/minsert" '(0.0 6000.0 0.0) - (car (lg-insert-tf (list '(2 . "TU_KEIN_BLOCK") '(10 0.0 0.0 0.0) (cons 50 (/ pi 2.0)) - '(70 . 3) '(44 . 3000.0)) - 2 0))) - ;; verschachtelt: Container bei (1000,0) um 90 Grad, Kind bei lokal (0,2000) - (tu-eqf "lg-tf-verketten" '(-1000.0 0.0 0.0) - (car (lg-tf-verketten - (lg-insert-tf (list '(2 . "TU_KEIN_BLOCK") '(10 1000.0 0.0 0.0) (cons 50 (/ pi 2.0))) 0 0) - (lg-insert-tf (list '(2 . "TU_KEIN_BLOCK") '(10 0.0 2000.0 0.0)) 0 0)))) - + (tu-nil "lg-reihen-auswerten/leer" (lg-reihen-auswerten nil)) + (tu-eqf "lg-reihe-eintrag" + '(2 4500.0 2.0) + (lg-reihe-eintrag '(("GESCHOSS" . "2") ("LAENGE" . "4500") + ("HAENGEEBENEN" . "2300/1200;1100/1100")))) + (tu-eqf "lg-reihe-eintrag/leer" + '(nil nil 0.0) + (lg-reihe-eintrag '(("GESCHOSS" . "") ("HAENGEEBENEN" . "")))) (tu-nil "lg-gang-aus-ecken/entartet" (lg-gang-aus-ecken '((0.0 0.0) (4000.0 0.0) (4000.0 0.0) (0.0 0.0))))