diff --git a/Lisp/export.lsp b/Lisp/export.lsp index 2b6e7ff..562435d 100644 --- a/Lisp/export.lsp +++ b/Lisp/export.lsp @@ -54,7 +54,7 @@ ;; Drei sich gegenseitig ausschliessende Werte (String, ueber CSV_EXPORT_ ;; KONFIG/dcl/csv_export_konfig.dcl bedienbar, siehe c:CSV_EXPORT_KONFIG ;; weiter unten): -;; "group_vf_gf" - Default. csv:unitmark-aktualisieren fasst Boegen/ +;; "group_vf_gf" - Default. csv:ketten-verarbeiten fasst Boegen/ ;; Streckenelemente/Umlenk-/Motorstation zu je einer ;; Zeile pro Foerdereinheit/Gefaelleeinheit zusammen, ;; die pattern_nested_*-Einzelteil-Zeilen bleiben aus @@ -82,7 +82,7 @@ (princ) ) ;; Abgeleitete Boolean-Abfragen - bestehende Aufrufstellen (csv:collect- -;; export-blocks/csv:unitmark-aktualisieren) bleiben dadurch unveraendert. +;; export-blocks/csv:ketten-verarbeiten) bleiben dadurch unveraendert. (defun csv:export-alle-elemente-p () (= *csv-export-modus* "all_elements")) (defun csv:export-separator-track-p () (= *csv-export-modus* "separator_track")) ;; Kurzformen, die die frueheren csv:export-alle-elemente-an/-aus 1:1 @@ -416,15 +416,31 @@ ;; 1000_mm (per Laenge auf der X-Achse gestreckt, siehe insert-inclined- ;; scaled-block, Lisp/ssg_ks_insert.lsp:260). Ohne diese Skalierung wuerde ;; K2 dort so berichtet, als waere der Block unskaliert (1:1) eingefuegt - -;; derselbe Fehler, den csv:vfgf-ks-loc fuer AS-/ES-Elemente schon per -;; elem-sx/elem-sy/elem-sz vermeidet (siehe dort). Fuer alle bisherigen +;; derselbe Fehler, den csv:record-welt-lage fuer verpackte Bausteine per +;; Record-Skalierung vermeidet (siehe dort). Fuer alle bisherigen ;; Aufrufer (Omniflo/Kreisel/AS-ES-Marker, durchweg uniform mit 1.0 skaliert ;; eingefuegt) ist die Multiplikation ein No-Op - unveraendertes Verhalten. -(defun csv:get-k-kos-strings (ename pt parent-R sx sy sz / ed bname blk-tbl sub-ent sub-ed - sub-bname sub-pt sub-extrusion sub-pt-real world-pt - target is-real result) - (setq ed (entget ename)) - (setq bname (cdr (assoc 2 ed))) +;; +;; Der eigentliche Kern ist csv:ks-welt-punkte (arbeitet auf einer +;; Blockdefinition + Weltlage, liefert Punkte statt Strings) - so koennen auch +;; Zeilen, deren exportierter INSERT NICHT der Kettenbaustein selbst ist +;; (Separator-Symbolkopie, AS-/ES-Marker, VF_n/GF_n-Wrapper), die KS ihres +;; echten Bausteins ueber DIESELBE Rechnung bekommen (siehe csv:k-liste). +(defun csv:get-k-kos-strings (ename pt parent-R sx sy sz) + (csv:k-liste-kodieren + (csv:ks-welt-punkte (cdr (assoc 2 (entget ename))) pt parent-R sx sy sz)) +) + +;; --- K1-K4 einer Blockdefinition an einer Weltlage, als Weltpunkte --- +;; bname = Blockdefinition, deren DIREKTE Sub-INSERTs K1-K4/KS_EIN/KS_AUS +;; gelesen werden (Regeln siehe csv:get-k-kos-strings). +;; pt/parent-R = Weltposition/volle 3x3-Orientierung dieser Definition. +;; sx/sy/sz = Skalierung dieser Definition. +;; Rueckgabe: Assoc-Liste (("K1" x y z) ("K2" x y z) ...) - echte K-Bloecke +;; vorne (Vorrang bei assoc), nil wenn die Definition keine KS traegt. +(defun csv:ks-welt-punkte (bname pt parent-R sx sy sz / blk-tbl sub-ent sub-ed + sub-bname sub-pt sub-extrusion sub-pt-real world-pt + target is-real result) (setq blk-tbl (tblsearch "BLOCK" bname)) (setq result nil) (if blk-tbl @@ -461,11 +477,7 @@ (* sy (cadr sub-pt-real)) (* sz (caddr sub-pt-real)))) (setq world-pt (csv:local-to-world pt parent-R sub-pt-real)) - (setq result (cons - (cons target - (csv:trans-encode - (car world-pt) (cadr world-pt) (caddr world-pt))) - result)) + (setq result (cons (cons target world-pt) result)) ) ) ) @@ -477,6 +489,127 @@ result ) +;; --- K-Punkteliste (csv:ks-welt-punkte) -> K-Liste mit trans-encode-Strings --- +(defun csv:k-liste-kodieren (punkte) + (mapcar (function (lambda (e) + (cons (car e) (csv:trans-encode (nth 1 e) (nth 2 e) (nth 3 e))))) + punkte) +) + +;; --- Platzierung eines ssg-collect-nested-inserts-Records in Weltlage --- +;; pt/R0/psx/psy/psz = Weltlage des INSERT, dessen Definition durchsucht wurde. +;; rec = (ename (x y z) R sx sy sz) relativ zu dieser Definition. +;; Rueckgabe: ((x y z) R sx sy sz) in Weltkoordinaten. Gemeinsam genutzt von +;; csv:nested-welt-records (Proxies/Marker) und csv:vfgf-k-kos-strings. +(defun csv:record-welt-lage (pt R0 psx psy psz rec / local-pt rot-pt) + (setq local-pt (nth 1 rec)) + (setq rot-pt (mat3-mul-vec3 R0 (list (* psx (car local-pt)) + (* psy (cadr local-pt)) + (* psz (caddr local-pt))))) + (list (mapcar '+ pt rot-pt) + (mat3-mul-mat3 R0 (nth 2 rec)) + (* psx (nth 3 rec)) (* psy (nth 4 rec)) (* psz (nth 5 rec))) +) + +;; --------------------------------------------------------------------------- +;; K1-K4 und Boundingbox je Export-Zeile: Stellvertreter vs. Kettenbaustein +;; --------------------------------------------------------------------------- +;; Bogen/Streckenelement/Motor-/Umlenkstation werden als 1:1-Kopie ihres +;; Kettenbausteins exportiert - K1/K2 (= KS_EIN/KS_AUS) und Boundingbox sind +;; die des Bausteins, aufeinanderfolgende Teile teilen sich exakt ihren +;; Anschlusspunkt (K2 des einen = K1 des naechsten). Drei Zeilenarten +;; exportieren dagegen einen STELLVERTRETER: +;; Separator - Kopie des Sensor-SYMBOLS Separator_SP; der Kettenbaustein ist +;; sein Verpacker Staustrecke_Separator_SP_300_mm (das Symbol +;; traegt nur ein eigenes KS_EIN, 235 mm innerhalb des Trennstegs) +;; AS/ES - ZZ_ASES_MARKER-Rechteck ohne eigene KS; der Baustein ist das +;; verpackte AS_Element_*/ES_Element_* (K1 = KS_EIN, K2 = KS_AUS: +;; beim AS Kreisel -> Kettenanfang, beim ES Kettenende -> Kreisel) +;; +;; Welche Geometrie die Zeile fuehrt, haengt am Export-Modus: +;; all_elements - Separator UND AS/ES: die des umgebenden BAUSTEINS, +;; genau wie bei allen anderen Kettenteilen: K1/K2 = +;; KS_EIN/KS_AUS des Trennstegs bzw. AS-/ES-Elements, +;; Boundingbox (und damit Position) = die des Bausteins. +;; Die Kette ist dann lueckenlos ueber K2 -> K1 verbunden. +;; group_vf_gf - AS/ES wie all_elements (sie schliessen die Kette an die +;; Einheiten an, deren K1/K2 ebenfalls vom Baustein +;; kommen); Separator wie separator_track. +;; separator_track - die des STELLVERTRETERS selbst: das KS des Separator- +;; Symbols und seine Symbol-Boundingbox, der AS-/ES-Marker +;; ohne K (Verhalten vor der Kettenerweiterung). +;; Die Modus-Entscheidung trifft der Aufrufer (csv:sep-proxies-erzeugen bzw. +;; csv:asmark-aktualisieren), csv:baustein-merken selbst merkt immer. +;; Die Baustein-Geometrie wird beim Erzeugen des Stellvertreters aus dem +;; Baustein-Record berechnet (csv:baustein-merken) und unter dessen Handle +;; gemerkt; csv:k-liste bzw. csv:block-to-json liefern sie dann anstelle der +;; eigenen. K1/K2 eines VF_n/GF_n-Wrappers kommen unabhaengig vom Modus aus +;; AS/ES (csv:vfgf-element-punkte). +;; Die Einheiten-Proxies (ZZ_UNIT_MARKER, csv:unitmark-einfuegen) tragen sich +;; hier ebenfalls ein - ihre Box ist die gemessene 3D-Vereinigung der Bausteine. +;; *csv-baustein-by-handle*: ((handle k-liste-kodiert bbox) ...), je +;; Exportlauf neu (csv:export-vorbereiten setzt zurueck). +(setq *csv-baustein-by-handle* nil) + +;; --- Boundingbox eines Bausteins an seiner Weltlage --- +;; Die verpackte Blockreferenz selbst liefert keine Welt-Boundingbox (sie ist +;; nicht Space-resident, siehe ssg-collect-nested-inserts) - darum eine +;; kurzlebige Kopie an derselben Lage einfuegen (csv:block-einfuegen-welt, +;; dieselbe Platzierung wie jede Proxy-Kopie), messen und sofort loeschen. +;; rec wie csv:nested-welt-records. Rueckgabe wie csv:get-bbox oder nil. +(defun csv:baustein-bbox (rec / ms kopie bbox) + (setq ms (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object)))) + (setq kopie (csv:block-einfuegen-welt ms (nth 2 rec) (nth 3 rec) (nth 4 rec) + (nth 5 rec) (nth 6 rec) (nth 7 rec) + (cdr (assoc 2 (entget (nth 0 rec)))))) + (if kopie + (progn + (setq bbox (csv:get-bbox kopie)) + (entdel kopie))) + bbox +) + +;; --- Baustein-Geometrie (K-Punkte + Boundingbox) unter dem Handle seines +;; Stellvertreters merken --- rec wie csv:nested-welt-records: (wrapper +;; nested-ent bname (x y z) R sx sy sz). Ob gemerkt wird, entscheidet der +;; Aufrufer je Modus (siehe oben). Traegt der Baustein keine KS, bleibt die +;; K-Liste nil und csv:k-liste faellt auf die KS des Stellvertreters zurueck. +(defun csv:baustein-merken (stellvertreter rec / punkte) + (setq punkte (csv:ks-welt-punkte (nth 2 rec) (nth 3 rec) (nth 4 rec) + (nth 5 rec) (nth 6 rec) (nth 7 rec))) + (setq *csv-baustein-by-handle* + (cons (list (cdr (assoc 5 (entget stellvertreter))) + (csv:k-liste-kodieren punkte) + (csv:baustein-bbox rec)) + *csv-baustein-by-handle*)) +) + +;; --- Gemerkte Baustein-Boundingbox eines Stellvertreters, sonst nil --- +(defun csv:baustein-bbox-gemerkt (handle) + (caddr (assoc handle *csv-baustein-by-handle*)) +) + +;; --- K-Liste (kodiert) eines exportierten INSERT --- +;; Gemerkte Baustein-KS (csv:baustein-merken) haben Vorrang, sonst die KS der eigenen +;; Blockdefinition an der eigenen Weltlage (OCS aufgeloest wie in +;; csv:block-to-json). Einstieg fuer K1-K4 in csv:block-to-json. +(defun csv:k-liste (ename / ed pt extrusion) + (setq ed (entget ename)) + (cond + ((cadr (assoc (cdr (assoc 5 ed)) *csv-baustein-by-handle*))) + (t + (setq pt (cdr (assoc 10 ed))) + (if (null (caddr pt)) (setq pt (list (car pt) (cadr pt) 0.0))) + (setq extrusion (cond ((cdr (assoc 210 ed))) ('(0.0 0.0 1.0)))) + (csv:get-k-kos-strings ename + (mat3-mul-vec3 (mat3-ocs-matrix extrusion) pt) + (mat3-from-normal-rotation extrusion (cond ((cdr (assoc 50 ed))) (0.0))) + (cond ((cdr (assoc 41 ed))) (1.0)) + (cond ((cdr (assoc 42 ed))) (1.0)) + (cond ((cdr (assoc 43 ed))) (1.0)))) + ) +) + ;; --- Wert aus csv:get-k-kos-strings nach Name lesen, "" falls nicht vorhanden --- (defun csv:k-kos (k-list name / found) (setq found (assoc name k-list)) @@ -514,46 +647,23 @@ ) ) -;; --- KS-Position eines VF/GF-Wrappers ueber das RICHTIGE Element --- -;; bname = Blockname des VF_n/GF_n-Wrappers. -;; elem-pat = Muster des KS-tragenden Teilbloecks ("AS_ELEMENT*" bzw. -;; "ES_ELEMENT*", Grossschreibung - wcmatch ist unempfindlich). -;; ks-pat = Muster des gesuchten Koordinatensystems ("KS_EIN,KSYS_EIN" -;; bzw. "KS_AUS,KSYS_AUS"). -;; Warum zwei Ebenen: das AS_Element UND das ES_Element eines VF_n fuehren -;; JEWEILS ein KS_EIN UND ein KS_AUS (siehe check_hoehen.lsp ch-measure-vfgf). -;; Ein flaches (ssg-collect-nested-inserts bname "KS_AUS") ueber den GANZEN -;; Wrapper lieferte darum zwei Treffer und (car ...) griff den falschen (den -;; des AS_Elements) - K2/ES landete auf der falschen (Anfangs-)Seite. Darum -;; ERST das passende Element (AS/ES) suchen und NUR IN DESSEN Blockdefinition -;; das KS. Die KS-Position wird durch die Weltlage des Elements (world-pt/ -;; R-world/Skalierung aus dem Element-Record) in das Koordinatensystem der -;; Wrapper-Blockdefinition transformiert - dieselbe Verkettung wie in -;; ssg-collect-nested-inserts-rel (OCS ist in den Records bereits aufgeloest). -;; Rueckgabe: (x y z) im Wrapper-Definitionsframe, oder nil wenn nicht gefunden. -(defun csv:vfgf-ks-loc (bname elem-pat ks-pat / elem-hits elem-rec elem-bname - elem-pt elem-R elem-sx elem-sy elem-sz ks-hits ks-loc - scaled) - (setq elem-hits (ssg-collect-nested-inserts bname elem-pat)) - (if elem-hits +;; --- K-Punkte des AS- bzw. ES-Elements eines VF/GF-Wrappers, in Weltlage --- +;; bname = Blockname des VF_n/GF_n-Wrappers. +;; pt/R0 = Weltlage des Wrapper-INSERT. +;; elem-pat = "AS_ELEMENT*" bzw. "ES_ELEMENT*". +;; Das AS_Element UND das ES_Element fuehren JEWEILS ein KS_EIN UND ein KS_AUS +;; (siehe check_hoehen.lsp ch-measure-vfgf) - darum ERST das Element suchen und +;; seine KS dann ueber csv:ks-welt-punkte lesen, dieselbe Rechnung, die auch die +;; AS-/ES-Zeile im Modus all_elements bekommt (csv:baustein-merken). K1/K2 des +;; Wrappers stimmen dadurch per Konstruktion mit K1 des AS bzw. K2 des ES +;; ueberein. Rueckgabe wie csv:ks-welt-punkte, nil wenn kein Element. +(defun csv:vfgf-element-punkte (bname pt R0 elem-pat / elem-rec lage) + (setq elem-rec (car (ssg-collect-nested-inserts bname elem-pat))) + (if elem-rec (progn - (setq elem-rec (car elem-hits)) - (setq elem-bname (strcase (cdr (assoc 2 (entget (car elem-rec)))))) - ;; Nur das KS INNERHALB dieser Element-Blockdefinition (nicht im Wrapper). - (setq ks-hits (ssg-collect-nested-inserts elem-bname ks-pat)) - (if ks-hits - (progn - (setq elem-pt (cadr elem-rec)) - (setq elem-R (caddr elem-rec)) - (setq elem-sx (nth 3 elem-rec) elem-sy (nth 4 elem-rec) elem-sz (nth 5 elem-rec)) - (setq ks-loc (cadr (car ks-hits))) ;; KS-Pos im Element-Frame - (setq scaled (list (* elem-sx (car ks-loc)) - (* elem-sy (cadr ks-loc)) - (* elem-sz (caddr ks-loc)))) - ;; Element-Weltlage (im Wrapper-Frame) + rotierte KS-Position. - (mapcar '+ elem-pt (mat3-mul-vec3 elem-R scaled)) - ) - ) + (setq lage (csv:record-welt-lage pt R0 1.0 1.0 1.0 elem-rec)) + (csv:ks-welt-punkte (cdr (assoc 2 (entget (car elem-rec)))) + (nth 0 lage) (nth 1 lage) (nth 2 lage) (nth 3 lage) (nth 4 lage)) ) ) ) @@ -565,12 +675,10 @@ ;; VF/GF-Wrapper fuehren - anders als Omniflo-Boegen - KEINE direkten K1-K4- ;; oder KS-Sub-INSERTs; ihre Streckenenden stecken je EINE Ebene tiefer: ;; KS_EIN im AS_Element*, KS_AUS im ES_Element* (siehe check_hoehen.lsp, -;; extract-ks-from-block-raw). csv:vfgf-ks-loc holt die KS-Position aus dem +;; extract-ks-from-block-raw). csv:vfgf-element-punkte holt die KS aus dem ;; JEWEILS zugehoerigen Element (nicht flach aus dem ganzen Wrapper - beide -;; Elemente tragen beide KS-Typen). Der so ermittelte Punkt (Wrapper-Frame) -;; wird ueber die Wrapper-Weltlage (reine Z-Drehung) in Weltkoordinaten -;; gedreht und wie K1-K4 als reiner Positions-String (csv:trans-encode) -;; exportiert. Damit hat auch eine Strecke K1 und K2 fuer die +;; Elemente tragen beide KS-Typen), direkt in Weltkoordinaten, und sie werden +;; wie K1-K4 als reiner Positions-String (csv:trans-encode) exportiert. Damit hat auch eine Strecke K1 und K2 fuer die ;; Python-Kollisionspruefung (export_neighbors.py: Schleuselemente + ;; Kreisel-Kollision ueber die AS/ES-Position mit fester BBox statt der ;; ganzen Wrapper-Box). @@ -586,22 +694,18 @@ ;; wird bei GF nach Z sortiert (hoeheres Z -> K1, tieferes Z -> K2). ;; Rueckgabe wie csv:get-k-kos-strings: (("K1" . str) ("K2" . str)) - nur die ;; tatsaechlich gefundenen Enden. -(defun csv:vfgf-k-kos-strings (ename pt rot-rad / ed bname as-loc es-loc - as-world es-world ein-world aus-world result) +(defun csv:vfgf-k-kos-strings (ename pt rot-rad / ed bname R0 as-world es-world + ein-world aus-world result) (setq ed (entget ename)) (setq bname (cdr (assoc 2 ed))) (setq result nil) - ;; Beide Enden im Wrapper-Frame holen und in Weltkoordinaten umrechnen. ;; VF_n/GF_n-Wrapper stehen an ihrem eigenen top-level INSERT immer flach ;; (Extrusion (0 0 1) - siehe csv:sep-proxies-erzeugen), darum genuegt hier - ;; weiterhin die reine Z-Drehungsmatrix (mat3-rz) statt der vollen - ;; Elternorientierung, die csv:get-k-kos-strings inzwischen braucht (siehe - ;; dort). AS traegt das KS_EIN, ES das KS_AUS - jeweils aus dem RICHTIGEN - ;; Element (csv:vfgf-ks-loc; beide Elemente fuehren beide KS-Typen). - (setq as-loc (csv:vfgf-ks-loc bname "AS_ELEMENT*" "KS_EIN,KSYS_EIN")) - (setq es-loc (csv:vfgf-ks-loc bname "ES_ELEMENT*" "KS_AUS,KSYS_AUS")) - (if as-loc (setq as-world (csv:local-to-world pt (mat3-rz rot-rad) as-loc))) - (if es-loc (setq es-world (csv:local-to-world pt (mat3-rz rot-rad) es-loc))) + ;; die reine Z-Drehungsmatrix (mat3-rz). AS-Eingang = K1 (KS_EIN) des AS, + ;; ES-Ausgang = K2 (KS_AUS) des ES (csv:vfgf-element-punkte). + (setq R0 (mat3-rz rot-rad)) + (setq as-world (cdr (assoc "K1" (csv:vfgf-element-punkte bname pt R0 "AS_ELEMENT*")))) + (setq es-world (cdr (assoc "K2" (csv:vfgf-element-punkte bname pt R0 "ES_ELEMENT*")))) ;; Eingang/Ausgang festlegen (siehe Richtung im Kopfkommentar). (cond ;; GF: Richtung ueber die Hoehe - hoeheres Z = Eingang, tieferes Z = Ausgang. @@ -613,13 +717,9 @@ ;; VF/Strecke (und GF mit nur einem Ende): AS = Eingang, ES = Ausgang. (t (setq ein-world as-world aus-world es-world)) ) - (if ein-world - (setq result (cons (cons "K1" - (csv:trans-encode (car ein-world) (cadr ein-world) (caddr ein-world))) result))) - (if aus-world - (setq result (cons (cons "K2" - (csv:trans-encode (car aus-world) (cadr aus-world) (caddr aus-world))) result))) - (reverse result) + (if ein-world (setq result (cons (cons "K1" ein-world) result))) + (if aus-world (setq result (cons (cons "K2" aus-world) result))) + (csv:k-liste-kodieren (reverse result)) ) @@ -715,7 +815,7 @@ ;; --- K1/K2 eines ZZ_UNIT_MARKER lesen --- ;; Fallback fuer csv:block-to-json (siehe dort): die Werte stehen bereits -;; fertig kodiert in den ATTDEFs K1/K2 (siehe csv:unitmark-aktualisieren), +;; fertig kodiert in den ATTDEFs K1/K2 (siehe csv:ketten-verarbeiten), ;; hier nur noch als K-Liste im Format von csv:get-k-kos-strings verpackt. (defun csv:unitmark-k-kos-strings (ename / attribs k1 k2 result) (setq attribs (ssg-attrib-read ename)) @@ -734,8 +834,8 @@ ;; "k1".."k4" (KOS-Strings der Koordinatensysteme im Block, siehe ;; csv:get-k-kos-strings) werden immer geschrieben, unabhaengig von ;; include-bbox -- Kodierung ueber csv:kos-encode (siehe dort). -(defun csv:block-to-json (ename include-bbox / ed blk-name layer pt rotation extrusion R-world - handle attribs bbox bbox-json psx psy psz +(defun csv:block-to-json (ename include-bbox / ed blk-name layer pt rotation extrusion + handle attribs bbox bbox-json insert-quat insert-kos k-list warnung-json warnung-eintrag zuordnung-fix-json zuordnung-fix-eintrag strecke-typ-json strecke-typ-eintrag @@ -762,16 +862,14 @@ ;; Extrusion=(0 0 1) reduziert sich das exakt auf die alte Uebernahme. (setq extrusion (cond ((cdr (assoc 210 ed))) ('(0.0 0.0 1.0)))) (setq pt (mat3-mul-vec3 (mat3-ocs-matrix extrusion) pt)) - (setq R-world (mat3-from-normal-rotation extrusion rotation)) (setq attribs (csv:read-attribs ename)) (setq insert-quat (csv:z-angle-to-quat (* (/ rotation pi) 180.0))) (setq insert-kos (csv:kos-encode (car pt) (cadr pt) (if (caddr pt) (caddr pt) 0.0) (nth 0 insert-quat) (nth 1 insert-quat) (nth 2 insert-quat) (nth 3 insert-quat))) - (setq psx (cond ((cdr (assoc 41 ed))) (1.0))) - (setq psy (cond ((cdr (assoc 42 ed))) (1.0))) - (setq psz (cond ((cdr (assoc 43 ed))) (1.0))) - (setq k-list (csv:get-k-kos-strings ename pt R-world psx psy psz)) + ;; K1-K4: gemerkte Baustein-KS eines Stellvertreters (Separator-Symbol, + ;; AS-/ES-Marker) oder die KS der eigenen Blockdefinition - siehe csv:k-liste. + (setq k-list (csv:k-liste ename)) ;; Omniflo-Geraden fuehren keine echten K-Bloecke - K1/K2 aus der Geometrie ;; (Anfang/Ende ueber Laenge + Rotation) synthetisieren, damit sie im Export ;; wie echte Anschluss-Koordinatensysteme erscheinen und in der Nachbar- @@ -791,7 +889,7 @@ (setq k-list (csv:vfgf-k-kos-strings ename pt rotation)) ) ;; ZZ_UNIT_MARKER (Foerdereinheit/Gefaelleeinheit): K1/K2 stehen bereits - ;; fertig kodiert als eigene ATTDEFs am Marker (csv:unitmark-aktualisieren + ;; fertig kodiert als eigene ATTDEFs am Marker (csv:ketten-verarbeiten ;; berechnet sie einmal bei der Marker-Erzeugung aus dem ersten/letzten ;; zugeordneten Element) - keine erneute KS-Suche noetig. (if (and (null k-list) @@ -801,7 +899,9 @@ (setq bbox-json "") (if include-bbox (progn - (setq bbox (csv:get-bbox ename)) + ;; Stellvertreter im Modus all_elements: Boundingbox des umgebenden + ;; Bausteins (csv:baustein-merken), sonst die eigene. + (setq bbox (cond ((csv:baustein-bbox-gemerkt handle)) (t (csv:get-bbox ename)))) (if bbox (setq bbox-json (strcat @@ -1068,62 +1168,51 @@ ;; Rueckgabe: Liste von Records ;; (wrapper-ename nested-ent nested-bname (x y z) R sx sy sz) ;; mit der fertigen Weltlage jedes Fundes (R = volle 3x3-Orientierung). -(defun csv:nested-welt-records (nested-pattern - / ss-all i ename ed bname nested pt rotation - extrusion0 R0 psx psy psz rec nested-ent nested-bname - local-pt R-nested R-final scaled-pt rot-pt world-pt - records) +(defun csv:nested-welt-records (nested-pattern / ss-all i ename records) (setq ss-all (ssget "X" (list (cons 0 "INSERT")))) (if ss-all (progn (setq i 0) (while (setq ename (ssname ss-all i)) - (setq ed (entget ename)) - (setq bname (cdr (assoc 2 ed))) - (setq nested - (if (wcmatch bname (csv:pattern-wrapper-fuer-proxies)) - (ssg-collect-nested-inserts bname nested-pattern) - ) - ) - (if nested - (progn - (setq pt (cdr (assoc 10 ed))) - (if (null (caddr pt)) (setq pt (list (car pt) (cadr pt) 0.0))) - (setq rotation (cond ((cdr (assoc 50 ed))) (0.0))) - ;; Extrusion des Wrapper-INSERTs selbst beruecksichtigen statt - ;; reine Z-Drehung anzunehmen - GF_n/VF_n stehen zwar bisher immer - ;; flach (Extrusion (0 0 1)), aber mat3-from-normal-rotation - ;; reduziert sich dafuer ohnehin exakt auf Rz(rotation), kostet - ;; also nichts und macht den Code robust falls sich das aendert. - (setq extrusion0 (cond ((cdr (assoc 210 ed))) ('(0.0 0.0 1.0)))) - (setq R0 (mat3-from-normal-rotation extrusion0 rotation)) - (setq psx (cond ((cdr (assoc 41 ed))) (1.0))) - (setq psy (cond ((cdr (assoc 42 ed))) (1.0))) - (setq psz (cond ((cdr (assoc 43 ed))) (1.0))) - (foreach rec nested - (setq nested-ent (nth 0 rec)) - (setq local-pt (nth 1 rec)) - (setq R-nested (nth 2 rec)) - (setq nested-bname (cdr (assoc 2 (entget nested-ent)))) - (setq scaled-pt (list (* psx (car local-pt)) - (* psy (cadr local-pt)) - (* psz (caddr local-pt)))) - (setq rot-pt (mat3-mul-vec3 R0 scaled-pt)) - (setq world-pt (list (+ (car pt) (car rot-pt)) - (+ (cadr pt) (cadr rot-pt)) - (+ (caddr pt) (caddr rot-pt)))) - (setq R-final (mat3-mul-mat3 R0 R-nested)) - (setq records - (cons (list ename nested-ent nested-bname world-pt R-final - (* psx (nth 3 rec)) (* psy (nth 4 rec)) (* psz (nth 5 rec))) - records)) - ) - ) - ) + (if (wcmatch (cdr (assoc 2 (entget ename))) (csv:pattern-wrapper-fuer-proxies)) + (setq records (append records (csv:wrapper-welt-records ename nested-pattern)))) (setq i (1+ i)) ) ) ) + records +) + +;; --- Verpackte Sub-INSERTs EINES Wrapper-INSERT in Weltlage --- +;; Wie csv:nested-welt-records, aber nur fuer den Wrapper ename (gleiches +;; Record-Format). Genutzt von csv:nested-welt-records und von der +;; Einheiten-Gruppierung (csv:kette-teile), die je VF_n/GF_n arbeitet. +(defun csv:wrapper-welt-records (ename nested-pattern / ed nested pt extrusion0 R0 + psx psy psz rec records) + (setq ed (entget ename)) + (setq nested (ssg-collect-nested-inserts (cdr (assoc 2 ed)) nested-pattern)) + (if nested + (progn + (setq pt (cdr (assoc 10 ed))) + (if (null (caddr pt)) (setq pt (list (car pt) (cadr pt) 0.0))) + ;; Extrusion des Wrapper-INSERTs selbst beruecksichtigen statt reine + ;; Z-Drehung anzunehmen - GF_n/VF_n stehen zwar bisher immer flach + ;; (Extrusion (0 0 1)), aber mat3-from-normal-rotation reduziert sich + ;; dafuer ohnehin exakt auf Rz(rotation), kostet also nichts und macht + ;; den Code robust falls sich das aendert. + (setq extrusion0 (cond ((cdr (assoc 210 ed))) ('(0.0 0.0 1.0)))) + (setq R0 (mat3-from-normal-rotation extrusion0 (cond ((cdr (assoc 50 ed))) (0.0)))) + (setq psx (cond ((cdr (assoc 41 ed))) (1.0))) + (setq psy (cond ((cdr (assoc 42 ed))) (1.0))) + (setq psz (cond ((cdr (assoc 43 ed))) (1.0))) + (foreach rec nested + (setq records + (cons (append (list ename (nth 0 rec) (cdr (assoc 2 (entget (nth 0 rec))))) + (csv:record-welt-lage pt R0 psx psy psz rec)) + records)) + ) + ) + ) (reverse records) ) @@ -1202,21 +1291,35 @@ "Staustrecke_Separator_SP_300_mm*" ) -;; --- Naechstliegenden Record aus einer csv:nested-welt-records-Liste zu -;; einem Weltpunkt finden --- (planare Distanz x/y reicht: die Symbole -;; sitzen praktisch am selben Punkt wie ihr Verpacker, siehe -;; csv:pattern-nested-separator-aussen) -(defun csv:nested-record-naechster (pt records / best best-d rec dx dy d) - (setq best nil best-d nil) - (foreach rec records - (setq dx (- (car (nth 3 rec)) (car pt))) - (setq dy (- (cadr (nth 3 rec)) (cadr pt))) - (setq d (+ (* dx dx) (* dy dy))) - (if (or (null best-d) (< d best-d)) - (progn (setq best rec) (setq best-d d)) - ) - ) - best +;; --- Trennsteg (Staustrecke_Separator_SP_300_mm) zu einem Separator_SP- +;; Symbol finden --- +;; sym-pt = Weltposition des Symbols (csv:nested-welt-records). +;; aussen-paare = Liste ((symbol-weltpunkt . trennsteg-record) ...), siehe +;; csv:trennsteg-paare. +;; Zugeordnet wird der Trennsteg, dessen EIGENES Symbol an sym-pt liegt +;; (Toleranz 1 mm) - NICHT der mit dem naechstliegenden Ursprung: das Symbol +;; sitzt 235 mm vom Ursprung seines Trennstegs, aber nur 65 mm vom Ursprung +;; des folgenden Bausteins; folgen zwei Trennstege aufeinander, griff die +;; Ursprungsnaehe den falschen. Ein Symbol ohne Trennsteg (Kreisel-Separator) +;; bekommt nil. +(defun csv:trennsteg-zu-symbol (sym-pt aussen-paare / treffer paar) + (foreach paar aussen-paare + (if (and (null treffer) (< (distance sym-pt (car paar)) 1.0)) + (setq treffer (cdr paar)))) + treffer +) + +;; --- Je Trennsteg-Record die Weltlage seines eingebauten Separator_SP- +;; Symbols berechnen --- Rueckgabe: ((symbol-weltpunkt . record) ...). +(defun csv:trennsteg-paare (recs-aussen / rec sym lage paare) + (foreach rec recs-aussen + (setq sym (car (ssg-collect-nested-inserts (nth 2 rec) (csv:pattern-nested-separator)))) + (if sym + (progn + (setq lage (csv:record-welt-lage (nth 3 rec) (nth 4 rec) + (nth 5 rec) (nth 6 rec) (nth 7 rec) sym)) + (setq paare (cons (cons (car lage) rec) paare))))) + (reverse paare) ) ;; --- Temporaere Kopie je verpacktem Separator_SP-Symbol --- @@ -1225,7 +1328,10 @@ ;; Die AS-/ES-Kettenenden laufen NICHT mehr hierueber - fuer sie setzt ;; csv:asmark-aktualisieren einen dauerhaften Marker (siehe dort). ;; -;; proxy-liste-Eintrag: (proxy-ename wrapper-ename typ (x y z) strecke-typ). +;; proxy-liste-Eintrag: (proxy-ename wrapper-ename typ (x y z) strecke-typ +;; trennsteg-ent) - trennsteg-ent = der verpackte Trennsteg (Kettenbaustein, +;; Schluessel fuer die ID-Vergabe in Kettenfolge, csv:ketten-ids-vergeben), +;; nil fuer ein Symbol ohne Trennsteg (Kreisel-Separator). ;; strecke-typ = "VF"/"GF"/nil, gelesen von ssg-sep-typ-xdata-lesen AM ;; AEUSSEREN Trennsteg-Insert (csv:pattern-nested-separator-aussen), NICHT am ;; Separator_SP-Symbol selbst (das ist Block-Definitions-geteilt, siehe dort) @@ -1235,22 +1341,28 @@ ;; Marker sitzt daher direkt am jeweiligen Separator-Insert (gesetzt bauzeitig ;; in vf_linienzug.lsp/Gefaellestrecke.lsp/vf_standard.lsp/vf_etage.lsp, ;; direkt nach dessen Einfuegung). Zuordnung Symbol<->Trennsteg ueber die -;; naechstliegende Weltposition (beide sitzen praktisch am selben Punkt). -(defun csv:sep-proxies-erzeugen ( / ms recs recs-aussen rec aussen-rec proxy proxy-liste) +;; Symbollage innerhalb des Trennstegs (csv:trennsteg-zu-symbol). +(defun csv:sep-proxies-erzeugen ( / ms recs aussen-paare rec aussen-rec proxy proxy-liste) (setq recs (csv:nested-welt-records (csv:pattern-nested-separator))) - (setq recs-aussen (csv:nested-welt-records (csv:pattern-nested-separator-aussen))) + (setq aussen-paare (csv:trennsteg-paare + (csv:nested-welt-records (csv:pattern-nested-separator-aussen)))) (if recs (progn (setq ms (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object)))) (foreach rec recs - (setq aussen-rec (csv:nested-record-naechster (nth 3 rec) recs-aussen)) + (setq aussen-rec (csv:trennsteg-zu-symbol (nth 3 rec) aussen-paare)) (setq proxy (csv:block-einfuegen-welt ms (nth 2 rec) (nth 3 rec) (nth 4 rec) (nth 5 rec) (nth 6 rec) (nth 7 rec) (cdr (assoc 2 (entget (nth 0 rec)))))) + ;; all_elements: K1/K2 + Boundingbox der Zeile = die des Trennstegs + ;; (der Kettenbaustein) statt des Symbols - siehe csv:baustein-merken. + (if (and proxy aussen-rec (csv:export-alle-elemente-p)) + (csv:baustein-merken proxy aussen-rec)) (if proxy (setq proxy-liste (cons (list proxy (nth 0 rec) (csv:proxy-typ (nth 2 rec)) (nth 3 rec) - (if aussen-rec (ssg-sep-typ-xdata-lesen (nth 1 aussen-rec)))) + (if aussen-rec (ssg-sep-typ-xdata-lesen (nth 1 aussen-rec))) + (if aussen-rec (nth 1 aussen-rec))) proxy-liste))) ) ) @@ -1267,7 +1379,9 @@ ;; LAYER kommen direkt aus den ATTDEFs der kopierten Original-Blockdefinition ;; (ssg-attrib-read auf die Kopie), wie bei Separator. ;; -;; proxy-liste-Eintrag: (proxy-ename wrapper-ename teileart-key (x y z)). +;; proxy-liste-Eintrag: (proxy-ename wrapper-ename teileart-key (x y z) +;; baustein-ent) - baustein-ent = der verpackte Baustein (Schluessel fuer die +;; ID-Vergabe in Kettenfolge, csv:ketten-ids-vergeben). ;; teileart-key (aus csv:element-teileart) wird NICHT ins JSON geschrieben - ;; Python klassifiziert die TeileArt ohnehin ueber block_name + die vier ;; pattern_nested_*-Keys aus cfg/export.cfg, wie jede andere Familie auch. @@ -1282,7 +1396,8 @@ (cdr (assoc 2 (entget (nth 0 rec)))))) (if proxy (setq proxy-liste - (cons (list proxy (nth 0 rec) (csv:element-teileart (nth 2 rec)) (nth 3 rec)) + (cons (list proxy (nth 0 rec) (csv:element-teileart (nth 2 rec)) (nth 3 rec) + (nth 1 rec)) proxy-liste))) ) ) @@ -1305,17 +1420,28 @@ ;; "csv_leave_proxies" (ssg_dbg.lsp) - dieser bleibt unveraendert und ;; steuert weiterhin zusaetzlich auch die Separator-Proxies ;; (csv:sep-proxies-loeschen). -(defun csv:element-proxies-loeschen (proxy-liste / behalten) - (setq behalten (or *csv-export-elemente-behalten* - *csv-export-pruef-zuordnung* +(defun csv:element-proxies-loeschen (proxy-liste art-key) + (csv:hilfskopien-loeschen proxy-liste art-key + (or *csv-export-elemente-behalten* *csv-export-pruef-zuordnung*)) +) + +;; --- Gemeinsame Loeschung aller Export-Hilfskopien --- +;; proxy-liste = Records, deren car die Hilfskopie ist. +;; art-key = Sprachschluessel der Objektart fuer die Meldung +;; ("exp-art-separator"/"exp-art-element"/"exp-art-einheit"). +;; zusaetzlich = weiterer Behalten-Grund (Konfig-Haken) oder nil. +;; Behalten, wenn der Debug-Schalter "csv_leave_proxies" gesetzt ist oder +;; zusaetzlich zutrifft - dann eine Meldung je Art (nur wenn es welche gibt). +(defun csv:hilfskopien-loeschen (proxy-liste art-key zusaetzlich / behalten) + (setq behalten (or zusaetzlich (and (car (atoms-family 1 '("DBG-SCHALTER-P"))) (dbg-schalter-p "csv_leave_proxies")))) - (if behalten - (princ (strcat "\n[EXPORT] csv_leave_proxies=1: " - (itoa (length proxy-liste)) - " Element-Proxy-Kopie(n) bleiben in der Zeichnung" - " (Abschalten: (dbg-schalter-off \"csv_leave_proxies\"))")) - (foreach rec proxy-liste (entdel (car rec))) + (cond + ((null proxy-liste)) + (behalten + (princ (ssg-textf "exp-hilfskopien-behalten" + (list (itoa (length proxy-liste)) (ssg-text art-key))))) + (t (foreach rec proxy-liste (entdel (car rec)))) ) (princ) ) @@ -1567,267 +1693,142 @@ ) ;; =========================================================================== -;; Foerdereinheit/Gefaelleeinheit-Gruppierung (ZZ_UNIT_MARKER) +;; Foerdereinheit/Gefaelleeinheit-Gruppierung (Modus group_vf_gf) ;; =========================================================================== -;; Fasst die Einzelbausteine einer VF_n/GF_n-Kette (Boegen, Strecken, Umlenk-/ -;; Motorstation, siehe csv:element-proxies-erzeugen) wieder zu Einheiten -;; zusammen: abwechselnd Foerdereinheit (VF) / Gefaelleeinheit (GF), je EINE -;; Zeile mit K1 vom ersten, K2 vom letzten enthaltenen Element. Laeuft rein -;; export-seitig (kein Bau-Code-Eingriff) - Einheiten-Grenzen kommen aus der -;; sepliste (SEP/AS/ES in echter Bau-Reihenfolge, XDATA-lfdnr) plus dem -;; bereits vorhandenen SSG_SEP_TYP je Separator (VF/GF), NICHT aus der -;; unzuverlaessigen csv:nested-welt-records-Listenreihenfolge (siehe -;; Kommentar dort - fuer einen einzelnen Wrapper doppelt umgekehrt) und NICHT -;; aus L_VF_m/L_GF_m (die zaehlen pro Segment, nicht pro Einheit - ein VF- -;; Einheit kann mehrere L_VF_m-Eintraege haben, GF1/GF2-Rampen einer VF- -;; Einheit landen im selben L_GF_m wie eigenstaendige GF-Stuecke, siehe -;; vfl-block-erstellen-Kommentar in vf_linienzug.lsp). +;; Eine VF_n/GF_n-Kette besteht abwechselnd aus Gefaelle- und Foerder- +;; abschnitten (GF, VF, GF, ...) - so baut der Linienzug sie auch iterativ auf. +;; Ein Foerderabschnitt (VF) ist eindeutig an seinen Stationen erkennbar: er +;; BEGINNT am Separator direkt vor der Umlenkstation und ENDET an der +;; Motorstation. Alles dazwischen ist Gefaelle (GF). Beide koennen um Kurven +;; laufen - darum wird die Reihenfolge NICHT ueber Projektion oder die +;; sepliste-XDATA bestimmt, sondern als Vektorkette entlang der KS: auf K2 +;; (KS_AUS) eines Bausteins liegt exakt K1 (KS_EIN) des naechsten. +;; +;; csv:kette-teile - Bausteine eines Wrappers mit Typ, Welt-Record, K1/K2 +;; csv:kette-ordnen - in Foerderrichtung ordnen (Start AS, K2 -> K1) +;; csv:kette-einheiten- Typfolge in VF-/GF-Einheiten schneiden (reine +;; Rechenfunktion, getestet in tests/test_unit.lsp) +;; csv:unitmark-erzeugen (weiter unten) - je Einheit ein Proxy-Rechteck -;; --- Sepliste-Eintraege um strecke-typ und verlaessliche Weltposition -;; anreichern --- -;; sepliste = ((typ lfdnr x y) ...) wie ssg-sepliste-xdata-lesen liefert -;; (XDATA-Ebene - deren x/y sind der ROHE Gruppencode-10-Punkt -;; des Bau-Primitivs und koennen gespiegelt/verschoben sein, -;; siehe die sepliste-x/y-Bereinigung im JSON-Export; hier NICHT -;; als Positionsquelle verwendet, nur zur Paarung mit dem echten -;; Proxy per csv:sepliste-paare, wie an anderer Stelle bereits -;; etabliert). -;; sep-proxies-eigene = NUR die sep-proxies-Records (siehe -;; csv:sep-proxies-erzeugen) DIESES Wrappers, in -;; Erzeugungsreihenfolge. -;; asmarks-eigene = NUR die asmark-Records (marker-ename wrapper-ename -;; typ lfdnr) DIESES Wrappers, aus csv:asmark-aktualisieren. -;; Rueckgabe: ((typ lfdnr strecke-typ welt-pt) ...) in lfdnr-Reihenfolge. -;; strecke-typ = nil fuer AS/ES (wird von csv:sepliste-partition vom -;; Nachbarn geerbt) bzw. fuer einen SEP-Eintrag ohne gefundenen Partner. -;; welt-pt = (x y z) der ECHTEN, verlaesslichen Proxy-/Marker-Position (SEP -;; ueber sep-proxies-eigene, AS/ES ueber den asmark-Entity-Einfuegepunkt), -;; oder nil, falls kein Partner gefunden wurde. -(defun csv:sepliste-mit-strecke-typ (sepliste sep-proxies-eigene asmarks-eigene - / proxies paare paar-by-lfdnr paar erg e - strecke-typ welt-pt m) - (setq proxies - (mapcar (function (lambda (r) (list (nth 2 r) (car (nth 3 r)) (cadr (nth 3 r))))) - sep-proxies-eigene)) - (setq paare (csv:sepliste-paare sepliste proxies)) - (setq paar-by-lfdnr nil) - (foreach paar paare - (setq paar-by-lfdnr (cons (cons (nth 0 paar) (nth 1 paar)) paar-by-lfdnr))) - (setq erg nil) - (foreach e sepliste - (setq strecke-typ nil welt-pt nil) - (cond - ((= (nth 0 e) "SEP") - (setq paar (assoc (nth 1 e) paar-by-lfdnr)) - (if paar - (progn - (setq strecke-typ (nth 4 (nth (cdr paar) sep-proxies-eigene))) - (setq welt-pt (nth 3 (nth (cdr paar) sep-proxies-eigene))) - ) - ) - ) - ((member (nth 0 e) (list "AS" "ES")) - (setq m nil) - (foreach kand asmarks-eigene - (if (and (null m) (= (nth 2 kand) (nth 0 e)) - (= (nth 3 kand) (itoa (nth 1 e)))) - (setq m kand))) - (if m (setq welt-pt (cdr (assoc 10 (entget (nth 0 m)))))) - ) - ) - (setq erg (cons (list (nth 0 e) (nth 1 e) strecke-typ welt-pt) erg)) - ) - (reverse erg) -) +;; Toleranz (mm), innerhalb der K2 eines Bausteins als K1 des naechsten gilt. +(defun csv:kette-toleranz-mm () 2.0) -;; --- Ersten SEP-typ in der Liste finden (Vorschau fuer AS) --- -;; Eine Kette beginnt immer mit einer Foerdereinheit (AS haengt am ersten -;; SEP-Eintrag, falls vorhanden) - Default "VF", falls die Kette gar keinen -;; Separator hat (reine Foerdereinheit ohne jeden Zwischenhalt). -(defun csv:sepliste-erster-sep-typ (sepliste-typisiert / e) - (setq e (car sepliste-typisiert)) +;; --- Bausteintyp aus dem Blocknamen --- +;; "AS"/"ES"/"SEP" wie csv:proxy-typ, sonst die Familien aus +;; csv:element-teileart (BOGEN/STRECKENELEMENT/UMLENKSTATION/MOTORSTATION). +(defun csv:kette-typ (bname / bn) + (setq bn (strcase bname)) (cond - ((null e) "VF") - ((and (= (nth 0 e) "SEP") (nth 2 e)) (nth 2 e)) - (t (csv:sepliste-erster-sep-typ (cdr sepliste-typisiert))) + ((wcmatch bn "AS_ELEMENT*") "AS") + ((wcmatch bn "ES_ELEMENT*") "ES") + ((wcmatch bn (strcase (csv:pattern-nested-separator-aussen))) "SEP") + (t (csv:element-teileart bname)) ) ) -;; --- Sepliste (mit strecke-typ) in Einheiten-Spannen partitionieren --- -;; sepliste-typisiert = ((typ lfdnr strecke-typ welt-pt) ...) in lfdnr- -;; Reihenfolge (Rueckgabe von csv:sepliste-mit-strecke-typ). -;; -;; Lauflaengen-Kodierung ueber den EFFEKTIVEN Typ jedes Eintrags, EIN -;; Vorwaerts-Durchlauf mit einer einzigen mitgefuehrten Zustandsvariable -;; "aktueller-typ" (das strecke-typ des zuletzt gesehenen SEP-Eintrags): -;; - AS: effektiver Typ = das strecke-typ des ERSTEN SEP-Eintrags der -;; ganzen Kette (Vorschau, csv:sepliste-erster-sep-typ) - eine Kette -;; beginnt immer mit einer Foerdereinheit. -;; - SEP: effektiver Typ = sein eigenes strecke-typ (faellt es aus - alter -;; Bestand ohne Marker -, bleibt der zuletzt bekannte Typ stehen). -;; "aktueller-typ" wird auf diesen Wert aktualisiert. -;; - ES: effektiver Typ = "aktueller-typ" (der zuletzt gesehene SEP, -;; also die Einheit, die gerade offen ist). -;; Eine neue Einheit beginnt, sobald sich der effektive Typ gegenueber dem -;; Vorgaenger aendert; gleich bleibender Typ (inkl. zwei aufeinanderfolgender -;; SEP-Eintraege desselben Typs, die GEMEINSAM eine einzige Einheit -;; bracketieren - HundM05-Beispiel: SEP3=GF,SEP4=GF sind EINE Gefaelleeinheit) -;; haengt an die offene Einheit an. Kein Sonderfall-Code fuer "erster/zweiter -;; SEP dieses Typs" noetig - die Lauflaengen-Regel deckt beides ab. -;; -;; Rueckgabe: ((einheit-typ (lfdnr ...)) ...) in Kettenreihenfolge. -;; Reine Rechenfunktion (keine Zeichnung, keine Datei) - getestet in -;; tests/test_unit.lsp. -(defun csv:sepliste-partition (sepliste-typisiert / erg e eff aktueller-typ - offen-typ offen-lfdnrs) - (setq aktueller-typ (csv:sepliste-erster-sep-typ sepliste-typisiert)) - (setq erg nil offen-typ nil offen-lfdnrs nil) - (foreach e sepliste-typisiert - (cond - ((= (nth 0 e) "SEP") - (setq aktueller-typ (cond ((nth 2 e)) (aktueller-typ))) - (setq eff aktueller-typ)) - (t (setq eff aktueller-typ)) - ) - (if (and offen-typ (/= eff offen-typ)) +;; --- Alle Kettenbausteine eines VF_n/GF_n-Wrappers --- +;; Rueckgabe: Liste von (typ rec k1 k2) - rec wie csv:nested-welt-records, +;; k1/k2 = Weltpunkte von KS_EIN/KS_AUS (csv:ks-welt-punkte) oder nil. +;; Gesucht wird der Trennsteg (nicht das Separator-Symbol darin): er ist der +;; Kettenbaustein, ssg-collect-nested-inserts steigt bei ihm nicht weiter ab. +(defun csv:kette-teile (wrapper / rec punkte typ teile) + (foreach rec (csv:wrapper-welt-records wrapper + (strcat (csv:pattern-nested-schleus) "," + (csv:pattern-nested-separator-aussen) "," + (csv:pattern-nested-element))) + (setq typ (csv:kette-typ (nth 2 rec))) + (if typ (progn - (setq erg (cons (list offen-typ (reverse offen-lfdnrs)) erg)) - (setq offen-typ nil offen-lfdnrs nil) - ) - ) - (setq offen-typ eff) - (setq offen-lfdnrs (cons (nth 1 e) offen-lfdnrs)) + (setq punkte (csv:ks-welt-punkte (nth 2 rec) (nth 3 rec) (nth 4 rec) + (nth 5 rec) (nth 6 rec) (nth 7 rec))) + (setq teile (cons (list typ rec (cdr (assoc "K1" punkte)) (cdr (assoc "K2" punkte))) + teile)))) ) - (if offen-typ - (setq erg (cons (list offen-typ (reverse offen-lfdnrs)) erg))) + (reverse teile) +) + +;; --- Nachfolger eines Bausteins: der, dessen K1 auf k2 liegt --- +(defun csv:kette-nachfolger (k2 teile / treffer tol) + (setq tol (csv:kette-toleranz-mm)) + (if k2 + (foreach t1 teile + (if (and (null treffer) (nth 2 t1) (< (distance k2 (nth 2 t1)) tol)) + (setq treffer t1)))) + treffer +) + +;; --- Anfang einer (Teil-)Kette: bevorzugt das AS, sonst ein Baustein, auf +;; dessen K1 kein K2 eines anderen liegt --- +(defun csv:kette-anfang (teile / anfang tol) + (setq tol (csv:kette-toleranz-mm)) + (foreach t1 teile + (if (and (null anfang) (= (car t1) "AS")) (setq anfang t1))) + (foreach t1 teile + (if (and (null anfang) + (not (vl-some (function (lambda (t2) + (and (not (eq t1 t2)) (nth 3 t2) (nth 2 t1) + (< (distance (nth 3 t2) (nth 2 t1)) tol)))) + teile))) + (setq anfang t1))) + (cond (anfang) ((car teile))) +) + +;; --- Bausteine in Foerderrichtung ordnen (Vektorkette K2 -> K1) --- +;; Beginnt am AS und haengt jeweils den Baustein an, dessen K1 auf dem K2 des +;; letzten liegt. Reisst die Kette ab (Baustein ohne KS, Luecke > Toleranz), +;; wird das gemeldet und mit dem Rest als neue Teilkette weitergemacht - kein +;; Baustein geht verloren, die Einheitengrenzen koennen dort aber falsch sein. +;; kontext = Blockname des Wrappers (nur fuer die Meldung). +(defun csv:kette-ordnen (teile kontext / rest geordnet aktuell naechster) + (setq rest teile) + (while rest + (if geordnet + (princ (ssg-textf "exp-kette-luecke" (list kontext (itoa (length rest)))))) + (setq aktuell (csv:kette-anfang rest)) + (while aktuell + (setq geordnet (cons aktuell geordnet)) + (setq rest (vl-remove aktuell rest)) + (setq naechster (csv:kette-nachfolger (nth 3 aktuell) rest)) + (setq aktuell naechster) + ) + ) + (reverse geordnet) +) + +;; --- Typfolge einer geordneten Kette in VF-/GF-Einheiten schneiden --- +;; typen = Liste der Bausteintypen in Foerderrichtung (siehe csv:kette-typ). +;; Regeln: +;; - AS/ES gehoeren zu keiner Einheit (eigene Export-Zeilen). +;; - Eine VF beginnt an einem SEP, dem direkt eine UMLENKSTATION folgt, +;; bzw. an einer UMLENKSTATION ohne solchen SEP davor, und endet MIT der +;; naechsten MOTORSTATION. +;; - Alles andere sammelt sich zu einer GF zwischen den VFs. +;; Rueckgabe: ((einheit-typ (index ...)) ...) mit 0-basierten Indizes in +;; typen, in Kettenreihenfolge; leere Einheiten entstehen nicht. +(defun csv:kette-einheiten (typen / erg i typ naechster offen-typ offen) + (setq i 0 offen-typ "GF") + (while (< i (length typen)) + (setq typ (nth i typen) naechster (nth (1+ i) typen)) + (cond + ((member typ '("AS" "ES"))) + ;; VF-Beginn: SEP vor Umlenkstation oder Umlenkstation selbst + ((and (/= offen-typ "VF") + (or (and (= typ "SEP") (= naechster "UMLENKSTATION")) + (= typ "UMLENKSTATION"))) + (if offen (setq erg (cons (list offen-typ (reverse offen)) erg))) + (setq offen-typ "VF" offen (list i))) + ;; VF-Ende: die Motorstation gehoert noch dazu + ((and (= offen-typ "VF") (= typ "MOTORSTATION")) + (setq erg (cons (list "VF" (reverse (cons i offen))) erg)) + (setq offen-typ "GF" offen nil)) + (t (setq offen (cons i offen))) + ) + (setq i (1+ i)) + ) + (if offen (setq erg (cons (list offen-typ (reverse offen)) erg))) (reverse erg) ) -;; --- Weltposition eines sepliste-lfdnr aus der typisierten Liste holen --- -(defun csv:sepliste-typisiert-pos (lfdnr sepliste-typisiert / treffer) - (setq treffer nil) - (foreach e sepliste-typisiert - (if (and (null treffer) (= (nth 1 e) lfdnr)) (setq treffer e))) - (if treffer (nth 3 treffer)) -) - -;; --- 2D-Skalarprodukt zweier Vektoren (x y) --- -(defun csv:dot2 (a b) (+ (* (car a) (car b)) (* (cadr a) (cadr b)))) - -;; --- Elemente den Einheiten-Spannen zuordnen --- -;; unit-spans = Rueckgabe von csv:sepliste-partition: -;; ((einheit-typ (lfdnr ...)) ...). -;; sepliste-typisiert = Rueckgabe von csv:sepliste-mit-strecke-typ (liefert -;; die Weltposition jedes Rand-lfdnr). -;; element-proxies-eigene = NUR die element-proxies-Records (siehe -;; csv:element-proxies-erzeugen) DIESES Wrappers, -;; (proxy-ename wrapper-ename teileart-key (x y z)). -;; -;; Vorgehen: fuer jede Spanne den ERSTEN und LETZTEN Rand-lfdnr in eine -;; Weltposition aufloesen (Start-/Endpunkt der Spanne entlang der Kette). -;; Kettenrichtung = Einheitsvektor vom allerersten zum allerletzten -;; Rand-lfdnr der GESAMTEN sepliste (AS->ES). Jedes Element wird per -;; Skalarprodukt auf diese Richtung projiziert (t-Wert) und der Spanne -;; zugeordnet, deren [t-start,t-ende]-Intervall am naechsten liegt (bei -;; eindeutiger Enthaltung: diese Spanne; sonst die mit dem kleinsten -;; Abstand zum naeheren Rand - kein Element bleibt unzugeordnet). -;; -;; Rueckgabe: Liste parallel zu unit-spans, je Spanne eine Liste -;; zugeordneter element-proxies-Records. -(defun csv:element-unit-zuordnung (unit-spans sepliste-typisiert - element-proxies-eigene / grenzen span - lfdnrs start-pos ende-pos richtung - erste-pos letzte-pos laenge t-werte - erg elem t-elem beste-i beste-abstand i - t-start t-ende abstand) - ;; Kettenrichtung ueber den allerersten/allerletzten Rand-lfdnr der - ;; gesamten sepliste bestimmen (nicht nur der ersten/letzten Spanne - bei - ;; einer Kette mit nur einer Spanne sind das dieselben Werte). - (setq erste-pos nil letzte-pos nil) - (foreach e sepliste-typisiert - (if (and (null erste-pos) (nth 3 e)) (setq erste-pos (nth 3 e)))) - (foreach e (reverse sepliste-typisiert) - (if (and (null letzte-pos) (nth 3 e)) (setq letzte-pos (nth 3 e)))) - (if (or (null erste-pos) (null letzte-pos) - (< (distance erste-pos letzte-pos) 1e-6)) - ;; Entartete Kette (kein Rand-Punkt aufloesbar, oder AS=ES-Position) - - ;; keine sinnvolle Projektion moeglich, jede Spanne bekommt keine - ;; Elemente zugeordnet (Aufrufer behandelt das wie "keine Elemente"). - (setq richtung '(1.0 0.0)) - (progn - (setq richtung (list (- (car letzte-pos) (car erste-pos)) - (- (cadr letzte-pos) (cadr erste-pos)))) - (setq laenge (sqrt (csv:dot2 richtung richtung))) - (if (> laenge 1e-6) - (setq richtung (list (/ (car richtung) laenge) (/ (cadr richtung) laenge))) - (setq richtung '(1.0 0.0)) - ) - ) - ) - ;; Je Spanne: [t-start, t-ende] aus dem ersten/letzten Rand-lfdnr. - (setq grenzen nil) - (foreach span unit-spans - (setq lfdnrs (cadr span)) - (setq start-pos (csv:sepliste-typisiert-pos (car lfdnrs) sepliste-typisiert)) - (setq ende-pos (csv:sepliste-typisiert-pos (last lfdnrs) sepliste-typisiert)) - (setq t-start - (if start-pos - (csv:dot2 (list (- (car start-pos) (car erste-pos)) - (- (cadr start-pos) (cadr erste-pos))) richtung) - 0.0)) - (setq t-ende - (if ende-pos - (csv:dot2 (list (- (car ende-pos) (car erste-pos)) - (- (cadr ende-pos) (cadr erste-pos))) richtung) - 0.0)) - (setq grenzen (cons (list (min t-start t-ende) (max t-start t-ende)) grenzen)) - ) - (setq grenzen (reverse grenzen)) - ;; Je Element: t-Wert projizieren, naechstliegende Spanne waehlen. Jeder - ;; Eintrag wird zunaechst als (t-elem . elem) gefuehrt, damit die Spanne - ;; am Ende NACH t SORTIERT werden kann - das liefert "erstes"/"letztes" - ;; Element einer Spanne entlang der Kettenrichtung (fuer K1/K2 der - ;; Einheiten-Zeile, siehe csv:unitmark-aktualisieren), ohne auf die - ;; unzuverlaessige csv:nested-welt-records-Reihenfolge angewiesen zu sein. - (setq erg nil) - (foreach span unit-spans (setq erg (cons nil erg))) - (setq erg (reverse erg)) - (foreach elem element-proxies-eigene - (setq t-elem - (csv:dot2 (list (- (car (nth 3 elem)) (car erste-pos)) - (- (cadr (nth 3 elem)) (cadr erste-pos))) richtung)) - (setq beste-i 0 beste-abstand nil i 0) - (foreach g grenzen - (setq abstand - (cond - ((and (>= t-elem (car g)) (<= t-elem (cadr g))) 0.0) - ((< t-elem (car g)) (- (car g) t-elem)) - (t (- t-elem (cadr g))) - )) - (if (or (null beste-abstand) (< abstand beste-abstand)) - (progn (setq beste-abstand abstand) (setq beste-i i))) - (setq i (1+ i)) - ) - (setq erg (csv:liste-setzen erg beste-i (cons (cons t-elem elem) (nth beste-i erg)))) - ) - ;; Je Spanne nach t sortieren, dann den t-Wert wieder abstreifen. - (mapcar - (function (lambda (paare) - (mapcar 'cdr (vl-sort paare (function (lambda (a b) (< (car a) (car b)))))))) - erg) -) - -;; --- Element einer Liste an Index i ersetzen (0-basiert) --- -;; Kleiner Hilfsbaustein, da AutoLISP kein eingebautes "setf (nth i lst)" hat. -(defun csv:liste-setzen (lst i wert / j out) - (setq out nil j 0) - (foreach e lst - (setq out (cons (if (= j i) wert e) out)) - (setq j (1+ j)) - ) - (reverse out) -) - ;; --- Bounding-Box-Vereinigung mehrerer Entities --- ;; Verallgemeinert csv:get-bbox (siehe dort) von einer Entity auf eine Liste: ;; min/max ueber alle vla-getboundingbox-Ergebnisse, gleiche Fehler- @@ -2115,7 +2116,15 @@ (cons "ELEMENT" (nth 2 elem)) (cons "ARTINR" artinr))) (ssg-layer-setzen mark "ases_marker") - (setq ergebnis (cons (list mark wrapper typ lfdnr) ergebnis)) + ;; all_elements/group_vf_gf: K1/K2 + Boundingbox der Zeile = + ;; die des echten AS-/ES-Elements (der Marker selbst traegt + ;; keine KS) - AS: Kreisel -> Kettenanfang, ES: Kettenende -> + ;; Kreisel. Siehe csv:baustein-merken. + (if (not (csv:export-separator-track-p)) + (csv:baustein-merken mark elem)) + ;; 5. Feld: das verpackte Element (Schluessel fuer die ID- + ;; Vergabe in Kettenfolge, csv:ketten-ids-vergeben). + (setq ergebnis (cons (list mark wrapper typ lfdnr (nth 1 elem)) ergebnis)) ) ) ) @@ -2184,16 +2193,8 @@ ;; sepliste-Koordinaten pruefen laesst. *cs-sep-fix-by-handle* und ;; *csv-sepliste-id-by-handle* werden trotzdem zurueckgesetzt - sie gelten nur ;; fuer den gerade gelaufenen Export. -(defun csv:sep-proxies-loeschen (proxy-liste / behalten) - (setq behalten (and (car (atoms-family 1 '("DBG-SCHALTER-P"))) - (dbg-schalter-p "csv_leave_proxies"))) - (if behalten - (princ (strcat "\n[EXPORT] csv_leave_proxies=1: " - (itoa (length proxy-liste)) - " Separator-Proxy-Kopie(n) bleiben in der Zeichnung" - " (Abschalten: (dbg-schalter-off \"csv_leave_proxies\"))")) - (foreach rec proxy-liste (entdel (car rec))) - ) +(defun csv:sep-proxies-loeschen (proxy-liste) + (csv:hilfskopien-loeschen proxy-liste "exp-art-separator" nil) (setq *cs-sep-fix-by-handle* nil) (setq *cs-sep-typ-by-handle* nil) (setq *csv-sepliste-id-by-handle* nil) @@ -2201,51 +2202,40 @@ ) ;; =========================================================================== -;; Foerdereinheit-/Gefaelleeinheit-Marker (ZZ_UNIT_MARKER) +;; Foerdereinheit-/Gefaelleeinheit-Proxies (ZZ_UNIT_MARKER) ;; =========================================================================== -;; Ein Rechteck, das der Export je Einheiten-Spanne (siehe -;; csv:sepliste-partition/csv:element-unit-zuordnung weiter oben) setzt und -;; dort DAUERHAFT stehen bleibt - analog zu ZZ_ASES_MARKER, aber auf die -;; Bounding-Box-Vereinigung der enthaltenen Elemente skaliert statt fest -;; quadratisch. Persistiert wie ZZ_ASES_MARKER ueber Exportlaeufe hinweg -;; (Wiederfinden ueber ZUORDNUNG+TYP+LFDNR), damit die TeileId stabil bleibt. -;; -;; Nur aktiv, wenn *csv-export-alle-elemente* NICHT gesetzt ist (siehe -;; Schalter weiter unten) - im Rohdaten-Modus werden keine neuen Marker -;; angelegt, ein Aufraeum-Durchlauf entfernt aber IMMER verwaiste Marker -;; (auch im Rohdaten-Modus - sonst blieben bei einem Wechsel gruppiert->roh -;; alte Marker als Karteileichen stehen). +;; Je Einheit (csv:kette-einheiten) ein Rechteck auf der Bounding-Box- +;; Vereinigung ihrer Bausteine. Es ist ein reines Export-Hilfsmittel wie die +;; Separator-/Element-Kopien: es entsteht bei jedem Export neu, bekommt in +;; ssg-id-check-all eine ID, liefert die Export-Zeile und wird am Ende von +;; csv:run-export wieder geloescht - ausser der Debug-Schalter +;; "csv_leave_proxies" (bzw. einer der Konfig-Haken, siehe +;; csv:element-proxies-loeschen) laesst es zur Ansicht stehen. +;; Nur im Modus group_vf_gf; in den anderen Modi entsteht keins. (defun csv:unitmark-blockname () "ZZ_UNIT_MARKER") ;; Attribut-Schema. Alle ATTDEFs unsichtbar (wie *csv-asmark-attrib-defs*). -;; ID - fuellt ssg-id-check-all, ueber Exportlaeufe stabil -;; ZUORDNUNG - ID des VF_n/GF_n-Wrappers (Schluessel zum Wiederfinden) +;; ID - fuellt ssg-id-check-all +;; ZUORDNUNG - ID des VF_n/GF_n-Wrappers (csv:unitmark-ids-setzen traegt +;; sie nach der ID-Vergabe nach) ;; TYP - "VF" (Foerdereinheit) oder "GF" (Gefaelleeinheit) -;; LFDNR - 1-basierte Einheiten-Nummer INNERHALB des Wrappers (NICHT -;; der sepliste-lfdnr - eine frische Zaehlung je Einheit) -;; LAENGE_m - Summe der LAENGE/A-Attribute aller enthaltenen -;; Streckenelement-Mitglieder (Meter, als String) -;; ANZAHL_BOEGEN - Anzahl der enthaltenen Mitglieder mit TeileArt "BOGEN" -;; K1/K2 - KS_EIN des ERSTEN bzw. KS_AUS des LETZTEN Mitglieds der -;; Spanne, bereits als csv:trans-encode-String (wie K1-K4 -;; ueberall sonst im Export) - NICHT als rtos-Text: rtos -;; haengt an DIMZIN/LUPREC/LUNITS und ist fuer persistente -;; ATTDEF-Werte ungeeignet (siehe rtos-Hinweis in anderen -;; sepliste-Serialisierungen, ssg_ks_insert.lsp). Der -;; fertig kodierte String wird unveraendert zurueckgelesen, -;; kein Decode/Re-encode-Rundlauf noetig. +;; LFDNR - 1-basierte Einheiten-Nummer INNERHALB des Wrappers +;; LAENGE_m - Summe der Laengen K1->K2 aller enthaltenen Streckenelemente +;; (Meter) - geometrisch, weil die Staustrecke beim Bau per +;; Laenge skaliert wird und ihr Attribut das nicht wiedergibt +;; ANZAHL_BOEGEN - Anzahl der enthaltenen Boegen (inkl. Vario-Kurven) +;; K1/K2 - KS_EIN des ERSTEN bzw. KS_AUS des LETZTEN Bausteins, als +;; csv:trans-encode-String (NICHT rtos, siehe DIMZIN-Hinweis) (setq *csv-unitmark-attrib-defs* '(("ID" "") ("ZUORDNUNG" "") ("TYP" "") ("LFDNR" "") ("LAENGE_m" "") ("ANZAHL_BOEGEN" "") ("K1" "") ("K2" "")) ) -;; --- Blockdefinition des Markers bei Bedarf anlegen --- +;; --- Blockdefinition des Proxies bei Bedarf anlegen --- ;; 1x1-Einheitsquadrat auf Layer "0" (wie csv:asmark-blockdef-sicherstellen) - -;; wird beim Einfuegen ueber sx/sy auf die tatsaechliche Bounding-Box- -;; Ausdehnung der Einheit skaliert (csv:block-einfuegen-welt), anders als der -;; feste ZZ_ASES_MARKER. Keine eigene DWG (reine Hilfsgeometrie). -;; Rueckgabe: Blockname oder nil. +;; wird beim Einfuegen ueber sx/sy auf die Bounding-Box der Einheit skaliert. +;; Keine eigene DWG (reine Hilfsgeometrie). Rueckgabe: Blockname oder nil. (defun csv:unitmark-blockdef-sicherstellen ( / name lastEnt ss e typ) (setq name (csv:unitmark-blockname)) (if (tblsearch "BLOCK" name) @@ -2275,299 +2265,188 @@ ) ) -;; --- Vorhandene Marker der Zeichnung einsammeln --- -;; Rueckgabe: Liste von (ename zuordnung typ lfdnr id), analog -;; csv:asmark-sammeln. -(defun csv:unitmark-sammeln ( / ss i ename attribs out) +;; --- Alle vorhandenen Proxies loeschen --- +;; Raeumt stehengebliebene Proxies eines Debug-Laufs und die frueher dauerhaft +;; gesetzten Marker aelterer Versionen weg, bevor neu aufgebaut wird. +;; Rueckgabe: Anzahl geloeschter Proxies. +(defun csv:unitmark-bestand-loeschen ( / ss i n) (setq ss (ssget "X" (list (cons 0 "INSERT") (cons 2 (csv:unitmark-blockname))))) + (setq n 0) (if ss (progn (setq i 0) - (while (setq ename (ssname ss i)) - (setq attribs (ssg-attrib-read ename)) - (setq out - (cons (list ename - (cond ((cdr (assoc "ZUORDNUNG" attribs))) ("")) - (cond ((cdr (assoc "TYP" attribs))) ("")) - (cond ((cdr (assoc "LFDNR" attribs))) ("")) - (cond ((cdr (assoc "ID" attribs))) (""))) - out)) - (setq i (1+ i)) - ) - ) - ) - out + (while (< i (sslength ss)) + (entdel (ssname ss i)) + (setq i (1+ i))) + (setq n (sslength ss)))) + n ) -;; --- Bestehenden Marker ueber (ZUORDNUNG, TYP, LFDNR) wiederfinden --- -(defun csv:unitmark-finden (bestand zuordnung typ lfdnr / m treffer) - (foreach m bestand - (if (and (null treffer) - (= (nth 1 m) zuordnung) - (= (nth 2 m) typ) - (= (nth 3 m) lfdnr)) - (setq treffer m) - ) - ) - treffer +;; --- Bounding-Box-Vereinigung einer Liste von Kettenbausteinen --- +;; Die verpackten Bausteine liefern selbst keine Welt-Boundingbox; darum je +;; Baustein eine kurzlebige Kopie an seiner Weltlage (csv:block-einfuegen- +;; welt, wie jede Proxy-Kopie), Vereinigung messen, Kopien sofort loeschen. +;; teile = Liste von (typ rec k1 k2). Rueckgabe wie csv:get-bbox oder nil. +(defun csv:kette-bbox (teile / ms kopien kopie t1 rec bbox) + (setq ms (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object)))) + (foreach t1 teile + (setq rec (nth 1 t1)) + (setq kopie (csv:block-einfuegen-welt ms (nth 2 rec) (nth 3 rec) (nth 4 rec) + (nth 5 rec) (nth 6 rec) (nth 7 rec) + (cdr (assoc 2 (entget (nth 0 rec)))))) + (if kopie (setq kopien (cons kopie kopien)))) + (if kopien (setq bbox (csv:get-bbox-union kopien))) + (foreach kopie kopien (entdel kopie)) + bbox ) -;; --- Laenge (m) eines Streckenelement-Mitglieds aus seinem LAENGE/A- -;; Attribut lesen; 0.0 falls keins vorhanden --- -(defun csv:unitmark-elem-laenge-mm (proxy-ename / attribs wert) - (setq attribs (ssg-attrib-read proxy-ename)) - (setq wert (cond ((cdr (assoc "LAENGE" attribs))) ((cdr (assoc "A" attribs))) (nil))) - (if wert (atof wert) 0.0) -) - -;; --- K1/K2 eines Mitglieds lesen, bereits als csv:trans-encode-String --- -;; Dieselbe KS_EIN/KS_AUS-Suche wie csv:get-k-kos-strings (nur EINE Ebene -;; tief in der Proxy-Blockdefinition, echte K1-K4 haben Vorrang). ks-ziel = -;; "K1" oder "K2" (Ziel-Slot wie dort). -;; Rueckgabe: 12-Zeichen Base64-String oder nil, falls das Mitglied kein -;; passendes KS traegt (z.B. das nie verwendete Vario_Kurve_*). -(defun csv:unitmark-elem-ks (proxy-ename ks-ziel / ed pt rotation extrusion - R-world psx psy psz blk-tbl sub-ent sub-ed - sub-bname sub-pt sub-extrusion sub-pt-real - is-real target treffer) - (setq ed (entget proxy-ename)) - (setq pt (cdr (assoc 10 ed))) - (if (null (caddr pt)) (setq pt (list (car pt) (cadr pt) 0.0))) - (setq rotation (cond ((cdr (assoc 50 ed))) (0.0))) - (setq extrusion (cond ((cdr (assoc 210 ed))) ('(0.0 0.0 1.0)))) - (setq pt (mat3-mul-vec3 (mat3-ocs-matrix extrusion) pt)) - (setq R-world (mat3-from-normal-rotation extrusion rotation)) - (setq psx (cond ((cdr (assoc 41 ed))) (1.0))) - (setq psy (cond ((cdr (assoc 42 ed))) (1.0))) - (setq psz (cond ((cdr (assoc 43 ed))) (1.0))) - (setq blk-tbl (tblsearch "BLOCK" (cdr (assoc 2 ed)))) - (setq treffer nil) - (if blk-tbl +;; --- Proxy fuer eine Einheit einfuegen und beschriften --- +;; mitglieder = die (typ rec k1 k2) der Einheit in Kettenreihenfolge. +;; Rueckgabe: ename des Proxies oder nil (keine Boundingbox ermittelbar). +(defun csv:unitmark-einfuegen (ms blockname wrapper typ lfdnr mitglieder + / bbox laenge-mm anzahl-boegen t1 k1 k2 mark) + (setq bbox (csv:kette-bbox mitglieder)) + (if bbox (progn - (setq sub-ent (cdr (assoc -2 blk-tbl))) - (while sub-ent - (setq sub-ed (entget sub-ent)) - (if (= (cdr (assoc 0 sub-ed)) "INSERT") - (progn - (setq sub-bname (strcase (cdr (assoc 2 sub-ed)))) - (setq is-real (wcmatch sub-bname "K1,K2,K3,K4")) - (setq target - (cond - (is-real sub-bname) - ((or (= sub-bname "KS_EIN") (= sub-bname "KSYS_EIN")) "K1") - ((or (= sub-bname "KS_AUS") (= sub-bname "KSYS_AUS")) "K2") - (t nil))) - (if (and target (= target ks-ziel) (or is-real (null treffer))) - (progn - (setq sub-pt (cdr (assoc 10 sub-ed))) - (if (null (caddr sub-pt)) - (setq sub-pt (list (car sub-pt) (cadr sub-pt) 0.0))) - (setq sub-extrusion (cond ((cdr (assoc 210 sub-ed))) ('(0.0 0.0 1.0)))) - (setq sub-pt-real (mat3-mul-vec3 (mat3-ocs-matrix sub-extrusion) sub-pt)) - (setq sub-pt-real (list (* psx (car sub-pt-real)) - (* psy (cadr sub-pt-real)) - (* psz (caddr sub-pt-real)))) - (setq sub-pt-real (csv:local-to-world pt R-world sub-pt-real)) - (setq treffer - (csv:trans-encode (car sub-pt-real) (cadr sub-pt-real) (caddr sub-pt-real))) - ) - ) - ) - ) - (setq sub-ent (entnext sub-ent)) - ) - ) - ) - treffer -) - -;; --- Alle Foerdereinheit-/Gefaelleeinheit-Marker der Zeichnung neu -;; aufbauen --- -;; Laeuft VOR ssg-id-check-all (csv:export-vorbereiten), analog -;; csv:asmark-aktualisieren. sep-proxies/element-proxies/asmarks = die drei -;; bereits erzeugten Proxy-/Marker-Listen dieses Exportlaufs. -;; -;; Ist *csv-export-alle-elemente* gesetzt (Rohdaten-Modus): KEINE neuen -;; Marker anlegen, nur den kompletten vorhandenen Bestand aufraeumen (sonst -;; blieben bei einem Wechsel gruppiert->roh alte Marker als Karteileichen -;; stehen). -;; -;; Rueckgabe: Liste von Records (marker-ename wrapper-ename typ lfdnr) fuer -;; csv:unitmark-ids-setzen. -(defun csv:unitmark-aktualisieren (sep-proxies element-proxies asmarks - / blockname bestand ms wrapper-enames - rec wrapper ed bname wrapper-id app - sepliste sepliste-typisiert sep-eigene - elem-eigene asmarks-eigene unit-spans - zuordnungen span span-i typ lfdnrs - zugeordnet alt alt-id mark bbox-enames - bbox laenge-mm anzahl-boegen elem - lfdnr-erstes lfdnr-letztes k1 k2 - ergebnis neu uebernommen verwaist) - (setq neu 0 uebernommen 0 verwaist 0) - (setq bestand (csv:unitmark-sammeln)) - ;; Neue Marker nur im GENAU gruppierten Modus anlegen - sowohl - ;; "all_elements" als auch "separator_track" wollen keine ZZ_UNIT_MARKER, - ;; der Aufraeum-Pass unten (verwaiste Marker loeschen) laeuft in JEDEM - ;; Modus unbedingt weiter. - (if (= *csv-export-modus* "group_vf_gf") - (progn - (setq blockname (csv:unitmark-blockdef-sicherstellen)) - (if blockname + (setq laenge-mm 0.0 anzahl-boegen 0) + (foreach t1 mitglieder + (if (and (= (car t1) "STRECKENELEMENT") (nth 2 t1) (nth 3 t1)) + (setq laenge-mm (+ laenge-mm (distance (nth 2 t1) (nth 3 t1))))) + (if (= (car t1) "BOGEN") (setq anzahl-boegen (1+ anzahl-boegen)))) + (setq k1 (nth 2 (car mitglieder)) k2 (nth 3 (last mitglieder))) + (setq mark + (csv:block-einfuegen-welt ms blockname + (list (nth 0 bbox) (nth 1 bbox) (nth 2 bbox)) (mat3-rz 0.0) + (max (nth 3 bbox) 1.0) (max (nth 4 bbox) 1.0) 1.0 + (cdr (assoc 2 (entget wrapper))))) + (if mark (progn - (setq ms (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object)))) - ;; Wrapper einsammeln (jeder nur einmal) - Vereinigung ueber alle - ;; drei Proxy-Listen, damit auch ein Wrapper OHNE Boegen/Strecken - ;; (nur AS-Separator-ES, reine Einzel-Foerdereinheit) erfasst wird. - (setq wrapper-enames nil) - (foreach rec sep-proxies - (if (not (member (nth 1 rec) wrapper-enames)) - (setq wrapper-enames (cons (nth 1 rec) wrapper-enames)))) - (foreach rec element-proxies - (if (not (member (nth 1 rec) wrapper-enames)) - (setq wrapper-enames (cons (nth 1 rec) wrapper-enames)))) - (foreach rec asmarks - (if (not (member (nth 1 rec) wrapper-enames)) - (setq wrapper-enames (cons (nth 1 rec) wrapper-enames)))) - (foreach wrapper (reverse wrapper-enames) - (setq ed (entget wrapper)) - (setq bname (cdr (assoc 2 ed))) - (setq wrapper-id (cond ((cdr (assoc "ID" (ssg-attrib-read wrapper)))) (""))) - (setq app - (cond - ((wcmatch (strcase bname) "VF_*") "SSG_VF_SEP") - ((wcmatch (strcase bname) "GF_*") "SSG_GF_SEP") - (t nil))) - (setq sepliste - (if (and app (car (atoms-family 1 '("SSG-SEPLISTE-XDATA-LESEN")))) - (ssg-sepliste-xdata-lesen wrapper app))) - (if sepliste - (progn - (setq sep-eigene nil) - (foreach rec sep-proxies - (if (eq (nth 1 rec) wrapper) (setq sep-eigene (cons rec sep-eigene)))) - (setq sep-eigene (reverse sep-eigene)) - (setq elem-eigene nil) - (foreach rec element-proxies - (if (eq (nth 1 rec) wrapper) (setq elem-eigene (cons rec elem-eigene)))) - (setq elem-eigene (reverse elem-eigene)) - (setq asmarks-eigene nil) - (foreach rec asmarks - (if (eq (nth 1 rec) wrapper) (setq asmarks-eigene (cons rec asmarks-eigene)))) - (setq asmarks-eigene (reverse asmarks-eigene)) - - (setq sepliste-typisiert - (csv:sepliste-mit-strecke-typ sepliste sep-eigene asmarks-eigene)) - (setq unit-spans (csv:sepliste-partition sepliste-typisiert)) - (setq zuordnungen - (csv:element-unit-zuordnung unit-spans sepliste-typisiert elem-eigene)) - - (setq span-i 0) - (foreach span unit-spans - (setq typ (car span)) - (setq lfdnrs (cadr span)) - ;; zugeordnet ist bereits NACH KETTENRICHTUNG SORTIERT - ;; (csv:element-unit-zuordnung) - das erste Element liefert - ;; K1, das letzte K2. - (setq zugeordnet (nth span-i zuordnungen)) - - ;; Bounding-Box-Vereinigung ueber alle zugeordneten - ;; Element-Proxies. Ist eine Spanne leer (z.B. eine ganz - ;; kurze Gefaelleeinheit ohne eigenes Bogen-/Strecken- - ;; Element zwischen zwei direkt benachbarten Separatoren), - ;; entsteht fuer sie kein Marker - eine Einheit ohne jedes - ;; zugeordnete Bauteil hat keine sinnvolle Geometrie. - (setq bbox-enames nil) - (foreach elem zugeordnet (setq bbox-enames (cons (nth 0 elem) bbox-enames))) - (setq bbox (if bbox-enames (csv:get-bbox-union bbox-enames))) - - (if bbox - (progn - ;; Laenge/Anzahl Boegen aus den zugeordneten Elementen. - (setq laenge-mm 0.0 anzahl-boegen 0) - (foreach elem zugeordnet - (if (= (nth 2 elem) "STRECKENELEMENT") - (setq laenge-mm (+ laenge-mm (csv:unitmark-elem-laenge-mm (nth 0 elem))))) - (if (= (nth 2 elem) "BOGEN") - (setq anzahl-boegen (1+ anzahl-boegen))) - ) - ;; K1/K2: eigenes KS_EIN des ERSTEN, KS_AUS des - ;; LETZTEN zugeordneten Elements (Kettenrichtungs- - ;; Sortierung, siehe oben) - fehlt bei einem Element - ;; das passende KS (z.B. das nie verwendete - ;; Vario_Kurve_*), bleibt K1/K2 leer, kein Abbruch. - (setq k1 (csv:unitmark-elem-ks (nth 0 (car zugeordnet)) "K1")) - (setq k2 (csv:unitmark-elem-ks (nth 0 (last zugeordnet)) "K2")) - - (setq mark - (csv:block-einfuegen-welt ms blockname - (list (nth 0 bbox) (nth 1 bbox) (nth 2 bbox)) - (mat3-rz 0.0) - (max (nth 3 bbox) 1.0) (max (nth 4 bbox) 1.0) 1.0 - bname)) - (if mark - (progn - (setq alt (csv:unitmark-finden bestand wrapper-id typ (itoa (1+ span-i)))) - (setq alt-id "") - (if alt - (progn - (setq alt-id (nth 4 alt)) - (entdel (nth 0 alt)) - (setq bestand (vl-remove alt bestand)) - (setq uebernommen (1+ uebernommen)) - ) - (setq neu (1+ neu)) - ) - (ssg-attrib-set-on mark - (list (cons "ID" alt-id) - (cons "ZUORDNUNG" wrapper-id) - (cons "TYP" typ) - (cons "LFDNR" (itoa (1+ span-i))) - (cons "LAENGE_m" (rtos (/ laenge-mm 1000.0) 2 3)) - (cons "ANZAHL_BOEGEN" (itoa anzahl-boegen)) - (cons "K1" (cond (k1) (""))) - (cons "K2" (cond (k2) (""))) - )) - (ssg-layer-setzen mark "ases_marker") - (setq ergebnis (cons (list mark wrapper typ (1+ span-i)) ergebnis)) - ) - ) - ) - ) - (setq span-i (1+ span-i)) - ) - ) - ) - ) - ) - ) + (ssg-attrib-set-on mark + (list (cons "ID" "") + (cons "ZUORDNUNG" (cond ((cdr (assoc "ID" (ssg-attrib-read wrapper)))) (""))) + (cons "TYP" typ) + (cons "LFDNR" (itoa lfdnr)) + (cons "LAENGE_m" (rtos (/ laenge-mm 1000.0) 2 3)) + (cons "ANZAHL_BOEGEN" (itoa anzahl-boegen)) + (cons "K1" (if k1 (csv:trans-encode (car k1) (cadr k1) (caddr k1)) "")) + (cons "K2" (if k2 (csv:trans-encode (car k2) (cadr k2) (caddr k2)) "")))) + (ssg-layer-setzen mark "ases_marker") + ;; Export-Geometrie wie bei jedem Stellvertreter: die gemessene 3D- + ;; Vereinigung der Bausteine statt der Box des flachen Rechtecks, + ;; K1/K2 wie in den Attributen (siehe *csv-baustein-by-handle*). + (setq *csv-baustein-by-handle* + (cons (list (cdr (assoc 5 (entget mark))) + (csv:k-liste-kodieren + (append (if k1 (list (cons "K1" k1))) + (if k2 (list (cons "K2" k2))))) + bbox) + *csv-baustein-by-handle*)))) ) ) - ;; Rest des Bestands (auch im Rohdaten-Modus, wo bestand nie durch obige - ;; Schleife verkleinert wurde): keine Kette/Einheit mehr dahinter. - (foreach m bestand - (entdel (nth 0 m)) - (setq verwaist (1+ verwaist)) + mark +) + +;; --- VF_n/GF_n-Wrapper der Zeichnung, nach ihrer ID aufsteigend --- +;; Wrapper ohne ID (frisch gebaut, nummeriert erst ssg-id-check-all) am Ende. +(defun csv:wrapper-nach-id ( / ss i liste) + (if (setq ss (ssget "X" (list (cons 0 "INSERT") (cons 2 "VF_*,GF_*")))) + (progn + (setq i 0) + (while (< i (sslength ss)) + (setq liste (cons (ssname ss i) liste)) + (setq i (1+ i))))) + (vl-sort liste + (function (lambda (a b / ia ib) + (setq ia (atoi (cond ((cdr (assoc "ID" (ssg-attrib-read a)))) (""))) + ib (atoi (cond ((cdr (assoc "ID" (ssg-attrib-read b)))) ("")))) + (cond ((= ia 0) nil) ((= ib 0) t) (t (< ia ib))))))) + +;; --- Einem Export-Objekt die naechste ID geben, falls es noch keine hat --- +;; naechste-id = zuletzt vergebene Nummer. Rueckgabe: neue letzte Nummer. +(defun csv:id-vergeben (ename naechste-id / id) + (setq id (cdr (assoc "ID" (ssg-attrib-read ename)))) + (if (or (null id) (= id "")) + (progn + (setq naechste-id (1+ naechste-id)) + (ssg-id-set-and-verify ename (ssg-id-format naechste-id) "Kettenfolge"))) + naechste-id +) + +;; --- Ketten verarbeiten: Einheiten-Proxies bauen und IDs in Kettenfolge --- +;; Laeuft VOR ssg-id-check-all (csv:export-vorbereiten). Je VF_n/GF_n-Wrapper +;; (nach Wrapper-ID aufsteigend): +;; 1. Bausteine holen und als Vektorkette ordnen (csv:kette-teile/-ordnen) +;; 2. nur Modus group_vf_gf: in Einheiten schneiden (csv:kette-einheiten) +;; und je Einheit einen Proxy setzen (csv:unitmark-einfuegen) +;; 3. alle Export-Objekte dieser Kette, die noch keine ID haben, entlang der +;; Kette AS -> ES aufsteigend nummerieren: AS-/ES-Marker, Separator- +;; Kopien, Element-Kopien (alle ueber ihren verpackten Baustein der +;; Kettenposition zugeordnet) und Einheiten-Proxies (an der Position +;; ihres ersten Bausteins, vor diesem). +;; Ohne diese Vergabe nummeriert erst ssg-id-check-all - in der Reihenfolge +;; von (ssget "X"), in BricsCAD also rueckwaerts (zuletzt erzeugt zuerst). +;; Die Export-CSV ist nach TeileId sortiert, damit stehen die Zeilen jeder +;; Kette jetzt von AS nach ES. Bereits vorhandene IDs (dauerhafte AS/ES- +;; Marker) bleiben unangetastet. +;; sep-proxies/element-proxies/asmarks = die Stellvertreter-Listen dieses +;; Laufs (letztes Feld jedes Records = verpackter Baustein). +;; Rueckgabe: Einheiten-Proxy-Records (proxy-ename wrapper-ename typ lfdnr) - +;; car ist der Proxy, damit csv:hilfskopien-loeschen sie entfernen kann. +(defun csv:ketten-verarbeiten (sep-proxies element-proxies asmarks + / alt gruppiert blockname ms traeger r naechste-id + wrapper teile einheit lfdnr mark starts + i teil u tr ergebnis) + (setq alt (csv:unitmark-bestand-loeschen)) + (setq gruppiert (= *csv-export-modus* "group_vf_gf")) + (if gruppiert (setq blockname (csv:unitmark-blockdef-sicherstellen))) + (setq ms (vla-get-ModelSpace (vla-get-ActiveDocument (vlax-get-acad-object)))) + ;; Stellvertreter ueber (wrapper baustein) nachschlagbar machen. + (foreach r sep-proxies + (if (nth 5 r) (setq traeger (cons (cons (list (nth 1 r) (nth 5 r)) (nth 0 r)) traeger)))) + (foreach r element-proxies + (if (nth 4 r) (setq traeger (cons (cons (list (nth 1 r) (nth 4 r)) (nth 0 r)) traeger)))) + (foreach r asmarks + (if (nth 4 r) (setq traeger (cons (cons (list (nth 1 r) (nth 4 r)) (nth 0 r)) traeger)))) + (setq naechste-id (ssg-id-max)) + (foreach wrapper (csv:wrapper-nach-id) + (setq teile (csv:kette-ordnen (csv:kette-teile wrapper) + (cdr (assoc 2 (entget wrapper))))) + ;; Einheiten (nur gruppiert); starts = ((erster-index . proxy) ...) + (setq starts nil lfdnr 0) + (if (and gruppiert blockname) + (foreach einheit (csv:kette-einheiten (mapcar 'car teile)) + (setq lfdnr (1+ lfdnr)) + (setq mark (csv:unitmark-einfuegen ms blockname wrapper (car einheit) lfdnr + (mapcar (function (lambda (idx) (nth idx teile))) (cadr einheit)))) + (if mark + (progn + (setq ergebnis (cons (list mark wrapper (car einheit) lfdnr) ergebnis)) + (setq starts (cons (cons (car (cadr einheit)) mark) starts)))))) + ;; IDs entlang der Kette + (setq i 0) + (foreach teil teile + (foreach u starts + (if (= (car u) i) (setq naechste-id (csv:id-vergeben (cdr u) naechste-id)))) + (if (setq tr (cdr (assoc (list wrapper (nth 1 (nth 1 teil))) traeger))) + (setq naechste-id (csv:id-vergeben tr naechste-id))) + (setq i (1+ i))) ) - (if (or (> neu 0) (> uebernommen 0) (> verwaist 0)) - (princ (ssg-textf "exp-unitmark-bilanz" - (list (itoa neu) (itoa uebernommen) (itoa verwaist))))) + (if gruppiert + (princ (ssg-textf "exp-unitmark-bilanz" (list (itoa (length ergebnis)) (itoa alt))))) (reverse ergebnis) ) -;; --- Nach der ID-Vergabe: ZUORDNUNG bereits gesetzt (anders als bei -;; ZZ_ASES_MARKER, siehe csv:unitmark-aktualisieren) - hier bleibt nur die -;; Bilanz-Meldung uebrig. Kein sepliste-Bezug (Einheiten sind nicht Teil der -;; sepliste selbst). --- -(defun csv:unitmark-ids-setzen (marker-liste / rec mark id gesetzt ohne-id) - (setq gesetzt 0 ohne-id 0) +;; --- Nach der ID-Vergabe: ZUORDNUNG nachtragen --- +;; Beim Erzeugen kann ein frisch gebauter Wrapper noch keine ID gehabt haben; +;; erst nach ssg-id-check-all steht sie fest. +(defun csv:unitmark-ids-setzen (marker-liste / rec wrapper-id gesetzt) + (setq gesetzt 0) (foreach rec marker-liste - (setq mark (nth 0 rec)) - (setq id (cdr (assoc "ID" (ssg-attrib-read mark)))) - (if (and id (> (strlen id) 0)) - (setq gesetzt (1+ gesetzt)) - (setq ohne-id (1+ ohne-id)) - ) + (setq wrapper-id (cdr (assoc "ID" (ssg-attrib-read (nth 1 rec))))) + (if (and wrapper-id (> (strlen wrapper-id) 0)) + (ssg-attrib-set-on (nth 0 rec) (list (cons "ZUORDNUNG" wrapper-id)))) + (if (> (strlen (cond ((cdr (assoc "ID" (ssg-attrib-read (nth 0 rec))))) (""))) 0) + (setq gesetzt (1+ gesetzt))) ) (if (> gesetzt 0) (princ (ssg-textf "exp-unitmark-ids" (list (itoa gesetzt))))) @@ -2626,7 +2505,7 @@ ;; csv:pattern-nested-element/csv:element-proxies-erzeugen): NUR im ;; Rohdaten-Modus (*csv-export-alle-elemente* = T) als eigene Export- ;; Zeile gesammelt. Im Default (gruppierter Modus, nil) fasst - ;; csv:unitmark-aktualisieren sie zu Foerdereinheit-/Gefaelleeinheit- + ;; csv:ketten-verarbeiten sie zu Foerdereinheit-/Gefaelleeinheit- ;; Zeilen zusammen (pattern_unit_marker unten) - die Proxy-Kopien ;; selbst werden dann trotz Treffer auf pattern_strecke (Vario*/ ;; Staustrecke* per Praefix) explizit AUSGESCHLOSSEN, damit sie nicht @@ -2703,6 +2582,9 @@ ;; Kopien - Separatoren UND AS/ES-Schleuselemente (der Aufrufer entfernt sie am ;; Ende wieder). label dient nur den Meldungen. (defun csv:export-vorbereiten (label / sep-proxies asmarks element-proxies unitmarks) + ;; Baustein-Geometrie der Stellvertreter (Separator-Kopie, AS-/ES-Marker) + ;; wird beim Erzeugen neu gemerkt - Stand eines frueheren Laufs verwerfen. + (setq *csv-baustein-by-handle* nil) ;; Verpackte Separator_SP-Symbole (siehe csv:sep-proxies-erzeugen) VOR der ;; ID-Vergabe durch temporaere, echte Kopien ersetzen - sie werden am Ende ;; von csv:run-export wieder entfernt (csv:sep-proxies-loeschen). @@ -2713,19 +2595,18 @@ ;; traegt dessen ID ueber Exportlaeufe hinweg (siehe csv:asmark-*). (setq asmarks (csv:asmark-aktualisieren)) ;; Die uebrigen Kettenbausteine (Boegen, gerade Foerderer-/Gefaellestrecken- - ;; Segmente, Umlenk-/Motorstation) ebenso wie die Separatoren durch - ;; temporaere Kopien ersetzen - siehe csv:element-proxies-erzeugen. MUSS wie - ;; sep-proxies VOR ssg-id-check-all stehen, damit die frischen Kopien in - ;; dessen Lauf mit nummeriert werden (siehe ssg-id-collect-blocks, - ;; ssg_id.lsp). Im Modus "separator_track" werden gar keine Element-Kopien - ;; erzeugt - dieser Modus kennt nur AS/ES/Separator. + ;; Segmente, Umlenk-/Motorstation) als temporaere Kopien - NUR im Modus + ;; all_elements, der sie als eigene Zeilen exportiert (siehe csv:element- + ;; proxies-erzeugen). MUSS wie sep-proxies VOR ssg-id-check-all stehen, + ;; damit die frischen Kopien in dessen Lauf mit nummeriert werden (siehe + ;; ssg-id-collect-blocks, ssg_id.lsp). (setq element-proxies - (if (csv:export-separator-track-p) nil (csv:element-proxies-erzeugen))) - ;; Foerdereinheit-/Gefaelleeinheit-Marker (ZZ_UNIT_MARKER) aus den drei - ;; obigen Proxy-/Marker-Listen bauen - MUSS nach ihnen (braucht ihre - ;; Weltpositionen) und VOR ssg-id-check-all stehen (frische Marker werden - ;; dort mit nummeriert), siehe csv:unitmark-aktualisieren. - (setq unitmarks (csv:unitmark-aktualisieren sep-proxies element-proxies asmarks)) + (if (csv:export-alle-elemente-p) (csv:element-proxies-erzeugen))) + ;; Ketten verarbeiten: Foerdereinheit-/Gefaelleeinheit-Proxies (ZZ_UNIT_ + ;; MARKER, nur Modus group_vf_gf) aus den KS-verketteten Bausteinen bauen und + ;; alle neuen Export-Objekte jeder Kette von AS nach ES aufsteigend + ;; nummerieren - VOR ssg-id-check-all, siehe csv:ketten-verarbeiten. + (setq unitmarks (csv:ketten-verarbeiten sep-proxies element-proxies asmarks)) ;; Vor dem Export: IDs aller Bloecke sicherstellen und Duplikate korrigieren. ;; Erst hier - also erst nachdem ALLE Kopien aus allen Wrapper-Bloecken ;; stehen - wird ueberhaupt eine ID vergeben. ssg-id-check-all ermittelt @@ -2783,9 +2664,10 @@ ;; bbox-Fehlerdiagnose fuer diesen Lauf zuruecksetzen (siehe csv:get-bbox). (setq *csv-bbox-fail-count* 0) (setq *csv-bbox-fail-first* nil) - ;; Nur die TEMPORAEREN Kopien zurueckgeben - die AS/ES-Marker bleiben - ;; bewusst in der Zeichnung stehen und duerfen nicht mitgeloescht werden. - (list sep-proxies element-proxies)) + ;; Nur die TEMPORAEREN Hilfsmittel zurueckgeben (Separator-/Element-Kopien, + ;; Einheiten-Proxies) - die AS/ES-Marker bleiben bewusst in der Zeichnung + ;; stehen und duerfen nicht mitgeloescht werden. + (list sep-proxies element-proxies unitmarks)) ;; --- Python-Export-Skript aufrufen und Ergebnis auswerten --------------- ;; Aus csv:run-export ausgelagert: das fertige raw-JSON (out-pfad) an das @@ -2851,13 +2733,14 @@ ;; (siehe csv:block-to-json); fuer EXPORTSIVAS nil. (defun csv:run-export (label py-name csv-name include-bbox / ss i ename fh out-pfad first-block count out-dir sep-proxies element-proxies - vorbereitung-ergebnis) + unitmarks vorbereitung-ergebnis) ;; Zeichnungszustand fuer den Export herrichten (Proxies, IDs, Zuordnung, ;; Attribut-Update, Sep/Scan-Zaehlung, REGENALL, bbox-Reset) - ausgelagert. - ;; Rueckgabe: (sep-proxies element-proxies), beide unten wieder zu entfernen. + ;; Rueckgabe: (sep-proxies element-proxies unitmarks), alle unten wieder zu entfernen. (setq vorbereitung-ergebnis (csv:export-vorbereiten label)) (setq sep-proxies (nth 0 vorbereitung-ergebnis)) (setq element-proxies (nth 1 vorbereitung-ergebnis)) + (setq unitmarks (nth 2 vorbereitung-ergebnis)) (princ (ssg-textf "exp-collect-blocks" (list label))) (setq ss (csv:collect-export-blocks)) @@ -2928,7 +2811,10 @@ ;; Sammel-Funktionen) erfuellt. Die AS-/ES-Marker (ZZ_ASES_MARKER) bleiben ;; bewusst stehen (siehe csv:export-vorbereiten). (csv:sep-proxies-loeschen sep-proxies) - (csv:element-proxies-loeschen element-proxies) + (csv:element-proxies-loeschen element-proxies "exp-art-element") + ;; Einheiten-Proxies: dieselbe Behalten-Regel wie die Element-Kopien + ;; (Debug-Schalter csv_leave_proxies / Konfig-Haken). + (csv:element-proxies-loeschen unitmarks "exp-art-einheit") (princ) ) @@ -2953,21 +2839,34 @@ ;; --- CSV_EXPORT_KONFIG: Dialog fuer Export-Modus + Proxy-Sichtbarkeit --- -(defun csv:export-konfig-init ( / idx) - (setq idx - (cond - ((= *csv-export-modus* "all_elements") "1") - ((= *csv-export-modus* "separator_track") "2") - (t "0"))) - (set_tile "modus" idx) +;; Reihenfolge der Combobox-Eintraege MUSS zwischen -init und -accept +;; uebereinstimmen (Index 0/1/2 <-> Modus-String) - beide leiten sie aus +;; derselben Liste *csv-export-konfig-modi* ab, damit sie nicht +;; auseinanderlaufen kann. +(setq *csv-export-konfig-modi* + (list + (cons "group_vf_gf" "Gruppiert: Foerdereinheit/Gefaelleeinheit (Standard)") + (cons "all_elements" "Alle Einzelelemente (Boegen, Strecken, Umlenk-/Motorstation)") + (cons "separator_track" "Nur Separator-Spur (AS/ES/Separator, ohne Streckenelemente)") + )) + +(defun csv:export-konfig-init ( / idx eintrag) + (start_list "modus") + (foreach eintrag *csv-export-konfig-modi* (add_list (cdr eintrag))) + (end_list) + (setq idx 0) + (setq eintrag + (vl-position *csv-export-modus* (mapcar 'car *csv-export-konfig-modi*))) + (if eintrag (setq idx eintrag)) + (set_tile "modus" (itoa idx)) (set_tile "pruef_zuordnung" (if *csv-export-pruef-zuordnung* "1" "0")) (set_tile "elemente_behalten" (if *csv-export-elemente-behalten* "1" "0")) ) -(defun csv:export-konfig-accept ( / idx) - (setq idx (get_tile "modus")) - (csv:export-modus-setzen - (cond ((= idx "1") "all_elements") ((= idx "2") "separator_track") (t "group_vf_gf"))) +(defun csv:export-konfig-accept ( / idx modus) + (setq idx (atoi (get_tile "modus"))) + (setq modus (car (nth idx *csv-export-konfig-modi*))) + (if modus (csv:export-modus-setzen modus)) (setq *csv-export-pruef-zuordnung* (= (get_tile "pruef_zuordnung") "1")) (setq *csv-export-elemente-behalten* (= (get_tile "elemente_behalten") "1")) ) diff --git a/Lisp/ssg_core.lsp b/Lisp/ssg_core.lsp index 4a265b1..9bcd60d 100644 --- a/Lisp/ssg_core.lsp +++ b/Lisp/ssg_core.lsp @@ -363,15 +363,23 @@ ;; Layer anlegen (falls nicht vorhanden) und optional aktivieren ;; lay-name = Name; color = Farbnummer als String z.B. "2"; set-aktiv = T/nil ;; Farbe wird nur bei Neuanlage gesetzt, bestehende Layer bleiben unveraendert -(defun ssg-make-layer (lay-name color set-aktiv / neu) - (setq neu (not (tblsearch "LAYER" lay-name))) - (if set-aktiv - (command "_LAYER" "_M" lay-name "") - (command "_LAYER" "_N" lay-name "") - ) - (if neu - (command "_LAYER" "_CO" color lay-name "") - ) +;; Ohne "_LAYER"-Befehl: ein bestehender Layer wird gar nicht angefasst (frueher +;; lief bei JEDEM Aufruf "_LAYER _N" und fuellte die Konsole, z.B. je Export- +;; Marker einmal), ein neuer per entmake angelegt, CLAYER direkt gesetzt. Nur +;; wenn entmake scheitert (ungueltiger Name), bleibt der alte Befehlsweg. +(defun ssg-make-layer (lay-name color set-aktiv / farbe) + (if (not (tblsearch "LAYER" lay-name)) + (progn + (setq farbe (atoi (cond (color) ("7")))) + (if (or (< farbe 1) (> farbe 255)) (setq farbe 7)) + (if (not (entmake (list '(0 . "LAYER") '(100 . "AcDbSymbolTableRecord") + '(100 . "AcDbLayerTableRecord") (cons 2 lay-name) + '(70 . 0) (cons 62 farbe) '(6 . "Continuous")))) + (progn + (command "_LAYER" "_N" lay-name "") + (command "_LAYER" "_CO" color lay-name ""))))) + (if (and set-aktiv (tblsearch "LAYER" lay-name)) + (setvar "CLAYER" lay-name)) ) ;; ------------------------------------------------------------ diff --git a/Lisp/ssg_id.lsp b/Lisp/ssg_id.lsp index ec88d1a..099b3d7 100644 --- a/Lisp/ssg_id.lsp +++ b/Lisp/ssg_id.lsp @@ -73,8 +73,9 @@ ;; weil der Marker in der Zeichnung stehen bleibt. (wcmatch bname "ZZ_ASES_MARKER*") ;; ZZ_UNIT_MARKER: die Foerdereinheit-/Gefaelleeinheit-Marker - ;; (siehe csv:unitmark-aktualisieren, export.lsp) - aus - ;; demselben Grund wie ZZ_ASES_MARKER. + ;; (siehe csv:ketten-verarbeiten, export.lsp) - temporaere + ;; Export-Proxies, die wie die Separator-Kopien eine ID fuer + ;; ihre Export-Zeile brauchen. (wcmatch bname "ZZ_UNIT_MARKER*") (wcmatch bname "Separator_SP*,S-LP*,Scanner*") (wcmatch bname "BTMT-Beladung*,SC_Entladung*") diff --git a/bin/show_exportcsv.bat b/bin/show_exportcsv.bat new file mode 100644 index 0000000..99abdce --- /dev/null +++ b/bin/show_exportcsv.bat @@ -0,0 +1,73 @@ +@echo off +REM ================================================================ +REM DXFMAKROS - Export-CSV als Boundingbox-Draufsicht (SVG) anzeigen +REM ================================================================ +REM Zeichnet jede Zeile der Export-CSV (EXPORTCSV) als achsparalleles +REM Rechteck aus Position + Boundingbox, mit Legende und Tooltip je +REM Rechteck sowie den Anschluss-Koordinatensystemen K1-K4 (rotes Kreuz, +REM blaue Linie K1->K2->K3->K4), und oeffnet das Ergebnis im Browser. +REM +REM Die Darstellung uebernimmt sps_skel (bin\material_flow.bat, +REM Option --show-bbs). sps_skel wird neben dxfmakros erwartet +REM (..\sps_skel) oder ueber die Umgebungsvariable SPS_SKEL_HOME. +REM +REM Aufruf: +REM bin\show_exportcsv.bat results\export.csv, alle Zeilen +REM bin\show_exportcsv.bat meine_export.csv andere CSV in results\ (oder Pfad) +REM bin\show_exportcsv.bat export.csv flow ohne VF/GF-Einzelbausteine +REM +REM Ergebnis: %SKEL_RESULTS%\_bbs.svg +REM ================================================================ + +setlocal + +REM Umgebung dxfmakros (DXFM_RESULTS ...) +call "%~dp0setenv.bat" >nul + +REM sps_skel suchen +if not defined SPS_SKEL_HOME set "SPS_SKEL_HOME=%DXFMAKRO%\..\sps_skel" +if not exist "%SPS_SKEL_HOME%\bin\material_flow.bat" ( + echo FEHLER: sps_skel nicht gefunden: %SPS_SKEL_HOME% + echo SPS_SKEL_HOME auf den sps_skel-Ordner setzen. + endlocal & exit /b 1 +) + +REM Umgebung sps_skel (SKEL_RESULTS ...) - material_flow.bat ruft setenv +REM zwar selbst auf, SKEL_RESULTS wird hier aber zum Oeffnen der SVG gebraucht. +call "%SPS_SKEL_HOME%\bin\setenv.bat" >nul + +REM Eingabe-CSV: Dateiname wird in DXFM_RESULTS gesucht, Pfade bleiben +set "CSV=%~1" +if "%CSV%"=="" set "CSV=export.csv" +if exist "%DXFM_RESULTS%\%CSV%" set "CSV=%DXFM_RESULTS%\%CSV%" +if not exist "%CSV%" ( + echo FEHLER: CSV nicht gefunden: %CSV% + echo Erst in BricsCAD EXPORTCSV ausfuehren. + endlocal & exit /b 1 +) +for %%F in ("%CSV%") do ( + set "CSV=%%~fF" + set "SVG=%SKEL_RESULTS%\%%~nF_bbs.svg" +) + +REM Darstellungsmodus: all (Default) oder flow +set "MODE=%~2" +if "%MODE%"=="" set "MODE=all" + +REM Alte SVG entfernen, damit nie eine veraltete Ansicht geoeffnet wird +if exist "%SVG%" del "%SVG%" + +call "%SPS_SKEL_HOME%\bin\material_flow.bat" --file "%CSV%" --show-bbs %MODE% --show-kx +set "RC=%ERRORLEVEL%" + +if not exist "%SVG%" ( + echo FEHLER: SVG wurde nicht erzeugt ^(material_flow Exit-Code %RC%^). + endlocal & exit /b 1 +) + +echo. +echo Boundingbox-Ansicht: %SVG% +REM Vorschau direkt im Standardprogramm fuer .svg (Browser) oeffnen +start "" "%SVG%" + +endlocal & exit /b 0 diff --git a/cfg/export.cfg b/cfg/export.cfg index 6599a2f..a631996 100644 --- a/cfg/export.cfg +++ b/cfg/export.cfg @@ -76,14 +76,12 @@ # Gefaellestrecken-Segmente, Umlenk-/Motorstation). Wie pattern_schleuselement # liegen sie NICHT als eigener top-level INSERT vor, sondern verpackt in der # Wrapper-Blockdefinition - die Muster dienen der SUCHE dort -# (csv:nested-welt-records). Eine TEMPORAERE Kopie des jeweiligen Original- -# Blocks wird IMMER erzeugt (csv:element-proxies-erzeugen, wie bei Separator/ -# pattern_separator - liefert die Positionsdaten fuer die Gruppierung unten) -# und nach dem Export IMMER wieder geloescht; als EIGENE Export-Zeile -# erscheinen sie aber NUR, wenn *csv-export-alle-elemente* (export.lsp) auf T -# gesetzt ist. Im Default (nil, gruppierter Modus) fasst -# csv:unitmark-aktualisieren sie stattdessen zu Foerdereinheit-/ -# Gefaelleeinheit-Zeilen zusammen (siehe pattern_unit_marker). Vario_Kurve_* +# (csv:nested-welt-records). Im Modus all_elements wird je Baustein eine +# TEMPORAERE Kopie erzeugt (csv:element-proxies-erzeugen) und als eigene +# Export-Zeile ausgegeben, danach wieder geloescht. Im gruppierten Modus +# (group_vf_gf, Default) fasst csv:ketten-verarbeiten die Bausteine +# stattdessen zu Foerdereinheit-/Gefaelleeinheit-Zeilen zusammen (siehe +# pattern_unit_marker). Vario_Kurve_* # ist laut Code-Kommentar (vf_linienzug.lsp) als "nirgends im Projekt # tatsaechlich eingefuegt" dokumentiert - in der Praxis kommt es doch vor # (siehe reale HundM05-Exporte), das Muster bleibt darum wirksam. @@ -93,18 +91,17 @@ # vier Muster wie Separator/Scanner aus (Stueckzahl steckt schon in den # GF_Bogen_*/VF_Bogen_*/ANZAHL_VF/ANZAHL_GF-Attributen des Wrappers). # -# pattern_unit_marker: der Marker, den der Export je zusammenhaengendem +# pattern_unit_marker: der Proxy, den der Export im gruppierten Modus je # Foerderer-Abschnitt ("Foerdereinheit") bzw. Gefaelle-Abschnitt # ("Gefaelleeinheit") einer VF_n/GF_n-Kette setzt (ZZ_UNIT_MARKER, ein -# Rechteck auf der Bounding-Box-Vereinigung aller enthaltenen Boegen/ -# Streckenelemente/Umlenk-/Motorstation-Mitglieder, csv:unitmark- -# aktualisieren in Lisp/export.lsp). Bleibt wie ZZ_ASES_MARKER dauerhaft in -# der Zeichnung stehen und behaelt seine ID ueber Exportlaeufe hinweg -# (Attribute ID/ZUORDNUNG/TYP/LFDNR/LAENGE_m/ANZAHL_BOEGEN/K1/K2, alle -# unsichtbar). Nur aktiv im gruppierten Modus (*csv-export-alle-elemente* = -# nil) - im Rohdaten-Modus werden keine neuen Marker angelegt, verwaiste -# Marker (z.B. nach einem Wechsel gruppiert->roh) werden aber immer -# aufgeraeumt. export_sivas.py schliesst dieses Muster wie die vier +# Rechteck auf der Bounding-Box-Vereinigung der enthaltenen Bausteine, +# csv:ketten-verarbeiten in Lisp/export.lsp). Die Kette wird dafuer als +# Vektorkette K2 -> K1 geordnet; eine Foerdereinheit reicht vom Separator vor +# der Umlenkstation bis zur Motorstation, alles dazwischen ist Gefaelle. +# Der Proxy ist ein reines Export-Hilfsmittel: er wird bei jedem Export neu +# erzeugt und danach geloescht, ausser der Debug-Schalter csv_leave_proxies +# ist gesetzt (Attribute ID/ZUORDNUNG/TYP/LFDNR/LAENGE_m/ANZAHL_BOEGEN/K1/K2, +# alle unsichtbar). export_sivas.py schliesst dieses Muster wie die vier # pattern_nested_*-Muster aus (Stueckzahl steckt in ANZAHL_VF/ANZAHL_GF). # ============================================================ diff --git a/dcl/csv_export_konfig.dcl b/dcl/csv_export_konfig.dcl index 776ad3d..a02ba3c 100644 --- a/dcl/csv_export_konfig.dcl +++ b/dcl/csv_export_konfig.dcl @@ -1,35 +1,27 @@ // ============================================================ // csv_export_konfig.dcl - CSV-Export Konfiguration (c:CSV_EXPORT_KONFIG, -// export.lsp). Steuert *csv-export-modus* (drei sich gegenseitig -// ausschliessende Radio-Buttons im selben boxed_radio_column) sowie die -// zwei unabhaengigen Sichtbarkeits-Haken fuer temporaere Element-Proxy- -// Kopien (*csv-export-pruef-zuordnung*/*csv-export-elemente-behalten*). +// export.lsp). Steuert *csv-export-modus* (Combobox mit drei sich +// gegenseitig ausschliessenden Eintraegen) sowie die zwei unabhaengigen +// Sichtbarkeits-Haken fuer temporaere Element-Proxy-Kopien +// (*csv-export-pruef-zuordnung*/*csv-export-elemente-behalten*). // -// Radio-Button-Labels sind FEST (Deutsch) - set_tile kann bei einem -// radio_button nur den Zustand, nicht das Label aendern (siehe Kommentar -// dcl/variofoerderer.dcl:16-23, gleiche Einschraenkung hier). +// popup_list statt radio_column: set_tile/get_tile auf einer +// boxed_radio_column liefern/erwarten den KEY des gewaehlten radio_button +// (String, z.B. "modus_all"), nicht den numerischen Index - das widersprach +// der urspruenglichen Annahme in csv:export-konfig-init/-accept (idx als +// "0"/"1"/"2" behandelt) und liess die Vorbelegung beim erneuten Oeffnen +// immer auf die erste Option zurueckfallen. popup_list ist eindeutig +// index-basiert (siehe dcl/sprache.dcl + SSG_LIB_Commands.lsp +// ssg-sprache-init/-accept, dasselbe Muster). // ============================================================ csv_export_konfig : dialog { label = "CSV-Export Konfiguration"; - : boxed_radio_column { - label = "Export-Modus:"; + : popup_list { key = "modus"; - - : radio_button { - key = "modus_group"; - label = "Gruppiert: Foerdereinheit/Gefaelleeinheit (Standard)"; - value = "1"; - } - : radio_button { - key = "modus_all"; - label = "Alle Einzelelemente (Boegen, Strecken, Umlenk-/Motorstation)"; - } - : radio_button { - key = "modus_sep"; - label = "Nur Separator-Spur (AS/ES/Separator, ohne Streckenelemente)"; - } + label = "Export-Modus:"; + width = 55; } spacer; diff --git a/doc/csv-export.md b/doc/csv-export.md index ee33597..7f7cbd0 100644 --- a/doc/csv-export.md +++ b/doc/csv-export.md @@ -104,8 +104,8 @@ Pro INSERT wird ein JSON-Objekt geschrieben: | `x`, `y`, `z`, `rotation` | `(assoc 10)` / `(assoc 50)` | roher Einfuegepunkt/-winkel, KEIN `vla-getboundingbox` | | `attribs` | alle ATTRIB-Werte | | | `insertpoint` | `csv:kos-encode` | Position+Rotation als 24-Zeichen-Base64 (Quaternion) | -| `k1`..`k4` | `csv:get-k-kos-strings` bzw. Fallbacks | Anschluss-Koordinatensysteme, siehe unten | -| `bbox` | `csv:get-bbox` (`vla-getboundingbox`) | NUR wenn `include-bbox=T` und der Aufruf gelingt; fehlt sonst komplett im JSON | +| `k1`..`k4` | `csv:k-liste` (Kern `csv:ks-welt-punkte`) bzw. Fallbacks | Anschluss-Koordinatensysteme, siehe unten | +| `bbox` | `csv:get-bbox` (`vla-getboundingbox`), im Modus `all_elements` fuer Separator/AS/ES die des Bausteins (`csv:baustein-merken`) | NUR wenn `include-bbox=T` und der Aufruf gelingt; fehlt sonst komplett im JSON | | `warnung` | `*cs-scanner-warnung-by-handle*` | strittige Scanner-Zuordnung aus `cs-zuordnung-lauf` | | `zuordnung_fix` | `*cs-sep-fix-by-handle*` | nur bei Proxy-Kopien: die feststehende Wrapper-ID | | `sepliste` | `ssg-sepliste-xdata-lesen` + `*csv-sepliste-id-by-handle*` | nur bei VF_n/GF_n, siehe eigener Abschnitt | @@ -116,7 +116,56 @@ Laenge+Rotation synthetisiert (`csv:gerade-k-kos-strings`). VF_n/GF_n leiten K1 (Eingang) und K2 (Ausgang) aus den eingebetteten AS_Element/ES_Element ab (`csv:vfgf-k-kos-strings`), damit die Kreisel<->Strecke-Kollisionspruefung in Python mit einer kleinen festen Box an der AS/ES-Position arbeiten kann statt -mit der ganzen (oft sehr langen) Wrapper-Box. +mit der ganzen (oft sehr langen) Wrapper-Box. K1 des Wrappers ist dabei K1 +des AS, K2 der K2 des ES (`csv:vfgf-element-punkte`, dieselbe Rechnung wie +deren eigene Zeilen). + +**Kettenteile: Stellvertreter vs. Baustein.** Innerhalb einer VF_n/GF_n-Kette +gilt fuer jedes Teil K1 = KS_EIN, K2 = KS_AUS des Bausteins - K2 eines Teils +ist exakt K1 des naechsten. Bogen/Streckenelement/Motor-/Umlenkstation werden +als 1:1-Kopie exportiert und erfuellen das von selbst. Separator und AS/ES +exportieren dagegen einen **Stellvertreter**: die Kopie des Sensor-Symbols +`Separator_SP` (sitzt 235 mm weit im 300-mm-Trennsteg +`Staustrecke_Separator_SP_300_mm`, hat nur EIN eigenes KS) bzw. den +`ZZ_ASES_MARKER` (200x200, ohne KS). Was die Zeile fuehrt, haengt am Modus: + +| Modus | Separator | AS/ES | +|---|---|---| +| `all_elements` | K1/K2 + bbox des Trennstegs | K1/K2 + bbox des AS-/ES-Elements (AS: K1 Kreisel, K2 Kettenanfang; ES: K1 Kettenende, K2 Kreisel) | +| `group_vf_gf` | KS + bbox des Symbols | wie `all_elements` (schliesst an die Einheiten an) | +| `separator_track` | KS + bbox des Symbols | bbox des Markers, keine K | + +IDs der neuen Export-Objekte jeder Kette (Separator-/Element-Kopien, neue +AS/ES-Marker, Einheiten-Proxies) werden vor `ssg-id-check-all` entlang der +Kette von AS nach ES aufsteigend vergeben (`csv:ketten-verarbeiten`) - die +CSV ist nach TeileId sortiert, die Zeilen stehen damit in Kettenfolge. + +Umgesetzt ueber `csv:baustein-merken`: beim Erzeugen des Stellvertreters +werden K-Punkte (`csv:ks-welt-punkte`) und bbox (kurzlebige Kopie des +Bausteins, `csv:baustein-bbox`) unter seinem Handle gemerkt +(`*csv-baustein-by-handle*`, je Lauf neu); `csv:k-liste` und +`csv:block-to-json` bevorzugen diese Werte. Der Trennsteg eines Symbols wird +ueber die Lage des Symbols IM Trennsteg gefunden (`csv:trennsteg-zu-symbol`), +nicht ueber den naechsten Ursprung. + +**Gruppierter Modus (`group_vf_gf`): Foerder-/Gefaelleeinheiten.** Eine +VF_n/GF_n-Kette wechselt zwischen Gefaelle- und Foerderabschnitten (GF, VF, +GF, ...). `csv:ketten-verarbeiten` holt je Wrapper alle Bausteine samt +Welt-KS (`csv:kette-teile`: AS, Trennstege, Boegen, Streckenelemente, +Umlenk-/Motorstation, ES), ordnet sie als **Vektorkette** - auf K2 eines +Bausteins liegt K1 des naechsten, Start am AS (`csv:kette-ordnen`, Toleranz +2 mm) - und schneidet die Typfolge in Einheiten (`csv:kette-einheiten`): +eine **Foerdereinheit** beginnt am Separator vor der Umlenkstation und endet +mit der Motorstation, alles dazwischen ist eine **Gefaelleeinheit**; AS/ES +bleiben eigene Zeilen. Kurven sind dabei kein Problem, weil nur die +KS-Nachbarschaft zaehlt. Je Einheit entsteht ein Proxy `ZZ_UNIT_MARKER` auf +der vereinigten Boundingbox (gemessen an kurzlebigen Kopien der Bausteine), +mit K1 vom ersten und K2 vom letzten Baustein, `LAENGE_m` = Summe der +Streckenelement-Laengen K1->K2, `ANZAHL_BOEGEN`. Alle Proxies werden nach +dem Export geloescht, ausser der Debug-Schalter `csv_leave_proxies` ist +gesetzt. Reisst die KS-Kette ab, meldet der Export das (`exp-kette-luecke`) +und fuehrt den Rest als eigene Teilkette weiter. Die fruehere Gruppierung +ueber die sepliste-XDATA und den Separator-Typ (`SSG_SEP_TYP`) ist entfallen. **Die `bbox` ist das einzige Feld, das `vla-getboundingbox` braucht** — alle anderen Felder kommen aus rohen DXF-Gruppencodes oder XDATA. Ein Ausfall von diff --git a/lang/de_DE.json b/lang/de_DE.json index 365fc43..b9457cc 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -711,6 +711,15 @@ "exp-asmark-blockdef-fehler": "\n[EXPORT] WARNUNG: Blockdefinition '%1' konnte nicht angelegt werden - es werden keine AS/ES-Marker gesetzt.", "exp-asmark-bilanz": "\n[EXPORT] AS/ES-Marker: %1 neu, %2 mit bisheriger ID uebernommen, %3 verwaiste entfernt.", "exp-asmark-ids": "\n[EXPORT] %1 AS/ES-Marker mit ihrer ID am sepliste-Eintrag vermerkt.", + "exp-unitmark-blockdef": "\n[EXPORT] Blockdefinition '%1' fuer die Einheiten-Proxies angelegt.", + "exp-unitmark-blockdef-fehler": "\n[EXPORT] WARNUNG: Blockdefinition '%1' konnte nicht angelegt werden - es werden keine Foerder-/Gefaelleeinheiten exportiert.", + "exp-unitmark-bilanz": "\n[EXPORT] Foerder-/Gefaelleeinheiten: %1 Proxy(s) erzeugt, %2 alte entfernt.", + "exp-unitmark-ids": "\n[EXPORT] %1 Einheiten-Proxy(s) mit ID versehen.", + "exp-kette-luecke": "\n[EXPORT] WARNUNG: Kette '%1' reisst ab (kein K1 auf dem letzten K2) - %2 Baustein(e) als eigene Teilkette weitergefuehrt, Einheitengrenzen dort pruefen.", + "exp-hilfskopien-behalten": "\n[EXPORT] csv_leave_proxies=1: %1 %2 bleiben in der Zeichnung (Abschalten: (dbg-schalter-off \"csv_leave_proxies\"))", + "exp-art-separator": "Separator-Kopie(n)", + "exp-art-element": "Element-Kopie(n)", + "exp-art-einheit": "Einheiten-Proxy(s)", "exp-update-hoehe-drehung": "\n[%1] Aktualisiere Hoehe/Drehung...", "exp-collect-blocks": "\n[%1] Sammle relevante Bloecke...", "exp-no-blocks-found": "\n[%1] Keine relevanten Bloecke gefunden.", diff --git a/lang/en_GB.json b/lang/en_GB.json index 50c89ae..7877a4f 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -711,6 +711,15 @@ "exp-asmark-blockdef-fehler": "\n[EXPORT] WARNING: block definition '%1' could not be created - no AS/ES markers are placed.", "exp-asmark-bilanz": "\n[EXPORT] AS/ES markers: %1 new, %2 kept with their previous ID, %3 orphaned ones removed.", "exp-asmark-ids": "\n[EXPORT] %1 AS/ES marker ID(s) recorded at their sepliste entry.", + "exp-unitmark-blockdef": "\n[EXPORT] Block definition '%1' for the unit proxies created.", + "exp-unitmark-blockdef-fehler": "\n[EXPORT] WARNING: block definition '%1' could not be created - no conveyor/gravity units are exported.", + "exp-unitmark-bilanz": "\n[EXPORT] Conveyor/gravity units: %1 proxy(s) created, %2 old ones removed.", + "exp-unitmark-ids": "\n[EXPORT] %1 unit proxy(s) given an ID.", + "exp-kette-luecke": "\n[EXPORT] WARNING: chain '%1' is broken (no K1 at the last K2) - %2 element(s) continued as a separate sub-chain, check the unit boundaries there.", + "exp-hilfskopien-behalten": "\n[EXPORT] csv_leave_proxies=1: %1 %2 remain in the drawing (switch off: (dbg-schalter-off \"csv_leave_proxies\"))", + "exp-art-separator": "separator copy(ies)", + "exp-art-element": "element copy(ies)", + "exp-art-einheit": "unit proxy(ies)", "exp-update-hoehe-drehung": "\n[%1] Updating height/rotation...", "exp-collect-blocks": "\n[%1] Collecting relevant blocks...", "exp-no-blocks-found": "\n[%1] No relevant blocks found.", diff --git a/lib/export_csv.py b/lib/export_csv.py index 71725c2..94f0326 100644 --- a/lib/export_csv.py +++ b/lib/export_csv.py @@ -274,7 +274,7 @@ def build_element_merkmale(block): def build_einheit_merkmale(block): """Merkmale-Dict fuer eine Foerdereinheit-/Gefaelleeinheit-Zeile (ZZ_UNIT_ - MARKER, siehe csv:unitmark-aktualisieren in export.lsp und + MARKER, siehe csv:ketten-verarbeiten in export.lsp und pattern_unit_marker in cfg/export.cfg). LAENGE_m/ANZAHL_BOEGEN kommen direkt aus den ATTDEFs des Markers - dort @@ -282,9 +282,15 @@ def build_einheit_merkmale(block): zugeordneten Streckenelement-Mitglieder bzw. Anzahl der Bogen-Mitglieder). Python hat im gruppierten Modus KEINEN Zugriff auf die Einzelteile selbst (die werden dort gar nicht erst exportiert), daher keine eigene - Neuberechnung hier.""" + Neuberechnung hier. + + "Zuordnung" ist die ID des VF_n/GF_n-Wrappers, aus dem diese Einheit + stammt (ATTDEF ZUORDNUNG, von csv:ketten-verarbeiten gesetzt) - + dieselbe Bedeutung wie "Zuordnung" bei build_sensor_merkmale, nur eine + Ebene hoeher (Einheit -> Strecke statt Sensor -> Carrier).""" attribs = block.get("attribs", {}) return { + "Zuordnung": attribs.get("ZUORDNUNG", ""), "Laenge_m": attribs.get("LAENGE_m", ""), "Anzahl_Boegen": attribs.get("ANZAHL_BOEGEN", ""), } @@ -1034,8 +1040,8 @@ def process_blocks(blocks, lookup, dbg=None): continue # ZZ_UNIT_MARKER (siehe cfg/export.cfg pattern_unit_marker sowie - # csv:unitmark-aktualisieren in Lisp/export.lsp): der persistente - # Marker, den Lisp je zusammenhaengendem Foerderer-/Gefaelle-Abschnitt + # csv:ketten-verarbeiten in Lisp/export.lsp): der temporaere + # Proxy, den Lisp je zusammenhaengendem Foerderer-/Gefaelle-Abschnitt # einer VF_n/GF_n-Kette setzt (gruppierter Modus, Default). TYP # entscheidet VF->Foerdereinheit / GF->Gefaelleeinheit, analog zur # AS/ES-Klassifikation oben. K1/K2 brauchen keine Sonderbehandlung - diff --git a/lib/export_sivas.py b/lib/export_sivas.py index 20573bb..22ad293 100644 --- a/lib/export_sivas.py +++ b/lib/export_sivas.py @@ -416,7 +416,7 @@ SKIP_BLOCKS = set(BLOCKPATTERNS.get("pattern_ks_subblocks", ["K1", "K2", "K3", " # siehe csv:element-proxies-erzeugen, export.lsp; nur im Rohdaten-Modus # *csv-export-alle-elemente*=T ueberhaupt in export_raw.json vorhanden) sowie # fuer die gruppierten Foerdereinheit-/Gefaelleeinheit-Marker (ZZ_UNIT_MARKER, -# csv:unitmark-aktualisieren, Default-Modus): ihre Stueckzahl steckt bereits +# csv:ketten-verarbeiten, Default-Modus): ihre Stueckzahl steckt bereits # in den GF_Bogen_*/VF_Bogen_*/ANZAHL_VF/ANZAHL_GF-Attributen des Wrappers # (*strecke-attr-gruppe*, ssg_core.lsp) - ein eigener Sivas-Eintrag wuerde # ebenso doppelt zaehlen. Muss VOR der pattern_strecke_module-Pruefung unten diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 39d447f..b03901e 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -530,229 +530,217 @@ ^C^C(ssg-ensure "OmniModulInsert") OMNI_EDIT - + - Rohrabhaenger - ^C^C(ssg-ensure "GeruestInsert") GERUEST_ROHRABHAENGER + Geruest... + ^C^C(ssg-ensure "GeruestInsert") GERUEST - - 2 Zoll Saeulen - ^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULE_2ZOLL - - - - - 1 Zoll Saeulen - ^C^C(ssg-ensure "GeruestInsert") GERUEST_SAEULE_1ZOLL - - - - - Wandbefestigung - ^C^C(ssg-ensure "GeruestInsert") GERUEST_WANDBEFESTIGUNG - - - Marker einfuegen ^C^C(ssg-ensure "Tro_Edit") TRO_INSERT - + Marker bearbeiten ^C^C(ssg-ensure "Tro_Edit") TRO_EDIT - + Bearbeiten (Auto) ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT - + Verbindung einfuegen ^C^C(ssg-ensure "Connection_Edit") CONNECTION_INSERT - + Verbindung bearbeiten ^C^C(ssg-ensure "Connection_Edit") CONNECTION_EDIT - + Eingang ^C^C(ssg-ensure "SSG_LIB_Commands") ILS_EINGANG_INSERT - + Ausgang ^C^C(ssg-ensure "SSG_LIB_Commands") ILS_AUSGANG_INSERT - + SPS Schliessen ^C^C - + Export Sivas ^C^C(ssg-ensure "export") EXPORTSIVAS - + Export CSV ^C^C(ssg-ensure "export") EXPORTCSV - + Umschalten 2D und 3D ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_SWITCH - + Alle Bloecke auf 2D ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_ALL_2D - + Alle Bloecke auf 3D ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_DIM_ALL_3D - + Sprache ^C^C(ssg-ensure "SSG_LIB_Commands") SSG_SPRACHE - + Planquadrate an/aus ^C^C(ssg-ensure "DrawPlanquadrate") PLANQUADRATE_TOGGLE - + + + CSV-Export + ^C^C(ssg-ensure "export") CSV_EXPORT_KONFIG + + + alle Tests ausfuehren und exportieren ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) SSG_RUN_ALL_TESTS_EXPORT - + Tests ausfuehren und stehen lassen ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) SSG_RUN_ALL_TESTS_OFFEN - + Export CSV/Sivas ALL ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_export_all.lsp")) TEST_EXPORT_ALL - + Kreisel ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp")) TEST_KREISEL - + Foerderer ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_foerderer.lsp")) TEST_FOERDERER - + Foerderer-Linienzug ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_linienzug.lsp")) TEST_LINIENZUG TEST_LINIENZUG_STUFE2 - + Omniflo ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo.lsp")) TEST_OMNIFLO - + Omniflo Strecke ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo_strecke.lsp")) TEST_OMNIFLO_STRECKE - + Gefaellestrecke ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_gefaellestrecke.lsp")) TEST_GEFAELLESTRECKE - + Mubea Gesamtmodell ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp")) TEST_MUBEA - + HundM05 Kreisel-Abschnitt ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")) TEST_HUNDM05 - + KS 2D/3D pruefen (CSV) ^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN - + Kreisel bearbeiten (ssg-ensure "KreiselInsert") KreiselEdit - + Omniflo Element bearbeiten (ssg-ensure "OmniModulInsert") OMNI_EDIT - + Gefaellestrecke bearbeiten (ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EDIT - + VarioFoerderer bearbeiten (ssg-ensure "VarioFoerderer") VARIOFOERDERER_EDIT - + TRO-Marker bearbeiten (ssg-ensure "Tro_Edit") TRO_EDIT - + Verbindung bearbeiten (ssg-ensure "Connection_Edit") CONNECTION_EDIT - + SSG Bearbeiten (Auto) (ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT @@ -769,11 +757,16 @@ SSG_LIB - - - - - + + Geruest... + + + + + + + + ILS @@ -1366,276 +1359,245 @@ - - Geruest - - Rohrabhaenger - - - - - - - Wandbefestigung - - - - - - - Saeulen - - 2 Zoll Saeulen - - - - - - 1 Zoll Saeulen - - - - - - + SPS - - + + Eingang - + Ausgang - + SPS Schliessen - + - + TRO Marker einfuegen - + Marker bearbeiten - + Bearbeiten (Auto) - + - + Connections Verbindung einfuegen - + Verbindung bearbeiten - + Bearbeiten (Auto) - + - + Export Export Sivas - + Export CSV - + - + Konfiguration Umschalten 2D und 3D - + Alle Bloecke auf 2D - + Alle Bloecke auf 3D - + Sprache - + Planquadrate an/aus - + - Konfiguration Schliessen + CSV-Export - + - + Tests alle Tests ausfuehren und exportieren - + Tests ausfuehren und stehen lassen - + Export CSV/Sivas ALL - + Kreisel - + Foerderer - + Foerderer-Linienzug - + Omniflo - + Omniflo Strecke - + Gefaellestrecke - + Mubea Gesamtmodell - + HundM05 Kreisel-Abschnitt - + KS 2D/3D pruefen (CSV) - + - + POP501 SSG_LIB Edit Context Kreisel bearbeiten - + Omniflo Element bearbeiten - + Gefaellestrecke bearbeiten - + VarioFoerderer bearbeiten - + TRO-Marker bearbeiten - + Verbindung bearbeiten - + SSG Bearbeiten (Auto) - + diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index 7fce004..dc8b6bb 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -411,86 +411,61 @@ (tu-eq "csv:element-teileart/unbekannt" nil (csv:element-teileart "AS_Element_90_links")) - ;; --- csv:sepliste-partition: sepliste in Foerdereinheit-/Gefaelleeinheit- - ;; Spannen aufteilen (Lauflaengen-Kodierung ueber den effektiven Typ) ----- - ;; Reine Rechenfunktion auf (typ lfdnr strecke-typ welt-pt)-Tupeln, hier - ;; ohne Zeichnung testbar (welt-pt wird von der Partitionierung selbst - ;; nicht gebraucht, darum ueberall nil). + ;; --- csv:kette-typ: Bausteintyp einer VF_n/GF_n-Kette aus dem Blocknamen -- + (tu-eq "csv:kette-typ/as" "AS" (csv:kette-typ "AS_Element_90_links_3D")) + (tu-eq "csv:kette-typ/es" "ES" (csv:kette-typ "ES_Element_30_rechts_2D")) + (tu-eq "csv:kette-typ/sep" "SEP" (csv:kette-typ "Staustrecke_Separator_SP_300_mm_3D")) + (tu-eq "csv:kette-typ/streckenelement" "STRECKENELEMENT" + (csv:kette-typ "Staustrecke_SP_1000_mm_3D")) + (tu-eq "csv:kette-typ/umlenk" "UMLENKSTATION" + (csv:kette-typ "Vario_Umlenkstation_500mm_rechts_3D")) + (tu-nil "csv:kette-typ/symbol-ist-kein-baustein" (csv:kette-typ "Separator_SP_3D")) - ;; HundM05 VF_1-Beispiel (echt verifiziert): AS, SEP2=VF, SEP3=GF, SEP4=GF, - ;; SEP5=VF, ES -> 3 Einheiten VF,GF,VF. SEP3+SEP4 bracketen GEMEINSAM eine - ;; einzige Gefaelleeinheit (nicht zwei separate). - (setq _sep-hundm05 - '(("AS" 1 nil nil) ("SEP" 2 "VF" nil) ("SEP" 3 "GF" nil) - ("SEP" 4 "GF" nil) ("SEP" 5 "VF" nil) ("ES" 6 nil nil))) - (tu-eq "csv:sepliste-partition/hundm05" - '(("VF" (1 2)) ("GF" (3 4)) ("VF" (5 6))) - (csv:sepliste-partition _sep-hundm05)) - - ;; Minimalfall: nur AS-SEP(VF)-ES, kein Typwechsel -> 1 Foerdereinheit ueber - ;; die ganze Kette. - (setq _sep-minimal '(("AS" 1 nil nil) ("SEP" 2 "VF" nil) ("ES" 3 nil nil))) - (tu-eq "csv:sepliste-partition/minimal" - '(("VF" (1 2 3))) - (csv:sepliste-partition _sep-minimal)) - - ;; Einzel-GF-Fall: die Gefaelleeinheit wird nur von EINEM SEP (nicht zwei) - ;; UND dem nachfolgenden ES bracketiert. - (setq _sep-einzel-gf - '(("AS" 1 nil nil) ("SEP" 2 "VF" nil) ("SEP" 3 "GF" nil) ("ES" 4 nil nil))) - (tu-eq "csv:sepliste-partition/einzel-gf" - '(("VF" (1 2)) ("GF" (3 4))) - (csv:sepliste-partition _sep-einzel-gf)) - - ;; 3+ gleichtypige SEP-Eintraege hintereinander muessen weiterhin EINE - ;; Einheit ergeben (nicht mehrere) - Lauflaengen-Regel, kein Sonderfall. - (setq _sep-dreifach-gf - '(("AS" 1 nil nil) ("SEP" 2 "VF" nil) ("SEP" 3 "GF" nil) - ("SEP" 4 "GF" nil) ("SEP" 5 "GF" nil) ("SEP" 6 "VF" nil) ("ES" 7 nil nil))) - (tu-eq "csv:sepliste-partition/dreifach-gf" - '(("VF" (1 2)) ("GF" (3 4 5)) ("VF" (6 7))) - (csv:sepliste-partition _sep-dreifach-gf)) - - ;; Kette beginnend mit GF (AS erbt den Typ des ersten SEP-Eintrags, hier GF - ;; statt des sonstigen Default "VF"). - (setq _sep-startet-gf - '(("AS" 1 nil nil) ("SEP" 2 "GF" nil) ("ES" 3 nil nil))) - (tu-eq "csv:sepliste-partition/startet-gf" + ;; --- csv:kette-einheiten: geordnete Typfolge in VF-/GF-Einheiten schneiden + ;; VF = Separator vor der Umlenkstation ... Motorstation; alles dazwischen + ;; GF; AS/ES gehoeren zu keiner Einheit. Reine Rechenfunktion. + ;; HundM05 VF_5 (Bausteinfolge aus der Testzeichnung, per KS-Kette geordnet): + ;; GF(1) VF(2..10) GF(11 12) VF(13..25) GF(26 27) - passt zu L_GF_m + ;; "0.727,0.201,0.318" des Wrappers (drei Gefaelleabschnitte). + (setq _kette-hundm05 + '("AS" "STRECKENELEMENT" "SEP" "UMLENKSTATION" "BOGEN" "STRECKENELEMENT" + "BOGEN" "STRECKENELEMENT" "BOGEN" "BOGEN" "MOTORSTATION" "SEP" + "STRECKENELEMENT" "SEP" "UMLENKSTATION" "BOGEN" "STRECKENELEMENT" "BOGEN" + "BOGEN" "BOGEN" "STRECKENELEMENT" "BOGEN" "BOGEN" "STRECKENELEMENT" "BOGEN" + "MOTORSTATION" "STRECKENELEMENT" "SEP" "ES")) + (tu-eq "csv:kette-einheiten/hundm05" + '(("GF" (1)) ("VF" (2 3 4 5 6 7 8 9 10)) ("GF" (11 12)) + ("VF" (13 14 15 16 17 18 19 20 21 22 23 24 25)) ("GF" (26 27))) + (csv:kette-einheiten _kette-hundm05)) + ;; Reine Gefaellestrecke ohne Stationen -> eine einzige GF. + (tu-eq "csv:kette-einheiten/nur-gf" '(("GF" (1 2 3))) - (csv:sepliste-partition _sep-startet-gf)) + (csv:kette-einheiten '("AS" "STRECKENELEMENT" "BOGEN" "SEP" "ES"))) + ;; Kette beginnt direkt mit dem Foerderer (Separator gleich hinter dem AS), + ;; endet mit der Motorstation vor dem ES -> nur eine VF, keine leeren GF. + (tu-eq "csv:kette-einheiten/nur-vf" + '(("VF" (1 2 3 4))) + (csv:kette-einheiten '("AS" "SEP" "UMLENKSTATION" "STRECKENELEMENT" "MOTORSTATION" "ES"))) + ;; Umlenkstation ohne Separator davor beginnt die VF selbst; der Separator, + ;; der NICHT vor einer Umlenkstation steht, bleibt im Gefaelle. + (tu-eq "csv:kette-einheiten/umlenk-ohne-sep" + '(("GF" (1 2)) ("VF" (3 4 5))) + (csv:kette-einheiten '("AS" "SEP" "BOGEN" "UMLENKSTATION" "STRECKENELEMENT" "MOTORSTATION" "ES"))) - ;; --- csv:dot2: 2D-Skalarprodukt --- - (tu-eqf "csv:dot2/achsen" 0.0 (csv:dot2 '(1.0 0.0) '(0.0 1.0))) - (tu-eqf "csv:dot2/parallel" 6.0 (csv:dot2 '(2.0 0.0) '(3.0 0.0))) - - ;; --- csv:element-unit-zuordnung: Elemente per Kettenrichtungs-Projektion - ;; den Einheiten-Spannen zuordnen und INNERHALB jeder Spanne nach der - ;; Projektion sortieren ----------------------------------------------- - ;; Gerade Kette AS(0,0) -SEP2(VF, 10,0)- SEP3(GF, 20,0) -ES(30,0)- entlang - ;; der X-Achse. unit-spans: VF=[1,2], GF=[2,3] (SEP2 gehoert zu beiden - ;; Spannen als Grenzmarker, siehe csv:sepliste-partition). - (setq _sep-proj - '(("AS" 1 nil (0.0 0.0 0.0)) ("SEP" 2 "VF" (10.0 0.0 0.0)) - ("SEP" 3 "GF" (20.0 0.0 0.0)) ("ES" 4 nil (30.0 0.0 0.0)))) - (setq _spans-proj (csv:sepliste-partition _sep-proj)) - (tu-eq "csv:sepliste-partition/proj-spans" '(("VF" (1 2)) ("GF" (3 4))) _spans-proj) - ;; Zwei Elemente: eines bei x=5 (klar in der VF-Spanne [0,10]), eines bei - ;; x=17 (in der Luecke zwischen den Spannen-Grenzpunkten [10,20], aber - ;; naeher an der GF-Grenze 20 als an der VF-Grenze 10 - eindeutig GF, kein - ;; Gleichstand wie bei x=15 in der Luecken-Mitte). - (setq _elem-vf (list 'PROXY1 'WRAPPER "STRECKENELEMENT" '(5.0 0.0 0.0))) - (setq _elem-gf (list 'PROXY2 'WRAPPER "STRECKENELEMENT" '(17.0 0.0 0.0))) - (setq _zuord (csv:element-unit-zuordnung _spans-proj _sep-proj (list _elem-vf _elem-gf))) - (tu-eq "csv:element-unit-zuordnung/vf-treffer" (list _elem-vf) (nth 0 _zuord)) - (tu-eq "csv:element-unit-zuordnung/gf-treffer" (list _elem-gf) (nth 1 _zuord)) - - ;; Sortierung innerhalb einer Spanne: zwei Elemente in der VF-Spanne, - ;; absichtlich in "falscher" Reihenfolge uebergeben - das Ergebnis muss - ;; nach x sortiert sein (frueheres x zuerst). - (setq _elem-a (list 'PROXY_A 'WRAPPER "BOGEN" '(8.0 0.0 0.0))) - (setq _elem-b (list 'PROXY_B 'WRAPPER "BOGEN" '(2.0 0.0 0.0))) - (setq _zuord2 (csv:element-unit-zuordnung _spans-proj _sep-proj (list _elem-a _elem-b))) - (tu-eq "csv:element-unit-zuordnung/sortiert" (list _elem-b _elem-a) (nth 0 _zuord2)) + ;; --- csv:kette-ordnen: Vektorkette K2 -> K1, unabhaengig von der + ;; Eingangsreihenfolge; Start am AS. rec wird dafuer nicht gebraucht (nil). + (setq _t-as (list "AS" nil '(0.0 0.0 0.0) '(10.0 0.0 0.0))) + (setq _t-s1 (list "STRECKENELEMENT" nil '(10.0 0.0 0.0) '(20.0 0.0 0.0))) + (setq _t-b (list "BOGEN" nil '(20.0 0.0 0.0) '(20.0 10.0 0.0))) + (setq _t-es (list "ES" nil '(20.0 10.0 0.0) '(30.0 10.0 0.0))) + (tu-eq "csv:kette-ordnen/verwuerfelt" + (list _t-as _t-s1 _t-b _t-es) + (csv:kette-ordnen (list _t-b _t-es _t-as _t-s1) "TEST")) + ;; Innerhalb der Toleranz (2 mm) gilt ein Anschluss noch als geschlossen. + (setq _t-s1b (list "STRECKENELEMENT" nil '(11.5 0.0 0.0) '(20.0 0.0 0.0))) + (tu-eq "csv:kette-ordnen/toleranz" + (list _t-as _t-s1b) + (csv:kette-ordnen (list _t-s1b _t-as) "TEST")) ;; --- csv:export-modus-setzen / -p-Praedikate: 3 Modi + Ungueltig-Schutz -- ;; Bestehenden Modus sichern/wiederherstellen, damit dieser Testblock keine