[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:
+151
-29
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
]
|
||||
|
||||
@@ -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)
|
||||
@@ -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")
|
||||
|
||||
Vendored
+1381
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user