[MERGE] Lager branch in main
This commit is contained in:
+762
-2
@@ -399,6 +399,342 @@
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: vf_linienzug.lsp - "Parallel zum Kreisel" (Rechenkerne)
|
||||
;; ------------------------------------------------------------
|
||||
;; Die Bau-Funktion vfl-gf-parallel-kreisel braucht eine Zeichnung (sie misst
|
||||
;; AS und Bogen an echten Bloecken); ihre beiden Rechenkerne sind davon frei
|
||||
;; und stehen deshalb hier:
|
||||
;; vfl-par-bogen-waehlen - welcher Bogen hebt den AS-Schwenk auf?
|
||||
;; vfl-par-gf-laenge - wie lang wird das GF-Stueck dazwischen?
|
||||
;; Die Plan-Turn-Werte unten sind die Vorzeichen-Konvention aus
|
||||
;; vf-element-plan-turn (KS_EIN -> KS_AUS in der XY-Ebene, links positiv).
|
||||
(defun tu-tests-vfl-parallel ( / _b30 _b60 _b90 _kand _l _plan _plan3 _g _p _w _ez _plan2)
|
||||
(princ "\n[vf_linienzug Parallel zum Kreisel]")
|
||||
|
||||
;; --- Bogenwahl: der Bogen muss den AS-Schwenk GENAU aufheben ---
|
||||
;; Rechts-Boegen schwenken negativ, Links-Boegen positiv.
|
||||
(setq _b30 '(30 . -30.0) _b60 '(60 . -60.0) _b90 '(90 . -90.0))
|
||||
(setq _kand (list _b30 _b60 _b90))
|
||||
;; AS links 30 Grad (Schwenk +30) -> 30-Grad-Bogen nach rechts
|
||||
(tu-eq "vfl-par-bogen/as30-rechts" 30 (vfl-par-bogen-waehlen 30.0 _kand 2.0))
|
||||
;; AS links 90 Grad (Schwenk +90) -> 90-Grad-Bogen nach rechts
|
||||
(tu-eq "vfl-par-bogen/as90-rechts" 90 (vfl-par-bogen-waehlen 90.0 _kand 2.0))
|
||||
;; Generisch: auch ein 60-Grad-Schwenk findet seinen Bogen - die Zuordnung
|
||||
;; folgt den gemessenen Bloecken, nicht einer gepflegten Tabelle.
|
||||
(tu-eq "vfl-par-bogen/as60-rechts" 60 (vfl-par-bogen-waehlen 60.0 _kand 2.0))
|
||||
;; kleine Messabweichung bleibt in der Toleranz
|
||||
(tu-eq "vfl-par-bogen/toleranz-ok" 30 (vfl-par-bogen-waehlen 31.2 _kand 2.0))
|
||||
;; ausserhalb der Toleranz: lieber nil als ein schiefer Bogen
|
||||
(tu-nil "vfl-par-bogen/zu-weit-weg" (vfl-par-bogen-waehlen 45.0 _kand 2.0))
|
||||
(tu-nil "vfl-par-bogen/leere-liste" (vfl-par-bogen-waehlen 30.0 '() 2.0))
|
||||
;; Gegenseite: Links-Boegen heben einen negativen AS-Schwenk auf
|
||||
(setq _kand (list '(30 . 30.0) '(60 . 60.0) '(90 . 90.0)))
|
||||
(tu-eq "vfl-par-bogen/as-rechts30-links" 30 (vfl-par-bogen-waehlen -30.0 _kand 2.0))
|
||||
|
||||
;; --- GF-Laenge: abstand = perp-as + L*k + perp-bogen ---
|
||||
;; Glatter Fall: k = 1 (AS schwenkt 90 Grad aus der Achse), feste Anteile
|
||||
;; zusammen 500 -> fuer 2000 mm Abstand bleiben 1500 mm GF.
|
||||
(tu-eqf "vfl-par-laenge/k1" 1500.0 (vfl-par-gf-laenge 2000.0 200.0 300.0 1.0))
|
||||
;; Gegenseite: k negativ -> der Abstand zaehlt auf der anderen Seite, der
|
||||
;; Betrag der Eingabe bleibt derselbe (Seite kommt aus der AS-Variante).
|
||||
(tu-eqf "vfl-par-laenge/k-negativ" 1500.0
|
||||
(vfl-par-gf-laenge 2000.0 -200.0 -300.0 -1.0))
|
||||
;; Schraege Ausschleusung: k = sin(60 Grad)
|
||||
(setq _l (vfl-par-gf-laenge 2000.0 0.0 0.0 (sin (/ (* 60.0 pi) 180.0))))
|
||||
(tu-eqf "vfl-par-laenge/k-sin60" (/ 2000.0 (sin (/ (* 60.0 pi) 180.0))) _l)
|
||||
;; Abstand kleiner als der feste Anteil -> negative Laenge (der Aufrufer
|
||||
;; meldet das als "Abstand zu klein", die Rechnung selbst raet nicht).
|
||||
(tu-true "vfl-par-laenge/zu-klein-negativ"
|
||||
(< (vfl-par-gf-laenge 100.0 200.0 300.0 1.0) 0.0))
|
||||
;; AS schwenkt gar nicht aus der Achse -> keine Loesung
|
||||
(tu-nil "vfl-par-laenge/kein-versatz" (vfl-par-gf-laenge 2000.0 0.0 0.0 0.0))
|
||||
|
||||
;; --- Grenzen einer VF-Einheit (Modus 2) ---
|
||||
;; Zwischen Umlenk- und Motorstation: hoechstens 2 Vario-Kurven und 25 m.
|
||||
;; Plan-Eintraege: ("Linie" hz laenge ...) / ("Bogen" hz chord ...) - nur
|
||||
;; Typ und Laenge (3. Feld) zaehlen hier.
|
||||
(setq _plan (list '("Linie" 0.0 9000.0 "VF") '("Bogen" 0.0 500.0)
|
||||
'("Linie" 0.0 8000.0 "VF") '("Bogen" 0.0 500.0)
|
||||
'("Linie" 0.0 6000.0 "VF")))
|
||||
;; 24000 mm, 2 Kurven -> alles im Rahmen
|
||||
(setq _g (vfl-m2-lauf-grenzen _plan 0 4 25000.0 2))
|
||||
(tu-eqf "vfl-m2-grenzen/laenge" 24000.0 (nth 0 _g))
|
||||
(tu-eq "vfl-m2-grenzen/kurven" 2 (nth 1 _g))
|
||||
(tu-nil "vfl-m2-grenzen/ok" (nth 2 _g))
|
||||
;; Dritte Kurve -> an ihr (Index 5) teilen, obwohl die Laenge noch passt
|
||||
(setq _plan3 (append _plan (list '("Bogen" 0.0 400.0) '("Linie" 0.0 300.0 "VF"))))
|
||||
(tu-eq "vfl-m2-grenzen/dritte-kurve" 5 (nth 2 (vfl-m2-lauf-grenzen _plan3 0 6 25000.0 2)))
|
||||
;; Zu lang -> am ersten Bogen teilen, nach dem die Grenze reisst (Index 3:
|
||||
;; bis dahin sind 9000+500+8000 = 17500 drin, die Grenze liegt bei 15000).
|
||||
(tu-eq "vfl-m2-grenzen/zu-lang" 3 (nth 2 (vfl-m2-lauf-grenzen _plan 0 4 15000.0 2)))
|
||||
;; Eine einzige lange Gerade: zu lang, aber kein Bogen zum Teilen -> -1
|
||||
(tu-eq "vfl-m2-grenzen/unteilbar" -1
|
||||
(nth 2 (vfl-m2-lauf-grenzen (list '("Linie" 0.0 30000.0 "VF")) 0 0 25000.0 2)))
|
||||
|
||||
;; --- Vorgabewert aus einem Prompt ziehen (Dialog-Feld vorbelegen) ---
|
||||
;; Die Konsolen-Prompts tragen ihre Vorgabe in Klammern; der Zahlen-Dialog
|
||||
;; liest sie daraus. Gesucht ist die LETZTE Klammergruppe MIT Zahl - die
|
||||
;; echten Texte enthalten davor "<" ohne Partner ("0 < Winkel <= 3") und
|
||||
;; runde Klammern mit Fliesstext, beides darf nicht stoeren.
|
||||
(tu-eq "vflw-vorgabe/neigungswinkel" "3"
|
||||
(vflw-vorgabe-aus-prompt "\nNeigungswinkel (Grad, 0 < Winkel <= 3) [3]: "))
|
||||
(tu-eq "vflw-vorgabe/neigungswinkel-berechnet" "3"
|
||||
(vflw-vorgabe-aus-prompt
|
||||
"\nNeigungswinkel (Grad, 0 < Winkel <= 3) [3] (deltaL wird berechnet und eingefuegt): "))
|
||||
(tu-eq "vflw-vorgabe/spitze-klammer" "2154.0"
|
||||
(vflw-vorgabe-aus-prompt "\nGewuenschte Hoehe am Kettenanfang (mm) <2154.0>: "))
|
||||
(tu-eq "vflw-vorgabe/negativ" "-12.5"
|
||||
(vflw-vorgabe-aus-prompt "Hoehendifferenz <-12.5>: "))
|
||||
;; Ohne Klammergruppe bleibt das Feld leer (nil), nicht geraten.
|
||||
(tu-nil "vflw-vorgabe/ohne-vorgabe"
|
||||
(vflw-vorgabe-aus-prompt "\nAbstand zum Kreisel (mm, senkrecht zur Achse): "))
|
||||
(tu-nil "vflw-vorgabe/keine-zahl"
|
||||
(vflw-vorgabe-aus-prompt "Bitte Namen eingeben [frei]: "))
|
||||
|
||||
;; --- Modus-2-Lauf-Anfang: Journal-Wert normieren ---
|
||||
;; Die Antwort wird als selbstbeschreibender Wert gefuehrt, damit ein
|
||||
;; Umsortieren/Umnummerieren der Optionen bestehende Ketten nicht
|
||||
;; umdeutet. Alte Ketten tragen dort noch die Ziffern der ALTEN Folge -
|
||||
;; die Zuordnung dafuer steht als Tabelle in *vfl-m2-anfang-alt* und wird
|
||||
;; hier komplett durchlaufen, statt einzelne Faelle abzuschreiben.
|
||||
(foreach _p *vfl-m2-anfang-alt*
|
||||
(tu-eq (strcat "vfl-m2-anfang/alt-" (car _p))
|
||||
(cdr _p) (vfl-m2-anfang-norm (car _p))))
|
||||
;; Jeder Tabellenwert muss auch ein gueltiger heutiger Wert sein - sonst
|
||||
;; laeuft eine Alt-Kette in den Unbekannt-Abbruch.
|
||||
(foreach _p *vfl-m2-anfang-alt*
|
||||
(tu-true (strcat "vfl-m2-anfang/alt-ziel-gueltig-" (car _p))
|
||||
(and (member (cdr _p) *vfl-m2-anfang-werte*) t)))
|
||||
;; Neue Werte gehen unveraendert durch.
|
||||
(foreach _w *vfl-m2-anfang-werte*
|
||||
(tu-eq (strcat "vfl-m2-anfang/neu-" _w) _w (vfl-m2-anfang-norm _w)))
|
||||
;; Unbekanntes wird NICHT geraten - nil heisst fuer den Aufrufer Abbruch.
|
||||
(tu-nil "vfl-m2-anfang/unbekannte-ziffer" (vfl-m2-anfang-norm "4"))
|
||||
(tu-nil "vfl-m2-anfang/leer" (vfl-m2-anfang-norm ""))
|
||||
(tu-nil "vfl-m2-anfang/tippfehler" (vfl-m2-anfang-norm "mit_gf1"))
|
||||
(tu-nil "vfl-m2-anfang/kein-string" (vfl-m2-anfang-norm 3))
|
||||
(tu-nil "vfl-m2-anfang/nil" (vfl-m2-anfang-norm nil))
|
||||
|
||||
;; --- Eck-Korrektur: gezeichneter Bogen gegen Eck-Bauteil ---
|
||||
;; Die Ecke des Pfads wird durch ein reales Bauteil ersetzt, dessen
|
||||
;; Fussabdruck abweichen darf. Die Differenz wird auf die Richtungen der
|
||||
;; beiden angrenzenden Geraden zerlegt. Werte aus dem echten Lauf vom
|
||||
;; 2026-10-26: 90-Grad-Ecke, Pfad R500 (Sehne 707.1 -> 500/-500), gebaute
|
||||
;; Vario-Kurve wirkt wie R406.2 -> je 93.78 mm auf beide Nachbargeraden.
|
||||
(setq _ez (vfl-eck-zerlegen 500.0 -500.0 406.22 -406.22 (- (/ pi 2.0))))
|
||||
(tu-eqf "vfl-eck-zerlegen/90-grad-davor" 93.78 (car _ez))
|
||||
(tu-eqf "vfl-eck-zerlegen/90-grad-danach" 93.78 (cadr _ez))
|
||||
;; 30-Grad-Ecke links, Gefaellebogen R500 trifft den Pfad fast exakt:
|
||||
;; nur 0.85 mm, und zwar ausschliesslich auf der Geraden DAVOR.
|
||||
(setq _ez (vfl-eck-zerlegen 250.0 66.99 249.15 66.99 (/ pi 6.0)))
|
||||
(tu-eqf "vfl-eck-zerlegen/30-grad-davor" 0.85 (car _ez))
|
||||
(tu-eqf "vfl-eck-zerlegen/30-grad-danach" 0.0 (cadr _ez))
|
||||
;; Deckungsgleiches Bauteil -> kein Zuschlag auf keiner Seite.
|
||||
(setq _ez (vfl-eck-zerlegen 500.0 -500.0 500.0 -500.0 (- (/ pi 2.0))))
|
||||
(tu-eqf "vfl-eck-zerlegen/gleich-davor" 0.0 (car _ez))
|
||||
(tu-eqf "vfl-eck-zerlegen/gleich-danach" 0.0 (cadr _ez))
|
||||
;; Ohne Schwenk ist die Zerlegung nicht eindeutig - nil statt Division durch 0.
|
||||
(tu-nil "vfl-eck-zerlegen/ohne-schwenk"
|
||||
(vfl-eck-zerlegen 100.0 0.0 90.0 0.0 0.0))
|
||||
;; GF-Boegen werden GENEIGT eingebaut: ihr Grundriss-Fussabdruck ist kuerzer
|
||||
;; als flach gemessen, und genau diese Differenz muss in die Eck-Korrektur.
|
||||
;; Werte aus dem echten Lauf 2026-10-26: Gefaellebogen_rechts_90_R500 flach
|
||||
;; dx=500 dz=-28.6, bei 3 Grad eingebaut 497.8 - die 2.2 mm blieben vorher
|
||||
;; als Rest am Kettenende stehen. Negatives dz muss dabei VERKUERZEN.
|
||||
(tu-eqf "vfl-projiziere-neigung/gf-bogen-3-grad"
|
||||
(- (* 500.0 (cos (* 3.0 (/ pi 180.0))))
|
||||
(* 28.6 (sin (* 3.0 (/ pi 180.0)))))
|
||||
(car (vfl-projiziere-neigung 500.0 -28.6 3.0)))
|
||||
(tu-true "vfl-projiziere-neigung/gf-bogen-kuerzer-als-flach"
|
||||
(< (car (vfl-projiziere-neigung 500.0 -28.6 3.0)) 500.0))
|
||||
;; Waagerecht eingebaut (Vario-Kurve) bleibt der Fussabdruck unveraendert.
|
||||
(tu-eqf "vfl-projiziere-neigung/waagerecht" 500.0
|
||||
(car (vfl-projiziere-neigung 500.0 -28.6 0.0)))
|
||||
|
||||
;; --- Bau-Funktion aus dem Journal ableiten (vf_spec.lsp) ---
|
||||
;; vsp-bau-journal waehlt die Modus-Funktion anhand des Journals, statt sie
|
||||
;; als zusaetzliches Argument zu bekommen (exakte Argumentzahl, siehe
|
||||
;; CLAUDE.md). Kein SEGS = Modus 1; SEGS mit der Formatmarke "m2v2" =
|
||||
;; Modus 2 (nur vf-linienzug-modus2 schreibt sie); SEGS ohne = Modus 3.
|
||||
(tu-true "vsp-bau-fn/ohne-segs-ist-modus1"
|
||||
(eq (vsp-bau-fn-fuer-journal
|
||||
(list (cons "PT" '(0.0 0.0 0.0)) (cons "STR" "1")))
|
||||
'vf-linienzug-modus))
|
||||
(tu-true "vsp-bau-fn/segs-mit-marke-ist-modus2"
|
||||
(eq (vsp-bau-fn-fuer-journal
|
||||
(list (cons "PT" '(0.0 0.0 0.0)) (cons "SEGS" '(("Linie")))
|
||||
(cons "STR" "m2v2") (cons "STR" "2")))
|
||||
'vf-linienzug-modus2))
|
||||
(tu-true "vsp-bau-fn/segs-ohne-marke-ist-modus3"
|
||||
(eq (vsp-bau-fn-fuer-journal
|
||||
(list (cons "PT" '(0.0 0.0 0.0)) (cons "SEGS" '(("Linie")))
|
||||
(cons "STR" "2")))
|
||||
'vf-linienzug-modus3))
|
||||
;; Die Marke zaehlt nur als STR-Eintrag - ein gleichlautender Wert in einem
|
||||
;; anderen Eintragstyp darf nicht faelschlich auf Modus 2 schliessen lassen.
|
||||
(tu-true "vsp-bau-fn/marke-nur-als-str"
|
||||
(eq (vsp-bau-fn-fuer-journal
|
||||
(list (cons "SEGS" '(("Linie"))) (cons "INT" "m2v2")))
|
||||
'vf-linienzug-modus3))
|
||||
|
||||
;; --- Segment-Klassifizierung: Wert statt Menue-Ziffer ---
|
||||
;; Gemeinsamer Normalisierer fuer alle selbstbeschreibenden Antworten.
|
||||
;; Bestandsketten tragen die Alt-Ziffer, neue Ketten den Wert; beide Mengen
|
||||
;; sind disjunkt. Unbekanntes gibt nil - der Aufrufer bricht dann ab.
|
||||
(foreach _p *vfl-m2-linie-alt*
|
||||
(tu-eq (strcat "vfl-wert-norm/linie-alt-" (car _p)) (cdr _p)
|
||||
(vfl-wert-norm (car _p) *vfl-m2-linie-werte* *vfl-m2-linie-alt*)))
|
||||
(foreach _p *vfl-m2-bogen-alt*
|
||||
(tu-eq (strcat "vfl-wert-norm/bogen-alt-" (car _p)) (cdr _p)
|
||||
(vfl-wert-norm (car _p) *vfl-m2-bogen-werte* *vfl-m2-bogen-alt*)))
|
||||
(foreach _p *vfl-m2-variante-alt*
|
||||
(tu-eq (strcat "vfl-wert-norm/variante-alt-" (car _p)) (cdr _p)
|
||||
(vfl-wert-norm (car _p) *vfl-m2-variante-werte* *vfl-m2-variante-alt*)))
|
||||
;; Neue Werte gehen unveraendert durch.
|
||||
(foreach _w *vfl-m2-bogen-werte*
|
||||
(tu-eq (strcat "vfl-wert-norm/bogen-neu-" _w) _w
|
||||
(vfl-wert-norm _w *vfl-m2-bogen-werte* *vfl-m2-bogen-alt*)))
|
||||
;; Jeder Alt-Zielwert muss ein gueltiger heutiger Wert sein, sonst laeuft
|
||||
;; eine Bestandskette in den Unbekannt-Abbruch.
|
||||
(foreach _p *vfl-m2-linie-alt*
|
||||
(tu-true (strcat "vfl-wert-norm/linie-ziel-gueltig-" (car _p))
|
||||
(and (member (cdr _p) *vfl-m2-linie-werte*) t)))
|
||||
;; Typ und Variante benutzten frueher BEIDE "1"/"2" und waren im Journal
|
||||
;; nicht zu unterscheiden - die neuen Wertevorraete muessen disjunkt sein.
|
||||
(tu-nil "vfl-wert-norm/bogen-und-variante-disjunkt"
|
||||
(vl-some (function (lambda (w) (if (member w *vfl-m2-variante-werte*) w)))
|
||||
*vfl-m2-bogen-werte*))
|
||||
(tu-nil "vfl-wert-norm/unbekannt-gibt-nil"
|
||||
(vfl-wert-norm "3" *vfl-m2-linie-werte* *vfl-m2-linie-alt*))
|
||||
(tu-nil "vfl-wert-norm/kein-string"
|
||||
(vfl-wert-norm 1 *vfl-m2-linie-werte* *vfl-m2-linie-alt*))
|
||||
|
||||
;; --- Gefalteter VF-Lauf erkennen (Schenkel = Fahrtrichtungen) ---
|
||||
;; Der Modus-2-Solver bilanziert skalar ueber EINE Achse. Liegt der Lauf
|
||||
;; gefaltet (U-Form), sitzen die festen Teile in einem anderen Schenkel als
|
||||
;; die Kletterstrecke und die Kette wird sichtbar falsch gebaut. Bis die
|
||||
;; Bilanz achsenweise rechnet, wird so ein Lauf abgewiesen - diese
|
||||
;; Erkennung entscheidet darueber.
|
||||
;; Plan-Eintraege: Linie = ("Linie" hz laenge typ ...), Bogen = ("Bogen" hz ...)
|
||||
(setq _plan2 (list (list "Linie" 0.0 9700.0 "VF" nil)
|
||||
(list "Bogen" 0.0 707.1 90 "rechts" "Vario-Kurve" "aussen")
|
||||
(list "Linie" -90.0 4296.0 "VF" nil)))
|
||||
(tu-eq "vfl-m2-schenkel/u-form-zwei-richtungen" 2
|
||||
(length (vfl-m2-schenkel _plan2 0 2)))
|
||||
(tu-true "vfl-m2-gefaltet/u-form" (vfl-m2-gefaltet-p _plan2 0 2))
|
||||
;; Gerader Lauf: eine Richtung, auch ueber mehrere Geraden hinweg.
|
||||
(setq _plan2 (list (list "Linie" 0.0 9700.0 "VF" nil)
|
||||
(list "Linie" 0.0 2000.0 "VF" nil)))
|
||||
(tu-eq "vfl-m2-schenkel/gerade-eine-richtung" 1
|
||||
(length (vfl-m2-schenkel _plan2 0 1)))
|
||||
(tu-nil "vfl-m2-gefaltet/gerade" (vfl-m2-gefaltet-p _plan2 0 1))
|
||||
;; Zurueck auf dieselbe Richtung zaehlt als NEUER Schenkel - die Kette ist
|
||||
;; dann seitlich versetzt, die Laengen liegen nicht mehr auf einer Linie.
|
||||
(setq _plan2 (list (list "Linie" 0.0 3000.0 "VF" nil)
|
||||
(list "Bogen" 0.0 707.1 90 "rechts" "Vario-Kurve" "aussen")
|
||||
(list "Linie" -90.0 1000.0 "VF" nil)
|
||||
(list "Bogen" -90.0 707.1 90 "links" "Vario-Kurve" "aussen")
|
||||
(list "Linie" 0.0 3000.0 "VF" nil)))
|
||||
(tu-eq "vfl-m2-schenkel/u-form-drei" 3
|
||||
(length (vfl-m2-schenkel _plan2 0 4)))
|
||||
;; Winkel werden normalisiert: 270 und -90 sind dieselbe Richtung.
|
||||
(setq _plan2 (list (list "Linie" -90.0 1000.0 "VF" nil)
|
||||
(list "Linie" 270.0 1000.0 "VF" nil)))
|
||||
(tu-eq "vfl-m2-schenkel/270-gleich-minus90" 1
|
||||
(length (vfl-m2-schenkel _plan2 0 1)))
|
||||
|
||||
;; --- Eingangs-Hardware auf einem Fueller-Segment ---
|
||||
;; Steht der Lauf-Eingang (GF1 + Separator + Umlenkstation + Bogen) auf
|
||||
;; einem FUELLER, muss dessen Laenge abgezogen werden - sonst bekommt der
|
||||
;; Fueller die volle Restlaenge, als staende dort nichts (real 2026-10-27:
|
||||
;; 5855 mm Plan, 10668 mm belegt, Kette 8005 mm daneben).
|
||||
;; Ist das Eingangs-Segment selbst der Kletterer, steckt dieselbe Laenge
|
||||
;; schon in feste-vf - dann MUSS der Abzug 0 sein, sonst doppelt.
|
||||
(tu-eqf "vfl-m2-eingang-fp/kletterer-kein-abzug" 0.0
|
||||
(vfl-m2-eingang-fp 0 0 '(0) 3726.34 (* 3.0 (/ pi 180.0))))
|
||||
;; Anderes Segment als der Eingang: ebenfalls nichts.
|
||||
(tu-eqf "vfl-m2-eingang-fp/fremdes-segment" 0.0
|
||||
(vfl-m2-eingang-fp 2 0 '(2) 3726.34 (* 3.0 (/ pi 180.0))))
|
||||
;; Eingang ist Fueller (Kletterer liegt woanders): GF1 + 300 + 500,
|
||||
;; projiziert auf 3 Grad, plus der Uebergangsbogen aus der Tabelle.
|
||||
;; Die DIFFERENZ zweier Aufrufe prueft den GF-Anteil exakt und kommt ohne
|
||||
;; die Bogen-Tabelle aus - die ist im file-freien Unit-Test leer
|
||||
;; (init-bibliothek laeuft hier nicht), der Bogenanteil faellt also weg.
|
||||
;; Eine absolute Schranke waere dadurch umgebungsabhaengig gewesen.
|
||||
(tu-eqf "vfl-m2-eingang-fp/gf-anteil-exakt"
|
||||
(* 3726.34 (cos (* 3.0 (/ pi 180.0))))
|
||||
(- (vfl-m2-eingang-fp 0 0 '(2) 3726.34 (* 3.0 (/ pi 180.0)))
|
||||
(vfl-m2-eingang-fp 0 0 '(2) 0.0 (* 3.0 (/ pi 180.0)))))
|
||||
;; Separator + Umlenkstation sind IMMER dabei, auch ohne GF und ohne Tabelle.
|
||||
(setq _l (vfl-m2-eingang-fp 0 0 '(2) 0.0 (* 3.0 (/ pi 180.0))))
|
||||
(tu-true "vfl-m2-eingang-fp/stationen-immer-dabei"
|
||||
(>= _l (* (+ *vfk-separator-laenge* *vfk-stations-laenge*)
|
||||
(cos (* 3.0 (/ pi 180.0))))))
|
||||
|
||||
;; --- Fremdanteil der Gefaellestrecke (fuer den stillen Nachrechner) ---
|
||||
;; Wieviel der vom Solver berechneten GF liegt NICHT auf dem Schenkel des
|
||||
;; Kletterers? Nur das darf dessen Spanne wieder zugeschlagen werden.
|
||||
;; Liegt der Eingang auf dem Kletterer selbst (gerader Normalfall), ist
|
||||
;; nichts fremd - dann MUSS 0 herauskommen, sonst wuerde der funktionierende
|
||||
;; Fall veraendert.
|
||||
(tu-eqf "vfl-m2-gf-fremd/eingang-ist-kletterer" 0.0
|
||||
(vfl-m2-gf-fremdanteil 3726.34 1 T))
|
||||
(tu-eqf "vfl-m2-gf-fremd/alles-einlauf" 3726.34
|
||||
(vfl-m2-gf-fremdanteil 3726.34 1 nil))
|
||||
(tu-eqf "vfl-m2-gf-fremd/halb-halb" 1863.17
|
||||
(vfl-m2-gf-fremdanteil 3726.34 2 nil))
|
||||
;; Alles am Auslauf (Modus 3, erzwungen bei offenem Anfang): die GF liegt
|
||||
;; dann beim Kletterer, nichts ist fremd.
|
||||
(tu-eqf "vfl-m2-gf-fremd/alles-auslauf" 0.0
|
||||
(vfl-m2-gf-fremdanteil 3726.34 3 nil))
|
||||
|
||||
;; --- ES-Reservierung auf die KS_AUS-Achse ---
|
||||
;; Vorgabe: quer zur KS_AUS-Achse MUSS 0 sein, laengs darf abweichen.
|
||||
;; Der reine Laengsanteil reicht dafuer NICHT - er laesst den bauteileigenen
|
||||
;; Querversatz stehen. Werte aus dem echten Lauf 2026-10-26:
|
||||
;; ES_Element_30_rechts an einer Geraden mit hz=-60, Schwenk -30 Grad,
|
||||
;; Fussabdruck (laengs 575.84 | quer -52.54). Reserve 484.8 statt 575.8 -
|
||||
;; die Gerade wird also rund 91 mm laenger und hebt den Querversatz auf.
|
||||
(tu-eqf "vfl-es-achs-reserve/echt-30-grad" 484.838050570331
|
||||
(vfl-es-achs-reserve 575.84 -52.54 -60.0 -30.0))
|
||||
;; Ohne Querversatz bleibt es beim reinen Laengsanteil.
|
||||
(tu-eqf "vfl-es-achs-reserve/ohne-quer" 500.0
|
||||
(vfl-es-achs-reserve 500.0 0.0 -60.0 -30.0))
|
||||
;; Ohne Schwenk faellt die Achse mit der Fahrtrichtung zusammen - dann gibt
|
||||
;; es keinen aufhebbaren Querversatz und der Laengsanteil ist richtig
|
||||
;; (Nenner 0, Rueckfall statt Division durch null).
|
||||
(tu-eqf "vfl-es-achs-reserve/ohne-schwenk" 575.84
|
||||
(vfl-es-achs-reserve 575.84 -52.54 -60.0 0.0))
|
||||
;; Richtungsunabhaengig: dieselbe Geometrie um 90 Grad gedreht gibt
|
||||
;; denselben Wert - die Reserve haengt an den Winkeln zueinander, nicht
|
||||
;; an der Lage im Welt-KS.
|
||||
(tu-eqf "vfl-es-achs-reserve/gedreht" 484.838050570331
|
||||
(vfl-es-achs-reserve 575.84 -52.54 30.0 -30.0))
|
||||
|
||||
;; --- Rueckwaerts bauen: Punkt entgegen der Fahrtrichtung zuruecksetzen ---
|
||||
;; vfl-rueck-punkt ist der Rechenkern des Rueckwaerts-Baus: zu einem
|
||||
;; BEKANNTEN Endpunkt den Startpunkt eines Bausteins finden. Vorwaerts gilt
|
||||
;; P_next = P + (L*cos hz, L*sin hz, -L*tan w) - hier also mit umgekehrtem
|
||||
;; Vorzeichen. Die Hoehe muss STEIGEN (der Vorgaenger liegt hoeher).
|
||||
(tu-eqf "vfl-rueck-punkt/ost-flach"
|
||||
(list 0.0 0.0 0.0) (vfl-rueck-punkt '(1000.0 0.0 0.0) 0.0 1000.0 0.0))
|
||||
(tu-eqf "vfl-rueck-punkt/nord-flach"
|
||||
(list 0.0 0.0 0.0) (vfl-rueck-punkt '(0.0 1000.0 0.0) 90.0 1000.0 0.0))
|
||||
;; 45 Grad Gefaelle: 1000 mm horizontal zurueck = 1000 mm hoeher
|
||||
(tu-eqf "vfl-rueck-punkt/45-grad"
|
||||
(list 0.0 0.0 1000.0) (vfl-rueck-punkt '(1000.0 0.0 0.0) 0.0 1000.0 45.0))
|
||||
;; Rundlauf: vorwaerts wieder auf den Ausgangspunkt (3 Grad, schraeg)
|
||||
(setq _l (vfl-rueck-punkt '(5000.0 3000.0 1800.0) 30.0 2000.0 3.0))
|
||||
(tu-eqf "vfl-rueck-punkt/rundlauf-x" 5000.0
|
||||
(+ (car _l) (* 2000.0 (cos (/ (* 30.0 pi) 180.0)))))
|
||||
(tu-eqf "vfl-rueck-punkt/rundlauf-y" 3000.0
|
||||
(+ (cadr _l) (* 2000.0 (sin (/ (* 30.0 pi) 180.0)))))
|
||||
(tu-eqf "vfl-rueck-punkt/rundlauf-z" 1800.0
|
||||
(- (caddr _l) (* 2000.0 (/ (sin (/ (* 3.0 pi) 180.0)) (cos (/ (* 3.0 pi) 180.0))))))
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: vf_linienzug.lsp - Laenge aus einer Ziellinie (X/Y)
|
||||
;; ------------------------------------------------------------
|
||||
@@ -446,6 +782,86 @@
|
||||
(+ (cadr _ks) (sin (/ pi 6.0))) 0.0)))
|
||||
(tu-true "vfl-laenge-bis-ziellinie/realfall-plausibel"
|
||||
(and _l (> _l 1430.0) (< _l 1431.0)))
|
||||
|
||||
;; --- AS-Seite aus der Lage des naechsten Punkts zur Basislinie ---
|
||||
;; Basislinie zeigt nach +X; ein Ziel mit +Y liegt links davon, mit -Y rechts.
|
||||
(tu-eq "vfl-seite-aus-lage/links"
|
||||
"links" (vfl-seite-aus-lage '(0.0 0.0 0.0) '(1000.0 0.0 0.0) '(500.0 800.0 0.0)))
|
||||
(tu-eq "vfl-seite-aus-lage/rechts"
|
||||
"rechts" (vfl-seite-aus-lage '(0.0 0.0 0.0) '(1000.0 0.0 0.0) '(500.0 -800.0 0.0)))
|
||||
;; Richtung der Basislinie umdrehen -> Seite dreht mit
|
||||
(tu-eq "vfl-seite-aus-lage/basislinie-umgedreht"
|
||||
"rechts" (vfl-seite-aus-lage '(1000.0 0.0 0.0) '(0.0 0.0 0.0) '(500.0 800.0 0.0)))
|
||||
;; schraege Basislinie (45 Grad): Ziel oberhalb davon liegt links
|
||||
(tu-eq "vfl-seite-aus-lage/schraeg"
|
||||
"links" (vfl-seite-aus-lage '(0.0 0.0 0.0) '(1000.0 1000.0 0.0) '(0.0 1000.0 0.0)))
|
||||
;; Z spielt keine Rolle (rein planare Entscheidung)
|
||||
(tu-eq "vfl-seite-aus-lage/z-ignoriert"
|
||||
"rechts" (vfl-seite-aus-lage '(0.0 0.0 5000.0) '(1000.0 0.0 -200.0) '(500.0 -800.0 999.0)))
|
||||
|
||||
;; --- VF-Hoehe je SEGMENT (Attribut VF_HOEHE_m, Sivas 4433-4437) ---
|
||||
;; Ein Eintrag je GERADEM VF-Abschnitt: Mittelwert aus dessen KS_EIN und
|
||||
;; KS_AUS, in METERN mit 3 Nachkommastellen. Zwischen Umlenk- und
|
||||
;; Motorstation koennen mehrere Abschnitte liegen (auf/ab/horizontal), die
|
||||
;; Liste laeuft darum parallel zu L_VF_m und VF_WINKEL.
|
||||
(vf-vfhoehe-reset)
|
||||
(tu-eq "vf-vfhoehe/leer-nach-reset" "" (vfl-join-komma *vf-acc-vfhoehe*))
|
||||
|
||||
;; 2000 mm und 3000 mm -> Mittel 2500 mm -> "2.500"
|
||||
(vf-vfhoehe-segment 2000.0 3000.0)
|
||||
(tu-eq "vf-vfhoehe/mittelwert-meter" "2.500" (vfl-join-komma *vf-acc-vfhoehe*))
|
||||
|
||||
;; Drei Abschnitte wie im realen Block (L_VF_m hatte dort 3 Eintraege):
|
||||
;; horizontal, horizontal, steigend - alle drei bekommen einen Wert.
|
||||
(vf-vfhoehe-reset)
|
||||
(vf-vfhoehe-segment 2076.0 2076.0) ; horizontal
|
||||
(vf-vfhoehe-segment 2076.0 2076.0) ; horizontal
|
||||
(vf-vfhoehe-segment 2076.0 2600.0) ; steigend -> Mittel 2338
|
||||
(tu-eq "vf-vfhoehe/drei-abschnitte"
|
||||
"2.076,2.076,2.338" (vfl-join-komma *vf-acc-vfhoehe*))
|
||||
|
||||
;; Unvollstaendige Messung haengt NICHTS an - sonst verschoebe sich die
|
||||
;; Liste gegen L_VF_m und eine Hoehe landete beim falschen Foerderer.
|
||||
(vf-vfhoehe-reset)
|
||||
(vf-vfhoehe-segment 1000.0 2000.0)
|
||||
(vf-vfhoehe-segment nil 3000.0)
|
||||
(vf-vfhoehe-segment 4000.0 nil)
|
||||
(tu-eq "vf-vfhoehe/unvollstaendig-ignoriert" "1.500" (vfl-join-komma *vf-acc-vfhoehe*))
|
||||
|
||||
;; negative Hoehen (Kette unter Null) muessen durchgehen
|
||||
(vf-vfhoehe-reset)
|
||||
(vf-vfhoehe-segment -500.0 -1500.0)
|
||||
(tu-eq "vf-vfhoehe/negativ" "-1.000" (vfl-join-komma *vf-acc-vfhoehe*))
|
||||
(vf-vfhoehe-reset)
|
||||
|
||||
;; vf-meter-3: GENAU 3 Nachkommastellen, unabhaengig von DIMZIN.
|
||||
;; (rtos x 2 3) allein kuerzt nachfolgende Nullen ("2.5", "-1") - real im
|
||||
;; Testlauf aufgetreten, deshalb eigene Formatierung.
|
||||
(tu-eq "vf-meter-3/glatt" "2.500" (vf-meter-3 2500.0))
|
||||
(tu-eq "vf-meter-3/ganzzahlig" "3.000" (vf-meter-3 3000.0))
|
||||
(tu-eq "vf-meter-3/negativ" "-1.000" (vf-meter-3 -1000.0))
|
||||
(tu-eq "vf-meter-3/null" "0.000" (vf-meter-3 0.0))
|
||||
(tu-eq "vf-meter-3/drei-stellen" "1.234" (vf-meter-3 1234.0))
|
||||
|
||||
;; --- SONDERFALL Standard/Etage: Hoehe ueber die GANZE Kette ---
|
||||
;; Nur ein Motor und nur ein gerader VF-Abschnitt, darum zaehlt dort
|
||||
;; AS-KS_EIN .. ES-KS_AUS statt des Segmentwerts (Nutzer-Vorgabe 2026-10-21).
|
||||
(vf-vfhoehe-reset)
|
||||
(vf-vfhoehe-kette 1000.0 3000.0)
|
||||
(tu-eq "vf-vfhoehe-kette/mittelwert" "2.000" (vfl-join-komma *vf-acc-vfhoehe*))
|
||||
|
||||
;; ERSETZT den beim Bau gesammelten Segmentwert, haengt ihn NICHT an -
|
||||
;; sonst stuenden fuer eine Standard-Anlage zwei Hoehen in der Liste.
|
||||
(vf-vfhoehe-reset)
|
||||
(vf-vfhoehe-segment 5000.0 5000.0) ; Segmentwert aus vfs-vf-koerper
|
||||
(vf-vfhoehe-kette 1000.0 3000.0)
|
||||
(tu-eq "vf-vfhoehe-kette/ersetzt-segmentwert" "2.000" (vfl-join-komma *vf-acc-vfhoehe*))
|
||||
|
||||
;; fehlender Endpunkt -> lieber leer als geraten
|
||||
(vf-vfhoehe-reset)
|
||||
(vf-vfhoehe-kette 1000.0 nil)
|
||||
(tu-eq "vf-vfhoehe-kette/ohne-endpunkt-leer" "" (vfl-join-komma *vf-acc-vfhoehe*))
|
||||
(vf-vfhoehe-reset)
|
||||
)
|
||||
|
||||
|
||||
@@ -2278,6 +2694,349 @@
|
||||
)
|
||||
)
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: KettenFoerderer.lsp + ssg_ks_insert.lsp (KS-Orientierung)
|
||||
;; ------------------------------------------------------------
|
||||
;; Reine Rechenkerne des Kettenfoerderers: Hoehenbilanz, Massstab,
|
||||
;; Grenzpruefung, KS-Winkel. Alles ohne Zeichnung und ohne Blockdateien -
|
||||
;; die zeichnungsabhaengigen Teile (kf-geometrie-messen, kf-kette-bauen)
|
||||
;; brauchen BricsCAD und bleiben dem Befehl KF_KS_PRUEFEN vorbehalten.
|
||||
(defun tu-tests-kf ( / _l _s _defs)
|
||||
(princ "\n[KettenFoerderer]")
|
||||
(if (not (car (atoms-family 1 '("KF-LAENGE-BERECHNEN"))))
|
||||
(tu-record nil "KettenFoerderer-Modul geladen"
|
||||
"KettenFoerderer.lsp nicht geladen - siehe tests/test_unit.scr")
|
||||
(progn
|
||||
;; --- ks-winkel-normalisieren: auf -180..180 falten ---
|
||||
(tu-eqf "ks-winkel-norm/190" -170.0 (ks-winkel-normalisieren 190.0))
|
||||
(tu-eqf "ks-winkel-norm/-190" 170.0 (ks-winkel-normalisieren -190.0))
|
||||
(tu-eqf "ks-winkel-norm/26" 26.0 (ks-winkel-normalisieren 26.0))
|
||||
(tu-eqf "ks-winkel-norm/360" 0.0 (ks-winkel-normalisieren 360.0))
|
||||
(tu-nil "ks-winkel-norm/nil" (ks-winkel-normalisieren nil))
|
||||
|
||||
;; --- ks-xy-winkel: X-Achse eines KS-Eintrags (origin x-end y-end z-end)
|
||||
(tu-eqf "ks-xy-winkel/entlang-X" 0.0
|
||||
(ks-xy-winkel '((0.0 0.0 0.0) (1.0 0.0 0.0) (0.0 2.0 0.0) (0.0 0.0 3.0))))
|
||||
(tu-eqf "ks-xy-winkel/entlang-Y" 90.0
|
||||
(ks-xy-winkel '((0.0 0.0 0.0) (0.0 1.0 0.0) (-2.0 0.0 0.0) (0.0 0.0 3.0))))
|
||||
;; versetzter Ursprung: nur die RICHTUNG zaehlt, nicht die Lage
|
||||
(tu-eqf "ks-xy-winkel/versetzt-45" 45.0
|
||||
(ks-xy-winkel (list '(100.0 50.0 0.0) '(101.0 51.0 0.0) '(99.0 51.0 0.0) '(100.0 50.0 1.0))))
|
||||
;; senkrechte X-Achse (keine XY-Laenge) -> nil statt Division durch 0
|
||||
(tu-nil "ks-xy-winkel/senkrecht"
|
||||
(ks-xy-winkel '((0.0 0.0 0.0) (0.0 0.0 1.0) (0.0 2.0 0.0) (0.0 0.0 3.0))))
|
||||
|
||||
;; --- kf-hz-folge: Folgebaustein an KS_AUS des Vorgaengers ausrichten ---
|
||||
;; Vorgaenger zeigt 26 Grad, Folgebaustein ist waagerecht gezeichnet (0)
|
||||
(tu-eqf "kf-hz-folge/26-auf-0" 26.0 (kf-hz-folge 26.0 0.0))
|
||||
;; Folgebaustein ist selbst schon um 26 Grad gezeichnet -> keine Drehung
|
||||
(tu-eqf "kf-hz-folge/26-auf-26" 0.0 (kf-hz-folge 26.0 26.0))
|
||||
;; fehlende Eigenrichtung -> Baustein uebernimmt die Vorgaengerrichtung
|
||||
(tu-eqf "kf-hz-folge/ohne-beta" 26.0 (kf-hz-folge 26.0 nil))
|
||||
(tu-nil "kf-hz-folge/ohne-phi" (kf-hz-folge nil 0.0))
|
||||
|
||||
;; --- kf-dy-eingebaut: Hoehenbeitrag nach Rz(hz) und X-Massstab ---
|
||||
;; waagerechter Baustein, waagerecht eingebaut -> kein Hoehengewinn
|
||||
(tu-eqf "kf-dy/0-grad" 0.0 (kf-dy-eingebaut 1000.0 0.0 0.0 1.0))
|
||||
;; 1000 mm unter 30 Grad -> 500 mm (sin 30 = 0.5)
|
||||
(tu-eqf "kf-dy/30-grad" 500.0 (kf-dy-eingebaut 1000.0 0.0 30.0 1.0))
|
||||
;; derselbe Baustein doppelt skaliert -> doppelter Hoehengewinn
|
||||
(tu-eqf "kf-dy/30-grad-skaliert-2" 1000.0 (kf-dy-eingebaut 1000.0 0.0 30.0 2.0))
|
||||
;; senkrecht eingebaut -> die volle Laenge als Hoehe
|
||||
(tu-eqf "kf-dy/90-grad" 1000.0 (kf-dy-eingebaut 1000.0 0.0 90.0 1.0))
|
||||
|
||||
;; --- kf-laenge-berechnen: Hoehenbilanz nach der Laenge aufloesen ---
|
||||
;; H=1000, Stationen tragen nichts bei, 30 Grad -> L = 1000/sin30 = 2000
|
||||
(tu-eqf "kf-laenge/30-grad-glatt" 2000.0
|
||||
(kf-laenge-berechnen 1000.0 0.0 0.0 0.0 30.0))
|
||||
;; Stationen tragen 100+150 bei -> nur 750 mm bleiben fuer das Stueck
|
||||
(tu-eqf "kf-laenge/mit-stationen" 1500.0
|
||||
(kf-laenge-berechnen 1000.0 100.0 150.0 0.0 30.0))
|
||||
;; Gegenprobe: die errechnete Laenge ergibt wieder genau H
|
||||
(setq _l (kf-laenge-berechnen 1000.0 100.0 150.0 0.0 30.0))
|
||||
(tu-eqf "kf-laenge/rundlauf-ergibt-H" 1000.0
|
||||
(+ 100.0 150.0 (kf-dy-eingebaut _l 0.0 30.0 1.0)))
|
||||
;; bereits geneigt gezeichnetes Zwischenstueck: dy-nativ wird abgezogen
|
||||
;; (dy-nativ skaliert NICHT mit, nur X wird skaliert)
|
||||
(tu-eqf "kf-laenge/mit-dy-nativ" 1800.0
|
||||
(kf-laenge-berechnen 1000.0 0.0 0.0 (/ 100.0 (cos (/ pi 6.0))) 30.0))
|
||||
;; waagerecht -> keine Hoehe erreichbar
|
||||
(tu-nil "kf-laenge/0-grad-unloesbar"
|
||||
(kf-laenge-berechnen 1000.0 0.0 0.0 0.0 0.0))
|
||||
|
||||
;; --- kf-skala-berechnen ---
|
||||
(tu-eqf "kf-skala/2000-von-1000" 2.0 (kf-skala-berechnen 2000.0 1000.0))
|
||||
(tu-nil "kf-skala/ohne-nativlaenge" (kf-skala-berechnen 2000.0 0.0))
|
||||
(tu-nil "kf-skala/ohne-laenge" (kf-skala-berechnen nil 1000.0))
|
||||
|
||||
;; --- kf-laenge-pruefen: Grenzen aus der JSON ---
|
||||
(tu-nil "kf-pruefen/in-ordnung" (kf-laenge-pruefen 2000.0 100.0 20000.0))
|
||||
(tu-eq "kf-pruefen/zu-kurz" "kf-fehler-laenge-unter-min"
|
||||
(kf-laenge-pruefen 50.0 100.0 20000.0))
|
||||
(tu-eq "kf-pruefen/zu-lang" "kf-fehler-laenge-ueber-max"
|
||||
(kf-laenge-pruefen 99999.0 100.0 20000.0))
|
||||
;; negative Laenge = Stationen bringen mehr Hoehe mit als gefordert
|
||||
(tu-eq "kf-pruefen/negativ" "kf-fehler-hoehe-zu-klein"
|
||||
(kf-laenge-pruefen -10.0 100.0 20000.0))
|
||||
(tu-eq "kf-pruefen/nil" "kf-fehler-winkel-null"
|
||||
(kf-laenge-pruefen nil 100.0 20000.0))
|
||||
|
||||
;; --- kf-zahl: JSON-Wert als Zahl (Parser liefert Zahl ODER String) ---
|
||||
(tu-eqf "kf-zahl/int" 26.0 (kf-zahl 26))
|
||||
(tu-eqf "kf-zahl/real" 26.0 (kf-zahl 26.0))
|
||||
(tu-eqf "kf-zahl/string" 26.0 (kf-zahl "26"))
|
||||
(tu-nil "kf-zahl/nil" (kf-zahl nil))
|
||||
|
||||
;; --- kf-attrib-defs: VF-Schema + KF-Zusatz, KEIN Tag doppelt ---
|
||||
(setq _defs (kf-attrib-defs))
|
||||
(tu-true "kf-attrib-defs/hat-ID" (assoc "ID" _defs))
|
||||
(tu-true "kf-attrib-defs/hat-FOERDERERTYP" (assoc "FOERDERERTYP" _defs))
|
||||
(tu-true "kf-attrib-defs/hat-WINKEL" (assoc "WINKEL" _defs))
|
||||
(tu-true "kf-attrib-defs/hat-STANDARD_STEUERUNG"
|
||||
(assoc "STANDARD_STEUERUNG" _defs))
|
||||
;; Reihenfolge wie im Sivas-Merkmalstamm: 361 folgt direkt auf den Typ,
|
||||
;; STANDARD_STEUERUNG steht also unmittelbar hinter WINKEL
|
||||
(tu-eq "kf-attrib-defs/361-folgt-auf-winkel" "STANDARD_STEUERUNG"
|
||||
(car (nth (1+ (kf-tag-index "WINKEL" _defs)) _defs)))
|
||||
;; FOERDERERTYP ist die BAUART im Klartext, der Winkel steht in WINKEL
|
||||
(tu-eq "kf-attrib-defs/FOERDERERTYP-ist-bauart" "Schraegfoerderer Stahl"
|
||||
(cadr (assoc "FOERDERERTYP" _defs)))
|
||||
(tu-true "kf-attrib-defs/hat-MOVIMOT" (assoc "MOVIMOT" _defs))
|
||||
;; Farbe und Antriebsmotor sind ZWEI Eigenschaften (Sivas 354 bzw. 355), nicht
|
||||
;; ein kombiniertes AUSFUEHRUNG-Attribut
|
||||
(tu-true "kf-attrib-defs/hat-FARBE" (assoc "FARBE" _defs))
|
||||
(tu-true "kf-attrib-defs/hat-ANTRIEBSMOTOR" (assoc "ANTRIEBSMOTOR" _defs))
|
||||
(tu-nil "kf-attrib-defs/kein-AUSFUEHRUNG" (assoc "AUSFUEHRUNG" _defs))
|
||||
;; Der Kettenfoerderer traegt sich selbst - die Geruest-Tags aus dem
|
||||
;; VF-Schema werden bewusst NICHT mitgefuehrt
|
||||
(tu-nil "kf-attrib-defs/kein-GERUEST_EINZELMODUL"
|
||||
(assoc "GERUEST_EINZELMODUL" _defs))
|
||||
(tu-nil "kf-attrib-defs/kein-GERUEST_TYP" (assoc "GERUEST_TYP" _defs))
|
||||
;; Jeder Tag darf nur EINMAL vorkommen (zwei ATTDEFs gleichen Tags waeren
|
||||
;; im Block ungueltig, ssg-attrib-set-on traefe nur den ersten).
|
||||
(setq _s 0)
|
||||
(foreach _d _defs (if (= (car _d) "FOERDERERTYP") (setq _s (1+ _s))))
|
||||
(tu-eq "kf-attrib-defs/FOERDERERTYP-nur-einmal" 1 _s)
|
||||
(setq _s 0)
|
||||
(foreach _d _defs (if (= (car _d) "ARTINR") (setq _s (1+ _s))))
|
||||
(tu-eq "kf-attrib-defs/ARTINR-nur-einmal" 1 _s)
|
||||
(setq _s 0)
|
||||
(foreach _d _defs (if (= (car _d) "ARTINR") (setq _s (1+ _s))))
|
||||
(tu-eq "kf-attrib-defs/ARTINR-nur-einmal" 1 _s)
|
||||
;; Der Winkel steht ALLEIN in FOERDERERTYP - kein zweites Winkel-Tag
|
||||
(tu-nil "kf-attrib-defs/kein-KF_WINKEL" (assoc "KF_WINKEL" _defs))
|
||||
(tu-nil "kf-attrib-defs/kein-KF_TYP" (assoc "KF_TYP" _defs))
|
||||
;; Das Schema ist EIGENSTAENDIG, nicht vom VF-Streckenschema geerbt -
|
||||
;; keines der VF-Tags darf durchschlagen
|
||||
(tu-nil "kf-attrib-defs/kein-SEITE_AS" (assoc "SEITE_AS" _defs))
|
||||
(tu-nil "kf-attrib-defs/kein-ANZAHL_VF" (assoc "ANZAHL_VF" _defs))
|
||||
(tu-nil "kf-attrib-defs/kein-TEILEART" (assoc "TEILEART" _defs))
|
||||
(tu-eq "kf-attrib-defs/LAYER-ist-F-3" "F-3" (cadr (assoc "LAYER" _defs)))
|
||||
|
||||
;; --- kf-variante-finden: ueber den Winkel, auch als String ---
|
||||
(tu-eq "kf-variante-finden/26" "A"
|
||||
(cdr (assoc "name"
|
||||
(kf-variante-finden 26
|
||||
'((("winkel" . 26) ("name" . "A"))
|
||||
(("winkel" . 30) ("name" . "B")))))))
|
||||
(tu-eq "kf-variante-finden/30-als-string" "B"
|
||||
(cdr (assoc "name"
|
||||
(kf-variante-finden 30
|
||||
'((("winkel" . "26") ("name" . "A"))
|
||||
(("winkel" . "30") ("name" . "B")))))))
|
||||
(tu-nil "kf-variante-finden/unbekannt"
|
||||
(kf-variante-finden 45 '((("winkel" . 26) ("name" . "A")))))
|
||||
|
||||
;; --- kf-antriebsart (Merkmal 357): Dropdown mit EINER Option ---
|
||||
;; Der Wert kommt aus dem ERSTEN Listeneintrag - nicht aus dem Code.
|
||||
(tu-eq "kf-antriebsart/aus-daten" "1.1 kW"
|
||||
(kf-antriebsart '(("antriebsart" (("name" . "1.1 kW") ("wert" . "1.1 kW"))))))
|
||||
;; eine zweite Option aendert die Vorgabe NICHT (Index 0 bleibt massgebend)
|
||||
(tu-eq "kf-antriebsart/erster-eintrag-gewinnt" "1.1 kW"
|
||||
(kf-antriebsart '(("antriebsart" (("name" . "1.1 kW") ("wert" . "1.1 kW"))
|
||||
(("name" . "0.55 kW") ("wert" . "0.55 kW"))))))
|
||||
;; Liste fehlt -> Rueckfall, aber als STRING (nicht T/nil)
|
||||
(tu-eq "kf-antriebsart/ohne-eintrag" "1.1 kW" (kf-antriebsart '(("titel" . "x"))))
|
||||
(tu-true "kf-antriebsart/ist-string"
|
||||
(= (type (kf-antriebsart '(("titel" . "x")))) 'STR))
|
||||
;; Dezimalpunkt, kein Komma (Nutzervorgabe)
|
||||
(tu-nil "kf-antriebsart/kein-komma"
|
||||
(vl-string-search "," (kf-antriebsart '(("titel" . "x")))))
|
||||
|
||||
;; --- kf-drehung-gesamt: Drehwinkel fuer KF_EDIT ---
|
||||
;; Regression: der Drehwinkel wird beim Bau in die Geometrie eingerechnet,
|
||||
;; die Blockreferenz selbst hat IMMER Drehung 0 (ssg-block-wrap-welt).
|
||||
;; KF_EDIT las nur Gruppencode 50 und baute eine mit 90 Grad gebaute
|
||||
;; Kette ungedreht neu. Der gebaute Winkel steht jetzt als XDATA.
|
||||
(tu-eqf "kf-drehung/nur-xdata" 90.0 (kf-drehung-gesamt 90.0 0.0))
|
||||
;; Referenz nachtraeglich von Hand um 90 Grad gedreht (Gruppencode 50 in
|
||||
;; Bogenmass) -> beides addiert sich
|
||||
(tu-eqf "kf-drehung/xdata-plus-referenz" 180.0
|
||||
(kf-drehung-gesamt 90.0 (/ pi 2.0)))
|
||||
;; Altbestand ohne XDATA: nur die Referenzdrehung (bisheriges Verhalten)
|
||||
(tu-eqf "kf-drehung/ohne-xdata" 45.0 (kf-drehung-gesamt nil (/ pi 4.0)))
|
||||
;; nichts bekannt -> 0, kein Absturz und kein nil
|
||||
(tu-eqf "kf-drehung/nichts" 0.0 (kf-drehung-gesamt nil nil))
|
||||
(tu-true "kf-drehung/ist-zahl" (numberp (kf-drehung-gesamt nil nil)))
|
||||
;; Summe ueber 180 Grad wird auf -180..180 gefaltet (270 = -90)
|
||||
(tu-eqf "kf-drehung/normalisiert" -90.0
|
||||
(kf-drehung-gesamt 180.0 (/ pi 2.0)))
|
||||
;; ganze Zahl aus der XDATA (nicht real) darf nicht abstuerzen
|
||||
(tu-eqf "kf-drehung/ganzzahl" 30.0 (kf-drehung-gesamt 30 0.0))
|
||||
|
||||
;; --- kf-neigung-aus-punkten: Kern der 3D-Aufrichtung ---
|
||||
;; Liefert (Schraeglaenge Neigungswinkel) aus Ketten-Start und -Ende.
|
||||
;; Die Kette wird AUFGERICHTET eingebaut, die Hoehe laeuft also in Z.
|
||||
;; 3-4-5-Dreieck: 3000 waagerecht, 4000 hoch -> 5000 schraeg
|
||||
(tu-eqf "kf-neigung/3-4-5-laenge" 5000.0
|
||||
(car (kf-neigung-aus-punkten '(0.0 0.0 0.0) '(3000.0 0.0 4000.0) 0.0)))
|
||||
;; 45 Grad: gleiche Betraege waagerecht und hoch
|
||||
(tu-eqf "kf-neigung/45-grad" 45.0
|
||||
(cadr (kf-neigung-aus-punkten '(0.0 0.0 0.0) '(1000.0 0.0 1000.0) 0.0)))
|
||||
;; waagerecht -> Winkel 0, Laenge = Horizontalabstand
|
||||
(tu-eqf "kf-neigung/waagerecht" '(2000.0 0.0)
|
||||
(kf-neigung-aus-punkten '(0.0 0.0 0.0) '(2000.0 0.0 0.0) 0.0))
|
||||
;; Der Horizontalanteil wird auf die KETTENRICHTUNG projiziert, nicht
|
||||
;; auf die Welt-X-Achse: bei 90 Grad Basisdrehung laeuft die Kette in Y.
|
||||
;; Ohne Projektion kaeme hier 0 heraus und der Winkel waere 90 statt 45.
|
||||
(tu-eqf "kf-neigung/gedreht-90" '(1414.213562 45.0)
|
||||
(kf-neigung-aus-punkten '(0.0 0.0 0.0) '(0.0 1000.0 1000.0) 90.0))
|
||||
;; fallende Kette -> negativer Winkel
|
||||
(tu-eqf "kf-neigung/fallend" -45.0
|
||||
(cadr (kf-neigung-aus-punkten '(0.0 0.0 1000.0) '(1000.0 0.0 0.0) 0.0)))
|
||||
;; Start = Ende -> nil statt Division durch 0
|
||||
(tu-nil "kf-neigung/nulllaenge"
|
||||
(kf-neigung-aus-punkten '(5.0 5.0 5.0) '(5.0 5.0 5.0) 0.0))
|
||||
|
||||
;; --- kf-matrix-aufrecht: Y_lokal wird zu Z_welt ---
|
||||
;; Das ist die Kernaussage der Aufrichtung. Geprueft wird sie an den
|
||||
;; Bildern der Einheitsvektoren, nicht an den Matrixeintraegen - so
|
||||
;; bleibt der Test lesbar und unabhaengig von der Schreibweise.
|
||||
(tu-eqf "kf-matrix/Y-lokal-wird-Z-welt" '(0.0 0.0 1.0)
|
||||
(mat3-mul-vec3 (kf-matrix-aufrecht 0.0 0.0) '(0.0 1.0 0.0)))
|
||||
;; Die Fahrtrichtung (X) bleibt bei Basisdrehung 0 die Welt-X-Achse
|
||||
(tu-eqf "kf-matrix/X-bleibt-X" '(1.0 0.0 0.0)
|
||||
(mat3-mul-vec3 (kf-matrix-aufrecht 0.0 0.0) '(1.0 0.0 0.0)))
|
||||
;; Basisdrehung 90 Grad dreht die Fahrtrichtung in die Welt-Y-Achse,
|
||||
;; die Hoehe bleibt dabei in Z
|
||||
(tu-eqf "kf-matrix/basis-90-dreht-X-nach-Y" '(0.0 1.0 0.0)
|
||||
(mat3-mul-vec3 (kf-matrix-aufrecht 90.0 0.0) '(1.0 0.0 0.0)))
|
||||
(tu-eqf "kf-matrix/basis-90-haelt-Z" '(0.0 0.0 1.0)
|
||||
(mat3-mul-vec3 (kf-matrix-aufrecht 90.0 0.0) '(0.0 1.0 0.0)))
|
||||
|
||||
;; --- Standard-Variante: steht in den DATEN, nicht im Code ---
|
||||
(tu-true "kf-variante-standard-p/markiert"
|
||||
(kf-variante-standard-p '(("winkel" . 26) ("standard" . T))))
|
||||
(tu-nil "kf-variante-standard-p/ohne-feld"
|
||||
(kf-variante-standard-p '(("winkel" . 30))))
|
||||
;; Index fuer die Vorauswahl - auch wenn der Standard NICHT der erste ist
|
||||
(tu-eq "kf-standard-index/zweiter" 1
|
||||
(kf-standard-index '((("winkel" . 26))
|
||||
(("winkel" . 30) ("standard" . T)))))
|
||||
(tu-eq "kf-standard-index/erster" 0
|
||||
(kf-standard-index '((("winkel" . 26) ("standard" . T))
|
||||
(("winkel" . 30)))))
|
||||
;; keine Variante markiert -> erste, statt nil (der Dialog braucht einen Index)
|
||||
(tu-eq "kf-standard-index/keiner" 0
|
||||
(kf-standard-index '((("winkel" . 26)) (("winkel" . 30)))))
|
||||
|
||||
;; --- kf-punkt-differenzen: zweite Hoehen-Eingabeart (2 Punkte) ---
|
||||
;; Gemessen wird die Differenz in Z - die Baugruppe steht aufgerichtet im
|
||||
;; Modell. Zurueckgegeben wird (dz dy): die HOEHE zuerst, dY nur zur
|
||||
;; Kontrolle (wer in einer Draufsicht pickt, sieht dz = 0).
|
||||
(tu-eqf "kf-punkt-diff/dz" '(1500.0 0.0)
|
||||
(kf-punkt-differenzen '(0.0 0.0 0.0) '(2000.0 0.0 1500.0)))
|
||||
;; Vorzeichen egal - die Reihenfolge der Punkte darf keine Rolle spielen
|
||||
(tu-eqf "kf-punkt-diff/umgekehrt" '(1500.0 0.0)
|
||||
(kf-punkt-differenzen '(2000.0 0.0 1500.0) '(0.0 0.0 0.0)))
|
||||
;; in einer Draufsicht gepickt: dz = 0, dY gross
|
||||
(tu-eqf "kf-punkt-diff/draufsicht" '(0.0 1200.0)
|
||||
(kf-punkt-differenzen '(0.0 0.0 0.0) '(3000.0 1200.0 0.0)))
|
||||
;; Punkte ohne Z (2D-Pick) duerfen nicht abstuerzen: dz ist dann 0
|
||||
(tu-eqf "kf-punkt-diff/ohne-z" '(0.0 800.0)
|
||||
(kf-punkt-differenzen '(0.0 0.0) '(100.0 800.0)))
|
||||
(tu-nil "kf-punkt-diff/nil" (kf-punkt-differenzen nil '(1.0 2.0 3.0)))
|
||||
|
||||
;; --- kf-auswahl-wert: "wert" vor "name", Vorgabe bei leerem Index ---
|
||||
(tu-eq "kf-auswahl-wert/wert" "Nein"
|
||||
(kf-auswahl-wert '((("name" . "Nein") ("wert" . "Nein"))) 0 "X"))
|
||||
(tu-eq "kf-auswahl-wert/ausserhalb" "X"
|
||||
(kf-auswahl-wert '((("name" . "Nein") ("wert" . "Nein"))) 5 "X"))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: check_hoehen.lsp - Phase 3 (Buehnen-Familien), reine Kerne
|
||||
;; ------------------------------------------------------------
|
||||
(defun tu-tests-hoehen-fam ( / _els)
|
||||
(princ "\n[check_hoehen/Phase 3 Familien]")
|
||||
|
||||
;; --- ch-familien: transitive Verbindung, Sortierung nach ID-Nummer ---
|
||||
(tu-eq "ch-familien/einzeln-und-kette"
|
||||
'(("b") ("c" "a" "d") ("e"))
|
||||
(ch-familien '(("a" 3) ("b" 1) ("c" 2) ("d" 5) ("e" 4))
|
||||
'(("a" "c") ("c" "d") ("x" "a"))))
|
||||
(tu-eq "ch-familien/kette-ueber-mittleren"
|
||||
'(("a" "b" "c"))
|
||||
(ch-familien '(("a" 1) ("b" 2) ("c" 3)) '(("a" "b") ("b" "c"))))
|
||||
(tu-eq "ch-familien/ohne-kanten"
|
||||
'(("a") ("b"))
|
||||
(ch-familien '(("a" 1) ("b" 2)) nil))
|
||||
(tu-eq "ch-familien/ring"
|
||||
'(("a" "b" "c"))
|
||||
(ch-familien '(("a" 1) ("b" 2) ("c" 3)) '(("a" "b") ("b" "c") ("c" "a"))))
|
||||
|
||||
;; --- ch-kreuz-abzug ---
|
||||
(tu-eq "ch-kreuz-abzug/kein" '("kein" . 0.0) (ch-kreuz-abzug 0.0 0.0 5000.0 5000.0 1500.0))
|
||||
(tu-eq "ch-kreuz-abzug/konflikt" '("konflikt" . 0.0) (ch-kreuz-abzug 1.5 0.0 5000.0 5000.0 1500.0))
|
||||
(tu-eq "ch-kreuz-abzug/konflikt2" '("konflikt" . 0.0) (ch-kreuz-abzug 1.5 2.0 5000.0 5000.0 1500.0))
|
||||
(tu-eq "ch-kreuz-abzug/hoehe" '("hoehe" . 0.0) (ch-kreuz-abzug 1.5 1.5 5000.0 6600.0 1500.0))
|
||||
(tu-eq "ch-kreuz-abzug/grenze" '("abzug" . 1.5) (ch-kreuz-abzug 1.5 1.5 5000.0 6500.0 1500.0))
|
||||
(tu-eq "ch-kreuz-abzug/abzug" '("abzug" . 1.5) (ch-kreuz-abzug 1.5 1.5 5000.0 5200.0 1500.0))
|
||||
|
||||
;; --- ch-strecke-abzug (Familiensaetze: idx handles z b) ---
|
||||
(tu-eq "ch-strecke-abzug/innen"
|
||||
'("innen" . 1.5)
|
||||
(ch-strecke-abzug '(1 ("a") 5000.0 1.5) '(1 ("a") 5000.0 1.5) 1500.0))
|
||||
(tu-eq "ch-strecke-abzug/innen-ohne-buehne"
|
||||
'("innen" . 0.0)
|
||||
(ch-strecke-abzug '(1 ("a") 5000.0 0.0) '(1 ("a") 5000.0 0.0) 1500.0))
|
||||
(tu-eq "ch-strecke-abzug/zwischen"
|
||||
'("abzug" . 1.5)
|
||||
(ch-strecke-abzug '(1 ("a") 5000.0 1.5) '(2 ("b") 5400.0 1.5) 1500.0))
|
||||
|
||||
;; --- ch-schleife-p: gleicher Kreisel + gleiche Hoehe ---
|
||||
(tu-true "ch-schleife-p/gleicher-kreisel-flach" (ch-schleife-p "K1" "K1" 5000.0 5000.0 1.0))
|
||||
(tu-true "ch-schleife-p/toleranz" (ch-schleife-p "K1" "K1" 5000.0 5000.8 1.0))
|
||||
(tu-nil "ch-schleife-p/hoehenunterschied" (ch-schleife-p "K1" "K1" 5000.0 4800.0 1.0))
|
||||
(tu-nil "ch-schleife-p/anderer-kreisel" (ch-schleife-p "K1" "K2" 5000.0 5000.0 1.0))
|
||||
(tu-nil "ch-schleife-p/kein-kreisel" (ch-schleife-p nil nil 5000.0 5000.0 1.0))
|
||||
|
||||
;; --- ch-abzug-anwenden ---
|
||||
(tu-eqf "ch-abzug-anwenden/normal" 2.5 (ch-abzug-anwenden 3.5 1.0))
|
||||
(tu-nil "ch-abzug-anwenden/gleich" (ch-abzug-anwenden 3.5 3.5))
|
||||
(tu-nil "ch-abzug-anwenden/groesser" (ch-abzug-anwenden 3.5 4.0))
|
||||
(tu-nil "ch-abzug-anwenden/null" (ch-abzug-anwenden 3.5 0.0))
|
||||
|
||||
;; --- ch-kreisel-finden: Kreisel r=400, Achse (400,0)-(2400,0) bzw. (400,5000)-(2400,5000) ---
|
||||
(setq _els (list (tu-bp-el "KREISEL" 0.0 0.0 5000.0 0.0 2000.0 "K1")
|
||||
(tu-bp-el "KREISEL" 0.0 5000.0 5000.0 0.0 2000.0 "K2")))
|
||||
(tu-eq "ch-kreisel-finden/auf-achse"
|
||||
"K1" (ch-kreisel-finden '(1000.0 100.0 5000.0) 5000.0 _els 300.0 100.0))
|
||||
(tu-eq "ch-kreisel-finden/zweiter"
|
||||
"K2" (ch-kreisel-finden '(1000.0 4900.0 5000.0) 5000.0 _els 300.0 100.0))
|
||||
(tu-eq "ch-kreisel-finden/hinter-dem-rad"
|
||||
"K1" (ch-kreisel-finden '(-200.0 0.0 5000.0) 5000.0 _els 300.0 100.0))
|
||||
(tu-nil "ch-kreisel-finden/zu-weit"
|
||||
(ch-kreisel-finden '(1000.0 1000.0 5000.0) 5000.0 _els 300.0 100.0))
|
||||
(tu-nil "ch-kreisel-finden/falsche-hoehe"
|
||||
(ch-kreisel-finden '(1000.0 0.0 5300.0) 5300.0 _els 300.0 100.0))
|
||||
)
|
||||
|
||||
|
||||
|
||||
;; ------------------------------------------------------------
|
||||
;; TESTS: ssg_core.lsp - Polygon-Helfer (reine 2D-Berechnung)
|
||||
;; ------------------------------------------------------------
|
||||
@@ -2720,11 +3479,12 @@
|
||||
(princ "\n================================================================")
|
||||
|
||||
(foreach fn '("tu-tests-core" "tu-tests-lang" "tu-tests-id" "tu-tests-vfcore"
|
||||
"tu-tests-etage" "tu-tests-vfl-es" "tu-tests-vfl-ziellinie"
|
||||
"tu-tests-etage" "tu-tests-vfl-es" "tu-tests-vfl-parallel"
|
||||
"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"
|
||||
"tu-tests-werkzeuge" "tu-tests-poly" "tu-tests-lager")
|
||||
"tu-tests-werkzeuge" "tu-tests-poly" "tu-tests-lager" "tu-tests-kf" "tu-tests-hoehen-fam")
|
||||
(tu-run-block fn))
|
||||
|
||||
(princ "\n\n----------------------------------------------------------------")
|
||||
|
||||
Reference in New Issue
Block a user