[ADD] Dematic/Arvato: Nachbau-Vorlage tests/testdata/dematic_arvato.json (Abschnitt Flowpuffer/Kreisel) + Treiber TEST_DEMATIC_ARVATO (Menue Tests, in alltests.json vorerst disabled); [FIX] dxf_scan_components.py: liest jetzt auch ASCII-DXF, Kreisel-Paarung global nach Abstand und nur auf gemeinsamer Achse (vorher klaute ein AN8 die SP8 des Nachbarn), Kreisel-Position aus der Radmitte statt dem Einfuegepunkt (AN8/SP8 Pinband haben das Rad ~15 m daneben), Kreisel als insert mit Mittenabstand statt connect (war an beiden Enden einen Radius zu kurz), AN8/SP8 Pinband erkannt, Projektkennung in den IDs per --projekt statt fest HundM05; [FIX] hundm05:bau-sensor brach bei Eintraegen ohne id mit bad argument type <NIL> ab

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-05 15:39:11 +02:00
parent fe5cb9664c
commit 1250864849
7 changed files with 1688 additions and 29 deletions
+151 -29
View File
@@ -44,6 +44,7 @@ import struct
import sys
from ezdxf.lldxf.types import BINARY_DATA, INT16, INT32, INT64, DOUBLE, BYTES
from ezdxf.lldxf.types import cast_tag_value
from ezdxf.math import Matrix44, OCS
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
@@ -62,6 +63,10 @@ MAX_PAAR_ABSTAND = 60000.0
# 10 mm deckt Rundungs- und Zeichenungenauigkeiten der Fremdzeichnung ab.
GERADE_MAX_DELTA_H = 10.0
# Projektkennung in den erzeugten IDs (Kreisel_<PROJEKT>_01 ...); main()
# setzt sie aus --projekt bzw. dem Namen der DXF-Datei.
PROJEKT = "HundM05"
# Toleranz fuer die Dedup-Rundung (Nachkommastellen).
RUND = 2
@@ -190,6 +195,48 @@ def iter_binary_tags(mm):
yield code, value
def iter_ascii_tags(mm):
"""Streamt (code, value)-Tags aus einem ASCII-DXF.
Gegenstueck zu iter_binary_tags fuer Zeichnungen, die als Text-DXF
gespeichert wurden (z.B. Dematic_arvato.dxf). Die Werte werden ueber die
ezdxf-Typtabelle in float/int gewandelt, damit lese_inserts dieselben
Typen sieht wie beim binaeren Lesen.
"""
i = 0
n = len(mm)
while i < n:
end = mm.find(b"\n", i)
if end < 0:
break
code_raw = mm[i:end].strip()
i = end + 1
end = mm.find(b"\n", i)
if end < 0:
end = n
value_raw = mm[i:end].rstrip(b"\r")
i = end + 1
if not code_raw:
continue
code = int(code_raw)
value = decode_str(value_raw)
if code == 0:
value = value.strip()
else:
try:
value = cast_tag_value(code, value)
except ValueError:
pass
yield code, value
def iter_tags(mm):
"""Binaer- oder ASCII-DXF anhand der Kopfzeile erkennen."""
if mm[:22] == b"AutoCAD Binary DXF\r\n\x1a\x00":
return iter_binary_tags(mm)
return iter_ascii_tags(mm)
# ---------------------------------------------------------------------------
# Familien-Erkennung (Blockname -> Bauteilfamilie)
# ---------------------------------------------------------------------------
@@ -197,8 +244,8 @@ def iter_binary_tags(mm):
# mit Wildcards - die Blocknamen der Fremdzeichnungen enthalten Umlaute und
# Sonderzeichen (z.B. "3D_Schraegfoerderer_Antrieb", "TEF_Bogen_90Grad_...").
FAMILIEN = [
("kreisel_an", ["AN8", "AN8_*"]),
("kreisel_sp", ["SP8", "SP8_*"]),
("kreisel_an", ["AN8", "AN8_*", "AN8 Pinband*"]),
("kreisel_sp", ["SP8", "SP8_*", "SP8 Pinband*"]),
("foerderer_antrieb", ["3D_TEF_Antrieb*", "3D_FF_Antrieb*",
"3D_Schr*rderer_Antrieb*", "Antrieb FF"]),
("foerderer_umlenk", ["3D_TEF_Umlenk*", "3D_FF_Umlenk*",
@@ -443,7 +490,7 @@ def lese_inserts(dxf_path):
fh.close()
raise
try:
for code, value in iter_binary_tags(mm):
for code, value in iter_tags(mm):
if code == 0:
# Ein ATTRIB endet immer am naechsten 0-Tag. Erst hier steht
# sicher fest, dass Tag UND Wert gelesen sind - in einem ATTRIB
@@ -496,6 +543,19 @@ def lese_inserts(dxf_path):
block_merken(aktueller_block)["kinder"].add(value)
elif aktuell == "ATTRIB":
attrib_tag = value
elif aktuell == "CIRCLE" and aktueller_block and code in (10, 20, 30):
# Mittelpunkt des ERSTEN Kreises der Blockdefinition merken -
# bei AN8/SP8 ist das das Rad. Die Pinband-Varianten in
# Dematic_arvato.dxf haben ihr Rad ~15 m neben dem
# Einfuegepunkt; ohne diesen Wert laege der Kreisel dort.
# Ein zweiter Kreis beginnt mit Code 10, waehrend "kreis" schon
# existiert - ab da ist der erste fertig (Code 30 ist optional).
info = block_merken(aktueller_block)
if code == 10 and "kreis" in info:
info["kreis_fertig"] = True
if not info.get("kreis_fertig"):
kreis = info.setdefault("kreis", [0.0, 0.0, 0.0])
kreis[{10: 0, 20: 1, 30: 2}[code]] = value
elif aktuell == "BLOCK" and aktueller_block and code in (10, 20, 30):
block_base[aktueller_block][{10: 0, 20: 1, 30: 2}[code]] = value
elif aktuell == "INSERT" and rec is not None:
@@ -630,6 +690,13 @@ def sammle_vorkommen(ms_inserts, block_inserts, block_base, max_tiefe=12,
xachse = mat.transform((1.0, 0.0, 0.0)) - ursprung
rot = math.degrees(math.atan2(xachse.y, xachse.x)) % 360.0
fam = familie_von(rec["name"])
# Kreisel-Stationen: Position = Radmitte, nicht Einfuegepunkt
# (siehe "kreis" in lese_inserts). Die Rotation oben bleibt die
# des Inserts.
kreis = ((block_info or {}).get(rec["name"], {}).get("kreis")
if fam in ("kreisel_an", "kreisel_sp") else None)
if kreis:
ursprung = mat.transform(tuple(kreis))
if fam:
treffer.append({
"familie": fam,
@@ -866,6 +933,48 @@ def zwillinge_zusammenfuehren(treffer):
# Paarbildung und Schema-Abbildung
# ---------------------------------------------------------------------------
# Querversatz (mm), bis zu dem AN8 und SP8 noch auf derselben Kreisel-Achse
# liegen. Beide Stationen sitzen auf der Mittellinie des Kreisels; in
# Dematic_arvato.dxf liegen echte Paare auf 0,2 mm genau auf einer Achse.
KREISEL_MAX_QUER = 100.0
def kreisel_paare_bilden(an_liste, sp_liste):
"""AN8 und SP8 zu Kreiseln paaren.
Global nach Abstand (kuerzestes Paar zuerst) statt AN8 fuer AN8 in
X-Reihenfolge: dort griff sich ein frueh sortierter AN8 die naechste noch
freie SP8 eines Nachbar-Kreisels, und alle folgenden Paare rutschten mit
(Dematic_arvato: ein 33,5-m-Kreisel wurde mit der SP8 eines 3,6-m-Kreisels
19 m daneben gepaart). Zusaetzlich muessen beide auf einer gemeinsamen
Achse liegen (Querversatz <= KREISEL_MAX_QUER).
Rueckgabe: (paare [(an, sp, abstand)] nach AN-Position sortiert,
AN8 ohne Partner, SP8 ohne Partner)
"""
kandidaten = []
for ia, an in enumerate(an_liste):
for isp, sp in enumerate(sp_liste):
dx = abs(sp["x"] - an["x"])
dy = abs(sp["y"] - an["y"])
if min(dx, dy) > KREISEL_MAX_QUER:
continue
kandidaten.append((math.hypot(dx, dy), ia, isp))
kandidaten.sort()
an_frei = set(range(len(an_liste)))
sp_frei = set(range(len(sp_liste)))
paare = []
for dist, ia, isp in kandidaten:
if ia in an_frei and isp in sp_frei:
an_frei.discard(ia)
sp_frei.discard(isp)
paare.append((an_liste[ia], sp_liste[isp], dist))
paare.sort(key=lambda p: (p[0]["x"], p[0]["y"]))
return (paare,
[an_liste[i] for i in sorted(an_frei)],
[sp_liste[i] for i in sorted(sp_frei)])
def paare_bilden(antriebe, umlenkungen):
"""Gegenseitig naechste Nachbarn paaren.
@@ -978,7 +1087,7 @@ def foerderer_eintrag(a, u, dist_xy, nummer, gf_winkel_min):
# Die echte Hoehe liefert der 3D-Zwilling (siehe Zusammenfuehrung).
if a.get("darstellung") == "2D":
return {
"test_id": "GERADE_HundM05_%02d" % nummer,
"test_id": "GERADE_%s_%02d" % (PROJEKT, nummer),
"typ": "gerade",
"darstellung": "2D",
"laenge": round(dist_xy, RUND),
@@ -993,7 +1102,7 @@ def foerderer_eintrag(a, u, dist_xy, nummer, gf_winkel_min):
if abs(dz) < GERADE_MAX_DELTA_H:
return {
"test_id": "GERADE_HundM05_%02d" % nummer,
"test_id": "GERADE_%s_%02d" % (PROJEKT, nummer),
"typ": "gerade",
"darstellung": a.get("darstellung", "?"),
"laenge": round(dist_xy, RUND),
@@ -1008,7 +1117,7 @@ def foerderer_eintrag(a, u, dist_xy, nummer, gf_winkel_min):
if dz < 0 and neigung >= gf_winkel_min:
return {
"test_id": "GF_HundM05_%02d" % nummer,
"test_id": "GF_%s_%02d" % (PROJEKT, nummer),
"modus": 1,
"darstellung": a.get("darstellung", "?"),
"deltaL_mm": round(dist_xy, RUND),
@@ -1025,7 +1134,7 @@ def foerderer_eintrag(a, u, dist_xy, nummer, gf_winkel_min):
}
return {
"test_id": "VF_HundM05_%02d" % nummer,
"test_id": "VF_%s_%02d" % (PROJEKT, nummer),
"typ": "standard",
"darstellung": a.get("darstellung", "?"),
"richtung": "Auf" if dz > 0 else "Ab",
@@ -1116,16 +1225,12 @@ def baue_eintraege(treffer, defaults, boegen, weichen,
# --- Kreisel: AN8 (Antriebsstation) + SP8 (Spannstation) --------------
durchmesser = defaults.get("kreisel", {}).get("durchmesser", 800.0)
an_liste = sorted(nach_familie.get("kreisel_an", []), key=lambda t: (t["x"], t["y"]))
sp_liste = list(nach_familie.get("kreisel_sp", []))
for i, an in enumerate(an_liste, start=1):
if not sp_liste:
hinweise.append("AN8 bei (%.2f, %.2f) ohne SP8-Partner" % (an["x"], an["y"]))
eintraege.append(sensor_eintrag(an, bekannte_bloecke, hinweise, treffer))
continue
sp = min(sp_liste, key=lambda s: math.hypot(s["x"] - an["x"], s["y"] - an["y"]))
sp_liste.remove(sp)
dist = math.hypot(sp["x"] - an["x"], sp["y"] - an["y"])
kreisel_paare, an_rest, sp_liste = kreisel_paare_bilden(
nach_familie.get("kreisel_an", []), nach_familie.get("kreisel_sp", []))
for an in an_rest:
hinweise.append("AN8 bei (%.2f, %.2f) ohne SP8-Partner" % (an["x"], an["y"]))
eintraege.append(sensor_eintrag(an, bekannte_bloecke, hinweise, treffer))
for i, (an, sp, dist) in enumerate(kreisel_paare, start=1):
rotation = math.degrees(math.atan2(sp["y"] - an["y"], sp["x"] - an["x"])) % 360.0
# AN8/SP8 sind flache 2D-Symbole auf Z=0 - die Einbauhoehe steht nicht
# im DXF. Sie wird aus den 3D-Modellen in der Umgebung abgeleitet
@@ -1144,19 +1249,31 @@ def baue_eintraege(treffer, defaults, boegen, weichen,
hoehe_hinweis = (" ACHTUNG hoehe=%.1f ist NICHT belegt: "
"AN8/SP8 sind flache 2D-Symbole auf Z=0 und "
"%s." % (hoehe, grund))
# an/sp sind Radmitten (siehe "kreis" in lese_inserts). draw-module
# (KreiselInsert.lsp) legt AN8 bei (radius, 0) und SP8 bei
# (radius + abstand, 0) in den Block: abstand ist also der
# Mittenabstand, und der Einfuegepunkt liegt einen Radius VOR der
# AN8-Mitte. Die fruehere "connect"-Ausgabe uebergab die Radmitten an
# kreisel-connect-script, das Aussenkanten erwartet - der Kreisel
# wurde dadurch an beiden Enden um einen Radius zu kurz.
radius = durchmesser / 2.0
richtung = math.radians(rotation)
eintraege.append({
"id": "Kreisel_HundM05_%02d" % i,
"function": "connect",
"start_x": an["x"], "start_y": an["y"], "start_z": an["z"],
"end_x": sp["x"], "end_y": sp["y"], "end_z": sp["z"],
"id": "Kreisel_%s_%02d" % (PROJEKT, i),
"function": "insert",
"x": round(an["x"] - radius * math.cos(richtung), RUND) + 0.0,
"y": round(an["y"] - radius * math.sin(richtung), RUND) + 0.0,
"z": hoehe,
"abstand": round(dist, RUND),
"rotation": round(rotation, RUND) + 0.0,
"typ": "STANDARD",
"darstellung": an.get("darstellung", "?"),
"hoehe": hoehe,
"comment": ("aus DXF: AN8 (Layer %s) -> SP8 (Layer %s), Abstand "
"%.2f; daraus folgt produktionsseitig abstand = %.2f - "
"%.1f = %.2f und rotation = %.2f Grad."
% (an["layer"], sp["layer"], dist, dist, durchmesser,
dist - durchmesser, rotation)) + hoehe_hinweis,
"comment": ("aus DXF: Radmitte %s (Layer %s) (%.2f, %.2f) -> "
"%s (Layer %s) (%.2f, %.2f), Mittenabstand %.2f, "
"rotation %.2f Grad; x/y = AN8-Mitte minus Radius."
% (an["block"], an["layer"], an["x"], an["y"],
sp["block"], sp["layer"], sp["x"], sp["y"], dist,
rotation)) + hoehe_hinweis,
})
for sp in sp_liste:
hinweise.append("SP8 bei (%.2f, %.2f) ohne AN8-Partner" % (sp["x"], sp["y"]))
@@ -1188,7 +1305,7 @@ def baue_eintraege(treffer, defaults, boegen, weichen,
hinweise.append("Omniflo %s ohne Sivasnr: '%s' (%s)"
% (typ, t["block"], grund))
eintraege.append({
"id": sivasnr or ("%s_HundM05_%02d" % (typ.upper(), i)),
"id": sivasnr or ("%s_%s_%02d" % (typ.upper(), PROJEKT, i)),
"type": typ,
"sivasnr": sivasnr,
"x": t["x"], "y": t["y"], "z": t["z"],
@@ -1346,7 +1463,7 @@ def main():
description="Erkennt ILS-/Omniflo-Komponenten in einem fremden DXF "
"und schreibt sie im JSON-Schema aus "
"tests/testdata/object_data.md.")
parser.add_argument("dxf", help="Quellzeichnung (binaeres DXF)")
parser.add_argument("dxf", help="Quellzeichnung (binaeres oder ASCII-DXF)")
parser.add_argument("data_dir", help="Datenverzeichnis mit json/")
parser.add_argument("output", help="Ziel-JSON")
parser.add_argument("--fenster", nargs=4, type=float,
@@ -1354,8 +1471,13 @@ def main():
help="Nur Bauteile in diesem XY-Fenster (mm) "
"ausgeben - fuer den Nachbau eines einzelnen "
"Anlagenabschnitts statt der ganzen Zeichnung")
parser.add_argument("--projekt",
help="Projektkennung in den erzeugten IDs "
"(Default: Name der DXF-Datei ohne Endung)")
args = parser.parse_args()
dxf_path, data_dir, output_path = args.dxf, args.data_dir, args.output
global PROJEKT
PROJEKT = args.projekt or os.path.splitext(os.path.basename(dxf_path))[0]
fenster = None
if args.fenster:
x0, y0, x1, y1 = args.fenster
+12
View File
@@ -734,6 +734,12 @@
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")) (c:TEST_HUNDM05)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00177">
<Macro>
<Name>Dematic/Arvato Flowpuffer (Vorlage)</Name>
<Command>^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) (c:TEST_DEMATIC_ARVATO)</Command>
</Macro>
</MenuMacro>
<MenuMacro UID="MM_00157">
<Macro>
<Name>KS 2D/3D pruefen (CSV)</Name>
@@ -1627,6 +1633,12 @@
<MacroRef MenuMacroID="MM_00156"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>Dematic/Arvato Flowpuffer (Vorlage)</NameRef>
<MenuItem>
<MacroRef MenuMacroID="MM_00177"/>
</MenuItem>
</PopMenuItem>
<PopMenuItem>
<NameRef>KS 2D/3D pruefen (CSV)</NameRef>
<MenuItem>
+1
View File
@@ -154,6 +154,7 @@
[Gefaellestrecke]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_gefaellestrecke.lsp")) (c:TEST_GEFAELLESTRECKE)
[Mubea Gesamtmodell]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp")) (c:TEST_MUBEA)
[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)
[<-KS 2D/3D pruefen (CSV)]^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN
***DOUBLECLICK
+1
View File
@@ -10,5 +10,6 @@
{ "name": "gefaellestrecke", "save": "dwg", "module": "Gefaellestrecke" },
{ "name": "mubea", "save": "dxf", "module": "KreiselInsert" },
{ "name": "hundm05", "save": "dxf", "module": "VarioFoerderer" },
{ "name": "dematic_arvato", "save": "dxf", "module": "VarioFoerderer", "disabled": true },
{ "name": "hm_recformat", "save": "dxf", "module": "VarioFoerderer", "disabled": true }
]
+138
View File
@@ -0,0 +1,138 @@
;; ============================================================
;; test_dematic_arvato.lsp - Nachbau des Abschnitts Flowpuffer/Kreisel der
;; Anlage Dematic/Arvato aus der Scanner-Vorlage.
;;
;; Datenquelle: tests/testdata/dematic_arvato.json, erzeugt mit
;; python lib/dxf_scan_components.py \
;; C:/develop/sps_skel/data/Dematic_arvato.dxf data \
;; tests/testdata/dematic_arvato.json --projekt Arvato \
;; --fenster -3000 159000 49000 193000
;;
;; Die Datei ist eine VORLAGE fuer den Nachbau, kein fertiger Testfall:
;; Hoehen fehlen (flaches 2D-Schema, alles auf Z=0), Seiten/Winkel einiger
;; Bloecke sind geraten (siehe "comment" je Eintrag).
;;
;; Eintragsarten (Schema von dxf_scan_components.py):
;; "function": "insert" ohne "block" -> Kreisel (hundm05:bau-kreisel ->
;; kreisel-insert-script; x/y = Einfuegepunkt
;; einen Radius vor der AN8-Radmitte, abstand =
;; Mittenabstand AN8-SP8)
;; "function": "insert" + "block" -> Einzelblock (hundm05:bau-sensor,
;; Fallback Separator_SP bei unbekanntem Block)
;; "typ": "gerade" -> waagrechter Foerderer Antrieb->Umlenkung -
;; dafuer gibt es noch keinen Bau-Pfad, wird
;; gemeldet und uebersprungen
;;
;; Keine eigene Bau-Logik: hundm05:bau-kreisel/-sensor aus
;; tests/test_hundm05.lsp wird mitgeladen (die Datei definiert nur Funktionen).
;;
;; Aufruf in BricsCAD:
;; (load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp"))
;; TEST_DEMATIC_ARVATO
;; ============================================================
(if (not (boundp '*dematic-arvato-records*)) (setq *dematic-arvato-records* nil))
;; Module und die Bau-Funktionen aus test_hundm05.lsp beim LADEN dieser Datei
;; holen, nicht erst in c:TEST_DEMATIC_ARVATO: in BricsCAD werden per load
;; definierte Funktionen erst nach Rueckkehr zum Top-Level sichtbar (siehe
;; tests/test_unit.scr).
(ssg-ensure "KreiselInsert")
(ssg-ensure "VarioFoerderer")
(ssg-ensure "SSG_LIB_Commands")
(if (null (car (atoms-family 1 '("HUNDM05:BAU-SENSOR"))))
(load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp")))
(defun dematic_arvato:datei ()
(strcat (getenv "DXFMAKRO") "/tests/testdata/dematic_arvato.json"))
;; Foerderer "gerade": noch kein Bau-Pfad - nur melden.
(defun dematic_arvato:gerade-melden (obj / tid rec)
(setq tid (ssg-val obj "test_id"))
(princ (strcat "\n [GERADE] " (if tid tid "?")
" uebersprungen - waagrechter Foerderer noch nicht unterstuetzt"))
(setq rec (vsp-rec-neu (if tid tid "(ohne id)")))
(setq rec (vsp-set rec "kind" "gerade"))
(vsp-set (vsp-set rec "status" "uebersprungen") "fehler_text"
"kein Bau-Pfad fuer typ gerade"))
(defun dematic_arvato:bau-eintrag (obj / kind res)
(cond
((and (= (ssg-val obj "function") "insert") (ssg-val obj "block"))
(setq kind "sensor")
(setq res (vl-catch-all-apply 'hundm05:bau-sensor (list obj))))
((= (ssg-val obj "function") "insert")
(setq kind "kreisel")
(setq res (vl-catch-all-apply 'hundm05:bau-kreisel (list obj))))
((= (ssg-val obj "typ") "gerade")
(setq kind "gerade")
(setq res (dematic_arvato:gerade-melden obj)))
(T
(setq kind "unbekannt")
(princ "\n WARNUNG: unbekannter Eintrag uebersprungen")
(setq res (vsp-set (vsp-rec-neu "(unbekannt)") "status" "uebersprungen"))))
(if (vl-catch-all-error-p res)
(progn
(princ (strcat "\n [" (strcase kind) "] Ausnahme: "
(vl-catch-all-error-message res)))
(vsp-set (vsp-set (vsp-set (vsp-rec-neu (cond ((ssg-val obj "id"))
((ssg-val obj "block"))
("?")))
"kind" kind) "status" "abbruch")
"fehler_text" (vl-catch-all-error-message res)))
res))
(defun c:TEST_DEMATIC_ARVATO ( / datei daten out zaehler st)
(setq datei (dematic_arvato:datei))
(princ "\n\n================================================================")
(princ "\n TEST_DEMATIC_ARVATO - Abschnitt Flowpuffer/Kreisel (Vorlage)")
(princ (strcat "\n " datei))
(princ "\n================================================================")
(cond
((null (car (atoms-family 1 '("VSP-REC-NEU"))))
(princ "\n[TEST_DEMATIC_ARVATO] FEHLER: vf_spec.lsp nicht geladen"
" (VarioFoerderer laden).")
(setq *dematic-arvato-records* nil))
((null (findfile datei))
(princ (strcat "\n[TEST_DEMATIC_ARVATO] FEHLER: " datei " nicht gefunden!"))
(setq *dematic-arvato-records* nil))
(T
(setq daten (ssg-json-laden datei))
(princ (strcat "\n " (itoa (length daten)) " Eintraege geladen"))
(ssg-start "TEST_DEMATIC_ARVATO"
'(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA")))
(setvar "OSMODE" 0)
(setvar "ATTREQ" 0)
(setvar "ATTDIA" 0)
(setq out '())
(foreach obj daten
(setq out (cons (dematic_arvato:bau-eintrag obj) out)))
(ssg-end)
(setq *dematic-arvato-records* (reverse out))
;; Zusammenfassung je Status
(setq zaehler '())
(foreach r *dematic-arvato-records*
(setq st (cond ((ssg-val r "status")) ("?")))
(if (assoc st zaehler)
(setq zaehler (subst (cons st (1+ (cdr (assoc st zaehler))))
(assoc st zaehler) zaehler))
(setq zaehler (cons (cons st 1) zaehler))))
(princ "\n================================================================")
(foreach z (reverse zaehler)
(princ (strcat "\n " (car z) ": " (itoa (cdr z)))))
(princ "\n================================================================")
(command "_.ZOOM" "_E")))
(princ))
;; Ergebnis-Export (Konvention <name>:export-results fuer test_run_all.lsp)
(defun dematic_arvato:export-results (out-dir / pfad)
(if (null *dematic-arvato-records*)
(princ "\n Keine Dematic/Arvato-Ergebnisse vorhanden.")
(progn
(vl-mkdir out-dir)
(setq pfad (strcat out-dir "/dematic_arvato_results.json"))
(vsp-results-schreiben *dematic-arvato-records* pfad)))
(princ))
(princ "\nTEST_DEMATIC_ARVATO geladen. Aufruf: TEST_DEMATIC_ARVATO")
(princ)
+4
View File
@@ -138,6 +138,10 @@
(defun hundm05:bau-sensor (obj / id blockname x y z rotation pt eff n vorher ent ed attribs rec)
(setq id (ssg-val obj "id"))
(setq blockname (ssg-val obj "block"))
;; Eintraege aus lib/dxf_scan_components.py haben kein "id" - die
;; Meldungen unten setzen id per strcat zusammen und brachen dann mit
;; "bad argument type <NIL>" ab.
(if (null id) (setq id (cond (blockname) ("(ohne id)"))))
(setq x (ssg-val obj "x")
y (ssg-val obj "y")
z (ssg-val obj "z")
+1381
View File
File diff suppressed because it is too large Load Diff