Files
dxfmakros/doc/plan/lager_rfq.md
T

275 lines
17 KiB
Markdown

# Lagerplanung in BricsCAD -> Lager-JSON (GOH-Buehnenlager)
Schema und Schnittstelle der Lagerplanung. Code: `Lisp/LagerInsert.lsp`,
`Lisp/LagerPruefung.lsp`. Daten: `data/json/lager.json`,
`cfg/stahlbau/regelwerk/*.json`, `cfg/layer.cfg` Abschnitt `[lager]`, Dialoge `dcl/lager.dcl`.
## Ziel und Datenfluss
Das RFQ-Programm (eigenes Repo) erzeugt das Ausschreibungsdokument. Die Makros
liefern ihm die technischen Daten des Lagers aus der Zeichnung, als EINE
JSON-Datei. Mapping auf das RFQ-Schema, Abgleich mit Handwerten und Darstellung
sind Sache des RFQ-Projekts.
```
BricsCAD (LISP) RFQ-Repo
LG_GESCHOSS / LG_BEREICH / LG_REIHE / LG_GANG
--LAGER_EXPORT--> DXFM_RESULTS/<dwg>_lager.json --> Dokument
^ Regelprofil cfg/stahlbau/regelwerk/<Land>.json (LagerPruefung.lsp, noch nicht im Export)
```
Grundsatz: jede fachliche Regel und jeder Kennwert wird genau einmal
implementiert, in LISP (`LagerInsert.lsp` Abschnitt EXPORT, Regeln in
`LagerPruefung.lsp`). Es gibt keinen Python-Schritt mehr (die fruehere
Overlay-YAML `lib/lager_yaml_export.py` und `LAGER_HAND_YAML` sind entfernt).
## JSON-Schnittstelle (`format` = `ssg-lager`, `version` = 2)
Einheiten mm, mm2, Grad; Koordinaten WCS, Nord = +Y. Werte stehen
selbstbeschreibend drin (`"belag_art": "spanplatte"`, keine Index-Codes). Fehlende
Werte sind `null`. Nicht-ASCII-Zeichen in Texten werden als `\uXXXX` geschrieben.
```
{
"format": "ssg-lager", "version": 2, "zeichnung", "erzeugt", "land",
"einheiten": {"laenge": "mm", "flaeche": "mm2", "winkel": "grad"},
"koordinaten": "WCS, Nord = +Y",
"lager": { geschosse, bereiche, reihen, regallaenge_mm, regalgrundflaeche_mm2,
schienenlaenge_mm, haengeebenen[], gaenge{}, belagsflaeche_mm2,
gitterrostflaeche_mm2, gitterkorb{}, huelle{bbox, laenge_mm, breite_mm} },
"geschosse": [ { nr, bezeichnung, id, handle, layer, hoehe_belag_mm, konstr_hoehe_mm,
lichte_hoehe_mm (Attribut), belag_art, personen, brandgefaehrdung,
kontur{handle, z, punkte[[x,y]...], flaeche_mm2, umfang_mm, bbox},
kennwerte{...}, herkunft{<kennwert>: {formel, quelle}} } ],
"bereiche": [ { nr, id, handle, layer, geschoss, gangbreite_mm, regaltiefe_mm,
reihen_je_gang, schienen_je_gang, quergang_abstand_mm, quergang_breite_mm,
richtung_grad, haengeebenen[], belag, unter_reihe, gitterkorb_hoehe_mm,
randgang_mm{n,o,s,w}, restbreite_mm, anzahl_reihen, anzahl_gaenge, kontur{} } ],
"reihen": [ { id, handle, layer, geschoss, bereich, bereich_handle, quelle, laenge_mm,
tiefe_mm, schienen, haengeebenen[], start, ende, mitte, winkel_grad,
ecken[4], flaeche_mm2, unter_reihe,
gitterkorb{hoehe_mm, bodenflaeche_mm2, offen_laengs_mm, offen_stirn_mm,
seitenflaeche_mm2} | null } ],
"gaenge": [ { id, handle, layer, geschoss, bereich, bereich_handle, quelle, laenge_mm,
breite_mm, art, belag, start, ende, mitte, winkel_grad, ecken[4], flaeche_mm2 } ],
"warnungen": [ ... ]
}
```
`geschosse` ist nach Belagshoehe sortiert (von unten nach oben). `start`/`ende`/
`mitte` sind 3D (Z der Einfuegung), `ecken` sind die vier Ecken des Grundrisses
(2D), Kante 1-2 und 3-4 laengs, 2-3 und 4-1 an den Stirnseiten.
`kennwerte` je Geschoss: `lichte_hoehe_mm`, `buehne` (true/false), `bereiche`,
`reihen`, `regallaenge_mm`, `regalgrundflaeche_mm2`, `schienenlaenge_mm`,
`haengeebenen` (je Schienenhoehe/Warenlaenge: `reihen`, `regallaenge_mm`),
`gaenge` (je Art gang/quergang/randgang: `anzahl`, `laenge_mm`, `flaeche_mm2`),
`belagsflaeche_mm2`, `gitterrostflaeche_mm2`, `gitterkorb` (Summen). Formeln:
Abschnitt "Kennwerte <- Zeichnung".
Erzeugt von `LAGER_EXPORT` (Menue Lager -> Export Lager-JSON), Beispiel:
`tests/output/lager_tests_lager.json` nach `TEST_LAGER`.
## Bloecke und Attribute
Alle Bloecke tragen `ID`, `GESCHOSS`, `LAYER`. Masse in mm, Winkel in Grad,
Werte selbstbeschreibend (keine Index-Codes). Verknuepfungen als XDATA
(App `SSG_LG`, Paare `1000 schluessel` + `1005 handle`/`1000 text`).
| Block | Geometrie | Attribute | XDATA |
|---|---|---|---|
| `LG_GESCHOSS` | Kopfsymbol unten links an der Belagskontur | `NR`, `BEZEICHNUNG`, `HOEHE_BELAG_mm`, `KONSTR_HOEHE_mm`, `LICHTE_HOEHE_mm` (leer = berechnet), `BELAG_ART` (`spanplatte`/`gitterrost`/`hallenboden`), `PERSONEN`, `BRANDGEFAEHRDUNG` | `kontur` -> Polylinie; Kontur: `besitzer`, `rolle` |
| `LG_BEREICH` | Symbol mit Pfeil in Reihenrichtung | `NR`, `GANGBREITE_mm`, `REGALTIEFE_mm`, `REIHEN_JE_GANG` (1/2), `SCHIENEN_JE_GANG`, `QUERGANG_ABSTAND_mm` (0 = keine), `QUERGANG_BREITE_mm`, `RICHTUNG`, `HAENGEEBENEN`, `BELAG`, `RANDGANG_N_mm`/`_O_`/`_S_`/`_W_` (0 = keiner), `UNTER_REIHE` (`gitterrost`/`gitterkorb`/`keine`, Absturzsicherung unter den Reihen, nur auf Buehnen), `GITTERKORB_HOEHE_mm`, `RESTBREITE_mm` (Ergebnis) | `kontur` -> Polylinie |
| `LG_REIHE_<L>_<T>` | Rechteck L x T um die Schienenlinie, Einfuegepunkt = Reihenanfang | `LAENGE`, `TIEFE_mm`, `HAENGEEBENEN`, `SCHIENEN`, `BEREICH`, `QUELLE` (`auto`/`auto_geaendert`/`manuell`) | `bereich` -> LG_BEREICH (nur Auto-Fuellung) |
| `LG_GANG_<L>_<B>_<BELAG>` | Rechteck L x B um die Gangachse + Schraffur je Belag (`lager.json belag_schraffur`, Layer 0/VONBLOCK; `hallenboden` ohne) | `LAENGE`, `BREITE_mm`, `ART` (`gang`/`quergang`/`randgang`), `BELAG`, `BEREICH`, `QUELLE` (`auto`/`auto_geaendert`/`manuell`) | `bereich` (Auto-Fuellung und manuelle Gaenge im Bereich) |
`HAENGEEBENEN` = `Schienenhoehe/Warenlaenge;...` ueber Belag, oberste zuerst,
z.B. `2300/1200;1100/1100`. Die Definitionen `LG_REIHE_*`/`LG_GANG_*` werden je
Geometrie wiederverwendet; die Werte stehen in den Attributen der Referenz.
### Geschosse und Layer
Layer je Geschoss: Basis aus `cfg/layer.cfg [lager]` + `_G<nr>`
(`LG_Reihe_G2`). `LG_GESCHOSS_AKTIV` friert die Layer der uebrigen Geschosse,
weil die 2D-Grundrisse uebereinander liegen. Neue Objekte bekommen das aktive
Geschoss; ohne aktives Geschoss entscheidet die Kontur, in der sie liegen. In
2D (alle Konturen auf Z = 0) ist eine Lage in mehreren Konturen nicht
eindeutig -> Rueckfrage bzw. Export-Warnung; in 3D entscheidet Z.
Jede Kontur gehoert genau einem Block. Wird eine schon vergebene Kontur
gewaehlt (z.B. dieselbe Halle fuer mehrere Geschosse), wird sie kopiert.
Der parametrische BricsCAD-Block `goh_rack` (frueher als Bestand mitgezaehlt)
wird nicht mehr unterstuetzt: Regale gibt es nur noch als `LG_REIHE_*`.
### Geschoss kopieren (`LG_GESCHOSS_KOPIEREN`)
Obergeschosse gleichen meist dem Geschoss darunter. Dialog `lg_geschoss_kopie`:
- Quelle: Vorgabe ist das oberste Geschoss. Damit wird ein weiteres Geschoss
nachtraeglich angehaengt, z.B. G3 -> G4.
- Anzahl.
- Geschosshoehe je Kopie: Vorgabe ist der Abstand zum Geschoss darunter, sonst
lichte Hoehe + Konstruktion.
- Belag.
- Versatz X/Y je Kopie: 0 = deckungsgleich. In einer 3D-Zeichnung (Konturen auf
Belagshoehe) wandert die Kopie zusaetzlich in Z.
Ein BricsCAD-KOPIEREN taugt nicht. Die XDATA-Verweise `kontur`/`besitzer`/`bereich`
zeigten dann weiter auf die Originale, und GESCHOSS, Layer und IDs blieben die alten.
Stattdessen entsteht jedes Objekt ueber die normalen Einfuegefunktionen neu:
- Geschoss und Bereiche mit kopierter Kontur; die Bereiche ohne Fuellung
(`lg-bereich-block-anlegen`).
- Reihen und Gaenge 1:1 aus der Quelle (`lg-linie-einfuegen`). Es wird nicht neu
gefuellt, damit Handaenderungen (`auto_geaendert`, manuelle Reihen/Gaenge) erhalten
bleiben.
- Belaege, die dem Geschossbelag der Quelle entsprachen, folgen dem neuen Belag,
inklusive Schraffur. Bewusst abweichende bleiben.
### Auto-Fuellung (`lg-fuellung-berechnen`)
Die Kontur wird in ein lokales System gedreht (Reihen entlang +X, `RICHTUNG`;
Vorgabe = Richtung der laengsten Konturkante). Quer dazu wird ab Unterkante ein
Modul nach dem anderen gelegt, nur volle Module:
- 2 Reihen je Gang: `Reihe | Gang | Reihe`, benachbarte Module Ruecken an Ruecken
- 1 Reihe je Gang: `Reihe | Gang`
Ein Streifen ist dort belegbar, wo Unter-, Mittel- und Oberkante in der Kontur
liegen (konkave Konturen werden korrekt beschnitten). Quergaenge: Luecken der
Breite `QUERGANG_BREITE_mm` nach je `QUERGANG_ABSTAND_mm`, ueber alle Reihen
ausgerichtet; keine Luecke am Reihenende, wenn dahinter kein Mindeststueck mehr
passt. Hauptgaenge laufen durch. Der Rest quer zu den Reihen steht in
`RESTBREITE_mm`. Edit des Bereichs = Neuaufbau aller Kinder (Sektions-Neuaufbau,
kein Feld-Splice) - aber nur der automatisch erzeugten (`QUELLE=auto`). Von Hand
eingefuegte (`manuell`) und von Hand geaenderte (`auto_geaendert`) Reihen und Gaenge
bleiben stehen und werden ausgespart, ebenso unverknuepfte manuelle Objekte, deren
Mitte in der Kontur liegt; die Anzahl wird gemeldet. Von Hand geloeschte
automatische Objekte entstehen bei dieser ausdruecklichen Neuberechnung neu.
**Randgaenge** (`RANDGANG_N/O/S/W_mm`, Nord = +Y Welt): jede Konturkante bekommt
den Randgang ihrer Himmelsrichtung (Aussennormale, auf N/O/S/W eingerastet,
45 Grad zaehlt zu N/S) als Rechteck von der Kante nach innen - auch bei L-Form
entlang der echten Kanten (dort bekommt z.B. auch die Stufenkante den
Nord-Randgang; Ausnahmen per `LG_GANG`). Ecken: N/S-Randgaenge besitzen sie;
an konvexen Ecken wird der O/W-Randgang gekuerzt, an einspringenden Ecken der
N/S-Randgang verlaengert (sonst bliebe ein freies Quadrat). Randgaenge an der
Unter-/Oberkante der Huelle verschieben den Modulstapel, an der linken/rechten
den Bezug der Quergaenge; Stufenkanten mitten im Stapel kappen nur die
betroffenen Reihen. Nicht rechtwinklige Ecken sind eine Naeherung.
**Sperrflaechen**: Randgaenge sowie von Hand eingefuegte und geaenderte Reihen und
Gaenge werden aus Reihen, Haupt- und Quergaengen ausgeschnitten - exakt ueber den
Band-Clip des Streifens (`ssg-poly-band-x`), Reststuecke unter der
Mindestlaenge fallen weg. Eine von Hand eingefuegte Reihe (`LG_REIHE`) oder ein
Gang (`LG_GANG`), dessen Mitte in einem Bereich liegt, wird mit ihm verknuepft.
**Von Hand Gesetztes loest KEINE Neuberechnung aus.** Beim Einfuegen und
Bearbeiten (`LG_REIHE`, `LG_GANG`, `LG_EDIT` einer Reihe/eines Gangs) schneidet das
Objekt nur seine Flaeche aus den ueberdeckten Objekten heraus
(`lg-sperre-anwenden`, Kern `lg-linie-zuschnitt`); die Reste behalten ihre Attribute.
Geschnitten wird nur, was rangniedriger ist (`lg-quelle-rang`: `auto` <
`auto_geaendert` < `manuell`) - ein manuelles Objekt schneidet aus automatischen und
geaenderten, ein geaendertes nur aus automatischen, manuelle untereinander nie. Alles
andere bleibt, wie der Anwender es hinterlassen hat: von Hand geloeschte Objekte
kommen nicht zurueck. Wird ein manueller Gang verkleinert oder geloescht, bleibt die
Luecke bis zur naechsten ausdruecklichen Neuberechnung (Doppelklick auf den
Bereich, OK).
`LG_GANG` zeichnet einen Gang entweder als Linie (Gangmitte, Breite aus dem
Dialog) oder ueber die Option `Rechteck` als Flaeche. Beim Rechteck
ergeben sich Lage und Breite aus der Flaeche, man muss sie also vorher nicht
kennen: die laengere Seite ist die Gangrichtung, die kuerzere die Breite (auf
ganze mm). Die Rundung verschiebt nur die Laengsseite gegenueber der ersten
gezeichneten Ecke - die Kante, an der man ansetzt (z.B. buendig an einer
Regalreihe), bleibt exakt liegen, sonst wuerde der Gang die Reihe um Bruchteile
eines mm ueberdecken und sie beim Zuschnitt entfernen; ebenso beginnt der Gang an
der Querseite der ersten Ecke (`lg-gang-aus-ecken`). Gezeichnet wird mit dem echten BricsCAD-Befehl RECHTECK
(`lg-rechteck-zeichnen`) - mit allen seinen Optionen (Abmessungen, Flaeche,
Drehung, Objektfang); ein gedrehtes Rechteck ergibt einen schraeg liegenden Gang.
Die gezeichnete Polylinie wird ausgewertet (`lg-rechteck-ecken-aus-poly`) und
wieder geloescht; mit Fase oder Rundung gezeichnete Flaechen werden abgelehnt.
Nach jedem Rechteck startet RECHTECK erneut, Enter ohne Rechteck beendet. Im Block
entsteht derselbe `LG_GANG_*` wie bei der Linie.
**Schraffur**: steckt in der Gang-Blockdefinition (Belag im Blocknamen), Muster
aus `lager.json belag_schraffur` - `spanplatte` ANSI31, `gitterrost` GRID,
`hallenboden` keine. Unbekannter Belag/Muster -> Meldung, Gang ohne Schraffur.
Reihen bleiben unschraffiert. Altbestand: fehlen einer vorhandenen
Blockdefinition ATTDEFs des Schemas, definiert `lg-blockdef` sie neu und
uebertraegt sie per `_.ATTSYNC` auf die Referenzen.
## Kennwerte <- Zeichnung
Reine Kerne in `LagerInsert.lsp` (getestet in `tu-tests-lager`). Jeder
Geschoss-Kennwert steht mit Formel und Quelle unter `herkunft`.
| Kennwert | Quelle / Formel |
|---|---|
| `lichte_hoehe_mm` | `LICHTE_HOEHE_mm`, sonst Belag darueber - Konstruktionshoehe darueber - eigener Belag; oberstes Geschoss nur mit Vorgabe (sonst `null` + Warnung) |
| `buehne` | `BELAG_ART` gesetzt und nicht `hallenboden`. Ohne Buehne: kein Belag, kein Gitterrost, kein Gitterkorb |
| `regallaenge_mm`, `regalgrundflaeche_mm2`, `schienenlaenge_mm` | Summe `LAENGE`, `LAENGE x TIEFE_mm`, `LAENGE x SCHIENEN` der Reihen des Geschosses |
| `haengeebenen[]` | je (Schienenhoehe, Warenlaenge): Anzahl Reihen und Summe `LAENGE`, nach Schienenhoehe absteigend (`lg-haengeebenen-summen`) |
| `gaenge` | je `ART` (gang/quergang/randgang, auch manuelle): Anzahl, Summe `LAENGE`, Summe `LAENGE x BREITE_mm` (`lg-gaenge-je-art`) |
| `belagsflaeche_mm2` | Summe `LAENGE x BREITE_mm` der Gaenge mit Belag != gitterrost; ohne Gangflaechen: Konturflaeche - Reihengrundflaeche |
| `gitterrostflaeche_mm2` | Gaenge mit Belag gitterrost + Grundflaeche der Reihen mit `UNTER_REIHE = gitterrost` |
| `gitterkorb` (je Reihe und Summe) | Reihen mit `UNTER_REIHE = gitterkorb`: Boden = `LAENGE x TIEFE_mm`; Seiten = offene Kantenlaenge x `GITTERKORB_HOEHE_mm`, getrennt nach Laengs- und Stirnseiten. Offen ist eine Kante, soweit keine Kante einer ANDEREN Reihe desselben Geschosses kollinear darauf liegt (Abstand < 1 mm, z.B. Ruecken an Ruecken; `lg-reihen-offene-kanten`) |
| `lager.huelle` | achsparallele Huelle aller Geschosskonturen, `laenge_mm` = laengere Seite |
| `lager.*` sonst | Summen der Geschoss-Kennwerte; `haengeebenen`/`gaenge` ueber alle zugeordneten Reihen/Gaenge |
`UNTER_REIHE` kommt aus dem verknuepften Bereich; Reihen ohne Bereich (und
Bereiche ohne Attribut, Altbestand) nehmen die Vorgabe `lager.json
bereich.unter_reihe`. `GITTERKORB_HOEHE_mm` ist vorerst ein Attribut am Bereich
und soll spaeter aus den Attributen berechnet werden.
Spaetere Phasen: Gelaender/Bordbrett, Oeffnungen, Treppen, Leitern, Zugaenge
(Phase 2), Schnitte (Phase 3), Fluchtwege (Phase 4/5), Regelwerk-Werte je
Geschoss im Export.
## Regelprofil
`cfg/stahlbau/regelwerk/<LAND>.json`, aufgeloest von `LagerPruefung.lsp`:
```json
{"id": "treppe.schrittmass_min", "art": "min", "einheit": "mm",
"werte": [{"wert": 590, "quelle": "ASR A1.8", "abschnitt": "4.5", "fassung": "...", "verifiziert": false},
{"wert": 600, "quelle": "EN ISO 14122-3", "abschnitt": "5", "fassung": "...", "verifiziert": false}]}
```
- `art`: `min` (strengster = groesster), `max` (strengster = kleinster), `wert`.
- `bedingung`: `<schluessel> <op> <wert>` (`=`, `<=`, `>=`, `<`, `>`) gegen einen
Kontext (z.B. `brandgefaehrdung`, `absturzhoehe`, `personen`). Fehlt der
Schluessel im Kontext, wird der Eintrag konservativ einbezogen.
- `tabelle` + `tabellen_schluessel`: Wert der ersten Zeile `[bis, wert]`, die den
Kontextwert abdeckt (Fluchtwegbreite nach Personen).
- `erbt_von`: Laenderprofil erbt alle Regeln, eigene Records mit gleicher `id`
ersetzen sie. `SK.json`/`PL.json` sind Gerueste (`gepflegt: false` -> Warnung).
- `LG_REGELN` zeigt alle Regeln mit Ergebnis und Protokoll (welche Quelle gewann).
**Alle Startwerte stehen auf `verifiziert: false`.** Wert, Abschnitt und
Fassung muessen gegen die Originaltexte (ASR A1.8, A2.1, A2.3, DGUV Regel
108-007, EN ISO 14122-3/-4) geprueft werden; besonders unsicher sind die
DGUV-Gangbreiten und die Abschnittsnummern.
## Stand
| Phase | Inhalt | Stand |
|---|---|---|
| 0 | Regelprofil + Resolver, Schema (dieses Dokument), Layer, Sprach-Keys, Menue, Laden | erledigt, Regelwerte unverifiziert |
| 1 | Geschoss, aktives Geschoss, Bereich + Auto-Fuellung, Einzelreihe, Edit, `LAGER_EXPORT` als Lager-JSON mit Kennwerten und Herkunft, Gitterkorb/Gitterrost unter den Reihen | erledigt (2D) |
| 1a | Regelwerk-Werte (aufgeloest je Geschoss) im Lager-JSON; Gitterkorb-Hoehe aus den Attributen berechnen | offen |
| 2 | Gelaender/Bordbrett aus Kontur, Kanten-Ausnahmen, Oeffnungen, Treppe (Auslegung nach Profil), Leiter | offen |
| 3 | Schema-Schnitt, 3D-Varianten | offen |
| 4 | `LAGER_PRUEFEN`, Fluchtweg (gezeichnet), Verstoss-Marker, Nachweis mit Regelpruefung | offen |
| 5 | automatische Fluchtweganalyse | offen |
| 6 | SK/PL-Profile, Kapazitaet, Kopplung Geruest, Stuecklisten-Klassen | offen |
## Tests
- `tests/test_unit.lsp`: `tu-tests-poly` (Polygon-Helfer in `ssg_core.lsp`),
`tu-tests-lager` (Fuellung, Geschosszuordnung, JSON-Schreiber, Kennwerte,
offene Kanten/Gitterkorb, Feldpruefung, Regelprofil).
- `tests/test_lager.lsp` (`TEST_LAGER`, `alltests.json`): Ablauf in einer
Zeichnung inkl. Neuberechnung, Reihen-Edit, Export (Schema, Geometrie,
Kennwerte, Gitterkorb), Geschoss-Kopie und `LG_REGALE`.