Merge branch 'master' of https://gitea.schoenenberger.de/Schoenenberger_Systeme_GmbH/dxfmakros
This commit is contained in:
@@ -203,3 +203,5 @@ cfg/geruest_user.json
|
||||
# Auswertung ist eingecheckt, die Zeichnung selbst nicht.
|
||||
/data/polylines.dwg
|
||||
/data/polylines.dxf
|
||||
bin/crash_report.txt
|
||||
bin/*.dmp
|
||||
|
||||
+12
-4
@@ -1545,7 +1545,11 @@
|
||||
;; BERUEHRUNG ("Kreis/Kreis" bzw. "Kreis/Tangente", Namen wie im Python-
|
||||
;; Export export_neighbors.compute_kreisel_touch_switches).
|
||||
;; - Beruehren sich nur Laufprofile (Kreisel liegen Seite an Seite) ->
|
||||
;; KOLLISION "Tangente/Tangente".
|
||||
;; KOLLISION "Tangente/Tangente". Rad/Rad an beiden Flanken zaehlt nur bei
|
||||
;; GLEICH ausgerichteten Raedern als Seite an Seite; in Gegenrichtung
|
||||
;; (Kreisel seitlich versetzt Ende an Ende) ist es eine Weiche.
|
||||
;; - Toleranz (toleranz_beruehrung, Standard 10 mm) faengt Zeichenungenauig-
|
||||
;; keiten ab - gilt fuer Spalt UND Ueberlappung.
|
||||
;; Die reinen Kerne (kreisel-bp-element/-paar/-berechnen) laufen ohne
|
||||
;; Zeichnung und sind in tests/test_unit.lsp getestet.
|
||||
|
||||
@@ -1676,10 +1680,14 @@
|
||||
(if (<= (abs (- d (+ r (kreisel-bp-get "r" eo)))) tol)
|
||||
(progn
|
||||
(setq pt (kreisel-bp-mitte (cadr rad) (cadr rad2)))
|
||||
;; Beide Kreiselraeder nur an der Flanke = Kreisel Seite an Seite
|
||||
;; Beide Kreiselraeder nur an der Flanke UND gleich ausgerichtet =
|
||||
;; Kreisel Seite an Seite. Zeigen die Raeder in Gegenrichtung, stossen
|
||||
;; die Kreisel seitlich versetzt Ende an Ende (Raeder liegen nebeneinander,
|
||||
;; die Laufprofile treffen sich nur in einem Punkt) - das ist eine Weiche.
|
||||
(if (and (kreisel-bp-frei-p rad pt tol) (kreisel-bp-frei-p rad2 pt tol)
|
||||
(not (and (kreisel-bp-flanke-p rad pt tol)
|
||||
(kreisel-bp-flanke-p rad2 pt tol))))
|
||||
(kreisel-bp-flanke-p rad2 pt tol)
|
||||
(> (kreisel-bp-dot (caddr rad) (caddr rad2)) 0.0))))
|
||||
(setq res (cons (list pt "Kreis/Kreis" rad
|
||||
(strcat (car rad) "/" (car rad2)))
|
||||
res))))))
|
||||
@@ -1766,7 +1774,7 @@
|
||||
)
|
||||
|
||||
;; Toleranzen aus data/json/component_defaults.json (Sektion kreisel)
|
||||
(defun kreisel-bp-toleranz () (float (ssg-cfg-or "kreisel" "toleranz_beruehrung" 1.0)))
|
||||
(defun kreisel-bp-toleranz () (float (ssg-cfg-or "kreisel" "toleranz_beruehrung" 10.0)))
|
||||
(defun kreisel-bp-toleranz-z () (float (ssg-cfg-or "kreisel" "toleranz_hoehe" 1.0)))
|
||||
|
||||
;; Alle KREISEL_n/ECKRAD_n im Modellbereich als Element-Records sammeln.
|
||||
|
||||
+61
-3
@@ -682,9 +682,67 @@
|
||||
(defun vf-set-as-masse (winkel seite / m)
|
||||
(setq m (vf-element-masse (strcat "AS_Element_" winkel "_" seite)))
|
||||
(if m (setq aus-dx (car m) aus-dy (cadr m) aus-dz (caddr m))))
|
||||
(defun vf-set-es-masse (winkel seite / m)
|
||||
(setq m (vf-element-masse (strcat "ES_Element_" winkel "_" seite)))
|
||||
(if m (setq ein-dx (car m) ein-dy (cadr m) ein-dz (caddr m))))
|
||||
;; Fussabdruck eines Elements ENTLANG der Fahrtrichtung (Laengsanteil).
|
||||
;;
|
||||
;; Warum das nicht (car (vf-element-masse ...)) ist: vf-element-masse liefert
|
||||
;; KS_EIN->KS_AUS im BLOCK-Koordinatensystem. Ein Element wird aber so gedreht
|
||||
;; eingebaut, dass sein KS_EIN auf der Fahrtrichtung liegt (insert-block-ks-to-ks
|
||||
;; bzw. insert-block-by-ks mit (hz - ein-ang)). Bei einem drehenden Element -
|
||||
;; ES_Element_30 hat ein-ang = 120 Grad - landet dadurch ein TEIL der
|
||||
;; Block-Y-Komponente auf der Fahrtrichtung, und die Block-X-Komponente allein
|
||||
;; unterschaetzt den Laengsverbrauch massiv: beim ES_Element_30_rechts 242.6 mm
|
||||
;; statt tatsaechlich 576.2 mm (realer Bug, Nutzer-Befund 2026-10-09: die Kette
|
||||
;; ragte 333.65 mm ueber den gepickten Endpunkt hinaus).
|
||||
;;
|
||||
;; Die Projektion ist hz-UNABHAENGIG (der Einbauwinkel kuerzt sich heraus), sie
|
||||
;; haengt nur am blockinternen ein-ang:
|
||||
;; laengs = vx*cos(ein-ang) + vy*sin(ein-ang)
|
||||
;; Gleiche Rechnung wie etage-laengs in vf_etage.lsp mit d = -ein-ang, dort fuer
|
||||
;; die Rand-Bilanz des Etage-Typs.
|
||||
;;
|
||||
;; Rueckgabe: Laenge in mm, oder nil wenn der Block/sein KS fehlt (Aufrufer
|
||||
;; faellt dann auf das alte Verhalten zurueck).
|
||||
(defun vf-element-laengs (blockname / i rad)
|
||||
(setq i (vf-element-ks-info blockname))
|
||||
(if (null i)
|
||||
nil
|
||||
(progn
|
||||
(setq rad (* (car i) (/ pi 180.0)))
|
||||
(+ (* (caddr i) (cos rad)) (* (cadddr i) (sin rad))))))
|
||||
|
||||
;; Gegenstueck zu vf-element-laengs: Versatz QUER zur Fahrtrichtung.
|
||||
;; quer = -vx*sin(ein-ang) + vy*cos(ein-ang)
|
||||
;; Ebenfalls hz-unabhaengig. Beim ES_Element_30 sind das rund -52.5 mm - der
|
||||
;; seitliche Versatz, mit dem das ES-KS_AUS neben der Fahrtachse landet. Er
|
||||
;; wird NICHT ausgeglichen (der Hauptstrang bleibt gerade, Nutzer-Entscheidung
|
||||
;; 2026-09-15), aber er muss BEKANNT sein: die Bahn des ES-KS_AUS verlaeuft um
|
||||
;; genau diesen Betrag seitlich versetzt, und nur mit ihm trifft die
|
||||
;; Schnittpunkt-Rechnung gegen eine Ziellinie die richtige Stelle.
|
||||
(defun vf-element-quer (blockname / i rad)
|
||||
(setq i (vf-element-ks-info blockname))
|
||||
(if (null i)
|
||||
nil
|
||||
(progn
|
||||
(setq rad (* (car i) (/ pi 180.0)))
|
||||
(+ (* (- (caddr i)) (sin rad)) (* (cadddr i) (cos rad))))))
|
||||
|
||||
;; Setzt ein-dx/ein-dy/ein-dz (BLOCK-Koordinaten, fuer Quer-/Hoehenrechnungen)
|
||||
;; und zusaetzlich ein-laengs: den Fussabdruck ENTLANG der Fahrtrichtung. Wer
|
||||
;; eine Laenge von deltaL reserviert, nimmt ein-laengs - NICHT (abs ein-dx),
|
||||
;; siehe vf-element-laengs.
|
||||
(defun vf-set-es-masse (winkel seite / m blk)
|
||||
(setq blk (strcat "ES_Element_" winkel "_" seite))
|
||||
(setq m (vf-element-masse blk))
|
||||
(if m (setq ein-dx (car m) ein-dy (cadr m) ein-dz (caddr m)))
|
||||
;; Fallback auf das alte (zu kleine) Mass, wenn das KS nicht lesbar ist -
|
||||
;; lieber etwas zu kurz reservieren als gar nicht bauen koennen.
|
||||
(setq ein-laengs (vf-element-laengs blk))
|
||||
(if (and (null ein-laengs) m) (setq ein-laengs (abs (car m))))
|
||||
;; ein-quer: seitlicher Versatz des ES-KS_AUS zur Fahrtachse (siehe
|
||||
;; vf-element-quer). Wird fuer die Ziellinien-Schnittpunktrechnung gebraucht.
|
||||
(setq ein-quer (vf-element-quer blk))
|
||||
(if (null ein-quer) (setq ein-quer 0.0))
|
||||
ein-laengs)
|
||||
|
||||
|
||||
;; ============================================================
|
||||
|
||||
+466
-28
@@ -116,6 +116,36 @@
|
||||
(defun vfl-as-winkel () (if (boundp '*vfl-as-winkel*) *vfl-as-winkel* "90"))
|
||||
(defun vfl-es-winkel () (if (boundp '*vfl-es-winkel*) *vfl-es-winkel* "90"))
|
||||
|
||||
;; Laengs-Fussabdruck des ES-Elements, den ein Segment VORAB von deltaL
|
||||
;; reservieren muss, damit die Kette am gepickten Punkt endet statt
|
||||
;; darueber hinauszuragen.
|
||||
;;
|
||||
;; ein-laengs setzt vf-set-es-masse (vf_core.lsp) aus dem KS des Blocks; es ist
|
||||
;; der Anteil ENTLANG der Fahrtrichtung. Frueher stand hier (abs ein-dx) - die
|
||||
;; Block-X-Komponente - und die unterschaetzt ein DREHENDES ES-Element massiv:
|
||||
;; beim ES_Element_30_rechts 242.6 mm statt 576.2 mm, die Kette ragte dadurch
|
||||
;; 333.65 mm zu weit (Nutzer-Befund 2026-10-09). Siehe vf-element-laengs.
|
||||
;;
|
||||
;; Der seitliche Versatz (ein-dy) wird hier BEWUSST nicht ausgeglichen - der
|
||||
;; Hauptstrang bleibt gerade (Nutzer-Entscheidung 2026-09-15, bestaetigt
|
||||
;; 2026-10-09; vgl. vfl-richtung-mit-drehendem-fussabdruck).
|
||||
;;
|
||||
;; WICHTIG - Kopplung an die Null-Konvention: an rund zwei Dutzend Stellen
|
||||
;; wird ein-dx bewusst auf 0 gesetzt (und spaeter restauriert), um einen
|
||||
;; DOPPELTEN Abzug zu verhindern, wenn das ES-Element an anderer Stelle schon
|
||||
;; beruecksichtigt ist. ein-laengs wird dort NICHT mitgefuehrt. Darum gilt
|
||||
;; ein genulltes ein-dx hier als "nichts reservieren" und gewinnt vor
|
||||
;; ein-laengs - sonst wuerde dieser Fix genau den Doppelabzug einbauen, den
|
||||
;; jene Stellen vermeiden.
|
||||
;;
|
||||
;; Rueckfallkette, damit eine fehlende Messung nie einen (- deltaL nil)-Absturz
|
||||
;; ausloest: genulltes ein-dx -> ein-laengs -> (abs ein-dx) -> 0.0.
|
||||
(defun vfl-es-laengs ()
|
||||
(cond ((and (numberp ein-dx) (< (abs ein-dx) 0.001)) 0.0)
|
||||
((numberp ein-laengs) (abs ein-laengs))
|
||||
((numberp ein-dx) (abs ein-dx))
|
||||
(t 0.0)))
|
||||
|
||||
;; ============================================================
|
||||
;; TEIL 0a-2: MELDUNGEN (statt alert im Bau-Pfad)
|
||||
;; ============================================================
|
||||
@@ -332,6 +362,21 @@
|
||||
(list (cdr e)))
|
||||
nil))
|
||||
|
||||
;; Art des naechsten Replay-Eintrags, OHNE ihn zu verbrauchen ("DL", "STR",
|
||||
;; "REAL", ...) bzw. nil bei leerer Queue. STEP-Marker werden dabei wie in
|
||||
;; vfl-replay-pop uebersprungen.
|
||||
;;
|
||||
;; Gebraucht fuer Abwaertskompatibilitaet: wird an einer Stelle eine NEUE
|
||||
;; Frage eingefuehrt, fehlt deren Antwort im Journal aelterer Ketten. Statt
|
||||
;; blind zu fragen (und dadurch den naechsten Wert als Antwort zu
|
||||
;; verschlucken - ein Queue-Desync), kann der Aufrufer hier nachsehen, was
|
||||
;; tatsaechlich als Naechstes ansteht, und die Frage bei einem Altbestand
|
||||
;; ueberspringen.
|
||||
(defun vfl-replay-peek-art ( / q)
|
||||
(setq q *vfl-replay-queue*)
|
||||
(while (and q (= (car (car q)) "STEP")) (setq q (cdr q)))
|
||||
(if q (car (car q)) nil))
|
||||
|
||||
;; ============================================================
|
||||
;; TEIL 0b-1b: GLIED-SCHEMA (single source of truth)
|
||||
;; ============================================================
|
||||
@@ -671,6 +716,69 @@
|
||||
(setq r (vl-catch-all-apply 'vflw-wahl-impl (list prompt optionen default-idx)))
|
||||
(if (vl-catch-all-error-p r) "" r))
|
||||
|
||||
;; RADIO-BUTTON-Variante des generischen Wahl-Dialogs.
|
||||
;;
|
||||
;; vflw-wahl zeigt eine Listbox; fuer kurze Entscheidungen (2-3 Optionen) sind
|
||||
;; Radio-Buttons uebersichtlicher - man sieht alle Moeglichkeiten auf einen
|
||||
;; Blick statt sie in einer Liste zu suchen (Nutzer-Wunsch 2026-10-14).
|
||||
;;
|
||||
;; Technik wie bei den Standard-/Etage-Radio-Dialogen (vf_standard.lsp,
|
||||
;; Kommentar dort): Radio-Labels lassen sich nach new_dialog NICHT per
|
||||
;; set_tile aendern - darum wird die DCL bei JEDEM Aufruf frisch geschrieben
|
||||
;; (ssg-dcl-temp-schreiben) und die Labels direkt mit dem schon von ssg-text
|
||||
;; aufgeloesten String befuellt. Das funktioniert dadurch in jeder Sprache,
|
||||
;; ohne Sprachweiche. Wiederverwendet werden vfs-dcl-radio-gruppe-zeilen und
|
||||
;; vfs-dcl-radio-idx-cond (vf_standard wird vor vf_linienzug geladen).
|
||||
;;
|
||||
;; Rueckgabe IDENTISCH zu vflw-wahl: Index als String ("1", "2", ...) bzw. ""
|
||||
;; bei Abbruch/Zurueck (dann ist *vfl-wizard-abbruch-grund* gesetzt). Dadurch
|
||||
;; ist sie ein direkter Ersatz und die Journal-Semantik bleibt unberuehrt.
|
||||
(defun vflw-radio-wahl-impl (prompt optionen default-idx /
|
||||
zeilen dcl-pfad dat idx ergebnis n sauber)
|
||||
(setq n (length optionen))
|
||||
;; Die Optionstexte kommen als Konsolenzeilen ("\n 1 - Ziellinie ..."):
|
||||
;; vflw-clean schneidet Umbruch, fuehrende Leerzeichen und die Nummerierung
|
||||
;; weg - im Dialog nummerieren die Radio-Buttons selbst. Genau wie in
|
||||
;; vflw-wahl-impl, dort beim Fuellen der Listbox.
|
||||
(setq sauber (mapcar '(lambda (o) (vflw-clean o)) optionen))
|
||||
(setq zeilen
|
||||
(append
|
||||
(list "vflw_radio_dyn : dialog {"
|
||||
(strcat " label = \"" (ssg-dcl-label-escape (vflw-clean prompt)) "\";"))
|
||||
(vfs-dcl-radio-gruppe-zeilen "vflwopt" "" sauber)
|
||||
(list " ok_cancel;" "}")))
|
||||
(setq dcl-pfad (ssg-dcl-temp-schreiben "vflwradio" zeilen))
|
||||
(if (null dcl-pfad)
|
||||
'FEHLER
|
||||
(progn
|
||||
(setq dat (load_dialog dcl-pfad))
|
||||
(if (not (new_dialog "vflw_radio_dyn" dat))
|
||||
(progn
|
||||
(if (and dat (>= dat 0)) (unload_dialog dat))
|
||||
(vl-file-delete dcl-pfad)
|
||||
'FEHLER)
|
||||
(progn
|
||||
;; Vorauswahl setzen (default-idx ist 1-basiert, Tiles sind 0-basiert)
|
||||
(set_tile (strcat "vflwopt_" (itoa (max 0 (1- (if default-idx default-idx 1))))) "1")
|
||||
(action_tile "accept"
|
||||
(strcat "(setq idx " (vfs-dcl-radio-idx-cond "vflwopt" n) ") (done_dialog 1)"))
|
||||
(action_tile "cancel" "(done_dialog 0)")
|
||||
(setq ergebnis (start_dialog))
|
||||
(unload_dialog dat)
|
||||
(vl-file-delete dcl-pfad)
|
||||
(if (= ergebnis 1)
|
||||
(itoa (1+ (if idx idx 0)))
|
||||
(progn (setq *vfl-wizard-abbruch-grund* "abbrechen") "")))))))
|
||||
|
||||
;; Dispatcher: bevorzugt Radio, faellt bei technischem Fehler (Temp-Datei
|
||||
;; nicht schreibbar/ladbar) auf die Listbox-Variante zurueck - genau wie die
|
||||
;; -radio/-popup-Paare in vf_standard.lsp.
|
||||
(defun vflw-radio-wahl (prompt optionen default-idx / r)
|
||||
(setq r (vl-catch-all-apply 'vflw-radio-wahl-impl (list prompt optionen default-idx)))
|
||||
(if (or (vl-catch-all-error-p r) (eq r 'FEHLER))
|
||||
(vflw-wahl prompt optionen default-idx)
|
||||
r))
|
||||
|
||||
;; ============================================================
|
||||
;; TEIL 0b-4: GRUPPEN-DIALOGE - GEMEINSAME PUNKTWAHL-BAUSTEINE
|
||||
;; ============================================================
|
||||
@@ -1865,10 +1973,16 @@
|
||||
(defun vfl-in-string (prompt)
|
||||
(vfl-in-value-p "STR"
|
||||
(function (lambda (v) (eq (type v) 'STR)))
|
||||
(function (lambda ()
|
||||
(function (lambda ( / txt)
|
||||
(if (and (vfl-wizard-mode-p) *vflw-menu-optionen*)
|
||||
(vflw-wahl (if *vflw-menu-frage* (ssg-text *vflw-menu-frage*) prompt)
|
||||
*vflw-menu-optionen* *vflw-menu-default*)
|
||||
(progn
|
||||
(setq txt (if *vflw-menu-frage* (ssg-text *vflw-menu-frage*) prompt))
|
||||
;; *vflw-menu-radio* setzt vfl-menu-radio fuer kurze Entscheidungen,
|
||||
;; bei denen Radio-Buttons uebersichtlicher sind als eine Listbox.
|
||||
;; Alle uebrigen Fragen bleiben unveraendert bei vflw-wahl.
|
||||
(if (and (boundp '*vflw-menu-radio*) *vflw-menu-radio*)
|
||||
(vflw-radio-wahl txt *vflw-menu-optionen* *vflw-menu-default*)
|
||||
(vflw-wahl txt *vflw-menu-optionen* *vflw-menu-default*)))
|
||||
(getstring prompt))))))
|
||||
|
||||
(defun vfl-in-real (prompt)
|
||||
@@ -1902,6 +2016,20 @@
|
||||
(setq *vflw-menu-default* default-idx)
|
||||
(setq *vflw-menu-frage* frage-key)
|
||||
(vfl-in-string prompt))
|
||||
;; Wie vfl-menu, zeigt die Auswahl im Wizard-Modus aber als RADIO-BUTTONS
|
||||
;; statt als Listbox - fuer kurze Entscheidungen (2-3 Optionen) uebersichtlicher
|
||||
;; (Nutzer-Wunsch 2026-10-14). Journal-Semantik identisch zu vfl-menu: es wird
|
||||
;; derselbe "STR"-Eintrag mit dem Auswahl-Index geschrieben. Das Flag ist
|
||||
;; lokal gebunden und gilt daher nur fuer DIESEN einen Aufruf.
|
||||
(defun vfl-menu-radio (prompt option-labels default-idx frage-key /
|
||||
*vflw-menu-optionen* *vflw-menu-default* *vflw-menu-frage*
|
||||
*vflw-menu-radio*)
|
||||
(setq *vflw-menu-optionen* option-labels)
|
||||
(setq *vflw-menu-default* default-idx)
|
||||
(setq *vflw-menu-frage* frage-key)
|
||||
(setq *vflw-menu-radio* T)
|
||||
(vfl-in-string prompt))
|
||||
|
||||
(defun vfl-menu-int (prompt option-labels default-idx frage-key /
|
||||
*vflw-menu-optionen* *vflw-menu-default* *vflw-menu-frage*)
|
||||
(setq *vflw-menu-optionen* option-labels)
|
||||
@@ -3206,23 +3334,68 @@
|
||||
(make-frame-from-dir endpunkt (hz-winkel->xu hz winkel))
|
||||
)
|
||||
|
||||
;; Ansicht auf Grundriss (Draufsicht, Welt-UCS) zoomen: nach jedem
|
||||
;; Kettenglied mit Geometrieerzeugung wird die neu entstandene Strecke sonst
|
||||
;; leicht aus dem sichtbaren Bereich oder in eine schraege 3D-Ansicht
|
||||
;; hinauslaufen - der naechste Punkt (vfl-neue-linie-messen, siehe unten)
|
||||
;; waere dann schwer/ungenau anzuwaehlen. _PLAN "_World" aendert nur die
|
||||
;; ANSICHT, nicht das aktuell aktive BKS. Rein kosmetisch (per
|
||||
;; vl-catch-all-apply abgesichert) - ein Fehler hier darf den eigentlichen
|
||||
;; Kettenbau nie unterbrechen.
|
||||
(defun vfl-view-refresh ( / )
|
||||
;; Headless nur Kosten: die Ansicht sieht niemand, _PLAN/_ZOOM laufen aber
|
||||
;; vor JEDER Laengeneingabe (vfl-neue-linie-messen) - im Batch reine Zeit.
|
||||
;; Blickrichtung ist Draufsicht (Welt-Z)? Dann ist ein _PLAN ueberfluessig.
|
||||
(defun vfl-draufsicht-p ( / vd)
|
||||
(setq vd (vl-catch-all-apply 'getvar (list "VIEWDIR")))
|
||||
(if (or (vl-catch-all-error-p vd) (null vd))
|
||||
t ; unbekannt -> nicht eingreifen
|
||||
(and (< (abs (car vd)) 1e-6)
|
||||
(< (abs (cadr vd)) 1e-6)
|
||||
(> (caddr vd) 0.0))))
|
||||
|
||||
;; Liegt pt komfortabel im sichtbaren Ausschnitt? VIEWCTR/VIEWSIZE geben Mitte
|
||||
;; und HOEHE des Viewports, SCREENSIZE das Seitenverhaeltnis. Der Faktor 0.85
|
||||
;; laesst einen Rand: ein Punkt direkt an der Fensterkante gilt als "fast
|
||||
;; draussen", damit auch die noch zu bauende Strecke Platz hat.
|
||||
;; Im Zweifel (Variable nicht lesbar) T -> lieber nichts tun als springen.
|
||||
(defun vfl-punkt-sichtbar-p (pt / ctr size scr aspect)
|
||||
(setq ctr (vl-catch-all-apply 'getvar (list "VIEWCTR"))
|
||||
size (vl-catch-all-apply 'getvar (list "VIEWSIZE"))
|
||||
scr (vl-catch-all-apply 'getvar (list "SCREENSIZE")))
|
||||
(if (or (vl-catch-all-error-p ctr) (vl-catch-all-error-p size)
|
||||
(vl-catch-all-error-p scr) (null ctr) (null size) (null pt)
|
||||
(not (numberp size)) (<= size 0.0))
|
||||
t
|
||||
(progn
|
||||
(setq aspect (if (and scr (numberp (car scr)) (numberp (cadr scr))
|
||||
(> (cadr scr) 0))
|
||||
(/ (float (car scr)) (float (cadr scr)))
|
||||
1.0))
|
||||
(and (< (abs (- (car pt) (car ctr))) (* 0.85 0.5 size aspect))
|
||||
(< (abs (- (cadr pt) (cadr ctr))) (* 0.85 0.5 size))))))
|
||||
|
||||
;; Ansicht fuer die naechste Punktwahl vorbereiten - so WENIG wie moeglich.
|
||||
;;
|
||||
;; Frueher lief hier vor JEDER Laengeneingabe hart (command "_.PLAN" "_World")
|
||||
;; + (command "_.ZOOM" "_Extents"). Bei einer grossen Anlage zoomt Extents auf
|
||||
;; die GESAMTE Zeichnung: die Ansicht sprang nach jedem Klick weg, und der
|
||||
;; Nutzer musste sich jedes Mal neu zurechtfinden (Nutzer-Wunsch 2026-10-09:
|
||||
;; "beim Setzen eines Segments an dieser Position bleiben").
|
||||
;;
|
||||
;; Jetzt wird nur eingegriffen, wenn es noetig ist:
|
||||
;; - _PLAN nur, wenn die Ansicht gar keine Draufsicht ist (in einer schraegen
|
||||
;; 3D-Ansicht ist ein XY-Pick mehrdeutig - das war der eigentliche Zweck).
|
||||
;; - verschoben wird nur, wenn pt aus dem sichtbaren Ausschnitt laeuft, und
|
||||
;; dann per _ZOOM _Center: der Ausschnitt folgt dem Baupunkt, die
|
||||
;; ZOOMSTUFE bleibt erhalten (anders als _Extents).
|
||||
;; Ist der Punkt sichtbar und die Ansicht eine Draufsicht, passiert GAR NICHTS.
|
||||
;;
|
||||
;; Rein kosmetisch und per vl-catch-all-apply abgesichert - ein Fehler hier
|
||||
;; darf den Kettenbau nie unterbrechen.
|
||||
(defun vfl-view-refresh (pt / size)
|
||||
;; Headless nur Kosten: die Ansicht sieht niemand.
|
||||
(if (not (vfl-headless-p))
|
||||
(vl-catch-all-apply
|
||||
(function (lambda ()
|
||||
(command "_.PLAN" "_World")
|
||||
(command "_.ZOOM" "_Extents")))
|
||||
nil))
|
||||
(progn
|
||||
(if (not (vfl-draufsicht-p))
|
||||
(vl-catch-all-apply 'command (list "_.PLAN" "_World")))
|
||||
(if (and pt (not (vfl-punkt-sichtbar-p pt)))
|
||||
(progn
|
||||
(setq size (vl-catch-all-apply 'getvar (list "VIEWSIZE")))
|
||||
(if (or (vl-catch-all-error-p size) (not (numberp size)))
|
||||
(vl-catch-all-apply 'command (list "_.ZOOM" "_Extents"))
|
||||
;; Mitte auf den Baupunkt, Hoehe unveraendert = gleiche Zoomstufe.
|
||||
(vl-catch-all-apply 'command
|
||||
(list "_.ZOOM" "_Center" (list (car pt) (cadr pt)) size)))))))
|
||||
(princ))
|
||||
|
||||
;; --- Hilfsfunktionen fuer die VF-Einheit ---
|
||||
@@ -3257,6 +3430,65 @@
|
||||
pt
|
||||
)
|
||||
|
||||
;; Punkt-Abfrage MIT Achsenzwang: der Cursor wird auf die Anschlussachse
|
||||
;; gezwungen, statt frei in jede Richtung zu laufen.
|
||||
;;
|
||||
;; Warum: das KS_AUS des zuletzt gebauten Teils legt die Richtung des KS_EIN
|
||||
;; des naechsten Teils bereits fest - frei ist nur noch die LAENGE. Bisher
|
||||
;; durfte der Nutzer irgendwohin klicken und vfl-in-abstand projizierte den
|
||||
;; Punkt STILL auf die Fahrtrichtung: das Ergebnis entsprach nicht dem Klick,
|
||||
;; und der Fehler fiel erst an der fertigen Kette auf (Nutzer-Befund
|
||||
;; 2026-10-09, sichtbarer Knick zwischen zwei Segmenten).
|
||||
;;
|
||||
;; Technik: SNAPANG (Rasterwinkel) temporaer auf hz drehen und ORTHOMODE
|
||||
;; einschalten - ORTHO richtet sich nach SNAPANG, der Cursor rastet dadurch
|
||||
;; auf der Anschlussachse (und 90 Grad quer dazu) ein.
|
||||
;;
|
||||
;; NICHT ueber einen BKS-Wechsel: der erste Versuch drehte das BKS per
|
||||
;; (command "_.UCS" "_3point" ...) - BricsCAD kennt diese Optionsbezeichnung
|
||||
;; nicht, der Aufruf scheiterte, und weil er in vl-catch-all-apply steckte,
|
||||
;; scheiterte er STILL: der Cursor blieb frei und nur die ORTHO-Rastung auf
|
||||
;; die WELT-Achsen war aktiv (Nutzer-Befund 2026-10-09: "kann immer noch jede
|
||||
;; Richtung waehlen"). SNAPANG braucht kein Kommando, keine Options-Syntax,
|
||||
;; kein _Previous und laesst das BKS voellig unberuehrt - getpoint liefert
|
||||
;; weiterhin dieselben Koordinaten wie bisher, es ist also KEINE
|
||||
;; Koordinaten-Transformation noetig.
|
||||
;;
|
||||
;; Erzwungen wird NUR die horizontale Richtung (Nutzer-Entscheidung
|
||||
;; 2026-10-09); die Hoehe bleibt frei, weil GF-/VF-Segmente ihre Neigung
|
||||
;; selbst festlegen. SNAPANG wirkt ausschliesslich in der XY-Ebene - genau
|
||||
;; das.
|
||||
;;
|
||||
;; Ohne base oder hz (erstes Kettensegment: Richtung noch frei) faellt die
|
||||
;; Funktion unveraendert auf vfl-getpoint zurueck - ebenso ohne GUI bzw.
|
||||
;; headless: dort gibt es keinen Cursor zu fuehren.
|
||||
;; Rueckgabe: Punkt wie vfl-getpoint (gleiches Bezugssystem) oder nil.
|
||||
(defun vfl-getpoint-achse (base prompt hz / alt-snapang alt-ortho pt)
|
||||
(if (or (null base) (null hz) (not (ssg-gui-p)) (vfl-headless-p))
|
||||
(vfl-getpoint base prompt)
|
||||
(progn
|
||||
(setq alt-snapang (vl-catch-all-apply 'getvar (list "SNAPANG")))
|
||||
(setq alt-ortho (vl-catch-all-apply 'getvar (list "ORTHOMODE")))
|
||||
(if (vl-catch-all-error-p alt-snapang) (setq alt-snapang nil))
|
||||
(if (vl-catch-all-error-p alt-ortho) (setq alt-ortho nil))
|
||||
;; SNAPANG erwartet RADIANT.
|
||||
(vl-catch-all-apply 'setvar (list "SNAPANG" (* (float hz) (/ pi 180.0))))
|
||||
(vl-catch-all-apply 'setvar (list "ORTHOMODE" 1))
|
||||
;; Gecatcht, damit SNAPANG/ORTHOMODE auch bei ESC oder Fehler sicher
|
||||
;; zurueckgesetzt werden - ein verdrehter Rasterwinkel wuerde sonst in
|
||||
;; der Zeichnung des Nutzers stehen bleiben. Ein Fehler wird zu nil,
|
||||
;; also exakt dem bisherigen Abbruch-Rueckgabewert von vfl-getpoint;
|
||||
;; der Aufrufer laeuft damit in seinen vorhandenen nil-Zweig.
|
||||
(setq pt (vl-catch-all-apply 'vfl-getpoint (list base prompt)))
|
||||
(if alt-snapang (vl-catch-all-apply 'setvar (list "SNAPANG" alt-snapang)))
|
||||
(if alt-ortho (vl-catch-all-apply 'setvar (list "ORTHOMODE" alt-ortho))
|
||||
(vl-catch-all-apply 'setvar (list "ORTHOMODE" 0)))
|
||||
(if (vl-catch-all-error-p pt) (setq pt nil))
|
||||
pt
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
;; Vorschlagswert fuer die GF-Zielhoehe: die aktuelle Kettenhoehe (ist-hoehe)
|
||||
;; UNVERAENDERT als Default anzubieten fuehrt in eine Falle - ein GF-Segment
|
||||
;; MUSS fallen (0 Grad Gefaelle gibt es nicht), ein direkt uebernommener
|
||||
@@ -3325,7 +3557,12 @@
|
||||
;; picken (Gummiband). Der Punkt lebt nur hier lokal, er wird nie
|
||||
;; journalisiert.
|
||||
(setq popped (vflw-pending-pop))
|
||||
(setq p2 (if popped (car popped) (vfl-getpoint p-akt prompt)))
|
||||
;; Achsenzwang, sobald die Fahrtrichtung vom Vorgaenger feststeht
|
||||
;; (hz-vorgabe): der Cursor rastet auf der Anschlussachse ein, statt
|
||||
;; frei zu laufen und spaeter still projiziert zu werden. Beim ERSTEN
|
||||
;; Segment (hz-vorgabe=nil) definiert der Klick die Richtung noch selbst
|
||||
;; - dort faellt vfl-getpoint-achse von sich aus auf vfl-getpoint zurueck.
|
||||
(setq p2 (if popped (car popped) (vfl-getpoint-achse p-akt prompt hz-vorgabe)))
|
||||
;; *vfl-letzter-pick-z*: die Z-Hoehe DIESES Picks, fuer eine unmittelbar
|
||||
;; nachfolgende Zielhoehe-Frage (siehe vfl-hoehe-endpunkt-abfragen) als
|
||||
;; Vorschlag verfuegbar machen - vorher bei JEDEM Endpunkt-Pick
|
||||
@@ -3360,6 +3597,101 @@
|
||||
(vfl-journal-record "REAL" hz-aktuell))
|
||||
(if deltaL (cons deltaL hz-aktuell) nil))
|
||||
|
||||
;; Laenge aus einer ZIELLINIE statt aus einem freien Klick.
|
||||
;;
|
||||
;; Steht die Fahrtrichtung fest (hz), ist die Laenge der letzten Strecke nicht
|
||||
;; mehr frei: die Bahn des ES-KS_AUS - um quer seitlich versetzt - trifft die
|
||||
;; angeklickte Linie in genau einem Punkt. Ein Klick kann diesen Punkt nur
|
||||
;; annaehern (bei weit herausgezoomter Ansicht sind das schnell etliche mm),
|
||||
;; die Rechnung trifft ihn exakt (Nutzer-Vorgabe 2026-10-09: "nur EIN Winkel,
|
||||
;; dann den Schnittpunkt auf der Linie anklicken, Z kann ignoriert werden").
|
||||
;;
|
||||
;; Z wird bewusst ignoriert - rein planare X/Y-Rechnung; die Hoehe kommt
|
||||
;; weiterhin aus dem Gefaellewinkel.
|
||||
;;
|
||||
;; JOURNAL: schreibt denselben "DL"-Eintrag wie vfl-in-abstand und liest beim
|
||||
;; Replay aus derselben Queue. Dadurch ist KEIN neues Journal-Format noetig -
|
||||
;; Doppelklick-Editieren, Replay und 2D/3D-Konvertierung sehen nur eine
|
||||
;; (genauere) Laenge und muessen von Ziellinien nichts wissen. Die Bindung an
|
||||
;; die Linie geht damit allerdings verloren: wird die Linie spaeter
|
||||
;; verschoben, folgt die Kette NICHT (dafuer muesste die Linie selbst
|
||||
;; journalisiert werden, wie Modus 2 es mit "OBJS" tut).
|
||||
;;
|
||||
;; Rueckgabe: Gesamtlaenge bis zum Schnittpunkt (der Aufrufer zieht davon wie
|
||||
;; gewohnt Separator-/ES-Fussabdruck ab) oder nil bei Abbruch / wenn keine
|
||||
;; brauchbare Linie getroffen wurde.
|
||||
(defun vfl-in-abstand-ziellinie (p-akt hz quer / popped pts L fertig p2 weg)
|
||||
(if *vfl-wizard-abbruch-grund*
|
||||
(progn
|
||||
(dbgmsg (strcat "ABBRUCH-TRIGGER (Ziellinie): " *vfl-wizard-abbruch-grund* " -> (exit)"))
|
||||
(exit)))
|
||||
;; Eigene Replay-Logik (ein Eintrag pro Aufruf) -> eigener Headless-Riegel:
|
||||
;; leere Queue ist ein Desync, kein "Nutzer soll waehlen".
|
||||
(if (and (null *vfl-replay-queue*) (vfl-headless-p))
|
||||
(vfl-headless-abbruch "DL"))
|
||||
;; --- Wahl des Eingabewegs (zwei gleichwertige Optionen) ---
|
||||
;; ABWAERTSKOMPATIBILITAET: Ketten, die VOR der Einfuehrung dieser Frage
|
||||
;; gebaut wurden, haben an dieser Stelle kein "STR" im Journal, sondern
|
||||
;; direkt den "DL"-Wert. Wuerde hier blind gefragt, verschluckte die
|
||||
;; Menue-Abfrage diesen Laengenwert als Antwort -> Queue-Desync und eine
|
||||
;; falsch nachgebaute Kette. Darum beim Replay erst nachsehen, was
|
||||
;; tatsaechlich ansteht: steht dort ein "DL", ist es ein Altbestand und die
|
||||
;; Frage entfaellt (dessen Laenge entstand durch freie Punktwahl).
|
||||
(if (and *vfl-replay-queue* (= (vfl-replay-peek-art) "DL"))
|
||||
(setq weg "2")
|
||||
(progn
|
||||
(princ (ssg-text "vfl-endpunkt-modus-header"))
|
||||
(princ (ssg-text "vfl-endpunkt-modus-opt-linie"))
|
||||
(princ (ssg-text "vfl-endpunkt-modus-opt-punkt"))
|
||||
(setq weg (vfl-menu-radio (ssg-text "prompt-wahl-1-2")
|
||||
(list (ssg-text "vfl-endpunkt-modus-opt-linie")
|
||||
(ssg-text "vfl-endpunkt-modus-opt-punkt")) 1
|
||||
"vfl-endpunkt-modus-header"))))
|
||||
(if *vfl-replay-queue*
|
||||
(progn
|
||||
(setq popped (vfl-replay-pop))
|
||||
(setq L (if popped (car popped) nil)))
|
||||
;; Live: wiederholen, bis eine brauchbare Eingabe vorliegt. Beide Wege
|
||||
;; liefern EINE Laenge und schreiben daher denselben einzelnen
|
||||
;; "DL"-Journaleintrag - der Replay sieht keinen Unterschied und muss von
|
||||
;; Ziellinien nichts wissen. Abbruch (ESC) liefert nil; der Aufrufer
|
||||
;; behandelt das wie jeden anderen Eingabe-Abbruch.
|
||||
(progn
|
||||
(setq fertig nil)
|
||||
(while (not fertig)
|
||||
(if (= weg "2")
|
||||
;; --- Option 2: freie Punktwahl (wie bisher) ---
|
||||
;; Punkt picken und auf die feststehende Fahrtrichtung projizieren.
|
||||
;; Der Achsenzwang (vfl-getpoint-achse) gilt dabei weiter, der
|
||||
;; Cursor rastet also auf der Anschlussachse ein. Noetig, wenn gar
|
||||
;; keine Ziellinie existiert (Nutzer-Wunsch 2026-10-12).
|
||||
(progn
|
||||
(setq p2 (vfl-getpoint-achse p-akt
|
||||
(ssg-text "vfl-prompt-endpunkt-fahrtrichtung") hz))
|
||||
(if (null p2)
|
||||
(setq L nil fertig t)
|
||||
(progn
|
||||
(setq L (vfl-projiziere-distanz p-akt p2 hz))
|
||||
(if (< L 1.0)
|
||||
(vfl-meldung (ssg-text "vfl-ziellinie-hinter-start"))
|
||||
(setq fertig t)))))
|
||||
;; --- Option 1: Ziellinie aus zwei Punkten, Schnittpunkt gerechnet ---
|
||||
(progn
|
||||
(setq pts (vfl-ziellinie-zwei-punkte))
|
||||
(cond
|
||||
;; ESC / Punkte identisch
|
||||
((null pts) (setq L nil fertig t))
|
||||
(t
|
||||
(setq L (vfl-laenge-bis-ziellinie p-akt hz quer (car pts) (cadr pts)))
|
||||
(cond
|
||||
;; parallel zur Fahrtrichtung -> kein eindeutiger Schnittpunkt
|
||||
((null L) (vfl-meldung (ssg-text "vfl-ziellinie-parallel")))
|
||||
;; Schnittpunkt liegt hinter dem Start -> unbrauchbar
|
||||
((< L 1.0) (vfl-meldung (ssg-text "vfl-ziellinie-hinter-start")))
|
||||
(t (setq fertig t))))))))))
|
||||
(vfl-journal-record (if L "DL" "NIL") L)
|
||||
L)
|
||||
|
||||
;; Rueckgabe: (deltaL hz) oder nil bei Abbruch. Foerderer-Maximallaenge 25 m:
|
||||
;; bei Ueberschreitung wird die Eingabe abgelehnt und der Endpunkt erneut
|
||||
;; abgefragt.
|
||||
@@ -3390,7 +3722,9 @@
|
||||
(if p2 (vfl-hz-snappen-absolut (vfl-planar-hz p-akt p2)) nil)))))
|
||||
|
||||
(defun vfl-neue-linie-messen (p-akt hz-vorgabe / erg deltaL hz-aktuell ergebnis fertig)
|
||||
(vfl-view-refresh)
|
||||
;; Ansicht nur nachfuehren, wenn der Baupunkt aus dem Bild laeuft - sonst
|
||||
;; bleibt der Ausschnitt stehen (siehe vfl-view-refresh).
|
||||
(vfl-view-refresh p-akt)
|
||||
(setq fertig nil)
|
||||
(while (not fertig)
|
||||
(setq erg (vfl-in-abstand p-akt hz-vorgabe
|
||||
@@ -3422,6 +3756,92 @@
|
||||
;; die Drehteller-Rotation, die insert-block-mixed-to-ks beim echten Einfuegen
|
||||
;; anwendet, und liefern empirisch bestaetigt einen falschen Wert (~210mm
|
||||
;; Schaetzung vs. ~420mm tatsaechlich noetiger Versatz bei AS_Element_30).
|
||||
;; ============================================================
|
||||
;; ZIELLINIE: X/Y-Lage des Kettenendes aus einer Linie ableiten
|
||||
;; ============================================================
|
||||
;; Steht die Fahrtrichtung fest (Frame des Vorgaengers) und soll die Kette mit
|
||||
;; einem ES-Element auf einer vorgegebenen Linie enden, ist die Laenge NICHT
|
||||
;; mehr frei: das ES-KS_AUS laeuft auf einer Geraden PARALLEL zur
|
||||
;; Fahrtrichtung (um den ES-Querversatz seitlich versetzt), und die trifft die
|
||||
;; Ziellinie in genau einem Punkt.
|
||||
;;
|
||||
;; WICHTIG - das ist bewusst eine REIN PLANARE (X/Y-)Rechnung, kein
|
||||
;; 3D-Schnittpunkt (Nutzer-Praezisierung 2026-10-09): die HOEHE ergibt sich
|
||||
;; weiterhin aus dem Gefaellewinkel (3 Grad), die Ziellinie bestimmt
|
||||
;; ausschliesslich die X/Y-Lage. Die Z-Koordinaten der Linie werden daher
|
||||
;; ignoriert.
|
||||
;;
|
||||
;; 2D-Kreuzprodukt (Determinante) zweier Richtungen - 0 heisst parallel.
|
||||
(defun vfl-kreuz2 (ax ay bx by) (- (* ax by) (* ay bx)))
|
||||
|
||||
;; Horizontale Laenge L vom Startpunkt bis zu dem Punkt, an dem die um
|
||||
;; quer seitlich versetzte Bahn in Richtung hz die Ziellinie (durch pa und pb)
|
||||
;; schneidet.
|
||||
;; p-start : Startpunkt der Bahn (X/Y zaehlen)
|
||||
;; hz : Fahrtrichtung in Grad
|
||||
;; quer : seitlicher Versatz der Bahn (ES-Querversatz; 0 = Achse selbst)
|
||||
;; pa/pb : zwei Punkte der Ziellinie
|
||||
;; Rueckgabe: L (kann negativ sein, der Aufrufer prueft das) oder nil, wenn
|
||||
;; die Ziellinie parallel zur Fahrtrichtung liegt (kein eindeutiger Treffer).
|
||||
(defun vfl-laenge-bis-ziellinie (p-start hz quer pa pb /
|
||||
rad ux uy nx ny vx vy wx wy nenner)
|
||||
(setq rad (* (float hz) (/ pi 180.0)))
|
||||
(setq ux (cos rad) uy (sin rad)) ; Fahrtrichtung
|
||||
(setq nx (- uy) ny ux) ; quer dazu
|
||||
(setq vx (- (car pb) (car pa)) ; Richtung der Ziellinie
|
||||
vy (- (cadr pb) (cadr pa)))
|
||||
(setq nenner (vfl-kreuz2 ux uy vx vy))
|
||||
(if (< (abs nenner) 1e-9)
|
||||
nil ; parallel -> kein Schnittpunkt
|
||||
(progn
|
||||
;; w = pa - (p-start + quer*n) (Startpunkt der versetzten Bahn)
|
||||
(setq wx (- (car pa) (+ (car p-start) (* quer nx)))
|
||||
wy (- (cadr pa) (+ (cadr p-start) (* quer ny))))
|
||||
(/ (vfl-kreuz2 wx wy vx vy) nenner))))
|
||||
|
||||
;; Ziellinie auswaehlen und als zwei Punkte zurueckgeben.
|
||||
;;
|
||||
;; entsel deckt BEIDE vom Nutzer gewuenschten Eingabewege in EINER Interaktion
|
||||
;; ab (Nutzer-Wunsch 2026-10-09 "kann man nicht beide anbieten?"): es liefert
|
||||
;; gleichzeitig das getroffene Objekt UND den Pickpunkt. Wird eine Linie
|
||||
;; getroffen, wird exakt mit ihr gerechnet; wird nichts getroffen, liefert die
|
||||
;; Funktion nil und der Aufrufer bleibt beim bisherigen Punkt-Verhalten.
|
||||
;;
|
||||
;; Statt den Objekttyp zu unterscheiden, wird die TANGENTE am Pickpunkt
|
||||
;; genommen (vlax-curve-*): fuer eine LINE ist das exakt die Linie selbst, fuer
|
||||
;; eine Polylinie genau das angeklickte Segment - ohne Segment-Suche von Hand.
|
||||
;; Rueckgabe: (pa pb) oder nil.
|
||||
;; Ziellinie durch ZWEI selbst gesetzte Punkte definieren.
|
||||
;;
|
||||
;; Allgemeiner als das Anklicken eines vorhandenen Objekts (Nutzer-Idee
|
||||
;; 2026-10-12): es muss gar keine Linie gezeichnet sein. Existiert doch eine,
|
||||
;; faengt man mit Objektfang zwei Punkte darauf und hat sie exakt erfasst -
|
||||
;; dieser Weg deckt den Objekt-Fall also mit ab.
|
||||
;;
|
||||
;; WICHTIG - hier KEIN Achsenzwang (vfl-getpoint statt vfl-getpoint-achse):
|
||||
;; die Ziellinie darf jede Richtung haben. Wuerde der Cursor auf die
|
||||
;; Fahrtrichtung gezwungen, koennte man nur Linien PARALLEL dazu definieren -
|
||||
;; und genau die haben keinen Schnittpunkt.
|
||||
;;
|
||||
;; Die beiden Punkte werden NICHT journalisiert: ins Journal geht allein die
|
||||
;; daraus berechnete Laenge (ein "DL", siehe vfl-in-abstand-ziellinie). Darum
|
||||
;; der rohe vfl-getpoint und nicht vfl-in-point.
|
||||
;; Rueckgabe: (p1 p2) oder nil bei Abbruch.
|
||||
(defun vfl-ziellinie-zwei-punkte ( / p1 p2)
|
||||
(setq p1 (vfl-getpoint nil (ssg-text "vfl-prompt-ziellinie-p1")))
|
||||
(if (null p1)
|
||||
nil
|
||||
(progn
|
||||
;; Gummiband ab p1, damit die entstehende Ziellinie sichtbar ist.
|
||||
(setq p2 (vfl-getpoint p1 (ssg-text "vfl-prompt-ziellinie-p2")))
|
||||
(if (or (null p2)
|
||||
(and (< (abs (- (car p2) (car p1))) 1e-9)
|
||||
(< (abs (- (cadr p2) (cadr p1))) 1e-9)))
|
||||
nil ; abgebrochen oder Punkte identisch
|
||||
(list p1 p2)))))
|
||||
|
||||
;; Planare Projektionsdistanz von neu-basis zu ziel-punkt entlang hz - siehe
|
||||
;; unten (unveraendert).
|
||||
(defun vfl-projiziere-distanz (neu-basis ziel-punkt hz / rad)
|
||||
(setq rad (* (float hz) (/ pi 180.0)))
|
||||
(+ (* (- (car ziel-punkt) (car neu-basis)) (cos rad))
|
||||
@@ -7006,9 +7426,11 @@
|
||||
)
|
||||
)
|
||||
;; ES-Fussabdruck VORAB reservieren, siehe Kommentar bei
|
||||
;; gf-kettenende-antwort oben.
|
||||
;; gf-kettenende-antwort oben. ein-laengs = Anteil ENTLANG
|
||||
;; der Fahrtrichtung (vf-element-laengs); (abs ein-dx) waere
|
||||
;; die Block-X-Komponente und damit viel zu klein.
|
||||
(if (= gf-kettenende-antwort "1")
|
||||
(setq deltaL (- deltaL (abs ein-dx))))
|
||||
(setq deltaL (- deltaL (vfl-es-laengs))))
|
||||
(if (< deltaL 1.0)
|
||||
(princ (ssg-text "vfl-fehler-linie-zu-kurz"))
|
||||
(progn
|
||||
@@ -7117,10 +7539,26 @@
|
||||
)
|
||||
(t
|
||||
;; --- Zweig A: Endpunkt waehlen (heutiges Verhalten + Separator) ---
|
||||
(setq linie-mess (vfl-neue-linie-messen p-aktuell
|
||||
(if frame (car (frame->hz-winkel frame)) nil)))
|
||||
(if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen")) (exit)))
|
||||
(setq deltaL (car linie-mess) hz-neu (cadr linie-mess))
|
||||
;; Steht die Fahrtrichtung bereits fest (frame) UND endet die Kette
|
||||
;; mit einem ES-Element, ist die Laenge nicht mehr frei: dann wird
|
||||
;; eine ZIELLINIE angeklickt und der Schnittpunkt exakt gerechnet
|
||||
;; (Nutzer-Vorgabe 2026-10-09 - ein Klick trifft den Schnittpunkt
|
||||
;; nie genau). Trifft der Klick keine Linie, faellt der Ablauf auf
|
||||
;; die gewohnte Punktwahl zurueck, damit kein Weg verbaut wird.
|
||||
(setq hz-neu (if frame (car (frame->hz-winkel frame)) nil))
|
||||
(if (and hz-neu (= gf-kettenende-antwort "1"))
|
||||
;; Richtung steht fest UND die Kette endet mit ES -> Ziellinie.
|
||||
;; Rueckgabe ist die Gesamtlaenge bis zum Schnittpunkt; der
|
||||
;; Separator-/ES-Fussabdruck wird weiter unten wie gewohnt
|
||||
;; abgezogen.
|
||||
(progn
|
||||
(setq deltaL (vfl-in-abstand-ziellinie p-aktuell hz-neu
|
||||
(if (numberp ein-quer) ein-quer 0.0)))
|
||||
(if (null deltaL) (progn (princ (ssg-text "vfl-abgebrochen")) (exit))))
|
||||
(progn
|
||||
(setq linie-mess (vfl-neue-linie-messen p-aktuell hz-neu))
|
||||
(if (null linie-mess) (progn (princ (ssg-text "vfl-abgebrochen")) (exit)))
|
||||
(setq deltaL (car linie-mess) hz-neu (cadr linie-mess))))
|
||||
(if (< deltaL 1.0)
|
||||
(princ (ssg-text "vfl-fehler-linie-zu-kurz"))
|
||||
(progn
|
||||
@@ -7188,7 +7626,7 @@
|
||||
;; anders als die optionalen vor/nach-Separatoren oben
|
||||
;; NICHT reserviert wurde).
|
||||
(if (= gf-kettenende-antwort "1")
|
||||
(setq deltaL (- deltaL (* *vfk-separator-laenge* (cos rad3)) (abs ein-dx))))
|
||||
(setq deltaL (- deltaL (* *vfk-separator-laenge* (cos rad3)) (vfl-es-laengs))))
|
||||
(if (< deltaL 1.0)
|
||||
(progn (princ (ssg-text "vfl-fehler-linie-zu-kurz")) (setq gf-ok nil)))
|
||||
(if gf-ok
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"toleranz_kollinear": 0.01,
|
||||
"toleranz_winkel": 1.0,
|
||||
"toleranz_min_distanz": 0.001,
|
||||
"toleranz_beruehrung": 1.0,
|
||||
"toleranz_beruehrung": 10.0,
|
||||
"toleranz_hoehe": 1.0,
|
||||
"weiche_marker_radius": 50.0
|
||||
},
|
||||
|
||||
@@ -426,6 +426,7 @@ ueberspringt sie. Passende Primitive waere `insert-hz-scaled-block-by-ks`
|
||||
| `mubea.json` | Gesamtanlage: Kreisel, VF Standard/Etage, GF-Template (20 Stueck), Separatoren, Scanner, BTMT, Eingang/Ausgang | `TEST_MUBEA` |
|
||||
| `dematic_arvato.json` | Vorlage aus `dxf_scan_components.py`: Kreisel, Einzelbloecke, `gerade` (Hoehen fehlen) | `TEST_DEMATIC_ARVATO` (abgeschaltet) |
|
||||
| `showroom_ils.json` | ILS-3.0-Showroom-Vorlage aus `dxf_scan_components.py` (Kreisel, Gefaellestrecken; Hoehen teils Platzhalter), gleicher Treiber wie `dematic_arvato.json` | `TEST_SHOWROOM_ILS` |
|
||||
| `test_system.json` | Testanlage aus `dxf_anlage_export.py` (`sps_skel/data/test_system.dxf`): 9 Kreisel, 10 Separatoren, BTMT Beladung, SC Entladung - Vorlage fuer die sps_skel-Pipeline (CSV -> TRO -> SCL), gleicher Treiber wie `dematic_arvato.json` | `TEST_TEST_SYSTEM` |
|
||||
| `hundm05_linienzug_polylines.json` | Polylinien aus `extract_polylines.py` | kein Treiber (Analyse-Daten) |
|
||||
| `vfl_journal_hm05_abbruch.json` | rohes Journal (`kind`/`value`) eines abgebrochenen Baus | kein Treiber |
|
||||
|
||||
|
||||
@@ -202,6 +202,7 @@ Aus dem Menue "Tests" bzw. der Kommandozeile; Details in `doc/LispTests.md`.
|
||||
| `TEST_MUBEA` | Mubea-Nachbau aus `tests/testdata/mubea.json` |
|
||||
| `TEST_DEMATIC_ARVATO` | Dematic/Arvato-Nachbau (Flowpuffer/Kreisel) |
|
||||
| `TEST_SHOWROOM_ILS` | ILS-3.0-Showroom-Nachbau (Kreisel, Gefaellestrecken; Hoehen noch Platzhalter) |
|
||||
| `TEST_TEST_SYSTEM` | Testanlage `test_system` nachbauen (9 Kreisel, Separatoren, BTMT) - Vorlage fuer sps_skel |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -99,6 +99,13 @@
|
||||
"vfl-es-setzen-frage": "\n\nES-Element setzen?",
|
||||
"vfl-es-nein-zielpunkt": "\n 2 - Nein (Kette endet direkt am Zielpunkt)",
|
||||
"vfl-prompt-endpunkt-fahrtrichtung": "\n\nEndpunkt entlang Fahrtrichtung waehlen (bestimmt die Laenge): ",
|
||||
"vfl-endpunkt-modus-header": "\n\nWie soll der Endpunkt bestimmt werden?",
|
||||
"vfl-endpunkt-modus-opt-linie": "\n 1 - Ziellinie zeichnen (2 Punkte) - der Schnittpunkt bestimmt die Laenge",
|
||||
"vfl-prompt-ziellinie-p1": "\n\nZiellinie - 1. Punkt (beliebige Richtung, Z wird ignoriert): ",
|
||||
"vfl-prompt-ziellinie-p2": "\n Ziellinie - 2. Punkt: ",
|
||||
"vfl-endpunkt-modus-opt-punkt": "\n 2 - Punkt waehlen - entlang der festen Fahrtrichtung",
|
||||
"vfl-ziellinie-parallel": "\n Die gewaehlte Linie liegt parallel zur Fahrtrichtung - es gibt keinen eindeutigen Schnittpunkt.",
|
||||
"vfl-ziellinie-hinter-start": "\n Der Schnittpunkt liegt hinter dem Startpunkt der Strecke - bitte eine andere Linie waehlen.",
|
||||
"vfl-prompt-endpunkt-frei": "\n\nEndpunkt der Linie (XY, beliebige Richtung): ",
|
||||
"vfl-fehler-laenge-max": "\n>>> FEHLER: Laenge %1 m ueberschreitet die Foerderer-Maximallaenge von 25 m - bitte anderen Endpunkt waehlen.",
|
||||
"vfl-glied-gf-bogen": "GF-Bogen (horizontale Kurve)",
|
||||
|
||||
@@ -99,6 +99,13 @@
|
||||
"vfl-es-setzen-frage": "\n\nPlace ES element?",
|
||||
"vfl-es-nein-zielpunkt": "\n 2 - No (chain ends directly at the target point)",
|
||||
"vfl-prompt-endpunkt-fahrtrichtung": "\n\nSelect end point along travel direction (defines the length): ",
|
||||
"vfl-endpunkt-modus-header": "\n\nHow should the end point be determined?",
|
||||
"vfl-endpunkt-modus-opt-linie": "\n 1 - Draw target line (2 points) - the intersection defines the length",
|
||||
"vfl-prompt-ziellinie-p1": "\n\nTarget line - 1st point (any direction, Z is ignored): ",
|
||||
"vfl-prompt-ziellinie-p2": "\n Target line - 2nd point: ",
|
||||
"vfl-endpunkt-modus-opt-punkt": "\n 2 - Select point - along the fixed travel direction",
|
||||
"vfl-ziellinie-parallel": "\n The selected line is parallel to the travel direction - there is no unique intersection.",
|
||||
"vfl-ziellinie-hinter-start": "\n The intersection lies behind the start of the run - please select a different line.",
|
||||
"vfl-prompt-endpunkt-frei": "\n\nEnd point of the line (XY, any direction): ",
|
||||
"vfl-fehler-laenge-max": "\n>>> ERROR: Length %1 m exceeds the conveyor maximum length of 25 m - please pick another end point.",
|
||||
"vfl-glied-gf-bogen": "GF arc (horizontal curve)",
|
||||
|
||||
@@ -336,6 +336,27 @@ def einzel_eintrag(e):
|
||||
])
|
||||
|
||||
|
||||
def kreisel_ids_eindeutig(kreisel, projekt, hinweise):
|
||||
"""Doppelte Kreisel-IDs aufloesen. Die Nummer kommt aus NUMMER bzw. dem
|
||||
Blocknamen; in einer Zeichnung, in der Kreisel einzeln gebaut wurden,
|
||||
beginnt sie jedes Mal neu bei 1 (test_system: vier KREISEL_1_*). Der
|
||||
erste behaelt seine ID, jeder weitere bekommt die naechste freie Nummer
|
||||
oberhalb der hoechsten vergebenen. Die Reihenfolge ist die der Eingabe
|
||||
(Blockname, x, y) und damit stabil."""
|
||||
muster = re.compile(r"^Kreisel_%s_(\d+)$" % re.escape(projekt))
|
||||
nummern = [int(m.group(1)) for m in (muster.match(k[sch.F_ID]) for k in kreisel) if m]
|
||||
naechste = max(nummern, default=0) + 1
|
||||
vergeben = set()
|
||||
for k in kreisel:
|
||||
if k[sch.F_ID] in vergeben:
|
||||
alt = k[sch.F_ID]
|
||||
k[sch.F_ID] = "Kreisel_%s_%02d" % (projekt, naechste)
|
||||
naechste += 1
|
||||
hinweise.append("%s doppelt - Kreisel bei %.2f/%.2f umbenannt in %s"
|
||||
% (alt, k[sch.F_X], k[sch.F_Y], k[sch.F_ID]))
|
||||
vergeben.add(k[sch.F_ID])
|
||||
|
||||
|
||||
def baue_eintraege(inserts, block_inhalt, projekt):
|
||||
"""Reihenfolge wie mubea.json: Kreisel, VF, GF, Einzelbloecke - die VF
|
||||
vor den GF, weil gf-init-bibliothek globale Elementmasse umsetzt."""
|
||||
@@ -344,6 +365,7 @@ def baue_eintraege(inserts, block_inhalt, projekt):
|
||||
name = e["name"] or ""
|
||||
if name.startswith("KREISEL_"):
|
||||
kreisel.append(kreisel_eintrag(e, block_inhalt, projekt))
|
||||
kreisel_ids_eindeutig(kreisel, projekt, hinweise)
|
||||
geo = [kreisel_geo(k) for k in kreisel]
|
||||
for e in inserts:
|
||||
name = e["name"] or ""
|
||||
|
||||
@@ -255,6 +255,14 @@ def build_sensor_merkmale(block):
|
||||
}
|
||||
|
||||
|
||||
def _sensor_zuordnung_attr(block):
|
||||
"""Carrier-ID (Kreisel/GF/VF-TeileId) eines Separator-/Scanner-Blocks aus
|
||||
der Zeichnung: zuordnung_fix (verpackte Kopie, siehe build_sensor_
|
||||
merkmale) vor dem ZUORDNUNG-Attribut. "" wenn nichts gesetzt ist."""
|
||||
return (block.get("zuordnung_fix")
|
||||
or block.get("attribs", {}).get("ZUORDNUNG", "") or "").strip()
|
||||
|
||||
|
||||
def build_element_merkmale(block):
|
||||
"""Merkmale-Dict fuer eine ausgepackte VF_n/GF_n-Sub-Komponente (Bogen/
|
||||
Streckenelement/Umlenkstation/Motorstation) - siehe csv:element-proxies-
|
||||
@@ -1341,6 +1349,11 @@ def process_blocks(blocks, lookup, dbg=None, lisp_weichen=None):
|
||||
# Zuordnung, die compute_sensor_zuordnung unten nicht
|
||||
# ueberschreiben darf - siehe build_sensor_merkmale.
|
||||
"_zuordnung_fix": bool(block.get("zuordnung_fix")),
|
||||
# Privates Feld: Carrier-ID aus der Zeichnung (zuordnung_fix
|
||||
# bzw. ZUORDNUNG-Attribut, von cs-zuordnung-lauf in
|
||||
# Lisp/count_sep_scan.lsp gepflegt) - hat in compute_sensor_
|
||||
# zuordnung/compute_kreisel_umlauf Vorrang vor der BBox-Suche.
|
||||
"_zuordnung_attr": _sensor_zuordnung_attr(block),
|
||||
# Roher INSERT-Punkt (nicht der bbox-Mittelpunkt) - dient
|
||||
# map_sepliste_kette_items als Koordinaten-FALLBACK, falls der
|
||||
# sepliste-Eintrag (noch) kein "id"-Feld traegt (Altbestand;
|
||||
@@ -1368,6 +1381,7 @@ def process_blocks(blocks, lookup, dbg=None, lisp_weichen=None):
|
||||
# sammelt - csv:block-to-json (export.lsp) haengt den Text als
|
||||
# "warnung"-Feld an den betroffenen Scanner-Block im JSON an.
|
||||
"warnung": block.get("warnung", ""),
|
||||
"_zuordnung_attr": _sensor_zuordnung_attr(block),
|
||||
**bbox_columns(block),
|
||||
})
|
||||
continue
|
||||
|
||||
+33
-4
@@ -784,6 +784,9 @@ def compute_sensor_zuordnung(items, tolerance_mm, kreisel_durchmesser_mm=800.0,
|
||||
gf_entries = []
|
||||
vf_entries = []
|
||||
kreisel_entries = []
|
||||
# TeileIds aller Carrier (GF/VF/Kreisel) - fuer den Vorrang des
|
||||
# ZUORDNUNG-Attributs ("_zuordnung_attr") vor der BBox-Suche.
|
||||
carrier_ids = set()
|
||||
|
||||
for item in items:
|
||||
bbox = item.get("_bbox")
|
||||
@@ -793,9 +796,12 @@ def compute_sensor_zuordnung(items, tolerance_mm, kreisel_durchmesser_mm=800.0,
|
||||
teileid = item.get("teileid", "")
|
||||
if teileart == "ILS 2.0 Gefaellestrecke":
|
||||
gf_entries.append((teileid, _bounds(bbox, half_tol)))
|
||||
carrier_ids.add(teileid)
|
||||
elif teileart in ("ILS 2.0 Strecke", "ILS 2.0 Strecke - Modul"):
|
||||
vf_entries.append((teileid, _bounds(bbox, half_tol)))
|
||||
carrier_ids.add(teileid)
|
||||
elif teileart == KREISEL_SPLIT_TEILEART:
|
||||
carrier_ids.add(teileid)
|
||||
bbox_links, bbox_rechts = kreisel_half_bboxes(item, kreisel_durchmesser_mm)
|
||||
kreisel_entries.append((f"{teileid}-L", _bounds(bbox_links, half_tol)))
|
||||
kreisel_entries.append((f"{teileid}-R", _bounds(bbox_rechts, half_tol)))
|
||||
@@ -824,10 +830,22 @@ def compute_sensor_zuordnung(items, tolerance_mm, kreisel_durchmesser_mm=800.0,
|
||||
result.append("")
|
||||
continue
|
||||
bounds = _bounds(bbox, half_tol)
|
||||
treffer = (_find(bounds, gf_entries)
|
||||
or _find(bounds, vf_entries)
|
||||
or _find(bounds, kreisel_entries)
|
||||
or "nicht zugeordnet")
|
||||
# Vorrang: ZUORDNUNG aus der Zeichnung (cs-zuordnung-lauf), sofern sie
|
||||
# einen vorhandenen Carrier nennt. Die BBox-Suche nimmt sonst den
|
||||
# ERSTEN Treffer - an einer Kreisel-Kreisel-Weiche ragt ein Separator
|
||||
# mit Toleranz in beide Kreisel und landete beim falschen (realer
|
||||
# Fall test_system, Separator 0018: Attribut 0005, BBox -> 0006).
|
||||
# Bei einem Kreisel wird nur noch die Haelfte (L/R) per BBox bestimmt.
|
||||
attr = (item.get("_zuordnung_attr") or "").strip()
|
||||
if attr in carrier_ids:
|
||||
haelften = [e for e in kreisel_entries
|
||||
if e[0] in (f"{attr}-L", f"{attr}-R")]
|
||||
treffer = (_find(bounds, haelften) if haelften else None) or attr
|
||||
else:
|
||||
treffer = (_find(bounds, gf_entries)
|
||||
or _find(bounds, vf_entries)
|
||||
or _find(bounds, kreisel_entries)
|
||||
or "nicht zugeordnet")
|
||||
if dbg:
|
||||
dbg(f" {item.get('teileart', '')} {item.get('teileid', '')!r} "
|
||||
f"bounds={_fmt_bounds(bounds)} -> {treffer!r}")
|
||||
@@ -1383,7 +1401,18 @@ def compute_kreisel_umlauf(items, tolerance_mm, durchmesser_mm=800.0,
|
||||
continue
|
||||
bounds = _bounds(bbox, half_tol)
|
||||
matched_tid = None
|
||||
# Vorrang: ZUORDNUNG-Attribut des Separators/Scanners, wenn es einen
|
||||
# Kreisel nennt (siehe compute_sensor_zuordnung) - die BBox-Suche
|
||||
# unten nimmt den ERSTEN ueberlappenden Kreisel und verwechselt an
|
||||
# einer Kreisel-Kreisel-Weiche die beiden Kreisel.
|
||||
attr = (item.get("_zuordnung_attr") or "").strip()
|
||||
if attr in kreisel_bounds:
|
||||
punkte_je_kreisel[attr].append(
|
||||
(teileid, bbox.get("cx", 0.0), bbox.get("cy", 0.0)))
|
||||
matched_tid = attr
|
||||
for tid, kb in kreisel_bounds.items():
|
||||
if matched_tid is not None:
|
||||
break
|
||||
if _overlaps(bounds, kb):
|
||||
punkte_je_kreisel[tid].append(
|
||||
(teileid, bbox.get("cx", 0.0), bbox.get("cy", 0.0)))
|
||||
|
||||
@@ -872,6 +872,12 @@
|
||||
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) (c:TEST_SHOWROOM_ILS)</Command>
|
||||
</Macro>
|
||||
</MenuMacro>
|
||||
<MenuMacro UID="MM_00210">
|
||||
<Macro>
|
||||
<Name>Testanlage test_system</Name>
|
||||
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_test_system.lsp")) (c:TEST_TEST_SYSTEM)</Command>
|
||||
</Macro>
|
||||
</MenuMacro>
|
||||
<MenuMacro UID="MM_00189">
|
||||
<Macro>
|
||||
<Name>KS 2D/3D pruefen (CSV)</Name>
|
||||
@@ -1921,6 +1927,12 @@
|
||||
<MacroRef MenuMacroID="MM_00188"/>
|
||||
</MenuItem>
|
||||
</PopMenuItem>
|
||||
<PopMenuItem>
|
||||
<NameRef>Testanlage test_system</NameRef>
|
||||
<MenuItem>
|
||||
<MacroRef MenuMacroID="MM_00210"/>
|
||||
</MenuItem>
|
||||
</PopMenuItem>
|
||||
<PopMenuItem>
|
||||
<NameRef>KS 2D/3D pruefen (CSV)</NameRef>
|
||||
<MenuItem>
|
||||
|
||||
@@ -186,6 +186,7 @@
|
||||
[HundM05 Kreisel-Abschnitt]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")) (c:TEST_HUNDM05)
|
||||
[Dematic/Arvato Flowpuffer (Vorlage)]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) (c:TEST_DEMATIC_ARVATO)
|
||||
[ILS 3.0 Showroom (Vorlage)]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) (c:TEST_SHOWROOM_ILS)
|
||||
[Testanlage test_system]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_test_system.lsp")) (c:TEST_TEST_SYSTEM)
|
||||
[<-KS 2D/3D pruefen (CSV)]^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN
|
||||
|
||||
***DOUBLECLICK
|
||||
|
||||
+2
-1
@@ -12,5 +12,6 @@
|
||||
{ "name": "hundm05", "save": "dxf", "module": "VarioFoerderer" },
|
||||
{ "name": "dematic_arvato", "save": "dxf", "module": "VarioFoerderer", "disabled": true },
|
||||
{ "name": "hm_recformat", "save": "dxf", "module": "VarioFoerderer", "disabled": true },
|
||||
{ "name": "showroom_ils", "save": "dxf", "module": "VarioFoerderer", "disabled": true }
|
||||
{ "name": "showroom_ils", "save": "dxf", "module": "VarioFoerderer", "disabled": true },
|
||||
{ "name": "test_system", "save": "dxf", "module": "VarioFoerderer" }
|
||||
]
|
||||
|
||||
@@ -145,3 +145,18 @@ def test_reihenfolge_vf_vor_gf():
|
||||
art = ["K" if "abstand" in e else "GF" if "modus" in e else
|
||||
"VF" if "typ" in e else e["block"] for e in eintraege]
|
||||
assert art == ["K", "K", "VF", "GF", "Scanner"]
|
||||
|
||||
|
||||
def test_doppelte_kreisel_nummern_werden_eindeutig():
|
||||
# test_system.dxf: Kreisel einzeln gebaut, NUMMER beginnt jedes Mal bei 1
|
||||
eins_a = _insert("KREISEL_1_STANDARD_2300", (-3561.74, 994.84, 2000.0), 0.0,
|
||||
{"NUMMER": "1"})
|
||||
eins_b = _insert("KREISEL_1_STANDARD_2900", (4940.59, -2303.25, 0.0), 90.0,
|
||||
{"NUMMER": "1"})
|
||||
zwei = _insert("KREISEL_2_STANDARD_4500", (4940.03, -7603.25, 0.0), 90.0,
|
||||
{"NUMMER": "2"})
|
||||
eintraege, hinweise = dae.baue_eintraege([eins_a, eins_b, zwei], {}, "T")
|
||||
ids = {k["id"]: k["x"] for k in eintraege}
|
||||
assert sorted(ids) == ["Kreisel_T_01", "Kreisel_T_02", "Kreisel_T_03"]
|
||||
assert ids["Kreisel_T_03"] == 4940.59 # der zweite KREISEL_1 weicht aus
|
||||
assert any("Kreisel_T_03" in h for h in hinweise)
|
||||
|
||||
@@ -538,3 +538,51 @@ class TestAsEsUeberEinlaufpunkt:
|
||||
umlauf = compute_kreisel_umlauf(
|
||||
items, tolerance_mm=200.0, durchmesser_mm=DURCHMESSER_MM)
|
||||
assert "0071" not in [p[0] for p in umlauf["0001"]]
|
||||
|
||||
|
||||
class TestZuordnungAttributVorBBox:
|
||||
"""Realer Fall test_system, Separator 0018: er sitzt an der Kreisel-
|
||||
Kreisel-Weiche zweier Kreisel und ragt mit Toleranz in die Box BEIDER.
|
||||
Die BBox-Suche nahm den ersten Kreisel in der Item-Liste (den falschen);
|
||||
das ZUORDNUNG-Attribut aus der Zeichnung (cs-zuordnung-lauf) nennt den
|
||||
richtigen und hat Vorrang."""
|
||||
|
||||
def _anlage(self, attr):
|
||||
# Kreisel 0006 senkrecht (Achse +Y), AN8-Mitte bei (0, 400);
|
||||
# Kreisel 0005 waagerecht (Achse +X), AN8-Mitte bei (0, -400):
|
||||
# AN8/AN8 beruehren sich bei (0, 0). Separator auf der Oberkante von
|
||||
# Kreisel 0005, 615 mm rechts der Weiche.
|
||||
k6 = _kreisel("0006", 0.0, 0.0, 90.0, abstand=2000.0)
|
||||
k5 = _kreisel("0005", -400.0, -400.0, 0.0, abstand=8000.0)
|
||||
sep = _separator("0018", 615.0, 0.0)
|
||||
sep["_zuordnung_attr"] = attr
|
||||
sep["merkmale"] = {}
|
||||
return [sep, k6, k5]
|
||||
|
||||
def test_umlauf_folgt_attribut(self):
|
||||
items = self._anlage("0005")
|
||||
umlauf = compute_kreisel_umlauf(items, tolerance_mm=200.0,
|
||||
durchmesser_mm=DURCHMESSER_MM)
|
||||
assert "0018" in [p[0] for p in umlauf["0005"]]
|
||||
assert "0018" not in [p[0] for p in umlauf["0006"]]
|
||||
|
||||
def test_ohne_attribut_bbox_rueckfall(self):
|
||||
items = self._anlage("")
|
||||
umlauf = compute_kreisel_umlauf(items, tolerance_mm=200.0,
|
||||
durchmesser_mm=DURCHMESSER_MM)
|
||||
alle = [p[0] for pts in umlauf.values() for p in pts]
|
||||
assert alle.count("0018") == 1
|
||||
|
||||
def test_sensor_zuordnung_folgt_attribut(self):
|
||||
from export_neighbors import compute_sensor_zuordnung
|
||||
items = self._anlage("0005")
|
||||
zuo = compute_sensor_zuordnung(items, 200.0,
|
||||
kreisel_durchmesser_mm=DURCHMESSER_MM)
|
||||
assert zuo[0].startswith("0005")
|
||||
|
||||
def test_unbekanntes_attribut_bbox_rueckfall(self):
|
||||
from export_neighbors import compute_sensor_zuordnung
|
||||
items = self._anlage("9999")
|
||||
zuo = compute_sensor_zuordnung(items, 200.0,
|
||||
kreisel_durchmesser_mm=DURCHMESSER_MM)
|
||||
assert zuo[0] != "9999" and zuo[0] != "nicht zugeordnet"
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
;; ============================================================
|
||||
;; test_test_system.lsp - Nachbau der Testanlage "test_system".
|
||||
;;
|
||||
;; Datenquelle: tests/testdata/test_system.json. Die Zeichnung wurde mit
|
||||
;; unseren Makros gebaut (KREISEL_n-Wrapper, Separatoren, BTMT), die Testdaten
|
||||
;; kommen darum aus dem Rueckleser, nicht aus dem Scanner:
|
||||
;; python lib/dxf_anlage_export.py \
|
||||
;; C:/develop/sps_skel/data/test_system.dxf \
|
||||
;; tests/testdata/test_system.json --projekt TestSystem
|
||||
;;
|
||||
;; Inhalt: 9 Kreisel (STANDARD, Ebenen 0 / 2000 / 3000), 10 Separatoren,
|
||||
;; BTMT Beladung und SC Entladung - keine Gefaellestrecken, keine VF.
|
||||
;; - Die Kreisel wurden in der Zeichnung einzeln gebaut, die Nummer begann
|
||||
;; dabei mehrmals neu bei 1 (vier KREISEL_1_*). dxf_anlage_export.py
|
||||
;; vergibt fuer die Doppelten Kreisel_TestSystem_07..09 - die Nummern der
|
||||
;; gebauten Zeichnung weichen also von der Vorlage ab.
|
||||
;; - Die x-Werte sind NACH dem Rueckleser von Hand korrigiert: in der
|
||||
;; Zeichnung lagen die Kreisel bis zu 5.5 mm daneben, jetzt beruehren sich
|
||||
;; alle 8 Weichenpaare exakt (1-9, 9-8, 8-7, 7-2, 2-3, 3-4, 4-5, 5-6;
|
||||
;; Kreisel 1 fest, Separatoren/BTMT mit ihrem Kreisel verschoben). Ein
|
||||
;; erneuter Lauf von dxf_anlage_export.py macht das rueckgaengig.
|
||||
;;
|
||||
;; Zweck: Vorlage fuer sps_skel. Nachbau -> EXPORTCSV -> CSV, auf die dort
|
||||
;; material_flow.py / tro_flow.py / scl_skeleton.py angewendet werden.
|
||||
;;
|
||||
;; Keine eigene Bau-Logik: Eintragsschema und Lauf wie TEST_DEMATIC_ARVATO
|
||||
;; (dematic_arvato:bau-datei aus tests/test_dematic_arvato.lsp).
|
||||
;;
|
||||
;; Aufruf in BricsCAD:
|
||||
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_test_system.lsp"))
|
||||
;; TEST_TEST_SYSTEM
|
||||
;; ============================================================
|
||||
|
||||
(if (not (boundp '*test-system-records*)) (setq *test-system-records* nil))
|
||||
|
||||
;; Beim LADEN holen (siehe test_dematic_arvato.lsp: per load definierte
|
||||
;; Funktionen sind erst nach Rueckkehr zum Top-Level sichtbar).
|
||||
(if (null (car (atoms-family 1 '("DEMATIC_ARVATO:BAU-DATEI"))))
|
||||
(load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")))
|
||||
|
||||
(defun test_system:datei ()
|
||||
(strcat (getenv "DXFMAKRO") "/tests/testdata/test_system.json"))
|
||||
|
||||
(defun c:TEST_TEST_SYSTEM ()
|
||||
(setq *test-system-records*
|
||||
(dematic_arvato:bau-datei "TEST_TEST_SYSTEM" "Testanlage test_system"
|
||||
(test_system:datei)))
|
||||
(princ))
|
||||
|
||||
;; Ergebnis-Export (Konvention <name>:export-results fuer test_run_all.lsp)
|
||||
(defun test_system:export-results (out-dir / pfad)
|
||||
(if (null *test-system-records*)
|
||||
(princ "\n Keine test_system-Ergebnisse vorhanden.")
|
||||
(progn
|
||||
(vl-mkdir out-dir)
|
||||
(setq pfad (strcat out-dir "/test_system_results.json"))
|
||||
(vsp-results-schreiben *test-system-records* pfad)))
|
||||
(princ))
|
||||
|
||||
(princ "\nTEST_TEST_SYSTEM geladen. Aufruf: TEST_TEST_SYSTEM")
|
||||
(princ)
|
||||
+119
-1
@@ -360,6 +360,95 @@
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: vf_linienzug.lsp - ES-Fussabdruck entlang der Fahrtrichtung
|
||||
;; ------------------------------------------------------------
|
||||
;; vfl-es-laengs liefert die Laenge, die ein Segment fuer das ES-Element
|
||||
;; reservieren muss. Getestet wird die Rueckfallkette: ohne sie wuerde ein
|
||||
;; fehlender Messwert zu (- deltaL nil) und damit zum Absturz fuehren.
|
||||
(defun tu-tests-vfl-es ( / _s-laengs _s-dx)
|
||||
(princ "\n[vf_linienzug ES]")
|
||||
;; globale Masse sichern - sie gehoeren dem laufenden Bau-Kontext
|
||||
(setq _s-laengs ein-laengs _s-dx ein-dx)
|
||||
|
||||
;; Normalfall: ein-laengs ist gesetzt und wird genommen.
|
||||
;; 576.2 = ES_Element_30_rechts entlang der Fahrtrichtung; (abs ein-dx)
|
||||
;; waere 242.6 - genau die 333.65 mm, um die die Kette frueher zu weit ragte.
|
||||
(setq ein-laengs 576.2 ein-dx -242.6)
|
||||
(tu-eqf "vfl-es-laengs/nimmt-laengs-nicht-dx" 576.2 (vfl-es-laengs))
|
||||
|
||||
;; Vorzeichen: reserviert wird immer ein Betrag
|
||||
(setq ein-laengs -576.2)
|
||||
(tu-eqf "vfl-es-laengs/betrag" 576.2 (vfl-es-laengs))
|
||||
|
||||
;; Genulltes ein-dx gewinnt: die Null-Konvention der Bau-Pfade bedeutet
|
||||
;; "ES anderswo schon beruecksichtigt - hier nichts reservieren". Ohne diese
|
||||
;; Kopplung wuerde der Fix einen doppelten Abzug einbauen.
|
||||
(setq ein-laengs 576.2 ein-dx 0.0)
|
||||
(tu-eqf "vfl-es-laengs/genulltes-dx-gewinnt" 0.0 (vfl-es-laengs))
|
||||
|
||||
;; KS nicht lesbar -> Rueckfall auf das alte (zu kleine) Blockmass
|
||||
(setq ein-laengs nil ein-dx -242.6)
|
||||
(tu-eqf "vfl-es-laengs/fallback-auf-dx" 242.6 (vfl-es-laengs))
|
||||
|
||||
;; gar nichts gemessen -> 0.0, niemals nil (Absturzschutz)
|
||||
(setq ein-dx nil)
|
||||
(tu-eqf "vfl-es-laengs/fallback-null" 0.0 (vfl-es-laengs))
|
||||
|
||||
(setq ein-laengs _s-laengs ein-dx _s-dx)
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: vf_linienzug.lsp - Laenge aus einer Ziellinie (X/Y)
|
||||
;; ------------------------------------------------------------
|
||||
;; Steht die Fahrtrichtung fest, ist die Laenge nicht mehr frei: die (ggf.
|
||||
;; seitlich versetzte) Bahn trifft die Ziellinie in genau einem Punkt.
|
||||
;; REIN PLANAR - die Hoehe kommt weiterhin aus dem Gefaellewinkel.
|
||||
(defun tu-tests-vfl-ziellinie ( / _p0 _l _ks)
|
||||
(princ "\n[vf_linienzug Ziellinie]")
|
||||
|
||||
(tu-eqf "vfl-kreuz2/einheitsachsen" 1.0 (vfl-kreuz2 1.0 0.0 0.0 1.0))
|
||||
(tu-eqf "vfl-kreuz2/parallel" 0.0 (vfl-kreuz2 2.0 4.0 1.0 2.0))
|
||||
|
||||
(setq _p0 '(0.0 0.0 0.0))
|
||||
|
||||
;; Fahrtrichtung 0 Grad, senkrechte Ziellinie bei x=1000 -> L=1000
|
||||
(tu-eqf "vfl-laenge-bis-ziellinie/senkrecht"
|
||||
1000.0 (vfl-laenge-bis-ziellinie _p0 0.0 0.0 '(1000.0 -500.0 0.0) '(1000.0 500.0 0.0)))
|
||||
|
||||
;; Querversatz verschiebt die BAHN seitlich, nicht laengs: bei einer zur
|
||||
;; Fahrtrichtung senkrechten Ziellinie bleibt L deshalb gleich.
|
||||
(tu-eqf "vfl-laenge-bis-ziellinie/querversatz-ohne-wirkung"
|
||||
1000.0 (vfl-laenge-bis-ziellinie _p0 0.0 52.5 '(1000.0 -500.0 0.0) '(1000.0 500.0 0.0)))
|
||||
|
||||
;; 45-Grad-Ziellinie durch (1000,0): die um +100 versetzte Bahn trifft sie
|
||||
;; 100 frueher (y=100 wird bei x=1100 erreicht -> ohne Versatz 1000+100).
|
||||
(tu-eqf "vfl-laenge-bis-ziellinie/schraege-linie"
|
||||
1100.0 (vfl-laenge-bis-ziellinie _p0 0.0 100.0 '(1000.0 0.0 0.0) '(2000.0 1000.0 0.0)))
|
||||
|
||||
;; Ziellinie PARALLEL zur Fahrtrichtung -> kein eindeutiger Treffer -> nil
|
||||
(tu-nil "vfl-laenge-bis-ziellinie/parallel"
|
||||
(vfl-laenge-bis-ziellinie _p0 0.0 0.0 '(0.0 500.0 0.0) '(1000.0 500.0 0.0)))
|
||||
|
||||
;; Z der Ziellinie ist irrelevant (rein planare Rechnung, Nutzer-Vorgabe):
|
||||
;; dieselbe Linie auf anderer Hoehe liefert dasselbe L.
|
||||
(tu-eqf "vfl-laenge-bis-ziellinie/z-ignoriert"
|
||||
1000.0 (vfl-laenge-bis-ziellinie _p0 0.0 0.0 '(1000.0 -500.0 7777.0) '(1000.0 500.0 -99.0)))
|
||||
|
||||
;; Realfall aus dem Nutzer-Log: nach dem 30-Grad-Bogen steht die Kette bei
|
||||
;; (901.21,-2728.97) mit hz=-120; das ES-KS_AUS laeuft 52.51 mm versetzt und
|
||||
;; landete bei (231.42,-3994.11). Eine Ziellinie durch diesen Punkt quer zur
|
||||
;; Fahrtrichtung muss genau die damals gebaute Gesamtlaenge liefern.
|
||||
(setq _ks '(231.42 -3994.11 0.0))
|
||||
(setq _l (vfl-laenge-bis-ziellinie '(901.21 -2728.97 0.0) -120.0 52.51
|
||||
_ks (list (+ (car _ks) (cos (/ pi 6.0))) ; 30 Grad = quer zu -120
|
||||
(+ (cadr _ks) (sin (/ pi 6.0))) 0.0)))
|
||||
(tu-true "vfl-laenge-bis-ziellinie/realfall-plausibel"
|
||||
(and _l (> _l 1430.0) (< _l 1431.0)))
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: export.lsp - CSV/KOS-Kodierung
|
||||
;; ------------------------------------------------------------
|
||||
@@ -846,6 +935,35 @@
|
||||
(tu-bp-el "ECKRAD" 400.0 800.0 0.0 0.0 0.0 "B"))
|
||||
1.0 1.0)))
|
||||
(tu-eq "kreisel-bp/flanke-eckrad" 1 (length _ber))
|
||||
;; Kreisel seitlich versetzt Ende an Ende (Raeder Flanke an Flanke, aber in
|
||||
;; Gegenrichtung) -> Weiche, keine Seite-an-Seite-Kollision
|
||||
(setq _erg (kreisel-bp-berechnen (list (tu-bp-el "KREISEL" 0.0 0.0 0.0 0.0 2000.0 "A")
|
||||
(tu-bp-el "KREISEL" 2000.0 800.0 0.0 0.0 2000.0 "B"))
|
||||
1.0 1.0))
|
||||
(tu-eq "kreisel-bp/ende-an-ende-art" '("Kreis/Kreis") (tu-bp-arten (car _erg)))
|
||||
(tu-eqf "kreisel-bp/ende-an-ende-punkt" '(2400.0 400.0) (cdr (assoc "p" (car (car _erg)))))
|
||||
(tu-nil "kreisel-bp/ende-an-ende-keine-kollision" (cadr _erg))
|
||||
;; Gleich ausgerichtete Raeder Flanke an Flanke (echtes Seite an Seite) -> keine Weiche
|
||||
(setq _erg (kreisel-bp-berechnen (list (tu-bp-el "KREISEL" 0.0 0.0 0.0 0.0 2000.0 "A")
|
||||
(tu-bp-el "KREISEL" 0.0 800.0 0.0 0.0 2000.0 "B"))
|
||||
1.0 1.0))
|
||||
(tu-nil "kreisel-bp/seite-an-seite-keine-weiche" (car _erg))
|
||||
;; results/test.dxf (E3/C7): Kreisel 2/3/4 Ende an Ende (0.9 mm Ueberlappung bzw.
|
||||
;; 5.5 mm), Kreisel 8 vor dem Profil von Kreisel 9 (2.6 mm Spalt) - mit 10 mm
|
||||
;; Toleranz drei Weichen
|
||||
(setq _erg (kreisel-bp-berechnen
|
||||
(list (tu-bp-el "KREISEL" 4940.03 -7603.25 2000.0 90.0 4500.0 "2")
|
||||
(tu-bp-el "KREISEL" 5739.13 -12898.65 2000.0 90.0 5296.0 "3")
|
||||
(tu-bp-el "KREISEL" 6533.6 -7603.44 2000.0 90.0 7889.0 "4")
|
||||
(tu-bp-el "KREISEL" -61.76 -974.08 2000.0 90.0 4000.0 "9")
|
||||
(tu-bp-el "KREISEL" 340.85 505.79 2000.0 0.0 3400.0 "8"))
|
||||
10.0 1.0))
|
||||
(tu-eq "kreisel-bp/test-dxf-paare"
|
||||
'(("2" "3") ("3" "4") ("9" "8"))
|
||||
(mapcar '(lambda (tr) (list (cdr (assoc "id" (cdr (assoc "a" tr))))
|
||||
(cdr (assoc "id" (cdr (assoc "b" tr))))))
|
||||
(car _erg)))
|
||||
(tu-nil "kreisel-bp/test-dxf-keine-kollision" (cadr _erg))
|
||||
)
|
||||
|
||||
|
||||
@@ -2138,7 +2256,7 @@
|
||||
(princ "\n================================================================")
|
||||
|
||||
(foreach fn '("tu-tests-core" "tu-tests-lang" "tu-tests-id" "tu-tests-vfcore"
|
||||
"tu-tests-etage"
|
||||
"tu-tests-etage" "tu-tests-vfl-es" "tu-tests-vfl-ziellinie"
|
||||
"tu-tests-export" "tu-tests-hoehen" "tu-tests-gf" "tu-tests-omni" "tu-tests-kreisel" "tu-tests-kreisel-bp"
|
||||
"tu-tests-sepliste" "tu-tests-json" "tu-tests-geruest"
|
||||
"tu-tests-sepscan" "tu-tests-vfl-segs" "tu-tests-vfl-abbruch"
|
||||
|
||||
Vendored
+218
@@ -0,0 +1,218 @@
|
||||
[
|
||||
{
|
||||
"id": "Kreisel_TestSystem_01",
|
||||
"function": "insert",
|
||||
"x": -3561.74,
|
||||
"y": 994.84,
|
||||
"z": 2000.0,
|
||||
"abstand": 2300.0,
|
||||
"rotation": 0.0,
|
||||
"typ": "STANDARD",
|
||||
"drehrichtung": "UZS",
|
||||
"comment": "aus Zeichnung: KREISEL_1_STANDARD_2300 (ID 0028), abstand aus Blockdefinition (AN8 -> SP8)"
|
||||
},
|
||||
{
|
||||
"id": "Kreisel_TestSystem_02",
|
||||
"function": "insert",
|
||||
"x": 4938.26,
|
||||
"y": -7603.25,
|
||||
"z": 2000.0,
|
||||
"abstand": 4500.0,
|
||||
"rotation": 90.0,
|
||||
"typ": "STANDARD",
|
||||
"drehrichtung": "UZS",
|
||||
"comment": "aus Zeichnung: KREISEL_2_STANDARD_4500 (ID 0033), abstand aus Blockdefinition (AN8 -> SP8), x auf exakte Beruehrung korrigiert (-1.77)"
|
||||
},
|
||||
{
|
||||
"id": "Kreisel_TestSystem_03",
|
||||
"function": "insert",
|
||||
"x": 5738.26,
|
||||
"y": -12898.65,
|
||||
"z": 2000.0,
|
||||
"abstand": 5295.71,
|
||||
"rotation": 90.0,
|
||||
"typ": "STANDARD",
|
||||
"drehrichtung": "GUZ",
|
||||
"comment": "aus Zeichnung: KREISEL_3_STANDARD_5296 (ID 0034), abstand aus Blockdefinition (AN8 -> SP8), x auf exakte Beruehrung korrigiert (-0.87)"
|
||||
},
|
||||
{
|
||||
"id": "Kreisel_TestSystem_04",
|
||||
"function": "insert",
|
||||
"x": 6538.26,
|
||||
"y": -7603.44,
|
||||
"z": 2000.0,
|
||||
"abstand": 7889.42,
|
||||
"rotation": 90.0,
|
||||
"typ": "STANDARD",
|
||||
"drehrichtung": "UZS",
|
||||
"comment": "aus Zeichnung: KREISEL_4_STANDARD_7889 (ID 0035), abstand aus Blockdefinition (AN8 -> SP8), x auf exakte Beruehrung korrigiert (+4.66)"
|
||||
},
|
||||
{
|
||||
"id": "Kreisel_TestSystem_05",
|
||||
"function": "insert",
|
||||
"x": 6138.26,
|
||||
"y": 1485.99,
|
||||
"z": 2000.0,
|
||||
"abstand": 9783.58,
|
||||
"rotation": 0.0,
|
||||
"typ": "STANDARD",
|
||||
"drehrichtung": "GUZ",
|
||||
"comment": "aus Zeichnung: KREISEL_5_STANDARD_9784 (ID 0036), abstand aus Blockdefinition (AN8 -> SP8), x auf exakte Beruehrung korrigiert (+4.66)"
|
||||
},
|
||||
{
|
||||
"id": "Kreisel_TestSystem_06",
|
||||
"function": "insert",
|
||||
"x": 6538.26,
|
||||
"y": 1885.99,
|
||||
"z": 2000.0,
|
||||
"abstand": 3718.63,
|
||||
"rotation": 90.0,
|
||||
"typ": "STANDARD",
|
||||
"drehrichtung": "UZS",
|
||||
"comment": "aus Zeichnung: KREISEL_6_STANDARD_3719 (ID 0037), abstand aus Blockdefinition (AN8 -> SP8), x auf exakte Beruehrung korrigiert (+4.66)"
|
||||
},
|
||||
{
|
||||
"id": "Kreisel_TestSystem_07",
|
||||
"function": "insert",
|
||||
"x": 4938.26,
|
||||
"y": -2303.25,
|
||||
"z": 2000.0,
|
||||
"abstand": 2900.0,
|
||||
"rotation": 90.0,
|
||||
"typ": "STANDARD",
|
||||
"drehrichtung": "GUZ",
|
||||
"comment": "aus Zeichnung: KREISEL_1_STANDARD_2900 (ID 0031), abstand aus Blockdefinition (AN8 -> SP8), x auf exakte Beruehrung korrigiert (-2.33)"
|
||||
},
|
||||
{
|
||||
"id": "Kreisel_TestSystem_08",
|
||||
"function": "insert",
|
||||
"x": 338.26,
|
||||
"y": 505.79,
|
||||
"z": 2000.0,
|
||||
"abstand": 3400.0,
|
||||
"rotation": 0.0,
|
||||
"typ": "STANDARD",
|
||||
"drehrichtung": "UZS",
|
||||
"comment": "aus Zeichnung: KREISEL_1_STANDARD_3400 (ID 0030), abstand aus Blockdefinition (AN8 -> SP8), x auf exakte Beruehrung korrigiert (-2.59)"
|
||||
},
|
||||
{
|
||||
"id": "Kreisel_TestSystem_09",
|
||||
"function": "insert",
|
||||
"x": -61.74,
|
||||
"y": -974.08,
|
||||
"z": 2000.0,
|
||||
"abstand": 4000.0,
|
||||
"rotation": 90.0,
|
||||
"typ": "STANDARD",
|
||||
"drehrichtung": "GUZ",
|
||||
"comment": "aus Zeichnung: KREISEL_1_STANDARD_4000 (ID 0032), abstand aus Blockdefinition (AN8 -> SP8), x auf exakte Beruehrung korrigiert (+0.02)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": -461.74,
|
||||
"y": 1466.18,
|
||||
"z": 2000.0,
|
||||
"rotation": 90.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0015, ZUORDNUNG 0032, ARTINR 200000077), x mit Kreisel 09 verschoben (+0.02)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": 1181.85,
|
||||
"y": 105.79,
|
||||
"z": 0.0,
|
||||
"rotation": 0.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0017, ZUORDNUNG 0030, ARTINR 200000077), x mit Kreisel 08 verschoben (-2.59)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": 3756.79,
|
||||
"y": 905.79,
|
||||
"z": 2000.0,
|
||||
"rotation": 180.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0018, ZUORDNUNG 0030, ARTINR 200000077), x mit Kreisel 08 verschoben (-2.59)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": 4538.26,
|
||||
"y": -1553.42,
|
||||
"z": 2000.0,
|
||||
"rotation": 90.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0019, ZUORDNUNG 0031, ARTINR 200000077), x mit Kreisel 07 verschoben (-2.33)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": 4538.26,
|
||||
"y": -3109.7,
|
||||
"z": 2000.0,
|
||||
"rotation": 270.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0020, ZUORDNUNG 0033, ARTINR 200000077), x mit Kreisel 02 verschoben (-1.77)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": 5338.26,
|
||||
"y": -6594.16,
|
||||
"z": 2000.0,
|
||||
"rotation": 90.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0021, ZUORDNUNG 0033, ARTINR 200000077), x mit Kreisel 02 verschoben (-1.77)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": 6938.26,
|
||||
"y": -6678.18,
|
||||
"z": 2000.0,
|
||||
"rotation": 90.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0022, ZUORDNUNG 0035, ARTINR 200000077), x mit Kreisel 04 verschoben (+4.66)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": 6138.26,
|
||||
"y": 362.53,
|
||||
"z": 2000.0,
|
||||
"rotation": 270.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0023, ZUORDNUNG 0035, ARTINR 200000077), x mit Kreisel 04 verschoben (+4.66)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": 7093.89,
|
||||
"y": 1885.99,
|
||||
"z": 2000.0,
|
||||
"rotation": 0.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0024, ZUORDNUNG 0036, ARTINR 200000077), x mit Kreisel 05 verschoben (+4.66)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "Separator_SP",
|
||||
"x": 6938.26,
|
||||
"y": 2848.54,
|
||||
"z": 2000.0,
|
||||
"rotation": 90.0,
|
||||
"comment": "aus Zeichnung: Separator_SP_3D (ID 0025, ZUORDNUNG 0037, ARTINR 200000077), x mit Kreisel 06 verschoben (+4.66)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "BTMT-Beladung",
|
||||
"x": 14622.43,
|
||||
"y": 1085.99,
|
||||
"z": 2000.0,
|
||||
"rotation": 0.0,
|
||||
"comment": "aus Zeichnung: BTMT-Beladung_3D (ID 0026, ARTINR 829662012), x mit Kreisel 05 verschoben (+4.66)"
|
||||
},
|
||||
{
|
||||
"function": "insert",
|
||||
"block": "SC_Entladung",
|
||||
"x": -2246.43,
|
||||
"y": 581.63,
|
||||
"z": 2000.0,
|
||||
"rotation": 179.49,
|
||||
"comment": "aus Zeichnung: SC_Entladung_3D (ID 0027, ARTINR 400100156)"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user