Merge branch 'master' of https://gitea.schoenenberger.de/Schoenenberger_Systeme_GmbH/dxfmakros
This commit is contained in:
+27
-12
@@ -133,18 +133,17 @@
|
||||
;; ============================================================
|
||||
|
||||
(defun c:SSG_BLOCKEDIT ( / ss ent ed bname attribs teileart)
|
||||
;; Implied Selection pruefen (Block muss vorselektiert sein)
|
||||
;; Block ermitteln: zuerst Implied Selection, dann Picking
|
||||
(setq ss (ssget "I"))
|
||||
(if (or (null ss) (/= (sslength ss) 1))
|
||||
(progn
|
||||
(princ "\nBlock auswaehlen: ")
|
||||
(setq ss (ssget ":S" '((0 . "INSERT"))))
|
||||
)
|
||||
)
|
||||
(if (null ss)
|
||||
(progn
|
||||
(princ "\nBitte zuerst einen Block auswaehlen.")
|
||||
(princ)
|
||||
(exit)
|
||||
)
|
||||
)
|
||||
(if (/= (sslength ss) 1)
|
||||
(progn
|
||||
(princ "\nBitte genau einen Block auswaehlen.")
|
||||
(princ "\nKein Block ausgewaehlt.")
|
||||
(princ)
|
||||
(exit)
|
||||
)
|
||||
@@ -191,14 +190,30 @@
|
||||
(c:OMNI_EDIT)
|
||||
)
|
||||
|
||||
;; Unbekannter Blocktyp -> Standard BEDIT
|
||||
;; Unbekannter Blocktyp -> natives EATTEDIT (Attribut-Editor)
|
||||
(t
|
||||
(princ (strcat "\nBlock bearbeiten (BEDIT): " bname))
|
||||
(command "_.BEDIT" bname)
|
||||
(princ (strcat "\nAttribute bearbeiten: " bname))
|
||||
(command "_.EATTEDIT")
|
||||
)
|
||||
)
|
||||
(princ)
|
||||
)
|
||||
|
||||
;; ============================================================
|
||||
;; C:EATTEDIT - Abfangen des eingebauten Doppelklick-Befehls
|
||||
;; UNDEFINE zwingt BricsCAD, auch interne Aufrufe ueber LISP
|
||||
;; zu leiten. Fallback auf _.EATTEDIT (Dot-Prefix = nativ,
|
||||
;; kein Loop) fuer unbekannte Bloecke.
|
||||
;; ============================================================
|
||||
(defun c:EATTEDIT ()
|
||||
(c:SSG_BLOCKEDIT)
|
||||
)
|
||||
(if (not *ssg-eattedit-undefined*)
|
||||
(progn
|
||||
(command "_.UNDEFINE" "EATTEDIT")
|
||||
(setq *ssg-eattedit-undefined* t)
|
||||
)
|
||||
)
|
||||
|
||||
(princ "\nSSG_LIB_Commands.lsp geladen - Dummy-Befehle registriert.")
|
||||
(princ)
|
||||
|
||||
+23
-23
@@ -140,13 +140,9 @@
|
||||
;; csv-name = Ergebnis-CSV-Name (z.B. "export.csv")
|
||||
(defun csv:run-export (label py-name csv-name / ss i ename fh out-pfad
|
||||
py-skript ergebnis-pfad cmd first-block count)
|
||||
;; Vor dem Export: Doppelte IDs pruefen und korrigieren
|
||||
(if (atoms-family 1 '("ssg-id-check-all"))
|
||||
(progn
|
||||
(princ (strcat "\n[" label "] Pruefe IDs auf Duplikate..."))
|
||||
;; Vor dem Export: IDs aller Bloecke sicherstellen und Duplikate korrigieren
|
||||
(princ (strcat "\n[" label "] Pruefe und vergebe IDs..."))
|
||||
(ssg-id-check-all)
|
||||
)
|
||||
)
|
||||
;; Vor dem Export HOEHE/DREHUNG aller Omniflo-Elemente aktualisieren
|
||||
(princ (strcat "\n[" label "] Aktualisiere Hoehe/Drehung..."))
|
||||
(omni:update-all-attribs)
|
||||
@@ -351,17 +347,6 @@
|
||||
)
|
||||
|
||||
|
||||
;; --- CSV-Zeile fuer ein Omniflo-Element bauen ---
|
||||
(defun csv:omni-csv-line (elem-nr teileart bezeichnung merkmale-json)
|
||||
(strcat (itoa elem-nr)
|
||||
";\"" teileart "\""
|
||||
";\"shape_" (substr (rtos (* (getvar "CDATE") 1000000.0) 2 0) 1 8)
|
||||
(substr (rtos (* (getvar "TDUSRTIMER") 1000000.0) 2 0) 1 8) "\""
|
||||
";\"" bezeichnung "\""
|
||||
";1"
|
||||
";" merkmale-json)
|
||||
)
|
||||
|
||||
|
||||
;; ============================================================
|
||||
;; C:OMNI_EXPORT - Omniflo-Elemente zaehlen und als CSV exportieren
|
||||
@@ -373,6 +358,9 @@
|
||||
len-ap110 len-ap60 laenge-str
|
||||
fh out-pfad lines subtyp merkmale)
|
||||
|
||||
;; Vor dem Export: IDs aller Bloecke sicherstellen und Duplikate korrigieren
|
||||
(princ "\n[OMNI_EXPORT] Pruefe und vergebe IDs...")
|
||||
(ssg-id-check-all)
|
||||
;; Vor dem Export HOEHE/DREHUNG aller Omniflo-Elemente aktualisieren
|
||||
(princ "\n[OMNI_EXPORT] Aktualisiere Hoehe/Drehung...")
|
||||
(omni:update-all-attribs)
|
||||
@@ -403,8 +391,12 @@
|
||||
(setq cnt-boegen (1+ cnt-boegen))
|
||||
(setq merkmale (csv:omni-bogen-merkmale ename rotation))
|
||||
(setq lines (cons
|
||||
(csv:omni-csv-line elem-nr "Omniflo Kurve"
|
||||
(strcat "OFBogen :" (itoa cnt-boegen)) merkmale)
|
||||
(strcat (itoa elem-nr)
|
||||
";\"Omniflo Kurve\""
|
||||
";\"" (or (csv:get-attrib ename "ID") "0000") "\""
|
||||
";\"" (strcat "OFBogen :" (itoa cnt-boegen)) "\""
|
||||
";1"
|
||||
";" merkmale)
|
||||
lines))
|
||||
)
|
||||
|
||||
@@ -421,8 +413,12 @@
|
||||
)
|
||||
(setq merkmale (csv:omni-weiche-merkmale ename rotation))
|
||||
(setq lines (cons
|
||||
(csv:omni-csv-line elem-nr "Omniflo Weiche"
|
||||
(strcat "OFWeiche :" (itoa cnt-weichen)) merkmale)
|
||||
(strcat (itoa elem-nr)
|
||||
";\"Omniflo Weiche\""
|
||||
";\"" (or (csv:get-attrib ename "ID") "0000") "\""
|
||||
";\"" (strcat "OFWeiche :" (itoa cnt-weichen)) "\""
|
||||
";1"
|
||||
";" merkmale)
|
||||
lines))
|
||||
)
|
||||
|
||||
@@ -437,8 +433,12 @@
|
||||
)
|
||||
(setq merkmale (csv:omni-gerade-merkmale ename rotation))
|
||||
(setq lines (cons
|
||||
(csv:omni-csv-line elem-nr "Omniflo Gerade"
|
||||
(strcat "OFGerade :" (itoa cnt-geraden)) merkmale)
|
||||
(strcat (itoa elem-nr)
|
||||
";\"Omniflo Gerade\""
|
||||
";\"" (or (csv:get-attrib ename "ID") "0000") "\""
|
||||
";\"" (strcat "OFGerade :" (itoa cnt-geraden)) "\""
|
||||
";1"
|
||||
";" merkmale)
|
||||
lines))
|
||||
)
|
||||
)
|
||||
|
||||
@@ -620,6 +620,41 @@
|
||||
)
|
||||
)
|
||||
|
||||
;; --- JSON-Array von flachen Objekten parsen ---
|
||||
;; Verwendet ssg-cfg-trim und ssg-cfg-parse-kv aus ssg_core.
|
||||
;; Rueckgabe: Liste von Alists (("key" . wert) ...)
|
||||
(defun ssg-parse-json-array (zeilen / in-obj obj ergebnis zeile kv trimmed)
|
||||
(setq in-obj nil obj nil ergebnis nil)
|
||||
(foreach zeile zeilen
|
||||
(setq trimmed (ssg-cfg-trim zeile))
|
||||
(cond
|
||||
((= trimmed "{")
|
||||
(setq in-obj T obj nil))
|
||||
((or (= trimmed "}") (= trimmed "},"))
|
||||
(if (and in-obj obj)
|
||||
(setq ergebnis (cons (reverse obj) ergebnis)))
|
||||
(setq in-obj nil))
|
||||
(in-obj
|
||||
(setq kv (ssg-cfg-parse-kv trimmed))
|
||||
(if kv (setq obj (cons kv obj))))
|
||||
)
|
||||
)
|
||||
(reverse ergebnis)
|
||||
)
|
||||
|
||||
;; JSON-Datei als flaches Array laden
|
||||
;; Rueckgabe: Liste von Alists oder nil bei Fehler
|
||||
(defun ssg-load-json (datei / zeilen)
|
||||
(setq zeilen (ssg-read-file-lines datei))
|
||||
(if zeilen (ssg-parse-json-array zeilen))
|
||||
)
|
||||
|
||||
;; Wert aus Alist lesen: (ssg-val alist "key")
|
||||
(defun ssg-val (alist key)
|
||||
(cdr (assoc key alist))
|
||||
)
|
||||
|
||||
|
||||
;; Verschachteltes JSON-Objekt parsen (1 Ebene tief)
|
||||
;; {"section": {"key": val, ...}, ...}
|
||||
;; -> (("section" ("key" . val) ...) ...)
|
||||
|
||||
+2
-2
@@ -103,8 +103,8 @@
|
||||
(princ "\n[SSG_LIB] WARNUNG: DXFMAKRO nicht gesetzt, Menue nicht geladen!")
|
||||
)
|
||||
|
||||
;; DBLCLKEDIT deaktivieren (Block-Editor nicht bei Doppelklick oeffnen)
|
||||
(setvar "DBLCLKEDIT" 0)
|
||||
;; DBLCLKEDIT=1: Doppelklick aktiv, ***DOUBLECLICK-Eintraege steuern Block-Verhalten
|
||||
(setvar "DBLCLKEDIT" 1)
|
||||
|
||||
(dbgflush)
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
+3
-8
@@ -13,7 +13,6 @@ CSV-Format:
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import uuid
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -35,10 +34,6 @@ def build_lookup(boegen, weichen):
|
||||
return lookup
|
||||
|
||||
|
||||
def generate_shape_id():
|
||||
return "shape_" + str(uuid.uuid4())
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Merkmale-Builder
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -151,7 +146,7 @@ def process_blocks(blocks, lookup):
|
||||
if bname in lookup:
|
||||
typ, eintrag = lookup[bname]
|
||||
elem_nr += 1
|
||||
shape_id = generate_shape_id()
|
||||
shape_id = block.get("attribs", {}).get("ID", "0000")
|
||||
|
||||
if typ == "bogen":
|
||||
bogen_count += 1
|
||||
@@ -182,7 +177,7 @@ def process_blocks(blocks, lookup):
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "Omniflo Gerade",
|
||||
"teileid": generate_shape_id(),
|
||||
"teileid": block.get("attribs", {}).get("ID", "0000"),
|
||||
"bezeichnung": f"OFGerade :{gerade_count}",
|
||||
"merkmale": build_gerade_merkmale(block),
|
||||
})
|
||||
@@ -195,7 +190,7 @@ def process_blocks(blocks, lookup):
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "ILS 2.0 Kreisel",
|
||||
"teileid": generate_shape_id(),
|
||||
"teileid": block.get("attribs", {}).get("ID", "0000"),
|
||||
"bezeichnung": f"Kreisel :{kreisel_count}",
|
||||
"merkmale": build_kreisel_merkmale(block),
|
||||
})
|
||||
|
||||
+3
-8
@@ -15,7 +15,6 @@ Argumente:
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import uuid
|
||||
|
||||
|
||||
def load_json(path):
|
||||
@@ -35,10 +34,6 @@ def build_lookup(boegen, weichen):
|
||||
return lookup
|
||||
|
||||
|
||||
def generate_shape_id():
|
||||
return "shape_" + str(uuid.uuid4())
|
||||
|
||||
|
||||
def classify_weiche(eintrag):
|
||||
"""Bestimmt den Weichen-Subtyp fuer die Omniflo Sum Zaehlung."""
|
||||
wt = eintrag.get("WeichenTyp", "")
|
||||
@@ -213,7 +208,7 @@ def process_blocks(blocks, lookup):
|
||||
if bname in lookup:
|
||||
typ, eintrag = lookup[bname]
|
||||
elem_nr += 1
|
||||
shape_id = generate_shape_id()
|
||||
shape_id = block.get("attribs", {}).get("ID", "0000")
|
||||
|
||||
if typ == "bogen":
|
||||
bogen_count += 1
|
||||
@@ -261,7 +256,7 @@ def process_blocks(blocks, lookup):
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "Omniflo Gerade",
|
||||
"teileid": generate_shape_id(),
|
||||
"teileid": block.get("attribs", {}).get("ID", "0000"),
|
||||
"bezeichnung": f"OFGerade :{gerade_count}",
|
||||
"anzahl": 1,
|
||||
"merkmale": build_gerade_merkmale(block)
|
||||
@@ -276,7 +271,7 @@ def process_blocks(blocks, lookup):
|
||||
items.append({
|
||||
"nr": elem_nr,
|
||||
"teileart": "ILS 2.0 Kreisel",
|
||||
"teileid": generate_shape_id(),
|
||||
"teileid": block.get("attribs", {}).get("ID", "0000"),
|
||||
"bezeichnung": f"Kreisel :{kreisel_count}",
|
||||
"anzahl": 1,
|
||||
"merkmale": build_kreisel_merkmale(block)
|
||||
|
||||
+1
-1
@@ -149,7 +149,7 @@
|
||||
|
||||
;; Pulldown-Menue in die Menueleiste einhaengen
|
||||
(menucmd "P13=+SSG_LIB.POP1")
|
||||
(setvar "DBLCLKEDIT" 0)
|
||||
(setvar "DBLCLKEDIT" 1)
|
||||
(princ "\n[SSG_LIB] Alle Module geladen. Menue aktiv.")
|
||||
)
|
||||
(princ "\n[SSG_LIB] WARNUNG: DXFM_LISP nicht gesetzt - Befehle nicht verfuegbar.")
|
||||
|
||||
@@ -126,6 +126,11 @@
|
||||
|
||||
***DOUBLECLICK
|
||||
[INSERT]^C^C(ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT
|
||||
[MTEXT]^C^CDDEDIT
|
||||
[TEXT]^C^CDDEDIT
|
||||
[ATTDEF]^C^CDDEDIT
|
||||
[HATCH]^C^CHATCHEDIT
|
||||
[DIMENSION]^C^CDDEDIT
|
||||
|
||||
***POP501
|
||||
[SSG_LIB Edit Context]
|
||||
|
||||
+83
-20
@@ -8,6 +8,9 @@ Die Tests folgen einer **zweistufigen Architektur**:
|
||||
2. **Python-Validierung** (`.py`) — pruefen die Ergebnisse mit pytest + ezdxf
|
||||
|
||||
```
|
||||
tests/alltests.json
|
||||
|
|
||||
v
|
||||
BricsCAD Kommandozeile
|
||||
| |
|
||||
| SSG_RUN_ALL_TESTS |
|
||||
@@ -18,14 +21,14 @@ BricsCAD Kommandozeile
|
||||
| | |
|
||||
v v |
|
||||
tests/output/ |
|
||||
kreisel_results.json |
|
||||
kreisel_tests.dxf |
|
||||
foerderer_results.json |
|
||||
foerderer_tests.dxf |
|
||||
kseinaus_results.json |
|
||||
kseinaus_tests.dxf |
|
||||
omniflo_results.json |
|
||||
omniflo_tests.dxf |
|
||||
kreisel_results.json (immer) |
|
||||
kreisel_tests.dxf (save: dxf) |
|
||||
foerderer_results.json (immer) |
|
||||
foerderer_tests.dwg (save: dwg) |
|
||||
kseinaus_results.json (immer) |
|
||||
(keine Zeichnung) (save: null) |
|
||||
omniflo_results.json (immer) |
|
||||
omniflo_tests.dxf (save: dxf) |
|
||||
omniflo_export.csv |
|
||||
|
|
||||
bin\run_tests.bat --runall
|
||||
@@ -36,6 +39,36 @@ tests/output/ |
|
||||
test_omniflo.py
|
||||
```
|
||||
|
||||
## alltests.json — Testregistry
|
||||
|
||||
Die Datei `tests/alltests.json` ist die zentrale Registry aller Test-Module.
|
||||
`SSG_RUN_ALL_TESTS` liest sie beim Start — die Testliste ist **nicht** hartcodiert in `test_run_all.lsp`.
|
||||
|
||||
```json
|
||||
[
|
||||
{ "name": "kreisel", "save": "dxf" },
|
||||
{ "name": "foerderer", "save": "dwg" },
|
||||
{ "name": "kseinaus", "save": null },
|
||||
{ "name": "omniflo", "save": "dxf" }
|
||||
]
|
||||
```
|
||||
|
||||
Felder pro Eintrag:
|
||||
|
||||
| Feld | Typ | Bedeutung |
|
||||
| --- | --- | --- |
|
||||
| `name` | String | Basisname des Testmoduls (Pflicht) |
|
||||
| `save` | `"dxf"` / `"dwg"` / `null` | Ob und als welches Format die Zeichnung gespeichert wird |
|
||||
|
||||
**JSON-Export laeuft immer** — unabhaengig vom `save`-Feld. Die Datei `<name>_results.json`
|
||||
wird in `tests/output/` geschrieben, sobald der Test abgeschlossen ist.
|
||||
|
||||
**Wann welches `save` verwenden:**
|
||||
|
||||
- `"dxf"` — wenn ein Python-Test (ezdxf) die Geometrie der Zeichnung pruefen soll
|
||||
- `"dwg"` — wenn die Zeichnung zur manuellen Kontrolle oder als DWG-Referenz erhalten bleiben soll
|
||||
- `null` (oder Feld weglassen) — wenn nur der JSON-Export benoetigt wird
|
||||
|
||||
## Ablauf fuer den Anwender
|
||||
|
||||
1. **BricsCAD starten** (ueber `bin\start_briscad.bat`) und die LISP-Testrunner ausfuehren (siehe Abschnitt "LISP-Tests in BricsCAD ausfuehren"). Die Testrunner erzeugen Bloecke in der Zeichnung und speichern Ergebnisse nach `tests/output/`.
|
||||
@@ -96,22 +129,33 @@ Dann alle Tests auf einmal ausfuehren:
|
||||
SSG_RUN_ALL_TESTS
|
||||
```
|
||||
|
||||
Oder einen einzelnen Test:
|
||||
`SSG_RUN_ALL_TESTS` liest die Testliste aus `tests/alltests.json` und fuehrt fuer jedes Modul aus:
|
||||
|
||||
1. Zeichnung leeren (ERASE ALL + PURGE x5) — saubere Basis fuer jeden Test
|
||||
2. `test_<name>.lsp` laden und `TEST_<NAME>` ausfuehren
|
||||
3. JSON-Export aufrufen: `<name>:export-results` — **immer**, unabhaengig von `save`
|
||||
4. Zeichnung speichern — nur wenn `"save"` in `alltests.json` gesetzt ist (`"dxf"` oder `"dwg"`)
|
||||
5. Bei Fehler: weiter mit naechstem Test (`vl-catch-all-apply`)
|
||||
|
||||
**Einzeltest** (z.B. nur Kreisel pruefen):
|
||||
|
||||
```lisp
|
||||
;; Einzeltest (z.B. Kreisel)
|
||||
;; Test-Datei laden und Befehl ausfuehren
|
||||
(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp"))
|
||||
TEST_KREISEL
|
||||
;; Ergebnisse manuell exportieren:
|
||||
;; JSON-Export manuell aufrufen:
|
||||
(kreisel:export-results (strcat (getenv "DXFMAKRO") "/tests/output"))
|
||||
```
|
||||
|
||||
`SSG_RUN_ALL_TESTS` fuehrt fuer jedes Modul in `*test-module*` folgendes aus:
|
||||
- Zeichnung leeren (ERASE + PURGE)
|
||||
- Testdatei laden und Befehl ausfuehren
|
||||
- JSON-Export aufrufen (`<name>:export-results`)
|
||||
- DXF speichern (`<name>_tests.dxf`)
|
||||
- Bei Fehler: weiter mit naechstem Test (vl-catch-all-apply)
|
||||
**Unterschied SSG_RUN_ALL_TESTS vs. Einzeltest:**
|
||||
|
||||
| | SSG_RUN_ALL_TESTS | Einzeltest |
|
||||
| --- | --- | --- |
|
||||
| Testliste | aus `alltests.json` | manuell gewaehlter Test |
|
||||
| Zeichnung leeren | automatisch vor jedem Test | nein (Zeichnung bleibt) |
|
||||
| JSON-Export | automatisch nach jedem Test | manuell aufrufen |
|
||||
| DXF/DWG speichern | gemaess `save` in `alltests.json` | manuell (SAVEAS / DXFOUT) |
|
||||
| Fehlerisolation | ja (Fehler unterbricht nicht weitere Tests) | nein |
|
||||
|
||||
### 2. Python-Validierung ausfuehren
|
||||
|
||||
@@ -229,13 +273,32 @@ Fuer ein neues Modul eine neue `.lsp`-Datei erstellen nach dem Muster:
|
||||
)
|
||||
```
|
||||
|
||||
Dann den Basisnamen in `*test-module*` (in `test_run_all.lsp`) eintragen:
|
||||
Dann den Basisnamen in `tests/alltests.json` eintragen:
|
||||
|
||||
```lisp
|
||||
(setq *test-module* '("kreisel" "foerderer" "kseinaus" "omniflo" "<modul>"))
|
||||
```json
|
||||
{ "name": "<modul>", "save": "dxf" }
|
||||
```
|
||||
|
||||
`"save"` waehlen je nach Bedarf (`"dxf"`, `"dwg"` oder `null`).
|
||||
`test_run_all.lsp` leitet alle Namen aus dem `"name"`-Feld ab — **nichts** in `test_run_all.lsp` aendern.
|
||||
|
||||
### Namenskonventionen (werden von test_run_all.lsp automatisch abgeleitet)
|
||||
|
||||
Aus dem Basisnamen `<name>` in `alltests.json` entstehen durch Konvention:
|
||||
|
||||
| Element | Schema | Beispiel fuer `"name": "kreisel"` |
|
||||
| --- | --- | --- |
|
||||
| LISP-Datei | `tests/test_<name>.lsp` | `tests/test_kreisel.lsp` |
|
||||
| BricsCAD-Befehl | `TEST_<NAME>` (Grossbuchstaben) | `TEST_KREISEL` |
|
||||
| Export-Funktion | `<name>:export-results` | `kreisel:export-results` |
|
||||
| JSON-Ergebnis | `output/<name>_results.json` | `output/kreisel_results.json` |
|
||||
| DXF/DWG-Datei | `output/<name>_tests.dxf/.dwg` | `output/kreisel_tests.dxf` |
|
||||
|
||||
Die Export-Funktion **muss** exakt so heissen: `<name>:export-results` (Namespace-Notation mit Doppelpunkt).
|
||||
Sie nimmt genau einen Parameter entgegen: den Pfad zum Output-Verzeichnis.
|
||||
|
||||
Wichtig:
|
||||
|
||||
- `omni:load-json` erwartet ein **flaches JSON-Array** mit flachen Objekten (kein Nesting)
|
||||
- `omni:val` liest Werte aus den geladenen Eintraegen
|
||||
- Script-Funktionen (z.B. `kreisel-insert-script`) muessen **ohne User-Interaktion** funktionieren
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
;; Erzeugt 12 Variofoerderer (6x Auf, 6x Ab) mit deltaL=7000
|
||||
;; und verschiedenen Hoehenstufen. Speichert:
|
||||
;; - tests/output/foerderer_results.json (Ergebnisse)
|
||||
;; - tests/output/foerderer_tests.dxf (Zeichnung)
|
||||
;; - tests/output/foerderer_tests.dwg (Zeichnung)
|
||||
;;
|
||||
;; Voraussetzungen:
|
||||
;; - SSG_LIB geladen (VarioFoerderer.lsp, ssg_core.lsp)
|
||||
|
||||
+17
-17
@@ -54,13 +54,13 @@
|
||||
(defun kreisel:run-insert-test (eintrag / id x y z abstand rotation typ
|
||||
pt blockEnt ed attribs block-name
|
||||
block-handle insert-point)
|
||||
(setq id (omni:val eintrag "id"))
|
||||
(setq x (omni:val eintrag "x"))
|
||||
(setq y (omni:val eintrag "y"))
|
||||
(setq z (omni:val eintrag "z"))
|
||||
(setq abstand (omni:val eintrag "abstand"))
|
||||
(setq rotation (omni:val eintrag "rotation"))
|
||||
(setq typ (omni:val eintrag "typ"))
|
||||
(setq id (ssg-val eintrag "id"))
|
||||
(setq x (ssg-val eintrag "x"))
|
||||
(setq y (ssg-val eintrag "y"))
|
||||
(setq z (ssg-val eintrag "z"))
|
||||
(setq abstand (ssg-val eintrag "abstand"))
|
||||
(setq rotation (ssg-val eintrag "rotation"))
|
||||
(setq typ (ssg-val eintrag "typ"))
|
||||
|
||||
(if (numberp x) (setq x (float x)))
|
||||
(if (numberp y) (setq y (float y)))
|
||||
@@ -98,14 +98,14 @@
|
||||
(defun kreisel:run-connect-test (eintrag / id sx sy sz ex ey ez typ
|
||||
ptStart ptEnd blockEnt ed attribs
|
||||
block-name block-handle insert-point)
|
||||
(setq id (omni:val eintrag "id"))
|
||||
(setq sx (omni:val eintrag "start_x"))
|
||||
(setq sy (omni:val eintrag "start_y"))
|
||||
(setq sz (omni:val eintrag "start_z"))
|
||||
(setq ex (omni:val eintrag "end_x"))
|
||||
(setq ey (omni:val eintrag "end_y"))
|
||||
(setq ez (omni:val eintrag "end_z"))
|
||||
(setq typ (omni:val eintrag "typ"))
|
||||
(setq id (ssg-val eintrag "id"))
|
||||
(setq sx (ssg-val eintrag "start_x"))
|
||||
(setq sy (ssg-val eintrag "start_y"))
|
||||
(setq sz (ssg-val eintrag "start_z"))
|
||||
(setq ex (ssg-val eintrag "end_x"))
|
||||
(setq ey (ssg-val eintrag "end_y"))
|
||||
(setq ez (ssg-val eintrag "end_z"))
|
||||
(setq typ (ssg-val eintrag "typ"))
|
||||
|
||||
(if (numberp sx) (setq sx (float sx)))
|
||||
(if (numberp sy) (setq sy (float sy)))
|
||||
@@ -194,7 +194,7 @@
|
||||
(princ)
|
||||
)
|
||||
(progn
|
||||
(setq testfaelle (omni:load-json tests-json-pfad))
|
||||
(setq testfaelle (ssg-load-json tests-json-pfad))
|
||||
(if (null testfaelle)
|
||||
(progn
|
||||
(princ "\n[TEST_KREISEL] FEHLER: Testdaten konnten nicht geladen werden.")
|
||||
@@ -213,7 +213,7 @@
|
||||
|
||||
;; Testfaelle ausfuehren
|
||||
(foreach eintrag testfaelle
|
||||
(setq func (omni:val eintrag "function"))
|
||||
(setq func (ssg-val eintrag "function"))
|
||||
(setq result-json
|
||||
(cond
|
||||
((= func "insert")
|
||||
|
||||
+57
-15
@@ -100,6 +100,47 @@
|
||||
)
|
||||
|
||||
|
||||
;; --- Post-Clean: Omniflo-Testbloecke aus der Zeichnung loeschen ---
|
||||
;; Entfernt alle INSERT-Entities mit rein numerischen Blocknamen (Omniflo SivasNr)
|
||||
;; sowie AP110-Geraden. Wird vom Test-Runner nach dem Export aufgerufen.
|
||||
;; Rueckgabe: Anzahl geloeschter Bloecke
|
||||
(defun omniflo:post-clean ( / ss-all i ename ed bname count)
|
||||
(setq count 0)
|
||||
(setq ss-all (ssget "X" (list (cons 0 "INSERT"))))
|
||||
(if ss-all
|
||||
(progn
|
||||
(setq i 0)
|
||||
(while (setq ename (ssname ss-all i))
|
||||
(setq ed (entget ename))
|
||||
(setq bname (cdr (assoc 2 ed)))
|
||||
(if (or
|
||||
;; Omniflo SivasNr: rein numerisch (beginnt mit Ziffer, kein Unterstrich)
|
||||
(and (wcmatch bname "#*") (null (vl-string-search "_" bname)))
|
||||
;; Omniflo Geraden
|
||||
(wcmatch (strcase bname) "AP110*,AP_110*")
|
||||
)
|
||||
(progn
|
||||
(entdel ename)
|
||||
(setq count (1+ count))
|
||||
)
|
||||
)
|
||||
(setq i (1+ i))
|
||||
)
|
||||
)
|
||||
)
|
||||
(princ (strcat "\n[OMNIFLO] Post-Clean: " (itoa count) " Bloecke entfernt."))
|
||||
count
|
||||
)
|
||||
|
||||
|
||||
;; --- BricsCAD-Befehl: Omniflo-Ergebnisse exportieren ---
|
||||
(defun c:TEST_OMNIFLO_EXPORT ( / tests-out-dir)
|
||||
(setq tests-out-dir (strcat (getenv "DXFMAKRO") "/tests/output"))
|
||||
(omniflo:export-results tests-out-dir)
|
||||
(princ)
|
||||
)
|
||||
|
||||
|
||||
;; ============================================================
|
||||
;; C:TEST_OMNIFLO
|
||||
;;
|
||||
@@ -107,15 +148,11 @@
|
||||
;; exportiert CSV nach tests/output/.
|
||||
;; ============================================================
|
||||
(defun c:TEST_OMNIFLO (/ tests-json-pfad testfaelle
|
||||
x-pos x-schritt
|
||||
x-val y-val
|
||||
idx eintrag sivasnr hoehe-str drehung-str
|
||||
description insert-pt anzahl-ok anzahl-fehler
|
||||
results-list tests-out-dir old-results)
|
||||
|
||||
(if (not *lib-initialized*)
|
||||
(init-bibliothek)
|
||||
)
|
||||
|
||||
(ssg-start "TEST_OMNIFLO"
|
||||
'(("OSMODE") ("ATTREQ") ("ATTDIA")))
|
||||
(setvar "OSMODE" 0)
|
||||
@@ -134,7 +171,7 @@
|
||||
(princ)
|
||||
)
|
||||
(progn
|
||||
(setq testfaelle (omni:load-json tests-json-pfad))
|
||||
(setq testfaelle (ssg-load-json tests-json-pfad))
|
||||
(if (null testfaelle)
|
||||
(progn
|
||||
(princ "\n[TEST_OMNIFLO] FEHLER: Testdaten konnten nicht geladen werden.")
|
||||
@@ -148,8 +185,6 @@
|
||||
(princ "\n================================================================")
|
||||
|
||||
;; Alle Bloecke einfuegen
|
||||
(setq x-pos 0.0)
|
||||
(setq x-schritt 200.0)
|
||||
(setq anzahl-ok 0)
|
||||
(setq anzahl-fehler 0)
|
||||
(setq results-list nil)
|
||||
@@ -157,24 +192,31 @@
|
||||
|
||||
(foreach eintrag testfaelle
|
||||
(setq idx (1+ idx))
|
||||
(setq sivasnr (omni:val eintrag "sivasnr"))
|
||||
(setq hoehe-str (omni:val eintrag "hoehe"))
|
||||
(setq sivasnr (ssg-val eintrag "sivasnr"))
|
||||
(setq hoehe-str (ssg-val eintrag "hoehe"))
|
||||
(if (null hoehe-str) (setq hoehe-str "2000"))
|
||||
(if (numberp hoehe-str)
|
||||
(setq hoehe-str (rtos hoehe-str 2 0))
|
||||
)
|
||||
(setq drehung-str (omni:val eintrag "drehung"))
|
||||
(setq drehung-str (ssg-val eintrag "drehung"))
|
||||
(if (null drehung-str) (setq drehung-str "0"))
|
||||
(if (numberp drehung-str)
|
||||
(setq drehung-str (rtos drehung-str 2 1))
|
||||
)
|
||||
(setq description (omni:val eintrag "description"))
|
||||
(setq description (ssg-val eintrag "description"))
|
||||
|
||||
(setq insert-pt (list x-pos 0.0 (atof hoehe-str)))
|
||||
;; x,y-Koordinaten aus JSON lesen (wie in omniflo_uebersicht.dxf)
|
||||
(setq x-val (ssg-val eintrag "x"))
|
||||
(setq y-val (ssg-val eintrag "y"))
|
||||
(if (null x-val) (setq x-val 0.0))
|
||||
(if (null y-val) (setq y-val 0.0))
|
||||
(if (not (numberp x-val)) (setq x-val (atof x-val)))
|
||||
(if (not (numberp y-val)) (setq y-val (atof y-val)))
|
||||
(setq insert-pt (list x-val y-val (atof hoehe-str)))
|
||||
|
||||
(princ (strcat "\n " (itoa idx) ". "
|
||||
(if description description (if sivasnr sivasnr "?"))
|
||||
" -> (" (rtos x-pos 2 0) ", 0, " hoehe-str ")"))
|
||||
" -> (" (rtos x-val 2 0) ", " (rtos y-val 2 0) ", " hoehe-str ")"))
|
||||
|
||||
(if (omni:test-insert sivasnr insert-pt hoehe-str drehung-str)
|
||||
(progn
|
||||
@@ -193,9 +235,9 @@
|
||||
)
|
||||
)
|
||||
|
||||
(setq x-pos (+ x-pos x-schritt))
|
||||
)
|
||||
|
||||
|
||||
;; Zusammenfassung
|
||||
(princ "\n================================================================")
|
||||
(princ (strcat "\n Eingefuegt: " (itoa anzahl-ok)
|
||||
|
||||
+79
-1
@@ -22,7 +22,7 @@ sys.path.insert(0, _LIB_DIR)
|
||||
|
||||
from export_csv import (
|
||||
build_lookup, process_blocks, build_bogen_merkmale,
|
||||
build_weiche_merkmale, load_json
|
||||
build_weiche_merkmale, load_json, format_csv_line
|
||||
)
|
||||
|
||||
|
||||
@@ -100,6 +100,16 @@ class TestOmnifloExportUnit:
|
||||
))
|
||||
self.items = process_blocks(self.blocks, self.lookup)
|
||||
|
||||
# CSV in output speichern
|
||||
out_dir = _output_dir()
|
||||
os.makedirs(out_dir, exist_ok=True)
|
||||
csv_path = os.path.join(out_dir, "omniflo_export.csv")
|
||||
header = "Elementnummer;TeileArt;TeileId;Bezeichnung;Anzahl;Merkmale"
|
||||
with open(csv_path, "w", encoding="utf-8") as f:
|
||||
f.write(header + "\n")
|
||||
for item in self.items:
|
||||
f.write(format_csv_line(item) + "\n")
|
||||
|
||||
def test_item_count_matches_testcases(self):
|
||||
"""Anzahl exportierter Elemente muss Anzahl Testfaelle entsprechen."""
|
||||
assert len(self.items) == len(self.tests), (
|
||||
@@ -348,3 +358,71 @@ class TestOmnifloExportCSV:
|
||||
assert not missing, (
|
||||
f"Zeile {i + 2}: Fehlende Weichen-Felder: {missing}"
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Referenz-Tests: CSV gegen Referenzdatei vergleichen
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _reference_dir():
|
||||
return os.path.join(os.path.dirname(os.path.abspath(__file__)), "reference")
|
||||
|
||||
|
||||
def _normalize_row(line):
|
||||
"""Splittet eine CSV-Zeile und ersetzt die TeileId (UUID) durch Platzhalter."""
|
||||
cols = line.strip().split(";", 5)
|
||||
if len(cols) >= 3:
|
||||
cols[2] = "<ID>"
|
||||
return cols
|
||||
|
||||
|
||||
class TestOmnifloReferenceCSV:
|
||||
"""Vergleicht den erzeugten Unit-Test-CSV-Export mit einer Referenzdatei."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup(self):
|
||||
self.out_csv = os.path.join(_output_dir(), "omniflo_export.csv")
|
||||
self.ref_csv = os.path.join(_reference_dir(), "omniflo_export_reference.csv")
|
||||
if not os.path.exists(self.out_csv):
|
||||
pytest.skip(
|
||||
"omniflo_export.csv nicht vorhanden - "
|
||||
"zuerst TestOmnifloExportUnit ausfuehren"
|
||||
)
|
||||
if not os.path.exists(self.ref_csv):
|
||||
pytest.skip("Referenzdatei nicht vorhanden: " + self.ref_csv)
|
||||
with open(self.out_csv, "r", encoding="utf-8") as f:
|
||||
self.out_lines = f.readlines()
|
||||
with open(self.ref_csv, "r", encoding="utf-8") as f:
|
||||
self.ref_lines = f.readlines()
|
||||
|
||||
def test_header_matches_reference(self):
|
||||
"""Header muss mit Referenz uebereinstimmen."""
|
||||
assert self.out_lines[0].strip() == self.ref_lines[0].strip(), (
|
||||
f"Header abweichend:\n Ist: {self.out_lines[0].strip()}\n"
|
||||
f" Soll: {self.ref_lines[0].strip()}"
|
||||
)
|
||||
|
||||
def test_zeilenanzahl_matches_reference(self):
|
||||
"""Zeilenanzahl muss mit Referenz uebereinstimmen."""
|
||||
assert len(self.out_lines) == len(self.ref_lines), (
|
||||
f"Zeilenanzahl abweichend: Ist={len(self.out_lines)}, "
|
||||
f"Soll={len(self.ref_lines)}"
|
||||
)
|
||||
|
||||
def test_zeilen_matches_reference(self):
|
||||
"""Alle Zeilen muessen mit Referenz uebereinstimmen (TeileId wird ignoriert)."""
|
||||
min_lines = min(len(self.out_lines), len(self.ref_lines))
|
||||
diffs = []
|
||||
for i in range(1, min_lines):
|
||||
out_cols = _normalize_row(self.out_lines[i])
|
||||
ref_cols = _normalize_row(self.ref_lines[i])
|
||||
if out_cols != ref_cols:
|
||||
diffs.append(
|
||||
f"Zeile {i + 1}:\n"
|
||||
f" Ist: {self.out_lines[i].strip()[:120]}\n"
|
||||
f" Soll: {self.ref_lines[i].strip()[:120]}"
|
||||
)
|
||||
assert not diffs, (
|
||||
f"{len(diffs)} abweichende Zeile(n) (erste 5):\n" +
|
||||
"\n".join(diffs[:5])
|
||||
)
|
||||
|
||||
@@ -146,6 +146,9 @@
|
||||
)
|
||||
|
||||
;; Zeichnung leeren fuer sauberen Testlauf
|
||||
;; Frozen Layer werden von _.ERASE _ALL ignoriert - deshalb
|
||||
;; erst alle Layer auftauen, entsperren und einschalten.
|
||||
(command "_.LAYER" "_Thaw" "*" "_Unlock" "*" "_On" "*" "")
|
||||
(if (ssget "_X")
|
||||
(command "_.ERASE" "_ALL" "")
|
||||
)
|
||||
|
||||
Vendored
+1145
-80
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user