From 1250864849283902a4438f47af686e1b6369f91a Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Mon, 5 Oct 2026 15:39:11 +0200 Subject: [PATCH 01/38] [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 ab Co-Authored-By: Claude Opus 5.5 --- lib/dxf_scan_components.py | 180 +++- menu/SSG_LIB.cui | 12 + menu/SSG_LIB.mnu | 1 + tests/alltests.json | 1 + tests/test_dematic_arvato.lsp | 138 +++ tests/test_hundm05.lsp | 4 + tests/testdata/dematic_arvato.json | 1381 ++++++++++++++++++++++++++++ 7 files changed, 1688 insertions(+), 29 deletions(-) create mode 100644 tests/test_dematic_arvato.lsp create mode 100644 tests/testdata/dematic_arvato.json diff --git a/lib/dxf_scan_components.py b/lib/dxf_scan_components.py index 2cb37f2..043bd20 100644 --- a/lib/dxf_scan_components.py +++ b/lib/dxf_scan_components.py @@ -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__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 diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 0cd7164..369b401 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -734,6 +734,12 @@ ^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) @@ -1627,6 +1633,12 @@ + + Dematic/Arvato Flowpuffer (Vorlage) + + + + KS 2D/3D pruefen (CSV) diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 578eece..703b508 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -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 diff --git a/tests/alltests.json b/tests/alltests.json index dc98cb9..f427384 100644 --- a/tests/alltests.json +++ b/tests/alltests.json @@ -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 } ] diff --git a/tests/test_dematic_arvato.lsp b/tests/test_dematic_arvato.lsp new file mode 100644 index 0000000..7823b7a --- /dev/null +++ b/tests/test_dematic_arvato.lsp @@ -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 :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) diff --git a/tests/test_hundm05.lsp b/tests/test_hundm05.lsp index e579570..4ca9f40 100644 --- a/tests/test_hundm05.lsp +++ b/tests/test_hundm05.lsp @@ -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 " 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") diff --git a/tests/testdata/dematic_arvato.json b/tests/testdata/dematic_arvato.json new file mode 100644 index 0000000..b9c122c --- /dev/null +++ b/tests/testdata/dematic_arvato.json @@ -0,0 +1,1381 @@ +[ + { + "id": "Kreisel_Arvato_03", + "function": "insert", + "x": 18737.94, + "y": 165252.93, + "z": 0.0, + "abstand": 3619.15, + "rotation": 90.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (18737.94, 165652.93) -> SP8 (Layer 1SP-800) (18737.94, 169272.08), Mittenabstand 3619.15, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + }, + { + "id": "Kreisel_Arvato_04", + "function": "insert", + "x": 35394.31, + "y": 176069.0, + "z": 370.0, + "abstand": 33044.28, + "rotation": 180.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 Pinband (Layer 1ANTR-800) (34994.31, 176069.00) -> SP8 Pinband (mit Inkrementalgeber 829522024) (Layer 1SP-800) (1950.03, 176069.00), Mittenabstand 33044.28, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=370.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + }, + { + "id": "Kreisel_Arvato_05", + "function": "insert", + "x": 36195.18, + "y": 188428.08, + "z": 0.0, + "abstand": 33470.18, + "rotation": 180.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (35795.18, 188428.08) -> SP8 (Layer 1SP-800) (2325.00, 188428.08), Mittenabstand 33470.18, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + }, + { + "id": "Kreisel_Arvato_06", + "function": "insert", + "x": 42097.73, + "y": 165252.93, + "z": 0.0, + "abstand": 3619.15, + "rotation": 90.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (42097.73, 165652.93) -> SP8 (Layer 1SP-800) (42097.72, 169272.08), Mittenabstand 3619.15, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + }, + { + "test_id": "GERADE_Arvato_01", + "typ": "gerade", + "darstellung": "2D", + "laenge": 8313.39, + "hz": 90.0, + "startpunkt": [2334.97, 177818.67, 0.0], + "endpunkt": [2334.96, 186132.06, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 90 Grad, Laenge 8313.39, Querversatz 0.01 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_09", + "typ": "gerade", + "darstellung": "2D", + "laenge": 8313.39, + "hz": 90.0, + "startpunkt": [14264.99, 177818.71, 0.0], + "endpunkt": [14264.99, 186132.1, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 90 Grad, Laenge 8313.39, Querversatz 0.00 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_10", + "typ": "gerade", + "darstellung": "2D", + "laenge": 3183.28, + "hz": 270.0, + "startpunkt": [19545.38, 174003.47, 370.0], + "endpunkt": [19545.58, 170820.19, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 270 Grad, Laenge 3183.28, Querversatz 0.20 (Bezugspunkt-Unterschied), Neigung 6.63 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_11", + "typ": "gerade", + "darstellung": "2D", + "laenge": 17664.81, + "hz": 0.0, + "startpunkt": [21626.92, 167134.77, 0.0], + "endpunkt": [39291.73, 167134.97, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 0 Grad, Laenge 17664.81, Querversatz 0.20 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_12", + "typ": "gerade", + "darstellung": "2D", + "laenge": 3124.62, + "hz": 0.0, + "startpunkt": [21626.97, 165578.18, 0.0], + "endpunkt": [24751.59, 165578.37, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 0 Grad, Laenge 3124.62, Querversatz 0.19 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_13", + "typ": "gerade", + "darstellung": "2D", + "laenge": 8313.39, + "hz": 90.0, + "startpunkt": [22854.62, 177818.71, 0.0], + "endpunkt": [22854.61, 186132.1, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 90 Grad, Laenge 8313.39, Querversatz 0.01 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_14", + "typ": "gerade", + "darstellung": "2D", + "laenge": 6717.41, + "hz": 0.0, + "startpunkt": [32574.32, 165578.18, 0.0], + "endpunkt": [39291.73, 165578.37, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 0 Grad, Laenge 6717.41, Querversatz 0.19 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_15", + "typ": "gerade", + "darstellung": "2D", + "laenge": 3706.41, + "hz": 180.0, + "startpunkt": [34650.88, 173417.91, 0.0], + "endpunkt": [30944.47, 173408.89, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 180 Grad, Laenge 3706.41, Querversatz 9.02 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "test_id": "GERADE_Arvato_16", + "typ": "gerade", + "darstellung": "2D", + "laenge": 3566.48, + "hz": 270.0, + "startpunkt": [41688.71, 185921.64, 0.0], + "endpunkt": [41678.01, 182355.16, 0.0], + "hoehe_unbekannt": true, + "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 270 Grad, Laenge 3566.48, Querversatz 10.70 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + }, + { + "function": "insert", + "block": "Vario_Motorstation_500mm_rechts", + "x": 41271.73, + "y": 171724.16, + "z": -370.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Antrieb FF', Layer 'z-3', auf Makro-Block 'Vario_Motorstation_500mm_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Umlenkstation_500mm_rechts", + "x": 30282.95, + "y": 174208.89, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Umlenkung FF', Layer 'z-3', auf Makro-Block 'Vario_Umlenkstation_500mm_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Umlenkstation_500mm_rechts", + "x": 36190.75, + "y": 186482.16, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Umlenkung FF', Layer 'z-3', auf Makro-Block 'Vario_Umlenkstation_500mm_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41377.46, + "y": 179475.63, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Lage=aussen, Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 35984.01, + "y": 173395.48, + "z": 0.0, + "rotation": 120.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 36210.84, + "y": 173622.64, + "z": 0.0, + "rotation": 150.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 36296.49, + "y": 173937.59, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41169.03, + "y": 187345.02, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41483.98, + "y": 187259.38, + "z": 0.0, + "rotation": 240.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41711.14, + "y": 187032.54, + "z": 0.0, + "rotation": 210.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Vario_Kurve_rechts_30_TEF_aussen", + "x": 41784.82, + "y": 180461.57, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 2801.42, + "y": 186442.19, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 4901.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 5801.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 6601.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 7401.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 8451.06, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 9251.06, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 10051.06, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 11391.05, + "y": 178054.91, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 12191.05, + "y": 178054.91, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 12991.05, + "y": 178054.91, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 14731.45, + "y": 186442.19, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 15801.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 16601.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 17401.05, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 18448.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 19348.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 20148.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 20948.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 23321.08, + "y": 186442.19, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 24608.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 25408.56, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 26908.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 27808.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 28608.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 29408.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 30958.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 31858.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 32658.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_links", + "x": 33458.55, + "y": 178054.88, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_rechts", + "x": 42932.74, + "y": 166073.59, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement rechts 200000241 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "AS_Element_90_rechts", + "x": 42932.74, + "y": 167630.19, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Ausschleuselement rechts 200000241 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "ES_Element_90_rechts", + "x": 4958.03, + "y": 166992.08, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Einschleuselement rechts 200000146 Seitenansicht', Layer '4-EE', auf Makro-Block 'ES_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "ES_Element_90_rechts", + "x": 8058.82, + "y": 168049.64, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Einschleuselement rechts 200000146 Seitenansicht', Layer '4-EE', auf Makro-Block 'ES_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "ES_Element_30_rechts", + "x": 20513.9, + "y": 187602.73, + "z": -4.49, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'Einschleuselement rechts 30° 200000688 Vorderansicht', Layer '0', auf Makro-Block 'ES_Element_30_rechts' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 2572.67, + "y": 175669.0, + "z": 370.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 3016.33, + "y": 188028.08, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 4628.04, + "y": 176469.0, + "z": 370.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 14946.35, + "y": 188028.08, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 15528.05, + "y": 176469.05, + "z": 370.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 19137.94, + "y": 168591.49, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 23535.98, + "y": 188028.08, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 24328.05, + "y": 176469.09, + "z": 370.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 34584.31, + "y": 176469.0, + "z": 370.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 35391.12, + "y": 188828.08, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-LP", + "x": 41697.93, + "y": 167818.8, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 2334.91, + "y": 186756.85, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 2334.97, + "y": 176994.56, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 5367.5, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 6267.5, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 7067.5, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 7867.5, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 8917.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 9717.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 10517.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 11857.51, + "y": 187359.45, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 12657.51, + "y": 187359.45, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 13457.51, + "y": 187359.45, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 14264.94, + "y": 186756.89, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 14264.99, + "y": 176994.61, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 16267.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 17067.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 17867.51, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 18915.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19546.07, + "y": 170249.91, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19546.07, + "y": 175157.16, + "z": 370.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19680.48, + "y": 167135.46, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19680.53, + "y": 165578.85, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 19815.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 20615.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 21415.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 22854.57, + "y": 186756.89, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 22854.62, + "y": 176994.61, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 25075.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 25462.17, + "y": 165578.85, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 25875.01, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 27375.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 28275.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 29075.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 29875.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 30851.32, + "y": 174208.89, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 30944.14, + "y": 165578.85, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 31425.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 31494.84, + "y": 173408.89, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 32325.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 33125.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 33925.0, + "y": 187359.42, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 36195.18, + "y": 187066.18, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 39889.85, + "y": 167135.46, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 39889.9, + "y": 165578.85, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 41439.64, + "y": 169070.08, + "z": 0.0, + "rotation": 120.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "S-SP", + "x": 41697.72, + "y": 182892.95, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 3166.57, + "y": 188414.66, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 4477.8, + "y": 176855.58, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 15096.6, + "y": 188414.66, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 15377.81, + "y": 176855.63, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 23686.22, + "y": 188414.66, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 24177.81, + "y": 176855.68, + "z": 370.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 25618.13, + "y": 165246.94, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 30966.81, + "y": 165246.94, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 41298.05, + "y": 167879.95, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + } +] From 36b6fdb650c0fde94736aed80bf38699057bca96 Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Mon, 5 Oct 2026 17:05:13 +0200 Subject: [PATCH 02/38] [ADD] doc/json-input-lisp.md: JSON-Eingabeformate je Element (Kreisel, Einzelbloecke, VF Standard/Etage, GF Modus 1-3, VF-Linienzug Spec/Journal, Omniflo, gerade) aus tests/testdata mit Feldern, Koordinaten-Bezug und Bau-Routine - ersetzt das geloeschte tests/testdata/object_data.md; [ADD] doc/lisp_methods.md: Uebersicht der LISP-Bau-Routinen je Einheit (Befehl + skriptfaehiger Kern, Signaturen, Rueckgaben, Voraussetzungen, Einfuegeprimitiven) Co-Authored-By: Claude Opus 5.5 --- doc/json-input-lisp.md | 437 +++++++++++++++++++++++++++++++++++++++++ doc/lisp_methods.md | 328 +++++++++++++++++++++++++++++++ 2 files changed, 765 insertions(+) create mode 100644 doc/json-input-lisp.md create mode 100644 doc/lisp_methods.md diff --git a/doc/json-input-lisp.md b/doc/json-input-lisp.md new file mode 100644 index 0000000..1c90257 --- /dev/null +++ b/doc/json-input-lisp.md @@ -0,0 +1,437 @@ +# JSON-Eingabe fuer den LISP-Bau + +Welche Objekte sich aus einer JSON-Datei an einer gegebenen x/y/z-Koordinate +erzeugen lassen, in welchem Format sie beschrieben werden und welche +LISP-Routine sie baut. Grundlage sind die Testdaten in `tests/testdata/*.json` +und die Treiber in `tests/test_*.lsp`, die sie lesen. + +Die zugehoerigen LISP-Routinen mit Signaturen stehen in +[lisp_methods.md](lisp_methods.md). Diese Seite ersetzt das fruehere +`tests/testdata/object_data.md` (geloescht in Commit `e147b89`, auf das Code- +Kommentare teilweise noch verweisen). + +--- + +## 0. Uebersicht + +| Objekt | Erkennungsmerkmal im JSON | Bau-Routine (Produktion) | Koordinaten-Eingang | Beispiel-Datei | +|---|---|---|---|---| +| [Kreisel (Insert)](#1-kreisel) | `"function": "insert"`, KEIN `block` | `kreisel-insert-script` | `x`,`y`,`z` = Einfuegepunkt | `kreisel_tests.json`, `mubea.json`, `hundm05.json`, `dematic_arvato.json` | +| [Kreisel (Connect)](#12-connect-start--und-endpunkt) | `"function": "connect"` | `kreisel-connect-script` | `start_*`, `end_*` | (nur `test_kreisel.lsp`, z.Z. kein Datensatz) | +| [Einzelblock](#2-einzelbloecke-separator-scanner-btmt-eingangausgang-vario-bausteine) (Separator, Scanner, BTMT, Eingang/Ausgang, Vario-Bausteine) | `"function": "insert"` + `"block"` | direktes `_.INSERT` nach `ssg-ils-block-laden` | `x`,`y`,`z` + `rotation` | `mubea.json`, `hundm05.json`, `dematic_arvato.json` | +| [VarioFoerderer Standard](#3-variofoerderer-standard-und-etage) | `test_id` beginnt mit `VF_`, `typ` fehlt oder `"standard"` | `berechne-alle-winkel` + `variofoerderer-einfuegen` + `vf-block-erstellen` | `x`,`y`,`z` = KS_EIN des AS-Elements | `mubea.json`, `foerderer_tests.json` | +| [VarioFoerderer Etage](#3-variofoerderer-standard-und-etage) | `test_id` `VF_*` + `"typ": "etage"` | `berechne-etage` + `etage-foerderanlage-einfuegen` + `vf-block-erstellen` | wie Standard | `mubea.json` | +| [Gefaellestrecke Modus 1](#4-gefaellestrecke) | `test_id` `GF_*` bzw. `"modus": 1` | `gefaellestrecke-einfuegen` (bzw. `gf-rebuild`) | `start_mm` = KS_EIN des AS-Elements | `mubea.json`, `gefaellestrecke_tests.json` | +| [Gefaellestrecke Modus 2](#42-modus-2---richtung-aus-zwei-punkten) | `"modus": 2` | wie Modus 1, `deltaL`/`hz` aus zwei Punkten | `start_mm` + `linie_start_mm`/`linie_ende_mm` | `gefaellestrecke_tests.json` | +| [Gefaellestrecke Modus 3](#43-modus-3---linienzug) | `"modus": 3` | nur ueber `test_gefaellestrecke.lsp` | `start_mm`, `ende_mm`, `bogen` | `gefaellestrecke_tests.json` | +| [VF-Linienzug-Kette (Spec)](#5-vf-linienzug-kette-spec) | Kopf mit `spec_id`, danach `glied`/`sub` | `vsp-bau-aus-spec` (Replay durch `vf-linienzug-modus`) | `start_punkt` = Kettenanfang | `hundm05.json` | +| [VF-Linienzug (Journal)](#6-vf-linienzug-eingabe-journal) | Kopf mit `test_id`, danach `typ` = `point_abs`/`real`/`string`/... | `vfl-journal-replay-start` + `vf-linienzug-modus` | erstes `point_abs` | `linienzug_tests.json`, `hm_recformat.json` | +| [Omniflo Bogen/Weiche](#71-bogen-und-weiche) | `"type": "bogen"` / `"weiche"` + `sivasnr` | `_.INSERT` der `.dxf` (Kern `omni:insert-dxf` fragt den Punkt interaktiv) | `x`,`y`, Z = `hoehe` | `omniflo_tests.json`, `omniflo_strecke_tests.json` | +| [Omniflo Gerade](#72-aluprofil-gerade) | `"type": "gerade"` + `profil` | `omni:make-gerade` | `x`,`y` -> `x_ende`,`y_ende`, Z = `hoehe` | `omniflo_strecke_tests.json` | +| [Waagrechte Foerderstrecke](#8-waagrechte-foerderstrecke-gerade---noch-ohne-bau-pfad) | `"typ": "gerade"` + `startpunkt` | **kein Bau-Pfad** (wird gemeldet und uebersprungen) | `startpunkt`, `endpunkt` | `dematic_arvato.json` | + +Nicht aus JSON baubar (es gibt keine Testdaten und keinen Treiber): Eckrad, +Geruest, TEF-Foerderer-Linie, TRO-Marker, Connections, Omniflo-Ladeschleife. +Fuer Eckrad und Geruest existiert ein skriptfaehiger Kern, siehe +[lisp_methods.md](lisp_methods.md). + +### Allgemeine Regeln + +- **Einheiten**: Laengen und Koordinaten in **mm**, Winkel in **Grad**. + Fahrtrichtung `hz`: 0 = +X (Ost), 90 = +Y (Nord), 180 = -X, 270 = -Y. +- **Z ist absolut**: `z` (bzw. Z in `start_mm`/`start_punkt`) ist die + Weltkoordinate des Einfuegepunkts, also die Einbauhoehe. +- **Dimension 2D/3D**: Gebaut wird in der aktuellen Dimension + (`ssg-ils-dim-aktuell`: `*ssg-ils-dim*` -> `DXFM_DIM`, Default 3D). + Das Feld `darstellung` in `dematic_arvato.json` ist reine Dokumentation und + wird nicht ausgewertet; `TEST_HUNDM05_2D`/`_3D` erzwingen die Dimension. +- **Flaches JSON**: Die meisten Dateien werden mit `ssg-load-json` gelesen + (zeilenweise, ein Objekt je `{`). Verschachtelte Objekte und mehrzeilige + Arrays darin funktionieren nicht - darum stehen z.B. die Glieder einer + Kette als eigene Objekte hinter ihrem Kopf-Objekt. Ausnahme: + `TEST_DEMATIC_ARVATO` liest mit dem rekursiven `ssg-json-laden`. +- **Reine Doku-Felder**: `comment`, `beschreibung`, `description`, `quelle`, + `row`, `seq`, `gruppe`, `assigned_to`, `hoehe_unbekannt`, `darstellung` + sowie alle `expect_*`/`erwartung_*`-Felder werden beim Bau nicht gelesen. + `expect_*` pruefen die Python-Tests gegen das Ergebnis. +- **Template-Felder** (nur `test_mubea.lsp`): `anzahl`, `delta_x`, `delta_y` + erzeugen aus einem Eintrag `anzahl` Kopien, jeweils um `delta_x`/`delta_y` + versetzt; `test_id` bekommt dann das Suffix `_01` ... `_nn`. Gilt fuer VF, + GF und Einzelbloecke. + +--- + +## 1. Kreisel + +Block `KREISEL_n`, gebaut von `KreiselInsert.lsp`. + +### 1.1 Insert (freier Punkt) + +```json +{ "id": "KR_Kreuz_Q1_0Grad", "function": "insert", + "x": 500, "y": 500, "z": 2500, + "abstand": 2000, "rotation": 0.0, "typ": "STANDARD" } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `id` | ja (fuer den Treiber) | Kennung im Ergebnis; NICHT die Block-ID (die vergibt `ssg-id-generate`) | - | +| `function` | ja | `"insert"`; ohne `block` = Kreisel | - | +| `x`, `y` | ja | Einfuegepunkt. Liegt auf der Kreiselachse **einen Radius (400 mm) vor der Mitte des Antriebsrads (AN)**, also am aeussersten Punkt der AN-Seite | - | +| `z` | ja | Einbauhoehe; wird als `hoehe` uebergeben und in das Attribut `HOEHE` geschrieben | `kreisel.default_hoehe` (2000) | +| `abstand` | ja | Mittenabstand Antriebsrad - Spannrad | `kreisel.default_laenge` (2300) | +| `rotation` | nein | Drehung der Achse AN -> SP, frei (kein Raster) | 0.0 | +| `typ` | nein | `"STANDARD"` oder `"PIN"` -> Attribut `KREISELART` | `"STANDARD"` | + +Treiber: `kreisel:run-insert-test` (`test_kreisel.lsp`), `mubea:build-kreisel`, +`hundm05:bau-kreisel` (auch fuer `dematic_arvato.json`). + +### 1.2 Connect (Start- und Endpunkt) + +```json +{ "id": "K2", "function": "connect", + "start_x": 0, "start_y": 0, "start_z": 2000, + "end_x": 5000, "end_y": 0, "end_z": 2000, "typ": "STANDARD" } +``` + +`start_*` und `end_*` sind die aeussersten Punkte der AN- bzw. SP-Seite. +`abstand` (= Distanz - Kreiseldurchmesser 800) und `rotation` werden daraus +berechnet. Die Einbauhoehe kommt aus `start_z`. Nur `test_kreisel.lsp` kennt +`connect`; die anderen Treiber bauen ausschliesslich `insert`. + +--- + +## 2. Einzelbloecke (Separator, Scanner, BTMT, Eingang/Ausgang, Vario-Bausteine) + +Jeder Eintrag mit `"function": "insert"` UND `"block"` wird als einzelner +Block eingefuegt, ohne Wrapper-Block und ohne Verkettung. + +```json +{ "id": "HundM05_SCANNER_02", "function": "insert", "block": "Scanner", + "x": 4095.5, "y": 1164.1, "z": 2154, "rotation": 270 } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `block` | ja | Blockname OHNE `_2D`/`_3D`-Suffix | - | +| `x`, `y`, `z` | ja | Einfuegepunkt = **Basispunkt der Block-DWG** (nicht KS_EIN) | - | +| `rotation` | nein | Drehung um Z | 0 | +| `id` / `test_id` | nein | Kennung im Ergebnis | `SEPARATOR_` bzw. Blockname | + +Ablauf: `ssg-ils-block-laden` loest den Namen auf `data/ils/_.dwg` +auf (3D-Fallback), danach `_.INSERT eff pt "" "" rotation` und +`ssg-id-generate`. **Fehlt die DWG, wird `Separator_SP` eingefuegt.** +Treiber: `mubea:build-separator`, `hundm05:bau-sensor` (auch Dematic). +Das Layer-Attribut `LAYER` wird dabei nicht angewendet; der Block landet auf +dem aktuellen Layer. + +### In den Testdaten verwendete Blocknamen + +| `block` | DWG in `data/ils` | Verwendet in | Hinweis | +|---|---|---|---| +| `Scanner` | `Scanner_2D/_3D.dwg` | mubea, hundm05, dematic_arvato | | +| `Separator_SP` | `Separator_SP_2D/_3D.dwg` | (Fallback) | Block von `ILS_SEPARATOR_INSERT` | +| `S-LP` | **fehlt** | mubea, hundm05, dematic_arvato | wird zu `Separator_SP` | +| `S-SP` | **fehlt** | dematic_arvato | wird zu `Separator_SP` | +| `BTMT-Beladung` | `BTMT-Beladung_2D/_3D.dwg` | mubea, hundm05 | wie `ILS_BTMT_Beladung` | +| `SC_Entladung` | `SC_Entladung_2D/_3D.dwg` | mubea, hundm05 | wie `ILS_BTMT_Entladung` | +| `Eingang` / `Ausgang` | `Eingang_*/Ausgang_*.dwg` | mubea | Symbole wie `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` | +| `AS_Element_90_links` / `_rechts` | vorhanden | dematic_arvato | loses AS-Element (sonst Teil eines VF/GF) | +| `ES_Element_90_rechts`, `ES_Element_30_rechts` | vorhanden | dematic_arvato | loses ES-Element | +| `Vario_Motorstation_500mm_rechts` | vorhanden | dematic_arvato | lose Motorstation | +| `Vario_Umlenkstation_500mm_rechts` | vorhanden | dematic_arvato | lose Umlenkstation | +| `Vario_Kurve_rechts_30_TEF_aussen` | vorhanden | dematic_arvato | lose Vario-Kurve | + +Grundsaetzlich ist **jeder** Blockname aus `data/ils` erlaubt (es gibt keine +Whitelist). Die losen AS/ES-/Vario-Bausteine bilden aber keine Kette und keinen +`VF_n`/`GF_n`-Block - fuer eine zusammenhaengende Strecke Abschnitt 3-5 nutzen. + +--- + +## 3. VarioFoerderer Standard und Etage + +Block `VF_n`. Eingang sind die **Gesamtmasse** der Anlage; Winkel und +Teillaengen berechnet der Solver. + +```json +{ "test_id": "VF_Schnitt_C", "richtung": "Auf", + "deltaL": 9110, "deltaH": 474, "winkel": 21, + "gf_verteilung": "manuell", "L_GF1": 2298, "seite": "links", + "hz": 0.0, "x": 400, "y": 14120, "z": 1554 } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `test_id` | ja | muss mit `VF_` beginnen (steuert den Dispatcher in `test_mubea.lsp`) | - | +| `typ` | nein | `"standard"` (AS/ES 90 Grad) oder `"etage"` (AS/ES 30 Grad, uebereinander) | `"standard"` | +| `richtung` | ja | `"Auf"` oder `"Ab"` | - | +| `deltaL` | ja | horizontale Gesamtlaenge inkl. AS/ES, Boegen, GF-Vor-/Nachlauf | - | +| `deltaH` | ja | Hoehendifferenz (Betrag; Vorzeichen kommt aus `richtung`) | - | +| `winkel` | nein | Bogenwinkel erzwingen, nur aus der Kandidatenliste (`vario.bogen_winkel`: 3, 6, 9, 12, 15, 18, 21, 27, 33, 39, 45, 51). Ist er nicht loesbar, wird NICHT gebaut | kleinster gueltiger Winkel | +| `L_GF1` | nein (mubea) | Vorlauf-Laenge (GF vor dem Foerderer); Nachlauf = Rest von `L_GF` | - | +| `gf_verteilung` | nein (foerderer) | `"gleichmaessig"`, `"vorne"`, `"hinten"`; in `mubea.json` nur Doku (dort zaehlt `L_GF1`) | `"gleichmaessig"` | +| `seite` | nein | `"links"`/`"rechts"` (Seite der AS/ES-Elemente) | `"links"` | +| `hz` | nein | Fahrtrichtung | 0.0 | +| `x`, `y`, `z` | ja (mubea) | Startpunkt = **KS_EIN des AS-Elements**; `z` = Einbauhoehe am Anfang | - | + +Hinweise: +- `foerderer_tests.json` hat statt `x/y/z` einen Kopf-Eintrag + `{"y_abstand": 600}`: alle Foerderer starten bei x = 0, z = 0 und werden um + `y_abstand` versetzt. Dieses Format kennt nur `test_foerderer.lsp`. +- `"Ab"` mit `deltaH` < 1 ist geometrisch unmoeglich und wird abgewiesen. +- Der Treiber schreibt nach dem Bau `vf-edit-xdata-schreiben` (Typ + `hz`), + damit der Block per Doppelklick editierbar ist. + +--- + +## 4. Gefaellestrecke + +Block `GF_n`: AS-Element -> Staustrecke (skaliert) -> Separator -> ES-Element. +Eingang ist die **horizontale Laenge**, nicht die Hoehendifferenz - die ergibt +sich aus Laenge und Neigung. + +### 4.1 Modus 1 - Werteingabe + +```json +{ "test_id": "GF_Mubea", "modus": 1, + "deltaL_mm": 9110, "hz_grad": 180.0, "winkel_grad": 2.27, + "start_mm": [9510, 12300, 2028], + "as_seite": "links", "es_seite": "links", + "as_winkel": "90", "es_winkel": "90" } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `test_id` | ja | in `mubea.json` muss sie mit `GF_` beginnen | - | +| `modus` | nein | `1` | - | +| `deltaL_mm` | ja | horizontale Gesamtlaenge AS + Staustrecke + Separator + ES | - | +| `winkel_grad` | nein | Neigung der Staustrecke | 3.0 | +| `hz_grad` | nein | Fahrtrichtung | 0.0 | +| `start_mm` | ja | `[x, y, z]` = **KS_EIN des AS-Elements**; Z = Einbauhoehe oben | - | +| `as_seite`, `es_seite` | nein | `"links"`/`"rechts"` | `"links"` | +| `as_winkel`, `es_winkel` | nein | `"90"` oder `"30"` (als STRING) | `"90"` | + +Die Staustrecke ergibt sich aus +`L_stau = (deltaL - aus-dx - ein-dx - 300 * cos(w)) / cos(w)` +(300 = `gefaelle.separator_breite`). Eine Ziel-Hoehe gibt es nicht. + +In `gefaellestrecke_tests.json` stehen `deltaL_mm`, `winkel_grad` und +`z_start_mm` in einem gemeinsamen Kopf-Eintrag ohne `test_id` und gelten fuer +alle Faelle der Datei. + +### 4.2 Modus 2 - Richtung aus zwei Punkten + +Wie Modus 1, aber `deltaL` und `hz` werden aus `linie_start_mm` -> +`linie_ende_mm` berechnet (nur X/Y). `start_mm` bleibt der Einfuegepunkt und +ist unabhaengig von der Linie. + +```json +{ "test_id": "M2_hz000", "modus": 2, "start_mm": [0, -35000, 5000], + "linie_start_mm": [0, -35000, 0], "linie_ende_mm": [10000, -35000, 0], + "as_seite": "links", "es_seite": "links", "as_winkel": "90", "es_winkel": "90" } +``` + +### 4.3 Modus 3 - Linienzug + +In der Produktion nicht skriptbar (`gf-linienzug-modus` waehlt vorgezeichnete +LINE/ARC-Objekte per Maus). `test_gefaellestrecke.lsp` zeichnet die Leitlinie +selbst und baut sie nicht-interaktiv nach. Zwei Formen: + +```json +{ "test_id": "M3_Bogen", "modus": 3, + "start_mm": [30000, -50000, 2000], "ende_mm": [38500, -43500, 1800], + "bogen": {"winkel_grad": 90, "radius_mm": 500, "seite": "links"}, + "as_seite": "links", "es_seite": "links", "as_winkel": "90", "es_winkel": "90" } +{ "test_id": "M3_hz270", "modus": 3, "richtung": "Sued", + "start_mm": [0, -50000, 5000], + "deltaH_quelle": "M2_hz000", "deltaL_quelle": "M2_hz000", ... } +``` + +`deltaH_quelle`/`deltaL_quelle` uebernehmen die Masse eines frueher gebauten +Falls. Dieses Format ist an den Treiber gebunden. Fuer neue Anlagen besser +eine VF-Linienzug-Spec (Abschnitt 5) mit `Linie-GF`/`GF-Bogen` verwenden. + +--- + +## 5. VF-Linienzug-Kette (Spec) + +Beliebige Ketten aus GF-Linien, GF-Boegen, Vario-Kurven und VF-Einheiten, +**ohne Dialog** gebaut (`VF_SPEC_BAU`, `TEST_HUNDM05`). Eine Kette = ein +Kopf-Objekt, danach ihre Glieder (`glied`) und deren Unterknoten (`sub`) in +Baureihenfolge. Ergebnis ist ein `VF_n`-Block mit vollem `SSG_VF_EDIT`-Journal +(per Doppelklick editierbar). + +```json +{ "spec_id": "VF_spec_LZ_01", "modus": 1, + "start_punkt": [4912.2, 1230.9, 2154.0], "start_hoehe": 2154.0, + "as": 1, "as_winkel": "90", "as_seite": "links" } +{ "glied": "Linie-GF", "nr": 1, "dl": 2249.3, "hz": 90.0, + "gefaelle": "winkel", "winkel": 3.0, "ende": "nein" } +{ "glied": "Horizontal-VF", "nr": 2, "dl": 3256.9, "gf_verteilung": "einlauf", + "vf_sep_vor": 0, "vf_sep_nach": 0, "vf_ende": "nein", "vf_separator": 0 } +{ "sub": "vario-kurve", "winkel": 90, "seite": "rechts", "variante": "innen" } +{ "sub": "motorstation" } +{ "glied": "ES", "winkel": "90", "seite": "links" } +``` + +**Kopf** + +| Feld | Bedeutung | +|---|---| +| `spec_id` | Kennung der Kette | +| `modus` | `1` (nur Modus 1 hat einen Uebersetzer) | +| `start_punkt` | `[x, y, z]` Kettenanfang (KS_EIN des AS-Elements bzw. erstes Glied) | +| `start_hoehe` | Einbauhoehe am Start | +| `as` | `1` = AS-Element setzen, `0` = nicht | +| `as_winkel` / `as_seite` | `"90"`/`"30"` bzw. `"links"`/`"rechts"` | + +**Glieder** (`glied`) + +| `glied` | wichtigste Felder | +|---|---| +| `Linie-GF` | `dl`, `hz` (nur beim ersten Glied der Kette), `laenge_modus` (`endpunkt`/`hoehe`/`steigend`), `ende` (`ja-mit-es`/`ja-ohne-es`/`nein`), `sep_vor`, `sep_nach`, `gefaelle` (`hoehe`/`winkel`) + `hoehe` bzw. `winkel` | +| `GF-Bogen` | `winkel` (30/60/90), `seite` | +| `Vario-Kurve` | als eigenes Glied (Kettenanfang) vom Uebersetzer noch NICHT unterstuetzt -> Spec-Fehler; Vario-Kurven als `sub` einer VF-Einheit angeben | +| `Horizontal-VF` | `dl`, `eingang_hoehe`, `gf_verteilung` (`haelfte`/`einlauf`), `vf_sep_vor`, `vf_sep_nach`, `vf_ende` (`ja-mit-es`/`nein`/`automatisch`/`zielpunkt-ohne-es`), `vf_separator` (nur bei `vf_ende` = `nein`) + `sub`-Knoten | +| `Linie-VF` | `dl`, `hoehe`, optional `winkel_idx` + `sub`-Knoten | +| `Linie` | `dl`, `hoehe`, `segment_typ` (`GF`/`VF`), optional `winkel_idx` | +| `ES` | `winkel` (`"90"`/`"30"`), `seite` | + +**Unterknoten einer VF-Einheit** (`sub`): `horizontal` (`sep_vor`, `sep_nach`), +`vario-kurve` (`winkel`, `seite`, `variante` `aussen`/`innen`), `auf-ab` +(`richtung` `auf`/`ab`, `hoehe`), `motorstation`, `kettenende` (`es`, +`es_winkel`, `es_seite`). + +Ja/Nein-Felder (`as`, `sep_vor`, `vf_sep_vor`, `es`, ...) als `1`/`0` oder +`"ja"`/`"nein"`; mehrwertige Felder (`ende`, `vf_ende`) nur mit den genannten +Woertern. Vollstaendige Regeln +(Menue-Codes je Frame, `hz` nur einmal, Verhalten bei `winkel_idx`): +[variofoerderer.md, Abschnitt 8b](variofoerderer.md#spec-pfad-kette-aus-eingabedaten-vf_spec_bau). +Die Spec wird nicht von Hand geschrieben, sondern mit +`python lib/vf_spec_export.py ` aus einer +aufgezeichneten Kette erzeugt. Fehlerhafte Specs werden komplett abgewiesen +(`vsp-pruefen` sammelt alle Fehler, gebaut wird dann nichts). + +**Andere Objekte in derselben Datei**: Neben den Ketten darf `hundm05.json` +Kreisel (Abschnitt 1) und Einzelbloecke (Abschnitt 2) enthalten. Erkennbar +sind sie an `function`; `vsp-gruppieren` ueberspringt sie, und +`hundm05:bau-zusatzobjekte` baut sie nach den Ketten. `vf_spec_export.py` +haengt sie beim Neuerzeugen unveraendert ans Dateiende. + +--- + +## 6. VF-Linienzug (Eingabe-Journal) + +Das Rohformat hinter der Spec: die Antworten auf die Fragen des interaktiven +Linienzug-Ablaufs, in Reihenfolge. Nur fuer Regressionstests gedacht - fuer +neue Anlagen die Spec (Abschnitt 5) verwenden. + +```json +{ "test_id": "VF_hundm05_LZ_01", "anlagetyp": "linienzug", "modus": 1, ... } +{ "typ": "point_abs", "wert": [4912.2, 1230.9, 2154.0], "kommentar": "Startpunkt" } +{ "typ": "real", "wert": 2154.0, "kommentar": "Hoehe (Z)" } +{ "typ": "string", "wert": "1", "kommentar": "AS-Element? Ja" } +{ "typ": "step", "wert": "Linie-GF", "kommentar": "Glied-Marker" } +{ "typ": "point_rel", "dL": 2249.3, "hz": 90.0, "kommentar": "Endpunkt" } +{ "typ": "int", "wert": 90, "kommentar": "Vario-Kurve Winkel" } +``` + +`typ`: `point_abs` (absoluter Punkt), `point_rel` (Abstand `dL` + Richtung +`hz`, `hz` nur beim ersten Segment), `real`, `int`, `string` (Menue-Code als +String), `step` (Glied-Marker, beim Replay uebersprungen). Kopf-Feld heisst +`anlagetyp`, nicht `typ`, damit Kopf und Eingabe unterscheidbar bleiben. + +| Datei | Treiber | +|---|---| +| `linienzug_tests.json`, `linienzug_tests_stufe2.json` | `TEST_LINIENZUG`, `TEST_LINIENZUG_STUFE2` | +| `hm_recformat.json` (5 echte HundM-Ketten, erzeugt mit `lib/vf_journal_export.py`) | `TEST_HM_RECFORMAT` (in `alltests.json` abgeschaltet) | + +--- + +## 7. Omniflo + +### 7.1 Bogen und Weiche + +```json +{ "id": "821104025", "type": "bogen", "sivasnr": "821104025", + "x": 219.4, "y": 223.06, "hoehe": 2000, "drehung": 0.0 } +``` + +| Feld | Pflicht | Bedeutung | Default | +|---|---|---|---| +| `type` | ja | `"bogen"` oder `"weiche"` | - | +| `sivasnr` | ja | Sivas-Nummer = Dateiname `%DXFM_OMNIFLO%/.dxf` | - | +| `x`, `y` | ja | Einfuegepunkt (`$INSBASE` der DXF, gesetzt mit `set_einfuegepkt.py`) | - | +| `hoehe` | nein | Z des Einfuegepunkts UND Attribut `HOEHE` | 2000 | +| `drehung` | nein | Drehung + Attribut `DREHUNG` | 0 | + +Es gibt kein `z`: die Hoehe ist zugleich die Z-Koordinate. Gueltige +Sivas-Nummern: `data/json/omniflo_boegen.json`, `omniflo_weichen.json`. +Treiber: `omni:test-insert` (`test_omniflo.lsp`), `omnistr:insert-bogen` +(`test_omniflo_strecke.lsp`). + +### 7.2 Aluprofil-Gerade + +```json +{ "seq": 1, "type": "gerade", "profil": "AP110", "laenge": 1000.0, + "x": 2000.0, "y": 0.0, "x_ende": 3000.0, "y_ende": 0.0, + "drehung": 0.0, "hoehe": 2000, "id": "0003" } +``` + +`profil` = `"AP60"`, `"AP110"` oder `"APG110"`. Die Gerade laeuft von +(`x`,`y`) nach (`x_ende`,`y_ende`) auf Z = `hoehe`; Laenge und Drehung folgen +aus den Punkten (`laenge` ist nur Doku). Gebaut mit `omni:make-gerade`. + +--- + +## 8. Waagrechte Foerderstrecke (`gerade`) - noch ohne Bau-Pfad + +```json +{ "test_id": "GERADE_Arvato_01", "typ": "gerade", "laenge": 8313.39, "hz": 90.0, + "startpunkt": [2334.97, 177818.67, 0.0], "endpunkt": [2334.96, 186132.06, 0.0] } +``` + +Ein Antriebs-/Umlenkstation-Paar ohne Hoehendifferenz, so von +`lib/dxf_scan_components.py` ausgegeben (ein VarioFoerderer ist bei +`deltaH` = 0 nicht loesbar). `TEST_DEMATIC_ARVATO` meldet diese Eintraege und +ueberspringt sie. Passende Primitive waere `insert-hz-scaled-block-by-ks` +(`vf_etage.lsp`) mit `Staustrecke_SP_1000_mm`, siehe +[lisp_methods.md](lisp_methods.md). + +--- + +## 9. Testdaten-Dateien im Ueberblick + +| Datei | Inhalt | Treiber / Befehl | +|---|---|---| +| `kreisel_tests.json` | 8 Kreisel (`insert`) | `TEST_KREISEL` | +| `foerderer_tests.json` | Kopf `y_abstand` + 17 VF Standard | `TEST_FOERDERER` | +| `gefaellestrecke_tests.json` | Kopf + GF Modus 1/2/3 | `TEST_GEFAELLESTRECKE` | +| `omniflo_tests.json` | 27 Boegen, 80 Weichen | `TEST_OMNIFLO` | +| `omniflo_strecke_tests.json` | Streckenzug aus Geraden und Boegen | `TEST_OMNIFLO_STRECKE` | +| `linienzug_tests.json` / `_stufe2.json` | Eingabe-Journal je einer Kette | `TEST_LINIENZUG` / `TEST_LINIENZUG_STUFE2` | +| `hm_recformat.json` | 5 HundM-Ketten als Journal | `TEST_HM_RECFORMAT` | +| `hundm05.json` | 5 HundM-Ketten als Spec + Kreisel, Separatoren, Scanner, BTMT | `TEST_HUNDM05`, `VF_SPEC_BAU` | +| `mubea.json` | Gesamtanlage: Kreisel, VF Standard/Etage, GF-Template (20 Stueck), Separatoren, Scanner, BTMT, Eingang/Ausgang | `TEST_MUBEA` | +| `dematic_arvato.json` | Vorlage aus `dxf_scan_components.py`: Kreisel, Einzelbloecke, `gerade` (Hoehen fehlen) | `TEST_DEMATIC_ARVATO` (abgeschaltet) | +| `hundm05_linienzug_polylines.json` | Polylinien aus `extract_polylines.py` | kein Treiber (Analyse-Daten) | +| `vfl_journal_hm05_abbruch.json` | rohes Journal (`kind`/`value`) eines abgebrochenen Baus | kein Treiber | + +--- + +## 10. Eigene Anlage beschreiben - Kurzanleitung + +1. Kreisel als `insert` (Abschnitt 1): `x/y` am aeussersten Punkt der AN-Seite, + `z` = Einbauhoehe. +2. Einfache Steig-/Fall-Strecken mit fester Form als VF Standard/Etage + (Abschnitt 3) bzw. Gefaellestrecke Modus 1 (Abschnitt 4.1), Startpunkt + jeweils = KS_EIN des AS-Elements. +3. Ketten mit Kurven, mehreren VF-Einheiten oder GF-Boegen als Spec + (Abschnitt 5) - am einfachsten eine Kette einmal interaktiv bauen, mit + `lib/vf_journal_export.py` + `lib/vf_spec_export.py` als Spec exportieren + und Startpunkt/Laengen anpassen. +4. Separatoren, Scanner, BTMT-Stationen, Eingang/Ausgang als Einzelblock + (Abschnitt 2). +5. Aus Kreisel, Einzelbloecken und Specs gemischt baut derzeit nur der + HundM05-Treiber (`TEST_HUNDM05`); fuer VF Standard/Etage + GF zusammen mit + Kreiseln den Mubea-Treiber (`TEST_MUBEA`) als Vorlage nehmen. diff --git a/doc/lisp_methods.md b/doc/lisp_methods.md new file mode 100644 index 0000000..11d78d7 --- /dev/null +++ b/doc/lisp_methods.md @@ -0,0 +1,328 @@ +# LISP-Routinen zum Bau einzelner Einheiten + +Uebersicht ueber die LISP-Funktionen, die eine Einheit (Kreisel, Eckrad, +VarioFoerderer, Gefaellestrecke, Omniflo-Element, Geruest, Einzelblock) +erzeugen, mit Signatur, Parametern, Rueckgabe und Voraussetzungen. + +Zu jedem Element steht der interaktive **Befehl** (was der Anwender aufruft) +und der **skriptfaehige Kern** (ohne `getpoint`/Dialog, aus Code oder JSON +aufrufbar). Das JSON-Format, mit dem die Testtreiber diese Kerne aufrufen, +steht in [json-input-lisp.md](json-input-lisp.md); alle Befehle in +[kommandos.md](kommandos.md). + +Einheiten: mm und Grad. `hz` = Fahrtrichtung in der XY-Ebene, 0 = +X, +90 = +Y. Punkte sind Listen `(x y z)` in Weltkoordinaten. + +--- + +## 0. Uebersicht + +| Einheit | Befehl | Skriptfaehiger Kern | Ergebnis-Block | Modul | +|---|---|---|---|---| +| Kreisel | `KreiselInsert`, `KreiselConnect`, `KreiselQuick` | `kreisel-insert-script`, `kreisel-connect-script` | `KREISEL_n` | `KreiselInsert.lsp` | +| Eckrad | `ILS_Eckrad` | `ils-eckrad-insert` | `ECKRAD_n` | `KreiselInsert.lsp` | +| VF Standard | `StandardVarioFoerderer`, `FOERDERANLAGE` | `berechne-standard` + `variofoerderer-einfuegen` + `vf-block-erstellen` | `VF_n` | `vf_standard.lsp`, `vf_core.lsp` | +| VF Etage | `EtageVarioFoerderer` | `berechne-etage` + `etage-foerderanlage-einfuegen` + `vf-block-erstellen` | `VF_n` | `vf_etage.lsp`, `vf_core.lsp` | +| VF Linienzug | `LinienzugVarioFoerderer` | `vsp-bau-aus-spec` (Spec) bzw. `vfl-journal-replay-start` + `vf-linienzug-modus` | `VF_n` | `vf_linienzug.lsp`, `vf_spec.lsp` | +| Gefaellestrecke | `GEFAELLESTRECKE_EINFACH`/`_3DLINIE` | `gf-rebuild` bzw. `gefaellestrecke-einfuegen` | `GF_n` | `Gefaellestrecke.lsp` | +| Gefaellestrecke Linienzug | `GEFAELLESTRECKE_LINIENZUG` | - (nur interaktiv; Kern `gf-linienzug-einfuegen` braucht analysierte Segmente) | `GF_n` | `Gefaellestrecke.lsp` | +| Separator, Scanner | `ILS_SEPARATOR_INSERT`, `ILS_SCANNER_INSERT` | - (Schleife mit `getpoint`); Kern: `ssg-ils-block-laden` + `_.INSERT` | Einzelblock | `SSG_LIB_Commands.lsp`, `ssg_core.lsp` | +| BTMT, Eingang/Ausgang | `ILS_BTMT_*`, `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` | wie Separator | Einzelblock | `SSG_LIB_Commands.lsp` | +| Omniflo Bogen/Weiche/TEF | `OMNI_APB_*`, `OMNI_W*_*`, `OMNI_TEF_*` ... | `_.INSERT` der `.dxf` (Kern `omni:insert-dxf` fragt den Punkt) | Einzelblock | `OmniModulInsert.lsp` | +| Omniflo Gerade | `OMNI_AP60`/`AP110`/`APG110` | `omni:make-gerade` | Compound-Block | `OmniModulInsert.lsp` | +| TEF-Foerderer-Linie | `TEF_FOERDERER_LINIE` | `tefl-insert-element` (ein Element) | Einzelbloecke | `TEFInsert.lsp` | +| Geruest (Saeule, Rohrabhaenger, Wandbefestigung) | `GERUEST`, `GERUEST_SAEULEN` ... | `geruest-block-bauen` | `GR__` | `GeruestInsert.lsp` | +| Geruest-Traeger | `GERUEST_TRAEGER` | `geruest-traeger-block-bauen` | `GR__` | `GeruestInsert.lsp` | + +--- + +## 1. Kreisel und Eckrad (`KreiselInsert.lsp`) + +### `kreisel-insert-script (pt abstand rotation typ hoehe)` + +Kreisel an einem freien Punkt. Ruft `draw-module` auf. + +| Parameter | Bedeutung | +|---|---| +| `pt` | Einfuegepunkt: aeusserster Punkt der AN-Seite auf der Achse (einen Radius = 400 mm vor der Mitte des Antriebsrads) | +| `abstand` | Mittenabstand Antriebsrad - Spannrad | +| `rotation` | Drehung der Achse AN -> SP in Grad | +| `typ` | `"STANDARD"` oder `"PIN"` (nil = `"STANDARD"`) -> Attribut `KREISELART` | +| `hoehe` | Einbauhoehe; nil = Z von `pt`, sonst `*kreisel-default-hoehe*` | + +Rueckgabe: Entity des `KREISEL_n`-Blocks oder nil. Setzt `ssg-start`/`ssg-end` +selbst. + +### `kreisel-connect-script (ptStart ptEnd typ hoehe)` + +Kreisel zwischen zwei aeussersten Punkten (AN-Seite, SP-Seite). Berechnet +`abstand` = Distanz - `*kreisel-durchmesser*` (800) und `rotation` aus den +Punkten. Rueckgabe wie oben. + +### `draw-module (basePoint abstand rotation attribs)` + +Gemeinsamer Bau-Kern beider Funktionen: setzt Antriebs- und Spannstation, +Tangenten, Beschriftung, fasst alles zu `KREISEL_n` zusammen, schreibt die +Attribute (`attribs` = Alist, wird mit `*kreisel-attrib-defs*` gemischt). +Direkt nur aufrufen, wenn zusaetzliche Attribute gesetzt werden muessen. + +### `ils-eckrad-insert (pt rotation attribs)` + +Eckrad als Compound-Block `ECKRAD_n`. + +| Parameter | Bedeutung | +|---|---| +| `pt` | **Radmitte** `(x y hoehe)` | +| `rotation` | Drehung in Grad | +| `attribs` | Alist mit Ueberschreibungen, z.B. `(("GERUEST_EINZELMODUL" . "1") ("GERUEST_TYP" . "Schoenenberger Geruest"))`; nil = Defaults | + +`c:ILS_Eckrad` berechnet die Radmitte aus Beruehrpunkt + Radius in Richtung +des zweiten Klicks. Rueckgabe: Entity des Blocks. + +--- + +## 2. VarioFoerderer Standard und Etage (`vf_core.lsp`, `vf_standard.lsp`, `vf_etage.lsp`) + +Ablauf in drei Schritten: **loesen** (Winkel und Teillaengen aus den +Gesamtmassen), **einfuegen** (Bausteine verketten), **Block bilden** +(`VF_n` mit Attributen). Der Dialog-Ablauf `vf-dialog-ablauf` / +`vf-dialog-berechnen-einfuegen` macht dasselbe, oeffnet aber Dialog 2 und ist +darum nicht skriptfaehig. + +### Vorbereitung + +| Funktion | Zweck | +|---|---| +| `init-bibliothek ()` | Bogen-, AS-/ES- und Stationsmasse aus den Bloecken lesen. Setzt `*lib-initialized*`. Wird von `berechne-standard` aufgerufen | +| `init-bibliothek-etage ()` | dasselbe fuer Etage, aufgerufen von `berechne-etage` | +| `vf-set-as-masse (winkel seite)` / `vf-set-es-masse (winkel seite)` | AS-/ES-Masse (`aus-dx`/`aus-dz`, `ein-dx`/`ein-dz`) fuer die Variante `"90"`/`"30"` + `"links"`/`"rechts"` setzen | + +### Loesen + +| Funktion | Rueckgabe | +|---|---| +| `berechne-standard (deltaL deltaH richtung seite)` | `(best-winkel L_GF L_VF ergebnis-liste)` | +| `berechne-alle-winkel (deltaL deltaH richtung feste-hz schon-flach)` | wie oben; `feste-hz` nil = 1600 mm feste Horizontale, `schon-flach` nil | +| `berechne-etage (deltaL deltaH richtung seite)` | wie oben, Etage-Geometrie (setzt die Gefaellebogen-Masse je `seite`) | +| `vf-winkel-solve (...)` | gemeinsamer L_GF/L_VF-Solve beider Typen (intern) | + +- `richtung` = `"Auf"`/`"Ab"`, `deltaH` als Betrag. +- `ergebnis-liste` = je Kandidatenwinkel `(winkel L_GF L_VF gueltig)`. + Kandidaten aus `vario.bogen_winkel` (3 ... 51). Einen bestimmten Winkel + erzwingen: Eintrag mit diesem `winkel` aus der Liste nehmen und + `gueltig`, `L_GF` > 0, `L_VF` > 0 pruefen (so `mubea:build-vario-one`). +- `L_GF` wird danach auf Vorlauf `L_GF1` und Nachlauf `L_GF2` aufgeteilt + (gleichmaessig / vorne / hinten / manuell, `foerderer:split-gf`). + +### Einfuegen + +``` +(variofoerderer-einfuegen deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz) +(etage-foerderanlage-einfuegen deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz) +``` + +Identische Signatur (Registry-Vertrag `*vf-typ-registry*`). `startpunkt` = +Lage von **KS_EIN des AS-Elements**, Z = Einbauhoehe am Anfang. `seite` = +`"links"`/`"rechts"`. Rueckgabe: Endpunkt (KS_AUS des ES-Elements). +`variofoerderer-einfuegen` ist aus Teilen zusammengesetzt (`vfs-as-teil`, +VF-Eingang/Koerper, `vfs-es-teil`), die auch der Linienzug nutzt. + +### Block bilden + +``` +(setq lastEnt (ssg-lastent-ohne-attribute)) ; VOR dem Einfuegen merken +...einfuegen... +(vf-block-erstellen anlage-typ seite (vf-next-number) n-scanner + hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2 + richtung best-winkel startpunkt lastEnt hz + geruest-einzelmodul geruest-typ) +(vf-edit-xdata-schreiben ent anlage-typ hz) ; editierbar per Doppelklick +``` + +- `anlage-typ` = `"standard"`/`"etage"`; `hoehe-bis` = +deltaH bei `"Auf"`, + -deltaH bei `"Ab"`; `geruest-einzelmodul` `"0"`/`"1"` (nil = `"1"`), + `geruest-typ` einer aus `*ssg-geruest-optionen*`. +- Sammelt alle Objekte seit `lastEnt` zum Block `VF_n`, setzt Layer, Attribute, + ID (`ssg-id-generate`) und Dimension. Rueckgabe: Entity des Blocks. +- `lastEnt` immer mit `ssg-lastent-ohne-attribute` holen, nicht mit + `(entlast)` (siehe `CLAUDE.md`, ssg_core). +- Blocknummer immer ueber `vf-next-number`: eine feste Nummer fuehrt bei der + zweiten Anlage zu einer Rueckfrage von `_.-BLOCK` und einem haengenden Befehl. + +--- + +## 3. VF-Linienzug (`vf_linienzug.lsp`, `vf_spec.lsp`) + +Ketten mit Vario-Kurven, GF-Boegen und mehreren VF-Einheiten. Der Bau-Ablauf +ist ein Frage-Antwort-Assistent; jede Eingabe wird journalisiert und als XDATA +am `VF_n`-Block gespeichert. Nicht-interaktiv baut man ihn, indem man ein +Journal **abspielt**. + +| Funktion | Zweck | +|---|---| +| `vf-linienzug-modus ()` | Modus 1, frei zeichnend. Liest alle Eingaben ueber `vfl-in-point`/`-string`/`-real`/`-int` - aus der Replay-Queue, falls eine aktiv ist | +| `vf-linienzug-modus2 ()` | Modus 2, Pfad + Zielhoehe (Objektauswahl, eigenes Journal `"linienzug2"`) | +| `vfl-journal-replay-start (forward-journal)` | Journal als Antwort-Queue setzen; danach `vf-linienzug-modus` aufrufen | +| `vsp-journal (spec)` | Spec -> Journal (nil bei Spec-Fehlern, Fehler in `*vsp-fehler*`) | +| `vsp-pruefen (spec)` | alle Spec-Fehler sammeln | +| `vsp-bau-aus-spec (spec)` | eine Kette aus einer Spec bauen (headless, Replay, Ergebnis-Record mit `status`, Block, `prompts`, `glieder_soll`/`glieder_ist`) | +| `vsp-bau-liste (specs)` | mehrere Specs, je mit `vl-catch-all-apply` | +| `vsp-bau-datei (datei)` | Spec-Datei lesen (`vsp-json-laden` + `vsp-gruppieren`) und alle Ketten bauen; das ist `VF_SPEC_BAU` | +| `vsp-headless-an ()` / `vsp-headless-aus ()` | Headless-Rahmen: `*vfl-headless*`, Wizard aus, `*ssg-gui-aus*`, zaehlende Eingabe-Stubs | + +Ein Abbruch im Headless-Modus nennt die Stelle (`*vfl-headless-fehler*`), +statt auf eine Live-Eingabe zu warten. Details zum Ablauf und zu den +Journal-Regeln: [variofoerderer.md](variofoerderer.md), Abschnitte 5-8b. + +--- + +## 4. Gefaellestrecke (`Gefaellestrecke.lsp`) + +### `gf-rebuild (deltaL winkel hz-winkel as-seite es-seite startpunkt as-winkel es-winkel geruest-einzelmodul geruest-typ)` + +Der bequemste skriptfaehige Einstieg fuer Modus 1/2: setzt die AS-/ES-Masse, +berechnet die Staustrecke +`L_stau = (deltaL - aus-dx - ein-dx - separator_breite * cos(w)) / cos(w)` +und ruft `gefaellestrecke-einfuegen`. Ohne Zusammenfassung und Rueckfrage +(eigentlich fuer `GEFAELLESTRECKE_EDIT` gedacht). + +| Parameter | Bedeutung | +|---|---| +| `deltaL` | horizontale Gesamtlaenge AS + Staustrecke + Separator + ES | +| `winkel` | Neigung der Staustrecke in Grad (Default im Dialog 3.0) | +| `hz-winkel` | Fahrtrichtung | +| `as-seite`, `es-seite` | `"links"`/`"rechts"` | +| `startpunkt` | **KS_EIN des AS-Elements**, Z = Einbauhoehe oben | +| `as-winkel`, `es-winkel` | `"90"`/`"30"` als STRING (nil = `"90"`) | +| `geruest-einzelmodul`, `geruest-typ` | wie beim VF | + +Rueckgabe: `(ename deltaH deltaL)` oder nil (Staustrecke <= 0.1 mm -> `alert`). + +### `gefaellestrecke-einfuegen (L_stau winkel startpunkt as-seite es-seite hz deltaL-total as-winkel es-winkel geruest-einzelmodul geruest-typ)` + +Eigentlicher Bau: AS-Element, skalierte Staustrecke, Separator, ES-Element, +Block `GF_n` mit Attributen, XDATA `SSG_GF_EDIT` und ID. Erwartet die +fertige Staustreckenlaenge `L_stau` und passend gesetzte AS-/ES-Masse +(`vf-set-as-masse`/`vf-set-es-masse`). Rueckgabe wie `gf-rebuild`. + +### Weitere + +| Funktion | Zweck | +|---|---| +| `gf-modus12-abschluss (... dialog-bestaetigt ...)` | Abschluss Modus 1/2 mit Zusammenfassung; fragt ohne `dialog-bestaetigt` = T per Konsole nach | +| `gf-init-bibliothek ()` | AS-/ES-Masse fuer die GF lesen | +| `gf-linienzug-modus ()` | Modus 3, interaktiv (Auswahl vorhandener LINE/ARC) | +| `gf-linienzug-einfuegen (segmente grade startframe)` | Bau-Kern von Modus 3, erwartet die von `gf-analysiere-kette` aufbereiteten Segmente | + +**Falle `*lib-initialized*`**: `gefaellestrecke-einfuegen` initialisiert die +GF-Masse nur, wenn `*lib-initialized*` nil ist - dasselbe Flag setzt +`init-bibliothek` des VarioFoerderers. Wer in einem Lauf erst VF und dann GF +baut, muss `gf-init-bibliothek` einmal selbst erzwingen (so +`mubea:ensure-gf-init` in `tests/test_mubea.lsp`), sonst rechnet die GF mit +den Vario-Massen und landet auf falscher Hoehe. + +--- + +## 5. Einzelbloecke: Separator, Scanner, BTMT, Eingang/Ausgang + +| Funktion | Zweck | +|---|---| +| `ils-insert-sensor (fname)` | Befehls-Kern Separator/Scanner: fuegt in einer Schleife ein, Punkt per `getpoint`, Drehung per `pause` - **nicht skriptfaehig** | +| `ils-insert-station (rohname)` | dasselbe fuer BTMT-Beladung, SC_Entladung, Eingang, Ausgang; setzt zusaetzlich den Layer aus dem `LAYER`-Attribut | +| `ssg-ils-block-laden (blockname)` | Blockdefinition `data/ils/_.dwg` einmal je Zeichnung laden; Rueckgabe: effektiver Blockname mit Suffix oder nil | +| `ssg-ils-block-datei (blockname)` | nur den Dateipfad aufloesen (3D-Fallback) | +| `ssg-block-layer-vorgabe` | `LAYER`-Attribut eines eingefuegten Blocks als Ziel-Layer anwenden | +| `ssg-id-generate (ent)` | eindeutige `ID` vergeben (nur wenn der Block ein ID-Attribut hat) | + +Skriptfaehig bauen (Muster aus `hundm05:bau-sensor`): + +```lisp +(setq eff (ssg-ils-block-laden "Scanner")) ; nicht per (and ...) verketten! +(command "_.INSERT" eff (list x y z) "" "" rotation) +(while (and (> (getvar "CMDACTIVE") 0) (< n 5)) (command "") (setq n (1+ n))) +(ssg-id-generate (entlast)) +``` + +`ATTREQ`/`ATTDIA` vorher auf 0 setzen. Restliche Prompts gezaehlt mit Enter +beantworten, nicht ungebremst: eine Rueckfrage, die Enter ablehnt, haelt +`CMDACTIVE` sonst dauerhaft > 0. + +--- + +## 6. Omniflo (`OmniModulInsert.lsp`) + +| Funktion | Zweck | +|---|---| +| `omni:insert-dxf (sivasnr-str hoehe drehung)` | `%DXFM_OMNIFLO%/.dxf` einfuegen, `HOEHE`/`DREHUNG` setzen, Layer. **Einfuegepunkt per Maus** (`pause`); Rueckgabe: Einfuegepunkt oder nil | +| `omni:insert-from-entry (dlg-result)` | Dialog-Ergebnis von Bogen/Weiche -> `omni:insert-dxf` | +| `omni:make-gerade (blockname pt pt2 srcAttribs textHeight textGap textEnt)` | **skriptfaehig**: Aluprofil-Gerade `"AP60"`/`"AP110"`/`"APG110"` von `pt` nach `pt2` als Compound-Block mit Text. `srcAttribs` per `omni:read-src-attribs`, `textEnt` nil. Kein `ssg-start` - Aufrufer setzt OSMODE/ATTREQ/ATTDIA = 0. Rueckgabe: Entity | +| `omni:insert-block (blockname laengemax)` | Befehls-Kern der Geraden (fragt `pt`/`pt2` per `getpoint`) | +| `omni:ladeschleifen-dialog (profiltyp init-hoehe)` | Dialog Ladeschleife, danach `omni:insert-dxf` | + +Skriptfaehig fuer Boegen/Weichen: `_.INSERT` der DXF direkt mit Punkt +`(x y hoehe)` und Drehung, danach `ssg-attrib-set-on` mit `HOEHE`/`DREHUNG` +(`omni:test-insert` in `tests/test_omniflo.lsp`). Die festen TEF-/Zubehoer- +Befehle (`OMNI_TEF_*`, `OMNI_STOPPER` ...) rufen `omni:insert-dxf` mit fester +Sivas-Nummer. `OMNI_TV_*` und `OMNI_APBW_*` sind Platzhalter ohne Bau-Logik. + +--- + +## 7. TEF-Foerderer-Linie (`TEFInsert.lsp`) + +| Funktion | Zweck | +|---|---| +| `c:TEF_FOERDERER_LINIE` | Start-/Endpunkt abfragen, Linie zeichnen, 1000-mm-TEF-Geraden (`0_B10030.dxf`) aneinanderreihen; das letzte Stueck wird zurueckversetzt, damit der Foerderer genau am Linienende endet | +| `tefl-insert-element (start richtung-einheit s hz winkel)` | ein Element an Position `s` (mm ab `start`) entlang der Linie, Rz(hz)*Ry(winkel) | +| `tefl-ensure-block-loaded (dxf-pfad)` | Blockdefinition einmal laden | + +--- + +## 8. Geruest (`GeruestInsert.lsp`) + +| Funktion | Zweck | +|---|---| +| `geruest-einfuegen (bg wahl)` | Befehls-Kern Saeulen/Rohrabhaenger/Wandbefestigung: baut aus der Dialog-Auswahl `wahl` = `(variante-index oben unten laenge farbe)` die Werte (ARTINR, BEZEICHNUNG, TEILEART, LAENGE, TEILEFARBE), fragt dann den Punkt per `getpoint` | +| `geruest-block-bauen (bg variante werte pt teile-dwgs)` | **skriptfaehiger Kern**: Dummy-DWG + Teile-DWGs bei `pt`, Block `GR__`. `bg` = Baugruppe aus `geruest.json`, `werte` = Attribut-Alist, `teile-dwgs` aus `geruest-teile-dwgs` | +| `geruest-traeger-einfuegen (bg wahl)` | Befehls-Kern Traeger: Schleife Startpunkt -> Endpunkt oder Laenge | +| `geruest-traeger-block-bauen (bg layer netto strebe strebe-pfad muffe-pfad werte pt winkel)` | **skriptfaehiger Kern** Traeger: LINE (0,0,0)-(netto,0,0), Streben, Muffe, Block bei `pt` mit `winkel` (Radiant). Rueckgabe: `(blockname . entity)` | +| `geruest-traeger-laenge`, `-start`, `-streben`, `-pruefen` | reine Berechnung (Netto-Laenge nach Abzuegen, Startpunkt, Strebenverteilung, min/max) - in `tests/test_unit.lsp` getestet | +| `geruest-traeger-beschriften (blockEnt)` | Beschriftungstext aus dem fertigen Block | +| `geruest-block-abschliessen (bg attribs werte lastEnt pt rot)` | gemeinsamer Schluss aller Geruest-Bloecke (ATTDEFs, Block bilden, einfuegen, ID) | + +Fuer Geruest gibt es noch keinen JSON-Treiber. + +--- + +## 9. Einfuegeprimitiven (`ssg_ks_insert.lsp`, `vf_etage.lsp`) + +Grundbausteine, auf denen VF, GF und Linienzug aufsetzen. Alle legen **KS_EIN** +des Blocks (nicht den Block-Ursprung) auf den Startpunkt und geben den +Weltpunkt von **KS_AUS** zurueck - damit lassen sich Bausteine verketten. + +| Funktion | Zweck | +|---|---| +| `ensure-block-loaded (name)` | Block einmal ins Dokument laden | +| `extract-ks-from-block (block-obj)` | KS_EIN/KS_AUS eines eingefuegten Blocks (VLA-Objekt) lesen, Cache `*ks-cache*` je Blockname | +| `insert-block-by-ks (blockname einfuegepunkt hz)` | Block nur um Z gedreht (AS/ES-Elemente, Stationen) | +| `insert-inclined-scaled-block (blockname startpunkt laenge winkel hz)` | Block in X auf `laenge` skaliert und um `winkel` geneigt, Rz(hz)*Ry(winkel) (Staustrecken) | +| `insert-rotated-block-with-ks (blockname startpunkt winkel block-dx block-dz hz)` | Block gedreht, `block-dx`/`block-dz` nur als Fallback ohne KS_AUS (Boegen) | +| `insert-hz-scaled-block-by-ks (blockname startpunkt laenge hz-winkel vert-winkel)` | waagrechter, auf `laenge` skalierter Block (`Staustrecke_SP_1000_mm`, Massstab `laenge/1000`); Kandidat fuer die noch fehlende waagrechte Foerderstrecke. Bricht bei fehlender Blockdatei mit `(exit)` ab - vorher mit `ssg-ils-block-laden` pruefen | +| `ssg-rot-matrix-zy (chz shz cv sv)` | 4x4-Rotationsmatrix Rz(hz)*Ry(vert) aus Cosinus/Sinus beider Winkel (`ssg_core.lsp`) | + +--- + +## 10. Gemeinsame Regeln fuer eigene Treiber + +- Systemvariablen ueber `ssg-start`/`ssg-end` sichern; `OSMODE` 0, + `ATTREQ` 0, `ATTDIA` 0 setzen, sonst fragt `_.INSERT` nach Attributen. +- Module vorher laden: `(ssg-ensure "KreiselInsert")`, `"VarioFoerderer"`, + `"Gefaellestrecke"`, `"SSG_LIB_Commands"`. +- Die Dimension folgt `ssg-ils-dim-aktuell`; fuer einen festen Lauf + `*ssg-ils-dim*` (bzw. `*vsp-dim-override*` beim Spec-Bau) setzen und danach + zuruecksetzen. +- Rueckgaben nicht mit `and`/`or` verketten - die liefern in AutoLISP nur + T/nil (siehe `CLAUDE.md`, Konventionen). +- Interaktive GUI abschalten: `ssg-gui-aus` bzw. `vsp-headless-an`. +- Vorbilder: `tests/test_mubea.lsp` (Kreisel, VF Standard/Etage, GF, + Einzelbloecke), `tests/test_hundm05.lsp` (Spec-Ketten, Kreisel, + Einzelbloecke), `tests/test_omniflo_strecke.lsp` (Omniflo). From 7290a1360789097500a2bb868275056b82e18d9f Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Tue, 6 Oct 2026 11:17:28 +0200 Subject: [PATCH 03/38] Doku erste Fassung erstellt --- doc/faq.md | 298 +++++++++++++++++++++++++---- doc/images/Kreisel-attribute.png | Bin 0 -> 15531 bytes doc/images/Kreisel-mit-gui.png | Bin 0 -> 19821 bytes doc/images/gefaellestrecke-gui.png | Bin 0 -> 23203 bytes doc/images/gefaellestrecke.png | Bin 0 -> 8729 bytes doc/images/variofoerderer.png | Bin 0 -> 9124 bytes doc/images/vf-gui1.png | Bin 0 -> 13327 bytes doc/images/vf-gui2.png | Bin 0 -> 7157 bytes 8 files changed, 258 insertions(+), 40 deletions(-) create mode 100644 doc/images/Kreisel-attribute.png create mode 100644 doc/images/Kreisel-mit-gui.png create mode 100644 doc/images/gefaellestrecke-gui.png create mode 100644 doc/images/gefaellestrecke.png create mode 100644 doc/images/variofoerderer.png create mode 100644 doc/images/vf-gui1.png create mode 100644 doc/images/vf-gui2.png diff --git a/doc/faq.md b/doc/faq.md index aa0cbcc..cad3670 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -1,85 +1,303 @@ # FAQ - Dokumentation +- [FAQ - Dokumentation](#faq---dokumentation) + - [Allgemein](#allgemein) + - [Darf ich Baugruppen kopieren?](#darf-ich-baugruppen-kopieren) + - [Darf ich Baugruppen auflösen?](#darf-ich-baugruppen-auflösen) + - [Darf ich Attribute in den Baugruppen manuell ändern?](#darf-ich-attribute-in-den-baugruppen-manuell-ändern) + - [Darf ich Baugruppen mustern?](#darf-ich-baugruppen-mustern) + - [1. Kreisel](#1-kreisel) + - [1.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#11-zusammensetzung-abhängigkeiten-randbedingungen) + - [Zusammensetzung einer Kreiselbaugruppe](#zusammensetzung-einer-kreiselbaugruppe) + - [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem) + - [Höhe (Laufprofil und Unterkante)](#höhe-laufprofil-und-unterkante) + - [1.2 Funktionen](#12-funktionen) + - [Wie füge ich einen Kreisel ein?](#wie-füge-ich-einen-kreisel-ein) + - [Wie drehe ich einen Kreisel?](#wie-drehe-ich-einen-kreisel) + - [Wie ändere ich die Höhe eines Kreisels?](#wie-ändere-ich-die-höhe-eines-kreisels) + - [Wie ändere ich die Länge eines Kreisels?](#wie-ändere-ich-die-länge-eines-kreisels) + - [2. Gefällestrecke](#2-gefällestrecke) + - [2.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#21-zusammensetzung-abhängigkeiten-randbedingungen) + - [Zusammensetzung einer Gefällestrecke](#zusammensetzung-einer-gefällestrecke) + - [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem-1) + - [Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP \<-\> Oberkante LP)](#höhe-und-übergang-zu-kreiselkoordinatensystem-unterkante-sp---oberkante-lp) + - [2.2 Funktionen](#22-funktionen) + - [Wie füge ich eine Gefällestrecke ein?](#wie-füge-ich-eine-gefällestrecke-ein) + - [Wie drehe ich eine Gefällestrecke?](#wie-drehe-ich-eine-gefällestrecke) + - [Wie ändere ich die Länge einer Gefällestrecke?](#wie-ändere-ich-die-länge-einer-gefällestrecke) + - [Wie baue ich eine Gefällestrecke mit einer bestimmten Kapazität als Puffer (freie Länge des Stauprofils)](#wie-baue-ich-eine-gefällestrecke-mit-einer-bestimmten-kapazität-als-puffer-freie-länge-des-stauprofils) + - [Wie baue ich eine Gefällestrecke zwischen zwei Kreiseln mit definiertem Abstand?](#wie-baue-ich-eine-gefällestrecke-zwischen-zwei-kreiseln-mit-definiertem-abstand) + - [Wie baue ich eine Gefällestrecke mit Kurven als Übergang zwischen zwei Kreiseln mit unterschiedlicher Höhe?](#wie-baue-ich-eine-gefällestrecke-mit-kurven-als-übergang-zwischen-zwei-kreiseln-mit-unterschiedlicher-höhe) + - [Wie baue ich eine Gefällestrecke mit manueller Höhenüberwindung ohne VF (QS-Platz Mubea)](#wie-baue-ich-eine-gefällestrecke-mit-manueller-höhenüberwindung-ohne-vf-qs-platz-mubea) + - [3. Varioförderer](#3-varioförderer) + - [3.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#31-zusammensetzung-abhängigkeiten-randbedingungen) + - [Zusammensetzung eines Varioförderer mit allen möglichen Komponenten](#zusammensetzung-eines-varioförderer-mit-allen-möglichen-komponenten) + - [Verfügbare Steigungen](#verfügbare-steigungen) + - [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem-2) + - [Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP \<-\> Oberkante LP)](#höhe-und-übergang-zu-kreiselkoordinatensystem-unterkante-sp---oberkante-lp-1) + - [3.2 Funktionen](#32-funktionen) + - [Welche Einfügemodi gibt es und wie unterscheiden sich diese?](#welche-einfügemodi-gibt-es-und-wie-unterscheiden-sich-diese) + - [Wie baue ich einen VF in einem Puffer mit Gefällestrecken als Umschleusung?](#wie-baue-ich-einen-vf-in-einem-puffer-mit-gefällestrecken-als-umschleusung) + - [Wie baue ich einen VF zur Anfahrung einer bestimmten Höhe (Arbeitsplatz)?](#wie-baue-ich-einen-vf-zur-anfahrung-einer-bestimmten-höhe-arbeitsplatz) + - [Wie baue ich einen VF als Übergang zwischen zwei verschiedenen Kreiseln (unterschiedliche Höhe und Position x/y/z)](#wie-baue-ich-einen-vf-als-übergang-zwischen-zwei-verschiedenen-kreiseln-unterschiedliche-höhe-und-position-xyz) + - [Wie baue ich einen Förderer zu Ebenenüberquerung zwischen zwei Pufferblöcken, welche übereinander positioniert sind?](#wie-baue-ich-einen-förderer-zu-ebenenüberquerung-zwischen-zwei-pufferblöcken-welche-übereinander-positioniert-sind) + - [Wie baue ich eine Strecke mit mehreren VF und Gefällestrecken hintereinander zur Überbrückung von großen Entfernungen?](#wie-baue-ich-eine-strecke-mit-mehreren-vf-und-gefällestrecken-hintereinander-zur-überbrückung-von-großen-entfernungen) + - [4. Scanner und Separator](#4-scanner-und-separator) + - [4.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#41-zusammensetzung-abhängigkeiten-randbedingungen) + - [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem-3) + - [In welchen Baugruppen sind Scanner und Separatoren bereits eingebaut (Blöcke)?](#in-welchen-baugruppen-sind-scanner-und-separatoren-bereits-eingebaut-blöcke) + - [Zuordnung der frei platzierten Scanner und Separatoren zu einem Kreisel, Gefällestrecke oder VF](#zuordnung-der-frei-platzierten-scanner-und-separatoren-zu-einem-kreisel-gefällestrecke-oder-vf) + - [4.2 Funktionen](#42-funktionen) + - [Wie füge ich einen Scanner ein?](#wie-füge-ich-einen-scanner-ein) + - [Wie füge ich einen Separator ein?](#wie-füge-ich-einen-separator-ein) + - [5. Be- und Entladung](#5-be--und-entladung) + - [5.1 Zusammensetzung, Abhängigkeiten, Randbedingungen](#51-zusammensetzung-abhängigkeiten-randbedingungen) + - [Einfügepunkt und Koordinatensystem](#einfügepunkt-und-koordinatensystem-4) + - [Übergang zu Rutschstange (Oberkante LP \<-\> Oberkante Rutschprofil)](#übergang-zu-rutschstange-oberkante-lp---oberkante-rutschprofil) + - [5.2 Funktionen](#52-funktionen) + - [Wie füge ich eine Beladung oder Entladung ein?](#wie-füge-ich-eine-beladung-oder-entladung-ein) + - [Wie binde ich einen FLEX Förderer an die Entladung an?](#wie-binde-ich-einen-flex-förderer-an-die-entladung-an) + ## Allgemein -- Darf ich Baugruppen kopieren? -- Darf ich Baugruppen auflösen? -- Darf ich Attribute in den Baugruppen manuell ändern? -- Darf ich Baugruppen mustern? +### Darf ich Baugruppen kopieren? + +Natürlich darf man eine erzeugte Baugruppe kopieren. Beim Export erhält es dann eine neue eigene ID, so dass keine Verwechslungen im CSV File auftreten können. + +### Darf ich Baugruppen auflösen? + +**Nein**. Der Export erkennt Baugruppen anhand ihres Blocknamens. Wird eine Baugruppe aufgelöst (EXPLODE), fällt sie komplett aus dem Export heraus: keine ID-Vergabe, keine Export-Zeile, keine Scanner-/Separator-Zuordnung. Zusätzlich gehen die Attribute dabei verloren, da sie nicht mehr mit einem Block verknüpft sind. + +### Darf ich Attribute in den Baugruppen manuell ändern? + +Grundsätzlich **ja**, dafür gibt es teilweise auch eigene Dialoge (z.B. zum Bearbeiten eines Kreisels). Zwei Punkte sind dabei zu beachten: + +- **ID**: Wird eine ID manuell auf einen bereits vergebenen Wert gesetzt, wird das beim nächsten Export als Duplikat erkannt und der zweiten gefundenen Baugruppe automatisch eine neue ID zugewiesen – der manuell gesetzte Wert kann also überschrieben werden. +- **Artikelnummer / Teileart**: Hier gibt es keine automatische Prüfung. Ein falsch gesetzter Wert führt zu einer falschen Merkmalszuordnung im Sivas-Export, ohne dass das vorher auffällt. + +Andere Attribute (Bezeichnung, Höhe, Abstand etc.) können bedenkenlos manuell angepasst werden, sollten aber nach Möglichkeit über die vorgesehenen Edit-Befehle statt direkt am Attribut geändert werden, damit die Geometrie konsistent bleibt. + +![Attribute](images/Kreisel-attribute.png) +*Abbildung: Attribute eines Kreisels* + + +### Darf ich Baugruppen mustern? + +**Ja**. Gemusterte Kopien tragen zunächst dieselbe ID wie das Original, beim nächsten Export-Lauf wird das als Duplikat erkannt und den weiteren Instanzen automatisch eine neue, eindeutige ID zugewiesen. Die Eindeutigkeit ist also am Ende gewährleistet, sobald einmal der Export (oder die ID-Prüfung) gelaufen ist. ## 1. Kreisel ### 1.1 Zusammensetzung, Abhängigkeiten, Randbedingungen -- Zusammensetzung einer Kreiselbaugruppe -- Einfügepunkt und Koordinatensystem -- Höhe (Laufprofil und Unterkante) +#### Zusammensetzung einer Kreiselbaugruppe + +Eine Kreiselbaugruppe besteht aus: + +- einem **AN8-Kreis** (Antriebsstation) +- einem **SP8-Kreis** (Spannstation) +- zwei **Tangentenlinien** (oben/unten) +- optional zwei **PIN-Linien** (nur bei Kreiselart "PIN") +- einem **Beschriftungstext** ("KREISEL n: Art_Abstand") +- Attributen wie ID, Bezeichnung, Artikelnummer, Montagehöhe, Kreiselart, Abstand, Anzahl Separator/Scanner/Rampen, Gerüsttyp, Drehrichtung, Drehung, Nummer + +Das verwandte Eckrad besteht nur aus einem AN8-Kreis plus eigenen Attributen – ohne Tangenten, PIN-Linien oder Beschriftung. + +#### Einfügepunkt und Koordinatensystem + +Bei Rotation 0 (horizontal) liegt der Einfügepunkt auf der linken Kreistangente der AN-Seite (Antriebsstation); die Spannstation liegt im Abstand "Abstand" dahinter. Die Rotation dreht den gesamten Kreisel um diesen Punkt. + +Beim Verbinden zweier Kreisel ist der Startpunkt explizit der äusserste AN-Punkt (Antriebsstation) und der Endpunkt der äusserste SP-Punkt (Spannstation); Abstand und Rotation werden aus Distanz und Winkel der beiden Klickpunkte berechnet. Beim Eckrad ist der Einfügepunkt der berechnete Kreismittelpunkt (Berührpunkt + Radius in Klickrichtung). + +#### Höhe (Laufprofil und Unterkante) + +Die Höhe wird über die Z-Koordinate des Einfügepunkts gesteuert (ein separates Laufprofil/Unterkante-Konzept gibt es beim Kreisel nicht). Wird beim Einfügen ein Punkt mit Höhe > 0 gewählt, gilt diese; ansonsten greift ein konfigurierbarer Standardwert (Default 2000 mm). Über den Bearbeiten-Dialog kann die Höhe jederzeit nachträglich geändert werden – der Kreisel wird dann mit der neuen Höhe neu aufgebaut. + +> **Hinweis**: Eine getrennte Betrachtung von "Laufprofil" und "Unterkante" (zwei unterschiedliche Bezugsebenen) ist technisch nicht hinterlegt – nur ein einziger Höhenwert steuert die Position. Der Zusammenhang zu Gefällestrecke/VF-Übergängen (siehe unten) ist eine reine Konstruktionsfrage. ### 1.2 Funktionen -- Wie füge ich einen Kreisel ein? -- Wie drehe ich einen Kreisel? -- Wie ändere ich die Höhe eines Kreisels? -- Wie ändere ich die Länge eines Kreisels? +#### Wie füge ich einen Kreisel ein? + +Unter *ILS -> Kreisel-Module -> Einfuegen*. Dann die Fragen nach Anfangspunkt, Länge und Höhe des Kreisels beantworten. Alternativ *ILS -> Kreisel-Module -> Verbinden*, um einen Kreisel direkt an einen bestehenden anzuschliessen. + +#### Wie drehe ich einen Kreisel? + +Am einfachsten durch einen Doppelklick auf den Kreisel und der Auswahl des Dropdowns Ausrichtung (Horizontal, Vertikal). Alternativ über *ILS -> Kreisel-Module -> Bearbeiten* (oder per Rechtsklick auf den Kreisel -> *Kreisel bearbeiten*). +![Oberfläche Kreisel](images/Kreisel-mit-gui.png) +*Abbildung: Kreisel-Dialog mit GUI-Eingabe* + +#### Wie ändere ich die Höhe eines Kreisels? + +Durch einen Doppelklick auf den Kreisel und der Eingabe der neuen Höhe unter Hoehe (mm). Alternativ über *ILS -> Kreisel-Module -> Bearbeiten* (oder per Rechtsklick auf den Kreisel -> *Kreisel bearbeiten*). + +#### Wie ändere ich die Länge eines Kreisels? + +Durch einen Doppelklick auf den Kreisel und der Eingabe des neuen Abstands im Bearbeiten-Dialog. Alternativ über *ILS -> Kreisel-Module -> Bearbeiten* (oder per Rechtsklick auf den Kreisel -> *Kreisel bearbeiten*). ## 2. Gefällestrecke ### 2.1 Zusammensetzung, Abhängigkeiten, Randbedingungen -- Zusammensetzung einer Gefällestrecke -- Einfügepunkt und Koordinatensystem -- Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP <-> Oberkante LP) +#### Zusammensetzung einer Gefällestrecke + +Im Standardfall besteht eine Gefällestrecke aus vier in Reihe eingefügten Bausteinen: + +1. **AUS-Element** +2. **Staustrecke** (auf die gewünschte Länge skaliert, um den Gefällewinkel geneigt) +3. **Separator** +4. **EIN-Element** + +Beim Aufbau entlang eines frei gezeichneten Linienzugs kommen zusätzlich Gefällebogen-Bausteine hinzu; vor jedem Bogen wird automatisch ein weiterer Separator eingefügt. + +![Gefaellestrecke](images/gefaellestrecke.png) +*Abbildung: Gefällestrecke* + + +#### Einfügepunkt und Koordinatensystem + +Jeder Baustein hat ein Ein- und ein Ausgangskoordinatensystem, über die die Bausteine beim Verketten passgenau aneinandergesetzt werden. Beim Verketten kommt das Eingangskoordinatensystem (nicht der Block-Ursprung) auf den Zielpunkt zu liegen. + +Der vom Anwender gepickte Startpunkt der Gefällestrecke entspricht dem Eingangskoordinatensystem des AUS-Elements; die Förderstrecken-Mittelachse läuft durch diesen Punkt. Am Kettenende wird die Höhe hingegen am Ausgangskoordinatensystem des EIN-Elements gemessen, damit dieses exakt der Zielhöhe entspricht. + +#### Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP <-> Oberkante LP) + +> **Hinweis**: Eine feste Höhenbeziehung zwischen "Unterkante SP" (Stauprofil) und "Oberkante LP" (Laufprofil eines Kreisels) ist nicht hinterlegt – das ist eine reine Konstruktionsfrage. Die Anschlusshöhe wird vom Konstrukteur über die Parameter Einfügehöhe/Zielhöhe gesteuert. ### 2.2 Funktionen -- Wie füge ich eine Gefällestrecke ein? -- Wie drehe ich eine Gefällestrecke? -- Wie ändere ich die Länge einer Gefällestrecke? -- Wie baue ich eine Gefällestrecke mit einer bestimmten Kapazität als Puffer (freie Länge des Stauprofils) -- Wie baue ich eine Gefällestrecke zwischen zwei Kreiseln mit definiertem Abstand? -- Wie baue ich eine Gefällestrecke mit Kurven als Übergang zwischen zwei Kreiseln mit unterschiedlicher Höhe? -- Wie baue ich eine Gefällestrecke mit manueller Höhenüberwindung ohne VF (QS-Platz Mubea) +#### Wie füge ich eine Gefällestrecke ein? + +Unter *ILS -> Gefaellestrecke -> einfach* für den Standardfall (Anfangspunkt, Länge, Höhe, Winkel über Dialog). Für eine Gefällestrecke entlang einer vorgezeichneten 3D-Linie *ILS -> Gefaellestrecke -> aus 3D-Linie*, für einen Linienzug aus mehreren Linien/Bögen *ILS -> Gefaellestrecke -> aus Linienzug (LINE + ARC)*. + +#### Wie drehe ich eine Gefällestrecke? + +Durch einen Doppelklick auf die Gefällestrecke (öffnet den Bearbeiten-Dialog mit denselben Eingaben wie beim Einfügen) oder per Rechtsklick -> *Gefaellestrecke bearbeiten*. + +#### Wie ändere ich die Länge einer Gefällestrecke? + +Durch einen Doppelklick auf die Gefällestrecke und Eingabe der neuen Länge im Bearbeiten-Dialog, oder per Rechtsklick -> *Gefaellestrecke bearbeiten*. + +#### Wie baue ich eine Gefällestrecke mit einer bestimmten Kapazität als Puffer (freie Länge des Stauprofils) + +#### Wie baue ich eine Gefällestrecke zwischen zwei Kreiseln mit definiertem Abstand? + +#### Wie baue ich eine Gefällestrecke mit Kurven als Übergang zwischen zwei Kreiseln mit unterschiedlicher Höhe? + +#### Wie baue ich eine Gefällestrecke mit manueller Höhenüberwindung ohne VF (QS-Platz Mubea) ## 3. Varioförderer ### 3.1 Zusammensetzung, Abhängigkeiten, Randbedingungen -- Zusammensetzung eines Varioförderer mit allen möglichen Komponenten -- Verfügbare Steigungen -- Einfügepunkt und Koordinatensystem -- Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP <-> Oberkante LP) +#### Zusammensetzung eines Varioförderer mit allen möglichen Komponenten + +Es gibt drei Anlagentypen: + +- **Standard**: gerade AS-/ES-Elemente + Staustrecke + Umlenk-/Motorstation + Separatoren, feste horizontale Blöcke. +- **Etage**: wie Standard, aber mit Etagen-Schrägsektion/-Bögen statt gerader AS-/ES-Elemente. +- **Linienzug**: frei aus der Zeichnung gebaute Kette aus AS-/ES-Element, Gefälle-Bogen, Vario-Kurve, horizontalem/geneigtem Förderer-Segment, Separatoren und Umlenk-/Motorstation. + +Der Bauteilablauf folgt dabei grundsätzlich: Startpunkt → optionales AS-Element → beliebige Folge aus Bogen / Gerade / Auf-Ab-Förderer / Horizontal-Förderer (mit Vario-Kurve bzw. horizontalem Zwischenstück) → Kettenende mit optionalem ES-Element. Jede Förderer-Einheit besteht aus Umlenkstation + Motorstation plus Separator(en). +![Variofoerderer](images/variofoerderer.png) +*Abbildung: Varioförderer Standard* + +#### Verfügbare Steigungen + +Zwei getrennte Winkel-Systeme: + +1. **Vertikale Neigung** (Gefälle/Steigung in Fahrtrichtung): aus einer festen Winkel-Tabelle (3, 6, 9, 12, 15, 18, 21, 27, 33, 39, 45, 51 Grad), maximal 51 Grad. +2. **Horizontale Kurven** (Gefälle-Bogen und Vario-Kurve): 30, 60 oder 90 Grad. + +**Wichtige Ausnahme**: AS-/ES-Elemente haben nur **30 und 90 Grad**, explizit **keine** 60-Grad-Variante. Die 30/60/90-Grad-Dreiteilung gilt also für Bögen/Vario-Kurve, nicht für AS-/ES-Elemente. + +#### Einfügepunkt und Koordinatensystem + +Identisch zum Gefällestrecke-Mechanismus: Die Verkettung erfolgt über Ein- und Ausgangskoordinatensysteme jedes Bausteins, das Eingangskoordinatensystem kommt dabei auf den Zielpunkt zu liegen. + +Beim Standard-Typ wird vor dem ersten Dialog der Startpunkt (X/Y) gepickt, die Z-Höhe kommt separat aus dem Dialogfeld "Einfügehöhe". Bei Etage ebenso. Im Linienzug-Modus ist der Startpunkt der erste Punktwahl-Schritt, die Starthöhe ein separates Zahlenfeld mit Default = Z des Punkts. + +#### Höhe und Übergang zu Kreiselkoordinatensystem (Unterkante SP <-> Oberkante LP) + +> **Hinweis**: Wie bei der Gefällestrecke gibt es keine feste Höhenbeziehung zwischen "Unterkante SP" und "Oberkante LP" eines Kreisels. Anschlusshöhen werden über die Parameter Einfügehöhe/Zielhöhe gesteuert – das ist eine reine Konstruktionsfrage. ### 3.2 Funktionen -- Welche Einfügemodi gibt es und wie unterscheiden sich diese? -- Wie baue ich einen VF in einem Puffer mit Gefällestrecken als Umschleusung? -- Wie baue ich einen VF zur Anfahrung einer bestimmten Höhe (Arbeitsplatz)? -- Wie baue ich einen VF als Übergang zwischen zwei verschiedenen Kreiseln (unterschiedliche Höhe und Position x/y/z) -- Wie baue ich einen Förderer zu Ebenenüberquerung zwischen zwei Pufferblöcken, welche übereinander positioniert sind? -- Wie baue ich eine Strecke mit mehreren VF und Gefällestrecken hintereinander zur Überbrückung von großen Entfernungen? +#### Welche Einfügemodi gibt es und wie unterscheiden sich diese? + +Unter *ILS -> Foerderer* stehen folgende Einfügemodi zur Verfügung: + +- **Standard -> Werte manuell**: alle Werte (Längen, Winkel, Höhen) werden über einen Dialog abgefragt. +- **Standard -> aus 3D-Linie**: wie Standard, aber entlang einer vorgezeichneten 3D-Linie. +- **Etage -> Werte manuell** / **Etage -> aus 3D-Linie**: wie Standard, jedoch mit Etagen-Schrägsektion/-Bögen statt gerader AS-/ES-Elemente. +- **3D-Linienzug**: frei aus der Zeichnung gebaute Kette, Schritt für Schritt über Dialoge/Konsole abgefragt (AS-Element, Bögen, Vario-Kurven, horizontale/geneigte Abschnitte, ES-Element). + +![Variofoerderer dialog1](images/vf-gui1.png) +*Abbildung: Varioförderer Dialog zur Erzeugung* + +![Variofoerderer dialog2](images/vf-gui2.png) +*Abbildung: Varioförderer Dialog zur Winkelbestimmung* + + +#### Wie baue ich einen VF in einem Puffer mit Gefällestrecken als Umschleusung? + +#### Wie baue ich einen VF zur Anfahrung einer bestimmten Höhe (Arbeitsplatz)? + +#### Wie baue ich einen VF als Übergang zwischen zwei verschiedenen Kreiseln (unterschiedliche Höhe und Position x/y/z) + +#### Wie baue ich einen Förderer zu Ebenenüberquerung zwischen zwei Pufferblöcken, welche übereinander positioniert sind? + +#### Wie baue ich eine Strecke mit mehreren VF und Gefällestrecken hintereinander zur Überbrückung von großen Entfernungen? ## 4. Scanner und Separator ### 4.1 Zusammensetzung, Abhängigkeiten, Randbedingungen -- Einfügepunkt und Koordinatensystem -- In welchen Baugruppen sind Scanner und Separatoren bereits eingebaut (Blöcke)? -- Zuordnung der frei platzierten Scanner und Separatoren zu einem Kreisel, Gefällestrecke oder VF +#### Einfügepunkt und Koordinatensystem + +Scanner und Separatoren werden als frei platzierbare Einzel-Blöcke eingefügt. Der Einfügepunkt ist ein frei gewählter Punkt, die Rotation wird im Anschluss interaktiv am Cursor festgelegt. + +Es gibt hier **kein** Koordinatensystem-Verkettungssystem wie bei Gefällestrecke/Varioförderer – der Block wird direkt an seinem Ursprung auf dem gewählten Punkt platziert. + +#### In welchen Baugruppen sind Scanner und Separatoren bereits eingebaut (Blöcke)? + +Innerhalb von Gefällestrecken- und Varioförderer-Ketten wird intern automatisch ein Separator eingefügt (als Trennsteg zwischen den Staustrecken-Segmenten). Diese verpackten Separatoren werden beim Export erkannt und in den Attributen "Anzahl Separator"/"Anzahl Scanner" der jeweiligen Baugruppe mitgezählt. + +Reine Scanner-Blöcke sind dagegen **nicht** standardmässig in Gefällestrecke/Varioförderer/Kreisel verbaut – sie kommen nur als frei platzierte Einzelblöcke vor. + +#### Zuordnung der frei platzierten Scanner und Separatoren zu einem Kreisel, Gefällestrecke oder VF + +Es gibt **keine feste Verknüpfung** zum Zeitpunkt des Einfügens. Die Zuordnung erfolgt erst **nachträglich beim Export** über die geometrische Nähe: Scanner außerhalb einer Baugruppen-Umgrenzung werden per Abstand der nächstgelegenen Baugruppe zugeordnet; ist der Abstand zu mehreren Kandidaten nahezu gleich, wird das als "strittig" markiert und im Export entsprechend vermerkt. + +Für Separatoren, die bereits in einer Kette verbaut sind, ist die Zuordnung dagegen von vornherein eindeutig. **Fazit**: Die Zuordnung frei platzierter Scanner/Separatoren ist rein geometrisch (Abstand), keine feste Verknüpfung. ### 4.2 Funktionen -- Wie füge ich einen Scanner ein? -- Wie füge ich einen Separator ein? +#### Wie füge ich einen Scanner ein? + +Unter *ILS -> Zusatzmodul -> Scanner einfuegen*. Dann Anfangspunkt auswählen und über den zweiten Klick den Winkel festsetzen. + +#### Wie füge ich einen Separator ein? + +Unter *ILS -> Zusatzmodul -> Separator einfuegen*. Dann Anfangspunkt auswählen und über den zweiten Klick den Winkel festsetzen. ## 5. Be- und Entladung ### 5.1 Zusammensetzung, Abhängigkeiten, Randbedingungen -- Einfügepunkt und Koordinatensystem -- Übergang zu Rutschstange (Oberkante LP <-> Oberkante Rutschprofil) +#### Einfügepunkt und Koordinatensystem + +Be- und Entladung werden als frei platzierbare Einzel-Blöcke eingefügt. Wie bei Scanner/Separator ist der Einfügepunkt ein frei gewählter Punkt, die Rotation wird interaktiv am Cursor festgelegt – es gibt keine Koordinatensystem-Verkettung zu einer vorgelagerten Strecke, die Station steht für sich allein in der Zeichnung. + +Bemerkenswert: Der Entladungsblock sitzt intern schräg im Raum, sodass bei der Koordinatenberechnung im Export eine zusätzliche Korrektur nötig ist, damit die Weltkoordinaten nicht verzerrt bzw. gespiegelt werden. + +#### Übergang zu Rutschstange (Oberkante LP <-> Oberkante Rutschprofil) + +> **Hinweis**: Eine feste Höhenbeziehung zwischen "Oberkante LP" und "Oberkante Rutschprofil" ist nicht hinterlegt. Diese Frage ist eine reine Konstruktionsfrage und sollte entsprechend beantwortet werden. ### 5.2 Funktionen -- Wie füge ich eine Beladung oder Entladung ein? -- Wie binde ich einen FLEX Förderer an die Entladung an? +#### Wie füge ich eine Beladung oder Entladung ein? +Unter *ILS -> Zusatzmodul -> BTMT-Beladung* bzw. *BTMT-Entladung*. Dann Anfangspunkt auswählen und über den zweiten Klick den Winkel festsetzen. + +#### Wie binde ich einen FLEX Förderer an die Entladung an? diff --git a/doc/images/Kreisel-attribute.png b/doc/images/Kreisel-attribute.png new file mode 100644 index 0000000000000000000000000000000000000000..15e20f6d49fa64cf3508bfa7bf0a6e0dc303a0db GIT binary patch literal 15531 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

8ysJW&y=7 zddOEAA7_;x*5i*|uKsd)tIx`)x@(=@|CP{qE{1M(BThPbm%xM|BqOTrk4G^t>BmOB_L{g?7fjq^Yk#`eem=|DFAX!wQwFM3)jz2QpDTt zVQcg8n2*Qy4@C7dwXiKtUzhq+B_IF+g3OgeSQ#j^!0d+r^7XCybgdVqtNxqEFm*G( zeDl|tTRNlSZB?~(0P1xhXYn~WT;nX-91OSrGU)i1KyxDRp7O#XqO(Kl@h9N^V34eo LqGYMKVbK2re*O}+ literal 0 HcmV?d00001 diff --git a/doc/images/Kreisel-mit-gui.png b/doc/images/Kreisel-mit-gui.png new file mode 100644 index 0000000000000000000000000000000000000000..c8a57de0224a76258d08589ab018bdd590677268 GIT binary patch literal 19821 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 MboFyt=akR{0P}KP@c;k- literal 0 HcmV?d00001 diff --git a/doc/images/gefaellestrecke-gui.png b/doc/images/gefaellestrecke-gui.png new file mode 100644 index 0000000000000000000000000000000000000000..0cae1e4c321dac900ff1276ff208fb000d2012d8 GIT binary patch literal 23203 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ℑH&)on}{@>Nz=8(?o49C5+3 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 Rq^&wKEe$B79Q-u+zW_pb(WU?Z literal 0 HcmV?d00001 From ba20d63f638cc7ece22cc6a98f18e6c4bd1634d0 Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Tue, 6 Oct 2026 13:35:46 +0200 Subject: [PATCH 04/38] [ADD] lib/dxf_anlage_export.py: gebaute und von Hand nachbearbeitete Anlage aus der Zeichnung zurueck in Nachbau-Testdaten (Kreisel, GF, VF standard/etage, VF-Linienzug als unveraendertes Journal, Einzelbloecke) - tests/testdata/dematic_arvato.json jetzt aus Dematic_TST.dxf; [ADD] dxf_scan_components.py: Gefaellestrecken aus Staustrecken-LINEs (Layer 6-SP), Start/Ende auf die Kreisel-Ketten verlaengert, AS-Element und Separator auf der Achse werden verbraucht, Steigfoerderer erkannt, --ohne-hoehen und --kreisel-hoehe; [ADD] vf_spec.lsp: Replay-Kern vsp-bau-journal aus vsp-bau-aus-spec herausgeloest (auch fuer aufgezeichnete Journale); [CHANGE] TEST_DEMATIC_ARVATO baut GF, VF standard/etage und Linienzug-Journale (mubea:gf-bauen/-vario-bauen wiederverwendet); [FIX] GF-Winkel aus Kreisel-Hoehen: AS/ES-Abfall mit falschem Vorzeichen an gf-winkel-berechnen uebergeben (3.79 statt ~2.49 Grad, GF endete 258 mm zu tief); [ADD] Tests test_dxf_scan_gf.py, test_dxf_anlage_export.py Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 5 +- Lisp/vf_spec.lsp | 29 +- lib/dxf_anlage_export.py | 408 ++++++ lib/dxf_scan_components.py | 416 +++++- tests/test_dematic_arvato.lsp | 225 +++- tests/test_dxf_anlage_export.py | 140 ++ tests/test_dxf_scan_gf.py | 168 +++ tests/test_mubea.lsp | 31 +- tests/testdata/dematic_arvato.json | 1930 ++++++++++------------------ 9 files changed, 2024 insertions(+), 1328 deletions(-) create mode 100644 lib/dxf_anlage_export.py create mode 100644 tests/test_dxf_anlage_export.py create mode 100644 tests/test_dxf_scan_gf.py diff --git a/CLAUDE.md b/CLAUDE.md index 84ed02c..79b2df9 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -101,7 +101,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `ssg_layer.lsp` | - | Layer-Verwaltung. `ssg-layer-visible-p` (aus ODER gefroren), `ssg-layer-gefroren-p`/`ssg-ent-layer-gefroren-p` (NUR gefroren, fuer den Export) | | `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad | ILS Kreisel und Eckrad komplett in AutoLISP | | `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) bleibt bewusst reine Konsole (im Code selbst als Legacy/"wird umgebaut" markiert). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/TODO-plan-vf-interactive.md`. Details/Entscheidungsbaum: `doc/variofoerderer.md` | -| `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/TODO-plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus`. Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | +| `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/TODO-plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus` (Replay-Kern `vsp-bau-journal` - nimmt auch ein unveraendert uebernommenes, aufgezeichnetes Journal, z.B. aus `dxf_anlage_export.py`). Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | | `Gefaellestrecke.lsp` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN); Modus 1 per DCL-Dialog (Einfuegehoehe, Element-Winkel 30/90); Doppelklick auf GF_n-Block ruft GEFAELLESTRECKE_EDIT (Dialog vorbelegt, Neuaufbau) | | `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_UPDATE_ATTRIBS, CSV_EXPORT_KONFIG | JSON-Sammlung und Python-Export (Omniflo-Merkmale/Sum-Zeile via lib/export_csv.py). **Gefrorene Layer**: `csv:collect-export-blocks` laesst Bloecke auf gefrorenen Layern aus (ausgeschaltete Layer zaehlen NICHT), Schalter `*csv-gefrorene-ausschliessen*` (Standard an, Toggle im Dialog CSV_EXPORT_KONFIG). Die Hilfsobjekte eines gefrorenen VF_n/GF_n (Separator-/Element-Kopien, Einheiten-/AS-ES-Marker) liegen auf eigenen Layern und werden darum ueber `*csv-ausschluss-enames*` mit ausgelassen (gesetzt in `csv:export-vorbereiten` per `csv:hilfskopien-ausschluss`); erzeugt und nummeriert werden sie trotzdem, damit IDs stabil bleiben. DrawPlanquadrate nutzt dieselbe Sammlung und folgt dem Filter | | `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_LADESCHLEIFE_AP110, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen, Ladeschleifen (`data/json/omniflo_ladeschleifen.json`, per `ssg-json-laden`, da die Beschreibungen Kommas enthalten; Blockdatei darf `.dwg` statt `.dxf` sein), Edit-Dialog | @@ -190,7 +190,8 @@ Abhaengigkeiten: `ezdxf`, Standard-Library. Benoetigen Umgebungsvariablen (`DXFM | `vf_journal_export.py` | Liest die Eingabe-Journale der `VF_n`-Bloecke (XDATA-App `SSG_VF_EDIT`, Marker `"linienzug"`) aus einer Zeichnung und schreibt sie als Frage-Antwort-Protokoll im Schema von `tests/testdata/linienzug_tests.json` (Gegenstueck zu `vfl-entry->string`; kein ezdxf, reine Gruppencode-Lesung). Optional `--csv ` fuer Strecken-ID und Erwartungswerte je Kette. Aufruf: `python vf_journal_export.py [--csv ...] [--kein-startpunkt-fix]` — erzeugt `tests/testdata/hm_recformat.json` aus `data/polylines.dxf` (die Aufzeichnung, aus der `tests/testdata/hundm05.json` als Spec abgeleitet wird) | | `dxf_vf_abbild.py` | Abbild der `VF_`/`GF_`-Wrapperbloecke einer Testzeichnung: Attribute UND Bausteinzusammensetzung je Kette, Ketten ueber den Einfuegepunkt der Spec zugeordnet (der Blockname taugt nicht - die VF-Nummer beginnt in jeder Zeichnung neu bei 1). Regressionsnetz fuer Umbauten am Bau-Ablauf: `--referenz` vergleicht gegen `tests/reference/hundm05_attribute.json` (Exit 1 bei Abweichung), `--schreibe-referenz` frischt sie nach einem GEPRUEFTEN Lauf auf. Faengt genau das, was der Ergebnis-Record nicht sieht - eine vertauschte `vfl-acc-*`-Reihenfolge (Komma-Listen `L_VF_m`/`L_GF_m`/`GF_WINKEL`, in der Zeichnung unsichtbar, im Sivas-Export falsch) und eine falsche Blockvariante. Liest ASCII-DXF streamend; binaere DXF kann `dxf_scan_components.py`. Genutzt von `tests/test_vf_geometrie.py` | | `vf_spec_export.py` | Uebersetzt ein Eingabe-Journal in eine **Spec** und zurueck (`spec_aus_journal` / `journal_aus_spec`) - Gegenstueck zu `vsp-journal` in `Lisp/vf_spec.lsp`, beide muessen dieselbe Tokenfolge liefern. Der Rundlauf `journal_aus_spec(spec_aus_journal(tok)) == tok` laeuft in `tests/test_vf_spec.py` gegen die 5 echten HundM-Ketten und beweist, dass die Spec das Journal verlustfrei abbildet. Schreibt das flache Spec-JSON (vom LISP-Parser lesbar). Objekte der Ziel-Datei, die keine Kette beschreiben (von Hand ergaenzte Anlagenteile mit `function`, z.B. Kreisel), werden beim Neuschreiben unveraendert ans Dateiende uebernommen - sonst waeren sie beim naechsten Lauf weg. Aufruf: `python vf_spec_export.py ` — erzeugt `tests/testdata/hundm05.json` (Spec, Eingabe fuer `TEST_HUNDM05`/`VF_SPEC_BAU`) aus `tests/testdata/hm_recformat.json` (Aufzeichnung) | -| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Aufruf: `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf | +| `dxf_anlage_export.py` | Gegenstueck zum Scanner: liest eine mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten - je Wrapper genau die Parameter, die auch dessen Edit-Befehl liest (KREISEL_n: Einfuegepunkt, `abstand` exakt aus der Blockdefinition; GF_n: SSG_GF_EDIT + SEITE_AS/ES, endet die GF auf einer Kreisel-Kette, wird dessen Hoehe `hoehe_ende_mm`; VF_n `standard`/`etage`: mubea-Schema wie `vfs-edit-basis-lesen`; VF_n `linienzug`: Journal UNVERAENDERT als `"typ": "linienzug_journal"` - bewusst keine Spec, weil der Bau-Dialog neuer ist als die Spec-Grammatik; uebrige Bloecke als Einzel-Insert ohne `_2D`/`_3D`-Suffix). Reihenfolge Kreisel, VF, GF, Einzelbloecke (VF vor GF wie mubea). Aufruf: `python dxf_anlage_export.py [--projekt NAME]` — erzeugt `tests/testdata/dematic_arvato.json` aus `Dematic_TST.dxf`. Test `tests/test_dxf_anlage_export.py` | +| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Gefaellestrecken, die als 3D-LINE auf einem Staustrecken-Layer gezeichnet sind (`GF_LINIE_LAYER`, z.B. `6-SP`), werden in einem zweiten Lesedurchgang zu Modus-1-Eintraegen: Start/Ende werden auf die Ketten der anschliessenden Kreisel verlaengert (gezeichnet ist nur die Staustrecke; `deltaL` reicht von AS- bis ES-Ursprung), AS-Seite aus dem Ausschleuselement am oberen Ende; dieses und Separatoren auf der Achse entfallen als Einzel-Insert (die GF baut beide selbst). Sitzt der AS am UNTEREN Ende, ist es ein Steigfoerderer und wird nur gemeldet (`gf_eintraege_aus_linien`, Test `tests/test_dxf_scan_gf.py`). `--ohne-hoehen` setzt alle Z auf 0, `--kreisel-hoehe X Y Z` gibt einem Kreisel seine Hoehe - die daran haengenden GF bekommen daraus `start_mm.z`/`hoehe_ende_mm`, den Winkel rechnet der Treiber (`dematic_arvato:gf-winkel` ueber `gf-winkel-berechnen`). Aufruf: `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf | ### Entwickler-Tools (`lib/`) - kein ezdxf, reine Text-/AutoLISP-Verarbeitung diff --git a/Lisp/vf_spec.lsp b/Lisp/vf_spec.lsp index 67b48ec..66609ff 100644 --- a/Lisp/vf_spec.lsp +++ b/Lisp/vf_spec.lsp @@ -903,15 +903,28 @@ ;; abgebrochene Kette bleibt also als lose Geometrie liegen und ist per ;; c:VF_SEKTION_RESTORE rettbar (vfl-segment-xdata-sichern hat pro Iteration ;; schon SSG_VF_EDIT_SEG/_PRE geschrieben). -(defun vsp-bau-aus-spec (spec / kopf sid journal rec vor-ent alt-error err - offen hl meld ist-glieder soll-glieder diff - ist-journal jdiff ent ed dim) +(defun vsp-bau-aus-spec (spec / kopf journal) (setq kopf (vsp-kopf spec)) - (setq sid (vsp-spec-id kopf)) + ;; vsp-journal sammelt seine Fehler in *vsp-fehler* - darum erst danach lesen. (setq journal (vsp-journal spec)) + (vsp-bau-journal (vsp-spec-id kopf) journal (ssg-val kopf "dim") *vsp-fehler*)) + +;; Eine Kette aus einem fertigen Eingabe-Journal bauen (Liste (art . wert) in +;; Bau-Reihenfolge, wie vfl-journal-replay-start sie erwartet). Gemeinsamer +;; Kern fuer Specs (vsp-bau-aus-spec, Journal per vsp-journal uebersetzt) und +;; fuer UNVERAENDERT uebernommene Aufzeichnungen - z.B. die SSG_VF_EDIT-XDATA +;; eines von Hand gebauten VF_n (tests/test_dematic_arvato.lsp, Journal per +;; vfl-string->entry gelesen). Letztere brauchen keinen Uebersetzer und +;; laufen darum auch dann, wenn der Dialog neuer ist als die Spec-Grammatik. +;; sid = Kennung im Record, dim = "2D"/"3D" oder nil (Sitzung), +;; fehler = Liste der Spec-Fehler (bei nil-Journal die Begruendung). +;; Erwartet den Headless-Rahmen (vsp-headless-an) beim Aufrufer. +(defun vsp-bau-journal (sid journal dim fehler / rec vor-ent alt-error err + offen hl meld ist-glieder soll-glieder diff + ist-journal jdiff ent ed) (setq soll-glieder (if journal (vfl-journal-glieder journal) nil)) (setq rec (vsp-rec-neu sid)) - (setq rec (vsp-set rec "spec_fehler" *vsp-fehler*)) + (setq rec (vsp-set rec "spec_fehler" fehler)) (setq rec (vsp-set rec "glieder_soll" soll-glieder)) (setq rec (vsp-set rec "eingaben_gesamt" (if journal (length journal) 0))) (princ (strcat "\n [SPEC] " sid)) @@ -919,9 +932,9 @@ (cond ;; --- Spec fehlerhaft: nichts bauen --- ((null journal) - (princ (strcat "\n " (itoa (length *vsp-fehler*)) + (princ (strcat "\n " (itoa (length fehler)) " Spec-Fehler, nichts gebaut:")) - (foreach f *vsp-fehler* (princ (strcat "\n - " f))) + (foreach f fehler (princ (strcat "\n - " f))) (setq rec (vsp-set rec "status" "spec-fehler")) (setq rec (vsp-set rec "dimension" (vsp-dim-text))) rec) @@ -934,7 +947,7 @@ ;; Feld in der Spec. Ist keines gesetzt, gilt die Sitzung. (setq dim (if (and (boundp '*vsp-dim-override*) *vsp-dim-override*) *vsp-dim-override* - (ssg-val kopf "dim"))) + dim)) (if dim (setq *ssg-ils-dim* dim)) (setq rec (vsp-set rec "dimension" (vsp-dim-text))) (princ (strcat " -> " (itoa (length journal)) " Journal-Eintraege, " diff --git a/lib/dxf_anlage_export.py b/lib/dxf_anlage_export.py new file mode 100644 index 0000000..c5e50e4 --- /dev/null +++ b/lib/dxf_anlage_export.py @@ -0,0 +1,408 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +dxf_anlage_export.py - Eine mit unseren Makros GEBAUTE (und von Hand +nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten +schreiben. + +Gegenstueck zu lib/dxf_scan_components.py: der Scanner liest FREMDE +Zeichnungen (Rohbloecke, Linien) und muss vieles raten. Hier stehen unsere +Wrapper-Bloecke in der Zeichnung, und jeder traegt seine Bau-Parameter +selbst - als Attribute und XDATA, genau die Werte, die auch der jeweilige +Edit-Befehl (Doppelklick) zum Neuaufbau liest. Typischer Ablauf: Scanner- +Vorlage nachbauen, in BricsCAD von Hand korrigieren/ergaenzen, Zeichnung als +DXF speichern und mit diesem Skript die Testdaten aktualisieren. + +Je Wrapper (Felder wie in tests/testdata/object_data.md bzw. mubea.json): + + KREISEL_n -> Kreisel ("function": "insert", x/y/z = Einfuegepunkt, + abstand = Mittenabstand AN8-SP8 aus der Blockdefinition, + rotation, typ = KREISELART) + GF_n -> Gefaellestrecke Modus 1 (XDATA SSG_GF_EDIT wie + gf-xdata-lesen + SEITE_AS/SEITE_ES wie GEFAELLESTRECKE_EDIT). + Endet die Strecke auf der Kette eines Kreisels, wird statt + des gebauten Winkels dessen Hoehe als hoehe_ende_mm + uebernommen - der Treiber rechnet den Winkel daraus neu. + VF_n "standard"/"etage" + -> VarioFoerderer im mubea-Schema (Parameter wie + vfs-edit-basis-lesen: Einfuegepunkt, hz aus XDATA, DELTA_L/ + DELTA_H/ANTRIEBFAHRTRICHTUNG/SEITE_AS/MOTORSEITE, dazu + VF_WINKEL und L_GF1 aus L_GF_m) + VF_n "linienzug" + -> das Eingabe-Journal UNVERAENDERT ("typ": + "linienzug_journal"). Bewusst KEINE Spec: der Bau-Dialog ist + neuer als die Spec-Grammatik (vf_linienzug_grammatik.py, + vf_spec.lsp), eine Uebersetzung wuerde desynchronisieren. + Der Treiber spielt das Journal per vsp-bau-journal ab. + sonstige Bloecke (Separator, Scanner, ...) + -> Einzel-Insert ("function": "insert", "block" ohne + _2D/_3D-Suffix, damit die Dimension der Sitzung gilt) + +Nicht uebernommen (gemeldet): "linienzug2" (Modus 2 - Journal verweist auf +Pfad-Objekte der Zeichnung per Handle) und Bloecke ohne Bau-Parameter. + +Aufruf: + python dxf_anlage_export.py [--projekt NAME] + +Beispiel (Dematic/Arvato, Nachbau-Daten fuer TEST_DEMATIC_ARVATO): + python lib/dxf_anlage_export.py C:/develop/sps_skel/data/Dematic_TST.dxf \\ + tests/testdata/dematic_arvato.json --projekt Arvato + +Bewusst OHNE ezdxf: reine Gruppencode-Lesung (vf_journal_export.gruppen), +ASCII-DXF. +""" + +import argparse +import collections +import json +import math +import os +import re +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from vf_journal_export import TRENNER, gruppen # noqa: E402 +from dxf_scan_components import arrays_einzeilig, kreisel_anschluss # noqa: E402 + +PREFIX = "[dxf_anlage_export]" +RUND = 2 + +# Kreisel-Durchmesser (Radmitte bis Kette), wie component_defaults.json. +KREISEL_RADIUS = 400.0 + +# Bis zu diesem Abstand (mm) gilt ein GF-Ende als auf der Kette eines +# Kreisels (der GF-Bau legt AS-/ES-Ursprung genau auf die Kette). +GF_KREISEL_TOL = 50.0 + +DIM_SUFFIX = re.compile(r"_(2D|3D)$") + + +# ============================================================ +# DXF lesen +# ============================================================ + +def _float(v): + try: + return float(v) + except (TypeError, ValueError): + return 0.0 + + +def lese_zeichnung(dxf_pfad): + """Modelspace-INSERTs (mit Attributen und XDATA je App) und die INSERTs + jeder Blockdefinition. + + Rueckgabe: (inserts, block_inhalt) + inserts - Liste {name, handle, p, rot, attribs, xdata}; xdata ist + app -> Liste der 1000er-Werte in Reihenfolge + block_inhalt - blockname -> Liste {name, p} der direkt enthaltenen + INSERTs (fuer den Kreisel-Mittenabstand) + """ + paare = gruppen(dxf_pfad) + inserts = [] + block_inhalt = {} + section = None + block = None + i, n = 0, len(paare) + while i < n: + code, wert = paare[i] + if code != "0": + i += 1 + continue + if wert == "SECTION" and i + 1 < n: + section = paare[i + 1][1].strip() + elif wert == "ENDSEC": + section = None + elif wert == "BLOCK": + j = i + 1 + while j < n and paare[j][0] != "0": + if paare[j][0] == "2": + block = paare[j][1] + break + j += 1 + elif wert == "ENDBLK": + block = None + elif wert == "INSERT" and section in ("ENTITIES", "BLOCKS"): + e = {"name": None, "handle": None, "p": [0.0, 0.0, 0.0], + "rot": 0.0, "attribs": {}, "xdata": {}, "ps": 0} + app = None + j = i + 1 + while j < n and paare[j][0] != "0": + c, v = paare[j] + if c == "2" and e["name"] is None: + e["name"] = v + elif c == "5" and e["handle"] is None: + e["handle"] = v + elif c in ("10", "20", "30") and app is None: + e["p"][{"10": 0, "20": 1, "30": 2}[c]] = _float(v) + elif c == "50": + e["rot"] = _float(v) + elif c == "67": + e["ps"] = int(_float(v)) + elif c == "1001": + app = v + e["xdata"][app] = [] + elif c == "1000" and app: + e["xdata"][app].append(v) + j += 1 + # Attribute: ATTRIB-Entities bis SEQEND (Wert Code 1, Tag Code 2) + while j < n and paare[j] == ("0", "ATTRIB"): + k = j + 1 + tag = val = None + while k < n and paare[k][0] != "0": + if paare[k][0] == "2" and tag is None: + tag = paare[k][1] + elif paare[k][0] == "1" and val is None: + val = paare[k][1] + k += 1 + if tag: + e["attribs"][tag] = val if val is not None else "" + j = k + if section == "ENTITIES": + if e["ps"] != 1: + inserts.append(e) + elif block: + block_inhalt.setdefault(block, []).append( + {"name": e["name"], "p": e["p"]}) + i = j + continue + i += 1 + return inserts, block_inhalt + + +# ============================================================ +# Wrapper -> Eintraege +# ============================================================ + +def _nummer(name): + m = re.search(r"_(\d+)", name) + return int(m.group(1)) if m else 0 + + +def _r(v): + return round(float(v), RUND) + 0.0 + + +def _richtung(hz): + rad = math.radians(hz) + return (math.cos(rad), math.sin(rad)) + + +def kreisel_eintrag(e, block_inhalt, projekt): + """Kreisel wie hundm05:bau-kreisel ihn erwartet.""" + a = e["attribs"] + abstand = _float(a.get("ABSTAND")) + quelle = "Attribut ABSTAND (ganze mm)" + # Genauer aus der Blockdefinition: Mittenabstand der beiden Stationen + stationen = [s for s in block_inhalt.get(e["name"], []) + if s["name"] and s["name"].upper().startswith(("AN8", "SP8"))] + an = [s for s in stationen if s["name"].upper().startswith("AN8")] + sp = [s for s in stationen if s["name"].upper().startswith("SP8")] + if an and sp: + abstand = math.hypot(sp[0]["p"][0] - an[0]["p"][0], + sp[0]["p"][1] - an[0]["p"][1]) + quelle = "Blockdefinition (AN8 -> SP8)" + nr = int(_float(a.get("NUMMER"))) or _nummer(e["name"]) + return collections.OrderedDict([ + ("id", "Kreisel_%s_%02d" % (projekt, nr)), + ("function", "insert"), + ("x", _r(e["p"][0])), ("y", _r(e["p"][1])), ("z", _r(e["p"][2])), + ("abstand", _r(abstand)), + ("rotation", _r(e["rot"])), + ("typ", a.get("KREISELART") or "STANDARD"), + ("comment", "aus Zeichnung: %s (ID %s), abstand aus %s" + % (e["name"], a.get("ID", "?"), quelle)), + ]) + + +def kreisel_geo(kreisel): + """kreisel_geo-Form (siehe dxf_scan_components.kreisel_anschluss) aus + einem Kreisel-Eintrag: Achse ab AN8-Radmitte = Einfuegepunkt + Radius.""" + u = _richtung(kreisel["rotation"]) + return {"id": kreisel["id"], + "a": (kreisel["x"] + KREISEL_RADIUS * u[0], + kreisel["y"] + KREISEL_RADIUS * u[1]), + "u": u, "laenge": kreisel["abstand"], "r": KREISEL_RADIUS, + "z": kreisel["z"]} + + +def kreisel_an_punkt(p, richtung, geo): + """Kreisel, auf dessen Kette p liegt (oder None).""" + ans = kreisel_anschluss(p, richtung, geo) + if ans and abs(ans[2]) <= GF_KREISEL_TOL: + return ans[0] + return None + + +def gf_eintrag(e, geo, projekt, hinweise): + """Gefaellestrecke Modus 1 - Felder wie GEFAELLESTRECKE_EDIT sie liest.""" + a = e["attribs"] + xd = e["xdata"].get("SSG_GF_EDIT") + if not xd or len(xd) < 6: + hinweise.append("%s ohne SSG_GF_EDIT-XDATA - uebersprungen" % e["name"]) + return None + hz, winkel = _float(xd[0]), _float(xd[1]) + z_start, deltaL = _float(xd[4]), _float(xd[5]) + start = (e["p"][0], e["p"][1]) + r = _richtung(hz) + ende = (start[0] + deltaL * r[0], start[1] + deltaL * r[1]) + eintrag = collections.OrderedDict([ + ("test_id", "GF_%s_%02d" % (projekt, _nummer(e["name"]))), + ("modus", 1), + ("deltaL_mm", _r(deltaL)), + ("hz_grad", _r(hz)), + ("start_mm", [_r(start[0]), _r(start[1]), _r(z_start)]), + ("as_seite", a.get("SEITE_AS") or "links"), + ("es_seite", a.get("SEITE_ES") or "links"), + ("as_winkel", xd[2] or "90"), + ("es_winkel", xd[3] or "90"), + ]) + k_start = kreisel_an_punkt(start, r, geo) + k_ende = kreisel_an_punkt(ende, (-r[0], -r[1]), geo) + if k_start: + eintrag["kreisel_start"] = k_start["id"] + if k_ende: + eintrag["kreisel_ende"] = k_ende["id"] + eintrag["hoehe_ende_mm"] = k_ende["z"] + kommentar = ("Endhoehe = Hoehe von %s (%.1f), Winkel rechnet der " + "Treiber neu; gebaut war %.4f Grad -> HOEHE_BIS %s" + % (k_ende["id"], k_ende["z"], winkel, + a.get("HOEHE_BIS_mm", "?"))) + else: + eintrag["winkel_grad"] = round(winkel, 4) + kommentar = "kein Kreisel am Ende - gebauter Winkel uebernommen" + eintrag["comment"] = "aus Zeichnung: %s (ID %s); %s" % ( + e["name"], a.get("ID", "?"), kommentar) + return eintrag + + +def vf_standard_eintrag(e, projekt, typ): + """VarioFoerderer im mubea-Schema (mubea:vario-bauen).""" + a = e["attribs"] + xd = e["xdata"].get("SSG_VF_EDIT") or [] + l_gf = [t for t in (a.get("L_GF_m") or "").split(",") if t.strip()] + eintrag = collections.OrderedDict([ + ("test_id", "VF_%s_%02d" % (projekt, _nummer(e["name"]))), + ("typ", typ), + ("richtung", a.get("ANTRIEBFAHRTRICHTUNG") or "Auf"), + ("deltaL", _r(_float(a.get("DELTA_L_mm")))), + ("deltaH", _r(_float(a.get("DELTA_H_mm")))), + ("winkel", int(_float(a.get("VF_WINKEL")))), + ("L_GF1", _r(1000.0 * _float(l_gf[0])) if l_gf else 0.0), + ("seite", a.get("SEITE_AS") or "rechts"), + ("motorseite", (a.get("MOTORSEITE") or "rechts").split(",")[0]), + ("hz", _r(_float(xd[1]) if len(xd) > 1 else 0.0)), + ("x", _r(e["p"][0])), ("y", _r(e["p"][1])), ("z", _r(e["p"][2])), + ("comment", "aus Zeichnung: %s (ID %s), Hoehe %s -> %s; deltaL/" + "deltaH aus den (ganzzahligen) Attributen" + % (e["name"], a.get("ID", "?"), a.get("HOEHE_VON_mm", "?"), + a.get("HOEHE_BIS_mm", "?"))), + ]) + return eintrag + + +def vf_journal_eintrag(e, projekt, nr): + """Linienzug: Journal unveraendert (Tokens 'ART:wert').""" + a = e["attribs"] + roh = "".join(e["xdata"]["SSG_VF_EDIT"][1:]) + tokens = [t for t in roh.split(TRENNER) if t] + return collections.OrderedDict([ + ("test_id", "VF_%s_LZ_%02d" % (projekt, nr)), + ("typ", "linienzug_journal"), + ("journal", tokens), + ("comment", "aus Zeichnung: %s (ID %s), %d Eingaben, Hoehe %s -> %s; " + "wird 1:1 abgespielt (vsp-bau-journal)" + % (e["name"], a.get("ID", "?"), len(tokens), + a.get("HOEHE_VON_mm", "?"), a.get("HOEHE_BIS_mm", "?"))), + ]) + + +def einzel_eintrag(e): + a = e["attribs"] + info = ", ".join("%s %s" % (k, a[k]) for k in ("ID", "ZUORDNUNG", "ARTINR") + if a.get(k)) + return collections.OrderedDict([ + ("function", "insert"), + ("block", DIM_SUFFIX.sub("", e["name"])), + ("x", _r(e["p"][0])), ("y", _r(e["p"][1])), ("z", _r(e["p"][2])), + ("rotation", _r(e["rot"])), + ("comment", "aus Zeichnung: %s%s" % (e["name"], + (" (%s)" % info) if info else "")), + ]) + + +def baue_eintraege(inserts, block_inhalt, projekt): + """Reihenfolge wie mubea.json: Kreisel, VF, GF, Einzelbloecke - die VF + vor den GF, weil gf-init-bibliothek globale Elementmasse umsetzt.""" + kreisel, vf, lz, gf, einzel, hinweise = [], [], [], [], [], [] + for e in sorted(inserts, key=lambda e: (e["name"] or "", e["p"][0], e["p"][1])): + name = e["name"] or "" + if name.startswith("KREISEL_"): + kreisel.append(kreisel_eintrag(e, block_inhalt, projekt)) + geo = [kreisel_geo(k) for k in kreisel] + for e in inserts: + name = e["name"] or "" + if name.startswith("KREISEL_"): + continue + if name.startswith("GF_"): + g = gf_eintrag(e, geo, projekt, hinweise) + if g: + gf.append(g) + elif name.startswith("VF_"): + xd = e["xdata"].get("SSG_VF_EDIT") + marker = xd[0] if xd else None + if marker in ("standard", "etage"): + vf.append(vf_standard_eintrag(e, projekt, marker)) + elif marker == "linienzug": + lz.append(vf_journal_eintrag(e, projekt, len(lz) + 1)) + else: + hinweise.append("%s: Marker %r nicht nachbaubar - uebersprungen" + % (name, marker)) + elif name.startswith("*") or name.startswith("ZZ_"): + continue # anonyme Bloecke, Export-Marker + else: + einzel.append(einzel_eintrag(e)) + gf.sort(key=lambda g: g["test_id"]) + vf.sort(key=lambda v: v["test_id"]) + kreisel.sort(key=lambda k: k["id"]) + return kreisel + vf + lz + gf + einzel, hinweise + + +def main(): + p = argparse.ArgumentParser( + description="Gebaute Anlage (Wrapper-Bloecke) aus einer Zeichnung in " + "Nachbau-Testdaten schreiben.") + p.add_argument("dxf", help="Zeichnung (ASCII-DXF)") + p.add_argument("output", help="Ziel-JSON") + p.add_argument("--projekt", help="Kennung in den IDs (Default: Dateiname)") + args = p.parse_args() + if not os.path.isfile(args.dxf): + print("%s FEHLER: DXF nicht gefunden: %s" % (PREFIX, args.dxf)) + sys.exit(1) + projekt = args.projekt or os.path.splitext(os.path.basename(args.dxf))[0] + + print("%s lese %s ..." % (PREFIX, args.dxf)) + inserts, block_inhalt = lese_zeichnung(args.dxf) + eintraege, hinweise = baue_eintraege(inserts, block_inhalt, projekt) + + zaehler = collections.Counter( + "Kreisel" if "abstand" in e else + "GF" if "modus" in e else + "VF Linienzug" if e.get("typ") == "linienzug_journal" else + "VF %s" % e["typ"] if "typ" in e and "test_id" in e else + e.get("block", "?") for e in eintraege) + for k, v in sorted(zaehler.items()): + print("%s %-22s %d" % (PREFIX, k, v)) + for h in hinweise: + print("%s ! %s" % (PREFIX, h)) + + with open(args.output, "w", encoding="utf-8") as fh: + fh.write(arrays_einzeilig(json.dumps(eintraege, ensure_ascii=False, + indent=2))) + fh.write("\n") + print("%s %d Eintraege geschrieben -> %s" + % (PREFIX, len(eintraege), args.output)) + + +if __name__ == "__main__": + main() diff --git a/lib/dxf_scan_components.py b/lib/dxf_scan_components.py index 043bd20..5b179de 100644 --- a/lib/dxf_scan_components.py +++ b/lib/dxf_scan_components.py @@ -11,6 +11,11 @@ also so, dass die Anlage per JSON-Treiber mit den Produktionsmakros nachgebaut werden kann (Vorbild: tests/testdata/mubea.json, das bisher von Hand aus einem DXF abgeleitet wurde). +Gefaellestrecken, die nicht als Blockpaar, sondern als 3D-LINE auf einem +Staustrecken-Layer gezeichnet sind (GF_LINIE_LAYER), werden in einem zweiten +Lesedurchgang erkannt und als Modus-1-Eintraege (Schema 2.1) ausgegeben, +siehe gf_eintraege_aus_linien. + Aufruf: python dxf_scan_components.py [--fenster X0 Y0 X1 Y1] @@ -128,6 +133,43 @@ ACHSE_MAX_QUER = 1500.0 # der Antriebsstationen, ohne benachbarte Bauteile zu verwechseln. ZWILLING_MAX_ABSTAND = 1500.0 +# --- Gefaellestrecken aus Staustrecken-Linien ------------------------------- +# Manche Zeichnungen (Dematic_arvato_reduced.dxf) fuehren die Gefaellestrecke +# nicht als Blockpaar, sondern als einfache 3D-LINE auf einem Staustrecken- +# Layer vom hohen zum tiefen Kreisel (dort: 27 Linien auf "6-SP", 10654 mm +# lang, 370 mm Gefaelle). Nur Modelspace-LINEs; Muster wie FAMILIEN. +GF_LINIE_LAYER = ["6-SP"] + +# Mindest-Hoehendifferenz (mm), ab der eine Staustrecken-Linie als Gefaelle +# gilt. Darunter ist sie eine waagrechte Strecke - die liegen auf denselben +# Layern (Rueckfuehrungen, Kreisel-Verbindungen) und sind keine GF. +GF_LINIE_MIN_DZ = 100.0 + +# Suchbereich fuer das Ausschleuselement am oberen Linienende, gemessen im +# Linien-KS: "entlang" ab Linienstart in Gefaellerichtung, "quer" seitlich. +# In Dematic_arvato_reduced.dxf sitzt es 1158 mm entlang und 467 mm quer - +# der Nachbar-AS der Linie daneben (800 mm Raster) liegt nur 433 mm quer auf +# der ANDEREN Seite. Darum entscheidet die Seite aus dem Blocknamen (links/ +# rechts), nicht der kleinste Abstand. +GF_AS_MAX_ENTLANG = 2000.0 +GF_AS_MAX_QUER = 700.0 + +# Groesste Luecke (mm) zwischen Linienende und Kreisel-Kette, bis zu der die +# Linie an diesen Kreisel angeschlossen wird. Gezeichnet ist nur die +# Staustrecke: oben fehlt das Ausschleuselement (~430 mm), unten das +# Einschleuselement (~480 mm) bis zur Kette. +GF_KREISEL_MAX_LUECKE = 1500.0 + +# Separatoren auf der GF-Achse: die Gefaellestrecke baut ihren eigenen +# (Staustrecke_Separator_SP_300_mm), der gezeichnete waere doppelt. Gilt fuer +# Vorkommen bis GF_SEP_MAX_QUER (mm) neben der Achse. +GF_SEP_MUSTER = ["S-SP", "S-LP", "Separator*"] +GF_SEP_MAX_QUER = 300.0 + +# Abstand (mm), bis zu dem eine --kreisel-hoehe X Y Z dem Kreisel mit diesem +# Einfuegepunkt (Eintrag x/y) zugeordnet wird. +KREISEL_HOEHE_TOL = 50.0 + # --------------------------------------------------------------------------- # Hilfsfunktionen @@ -593,6 +635,62 @@ def lese_inserts(dxf_path): return ms_inserts, block_inserts, block_base, statistik, block_info +def lese_linien(dxf_path, layer_muster): + """Liest alle Modelspace-LINEs auf den Layern aus layer_muster. + + Eigener Durchlauf statt Erweiterung von lese_inserts: dessen Rueckgabe + nutzt auch lib/dxf_abbild.py, und die Linien braucht nur die + Gefaellestrecken-Erkennung. Kostet einen zweiten Lesedurchgang. + + Rueckgabe: Liste {"layer", "a": [x, y, z], "b": [x, y, z]} in WCS + (eine LINE ist immer in WCS angegeben, keine OCS-Umrechnung noetig). + """ + linien = [] + section = None + warte_auf_sectionname = False + rec = None + + def ablegen(r): + if r and r["ps"] != 1 and matches_any(r["layer"] or "", layer_muster): + linien.append({"layer": r["layer"], "a": r["a"], "b": r["b"]}) + + fh = io.open(dxf_path, "rb") + try: + mm = mmap.mmap(fh.fileno(), 0, access=mmap.ACCESS_READ) + except ValueError: + fh.close() + raise + try: + for code, value in iter_tags(mm): + if code == 0: + ablegen(rec) + rec = None + if value == "SECTION": + warte_auf_sectionname = True + elif value == "ENDSEC": + section = None + elif value == "LINE" and section == "ENTITIES": + rec = {"layer": None, "a": [0.0, 0.0, 0.0], + "b": [0.0, 0.0, 0.0], "ps": 0} + elif code == 2 and warte_auf_sectionname: + section = value + warte_auf_sectionname = False + elif rec is not None: + if code == 8: + rec["layer"] = value + elif code in (10, 20, 30): + rec["a"][{10: 0, 20: 1, 30: 2}[code]] = value + elif code in (11, 21, 31): + rec["b"][{11: 0, 21: 1, 31: 2}[code]] = value + elif code == 67: + rec["ps"] = value + ablegen(rec) + finally: + mm.close() + fh.close() + return linien + + def insert_matrix(rec, block_base): """Transformationsmatrix eines INSERT (inkl. Basispunkt des Zielblocks). @@ -1213,15 +1311,242 @@ def sensor_eintrag(t, bekannte_bloecke=None, hinweise=None, treffer=None): } +def as_am_ende(p, richtung, as_liste, belegt): + """Ausschleuselement an einem Linienende suchen. + + p = Linienende (x, y), richtung = Einheitsvektor (x, y) von dort in die + Linie hinein. Gesucht wird im Linien-KS (siehe GF_AS_MAX_ENTLANG/-QUER); + "quer" ist positiv LINKS der Richtung. Ein AS mit Seite im Blocknamen muss + auf dieser Seite liegen - das trennt ihn vom Nachbar-AS der Linie daneben. + Bereits vergebene AS (belegt = Menge von id()) zaehlen nicht. + + Rueckgabe: (treffer, zielblock, geraten) oder None. + """ + beste = None + for t in as_liste: + if id(t) in belegt: + continue + vx, vy = t["x"] - p[0], t["y"] - p[1] + entlang = vx * richtung[0] + vy * richtung[1] + quer = richtung[0] * vy - richtung[1] * vx + if not (0.0 <= entlang <= GF_AS_MAX_ENTLANG and abs(quer) <= GF_AS_MAX_QUER): + continue + block, geraten = mappe_block(t["block"]) + if "Seite=%s" % DEFAULT_SEITE not in (geraten or []): + if block.endswith("_links") and quer < 0: + continue + if block.endswith("_rechts") and quer > 0: + continue + if beste is None or abs(quer) < beste[0]: + beste = (abs(quer), t, block, geraten or []) + return beste[1:] if beste else None + + +def kreisel_anschluss(p, richtung, kreisel): + """Schnittpunkt einer GF-Achse mit der naechsten Kreisel-Kette. + + p = Linienende (x, y), richtung = Einheitsvektor (x, y) der GF-Achse. + Je Kreisel (siehe kreisel_geo in baue_eintraege: Achse von der AN8- zur + SP8-Radmitte, Kette im Abstand r beidseits) wird die Kette auf der Seite + von p genommen und die Achse bis dorthin verlaengert bzw. gekuerzt. Nur + Kreisel, an deren Laenge p liegt und deren Kette hoechstens + GF_KREISEL_MAX_LUECKE entfernt ist; bei mehreren gewinnt die kleinste + Verschiebung. + + Rueckgabe: (kreisel, punkt (x, y), verschiebung entlang richtung) oder None. + """ + beste = None + for k in kreisel: + ux, uy = k["u"] + nx, ny = -uy, ux + vx, vy = p[0] - k["a"][0], p[1] - k["a"][1] + t = vx * ux + vy * uy + q = vx * nx + vy * ny + if not (-k["r"] <= t <= k["laenge"] + k["r"]): + continue + if abs(abs(q) - k["r"]) > GF_KREISEL_MAX_LUECKE: + continue + dn = richtung[0] * nx + richtung[1] * ny + if abs(dn) < 1e-6: # GF parallel zum Kreisel + continue + kette = k["r"] if q >= 0 else -k["r"] + lam = (kette - q) / dn + if beste is None or abs(lam) < abs(beste[2]): + beste = (k, (p[0] + lam * richtung[0], p[1] + lam * richtung[1]), lam) + return beste + + +def gf_eintraege_aus_linien(linien, as_liste, kreisel=None, sep_liste=None, + winkel_default=3.0): + """Gefaellestrecken (Modus 1, Schema 2.1) aus Staustrecken-Linien. + + Eine Gefaellestrecke laeuft immer bergab: Start ist das HOEHERE + Linienende, unabhaengig von der Zeichenrichtung. Das Ausschleuselement + gehoert an dieses obere Ende. Sitzt es dagegen am UNTEREN Ende, faehrt + die Strecke vom tiefen Kreisel hinauf - das ist ein Steigfoerderer und + keine GF (Dematic_arvato_reduced.dxf: 3 solche Linien); sie wird + gemeldet und uebersprungen. + + Anschluss an die Kreisel: gezeichnet ist nur die Staustrecke. Das Makro + legt den Ursprung des AS-Elements auf start_mm und dessen Einlauf + (KS_EIN) seitlich daneben, auf gleicher Hoehe der Achse; ebenso liegt der + Auslauf des ES-Elements neben dessen Ursprung, und deltaL_mm reicht von + AS- bis ES-Ursprung (gemessen an GF_Mubea: 9510 -> 399.2 = 9110.8). Damit + beide die Kreisel-Kette treffen, werden Start und Ende auf die jeweils + naechste Kette geschoben (kreisel_anschluss). Ohne Kreisel in Reichweite + bleibt das Linienende stehen und es gibt einen Hinweis. + + Hoehen: tragen beide Kreisel eine Anwender-Hoehe ("z_anwender"), wird + start_mm.z die des oberen und hoehe_ende_mm die des unteren Kreisels - + den Winkel rechnet dann der LISP-Treiber mit gf-winkel-berechnen + (dieselbe Naeherung wie Modus 3, mit den Elementmassen der aktuellen + 2D/3D-Bibliothek). Sonst ist winkel_default ein Platzhalter. + + Rueckgabe: (eintraege, verbrauchte ids, hinweise). Verbraucht werden das + AS am oberen Ende und Separatoren auf der Achse (sep_liste) - beides baut + die Gefaellestrecke selbst mit, als Einzel-Insert stuenden sie doppelt in + der Zeichnung (und im Sivas-Export). Der AS eines uebersprungenen + Steigfoerderers bleibt unverbraucht. + """ + eintraege, hinweise = [], [] + belegt = set() + waagrecht = 0 + kandidaten = [] + for ln in linien: + a, b = ln["a"], ln["b"] + if abs(a[2] - b[2]) < GF_LINIE_MIN_DZ: + waagrecht += 1 + continue + hoch, tief = (a, b) if a[2] > b[2] else (b, a) + lxy = math.hypot(tief[0] - hoch[0], tief[1] - hoch[1]) + if lxy <= 0.0: + continue + kandidaten.append((hoch, tief, lxy, ln["layer"])) + kandidaten.sort(key=lambda k: (round(k[0][0], RUND), round(k[0][1], RUND))) + + for hoch, tief, lxy, layer in kandidaten: + r = ((tief[0] - hoch[0]) / lxy, (tief[1] - hoch[1]) / lxy) + oben = as_am_ende(hoch, r, as_liste, belegt) + if oben is None: + unten = as_am_ende(tief, (-r[0], -r[1]), as_liste, belegt) + if unten is not None: + # AS NICHT verbrauchen: er gehoert zum Steigfoerderer und + # bleibt als Einzel-Insert in der Ausgabe stehen. + hinweise.append( + "Staustrecken-Linie (%.0f, %.0f, %.0f) -> (%.0f, %.0f, " + "%.0f): Ausschleuselement am UNTEREN Ende - Steigfoerderer, " + "keine Gefaellestrecke, uebersprungen" + % (tief[0], tief[1], tief[2], hoch[0], hoch[1], hoch[2])) + continue + tid = "GF_%s_%02d" % (PROJEKT, len(eintraege) + 1) + kommentar = ("aus DXF: LINE auf Layer '%s' (%.2f, %.2f) -> (%.2f, " + "%.2f), Laenge XY %.2f" + % (layer, hoch[0], hoch[1], tief[0], tief[1], lxy)) + + # Start/Ende auf die Kreisel-Ketten schieben + start, ende = (hoch[0], hoch[1]), (tief[0], tief[1]) + k_start = k_ende = None + for wo, p, rr in (("oberen", hoch, r), ("unteren", tief, (-r[0], -r[1]))): + ans = kreisel_anschluss(p, rr, kreisel or []) + if ans is None: + hinweise.append("%s: kein Kreisel am %s Ende - Linienende " + "bleibt stehen" % (tid, wo)) + kommentar += "; am %s Ende kein Kreisel in Reichweite" % wo + continue + k, punkt, lam = ans + kommentar += ("; am %s Ende um %.1f mm bis zur Kette von %s " + "verlaengert" % (wo, -lam, k["id"])) + if wo == "oberen": + start, k_start = punkt, k + else: + ende, k_ende = punkt, k + laenge = (ende[0] - start[0]) * r[0] + (ende[1] - start[1]) * r[1] + + eintrag = { + "test_id": tid, + "modus": 1, + "deltaL_mm": round(laenge, RUND), + "hz_grad": round(math.degrees(math.atan2(r[1], r[0])) % 360.0, RUND) + 0.0, + "start_mm": [round(start[0], RUND) + 0.0, round(start[1], RUND) + 0.0, 0.0], + "as_seite": DEFAULT_SEITE, + "es_seite": "links", + "as_winkel": str(DEFAULT_SCHLEUS_WINKEL), + "es_winkel": str(DEFAULT_SCHLEUS_WINKEL), + } + if k_start: + eintrag["kreisel_start"] = k_start["id"] + if k_ende: + eintrag["kreisel_ende"] = k_ende["id"] + if (k_start and k_ende and k_start.get("z_anwender") is not None + and k_ende.get("z_anwender") is not None): + eintrag["start_mm"][2] = float(k_start["z_anwender"]) + eintrag["hoehe_ende_mm"] = float(k_ende["z_anwender"]) + eintrag["hoehe_quelle"] = "Anwender" + kommentar += ("; Hoehen vom Anwender (Kreisel %s / %s), den Winkel " + "rechnet der Treiber" % (k_start["id"], k_ende["id"])) + else: + eintrag["winkel_grad"] = winkel_default + eintrag["hoehe_unbekannt"] = True + kommentar += ("; Hoehen unbekannt - winkel_grad %.1f ist Platzhalter" + % winkel_default) + + if oben is not None: + t, block, geraten = oben + belegt.add(id(t)) + teile = block.split("_") # AS_Element__ + eintrag["as_winkel"], eintrag["as_seite"] = teile[2], teile[3] + kommentar += ("; AS aus Block '%s' bei (%.2f, %.2f) -> %s, als " + "Einzel-Insert entfernt (baut die GF selbst)" + % (t["block"], t["x"], t["y"], block)) + if geraten: + kommentar += " - geraten: %s" % ", ".join(geraten) + else: + kommentar += ("; KEIN Ausschleuselement am oberen Ende gefunden - " + "as_seite/as_winkel sind Defaults") + hinweise.append("%s ohne Ausschleuselement am oberen Ende" % tid) + + # Separatoren auf der Achse zwischen Start und Ende + weg = [] + for s in sep_liste or []: + if id(s) in belegt or not matches_any(s["block"], GF_SEP_MUSTER): + continue + vx, vy = s["x"] - start[0], s["y"] - start[1] + entlang = vx * r[0] + vy * r[1] + quer = r[0] * vy - r[1] * vx + if 0.0 <= entlang <= laenge and abs(quer) <= GF_SEP_MAX_QUER: + belegt.add(id(s)) + weg.append("%s bei (%.0f, %.0f)" % (s["block"], s["x"], s["y"])) + if weg: + kommentar += ("; Separator auf der Achse entfernt (die GF baut " + "ihren eigenen): %s" % ", ".join(weg)) + + kommentar += "; es_seite/es_winkel sind Defaults (kein ES im DXF)." + eintrag["comment"] = kommentar + eintraege.append(eintrag) + + if waagrecht: + hinweise.append("%d waagrechte Staustrecken-Linie(n) auf %s - keine " + "Gefaellestrecke, nicht ausgegeben" + % (waagrecht, "/".join(GF_LINIE_LAYER))) + return eintraege, belegt, hinweise + + def baue_eintraege(treffer, defaults, boegen, weichen, - bekannte_bloecke=None): - """Erkannte Vorkommen auf die Schemata aus object_data.md abbilden.""" + bekannte_bloecke=None, linien=None, kreisel_hoehen=None): + """Erkannte Vorkommen auf die Schemata aus object_data.md abbilden. + + kreisel_hoehen: Liste (x, y, z) vom Anwender - z gilt fuer den Kreisel, + dessen Einfuegepunkt (Eintrag x/y) hoechstens KREISEL_HOEHE_TOL entfernt + liegt, und fuer die Gefaellestrecken, die an ihm anschliessen. + """ nach_familie = {} for t in treffer: nach_familie.setdefault(t["familie"], []).append(t) eintraege = [] hinweise = [] + kreisel_geo = [] # Achse/Kette je Kreisel fuer kreisel_anschluss + offene_hoehen = list(kreisel_hoehen or []) # --- Kreisel: AN8 (Antriebsstation) + SP8 (Spannstation) -------------- durchmesser = defaults.get("kreisel", {}).get("durchmesser", 800.0) @@ -1275,10 +1600,47 @@ def baue_eintraege(treffer, defaults, boegen, weichen, sp["block"], sp["layer"], sp["x"], sp["y"], dist, rotation)) + hoehe_hinweis, }) + kreisel = eintraege[-1] + for h in offene_hoehen: + if math.hypot(h[0] - kreisel["x"], h[1] - kreisel["y"]) <= KREISEL_HOEHE_TOL: + kreisel["z"] = float(h[2]) + kreisel["hoehe_quelle"] = "Anwender" + kreisel["comment"] += " Hoehe %.1f vom Anwender." % h[2] + offene_hoehen.remove(h) + break + kreisel_geo.append({ + "id": kreisel["id"], + "a": (an["x"], an["y"]), + "u": (math.cos(richtung), math.sin(richtung)), + "laenge": dist, + "r": radius, + "z_anwender": kreisel["z"] if kreisel.get("hoehe_quelle") else None, + }) + for h in offene_hoehen: + hinweise.append("Kreisel-Hoehe %.1f bei (%.2f, %.2f): kein Kreisel-" + "Einfuegepunkt in %g mm - nicht verwendet" + % (h[2], h[0], h[1], KREISEL_HOEHE_TOL)) for sp in sp_liste: hinweise.append("SP8 bei (%.2f, %.2f) ohne AN8-Partner" % (sp["x"], sp["y"])) eintraege.append(sensor_eintrag(sp, bekannte_bloecke, hinweise, treffer)) + # --- Gefaellestrecken aus Staustrecken-Linien --------------------------- + # Nach den Kreiseln (Anschluss an deren Ketten) und vor dem Rest-Block: + # sie entnehmen ihre Ausschleuselemente und Separatoren aus den Familien + # (siehe gf_eintraege_aus_linien), der Rest-Block darf diese nicht mehr + # als Einzel-Insert ausgeben. + if linien: + as_liste = [t for t in nach_familie.get("schleuselement", []) + if mappe_block(t["block"])[0].startswith("AS_Element")] + gf, belegt, gf_hinweise = gf_eintraege_aus_linien( + linien, as_liste, kreisel_geo, nach_familie.get("sensor", []), + defaults.get("gefaelle", {}).get("default_winkel", 3.0)) + eintraege.extend(gf) + hinweise.extend(gf_hinweise) + for familie in ("schleuselement", "sensor"): + nach_familie[familie] = [t for t in nach_familie.get(familie, []) + if id(t) not in belegt] + # --- Foerderer: Antriebs- und Umlenkstation paaren --------------------- gf_winkel_min = defaults.get("gefaelle", {}).get("default_winkel", 3.0) paare, rest_a, rest_u = paare_bilden(nach_familie.get("foerderer_antrieb", []), @@ -1400,6 +1762,37 @@ def filtere_fenster(eintraege, fenster): return behalten, len(eintraege) - len(behalten), ohne_punkte +def hoehen_entfernen(eintraege): + """Alle Hoehen auf 0 setzen, ausser den vom Anwender vorgegebenen. + + Fuer Zeichnungen, deren Z-Werte (noch) nicht belastbar sind: lieber + gar keine Hoehe als eine, die nach Einbauhoehe aussieht und keine ist. + Ausgenommen sind Eintraege mit hoehe_quelle "Anwender" (--kreisel-hoehe + und die daran anschliessenden Gefaellestrecken). + Rueckgabe: Anzahl der geaenderten Eintraege. + """ + n = 0 + for e in eintraege: + if e.get("hoehe_quelle") == "Anwender": + continue + geaendert = False + for feld in ("z", "hoehe"): + if feld in e and e[feld] != 0.0: + e[feld] = 0.0 + geaendert = True + for feld in ("startpunkt", "start_mm", "endpunkt"): + p = e.get(feld) + if isinstance(p, list) and len(p) >= 3 and p[2] != 0.0: + p[2] = 0.0 + geaendert = True + if any(f in e for f in ("z", "hoehe", "startpunkt", "start_mm")): + e["hoehe_unbekannt"] = True + if geaendert: + e["comment"] = e.get("comment", "") + " [Hoehe entfernt: --ohne-hoehen]" + n += 1 + return n + + def arrays_einzeilig(text): """Zahlen-Arrays im JSON-Text auf eine Zeile ziehen. @@ -1471,6 +1864,15 @@ def main(): help="Nur Bauteile in diesem XY-Fenster (mm) " "ausgeben - fuer den Nachbau eines einzelnen " "Anlagenabschnitts statt der ganzen Zeichnung") + parser.add_argument("--ohne-hoehen", action="store_true", + help="Alle Hoehen auf 0 setzen (Z der Zeichnung nicht " + "belastbar); ausgenommen --kreisel-hoehe") + parser.add_argument("--kreisel-hoehe", nargs=3, type=float, action="append", + metavar=("X", "Y", "Z"), + help="Hoehe Z fuer den Kreisel mit Einfuegepunkt X/Y " + "(wie im Ausgabe-JSON); gilt auch fuer Start/Ende " + "der daran anschliessenden Gefaellestrecken. " + "Mehrfach angebbar") parser.add_argument("--projekt", help="Projektkennung in den erzeugten IDs " "(Default: Name der DXF-Datei ohne Endung)") @@ -1529,8 +1931,16 @@ def main(): dim_stat["attribute_uebernommen"], dim_stat["nur_2d"], dim_stat["nur_3d"], len(treffer))) + linien = lese_linien(dxf_path, GF_LINIE_LAYER) + print("%s %d Staustrecken-Linien auf %s" % (PREFIX, len(linien), + "/".join(GF_LINIE_LAYER))) + eintraege, hinweise = baue_eintraege(treffer, defaults, boegen, weichen, - bekannte_bloecke) + bekannte_bloecke, linien, + args.kreisel_hoehe) + if args.ohne_hoehen: + print("%s --ohne-hoehen: Hoehe in %d Eintraegen auf 0 gesetzt" + % (PREFIX, hoehen_entfernen(eintraege))) if fenster: vorher = len(eintraege) diff --git a/tests/test_dematic_arvato.lsp b/tests/test_dematic_arvato.lsp index 7823b7a..6fcb57c 100644 --- a/tests/test_dematic_arvato.lsp +++ b/tests/test_dematic_arvato.lsp @@ -1,30 +1,53 @@ ;; ============================================================ ;; test_dematic_arvato.lsp - Nachbau des Abschnitts Flowpuffer/Kreisel der -;; Anlage Dematic/Arvato aus der Scanner-Vorlage. +;; Anlage Dematic/Arvato. ;; -;; 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 +;; Datenquelle: tests/testdata/dematic_arvato.json. Entstehung in zwei +;; Stufen: +;; 1. Vorlage aus der Fremdzeichnung (Scanner, raet vieles): +;; python lib/dxf_scan_components.py \ +;; C:/develop/sps_skel/data/Dematic_arvato_reduced.dxf data \ +;; tests/testdata/dematic_arvato.json --projekt Arvato \ +;; --fenster -2534 -4549 49466 29451 --ohne-hoehen \ +;; --kreisel-hoehe 35860.37 12519.72 2437 \ +;; --kreisel-hoehe 36661.24 24878.8 1826 +;; 2. Vorlage mit diesem Treiber bauen, in BricsCAD von Hand korrigieren +;; und ergaenzen (VF-Ketten, Hoehen, Sensoren aufgeraeumt), als DXF +;; speichern und daraus die Testdaten neu schreiben - AKTUELLER STAND: +;; python lib/dxf_anlage_export.py \ +;; C:/develop/sps_skel/data/Dematic_TST.dxf \ +;; tests/testdata/dematic_arvato.json --projekt Arvato ;; -;; 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): +;; Eintragsarten: ;; "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 +;; kreisel-insert-script; x/y = Einfuegepunkt, +;; abstand = Mittenabstand AN8-SP8) +;; "function": "insert" + "block" -> Einzelblock (hundm05:bau-sensor) +;; "typ": "standard"/"etage" + "test_id" +;; -> VarioFoerderer ueber mubea:vario-bauen +;; (mubea-Schema: deltaL, deltaH, richtung, +;; winkel, L_GF1, seite, hz, x/y/z), optional +;; "motorseite" +;; "typ": "linienzug_journal" +;; -> Linienzug-Kette: das aufgezeichnete Eingabe- +;; Journal (SSG_VF_EDIT) wird 1:1 abgespielt +;; (vsp-bau-journal) - keine Spec, weil der +;; Dialog neuer ist als die Spec-Grammatik +;; "modus": 1 -> Gefaellestrecke ueber mubea:gf-bauen +;; (start_mm + deltaL_mm, kein Endpunkt). Mit +;; hoehe_ende_mm (Hoehe des Kreisels am Ende) +;; rechnet dematic_arvato:gf-winkel den Winkel, +;; sonst gilt winkel_grad. +;; "typ": "gerade" -> waagrechter Foerderer aus der Scanner-Vorlage - +;; kein Bau-Pfad, wird gemeldet und uebersprungen +;; +;; Reihenfolge wie mubea.json (VF vor GF): gf-init-bibliothek setzt die +;; globalen AS/ES-Masse um, siehe mubea:ensure-gf-init. ;; ;; Keine eigene Bau-Logik: hundm05:bau-kreisel/-sensor aus -;; tests/test_hundm05.lsp wird mitgeladen (die Datei definiert nur Funktionen). +;; tests/test_hundm05.lsp und mubea:gf-bauen/-vario-bauen aus +;; tests/test_mubea.lsp werden mitgeladen (beide Dateien definieren nur +;; Funktionen), Linienzug-Ketten laufen ueber vsp-bau-journal (vf_spec.lsp). ;; ;; Aufruf in BricsCAD: ;; (load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp")) @@ -40,12 +63,30 @@ (ssg-ensure "KreiselInsert") (ssg-ensure "VarioFoerderer") (ssg-ensure "SSG_LIB_Commands") +(ssg-ensure "Gefaellestrecke") (if (null (car (atoms-family 1 '("HUNDM05:BAU-SENSOR")))) (load (strcat (getenv "DXFMAKRO") "/tests/test_hundm05.lsp"))) +(if (null (car (atoms-family 1 '("MUBEA:VARIO-BAUEN")))) + (load (strcat (getenv "DXFMAKRO") "/tests/test_mubea.lsp"))) (defun dematic_arvato:datei () (strcat (getenv "DXFMAKRO") "/tests/testdata/dematic_arvato.json")) +;; Record um den gebauten Block ergaenzen (oder als Abbruch markieren). +(defun dematic_arvato:rec-block (rec ent fehlertext / ed) + (if (and ent (= (type ent) 'ENAME)) + (progn + (setq ed (entget ent)) + (princ (strcat " -> Block " (cdr (assoc 2 ed)))) + (setq rec (vsp-set rec "block_name" (cdr (assoc 2 ed)))) + (setq rec (vsp-set rec "block_handle" (cdr (assoc 5 ed)))) + (setq rec (vsp-set rec "insert_point" (cdr (assoc 10 ed)))) + (setq rec (vsp-set rec "attribs" (ssg-attrib-read ent))) + (vsp-set rec "status" "executed")) + (progn + (princ (strcat " FEHLER: " fehlertext)) + (vsp-set (vsp-set rec "status" "abbruch") "fehler_text" fehlertext)))) + ;; Foerderer "gerade": noch kein Bau-Pfad - nur melden. (defun dematic_arvato:gerade-melden (obj / tid rec) (setq tid (ssg-val obj "test_id")) @@ -56,15 +97,146 @@ (vsp-set (vsp-set rec "status" "uebersprungen") "fehler_text" "kein Bau-Pfad fuer typ gerade")) -(defun dematic_arvato:bau-eintrag (obj / kind res) +;; Gefaellewinkel aus Start- und Endhoehe - derselbe Loeser wie Modus 3 +;; (gf-winkel-berechnen, Gefaellestrecke.lsp) mit den AS/ES-Massen der +;; aktuellen 2D/3D-Bibliothek. Die Kette ist eine einzige Gerade plus der +;; eine Separator vor dem ES (extra-sep 1); ihre Laenge ohne AS/ES/Separator +;; ist deltaL - aus-dx - ein-dx - 300, damit ergibt der Loeser als +;; Gesamtlaenge wieder genau deltaL (deltaL reicht von AS- bis ES-Ursprung). +;; VORZEICHEN: vf-set-as-masse (vf_core) misst dz als KS_AUS.z - KS_EIN.z +;; (bei AS/ES negativ), gf-winkel-berechnen erwartet die Konvention von +;; gf-init-bibliothek (KS_EIN.z - KS_AUS.z, positiv) und zieht den Wert ab. +;; Mit der VF-Konvention wurde der feste AS/ES-Abfall addiert statt +;; abgezogen - real gebaut: 3.79 statt ~2.49 Grad, GF endete 258 mm unter +;; dem Kreisel (HOEHE_BIS 1568 statt 1826). Darum hier der Betrag. +(defun dematic_arvato:gf-winkel (deltaL hz as-seite es-seite as-winkel es-winkel + z-start z-ende / winkel) + (mubea:ensure-gf-init) + (vf-set-as-masse as-winkel as-seite) + (vf-set-es-masse es-winkel es-seite) + (setq aus-dz (abs (float aus-dz)) ein-dz (abs (float ein-dz))) + (setq winkel + (gf-winkel-berechnen + (list (list "Linie" hz (- deltaL (float aus-dx) (float ein-dx) 300.0) 0 "links")) + (- z-start z-ende) 1)) + (vf-set-as-masse "90" as-seite) + (vf-set-es-masse "90" es-seite) + winkel) + +;; Gefaellestrecke (Modus 1) bauen - Felder wie mubea:build-gf, ohne dessen +;; anzahl/delta-Vervielfaeltigung (jede GF steht einzeln in der Datei). +;; Mit "hoehe_ende_mm" (Hoehe des Kreisels am Ende) wird der Winkel daraus +;; gerechnet, sonst gilt "winkel_grad" (Default 3.0). +(defun dematic_arvato:bau-gf (obj / tid start deltaL hz winkel z-ende + as-seite es-seite as-winkel es-winkel rec) + (setq tid (ssg-val obj "test_id") + start (ssg-val obj "start_mm") + deltaL (ssg-val obj "deltaL_mm") + hz (ssg-val obj "hz_grad") + winkel (ssg-val obj "winkel_grad") + z-ende (ssg-val obj "hoehe_ende_mm") + as-seite (cond ((ssg-val obj "as_seite")) ("links")) + es-seite (cond ((ssg-val obj "es_seite")) ("links")) + as-winkel (cond ((ssg-val obj "as_winkel")) ("90")) + es-winkel (cond ((ssg-val obj "es_winkel")) ("90"))) + (setq rec (vsp-rec-neu (if tid tid "(ohne id)"))) + (setq rec (vsp-set rec "kind" "gefaellestrecke")) + (setq rec (vsp-set rec "dimension" (vsp-dim-text))) (cond + ((not (and (= (type start) 'LIST) (= (length start) 3) + (numberp deltaL) (numberp hz))) + (princ (strcat "\n [GF] " (if tid tid "?") + " - FEHLER: start_mm, deltaL_mm und hz_grad muessen gesetzt sein")) + (vsp-set (vsp-set rec "status" "spec-fehler") "fehler_text" + "start_mm, deltaL_mm oder hz_grad fehlt bzw. ist ungueltig")) + ((and (numberp z-ende) (>= z-ende (caddr start))) + (princ (strcat "\n [GF] " (if tid tid "?") + " - FEHLER: hoehe_ende_mm liegt nicht unter der Starthoehe")) + (vsp-set (vsp-set rec "status" "spec-fehler") "fehler_text" + "hoehe_ende_mm >= start_mm.z - kein Gefaelle")) + (T + (setq winkel + (cond + ((numberp z-ende) + (dematic_arvato:gf-winkel (float deltaL) (float hz) as-seite es-seite + as-winkel es-winkel + (float (caddr start)) (float z-ende))) + ((numberp winkel) (float winkel)) + (T 3.0))) + ;; Winkel und Soll-Endhoehe als Meldung (das Record-Schema aus vf_spec + ;; kennt dafuer kein Feld); die Ist-Endhoehe steht in attribs HOEHE_BIS. + (setq rec (vsp-set rec "meldungen" + (list (strcat "winkel_grad " (rtos winkel 2 3) + (if (numberp z-ende) + (strcat " aus Hoehe " (rtos (caddr start) 2 1) + " -> " (rtos z-ende 2 1)) + ""))))) + (dematic_arvato:rec-block rec + (mubea:gf-bauen tid (mapcar 'float start) (float deltaL) (float hz) + as-seite es-seite as-winkel es-winkel winkel) + "gefaellestrecke-einfuegen lieferte keinen GF-Block")))) + +;; VarioFoerderer "standard"/"etage" - mubea-Schema, Bau ueber +;; mubea:vario-bauen. "motorseite" wirkt wie im Edit-Dialog ueber den +;; Override *vf-motorseite* (vf-block-erstellen liest ihn). +(defun dematic_arvato:bau-vf (obj / tid typ rec ent) + (setq tid (ssg-val obj "test_id") + typ (cond ((ssg-val obj "typ")) ("standard"))) + (setq rec (vsp-rec-neu (if tid tid "(ohne id)"))) + (setq rec (vsp-set rec "kind" "vario")) + (setq rec (vsp-set rec "dimension" (vsp-dim-text))) + (setq *vf-motorseite* (ssg-val obj "motorseite")) + (setq ent + (vl-catch-all-apply 'mubea:vario-bauen + (list tid typ (ssg-val obj "richtung") + (float (ssg-val obj "deltaL")) (float (ssg-val obj "deltaH")) + (ssg-val obj "winkel") (float (cond ((ssg-val obj "L_GF1")) (0.0))) + (ssg-val obj "seite") (ssg-val obj "hz") + (list (float (ssg-val obj "x")) (float (ssg-val obj "y")) + (float (ssg-val obj "z")))))) + (setq *vf-motorseite* nil) + (if (vl-catch-all-error-p ent) + (vsp-set (vsp-set rec "status" "abbruch") "fehler_text" + (vl-catch-all-error-message ent)) + (dematic_arvato:rec-block rec ent + "kein VF-Block (deltaL beim gewuenschten Winkel nicht loesbar?)"))) + +;; Linienzug-Kette: aufgezeichnetes Journal ("ART:wert"-Tokens, wie in der +;; SSG_VF_EDIT-XDATA) 1:1 abspielen. Headless-Rahmen wie vsp-bau-datei; er +;; MUSS auch nach einem Fehler zurueck, sonst bleiben getstring/getpoint der +;; Sitzung ersetzt. +(defun dematic_arvato:bau-journal (obj / tid journal res) + (setq tid (cond ((ssg-val obj "test_id")) ("(ohne id)"))) + (setq journal (mapcar 'vfl-string->entry (ssg-val obj "journal"))) + (vsp-headless-an) + (setq res (vl-catch-all-apply 'vsp-bau-journal + (list tid journal nil + (if journal nil (list "Feld \"journal\" fehlt oder ist leer"))))) + (vsp-headless-aus) + (if (vl-catch-all-error-p res) + (vsp-set (vsp-set (vsp-rec-neu tid) "status" "abbruch") "fehler_text" + (vl-catch-all-error-message res)) + res)) + +(defun dematic_arvato:bau-eintrag (obj / kind res typ) + (setq typ (ssg-val obj "typ")) + (cond + ((ssg-val obj "modus") + (setq kind "gefaellestrecke") + (setq res (vl-catch-all-apply 'dematic_arvato:bau-gf (list obj)))) + ((= typ "linienzug_journal") + (setq kind "linienzug") + (setq res (dematic_arvato:bau-journal obj))) + ((and (member typ '("standard" "etage")) (ssg-val obj "test_id")) + (setq kind "vario") + (setq res (dematic_arvato:bau-vf obj))) ((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") + ((= typ "gerade") (setq kind "gerade") (setq res (dematic_arvato:gerade-melden obj))) (T @@ -76,6 +248,7 @@ (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 "test_id")) ((ssg-val obj "block")) ("?"))) "kind" kind) "status" "abbruch") @@ -85,11 +258,11 @@ (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 "\n TEST_DEMATIC_ARVATO - Abschnitt Flowpuffer/Kreisel") (princ (strcat "\n " datei)) (princ "\n================================================================") (cond - ((null (car (atoms-family 1 '("VSP-REC-NEU")))) + ((null (car (atoms-family 1 '("VSP-BAU-JOURNAL")))) (princ "\n[TEST_DEMATIC_ARVATO] FEHLER: vf_spec.lsp nicht geladen" " (VarioFoerderer laden).") (setq *dematic-arvato-records* nil)) @@ -104,6 +277,10 @@ (setvar "OSMODE" 0) (setvar "ATTREQ" 0) (setvar "ATTDIA" 0) + ;; Vario-Bibliothek (Bogen-/AS-/ES-Masse) wie C:TEST_MUBEA, und die + ;; GF-Elementmasse in jeder Zeichnung neu ermitteln. + (if (vsp-lib-noetig-p) (init-bibliothek)) + (setq *mubea-gf-init-done* nil) (setq out '()) (foreach obj daten (setq out (cons (dematic_arvato:bau-eintrag obj) out))) diff --git a/tests/test_dxf_anlage_export.py b/tests/test_dxf_anlage_export.py new file mode 100644 index 0000000..b934190 --- /dev/null +++ b/tests/test_dxf_anlage_export.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +test_dxf_anlage_export.py - Gebaute Anlage -> Nachbau-Testdaten +(lib/dxf_anlage_export.py). Laeuft ohne BricsCAD und ohne DXF: die +Wrapper-Daten sind die Werte aus Dematic_TST.dxf, von Hand nachgestellt +(Form wie lese_zeichnung sie liefert). + + 1. Kreisel: abstand exakt aus der Blockdefinition (AN8 -> SP8), nicht aus + dem ganzzahligen ABSTAND-Attribut. + 2. GF auf zwei Kreiselketten: Endhoehe = Hoehe des Kreisels am Ende, + der (falsch) gebaute Winkel wird NICHT uebernommen. + 3. GF ohne Kreisel am Ende: gebauter Winkel bleibt. + 4. VF "standard": Parameter wie vfs-edit-basis-lesen, L_GF1 aus L_GF_m. + 5. VF "linienzug": Journal unveraendert als Token-Liste. + 6. Einzelblock: _2D/_3D-Suffix entfaellt. +""" + +import os +import sys + +import pytest + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), + "..", "lib")) +import dxf_anlage_export as dae # noqa: E402 + + +def _insert(name, p, rot=0.0, attribs=None, xdata=None): + return {"name": name, "handle": "1", "p": list(p), "rot": rot, + "attribs": attribs or {}, "xdata": xdata or {}, "ps": 0} + + +KREISEL_OBEN = _insert("KREISEL_2_STANDARD_33044", (35860.37, 12519.72, 2437.0), + 180.0, {"ID": "0002", "NUMMER": "2", "ABSTAND": "33044", + "KREISELART": "STANDARD"}) +KREISEL_UNTEN = _insert("KREISEL_3_STANDARD_33470", (36661.24, 24878.8, 1826.0), + 180.0, {"ID": "0003", "NUMMER": "3", "ABSTAND": "33470", + "KREISELART": "STANDARD"}) +BLOCK_INHALT = { + "KREISEL_2_STANDARD_33044": [{"name": "AN8_3D", "p": [400.0, 0.0, 0.0]}, + {"name": "SP8_3D", "p": [33444.28, 0.0, 0.0]}], + "KREISEL_3_STANDARD_33470": [{"name": "AN8_3D", "p": [400.0, 0.0, 0.0]}, + {"name": "SP8_3D", "p": [33870.18, 0.0, 0.0]}], +} + + +def _geo(): + return [dae.kreisel_geo(dae.kreisel_eintrag(k, BLOCK_INHALT, "T")) + for k in (KREISEL_OBEN, KREISEL_UNTEN)] + + +def test_kreisel_abstand_aus_blockdefinition(): + k = dae.kreisel_eintrag(KREISEL_OBEN, BLOCK_INHALT, "T") + assert k["id"] == "Kreisel_T_02" + assert k["abstand"] == pytest.approx(33044.28, abs=0.01) + assert (k["x"], k["y"], k["z"], k["rotation"]) == (35860.37, 12519.72, 2437.0, 180.0) + ohne_block = dae.kreisel_eintrag(KREISEL_OBEN, {}, "T") + assert ohne_block["abstand"] == 33044.0 + + +def test_gf_zwischen_zwei_kreiseln_bekommt_endhoehe(): + gf = _insert("GF_1", (5833.56, 12919.72, 2437.0), 0.0, + {"ID": "0005", "SEITE_AS": "links", "SEITE_ES": "links", + "HOEHE_BIS_mm": "1568"}, + {"SSG_GF_EDIT": ["90", "3.7929", "90", "90", "2437", "11559.08"]}) + hinweise = [] + e = dae.gf_eintrag(gf, _geo(), "T", hinweise) + assert e["test_id"] == "GF_T_01" + assert e["start_mm"] == [5833.56, 12919.72, 2437.0] + assert e["deltaL_mm"] == 11559.08 and e["hz_grad"] == 90.0 + assert (e["kreisel_start"], e["kreisel_ende"]) == ("Kreisel_T_02", "Kreisel_T_03") + assert e["hoehe_ende_mm"] == 1826.0 + assert "winkel_grad" not in e + assert hinweise == [] + + +def test_gf_ohne_kreisel_behaelt_gebauten_winkel(): + gf = _insert("GF_7", (0.0, 0.0, 1000.0), 0.0, {}, + {"SSG_GF_EDIT": ["0", "3", "90", "30", "1000", "5000"]}) + e = dae.gf_eintrag(gf, _geo(), "T", []) + assert e["winkel_grad"] == 3.0 + assert "hoehe_ende_mm" not in e and "kreisel_ende" not in e + assert e["es_winkel"] == "30" + + +def test_gf_ohne_xdata_wird_gemeldet(): + hinweise = [] + assert dae.gf_eintrag(_insert("GF_9", (0, 0, 0)), [], "T", hinweise) is None + assert "SSG_GF_EDIT" in hinweise[0] + + +def test_vf_standard(): + vf = _insert("VF_2", (3314.07, 24478.8, 1826.0), 0.0, + {"ID": "0082", "DELTA_L_mm": "11559", "DELTA_H_mm": "611", + "ANTRIEBFAHRTRICHTUNG": "Auf", "SEITE_AS": "links", + "MOTORSEITE": "rechts", "VF_WINKEL": "15", + "L_GF_m": "1.907,1.907"}, + {"SSG_VF_EDIT": ["standard", "270"]}) + e = dae.vf_standard_eintrag(vf, "T", "standard") + assert e["test_id"] == "VF_T_02" + assert (e["richtung"], e["deltaL"], e["deltaH"], e["winkel"]) == ("Auf", 11559.0, 611.0, 15) + assert e["L_GF1"] == 1907.0 and e["hz"] == 270.0 + assert (e["seite"], e["motorseite"]) == ("links", "rechts") + assert (e["x"], e["y"], e["z"]) == (3314.07, 24478.8, 1826.0) + + +def test_vf_linienzug_journal_unveraendert(): + roh = ["linienzug", "PT:42161.679193,2448.319538,0^JREAL:2177^JSTR:1^JSTR:9", + "0^JSTEP:Linie-VF^JDL:9370.410886"] + vf = _insert("VF_26", (42161.68, 2448.32, 2177.0), 0.0, {"ID": "0184"}, + {"SSG_VF_EDIT": roh}) + e = dae.vf_journal_eintrag(vf, "T", 1) + assert e["typ"] == "linienzug_journal" and e["test_id"] == "VF_T_LZ_01" + # Chunk-Grenze mitten im Token ("STR:9" + "0") wird korrekt zusammengesetzt + assert e["journal"] == ["PT:42161.679193,2448.319538,0", "REAL:2177", "STR:1", + "STR:90", "STEP:Linie-VF", "DL:9370.410886"] + + +def test_einzelblock_ohne_dimensionssuffix(): + e = dae.einzel_eintrag(_insert("Separator_SP_3D", (3038.72, 12119.73, 2473.0), + 0.0, {"ID": "0043", "ZUORDNUNG": "0002"})) + assert e["block"] == "Separator_SP" + assert e["function"] == "insert" and e["z"] == 2473.0 + assert "ID 0043" in e["comment"] + + +def test_reihenfolge_vf_vor_gf(): + inserts = [ + _insert("GF_1", (5833.56, 12919.72, 2437.0), 0.0, {}, + {"SSG_GF_EDIT": ["90", "3", "90", "90", "2437", "11559.08"]}), + _insert("Scanner_3D", (1, 2, 3)), + _insert("VF_2", (0, 0, 0), 0.0, {}, {"SSG_VF_EDIT": ["standard", "0"]}), + KREISEL_OBEN, KREISEL_UNTEN, + _insert("*U12", (0, 0, 0)), + ] + eintraege, _ = dae.baue_eintraege(inserts, BLOCK_INHALT, "T") + art = ["K" if "abstand" in e else "GF" if "modus" in e else + "VF" if "typ" in e else e["block"] for e in eintraege] + assert art == ["K", "K", "VF", "GF", "Scanner"] diff --git a/tests/test_dxf_scan_gf.py b/tests/test_dxf_scan_gf.py new file mode 100644 index 0000000..65de3c1 --- /dev/null +++ b/tests/test_dxf_scan_gf.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +test_dxf_scan_gf.py - Gefaellestrecken aus Staustrecken-Linien +(gf_eintraege_aus_linien in lib/dxf_scan_components.py). Laeuft ohne +BricsCAD und ohne DXF: die Linien und Ausschleuselemente sind die +gemessenen Werte aus Dematic_arvato_reduced.dxf, von Hand nachgestellt. + + 1. Fallende Linie mit AS am oberen Ende -> GF, AS wird verbraucht. + 2. Der Nachbar-AS der Linie daneben (800 mm Raster, auf der anderen Seite + naeher dran) wird NICHT gegriffen - die Seite aus dem Blocknamen + entscheidet, nicht der kleinste Abstand. + 3. Rueckwaerts gezeichnete GF (tiefes Ende zuerst) -> Start bleibt oben. + 4. AS am UNTEREN Ende -> Steigfoerderer, keine GF, AS bleibt unverbraucht. + 5. Waagrechte Linie -> keine GF. + 6. Anschluss an die Kreisel: Start/Ende werden auf die Ketten geschoben, + deltaL reicht von Kette zu Kette; Hoehen kommen von den Kreiseln. + 7. Separator auf der Achse wird verbraucht, einer daneben nicht. + 8. hoehen_entfernen laesst nur Anwender-Hoehen stehen. +""" + +import os +import sys + +import pytest + +sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), + "..", "lib")) +import dxf_scan_components as dsc # noqa: E402 + +AS_LINKS = "Ausschleuselement links 200000217 Draufsicht" + + +def _as(x, y, z=3191.63, block=AS_LINKS): + return {"familie": "schleuselement", "block": block, + "x": x, "y": y, "z": z, "rot": 270.0} + + +def _linie(a, b, layer="6-SP"): + return {"layer": layer, "a": list(a), "b": list(b)} + + +@pytest.fixture(autouse=True) +def _projekt(monkeypatch): + monkeypatch.setattr(dsc, "PROJEKT", "Test") + + +# Die beiden Kreisel am GF-Feld (Radmitten AN8 -> SP8, r = 400), wie +# baue_eintraege sie als kreisel_geo anlegt. Ketten: oben y = 12919.72, +# unten y = 24478.8. +def _kreisel_oben(z=2437.0): + return {"id": "K_oben", "a": (35460.37, 12519.72), "u": (-1.0, 0.0), + "laenge": 33044.28, "r": 400.0, "z_anwender": z} + + +def _kreisel_unten(z=1826.0): + return {"id": "K_unten", "a": (36261.24, 24878.8), "u": (-1.0, 0.0), + "laenge": 33470.18, "r": 400.0, "z_anwender": z} + + +def test_gf_mit_as_am_oberen_ende(): + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + as_eigen = _as(5367.10, 14505.61) + eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [as_eigen]) + assert len(eintraege) == 1 + gf = eintraege[0] + assert gf["test_id"] == "GF_Test_01" + assert gf["modus"] == 1 + # ohne Kreisel: Linienende bleibt stehen, Hoehe unbekannt -> Platzhalter + assert gf["start_mm"] == [5833.56, 13348.38, 0.0] + assert gf["deltaL_mm"] == pytest.approx(10654.16, abs=0.01) + assert gf["hz_grad"] == 90.0 + assert gf["winkel_grad"] == 3.0 + assert gf["hoehe_unbekannt"] is True + assert (gf["as_seite"], gf["as_winkel"]) == ("links", "90") + assert belegt == {id(as_eigen)} + assert len(hinweise) == 2 and all("kein Kreisel" in h for h in hinweise) + + +def test_anschluss_an_beide_kreisel_mit_hoehen(): + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + eintraege, _, hinweise = dsc.gf_eintraege_aus_linien( + [linie], [_as(5367.10, 14505.61)], [_kreisel_oben(), _kreisel_unten()]) + gf = eintraege[0] + assert gf["start_mm"][1] == pytest.approx(12919.72, abs=0.01) + assert gf["start_mm"][2] == 2437.0 + assert gf["hoehe_ende_mm"] == 1826.0 + assert gf["hoehe_quelle"] == "Anwender" + assert "winkel_grad" not in gf # rechnet der LISP-Treiber + assert gf["deltaL_mm"] == pytest.approx(24478.8 - 12919.72, abs=0.05) + assert (gf["kreisel_start"], gf["kreisel_ende"]) == ("K_oben", "K_unten") + assert hinweise == [] + + +def test_kreisel_ohne_hoehe_gibt_platzhalter(): + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + eintraege, _, _ = dsc.gf_eintraege_aus_linien( + [linie], [], [_kreisel_oben(z=None), _kreisel_unten()]) + assert eintraege[0]["kreisel_start"] == "K_oben" + assert "hoehe_ende_mm" not in eintraege[0] + assert eintraege[0]["winkel_grad"] == 3.0 + + +def test_separator_auf_achse_wird_verbraucht(): + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + sep_achse = {"familie": "sensor", "block": "S-SP", "x": 5834.0, "y": 23810.0} + sep_daneben = {"familie": "sensor", "block": "S-SP", "x": 6734.0, "y": 23810.0} + scanner = {"familie": "sensor", "block": "Scanner", "x": 5834.0, "y": 20000.0} + _, belegt, _ = dsc.gf_eintraege_aus_linien( + [linie], [], [_kreisel_oben(), _kreisel_unten()], + [sep_achse, sep_daneben, scanner]) + assert belegt == {id(sep_achse)} + + +def test_hoehen_entfernen_laesst_anwender_hoehen_stehen(): + eintraege = [ + {"id": "K1", "x": 0, "y": 0, "z": 2437.0, "hoehe_quelle": "Anwender"}, + {"block": "S-SP", "x": 0, "y": 0, "z": 2821.63, "comment": ""}, + {"test_id": "G", "typ": "gerade", "startpunkt": [0, 0, 5.0], + "endpunkt": [1, 0, 5.0]}, + ] + assert dsc.hoehen_entfernen(eintraege) == 2 + assert eintraege[0]["z"] == 2437.0 + assert eintraege[1]["z"] == 0.0 and eintraege[1]["hoehe_unbekannt"] is True + assert eintraege[2]["startpunkt"][2] == 0.0 and eintraege[2]["endpunkt"][2] == 0.0 + + +def test_nachbar_as_auf_falscher_seite_wird_nicht_gegriffen(): + # Linie bei x=5834; ihr AS 467 mm links, der AS der Nachbarlinie + # (x=6734) 433 mm RECHTS - also naeher, aber auf der falschen Seite. + linie = _linie((5833.56, 13348.38, 3191.63), (5833.44, 24002.54, 2821.63)) + as_eigen = _as(5367.10, 14505.61) + as_nachbar = _as(6267.10, 14505.61) + _, belegt, _ = dsc.gf_eintraege_aus_linien([linie], [as_nachbar, as_eigen]) + assert belegt == {id(as_eigen)} + + +def test_rueckwaerts_gezeichnete_gf_startet_oben(): + linie = _linie((5833.44, 24002.54, 2821.63), (5833.56, 13348.38, 3191.63)) + eintraege, _, _ = dsc.gf_eintraege_aus_linien([linie], [_as(5367.10, 14505.61)]) + assert eintraege[0]["start_mm"][:2] == [5833.56, 13348.38] + assert eintraege[0]["hz_grad"] == 90.0 + + +def test_as_am_unteren_ende_ist_steigfoerderer(): + # Gemessen: Linie x=2801 von 2822 hinauf auf 3192, AS am tiefen Ende. + linie = _linie((2801.42, 24043.0, 2821.63), (2801.42, 13389.0, 3191.63)) + as_unten = _as(3267.48, 22892.92, z=2821.63) + eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], [as_unten]) + assert eintraege == [] + assert belegt == set() + assert len(hinweise) == 1 and "Steigfoerderer" in hinweise[0] + + +def test_waagrechte_linie_ist_keine_gf(): + linie = _linie((36661.0, 10279.0, 2821.63), (36661.0, 24879.0, 2821.63)) + eintraege, belegt, hinweise = dsc.gf_eintraege_aus_linien([linie], []) + assert eintraege == [] + assert belegt == set() + assert any("waagrechte" in h for h in hinweise) + + +def test_ohne_as_defaults_und_hinweis(): + linie = _linie((0.0, 0.0, 1000.0), (5000.0, 0.0, 800.0)) + eintraege, _, hinweise = dsc.gf_eintraege_aus_linien([linie], []) + assert eintraege[0]["hz_grad"] == 0.0 + assert eintraege[0]["as_seite"] == dsc.DEFAULT_SEITE + assert any("ohne Ausschleuselement" in h for h in hinweise) diff --git a/tests/test_mubea.lsp b/tests/test_mubea.lsp index 3d92a29..a4f29bb 100644 --- a/tests/test_mubea.lsp +++ b/tests/test_mubea.lsp @@ -146,8 +146,18 @@ ;; gueltigen Winkel zu nehmen. L_GF1 aus JSON ist der Vorlauf-Zielwert; ;; L_GF2 (Nachlauf) ist der Rest (L_GF_gesamt - L_GF1). (defun mubea:build-vario-one (tid typ richtung deltaL deltaH winkel-soll gf1-ziel seite hz - startpunkt / ergebnis winkel-treffer best-winkel L_GF L_VF - gf1 gf2 hoehe-bis lastEnt ent vf-nummer) + startpunkt) + (mubea:ent-json tid "vario" + (mubea:vario-bauen tid typ richtung deltaL deltaH winkel-soll gf1-ziel seite hz + startpunkt))) + +;; Der eigentliche Bau ohne Ergebnis-Format - auch von +;; tests/test_dematic_arvato.lsp genutzt (dort mit vsp-Records). +;; Rueckgabe: Entity des VF_n-Blocks oder nil (auch, wenn deltaL beim +;; gewuenschten Winkel nicht loesbar ist). +(defun mubea:vario-bauen (tid typ richtung deltaL deltaH winkel-soll gf1-ziel seite hz + startpunkt / ergebnis winkel-treffer best-winkel L_GF L_VF + gf1 gf2 hoehe-bis lastEnt ent vf-nummer) (if (or (null seite) (= seite "")) (setq seite "links")) (if (or (null typ) (= typ "")) (setq typ "standard")) (if (null hz) (setq hz 0.0) (setq hz (float hz))) @@ -207,12 +217,12 @@ ;; Linienzug/Altbestand bleiben unmarkiert. (if (and ent (= (type ent) 'ENAME) (member typ '("standard" "etage"))) (vf-edit-xdata-schreiben ent typ hz)) - (mubea:ent-json tid "vario" ent)) + (if (and ent (= (type ent) 'ENAME)) ent nil)) (progn (princ (strcat "\n FEHLER: deltaL=" (rtos deltaL 2 0) " bei Winkel " (if winkel-soll (rtos winkel-soll 2 0) "auto") " nicht loesbar (kein gueltiges L_GF/L_VF).")) - (mubea:result-json tid "vario" "failed" nil nil nil nil))) + nil)) ) ;; --- Vario(s) aus einem Template-Eintrag bauen --- @@ -290,8 +300,15 @@ ;; sep_x = 300 * cos(v), v = Element-Winkel (winkel_grad, Default 3 Grad) ;; Die Zielhoehe ergibt sich aus L_stau/Winkel (kein Ziel-Hoehen-Parameter). ;; Rueckgabe: Ergebnis-JSON-String. -(defun mubea:build-gf-one (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel / - rad sep-x test-L_stau ent) +(defun mubea:build-gf-one (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel) + (mubea:ent-json tid "gefaellestrecke" + (mubea:gf-bauen tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel))) + +;; Der eigentliche Bau ohne Ergebnis-Format - auch von +;; tests/test_dematic_arvato.lsp genutzt (dort mit vsp-Records). +;; Rueckgabe: Entity des GF_n-Blocks oder nil. +(defun mubea:gf-bauen (tid start-mm deltaL hz as-seite es-seite as-winkel es-winkel winkel / + rad sep-x test-L_stau ent) (mubea:ensure-gf-init) ;; Element-Masse fuer die gewaehlte AS/ES-Variante setzen, damit aus-dx/ein-dx ;; zur Variante (90/30 Grad) passen. Danach wieder auf 90 zuruecksetzen. @@ -312,7 +329,7 @@ deltaL as-winkel es-winkel "0" "Schoenenberger Geruest"))) (vf-set-as-masse "90" as-seite) (vf-set-es-masse "90" es-seite) - (mubea:ent-json tid "gefaellestrecke" ent) + ent ) ;; --- Gefaellestrecke(n) aus einem Template-Eintrag bauen --- diff --git a/tests/testdata/dematic_arvato.json b/tests/testdata/dematic_arvato.json index b9c122c..26603ec 100644 --- a/tests/testdata/dematic_arvato.json +++ b/tests/testdata/dematic_arvato.json @@ -1,1381 +1,743 @@ [ + { + "id": "Kreisel_Arvato_01", + "function": "insert", + "x": 19204.0, + "y": 1703.66, + "z": 2177.0, + "abstand": 3619.14, + "rotation": 90.0, + "typ": "STANDARD", + "comment": "aus Zeichnung: KREISEL_1_STANDARD_3619 (ID 0001), abstand aus Blockdefinition (AN8 -> SP8)" + }, + { + "id": "Kreisel_Arvato_02", + "function": "insert", + "x": 35860.37, + "y": 12519.72, + "z": 2437.0, + "abstand": 33044.28, + "rotation": 180.0, + "typ": "STANDARD", + "comment": "aus Zeichnung: KREISEL_2_STANDARD_33044 (ID 0002), abstand aus Blockdefinition (AN8 -> SP8)" + }, { "id": "Kreisel_Arvato_03", "function": "insert", - "x": 18737.94, - "y": 165252.93, - "z": 0.0, - "abstand": 3619.15, - "rotation": 90.0, + "x": 36661.24, + "y": 24878.8, + "z": 1826.0, + "abstand": 33470.18, + "rotation": 180.0, "typ": "STANDARD", - "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (18737.94, 165652.93) -> SP8 (Layer 1SP-800) (18737.94, 169272.08), Mittenabstand 3619.15, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + "comment": "aus Zeichnung: KREISEL_3_STANDARD_33470 (ID 0003), abstand aus Blockdefinition (AN8 -> SP8)" }, { "id": "Kreisel_Arvato_04", "function": "insert", - "x": 35394.31, - "y": 176069.0, - "z": 370.0, - "abstand": 33044.28, - "rotation": 180.0, - "typ": "STANDARD", - "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 Pinband (Layer 1ANTR-800) (34994.31, 176069.00) -> SP8 Pinband (mit Inkrementalgeber 829522024) (Layer 1SP-800) (1950.03, 176069.00), Mittenabstand 33044.28, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=370.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." - }, - { - "id": "Kreisel_Arvato_05", - "function": "insert", - "x": 36195.18, - "y": 188428.08, - "z": 0.0, - "abstand": 33470.18, - "rotation": 180.0, - "typ": "STANDARD", - "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (35795.18, 188428.08) -> SP8 (Layer 1SP-800) (2325.00, 188428.08), Mittenabstand 33470.18, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." - }, - { - "id": "Kreisel_Arvato_06", - "function": "insert", - "x": 42097.73, - "y": 165252.93, - "z": 0.0, - "abstand": 3619.15, + "x": 42563.78, + "y": 1703.66, + "z": 2177.0, + "abstand": 3619.14, "rotation": 90.0, "typ": "STANDARD", - "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (42097.73, 165652.93) -> SP8 (Layer 1SP-800) (42097.72, 169272.08), Mittenabstand 3619.15, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe." + "comment": "aus Zeichnung: KREISEL_4_STANDARD_3619 (ID 0004), abstand aus Blockdefinition (AN8 -> SP8)" }, { - "test_id": "GERADE_Arvato_01", - "typ": "gerade", - "darstellung": "2D", - "laenge": 8313.39, - "hz": 90.0, - "startpunkt": [2334.97, 177818.67, 0.0], - "endpunkt": [2334.96, 186132.06, 0.0], - "hoehe_unbekannt": true, - "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 90 Grad, Laenge 8313.39, Querversatz 0.01 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." - }, - { - "test_id": "GERADE_Arvato_09", - "typ": "gerade", - "darstellung": "2D", - "laenge": 8313.39, - "hz": 90.0, - "startpunkt": [14264.99, 177818.71, 0.0], - "endpunkt": [14264.99, 186132.1, 0.0], - "hoehe_unbekannt": true, - "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 90 Grad, Laenge 8313.39, Querversatz 0.00 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." - }, - { - "test_id": "GERADE_Arvato_10", - "typ": "gerade", - "darstellung": "2D", - "laenge": 3183.28, + "test_id": "VF_Arvato_02", + "typ": "standard", + "richtung": "Auf", + "deltaL": 11559.0, + "deltaH": 611.0, + "winkel": 15, + "L_GF1": 1907.0, + "seite": "links", + "motorseite": "rechts", "hz": 270.0, - "startpunkt": [19545.38, 174003.47, 370.0], - "endpunkt": [19545.58, 170820.19, 0.0], - "hoehe_unbekannt": true, - "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 270 Grad, Laenge 3183.28, Querversatz 0.20 (Bezugspunkt-Unterschied), Neigung 6.63 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + "x": 3314.07, + "y": 24478.8, + "z": 1826.0, + "comment": "aus Zeichnung: VF_2 (ID 0082), Hoehe 1826 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "test_id": "GERADE_Arvato_11", - "typ": "gerade", - "darstellung": "2D", - "laenge": 17664.81, - "hz": 0.0, - "startpunkt": [21626.92, 167134.77, 0.0], - "endpunkt": [39291.73, 167134.97, 0.0], - "hoehe_unbekannt": true, - "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 0 Grad, Laenge 17664.81, Querversatz 0.20 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + "test_id": "VF_Arvato_03", + "typ": "standard", + "richtung": "Auf", + "deltaL": 11559.0, + "deltaH": 611.0, + "winkel": 15, + "L_GF1": 1907.0, + "seite": "links", + "motorseite": "rechts", + "hz": 270.0, + "x": 15285.06, + "y": 24478.8, + "z": 1826.0, + "comment": "aus Zeichnung: VF_3 (ID 0083), Hoehe 1826 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "test_id": "GERADE_Arvato_12", - "typ": "gerade", - "darstellung": "2D", - "laenge": 3124.62, - "hz": 0.0, - "startpunkt": [21626.97, 165578.18, 0.0], - "endpunkt": [24751.59, 165578.37, 0.0], - "hoehe_unbekannt": true, - "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 0 Grad, Laenge 3124.62, Querversatz 0.19 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + "test_id": "VF_Arvato_05", + "typ": "standard", + "richtung": "Auf", + "deltaL": 11559.0, + "deltaH": 611.0, + "winkel": 15, + "L_GF1": 1907.0, + "seite": "links", + "motorseite": "rechts", + "hz": 270.0, + "x": 23843.05, + "y": 24478.8, + "z": 1826.0, + "comment": "aus Zeichnung: VF_5 (ID 0084), Hoehe 1826 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "test_id": "GERADE_Arvato_13", - "typ": "gerade", - "darstellung": "2D", - "laenge": 8313.39, - "hz": 90.0, - "startpunkt": [22854.62, 177818.71, 0.0], - "endpunkt": [22854.61, 186132.1, 0.0], - "hoehe_unbekannt": true, - "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 90 Grad, Laenge 8313.39, Querversatz 0.01 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." - }, - { - "test_id": "GERADE_Arvato_14", - "typ": "gerade", - "darstellung": "2D", - "laenge": 6717.41, - "hz": 0.0, - "startpunkt": [32574.32, 165578.18, 0.0], - "endpunkt": [39291.73, 165578.37, 0.0], - "hoehe_unbekannt": true, - "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 0 Grad, Laenge 6717.41, Querversatz 0.19 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." - }, - { - "test_id": "GERADE_Arvato_15", - "typ": "gerade", - "darstellung": "2D", - "laenge": 3706.41, + "test_id": "VF_Arvato_06", + "typ": "standard", + "richtung": "Auf", + "deltaL": 22559.0, + "deltaH": 0.0, + "winkel": 12, + "L_GF1": 6852.0, + "seite": "rechts", + "motorseite": "rechts", "hz": 180.0, - "startpunkt": [34650.88, 173417.91, 0.0], - "endpunkt": [30944.47, 173408.89, 0.0], - "hoehe_unbekannt": true, - "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 180 Grad, Laenge 3706.41, Querversatz 9.02 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + "x": 42163.78, + "y": 4017.06, + "z": 2177.0, + "comment": "aus Zeichnung: VF_6 (ID 0085), Hoehe 2177 -> 2177; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "test_id": "GERADE_Arvato_16", - "typ": "gerade", - "darstellung": "2D", - "laenge": 3566.48, - "hz": 270.0, - "startpunkt": [41688.71, 185921.64, 0.0], - "endpunkt": [41678.01, 182355.16, 0.0], - "hoehe_unbekannt": true, - "comment": "aus DXF: Antrieb FF -> Umlenkung FF (Layer z-3 / z-3), Achse 270 Grad, Laenge 3566.48, Querversatz 10.70 (Bezugspunkt-Unterschied), Neigung 0.00 Grad; 2D-Schema - Z ist dort keine Einbauhoehe, darum waagrechte Strecke und hoehe_unbekannt=true. Einbauhoehe nur ueber den 3D-Zwilling zu bekommen." + "test_id": "VF_Arvato_08", + "typ": "standard", + "richtung": "Auf", + "deltaL": 6852.0, + "deltaH": 260.0, + "winkel": 18, + "L_GF1": 767.0, + "seite": "links", + "motorseite": "rechts", + "hz": 90.0, + "x": 19551.49, + "y": 5265.19, + "z": 2177.0, + "comment": "aus Zeichnung: VF_8 (ID 0183), Hoehe 2177 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" + }, + { + "test_id": "VF_Arvato_LZ_01", + "typ": "linienzug_journal", + "journal": [ + "PT:42161.679193,2448.319538,0", + "REAL:2177", + "STR:1", + "STR:90", + "STR:2", + "STEP:Linie-VF", + "STR:4", + "DL:9370.410886", + "REAL:-180", + "STR:1", + "REAL:2800", + "INT:1", + "STR:2", + "STR:2", + "STR:2", + "STEP:Linie-GF", + "STR:2", + "STR:1", + "STR:3", + "DL:6187.72996", + "STR:1", + "STR:2", + "STR:2", + "REAL:3", + "STEP:Linie-VF", + "STR:3", + "DL:4572.938729", + "STR:2", + "INT:1", + "STR:3", + "STR:1", + "STEP:ES", + "STR:90", + "STR:1", + "DL:2872.479403", + "REAL:2100", + "STR:3", + "STR:1", + "STEP:ES", + "STR:90", + "STR:2", + "DL:2857.418974", + "REAL:2000", + "STR:3", + "STR:1", + "STEP:ES", + "STR:90", + "STR:2", + "DL:2850.93244", + "REAL:2177", + "INT:2", + "STR:2" + ], + "comment": "aus Zeichnung: VF_26 (ID 0184), 52 Eingaben, Hoehe 2177 -> 2174; wird 1:1 abgespielt (vsp-bau-journal)" + }, + { + "test_id": "GF_Arvato_01", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [5833.56, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_1 (ID 0005); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_02", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [6733.56, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_2 (ID 0006); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_03", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [7533.56, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_3 (ID 0007); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_04", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [8333.56, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_4 (ID 0008); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_05", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [9383.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_5 (ID 0009); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_06", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [10183.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_6 (ID 0010); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_07", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [10983.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_7 (ID 0011); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_08", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [12323.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_8 (ID 0012); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_09", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [13123.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_9 (ID 0013); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_10", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [13923.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_10 (ID 0014); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_11", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [16733.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_11 (ID 0015); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_12", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [17533.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_12 (ID 0016); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_13", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [18333.57, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_13 (ID 0017); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_14", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [19381.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_14 (ID 0018); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_15", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [20281.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_15 (ID 0019); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_16", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [21081.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_16 (ID 0020); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_17", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [21881.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_17 (ID 0021); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_18", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [25541.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_18 (ID 0022); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_19", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [26341.07, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_19 (ID 0023); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_20", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [27841.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_20 (ID 0024); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_21", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [28741.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_21 (ID 0025); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_22", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [29541.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_22 (ID 0026); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_23", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [30341.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_23 (ID 0027); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_24", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [31891.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_24 (ID 0028); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_25", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [32791.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_25 (ID 0029); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_26", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [33591.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_26 (ID 0030); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + }, + { + "test_id": "GF_Arvato_27", + "modus": 1, + "deltaL_mm": 11559.08, + "hz_grad": 90.0, + "start_mm": [34391.06, 12919.72, 2437.0], + "as_seite": "links", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Arvato_02", + "kreisel_ende": "Kreisel_Arvato_03", + "hoehe_ende_mm": 1826.0, + "comment": "aus Zeichnung: GF_27 (ID 0031); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" }, { "function": "insert", - "block": "Vario_Motorstation_500mm_rechts", - "x": 41271.73, - "y": 171724.16, - "z": -370.0, + "block": "Separator_SP", + "x": 3038.72, + "y": 12119.73, + "z": 2473.0, "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Antrieb FF', Layer 'z-3', auf Makro-Block 'Vario_Motorstation_500mm_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0043, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", - "block": "Vario_Umlenkstation_500mm_rechts", - "x": 30282.95, - "y": 174208.89, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Umlenkung FF', Layer 'z-3', auf Makro-Block 'Vario_Umlenkstation_500mm_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "Vario_Umlenkstation_500mm_rechts", - "x": 36190.75, - "y": 186482.16, - "z": 0.0, + "block": "Separator_SP", + "x": 3482.38, + "y": 24478.8, + "z": 1826.0, "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Umlenkung FF', Layer 'z-3', auf Makro-Block 'Vario_Umlenkstation_500mm_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0044, ZUORDNUNG 0003, ARTINR 200000077)" }, { "function": "insert", - "block": "Vario_Kurve_rechts_30_TEF_aussen", - "x": 41377.46, - "y": 179475.63, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'tef30°', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Lage=aussen, Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "Vario_Kurve_rechts_30_TEF_aussen", - "x": 35984.01, - "y": 173395.48, - "z": 0.0, - "rotation": 120.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "Vario_Kurve_rechts_30_TEF_aussen", - "x": 36210.84, - "y": 173622.64, - "z": 0.0, - "rotation": 150.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "Vario_Kurve_rechts_30_TEF_aussen", - "x": 36296.49, - "y": 173937.59, - "z": 0.0, + "block": "Separator_SP", + "x": 5094.1, + "y": 12919.72, + "z": 2473.0, "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0045, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", - "block": "Vario_Kurve_rechts_30_TEF_aussen", - "x": 41169.03, - "y": 187345.02, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "block": "Separator_SP", + "x": 15412.41, + "y": 24478.8, + "z": 1826.0, + "rotation": 0.0, + "comment": "aus Zeichnung: Separator_SP_3D (ID 0046, ZUORDNUNG 0003, ARTINR 200000077)" }, { "function": "insert", - "block": "Vario_Kurve_rechts_30_TEF_aussen", - "x": 41483.98, - "y": 187259.38, - "z": 0.0, - "rotation": 240.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "Vario_Kurve_rechts_30_TEF_aussen", - "x": 41711.14, - "y": 187032.54, - "z": 0.0, - "rotation": 210.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "Vario_Kurve_rechts_30_TEF_aussen", - "x": 41784.82, - "y": 180461.57, - "z": 0.0, + "block": "Separator_SP", + "x": 15994.1, + "y": 12919.78, + "z": 2473.0, "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'tef30°außen', Layer '0', auf Makro-Block 'Vario_Kurve_rechts_30_TEF_aussen' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Seite=rechts - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0047, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", - "block": "AS_Element_90_links", - "x": 2801.42, - "y": 186442.19, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 4901.05, - "y": 178054.88, - "z": 370.0, + "block": "Separator_SP", + "x": 19604.0, + "y": 5042.22, + "z": 2177.0, "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0048, ZUORDNUNG 0001, ARTINR 200000077)" }, { "function": "insert", - "block": "AS_Element_90_links", - "x": 5801.05, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "block": "Separator_SP", + "x": 24002.04, + "y": 24478.8, + "z": 1826.0, + "rotation": 0.0, + "comment": "aus Zeichnung: Separator_SP_3D (ID 0049, ZUORDNUNG 0003, ARTINR 200000077)" }, { "function": "insert", - "block": "AS_Element_90_links", - "x": 6601.05, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 7401.05, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 8451.06, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 9251.06, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 10051.06, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 11391.05, - "y": 178054.91, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 12191.05, - "y": 178054.91, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 12991.05, - "y": 178054.91, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 14731.45, - "y": 186442.19, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 15801.05, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 16601.05, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 17401.05, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 18448.56, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 19348.56, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 20148.56, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 20948.56, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 23321.08, - "y": 186442.19, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 24608.56, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 25408.56, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 26908.55, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 27808.55, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 28608.55, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 29408.55, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 30958.55, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 31858.55, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 32658.55, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_links", - "x": 33458.55, - "y": 178054.88, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement links 200000217 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_links' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "AS_Element_90_rechts", - "x": 42932.74, - "y": 166073.59, - "z": 0.0, + "block": "Separator_SP", + "x": 24794.1, + "y": 12919.82, + "z": 2473.0, "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement rechts 200000241 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0050, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", - "block": "AS_Element_90_rechts", - "x": 42932.74, - "y": 167630.19, - "z": 0.0, + "block": "Separator_SP", + "x": 35050.37, + "y": 12919.72, + "z": 2437.0, "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Ausschleuselement rechts 200000241 Draufsicht', Layer '0', auf Makro-Block 'AS_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0051, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", - "block": "ES_Element_90_rechts", - "x": 4958.03, - "y": 166992.08, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Einschleuselement rechts 200000146 Seitenansicht', Layer '4-EE', auf Makro-Block 'ES_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "ES_Element_90_rechts", - "x": 8058.82, - "y": 168049.64, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Einschleuselement rechts 200000146 Seitenansicht', Layer '4-EE', auf Makro-Block 'ES_Element_90_rechts' abgebildet; ACHTUNG geraten (im DXF nicht ableitbar): Winkel=90 - bei Bedarf hier im JSON korrigieren; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "ES_Element_30_rechts", - "x": 20513.9, - "y": 187602.73, - "z": -4.49, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'Einschleuselement rechts 30° 200000688 Vorderansicht', Layer '0', auf Makro-Block 'ES_Element_30_rechts' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 2572.67, - "y": 175669.0, - "z": 370.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 3016.33, - "y": 188028.08, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 4628.04, - "y": 176469.0, - "z": 370.0, + "block": "Separator_SP", + "x": 35857.18, + "y": 25278.8, + "z": 1826.0, "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0052, ZUORDNUNG 0003, ARTINR 200000077)" }, { "function": "insert", - "block": "S-LP", - "x": 14946.35, - "y": 188028.08, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 15528.05, - "y": 176469.05, - "z": 370.0, - "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 19137.94, - "y": 168591.49, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 23535.98, - "y": 188028.08, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 24328.05, - "y": 176469.09, - "z": 370.0, - "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 34584.31, - "y": 176469.0, - "z": 370.0, - "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 35391.12, - "y": 188828.08, - "z": 0.0, - "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-LP", - "x": 41697.93, - "y": 167818.8, - "z": 0.0, + "block": "Separator_SP", + "x": 42163.99, + "y": 4269.52, + "z": 2177.0, "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 2334.91, - "y": 186756.85, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 2334.97, - "y": 176994.56, - "z": 370.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 5367.5, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 6267.5, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 7067.5, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 7867.5, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 8917.51, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 9717.51, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 10517.51, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 11857.51, - "y": 187359.45, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 12657.51, - "y": 187359.45, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 13457.51, - "y": 187359.45, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 14264.94, - "y": 186756.89, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 14264.99, - "y": 176994.61, - "z": 370.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 16267.51, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 17067.51, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 17867.51, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 18915.01, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 19546.07, - "y": 170249.91, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 19546.07, - "y": 175157.16, - "z": 370.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 19680.48, - "y": 167135.46, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 19680.53, - "y": 165578.85, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 19815.01, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 20615.01, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 21415.01, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 22854.57, - "y": 186756.89, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 22854.62, - "y": 176994.61, - "z": 370.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 25075.01, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 25462.17, - "y": 165578.85, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 25875.01, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 27375.0, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 28275.0, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 29075.0, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 29875.0, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 30851.32, - "y": 174208.89, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 30944.14, - "y": 165578.85, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 31425.0, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 31494.84, - "y": 173408.89, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 32325.0, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 33125.0, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 33925.0, - "y": 187359.42, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 36195.18, - "y": 187066.18, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 39889.85, - "y": 167135.46, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 39889.9, - "y": 165578.85, - "z": 0.0, - "rotation": 0.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 41439.64, - "y": 169070.08, - "z": 0.0, - "rotation": 120.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "S-SP", - "x": 41697.72, - "y": 182892.95, - "z": 0.0, - "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-SP', Layer '5SEP-SP'; Block 'S-SP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0053, ZUORDNUNG 0004, ARTINR 200000077)" }, { "function": "insert", "block": "Scanner", - "x": 3166.57, - "y": 188414.66, - "z": 0.0, + "x": 3632.63, + "y": 24865.38, + "z": 1826.0, "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Scanner_3D (ID 0073, ZUORDNUNG 0003, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 4477.8, - "y": 176855.58, - "z": 370.0, + "x": 4943.86, + "y": 13306.31, + "z": 2473.0, "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Scanner_3D (ID 0074, ZUORDNUNG 0005, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 15096.6, - "y": 188414.66, - "z": 0.0, + "x": 15562.65, + "y": 24865.38, + "z": 1826.0, "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Scanner_3D (ID 0075, ZUORDNUNG 0003, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 15377.81, - "y": 176855.63, - "z": 370.0, + "x": 15843.86, + "y": 13306.36, + "z": 2473.0, "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Scanner_3D (ID 0076, ZUORDNUNG 0002, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 23686.22, - "y": 188414.66, - "z": 0.0, + "x": 24152.28, + "y": 24865.38, + "z": 1826.0, "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Scanner_3D (ID 0077, ZUORDNUNG 0003, ARTINR 829534306)" }, { "function": "insert", "block": "Scanner", - "x": 24177.81, - "y": 176855.68, - "z": 370.0, + "x": 24643.86, + "y": 13306.4, + "z": 2473.0, "rotation": 90.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "Scanner", - "x": 25618.13, - "y": 165246.94, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "Scanner", - "x": 30966.81, - "y": 165246.94, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" - }, - { - "function": "insert", - "block": "Scanner", - "x": 41298.05, - "y": 167879.95, - "z": 0.0, - "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt)" + "comment": "aus Zeichnung: Scanner_3D (ID 0078, ZUORDNUNG 0022, ARTINR 829534306)" } ] From f1583d2d4136e0e7fd3916789fccad38ca65d54e Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Tue, 6 Oct 2026 17:08:16 +0200 Subject: [PATCH 05/38] [ADD] doc/kommandos.md: Kommandouebersicht (BricsCAD-Befehle, Test-Befehle, bin-Skripte, Python-Kommandozeilen, pytest); [CHANGE] menu/SSG_LIB.cui: MenuMacro-UIDs von BricsCAD neu nummeriert Co-Authored-By: Claude Opus 5.5 --- doc/kommandos.md | 295 +++++++++++++++++++++++++++++++++++++++++++++++ menu/SSG_LIB.cui | 38 +++--- 2 files changed, 314 insertions(+), 19 deletions(-) create mode 100644 doc/kommandos.md diff --git a/doc/kommandos.md b/doc/kommandos.md new file mode 100644 index 0000000..5419396 --- /dev/null +++ b/doc/kommandos.md @@ -0,0 +1,295 @@ +# Kommandouebersicht + +Diese Seite listet alle Kommandos des Projekts auf einen Blick: + +1. [BricsCAD-Befehle (AutoLISP)](#1-bricscad-befehle-autolisp) - an der BricsCAD-Kommandozeile einzugeben +2. [Test-Befehle in BricsCAD](#2-test-befehle-in-bricscad) +3. [Batch-/Shell-Skripte (`bin/`)](#3-batch-shell-skripte-bin) +4. [Python-Kommandozeilen (`lib/`)](#4-python-kommandozeilen-lib) +5. [Python-Tests (`pytest`)](#5-python-tests-pytest) + +Ausfuehrliche Beschreibungen stehen in `Lisp/README.md`, `doc/variofoerderer.md`, +`doc/tools.md` (set_einfuegepunkt/set_koords), `doc/dbg2lsp.md`, `doc/csv-export.md` +und `doc/LispTests.md`. Diese Seite ist nur der Einstieg. + +**Voraussetzung fuer alle BricsCAD-Befehle**: Menue `menu/SSG_LIB.mnu` einmalig per +`_MENULOAD` geladen (siehe `CLAUDE.md`, "Menue einrichten"). Die MNL laedt die Module +dann beim Start. Befehle, die nicht im Menue stehen, lassen sich trotzdem an der +Kommandozeile aufrufen, sofern ihr Modul geladen ist - sonst vorher +`(ssg-ensure "Modulname")` eingeben. + +--- + +## 1. BricsCAD-Befehle (AutoLISP) + +Gross-/Kleinschreibung spielt an der Kommandozeile keine Rolle. + +### ILS Kreisel / Eckrad (`KreiselInsert.lsp`) + +| Befehl | Beschreibung | +|---|---| +| `KreiselInsert` | Kreisel einfuegen: Position und Parameter (Abstand, Typ, Rotation, Hoehe) manuell eingeben | +| `KreiselConnect` | Kreisel zwischen zwei gewaehlten Punkten einfuegen (Abstand und Drehung aus den Punkten) | +| `KreiselQuick` | Kreisel schnell mit Standardwerten (horizontal) einfuegen | +| `KreiselEdit` | Bestehenden Kreisel per Dialog (`kreisel_edit.dcl`) bearbeiten und neu aufbauen | +| `KreiselRedraw` | Kreisel aus seinen Block-Attributen neu zeichnen (z.B. mit neuem Abstand) | +| `KreiselParams` | Aktuelle Kreisel-Parameter anzeigen | +| `KreiselLabelSetup` | Beschriftung einstellen (Hoehe, Farbe, Abstand, Schriftart) | +| `KreiselLabelPos` | Versatz der Beschriftung (dx/dy) einstellen | +| `KreiselLabelHoehe` | Texthoehe der Beschriftung einstellen | +| `ILS_Eckrad` | Eckrad an einem Tangentenpunkt mit Richtung einfuegen | + +### VarioFoerderer (`VarioFoerderer.lsp` -> `vf_core`/`vf_standard`/`vf_etage`/`vf_linienzug`/`vf_spec`) + +| Befehl | Beschreibung | +|---|---| +| `FOERDERANLAGE` / `VarioFoerderer` | Hauptbefehl, fragt den Anlagentyp (Standard/Etage/Linienzug) ab | +| `StandardVarioFoerderer` | Standardtyp (AS/ES 90 Grad), Werte per DCL-Dialog | +| `StandardVarioFoerderer3D` | Standardtyp aus einer gewaehlten 3D-Linie | +| `EtageVarioFoerderer` | Etagentyp (AS/ES 30 Grad), Werte per DCL-Dialog | +| `EtageVarioFoerderer3D` | Etagentyp aus einer gewaehlten 3D-Linie | +| `LinienzugVarioFoerderer` | Linienzug, fragt Modus 1/2/3 ab | +| `VARIOFOERDERER_EDIT` | VF_n-Block editieren (dispatcht per XDATA-Marker auf Standard/Etage/Linienzug); auch per Doppelklick | +| `VARIOFOERDERER_NACHRUESTEN` / `VF_NACHRUESTEN` | Altbestand-VF_n-Bloecke ohne `SSG_VF_EDIT`-Marker editierbar machen | +| `Vario_Kette_Merge` | Mehrere einzeln gebaute VF_n-Bloecke ab einem Start-Baustein zu einem Gesamt-Block zusammenfuehren | +| `VF_SEKTION_RESTORE` | Aufgebrochene Linienzug-Kette aus der XDATA der losen Objekte wieder zu einem Block mit Journal zusammensetzen | +| `VF_WIZARD_AN` / `VF_WIZARD_AUS` | Linienzug-Fragen per DCL-Assistent (Standard) bzw. per Konsole stellen | +| `VF_SPEC_BAU` | Linienzug-Ketten ohne Dialog aus einer Spec-Datei bauen (`DXFM_VF_SPEC`, Default `tests/testdata/hundm05.json`) | +| `VFL_KS_DIAG` | Diagnose: inneren Aufbau eines Blocks anzeigen (Lage von KS_EIN/KS_AUS) | + +### Gefaellestrecke (`Gefaellestrecke.lsp`) + +| Befehl | Beschreibung | +|---|---| +| `GEFAELLESTRECKE` | Fragt den Eingabemodus per Konsole ab | +| `GEFAELLESTRECKE_EINFACH` | Modus 1: Werteingabe per DCL-Dialog | +| `GEFAELLESTRECKE_3DLINIE` | Modus 2: aus einer 3D-Linie | +| `GEFAELLESTRECKE_LINIENZUG` | Modus 3: aus einem Linienzug (LINE + ARC) | +| `GEFAELLESTRECKE_EDIT` | GF_n-Block editieren (Dialog vorbelegt, Neuaufbau); auch per Doppelklick | + +### ILS-Zusatzmodule, Sensoren, Ein-/Ausgang (`SSG_LIB_Commands.lsp`) + +| Befehl | Beschreibung | +|---|---| +| `ILS_BTMT_Beladung` | BTMT-Beladung wiederholt einfuegen (Drehung interaktiv) | +| `ILS_BTMT_Entladung` | BTMT-Entladung wiederholt einfuegen | +| `ILS_EINGANG_INSERT` / `ILS_AUSGANG_INSERT` | Eingang-/Ausgang-Symbol frei platzieren | +| `ILS_SCANNER_INSERT` | Scanner einfuegen | +| `ILS_SEPARATOR_INSERT` | Separator einfuegen | +| `TEF_FOERDERER_LINIE` (`TEFInsert.lsp`) | Linie zwischen zwei Punkten zeichnen und mit 1000-mm-TEF-Geraden belegen | + +### Omniflo (`OmniModulInsert.lsp`) + +| Befehl(e) | Beschreibung | +|---|---| +| `OMNI_LOAD` | Omniflo-Komponentendaten laden | +| `OMNI_INFO_BOGEN` / `OMNI_INFO_WEICHE` | Daten eines Bogens / einer Weiche anzeigen | +| `OMNI_APB60_90`, `OMNI_APB_630_90`, `OMNI_APB_630_45`, `OMNI_APB_550_675`, `OMNI_APB_550_225`, `OMNI_APB_650_180` | Boegen einfuegen (Dialog `omniflo_boegen.dcl`) | +| `OMNI_AP60`, `OMNI_AP110`, `OMNI_APG110` | Gerade Profile einfuegen | +| `OMNI_W90_Einfach`/`_Doppel`/`_Dreiwege` | Weichen 90 Grad (Dialog `omniflo_weichen.dcl`) | +| `OMNI_W45_Einfach`/`_Doppel`/`_Dreiwege` | Weichen 45 Grad | +| `OMNI_WP_Einfach`/`_Doppel`/`_Dreiwege` | Parallelweichen | +| `OMNI_WK_Einfach`/`_Doppel`/`_Dreiwege` | Weichenkoerper | +| `OMNI_WKomb_Delta_1400`, `OMNI_WKomb_Delta_1600`, `OMNI_WKomb_Star` | Weichenkombinationen (Delta, Stern) | +| `OMNI_APBW_R400_45_140`, `OMNI_APBW_R400_675_260`, `OMNI_APBW_R550_45_77`, `OMNI_APBW_R550_45_194`, `OMNI_APBW_R550_225_360`, `OMNI_APBW_R550_225_410A`/`B`/`C`, `OMNI_APBW_R550_675_58`/`_125`/`_208`/`_360`, `OMNI_APBW_R650_90_300`, `OMNI_APBW_R750_90_200` | Boegen fuer Weichen (fest, ohne Dialog) | +| `OMNI_TEF_UmlenkL`/`R`, `OMNI_TEF_AntriebL`/`R`, `OMNI_TEF_Gerade` | TEF-Elemente (fest, ohne Drehung) | +| `OMNI_STOPPER`, `OMNI_SCANNER`, `OMNI_BUERSTENBREMSE` | Anbaugruppen | +| `OMNI_TV_W_W`, `OMNI_TV_W_AP`, `OMNI_TV_W_AP60`, `OMNI_TV_W_AP110`, `OMNI_TV_W_AP110_W`, `OMNI_TV_50`, `OMNI_TV_80`, `OMNI_TV_ENDPLATTE`, `OMNI_TV_ANSCHLAG`, `OMNI_TV_MUFFE`, `OMNI_TV_A_AP110_AP60`, `OMNI_TV_A_AP60_ST`, `OMNI_TV_A_AP110_ST`, `OMNI_TV_SW_II_SW_SW`, `OMNI_TV_SW_III_AP110`, `OMNI_TV_SW_III_AP110_SW`, `OMNI_TV_SW_IV_AP60`, `OMNI_TV_SW_IV_ST` | Verbinder | +| `OMNI_LADESCHLEIFE_AP110` | Ladeschleife (Dialog `omniflo_ladeschleifen.dcl`) | +| `OMNI_KettenFoerderer` | Platzhalter (noch ohne Funktion) | +| `OMNI_EDIT` | Omniflo-Element per Dialog bearbeiten; auch per Doppelklick | + +### Geruest (`GeruestInsert.lsp`) + +| Befehl | Beschreibung | +|---|---| +| `GERUEST` | Geruest-Dialog (Bereich frei waehlbar) | +| `GERUEST_SAEULEN` / `GERUEST_ROHRABHAENGER` / `GERUEST_WANDBEFESTIGUNG` | Derselbe Dialog, im jeweiligen Bereich geoeffnet | +| `GERUEST_TRAEGER` | Rohr-Geruest-Traeger: Dialog (`geruest_traeger.dcl`), danach Start-/Endpunkt oder Laenge bis ESC/Enter | +| `GERUEST_TRAEGER_BESCHRIFTEN` | Alle Traeger der Zeichnung neu beschriften, verwaiste Beschriftungen entfernen | + +### TRO und Connections (`Tro_Edit.lsp`, `Connection_Edit.lsp`) + +| Befehl | Beschreibung | +|---|---| +| `TRO_INSERT` | TRO-Marker (`TRO_SYM_`) einfuegen und ID/TYPE setzen (Blockdefinition muss existieren) | +| `TRO_EDIT` | ID/TYPE eines TRO-Markers per Dialog aendern | +| `CONNECTION_INSERT` | Verbindungspfeil (Fluss) zwischen zwei Elementen zeichnen | +| `CONNECTION_EDIT` | Quelle/Ziel einer Verbindung aendern | + +### Export und IDs (`export.lsp`, `ssg_id.lsp`, `count_sep_scan.lsp`, `check_hoehen.lsp`) + +| Befehl | Beschreibung | +|---|---| +| `EXPORTSIVAS` | Sivas-Export-CSV mit Summierungszeilen (ruft `lib/export_sivas.py`) | +| `EXPORTCSV` | Einfache Item-Liste aller Bloecke inkl. Bounding-Box/Planquadrat (ruft `lib/export_csv.py`) | +| `CSV_EXPORT_KONFIG` | Export-Einstellungen per Dialog (u.a. gefrorene Layer ausschliessen) | +| `OMNI_UPDATE_ATTRIBS` | HOEHE und DREHUNG aller Omniflo-Elemente aus der Geometrie aktualisieren | +| `IDSCHECK` | Alle Bloecke auf doppelte IDs pruefen und korrigieren | +| `IDGENERATE` | Gewaehltem Block eine neue ID zuweisen | +| `ZAEHLE_SEP_SCAN` | Scanner/Separatoren je Kreisel/VF/GF zaehlen und in ANZAHL_SCANNER/ANZAHL_SEPARATOR schreiben (laeuft auch automatisch vor jedem Export) | +| `HOEHEN_CHECK` | Hoehen von Kreiseln/VF/GF messen und in HOEHE/HOEHE_VON_mm/HOEHE_BIS_mm/MONTAGEHOEHE_m schreiben | +| `CALLPYTHON` (`external_call.lsp`) | Test des LISP->Python-Aufrufs (`lib/testpycall.py`) | + +### Konfiguration, Planquadrate, Doppelklick + +| Befehl | Beschreibung | +|---|---| +| `SSG_DIM_SWITCH` | Globalen Modus 2D/3D umschalten (`DXFM_DIM`) | +| `SSG_DIM_ALL_2D` / `SSG_DIM_ALL_3D` | Alle VF_n-/GF_n-Bloecke der Zeichnung nach 2D bzw. 3D umbauen | +| `SSG_SPRACHE` | Sprache Deutsch/Englisch waehlen (`DXFM_LANG`) | +| `DRAW_PLANQUADRATE` | Planquadrat-Raster (Block `ZZ_PLANQUADRATE`) zeichnen bzw. neu aufbauen | +| `DELETE_PLANQUADRATE` | Planquadrat-Raster entfernen | +| `PLANQUADRATE_TOGGLE` | Raster an/aus (zeichnen, falls keins existiert, sonst entfernen) | +| `SSG_BLOCKEDIT` | Doppelklick-/Kontextmenue-Dispatcher: Kreisel, Omniflo, GF_*, VF_*, GR_*, TRO_* auf den passenden Edit-Befehl | +| `EATTEDIT` | Ueberschreibt den nativen Befehl, leitet an `SSG_BLOCKEDIT` weiter (Fallback `_.EATTEDIT`) | + +### Layer-Werkzeuge (`ssg_layer.lsp`) + +| Befehl | Beschreibung | +|---|---| +| `SSG-LayerSet` | Layer eines angeklickten Objekts aktiv setzen | +| `SSG-LayerInfo` | Layer eines Objekts anzeigen | +| `SSG-LayerMove` | Objekte auf einen anderen Layer verschieben | +| `SSG-LayerCopy` | Objekte auf einen anderen Layer kopieren | +| `SSG-LayerMoveType` | Alle Objekte eines Typs (Referenzobjekt) vom gleichen Layer auf einen neuen Layer verschieben | +| `SSG-LayerOff` / `SSG-LayerFreeze` | Layer per Anklicken aus-/einfrieren | +| `SSG-FreezeAll` | Alle Layer ausser dem aktiven einfrieren | +| `SSG-ThawAll` / `SSG-LayerOnAll` | Alle Layer auftauen / einschalten | +| `SSG-LayerDelete` | Alle Objekte eines Layers und den Layer loeschen (mit Sicherheitsabfrage) | + +### Block-Pflege und Diagnose (Entwickler) + +Arbeiten auf den Block-DWGs in `data/ils` (Voraussetzung `DXFM_DATA`). + +| Befehl | Beschreibung | +|---|---| +| `ILS_ATTR_SYNC` (`addattribute.lsp`) | ATTDEFs der DWGs mit `data/ils/allocations.json` abgleichen; Modus Ergaenzen/Ersetzen | +| `ILS_ATTR_REPLACE` | Direkt Modus "Ersetzen" (Sicherheitsfrage bleibt) | +| `ILS_ATTR_COLLECT` (`collect_attributes.lsp`) | Aktuelle ATTDEF-Werte aller DWGs nach `allocations_collected.json` schreiben | +| `ILS_BLOCK_LIST` (`list_blocks.lsp`) | Sub-Block-Definitionen aller DWGs nach `blocks_collected.json` schreiben (Kollisionen 2D/3D finden) | +| `ILS_BLOCK_PURGE` (`purge_blocks.lsp`) | Unbenutzte Bloecke/Layer in allen DWGs entfernen | +| `KS_PRUEFEN` (`ks_pruefung.lsp`) | KS_EIN/KS_AUS der 2D- gegen die 3D-Variante vergleichen, Ergebnis als CSV | +| `MenuInventory` (`menu-inventory.lsp`) | Menuegruppen, Plugins und Startdateien von BricsCAD auflisten | + +--- + +## 2. Test-Befehle in BricsCAD + +Aus dem Menue "Tests" bzw. der Kommandozeile; Details in `doc/LispTests.md`. + +| Befehl | Beschreibung | +|---|---| +| `SSG_RUN_ALL_TESTS` | Alle in `tests/alltests.json` aktivierten Szenarien ausfuehren (fragt den Modus ab) | +| `SSG_RUN_ALL_TESTS_EXPORT` | Dito, Automatik: speichern + CSV/Sivas-Export + schliessen | +| `SSG_RUN_ALL_TESTS_OFFEN` | Dito, Kontrolle: Zeichnungen bleiben offen, kein Export | +| `TEST_EXPORT_ALL` | Jede Zeichnung aus `tests/output/` oeffnen und exportieren | +| `TEST_UNIT` | File- und zeichnungsfreie Unit-Tests (`tests/test_unit.lsp`), Ergebnis `tests/output/unit_results.txt` | +| `TEST_VF_SPEC` | Unit-Test Spec-Uebersetzer (`vsp-journal`) | +| `TEST_VFL_SCHEMA` | Unit-Test Glied-Schema des Linienzugs | +| `TEST_KREISEL` | Kreisel-Szenario | +| `TEST_FOERDERER` | VarioFoerderer-Szenario | +| `TEST_GEFAELLESTRECKE` | Gefaellestrecke-Szenario | +| `TEST_LINIENZUG` / `TEST_LINIENZUG_STUFE2` | Linienzug-Szenarien | +| `TEST_OMNIFLO` | Alle Omniflo-Testbloecke einfuegen | +| `TEST_OMNIFLO_STRECKE` | Omniflo-Streckenzug aufbauen | +| `TEST_HM_RECFORMAT` (`_2D`/`_3D`) | Echte HundM-Aufzeichnungen per Journal-Replay nachbauen | +| `TEST_HUNDM05` (`_2D`/`_3D`) | HundM05-Anlage aus der Spec bauen | +| `TEST_MUBEA` | Mubea-Nachbau aus `tests/testdata/mubea.json` | +| `TEST_DEMATIC_ARVATO` | Dematic/Arvato-Nachbau (Flowpuffer/Kreisel) | + +--- + +## 3. Batch-/Shell-Skripte (`bin/`) + +Alle Skripte rufen zuerst `setenv.bat` (bzw. `setenv.sh`) auf. + +| Skript | Beschreibung | +|---|---| +| `setenv.bat` / `setenv.sh` | Umgebungsvariablen setzen (`DXFMAKRO`, `DXFM_LISP`, `DXFM_DATA`, `BRICSCAD` ...); `.sh` muss gesourct werden | +| `start_briscad.bat` | Umgebung setzen und BricsCAD starten | +| `get_cmd.bat` / `get_cmd.sh` | Shell mit gesetzter Umgebung oeffnen | +| `install_py.bat` / `install_py.sh` | `.venv` anlegen und `requirements.txt` installieren (nur wenn noch nicht vorhanden) | +| `activate_venv.bat` / `activate_venv.sh` | `.venv` aktivieren, Python-Version und Pakete anzeigen | +| `run_tests.bat` | Testausfuehrung, siehe unten | +| `create_tests.bat` | Kompletter ILS-Testlauf: Basis-DXF erzeugen, BricsCAD mit `ILS_test.scr`, Ergebnisse validieren | +| `set_einfuegepunkt.bat [schalter]` | Wrapper fuer `lib/set_einfuegepkt.py` (siehe `doc/tools.md`) | +| `set_coords.bat [schalter]` | Wrapper fuer `lib/set_koords.py` (siehe `doc/tools.md`) | +| `dbg2lsp.bat [argumente]` | Wrapper fuer `lib/dbg2lsp.py` (siehe `doc/dbg2lsp.md`) | +| `show_exportcsv.bat [csv] [flow] [mflow] [track]` | Export-CSV mit sps_skel als SVG darstellen; `flow` ohne VF/GF-Einzelbausteine, `mflow` Materialfluss-Graph, `track` Bahnzusammenhang (beide brauchen Graphviz) | + +### `run_tests.bat` + +``` +bin\run_tests.bat --lisp BricsCAD headless (/b tests\test_unit.scr), TEST_UNIT, Auswertung unit_results.txt +bin\run_tests.bat --check [test_xyz.py] pytest-Validierung (alle oder eine Datei) +bin\run_tests.bat --diff_references [datei] CSVs tests\reference vs. tests\output vergleichen, bei Unterschieden meld +bin\run_tests.bat Hilfe +``` + +--- + +## 4. Python-Kommandozeilen (`lib/`) + +Aufruf mit aktivierter `.venv` (bzw. ueber `setenv`, damit `DXFM_*` gesetzt sind). +`python --help` zeigt bei den argparse-Skripten alle Optionen. + +### Export (normalerweise von `EXPORTSIVAS`/`EXPORTCSV` aufgerufen) + +| Aufruf | Beschreibung | +|---|---| +| `python export_sivas.py [--mit-bezeichnung]` | Sivas-CSV mit Summierungszeilen, zusaetzlich `_zusammengefasst.csv` | +| `python export_csv.py ` | Einfache Item-Liste (Planquadrat, Bounding-Box, Nachbarn, Merkmale) | +| `python export_graph.py []` | Materialfluss-Graph aus dem CSV-Export als `.json`, `.dot` und `.mmd` | + +Reine Bibliotheken ohne eigene Kommandozeile: `export_blockpatterns.py`, +`export_neighbors.py`, `export_planquadrat.py`, `merkmalstamm.py`, `sivas_mapping.py`, +`omniflo_utils.py`, `vf_linienzug_grammatik.py`. + +### Omniflo-DXF-Aufbereitung + +| Aufruf | Beschreibung | +|---|---| +| `python set_einfuegepkt.py [--boegen] [--weichen45] [--weichen90] [--weichenkoerper] [--weichen-parallel] [--delta] [--dreifachweiche] [--sternweiche] [--number SIVASNR] [--show-omniflo]` | `$INSBASE` der Omniflo-DXFs setzen | +| `python set_koords.py [--k1set] [--k2set] [--k3set] [--k4set] [--set-all] [--force] [--test] [--number SIVASNR] [--show-omniflo]` | KS-Bloecke K1-K4 in die Omniflo-DXFs setzen | +| `python split_block_library.py` | `data/block_libraries/ils_library.dxf` in einzelne DXFs je Block aufteilen | + +### VarioFoerderer-Journal und Spec + +| Aufruf | Beschreibung | +|---|---| +| `python vf_journal_export.py [--csv ] [--kein-startpunkt-fix]` | `SSG_VF_EDIT`-Journale der VF_n-Bloecke als Frage-Antwort-Protokoll (z.B. `tests/testdata/hm_recformat.json`) | +| `python vf_spec_export.py ` | Protokoll in eine Spec uebersetzen (z.B. `tests/testdata/hundm05.json`) | +| `python dxf_vf_abbild.py [--spec S] [--json J] [--referenz R] [--schreibe-referenz] [--praefix VF_,GF_]` | Attribut-/Bausteinabbild der VF_/GF_-Bloecke; `--referenz` vergleicht (Exit 1 bei Abweichung) | +| `python dump_vf_wrapper_inhalt.py ` | Diagnose: Sub-INSERTs je VF_n/GF_n-Wrapper in Baureihenfolge | +| `python dump_vf_kette_inhalt.py []` | Diagnose: Glied-Folge der Spec gegen die tatsaechliche Separatorliste | + +### Fremdzeichnungen auswerten + +| Aufruf | Beschreibung | +|---|---| +| `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1] [--projekt NAME]` | ILS-/Omniflo-Komponenten einer fremden Zeichnung als Nachbau-JSON erkennen | +| `python dxf_abbild.py [--fenster X0 Y0 X1 Y1] [--max-tiefe N] [--ohne-geometrie-container]` | Getreue Abbildung aller Bauteile (ohne Interpretation) als JSON | +| `python extract_polylines.py [--layer Z-6]` | LWPOLYLINEs eines Layers mit Stuetzpunkten und Laengen als JSON | + +### Entwickler-Tools + +| Aufruf | Beschreibung | +|---|---| +| `python dbg2lsp.py --method NAME [--recursive] [--max-depth N] [--search-dir D] [--exclude NAME] [--add-open DATEI METHODE] [--dbg-file F] [--dbg-envvar V] [--force] [--dry-run]` | LISP-Funktionen mit `ssg_dbg.lsp`-Aufrufen instrumentieren (siehe `doc/dbg2lsp.md`) | +| `python testpycall.py []` | Gegenstueck zu `CALLPYTHON` | + +--- + +## 5. Python-Tests (`pytest`) + +``` +pytest tests/ alle Python-Tests +pytest tests/test_vf_spec.py einzelne Datei +bin\run_tests.bat --check dasselbe ueber das Batch-Skript +``` + +Die Szenario-Tests (`test_kreisel.py`, `test_foerderer.py`, `test_hundm05.py` ...) +validieren die Ausgaben der zugehoerigen BricsCAD-Testbefehle in `tests/output/` +gegen `tests/reference/`; reine Python-Tests wie `test_vf_spec.py`, +`test_vf_journal_grammatik.py` oder `test_export_graph.py` laufen ohne BricsCAD. diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 369b401..50aeee5 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -734,55 +734,55 @@ ^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 - + Kreisel bearbeiten (ssg-ensure "KreiselInsert") KreiselEdit - + Omniflo Element bearbeiten (ssg-ensure "OmniModulInsert") OMNI_EDIT - + Gefaellestrecke bearbeiten (ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EDIT - + VarioFoerderer bearbeiten (ssg-ensure "VarioFoerderer") VARIOFOERDERER_EDIT - + TRO-Marker bearbeiten (ssg-ensure "Tro_Edit") TRO_EDIT - + Verbindung bearbeiten (ssg-ensure "Connection_Edit") CONNECTION_EDIT - + SSG Bearbeiten (Auto) (ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT @@ -1636,60 +1636,60 @@ Dematic/Arvato Flowpuffer (Vorlage) - + KS 2D/3D pruefen (CSV) - + - + POP501 SSG_LIB Edit Context Kreisel bearbeiten - + Omniflo Element bearbeiten - + Gefaellestrecke bearbeiten - + VarioFoerderer bearbeiten - + TRO-Marker bearbeiten - + Verbindung bearbeiten - + SSG Bearbeiten (Auto) - + From fcb4444ee18e5a7264354b568d384c37a9067a91 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Wed, 7 Oct 2026 11:40:11 +0200 Subject: [PATCH 06/38] [ADD] Block- und Text-Werkzeuge aus Walz (ACADSST) uebernommen Neue Module ssg_blocktools.lsp (SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN) und ssg_texttools.lsp (SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL) sowie der generische Eingabe-Wrapper ssg_input.lsp, dazu Menue-/Lade-Integration, zweisprachige Texte und Unit-Tests fuer die reinen Kerne. Co-Authored-By: Claude Sonnet 5 --- CLAUDE.md | 4 + Lisp/README.md | 57 + Lisp/ssg_blocktools.lsp | 311 ++ Lisp/ssg_input.lsp | 162 + Lisp/ssg_load.lsp | 6 +- Lisp/ssg_texttools.lsp | 285 ++ bin/show_exportcsv.bat | 32 +- doc/faq.pdf | 7212 +++++++++++++++++++++++++++++++++++++++ lang/de_DE.json | 56 +- lang/en_GB.json | 56 +- menu/SSG_LIB.mnl | 7 +- menu/SSG_LIB.mnu | 9 + tests/test_unit.lsp | 74 +- 13 files changed, 8260 insertions(+), 11 deletions(-) create mode 100644 Lisp/ssg_blocktools.lsp create mode 100644 Lisp/ssg_input.lsp create mode 100644 Lisp/ssg_texttools.lsp create mode 100644 doc/faq.pdf diff --git a/CLAUDE.md b/CLAUDE.md index 84ed02c..c49f03b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -78,6 +78,7 @@ Die `start_briscad.bat` ruft `setenv.bat` auf und startet BricsCAD. | Geruest | `GeruestInsert` | GERUEST_SAEULEN, GERUEST_ROHRABHAENGER, GERUEST_WANDBEFESTIGUNG (derselbe Dialog, im jeweiligen Bereich geoeffnet), GERUEST_TRAEGER (eigener Dialog), GERUEST_TRAEGER_BESCHRIFTEN (Untermenue Geruest -> Funktionen -> Traeger beschriften; alle Traeger der Zeichnung neu beschriften); Gattertraeger noch Platzhalter auf GERUEST | | Connections | `Connection_Edit` + `SSG_LIB_Commands` | CONNECTION_INSERT, CONNECTION_EDIT, ILS_EINGANG_INSERT, ILS_AUSGANG_INSERT | | Export | `export` | EXPORTSIVAS, EXPORTCSV, CALLPYTHON | +| Werkzeuge | `ssg_blocktools`, `ssg_texttools` | SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN, SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL | | Konfiguration | `SSG_LIB_Commands` + `DrawPlanquadrate` | SSG_DIM_SWITCH, SSG_SPRACHE, PLANQUADRATE_TOGGLE (DRAW_PLANQUADRATE/DELETE_PLANQUADRATE) | | Doppelklick/Kontextmenue | `SSG_LIB_Commands` | SSG_BLOCKEDIT (dispatcht Kreisel->KreiselEdit, Omniflo->OMNI_EDIT, GF_*->GEFAELLESTRECKE_EDIT, VF_*->VARIOFOERDERER_EDIT) | @@ -99,6 +100,9 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `ssg_dbg.lsp` | - | Debug-Logging (dbgopen, dbgmsg, dbgflush, dbgclose) | | `ssg_dialog.lsp` | - | DCL-Dialog-Vorlagen und Hilfsfunktionen | | `ssg_layer.lsp` | - | Layer-Verwaltung. `ssg-layer-visible-p` (aus ODER gefroren), `ssg-layer-gefroren-p`/`ssg-ent-layer-gefroren-p` (NUR gefroren, fuer den Export) | +| `ssg_input.lsp` | - | Generische Eingabe-Wrapper `ssg-in-real/-int/-string/-point/-dist/-keyword/-yesno` (Vorgabe in `<..>`, Enter = Vorgabe, optionaler Hook `*ssg-in-hook*` fuer Journale). Steht NEBEN den VF-spezifischen `vfl-in-*` (diese bleiben unveraendert). `ssg-in-yesno` liefert T bei Ja (anders als `ssg-ques`, das T fuer die nicht vorgegebene Antwort liefert); Schluesselwoerter aus `ssg-text "in-yesno-keys"` | +| `ssg_blocktools.lsp` | SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN | Block-Werkzeuge fuer das aktuelle Layout (Ursprung ACADSST `TOOLS.LSP`/`ssg.lsp`): Einfuegungen zaehlen (Pick, wcmatch-Muster oder Statistik aller Bloecke), alle Einfuegungen loeschen (Rueckfrage, gesperrte Layer bleiben), Attributwerte zeichnungsweit/in Auswahl suchen+ersetzen (Vorschau mit Anzahl, Teilstring oder Gesamtwert). Wirksamer Blockname (dynamische Bloecke). Reine Kerne `ssg-bt-name-passt-p`, `ssg-bt-zaehle-namen`, `ssg-bt-wert-neu` in `tests/test_unit.lsp` getestet | +| `ssg_texttools.lsp` | SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL | Text-Werkzeuge (Ursprung ACADSST `CHGTEXT`/`PARTEXT`/`ALTHOEHE`/`ALTSTIL`): Suchen/Ersetzen in TEXT, MTEXT und Block-Attributen (nutzt `ssg-bt-*`, daher NACH `ssg_blocktools` laden), Text parallel zu Linie/Polylinie/Bogen (lesbar ausgerichtet, Abstand), Hoehe/Stil aendern. Arbeitet in der XY-Ebene des Welt-KS. Reine Kerne `ssg-tt-lesbarer-winkel`, `ssg-tt-versetzt` getestet | | `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad | ILS Kreisel und Eckrad komplett in AutoLISP | | `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) bleibt bewusst reine Konsole (im Code selbst als Legacy/"wird umgebaut" markiert). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/TODO-plan-vf-interactive.md`. Details/Entscheidungsbaum: `doc/variofoerderer.md` | | `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/TODO-plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus`. Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | diff --git a/Lisp/README.md b/Lisp/README.md index 1f38fb2..463944b 100644 --- a/Lisp/README.md +++ b/Lisp/README.md @@ -323,6 +323,63 @@ Benutzerfreundliche BricsCAD-Befehle für Layer-Operationen. Alle Befehle sicher --- +### `ssg_input.lsp` – Generische Eingabe-Wrapper + +Abfragen mit Vorgabewert (`<..>` im Prompt, Enter = Vorgabe). Steht neben den VF-spezifischen `vfl-in-*` (`vf_linienzug.lsp`); diese bleiben unveraendert. Kein Journal, aber ein optionaler Hook. ESC bricht wie ueblich ueber `*error*` ab. + +| Funktion | Beschreibung | +| --- | --- | +| `ssg-in-real text default` | Reelle Zahl (`getreal`), Vorgabe ohne ueberfluessige Nullen angezeigt | +| `ssg-in-int text default` | Ganzzahl (`getint`) | +| `ssg-in-string text default` | String mit Leerzeichen; Enter ohne Eingabe liefert die Vorgabe (ohne Vorgabe `nil`) | +| `ssg-in-point text default base` | Punkt, `base` = Gummiband-Basispunkt oder `nil` | +| `ssg-in-dist text default base` | Abstand (`getdist`) | +| `ssg-in-keyword text schluessel default` | Schluesselwort im `initget`-Format, z.B. `"Alle Auswahl"` | +| `ssg-in-yesno text default` | Ja/Nein, **T = Ja**; `default` T = Enter bedeutet Ja. Woerter aus `ssg-text "in-yesno-keys"` | +| `ssg-in-default wert default`, `ssg-in-fmt-real`, `ssg-in-fmt-pt`, `ssg-in-prompt`, `ssg-in-first-word`, `ssg-in-second-word` | Reine Hilfsfunktionen (in `tests/test_unit.lsp` getestet) | + +Hook (z.B. fuer ein Eingabe-Journal): `(setq *ssg-in-hook* 'meine-funktion)` mit `(defun meine-funktion (art prompt wert) ...)`; `art` ist `"REAL"`, `"INT"`, `"STRING"`, `"POINT"`, `"DIST"`, `"KEYWORD"` oder `"YESNO"`. Ein Hook, der einen Fehler wirft, wird abgeschaltet. + +--- + +### `ssg_blocktools.lsp` – Block-Werkzeuge + +Ursprung: ACADSST `TOOLS.LSP` (`BLKANZAHL`, `BLKENTF`), `DINGEN2` (`g-bli`), `ssg.lsp` (`suchen-aendern`). Arbeitet im **aktuellen Layout-Reiter**. Blocknamen werden ueber den wirksamen Namen verglichen (dynamische Bloecke); Muster mit `wcmatch` (`*`, `?`, `#`, ohne Gross-/Kleinschreibung). + +| Befehl | Beschreibung | +| --- | --- | +| `SSG_BLOCK_COUNT` | Block anklicken, `Name` fuer ein Muster, oder Enter fuer eine Statistik aller Bloecke | +| `SSG_BLOCK_DELETE` | Alle Einfuegungen eines Blocks/Musters loeschen; Rueckfrage (Vorgabe Nein), Einfuegungen auf gesperrten Layern bleiben stehen; eine Undo-Gruppe | +| `SSG_ATTR_ERSETZEN` | Attributwerte suchen/ersetzen: Bereich (Alle mit Blockname-Muster / Auswahl), Tag-Muster, Suchtext, Ersatz, Modus Teil (Teilstring) oder Gesamt (ganzer Wert). Zeigt vorab die Anzahl und fragt nach | + +| Funktion | Beschreibung | +| --- | --- | +| `ssg-bt-inserts muster` | Entity-Liste aller Einfuegungen im Layout (optional nach Muster) | +| `ssg-bt-statistik muster` | `((NAME . ANZAHL) ...)` alphabetisch | +| `ssg-bt-attr-ersetzen-ent ent tag suche ersatz teil-p probe-p` | Attribute EINER Einfuegung ersetzen bzw. nur zaehlen (`probe-p`); Rueckgabe Anzahl | +| `ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p probe-p` | Dasselbe fuer eine Entity-Liste | +| `ssg-bt-wert-neu wert suche ersatz teil-p` | Reiner Kern: neuer Wert oder `nil` (unveraendert); beachtet Gross-/Kleinschreibung | +| `ssg-bt-name-passt-p`, `ssg-bt-zaehle-namen`, `ssg-bt-muster-escape` | Reine Hilfsfunktionen (getestet) | + +--- + +### `ssg_texttools.lsp` – Text-Werkzeuge + +Ursprung: ACADSST `CHGTEXT.LSP`, `PARTEXT.LSP`, `ALTHOEHE.LSP`, `ALTSTIL.LSP`. Laden **nach** `ssg_blocktools` (nutzt `ssg-bt-wert-neu` und `ssg-bt-attr-ersetzen-liste`). Arbeitet in der XY-Ebene des Welt-KS. + +| Befehl | Beschreibung | +| --- | --- | +| `SSG_TEXT_ERSETZEN` | Suchen/Ersetzen in TEXT, MTEXT **und** Block-Attributen; Bereich Alle (Layout) oder Auswahl; Vorschau mit Anzahl, Rueckfrage | +| `SSG_TEXT_PARALLEL` | Linie/Polylinie/Bogen anklicken, Text wird parallel (lesbar, nie auf dem Kopf) mit Abstand gesetzt; Hoehe, Abstand und letzter Text werden fuer die Sitzung gemerkt; Enter beendet | +| `SSG_TEXT_HOEHE` | Texthoehe gewaehlter TEXT/MTEXT aendern | +| `SSG_TEXT_STIL` | Textstil gewaehlter TEXT/MTEXT aendern (Stil muss existieren) | + +Reine Kerne (getestet): `ssg-tt-lesbarer-winkel` (Winkel 90 Grad bis 270 Grad um 180 Grad drehen, Ergebnis in [0, 2 pi)), `ssg-tt-versetzt`. + +Nicht uebernommen aus Walz: `Export`/`Import` von Texten (besser per Python/ezdxf), `KREISTXT`, `TXTBOXED`, `CHTEXT`/`ASCTEXT`/`PTEXT` (Autodesk 1990, durch BricsCAD-Standard ersetzt). + +--- + ### `ssg_load.lsp` – Laderoutine Lädt alle Module in der richtigen Reihenfolge. Ermittelt den Pfad automatisch über `findfile`. Ruft direkt nach `ssg_core.lsp` die Funktion `ssg-load-config` auf, damit die JSON-Konfiguration für alle nachfolgenden Module verfügbar ist. diff --git a/Lisp/ssg_blocktools.lsp b/Lisp/ssg_blocktools.lsp new file mode 100644 index 0000000..7b5baa7 --- /dev/null +++ b/Lisp/ssg_blocktools.lsp @@ -0,0 +1,311 @@ +;; ============================================================ +;; SSG_BLOCKTOOLS.LSP - Block-Werkzeuge fuer die aktuelle Zeichnung +;; +;; Ursprung: ACADSST/MENU/TOOLS.LSP (BLKANZAHL, BLKENTF), DINGEN2 +;; (g-bli) und ssg.lsp (suchen-aendern) - neu geschrieben im ssg-Stil +;; (Undo-Gruppe, i18n, Ja/Nein-Rueckfrage, keine Globals). +;; +;; Befehle: +;; SSG_BLOCK_COUNT Einfuegungen zaehlen (ein Block, Namensmuster +;; oder Statistik aller Bloecke) +;; SSG_BLOCK_DELETE Alle Einfuegungen eines Blocks/Namensmusters +;; loeschen (mit Rueckfrage) +;; SSG_ATTR_ERSETZEN Attributwerte zeichnungsweit oder in einer +;; Auswahl suchen und ersetzen (mit Vorschau) +;; +;; Blocknamen werden ueber den WIRKSAMEN Namen verglichen (dynamische +;; Bloecke: EffectiveName statt "*U12"). Muster arbeiten mit wcmatch +;; (Platzhalter * ? #, ohne Beachtung der Gross-/Kleinschreibung). +;; Es wird nur der aktuelle Layout-Reiter (Modell ODER Papierbereich) +;; durchsucht. +;; +;; Setzt ssg_core.lsp, ssg_lang.lsp und ssg_input.lsp voraus. +;; ============================================================ + +(vl-load-com) + +;; ------------------------------------------------------------ +;; REINE HILFSFUNKTIONEN (in test_unit getestet) +;; ------------------------------------------------------------ + +;; T, wenn name auf das wcmatch-Muster passt (ohne Gross-/Kleinschreibung). +;; muster nil oder "" -> alle Namen passen. +(defun ssg-bt-name-passt-p (name muster) + (if (or (null muster) (= muster "")) + T + (if (wcmatch (strcase name) (strcase muster)) T nil) + ) +) + +;; Liste von Namen -> Alist ((NAME . ANZAHL) ...), alphabetisch sortiert +;; (ohne Beachtung der Gross-/Kleinschreibung). +(defun ssg-bt-zaehle-namen (namen / alist eintrag) + (foreach name namen + (setq eintrag (assoc name alist)) + (if eintrag + (setq alist (subst (cons name (1+ (cdr eintrag))) eintrag alist)) + (setq alist (cons (cons name 1) alist)) + ) + ) + (vl-sort alist '(lambda (a b) (< (strcase (car a)) (strcase (car b))))) +) + +;; Sonderzeichen eines Blocknamens fuer wcmatch maskieren (Backquote), damit +;; ein per Pick gewaehlter Name nur sich selbst trifft. +(defun ssg-bt-muster-escape (name / res i c) + (setq res "" i 1) + (while (<= i (strlen name)) + (setq c (substr name i 1)) + (if (vl-string-search c "#@.*?~[],`") + (setq res (strcat res "`")) + ) + (setq res (strcat res c) + i (1+ i)) + ) + res +) + +;; Muster ohne Maskier-Backquotes (fuer Meldungen) +(defun ssg-bt-muster-anzeige (muster) + (ssg-str-replace-all "" "`" muster) +) + +;; Neuer Attributwert oder nil, wenn der Wert unveraendert bleibt. +;; teil-p = T : suche wird als Teilstring ueberall ersetzt +;; teil-p = nil: nur ersetzen, wenn der GESAMTE Wert gleich suche ist +;; Leere suche aendert nichts. Gross-/Kleinschreibung wird beachtet. +(defun ssg-bt-wert-neu (wert suche ersatz teil-p) + (cond + ((or (null suche) (= suche "") (null wert)) nil) + (teil-p + (if (vl-string-search suche wert) + (ssg-str-replace-all ersatz suche wert) + nil + ) + ) + ((= wert suche) ersatz) + (t nil) + ) +) + +;; ------------------------------------------------------------ +;; ZEICHNUNGSZUGRIFF +;; ------------------------------------------------------------ + +;; Wirksamer Blockname einer Einfuegung (dynamische Bloecke beachten) +(defun ssg-bt-effname (ent / res) + (setq res (vl-catch-all-apply 'vla-get-effectivename + (list (vlax-ename->vla-object ent)))) + (if (vl-catch-all-error-p res) + (cdr (assoc 2 (entget ent))) + res + ) +) + +;; T, wenn der Layer der Entity gesperrt ist +(defun ssg-bt-layer-gesperrt-p (ent / lay) + (setq lay (tblsearch "LAYER" (cdr (assoc 8 (entget ent))))) + (and lay (= 4 (logand 4 (cdr (assoc 70 lay))))) +) + +;; Alle Einfuegungen im aktuellen Layout, optional gefiltert nach Namensmuster. +;; Rueckgabe: Liste von Entity-Namen (kann leer sein). +(defun ssg-bt-inserts (muster / ss i ent res) + (setq ss (ssget "_X" (list '(0 . "INSERT") (cons 410 (getvar "CTAB"))))) + (if ss + (progn + (setq i 0) + (while (setq ent (ssname ss i)) + (if (ssg-bt-name-passt-p (ssg-bt-effname ent) muster) + (setq res (cons ent res)) + ) + (setq i (1+ i)) + ) + ) + ) + (reverse res) +) + +;; Statistik: ((NAME . ANZAHL) ...) fuer alle Einfuegungen passend zum Muster +(defun ssg-bt-statistik (muster) + (ssg-bt-zaehle-namen (mapcar 'ssg-bt-effname (ssg-bt-inserts muster))) +) + +;; Block per Pick oder Namensmuster waehlen. +;; Rueckgabe: Namensmuster (String) oder nil bei Enter ("alle"). +(defun ssg-bt-muster-waehlen (text / sel ed) + (initget "Name") + (setq sel (entsel text)) + (cond + ((null sel) nil) + ((= (type sel) 'STR) + (setq sel (getstring T (ssg-text "bt-prompt-muster"))) + (if (= sel "") nil sel) + ) + (t + (setq ed (entget (car sel))) + (if (= (cdr (assoc 0 ed)) "INSERT") + (ssg-bt-muster-escape (ssg-bt-effname (car sel))) + (progn (prompt (ssg-text "bt-kein-block")) nil) + ) + ) + ) +) + +;; Attribute EINER Einfuegung ersetzen (oder nur zaehlen, wenn probe-p). +;; tag = wcmatch-Muster fuer den Attribut-Tag ("*" = alle). +;; Rueckgabe: Anzahl betroffener Attribute. +(defun ssg-bt-attr-ersetzen-ent (ent tag suche ersatz teil-p probe-p + / e ed neu n) + (setq n 0 + e (entnext ent)) + (while (and e + (= "ATTRIB" (cdr (assoc 0 (setq ed (entget e)))))) + (if (and (ssg-bt-name-passt-p (cdr (assoc 2 ed)) tag) + (setq neu (ssg-bt-wert-neu (cdr (assoc 1 ed)) suche ersatz teil-p))) + (progn + (setq n (1+ n)) + (if (not probe-p) + (entmod (subst (cons 1 neu) (assoc 1 ed) ed)) + ) + ) + ) + (setq e (entnext e)) + ) + (if (and (> n 0) (not probe-p)) (entupd ent)) + n +) + +;; Attribute einer Liste von Einfuegungen ersetzen. Rueckgabe: Anzahl. +(defun ssg-bt-attr-ersetzen-liste (ents tag suche ersatz teil-p probe-p / n) + (setq n 0) + (foreach ent ents + (setq n (+ n (ssg-bt-attr-ersetzen-ent ent tag suche ersatz teil-p probe-p))) + ) + n +) + +;; Auswahlsatz -> Liste von Entity-Namen (nur INSERT) +(defun ssg-bt-ss-inserts (ss / i ent res) + (if ss + (progn + (setq i 0) + (while (setq ent (ssname ss i)) + (if (= (cdr (assoc 0 (entget ent))) "INSERT") + (setq res (cons ent res)) + ) + (setq i (1+ i)) + ) + ) + ) + (reverse res) +) + +;; ------------------------------------------------------------ +;; BEFEHLE +;; ------------------------------------------------------------ + +(defun c:SSG_BLOCK_COUNT ( / muster stat summe) + (setq muster (ssg-bt-muster-waehlen (ssg-text "bt-prompt-waehlen-count"))) + (setq stat (ssg-bt-statistik muster)) + (cond + ((null stat) + (prompt (if muster + (ssg-textf "bt-count-keine" (list (ssg-bt-muster-anzeige muster))) + (ssg-text "bt-count-keine-alle"))) + ) + ((and muster (null (cdr stat))) + (prompt (ssg-textf "bt-count-ergebnis" (list (cdar stat) (caar stat)))) + ) + (t + (setq summe 0) + (foreach z stat + (prompt (ssg-textf "bt-count-zeile" (list (car z) (cdr z)))) + (setq summe (+ summe (cdr z))) + ) + (prompt (ssg-textf "bt-count-summe" (list summe (length stat)))) + ) + ) + (princ) +) + +(defun c:SSG_BLOCK_DELETE ( / muster ents frei gesperrt n) + (setq muster (ssg-bt-muster-waehlen (ssg-text "bt-prompt-waehlen-delete"))) + (if (null muster) + (prompt (ssg-text "bt-delete-kein-muster")) + (progn + (setq ents (ssg-bt-inserts muster)) + (foreach ent ents + (if (ssg-bt-layer-gesperrt-p ent) + (setq gesperrt (cons ent gesperrt)) + (setq frei (cons ent frei)) + ) + ) + (cond + ((null ents) + (prompt (ssg-textf "bt-count-keine" (list (ssg-bt-muster-anzeige muster))))) + ((null frei) + (prompt (ssg-textf "bt-delete-alle-gesperrt" (list (length gesperrt))))) + ((ssg-in-yesno (ssg-textf "bt-delete-frage" (list (length frei) (ssg-bt-muster-anzeige muster))) nil) + (ssg-start (ssg-text "bt-delete-titel") nil) + (setq n 0) + (foreach ent frei + (if (entdel ent) (setq n (1+ n))) + ) + (ssg-end) + (prompt (ssg-textf "bt-delete-ergebnis" (list n))) + (if gesperrt + (prompt (ssg-textf "bt-delete-gesperrt" (list (length gesperrt))))) + ) + (t (prompt (ssg-text "bt-abgebrochen"))) + ) + ) + ) + (princ) +) + +(defun c:SSG_ATTR_ERSETZEN ( / k-bereich k-modus bereich ents muster tag suche ersatz modus teil-p n) + (setq k-bereich (ssg-text "in-keys-bereich") + k-modus (ssg-text "in-keys-modus") + bereich (ssg-in-keyword (ssg-text "bt-attr-bereich") k-bereich + (ssg-in-first-word k-bereich))) + (if (= bereich (ssg-in-first-word k-bereich)) + (progn + (setq muster (ssg-in-string (ssg-text "bt-attr-muster") "*")) + (setq ents (ssg-bt-inserts muster)) + ) + (progn + (prompt (ssg-text "bt-attr-auswahl")) + (setq ents (ssg-bt-ss-inserts (ssget '((0 . "INSERT"))))) + ) + ) + (cond + ((null ents) (prompt (ssg-text "bt-attr-keine-bloecke"))) + (t + (setq tag (ssg-in-string (ssg-text "bt-attr-tag") "*") + suche (ssg-in-string (ssg-text "bt-attr-suche") nil)) + (if (or (null suche) (= suche "")) + (prompt (ssg-text "bt-abgebrochen")) + (progn + (setq ersatz (ssg-in-string (ssg-text "bt-attr-ersatz") "") + modus (ssg-in-keyword (ssg-text "bt-attr-modus") k-modus + (ssg-in-first-word k-modus)) + teil-p (= modus (ssg-in-first-word k-modus))) + (setq n (ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p T)) + (cond + ((= n 0) (prompt (ssg-text "bt-attr-nichts"))) + ((ssg-in-yesno (ssg-textf "bt-attr-frage" (list n (length ents))) T) + (ssg-start (ssg-text "bt-attr-titel") nil) + (setq n (ssg-bt-attr-ersetzen-liste ents tag suche ersatz teil-p nil)) + (ssg-end) + (prompt (ssg-textf "bt-attr-ergebnis" (list n)))) + (t (prompt (ssg-text "bt-abgebrochen"))) + ) + ) + ) + ) + ) + (princ) +) + +(princ) diff --git a/Lisp/ssg_input.lsp b/Lisp/ssg_input.lsp new file mode 100644 index 0000000..93c59dc --- /dev/null +++ b/Lisp/ssg_input.lsp @@ -0,0 +1,162 @@ +;; ============================================================ +;; SSG_INPUT.LSP - Generische Eingabe-Wrapper (ssg-in-*) +;; +;; Allgemeingueltige Abfragen mit Vorgabewert, Anzeige "" im +;; Prompt und Enter = Vorgabe (Idee von g_in/g_ky aus den ACADSST- +;; Makros). Steht NEBEN den VF-spezifischen vfl-in-* aus +;; vf_linienzug.lsp; diese bleiben unveraendert. +;; +;; Alle Funktionen liefern den eingegebenen Wert oder die Vorgabe. +;; ESC bricht wie ueblich ueber *error* ab (z.B. ssg-errhan). +;; Ist kein Wert eingegeben und keine Vorgabe da, ist die Rueckgabe nil. +;; +;; Optionaler Hook (z.B. fuer ein Eingabe-Journal): +;; (setq *ssg-in-hook* 'meine-funktion) +;; (defun meine-funktion (art prompt wert) ...) ;; art = "REAL" "INT" +;; ;; "STRING" "POINT" +;; ;; "DIST" "KEYWORD" +;; ;; "YESNO" +;; Ein Hook, der einen Fehler wirft, wird abgeschaltet. +;; +;; Setzt ssg_core.lsp (und fuer ssg-in-yesno ssg_lang.lsp) voraus. +;; ============================================================ + +(vl-load-com) + +;; ------------------------------------------------------------ +;; REINE HILFSFUNKTIONEN (ohne Zeichnung, in test_unit getestet) +;; ------------------------------------------------------------ + +;; Vorgabe einsetzen, wenn kein Wert eingegeben wurde +(defun ssg-in-default (wert default) + (if wert wert default) +) + +;; Reelle Zahl ohne ueberfluessige Nullen: 5.0 -> "5", 2.50 -> "2.5" +(defun ssg-in-fmt-real (v / s) + (setq s (rtos v 2 6)) + (if (vl-string-position 46 s) + (progn + (while (= (substr s (strlen s)) "0") + (setq s (substr s 1 (1- (strlen s)))) + ) + (if (= (substr s (strlen s)) ".") + (setq s (substr s 1 (1- (strlen s)))) + ) + ) + ) + s +) + +;; Punkt als "x,y,z" (fehlende Z-Werte als 0) +(defun ssg-in-fmt-pt (p) + (strcat (ssg-in-fmt-real (car p)) "," + (ssg-in-fmt-real (cadr p)) "," + (ssg-in-fmt-real (if (caddr p) (caddr p) 0.0))) +) + +;; Prompt aufbauen: " : " bzw. ": " ohne Vorgabe +(defun ssg-in-prompt (text default-str) + (strcat text + (if default-str (strcat " <" default-str ">") "") + ": ") +) + +;; Erstes Wort eines Schluesselwort-Strings: "Ja Nein" -> "Ja" +(defun ssg-in-first-word (schluessel / pos) + (if (setq pos (vl-string-search " " schluessel)) + (substr schluessel 1 pos) + schluessel + ) +) + +;; Zweites Wort: "Ja Nein" -> "Nein" +(defun ssg-in-second-word (schluessel / pos) + (if (setq pos (vl-string-search " " schluessel)) + (substr schluessel (+ pos 2)) + "" + ) +) + +;; ------------------------------------------------------------ +;; HOOK +;; ------------------------------------------------------------ +(defun ssg-in-notify (art text wert / res) + (if *ssg-in-hook* + (progn + (setq res (vl-catch-all-apply *ssg-in-hook* (list art text wert))) + (if (vl-catch-all-error-p res) (setq *ssg-in-hook* nil)) + ) + ) + wert +) + +;; ------------------------------------------------------------ +;; ABFRAGEN +;; text = Prompt ohne Doppelpunkt, z.B. "\nHoehe" +;; ------------------------------------------------------------ + +(defun ssg-in-real (text default / w) + (setq w (getreal (ssg-in-prompt text (if default (ssg-in-fmt-real default))))) + (ssg-in-notify "REAL" text (ssg-in-default w default)) +) + +(defun ssg-in-int (text default / w) + (setq w (getint (ssg-in-prompt text (if default (itoa default))))) + (ssg-in-notify "INT" text (ssg-in-default w default)) +) + +;; String (mit Leerzeichen). Enter ohne Eingabe -> Vorgabe. +(defun ssg-in-string (text default / w) + (setq w (getstring T (ssg-in-prompt text default))) + (if (= w "") (setq w nil)) + (ssg-in-notify "STRING" text (ssg-in-default w default)) +) + +;; Punkt. base = Gummiband-Basispunkt oder nil, default = Punkt oder nil. +(defun ssg-in-point (text default base / w) + (setq w (if base + (getpoint base (ssg-in-prompt text (if default (ssg-in-fmt-pt default)))) + (getpoint (ssg-in-prompt text (if default (ssg-in-fmt-pt default)))) + )) + (ssg-in-notify "POINT" text (ssg-in-default w default)) +) + +;; Abstand. base = Basispunkt oder nil. +(defun ssg-in-dist (text default base / w) + (setq w (if base + (getdist base (ssg-in-prompt text (if default (ssg-in-fmt-real default)))) + (getdist (ssg-in-prompt text (if default (ssg-in-fmt-real default)))) + )) + (ssg-in-notify "DIST" text (ssg-in-default w default)) +) + +;; Schluesselwort ohne Hook (intern, auch von ssg-in-yesno genutzt). +(defun ssg-in-keyword-raw (text schluessel default / w) + (initget 0 schluessel) + (setq w (getkword + (ssg-in-prompt + (strcat text " [" (vl-string-translate " " "/" schluessel) "]") + default))) + (ssg-in-default w default) +) + +;; Schluesselwort. schluessel im initget-Format, z.B. "Alle Auswahl". +;; Rueckgabe: gewaehltes Schluesselwort (volle Schreibweise) oder default. +(defun ssg-in-keyword (text schluessel default) + (ssg-in-notify "KEYWORD" text (ssg-in-keyword-raw text schluessel default)) +) + +;; Ja/Nein-Abfrage, Rueckgabe T bei Ja, nil bei Nein (anders als ssg-ques, +;; das T fuer die NICHT-vorgegebene Antwort liefert). +;; default = T -> Enter bedeutet Ja, nil -> Enter bedeutet Nein. +;; Die Schluesselwoerter kommen aus ssg-text "in-yesno-keys" (z.B. "Ja Nein"). +(defun ssg-in-yesno (text default / schluessel ja nein w) + (setq schluessel (ssg-text "in-yesno-keys") + ja (ssg-in-first-word schluessel) + nein (ssg-in-second-word schluessel)) + (setq w (ssg-in-keyword-raw text schluessel (if default ja nein))) + (ssg-in-notify "YESNO" text (= w ja)) +) + +(princ) diff --git a/Lisp/ssg_load.lsp b/Lisp/ssg_load.lsp index 9228d76..c806db1 100644 --- a/Lisp/ssg_load.lsp +++ b/Lisp/ssg_load.lsp @@ -28,6 +28,7 @@ (load (strcat base-path "ssg_dbg.lsp") "ssg_dbg.lsp nicht gefunden") (load (strcat base-path "ssg_dialog.lsp") "ssg_dialog.lsp nicht gefunden") (load (strcat base-path "ssg_layer.lsp") "ssg_layer.lsp nicht gefunden") + (load (strcat base-path "ssg_input.lsp") "ssg_input.lsp nicht gefunden") ;; Gemeinsame KS-Extraktion + Einfuegeprimitiven - MUSS vor VarioFoerderer ;; und Gefaellestrecke geladen werden (beide nutzen sie). (load (strcat base-path "ssg_ks_insert.lsp") "ssg_ks_insert.lsp nicht gefunden") @@ -39,7 +40,10 @@ (load (strcat base-path "Tro_Edit.lsp") "Tro_Edit.lsp nicht gefunden") (load (strcat base-path "Connection_Edit.lsp") "Connection_Edit.lsp nicht gefunden") (load (strcat base-path "SSG_LIB_Commands.lsp") "SSG_LIB_Commands.lsp nicht gefunden") - (prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, KreiselInsert, VarioFoerderer, Gefaellestrecke, export, OmniModulInsert, SSG_LIB_Commands") + ;; Werkzeuge: ssg_texttools nutzt ssg_blocktools, beide nutzen ssg_input + (load (strcat base-path "ssg_blocktools.lsp") "ssg_blocktools.lsp nicht gefunden") + (load (strcat base-path "ssg_texttools.lsp") "ssg_texttools.lsp nicht gefunden") + (prompt "\nSSG-Bibliotheken geladen: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, ssg_input, KreiselInsert, VarioFoerderer, Gefaellestrecke, export, OmniModulInsert, SSG_LIB_Commands, ssg_blocktools, ssg_texttools") (princ) ) diff --git a/Lisp/ssg_texttools.lsp b/Lisp/ssg_texttools.lsp new file mode 100644 index 0000000..7b8866b --- /dev/null +++ b/Lisp/ssg_texttools.lsp @@ -0,0 +1,285 @@ +;; ============================================================ +;; SSG_TEXTTOOLS.LSP - Text-Werkzeuge +;; +;; Ursprung: ACADSST/MENU/CHGTEXT.LSP (Suchen/Ersetzen), PARTEXT.LSP +;; (Tbpl: parallel beschriften), ALTHOEHE.LSP (Tsz), ALTSTIL.LSP (Ts). +;; Neu geschrieben im ssg-Stil (Undo-Gruppe, i18n, ssg-in-*). +;; +;; Befehle: +;; SSG_TEXT_ERSETZEN Zeichenketten in TEXT, MTEXT und Block- +;; Attributen suchen/ersetzen (mit Vorschau) +;; SSG_TEXT_PARALLEL Text parallel zu Linie/Polylinie/Bogen setzen +;; (lesbar ausgerichtet, mit Abstand zur Linie) +;; SSG_TEXT_HOEHE Texthoehe von TEXT/MTEXT aendern +;; SSG_TEXT_STIL Textstil von TEXT/MTEXT aendern +;; +;; Arbeitet in der XY-Ebene des Welt-KS (Textrotation = WKS-Winkel). +;; Setzt ssg_core.lsp, ssg_lang.lsp, ssg_input.lsp und ssg_blocktools.lsp +;; (ssg-bt-wert-neu, ssg-bt-attr-ersetzen-ent) voraus. +;; ============================================================ + +(vl-load-com) + +;; ------------------------------------------------------------ +;; REINE HILFSFUNKTIONEN (in test_unit getestet) +;; ------------------------------------------------------------ + +;; Winkel (Bogenmass) so drehen, dass ein Text lesbar bleibt: Winkel im +;; Bereich (90 Grad, 270 Grad] werden um 180 Grad gedreht. Ergebnis in +;; [0, 2*pi). +(defun ssg-tt-lesbarer-winkel (a) + (setq a (rem a (* 2.0 pi))) + (if (< a 0.0) (setq a (+ a (* 2.0 pi)))) + (if (and (> a (+ (/ pi 2.0) 1e-9)) + (<= a (+ (* 1.5 pi) 1e-9))) + (setq a (- a pi)) + ) + (if (< a 0.0) (setq a (+ a (* 2.0 pi)))) + a +) + +;; Punkt um abstand in Richtung winkel verschieben (2D, Z bleibt erhalten) +(defun ssg-tt-versetzt (p winkel abstand) + (list (+ (car p) (* abstand (cos winkel))) + (+ (cadr p) (* abstand (sin winkel))) + (if (caddr p) (caddr p) 0.0)) +) + +;; ------------------------------------------------------------ +;; AUSWAHL +;; ------------------------------------------------------------ + +;; Auswahlsatz der angegebenen Typen holen (z.B. "TEXT,MTEXT,INSERT"). +;; alle-p = T -> alle im aktuellen Layout, nil -> Benutzerwahl +(defun ssg-tt-ss-holen (alle-p typen) + (if alle-p + (ssget "_X" (list (cons 0 typen) (cons 410 (getvar "CTAB")))) + (ssget (list (cons 0 typen))) + ) +) + +;; Auswahlsatz -> Liste von Entity-Namen mit Typ-Filter ("TEXT" "MTEXT" ...) +(defun ssg-tt-ss-liste (ss typen / i ent res) + (if ss + (progn + (setq i 0) + (while (setq ent (ssname ss i)) + (if (member (cdr (assoc 0 (entget ent))) typen) + (setq res (cons ent res)) + ) + (setq i (1+ i)) + ) + ) + ) + (reverse res) +) + +;; ------------------------------------------------------------ +;; SUCHEN / ERSETZEN +;; ------------------------------------------------------------ + +;; TEXT/MTEXT-Inhalte ersetzen (oder nur zaehlen). Rueckgabe: Anzahl Texte. +(defun ssg-tt-text-ersetzen-liste (ents suche ersatz teil-p probe-p + / n obj alt neu) + (setq n 0) + (foreach ent ents + (setq obj (vlax-ename->vla-object ent) + alt (vla-get-textstring obj) + neu (ssg-bt-wert-neu alt suche ersatz teil-p)) + (if neu + (if probe-p + (setq n (1+ n)) + (if (not (vl-catch-all-error-p + (vl-catch-all-apply 'vla-put-textstring (list obj neu)))) + (setq n (1+ n)) + ) + ) + ) + ) + n +) + +;; Texte + Attribute in einem Auswahlsatz ersetzen/zaehlen. +;; Rueckgabe: (anzahl-texte . anzahl-attribute) +(defun ssg-tt-ersetzen-ss (ss suche ersatz teil-p probe-p) + (cons + (ssg-tt-text-ersetzen-liste + (ssg-tt-ss-liste ss '("TEXT" "MTEXT")) suche ersatz teil-p probe-p) + (ssg-bt-attr-ersetzen-liste + (ssg-tt-ss-liste ss '("INSERT")) "*" suche ersatz teil-p probe-p) + ) +) + +(defun c:SSG_TEXT_ERSETZEN ( / k-bereich k-modus alle-p ss suche ersatz modus teil-p z) + (setq k-bereich (ssg-text "in-keys-bereich") + k-modus (ssg-text "in-keys-modus") + alle-p (= (ssg-in-keyword (ssg-text "tt-bereich") k-bereich + (ssg-in-first-word k-bereich)) + (ssg-in-first-word k-bereich))) + (if (not alle-p) (prompt (ssg-text "tt-auswahl"))) + (setq ss (ssg-tt-ss-holen alle-p "TEXT,MTEXT,INSERT")) + (if (null ss) + (prompt (ssg-text "tt-keine-objekte")) + (progn + (setq suche (ssg-in-string (ssg-text "tt-suche") nil)) + (if (or (null suche) (= suche "")) + (prompt (ssg-text "tt-abgebrochen")) + (progn + (setq ersatz (ssg-in-string (ssg-text "tt-ersatz") "") + modus (ssg-in-keyword (ssg-text "tt-modus") k-modus + (ssg-in-first-word k-modus)) + teil-p (= modus (ssg-in-first-word k-modus))) + (setq z (ssg-tt-ersetzen-ss ss suche ersatz teil-p T)) + (cond + ((= 0 (+ (car z) (cdr z))) (prompt (ssg-text "tt-nichts"))) + ((ssg-in-yesno (ssg-textf "tt-frage" (list (car z) (cdr z))) T) + (ssg-start (ssg-text "tt-ersetzen-titel") nil) + (setq z (ssg-tt-ersetzen-ss ss suche ersatz teil-p nil)) + (ssg-end) + (prompt (ssg-textf "tt-ergebnis" (list (car z) (cdr z))))) + (t (prompt (ssg-text "tt-abgebrochen"))) + ) + ) + ) + ) + ) + (princ) +) + +;; ------------------------------------------------------------ +;; PARALLEL BESCHRIFTEN +;; ------------------------------------------------------------ + +;; Winkel der Kurve (Linie, Polylinie, Bogen, ...) am Punkt pt (WKS). +;; Rueckgabe: Winkel in Bogenmass oder nil, wenn nicht ermittelbar. +(defun ssg-tt-kurven-winkel (ent pt / obj cp param deriv) + (setq obj (vlax-ename->vla-object ent)) + (setq cp (vl-catch-all-apply 'vlax-curve-getclosestpointto (list obj pt))) + (if (or (vl-catch-all-error-p cp) (null cp)) + nil + (progn + (setq param (vl-catch-all-apply 'vlax-curve-getparamatpoint (list obj cp))) + (if (or (vl-catch-all-error-p param) (null param)) + nil + (progn + (setq deriv (vl-catch-all-apply 'vlax-curve-getfirstderiv (list obj param))) + (if (or (vl-catch-all-error-p deriv) (null deriv)) + nil + (list (atan (cadr deriv) (car deriv)) cp) + ) + ) + ) + ) + ) +) + +;; TEXT erzeugen (unten mittig, Gruppe 73 = 1 damit Gruppe 11 gilt) +(defun ssg-tt-text-machen (p hoehe string winkel) + (entmake (list '(0 . "TEXT") + (cons 8 (getvar "CLAYER")) + (cons 7 (getvar "TEXTSTYLE")) + (cons 10 p) + (cons 11 p) + (cons 40 hoehe) + (cons 1 string) + (cons 50 winkel) + (cons 72 1) + (cons 73 1))) +) + +(defun c:SSG_TEXT_PARALLEL ( / sel info a ar p text) + (ssg-start (ssg-text "tt-parallel-titel") nil) + (if (or (null *ssg-tt-hoehe*) (<= *ssg-tt-hoehe* 0.0)) + (setq *ssg-tt-hoehe* (if (> (getvar "TEXTSIZE") 0.0) (getvar "TEXTSIZE") 2.5)) + ) + (setq *ssg-tt-hoehe* (ssg-in-real (ssg-text "tt-hoehe") *ssg-tt-hoehe*)) + (if (null *ssg-tt-abstand*) + (setq *ssg-tt-abstand* (* 0.5 *ssg-tt-hoehe*)) + ) + (setq *ssg-tt-abstand* (ssg-in-real (ssg-text "tt-abstand") *ssg-tt-abstand*)) + (while (setq sel (entsel (ssg-text "tt-parallel-waehlen"))) + (setq info (ssg-tt-kurven-winkel (car sel) (trans (cadr sel) 1 0))) + (if (null info) + (prompt (ssg-text "tt-parallel-keine-kurve")) + (progn + (setq a (car info) + ar (ssg-tt-lesbarer-winkel a) + p (ssg-tt-versetzt (cadr info) (+ ar (/ pi 2.0)) *ssg-tt-abstand*) + text (ssg-in-string (ssg-text "tt-text") *ssg-tt-text*)) + (if (and text (/= text "")) + (progn + (setq *ssg-tt-text* text) + (if (not (ssg-tt-text-machen p *ssg-tt-hoehe* text ar)) + (prompt (ssg-text "tt-parallel-fehler")) + ) + ) + ) + ) + ) + ) + (ssg-end) + (princ) +) + +;; ------------------------------------------------------------ +;; HOEHE / STIL AENDERN +;; ------------------------------------------------------------ + +(defun c:SSG_TEXT_HOEHE ( / ents hoehe n) + (prompt (ssg-text "tt-auswahl")) + (setq ents (ssg-tt-ss-liste (ssget '((0 . "TEXT,MTEXT"))) '("TEXT" "MTEXT"))) + (if (null ents) + (prompt (ssg-text "tt-keine-objekte")) + (progn + (setq hoehe (ssg-in-real (ssg-text "tt-hoehe") + (if (> (getvar "TEXTSIZE") 0.0) (getvar "TEXTSIZE") nil))) + (if (or (null hoehe) (<= hoehe 0.0)) + (prompt (ssg-text "tt-abgebrochen")) + (progn + (ssg-start (ssg-text "tt-hoehe-titel") nil) + (setq n 0) + (foreach ent ents + (if (not (vl-catch-all-error-p + (vl-catch-all-apply 'vla-put-height + (list (vlax-ename->vla-object ent) hoehe)))) + (setq n (1+ n)) + ) + ) + (ssg-end) + (prompt (ssg-textf "tt-geaendert" (list n))) + ) + ) + ) + ) + (princ) +) + +(defun c:SSG_TEXT_STIL ( / ents stil n) + (prompt (ssg-text "tt-auswahl")) + (setq ents (ssg-tt-ss-liste (ssget '((0 . "TEXT,MTEXT"))) '("TEXT" "MTEXT"))) + (if (null ents) + (prompt (ssg-text "tt-keine-objekte")) + (progn + (setq stil (ssg-in-string (ssg-text "tt-stil") (getvar "TEXTSTYLE"))) + (cond + ((or (null stil) (null (tblsearch "STYLE" stil))) + (prompt (ssg-textf "tt-stil-fehlt" (list (if stil stil ""))))) + (t + (ssg-start (ssg-text "tt-stil-titel") nil) + (setq n 0) + (foreach ent ents + (if (not (vl-catch-all-error-p + (vl-catch-all-apply 'vla-put-stylename + (list (vlax-ename->vla-object ent) stil)))) + (setq n (1+ n)) + ) + ) + (ssg-end) + (prompt (ssg-textf "tt-geaendert" (list n)))) + ) + ) + ) + (princ) +) + +(princ) diff --git a/bin/show_exportcsv.bat b/bin/show_exportcsv.bat index 37f9b67..1324403 100644 --- a/bin/show_exportcsv.bat +++ b/bin/show_exportcsv.bat @@ -6,11 +6,12 @@ REM Zeichnet jede Zeile der Export-CSV (EXPORTCSV) als achsparalleles REM Rechteck aus Position + Boundingbox, mit Legende und Tooltip je REM Rechteck sowie den Anschluss-Koordinatensystemen K1-K4 (rotes Kreuz, REM blaue Linie K1->K2->K3->K4), und oeffnet das Ergebnis im Browser. -REM Optional zusaetzlich Materialfluss- und Bahnzusammenhang-Graph. +REM Optional zusaetzlich Materialfluss-, Bahnzusammenhang- und TRO-Fluss-Graph. REM REM Die Darstellung uebernimmt sps_skel (bin\material_flow.bat, -REM Option --show-bbs). sps_skel wird neben dxfmakros erwartet -REM (..\sps_skel) oder ueber die Umgebungsvariable SPS_SKEL_HOME. +REM Option --show-bbs, bzw. bin\tro_flow.bat fuer 'tro'). sps_skel wird +REM neben dxfmakros erwartet (..\sps_skel) oder ueber die Umgebungs- +REM variable SPS_SKEL_HOME. REM REM Aufruf: REM bin\show_exportcsv.bat results\export.csv, alle Zeilen @@ -18,13 +19,15 @@ REM bin\show_exportcsv.bat meine_export.csv andere CSV in results\ (oder Pf REM bin\show_exportcsv.bat export.csv flow ohne VF/GF-Einzelbausteine REM bin\show_exportcsv.bat export.csv mflow zusaetzlich Materialfluss-Graph REM bin\show_exportcsv.bat export.csv track zusaetzlich Bahnzusammenhang-Graph -REM bin\show_exportcsv.bat export.csv flow mflow track alles kombiniert +REM bin\show_exportcsv.bat export.csv tro zusaetzlich TRO-Fluss-Graph (lagerichtig) +REM bin\show_exportcsv.bat export.csv flow mflow track tro alles kombiniert REM -REM mflow/track brauchen Graphviz ('dot' im PATH). +REM mflow/track/tro brauchen Graphviz ('dot' bzw. 'neato' im PATH). REM REM Ergebnis: %SKEL_RESULTS%\_bbs.svg REM %SKEL_RESULTS%\_material_flow.svg (nur mit 'mflow') REM %SKEL_RESULTS%\_track.svg (nur mit 'track') +REM %SKEL_RESULTS%\_tro_flow.svg (nur mit 'tro') REM ================================================================ setlocal @@ -58,20 +61,24 @@ for %%F in ("%CSV%") do ( set "SVG=%SKEL_RESULTS%\%%~nF_bbs.svg" set "MF_SVG=%SKEL_RESULTS%\%%~nF_material_flow.svg" set "TRACK_SVG=%SKEL_RESULTS%\%%~nF_track.svg" + set "TRO_SVG=%SKEL_RESULTS%\%%~nF_tro_flow.svg" ) REM Weitere Argumente (Reihenfolge beliebig): REM all (Default) / flow - Darstellungsmodus der Boundingbox-Ansicht REM mflow - zusaetzlich Materialfluss-SVG erzeugen und oeffnen REM track - zusaetzlich Bahnzusammenhang-SVG erzeugen und oeffnen +REM tro - zusaetzlich TRO-Fluss-SVG (lagerichtig) erzeugen und oeffnen set "MODE=all" set "MFLOW=" set "TRACK=" -for %%A in (%2 %3 %4) do ( +set "TRO=" +for %%A in (%2 %3 %4 %5) do ( if /i "%%~A"=="all" set "MODE=all" if /i "%%~A"=="flow" set "MODE=flow" if /i "%%~A"=="mflow" set "MFLOW=1" if /i "%%~A"=="track" set "TRACK=1" + if /i "%%~A"=="tro" set "TRO=1" ) REM Beide Graphen entstehen erst mit --tosvg (Graphviz 'dot') @@ -83,10 +90,15 @@ REM Alte SVGs entfernen, damit nie eine veraltete Ansicht geoeffnet wird if exist "%SVG%" del "%SVG%" if defined MFLOW if exist "%MF_SVG%" del "%MF_SVG%" if defined TRACK if exist "%TRACK_SVG%" del "%TRACK_SVG%" +if defined TRO if exist "%TRO_SVG%" del "%TRO_SVG%" call "%SPS_SKEL_HOME%\bin\material_flow.bat" --file "%CSV%" --show-bbs %MODE% --show-kx %OPTS% set "RC=%ERRORLEVEL%" +if defined TRO ( + call "%SPS_SKEL_HOME%\bin\tro_flow.bat" --file "%CSV%" --tosvg --use-cords +) + if not exist "%SVG%" ( echo FEHLER: SVG wurde nicht erzeugt ^(material_flow Exit-Code %RC%^). endlocal & exit /b 1 @@ -115,6 +127,14 @@ if defined TRACK ( echo WARNUNG: Bahnzusammenhang-SVG wurde nicht erzeugt ^(Graphviz 'dot' vorhanden?^). ) ) +if defined TRO ( + if exist "%TRO_SVG%" ( + echo TRO-Fluss: %TRO_SVG% + start "" "%TRO_SVG%" + ) else ( + echo WARNUNG: TRO-Fluss-SVG wurde nicht erzeugt ^(Graphviz 'neato' vorhanden?^). + ) +) endlocal & exit /b 0 diff --git a/doc/faq.pdf b/doc/faq.pdf new file mode 100644 index 0000000..66ea65c --- /dev/null +++ b/doc/faq.pdf @@ -0,0 +1,7212 @@ +%PDF-1.4 +%Óëéá +1 0 obj +<> +endobj +3 0 obj +<> +endobj +5 0 obj +<> +endobj +7 0 obj +<> +endobj +8 0 obj +<> +endobj +9 0 obj +<> +endobj +10 0 obj +<> +endobj +11 0 obj +<> +endobj +12 0 obj +<> +endobj +13 0 obj +<> +endobj +14 0 obj +<> +endobj +15 0 obj +<> +endobj +16 0 obj +<> +endobj +17 0 obj +<> +endobj +18 0 obj +<> +endobj +19 0 obj +<> +endobj +20 0 obj +<> +endobj +21 0 obj +<> +endobj +22 0 obj +<> +endobj +23 0 obj +<> +endobj +24 0 obj +<> +endobj +25 0 obj +<> +endobj +26 0 obj +<> +endobj +27 0 obj +<> +endobj +28 0 obj +<> +endobj +29 0 obj +<> +endobj +30 0 obj +<> +endobj +31 0 obj +<> +endobj +32 0 obj +<> +endobj +33 0 obj +<> +endobj +34 0 obj +<> +endobj +35 0 obj +<> +endobj +36 0 obj +<> +endobj +37 0 obj +<> +endobj +38 0 obj +<> +endobj +39 0 obj +<> +endobj +40 0 obj +<> +endobj +41 0 obj +<> +endobj +42 0 obj +<> +endobj +43 0 obj +<> +endobj +44 0 obj +<> +endobj +45 0 obj +<> +endobj +46 0 obj +<> +endobj +47 0 obj +<> +endobj +48 0 obj +<> +endobj +49 0 obj +<> +endobj +50 0 obj +<> stream +xœí\[o%· ~?¿BÏ:KJ”D‹l¯�h +$1Ð÷:Ý ŠnŠÝ¦ÿ¿ ®ÔœËìñ¬“ ©ãsf$ñ#E~äÌx±.åÌõ'. Sbóôáðñ€è—`½Áè�µ fã,†%¤dͧþöóãáãÁ-h}¯|ÓW>}8@>ôíW¦|ùôþðê+gÞÿçðêOh^¿~õõÝŸß0oÞܾ½;X0M`4(3¼;Ü}wxõ×ÿøÝOŸþûôS?ëù·�‡Wd,›Çw,J¡±`(šÇ‡×6½1�ÿ< ]À•u>~oDNŽÀ ”O¼ {ÏH>ÀG¢úyWÎó˜Ç¾,ËüËßÿÕhë‰M‚Å›ŠK†:ˆ€z´Fd.xÏ&á‚Id )$+2ò!¤`žäêÀ–mi 6E–3=Xdk’h'?"³!ÆàE–¿a¹ZŽ“å’H†B†ó‰24‘‘œÈdìåâP–Eš—K†|Q!d™üX‘y“œ\á Lq:J Sòõ(´xr¶¬aÌG‹uQ/Ë-)„ PŽå»%:kÎzº…RdÔ€¸ÅaDdçL¢¥Ø-É€Ãö„É\1èÓa:šõ•£mNYß@}6NE[[f««â”µí+gÎÊz«Tdnßò• æ| 8Sc.ƒZ,³Ln“-ÀV0·eS1 2 VûЏ;€º®»Ê4Cw*µ–æ{j½ÝI'ͺ;+ ºÛ7œúî˜àìûHÁO˜‡›ñ~8¼Ë‘iIâ$5:•?>½?uÜu�¦¨À¤0G�°úðbQçThõZ�ÂÕ•3D›ãǶ5ER½› �A„®m°ï®¶qY\·w#"RÛƒ\í�²°ïV®žÁY\76J. kàîm"ì‘‚‹cZÌâT¸¸nY@Õ�űó5¾9ƒ>NÍkô@ÔlžT6[(¸�Ö]I“*}Ïj·­®ªñ MXÖÀ1£Þ#Œ¶�=eKWmýt˜�WýõHØôsâØ^zu˜µç|fS²ò�”Æ�¿Z*×wt �#äñW˜CŽ+ ónèVYš‰¡˜¸yí#ãRåOzå{cIÊKÇâ•GkE•÷PÔ>è©=U�Žu€¾ÿ†Mâ)ëq·î‡ï.IJʶ΄41¤!€AäÔ€êïM R5Xåàt!0E¤P'FÁÅYã�/Œïê¨/«@�« +-žzJ%þÊÒ)Ðm�ǾžÃEM97ÇeW~[lÎ×Þ×˜ÜÆá:v=ÇÚ+ a ‰§�¤mH‚})HÚy©xJÏÏ„AcÃL·Aaº”š—ó¯¯Ç0±(Ü®ëàĬk€Í[�*/àºíêv”ã¡ÎÓçðÏÜjÀïü2]À-„òB+ ßÈ9…ŠAY»fP"‘”£ø“µ9;»¤B½È$‘óÄžDš3¾"OÖVj 2�Èò׉:‰4ó ÅœD&ƒ«<'¢La&Ú$ÒÌvkÊ¢$m€œQ­�I“:Üs²¥§ïi¾žéÇÂ:#PëïäaÒ´Ñ I§# +ºÊ[&ˆ;ÁQưÇ6sÕ¢š'‰$«lô(5%«ÙjîžH’Hsš7jñ•LZæ€C)¥“Ѱ6BÀ…¸¤‰‰4¯Öh“A³åÄŽ²\¹B¿R9�šCyW_�ò¾jå¯J?åÙ µ:`j¯(hÕ®ê&ˆ'LÅÝ’{8n“"k)BÀÍïGö'•öèᚬ™‘¥=Ì·©‘õ°RkyêÞŽš£.¬JÓ–Ó%ýµs±Dfx)RR¢Dðžžnjd¿)ô©ƒ¥Sc½Þù‘òrZkàÆ‘Vs&Ps—1®¼ó®àŒ {xn/cc#^»všv�ôvÙ +€SèÀYÐÀñrf7È™—:9ÓŠ'Ö–w +¨ûhYl Õ¶0.ž�Td­E“é¼­j?£ÙG3³¸[1 ¸>«às°‡jÙ ªÅ`vªu[H¹lÊÆQáÀ>Ìä=Céko*ÕMûpN§ûU­ºW|µñá»k" �ƒ=m„tãÜ:¤cÛP騧F3îÇmy¿'ÄÛ�/–-Ä»›Q¥æ²Ú<§H÷Q”ÙÌuÇ×]U�XŽ]ÜŽív8vlÏ�•‚·_ «q:̺´'̺í0K@g9U_ž%ÎמŠ9GÀ…màäûuàé K¸'Ⱥí K6¼x+öô‚ž«�ª‰Öõ¯HØ!±*€‰JÍ©™Tgn*€E*µ©˜(W{V"“¯n*€E*¡*€EØ–Û µ˜™,ÃM°H“ ”FœE)IQ)UÑ\«Ã½ìR£ômš¯—rje½äSôâpÒµU‘ +”^l*ðjQ:�Ü‹We{Âl®ZU×À"¥ƒÑÔÌ«éJ¡FS ,RQYÝ' Ê•ŸçIÍ\#"O5°H¥šŒFWªNœ .õé|‹@¤²Zk´Ñ Ysª�³\9C¿R¹�šC9X_�rľjå²J?åÜ µ :`j»(hÕÆê&ˆ'LÅÝ’{j`·]uÂäU \”p‹p§n¨f\N¡•€×Dt]SØCžÜv}LVJþîêc§ ñBæ¶ ¥¯�_ÚCI6{m6�¿±º˜4eóve£mÊæÝ¥ºx Oà±É27jV¿k¾¸Ù‹¹ß ê¨Ý?»þ– œ«Ï <”çPl�Þήô;£ò¢¾ß0~¨3]Sõ“®ú}Üßi»ê÷|ß_ªê']õû´'ŽÒvÕàlaûŒªÿùqsg7€tò ¸+–n'Ÿ`Ï¿Ïíìî* ¼N:Á퉚~;éúE Ý]™üZ`u: +aOÒo§#¹syÆuëþgÚ¶™nÝ ¶pÎ=e'+]›xkM‰Y�ö¬ÈÛ1GÐsÑèXäÔäÔs%iž_R`nY«Tû9©*$P©ê¤ëÅ¡YIžyÔèœeô(óœëœçA®É…ž”ïEØ“2üF.d0ϦŒ_Â÷„FÝ(ÚFäíOy´sêÜ›Ý/<ã×q¬³ë çZS®V·uW5ØuÁEs‚h÷¤7¿Í ¢;›Þ~ÁŶçŸØ4z >›‡qÚ*ѷܸÖП`éÓÊîTùþ0[`Ê{«Jå:—ÓŒ*Æ]ùl›QÅøkÎg—©»¸œŸ)´rÁîj5¬Û9Üκ¸TêŒ^ÆQ)϶݌¡ßÖsuÅ4š!yôú \ï +Ñåôs®÷`ôþê÷/i"ë—£ôTmTÍL‘‘—Wtï_¤1H3w´G9·¹UUD6Ä@Së_¤,èÖ¿ÈÛ {¸"cH§Ö¿H¥i?:ÿY’R¢Ò+fLSç_îÍæ1HïJO³õþµZWïs«õ�w}´¦ý¥ ŽHo°+àÚûEàù%e {Âb®T·ýE"=Š…)©É¼è[^©P‹ò¢/«'ßX^¨¡Ü0è:Ò‰®¿H¥NF£F26ð„/�èú‹tÝõgì–$ÝõÏråtÔõŸæP¾ÕW£|°¯Zy+�èú+$”ûwÀÔFÉжçæú–ê&ˆÇ–ânÇ=Mÿ°Qø¶�#bMW^w²v GÓ°?Ò{7Øp~ ÜWˆÞ_óú€~N™Ýâ¶ŸSf¢•Ö¿»»A—"ì÷ôÂv)Â!¼Ô]€0¹,·¤DHøLŸ=SPЊH¨Â#6³žbx½H. +q’æ.<ÔsêDj߸ƮºaÞCÃvÂÜé`Á_¢^¤4ìðê6¥Wfémì2.™¼…¹ç±}ö¹½fË öt£Ã6[N¿­{9Qw%“ÝÓÀˆÛ]Éäìÿïå|Ñ{9ÉÓž{9Qgiyd‡ù·³tŠa�¥_ê^NÔÙ0¥=Q3ngCyݦÑí¿YxVú9:lfO ³×_ $P3\Ý�N<üÜömys½‹üª¬ßìq´È¼j çs.Üh»íª^GÔÉ w½fº�ÝìÙGmŸÑíð�]�.Áô2áú|Øî”5ÝžÙM9טsÍ­´ÉÛxmL•�‡9¿9|sø˜Íb‰q±Þ8A>Ïÿ«ùvé_̈)³¹‚I“µ\\"Ëý=ž ”¨>ü��ŠS„\&Õ(ù&²«Ÿ©Äãü8yýù3]ÕqX ÿÿìO¤_¾$á‘ÑékrJ°ò¹q-/>‰Ó|²Tm™ÿtÌÅ +endstream +endobj +53 0 obj +<> +endobj +54 0 obj +<> +endobj +55 0 obj +<> +endobj +56 0 obj +<> +endobj +57 0 obj +<> +endobj +58 0 obj +<> +endobj +59 0 obj +<> +endobj +60 0 obj +<> +endobj +61 0 obj +<> +endobj +62 0 obj +<> +endobj +63 0 obj +<> +endobj +64 0 obj +<> +endobj +65 0 obj +<> +endobj +66 0 obj +<> +endobj +67 0 obj +<> +endobj +68 0 obj +<> +endobj +69 0 obj +<> +endobj +70 0 obj +<> +endobj +71 0 obj +<> +endobj +72 0 obj +<> +endobj +73 0 obj +<> +endobj +74 0 obj +<> +endobj +75 0 obj +<> +endobj +76 0 obj +<> stream +xœí\[«$Ç ~Ÿ_ÑÏ÷J¥ºÂbØ™sÆâ€ã…¼gÛ„ØÁçÿÕUU}�ïKì…åÌTw«T’ªôéÒ3+ +ñßL_Ìâ«×8 ÁO~¼ü|A4³UfBg&¥ Ì ½ŸH¡�mjúø�Ë_ÿ0ýtùùB3*é¥OåÉ/4ÍÎ0=ˆ×ÿòÕ”>|üþòæ+š¾ÿÏåÍŸþö¯éíÛ7_ßþø2Áôå—×—Û-Mä'3žè»øüˆ¨ÐH_>~yýúvyóçÿôí/ÿûá—J +3©ëûË›»žPOï¿»`Z5NèaBÐvzÿãå-½Ð7퀴ÐÀx1Æ×-€¾æï>�LŸù/�SP!}6/‰†1é»Òùþ�è3-¾fòóúÝm#øâïÀ¸|äÿ®çC]Ü-ÍQÖ×̃i´" —iò÷¼v—ø‡€R_Nïÿyy}¿¢Ç(©DÕ)ÑÂJ¤J´þ3+1*êžÄß­Š0IiZ÷ +ŒŠÏüðseN9G½'óÇB£Û=—×¥…’;e¿f^¼˜Óg¾±(oOŒ²ÙFŠ=V›ÚcçÞ‹µˆzÍþª�»,fЬ¡Ç<?ÁôþïÓ[£ò„7aèJÈî +€üý–ÿFC}ÀHµ4Rý„‘šc#ETŸÁHÙ@YÂQñBSòÄ('P¼_® å±7h#øY;�>Õ¸)[@<ý„¡Ç¹ïÙZ˜Ö« u?a¼H:‹·Ny_ä¸ÌN¬ºf'>Ú·Å¢Ê(¦lÔõÞLï¡ÃÓvv©Ÿñ€î„]š_ÓFÛ´£ÌZ…¡mi'Ä.´EM¼õ»oþ±³ì5?;œ+ª˜A°·l÷Þw®ñRh—3n<O™Lõùg,×ïµð*&ý�V›Y\lÄПŠ<-QøÐ/IÉ#]zìé–gö¬öÍW†¡ÛÂx}¶8ï'Ä g3ýxñnŽS¥!O¨Õăd��ƒfFÊñ ‡`CÔÆ=}`Ö+¯( ;«|$`@¡�÷ڈ☲ÎÙ�ÆøszˆHû4jƒ™¼e:!P´^YŃÚXyÐC0‘€eþ´Â4ÈêÉ^ˆÉ³‡¼ç1†¾!>cf´^»þ={ŒÕ’�ž�&UÖQçÔ³"›…Vù£9XkµîVB³#¥ûEÓ¬ƒó(¥C3¡Ã$�*Fš1 §,éD²*G­©‘Šž?\†xùvêH/_9)ñê!¤I{Ä«OìÕe(^¼¬ø3úô|ŽâÇl”x£â @õ"WÌ +Ø$ò¦Ål“™:=ªªb•T\M ÚN3’ú´4(1“4¾Ê•4ÓÊ¿´h±ViüU.r›TÊ-%„-·_U‹[S oþáòíŽÊá܆/ +û¾`b—�BtXNù‚/òi;FD D™�¯ÉÀÝÍ(y*ŸpÆXãQ«ÂgP"¤šE Ô ÔyYÅ©Q@s’Q,eÙN8 â)î-øŒæšœb=ñoùïk6–y0ƒÓ+Ñ §ønÍ›<"ò.zTdŸù‰ðQé•ôí!;ÞwÍšê²^NqÇkF?8ŽgtÐ(�Õ%Šp½"ÍMDø<�°‹l”y*‡r"´Q¶@Huð‡W4"áå;fdÌÝ…žþ<ÇÂ×â×r,kk*.áÍÉì‚åŸÉ¬à‰è@ùšZ)Gаà8F± X˜÷‘a ©ÆÓFu8ÿ3«ZFÈ‹HŽÓ+§"TÂâÜ>54�‰Ž"NaÐ#Vä¥S#õ”S;ðëìÔ|N­dCÃòTí‚ëG�‡êòǤŸqêD™ŒÞ +ŸòPîñÀàås�%f;ßJö× NøVr›Ù…gÅs°¿ÓV0«´ˆf)¨1šå¡E4K�–Ñ,®D³<¼ˆf)èE4ËcËh–G (ð2šåAë•Ó2øàÁ•h–‡‡h6‰h–‚é£YqC‹—¡Zus¶0Lð×6±’ÜÉE×0°I§…‹BŒ%°ìÞBP¡µ¦F*zî¢YB뉦ŽŽÑ,ñê±�fy˜W¯'¹ XF³<¸Íòð"šåÁE4˃CÍòð"š¥UÅÐE³ñŠ4XF³ÝLÒø`Í +þ¥EÃZ4+ä"·I ÜRBØrûá2š +ôMÃÏD³ês8ËÕŒìö| gUöì„ÌÒe�ÁVZ�œ÷Vzz�ê™óþ/²§× +†%ÿæÂW奋Õô ¸RàŠ]¬Öêÿ+|¥Âió „£N[½•€ß*ëúfO%Ô“U°ºtÝÛQ I ó¼ +¨çDýôž*füïéÈP�¤±É#µBA,ä@ä¡*©îxqÏÀI:€“ñxñv<^>W A]ÅÀS= '’(6›>)KG³îD¶ÃÉcôdB]ègœ�Hb‚½§È+}Jù�7)‹Œ®çKòe£Ö„‰àé´øõIѯÍ÷BSØ M±Ì¯¢E†¢x�2)óoÍ6:1;{6øaV‹XfuÉá¬�GZYëxÅϤ¼wÊ5•òúf¶‘ж'B¾ÀÉdDS/@ê=ѳö-6_§Ó!È\›©TÛv³±h‰'®ñB˜•Õ`½=žC™üy +N© ôsdHfKÁ£ŽE²IÊP!¥ÈY}8®}fÖX°Ö‹Z?>*ýšI!9  V¡2)ÐŽ™ÚTß&·›¶óðúÚ~ÜØv�¬¸´+'–@XìŒY¶[ÕS¤¤BJK 'ÍŠ“¨)×—ü¹dãÝàH2õ‘Ökö·]:·œ˜cTZë©wÝ6¢›¦Ò¹¶|iwÍ2Àý5×SÜ÷r¨a„)gé] #"¼«ZÞÑ¢ Y‹•3+¸}]çŽÒiå ïf«½0Å,–’>h3Šd¥…£8³*f›²gš³*È¯Š¢¨:ô©è1+Ï p·&î¦æ£ 0‚òm‡àZÒüw‡ð›s�¯{K±ú¾¡?wÛò-I±vÚ‚Öá³z%7§à–‡‰k�êøøÒûQ•Á9#é×cz-.8:¢E]±�{kÔ|í³5˜ËŽ@+èßs`"&§–ÖºUŽ‘> ˆ<ý†QZÂlŒS—¹5Ú)®i_Ø\øæ2 +aÏ&NÚš{/<.ÛO€PnþŠ0íwÜ:$W;PÏB@m×%â݉I¶EµÅï&Ôݼ°¹{ì§×Ù ×ííŒp7õúé`z?ÙQëD+V÷~“;ã"�8°ûpé¡gÔÝ8Ñ/ÕÑ{P-$ó}U£lNh©V—7ÍŽ]Ö V2rîûRÁ26Ý´òAϽu%yÂÊ»ö]ó‘i²�Û®îßvÈFYIƒÈĦÖȤÞVÝ™ÔáÚ™Ôà:™ÔßÚ™ÔÞª:·�»[{ “z[;“:[mç�rcë€cR_«îpLnk-ÎÏûÇÔëÂ&:=ŽI3v8¦2&¼vá_¸w±Î†ª@\H‚óV$›Æ$UPcªÊ¨¨´‡1©“¹‡1¹åYΗ<À˜ÔFÝÁ˜ÔnÝØܙ=À˜ÔÃíŒI�Þ½l#j@1¹y¼C1žª"i@1|IÚ-QŒ˜GÚWfHaáYZk[�´kZ‚˜*.¹SôˆI +èALU”oŠÜ1æ �¾€¢9)–hf�žLiŠaæ¦V7ƒ1¶Kú”ßÇi!e-eÿ„ù<£„•¼ŸÑt™˜¾X Odg‹¤< +–Ž×~ÁN)šy)…‚¸”ø]ž³ÑýVIãY�‰¬ë…Ù¤ $~ë¾âvW}.#4þQGZoû®ÒJyíÇ“¯>ô¹ +°tÅ-€§Ù_N(……Åd ôì«–RI„†%c»ð&,xTeiHÕ¯u« µþîˆéK|‹BèJ²yòo.ß\~Ž}‹J{œ•™È€å¿Û?-ÇŸö~MŽ÷UÔ �B§@r³óLAÉidV'ûŒŠp�ŒDÂìc†­Ráæ`¤ü7䂟Îc�ÿ†]ªäí 1ŒB¨›Úì?pç‘ä3í¼:xÖÏ&•ýÅ|‘e©™ÿ\piX +endstream +endobj +79 0 obj +<> stream +xœ}�½JÃ…¿Ô‚(Šƒ28¸h“¦iRpi"×V¡©S’¦AìOHSôtspu+.¾€èc(âà#ˆ ³¤AR�xàÂÇáÀ½÷@®�— ?ˆÂFÝ[V[œG@`*ÛdK€ï—$û¼õO.K oä@¶¬6`ÍOø,f'á˘O£ asxÐ0A¸6ývfØ Â8ÿìô{c7½›%opØZÀ:u† ñéáQ¤É ÇØÑ0QÙ£F …*åéÔ�(£SÁÀÀÄDGACAa•jÜg²rxúÌ]¥žs PxM½� ¬œÃýcê¥vhO­<�ëváó–-X}‚Å£ßb3~ÿü*²Ï—mDJHÈT~…ÍK½ +endstream +endobj +78 0 obj +<> stream +xœí�»Ž+ǵ†_CÎ+ì`gHÁŠxA‚8ÚŽ ö p0‘eè lÓ� =¹·Bëì`ȾÕeեɮ^ìîoðacv±XÝì5ü¹ºXµþ�~÷?µ|ñÅoî~?”Oþ÷3«åáùðZmœnχÃó}ý¯Ùbþbÿ¾©^O�ošß϶�nª×—m?x¤§3fä$¯Õ®}è¸0ž¸­^ë÷Ð�ûCûßmõ꿜ùà±áó/w_ª}n æ£" +lÿT» ¸Ö·~ç)u{Ó9Ü3[�ßÜí^š1«—ƒ­Àµ>w²lº±íhKQàO¿Úu?oÿô±ú,’ñfAP‚  + @ "€£(0\90D-P` ˆZ À@´@�� hq +ÜmF;æî&›ç¾³[P¡˜Ÿw +gèd_ÕÁÚt|ÚäÛ×jp@�ÇÆ âÇoëÉÔ…(H)>‰äñд ó¸?´}òu9ˆüó[ $…øþéxxz4«–‰Õr6UW¾ç¸ßz…w ïzžíQÎݼZm�ÄN�ÿð§¿R¥ e¸ÍlC5ÊúßýX*ùØýr·Û× +üÚô9 ¯“›å%_­:–0$ˆR|jùëÃõO`Qà˜À¦:X3 »—ZK{–†rS\IÿahåYˆ�Þ¢À£QB�Í gN ­À–Øvùp_øô_W¥6Ž‹_Ä7¶(0ÀhP`CT¥o’9pŸÓ¶9p;x3ç æÀ''‹ú‰äÀ×ñL§ÀŸ}Ý.Š “"–îµ*ÚMÏÖ_« ™¾ªš>Ûªwܸk‡:¯X‹Ù ÁÐ Ö|öõîíŸÿP'À_}þ†y`€±]�ýE¼ÝŠˆn–àå):Qì[ÿl»5­ \?ÇaNGm†`H?ÿÒ�ph[Þ~ý%90ÀxÜÀž8Ї ¨€AЂ  + @ \Š´@�´@�´@�´@�´˜‡óãû×××?~¥}¹F$®Àÿøç¿ÞI?ÿøç¿¢ +üýOÍžá_¾5Ú¿ýùÔôÓw±“¯þþëé៿¿@�ã#Üq~÷îÝþû_ŸwïÞÅø»_º² q½ÍÕI–H >«ß¯?|w–ÍŸ¿¯›„¶ÿùå¯åÛZºþþ¬áÆþå§M×÷ÿË'®2ÿå‡çã~#ëÛ®sýÓž€"ø<qRÅ^ë‡Ò9p-¹~}ïr#žõPưFþ¦ÿ8¨õ¹Ñp=’ +üÛoÿþôÿþfòÛoÿŽ(°©oŽÖe+p;ÛàæÀM{?l¶[ÿí†Õ¾ø°rrØ'¬ÀvÞk+g®wÚ8¶[?¬¬m’ +üAú *°9×Úÿf&W`¾˜€›b\ö§X#“BK–×KÝêunþï�»#;«)¾ùñ=³ Í¨ë�ݯÞ>é³âZ$ëæRa»%®À^Rm/±øõ½utïXÎ (0h3�=qKÐÐÐЧN ˆZ À@´@�� h�AЂ Åø +¼­Ú}¿Õæáù`ì~Ùê¿^‘x÷ÒÅqpc×âô‹"9ðIxÏï»î—æ÷×ÃÓ£úK/ˆ�ûCû‰¹­^«Ý°Æ‡ç—6Ð÷OÇ×Ãó½ö ¸M¦Sà&=&#ºE¼ î^¬�Îú÷üF±ÎLªÀ§wëqÿ ÿªÁÁ ¢{ó"ÞÑ„ È�"L«ÀÆ+Ü1î>7óû¡NÂD 90Ë�OòËÌ?@æ�¡Ì<0Ù/@š‰×Bð–¼MF^ �üäÁz`=pÿ7@èb°'"€(0D-P` ˆZ À@´À¥@ r` ˆZ À@´@�� h�AÐb® +üð| æáxLDÂpf|w'rè­Ê[xT¢Õ)O•²jüæ¥é‰™¬�2 +lÖ(óÎB�G%ÄÍ)†»‘�X‡3#X=eØO¥N?M‰àÓ›®Ï€vbCi»‡Îùع}_ �ÅÆû;ûw±ç�c1¹¢RÆ¡ ZÂØ_´:¦Á`mÚÂT°„5R~¢s3Œ»Q»„»Û§�0toQK(°%(pµql†œ‹ +–1_tÕXÏîRcf+¥¬÷3 ^{¦¿?½ ôE�M‘Ï”e¸w9i³Ó`,¥ŸXˆ÷$û…U3Ql‹í¦:wpoW¥>fZåÌPàþb“æÏZ‰ÉüW3‰`mžªæºµ¦Eá°"¿°v +Ï›"f,fhߘáµm‹¸¢Ú P`cÑÅËS¢go¯s8®ê«ùè�L©³ç”÷ª,Ó¦*·§ó­ÀZ˜ëž¸Ò¬l½ñ2ƒpó À&FZ¾¢xaA˜(0D-P` ˆZàR 90D-P` ˆZ À@´@�� h�AТ˜{Ö6bÕJ·pV»ÂÜÙzîcUè2ŠÆ°¡uä ö{´ûºÒŽ•®=Ù¥ø´«÷h·‰»‰ÕÏz¥=žïÆ4vHëÀ¢P2]6ê ìw¥x�àRH�‡§G«ød¼þyB�OYq3”¨À++&9:^åj¢R¼Œž‰Fp)£À�ûƒWˆÛ)x˜´ s•öq°…7> \ÄSáÐcïËç•Oï/¸h ô +‹" +l•”4í0œZ”öS +|’…“ˆóÀÜç^‡ ÀÖý…3ÍîR–Lˆ¸=È „[&È]%Úïvä(p�{í$À×#åÀr1v×Tˆà + +(°‘÷ÊnA¦%±Ñ-­Àç4¸ª$eÆhì*¢9°©Àb>Ì<0À…ñÈpmp½;Sß(S�·1ÑâV÷r¤oâÌ›—úÚŠ¦B¬…¸œÑØpŸoh2([c{÷±G�ÝõÀÎC¾2{ÂA<Ó¯þíµT6b=0À…°'"€(0D-P` ˆZ À@´À¥@ r` ˆZ À@´@�� h�AЂ E‘ºv¹ÈMeoM56·Ú%¶ÒVDžEŽç…tÆ*ÎVŸ‰?Nµs·BwF»ç™;ŽØY;âYA À˜”Q`ÃT¨y/¥Ôí³fùÁŠÈÖ“ß É+±©„"ò˜NÉ÷àyf�3Ÿ²`~%C"™2 +\ퟎ]9—¾ž¤Y2ë®yÔ*³ã[ÙÃ:j&x!Éõ»†*pê<3ÇÉWàö¢uo6M>QÁ·Ø,Ä|>GfG!Þ´5*7Õq¿�(’S»Ò³"r†µž›ðBÎ*ÞSNÑýá‚q˜“0çÙ�¾Ù$ùgD�É�ÊQJ�yܽžïÊvV›�‘;¬Ýâ{!õ’UW6‹ {•…Iæœó4Ž×Y¼ŒÎ‡ˆø{I +¸§€1(¦Àç)‚ÃÑsvKæ–¶‘7l×÷BrŸuû9ð-*°mHcSN�{o…¡ó«ÖÔ±7lCÀ ÉÉÙ.S`•yà›S`²_€âT`©%o��aE6ä…äâBž|-ÄÍ)0ò 0+ð›Ø:[ÉŠ(0HÐ ©{T˜�È^Ç›8Ïìqò×ßš ‰`LØ@ xRä-~ú.Ï@"€(0D-p)Ђ"€(0D-P` ˆZ À@´@�� hQ|WòŠ­fD¶KQ×~Y#XL©Àk³þ™y.EFɸmÕ~ðå7€Ë„ +bÌ*…«¹Ô�ûƒ-¼îÓÍÏÁì�Ř ]ŠBSy]1É�ß�wƒŸ³m-�ÄûâÎä·}{Šgb�' +¸ò‘«¼ÔçnuT`£˜p~È"ƒÌ‡b³²ÁMxjÂÁn<Ýff[�9„ïœ{a!F�Eº+¾JñKý¦Nƒ3rà!#†EPð›¸sê⥵§\%f�›Rˆ¦»¡û⮃{÷jœIâÐË'ºÍK/…ü3~©ÏipU¥æ�‡„Œy`XE×Bô¶DîÄBÞ7qÝ—8ÉgÅî‹k¤opº1#ã¬ß#C¸ò¡«”s©ë5f�e ÞDFÈBƒÌŠÒ.E§i¯Æè™F™Óë�;§›×þF8¸ØjÚ?�iÞæëuñL'¿ÄoâÜ+¸J÷y—Ú^HæMþg�#þñ ¿0SØ@ "€(0D-P` ˆZàR 90D-P` ˆZ À@´@�� h�AТ˜çyÍhºá@2ˆRÅ›nÛx‚n ³³9°©ZJ)p®=�žäÑÖU©¤§Q9m[¦TfÁÉ5–ÚÈ¡�'¼fâ>D%Ýp ĺ4ÙîÅrò/ ÑhòíkìP; HÎðšiÞ¡Zn8b'›†Àžœ§ŽÝÄŽP§7¬ÀÜ}ˆQà¤×L`x:7ˆѸŰØÊ‡ý‚ùígœÕRB�Sž5RÑïiÝp ĺšºùÓêª1 ,ïu‹óó5(@‚ +œáY#§£“¹á@2ˆ¡¸Ë“…yàà`SÄ##ßkFÅ ’A´.²5ó`ÜwÔÁ’ÖBô0ctŽzÍØwµw:n8� ¢�“Áöñ2®§¿¸ŸÇà²D`OD-P` ˆZ À@´@�� h�K€äÀ@´@�� h�AЂ  + @‹‰]Šü‚íN­óÞÖ]t»RDN¥w“S¤jg7ú5Šó ˜2:»‡èÍ}œkUv{µDs·8uuJ1­K‘ä%da™%¬Ž.Q`É)ä…dZt$4Ë€)ÐY:Ä›î@Á28�ñGÂ/¯ôÒê¿äLã0µK‘ï%d`õOZ] À)±•½Aѳ²ª �ƒÇõŠsZ%†äñÇ"6 ‘™Ü¥Èójñr­„ÕÑ›Ks`W ‡)p†Sÿ*¤Î¡ã +§!”ß,”‘F˜ ÓºI^BÝSüâÀ)«£~–ò¢yà&áôÆtÌw6•15�<+³~¦ØÙ:“¤w'#�?Ñê”T˜(…†K‘í%t'[f¤­Ž.û&®£3E +æÀݱû 0~VNº(wöO^üï��—KG +õQ€«Ñq)2½„œ$3�+¸“ýüÉáôY™–�ÎÁCäÌ—²œ¸Õ“ý”EÇ¥Èô¿ÜÏd¸‹¦Hƒ¾žË7` +u"k-„hrz5âj4ä 4Óº ^B›êÕý©v¹ƒX +,-¯u‘L‘‚ë�ÝA2ϪÒ}¨³ò&ÁõÀîøã.NpxëF5({†h±L–÷��ó¾n1ˆ+`™ + !ˆ* À@´À¥@ r` ˆZ À@´@�� h�AЂ .Eu»yÆÞáÜWo—¶<ßÖ†ßPežèo¸\Š„’8féõÌWk�–ý)ã:tu�BmÛªPQbÀ¥(âû3àUÄÛc§QÄuèê î^&M0"¸…Ÿ;äU$Ú:â�x %FQ`€òàRtºË5pЫˆµ{eË»]ÄÛËÒ .E¡™Øa¯"ÝnPÞuèÚ ’L.E�oà«Èi÷O»˜ëÐÕAd` +p)’×B }YíÞisº6ˆ¬…˜\ŠúÓ6¦j‡¾Šh»¸¸¬ëЕA´¯ 0@)Ø@‹e*0.E¹Å ¬€e*0 „ ¨€AЗ"-È�� h�AЂ  + @ "€ër)ŠÙÉ'lîM>o ö÷›Ä Èá +ó7»’TX—KQÄ(yÂ�"¹‡ë+L‹ð$_µ>TæPaÅ.EVQÊбöOÇNˆäš“9¥€£¯ú :%€ +ër) +Ú…�Õ¶lªã~+.«{ðUßThPa].E!{ Ø ×-mÑ`ïp}yù !QøUß ¸¨°.—¢€=PüX§ ŠÃ1èþÊÏÝFÿUßäÀ*¬Ë¥H¶J«ËÏóÜß‚�ö«¾)˜Pa].E¢=Pæ±r§|#�Æ«¾1X  Âº\Š${ }æ±²X\,¹Ý¬P�=q@´X¦ãR4�[ "À +X¦Ã@"€ +(0D-p)Ђ"€(0D-P` ˆZ À@´@�� hQ®B»µ97jâc•sL”ßñF+•É;2"[•½a·Uÿ¬AþJ9{“ãH5ý 8‡ö.×õ‹‚ +lÔ瀫NÙ¿s7U^5›®fÂ0=±Œ�šc‰ã‡õ±k£åú+eí‰X ¹ðô�PœÓü\( Àm½  ØözëHKÓEÐâ"3šgû+ Pà€’_-9ôÙtágVN»ˆ À)R�2.h�Æ åeFlºËe�Ì N9 YõÞ‡(pÚ©�bÁÌ‘Šv¢ÀJŒ¯ÀÛêµwü1îdƒ&>ö¤î�y`cÞØ›‡‰ këXŽ¿RðeŠÓ# ¤–ÐG›-£Àó¤xœ7‡K#óõätWî™Í�–çù+ Ê�ƒHäÀ« øôÓÏÊú£J P`áYýÕØíO‘/\Š’�ë?Ñ^¨Ð>OâóÀík÷Ê‹’bew�Ä™Ï5nvEÊîé4öùmêé~‡ä³rþ¼ÆÔë5?ñX2¸¥; ç³´[ÂØZˆîªŠ5�}I±ÔÃt²3¢ºšßÓ’zñcÚ{ºuzæÄWôY¹áygž|½ÆlÏùã^,¸¥;‡ÎgADW£ü@c’O2£OÏï™Î�ãrz�¿ðœC›óW‘×ÛÒf&(ðbÁ¥(Ýy… +,_ÕsbæÌ Ê–š6—ÇÄçEã=í§t'–xº©ŸÆLêYò_xΙ‡‹\™û§ªù3ÞVõëÚT¡ïþ`ÞàR”î¼B^Uc-D¾Ð-vÛɸPösc©i^ÏàtPôé¦Ôáè9†Ÿ•ü Ϥ{ÖËSôõš&YÎ%]ÊÄÔ°'ÖDvÕ�6+R`\ŠÂÌ&ˆc`˜�.í^fÇŠÂDP` ˆZàR 90D-P` ˆZ À@´@�� h�AТLm´þÇ.`âµglUÕžê+Ø«ëÝí¢ùžG¯míp»Z‚³ŸÚÞX:+2 ÜY/ÓÙ{Û_tv™äR¶:¥©Zf{È�È!TÛ§Án·ícv/�­[´ªC¼ƒuôãá�<èž5ã“[bÔ¢+q“giÅëËb0$G�««õîvyÀTqž«ød–á} Dh´Ìîà�ûƒ}¬EèÏP¶-J£FQ¦¼K. –!‘õ#ù)H>G®[Ù¹ƒëí"­Ç2L�ÛÚ¹ÂAÏš91L�å:Ìöü<d0}3$= t=âM1,ž×Jk|a·ˆêÁCØ3"1ñ�¢ ŒÆq¦gPŽÇ�= ‡BFHÚWxˆ«Ñ�_€ÒLçÔy—ç14@�öF–I +â)jÞ4»öI,öÄAЂ  + @‹ÿÆÐ5° +endstream +endobj +81 0 obj +<> stream +xœ­\[�d7~Ÿ_qž‘⵫\e[ZEÚ陎�°<’"‰²$ÿù^¾œîž,H«éøøR7þ\¶Q€!ýïЇ>¾Pâ?½5*˜üñÍO??CŠ�ãè ­´õþ@0¬88>}ûô×ß?>ýü„Ê¥þò¯Úò E±;�>ÿù«#ÿøôýÓ»¯ðøþ¿OïþøÓ�ùåÓ¯ßür¼ÿîëËï_}|ùåóËåéùãÓ»«=Œ=>~÷d²¼æ}€v||üáé½Ö`µ&£µuZ[¯5Qþ«±|så_,¿hmIkò¹¬ÖÓÏZCiG/ùoªËZÛçÜjÇù µ¾–þŸµv—\'õuíã¦q¸Œ#dŒßmŸµ6Fk})对¿4ž)õLùVäkzš\¿ý¾jM�ÇŒõI÷q£ì©í5ÿKýÙ®O꣖q—;õóAØUŒ]uMu¡÷M­Î—ÇÇ?½~¼åÅà‹­íÆ‘RϦ”/IJè¬dñeDá¥j�XV¥÷fí7iqéÞ§P,GÂ\úzÞßû‰cÅâA6ˆ¶W1ŽŒ×elýÔö¯â›Íž|$šSý"?_ÖYñ¨G­ëãfýî{Ò€®žœ¬ u4(=úIßc?Õ1Åúa±"aÓ’ºe›¢ZÌý)—e¯1u2ŸáÉ’¾‰I¯__žÞ]ÿõý¯Ÿ¾m d +(½û›óÇËOiˆÏÁ½4ÆŠ}pûlÐX®ÓFcUø¤7”½y½v‡Ê[ŒøÞ;­èe«‡®Ù«ÍK�É$€sÊ¡±6Úâã?Ž÷2PSc•Fk\p­Æ¾© "FëD%ßÓ^Ä<,(¯mòŠ,CãFYRA£Á±ÆµÕ8·£�¼Â +c,j¿ÌÒÍŽY)c”uÞ¸ ËVó +Á{]ݪŠâ` î-Bù`Ù˜nçVYo +Ì›>  +l)ÑUÖÕ)bC€¢Åsú°Õìùþ@¥z àýÉöCùÀÜ7ÉiW„µ+@Çön¹õEXbÍì»›Êöƒ�nÑB€à�6»ƒU°¬­£»¢8YÖÀòžšêL€;qO2î vÐO–jÀ¿UtpLŒs8œÃ7AQE¹�ä`ÆLë‹.P"× y¼f;h…¨µÞ�B€.ã2ß*+¨AýöÒ!‘%Yäui(ŵS’$Ô%B…Xšå¢è:)KôÄÂùA@¢-Äî*ÈŠ~ºÓ©�œ3­¡çl‹J‰½¹Y +Å‘òV*±“¹ÊÖ1öœF»žÅº(ˆÞk'O�F“(7#Mh –”LzðÃHåö¡YäÒ)‰¤òu›Ðè¹íD¬Q�"k¥2’ÈÎ Z#¼¾ÓõæMY×õ:µï™K4•m‘ûa�ÆØg›J-Zð”ÕS�H·¡æ’à�q’-¸Ð_?Ž!énÔŒËFŒ&r8ĹÛl\¨�-7hU§êI{�¢ˆnÏ™º±LcLm’\¼–�¹^Úº„iãyõ¶Óœ"RèÞ‰ñ »€Á,g„мV„̫ط\$ÈÝÐ?L¨Øé6pYøÙÕg΀Aª;^:ÓpŸ¥»¶-Å—N”ëúÚ3F07rÜ´þì¶â$—‚<%]Phµ—8¯Í¡è”×�ÄžßvÚR:D­ íÝ…ÝËŠ‹’¯œØÇÜO(;»å3þÞ2×ùCy–nää’�$¾â&“Â/ƒFøûº.5eýÎEÇOÖ©”Ãç\äcŽ#–!Åj^+CÚÄ2¯Èe–˜ŽobköàÁåRÇàbMÒ`|ªi”ÆÔ!°sL¹Øqn¬ÑæBÒÆ–cÁ—ŠìÁÆ2Kì4æ2¯ƒ‰�9Êe�Ë¥ù°1KcÈp)Ч–Tê bR†}\ËÅw«¼ qaêÝXE¡ÊPdz +ÐI±"0'[6ñQ9@3ê‰Êç�°*4Îd{T³¡2!+ÙÍ‹J3ÚÜ_ul†Õ¡ß°÷R�v4gû¾^´#¶é`% TŽôåII ©×fFÒX4#©×° i,³1Ý5 i,�‘Ôkœ‘4-H #é¡‹ØËIË¢#�ÆÒ(®DR¯m™|ñ×¢éSŸº½uŸärœ‚]œMêŽ,R»AÍ +¨º±*žI£vÜëæ‡�›°ºqÀÏX4ã§×zÂÏX²àg,Ì`Yñ3„¨0øÂ?C˜ð3„?CˆÀ„Ÿ!DQiÀÏ*~fø? ül­~Šq~6‰:~6©~ +ý~6KÈ ¯“ÓC¯øÙà6ŽòÝ‘·ðóvÖ8â§×î³ðÓ=ŽŸ}(äœÄÙá§UŽ�3§gT7d™3&3€Z…v’¤h”¨�ï›MBó  $hÆ» 4WЫŒ aˆ +°;Єh  4�ÐÚ€&ÐB?cÙL?c™×'Ôšég*êô3¢Ýˆœí»€ÏÚ�@O1^EÏ&–@Ï&¾€O¡g‡Ïj�SÍl ΄yì5GÀÆaX:Â'`Ôø˜á`Ÿ3|z0Qc3jiâéqá3–ÚàðèF3¬Üh[³¡Ÿ±t¦ŸLó£á3}’‘`ú)Ç‘ÑU%AX¥–ÑÚõ“a]-!ÃVøì–•3 +VølŽòÝ‘7ànoŠ|BݧD€8.¹ �`nCg0²{t%Á¨ ò�ó-%ÓÒ\ÑeÚã�#íW¡Ö·½{ßfã&pºÙ!„üâØÈ@Oš lç¨ +(Q5Å鈪9\GT�˜Q5Ç쌪9fGTM1›éi ÔüGXM�&XÍ��°šÅ˜võ> Œ®fÅ®Z?ájû.¦tëGL~1bň&˜’¦€€¡iǦfaÍt 鄉"6gÀÆiX�:"kÖyDÖ¬³DÖ¬ñ„¬Iáacï‹Ê£š¸!¦>7êÄÔ§žGbË6ÈšE‘Õbó$NÈ?É`ÀYÅ82Àp&¦]j°¸!¦Ýr +Øec/,+g•]‘µ9ÊwGÞBÖÛ{Ý„¬d*²–«3“GŽoGß;÷6Œe¥-ûD›(XN"Óæ¿žø¿Go³r0¤ +Mmã6 ­×li̘ÚËYX;�¼Ò¨O"ü7ØIf·0»€Ù¯¹ö;ŽÙ�9Àa¡µ6´–Ê¿Vüå°£µVü�e�žð·}¿õ# BŒX‘¤ &à¦) €IhÚ¬ZDà\3\ƒCa`›Í°qV—ŽðËn…_æ~™7ð˼[¦%/Ë6Ä–i‚_¦~™6y�X:ç|Îôä6ü2 ðÛZ˨¡M^ K$Â�VøúÉÀ¦5/Ð &§ +oà·9Àmå»#oÁïí�r‚_‡Ÿ“€;nC^  â¨]Â*yTÖãÀe/íÒgPl ‚8�¤é6nÞËçž@ñ†?ËkÜgw…™t†kPêT¡;Ú-Â3R>@K°Ëåw]ÅŒ¼7,nçÁ�·¡å�˜÷Ë�X,Z ;è•;½ƒî Wî–±X´BwXÄbÙÝÁì ;,b©H w˜Äúw�a9“ãU +ë�X_@Z؈5{„lfk@*Ì+·96Ãêи}X�Û§ó#Æó›±X8·w+p{·n歷„_ÄbÙ¸½[�Û×±økn?ˆõÖ"fÄ8"ºür Ö¥Ñ*ôaÝ,!¿LL¿9ëpGùîÈÀ�÷Ä|�§T÷Þv =7×íÚ{­ßòöK"ØE\q¼Š6òjõ¶‰Ÿ‚ȈëÅöìMÙ£ä÷‘7hR‡z™ÕÖK·/F/#sÝÃë1êåz2æC°®y"]­’¾“¸Œ‚Â{URñfÉ‹ìuúwÉmZ]',õ,¢ƒû…‹­Gçv›:¸õì½…ï^? „ââ³¼>M¡kžâXøq¸Û¯Ý Ö=võdÙx‰«(Û+?âEÚzR<ƨÆ~‰{×§Ìì ¯ß0¿ŸËuᔉ{¯î”Ô"Y¯4É;ÿûÔâzoÛßp±#±å_noÉaå�kÐ޽ыöî¥0Ô†v—žB¹|,^†¶¡ËmE,‡M’‘î®Ü—Ö)7üâzT€È/¿@1¢.ï�Ï +}E«ôúÊ«h]F2lTd<>ø*—lo˜ŽîÍWÔÄ«¯I +l7ÖÙ ŽŸ¸ÅãBìtÚ>‹'©—’šŒ«¸~í±˜6ó‹qWý17¯÷Òê›�å.»œ¯Ó$Þ°mæÞVnÛç_]rä«�ÿÏM­ÍëÝyŒCöO]ß|ÌzËs—fo='O›¯{(ñ2'-ó— ñh÷d i +=Òv^QOâ ¯®+ ˜Ÿ&Ýà? yôù³+oƒãÓÝèQ°ñ~HšãßóÿCƒøëÞcÞ2|„ñíšSΛtpT£&%Ë3ŠD#Æ'Ös'ÎèúL·öb(#FúòÌH3°üŽÃÍ^ѳJ¯êŒÑ5køv“¸Ós1 Ú$ð™69iëUΉÈñ’ÈÒ3ÿ(-™í +endstream +endobj +83 0 obj +<> +endobj +84 0 obj +<> +endobj +85 0 obj +<> stream +xœÍZY«\7~ï_qž¢[’ª´€1ôæ!ž¹�àI3qŒçÿZꨤ³u. ÄÜݧ¥ªRÕW«Zó¿ &˜¾Sâc@­¢Ž1L?�¾œ´&å MÚÓd � a²F;åb4ÓןN?þmúíôåd•6”é•w¼ó»ˆA+C‰žÂ¦öß?¿Ÿ†'_9½|ìôË輪˯Ÿ?þ÷ß¿ý4½{÷òÃõï· ¦÷ï/·ëÉÐd­§É¹89—„øù“BpR™®øThb¢ÉûHìJyCúËk3ûû×ÓË?>ÿö¯o_ÿøøm–@W .¯§—N§×ŸOº¨QO&«ÁM¯ŸNﬠ@ïä´~?½þçtÝb`Ž © `À+X34 +ÓIazý÷ô®,£´œêò$“¯ÏuÙJ7:7’¼'}gîu?³sõý£|ÏÏÒógßï·.‹¥#) +1à,XÚ€X¦÷´¢´L0=»”ïÓÌðV_7˜ºk¥åšÀ™O4}·C«²6øÃ¥¬KϳœÔ”„ÔxÌçñU6S|­JMù½Ì ŒË;dË *›{£6¬+Z8ÒFZ—­ÁZÑÇÐ÷¦q¤a½Ðʨ%[´c#)íu >f‡¡mxÎæðž÷T…d¡|�ãù`· ¡Î—îƒ?ü³Ž(ark9Ýž{KdàùuÍdm˜¦Í¼þ\µ%jÁ¹ÈÆF{,‚]T‘²æª›yeÓ£œÓ¢ð¡FMÅZ˜$É‘á!àäÂFH’µ+ ÅCƒ¯Ía‹Í‡US3”¼T/ͽ„Öæ$bsV••;­/ÇÊ.—RéyȽ—Ìnì�„Uöj͋٨”Ž‚Áš³û¥GùÌUS,»–¸ÄZY'g¤qH¢~~¦¯¥ýÚ“%£µ;�Ké�ʸ@Ô·´Ee¬Ýnb�ZÅ�{e!€¾­ÄÐ0Ä5/<\÷©G:ͼn„œ,ß’Úcߺ$›>›�Í<”Qéù³é’i¤à2Ž$mI'õžiî†ýÒ…Ž9™µæYŠPã¬À ¤¢·Û’¹ì—­Ãµ—z3ãÚvª…ö•î¹­eÏke(óˆøÌó <AapÊâ+ç  [T–6[�,)�ºh'â¹è¢çñÉŽ6›ÒrL¶·ÖçdÀUœÍ&¼ˆÌÇŽpk±Ç0c�Ï�¦~>~×!Ö><׉ÀÄ’•Æ,‡gˇ¢(;€€–±qt‚øáJðèb½x^«O ADo—Õ§8l¶õ}iª,tѦì08û!B:eÓR×;d[ô<«ÐX[»`Óc–¸r³Š0DÓ¾ �Pp‰ +j':kMc~µ†ŽJ<‰Ê8Dé7¾À{e®­�¨½ŠS(BoP·/ðZÏRŒ‹¦6*ŠÚw�Â&óP™“çÂbǶeÂqËNš§‚ÜÌ™j¨ú¤]a3€Q!ª«kÑZŠ+¹w{ jÆœ-6Ü4×vkI¬Âf›�É!ÀÈ‚‚²éªBð1×’tmmàrE»T Y…&º¶ªM*XVÛ~Å£ÎU¡æpß +w¶PDzëá +epʧ½€phù¨ï‚¶sp�áA…A1]8*áWbÐ\¨Å7Oƒç¾J$rCµGŒA|­ +Z+rÑ�B¼U˜;Põ~âÊÛ‚sÙt “nàæmÎâr¤s-õá1äÍ>äÓ4 ]HÕn“ø/úz…µ +Æk\™ù­^biÆîbÞ£|](ätž ˜;¡‘ÍÈkäì× ÄnTC °sa+ +Ä¥"vÀy�)ï8æ:͵a�Ä̳<ýDI¡ñ8s9·2—ŸQ‡V¥Ñ±’�tå7¤4@û‹È5»¦0M‡9Ì`7à Å¡9tC}i›Ïdô~ÚÿMR–ÈM±WµW>ì†ï©çRK€É3—þ¦{$â5¨2�©ÌwéµNR4ÖgP_ã.Uœ‚ü 2 ótu_µ´•{r00–{ƒ¢˜!ùe‘¥eþp² +endstream +endobj +87 0 obj +<> stream +xœí�k�Õaï»ê~NqôD�2R,ŒËFˆkVH~ »ÊüH>b17Ö*•¹.=ð‡`X¾eyHº¾NÛસîÞ¼V2ÁÛyȱ ’X±ŽÉµ×Á¹²œÕ®VnfÎÌ™ÓݧŸÓÝçtŸß¿~³=§ß=}~:çLÏ7nú ÊNB!„RtV­¾ÀnÖ€M¿Œ`¼ +0Žñ�!”ŠñЦ"V®Ðcüâ,ã7€Æƒ½Ô\ ÀBŒ×`Àp˜¿“€µ Z90~÷€Z€h$ÁÈ(ȃµ¢A®`(-?ÈUM¹¢q?¤Pˆ@wüʸ?$°b%ƒñSY!Æ?VX€–²ýÊx„À€�ÿ8Tào(8Ln¿B�¬Æé²ÀUrøvà +…ˆ–î‘Õ¯*×É!Z ÊÇÈéWÆïð³‡ñ‹ÊR°,€2 Áª£\¯šrcüã“Õ²R‰–n`­_¯Ýò³|Ô•Eaú"¬^ÕrY–ñ @I¤oÂòùÕU¿ûžkßÿ��7|覑Í[¶~¸R¶@Õ~oÙ¼ñ†]ûþ\õ»ïÉjY4d@ÓÉãW×¼ïýýØ-‡¾öõç_øÞìOöëß,€ƒüä§?{þ…ïþÚ×?ú±[®yßûCÍY4d€³dð+yó¼á†Ýý¥½'_›5~{K8õÚìÝ_Ú{à  +õbYà&iËçW×¼ïýwi¯ñû9XÈÝÿcoÖ¶, šH¢_·_õ»ïùèÇþ€ö+ÐrêµÙ�~쮺ê=™ÀcYÐ8²µ_­XyŵïÿÀ¡¯}Ýøm¬åð×¾~íµÐ}Í0±-Ëø- 2ûÕŠ•Wl¼áCÏ¿ð=ã÷p°–ç_øÞFÿˆ¬,£ß�߆$ówÁM#›ùþ Äð“Ÿþ즑Íy‹æ,¨5©†¸kŸ+¸eë‡�ßÀÀr¶lýpôSIÓ(–u$íS´ÏZG± ‘®biž'OC4šÜMX«Q,wxÏÚuÏ9žþì‘£W¯û½øyûŠ•Ç²P,¨-%*ÖÕW¯}ù•SòõçwîJ¼�ß²m{šb¿þÍâcßx(V]ƒb ƒbô‰ó«Ä±î(–ÁT¡XgÚ¼ù¡3¥¯†4'‰Šµ<áï‘–…b@ݨ�bM�mÚ46UÑÊjŸb©.td—çy»Ž¼—”î,vdÆEbƒbô)E±.4Ñò<¯5¡½éö“Ò�P,ôŠuæ¡Í^q¤(VgÁžWà²I#ƒbô)S±¦Æ6yÅYŠå�N±Žìò%ÚüÐC²A«gH}Iê»S`rT1ÿZ‰ аjõ•±ÝckEÅšhI¿êÚјlÐꨗH·@ß�“õÅ‹òdûØ à d«µIè½ÙkI ®£h¬0!ÅÚ¼YíìÊRÿÏ#»äK¡Iò¿ýéGví:UÌ·‹Ä%•bEXVºïæïœ‰”©X›6©ýƒ]±éÿ9Ñ’/kêü·?}¢Õšˆ+6(”#1“´¦N7eÿEÏúüËl’by¢ÑÊïHƒwÕì:2hõò|³è‹)kA±HlP,€rË-M!Ÿñ79y²�©ç?žom±À¢‚í]]¥R§«/ÂËÔV5‰v,Ö ]* X5òMé‹VB1‹$Å(¿£ðÜ ]JëE2¾)}ÑŠ*^”Ú (V¬Z¶Wéñ�Âþx÷�Dù¾cØïÜ¥ŽÜ:Q,êOBBA±*P¬A'\H¢|íG}ÿiù<)²˜F±㪢+¼ê&uú…jó®]A;’­wƒAV¢ýJù¦ ¾Xð�„'B‡ƒb$=×]ûh÷à× —¯X•ðÐ1ªÕò5éûõ&ZÊ´Èbº19goE‘ŠZfc‹;«X«Ò}©0î¾dú¶ �†‹T‹X Ū{P,baP,«îA±ˆ…A±ò+–âWËW¬ºyËVí•”‹X˜(źyËVqÇ�xÞg°,¨?(V½ƒb ƒb XuŠE, Š€bÕ=; ±2ÚËÅgX“¤XáçŽ:ŠbBR& XÃ�xDzÀfP,BHuA±ÀP,BHuA±ÀP,BHuA±À Ö$)Vª€F±²Æô0d31}ÔÍÄôQ7“˜¢Q¬ˆïé~ Ë;A±ÌÄÁÇ,¸¬Xï: Å2ª]w¹Å7@±Ì„j×�p®A±À P,3¡Úu'œë@P,p€5Ã(VÀ¯–/ϨXSc›6�Me˜!Kô ŸÛäy­‰l‹šhy^ñªv�ìòd6?tF�²ëH°LÌ{S€bå¹fÌŸôà¹>óÐfÿ™ví\wkùª4xG± ¶T¬XÝÊNV\iªËܦ›±³ú¬U­ÈD«pÉÒ)–¯ê”w*äî«4SlŽZíúÎNú³œýz°á¤Ïõ‘]ýsudWW²š}®ÃA±ÀªU¬NýØjÉ:²jŦÊÌ_QG%I±”?Ï<´ÙWÇL±:&ËŠ“ÝQ(N[ÃÏu8(8@¥Š%ªÇA�×3.Ñ÷1˜æ &øþü! +w7ÖêMêU…J¡`Õ*W¬¬·5Ñ›¡3{Ôteãû«( u#¦£°[ªÆ%^§™bu’kpúúÞA$�ôÐy±ã¤G*VXŸšx®ÃA±ÀR)VʱîIŠÕ¯¯ÔZÏó×`J³ÁD«ûBÛj1Ñê”R‡Øô–Ù@3¨vý3jªK9ÞFÌ5]]i‰Š%#:�^íLx GƒÓ׿äAïŸ?ýI÷—97ˆ%'=â\÷z ¯Óá„kù°Š…e€mT¨XƒÚ®_‡©b¯N�hùZÂe”9ð–vŠvýj›‰ú"jzćŒã�GšV¬ðõ žqÙÎ>é�2çÎ|ÎôI×�kéWÍïŨN±5a¯0¨X"Šhùº�üƒ¸*V,¥±¤�D�î�fnöè´Š0œø“Š%']÷�BŸ$5û\‡ƒb€T§X¾‘ò�F‘&Ñ÷× + …—ê(¬*ß8¯Ø±X™kÛÒÇb)_äW¾nÖØ/òëÆbi; +£š¥4sibÇIœkåT«Cï{®ÃA±Àý*ƒb-‹U,SC·æ›MŸh&ô'‰qò½·Ä·µmVýBê7}+�ÊWÛ*­l¥�Åjl†îÑ;ÿ;Nºãç:œ›·l]V¬8ËB± vT§X6ĆG$ÉPíVN:ç: À-Å:çûbêTôt÷æÇÐè˜?éœë@P,p×Ë¢PíºÎu (8Še,T»î„sŠPˆbõ¾Nˆbe +Õ®;á\ÒS¬ xG± v XÆBµëN8×� Xà(–±ìt2¦�º™˜>êfs@P,p‹RuP,p€d¿ŠR¬ð£ÝQ,BHšh+ßÞQ,°‹RuP,p‹RuP,p«øÌÍ͵ÛíiBÜN»Ýž››;§ ŠïWZÅŠëŽb‰´Ûíùùùwq;óóóív[ûŠ¥XVàé£ZÅJ´,ã·S«øLOO›®Ü±"ÓÓÓÚÏŠ€b‹ Å*>(!"(8LmkjlÓ¦±©ŠV–-(!"(8LίfW¬©±Mž—OŠ´6•~bå±Q±fÆGFÆgLoq-©kUŒb%~©Ë+©J±:òÓj(@5Q,ŸØ¤ñœa\(fÞÀ[3ã#žç�NÊ “£ž' +ˆ·ºAÊÈ�A±Àa*R,á>­~;–êBý×Ýv®n6�Mu'޵<ÏkM +O´úµkLèþ9qÎ·ÕæÄìSáòêý¶Î”a-m(Å&™kdtTNêü9Òýkrt V“£Šƒ¢fqqqvv6<}vvvqqQþ‰b€ÃT£X}I’ŽV¬ŽÛôÄg¢ÕÕ*U„:…•};’3«_~ |GØü«¨J±-E]‰éNíþÙ+£´%‰B‘³¨“­OÁ¶(�b�Oö§MŽz£ãã}Å«HröìÙsüøquâñãÇ÷ìÙsáÂ9ÅgÉ>Ö=îÑîźY§X¾f¨~‹U°K´PõJëHªûèÚÁ+qÊPb5ˆO±<zÓó˜Ž�N +9ê™MÀ…z­J±³È–'m+–�&�bõ„J¼î˜H!19þ¼jY¯Ο?¯–‰T¬›õŠ•ïï(XH5Š¥vÇõzä"õ¦/Z(Ö Û²LÅ +‹�j;B˜S|ï†Ú bf S¼N¯X=¡êµ’ÔÑ"I‘–¥õ+ \¦Åòuð ±Q:ýz]sSc­žãtug"lP¡ŽB­b †e—¯k7Û¤®³¢ŽÂ´ŠÕk¯zGãNIŠ%ÝL»Ò`ÉAÏ£¿ŒNC’aYZ¿B±ÀeªQ,QOldÓVhú`({d3—Ò&†»‡Û ÄRúc¯”åk8Xg•ÃÝu½~!_R«×¨”8‹Ö—z¶¥X�)3ã#r¥<ç�¤Ë|7Ú·P,p–œŠáWË–¯Ô�Ų?-¥�lØäîî÷¥ÉÑ�ü³GÍòŽìߟ‘ó÷¾8˜R±‚ý‹ÅVÅĹÄ*ÖÊžb¥ñž¨X}Ë2S8®XJ#Vq‚eç£G 1 œÅqÅ*)(!"(8 ŠUFP,BDP,p–ìŠ÷ÜQKÅ"D$Q±R>}Å€Ú�b•‘v»õ+BÜÉüü|»ÝÖ~FP,h<(V™››;vìØ „¸�cÇŽÍÍÍi?#(4‹R}P,h<(!¤ú XÐtr}�0òÑî+Q,BHšÄ(Ör šŠE1 šŠÕ¨ÌÍ͵Ûíi‘v»5úºÀpÒj šŠÕ¨ð°ˆøÄ}Ôø}À„bmjµ¤št,eS¤¨Q¬ô³ÔA±FFÆgä3ãÝ?gÆGT§è–P¦©s45Áz¿„Sé; ƒ£=:ùŽz´G'»¯ǼwŽš ¦zÅ›èWh-¯5ÖÿcjlS¯Þ�\ƒ¿;ïÞíÖ‰c-åOµ"òÝîšïö§–Ô¶ý"½�ôÍ¢.TqÆ^e^Ex#{SŠ·´$ÅR29Ú­Ý{ÿëMêZ@M³¸¸8;;ž>;;»¸¸(ÿŒU¬ÎYé·³N´#Ï@}+ç¡öÅ€FcD±z-D²i*`)JS•Æa|mM†ã+¯F7oüí*+qJLÅ3\R*–¿éjЋU÷œ?^­úE¥þüyµLRGaϱzÿó½+ ;ÏYèô +jZ±:/z’UÅÊy¨ýA± Ñ˜Q¬ G•ªX�*шb©5³ Š¥ +–Œ0­ú‹–¬úµ•~š±X]¹ê7f ¯Xþ�oïè«÷¢VŠ•çPû“C±ú–¯XXØ€!Å +Ön…ƒ›PG¡®ÖëõÞßU¿Â˜RÉB…ZÅôùGèhÊ+U³ùŽB­`‰4¤ÓPTýÚJ?Õp÷nãç઒ïªÝÄy: +û +V÷åèxÍ+ó¡öÅ€Fc‰b…‡»Ÿ“#Σ†»ûϨ#ÏÃmP¡ÁðÉ­^Ê\ƒ1ùþUËÍ“e5 _†ÏW7Ü}Ôÿe5aOAÁêT퓃×u«â£2ß�ö­ß(T&ùúš•q}E+V¯±†Ç?áöÅ€FSµbu~ñ=‘I}Bà KÍ褮P³“üèÑ¡ÇÎÅ)Và¡ ê»1í‹õ Š“S±–£X£4b•)X<ô2EËgÁC+–Ë©^±Ä=Íô}Åj`¨ÜÃèT ÅjZ¨ÜƒbU ÅjZ¨ÜƒbU \eM.ÅZ­X+Q,ãi·ÛQ_ï"âëoív›³PAµ¢X+£KûôQ ,Åj`æææŽ;ö‰È±cÇæææ8 $ñP£XÐ\P,Bˆ± XÐ\P,Bˆ± XÐ\P,Bˆ± XÐ\ëŠTŠåÿ:á²e(!$9ÅZæW¬å(4Šuà;íËîxÁ»ý¹0—ÝñÂîo¼\í=žb,(4—ªëŽÇNhåJåÀwJÿB=!Ć XÐ\ªV¬¨ö+[Öw+¿ÓG¤ÿ³‚åþ¦`šL=xã�fý™¼„y‡Y&!EÅ€æ2¼bií£X‰~%Pg™zðFùóÉe�^6&ZC®PÝt±ùy­Å"ML@±–ùkyœbEZ–¼­™¾»€ãX¤X·ÿå+aÅêHÊ@¦l•£ZÙè¬{¸æ«Å"M ŠÍÅÅúæ÷~û_N‡Kߎ4hê¾ÛU…[Ý=Uäë@ùà„ÐÛç”>ÂÀQËT·AÝÎÀæ‹)ƒÂ²Ò×àÕ™¢[~wÆVëF¯¿«J'æ |Íá#ƒbÓA± ¹S¬O?<åWªbEôß)!TA5� iË÷¦L´ú‚£mÅ’6•j™¡6¯@G¡´µp 7²÷§nù½»¥;ØÑ+ß›¡¿sƒ)¡B±ˆA± ¹$+Vøgî;w<ýsG3(Vë/_ùÆ÷¦õ+�bõe¥ï'J"Z®üòã+ßk¡ŠmnŠW¬ømˆYl”íÈײÍJ»üð&i¨=&(±/ÑŠµ*F±âG¼£X`ÆKXÖ?ÿêBد"; +£Ä Q±ô"¡ˆVÅŠÙ†˜‰qŠ¥4®%Έb‘FÅ€æbR±¼ÛŸû¯»õÏp�å}ÃÝ�tþ.¹°`øæÕ”ï�šïÏ©Ùîv•¼Ì!Ë¿ Ë�R,}G¡¢nþîÑÁ‹ ŠÍ¥jÅÊñ\,ÍCbr+ov†‡¦{R�ÃØÅ$Ÿq(‹M^fäwýƒ±&¢K]ÿ®ŽÅÒ+–n¸{‘r›ƒ{�bÓA± ¹T­X¾ÓNT¬Ý��¨üNO1 J¢_¯XçÎ�ÛýØË1¿Qxà¯ùõB\ÉÍ7o½<^±VdV,ð`F±!DÅ€†‚bBLÅ€†‚bBLÅ€†’O±VG+ÖJ‹’>ÉÃÝãðŽb€µ X¶dnn®ÝnOÒÄ´Ûí¹¹¹sº XÐPP,[Òn·çççß!¤‰™ŸŸo·õßF± ¡ X¶dzzÚt5HH‰™žžÖ^ù(4”Tв¬ÎínyŒb-[y9Š•1(ivb«3Ü]±, ŠeKP,Òì Xà(–-A±H³ƒb€cP¬©±MòÇ�7�•óÄSc›2-Z–Ï:cqÉ X3ã##ã3åÖ‡&ÖE #Çp÷ÕZÅZ–N±ü^55Ö*Çgr+–¹økf|¤o¡Ái®b)û­Ûñ¢Ö�4šH‚b-÷+Öò�b)¿½:»baY` +ŠåyÁ©ƒ†­®èt…g¬åy^kB•µ­Éß æŸõWk¢·�V+8©_¾Õ +­BÎ%6INe +33U±F~19::¬«ªX¿¬kf|´œõ¢XEgqqqvv6<}vvvqqQþ‰b€cP¬óÿþ¿eM´úÎÒ“¨®Þ 4&¨XÚò½)­�MõÞ{¯WJõ"ùf°£P;×`Þ@ÃJR¬°WMŽö›wFÇ;’0Þÿ»WtÐÔŸw0¥«3ñsE”éLñ7,EÎÕ]j¸)*¾ü`uê3¯*Kòu |pBèm2töìÙsüøquâñãÇ÷ìÙsáÂ9ÅÇ0£X²zÍLêØ,/ºåÊ/`¾ò]#’t.jl•°%_Ÿ`ß–åãç*§WQU¬žN ¤#þ¿úöĤ3‡˜Ò/:9ªºÖÈøŒ~®¤2JÓRÿeì\Ê–ôµ'¾¼²Sé‰�W£XÚòr‡úˆ]�óçÏ«–%üêüùój Øb Ë +úLØa´Š¥7E´j®X½Ó� ZAX-SD �ODum>)ËäXrúµhvª?CÊ-Œ_×à êŽ).Ò²´~…b€{˜T,aYj¯Ü¹°Ã(�€ý~9Mùþ¨ùþœƒ¹t]~rá¾.?ÕÍbçò +¥£PI·Y&ŸbD"~®¢–¬v÷¥Y‹oO•©é·0¾ü`áJ?&ŠUN„eiý*Ó7 +—ù¿Q˜O±øR!˜Æ°bõÆežãào&’oêÆ¢{Rºõí)r¸»¯“ñœ¯|ìp÷ÊkD6ºô| ÔQ¨é wú;ãbçŠ,£LIµdÕ”Ò¬Å?9¨g‰[¨Ž)‹(?êßšÀ±$Åf¾í[(8†yÅ +�~/9<ŸAU±4�.PºÀÄp÷èaÞááîýN·¸¹"Êh£3—o`~x¸»®¼ÍÚbç•ov†äk×¥l�ÚÒÆp÷êƒb€I^ýrå+µB±*µ¬:(VC2©ûf$q5(˜¤jÅÊ÷h÷ÀÓÝWezº{”bUÝ–e_£XJ#‚E)çéî<àÒá¤byþ”ï2–¦1ŠEˆ6(˜Ä%ÅR_”ï/5ŠEš LâŒb ­Â²Ô´Ûí¨¯bR÷ÌÏÏ·Ûmí•�b@ÔR±V+~•í7 +Q,5sssÇŽ{��&æØ±csssÚ+_?Ü]ÿèQ òâ†bþIJq9(T�ŠŠEˆãA±  +ÜS,,‹ǃb@ X„Ç‚b@X©X!¿*X±cà !N%·b%>à]ÞâÌßÛÀ8®*!ÄÙ XP(Ñeú�·¶>sÙWNzÚÕóÉ¿š�~ã­¢öåìÙ³§OŸžžž>QÛÌÌÌœ={¶¨BP,¨‹„2ýÆ[—}åä½ß}ó­ùKïTž·æ/ýÅ÷uÙ½' ±¬³gÏNOOÿ⿸tÉÀ¾’K—.½ùæ›ÓÓÓXVQA±  +¬T¬�euïu+üеÅ*+Ÿ|lvüûgßyç�ßú­ß2õß?;ú¯[Ÿ~_fff~ùË_š¶¤277wúôé"N/‰P¬ZÅÒŽxG± ( Å;Ð~kþ’°Syk~é²{O¿/'NœXZZ2¸#Eeii)ê÷HÖ XP( Å;Ð6«Âî¼ú˜Ë”'N˜Ý—sâĉ"N/A± P,ŠP,³­X(V8(VQA±  +L(V¬_¥Q¬U w/5޶bÍŒ�ŒŒÏÄOÉ”!gÅ**©†»ëF¼'>z”§�À‹„’£kf|Äë§§ª`LŽzž7:™Í(ÊW¬îVË�D±œ ŠU€b‘P²¶buLeà�êü%ÃÿvšTÔŠÕÙÂÑQ©A(–3A±  +P,JÆV¬ÉÑ€A µè FèÝÔ)[±Ä¶¯g\JSœ~Êø¸l“4Þù캗…½A#^`–]™ˆ XEÅ€*@±H(ÙZ±4m5“£ÞèdgúÈHöþÁªZ±úÛ-Kimë½ÔO‘{ÔÝMßÂ:oöW-Ü[KhM™È XEÅ€*¨Z±®Ì¯X<ݽªdkÅŠQ,O4Ðä�¬wJW¬Áf÷ÍFÝáJÉSÔøß}'´À¾PEÎ’Ô±ˆb•,OwG± /( %ãX¬øŽÂ@ËNªTЊ�ßà±ôŠ?vK«X1³ XUÅ€*@±H(Y¿Q˜0Ü=Çx÷nÊT,¿÷ IT §÷vì±§~y uõ)4 Še"(TŠEBÉñ\,µQh0®;ì]éRz+VPfºŽ5zðDøQávªèYÄp÷ >fA±LÅ€*¨‡b]¡Q¬�e¡X‡§»Û«¨ôkù@±–G>Ý=ühw Ò�b‘P}º»õA±Š +ŠUP_Å¢£°´\ö•“oÍ_2ÛŠõÖüR!Š5==½´´dpGŠÊÒÒŠUTü…«P,(ŠueαXñ?ݵ,«�l9|æÏ޾)[“Œü÷/Žýê“5;ü¾œ>}znnδ�7ß|sff¦ˆÓK2µb1 òb¥bi›°¢; +{–uù²•7þþM¯¿^@½ìx¦ß8{ÙWNþÅ÷õÖü¥ê]â­ùKvô_/ûÊÉé7ο/gÏž�žž~óÍ7ëÛ–µ´´4777==}öl„¼þúì�¿SÄX÷U¡çŽæS,Ó7v°�)Ö²e+7\¿ñùç�š¾…7!ÓoœýäáÞ¾çÝõbÅ\ö¥¿Ý2þO…ø•ÈÙ³güã÷»ß=ZÏüÍßüÍñãÇñ«¢òÜsÏo¸~c>Åê[Š)¨‡bÅw(Ö5×\{èÐaÓ·pBˆ½9tèð5×\¯XQc±Ò)–é»:X‚•ŠÙ�•¤XW¬¹ê#ùØ«'Oš¾‹BlÌ«¯¾ú‘�|ìŠ5W¥nÅÊ1ÜÝô],¡®Š¥ûRaײ޻þ}_¼ûnÓ7rBˆ�ùâÝw¿wýû–%ŽuG±`xjõІhÅò=ºáúëoøâÝwÓ–E‘yõÕW¿x÷Ý×_CôsÝQ,(”z)Vâp¬î÷ +/_¶ò½ï½æÃùèÁC‡ž{î9¾cHˆ³yýõÙçŸþà¡CþÈGßûÞkü~•8 Å€!°Q±†úRáå=V\±æªõ×\»aÃÆo¼ióÍ[6oNÉÍå1b#Ð8Œ_T +}jÒruܼåÆoÚ°aãúk®½bÍU—/[!îAÅZ‘I±n_æïêÖãß5d�zPÅJ7âÝoY=._ñ;–Ïïde™–ßn¿]—› ˆ-7~ +ª"ꪎü”ñIŒ¤óñÜ +„_E*VB/!ŠP 1Õ¿2¤Xiú +Ó*VlC–T¬ËmQ,çÕË*œ·£LdV) ËïWzÅJ? Å(–(•B±† (ÅÊÒ�µ¬´†¬Ê•ÌxU �§˜8ÿ¸¥ð«Â‹çŽd"lSÍñ+sŠ•dY©¿TØU¬å)K´eILßüQ/¨Ž¦(S2��¹F±–'4a ýuB ¡j”_Õ^±²5dù+ +óÕD±êÝ¿Cïd])¬Ï®Æ6¥ÿü&øUŠ&¬a‹€È�Ôª¦ù•ÝŠeY©k`Y+ô\®§êU¢�eó4ã²ÑÊU¦f«T¤VùkY\–_±âü +Å(!W(VA ¥Xé²,«õ2^Y«dÅ4©BqmD&,¨iʔݚ²©TZ¿ÊÛ„…b”BýªIе"¦!+‹ee½Õë}Ìx-VÆ¥¢1?•UQ¦Jéý*[ÖŠ˜�îib¡Xy@±Š£ÅŠí.ÌØ–UŽ�Õ¸ #™ÿmRÆ'4¯¢+黄(@Y XÅ‘ê¹ ©Ýþj¡¶»°Ë*W½ð10B† Ò•Šõ+í(÷,½„(@Ù XÅ‘fÄ{ìÓ±´ƒÞ£²˪\·ŠV²Œ>†’9E¶k£�nqóŸ�VIB~7 ++æwsR?tÅÈIckêŸþaÀù?êŸUmCZÅÊÜ�•Ͳ´¯#rúXvõBÉêKÉ*eü"ϨRZRøMX¶Ð$Åü©´bU¨X)û +Ó?æ=­eIÒé–•>VTãC¹Mgø[‡«ô3kÞ”²YSZ­Š÷«ŒÝi¨«P†Q¬ô Y‘–U�bÙ¤^uV8C~¨·#ã\752 R©+äWùš°P,HO½+ˈ,ŸeU'@ø¼± df0.3 ±šR©J™Ò ÿ¼'´_¥……bØHûÞ/WÉÛµ+Ìñ]ÿKåŠ'?5øó¿«ŸžšÜõµ0ÿ0à +þ~g�¿ÛyøïvþÑÎC?Úy臟üÁ|é�ýþ?rì¿ þÛVÏ;çyÿæyoyÞYÏû•çýÒóþÕó~áysž÷sÏû¿ž÷/ž÷†çýÔóþÙó~ây³ž÷ºçÍxÞkžwÚóNyÞ«ž×ö¼W¦#8‘…Š`*‚g与ÌÈ?ÁßÄß9CQGLKÔiÊzmh/°(²^½QŸ‚¨O�ö#örQŸ_õ3Þî~ðOuo¯uo¯wo?éÞ(~Ú½iüK÷òóîÍäÝË/»7™³Ýοuo>ç<ïמwÞó~ãyÿÞeÞóº,zÞÅ>K].uy[á…ÿñ.´S�×à«V_A¦ËÖªÎ,ÇwÉw­lÅŠiÈJê.ŒzŒC>rüƒº¬¦0ã­Ðxìi€mÿ`Ö.ÂôMX´béIT¦˜Ê ×#¤Wý(ÅZÕï( ¹öäÉj¯ä!û +³*ÖЖ5¼b•ö�…B² +¶,Ô @GÙŸ‚!TÊœ_9®XUTRÕn ˜¢JÅ*öj)D±Êذâ²â-+Ôi8œnUå]ø”�©kxh› +¢# Þ ýŠ^Âêë‚¢…hÕ—Ê«ð+¤@Å*z Ó+VbCÖài-+5V2TÍŒ_Ty•©•JíW±ß"ÌÛ„å–bUZI™^TCŠU’�®X…nj� Y1_0,²†§�ž†¿9oAeÙQñ~•ø¬_$t°—Ð@%eÓvBy”­Xå]e(VŽmîü|„üM‰K}Ä�Nˆ Xì"~˜âB—ù.ÿÞýåŠßtÂâ×]Ô_Ô‘?ªófõ§u~îy?óÿÀŽäŸ#øIf3òzg²0S¯•Éiˆ ÔÞõÈtáE]½Qdýth?bQŸÓ(ÔÏøý_ÈùYÿn $GÜ+ÔŸÊ¿–óÿü¿–ó›þ¯åÌ÷ïH ýÛ”ú›9KÊ -åÏæXóû95¨¤ì[,”A©ŠeìJN±ŠØò5» SÁ0®Ó°(êÚf +ãí6 i jNCSž–¨¬¬Ž¿JlÂJ{/rª «¦ºRÓÍv�òËä50´b­Z}åaYÅ)VÅ–e½’¹¤p®`ü"©ÊŽªô«Lýƒ®)V­E¥Öï%)–á³_„b mY…7dù-+òk†öc¼–�ÿ8äò«•™üŠ&, P”ìBã)C±ÌŸ÷‚k8ËÊ¡XîXVzŒWÁ`-Æ/ΊX 4¿rG±ÌWR술XñTÞ�•í;†²Ó0ãuDÝ0.ÍÆøùµ”4Ÿå,ƒ¯rûUÃË| Åî8CáŠeÅé.N± +±¬|Š•dYºF­(RÞ½ñ1€BÉôÑKûqŽ•«Ü~åH–5;å Å*–-'ºPÅ2Ø]X¤e¥'c½`¼¨Œ¬ŸŽâ?žI7„¡ýªÉŠeK Å®9C�ŠeÑ).Z±¬·¬Ê5¬B…Ãë§� ¦Û©ZŸ²øMXA,ª¡ØAg(J±ì:¹%(Öð–•õŽW´eÕÓÇLø[Q—óVÓ4ÊAuŸÜ"üª±ŠeW Ån:C!ŠeÝiµR±jeYÎ(™=`5õÀøÇ ¿Êƒu•»é(V&*oȪ‹eái`?Æ/ò²Ư\P,ëj(vÖ†W,O¨­Š•ײÜ­ò0^¿C"Æ/’ú1¤\¹àW–VR쬠XYÁ²Àð«4ØXC±ËÎ0¤bYz*›©Xˆ\’«œ~…b5wÙZP¬¬˜xÞ{¤e!ZNQ”\áW ÆÍ½¶“aËÞóX¦bÙaYAÑŠÇx½‰dúPyqÁ¯¬®¤Øq7@±r0œbhYÙDkHŒW@ÖRå'qøû†#~eu%ÅŽ»AnŲú –¬X–Y–ãBÕ ÿ8TãTø•ƒ8¾û–€båchÅ*ϲš¦d…`¼*‡DŒ_$å`öî®_Ù^I±ûn�O±*>wéW×+Y¾b5Ȳð7€0Æ?>Ń_U¶êè�+/E(Ö•ÊMÏü¸V¯‚¡2Œ_lMÀ)¿2eR¨~eJ´P,ãÔE±Ò¬qP¬NŠ…e@‰¨w˜*ïÛf©Þ.¢lJþij“À (VnŠS,, JÁM¿2å3Q+•öÕøƒÁS€bå¥PÅ ZP ~¹r˯,¬¤ŒŒËB±Œƒb –â²\ÙÖ„åÚ¡ßñ¯‰b%®ÔW¦ÆŠueàßžÆïÕP#o¼ XøŽM+M3lSK€hYÁÞ}û·m»50ñOî¸sï¾ýk×­ß¶íÖ½ûö¸idK` Z>xÝõ+W­ùàu×ËׂµëÖßvÛQæSŸþ¬º(íêöîÛÛm;b¶6†µëÖïÝ·?MI±�1{*¶M-Þ’ÛnÛ!75ÓºÔãsÓÈ–ðDÁ§>ýÙ½ûöÿÉw®]·>ý[�¹’ XøŽvÅ2uõZ¨X%Šà=Óø=ÜA.\¸��‡~ôÂ… BöîÛ/ +HÄ»?ü¨º„'Ÿ|*J±¶m»õÂ… ÒFn»mÇ… ¾ñÍo‰2¯ž<ùêÉ“Òd« (Vxkã[›¦¤ØÎ‡~T®ôÏÿü~uO÷îÛ¿°°Ð+¼ýã Ý|æÉ'Ÿzòɧ×õ©OvaaAÝÁëú6uÛm;î»ï�‡~taaA¶‡~ôä©S{÷íòɧTý‹y« WÕÞ™#×h¡ÏX¸INQ/ÅJü¾F³K‚kCÔõòÏ@Í®z…D‚¬ÇK ldÛö�‹6¥………;vߥxòɧNž:³º˜­�aíºõb_â¨ÝÎÀD±§ZÅRU3½b  +O¿nÃÆÅÅEyðïØ}×â⢰¸ÛnÛ±¸¸x݆�â­o~ëñ§žzZ¼Žy«î„ï ß™­ÅìC±¬ÂÂMr +kÈ «ð8 ZX\\Ü·ÿ€xýÈ#Õ*~åª5ûöX\\ŒŸK}fÛö�/.. +uQ_«äìQ«Ó®7†ë6l}êôiY8¥b]¼xñŽÝwݱû®}û|ú3(§?òÈÁ§Ÿ~F-ùÒK?k?ýÚkꎯ]·þâÅ‹bkcÞ²�øOw•ÞŠk� ?�cü Xr@ ^еöà»MV,I¾r~ŒW@F¸xñâ¾ý>÷¹ÛÅ‹À»ûö¸xñb`â»ïºxñâÈæ­r O?ý̾ýˆw·mÿ¸Zã?òÈÁ‹Ý|ëñ'îØ}—\ˆººð¢äìÚ�ŒA»ýZÛ)‡El¤º(YX¼�›ôôÓÏ)Ìu6Š#pÿýcûö8ýÚk/½ôáœáÙå”ðŽË)1oå úÏr•ãFa›hÙ³%R#ÅŠêìVåÊ%Å’¿Õ JÅzé¥\¼xñôk¯]¼x1оváHj žI±„·|ëñ'.öóôÓÏHÑ2®X�÷¹ÛG6o]ZZ +TñûÜ#êëýî¹ÿþ±¥¥¥×ff¤È%ÄTèÛoýÄÒÒÒö[?¡}K.S]]üÖf’‡Ä¶óÑG‰�ÝàžÝw~Ạµ‹RwJ8’8naGJÃý÷�‰#POÅ2þqvŽ47íÊî۬Ξ�ÍÙùÏÜ{o�x÷æyÐVÂF&)Vðw6ÝjÅjÕÔw™YZZºÿþ1ñúsŸ»=P;EhØ£�J_¡Ç(–ºRQÀ¸bÅlg”b­Z½æÓŸùÃ¥¥¥Ýw~!Ÿbí?pÏ¥K—V­¾òàÁÃÏ<ó¬zÙüð‡?êîï•3gΈ‚µëÖ_ºt©»qoA#±ížl|¼mÄ)¼ã»²Î¾r,0ÍU‰R7 põ¢XP,—.]R+èÇŸø¶ZAËÚ_²ûÎ/f ü`û­Ÿ� ܱãö;n�)^]üÖ&’¸@íf$.*\X·™3gޤ]Q`<üÃþHÛÀþŠ#öøß~ü‰o¶¶ÛÈ÷4 ïÉf›’,< î€b ¿mO”M@ZÖ®[?s挬£µŠòÌ3Ï^ºt©Û]¨YB€°AÉŸùìÍœ9#^×W±®Û°ñR7iK�wdóVéQb!»ïü‚xK×Úuë…�ª‡îñ'¾-Wó4;ïÉ-ËÎâ P¬°q5ô¹X`€°´ˆJ_´«hE˜€( –ðÌ3ÏÊ!La£8xððjÃãO|[”yü‰oÏœ9#õ@¬.¼(¹…ÚuÅ´Ø„·_Û’6¼b­Z}å�wýéÛo¿ý쳓‰ÇüàÁÃo¿ýö<øÀ¾ýöÛV6¯%Þevìhæ:pÏ—Ÿ}vòí·ßVM5æ-h$Þ™M)–…‡Â)ê¨Xú!îê¶¡XPîùrØ+>óÙ?:pÏ—G6oÝ~ë'Ü£¹ØDá6îù²±Øë6l”%×mظcGK”ùÌgÿH]¬X�¹µab+¼ý;v´ToQ·*ý¢¢ +ßyןjfdóVõ(iß +/_ö;ïúÓu¿wMú· yØyg6bYv +w¨�b…Ÿ‚…b€ÄÎ;3Šå ùŒ(æ¬U¬X�-A±,G´qEÁ@t;ïÌ(–ƒÄQÌ#³‚b£”D± † ×ߣX®¿ÁøBݱóÎŒb9H¼bEY–YÅÒübNĆ• W/€mØygF±$ÞˆÒ(V L•Šõ¤÷jàÒ°“êÿ¹�hPÕ+•”qê«XÚëÅSíEÚõšú!*)ã$QÀ ÄŸ(W/€µ|•ö'y(–›ÔT±bþ±PÙ¡ãê°ƒ�R�9ìÎAI&Åêù•bYážD ÌböþhÂró @]ËB¸tlÆñ»´ã»o iŒHz”ªX=QG±À>¿K;¾û–�^±¢š³r,°îpéØ�³÷jgwÜ6†T¬ðyD±Àœ½W;»ã¶�be…K .8xÇvp—­%¥~L'<î=ëë W/@]pðŽíà.[KzÅŠšâ”bqéÔ §îÛNí¬ý ¯X�sj¡b½{ï½CÐî)Ø�S÷m§vÖ~ +1"Ë+^¢ð+€fãÈÝۑݬE‘<³v*V”J¥÷+®^€šâÈÝۑݬ‘8¹Ö*VX¨ð+Ghü=¼ñ;XGŠ5¢w=¯‘ŠÅ¥ Pw|'oð®Õ§KÕ*š°\£‘7óFîT3(܈,W,!Wø€›4ì–Þ°Ýi�'Šv•£0Œ&Õ.gQ,®^€†Ñ¤{“öRbíIÏÔQhí^@nsooÌŽ@V,<õ™†»[¸ýP ¸Ã7` 7ž} µ¾É×z㡬º2=zÔª-€2¨é­¾¦› …SÞ•�iÉ™~@'Ó’½w=°‡:VRÆ 5E\õe,6mÉÔ?]Ò¦€µ¯¤Ìn'4€2.6ËuÁò:… +â)ÖÀ‹]W/€ãØYIQCAzŠºZŠZ—.H쩤¨¡ …\{Æ—�ÄxC Ã0¤Ÿ9/W/Ä`ª’¢†‚¢È}-åž‹KRRe%E e Ÿh’i–R— (µ’¢†‚jP —X²¨E¤!}µ’¾’2¾Sà ñ—_Ìt.Z(•ĺ†J +j�öGÌÿH@4Ú©Æ«TÈÊÿù(V +endstream +endobj +88 0 obj +<> stream +xœåZY«ÝT~ϯȳÐ}׸¸`…ê}¶Ö¢Ø–ÖöÿKö�ìäd:µ +járÎI²×ð­y¥†8Ä-´Ð>1ÕO/h†àÛ—oš÷ ¢KÚ¢Ó–HÁ€xß2¡56j?¼j~øª}Û¼oÉ$M$•ã/té*r¾ýòMñ™ïžµéˇ×ÍÝ3n_ÿÑÜ]~}ýéëöþþîùñëS íÓ§‡Ó±¹ûÑ»öô®yѼo¸g’d Ÿ 9€UòççÇæîÛwo¿ÿøáÓË�=Ì\�ÍÝÅC‹Ò>þÒ`V¤%hEÛÇ7Í= €hþ;È@€zEyÀ0�TŸ¶�¿5žŒpè¨>þÜÞˆOÔÆP�gF?q@èt‹ì$]SJ¬:6 +™’ËlØÐ1Ÿ-œ²xRTð‘óùq ª�QšF)ÃYBŸ¤°…£K×2Öêàt#5»ñ°�CþíÆéàŽé~¦V­cb¯�G Æ;„ 3Ð w߉6á™Å#<¨8…NÔšŠŒYd—¬ªœþŠ`rΟžs¦#‰¾„ +®šÞ9óžQ6z�ì3:¯ùü¢×Ì?ßëã'r̘­ðÖ)ÏCöl?~ÉË»?輺Ð.ÑPщrH¾ÖÉŸññ8ÈŸ]cÙв�lw-Yú@ÎÎc¯QÙëýg¦€‡Nv¬è~†e1ºd¨�À%NÌÆvù›Fœ7`Ñuÿg3qMo<šqÿæ“#ãăŒD‰ Îªjÿ¾¨€Ü€Â®{ˆxgtF�”ذs�‚û gˆzmÙ²ñÈâÜm6v«6Ö †°'´×Ú¬Û +N1ú²UºlÕqYÚ‘xÖ3�’Aï´æñÿ)PˆëeƒIÉkç¿[¢�6<ƒ™8Ê¿¢Báznɱ“ØU¢PÆ„ ¯×–AµJ ¹‚t&µe(¼ é,º„VnrÞ1}á´Û²†»Ô +þZªà{©Ò¸i<‰ˆ³=²Yy6*>( q…²p"û—ñ‚]±/7øoÃlyHêó ²Ö¤²ÇXÄ‚Hì]˜3yïhp…<¼!Pð;îdD½Q Öú�Kö¨[äZ$•¿UóÌÖÚ¤Ÿw¤šyÊ|Ü…v½#€…¹g-̪(9O�‡�N¥9úà¸ìfëSDífZR"Ú½n&;ܬ'Ë¥š$²Ô]ëêÉ«dUé#‡¬No²KÒÕ^{¤îúî¶V×…¢®Û«îFq�êöd)¿›b¼)G̰Ý,g +دÏêù³¬†ªÐ�*9—äÞ¿£¸TUn©Ä—ÕS�ï#=U.Z«œŸ†Ã¥¢¬äÉíFtñÂóœí?iSbÈU­Œ=-Ëh5qØÁ¸r£q¸Eëí(jQÆÃp­È„çÍU™Bß”uµ;yy¦XÐtƒï”2;•4"Q’ˆVKÊ"¹-óìò²µ§9]&ŽÖyuxO#y¢ÏŽvbØa¼ˆoÃ; H<Ò–l÷9¼“Ÿ¾+ï¾m½ �–°m‚�IÙ�Ê¢¡4wš›‹œ™sJÄ!/ì**±nsþ É¡b»’÷\ñ3¬Reo Äÿ¢€Ðïfüú‘€œG®ÏÄÕÕÉná¬7:%j~QäÚ2%@ùì +endstream +endobj +90 0 obj +<> stream +xœíÝOŽÇžpŽñFšH,AxgK^‚ØÂ0Ò¬Z¬Aì�³lqä 7€34zËÙÒWéÑóÏ +Ç‹ˆŒŒÌªêÊêú„>²ìvVUfDþùVdDÖ?þã?ÿ´üßÿ¾ßˆ£WÀ©¸wï&ÜÜÜ}e8!)I +“,%L°Â½{7E˜<ú*׿Âô½{y�}•¶¦H�º%“¨é c*LÊNÂ$À,=“S„I€YyX2û&'LÌ&§“³$Éñ*:úšl�09%U‚0 0eê6÷ÑWl;Ô À”f·ä9§›}”£oÀq�m·d§’agŽ0 0Õ3yôµºÍnÆN'd&õLa²ç:ÅÈüî¿0 ÎsÀ䊞ɔ*SE “çÙ-9&GªH˜HÎsö�ÙÜ»[Ú-y—”0 °£¥Ý’w)A &Ãúé@ns=“E˜ì÷CÖO:úV‘0¹¨¤0ÙïÌ8ÂdÑ39µdñ ÝÂ$ÀЇÝ¥UßÝî,Yÿ¨â]ª +€E¦œ8û»” úw´§*m°3à®ê<‚{°}­ØÆ¼g²˜†pnš�ï–<‡09•'có…Ià åAhÝOÞ“çöóå!åÀÕ£%Ï-Læy2ï¼u§8C»'É3“©¢tNçf/Ý’g&‹»Û:'€ó´—$yža2¶º\š&¿ûiEàÎëtK.Í?ÂdsZ÷yV pÆopO=R²Y޾]·_�õ�îüf÷ÙÖ p·�ßà^4¡ûèÛuûÕ˜ßæ.¢õßw½ÿ\êèk °‹º%½çÑ7í(•Yü*wY½Yí}mv4ž$…ÉÁ /~tòïiÝU}mvÔI’«»%Ï9LÖ?_þ×Èɉ:>ú +ì¢ß-)L.Õ|Vy>TR˜î’¿RÍÄ/q¯žš-LFzü·�:'€»%…™:+ƒyr0IÊ w@¿}‹V‰”uÿ6°»Earê%Ë>q¢Ìx‹Ûšý9¢Â]ÒO’õ�ë~¤ìì67Š¢(Š¢¬-‘ ‹¿¤æ©_¸ìƒ¦³_'L9¡-$É»ª“$›ûÉÍÍÍx’Œ²öèQEQe}˜l¾¶÷A­Ù“)Ä¿tR�$y·Íî*ͯ¤¢(Š¢ÜBÙ%LN½C{±�RÇÈÙT0õ\k09u×»ÞU„IEQEÙWÙ=LN½O¹ÀXI1 3þ-_R’<Ñô#sµòWÍ�&EQe—²¯09»d¿w(¿O=;3·~ gb$INõoë™TEQ”C”ý†ÉNe§+²Xlð1AbäÙZ)ó¸ÿ"L*Š¢(ÊË�z&o[õCæ½FE§eÑ¿$LR[ú¥#ÿ—b·Lû!�¹D®xÎdç­š?�ó÷fWíüÎãT˜ì†£×-1›$›ßbН3ÿZ\˜€ÊÈ%r_a2–¹¹×xžù_ÿ+K¶ÍY”©ÎÉ£×*[3&§²¥žIhÚ`Ïdú—ÎÅ}ªsòèõÉ– vK6Ëà(EQEQêr”1“#z÷µYa¶O2€0©(Š¢(»—cÍæn^Ó›yòèù„“3r�;ßw;†EQå¬Ë-?grQ9z&áÔ îi;@Š¢(Šrîek¿€#F²w¤¢(Š¢®lê·¹ÅHG˜TEQ”C”]Âä`Œüka1’-&EQe/eu˜\4+§9€S·â9“õK8O‹Â¤ @n0LŠ‘Ôša²üD1NÖý/.^üøÇׯ߾~ýöéó—7oß=zü¤^òòòC,3¥ùþOŸ=ÿúõÛÏ¿üzô-]çé³çQ9Ÿ>¹¸x=»üÅÅë¯_¿õ—üù—_¿~ývyùáÖùÍÛw÷<oÇbÍ—nþ¦Üð06êÅËW뫳ck…[k…Eâàš­ÒÁZ}ôøIj©ºÓ¾yû.–¹¼üÐ{•|rç¶é·÷¿ßL”:ê|ýúmjá(õûßððêêûÍÍMsÞ¾�ÿ(¶ñêê{ÿÐŽ*ýíýï�ež>{~ss³:¥,]ç××ùٲߎùš¯ØüMyóö]Zíu�5µck…Ûl…E..^ÏVé`­6ߪ?ÿòk½Ìö/Ð{¬ó|ONoجºÙjI׋ñ½=ÕçsÿÁÃ××Åöæq —§æÎ“_‚?}þÒÜ´×׋>¨¹CWó/_Es¼xùêêêûáº58ét_ºŸ>{þôÙó襌¿üøG¾|œ4Ò’µâýó3Ã)†É8ââ5Ó<0 #géû>}öü_‡Ó©)šéÅËWÑjypýù—_ë¶KWütÞ^·ù›»ß§Ï_š§ñÃ…I­°ßVXäòòCó4•÷Œ�Ôê£ÇOÒi016¤ˆÄñÇèYŠÞžxÕÆû'÷&£Âc«ãËrÔgT~º¦ô¿EÛ¥w»¸x�ª·¹üà%&}z¾½±b·Ö×ëðæí»âﱑu‹ÿgƒEGúýS4�2�‹òmŒ+~ü{„ÏCo>wXºl5�£æ×½8i wÅ7ÓS “q€çwRµtN‰û½2®[çü’�¾•w®ni™¼™ÖmþvÄÚÆ}œú›Ñ`c­ “Za¿­°Hœ¦ú•3R«qõÏ/å)º¤ÆFñ²~áí=Læ;m38EÌîwN6œÎ1˜w/O]bò+Q½½‹.j»ˆÕ(ºcë>}þR¬FÔØÔà�ñO‰k}~èåwÕc½ùÜa³/Î6Å8xÜ¥cèÅËW1,§H–�_J[�.=÷<Œ·Ýq|`ê¡J×£:`(Lj…ý¶Â"�ûé‹jµþ‹HÜ<ÔïŸö¼-R=䕟WN +˜·EÊy[¯ÈB “Ñë^4t|bÝ5W´]}¸E€¯ŽîåßÞÿÞ¹ÄD[Äua$L®;”F¤Žîzâvs½z+¾3>zü¤è„OÅùÅôãÇ?Ò¾yûné�tHb×mFµ$âM¾[ŽÇÂ8㵫¿úÅ9¤¸øÖ'êtg$/ùé=N#³Cqb=Óá`Ý‘W“N·C|\ºÛ•JþVŘÉÔ%5¾zãâkig|f:Ëå7¸ù±Vé¦a*¤ë?æoþÛûß‹F¹¼üPøYÝÓèÔW€¥a²?­º´Â.­�’Õìì¿XóÈWqݯ³Ö`­6g4S +«Qóu®ˆÃ95e4}q¦Š¼¨ü<GµÔƒ_¼|Õüã¢v©óþ±b÷ëŸáÓ�ï~4Š=$ošØÒ~CtV ª÷Ñã'ƒarÝ¡4(­L±½�?‰¯Zyë{ÚÔ´²Ù9D�?©oåG_Í�ëë««ïÅXnX$NkK;Æca�‚V„Éæˆ‘â�i@H ΉoŽñ—t€¤e~\__\¼Î‡‘ä_“ãÛt:Ò§N>³sg:W$Õô&qJIîÒH¡ÎêÍŠ“O|n>`3¦n~úˆOŸ¿ãÊ:ÒÒ•%vÂ¼Š®®¾_]}/†Ÿ­¸Ÿ—ƒ´žñŸu‡ÕÒ0yÓ-õûh…½´Bª`ÞFS³oò|2R«�Ã<ÿ¸b÷(Z3�ôò=$o‹h ¢òS,Ì›#o‹Hªu[/jš‘:ïÏ+v¿©3|„–zZS„œX¸ÿÂ<ÆO­@lcÔç¢0¹ôPT_v\_§œ‘޲ø”â’Ñ)õæ_^~H_Uš×ú¸¦,=¨!·.àÅ«®®¾w¾¥î볦FË_îŠÓoˆl–ú]Ó99¿Æg3á.a²îbJÛÒ Å7ÇEѱ–¹þq}=ÕqÑì[cò.îÔ©•'á81¦W¥ÚȯéB™¯I=†pP=@«Ž•63®\MÅ85õ¬žâ¡–¶B?ØÄý»ŽX¬˜Á`Šª8V˜ÌÛ" YÏ«"N\iÅÒΙ·EŠ:õγ¨iFê¼9G,IkÞ9çsx”‘+õ·†ßÞÿÞ<.Ò~Õ\�¢ÿyQ˜\z( гAZ¥xç¢c$mT1Š2®õw½¼ÓûãÇ?Nbˆ5'gêðoÞ×(^Õ,�Ãj—ÎÅä¢ç?NõWò"…ÆAZÄÝÁL¸:LÖ/Ìï5o›yuõýÍÛwûºãÁ&"µÑl‚âúµtó›�;•¥‹SÔa³™Öí<Íl¡¢¸¹9Ûßµâ2­ÖµÂ^Æï5Gë¥Ê¯ÕC„Éú³ŠsW±bÍõL÷a§ViÐAÇL&÷<Œ¶H]|ýOŒ!ÝÓiÎæ®G6¿Œ9|Q˜\z( Jkÿ_(RSé·9¿{‘8ùüü˯q}9Гè8sS‡3.ÿ·ùh NÚ%LÃÝÓ`þøÏ8úš�¢ù˜íæiäÐa²Ô§Âd1DíÇõõìï:öwš 9ç4Ä'ÖŸµ{Œé¼ªcš—Î¥;O={qjtše6õ}Ç0©Æ[á @È`o'Lö+¼-6&sSÝïý}# +�.»^^ôÖÖ+P?‡j÷09Û|ãuGz¬dÑíQ3êª?©a‘úñ°SGVq_£&×Ý_=6#_‡b~ešA0õ¡���=CVŠ6Ÿp’ÜÔžf˜Œ³G=À»ÿË,ÅÂýn^n¦Æ°�oþ6cÌÔ™3¿*u>´³-«'àh…]Za|Δ|Fj5Ín6bê\šê>*&æœh˜Ü㜑%›½âÅÝáæ¸”Øü—°øK¾L~YÿÎm†Éü^vý/=~›\Œ™_7g¼¹a…ÁGëo!LFÄzñòUz`]ú_õý޿𝠓S Ì•ù¨ï\œ(¦Âdòâå«ËËir÷Tÿd=œ©?$¦y¹)zzWlþcLgߎ¾²zÂìá&àh…½´Âøœ)ùs™kµù¶#}ÂS»ÍlËn-LîeÎøŽ4Òc<»äÝ #Çé-‡Ét7­Ù_s..^Ç9!χ+&à,mnX'ŽšNÛFÂdúZZO…›ºoÇ]º�­ “S�ùj>°(W?Ÿ3Æï6òé+~š!¾½Öm:5¸´¿-#›¿ÁÓydtj…b¦ÿx˜™€£öÞ +ãpš¿e\OQ©Õæ#£‹äß|âDýàµÁ4²µ0¹zN³: S³ZòËæn�ž}ß©›sUÒC‡Š‰r·&S‡dlTóÁwivQ{#p¢3yj›ÛÜB:ÁÖ?1óRçXúûQÂdº—T<º-óü‘ŒiàMÿœ5ºxóΣ‹�ËpT€)¢lÑÍ‹ÈHOÂÓgÏ‹ßÓi¾jä|8»ù[‹1ýQ^y‰}é@aR+¬h…©²ôÔQŸšÙ9´ï?xXL‹k6b±þõÇͶE³òo!Lî¥Î›«ôèñ“ÙVh>ì÷ÅËW#ÎÒýs;a²îÍ.6?þïê‡ Ç�oæ¸ôÛì"’1µLón³Ö½ªÐ_±|,ÍÔÿ*ŽÍØÞüëüÄL¼Ãàñ Çö6?ºùéù:4·bé/àt*¤¿‹6¿Ù¸õçŸÕüèf]-ÝyúÊê_S 4¾ãi…}µÂøÓ˜G¤Zÿå#‡vz«‘­n~Ül[4+¼-Vì¥{¬óþs&;o8»KžrGöÏ©#½Xùu‡ÒR�:ÜÙÆ?e—_¾¸»ß{²òg+͂Խù`NaàXò±‘'ô$Ã]Æå°/ùã(Oh„Þîãräÿ5ÔÑ +endstream +endobj +91 0 obj +<> stream +xœÝ[ÛŽ7}ﯨç¬!)Š’ÃÀtÏt° àì»ïNbd7ŽaÇþÿ…T’Š¥ºõ,ì…““™®Ö�‡ÔáU1dcþg€†F} Œ&bŒaxóîôá„èŒ�л�È�a°„b$F>þ|úç߆ßONÖ ¹<ÞøWíù]Ä`¼KŽa˜þóãwC÷äãÛÓÝwÁoÿ8Ý�{ÿæ?¯?¿ÿôóðòåÝ÷—¿? 0¼zu~¸œÈ NœDâ ’VñË Ã>ð`ò¸êÓ8&§1k?×z½>}8Rh«ᢘà“ÉãCï1~óî¹E=ý›Îk}üþrº»þúöóÇi­XÖz÷¯ÃÃû<ÓM íÏòÃûßÿñéãç7ŸÚDT&:?�î®äáé—ŽÖà@08+vxzwz @ À®ü\ø +ÀÀ‡|€`è€G©m¯ã3'.õs¯†§Ÿ�ÄPð)†ž~^–žÀ�c‹hØ;D5È_<>mfµaŽÖ ch†…Ñ lDŘ¼X« —¬±l½k«IÆ€nW>ÓØž½ñNËwT~FˆŒXëƒÀ«qš!7´l€)Ê©Ô(cz©ØŽÓ¢¡Aì¼1 Ç9^޹÷P|åËà®îʲ•·Y�œÚð¹šV>wßk§¤Gk/ú¨9³yŠÌüìQc¿ó¢<¸Žså qs»ëxéÙÚç#\Z?§žÛmÌŽsÁ™=ø¹WÝh\þÛkCª·wÜ)RÜ™b=/O„AÁS—ÇÓrgðá<ZQ+{Pûå^µUÐ#*¸Öa @Æ2{{# eáÕÿP~¼òS1¼�½¯GΥϥðݹ[Sh±ïÂêŽt#Ϧ•qYi6¾ “WaËߊ·á¢\[x{¶Š‚ }˜":Ï3£GåÚ.WÕç^»ù€ŠÜ!9jTÔQ�‹“«5 Š9\Ò–æüæ’ÇÉmSRãÉ*ru5†\‰½ d\yS¦Ô9QñD�1?÷ìn<Áÿ7ÆÛ¼rÇŽ¥i�1Õï$X7%¼ÈVÆ ¦  ‚%ø¸AÃÀ_:Þqûp×4”vm†AÑK^+ÈE¹è:ºµn*íW)«ôë×Úx³n¾•�B�úªk«î“ÐèÔBÇ‹ýfhĬZñ<‚˜óx¸Á·R9*÷Б×ñBã!½u¿vVŸEê´Cè`ñ¶p›Q¨¬Ýxí2Ž +§M÷‹ÚíE5í1JÏÑü\OE¨žº‘_™\Žå¸Ø:ë<²Ö•Ÿ­¾FJ0ÂLFwÑÒg&zl½=˜Àh~¹L^ÈHŽËŠ Ñ:ç¾ A?i Ûü5jEkPÖEÏ3+g�Ç”7ROú¯e/TJ¢¹ +^‰Œ·ÄD‹‘éZF¾Ä�ß�NñãQÅOÅÚÝWœI‚öØäÞƒ©Ã®‰hbȇAµ€v^“öqžÚ×é´ô©Àê }î„[ é{®2'‡‡Óá±å°§;^#VÖ‘v—Ú'(uIÅØ¢iªÂìwr^Øn­ÄË�&Îñëñ>-�®sm»¹ÊîT9Ë�JtÌ�ÛT ­òK¶xKáë8Õ.¹N9±¶=ÓúI¥Ÿkí49[³z^d‚�Áˆõ~Nf8—C·*…/ó6Ïr²­ù¯É’^5°êWÃôªNÄò¼|•<íÑÕìŠnYF«%°‚ÖÞnv˜Û­kG +´Þ¤®>LüÃhM,ôGƒ�ºw|�t”ø;�"s«š¾%�ÇŽÅØ„6„EV÷®ú]Qô�˜ÙO9©Ìf�ãLYb³Œ¨²áÀ(Èí ‹ÞÄhQT*scEC ª�X +$Ë/j­Ï õ`#)®s«qì‰Q%µK±# +»uµ¯Ìá"z�ë·'er' =¶=ƒp¬´|¬‡f{ßÕ«º ;g®-†yNµ7€‰®SªÖKh"QpK± '&:ÂkÁÖÐ\Ë‹%Ævf8¨�»`lªÓ«yÒa"§°BÞZHi3‘†}� Z V¶€\+š/§åŽb¦cì‘ùv`猓¹ù:Âf„©�¸£ÄpÑ C+~)1P%ÁzØ« ¿NI<'}ž¦�«å™ë$3¤; ¶ïzN-ÏëVªãUÿmeŠ–YìJ!o¨ÚçkTõ�þÏô¸ÈT+Z}.äR_�Ó•à‡©}“Cµ_ +(#J9\¯jŽFXG!Êû;”!)A:¡ù îQUÿ8æ”ý¢ªØh(à“V´h‘vC|ú¨Š³øÀi—õ>ÍqVè-¾:ó«Zʱ£ 7Œ�TR*‘ç<+9Á&7¥‘�ÍgseùŸ –nuB=CÕz•±áqÒõ¶fxJºE�µIªÎI× N ¹£s?úýhÅT?‘4ê‡êñFŠ·4Òä¶FÄ÷Õ›™ÚþÂâ‰ÙD‰žüóäÓ±\êý +"êªeµt½µÑ}I¶\­´jšº*Igóêò\ÀÖ“Ôô˹U%Ÿ5=Ò® «ÜÐgi}e ;)ÝnÔyU©¯aÒÙÊ-M߯Ý÷Ü¿ãÅ@•–W.Ww_„@UáeÕ¹z¶U¡KÈ +ï‰eEñŸ§ÊòV,LÜuÁ-l0½‹£ x& èñ·R0ï†Ñ8:ŒÀ]q÷ˆËhÿœÃ©M3£é‘è�ˆ6è±éæùõµxCìýšž"ûݾ&Æwdç3è”MÎófS:8%§·ªþÄlºxái‡­Önªšm¡³qËçš«¾3_oá³CV­”àjJlO_™ôN8ˆ`ÒÝ„Zà_�óÞ ‘`ò FY}LzÇ7”‚$[špˬr:O±ý ÉÁUA²A§MlÔzñE¿>ÕªÛœÃ}q‹Y¯M2¥jë H´ú ÃÓWšBô²êŽ•ZPŸØ¬]¥©+ªñ.¢Ý;F°vy¥{˜Zºê;?PhY•j_å†ÌGV•éRÆr:2(¤ÔåÓx‰t©w¡9R審7ÜnŽmÆS&Š!PX¸}ºÃ1Xx³©/öpc¿øÉøÅº�ÑP´‘õ›ÂåòÀ¦÷¸Û0ê}V¯#é²ç¤=^ç·Â“Ó‰rƒu é÷ö‹õ鯣·ÄsXÉgAe½ñ™S©½ÄSkª<^öe|ü,UöƒxLïX¤|ÔFA€¶üŽcæC.Ï üŽ»£Ú òÿg€Ð.àºD4àZÝ''^ÒIw£o0.&#ô|yÉÚ3ÿ5?%€ +endstream +endobj +93 0 obj +<> stream +xœíÝ¿ŽÔÊ—ÀñÑîKp¥›�D8£¹H„ RñˆD7ñ#^ÐOúe+ Ï0£Ÿv“ÝpúUzuçr8œª:.Ûí*w÷×ú3Ýmw¹\Ž«l÷½ß~¿‡ÿ÷¡p ˆ<Б'Ú ò@DžhƒÈmy  "O´Aä €6ˆ<Б'Ú ò@DžhƒÈmy  "O´Aä €6ˆ<Б'Ú ò@DžhƒÈmy  "O´Aä €6ˆ<Б'Ú ò@DžhƒÈmy  "O´Aä €6ˆ<Б'Ú ò@DžhƒÈmy  "O´Aä €6ˆ<Б'Ú ò@DžhƒÈmy`1ÿý?·?ýç?í¿ÝÓ€CòK„iÆ<‰<°[DžhƒÈà ýïŸÖæ?þñÏŸÿþ×ïù××dT†ÿñ¯“?þu’þ-ÿv/€ý"]I¶g¡[jö˜gyºWˆI¯QŠ<éV€AÇyº?ˆÅ‘gú"g_"Ï?~,Û1‹Tÿôoù7û±Òr²=9`vpì*£>?ê(³°ÕÒ v¯dã}•ò_:‹lÏâú‘Ánå¯Ï˜Ezºî½-°´5?Ïó�Ü2ª‰®Œ<³pK÷fpé6véU*??êø²°ÛÒ¦v¯dã}•A}äY3¬‘íæˆ?qDVóF¥Ê¸hä¿Þ½\º�]z"O–ùK›Ú½’�÷U:£"Ïô3þ­péÞ‹ëyžlO‚ +Ø&ò,µÝ›Á¥ÛØ¥W©ùü¨ƒËÂrlK³Ú½’�÷U: +"ÏàÝ8ò”ådË%£8\ý"O­ìƒupTC=9òÌ~ {K¸h»ô*Dž,,3—fµ{%ï«tæDžé°Feä)ú ÀÎõˆ<]e�+à½ß~ßn·éF²/N~ž§~Ò®" lÿcT—¥c?_ÊÀ`ûõ«Œú¼~lT’€c U»²v,ZUG¥Ä~~_Ò [¼·=^ë—UÆDžÄŸ8@m#ÏÒ™¦ 5ýTû‰¯w­´»ÈSOK]c²O æÉ¸Áñƒ�KþÇjû‘Û@3?#Ϻ:¾Æy„‘­SÏ¥ÐMŽ<·'™>È~¡íìJa'ñ'M«ÈspšC‡7ÝÒr¶=]¥ûìÏ¢óJK¯Âl; ËÌ¥Yí^ÉÆû*…ù×yþ²J2©g_/¥M?ì½&‘g\Ùå3i•ÔeTC=-òÌÞdÔ½\º�]z"O–™K³Ú½’�÷U: +“#ÏlÏRº®L:»RÚì'�ýÖ$ò,�Ê餺•®xÕPO{ªRö­îÍàÒmìÒ«ðT%–ùKƒÚ=öGº7_ )‚i‘g©g)_Ýùó¾—0�bï-y×®Èl#Ö%òäIòË­BäÉÂ2iS»W²ñ¾J‡`lä?L>ˆ K÷ê¹æ¦£A+4ê×3‡çßðSh/ß ß?„&X&ò ª‰T¥å®f©¹·Ý½¾s®õüðüÏÔ| ÆœoÛÈÏÉà8•êÎÌz7¿jÇ«ïdǧåÕé¦jîmÛ­Ä‘gÍŸØW DžA©øÔˆ ÍKæÛ'=I~‡&·�ØUL÷*¹~¥ì +^´ÿÆíOúÀçšçyîä»éB‚O‚]Gž5ag)øìŸ³MØ‘î-ö +u?ŽÀªt¯’ëaÏî³#–ÙÆ$h[VÕþØ}Lc…àbáÈS^Ô°³ô„¥þù° Óö…ë<'dpœêçQõ®ãužÙ(1�ÁæDž5)\U¤ÉH#ÌRðÙ=ÍÀ»‹<³w¦gÃNyöÏ�Ý™ybm-?°NÝëfwiPgKe˼Âö§4¶™Ÿ«J60lG‘§ÖÙRØé–ƒ¬&Óª÷–|…ºJ`�º×ͽ“¶ÌÙ¦f�íO)øLÇpV•l`À®#O¡¿·^ª8i¹ m!»ï,Ì—�k^©óLÌÁ׻牕�9³¿s´¶”E»ˆ<³å¿ô²þ»¼¤¥#Oš‡dlT93òLWISÒ=Oœì¤aö…Ý“ +TY2òÔÁÏ# ;57Ú&m €G•ñìy}äY3±¾æøÍ…�¶“%øÄþ™y–ÂÎôâÏþ;ÛÊÎ[šié1Ïý½Ã(H¡(ý2K÷¤æEž¥bäçb;ßå£Ê=Çc ‘ç^tU¥.õ˜»Zì«]Gž„�qþLÖ}_`çDžƒÁç¾4¶ÙaO‚O쟑g¶šS•ÚDžÁTÔõV õà@ì4ò¤êípbhp¶(øÌ¾ÜÅI·‹C05ò, xÖ}D³1Ïì—ºhsýV}ÏÛ=©@Ñî"Oμ£ì*ò îxüj÷J÷<©Ï±4l¦óŘyvæËFPéK(%¦{žŒÊ4&±ÆGž¥Ñ~ιcí<ŒœÜíK·EŒý¶‹È“OÀzväIð‰ý62ò,…�xÀz[äÉöÆŽ"OJ;`UæOܯY)åû»G8c"O<Xƒú� zd¬Kuä™-Ì„�tA§Œ½4#òÜþ{¡„Ð#BØKu‘g©xyÐ 7_`ÿL�< ;èŽà{¦"òd<€u +"O7FÔ=©À½©‘'ž¬DÐM»Îº{R�Áȳ4àIØ ÀdÃN‚O¬Tyrcë—Žyb¥&Ež„�¬G¶§&øÄ•#O<ØÙÈS^'òÄŠŒ�< ;X¡¿ûåŸ}6ÞXŸBä<¥�È€úÙ5ÿøËÎTêÝÓ‰£VŠ<œ.ÙÑο_'ì`•ü°ç‰¿É½{ +qì‚Ùö_Çê³WxöO?øá—nÚŸò®þtFž…šæŒ‰È€•û{xó×[–šàS? ,b(òüsžøÈ³âÀ¯´×v‘§¾[³z÷½ÀÒh³4ÛÞ=…ÀÉFžõÁ'‘'zÉFžvOÈš3ìIä‰.´ÄÊ¿zÍ'€•›3ìIG�.¤ÄÚ‘Oý— ÀÊ•‚Oûn°tO?ŽŠ½¥ÝxvO¨aoÎ{ÆkuO?ŽŠŽsv°§çÜK«y¢%wˆ–Ûî õ& {y¢=WÞ;ØSc‡=‰<±œÁ‹ŠÓ§*uO3˜ û“FÜa„–â2¦yº_Ý{gì„{÷ãð Ÿðü¢§pê'Ü»'‡§>òdÌ€Ã0|Òãc!•‘§]º§Ì‘>UÞ¡ÇÇBˆ<86Œy¢—8ªÌÞ×=Í`ŽQ?iìPå8'wp0ˆ<Ñ˨v"O‘'z©Œ<Ó(ì)"O¬S|ãØGõ¿¤ ´á~½¨{zÀ®¤‘g÷$áÈyp¨óÄÚyp¨ˆ<±6Dž*"O¬ ‘'‡ÊöïôõX"OUy2æ €åy %"O´¡‘çöÏ?»'€Ô—¯ß¾|ý–}ëòò“¼u}ý=uyùI>vÿÁÃËËO××ß¿|ýöâå«î{tqñúË×o××߯®>Ÿž�Û·^¼|%o½ÿðñþƒ‡ö­7oßÉ~]\¼v ÞZHé»=~r}ýýÑã'õ›Š�Ni×ìZOŸ=wi¸ºúœÍÞÆ$…. ¥,º¼ü¤%¶Ò—¯ßÜv‚}ŠVðVcr@Ý‹¯¯¯¿OØÚýKå'Ȩiy¸´/_]_Ï6_R¢^¼|%•ÊÖǧϞËn¦5(Í|K�T*Û4�-Õ•GV[ÑëëïoÞ¾³‡cT>-Iº/ÙÝ”ÕÓ~G2Yyyù)(0õi˜LŽõ¨�?züDÿæí»øXhÎØzá²ÅfÎýßø(Ÿ¯LLp¸w®²jùðåë·f}±³žÆ|ß½ÿðq»Ý¦MîéÙùv»½ºú|ï·ßå�§Ïž[ÒÎÜððææV*ÝÅÅëív×£¥]]}Þn·¯¥QÚn·ÚJò..^¿xùêææöææÖ®uss+�Ëv»µ�[ðÖr¶Ûm¶Ñ¸ÿàáÓgÏë ||tJ»&kI³àŠÇ£ÇO$m𽽂Ïûnÿ½¸Œzúìùv»M4Û­×$»�`߃¢¼ÕØ‹—¯$Ç\æÈ!ž�ÿ²;iù 2jZ6+NÙ/•’pzv.åšÁl}”}‘Ý”µJ¥F,J^w_q}ýÝ6e63§�5=~r·ÙH(í†ûöú|Z’4JÍìÝfsyùÉõ;Zžå-Ùx¶-ªOÃdÒWÞÜÜJwYI2ùé³çAjk™Ö ÉçG�ŸØÌ¿¼ü¤Åìêê³ô×_¾~«éŽe³r¸å,-l»R_5Ò–Á)“w›�fE3ëiÌ€�0­7oßiñ+Bú1{"6¡ÛiŠmÃ"mŽüm÷B:)ó²–móµ ÞZT�á£G'Ø5·Öûï6ù[N÷tû2rÕåXK"//?iÚìŽÌ‰<ï?x(A‘ÛN°ï¥¢¿Õ˜Ìn¤ýã´ÈSJ…i“¥ü5-ÛÐÓ½.]Þ¨Œr±SÐ*ÞÜÜÖt)ÒinÜÜÜî<ò”œO+õ—¯ß´¢ÕçCÐ’XA[$éÉŽŒéqÑ×m‹*Ó0‡lSª@},TÓÈ»ÄKn¤Á¤;j:zÿâå«Á¯È&ûn³)Í„ÎT_5,91±¯HÜÒx˜«{u`¤ŸueφôA9=;·'G¶Q*Í{¾ÿðÑ�ÚWt(þêê³®+›’³¤`”>”Ïkkf£3�iCªE:xKfouì]^Ôy(�~å�a”Y!�$*åªTÏtgm–ÚÙ‡ËËOÙx88:Á®¹9Y›u®²ëFôÉ�»Ó³s=”zPd,ER.ç°:7”În$‚JÏ5æGžÛíön³‘6ßn§´ïAÑ +Þª,õ_N í¤ëË&Gž.7lÕ+eÔ´T¸k4g¤•×õ˜ÊñµÍˆûRíÚ(Lf[f×2PyJÙ¸ÛlË›ëû¤`Ÿž�§5H¶©…ÜžÖ$IzºÒ襾’žOé+ñ[6‹¤›K“g«j:£Wˆs“hWWŸeã¶)s#ÿñõŸéÑ v-ÛVKó’míåB#»–^ã²Ú횻ң4¦ì�4¶Å“&ÅÅKú½’W)Wn]b‚}ŠÖà[ƒ£>cc6>·ÑT°‘ £4“¥TØkó É´»±Jwõ…ëŒì.ÈêõßT�ô“7J³#Õ.[ì8§ô†.Vtã6îŒÁ"´Q˜Ìuß®°é¼@z¦’¹-éÔk�=7ÔK8ÒÑl×gÙ“åÁj«çAòï‘§›çr]€�<Ó/Í®eW·£Rš3¶îÈ\[åÕòéÑY"ò,Åi.ò´·ÿÖ·ö2½%» ~tÉÅKn^rP›Ès°`Ôgl@²È^’Þ0RŸ3š ÛDhŸ»PäÙ&£\ÓçZEÙÈàýæNéòÑtt%�¦ÒWÜ…y¥fgrår[p·±KJêóa~äémh'1¹KÞm6"Ï™ÙåÎMä_{åØ#OHI'åÇÆ{¥�_^~Òèîn³‘lÆ–Óþzì5´AÕÈzñò•Ľ’ÈëëïZ ²á« Dß¼}'g1Ò º:"Ï^ì8¤ BÚ•½·=ØÎà àÚ€ØïM/é ú¬¸ÚjØœÔÄ‘§}œTÍ[;�<ûn½XH‡M*�²^-PÚµl[-±\6a.$^:òL˧ÄÛս핑ç£ÇOÖy¦—ñÛøjräé2yl!™–‡KGž6¯Ü…Ù{ºã~SúÖú«—]š^u)UXO"–Ž<%Àp“õùPjIÒ½.µEÙmÊtL¢wšP“†ùÙ%™�a‘¹´‘É‘§„�i„™^è>“ÚjewPò\‹„]wTK2¶jX§gçRO%KwLÜðÐv‘n[äˆ<;ÒQôô>²Qu¤¦‹×€ÓžÃêE_ú±i‘gvf¯?—ë¢õÁhö­»ÍF6¼µt䙽k&͇ӳs}ìIMû£ßìš»ßV/*Kï3•Ã7ªßŸßÚÛé-› {õÑœë<³‰ ö=(ZÁ[-ªtTDš}© s®ót…V®a+eÔ´6!ò Z+nfÓ[_í�éö»²Ã¤AffWöZ÷¸§à"±ÊÈ3;ã3…JÙ+%ìCKÒa™æN/� ~•Æ‘Qagéžw/e‚‹Hí ‰"Ï �ÂLÒŽ¥�CPGÜuÝ¥)�ÒŠ®¥M/ݱO§©‰<³agºq;Öê†f‡Ô‚·–Ž<µnJ>¸Û7NÏÎí³›JÏy ŽN°k6,‘HÞÍÌJÂìšEžîE¥ƒx Ͷû­à­f•Þ¦çÈu“çŒìÍ2«å®©ÎfÔ„dï¸ÔG9ÉgJ'_¥£ïµä¤ ÛºJ»ê¾tç‘gpž›ÞÝ •*]gguIv;Ù}�‹Vé­�TÙGj-KsLÏn²7ŒÔœË늲wö`•2jB¶É(GŠ“ëVâîI(ÑBš¥’?îi�ÒKº:XüL‹</UžC%í�û´Æ8\ö–Z—†R[äz»…Ó³sÛHºûÜíÆKi˜Ù•îË–3ûœ@ œÜhíוʤ>ë©T7ë§ìƒ»á¤j¿é¶Y:’ERtÓC�ýº¸jƒþº‡dEÚ—Ù n5ýR¨4yRn³·9Ø"ÔŽ �Ç¥‡ó ^H¯s5[Sz‰Ž#3J."­y:™›ŠÊÞ %_šMUpçTv;.@u½†$/½}Õþ[zŒ›¬.{äƒfû„£3¸×²V6yƒÈýk÷:}’°}°®%MM¶(ôNÆì£°ÇþÞ}v;é¾×­ô­Ê‚1*c³‘gœc§gçÙZS™W£ +É´œ-fÙJWÊd·…ùmQ©áµße›qyÆHºz©ur?‘™ÖÍÊÇfJpHêw…!{f$o¹üÉ&,®¥|NKH):ÍþŠ«Ý)Íg—á¶4ÆÅ;nçì;Ò;JÍ/å¡{FÉRßXCök -rÏÀœ¯þú�£ÊgûK~U¤{2öˆ\ÚÔ=ë×7£ÞøØ}’n iØ£<Œ¶hç¿V¿óÈó0òÀ^c:ƒì:¼ŒZÃaZCök Ç–È“�O:@>4öÿìH[ +endstream +endobj +94 0 obj +<> stream +xœÝ[K�$· ¾÷¯¨skIŠÔ0 ÌôÌ’IHÎÙØN‚؆7öÿô¦T]]½v|É‹éV•$Ф>>Û��ùßlŸõ50šˆ1†í÷—.ˆbɆ^6"Âf �q1Òöñ«Ë_~³}wùáb ’äõʧ6ó3Œh½‘´äçúr+>~sy÷¥Ý¾ùÏåݾÿîÏ?~üéÃ�Û矿ûýõ·/l_|ñür½<¿¿¼{Ú�·÷__°PŒÁæ0ºíý·—Ïì_8€`ùb{ÿ¯‹ (XÚ`{ÿ÷ísf ê½4Çðsýʘàx‡žêxpéý·ú?ˆ e?d6ÑEO~ìê¯ù B‰‚ÐôBÚF ní붯…Ôº´CCÖY +}¢ÄüÀD�qZ1 ˆ ±‰ÐôÝ%r¤¾SVöÖX+ÑŽ•ù©r +ËçLÞ €T.§Å×ôfå� œe¿pâªWeÐ9 Ý‹y›PéÇÛ\’º½ø¼XL +JÑ-̨ұ†È‹�8x¨ORõ‡}•ïu9eYåõý=•$ U%éÀ_Çt¢6ýõ÷×[ +�ç +Oÿ>¯Z×Hž¶–JÞÂØô~À�ZcH@†h‡°ŸÔYýÐ�®âTÕ¼°€bù Ï–¬Èêh+q\yòRç@=@%(=‡ë‰ôIKŸ7Â�ð-Ø*|L`#°Þ´`=Î’—zb*ÒLlËc~°tVíêìL:c“Ô ì©dìTæEƒ ÄÌÞuÊ ÉF8DQù`Øü€ F‡ÜØ—rí�µPA˜„ú€ƒ NÝø§&²fmsK!h…¨ªn ÆH1<ð„C]L8Æ.‚ŸL×áRòÄ{bl”—f�(•8fÊUüT8½¨K o2<þ"‘ÕÒ¶ ëÝxŸŸhr×#A}ò)øZOKŒ�Ìx­›£õ`#ÝSàö8”ßcÊc~¢4¢òlãº�èÈݾâùæzÅ*¾-Víù馅<È<âÇ$>½Ô/¼U'R:S>7ôÖwCÿR •«�ÕR6ǧ:IÍ­Fm5ðͬv½5I‰‡µ¿„ÑGeܳ1)OÉXŒ¢ævSÞˆ†-‹ší'sCh¼Vgí¶{Ð<Ùî(�0»On6—³åÀ!¥ÚTÙZ}€ÎªáWº`Äy;“z&iYÌæ^ÐLÐüE%nÞ�¨óûa¯»Ýœôê…ð“¦@®åTm _&‚÷·wR]%•ÃæXÀÈöí…½Éa¡+CÁ"niÌ:‘üäÓX€è"•1‡Û‡4Û +ä˨wDéMÂ�ß$–|#罓2FÎ×Ù`­å2(€»´F õ=Ð¥1çÁ–±Á¥¹Î £/£Ñº�%‘/èêPŒ’ÆòZ6Mƒ.$ŸC=g8&:–a#l©Ñ fZÙ�õš¬„UÎ^Vê­ñ–Èâ|Jk8ú€šÖXôXØÑØf ÆrÈÁ^›¬²`ݘmýpYž£ó²éu8šÀÕ~�0•í:Y Y ›¢žƒ‰® õcr0Þ"—É� G—YY˜ÆÁX”8ñ–ƒÁ¥ð¶ �sL¹iYqhbäPÄØÅœ)Eh“•ƨ]”nuz†vš•ªªÓ)¥î|PÊŸÙ•¶VפðUÊì~¡ +ÿó>{9…!Ç\¾>‚߸¸„9ÒÓ&®yŠ1Y‰^eüd’n¸YVÃ} ƒá. "FcÙzÑ”á‹B©ð0! ýZ,†T´}§ ,Ì¨ØæÃk5…®Œd‚Ck÷\˜_âÞX¬m¨ÌTz¯™ƒCªkQY¯­Ýɲ5Ó5­kZÞñ¼V7yo•�qÜ«ÛÒ²;idñ-‰‘ÃaR�äË ¬QÜNšE"廿ÎB<48¡Õ_v�®Y«¯”ì ½K* AÞƒtû¤5HSɦ«‚Œš˜ªÉ´;Ï÷C²)“™c…±k�â>C¢Ý÷–EјÒkíýÊx#�Öjb¢ÖÔ±H«v¡±nWŒõóË+Q?…›EºW°kV#—€žöñAÍ’D#ä¬_�à å…zM:•Ÿë�ÞÎ +aþ…Tvh²»¬žKÓ{™ w+\Êø†:ÿ€�Ÿf©4û_'ij4#žç%t·kunh4_UNQT•³*Y¿mTŸ=ÍyJí"õ›øTOª¸•Ní®#y½æoÛÍ®þyoÀ3ÑÞ_«‰RÑâxíD=Óë(ñæwOjwãVÞ½…jý~è·€,Ce;\,Ì;D†ÝͽÙ’¨S+EFšñáV¥¿£Ä›O\E˜?Ÿ\¬i�/ø£ë¦¢ûê]·š7³±6ªLþØUEÕšZZ1ýSÑ©Y�{�1ífç…š�kS›ÄI ;ëÛžëlÝjctCËz×qñÈmhàú Mj¬¤fXý¬õgMº^õ¬êW~¾a#ŸUÅæoß #0~8çö3òuRC +ˆ˜GBöÜô€.l]µyøãå‡ !…Þ‰÷KmÆóe�ÊÀ½f¼leÞþùÍO¿&¦Õ‡Þý5Úíåû¼×/jù;²eS;À-~lÕцRcßö­=݈Ô~¹ÕÅiÕLñHAõ†éZ'˜à%zçk�ÎHjwÓoÌÕΔå{×Pf GÆ�c•\¯H6,,.…Ú}zÞŠÏ„»ºú÷!œ¤ƒkþCec0LÁ#uÚqdd˜ùªDZ³ænRÕÒ8Ÿ�cž;˦|½‰VD½Ð;*ìò`ò•j'¥”åûƒ1iì½´yÖ³ZEÊØôýI}w un¡Ê7*ê÷P׫®¸vÃAÍë °µ¹}çÖ¹“Œ¥µyóø¶‡Þ»)�Þö“f¦Ìé¾ìªR˜ˆ€âf›{Vcœã}êa“nŒ?;Ñý`C0” ±:×C(p”ˆ¹•A¨ÍYVŒµ~rJ�pÔÏúiçÛ”¿·žç%#�t¹=?ѳìs§Î„ôk»Bª]¬¬+ð¨Ð¨‘¿/ÍÜu“”_ÕøöKû rø¢‹EMÚ8äu~ÁNœ3k“k˜ôQŸÀ) /ºu,Ý3JîûAœ<ϘR³Š�^3 ÖZdÔîùˆìÎÐOJ‹¢‘U�ÜfG!¦æŸÝ/Lð²÷ËŽBl¼7 @_³¬.ë5‚~É�7kà îxÿAD/ºUɵ‹rÒΑ¯›�‹^ärbTŸ¯÷I¥¥÷pÍÞÌ–·gKÿf¾Æ4œŠè\äZÞÌÞSMRGù¹ Ÿ·qõV¼¹IÈÿ®.zC¡èˆì ÀSBDQaMwOÚÖf*íaÞÂ�šMbo<…TâšÚa•‘&㲚ÛëãvY¾ùÛ«–ëaJÙÍ�;YPq‡u÷}™Ä9µWeÛP¥jÜü¨Þ6 �¬ø½6°–9êãÏ*JoLJa̺�éwyNo‚¤‚!íòm¿–ò»Õò�ß;ÈÐÏ?–é½&S„UcÎ1™TJ¦7¬/?$”Ê­¡b·´éHqæ+—Oº$uÚ|mÜÓ˜/Ê{ïù·çįEÞ·­SúOë'ký¥ïó€t«üD/L¼Lú�»342«ÄcJ¦ ‰’Í +¸ô÷ø÷ÁéÓY~0ŸÈmqöx¼)ñ +õ.ÅXÙSsYEf¥]ñ)¥—q²¯’cžîÕ*H «aÌãÝUmpòÏ¥±g„ðéþ”ˆ5« æŒ‚ÊÉÜP].½_&YKæ¿)â´ø +endstream +endobj +96 0 obj +<> stream +xœí�ß�Ç�àù: ²•Øp`9ë•mXÛðÌzù×Ú~8äåþƒ4`ÑNp‡A´A?,¨·ŒXÁŽðÃàCd[ñeéWfv–¢elfc`ì;àaF<BÝÕ]]ÕUÝl6›ýƒýùà ‰¬®êœ®þð[ÝÍ>ñ•{O|åwŸ ¬ñU‚ ˆFéÏ*†Tž÷ž¨™Kß©jwÝMÍ�»Ëв;~Qº/ÒÛð^U‚÷}íþ‡ùÆc�?ñäÖé3O=]ã8CAä¥Û—ˆ'·N?öø?ò�û¾v¿™Š’S=òìsÏ_øÉ?½ù×ãßÿáàÿþ?‚ ‚X�ÿþ—.ÿúÂOÞ~ö¹çO=ôˆšŠ�?þĹïÿàêoÇ¥¯*AA¬.®ýöwç¾ÿƒÇB&=õÐ#ç¾ÿƒÒ×� ‚ Љsÿ™Þ÷µûŸ}îï®þöw¥¯AA×~û»gŸû»ûîsÏ>üÈ7.üäŸJ_%‚ ‚(2.üäí‡þÆÝ'îyìñ'Þ¿üëÒׇ ‚ ŠŒ÷/ÿú1ï,á“[§¹:” ‚hZŒÿ‡'·Nß}âž3O=]úÊADñqæ©§ñ AÑØð<øUðü /ª¦S‡æÄÁßêÁ—ξbŽ=ÊBi¢V«%f¸wåº_}þ…Õ#³œ�(.�3‰ÌS¬Œ(Œ¬�Üd±PõÓs[qòäêÀ£(yçÝ÷D¡l(?1ñ)‰�ÂÚV¬­Xy¹ Èú¤Ü+LFòÊÈÒåJªid{åþi«nNúŒ• "ÇL/A׃gRyPMŽ"Ɉ”š80FL§žÏÇØÈùA1Už‰S›¨Çð—ξ"½ ¥,ÄœÅk5Õ’ó‘â0ç)VÆ@ ¹{P•nŠ$‰ y0á’« €ÔäîAí:c4À6.jõ ¥­lcó µ>@ ¹{Ð~ß„Yd¹NÆêAûm®í‚ëdtpÛ¬«ð @]ÀƒÐdð 4<M@“ÁƒÐdð T™³�¤ìOÖ™²÷îrHþLð T™³gÏþ¥aàAX)ô)<U†> �/ô)<U†> �/ô)<U†> �/ô)“uöàngc£SÝß�[½V{·³±ø¯�»¿ÙZ¹ÏËÒg/¾,~;öô›Ÿhï[/_ŒÔH*©.9x°â{~æ5LhµÂÞ$g´¾}ê/^ zTûÔ*<¨íxiöÃeöÕ ]C­`>ªpåjÞ eyÖMs7+Û#7ºNÕzm´Ïº�Oëw_ößòæiñ*MI•QûìÂ]iÑšÈeææL–e¥\†%=(+ÌýºW.Óñ²w÷é³êwV¿@vÂOÞ<íNLSRiêÁ%[­Öƒëܧ|®±æ}ÊJq “/ñ %·¼ãˆÇÓ‹:ZzæVŠm¢ùo7:»J{o‘–Eë;³uÿ +õFó·b­ˆ^Õ)ÖÕ3>�¤M3‘]Ö­ã8­à#V>Ukyä#q§”ÿEVï³r(FÇ(ýÑ�¦¤ÒÌ÷`¤_ÄìBú™¢NäkaÐz\ü<õîë϶Ì©åtâ—nöV³Ë¨ŸIî½Éì\ëܧ¬\Ç>ee%lé¸yåÁ»â둚Ev<¯Kl¢í™ÆžÕuüúþ|”ÃEÒïÕ”G€pQ¡…cd®Ø�í­ú˜à¸ÕKþ«mšK§“')ÄÊÄ•«ó¯hŸÕ¿…¦í¡5º’uŠî�)êX=˜ÔãçíAzZ»t³·š]F’_o²|Î!kݧð �œóÁè¤Ì•:áTãKZBclSûÚ§ùÓ¾B'{ÐÿîSÙº „m‰›‰uõÒošíÃ×úld>qG†¸õ¯±ôûíš�á¤íJq»PšÝ,nÎq;¶%q³Í3Òƒ¾‚ªËJ³žÉ3Y¾7]`­ûTã¢6Jò ò¥qQªÒ‰ô¬¸�0q\ÔCéËs”°-Ö%Æ­^úMKÞ¦l}VùB]ŒóƒÁÉüàôüzŸÓ_¸+©5ãZ¥©“Òƒ óô zPzÎ]Ïl›™¾7åîÁj÷)Egëݧ¬u~Ð6ÈiìÞº9R5 Û(Sý=ÝXtCyáyŠÝŽ£u•4 JØI8\tGcõØ4æøÕ"}V×xùßb�>ë_Ú^ܶÖ×x§êJ »�­UlýKhì@GXmÎ<õdŒ‹ÚföV³Ë$LÊ£7™�kÍûTØ©”ÓîkÛ§¬”{�ŒÙU[‘:sšÈoœ�]ÙÞ=eÙ9ÕauÝZÆceÔ¯us”°-’`ŠßÖ\½”›7Ùi³ôYóP˜ðw.‚†ßó›ª+%îB¶V±ud•øû@Ý-“æiö ¥²¸Nƞʙ½Õì2’¼zS²éS5§Ñ÷Ñ7•õ¾×iíá÷d*}ªÖàÁF²ö¿}±ÎàÁJBŸª1xj } _èS&xª } _èS&xª } _èS&xª } _èS&xªÌÙFRö§ëLÙ{w9$&‰ü +€õ@“ÁƒÐdð 4+Q*O£?ýæ'^Ï£÷Yƃʣҗ> ,Ú‘­õÓ–JFöÚâƒn÷ò·¨Ôwì�N7aÊûñ«Eyp�8 V¢¼ør`²‹/{&¼ø²ï6×�Þ«4%U¦æØV—ÖÀƒû;[­ÖÖÎ~Òqº×žW–Aó`ú&»NâgX„—‘YîÛ +!~\ô“7OŸ~󩸠à/iJ*MU<è�µhéaXâÕö:lÇ *„Sƒá–„úÆkoéÁ°T«åtd…–¹€ Ç WX4ß5ëÇ­Rž*�zpgk«ÝÞJÔœ«JÁ,Ìf³ñxl–�ÇãÙl&ß&y0vo ÷½poQ­Ù™Ûá­ûäÜnemeì½RƒnCÇÙh�*hW®o_î]r$Öƒ¦ãü×iJ*M5ÆEÝÂè,ÁWÆ®£ö\q0 ;TX?èZ‰õ#¯ÝúúWSµ‚ÖÓõÖ™ûõÍUZ¹] îì‡ùžx¯N“C¢­¹i#D¹uëÖööö`0P ƒÁöööÑÑ‘,‰ hÛ[÷.sg^t‡7öÉTÝ*lYzˆEdòÄŸhW~,"\!z“ªßG_AV6ø£zP·›?4*“Äð2R<¸bŠþ=™²‡¹píÁƒ&x0%ÊöU§ø=™ +RŒ Ø»RÃïɬ9xÐVÕVne¥F 0Ù :[ûü#õ]«ê‹HÚhq<žíyZBä~Ñ|Päz�è¬"SS6[F9ǃsKb7DîTGýÈX6,Àƒá(-€�Ü=¨�g +û(cœîK¯ÄñEä9©kjεz0ùŸ¬>]GI5 Ñ4ǃJ:ˆÀ§90ÁƒÐdð 4<M®šÉd2�†P£Ñh2™Ä€WÍh4:<<¼%qxx8�âŽÒxpÕ ‡Ã²w€¦3ãŽÒxpÕàA€ÒÁƒ%‚J'³ñ‹_,Ôj>»���N>¿í™ã¬V (�Â<¸¡>rÉúóesåe­°da©,áÁý�­V«ÝËwg˜O¯Ýjmíì½X€ÕQœç:(›Ó׬º]ÇxH½y²kYÌãNh÷¼²r¯�É‹Á2¬ËQ*Éi½6&€u"³ÿë?üÃB­LívdŽèMó<Õq”Œ1,qºJõ Ç ËC»…¿–ítŒYÍwåJltvÍEëë'VÐ+ÉS¥ª¥Æ|ÇyE¾pä‹°®_ e± *¯Üe…uâ“=mVá +T™Ùl6�Íòñx<›ÍäÛJŒ‹Š§yÞñ't�–ГZU*O-÷ Ý"­fdV‘榣õ]«ê‹X­C�)nÿG…¦edÞ›žMyó=h¤vA“0ItßêïR  |nݺµ½½= ÔÂÁ`°½½}tt$K +»^Ô>P©&\V=©­’Ef­im•Ü<®$îcZ»õÔЯ´hÑšÆÍÕ•¥‚·h%áëµ½‘š‡`Šf:�ª*œN§j�Ò<¨æVidT°eY¦íÌó <Ï’b´S]´˜ƒ²‘š$„P¤ +­\ƃ?ÿùÏjeñ ¢Á´ù <ו”1.jõ`xªP9hÏþ–5.ƒ>Ý3—õÚ•%ÆEƒ©� É ÎZ%X¦•ëZü Wæz0hb¹ÐEe×ɘٜßÜ?˜¸hý)õå\'‡¢¯ý�­àšš¹×ÉèÅXŠ‚Är§Î^ž/ gO:µãÐÃ:©0ÖqÏ +˜wßD�Õ|ÎÔgâå5j-iû }8²ªÞ-¼åzQX+ð`J:¸ .q}å5˜Éýƒ°^àÁ)ò÷däêRð{2°vð;Û%Âï‹”,<P:x°Dx=@¹ð<úr™L&ý~ÿ2”D¿ßŸL&qGi<M@“ÁƒÐdæxð›xÖ™X~³fœL&£Ñh 3�²\'S7r{XÉxßDÝ<ÈíêG–ûèñ ¬ xš €&Sœ•çÅÛŸé®>Y>ϧ¾/íAž¿°¾dõà‰E=è„öë:ɶ]¥ǯ§ŽžÕƒÈ`-(Ѓ†ü ÑÓž¯?½4RÇoµ˜&5Jy¥¦;¨!³Ùl<›åãñx6›É·…y°ëx6 eØ Í( h5êäèA÷Ùê�½§»ëI¢ûäuA{ÇUÞNðÞk£5°´€²¹uëÖööö`0P ƒÁöööÑÑ‘,)̃>B‡NW=]è Òô Ygû…Ø=ØkÚÒ…èê¹¢ç9ÿ­l%óA¥n¯�.Á€B˜N§ª +…§Ó©Z§hYžyÐêÁÖÆƒÀƒÐdð 4<M.Äd2�FC¨£Ñˆëdò‚»3jGCî›(îÖ¨#M¸�¾ð @Áƒy�êÌ <PG +ó ûXy§+ߺOœ�{ª¼ò`ú¥�óÉk†‰,ëAžfPÅypÃq¤�\1mĺ)wmîÁðéöéŸQoõ rX1z°Ó tÔuZNGIÖ|eˆt1|ïN�LõŒÖqü·zU㽯¿¸*RŽMM@ó ”×þÎV«ÝKó—Àƒ¹2›ÍÆã±Y>�g³™|[¤w=v…ž|I¹ã£¡ÿä+ßKÆTÏbþðjØà ë8]1óƒƒp–qQ£Îª=x§×–t�I{í olï¸ÊÛ Þ{m´–ÖÏ­[·¶··ƒ�Z8 ¶··�ŽŽdI±ôÄ&s9UUª×¬çõÄTm„3œÙ�– ù£9³Î¢›ƒÝƒ½v -]ˆn¡ž+zžóßÊV2TêöÚéL€Æ3�NU + N§SµNÁŒÊn) +š“¬\Ù‰BûùAm€T¥Ý‹ŒyªoUý…mµR±@€T¡U‚%xP’<.꿲�‹*ft”Ën:»ae}öjÕV4.êº+’*,æA6X¡B«+àAó:™™ãÅ]'£�‹*—¼¨Ãžz²i›¡zuÍÊΆ*T¥(0ÆE­ N¶ý‰\:°0‡ÖIÜGŸ1×ɈQï½:4jN»N&êÁ T® á2€<ÁƒyÁïÉÔ<˜x ŽàÁ¼Àƒuæ¨#x0/x=@íàyô92™Lúýþe¨ý~2™ÄØñ 4<M@“ÁƒÐdðàú1™LF£Ñ¨�‹ÞÁƒ°&HZ%X’ƒ1IýLY4Üí8÷„#¥Ê¨æ�R%Ô«2¶jÏþâÕ9?±42Vsp5\qK>¨­yÉç\çí0. +ë‰P¡U‚%Ý7út‹ÇÈûÔüÉrÿ‚‘ ʉ–ÙÊ×ÊÍ †‚BF†`ÝښŬxärŸÈ’LaÇý)rCõàþN;𜙺—’’ ÀÚpèa�”уÇ+vý2Ø'½¥!Ëgé÷ê·Mè÷M� +@Sh¬#I›ÁBw9.®A~O 4ÖƒÍDÀƒ�DÀƒ�DÀƒ�‚çѨd=¬'“ɤßï_�~¿?™L⎙xš €&ƒ ÉàAh2xšLf¬<°ÞàAh2xš €&ƒ ÉàAh2xš €&³ŒwÏo¶6Ïï®`í¼e¬jÖ®¿œÉƒ®CCížwVc+<«$³k +¦ˆÞTÏbç�V«åtU£ÉבúÑc2@®${0á÷ÙliZ×i9]ñR˜Îó˜_dñ µ¾_Òu¼F>XøÏÑÀš�̓qÝŒ$p�õbr@Ý’Z}׌-iÎh+€¬äîAm\Tz-⬹´;N±!€<È݃Úu2á8§šËîS†H[1õƒËm‚–J+€ÌäîAû}‘"=›“7ǸN¦%͹0F‘À2ð·W;8žKzP_…˜ùÇyÐ>.ªøU Kð @"U¸°´çö*³�?ÏØ+Nõ„Ý8ª—åΨçí´]'ÌR®st+ð À?öÚµ}xãóÃ/îÎç‡_üøã?ûѵ\TxóæÍápøÇ?þñ‹/JØ–\øâ‹/nܸ1Q!Ô<5å[?ï||óÎ�;_úÒ—Êú÷‡üÇ™·>Y~[ö÷÷ÿô§?•­²˜L&ׯ_ÏãÏ PxjJëÕÑç‡_%•Å燷�ýèÚòÛ²··wûöí7$/nß¾=óøó„šÒzuTî1_(¸õêhùmÙÛÛ+w[rdoo/�?/@qàA¨)ÂƒåæƒxÐBíÀƒPSšîïlmíì'—,Ä’Í ð Ô<5%C>¸¿³Õ +ð�ýªzíV«Õî-vØ_½½µ–+‰òBMY4tuð]ç¹ï¤ôÉi((t×°Ý–®Âƒyƒ¡¦,˜öÚ͉ã¿ocjjVíA±‚áúùZT’Z{ÉÎŽÌnÃ4XO}=Ú;²r+L‡#MömubÀƒP;ð Ô”ÅòAKÖÓk·Ú=·|kkñáТòÁ`½¥•¼Õi/‘[äm¦63wr¸½je)FK�Xð Ô<5e±|0Áƒ-‘êd0á�•{0\í@?ꆡÍ/QѧÞ1fX/¶É¼qT<µBMYðü`ò¸h$GJEù`ÄHÚ ÍôL>Ÿhõ`B<k„š²èõ¢s®“Ép¡ŒÇ*=¨ËY˜\Ñ�?9±Dl©nxc\4ê8£ „µBMÉpÿ š^…„˜rLÇÊóÁ¨q<öŒ{?Ì»AÌŒ/¾‰¸N&ê¸H<k „šÂïÉT<µBMièïÉT<µBM9öÚµ*™LÊ–Xܸqc?�?/@qnþ퓟~šCw(Œág7�½víÇÿ¹¬çÑÿðƒÿ8öÚµág9<~]<�þÆ�õÍ +oß¾=™Lx=ÔŽO?oþí“Ç�Ÿø›G{ÿýÊ^€Å~vó[oíµþÇÿiý÷� +Žcßÿç3;ÿ’‹7oÞüÍo~óá‡~PO~õ«_ $µãÒ¥÷ÿæÑÇŽ?qêÔÃ.¼UöêÊ… o�:õðñã'î¹÷¾gžyîêµke¯@A\½zõ™gž»çÞûŽ?qüø‰ÿú¡ï�;WöJÄ÷Î�{ð¯r%x—ëÁ/?ñè£�ïÜ9²BXo®^½ú½sç}ôñ/{™ ëÁ»\~ùø‰<õô3Ïþã… —.]â +RX'>ýtüþûïÿã… O?ó샞R%øÿ–q +endstream +endobj +97 0 obj +<> stream +xœí�MoÜFšÇûø°qâÙd²˜‹c{ŒíDqz-�#ä˜/ÑõiwØžCN‰ù&A{³6 £,�„Ø–µXHR´BC$Jl èŒpœÈ6ä1²Û]äÇõÖ$›/Möÿ‡BB‹UOU=ÿªb±E¿qìÍ7ôáŸÓ¯¿�€Pª��j j „ß¾ý»“§Þ=söý«ç‡†. " ô^ºðaõü™³ïŸ<õîoßþ�*ä'~?<üñ�_,..>|øðg@¯òðáÃÅÅÅ7¾þøÄ‰ßs!Ÿ}oàҥ˛[[yÛˆÀÖÖÖåË:ûÞÍÈ—/ÿ)o£1¹t鲘�‡‡?ÆŒ @qÙÚÚþøÿŸ�ÿr㋼mtÅ_n|qòÔ»wó6ÐwÏœ}»Ö�‡~X=Ÿ·€º�· €€–ènÞ¼élo«ñÎööÍ›7í÷ýÑruzzzii‰ÇLMM-//[nY^^žœœtG{ÕqœI†)Y$¦§§í&Å`aaazzšª#H$ç©©©¨µž��]j355ò–¥¥%a¿€ª#Ý:;;Ë#%´êB‹ÍâXt:¿º¼¼¾.&&''EIuM/àlo·<$(gm¤Š]Ë’K,//[z?”©ŽÓ}'J¤¡eáÜZÇq„çtY\l-Ké÷ðééi~Æù»Ô²ÔËÒ¤²"!EZ&-«Ê )äŽZ–jvvÖÔwaí,‚–Åœ%Æ.q�`qÝh9ÒXÊ휚š¢Ó�™t£å¥¥%)žšTrIÖŸZæú /ä0Zæ#ªðC¾ì—DO ‡áj]XX�–ÓZ-ÏÎΪëXŠ$˜œœ:mÄÕé6äu”�ˆÎF™Hy +cD¤dUYÊ[Cä j155EfP---‰Hº‘ZL´’h +í½ÂZa<$Ù¦[¹ÐDïЩé@ØC½C­:==M‘ÚæU‹VÇ+¾Ìæƒ 5‚êHT–è,jU2†JÑ.¢Ä±(‹ú�¬¢rÔáº*/ä0Zæ“”4žS‹‰v–ÔÊŸï„3KÏËâ*”£[¸“ÌÎÎ’oS$¹“ÈYs¢|È…Ô<…1êbOš’„_QŒv¢Há‡Ü{Å�0Œ7”ö^ò+1&ÐíÒpjï2jsa‰ +蔊ãZ&«hèÉfÛ¨E«ÝÄËÕªƒÊ¥¡IZ9¨í£•?Mú!µL­G²•*Õ?Z¦¶ZXX �’¦'¾‚¢f”ž‰DÇ©ó²$ ÑA|X& k{–ç<Äqîljž¦¿X]¨� z M¦ñD·ªZæO‘–{ÅhÆÛ?ƼLû¼ ~ÚQËb^°´•VË–ýñ„ PŸ,ZÖ[˦{�ôö¾hé«úžxÈ2iYZc‹cÕ%¤5¶8–Þ¡¨gùªUZcKs“䥦g ÒŽXšÒí´Bãwd�IËô|Á×�ï¥Hi�iŸGtoþœÒQËËË˼ÑìÍK%ZvGÅøÀ×ö-2jÞ†êUºD^Až©Õ2/·×֨齓"¸;ÑâPlS˜´,-�Ô«mMðK|I,u·�ï}ñu � Ú�+Ú@Ój™WGÝ¡E‹Él˼ÌÛ�ï}Ùï¥í2¾÷õ� (¤q/¤–©wø~£©yí“25�¡ UG¢¢E ÷%Ѫ–¥v6i™—Ûk{_éýV¤oéÍבÞ/gO®W;byE^8 e-ÚE~¾Dú݃´n):Ð2è7Ôåz9€–(Ð2åZ @Ë”h€r-P eÊ´ @9úã@ñ„–(Ð2å Zn6›ëëë úžõõõf³ùDG!´¼¾¾~ppð +€¾çàà`}}]+“Bh¹ÑhäÝ„ô +�FC+h€b-PR×òêØÀÀØj7 Ì@Ë‘´ì‹nul B'3µJmÆ$ÉÂhÙ™¨V*õùä2y3_¯TªNÞfdE$-·4Kú`'f1f­åù:õ^[�/΋Rz¸uÁ2»¯��Ÿ·° +ÞOLe´\*x££Í!Gt&ª~¦í“ù(µ#ûeËìÍ»ºn€ùzÿ¨9’–g<1ÏÔj335W‚â@H²ýß±šÛ­Ä$Õ™ZELå­9]à�Š�¹>Ž–]`òÅëQò8Ùý.oe½½>áüßKêfÉ ß +7† ÜÙì$aŠÃµ{¥iäÍ®ÔWÓ&z h}‹/^ìîîªñ»»»/^¼ ÓHZöd·:V5ì œ´\ñ&ï™ZÅSw;Þ¼ë\þ‰hù•<ï(±ž„åT¾Ïè¼'ž–ÝCräWžˆYL‡œƒ—[gõzULf®€\ehã;f*Z#¢–õfÛš]­¯Ú&†¼¤lcµ@ŒúõÏŸ?]YYá‘+++£££Ïž=£˜h{_«c­…µøoðDæ“€º+\¿��ùA;A-û‘ú5vàºövÍ*”V‰¦x‘ßÖx²¹.´b Ç@‘·)Þ”­W¦ûÿhµ34²­Ùµ£™Ô&ª‰º5v¼°¶qQxúô)—³òÓ§OyšˆûØíYµµÂº¬�­zKm‹–ÆfhZV•›º–;/ÔtZfª�2²{ŽÃvÒb ÎË6?SÌ&3¤S|�‰ªgi*ó2Ù¯«¯Ü&û4»‘ñZ s’³VÈ1ÞIÍÔjµš«½™Zk LœXµ¼ê­¸Åc³7IµœÊ;Ô—ñ ÍöD©›¹Ô�%�ì±­KýnµÜ^\Ï»R6$îr^6Ì‹aKÆk�RÌË!g­�ch9 8þtÜIËþæ_f§ú¼ÜƲÁ\/pSäÝ¡–\Ç‘7]üŒ5{_ò6º®¼8žlÈ«­TßÎdçe¥Ló^Kê_3·a,-—eZv9h£½T¦ß}ñ…›XDòy¥ÃLؼVÞI…÷õ}Š7ű<”72Ìi�fÇñdÓ²$üþ›¹~ºgC³+õUÛDÿR°û§Œ2ìc‡¤LZî†rvy‰–—1ÁûåþÓ²f§¥øxÛ[ý +~÷Õ¦ÿ´ @±�–(…Ö2¾+€ èßi6›÷ïß_ ï¹ÿ~¡¿÷è´ @9€–(Ð2åZ @Ë”ƒžÐòêÕ>¸ïO›c2ã~Þ(ðW™Z„mi[˜@þ«W?SŸnK¨¤Ô­ÉØ ÊF -3¯ ç‚–TI+E¸›ÀœåL-¼ÛDµ0^]ºn�VÅS²°±V“íìØ¹á ˆÒ-@%†–ý +ÙY“%¤å–?óq¦fö±ð~_ -g!ƒ™ÚWg¢Ø¹R He&†–ý.jõîê“ÀtØŽh§¸ZkØà5]ÊUU/,æ*ÿÚ§mê5ø³T"-¯Û3~fl€2Y¨ÉÍ\½öæ5‚æFnIíª—?-5�Mª{4 ªÔà}>ÑÏÊ;%Ã:´0oOñut%½±§:÷»Z�ì¶Ê„IË;:Ükž�ÈÿçäþÆÅ¯¦´k™í³u•}zHêx½(%šRº ­êkJúJ!Õ{©U3‚s�œ›µI•A‹Wȿӯ‘÷ 6‘=ÏJßÂJ‹Qnjz‹yö~×V‡%49!ð•Ä¢em|°_¥ØeM*3¥´ÎËb4íãùL DéFi–ïh¡œ›˜[™ÿiGŒ0MÄó±§WÆ¢@„?²u…Ÿ­9+cY®¦ÑæÙ±ßM6˜=X´KËÞ£ ÷öýË„UË| —s NW–çÜ€�ŸýÃ[(µ‡:PØ]T×D34-ÛÓ۵쎱ÞóO -kêèÅÆÖrÈêçe %Y- çe Hé“›ê¤CKG]Je½êŠLÓãL°:—V”®”hð1ï^«…º«5ɪ…xù�W¥ ?ý|ðÕªþ#Ø%Öòƒ•Fî-�€�xx°¢ÿÇ) e„bh¡¡Gµ¼:600–Ò/z e„R† ´<üídë—wu𣖷&ªÕ‰­� )qFÁoÿkÑy›QÒ íñ¹Ö¿æ<¾•³mYhy V#e¶D:ÐY§jy«åú.ÕqÇ(Om|–ZWV«:õù‰¥º¾PŸóÏ�D­i‚6°ÈVš\lðRJ \{æê•¼GõL´<6ãI³õ›û1ïdul@ú“?¦=wsE{Ç~?“h²çZnu¢ßÎx}b«Øóòüˆ˜ B¾î®«§ å°6ÌÕGæ‚ÌÞ†v˜«·KרÓZy‘ ‡gÏ_ìììªñ;;»Ïž¿ Ól´ì~JèÑU%ûƒ÷±é3SO)ƒ1òDzºÒ²Æ1¨ý±WRÇüˆ7ÞŒŒ·"ÇëÞéœHV©ŠSg¼êůP©ž¦]VàTc˜¢/š:û°N–»bŒZ‰Û ´VMVË‘l˜ ¬Uö¸SvÒB~ù�WÏž�ŽŽ./¯ðÈåå•ÑÑÑ_že®eöM­NIé’råyYùXVt¸–ÍËfÖk"Æ�¿mY¹§BG­wè®Ð�ª¸Öó¬®/f®^ŸSO]ü—óÝ©£›Lkl}†þ°ú–.lÐß’¡ nÇnW¯&žüô”ËYùÉOOyšÌ´L³owZt¥h�–Ý ÔŸþÔÞ (ZוRíŸO5#Ü’\1xª�Œ–•º‡÷y{H܆¨ ì¤m˜«K«è =)?p‘œµBÎTË„m�í&uÎlEM15¶‰æ=?'´ÆæbQû¥K-Ó|mÊ*à!:E‹ô|–ïFËZ?Œ¬åîæÄh6˜„œ™ Òò^±'Íy™ËY+ä\µ¬Ûûò¾B;ߔċñ¿”}L-ö=ýÈ–²¯PÖØáµì¥ô +Õ1â>pµÝfN>õ Ž ¼C#üÞý´ @9€–(Ð2åZÅe¤/1µ´ Š‹Å±Ë +´ J ´Ì�–Aq�–9Ð2(.Ð2ZæÜºu+³»@÷(ŽýõÔ¦¾Î˦”É@Ë!ýùC:å9ä¢Q诿þû^�1’c=åjxûo.«šchùüàP¤ô·nÝê¨ !îâ�Àãiªº)4ƒAбIÊm1ÿùoÛy™•&½ eí¬gºK¯�¸¥9�¦{u  M¯5O]9¨÷ª™H6€ 0j9p\*zDËZyš§ML‘â˜Oô’ĤIŸkœÇX2çùÓíÚx)ÌÑ™-s²×²4»ýÄž›$I­º)íU/BM¬˜âÕ ålÀ›“˼Lºˆ´Æ¶hJ½d¹Êіؽ–A6`ï‹“ýÞOUËêƒm -«Æ$«eêÚX}FVSjWøêFœš8¤–M# HüV„“”–¥—Mc¤dÚÄö|¤x)1¿ª=6e®}à•Lñ’~¡ål€–9 j™sK!´±yÒÍï¾ ßì�–9)iYš!oÌ—xv¥v%Z椧eÒZæ@Ë ¸@Ëhh™-ƒâ2Ò—˜ZZ @Ë”h€r-P eÊA -z“HZ h€r-P eÊ´ @9€–(Ð2åZ¶Ðxôxðúö‘+•O׳Ÿüu·ñèqRuÙßßßÜÜl4k…Åqœýýý¤¤|@Ë&�¹²ñùݽÇ/_eÎプã~<òùF"rÞßßo4ßÿýË—9Ô%^¾|¹··×h4 gв‰OþswâÁ~¾üÙ�¿^OàŸepç‡~È·.‰Ðl6777“èÞ-›¨|ºžËŒÌy|pxäó�îë²¶¶vxx˜o]áðð°Ñh$ѽ%Z6Qùt=oÏmQùt½ûº¬­­å]�ÄX[[K¢{K´lZîM eв‰>Õ²3Q­N8ö˜Hty»´lZ6CËÎDµâáú/÷äùz¥R©ÏGË3}-·­&#¡åÂ-›ˆªå–$|§mé¶uFž¼žÔµÜ²°^'½AË…Z6QËóuIªÂ‡]OV®†&m- }û\i³Å…>fb‚Vþr$¸iSŸ ÄY"ÝâèÒ€–M@Ë&¢iY3ûÌ×+õùV|µ}iM¤¬eÏn3[?¸‡úªQ»š�ÌZ—ýúòÄn)Ê-š4F eв‰Ä´\SNL5§«eßlOB¼"B”�c8Á«¯” =åoé´&‡–M@Ë&]cKsURÕ²¤ªÀ~x-ÛŸ¯µZ¶Ü-ÇZ6‘ðÞWÜͯ4µ`ÄhĤä^¶ÆˆšG)e�-ëT¹ZNhÙD—ï¤üMUàQHQ˲jÚbžWÞ«©oÚÔ™×|‹Øû’u*Ý-'´l¢O+Òó@Ë& eÐro-›€–M¹²Ñ '•ˆ–�FiþN +Z6-›¼¾ýÙ�½|]wüþ�Ÿüu·ûºlnn6›Í|ë’{{{Žã$ѽ%äüàÐÎnÞR>�ö�\Ùðc^ßùìÎß�\ÙhóÞÑ£ÇZZnËùøñ“>¾víú—_ÞÞÙÁÎ6½ËÎÎîíÛw®]»~á£áãÇOúBnkùµ£ÇÞ|ëíwNœúÃé³çÎUÏŸŠþõü ‚=t#±sçª8}ö�§Þ|ëí׎ó´ü.çvxïùáŸR ¯# ”+$/.À<Û‚e“òoþ]O4ì +endstream +endobj +98 0 obj +<> stream +xœÕ[[‹%·~?¿¢ŸÖJ%U©Æ0sf� Ä' És6¶s±½xcÿÿPº–Ô}ú̆˜/ÞíQ·JuÓ÷I%�Ÿò›Ýìö™Q?rp&¹”x{ÿÃå§‹shps7´ÆæÍƒ#C)Áöñ›ËŸ~³ýxùéâ�ÌòÊSëù€G2€"ЄÄÛøë_nKËÇï.o¾d¿}÷¯Ë›çï?¼ÿç׿|øù›íóÏß|uýíËf·/¾x~¹^·è=nDi#-¾½ØÍ„Èa3Y®ú©È "³õCÕKþäò'›‡ûÕõòæ÷~üãÏyÿs×ÀU žß]ÞÜÂæÂöîÛ‹+~tØ-Ðöî‡ËçÖZØÚpµ­µÖ[ëé‹íÝ?.ÁrÑ1ov{÷×ísk1Z‚µè¬ í˳“¾1w$k$ÒEº/Òñ©ŽV;æ¶d-Bi“Ÿ³påg´©*ÁE y±ÈeÂ­È O‹œ,p£‡°· ˳(‹u�ð¶´‰ûl­¶Ö�µþj­½Ö�žê@¾*CªßM)s-ßee^Š×àÙÚ(íÏã]î Åùÿæ(Rã4ï‡ñ>?ËûbèÛwgI¸&Áêî{. ©&Ëm„N:AK W¾a7<VëÐZ×B§’/ÿÌ#­ Àöœ ä¨ä…›Òåªú¼ψ\×T‡bGñXë:Òì$…GãB +î“Shx”Ûy ƒþyî„êÌ›òŠ0G[Ãì©&æsMœk•z–¤ÅÜHÀFëïš»‹³WÀâgoP1�™¡Íl1<Ê?ñb3¤ç.×oëlÈ9ÜÞÛ1Æ:q;I®5WßA]Ш‹p +ï\ƒÝoõQ«¦¤³óèÎZƒ–#§‡ð¤0¹Â^ËõlïÛÞ;ZÃÁ2Œ¾<ò½ûõmþÖ“áäqFW 5äý¤IT3/GµH +Æ +¤iØ>�ûtkœœ,ùùc«Ð·u.ЛàÈ:š;` ^sL“ÆSrjÒŽ4/‘—gw«¸\³ÖƒŽÃ¡``„Ov’�²äëƒüñçù$PçOó5>5?±ŽØÃé‚!9“8øˆZW§�šñ",�¾¢<�éIךr·1ótk2*‰vÙm,Thª¡ûí 9½_šå÷Ð,“0÷i�~ve¼äƒ)ö¤¦Ír5Žt½—@Iˆ+ œ£|N�èkdò¨§){�œ¸líÙ"Ç€QÀ±~ÆÌî¹ ‚EÚE'‡'¥ï²Æc7ÛsÈT¾Ìq SMLc«�5-?a“×~:=në7¯W¶özÚ'gæ,Ü*>ƒ2;œ¬W&À:Õë³ñ1&?c½›gdVªb¤¾—57ƒ&.¨CÆ‹ –w¼|Û®¸elBq ~Í œÐvx§‡­ùbGnì ¶4)yGz…W› P°ÄCº;/*™²q>ZŸ@­ž +{ ‚S´q­v$ +˜’ê˜\Ôlzp®ƒ#Y"Þõ¸z¼” 1´Ue¡ç %ð <óÏmÆÆG“ Õ²<\_‡ûë NÂyɆd5»,š}Ra_à=‹^*sß­Õà�ëãý;ºGÜR³úþ¬`»Ž€l¼”FÔ0²»ÊDQÝ­×FP7îʃDÆ…€ÞÍ Cåâd)àÉ+–W"¤~ÝGzÄÀ ìöK/.ÄÝ8¯¹ÛÆ€Õ²àöñœ“¡O+Yíö¥­tÙö–ÚÀ`Ùäy‡Äzk$µa=ºDîÔq›7¿­VÔ,kï�6˜­büÉÛ�uköšòw¨rÔ¦[/ÓÅÞe™>±Œ×,CqÇ2÷,C¼gâ#–!Þ³ ¥=ËP:`J{–¡dˆMxAIÔp ËPÚ³Œ´)–‰va™þ^Á[—£€0�8³LWL�j7@Á¯²tàtw‰‚óîºûÊÅŠz0à h¾ufŠb3N4C$6;=™ŠßZ-Ú± áže�X†paÂ=˱ áŽe¨’pa‰eZg�4c�^¸#™®³NW<"™î=hO2Ù¯;’éþ�qâÇ3– ¯`™^DúõXfœPÕwT0,³;»yÄk aað¦V.‡i�!Ö]b5Ù³A°h_wêÙ�MÂ1b÷íÙm_¥ß!z+û©ÃÐÎ:/jïÙŽpZ¿…=Î=zŽø¤ŸÓñ9í?Ù=â'{„øÉî?¹=â''ÏnFüä0'ÀOnøÉm+¤†íiÂ{iRxŸ`Áûþ^M£)�W¦WWK¡[Ó^Á ²ràew‡‚Õî¶Ž¾Ê½ +¥{ à `¾tF{NÆQœÑžY–´í™ ·n*˜ x î9 +ÌùÉNŽˆa�{l!pÏÑx‡ir®²îážãî9¶8r\à^^©Lh�UʨQTru}F +v�U®*ëTVw?¨ìïîRóD9Vͨ€x(�<ƒûø +¸ïEè{ïÛƒè ¡Õõ±ÿÙö€ÏÁß‘a”e¾24¯(“¹ô  +)ŸŠñ§ºñ¿Ê`O]à£3å�Rò×á¿ÆO±î@TtwBà%‘�´\QÈG„OêÀéàBâùè"„¤;¹¨.=Å벧ӥ .FèÛ=mï´ž…¢¹ˆmÄÂö3°:à´Ëªàœ�Á)6&ïW6–¦•�ɇ|/E£Œ´DšÙXZ³On‘G¡Ð'm;6–Æ…�¥ieciÛ³±´.lœ›“§™�ÇûÁ]Ì Œ2ÞÄÆC­A>]ûÁRÚÊNgÃõ†Û;j÷�€ƒ€ùЉ�¥i©ð‘‡¥Â'-û +Ÿ´‚/­®½Û‘±´íÉXZ§½—4¬{/iÛ“±´.dLÞõ0º™Œó+�n%c=ŠÎ-·î½†Î:UÝ?èäoîÒÓö^#q'a<ábxp5(ƒ“Oýˆó|ù>_f{DþüÔDÜä0Ÿš( Z -ÍGÇGôµ»wg£²ÞŸè%)T2õ©K99çŒßŸEõq«Å�]nóã”eÜã;ÿþ¨w÷^d½Д–4„@j¤ÏÓa®J>.Ò½‚Ú¨Õ?sÙ2¼Ž~z™òˆ›[S]ØE8_< ÊqPG{;ξ0í¥egƒê÷¢|UÕ¶:t:“kYõ´dJõŸ>¦móå(Q^KÎR¨äüµ\4çˆÕë6ß7ç|‹\hÃÈ«÷?<¸ª}ûûw¿|7Å¡•dÞü9Ñöò!òª;êŸz#Îë$vckS_$?B:?D¦^wQR[œB�}»Äy|äyGrVÔ÷³�~S#ÎGöª*åÀ`tÀúíµ_§pV"—"©k©Ì†ÖŸ ’Ó¯;Ï~\Ÿ_�ŠaMÁ„åžÇ‹º4O9jÅàâ.Ì�-M½¯™ôÉiGšÆ_7MÏwt>„�Aî?JÓtž¦^È¿¤é�úº4�À1Æÿ÷Ä›²Špç�gË8KÏîh´Hj3Ö~Qá +%_ÄåØIfx´9CîÿbŽ<=ÊŸTÚÒ²ã5‘3(÷ßmh÷ÀC¹¦˜a~¦ÔUH”àä¼èRœüÖ‚¯ÿ¦ºÓ µÍÖÓ©TÏdòýçl?­|>ï"ÕÀÈÎë>ûÆ�¾l0‰z¼¬²ŽÌ¿>sê; +endstream +endobj +100 0 obj +<> stream +xœÅ[ÙŠ%Ç}¿_QÏåDDfäÃÀ]º…d�Ý �m�A2#Ëÿo2+—ȬõöŒ¬†ænU¹ÄzâD–"ÒßLß(ñÑTCðÓ�?_>_YYâ OD +Œ÷“&´Ê†@Ó¯ÿ¸üð§é—Ëç‹VHœÆ›ß•;¿!fÇq4H¿þõÛi~óëO—ßêé§ÿ\>üåß¿üí·_ÿûãoÓÇ�¾»ÿù1ÁôéÓíq¿ÜÞ.^™&4ÓÛ?/8¯'‚ÉÛéíçËG}0wã@þ4½ý뢽òš&˜Þþ>}0€½¸.ÞcÌ-öówŒóûø¿×€B»§|¿¸òõ:Ïòü�çßâKºÇÍŸéšÇ 6®ç5ÿÇ{ì|çý+£-‹ ù¼�—t¡ +D~¸ ®ÖÌ#ÇQÓ*óŠãç"…:s™=ßo®Di’—·ËËw÷5�á �÷èŒy'Ydòõ!KåVeŒ”DW E°:!— ôJK×@þwóà”öÚù°ª º¸{VDÞ.Üòr¹ÍPÌ'ͤ³ÒLþî÷Ê¢ceiýG(k4Së…l³’¬Qd;ßf¾æÙ…¦’ÚóÊ;#3Ï×Ì£¢W`µq®÷¯{¾2Ì>FÊ[Kˆ½ +ó´"r¬Cûµ›8‹Ð¸¶ˆÎ^êH�x¹C/vⳌ°YI±Ólk6(βýÒu¾öj,ª]3Öê*®ßžuq(Ö¥Óå^¡'‹®™S^×]¸ åÝ0~¾ç×dü†¯� ßüŸ ?}”bÑ ¢r`�¹�ì:Í*Ç~A¸tihé7bZ�KB£Lt¨fm,6TÓ�ÒdÃfh|Úá@iM qÕá¶²hZük¶¾–üÂvò{ÍSÏÓj£\0�†4úº´ñQY¯´ Þë¥_¢ˆ@½ÒöÁek‹Á|Ïæ‹%æa*mA‹PQÈk9Ìæ„SXú��")Ýα &J뤭5„ ‚5ÞhÿZƒ_é³ï €Cåƒféƒ]䄞@¯¦ðuø¦€'‘jRAûE*: õnM²9«Ðu.~¼«m³^ÇU}ªžßÇ×äGií+1cN«H&ä>øãÿñ&f³ìÈ(ô†�ØQЇ^PT“¦Œ1³8…Î9mÚØ/¿ tè],½ËL„‹=0•dˆ‹5•šå?BÎÑÂt†œaTÒA†$ÃÑÆBm¿P´JÇ¡Á/lm]pÎÞžŒ1®á œ•§š¥¢Ù¸f `”ñ-6ÉëÇâ•ÖPø=ûüYÖ[gæp­‚±`ŒH—erMÞ;8Šá@�‚?ñ‹ñy0¶`­HÊÙpŸY׿P³|Y±qdPûY(N@ËOekUæš°:8A^7t¸©*2%F3û ¦à2igÛõæ¶±&{ßRÔÓ»0÷¼‹` ‡p掗Iµh]MÞœ˜cSçŒG{|RAdM]¤îZ²ë^ÀΜ®¢2ëjuAï®ÈŸ�à–<:õÉ¡¾ÐºUhi;˜ºcLe�s%™nCN™×Îk¨Ï†©•6Ú‰» Ð1_oœrä…$¨Ë DÊêž™pp=ƒ¡`—FÂ0÷‚eæiQ‘`°’óCZœ©ÜßWÏ‘C½rxÆ 0k *¢âX�4éþ‚¦áøŒ—L»¯–n¾=Z}§¥Eõ#¶4"�6‹1±À4`¹óØŒÍÜrç_Ê£ƒrëZµ^ ¹4ó5cåÌMò°j½¶²\EÁºN@m]ï ®éhÁ3”š–›zOò‰#“ZYT+îÁ~Ɇ^ļ‚«ãÛ†³Óx$hÇ‚Z íxmö’^«Þœ.:�#¢UÝT©Y­7òœŸv¨ã¾?�Š›X®"ÇB§ìJ�™e}4-în ë]7­«ˆÊ¢!ID¶¸ºB·¢eë$“Ë5…dá“›×§ˆâú²¤XÜÚèÒš[ùÞG¬suª¬Hç÷‘�Ë+'J’„Ýù¦ìZ¦_}Y)�ûF‘e¨Ê!0�“°tÓãpã¨$‘ª¨²-äŒv²²é#Tç÷cïÀ4J«Û_Ú {¸öN$›S�O´\-ÿè.ãä¬}§¼ÕäZïu�$ri¼ç‘gç’‰ô�¡²ëË*çܲJ[Ôzi¿ ‘U çž§pýJ?€c\¸.ö.—¯6¨¬ó—¦"Ë�Ü) ¤f¸è¤\ƒ4�0³è2 ¨b·yÕ³�÷,|,¶Ô ïqœõ•ÜÒ¹7¥=Z#|[ îš]C0g» #BÏt2rô0v"$U¼wÒŠŠ“ @¬VÎxðõ½Yi% E'£(¤r£‹ÕÅZE6� ®ôs­ö$„“HCDQ>‘X=céh ~×Uà +É<ÃTú¥dâ*ê~´.¾y}ÂäyÆ,§ÆÚÊ%<ì¥|~´D^¤^;©×aß‹¸Ìuc뢎ñX…ãoŽ£¶¯­ÿœaT°±#C+ [”X;¢:*^×Ò¸ÉNZ£Q'º£mòŽ1F&pß¶[Ûl9¸4sßšeä̇IœSdÙj9IÙn�AضZ|7jÛÞš/–3zÑ×@ëTl[­ �³i�ÊáaâœÂø /JAûu³þ8еl¹Q†ç4"ömª¯AÛ”€´G×,Õ}(�èØaOP‰�ë™…Ò•kpT£ƒAòØnÙÏZ d¡!r­ÐZ@»Ç›Ó>«ØÕ+½ ®Æ­‚å/ÅòñÐUHÜÁïæå¡‹­âPžìqÊS@X‰¤Òc^ŸoŒn|º+NKÍÏ­ì#Ë<¦jC€S¬ÑÑLaß,«¤?1ß ~H° �6›%«À„Æ/äUš ¼e-b‰šÊa›l‡Æ*íÑká>AúßÁþ ö%MV Ûï:ô…¤xˆÝ»f×5i²Ã¯¯!ß2g‹G;¡§È.‡Ædæ×%"mŒó‘Ȥ²7‰UÔRj…«k`žÕäÖ�‡;>ž˹™s|¶ÙhÍéˆÜ*wvKû\&€r>šˆX,9­SçUÕ$²«€éc9–ÔŽšFÀñ8Î .ð/¬Ð‹P+ÙÁ8]‹ºìåºjÎ�¥yîWu\>Ä,teÑMŽ+Pp-s‘h1ÍÊ¿¬î]…Æ£]cV·h_µ+ÁC·ÞÛ§L ýy¬iŠc²l¾ ø|°Êæ”ÕØfÓqàüÞJß +ô妥•…®A §Š|ìO“wÅ‚ Wª¶$�BC/'ËO:$ „¡('›ŠJž¡D6�f°«Ѻ÷ˆG±é ©t$–¬³›¤ß™ÒgQú¾î8Ö{2ën½d\eq’ƹ­lM@Åù|oÊÇ&q|þ4 Ö¸2‹8w†²õQz4'ïš!ƒâ(ÅÄ%…½á|A¡Ù9ÀÅBÏs†£�­êø‰ôâ¡•Í 6þr�Ÿ¢êz*$dèïÁFˆwÐG,~ÆdOŸ• èÜûÏJò³g%©l=ÝsìÏŠÚ:·}¦mó å98 “§‡¶'÷Á+:¦KB¸×+qr¾´d©™ÿòe4… +endstream +endobj +102 0 obj +<> stream +xœåZY�ÜÈ ~ï_¡ç[C²È:ÃÀtO÷"ÀÉùÞØ�×°ãýÿA]*–Fju{o€x0n�ÔE²x|ÿñþË,V ŽÏ‡‡ OÈÓóÏ,zĉ`ŠÜôüáðÀAñœ®ìÛéù×Ãùy‹i–$›Ô«ØÐ €.Ö%ò„åÚ>Hbí2[‡†¬³&˜žœÞ0ù$}„Ø—E|Y!èØÕuX~ûÞÊ5Ÿêý˜™¢°±Š{®™zú}¬«qG+öªÚ-‚ña¡¬“¥Í÷¸IØŸ%YĈ­*K÷ÎE;ygÜT �îÀÇ¢%�ö¼¶® éZZò‹5O…欽Ås:W>§ªýsÓ×¶ZUKnöQÙè\¹V[g�´]úò™ÿ®>ÒèàžÅX[LhUBŽ-RªD‰z“"`÷�|¯íý¸âizwMb[½Œ… ‘GŸ—æûù[ä ØÁCiݧ‰vö-»aC| @¸¢³ùö¡Ôh(n¡þò” ;ŒÈ¸àמ"¹(wÍR¡Æã%zç¾iüu¤!4­ôûÿŽ4Œøg"M-FøR@‘fª ÌUU•þ\S'éè¼³4Ï/fÜ,.\É›H'\^ +i0 &3ûîÈU Ö‡(@ýo¬¨H†£ÃŽö)?ˆÆZhƒ +–ú€ƒS!ÛÐÁDvÀU´Væ–Bðäû +(!ÌbŒà O¸í]8:—´÷ȵIª@‹aOŒ]�R”â :ñxƒR¶¤ªŽ�³Ñ‹tpٰᦩˆ+Š‘ i,Èz§RÛqC&wÚ2ÔÝ»àSÝEt,1Þ²â\™£õ`#­›)ð <6íw›óØ€wZ#b'e›Ö}DGn= +Äó ÊõJU¼nVíþîBä néc0Ÿ&õʤڱÒ6˜"씩R¨%ÏPŒÅä˜v‹<ÖXNY½»ÙFN(ßgo<A¥ +jÅI©'É8ký`(%Q¯q,`ŠNCWM;)/žZ~,lS-ÁÙñ˰§ºý¦5^ÕÜ«³b]÷Ø ‘eY�×\ÊÖZ) Ò‹’¼ÞvúsIpR4Eò¡ËÖtÜJˆD#×§R®ý\بÖB{K+Ž”×$þ¸(iæµ ¹¯5ÈHº>^6"‹êöÔK£¡�“ý‚L¢½;'µfË:3�Ey:v2v�ÇEíHi²¢+ù4er!Œ±å»š²p¤jÚVeJwÓÙ ”@ÙíΊFTõvuwrU`©ê×&YT¬³«\z�Ñ”x¤®ÌÙÍ›ëˆRöyá~aß¼[9[áÈïã"ŽÖ�g dž”ˆ±u|C\Û°u¤ Ÿ}w js¹Ú®W¥&#Ì’j…²ò2yÙ¨ØRúZãI$Ð=»«ô-·+„|Ryä0Út9¥¯äû³9kŒÍ»s+ƒ‹Š~³ÛèXÓ×wD¼³¾Íž:ÕÆ5[ZÙf·¥BÚÍÎÛEÆH[~áØÛXmI|R-³ò†[²KÖiEó<�¨FÖúž'Wà@ÛrÖ”T<{Të á“jÍ¡;Tƒ nþâTÈ/qs¹ßÀÁ`¶w°î÷g�_1yßÌ ÎE¥9ÖTAÝ|k­>mß)3 …£JØç:£Cã¼øðrÐ3ïë¬ ¦–tÞtا[I6盃¬¢A©\1ˆ‘‚0oÎpçÛ ÔâÑw웽ñI]k5KÚ´dÆÅ:DjÐø9óبÃö1ÀîÜÞ¶i» ÚKi‹&DÇAµ7�ãl™#R„IË':*�BãÅXŽ–�pVõWð¢sXvÁK©Ròó²˜eîÓE"ŒqhjwvcgyPßzHvÎGåx±8yòiÏh;cwNFó-WÐQ!ãcëGÈÿ4ÏZ®ð¾>úŽhbÈM–’`Î+`ò¢Üj;Ö*þ¸ƒªKȺ^«H;Dh@jÑš0âºåW¼§AÒ¢[º‡Öu©9F;ÃF§ðm®C~ö‰Ø†Ù|\Ï–Ë"wzŸº¥fÍ´®�áÅ1ÎÐ׬¥Y¿_ÓY2ž"/Ê]ì„¥ªr¨öÕwxC¸¥ùæÔ~Û›¹²Çn.±/³0/èÍå€2rG�[[Aý:ðv7Ïžƒ�_?{–{gÏkÇ£Eǯ³nM·g„›31ª<$¢ú¨Mæ_?Èòûy5Ìùß8Õ‡WG6´R Þ8îÑå7݈’É +¸ô¹ýú^ºzÿáúëqÙ4nŠc¨ûú*ͯµ(áU¹kÒ%� /f*˜æç¶~Æ ÈõÔÏx•ª ÖH~›¡yN!q}Y´&Í&¬^—�44®®ehï‹lòLÖùÈhž( +endstream +endobj +2 0 obj +<> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Annots [7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R 16 0 R 17 0 R 18 0 R 19 0 R 20 0 R 21 0 R 22 0 R 23 0 R 24 0 R 25 0 R 26 0 R 27 0 R 28 0 R 29 0 R 30 0 R 31 0 R 32 0 R 33 0 R 34 0 R 35 0 R 36 0 R 37 0 R 38 0 R 39 0 R 40 0 R 41 0 R 42 0 R 43 0 R 44 0 R 45 0 R 46 0 R 47 0 R 48 0 R 49 0 R] +/Contents 50 0 R +/StructParents 0 +/Tabs /S +/Parent 103 0 R>> +endobj +51 0 obj +<> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Annots [53 0 R 54 0 R 55 0 R 56 0 R 57 0 R 58 0 R 59 0 R 60 0 R 61 0 R 62 0 R 63 0 R 64 0 R 65 0 R 66 0 R 67 0 R 68 0 R 69 0 R 70 0 R 71 0 R 72 0 R 73 0 R 74 0 R 75 0 R] +/Contents 76 0 R +/StructParents 44 +/Tabs /S +/Parent 103 0 R>> +endobj +77 0 obj +<> +/XObject <> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Contents 81 0 R +/StructParents 68 +/Tabs /S +/Parent 103 0 R>> +endobj +82 0 obj +<> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Contents 85 0 R +/StructParents 69 +/Tabs /S +/Parent 103 0 R>> +endobj +86 0 obj +<> +/XObject <> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Contents 88 0 R +/StructParents 70 +/Tabs /S +/Parent 103 0 R>> +endobj +89 0 obj +<> +/XObject <> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Contents 91 0 R +/StructParents 71 +/Tabs /S +/Parent 103 0 R>> +endobj +92 0 obj +<> +/XObject <> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Contents 94 0 R +/StructParents 72 +/Tabs /S +/Parent 103 0 R>> +endobj +95 0 obj +<> +/XObject <> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Contents 98 0 R +/StructParents 73 +/Tabs /S +/Parent 103 0 R>> +endobj +99 0 obj +<> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Contents 100 0 R +/StructParents 74 +/Tabs /S +/Parent 104 0 R>> +endobj +101 0 obj +<> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Contents 102 0 R +/StructParents 75 +/Tabs /S +/Parent 104 0 R>> +endobj +103 0 obj +<> +endobj +104 0 obj +<> +endobj +105 0 obj +<> +endobj +106 0 obj +<> +endobj +110 0 obj +<> +endobj +109 0 obj +<> +endobj +113 0 obj +<> +endobj +115 0 obj +<> +endobj +114 0 obj +<>]>> +endobj +118 0 obj +<> +endobj +120 0 obj +<> +endobj +119 0 obj +<>]>> +endobj +123 0 obj +<> +endobj +125 0 obj +<> +endobj +124 0 obj +<>]>> +endobj +122 0 obj +<> +endobj +127 0 obj +<> +endobj +129 0 obj +<> +endobj +128 0 obj +<>]>> +endobj +126 0 obj +<> +endobj +131 0 obj +<> +endobj +133 0 obj +<> +endobj +132 0 obj +<>]>> +endobj +130 0 obj +<> +endobj +135 0 obj +<> +endobj +137 0 obj +<> +endobj +136 0 obj +<>]>> +endobj +134 0 obj +<> +endobj +121 0 obj +<>]>> +endobj +117 0 obj +<> +endobj +139 0 obj +<> +endobj +141 0 obj +<> +endobj +140 0 obj +<>]>> +endobj +144 0 obj +<> +endobj +146 0 obj +<> +endobj +145 0 obj +<>]>> +endobj +149 0 obj +<> +endobj +151 0 obj +<> +endobj +150 0 obj +<>]>> +endobj +148 0 obj +<> +endobj +153 0 obj +<> +endobj +155 0 obj +<> +endobj +154 0 obj +<>]>> +endobj +152 0 obj +<> +endobj +157 0 obj +<> +endobj +159 0 obj +<> +endobj +158 0 obj +<>]>> +endobj +156 0 obj +<> +endobj +147 0 obj +<>]>> +endobj +143 0 obj +<> +endobj +161 0 obj +<> +endobj +163 0 obj +<> +endobj +162 0 obj +<>]>> +endobj +166 0 obj +<> +endobj +168 0 obj +<> +endobj +167 0 obj +<>]>> +endobj +165 0 obj +<> +endobj +170 0 obj +<> +endobj +172 0 obj +<> +endobj +171 0 obj +<>]>> +endobj +169 0 obj +<> +endobj +174 0 obj +<> +endobj +176 0 obj +<> +endobj +175 0 obj +<>]>> +endobj +173 0 obj +<> +endobj +178 0 obj +<> +endobj +180 0 obj +<> +endobj +179 0 obj +<>]>> +endobj +177 0 obj +<> +endobj +164 0 obj +<>]>> +endobj +160 0 obj +<> +endobj +142 0 obj +<>]>> +endobj +138 0 obj +<> +endobj +182 0 obj +<> +endobj +184 0 obj +<> +endobj +183 0 obj +<>]>> +endobj +187 0 obj +<> +endobj +189 0 obj +<> +endobj +188 0 obj +<>]>> +endobj +192 0 obj +<> +endobj +194 0 obj +<> +endobj +193 0 obj +<>]>> +endobj +191 0 obj +<> +endobj +196 0 obj +<> +endobj +198 0 obj +<> +endobj +197 0 obj +<>]>> +endobj +195 0 obj +<> +endobj +200 0 obj +<> +endobj +202 0 obj +<> +endobj +201 0 obj +<> <>]>> +endobj +199 0 obj +<> +endobj +190 0 obj +<>]>> +endobj +186 0 obj +<> +endobj +204 0 obj +<> +endobj +206 0 obj +<> +endobj +205 0 obj +<>]>> +endobj +209 0 obj +<> +endobj +211 0 obj +<> +endobj +210 0 obj +<>]>> +endobj +208 0 obj +<> +endobj +213 0 obj +<> +endobj +215 0 obj +<> +endobj +214 0 obj +<>]>> +endobj +212 0 obj +<> +endobj +217 0 obj +<> +endobj +219 0 obj +<> +endobj +218 0 obj +<>]>> +endobj +216 0 obj +<> +endobj +221 0 obj +<> +endobj +223 0 obj +<> +endobj +222 0 obj +<> <>]>> +endobj +220 0 obj +<> +endobj +225 0 obj +<> +endobj +227 0 obj +<> +endobj +226 0 obj +<>]>> +endobj +224 0 obj +<> +endobj +229 0 obj +<> +endobj +231 0 obj +<> +endobj +230 0 obj +<> <>]>> +endobj +228 0 obj +<> +endobj +233 0 obj +<> +endobj +235 0 obj +<> +endobj +234 0 obj +<> <>]>> +endobj +232 0 obj +<> +endobj +207 0 obj +<>]>> +endobj +203 0 obj +<> +endobj +185 0 obj +<>]>> +endobj +181 0 obj +<> +endobj +237 0 obj +<> +endobj +239 0 obj +<> +endobj +238 0 obj +<>]>> +endobj +242 0 obj +<> +endobj +244 0 obj +<> +endobj +243 0 obj +<>]>> +endobj +247 0 obj +<> +endobj +249 0 obj +<> +endobj +248 0 obj +<>]>> +endobj +246 0 obj +<> +endobj +251 0 obj +<> +endobj +253 0 obj +<> +endobj +252 0 obj +<>]>> +endobj +250 0 obj +<> +endobj +255 0 obj +<> +endobj +257 0 obj +<> +endobj +256 0 obj +<>]>> +endobj +254 0 obj +<> +endobj +259 0 obj +<> +endobj +261 0 obj +<> +endobj +260 0 obj +<> <>]>> +endobj +258 0 obj +<> +endobj +245 0 obj +<>]>> +endobj +241 0 obj +<> +endobj +263 0 obj +<> +endobj +265 0 obj +<> +endobj +264 0 obj +<>]>> +endobj +268 0 obj +<> +endobj +270 0 obj +<> +endobj +269 0 obj +<>]>> +endobj +267 0 obj +<> +endobj +272 0 obj +<> +endobj +274 0 obj +<> +endobj +273 0 obj +<>]>> +endobj +271 0 obj +<> +endobj +276 0 obj +<> +endobj +278 0 obj +<> +endobj +277 0 obj +<>]>> +endobj +275 0 obj +<> +endobj +280 0 obj +<> +endobj +282 0 obj +<> +endobj +281 0 obj +<> <>]>> +endobj +279 0 obj +<> +endobj +284 0 obj +<> +endobj +286 0 obj +<> +endobj +285 0 obj +<> <>]>> +endobj +283 0 obj +<> +endobj +288 0 obj +<> +endobj +290 0 obj +<> +endobj +289 0 obj +<> <>]>> +endobj +287 0 obj +<> +endobj +266 0 obj +<>]>> +endobj +262 0 obj +<> +endobj +240 0 obj +<>]>> +endobj +236 0 obj +<> +endobj +292 0 obj +<> +endobj +294 0 obj +<> +endobj +293 0 obj +<>]>> +endobj +297 0 obj +<> +endobj +299 0 obj +<> +endobj +298 0 obj +<>]>> +endobj +302 0 obj +<> +endobj +304 0 obj +<> +endobj +303 0 obj +<>]>> +endobj +301 0 obj +<> +endobj +306 0 obj +<> +endobj +308 0 obj +<> +endobj +307 0 obj +<>]>> +endobj +305 0 obj +<> +endobj +310 0 obj +<> +endobj +312 0 obj +<> +endobj +311 0 obj +<> <>]>> +endobj +309 0 obj +<> +endobj +300 0 obj +<>]>> +endobj +296 0 obj +<> +endobj +314 0 obj +<> +endobj +316 0 obj +<> +endobj +315 0 obj +<>]>> +endobj +319 0 obj +<> +endobj +321 0 obj +<> +endobj +320 0 obj +<>]>> +endobj +318 0 obj +<> +endobj +323 0 obj +<> +endobj +325 0 obj +<> +endobj +324 0 obj +<>]>> +endobj +322 0 obj +<> +endobj +317 0 obj +<>]>> +endobj +313 0 obj +<> +endobj +295 0 obj +<>]>> +endobj +291 0 obj +<> +endobj +327 0 obj +<> +endobj +329 0 obj +<> +endobj +328 0 obj +<>]>> +endobj +332 0 obj +<> +endobj +334 0 obj +<> +endobj +333 0 obj +<>]>> +endobj +337 0 obj +<> +endobj +339 0 obj +<> +endobj +338 0 obj +<>]>> +endobj +336 0 obj +<> +endobj +341 0 obj +<> +endobj +343 0 obj +<> +endobj +342 0 obj +<>]>> +endobj +340 0 obj +<> +endobj +335 0 obj +<>]>> +endobj +331 0 obj +<> +endobj +345 0 obj +<> +endobj +347 0 obj +<> +endobj +346 0 obj +<>]>> +endobj +350 0 obj +<> +endobj +352 0 obj +<> +endobj +351 0 obj +<>]>> +endobj +349 0 obj +<> +endobj +354 0 obj +<> +endobj +356 0 obj +<> +endobj +355 0 obj +<>]>> +endobj +353 0 obj +<> +endobj +348 0 obj +<>]>> +endobj +344 0 obj +<> +endobj +330 0 obj +<>]>> +endobj +326 0 obj +<> +endobj +116 0 obj +<>]>> +endobj +112 0 obj +<> +endobj +111 0 obj +<>]>> +endobj +358 0 obj +<> +endobj +357 0 obj +<> +endobj +360 0 obj +<> +endobj +359 0 obj +<> +endobj +362 0 obj +<> +endobj +361 0 obj +<> +endobj +364 0 obj +<> +endobj +363 0 obj +<> +endobj +367 0 obj +<> +endobj +366 0 obj +<> +endobj +368 0 obj +<> +endobj +365 0 obj +<> +endobj +370 0 obj +<> +endobj +369 0 obj +<> +endobj +372 0 obj +<> +endobj +374 0 obj +<> +endobj +373 0 obj +<> +endobj +375 0 obj +<> +endobj +371 0 obj +<> +endobj +378 0 obj +<> +endobj +380 0 obj +<> +endobj +379 0 obj +<> +endobj +381 0 obj +<> +endobj +377 0 obj +<> +endobj +383 0 obj +<> +endobj +385 0 obj +<> +endobj +384 0 obj +<> +endobj +386 0 obj +<> +endobj +382 0 obj +<> +endobj +376 0 obj +<>]>> +endobj +388 0 obj +<> +endobj +387 0 obj +<> +endobj +390 0 obj +<> +endobj +391 0 obj +<> +endobj +393 0 obj +<> +endobj +392 0 obj +<> +endobj +389 0 obj +<> +endobj +395 0 obj +<> +endobj +394 0 obj +<> +endobj +398 0 obj +<> +endobj +397 0 obj +<> +endobj +399 0 obj +<> +endobj +396 0 obj +<> +endobj +401 0 obj +<> +endobj +400 0 obj +<> +endobj +403 0 obj +<> +endobj +402 0 obj +<> +endobj +405 0 obj +<> +endobj +404 0 obj +<> +endobj +407 0 obj +<> +endobj +406 0 obj +<> +endobj +410 0 obj +<> +endobj +411 0 obj +<> +endobj +413 0 obj +<> +endobj +412 0 obj +<> +endobj +414 0 obj +<> +endobj +409 0 obj +<> +endobj +416 0 obj +<> +endobj +417 0 obj +<> +endobj +419 0 obj +<> +endobj +418 0 obj +<> +endobj +420 0 obj +<> +endobj +415 0 obj +<> +endobj +422 0 obj +<> +endobj +423 0 obj +<> +endobj +425 0 obj +<> +endobj +424 0 obj +<> +endobj +426 0 obj +<> +endobj +421 0 obj +<> +endobj +428 0 obj +<> +endobj +429 0 obj +<> +endobj +431 0 obj +<> +endobj +430 0 obj +<> +endobj +432 0 obj +<> +endobj +427 0 obj +<> +endobj +434 0 obj +<> +endobj +435 0 obj +<> +endobj +437 0 obj +<> +endobj +436 0 obj +<> +endobj +438 0 obj +<> +endobj +433 0 obj +<> +endobj +440 0 obj +<> +endobj +441 0 obj +<> +endobj +439 0 obj +<> +endobj +408 0 obj +<>]>> +endobj +443 0 obj +<> +endobj +442 0 obj +<> +endobj +445 0 obj +<> +endobj +444 0 obj +<> +endobj +447 0 obj +<>]>> +endobj +446 0 obj +<> +endobj +449 0 obj +<> +endobj +448 0 obj +<> +endobj +451 0 obj +<> +endobj +450 0 obj +<> +endobj +453 0 obj +<> +endobj +452 0 obj +<> +endobj +457 0 obj +<> +endobj +456 0 obj +<> +endobj +458 0 obj +<> +endobj +455 0 obj +<> +endobj +454 0 obj +<> +endobj +460 0 obj +<> +endobj +459 0 obj +<> +endobj +462 0 obj +<> +endobj +461 0 obj +<> +endobj +464 0 obj +<> +endobj +466 0 obj +<> +endobj +465 0 obj +<> +endobj +467 0 obj +<> +endobj +469 0 obj +<> +endobj +468 0 obj +<> +endobj +470 0 obj +<> +endobj +463 0 obj +<> +endobj +472 0 obj +<> +endobj +471 0 obj +<> +endobj +474 0 obj +<> +endobj +476 0 obj +<> +endobj +475 0 obj +<> +endobj +477 0 obj +<> +endobj +479 0 obj +<> +endobj +478 0 obj +<> +endobj +480 0 obj +<> +endobj +481 0 obj +< +/P 473 0 R +/Pg 86 0 R +/K 0>> +endobj +483 0 obj +<> +endobj +482 0 obj +<> +endobj +473 0 obj +<> +endobj +485 0 obj +<> +endobj +484 0 obj +<> +endobj +487 0 obj +<> +endobj +489 0 obj +<> +endobj +488 0 obj +<> +endobj +490 0 obj +<> +endobj +492 0 obj +<> +endobj +491 0 obj +<> +endobj +493 0 obj +<> +endobj +486 0 obj +<> +endobj +495 0 obj +<> +endobj +494 0 obj +<> +endobj +497 0 obj +<> +endobj +499 0 obj +<> +endobj +498 0 obj +<> +endobj +500 0 obj +<> +endobj +502 0 obj +<> +endobj +501 0 obj +<> +endobj +503 0 obj +<> +endobj +496 0 obj +<> +endobj +505 0 obj +<> +endobj +504 0 obj +<> +endobj +507 0 obj +<> +endobj +506 0 obj +<> +endobj +509 0 obj +<> +endobj +508 0 obj +<> +endobj +511 0 obj +<> +endobj +510 0 obj +<> +endobj +514 0 obj +<> +endobj +516 0 obj +<> +endobj +515 0 obj +<> +endobj +513 0 obj +<> +endobj +518 0 obj +<> +endobj +520 0 obj +<> +endobj +519 0 obj +<> +endobj +521 0 obj +<> +endobj +517 0 obj +<> +endobj +523 0 obj +<> +endobj +525 0 obj +<> +endobj +524 0 obj +<> +endobj +522 0 obj +<> +endobj +527 0 obj +<> +endobj +529 0 obj +<> +endobj +528 0 obj +<> +endobj +526 0 obj +<> +endobj +512 0 obj +<>]>> +endobj +531 0 obj +<> +endobj +530 0 obj +<> +endobj +533 0 obj +<> +endobj +535 0 obj +<> +endobj +534 0 obj +<> +endobj +532 0 obj +<> +endobj +537 0 obj +<> +endobj +536 0 obj +<> +endobj +539 0 obj +<> +endobj +538 0 obj +<> +endobj +541 0 obj +<> +endobj +540 0 obj +<> +endobj +543 0 obj +<> +endobj +542 0 obj +<> +endobj +547 0 obj +<> +endobj +546 0 obj +<> +endobj +548 0 obj +<> +endobj +545 0 obj +<> +endobj +544 0 obj +<> +endobj +550 0 obj +<> +endobj +549 0 obj +<> +endobj +552 0 obj +<> +endobj +551 0 obj +<> +endobj +554 0 obj +<> +endobj +556 0 obj +<> +endobj +555 0 obj +<> +endobj +557 0 obj +<> +endobj +559 0 obj +<> +endobj +558 0 obj +<> +endobj +560 0 obj +<> +endobj +562 0 obj +<> +endobj +561 0 obj +<> +endobj +563 0 obj +<> +endobj +553 0 obj +<> +endobj +565 0 obj +<> +endobj +564 0 obj +<> +endobj +567 0 obj +<> +endobj +569 0 obj +<> +endobj +568 0 obj +<> +endobj +570 0 obj +<> +endobj +566 0 obj +<> +endobj +572 0 obj +<> +endobj +571 0 obj +<> +endobj +574 0 obj +<> +endobj +576 0 obj +<> +endobj +575 0 obj +<> +endobj +577 0 obj +<> +endobj +573 0 obj +<> +endobj +579 0 obj +<> +endobj +578 0 obj +<> +endobj +581 0 obj +<> +endobj +580 0 obj +<> +endobj +583 0 obj +<> +endobj +582 0 obj +<> +endobj +585 0 obj +<> +endobj +584 0 obj +<> +endobj +587 0 obj +<> +endobj +586 0 obj +<> +endobj +589 0 obj +<> +endobj +588 0 obj +<> +endobj +591 0 obj +<> +endobj +590 0 obj +<> +endobj +593 0 obj +<> +endobj +592 0 obj +<> +endobj +596 0 obj +<> +endobj +598 0 obj +<> +endobj +597 0 obj +<> +endobj +599 0 obj +<> +endobj +595 0 obj +<> +endobj +601 0 obj +<> +endobj +603 0 obj +<> +endobj +602 0 obj +<> +endobj +604 0 obj +<> +endobj +600 0 obj +<> +endobj +606 0 obj +<> +endobj +608 0 obj +<> +endobj +607 0 obj +<> +endobj +609 0 obj +<> +endobj +605 0 obj +<> +endobj +594 0 obj +<>]>> +endobj +611 0 obj +<> +endobj +612 0 obj +<> +endobj +614 0 obj +<> +endobj +613 0 obj +<> +endobj +610 0 obj +<> +endobj +616 0 obj +<> +endobj +615 0 obj +<> +endobj +618 0 obj +<> +endobj +617 0 obj +<> +endobj +621 0 obj +<> +endobj +623 0 obj +<> +endobj +622 0 obj +<> +endobj +624 0 obj +<> +endobj +620 0 obj +<> +endobj +626 0 obj +<> +endobj +628 0 obj +<> +endobj +627 0 obj +<> +endobj +629 0 obj +<> +endobj +625 0 obj +<> +endobj +619 0 obj +<>]>> +endobj +632 0 obj +<> +endobj +631 0 obj +<> +endobj +633 0 obj +<> +endobj +635 0 obj +<> +endobj +634 0 obj +<> +endobj +636 0 obj +<> +endobj +638 0 obj +<> +endobj +637 0 obj +<> +endobj +639 0 obj +<> +endobj +630 0 obj +<> +endobj +641 0 obj +<> +endobj +640 0 obj +<> +endobj +643 0 obj +<> +endobj +642 0 obj +<> +endobj +645 0 obj +<> +endobj +644 0 obj +<> +endobj +647 0 obj +<> +endobj +646 0 obj +<> +endobj +651 0 obj +<> +endobj +650 0 obj +<> +endobj +652 0 obj +<> +endobj +649 0 obj +<> +endobj +648 0 obj +<> +endobj +654 0 obj +<> +endobj +653 0 obj +<> +endobj +656 0 obj +<> +endobj +655 0 obj +<> +endobj +658 0 obj +<> +endobj +660 0 obj +<> +endobj +659 0 obj +<> +endobj +661 0 obj +<> +endobj +657 0 obj +<> +endobj +664 0 obj +<> +endobj +666 0 obj +<> +endobj +665 0 obj +<> +endobj +667 0 obj +<> +endobj +663 0 obj +<> +endobj +669 0 obj +<> +endobj +671 0 obj +<> +endobj +670 0 obj +<> +endobj +672 0 obj +<> +endobj +668 0 obj +<> +endobj +674 0 obj +<> +endobj +676 0 obj +<> +endobj +675 0 obj +<> +endobj +677 0 obj +<> +endobj +679 0 obj +<> +endobj +678 0 obj +<> +endobj +680 0 obj +<> +endobj +673 0 obj +<> +endobj +682 0 obj +<> +endobj +684 0 obj +<> +endobj +683 0 obj +<> +endobj +685 0 obj +<> +endobj +681 0 obj +<> +endobj +662 0 obj +<>]>> +endobj +687 0 obj +<> +endobj +688 0 obj +<> +endobj +690 0 obj +<> +endobj +689 0 obj +<> +endobj +686 0 obj +<> +endobj +692 0 obj +<> +endobj +693 0 obj +<> +endobj +695 0 obj +<> +endobj +694 0 obj +<> +endobj +691 0 obj +<> +endobj +697 0 obj +<> +endobj +696 0 obj +<> +endobj +699 0 obj +<> +endobj +698 0 obj +<> +endobj +701 0 obj +<> +endobj +700 0 obj +<> +endobj +703 0 obj +<> +endobj +702 0 obj +<> +endobj +705 0 obj +<> +endobj +704 0 obj +<> +endobj +707 0 obj +<> +endobj +706 0 obj +<> +endobj +709 0 obj +<> +endobj +708 0 obj +<> +endobj +711 0 obj +<> +endobj +710 0 obj +<> +endobj +713 0 obj +<> +endobj +712 0 obj +<> +endobj +715 0 obj +<> +endobj +717 0 obj +<> +endobj +716 0 obj +<> +endobj +718 0 obj +<> +endobj +714 0 obj +<> +endobj +720 0 obj +<> +endobj +719 0 obj +<> +endobj +722 0 obj +<> +endobj +721 0 obj +<> +endobj +724 0 obj +<> +endobj +726 0 obj +<> +endobj +725 0 obj +<> +endobj +727 0 obj +<> +endobj +723 0 obj +<> +endobj +729 0 obj +<> +endobj +728 0 obj +<> +endobj +731 0 obj +<> +endobj +733 0 obj +<> +endobj +732 0 obj +<> +endobj +734 0 obj +<> +endobj +736 0 obj +<> +endobj +735 0 obj +<> +endobj +737 0 obj +<> +endobj +730 0 obj +<> +endobj +739 0 obj +<> +endobj +741 0 obj +<> +endobj +740 0 obj +<> +endobj +742 0 obj +<> +endobj +738 0 obj +<> +endobj +744 0 obj +<> +endobj +743 0 obj +<> +endobj +746 0 obj +<> +endobj +745 0 obj +<> +endobj +748 0 obj +<> +endobj +750 0 obj +<> +endobj +749 0 obj +<> +endobj +751 0 obj +<> +endobj +747 0 obj +<> +endobj +753 0 obj +<> +endobj +752 0 obj +<> +endobj +755 0 obj +<> +endobj +757 0 obj +<> +endobj +756 0 obj +<> +endobj +758 0 obj +<> +endobj +754 0 obj +<> +endobj +760 0 obj +<> +endobj +759 0 obj +<> +endobj +762 0 obj +<> +endobj +761 0 obj +<> +endobj +764 0 obj +<> +endobj +763 0 obj +<> +endobj +766 0 obj +<> +endobj +765 0 obj +<> +endobj +768 0 obj +<> +endobj +767 0 obj +<> +endobj +770 0 obj +<> +endobj +769 0 obj +<> +endobj +774 0 obj +<> +endobj +773 0 obj +<> +endobj +775 0 obj +<> +endobj +772 0 obj +<> +endobj +771 0 obj +<> +endobj +777 0 obj +<> +endobj +776 0 obj +<> +endobj +779 0 obj +<> +endobj +778 0 obj +<> +endobj +781 0 obj +<> +endobj +783 0 obj +<> +endobj +782 0 obj +<> +endobj +784 0 obj +<> +endobj +786 0 obj +<> +endobj +785 0 obj +<> +endobj +787 0 obj +<> +endobj +780 0 obj +<> +endobj +789 0 obj +<> +endobj +788 0 obj +<> +endobj +108 0 obj +<> +endobj +790 0 obj +[109 0 R 110 0 R 113 0 R 115 0 R 118 0 R 120 0 R 123 0 R 125 0 R 127 0 R 129 0 R 131 0 R 133 0 R 135 0 R 137 0 R 139 0 R 141 0 R 144 0 R 146 0 R 149 0 R 151 0 R 153 0 R 155 0 R 157 0 R 159 0 R 161 0 R 163 0 R 166 0 R 168 0 R 170 0 R 172 0 R 174 0 R 176 0 R 178 0 R 180 0 R 182 0 R 184 0 R 187 0 R 189 0 R 192 0 R 194 0 R 196 0 R 198 0 R 200 0 R 202 0 R 204 0 R 206 0 R 209 0 R 211 0 R 213 0 R 215 0 R 217 0 R 219 0 R 221 0 R 223 0 R 225 0 R 227 0 R 229 0 R 231 0 R 233 0 R 235 0 R 237 0 R 239 0 R 242 0 R 244 0 R 247 0 R 249 0 R 251 0 R 253 0 R 255 0 R 257 0 R 259 0 R 261 0 R 263 0 R 265 0 R 268 0 R 270 0 R 272 0 R 274 0 R] +endobj +791 0 obj +[276 0 R 278 0 R 280 0 R 282 0 R 284 0 R 286 0 R 288 0 R 290 0 R 292 0 R 294 0 R 297 0 R 299 0 R 302 0 R 304 0 R 306 0 R 308 0 R 310 0 R 312 0 R 314 0 R 316 0 R 319 0 R 321 0 R 323 0 R 325 0 R 327 0 R 329 0 R 332 0 R 334 0 R 337 0 R 339 0 R 341 0 R 343 0 R 345 0 R 347 0 R 350 0 R 352 0 R 354 0 R 356 0 R 358 0 R 360 0 R 362 0 R 364 0 R 367 0 R 368 0 R 370 0 R 372 0 R 374 0 R 375 0 R 378 0 R 380 0 R 381 0 R 383 0 R 385 0 R 386 0 R] +endobj +792 0 obj +[388 0 R 390 0 R 391 0 R 393 0 R 395 0 R 398 0 R 399 0 R 401 0 R 403 0 R 405 0 R 407 0 R 410 0 R 411 0 R 413 0 R 414 0 R 416 0 R 417 0 R 419 0 R 420 0 R 422 0 R 423 0 R 425 0 R 426 0 R 428 0 R 429 0 R 431 0 R 432 0 R 434 0 R 435 0 R 437 0 R 438 0 R 440 0 R 441 0 R 443 0 R 445 0 R 447 0 R] +endobj +793 0 obj +[454 0 R 447 0 R 449 0 R 451 0 R 453 0 R 457 0 R 458 0 R 460 0 R 462 0 R 464 0 R 466 0 R 467 0 R 469 0 R 470 0 R 472 0 R 474 0 R 476 0 R 477 0 R 479 0 R 480 0 R] +endobj +794 0 obj +[481 0 R 483 0 R 485 0 R 487 0 R 489 0 R 490 0 R 492 0 R 493 0 R 495 0 R 497 0 R 499 0 R 500 0 R 502 0 R 503 0 R 505 0 R 507 0 R 509 0 R 511 0 R 514 0 R 516 0 R 518 0 R 520 0 R 521 0 R 523 0 R 525 0 R 527 0 R 529 0 R 531 0 R] +endobj +795 0 obj +[544 0 R 533 0 R 535 0 R 537 0 R 539 0 R 541 0 R 543 0 R 547 0 R 548 0 R 550 0 R 552 0 R 554 0 R 556 0 R 557 0 R 559 0 R 560 0 R 562 0 R 563 0 R 565 0 R 567 0 R 569 0 R 570 0 R 572 0 R 574 0 R 576 0 R 577 0 R 579 0 R 581 0 R] +endobj +796 0 obj +[583 0 R 585 0 R 587 0 R 589 0 R 591 0 R 593 0 R 596 0 R 598 0 R 599 0 R 601 0 R 603 0 R 604 0 R 606 0 R 608 0 R 609 0 R 611 0 R 612 0 R 614 0 R 616 0 R 618 0 R 621 0 R 623 0 R 624 0 R 626 0 R 628 0 R 629 0 R 632 0 R 633 0 R 635 0 R 636 0 R 638 0 R 639 0 R 641 0 R 643 0 R] +endobj +797 0 obj +[648 0 R 645 0 R 647 0 R 651 0 R 652 0 R 654 0 R 656 0 R 658 0 R 660 0 R 661 0 R 664 0 R 666 0 R 667 0 R 669 0 R 671 0 R 672 0 R 674 0 R 676 0 R 677 0 R 679 0 R 680 0 R 682 0 R 684 0 R 685 0 R 687 0 R 688 0 R 690 0 R 692 0 R 693 0 R 695 0 R] +endobj +798 0 obj +[697 0 R 699 0 R 701 0 R 703 0 R 705 0 R 707 0 R 709 0 R 711 0 R 713 0 R 715 0 R 717 0 R 718 0 R 720 0 R 722 0 R 724 0 R 726 0 R 727 0 R 729 0 R 731 0 R 733 0 R 734 0 R 736 0 R 737 0 R 739 0 R 741 0 R 742 0 R 744 0 R 746 0 R] +endobj +799 0 obj +[771 0 R 748 0 R 750 0 R 751 0 R 753 0 R 755 0 R 757 0 R 758 0 R 760 0 R 762 0 R 764 0 R 766 0 R 768 0 R 770 0 R 774 0 R 775 0 R 777 0 R 779 0 R 781 0 R 783 0 R 784 0 R 786 0 R 787 0 R 789 0 R] +endobj +800 0 obj +<> +endobj +107 0 obj +<> +endobj +801 0 obj +<> +/StructTreeRoot 107 0 R +/ViewerPreferences <> +/Lang (de-DE)>> +endobj +802 0 obj +<> stream +xœì½ |Eöþ­¾¦gzîÉ$“L 3ŽN2I†@#iŽ ‚\j È¥ —"‚¸€JÄ%*Ñõ̲¬º:‹QñbEÅû>QAYOÈô«f&p¯ÿÿ÷û_Ÿy�yU]]Ý]õêÕ«o½ªÉ€°@Î,f¿ãm€´¨¿p`MíÂÚ%oâ=€¸wò¥瘜3o8€G'/œïû_÷1àÚ˜r§Î¹äÒ!?¸è´0]|ÉÄysàE fú–Kf-šzÁñÑ…ÀÌZ ïÂi —^yÏkŸþôðôÕÓ¦LlЛn«È2½¦M›21Íêú è2íÒùWÎþ(ïÐ÷ `Ǭٓ'þ{íM@· + ½þÒ‰Wαë–CÉà»lâ¥Szÿá¢Kî€{oÎìyóõ‘¸ ôúœ¹SæÜþ]çm€r5 k à!à º ¹mðá!ÀÁŽ ®D«éb,7#}8}æoäÛb€í§3�¿i‹Ñ”ޤYŠø—ç?Ï]\:ÁVñ3¼2»òøÏ�ÓðKaôë'fžÜj‹™&0¶?�Î'·B„,6‹!€xã!ÿ&¦rNYä‘8�ãøeýø’ï¬íóAƒ¯­R|;6’Xä9΢ÓkÄf*dàè[¤�goMƒ€»äÂ|ÈEwTb,&à*|‚Ïq¿à¤Ïîsùok«Ôuö¤\tƒŠ~˜€‰gåé«ëú§«õ‡õôëô•{±÷¾oîáöœ)±BŒ¥¥ŒL7q;Æ$⬔ˆóð!?:äá�5—`0Sp fc +.À\ˆ)˜‹y˜ŽÙ¸ >”¡½QÒ!—�åóaKY€Y˜ˆ¹gœ�™ûOð¡Å(E|¨ÁtLÆ\ÌÆ<ÌÆṪ0s1‡ñ‰˜Ÿx|è‡Y˜ÅÞ7—`æc^âíóXYb +XN Lì3S0 s1WÀ‡ó1SpÆ`‹ù0 ±³±€½yfãV"&c6æ`æ¶¿Ë×^öb„˜L“g½QÀÊ1³0ÓàÃ`LÄeì“13‘w(fc“ä`,@«q¼^c0 ÓY]fýÓòLeòð¡?¦cf±Ô‰L§×1þœÙ‰šúØ[`.&³ú&¥|kš²—¡�Iχù˜ÆÒj0c˜t¦³û.cò=‡Ý?…嘂K1‰I»�q_¢Dɼ>–>�µítÌioÅSõ ×çc"¦c案ÙB f“uÈ0ê1aÒc01®@Ñc0ì·Á«Þ+lúIØ`×O‡~8õp"M?ãiÈÐOÀ �~éŒg S?²ôãÈD¶þwd¡“þwxÑYÿ;²‘£ÿ�àÓ�¡3üú1ä W?ºè¿ÂÏx.òô_@¾þ+º «þ+òÐMÿùè®ÿ‚®è¡ÿB-�þ3º£@ÿ=P¤ÿ Aý' Xÿ …(ÑBJõŸd¼=õQ‚2ýG”¢—þ#Bè­ÿˆž(×@Âúè…>úè� +ý”3ƹúßÐ}õ¿áTêCúéGq.úëGÑõ£¨D•~ªôïуôïÑçéßcëßc †èß¡ +Cõï0Õúw8Ãôï05ú Áùú Åýª1R?‚a©F Fé‡1côÃ8è‡1ê‡1éßbjõo1ý[ŒÁXý.À8ý.ÄÅú!\„ñú!Ô2ÁýŒÅDýŒcübLÖ¢ úAŒÇý &`ªþ5êq‰þ5ÕýkLb|2fè_£3õ¯¨Fê_a*.Ó¿¢öFÿ +Ó0GÿÓq¹þ%f`®þ%fbžþ%fa�~—b¡~—1>Wèho×àr,Ò¿À\,Ö¿À<Æçãjý ,À}?b©¾ÿãß2}?®Ä2}áwú>\Åøb¬Ð÷áj¬Ô÷a ®Ó÷b)®×÷âÜ ïÅ2¬Ò?ǵhÔ?Çï°ZÿËq“þ9Vàfý3¬ÄÍú縷èŸázܪ†p›þVávýS4b­þ)nD“þ)VãýÜ„;õOp3ÖéŸà4ëŸàV4ëc îÖ?Æm¸Gÿ·ã^ýc¬Å}úGhÂýúG¸èáN<¨„»ð�þ!Ö¡EÿÍøƒþ!îÆzýC܃?êà÷Ø €{ñ'ý܇Gôp?ÑßÇø³þ>Äcúûx�ëï£õ÷ðÆ×c“þþˆÍú{Ø€Íú»ø¶êïâa<¡¿‹GЪ¿‹GѪ¿ƒ?c›þÃvý<Ž'õ·ÅÓúÛØÈø&<£¿�ÍØ©¿�-xV Ású[ØŠçõ·ð^ÔßB+^ÔßÄ6ìÒßÄv¼¤¿‰'±[;ð²þžÂ+úxšñg°G;±GÏâuýu<‡7ô×ñ<ã/àMý5¼ˆ·õ×° ïè¯á¯xW /á=}vã}}^Æú¼‚õ=xé¯b>Ñ_ÅkŒ¿ŽOõWñ>Ó_Á›Ø«¿‚·°Ooc¿þ +ÞÁúËxô—ñ¾Ô_ÆûøJàk}7>ÄA}7>Â!}7>Æ·ún|‚oõ—ð)Žè/á3|§¿„Ïß‹£ú_±ÓÿŠýøQß…/?€Ÿô]ø?ë»ð~ÑwákÓwá Žé/â×_Ä!œÐ_Ä·ŒF›þŽ0þtý|OˆþŽ¢?�¿^?0þ#ôçñõçð31èÏá"ëÏáWbÔŸÃ1bÒŸÅ߉¢?‹ãĬ?‹Ä¢?‹“ĦïD±ë;c\'}ç6øHß-Fêk%ÉHÏd¤4 &#EÉHA2bNF„d„OFˆv‚ÅtÆcŒŸdüGÆÿÆøQÆ¿güã‡ÿ„ñ�ÿ€ñ·ßÃø«Œ¿ÌønÆ_b|ã/0þã;ŠñxÉ62þ8ã«¿‘ñFÆW1^ÎxoÆW0¾œñk_ÊøÆ'1>‚ñÁŒ[)>-ÁùÂah·ÚD£%üùÞôŒìwÞMÏÈ^|uºwñÕ™o¾•ž‘½ðŠôŒìKç¤gdÏš�ž‘=ó²tïÌË®™›5Aš;û’iîì©ÓÓÜÙS¦¥y§L[yyVæ¼ô«dú ÈôŸ†Ú' 5Ü48'¸Cø +A‘'ò›]zÎÞ§…_A°—qŸpt³ÅÖZ…C›”´ð6}§ðýfon¸²ŸEø ·?‚ 8Á¿ge>¸Y±‡‹Ÿ"ü/£œŒÙÜÔ%§òÒÿwØH?ÜOú�Ó÷nù[w5¬µmó¹âa—n4¬Ü\Œ‡Ù4Í©O7sj+Y±i�Im%ׯƒeñàͶΤ޽Τ®kæÔæ&QmÕ÷>ñ]Zzø¶5<�kæŸ\éáÃM‚º¦©KMP&{2ÃS'“;š¸x†¦¼náòÞP{¯ÐsZ Ùº„SO~lR·‘¾¤b§j­¤bSN—p+ nZ«­¤hó +^}£•ü…hdd²_ÈÍ kÏedгÍ;³¼4|b§ÝÞó*-ÇÎ'vá—_bq-ý¨b ZʩœÌfiÀÆÇ9õñ¥q ¼ms²G<Õµ[x¹« ’•›MìÎìÕ�;‡W5 +jã +“zã +^½ö¢.Y*¨KWÄ«Ûo’'34µ¼jz}+)§¹Øy/vÞ+V‡R�yóœU´³ËI âÿŽæÍSçÍOÖŽÆXjÔ­¬ý¢˜·ÑH¥>bTÿê¨<ª:*�Í +ô¯Ž¾4ª:Úkĸ¨9Ð#¸c6r”IÜ€1ãÆÕös“¾h h =Ñ@JÑ@‚h Eh h f4 „G!Úù zC¬ádÃ� k8Úð}цC Ÿ4|ÔðAÃÛ {^mx¹awÃK »^hx®agÃS [66<Þ°ºáƆƆU +–7\Ó°´aIä† ƒ¬ ÿ©$NQä¿¿EUÅÃHõØx’¼# ˆ§èõU§xlx¬»þ3Ë�ØöxNn�~D|n°þ-�пíø$ýˆ‚-x7âZ\{,yEN|„øic"y^"œ àr,äá¹yïýGžÓ)Š X“ˆo@K{:�ß�iíçwbu¢dËY¸�rÿkÚ‹½¸ÈÓ„;ëÚuÔˆñ<®ÅPŒÅHñcñc\‡ZÜŠÚÈaY‡¼¯'ê \‰+p&â*\›¸v-“صKYx®Åm¸÷ãNò6†a>°áÔävc.e~šéx b–b¦Ø ×ú÷¸—üCîÿçéLÆØÛû�ù3âjîX8À"Ü¡ÿˆ1„˜‰a†é±ÀŽS· +{à�î§:ÆVÌ [1 Oþ÷Ñ›ÜviÛBýwúrññ áiá0ß dâ2\ƒÕ¸d±5¸¿£ŒR”¢¥(E)úÿ-ǬÅZ}¥þF¡»”†Ç0ƒbµb=nÁJ¬ÄÅläý#îB-öá^Tc:¶èO{Ê=hÀ>ŒE5 ´ V6Œ3êüá5ê‡|Þ ýûi•}Ï­8§O¸¼w¯²ž¡Ò’â`Qa�Ú£{·®ùy]¹~_NçNÙÞ¬LOFº;ÍåtØmV‹Y1eƒ$ +9Ȗ‚¨“·Š~fDµë£\^` ßï/,ˆºN]iÕw®îx Q§šŒ¹â±x!¢Ò€¨!^ßô¨61Š} v6®nµcR½jn4L¼¸6ÊOŒlŸW5mL4»zÄØÚ(ŸWE?õÓ|´¹2FÏW5Í×H¯M«�òy��´ÑOKo˜6¥žª © ,,ˆÔ^ïßé�:Ô^_u¨QK``ÔrÕ/ßXå™î£§��×û¢÷�¬íxÕOy$ñø«UÓêTÍèO›$ØÞlL‡4°ÆÑnœè‹.›4#®{W'õßßh�šñ{ý~¿Ÿ6»1!ʆú´È3&ÒjVÍð5Þ8…Uu5«šßïõUÍH?ôF_UD=ÆÖVM T�z¡¯10Ñåóμ×ï�fªôÆÆÆ*Zĉ ý âEŽfª§ÊOû„W%Q.o@TÃŒam૊jFI‰ cémôJýÀHÄow>Ï5ä]/|�ô‰†¼hšj÷¿à/,ØYXP=ª¶j —Õ>Ê ¨=÷ˆÇ{$RXP=¢=™xªGÕ6�xã2ª¨ׂiIV?&Þ�¹ö–÷û#‰üì©{<Þ=‘‚A�Aõ��ƒ¾A�õ�[õe“>{ q£ÙÜ8§ªÞÇz>™Øªo¿Ñ´:µ×O#} + |Tß�ªŽºFŽ£Í3È7mbÜXTüå^¿#’Ì3âŸ]Nô³¨a@Tbý¬Ñ~¸° jPë÷úQóÒª-÷Fíå´›ú¢¸ ¶ÕŽÉLg›ÅèÚ(ç¥=…�äUM��ןTj÷F&R#…~?íC7¶j˜TXà�.Y?÷a’w´ ‰rõôÊÎä÷ôʲä•öÛëþÂu?ýK�î¨Ï�Ž€Ó2ù3sÛÝ9¦¶U?V•ËÍíPË{¹DŒóò4fRv_E4Ce7R™D»©�ö€ï�@Ô®Fŵ;½ŸÝ…“D«´×pyö7» µ�H³GIE”¤Ót¸¢„™t>£C×þs _v£7zíêÈ´>…Q­‡¿°ÀW%õ¬·Œ©MH©Ü›èEô]ChUN¿Þ.Ådž³¥[=洳ϥ‚¿zLû }nt�š|Tüü<ÕÛñtð—‡$/#ÊåùC¨P[õ�åÞÓÒF×FµxRõ¨Ú%Þ«èx‘þ䆑5rÃè±µ9ôßf|7Œ©ÝÄn@}ÿÈÆ.䆑µÛ|€ÆR9šJé‰�ž šT�ªÝÄÉ,¿w›,cW–ÀÎ'·°49™F0¹•‹§Ùã/Êg/ÒÀar«¿¢%s ˜Ü*ÇÓ–±4FÌqY«™DMÖŒš™³pÞ�„&m5y;Œ›ÍÄB¼—qF±äV²l£QóÆs,ƒ‘hñÞpÁ©W_0¶v³âe<‰ô§ô�¦Z匈*öqQ;mDÀõeíö6Ú©¹ŽFTjÒ¾¤vpúÀ‚�yä†ëtq4­zÔ8o”D +øÛ�ó:×â<ƒ“¤� !—’Uäò7‚ÛÅ›ùYüG‚[xDÌëÄ?‹_J.©Zj•Z ý _Èy—1ÝXoüÊÔÇ4Üô{ŬLP›§š?¶ ²€‡~kó7«¹t?, .ÂA²]ùn%;0‡ï¬FàBahx©0‹…° +#Ð"ŒÀla& #0V�ñ4?½W\Dìô94äïˆï»#]¸;„Ÿ0^¼;3vð±C\‚ñâcØÁù±ƒûiB vð/`‡!ˆâIì�dŒ'ÂÝØ!hX$” »x ŽÁiX„,¡YÂ,8…[á?³nü¨x(81VØ‚õü&Ô [Q/QÏ]‹2¿ëÉQÜJŽê}øã,¾^:€õ4]ˆ¢žÞGóq/a=?Ó¸­P…ëq+ÿ.¬âKðð�"‹ÿVþÞ³ßÿψ–¿ã9-ßzïo-çYi×ãÖyÏØS:Ò‘øXò¥,ÿ“$ü?]€¥(E)JQŠR”¢¥(E)JQŠR”¢¥(E)JQŠR”¢¥(E)JQŠR”¢¥(E)JQŠR”¢ýK’¾Æ×àè¾Ta…¸< ÈÒáð¢hÜã ÷ ¸§rOIqÈáwäùþõüg'·r[Û†Š �7®†ƒÃCüÇÜ2±™=! ¥Ù„!(<#¼.ˆ‚`ä%ÎÀó¨ í)%Ag8XWRL‡ßp�žkȧkÄæX?ò ýÐ_’YÛÎ](6È~š*ÚRC(+çˆÄÃ'’È!@‘e³T#Û©F>ÄÓ€ªûTÕî{o*+KŠI�ª’v‚ÃÎ�¹-ö2éµ6¶+¶�Lâ œ‘\[3ÄúÎô$îgïº ’~t³BjЪÕ…Ôô6²7ó­úѿВ[õcš…¾ZVˆtHÄ!Bßêp†iÚ_îjù÷‘òØ®µ¤<¶�,$?“¿“«c·µýÚöwúFX+¨P0DóóVA¶4 áéˆÍ@,¼V"ˆýE“�<%´ê{7›¥!¨î ‡÷¨Ä¾žà„ñuªÃ‰p8Ëc?b?RRL¨pýe~GÈáÖÆf­Œ]Jn_IÖrN¹ŽÜ»]cÇH€G•Ö)Ì“0§ñ›øÌR º)R –qš#s0ת¢o¥áVEªá‚"© ªªšµGUaÿ%k­q]p‘Šû,8K#‡iÝn%ǹMÜbðÈÖì9Ÿ#ô7¼à#„ë‚uÖ©´¸e~nSÛg\.9~-½oŽ~ˆŒÀ+P�­9 EÇÁe|<‡ò´�ºàåûP©–gäæ—õì*Mw§IŸõëWìß?½QÑ€EEý¢Ð�|!ÓËLÍr!°+¨¡?‡Æƒ¨ –µŽ�á ÛF¬ã›ÿ~¥t8\¨ÍŸ7Áºkn¬r8²Ü«4“ÍÕ±Č战‰JžJ•x‚YGœá •z'I�Üü|®¬§³W¯��·û}»ßÇŸì·xóÜYš_QyÕ_�ç7Ä>�í!…¤;÷ö–Ø¡g&OØJŒ�ì ¾ç'·9¸†¶5mO‚àÀ½#n‡�4‹Å€F" Äb TV:ÃÁ Ù*)öVÞPÖ—ïâÞiq 7¥¸×¢Óòû +ï»JŠ{˜×ÛB•U~*ÕK~¿¸ =P¡uîìZeò�Vi~t²ú:­‹ø<&“h›#V*UBž`%Ó«d�á#¥%Ťgȵr†²^½B¥�9wš•3Xy·ßí/ëÙ—ëÝ—ç…îçÕ—_|ÑÈ@Õ#‹k︬²ëùWŽœ²¼&‡{ùä�Ý.nš5|ºærûOêçË*ÒºFœštkÝ�WÍé3xj$Òçöó.^½téùåS§NÁbýk~›¸ Ý1Wë—¾*ËÕ…—sse¬Òl6UÎÌ"¶,¢ðYYžNžæH§Ëålޏ\¦N†^2�l—}2oäeÙ$šíƪ6a|]•#«á©$f¢²Ž8ÂAgF˜5ª• äv-K•öåÊìþ@YÈçèéÏ5”Å+oÝ�y~Û�•ÛçìY´æÉêEcs®¸œLŠýp×ÊUO�½mZ8¶ÈÕcC䎉÷]Þwxtnþà©ɼ‘È?M½oT騥Ãb_ŽäÞµW€ýö“Ø +Üè«uæ‰Ø(iv«$Ù2dA¶ÉÍ#qXm6É*I Ep†C!Z~â :ÃaG(”eo+ÝE�lÈ`v /ß›øVžÕÚú`Ûøñ;o +ź�oª¯[t™Ø|²æŽØãdäÍ3þvì×ËOÖpO/mà T_Zô¯ùÝb3¥d7fedÄež'ç8›#99&�Ç».⑜TÌDù'"fòõUV¼¸dÏ–kÏ|¦Q.¿ÛÏǵŠß=xåŽy/M¼mÝð%µÁ›;iÚ¹™%Ü�m¿vò Ξ»eI?²uúÃWõ¯xl|ѨùU«ïãx�ç^_Çñ³ ²œ­ÍÇÄMð¡'i]œ&¬òû{©™«4Sv~s$+;»Øæt¦ÙÒX§.îЩYé©=Çûw)íàŽp²ÔE‰^šáfåv‡X‘ ‰ŽáNëÌÑZñ±�W®Ÿ8ë‘+úŽ^÷Áʵcg/®o¾ìaò�ñwÎì³!ÿ¼iýÏ�6Lí1lºÖwêànä¯Ó£ËÎû§ŸÖ=IJ>\Øýîð…¿ÿì†ÍÚ‚¯¬¾rLaÑùÓÏzm}ïà˜´m&üb3œ(ܹNsj6Y†°;öu‡$SõHv_*úp»•ç8C —ÓÙ—ëí/óó?øë¦Íž=꬞0£atf[ «xNøáw~Š�Œý|í2¢òÝKëÔµô7Çêß0»@oTcœ,_%÷otŠn§ì”�ÈZUTTÓe•·:÷ÜPsäÜs»[rº¯‹ädZÎkŽX IñÆ5‚ YíöÓÓb†ã#˜‹Z’ü|jPâ6F2tæÝ é÷N¸,!p×çc» ˜\YwÙ¹³Ö^xÑÚY—�ë;i@—�‹¹dêÃWWmê^=³_匵û°ýûN¯)åõ»°¤ä"-?O»¨´ì¢Ê\rkx^Ã(Oχ&ŸݤÞå“®>ù¡žžQ óÂãï™Ý·ïì{f ˜5¬{�a³úWLQ¤ÖÌä"¡‹úåå÷»¨´g­–—߯–jßxýkþð)íóc•œa·÷RWiÎâu›Ó™/R5Ì6œÕo’ +«,o¨}€Ivš€WŸˆÎÒ¾ÃÃïø ñæYW\?qÝŒráâ7Ïé[µøO ³þ8·b£:lzßs¦V«Ý‡ÍìžR­ò�c{Þ�]úû#Öí]³­ß-“gD¯tÑ2�¾abYð‚Uî] ™LëÆÆg! +2P¡¥KˆŽ“ìfgtœÙeäÝ�çØ‚6ÎÖª¦ �†4Ø‚™ 4\¾/NèAI±«ÃÎÿÆhL„|yÿ¢"M+*êrSûÏ13Š•Ã†ÉZºÍFlfbãå±j¶Mvãã|¢4ÔÀ™)¾1S|c^fM@kÚXƒVJŠl‚ªº�¡ZRB�YÇâºø€k°_¿`Qÿþ÷/Xpªˆm�&ð±ãa–0  ÐÌWb øƒ#ý­ÅŒš9<áyhÕ÷þ…‚.‘$ ª¡ ú‚¡`�ê ‡KŠÕº‘8Ž<áDŠ·Pì(&Þ!Õ }6‚*<ö] Fq£°öäþQúá®h{kÅÙuáh] ¤½.‘$Ò¡.\â=\P}!¨†N« !eì uáV´]Í_Ìc#šH¹Dîˆu‡åúw| ³5! Òòá$vÑaK³5EÒt)ˆŽëâò}Ï?~M7Ò­›#s…ÉTæ vnŸ#¬Û÷Î>¦dö]q^R¿gºr^A.ýG³…~¿?—Üœ5º»vÉØÑÔ•-Í\­ïvþÂáCçO3zl¯¢ê¬X½ÏWÌñûs‚E>m%ú[(N±Øð†V`0Y"F»5œl4)D±Xm¼`æb&ÄÎzEð(2Œ´ê·Ðˆ¹UßÉ" +•~˜Æ¬£I³l‘jÌš3}°YÒdÇÛø5›Mâ‰(ÛÌ +ÏY�“I¼B$W‚ˆ­úAͪ˜1 ÆáƒŽPPUëêœaƒ•á  +»çû YöOUõgm>•¨ªJ;Äõ;wZwî´_oݹSܹ“¨uuþïç$äâó»$/:·ßÕvÿ-Orù�Ý·OQ“åsr[ŒÂŽ[¸É�ûŸhû=YvBPl† ÈÁ'šÙh!’Bx�Øy�–²HA�ìq8­ú/ôô\3ÒY‘_SPC̓ú�ªª¨jÝ7j8™âŸ=Ðѹ¨ÈêB?3 wzº;MðŽPi¯²žþd¸ƒÜµý£ó×<;¶ûø£�÷ÆŽ<{`íC±õbóÖÛ®Ú’/8¶­m= r±’•‹Þlkn;¹úªEãõƒÂjqÜX§ÙªLdÈPžØ2ˆ™7R%1›QÃ{Ô˜¸iÂ5n·‹s­‰p.(ÄÌ+ŠE¶¬‰È”bªR• +Q” ;®�J;D´[¤‘ +It)Ì‚°ÓY½êû15ä1u¡G]]žðÁa‡?Žœh4TÚ[X}ß‘Øk±[ɽ¤ï«×5oÿ5¶‡ä|óÁ½cH#ÑH-ÙpÎæ c[c‡cÇc»ëiÚˆ}=èN-<Oì"ŒL)dªmN�–T Í),±´ê?Ñf´$TÃ’hVK«~Hó(R�Åâ0ÒªiU�T�ŒKYÛÇu –Ð�Øfªɦfm�¶j´¶ Íì£Uå!Zgÿ²šû%6.vß;ï‘,Ò§m«ØÜVÛ»TäNÜAŠˆ›ë +BkÆo›¡`ŽÖS2®‰H‘֨Œ‰#¦5âäÄ5ŽdA,’‰ØD l¢6-%‰Ú‘Vý8Gh¨°ñä”¶†BtúÛ®¡*h{ƒ“ÚŽs#Äæ»b�;c¦DùÖ2OÉ%Z-‹�# +Ïq²Á)“5™@á$Z.‰–K¢å’–Zõ´\†„ÔiHÇ[CP‰»ÚË–(™3ÌÜÌ—A‹pøùµñmà>¹˜ýζ•ôÇ¡âšO‘V&ÓŒ0›@ì"Óùs̨ñd¬‰x<2’šnSrÎtJ×32ÜvE�@[Y ML Œ¥îVý;ZPj¹ÌFxOï ´°î`?½'$êÂægv‰�3Ìd f=ó$ÿot6þ v,¶'¶’ü� 8tßcßý-ö*éüó†Å±]dÿ¤«Èj2ˆÔ�G†m¿,¶%v,v4¶{¹í®xû?0ýY¤ –ù5Yå5j1qŠN/ñFÐ:@:UÑk!´ÄIÕ…Xd�æh�æ–Š C(&z�<Ãð©´ïWVV&)îÜ£þÂ�ðÆ¶¬ ¸¯6p7·Í›ÛnäØüe@˜gƾK qr<*+Ip»=D6l›A�¦äT±f\ªeÐ2LˆÍHì¢$ɼ¼&»^¤¶=›–Oíô �2«œÉCûGBçL­úqªs&“Õâp¶[ëÒ ÊfJ´�’�·Ž¤%g§GˆS?øË˜^½.übÇé±/=ë»’kùæ„´›aÇ=Zö+én [¹¥„ô }g÷˜-d˜�:/­Éq›àÊMV;EÚmx«ÍFìs@@/fÒÀii+ÄÇ*Ú +"íAG=è˜f¤]Hfý'Y :l×…C¡ m 6LÓAZ­«£c2Éï`MêÕ›„ˆðà¡¶÷r † ‚ÕÃyÞl[ÇÝšgië+6·�O÷r—·�H´ß"6CÄuš‘Ìú0io¶3e8šP +6²PaáÁÍ&îÝldáNÍcÊ,І³4‹$4‹´ê?°:±£­JWf[+ã*äðó-mž œ&6�%J)Í›áÅvÍ}UYà"ù®^.nn:Ig’¶$…ÏÐNoKÏ"¢Ñ"9N'/œ¥4Y4!‹ö ª=„H ;J½¿¤“‹Ê?Ã"Õ¸,ì­�}©£Uÿ�ÖÇ‘Ð8�B¨ª.U�a:¡¨ ±Š…ãMD›‡yNëüGÏÞÉ@XK¥»i[‘ô ÖZÒÜ?Z�+–>*–áNä?#­!›¤f‘gß⟛û‡‰=NlO¾ðù“šØ|Ò3/¼° .Q›áŸ5Ëf2W!Wrd ! +í1&569!—cZ�aH'£‰7ÛÙvÂAT•ƒÞ“©H5·"Ê4¯LóÊ4¯¼Ô˜�ƒ1©«ñá4Ù®áÒ„4ØIÁ¸0˜;¶]]O !¿Ìµ×Ú:g;%yÃGÜk…Á´A¸B Ýyâ'±ùÄ݃²ú6ñ?ÄgÝŇÅMlfz­ÖÎ5¸$óšˆ$œ9¸/q'TØ�˜Ò��DŸ»ØÍ¹Ý™6z‡�Þa£wØ–ðÔPòÔò'Ö2O ^ ��ĸygœ$ì;å\,özl YHú“îdfluì�ý±¯ˆëÓÃÄ;æ!·‘þd,¹'6'öTì�Ø4±4¶=ökìרS¤'q“lÒ+��„îb3LpâV­û ‰p6bÌX1›yÎÉ+k" ¤š½Í”À|¦æ3Ñæ¡æ§Ô¾K­Ë(¥ƒApSUCgÌNèô¸n�¾ñæ6NºöÝ�ù âHºi…�/õ÷íWlÜ@ß‚þ…£ éRVìÔ¶ñ@åÌáM7‘ÛÊÏ/Íh»WlÖßR_½dR•K°w/?/È�n;–Þ%Ú¼kA°H?È&nBÞÒÜÕedh”Gf‘AnÒÓcFMª©fÔtc# j2©D.4£ÆA¯ \¹‚§$ ^bæ½ÍÓiMÄ#€…'%%ÒšH‰Ëë-È¥RË¥‚Î¥‚Î]âr‘šV@Ó +hZÁ#5ˆ6Úó�ÄhìMäø(ĺt\` ¹ÅÁ©ý†ç�å±ï™0¾Î*u$æÅ‰·®wYgžÍ抸®E|ÜE—t§uæ2Nù2åN˜>£ðîu¡±‹Ï«þ]}ï Wo®{gâ5í}Ù…½º�˜W]Ó8íÜÑ7µNÍm˜V×gWçb¿sÞ¬>ž×¯KþðñWŒ˜´f|Qè©ÚŒž£Îé=¢ß¼ü1S¯1ãö‹»+ît3›'-ÕÞIDI\‘èέúq�­ó‰°r¼Øÿu‘bŽŠ‡£âᨠ¸¥<Ç|rÕ“ç�²Q£MЪïÜDgª£ö2‘û~O°ˆ™Šª*O-H +æØ¤ ±Éü"w<&r±>¬Þ›aÁUZ grš8NvÊœ"pF +×ͼȟ=)D1[¤E¡5È0K5ŠÍ@3h&ÍdX*´ê1ÍH‡_1M09ðPÈÚn¯èJ�#䈻mŸ·ý²�Ì'—là¶µpUü¥'ï��Gæ/�¾bû%Í´X!ó:®*­ú›Í¤F¡Àǵ\…ÔÅfR#ø,”)¤&¬�^™o †n´wSXÇ@ß)#­8žçÚ +J«~’vi2ç¥Ò� +,éoœÒ&±µ×�Zg�6ÓôzWžðtVNý–Ò*+�á°ÚŽ;Ô¤ÆÒEÐ$à¾j;²­íØ“ä&—I�3I“Ø||ªØ|â–Þƒ+ª„Ùse†zйH?Í·ØKe‘…id¡…Ì3“F²˜#^Ÿ5Y”¥ÑnkTPã¢Î ó ¢ÆL¥c2£Æ$SÇ“1îˆ]ÒG s-Ò™¬f4£ÔÿåMH×›�®—ÞàRH�™J×L¥kö(„ÂÍ—´\*ØŒrÊmŒgPå0ãlΖ‘úmô%�¨vÑæÊ�L +oJsI„Ë0šl> +‘è Ð;öjifÔØh¥lR¯�”`'RG=fq4§:B¡ø_ÓÄ)�ÅO§º8‘8æcدó%BC}l拱]‚ ¥ÅÞ>vñ6RâE1‹œû)¶Ë‚�Aòhóžçtâ+±ùÄ–ªê²q°�†kzÒÿ$ÇZKh›áÆN-s±‹\å$ ,d¾™Ì—ÉYđń¸hýÌ·è£\ö%F¡½š‰Æ\r¼Õޱ61Ñbû lfÔzÍæIbl6~1ÉæXsd*]Á¨ðF·IIc«ð@†bdsP`¸‹êè.uF'×Qh Y% !“Ua Í{b[mNÁä‰=úÙôÉë”.ø<¤äÙØ¹\^fQFqÛÇÜ›Üî˜\ZÚ?ŸüÔNôãzfy¦hþyŒ„ˆ¼Ó‹¼‘£Ö„£Ö„“â60ᢡ–ÎÌ hYØ$VoIôÙH]0DûÚ7ޤ5¤8ŸÂ¢=tñ¦ŽPTtª›ÕǺnˆ…ž!ý¤N¼)›Œ›O^ÙögåW·]i–Û‹»„þ�;¡�ù[ÖkV³DBì„5�D›¦„ÆÊPއ ð}Ä¡"g³Å‘ÏàE"dMDpB6Èêž‘X Ò¡æEJ";b6'ÎÒèÐg¦õ3ˆwçÔ­î̃ÉÙX;TžÂT‘U•ZRB÷Ð…¡ád+ßóÄ›|¿6N€8÷Dþ]Aáí»¨ý@ì}~”>QqºÐ/‘áBK‹°è›??þá+³þpMÓŸî½þ–ÇÖ®·Õ¿;òuL�½Â ¹åš�^y乿‚ ^?ÈOzôèC�?¾ýÆêñbï‡÷®>¹šŸ¿zýO:i‹Æ: vÁòð²f7 „·Y‰]êÂtY¦ËÍ pµ²JÚ¨�34E¸lSÀhŠXÒ3lîN®NM—]pg¦ŸóWÅ„‰VŽÍÑTZocWÁG³úhVÍê[n§-l§Šn§Šnv=¥è,wF(é’?ÍjÑfޝRaB]žÝÏ<¿>GBýíNªþegªÛ�§oþóïÉU‚oŸùæÄG¯7--X|×£¸¡ñÏ£Ú^ÜROn›óq|EDÒsýÍm¯ßyÕcŸþõ‘=/P-XðÇÄÃpà­g'œ�Øâ6ºÍ‚M ªoÂÙÖ)oi²çÓ:³žï2Ÿéƒ[aäâ‹%„ÛÊ\p®Ó—[Î4â•I¸?à°ÓÊ&¼Æ!Ÿƒ?ÖòÝ•---ÂÂ�ÈXn8Ѷ­iÛ!n›ñ\l8úßoÉTñC¶c¸€4y¬6‹qo1ó“ôâ3Ǥ–DÙ,‰²Y,{\aé\;±µµr×»D\GèxAß¾…••�–Q¨(*:÷Ü¢‚¾ÇOÒ_Ëé}b�Y9Ìð`¦Ö“ãˆ]°¸&�³(6¶hÐá³Ó'ÙM°OÒ‹¥³„|�‰˜3% +f2eeÆ VGK¶+^´äа+±â—×qÅ ã^2ô•§õÚoˈD¹Õ“±ï}ë +ÉTþ(i/G­0ãnÍ~•™\¡Pt¾ÄD–bN·ƒÏô,—NÂ9“HÜ¢Ûd“`RBEÃA£{˜ÍÔ,ÒµóYË:+D!î¾×·²¡ÏÊ#>ºÓµíºÄRB%…6‰Õ¶ˆKAxb1�„ì«XÎÉcïÇòÈáXšxød%y7æŒ×‡ ƒG-�¸¹ßÔéXB—™¬ …SJÀöR³õ ¡--âáø¥1‚9øtë3"�έúÁ'èDÍOøìVý ­€n¤H'fAt§{‹ÇÒéä±»l&âüW¯?¬eÓ÷[MNSÿ4Íè 4£c…“:J(B²R„ä=Ó ·Âd¢â4iRc33ïó›VÇÇQUµ³EO¢V¥*±MTÐ …*+éþÍŒƒ*™P§Æòý¯½²}†é´3JcZ¦_=ýö–of­ni.}sú=�æî'£¸aßµóº¶V®žýeM[«€·/˜ðNlB»v±˜ÚÇ)›c²%­Îo è—bsÒþc›“öOlNÂäü¦Í‰×ÕM�ÎâZZ„ùŸlØÄ &ƒ¶ÝDkõðsîI ©‚‡yûWi�LMájàlŠ ]27E$û™­´¼ƒËÿ(›øÄ]ý­úg BQŸ?dm¦vŸÿò¸ÏŸÄ|æoøü)R<}õ_sQÆ<ýî4ðÉñ¢¬g>7ê‹ØßHÖÑ/ ‰}ûé½­Ûï¹ï‘G<$çáHnì«ã?Ç>ä׿ÿÔÖ·^{zçíǺ T×OCûÞ$ÚlRïÿwhßyæÔö¿Dû§�žI´ßÞbÿíïúìø‡�ÓŽöÛšÄ÷·üÚ§¸¢;ôÞMZY/ŸÇ6›%Ž-ëÙ ág„Ϊ³Jí_d|4hfþøì7¼5ž‚‚kÖ>º~ù­�ĺs׿D\GtR²þæ¶=MKûø¯w¿ï™ÜÁ ;"Û`Öj]i• nÙ˜8+[†Ót殊†VýGÍJ�‡ÔhO_ÓYêžÒÒ`eâµw-ïv¨#§ßÔÒ"n�h¹üXÿ®GÚ~ðö¬EVj-¦éy›àAÐ2 ù„O'¼ÑLŒtm�ØÕN‹è¤ò-£1S9ÃzÝl�…´ÂŒÌ´Ì¦HšÔYAx…'|!ß)LÏÈèÖy¹Í†nËéú0ó£øÄb‘ÅbÐÖ@vbs�ƒ¹Þ©ß½Ýé¾+ît÷ØwQo;ClÌñ0�ºÛÓC¥ÿÖÙ>íº>È«¼ dà%U�þ—ÝT½rúå· -ëÔ©|Dhà¬aÝ̹mĽyÑÉ·v\ÞÞUµç ž]�_´~¨;¿Ì×­W�Ü´¬ÞUcû›3´ •�ªâ®ƒHÃÕÚ9<ÓÒ´4'礳Q“É`•ƒAjŠl€…î³HI‘Ï\T\!$–o„ÄJº@wž(q�uº—ƒjºÒ�·}JZR¬ÒMU†Ú{³�2l.Ê]ÛgBìÇh´…p±Ø ‘} M>RÀ�_}¼,öæê¶g.©ÍeßÏùǼz¿8ð€ÖkˆD†H„·°†µñÄ,7oÍ´ÏÙm²�œ�•lÄF—âŽÔ“‰Ý¾'Y‡³Ù\gnNZa0µ»è9¦ª®3;Ü©Í$ñ¾Ö>$"1�{é©mq„øý-ÂÔ÷b·=tìÊ»[ÜN¶p m[c;6Þ ¡ß¤à_¡Þ+,Ö,‹�º‚�…aŽy…:ÎæHcË›™I·×B1°ÍoŠ�çܼMI:ÅØã[$-‚9áhgËR|Pe^?µTeßÇ3ßzÒiÙѱο›ö@ìê-DèdLéÄ.à$´yF�[Ó—£èƈQðâ--ýJ/¹"�,4“Å&2Ÿ�r#ém&^jØ6ßeÑL‰sŽâº‹-�JÖÌæ‡l—ÆäV}'õ³¦±Q/éŠ�;s©û•Jo»TÌI÷âZ€9Ï™8lŒs’-Ãå…Á¤ØLÝßí^Ûv§-Tr¶£;±'”ne"q%C1ÛóðÛfAà�_¶Ä^~ô“ ó¶Ãw¼ceÎö÷i�².á6¿€“±@¸ ”ÇÉ“y½»–ñBbE‚¿M\Ø«¹»È<+Yd&óMd1O0ïv|秊ÊÜ<3Ñ3>yÆdeIôBs"d{%\t°¤îB쉑…Ê”: â~s«�íëaœ�ï°°�aº*!QîVH /9\‚b±)à, +ǹºs“™î&u„‚´gwÜ ñÛ+Fî”ã‚$üm± dÔ3»]Y‚ØcÏS¤.¶é™]én�Põ:“Ȱœ ±*¶…ü™bvíN£2³Æ:óï +@îÖL–4 ‘8’F¡€mœ‰w[‘¡Új3ÛìL ìDiŸKI¬‡X“ý‡H +oNKvš´d§I·Ð‹s¢Ó˜OuVÛö�rÁPH­LvûÄÒTr^ÕûÔÂÿn¬ûÒšZVpußQ±9[‰[´K¢�œ¸8öœåvçÚçøØÉöJOO>=îGçç€Ь&‰HÔ�îI(z|ÅâߺƵdÿ�ý)"¸™Ã½)"Û~Ó�þOèq:Í�ÎÏi{�«=ù7¾íc>�óä“«C|¿Õº_9•pù(ˆ·�N¤š…#è”!Zò8’%æC-+#jYt=îM¯çò1 n™dmä¹V}¿f +v·¥åñ\�£ý]�#lvǨø;ð@ßÁsèêç�y<×ÅqÚ;ؘÂî¨MÜqüŽü^Ù‘Ç‘Îî èG?(¤Iòð f´å8ˆ]ô%ÝGY´ï”*¨É1šLÆ;"ž.¦¦´b�½)â!„ïÂ7Eº¤§¹s¼FÀeYî¥}Óë•–ûémÔwèwÑætQ·™‹vp׊´ä®¤4j!Ó³2ú�Ú J¿<ðÝ¿�t©‰&J¸‡êòÊȶkY¯8Àu8Žä\ßàiR —쩞pé /mZx×e¿nùdûú]w\I®úì‰)ÜýÅ·_}Ç“i¿K[?wÖ±WN<-ŒÝyðé{®y¹«X{`ãQpX"<ǽ ^Ïf5=è·kœÏš�;yÛN»›ØxâæÝ|¦‡NʃÁºº}ö}aô>‡87©[Ÿòn=ú”Ç.ìqN¸{÷Š>Âsåj�òp÷î}Îé)¾$ǰïêÚ¶räÛwÚšL|¨¢_Ï%øšÈÒ(¾Fdh&ÂɼA„ñi x„ƒ{èF—¿+ýªJYoÿ×ÂúÅD‹í\tâbî®+ׯ¶±-kÆ¿~Šb ûÿã?=Äó�y�¤vâyY–E Y’d™$Ñ$%Ù ‰²A‘D‰Þ&B2ˆI0xºÅÕ`0Q0ˆFQO}Û]¦ßx?ãð†vÖ~QÄ¿¥3Ÿ’¢¥(E)JQŠR”¢ýo‘€Y‘)fŽ#UA€Ì‹¼xf– 2ÅÌF^0HŠÑh0$ƒlP †w)f–Ú1³’ÄÌ’Q”þÌS˜9E)JQŠR”¢¥(Eÿ/"‹Y¦?pߎ™�3Ú‰ç�F£D1³Ñ �¼(Kf“É`’ £l–“˜Ù K²A�˜™Âl‰bfIêo�àq’(Žþï1ó™OIQŠR”¢¥(E)JQŠþ·H`³š(fNì‹Aÿ�˜$·Ï›L&LF£"LŠ  E‘£,›ŒV£L�0$ÈFƒQ�² ‹l4Ró)?tœLIŒÜ�ØíÉÄxø8‘Ï|JŠR”¢¥(E)JQŠRô¿EvÛé˜Y¡˜ÙØN<¯ÐÏ&£I‘eE$£l5›�f“QVL6£‘�^C3A¬ô>É e³A•†™�Oþ'r +3§(E)JQŠR”¢¥èÿ.²Ò/Ú¶¹‚%ˆ"Ì‚A0œÂÌ‚`6›e(&Ål”ÍfQ2É6‹Åd1�fÅn2Rç1 0šd“Q4™(f¶™L&“d�L²Y–;À[sxœ$S;ûo0ó™OIQŠR”¢¥(E)JQŠþ·ÈÀå4ŸÂÌ’‹ S; ‚Åb1¬˜-&£Å"£ÃjU¬ŠÉd1;…:�!䓤(¢hí +uMË’b´&üÐq²t€ÇÿG{wÒ£ºEønÀCÍs• é~SZÉ“òÿ\b·1Ž7aãÝù…l‹ëíÑÕA<°õX¾°DÞO8Š&¢àå\HžoœÏ$Oõ©f«ÓIJÙ�äB±VªsÍ[§5ׂ1)<çÓò˜b¼å¬âütjO–sΫ¦âí´q~¾Mnâñ_�õá Käý€£X"ÊQÏåŠùFU‘>µ§F¬N'­5#%•á\›s#Y´VX)„VQŠ)SK\2)j)§?/ RJY·µä†ñM¼Õ›xü ×cYD¿´DÞO8J ¢¾˜)3eÛº¦é_Õ™Z�ÏÖZNF'…sU«Eö^y-¥3E«©ÞAŒ¤æZÖZU•¨’ÒZ7¬QÂs±‰·n�¦=WDžŸ/,‘÷SŽ’ˆhìÝÔ!^z ù3?3½:Ÿ½÷‚œ±^IêÖÈ.F�RÞöFš÷¾Ê££«JVEcZÞj„Ï·ùM<~˜¿®—‹¯Ï–Èû)G)Dt»„©C¼ô"ZŠ•¨¸YUUŒQR°>jSÜs¶ÙýÅÙ©ÞA‚´SδÎÖµ®ëœc’Y•”Ú¬„ã&?L»ç¹"B�M‚þ×~ +ÀQ"z»þ73§JT®ª*¥¤(8ŸŒN©áN_J±Å[“ÂÕÙ9ôJ2_™ÙÍ™Ù}ef§³Ò›•pZcñ“[�5;¿P¼ØO8Ê”™¿½çéwwK—˜Q©U-ýª®K)†rH�³¥kE0oÆè]IïÑO•hR䢉ŽÇÐ4¶¹…£Ð"ØÞØM¼-›xü0ížçZ5-å�—Šû)G¹Ñ?ú©CüUw‚ÆÆ4:­šfGG}îÆÆ SÙ¿Þò­Ä8v?JÊ4ï}Cq%Š’Û6´¹”¢¬Ìþâü&ÞŽ›xü0åhÊËE"zm‰¼Ÿp”"úëó2uˆ—^„¤kk[[Vm{½^]ºá–âí�ë>þº¿wïCηñ³/Í{ßÔ‡>˾c,±Ÿ]ß÷Úë.¾…¸‰··5?õÓÑ-s€~e‰¼Ÿp”ŸDô÷ïÛÔ!^zŠîÌ3ׯ»ßï‘nãõ½äû‡°cþóÛ÷áû¥ïî×ß—aZS 2¦±ÓãÀyáŸÃ8Ž&˜!¤¼‰·÷5?Í_–‹9@¿²DÞO8Êç¿Ç?G:Ç +endstream +endobj +803 0 obj +<> +endobj +804 0 obj +<> +/W [0 [645.50781 0 0 273.92578 0 392.08984] 11 12 301.75781 14 [684.08203 216.79688 399.90234 216.79688 389.64844] 19 28 539.0625 29 30 216.79688 31 33 684.08203 34 [448.24219 0 645.01953 573.24219 619.14063 701.17188 505.85938 488.28125 686.03516 709.96094 266.11328 356.93359 580.07813 470.70313 897.94922 748.04688 753.90625 560.05859 753.90625 598.14453 531.25 523.92578 687.01172 621.09375 934.08203 589.84375 552.73438 570.3125] 66 [415.03906 0 508.78906 587.89063 461.91406 588.86719 522.94922 312.98828 588.86719 565.91797 242.1875 242.1875 497.07031 242.1875 861.32813 565.91797 585.9375 587.89063 588.86719 347.65625 424.31641 338.86719 565.91797 479.00391 722.65625 458.98438 483.88672 452.14844] 104 [687.01172 0 0 0 508.78906] 124 [585.9375] 129 [565.91797] 137 [543.94531] 2862 [862.79297]] +/DW 500>> +endobj +805 0 obj +<> stream +xœ]’Énà †ï<Çä±ÄIɲTÛ±äCÕÍ80v‘jŒ09äí+Y¤}Ã,?3°²©keŸ~R-Ú«=ÌÓÅ+ gŒ%BRmT¸îjìaeSµ×9ÀØØ~"YF)û‚ÁÌÁ_éêUOgXöá5xcº:•íš°öâÜ/Œ`å$Ï©†ž°ò­sïÝ”aئÑ`ƒ ×Í©lŸßWT"‹¨FMf×)ð�€dœsžÓ¬®ë:'`õ¿{ÁcعW?�G÷mN3Î%Ï‘v‘$R"‘v5Ò>EªÊH%Ò1Az‰Tï‘R)z¦‡³KNÉÅv¡B‰boª’»Æç› +LÁc™F­Ç»V< +4Êi[ᑈøŽhÜEã^ÜŠÅôK“–a>& .Þƒ 8qìúÒocáñ)Üä–¨eýòh¢P +endstream +endobj +4 0 obj +<> +endobj +806 0 obj +<> stream +xœí¼ xTEö7ü«º·—ôÞ�¥;é¦ûv:i–N$�ˆ¤ ˆ‘=Ä4C†„ve (®ÄŒ¨èß}EgtÔ†›lÀ˜uD\\‘ˆ èe!õYÕ A�÷ãûžÿó¾Ï¼Ï¿rûÔ©ªsOÕ­{¶{î6ÈÀäé…K>ùã0€D4ÔVN¬›r÷¢ƒÀ~OÓ¥�Ë褀º¬lº|¥²iç¡;Ý:@{Ù¼eó/ñDFÈFu~cË2dŸeþ’+ç�˜ð�(ï‚Ã̽tuàO‡^Ìßú 47Î=õʆ~i0|Á‚æFGQŠ ³ä,¸tåêiVí7€4 5K–65Þõcït=€ß]Ú¸z™¶Úú@<”Ë/mõÝÌy=@O-[Ú²’ Â})ããËV4/{¬ãØg€ÿ8`*�= °Cìà{3ƒnAö@ +¸Ð8MЀB‚(¬?çù…ºÑ½“0Ö†S›O]e=產Gg�µ~ê‡Ͷ–ýKïÖ‹�Ç?ê?ˆ×k,žÚ|f¾ ú©R’$iÙ ôš‡4EqÇjéuÌ£½†µ2åEæ´}§¬™8VA +6iÞì�JŠt£IG„1ÈA;3H@ãg¦A³¦AFƒ¨m� CA)1óp)–c#6qßóÍÿa/û蜿&Öô£}H”áÿ/�X‡¿�Sô~é}�K;V·Z¯¦¤v™†ü÷þYÒøŸu¢u¢Méûç0ÅþRÝÚ>—@KÿÍÕü/ +}´Ûù¹r fÈ-8$· LnA­Ü‚¬xßD¹�r ¦óöÿ÷Yþ÷¹õÁÇ!¶/©ÿŽ^û Öþàü ¹&`&—69 ^ÜÇ XÇ),XÇ%T"Çå>4¸`‰ãZXT`¢K05¨E3V  ±—AA c†c¢h/ÅJ\‰ehÆÈ>ç)˜†fÌÇ*,A#V@ÁLÄB4a–¢K1+1ðTgÏ + +1…5X€f(?šQÁX,Å +,°+ãk X_ÇBÌǬDK|U-âz.G3æ +J3 âw!š1+ÐŒ+ `²˜á2Ô$çº�¸K± ++¡` –b¾¸"MXŠe¸R¬>6—’¼‚!(‚‚`²U‚<±~•˰ +.D#.<š°8N{–b�Øí ± +sÅŽÅ®‹ïÅBq-Kþízæ‰ýP0 1KDo쮜{�1>KãWªˆYVašÄõ&îÒâÞðžU¸ sÅî)X™¼'P#vg¡8ï2±¿£ÄùÍ‚¢—bŽØí¹*ñ%hÑß"dc!–%ïâÙëàã+ш…X‚ 4Û‘©ÙŽ,Ío�)áØ';ÆëÞ…ìç5ý @4þžÂ&²›°&ÇáÂflCþ'*ñ0®Á=X -fâ/¸Ó0 Tâ’ɺP€Ç á1ì…—à:lGq±O±7Kob-n†Ù¨À,Åíäb¶ +³pH¾%¸—aieuìv7û5žÀ6é/ì ŒÈBš°—}¡y›½�|̽x‡ÈÝ)[Æ%hÅ6é—X�‡¤z™°ùìÔ÷+ðã +ì…Œ‰ØKvÑ.þ^>!.r�4Vó6ûSÙnHð  ð¶“ad<õkf±‰l/2��ÕhŃèÀVlEÀ»Ä¤9Î~ÍŽ#y˜€5èÂ_É.©÷Ìõ½å€° QŠ XŠ?â%¼FäOt©Æ¤)Ô„5W±ýHÃPÌÀ%ø ºð1ùš^G¯£k¤åql ,¸wñÝÆ ø�d‘2™ÔÒ�t)}DZ=ò0C1 q+ÀKø€„ÈVj¢û¤_É¿•¿ÓöëífhÄ/ðKü‰˜‰‹(¤…Ü@��èX:›þ‚––ßÐ5ƒŸãRÜŽßâkâ #ÈTò3²€\CÖ’»Èƒd/y�£´†.¦_J ¤åÒä1òyºÜ"ߨ¹Es›öXo]ïîÞ×{¿f…ìLÅ5¸wá^<‚.lÃ>¼ƒwp‡‰†‰…XˆBüd¹š\M®#·“ÇÉSäiÒE^#¯‘ÃäSòùùŽ‚‚j©›úi6ͦº‚^Aï¡Ó}t}�~N¿•œR¶’†IeRDZ*-—ÖJ¤ ÒéC9KÞ'3M¡¦PsŸæQÍSšßjþ¬9®5énÐCÿêé_�tæƒ^ô®ë½¯·£·‹}ˆtd" øP†©hD#a5îÃØŒ7‰‰¸HDF“‹ÉT2›,"ËÉjr¹‰î@¹ŸàIúˆ4Ps™v�6�¼LÊm4•t�ÊOóØ€äI“†›H½ô�öKúVaŸlÀÒïäçè>ú{i¢|\3�,À¥¸·`9»Wjêä7È|H¤¹r7îÁ5R¡ìÇ=Xƒ˜…l… ÛE…4+à‚“EdÄCx 2Vc!Òp .Ã_Ñ¥­¡QÌ×XH3>äWz§a&{²ù¸ŒÝ�|¶kÙ5ˆâ)Å�xŠÜÜ{5–Á‹wð¹X3ŽîÓŒcù´�¾C§Óûν¿É%.|†Ïð{£5;Ð&¿…é(gëÙß�ŽÈƃ˜ƒ‹p—â Å…Ò.õN¢ílœ´ Wja*û ó°%˜Œçð„NƒF]=²JÞÀV\�f:�­”š{â܉YâenÅ­òrùFù[¬Ç]¸¿ÀF<�g°Yè>/ü®Î¨×ÿàù@–$m²œgô§å‡Ãõ¢m2¦ü˜¯.YΓ¯Žq.FÑ6 HÌç+Ëÿ |­fãøjdYŸ,çÉWÏ�8³hÛ̦óMI–óä›Â�>|S`7›¹/ëS´Íÿ?¾š¾|Sm–ó5&Ëyò5ðm� �MìqºÍœ#N:­Ö”,çÉ×ô#¾®4‡¸�g‹^§3'Ëyò5–—4ð†;#-&ÊÉ’¢×[“å<ùZùç›!Úý23~À× ×Û’å<ùÚøç’)ÚŠÛ%nçÙbLIq$ËyòµóÃÃÝ¢íwgþ÷ðuôåë@®ÏƒDO¬˜ †ôd9O¾i@z‚‹¼1(Gbr¶XL&g²œ'_'?â“#Úƒƒàq²šÍYÉrž|³øa‰áAÑ.D¢'Vì‹'YΓ¯‡q.D{xþ@!~g‹Ãjõ&Ëyòõò#Î%_´GÍ‹©^²¤ÚlJ²œ'_…q.CE{li!ÎÍd¤¦æ&ËyòÍåGœK©hW—�ΧÌôôAÉrž|ñ#Î¥\´§�-Äälñ8�ƒ“å<ùæ‡+†�íY«„˜œ-¾¬¬¢d9O¾EüpÇð‰Š1·¦ZˆÉÙâ÷xF$ËyòÁ�~1¼@ Â?»yeËŠåË–^vé’Å‹.˜?¯yN}Ý%µ3j&Oª—�¾ lÔÈÒ%Ê‹ +‡)œŸ4p@ÿ`nN Û¯ø¼ý<î¬L—3#=-Õa·Y-f“Ñ�¢×i5²D òªã5Ø ÊÁÀ…æóv QQƒ�}:T¥QQÇ�K£* ‚L9—2ܨ¨ó~@ŽQ†“”Ħ”¡,?O© +(êÞÊ€%3§ÖõöÊ@DQ{>Qàn® Düþü?·§1ޣ͵ý år’5•4&p5R â"¢«jùŒíaùy—Gi °Ì¦D)ß>L©SIcdd�+?Ïïç7ø¶hsòóüjëÔºX[Áw¡ˆJøÈ®ÄHú >ÒšIžÞðççu‰ìvºª&«-#µjÁH•dü/†›cãÕÓÕSgÖ)Um ñ½­®9§‘‹cjêØ:ÉMãuKbTuŒ�•$æ�:“*çªr®VõܨN?µ.ÖC”qª­áÂŒüþó<)ÊŽó³Duö´ø2Õ‘¡sÛ£ÎiŸ³}¢� )Jc}¶ØDA1QMQ96NPËhŠêc}­1êqj=š¢6>²”b0VÚAÇÖÔ… %á‘áQáÑ´œºÛ ïê( �ÜN€Q�£I9q··Ò±ÓDw”´¶� +»· NÓâ”­Ex_k²/JÁÉú0ŠDbºnÆÙ+˜1³®s4ʉ[ÀH$2†niÇÖÔõÕ!a˜¸œ_ª3Ѷêéª䃆nCŸa…Ÿ¨’€:;°ÚϯN­ \éW騀ª(³êü~;Æ{"mmJ›ÒˆÚÐT[ƒ|ˆäy"nDm�“ u{"�>M“'Ò&äªÓÃmHr¶«³­\)�¶ÄtjÓOΦÊA•üŒCqˆå·G 6¿ŒOÚ6«mfÀð«ýøÄñuüªÅ£ì±"œS“ª4Ì㺤p#7'?/pQ;�5uÛE�ª¹*Íå¿Æ¹ê°±ÓêüÊܧ +p¥á‚ÿo‰H"îHó6Û¨D‹Ä[1õmSçŸÛ\�lŽã¿UÎ3ª*ëW¹Õ%‘P’¤‘_s›b Œä +>Rœ<žÿTMîxµµ©Q¥¹ª6wBS@Õä^¤¶6)usb;Èu�œšóóÄ.ÇgR/ �Ã2 ¨¤¦Î¯Ò\~9jë¥!¢44(*™Zç÷»U3µÎ¯ÌkTÃ�Fn7¦Ä®gÊÌ:~Õ�mÓëü*øms«ºš:e^cs€W•Ë{l÷ùåïW‡éu*Ümm�6•DT9wœ2¯QQ5AUœÀ+MP] +46óÈnìšc!‡ÒÛÎÍ]ðG›Uš+öR*QŠ94µñ¸±¾!¤jrímŽ6¥´­n;êmü•wSmC(àWlÊ8EÜêFwÀÏ7aoEFåçÅSr9¡ªÉGP½4Ô^¯Ë=Û#Ž¥¡±^pA„:%A¢‡&W]R©s„ŠiüâÉ´™Â/hs'ðÍÓäNhPÔð´:¿›Ÿ­¨´&î6bçO৺7,vu +û/€??¯=—¬›Ò×ÎRÕÓ~æVI$¿½ææ +£”Çÿh6úÁ'…¤A(ƒOÔ¡íç‹J:ƒ.ßkÏIÑ- •v„úù¶Iý¥~£|á¨èt¤Z+ò%*’‚¥’‚Í’‚�’³%/l’k$/Z%/6K^씼xMòòŽä£ŠäÅRÉ‹G%/ºùˆÔOòt(>[E)k¤LPX%'¾”œ`’|’’“%'fKNÜ)9ñ¨ä„VÐñž¥ßÓ®‘œØ)9q\Œ„%gÇÝEá¨äì¸MT�‹–Šfc¬9«^4;/‰Äê‰Scuå„ÙÈÙÐâX÷à1±º^¬vä¶òÚ`.ÜU‘!eà5)ˤ ºVBàÃF)ª”*iã=aÉÑ™,|t§$ƒHT"˜ Û%‘³½°Â@ýøè´'6B{:-öÂG+.¢‡±™ÆNz=LÓé‡XC»ùžÓn”Ón<ú}½“vcíÆ—´ZÚM»é!zˆ~@?€•D=ˆrz³éA<ú=¾“Ä—ô tô =}Ÿyr¼œ¾Jß§ïÃFß¡ïÑ÷`¥ï‚Ðwé»l}³£¤´p›@BqÄ—Gœî8âÈ(ŒÒ7:¾èÛ&%—¨R6F£HÊîÈê‹J®Ž²…¾(ý¨S ù6V ¡û¡ÒýüSº6º +Ý�)t?è~,£û¡E=€eôZél °‘€Jp)û¾Çö}�B÷@¡¯Bù~d=€0=€)ôôôµ%ä‹Ò}Á1¾Š úWúœðѽô/¢~•¾(êWè ¢~™¾/|t}±ÃëC…‘¾З`£/ÂF_B}ú§Î‡�UØéNøèNÐ�(§;1™îÄlºwÒ�ÐÒ�4»c®ÏQa¤;°Gøh>õ“x\�ð"_88vBaXá 8ò‚°2ò‚ÂG•Gƒ4¼ïÁ°ÂAðŽ» Ã +Á›Ö†‚W]_V8.¹¼0¬pœ»¨0¬pœ9»0¬pœ\SV&×Fé#Ïæô÷•L^L” ++½CèÓ+0…^™^Áÿð­Ì×ö‹ŽAƒ|QúP84p�¯u;i}Ž´N#­�“ÖfÒzi½ž´–‘ÖŸ“Öiõ�V/i “ÖdÄ÷ÂÔJÂ]ç4KÃ.Òº‡´n"­-¤5HZsIkiUHI8JýŠDU%ªÎ +®tÔßyÁèBk…•úQNýXCý�°“ú±ïû­0õw*Ù1âL/¯³;•ÇÚƒG.­¸ˆ>�5ôyÜIŸÇ!úú<$Xéó(ÿ~l6}»èóøò{zFŸ‡‡h6îÐJ³Q@³QN³1›fc ÍÆ—4Z±œ/©KãKÜ,Æ]_ødê‡LŸ§Ï‹·¨~ê÷³yl!Û…Ò�bõ’É^æ¥%ÈàIc‡]o�óÖ¯Íß|mFJE +½ƒÞÉM7ݯïìø¶Ÿ/JèîðU¤“ûá• |¤A’ �Ñ�ž×ÅðÐßÂG +;<µ¾(±vó|Û‰…ŸµÕ÷­çˆïSO”’­¾cž¾·”¨L:|óDéo·úö{nõ½\Õ“ßsÁ(!¾íŠ ÝæáÛ´G�^Œ’‡:|×ñj«ïZÏxßb�hŽ ü¼%*“°Õ7-8Ów¡çV_¥gŽ/ÜÕ“­¾rÏÏ}e1ªaüœ­¾!ž¾P ä©õ ôˆIÞ¨Lº|ÃfÌ(‰’á<Ý}º:ÝdÝp]¡.Oç×ùtýtn]šÞ¡·é-z“Þ ×ëµzYOõЧEYw8Ä?ÄKÓŠïñ´2‡²Àm”Cûr�=ÅEPS¥jZ=} ©Vw5¡zŽ¢žœˆÃÔ™ª&0†¨ŽjT׌QG„ª£:6M- U«º)?«k'䎈:"¤ÒuQ‚šº(a¼ëf7O±l!ö›owózÀÍ·G"pe\^î*wŒ¶—Ž«ü Ї¡³ÅuÞoŒz_õôºŽaÏ<ÓoLD-8cýÆDªÕÿ⩘mä+r¼ªrù¯"uÛ¤Ñ䫪i¼_]‰TGI­ ƒBþQU¹ A^Eê¶é½P8½7F÷PŒ.—|Åérx©Û–’‚\A—›’"èdÂéÚ[rª*Ûsr�SA‹ iq*}iöäVU¶çæ +šŒVì4{2Z9�:Z�xW Ÿk|x¼˜ BÔ§Ôµë1&2vV¬î¤Fƒcl]ƒÛ“a[6ZÈð(¿ë:÷vä)CÕ£šcÄP~E~’!†,uf]»NW¥†ø%©#}FcU”íŠuž^­Žä�’”$ä}e¼/%%Nøãû¿*^�åZÐJwt’°—¬DKDR½Õ5TuT×Ä“BÛñ¨ð-„V¶�iIðˆ/;B¬ ~͉ßÊUq,¾+ãuìÌB-‰-I¾Y¡äŽ­lÅv†fÕUX¤áR*à“†HȇOÊ— +PŸT(„AŸDK|)úŸÑPéÓi+} ®‘Ä7ÀáE#I„—æsã.|£gÐCÏz‘‚vÄ7`Fv&˜Ø˜afg`Ð + ;¬ì ì°²ÓpÀÎN#viHe§‘ŽTö2�ƾƒéì;¸�ÎN!Nö²�ÉNÁ�,v +ûÁÍNÁ û>ôcßÂûÙPØ·@aß ~ö r‘;AÙìkôG€}�Èa_c ‚ìk 0„þì$ò0€�D¾€ƒ1ˆ�DBì$† Ÿ�ÄP䳡ƒÙ¿P„ö/c;�aÇPv%(b'0ÅìŸ(p$†±b”€eÎþ‰ PÂþ‰ÑÁþ‰r”²¯ÆHö*0Š}…1(c_a,ÊØ?P‰ Ø?P…Ñì‡rvãfÇq!*ØqLÀv X�±ì8.F%;މǾÄ$'c<ûSp!ûS1�}�iNÇEì Ô šõ`&²Ô +x &±Ôa2ûLaŸc&¦°ü SÙ瘅éìsÔ£†}ŽŸ 83ØßÑ€Zöw4âöwÌÁ%ì34!Â>Ã\ÌdŸ¡?cŸaf±O1_À¨gŸb!~ÎŽaاX,à4²Où7–ìÿŽ”ã_’²cX†¹ì,G3û+0Ÿ}‚Wbû«°�}ŒË±ˆ}Œ+°ˆÅj,fGq%.eGq.cGqµ€×`);Šk±ŒÅuXÎŽ`�€­haGp=V²#¸«ÿ¶érönðf\Áã¬f‡±W²ÃX‡«ØaÜŠ«Ù‡hÃ5ìC܆kÙa¬ÇµìCÜŽëØ‡¸k؇¸׳±׳nÜ…X7îÆ�¬ÿ…›Ø!Ü#ླྀ™Â}XËá~¬cÝxëØ!<ˆ[Ù!<„6ö~�ÛØxëÙø¥€�àöÅ�ìlÄöÃv�ã.v¿ÂÝì ~�ÿbñîaïãIÜËÞÃop{Oá~öžð<ÀÞÃoñ {¿Ã/Ø{Ø$àïñ0{›ñKöT<ÂÞC;aï¢�²wщ�ì]táqö¶àWìmlðYüš½�(ž`ocždoc»€;ð{Ïáiöþ€gØ[ø£€;ñ[öváwì-ü ›Ø[ø3~ÏÞÂóØÌ`7Tv/ �ý / +ø:Øßðt²ýx]l?ö` Û�W°•íÇ«x–íÇ^DÙ~üÛØ~ìð5lgûñ:žcûñþÀÞÄ›ø{ûñGöþ†�ì À.ö:Þðmü™½Žwð<{ïb7{ï ø>^`¯ã ^d¯ã¼Ä^Ã!»ñ2Û‡±‡íÃa¼Âöá#�àU¶G±—íÃÇø+Û‡Oðû+Ž ø)^gÅgxƒíÅßñ&Û‹ÏìÁ~¶_à{_â-ö*Ž ø¼Í^ÅWx‡½Šâ]ö*Nø/¼Ï^ÁId¯àk|À^Á7ø€íÁ·8ÄöàºÙ|‡Ùœð >b/£GØË`8Ê^þ›þ¿Á¦ÿã?ܦÿý¼mú§ÿƦú#›~ìߨôO~dÓ?>›~$iÓWœcÓ?ú76ý#aÓ?ú‘M?,lúá>6ý°°é‡…M?ÜǦø#›Þ-lz·°éÝÿ�6ý�ÿC6}ÿÿØôÿ±éÿq6ý?=Nÿϵéÿ.Nÿ›þ?6ý§mú_þ/°éüChøgútÓEÉ­.J §B#‘`ÐÉG2õZÍ*=G‡"…rw"…'¿Êˇ �¤“"BžÞÐ[—©ùüT(f°Od»flèGzù +Úiìã¡,¯¬IóšÍΔ(;ÖeµÒ gšÍtFŠ&Þƒ “‰Î€‰÷¡  +í-…ö¢¼G\s»öÇœNtY­ZÎéã.³Y _„3�F-giã=°™Lò¾$˳<ÓdíZºÎ¸Îú²E“¢3ºhUêÅéeŽuפÎJŸ•9ͽX·ØØ”º$}qfƒûJz…örãUÖµÚt÷Ù^v½Khß³f%—Tac'x4A¨…“}Åã‹8þ �/H8l¯u¶¤„ý�â!))¶šRa`'’„)ìXŒðÙÚ” >»ÉdŠ’pW­Ýb4ƽÙ%áÎZ{ ¢lWØäóÿÆ€"A +}œ1Ò­µØà}é6.?¡P¨>Ô + ´~¹@ã[Aê—£^¥cÕð”º.­’ióDÙñªÿø½�ÏøÞþ;X7¬¬â3i2bÿÒÂÝnN‹J]KÌf9+*t,‘5p•‡ÊC\ÌmŽáE…ŽtÕ²ûSmE…Ãí¶` [§�±øÍ�—w¬³èÍÇö_y×¶§¯¹æé§¯»æ¢zú&‘É¿›ÝÙËÞííí}~ÓÏ’_öÞÿåq²€,úbá- 8Ðï4»` .a�†ä•'Cb·�@ ±½HnJØ_+…ÍöâÅòz'}P/ÿN&)Ðj¨”¢!&JöÄîø}áwDYw—ÍFg Ê> Û…¸z„¸Z„¸FÙñp&Æ„Ä éË2iÂfk±†ó²p^¢hªÉ4n'eäfÄLÅòØ¥~y(f•Ê�¥Ä^Êï êC$6è›(Iц5šbJá{]î(-ÈÚkw”ñìZ­nØðá%Eô»®Š7kî?\°R¾zô5¾ß�ß3e€¬Óì‚—öºÓ¨»ÍìJMÕÎ0s…²ÛòE8ÅfÓÎ0{Ó4^®¨NNàõòQ¯ÇbÓÎðšøz£tGØD N§â³Ù)U|vGiÁ~¾ ‚½(à*çpw!WašœÐäpP1a8Åj§‰yºÃFG*�áMã}œw58¹Á0é g”}»ýS³q­æóñÙÄdáñ£4£´;4;µ;t/é_öè&˜"¦ËbÓ\ËUŽ«Rou<ç8šuÔ}<Ë´Óøl*õlz­v�'+ÍãÉÒ{²$BõYÉìµEé¯;'Û‰=J\[ø:ÁÖI¨ÉpŽºú¨»!©îæZC‹óM€p•';èõü|�a“}K9�M—Ò5T¦Ûi|äÎv¡¤õ'zl'CÜþ +í,;SVÞs¦þˆÝÁåÁá,]k²\kÛMìŽÒ¡Câ*NqÛ<¶~6¯MûGv:Ö =;Žv }A=©_‰¸ù­5»u:3õF¥¢®%Ô”fÚ›×^{©½ÈQZ0dh$7Ý,>¼døðaÅÁ@¶V×8Wêô4­V§ÕêdÝéêÌýÕC_>õàÕ7–34»"'ûx c¦+Ìï¯ËÂU&d2Ód`À`¶š¬^ƒa`º×#{z4ͳɕIàPl\ ]�K 'p¿·€ÿÁQZ^në±õ8J z^´½è(µíò—�!s†¹Ê|‹Y®²_b¿Ü-MËXb[”67c•ùÊ´[Ìmi·ºŸ0Œ&³EÖ‘€ÙD¸ ðnwþOçÍdX—É”.»¶Ó_#“.§¤{=Ù;Ðì8G.}äÂÑÇ 8Zf+Kª¸¸)­ºsNÒõ9I×ç$]KPøŽ AФÁ(;ñ,??¸!ß%#:2ß$ÛÉ€í +“žaC^”Ü®P�¯¸ñ?ªOú€3G¸õØ„¬ÅD-)^Eвn2bD„›#²œ ‘&³Õ• +¶,±Z=å¨Tðì’�æL—Ë“.$Ê#$ª° ˆ UA¨¨°Ô^ZPĽCI÷Bªt%I4!`\Ât"�¬íòÝ»xÍæÇ¯-º8Íal‰Þ²háú´.ÿg¿_½gñ¼¹7lè=vàOŒÜèzp­zÃ5�¥=BW_ÛtÃM7)[^šß1wöý¸cWï¿>æÿ“O Û4Ûùÿ B=\òžƒ‰�Šm{W­Yw š„'Ñ&�”¤oI š„oÑ&�”¤·I :}œXŸ@t ï¬×'iâ®IŸ@4 D›@RHÜ�…Kju¦¦‡LO›^6i.–.6ß#KBõ0i%�Æ`”t0™Ìæ=’œ&I²d5™e�´ƒî€”l  Ë0™°Ç Gé¼g5C¸Ÿ¯Ø�ps†XL%�/Dpeˆ’’°YÎëZýÃt¬”ë¨ÑœV j£ +•(?™ŸC£ìÈV~Ýb‰’õBô>ç±÷r'¸O(³}lNÎv¢ìd™½”Ë[iéÚÁ!ùZÛn«Õ:t¯•ÍìƒG©9Êö‡�E¥Rv~©$÷ëW&^ÊÖ£~쬺pš)l,5µN)5…ƒ¥¦lO©)œ_{mK~â«„Ü[MrŠV2Ó¨Tø,]`’®4TTTó¥vÿ0Rd/JØ%;¡÷�¹‰þò¿^|±«w™ý„´õôEOô>Fezï™Å "êõkž„—êDD’š�GI5Åï¶#�¤šâ·Ôa2›·qE�Ám lWØÌ·‘x,ozºÇÁ�¬Ñ*Ë^�ÙB sEÙg"„ˆ0˜ÜýqƒÇÙQZpf·mwˆÛ¸b‡pÓV«³®ì×Öï¾Ôߤ>o:`zÏ­OIuYeI©†tGjê‹5Í’šf±š£ô×áT>uزÑB-k8�Ä—ñ¬U&or%®°�/È>Û¶Ô¶Æv§M¶�· s æ"pÙ\Ô•°a® Šã92 Vr/ÌdD‡eËOÙ2ß¹¶ìkV_á+ÅÔÛK êm=¶#kõƒCškm»Ñ×av¥ Ñ 1ngÝ�„]ã–my=ÕŸ´�9Õb1›åô˜…KO·zdîzÌVGT*êXb•³€ÿŠìEö˜ßìkÞ´ºþ©þt¿4¼¨éi:m ;8ãé.¹¡kÓúKÖxúúΙg'ßt×.¢_yû‰¿œ!­¶¶Ûv?þPÇäò ú�ßõ^>«÷äë/ÝÕÑ Š‰ì9]³ ý0ˆ|ÚÇsú¬ÄGf‰¸xÃfb6§i¼nM¶7ÍlðäÚx %žµl^§�‹ŽSøM§xÖrÆŒöîßk{!!Bõ=¶Ýõ\„òg’J]8½2³R™é¨QKsusõ‹s••úUž›õ·xè÷gØu +¿‡ýc&@;#Àƒ97Çüb€/kŠ™šÍinò&�E£Üc&I¸ï–Üsä'·�üäö‘ŸÜ›��Íf£¶(;þ,�¹mò Q2¢Ó›P:o {õfóÁÇKJÃærçlçRç§ì´Å œ6“0«–ZggåÌàkvFiNg(ùèó•}å­'æ8…Ã,¨ïI +×6€uõWŠ?š�.΀ûΈ{ !ƒy€�)³Ù�–-d*ÍìÖ—éÖœ•©Â˜4]°¿xjÒê¸wtðð+� »­„ûJ’ÖGÖ¤ï:]y×V̘C+ž›ßuæŠ×nú°÷È/o=¶éà™’ÉwLZñëǯ¾êyºeÑ�‰CFñ~SCï×o´õ\GªÉ5äé?=õçÓ량Dy`óf4r†æ70ã6‘�°ì6ÙLdª—S$3¸aB‰œb2·Hå·e²ˆj%šeÕ·¤ü“Él2›Jåd6YJÖ™dZâ +<Év¢~yÙÄ=“l'ù3Ï6ðh·Ô^ mÉòzwWŠI"ºF„®•Ç3(ZHZ]`¸ÃQÒ(mYßÛS=ܺMºáŸ·Ê§6­¿·×Ñû]ô½Mä3òÒÃ�0�}"gjvÁ‰†ÐÏêM— nï`îÆœ©©tÆàÁ¿W«àu˜½Üá‹$ʼn­"G²FÙqau­‰ŽˆA«KâƒÜoJ *)©rRNº‰“§ ŽéBåÒÏæ"ÎMtpÔSZšÌw<+¢M,D[È‘÷°&Ül|~Þ'EÙép6ïäÓò3Ó…íOWzöú“õ”–’‚ø?®õ‡e��2&?6}:D“2„\‹kÉ5òJýrã +Ó*óUÎÛÐFÖË·è¯7ÞdºÅ|»óUû‹©¼.˜ÜÞÁ“>›yŽ^{ûèµ7¡×[k½-;SHJ…ƒÎG¨u¨u¨�µXÃJ xˆ•Àj³Rk”ÜÕUèJ¨¾+¡ú®DÄÕ¢JDŠÒù�9 ¢œQN"©’Ó’žxTWÒÃé4}ÃЗ¾F8‘<9‘ô7ÉàÙQZ/¶’G1}Ì@6ëîð(YQÖÝ¡(¼ÊW‚QÖÝ>P!‰r!õ+–cy$âî„É=X˜·[ë ̂ìõ ³ ícJy„B‚ÁaÅñ‡±D¨ŒaÅÃSÓúXƒ¾¦�,Z¶äã�»>[|éÚÛ{O¾óNïÉ»æÜ²xÁͷΛ¿nä„ Ó¯jÓ k~#¹>°h㻇6λ`ÞîuÏ1²ëÎ?‘š7Ý8»iíM§ÙÄ “Ÿl½á™§Ï÷qÍòb�y6§ð¬Ñç"ȵ»¢ì¤Kîä…_pñDÉ.—.»L»È—Ø]ö¼�q€×jñY&[$‹% S�f›];ƒðP#›?|óÝÞª/·PlxA(Ä•ÈÆý×Á’y†>‹8.…‰xÉ.tñßÌzî\?˜ª ïDáñ#³.Î~–qI`ž´$ãÒ¬ù�«²®õ®ÏºÍûPÆÓYÏe}–ñ±rRI½ 㑌MÒÈ�sµt€w²e6�«<|ò攘7ìâÓú*ú÷‘}_Ù÷%dŸã¤Æ>tFv2IgìCg$#Âösƒ­ yÜ×nÁ–Ü„ä&´ 7¡¹-ö¤ØÃvjß:G zl'ã—ÿdÈuÖî@Ö�ëîô+Z%‘XNê#ÂÊFKÌZ,iÉ Jx¾Yˆ¤Œ…S£é°âþÜóÑaÅ(*ÌpØEf1H„x§ ¹_¶)ãšÆé×NN†ï¸tëi¢{ñΞ«¯úÇã¿{—¾òÄÊÕO_sícdºíªË.^óö2“«v1Ñ¿}ˆØêý¨÷«ÞOz;¿S*þÅÖݯ߼™Ë÷Eì˜ì‘GcJ¤láóRÌ)ƒ2ÍYƒš *5O/q�4aP½¹~Ð"óÂA CÚÌ· |(ãYO›ÓÄ<…‹ŽÅÓOf>3`k掻3÷ x#ýà}eñrWaçjàpp¨v{� &sÌçô¹ByƒŠKåÒ¼ ò…yµúHhž~aèrÓZÓ˦oÍ߆ì%Å"Û +rŠ�…þ4×ì�KÒ�žK¹åNË£fÑG¶Ã�“ÄW(t²ïâI¾e¶2q›zB=õüñ®L¼Î(åïµÆ^N³Ùµ):­^Kµ¶‡v­ÕMB$4èúëIhy=V¸·À�‘*Ѩ”ßµDÒ¬Q©°c‰�Ä„¢Bþ0Xd +V\ŸŒ�: ¤ó´]Ç£�¦fÝxùųÜ# +§UîÛ'=´~ùââq—8~i×0gýéyü.­´Ay4ÒR~—*îFjŸ˜ËvNêþ,nïƒ÷K80ÔÂÓw÷Á³úàœ>¡Âž>¸»žÕ7±Þ$nîƒ[úàÖ>8_·õÁ}p{<µ�yékj}p{Üäõ‰ˆ>%ÊÞO4š‹så#ò‘”�GÍß4'êÔ+�—[I‘¤€×£M÷�ZѲ2m†×rɆÜ�¹4×é̲än°»,¬”KX(áõ…•JaºxÉ-‡� +[e¶Jø{{”�ú�ÅŠ’úN—þG‚rÌ(™k]¹ÜÄ-fr'gr‹™Üüŧ�Ïä–ùLnŸÉe½< +ÑÎp›øœîDŒáŽ’ú­ E�Ä$�„Bâ +™VÈ%¯�lÀFPÊ18»~BãlBãl±Ïø´ÈˆëÜé„Î�§ ¥3�a2sr£du§üW(4éD«¸¢l"7“Gl}:c/zζÏLªj®üxù +pu,/ç™[�]¼],uÄÓbJK ¦™ìnâ0§» øûçëÅ‹èPè§’êñœ©ÁfÈ2À@´Æô¨4dë£.EÒz£Ò�Ž%ÚXÈPX*//�©mQºxÕãϰö€½8(”W`�l­6ݾö±Â']~¿ïº=�<Ó˜5zÙ=]us/¾~¤¼wÒì9uÛ7o=ÓŸþrÉì‘÷þúÌý´cõê)Ýuæîï/ì](uË£aƒ‡üQØß%F¢ƒ\£h5½Ò¤-O/ϬÎÜàÝèÕ§»Ë½•©•îé©ÓÝM©Mîo«w¿öoŽ�µŸš>sÙÒlS(½”3M ãL3éBúŽé=×GŸf~ì>M­D6§eyŒ:‹6Í#aqZŠx¸ûUŸp÷DŸp7‘ÁÈ©wÚVb³†­ ÖV«ì Mt†W8m«pÚÖ¤Ó¶ +§mÍcB¹ÌX3¸�ˆ|—An ¡•ö„$þð’°³Öžó#¿œx¡‹Ëí€Z]ŽpÕYÂUg W-R£º,áª3ûyWú‹Ï‘¿úå?tÓÜKóæ þ¦§§¼¼Ç^÷Îõ˱ÜÝ ‘ÓÄ;CÙhÑš�YQ)¿c‰1&*åå¡R.(ÄKv ?ìž9oÐý3þÐûåÒ7¯{aùãgü¿[ÝòäæËWýªw!Õ�šDÝÆÞŸ¼ãÔXiÓ޽Ͽ´ÿÀKþ áéP +endstream +endobj +807 0 obj +<> +endobj +808 0 obj +<> +/W [3 [277.83203] 16 [333.00781 277.83203 277.83203] 19 71 556.15234 73 [277.83203] 80 [833.00781 0 0 0 556.15234]] +/DW 750>> +endobj +809 0 obj +<> stream +xœ]‘Ïj„0ÆïyŠ9î–$Öº$P"‚‡þ¡v@“Ñj 1|ûbb·ÐC?f¾|ßL¨lªÆšôÝϪѱÚã2¯^!ô8KxÚ¨pP¼ÕÔ9BeSµÛpjì0“² 8š%ø NÏzîñLè›×è�át“í™Ðvuî'´4„ʗνv�²K£Ñ¶ËM¶Ÿ›CÈ"ó”FÍ×)ô�‘”Œ1& ¬ëº­þW/’ªÔWçc÷ƒ€’±Œ‰�òN¿Ïm,Þ?ÇÍnWíç—ŠŠ/ +endstream +endobj +6 0 obj +<> +endobj +810 0 obj +<> stream +xœí¼i|UÚ7ü?µwW/U½¤·,Ýi’�¤“4Ih ¤M" 1  +âÆ2ˆFÄ%㸠ã¨ã­:gDEGÅ7TT\¢¢2˜T½wUw'uÞy><ϧ9õË9Ug»®s­ç:UàŒ©ÑŠIÙ]ÙéÐ6}줖 [V¿ +XÇìs·/-ØÍT”À®¹®®µp>�À\:é9‹Oo~ë ¨ 0Ï:§}ùRˆE‡r΢‹ç—ï=ç@ùÕ@Á :_ôòÊÇ€s`zwÁ¼öí«cwd€ª æµ»l¦32 À�‹W\T7Ã7Ä@TbÑ’¹í–Wè·ê]€ä/n¿h)3Äú@²Ïo_áºÙü¹/_²,›,OZ¾¶Æ­X;­‡la[»m»ööÇ$“”�VKïÈr§üüÏ^¦¯ýûË1�"']¿t½°ÃqO†XTå¿'&u·SGá莠ˆ®Áµ†8^­½Ät¡!ÓÆtaåÉã™.41]˜œyfï%T¦¤…1Æý�0³!l5î?ÅV¦[™aØÊ*˜À…°•º[éëb˱•ñ`+/¶rÍØÊɘÀ|‘*Ù8¶2—a£ �Ý�Íìt˜3ìpï`Ø/­‘™Œ8ó=6Òob¦ábã.ˆ‰hÇÅX‚•äEX‚s Œ‚˜‹%XŠ‹qA?¬`?îºý ¢°ÿ©ÅíX„¥X€ Æ£çsÌÅyé¾° ê�ÇJt+N­k`¡±–E¿ˆÏ|ƒ:}bµí5N\cjž%é• (+qæëÍPyÚ�A¬Äùè0¨Ä +,0ê&átL3¨³Ðw¾AßQÆøyF�yXŒ9µ;Œ<˜Æ(Ó7hÔ/7x»Kû¹8°½}Ú±‹°¥O"Êô€à æÌ—‰3MÖøþ²<Ù¯½žåɾô²¬À¥—ùö¾’åɾpU–'{ñÒ,Oö¢%YžìóÎÏ +œwþÚ ü+VºÜÙçœërgÏ_èrgÏ[à +Ì[°q™ß·<ë’z_èâz_(zª…ùQV…˜@Òy�9ò°UŽ'º™/¶‹®øãÚN櫇ùñÚS­ÌQ\Ë| ‚²tþ•�âg‹R¼ö¯¤îÛíäTÜINMX©c?P‘‘£?0‘nmçÃ?„Ãñnmg"çgVü³ƒtäà§T$ñ©Óñ™ú*Òü*2ö¯d ¦‘% È²h»–wÞ“ä|²˜œ +²ˆœ·�Ž4î ç��µ‰±·1‘;ne#·ÝÊD~{+麕‹ÜºÅiÿùÝf*rãf&rÃõläúÍtdówž478—:ív*rË{ÞÍ[èÈM[¨H·öA¶¥`h|ú²{ ùö{ÞÀ÷{O n”6{üq²�,H §#_v2‘/:éÈU�LäÊN.Ò¹ÁùÕZY·†‰¬]ÃDV¯á#k6ÐÆœ£æx}ñ9HäŠ $²i‰\¾��lÜÀEÖoà#�j··Êí®t;F¸í1·¥Âm*wsen:êF©;ïT 9Qr(2�4Â�&2KÉ„D”ùÚ~ø+Û¡Ûy‡‰xxÔáÆÃ9üãaV<2óÈUG~<¢µ¼Â"ÛÐ"{!ç�Õý—ö)æã|íS}w¢}ŠXª}‚…X¦}‚sq�ö ÎÃrí,ÂJíc,Æ…ÚÇ8ßÈ—`•ö±¾7Ð>Æ2\¬À¸T;€åF¾—i°«µ�p!ÖhýoœºNûa�ö!.Ưµq‰‘_Š Ú‡¸ µ±—k` 6i`-®Ð>À:\©íǯЩíǯqµ¶ëq�¶ðí}lÄo´ý¸×jïc®ÓÞǸA{Wb³ö:q£ö®Âí=\�›´wq nÖÞÅop«ö.®E—ö.®C—ö®ÇoµwpnÓÞÁfÜ®½ƒq‡ö6¶àNímÜ„»´·q3îÖÞÆ-ø½¶·b«¶]øƒ¶¿Å=Ú>܆?joáw¸W{ ·ã>í-Ü�?ioáNüI{wá´7q7ÔÞÄïñ�ö&¶b›öþ`ä÷`»öþˆ‡µ7p/Ö^Ç}xT{÷ã1íuü ÝÚëxÝÚkø<®½†±C{ á/Ú«Pð7íUl3òíxR{c§ö*ÁSÚ+ø3žÖ^Á£xF{�áYítãYm/ÇsÚ^ìÀóÚ^ü»µ½x/h/ã¯ø‡ö2þfäOb�ö2vb�öžÂKÚKx/k/á#ß…½Ú?ñ,^Õþ‰çðšöOü¯kÿÄóxCÛƒÝxSÛƒð–¶ÿÀ>m^ÄÛڋ؃wµñO# ïi/âe¼¯ý{ñ�ö¼‚µàU|¤ý¯á€ö^ÇÇÚ xŸh/àM|ª½€·pPÛ�}øLÛ�·ñ…¶ïàKm7ÞÅ—Úóx=Úóx‡µç±ßÈ?Àíïø_kÇGøV{ŒücÕžÃ'øN{Ÿâ{í9Ä1í9|†cÚ³øǵgñ~ԞŗF~}Ú.ôùahÚ.|Eˆ¶ GÑžÁׄ֞Á7Fþ-a´gp”°ÚÓøŽðÚÓøžÚÓø�˜´§qŒ˜µ§ð/"jOá8±hOáGbÕžB/±k;ÑG$m'T#׈¬í ¸QydÎ|À0úŒ¥‚JŽ,Ç Íòœhx�ç8�yð©�ÏòÃó4ÍÑfžçy†exÎÄqì@d¥Ÿq'E[|Ö_²€Å"œ„ –Ïôæ38 0qœÉİ'šL¼Iày“`pâxžÕqâiQljeYž7óÜ $Lÿ8¥®8ÀjRGtŽ,À°àãd‚‰ƒI€™çMf†x‹Ù,˜^0™¬¦ô<àNàYA`ž±‚ °+ðfž? ''&a—A8Ùíæœôe1xSj˜LÐ=4Ñ QD‘åÍ‚Í"šD³`Ívsª è¤ÓéÈŒÍd2™8žÓé( BB~0ž™9Ò%HÒˆ“Å$ˆ'»Õb¶˜M&‹(™aNOgÌ&ÎlfYk7›ÍfŽçÌ&«É4 Ë ð™dîÏúK�eÑ�«~œX‚9ÓÛ¬Oeáaa5™,VVM’Õj¶Šf³E”Å~œDA4ñ¢™eͬd6‹ºL™M¶ÿ3œÄ �NËNºü°1ÝA+¬¬ØÌf›�,f‡Ýf±YDÑfuZ @ú´“ÅÌ[D–YÙb±è\³˜í¢y¶Aàã™™#]š·Û6 ‚pL–Lo `‡Ý»vQ´K¼É&ºdÉ*Ù,»Ímƒ5½D�t‚ÕÊqÎiµZ­‚I°Š²E„„½ŸÉÚŸõ—fÀë•ÔA—Þ Ñ–Zl6ÝŠÉ"d;V‹ìDÉâq:ìÉj“%¯dÒ§³[ìV“ÝÆóV>Ën·ÛÍ¢ÉnuZ­–øò ðƒñÌÌ‘.E �pÒå‡a‘I–$À §N.›Íé6Y6¿Û%»vÉå8RÝ»l•ífY»à“dY-¢dϲÛ!á~0ž™9R:ƒrrœ*ªË�`�UNw�eÀ ·.'Üv»;ËduÚ³=YŽ,§$»�9ÎÌù§ä°9$Ñ! ‚$ô“V‹UtHI² ÀwŸIŽþ¬¿´Á {@tù1Yasdz;<6xÜðʲÇg¶¹¥<Ÿ×åu;œwÐ gz‰.»K¶¸œ&“Ôãt¹\V›Å)ûò ÂxúIq"í2s¤tR†B?ÅÉîLwt:áäÐq²»å ßçòe9�Þ¬PVz8\’Ëau¹tœr]:Nv«Ëáw8Æ;ˆ$'àäDH§‚ê2m¶Cr§;¸Ý€~ ~/.§?Û"y�áœlO¶×�ðx‘•žÛãð¸lž,Qt‹ùY�Ç.Ù²\¹.× $ƒÀ¦]fŽÔƒNÊáÃB—iQ†Ó›Z¼^ ¹ä�—••´:î¡¡ ?ðúr³‡gg΂=~—ß#ù}‹ÇRèóûý²CòyBÏ $rûÁ$¿žù?è *-ÍPQ]¦-N¸üé~¿ñfÄ…`ò½ÞPØîÊõ g‡sý�P^i.²S}9YÙ>Gv¶Õê·ÏÎÎÉv¸Ù¾Ÿ/k~høLÊîÏ�z9h0¨¢"˜6Fi™¶¹�•“î�“„ÎB8ˆ‚€H¡”ô— -Ì+ eç U„ŒÅë|Éóæœy¹6[¶­47//Ï•åÌ ÍxàIóopÊ˰ÿA'%{HgÛ¥/�í‚÷Ä1LziÚÁT®ÝhŸê0í;£?Ô½Ù.8©ñZݬs@ëÁ”„ôŸ±ø3>Á^£z{ºù·¸ wãu\ú‹!‹HÃ/¶þb"ÓH=)'aãþTRC"ý÷qÄ ýý<ÄF8¨øŸã¼‰opœpøÇð4¾ø™‰•A0–“ $LŽ£ßÿ¤ß x D«¸Wc56b^Å7øtðÆ<†¼‘”t¯Âcx—àWéÆ{Ñ‘¾»÷ào±‘áldjdÚW�q;p>Â=ëú˜ô“éÆ_jäªåd´«eö@æîÔ%¨O#cðn=?€ÞÁcÕùêd&6`:µ2†L"Ù8€}ø'va®Q¿Q¯è[Üw§¶^[Æfße^dmôo6á9¼‰õPðŽ@û¿¶úÿ¦ÿ¦ÿ¦ÿ¦ÿ¦ÿ¦ÿÛi=žÀ�¸QÛ¨=ˆf ã\xã0NmaÛp-6b#faƉX±Žä�XˆGNšåut�:ãíñ”ÔÎÀãxŒ� $ÎÜØ1sFrZó“'MlœpúøÓÆÕ×�š¨3ºfÔ)ñ‘ÕU•#båeÑÒ’âÈðaC‹ + †„óCÁ¼Üœì€ßçõd¹]N‡,ÙmV‹h6 <Ç24EPL¼Š·¾¥á\ÅWߦXÂcÃRP±L>2)ªÀ…å`,š,I÷R؈g£âjjÙ†ÄȤÂENî2Y¡ ¤oB +“Á…)P˜‚ð„öehsK(,½èoO&KŠ}K(P¨…*8]¡ º`B{°C‘šZBzƒQsº‚¦ý¯[ûhd( `d(PÐÜ¢äf“ÉŸCòq@Ûyš“I§´Íâ««Àµ –�¸õnGFBA�24¢P’‚c6DâúF!N…¸')pœBöÁÈŸ¡ACǹᆎ…Н¾£m€¦GR ;ƒ�Í-r, +H7*ÏOiÙ&šëÃõóÌÉ’bØfëÃõ¢^¡XÂK·ËbÜP–†S¶Q¬%ÅŠCG·Aÿ;WI\Õ¦PᱡP¨¤Xq´tk;¯ÜÅÉÜ9Sw)$®^áSH*‰vW·ï켺[œ¶ˆ¥#ÜÑ>«E¡Û“%ÅÛ@4,˜¦d76ÍhQè‚ý¯mAPg÷X#Ó™lXì �ÕÛ´)tAx¬Îôê;ÌkÓÅ„´…Ç–+¦ú–M¡�ÅQß²©A‘#Š5}æ"�" +zAÃ�0ѽ »©hOE´Ñ=åetØI”ÍßÏïU9r\q-y„ÚN]ž„¨IÎI¡H´Õ�cH¨2Dmï{� +“GÞÑ^ÒôV¶ 4 EÓt>*t°äÕBªŠ¢¨ a ÙDB„ÞÚ× ~Ju³]ÿºˆ»BÿMDƒv�9“ÝdÄÙü•�$‰iIrZ®LP¬ùÖ$ËÃvk>ÔFà­�oÔßãˆGÏžÝÚS^Æe !=£óe)V!KTƒ +â&<9ª~õõžÝ»|ÔKd%ÙÔW Þ¨^ƼÝ×§ÈQ¢ù¹R;ÈðìväcU¢Î/Šï•6[î• Žbœ§K Ì4ü¢Y4ßšÅ�;Dßš‘H¡M„„|v1Ó‡Û-Ýštó¨�ȈyuÄjcÑÙ­Ù�¸7jĨŽEu^ú{bÑ9�——UËY±ŠªÊ…ápe,X9"œÏËU±Š,·Äº³²Ü.&”¿òº�oúã /%Þ7¯»âæÝï~§¸EQßVûÞ�ç­m ¾ÙñP+¡&>w»zð4ÖùØÆÝ_èß04iŸ3Øí£�X”¨­»Ê1ò*ÁÍ +w +аS ‚C€ÿK”J¥ÁÒDéu¥¬™.-�4äËÜl,6ztž5oØmÉ<Ÿõ´Û’V>M~}5rÌ�æƒ�Gu9‰K=ROy™sĪº°°rÄ*V‘K¹]ŸK»]6*œ_J¸r©XŪrD)ηQΓž›Âãž¶ø¢†Kîë˜ÿ¥c×-wîø!6ýeÙ’¿lšH"¹#'••NÔË’É#ƒÅ�ÒÚð�1Ñ€?Z;¤°¶ÄG~]³äìFoÕ}ç4_=?Ÿ×9eþ«¼�mËFϺyqͨE7_X>¹*'·jrYdr™šTX_ž�]QWXT_ž�S^¯Ëådí SËnG.*М(ÎC'¬D¤­ÖÃ:Ý žw—Jw$­(%º´”õû‡Üšôó†´úÊàz\ÙXÔ/e¨+/#.ŠãÂùEÿ«‹8�0r¤ áN†©�v×g›•µËîø}7áÎ~ºeËâÑ6îX¶rÇúõ©ìŠñ‘a ÙÙ±ñÅÃÇ–hÇ“ê«//I˜ ï¿B]S·òîöe;.?}æÇMÕíㆠ©m‰�<«&/4r"¡PËÜËL�x"�!4ŽHtM-¥wÒM�ÒÊÆpe„�hëžX4¦[‚=ÒžÖeޏ#.;âåe¤’¸‰›0÷öΠïé›OuÕ’ûï&OVpêQP&2÷2ÓÀ£6‘Ï‚£‰kâ¨�áxƒe ¡ÓVÕ$öîça™H¥qé°¨Ûú:è{È÷êô"2$÷°:ÆhŸÓIv;"…‰‰av�X8·/ás<œô1‘(¡Ì,vŽ|¨l(M»sw­eVÊjíŽFV÷ ¯õè ô{¥¦ +Ýð�=»•¤ä¹z �TŽ—«ªRÒm£xíveyèü¢ÂÊÕU± +ý`‚çoCª†Ƈº²†�2ùÞÆI�¶·Þ¹ª>»ªiD¸2ì°Š+›*+++›Î1"6‚Üá?5§tbýèÜ`uõ¨!y•…Y§Ö‘’ÒÒa-W¶�žÛ2%’SQ^öVÈê„²Š±ã¢Ñhéiã£QPú;\öz¶ <ì¸2‘cç 8bá(Ád‰hµÙiÆÂˆf“�±Xºµc‰r“,,GÑ‚ÝN_Ÿ´Û-¦~zôãßt,?tñCK×®^Êv)w®x0Ÿq>±éÙƒÌêígÞÞ÷„zù‚Óçè–c+ÀÞfpBB4‘ ÓfYas’ÐÌê •X­Óšißnàg eø³$H/Õ«ž­þáñ;_ùªç ¶«¯Aݦ.e6÷.ïÝ·çKÝooMÿÎPÄi‰aœis’ãÌ1oNÅnNR4#0BZ¹¬œyMÆ«÷èj�Å¢ÑÉS^ +ÉýƒÞ­ô(U ¯«ÊÇv©ÿRŸR�«ÝiÈô‡Æîå”D¾‹x‡@6'ša2»$Š[äËxŠï™èˆëÀH?(úC•#{Õ¨úWz4³Y½S=Þ÷*Û‚ ÚAv4»>ÌJÄ`–Ìg""Å ãõlNz½N�rÞ�¤œ¢h¬7$ÆãqK¢ˆ5nw@ZÍ¦Ä n8ߌ“´\]Rg·¢µ€ ¡S¿Â#†ó)·++VQ­cÆŽ~E}^½G]F!ç~üà=Gv÷xjÅXõCjNÛÅd-i"ÍäþZuo›úãÛï}"^}ûdЇ]mp&žÈèë“Ç +×ç—ë0ÓmÂB¬³&È– +fЧ'†ÚÚZ�B'ó‚]­>Ñ÷ ¾Ÿ¤šÉXj|_7ÛÕ·‹ªIÃ"�½˜ô¨>­ƒ¢Q[K¢¦¦ õa5CÚAê8Û †%\'ÐÂõIÚ)Ò,kųÙf•ÓŠƒÚ4­Êˈ„´³’åu\ý®oYÛÔsÞ#uT\ý@ýg‰Ö’ñô´ôš'²]�pjbè0‰Äm$NˆÙ&–Õ…ƒ¶Û¥´d8̃%C·-q]4jžxyimmFHaQØX{¬ªš„;Q] Î¶øYc1–lr5ù•j¡–8F÷Õ±]}3²GPÓûÒXÐúY,O˜cè�níÈÃ27É(%£üìa[º´¦K‹Q~ð°˜.ÍéÒd”;6Ó�ñÏ ¨‘.Æý¿—¨­íç}¼÷~RO9Ù®¥9Äsl¨J ]U.ªÈL†òDv8hƯó,Çi•Öå2™’£­=ñ”0ÄQ[›!‡<¢:Ìñ$¤“%Ë­!Yƒ4<§>e|.UQ�©÷ÛòLVõ=²�„%.�K +ÈzÆU÷n8¥·œ~¶è®×îì=Èvõ>8ÿœU-tSFRÔ¿·À¨D¸ÚBŠÄj‘"¬ÝÁ˜M3MìX+Ën‘ÖMe&ÊÔ�^<6ˆa)~ VX)‡ØÕ}ÛF¸A}‰Ì¢âE!F åôÆ3†N¼­÷ÛÕ{ó¨S*6Ó>Ýrêzþwv;Dxôh Žë“pr–ë“cZt·Ûg_MGO²™lJi�œäs†Öê¶“¦ÔÕËH'i 1r©ºJ}åþ矿û�»þæ#ד:2�lUÏWSTç0Ö^yýØ×oì?–¶ß̆U“t½ñ»¤(Ò”ƒ6ÿ.IÓÜê ­ÌFÙl‘¬ Re©(§bJi³¦!(» [¬‘ÒÀãT®º[ííZK(U%‡UÛ¥V¿¥~G=¢žúÑ{)ÔrSÙíp££A‡K† d]ŸäêäpÈ.Ʋ:˜Oòó‹ü«™1úäxü¹AV<®ë,,*”¥êªPГ%K<§ NGçóœÛåÑ-[Uåˆ"ƒJO?ýì.2ŽÄþú·gy OÎSkþ6{î}ó:::îþãœ9gÏö=ÿ9•L}õ•ÝÏ«�ª½Ì[9õ÷Où˜?¯[ûÊë—]vÑ%¯¿¿ú²´ç;Ëøö'ÉDyÀIœ¦àjý«2"Š�!Óš„a¿EÚì!О¿Yô·'Eš˜�Õþ4hò÷;ªG¼U×.º”‡ÓôµQ¼;—ö9µ 0{–zÍ~_i4–{–úW +”¹tÚªÓƒ5#cî¾;®^P›ø�,^õõ½Ãv©—4®�?Á͘KjB4Ôe5£g<¡kÃ,í 3‚ÝŽJ\�Hš+ý•!ü0ÂúÜ>Šñº¼”h'&1ÊF69S©<„ÉŠùó²ònLf1Æ‚M4abÌ�ɘÓï/²Z&¥«ƒ&b2UŠ«[{¤×ôXÐ`žôœ:7rJ§ÎžÝг[Ó©ZÎÊÊJE™è*Ë#—Ò™hÁ“‰² +çœõâ‚Ñ3Gç–M½ îÞ?Ìøí‹,ýŸÓ‡œ9#9´zƘüÂqµÓ¯œ3bæm/-¿ðõj’8ýô¬¢Ê¼áu#GƽpíÒ»”²Õ×}…>‹»°24$+÷™2ýYý~^ñPý{/f³±Ç)Ixha9vs’£Á‚¥Ö”Ñ„¦ÓÛøžXE4ãskœ=³Y=G}B]Ȭ`6ÿ¸˜ÙLx�ƒl%Û+ŠÊt}’rZh–ÆQ´ók‚LC1)ƒÛ£»H]ˤPP–Crª`+ûîéë&c‰DDRO-ZE×ôîT·’&z¢Aß%O6ŸíêõOSßD¤Ÿíü1ÃÞŸž(¯ +�*)r‘"+)ÉPóH3Ui"EI‘"RM¨a "mN»ÆÑ€�hÚôg’‰„Ò;é 9Ó¶?U:ùcêFµë°“aLòQõ*uiÁÊqŒ�0dÆ—V3ÃÈÏéHÒ·ŒOΩí]Àvõ6Œ>gÒLú±ÞÑ•óΘBÿU§�þ‰z5Û7F$òŠÌ¤�"…„ˆ´É%2fQr¹9SG�ÉÀÑá‰G£ýˆ#üLýˆ…[­þê›�áýÇÔµd·:›\¹Çëd,¡�ɵ™¼êªWË©=Ôµ96nøTr_Dÿ¯Ì†%nL ‡ ”ÈQ1öÒžeXfs’¥ÁÐCSHm%x‘2B¹X +¯´=©Moúu… +…*u1t“óÀ�«©ý}Ó™‰}åÔÞô>Âÿ¹7¤[á¸v�ÞÇøàF®OŒx/O™8G‰~¡=ÄN‹žÓ’%‘²²bŽ“¸é6çæ$›µÑ®Ü}KÒ)ÙÅ,lL©: Ùý— ÑžxJ%bý»ÐHK™g�ÚkígØÏ¶/±¯µ_k¿Ãnj $ S®+�숟=»5=œ*+'úF5ª sáüÂJ© @?2ª¬ªŠe¶’O;?zŸú:sÎ [þDÚIÖ£�ý¡î“ÙäQõÍ]�‰äÒÍÜw ^ZpïâÃù#ÔÆ] ^תª†KõUoÔ2²‡ ! ‰¡´›¸íî-I{0¶$MËú ·ÌKy½y”ƒÛÐüY‘q€i¤3ú^v§vo± +‡[¢Âùt¿{çsäYFÝEj˜•o=÷Æñ½=÷‚ä¢U‹ç�½zÕ*öPß%«GiP_  çþú�·®½ö7º|Ž×Òל™Èu»�”sK’Ê26þ[’‚$f„SZŸÚö·ÆíøS›Ù.œ�Êþ}~ŠhÕô5ç½pH}—Ä ÷ç)s/¹âŽ[6^¸¬` Éýˆ°¤¤L=:Ꭻ¯øí�N㵃̒4�F&r騒d³ˆÛæÝ[’¢d‡L°ÞfËó®RÁG,ÖO£ÐݘÁDªrbž˜")¢¤Ä,Qw1‹öîü‚P{Ÿ›Ì�õ…­ /¼`^ÛÅ×ÜCìߪ¤â7T{/7©cîÛtCW«Æ´&ªÁPIJ,M<äö¤Ç&xn_&Ð7'…,›ë–¤MªåÇùò £ÌA9>Ù FÓ{9mMï(ŒH$å–ËËt1$¡¬PEµÛ £Ž½Ã­‹!Ç39}1Ý·î7Ž©‡Éз>øN}gûÄ%rÏþ¦�'ç÷®~ÿñèw×ÌÖyYÐ!Ž� ÓQHDäÌnÁÂZ­–›’V;\[’å ¶$„çË ÿØÂÚL‚fb6\‹î\ZiSZidCöŒ3›p¾Ûsë›…pe¬r„~2C‡F�¼å‹/Ôgxàã]m æ¸÷‹?ïýœö|¾ö¡7\ÕŠ˜gÝwý”ˆë3Â�ŠëVõšÒ~åÖ-ë¶Ü ¢ÿ×f{2Êbr[;³%i×6µ�§EØÐ¿»¯H;Ùú†¸Ê:�Ýéh,”™Yê³[§-04xÅßÉ,j܇kÚûºÙC}—mSgét\�w؃aÇÐD–Õm³s˜;“ƒ‰6Ñ– ©³·�=¼F¤“_hð)Ëíâœz QÐ4~Ó”yó HwŸÝpÚŒ§�Ÿõãl ´KÕ¼4 ¯~º('—ÇîÚ’´g{ÒÐh“l¢eˆ`VY•eàŠh?Ä´dû÷œÚE…ó‹*³b•ƒqxoCs]lË ˆ,= É=VðÃ¥i¼‰= â‰aÝf;‡ˆ…Xs¾X!R¢h³̆��߈|cÏUÈñV}W+/FH:ê%!ÂlR7ª�§ %)'«ÔëI¯Ê°‡zG‘}j^ +"yŠ=Y qSÀ†þØÔˆ‡9DžÒ'`¥úsûr1/GŽ”C‰1Én‡=›Ù’Ì–ü.‹×²%é•Ȇl‚lªsI 3-û… S^дahYê5Lê<»"B¼ÒQOJèuq× ‹eüm¿äôK�;¦Ÿ�zt1âö«Ïn�’÷½JòÔiê[t¢ëu‰’<Ã'«Ã˜$d>9�ñÉŒ�ó›üºWî÷ɹœƒúŸ|‚%Ò}rfå'ùdi°K~íïûú^yüÜ¥3­z¥ýÒU}ÛÙ7»V¿úÒðÈ#šÏ½ü�·Û攵Æ,10ÌÁ¨DÐê&�ŒG´ÛSþÐj“i�1þÐëW?c“3bƒgu‡xÞËO}I¨—ž˜‘rˆ3^´rvÇÅê0ªãbý–À°xŸ7w\ñ‡ÖßxSJNèã€]?‰åÝ‚Ý\KÊš9�’Í܆A'P†ËÛÓZa˜¡ÂÁ2¢{�øÄsV´i|¦"›:�wó¯Uƒ¿½lA�v�žÆøP�‹Å|±œÏd•o$„)gnI–gmôûs²rnIfI~~ñÆôFuÉß G{veÜí =¡¸Ä¿ÖOùv #ƒ6ƒz›UWîi"md)áZIÙO¼¬<VÁa)� Ý……? ë&ÿ¶aZ{qCsáèÖÚPãê»Î{õØš+ëòª‡{‡œrZ¸vþéEg¬ÿÓ¬ûÑÒÒhîÐ\¯ÝS9nVíôËÎ(p»Ž†Ã¢;äΚã±d�7ûÔ™¿šR kå0í u„­†s#ítM‰œ7%�N™§d}Ÿf6ó6Näyî¦$o¬QŽpVNì‚ ic–^Ú³·F3nTÖ=úÉ'¶\8(^½@Ö=¼+VQMw�ºýž{ȨO?][Qi) 3É럿7CÝý¹:çNã�»þη™AÚr¸i kÑ%UìvÃt˜"}ëלԖÍ8]:©åÓ¬>ˮܥÞFF=pæ|2ê¶?“‡¨sû¶ï[5Ÿš¢ÿ‰™Æè¿ÜL$†Ñ$N‘jB†‚Pn‘¶Áæ0ÄAñtfãjeèè㥹#ÞÚŠÚŠLh„ŸéˆŠ™¦®WoQ·�æí¹,Ãç>Ê  ú®<¯ñ´…Ôjÿ- \£ÿl«)«ò“"·€Šd¤™T›H•�Ë0�‘ÂÙ=´H™Ý§h?)þ¬�ÅjõHªupú3A¨3SrMê>õ‘›íÇ[ïV»Õý¤î3˱V…”Ü®ÿ]ܨãJµÔœ6¹¼o+ƒ¾Žhý¸2ê–¾ßÌSN¡nÓq ë®ÿÆ­91"n!…REÈ0BhÑí¶Ú9‹L«ôãüm§(ŠòØæXÍs +Å*‘£­=o_´ö> +endobj +812 0 obj +<> +/W [0 [645.50781 0 0 275.87891] 11 12 369.14063 15 [270.99609 404.29688 0 443.35938] 19 28 575.19531 31 33 707.03125 34 [437.98828 0 703.125 641.11328 0 737.30469 532.22656 520.01953 710.9375 766.11328 316.89453 445.3125 648.92578 511.23047 957.03125 790.03906 758.30078 614.25781 758.30078 652.83203 560.54688 585.9375 723.14453 666.99219 1004.88281 655.27344 0 606.93359] 68 [538.08594 620.11719 479.98047 619.14063 541.01563 383.30078 619.14063 602.05078 284.17969 284.17969 559.08203 284.17969 916.01563 604.98047 611.32813 620.11719 619.14063 397.94922 439.94141 389.16016 604.98047 541.99219 797.36328 552.24609 538.08594 479.00391] 104 [723.14453 0 0 0 538.08594] 124 [610.83984] 129 [604.98047] 137 [627.92969]] +/DW 0>> +endobj +813 0 obj +<> stream +xœ]’Ïnƒ0 ÆïyŠÛC•(¥Bê HöGc} +†E! +é�·Ÿ°»VÚ� ŸãÏú[äUQí¹øpS[ƒç½6�ƒyº¹øm˜ +x§['<Û±±LäUQ/³‡±2ýÄÒ”sñ ƒž½[øæÔMWØ2ñî:pÚ |sÉë-õÍÚÁx.Y–ñz&òׯ¾5#p�²]Õ�ñÚ/»K^?3¾ <@Vä¦�:˜mÓ‚kÌ,•RÊŒ§eY–Óý»?’êÚ·ß�Ãì0ã©”�ÌVR1R•D9RX íOHq‚TÐ]œ#�#¤Q#%Šˆ2“#éÈÝÝGòçêÙÄ ¦Iª$¨•äGI +RAPðÞGIA’+’‡$ÈH@‚ðLÁˆ‚{üEŠ‚J¡*uQæžž!V÷ÈòúÒëF<ÆØÞœãqmptëд�ÇfÙÉ®ªõûª ¯ß +endstream +endobj +52 0 obj +<> +endobj +814 0 obj +<> stream +xœ¥z |åýþóα÷1{ïfsìf³¹6÷’ B²ä"$’  —œ‚àT ¨D j´–RK©µvÀ+µ(b½¨'¢õÂPŠG)�}ÿ�Ù ¤´Ÿßæ3ï¼Ç÷}ßçý^ï1@ ŒŸ��W×cº ýÚ'UŽkYÙr훀á5€?2kQÇ~br2À8<7kå +ϤÔj \0Ûæ,™»è±7 +߬" Þ0·cù¸áˆNêeîÂÕs¯yù; Uœ¥]�‹®úÀñãh ~ ~¿kvGç©Çî©È:]]³;Ì‚Þ �i’º­¸ê­ÍF5ÀgLháâY?±'þ0ï$qQÇUK¸ í;‰๢cÑlëøìòà@2–,^¾‚Va@J¤ò%Ëf/yO}Í×€ú,À½*h`�’R!ñf¹vl²1`ê àdjÐZ/µy‰‹ª�a@{×ÙɧOk;T ]@±MîƒdÿÒ¤¿ ›a,ùn•\ðÀóU#¤÷ç\3{vòÀ§ÚÍ,0PËôÒÅr­DB¥âûø ý€¸¥7–±¯ccV1Œ–g8†S3ì:H8‡®q<x<ÿf¸‘èU;Æò«Ã‡%>ñ}gd†1ˆÔ´‚•{µ‚ƒ U.WÁƒ4�‰ †££1õ˜Œ)˜‡%¸kð~ò”Êí¥žG9 +cP‡&LA`Ù%ýô¿Ü›é GpŽÿËsÉ»˰ wãn<8tÏ÷¬è½^¾û�igngža>gKÙR¶�m`¯aog?æb¢w'÷ +÷ïçkø­ò½ïü[áT,R<¡t*¯V>¢ŠWµ«v¨v¨^Rý¤^¨~JÖ´iÚ4¿Ö hÇhûÎÝ.{¿þ_îþ—[— óH‰)’„95€N\�˜�3С)g�aÑ8w^œ‡±Ñ¸’ýMÀlÌÅbÌÆDŒA&Æ`:°ó0 “0˰ó°WÀƒ|d¡¹çÕñȵ<Ô:?~1åïáAr�‡|x0N¦Y†ÅXŽÅ˜ƒð ‹± Kä°+¢}gÁƒQXˆ…ð  ó0]X�årj6–Ë8Wb6:‘ŧc× b1ÁË+³k™Å´FŠóWGT– âúKÑr ’�¼ôEž†ãü45©=7Ð;¹í¨åãp#¿µlµìW¨å×ãFƒ2-÷ +jÙ‡Q«Ø‚ZƒÚóÛãv£–= ?—�ýüõØÍ+pH¹ΕßB÷þ'lÜ$Ôs“PÆ^+¿ëÙÏQÏLƒ†›D?à®D.cF»<îc‘¸âärkQÌÕHôô¯2ÆÃ²i˜í˜É­ÂÌ‹û`ïýÏýÿ·KÂô­+ׯùÿ«þżŒÃü1Ø!yXç`ÈaƃÑÞ åôKzãP„Óè�2=ÂODÛ:H�󿆞©¡ß°­Ðô›Ëõ~p0¦Š>\$ÙÍ^}/°ë~.…ó®·ñöÿaø"v£'ß�ûÎåKñ»Ñu.}¶F‘E,åösÿûuG°Ÿ‘§ ó³²p€Ø�õ¨Å4òïñïá´`ZþÝǺóh_•Ci”WaÖ k°>Z¶^æä²EòûV¬Ç­Ø‚¸ƒ¼‰±X�NìjLá˘�E‹Ìà ؉u¸ ø>˜˜$˜XÐï°sÿÍ÷ÿûu fa;ö…7†×¢�X‰k˜Ÿ g=·�~�fTc>`¬r^8Ÿá)lÁF, 5}tÄîˆ}ë�Ý{õ5v÷Õ׸^Ãîˆ]¹Êîˆ]´Äîˆ]¸Øîˆ]p…Ý½àŠµËbV\iµÅÎ�oµÅΙgµÅÎgwm\ãZn_Sáò®®pyËþBÊA`$£°ƒŒC�<ü�´@q¨Ÿ„Yy'¥Jﲇ2²#oG¬ô²'Š¿8ÊBG3²ŠCGݱš愄â~º/dÙç+½›–^<¡‰ 4}Â<¢V_ü8a ¹™ÀÀYMàÌŸøÀÉO˜ÀþL ôw‡«ø½O˜@?Ý÷Ð'9¹r#®Oââ‹Co;Åß<Ížîcwõ1�¾^>ÐO�<ö­Õ^|k+ǰ؋�õr�§H5©ƒ©z´WèéMJè§GBÚYNWñœYd{¯ÔÁ‘‡zý©Åý„Á\|ð ̾Ç^ôùŠ_zAއ„Z}ñ××1�=bº.2¾7�f¹òŸSRå&c·ÆÇߨͺ7h[6°�õkIàÚë¸Àuäá…Jg:]Å37�Àæ $°i lÜ@×oà_mø×fÞâ.´9 l¶|›y˜Í´éòlê\›"ÇÆfÛ�eG†“0’"R ) …0@KŠ0‚¡îßÏˤ´¤#H¦’°Èp¢ØËÒ„Q^¢!Z‰Š¨a +¢„ ˆ +Z¢Â¢BÝ¿ßO¾!*œ!*( %L%l!°DÚÊÒ„äCjŠ1=`È}†$Ÿ1>ÁàI0.I?’Π„I¡¤%I;’8£`Ò©5Z�B©Ò±¯atÉŠØëL0²eìG,û+|ÆMâôNeŒÞ&8ôfΪÏv“Œ’ô’Ô’ä’¤’ÄOI|‰»ÄYb+1—KÔ%ж% Áf"šëP×\.ZHê&”‹Á@]?ëióu¢ºajËBnnƒ‘ÙÜOÐ,r›û4‹æŠ)S[ú‰K*Þè~„@¬kßxSk 'vÖMh×ŵŠyRd[\+êļFÑí+\|-—ƒåƒ©ÁØžÔä*1½ªC̨j¯” VôEÕ¼~¢©š×ÑO4¾Ê~¢Š¤Ûû‰ÊW­ÞO†K¹EUóÚûI‘D%§ ätA„ìÜEV\ù3@A p.ö_. »èËê&ül˜{Ô;šÊëDUS�¨j˜*ÆøÊëÄšêÄ‚†©¢ÎW.﹈tA‡S* +Ô4 544 �j¡¥aè £ÐÃ@`€‘ž…= &z&˜é˜a¥g`‘C+ô lpÒÓ°Ë¡.zNÄÐÓp!–þ 1ˆ£ÿ‚ñô_ˆEýâà¡§/=…$ÒSð ‰þ^9L„Ÿþ>$Ó" )ôŸð#•þ„d¤ÑŸ�‚tú“´s¢?" ôG¤#‹þˆ²éÈ@ý™È¥? yôdËa†Ñï‘‹|ú=òP@¿G…ô{ C=‰|Ó“(Àpz…(¡'Q$‡ÅIÿ!íÎè?0eô(Á(z#QNO •ôÊPEO „*úF¡š~‡rŒ¦ß¡5ô;Tb ýU¨¥ß¢uô[ŒÆXú-j0ŽÇŒ§ÇQ‹zuh¤Ç1�ôÆ¡‰C=šé1ŒÇDz ˜D�¡“é7hB ýÐJ¿A3¦Ð¯1Séט„iôkLÆtú5Zä°3èWÒŽ’~…©r8 ³è—hC'ýÓ1›~‰˜C�¢séQi.¦G1Sga>=ŠN, _`6Ñ/0WÐ/¤Ýý]XB?Ç<,¥Ÿc>–ÑϱËéçXˆ+égX„•ô3\!‡‹±Š~†%XM?ÃR¬¦Ÿb®¦Ÿb¹®À5ôS\‰ké'X‰ëè'X…uô\…uôc¬Æ/èÇX#‡Wcý×`#ý×âz×a=‚µØL�`n¤a=ºéGø¶Ò�p=n¢an¦b#n¦áÜB?Ä&l£b3n¥âFÜF?@7n§` zéØŠíô}Ü„;èû¸wÑ÷q úèû؆>úzp7}·âúnýô=ÜŽ_Ñ¿£;èß±¿¦ÇØIÿŽ;ñú.îÂ}ô]ôá·ô]Ü�]ô]܃ßÑwðKì¦ïà^üž¾ƒ_áôìÀèaü¤‡±ÒÃø þDã>ì¡oã·r¸ {éÛø¢oc7¢‡ð{’Ã#8AÿŠ�ñúW|‚ïéóøT?Ãôy|Žéóø?Ñçq§èóø§è|…Óô¾ÆzßÈá1 Ðçp\¿¥Ïá;Bès8AÝ�–îÇI9üžpt?~ <}?%}?}ÿ$jú,N }ÿ"Zú N}gˆž>ƒ³ÄH÷a€tÂrH‰‰î 5475Œ7¶®vLÍèêŠòQ¡²Ò‘%#†ä æåædgefÒÓRS’ýI¾D¯'!>.Öãr:ì6«ÅlŒ½N«Q«” +žc‚ â�-UóEWE»¨óUú�¨«?1.[„Ùíõ™<ÁìÖÌ(•ÈDXêDkCË„ŠZEEàb’z‘õ '½"ÌãÜž*‘ó‹œßWÛÑ)¦6µx}ÂÛîså­­™bLE‹×ë¿ÈøÇˆ¬_dýµžNQhhñJrÎ -ÒÓO?)òºEy[Ý"šZÄøÁdkë¥@>Ð}Á¬'ÝÂ�«¢R„utŸˆ°Id'Š ¢DL ˆŒ_Q"·†l‘XOŠÄ"Û8æ »�ª)ºª:çûª:牮ŠÎö!žžˆpÔëéöt7µ˜‚n¯W]'¾ÐزG«©ðUÌÖ´ff@ÎÀ�¶ÂW¡•2D�oÉ¢+%r„ÑU ßÃ@¥ÏÌÍÜ*é™/†¶´‹ŒßWéõz33DËPI?Ý·õü"ˆæÀ`̉E@ˆŠ +Qá™'†:Dlñìɨ׽µ_ÀÌö€®Ó×Ù1­Ed;Z33ö€õWu5‹±u SZDÖ_%=í]IÜ•r ÏSÕåéöUJe]í"ë÷UJB¿ ¿³kv»¤&¤ÝW™™!ª+Z6y÷¹EsE˦*Ñõ¾JQ¿æ37Û]åœç‘’ÝÝ›<âŽÆ–óK½RØÚÚêÌÌðtWùªºÚ+33ªæ—K"É>'6YÇtÊ méðˆëfÎ�è^ÇÖAý÷v ¢î'¯Ûëõz%ñÈ£¬ìlŸ/Ažß! ³j¾§{Ëly¨[å¡y½nOÕüJé‘*zªDL�SZªº|UCzº}‘õ_\×ë]©bww•±£³<3#Yt†ðK6á‘ñWˆ¡fù…fYž*1ÔQÙÍŠL‘ªI%í•­­ÞˆÜY¿GTú7ñY>O·Ô¢Ò/Z‚÷9ofƾ̌º¦–ªJ·Þš™Q×p.›8ëšZº³�»#<ª›à«kŒhA×`ÐÞ1`æœä½ÞÖ(½ÜêA§û`kfFµ¯º½»»Úç©înïîè§ëfú<‚¯{�N×½¤ªÝ#[>éè§Olq‹Õ[[E¡½‹ ÏÌðHúVÝT'Z§Jâ©ötuDœE™Ï[äöšZiþSqÔÎDe…¨�í¬[8–™!ê*Z¼nOµä^úé‰"·(Ifê1±¥_À,Ygå CÄ„‘qK–¶ú«æMˆ2ÈíTÉï5Fs[33¼^Ɇ¶ô‡033Ã+®kl‰¤=˜éÞ‹Pv UdÚ¥’}ƒ%¶‰RɺÁ’sÕÛ}ÞÌ §´5º¬NŸ¯ÏÝ&ŸÙSœ-ó_v·�â¾æ–~zªHTEÅm©haÝL4ƸY)¦ øO‰èÈ%žˆ©�nÁçyÍ' +‘¯hÙç.iõ&f’™!Ö$«aüÂk¾‰ä;aDR"»”‹Hd—Î:ŠDb9§<žªîö¨v�?¬èÐÙu鱉œ_ð‰ºŸÜz“Ù'�ðÙ¥E=µ¿Z²%·7BQÛ*$,ŽÉAf†è®hñˆ¤½JD£ñTyº$a‹žöJÙ ´ºÏÏî§GÚ+%·×â©’HÜQµnuGTû"]ûß5|Ý·¸~kk×ðÌ 1”îÍÌð䋤]¶–æ–(—ŠÜQ+’ú# åÂòs\¤ù9wëš/H�×®\VtÎð›[ÄêÀ`;‘ôè€ûüdÍEÅc‹!2~“¤bó=²�„Ú£Í^PÐØ"†:{nj¹Ö½FšW”ïñ‘Í�{Bdó„)-� €gssË^†0íå­{’ÈæÆ–Ç=@HÎe¤\)SJx¤êH]SË^F%Ó»ëäRNÎ�Ó³ú ä<Õ`Á¬~&’' æ1˜ÕÏEòBrž¼Ì`’ÎfµåзEVút9WVDr˜Èa³R¡Tñ¼ +,”¼Z:|Vð +•RsŽL¡à<«P°àYµB¡Çqrá!§—OG޵uZÕ&NúLÉŸOÍF0©”*µB!cRh¤ï^J…B¥ÒJßÂäK©ä• +N©d¡`5J…Ï)/�Iù?aÒëTçŽÜ%Lêh3Ê!LêALÒ6•B«‘p*”j•îÁä´ CRW*!D›Ña$K0št:0h­f §No2Úe¼2µ^£×)õzt +›^¯‡Z­Ò_¢S=.ŸŽHÛí2 aR©`‰6cŒr€0M½Þ%½Ý*áÔ,&×92£QgÔ«ŒF%ôJ‡Ñ`„F«–‹tvh¼€áç˜Ô@œÛ2¤‰j5¬Ñf„!LVÀl²Ø +T0é�vi0­fwd.�¨½`P ‚ +•K “p F¸|:"mO¼mH5Ø£ÍD;“8h¬f«CìPÃbŒ‘¾žZ“ݘ#d&“Á$¨Mf•Ûl2A«×˜/Á.ŸŽHÛ›p!&G“y“°YlNAp@ «ÑíŠ`rØd¹ÊÔfƒYИÍjêX‹Ù �^+·p‘°Ì¸|:"m¢sÈ:´Z¸¢ÍX#9’T]€ÃæŒ1›]ÐÀnŠ—þͰ›-.G"`‹�Y­‚Õ¬µÚ40k<6«z£Îv FXqùtDÚé)î!MÔëm&ú#ƒÄÁ8ÀítÇÛlqÐÂeIôpÚìq1)ѯà€ÃavXu‡6m’Óî€Ñd�[°\ء㤤_F +?¤‰rz½ômÊG�rn~/ÊP2óI}~ÿ»à±»ÝÝ'¸òûé‰�:'Ÿäççô�P¢ìx^v[Q$4g/–Æn`”¶xÖf50¾Ä,&¥0ž æ•2ùÃ’}¾ÂH,‹ñ%ea)Ì‹g8wÆô[g—tŽN)ßôò�…óÛêc}îºÉ3²çÝ<)IÜ»(aUׯÆŽh- ¶5U»cBõÓ‹fß<-�[Z³¾«ÎÌ© šæ—Nݹ¦Æèˆ3ÞcNr›‚­ÚrSú¸+*ãŠ�Îxã}›I[4u98èWdç€)ãE£à]”/;Á/áÎVÊHèØ‹Òd—9>ÕáH�7™¤wZ¼i¯)>í‚ v·J¹öÔ³9!õlŸ#5ÞlŽ›âÓBj±–»� %,óÏãqz@vQ^vQnŽ?ŸH·�Ô2×\ËNYÛKŠdæ�áø`è�w'ß%p„4L�Ýnä,8dg—™‹‹%ÙzY/ë#A INΖ?,ßg`•ÄË5°ãËçÙIâéð„p¬F§çÃ÷’ïHOx1ßwz·E£7èôjµË£¸¬ô?7‡ïƒ~ä 6dàÓ{Ì�“9¾ÇÌÊŒ»”ô½Ä›Ï(%qû":ÀJJ G¹9É㯞XÚVšÐ¸íÀòp-É&[&m˜’%:ó'Ž|½ó©Ië'¦�½õާç�¾¹5ÀuV\Ý9Fà4ùcg,þý²|_NóÒŽäÊü„pnjMçÈ�•óVœM»@ÒáéQ¾‰ß ?2C:«à±«ÕØã´@Ò^m²¥�ß“È] ¿¹9$‹•ôRòÄB¥B‘¼¹ )˜gwð™quSŒÜþ�ÝSË×Ü?·|á´Æä”ÆÇ—oþè—“V½G‚O®;PÉ=`IõXç?qæÖU�]2ºý6ÑŸ2å·_ÞüþÉu…>ÉÕüj¾¸ Ù‡˜ùž£Q3=�E�ÚLz4‘pfÇÈ>ÄËz•òC¼\öÀá.Þ0æ1cãT$›9Ì3aÇ�a‡¤uC-«áiù†Q)ͤG%7i.ÎjÎil>ÃxÂ�âÂaûÝ›ävn¤Ÿósø½ 'd±öØlɳ±'Æb„$%VØ#’¨’#¢*j+;ž—gŠtp¾° + +-ÞB/;(¯RN²T_í�8gUEï×;'�ZóÇEu«‡M +?ì%§nšø·µ·}ùë‰9Ó·öº©ví¼¦8n—=Ýk�ÿØ©›®|âU.+ÙÙ;° ³dæ¾Ú´â�?ß½x¤9ÖkŒò”IáûÀBó13¬ìïƒ>üé’ý ôœL×ó}0Có�Ú¬‰Ðâ#ÉÉ)>É&Ù`AA! 2#ÉÉ×Ãõ +3ÏõJµoá´.-sÛgÌ›™ÌMZ�v`$ß70]£e–FÛe›ø>ðÐ?ÂõD{—,ÝK‚ÄËæ¸HöƒáÌ¾ï ¡WlãûàGlHÏ[=lŒ^ïJŠa‰ ÙÁ² ¹8Ûì(ÎÍñú,…²{ð±Yl¾O¡PÊžÃnwD€òí¿{E—ìâtI)åm: ZNá¶¾²“ä¼ð©ÑÄ(„¬$†ý�}¶¸g‚sDa†v …Ù¥Ë,î +Ü:ólˆï˜”Yß�Å슎D¡áû� sQˆpÈë#YlŠ„Cê�ijŽ`)[h rï>1ð«R)ˆ‚°Ï|·‹d¿HÎð�šåÇ)˜¯îç®U9bœJM\|œöÌ�|ß™»%÷¥Öy|‰:®&bs\�üO£1!ïésB�…Õš%f7Ÿï¿ìv‡ÅÇ&KÖç»Ø‡q=£–ÝÛ–=Ú~Uÿ|Çì ×^ÿ€äºæmoÏãKÛË?¸âùy·µ¥s…mÛŽRqÆöÆp>y`zËÀ½|_QÇú©9�#¼§òš�ÀO�r�çÚÄ�%`Í×pîð=Ã9or�[š‘–?Ø&Ké<}wÈþ•»pvÍbR¤ELd’r°¹ªÆOJoXT3¬©°´£ÒgL©œw{gÑŽƸ8OÓ´™9c�öÆo™ÛZ‘2òª=Wf¶6×Åqûͧ!³ª)){luujfKÛÜë”Iå©BŒWxБ–`N*›”—YS5:àkl_ZÞtÛâQZ‹C‚ý÷WyV2>Êš ߣ�Bž¤ü^â“ÖÜ®pWøäDÏð°ŸñÌé0ÏÜ ‚Ýô(ßÇ÷Á ᱘Þâa ’NÈþÐÀFŒº Ðd ì9ïl rÅO½åoÛ?¸²T«~ð�äÔJ.gâòЉ7ÌãüËLpë{ÛÇW¯ÙÕX˜ÃúÏ~î((È17¬¬OÉ™sïìjøÝ|ŒPïeX‚lY YIõ•’ò‘ Ó¼ûðƒ÷òËñz“Iɬ†ï;óËØÑ1z�×kàfIÚ|PÅÉv¦Þ«c5ƒ­$J¦DäöÑö†b|ÓÞi ÏršxaàÈcËöÖ2ÏñÁ¤b2û¦°ŒÔ£Ñ¨d Or) õ‰ž†¸3‡ù¾3O%Ö'’R’®òÌñc¿ßgàj"ý‡Ì§È^9?”dƒ ò)¾çóŒŽ'Çø³<ÓÎ eÄ]—/n[º´méRÉEy•ÞBIN|Ü™çÙï™×5\Þ€3�cøÅgÒî r¯Þ)Í_õô(çà\ð ö�VaÓåôšìI½q‚<¥È7°6_)+y•!—lw(““}‰.*C®�½QeÔ*ï'œRÉq ¡úöQ‹Îâ7í»®áþæ?û¦§MÞ8³"Õd TdåM[šçÓ’šäm vkQÉp[îäò䜷Ì~{ßm+ª�¦U*]aëŠÕ+sЧ†|iÕÓæ.ȃ2z”SñǃlÄ„ôɺ´^¥Ýìéu +zH4OšU¢3¯dS$È*d)óìÊÁÅ*k·K�9Uliû¦=K²fNŸä#ÃvÍÕ:´Œ§fÂŒ¢[¹Û–Y�W¶¢½Z¨Hœ[8zåôê,ÓWy÷]7/¥w&ÚùÝa{îÂô`Óð„ž,žJ¬]Ó×~Ɠݴpµ¼ú®§GÙ�œ ~d„L!G`Aô½V{Ht6d{=ÂÐl˜]Ô–›CÙj—¦BåEÓ Ûž¾ª¦jñ¤ÒTËu‹Êo.ó�Z_3}Ë´¬ÄŠ™kåÙ|0§¡kÉâœ[n/ ÜçK -¹«µù7=×´uV‡6*óõü1$¢®�^›×k²+lɽq‚Wæ¡Äƨ؇•2ËÝ$K~£R¯QÞÏ+U,—TÓ0¥ zÉøô„Q�Ý{¯(j÷uí ¿›â#¾Â ¼Å²;ØBM¬Ç'4µ:ü'½'çw•˜ ¦Y*§¯ííâ§ój¿`þ}[Îr/nyºåšú$� + ý œ [z +J�ö8Ôt_Ȫ3Ö¨µZ×ËÇšó{�ö@oÒ ÝKêÈÍñKÂON)”-†)¼´`†T¡ÉÕ´éù›gö”$”ÝÜÔzýŒ2›�KÓÐ’_µd| ¥vÁæß´µ=QÿçÄŽÂé÷,-³¤�Ê.l«™íQ×^õrï„,Ï]ÉÆ;uúŽ‘­#ârÛ·Mo} oýô|§qµJ7¹÷ù+ +¦•'g�í˜3+¹§“õØÒ:lJ[ŒÐëœQ?P]°>K)›•kdÅ&3’Ó)ÕZ~Õ®k9•‚]ZwE£°`©¼ïÎß2kÑðu˜°>¿d„uàU¦EHO÷iê'Õ­º­&,ðÇ’Š;F§Þíô$cãÁ¯„Â5Ë“@4Fs/‹ìãeoµÏÍñK*–�ôЍe[¬ÑÜ`ž�ìp•%ÌîÔh{wmW+3scRLSGffŒ•‘QÊ©4³'º*ó˜…éYBZ@¡à¾È •ee åA€?�¤IœšÑ*lŒMkTJL(+3™‹‹#ËÕèZ•ÉI2ÿé°È-—†z€#áCLÊÀ»LÜÀ§ü±³3É^yLnþ8lÐ=¬At(ç�ƒɹqœÃN°+L£èAs{ÏÔFAG°*®ä\#í;…òB6±wôH!רt� –•�;ò~.5î‰Â B¡ŒúõxÆ! Tq¥R«åVßw-§Rr•5É�ãF�H×,صVJWW§4Õ�‘¦Y°ë^•`а;x¯PrIÍÓ熦�ô°þ‰‹F®[wžÐMéi>Íø‰¾’†©3²Âš¡Œ‘�R†Žy/eâøJ{ÊĤôÔá3G§&WÍ,)ê�Ö ‚b€³s.dJZ¡´9lqFŸÐ›&{û²ÿ¤›?gWjÏé蘚ò_\1ÞpÑ|g-Y9sT ã°’¶sÚ:¶¥þªm¢,쓞VÛõ£§9WôÜÄ×ËÛ]½Fá?œ› Nœƒë5öô¸žWÑrÓ¬üÆÛ^3ù¦ÎÂÝžáMÁ–›gæ'OÖzóÌaÌÆÍ?<¶ h^ïô›~|dnѼÞ9£fWù§ÜöäÌÒÙ£“[o{ + ýkØÏ©äµ‡<éÜAi.7º’{c£|:^68•'§Dx”Ø,(8§då…3Ç©<å³n¸îˆå�9»N+ujÅn^¥b¹Ñ{çI3ÒnKFUÞ°©õ¡<ŸºÌœWP䬺²mtŽ“é«ýU_÷¼‘vcØÅíˆLJÃËF˜W¯Êiß6Gò8�šsæf†«ôEÖø‘ù=°n}âÃZ›É9‘\Èb¯á¤ÔÁ@^^v‘,m_òB6°Ñ5‰ƒ sÖQžáó'�2·ß·Mm6êØ�¬J¥b8Où˜¦œØB;Û¤sÔ]}ï„p9³;}Ú´æÄøŠ² ¡xÚ¨$­dU=Êœâ\ÈEjÈé5¤)8Ëœ¶7KøÎE\ñ½»´ýhÚH`òöÃn¿ðp¯@Þ}HÇL’èíæPæ’¢és-þbÿ’Y�é½ âkÆT¸¼ÖUuþÎYÆäÒì9YS»§Õ¬ÏdÇÆ%M—HuŒºqÒðŇ©‡ñC¬ÝÐ0:&##3¶tÓÄÒ¥“‡ÅÚ%þͤß2¯óÙðÃô‚^¯ê5Ù}$ÉÓgDÙñ`0/[ž…䈨¿9ÿ$§ Ð™ Y/³7^®Ðeæê’SSŒ ¾ÖÔ↠C«ZyÂî|.¿,Ÿ-# {åÀÇ 5ö`¦JgTl3Úâ +ÆåÄ�ó0™[N3F‹@¯GpåʤcèÈzX›Ük²gc�ò&ºVú + + + Λ ™Á �¼°”;ÕFÙHõÒ‡tÉHKÊg•{U=·*â‘ÆŒÉh™P[’®Yð[âKi®¿ÐDCzɘ™Ü�ݲ1×µ&�lœÚžA~ˆì Ø�8éÛFÒ#¼Ó[ƒ~úeHáI/gƒ²WeŒn�ó·ì¡0Õ gÕ±ø:�u²¯ž}jK>ÚBid'Àob’Q)_º/‘|ö´œßÍ@>¹?ÌígøM0ÂgHŸ`Ó>³„ÝÆ2F–°Èn“Nµåõ–> +endobj +816 0 obj +<> +/W [0 [645.50781 0 0 274.90234] 11 12 304.19922 14 [685.05859 0 399.90234] 22 [539.0625] 29 [217.77344 0 0 0 685.05859 0 0 631.83594 573.24219 639.16016 711.91406 499.02344 488.76953 687.98828 0 266.11328 0 599.60938 462.89063 817.87109 750.97656 0 0 0 582.03125 497.07031 525.87891 688.96484 627.92969 929.19922 0 0 569.82422] 68 69 541.99219 70 [436.03516 541.99219 486.81641 294.92188 541.99219 557.12891 258.78906 0 490.23438 258.78906 857.91016 562.01172 535.15625 541.99219 0 354.98047 395.01953 323.24219 558.10547] 93 [452.14844] 108 [541.99219] 124 [535.15625]] +/DW 0>> +endobj +817 0 obj +<> stream +xœ]’Ënƒ0E÷þ +/›EdóL*!¤‚Ä¢•樥b,ã,øûŠ™<¤.lé˜{ñψ¢.k£=Ÿnêð¼×F9˜§«ë€_`І!Wºó7½[ËDQ—Í2{kÓO,Ë8_0èÙ»…¿Ôt� N�Ófà/ç¢Ù0Ñ\­ý…Œç’å9WÐ3Q¼µö½� ´mkÆk¿lÏEóT|/xˆPšnR0Û¶ךX&¥”9ϪªªrFýûÜl—¾ûiÊ£œgR†2G:‘IT¥HQDT�€èDT ůH)R&D;¢””§iGT¥ý–qwOü¬ðˆ2IêpOwÆDº: C*'¢t1U%÷ä+ÄØì1ý3%{Lö„ž(%{BödOu„·¬”n}ñu2íì®Î�ñ8>ØÂµyÚÀcÂìdW׺þT±H +endstream +endobj +80 0 obj +<> +endobj +xref +0 818 +0000000000 65535 f +0000000015 00000 n +0000096310 00000 n +0000000286 00000 n +0000186756 00000 n +0000000323 00000 n +0000202416 00000 n +0000000399 00000 n +0000000548 00000 n +0000000691 00000 n +0000000853 00000 n +0000001025 00000 n +0000001217 00000 n +0000001379 00000 n +0000001520 00000 n +0000001712 00000 n +0000001885 00000 n +0000002064 00000 n +0000002239 00000 n +0000002385 00000 n +0000002560 00000 n +0000002722 00000 n +0000002914 00000 n +0000003107 00000 n +0000003267 00000 n +0000003460 00000 n +0000003640 00000 n +0000003821 00000 n +0000004049 00000 n +0000004274 00000 n +0000004420 00000 n +0000004610 00000 n +0000004785 00000 n +0000004990 00000 n +0000005254 00000 n +0000005519 00000 n +0000005743 00000 n +0000006012 00000 n +0000006280 00000 n +0000006529 00000 n +0000006777 00000 n +0000006937 00000 n +0000007131 00000 n +0000007351 00000 n +0000007519 00000 n +0000007702 00000 n +0000007933 00000 n +0000008160 00000 n +0000008306 00000 n +0000008510 00000 n +0000008728 00000 n +0000096870 00000 n +0000217906 00000 n +0000011999 00000 n +0000012214 00000 n +0000012477 00000 n +0000012740 00000 n +0000013025 00000 n +0000013308 00000 n +0000013597 00000 n +0000013885 00000 n +0000014041 00000 n +0000014234 00000 n +0000014415 00000 n +0000014634 00000 n +0000014873 00000 n +0000015112 00000 n +0000015258 00000 n +0000015433 00000 n +0000015607 00000 n +0000015762 00000 n +0000015955 00000 n +0000016136 00000 n +0000016342 00000 n +0000016488 00000 n +0000016677 00000 n +0000016875 00000 n +0000097307 00000 n +0000021173 00000 n +0000020804 00000 n +0000230309 00000 n +0000028783 00000 n +0000097600 00000 n +0000032575 00000 n +0000032616 00000 n +0000032657 00000 n +0000097892 00000 n +0000034892 00000 n +0000050488 00000 n +0000098185 00000 n +0000052227 00000 n +0000058473 00000 n +0000098502 00000 n +0000060987 00000 n +0000068002 00000 n +0000098795 00000 n +0000071568 00000 n +0000082030 00000 n +0000087942 00000 n +0000099124 00000 n +0000091135 00000 n +0000099381 00000 n +0000094121 00000 n +0000099675 00000 n +0000099797 00000 n +0000099879 00000 n +0000099947 00000 n +0000166497 00000 n +0000161584 00000 n +0000105031 00000 n +0000104952 00000 n +0000127307 00000 n +0000127221 00000 n +0000105113 00000 n +0000105265 00000 n +0000105186 00000 n +0000127071 00000 n +0000107132 00000 n +0000105374 00000 n +0000105526 00000 n +0000105447 00000 n +0000106998 00000 n +0000105896 00000 n +0000105635 00000 n +0000105787 00000 n +0000105708 00000 n +0000106236 00000 n +0000105974 00000 n +0000106126 00000 n +0000106047 00000 n +0000106578 00000 n +0000106314 00000 n +0000106468 00000 n +0000106388 00000 n +0000106920 00000 n +0000106656 00000 n +0000106810 00000 n +0000106730 00000 n +0000110954 00000 n +0000107218 00000 n +0000107372 00000 n +0000107292 00000 n +0000110836 00000 n +0000108898 00000 n +0000107482 00000 n +0000107636 00000 n +0000107556 00000 n +0000108772 00000 n +0000108010 00000 n +0000107746 00000 n +0000107900 00000 n +0000107820 00000 n +0000108352 00000 n +0000108088 00000 n +0000108242 00000 n +0000108162 00000 n +0000108694 00000 n +0000108430 00000 n +0000108584 00000 n +0000108504 00000 n +0000110750 00000 n +0000108984 00000 n +0000109138 00000 n +0000109058 00000 n +0000110616 00000 n +0000109512 00000 n +0000109248 00000 n +0000109402 00000 n +0000109322 00000 n +0000109854 00000 n +0000109590 00000 n +0000109744 00000 n +0000109664 00000 n +0000110196 00000 n +0000109932 00000 n +0000110086 00000 n +0000110006 00000 n +0000110538 00000 n +0000110274 00000 n +0000110428 00000 n +0000110348 00000 n +0000115978 00000 n +0000111040 00000 n +0000111194 00000 n +0000111114 00000 n +0000115860 00000 n +0000112758 00000 n +0000111304 00000 n +0000111458 00000 n +0000111378 00000 n +0000112632 00000 n +0000111832 00000 n +0000111568 00000 n +0000111722 00000 n +0000111642 00000 n +0000112174 00000 n +0000111910 00000 n +0000112064 00000 n +0000111984 00000 n +0000112554 00000 n +0000112252 00000 n +0000112406 00000 n +0000112326 00000 n +0000115774 00000 n +0000112844 00000 n +0000112998 00000 n +0000112918 00000 n +0000115616 00000 n +0000113372 00000 n +0000113108 00000 n +0000113262 00000 n +0000113182 00000 n +0000113714 00000 n +0000113450 00000 n +0000113604 00000 n +0000113524 00000 n +0000114056 00000 n +0000113792 00000 n +0000113946 00000 n +0000113866 00000 n +0000114436 00000 n +0000114134 00000 n +0000114288 00000 n +0000114208 00000 n +0000114778 00000 n +0000114514 00000 n +0000114668 00000 n +0000114588 00000 n +0000115158 00000 n +0000114856 00000 n +0000115010 00000 n +0000114930 00000 n +0000115538 00000 n +0000115236 00000 n +0000115390 00000 n +0000115310 00000 n +0000121009 00000 n +0000116064 00000 n +0000116218 00000 n +0000116138 00000 n +0000120891 00000 n +0000118132 00000 n +0000116328 00000 n +0000116482 00000 n +0000116402 00000 n +0000117998 00000 n +0000116856 00000 n +0000116592 00000 n +0000116746 00000 n +0000116666 00000 n +0000117198 00000 n +0000116934 00000 n +0000117088 00000 n +0000117008 00000 n +0000117540 00000 n +0000117276 00000 n +0000117430 00000 n +0000117350 00000 n +0000117920 00000 n +0000117618 00000 n +0000117772 00000 n +0000117692 00000 n +0000120805 00000 n +0000118218 00000 n +0000118372 00000 n +0000118292 00000 n +0000120655 00000 n +0000118746 00000 n +0000118482 00000 n +0000118636 00000 n +0000118556 00000 n +0000119088 00000 n +0000118824 00000 n +0000118978 00000 n +0000118898 00000 n +0000119431 00000 n +0000119166 00000 n +0000119320 00000 n +0000119240 00000 n +0000119813 00000 n +0000119509 00000 n +0000119663 00000 n +0000119583 00000 n +0000120195 00000 n +0000119891 00000 n +0000120045 00000 n +0000119965 00000 n +0000120577 00000 n +0000120273 00000 n +0000120427 00000 n +0000120347 00000 n +0000124192 00000 n +0000121095 00000 n +0000121249 00000 n +0000121169 00000 n +0000124074 00000 n +0000122827 00000 n +0000121360 00000 n +0000121516 00000 n +0000121435 00000 n +0000122701 00000 n +0000121894 00000 n +0000121627 00000 n +0000121783 00000 n +0000121702 00000 n +0000122239 00000 n +0000121972 00000 n +0000122128 00000 n +0000122047 00000 n +0000122623 00000 n +0000122317 00000 n +0000122473 00000 n +0000122392 00000 n +0000123988 00000 n +0000122913 00000 n +0000123069 00000 n +0000122988 00000 n +0000123870 00000 n +0000123447 00000 n +0000123180 00000 n +0000123336 00000 n +0000123255 00000 n +0000123792 00000 n +0000123525 00000 n +0000123681 00000 n +0000123600 00000 n +0000126985 00000 n +0000124278 00000 n +0000124434 00000 n +0000124353 00000 n +0000126867 00000 n +0000125620 00000 n +0000124545 00000 n +0000124701 00000 n +0000124620 00000 n +0000125502 00000 n +0000125079 00000 n +0000124812 00000 n +0000124968 00000 n +0000124887 00000 n +0000125424 00000 n +0000125157 00000 n +0000125313 00000 n +0000125232 00000 n +0000126781 00000 n +0000125706 00000 n +0000125862 00000 n +0000125781 00000 n +0000126663 00000 n +0000126240 00000 n +0000125973 00000 n +0000126129 00000 n +0000126048 00000 n +0000126585 00000 n +0000126318 00000 n +0000126474 00000 n +0000126393 00000 n +0000127494 00000 n +0000127413 00000 n +0000127643 00000 n +0000127562 00000 n +0000127792 00000 n +0000127711 00000 n +0000127940 00000 n +0000127859 00000 n +0000128242 00000 n +0000128089 00000 n +0000128008 00000 n +0000128161 00000 n +0000128400 00000 n +0000128319 00000 n +0000128783 00000 n +0000128468 00000 n +0000128630 00000 n +0000128549 00000 n +0000128702 00000 n +0000129658 00000 n +0000129177 00000 n +0000128868 00000 n +0000129024 00000 n +0000128943 00000 n +0000129096 00000 n +0000129572 00000 n +0000129263 00000 n +0000129419 00000 n +0000129338 00000 n +0000129491 00000 n +0000129854 00000 n +0000129774 00000 n +0000130243 00000 n +0000129921 00000 n +0000130015 00000 n +0000130175 00000 n +0000130095 00000 n +0000130408 00000 n +0000130328 00000 n +0000130708 00000 n +0000130556 00000 n +0000130476 00000 n +0000130628 00000 n +0000130865 00000 n +0000130785 00000 n +0000131013 00000 n +0000130933 00000 n +0000131161 00000 n +0000131081 00000 n +0000131310 00000 n +0000131229 00000 n +0000134031 00000 n +0000131767 00000 n +0000131377 00000 n +0000131452 00000 n +0000131614 00000 n +0000131533 00000 n +0000131686 00000 n +0000132251 00000 n +0000131861 00000 n +0000131936 00000 n +0000132098 00000 n +0000132017 00000 n +0000132170 00000 n +0000132735 00000 n +0000132345 00000 n +0000132420 00000 n +0000132582 00000 n +0000132501 00000 n +0000132654 00000 n +0000133219 00000 n +0000132829 00000 n +0000132904 00000 n +0000133066 00000 n +0000132985 00000 n +0000133138 00000 n +0000133703 00000 n +0000133313 00000 n +0000133388 00000 n +0000133550 00000 n +0000133469 00000 n +0000133622 00000 n +0000133953 00000 n +0000133797 00000 n +0000133872 00000 n +0000134260 00000 n +0000134179 00000 n +0000134408 00000 n +0000134327 00000 n +0000134593 00000 n +0000134476 00000 n +0000134740 00000 n +0000134660 00000 n +0000134887 00000 n +0000134807 00000 n +0000135035 00000 n +0000134955 00000 n +0000135411 00000 n +0000135334 00000 n +0000135182 00000 n +0000135102 00000 n +0000135254 00000 n +0000135582 00000 n +0000135502 00000 n +0000135730 00000 n +0000135650 00000 n +0000136338 00000 n +0000135798 00000 n +0000135959 00000 n +0000135878 00000 n +0000136027 00000 n +0000136189 00000 n +0000136108 00000 n +0000136257 00000 n +0000136520 00000 n +0000136439 00000 n +0000137438 00000 n +0000136588 00000 n +0000136750 00000 n +0000136669 00000 n +0000136818 00000 n +0000136980 00000 n +0000136899 00000 n +0000137048 00000 n +0000137129 00000 n +0000137370 00000 n +0000137290 00000 n +0000137635 00000 n +0000137555 00000 n +0000138239 00000 n +0000137703 00000 n +0000137863 00000 n +0000137783 00000 n +0000137931 00000 n +0000138091 00000 n +0000138011 00000 n +0000138159 00000 n +0000138420 00000 n +0000138340 00000 n +0000139028 00000 n +0000138488 00000 n +0000138649 00000 n +0000138568 00000 n +0000138717 00000 n +0000138879 00000 n +0000138798 00000 n +0000138947 00000 n +0000139210 00000 n +0000139129 00000 n +0000139359 00000 n +0000139278 00000 n +0000139508 00000 n +0000139427 00000 n +0000139657 00000 n +0000139576 00000 n +0000141037 00000 n +0000139952 00000 n +0000139724 00000 n +0000139880 00000 n +0000139799 00000 n +0000140339 00000 n +0000140030 00000 n +0000140186 00000 n +0000140105 00000 n +0000140258 00000 n +0000140653 00000 n +0000140425 00000 n +0000140581 00000 n +0000140500 00000 n +0000140959 00000 n +0000140731 00000 n +0000140887 00000 n +0000140806 00000 n +0000141253 00000 n +0000141172 00000 n +0000141568 00000 n +0000141320 00000 n +0000141500 00000 n +0000141420 00000 n +0000141725 00000 n +0000141645 00000 n +0000141873 00000 n +0000141793 00000 n +0000142020 00000 n +0000141940 00000 n +0000142167 00000 n +0000142087 00000 n +0000142544 00000 n +0000142467 00000 n +0000142315 00000 n +0000142235 00000 n +0000142387 00000 n +0000142715 00000 n +0000142635 00000 n +0000142864 00000 n +0000142783 00000 n +0000143703 00000 n +0000142932 00000 n +0000143094 00000 n +0000143013 00000 n +0000143162 00000 n +0000143324 00000 n +0000143243 00000 n +0000143392 00000 n +0000143554 00000 n +0000143473 00000 n +0000143622 00000 n +0000143901 00000 n +0000143820 00000 n +0000144280 00000 n +0000143969 00000 n +0000144131 00000 n +0000144050 00000 n +0000144199 00000 n +0000144446 00000 n +0000144365 00000 n +0000144825 00000 n +0000144514 00000 n +0000144676 00000 n +0000144595 00000 n +0000144744 00000 n +0000144991 00000 n +0000144910 00000 n +0000145140 00000 n +0000145059 00000 n +0000145288 00000 n +0000145208 00000 n +0000145436 00000 n +0000145356 00000 n +0000145584 00000 n +0000145504 00000 n +0000145732 00000 n +0000145652 00000 n +0000145880 00000 n +0000145800 00000 n +0000146028 00000 n +0000145948 00000 n +0000147276 00000 n +0000146401 00000 n +0000146095 00000 n +0000146249 00000 n +0000146169 00000 n +0000146321 00000 n +0000146795 00000 n +0000146487 00000 n +0000146642 00000 n +0000146561 00000 n +0000146714 00000 n +0000147190 00000 n +0000146881 00000 n +0000147037 00000 n +0000146956 00000 n +0000147109 00000 n +0000147730 00000 n +0000147400 00000 n +0000147481 00000 n +0000147662 00000 n +0000147581 00000 n +0000147896 00000 n +0000147815 00000 n +0000148045 00000 n +0000147964 00000 n +0000148902 00000 n +0000148421 00000 n +0000148112 00000 n +0000148268 00000 n +0000148187 00000 n +0000148340 00000 n +0000148816 00000 n +0000148507 00000 n +0000148663 00000 n +0000148582 00000 n +0000148735 00000 n +0000149723 00000 n +0000149102 00000 n +0000149021 00000 n +0000149174 00000 n +0000149336 00000 n +0000149255 00000 n +0000149408 00000 n +0000149570 00000 n +0000149489 00000 n +0000149642 00000 n +0000149913 00000 n +0000149832 00000 n +0000150062 00000 n +0000149981 00000 n +0000150209 00000 n +0000150129 00000 n +0000150356 00000 n +0000150276 00000 n +0000150733 00000 n +0000150656 00000 n +0000150504 00000 n +0000150424 00000 n +0000150576 00000 n +0000150904 00000 n +0000150824 00000 n +0000151052 00000 n +0000150972 00000 n +0000151428 00000 n +0000151120 00000 n +0000151280 00000 n +0000151200 00000 n +0000151348 00000 n +0000153343 00000 n +0000151822 00000 n +0000151513 00000 n +0000151669 00000 n +0000151588 00000 n +0000151741 00000 n +0000152217 00000 n +0000151908 00000 n +0000152064 00000 n +0000151983 00000 n +0000152136 00000 n +0000152846 00000 n +0000152303 00000 n +0000152459 00000 n +0000152378 00000 n +0000152531 00000 n +0000152693 00000 n +0000152612 00000 n +0000152765 00000 n +0000153257 00000 n +0000152948 00000 n +0000153104 00000 n +0000153023 00000 n +0000153176 00000 n +0000153813 00000 n +0000153475 00000 n +0000153583 00000 n +0000153745 00000 n +0000153664 00000 n +0000154236 00000 n +0000153898 00000 n +0000154006 00000 n +0000154168 00000 n +0000154087 00000 n +0000154401 00000 n +0000154321 00000 n +0000154549 00000 n +0000154469 00000 n +0000154697 00000 n +0000154617 00000 n +0000154845 00000 n +0000154765 00000 n +0000154993 00000 n +0000154913 00000 n +0000155141 00000 n +0000155061 00000 n +0000155289 00000 n +0000155209 00000 n +0000155437 00000 n +0000155357 00000 n +0000155585 00000 n +0000155505 00000 n +0000155966 00000 n +0000155652 00000 n +0000155813 00000 n +0000155732 00000 n +0000155885 00000 n +0000156132 00000 n +0000156051 00000 n +0000156281 00000 n +0000156200 00000 n +0000156663 00000 n +0000156348 00000 n +0000156510 00000 n +0000156429 00000 n +0000156582 00000 n +0000156829 00000 n +0000156748 00000 n +0000157446 00000 n +0000156897 00000 n +0000157059 00000 n +0000156978 00000 n +0000157131 00000 n +0000157293 00000 n +0000157212 00000 n +0000157365 00000 n +0000157862 00000 n +0000157547 00000 n +0000157709 00000 n +0000157628 00000 n +0000157781 00000 n +0000158028 00000 n +0000157947 00000 n +0000158177 00000 n +0000158096 00000 n +0000158556 00000 n +0000158245 00000 n +0000158407 00000 n +0000158326 00000 n +0000158475 00000 n +0000158722 00000 n +0000158641 00000 n +0000159101 00000 n +0000158790 00000 n +0000158952 00000 n +0000158871 00000 n +0000159020 00000 n +0000159267 00000 n +0000159186 00000 n +0000159416 00000 n +0000159335 00000 n +0000159566 00000 n +0000159484 00000 n +0000159716 00000 n +0000159634 00000 n +0000159865 00000 n +0000159783 00000 n +0000160014 00000 n +0000159932 00000 n +0000160395 00000 n +0000160318 00000 n +0000160164 00000 n +0000160082 00000 n +0000160236 00000 n +0000160569 00000 n +0000160487 00000 n +0000160719 00000 n +0000160637 00000 n +0000161333 00000 n +0000160787 00000 n +0000160951 00000 n +0000160869 00000 n +0000161019 00000 n +0000161183 00000 n +0000161101 00000 n +0000161251 00000 n +0000161516 00000 n +0000161434 00000 n +0000162554 00000 n +0000163197 00000 n +0000163648 00000 n +0000163955 00000 n +0000164134 00000 n +0000164377 00000 n +0000164620 00000 n +0000164911 00000 n +0000165170 00000 n +0000165413 00000 n +0000165624 00000 n +0000166593 00000 n +0000166810 00000 n +0000185103 00000 n +0000185346 00000 n +0000186360 00000 n +0000186897 00000 n +0000201510 00000 n +0000201747 00000 n +0000202072 00000 n +0000202557 00000 n +0000216312 00000 n +0000216560 00000 n +0000217492 00000 n +0000218053 00000 n +0000228856 00000 n +0000229111 00000 n +0000229896 00000 n +trailer +<> +startxref +230458 +%%EOF diff --git a/lang/de_DE.json b/lang/de_DE.json index 055680d..78d3d67 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -1040,6 +1040,60 @@ "gr-tr-beschr-stil-fehlt": "\nTextstil %1 fehlt in der Zeichnung - Beschriftung mit aktuellem Stil %2.", "gr-tr-beschr-ausrichtung": "\nUnbekannte Ausrichtung %1 fuer die Traeger-Beschriftung - verwende BC.", "gr-tr-beschr-ergebnis": "\n%1 Traeger beschriftet (davon %2 ohne bekannte Variante), %3 nicht beschriftbar, %4 verwaiste Beschriftungen entfernt.", - "gr-tr-beschr-keine": "\nKeine Rohr-Geruest-Traeger in der Zeichnung." + "gr-tr-beschr-keine": "\nKeine Rohr-Geruest-Traeger in der Zeichnung.", + "in-yesno-keys": "Ja Nein", + "in-keys-bereich": "Alle Auswahl", + "in-keys-modus": "Teil Gesamt", + "bt-prompt-muster": "\nBlockname oder Muster (z.B. GR_*): ", + "bt-kein-block": "\nDas gewaehlte Objekt ist keine Blockeinfuegung.", + "bt-prompt-waehlen-count": "\nBlock waehlen [Name/Muster] : ", + "bt-count-keine": "\nKeine Einfuegungen von %1 gefunden.", + "bt-count-keine-alle": "\nKeine Blockeinfuegungen im aktuellen Layout.", + "bt-count-ergebnis": "\n%1 Einfuegung(en) von %2.", + "bt-count-zeile": "\n %1: %2", + "bt-count-summe": "\nGesamt: %1 Einfuegung(en) in %2 Block(s).", + "bt-prompt-waehlen-delete": "\nZu loeschenden Block waehlen [Name/Muster]: ", + "bt-delete-kein-muster": "\nKein Block gewaehlt - nichts geloescht.", + "bt-delete-alle-gesperrt": "\nAlle %1 Einfuegung(en) liegen auf gesperrten Layern - nichts geloescht.", + "bt-delete-frage": "%1 Einfuegung(en) von %2 loeschen?", + "bt-delete-titel": "Bloecke loeschen", + "bt-delete-ergebnis": "\n%1 Einfuegung(en) geloescht.", + "bt-delete-gesperrt": "\n%1 Einfuegung(en) auf gesperrten Layern blieben stehen.", + "bt-abgebrochen": "\nAbgebrochen - nichts geaendert.", + "bt-attr-bereich": "\nBereich", + "bt-attr-muster": "\nBlockname-Muster", + "bt-attr-auswahl": "\nBloecke waehlen: ", + "bt-attr-keine-bloecke": "\nKeine passenden Blockeinfuegungen gefunden.", + "bt-attr-tag": "\nAttribut-Tag (Muster)", + "bt-attr-suche": "\nSuchen nach", + "bt-attr-ersatz": "\nErsetzen durch", + "bt-attr-modus": "\nErsetzen als", + "bt-attr-nichts": "\nKein Attributwert enthaelt den Suchtext.", + "bt-attr-frage": "%1 Attributwert(e) in %2 Block(s) aendern?", + "bt-attr-titel": "Attribute ersetzen", + "bt-attr-ergebnis": "\n%1 Attributwert(e) geaendert.", + "tt-bereich": "\nBereich", + "tt-auswahl": "\nObjekte waehlen: ", + "tt-keine-objekte": "\nKeine passenden Objekte gefunden.", + "tt-suche": "\nSuchen nach", + "tt-ersatz": "\nErsetzen durch", + "tt-modus": "\nErsetzen als", + "tt-nichts": "\nKein Text und kein Attributwert enthaelt den Suchtext.", + "tt-frage": "%1 Text(e) und %2 Attributwert(e) aendern?", + "tt-ersetzen-titel": "Text ersetzen", + "tt-ergebnis": "\n%1 Text(e) und %2 Attributwert(e) geaendert.", + "tt-abgebrochen": "\nAbgebrochen - nichts geaendert.", + "tt-parallel-titel": "Text parallel beschriften", + "tt-hoehe": "\nTexthoehe", + "tt-abstand": "\nAbstand zur Linie", + "tt-parallel-waehlen": "\nLinie, Polylinie oder Bogen waehlen (Enter = Ende): ", + "tt-parallel-keine-kurve": "\nWinkel am gewaehlten Objekt nicht ermittelbar.", + "tt-text": "\nText", + "tt-parallel-fehler": "\nText konnte nicht erzeugt werden.", + "tt-hoehe-titel": "Texthoehe aendern", + "tt-geaendert": "\n%1 Text(e) geaendert.", + "tt-stil": "\nTextstil", + "tt-stil-fehlt": "\nTextstil %1 existiert nicht in der Zeichnung.", + "tt-stil-titel": "Textstil aendern" } } diff --git a/lang/en_GB.json b/lang/en_GB.json index 2714170..8af50c3 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -1040,6 +1040,60 @@ "gr-tr-beschr-stil-fehlt": "\nText style %1 missing in drawing - labelling with current style %2.", "gr-tr-beschr-ausrichtung": "\nUnknown justification %1 for beam label - using BC.", "gr-tr-beschr-ergebnis": "\n%1 beam(s) labelled (%2 without known variant), %3 not labellable, %4 orphaned label(s) removed.", - "gr-tr-beschr-keine": "\nNo pipe scaffold beams in the drawing." + "gr-tr-beschr-keine": "\nNo pipe scaffold beams in the drawing.", + "in-yesno-keys": "Yes No", + "in-keys-bereich": "All Selection", + "in-keys-modus": "Part Whole", + "bt-prompt-muster": "\nBlock name or pattern (e.g. GR_*): ", + "bt-kein-block": "\nThe selected object is not a block reference.", + "bt-prompt-waehlen-count": "\nSelect block [Name/pattern] : ", + "bt-count-keine": "\nNo references of %1 found.", + "bt-count-keine-alle": "\nNo block references in the current layout.", + "bt-count-ergebnis": "\n%1 reference(s) of %2.", + "bt-count-zeile": "\n %1: %2", + "bt-count-summe": "\nTotal: %1 reference(s) in %2 block(s).", + "bt-prompt-waehlen-delete": "\nSelect block to delete [Name/pattern]: ", + "bt-delete-kein-muster": "\nNo block selected - nothing deleted.", + "bt-delete-alle-gesperrt": "\nAll %1 reference(s) are on locked layers - nothing deleted.", + "bt-delete-frage": "Delete %1 reference(s) of %2?", + "bt-delete-titel": "Delete blocks", + "bt-delete-ergebnis": "\n%1 reference(s) deleted.", + "bt-delete-gesperrt": "\n%1 reference(s) on locked layers were kept.", + "bt-abgebrochen": "\nCancelled - nothing changed.", + "bt-attr-bereich": "\nScope", + "bt-attr-muster": "\nBlock name pattern", + "bt-attr-auswahl": "\nSelect blocks: ", + "bt-attr-keine-bloecke": "\nNo matching block references found.", + "bt-attr-tag": "\nAttribute tag (pattern)", + "bt-attr-suche": "\nFind", + "bt-attr-ersatz": "\nReplace with", + "bt-attr-modus": "\nReplace as", + "bt-attr-nichts": "\nNo attribute value contains the search text.", + "bt-attr-frage": "Change %1 attribute value(s) in %2 block(s)?", + "bt-attr-titel": "Replace attributes", + "bt-attr-ergebnis": "\n%1 attribute value(s) changed.", + "tt-bereich": "\nScope", + "tt-auswahl": "\nSelect objects: ", + "tt-keine-objekte": "\nNo matching objects found.", + "tt-suche": "\nFind", + "tt-ersatz": "\nReplace with", + "tt-modus": "\nReplace as", + "tt-nichts": "\nNo text or attribute value contains the search text.", + "tt-frage": "Change %1 text(s) and %2 attribute value(s)?", + "tt-ersetzen-titel": "Replace text", + "tt-ergebnis": "\n%1 text(s) and %2 attribute value(s) changed.", + "tt-abgebrochen": "\nCancelled - nothing changed.", + "tt-parallel-titel": "Label parallel to line", + "tt-hoehe": "\nText height", + "tt-abstand": "\nDistance to line", + "tt-parallel-waehlen": "\nSelect line, polyline or arc (Enter = finish): ", + "tt-parallel-keine-kurve": "\nCannot determine the angle on the selected object.", + "tt-text": "\nText", + "tt-parallel-fehler": "\nText could not be created.", + "tt-hoehe-titel": "Change text height", + "tt-geaendert": "\n%1 text(s) changed.", + "tt-stil": "\nText style", + "tt-stil-fehlt": "\nText style %1 does not exist in the drawing.", + "tt-stil-titel": "Change text style" } } diff --git a/menu/SSG_LIB.mnl b/menu/SSG_LIB.mnl index c899576..aff32f1 100644 --- a/menu/SSG_LIB.mnl +++ b/menu/SSG_LIB.mnl @@ -2,7 +2,7 @@ ;; SSG_LIB.mnl - Automatisch geladen beim MENULOAD von SSG_LIB.mnu ;; ;; Definiert den Lazy-Loader (ssg-ensure) und laedt alle Module. -;; Kern-Module: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, ssg_id +;; Kern-Module: ssg_core, ssg_lang, ssg_dbg, ssg_dialog, ssg_layer, ssg_id, ssg_input ;; Feature-Module: KreiselInsert, Gefaellestrecke, VarioFoerderer, ... ;; ============================================================ @@ -144,6 +144,8 @@ (ssg-ensure "ssg_dialog") (ssg-ensure "ssg_layer") (ssg-ensure "ssg_id") + ;; Generische Eingabe-Wrapper (ssg-in-*), von den Werkzeug-Modulen genutzt + (ssg-ensure "ssg_input") ;; Gemeinsame KS-Extraktion + Block-Einfuegeprimitiven (von Gefaellestrecke ;; UND VarioFoerderer genutzt) - MUSS vor beiden geladen sein. (ssg-ensure "ssg_ks_insert") @@ -159,6 +161,9 @@ ;; Tro_Edit wird nicht vorgeladen - der Dispatcher SSG_BLOCKEDIT und die ;; Menuemakros holen es per (ssg-ensure "Tro_Edit") bei Bedarf nach. (ssg-ensure "SSG_LIB_Commands") + ;; Werkzeuge (Reihenfolge: ssg_texttools nutzt ssg_blocktools) + (ssg-ensure "ssg_blocktools") + (ssg-ensure "ssg_texttools") ;; Menue einhaengen (menucmd "P13=+SSG_LIB.POP1") diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 703b508..0d76301 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -141,6 +141,15 @@ [Sprache]^C^C(ssg-ensure "SSG_LIB_Commands") SSG_SPRACHE [Planquadrate an/aus]^C^C(ssg-ensure "DrawPlanquadrate") PLANQUADRATE_TOGGLE [<-CSV-Export]^C^C(ssg-ensure "export") CSV_EXPORT_KONFIG +[->Werkzeuge] +[Bloecke zaehlen]^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_COUNT +[Bloecke loeschen]^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_DELETE +[Attribute ersetzen]^C^C(ssg-ensure "ssg_blocktools") SSG_ATTR_ERSETZEN +[--] +[Text ersetzen]^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_ERSETZEN +[Text parallel beschriften]^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_PARALLEL +[Texthoehe aendern]^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_HOEHE +[<-Textstil aendern]^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_STIL [->Tests] [alle Tests ausfuehren und exportieren]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_EXPORT) [Tests ausfuehren und stehen lassen]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_OFFEN) diff --git a/tests/test_unit.lsp b/tests/test_unit.lsp index 7c8c66e..7f4d864 100644 --- a/tests/test_unit.lsp +++ b/tests/test_unit.lsp @@ -1580,6 +1580,77 @@ (strcat "harter Fehler: " (vl-catch-all-error-message res)))) ) +;; ------------------------------------------------------------ +;; TESTS: ssg_input / ssg_blocktools / ssg_texttools - reine Funktionen +;; (die interaktiven Befehle SSG_BLOCK_*, SSG_ATTR_ERSETZEN, SSG_TEXT_* +;; brauchen eine Zeichnung und sind hier NICHT abgedeckt) +;; ------------------------------------------------------------ + +(defun tu-tests-werkzeuge ( / _e) + (princ "\n[ssg_input / ssg_blocktools / ssg_texttools]") + (if (not (and (car (atoms-family 1 '("SSG-IN-DEFAULT"))) + (car (atoms-family 1 '("SSG-BT-WERT-NEU"))) + (car (atoms-family 1 '("SSG-TT-LESBARER-WINKEL"))))) + (tu-record nil "werkzeuge/geladen" + "ssg_input/ssg_blocktools/ssg_texttools nicht geladen (ssg_load.lsp)") + (progn + ;; --- ssg_input --- + (tu-eqf "ssg-in-default/vorgabe" 5.0 (ssg-in-default nil 5.0)) + (tu-eqf "ssg-in-default/eingabe" 3.0 (ssg-in-default 3.0 5.0)) + (tu-nil "ssg-in-default/beides-nil" (ssg-in-default nil nil)) + (tu-eq "ssg-in-fmt-real/ganz" "5" (ssg-in-fmt-real 5.0)) + (tu-eq "ssg-in-fmt-real/halb" "2.5" (ssg-in-fmt-real 2.5)) + (tu-eq "ssg-in-fmt-real/null" "0" (ssg-in-fmt-real 0.0)) + (tu-eq "ssg-in-fmt-real/hundert" "100" (ssg-in-fmt-real 100.0)) + (tu-eq "ssg-in-fmt-real/bruch" "0.125" (ssg-in-fmt-real 0.125)) + (tu-eq "ssg-in-fmt-real/negativ" "-1.5" (ssg-in-fmt-real -1.5)) + (tu-eq "ssg-in-fmt-pt/3d" "1,2.5,0" (ssg-in-fmt-pt '(1.0 2.5 0.0))) + (tu-eq "ssg-in-fmt-pt/2d" "1,2,0" (ssg-in-fmt-pt '(1.0 2.0))) + (tu-eq "ssg-in-prompt/mit-vorgabe" "\nHoehe <5>: " (ssg-in-prompt "\nHoehe" "5")) + (tu-eq "ssg-in-prompt/ohne" "\nHoehe: " (ssg-in-prompt "\nHoehe" nil)) + (tu-eq "ssg-in-first-word" "Ja" (ssg-in-first-word "Ja Nein")) + (tu-eq "ssg-in-first-word/ein-wort" "Ja" (ssg-in-first-word "Ja")) + (tu-eq "ssg-in-second-word" "Nein" (ssg-in-second-word "Ja Nein")) + (tu-eq "ssg-in-second-word/ein-wort" "" (ssg-in-second-word "Ja")) + + ;; --- ssg_blocktools --- + (tu-true "ssg-bt-name-passt-p/muster" (ssg-bt-name-passt-p "GR_TR_1" "gr_*")) + (tu-nil "ssg-bt-name-passt-p/kein" (ssg-bt-name-passt-p "GR_TR_1" "XX*")) + (tu-true "ssg-bt-name-passt-p/nil" (ssg-bt-name-passt-p "ABC" nil)) + (tu-true "ssg-bt-name-passt-p/leer" (ssg-bt-name-passt-p "ABC" "")) + (tu-true "ssg-bt-name-passt-p/escape-ja" (ssg-bt-name-passt-p "A.B" "A`.B")) + (tu-nil "ssg-bt-name-passt-p/escape-nein" (ssg-bt-name-passt-p "AxB" "A`.B")) + (tu-eq "ssg-bt-muster-escape" "A`.B`#1" (ssg-bt-muster-escape "A.B#1")) + (tu-eq "ssg-bt-muster-anzeige" "A.B#1" (ssg-bt-muster-anzeige "A`.B`#1")) + (tu-eq "ssg-bt-zaehle-namen" + '(("Alpha" . 1) ("Beta" . 1) ("Zeta" . 3)) + (ssg-bt-zaehle-namen '("Zeta" "Alpha" "Zeta" "Beta" "Zeta"))) + (tu-nil "ssg-bt-zaehle-namen/leer" (ssg-bt-zaehle-namen nil)) + (tu-eq "ssg-bt-wert-neu/teil" "ABC_1" (ssg-bt-wert-neu "ABC-1" "-" "_" T)) + (tu-eq "ssg-bt-wert-neu/mehrfach" "a.b.c" (ssg-bt-wert-neu "a-b-c" "-" "." T)) + (tu-eq "ssg-bt-wert-neu/loeschen" "AC" (ssg-bt-wert-neu "ABC" "B" "" T)) + (tu-nil "ssg-bt-wert-neu/kein-treffer" (ssg-bt-wert-neu "ABC" "X" "y" T)) + (tu-eq "ssg-bt-wert-neu/gesamt-ja" "X" (ssg-bt-wert-neu "ABC" "ABC" "X" nil)) + (tu-nil "ssg-bt-wert-neu/gesamt-nein" (ssg-bt-wert-neu "ABCD" "ABC" "X" nil)) + (tu-nil "ssg-bt-wert-neu/leere-suche" (ssg-bt-wert-neu "ABC" "" "X" T)) + (tu-nil "ssg-bt-wert-neu/gross-klein" (ssg-bt-wert-neu "abc" "ABC" "X" T)) + + ;; --- ssg_texttools --- + (tu-eqf "ssg-tt-lesbarer-winkel/0" 0.0 (ssg-tt-lesbarer-winkel 0.0)) + (tu-eqf "ssg-tt-lesbarer-winkel/45" (/ pi 4.0) (ssg-tt-lesbarer-winkel (/ pi 4.0))) + (tu-eqf "ssg-tt-lesbarer-winkel/90" (/ pi 2.0) (ssg-tt-lesbarer-winkel (/ pi 2.0))) + (tu-eqf "ssg-tt-lesbarer-winkel/135" (* 1.75 pi) (ssg-tt-lesbarer-winkel (* 0.75 pi))) + (tu-eqf "ssg-tt-lesbarer-winkel/180" 0.0 (ssg-tt-lesbarer-winkel pi)) + (tu-eqf "ssg-tt-lesbarer-winkel/270" (/ pi 2.0) (ssg-tt-lesbarer-winkel (* 1.5 pi))) + (tu-eqf "ssg-tt-lesbarer-winkel/-45" (* 1.75 pi) (ssg-tt-lesbarer-winkel (- (/ pi 4.0)))) + (tu-eqf "ssg-tt-lesbarer-winkel/360" 0.0 (ssg-tt-lesbarer-winkel (* 2.0 pi))) + (tu-eqf "ssg-tt-versetzt/x" '(5.0 0.0 0.0) (ssg-tt-versetzt '(0.0 0.0 0.0) 0.0 5.0)) + (tu-eqf "ssg-tt-versetzt/y" '(0.0 2.0 0.0) (ssg-tt-versetzt '(0.0 0.0 0.0) (/ pi 2.0) 2.0)) + (tu-eqf "ssg-tt-versetzt/2d" '(1.0 4.0 0.0) (ssg-tt-versetzt '(1.0 1.0) (/ pi 2.0) 3.0)) + ) + ) +) + (defun c:TEST_UNIT ( / out-dir report) (tu-reset) (princ "\n================================================================") @@ -1589,7 +1660,8 @@ (foreach fn '("tu-tests-core" "tu-tests-lang" "tu-tests-id" "tu-tests-vfcore" "tu-tests-export" "tu-tests-gf" "tu-tests-omni" "tu-tests-kreisel" "tu-tests-sepliste" "tu-tests-json" "tu-tests-geruest" - "tu-tests-sepscan" "tu-tests-vfl-segs" "tu-tests-vfl-abbruch") + "tu-tests-sepscan" "tu-tests-vfl-segs" "tu-tests-vfl-abbruch" + "tu-tests-werkzeuge") (tu-run-block fn)) (princ "\n\n----------------------------------------------------------------") From 4d0d689815816b0ed79e7dc0172693a2c159d752 Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Wed, 7 Oct 2026 15:00:45 +0200 Subject: [PATCH 07/38] [ADD] Nachbau ILS-3.0-Showroom: tests/testdata/showroom_ils.json aus Showroom_ILS_3_0.dxf (6 Kreisel, 11 Gefaellestrecken, Separatoren/Scanner; Hoehen noch Platzhalter), Treiber tests/test_showroom_ils.lsp (TEST_SHOWROOM_ILS, Menue Tests -> ILS 3.0 Showroom), in alltests.json bis zu den Hoehen deaktiviert; [ADD] dxf_scan_components.py: --flach (waagrechte Staustrecken mit AS an genau einem Ende als GF), --kreisel-achse (Kreisel ohne AN8/SP8, z.B. Schleifen mit Weichenboegen), zerstueckelte Staustrecken-Linien werden vereint, ES am unteren Ende wird erkannt und verbraucht, AS/ES-Seite ohne Seitenangabe im Namen aus der Lage zur Fahrtrichtung, Kurznamen AE-*/EE-*; [FIX] Kreisel-Paarung: zwei Kreisel auf derselben Achse wurden ueber die Luecke gepaart (800 + 12832 statt 9033 + 3000) - Tausch-Nachbesserung auf minimale Abstandssumme; [CHANGE] test_dematic_arvato.lsp: Lauf als dematic_arvato:bau-datei herausgeloest (vom Showroom-Treiber mitgenutzt); [ADD] Tests in test_dxf_scan_gf.py Co-Authored-By: Claude Opus 5.5 --- doc/kommandos.md | 1 + lib/dxf_scan_components.py | 226 +++++++++++++++-- menu/SSG_LIB.cui | 44 ++-- menu/SSG_LIB.mnu | 1 + tests/alltests.json | 3 +- tests/test_dematic_arvato.lsp | 34 ++- tests/test_dxf_scan_gf.py | 94 +++++++ tests/test_showroom_ils.lsp | 58 +++++ tests/testdata/showroom_ils.json | 410 +++++++++++++++++++++++++++++++ 9 files changed, 824 insertions(+), 47 deletions(-) create mode 100644 tests/test_showroom_ils.lsp create mode 100644 tests/testdata/showroom_ils.json diff --git a/doc/kommandos.md b/doc/kommandos.md index 5419396..4da84b0 100644 --- a/doc/kommandos.md +++ b/doc/kommandos.md @@ -197,6 +197,7 @@ Aus dem Menue "Tests" bzw. der Kommandozeile; Details in `doc/LispTests.md`. | `TEST_HUNDM05` (`_2D`/`_3D`) | HundM05-Anlage aus der Spec bauen | | `TEST_MUBEA` | Mubea-Nachbau aus `tests/testdata/mubea.json` | | `TEST_DEMATIC_ARVATO` | Dematic/Arvato-Nachbau (Flowpuffer/Kreisel) | +| `TEST_SHOWROOM_ILS` | ILS-3.0-Showroom-Nachbau (Kreisel, Gefaellestrecken; Hoehen noch Platzhalter) | --- diff --git a/lib/dxf_scan_components.py b/lib/dxf_scan_components.py index 5b179de..7863a95 100644 --- a/lib/dxf_scan_components.py +++ b/lib/dxf_scan_components.py @@ -153,6 +153,15 @@ GF_LINIE_MIN_DZ = 100.0 # rechts), nicht der kleinste Abstand. GF_AS_MAX_ENTLANG = 2000.0 GF_AS_MAX_QUER = 700.0 +# Wie weit (mm) das AS/ES VOR dem Linienende liegen darf, also schon auf der +# Kreisel-Seite. In Dematic_arvato liegt es innerhalb der Linie; im +# Showroom_ILS_3_0-Plan endet die Staustrecke 305 mm vor dem Element, das auf +# der Kreisel-Kette sitzt. Kleiner als das Linienraster quer zur Kette +# (Nachbar-GF der Gegenrichtung lag dort 1200 mm entfernt). +GF_AS_MAX_VOR = 800.0 +# Toleranz (mm) fuer zusammenstossende Linienenden beim Zusammenfassen +# zerstueckelter Staustrecken (linien_zusammenfassen). +GF_LINIE_STOSS_TOL = 1.0 # Groesste Luecke (mm) zwischen Linienende und Kreisel-Kette, bis zu der die # Linie an diesen Kreisel angeschlossen wird. Gezeichnet ist nur die @@ -303,8 +312,9 @@ FAMILIEN = [ ("omniflo_weiche", ["Weiche *", "Weichen-TEF*"]), ("bogen", ["3D_ILS_Bogen_*", "3D_FF_Bogen_*", "TEF_Bogen_*", "tef30*", "tef90*"]), + # "AE-D"/"EE-R": Kurznamen der aelteren ILS-Plaene (Showroom_ILS_3_0.dxf) ("schleuselement", ["Ausschleuselement*", "Einschleuselement*", - "EE_Neu*", "AE_Neu*"]), + "EE_Neu*", "AE_Neu*", "AE-*", "EE-*"]), ("sensor", ["S-LP", "S-SP", "SCAN", "SCAN_*", "Scanner*", "Separator*", "Stopper*", "Stopperschleuse*"]), ] @@ -399,12 +409,12 @@ def mappe_block(bname): geraten) # Aus-/Einschleuselement -> AS_Element / ES_Element - if "ausschleus" in low or low.startswith("ae_"): + if "ausschleus" in low or low.startswith(("ae_", "ae-")): winkel, geschaetzt = winkel_aus_name(bname, DEFAULT_SCHLEUS_WINKEL) if geschaetzt: geraten.append("Winkel=%d" % winkel) return "AS_Element_%d_%s" % (winkel, seite_aus()), geraten - if "einschleus" in low or low.startswith("ee_"): + if "einschleus" in low or low.startswith(("ee_", "ee-")): winkel, geschaetzt = winkel_aus_name(bname, DEFAULT_SCHLEUS_WINKEL) if geschaetzt: geraten.append("Winkel=%d" % winkel) @@ -1047,17 +1057,25 @@ def kreisel_paare_bilden(an_liste, sp_liste): 19 m daneben gepaart). Zusaetzlich muessen beide auf einer gemeinsamen Achse liegen (Querversatz <= KREISEL_MAX_QUER). + Danach Tausch-Nachbesserung auf minimale Abstandssumme (siehe unten). + Rueckgabe: (paare [(an, sp, abstand)] nach AN-Position sortiert, AN8 ohne Partner, SP8 ohne Partner) """ + def abstand(an, sp): + """Mittenabstand, oder None wenn nicht auf gemeinsamer Achse.""" + dx = abs(sp["x"] - an["x"]) + dy = abs(sp["y"] - an["y"]) + if min(dx, dy) > KREISEL_MAX_QUER: + return None + return math.hypot(dx, dy) + 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)) + d = abstand(an, sp) + if d is not None: + kandidaten.append((d, ia, isp)) kandidaten.sort() an_frei = set(range(len(an_liste))) sp_frei = set(range(len(sp_liste))) @@ -1066,7 +1084,29 @@ def kreisel_paare_bilden(an_liste, sp_liste): 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.append([an_liste[ia], sp_liste[isp], dist]) + + # Nachbesserung: zwei Paare tauschen ihre SP8, solange die Summe der + # Abstaende dadurch kleiner wird. "Kuerzestes Paar zuerst" allein + # scheitert an zwei Kreiseln auf DERSELBEN Achse: die Luecke zwischen + # SP8 des einen und AN8 des anderen ist kuerzer als beide Kreisel und + # wird zuerst gepaart (Showroom_ILS_3_0: 800 + 12832 statt 9033 + 3000). + # Die echte Zuordnung hat immer die kleinere Summe - jede vertauschte + # Paarung ueberspannt mindestens eine Luecke doppelt. + verbessert = True + while verbessert: + verbessert = False + for i in range(len(paare)): + for j in range(i + 1, len(paare)): + a1, s1, d1 = paare[i] + a2, s2, d2 = paare[j] + n1, n2 = abstand(a1, s2), abstand(a2, s1) + if n1 is None or n2 is None or n1 + n2 >= d1 + d2 - 1e-6: + continue + paare[i] = [a1, s2, n1] + paare[j] = [a2, s1, n2] + verbessert = True + paare = [tuple(p) for p in paare] paare.sort(key=lambda p: (p[0]["x"], p[0]["y"])) return (paare, [an_liste[i] for i in sorted(an_frei)], @@ -1320,6 +1360,10 @@ def as_am_ende(p, richtung, as_liste, belegt): auf dieser Seite liegen - das trennt ihn vom Nachbar-AS der Linie daneben. Bereits vergebene AS (belegt = Menge von id()) zaehlen nicht. + Funktioniert genauso fuer Einschleuselemente am unteren Ende (es_liste in + gf_eintraege_aus_linien), dann mit der Richtung vom unteren Ende in die + Linie hinein. + Rueckgabe: (treffer, zielblock, geraten) oder None. """ beste = None @@ -1329,7 +1373,8 @@ def as_am_ende(p, richtung, as_liste, belegt): vx, vy = t["x"] - p[0], t["y"] - p[1] entlang = vx * richtung[0] + vy * richtung[1] quer = richtung[0] * vy - richtung[1] * vx - if not (0.0 <= entlang <= GF_AS_MAX_ENTLANG and abs(quer) <= GF_AS_MAX_QUER): + if not (-GF_AS_MAX_VOR <= entlang <= GF_AS_MAX_ENTLANG + and abs(quer) <= GF_AS_MAX_QUER): continue block, geraten = mappe_block(t["block"]) if "Seite=%s" % DEFAULT_SEITE not in (geraten or []): @@ -1376,8 +1421,78 @@ def kreisel_anschluss(p, richtung, kreisel): return beste +def linien_zusammenfassen(linien): + """Kollineare, aneinanderstossende Linien desselben Layers vereinen. + + Eine Staustrecke ist im Plan oft in Stuecke zerlegt (Showroom_ILS_3_0: + vier LINEs je GF, an den Separatoren getrennt). Als Einzelstuecke fehlte + jedem das AS am einen oder das ES am anderen Ende. Vereint wird nur bei + gleicher Richtung (in 3D) und Stoss innerhalb GF_LINIE_STOSS_TOL. + """ + def richtung(ln): + d = [ln["b"][i] - ln["a"][i] for i in range(3)] + n = math.sqrt(sum(c * c for c in d)) + return [c / n for c in d] if n else None + + def kollinear(r1, r2): + kreuz = (r1[1] * r2[2] - r1[2] * r2[1], r1[2] * r2[0] - r1[0] * r2[2], + r1[0] * r2[1] - r1[1] * r2[0]) + # 1e-3 rad (~0.06 Grad): die Plaene sind nicht exakt gezeichnet - + # im Showroom-Plan sitzt das Separatorstueck 0,3 mm neben der Achse, + # das verkippt das bis dahin vereinte Stueck um ~2.6e-4. + return math.sqrt(sum(c * c for c in kreuz)) < 1e-3 + + def gleich(p, q): + return math.dist(p, q) <= GF_LINIE_STOSS_TOL + + rest = [{"layer": ln["layer"], "a": list(ln["a"]), "b": list(ln["b"])} + for ln in linien] + fertig = [] + while rest: + akt = rest.pop(0) + gewachsen = True + while gewachsen: + gewachsen = False + ra = richtung(akt) + for ln in rest: + rb = richtung(ln) + if (ln["layer"] != akt["layer"] or ra is None or rb is None + or not kollinear(ra, rb)): + continue + # Die vier moeglichen Stoesse; das Ergebnis behaelt die + # beiden aeusseren Enden. + for p_akt, q_akt in (("a", "b"), ("b", "a")): + for p_ln, q_ln in (("a", "b"), ("b", "a")): + if gleich(akt[p_akt], ln[p_ln]): + akt = {"layer": akt["layer"], "a": akt[q_akt], + "b": ln[q_ln]} + gewachsen = True + break + if gewachsen: + break + if gewachsen: + rest.remove(ln) + break + fertig.append(akt) + return fertig + + +def seite_aus_lage(t, p, r): + """Seite eines AS/ES aus seiner Lage zur GF-Fahrtrichtung. + + t = Element, p = Punkt auf der Achse, r = Fahrtrichtung der GF (bergab). + Links der Fahrtrichtung -> "links", sonst "rechts" - dieselbe Zuordnung + wie in Dematic_arvato ("Ausschleuselement links" liegt links der + Fahrtrichtung, siehe as_am_ende). Nur fuer Bloecke ohne Seite im Namen + ("AE-D"/"EE-R"); gespiegelte Inserts landen dadurch automatisch auf der + Gegenseite. + """ + vx, vy = t["x"] - p[0], t["y"] - p[1] + return "links" if r[0] * vy - r[1] * vx > 0 else "rechts" + + def gf_eintraege_aus_linien(linien, as_liste, kreisel=None, sep_liste=None, - winkel_default=3.0): + winkel_default=3.0, es_liste=None, flach=False): """Gefaellestrecken (Modus 1, Schema 2.1) aus Staustrecken-Linien. Eine Gefaellestrecke laeuft immer bergab: Start ist das HOEHERE @@ -1407,15 +1522,35 @@ def gf_eintraege_aus_linien(linien, as_liste, kreisel=None, sep_liste=None, die Gefaellestrecke selbst mit, als Einzel-Insert stuenden sie doppelt in der Zeichnung (und im Sivas-Export). Der AS eines uebersprungenen Steigfoerderers bleibt unverbraucht. + + es_liste: Einschleuselemente; eines am unteren Ende liefert es_seite/ + es_winkel und wird ebenfalls verbraucht. Ohne es_liste bleiben beide + Defaults (Dematic_arvato hat kein ES im Plan). + + flach: 2D-Plan ohne Hoehen (alle Linien waagrecht, z.B. + Showroom_ILS_3_0). Dann ist eine waagrechte Linie eine GF, wenn genau an + EINEM Ende ein Ausschleuselement sitzt - dieses Ende ist oben. Ohne flach + werden waagrechte Linien wie bisher uebergangen. """ eintraege, hinweise = [], [] belegt = set() waagrecht = 0 kandidaten = [] - for ln in linien: + for ln in linien_zusammenfassen(linien): a, b = ln["a"], ln["b"] if abs(a[2] - b[2]) < GF_LINIE_MIN_DZ: - waagrecht += 1 + lxy = math.hypot(b[0] - a[0], b[1] - a[1]) + if not (flach and lxy > 0.0): + waagrecht += 1 + continue + r_ab = ((b[0] - a[0]) / lxy, (b[1] - a[1]) / lxy) + as_a = as_am_ende(a, r_ab, as_liste, belegt) + as_b = as_am_ende(b, (-r_ab[0], -r_ab[1]), as_liste, belegt) + if (as_a is None) == (as_b is None): + waagrecht += 1 + continue + hoch, tief = (a, b) if as_a is not None else (b, a) + kandidaten.append((hoch, tief, lxy, ln["layer"])) continue hoch, tief = (a, b) if a[2] > b[2] else (b, a) lxy = math.hypot(tief[0] - hoch[0], tief[1] - hoch[1]) @@ -1495,6 +1630,13 @@ def gf_eintraege_aus_linien(linien, as_liste, kreisel=None, sep_liste=None, belegt.add(id(t)) teile = block.split("_") # AS_Element__ eintrag["as_winkel"], eintrag["as_seite"] = teile[2], teile[3] + if "Seite=%s" % DEFAULT_SEITE in geraten: + eintrag["as_seite"] = seite_aus_lage(t, hoch, r) + geraten = [g for g in geraten if not g.startswith("Seite=")] + block = "AS_Element_%s_%s" % (eintrag["as_winkel"], + eintrag["as_seite"]) + kommentar += ("; as_seite %s aus der Lage zur Fahrtrichtung" + % eintrag["as_seite"]) kommentar += ("; AS aus Block '%s' bei (%.2f, %.2f) -> %s, als " "Einzel-Insert entfernt (baut die GF selbst)" % (t["block"], t["x"], t["y"], block)) @@ -1520,7 +1662,28 @@ def gf_eintraege_aus_linien(linien, as_liste, kreisel=None, sep_liste=None, kommentar += ("; Separator auf der Achse entfernt (die GF baut " "ihren eigenen): %s" % ", ".join(weg)) - kommentar += "; es_seite/es_winkel sind Defaults (kein ES im DXF)." + unten = (as_am_ende(tief, (-r[0], -r[1]), es_liste, belegt) + if es_liste else None) + if unten is not None: + t, block, geraten = unten + belegt.add(id(t)) + teile = block.split("_") # ES_Element__ + eintrag["es_winkel"], eintrag["es_seite"] = teile[2], teile[3] + if "Seite=%s" % DEFAULT_SEITE in geraten: + eintrag["es_seite"] = seite_aus_lage(t, tief, r) + geraten = [g for g in geraten if not g.startswith("Seite=")] + block = "ES_Element_%s_%s" % (eintrag["es_winkel"], + eintrag["es_seite"]) + kommentar += ("; es_seite %s aus der Lage zur Fahrtrichtung" + % eintrag["es_seite"]) + kommentar += ("; ES aus Block '%s' bei (%.2f, %.2f) -> %s, als " + "Einzel-Insert entfernt (baut die GF selbst)" + % (t["block"], t["x"], t["y"], block)) + if geraten: + kommentar += " - geraten: %s" % ", ".join(geraten) + kommentar += "." + else: + kommentar += "; es_seite/es_winkel sind Defaults (kein ES im DXF)." eintrag["comment"] = kommentar eintraege.append(eintrag) @@ -1532,12 +1695,20 @@ def gf_eintraege_aus_linien(linien, as_liste, kreisel=None, sep_liste=None, def baue_eintraege(treffer, defaults, boegen, weichen, - bekannte_bloecke=None, linien=None, kreisel_hoehen=None): + bekannte_bloecke=None, linien=None, kreisel_hoehen=None, + kreisel_achsen=None, flach=False): """Erkannte Vorkommen auf die Schemata aus object_data.md abbilden. kreisel_hoehen: Liste (x, y, z) vom Anwender - z gilt fuer den Kreisel, dessen Einfuegepunkt (Eintrag x/y) hoechstens KREISEL_HOEHE_TOL entfernt liegt, und fuer die Gefaellestrecken, die an ihm anschliessen. + + kreisel_achsen: Liste (x1, y1, x2, y2) vom Anwender - Radmitten eines + Kreisels ohne AN8/SP8 im Plan (Showroom_ILS_3_0: Schleifen, die an beiden + Enden mit Weichenboegen schliessen). Wird als STANDARD-Kreisel + angenaehert, x1/y1 gilt als AN8-Seite. + + flach: siehe gf_eintraege_aus_linien. """ nach_familie = {} for t in treffer: @@ -1555,6 +1726,12 @@ def baue_eintraege(treffer, defaults, boegen, weichen, 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 x1, y1, x2, y2 in kreisel_achsen or []: + an = {"block": "(manuell AN8)", "layer": "--kreisel-achse", + "x": x1, "y": y1, "z": 0.0, "darstellung": "2D"} + sp = {"block": "(manuell SP8)", "layer": "--kreisel-achse", + "x": x2, "y": y2, "z": 0.0, "darstellung": "2D"} + kreisel_paare.append((an, sp, math.hypot(x2 - x1, y2 - y1))) 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 @@ -1632,9 +1809,12 @@ def baue_eintraege(treffer, defaults, boegen, weichen, if linien: as_liste = [t for t in nach_familie.get("schleuselement", []) if mappe_block(t["block"])[0].startswith("AS_Element")] + es_liste = [t for t in nach_familie.get("schleuselement", []) + if mappe_block(t["block"])[0].startswith("ES_Element")] gf, belegt, gf_hinweise = gf_eintraege_aus_linien( linien, as_liste, kreisel_geo, nach_familie.get("sensor", []), - defaults.get("gefaelle", {}).get("default_winkel", 3.0)) + defaults.get("gefaelle", {}).get("default_winkel", 3.0), + es_liste, flach) eintraege.extend(gf) hinweise.extend(gf_hinweise) for familie in ("schleuselement", "sensor"): @@ -1873,6 +2053,17 @@ def main(): "(wie im Ausgabe-JSON); gilt auch fuer Start/Ende " "der daran anschliessenden Gefaellestrecken. " "Mehrfach angebbar") + parser.add_argument("--kreisel-achse", nargs=4, type=float, + action="append", metavar=("X1", "Y1", "X2", "Y2"), + help="Kreisel ohne AN8/SP8 im Plan (z.B. Schleife mit " + "Weichenboegen an beiden Enden): Radmitten der " + "beiden Enden, X1/Y1 = AN8-Seite. Wird als " + "STANDARD-Kreisel angenaehert. Mehrfach angebbar") + parser.add_argument("--flach", action="store_true", + help="2D-Plan ohne Hoehen: waagrechte Staustrecken-" + "Linien mit Ausschleuselement an genau einem " + "Ende als Gefaellestrecke ausgeben (Hoehen dann " + "ueber --kreisel-hoehe)") parser.add_argument("--projekt", help="Projektkennung in den erzeugten IDs " "(Default: Name der DXF-Datei ohne Endung)") @@ -1937,7 +2128,8 @@ def main(): eintraege, hinweise = baue_eintraege(treffer, defaults, boegen, weichen, bekannte_bloecke, linien, - args.kreisel_hoehe) + args.kreisel_hoehe, args.kreisel_achse, + args.flach) if args.ohne_hoehen: print("%s --ohne-hoehen: Hoehe in %d Eintraegen auf 0 gesetzt" % (PREFIX, hoehen_entfernen(eintraege))) diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 50aeee5..467be1c 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -741,48 +741,54 @@ + + ILS 3.0 Showroom (Vorlage) + ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) (c:TEST_SHOWROOM_ILS) + + + KS 2D/3D pruefen (CSV) ^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN - + Kreisel bearbeiten (ssg-ensure "KreiselInsert") KreiselEdit - + Omniflo Element bearbeiten (ssg-ensure "OmniModulInsert") OMNI_EDIT - + Gefaellestrecke bearbeiten (ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EDIT - + VarioFoerderer bearbeiten (ssg-ensure "VarioFoerderer") VARIOFOERDERER_EDIT - + TRO-Marker bearbeiten (ssg-ensure "Tro_Edit") TRO_EDIT - + Verbindung bearbeiten (ssg-ensure "Connection_Edit") CONNECTION_EDIT - + SSG Bearbeiten (Auto) (ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT @@ -1640,56 +1646,62 @@ - KS 2D/3D pruefen (CSV) + ILS 3.0 Showroom (Vorlage) + + KS 2D/3D pruefen (CSV) + + + + - + POP501 SSG_LIB Edit Context Kreisel bearbeiten - + Omniflo Element bearbeiten - + Gefaellestrecke bearbeiten - + VarioFoerderer bearbeiten - + TRO-Marker bearbeiten - + Verbindung bearbeiten - + SSG Bearbeiten (Auto) - + diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 703b508..7b7ed54 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -155,6 +155,7 @@ [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) +[ILS 3.0 Showroom (Vorlage)]^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) (c:TEST_SHOWROOM_ILS) [<-KS 2D/3D pruefen (CSV)]^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN ***DOUBLECLICK diff --git a/tests/alltests.json b/tests/alltests.json index f427384..d0caa14 100644 --- a/tests/alltests.json +++ b/tests/alltests.json @@ -11,5 +11,6 @@ { "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 } + { "name": "hm_recformat", "save": "dxf", "module": "VarioFoerderer", "disabled": true }, + { "name": "showroom_ils", "save": "dxf", "module": "VarioFoerderer", "disabled": true } ] diff --git a/tests/test_dematic_arvato.lsp b/tests/test_dematic_arvato.lsp index 6fcb57c..3583bec 100644 --- a/tests/test_dematic_arvato.lsp +++ b/tests/test_dematic_arvato.lsp @@ -255,25 +255,27 @@ "fehler_text" (vl-catch-all-error-message res))) res)) -(defun c:TEST_DEMATIC_ARVATO ( / datei daten out zaehler st) - (setq datei (dematic_arvato:datei)) +;; Alle Eintraege einer Nachbau-Datei bauen und die Records zurueckgeben +;; (nil bei Fehler vor dem Bau). Gemeinsamer Lauf fuer jeden Treiber mit +;; diesem Eintragsschema - auch tests/test_showroom_ils.lsp. +;; befehl = Name fuer Meldungen/ssg-start, titel = Kopfzeile, datei = JSON +(defun dematic_arvato:bau-datei (befehl titel datei / daten out records zaehler st) (princ "\n\n================================================================") - (princ "\n TEST_DEMATIC_ARVATO - Abschnitt Flowpuffer/Kreisel") + (princ (strcat "\n " befehl " - " titel)) (princ (strcat "\n " datei)) (princ "\n================================================================") (cond ((null (car (atoms-family 1 '("VSP-BAU-JOURNAL")))) - (princ "\n[TEST_DEMATIC_ARVATO] FEHLER: vf_spec.lsp nicht geladen" - " (VarioFoerderer laden).") - (setq *dematic-arvato-records* nil)) + (princ (strcat "\n[" befehl "] FEHLER: vf_spec.lsp nicht geladen" + " (VarioFoerderer laden).")) + nil) ((null (findfile datei)) - (princ (strcat "\n[TEST_DEMATIC_ARVATO] FEHLER: " datei " nicht gefunden!")) - (setq *dematic-arvato-records* nil)) + (princ (strcat "\n[" befehl "] FEHLER: " datei " nicht gefunden!")) + 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"))) + (ssg-start befehl '(("OSMODE") ("CECOLOR") ("ATTREQ") ("ATTDIA"))) (setvar "OSMODE" 0) (setvar "ATTREQ" 0) (setvar "ATTDIA" 0) @@ -285,10 +287,10 @@ (foreach obj daten (setq out (cons (dematic_arvato:bau-eintrag obj) out))) (ssg-end) - (setq *dematic-arvato-records* (reverse out)) + (setq records (reverse out)) ;; Zusammenfassung je Status (setq zaehler '()) - (foreach r *dematic-arvato-records* + (foreach r records (setq st (cond ((ssg-val r "status")) ("?"))) (if (assoc st zaehler) (setq zaehler (subst (cons st (1+ (cdr (assoc st zaehler)))) @@ -298,7 +300,13 @@ (foreach z (reverse zaehler) (princ (strcat "\n " (car z) ": " (itoa (cdr z))))) (princ "\n================================================================") - (command "_.ZOOM" "_E"))) + (command "_.ZOOM" "_E") + records))) + +(defun c:TEST_DEMATIC_ARVATO () + (setq *dematic-arvato-records* + (dematic_arvato:bau-datei "TEST_DEMATIC_ARVATO" "Abschnitt Flowpuffer/Kreisel" + (dematic_arvato:datei))) (princ)) ;; Ergebnis-Export (Konvention :export-results fuer test_run_all.lsp) diff --git a/tests/test_dxf_scan_gf.py b/tests/test_dxf_scan_gf.py index 65de3c1..25a9c0f 100644 --- a/tests/test_dxf_scan_gf.py +++ b/tests/test_dxf_scan_gf.py @@ -166,3 +166,97 @@ def test_ohne_as_defaults_und_hinweis(): assert eintraege[0]["hz_grad"] == 0.0 assert eintraege[0]["as_seite"] == dsc.DEFAULT_SEITE assert any("ohne Ausschleuselement" in h for h in hinweise) + + +# --- Showroom_ILS_3_0.dxf: flacher 2D-Plan, Werte dort gemessen ------------- + +def _station(x, y): + return {"x": x, "y": y} + + +def test_kreisel_paare_zwei_kreisel_auf_einer_achse(): + # x=26998: AN8 y=3466 / SP8 y=12499 und AN8 y=13299 / SP8 y=16299. Die + # Luecke SP8(12499)-AN8(13299) = 800 ist das kuerzeste Paar - ohne + # Tausch-Nachbesserung kamen 800 + 12833 statt 9033 + 3000 heraus. + an = [_station(26998.0, 3466.4), _station(26998.0, 13298.9)] + sp = [_station(26998.0, 16298.9), _station(26998.0, 12498.9)] + paare, an_rest, sp_rest = dsc.kreisel_paare_bilden(an, sp) + assert an_rest == [] and sp_rest == [] + abstaende = sorted(round(p[2], 1) for p in paare) + assert abstaende == [3000.0, 9032.5] + + +def test_zerstueckelte_linie_wird_vereint(): + # GF bei x=34006 in vier Stuecken, das Separatorstueck 0,3 mm daneben + stuecke = [ + _linie((34005.93, 13893.90, 0.0), (34005.93, 14193.90, 0.0)), + _linie((34005.93, 15043.90, 0.0), (34005.93, 15593.90, 0.0)), + _linie((34006.24, 14744.31, 0.0), (34006.24, 15044.31, 0.0)), + _linie((34005.93, 14193.90, 0.0), (34005.93, 14743.90, 0.0)), + ] + vereint = dsc.linien_zusammenfassen(stuecke) + assert len(vereint) == 1 + ys = sorted([vereint[0]["a"][1], vereint[0]["b"][1]]) + assert ys == pytest.approx([13893.90, 15593.90], abs=0.01) + + +def test_parallele_nachbarlinie_wird_nicht_vereint(): + linien = [_linie((0.0, 0.0, 0.0), (0.0, 1000.0, 0.0)), + _linie((800.0, 1000.0, 0.0), (800.0, 2000.0, 0.0))] + assert len(dsc.linien_zusammenfassen(linien)) == 2 + + +def _kreisel_d(): + # Schleife oben (Kette unten y=15898.9), Radmitten per --kreisel-achse + return {"id": "K_D", "a": (27797.93, 16298.9), "u": (1.0, 0.0), + "laenge": 8908.0, "r": 400.0, "z_anwender": None} + + +def _kreisel_e(): + # Schleife Mitte (Kette oben y=13493.9) + return {"id": "K_E", "a": (28772.93, 13093.9), "u": (1.0, 0.0), + "laenge": 6533.0, "r": 400.0, "z_anwender": None} + + +def test_flacher_plan_richtung_und_seiten_aus_as_es(): + # Waagrechte Linie; AE-D sitzt 305 mm VOR dem oberen Ende auf der + # Kreisel-Kette, 180 mm links der Fahrtrichtung (Fahrt -y, links = +x). + # EE-R am unteren Ende 212 mm rechts davon. + linie = _linie((30455.93, 13893.9, 0.0), (30455.93, 15593.9, 0.0)) + ae = {"familie": "schleuselement", "block": "AE-D", + "x": 30636.27, "y": 15898.9, "z": 0.0, "rot": 270.0} + ee = {"familie": "schleuselement", "block": "EE-R", + "x": 30243.76, "y": 13493.9, "z": 0.0, "rot": 90.0} + eintraege, belegt, _ = dsc.gf_eintraege_aus_linien( + [linie], [ae], [_kreisel_d(), _kreisel_e()], es_liste=[ee], flach=True) + assert len(eintraege) == 1 + gf = eintraege[0] + assert gf["hz_grad"] == 270.0 + assert gf["start_mm"][:2] == [30455.93, 15898.9] + assert gf["deltaL_mm"] == pytest.approx(2405.0, abs=0.01) + assert (gf["as_seite"], gf["es_seite"]) == ("links", "rechts") + assert (gf["kreisel_start"], gf["kreisel_ende"]) == ("K_D", "K_E") + assert belegt == {id(ae), id(ee)} + + +def test_flacher_plan_ohne_flach_schalter_keine_gf(): + linie = _linie((30455.93, 13893.9, 0.0), (30455.93, 15593.9, 0.0)) + ae = {"familie": "schleuselement", "block": "AE-D", + "x": 30636.27, "y": 15898.9, "z": 0.0, "rot": 270.0} + eintraege, _, _ = dsc.gf_eintraege_aus_linien([linie], [ae]) + assert eintraege == [] + + +def test_flacher_plan_ohne_as_keine_gf(): + # Staulinie am Kreisel B (x=36348) - kein AS an einem Ende + linie = _linie((36347.6, 11313.9, 0.0), (36347.6, 14913.9, 0.0)) + eintraege, _, hinweise = dsc.gf_eintraege_aus_linien([linie], [], flach=True) + assert eintraege == [] + assert any("waagrechte" in h for h in hinweise) + + +def test_kurznamen_ae_ee(): + assert dsc.familie_von("AE-D") == "schleuselement" + assert dsc.familie_von("EE-R") == "schleuselement" + assert dsc.mappe_block("AE-D")[0].startswith("AS_Element_90_") + assert dsc.mappe_block("EE-R")[0].startswith("ES_Element_90_") diff --git a/tests/test_showroom_ils.lsp b/tests/test_showroom_ils.lsp new file mode 100644 index 0000000..8e20f8a --- /dev/null +++ b/tests/test_showroom_ils.lsp @@ -0,0 +1,58 @@ +;; ============================================================ +;; test_showroom_ils.lsp - Nachbau des ILS-3.0-Showrooms. +;; +;; Datenquelle: tests/testdata/showroom_ils.json, erzeugt aus der +;; Fremdzeichnung (flacher 2D-Plan, keine Hoehen): +;; python lib/dxf_scan_components.py \ +;; C:/develop/sps_skel/data/Showroom_ILS_3_0.dxf data \ +;; tests/testdata/showroom_ils.json --projekt Showroom \ +;; --flach --ohne-hoehen \ +;; --kreisel-achse 27797.93 16298.90 36705.93 16298.90 \ +;; --kreisel-achse 28772.93 13093.90 35305.93 13093.90 +;; +;; Inhalt: 6 Kreisel, 11 Gefaellestrecken (Modus 1), Separatoren/Scanner. +;; - Kreisel_Showroom_05/06 sind Schleifen ohne AN8/SP8 im Plan (an beiden +;; Enden Weichenboegen) - per --kreisel-achse als STANDARD-Kreisel +;; angenaehert (Radmitten = Mittelpunkte der PIN-Kreise). +;; - Weichen (WB-*/WM-*/WL-*/WR-*) werden bewusst NICHT nachgebaut. +;; - HOEHEN FEHLEN NOCH: alle z = 0, die GF laufen mit dem Platzhalter +;; winkel_grad 3.0. Sobald die Kreisel-Hoehen bekannt sind, den Scanner +;; mit --kreisel-hoehe X Y Z je Kreisel neu laufen lassen - dann bekommen +;; die GF start_mm.z/hoehe_ende_mm und der Treiber rechnet den Winkel. +;; +;; Keine eigene Bau-Logik: Eintragsschema und Lauf wie TEST_DEMATIC_ARVATO +;; (dematic_arvato:bau-datei aus tests/test_dematic_arvato.lsp). +;; +;; Aufruf in BricsCAD: +;; (load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) +;; TEST_SHOWROOM_ILS +;; ============================================================ + +(if (not (boundp '*showroom-ils-records*)) (setq *showroom-ils-records* nil)) + +;; Beim LADEN holen (siehe test_dematic_arvato.lsp: per load definierte +;; Funktionen sind erst nach Rueckkehr zum Top-Level sichtbar). +(if (null (car (atoms-family 1 '("DEMATIC_ARVATO:BAU-DATEI")))) + (load (strcat (getenv "DXFMAKRO") "/tests/test_dematic_arvato.lsp"))) + +(defun showroom_ils:datei () + (strcat (getenv "DXFMAKRO") "/tests/testdata/showroom_ils.json")) + +(defun c:TEST_SHOWROOM_ILS () + (setq *showroom-ils-records* + (dematic_arvato:bau-datei "TEST_SHOWROOM_ILS" "ILS 3.0 Showroom" + (showroom_ils:datei))) + (princ)) + +;; Ergebnis-Export (Konvention :export-results fuer test_run_all.lsp) +(defun showroom_ils:export-results (out-dir / pfad) + (if (null *showroom-ils-records*) + (princ "\n Keine Showroom-Ergebnisse vorhanden.") + (progn + (vl-mkdir out-dir) + (setq pfad (strcat out-dir "/showroom_ils_results.json")) + (vsp-results-schreiben *showroom-ils-records* pfad))) + (princ)) + +(princ "\nTEST_SHOWROOM_ILS geladen. Aufruf: TEST_SHOWROOM_ILS") +(princ) diff --git a/tests/testdata/showroom_ils.json b/tests/testdata/showroom_ils.json new file mode 100644 index 0000000..81e9af7 --- /dev/null +++ b/tests/testdata/showroom_ils.json @@ -0,0 +1,410 @@ +[ + { + "id": "Kreisel_Showroom_01", + "function": "insert", + "x": 26997.93, + "y": 3066.4, + "z": 0.0, + "abstand": 9032.5, + "rotation": 90.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 3466.40) -> SP8 (Layer 1SP-800) (26997.93, 12498.90), Mittenabstand 9032.50, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. [Hoehe entfernt: --ohne-hoehen]", + "hoehe_unbekannt": true + }, + { + "id": "Kreisel_Showroom_02", + "function": "insert", + "x": 26997.93, + "y": 12898.9, + "z": 0.0, + "abstand": 3000.0, + "rotation": 90.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 13298.90) -> SP8 (Layer 1SP-800) (26997.93, 16298.90), Mittenabstand 3000.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. [Hoehe entfernt: --ohne-hoehen]", + "hoehe_unbekannt": true + }, + { + "id": "Kreisel_Showroom_03", + "function": "insert", + "x": 37105.93, + "y": 9888.9, + "z": 0.0, + "abstand": 7200.0, + "rotation": 180.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (36705.93, 9888.90) -> SP8 (Layer 1SP-800) (29505.93, 9888.90), Mittenabstand 7200.00, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. [Hoehe entfernt: --ohne-hoehen]", + "hoehe_unbekannt": true + }, + { + "id": "Kreisel_Showroom_04", + "function": "insert", + "x": 36705.93, + "y": 10288.9, + "z": 0.0, + "abstand": 4810.0, + "rotation": 90.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (36705.93, 10688.90) -> SP8 (Layer 1SP-800) (36705.93, 15498.90), Mittenabstand 4810.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. [Hoehe entfernt: --ohne-hoehen]", + "hoehe_unbekannt": true + }, + { + "id": "Kreisel_Showroom_05", + "function": "insert", + "x": 27397.93, + "y": 16298.9, + "z": 0.0, + "abstand": 8908.0, + "rotation": 0.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (27797.93, 16298.90) -> (manuell SP8) (Layer --kreisel-achse) (36705.93, 16298.90), Mittenabstand 8908.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe.", + "hoehe_unbekannt": true + }, + { + "id": "Kreisel_Showroom_06", + "function": "insert", + "x": 28372.93, + "y": 13093.9, + "z": 0.0, + "abstand": 6533.0, + "rotation": 0.0, + "typ": "STANDARD", + "darstellung": "2D", + "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (28772.93, 13093.90) -> (manuell SP8) (Layer --kreisel-achse) (35305.93, 13093.90), Mittenabstand 6533.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe.", + "hoehe_unbekannt": true + }, + { + "test_id": "GF_Showroom_01", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [30455.93, 15898.9, 0.0], + "as_seite": "links", + "es_seite": "rechts", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_05", + "kreisel_ende": "Kreisel_Showroom_06", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (30455.93, 15593.90) -> (30455.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (30636.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (30456, 13994), S-SP bei (30456, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (30243.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_02", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [31255.93, 12693.9, 0.0], + "as_seite": "rechts", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_06", + "kreisel_ende": "Kreisel_Showroom_03", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (31255.93, 12388.90) -> (31255.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31075.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (31256, 10789), S-SP bei (31256, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31468.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_03", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [31255.93, 15898.9, 0.0], + "as_seite": "links", + "es_seite": "rechts", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_05", + "kreisel_ende": "Kreisel_Showroom_06", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (31255.93, 15593.90) -> (31255.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31436.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (31256, 13994), S-SP bei (31256, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31043.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_04", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [32055.93, 12693.9, 0.0], + "as_seite": "rechts", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_06", + "kreisel_ende": "Kreisel_Showroom_03", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (32055.93, 12388.90) -> (32055.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31875.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (32056, 10789), S-SP bei (32056, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (32268.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_05", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [32055.93, 15898.9, 0.0], + "as_seite": "links", + "es_seite": "rechts", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_05", + "kreisel_ende": "Kreisel_Showroom_06", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (32055.93, 15593.90) -> (32055.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (32236.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (32056, 13994), S-SP bei (32056, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31843.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_06", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [33205.93, 12693.9, 0.0], + "as_seite": "rechts", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_06", + "kreisel_ende": "Kreisel_Showroom_03", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (33205.93, 12388.90) -> (33205.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33025.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (33206, 10789), S-SP bei (33206, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (33418.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_07", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [33205.93, 15898.9, 0.0], + "as_seite": "links", + "es_seite": "rechts", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_05", + "kreisel_ende": "Kreisel_Showroom_06", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (33205.93, 15593.90) -> (33205.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33386.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (33206, 13994), S-SP bei (33206, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (32993.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_08", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [34005.93, 12693.9, 0.0], + "as_seite": "rechts", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_06", + "kreisel_ende": "Kreisel_Showroom_03", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (34005.93, 12388.90) -> (34005.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33825.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34006, 10789), S-SP bei (34006, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (34218.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_09", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [34005.93, 15898.9, 0.0], + "as_seite": "links", + "es_seite": "rechts", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_05", + "kreisel_ende": "Kreisel_Showroom_06", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (34005.93, 15593.90) -> (34005.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34186.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34006, 13994), S-SP bei (34006, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (33793.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_10", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [34805.93, 12693.9, 0.0], + "as_seite": "rechts", + "es_seite": "links", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_06", + "kreisel_ende": "Kreisel_Showroom_03", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (34805.93, 12388.90) -> (34805.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34625.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34806, 10789), S-SP bei (34806, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (35018.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "test_id": "GF_Showroom_11", + "modus": 1, + "deltaL_mm": 2405.0, + "hz_grad": 270.0, + "start_mm": [34805.93, 15898.9, 0.0], + "as_seite": "links", + "es_seite": "rechts", + "as_winkel": "90", + "es_winkel": "90", + "kreisel_start": "Kreisel_Showroom_05", + "kreisel_ende": "Kreisel_Showroom_06", + "winkel_grad": 3.0, + "hoehe_unbekannt": true, + "comment": "aus DXF: LINE auf Layer '6-SP' (34805.93, 15593.90) -> (34805.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34986.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34806, 13994), S-SP bei (34806, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (34593.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + }, + { + "function": "insert", + "block": "S-LP", + "x": 26597.93, + "y": 11973.9, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "S-LP", + "x": 26597.93, + "y": 13982.92, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "S-LP", + "x": 27397.93, + "y": 5450.07, + "z": 0.0, + "rotation": 90.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "S-LP", + "x": 27397.93, + "y": 15773.9, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "S-LP", + "x": 29397.93, + "y": 13493.9, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "S-LP", + "x": 30343.39, + "y": 9488.9, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "S-LP", + "x": 32083.74, + "y": 9488.9, + "z": 0.0, + "rotation": 0.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "S-LP", + "x": 35905.93, + "y": 10288.9, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "S-LP", + "x": 37105.93, + "y": 14978.9, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "Scanner", + "x": 29398.73, + "y": 13176.71, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "Scanner", + "x": 30343.39, + "y": 9208.9, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "Scanner", + "x": 32083.74, + "y": 9208.9, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "Scanner", + "x": 35905.93, + "y": 10008.9, + "z": 0.0, + "rotation": 270.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + }, + { + "function": "insert", + "block": "Scanner", + "x": 36825.93, + "y": 14978.9, + "z": 0.0, + "rotation": 180.0, + "darstellung": "2D", + "hoehe_unbekannt": true, + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + } +] From 8885b5c96ac528dbc3499e82d00b68cb315610ce Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Wed, 7 Oct 2026 15:23:39 +0200 Subject: [PATCH 08/38] [ADD] dxf_scan_components.py: Separatoren/Scanner auf einer Kreisel-Kette uebernehmen dessen Anwender-Hoehe (sensor_hoehen_von_kreiseln, bei --kreisel-hoehe) + Tests; [FIX] GF-Winkel aus Kreisel-Hoehen (dematic_arvato:gf-winkel): Modus 1 haelt die horizontale Laenge fest - Abfall = (deltaL - aus-dx - ein-dx) * tan(w) statt asin-Naeherung von gf-winkel-berechnen, ES-Abfall beim aktuellen Winkel gemessen und iteriert (steile GF wie Showroom ~37 Grad endeten sonst weit unter dem Kreisel); [CHANGE] Showroom ILS: Testdaten und Treiber aktualisiert Co-Authored-By: Claude Opus 5.5 --- lib/dxf_scan_components.py | 53 +++++++ tests/test_dematic_arvato.lsp | 66 +++++++-- tests/test_dxf_scan_gf.py | 26 ++++ tests/test_showroom_ils.lsp | 37 +++-- tests/testdata/showroom_ils.json | 238 ++++++++++++++----------------- 5 files changed, 267 insertions(+), 153 deletions(-) diff --git a/lib/dxf_scan_components.py b/lib/dxf_scan_components.py index 7863a95..fc03960 100644 --- a/lib/dxf_scan_components.py +++ b/lib/dxf_scan_components.py @@ -1973,6 +1973,53 @@ def hoehen_entfernen(eintraege): return n +# Querabstand (mm) zur Kreisel-Kette, bis zu dem ein Einzelteil (Separator, +# Scanner) als "auf dem Kreisel" gilt und dessen Anwender-Hoehe bekommt. +SENSOR_KETTE_MAX_QUER = 350.0 + + +def sensor_hoehen_von_kreiseln(eintraege, durchmesser=800.0): + """Einzelteile auf einer Kreisel-Kette bekommen dessen Anwender-Hoehe. + + Im flachen 2D-Plan (--ohne-hoehen) stehen Separatoren/Scanner sonst auf + Z=0, waehrend der Kreisel per --kreisel-hoehe auf seiner Hoehe sitzt. + Kette = Achse (Einfuegepunkt + Radius entlang rotation, Laenge abstand) + im Abstand r beidseits, plus die Halbkreise an den Enden. Nur Kreisel mit + hoehe_quelle "Anwender"; bei mehreren gewinnt der naechste. + + Rueckgabe: Anzahl gesetzter Hoehen. + """ + r = durchmesser / 2.0 + kreisel = [] + for e in eintraege: + if "abstand" in e and e.get("hoehe_quelle") == "Anwender": + w = math.radians(e.get("rotation", 0.0)) + u = (math.cos(w), math.sin(w)) + a = (e["x"] + r * u[0], e["y"] + r * u[1]) + kreisel.append((e, a, u, float(e["abstand"]))) + gesetzt = 0 + for e in eintraege: + if e.get("function") != "insert" or "block" not in e: + continue + beste = None + for k, a, u, laenge in kreisel: + vx, vy = e["x"] - a[0], e["y"] - a[1] + t = max(0.0, min(laenge, vx * u[0] + vy * u[1])) + # Abstand zur Achse (Strecke), davon r abgezogen = Abstand zur Kette + d = abs(math.hypot(vx - t * u[0], vy - t * u[1]) - r) + if d <= SENSOR_KETTE_MAX_QUER and (beste is None or d < beste[0]): + beste = (d, k) + if beste: + k = beste[1] + e["z"] = float(k["z"]) + e["hoehe_quelle"] = "Anwender" + e.pop("hoehe_unbekannt", None) + e["comment"] += " Hoehe %.1f von %s (liegt auf dessen Kette)." % ( + k["z"], k["id"]) + gesetzt += 1 + return gesetzt + + def arrays_einzeilig(text): """Zahlen-Arrays im JSON-Text auf eine Zeile ziehen. @@ -2133,6 +2180,12 @@ def main(): if args.ohne_hoehen: print("%s --ohne-hoehen: Hoehe in %d Eintraegen auf 0 gesetzt" % (PREFIX, hoehen_entfernen(eintraege))) + if args.kreisel_hoehe: + print("%s Einzelteile auf Kreisel-Ketten: Hoehe in %d Eintraegen vom " + "Kreisel uebernommen" + % (PREFIX, sensor_hoehen_von_kreiseln( + eintraege, + defaults.get("kreisel", {}).get("durchmesser", 800.0)))) if fenster: vorher = len(eintraege) diff --git a/tests/test_dematic_arvato.lsp b/tests/test_dematic_arvato.lsp index 3583bec..de1db72 100644 --- a/tests/test_dematic_arvato.lsp +++ b/tests/test_dematic_arvato.lsp @@ -109,16 +109,38 @@ ;; Mit der VF-Konvention wurde der feste AS/ES-Abfall addiert statt ;; abgezogen - real gebaut: 3.79 statt ~2.49 Grad, GF endete 258 mm unter ;; dem Kreisel (HOEHE_BIS 1568 statt 1826). Darum hier der Betrag. +;; +;; NICHT gf-winkel-berechnen: dessen asin(dH / L) behandelt die Laenge als +;; SCHRAEGE Laenge (richtig fuer Modus 3). Modus 1 haelt aber die +;; HORIZONTALE Laenge deltaL fest und streckt die Staustrecke um 1/cos(w) +;; (mubea:gf-bauen) - der Abfall der Schraege (Staustrecke + Separator) ist +;; dann genau (deltaL - aus-dx - ein-dx) * tan(w). Bei 2-3 Grad (Dematic) +;; ist das gleich, bei steilen GF nicht: Showroom_ILS_3_0 faellt 1860 mm auf +;; 2405 mm (~37 Grad), asin ergab ~50 Grad und die GF endete weit unter dem +;; unteren Kreisel. Der Abfall des ES haengt von der Einlaufneigung ab - er +;; wird wie in Modus 3 (gf-messe-dz-block) beim aktuellen Winkel gemessen +;; und iteriert; das AS liegt flach, sein Abfall ist fest (aus-dz). (defun dematic_arvato:gf-winkel (deltaL hz as-seite es-seite as-winkel es-winkel - z-start z-ende / winkel) + z-start z-ende / L dz-as dz-es winkel vorher + iter rad-h rad-v) (mubea:ensure-gf-init) (vf-set-as-masse as-winkel as-seite) (vf-set-es-masse es-winkel es-seite) - (setq aus-dz (abs (float aus-dz)) ein-dz (abs (float ein-dz))) - (setq winkel - (gf-winkel-berechnen - (list (list "Linie" hz (- deltaL (float aus-dx) (float ein-dx) 300.0) 0 "links")) - (- z-start z-ende) 1)) + (setq L (- deltaL (float aus-dx) (float ein-dx)) + dz-as (abs (float aus-dz)) + dz-es (abs (float ein-dz)) + rad-h (* hz (/ pi 180.0)) + vorher -999.0 + iter 0) + (setq winkel (* (atan (- z-start z-ende dz-as dz-es) L) (/ 180.0 pi))) + (while (and (< iter 6) (> (abs (- winkel vorher)) 0.001)) + (setq vorher winkel + rad-v (* winkel (/ pi 180.0))) + (setq dz-es (gf-messe-dz-block (strcat "ES_Element_" es-winkel "_" es-seite) + (list (* (cos rad-h) (cos rad-v)) (* (sin rad-h) (cos rad-v)) + (- (sin rad-v))))) + (setq winkel (* (atan (- z-start z-ende dz-as dz-es) L) (/ 180.0 pi)) + iter (1+ iter))) (vf-set-as-masse "90" as-seite) (vf-set-es-masse "90" es-seite) winkel) @@ -171,10 +193,34 @@ (strcat " aus Hoehe " (rtos (caddr start) 2 1) " -> " (rtos z-ende 2 1)) ""))))) - (dematic_arvato:rec-block rec - (mubea:gf-bauen tid (mapcar 'float start) (float deltaL) (float hz) - as-seite es-seite as-winkel es-winkel winkel) - "gefaellestrecke-einfuegen lieferte keinen GF-Block")))) + (setq rec + (dematic_arvato:rec-block rec + (mubea:gf-bauen tid (mapcar 'float start) (float deltaL) (float hz) + as-seite es-seite as-winkel es-winkel winkel) + "gefaellestrecke-einfuegen lieferte keinen GF-Block")) + ;; Ist-Endhoehe gegen den Kreisel am Ende pruefen + (dematic_arvato:gf-endhoehe-pruefen rec z-ende)))) + +;; HOEHE_BIS_mm des gebauten GF-Blocks mit der Soll-Endhoehe vergleichen; +;; mehr als 5 mm daneben -> status "warnung" + Meldung (die GF trifft den +;; unteren Kreisel nicht). +(defun dematic_arvato:gf-endhoehe-pruefen (rec z-ende / ist diff) + (setq ist (cdr (assoc "HOEHE_BIS_mm" (ssg-val rec "attribs")))) + (cond + ((not (and (numberp z-ende) ist (= (ssg-val rec "status") "executed"))) rec) + (T + (setq diff (- (atof ist) z-ende)) + (setq rec (vsp-set rec "meldungen" + (append (ssg-val rec "meldungen") + (list (strcat "HOEHE_BIS " ist " (Soll " + (rtos z-ende 2 0) ", Abweichung " + (rtos diff 2 0) " mm)"))))) + (if (> (abs diff) 5.0) + (progn + (princ (strcat "\n WARNUNG: GF endet bei " ist " statt " + (rtos z-ende 2 0))) + (vsp-set rec "status" "warnung")) + rec)))) ;; VarioFoerderer "standard"/"etage" - mubea-Schema, Bau ueber ;; mubea:vario-bauen. "motorseite" wirkt wie im Edit-Dialog ueber den diff --git a/tests/test_dxf_scan_gf.py b/tests/test_dxf_scan_gf.py index 25a9c0f..3768974 100644 --- a/tests/test_dxf_scan_gf.py +++ b/tests/test_dxf_scan_gf.py @@ -260,3 +260,29 @@ def test_kurznamen_ae_ee(): assert dsc.familie_von("EE-R") == "schleuselement" assert dsc.mappe_block("AE-D")[0].startswith("AS_Element_90_") assert dsc.mappe_block("EE-R")[0].startswith("ES_Element_90_") + + +def test_sensor_bekommt_hoehe_des_kreisels(): + # Kreisel_Showroom_03: Einfuegepunkt (37105.93, 9888.9), rotation 180, + # Ketten y=9488.9/10288.9. Separator auf der Kette, Scanner 280 mm + # innerhalb, ein Teil 1000 mm daneben bleibt unberuehrt. + kreisel = {"id": "K3", "x": 37105.93, "y": 9888.9, "z": 1700.0, + "abstand": 7200.0, "rotation": 180.0, "hoehe_quelle": "Anwender"} + sep = {"function": "insert", "block": "S-LP", "x": 30343.39, "y": 9488.9, + "z": 0.0, "hoehe_unbekannt": True, "comment": ""} + scan = {"function": "insert", "block": "Scanner", "x": 35905.93, + "y": 10008.9, "z": 0.0, "comment": ""} + weit = {"function": "insert", "block": "S-LP", "x": 33000.0, "y": 11300.0, + "z": 0.0, "comment": ""} + assert dsc.sensor_hoehen_von_kreiseln([kreisel, sep, scan, weit]) == 2 + assert sep["z"] == 1700.0 and "hoehe_unbekannt" not in sep + assert scan["z"] == 1700.0 + assert weit["z"] == 0.0 + + +def test_sensor_ohne_anwender_hoehe_bleibt(): + kreisel = {"id": "K", "x": 0.0, "y": 0.0, "z": 0.0, "abstand": 5000.0, + "rotation": 0.0} + sep = {"function": "insert", "block": "S-LP", "x": 1000.0, "y": 400.0, + "z": 0.0, "comment": ""} + assert dsc.sensor_hoehen_von_kreiseln([kreisel, sep]) == 0 diff --git a/tests/test_showroom_ils.lsp b/tests/test_showroom_ils.lsp index 8e20f8a..0ff80b7 100644 --- a/tests/test_showroom_ils.lsp +++ b/tests/test_showroom_ils.lsp @@ -1,24 +1,35 @@ ;; ============================================================ ;; test_showroom_ils.lsp - Nachbau des ILS-3.0-Showrooms. ;; -;; Datenquelle: tests/testdata/showroom_ils.json, erzeugt aus der -;; Fremdzeichnung (flacher 2D-Plan, keine Hoehen): -;; python lib/dxf_scan_components.py \ -;; C:/develop/sps_skel/data/Showroom_ILS_3_0.dxf data \ -;; tests/testdata/showroom_ils.json --projekt Showroom \ -;; --flach --ohne-hoehen \ -;; --kreisel-achse 27797.93 16298.90 36705.93 16298.90 \ -;; --kreisel-achse 28772.93 13093.90 35305.93 13093.90 +;; Datenquelle: tests/testdata/showroom_ils.json. Entstehung in zwei Stufen: +;; 1. Scanner auf der Fremdzeichnung (flacher 2D-Plan, Hoehen vom Anwender): +;; python lib/dxf_scan_components.py \ +;; C:/develop/sps_skel/data/Showroom_ILS_3_0.dxf data \ +;; tests/testdata/showroom_ils.json --projekt Showroom \ +;; --flach --ohne-hoehen \ +;; --kreisel-achse 27797.93 16298.90 36705.93 16298.90 \ +;; --kreisel-achse 28772.93 13093.90 35305.93 13093.90 \ +;; --kreisel-hoehe 26997.93 3066.4 5055 \ +;; --kreisel-hoehe 26997.93 12898.9 5055 \ +;; --kreisel-hoehe 37105.93 9888.9 1700 \ +;; --kreisel-hoehe 27397.93 16298.9 5055 \ +;; --kreisel-hoehe 28372.93 13093.9 3195 +;; 2. VON HAND (geht bei Stufe 1 verloren - danach neu eintragen): +;; Kreisel_Showroom_04 (vertikal, rechts) samt Separator/Scanner bei +;; y=14979 entfernt, dafuer VF_Showroom_01 (VarioFoerderer standard, +;; Auf von Kreisel_Showroom_03 zu Kreisel_Showroom_05) eingetragen. ;; -;; Inhalt: 6 Kreisel, 11 Gefaellestrecken (Modus 1), Separatoren/Scanner. +;; Inhalt: 5 Kreisel, 1 VarioFoerderer, 11 Gefaellestrecken (Modus 1), +;; Separatoren/Scanner. +;; - Ebenen: oben 5055 (Kreisel 01/02/05), Mitte 3195 (06), unten 1700 (03). ;; - Kreisel_Showroom_05/06 sind Schleifen ohne AN8/SP8 im Plan (an beiden ;; Enden Weichenboegen) - per --kreisel-achse als STANDARD-Kreisel ;; angenaehert (Radmitten = Mittelpunkte der PIN-Kreise). ;; - Weichen (WB-*/WM-*/WL-*/WR-*) werden bewusst NICHT nachgebaut. -;; - HOEHEN FEHLEN NOCH: alle z = 0, die GF laufen mit dem Platzhalter -;; winkel_grad 3.0. Sobald die Kreisel-Hoehen bekannt sind, den Scanner -;; mit --kreisel-hoehe X Y Z je Kreisel neu laufen lassen - dann bekommen -;; die GF start_mm.z/hoehe_ende_mm und der Treiber rechnet den Winkel. +;; - Die GF sind steil (1860 bzw. 1495 mm Abfall auf 2405 mm) - den Winkel +;; rechnet dematic_arvato:gf-winkel aus hoehe_ende_mm, und +;; dematic_arvato:gf-endhoehe-pruefen meldet "warnung", wenn eine GF +;; den unteren Kreisel um mehr als 5 mm verfehlt. ;; ;; Keine eigene Bau-Logik: Eintragsschema und Lauf wie TEST_DEMATIC_ARVATO ;; (dematic_arvato:bau-datei aus tests/test_dematic_arvato.lsp). diff --git a/tests/testdata/showroom_ils.json b/tests/testdata/showroom_ils.json index 81e9af7..b46510c 100644 --- a/tests/testdata/showroom_ils.json +++ b/tests/testdata/showroom_ils.json @@ -4,407 +4,385 @@ "function": "insert", "x": 26997.93, "y": 3066.4, - "z": 0.0, + "z": 5055.0, "abstand": 9032.5, "rotation": 90.0, "typ": "STANDARD", "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 3466.40) -> SP8 (Layer 1SP-800) (26997.93, 12498.90), Mittenabstand 9032.50, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. [Hoehe entfernt: --ohne-hoehen]", - "hoehe_unbekannt": true + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 3466.40) -> SP8 (Layer 1SP-800) (26997.93, 12498.90), Mittenabstand 9032.50, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 5055.0 vom Anwender.", + "hoehe_quelle": "Anwender" }, { "id": "Kreisel_Showroom_02", "function": "insert", "x": 26997.93, "y": 12898.9, - "z": 0.0, + "z": 5055.0, "abstand": 3000.0, "rotation": 90.0, "typ": "STANDARD", "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 13298.90) -> SP8 (Layer 1SP-800) (26997.93, 16298.90), Mittenabstand 3000.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. [Hoehe entfernt: --ohne-hoehen]", - "hoehe_unbekannt": true + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 13298.90) -> SP8 (Layer 1SP-800) (26997.93, 16298.90), Mittenabstand 3000.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 5055.0 vom Anwender.", + "hoehe_quelle": "Anwender" }, { "id": "Kreisel_Showroom_03", "function": "insert", "x": 37105.93, "y": 9888.9, - "z": 0.0, + "z": 1700.0, "abstand": 7200.0, "rotation": 180.0, "typ": "STANDARD", "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (36705.93, 9888.90) -> SP8 (Layer 1SP-800) (29505.93, 9888.90), Mittenabstand 7200.00, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. [Hoehe entfernt: --ohne-hoehen]", - "hoehe_unbekannt": true - }, - { - "id": "Kreisel_Showroom_04", - "function": "insert", - "x": 36705.93, - "y": 10288.9, - "z": 0.0, - "abstand": 4810.0, - "rotation": 90.0, - "typ": "STANDARD", - "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (36705.93, 10688.90) -> SP8 (Layer 1SP-800) (36705.93, 15498.90), Mittenabstand 4810.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. [Hoehe entfernt: --ohne-hoehen]", - "hoehe_unbekannt": true + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (36705.93, 9888.90) -> SP8 (Layer 1SP-800) (29505.93, 9888.90), Mittenabstand 7200.00, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 1700.0 vom Anwender.", + "hoehe_quelle": "Anwender" }, { "id": "Kreisel_Showroom_05", "function": "insert", "x": 27397.93, "y": 16298.9, - "z": 0.0, + "z": 5055.0, "abstand": 8908.0, "rotation": 0.0, "typ": "STANDARD", "darstellung": "2D", - "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (27797.93, 16298.90) -> (manuell SP8) (Layer --kreisel-achse) (36705.93, 16298.90), Mittenabstand 8908.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe.", - "hoehe_unbekannt": true + "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (27797.93, 16298.90) -> (manuell SP8) (Layer --kreisel-achse) (36705.93, 16298.90), Mittenabstand 8908.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 5055.0 vom Anwender.", + "hoehe_quelle": "Anwender" }, { "id": "Kreisel_Showroom_06", "function": "insert", "x": 28372.93, "y": 13093.9, - "z": 0.0, + "z": 3195.0, "abstand": 6533.0, "rotation": 0.0, "typ": "STANDARD", "darstellung": "2D", - "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (28772.93, 13093.90) -> (manuell SP8) (Layer --kreisel-achse) (35305.93, 13093.90), Mittenabstand 6533.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe.", - "hoehe_unbekannt": true + "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (28772.93, 13093.90) -> (manuell SP8) (Layer --kreisel-achse) (35305.93, 13093.90), Mittenabstand 6533.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 3195.0 vom Anwender.", + "hoehe_quelle": "Anwender" + }, + { + "test_id": "VF_Showroom_01", + "typ": "standard", + "richtung": "Auf", + "deltaL": 5610.0, + "deltaH": 3355.0, + "seite": "links", + "hz": 90.0, + "x": 36305.93, + "y": 10288.9, + "z": 1700.0, + "comment": "von Hand: ersetzt Kreisel_Showroom_04 (vertikaler Kreisel AN8 (36706, 10689) -> SP8 (36706, 15499)) samt dessen Separator/Scanner bei y=14979. AS auf der oberen Kette von Kreisel_Showroom_03 (y=10288.9, Hoehe 1700) auf dem linken Strang des alten Kreisels (x=36306), Steigung +Y bis zur unteren Kette von Kreisel_Showroom_05 (y=15898.9, Hoehe 5055): deltaL 15898.9 - 10288.9 = 5610, deltaH 5055 - 1700 = 3355. seite noch offen (links als Vorgabe), winkel waehlt der Solver." }, { "test_id": "GF_Showroom_01", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [30455.93, 15898.9, 0.0], + "start_mm": [30455.93, 15898.9, 5055.0], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (30455.93, 15593.90) -> (30455.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (30636.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (30456, 13994), S-SP bei (30456, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (30243.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 3195.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (30455.93, 15593.90) -> (30455.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (30636.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (30456, 13994), S-SP bei (30456, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (30243.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_02", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [31255.93, 12693.9, 0.0], + "start_mm": [31255.93, 12693.9, 3195.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_06", "kreisel_ende": "Kreisel_Showroom_03", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (31255.93, 12388.90) -> (31255.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31075.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (31256, 10789), S-SP bei (31256, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31468.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 1700.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (31255.93, 12388.90) -> (31255.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31075.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (31256, 10789), S-SP bei (31256, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31468.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_03", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [31255.93, 15898.9, 0.0], + "start_mm": [31255.93, 15898.9, 5055.0], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (31255.93, 15593.90) -> (31255.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31436.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (31256, 13994), S-SP bei (31256, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31043.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 3195.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (31255.93, 15593.90) -> (31255.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31436.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (31256, 13994), S-SP bei (31256, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31043.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_04", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [32055.93, 12693.9, 0.0], + "start_mm": [32055.93, 12693.9, 3195.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_06", "kreisel_ende": "Kreisel_Showroom_03", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (32055.93, 12388.90) -> (32055.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31875.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (32056, 10789), S-SP bei (32056, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (32268.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 1700.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (32055.93, 12388.90) -> (32055.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31875.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (32056, 10789), S-SP bei (32056, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (32268.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_05", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [32055.93, 15898.9, 0.0], + "start_mm": [32055.93, 15898.9, 5055.0], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (32055.93, 15593.90) -> (32055.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (32236.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (32056, 13994), S-SP bei (32056, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31843.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 3195.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (32055.93, 15593.90) -> (32055.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (32236.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (32056, 13994), S-SP bei (32056, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31843.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_06", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [33205.93, 12693.9, 0.0], + "start_mm": [33205.93, 12693.9, 3195.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_06", "kreisel_ende": "Kreisel_Showroom_03", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (33205.93, 12388.90) -> (33205.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33025.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (33206, 10789), S-SP bei (33206, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (33418.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 1700.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (33205.93, 12388.90) -> (33205.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33025.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (33206, 10789), S-SP bei (33206, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (33418.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_07", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [33205.93, 15898.9, 0.0], + "start_mm": [33205.93, 15898.9, 5055.0], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (33205.93, 15593.90) -> (33205.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33386.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (33206, 13994), S-SP bei (33206, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (32993.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 3195.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (33205.93, 15593.90) -> (33205.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33386.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (33206, 13994), S-SP bei (33206, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (32993.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_08", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [34005.93, 12693.9, 0.0], + "start_mm": [34005.93, 12693.9, 3195.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_06", "kreisel_ende": "Kreisel_Showroom_03", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (34005.93, 12388.90) -> (34005.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33825.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34006, 10789), S-SP bei (34006, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (34218.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 1700.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (34005.93, 12388.90) -> (34005.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33825.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34006, 10789), S-SP bei (34006, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (34218.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_09", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [34005.93, 15898.9, 0.0], + "start_mm": [34005.93, 15898.9, 5055.0], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (34005.93, 15593.90) -> (34005.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34186.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34006, 13994), S-SP bei (34006, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (33793.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 3195.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (34005.93, 15593.90) -> (34005.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34186.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34006, 13994), S-SP bei (34006, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (33793.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_10", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [34805.93, 12693.9, 0.0], + "start_mm": [34805.93, 12693.9, 3195.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_06", "kreisel_ende": "Kreisel_Showroom_03", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (34805.93, 12388.90) -> (34805.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34625.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34806, 10789), S-SP bei (34806, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (35018.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 1700.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (34805.93, 12388.90) -> (34805.93, 10688.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_03 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_06 / Kreisel_Showroom_03), den Winkel rechnet der Treiber; as_seite rechts aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34625.60, 12693.90) -> AS_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34806, 10789), S-SP bei (34806, 11602); es_seite links aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (35018.11, 10288.90) -> ES_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "test_id": "GF_Showroom_11", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [34805.93, 15898.9, 0.0], + "start_mm": [34805.93, 15898.9, 5055.0], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "winkel_grad": 3.0, - "hoehe_unbekannt": true, - "comment": "aus DXF: LINE auf Layer '6-SP' (34805.93, 15593.90) -> (34805.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen unbekannt - winkel_grad 3.0 ist Platzhalter; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34986.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34806, 13994), S-SP bei (34806, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (34593.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." + "hoehe_ende_mm": 3195.0, + "hoehe_quelle": "Anwender", + "comment": "aus DXF: LINE auf Layer '6-SP' (34805.93, 15593.90) -> (34805.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34986.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34806, 13994), S-SP bei (34806, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (34593.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, { "function": "insert", "block": "S-LP", "x": 26597.93, "y": 11973.9, - "z": 0.0, + "z": 5055.0, "rotation": 270.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 5055.0 von Kreisel_Showroom_01 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "S-LP", "x": 26597.93, "y": 13982.92, - "z": 0.0, + "z": 5055.0, "rotation": 90.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 5055.0 von Kreisel_Showroom_02 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "S-LP", "x": 27397.93, "y": 5450.07, - "z": 0.0, + "z": 5055.0, "rotation": 90.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 5055.0 von Kreisel_Showroom_01 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "S-LP", "x": 27397.93, "y": 15773.9, - "z": 0.0, + "z": 5055.0, "rotation": 270.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 5055.0 von Kreisel_Showroom_02 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "S-LP", "x": 29397.93, "y": 13493.9, - "z": 0.0, + "z": 3195.0, "rotation": 0.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 3195.0 von Kreisel_Showroom_06 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "S-LP", "x": 30343.39, "y": 9488.9, - "z": 0.0, + "z": 1700.0, "rotation": 0.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "S-LP", "x": 32083.74, "y": 9488.9, - "z": 0.0, + "z": 1700.0, "rotation": 0.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "S-LP", "x": 35905.93, "y": 10288.9, - "z": 0.0, + "z": 1700.0, "rotation": 180.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" - }, - { - "function": "insert", - "block": "S-LP", - "x": 37105.93, - "y": 14978.9, - "z": 0.0, - "rotation": 270.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "Scanner", "x": 29398.73, "y": 13176.71, - "z": 0.0, + "z": 3195.0, "rotation": 270.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 3195.0 von Kreisel_Showroom_06 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "Scanner", "x": 30343.39, "y": 9208.9, - "z": 0.0, + "z": 1700.0, "rotation": 270.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "Scanner", "x": 32083.74, "y": 9208.9, - "z": 0.0, + "z": 1700.0, "rotation": 270.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" }, { "function": "insert", "block": "Scanner", "x": 35905.93, "y": 10008.9, - "z": 0.0, + "z": 1700.0, "rotation": 270.0, "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" - }, - { - "function": "insert", - "block": "Scanner", - "x": 36825.93, - "y": 14978.9, - "z": 0.0, - "rotation": 180.0, - "darstellung": "2D", - "hoehe_unbekannt": true, - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen]" + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).", + "hoehe_quelle": "Anwender" } ] From 4edf294dd264790dfa63310d8c8019350928358f Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Wed, 7 Oct 2026 15:35:54 +0200 Subject: [PATCH 09/38] [CHANGE] CLAUDE.md: Scanner-Beschreibung (dxf_scan_components.py) um --flach, --kreisel-achse, Sensor-Hoehen und Kreisel-Paarung ergaenzt, GF-Winkel jetzt atan ueber die horizontale Laenge statt gf-winkel-berechnen; [CHANGE] menu/SSG_LIB.cui: von BricsCAD aus der .mnu nachgezogen (Werkzeuge-Menue der Block-/Text-Tools) Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 2 +- menu/SSG_LIB.cui | 195 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 143 insertions(+), 54 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index a118414..63ff4e1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -195,7 +195,7 @@ Abhaengigkeiten: `ezdxf`, Standard-Library. Benoetigen Umgebungsvariablen (`DXFM | `dxf_vf_abbild.py` | Abbild der `VF_`/`GF_`-Wrapperbloecke einer Testzeichnung: Attribute UND Bausteinzusammensetzung je Kette, Ketten ueber den Einfuegepunkt der Spec zugeordnet (der Blockname taugt nicht - die VF-Nummer beginnt in jeder Zeichnung neu bei 1). Regressionsnetz fuer Umbauten am Bau-Ablauf: `--referenz` vergleicht gegen `tests/reference/hundm05_attribute.json` (Exit 1 bei Abweichung), `--schreibe-referenz` frischt sie nach einem GEPRUEFTEN Lauf auf. Faengt genau das, was der Ergebnis-Record nicht sieht - eine vertauschte `vfl-acc-*`-Reihenfolge (Komma-Listen `L_VF_m`/`L_GF_m`/`GF_WINKEL`, in der Zeichnung unsichtbar, im Sivas-Export falsch) und eine falsche Blockvariante. Liest ASCII-DXF streamend; binaere DXF kann `dxf_scan_components.py`. Genutzt von `tests/test_vf_geometrie.py` | | `vf_spec_export.py` | Uebersetzt ein Eingabe-Journal in eine **Spec** und zurueck (`spec_aus_journal` / `journal_aus_spec`) - Gegenstueck zu `vsp-journal` in `Lisp/vf_spec.lsp`, beide muessen dieselbe Tokenfolge liefern. Der Rundlauf `journal_aus_spec(spec_aus_journal(tok)) == tok` laeuft in `tests/test_vf_spec.py` gegen die 5 echten HundM-Ketten und beweist, dass die Spec das Journal verlustfrei abbildet. Schreibt das flache Spec-JSON (vom LISP-Parser lesbar). Objekte der Ziel-Datei, die keine Kette beschreiben (von Hand ergaenzte Anlagenteile mit `function`, z.B. Kreisel), werden beim Neuschreiben unveraendert ans Dateiende uebernommen - sonst waeren sie beim naechsten Lauf weg. Aufruf: `python vf_spec_export.py ` — erzeugt `tests/testdata/hundm05.json` (Spec, Eingabe fuer `TEST_HUNDM05`/`VF_SPEC_BAU`) aus `tests/testdata/hm_recformat.json` (Aufzeichnung) | | `dxf_anlage_export.py` | Gegenstueck zum Scanner: liest eine mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten - je Wrapper genau die Parameter, die auch dessen Edit-Befehl liest (KREISEL_n: Einfuegepunkt, `abstand` exakt aus der Blockdefinition; GF_n: SSG_GF_EDIT + SEITE_AS/ES, endet die GF auf einer Kreisel-Kette, wird dessen Hoehe `hoehe_ende_mm`; VF_n `standard`/`etage`: mubea-Schema wie `vfs-edit-basis-lesen`; VF_n `linienzug`: Journal UNVERAENDERT als `"typ": "linienzug_journal"` - bewusst keine Spec, weil der Bau-Dialog neuer ist als die Spec-Grammatik; uebrige Bloecke als Einzel-Insert ohne `_2D`/`_3D`-Suffix). Reihenfolge Kreisel, VF, GF, Einzelbloecke (VF vor GF wie mubea). Aufruf: `python dxf_anlage_export.py [--projekt NAME]` — erzeugt `tests/testdata/dematic_arvato.json` aus `Dematic_TST.dxf`. Test `tests/test_dxf_anlage_export.py` | -| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Gefaellestrecken, die als 3D-LINE auf einem Staustrecken-Layer gezeichnet sind (`GF_LINIE_LAYER`, z.B. `6-SP`), werden in einem zweiten Lesedurchgang zu Modus-1-Eintraegen: Start/Ende werden auf die Ketten der anschliessenden Kreisel verlaengert (gezeichnet ist nur die Staustrecke; `deltaL` reicht von AS- bis ES-Ursprung), AS-Seite aus dem Ausschleuselement am oberen Ende; dieses und Separatoren auf der Achse entfallen als Einzel-Insert (die GF baut beide selbst). Sitzt der AS am UNTEREN Ende, ist es ein Steigfoerderer und wird nur gemeldet (`gf_eintraege_aus_linien`, Test `tests/test_dxf_scan_gf.py`). `--ohne-hoehen` setzt alle Z auf 0, `--kreisel-hoehe X Y Z` gibt einem Kreisel seine Hoehe - die daran haengenden GF bekommen daraus `start_mm.z`/`hoehe_ende_mm`, den Winkel rechnet der Treiber (`dematic_arvato:gf-winkel` ueber `gf-winkel-berechnen`). Aufruf: `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf | +| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Gefaellestrecken, die als 3D-LINE auf einem Staustrecken-Layer gezeichnet sind (`GF_LINIE_LAYER`, z.B. `6-SP`), werden in einem zweiten Lesedurchgang zu Modus-1-Eintraegen: Start/Ende werden auf die Ketten der anschliessenden Kreisel verlaengert (gezeichnet ist nur die Staustrecke; `deltaL` reicht von AS- bis ES-Ursprung), AS-Seite aus dem Ausschleuselement am oberen Ende; dieses und Separatoren auf der Achse entfallen als Einzel-Insert (die GF baut beide selbst). Sitzt der AS am UNTEREN Ende, ist es ein Steigfoerderer und wird nur gemeldet (`gf_eintraege_aus_linien`, Test `tests/test_dxf_scan_gf.py`). `--ohne-hoehen` setzt alle Z auf 0, `--kreisel-hoehe X Y Z` gibt einem Kreisel seine Hoehe - die daran haengenden GF bekommen daraus `start_mm.z`/`hoehe_ende_mm`, den Winkel rechnet der Treiber (`dematic_arvato:gf-winkel`: atan ueber die HORIZONTALE Laenge, ES-Abfall per `gf-messe-dz-block` iteriert - NICHT `gf-winkel-berechnen`, dessen asin bei steilen GF wie im Showroom ~50 statt ~37 Grad liefert; `dematic_arvato:gf-endhoehe-pruefen` meldet `warnung` bei > 5 mm Abweichung von HOEHE_BIS). Flache 2D-Plaene: `--flach` (waagrechte Staustrecke mit AS an genau einem Ende = GF, zerstueckelte Linien werden vereint, ES am unteren Ende wird verbraucht, AS/ES-Seite ohne Namensangabe aus der Lage zur Fahrtrichtung), `--kreisel-achse X1 Y1 X2 Y2` (Kreisel ohne AN8/SP8), Einzelteile auf einer Kreisel-Kette erben dessen Anwender-Hoehe (`sensor_hoehen_von_kreiseln`). Kreisel-Paarung mit Tausch-Nachbesserung auf minimale Abstandssumme (zwei Kreisel auf einer Achse). Genutzt fuer `tests/testdata/showroom_ils.json` (`TEST_SHOWROOM_ILS`). Aufruf: `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf | ### Entwickler-Tools (`lib/`) - kein ezdxf, reine Text-/AutoLISP-Verarbeitung diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 467be1c..2bc9c00 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -669,126 +669,168 @@ + + Bloecke zaehlen + ^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_COUNT + + + + + Bloecke loeschen + ^C^C(ssg-ensure "ssg_blocktools") SSG_BLOCK_DELETE + + + + + Attribute ersetzen + ^C^C(ssg-ensure "ssg_blocktools") SSG_ATTR_ERSETZEN + + + + + Text ersetzen + ^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_ERSETZEN + + + + + Text parallel beschriften + ^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_PARALLEL + + + + + Texthoehe aendern + ^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_HOEHE + + + + + Textstil aendern + ^C^C(ssg-ensure "ssg_texttools") SSG_TEXT_STIL + + + alle Tests ausfuehren und exportieren ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_EXPORT) - + Tests ausfuehren und stehen lassen ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_run_all.lsp")) (c:SSG_RUN_ALL_TESTS_OFFEN) - + Export CSV/Sivas ALL ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_export_all.lsp")) (c:TEST_EXPORT_ALL) - + Kreisel ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_kreisel.lsp")) (c:TEST_KREISEL) - + Foerderer ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_foerderer.lsp")) (c:TEST_FOERDERER) - + Foerderer-Linienzug ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_linienzug.lsp")) (c:TEST_LINIENZUG) (c:TEST_LINIENZUG_STUFE2) - + Omniflo ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo.lsp")) (c:TEST_OMNIFLO) - + Omniflo Strecke ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_omniflo_strecke.lsp")) (c:TEST_OMNIFLO_STRECKE) - + 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) - + ILS 3.0 Showroom (Vorlage) ^C^C(load (strcat (getenv "DXFMAKRO") "/tests/test_showroom_ils.lsp")) (c:TEST_SHOWROOM_ILS) - + KS 2D/3D pruefen (CSV) ^C^C(load (strcat (getenv "DXFMAKRO") "/Lisp/ks_pruefung.lsp")) KS_PRUEFEN - + Kreisel bearbeiten (ssg-ensure "KreiselInsert") KreiselEdit - + Omniflo Element bearbeiten (ssg-ensure "OmniModulInsert") OMNI_EDIT - + Gefaellestrecke bearbeiten (ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EDIT - + VarioFoerderer bearbeiten (ssg-ensure "VarioFoerderer") VARIOFOERDERER_EDIT - + TRO-Marker bearbeiten (ssg-ensure "Tro_Edit") TRO_EDIT - + Verbindung bearbeiten (ssg-ensure "Connection_Edit") CONNECTION_EDIT - + SSG Bearbeiten (Auto) (ssg-ensure "SSG_LIB_Commands") SSG_BLOCKEDIT @@ -810,6 +852,7 @@ + ILS @@ -1571,137 +1614,183 @@ - Tests + Werkzeuge - alle Tests ausfuehren und exportieren + Bloecke zaehlen - Tests ausfuehren und stehen lassen + Bloecke loeschen - Export CSV/Sivas ALL + Attribute ersetzen - Kreisel + Text ersetzen - Foerderer + Text parallel beschriften - Foerderer-Linienzug + Texthoehe aendern - Omniflo + Textstil aendern + + + Tests - Omniflo Strecke - - - - - - Gefaellestrecke + alle Tests ausfuehren und exportieren - Mubea Gesamtmodell + Tests ausfuehren und stehen lassen - HundM05 Kreisel-Abschnitt + Export CSV/Sivas ALL + - Dematic/Arvato Flowpuffer (Vorlage) - - - - - - ILS 3.0 Showroom (Vorlage) + Kreisel - KS 2D/3D pruefen (CSV) + Foerderer + + Foerderer-Linienzug + + + + + + Omniflo + + + + + + Omniflo Strecke + + + + + + Gefaellestrecke + + + + + + Mubea Gesamtmodell + + + + + + HundM05 Kreisel-Abschnitt + + + + + + Dematic/Arvato Flowpuffer (Vorlage) + + + + + + ILS 3.0 Showroom (Vorlage) + + + + + + KS 2D/3D pruefen (CSV) + + + + - + POP501 SSG_LIB Edit Context Kreisel bearbeiten - + Omniflo Element bearbeiten - + Gefaellestrecke bearbeiten - + VarioFoerderer bearbeiten - + TRO-Marker bearbeiten - + Verbindung bearbeiten - + SSG Bearbeiten (Auto) - + From f23a6fd0c2633ca8e258036746eaa6c54c30016a Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Wed, 7 Oct 2026 15:49:18 +0200 Subject: [PATCH 10/38] [FIX] GF aus Kreisel-Hoehen endeten bei steiler Neigung vor der Kette des unteren Kreisels (Showroom ~144 mm bei 43 Grad, Hoehe stimmte): mubea:gf-bauen zog die FLACH gemessene ES-Laenge ein-dx ab, geneigt ist das ES horizontal deutlich kuerzer. Neu dematic_arvato:gf-geometrie (Winkel UND Staustreckenlaenge, ES-Laenge und -Abfall bei der Einlaufneigung per dematic_arvato:es-mass gemessen und iteriert) + dematic_arvato:gf-bauen-exakt (gefaellestrecke-einfuegen mit dieser Staustreckenlaenge); ersetzt dematic_arvato:gf-winkel. Doku in CLAUDE.md und test_showroom_ils.lsp nachgezogen Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 2 +- tests/test_dematic_arvato.lsp | 142 +++++++++++++++++++++++----------- tests/test_showroom_ils.lsp | 3 +- 3 files changed, 98 insertions(+), 49 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 63ff4e1..9712b9f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -195,7 +195,7 @@ Abhaengigkeiten: `ezdxf`, Standard-Library. Benoetigen Umgebungsvariablen (`DXFM | `dxf_vf_abbild.py` | Abbild der `VF_`/`GF_`-Wrapperbloecke einer Testzeichnung: Attribute UND Bausteinzusammensetzung je Kette, Ketten ueber den Einfuegepunkt der Spec zugeordnet (der Blockname taugt nicht - die VF-Nummer beginnt in jeder Zeichnung neu bei 1). Regressionsnetz fuer Umbauten am Bau-Ablauf: `--referenz` vergleicht gegen `tests/reference/hundm05_attribute.json` (Exit 1 bei Abweichung), `--schreibe-referenz` frischt sie nach einem GEPRUEFTEN Lauf auf. Faengt genau das, was der Ergebnis-Record nicht sieht - eine vertauschte `vfl-acc-*`-Reihenfolge (Komma-Listen `L_VF_m`/`L_GF_m`/`GF_WINKEL`, in der Zeichnung unsichtbar, im Sivas-Export falsch) und eine falsche Blockvariante. Liest ASCII-DXF streamend; binaere DXF kann `dxf_scan_components.py`. Genutzt von `tests/test_vf_geometrie.py` | | `vf_spec_export.py` | Uebersetzt ein Eingabe-Journal in eine **Spec** und zurueck (`spec_aus_journal` / `journal_aus_spec`) - Gegenstueck zu `vsp-journal` in `Lisp/vf_spec.lsp`, beide muessen dieselbe Tokenfolge liefern. Der Rundlauf `journal_aus_spec(spec_aus_journal(tok)) == tok` laeuft in `tests/test_vf_spec.py` gegen die 5 echten HundM-Ketten und beweist, dass die Spec das Journal verlustfrei abbildet. Schreibt das flache Spec-JSON (vom LISP-Parser lesbar). Objekte der Ziel-Datei, die keine Kette beschreiben (von Hand ergaenzte Anlagenteile mit `function`, z.B. Kreisel), werden beim Neuschreiben unveraendert ans Dateiende uebernommen - sonst waeren sie beim naechsten Lauf weg. Aufruf: `python vf_spec_export.py ` — erzeugt `tests/testdata/hundm05.json` (Spec, Eingabe fuer `TEST_HUNDM05`/`VF_SPEC_BAU`) aus `tests/testdata/hm_recformat.json` (Aufzeichnung) | | `dxf_anlage_export.py` | Gegenstueck zum Scanner: liest eine mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten - je Wrapper genau die Parameter, die auch dessen Edit-Befehl liest (KREISEL_n: Einfuegepunkt, `abstand` exakt aus der Blockdefinition; GF_n: SSG_GF_EDIT + SEITE_AS/ES, endet die GF auf einer Kreisel-Kette, wird dessen Hoehe `hoehe_ende_mm`; VF_n `standard`/`etage`: mubea-Schema wie `vfs-edit-basis-lesen`; VF_n `linienzug`: Journal UNVERAENDERT als `"typ": "linienzug_journal"` - bewusst keine Spec, weil der Bau-Dialog neuer ist als die Spec-Grammatik; uebrige Bloecke als Einzel-Insert ohne `_2D`/`_3D`-Suffix). Reihenfolge Kreisel, VF, GF, Einzelbloecke (VF vor GF wie mubea). Aufruf: `python dxf_anlage_export.py [--projekt NAME]` — erzeugt `tests/testdata/dematic_arvato.json` aus `Dematic_TST.dxf`. Test `tests/test_dxf_anlage_export.py` | -| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Gefaellestrecken, die als 3D-LINE auf einem Staustrecken-Layer gezeichnet sind (`GF_LINIE_LAYER`, z.B. `6-SP`), werden in einem zweiten Lesedurchgang zu Modus-1-Eintraegen: Start/Ende werden auf die Ketten der anschliessenden Kreisel verlaengert (gezeichnet ist nur die Staustrecke; `deltaL` reicht von AS- bis ES-Ursprung), AS-Seite aus dem Ausschleuselement am oberen Ende; dieses und Separatoren auf der Achse entfallen als Einzel-Insert (die GF baut beide selbst). Sitzt der AS am UNTEREN Ende, ist es ein Steigfoerderer und wird nur gemeldet (`gf_eintraege_aus_linien`, Test `tests/test_dxf_scan_gf.py`). `--ohne-hoehen` setzt alle Z auf 0, `--kreisel-hoehe X Y Z` gibt einem Kreisel seine Hoehe - die daran haengenden GF bekommen daraus `start_mm.z`/`hoehe_ende_mm`, den Winkel rechnet der Treiber (`dematic_arvato:gf-winkel`: atan ueber die HORIZONTALE Laenge, ES-Abfall per `gf-messe-dz-block` iteriert - NICHT `gf-winkel-berechnen`, dessen asin bei steilen GF wie im Showroom ~50 statt ~37 Grad liefert; `dematic_arvato:gf-endhoehe-pruefen` meldet `warnung` bei > 5 mm Abweichung von HOEHE_BIS). Flache 2D-Plaene: `--flach` (waagrechte Staustrecke mit AS an genau einem Ende = GF, zerstueckelte Linien werden vereint, ES am unteren Ende wird verbraucht, AS/ES-Seite ohne Namensangabe aus der Lage zur Fahrtrichtung), `--kreisel-achse X1 Y1 X2 Y2` (Kreisel ohne AN8/SP8), Einzelteile auf einer Kreisel-Kette erben dessen Anwender-Hoehe (`sensor_hoehen_von_kreiseln`). Kreisel-Paarung mit Tausch-Nachbesserung auf minimale Abstandssumme (zwei Kreisel auf einer Achse). Genutzt fuer `tests/testdata/showroom_ils.json` (`TEST_SHOWROOM_ILS`). Aufruf: `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf | +| `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Gefaellestrecken, die als 3D-LINE auf einem Staustrecken-Layer gezeichnet sind (`GF_LINIE_LAYER`, z.B. `6-SP`), werden in einem zweiten Lesedurchgang zu Modus-1-Eintraegen: Start/Ende werden auf die Ketten der anschliessenden Kreisel verlaengert (gezeichnet ist nur die Staustrecke; `deltaL` reicht von AS- bis ES-Ursprung), AS-Seite aus dem Ausschleuselement am oberen Ende; dieses und Separatoren auf der Achse entfallen als Einzel-Insert (die GF baut beide selbst). Sitzt der AS am UNTEREN Ende, ist es ein Steigfoerderer und wird nur gemeldet (`gf_eintraege_aus_linien`, Test `tests/test_dxf_scan_gf.py`). `--ohne-hoehen` setzt alle Z auf 0, `--kreisel-hoehe X Y Z` gibt einem Kreisel seine Hoehe - die daran haengenden GF bekommen daraus `start_mm.z`/`hoehe_ende_mm`, den Winkel rechnet der Treiber (`dematic_arvato:gf-geometrie`: atan ueber die HORIZONTALE Laenge, ES-Laenge UND -Abfall bei der Einlaufneigung gemessen und iteriert, Staustrecke daraus - die flache ES-Laenge liess steile GF ~144 mm vor der Kette enden - NICHT `gf-winkel-berechnen`, dessen asin bei steilen GF wie im Showroom ~50 statt ~37 Grad liefert; `dematic_arvato:gf-endhoehe-pruefen` meldet `warnung` bei > 5 mm Abweichung von HOEHE_BIS). Flache 2D-Plaene: `--flach` (waagrechte Staustrecke mit AS an genau einem Ende = GF, zerstueckelte Linien werden vereint, ES am unteren Ende wird verbraucht, AS/ES-Seite ohne Namensangabe aus der Lage zur Fahrtrichtung), `--kreisel-achse X1 Y1 X2 Y2` (Kreisel ohne AN8/SP8), Einzelteile auf einer Kreisel-Kette erben dessen Anwender-Hoehe (`sensor_hoehen_von_kreiseln`). Kreisel-Paarung mit Tausch-Nachbesserung auf minimale Abstandssumme (zwei Kreisel auf einer Achse). Genutzt fuer `tests/testdata/showroom_ils.json` (`TEST_SHOWROOM_ILS`). Aufruf: `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf | ### Entwickler-Tools (`lib/`) - kein ezdxf, reine Text-/AutoLISP-Verarbeitung diff --git a/tests/test_dematic_arvato.lsp b/tests/test_dematic_arvato.lsp index de1db72..a286aa7 100644 --- a/tests/test_dematic_arvato.lsp +++ b/tests/test_dematic_arvato.lsp @@ -36,7 +36,8 @@ ;; "modus": 1 -> Gefaellestrecke ueber mubea:gf-bauen ;; (start_mm + deltaL_mm, kein Endpunkt). Mit ;; hoehe_ende_mm (Hoehe des Kreisels am Ende) -;; rechnet dematic_arvato:gf-winkel den Winkel, +;; rechnet dematic_arvato:gf-geometrie Winkel +;; und Staustreckenlaenge (gf-bauen-exakt), ;; sonst gilt winkel_grad. ;; "typ": "gerade" -> waagrechter Foerderer aus der Scanner-Vorlage - ;; kein Bau-Pfad, wird gemeldet und uebersprungen @@ -97,59 +98,99 @@ (vsp-set (vsp-set rec "status" "uebersprungen") "fehler_text" "kein Bau-Pfad fuer typ gerade")) -;; Gefaellewinkel aus Start- und Endhoehe - derselbe Loeser wie Modus 3 -;; (gf-winkel-berechnen, Gefaellestrecke.lsp) mit den AS/ES-Massen der -;; aktuellen 2D/3D-Bibliothek. Die Kette ist eine einzige Gerade plus der -;; eine Separator vor dem ES (extra-sep 1); ihre Laenge ohne AS/ES/Separator -;; ist deltaL - aus-dx - ein-dx - 300, damit ergibt der Loeser als -;; Gesamtlaenge wieder genau deltaL (deltaL reicht von AS- bis ES-Ursprung). -;; VORZEICHEN: vf-set-as-masse (vf_core) misst dz als KS_AUS.z - KS_EIN.z -;; (bei AS/ES negativ), gf-winkel-berechnen erwartet die Konvention von -;; gf-init-bibliothek (KS_EIN.z - KS_AUS.z, positiv) und zieht den Wert ab. -;; Mit der VF-Konvention wurde der feste AS/ES-Abfall addiert statt -;; abgezogen - real gebaut: 3.79 statt ~2.49 Grad, GF endete 258 mm unter -;; dem Kreisel (HOEHE_BIS 1568 statt 1826). Darum hier der Betrag. +;; ES-Element bei Einlaufneigung w (Grad, bergab) in Fahrtrichtung hz +;; vermessen: horizontale Laenge entlang hz und Abfall von KS_EIN bis KS_AUS. +;; Wie gf-messe-dz-block (Gefaellestrecke.lsp), liefert aber zusaetzlich die +;; Laenge - beide aendern sich mit der Neigung (90-Grad-ES flach ~436 mm +;; lang, bei 43 Grad nur noch ~292 mm). +;; Rueckgabe: (dx dz), dz positiv = nach unten. +(defun dematic_arvato:es-mass (blockname hz w / rad-h rad-v frame-aus ent-vor ent-nach p) + (setq rad-h (* hz (/ pi 180.0)) + rad-v (* w (/ pi 180.0))) + (setq ent-vor (entlast)) + (setq frame-aus + (insert-block-ks-to-ks blockname + (make-frame-from-dir '(0 0 0) + (list (* (cos rad-h) (cos rad-v)) (* (sin rad-h) (cos rad-v)) + (- (sin rad-v)))))) + (setq ent-nach (entlast)) + (if (and ent-nach (not (eq ent-nach ent-vor))) (entdel ent-nach)) + (setq p (car frame-aus)) + (list (+ (* (car p) (cos rad-h)) (* (cadr p) (sin rad-h))) + (- 0.0 (caddr p)))) + +;; Winkel UND Staustreckenlaenge einer GF (Modus 1) aus Start- und Endhoehe, +;; so dass der ES-Auslauf genau auf Hoehe UND Kette des unteren Kreisels +;; liegt. deltaL reicht von AS-KS_EIN bis ES-KS_AUS (horizontal). ;; -;; NICHT gf-winkel-berechnen: dessen asin(dH / L) behandelt die Laenge als -;; SCHRAEGE Laenge (richtig fuer Modus 3). Modus 1 haelt aber die -;; HORIZONTALE Laenge deltaL fest und streckt die Staustrecke um 1/cos(w) -;; (mubea:gf-bauen) - der Abfall der Schraege (Staustrecke + Separator) ist -;; dann genau (deltaL - aus-dx - ein-dx) * tan(w). Bei 2-3 Grad (Dematic) -;; ist das gleich, bei steilen GF nicht: Showroom_ILS_3_0 faellt 1860 mm auf -;; 2405 mm (~37 Grad), asin ergab ~50 Grad und die GF endete weit unter dem -;; unteren Kreisel. Der Abfall des ES haengt von der Einlaufneigung ab - er -;; wird wie in Modus 3 (gf-messe-dz-block) beim aktuellen Winkel gemessen -;; und iteriert; das AS liegt flach, sein Abfall ist fest (aus-dz). -(defun dematic_arvato:gf-winkel (deltaL hz as-seite es-seite as-winkel es-winkel - z-start z-ende / L dz-as dz-es winkel vorher - iter rad-h rad-v) +;; H = deltaL - aus-dx - es_dx(w) horizontale Laenge der Schraege +;; tan(w) = (dH - aus-dz - es_dz(w)) / H Schraege = Staustrecke + Separator +;; L_stau = H / cos(w) - 300 +;; +;; es_dx/es_dz werden beim aktuellen Winkel gemessen (dematic_arvato:es-mass) +;; und iteriert; das AS liegt flach, aus-dx/aus-dz sind fest. +;; +;; Warum nicht mubea:gf-bauen / gf-winkel-berechnen: +;; - gf-winkel-berechnen rechnet asin(dH / L), also mit SCHRAEGER Laenge +;; (Modus 3); Modus 1 haelt aber die horizontale Laenge fest. Bei 2-3 Grad +;; (Dematic) gleich, bei den steilen Showroom-GF (1860 mm auf 2405 mm) +;; ~50 statt ~43 Grad - die GF endete weit unter dem Kreisel. +;; - mubea:gf-bauen zieht die FLACH gemessene ES-Laenge ein-dx ab. Bei 43 +;; Grad ist das ES horizontal ~144 mm kuerzer, die GF hoerte so 144 mm +;; vor der Kette des unteren Kreisels auf (Hoehe stimmte). +;; VORZEICHEN: vf-set-as-masse misst aus-dz als KS_AUS.z - KS_EIN.z +;; (negativ) - darum der Betrag (Dematic: sonst HOEHE_BIS 1568 statt 1826). +;; Rueckgabe: (winkel L_stau) +(defun dematic_arvato:gf-geometrie (deltaL hz as-seite es-seite as-winkel es-winkel + z-start z-ende / es-block dH es H winkel vorher + iter dx-as dz-as) (mubea:ensure-gf-init) (vf-set-as-masse as-winkel as-seite) (vf-set-es-masse es-winkel es-seite) - (setq L (- deltaL (float aus-dx) (float ein-dx)) - dz-as (abs (float aus-dz)) - dz-es (abs (float ein-dz)) - rad-h (* hz (/ pi 180.0)) - vorher -999.0 - iter 0) - (setq winkel (* (atan (- z-start z-ende dz-as dz-es) L) (/ 180.0 pi))) - (while (and (< iter 6) (> (abs (- winkel vorher)) 0.001)) + (setq es-block (strcat "ES_Element_" es-winkel "_" es-seite) + dx-as (float aus-dx) + dz-as (abs (float aus-dz)) + dH (- z-start z-ende) + es (list (float ein-dx) (abs (float ein-dz))) + vorher -999.0 + iter 0) + (setq H (- deltaL dx-as (car es)) + winkel (* (atan (- dH dz-as (cadr es)) H) (/ 180.0 pi))) + (while (and (< iter 8) (> (abs (- winkel vorher)) 0.0005)) (setq vorher winkel - rad-v (* winkel (/ pi 180.0))) - (setq dz-es (gf-messe-dz-block (strcat "ES_Element_" es-winkel "_" es-seite) - (list (* (cos rad-h) (cos rad-v)) (* (sin rad-h) (cos rad-v)) - (- (sin rad-v))))) - (setq winkel (* (atan (- z-start z-ende dz-as dz-es) L) (/ 180.0 pi)) + es (dematic_arvato:es-mass es-block hz winkel) + H (- deltaL dx-as (car es)) + winkel (* (atan (- dH dz-as (cadr es)) H) (/ 180.0 pi)) iter (1+ iter))) (vf-set-as-masse "90" as-seite) (vf-set-es-masse "90" es-seite) - winkel) + (list winkel (- (/ H (cos (* winkel (/ pi 180.0)))) 300.0))) + +;; GF mit vorgegebener Staustreckenlaenge einfuegen (wie mubea:gf-bauen, aber +;; L_stau kommt aus dematic_arvato:gf-geometrie statt aus der flachen +;; ES-Laenge). +(defun dematic_arvato:gf-bauen-exakt (tid start-mm deltaL hz as-seite es-seite + as-winkel es-winkel winkel L_stau / ent) + (mubea:ensure-gf-init) + ;; Element-Masse der Variante wie in mubea:gf-bauen, danach zurueck auf 90 + (vf-set-as-masse as-winkel as-seite) + (vf-set-es-masse es-winkel es-seite) + (princ (strcat "\n [GF] " tid " -> Start=(" (rtos (car start-mm) 2 0) + "," (rtos (cadr start-mm) 2 0) "," (rtos (caddr start-mm) 2 0) + ") hz=" (rtos hz 2 0) " deltaL=" (rtos deltaL 2 0) + " winkel=" (rtos winkel 2 3) " L_stau=" (rtos L_stau 2 1))) + (setq ent (car (gefaellestrecke-einfuegen + L_stau winkel start-mm as-seite es-seite hz + deltaL as-winkel es-winkel "0" "Schoenenberger Geruest"))) + (vf-set-as-masse "90" as-seite) + (vf-set-es-masse "90" es-seite) + ent) ;; Gefaellestrecke (Modus 1) bauen - Felder wie mubea:build-gf, ohne dessen ;; anzahl/delta-Vervielfaeltigung (jede GF steht einzeln in der Datei). ;; Mit "hoehe_ende_mm" (Hoehe des Kreisels am Ende) wird der Winkel daraus ;; gerechnet, sonst gilt "winkel_grad" (Default 3.0). -(defun dematic_arvato:bau-gf (obj / tid start deltaL hz winkel z-ende +(defun dematic_arvato:bau-gf (obj / tid start deltaL hz winkel z-ende geo as-seite es-seite as-winkel es-winkel rec) (setq tid (ssg-val obj "test_id") start (ssg-val obj "start_mm") @@ -177,12 +218,15 @@ (vsp-set (vsp-set rec "status" "spec-fehler") "fehler_text" "hoehe_ende_mm >= start_mm.z - kein Gefaelle")) (T + ;; Mit Endhoehe: Winkel + Staustreckenlaenge exakt (gf-geometrie), + ;; sonst fester Winkel ueber mubea:gf-bauen. + (setq geo (if (numberp z-ende) + (dematic_arvato:gf-geometrie (float deltaL) (float hz) + as-seite es-seite as-winkel es-winkel + (float (caddr start)) (float z-ende)))) (setq winkel (cond - ((numberp z-ende) - (dematic_arvato:gf-winkel (float deltaL) (float hz) as-seite es-seite - as-winkel es-winkel - (float (caddr start)) (float z-ende))) + (geo (car geo)) ((numberp winkel) (float winkel)) (T 3.0))) ;; Winkel und Soll-Endhoehe als Meldung (das Record-Schema aus vf_spec @@ -195,8 +239,12 @@ ""))))) (setq rec (dematic_arvato:rec-block rec - (mubea:gf-bauen tid (mapcar 'float start) (float deltaL) (float hz) - as-seite es-seite as-winkel es-winkel winkel) + (if geo + (dematic_arvato:gf-bauen-exakt tid (mapcar 'float start) (float deltaL) + (float hz) as-seite es-seite as-winkel + es-winkel winkel (cadr geo)) + (mubea:gf-bauen tid (mapcar 'float start) (float deltaL) (float hz) + as-seite es-seite as-winkel es-winkel winkel)) "gefaellestrecke-einfuegen lieferte keinen GF-Block")) ;; Ist-Endhoehe gegen den Kreisel am Ende pruefen (dematic_arvato:gf-endhoehe-pruefen rec z-ende)))) diff --git a/tests/test_showroom_ils.lsp b/tests/test_showroom_ils.lsp index 0ff80b7..bb3e9bf 100644 --- a/tests/test_showroom_ils.lsp +++ b/tests/test_showroom_ils.lsp @@ -27,7 +27,8 @@ ;; angenaehert (Radmitten = Mittelpunkte der PIN-Kreise). ;; - Weichen (WB-*/WM-*/WL-*/WR-*) werden bewusst NICHT nachgebaut. ;; - Die GF sind steil (1860 bzw. 1495 mm Abfall auf 2405 mm) - den Winkel -;; rechnet dematic_arvato:gf-winkel aus hoehe_ende_mm, und +;; und die Staustreckenlaenge rechnet dematic_arvato:gf-geometrie aus +;; hoehe_ende_mm (ES-Masse bei der Neigung gemessen), und ;; dematic_arvato:gf-endhoehe-pruefen meldet "warnung", wenn eine GF ;; den unteren Kreisel um mehr als 5 mm verfehlt. ;; From 2cedee43c126b6e1e4de61a34ecd39b4bea48c34 Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Wed, 7 Oct 2026 16:15:17 +0200 Subject: [PATCH 11/38] [ADD] Showroom ILS: BTMT Beladung (Kreisel_Showroom_03) und BTMT Entladung (Kreisel_Showroom_01) in tests/testdata/showroom_ils.json - Einfuegepunkt/Drehung aus der gebauten Zeichnung (results/export_raw.json, EXPORTCSV vom 2026-10-07); Treiber-Kopf um die Handnachtraege ergaenzt Co-Authored-By: Claude Opus 5.5 --- tests/test_showroom_ils.lsp | 5 ++++- tests/testdata/showroom_ils.json | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/test_showroom_ils.lsp b/tests/test_showroom_ils.lsp index bb3e9bf..731559f 100644 --- a/tests/test_showroom_ils.lsp +++ b/tests/test_showroom_ils.lsp @@ -18,9 +18,12 @@ ;; Kreisel_Showroom_04 (vertikal, rechts) samt Separator/Scanner bei ;; y=14979 entfernt, dafuer VF_Showroom_01 (VarioFoerderer standard, ;; Auf von Kreisel_Showroom_03 zu Kreisel_Showroom_05) eingetragen. +;; Showroom_BTMT_BEL_01 (Kreisel_Showroom_03) und Showroom_BTMT_ENT_01 +;; (Kreisel_Showroom_01) aus der gebauten Zeichnung uebernommen +;; (results/export_raw.json, EXPORTCSV vom 2026-10-07). ;; ;; Inhalt: 5 Kreisel, 1 VarioFoerderer, 11 Gefaellestrecken (Modus 1), -;; Separatoren/Scanner. +;; Separatoren/Scanner, BTMT Be- und Entladung. ;; - Ebenen: oben 5055 (Kreisel 01/02/05), Mitte 3195 (06), unten 1700 (03). ;; - Kreisel_Showroom_05/06 sind Schleifen ohne AN8/SP8 im Plan (an beiden ;; Enden Weichenboegen) - per --kreisel-achse als STANDARD-Kreisel diff --git a/tests/testdata/showroom_ils.json b/tests/testdata/showroom_ils.json index b46510c..b281a11 100644 --- a/tests/testdata/showroom_ils.json +++ b/tests/testdata/showroom_ils.json @@ -384,5 +384,25 @@ "darstellung": "2D", "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1700.0 von Kreisel_Showroom_03 (liegt auf dessen Kette).", "hoehe_quelle": "Anwender" + }, + { + "id": "Showroom_BTMT_BEL_01", + "comment": "BTMT Beladung auf Kreisel_Showroom_03 (Hoehe 1700) - von Hand in der gebauten Showroom-Zeichnung ergaenzt, Einfuegepunkt/Drehung aus results/export_raw.json (EXPORTCSV vom 2026-10-07, Block BTMT-Beladung_3D, ID 0040)", + "function": "insert", + "block": "BTMT-Beladung", + "x": 29877.99, + "y": 9478.98, + "z": 1690.08, + "rotation": 180.0 + }, + { + "id": "Showroom_BTMT_ENT_01", + "comment": "BTMT Entladung auf Kreisel_Showroom_01 (Hoehe 5055) - von Hand in der gebauten Showroom-Zeichnung ergaenzt, Einfuegepunkt/Drehung aus results/export_raw.json (EXPORTCSV vom 2026-10-07, Block SC_Entladung_3D, ID 0041)", + "function": "insert", + "block": "SC_Entladung", + "x": 27397.93, + "y": 4555.45, + "z": 5055.0, + "rotation": 270.0 } ] From 20fc01ab25a75ddeb09c7a567a621042a9c3c487 Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Wed, 7 Oct 2026 18:20:18 +0200 Subject: [PATCH 12/38] [CHANGE] Showroom ILS: neue Hoehen - Kreisel 01/02/05 (in der Zeichnung KREISEL_1/2/4) 2226.4, Kreisel 06 (KREISEL_5) 1970, Kreisel 03 (KREISEL_3) bleibt 1700; GF-Start/-Endhoehen, Separatoren/Scanner und BTMT Entladung nachgezogen. VF_Showroom_01 steigt damit nur noch 526.4 mm auf 5610 mm und ist loesbar (21 Grad Bogen, headless mit berechne-alle-winkel geprueft) - mit 3355 mm Steigung brauchte er mindestens ~7000 mm. Treiber-Kopf (Hoehen, Scanner-Aufruf, Kreisel-Nummern der gebauten Zeichnung) angepasst Co-Authored-By: Claude Opus 5.5 --- tests/test_showroom_ils.lsp | 13 ++--- tests/testdata/showroom_ils.json | 82 ++++++++++++++++---------------- 2 files changed, 48 insertions(+), 47 deletions(-) diff --git a/tests/test_showroom_ils.lsp b/tests/test_showroom_ils.lsp index 731559f..e9f9f16 100644 --- a/tests/test_showroom_ils.lsp +++ b/tests/test_showroom_ils.lsp @@ -9,11 +9,11 @@ ;; --flach --ohne-hoehen \ ;; --kreisel-achse 27797.93 16298.90 36705.93 16298.90 \ ;; --kreisel-achse 28772.93 13093.90 35305.93 13093.90 \ -;; --kreisel-hoehe 26997.93 3066.4 5055 \ -;; --kreisel-hoehe 26997.93 12898.9 5055 \ +;; --kreisel-hoehe 26997.93 3066.4 2226.4 \ +;; --kreisel-hoehe 26997.93 12898.9 2226.4 \ ;; --kreisel-hoehe 37105.93 9888.9 1700 \ -;; --kreisel-hoehe 27397.93 16298.9 5055 \ -;; --kreisel-hoehe 28372.93 13093.9 3195 +;; --kreisel-hoehe 27397.93 16298.9 2226.4 \ +;; --kreisel-hoehe 28372.93 13093.9 1970 ;; 2. VON HAND (geht bei Stufe 1 verloren - danach neu eintragen): ;; Kreisel_Showroom_04 (vertikal, rechts) samt Separator/Scanner bei ;; y=14979 entfernt, dafuer VF_Showroom_01 (VarioFoerderer standard, @@ -24,12 +24,13 @@ ;; ;; Inhalt: 5 Kreisel, 1 VarioFoerderer, 11 Gefaellestrecken (Modus 1), ;; Separatoren/Scanner, BTMT Be- und Entladung. -;; - Ebenen: oben 5055 (Kreisel 01/02/05), Mitte 3195 (06), unten 1700 (03). +;; - Ebenen: oben 2226.4 (Kreisel 01/02/05), Mitte 1970 (06), unten 1700 (03) +;; - in der gebauten Zeichnung KREISEL_1/2/4, KREISEL_5, KREISEL_3. ;; - Kreisel_Showroom_05/06 sind Schleifen ohne AN8/SP8 im Plan (an beiden ;; Enden Weichenboegen) - per --kreisel-achse als STANDARD-Kreisel ;; angenaehert (Radmitten = Mittelpunkte der PIN-Kreise). ;; - Weichen (WB-*/WM-*/WL-*/WR-*) werden bewusst NICHT nachgebaut. -;; - Die GF sind steil (1860 bzw. 1495 mm Abfall auf 2405 mm) - den Winkel +;; - GF: den Winkel ;; und die Staustreckenlaenge rechnet dematic_arvato:gf-geometrie aus ;; hoehe_ende_mm (ES-Masse bei der Neigung gemessen), und ;; dematic_arvato:gf-endhoehe-pruefen meldet "warnung", wenn eine GF diff --git a/tests/testdata/showroom_ils.json b/tests/testdata/showroom_ils.json index b281a11..e6b5f04 100644 --- a/tests/testdata/showroom_ils.json +++ b/tests/testdata/showroom_ils.json @@ -4,12 +4,12 @@ "function": "insert", "x": 26997.93, "y": 3066.4, - "z": 5055.0, + "z": 2226.4, "abstand": 9032.5, "rotation": 90.0, "typ": "STANDARD", "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 3466.40) -> SP8 (Layer 1SP-800) (26997.93, 12498.90), Mittenabstand 9032.50, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 5055.0 vom Anwender.", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 3466.40) -> SP8 (Layer 1SP-800) (26997.93, 12498.90), Mittenabstand 9032.50, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.", "hoehe_quelle": "Anwender" }, { @@ -17,12 +17,12 @@ "function": "insert", "x": 26997.93, "y": 12898.9, - "z": 5055.0, + "z": 2226.4, "abstand": 3000.0, "rotation": 90.0, "typ": "STANDARD", "darstellung": "2D", - "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 13298.90) -> SP8 (Layer 1SP-800) (26997.93, 16298.90), Mittenabstand 3000.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 5055.0 vom Anwender.", + "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 13298.90) -> SP8 (Layer 1SP-800) (26997.93, 16298.90), Mittenabstand 3000.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.", "hoehe_quelle": "Anwender" }, { @@ -43,12 +43,12 @@ "function": "insert", "x": 27397.93, "y": 16298.9, - "z": 5055.0, + "z": 2226.4, "abstand": 8908.0, "rotation": 0.0, "typ": "STANDARD", "darstellung": "2D", - "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (27797.93, 16298.90) -> (manuell SP8) (Layer --kreisel-achse) (36705.93, 16298.90), Mittenabstand 8908.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 5055.0 vom Anwender.", + "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (27797.93, 16298.90) -> (manuell SP8) (Layer --kreisel-achse) (36705.93, 16298.90), Mittenabstand 8908.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.", "hoehe_quelle": "Anwender" }, { @@ -56,12 +56,12 @@ "function": "insert", "x": 28372.93, "y": 13093.9, - "z": 3195.0, + "z": 1970.0, "abstand": 6533.0, "rotation": 0.0, "typ": "STANDARD", "darstellung": "2D", - "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (28772.93, 13093.90) -> (manuell SP8) (Layer --kreisel-achse) (35305.93, 13093.90), Mittenabstand 6533.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 3195.0 vom Anwender.", + "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (28772.93, 13093.90) -> (manuell SP8) (Layer --kreisel-achse) (35305.93, 13093.90), Mittenabstand 6533.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 1970 vom Anwender.", "hoehe_quelle": "Anwender" }, { @@ -69,27 +69,27 @@ "typ": "standard", "richtung": "Auf", "deltaL": 5610.0, - "deltaH": 3355.0, + "deltaH": 526.4, "seite": "links", "hz": 90.0, "x": 36305.93, "y": 10288.9, "z": 1700.0, - "comment": "von Hand: ersetzt Kreisel_Showroom_04 (vertikaler Kreisel AN8 (36706, 10689) -> SP8 (36706, 15499)) samt dessen Separator/Scanner bei y=14979. AS auf der oberen Kette von Kreisel_Showroom_03 (y=10288.9, Hoehe 1700) auf dem linken Strang des alten Kreisels (x=36306), Steigung +Y bis zur unteren Kette von Kreisel_Showroom_05 (y=15898.9, Hoehe 5055): deltaL 15898.9 - 10288.9 = 5610, deltaH 5055 - 1700 = 3355. seite noch offen (links als Vorgabe), winkel waehlt der Solver." + "comment": "von Hand: ersetzt Kreisel_Showroom_04 (vertikaler Kreisel AN8 (36706, 10689) -> SP8 (36706, 15499)) samt dessen Separator/Scanner bei y=14979. AS auf der oberen Kette von Kreisel_Showroom_03 (y=10288.9, Hoehe 1700) auf dem linken Strang des alten Kreisels (x=36306), Steigung +Y bis zur unteren Kette von Kreisel_Showroom_05 (y=15898.9, Hoehe 2226.4): deltaL 15898.9 - 10288.9 = 5610, deltaH 2226.4 - 1700 = 526.4. seite noch offen (links als Vorgabe), winkel waehlt der Solver." }, { "test_id": "GF_Showroom_01", "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [30455.93, 15898.9, 5055.0], + "start_mm": [30455.93, 15898.9, 2226.4], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "hoehe_ende_mm": 3195.0, + "hoehe_ende_mm": 1970.0, "hoehe_quelle": "Anwender", "comment": "aus DXF: LINE auf Layer '6-SP' (30455.93, 15593.90) -> (30455.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (30636.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (30456, 13994), S-SP bei (30456, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (30243.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, @@ -98,7 +98,7 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [31255.93, 12693.9, 3195.0], + "start_mm": [31255.93, 12693.9, 1970.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", @@ -114,14 +114,14 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [31255.93, 15898.9, 5055.0], + "start_mm": [31255.93, 15898.9, 2226.4], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "hoehe_ende_mm": 3195.0, + "hoehe_ende_mm": 1970.0, "hoehe_quelle": "Anwender", "comment": "aus DXF: LINE auf Layer '6-SP' (31255.93, 15593.90) -> (31255.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (31436.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (31256, 13994), S-SP bei (31256, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31043.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, @@ -130,7 +130,7 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [32055.93, 12693.9, 3195.0], + "start_mm": [32055.93, 12693.9, 1970.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", @@ -146,14 +146,14 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [32055.93, 15898.9, 5055.0], + "start_mm": [32055.93, 15898.9, 2226.4], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "hoehe_ende_mm": 3195.0, + "hoehe_ende_mm": 1970.0, "hoehe_quelle": "Anwender", "comment": "aus DXF: LINE auf Layer '6-SP' (32055.93, 15593.90) -> (32055.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (32236.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (32056, 13994), S-SP bei (32056, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (31843.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, @@ -162,7 +162,7 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [33205.93, 12693.9, 3195.0], + "start_mm": [33205.93, 12693.9, 1970.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", @@ -178,14 +178,14 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [33205.93, 15898.9, 5055.0], + "start_mm": [33205.93, 15898.9, 2226.4], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "hoehe_ende_mm": 3195.0, + "hoehe_ende_mm": 1970.0, "hoehe_quelle": "Anwender", "comment": "aus DXF: LINE auf Layer '6-SP' (33205.93, 15593.90) -> (33205.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (33386.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (33206, 13994), S-SP bei (33206, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (32993.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, @@ -194,7 +194,7 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [34005.93, 12693.9, 3195.0], + "start_mm": [34005.93, 12693.9, 1970.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", @@ -210,14 +210,14 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [34005.93, 15898.9, 5055.0], + "start_mm": [34005.93, 15898.9, 2226.4], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "hoehe_ende_mm": 3195.0, + "hoehe_ende_mm": 1970.0, "hoehe_quelle": "Anwender", "comment": "aus DXF: LINE auf Layer '6-SP' (34005.93, 15593.90) -> (34005.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34186.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34006, 13994), S-SP bei (34006, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (33793.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, @@ -226,7 +226,7 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [34805.93, 12693.9, 3195.0], + "start_mm": [34805.93, 12693.9, 1970.0], "as_seite": "rechts", "es_seite": "links", "as_winkel": "90", @@ -242,14 +242,14 @@ "modus": 1, "deltaL_mm": 2405.0, "hz_grad": 270.0, - "start_mm": [34805.93, 15898.9, 5055.0], + "start_mm": [34805.93, 15898.9, 2226.4], "as_seite": "links", "es_seite": "rechts", "as_winkel": "90", "es_winkel": "90", "kreisel_start": "Kreisel_Showroom_05", "kreisel_ende": "Kreisel_Showroom_06", - "hoehe_ende_mm": 3195.0, + "hoehe_ende_mm": 1970.0, "hoehe_quelle": "Anwender", "comment": "aus DXF: LINE auf Layer '6-SP' (34805.93, 15593.90) -> (34805.93, 13893.90), Laenge XY 1700.00; am oberen Ende um 305.0 mm bis zur Kette von Kreisel_Showroom_05 verlaengert; am unteren Ende um 400.0 mm bis zur Kette von Kreisel_Showroom_06 verlaengert; Hoehen vom Anwender (Kreisel Kreisel_Showroom_05 / Kreisel_Showroom_06), den Winkel rechnet der Treiber; as_seite links aus der Lage zur Fahrtrichtung; AS aus Block 'AE-D' bei (34986.27, 15898.90) -> AS_Element_90_links, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90; Separator auf der Achse entfernt (die GF baut ihren eigenen): S-SP bei (34806, 13994), S-SP bei (34806, 14807); es_seite rechts aus der Lage zur Fahrtrichtung; ES aus Block 'EE-R' bei (34593.76, 13493.90) -> ES_Element_90_rechts, als Einzel-Insert entfernt (baut die GF selbst) - geraten: Winkel=90." }, @@ -258,10 +258,10 @@ "block": "S-LP", "x": 26597.93, "y": 11973.9, - "z": 5055.0, + "z": 2226.4, "rotation": 270.0, "darstellung": "2D", - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 5055.0 von Kreisel_Showroom_01 (liegt auf dessen Kette).", + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 2226.4 von Kreisel_Showroom_01 (liegt auf dessen Kette).", "hoehe_quelle": "Anwender" }, { @@ -269,10 +269,10 @@ "block": "S-LP", "x": 26597.93, "y": 13982.92, - "z": 5055.0, + "z": 2226.4, "rotation": 90.0, "darstellung": "2D", - "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 5055.0 von Kreisel_Showroom_02 (liegt auf dessen Kette).", + "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 2226.4 von Kreisel_Showroom_02 (liegt auf dessen Kette).", "hoehe_quelle": "Anwender" }, { @@ -280,10 +280,10 @@ "block": "S-LP", "x": 27397.93, "y": 5450.07, - "z": 5055.0, + "z": 2226.4, "rotation": 90.0, "darstellung": "2D", - "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 5055.0 von Kreisel_Showroom_01 (liegt auf dessen Kette).", + "comment": "aus DXF: Block 'S-LP', Layer 'TGW_HB_2OG-AM_5'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 2226.4 von Kreisel_Showroom_01 (liegt auf dessen Kette).", "hoehe_quelle": "Anwender" }, { @@ -291,10 +291,10 @@ "block": "S-LP", "x": 27397.93, "y": 15773.9, - "z": 5055.0, + "z": 2226.4, "rotation": 270.0, "darstellung": "2D", - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 5055.0 von Kreisel_Showroom_02 (liegt auf dessen Kette).", + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 2226.4 von Kreisel_Showroom_02 (liegt auf dessen Kette).", "hoehe_quelle": "Anwender" }, { @@ -302,10 +302,10 @@ "block": "S-LP", "x": 29397.93, "y": 13493.9, - "z": 3195.0, + "z": 1970.0, "rotation": 0.0, "darstellung": "2D", - "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 3195.0 von Kreisel_Showroom_06 (liegt auf dessen Kette).", + "comment": "aus DXF: Block 'S-LP', Layer '5SEP-LP'; Block 'S-LP' ist in data/ils/ NICHT vorhanden - erzeugt im Testlauf einen Platzhalter; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1970 von Kreisel_Showroom_06 (liegt auf dessen Kette).", "hoehe_quelle": "Anwender" }, { @@ -346,10 +346,10 @@ "block": "Scanner", "x": 29398.73, "y": 13176.71, - "z": 3195.0, + "z": 1970.0, "rotation": 270.0, "darstellung": "2D", - "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 3195.0 von Kreisel_Showroom_06 (liegt auf dessen Kette).", + "comment": "aus DXF: Block 'SCAN', Layer 'ZZSCANNER', auf Makro-Block 'Scanner' abgebildet; 2D-Schema ohne 3D-Zwilling - z ist keine Einbauhoehe (hoehe_unbekannt) [Hoehe entfernt: --ohne-hoehen] Hoehe 1970 von Kreisel_Showroom_06 (liegt auf dessen Kette).", "hoehe_quelle": "Anwender" }, { @@ -397,12 +397,12 @@ }, { "id": "Showroom_BTMT_ENT_01", - "comment": "BTMT Entladung auf Kreisel_Showroom_01 (Hoehe 5055) - von Hand in der gebauten Showroom-Zeichnung ergaenzt, Einfuegepunkt/Drehung aus results/export_raw.json (EXPORTCSV vom 2026-10-07, Block SC_Entladung_3D, ID 0041)", + "comment": "BTMT Entladung auf Kreisel_Showroom_01 (Hoehe 2226.4) - von Hand in der gebauten Showroom-Zeichnung ergaenzt, Einfuegepunkt/Drehung aus results/export_raw.json (EXPORTCSV vom 2026-10-07, Block SC_Entladung_3D, ID 0041)", "function": "insert", "block": "SC_Entladung", "x": 27397.93, "y": 4555.45, - "z": 5055.0, + "z": 2226.4, "rotation": 270.0 } ] From 9b831a55c8215bb2760c7226daf9da4f50f6841a Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Wed, 7 Oct 2026 19:55:41 +0200 Subject: [PATCH 13/38] =?UTF-8?q?help=20f=C3=BCr=20show=5Fexportcsv.bat=20?= =?UTF-8?q?dazu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/show_exportcsv.bat | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/bin/show_exportcsv.bat b/bin/show_exportcsv.bat index 1324403..e1fee54 100644 --- a/bin/show_exportcsv.bat +++ b/bin/show_exportcsv.bat @@ -32,6 +32,38 @@ REM ================================================================ setlocal +if /i "%~1"=="--help" goto :help +if /i "%~1"=="-h" goto :help +if "%~1"=="/?" goto :help +goto :main + +:help +echo Aufruf: +echo bin\show_exportcsv.bat results\export.csv, alle Zeilen +echo bin\show_exportcsv.bat meine_export.csv andere CSV in results\ ^(oder Pfad^) +echo bin\show_exportcsv.bat export.csv flow ohne VF/GF-Einzelbausteine +echo bin\show_exportcsv.bat export.csv mflow zusaetzlich Materialfluss-Graph +echo bin\show_exportcsv.bat export.csv track zusaetzlich Bahnzusammenhang-Graph +echo bin\show_exportcsv.bat export.csv tro zusaetzlich TRO-Fluss-Graph ^(lagerichtig^) +echo bin\show_exportcsv.bat export.csv flow mflow track tro alles kombiniert +echo. +echo Schalter ^(2.-5. Argument, Reihenfolge beliebig^): +echo all Darstellungsmodus: alle Zeilen ^(Default^) +echo flow Darstellungsmodus: ohne VF/GF-Einzelbausteine +echo mflow zusaetzlich Materialfluss-SVG erzeugen und oeffnen +echo track zusaetzlich Bahnzusammenhang-SVG erzeugen und oeffnen +echo tro zusaetzlich TRO-Fluss-SVG ^(lagerichtig^) erzeugen und oeffnen +echo. +echo mflow/track/tro brauchen Graphviz ^('dot' bzw. 'neato' im PATH^). +echo. +echo Ergebnis: +echo %%SKEL_RESULTS%%\^_bbs.svg +echo %%SKEL_RESULTS%%\^_material_flow.svg ^(nur mit 'mflow'^) +echo %%SKEL_RESULTS%%\^_track.svg ^(nur mit 'track'^) +echo %%SKEL_RESULTS%%\^_tro_flow.svg ^(nur mit 'tro'^) +endlocal & exit /b 0 + +:main REM Umgebung dxfmakros (DXFM_RESULTS ...) call "%~dp0setenv.bat" >nul From 46afb33b0bee3cad40b2cf7e937ba8168e14f08d Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Wed, 7 Oct 2026 20:55:58 +0200 Subject: [PATCH 14/38] [ADD] Kreisel-Drehrichtung (DREHRICHTUNG) per JSON steuerbar: kreisel-insert-script bekommt optionalen 6. Parameter drehrichtung (GUZ/UZS), hundm05:bau-kreisel liest ihn aus dem Testdaten-JSON aus. Showroom ILS: Kreisel_Showroom_02/03/05 GUZ, Kreisel_Showroom_01/06 UZS eingetragen. Doku (lisp_methods.md, json-input-lisp.md) nachgezogen. Co-Authored-By: Claude Sonnet 5 --- Lisp/KreiselInsert.lsp | 22 +++++++++++++--------- doc/json-input-lisp.md | 5 ++++- doc/lisp_methods.md | 3 ++- tests/test_hundm05.lsp | 9 +++++---- tests/testdata/showroom_ils.json | 5 +++++ 5 files changed, 29 insertions(+), 15 deletions(-) diff --git a/Lisp/KreiselInsert.lsp b/Lisp/KreiselInsert.lsp index a2b2c40..7625716 100644 --- a/Lisp/KreiselInsert.lsp +++ b/Lisp/KreiselInsert.lsp @@ -691,21 +691,25 @@ ;; ============================================================ ;; Kreisel per Script einfuegen (Insert) -;; pt : Einfuegepunkt (x y z) -;; abstand : Abstand in mm -;; rotation : Drehwinkel in Grad -;; typ : Kreiselart ("STANDARD", "PIN", ...) -;; hoehe : Hoehe in mm (oder nil fuer Z aus pt) +;; pt : Einfuegepunkt (x y z) +;; abstand : Abstand in mm +;; rotation : Drehwinkel in Grad +;; typ : Kreiselart ("STANDARD", "PIN", ...) +;; hoehe : Hoehe in mm (oder nil fuer Z aus pt) +;; drehrichtung : "GUZ"/"UZS" (optional, nil -> Default aus *kreisel-attrib-defs*) ;; Rueckgabe: Entity-Name des erzeugten Blocks oder nil -(defun kreisel-insert-script (pt abstand rotation typ hoehe / z blockEnt) +(defun kreisel-insert-script (pt abstand rotation typ hoehe drehrichtung + / z blockEnt attribs) (ssg-start (ssg-text "kreisel-start-script-insert") '(("OSMODE") ("CECOLOR"))) (if (null typ) (setq typ "STANDARD")) (setq z (if hoehe hoehe (if (and pt (caddr pt)) (caddr pt) *kreisel-default-hoehe*))) + (setq attribs (list (cons "KREISELART" typ) + (cons "HOEHE" (rtos z 2 0)))) + (if drehrichtung + (setq attribs (cons (cons "DREHRICHTUNG" drehrichtung) attribs))) (setq blockEnt - (draw-module (list (car pt) (cadr pt) z) abstand rotation - (list (cons "KREISELART" typ) - (cons "HOEHE" (rtos z 2 0))))) + (draw-module (list (car pt) (cadr pt) z) abstand rotation attribs)) (ssg-end) blockEnt ) diff --git a/doc/json-input-lisp.md b/doc/json-input-lisp.md index 1c90257..da5fc03 100644 --- a/doc/json-input-lisp.md +++ b/doc/json-input-lisp.md @@ -82,9 +82,12 @@ Block `KREISEL_n`, gebaut von `KreiselInsert.lsp`. | `abstand` | ja | Mittenabstand Antriebsrad - Spannrad | `kreisel.default_laenge` (2300) | | `rotation` | nein | Drehung der Achse AN -> SP, frei (kein Raster) | 0.0 | | `typ` | nein | `"STANDARD"` oder `"PIN"` -> Attribut `KREISELART` | `"STANDARD"` | +| `drehrichtung` | nein | `"GUZ"` oder `"UZS"` -> Attribut `DREHRICHTUNG` | `"UZS"` | Treiber: `kreisel:run-insert-test` (`test_kreisel.lsp`), `mubea:build-kreisel`, -`hundm05:bau-kreisel` (auch fuer `dematic_arvato.json`). +`hundm05:bau-kreisel` (auch fuer `dematic_arvato.json`/`showroom_ils.json`). +Nur `hundm05:bau-kreisel` liest `drehrichtung` aus und reicht sie an +`kreisel-insert-script` weiter; `mubea:build-kreisel` setzt es (noch) nicht um. ### 1.2 Connect (Start- und Endpunkt) diff --git a/doc/lisp_methods.md b/doc/lisp_methods.md index 11d78d7..5bb2287 100644 --- a/doc/lisp_methods.md +++ b/doc/lisp_methods.md @@ -38,7 +38,7 @@ Einheiten: mm und Grad. `hz` = Fahrtrichtung in der XY-Ebene, 0 = +X, ## 1. Kreisel und Eckrad (`KreiselInsert.lsp`) -### `kreisel-insert-script (pt abstand rotation typ hoehe)` +### `kreisel-insert-script (pt abstand rotation typ hoehe drehrichtung)` Kreisel an einem freien Punkt. Ruft `draw-module` auf. @@ -49,6 +49,7 @@ Kreisel an einem freien Punkt. Ruft `draw-module` auf. | `rotation` | Drehung der Achse AN -> SP in Grad | | `typ` | `"STANDARD"` oder `"PIN"` (nil = `"STANDARD"`) -> Attribut `KREISELART` | | `hoehe` | Einbauhoehe; nil = Z von `pt`, sonst `*kreisel-default-hoehe*` | +| `drehrichtung` | `"GUZ"`/`"UZS"` -> Attribut `DREHRICHTUNG` (optional, nil = Default `"UZS"` aus `*kreisel-attrib-defs*`) | Rueckgabe: Entity des `KREISEL_n`-Blocks oder nil. Setzt `ssg-start`/`ssg-end` selbst. diff --git a/tests/test_hundm05.lsp b/tests/test_hundm05.lsp index 4ca9f40..bf972ca 100644 --- a/tests/test_hundm05.lsp +++ b/tests/test_hundm05.lsp @@ -78,14 +78,15 @@ ;; Rueckgabe: Ergebnis-Record in derselben Form wie die Ketten, damit ;; vsp-results-schreiben beide in EINE Datei schreibt (unterschieden ueber ;; das Feld "kind"). -(defun hundm05:bau-kreisel (obj / id x y z abstand rotation typ pt ent ed rec) +(defun hundm05:bau-kreisel (obj / id x y z abstand rotation typ drehrichtung pt ent ed rec) (setq id (ssg-val obj "id")) (setq x (ssg-val obj "x") y (ssg-val obj "y") z (ssg-val obj "z") abstand (ssg-val obj "abstand") rotation (ssg-val obj "rotation") - typ (ssg-val obj "typ")) + typ (ssg-val obj "typ") + drehrichtung (ssg-val obj "drehrichtung")) (if (numberp x) (setq x (float x))) (if (numberp y) (setq y (float y))) (if (numberp z) (setq z (float z))) @@ -106,9 +107,9 @@ (princ (strcat "\n [KREISEL] " id " -> (" (rtos x 2 0) ", " (rtos y 2 0) ", " (rtos (if z z 0.0) 2 0) ") A=" (rtos abstand 2 0) " R=" (rtos (if rotation rotation 0.0) 2 1) - " " typ)) + " " typ (if drehrichtung (strcat " " drehrichtung) ""))) (setq ent (kreisel-insert-script pt abstand - (if rotation rotation 0.0) typ z)) + (if rotation rotation 0.0) typ z drehrichtung)) (if ent (progn (setq ed (entget ent)) diff --git a/tests/testdata/showroom_ils.json b/tests/testdata/showroom_ils.json index e6b5f04..69e9c24 100644 --- a/tests/testdata/showroom_ils.json +++ b/tests/testdata/showroom_ils.json @@ -9,6 +9,7 @@ "rotation": 90.0, "typ": "STANDARD", "darstellung": "2D", + "drehrichtung": "UZS", "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 3466.40) -> SP8 (Layer 1SP-800) (26997.93, 12498.90), Mittenabstand 9032.50, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.", "hoehe_quelle": "Anwender" }, @@ -22,6 +23,7 @@ "rotation": 90.0, "typ": "STANDARD", "darstellung": "2D", + "drehrichtung": "GUZ", "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 13298.90) -> SP8 (Layer 1SP-800) (26997.93, 16298.90), Mittenabstand 3000.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.", "hoehe_quelle": "Anwender" }, @@ -35,6 +37,7 @@ "rotation": 180.0, "typ": "STANDARD", "darstellung": "2D", + "drehrichtung": "GUZ", "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (36705.93, 9888.90) -> SP8 (Layer 1SP-800) (29505.93, 9888.90), Mittenabstand 7200.00, rotation 180.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 1700.0 vom Anwender.", "hoehe_quelle": "Anwender" }, @@ -48,6 +51,7 @@ "rotation": 0.0, "typ": "STANDARD", "darstellung": "2D", + "drehrichtung": "GUZ", "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (27797.93, 16298.90) -> (manuell SP8) (Layer --kreisel-achse) (36705.93, 16298.90), Mittenabstand 8908.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.", "hoehe_quelle": "Anwender" }, @@ -61,6 +65,7 @@ "rotation": 0.0, "typ": "STANDARD", "darstellung": "2D", + "drehrichtung": "UZS", "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (28772.93, 13093.90) -> (manuell SP8) (Layer --kreisel-achse) (35305.93, 13093.90), Mittenabstand 6533.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 1970 vom Anwender.", "hoehe_quelle": "Anwender" }, From 1e2e28e5326fb8ef63b166bb11c43a303fdcdf38 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Thu, 8 Oct 2026 09:28:11 +0200 Subject: [PATCH 15/38] [FIX] kreisel-insert-script Aufrufer in test_kreisel.lsp/test_mubea.lsp an 6. Parameter drehrichtung angepasst (seit 46afb33), sonst Abbruch mit "too few / too many arguments" Co-Authored-By: Claude Sonnet 5 --- tests/test_kreisel.lsp | 10 ++++++---- tests/test_mubea.lsp | 19 ++++++++++--------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/test_kreisel.lsp b/tests/test_kreisel.lsp index 531fdb9..4ab63a2 100644 --- a/tests/test_kreisel.lsp +++ b/tests/test_kreisel.lsp @@ -52,8 +52,8 @@ ;; --- Einzelnen Insert-Testfall ausfuehren --- (defun kreisel:run-insert-test (eintrag / id x y z abstand rotation typ - pt blockEnt ed attribs block-name - block-handle insert-point) + drehrichtung pt blockEnt ed attribs + block-name block-handle insert-point) (setq id (ssg-val eintrag "id")) (setq x (ssg-val eintrag "x")) (setq y (ssg-val eintrag "y")) @@ -61,6 +61,7 @@ (setq abstand (ssg-val eintrag "abstand")) (setq rotation (ssg-val eintrag "rotation")) (setq typ (ssg-val eintrag "typ")) + (setq drehrichtung (ssg-val eintrag "drehrichtung")) (if (numberp x) (setq x (float x))) (if (numberp y) (setq y (float y))) @@ -71,9 +72,10 @@ (setq pt (list x y z)) (princ (strcat "\n [INSERT] " id " -> (" (rtos x 2 0) ", " (rtos y 2 0) ", " (rtos z 2 0) ") A=" (rtos abstand 2 0) - " R=" (rtos rotation 2 1) " " typ)) + " R=" (rtos rotation 2 1) " " typ + (if drehrichtung (strcat " " drehrichtung) ""))) - (setq blockEnt (kreisel-insert-script pt abstand rotation typ z)) + (setq blockEnt (kreisel-insert-script pt abstand rotation typ z drehrichtung)) (if blockEnt (progn diff --git a/tests/test_mubea.lsp b/tests/test_mubea.lsp index a4f29bb..982a6b6 100644 --- a/tests/test_mubea.lsp +++ b/tests/test_mubea.lsp @@ -119,19 +119,20 @@ ;; ============================================================ ;; --- Kreisel (wie test_kreisel: kreisel-insert-script) --- -(defun mubea:build-kreisel (e / id x y z abstand rotation typ pt ent) - (setq id (ssg-val e "id") - x (float (ssg-val e "x")) - y (float (ssg-val e "y")) - z (float (ssg-val e "z")) - abstand (float (ssg-val e "abstand")) - rotation (float (ssg-val e "rotation")) - typ (ssg-val e "typ")) +(defun mubea:build-kreisel (e / id x y z abstand rotation typ drehrichtung pt ent) + (setq id (ssg-val e "id") + x (float (ssg-val e "x")) + y (float (ssg-val e "y")) + z (float (ssg-val e "z")) + abstand (float (ssg-val e "abstand")) + rotation (float (ssg-val e "rotation")) + typ (ssg-val e "typ") + drehrichtung (ssg-val e "drehrichtung")) (if (null typ) (setq typ "STANDARD")) (setq pt (list x y z)) (princ (strcat "\n [KREISEL] " id " -> (" (rtos x 2 0) "," (rtos y 2 0) "," (rtos z 2 0) ") A=" (rtos abstand 2 0) " R=" (rtos rotation 2 1))) - (setq ent (kreisel-insert-script pt abstand rotation typ z)) + (setq ent (kreisel-insert-script pt abstand rotation typ z drehrichtung)) (mubea:ent-json id "kreisel" ent) ) From 00fd48d02e0ec0d599b8c757a23b10729997153a Mon Sep 17 00:00:00 2001 From: Yuelin Wang Date: Thu, 8 Oct 2026 09:55:38 +0200 Subject: [PATCH 16/38] fix: VF-Linienzug Modus 1 GF+ES-Separator-Laenge/Hoehe korrigieren Neue Linie: GF (Zweig A+B) zog bei Kettenende mit ES-Element nur den ES-eigenen Fussabdruck von deltaL/deltaH ab, nicht den zusaetzlichen automatischen 300mm-Separator, den vfl-insert-es-element immer selbst vor dem ES-Block einfuegt - die Kette baute dadurch zu lang/zu tief. Zusaetzlich: "Separator NACH" im Wizard-Dialog (vflw-gruppe-sep-gf-impl) wird jetzt ausgegraut statt gefragt+nachtraeglich verworfen, wenn das GF-Segment ohnehin mit einem ES-Element endet (der automatische Separator deckt das bereits ab). Pending-Queue-Anzahl bleibt dabei unveraendert (Dialog pusht weiterhin 2 Werte), um keinen Versatz mit den nachfolgenden Konsolen-Abfragen zu erzeugen. Co-Authored-By: Claude Sonnet 5 --- Lisp/vf_linienzug.lsp | 83 ++++++++++++++++++++++++++++++++++++------- lang/de_DE.json | 4 +++ lang/en_GB.json | 4 +++ 3 files changed, 79 insertions(+), 12 deletions(-) diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 3dbd70c..d849e94 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -1033,7 +1033,17 @@ ;; "Neue Linie: GF" - Separator VOR/NACH (2 Ja/Nein-Toggles in einem ;; Bildschirm). Siehe dcl/vf_linienzug_wizard.dcl (vflw_sep_gf). -(defun vflw-gruppe-sep-gf-impl ( / dat ergebnis gsepvor gsepnach) +;; es-folgt-sep: T, wenn dieses GF-Stueck das Kettenende MIT ES-Element ist +;; (gf-kettenende-antwort steht beim Aufruf schon fest, siehe Aufrufer) - +;; dann baut vfl-insert-es-element ohnehin IMMER seinen eigenen Separator +;; VOR dem ES-Block, ein zusaetzlicher "Separator NACH" waere ein zweiter, +;; direkt anschliessender Separator. Statt die Frage zu stellen und die +;; Antwort hinterher zu verwerfen (Nutzer-Feedback 2026-10-08: verwirrend), +;; wird die Kachel hier direkt deaktiviert+abgehakt - der bestehende +;; Konsolen-/Sicherheitsnetz-Pfad (siehe Aufrufer, "ueberschrieben"-Meldung) +;; bleibt UNVERAENDERT bestehen (deckt weiterhin den reinen Konsolen-Fall ab, +;; wo diese Dialog-Funktion gar nicht laeuft). +(defun vflw-gruppe-sep-gf-impl (es-folgt-sep / dat ergebnis gsepvor gsepnach) (setq dat (load_dialog (vflw-dcl-pfad))) (if (not (new_dialog "vflw_sep_gf" dat)) (if (and dat (>= dat 0)) (unload_dialog dat)) @@ -1041,6 +1051,7 @@ (set_tile "kopf" (vflw-clean (ssg-text "vfl-sep-gf-header"))) (set_tile "sepvor" "0") (set_tile "sepnach" "0") + (if es-folgt-sep (mode_tile "sepnach" 1)) (action_tile "accept" "(setq gsepvor (get_tile \"sepvor\")) (setq gsepnach (get_tile \"sepnach\")) (done_dialog 1)") (action_tile "cancel" "(done_dialog 0)") @@ -7008,7 +7019,7 @@ (setq hz-neu (car (frame->hz-winkel frame))) ) (setq rad3 (* gf-max-winkel (/ pi 180.0))) - (if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-sep-gf-impl nil)) + (if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-sep-gf-impl (list (= gf-kettenende-antwort "1")))) (princ (ssg-text "vfl-sep-vor-gf-frage")) (princ (ssg-text "vfl-ja")) (princ (ssg-text "vfl-nein")) @@ -7050,9 +7061,16 @@ (if (> sep-anzahl 0) (setq deltaH (max 0.0 (- deltaH (* sep-anzahl *vfk-separator-laenge* (sin rad3)))))) ;; ES-Fussabdruck VORAB reservieren, siehe Kommentar bei - ;; gf-kettenende-antwort oben. + ;; gf-kettenende-antwort oben. ES bringt IMMER seinen eigenen + ;; Separator mit (vfl-insert-es-element, siehe Kommentar oben + ;; "bringt seinen eigenen Separator VOR dem ES-Block schon + ;; mit") - dessen Hoehenanteil fehlte hier bisher komplett + ;; (realer Bug, Nutzer-Meldung 2026-10-08: Kette baute zu lang/ + ;; zu tief, weil der automatische Kettenende-Separator anders + ;; als die optionalen vor/nach-Separatoren oben NICHT reserviert + ;; wurde). (if (= gf-kettenende-antwort "1") - (setq deltaH (max 0.0 (- deltaH (abs ein-dz))))) + (setq deltaH (max 0.0 (- deltaH (* *vfk-separator-laenge* (sin rad3)) (abs ein-dz))))) (if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-gefaelle-impl (list (vfl-gf-hoehe-vorschlag (caddr p-aktuell)) t nil))) @@ -7116,7 +7134,7 @@ ;; gepickten deltaL abgezogen, damit die Kette exakt am ;; gepickten Punkt endet statt danach ueberzustehen. (setq rad3 (* gf-max-winkel (/ pi 180.0))) - (if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-sep-gf-impl nil)) + (if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-sep-gf-impl (list (= gf-kettenende-antwort "1")))) (princ (ssg-text "vfl-sep-vor-gf-frage")) (princ (ssg-text "vfl-ja")) (princ (ssg-text "vfl-nein")) @@ -7139,9 +7157,15 @@ (if (> sep-anzahl 0) (setq deltaL (- deltaL (* sep-anzahl *vfk-separator-laenge* (cos rad3))))) ;; ES-Fussabdruck VORAB reservieren, siehe Kommentar bei - ;; gf-kettenende-antwort oben. + ;; gf-kettenende-antwort oben. ES bringt IMMER seinen + ;; eigenen Separator mit (vfl-insert-es-element) - dessen + ;; Laenge fehlte hier bisher komplett (realer Bug, + ;; Nutzer-Meldung 2026-10-08: Kette baute ca. 300mm*cos(w) + ;; zu lang, weil der automatische Kettenende-Separator + ;; anders als die optionalen vor/nach-Separatoren oben + ;; NICHT reserviert wurde). (if (= gf-kettenende-antwort "1") - (setq deltaL (- deltaL (abs ein-dx)))) + (setq deltaL (- deltaL (* *vfk-separator-laenge* (cos rad3)) (abs ein-dx)))) (if (< deltaL 1.0) (progn (princ (ssg-text "vfl-fehler-linie-zu-kurz")) (setq gf-ok nil))) (if gf-ok @@ -8985,6 +9009,12 @@ (princ (ssg-text "vfl-vwnb-titel")) (princ "\n=========================================") + ;; "Zurueck"/"Abbrechen"-Flag ganz am Anfang zuruecksetzen - identischer Fix + ;; wie in vf-linienzug-modus/-modus2 (siehe dortiger Kommentar): sonst + ;; wuerde ein von einem VORHERIGEN Lauf noch gesetztes Flag den allerersten + ;; vfl-in-*-Aufruf dieses NEUEN Laufs sofort wieder abbrechen. + (setq *vfl-wizard-abbruch-grund* nil) + ;; --- Debug-Session (Schalter "vfl-modus3", DEFAULT AN) ------------------- ;; Bei Bedarf abschaltbar: (dbg-schalter-off "vfl-modus3") in der Konsole. ;; Alle interaktiven Eingaben (Punkte, Hoehen, Seiten, Winkel, Menue- @@ -9503,6 +9533,7 @@ nonclimber-cnt nkurve kurve-chords run-span hor-koerper-len hor-pairs flat-p flat-zone-erste fill-len wahl3 rad3v feste-vf dH-adj dir-x dir-y fill-D end-hz + laengs-wert quer-wert soll-korrigiert es-vek-fix es-along-fix gf-total br-gf-mode br-gf2-exp filler-A-len filler-a-done as-vorhanden es-vorhanden dbg-an dbg-old-error @@ -9512,6 +9543,16 @@ (princ (ssg-text "vfl-m3-titel")) (princ "\n=========================================") + ;; "Zurueck"/"Abbrechen"-Flag ganz am Anfang zuruecksetzen (auch schon vor + ;; der ersten Praeambel-Frage) - sonst wuerde ein von einem VORHERIGEN Lauf + ;; (egal ob Modus 1/2/3) noch gesetztes Flag (z.B. nach "Abbrechen") den + ;; allerersten vfl-in-*-Aufruf DIESES NEUEN Laufs sofort wieder abbrechen + ;; (siehe zentraler Check in vfl-in-value/-value-p) - identischer Fix wie in + ;; vf-linienzug-modus (Modus 1). Realer Bug: ein zweiter Modus-2-Aufruf in + ;; derselben Zeichnung/Session brach sofort mit "ABBRUCH-TRIGGER: + ;; *vfl-wizard-abbruch-grund*=abbrechen" ab, ohne ueberhaupt die + ;; Pfad-Auswahl anzuzeigen (Livetest 2026-09-21). + (setq *vfl-wizard-abbruch-grund* nil) ;; *vfl-journal* VOR dem allerersten vfl-in-*-Aufruf zuruecksetzen (nicht ;; *vfl-replay-queue*, siehe Kommentar bei vfl-journal-reset-lauf und die ;; analoge Korrektur in vf-linienzug-modus). Frueher stand dieser Reset erst @@ -10304,12 +10345,30 @@ ;; ~0 sein (Endpunkt liegt auf der KS_AUS-Achse), Laengs = ES-Ausladung. (setq end-hz (car (frame->hz-winkel frame))) ; KS_AUS-Achsrichtung (setq dir-x (cos (* end-hz (/ pi 180.0))) dir-y (sin (* end-hz (/ pi 180.0)))) - (princ (ssg-textf "vfl-m3-laengs-quer" - (list (rtos (+ (* (- (car ist-ende) (car soll-ende)) dir-x) - (* (- (cadr ist-ende) (cadr soll-ende)) dir-y)) 2 1) - (rtos (+ (* (- (car ist-ende) (car soll-ende)) (- dir-y)) - (* (- (cadr ist-ende) (cadr soll-ende)) dir-x)) 2 1)))) + (setq laengs-wert (+ (* (- (car ist-ende) (car soll-ende)) dir-x) + (* (- (cadr ist-ende) (cadr soll-ende)) dir-y))) + (setq quer-wert (+ (* (- (car ist-ende) (car soll-ende)) (- dir-y)) + (* (- (cadr ist-ende) (cadr soll-ende)) dir-x))) + (princ (ssg-textf "vfl-m3-laengs-quer" (list (rtos laengs-wert 2 1) (rtos quer-wert 2 1)))) (princ (ssg-text "vfl-m3-achse-hinweis")) + ;; Soll (ES-korrigiert): der gepickte Zielpunkt, verschoben um den bereits + ;; oben gemessenen Laengs-Wert entlang der KS_AUS-Achse - zeigt, dass die + ;; Abweichung oben keine Unsicherheit ist, sondern GENAU der ES-eigene + ;; Fussabdruck (90/30-Grad-Schwenk, siehe doc/VarioFoerderer_Linienzug_ + ;; Prinzipien.md Abschnitt 6/14.11: "seitliche ES-Ausladung, kein Fehler"). + ;; Bewusst aus dem bereits gemessenen Laengs-Wert abgeleitet statt ueber + ;; eine zweite, eigenstaendige vf-element-ks-info-Neuberechnung - das waere + ;; ein zweiter Rechenweg fuer dieselbe Information mit eigenem Bug-Risiko, + ;; hier reicht die Umkehrung der bereits validierten Laengs/Quer-Zerlegung. + (setq soll-korrigiert (list (+ (car soll-ende) (* laengs-wert dir-x)) + (+ (cadr soll-ende) (* laengs-wert dir-y)) + (caddr soll-ende))) + (princ (ssg-textf "vfl-m3-ziel-soll-es-korrigiert" + (list (rtos (car soll-korrigiert) 2 1) (rtos (cadr soll-korrigiert) 2 1) (rtos (caddr soll-korrigiert) 2 1)))) + (princ (ssg-textf "vfl-m3-abweichung-es-korrigiert" + (list (rtos (- (car ist-ende) (car soll-korrigiert)) 2 1) + (rtos (- (cadr ist-ende) (cadr soll-korrigiert)) 2 1) + (rtos (- (caddr ist-ende) (caddr soll-korrigiert)) 2 1)))) (princ "\n=========================================") (if dbg-an diff --git a/lang/de_DE.json b/lang/de_DE.json index 78d3d67..34df8a6 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -245,6 +245,8 @@ "vfl-m3-abweichung": "\n Abweichung: dX=%1 dY=%2 dZ=%3 mm", "vfl-m3-laengs-quer": "\n Laengs KS_AUS-Achse: %1 mm | Quer zur Achse (soll ~0): %2 mm", "vfl-m3-achse-hinweis": "\n (dZ=Ziel-Hoehe; Quer zur KS_AUS-Achse ~0 => Endpunkt liegt auf der Achse)", + "vfl-m3-ziel-soll-es-korrigiert": "\n Soll (ES-korrigiert): X=%1 Y=%2 Z=%3 (Ziel + bekannter ES-Laengsversatz)", + "vfl-m3-abweichung-es-korrigiert": "\n Abweichung (ES-korrigiert): dX=%1 dY=%2 dZ=%3 mm", "gf-fehler-block-fehlt": "\n FEHLER: Block '%1' fehlt", "gf-fehler-block-fehlt-ausruf": "\n FEHLER: Block '%1' fehlt!", "gf-fehler-blockdatei-fehlt": "\n FEHLER: Block-Datei nicht gefunden: %1", @@ -500,6 +502,7 @@ "vfc-alert-keine-gueltige-linie": "Keine gueltige Linie ausgewaehlt!", "vfc-bitte-3dlinie-foerderstrecke": "\nBitte 3D-Linie fuer die Foerderstrecke auswaehlen:", "vfc-bks-weltkoordinaten": "\n BKS auf Weltkoordinaten gesetzt.", + "vfc-dlg-startpunkt-kopf": "Startpunkt der Anlage waehlen (X/Y):", "vfc-eingabemodus-3dlinie": "\n 1 - 3D-Linie auswaehlen (Start- und Endpunkt mit Hoehe)", "vfc-eingabemodus-header": "\n\nEingabemodus waehlen:", "vfc-eingabemodus-werte": "\n 2 - Werte manuell eingeben", @@ -526,6 +529,7 @@ "vfc-objekt-block-waehlen": "\n >> Objekt (Block) waehlen: ", "vfc-prompt-delta-h": "\n%1H - Hoehenunterschied (mm): ", "vfc-prompt-delta-l": "\n%1L - Horizontale Distanz (mm): ", + "vfc-prompt-einfuegehoehe-3dlinie": "\nEinfuegehoehe (mm) [%1 - Hoehe des Linien-Startpunkts]: ", "vfc-prompt-startpunkt-aus": "\nStartpunkt fuer AUS_Element waehlen: ", "vfc-prompt-wahl-1-2-ohne-default": "\nIhre Wahl (1/2): ", "vfc-status-ok": " OK", diff --git a/lang/en_GB.json b/lang/en_GB.json index 8af50c3..b758b4d 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -245,6 +245,8 @@ "vfl-m3-abweichung": "\n Deviation: dX=%1 dY=%2 dZ=%3 mm", "vfl-m3-laengs-quer": "\n Along KS_AUS axis: %1 mm | across axis (should be ~0): %2 mm", "vfl-m3-achse-hinweis": "\n (dZ=target height; across KS_AUS axis ~0 => end point lies on the axis)", + "vfl-m3-ziel-soll-es-korrigiert": "\n Target (ES-corrected): X=%1 Y=%2 Z=%3 (target + known ES lateral offset)", + "vfl-m3-abweichung-es-korrigiert": "\n Deviation (ES-corrected): dX=%1 dY=%2 dZ=%3 mm", "gf-fehler-block-fehlt": "\n ERROR: block '%1' missing", "gf-fehler-block-fehlt-ausruf": "\n ERROR: block '%1' missing!", "gf-fehler-blockdatei-fehlt": "\n ERROR: block file not found: %1", @@ -500,6 +502,7 @@ "vfc-alert-keine-gueltige-linie": "No valid line selected!", "vfc-bitte-3dlinie-foerderstrecke": "\nPlease select a 3D line for the conveyor section:", "vfc-bks-weltkoordinaten": "\n UCS set to world coordinates.", + "vfc-dlg-startpunkt-kopf": "Select start point of the system (X/Y):", "vfc-eingabemodus-3dlinie": "\n 1 - Select 3D line (start and end point with height)", "vfc-eingabemodus-header": "\n\nSelect input mode:", "vfc-eingabemodus-werte": "\n 2 - Enter values manually", @@ -526,6 +529,7 @@ "vfc-objekt-block-waehlen": "\n >> Select object (block): ", "vfc-prompt-delta-h": "\n%1H - height difference (mm): ", "vfc-prompt-delta-l": "\n%1L - horizontal distance (mm): ", + "vfc-prompt-einfuegehoehe-3dlinie": "\nInsertion height (mm) [%1 - height of the line start point]: ", "vfc-prompt-startpunkt-aus": "\nSelect start point for AUS_Element: ", "vfc-prompt-wahl-1-2-ohne-default": "\nYour choice (1/2): ", "vfc-status-ok": " OK", From 16a15bb83b5e6ca8907d7a1cc8a93361221469c0 Mon Sep 17 00:00:00 2001 From: Yuelin Wang Date: Thu, 8 Oct 2026 09:55:56 +0200 Subject: [PATCH 17/38] feat: VF-Werteingabe Radio-Dialoge + Startpunkt-Dialog (Standard+Etage) Dropdown-Dialoge der Standard-/Etage-Werteingabe durch Radio-Buttons ersetzt (vfs-dialog-eingabe-basis-radio/vfs-dialog-winkel-verteilung- radio in vf_standard.lsp), da sich Radio-Labels nach new_dialog nicht per set_tile aendern lassen - die DCL wird dafuer bei jedem Aufruf frisch zur Laufzeit geschrieben (neue Kernel-Helfer ssg-dcl-temp- schreiben/ssg-dcl-label-escape in ssg_core.lsp) und dadurch sprachunabhaengig. Popup-Varianten bleiben als Fallback erhalten, falls das Schreiben/Laden der Temp-DCL-Datei scheitert. Startpunkt der Anlage wird jetzt ebenfalls per Dialog gepickt (vfc-dialog-startpunkt-waehlen, neue vfc_startpunkt-Dialogdefinition in dcl/variofoerderer.dcl) statt per reinem Konsolen-getpoint - analog zum bestehenden Punktwahl-Muster im Linienzug-Wizard. Zusaetzlich: Einfuegehoehe der 3D-Linien-Eingabe ist jetzt explizit abfragbar (Vorschlag = Z des Linien-Startpunkts), ueberschreibt nur die absolute Hoehe, deltaH/Steigung bleiben unveraendert aus der Linie abgeleitet. Gemeinsam mit vf_standard.lsp nach Merge-Konflikt zusammengefuehrt: der Kollege hatte an derselben Stelle unabhaengig vfs-edit-basis-lesen ergaenzt (gemeinsame Attribut-Leseroutine fuer Standard- UND Etage-Edit) - beide Ergaenzungen sind inhaltlich unabhaengig und bleiben nebeneinander bestehen. Co-Authored-By: Claude Sonnet 5 --- Lisp/ssg_core.lsp | 38 ++++ Lisp/vf_core.lsp | 68 +++++++- Lisp/vf_standard.lsp | 382 ++++++++++++++++++++++++++++++++++++++--- dcl/variofoerderer.dcl | 60 ++++++- 4 files changed, 518 insertions(+), 30 deletions(-) diff --git a/Lisp/ssg_core.lsp b/Lisp/ssg_core.lsp index 298e43c..cfe95c8 100644 --- a/Lisp/ssg_core.lsp +++ b/Lisp/ssg_core.lsp @@ -1622,6 +1622,44 @@ ) +;; ------------------------------------------------------------ +;; DCL ZUR LAUFZEIT GENERIEREN +;; ------------------------------------------------------------ +;; Escaped Anfuehrungszeichen in einem DCL-Label-String ("->''), damit ein +;; Label mit Anfuehrungszeichen (z.B. aus Nutzerdaten oder Zoll-Angaben) die +;; DCL-Zeile nicht vorzeitig beendet. Fachlich identisch zu +;; geruest-dcl-label (GeruestInsert.lsp), aber hier als generischer +;; Kernel-Helfer fuer jeden Aufrufer, der DCL-Text zusammenbaut. +(defun ssg-dcl-label-escape (text / i c out) + (setq i 0 out "") + (while (< i (strlen text)) + (setq c (substr text (1+ i) 1)) + (setq out (strcat out (if (= c "\"") "''" c))) + (setq i (1+ i)) + ) + out +) + +;; Schreibt eine Liste von Textzeilen als temporaere DCL-Datei und liefert +;; deren Pfad zurueck (oder nil bei Fehler, z.B. wenn open scheitert). Der +;; Aufrufer ist fuer load_dialog/unload_dialog UND das Loeschen der Datei +;; (vl-file-delete) danach selbst verantwortlich - analog zum bestehenden +;; Muster in GeruestInsert.lsp (geruest-dcl-schreiben), hier nur als +;; generischer Baustein fuer WEITERE Aufrufer (GeruestInsert.lsp selbst +;; bleibt unveraendert, um dessen Code nicht anzufassen). +(defun ssg-dcl-temp-schreiben (praefix zeilen / pfad f) + (setq pfad (vl-filename-mktemp praefix nil ".dcl")) + (if (setq f (open pfad "w")) + (progn + (foreach zeile zeilen (write-line zeile f)) + (close f) + pfad + ) + nil + ) +) + + ;; ------------------------------------------------------------ ;; REKURSIVER JSON-PARSER ;; ------------------------------------------------------------ diff --git a/Lisp/vf_core.lsp b/Lisp/vf_core.lsp index ec18f05..a1db915 100644 --- a/Lisp/vf_core.lsp +++ b/Lisp/vf_core.lsp @@ -704,7 +704,8 @@ eingabe) (defun vf-eingabe-abfragen ( / eingabe-modus line-points startpunkt endpunkt differenz - deltaL deltaH deltaX deltaY richtung antwort hz-winkel) + deltaL deltaH deltaX deltaY richtung antwort hz-winkel + hoehe-override) ;; Eingabemodus: von einem Menue-Wrapper vorbelegt (dann keine Frage) oder ;; interaktiv. Die Vorauswahl gilt nur EINMAL und wird hier verbraucht, ;; damit ein spaeterer Direktaufruf wieder fragt. @@ -750,6 +751,17 @@ (progn (setq richtung "Ab") (setq deltaH (abs deltaH)) (princ (ssg-text "vfc-foerderrichtung-ab"))) ) + ;; Einfuegehoehe explizit abfragbar - ueberschreibt NUR die absolute + ;; Z-Hoehe des Startpunkts (Vorschlag = Z des Linien-Startpunkts, + ;; Enter uebernimmt ihn unveraendert). deltaH/Steigung bleiben davon + ;; unberuehrt, die kommen weiterhin aus der Geometrie der gepickten + ;; Linie selbst - nur WO die Anlage absolut eingefuegt wird, ist + ;; jetzt eingebbar (bisher ausschliesslich aus der Linie abgeleitet). + (setq hoehe-override + (getreal (ssg-textf "vfc-prompt-einfuegehoehe-3dlinie" + (list (rtos (caddr startpunkt) 2 1))))) + (if hoehe-override + (setq startpunkt (list (car startpunkt) (cadr startpunkt) hoehe-override))) ) (progn (princ (ssg-text "vfc-modus-werteingabe-header")) @@ -1055,12 +1067,64 @@ (list vf-insert vf-endpunkt) ) +;; Startpunkt der Anlage per Dialog waehlen (Punktwahl-Button + Anzeige, +;; dcl/variofoerderer.dcl Tile vfc_startpunkt) - dasselbe "Schliessen- +;; Picken-Neu-Zeigen"-Muster wie der Linienzug-Wizard +;; (vflw-gruppe-punkt-hoehe-impl, vf_linienzug.lsp:697), aber ohne dessen +;; Wizard-Pending-Queue: der Punkt wird direkt zurueckgegeben. kopf/ +;; pt_anzeige kommen per set_tile aus ssg-text - anders als +;; vfc-dialog-typ-waehlen also KEIN *ssg-lang*-Gate noetig, der Dialog +;; funktioniert in jeder Sprache. Rueckgabe: Punkt (Liste X Y Z) oder nil, +;; wenn kein Dialog gezeigt werden konnte/durfte (GUI aus) ODER abgebrochen +;; wurde - der Aufrufer (vf-dialog-ablauf) faellt dann auf den alten +;; Konsolen-getpoint zurueck. +(defun vfc-dialog-startpunkt-waehlen (kopf-key / dcl-pfad dat ergebnis gpunkt fertig) + (if (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p)) + (progn + (setq fertig nil) + (while (not fertig) + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "vfc_startpunkt" dat)) + (progn + (if (and dat (>= dat 0)) (unload_dialog dat)) + (setq fertig t gpunkt nil) + ) + (progn + (set_tile "kopf" (ssg-text "vfc-dlg-startpunkt-kopf")) + (if gpunkt + (set_tile "pt_anzeige" + (strcat "X=" (rtos (car gpunkt) 2 1) + " Y=" (rtos (cadr gpunkt) 2 1) + " Z=" (rtos (caddr gpunkt) 2 1))) + ) + (action_tile "pick" "(done_dialog 2)") + (action_tile "accept" "(done_dialog 1)") + (action_tile "cancel" "(done_dialog 0)") + (setq ergebnis (start_dialog)) + (unload_dialog dat) + (cond + ((= ergebnis 2) (setq gpunkt (getpoint (ssg-text kopf-key)))) + ((= ergebnis 1) (setq fertig t)) + (t (setq fertig t gpunkt nil)) + ) + ) + ) + ) + gpunkt + ) + nil + ) +) + ;; Neuanlage (Menue/Konsole -> Dialog) fuer einen Registry-Typ: Startpunkt ;; (X/Y) picken, Basis-Dialog, dann vf-dialog-berechnen-einfuegen. (defun vf-dialog-ablauf (typ vf-nummer horizontal-p / eingabe deltaL deltaH richtung z-start hz seite startpunkt startpunkt-xy dim geruest-einzelmodul geruest-typ motorseite) - (setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus"))) + (setq startpunkt-xy (vfc-dialog-startpunkt-waehlen "vfc-prompt-startpunkt-aus")) + (if (null startpunkt-xy) + (setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus")))) (if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0))) (setq eingabe (vfs-dialog-eingabe-basis nil)) (if (null eingabe) diff --git a/Lisp/vf_standard.lsp b/Lisp/vf_standard.lsp index 99e8daf..9f11549 100644 --- a/Lisp/vf_standard.lsp +++ b/Lisp/vf_standard.lsp @@ -808,6 +808,19 @@ ;; zwei DCL-Dialoge: Basis-Eingabe und Winkel/Verteilung. Die ;; 3D-Linie-Eingabe sowie die Typen "etage"/"linienzug" bleiben ;; unveraendert interaktiv (siehe Verzweigung in c:VarioFoerderer). +;; +;; Beide Dialoge existieren je in zwei Varianten: +;; -popup (Dropdowns, urspruengliche Implementierung, unveraendert) und +;; -radio (Radio-Buttons statt Dropdown). Radio-Button-Labels lassen sich +;; nach new_dialog nicht per set_tile aendern (DCL-Limitierung) - die +;; -radio-Varianten loesen das, indem sie ihre DCL-Datei bei JEDEM Aufruf +;; frisch per ssg-dcl-temp-schreiben (ssg_core.lsp) schreiben und die +;; Labels dabei direkt mit dem schon von ssg-text/ssg-textf aufgeloesten +;; String befuellen - funktioniert dadurch in jeder Sprache, keine +;; Sprachweiche noetig (anders als vfc-dialog-typ-waehlen). Die +;; namenlosen Dispatcher-Funktionen (ohne Suffix) bevorzugen -radio und +;; fallen nur bei einem technischen Fehler (Temp-Datei nicht schreibbar/ +;; ladbar, Sentinel 'FEHLER) auf -popup zurueck. ;; ============================================================ ;; Bau-Parameter eines bestehenden VF_n-Blocks aus XDATA + Attributen lesen - @@ -846,14 +859,76 @@ (cons "hz" hz) (cons "z-start" z-start))) -;; Basis-Eingabe (Dialog 1): deltaL, deltaH, Richtung, Einfuegehoehe, -;; Fahrtrichtung, Seite, Geruest fuer Einzelmodul, Geruestoption. +;; Baut die DCL-Zeilen einer boxed_radio_column mit einem radio_button pro +;; Eintrag in "labels" (Tile-Keys "_0".."_(n-1)"). labels +;; sind bereits fertige, uebersetzte Strings (ssg-text/ssg-textf) - werden +;; hier nur noch fuer die DCL-Syntax escaped (ssg-dcl-label-escape). +;; Gemeinsam genutzt von vfs-dialog-eingabe-basis-radio UND +;; vfs-dialog-winkel-verteilung-radio. +(defun vfs-dcl-radio-gruppe-zeilen (prefix box-label labels / zeilen i) + (setq zeilen (list + ": boxed_radio_column {" + (strcat " label = \"" (ssg-dcl-label-escape box-label) "\";") + (strcat " key = \"" prefix "\";"))) + (setq i 0) + (foreach lbl labels + (setq zeilen (append zeilen (list + (strcat " : radio_button { key = \"" prefix "_" (itoa i) "\"; label = \"" + (ssg-dcl-label-escape lbl) "\"; }")))) + (setq i (1+ i)) + ) + (append zeilen (list "}")) +) + +;; Baut das (cond ...)-Fragment (als String), das innerhalb eines +;; action_tile-Callbacks den gewaehlten Index 0..(n-1) einer per +;; vfs-dcl-radio-gruppe-zeilen erzeugten Gruppe ermittelt. n ist die +;; tatsaechliche Options-Anzahl zum Generierungszeitpunkt - dadurch bleibt +;; z.B. die Geruesttyp- oder Winkel-Gruppe korrekt, auch wenn deren Anzahl +;; sich einmal aendert (kein hartkodiertes "_1"/"_2"/"_3" im Aufrufer). +(defun vfs-dcl-radio-idx-cond (prefix n / s i) + (setq s "(cond " i 1) + (while (< i n) + (setq s (strcat s "((= (get_tile \"" prefix "_" (itoa i) "\") \"1\") " (itoa i) ")")) + (setq i (1+ i)) + ) + (strcat s "(t 0))") +) + +;; L_GF1/L_GF2 aus dem gewaehlten Verteilungsmodus ("0".."3") berechnen - +;; gemeinsam genutzt von der Popup- UND der Radio-Variante von +;; vfs-dialog-winkel-verteilung (frueher inline in beiden dupliziert). +;; Rueckgabe: (L_GF1 L_GF2). +(defun vfs-verteilung-berechnen (verteilung-modus L_GF staustrecke-basis lgf1-manuell-str / + L_GF1 L_GF2) + (cond + ((= verteilung-modus "0") + (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0))) + ((= verteilung-modus "1") + (setq L_GF1 (float staustrecke-basis)) + (setq L_GF2 (max 0.0 (- L_GF (float staustrecke-basis))))) + ((= verteilung-modus "2") + (setq L_GF2 (float staustrecke-basis)) + (setq L_GF1 (max 0.0 (- L_GF (float staustrecke-basis))))) + ((= verteilung-modus "3") + (setq L_GF1 (atof lgf1-manuell-str)) + (if (or (null L_GF1) (< L_GF1 0)) (setq L_GF1 (/ L_GF 2.0))) + (if (> L_GF1 L_GF) (setq L_GF1 L_GF)) + (setq L_GF2 (max 0.0 (- L_GF L_GF1)))) + (t (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0))) + ) + (list L_GF1 L_GF2) +) + +;; Basis-Eingabe (Dialog 1, Popup-Variante): deltaL, deltaH, Richtung, +;; Einfuegehoehe, Fahrtrichtung, Seite, Geruest fuer Einzelmodul, +;; Geruestoption. ;; prefill: Assoziationsliste zur Vorbelegung (fuer VARIOFOERDERER_EDIT) mit ;; Schluesseln "deltaL" "deltaH" "richtung" "einfuegehoehe" "hz" "seite" ;; "geruest-einzelmodul" "geruest-typ" - oder nil fuer Neuanlage mit Defaults. ;; Rueckgabe: (deltaL deltaH richtung einfuegehoehe hz seite ;; geruest-einzelmodul geruest-typ) oder nil bei Abbruch. -(defun vfs-dialog-eingabe-basis (prefill / dcl-pfad dat ergebnis +(defun vfs-dialog-eingabe-basis-popup (prefill / dcl-pfad dat ergebnis dlg-deltal dlg-deltah dlg-richtung dlg-hoehe dlg-fahrtrichtung dlg-seite dlg-motorseite dlg-dimension dlg-geruest-einzelmodul dlg-geruest-typ @@ -973,17 +1048,169 @@ ) ) -;; Winkel/Verteilung-Eingabe (Dialog 2): Winkel-Popup aus den vorher +;; Basis-Eingabe (Dialog 1, Radio-Button-Variante) - siehe Kopfkommentar +;; des DCL-DIALOG-Abschnitts. Gleiche prefill-Struktur/Rueckgabe wie +;; -popup; 'FEHLER bei technischem Fehler (Dispatcher faellt dann zurueck). +(defun vfs-dialog-eingabe-basis-radio (prefill / zeilen dcl-pfad dat ergebnis + dlg-deltal dlg-deltah dlg-hoehe + dlg-richtung-idx dlg-fahrt-idx dlg-seite-idx + dlg-motorseite-idx dlg-dim-idx + dlg-geruest-einzelmodul dlg-geruest-typ-idx + deltaL deltaH richtung hz seite z-start dim + motorseite geruest-einzelmodul geruest-typ + sel-richtung sel-fahrt sel-seite sel-motorseite + sel-dim sel-geruest-typ n-geruest-typ) + ;; Vorbelegte Auswahl-Indizes aus prefill ableiten - gleiche Logik wie + ;; -popup, nur als Index statt als Popup-Tile-Wert. + (setq sel-richtung + (if (and prefill (equal (cdr (assoc "richtung" prefill)) "Ab")) 1 0)) + (setq sel-fahrt + (if prefill + (cond ((equal (cdr (assoc "hz" prefill)) 90.0 0.1) 1) + ((equal (cdr (assoc "hz" prefill)) 180.0 0.1) 2) + ((equal (cdr (assoc "hz" prefill)) 270.0 0.1) 3) + (t 0)) + 0)) + (setq sel-seite + (if (and prefill (equal (cdr (assoc "seite" prefill)) "links")) 1 0)) + (setq sel-motorseite + (if (and prefill (equal (cdr (assoc "motorseite" prefill)) "links")) 1 0)) + (setq sel-dim + (if (equal (cond ((cdr (assoc "dim" prefill))) ((ssg-ils-dim-aktuell))) "2D") 1 0)) + (setq n-geruest-typ (length *ssg-geruest-optionen*)) + (setq sel-geruest-typ + (ssg-geruest-typ-to-idx (if prefill (cdr (assoc "geruest-typ" prefill)) nil))) + + (setq zeilen (list + "vfs_basis_dyn : dialog {" + " label = \"VarioFoerderer (Standard) - Eingabe\";" + " : column {" + " : boxed_column {" + " label = \"Geometrie\";" + " : row {" + " : edit_box { key = \"deltal\"; label = \"Horizontale Distanz deltaL (mm):\"; edit_width = 10; }" + " : edit_box { key = \"deltah\"; label = \"Hoehenunterschied deltaH (mm):\"; edit_width = 10; }" + " }")) + (setq zeilen (append zeilen + (vfs-dcl-radio-gruppe-zeilen "richtung" "Foerderrichtung:" + (list (ssg-text "vfs-dlg-richtung-auf") (ssg-text "vfs-dlg-richtung-ab"))))) + (setq zeilen (append zeilen (list + " : edit_box { key = \"einfuegehoehe\"; label = \"Einfuegehoehe (mm):\"; edit_width = 10; }" + " }" + " : boxed_column {" + " label = \"Ausrichtung\";"))) + (setq zeilen (append zeilen + (vfs-dcl-radio-gruppe-zeilen "fahrtrichtung" "Fahrtrichtung:" + (list (ssg-textf "gf-dlg-richtung-0" (list grad-zeichen)) + (ssg-textf "gf-dlg-richtung-90" (list grad-zeichen)) + (ssg-textf "gf-dlg-richtung-180" (list grad-zeichen)) + (ssg-textf "gf-dlg-richtung-270" (list grad-zeichen)))))) + (setq zeilen (append zeilen + (vfs-dcl-radio-gruppe-zeilen "seite" "Seite:" + (list (ssg-text "gf-dlg-rechts") (ssg-text "gf-dlg-links"))))) + (setq zeilen (append zeilen + (vfs-dcl-radio-gruppe-zeilen "motorseite" "Motorseite:" + (list (ssg-text "gf-dlg-rechts") (ssg-text "gf-dlg-links"))))) + (setq zeilen (append zeilen + (vfs-dcl-radio-gruppe-zeilen "dimension" "Darstellung (2D/3D):" (list "3D" "2D")))) + (setq zeilen (append zeilen (list + " }" + " : boxed_column {" + " label = \"Geruest\";" + " : toggle { key = \"geruest_einzelmodul\"; label = \"Geruest fuer Einzelmodul\"; }"))) + (setq zeilen (append zeilen + (vfs-dcl-radio-gruppe-zeilen "geruest_typ" "Geruestoption:" *ssg-geruest-optionen*))) + (setq zeilen (append zeilen (list + " }" + " }" + " ok_cancel;" + "}"))) + + (setq dcl-pfad (ssg-dcl-temp-schreiben "vfsbasis" zeilen)) + (if (null dcl-pfad) + 'FEHLER + (progn + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "vfs_basis_dyn" dat)) + (progn + (if (and dat (>= dat 0)) (unload_dialog dat)) + (vl-file-delete dcl-pfad) + 'FEHLER + ) + (progn + (set_tile "deltal" (if prefill (rtos (cdr (assoc "deltaL" prefill)) 2 0) "15000")) + (set_tile "deltah" (if prefill (rtos (cdr (assoc "deltaH" prefill)) 2 0) "3000")) + (set_tile "einfuegehoehe" (if prefill (rtos (cdr (assoc "einfuegehoehe" prefill)) 2 1) "0")) + (set_tile (strcat "richtung_" (itoa sel-richtung)) "1") + (set_tile (strcat "fahrtrichtung_" (itoa sel-fahrt)) "1") + (set_tile (strcat "seite_" (itoa sel-seite)) "1") + (set_tile (strcat "motorseite_" (itoa sel-motorseite)) "1") + (set_tile (strcat "dimension_" (itoa sel-dim)) "1") + (set_tile "geruest_einzelmodul" + (if (or (null prefill) (equal (cdr (assoc "geruest-einzelmodul" prefill)) "1")) "1" "0")) + (set_tile (strcat "geruest_typ_" (itoa sel-geruest-typ)) "1") + + (action_tile "accept" + (strcat + "(setq dlg-deltal (get_tile \"deltal\"))" + "(setq dlg-deltah (get_tile \"deltah\"))" + "(setq dlg-hoehe (get_tile \"einfuegehoehe\"))" + "(setq dlg-richtung-idx " (vfs-dcl-radio-idx-cond "richtung" 2) ")" + "(setq dlg-fahrt-idx " (vfs-dcl-radio-idx-cond "fahrtrichtung" 4) ")" + "(setq dlg-seite-idx " (vfs-dcl-radio-idx-cond "seite" 2) ")" + "(setq dlg-motorseite-idx " (vfs-dcl-radio-idx-cond "motorseite" 2) ")" + "(setq dlg-dim-idx " (vfs-dcl-radio-idx-cond "dimension" 2) ")" + "(setq dlg-geruest-einzelmodul (get_tile \"geruest_einzelmodul\"))" + "(setq dlg-geruest-typ-idx " (vfs-dcl-radio-idx-cond "geruest_typ" n-geruest-typ) ")" + "(done_dialog 1)" + ) + ) + (action_tile "cancel" "(done_dialog 0)") + + (setq ergebnis (start_dialog)) + (unload_dialog dat) + (vl-file-delete dcl-pfad) + + (if (= ergebnis 1) + (progn + (setq deltaL (atof dlg-deltal)) + (setq deltaH (atof dlg-deltah)) + (setq richtung (nth dlg-richtung-idx '("Auf" "Ab"))) + (setq z-start (atof dlg-hoehe)) + (setq hz (nth dlg-fahrt-idx '(0.0 90.0 180.0 270.0))) + (setq seite (nth dlg-seite-idx '("rechts" "links"))) + (setq motorseite (nth dlg-motorseite-idx '("rechts" "links"))) + (setq dim (nth dlg-dim-idx '("3D" "2D"))) + (setq geruest-einzelmodul dlg-geruest-einzelmodul) + (setq geruest-typ (ssg-geruest-idx-to-typ dlg-geruest-typ-idx)) + (list deltaL deltaH richtung z-start hz seite dim geruest-einzelmodul geruest-typ motorseite) + ) + nil + ) + ) + ) + ) + ) +) + +;; Dispatcher: bevorzugt die Radio-Button-Variante (siehe Kopfkommentar des +;; DCL-DIALOG-Abschnitts), Rueckfall auf -popup nur bei technischem Fehler. +(defun vfs-dialog-eingabe-basis (prefill / ergebnis) + (setq ergebnis (vfs-dialog-eingabe-basis-radio prefill)) + (if (eq ergebnis 'FEHLER) (vfs-dialog-eingabe-basis-popup prefill) ergebnis) +) + +;; Winkel/Verteilung-Eingabe (Dialog 2, Popup-Variante): Winkel-Popup aus den vorher ;; berechneten gueltigen Varianten (gueltige-winkel/ergebnis-liste, siehe ;; berechne-alle-winkel), plus L_GF-Verteilung vorne/hinten (analog Schritt ;; 8+9 in c:VarioFoerderer). ;; prefill: Assoziationsliste ("winkel" . best-winkel) ("verteilung-idx" . "0".."3") ;; ("lgf1" . mm) - oder nil fuer Vorbelegung mit dem kleinsten gueltigen Winkel. ;; Rueckgabe: (best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus) oder nil bei Abbruch. -(defun vfs-dialog-winkel-verteilung (gueltige-winkel ergebnis-liste staustrecke-basis prefill / +(defun vfs-dialog-winkel-verteilung-popup (gueltige-winkel ergebnis-liste staustrecke-basis prefill / dcl-pfad dat ergebnis w eintrag idx sel-idx init-verteilung dlg-winkel dlg-verteilung dlg-lgf1 - best-winkel L_GF L_VF verteilung-modus L_GF1 L_GF2) + best-winkel L_GF L_VF verteilung-modus L_GF1 L_GF2 lgf-paar) (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl")) (setq dat (load_dialog dcl-pfad)) (if (not (new_dialog "variofoerderer_winkel" dat)) @@ -1052,22 +1279,8 @@ (setq eintrag (assoc best-winkel ergebnis-liste)) (setq L_GF (nth 1 eintrag) L_VF (nth 2 eintrag)) (setq verteilung-modus dlg-verteilung) - (cond - ((= verteilung-modus "0") - (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0))) - ((= verteilung-modus "1") - (setq L_GF1 (float staustrecke-basis)) - (setq L_GF2 (max 0.0 (- L_GF (float staustrecke-basis))))) - ((= verteilung-modus "2") - (setq L_GF2 (float staustrecke-basis)) - (setq L_GF1 (max 0.0 (- L_GF (float staustrecke-basis))))) - ((= verteilung-modus "3") - (setq L_GF1 (atof dlg-lgf1)) - (if (or (null L_GF1) (< L_GF1 0)) (setq L_GF1 (/ L_GF 2.0))) - (if (> L_GF1 L_GF) (setq L_GF1 L_GF)) - (setq L_GF2 (max 0.0 (- L_GF L_GF1)))) - (t (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0))) - ) + (setq lgf-paar (vfs-verteilung-berechnen verteilung-modus L_GF staustrecke-basis dlg-lgf1)) + (setq L_GF1 (car lgf-paar) L_GF2 (cadr lgf-paar)) (list best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus) ) nil @@ -1076,6 +1289,131 @@ ) ) +;; Winkel/Verteilung-Eingabe (Dialog 2, Radio-Button-Variante) - siehe +;; Kopfkommentar des DCL-DIALOG-Abschnitts. Gleiche prefill-Struktur/ +;; Rueckgabe wie -popup; 'FEHLER bei technischem Fehler. +(defun vfs-dialog-winkel-verteilung-radio (gueltige-winkel ergebnis-liste staustrecke-basis prefill / + zeilen dcl-pfad dat ergebnis w eintrag labels + sel-winkel sel-verteilung idx toggle-zeile i + dlg-winkel-idx dlg-verteilung-idx dlg-lgf1 + best-winkel L_GF L_VF verteilung-modus L_GF1 L_GF2 lgf-paar) + ;; Winkel-Labels vorab aufloesen - gleiche Texte wie im Popup. + (setq labels nil) + (foreach w gueltige-winkel + (setq eintrag (assoc w ergebnis-liste)) + (setq labels (append labels (list + (if (= w 0) + (ssg-textf "vfs-dlg-winkel-horizontal" + (list (rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1))) + (ssg-textf "vfs-dlg-winkel-option" + (list (itoa w) grad-zeichen (rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1))) + ))) + ) + ) + + ;; Vorbelegung: Winkel aus prefill (falls noch gueltig), sonst erster + ;; (kleinster) gueltiger Winkel - analog der automatischen Konsolen-Wahl. + (setq sel-winkel 0 idx 0) + (if prefill + (foreach w gueltige-winkel + (if (equal w (cdr (assoc "winkel" prefill))) (setq sel-winkel idx)) + (setq idx (1+ idx)) + ) + ) + (setq sel-verteilung + (if prefill (atoi (cdr (assoc "verteilung-idx" prefill))) 0)) + + (setq zeilen (list + "vfs_winkel_dyn : dialog {" + " label = \"VarioFoerderer (Standard) - Winkel / Verteilung\";" + " : column {")) + (setq zeilen (append zeilen (vfs-dcl-radio-gruppe-zeilen "winkel" "Winkel:" labels))) + (setq zeilen (append zeilen (list + " : boxed_column {" + " label = \"Verteilung Gefaellestrecken (vorne/hinten)\";"))) + (setq zeilen (append zeilen + (vfs-dcl-radio-gruppe-zeilen "verteilung" "Modus:" + (list (ssg-text "vfs-dlg-verteilung-1") (ssg-text "vfs-dlg-verteilung-2") + (ssg-text "vfs-dlg-verteilung-3") (ssg-text "vfs-dlg-verteilung-4"))))) + (setq zeilen (append zeilen (list + " : edit_box { key = \"lgf1_manuell\"; label = \"L_GF1 vorne (mm):\"; edit_width = 10; }" + " }" + " }" + " ok_cancel;" + "}"))) + + (setq dcl-pfad (ssg-dcl-temp-schreiben "vfswinkel" zeilen)) + (if (null dcl-pfad) + 'FEHLER + (progn + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "vfs_winkel_dyn" dat)) + (progn + (if (and dat (>= dat 0)) (unload_dialog dat)) + (vl-file-delete dcl-pfad) + 'FEHLER + ) + (progn + (set_tile (strcat "winkel_" (itoa sel-winkel)) "1") + (set_tile (strcat "verteilung_" (itoa sel-verteilung)) "1") + (set_tile "lgf1_manuell" + (if (and prefill (cdr (assoc "lgf1" prefill))) + (rtos (cdr (assoc "lgf1" prefill)) 2 1) "0")) + (mode_tile "lgf1_manuell" (if (= sel-verteilung 3) 0 1)) + + ;; Jedes der 4 Verteilung-Radio-Tiles braucht sein EIGENES + ;; action_tile (haengt bei Radio-Buttons nicht am Gruppen-Key wie + ;; bisher am popup_list-Key "verteilung"). + (setq toggle-zeile + "(mode_tile \"lgf1_manuell\" (if (= (get_tile \"verteilung_3\") \"1\") 0 1))") + (setq i 0) + (while (< i 4) + (action_tile (strcat "verteilung_" (itoa i)) toggle-zeile) + (setq i (1+ i)) + ) + + (action_tile "accept" + (strcat + "(setq dlg-winkel-idx " (vfs-dcl-radio-idx-cond "winkel" (length gueltige-winkel)) ")" + "(setq dlg-verteilung-idx " (vfs-dcl-radio-idx-cond "verteilung" 4) ")" + "(setq dlg-lgf1 (get_tile \"lgf1_manuell\"))" + "(done_dialog 1)" + ) + ) + (action_tile "cancel" "(done_dialog 0)") + + (setq ergebnis (start_dialog)) + (unload_dialog dat) + (vl-file-delete dcl-pfad) + + (if (= ergebnis 1) + (progn + (setq best-winkel (nth dlg-winkel-idx gueltige-winkel)) + (setq eintrag (assoc best-winkel ergebnis-liste)) + (setq L_GF (nth 1 eintrag) L_VF (nth 2 eintrag)) + (setq verteilung-modus (itoa dlg-verteilung-idx)) + (setq lgf-paar (vfs-verteilung-berechnen verteilung-modus L_GF staustrecke-basis dlg-lgf1)) + (setq L_GF1 (car lgf-paar) L_GF2 (cadr lgf-paar)) + (list best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus) + ) + nil + ) + ) + ) + ) + ) +) + +;; Dispatcher: bevorzugt die Radio-Button-Variante (siehe Kopfkommentar des +;; DCL-DIALOG-Abschnitts), Rueckfall auf -popup nur bei technischem Fehler. +(defun vfs-dialog-winkel-verteilung (gueltige-winkel ergebnis-liste staustrecke-basis prefill / ergebnis) + (setq ergebnis (vfs-dialog-winkel-verteilung-radio gueltige-winkel ergebnis-liste staustrecke-basis prefill)) + (if (eq ergebnis 'FEHLER) + (vfs-dialog-winkel-verteilung-popup gueltige-winkel ergebnis-liste staustrecke-basis prefill) + ergebnis + ) +) + ;; ============================================================ ;; XDATA-Metadaten fuer den Edit-Nachbau (App "SSG_VF_EDIT"). ;; Markiert ein VF_n-INSERT als "mit dem Standard-Dialog erstellt" und diff --git a/dcl/variofoerderer.dcl b/dcl/variofoerderer.dcl index ef475a9..e47686c 100644 --- a/dcl/variofoerderer.dcl +++ b/dcl/variofoerderer.dcl @@ -5,12 +5,21 @@ // Konsolen-Liste am Befehlsanfang. Radio-Buttons statt Dropdown, daher // Labels FEST auf Deutsch (siehe Kommentar bei vfc_linienzug_modus). // vfc_linienzug_modus: NUR bei Typ "Linienzug" - Modus 1/2/3 waehlen. -// variofoerderer_basis/variofoerderer_winkel: Werteingabe fuer den -// Standardfall (anlage-typ "standard"): deltaL, deltaH, Foerderrichtung, -// Einfuegehoehe, Fahrtrichtung, Seite, Winkel, GF-Verteilung. -// Die 3D-Linie-Eingabe (Modus "3D-Linie"), der Etage-Typ und die -// Linienzug-Kette selbst (nach der Modus-Wahl) bleiben interaktiv -// (Kommandozeile bzw. eigener Wizard in vf_linienzug_wizard.dcl). +// vfc_startpunkt: Startpunkt der Anlage picken (Punktwahl-Button + +// X/Y/Z-Anzeige) - ersetzt den reinen Konsolen-getpoint fuer +// Standard UND Etage (vfc-dialog-startpunkt-waehlen, vf_core.lsp). +// variofoerderer_basis/variofoerderer_winkel: Popup-Fallback-Varianten +// der Werteingabe (deltaL, deltaH, Foerderrichtung, Einfuegehoehe, +// Fahrtrichtung, Seite, Motorseite, Dimension, Geruest, Winkel, +// GF-Verteilung) - gemeinsam genutzt von Standard UND Etage. Die +// bevorzugten Radio-Button-Varianten (vfs_basis_dyn/vfs_winkel_dyn) +// werden zur Laufzeit generiert (vfs-dialog-eingabe-basis-radio/ +// vfs-dialog-winkel-verteilung-radio in vf_standard.lsp) und stehen +// NICHT in dieser Datei - diese beiden Dialoge hier sind nur noch der +// Fallback, falls das Schreiben/Laden der Temp-DCL-Datei mal scheitert. +// Die 3D-Linie-Eingabe (Modus "3D-Linie") und die Linienzug-Kette selbst +// (nach der Modus-Wahl) bleiben interaktiv (Kommandozeile bzw. eigener +// Wizard in vf_linienzug_wizard.dcl). // ============================================================ // Anlagen-Typ waehlen (Standard/Etage/Linienzug). Radio-Buttons statt @@ -101,6 +110,45 @@ vfc_linienzug_modus : dialog { } } +// Startpunkt der Anlage waehlen - Punktwahl-Button + Anzeige, analog +// vflw_punkt_zahl (dcl/vf_linienzug_wizard.dcl): der Button schliesst den +// Dialog (done_dialog 2), DANACH laeuft getpoint auf der Kommandozeile +// (aus einem action_tile-Callback heraus funktioniert getpoint in BricsCAD +// nicht), der Dialog wird danach mit der Anzeige erneut aufgebaut. "kopf" +// und "pt_anzeige" werden per set_tile aus ssg-text befuellt (siehe +// vfc-dialog-startpunkt-waehlen, vf_core.lsp) - deshalb sprachunabhaengig +// nutzbar. Button-Chrome bleibt hart deutsch, wie im Rest dieser Datei. +vfc_startpunkt : dialog { + label = "VarioFoerderer - Startpunkt"; + + : column { + : text { + key = "kopf"; + label = ""; + width = 50; + } + : row { + : button { + key = "pick"; + label = "Punkt waehlen..."; + fixed_width = true; + width = 18; + } + : text { + key = "pt_anzeige"; + label = "(kein Punkt gewaehlt)"; + } + } + } + + : row { + alignment = centered; + : button { key = "accept"; label = "Ok Weiter"; is_default = true; fixed_width = true; width = 12; } + spacer; + : button { key = "cancel"; label = "Abbrechen"; is_cancel = true; fixed_width = true; width = 12; } + } +} + variofoerderer_basis : dialog { label = "VarioFoerderer (Standard) - Eingabe"; From 8ef73240323e4ca33c49fc3393cd351548e6eed5 Mon Sep 17 00:00:00 2001 From: Samer Ayadi Date: Thu, 8 Oct 2026 11:35:12 +0200 Subject: [PATCH 18/38] [FIX] Kreisel-Umlauf (export_neighbors.compute_kreisel_umlauf): AS/ES, deren ZZ_ASES_MARKER-Box keinen Kreisel trifft, ueber den Ein-/Auslaufpunkt der Strecke (K1 = KS_EIN, K2 = KS_AUS) zuordnen - laeuft eine Strecke parallel zum Kreisel, liegt der Marker (Einfuegepunkt) ~560 mm neben der Kette, der Einlauf aber darauf (Dematic VF_5 an Kreisel1 fehlte in den TrackIds); bereits zugeordnete AS/ES unveraendert + Tests; [ADD] dxf_anlage_export.py: Kreisel-Drehrichtung (DREHRICHTUNG) ins Testdaten-JSON; [CHANGE] dematic_arvato.json aus dem aktuellen Dematic_TST.dxf (Kreisel 1/4 GUZ, BTMT Be-/Entladung, Scanner vor Separator 0048) Co-Authored-By: Claude Opus 5.5 --- CLAUDE.md | 2 +- lib/dxf_anlage_export.py | 6 +- lib/export_neighbors.py | 30 ++++++ tests/test_dxf_anlage_export.py | 7 ++ tests/test_export_kreisel_umlauf.py | 53 ++++++++++ tests/testdata/dematic_arvato.json | 147 +++++++++++++++++----------- 6 files changed, 185 insertions(+), 60 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 9712b9f..82cca61 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -194,7 +194,7 @@ Abhaengigkeiten: `ezdxf`, Standard-Library. Benoetigen Umgebungsvariablen (`DXFM | `vf_journal_export.py` | Liest die Eingabe-Journale der `VF_n`-Bloecke (XDATA-App `SSG_VF_EDIT`, Marker `"linienzug"`) aus einer Zeichnung und schreibt sie als Frage-Antwort-Protokoll im Schema von `tests/testdata/linienzug_tests.json` (Gegenstueck zu `vfl-entry->string`; kein ezdxf, reine Gruppencode-Lesung). Optional `--csv ` fuer Strecken-ID und Erwartungswerte je Kette. Aufruf: `python vf_journal_export.py [--csv ...] [--kein-startpunkt-fix]` — erzeugt `tests/testdata/hm_recformat.json` aus `data/polylines.dxf` (die Aufzeichnung, aus der `tests/testdata/hundm05.json` als Spec abgeleitet wird) | | `dxf_vf_abbild.py` | Abbild der `VF_`/`GF_`-Wrapperbloecke einer Testzeichnung: Attribute UND Bausteinzusammensetzung je Kette, Ketten ueber den Einfuegepunkt der Spec zugeordnet (der Blockname taugt nicht - die VF-Nummer beginnt in jeder Zeichnung neu bei 1). Regressionsnetz fuer Umbauten am Bau-Ablauf: `--referenz` vergleicht gegen `tests/reference/hundm05_attribute.json` (Exit 1 bei Abweichung), `--schreibe-referenz` frischt sie nach einem GEPRUEFTEN Lauf auf. Faengt genau das, was der Ergebnis-Record nicht sieht - eine vertauschte `vfl-acc-*`-Reihenfolge (Komma-Listen `L_VF_m`/`L_GF_m`/`GF_WINKEL`, in der Zeichnung unsichtbar, im Sivas-Export falsch) und eine falsche Blockvariante. Liest ASCII-DXF streamend; binaere DXF kann `dxf_scan_components.py`. Genutzt von `tests/test_vf_geometrie.py` | | `vf_spec_export.py` | Uebersetzt ein Eingabe-Journal in eine **Spec** und zurueck (`spec_aus_journal` / `journal_aus_spec`) - Gegenstueck zu `vsp-journal` in `Lisp/vf_spec.lsp`, beide muessen dieselbe Tokenfolge liefern. Der Rundlauf `journal_aus_spec(spec_aus_journal(tok)) == tok` laeuft in `tests/test_vf_spec.py` gegen die 5 echten HundM-Ketten und beweist, dass die Spec das Journal verlustfrei abbildet. Schreibt das flache Spec-JSON (vom LISP-Parser lesbar). Objekte der Ziel-Datei, die keine Kette beschreiben (von Hand ergaenzte Anlagenteile mit `function`, z.B. Kreisel), werden beim Neuschreiben unveraendert ans Dateiende uebernommen - sonst waeren sie beim naechsten Lauf weg. Aufruf: `python vf_spec_export.py ` — erzeugt `tests/testdata/hundm05.json` (Spec, Eingabe fuer `TEST_HUNDM05`/`VF_SPEC_BAU`) aus `tests/testdata/hm_recformat.json` (Aufzeichnung) | -| `dxf_anlage_export.py` | Gegenstueck zum Scanner: liest eine mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten - je Wrapper genau die Parameter, die auch dessen Edit-Befehl liest (KREISEL_n: Einfuegepunkt, `abstand` exakt aus der Blockdefinition; GF_n: SSG_GF_EDIT + SEITE_AS/ES, endet die GF auf einer Kreisel-Kette, wird dessen Hoehe `hoehe_ende_mm`; VF_n `standard`/`etage`: mubea-Schema wie `vfs-edit-basis-lesen`; VF_n `linienzug`: Journal UNVERAENDERT als `"typ": "linienzug_journal"` - bewusst keine Spec, weil der Bau-Dialog neuer ist als die Spec-Grammatik; uebrige Bloecke als Einzel-Insert ohne `_2D`/`_3D`-Suffix). Reihenfolge Kreisel, VF, GF, Einzelbloecke (VF vor GF wie mubea). Aufruf: `python dxf_anlage_export.py [--projekt NAME]` — erzeugt `tests/testdata/dematic_arvato.json` aus `Dematic_TST.dxf`. Test `tests/test_dxf_anlage_export.py` | +| `dxf_anlage_export.py` | Gegenstueck zum Scanner: liest eine mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung zurueck in Nachbau-Testdaten - je Wrapper genau die Parameter, die auch dessen Edit-Befehl liest (KREISEL_n: Einfuegepunkt, `abstand` exakt aus der Blockdefinition, `drehrichtung` aus DREHRICHTUNG; GF_n: SSG_GF_EDIT + SEITE_AS/ES, endet die GF auf einer Kreisel-Kette, wird dessen Hoehe `hoehe_ende_mm`; VF_n `standard`/`etage`: mubea-Schema wie `vfs-edit-basis-lesen`; VF_n `linienzug`: Journal UNVERAENDERT als `"typ": "linienzug_journal"` - bewusst keine Spec, weil der Bau-Dialog neuer ist als die Spec-Grammatik; uebrige Bloecke als Einzel-Insert ohne `_2D`/`_3D`-Suffix). Reihenfolge Kreisel, VF, GF, Einzelbloecke (VF vor GF wie mubea). Aufruf: `python dxf_anlage_export.py [--projekt NAME]` — erzeugt `tests/testdata/dematic_arvato.json` aus `Dematic_TST.dxf`. Test `tests/test_dxf_anlage_export.py` | | `dxf_scan_components.py` | Erkennt ILS-/Omniflo-Komponenten in einer **fremden** Projektzeichnung (ohne unsere Wrapper-Bloecke) und schreibt sie im JSON-Schema aus `tests/testdata/object_data.md` — Grundlage fuer Nachbau-Testfaelle wie `tests/testdata/mubea.json`. Liest binaere DXF im GB-Bereich streamend per mmap (ezdxf-DOM waere zu gross), loest INSERTs inkl. OCS/Extrusionsrichtung rekursiv in Weltkoordinaten auf, paart AN8/SP8 zu Kreiseln und Antrieb/Umlenkung zu Foerderern. Gefaellestrecken, die als 3D-LINE auf einem Staustrecken-Layer gezeichnet sind (`GF_LINIE_LAYER`, z.B. `6-SP`), werden in einem zweiten Lesedurchgang zu Modus-1-Eintraegen: Start/Ende werden auf die Ketten der anschliessenden Kreisel verlaengert (gezeichnet ist nur die Staustrecke; `deltaL` reicht von AS- bis ES-Ursprung), AS-Seite aus dem Ausschleuselement am oberen Ende; dieses und Separatoren auf der Achse entfallen als Einzel-Insert (die GF baut beide selbst). Sitzt der AS am UNTEREN Ende, ist es ein Steigfoerderer und wird nur gemeldet (`gf_eintraege_aus_linien`, Test `tests/test_dxf_scan_gf.py`). `--ohne-hoehen` setzt alle Z auf 0, `--kreisel-hoehe X Y Z` gibt einem Kreisel seine Hoehe - die daran haengenden GF bekommen daraus `start_mm.z`/`hoehe_ende_mm`, den Winkel rechnet der Treiber (`dematic_arvato:gf-geometrie`: atan ueber die HORIZONTALE Laenge, ES-Laenge UND -Abfall bei der Einlaufneigung gemessen und iteriert, Staustrecke daraus - die flache ES-Laenge liess steile GF ~144 mm vor der Kette enden - NICHT `gf-winkel-berechnen`, dessen asin bei steilen GF wie im Showroom ~50 statt ~37 Grad liefert; `dematic_arvato:gf-endhoehe-pruefen` meldet `warnung` bei > 5 mm Abweichung von HOEHE_BIS). Flache 2D-Plaene: `--flach` (waagrechte Staustrecke mit AS an genau einem Ende = GF, zerstueckelte Linien werden vereint, ES am unteren Ende wird verbraucht, AS/ES-Seite ohne Namensangabe aus der Lage zur Fahrtrichtung), `--kreisel-achse X1 Y1 X2 Y2` (Kreisel ohne AN8/SP8), Einzelteile auf einer Kreisel-Kette erben dessen Anwender-Hoehe (`sensor_hoehen_von_kreiseln`). Kreisel-Paarung mit Tausch-Nachbesserung auf minimale Abstandssumme (zwei Kreisel auf einer Achse). Genutzt fuer `tests/testdata/showroom_ils.json` (`TEST_SHOWROOM_ILS`). Aufruf: `python dxf_scan_components.py [--fenster X0 Y0 X1 Y1]` — ohne `--fenster` liefert eine Anlagenzeichnung leicht ueber 1300 Eintraege, zuviel fuer einen Testlauf | ### Entwickler-Tools (`lib/`) - kein ezdxf, reine Text-/AutoLISP-Verarbeitung diff --git a/lib/dxf_anlage_export.py b/lib/dxf_anlage_export.py index c5e50e4..f864696 100644 --- a/lib/dxf_anlage_export.py +++ b/lib/dxf_anlage_export.py @@ -17,7 +17,7 @@ Je Wrapper (Felder wie in tests/testdata/object_data.md bzw. mubea.json): KREISEL_n -> Kreisel ("function": "insert", x/y/z = Einfuegepunkt, abstand = Mittenabstand AN8-SP8 aus der Blockdefinition, - rotation, typ = KREISELART) + rotation, typ = KREISELART, drehrichtung = DREHRICHTUNG) GF_n -> Gefaellestrecke Modus 1 (XDATA SSG_GF_EDIT wie gf-xdata-lesen + SEITE_AS/SEITE_ES wie GEFAELLESTRECKE_EDIT). Endet die Strecke auf der Kette eines Kreisels, wird statt @@ -210,6 +210,10 @@ def kreisel_eintrag(e, block_inhalt, projekt): ("abstand", _r(abstand)), ("rotation", _r(e["rot"])), ("typ", a.get("KREISELART") or "STANDARD"), + # Umlaufsinn: bestimmt die Reihenfolge im Kreisel-Umlauf und damit den + # TRO-Fluss - ohne ihn kam jeder Nachbau als UZS heraus (Dematic 1/4: + # GUZ). hundm05:bau-kreisel reicht ihn an kreisel-insert-script weiter. + ("drehrichtung", a.get("DREHRICHTUNG") or "UZS"), ("comment", "aus Zeichnung: %s (ID %s), abstand aus %s" % (e["name"], a.get("ID", "?"), quelle)), ]) diff --git a/lib/export_neighbors.py b/lib/export_neighbors.py index 3b099fe..81d3e44 100644 --- a/lib/export_neighbors.py +++ b/lib/export_neighbors.py @@ -1287,6 +1287,11 @@ def compute_kreisel_umlauf(items, tolerance_mm, durchmesser_mm=800.0, punkte_je_kreisel = {tid: [] for tid in kreisel} + # Ein-/Auslaufpunkt je Strecke (K1 = KS_EIN des AS, K2 = KS_AUS des ES), + # fuer AS/ES, deren Marker-Box keinen Kreisel trifft (siehe unten). + strecken_kos = {it.get("teileid", ""): _asel_kos_xy(it) + for it in items if it.get("teileart", "") in GF_VF_TEILEARTEN} + for item in items: if item.get("teileart", "") not in KREISEL_UMLAUF_TEILEARTEN: continue @@ -1305,6 +1310,31 @@ def compute_kreisel_umlauf(items, tolerance_mm, durchmesser_mm=800.0, (teileid, bbox.get("cx", 0.0), bbox.get("cy", 0.0))) matched_tid = tid break + # Rueckfall fuer AS/ES: der ZZ_ASES_MARKER sitzt auf dem EINFUEGEPUNKT + # des Elements, der Kreisel beruehrt aber dessen Ein-/Auslauf (KS_EIN/ + # KS_AUS). Ein 90-Grad-Element hat den Einlauf ~610 mm seitlich - laeuft + # die Strecke quer vom Kreisel weg, liegt dieser Versatz entlang der + # Kette und der Marker trotzdem darauf; laeuft sie PARALLEL zum + # Kreisel, liegt er quer dazu und der Marker ~560 mm daneben (Dematic/ + # Arvato VF_5 an Kreisel1: Marker 557 mm, Einlauf 52 mm von der Kette, + # Review 2026-10-08). Nur wenn die Marker-Box nichts trifft - bereits + # zugeordnete AS/ES behalten Position und Reihenfolge. + if matched_tid is None and item.get("teileart", "") in ( + AUSSCHLEUS_TEILEART, EINSCHLEUS_TEILEART): + k1_xy, k2_xy = strecken_kos.get(item.get("_zuordnung", ""), (None, None)) + pt = k1_xy if item.get("teileart", "") == AUSSCHLEUS_TEILEART else k2_xy + if pt is not None: + pt_bounds = _bounds({"cx": pt[0], "cy": pt[1], "dx": 0.0, "dy": 0.0}, + half_tol) + for tid, kb in kreisel_bounds.items(): + if _overlaps(pt_bounds, kb): + punkte_je_kreisel[tid].append((teileid, pt[0], pt[1])) + matched_tid = tid + if dbg: + dbg(f" Umlauf-Kandidat {teileid!r}: Marker-Box ohne " + f"Kreisel, Ein-/Auslauf ({pt[0]:.0f},{pt[1]:.0f}) " + f"liegt auf Kreisel {tid}") + break if dbg: if matched_tid is not None: dbg(f" Umlauf-Kandidat {teileid!r} ({item.get('teileart', '')!r}) " diff --git a/tests/test_dxf_anlage_export.py b/tests/test_dxf_anlage_export.py index b934190..22fb36f 100644 --- a/tests/test_dxf_anlage_export.py +++ b/tests/test_dxf_anlage_export.py @@ -57,6 +57,13 @@ def test_kreisel_abstand_aus_blockdefinition(): assert (k["x"], k["y"], k["z"], k["rotation"]) == (35860.37, 12519.72, 2437.0, 180.0) ohne_block = dae.kreisel_eintrag(KREISEL_OBEN, {}, "T") assert ohne_block["abstand"] == 33044.0 + assert k["drehrichtung"] == "UZS" # Attribut fehlt -> Vorgabe + + +def test_kreisel_drehrichtung_aus_attribut(): + guz = _insert("KREISEL_4_STANDARD_3619", (42563.78, 1703.66, 2177.0), 90.0, + {"NUMMER": "4", "DREHRICHTUNG": "GUZ"}) + assert dae.kreisel_eintrag(guz, {}, "T")["drehrichtung"] == "GUZ" def test_gf_zwischen_zwei_kreiseln_bekommt_endhoehe(): diff --git a/tests/test_export_kreisel_umlauf.py b/tests/test_export_kreisel_umlauf.py index 2d712b3..b2bce05 100644 --- a/tests/test_export_kreisel_umlauf.py +++ b/tests/test_export_kreisel_umlauf.py @@ -485,3 +485,56 @@ class TestAsEsImKreiselUmlauf: keys = [p[0] for p in umlauf["0001"]] assert "0057" not in keys, ( "ES-Item weit ausserhalb der Kreiselbox wurde faelschlich erkannt") + + +def _trans(x, y, z=0.0): + """Gegenstueck zu _decode_trans_xy (csv:trans-encode in export.lsp): drei + vorzeichenbehaftete 24-Bit-Fixed-Point-Werte (Faktor 10), je 4 Zeichen.""" + from export_neighbors import _B64_CHARS + text = "" + for v in (x, y, z): + n = int(round(v * 10.0)) & 0xFFFFFF + text += "".join(_B64_CHARS[(n >> s) & 63] for s in (18, 12, 6, 0)) + return text + + +def _strecke(teileid, k1_xy, k2_xy): + return {"teileart": "ILS 2.0 Strecke", "teileid": teileid, + "k1": _trans(*k1_xy), "k2": _trans(*k2_xy)} + + +class TestAsEsUeberEinlaufpunkt: + """Dematic/Arvato VF_5 an Kreisel1 (Review 2026-10-08): die Strecke laeuft + PARALLEL zum Kreisel, der 90-Grad-Einlauf (KS_EIN) liegt darum quer zur + Kette - Marker (Einfuegepunkt) 557 mm neben der Kette, Einlauf nur 52 mm + davor. Kreisel entlang +Y, rechte Kette bei x = +400.""" + + def _kreisel_y(self): + return _kreisel("0001", 0.0, 0.0, 90.0, abstand=3619.0) + + def test_marker_daneben_einlauf_auf_der_kette(self): + items = [self._kreisel_y(), + _separator("0043", 400.0, 1500.0), + _ases("ILS Ausschleuselement", "0071", 957.0, 2283.0, "0009"), + _strecke("0009", (348.0, 2283.0), (348.0, 9000.0))] + umlauf = compute_kreisel_umlauf( + items, tolerance_mm=200.0, durchmesser_mm=DURCHMESSER_MM) + punkte = {p[0]: p for p in umlauf["0001"]} + assert "0071" in punkte, "AS ueber den Einlaufpunkt nicht im Umlauf" + # nach dem Einlauf einsortiert, nicht nach dem Marker + assert len(umlauf["0001"]) == 2 + + def test_ohne_einlaufpunkt_bleibt_es_bei_der_marker_box(self): + items = [self._kreisel_y(), + _ases("ILS Ausschleuselement", "0071", 957.0, 2283.0, "0009")] + umlauf = compute_kreisel_umlauf( + items, tolerance_mm=200.0, durchmesser_mm=DURCHMESSER_MM) + assert "0071" not in [p[0] for p in umlauf["0001"]] + + def test_einlauf_weit_weg_wird_nicht_zugeordnet(self): + items = [self._kreisel_y(), + _ases("ILS Ausschleuselement", "0071", 957.0, 2283.0, "0009"), + _strecke("0009", (5000.0, 2283.0), (9000.0, 2283.0))] + umlauf = compute_kreisel_umlauf( + items, tolerance_mm=200.0, durchmesser_mm=DURCHMESSER_MM) + assert "0071" not in [p[0] for p in umlauf["0001"]] diff --git a/tests/testdata/dematic_arvato.json b/tests/testdata/dematic_arvato.json index 26603ec..7aade0b 100644 --- a/tests/testdata/dematic_arvato.json +++ b/tests/testdata/dematic_arvato.json @@ -8,7 +8,8 @@ "abstand": 3619.14, "rotation": 90.0, "typ": "STANDARD", - "comment": "aus Zeichnung: KREISEL_1_STANDARD_3619 (ID 0001), abstand aus Blockdefinition (AN8 -> SP8)" + "drehrichtung": "GUZ", + "comment": "aus Zeichnung: KREISEL_1_STANDARD_3619 (ID 0056), abstand aus Blockdefinition (AN8 -> SP8)" }, { "id": "Kreisel_Arvato_02", @@ -19,6 +20,7 @@ "abstand": 33044.28, "rotation": 180.0, "typ": "STANDARD", + "drehrichtung": "UZS", "comment": "aus Zeichnung: KREISEL_2_STANDARD_33044 (ID 0002), abstand aus Blockdefinition (AN8 -> SP8)" }, { @@ -30,6 +32,7 @@ "abstand": 33470.18, "rotation": 180.0, "typ": "STANDARD", + "drehrichtung": "UZS", "comment": "aus Zeichnung: KREISEL_3_STANDARD_33470 (ID 0003), abstand aus Blockdefinition (AN8 -> SP8)" }, { @@ -41,10 +44,11 @@ "abstand": 3619.14, "rotation": 90.0, "typ": "STANDARD", - "comment": "aus Zeichnung: KREISEL_4_STANDARD_3619 (ID 0004), abstand aus Blockdefinition (AN8 -> SP8)" + "drehrichtung": "GUZ", + "comment": "aus Zeichnung: KREISEL_4_STANDARD_3619 (ID 0055), abstand aus Blockdefinition (AN8 -> SP8)" }, { - "test_id": "VF_Arvato_02", + "test_id": "VF_Arvato_01", "typ": "standard", "richtung": "Auf", "deltaL": 11559.0, @@ -57,10 +61,10 @@ "x": 3314.07, "y": 24478.8, "z": 1826.0, - "comment": "aus Zeichnung: VF_2 (ID 0082), Hoehe 1826 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" + "comment": "aus Zeichnung: VF_1 (ID 0005), Hoehe 0 -> 611; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "test_id": "VF_Arvato_03", + "test_id": "VF_Arvato_02", "typ": "standard", "richtung": "Auf", "deltaL": 11559.0, @@ -73,10 +77,10 @@ "x": 15285.06, "y": 24478.8, "z": 1826.0, - "comment": "aus Zeichnung: VF_3 (ID 0083), Hoehe 1826 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" + "comment": "aus Zeichnung: VF_2 (ID 0006), Hoehe 0 -> 611; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "test_id": "VF_Arvato_05", + "test_id": "VF_Arvato_03", "typ": "standard", "richtung": "Auf", "deltaL": 11559.0, @@ -89,10 +93,10 @@ "x": 23843.05, "y": 24478.8, "z": 1826.0, - "comment": "aus Zeichnung: VF_5 (ID 0084), Hoehe 1826 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" + "comment": "aus Zeichnung: VF_3 (ID 0007), Hoehe 0 -> 611; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "test_id": "VF_Arvato_06", + "test_id": "VF_Arvato_04", "typ": "standard", "richtung": "Auf", "deltaL": 22559.0, @@ -105,10 +109,10 @@ "x": 42163.78, "y": 4017.06, "z": 2177.0, - "comment": "aus Zeichnung: VF_6 (ID 0085), Hoehe 2177 -> 2177; deltaL/deltaH aus den (ganzzahligen) Attributen" + "comment": "aus Zeichnung: VF_4 (ID 0008), Hoehe 0 -> 0; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { - "test_id": "VF_Arvato_08", + "test_id": "VF_Arvato_05", "typ": "standard", "richtung": "Auf", "deltaL": 6852.0, @@ -121,7 +125,7 @@ "x": 19551.49, "y": 5265.19, "z": 2177.0, - "comment": "aus Zeichnung: VF_8 (ID 0183), Hoehe 2177 -> 2437; deltaL/deltaH aus den (ganzzahligen) Attributen" + "comment": "aus Zeichnung: VF_5 (ID 0009), Hoehe 0 -> 260; deltaL/deltaH aus den (ganzzahligen) Attributen" }, { "test_id": "VF_Arvato_LZ_01", @@ -180,7 +184,7 @@ "INT:2", "STR:2" ], - "comment": "aus Zeichnung: VF_26 (ID 0184), 52 Eingaben, Hoehe 2177 -> 2174; wird 1:1 abgespielt (vsp-bau-journal)" + "comment": "aus Zeichnung: VF_6 (ID 0010), 52 Eingaben, Hoehe 2177 -> 2174; wird 1:1 abgespielt (vsp-bau-journal)" }, { "test_id": "GF_Arvato_01", @@ -195,7 +199,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_1 (ID 0005); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_1 (ID 0011); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_02", @@ -210,7 +214,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_2 (ID 0006); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_2 (ID 0012); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_03", @@ -225,7 +229,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_3 (ID 0007); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_3 (ID 0013); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_04", @@ -240,7 +244,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_4 (ID 0008); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_4 (ID 0014); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_05", @@ -255,7 +259,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_5 (ID 0009); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_5 (ID 0015); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_06", @@ -270,7 +274,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_6 (ID 0010); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_6 (ID 0016); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_07", @@ -285,7 +289,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_7 (ID 0011); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_7 (ID 0017); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_08", @@ -300,7 +304,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_8 (ID 0012); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_8 (ID 0018); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_09", @@ -315,7 +319,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_9 (ID 0013); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_9 (ID 0019); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_10", @@ -330,7 +334,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_10 (ID 0014); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_10 (ID 0020); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_11", @@ -345,7 +349,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_11 (ID 0015); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_11 (ID 0021); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_12", @@ -360,7 +364,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_12 (ID 0016); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_12 (ID 0022); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_13", @@ -375,7 +379,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_13 (ID 0017); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_13 (ID 0023); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_14", @@ -390,7 +394,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_14 (ID 0018); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_14 (ID 0024); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_15", @@ -405,7 +409,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_15 (ID 0019); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_15 (ID 0025); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_16", @@ -420,7 +424,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_16 (ID 0020); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_16 (ID 0026); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_17", @@ -435,7 +439,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_17 (ID 0021); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_17 (ID 0027); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_18", @@ -450,7 +454,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_18 (ID 0022); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_18 (ID 0028); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_19", @@ -465,7 +469,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_19 (ID 0023); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_19 (ID 0029); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_20", @@ -480,7 +484,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_20 (ID 0024); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_20 (ID 0030); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_21", @@ -495,7 +499,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_21 (ID 0025); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_21 (ID 0031); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_22", @@ -510,7 +514,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_22 (ID 0026); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_22 (ID 0032); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_23", @@ -525,7 +529,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_23 (ID 0027); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_23 (ID 0033); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_24", @@ -540,7 +544,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_24 (ID 0028); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_24 (ID 0034); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_25", @@ -555,7 +559,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_25 (ID 0029); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_25 (ID 0035); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_26", @@ -570,7 +574,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_26 (ID 0030); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_26 (ID 0036); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "test_id": "GF_Arvato_27", @@ -585,7 +589,7 @@ "kreisel_start": "Kreisel_Arvato_02", "kreisel_ende": "Kreisel_Arvato_03", "hoehe_ende_mm": 1826.0, - "comment": "aus Zeichnung: GF_27 (ID 0031); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 3.7929 Grad -> HOEHE_BIS 1568" + "comment": "aus Zeichnung: GF_27 (ID 0037); Endhoehe = Hoehe von Kreisel_Arvato_03 (1826.0), Winkel rechnet der Treiber neu; gebaut war 2.4700 Grad -> HOEHE_BIS 1825" }, { "function": "insert", @@ -594,7 +598,7 @@ "y": 12119.73, "z": 2473.0, "rotation": 0.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0043, ZUORDNUNG 0002, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0038, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", @@ -603,7 +607,7 @@ "y": 24478.8, "z": 1826.0, "rotation": 0.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0044, ZUORDNUNG 0003, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0039, ZUORDNUNG 0003, ARTINR 200000077)" }, { "function": "insert", @@ -612,7 +616,7 @@ "y": 12919.72, "z": 2473.0, "rotation": 180.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0045, ZUORDNUNG 0002, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0040, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", @@ -621,7 +625,7 @@ "y": 24478.8, "z": 1826.0, "rotation": 0.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0046, ZUORDNUNG 0003, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0041, ZUORDNUNG 0003, ARTINR 200000077)" }, { "function": "insert", @@ -630,7 +634,7 @@ "y": 12919.78, "z": 2473.0, "rotation": 180.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0047, ZUORDNUNG 0002, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0042, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", @@ -639,7 +643,7 @@ "y": 5042.22, "z": 2177.0, "rotation": 270.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0048, ZUORDNUNG 0001, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0043, ZUORDNUNG 0056, ARTINR 200000077)" }, { "function": "insert", @@ -648,7 +652,7 @@ "y": 24478.8, "z": 1826.0, "rotation": 0.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0049, ZUORDNUNG 0003, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0044, ZUORDNUNG 0003, ARTINR 200000077)" }, { "function": "insert", @@ -657,7 +661,7 @@ "y": 12919.82, "z": 2473.0, "rotation": 180.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0050, ZUORDNUNG 0002, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0045, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", @@ -666,16 +670,16 @@ "y": 12919.72, "z": 2437.0, "rotation": 180.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0051, ZUORDNUNG 0002, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0046, ZUORDNUNG 0002, ARTINR 200000077)" }, { "function": "insert", "block": "Separator_SP", - "x": 35857.18, + "x": 35182.77, "y": 25278.8, "z": 1826.0, "rotation": 180.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0052, ZUORDNUNG 0003, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0047, ZUORDNUNG 0003, ARTINR 200000077)" }, { "function": "insert", @@ -684,7 +688,7 @@ "y": 4269.52, "z": 2177.0, "rotation": 90.0, - "comment": "aus Zeichnung: Separator_SP_3D (ID 0053, ZUORDNUNG 0004, ARTINR 200000077)" + "comment": "aus Zeichnung: Separator_SP_3D (ID 0048, ZUORDNUNG 0055, ARTINR 200000077)" }, { "function": "insert", @@ -693,7 +697,7 @@ "y": 24865.38, "z": 1826.0, "rotation": 90.0, - "comment": "aus Zeichnung: Scanner_3D (ID 0073, ZUORDNUNG 0003, ARTINR 829534306)" + "comment": "aus Zeichnung: Scanner_3D (ID 0049, ZUORDNUNG 0003, ARTINR 829534306)" }, { "function": "insert", @@ -702,7 +706,7 @@ "y": 13306.31, "z": 2473.0, "rotation": 90.0, - "comment": "aus Zeichnung: Scanner_3D (ID 0074, ZUORDNUNG 0005, ARTINR 829534306)" + "comment": "aus Zeichnung: Scanner_3D (ID 0050, ZUORDNUNG 0011, ARTINR 829534306)" }, { "function": "insert", @@ -711,7 +715,7 @@ "y": 24865.38, "z": 1826.0, "rotation": 90.0, - "comment": "aus Zeichnung: Scanner_3D (ID 0075, ZUORDNUNG 0003, ARTINR 829534306)" + "comment": "aus Zeichnung: Scanner_3D (ID 0051, ZUORDNUNG 0003, ARTINR 829534306)" }, { "function": "insert", @@ -720,7 +724,7 @@ "y": 13306.36, "z": 2473.0, "rotation": 90.0, - "comment": "aus Zeichnung: Scanner_3D (ID 0076, ZUORDNUNG 0002, ARTINR 829534306)" + "comment": "aus Zeichnung: Scanner_3D (ID 0052, ZUORDNUNG 0002, ARTINR 829534306)" }, { "function": "insert", @@ -729,7 +733,7 @@ "y": 24865.38, "z": 1826.0, "rotation": 90.0, - "comment": "aus Zeichnung: Scanner_3D (ID 0077, ZUORDNUNG 0003, ARTINR 829534306)" + "comment": "aus Zeichnung: Scanner_3D (ID 0059, ZUORDNUNG 0003, ARTINR 829534306)" }, { "function": "insert", @@ -738,6 +742,33 @@ "y": 13306.4, "z": 2473.0, "rotation": 90.0, - "comment": "aus Zeichnung: Scanner_3D (ID 0078, ZUORDNUNG 0022, ARTINR 829534306)" + "comment": "aus Zeichnung: Scanner_3D (ID 0054, ZUORDNUNG 0028, ARTINR 829534306)" + }, + { + "function": "insert", + "block": "BTMT-Beladung", + "x": 42163.78, + "y": 4978.68, + "z": 2177.0, + "rotation": 270.0, + "comment": "aus Zeichnung: BTMT-Beladung_3D (ID 0057, ARTINR 829662012)" + }, + { + "function": "insert", + "block": "SC_Entladung", + "x": 35609.45, + "y": 25278.8, + "z": 1826.0, + "rotation": 0.0, + "comment": "aus Zeichnung: SC_Entladung_3D (ID 0058, ARTINR 400100156)" + }, + { + "function": "insert", + "block": "Scanner", + "x": 42163.78, + "y": 4224.88, + "z": 2177.0, + "rotation": 180.0, + "comment": "aus Zeichnung: Scanner_3D (ID 0053, ZUORDNUNG 0055, ARTINR 829534306)" } ] From 823dc6728d5455b79f9c29c777cae1091ba54bc7 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Thu, 8 Oct 2026 12:44:36 +0200 Subject: [PATCH 19/38] [CHANGE] Streckengruppe-Menue in Werte-manuell/Zielhoehe/Stueckweise aufgeteilt, QC-Linien unter Gefaellestrecke verschoben, Linienzug-Wizard "Naechstes Element" neu sortiert (GF vor VF) mit eigenem Abschliessen-Knopf statt Kettenende-Radio Lisp/vf_core.lsp: fuenf eigene Menue-Wrapper (LinienzugVarioFoerdererManuell/-Zielhoehe/-Stueckweise, QcLinieMitGf/-UForm) ersetzen den alten interaktiven Modus-Dialog; vfc-dialog-linienzug-modus-waehlen entfaellt. dcl/vf_linienzug_wizard.dcl + Lisp/vf_linienzug.lsp: "Neue Linie BIS Kettenende" ist kein Radio mehr, sondern eigener Button "OK und Abschliessen" neben "Ok Weiter"; GF-Optionen stehen vor VF-Optionen. Menue (SSG_LIB.mnu/.cui), lang/*.json, doc/kommandos.md, doc/lisp_methods.md, doc/faq.md nachgezogen. Co-Authored-By: Claude Sonnet 5 --- Lisp/vf_core.lsp | 110 +- Lisp/vf_linienzug.lsp | 21 +- dcl/variofoerderer.dcl | 56 +- dcl/vf_linienzug_wizard.dcl | 28 +- doc/faq.md | 31 +- doc/faq.pdf | 8862 ++++++++++++++++-------------- doc/kommandos.md | 6 +- doc/lisp_methods.md | 2 +- lang/de_DE.json | 6 +- lang/en_GB.json | 6 +- menu/SSG_LIB.cui | 70 +- menu/SSG_LIB.mnu | 9 +- tests/testdata/showroom_ils.json | 4 +- 13 files changed, 4935 insertions(+), 4276 deletions(-) diff --git a/Lisp/vf_core.lsp b/Lisp/vf_core.lsp index ec18f05..3ed65b6 100644 --- a/Lisp/vf_core.lsp +++ b/Lisp/vf_core.lsp @@ -80,6 +80,11 @@ ;; Von den Menue-Wrappern gesetzt, damit die Konsolen-/Dialog-Frage ;; entfaellt. nil = interaktiv fragen (Direktaufruf VarioFoerderer). (if (null *vf-vorauswahl-eingabemodus*) (setq *vf-vorauswahl-eingabemodus* nil)) +;; Vorauswahl des Linienzug-Modus (1-5): von jedem der fuenf Linienzug- +;; Menue-Wrapper (c:LinienzugVarioFoerdererManuell/-Zielhoehe/-Stueckweise, +;; c:QcLinieMitGf/-UForm) gesetzt - der frueher hier noetige Modus-Dialog/ +;; Konsolen-Fallback ist dadurch komplett entfallen (siehe c:VarioFoerderer). +(if (null *vf-vorauswahl-linienzug-modus*) (setq *vf-vorauswahl-linienzug-modus* nil)) ;; Registriert einen Foerderanlagen-Typ. ;; berechne-fn: '(lambda (deltaL deltaH richtung seite) ...) @@ -1108,14 +1113,14 @@ ) ;; ============================================================ -;; TEIL 11b: DIALOG-AUSWAHL FUER TYP/LINIENZUG-MODUS (Radio-Buttons) +;; TEIL 11b: DIALOG-AUSWAHL FUER TYP (Radio-Buttons) ;; ============================================================ -;; Ersetzen die beiden Konsolen-Listen am Anfang von c:VarioFoerderer durch -;; Radio-Button-Dialoge (dcl/variofoerderer.dcl, vfc_typ/vfc_linienzug_modus) -;; - alle Optionen sofort sichtbar statt Dropdown. WICHTIG: Radio-Button- +;; Ersetzt die Konsolen-Liste am Anfang von c:VarioFoerderer durch einen +;; Radio-Button-Dialog (dcl/variofoerderer.dcl, vfc_typ) - alle Optionen +;; sofort sichtbar statt Dropdown. WICHTIG: Radio-Button- ;; Labels sind im DCL fest auf Deutsch einprogrammiert (set_tile kann das ;; Label eines radio_button nicht setzen, nur den Zustand - siehe DCL- -;; Kommentar). Beide Funktionen geben deshalb nur dann etwas anderes als nil +;; Kommentar). Die Funktion gibt deshalb nur dann etwas anderes als nil ;; zurueck, wenn GUI erlaubt ist (Tests: ssg-gui-aus) UND Deutsch aktiv ist - ;; sonst faellt der Aufrufer automatisch auf die alte, vollstaendig ;; uebersetzte Konsolen-Liste zurueck (unveraendert im Code stehen @@ -1161,47 +1166,11 @@ ) ) -;; "Zurueck" springt zur Anlagen-Typ-Frage zurueck - Rueckgabe 'ZURUECK, vom -;; Aufrufer (c:VarioFoerderer) ausgewertet (dort erneuter Aufruf von -;; vfc-dialog-typ-waehlen statt hier lokal aufzuloesen). -(defun vfc-dialog-linienzug-modus-waehlen ( / dcl-pfad dat gmodus ergebnis) - (if (and (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p)) - (= *ssg-lang* "de_DE")) - (progn - (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl")) - (setq dat (load_dialog dcl-pfad)) - (if (not (new_dialog "vfc_linienzug_modus" dat)) - (progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil) - (progn - (set_tile "modus_1" "1") - (action_tile "accept" - "(setq gmodus (cond ((= (get_tile \"modus_2\") \"1\") 2) - ((= (get_tile \"modus_3\") \"1\") 3) - ((= (get_tile \"modus_4\") \"1\") 4) - ((= (get_tile \"modus_5\") \"1\") 5) - (t 1))) - (done_dialog 1)") - (action_tile "cancel" "(done_dialog 0)") - (action_tile "back" "(done_dialog 2)") - (setq ergebnis (start_dialog)) - (unload_dialog dat) - (cond - ((= ergebnis 1) gmodus) - ((= ergebnis 2) 'ZURUECK) - (t 'ABBRUCH) - ) - ) - ) - ) - nil - ) -) - ;; ============================================================ ;; TEIL 12: DISPATCHER c:VarioFoerderer ;; ============================================================ -;; Erzwungener QC-Modus (Linienzug-Modus 4/5, vfc-dialog-linienzug-modus- -;; waehlen/Konsolen-Fallback unten): "4"/"5" waehrend des naechsten +;; Erzwungener QC-Modus (Linienzug-Modus 4/5, siehe *vf-vorauswahl-linienzug- +;; modus* oben/c:QcLinieMitGf*): "4"/"5" waehrend des naechsten ;; vf-linienzug-modus-Laufs, sonst nil. Von vf-linienzug-modus (vf_linienzug. ;; lsp, spaeter geladen) gelesen/geleert - globale Vorab-Deklaration hier, ;; damit sie unabhaengig von der Lade-Reihenfolge existiert. @@ -1213,7 +1182,7 @@ best-winkel L_GF L_GF1 L_GF2 L_VF idx eintrag wahl antwort verteilung-modus n-scanner vf-nummer hoehe-von hoehe-bis lastEnt - staustrecke-basis vf-insert dlg-typ dlg-modus zurueck-zu-typ) + staustrecke-basis vf-insert dlg-typ zurueck-zu-typ) (princ "\n=========================================") (princ (ssg-text "vfc-banner-titel")) @@ -1272,24 +1241,13 @@ ;; Kette mit gemischten GF/VF-Segmenten), passt nicht in das berechne-fn/ ;; einfuege-fn-Schema fuer ein einzelnes durchgehendes Segment - siehe ;; vf_linienzug.lsp. Dispatcht hier direkt und beendet den Standard-Ablauf. + ;; Jeder Aufrufer (Menue-Wrapper c:LinienzugVarioFoerderer*/c:QcLinieMitGf*) + ;; setzt *vf-vorauswahl-linienzug-modus* VOR dem Aufruf - der frueher + ;; hier gefuehrte Modus-Dialog/Konsolen-Fallback ist dadurch entfallen. (if (= anlage-typ "linienzug") (progn - (setq dlg-modus (vfc-dialog-linienzug-modus-waehlen)) - (cond - ((eq dlg-modus 'ABBRUCH) (exit)) - ((eq dlg-modus 'ZURUECK) (setq zurueck-zu-typ t)) - (dlg-modus (setq wahl dlg-modus)) - (t - ;; Dialog nicht verfuegbar/nicht erlaubt - alte Konsolen-Liste. - (princ (ssg-text "vfc-linienzug-modus-header")) - (princ (ssg-text "vfc-linienzug-modus-1")) - (princ (ssg-text "vfc-linienzug-modus-2")) - (princ (ssg-text "vfc-linienzug-modus-3")) - (princ (ssg-text "vfc-linienzug-modus-4")) - (princ (ssg-text "vfc-linienzug-modus-5")) - (setq wahl (getint (ssg-text "prompt-wahl-1-5"))) - ) - ) + (setq wahl *vf-vorauswahl-linienzug-modus* + *vf-vorauswahl-linienzug-modus* nil) (if (not zurueck-zu-typ) (progn ;; Konsolen-Nummer -> interne Funktion: @@ -1540,7 +1498,6 @@ ;; Menue-Wrapper: jeder feste Endpunkt der VarioFoerderer-Erzeugung ist ;; direkt aufrufbar (Typ + Eingabemodus vorbelegt, keine Rueckfrage). -;; Nur der Linienzug fragt intern noch Modus 1/2/3 (komplexer Fall). ;; Eingabemodus-Vorauswahl: "2" = Werte manuell (DCL-Dialog), ;; "1" = aus 3D-Linie (Linie picken). @@ -1568,9 +1525,34 @@ (c:VarioFoerderer) ) -;; --- Linienzug (bleibt interaktiv: fragt Modus 1/2/3) --- -(defun c:LinienzugVarioFoerderer () - (setq *vf-vorauswahl-typ* "linienzug") +;; --- Linienzug/Streckengruppe (Modus 1/2/3, Typ+Modus vorbelegt) --- +(defun c:LinienzugVarioFoerdererManuell () + (setq *vf-vorauswahl-typ* "linienzug" + *vf-vorauswahl-linienzug-modus* 1) + (c:VarioFoerderer) +) +(defun c:LinienzugVarioFoerdererZielhoehe () + (setq *vf-vorauswahl-typ* "linienzug" + *vf-vorauswahl-linienzug-modus* 2) + (c:VarioFoerderer) +) +(defun c:LinienzugVarioFoerdererStueckweise () + (setq *vf-vorauswahl-typ* "linienzug" + *vf-vorauswahl-linienzug-modus* 3) + (c:VarioFoerderer) +) + +;; --- QC-Linie (Linienzug-Modus 4/5, Typ+Modus vorbelegt) --- +;; Menue: ILS -> Gefaellestrecke (gehoeren inhaltlich dorthin, technisch +;; weiterhin ueber den Linienzug-Ablauf/*vfl-forciere-qc-modus* gebaut). +(defun c:QcLinieMitGf () + (setq *vf-vorauswahl-typ* "linienzug" + *vf-vorauswahl-linienzug-modus* 4) + (c:VarioFoerderer) +) +(defun c:QcLinieMitGfUForm () + (setq *vf-vorauswahl-typ* "linienzug" + *vf-vorauswahl-linienzug-modus* 5) (c:VarioFoerderer) ) diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 3dbd70c..6274aab 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -1516,11 +1516,11 @@ (princ)) ;; "Naechstes Element waehlen" - Hauptmenue des Linienzug-Aufbaus (Modus 1). -;; Kettenanfang (frame=nil): alle 6 Optionen waehlbar, Vario-Kurve inklusive -;; (kann nur als allererstes Kettenglied gewaehlt werden - siehe Kommentar an -;; der Aufrufstelle). Sonst (Frame vorhanden): Vario-Kurve per mode_tile -;; deaktiviert, die uebrigen 5 Optionen behalten dieselbe Reihenfolge/ -;; Bedeutung wie im Konsolen-Menue, nur ohne die Luecke. Pusht die +;; Kettenanfang (frame=nil): alle 5 Radio-Optionen waehlbar, Vario-Kurve +;; inklusive (kann nur als allererstes Kettenglied gewaehlt werden - siehe +;; Kommentar an der Aufrufstelle). Sonst (Frame vorhanden): Vario-Kurve per +;; mode_tile deaktiviert, die uebrigen 4 Optionen behalten dieselbe +;; Reihenfolge/Bedeutung wie im Konsolen-Menue, nur ohne die Luecke. Pusht die ;; POSITIONELLE Antwort ("1".."6" bzw. "1".."5"), identisch zur bisherigen ;; Konsolen-Nummerierung, damit Journal/Replay unveraendert bleiben - die ;; Radio-Buttons selbst tragen daher STABILE, kontextunabhaengige Keys @@ -1531,8 +1531,11 @@ ;; - eindeutig als VF erkannt (Startpunkt liegt auf einer bestehenden ;; VF-Kette) macht "GF-Bogen"/"Neue Linie: GF" als DIREKTE Fortsetzung keinen ;; Sinn (kein GF-Baustein wird an dieser Stelle einfach an ein VF-Teil -;; angeflanscht) - diese beiden Optionen werden dann ausgegraut. "Neue Linie -;; BIS Kettenende" bleibt immer waehlbar (hat ihre eigene GF/VF-Erkennung). +;; angeflanscht) - diese beiden Optionen werden dann ausgegraut. +;; "Neue Linie BIS Kettenende" ist kein Radio mehr, sondern der eigene Button +;; "abschliessen" (done_dialog 3) - er setzt slot direkt auf 6 und ignoriert +;; die aktuelle Radio-Auswahl (hat ihre eigene GF/VF-Erkennung, bleibt daher +;; immer waehlbar, auch wenn GF-Bogen/Neue Linie: GF ausgegraut sind). (defun vflw-gruppe-naechstes-element-impl (kettenanfang familie / dat ergebnis slot gwahl) (setq dat (load_dialog (vflw-dcl-pfad))) (if (not (new_dialog "vflw_naechstes_element" dat)) @@ -1551,15 +1554,15 @@ ((= (get_tile \"wahl_variokurve\") \"1\") 2) ((= (get_tile \"wahl_linievf\") \"1\") 4) ((= (get_tile \"wahl_horizontalvf\") \"1\") 5) - ((= (get_tile \"wahl_linieende\") \"1\") 6) (t 3))) (done_dialog 1)") + (action_tile "abschliessen" "(setq slot 6) (done_dialog 3)") (action_tile "cancel" "(done_dialog 0)") (action_tile "back" "(done_dialog 2)") (setq ergebnis (start_dialog)) (unload_dialog dat) (cond - ((= ergebnis 1) + ((or (= ergebnis 1) (= ergebnis 3)) (setq gwahl (if (or kettenanfang (<= slot 2)) slot (1- slot))) (vflw-pending-push-all (list (itoa gwahl)))) ((= ergebnis 2) (setq *vfl-wizard-abbruch-grund* "zurueck")) diff --git a/dcl/variofoerderer.dcl b/dcl/variofoerderer.dcl index ef475a9..de452d1 100644 --- a/dcl/variofoerderer.dcl +++ b/dcl/variofoerderer.dcl @@ -3,14 +3,16 @@ // Dialoge fuer c:VarioFoerderer (vf_core.lsp): // vfc_typ: Anlagen-Typ waehlen (Standard/Etage/Linienzug) - ersetzt die // Konsolen-Liste am Befehlsanfang. Radio-Buttons statt Dropdown, daher -// Labels FEST auf Deutsch (siehe Kommentar bei vfc_linienzug_modus). -// vfc_linienzug_modus: NUR bei Typ "Linienzug" - Modus 1/2/3 waehlen. +// Labels FEST auf Deutsch. // variofoerderer_basis/variofoerderer_winkel: Werteingabe fuer den // Standardfall (anlage-typ "standard"): deltaL, deltaH, Foerderrichtung, // Einfuegehoehe, Fahrtrichtung, Seite, Winkel, GF-Verteilung. // Die 3D-Linie-Eingabe (Modus "3D-Linie"), der Etage-Typ und die -// Linienzug-Kette selbst (nach der Modus-Wahl) bleiben interaktiv -// (Kommandozeile bzw. eigener Wizard in vf_linienzug_wizard.dcl). +// Linienzug-Kette selbst bleiben interaktiv (Kommandozeile bzw. eigener +// Wizard in vf_linienzug_wizard.dcl). Der Linienzug-Modus (1/2/3/4/5) wird +// seit den Menue-Wrappern c:LinienzugVarioFoerderer*/c:QcLinieMitGf* nicht +// mehr per Dialog erfragt, sondern ist je Menuepunkt fest vorbelegt - der +// frueher hier gefuehrte Dialog vfc_linienzug_modus ist dadurch entfallen. // ============================================================ // Anlagen-Typ waehlen (Standard/Etage/Linienzug). Radio-Buttons statt @@ -39,7 +41,7 @@ vfc_typ : dialog { } : radio_button { key = "typ_linienzug"; - label = "3D-Linienzug (gemischte GF/VF-Kette)"; + label = "Streckengruppe (gemischte GF/VF-Kette)"; } } @@ -57,50 +59,6 @@ vfc_typ : dialog { } } -// Linienzug-Modus waehlen (nur wenn Anlagen-Typ = Linienzug). Radio-Buttons, -// gleicher Deutsch-fest-Grund wie bei vfc_typ oben. -vfc_linienzug_modus : dialog { - label = "VarioFoerderer - Linienzug Modus"; - - : boxed_radio_column { - label = "Linienzug-Modus waehlen:"; - key = "modus"; - - : radio_button { - key = "modus_1"; - label = "Manuelle Eingabe (Punkte klicken)"; - value = "1"; - } - : radio_button { - key = "modus_2"; - label = "3D-Objekte + Ziel-Hoehe (Randwert-Solver, fertig)"; - } - : radio_button { - key = "modus_3"; - label = "3D-Objekte stueckweise (Vorwaerts-Nachbau, in Arbeit)"; - } - : radio_button { - key = "modus_4"; - label = "QC Linie mit GF (automatische Auf-Ab-Berechnung)"; - } - : radio_button { - key = "modus_5"; - label = "QC Linie mit GF und U-Form"; - } - } - - // "Zurueck" springt hier sinnvoll zur Anlagen-Typ-Frage zurueck (siehe - // vfc-dialog-linienzug-modus-waehlen/c:VarioFoerderer). - : row { - alignment = centered; - : button { key = "back"; label = "Zurueck"; fixed_width = true; width = 12; } - spacer; - : button { key = "accept"; label = "Ok Weiter"; is_default = true; fixed_width = true; width = 12; } - spacer; - : button { key = "cancel"; label = "Abbrechen"; is_cancel = true; fixed_width = true; width = 12; } - } -} - variofoerderer_basis : dialog { label = "VarioFoerderer (Standard) - Eingabe"; diff --git a/dcl/vf_linienzug_wizard.dcl b/dcl/vf_linienzug_wizard.dcl index 6447aea..3a31dc8 100644 --- a/dcl/vf_linienzug_wizard.dcl +++ b/dcl/vf_linienzug_wizard.dcl @@ -523,12 +523,18 @@ vflw_horizontal : dialog { } // "Naechstes Element waehlen" - Hauptmenue des Linienzug-Aufbaus (Modus 1). -// IMMER alle 6 Optionen im Dialog vorhanden (stabile Keys) - "Vario-Kurve" +// IMMER alle 5 Optionen im Dialog vorhanden (stabile Keys) - "Vario-Kurve" // wird per mode_tile deaktiviert, wenn kein echter Kettenanfang vorliegt // (siehe vflw-gruppe-naechstes-element-impl, das dort auch die Positions- // Nummerierung passend umrechnet). Radio-Buttons statt Dropdown, Labels fest // deutsch, OHNE Nummern-Prefix (anders als die Konsolen-Variante - hier -// braucht es keine Zifferneingabe). +// braucht es keine Zifferneingabe). GF-Optionen stehen zuerst, VF-Optionen +// danach (nur Reihenfolge, kein echtes 2-Spalten-Layout: radio_button-Tiles +// muessen DIREKTE Kinder EINES Clusters sein, sonst ist die gegenseitige +// Ausschliesslichkeit kaputt - siehe Warnung bei vflw_winkel_hoehen unten, +// per Test bestaetigt). "Neue Linie BIS Kettenende" ist kein Radio mehr, +// sondern der eigene Button "OK und Abschliessen" unten (ruft direkt Slot 6 +// auf, ohne vorher eine Radio-Auswahl zu verlangen). vflw_naechstes_element : dialog { label = "VarioFoerderer Assistent"; @@ -542,27 +548,29 @@ vflw_naechstes_element : dialog { key = "wahl"; label = ""; : radio_button { key = "wahl_gfbogen"; label = "GF-Bogen (horizontale Kurve)"; } - : radio_button { key = "wahl_variokurve"; label = "Vario-Kurve (horizontale Kurve, 30/60/90 Grad)"; } : radio_button { key = "wahl_liniegf"; label = "Neue Linie: GF (Gefaellestrecke)"; value = "1"; } + : radio_button { key = "wahl_variokurve"; label = "Vario-Kurve (horizontale Kurve, 30/60/90 Grad)"; } : radio_button { key = "wahl_linievf"; label = "Neue Linie: Ab/Auf VF (VarioFoerderer-Einheit)"; } : radio_button { key = "wahl_horizontalvf"; label = "Neue VF mit horizontalem Anfang (Horizontal-Stueck)"; } - : radio_button { key = "wahl_linieende"; label = "Neue Linie BIS Kettenende (danach Separator + ES-Element)"; } } } // PROTOTYP "Zurueck"-Button (siehe Plan curious-prancing-parasol.md): ersetzt - // ok_cancel durch eine eigene 3-Button-Zeile. done_dialog-Codes: 0=Abbrechen + // ok_cancel durch eine eigene 4-Button-Zeile. done_dialog-Codes: 0=Abbrechen // (unveraendert, is_cancel -> ESC/Leertaste wirkt weiterhin), 1=Weiter - // (unveraendert, is_default), NEU 2=Zurueck (verwirft das zuletzt gebaute + // (unveraendert, is_default), 2=Zurueck (verwirft das zuletzt gebaute // Kettenglied und fragt es neu ab, siehe vflw-gruppe-naechstes-element-impl/ - // vfl-modus-abbruch-sichern). + // vfl-modus-abbruch-sichern), NEU 3=Abschliessen (entspricht der fruehen + // Radio-Option "Neue Linie BIS Kettenende" - ignoriert die Radio-Auswahl). : row { alignment = centered; - : button { key = "back"; label = "Zurueck"; fixed_width = true; width = 12; } + : button { key = "back"; label = "Zurueck"; fixed_width = true; width = 12; } spacer; - : button { key = "accept"; label = "Ok Weiter"; is_default = true; fixed_width = true; width = 12; } + : button { key = "accept"; label = "Ok Weiter"; is_default = true; fixed_width = true; width = 12; } spacer; - : button { key = "cancel"; label = "Abbrechen"; is_cancel = true; fixed_width = true; width = 12; } + : button { key = "abschliessen"; label = "OK und Abschliessen"; fixed_width = true; width = 18; } + spacer; + : button { key = "cancel"; label = "Abbrechen"; is_cancel = true; fixed_width = true; width = 12; } } } diff --git a/doc/faq.md b/doc/faq.md index cad3670..39117ec 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -136,6 +136,12 @@ Durch einen Doppelklick auf den Kreisel und der Eingabe des neuen Abstands im Be ## 2. Gefällestrecke +- einfach +- aus 3D Linie +- aus Linienzug +- QC mit 30 Grad ES/AS +- QC mit 90 Grad ES/AS + ### 2.1 Zusammensetzung, Abhängigkeiten, Randbedingungen #### Zusammensetzung einer Gefällestrecke @@ -187,6 +193,29 @@ Durch einen Doppelklick auf die Gefällestrecke und Eingabe der neuen Länge im ## 3. Varioförderer +Varioförderer können auf verschiedene Arten gebaut werden: + +1. Standard +2. Etage +3. Variabel + - Manuelle Eingabe + - 3D-OBjekte mit Ziel-höhe + - 3D Objekte Stückweise (wird gerade noch implementiert bzw. ist expirementell) + +Der **"Standard Förderer"** ist die Verbindung von zwei Kreiseln mit einem definierten Abstand und (wenn nötig) einer Höhendifferenz. (z.B. für eine Umschleusung in einem Gefällepuffer) + +Ein **Etagenförderer** hat 30° Aussschleuselemente und wird verwendet, um zwei Kreisel über eine Etage zu verbinden. Diese beiden Kreisel müssen dabei übereinander liegen. + +Standard und Etage können aufgerufen werden mit _"Werte manuell"_ oder _"3D - Linie"_. +- Bei "Werte Manuell" definiert man den Verlauf durch Höhe und Länge über die Eingabe in einer Oberfläche. +- bei "3D Linie" ist die Auswahl einer Gerade im Raum möglich. Damit wird Richtung, Länge und Höhendifferenz angegeben. Dadurch werden diese Werte in die Oberfläche übernommen. Der beliebige Winkel in der Ebene kann durch die Linie festgelegt werden und ist nicht auf die Raster 0,90,270 Grad festgelegt + +Die **Variablen Förderer** könne auf drei verschiedene Arten definiert werden: + +- die manuelle Eingabe frägt nach der Definition des AS Elementes ab, ob man abwechselnd eine GF oder einen VF definieren möchte. Mit einem Knopf unten kann man den Assistenten abschliessen und das ES erzeugen +- Eine 3D Linie muss aus Geraden und Bögen (Winkel 30° mit dem Radius 500mm) bestehen. Wenn eine 3D Linie für Verlauf mit der korrekten Zielhöhe existiert, kann man iterativ die Einzelelemente (oder auch mehrere) dieser Einzellinien Linie anwählen, um den nächsten Förderer oder den nöchsten Gefälle-Anteil zu definieren. + + ### 3.1 Zusammensetzung, Abhängigkeiten, Randbedingungen #### Zusammensetzung eines Varioförderer mit allen möglichen Komponenten @@ -229,7 +258,7 @@ Unter *ILS -> Foerderer* stehen folgende Einfügemodi zur Verfügung: - **Standard -> Werte manuell**: alle Werte (Längen, Winkel, Höhen) werden über einen Dialog abgefragt. - **Standard -> aus 3D-Linie**: wie Standard, aber entlang einer vorgezeichneten 3D-Linie. - **Etage -> Werte manuell** / **Etage -> aus 3D-Linie**: wie Standard, jedoch mit Etagen-Schrägsektion/-Bögen statt gerader AS-/ES-Elemente. -- **3D-Linienzug**: frei aus der Zeichnung gebaute Kette, Schritt für Schritt über Dialoge/Konsole abgefragt (AS-Element, Bögen, Vario-Kurven, horizontale/geneigte Abschnitte, ES-Element). +- **Streckengruppe**: frei aus der Zeichnung gebaute Kette, Schritt für Schritt über Dialoge/Konsole abgefragt (AS-Element, Bögen, Vario-Kurven, horizontale/geneigte Abschnitte, ES-Element). ![Variofoerderer dialog1](images/vf-gui1.png) *Abbildung: Varioförderer Dialog zur Erzeugung* diff --git a/doc/faq.pdf b/doc/faq.pdf index 66ea65c..0596dd4 100644 --- a/doc/faq.pdf +++ b/doc/faq.pdf @@ -4,8 +4,8 @@ <> +/CreationDate (D:20261008104358+00'00') +/ModDate (D:20261008104358+00'00')>> endobj 3 0 obj <> stream -xœí\[o%· ~?¿BÏ:KJ”D‹l¯�h -$1Ð÷:Ý ŠnŠÝ¦ÿ¿ ®ÔœËìñ¬“ ©ãsf$ñ#E~äÌx±.åÌõ'. Sbóôáðñ€è—`½Áè�µ fã,†%¤dͧþöóãáãÁ-h}¯|ÓW>}8@>ôíW¦|ùôþðê+gÞÿçðêOh^¿~õõÝŸß0oÞܾ½;X0M`4(3¼;Ü}wxõ×ÿøÝOŸþûôS?ëù·�‡Wd,›Çw,J¡±`(šÇ‡×6½1�ÿ< ]À•u>~oDNŽÀ ”O¼ {ÏH>ÀG¢úyWÎó˜Ç¾,ËüËßÿÕhë‰M‚Å›ŠK†:ˆ€z´Fd.xÏ&á‚Id )$+2ò!¤`žäêÀ–mi 6E–3=Xdk’h'?"³!ÆàE–¿a¹ZŽ“å’H†B†ó‰24‘‘œÈdìåâP–Eš—K†|Q!d™üX‘y“œ\á Lq:J Sòõ(´xr¶¬aÌG‹uQ/Ë-)„ PŽå»%:kÎzº…RdÔ€¸ÅaDdçL¢¥Ø-É€Ãö„É\1èÓa:šõ•£mNYß@}6NE[[f««â”µí+gÎÊz«Tdnßò• æ| 8Sc.ƒZ,³Ln“-ÀV0·eS1 2 VûЏ;€º®»Ê4Cw*µ–æ{j½ÝI'ͺ;+ ºÛ7œúî˜àìûHÁO˜‡›ñ~8¼Ë‘iIâ$5:•?>½?uÜu�¦¨À¤0G�°úðbQçThõZ�ÂÕ•3D›ãǶ5ER½› �A„®m°ï®¶qY\·w#"RÛƒ\í�²°ïV®žÁY\76J. kàîm"ì‘‚‹cZÌâT¸¸nY@Õ�űó5¾9ƒ>NÍkô@ÔlžT6[(¸�Ö]I“*}Ïj·­®ªñ MXÖÀ1£Þ#Œ¶�=eKWmýt˜�WýõHØôsâØ^zu˜µç|fS²ò�”Æ�¿Z*×wt �#äñW˜CŽ+ ónèVYš‰¡˜¸yí#ãRåOzå{cIÊKÇâ•GkE•÷PÔ>è©=U�Žu€¾ÿ†Mâ)ëq·î‡ï.IJʶ΄41¤!€AäÔ€êïM R5Xåàt!0E¤P'FÁÅYã�/Œïê¨/«@�« --žzJ%þÊÒ)Ðm�ǾžÃEM97ÇeW~[lÎ×Þ×˜ÜÆá:v=ÇÚ+ a ‰§�¤mH‚})HÚy©xJÏÏ„AcÃL·Aaº”š—ó¯¯Ç0±(Ü®ëàĬk€Í[�*/àºíêv”ã¡ÎÓçðÏÜjÀïü2]À-„òB+ ßÈ9…ŠAY»fP"‘”£ø“µ9;»¤B½È$‘óÄžDš3¾"OÖVj 2�Èò׉:‰4ó ÅœD&ƒ«<'¢La&Ú$ÒÌvkÊ¢$m€œQ­�I“:Üs²¥§ïi¾žéÇÂ:#PëïäaÒ´Ñ I§# -ºÊ[&ˆ;ÁQưÇ6sÕ¢š'‰$«lô(5%«ÙjîžH’Hsš7jñ•LZæ€C)¥“Ѱ6BÀ…¸¤‰‰4¯Öh“A³åÄŽ²\¹B¿R9�šCyW_�ò¾jå¯J?åÙ µ:`j¯(hÕ®ê&ˆ'LÅÝ’{8n“"k)BÀÍïGö'•öèᚬ™‘¥=Ì·©‘õ°RkyêÞŽš£.¬JÓ–Ó%ýµs±Dfx)RR¢Dðžžnjd¿)ô©ƒ¥Sc½Þù‘òrZkàÆ‘Vs&Ps—1®¼ó®àŒ {xn/cc#^»všv�ôvÙ +€SèÀYÐÀñrf7È™—:9ÓŠ'Ö–w -¨ûhYl Õ¶0.ž�Td­E“é¼­j?£ÙG3³¸[1 ¸>«às°‡jÙ ªÅ`vªu[H¹lÊÆQáÀ>Ìä=Céko*ÕMûpN§ûU­ºW|µñá»k" �ƒ=m„tãÜ:¤cÛP騧F3îÇmy¿'ÄÛ�/–-Ä»›Q¥æ²Ú<§H÷Q”ÙÌuÇ×]U�XŽ]ÜŽív8vlÏ�•‚·_ «q:̺´'̺í0K@g9U_ž%ÎמŠ9GÀ…màäûuàé K¸'Ⱥí K6¼x+öô‚ž«�ª‰Öõ¯HØ!±*€‰JÍ©™Tgn*€E*µ©˜(W{V"“¯n*€E*¡*€EØ–Û µ˜™,ÃM°H“ ”FœE)IQ)UÑ\«Ã½ìR£ômš¯—rje½äSôâpÒµU‘ -”^l*ðjQ:�Ü‹We{Âl®ZU×À"¥ƒÑÔÌ«éJ¡FS ,RQYÝ' Ê•ŸçIÍ\#"O5°H¥šŒFWªNœ .õé|‹@¤²Zk´Ñ Ysª�³\9C¿R¹�šC9X_�rľjå²J?åÜ µ :`j»(hÕÆê&ˆ'LÅÝ’{j`·]uÂäU \”p‹p§n¨f\N¡•€×Dt]SØCžÜv}LVJþîêc§ ñBæ¶ ¥¯�_ÚCI6{m6�¿±º˜4eóve£mÊæÝ¥ºx Oà±É27jV¿k¾¸Ù‹¹ß ê¨Ý?»þ– œ«Ï <”çPl�Þήô;£ò¢¾ß0~¨3]Sõ“®ú}Üßi»ê÷|ß_ªê']õû´'ŽÒvÕàlaûŒªÿùqsg7€tò ¸+–n'Ÿ`Ï¿Ïíìî* ¼N:Á퉚~;éúE Ý]™üZ`u: -aOÒo§#¹syÆuëþgÚ¶™nÝ ¶pÎ=e'+]›xkM‰Y�ö¬ÈÛ1GÐsÑèXäÔäÔs%iž_R`nY«Tû9©*$P©ê¤ëÅ¡YIžyÔèœeô(óœëœçA®É…ž”ïEØ“2üF.d0ϦŒ_Â÷„FÝ(ÚFäíOy´sêÜ›Ý/<ã×q¬³ë çZS®V·uW5ØuÁEs‚h÷¤7¿Í ¢;›Þ~ÁŶçŸØ4z >›‡qÚ*ѷܸÖП`éÓÊîTùþ0[`Ê{«Jå:—ÓŒ*Æ]ùl›QÅøkÎg—©»¸œŸ)´rÁîj5¬Û9Üκ¸TêŒ^ÆQ)϶݌¡ßÖsuÅ4š!yôú \ï -Ñåôs®÷`ôþê÷/i"ë—£ôTmTÍL‘‘—Wtï_¤1H3w´G9·¹UUD6Ä@Së_¤,èÖ¿ÈÛ {¸"cH§Ö¿H¥i?:ÿY’R¢Ò+fLSç_îÍæ1HïJO³õþµZWïs«õ�w}´¦ý¥ ŽHo°+àÚûEàù%e {Âb®T·ýE"=Š…)©É¼è[^©P‹ò¢/«'ßX^¨¡Ü0è:Ò‰®¿H¥NF£F26ð„/�èú‹tÝõgì–$ÝõÏråtÔõŸæP¾ÕW£|°¯Zy+�èú+$”ûwÀÔFÉжçæú–ê&ˆÇ–ânÇ=Mÿ°Qø¶�#bMW^w²v GÓ°?Ò{7Øp~ ÜWˆÞ_óú€~N™Ýâ¶ŸSf¢•Ö¿»»A—"ì÷ôÂv)Â!¼Ô]€0¹,·¤DHøLŸ=SPЊH¨Â#6³žbx½H. -q’æ.<ÔsêDj߸ƮºaÞCÃvÂÜé`Á_¢^¤4ìðê6¥Wfémì2.™¼…¹ç±}ö¹½fË öt£Ã6[N¿­{9Qw%“ÝÓÀˆÛ]Éäìÿïå|Ñ{9ÉÓž{9Qgiyd‡ù·³tŠa�¥_ê^NÔÙ0¥=Q3ngCyݦÑí¿YxVú9:lfO ³×_ $P3\Ý�N<üÜömys½‹üª¬ßìq´È¼j çs.Üh»íª^GÔÉ w½fº�ÝìÙGmŸÑíð�]�.Áô2áú|Øî”5ÝžÙM9טsÍ­´ÉÛxmL•�‡9¿9|sø˜Íb‰q±Þ8A>Ïÿ«ùvé_̈)³¹‚I“µ\\"Ëý=ž ”¨>ü��ŠS„\&Õ(ù&²«Ÿ©Äãü8yýù3]ÕqX ÿÿìO¤_¾$á‘ÑékrJ°ò¹q-/>‰Ó|²Tm™ÿtÌÅ +/Length 3208>> stream +xœí\m�· þ¾¿BŸ tLQ”D†�»ó]Z )�ä€~ï¥vPÔ)ì¦ÿ¿ ^©Ù—ñÞø’ ©�î93’ø�"rfvA—ò?Ìõ_&»$››§‡�kýнAô°1‡6,!%4ŸþqøÛÌ�‡�·Xôy¼òM_ùôáùз_™òåÓû믜yÿŸÃ«?Yóúõ«¯ïþüÖ€yóæöíÝÁk[ce†w‡û¯ï¯þúï¿ûéÓŸ~êçÛzþíãáÕdóøî`‹RÖ ŠæñÃá5¦7æñŸ‹ ¸²ÎÇï�È À8 å#€Gºð à€äÓø@T?ïÊyÞæ±ïË2ÿò÷õb] ±I°xóá@qÉP°³Þ¢™ Þ³Iv±È’ÈRH(2ò!¤`žäêÀÈE¦Èr¦´Œ&‰vòOdb ^dù›-WËq¡\ÉPÈÃp>Q†¶AdäC'2Y{¹8”¥E‘æå’!_TY&ÿPdÞ$'WøÅ¦8¥…)ùhõ(´xrXÖ0æ£]ÔËrK +!”cùn‰ÑÙYO·PŠl5 nq6Zdç›DK °[ 8’‡)ð„É\1èÓa:šõ•£mNYß@}6NE[,³ÕUqÊÚö•3ge=*™Û·|eƒ9_ÎTĘˠ¨€e–É1a¶š€¹-s˜Š¹X�¹X°ÚWÄÝÔuÝU¦ºS©µ4ßSëíN:iÖÝYaÐݾáÔwÇgßG +öxÂ<ÜŒ÷Ãá]ŽLK'©Ñ©üçÓûsQÇÍQÇÒu˜æ¨°>¼XÔ9Z½„Ö£pDuåÌÆZÌñˆcÛš"©ÞÍÈ B×¶wÌEØw WÛ¸,®[‹»­¥¶¹Ú;eaß­\=ƒ³¸nl..”\ÖÀÝÛDØ#ÇD›Å5¨pqݲ€ª!‹c[›¯ñÍôqj^£¢æ`ó¤²ÙBÁm,°îJšTéxV»mu�P�i²Žõa´…ð”-]µõÓa>^õ×#Ù¦ÿ˜ÓŽí¥Wg³öœÏlj@V^"�ÒòW¤r}GZÐ8B…9ä¸Ò0ïö�a•%¡™Љ›€Ñ>2.Uþ¤§Q¾7–¤¼t,^y´VTyÿEí“�žÚSéXèûoØ$ž²wëþpøîB,«lëLHóCš0Ör j@õ囹¬rpº˜Ž"R¨[ÁÅ¡ñÆÆwuTŽ—U ÈU…O=¥eéè¶Æc_Ïᢦœ›ã²+-6çkïkLnãp»žƒx$¬!ñ´’´ IÀ—‚¤�—ЧDñŒðLH,hLbØ�‰µÛ 0]JÍËùÏ×ã ˜Xn×upâ Ö5Àæ­F•pÝvu;ÊñPçésøçŽðÄ{¿L—p„ðB^(`åcaãs9G ¬bPˆk%I9Š?!æìì’ +õ"“DÎ{iÎøŠ{¨nP-ãl§Z·…”˦lnða&ïJ_{S©nÚ‡Óp:ݯj5нâ«�ß]©Hèìh#¤çÖ!ݶ •Ž}j4ãžq0hËû=!7B¼X>´ïnF•š#Èjóœ"ÝGQf3×_wU‚:»¸'ãv8vŒçÀ‰JÁÛ/ ÐU€8f]ÚfÝv˜% 3€œª/Ï‚çkOÅœ#àÂ6pòý:ðt�%»'Ⱥí K^¼‡{zAÏÕ¿NÕ¿DëúW$ì,±*€‰JÍ©™Tgn*€E*µ©˜(W{¨ +‘ÉW7À"•‹¬*€EËí„Z̈L–ᦠ+X¤ÉJ£΢”¤¨”ª‰h®€Õá^v©Qz�6Í×K9µ²^ò) zq8éÚªHJ/6xµ(�@îÅ«2ž0›«VÕ5°HDé`ô0¥ójºR¨ÑT‹TTV÷ ˆråçyR3׈–§X¤RMF£�+U§� .õé|‹@¤²Z4ÚhЬ9ÕÀY®œ¡_©ÜFÍ¡¬¯F9b_µrY¥ŸrÚ0µ]´jcuĦânÉ=5°Û®�‰:aòª®J¸E¸S7 T3®§ÐJÀk"º®�)ì!On»>¦+%wõ±Ó„Œx!sÛ„ŒÒ‹×Ç/í¡¤ ›‡=„�¶ ›·¿±º˜4e󸇲Ñ6eóîR]¼†'ðØdˆµ«ß5_ÜìÅÜïuÔîŸ]KÐÎÕgPÊs(X£·Ã•~Gc4C^@Ô÷Æu¦kª~ÒU¿�{â;mWýž�âûKUý¤«~ŸöÄQÚ®úœ-lŸQõ??nîì�N>ÁÛÉ'à¹â÷¹Ý€=À]”×I'¸=QÓo'�@¿h¡»+“_ ¬NG!ìéBúít$w.Ïx nÝÿLÛ6Ó­»Á΢§Œ âd¥ko­)1ëÑžy;æz.‹œšœz®$ÍóK +Ì-k•j?'U…*U�t½84+É3�Ýâ‚C¶ƒÅažs�ó<È5¹Ð“ò½{R†ßÈ… &Ú³)ã—ð=¡Q7Š6…yûSíœ:÷f÷Ëžñë8ÖÙuP�s­)W«Ûº¿«ìºà¢9AÄ=éÍos‚èΦ·_ApÁöü³›fC¯ƒÁgóð/î@ÛA%ú–×ú,}ZÙ�*ßf LyoU©\çršQŸ+Ÿm3ªÍùìÒ#u——ó3…V.Ø]­Æ�u;"'ƒÛY—J�ÑË8*å™…m7cè·õ\]1�fH½>×»Bt9ýœëý½¶aÕû‰4‘õËl£ôT1ªf¦ÈÈË‹+º÷/Ò¤™;Ú£l9·¹UUDb ©õ/Rºõ/²ÀtWd ÉÛ©õ/RiÚ�Ζ¤”¨ôŠÙ¦©ó¯÷fó¤w¥§ÙzÿZ­«÷¹ÕúÇ»>ZÓþRPG¤7Øpíý¢ðü’€²ž°˜«Õm‘ˆÆF�âEaJj2/ú–W*Ô¢¼èËêÉ7–*B(7 ºŽt¢ë/R韓Ѩ‘Œ <áK'ºþ"]wýÙvK’îúg¹ò:êúOs(ßê«Q>ØW­¼•NtýÊý;`j£dhÛss}KuÄcKq·ãž¦Ø(ü cãˆ6Œ¦¿+¯;!.À!ÙÑ4ì�ôÞ 6œ÷Ç¢÷×¼> ŸSf·‡8…íç”™h¥õïî.@Ð¥û=ý…°]Šp/u L.kƒ[R"Kö™>{¦  ‘P…Glf=Åðz‘\6”µ‹�„0wá¡–˜S'RûÆ5vÕó:¶+æN þõB ¥a‡W·)½2Koc—ì’É[˜+qÛgŸÛk¶œ`O7:l³ådá·u/'ê®dÂ= Œ¸Ý•Lÿ/ç‹ÞËIžöÜˉ:KËË ;Ì¿�¥S ë,ýR÷r¢Î†)퉚q;Êë6­ˆn¿fá ôstØÌžf¯¿H f¸8º�xø¹íÛòæzùUY¿Ùãh‘yÕÎç\¸?ÐvÛU½Ž¨“›»ë5ÓíìfÏ>jûŒn‡ïìzt ¦— ×çÃv§ü¨éöÌnʹƜkn¥MÞÆkcª„<ÌùÍá›ÃÇl$¶ zã<ù<ÿS3òíÒÖ)³¹‚I“µ\\"Ëý=ž ”¨>ü��ŠS„\-,L.ªQòMdW?S‰Çùqòú{ùóöâ¨NªPÈ? cÁöGÒ/_#¿d‚6¿Þ¯É9åsãZé`ÄSÓÑâ\$@×£ÌX‡˜ë}äÑD endstream endobj 53 0 obj @@ -631,7 +632,7 @@ endobj endobj 76 0 obj <> stream +/Length 3867>> stream xœí\[«$Ç ~Ÿ_ÑÏ÷J¥ºÂbØ™sÆâ€ã…¼gÛ„ØÁçÿÕUU}�ïKì…åÌTw«T’ªôéÒ3+ ñßL_Ìâ«×8 ÁO~¼ü|A4³UfBg&¥ Ì ½ŸH¡�mjúø�Ë_ÿ0ýtùùB3*é¥OåÉ/4ÍÎ0=ˆ×ÿòÕ”>|üþòæ+š¾ÿÏåÍŸþö¯éíÛ7_ßþø2Áôå—×—Û-Mä'3žè»øüˆ¨ÐH_>~yýúvyóçÿôí/ÿûá—J 3©ëûË›»žPOï¿»`Z5NèaBÐvzÿãå-½Ð7퀴ÐÀx1Æ×-€¾æï>�LŸù/�SP!}6/‰†1é»Òùþ�è3-¾fòóúÝm#øâïÀ¸|äÿ®çC]Ü-ÍQÖ×̃i´" —iò÷¼v—ø‡€R_Nïÿyy}¿¢Ç(©DÕ)ÑÂJ¤J´þ3+1*êžÄß­Š0IiZ÷ @@ -651,7 +652,7 @@ N ƒ^[Þb‘úù�­£Õ—eßí¸lÑ-/i­©êÑT]ͽ@[ÓøJû#U¤Î”_ñ>Ñ{P-$ó}U£lNh©V—7ÍŽ]Ö V2rîûRÁ26Ý´òAϽu%yÂÊ»ö]ó‘i²�Û®îßvÈFYIƒÈĦÖȤÞVÝ™ÔáÚ™Ôà:™ÔßÚ™ÔÞª:·�»[{ “z[;“:[mç�rcë€cR_«îpLnk-ÎÏûÇÔëÂ&:=ŽI3v8¦2&¼vá_¸w±Î†ª@\H‚óV$›Æ$UPcªÊ¨¨´‡1©“¹‡1¹åYΗ<À˜ÔFÝÁ˜ÔnÝØܙ=À˜ÔÃíŒI�Þ½l#j@1¹y¼C1žª"i@1|IÚ-QŒ˜GÚWfHaáYZk[�´kZ‚˜*.¹SôˆI èALU”oŠÜ1æ �¾€¢9)–hf�žLiŠaæ¦V7ƒ1¶Kú”ßÇi!e-eÿ„ù<£„•¼ŸÑt™˜¾X Odg‹¤< –Ž×~ÁN)šy)…‚¸”ø]ž³ÑýVIãY�‰¬ë…Ù¤ $~ë¾âvW}.#4þQGZoû®ÒJyíÇ“¯>ô¹ -°tÅ-€§Ù_N(……Åd ôì«–RI„†%c»ð&,xTeiHÕ¯u« µþîˆéK|‹BèJ²yòo.ß\~Ž}‹J{œ•™È€å¿Û?-ÇŸö~MŽ÷UÔ �B§@r³óLAÉidV'ûŒŠp�ŒDÂìc†­Ráæ`¤ü7䂟Îc�ÿ†]ªäí 1ŒB¨›Úì?pç‘ä3í¼:xÖÏ&•ýÅ|‘e©™ÿ\piX +°tÅ-€§Ù_N(……Åd ôì«–RI„†%c»ð&,xTeiHÕ¯u« µþîˆéK|‹BèJ²yòo.ß\~Ž}‹J{œ•™È€å¿Û?-ÇŸö~MŽ÷UÔ �B§@r³óLAÉidV'ûŒŠp�ŒDÂìc†­Ráæ`¤ü7䂟Îc�ÿ^w©ûEˆqBÝÕfÿ™€³Vž¡>Ó¬ƒgýœÊþb:�³ÀDNƒ¢º‰PKuý=Ím× endstream endobj 79 0 obj @@ -732,28 +733,19 @@ endstream endobj 81 0 obj <> stream -xœ­\[�d7~Ÿ_qž‘⵫\e[ZEÚ陎�°<’"‰²$ÿù^¾œîž,H«éøøR7þ\¶Q€!ýïЇ>¾Pâ?½5*˜üñÍO??CŠ�ãè ­´õþ@0¬88>}ûô×ß?>ýü„Ê¥þò¯Úò E±;�>ÿù«#ÿøôýÓ»¯ðøþ¿OïþøÓ�ùåÓ¯ßür¼ÿîëËï_}|ùåóËåéùãÓ»«=Œ=>~÷d²¼æ}€v||üáé½Ö`µ&£µuZ[¯5Qþ«±|så_,¿hmIkò¹¬ÖÓÏZCiG/ùoªËZÛçÜjÇù µ¾–þŸµv—\'õuíã¦q¸Œ#dŒßmŸµ6Fk})对¿4ž)õLùVäkzš\¿ý¾jM�ÇŒõI÷q£ì©í5ÿKýÙ®O꣖q—;õóAØUŒ]uMu¡÷M­Î—ÇÇ?½~¼åÅà‹­íÆ‘RϦ”/IJè¬dñeDá¥j�XV¥÷fí7iqéÞ§P,GÂ\úzÞßû‰cÅâA6ˆ¶W1ŽŒ×elýÔö¯â›Íž|$šSý"?_ÖYñ¨G­ëãfýî{Ò€®žœ¬ u4(=úIßc?Õ1Åúa±"aÓ’ºe›¢ZÌý)—e¯1u2ŸáÉ’¾‰I¯__žÞ]ÿõý¯Ÿ¾m d -(½û›óÇËOiˆÏÁ½4ÆŠ}pûlÐX®ÓFcUø¤7”½y½v‡Ê[ŒøÞ;­èe«‡®Ù«ÍK�É$€sÊ¡±6Úâã?Ž÷2PSc•Fk\p­Æ¾© "FëD%ßÓ^Ä<,(¯mòŠ,CãFYRA£Á±ÆµÕ8·£�¼Â -c,j¿ÌÒÍŽY)c”uÞ¸ ËVó -Á{]ݪŠâ` î-Bù`Ù˜nçVYo +Ì›>  -l)ÑUÖÕ)bC€¢Åsú°Õìùþ@¥z àýÉöCùÀÜ7ÉiW„µ+@Çön¹õEXbÍì»›Êöƒ�nÑB€à�6»ƒU°¬­£»¢8YÖÀòžšêL€;qO2î vÐO–jÀ¿UtpLŒs8œÃ7AQE¹�ä`ÆLë‹.P"× y¼f;h…¨µÞ�B€.ã2ß*+¨AýöÒ!‘%Yäui(ŵS’$Ô%B…Xšå¢è:)KôÄÂùA@¢-Äî*ÈŠ~ºÓ©�œ3­¡çl‹J‰½¹Y -Å‘òV*±“¹ÊÖ1öœF»žÅº(ˆÞk'O�F“(7#Mh –”LzðÃHåö¡YäÒ)‰¤òu›Ðè¹íD¬Q�"k¥2’ÈÎ Z#¼¾ÓõæMY×õ:µï™K4•m‘ûa�ÆØg›J-Zð”ÕS�H·¡æ’à�q’-¸Ð_?Ž!énÔŒËFŒ&r8ĹÛl\¨�-7hU§êI{�¢ˆnÏ™º±LcLm’\¼–�¹^Úº„iãyõ¶Óœ"RèÞ‰ñ »€Á,g„мV„̫ط\$ÈÝÐ?L¨Øé6pYøÙÕg΀Aª;^:ÓpŸ¥»¶-Å—N”ëúÚ3F07rÜ´þì¶â$—‚<%]Phµ—8¯Í¡è”×�ÄžßvÚR:D­ íÝ…ÝËŠ‹’¯œØÇÜO(;»å3þÞ2×ùCy–nää’�$¾â&“Â/ƒFøûº.5eýÎEÇOÖ©”Ãç\äcŽ#–!Åj^+CÚÄ2¯Èe–˜ŽobköàÁåRÇàbMÒ`|ªi”ÆÔ!°sL¹Øqn¬ÑæBÒÆ–cÁ—ŠìÁÆ2Kì4æ2¯ƒ‰�9Êe�Ë¥ù°1KcÈp)Ч–Tê bR†}\ËÅw«¼ qaêÝXE¡ÊPdz -ÐI±"0'[6ñQ9@3ê‰Êç�°*4Îd{T³¡2!+ÙÍ‹J3ÚÜ_ul†Õ¡ß°÷R�v4gû¾^´#¶é`% TŽôåII ©×fFÒX4#©×° i,³1Ý5 i,�‘Ôkœ‘4-H #é¡‹ØËIË¢#�ÆÒ(®DR¯m™|ñ×¢éSŸº½uŸärœ‚]œMêŽ,R»AÍ -¨º±*žI£vÜëæ‡�›°ºqÀÏX4ã§×zÂÏX²àg,Ì`Yñ3„¨0øÂ?C˜ð3„?CˆÀ„Ÿ!DQiÀÏ*~fø? ül­~Šq~6‰:~6©~ -ý~6KÈ ¯“ÓC¯øÙà6ŽòÝ‘·ðóvÖ8â§×î³ðÓ=ŽŸ}(äœÄÙá§UŽ�3§gT7d™3&3€Z…v’¤h”¨�ï›MBó  $hÆ» 4WЫŒ aˆ -°;Єh  4�ÐÚ€&ÐB?cÙL?c™×'Ôšég*êô3¢Ýˆœí»€ÏÚ�@O1^EÏ&–@Ï&¾€O¡g‡Ïj�SÍl ΄yì5GÀÆaX:Â'`Ôø˜á`Ÿ3|z0Qc3jiâéqá3–ÚàðèF3¬Üh[³¡Ÿ±t¦ŸLó£á3}’‘`ú)Ç‘ÑU%AX¥–ÑÚõ“a]-!ÃVøì–•3 -VølŽòÝ‘7ànoŠ|BݧD€8.¹ �`nCg0²{t%Á¨ ò�ó-%ÓÒ\ÑeÚã�#íW¡Ö·½{ßfã&pºÙ!„üâØÈ@Oš lç¨ -(Q5Å鈪9\GT�˜Q5Ç쌪9fGTM1›éi ÔüGXM�&XÍ��°šÅ˜võ> Œ®fÅ®Z?ájû.¦tëGL~1bň&˜’¦€€¡iǦfaÍt 鄉"6gÀÆiX�:"kÖyDÖ¬³DÖ¬ñ„¬Iáacï‹Ê£š¸!¦>7êÄÔ§žGbË6ÈšE‘Õbó$NÈ?É`ÀYÅ82Àp&¦]j°¸!¦Ýr -Øec/,+g•]‘µ9ÊwGÞBÖÛ{Ý„¬d*²–«3“GŽoGß;÷6Œe¥-ûD›(XN"Óæ¿žø¿Go³r0¤ -Mmã6 ­×li̘ÚËYX;�¼Ò¨O"ü7ØIf·0»€Ù¯¹ö;ŽÙ�9Àa¡µ6´–Ê¿Vüå°£µVü�e�žð·}¿õ# BŒX‘¤ &à¦) €IhÚ¬ZDà\3\ƒCa`›Í°qV—ŽðËn…_æ~™7ð˼[¦%/Ë6Ä–i‚_¦~™6y�X:ç|Îôä6ü2 ðÛZ˨¡M^ K$Â�VøúÉÀ¦5/Ð &§ -oà·9Àmå»#oÁïí�r‚_‡Ÿ“€;nC^  â¨]Â*yTÖãÀe/íÒgPl ‚8�¤é6nÞËçž@ñ†?ËkÜgw…™t†kPêT¡;Ú-Â3R>@K°Ëåw]ÅŒ¼7,nçÁ�·¡å�˜÷Ë�X,Z ;è•;½ƒî Wî–±X´BwXÄbÙÝÁì ;,b©H w˜Äúw�a9“ãU -ë�X_@Z؈5{„lfk@*Ì+·96Ãêи}X�Û§ó#Æó›±X8·w+p{·n歷„_ÄbÙ¸½[�Û×±økn?ˆõÖ"fÄ8"ºür Ö¥Ñ*ôaÝ,!¿LL¿9ëpGùîÈÀ�÷Ä|�§T÷Þv =7×íÚ{­ßòöK"ØE\q¼Š6òjõ¶‰Ÿ‚ȈëÅöìMÙ£ä÷‘7hR‡z™ÕÖK·/F/#sÝÃë1êåz2æC°®y"]­’¾“¸Œ‚Â{URñfÉ‹ìuúwÉmZ]',õ,¢ƒû…‹­Gçv›:¸õì½…ï^? „ââ³¼>M¡kžâXøq¸Û¯Ý Ö=võdÙx‰«(Û+?âEÚzR<ƨÆ~‰{×§Ìì ¯ß0¿ŸËuᔉ{¯î”Ô"Y¯4É;ÿûÔâzoÛßp±#±å_noÉaå�kÐ޽ыöî¥0Ô†v—žB¹|,^†¶¡ËmE,‡M’‘î®Ü—Ö)7üâzT€È/¿@1¢.ï�Ï -}E«ôúÊ«h]F2lTd<>ø*—lo˜ŽîÍWÔÄ«¯I -l7ÖÙ ŽŸ¸ÅãBìtÚ>‹'©—’šŒ«¸~í±˜6ó‹qWý17¯÷Òê›�å.»œ¯Ó$Þ°mæÞVnÛç_]rä«�ÿÏM­ÍëÝyŒCöO]ß|ÌzËs—fo='O›¯{(ñ2'-ó— ñh÷d i -=Òv^QOâ ¯®+ ˜Ÿ&Ýà? yôù³+oƒãÓÝèQ°ñ~HšãßóÿCƒøëÞcÞ2|„ñíšSΛtpT£&%Ë3ŠD#Æ'Ös'ÎèúL·öb(#FúòÌH3°üŽÃÍ^ѳJ¯êŒÑ5køv“¸Ós1 Ú$ð™69iëUΉÈñ’ÈÒ3ÿ(-™í +/Length 3727>> stream +xœ­\[�d7~Ÿ_qž‘âuUùR–V‘vz¦#$‚¬Ï„$€H¢,ÉÿG¾—/§»' Òj:>¾ÔÍŸ?—mRHÿ;ô¡�/”øO6 „ÀÇ7?<ýü`•C{€·¢ÕJ惜r!àñéÛ§¿þîøñéç'R€6õ—Õ–_8t¨lìN§ÏþêÈ?>}ÿôî+:¾ÿïÓ»?þôã_~ùôë7¿ïß¿ûúòû—C_~ùüryzþøôîj0ÇÇïž Ë êµwÇÇžÞk�Fk Z¯µa­­Í5•o¾ü‹å­�ÕÚr.«õô³ÖXÚÙ—ü7ÕuZ›çÜjÇù µ¾–þŸµö—\'õuíã¦q\GÈ¿›:¾Ó@k})对¿4”zP¾ùšž�ë·ßW­-æ1c}«û¸QöÔöšÿ¥þL×'õQË\—;õóAØUŒ]uMu±÷m[�/��ÿ~zýxË‹�‹�鯑RÏPÊ‹bYtV²ø‡2¢ðRµF,«Ò3¬ý&-.Ýû6ËYa WúzÞ@îýıbq� DÛ«GFƒï2¶~jûWñÍdO>Í©~‘ß]ÖYñ¨G�ïãfýî{PWONÖÅ:–yÒ€{ì§:P¬+6-m·l³BôB‹¹?Eø2Ž•·EL�€Œ3<«obÒë×—§w×}ÿë§o(A¥wó|¼ü”†øÜKc¬Ø‡7±Ï} quÚhª +ŸôF²7Ökw¤ØPÄ÷ÞiE/S=tÍ^•/5&“Þ+O`L´ÅÇïe ¦ +`”&>øVc ßT IYGÆ‹JÜÓ\Ä<,(‡¯mËÊ . �se¬bBM@c�k«qnG3yÅ)б¨y™ V7;f¥”ñ >Á²ÕX2{ìêVU” ®·å 9€nçF6àÀ󦤂36ÑUÖÕ+ëÀ"‰ÏéCPèŒvìî��¶´ ¦àP�OÆ0ÊGÁ[‹÷MrÚ•¥Ú’wæn¹á"¬uÚ9în*KØ bu‹ö~@Úì§‚qÚ1º/Š[ãÑ> ï©©ÎA¼÷VƽÅô[ckÀ¿UtðÎ:šÃá|wôˆT”­ `Z_t�¹fØ‘çák¶ƒVDZ{á,è2.óm¡2‚Ôo/�$‹n]ÚJqí”$ u‰P!–f¹(úNÊýA±p~�h +±»Š²¢Ÿîtj'çLkìs¶E¥D�Þ\‹,…âHy+•ØÉ\eë{N#¬ó <‹uI½×Nž�¶¢FšÐ,)™ôà‡‘0ÊíC³È¥SIåë6¡ÑsÓ‰X£:EÖJe$‘�´Fx¹ÓõæMY×÷:µï™K4•m‘ûa�ÆØg›J-Zð‡ê©G¤ÛPsIðÆ8É\è/�cHº5se#f'r8Ĺßl\l[nЪNÕ“æ:E‘½=gêÆ2�1µYHrñZråzië¦�çeÔÛLsrˆH¡{'Æ'ìGFXî+ò2¯bßr‘ wg@~˜P9¯ÛÀeác4Æø¾ŒõHYÃÁê¾Tž¶8]Áé¥RrèsðstÎN¿¼�¤œËuÚÕã°/…2 ÎzxÀ(gR�ò<}=ñá9ûÌö­¬eIp++�yÞ¿u—3G½Y‹sÖ}Úâµ ä5…šÇæ�1~c” +ý wEÕê>€C·ŸÖ›Œë…©ÌÞ­>Ð}톎¼¶Xð̃ûdWŸ9©îxéLÃ}–îÛ¶”^:Q®ëkKÌ€`~ä¸iýÙmÅ­\ +ò”ôA‘Ñ,#p^šCÉ+ÖÁŠ=¿é´¥tHZaÚ» »——$_9±ÜO({³å3|o™ëü¡‹„ðÞ'�-Sú17nöð>6J¦ÌFó^¸0ØÖ{B¶ms‚÷QT<¤³¼¯~ô>û±ùÙ§˜i‘ÐZ‹˜ãˆèjõ lR‹hú‰°n–áß &&J·¬˜QÍ~ã(îŽüçÓw§¨t;Õë"*qMw,¨«ÈþÝ^@ƒbRþ·ó¿·…Ïeãß�Ý…ÀÞnpýž(su’$¦êƒc–‚´£9Ó÷õòØ ±M+I r” /çHj’²†IcÑŒ¤¬qAÒXfbºk@ÒX:#)kš‘4-H #é¡‹£““"–E!F �¥Q\‰¤¬M™|ñ×¢éSŸº½uŸärœ‚]œMêŽ,R»AÍ +¨º±*žI£vÜëæÇ�›¨ºqÀÏX4ã'k=ág,Yð3"e°¬øBT˜ü a‡Ÿ!LøŠŸ!DpÂÏ¢¨vÀÏ*~fø? ül­~Šq~6‰:~6©~ +ý~6KÈ ¯“ÓC¯øÙà7ŽâîÈ[øy;kñ“µÿ,üô�ãgŠ\NâìðÓ(ïÀÃéÕ YæŒÉ  F‘™$©%jçû°Ih¾4ƒÍx`7�&Ò +šh˜†¨@³MŒB;€&Ú4Ñn@íB?cÙL?cë@j¢�ég*êô3¢Ýˆœí»€ÏÚ�@O1^EÏ&–@Ï&¾€O¡g‡Ïj�SÍl ΄yì5GàÆaT:Â'RÔøDœáqŸˆ3|2BÔF-!ž‡>c© žŽn4ˆ`åGÛ†~ÆÒ™~2Bó#Œð™>ÉH€…~ÊqdtU‰DV©e´výdXWKÈðÇ>»eåŒÂ>›£¸;ò|âíMq‚O¬›â”Ç%w¡á6t�Ý“/ F äxœo)AKsE—i¦!GÚ¯B5¬o'z÷¾ÍÆ!¸t³C=$øÅ±`Oš l稊$Q5Å鈪9\GT�˜Q5Ç쌪9fGTM1›éi Ôü›FXM�&XÍ��°šÅ˜võœ¦W³b W O¸Ú¾‹)Ýú“_ŒX1¢ &€¤) GhÚ±©™D@X3]C:ab�ˆÍ¸qU§ŽÈšu‘5ë,‘5kòMêP/³šúbéöåÏè…2×=¼³=£\/CÆ|Õ5Od «UÒw+.£�ð^•T¼Yb‘½Nÿ.¹M«ë…¥žEt¸~ábëѹݦm={oa¥»×O‚%qñY^Ÿ¶¡kžâXøq¸ÛÎEÃ×îã»z²l¼ÄU”í•ñ"m=)cTS¿Ä½ëSfö†‹×o˜ßÏåºpÊÄ=�WwJjÑVÚÊ;ÿûÔâzoÛßp±·bË¿Ü"Þ’ÃÊ× ½{£—ÌÝKa¤Áî.=…rùX¼ mC—ÛŠT›$#Ý]¹//.ŒW>nøÅõ8¬‘_~¡rD~¸¼7>o(ô•ŒÒë+¯v uÉ0¨È0Üøà«\²½a:{o¾’¶nbõ5IAíÆš%D£Ægnñ¸�:�6ÏâIê¥$€æã*îƒ_{,¦ ÁüâAÜUÌÍë½´úæc¹Ë.çÃë4‰7€0,F›¹·•ÛôùW—ùjãÿsSDkx½;�)bÈþ©ë›�Yoyî2Âì­çäióuo%^æ¤eþ2!žÝ½CÚE�¬}8¤Í¼¢ž<Ä^]W0?MºÁòèógWV¼ ŽOw£GÑÄû}ö «]ü{þhÝ{Ì›BÆa|»æ•gHG5jBQ²<£H4b|b=wâA×gºµ°1Òß�gFz˜Aåwº€p³Wb§ò³:]s±àn·   ³l“Ð eÞä¤-«”‘Ùr�œÈ�-ÁHwýþžl endstream endobj 83 0 obj @@ -766,16 +758,19 @@ endobj endobj 85 0 obj <> stream -xœÍZY«\7~ï_qž¢[’ª´€1ôæ!ž¹�àI3qŒçÿZꨤ³u. ÄÜݧ¥ªRÕW«Zó¿ &˜¾Sâc@­¢Ž1L?�¾œ´&å MÚÓd � a²F;åb4ÓןN?þmúíôåd•6”é•w¼ó»ˆA+C‰žÂ¦öß?¿Ÿ†'_9½|ìôË輪˯Ÿ?þ÷ß¿ý4½{÷òÃõï· ¦÷ï/·ëÉÐd­§É¹89—„øù“BpR™®øThb¢ÉûHìJyCúËk3ûû×ÓË?>ÿö¯o_ÿøøm–@W .¯§—N§×ŸOº¨QO&«ÁM¯ŸNﬠ@ïä´~?½þçtÝb`Ž © `À+X34 -ÓIazý÷ô®,£´œêò$“¯ÏuÙJ7:7’¼'}gîu?³sõý£|ÏÏÒógßï·.‹¥#) -1à,XÚ€X¦÷´¢´L0=»”ïÓÌðV_7˜ºk¥åšÀ™O4}·C«²6øÃ¥¬KϳœÔ”„ÔxÌçñU6S|­JMù½Ì ŒË;dË *›{£6¬+Z8ÒFZ—­ÁZÑÇÐ÷¦q¤a½Ðʨ%[´c#)íu >f‡¡mxÎæðž÷T…d¡|�ãù`· ¡Î—îƒ?ü³Ž(ark9Ýž{KdàùuÍdm˜¦Í¼þ\µ%jÁ¹ÈÆF{,‚]T‘²æª›yeÓ£œÓ¢ð¡FMÅZ˜$É‘á!àäÂFH’µ+ ÅCƒ¯Ía‹Í‡US3”¼T/ͽ„Öæ$bsV••;­/ÇÊ.—RéyȽ—Ìnì�„Uöj͋٨”Ž‚Áš³û¥GùÌUS,»–¸ÄZY'g¤qH¢~~¦¯¥ýÚ“%£µ;�Ké�ʸ@Ô·´Ee¬Ýnb�ZÅ�{e!€¾­ÄÐ0Ä5/<\÷©G:ͼn„œ,ß’Úcߺ$›>›�Í<”Qéù³é’i¤à2Ž$mI'õžiî†ýÒ…Ž9™µæYŠPã¬À ¤¢·Û’¹ì—­Ãµ—z3ãÚvª…ö•î¹­eÏke(óˆøÌó <AapÊâ+ç  [T–6[�,)�ºh'â¹è¢çñÉŽ6›ÒrL¶·ÖçdÀUœÍ&¼ˆÌÇŽpk±Ç0c�Ï�¦~>~×!Ö><׉ÀÄ’•Æ,‡gˇ¢(;€€–±qt‚øáJðèb½x^«O ADo—Õ§8l¶õ}iª,tѦì08û!B:eÓR×;d[ô<«ÐX[»`Óc–¸r³Š0DÓ¾ �Pp‰ -j':kMc~µ†ŽJ<‰Ê8Dé7¾À{e®­�¨½ŠS(BoP·/ðZÏRŒ‹¦6*ŠÚw�Â&óP™“çÂbǶeÂqËNš§‚ÜÌ™j¨ú¤]a3€Q!ª«kÑZŠ+¹w{ jÆœ-6Ü4×vkI¬Âf›�É!ÀÈ‚‚²éªBð1×’tmmàrE»T Y…&º¶ªM*XVÛ~Å£ÎU¡æpß -w¶PDzëá -epʧ½€phù¨ï‚¶sp�áA…A1]8*áWbÐ\¨Å7Oƒç¾J$rCµGŒA|­ -Z+rÑ�B¼U˜;Põ~âÊÛ‚sÙt “nàæmÎâr¤s-õá1äÍ>äÓ4 ]HÕn“ø/úz…µ -Æk\™ù­^biÆîbÞ£|](ätž ˜;¡‘ÍÈkäì× ÄnTC °sa+ -Ä¥"vÀy�)ï8æ:͵a�Ä̳<ýDI¡ñ8s9·2—ŸQ‡V¥Ñ±’�tå7¤4@û‹È5»¦0M‡9Ì`7à Å¡9tC}i›Ïdô~ÚÿMR–ÈM±WµW>ì†ï©çRK€É3—þ¦{$â5¨2�©ÌwéµNR4ÖgP_ã.Uœ‚ü 2 ótu_µ´•{r00–{ƒ¢˜!ùe‘¥eþp² +/Length 2171>> stream +xœÍZY«\7~ï_qž¢[R•60†^ÃÒ*êÃôñÓéËIk«œ±“öv2Æ‚ +aB£�r1šéëO§ÿ6ývúrB¥�ÍôÊ;Þù]¤ •±‰ž¢¦öß?¿Ÿ†'_9½|púå÷ÓËå×Ïÿûá�Ïß~šÞ½{ùáú÷ÛÓû÷—Ûõdì„èíä\œœKBü|‚I‘4©LW|*4)Ñä}VìJyCúËk3ûû×ÓË?>ÿö¯o_ÿøøm–@W .¯§—Mš¦×ŸOº¨QO&Ôà¦×O§wˆ6X @wë´~?½þçtÝb`Ž�© Œ @W €32ŠÒIazý÷ô®,³i¹­Ë“L¾>×e«½Øs#É{Òwæ^÷3;Wß?Ê÷ü,�1öý~tY,­²!šKˆÊÂôÞ®(-LÏ.åûÄ43¼Õ× ¦îZi¹&pæSMŸóá5@Öø”uéy–Ó6%‘m<æóø*›© +¾V%‡¦ü^fÆŽå±å•M�½Q芎´‘Öek°Vô±ô½iœì°^heÔí`´J{Bƒ�Ùaˆ ÏÙ\Þóžª�,”ïq<ì¶!ÔYøÒ}ð‡?cÖÀƒ„‡�Ò&dà“«æX1›‘iÍ^›ö\êÚÀѨÒ^ $&>¶hcí�·› 4BzeK< ×gäŸx%:%2xmÒß’ÿ±… „j¡„dùd—êH[Îrg7-ÒµÇkkÓÒV|¾ÔS1¯su®£Ü‚2·X³zRŠb.þZ¸±žóéÍs’mó© ʃW€V['ܳ|¡�œóÑ·|ëy¾8Ôf”#c}X&´»pTϹ]Ô¤»Åp=Ðf^fåøý³ÉV”e9<Øv¬ ;} …·{ͽ¤LÊqú˜gDLcO£!°G¹·yåŒÍs£Ãô³õCKÛŒ +=–çDƒ-ÍK9gÙVQUÎ)±¢�ÄÆ Ês Çž�Z³I‹º½ò>šèb¯îšfUy¡škÍe²Rq}ëëA)•M0¸zqï!í\­òÙ3·n²Jsmå{L·ðn* �lÎ¥öÈk•ÆcÐßcHצÇlÊ»HÙ\gñ~N–O˜‘Óí¹·Dž_×LÖ†iÚÌëÏU[¢œ‹lj´Ç"ØE­…°,‚¹*§f^YÁtÅ(ç´(æZ’.Ö.W´K•XTd¢ a«ÑV4€û�:W…šÃ}+ÜÙBË®‡+”Á)4N{áÐòQßm)æàà +ƒbº4pT¯Ġ¹PŠožÏ}•HÖm Õmh0ñµ*h­È] Gv +ñVaî@Õûqˆ+o ÎmdÓ5Lºi€›·9‹Ë‘εԇÇ�7û�OÓ$r!U»Mâ¿èëVÔ*¯ieæ·z‰u¤ÜÅ<£|](ätž ˜;¡‘ÍÈkäì›Ö ÄnTc`çÂVˆKEì€5ò SÞqÌuškÃ9ˆ™gyú‰’BÓqær·2—ŸQG¨ÒèØ ÉGºòR�ŠýEäšÝS˜¶‡9Ì`7£ Å¡9tC}‰Íg2zž9«¯ëì•ýmånaìñW'@GsŠÍkMâGçzÞËÊ}™¸‹ãF×òùM ¤Z¬“twïHŽ½Âƒ‘·<1e¯—Ís¡íÛ|‹cD�ZhëÌòê�ã8÷Þyóõ-9`íá¨n?/òõfU¨á/–ö§�…¦h£1½ú£ÕØ =­#åó %H¸U4+ã6ì?×ûko”§ä{=H¼ºÿ‡�>�}ÃMDÓø‘ÎÂ>¤0²'ê2£Â|×â߀™wðàP�äýŸ„Ã~k¢É)�efØŽÖ_Á~8}8}É?/2õ÷OhÁ¥×íŸL¥w?íÿ&)K䦨«Ú+Ÿ vÃ÷Ôs)M%Àä™KÓ=ñT„ÎTæ;„ôZ')šê3¨¯—]ªœ"È?!Ó0�W÷%Á¨™ŒÄž ŒÄåÆÞ b:„dGu¾€è LCSý¢šë\¦1 endstream endobj 87 0 obj @@ -857,14 +852,16 @@ endstream endobj 88 0 obj <> stream -xœåZY«ÝT~ϯȳÐ}׸¸`…ê}¶Ö¢Ø–ÖöÿKö�ìäd:µ -járÎI²×ð­y¥†8Ä-´Ð>1ÕO/h†àÛ—oš÷ ¢KÚ¢Ó–HÁ€xß2¡56j?¼j~øª}Û¼oÉ$M$•ã/té*r¾ýòMñ™ïžµéˇ×ÍÝ3n_ÿÑÜ]~}ýéëöþþîùñëS íÓ§‡Ó±¹ûÑ»öô®yѼo¸g’d Ÿ 9€UòççÇæîÛwo¿ÿøáÓË�=Ì\�ÍÝÅC‹Ò>þÒ`V¤%hEÛÇ7Í= €hþ;È@€zEyÀ0�TŸ¶�¿5žŒpè¨>þÜÞˆOÔÆP�gF?q@èt‹ì$]SJ¬:6 -™’ËlØÐ1Ÿ-œ²xRTð‘óùq ª�QšF)ÃYBŸ¤°…£K×2Öêàt#5»ñ°�CþíÆéàŽé~¦V­cb¯�G Æ;„ 3Ð w߉6á™Å#<¨8…NÔšŠŒYd—¬ªœþŠ`rΟžs¦#‰¾„ -®šÞ9óžQ6z�ì3:¯ùü¢×Ì?ßëã'r̘­ðÖ)ÏCöl?~ÉË»?輺Ð.ÑPщrH¾ÖÉŸññ8ÈŸ]cÙв�lw-Yú@ÎÎc¯QÙëýg¦€‡Nv¬è~†e1ºd¨�À%NÌÆvù›Fœ7`Ñuÿg3qMo<šqÿæ“#ãăŒD‰ Îªjÿ¾¨€Ü€Â®{ˆxgtF�”ذs�‚û gˆzmÙ²ñÈâÜm6v«6Ö †°'´×Ú¬Û -N1ú²UºlÕqYÚ‘xÖ3�’Aï´æñÿ)PˆëeƒIÉkç¿[¢�6<ƒ™8Ê¿¢Báznɱ“ØU¢PÆ„ ¯×–AµJ ¹‚t&µe(¼ é,º„VnrÞ1}á´Û²†»Ô -þZªà{©Ò¸i<‰ˆ³=²Yy6*>( q…²p"û—ñ‚]±/7øoÃlyHêó ²Ö¤²ÇXÄ‚Hì]˜3yïhp…<¼!Pð;îdD½Q Öú�Kö¨[äZ$•¿UóÌÖÚ¤Ÿw¤šyÊ|Ü…v½#€…¹g-̪(9O�‡�N¥9úà¸ìfëSDífZR"Ú½n&;ܬ'Ë¥š$²Ô]ëêÉ«dUé#‡¬No²KÒÕ^{¤îúî¶V×…¢®Û«îFq�êöd)¿›b¼)G̰Ý,g -دÏêù³¬†ªÐ�*9—äÞ¿£¸TUn©Ä—ÕS�ï#=U.Z«œŸ†Ã¥¢¬äÉíFtñÂóœí?iSbÈU­Œ=-Ëh5qØÁ¸r£q¸Eëí(jQÆÃp­È„çÍU™Bß”uµ;yy¦XÐtƒï”2;•4"Q’ˆVKÊ"¹-óìò²µ§9]&ŽÖyuxO#y¢ÏŽvbØa¼ˆoÃ; H<Ò–l÷9¼“Ÿ¾+ï¾m½ �–°m‚�IÙ�Ê¢¡4wš›‹œ™sJÄ!/ì**±nsþ É¡b»’÷\ñ3¬Reo Äÿ¢€Ðïfüú‘€œG®ÏÄÕÕÉná¬7:%j~QäÚ2%@ùì +/Length 2767>> stream +xœå[Ûn$·}Ÿ¯èç¦êÂ"‹Àbi$âN$ÏÙØ›Y»±ÿ?`7/ÕÍžžÑú$ HSݬ*žª:¼Ž#NóÏL_8óQ=º„)éôîÃéã Q\ ™0ÊD$àÀ«NL\H‰¦Oßœþò»é»ÓÇ!©C’E%¢ðü ã"E.�ß}8ÁüΟ¾œ–>½?Ý}ÉÓûÿœîžÿùþÇOßLoÞÜ}uþýãÓÛ·�çÓÝ_5N�ߟ¾>}¸¬¾§b{§³sÖh�Ϫ½”ö³fÿýÖÝø±¶j[¶6Jfëú}xX²<ÿBÎꪻVƒÑ3ûá‹,û_ðQìþ—Ô¸h�B–-‘>Ð3—ä›k‡DvžRPýL +È8Ìà”Äš“BwLÖ û’6 âb‰Ù…Ìß´²$x9ÎŽ3hZðh'axý™˜"¹èüš jå¨Jøåª¢yŠpœ!^£“ –”ØqŒ‰RüŒd˜ûu=È��"û_ãxcIâHqå¹$¯èÕëƒIùÕ“g£ôþuаK‰1ü Jº: „$¿µ%\PJ»üÞLò¾Û­mg;p vÝGÓ¬× 85è—£1–¨®‡¥ˆá˜y„jkã·3@!THn!¯Îÿï…t%S0¹M¢üOŒPx< �›¸iˆB¿VL8n¨ AC eÉ! uQøÜélN 1iò4¬¾þð·w?ê<Ëëäc'Ó‡“�n^£‡E¤Œ¹ƒ.q™_C‡>ËRH´È¼™ÞåÖAI).Òæÿœ¡Îo’^db ²È(İ´fö‹P ›YIÒòbPÂ,ó"ð"ËnäÆav ã"M&/³ÿŠ(%ɲYç&â0¨�«çÞ©OѨñNõ�õjœI5Rßr(×d¤”(é OÊŠR�A»•²wÿ¿.ªZÎò`Éc‡QP¢ó€!àuP.yUfµÉN1_ejy¾Ë¡¢_'¢É˜�j‚8Ú#㇠>…ó¥@½ºþ\z‘‚—”niñTŒ#GàDûaRƒ�‹ñ»-yXñ•ÑHØUqE=& ö«@¢¿Üh òûa͇W{·RAn@ð«ðYU?±V^]‰Ò›†ë7=RàJô�}!:/JË5¯¶-§ŸóÚãúžåîíyÍ‘ÜÜ¢è”�,)Õsºåt‰HeÈáޝÑLyÐ2çóõ¶B¬(¸âƒåÃõU‡v®ÍYÁóxþÚ®Ih?žÞîóÏ1×ÇÚíúF2; b®eàê,�óžºm‘�îy'µ|–íº¬jlîÉàãå¥ÇñvlžÜÅù.�@ÛUA_Ï„¯¥G:®‘Vm[’›‡Ns'‚ëL§Þò­±²/v‘�wŒlÛ¯{_»+‹7t±¯'CÔSb?¦ýX·¬N¢`’Ÿ±nùxŒ¼‡I½B²{³Ã\:«™+÷Kæ6~37G®]Pk7K¼¹]Ro"åÒ¶·±à “£2¿7Uò´¹Òqßõ´*-ÕçËiv|_æY›ÿÏ{7¥™¿!Íú²¢Ž&‹Zš×ÑÞqñ}=Q*‡òþüò�ƒ’’4Ü ^u÷ø–¬é.B=øÅxkw¯ ®¹»]-•o0ÞÊ_Ïß±ÈÊÈ+:’‰BþÛ¿é±ýFþïÚ×.fwÔVÎrt ÔŽµÊ@&…Hg'›s»J"‚SÏÑh™9ŠËß´t}¦ær{jþûp¨•58ó7_Ú•=n“oƒªÚ6ó‚•ld/´Í»ÄqmΗÙ-sô`FÈò „ë¿*¢ê endstream endobj 90 0 obj @@ -893,20 +890,39 @@ endstream endobj 91 0 obj <> stream -xœÝ[ÛŽ7}ﯨç¬!)Š’ÃÀtÏt° àì»ïNbd7ŽaÇþÿ…T’Š¥ºõ,ì…““™®Ö�‡ÔáU1dcþg€†F} Œ&bŒaxóîôá„èŒ�л�È�a°„b$F>þ|úç߆ßONÖ ¹<ÞøWíù]Ä`¼KŽa˜þóãwC÷äãÛÓÝwÁoÿ8Ý�{ÿæ?¯?¿ÿôóðòåÝ÷—¿? 0¼zu~¸œÈ NœDâ ’VñË Ã>ð`ò¸êÓ8&§1k?×z½>}8Rh«ᢘà“ÉãCï1~óî¹E=ý›Îk}üþrº»þúöóÇi­XÖz÷¯ÃÃû<ÓM íÏòÃûßÿñéãç7ŸÚDT&:?�î®äáé—ŽÖà@08+vxzwz @ À®ü\ø -ÀÀ‡|€`è€G©m¯ã3'.õs¯†§Ÿ�ÄPð)†ž~^–žÀ�c‹hØ;D5È_<>mfµaŽÖ ch†…Ñ lDŘ¼X« —¬±l½k«IÆ€nW>ÓØž½ñNËwT~FˆŒXëƒÀ«qš!7´l€)Ê©Ô(cz©ØŽÓ¢¡Aì¼1 Ç9^޹÷P|åËà®îʲ•·Y�œÚð¹šV>wßk§¤Gk/ú¨9³yŠÌüìQc¿ó¢<¸Žså qs»ëxéÙÚç#\Z?§žÛmÌŽsÁ™=ø¹WÝh\þÛkCª·wÜ)RÜ™b=/O„AÁS—ÇÓrgðá<ZQ+{Pûå^µUÐ#*¸Öa @Æ2{{# eáÕÿP~¼òS1¼�½¯GΥϥðݹ[Sh±ïÂêŽt#Ϧ•qYi6¾ “WaËߊ·á¢\[x{¶Š‚ }˜":Ï3£GåÚ.WÕç^»ù€ŠÜ!9jTÔQ�‹“«5 Š9\Ò–æüæ’ÇÉmSRãÉ*ru5†\‰½ d\yS¦Ô9QñD�1?÷ìn<Áÿ7ÆÛ¼rÇŽ¥i�1Õï$X7%¼ÈVÆ ¦  ‚%ø¸AÃÀ_:Þqûp×4”vm†AÑK^+ÈE¹è:ºµn*íW)«ôë×Úx³n¾•�B�úªk«î“ÐèÔBÇ‹ýfhĬZñ<‚˜óx¸Á·R9*÷Б×ñBã!½u¿vVŸEê´Cè`ñ¶p›Q¨¬Ýxí2Ž -§M÷‹ÚíE5í1JÏÑü\OE¨žº‘_™\Žå¸Ø:ë<²Ö•Ÿ­¾FJ0ÂLFwÑÒg&zl½=˜Àh~¹L^ÈHŽËŠ Ñ:ç¾ A?i Ûü5jEkPÖEÏ3+g�Ç”7ROú¯e/TJ¢¹ -^‰Œ·ÄD‹‘éZF¾Ä�ß�NñãQÅOÅÚÝWœI‚öØäÞƒ©Ã®‰hbȇAµ€v^“öqžÚ×é´ô©Àê }î„[ é{®2'‡‡Óá±å°§;^#VÖ‘v—Ú'(uIÅØ¢iªÂìwr^Øn­ÄË�&Îñëñ>-�®sm»¹ÊîT9Ë�JtÌ�ÛT ­òK¶xKáë8Õ.¹N9±¶=ÓúI¥Ÿkí49[³z^d‚�Áˆõ~Nf8—C·*…/ó6Ïr²­ù¯É’^5°êWÃôªNÄò¼|•<íÑÕìŠnYF«%°‚ÖÞnv˜Û­kG -´Þ¤®>LüÃhM,ôGƒ�ºw|�t”ø;�"s«š¾%�ÇŽÅØ„6„EV÷®ú]Qô�˜ÙO9©Ìf�ãLYb³Œ¨²áÀ(Èí ‹ÞÄhQT*scEC ª�X -$Ë/j­Ï õ`#)®s«qì‰Q%µK±# -»uµ¯Ìá"z�ë·'er' =¶=ƒp¬´|¬‡f{ßÕ«º ;g®-†yNµ7€‰®SªÖKh"QpK± '&:ÂkÁÖÐ\Ë‹%Ævf8¨�»`lªÓ«yÒa"§°BÞZHi3‘†}� Z V¶€\+š/§åŽb¦cì‘ùv`猓¹ù:Âf„©�¸£ÄpÑ C+~)1P%ÁzØ« ¿NI<'}ž¦�«å™ë$3¤; ¶ïzN-ÏëVªãUÿmeŠ–YìJ!o¨ÚçkTõ�þÏô¸ÈT+Z}.äR_�Ó•à‡©}“Cµ_ -(#J9\¯jŽFXG!Êû;”!)A:¡ù îQUÿ8æ”ý¢ªØh(à“V´h‘vC|ú¨Š³øÀi—õ>ÍqVè-¾:ó«Zʱ£ 7Œ�TR*‘ç<+9Á&7¥‘�ÍgseùŸ –nuB=CÕz•±áqÒõ¶fxJºE�µIªÎI× N ¹£s?úýhÅT?‘4ê‡êñFŠ·4Òä¶FÄ÷Õ›™ÚþÂâ‰ÙD‰žüóäÓ±\êý -"êªeµt½µÑ}I¶\­´jšº*Igóêò\ÀÖ“Ôô˹U%Ÿ5=Ò® «ÜÐgi}e ;)ÝnÔyU©¯aÒÙÊ-M߯Ý÷Ü¿ãÅ@•–W.Ww_„@UáeÕ¹z¶U¡KÈ -ï‰eEñŸ§ÊòV,LÜuÁ-l0½‹£ x& èñ·R0ï†Ñ8:ŒÀ]q÷ˆËhÿœÃ©M3£é‘è�ˆ6è±éæùõµxCìýšž"ûݾ&Æwdç3è”MÎófS:8%§·ªþÄlºxái‡­Önªšm¡³qËçš«¾3_oá³CV­”àjJlO_™ôN8ˆ`ÒÝ„Zà_�óÞ ‘`ò FY}LzÇ7”‚$[špˬr:O±ý ÉÁUA²A§MlÔzñE¿>ÕªÛœÃ}q‹Y¯M2¥jë H´ú ÃÓWšBô²êŽ•ZPŸØ¬]¥©+ªñ.¢Ý;F°vy¥{˜Zºê;?PhY•j_å†ÌGV•éRÆr:2(¤ÔåÓx‰t©w¡9R審7ÜnŽmÆS&Š!PX¸}ºÃ1Xx³©/öpc¿øÉøÅº�ÑP´‘õ›ÂåòÀ¦÷¸Û0ê}V¯#é²ç¤=^ç·Â“Ó‰rƒu é÷ö‹õ鯣·ÄsXÉgAe½ñ™S©½ÄSkª<^öe|ü,UöƒxLïX¤|ÔFA€¶üŽcæC.Ï üŽ»£Ú òÿg€Ð.àºD4àZÝ''^ÒIw£o0.&#ô|yÉÚ3ÿ5?%€ +/Length 2393>> stream +xœÝZÛŽ¹ }ﯨç–IŠÔ0 ôôL/ò°6 ywv�\¼†ûÿ©$¥®KO²vcÃîî*](’:<¤dÈÆüg‚ ¦WFý Œ&bŒaz÷áôé„(Æ‘Lèe"0À!L–Ð#MŸ<ýùwÓϧO'k�$�7«=_¡D ÆKÐp Óòß¿›†'ŸßŸ^ìôþ_§×ÿüøî?|ýøåÇéÍ›×ß_~ÿ8ÁôöíÃãåD2‰G;9'ç’?�`2ìO&�«~Ícr³öÕ+ýÍÒßÜ6OÿôýåôúþÓ—Ï_ß}i`‘àáùôúÊòôüÓ g=âD0 :7=8½ àÀ°Ä’žENïËïô.µÀ×òø¼¼ÏcaiëÊó j®üì\Ú<.ÏÙðƒêï—9³lW5þEÉóXd>«9Ÿ„æu¥zœÚ>µu—yž,ǵ—#ÏYäLkHms›ky&óm-�¦ ¥·4G]‡ÖM–ñayVe§·ÓóßOOÏ{ ¡XPbY¥”«6«æªUW$Íš8 dî“Ǩ’ûEƒù™/m]¯!½²6f}Vå�å3µ±®ü®óÉ2G·­5e‰P~§öˆUc?œ>�)´�þJ¢3Á'x˜F™7ÿ»ëú·÷_?/ûšÊ®zý—ÓãÇ<Ó]€òÒíkõö °f}&¬û—Ë•â·×ÙŠ�áã±WÉšDr†‚GHxûü×éMé™l6{'FÃ^$8Õ aca¬&´º0צͮÌ]]¦-p'XcÙziÒHqåÖ®ü¦¹={ã).âgŸ£¦"ã¬õA)À+‰²£æ†– 0E×k*ïç¤ÓKÕí<- +œíÃ�æäѨ*nÜÿ²ìÿ=DjhÄ‹òÆ÷Ú(ë +¾é£æÌT#?{Òº_Só–F¾]ç¹²“ 8SÇkˆ;ü¾©W"¥�ÙpÄÄèÁ÷V•yq5Œ- 9†w!®ð^áÑ)¥ž  Ñy1M“è¼lø&Ù£Ú/gÕV©Q©k] ÈXfoïTÃz”n¾ç—…�¾÷ÍüÈ@eš�h™BÈ}rDZ®%úIóâ‹v²¶|W¸ —>'ì¤(´�‹Gçy:xT¦}TîrU}4wÁ(rÇP Ô¨Š&š¨|oaKc~3ÉÓb¶™JÌ!)8ãÉ*p¿p‹ì{š¹ÁÊ»"¥Ž‰ +'CÖ–Ýõ'øßúx›×û±n\cµÆ‹ V–€—9ѹL|ƒRܪŸ6`8øË€;²¯î†Ò®­T³ÁwINšÊ�2ѵ�þbbm©�¥é­’µáfÝ|+.…:ôUÓVÞ&ic` .Ž›a“§�J|˜•˜ãx¸Ã¶T1Jç!�e™ómŽøM£zç©Ë¡ €ÅûÜ­ƒP;X›ñ:DåN›æwj·Ö´‡(#FóK-Å5ß»_‘ÜÓqײÌÞ³Ö™Ÿ š}Í� `BG£Ï·U™è©õö`C >¹,VÈšœ7–u&D+"¿B¿p Ûì5sEk ['IÜ5f2ÖEdì×ì9AOúŽ×²*$QÏ‚WF"ã-1ÑÍȩ’G¾øOØ÷†Iãì0Èå”χÝQmp†!_fG¨X„q¿ODÔî«>ÙaI;ëFß`bZ„žŽK×ZÏ@‹”Å\ÿ¤9Ðe endstream endobj 93 0 obj +<> stream +xœÝ\]�,¹m}ï_ÑϬ+‰¤$‹fzfâŽ/à÷\Ç6‚¬ƒÝ8ÿ?Ð7õQU=ûe¸ØiU•D‘Ô!u¨*e�Ów}×÷ß(ñ3 Ql˜ÃýÛ�·ŸnÆ�r–îÆÓÝZÒJcw°Æ)Çlï?ÿÇíÿtÿëí§(c)õ—ÿªOþư¯(ö§ÓõûážÿøùÏ·/?ÀýÏÿsûò¯ÿý×ßÿíçÿýö·ûwß}ùíãŸßîúþý÷¯o�Ûë×Û—²wƒ÷¯º™,±¹[}w†Ýýë�·ï´†­ñ¡5­5h�ôýýëÞ (mØ»¾ýãý;­µ¦ î‹Ï8­ñµü¹�L¿Ç¾”vÖÚÅû?Ê¿ 59­ÉkMy<ƒ¨Ø±·¾�Êïék[È7ÄaH—¡ý^¢:µqèt�.ÿ|¼BÁ�bÄžÒ„Þ‹" Ý�¤´c7jé­‹ã¤X˜g‡�¿ŠF¹ü¢ê×ÜVµc­b 0Î]šÍ~”Áâœ_„™|ŸsÔåµVÚ8§{�I#ÅÈmh å�Ñ`¿Ñ¦ A:çYhŠ‹Lu’�tãû×Ûûo;G5׎jÁÿŠõMk*ÓˆÝV±¤‹å{RGl•ålX¬^}±Úh1f›¤+ˆæåâûä›bÕó¤ +ËÀHÂ]ÒRÀ@„ÓzÑEFÌ«®­8,Ý{­­½ðû„wø_“wLvIî6pFYp ¼�8]ð +Éox Y3ê¸ €0÷ìAƒð³a«—_伯¥ ÷ÿXï¥2|ñGŽqÖ²›”Q¬ÊZOÀ¦ëPΤøOZ£oˆ^Þ¿žº$sqIûªµôÇ/®Pÿz>ý.^WE†.ÁqVl¼?˜Å­Mˆù˜1Ð�ý"æê»ï4·¹S© `­-÷¨ ƒ¨ÖÉ¡‡E'oå]&PŠ×/ƒ!JëãÝšÕø‹ñMÀT³áAÐàÍhy*3¶ÙšQm©Íw•Ž®} �Òm\msÍŠK.&º—>%QñÏ÷r� �À¶šA%û‰,êpa‡É׋Lä§¾ë ‘UG}²ŠçÌÛ Åù÷ÿjús§úCRäCÌýRÍÌ V#_ØÆŸöí´ì´äNqˆ±Ä¬é_YÍVþpNáé9ùPçDOΉ¯çÔ:µ¡‹ŸÍv(²ÑÏÊLZ/‹í*�5—B÷^ŸZ$ˆD>êð_~ ¸ó['W3¦Stÿñ¼JT››ºÇ6päR›W™c[Ð츴!9sÿŸvÁ ¹Õ;kã�¤­ éΠ4ä6ë¼wœÛ¬óåi r+is.v ¹Éãb’óº´Íéa§ i´&·2¸{ $˜™)6EcŽO�2. ®£ +ÈäPô‚Šl•¿‡1½*zª‚�bç¢�”kÁŒ…샑Æ›¬‘¨9ãc›a UÃäò£1MÊV[Ø�Í ÚôÛmºn\¸Ý� +œŽ¡¥<\‹RFy—ÒÇhNaœ&*YÁR2÷Ao¨À85ŒÊæ¬án +Œâ&óu“a³&fk6cã}ð†ú°ô›>Œô°*�tÄ*¸tÙ>EéÜUrT�ÉåÒµ+Vµ‚_�º-ÿrû}¥rŽ`NaÅèˆ+ÖV\¹H¢RÌ“9ß‹„™KˆA 1ˆ� h7@ ptktÜ€Ð.pY( +¨ã‚òƒ½PÇ¿Ý1¨ã¥cPÇÞÍà+¨wƒzƘØ"0Í„1íºpìÚ‹Xb8±Vš`bMµ ˆÕ'¦Ú—iÓ‰XÍIwxʪO:vf™f »±T«Ž !Κ”gmäx>Nzð È€[AÜdÀ­ np;�·‚L¶0å¿�7€L{X8ŽF¸XH¸b\8­˜¢pï¦ ¹ ü +2I¹ È4#ø�±B7æ(sžág”A¹±¾ì‚¬Ö6¢Ç[A›÷žMï¶yð&2ò�Ü[ºKr…œ^PÈéhV3 �3k¢ãÌ.ÑqfMtœ]QÈÙ +9Ÿ@ÈÙ„œUA7��³39;€�ƒ „Úuáøµ±BÒpì&Ê‚�‰N•_,N1Ñ¾Š›FÄbošk˜ 4,°£ÙÂnlÕ¦#9½$:Äs¢C¼Ktˆ ¢°b…QX1ˆÂŠA"8ЄA”X°‚â¨Ù˜FŠW„3ägGÊ£ÌÔä~Øä+f(|»éB¬�¦2±Z„rźjFð«­B7åt¾�ÍäÜ„@ QlÉ_¨lzƒV„F7lzsäÊCuÓ/ÈÇJü4ò¨lú%I@…$@ {¦�’l«'¬–îB­J5£ŽC�­¼O•QV½èµôýDÊÜ¿H¯+4ç{üÈûDâ¶ìý¤n®zæs¶cú žäq.µ€… +cALÑ uýQ–/ªm£ *‹|`í†Cf�òo™øå(ÜU=ãœ{0ž•Ñ‘…—3ÞÚ�ÌoaÈ*@ë=,’!]Оœ=udñw|ý' KsV?SpZ©¸³*’,ÔßmµV¯7o¿÷b[S›ø„ˆµµô8¯,ïéf¦©¼Û¤zëk9I\~[kœ3>52tCÖCÑì@xVl©„ýdñÚÇ™•N‹G¥ë+<±çY²„Ó‚×ë’^õ|Q.D«,@F™Ã¢‡*òld…ê9T¸’ùbg�FyF‘“É^{Í!þN %h@pÚÕôîÜ5Z88»¶ …÷þ2-ƒÊ�ˆþô/›x},öœÔ±6æmc†'@!T–³›á´±ÿ®dIŠá q3Ž“L@àúµ¶€ýD?öZ4„“üU‹]v¹ Œ¹re¼\ØÞ„_^„Ø;â‘�Ÿ-Éü­µÉzöA¡g�vWêv×AÏúÔ*—à…šRºSªéAi�v®ñ×ÓAJ;B+Žâ”j8*ÖÎÒ¾öz@^g2Õ¬ÈYå*Š˜L­¯~&I´þ\mè�"N >ªMîL hkºq=Õó˜Ð)Ë. v›‹d.lÍzãÍcæO±ìœ\nJ»`Ì;,J·qÞ-cߋŶ²¯Æ²kó¹5í¿±ïî<®Ë>�r[©\`Ù1æÆXáÀ¼¯ å¾TÁ¾�m…ÎļW5>·Æs@)mCÆ•¶HM`ÚízJÏ”�ðp=ï—½‘ý”�5�#Æ=¸—‚•�zò÷½œgÛúw…†€¤â*“ ܇n +»1T“~»M×ãfxèÆç=³®Ñ{ƒX…Òcá å4±1‹RX8Ȧ4,D¥Ô-6JSZ ù)­…®]6d34&i¾Ðž^¯³Æì5Í¿²Dɳ«6©…»Šù Çnš�  *L.•®Z¹¨ª üj©Ð ù—ÛŸ�ëœïçb¹×SÝUØ)8 l�¬?›á å´ªgJŽûù�Õ þÃ!ÑñH‰Õ!: +Óº£üX_´�%�œÇ¼7ÚÆñƒÓ«ÛDoÚþ³žØëÐy˜lèÛÙ ;%Tœ5á¦sb'øFâ?ÛÿÙ®øÏ°â?ÃÿVüg\ñŸ±ºbå1æê“\ Œ™¹–K™qç,a!6 üOܨD”v] OíF@”¯"YKÀ]_£˜gGЦ´Mq �…‚p7SØ�É štĶÊ8OC`36»Àf ¬×ÀzXO€õXWÚz0ƒN´õ`-Ý ©'ü�—¤+èÿó0<áHx¡^ñ_LO:¶^ñ¿éK.³Ãÿf¿±Tè–< ö:pM +çÝÙœ¥î³ÓçÀa¿_!ðµïi«úºRÕ)È3pºÇ_è±ù°ì°ÆÍAÏ 4öA3Qùq*zH¹†ôÐŽ*þRâ®m$…ÉÁ'€ÇAòl£‰|BIt\Þ+íK³57ý Õ“‹°¶ ȵÈQ_£ÙÎûÉ@ÐÎkE²Õ?^¤„_¿�ŒÉ2cé÷“•$mÐr,ñìÎbËÜ­_TÉë1·â5WçJw)ÓŒ m\±~vgdë×µíñþŒµ\; yuš‡ø;¢ÛKù]�F¢Ìóš¹:3N¡FÞ‰Û™K;Ìýªg¼ ”Q%â�ç#�AÙ@&VêÇ#�õ3gûò çÇhõ©<åH¡užÂß™ˆ†‹Ã.F÷H#‰ÙñlGNGSü»Ö~vãóùƒÛàDÆÎ çŒ=6¥š"¹`0)’iHlCr4fì±uÎØl>B*R Ø¶06±qblbÓÌØÄ¶rÔDdi±uflR[ÏØ`ÌØûõž*ö~zR)G,¹g¬'¨MþžÉÊy¶”·+¤gÆYqÆ÷ :+˜Ü˜±'SL{7T“{lš¶<%ì±eMØcë”°³�Ç+rS›¦ ›„=¶ {l˜öض26±ufl؆jHÆŒ=]¾Ðž^#ÆþÕ$ê^ؤî*æ'»iB,€¦0±T„jÅ¢j&ð«¥B7äYÂ~ý¦DÜ|–$d +”Wo'=ÅEpÆ÷˜)É, †LZ0®½Él7 �ë¸ NÈxRð«ÏTÙ[Ñ®¤‰[©Vèk¯IÈtJNÔ¡¾h5 +®“¦¶Íš·:�Òê½_E‹¹Êã§´*s<‚–{âÌC*ðÕdÄ+K³öM�¬s*zEÛYÂÇ”ÒíÆç*†ò°ØlÌÅÆ% õ=}¬ÞUÊ{ç ZXŒÊù&,…é^z<ŽËAÆevK\f·0iÌ~aÒbÛʤÅÖ%.sXã2‡M\æ°0i±mfÒbÛ&0sX3‡!0gXPß®‹�ÐúÁCŒXcLL¢6²ÄL{lk*!°©®…J¡bR›1ìÆhP�:FfvùlóÐå3Ðb<*ѱh‰ÌŒ •Û6‘™qŠÌŒkdfÜPi±u¢Ò˜±§À/I_(K§é£H÷Â%.7™¥»â..7=È@k\fÚÅ妿±Sèv< Ì—¯ûÅlŽÕàqɤø”§bäF¥Á×#v±¬ããY ]ß>a'æ;Gßd˜¸š”H™MÈ}è= |”Y°Cb~æ‰÷2¸¯�íÞL± r9Æ¡ýžs§/Ÿ³‹CˆPµîÙ8ëö«€<>¡\/T…{³z†ëÙ yMOhðHƒùdWÿÏ0Hua¥4½þzš7ؾ�õ&Ž|ãZ°kaØwðÞ˜y 7dhƃrÆ~¦äQ>#g¬K†I<;= +$ñôÓ¯äì²Aœ^e˜‰žM={ˆ¿yéšøZ[Ì”åwñúË]•Œë9WÆå ´�‹µ—¦>?h�,¼|§¡noêG¢hL‡çZLMj:-·3É#…µZê%¿»ýîöSú:¥Å`”¥;�vñÿÇß·Œ�}Ò2j!ÍÔÝy<%íUþ:‹mtW+ßÊIÖOÌ�x£Ë›evø* ”ÿs>1œ¾¾SN§ÿ¿žö +ñ%ÍtÒÚmj¿/çϰQhMò™´£³²>yðldwü8˜ð¨Åb,йþW½I� +endstream +endobj +95 0 obj <œ-fÙJWÊd·…ùmQ©áµße›qyÆHºz©ur?‘™ÖÍÊÇfJpHêw…!{f$o¹üÉ&,®¥|NKH):ÍþŠ«Ý)Íg—á¶4ÆÅ;nçì;Ò;JÍ/å¡{FÉRßXCök -rÏÀœ¯þú�£ÊgûK~U¤{2öˆ\ÚÔ=ë×7£ÞøØ}’n iØ£<Œ¶hç¿V¿óÈó0òÀ^c:ƒì:¼ŒZÃaZCök Ç–È“�O:@>4öÿìH[ endstream endobj -94 0 obj +96 0 obj <> stream -xœÝ[K�$· ¾÷¯¨skIŠÔ0 ÌôÌ’IHÎÙØN‚؆7öÿô¦T]]½v|É‹éV•$Ф>>Û��ùßlŸõ50šˆ1†í÷—.ˆbɆ^6"Âf �q1Òöñ«Ë_~³}wùáb ’äõʧ6ó3Œh½‘´äçúr+>~sy÷¥Ý¾ùÏåݾÿîÏ?~üéÃ�Û矿ûýõ·/l_|ñür½<¿¿¼{Ú�·÷__°PŒÁæ0ºíý·—Ïì_8€`ùb{ÿ¯‹ (XÚ`{ÿ÷ísf ê½4Çðsýʘàx‡žêxpéý·ú?ˆ e?d6ÑEO~ìê¯ù B‰‚ÐôBÚF ní붯…Ôº´CCÖY -}¢ÄüÀD�qZ1 ˆ ±‰ÐôÝ%r¤¾SVöÖX+ÑŽ•ù©r -ËçLÞ €T.§Å×ôfå� œe¿pâªWeÐ9 Ý‹y›PéÇÛ\’º½ø¼XL -JÑ-̨ұ†È‹�8x¨ORõ‡}•ïu9eYåõý=•$ U%éÀ_Çt¢6ýõ÷×[ -�ç -Oÿ>¯Z×Hž¶–JÞÂØô~À�ZcH@†h‡°ŸÔYýÐ�®âTÕ¼°€bù Ï–¬Èêh+q\yòRç@=@%(=‡ë‰ôIKŸ7Â�ð-Ø*|L`#°Þ´`=Î’—zb*ÒLlËc~°tVíêìL:c“Ô ì©dìTæEƒ ÄÌÞuÊ ÉF8DQù`Øü€ F‡ÜØ—rí�µPA˜„ú€ƒ NÝø§&²fmsK!h…¨ªn ÆH1<ð„C]L8Æ.‚ŸL×áRòÄ{bl”—f�(•8fÊUüT8½¨K o2<þ"‘ÕÒ¶ ëÝxŸŸhr×#A}ò)øZOKŒ�Ìx­›£õ`#ÝSàö8”ßcÊc~¢4¢òlãº�èÈݾâùæzÅ*¾-Víù馅<È<âÇ$>½Ô/¼U'R:S>7ôÖwCÿR •«�ÕR6ǧ:IÍ­Fm5ðͬv½5I‰‡µ¿„ÑGeܳ1)OÉXŒ¢ævSÞˆ†-‹ší'sCh¼Vgí¶{Ð<Ùî(�0»On6—³åÀ!¥ÚTÙZ}€ÎªáWº`Äy;“z&iYÌæ^ÐLÐüE%nÞ�¨óûa¯»Ýœôê…ð“¦@®åTm _&‚÷·wR]%•ÃæXÀÈöí…½Éa¡+CÁ"niÌ:‘üäÓX€è"•1‡Û‡4Û -ä˨wDéMÂ�ß$–|#罓2FÎ×Ù`­å2(€»´F õ=Ð¥1çÁ–±Á¥¹Î £/£Ñº�%‘/èêPŒ’ÆòZ6Mƒ.$ŸC=g8&:–a#l©Ñ fZÙ�õš¬„UÎ^Vê­ñ–Èâ|Jk8ú€šÖXôXØÑØf ÆrÈÁ^›¬²`ݘmýpYž£ó²éu8šÀÕ~�0•í:Y Y ›¢žƒ‰® õcr0Þ"—É� G—YY˜ÆÁX”8ñ–ƒÁ¥ð¶ �sL¹iYqhbäPÄØÅœ)Eh“•ƨ]”nuz†vš•ªªÓ)¥î|PÊŸÙ•¶VפðUÊì~¡ -ÿó>{9…!Ç\¾>‚߸¸„9ÒÓ&®yŠ1Y‰^eüd’n¸YVÃ} ƒá. "FcÙzÑ”á‹B©ð0! ýZ,†T´}§ ,Ì¨ØæÃk5…®Œd‚Ck÷\˜_âÞX¬m¨ÌTz¯™ƒCªkQY¯­Ýɲ5Ó5­kZÞñ¼V7yo•�qÜ«ÛÒ²;idñ-‰‘ÃaR�äË ¬QÜNšE"廿ÎB<48¡Õ_v�®Y«¯”ì ½K* AÞƒtû¤5HSɦ«‚Œš˜ªÉ´;Ï÷C²)“™c…±k�â>C¢Ý÷–EјÒkíýÊx#�Öjb¢ÖÔ±H«v¡±nWŒõóË+Q?…›EºW°kV#—€žöñAÍ’D#ä¬_�à å…zM:•Ÿë�ÞÎ -aþ…Tvh²»¬žKÓ{™ w+\Êø†:ÿ€�Ÿf©4û_'ij4#žç%t·kunh4_UNQT•³*Y¿mTŸ=ÍyJí"õ›øTOª¸•Ní®#y½æoÛÍ®þyoÀ3ÑÞ_«‰RÑâxíD=Óë(ñæwOjwãVÞ½…jý~è·€,Ce;\,Ì;D†ÝͽÙ’¨S+EFšñáV¥¿£Ä›O\E˜?Ÿ\¬i�/ø£ë¦¢ûê]·š7³±6ªLþØUEÕšZZ1ýSÑ©Y�{�1ífç…š�kS›ÄI ;ëÛžëlÝjctCËz×qñÈmhàú Mj¬¤fXý¬õgMº^õ¬êW~¾a#ŸUÅæoß #0~8çö3òuRC -ˆ˜GBöÜô€.l]µyøãå‡ !…Þ‰÷KmÆóe�ÊÀ½f¼leÞþùÍO¿&¦Õ‡Þý5Úíåû¼×/jù;²eS;À-~lÕцRcßö­=݈Ô~¹ÕÅiÕLñHAõ†éZ'˜à%zçk�ÎHjwÓoÌÕΔå{×Pf GÆ�c•\¯H6,,.…Ú}zÞŠÏ„»ºú÷!œ¤ƒkþCec0LÁ#uÚqdd˜ùªDZ³ænRÕÒ8Ÿ�cž;˦|½‰VD½Ð;*ìò`ò•j'¥”åûƒ1iì½´yÖ³ZEÊØôýI}w un¡Ê7*ê÷P׫®¸vÃAÍë °µ¹}çÖ¹“Œ¥µyóø¶‡Þ»)�Þö“f¦Ìé¾ìªR˜ˆ€âf›{Vcœã}êa“nŒ?;Ñý`C0” ±:×C(p”ˆ¹•A¨ÍYVŒµ~rJ�pÔÏúiçÛ”¿·žç%#�t¹=?ѳìs§Î„ôk»Bª]¬¬+ð¨Ð¨‘¿/ÍÜu“”_ÕøöKû rø¢‹EMÚ8äu~ÁNœ3k“k˜ôQŸÀ) /ºu,Ý3JîûAœ<ϘR³Š�^3 ÖZdÔîùˆìÎÐOJ‹¢‘U�ÜfG!¦æŸÝ/Lð²÷ËŽBl¼7 @_³¬.ë5‚~É�7kà îxÿAD/ºUɵ‹rÒΑ¯›�‹^ärbTŸ¯÷I¥¥÷pÍÞÌ–·gKÿf¾Æ4œŠè\äZÞÌÞSMRGù¹ Ÿ·qõV¼¹IÈÿ®.zC¡èˆì ÀSBDQaMwOÚÖf*íaÞÂ�šMbo<…TâšÚa•‘&㲚ÛëãvY¾ùÛ«–ëaJÙÍ�;YPq‡u÷}™Ä9µWeÛP¥jÜü¨Þ6 �¬ø½6°–9êãÏ*JoLJa̺�éwyNo‚¤‚!íòm¿–ò»Õò�ß;ÈÐÏ?–é½&S„UcÎ1™TJ¦7¬/?$”Ê­¡b·´éHqæ+—Oº$uÚ|mÜÓ˜/Ê{ïù·çįEÞ·­SúOë'ký¥ïó€t«üD/L¼Lú�»342«ÄcJ¦ ‰’Í -¸ô÷ø÷ÁéÓY~0ŸÈmqöx¼)ñ -õ.ÅXÙSsYEf¥]ñ)¥—q²¯’cžîÕ*H «aÌãÝUmpòÏ¥±g„ðéþ”ˆ5« æŒ‚ÊÉÜP].½_&YKæ¿)â´ø +/Length 3674>> stream +xœÍ\Y�·~Ÿ_ÑÏL±Èªb ìÌîâN$ÏQlç°lرÿÀ³‹ìžî‘± íL7�b_]\çcþo±‹]>3ê« ˜1ÊòþÃåÇ v´@ Å9²Æ¢Èâ°áÝòÓ×—¿ünùþòãÅp”×+ŸÚÌÏœóÄÆQZÐ`”eýçO_,Ó“Ÿ¾½¼ùBüòí.o®ßýðþß_ýòÃÏ_/oß¾ùòöûçÅ.Ÿ~}¾]-bC\˜ÓßDÅ7» ‚‹ÉëªoeMLk¶y¤f¥?yBú“Çæí_¾¼]Þüáoßõ½¡î�²笡åÃɌãòH¼å%=óL”‡�Œ˜ž‰�]y†D¼¼O³Yœ¸Pž†�F’u y¤3Ö;—ž9�©‘ ÊMv—ÕÓÊÒ4.³!ÇØœuwzõgw¼RçßaçG¥W^éJømR¿ÉÉn�ì¡Õ¸$ê×ìþw4›µ0çu“”¬[›«ïžT¸Æð¨[âS=©âV:5×�)i¾Ž–Ø,»Æj.c:·�Õ¨.¢ÅñÒ‰ººš9g–ú-‹µÛ±ÊC+Të÷C¿®ø‡´ªl‡‹‰yw‘ac¹ÇÆ–E:0ºöŠ'}Œo>qaþ|bXÃ:ø£ëÚë6²®˜å�÷Qðã1«Š*÷”,¬>ûHtj¤å¤Âú®"Õ²ÖRˆ½5µy@œ±ag]¼»®ÒÍ>¦eÏ`d?Cyȸ>è“+]s¬aÔú3€v¢"ˆë +!^hµÒWWõ~² {`üp­íêtÙq¼6:ÎEŒ°bÏ]�UÊ•iu_]~¼8pÒ›TŸ!Õ>U(ÁE›Vï?œ4…^ÿùí/?­=)h�¡7�´<ÿ�÷z¨v¼ÍŽ3*×b÷F›M4OCÊk…1~ë^¤ÀF˜cœRõu†8‰°¾Íb-o­‘@10¯o»2—lˆ=#ºŠ—ÑxÙÆ†4º8gØ2ªª:•ª:¤`=ø‘øm]Þ“¡€NosV—ã'–³oDe£tÀÎÇ)gMyÚ‘_R%‚•TÈ�V'»ñÆb‹aØ`(Ô犨PyEÆO/†°Q©ÆèSï±OëTJ­Üiî` +}:F«àqnDø'…}/k$Q×rf“T½ê6¢aCdx¾[›:C46xM‹Qs0×åÇÞX�0UïhgÖ�ÛêW\0oÀ[¡8˜M+%v%Ó턈Ùm<ï;LÔXÔ¶�´v¨¸Å&‚aëh Ö†xY‰0qxMÉ ªÏ7õ9)%MßLJƒ‹Zµ¯j*φïOê;OÔñDUhTÔïR׫±¸ŽÃ­š—-7‰ãZÙiWå>[ç  ò°µSƒ±|䇬=>`í}Ù5;¨Ja"X }îYs±GôÅ¢ ‘$*›Š­�M‡{÷î8›†TjÍŽX�ë!¸W‰Ù+!Ä +|d¼CPòhŠ£L<ë§­)¯9À\KºÜÞŸèÙûà<˜Òáÿi‹T›dY·ÞA¡�} _äܱ4)ݶ)Ê߉j|ûµ rþ¢;EMÚ°ÊëÔÀÜIpæ} + ‹>®'`%áI·îK÷Œ’ã8Säsmv%¤7̤ÀZK�š�¯©ÝÙæ'mE”hh$¶Œ™�ÄTèŸãÁâäζ>î9’C˜x€6³¬.³ÙnäÌœ8(oQþÚq«’k†rr�#™›Ø8éEî%FõùvLªÓ7^nÛBán¹¼½S™yþÎuZP‘’]Œœ{›9zªUêHŸZñy]MoÆ›]BþwMÑ… +ç)U‹¼ëªN¢d®w–HÚ×[T:ÂÜÃ�ZNÂ`R›Võ˾W9ig8;¡1±½­`\Ó.�Æ¢‹<ûÛ*òž¦”mÁìØ$Ù3ÖÇ2™s±—ºoÊ·�ªÕ¨2]æLíNõZ×�?ºÿÕJGýùUeéíøvufÝÏt[ë›–R»Ðmêm¿VóÛX_w§DŸ5hª³j-;kÌ9ÆDpª$ÓN˜õWê¨rkU±=mº§8£Éå“NUF]7ŸoìiÌ'½÷ú o9ñ[ÑŸ÷mëØú÷¬�27`ú>HÇ£ªOôÎÄëÝŽI· ë§n†FæS ;nçfÊÖ«@Ú¿´â:7°` �]ÒQY'[“I¦jI‹ŒZÚJ+*RT•VÍe;ÚÖ^Üí¸y:§lrn<·z +Þí\¹=niåtÃ_«{¼õžÂວkó´ÊkÀy®žíZÝïU™Ø5¥ƒRõXWx@={/f÷=–¶jD«÷–:ý±³Äùt¤Â©ÉØö.oõêMîÔ:JyÏ/C¬.£¥aC%FÇ� +a¹ªƒðÑ*4/¸§Ûy£�ùô´&b¥Ôs*f±ýÀ|ÿ­Å”‡JZ/©³qΦÛ6÷Ž»‘óTÕ:Ó^íH2\ªcöÒŽþm.6§x«€Ø©â >`;?»ÞžÆ—b‰TMff×+²VûZ”µÖ�•!.œ¼åìGr`^‹6ÖZqÛŒŒcK„êÙHªçÓÿG„ªà·Ç•¥íà [IƒÑϔծz^DŸSÈÖ)o…V7Fn; ƒK·‚�¾%Ñ )¯uåÛ™�Ôp0)PÔ +Ô«§ÆhÇ¢E¶Ê÷lïã‚MË 0EAïðMw|7!Ô|÷åý!Å%¨½_FÔéóvêèÖoÍ�t�®ƒ¶ë6à§“;Í;® +{O…vÔ�fH8ú¤½BgJ»£ž´Åì!¸™Š +2 +>ªº!LyUIo}E÷úÊÌæí¥OgUêYh�!qÖo ¨Š³Z~D“ÿ)¦Ç< .ßj =xÔÑ­¨È *úÕ©cãAȲcƒèÔóZ�HõuBô#ÚÃh‘tç’|–i\YÜtî3ç_NcãÓ!¬l\'HÿÝ®ÍKqˆéúp#¹n—û–‘ì +Å@wfÔ(¦û­À°æ­égbLwˆU”W$�c´,ª~w^´ +‘¬�ú]훇 <Ç­ž#2Rº=¼Ê¤îA‚v¨÷7—º9±e–ÍŒÑày8“~ɳuZϘ£óÃå‚f<;‡6›íü䟃§ù7Oh 9Ã)¤½Óúv.�W àñ¶…¨<æ6V¹4D5Ètn½;”nô$Ž:Hww<Ù|‡çþo¿§Og7|²Ìx‰cÏ"˜Òqtý [Œ\odh=ͼHH—rr$ÐWÉ]ËÖ°­ss·–¶óÏëáª^Ø Íÿ7°½z2'‚A—ÊjŽí—"Oæ¦[,aÜ+xк ë‹*®ÿæA@ endstream endobj -96 0 obj +98 0 obj <ýtüþûïÿã… O?ó샞R%øÿ–q endstream endobj -97 0 obj +99 0 obj <�ö�\Ùðc^ßùìÎß�\ÙhóÞÑ£ÇZZnËùøñ“>¾víú—_ÞÞÙÁÎ6½ËÎÎîíÛw®]»~á£áãÇOúBnkùµ£ÇÞ|ëíwNœúÃé³çÎUÏŸŠþõü ‚=t#±sçª8}ö�§Þ|ëí׎ó´ü.çvxïùáŸR ¯# ”+$/.À<Û‚e“òoþ]O4ì endstream endobj -98 0 obj -<> stream -xœÕ[[‹%·~?¿¢ŸÖJ%U©Æ0sf� Ä' És6¶s±½xcÿÿPº–Ô}ú̆˜/ÞíQ·JuÓ÷I%�Ÿò›Ýìö™Q?rp&¹”x{ÿÃå§‹shps7´ÆæÍƒ#C)Áöñ›ËŸ~³ýxùéâ�ÌòÊSëù€G2€"ЄÄÛøë_nKËÇï.o¾d¿}÷¯Ë›çï?¼ÿç׿|øù›íóÏß|uýíËf·/¾x~¹^·è=nDi#-¾½ØÍ„Èa3Y®ú©È "³õCÕKþäò'›‡ûÕõòæ÷~üãÏyÿs×ÀU žß]ÞÜÂæÂöîÛ‹+~tØ-Ðöî‡ËçÖZØÚpµ­µÖ[ëé‹íÝ?.ÁrÑ1ov{÷×ísk1Z‚µè¬ í˳“¾1w$k$ÒEº/Òñ©ŽV;æ¶d-Bi“Ÿ³påg´©*ÁE y±ÈeÂ­È O‹œ,p£‡°· ˳(‹u�ð¶´‰ûl­¶Ö�µþj­½Ö�žê@¾*CªßM)s-ßee^Š×àÙÚ(íÏã]î Åùÿæ(Rã4ï‡ñ>?ËûbèÛwgI¸&Áêî{. ©&Ëm„N:AK W¾a7<VëÐZ×B§’/ÿÌ#­ Àöœ ä¨ä…›Òåªú¼ψ\×T‡bGñXë:Òì$…GãB -î“Shx”Ûy ƒþyî„êÌ›òŠ0G[Ãì©&æsMœk•z–¤ÅÜHÀFëïš»‹³WÀâgoP1�™¡Íl1<Ê?ñb3¤ç.×oëlÈ9ÜÞÛ1Æ:q;I®5WßA]Ш‹p -ï\ƒÝoõQ«¦¤³óèÎZƒ–#§‡ð¤0¹Â^ËõlïÛÞ;ZÃÁ2Œ¾<ò½ûõmþÖ“áäqFW 5äý¤IT3/GµH -Æ -¤iØ>�ûtkœœ,ùùc«Ð·u.ЛàÈ:š;` ^sL“ÆSrjÒŽ4/‘—gw«¸\³ÖƒŽÃ¡``„Ov’�²äëƒüñçù$PçOó5>5?±ŽØÃé‚!9“8øˆZW§�šñ",�¾¢<�éIךr·1ótk2*‰vÙm,Thª¡ûí 9½_šå÷Ð,“0÷i�~ve¼äƒ)ö¤¦Ír5Žt½—@Iˆ+ œ£|N�èkdò¨§){�œ¸líÙ"Ç€QÀ±~ÆÌî¹ ‚EÚE'‡'¥ï²Æc7ÛsÈT¾Ìq SMLc«�5-?a“×~:=në7¯W¶özÚ'gæ,Ü*>ƒ2;œ¬W&À:Õë³ñ1&?c½›gdVªb¤¾—57ƒ&.¨CÆ‹ –w¼|Û®¸elBq ~Í œÐvx§‡­ùbGnì ¶4)yGz…W› P°ÄCº;/*™²q>ZŸ@­ž -{ ‚S´q­v$ -˜’ê˜\Ôlzp®ƒ#Y"Þõ¸z¼” 1´Ue¡ç %ð <óÏmÆÆG“ Õ²<\_‡ûë NÂyɆd5»,š}Ra_à=‹^*sß­Õà�ëãý;ºGÜR³úþ¬`»Ž€l¼”FÔ0²»ÊDQÝ­×FP7îʃDÆ…€ÞÍ Cåâd)àÉ+–W"¤~ÝGzÄÀ ìöK/.ÄÝ8¯¹ÛÆ€Õ²àöñœ“¡O+Yíö¥­tÙö–ÚÀ`Ùäy‡Äzk$µa=ºDîÔq›7¿­VÔ,kï�6˜­büÉÛ�uköšòw¨rÔ¦[/ÓÅÞe™>±Œ×,CqÇ2÷,C¼gâ#–!Þ³ ¥=ËP:`J{–¡dˆMxAIÔp ËPÚ³Œ´)–‰va™þ^Á[—£€0�8³LWL�j7@Á¯²tàtw‰‚óîºûÊÅŠz0à h¾ufŠb3N4C$6;=™ŠßZ-Ú± áže�X†paÂ=˱ áŽe¨’pa‰eZg�4c�^¸#™®³NW<"™î=hO2Ù¯;’éþ�qâÇ3– ¯`™^DúõXfœPÕwT0,³;»yÄk aað¦V.‡i�!Ö]b5Ù³A°h_wêÙ�MÂ1b÷íÙm_¥ß!z+û©ÃÐÎ:/jïÙŽpZ¿…=Î=zŽø¤ŸÓñ9í?Ù=â'{„øÉî?¹=â''ÏnFüä0'ÀOnøÉm+¤†íiÂ{iRxŸ`Áûþ^M£)�W¦WWK¡[Ó^Á ²ràew‡‚Õî¶Ž¾Ê½ -¥{ à `¾tF{NÆQœÑžY–´í™ ·n*˜ x î9 -ÌùÉNŽˆa�{l!pÏÑx‡ir®²îážãî9¶8r\à^^©Lh�UʨQTru}F -v�U®*ëTVw?¨ìïîRóD9Vͨ€x(�<ƒûø -¸ïEè{ïÛƒè ¡Õõ±ÿÙö€ÏÁß‘a”e¾24¯(“¹ô  -)ŸŠñ§ºñ¿Ê`O]à£3å�Rò×á¿ÆO±î@TtwBà%‘�´\QÈG„OêÀéàBâùè"„¤;¹¨.=Å벧ӥ .FèÛ=mï´ž…¢¹ˆmÄÂö3°:à´Ëªàœ�Á)6&ïW6–¦•�ɇ|/E£Œ´DšÙXZ³On‘G¡Ð'm;6–Æ…�¥ieciÛ³±´.lœ›“§™�ÇûÁ]Ì Œ2ÞÄÆC­A>]ûÁRÚÊNgÃõ†Û;j÷�€ƒ€ùЉ�¥i©ð‘‡¥Â'-û -Ÿ´‚/­®½Û‘±´íÉXZ§½—4¬{/iÛ“±´.dLÞõ0º™Œó+�n%c=ŠÎ-·î½†Î:UÝ?èäoîÒÓö^#q'a<ábxp5(ƒ“Oýˆó|ù>_f{DþüÔDÜä0Ÿš( Z -ÍGÇGôµ»wg£²ÞŸè%)T2õ©K99çŒßŸEõq«Å�]nóã”eÜã;ÿþ¨w÷^d½Д–4„@j¤ÏÓa®J>.Ò½‚Ú¨Õ?sÙ2¼Ž~z™òˆ›[S]ØE8_< ÊqPG{;ξ0í¥egƒê÷¢|UÕ¶:t:“kYõ´dJõŸ>¦móå(Q^KÎR¨äüµ\4çˆÕë6ß7ç|‹\hÃÈ«÷?<¸ª}ûûw¿|7Å¡•dÞü9Ñöò!òª;êŸz#Îë$vckS_$?B:?D¦^wQR[œB�}»Äy|äyGrVÔ÷³�~S#ÎGöª*åÀ`tÀúíµ_§pV"—"©k©Ì†ÖŸ ’Ó¯;Ï~\Ÿ_�ŠaMÁ„åžÇ‹º4O9jÅàâ.Ì�-M½¯™ôÉiGšÆ_7MÏwt>„�Aî?JÓtž¦^È¿¤é�úº4�À1Æÿ÷Ä›²Špç�gË8KÏîh´Hj3Ö~Qá +%_ÄåØIfx´9CîÿbŽ<=ÊŸTÚÒ²ã5‘3(÷ßmh÷ÀC¹¦˜a~¦ÔUH”àä¼èRœüÖ‚¯ÿ¦ºÓ µÍÖÓ©TÏdòýçl?­|>ï"ÕÀÈÎë>ûÆ�¾l0‰z¼¬²ŽÌ¿>sê; -endstream -endobj 100 0 obj <> stream -xœÅ[ÙŠ%Ç}¿_QÏåDDfäÃÀ]º…d�Ý �m�A2#Ëÿo2+—ȬõöŒ¬†ænU¹ÄzâD–"ÒßLß(ñÑTCðÓ�?_>_YYâ OD -Œ÷“&´Ê†@Ó¯ÿ¸üð§é—Ëç‹VHœÆ›ß•;¿!fÇq4H¿þõÛi~óëO—ßêé§ÿ\>üåß¿üí·_ÿûãoÓÇ�¾»ÿù1ÁôéÓíq¿ÜÞ.^™&4ÓÛ?/8¯'‚ÉÛéíçËG}0wã@þ4½ý뢽òš&˜Þþ>}0€½¸.ÞcÌ-öówŒóûø¿×€B»§|¿¸òõ:Ïòü�çßâKºÇÍŸéšÇ 6®ç5ÿÇ{ì|çý+£-‹ ù¼�—t¡ -D~¸ ®ÖÌ#ÇQÓ*óŠãç"…:s™=ßo®Di’—·ËËw÷5�á �÷èŒy'Ydòõ!KåVeŒ”DW E°:!— ôJK×@þwóà”öÚù°ª º¸{VDÞ.Üòr¹ÍPÌ'ͤ³ÒLþî÷Ê¢ceiýG(k4Së…l³’¬Qd;ßf¾æÙ…¦’ÚóÊ;#3Ï×Ì£¢W`µq®÷¯{¾2Ì>FÊ[Kˆ½ -ó´"r¬Cûµ›8‹Ð¸¶ˆÎ^êH�x¹C/vⳌ°YI±Ólk6(βýÒu¾öj,ª]3Öê*®ßžuq(Ö¥Óå^¡'‹®™S^×]¸ åÝ0~¾ç×dü†¯� ßüŸ ?}”bÑ ¢r`�¹�ì:Í*Ç~A¸tihé7bZ�KB£Lt¨fm,6TÓ�ÒdÃfh|Úá@iM qÕá¶²hZük¶¾–üÂvò{ÍSÏÓj£\0�†4úº´ñQY¯´ Þë¥_¢ˆ@½ÒöÁek‹Á|Ïæ‹%æa*mA‹PQÈk9Ìæ„SXú��")Ýα &J뤭5„ ‚5ÞhÿZƒ_é³ï €Cåƒféƒ]䄞@¯¦ðuø¦€'‘jRAûE*: õnM²9«Ðu.~¼«m³^ÇU}ªžßÇ×äGií+1cN«H&ä>øãÿñ&f³ìÈ(ô†�ØQЇ^PT“¦Œ1³8…Î9mÚØ/¿ tè],½ËL„‹=0•dˆ‹5•šå?BÎÑÂt†œaTÒA†$ÃÑÆBm¿P´JÇ¡Á/lm]pÎÞžŒ1®á œ•§š¥¢Ù¸f `”ñ-6ÉëÇâ•ÖPø=ûüYÖ[gæp­‚±`ŒH—erMÞ;8Šá@�‚?ñ‹ñy0¶`­HÊÙpŸY׿P³|Y±qdPûY(N@ËOekUæš°:8A^7t¸©*2%F3û ¦à2igÛõæ¶±&{ßRÔÓ»0÷¼‹` ‡p掗Iµh]MÞœ˜cSçŒG{|RAdM]¤îZ²ë^ÀΜ®¢2ëjuAï®ÈŸ�à–<:õÉ¡¾ÐºUhi;˜ºcLe�s%™nCN™×Îk¨Ï†©•6Ú‰» Ð1_oœrä…$¨Ë DÊêž™pp=ƒ¡`—FÂ0÷‚eæiQ‘`°’óCZœ©ÜßWÏ‘C½rxÆ 0k *¢âX�4éþ‚¦áøŒ—L»¯–n¾=Z}§¥Eõ#¶4"�6‹1±À4`¹óØŒÍÜrç_Ê£ƒrëZµ^ ¹4ó5cåÌMò°j½¶²\EÁºN@m]ï ®éhÁ3”š–›zOò‰#“ZYT+îÁ~Ɇ^ļ‚«ãÛ†³Óx$hÇ‚Z íxmö’^«Þœ.:�#¢UÝT©Y­7òœŸv¨ã¾?�Š›X®"ÇB§ìJ�™e}4-în ë]7­«ˆÊ¢!ID¶¸ºB·¢eë$“Ë5…dá“›×§ˆâú²¤XÜÚèÒš[ùÞG¬suª¬Hç÷‘�Ë+'J’„Ýù¦ìZ¦_}Y)�ûF‘e¨Ê!0�“°tÓãpã¨$‘ª¨²-äŒv²²é#Tç÷cïÀ4J«Û_Ú {¸öN$›S�O´\-ÿè.ãä¬}§¼ÕäZïu�$ri¼ç‘gç’‰ô�¡²ëË*çܲJ[Ôzi¿ ‘U çž§pýJ?€c\¸.ö.—¯6¨¬ó—¦"Ë�Ü) ¤f¸è¤\ƒ4�0³è2 ¨b·yÕ³�÷,|,¶Ô ïqœõ•ÜÒ¹7¥=Z#|[ îš]C0g» #BÏt2rô0v"$U¼wÒŠŠ“ @¬VÎxðõ½Yi% E'£(¤r£‹ÕÅZE6� ®ôs­ö$„“HCDQ>‘X=céh ~×Uà -É<ÃTú¥dâ*ê~´.¾y}ÂäyÆ,§ÆÚÊ%<ì¥|~´D^¤^;©×aß‹¸Ìuc뢎ñX…ãoŽ£¶¯­ÿœaT°±#C+ [”X;¢:*^×Ò¸ÉNZ£Q'º£mòŽ1F&pß¶[Ûl9¸4sßšeä̇IœSdÙj9IÙn�AضZ|7jÛÞš/–3zÑ×@ëTl[­ �³i�ÊáaâœÂø /JAûu³þ8еl¹Q†ç4"ömª¯AÛ”€´G×,Õ}(�èØaOP‰�ë™…Ò•kpT£ƒAòØnÙÏZ d¡!r­ÐZ@»Ç›Ó>«ØÕ+½ ®Æ­‚å/ÅòñÐUHÜÁïæå¡‹­âPžìqÊS@X‰¤Òc^ŸoŒn|º+NKÍÏ­ì#Ë<¦jC€S¬ÑÑLaß,«¤?1ß ~H° �6›%«À„Æ/äUš ¼e-b‰šÊa›l‡Æ*íÑká>AúßÁþ ö%MV Ûï:ô…¤xˆÝ»f×5i²Ã¯¯!ß2g‹G;¡§È.‡Ædæ×%"mŒó‘Ȥ²7‰UÔRj…«k`žÕäÖ�‡;>ž˹™s|¶ÙhÍéˆÜ*wvKû\&€r>šˆX,9­SçUÕ$²«€éc9–ÔŽšFÀñ8Î .ð/¬Ð‹P+ÙÁ8]‹ºìåºjÎ�¥yîWu\>Ä,teÑMŽ+Pp-s‘h1ÍÊ¿¬î]…Æ£]cV·h_µ+ÁC·ÞÛ§L ýy¬iŠc²l¾ ø|°Êæ”ÕØfÓqàüÞJß -ô妥•…®A §Š|ìO“wÅ‚ Wª¶$�BC/'ËO:$ „¡('›ŠJž¡D6�f°«Ѻ÷ˆG±é ©t$–¬³›¤ß™ÒgQú¾î8Ö{2ën½d\eq’ƹ­lM@Åù|oÊÇ&q|þ4 Ö¸2‹8w†²õQz4'ïš!ƒâ(ÅÄ%…½á|A¡Ù9ÀÅBÏs†£�­êø‰ôâ¡•Í 6þr�Ÿ¢êz*$dèïÁFˆwÐG,~ÆdOŸ• èÜûÏJò³g%©l=ÝsìÏŠÚ:·}¦mó å98 “§‡¶'÷Á+:¦KB¸×+qr¾´d©™ÿòe4… +/Length 2832>> stream +xœÕ[m‹e· þ~Åù\ˆW–,ˆ%0sgn(4…6 íçn“´¥IÈ6ùÿÅï²Ï¹/a³ ,3£slË’ü<–tb�bþoƒ ¶ÏŒú38k¢�1lï¿;ýx²–�GÞ¬ð†È`À…°Zo|Œ¸}øúô—ßmߟ~<‘±Èy¾ò[ù2 §Ù ?ýó[ùå÷§7_ÐöíNoþøÃ÷_ýôáç÷?moß¾ùòüû— ¶Ï?~9Ÿžß�Þ\ÜfÝö-êÚ a È~{÷Ýé-¶,.ýÎ@Ÿoïþuz}wzýò|´€Õ XWà`(íB-ƒg¼�OÓX@[~ÇÀØ–ÏK{o¬sLiÊwßÞ8™^°ÑPðbãxa<¼®8Þ´Œe6Þ�ŸUO*²rÏu±ª¾kê_ÜÓxÖ4Î[LãÎU‚UïB/å�¼Þ woPÌCã<\v=OÊM�'û2Yäûw·U[¸° ÞðöÝɉɱì‹(�µ[’‘gί‰± .ÉD±È{»½O£}À€R¤â­¤7Іüf0@ˆI†^Äs‘¡_F¹"d°›óF<ÆPßóÁú$sì¨È„<Ög½¬i$æÍqÒŸ­¯²“(ÏÓ6Ö'ú±3ÁE«gq†aÓ¡­ç ’hµÈDï}±eÕžŒ"Ùy—d\”`µ9È�[ÌÑÌFÆÆ²Éa^2àÉ• ›#ðÀaÔúþ´<·>lÓ4l‚ ^/dž–Õ†Vl�ØmZygbÚî´Kg„¬+ƒ‡9\d·a3gÈz7›Ö"Ó'¸¤jvåð•ëntÅ�ÃËn›¡�Ö!3ÖÑÁÕ4R!Ø´Ö±:ö§£ºYBG3˜>'ݲú@5ÈÞOa¸ñ§o®AšÓ�ƸbšOh±¡½Ïp ÆÅH®ãH7§€Ëu4M±áCt±I†ÞÏì’„ »$ÑÊ.I¶g—$]Ù%Ë:»¤MMìÒ`³ ÔëU¤j 8íÚÜÕ»ì=Ì1p|˜­Á½6ï …á=R��GãŒôy�°"}×h„`×ZŪڟŠên ýÝ`êœ ËªÕ {?…áÆHoᨧ^Ï ãÞ\I „Œg hó”ÀÚÛÈo½ œîöj£ySøHM oÛ1šÜ<û#füU¹ÏÒM�XcņIÉOC~�œ¤¦• ºƒÏežV=[­”æÎòŠÜ¸¤\9=ñuþ×:ö\ ÒZh–:¶DwÍO\“±§™6{]ЕŸMc§4§«—uG®hž¦IÚ¤¶¿1ŒÌ3[b©ÐÞ bë4‹Ûq±¸= ïjzIvÀÅ êf.Ÿ næbñûš^®\,~ÏÅâ�².ñ{.N²ÁÅ" ·ÇŠú,Š0Ôz�WºZŠ|šöŠ¥Ô.�us(Öëfëä¨Ì«H´;FÍ¡3‹Ûq±ÐÊÅ’@–.Úe]‚û¬K0ý¾r±àÂÅ‚{.<âbÁ= v7âÂÅé‘Üg]j\¸ã⮵ŽÕ±?ոϺºÁô9é–ÕŠö\Üü†oq1?ÀÅI»ÏB¾\¸¥p•‘óµô¬‰ˆ�—ÞBë)”i ¡CÕvÉÌDåß}öñ·û/Þåî—Ú[/ɵêSM’•W�¥+ù�î�h°v¬æÔÍ›f khßrõr+í-œÔ¸¬³CmÖtEï¼TÒ»VºË �Cé” óêzUI0SWk[…ûdè •I© ö*¨{ŒØzÕóˆh›Yk ¬!!P§ì†u±×ÑAKÉñ:Y¶5ªq/Ê4¢jÀÕžSg¯ÕÓ(Õ0ì—„û|'�²~*ûÖÿSê,áêÈ æPÚÆâƒ¹Ó/ÎGóòÏoþðõ8—­Ìóæ¯1l/?ä5>¢'}íøß®¼øÔ™†~ó¾‡&ñvÚ�JΘµùÈU¿g›Ëµ¦é•™³¢Ò›*±âoá)Ïe.‹†ÅbÐOs´6tÂQ¼Oc9m¼7ìÉMo<Ö¿_é_›Í8&�Î8+Ñ+¼¯ š¯©Ù<Å'¤ sqþµ…(ºüç/�P„¡ñÓE(ÞÎɹ-DõeÀ½Ï ðv„RºK”³>¡$Šü¿ÇÜÜ +“[2 ð<{6G#C¯’;¨ÿvyÍ9t'a‡-Ä(í�/ɯã–üÂÙþA½wžsÛk­8ŠåC˜6¦]²¾õ}ªëÄúOƒ×üYµ?ϽÍfÂ~ÁcãÈ/·À‡®‰ºsÚ®dÔ¾oQŒØWn««¸F¼ç´;ín„-ýNÛ¡h+€Äj–çqlke¾E?Pæ¿øRO}:”$!zhm+ë‹óX¡ßY|½Û_T•ã¥ÜIî{ëN“½%á·8bK ú ¯Øþ\JYTÊô´ïÈd¿7ôÒa®ËDù�Šj¹íd®kö¿Ú‡^&x�öZÍq¾iL ŸGeMßX{¼zG@ÂN—^>»Œ�)LZ Ö`óÑ@Ïþcõ¼Ìnì7êƒhígE¦[ÚqtYèYr!ëT·Goç„È�ˆ×•¼ÞsÉø\æè¿ùþ~ä[ÿ£ÈÇ…Ø­5˜¯;Z#vÂ3Ôõ/yisÎZ—uÆ¥¥*ÅjC·K sâÀ!�=> stream -xœåZY�ÜÈ ~ï_¡ç[C²È:ÃÀtO÷"ÀÉùÞØ�×°ãýÿA]*–Fju{o€x0n�ÔE²x|ÿñþË,V ŽÏ‡‡ OÈÓóÏ,zĉ`ŠÜôüáðÀAñœ®ìÛéù×Ãùy‹i–$›Ô«ØÐ €.Ö%ò„åÚ>Hbí2[‡†¬³&˜žœÞ0ù$}„Ø—E|Y!èØÕuX~ûÞÊ5Ÿêý˜™¢°±Š{®™zú}¬«qG+öªÚ-‚ña¡¬“¥Í÷¸IØŸ%YĈ­*K÷ÎE;ygÜT �îÀÇ¢%�ö¼¶® éZZò‹5O…欽Ås:W>§ªýsÓ×¶ZUKnöQÙè\¹V[g�´]úò™ÿ®>ÒèàžÅX[LhUBŽ-RªD‰z“"`÷�|¯íý¸âizwMb[½Œ… ‘GŸ—æûù[ä ØÁCiݧ‰vö-»aC| @¸¢³ùö¡Ôh(n¡þò” ;ŒÈ¸àמ"¹(wÍR¡Æã%zç¾iüu¤!4­ôûÿŽ4Œøg"M-FøR@‘fª ÌUU•þ\S'éè¼³4Ï/fÜ,.\É›H'\^ -i0 &3ûîÈU Ö‡(@ýo¬¨H†£ÃŽö)?ˆÆZhƒ -–ú€ƒS!ÛÐÁDvÀU´Væ–Bðäû -(!ÌbŒà O¸í]8:—´÷ȵIª@‹aOŒ]�R”â :ñxƒR¶¤ªŽ�³Ñ‹tpٰᦩˆ+Š‘ i,Èz§RÛqC&wÚ2ÔÝ»àSÝEt,1Þ²â\™£õ`#­›)ð <6íw›óØ€wZ#b'e›Ö}DGn= -Äó ÊõJU¼nVíþîBä néc0Ÿ&õʤڱÒ6˜"씩R¨%ÏPŒÅä˜v‹<ÖXNY½»ÙFN(ßgo<A¥ -jÅI©'É8ký`(%Q¯q,`ŠNCWM;)/žZ~,lS-ÁÙñ˰§ºý¦5^ÕÜ«³b]÷Ø ‘eY�×\ÊÖZ) Ò‹’¼ÞvúsIpR4Eò¡ËÖtÜJˆD#×§R®ý\بÖB{K+Ž”×$þ¸(iæµ ¹¯5ÈHº>^6"‹êöÔK£¡�“ý‚L¢½;'µfË:3�Ey:v2v�ÇEíHi²¢+ù4er!Œ±å»š²p¤jÚVeJwÓÙ ”@ÙíΊFTõvuwrU`©ê×&YT¬³«\z�Ñ”x¤®ÌÙÍ›ëˆRöyá~aß¼[9[áÈïã"ŽÖ�g dž”ˆ±u|C\Û°u¤ Ÿ}w js¹Ú®W¥&#Ì’j…²ò2yÙ¨ØRúZãI$Ð=»«ô-·+„|Ryä0Út9¥¯äû³9kŒÍ»s+ƒ‹Š~³ÛèXÓ×wD¼³¾Íž:ÕÆ5[ZÙf·¥BÚÍÎÛEÆH[~áØÛXmI|R-³ò†[²KÖiEó<�¨FÖúž'Wà@ÛrÖ”T<{Të á“jÍ¡;Tƒ nþâTÈ/qs¹ßÀÁ`¶w°î÷g�_1yßÌ ÎE¥9ÖTAÝ|k­>mß)3 …£JØç:£Cã¼øðrÐ3ïë¬ ¦–tÞtا[I6盃¬¢A©\1ˆ‘‚0oÎpçÛ ÔâÑw웽ñI]k5KÚ´dÆÅ:DjÐø9óبÃö1ÀîÜÞ¶i» ÚKi‹&DÇAµ7�ãl™#R„IË':*�BãÅXŽ–�pVõWð¢sXvÁK©Ròó²˜eîÓE"ŒqhjwvcgyPßzHvÎGåx±8yòiÏh;cwNFó-WÐQ!ãcëGÈÿ4ÏZ®ð¾>úŽhbÈM–’`Î+`ò¢Üj;Ö*þ¸ƒªKȺ^«H;Dh@jÑš0âºåW¼§AÒ¢[º‡Öu©9F;ÃF§ðm®C~ö‰Ø†Ù|\Ï–Ë"wzŸº¥fÍ´®�áÅ1ÎÐ׬¥Y¿_ÓY2ž"/Ê]ì„¥ªr¨öÕwxC¸¥ùæÔ~Û›¹²Çn.±/³0/èÍå€2rG�[[Aý:ðv7Ïžƒ�_?{–{gÏkÇ£Eǯ³nM·g„›31ª<$¢ú¨Mæ_?Èòûy5Ìùß8Õ‡WG6´R Þ8îÑå7݈’É -¸ô¹ýú^ºzÿáúëqÙ4nŠc¨ûú*ͯµ(áU¹kÒ%� /f*˜æç¶~Æ ÈõÔÏx•ª ÖH~›¡yN!q}Y´&Í&¬^—�44®®ehï‹lòLÖùÈhž( +/Length 2673>> stream +xœí[ÛŠ$Ç}ﯨgƒrã’‘Xfº§…d�= �m�A2»–ÿßTV^¢²®=»²ÁÚ…¥»'«"3ãrâDT–!Žéß ßõ3X4c Ã�?_>^Å8’½ Dl:ãb¤áÓß.?üaøåòñÂI’¼é[¹ó +>²ñ2 +„tÁŸ¿¦/Ÿ~º¼û–‡Ÿþuy÷§þò—_?ýûÇ_‡÷ïß}wýãm€áÇçÛõòüzyw·áðú÷ N+Æ�`ˆaxýùò="0;;þ·‚ÓD¦q ùo^]?þ�ó=’?=€ÐøûÃðú�ËËëåå»ëÚBq¾Pt†GÑ fòuÁIh0�¬µÞ 0¼þu0 °¢µ»qp°Æ‹mà[ˆ†Ùr¨ò9 .4QâÒ€3Ñ:°6Ö[&g +Á“ow@@k ÆH1œ±! Î…6‹àÃëÚ5éWŒXO›eRŠ7ЉÇJÙZ•}ÊŽ£isÀ}Æ›¦¢I¿F$D5…”)ˆ½k×Ûç�5¹ë–¡Þ…½æ]Dg%Æ3w¼äÉ‘=p¤u3{bŽMû�sø 5"6Q\´î#:rëQ ÞžP®Wª²ëfõ‘�w7äANhpK3óiQŸ³UXiLIƒ©Ð€v‰¢Îe¥0* ÃyãçSƒó +õÙ1Ù°e¯vì×SM×[o<A¥ šå"ã˜ýÌNjE¶ú1[–¢ÓÈ•³“�kþœ.¶h(Dp<¿4Ç]Z*ÎBI?_>G¶¥ûŸš¼¤56ÞgïÓŽÓïØîU—îçéš:Çm«2E­#d£)gHׇIÆ8-ÉôÝ_ó¾_Ú}V;Q^·v&QÜ‚ü\Oç°9›­Ö^οÔG1úŽU)f«Ö™ŸÆD0f‰¬énÕ¼¶²{žÝ7M§k'OGö&²óóXðÍFiÔùÀµù@Ý;dÝÙÉ&eµ!ëÇ©{p¾‹äC/jÞØ|«ÊwY–dyÔ40êØ†f‡j÷{þ¬v?:{tNZÕMe匎\áyîä9?mO.ûXÉŒxM¢‘¡Ð·‚1“ªfu»[FCÑ?›U�*¢qhI|XAÕ5ÝÂÊ‹S„sœ¤“5H.JžÒb>á‰WðÔümMºöåŠ^‘Â�y÷æKE^�i…?Huå$Ñ0!iÒ�oÊ�5 +÷×TeÚϤÂXUÀ$'/`¤'À&”R U¶¥!Î*pÄ*µ²OÎß•Yª¬¬ÚÙÎ@EÒèáè�H5§`À³©µ]5HNÆ÷&8&ÍÒ +dT[!Qjyªl$ˆ Îêš&ë•»ôì”=tŠ%˜/8Ù—îÛh9<µ TäK-½à"rqqùj‹Æùà—øåÊ®¥öI€G˜€q¾ÞО×xÃTˆ:Ã,‘Ãlv¸xJ8LâBç(ÚÉ2ƒ²Å4qžyߊFãýæÎ(EÁ3½¤Ët܌ġ3¸_Æî&•èh�¦˜Å”I1ÐÑE9Ö(غ{–:Wj´÷e¥6¶ØçÎb@gUh+Æ]s£oì%©í¦TçÖ±¤gç<-e 0ñ +‘*×;éEE‰I V«g¼vÜúÚ¼´äZ‰ÊÀ¥~pŠÿ…Ç wºNQ9¾rÊqü9ƒ*µQœ¡ò ¢r"­:¤lð>îf•A·B²ŠÍˆ"”a©™q •qß²sª<íò21–S²¶R‰t{)¿o-�­'̺ª¿™ÿ–©.YZJ¨2nKšp˜Þã!h;[@;LÞDÇÁyZ!تºÚÑÔQݺ–ÄmŽÑ +F3Íõ±á€ÅXk³oÛM³_¶4oßš¥o—w“xoȉc=IÙn… l[-¡;Û]•/ŽÓÑ— ê Å®s6 Ò˜ç}�J”ïKܳ²ä'…ê×͆8ã¡Ö�-5jtN±UÎ_ªcSðh¯Sc÷¼=6:ŒW<ÑEôXsì-o·‘QF£na{¥]žô8gƒÎ�jžWØ”õÅP½nÙçÈ"Ö¯RåÏeò ÇÔ7øm¨¼d}/”ªê¦à˜ºËÞŠ+Hª#æþHxç§-Їq˜Ñ|B‰‚Ìg†œû{Ës…yæq—Ö žjÍd÷cÀ‰IöSó�è ©Ȭ…6¹¥˜(„6,ôUº3Ñ'Ävµ93J™söCë  ¬Â'êø;Ú¿ìkšœé¶¯}³v(nj÷~§©ë›6Ù®¯ß2gãè)ºËИÜüiIH[³ùHenße$ØÔQd­µÒ¨k`šÕâv×a–¢6€ÙsñÇS |òÙÑ›Ë*wvë÷™Æ‡ÉEêŠÆ$Svm·¾k^MM*»*–ÞWcÉ쨘éH8nçà¼ð‚ ùÂJ—`µº5xÀ¦kM—C£\WÝù¶tϽڪʕcÎâcm ÛŒ+Tp-KÑhqÍ�nYÝ›êŒ[»Æ®n±>¾(:êVÀ£Xä`Ÿ:�ïJûS^9ÛÇKG›¯Š>÷–AUÏ….Y?)�)½æ'ì»V XÚŸ«Íœ²×|Z3N�Žœ_[å[‰¾(�Ø–VzºF�ªñ±5KÓºÕ]©ÖÒý Pz9Y}âqÏ0HA(Êɦ²’G:"ÏmçW‹6«îQl¡L¦T<ö•œw›=¿3¥Ï¢ô½ïÖ[2ën½l¸êâ$Éy^QØš‚Jð…¹+»D<.pÆB½øDn"NϺ²õV zt2vÝPÀÈD(ÛÄ%…½™á|F¡9 €­ =Þ2ì}lÕÆ¤ÿú¨aô¯ÊÇ_Îðñsí€ë��˜©7R¼‚Þsñ.Kç�IFþŒc’òè1I*[�‘ç-öÇÏCm€Û>ζy|‹òÑëƒCÛ“¿ýÌÕ‰vIôåÐ÷Ï»ò¦ÉÖ–GZú¾ÃGktX[�,¶z|ÿ8ẩ šÕ–ÒTTë‰Æ§xtŸö:î)õu±Â|À ñˆÑs„Î(—Zu¹ñ ªQ8ø€Bm.ÊÅŽg½œÐç½#½ìÛŒ¥–ÒŠ™Õ¿j½ %T³ f*éZ«Áõéî4À,{wm³ ë{VêÑDO›ÅÖ•îË!úbêì©Ã:.ž”™ +àß×�¾tÁj2,õÚ¡ÑÊýi�>þVq¯Zކ!H´oh9¾)öKÿ´q$ø,¤g‘¢MôßG +eO�РŶV)ë0¢ÊŽÊ0HùÌš&cã%zç>röÊ1¡�8öÕþÝCZú_B¾Ôƒ€¡–AY,kkë| +é ÍåAqÿSýb>ÍOˆ¸.ña‚úõ=ž¯ïñ|}�çë{<ÿßïñðqM‰@N?êüý½ÉóýåûËÇôR,Ù€†d`7~n¿W;~Û{“v´GÒ¹âœù\ƒQ9VS™Ž�òljUÍO«õB<‚ IóU +Ž�4ΟqÊÐhóß >ïJåÀf:q€Å%&û÷E6‘0}_"º¤)úê½Ф�̦ÌHÂì-P3[È&ûá±y +endstream +endobj +104 0 obj +<> stream +xœ¥YÙ®G }ï¯èçHÔµ]v-Bšå!‘H®” €”þ?ªjWµ»§gAáJÌôR./ÇÇv�#Ÿë¿F_8s™]ÆœÓøöãðe@HFŒ2 8à”FO\șƯï†?~? _ï�¤Ê›¾µ•/<’“"ÏqNãüßo¯ÇÕ�¯†§×É�þžöÿ|~û÷›ïŸ¿½_¾|úåðóq„ñÕ«ýñ0ñ cyd.Z¼`t�® +6W“P.BûB1ËÊ_]QþêËU�Ó/‡áé×ÏŸ~ÿöõûÛo]TöÏÃÓ™Gäñùý€“#q$<†ñùãð€€xI‚§kÒk‰|`žžõ÷vºn7É™ž³>/Ïêš3€½Îú^àƒ®÷³ü²—§g]¦è3]×t+ïTýŽ*ï<ÙRí:Ä"#ði^Çf«ÞE§¤×eTÝýnÖ£®]éíƒÊgÕg�‘ôyRûšþÍFš®«ÜÃäQ¿wÊ«ñù¯áô|3œ>µpZÓŒIM…¶“Ùʬ¹ž.cŠ;öÒ8›[ݱµÇÙ˜d\é'Ó(–œ )�0>ÿ9¾T¿ÄÙOU9š�IÃZ÷.ª¸;yÆ£(Þ)¨Â¢þ·1É*KãÒ±rÖÏÝìÄ=ÍÎì8oØãìÓ +鑸hñ=Õ×£‹1Syé32ù×ä³ñ ª-kõ>L9ãsŽÄ)dñ]z÷¨j_Ñ»ÅÇéÞE–ˆ”(tM­GÙÀL–ZO™6Á½‹$bL�¯6Õ¯ánÙyŠÈi!è*挿 +ø{<5ɺuA7 Ó{–ÿ:nl²Ùï?”ó‰þ8‹mÛÖP›à 6‘WŠÝ/ŒiU4ŠÍÐh […�šp+Æx¤ÀT§*¡— ´([‡·¢!7Á³{J”Ñvf4†R@¨­ Q�(¸&˜¤_3çÚÞ)ƒ’à ì8ƒÛ Èo„|6æ41ƒ© ²×jAsü¶RÚ¦|±?˜8ÔXDö¢=Ù�‚.D‰ —cØÉ�LK/œJzKÑ…¡a£Þ(Õ7„lòÁnÒ(‰“”R\°^/r§Ç#Ô]$dœÙ¯Ãñh¾[7ë3ÙÍ}HgÆ ½Äa®AVÏ[½Ø]ð–„¶‘’P‘’cíÑ¥8ñìÃÝÜmU‰’bÒ*ŠMË`øØ41e ì<­2ádz°¨•B +/«X…àyjTÊwlýb«2÷å"‘Æ2\¬%_µÆwE0€¯w’óBÌxY\�|¸4¾4.AjA£½¡Æ øž…$"Kà׌º³·Ü¬]Nì£,4è…`ƒL.:®±½vòû 4“BõõVO²›)ÂRËÖ·#¿�žFI«‰éGdÝÆ‹ †+ÓÂ%ÛÜæü ì5$¼ß®—ëF·‘•`\Ó&^&ìÅp³UGdû¾Ö òä"e^u¼8 õå¢ã7ïðåÖñëÅý¼qzw�s¼Ä_Öa^Éë �‰Á£-®­§þ_ìVÉœ/"!]’¸$nÙ˜”ƒ1s ݽº�wÂ) Ì\‡reøú€'Æ€s  ¬CKΛŠ?mž†�fQ‚WðI7GÁVÄ‹ŽÄh¨ù väÀ’sX³ov’1.F©«›7_I€ÒŊ롉Ö@½¡_Ÿ9¬ù–R‹c+uòn�ÛÐF‹úà™�Ý“èŽ Òý#„FH>]’‘ÂëúÙî�`½…$ç뱟هÊçÚ¼/:�ÞØÖ}:òÁÓ<.Ú£ª¢_s¥¨Ë×I':BJyNƒ’¦µ‰æìêjÜîxá¶£³8�~á‡í®óÞNxÛáÞƒkå߸\Û çE§>^¸‹Â{úÝžiÙ£c”ê-Jœ9Ó«÷Z/š—}i¯[‡k<�Gëóż°ª /šëÛ\HÒªùz9ÎE¥ÍAö9�VÓÚi5¹®ŽB›‰lp¾nÜZWЧÁG‹>2ƒD’kT)FÇø8]v_ä‰(é”*.-'ý~~³N¢ÒšhŸ8S-–§9„.JЦjXÊmpÚšO¦c^Sñ›áÍð¥þ~@œÐ‘Œ^ ”Ï뿊”oo?ÞþÑ¡Æ&Œy™îÑÅT$P;&êyÂS^ÕA|Ù™®…DlœÑ¥`9I÷ú™'n@Ö{ Ÿû›R}bGž}¡Ï!¬íŠ÷‘�æ1Q\–½+çÞ +«\O–47×2 ƒ\)ñ‡)�üÖÓ�­ endstream endobj 2 0 obj @@ -1076,7 +1100,7 @@ endobj /Contents 50 0 R /StructParents 0 /Tabs /S -/Parent 103 0 R>> +/Parent 105 0 R>> endobj 51 0 obj <> +/Parent 105 0 R>> endobj 77 0 obj <> +/Parent 105 0 R>> endobj 82 0 obj <> +/Parent 105 0 R>> endobj 86 0 obj <> +/Parent 105 0 R>> endobj 89 0 obj <> +/Parent 105 0 R>> endobj 92 0 obj <> -/XObject <> +/ExtGState <> /Font <>>> /MediaBox [0 0 595.91998 841.91998] -/Contents 94 0 R +/Contents 93 0 R /StructParents 72 /Tabs /S -/Parent 103 0 R>> +/Parent 105 0 R>> endobj -95 0 obj +94 0 obj <> -/XObject <> +/XObject <> /Font <>>> /MediaBox [0 0 595.91998 841.91998] -/Contents 98 0 R +/Contents 96 0 R /StructParents 73 /Tabs /S -/Parent 103 0 R>> +/Parent 105 0 R>> endobj -99 0 obj +97 0 obj <> +/XObject <> /Font <>>> +/F52 52 0 R +/F80 80 0 R>>>> /MediaBox [0 0 595.91998 841.91998] /Contents 100 0 R /StructParents 74 /Tabs /S -/Parent 104 0 R>> +/Parent 106 0 R>> endobj 101 0 obj <> +/ExtGState <> /Font <> +/Parent 106 0 R>> endobj 103 0 obj -<> -endobj -104 0 obj -<> +<> +/Font <>>> +/MediaBox [0 0 595.91998 841.91998] +/Contents 104 0 R +/StructParents 76 +/Tabs /S +/Parent 106 0 R>> endobj 105 0 obj <> +/Count 8 +/Kids [2 0 R 51 0 R 77 0 R 82 0 R 86 0 R 89 0 R 92 0 R 94 0 R] +/Parent 107 0 R>> endobj 106 0 obj +<> +endobj +107 0 obj +<> +endobj +108 0 obj <> +/wie-drehe-ich-eine-gef#25C3#25A4llestrecke [89 0 R /XYZ 15 233.66998 0] +/wie-#25C3#25A4ndere-ich-die-l#25C3#25A4nge-einer-gef#25C3#25A4llestrecke [89 0 R /XYZ 15 156.419983 0] +/einf#25C3#25BCgepunkt-und-koordinatensystem-1 [89 0 R /XYZ 15 620.66998 0] +/wie-f#25C3#25BCge-ich-eine-gef#25C3#25A4llestrecke-ein [89 0 R /XYZ 15 327.41998 0] +/h#25C3#25B6he-und-#25C3#25BCbergang-zu-kreiselkoordinatensystem-unterkante-sp---oberkante-lp [89 0 R /XYZ 15 450.41998 0] +/22-funktionen [89 0 R /XYZ 15 358.16998 0] +/wie-baue-ich-eine-gef#25C3#25A4llestrecke-mit-manueller-h#25C3#25B6hen#25C3#25BCberwindung-ohne-vf-qs-platz-mubea [92 0 R /XYZ 15 734.66998 0] +/31-zusammensetzung-abh#25C3#25A4ngigkeiten-randbedingungen [92 0 R /XYZ 15 159.419983 0] +/wie-baue-ich-eine-gef#25C3#25A4llestrecke-mit-kurven-als-#25C3#25BCbergang-zwischen-zwei-kreiseln-mit-unterschiedlicher-h#25C3#25B6he [92 0 R /XYZ 15 781.16998 0] +/wie-baue-ich-eine-gef#25C3#25A4llestrecke-mit-einer-bestimmten-kapazit#25C3#25A4t-als-puffer-freie-l#25C3#25A4nge-des-stauprofils [92 0 R /XYZ 15 841.91998 0] +/zusammensetzung-eines-variof#25C3#25B6rderer-mit-allen-m#25C3#25B6glichen-komponenten [92 0 R /XYZ 15 129.419983 0] +/3-variof#25C3#25B6rderer [92 0 R /XYZ 15 703.91998 0] +/wie-baue-ich-eine-gef#25C3#25A4llestrecke-zwischen-zwei-kreiseln-mit-definiertem-abstand [92 0 R /XYZ 15 811.91998 0] +/welche-einf#25C3#25BCgemodi-gibt-es-und-wie-unterscheiden-sich-diese [94 0 R /XYZ 15 97.919983 0] +/einf#25C3#25BCgepunkt-und-koordinatensystem-2 [94 0 R /XYZ 15 374.66998 0] +/verf#25C3#25BCgbare-steigungen [94 0 R /XYZ 15 538.91998 0] +/h#25C3#25B6he-und-#25C3#25BCbergang-zu-kreiselkoordinatensystem-unterkante-sp---oberkante-lp-1 [94 0 R /XYZ 15 220.91998 0] +/32-funktionen [94 0 R /XYZ 15 128.669983 0] +/wie-baue-ich-einen-vf-in-einem-puffer-mit-gef#25C3#25A4llestrecken-als-umschleusung [97 0 R /XYZ 15 286.91998 0] +/wie-baue-ich-einen-vf-als-#25C3#25BCbergang-zwischen-zwei-verschiedenen-kreiseln-unterschiedliche-h#25C3#25B6he-und-position-xyz [97 0 R /XYZ 15 226.16998 0] +/wie-baue-ich-einen-vf-zur-anfahrung-einer-bestimmten-h#25C3#25B6he-arbeitsplatz [97 0 R /XYZ 15 256.16998 0] +/wie-baue-ich-einen-f#25C3#25B6rderer-zu-ebenen#25C3#25BCberquerung-zwischen-zwei-pufferbl#25C3#25B6cken-welche-#25C3#25BCbereinander-positioniert-sind [97 0 R /XYZ 15 178.91998 0] +/wie-baue-ich-eine-strecke-mit-mehreren-vf-und-gef#25C3#25A4llestrecken-hintereinander-zur-#25C3#25BCberbr#25C3#25BCckung-von-gro#25C3#259Fen-entfernungen [97 0 R /XYZ 15 131.669983 0] +/in-welchen-baugruppen-sind-scanner-und-separatoren-bereits-eingebaut-bl#25C3#25B6cke [101 0 R /XYZ 15 661.16998 0] +/4-scanner-und-separator [101 0 R /XYZ 15 841.91998 0] +/wie-f#25C3#25BCge-ich-einen-separator-ein [101 0 R /XYZ 15 247.16998 0] +/5-be--und-entladung [101 0 R /XYZ 15 170.66998 0] +/42-funktionen [101 0 R /XYZ 15 355.16998 0] +/einf#25C3#25BCgepunkt-und-koordinatensystem-4 [101 0 R /XYZ 15 110.669983 0] +/zuordnung-der-frei-platzierten-scanner-und-separatoren-zu-einem-kreisel-gef#25C3#25A4llestrecke-oder-vf [101 0 R /XYZ 15 523.91998 0] +/41-zusammensetzung-abh#25C3#25A4ngigkeiten-randbedingungen [101 0 R /XYZ 15 812.66998 0] +/einf#25C3#25BCgepunkt-und-koordinatensystem-3 [101 0 R /XYZ 15 781.91998 0] +/51-zusammensetzung-abh#25C3#25A4ngigkeiten-randbedingungen [101 0 R /XYZ 15 141.419983 0] +/wie-f#25C3#25BCge-ich-einen-scanner-ein [101 0 R /XYZ 15 324.41998 0] +/wie-binde-ich-einen-flex-f#25C3#25B6rderer-an-die-entladung-an [103 0 R /XYZ 15 535.16998 0] +/#25C3#25BCbergang-zu-rutschstange-oberkante-lp---oberkante-rutschprofil [103 0 R /XYZ 15 718.91998 0] +/52-funktionen [103 0 R /XYZ 15 643.16998 0] +/wie-f#25C3#25BCge-ich-eine-beladung-oder-entladung-ein [103 0 R /XYZ 15 612.41998 0]>> endobj -110 0 obj +112 0 obj <> endobj -109 0 obj +111 0 obj <> -endobj -113 0 obj -<> +/K [0 112 0 R]>> endobj 115 0 obj <> -endobj -114 0 obj -<>]>> -endobj -118 0 obj -<> -endobj -120 0 obj -<> -endobj -119 0 obj -<>]>> -endobj -123 0 obj -<> -endobj -125 0 obj -<> -endobj -124 0 obj -<>]>> -endobj -122 0 obj -<> -endobj -127 0 obj -<> -endobj -129 0 obj -<> -endobj -128 0 obj -<>]>> -endobj -126 0 obj -<> -endobj -131 0 obj -<> -endobj -133 0 obj -<> -endobj -132 0 obj -<>]>> -endobj -130 0 obj -<> -endobj -135 0 obj -<> -endobj -137 0 obj -<> -endobj -136 0 obj -<>]>> -endobj -134 0 obj -<> -endobj -121 0 obj -<>]>> +/K 2>> endobj 117 0 obj <> +/Pg 2 0 R +/K 3>> +endobj +116 0 obj +<>]>> +endobj +120 0 obj +<> +endobj +122 0 obj +<> +endobj +121 0 obj +<>]>> +endobj +125 0 obj +<> +endobj +127 0 obj +<> +endobj +126 0 obj +<>]>> +endobj +124 0 obj +<> +endobj +129 0 obj +<> +endobj +131 0 obj +<> +endobj +130 0 obj +<>]>> +endobj +128 0 obj +<> +endobj +133 0 obj +<> +endobj +135 0 obj +<> +endobj +134 0 obj +<>]>> +endobj +132 0 obj +<> +endobj +137 0 obj +<> endobj 139 0 obj <> -endobj -141 0 obj -<> -endobj -140 0 obj -<>]>> -endobj -144 0 obj -<> -endobj -146 0 obj -<> -endobj -145 0 obj -<>]>> -endobj -149 0 obj -<> -endobj -151 0 obj -<> -endobj -150 0 obj -<>]>> -endobj -148 0 obj -<> -endobj -153 0 obj -<> -endobj -155 0 obj -<> -endobj -154 0 obj -<>]>> -endobj -152 0 obj -<> -endobj -157 0 obj -<> -endobj -159 0 obj -<> -endobj -158 0 obj -<>]>> -endobj -156 0 obj -<> -endobj -147 0 obj -<>]>> -endobj -143 0 obj -<> -endobj -161 0 obj -<> -endobj -163 0 obj -<> -endobj -162 0 obj -<>]>> -endobj -166 0 obj -<> -endobj -168 0 obj -<> -endobj -167 0 obj -<>]>> -endobj -165 0 obj -<> -endobj -170 0 obj -<> -endobj -172 0 obj -<> -endobj -171 0 obj -<>]>> -endobj -169 0 obj -<> -endobj -174 0 obj -<> -endobj -176 0 obj -<> -endobj -175 0 obj -<>]>> -endobj -173 0 obj -<> -endobj -178 0 obj -<> -endobj -180 0 obj -<> -endobj -179 0 obj -<>]>> -endobj -177 0 obj -<> -endobj -164 0 obj -<>]>> -endobj -160 0 obj -<> -endobj -142 0 obj -<>]>> +/K 13>> endobj 138 0 obj <>]>> +endobj +136 0 obj +<> +/P 123 0 R +/K [137 0 R 138 0 R]>> +endobj +123 0 obj +<>]>> +endobj +119 0 obj +<> +endobj +141 0 obj +<> +endobj +143 0 obj +<> +endobj +142 0 obj +<>]>> +endobj +146 0 obj +<> +endobj +148 0 obj +<> +endobj +147 0 obj +<>]>> +endobj +151 0 obj +<> +endobj +153 0 obj +<> +endobj +152 0 obj +<>]>> +endobj +150 0 obj +<> +endobj +155 0 obj +<> +endobj +157 0 obj +<> +endobj +156 0 obj +<>]>> +endobj +154 0 obj +<> +endobj +159 0 obj +<> +endobj +161 0 obj +<> +endobj +160 0 obj +<>]>> +endobj +158 0 obj +<> +endobj +149 0 obj +<>]>> +endobj +145 0 obj +<> +endobj +163 0 obj +<> +endobj +165 0 obj +<> +endobj +164 0 obj +<>]>> +endobj +168 0 obj +<> +endobj +170 0 obj +<> +endobj +169 0 obj +<>]>> +endobj +167 0 obj +<> +endobj +172 0 obj +<> +endobj +174 0 obj +<> +endobj +173 0 obj +<>]>> +endobj +171 0 obj +<> +endobj +176 0 obj +<> +endobj +178 0 obj +<> +endobj +177 0 obj +<>]>> +endobj +175 0 obj +<> +endobj +180 0 obj +<> endobj 182 0 obj <> +/K 33>> +endobj +181 0 obj +<>]>> +endobj +179 0 obj +<> +endobj +166 0 obj +<>]>> +endobj +162 0 obj +<> +endobj +144 0 obj +<>]>> +endobj +140 0 obj +<> endobj 184 0 obj <> +endobj +186 0 obj +<> endobj -183 0 obj +185 0 obj <>]>> endobj -187 0 obj +189 0 obj <> endobj -189 0 obj +191 0 obj <> endobj -188 0 obj +190 0 obj <>]>> endobj -192 0 obj +194 0 obj <> endobj -194 0 obj +196 0 obj <> endobj -193 0 obj +195 0 obj <>]>> endobj -191 0 obj +193 0 obj <> -endobj -196 0 obj -<> +/P 192 0 R +/K [194 0 R 195 0 R]>> endobj 198 0 obj <> -endobj -197 0 obj -<>]>> -endobj -195 0 obj -<> +/K 40>> endobj 200 0 obj <> +/K 41>> +endobj +199 0 obj +<>]>> +endobj +197 0 obj +<> endobj 202 0 obj <> +endobj +204 0 obj +<> endobj -201 0 obj +203 0 obj <> <>]>> endobj -199 0 obj +201 0 obj <> +/P 192 0 R +/K [202 0 R 203 0 R]>> endobj -190 0 obj +192 0 obj <>]>> endobj -186 0 obj +188 0 obj <> -endobj -204 0 obj -<> +/P 187 0 R +/K [189 0 R 190 0 R 192 0 R]>> endobj 206 0 obj <> -endobj -205 0 obj -<>]>> -endobj -209 0 obj -<> -endobj -211 0 obj -<> -endobj -210 0 obj -<>]>> +/K 44>> endobj 208 0 obj <> +/Pg 2 0 R +/K 45>> +endobj +207 0 obj +<>]>> +endobj +211 0 obj +<> endobj 213 0 obj <> -endobj -215 0 obj -<> -endobj -214 0 obj -<>]>> +/Pg 2 0 R +/K 47>> endobj 212 0 obj <>]>> +endobj +210 0 obj +<> +/P 209 0 R +/K [211 0 R 212 0 R]>> +endobj +215 0 obj +<> endobj 217 0 obj <> -endobj -219 0 obj -<> -endobj -218 0 obj -<>]>> +/Pg 2 0 R +/K 49>> endobj 216 0 obj <>]>> +endobj +214 0 obj +<> +/P 209 0 R +/K [215 0 R 216 0 R]>> +endobj +219 0 obj +<> endobj 221 0 obj <> +/K 51>> +endobj +220 0 obj +<>]>> +endobj +218 0 obj +<> endobj 223 0 obj <> +endobj +225 0 obj +<> endobj -222 0 obj +224 0 obj <> <>]>> endobj -220 0 obj +222 0 obj <> -endobj -225 0 obj -<> +/P 209 0 R +/K [223 0 R 224 0 R]>> endobj 227 0 obj <> -endobj -226 0 obj -<>]>> -endobj -224 0 obj -<> +/K 54>> endobj 229 0 obj <> +/K 55>> +endobj +228 0 obj +<>]>> +endobj +226 0 obj +<> endobj 231 0 obj <> +endobj +233 0 obj +<> endobj -230 0 obj +232 0 obj <> <>]>> endobj -228 0 obj +230 0 obj <> -endobj -233 0 obj -<> +/P 209 0 R +/K [231 0 R 232 0 R]>> endobj 235 0 obj <> +endobj +237 0 obj +<> endobj -234 0 obj +236 0 obj <> <>]>> endobj -232 0 obj +234 0 obj <> +/P 209 0 R +/K [235 0 R 236 0 R]>> endobj -207 0 obj +209 0 obj <>]>> endobj -203 0 obj +205 0 obj <> +/P 187 0 R +/K [206 0 R 207 0 R 209 0 R]>> endobj -185 0 obj +187 0 obj <>]>> endobj -181 0 obj +183 0 obj <> -endobj -237 0 obj -<> +/P 118 0 R +/K [184 0 R 185 0 R 187 0 R]>> endobj 239 0 obj <> +endobj +241 0 obj +<> endobj -238 0 obj +240 0 obj <>]>> endobj -242 0 obj +244 0 obj <> endobj -244 0 obj +246 0 obj <> endobj -243 0 obj +245 0 obj <>]>> endobj -247 0 obj +249 0 obj <> endobj -249 0 obj +251 0 obj <> endobj -248 0 obj +250 0 obj <>]>> endobj -246 0 obj +248 0 obj <> -endobj -251 0 obj -<> +/P 247 0 R +/K [249 0 R 250 0 R]>> endobj 253 0 obj <> -endobj -252 0 obj -<>]>> -endobj -250 0 obj -<> +/K 66>> endobj 255 0 obj <> -endobj -257 0 obj -<> -endobj -256 0 obj -<>]>> +/Pg 2 0 R +/K 67>> endobj 254 0 obj <>]>> +endobj +252 0 obj +<> +/P 247 0 R +/K [253 0 R 254 0 R]>> +endobj +257 0 obj +<> endobj 259 0 obj <> +/K 69>> +endobj +258 0 obj +<>]>> +endobj +256 0 obj +<> endobj 261 0 obj <> +endobj +263 0 obj +<> endobj -260 0 obj +262 0 obj <> <>]>> endobj -258 0 obj +260 0 obj <> +/P 247 0 R +/K [261 0 R 262 0 R]>> endobj -245 0 obj +247 0 obj <>]>> endobj -241 0 obj +243 0 obj <> -endobj -263 0 obj -<> +/P 242 0 R +/K [244 0 R 245 0 R 247 0 R]>> endobj 265 0 obj <> -endobj -264 0 obj -<>]>> -endobj -268 0 obj -<> -endobj -270 0 obj -<> -endobj -269 0 obj -<>]>> +/K 72>> endobj 267 0 obj <> +/Pg 2 0 R +/K 73>> +endobj +266 0 obj +<>]>> +endobj +270 0 obj +<> endobj 272 0 obj <> -endobj -274 0 obj -<> -endobj -273 0 obj -<>]>> +/Pg 2 0 R +/K 75>> endobj 271 0 obj <>]>> +endobj +269 0 obj +<> +/P 268 0 R +/K [270 0 R 271 0 R]>> +endobj +274 0 obj +<> endobj 276 0 obj <> -endobj -278 0 obj -<> -endobj -277 0 obj -<>]>> +/Pg 2 0 R +/K 77>> endobj 275 0 obj <>]>> +endobj +273 0 obj +<> +/P 268 0 R +/K [274 0 R 275 0 R]>> +endobj +278 0 obj +<> endobj 280 0 obj <> +/K 1>> +endobj +279 0 obj +<>]>> +endobj +277 0 obj +<> endobj 282 0 obj <> +endobj +284 0 obj +<> endobj -281 0 obj +283 0 obj <> <>]>> endobj -279 0 obj +281 0 obj <> -endobj -284 0 obj -<> +/P 268 0 R +/K [282 0 R 283 0 R]>> endobj 286 0 obj <> +endobj +288 0 obj +<> endobj -285 0 obj +287 0 obj <> <>]>> endobj -283 0 obj +285 0 obj <> -endobj -288 0 obj -<> +/P 268 0 R +/K [286 0 R 287 0 R]>> endobj 290 0 obj <> +endobj +292 0 obj +<> endobj -289 0 obj +291 0 obj <> <>]>> endobj -287 0 obj +289 0 obj <> +/P 268 0 R +/K [290 0 R 291 0 R]>> endobj -266 0 obj +268 0 obj <>]>> endobj -262 0 obj +264 0 obj <> +/P 242 0 R +/K [265 0 R 266 0 R 268 0 R]>> endobj -240 0 obj +242 0 obj <>]>> endobj -236 0 obj +238 0 obj <> -endobj -292 0 obj -<> +/P 118 0 R +/K [239 0 R 240 0 R 242 0 R]>> endobj 294 0 obj <> +endobj +296 0 obj +<> endobj -293 0 obj +295 0 obj <>]>> endobj -297 0 obj +299 0 obj <> endobj -299 0 obj +301 0 obj <> endobj -298 0 obj +300 0 obj <>]>> endobj -302 0 obj +304 0 obj <> endobj -304 0 obj +306 0 obj <> endobj -303 0 obj +305 0 obj <>]>> endobj -301 0 obj +303 0 obj <> -endobj -306 0 obj -<> +/P 302 0 R +/K [304 0 R 305 0 R]>> endobj 308 0 obj <> -endobj -307 0 obj -<>]>> -endobj -305 0 obj -<> +/K 14>> endobj 310 0 obj <> +/K 15>> +endobj +309 0 obj +<>]>> +endobj +307 0 obj +<> endobj 312 0 obj <> +endobj +314 0 obj +<> endobj -311 0 obj +313 0 obj <> <>]>> endobj -309 0 obj +311 0 obj <> +/P 302 0 R +/K [312 0 R 313 0 R]>> endobj -300 0 obj +302 0 obj <>]>> endobj -296 0 obj +298 0 obj <> -endobj -314 0 obj -<> +/P 297 0 R +/K [299 0 R 300 0 R 302 0 R]>> endobj 316 0 obj <> -endobj -315 0 obj -<>]>> -endobj -319 0 obj -<> -endobj -321 0 obj -<> -endobj -320 0 obj -<>]>> +/K 18>> endobj 318 0 obj <> -endobj -323 0 obj -<> -endobj -325 0 obj -<> -endobj -324 0 obj -<>]>> -endobj -322 0 obj -<> +/Pg 51 0 R +/K 19>> endobj 317 0 obj <>]>> +/S /Link +/P 315 0 R +/K [318 0 R <>]>> endobj -313 0 obj +321 0 obj +<> +endobj +323 0 obj +<> +endobj +322 0 obj +<>]>> +endobj +320 0 obj <> +/P 319 0 R +/K [321 0 R 322 0 R]>> endobj -295 0 obj +325 0 obj <>]>> -endobj -291 0 obj -<> +/S /Lbl +/P 324 0 R +/Pg 51 0 R +/K 22>> endobj 327 0 obj <> -endobj -329 0 obj -<> -endobj -328 0 obj -<>]>> -endobj -332 0 obj -<> -endobj -334 0 obj -<> -endobj -333 0 obj -<>]>> -endobj -337 0 obj -<> -endobj -339 0 obj -<> -endobj -338 0 obj -<>]>> -endobj -336 0 obj -<> -endobj -341 0 obj -<> -endobj -343 0 obj -<> -endobj -342 0 obj -<>]>> -endobj -340 0 obj -<> -endobj -335 0 obj -<>]>> -endobj -331 0 obj -<> -endobj -345 0 obj -<> -endobj -347 0 obj -<> -endobj -346 0 obj -<>]>> -endobj -350 0 obj -<> -endobj -352 0 obj -<> -endobj -351 0 obj -<>]>> -endobj -349 0 obj -<> -endobj -354 0 obj -<> -endobj -356 0 obj -<> -endobj -355 0 obj -<>]>> -endobj -353 0 obj -<> -endobj -348 0 obj -<>]>> -endobj -344 0 obj -<> -endobj -330 0 obj -<>]>> +/K 23>> endobj 326 0 obj <> +/S /Link +/P 324 0 R +/K [327 0 R <>]>> endobj -116 0 obj -<>]>> -endobj -112 0 obj +324 0 obj <> +/P 319 0 R +/K [325 0 R 326 0 R]>> endobj -111 0 obj +319 0 obj <>]>> +/ListNumbering /Square>>]>> +endobj +315 0 obj +<> +endobj +297 0 obj +<>]>> +endobj +293 0 obj +<> +endobj +329 0 obj +<> +endobj +331 0 obj +<> +endobj +330 0 obj +<>]>> +endobj +334 0 obj +<> +endobj +336 0 obj +<> +endobj +335 0 obj +<>]>> +endobj +339 0 obj +<> +endobj +341 0 obj +<> +endobj +340 0 obj +<>]>> +endobj +338 0 obj +<> +endobj +343 0 obj +<> +endobj +345 0 obj +<> +endobj +344 0 obj +<>]>> +endobj +342 0 obj +<> +endobj +337 0 obj +<>]>> +endobj +333 0 obj +<> +endobj +347 0 obj +<> +endobj +349 0 obj +<> +endobj +348 0 obj +<>]>> +endobj +352 0 obj +<> +endobj +354 0 obj +<> +endobj +353 0 obj +<>]>> +endobj +351 0 obj +<> +endobj +356 0 obj +<> endobj 358 0 obj <> +/K 37>> endobj 357 0 obj <> +/S /Link +/P 355 0 R +/K [358 0 R <>]>> +endobj +355 0 obj +<> +endobj +350 0 obj +<>]>> +endobj +346 0 obj +<> +endobj +332 0 obj +<>]>> +endobj +328 0 obj +<> +endobj +118 0 obj +<>]>> +endobj +114 0 obj +<> +endobj +113 0 obj +<>]>> endobj 360 0 obj <> +/K 38>> endobj 359 0 obj <> endobj 362 0 obj @@ -3097,12 +3124,12 @@ endobj /S /NonStruct /P 361 0 R /Pg 51 0 R -/K 40>> +/K 39>> endobj 361 0 obj <> endobj 364 0 obj @@ -3110,270 +3137,270 @@ endobj /S /NonStruct /P 363 0 R /Pg 51 0 R -/K 41>> +/K 40>> endobj 363 0 obj <> endobj -367 0 obj -<> -endobj 366 0 obj <> -endobj -368 0 obj -<> +/K 41>> endobj 365 0 obj <> +/S /H3 +/P 110 0 R +/K 366 0 R>> +endobj +369 0 obj +<> +endobj +368 0 obj +<> endobj 370 0 obj <> +/K 43>> endobj -369 0 obj +367 0 obj <> +/S /P +/P 110 0 R +/K [368 0 R 370 0 R]>> endobj 372 0 obj <> +/K 44>> +endobj +371 0 obj +<> endobj 374 0 obj <> +/K 45>> endobj -373 0 obj +376 0 obj <> +/S /NonStruct +/P 375 0 R +/Pg 51 0 R +/K 46>> endobj 375 0 obj <> +endobj +377 0 obj +<> endobj -371 0 obj +373 0 obj <> +/P 110 0 R +/K [374 0 R 375 0 R 377 0 R]>> endobj -378 0 obj +380 0 obj <> endobj -380 0 obj +382 0 obj +<> +endobj +381 0 obj +<> +endobj +383 0 obj <> +/K 50>> endobj 379 0 obj <> -endobj -381 0 obj -<> -endobj -377 0 obj -<> -endobj -383 0 obj -<> +/P 378 0 R +/K [380 0 R 381 0 R 383 0 R]>> endobj 385 0 obj <> +endobj +387 0 obj +<> endobj -384 0 obj -<> -endobj 386 0 obj <> -endobj -382 0 obj -<> -endobj -376 0 obj -<>]>> +/S /Strong +/P 384 0 R +/K 387 0 R>> endobj 388 0 obj <> +/P 384 0 R +/Pg 51 0 R +/K 53>> endobj -387 0 obj +384 0 obj <> +/S /LI +/P 378 0 R +/K [385 0 R 386 0 R 388 0 R]>> +endobj +378 0 obj +<>]>> endobj 390 0 obj <> -endobj -391 0 obj -<> -endobj -393 0 obj -<> -endobj -392 0 obj -<> +/K 0>> endobj 389 0 obj <> +/P 110 0 R +/K 390 0 R>> +endobj +392 0 obj +<> +endobj +393 0 obj +<> endobj 395 0 obj <> +/K 3>> endobj 394 0 obj <> endobj -398 0 obj +391 0 obj <> +/S /P +/P 110 0 R +/K [392 0 R 393 0 R 394 0 R]>> endobj 397 0 obj <> -endobj -399 0 obj -<> +/K 4>> endobj 396 0 obj <> +/S /H3 +/P 110 0 R +/K 397 0 R>> +endobj +400 0 obj +<> +endobj +399 0 obj +<> endobj 401 0 obj <> +/K 6>> endobj -400 0 obj +398 0 obj <> +/S /P +/P 110 0 R +/K [399 0 R 401 0 R]>> endobj 403 0 obj <> +/K 7>> endobj 402 0 obj <> endobj 405 0 obj @@ -3381,12 +3408,12 @@ endobj /S /NonStruct /P 404 0 R /Pg 77 0 R -/K 9>> +/K 8>> endobj 404 0 obj <> endobj 407 0 obj @@ -3394,266 +3421,266 @@ endobj /S /NonStruct /P 406 0 R /Pg 77 0 R -/K 10>> +/K 9>> endobj 406 0 obj <> endobj -410 0 obj -<> -endobj -411 0 obj +409 0 obj <> +/K 10>> +endobj +408 0 obj +<> +endobj +412 0 obj +<> endobj 413 0 obj <> +endobj +415 0 obj +<> endobj -412 0 obj -<> -endobj 414 0 obj <> -endobj -409 0 obj -<> +/S /Strong +/P 411 0 R +/K 415 0 R>> endobj 416 0 obj <> +endobj +411 0 obj +<> +endobj +418 0 obj +<> endobj -417 0 obj -<> -endobj 419 0 obj <> +endobj +421 0 obj +<> endobj -418 0 obj -<> -endobj 420 0 obj <> -endobj -415 0 obj -<> +/S /Strong +/P 417 0 R +/K 421 0 R>> endobj 422 0 obj <> +endobj +417 0 obj +<> +endobj +424 0 obj +<> endobj -423 0 obj -<> -endobj 425 0 obj <> +endobj +427 0 obj +<> endobj -424 0 obj -<> -endobj 426 0 obj <> -endobj -421 0 obj -<> +/S /Strong +/P 423 0 R +/K 427 0 R>> endobj 428 0 obj <> +endobj +423 0 obj +<> +endobj +430 0 obj +<> endobj -429 0 obj -<> -endobj 431 0 obj <> +endobj +433 0 obj +<> endobj -430 0 obj -<> -endobj 432 0 obj <> -endobj -427 0 obj -<> +/S /Strong +/P 429 0 R +/K 433 0 R>> endobj 434 0 obj <> +endobj +429 0 obj +<> +endobj +436 0 obj +<> endobj -435 0 obj -<> -endobj 437 0 obj <> -endobj -436 0 obj -<> -endobj -438 0 obj -<> -endobj -433 0 obj -<> -endobj -440 0 obj -<> -endobj -441 0 obj -<> +/K 28>> endobj 439 0 obj <> +/S /NonStruct +/P 438 0 R +/Pg 77 0 R +/K 29>> endobj -408 0 obj +438 0 obj <>]>> +/S /Strong +/P 435 0 R +/K 439 0 R>> +endobj +440 0 obj +<> +endobj +435 0 obj +<> +endobj +442 0 obj +<> endobj 443 0 obj <> +/K 32>> endobj -442 0 obj +441 0 obj <> +/S /LI +/P 410 0 R +/K [442 0 R 443 0 R]>> +endobj +410 0 obj +<>]>> endobj 445 0 obj <> +/K 33>> endobj 444 0 obj <> endobj 447 0 obj @@ -3661,27 +3688,27 @@ endobj /S /NonStruct /P 446 0 R /Pg 77 0 R -/K [35 <>]>> +/K 34>> endobj 446 0 obj <> endobj 449 0 obj <> +/MCID 1>>]>> endobj 448 0 obj <> endobj 451 0 obj @@ -3689,12 +3716,12 @@ endobj /S /NonStruct /P 450 0 R /Pg 82 0 R -/K 3>> +/K 2>> endobj 450 0 obj <> endobj 453 0 obj @@ -3702,71 +3729,71 @@ endobj /S /NonStruct /P 452 0 R /Pg 82 0 R -/K 4>> +/K 3>> endobj 452 0 obj <> endobj -457 0 obj -<> -endobj -456 0 obj -<> -endobj -458 0 obj -<> -endobj 455 0 obj <> +/Pg 82 0 R +/K 4>> endobj 454 0 obj <> +endobj +459 0 obj +<> +/K 5>> +endobj +458 0 obj +<> endobj 460 0 obj <> +/K 6>> endobj -459 0 obj +457 0 obj <> +/S /P +/P 456 0 R +/K [458 0 R 460 0 R]>> +endobj +456 0 obj +<> endobj 462 0 obj <> +/K 7>> endobj 461 0 obj <> endobj 464 0 obj @@ -3774,2290 +3801,2812 @@ endobj /S /NonStruct /P 463 0 R /Pg 82 0 R -/K 9>> +/K 8>> +endobj +463 0 obj +<> endobj 466 0 obj <> +/K 9>> endobj -465 0 obj +468 0 obj <> +/S /NonStruct +/P 467 0 R +/Pg 82 0 R +/K 10>> endobj 467 0 obj <> +/S /Em +/P 465 0 R +/K 468 0 R>> endobj 469 0 obj <> +endobj +471 0 obj +<> endobj -468 0 obj -<> -endobj 470 0 obj <> -endobj -463 0 obj -<> +/S /Em +/P 465 0 R +/K 471 0 R>> endobj 472 0 obj <> +/K 13>> endobj -471 0 obj +465 0 obj <> +/S /P +/P 110 0 R +/K [466 0 R 467 0 R 469 0 R 470 0 R 472 0 R]>> endobj 474 0 obj <> +/K 14>> +endobj +473 0 obj +<> endobj 476 0 obj <> +/K 15>> endobj -475 0 obj +478 0 obj <> +/S /NonStruct +/P 477 0 R +/Pg 82 0 R +/K 16>> endobj 477 0 obj <> +/S /Em +/P 475 0 R +/K 478 0 R>> endobj 479 0 obj <> -endobj -478 0 obj -<> -endobj -480 0 obj -<> +/K 17>> endobj 481 0 obj < -/P 473 0 R -/Pg 86 0 R -/K 0>> -endobj -483 0 obj -<> +/P 480 0 R +/Pg 82 0 R +/K 18>> +endobj +480 0 obj +<> endobj 482 0 obj <> +/S /NonStruct +/P 475 0 R +/Pg 82 0 R +/K 19>> endobj -473 0 obj +483 0 obj <> +/S /Figure +/Alt +/P 475 0 R +/Pg 86 0 R +/K 0>> endobj 485 0 obj <> +/K 1>> endobj 484 0 obj <> endobj +475 0 obj +<> +endobj 487 0 obj <> +/K 2>> +endobj +486 0 obj +<> endobj 489 0 obj <> +/K 3>> endobj -488 0 obj +491 0 obj <> +/S /NonStruct +/P 490 0 R +/Pg 86 0 R +/K 4>> endobj 490 0 obj <> +/S /Em +/P 488 0 R +/K 491 0 R>> endobj 492 0 obj <> +endobj +494 0 obj +<> endobj -491 0 obj -<> -endobj 493 0 obj <> -endobj -486 0 obj -<> +/S /Em +/P 488 0 R +/K 494 0 R>> endobj 495 0 obj <> +/K 7>> endobj -494 0 obj +488 0 obj <> +/S /P +/P 110 0 R +/K [489 0 R 490 0 R 492 0 R 493 0 R 495 0 R]>> endobj 497 0 obj <> +/K 8>> +endobj +496 0 obj +<> endobj 499 0 obj <> +/K 9>> endobj -498 0 obj +501 0 obj <> +/S /NonStruct +/P 500 0 R +/Pg 86 0 R +/K 10>> endobj 500 0 obj <> +/S /Em +/P 498 0 R +/K 501 0 R>> endobj 502 0 obj <> +endobj +504 0 obj +<> endobj -501 0 obj -<> -endobj 503 0 obj <> -endobj -496 0 obj -<> +/S /Em +/P 498 0 R +/K 504 0 R>> endobj 505 0 obj <> +/K 13>> endobj -504 0 obj +498 0 obj <> +/S /P +/P 110 0 R +/K [499 0 R 500 0 R 502 0 R 503 0 R 505 0 R]>> endobj 507 0 obj <> +/K 14>> endobj 506 0 obj <> endobj -509 0 obj +510 0 obj <> -endobj -508 0 obj -<> +/K 15>> endobj 511 0 obj <> +endobj +509 0 obj +<> +endobj +513 0 obj +<> endobj -510 0 obj -<> -endobj 514 0 obj <> endobj +512 0 obj +<> +endobj 516 0 obj <> endobj -515 0 obj +517 0 obj <> -endobj -513 0 obj -<> -endobj -518 0 obj -<> endobj +515 0 obj +<> +endobj +519 0 obj +<> +endobj 520 0 obj <> -endobj -519 0 obj -<> -endobj -521 0 obj -<> endobj -517 0 obj +518 0 obj <> +/P 508 0 R +/K [519 0 R 520 0 R]>> +endobj +522 0 obj +<> endobj 523 0 obj <> +/K 24>> +endobj +521 0 obj +<> +endobj +508 0 obj +<>]>> endobj 525 0 obj <> +/K 25>> endobj 524 0 obj <> endobj -522 0 obj -<> -endobj 527 0 obj <> +/K 26>> +endobj +526 0 obj +<> endobj 529 0 obj <> +/K 27>> endobj 528 0 obj <> -endobj -526 0 obj -<> -endobj -512 0 obj -<>]>> -endobj -531 0 obj -<> -endobj -530 0 obj -<> -endobj -533 0 obj -<> -endobj -535 0 obj -<> -endobj -534 0 obj -<> +/P 110 0 R +/K 529 0 R>> endobj 532 0 obj <> +/S /Lbl +/P 531 0 R +/Pg 86 0 R +/K 28>> endobj -537 0 obj +534 0 obj <> +/P 533 0 R +/Pg 86 0 R +/K 29>> +endobj +533 0 obj +<> +endobj +531 0 obj +<> endobj 536 0 obj <> +/S /Lbl +/P 535 0 R +/Pg 86 0 R +/K 30>> +endobj +538 0 obj +<> +endobj +537 0 obj +<> endobj 539 0 obj <> +/P 535 0 R +/Pg 86 0 R +/K 32>> endobj -538 0 obj +535 0 obj <> +/S /LI +/P 530 0 R +/K [536 0 R 537 0 R 539 0 R]>> endobj 541 0 obj <> -endobj -540 0 obj -<> +/Pg 86 0 R +/K 33>> endobj 543 0 obj <> +/Pg 86 0 R +/K 34>> endobj 542 0 obj <> endobj +540 0 obj +<> +endobj +545 0 obj +<> +endobj 547 0 obj <> +/Pg 86 0 R +/K 36>> endobj 546 0 obj <> -endobj -548 0 obj -<> -endobj -545 0 obj -<> +/K 547 0 R>> endobj 544 0 obj <> +/S /LI +/P 530 0 R +/K [545 0 R 546 0 R]>> endobj -550 0 obj +530 0 obj <> +/S /L +/P 110 0 R +/K [531 0 R 535 0 R 540 0 R 544 0 R] +/A [<>]>> endobj 549 0 obj <> -endobj -552 0 obj -<> +/K 1>> +endobj +548 0 obj +<> endobj 551 0 obj <> +/S /Figure +/Alt (Gefaellestrecke) +/P 550 0 R +/Pg 89 0 R +/K 2>> endobj -554 0 obj +553 0 obj <> +/K 3>> endobj -556 0 obj +552 0 obj <> +/S /Em +/P 550 0 R +/K 553 0 R>> +endobj +550 0 obj +<> endobj 555 0 obj <> +/S /NonStruct +/P 554 0 R +/Pg 89 0 R +/K 4>> +endobj +554 0 obj +<> endobj 557 0 obj <> +/K 5>> +endobj +556 0 obj +<> endobj 559 0 obj <> +/K 6>> endobj 558 0 obj <> endobj -560 0 obj -<> -endobj -562 0 obj -<> -endobj 561 0 obj <> -endobj -563 0 obj -<> +/K 7>> endobj -553 0 obj +560 0 obj <> +/S /H4 +/P 110 0 R +/K 561 0 R>> endobj 565 0 obj <> +/K 8>> endobj 564 0 obj <> endobj -567 0 obj +566 0 obj <> +/K 9>> endobj -569 0 obj +563 0 obj <> +endobj +562 0 obj +<> +/K [0 563 0 R]>> endobj 568 0 obj <> +/S /NonStruct +/P 567 0 R +/Pg 89 0 R +/K 10>> +endobj +567 0 obj +<> endobj 570 0 obj <> +/K 11>> endobj -566 0 obj +569 0 obj <> +/S /H4 +/P 110 0 R +/K 570 0 R>> endobj 572 0 obj <> -endobj -571 0 obj -<> +/K 12>> endobj 574 0 obj <> +/K 13>> endobj -576 0 obj +573 0 obj <> +/S /Em +/P 571 0 R +/K 574 0 R>> endobj 575 0 obj <> +/S /NonStruct +/P 571 0 R +/Pg 89 0 R +/K 14>> endobj 577 0 obj <> +/K 15>> endobj -573 0 obj +576 0 obj <> -endobj -579 0 obj -<> +/S /Em +/P 571 0 R +/K 577 0 R>> endobj 578 0 obj <> +/S /NonStruct +/P 571 0 R +/Pg 89 0 R +/K 16>> +endobj +580 0 obj +<> +endobj +579 0 obj +<> endobj 581 0 obj <> +/K 18>> endobj -580 0 obj +571 0 obj <> +/S /P +/P 110 0 R +/K [572 0 R 573 0 R 575 0 R 576 0 R 578 0 R 579 0 R 581 0 R]>> endobj 583 0 obj <> +/Pg 89 0 R +/K 19>> endobj 582 0 obj <> endobj 585 0 obj <> -endobj -584 0 obj -<> +/Pg 89 0 R +/K 20>> endobj 587 0 obj <> +/Pg 89 0 R +/K 21>> endobj 586 0 obj <> endobj -589 0 obj -<> -endobj 588 0 obj <> -endobj -591 0 obj -<> +/P 584 0 R +/Pg 89 0 R +/K 22>> +endobj +584 0 obj +<> endobj 590 0 obj <> -endobj -593 0 obj -<> +/P 589 0 R +/Pg 89 0 R +/K 23>> +endobj +589 0 obj +<> endobj 592 0 obj <> +/S /NonStruct +/P 591 0 R +/Pg 89 0 R +/K 24>> endobj -596 0 obj -<> -endobj -598 0 obj +594 0 obj <> +/P 593 0 R +/Pg 89 0 R +/K 25>> +endobj +593 0 obj +<> +endobj +595 0 obj +<> +endobj +591 0 obj +<> endobj 597 0 obj <> +/S /NonStruct +/P 596 0 R +/Pg 92 0 R +/K 0>> +endobj +596 0 obj +<> endobj 599 0 obj <> +/K 1>> endobj -595 0 obj +598 0 obj <> +/S /H4 +/P 110 0 R +/K 599 0 R>> endobj 601 0 obj <> +/K 2>> +endobj +600 0 obj +<> endobj 603 0 obj <> +/K 3>> endobj 602 0 obj <> endobj -604 0 obj -<> -endobj -600 0 obj -<> -endobj -606 0 obj -<> -endobj -608 0 obj -<> -endobj -607 0 obj -<> -endobj -609 0 obj -<> -endobj 605 0 obj <> +/S /NonStruct +/P 604 0 R +/Pg 92 0 R +/K 4>> endobj -594 0 obj +604 0 obj <>]>> +/S /H2 +/P 110 0 R +/K 605 0 R>> +endobj +607 0 obj +<> +endobj +606 0 obj +<> +endobj +610 0 obj +<> endobj 611 0 obj <> +/K 7>> endobj -612 0 obj +609 0 obj <> +endobj +613 0 obj +<> +/K 8>> endobj 614 0 obj <> +/K 9>> endobj -613 0 obj +612 0 obj <> -endobj -610 0 obj -<> +/S /LI +/P 608 0 R +/K [613 0 R 614 0 R]>> endobj 616 0 obj <> +endobj +617 0 obj +<> +/K 11>> endobj -615 0 obj +620 0 obj <> -endobj -618 0 obj -<> -endobj -617 0 obj -<> +/K 12>> endobj 621 0 obj <> +/K 13>> +endobj +619 0 obj +<> endobj 623 0 obj <> -endobj -622 0 obj -<> +/K 14>> endobj 624 0 obj <> +/K 15>> endobj -620 0 obj +622 0 obj <> +/P 618 0 R +/K [623 0 R 624 0 R]>> endobj 626 0 obj <> -endobj -628 0 obj -<> +/K 16>> endobj 627 0 obj <> -endobj -629 0 obj -<> +/K 17>> endobj 625 0 obj <> +/P 618 0 R +/K [626 0 R 627 0 R]>> endobj -619 0 obj +618 0 obj <>]>> +endobj +615 0 obj +<> +endobj +608 0 obj +<>]>> endobj +629 0 obj +<> +endobj +631 0 obj +<> +endobj +630 0 obj +<> +endobj 632 0 obj <> +/K 20>> endobj -631 0 obj +628 0 obj <> -endobj -633 0 obj -<> -endobj -635 0 obj -<> +/S /P +/P 110 0 R +/K [629 0 R 630 0 R 632 0 R]>> endobj 634 0 obj <> +/S /NonStruct +/P 633 0 R +/Pg 92 0 R +/K 21>> endobj 636 0 obj <> +/K 22>> endobj -638 0 obj +635 0 obj <> +/S /Strong +/P 633 0 R +/K 636 0 R>> endobj 637 0 obj <> +/S /NonStruct +/P 633 0 R +/Pg 92 0 R +/K 23>> +endobj +633 0 obj +<> endobj 639 0 obj <> -endobj -630 0 obj -<> +/K 24>> endobj 641 0 obj <> +/K 25>> endobj 640 0 obj <> endobj -643 0 obj -<> -endobj 642 0 obj <> +/S /NonStruct +/P 638 0 R +/Pg 92 0 R +/K 26>> +endobj +644 0 obj +<> +endobj +643 0 obj +<> endobj 645 0 obj <> +/P 638 0 R +/Pg 92 0 R +/K 28>> endobj -644 0 obj +638 0 obj <> +/P 110 0 R +/K [639 0 R 640 0 R 642 0 R 643 0 R 645 0 R]>> +endobj +648 0 obj +<> +endobj +649 0 obj +<> endobj 647 0 obj <> -endobj -646 0 obj -<> +/K [648 0 R 649 0 R]>> endobj 651 0 obj <> -endobj -650 0 obj -<> +/Pg 92 0 R +/K 31>> endobj 652 0 obj <> +/P 650 0 R +/Pg 92 0 R +/K 32>> endobj -649 0 obj +650 0 obj <> +/S /LI +/P 646 0 R +/K [651 0 R 652 0 R]>> endobj -648 0 obj +646 0 obj <> +/S /L +/P 110 0 R +/K [647 0 R 650 0 R] +/A [<>]>> endobj 654 0 obj <> -endobj -653 0 obj -<> +/Pg 92 0 R +/K 33>> endobj 656 0 obj <> +/Pg 92 0 R +/K 34>> endobj 655 0 obj <> endobj -658 0 obj +657 0 obj <> +/P 653 0 R +/Pg 92 0 R +/K 35>> +endobj +653 0 obj +<> endobj 660 0 obj <> -endobj -659 0 obj -<> +/Pg 92 0 R +/K 36>> endobj 661 0 obj <> +/P 659 0 R +/Pg 92 0 R +/K 37>> endobj -657 0 obj +659 0 obj <> +/S /LI +/P 658 0 R +/K [660 0 R 661 0 R]>> +endobj +663 0 obj +<> endobj 664 0 obj <> +/S /NonStruct +/P 662 0 R +/Pg 92 0 R +/K 39>> +endobj +662 0 obj +<> +endobj +658 0 obj +<>]>> endobj 666 0 obj <> +/Pg 92 0 R +/K 40>> endobj 665 0 obj <> endobj -667 0 obj -<> -endobj -663 0 obj -<> -endobj -669 0 obj -<> -endobj -671 0 obj -<> -endobj -670 0 obj -<> -endobj -672 0 obj -<> -endobj 668 0 obj <> +/S /NonStruct +/P 667 0 R +/Pg 92 0 R +/K 41>> +endobj +667 0 obj +<> +endobj +670 0 obj +<> +endobj +669 0 obj +<> +endobj +673 0 obj +<> +endobj +675 0 obj +<> endobj 674 0 obj <> +/S /Strong +/P 672 0 R +/K 675 0 R>> endobj 676 0 obj <> +/P 672 0 R +/Pg 94 0 R +/K 3>> endobj -675 0 obj +672 0 obj <> -endobj -677 0 obj -<> -endobj -679 0 obj -<> +/S /LI +/P 671 0 R +/K [673 0 R 674 0 R 676 0 R]>> endobj 678 0 obj <> +/S /Lbl +/P 677 0 R +/Pg 94 0 R +/K 4>> endobj 680 0 obj <> +/P 679 0 R +/Pg 94 0 R +/K 5>> endobj -673 0 obj +679 0 obj <> +/S /Strong +/P 677 0 R +/K 680 0 R>> endobj -682 0 obj -<> -endobj -684 0 obj +681 0 obj <> +/P 677 0 R +/Pg 94 0 R +/K 6>> +endobj +677 0 obj +<> endobj 683 0 obj <> +/S /Lbl +/P 682 0 R +/Pg 94 0 R +/K 7>> endobj 685 0 obj <> +/P 684 0 R +/Pg 94 0 R +/K 8>> endobj -681 0 obj +684 0 obj +<> +endobj +686 0 obj +<> +endobj +682 0 obj <> +/P 671 0 R +/K [683 0 R 684 0 R 686 0 R]>> endobj -662 0 obj +671 0 obj <>]>> endobj -687 0 obj -<> -endobj 688 0 obj <> -endobj -690 0 obj -<> +/P 687 0 R +/Pg 94 0 R +/K 10>> endobj 689 0 obj <> +/S /Figure +/Alt (Variofoerderer) +/P 687 0 R +/Pg 94 0 R +/K 11>> endobj -686 0 obj +691 0 obj +<> +endobj +690 0 obj +<> +endobj +687 0 obj <> -endobj -692 0 obj -<> +/P 110 0 R +/K [688 0 R 689 0 R 690 0 R]>> endobj 693 0 obj <> +/P 692 0 R +/Pg 94 0 R +/K 13>> +endobj +692 0 obj +<> endobj 695 0 obj <> +/Pg 94 0 R +/K 14>> endobj 694 0 obj <> -endobj -691 0 obj -<> -endobj -697 0 obj -<> -endobj -696 0 obj -<> -endobj -699 0 obj -<> +/P 110 0 R +/K 695 0 R>> endobj 698 0 obj <> +/S /Lbl +/P 697 0 R +/Pg 94 0 R +/K 15>> +endobj +700 0 obj +<> +endobj +699 0 obj +<> endobj 701 0 obj <> +/P 697 0 R +/Pg 94 0 R +/K 17>> endobj -700 0 obj +697 0 obj <> +/S /LI +/P 696 0 R +/K [698 0 R 699 0 R 701 0 R]>> endobj 703 0 obj <> -endobj -702 0 obj -<> +/Pg 94 0 R +/K 18>> endobj 705 0 obj <> +/Pg 94 0 R +/K 19>> endobj 704 0 obj <> endobj -707 0 obj -<> -endobj 706 0 obj <> +/S /NonStruct +/P 702 0 R +/Pg 94 0 R +/K 20>> +endobj +702 0 obj +<> +endobj +696 0 obj +<>]>> endobj 709 0 obj <> +/Pg 94 0 R +/K 21>> endobj 708 0 obj <> endobj -711 0 obj -<> -endobj 710 0 obj <> +/S /NonStruct +/P 707 0 R +/Pg 94 0 R +/K 22>> +endobj +712 0 obj +<> +endobj +711 0 obj +<> endobj 713 0 obj <> -endobj -712 0 obj -<> +/P 707 0 R +/Pg 94 0 R +/K 24>> endobj 715 0 obj <> +/Pg 94 0 R +/K 25>> endobj -717 0 obj +714 0 obj <> +/S /Strong +/P 707 0 R +/K 715 0 R>> endobj 716 0 obj <> +/S /NonStruct +/P 707 0 R +/Pg 94 0 R +/K 26>> +endobj +707 0 obj +<> endobj 718 0 obj <> +/P 717 0 R +/Pg 94 0 R +/K 27>> endobj -714 0 obj +717 0 obj <> +/S /H4 +/P 110 0 R +/K 718 0 R>> endobj 720 0 obj <> +/Pg 94 0 R +/K 28>> endobj 719 0 obj <> endobj 722 0 obj <> +/Pg 94 0 R +/K 29>> endobj 721 0 obj <> endobj 724 0 obj <> -endobj -726 0 obj -<> -endobj -725 0 obj -<> -endobj -727 0 obj -<> +/Pg 94 0 R +/K 30>> endobj 723 0 obj <> +/S /H4 +/P 110 0 R +/K 724 0 R>> +endobj +728 0 obj +<> +endobj +727 0 obj +<> endobj 729 0 obj <> +/P 726 0 R +/Pg 94 0 R +/K 32>> endobj -728 0 obj +726 0 obj <> +/S /P +/P 725 0 R +/K [727 0 R 729 0 R]>> +endobj +725 0 obj +<> endobj 731 0 obj <> +/Pg 94 0 R +/K 33>> +endobj +730 0 obj +<> endobj 733 0 obj <> +/Pg 94 0 R +/K 34>> endobj 732 0 obj <> endobj -734 0 obj -<> -endobj -736 0 obj -<> -endobj 735 0 obj <> +/S /NonStruct +/P 734 0 R +/Pg 97 0 R +/K 0>> endobj 737 0 obj <> +/P 736 0 R +/Pg 97 0 R +/K 1>> endobj -730 0 obj +736 0 obj <> -endobj -739 0 obj -<> -endobj -741 0 obj -<> -endobj -740 0 obj -<> -endobj -742 0 obj -<> +/S /Em +/P 734 0 R +/K 737 0 R>> endobj 738 0 obj <> +endobj +734 0 obj +<> +/P 110 0 R +/K [735 0 R 736 0 R 738 0 R]>> +endobj +741 0 obj +<> +endobj +743 0 obj +<> +endobj +742 0 obj +<> endobj 744 0 obj <> +/P 740 0 R +/Pg 97 0 R +/K 5>> endobj -743 0 obj +740 0 obj <> +/S /LI +/P 739 0 R +/K [741 0 R 742 0 R 744 0 R]>> endobj 746 0 obj <> -endobj -745 0 obj -<> +/Pg 97 0 R +/K 6>> endobj 748 0 obj <> -endobj -750 0 obj -<> -endobj -749 0 obj -<> -endobj -751 0 obj -<> +/Pg 97 0 R +/K 7>> endobj 747 0 obj <> +/S /Strong +/P 745 0 R +/K 748 0 R>> +endobj +749 0 obj +<> +endobj +745 0 obj +<> +endobj +751 0 obj +<> endobj 753 0 obj <> +/Pg 97 0 R +/K 10>> endobj 752 0 obj <> endobj +754 0 obj +<> +endobj +756 0 obj +<> +endobj 755 0 obj <> +/S /Strong +/P 750 0 R +/K 756 0 R>> endobj 757 0 obj <> +/P 750 0 R +/Pg 97 0 R +/K 13>> endobj -756 0 obj +750 0 obj <> -endobj -758 0 obj -<> -endobj -754 0 obj -<> -endobj -760 0 obj -<> +/S /LI +/P 739 0 R +/K [751 0 R 752 0 R 754 0 R 755 0 R 757 0 R]>> endobj 759 0 obj <> +/S /Lbl +/P 758 0 R +/Pg 97 0 R +/K 14>> +endobj +761 0 obj +<> +endobj +760 0 obj +<> endobj 762 0 obj <> +/P 758 0 R +/Pg 97 0 R +/K 16>> endobj -761 0 obj +758 0 obj <> +/S /LI +/P 739 0 R +/K [759 0 R 760 0 R 762 0 R]>> +endobj +739 0 obj +<>]>> endobj 764 0 obj <> -endobj -763 0 obj -<> -endobj -766 0 obj -<> +/Pg 97 0 R +/K 17>> endobj 765 0 obj <> -endobj -768 0 obj -<> +/P 763 0 R +/Pg 97 0 R +/K 18>> endobj 767 0 obj <> +endobj +766 0 obj +<> +endobj +763 0 obj +<> +/P 110 0 R +/K [764 0 R 765 0 R 766 0 R]>> +endobj +769 0 obj +<> endobj 770 0 obj <> +/P 768 0 R +/Pg 97 0 R +/K 21>> endobj -769 0 obj +772 0 obj <> +/S /NonStruct +/P 771 0 R +/Pg 97 0 R +/K 22>> +endobj +771 0 obj +<> +endobj +768 0 obj +<> endobj 774 0 obj <> +/Pg 97 0 R +/K 23>> endobj 773 0 obj <> endobj -775 0 obj -<> -endobj -772 0 obj -<> -endobj -771 0 obj -<> -endobj -777 0 obj -<> -endobj 776 0 obj <> -endobj -779 0 obj -<> +/P 775 0 R +/Pg 97 0 R +/K 24>> +endobj +775 0 obj +<> endobj 778 0 obj <> +endobj +777 0 obj +<> +/P 110 0 R +/K 778 0 R>> endobj -781 0 obj +780 0 obj <> +/P 779 0 R +/Pg 97 0 R +/K 26>> endobj -783 0 obj +779 0 obj <> +/S /H4 +/P 110 0 R +/K 780 0 R>> endobj 782 0 obj <> +/S /NonStruct +/P 781 0 R +/Pg 97 0 R +/K 27>> +endobj +781 0 obj +<> endobj 784 0 obj <> +/MCID 0>>]>> +endobj +783 0 obj +<> endobj 786 0 obj <> +/K 1>> endobj 785 0 obj <> endobj -787 0 obj -<> -endobj -780 0 obj -<> -endobj -789 0 obj -<> -endobj 788 0 obj <> +/S /NonStruct +/P 787 0 R +/Pg 101 0 R +/K 2>> endobj -108 0 obj +787 0 obj +<> +endobj +790 0 obj +<> +endobj +789 0 obj +<> +endobj +792 0 obj +<> +endobj +794 0 obj +<> +endobj +793 0 obj +<> +endobj +795 0 obj +<> +endobj +791 0 obj +<> +endobj +797 0 obj +<> +endobj +796 0 obj +<> +endobj +799 0 obj +<> +endobj +798 0 obj +<> +endobj +801 0 obj +<> +endobj +803 0 obj +<> +endobj +802 0 obj +<> +endobj +804 0 obj +<> +endobj +800 0 obj +<> +endobj +806 0 obj +<> +endobj +805 0 obj +<> +endobj +808 0 obj +<> +endobj +810 0 obj +<> +endobj +809 0 obj +<> +endobj +811 0 obj +<> +endobj +813 0 obj +<> +endobj +812 0 obj +<> +endobj +814 0 obj +<> +endobj +807 0 obj +<> +endobj +816 0 obj +<> +endobj +818 0 obj +<> +endobj +817 0 obj +<> +endobj +819 0 obj +<> +endobj +815 0 obj +<> +endobj +821 0 obj +<> +endobj +820 0 obj +<> +endobj +823 0 obj +<> +endobj +822 0 obj +<> +endobj +825 0 obj +<> +endobj +827 0 obj +<> +endobj +826 0 obj +<> +endobj +828 0 obj +<> +endobj +824 0 obj +<> +endobj +830 0 obj +<> +endobj +829 0 obj +<> +endobj +832 0 obj +<> +endobj +834 0 obj +<> +endobj +833 0 obj +<> +endobj +835 0 obj +<> +endobj +831 0 obj +<> +endobj +837 0 obj +<> +endobj +836 0 obj +<> +endobj +839 0 obj +<> +endobj +838 0 obj +<> +endobj +841 0 obj +<> +endobj +840 0 obj +<> +endobj +843 0 obj +<> +endobj +842 0 obj +<> +endobj +845 0 obj +<> +endobj +844 0 obj +<> +endobj +847 0 obj +<> +endobj +846 0 obj +<> +endobj +851 0 obj +<> +endobj +850 0 obj +<> +endobj +852 0 obj +<> +endobj +849 0 obj +<> +endobj +848 0 obj +<> +endobj +854 0 obj +<> +endobj +853 0 obj +<> +endobj +856 0 obj +<> +endobj +855 0 obj +<> +endobj +858 0 obj +<> +endobj +860 0 obj +<> +endobj +859 0 obj +<> +endobj +861 0 obj +<> +endobj +863 0 obj +<> +endobj +862 0 obj +<> +endobj +864 0 obj +<> +endobj +857 0 obj +<> +endobj +866 0 obj +<> +endobj +865 0 obj +<> +endobj +110 0 obj <> +/P 109 0 R +/K [111 0 R 113 0 R 359 0 R 361 0 R 363 0 R 365 0 R 367 0 R 371 0 R 373 0 R 378 0 R 389 0 R 391 0 R 396 0 R 398 0 R 402 0 R 404 0 R 406 0 R 408 0 R 410 0 R 444 0 R 446 0 R 448 0 R 450 0 R 452 0 R 454 0 R 456 0 R 461 0 R 463 0 R 465 0 R 473 0 R 475 0 R 486 0 R 488 0 R 496 0 R 498 0 R 506 0 R 508 0 R 524 0 R 526 0 R 528 0 R 530 0 R 548 0 R 550 0 R 554 0 R 556 0 R 558 0 R 560 0 R 562 0 R 567 0 R 569 0 R 571 0 R 582 0 R 584 0 R 589 0 R 591 0 R 596 0 R 598 0 R 600 0 R 602 0 R 604 0 R 606 0 R 608 0 R 628 0 R 633 0 R 638 0 R 646 0 R 653 0 R 658 0 R 665 0 R 667 0 R 669 0 R 671 0 R 687 0 R 692 0 R 694 0 R 696 0 R 707 0 R 717 0 R 719 0 R 721 0 R 723 0 R 725 0 R 730 0 R 732 0 R 734 0 R 739 0 R 763 0 R 768 0 R 773 0 R 775 0 R 777 0 R 779 0 R 781 0 R 783 0 R 785 0 R 787 0 R 789 0 R 791 0 R 796 0 R 798 0 R 800 0 R 805 0 R 807 0 R 815 0 R 820 0 R 822 0 R 824 0 R 829 0 R 831 0 R 836 0 R 838 0 R 840 0 R 842 0 R 844 0 R 846 0 R 848 0 R 853 0 R 855 0 R 857 0 R 865 0 R]>> endobj -790 0 obj -[109 0 R 110 0 R 113 0 R 115 0 R 118 0 R 120 0 R 123 0 R 125 0 R 127 0 R 129 0 R 131 0 R 133 0 R 135 0 R 137 0 R 139 0 R 141 0 R 144 0 R 146 0 R 149 0 R 151 0 R 153 0 R 155 0 R 157 0 R 159 0 R 161 0 R 163 0 R 166 0 R 168 0 R 170 0 R 172 0 R 174 0 R 176 0 R 178 0 R 180 0 R 182 0 R 184 0 R 187 0 R 189 0 R 192 0 R 194 0 R 196 0 R 198 0 R 200 0 R 202 0 R 204 0 R 206 0 R 209 0 R 211 0 R 213 0 R 215 0 R 217 0 R 219 0 R 221 0 R 223 0 R 225 0 R 227 0 R 229 0 R 231 0 R 233 0 R 235 0 R 237 0 R 239 0 R 242 0 R 244 0 R 247 0 R 249 0 R 251 0 R 253 0 R 255 0 R 257 0 R 259 0 R 261 0 R 263 0 R 265 0 R 268 0 R 270 0 R 272 0 R 274 0 R] +867 0 obj +[111 0 R 112 0 R 115 0 R 117 0 R 120 0 R 122 0 R 125 0 R 127 0 R 129 0 R 131 0 R 133 0 R 135 0 R 137 0 R 139 0 R 141 0 R 143 0 R 146 0 R 148 0 R 151 0 R 153 0 R 155 0 R 157 0 R 159 0 R 161 0 R 163 0 R 165 0 R 168 0 R 170 0 R 172 0 R 174 0 R 176 0 R 178 0 R 180 0 R 182 0 R 184 0 R 186 0 R 189 0 R 191 0 R 194 0 R 196 0 R 198 0 R 200 0 R 202 0 R 204 0 R 206 0 R 208 0 R 211 0 R 213 0 R 215 0 R 217 0 R 219 0 R 221 0 R 223 0 R 225 0 R 227 0 R 229 0 R 231 0 R 233 0 R 235 0 R 237 0 R 239 0 R 241 0 R 244 0 R 246 0 R 249 0 R 251 0 R 253 0 R 255 0 R 257 0 R 259 0 R 261 0 R 263 0 R 265 0 R 267 0 R 270 0 R 272 0 R 274 0 R 276 0 R] endobj -791 0 obj -[276 0 R 278 0 R 280 0 R 282 0 R 284 0 R 286 0 R 288 0 R 290 0 R 292 0 R 294 0 R 297 0 R 299 0 R 302 0 R 304 0 R 306 0 R 308 0 R 310 0 R 312 0 R 314 0 R 316 0 R 319 0 R 321 0 R 323 0 R 325 0 R 327 0 R 329 0 R 332 0 R 334 0 R 337 0 R 339 0 R 341 0 R 343 0 R 345 0 R 347 0 R 350 0 R 352 0 R 354 0 R 356 0 R 358 0 R 360 0 R 362 0 R 364 0 R 367 0 R 368 0 R 370 0 R 372 0 R 374 0 R 375 0 R 378 0 R 380 0 R 381 0 R 383 0 R 385 0 R 386 0 R] +868 0 obj +[278 0 R 280 0 R 282 0 R 284 0 R 286 0 R 288 0 R 290 0 R 292 0 R 294 0 R 296 0 R 299 0 R 301 0 R 304 0 R 306 0 R 308 0 R 310 0 R 312 0 R 314 0 R 316 0 R 318 0 R 321 0 R 323 0 R 325 0 R 327 0 R 329 0 R 331 0 R 334 0 R 336 0 R 339 0 R 341 0 R 343 0 R 345 0 R 347 0 R 349 0 R 352 0 R 354 0 R 356 0 R 358 0 R 360 0 R 362 0 R 364 0 R 366 0 R 369 0 R 370 0 R 372 0 R 374 0 R 376 0 R 377 0 R 380 0 R 382 0 R 383 0 R 385 0 R 387 0 R 388 0 R] endobj -792 0 obj -[388 0 R 390 0 R 391 0 R 393 0 R 395 0 R 398 0 R 399 0 R 401 0 R 403 0 R 405 0 R 407 0 R 410 0 R 411 0 R 413 0 R 414 0 R 416 0 R 417 0 R 419 0 R 420 0 R 422 0 R 423 0 R 425 0 R 426 0 R 428 0 R 429 0 R 431 0 R 432 0 R 434 0 R 435 0 R 437 0 R 438 0 R 440 0 R 441 0 R 443 0 R 445 0 R 447 0 R] +869 0 obj +[390 0 R 392 0 R 393 0 R 395 0 R 397 0 R 400 0 R 401 0 R 403 0 R 405 0 R 407 0 R 409 0 R 412 0 R 413 0 R 415 0 R 416 0 R 418 0 R 419 0 R 421 0 R 422 0 R 424 0 R 425 0 R 427 0 R 428 0 R 430 0 R 431 0 R 433 0 R 434 0 R 436 0 R 437 0 R 439 0 R 440 0 R 442 0 R 443 0 R 445 0 R 447 0 R 449 0 R] endobj -793 0 obj -[454 0 R 447 0 R 449 0 R 451 0 R 453 0 R 457 0 R 458 0 R 460 0 R 462 0 R 464 0 R 466 0 R 467 0 R 469 0 R 470 0 R 472 0 R 474 0 R 476 0 R 477 0 R 479 0 R 480 0 R] +870 0 obj +[456 0 R 449 0 R 451 0 R 453 0 R 455 0 R 459 0 R 460 0 R 462 0 R 464 0 R 466 0 R 468 0 R 469 0 R 471 0 R 472 0 R 474 0 R 476 0 R 478 0 R 479 0 R 481 0 R 482 0 R] endobj -794 0 obj -[481 0 R 483 0 R 485 0 R 487 0 R 489 0 R 490 0 R 492 0 R 493 0 R 495 0 R 497 0 R 499 0 R 500 0 R 502 0 R 503 0 R 505 0 R 507 0 R 509 0 R 511 0 R 514 0 R 516 0 R 518 0 R 520 0 R 521 0 R 523 0 R 525 0 R 527 0 R 529 0 R 531 0 R] +871 0 obj +[483 0 R 485 0 R 487 0 R 489 0 R 491 0 R 492 0 R 494 0 R 495 0 R 497 0 R 499 0 R 501 0 R 502 0 R 504 0 R 505 0 R 507 0 R 510 0 R 511 0 R 513 0 R 514 0 R 516 0 R 517 0 R 519 0 R 520 0 R 522 0 R 523 0 R 525 0 R 527 0 R 529 0 R 532 0 R 534 0 R 536 0 R 538 0 R 539 0 R 541 0 R 543 0 R 545 0 R 547 0 R] endobj -795 0 obj -[544 0 R 533 0 R 535 0 R 537 0 R 539 0 R 541 0 R 543 0 R 547 0 R 548 0 R 550 0 R 552 0 R 554 0 R 556 0 R 557 0 R 559 0 R 560 0 R 562 0 R 563 0 R 565 0 R 567 0 R 569 0 R 570 0 R 572 0 R 574 0 R 576 0 R 577 0 R 579 0 R 581 0 R] +872 0 obj +[562 0 R 549 0 R 551 0 R 553 0 R 555 0 R 557 0 R 559 0 R 561 0 R 565 0 R 566 0 R 568 0 R 570 0 R 572 0 R 574 0 R 575 0 R 577 0 R 578 0 R 580 0 R 581 0 R 583 0 R 585 0 R 587 0 R 588 0 R 590 0 R 592 0 R 594 0 R 595 0 R] endobj -796 0 obj -[583 0 R 585 0 R 587 0 R 589 0 R 591 0 R 593 0 R 596 0 R 598 0 R 599 0 R 601 0 R 603 0 R 604 0 R 606 0 R 608 0 R 609 0 R 611 0 R 612 0 R 614 0 R 616 0 R 618 0 R 621 0 R 623 0 R 624 0 R 626 0 R 628 0 R 629 0 R 632 0 R 633 0 R 635 0 R 636 0 R 638 0 R 639 0 R 641 0 R 643 0 R] +873 0 obj +[597 0 R 599 0 R 601 0 R 603 0 R 605 0 R 607 0 R 610 0 R 611 0 R 613 0 R 614 0 R 616 0 R 617 0 R 620 0 R 621 0 R 623 0 R 624 0 R 626 0 R 627 0 R 629 0 R 631 0 R 632 0 R 634 0 R 636 0 R 637 0 R 639 0 R 641 0 R 642 0 R 644 0 R 645 0 R 648 0 R 649 0 R 651 0 R 652 0 R 654 0 R 656 0 R 657 0 R 660 0 R 661 0 R 663 0 R 664 0 R 666 0 R 668 0 R 670 0 R] endobj -797 0 obj -[648 0 R 645 0 R 647 0 R 651 0 R 652 0 R 654 0 R 656 0 R 658 0 R 660 0 R 661 0 R 664 0 R 666 0 R 667 0 R 669 0 R 671 0 R 672 0 R 674 0 R 676 0 R 677 0 R 679 0 R 680 0 R 682 0 R 684 0 R 685 0 R 687 0 R 688 0 R 690 0 R 692 0 R 693 0 R 695 0 R] +874 0 obj +[725 0 R 673 0 R 675 0 R 676 0 R 678 0 R 680 0 R 681 0 R 683 0 R 685 0 R 686 0 R 688 0 R 689 0 R 691 0 R 693 0 R 695 0 R 698 0 R 700 0 R 701 0 R 703 0 R 705 0 R 706 0 R 709 0 R 710 0 R 712 0 R 713 0 R 715 0 R 716 0 R 718 0 R 720 0 R 722 0 R 724 0 R 728 0 R 729 0 R 731 0 R 733 0 R] endobj -798 0 obj -[697 0 R 699 0 R 701 0 R 703 0 R 705 0 R 707 0 R 709 0 R 711 0 R 713 0 R 715 0 R 717 0 R 718 0 R 720 0 R 722 0 R 724 0 R 726 0 R 727 0 R 729 0 R 731 0 R 733 0 R 734 0 R 736 0 R 737 0 R 739 0 R 741 0 R 742 0 R 744 0 R 746 0 R] +875 0 obj +[735 0 R 737 0 R 738 0 R 741 0 R 743 0 R 744 0 R 746 0 R 748 0 R 749 0 R 751 0 R 753 0 R 754 0 R 756 0 R 757 0 R 759 0 R 761 0 R 762 0 R 764 0 R 765 0 R 767 0 R 769 0 R 770 0 R 772 0 R 774 0 R 776 0 R 778 0 R 780 0 R 782 0 R 784 0 R] endobj -799 0 obj -[771 0 R 748 0 R 750 0 R 751 0 R 753 0 R 755 0 R 757 0 R 758 0 R 760 0 R 762 0 R 764 0 R 766 0 R 768 0 R 770 0 R 774 0 R 775 0 R 777 0 R 779 0 R 781 0 R 783 0 R 784 0 R 786 0 R 787 0 R 789 0 R] +876 0 obj +[784 0 R 786 0 R 788 0 R 790 0 R 792 0 R 794 0 R 795 0 R 797 0 R 799 0 R 801 0 R 803 0 R 804 0 R 806 0 R 808 0 R 810 0 R 811 0 R 813 0 R 814 0 R 816 0 R 818 0 R 819 0 R 821 0 R 823 0 R 825 0 R 827 0 R 828 0 R 830 0 R 832 0 R 834 0 R 835 0 R 837 0 R 839 0 R 841 0 R] endobj -800 0 obj +877 0 obj +[848 0 R 843 0 R 845 0 R 847 0 R 851 0 R 852 0 R 854 0 R 856 0 R 858 0 R 860 0 R 861 0 R 863 0 R 864 0 R 866 0 R] +endobj +878 0 obj <> +/Nums [0 867 0 R 1 116 0 R 2 121 0 R 3 126 0 R 4 130 0 R 5 134 0 R 6 138 0 R 7 142 0 R 8 147 0 R 9 152 0 R 10 156 0 R 11 160 0 R 12 164 0 R 13 169 0 R 14 173 0 R 15 177 0 R 16 181 0 R 17 185 0 R 18 190 0 R 19 195 0 R 20 199 0 R 21 203 0 R 22 203 0 R 23 207 0 R 24 212 0 R 25 216 0 R 26 220 0 R 27 224 0 R 28 224 0 R 29 228 0 R 30 232 0 R 31 232 0 R 32 236 0 R 33 236 0 R 34 240 0 R 35 245 0 R 36 250 0 R 37 254 0 R 38 258 0 R 39 262 0 R 40 262 0 R 41 266 0 R 42 271 0 R 43 275 0 R 44 868 0 R 45 279 0 R 46 283 0 R 47 283 0 R 48 287 0 R 49 287 0 R 50 291 0 R 51 291 0 R 52 295 0 R 53 300 0 R 54 305 0 R 55 309 0 R 56 313 0 R 57 313 0 R 58 317 0 R 59 322 0 R 60 326 0 R 61 330 0 R 62 335 0 R 63 340 0 R 64 344 0 R 65 348 0 R 66 353 0 R 67 357 0 R 68 869 0 R 69 870 0 R 70 871 0 R 71 872 0 R 72 873 0 R 73 874 0 R 74 875 0 R 75 876 0 R 76 877 0 R]>> endobj -107 0 obj +109 0 obj <> +/K 110 0 R +/ParentTreeNextKey 77 +/ParentTree 878 0 R>> endobj -801 0 obj +879 0 obj <> -/StructTreeRoot 107 0 R +/StructTreeRoot 109 0 R /ViewerPreferences <> /Lang (de-DE)>> endobj -802 0 obj -<> stream -xœì½ |Eöþ­¾¦gzîÉ$“L 3ŽN2I†@#iŽ ‚\j È¥ —"‚¸€JÄ%*Ñõ̲¬º:‹QñbEÅû>QAYOÈô«f&p¯ÿÿ÷û_Ÿy�yU]]Ý]õêÕ«o½ªÉ€°@Î,f¿ãm€´¨¿p`MíÂÚ%oâ=€¸wò¥瘜3o8€G'/œïû_÷1àÚ˜r§Î¹äÒ!?¸è´0]|ÉÄysàE fú–Kf-šzÁñÑ…ÀÌZ ïÂi —^yÏkŸþôðôÕÓ¦LlЛn«È2½¦M›21Íêú è2íÒùWÎþ(ïÐ÷ `Ǭٓ'þ{íM@· - ½þÒ‰Wαë–CÉà»lâ¥Szÿá¢Kî€{oÎìyóõ‘¸ ôúœ¹SæÜþ]çm€r5 k à!à º ¹mðá!ÀÁŽ ®D«éb,7#}8}æoäÛb€í§3�¿i‹Ñ”ޤYŠø—ç?Ï]\:ÁVñ3¼2»òøÏ�ÓðKaôë'fžÜj‹™&0¶?�Î'·B„,6‹!€xã!ÿ&¦rNYä‘8�ãøeýø’ï¬íóAƒ¯­R|;6’Xä9΢ÓkÄf*dàè[¤�goMƒ€»äÂ|ÈEwTb,&à*|‚Ïq¿à¤Ïîsùok«Ôuö¤\tƒŠ~˜€‰gåé«ëú§«õ‡õôëô•{±÷¾oîáöœ)±BŒ¥¥ŒL7q;Æ$⬔ˆóð!?:äá�5—`0Sp fc -.À\ˆ)˜‹y˜ŽÙ¸ >”¡½QÒ!—�åóaKY€Y˜ˆ¹gœ�™ûOð¡Å(E|¨ÁtLÆ\ÌÆ<ÌÆṪ0s1‡ñ‰˜Ÿx|è‡Y˜ÅÞ7—`æc^âíóXYb -XN Lì3S0 s1WÀ‡ó1SpÆ`‹ù0 ±³±€½yfãV"&c6æ`æ¶¿Ë×^öb„˜L“g½QÀÊ1³0ÓàÃ`LÄeì“13‘w(fc“ä`,@«q¼^c0 ÓY]fýÓòLeòð¡?¦cf±Ô‰L§×1þœÙ‰šúØ[`.&³ú&¥|kš²—¡�Iχù˜ÆÒj0c˜t¦³û.cò=‡Ý?…嘂K1‰I»�q_¢Dɼ>–>�µítÌioÅSõ ×çc"¦c案ÙB f“uÈ0ê1aÒc01®@Ñc0ì·Á«Þ+lúIØ`×O‡~8õp"M?ãiÈÐOÀ �~éŒg S?²ôãÈD¶þwd¡“þwxÑYÿ;²‘£ÿ�àÓ�¡3üú1ä W?ºè¿ÂÏx.òô_@¾þ+º «þ+òÐMÿùè®ÿ‚®è¡ÿB-�þ3º£@ÿ=P¤ÿ Aý' Xÿ …(ÑBJõŸd¼=õQ‚2ýG”¢—þ#Bè­ÿˆž(×@Âúè…>úè� -ý”3ƹúßÐ}õ¿áTêCúéGq.úëGÑõ£¨D•~ªôïуôïÑçéßcëßc †èß¡ -Cõï0Õúw8Ãôï05ú Áùú Åýª1R?‚a©F Fé‡1côÃ8è‡1ê‡1éßbjõo1ý[ŒÁXý.À8ý.ÄÅú!\„ñú!Ô2ÁýŒÅDýŒcübLÖ¢ úAŒÇý &`ªþ5êq‰þ5ÕýkLb|2fè_£3õ¯¨Fê_a*.Ó¿¢öFÿ -Ó0GÿÓq¹þ%f`®þ%fbžþ%fa�~—b¡~—1>Wèho×àr,Ò¿À\,Ö¿À<Æçãjý ,À}?b©¾ÿãß2}?®Ä2}áwú>\Åøb¬Ð÷áj¬Ô÷a ®Ó÷b)®×÷âÜ ïÅ2¬Ò?ǵhÔ?Çï°ZÿËq“þ9Vàfý3¬ÄÍú縷èŸázܪ†p›þVávýS4b­þ)nD“þ)VãýÜ„;õOp3ÖéŸà4ëŸàV4ëc îÖ?Æm¸Gÿ·ã^ýc¬Å}úGhÂýúG¸èáN<¨„»ð�þ!Ö¡EÿÍøƒþ!îÆzýC܃?êà÷Ø €{ñ'ý܇Gôp?ÑßÇø³þ>Äcúûx�ëï£õ÷ðÆ×c“þþˆÍú{Ø€Íú»ø¶êïâa<¡¿‹GЪ¿‹GѪ¿ƒ?c›þÃvý<Ž'õ·ÅÓúÛØÈø&<£¿�ÍØ©¿�-xV Ású[ØŠçõ·ð^ÔßB+^ÔßÄ6ìÒßÄv¼¤¿‰'±[;ð²þžÂ+úxšñg°G;±GÏâuýu<‡7ô×ñ<ã/àMý5¼ˆ·õ×° ïè¯á¯xW /á=}vã}}^Æú¼‚õ=xé¯b>Ñ_ÅkŒ¿ŽOõWñ>Ó_Á›Ø«¿‚·°Ooc¿þ -ÞÁúËxô—ñ¾Ô_ÆûøJàk}7>ÄA}7>Â!}7>Æ·ún|‚oõ—ð)Žè/á3|§¿„Ïß‹£ú_±ÓÿŠýøQß…/?€Ÿô]ø?ë»ð~ÑwákÓwá Žé/â×_Ä!œÐ_Ä·ŒF›þŽ0þtý|OˆþŽ¢?�¿^?0þ#ôçñõçð31èÏá"ëÏáWbÔŸÃ1bÒŸÅ߉¢?‹ãĬ?‹Ä¢?‹“ĦïD±ë;c\'}ç6øHß-Fêk%ÉHÏd¤4 &#EÉHA2bNF„d„OFˆv‚ÅtÆcŒŸdüGÆÿÆøQÆ¿güã‡ÿ„ñ�ÿ€ñ·ßÃø«Œ¿ÌønÆ_b|ã/0þã;ŠñxÉ62þ8ã«¿‘ñFÆW1^ÎxoÆW0¾œñk_ÊøÆ'1>‚ñÁŒ[)>-ÁùÂah·ÚD£%üùÞôŒìwÞMÏÈ^|uºwñÕ™o¾•ž‘½ðŠôŒìKç¤gdÏš�ž‘=ó²tïÌË®™›5Aš;û’iîì©ÓÓÜÙS¦¥y§L[yyVæ¼ô«dú ÈôŸ†Ú' 5Ü48'¸Cø -A‘'ò›]zÎÞ§…_A°—qŸpt³ÅÖZ…C›”´ð6}§ðýfon¸²ŸEø ·?‚ 8Á¿ge>¸Y±‡‹Ÿ"ü/£œŒÙÜÔ%§òÒÿwØH?ÜOú�Ó÷nù[w5¬µmó¹âa—n4¬Ü\Œ‡Ù4Í©O7sj+Y±i�Im%ׯƒeñàͶΤ޽Τ®kæÔæ&QmÕ÷>ñ]Zzø¶5<�kæŸ\éáÃM‚º¦©KMP&{2ÃS'“;š¸x†¦¼náòÞP{¯ÐsZ Ùº„SO~lR·‘¾¤b§j­¤bSN—p+ nZ«­¤hó -^}£•ü…hdd²_ÈÍ kÏedгÍ;³¼4|b§ÝÞó*-ÇÎ'vá—_bq-ý¨b ZʩœÌfiÀÆÇ9õñ¥q ¼ms²G<Õµ[x¹« ’•›MìÎìÕ�;‡W5 -jã -“zã -^½ö¢.Y*¨KWÄ«Ûo’'34µ¼jz}+)§¹Øy/vÞ+V‡R�yóœU´³ËI âÿŽæÍSçÍOÖŽÆXjÔ­¬ý¢˜·ÑH¥>bTÿê¨<ª:*�Í -ô¯Ž¾4ª:Úkĸ¨9Ð#¸c6r”IÜ€1ãÆÕös“¾h h =Ñ@JÑ@‚h Eh h f4 „G!Úù zC¬ádÃ� k8Úð}цC Ÿ4|ÔðAÃÛ {^mx¹awÃK »^hx®agÃS [66<Þ°ºáƆƆU +–7\Ó°´aIä† ƒ¬ ÿ©$NQä¿¿EUÅÃHõØx’¼# ˆ§èõU§xlx¬»þ3Ë�ØöxNn�~D|n°þ-�пíø$ýˆ‚-x7âZ\{,yEN|„øic"y^"œ àr,äá¹yïýGžÓ)Š X“ˆo@K{:�ß�iíçwbu¢dËY¸�rÿkÚ‹½¸ÈÓ„;ëÚuÔˆñ<®ÅPŒÅHñcñc\‡ZÜŠÚÈaY‡¼¯'ê \‰+p&â*\›¸v-“صKYx®Åm¸÷ãNò6†a>°áÔävc.e~šéx b–b¦Ø ×ú÷¸—üCîÿçéLÆØÛû�ù3âjîX8À"Ü¡ÿˆ1„˜‰a†é±ÀŽS· -{à�î§:ÆVÌ [1 Oþ÷Ñ›ÜviÛBýwúrññ áiá0ß dâ2\ƒÕ¸d±5¸¿£ŒR”¢¥(E)úÿ-ǬÅZ}¥þF¡»”†Ç0ƒbµb=nÁJ¬ÄÅläý#îB-öá^Tc:¶èO{Ê=hÀ>ŒE5 ´ V6Œ3êüá5ê‡|Þ ýûi•}Ï­8§O¸¼w¯²ž¡Ò’â`Qa�Ú£{·®ùy]¹~_NçNÙÞ¬LOFº;ÍåtØmV‹Y1eƒ$ -9Ȗ‚¨“·Š~fDµë£\^` ßï/,ˆºN]iÕw®îx Q§šŒ¹â±x!¢Ò€¨!^ßô¨61Š} v6®nµcR½jn4L¼¸6ÊOŒlŸW5mL4»zÄØÚ(ŸWE?õÓ|´¹2FÏW5Í×H¯M«�òy��´ÑOKo˜6¥žª © ,,ˆÔ^ïßé�:Ô^_u¨QK``ÔrÕ/ßXå™î£§��×û¢÷�¬íxÕOy$ñø«UÓêTÍèO›$ØÞlL‡4°ÆÑnœè‹.›4#®{W'õßßh�šñ{ý~¿Ÿ6»1!ʆú´È3&ÒjVÍð5Þ8…Uu5«šßïõUÍH?ôF_UD=ÆÖVM T�z¡¯10Ñåóμ×ï�fªôÆÆÆ*Zĉ ý âEŽfª§ÊOû„W%Q.o@TÃŒam૊jFI‰ cémôJýÀHÄow>Ï5ä]/|�ô‰†¼hšj÷¿à/,ØYXP=ª¶j —Õ>Ê ¨=÷ˆÇ{$RXP=¢=™xªGÕ6�xã2ª¨ׂiIV?&Þ�¹ö–÷û#‰üì©{<Þ=‘‚A�Aõ��ƒ¾A�õ�[õe“>{ q£ÙÜ8§ªÞÇz>™Øªo¿Ñ´:µ×O#} - |Tß�ªŽºFŽ£Í3È7mbÜXTüå^¿#’Ì3âŸ]Nô³¨a@Tbý¬Ñ~¸° jPë÷úQóÒª-÷Fíå´›ú¢¸ ¶ÕŽÉLg›ÅèÚ(ç¥=…�äUM��ןTj÷F&R#…~?íC7¶j˜TXà�.Y?÷a’w´ ‰rõôÊÎä÷ôʲä•öÛëþÂu?ýK�î¨Ï�Ž€Ó2ù3sÛÝ9¦¶U?V•ËÍíPË{¹DŒóò4fRv_E4Ce7R™D»©�ö€ï�@Ô®Fŵ;½ŸÝ…“D«´×pyö7» µ�H³GIE”¤Ót¸¢„™t>£C×þs _v£7zíêÈ´>…Q­‡¿°ÀW%õ¬·Œ©MH©Ü›èEô]ChUN¿Þ.Ådž³¥[=洳ϥ‚¿zLû }nt�š|Tüü<ÕÛñtð—‡$/#ÊåùC¨P[õ�åÞÓÒF×FµxRõ¨Ú%Þ«èx‘þ䆑5rÃè±µ9ôßf|7Œ©ÝÄn@}ÿÈÆ.䆑µÛ|€ÆR9šJé‰�ž šT�ªÝÄÉ,¿w›,cW–ÀÎ'·°49™F0¹•‹§Ùã/Êg/ÒÀar«¿¢%s ˜Ü*ÇÓ–±4FÌqY«™DMÖŒš™³pÞ�„&m5y;Œ›ÍÄB¼—qF±äV²l£QóÆs,ƒ‘hñÞpÁ©W_0¶v³âe<‰ô§ô�¦Z匈*öqQ;mDÀõeíö6Ú©¹ŽFTjÒ¾¤vpúÀ‚�yä†ëtq4­zÔ8o”D -øÛ�ó:×â<ƒ“¤� !—’Uäò7‚ÛÅ›ùYüG‚[xDÌëÄ?‹_J.©Zj•Z ý _Èy—1ÝXoüÊÔÇ4Üô{ŬLP›§š?¶ ²€‡~kó7«¹t?, .ÂA²]ùn%;0‡ï¬FàBahx©0‹…° -#Ð"ŒÀla& #0V�ñ4?½W\Dìô94äïˆï»#]¸;„Ÿ0^¼;3vð±C\‚ñâcØÁù±ƒûiB vð/`‡!ˆâIì�dŒ'ÂÝØ!hX$” »x ŽÁiX„,¡YÂ,8…[á?³nü¨x(81VØ‚õü&Ô [Q/QÏ]‹2¿ëÉQÜJŽê}øã,¾^:€õ4]ˆ¢žÞGóq/a=?Ó¸­P…ëq+ÿ.¬âKðð�"‹ÿVþÞ³ßÿψ–¿ã9-ßzïo-çYi×ãÖyÏØS:Ò‘øXò¥,ÿ“$ü?]€¥(E)JQŠR”¢¥(E)JQŠR”¢¥(E)JQŠR”¢¥(E)JQŠR”¢¥(E)JQŠR”¢ýK’¾Æ×àè¾Ta…¸< ÈÒáð¢hÜã ÷ ¸§rOIqÈáwäùþõüg'·r[Û†Š �7®†ƒÃCüÇÜ2±™=! ¥Ù„!(<#¼.ˆ‚`ä%ÎÀó¨ í)%Ag8XWRL‡ßp�žkȧkÄæX?ò ýÐ_’YÛÎ](6È~š*ÚRC(+çˆÄÃ'’È!@‘e³T#Û©F>ÄÓ€ªûTÕî{o*+KŠI�ª’v‚ÃÎ�¹-ö2éµ6¶+¶�Lâ œ‘\[3ÄúÎô$îgïº ’~t³BjЪÕ…Ôô6²7ó­úѿВ[õcš…¾ZVˆtHÄ!Bßêp†iÚ_îjù÷‘òØ®µ¤<¶�,$?“¿“«c·µýÚöwúFX+¨P0DóóVA¶4 áéˆÍ@,¼V"ˆýE“�<%´ê{7›¥!¨î ‡÷¨Ä¾žà„ñuªÃ‰p8Ëc?b?RRL¨pýe~GÈáÖÆf­Œ]Jn_IÖrN¹ŽÜ»]cÇH€G•Ö)Ì“0§ñ›øÌR º)R –qš#s0ת¢o¥áVEªá‚"© ªªšµGUaÿ%k­q]p‘Šû,8K#‡iÝn%ǹMÜbðÈÖì9Ÿ#ô7¼à#„ë‚uÖ©´¸e~nSÛg\.9~-½oŽ~ˆŒÀ+P�­9 EÇÁe|<‡ò´�ºàåûP©–gäæ—õì*Mw§IŸõëWìß?½QÑ€EEý¢Ð�|!ÓËLÍr!°+¨¡?‡Æƒ¨ –µŽ�á ÛF¬ã›ÿ~¥t8\¨ÍŸ7Áºkn¬r8²Ü«4“ÍÕ±Č战‰JžJ•x‚YGœá •z'I�Üü|®¬§³W¯��·û}»ßÇŸì·xóÜYš_QyÕ_�ç7Ä>�í!…¤;÷ö–Ø¡g&OØJŒ�ì ¾ç'·9¸†¶5mO‚àÀ½#n‡�4‹Å€F" Äb TV:ÃÁ Ù*)öVÞPÖ—ïâÞiq 7¥¸×¢Óòû -ï»JŠ{˜×ÛB•U~*ÕK~¿¸ =P¡uîìZeò�Vi~t²ú:­‹ø<&“h›#V*UBž`%Ó«d�á#¥%Ťgȵr†²^½B¥�9wš•3Xy·ßí/ëÙ—ëÝ—ç…îçÕ—_|ÑÈ@Õ#‹k︬²ëùWŽœ²¼&‡{ùä�Ý.nš5|ºærûOêçË*ÒºFœštkÝ�WÍé3xj$Òçöó.^½téùåS§NÁbýk~›¸ Ý1Wë—¾*ËÕ…—sse¬Òl6UÎÌ"¶,¢ðYYžNžæH§Ëålޏ\¦N†^2�l—}2oäeÙ$šíƪ6a|]•#«á©$f¢²Ž8ÂAgF˜5ª• äv-K•öåÊìþ@YÈçèéÏ5”Å+oÝ�y~Û�•ÛçìY´æÉêEcs®¸œLŠýp×ÊUO�½mZ8¶ÈÕcC䎉÷]Þwxtnþà©ɼ‘È?M½oT騥Ãb_ŽäÞµW€ýö“Ø +Üè«uæ‰Ø(iv«$Ù2dA¶ÉÍ#qXm6É*I Ep†C!Z~â :ÃaG(”eo+ÝE�lÈ`v /ß›øVžÕÚú`Ûøñ;o -ź�oª¯[t™Ø|²æŽØãdäÍ3þvì×ËOÖpO/mà T_Zô¯ùÝb3¥d7fedÄež'ç8›#99&�Ç».⑜TÌDù'"fòõUV¼¸dÏ–kÏ|¦Q.¿ÛÏǵŠß=xåŽy/M¼mÝð%µÁ›;iÚ¹™%Ü�m¿vò Ξ»eI?²uúÃWõ¯xl|ѨùU«ïãx�ç^_Çñ³ ²œ­ÍÇÄMð¡'i]œ&¬òû{©™«4Sv~s$+;»Øæt¦ÙÒX§.îЩYé©=Çûw)íàŽp²ÔE‰^šáfåv‡X‘ ‰ŽáNëÌÑZñ±�W®Ÿ8ë‘+úŽ^÷Áʵcg/®o¾ìaò�ñwÎì³!ÿ¼iýÏ�6Lí1lºÖwêànä¯Ó£ËÎû§ŸÖ=IJ>\Øýîð…¿ÿì†ÍÚ‚¯¬¾rLaÑùÓÏzm}ïà˜´m&üb3œ(ܹNsj6Y†°;öu‡$SõHv_*úp»•ç8C —ÓÙ—ëí/óó?øë¦Íž=꬞0£atf[ «xNøáw~Š�Œý|í2¢òÝKëÔµô7Çêß0»@oTcœ,_%÷otŠn§ì”�ÈZUTTÓe•·:÷ÜPsäÜs»[rº¯‹ädZÎkŽX IñÆ5‚ YíöÓÓb†ã#˜‹Z’ü|jPâ6F2tæÝ é÷N¸,!p×çc» ˜\YwÙ¹³Ö^xÑÚY—�ë;i@—�‹¹dêÃWWmê^=³_匵û°ýûN¯)åõ»°¤ä"-?O»¨´ì¢Ê\rkx^Ã(Oχ&ŸݤÞå“®>ù¡žžQ óÂãï™Ý·ïì{f ˜5¬{�a³úWLQ¤ÖÌä"¡‹úåå÷»¨´g­–—߯–jßxýkþð)íóc•œa·÷RWiÎâu›Ó™/R5Ì6œÕo’ -«,o¨}€Ivš€WŸˆÎÒ¾ÃÃïø ñæYW\?qÝŒráâ7Ïé[µøO ³þ8·b£:lzßs¦V«Ý‡ÍìžR­ò�c{Þ�]úû#Öí]³­ß-“gD¯tÑ2�¾abYð‚Uî] ™LëÆÆg! -2P¡¥KˆŽ“ìfgtœÙeäÝ�çØ‚6ÎÖª¦ �†4Ø‚™ 4\¾/NèAI±«ÃÎÿÆhL„|yÿ¢"M+*êrSûÏ13Š•Ã†ÉZºÍFlfbãå±j¶Mvãã|¢4ÔÀ™)¾1S|c^fM@kÚXƒVJŠl‚ªº�¡ZRB�YÇâºø€k°_¿`Qÿþ÷/Xpªˆm�&ð±ãa–0  ÐÌWb øƒ#ý­ÅŒš9<áyhÕ÷þ…‚.‘$ ª¡ ú‚¡`�ê ‡KŠÕº‘8Ž<áDŠ·Pì(&Þ!Õ }6‚*<ö] Fq£°öäþQúá®h{kÅÙuáh] ¤½.‘$Ò¡.\â=\P}!¨†N« !eì uáV´]Í_Ìc#šH¹Dîˆu‡åúw| ³5! Òòá$vÑaK³5EÒt)ˆŽëâò}Ï?~M7Ò­›#s…ÉTæ vnŸ#¬Û÷Î>¦dö]q^R¿gºr^A.ýG³…~¿?—Üœ5º»vÉØÑÔ•-Í\­ïvþÂáCçO3zl¯¢ê¬X½ÏWÌñûs‚E>m%ú[(N±Øð†V`0Y"F»5œl4)D±Xm¼`æb&ÄÎzEð(2Œ´ê·Ðˆ¹UßÉ" -•~˜Æ¬£I³l‘jÌš3}°YÒdÇÛø5›Mâ‰(ÛÌ -ÏY�“I¼B$W‚ˆ­úAͪ˜1 ÆáƒŽPPUëêœaƒ•á  -»çû YöOUõgm>•¨ªJ;Äõ;wZwî´_oݹSܹ“¨uuþïç$äâó»$/:·ßÕvÿ-Orù�Ý·OQ“åsr[ŒÂŽ[¸É�ûŸhû=YvBPl† ÈÁ'šÙh!’Bx�Øy�–²HA�ìq8­ú/ôô\3ÒY‘_SPC̓ú�ªª¨jÝ7j8™âŸ=Ðѹ¨ÈêB?3 wzº;MðŽPi¯²žþd¸ƒÜµý£ó×<;¶ûø£�÷ÆŽ<{`íC±õbóÖÛ®Ú’/8¶­m= r±’•‹Þlkn;¹úªEãõƒÂjqÜX§ÙªLdÈPžØ2ˆ™7R%1›QÃ{Ô˜¸iÂ5n·‹s­‰p.(ÄÌ+ŠE¶¬‰È”bªR• -Q” ;®�J;D´[¤‘ -It)Ì‚°ÓY½êû15ä1u¡G]]žðÁa‡?Žœh4TÚ[X}ß‘Øk±[ɽ¤ï«×5oÿ5¶‡ä|óÁ½cH#ÑH-ÙpÎæ c[c‡cÇc»ëiÚˆ}=èN-<Oì"ŒL)dªmN�–T Í),±´ê?Ñf´$TÃ’hVK«~Hó(R�Åâ0ÒªiU�T�ŒKYÛÇu –Ð�Øfªɦfm�¶j´¶ Íì£Uå!Zgÿ²šû%6.vß;ï‘,Ò§m«ØÜVÛ»TäNÜAŠˆ›ë -BkÆo›¡`ŽÖS2®‰H‘֨Œ‰#¦5âäÄ5ŽdA,’‰ØD l¢6-%‰Ú‘Vý8Gh¨°ñä”¶†BtúÛ®¡*h{ƒ“ÚŽs#Äæ»b�;c¦DùÖ2OÉ%Z-‹�# -Ïq²Á)“5™@á$Z.‰–K¢å’–Zõ´\†„ÔiHÇ[CP‰»ÚË–(™3ÌÜÌ—A‹pøùµñmà>¹˜ýζ•ôÇ¡âšO‘V&ÓŒ0›@ì"Óùs̨ñd¬‰x<2’šnSrÎtJ×32ÜvE�@[Y ML Œ¥îVý;ZPj¹ÌFxOï ´°î`?½'$êÂægv‰�3Ìd f=ó$ÿot6þ v,¶'¶’ü� 8tßcßý-ö*éüó†Å±]dÿ¤«Èj2ˆÔ�G†m¿,¶%v,v4¶{¹í®xû?0ýY¤ –ù5Yå5j1qŠN/ñFÐ:@:UÑk!´ÄIÕ…Xd�æh�æ–Š C(&z�<Ãð©´ïWVV&)îÜ£þÂ�ðÆ¶¬ ¸¯6p7·Í›ÛnäØüe@˜gƾK qr<*+Ip»=D6l›A�¦äT±f\ªeÐ2LˆÍHì¢$ɼ¼&»^¤¶=›–Oíô �2«œÉCûGBçL­úqªs&“Õâp¶[ëÒ ÊfJ´�’�·Ž¤%g§GˆS?øË˜^½.übÇé±/=ë»’kùæ„´›aÇ=Zö+én [¹¥„ô }g÷˜-d˜�:/­Éq›àÊMV;EÚmx«ÍFìs@@/fÒÀii+ÄÇ*Ú -"íAG=è˜f¤]Hfý'Y :l×…C¡ m 6LÓAZ­«£c2Éï`MêÕ›„ˆðà¡¶÷r † ‚ÕÃyÞl[ÇÝšgië+6·�O÷r—·�H´ß"6CÄuš‘Ìú0io¶3e8šP -6²PaáÁÍ&îÝldáNÍcÊ,І³4‹$4‹´ê?°:±£­JWf[+ã*äðó-mž œ&6�%J)Í›áÅvÍ}UYà"ù®^.nn:Ig’¶$…ÏÐNoKÏ"¢Ñ"9N'/œ¥4Y4!‹ö ª=„H ;J½¿¤“‹Ê?Ã"Õ¸,ì­�}©£Uÿ�ÖÇ‘Ð8�B¨ª.U�a:¡¨ ±Š…ãMD›‡yNëüGÏÞÉ@XK¥»i[‘ô ÖZÒÜ?Z�+–>*–áNä?#­!›¤f‘gß⟛û‡‰=NlO¾ðù“šØ|Ò3/¼° .Q›áŸ5Ëf2W!Wrd ! -í1&569!—cZ�aH'£‰7ÛÙvÂAT•ƒÞ“©H5·"Ê4¯LóÊ4¯¼Ô˜�ƒ1©«ñá4Ù®áÒ„4ØIÁ¸0˜;¶]]O !¿Ìµ×Ú:g;%yÃGÜk…Á´A¸B Ýyâ'±ùÄ݃²ú6ñ?ÄgÝŇÅMlfz­ÖÎ5¸$óšˆ$œ9¸/q'TØ�˜Ò��DŸ»ØÍ¹Ý™6z‡�Þa£wØ–ðÔPòÔò'Ö2O ^ ��ĸygœ$ì;å\,özl YHú“îdfluì�ý±¯ˆëÓÃÄ;æ!·‘þd,¹'6'öTì�Ø4±4¶=ökìרS¤'q“lÒ+��„îb3LpâV­û ‰p6bÌX1›yÎÉ+k" ¤š½Í”À|¦æ3Ñæ¡æ§Ô¾K­Ë(¥ƒApSUCgÌNèô¸n�¾ñæ6NºöÝ�ù âHºi…�/õ÷íWlÜ@ß‚þ…£ éRVìÔ¶ñ@åÌáM7‘ÛÊÏ/Íh»WlÖßR_½dR•K°w/?/È�n;–Þ%Ú¼kA°H?È&nBÞÒÜÕedh”Gf‘AnÒÓcFMª©fÔtc# j2©D.4£ÆA¯ \¹‚§$ ^bæ½ÍÓiMÄ#€…'%%ÒšH‰Ëë-È¥RË¥‚Î¥‚Î]âr‘šV@Ó -hZÁ#5ˆ6Úó�ÄhìMäø(ĺt\` ¹ÅÁ©ý†ç�å±ï™0¾Î*u$æÅ‰·®wYgžÍ抸®E|ÜE—t§uæ2Nù2åN˜>£ðîu¡±‹Ï«þ]}ï Wo®{gâ5í}Ù…½º�˜W]Ó8íÜÑ7µNÍm˜V×gWçb¿sÞ¬>ž×¯KþðñWŒ˜´f|Qè©ÚŒž£Îé=¢ß¼ü1S¯1ãö‹»+ît3›'-ÕÞIDI\‘èέúq�­ó‰°r¼Øÿu‘bŽŠ‡£âᨠ¸¥<Ç|rÕ“ç�²Q£MЪïÜDgª£ö2‘û~O°ˆ™Šª*O-H -æØ¤ ±Éü"w<&r±>¬Þ›aÁUZ grš8NvÊœ"pF -×ͼȟ=)D1[¤E¡5È0K5ŠÍ@3h&ÍdX*´ê1ÍH‡_1M09ðPÈÚn¯èJ�#䈻mŸ·ý²�Ì'—là¶µpUü¥'ï��Gæ/�¾bû%Í´X!ó:®*­ú›Í¤F¡Àǵ\…ÔÅfR#ø,”)¤&¬�^™o †n´wSXÇ@ß)#­8žçÚ -J«~’vi2ç¥Ò� -,éoœÒ&±µ×�Zg�6ÓôzWžðtVNý–Ò*+�á°ÚŽ;Ô¤ÆÒEÐ$à¾j;²­íØ“ä&—I�3I“Ø||ªØ|â–Þƒ+ª„Ùse†zйH?Í·ØKe‘…id¡…Ì3“F²˜#^Ÿ5Y”¥ÑnkTPã¢Î ó ¢ÆL¥c2£Æ$SÇ“1îˆ]ÒG s-Ò™¬f4£ÔÿåMH×›�®—ÞàRH�™J×L¥kö(„ÂÍ—´\*ØŒrÊmŒgPå0ãlΖ‘úmô%�¨vÑæÊ�L -oJsI„Ë0šl> -‘è Ð;öjifÔØh¥lR¯�”`'RG=fq4§:B¡ø_ÓÄ)�ÅO§º8‘8æcدó%BC}l拱]‚ ¥ÅÞ>vñ6RâE1‹œû)¶Ë‚�Aòhóžçtâ+±ùÄ–ªê²q°�†kzÒÿ$ÇZKh›áÆN-s±‹\å$ ,d¾™Ì—ÉYđń¸hýÌ·è£\ö%F¡½š‰Æ\r¼Õޱ61Ñbû lfÔzÍæIbl6~1ÉæXsd*]Á¨ðF·IIc«ð@†bdsP`¸‹êè.uF'×Qh Y% !“Ua Í{b[mNÁä‰=úÙôÉë”.ø<¤äÙØ¹\^fQFqÛÇÜ›Üî˜\ZÚ?ŸüÔNôãzfy¦hþyŒ„ˆ¼Ó‹¼‘£Ö„£Ö„“â60ᢡ–ÎÌ hYØ$VoIôÙH]0DûÚ7ޤ5¤8ŸÂ¢=tñ¦ŽPTtª›ÕǺnˆ…ž!ý¤N¼)›Œ›O^ÙögåW·]i–Û‹»„þ�;¡�ù[ÖkV³DBì„5�D›¦„ÆÊPއ ð}Ä¡"g³Å‘ÏàE"dMDpB6Èêž‘X Ò¡æEJ";b6'ÎÒèÐg¦õ3ˆwçÔ­î̃ÉÙX;TžÂT‘U•ZRB÷Ð…¡ád+ßóÄ›|¿6N€8÷Dþ]Aáí»¨ý@ì}~”>QqºÐ/‘áBK‹°è›??þá+³þpMÓŸî½þ–ÇÖ®·Õ¿;òuL�½Â ¹åš�^y乿‚ ^?ÈOzôèC�?¾ýÆêñbï‡÷®>¹šŸ¿zýO:i‹Æ: vÁòð²f7 „·Y‰]êÂtY¦ËÍ pµ²JÚ¨�34E¸lSÀhŠXÒ3lîN®NM—]pg¦ŸóWÅ„‰VŽÍÑTZocWÁG³úhVÍê[n§-l§Šn§Šnv=¥è,wF(é’?ÍjÑfޝRaB]žÝÏ<¿>GBýíNªþegªÛ�§oþóïÉU‚oŸùæÄG¯7--X|×£¸¡ñÏ£Ú^ÜROn›óq|EDÒsýÍm¯ßyÕcŸþõ‘=/P-XðÇÄÃpà­g'œ�Øâ6ºÍ‚M ªoÂÙÖ)oi²çÓ:³žï2Ÿéƒ[aäâ‹%„ÛÊ\p®Ó—[Î4â•I¸?à°ÓÊ&¼Æ!Ÿƒ?ÖòÝ•---ÂÂ�ÈXn8Ѷ­iÛ!n›ñ\l8úßoÉTñC¶c¸€4y¬6‹qo1ó“ôâ3Ǥ–DÙ,‰²Y,{\aé\;±µµr×»D\GèxAß¾…••�–Q¨(*:÷Ü¢‚¾ÇOÒ_Ëé}b�Y9Ìð`¦Ö“ãˆ]°¸&�³(6¶hÐá³Ó'ÙM°OÒ‹¥³„|�‰˜3% -f2eeÆ VGK¶+^´äа+±â—×qÅ ã^2ô•§õÚoˈD¹Õ“±ï}ë -ÉTþ(i/G­0ãnÍ~•™\¡Pt¾ÄD–bN·ƒÏô,—NÂ9“HÜ¢Ûd“`RBEÃA£{˜ÍÔ,ÒµóYË:+D!î¾×·²¡ÏÊ#>ºÓµíºÄRB%…6‰Õ¶ˆKAxb1�„ì«XÎÉcïÇòÈáXšxød%y7æŒ×‡ ƒG-�¸¹ßÔéXB—™¬ …SJÀöR³õ ¡--âáø¥1‚9øtë3"�έúÁ'èDÍOøìVý ­€n¤H'fAt§{‹ÇÒéä±»l&âüW¯?¬eÓ÷[MNSÿ4Íè 4£c…“:J(B²R„ä=Ó ·Âd¢â4iRc33ïó›VÇÇQUµ³EO¢V¥*±MTÐ …*+éþÍŒƒ*™P§Æòý¯½²}†é´3JcZ¦_=ýö–of­ni.}sú=�æî'£¸aßµóº¶V®žýeM[«€·/˜ðNlB»v±˜ÚÇ)›c²%­Îo è—bsÒþc›“öOlNÂäü¦Í‰×ÕM�ÎâZZ„ùŸlØÄ &ƒ¶ÝDkõðsîI ©‚‡yûWi�LMájàlŠ ]27E$û™­´¼ƒËÿ(›øÄ]ý­úg BQŸ?dm¦vŸÿò¸ÏŸÄ|æoøü)R<}õ_sQÆ<ýî4ðÉñ¢¬g>7ê‹ØßHÖÑ/ ‰}ûé½­Ûï¹ï‘G<$çáHnì«ã?Ç>ä׿ÿÔÖ·^{zçíǺ T×OCûÞ$ÚlRïÿwhßyæÔö¿Dû§�žI´ßÞbÿíïúìø‡�ÓŽöÛšÄ÷·üÚ§¸¢;ôÞMZY/ŸÇ6›%Ž-ëÙ ág„Ϊ³Jí_d|4hfþøì7¼5ž‚‚kÖ>º~ù­�ĺs׿D\GtR²þæ¶=MKûø¯w¿ï™ÜÁ ;"Û`Öj]i• nÙ˜8+[†Ót殊†VýGÍJ�‡ÔhO_ÓYêžÒÒ`eâµw-ïv¨#§ßÔÒ"n�h¹üXÿ®GÚ~ðö¬EVj-¦éy›àAÐ2 ù„O'¼ÑLŒtm�ØÕN‹è¤ò-£1S9ÃzÝl�…´ÂŒÌ´Ì¦HšÔYAx…'|!ß)LÏÈèÖy¹Í†nËéú0ó£øÄb‘ÅbÐÖ@vbs�ƒ¹Þ©ß½Ýé¾+ît÷ØwQo;ClÌñ0�ºÛÓC¥ÿÖÙ>íº>È«¼ dà%U�þ—ÝT½rúå· -ëÔ©|Dhà¬aÝ̹mĽyÑÉ·v\ÞÞUµç ž]�_´~¨;¿Ì×­W�Ü´¬ÞUcû›3´ •�ªâ®ƒHÃÕÚ9<ÓÒ´4'礳Q“É`•ƒAjŠl€…î³HI‘Ï\T\!$–o„ÄJº@wž(q�uº—ƒjºÒ�·}JZR¬ÒMU†Ú{³�2l.Ê]ÛgBìÇh´…p±Ø ‘} M>RÀ�_}¼,öæê¶g.©ÍeßÏùǼz¿8ð€ÖkˆD†H„·°†µñÄ,7oÍ´ÏÙm²�œ�•lÄF—âŽÔ“‰Ý¾'Y‡³Ù\gnNZa0µ»è9¦ª®3;Ü©Í$ñ¾Ö>$"1�{é©mq„øý-ÂÔ÷b·=tìÊ»[ÜN¶p m[c;6Þ ¡ß¤à_¡Þ+,Ö,‹�º‚�…aŽy…:ÎæHcË›™I·×B1°ÍoŠ�çܼMI:ÅØã[$-‚9áhgËR|Pe^?µTeßÇ3ßzÒiÙѱο›ö@ìê-DèdLéÄ.à$´yF�[Ó—£èƈQðâ--ýJ/¹"�,4“Å&2Ÿ�r#ém&^jØ6ßeÑL‰sŽâº‹-�JÖÌæ‡l—ÆäV}'õ³¦±Q/éŠ�;s©û•Jo»TÌI÷âZ€9Ï™8lŒs’-Ãå…Á¤ØLÝßí^Ûv§-Tr¶£;±'”ne"q%C1ÛóðÛfAà�_¶Ä^~ô“ ó¶Ãw¼ceÎö÷i�².á6¿€“±@¸ ”ÇÉ“y½»–ñBbE‚¿M\Ø«¹»È<+Yd&óMd1O0ïv|秊ÊÜ<3Ñ3>yÆdeIôBs"d{%\t°¤îB쉑…Ê”: â~s«�íëaœ�ï°°�aº*!QîVH /9\‚b±)à, -ǹºs“™î&u„‚´gwÜ ñÛ+Fî”ã‚$üm± dÔ3»]Y‚ØcÏS¤.¶é™]én�Põ:“Ȱœ ±*¶…ü™bvíN£2³Æ:óï -@îÖL–4 ‘8’F¡€mœ‰w[‘¡Új3ÛìL ìDiŸKI¬‡X“ý‡H -oNKvš´d§I·Ð‹s¢Ó˜OuVÛö�rÁPH­LvûÄÒTr^ÕûÔÂÿn¬ûÒšZVpußQ±9[‰[´K¢�œ¸8öœåvçÚçøØÉöJOO>=îGçç€Ь&‰HÔ�îI(z|ÅâߺƵdÿ�ý)"¸™Ã½)"Û~Ó�þOèq:Í�ÎÏi{�«=ù7¾íc>�óä“«C|¿Õº_9•pù(ˆ·�N¤š…#è”!Zò8’%æC-+#jYt=îM¯çò1 n™dmä¹V}¿f -v·¥åñ\�£ý]�#lvǨø;ð@ßÁsèêç�y<×ÅqÚ;ؘÂî¨MÜqüŽü^Ù‘Ç‘Îî èG?(¤Iòð f´å8ˆ]ô%ÝGY´ï”*¨É1šLÆ;"ž.¦¦´b�½)â!„ïÂ7Eº¤§¹s¼FÀeYî¥}Óë•–ûémÔwèwÑætQ·™‹vp׊´ä®¤4j!Ó³2ú�Ú J¿<ðÝ¿�t©‰&J¸‡êòÊȶkY¯8Àu8Žä\ßàiR —쩞pé /mZx×e¿nùdûú]w\I®úì‰)ÜýÅ·_}Ç“i¿K[?wÖ±WN<-ŒÝyðé{®y¹«X{`ãQpX"<ǽ ^Ïf5=è·kœÏš�;yÛN»›ØxâæÝ|¦‡NʃÁºº}ö}aô>‡87©[Ÿòn=ú”Ç.ìqN¸{÷Š>Âsåj�òp÷î}Îé)¾$ǰïêÚ¶räÛwÚšL|¨¢_Ï%øšÈÒ(¾Fdh&ÂɼA„ñi x„ƒ{èF—¿+ýªJYoÿ×ÂúÅD‹í\tâbî®+ׯ¶±-kÆ¿~Šb ûÿã?=Äó�y�¤vâyY–E Y’d™$Ñ$%Ù ‰²A‘D‰Þ&B2ˆI0xºÅÕ`0Q0ˆFQO}Û]¦ßx?ãð†vÖ~QÄ¿¥3Ÿ’¢¥(E)JQŠR”¢ýo‘€Y‘)fŽ#UA€Ì‹¼xf– 2ÅÌF^0HŠÑh0$ƒlP †w)f–Ú1³’ÄÌ’Q”þÌS˜9E)JQŠR”¢¥(Eÿ/"‹Y¦?pߎ™�3Ú‰ç�F£D1³Ñ �¼(Kf“É`’ £l–“˜Ù K²A�˜™Âl‰bfIêo�àq’(Žþï1ó™OIQŠR”¢¥(E)JQŠþ·H`³š(fNì‹Aÿ�˜$·Ï›L&LF£"LŠ  E‘£,›ŒV£L�0$ÈFƒQ�² ‹l4Ró)?tœLIŒÜ�ØíÉÄxø8‘Ï|JŠR”¢¥(E)JQŠRô¿EvÛé˜Y¡˜ÙØN<¯ÐÏ&£I‘eE$£l5›�f“QVL6£‘�^C3A¬ô>É e³A•†™�Oþ'r -3§(E)JQŠR”¢¥èÿ.²Ò/Ú¶¹‚%ˆ"Ì‚A0œÂÌ‚`6›e(&Ål”ÍfQ2É6‹Åd1�fÅn2Rç1 0šd“Q4™(f¶™L&“d�L²Y–;À[sxœ$S;ûo0ó™OIQŠR”¢¥(E)JQŠþ·ÈÀå4ŸÂÌ’‹ S; ‚Åb1¬˜-&£Å"£ÃjU¬ŠÉd1;…:�!䓤(¢hí -uMË’b´&üÐq²t€ÇÿG{wÒ£ºEønÀCÍs• é~SZÉ“òÿ\b·1Ž7aãÝù…l‹ëíÑÕA<°õX¾°DÞO8Š&¢àå\HžoœÏ$Oõ©f«ÓIJÙ�äB±VªsÍ[§5ׂ1)<çÓò˜b¼å¬âütjO–sΫ¦âí´q~¾Mnâñ_�õá Käý€£X"ÊQÏåŠùFU‘>µ§F¬N'­5#%•á\›s#Y´VX)„VQŠ)SK\2)j)§?/ RJY·µä†ñM¼Õ›xü ×cYD¿´DÞO8J ¢¾˜)3eÛº¦é_Õ™Z�ÏÖZNF'…sU«Eö^y-¥3E«©ÞAŒ¤æZÖZU•¨’ÒZ7¬QÂs±‰·n�¦=WDžŸ/,‘÷SŽ’ˆhìÝÔ!^z ù3?3½:Ÿ½÷‚œ±^IêÖÈ.F�RÞöFš÷¾Ê££«JVEcZÞj„Ï·ùM<~˜¿®—‹¯Ï–Èû)G)Dt»„©C¼ô"ZŠ•¨¸YUUŒQR°>jSÜs¶ÙýÅÙ©ÞA‚´SδÎÖµ®ëœc’Y•”Ú¬„ã&?L»ç¹"B�M‚þ×~ -ÀQ"z»þ73§JT®ª*¥¤(8ŸŒN©áN_J±Å[“ÂÕÙ9ôJ2_™ÙÍ™Ù}ef§³Ò›•pZcñ“[�5;¿P¼ØO8Ê”™¿½çéwwK—˜Q©U-ýª®K)†rH�³¥kE0oÆè]IïÑO•hR䢉ŽÇÐ4¶¹…£Ð"ØÞØM¼-›xü0ížçZ5-å�—Šû)G¹Ñ?ú©CüUw‚ÆÆ4:­šfGG}îÆÆ SÙ¿Þò­Ä8v?JÊ4ï}Cq%Š’Û6´¹”¢¬Ìþâü&ÞŽ›xü0åhÊËE"zm‰¼Ÿp”"úëó2uˆ—^„¤kk[[Vm{½^]ºá–âí�ë>þº¿wïCηñ³/Í{ßÔ‡>˾c,±Ÿ]ß÷Úë.¾…¸‰··5?õÓÑ-s€~e‰¼Ÿp”ŸDô÷ïÛÔ!^zŠîÌ3ׯ»ßï‘nãõ½äû‡°cþóÛ÷áû¥ïî×ß—aZS 2¦±ÓãÀyáŸÃ8Ž&˜!¤¼‰·÷5?Í_–‹9@¿²DÞO8Êç¿Ç?G:Ç +/Length 18313>> stream +xœì½ |EÚü¯¾æ¾3É$“�™ G'™$C ƒ‘4 A ¹Ô �KE.Ea•Ȫ(Q‰®g–eÕÕáX ˆŠ+*Þ÷ ˆŠÊz²�t[53!€»ï¾ß÷¾ßõ›§3OUWWw×sÔSO=U“`'€\8&X2Ü~ÇÛiÐpñ ÚºEuKßÄV@Ü?õ²És/x(XpÛ¦.Zàû_ÿ1àz0æLŸ{éeC}p)�u0N¸tòü¹ð"3}Ë¥sOÏ0÷ÜÌn´Ïh¼ìê?\µþyàá ÀÓ×Θ6¹Qk¾­ Ëô�1cÚä«ëG€LÐ}Æe ®ž÷Y^Ð +äïšsÅÔÉ�]û´ è9Hm¸lòÕsíšå@2ø.Ÿ|Ù´~¼äR€{àÞ›{ÅüÚ(\�rz}î¼isoÿ®ÛÀ´ +Ð+ ࡇ.è4 6ÀävÀ‡‡ ;‚¸­Æ XmÚúÌßèìPÛO§fŸ|Ó¦Ò’®` +²ñ¯Ï–/¹u’­ügxõìÊã?—?NÓ/…1¯ŸšÝ¾Ý¦§0t>�.$·B„^lCñÆRþMLçœz‘3‰œÀ Ç/èÇ—xgíŸ +|âÛê(bÑ?Èq>�^ ¶PÎ Gß <{k +ÜO儿}ÈA/T`&áDñ >Ç!ü‚vŸÝçòßÖQ¡iìY9è 1 “£ÖMÓ¾8ãx[[«=¬Ý¨]¯­Þ�ý÷}s·ïl¾ýKÐam­``:ÚÏØ16žç`Åàxž‡yñ¼Ð¥Ž¬ñ¼+€1˜†Kq¦á" Å؆y˜�™¸—ÇR¢Š»Ôò±z>Œf% 1“1דּ³kÿ>” %(…µ˜‰©˜‡+0W`:À‡*\�y˜Ëðd,ˆ¿¿> ÄÌaK1 0?þöù¬­‹0 �¬¦Fö‚i˜‚y˜†«àÃ…˜‹i¸c±˜å|ŽÉXŒ+°�½y®À¥¬E>LŘ‹Å˜×ù._gÛ‹bkÇdÌÁ\Ì€C0—³gLÅìxÝa¸3'‡`!Å1ºÆbf2ZæüËöLgüð¡31sXédÆ�3iŒ=çŠ8¥>ö–…˜‡©ŒÞ—¯b²¡% q9÷|X€¬¬C1–qg&»ïrÆßóØýÓX�i¸ S·öÅ[”¨ëcåó™lgbn§OÓA¯/ÀdÌÄÌG!³#„Ì8¡× ‡ASa€QSadØ“¦Â ³Ö ¬Z¬°ií°Á®µÃ‡ÖœÚ)8‘¢�‚‹á¤i§à†G;‰T†Ó�®�„ÚI¤#Sû2�¥ý^tÓþ�Ldkÿ@|Ú tƒ_;�läh'àCwíWøÎA®ö+ÈÓ~EwôÐ~E.zj¿ ½´_нµ_¨=Ð~F/äk?£7 +µŸ!#¨ý„|i?¡ÅÚO(D‰ö‚ ¡�ö#ŠQªýˆôÕ~Dý´ÑeÚ(EXû}Ñ_ûýP®ý€2†Ã8_û;úc€öwœ‡ +íï(Ç@í8ÎG¥v0H;Ž +TkÇ¡ Zû1Xû•¸@ûU¢}�Aª}‡j Ó¾Ã`Ôhßá ×¾ÃÔjÇ0jÇ0 #µc¨Á(í†c”vµ­ÅŒÕŽâB\¤ÅH\¬Å(\¢}‹Ñ¨Ó¾ÅD´o1ã´#¸ãµ#¸´#¸µ#¨c8‚IÚ7‡ÉÚ7ÏðLÕ£�ÚaLÄ4í0&aºö5p©ö5ÕíkLax*fi_£³µ¯¨Fj_a:.×¾¢öFû +30Wû3q¥ö%fažö%fc¾ö%æ`¡v—a‘v—3|®ÒÑÞ®•X¬}�yX¢}�ù /ÀµÚXˆ¥ÚA,Â2íà?ÇÁåÚA\�åÚ,Æï´¸†á%X¥ÀµX­ÀR\¯íÇ2Ü íÇu¸QÛ�åX£}ŽhÒ>Çï°Vû+ñ{ís¬ÂÍÚgX�›µÏq=nÑ>à ¸Uû 7â6í3¬ÁíÚ§hÂzíSÜ„fíS¬ÅÚ'ø=îÔ>ÁÍØ }‚[Т}‚[Ñ¢}Œu¸[û·áícÜŽ{µ�±÷i¡÷ká< }„;ñ öîÂCڇ؀VíC´à�Ú‡¸µqþ¤}€?`“öîÅŸµpÑ>ÀýxD{à/Úûx�iïã!<®½�VlÖÞÃÞˆ-Ú{ø¶jïa¶jïâÏØ®½‹‡ñ„ö.A›ö.E›öþ‚Ú;x ;µwð8žÔÞFOkoc3Ã[ðŒö6¶b·ö6¶áYí-üÏioa;ž×ÞÂxQ{ mxQ{;°G{;ñ’ö&žÄ^íMìÂËÚx +¯hoài†ŸÁ>í ìÆ>íu<‹×µ×ñÞÐ^Çó ¿€7µ×ð"ÞÖ^ü£½†¿á]í5¼„÷´}Ø‹÷µ}xhûð +>ÔöáU|¤½Š}øD{¯1ü:>Õ^ÅøL{ob¿ö +ÞÂí¼�ƒÚ+x_h/ã]Ò^Æ{øR{ïã+íe|€¯µ½ø‡µ½øG´½øßj{ñ ¾Õ^§8¦½„Ïð�ö>gx?ŽkÃü]ûâGm¾`ø~ÒöàKü¬íÁWøEÛƒ¯qBÛƒÃ8¡½ˆopR{GpJ{ß2|Ú 8Æðwдð=!Ú 8Nˆö<þNxíyüÀð�DОÇODÔžÃÏD§=‡_ˆ^{¿ƒöN£ö,þALÚ³8IÌÚ³8E,Ú³h'6m7:ˆ]Û •a�8´Ý;à#¶‘!Ê)–ÓVngøG†ÿÎðq†¿gøÃGþ„á�þ€á·ÞÇð« ¿Ìð^†_bxÃ/0üû~ŠáXË63ü8Ãk¾‰á&†×0\Æp?†W1¼’áë^ÆðR†§0<’á! [)>-Á…ÂQ(·Êdƒ%üùþÔ´ÌwÞMMË\rmªwɵéo¾•š–¹èªÔ´ÌËæ¦¦eι"5-söå©ÞÙ—_7/cÁÂw楳RÜ™Óg¦¸3§ÍHñN›±úÊŒôù©×T¥ûW¥ûÏ Cî†n’Ü%|… Èƒù­.-{ÿÓ¯ ØÏ°O8¾Õâ+m‘-¦”ðm·ðýVoN¸b Eø ·?‚ (Ž¿gm>¼Õd=E.ú§¼œb2vks÷ìŠgHå?ï°‘�¸Ÿ §íßö÷^rXi#ÊÖó«bi÷ž4­ØšŒ¥i™4=_IÍ“Ã_}ÍËÊ×ù…aåkofX›�nÓv+©¯aåÃ^½ÃcFsò胜싚,á„#DñrrG»Q>õ¸(ÿp�“Ÿ‘“•�ÒÒÃää6m÷ÖƒEÅì!ŽƒYÝÂÊ{iiáoŸæä§[8¹�¬Ú²Á(·‘±dy,¹N±m0Êwo0ÊZ8¹¥Y”Û´ýO|—’¾mOóŠù'Wjøh³ ¯kîžM LS=éáéSÉÍ\¬BsnÏpY?ÈýViÙm„l_ÊÉíåd)ßÂÉJ)ß’Ý=ÜF‚[–òr)ÜºŠ—ßh#ù%Êié¬Á†rrÃÊsiiôlëî /MŸØmw†÷½JÛ±û‰½�@øå—X^I=n²„�,ãä¢)f³TµùqN~|YŒoÛœìOõèÞE®ÇÈdõ–&#»3sm·ná5M‚Ü´Ê(ß´Š—W\Gä¥ËyÙª¹§xÒÃSVùÆUD¾a‘W¯"òÊU‚üͪ¬âf®"=Vo?·§¯Û]êvöqÛBns‰ÛPì–ŠÜ|Ð�B÷À<2ŒÔÀ�‘d8æ’a ¤?96RF°’¾¤¬0‘2œGÊPóÏÏ+¤ L¤/Î#}1žô;éB¤-¼–=ÐOŒÄѬD":X1›èA`"zœGô¨ùgú$Ñã[¢Ç)¢‡1b<1â&bO$%‡×²ózX{ö°•öµ†úÚzËÖ|Ù–°vغe[}Ù60(þˆ6ÒŸ––UÏlh#e´;ïËÎûbÏêÒ +2ÁÂsšvn;) Kþ¿‚ùóåù ÔÑ+�z¢5c~ƒó7(×GŽ®¬‰êG×Dõ#ÇG3•5Ñ—F×DûŽ5*7ƒ«»™£HâªÆŽ_7ÐM ‘”£‘ôA#)A# ¢‘¢‘䣑˜ÑH4�„(6j�jc{ã��o<Þø}ã±Æ#�Ÿ4~ÔøAãÛ�û_m|¹qoãK�{_h|®qwãS�Û77>Þ¸¶ñ¦Æ¦Æ5�«W6^׸¬qiã”Æ‘�C­�ÿ)'NCä¿‹,‹G‘ +¹ñ$pW+ÑkkNcu„ÚKû™Õ‡º3V“Û§€…¢}ËG`´o»>I;&„àD+ÁMX�«ÔÇWôñ�;mŠÏ�§³\‰å˜òo"7ïá½ÿ0ÆÓ¢Ø„uñü&´v–ÓüݘÑy~'ÖÆ[¶’¥ëÑÔ¥ö¿‡ýØ�ûqˆ7Êç›ìkŒÚGÖùéV24Š‘uôÓ¦,ó{£(óG¼QŒ®‹vKœF"¿ÕÈ€¶û¬fŽ MöÍæôªAQ¤l†ù`nZíx¢(�ö”£\®=Šrö4£$å‡(qE‰»6 +癯 ·í/û T7Î +T7ÎŒ¦W56œæéñGý¾&_Óè:GÈë÷³F×D_U·Ùd¬ +TM3F +òÁ +°Ùhª +T™hAÔ˜»™˜–áÌÕý7sÐ[ +ò£NÚÜjú™Unjˆr¹�A~¿¿ ?ê:}¥MÛ½¶ë%D�r"çŠåb�ˆJUQ]¬¾™Qer7ù6çïnZÛfÇ”ÙÜhœ<¡.ÊOŽäoŸ[=cl4³f为(Ÿ[M? 3|T܃¢ÂóUÏð5Ñk3¢|n`úå�3¦5P5! �AùQCUÝ þÝÞ¨³ªî†ê¨CŽZƒ¢–kyù¦jÏL=mjºÁ½T]׫~Š#‘ˆ§ ß×T¨žÑ0¨ ¿zV%I°SlL‡62á(7MöE—O™Ó½Ékúïo²GÍ¿ø½~¿ßOÅÃnŒ³²±amò¬É”ÌêY¾¦›¦1R×2Òü~¯¯zÖ ú¡7úª£¸(ê©WW=#P}ú…¾¦Àd_”Ï=û^¿?š.Ó›šªi'7VäÇšM—O·Ÿö ¯L¢\nUTËŒe2ðUG•Ƀ"ñ¢x…qô6z¥aP$â�É�ÏõEu¹7ˆ…_}¢.7š"Ûý/ø òwä׌®«äeÔG¹ªºó�y¼Ç"ù5#;‹‰§ft]Sð˜7Æ£š1�šQ1-˜‘@ cc˜ë”¼ß‰×gOÝçñî‹ä nhjð njhšÜ¦-ŸðÙM›Íæ¦¹Õ >ÖóÉä6mçMÞè൑¨½aé_�ï£ú6xtMÔ5j<Ï`ߌÉ1cQð—yýŽH¢ÎÈu9ÞÏ¢ºª¨ÄúY“ýhA~Ô\Uç÷úSóÒ¦/óFíe´›ú¢¸¨®ÍŽ©LgšŘº(ç¥=…�äVÏg�ןPj÷FÅK#ù~?íC7µ)˜R�ï�.U;÷aŠw ” ‰r ôÊîÄ÷EôÊòÄ•ÎÛþ‚| ?ý[�îªÏMŽ€Ó2þ3sÛÝ=¶®M;QÕ—ÅÅíªªã½\<Çyyš3Ê»¯<š&³)O¢=å&{À÷F j—£bUÝnoyÄgwDá$ùÑ!2í5\®ý�À^Bm'RìQR%©´®(a&�O+‹W§òøª›âÚÕ•¬øÐ8ã·i‹ +¹ö@Ôü‹7Vßá P +_e&-n©sÓ¾äõÇj ‹D­ÔG­G*È�z«ê|QÒPÅ(–ñUûfPaG} ƒ˜ˆx»·iûQ³W竦U¼qµŽxcª}–®ýç¾ü&otÅÚÈŒþùQ¥·¿ ßW% ¬·Œ­‹s©ÌïEô]C))g^ïäb¢Î¹Ü­{ÆY—çÒÁ_3¶ó„>7:XN<*v~�ìíz:ä¬ËC—år}Ž¡”©mÚî2ïecê¢J¬¨ftÝRï5t<áHåæ¹qÔf…Ü8f\Ýf•;ì€ïƱu[8ÂU5TF6w'7ŽªÛáVÊÑRZHO|ô5¤ftÝNÏê{w(ÀrvU`ì|j+Ó'ʦ¶q±2{ìEyìE +8LmbW”DmSÛô±²å¬Œ \Ö)FQÑ+ÅÌY8ïfB‹¶ˆŠ~' [ÍÄB¼›—sU£YqY¾Ù xc5–Ã@”X o¼èô«/W·Õ ñ2‰D*)üSTË£\ÕÈ(¡lµS!úö¨/c¯·ÉNÍu4"S“ö%µƒ3äoÎ%7ŽìJÓ„hJÍèñÞ(‰ðwt9Và<ƒvR@†’ËÈò +ù‰ÉíáÍüþ#Á-<"¦‹õâ_Ä/%—T#µImºJÝúˆ~�!ÕÐ`øÊØß8Âø“Ù4ÉtÔ<Ýü±e°åAëyÖc¶ +Û]ötûqǵŽ×œáÎc„s„ó]×(W[J(å w¦{gj õÒÔÓ +Ò.NûÉSïy5}Hú³¦Œ{2:¼³½/fNÉlÏš—õÉo?ÇŽnÖÿâèÑy(Ý”n+OÙ¦.Çàÿ‘c|òHÉ#y$�ä‘<’GòHÉ#y$�ä‘<’GòHÉ#yüÿìX&öÆÆÄ¶®8–ò<ô[›'¸YXËÍ¢ûaq1“]èÁ‡p+Ù…¹|7í�0 #AÓË„‘X"Œ„U‰Va$®FbŠ0ã„‘˜HëÓ{ÅÅÄNŸCSþŽØîQ±R…;°Kø Å{°K0c»Ä¥˜(>†]œ»¸�‘"´bÿv邨%¶c—¤ÇDaI<Ý‹]‚‚ÅB1z‰×áa᜺ÅÈÚ�!Ì�S¸þ³iãGÇRÁ‰qÂ6lä· AØŽ!ˆnJYþl$Çq+9®õçO²üFé6Òr!Šz­Ç½„�ü4Ìà¶CnÀ­ü»°Š/ÁÃ?Š þsXù{Ï}ÿ¿Úþ®ç´}ÿ齿´�ç”Ý€[¶“ôÜ{Æ�Ö‘®À�ÄÒÿ+mùŸáÿé$! IHB’�„$$! IHB’�„$$! IHB’�„$$! IHB’�„$$! IHB’�„$$áß‚ô5¾G÷¥ +«ÄEà¡C†bÒ^/ŠÁ}Îpp‚û*ö…~G®ßáßÈÖ¾�ÛÞ1L\t²i½0â?æ–‹-ì %Å&d AááuA/q:žGEh_ :ÃÁúâ"â8üŽ€ƒôYG>]'¶¨É3ôCIf­º“»Xl�Y´›H-¡¨Œ#ŸxD"G“^o–jõv“T«?ÂÓ„ÊdÙxï**Š‹H½,“v‚ÃÎ�½M}™ô]¯îQw’)œŽ3�ËÕUªN5Ñw¦þ³ð {ç°�´ã[M¤mÚqÅd"µý ìÍ|›vü¯ôEGômÚ ÅB_­7鈈#„¾Õá Ó6t¾ÜÕùò‡o#eêžõ¤LÝI‘ŸÉ?ȵêm¿vüƒ¾û0®Ö 2Lªøy« ·ê#t:áéˆMG,¼V"ˆ•¢QGžÚ´ý[ÍR­”„Ãûdb?OpÒÄzÙáD8œá±³+."”¹þR¿#äð ëÕ9«ÕËÈí«ÉzÎI3דÛÕË@ÐC=AÊq<ª•¬0O œÂoà3Kµèi’j±œSéC¸6í}+M·›¤Z.(’ú ,Ëûdö_2öQŠësù€‹”ß¿pá!5…¥´ÝJNr[¸%à‘©Ø92&r!GèoyÁG Ö묗isKýÜ–ŽÏ¸rr½o®v„ŒÄ+0!Sq@ŠŽ‡Ëðx6ä9>h!õÁ+ B..JËÉ+íÓ7T’êN‘>/8°0XY™ZYXXUUXX í�æä ˜^¦+–«�Ý„Zú³h\0ˆŠ`q‘ë ¾ cäî1±åWK7‚ÃÅÚ×|»¸vxÐKqc�Ñá^£m®–ˆM'¦µDÄtTÈðTÈÄÌ8æ )×S8I +ääåq¥}œ}û†|¼ÝïsØý>¾}à’­óæüyAyÅ5]Hžß¤~ªî#¤÷ö6õÈ3S'm'†GvßóS;\cǺŽ'ApàÞwŠ,ÅbÑ¡‰èu:bÑ**œá`ˆ�í ù+¯+À÷ qï´º†ŽŸVÔwñÂy„÷]ÅE½Ím¡Šj?åêePÜ‚Þ(Wºus­1ú�ü¬5ŠYV_Ö†ˆÏc4ŠV±%bÕ¡Bv ä V0½JÐè +)."} +¹@ޕӕöí*鯹S¬œÎÊ»ýniŸ\¿ŽxîõõêxŽ/¿âÊË+´¯yUÜú`°ÒÝiÄ¿¿¯œ¾F1fæµD223‹lNgŠ-…uê¢.�šµžÚóp¬—Ðî'Z]ïà%inÖnwˆ5Yïî”n¥ŠW]½qòœG®0fë×�»bICËåç SM¼svÿMy̨<Æp¹÷ð™Ê€éCz’¿ÍŒ.¿`ÜŸÚð$)þpQ¯»Ãÿá³·* ¼ºæê±…Ζ”~¸Ã«:ÞZu.- ¥EB:i‘ˆ$‘.´pñ÷pAù… :ƒBJÙAiáVu\ËOà‚êÈfR&‘Æ;Ônà°RûŽ/f¶&„ÁJœÄ.:l)¶æHŠ€üîùÑñÝ]¾ïù¢Ç¯ëIzöt¤¯2KÔÎp„ƒõÞ9À”̾'†‹‹&M¬'Ì 13‘ÀS¬‚;%5�Ïé‘WÚ§5ê©î�D.4XCÃÇ å*cƒ¾vCëðë§õïsá„ û¤š.ÈÏ¡ÿh¶Àï÷ç�›3ÆôR.7æ¢ú²¢a%é«£ =/\4bØ‚ÉcÇŒë[X“¡6ø|…Ál¿?;XèóQ)ÑßBqŠ-ÐÁ†7”|�Žè%b°›QËé F1Y¬6^0ó1bç ½"xL2œ´i‡·ÑŒ¹MÛÍ2&Êý0ÍY-£ šÌz‹TkVœ©CÌ’¢·q¼�_±Ù$žˆz›ÙÄsVƒÅh¯ÉÕ b›vX±šÌÃpˆAG((Ëõõδ0‚ÁŠpP†Ýó‚ý… û§²ü‚3�ŠO&²,ÓqÃîÝÖÝ»í7Xwïwï&r}½?Àûù ¹ø¼IÇ‹Î�wuÜË“\Þc÷0™£åsr›JÝŽ[¸©Ý*Ïtü�Ž,»!(¶À†4dãÅl°ÉDx�Øy�¶²Ð„Z½Çáð¬‹8ééë"T%ÖEoH7K”h‰vk‰vë¥YmÚñ­©–¥æXªMRmV–H«‰K¯s7�Cºõ&©Öíö;Ò)ãÒiQ:-J_†6í}Ú´_è3è¹b ³"¿bB-5ò7²,Sç@–뿑ÉGøÜ�ŽÎ5@YVrø™ѹSSÝ)B€w„Jú–öñ'Ò]ä®�­Z°î1õÄÞ“�6Ý«{öÐú‡Ô�bËöÛ®Ù–'8v¬o;$rjñêÅov´t´¯½F¥ÁDí°°VÜ76(¶j# +2Œ'¶4bæ TIÌfÔòj�&¸iA• µn·‹s­‹p.˜ˆ™7™,z˺ˆ^€©ˆªT…‰˜LivÊ\;åš}©h·Hµ"e’è21 Â(¦³z9ÔÅí‹çä�#ÄÔ…Žúú\)àƒÃÌs¢ÙPI?aí}ÇÔ×Ô[ɽdÀ«×·ìüUÝG²¿ùàÞò±¤‰(¤Žl:oëÅêvõ¨zRÝÛ@{Ð.@ïAw*yà xba`J¡§J!Pq +´¥§°ÔÒ¦ýDÅh‰«†%.VK›vDñ˜¤Z‹Åa ¤(©ªG†eLö1Pã: n¥*�5“},Û9¨QjAÅ죤òŽ¥Ù¿‹¬å~QÇ«÷½óÉ ý;¶‹-Õê6õ2‘;u)$n®¥Œß&¶À„¹Jɰ."qDZ'IFŽ×Eˆ“×E8^Ð zÀ"iƒ�´ÁFÚ`ã2§Ž´i'Ù8BSONkk(D§¿�*Ô‹‹ü~‡ßÿðÛ:ôÜopRÇIn¤Ør—¸S5ÆÛ·žEJ.Uòi[l1ñ§×9õd]DÏ `â$Ú.‰¶K¢í’–éÚ´S´]º8×iJÇ[]Ð %t¶-Þ2g˜…5X,ƒ6)àðóëc ÚÄ} rªýÎŽÕôÇ¡bšO=­t<¦`$6�ØE¦óç™QëI[ñxôHhºÍ”m⌧u=-Ím7™ P) TÄ´ÁXænÓ¾£ ¥©’Ãl„÷Ìž@;ëö3{Bœ68»K„œaÆk0ë™+ù£;°øèê uŸºšü‘T¹ï±ïþ®¾Jºý¼i‰º‡œr YK“ZòÈð�—«ÛÔêquo¹í®˜|„˜þ,V†èùu½$ê×ÉEÄ):�¼Ä@i€tšÐë!” â¤êB,z�Öh �Ö–‰qC(Æ{�<ËðÉ´ïWTT$)Ü£ñÂ�ðÃ¦ŽŒM›¸¯6q7wÌ[:nâØüe@YdƾËqr<**Hð»=D7m[@�¢æd±f\¦¤Ñ2LˆÍ@ì¢$éyýºï2ñ"µí™´}"h§íôÐ3âŒÚ?â:glÓNR�3­‡³ÓZ—e6S¢rJtÞz’’˜�:!Nþà¯cûö½ø‹M§©_z6ö +ø–8·[`Ç=JæR+ée [¹e„ô&ý g÷˜-d¸�/­‰q›à +Ê�V;EÚmx«ÍFìsA@/¦S +à4ŠT +±±ŠJA¤=èx¼�P ´ éYÿIPA‡íúp(¤²`Ã4¤åúz:&“¼&’Pß~$D„�t¼—­6m¬ÎófÇîÖ\KDZ¥cbª—»²cd\F|«Ø×+"0ëø½ÕΔáx\)ØËRKo5²tÿVKw+cöQÔ�£Y$®Y¤Mû�ÑDÄ®¶*n\™m­ˆY¨�ÃÏ·vx6qŠØrR�·Rš'¶À‹�Šûš ²ÐEò\}]ܼT’Ê8mI0Ÿy;ýh.5ƒˆ‹ät8�¼pŽÒdЂ Ú/¨ö"Åí(�þ’,åšEªuYºØJ�}™£Mû�ÒãˆkœƒN!dY—ÈÎ0�PÔ‡aᘈ¨xXä´Þpôé�t„I*ÕMeERÓ˜´¤y² +—š:ZMs§ +ú?#m!›$g�gß⟛÷ÇɽOmM½øùvEli÷Ì/êÏŠqFTĸðÅr•™Ì3‘«9²”í1Fjmú8_N(AæC:‰(Œ¼�ØÎµâ üp8(«ôžt“Tëp›D=­«§uõ´®~™!ÎCBWcÃiB®á’87ØIÁ3X8¶S]O3!¯Ô•×:ºe:%ý¦�¸× +,‚q“p•,¼óÔObË©»g hæˆÍº‹‹[ØÌt…Ò Îu¸$óºˆ$œ=¸/uÇUØŸÒ”9‰>w‘›s»Ómô½ÃFï°-å©¡ä©å�¯9¤Ÿ¼˜t–' ÆÌ;Ã$nß)æTõuuYD*I/2[]«¾sPýЏ>=Jìê ¹�T’qäu®ú”ú€:C,Qwª¿ª¿ªO‘>ÄM2I߸$ô[`„·*½K„³³`ƺˆÙÌsNÞ´.Âó:ªË:}§¹Xj§ý“ª-í ݨêRJìö3¡ÔÆ”�RK–qñÞɵi?1)r þŸá÷v!˜ž1'—-ðP/q÷Öî'�›HÓWê×ß?}ì 5Êuë8(¶ìõUµ�;Ô±í¾u$“ɯBÊ· ÝÑWÉpÙ‡ÙìO\vèõnæ›f­‹8áBÅžN†‘BÁ�}›\оy{¿¾~_ZªÃ®“tÄŸ+ñ9:ÉaOK •ôëë°÷ÈãTõ�O<¹‹ $=·oß™_BnW_W˜5ïà₩éÓ£7Þ¸j•gï^RIÆï{í¥—¨ ^-¨Ÿ¿ìKzHýU=ñÐ--ÄM²ZîNHc·Ø‚LôÀ“Jÿjá+±qÄ,¦uÓë»­‹èõÆ,SÖºˆ‰'Æ4ƒƒÊ%Ö“¨\º/u,æÈ5„pgŒy,—É9:<0;Õ«Û9Nª1ÞÛŒqŸÏ÷ùŒT<Ôü”Ø÷Èõi%t0`ªŠ`è¬Ù �×O¢Ó·B>ÀÂÆ‰Ð¾»ŸF‰0­°û¥ãþk‚M›È£ï[XY0fáÐî¥EÁ¬ŽÍ‡*f�Èoþ=¹­ìÂ’´Ž{Å–`Ã- 5K§T»{¯² ‚ü˜Žy\ªÌ_‚ÅÚaþ3q Jñ–â®)%à +Éà\2(ƒ v“>3j{SM5£¶'aP›N9r±µzÕ�ïÊ<Å ð3ïõ(ž¬u�BL<).–ÖEŠ]^o~åZetetÎR—‹äÓ²|Z–OËò—¨A´Ñžo C?¢��B¬KÇç[Ì9µ¿Àü9dxìû&M¬w„Jñyq|À­ïWÚ�g³¹B®G! Ñ%‚Å)ݸ´Ó±ÌÅ9“fÎ*¸{ChÜ’ j~×Ðïâµ[ëß™|Ýßú]~qß^#ç×Ô6Í8ÌïÛ¦ç4Ψ￧[‘ß9Nÿ‹/Ø=oÄÄ«FNY7±0ôT]ZŸÑçõY9 7oìôkGκ}B/“;½ÁÌæIËï$¢$®‹Ht g +‚6í¤ÂÖùDX9^¬|]¤> GÙÃQöp”Ü2ž:Ç|bÕ“ç zƒBEЦíÞBg²£Óíe,#öƒž`!3 Ô«ª8½ )˜Õ)›Ô©ü"wR9ê±>¬Þ[`Á5J1gt9NïÔs&�3PwÝÌ‹ü¹c‘‰˜Ì©Öd¢¤™¥Z“MG+éh%­¤[&´iªb ‡[1�701ðP—µÓ^Ñ•:GÈK„w;>ïøeY@.ÝÄ êhåªùËÚïU/ óW‚À _1û%ŸÄDt\5µiol5“Zu|,±TÉ1‘Z¡ÈLjŸ…"© ›H_�,Ð]OÚ»©[Çœ¾ÓFÚ¤ãxž3Q)˜Ú´vÚ¥iÊ‚—¦žÔPÇ’þÆ)‰­“Bj�*¦'èõ<á鬜Æ#¨kXBIV8Ãa¹Óï�KA‡ðUDZ'ž$¿w}:i[NN[NÝÒoHyµpõ¹2]õ¹È@Å·ÄKg�E)d‘…Ì7“…²„#^Ÿµ¥Ðnk0¡ÖEƒD­™rÇhF­QOO†X +tIµ,´Hg²ŠÁŒZÐø—7Î]oœ»^zƒËDjÍ”»fÊ]³ÇD¨»ù’’C›VF±�á4 nc˜ÍÙÒâC¿�¾$‹jm®4Éhâ�).‰pi£-ÍG]$úBèû•3jm”(›”Æ›€,S0‹ÔÓˆYÌ›“¡Pì/áÓÄ î‹Ÿ õ1 1Ÿ�ù~�>_<Õ5¨³_T?t ‚”¢¾ÿ¼:a)v‰¢˜A΀Ùõ‚�Fr©xOՅßúJl9µ­º¦t¼0üÔ£áÚ>ô?É1i -b ÜØ­¤/q‘kœd¡…,0“z²PGsd !.JŸƒÅ}ë}ñQh¿b¤9—>&µL&F*!¶ÂfF-¡×lž„�ÍÆ/ÆÙlK|ŽL¹+L¼Ám4¥°Ux Íd`sPÇpÕÑ=ŒN0®+Ó⼊»†ŒW]˜%´ìS·Ûœ‚Ñ£>úÙ¯~�äf¥ +>)~V=ŸËM/L+êø˜{“Û«êKJ*óÈOáx?n`–gšâŸ/Á@ˆÈ;-¼È8jM8jM8)fã š*©Ì Š–¥€MbtK¢ÏFêƒ!Ú×¾q$¬!õó©[´�.ÞÔê�îf j�Mjè2PÊâ�™d¤ØÒ~uÇwœ•_ÛqµyxN_îFú?î„FoÙ¨Xͱ&‰Š¦˜æJQ އ ðýÅa"g3Å|‘OãE"d]DpB¯ÓëhxFb¤¡æEJxvÄlŽŸ¥Ð¡ÏLéÓéˆ ç4¬îL ƒ‰ÙXÌw¨8í;PE–ejI Ý@„Æö6¾Ï©7ù�œqÞ©¼»‚ÂÛwQûõ}~´6Ù‘ãc\lLDvü¶:—WjÏ͵ÇÖ|�N’Ü)©Ô/àW¶ +³ßØð2š„ÞÞÑ|ç‹dfë¯óÌŽ\sßým^O²ƒ2—mjP·>Ç>êÒšI�¬¤^æFí°0V< +;²p�"ÃHìï&n›»9bKÕy ÞæˆÁ.àìxøJOÜ•÷PWÑÌÒ/” “TëñdKœ“VwÒêNZݹŠ�õ:èsTå ›ëdw Ô�áûÇ9Ð9ÖOšXŸpÇ¢ ¡§ÛÎrø8át¡_"#„ÖVañ7/~~òÃWæüñºæ?ß{Ã-�­_/íhxU=öµª©¯pCo¹nó¡Wyîo hÐóSÜX­Œ¯ã‰Á–nãLp3Ï"ØÍ.•ôš#z;|fR ˜¨MœIª�k"&Zf:{¾¾RL¡ŠV]‚xÔC�éú[—Ùx¯¸ˆúɹR ¥}wêbRíÇ7,zðcõG’óà —ÎûÝö>ußõ‹‚�¬/:H¨dÓÈOl{#B¥Ø ìq)Þ­”Ù$b—2™Bs^ÑK5˜¸­n“»9b²Ûà°œ XEĘ枈kîq¥7ÓÜl%ÐC ôP=+õ´wè­T™©´õ]…ØUŸ;…È’â"±�+1#4äñ1ñÅD)Ø[…yß=û5Á»o7­­­Ëîxô�7­yä±=ÄuL%%¹kN}qçµ�~òÜæ}{bTóŸ +8‘ŽÇÿjÓ»$ÑØP�É:„®¦“æHzº`3ÍCª-µ9b³_§#ºTêQñétXébë^f wÅýW| wQ€º².—7�Ù6BóäWš)ÌtÞn΢ýá¬)¬üM dž»hÙtfäO¥vwrÃéî‘GY¡ã?í(¢-YwÃgž ¶½{?ÙDn¸zÁƒ.òþ#;çµL!iß“µýëÒ›ïÝx=µ}¥w¿Ä!M;`×v+ý隌àôfÑb17G,6'×q�T5ƒ 0Ã,Z ”,%Ë@É2¬2Æçò,�Mü¾RŒ,™ê¦’ú.QÎP �ú×Ë¡àé=.Ž® âÎ ä¸Ý±ýB�Ò[äNãî/:ÿÑãÇzüñ�7Õ䋼޻¶}-¿`íÆžtR‰ªÝ»à�¹xY±ÂÛ¬Ä.ugº¬§ËÍÌájcDÚh�Ó5G¸LcÀhŽXRÓlî,WVsÄeÜé©ç¸ù« b<†D‰cs4™Òmè!øhU­ê£U}+íTÂvªèvªèö`�ÓŠÞÅr§…!ù3¬sl• +“êsí~ùõ9âêowRõ/=[ý;=}ó_þ@®~ûÌ7§>z½Qhmýã’»ýã�MÝñê�ÖrÛ܈ã+"’>oîxýÎkûôo�ì{�jÁF€?!…w(=9;áìÄ.·ÁmlU}#ΰNGK=ÿ„Ò�õ|—ùìÜ*cžgžº�…à\g.·œmÄ+pÀa§ÄÆ£Æ!Ÿƒ?ÑúÝÕ­­­Â¢�È8nQv¬ëØ%í˜õœ: ýï·dºø!Û‹1B @š:V›Å0…·˜ù)ZÑÙcÒ*K¼m–xÛ,‡=¦°t®ßÚZ±ç¬]"®€#t2À€ü‚ŠŠ@k«(”ž~aþ€“íôß×rZµk‡ÌVúp± ×Ôñ“�-4GøÌÔ)v#ìS´"é&_g$ÆxÃŒñ†�鱆ÕÓ–í‰5-14쉯øåv]1躗… {å©Á•Ã*÷·ŽŒ·[nW¿÷m( Óù㤳ý]µÂŒ»û5fr•‰zçK�d!æÄ|ˆ0÷™žåÐI8g‰[tmŒ&¡�"êÃA¡{˜ÍÔ,Òµó9Ë:«D!¾×¶³¡ÏÊ#6ºÓµíúøRBumâ« l—:áñÅ"ü‰¯Ôr:œ“ÇÞWsÉQ5E<Ú^AÞU�1zÈ0ñ(xôWR‰›ûM�VãºÌxMˆ(œV¶—š­ km�Æž(�<ÈÆ§Û‡šÉP�tkÓ?A'j~Âg¶io(ùt#E*1 ¢;Õ+X<–æH–Çóß½þ¨’Ißo5:�•)ZÑA+:hEÇ*' 4SÉJ=$ïÙA¸UF#e§Q±�Z›‘˜yŸß¸ª(6ŽÊ²�-xâT•ÈÄ~yÜè/Ô¿“Œã_¢~ûé½m;ï¹ï‘G<$ûáHŽúÕÉŸÕù�ï?µý­×žÞýõöÕ^Õõ3¼}oÂÛlRÜßÿïyûγ§¶ÿMoÿŒÑ3áíwJìßxû{>;ùáßævzûÍâûÛ~ÃÛ§~E/æWPº›•Ò˜kL¼|Ü9¶Ù,qçØâ°žë4üO;Çi¡sh–©ýëâŸã´ +³|ö‚ÞšH�‚ëÖ?ºqå­�¨½¸^"®c)ÞxsǾæe�}ü·Í{_ŒõLn—à„‘0k‡•”d�[oŒœ•-Ãi<{WÅ*]›ö£b¥ÁCÔ‰g.‡é,u_II°"áâuv-æÞí’GÍü}k«¸5¢äðãü{éøEÀÛs[©µ˜¡æm‚…x@I×å>•ð31еAbd;m¢“ò·”æŒeÌ×ëië&¤¤¥§¤7GRì Á +›xÂðÍ‘‚Ô´´žÝVÚlè¹’®³8ŠO,9Q,•2ã›k,ôNãî�A÷=± »Ç¾‡F󪂮“h¸=5Tò_Ûg\ÿÀ¹º´:PyùïkVϼòöÂa¥YYe#Cƒæ ïU5÷¶‘÷æF§ÞÚ+œpyûU×�7䊚¼Â�ÃÜy¥¾ž}{ç¤dô«7`øÜaÝ)‡dí·B "×*çñLKSRœœ“ÎF�F�U2étRsDg,tǘE²H&ýÙ‹Š«„øò�_IèÎS,b�pÝK‚A9áºÒ�·sJZ\$ÓMUæµ÷c;eØ\”[Ñ’úc4ÚJ8U ÁY(Oi"7·ÚÙ¾†ùØ î «uÃÝ&RËK—`²ØLà,&Žs›èNÌ-fº›Ô +ÒžÝu3Äo¯¸Ó|Œ1’ð·©›Èègöº2±÷¾§H½ºå™=©n�Põ:©JdxvÐP­n#¿pFõÁ½Èc”gVµÿ®¤ànÅhI!°‰#)TòÙÆ™X÷𱪭6³ÍÎÔÀNL�s)‰õk¢ÿÉÄ›S�&%ÑiR-ô¢Åï4æÓ�†QÛ¹Q. +ɉn_šJÌ«ú�^áßU{-;¤È¥ù×­ÎÝNÜ¢]m$ àÔõ9ËíÎõÏñjûQ[…§Ÿ‹£ósÀ€?*V£D$G÷Ä=¶bñ_†Æ•�ÿEÀ½9"¸YÀ½9¢·ýfý_ÐcpF�ŸÛñ W×þ7±ãc>•³ýɵ!~àZM‹­œJ‡¸<”D‡[H©Gšbá²ÒDK.G2Ä<È¥¥D.-…¦Å¢éâ \DÂ-S€ŒÍ<צTŒÁ^¶”\žËwtÞ¢i1›Ý1:ö<ÐwðzøyC.Ïuwœñ6¦°;êâwÜ»ƒ#:¿WïÈåH·.w€Ã~w‡ø0óâË?œD`•$óIà •î ¶x›�¤ñžtÞ õg“*ûûæqÃc?D{Ëß$9ít“ó¼þ‚‡œ?p¸�'NàW<´`þ}÷Ï[ðÙ6a`Õ¤†ÊÊñlv¤R$¹xP1ØrÄ.úA¬ ÚƒKL¨Í6�†;"žîÆæ”"�½9â!„ïÎ7Gº§¦¸³½ÀeYé¥Âë•Vúém4‚éwQ¥rÑà�‹šת”ÄÞ¨j§SâsCú½Þ L¿ÂðÝEžRÉqE‰©êsKãäõ(ís³Ž€#A¿Î-8R¤@ÙW3é²_Ú²è®Ë'ÝúÉÎ�{\óÙÓ¸û‹n¿öŽ'S~—²qÞœ«ÔWN=-ŒÛ}øé{®{¹‡X£>°ù88,žã^o`RéM¿ãã|ÖlØÍÛvÛÝÄÆ7ïæÓ=44 Ö×°@ð t‘ƒ¿Kž›Ò³YÏÞýËÔ‹{ŸîÕ«¼¿ð\™Ü»,Ü«WÿózÆRêå’“Ø7†mÛ9òm„;ce(6`Ò/ |MôÒh¾¤)FÂéy�ÃÓ@ð ÷Ñí.ú…™Ò~þ¯…�Kˆ¢î^|jw×ÕëÕm‚ºmý"úx`êc2éèwb?ÄóÐó/H�Àóz½^„N§ÓK’^Ï ’hÔ$½Nõ:“$Jô6’NÔI‚NÇÓm¶:�N'ˆ‚N4ˆ¢xú÷zú­û³¾…¯‹¡ØÛcEü—pöS’�„$$! IHB’�„ÿ-00›ôÔgŽyª‚=/òâ9>³^§§>³�t’É`Ðt’N¯3étÌé¥>³Ôé3›>³d¥ÿÌgOŸ$}æ$$! IHB’�„$ü¿ Œ,f= œö™ ÔgÖuÏ ‰úÌ�d0ð¢^2�:£^§3èÍú„ϬÓKz� �ûÌÔÍ–¨Ï,I]Ü[C§[|¨ýß÷™Ï~J’�„$$! IHB’ð¿&6«‘úÌñ}"è?1“ô�ÀóF£Q£Á`ÒëŒ&A4è,&“ÞdÐë�«AOaHÐt½hÐ ‚N°è a>‡Ž�1á#wv»>þöØÅÿ ˆ|öS’�„$$! IHB’�„ÿ-°°ÛÎô™MÔg6tÏ›èŽg£ÁhÒëM&A2è­f³Ál4èMF›ÁÀœ^]Âg6‚^°Òû$�hЛuú.>³é_ù̆øÛÙÉDNúÌIHB’�„$$! Iø¿ ¬ô‹€vÛ\Á +DfA'èNûÌ‚`6›õ0MfƒÞl%£Þf±-FƒÁl² 4x  F½Ñ �Ôg¶ýíݹrãFÐ[ï;ÐXHŠÒhÆVÍL•ÿÿãl,a&¦f÷€…×é­[�$cŒ•UÉjQׇx+öX|ÃÖãfæû)Ï¢‰È;qËÌeIò¥~©ØîåEJÙ�àB²FÊ¢â�UŠ+ΘŽó¹<¦šo8+9/Ц0|®¦ë’7jë¡Wò+#ðõXo_?| D¾Ÿð,†ˆbPËBòò ,IuQó]Q(¥RBjΔ.kÁ¼1ÂHΕ BÌå15ļ¢(Xá„¢j*ÁæÆùv›úÊÈb=ÖÛ×(‘ï§<‹#¢.™e¹byPUd +V4rWÆNZi+„±e£xrN:%¥ÑIÉ9#¡¸’µšY¼ŒJ)U³Z ËÅ!Þš¯Œ| Öc½]=V"ßOx–HDC¶sf^³m]ÓüÏî\ïÊÒ9'Èjë•ô¾bFv!è`”ò6=¯w'e„QµÑU%«VcÞh„<Ä[ÿ•‘æMzËÉˬGJäû)ÏÒÑ4øy‡xÛ‹h(”¢äfW–!IÞº Uˆ5³ªOÉ$«upƒ5––ÞW[iucMU©*k-̨(•¼ÝöX|³¼n¶Û—ýH‰|?àY2]NqÞ!Þö"¥JVÂîª*¥¤(º�ŒImýžºÎuÞÚNÞÍë$Éxí-ó®®M=:ï=WÜéVëC%œöX|3wÏä¶œ¼h’ôŸî§<ËHD¯çgæ¶’•t»ªjÛVSô¡µ¦máÍ)g—ƒ³m<{·„^EvÍÌ~ÉÌ~ÍÌÞtÚ*áv�Å7~=Ö̼äïG/î§<Ëœ™¿½uó÷î¶]bN¹Öµ +»ºÎ9[êbÛ{—{&£}Ç8¦àsû–¼Mš|²É‹›Æ5—˜R’FF7Xwˆ·ù+#ÌÝ3Å-'¢Ç/î§<Ë…ˆþü>Ì;Ä뺃”45¶1í®i¦iò4týãt⺠çKwÉ)Mý÷Üv´ô¾1ûœdî‹ì½Ë9k§ºpòáo§í[‡Gsަn»½%z¬D¾Ÿð,ïDôëó4ïo{ŠÎÌ1—wŒ�ÏçH§~¼´éò*Ì�þ¸¾õoc×]¦Ï!÷´ô¾í‡N =ç-ÿÑÃ`‚éÓkL‡x{ÙcñÍ0ý–“—ýH‰|?àY~Ñ_¿/óñ¶¡éÊ÷ÃŽóëõšè2�ßrw}—nê~~û?NC=ÿ>�syL‘òÔN½™F!²ø§i²ÑŽÝ{Ûâíu�Å7Ëëã–“—ýH‰|?àY>ÿ9þÀ°F endstream endobj -803 0 obj +881 0 obj <> +/FontFile2 880 0 R>> endobj -804 0 obj +882 0 obj <> -/W [0 [645.50781 0 0 273.92578 0 392.08984] 11 12 301.75781 14 [684.08203 216.79688 399.90234 216.79688 389.64844] 19 28 539.0625 29 30 216.79688 31 33 684.08203 34 [448.24219 0 645.01953 573.24219 619.14063 701.17188 505.85938 488.28125 686.03516 709.96094 266.11328 356.93359 580.07813 470.70313 897.94922 748.04688 753.90625 560.05859 753.90625 598.14453 531.25 523.92578 687.01172 621.09375 934.08203 589.84375 552.73438 570.3125] 66 [415.03906 0 508.78906 587.89063 461.91406 588.86719 522.94922 312.98828 588.86719 565.91797 242.1875 242.1875 497.07031 242.1875 861.32813 565.91797 585.9375 587.89063 588.86719 347.65625 424.31641 338.86719 565.91797 479.00391 722.65625 458.98438 483.88672 452.14844] 104 [687.01172 0 0 0 508.78906] 124 [585.9375] 129 [565.91797] 137 [543.94531] 2862 [862.79297]] +/W [0 [645.50781 0 0 273.92578 0 392.08984] 11 12 301.75781 14 [684.08203 216.79688 399.90234 216.79688 389.64844] 19 28 539.0625 29 30 216.79688 31 33 684.08203 34 [448.24219 0 645.01953 573.24219 619.14063 701.17188 505.85938 488.28125 686.03516 709.96094 266.11328 356.93359 580.07813 470.70313 897.94922 748.04688 753.90625 560.05859 753.90625 598.14453 531.25 523.92578 687.01172 621.09375 934.08203 589.84375 552.73438 570.3125] 66 [415.03906 0 508.78906 587.89063 461.91406 588.86719 522.94922 312.98828 588.86719 565.91797 242.1875 242.1875 497.07031 242.1875 861.32813 565.91797 585.9375 587.89063 588.86719 347.65625 424.31641 338.86719 565.91797 479.00391 722.65625 458.98438 483.88672 452.14844] 104 [687.01172 0 0 0 508.78906] 124 [585.9375] 129 [565.91797 0 376.95313] 137 [543.94531] 2862 [862.79297]] /DW 500>> endobj -805 0 obj +883 0 obj <> stream -xœ]’Énà †ï<Çä±ÄIɲTÛ±äCÕÍ80v‘jŒ09äí+Y¤}Ã,?3°²©keŸ~R-Ú«=ÌÓÅ+ gŒ%BRmT¸îjìaeSµ×9ÀØØ~"YF)û‚ÁÌÁ_éêUOgXöá5xcº:•íš°öâÜ/Œ`å$Ï©†ž°ò­sïÝ”aئÑ`ƒ ×Í©lŸßWT"‹¨FMf×)ð�€dœsžÓ¬®ë:'`õ¿{ÁcعW?�G÷mN3Î%Ï‘v‘$R"‘v5Ò>EªÊH%Ò1Az‰Tï‘R)z¦‡³KNÉÅv¡B‰boª’»Æç› -LÁc™F­Ç»V< -4Êi[ᑈøŽhÜEã^ÜŠÅôK“–a>& .Þƒ 8qìúÒocáñ)Üä–¨eýòh¢P +/Length 329>> stream +xœ]’Ïnƒ0 ÆïyŠÛCE’ÒŽJi@‘8ì�Æú ‹4 +é�·ŸbÓVÚ�D?Çö÷%&Èʼ4ÚñàÓŽMŽwÚ´æñfàWèµaRñV7n%\›¡žX�•yµÌ†Òt#‹c΃/èõììÂ7¯íx…- >l V›žo.YµeAu›¦_À8.X’ð:doõô^À,Û•-§Ý²»dÕ3ã{™€+dInš±…yª°µé�ÅB‘ð¸(Š"a`Úçr-»vÍOm1}ŸðX%¤‘B +Ò¡@:FHyF”!�C¤¢âˆI"ÊŒH!%…èD]¨gê”�{O©:{’'…ÖW�áÝñó†)¶¤©"r~¾;Ç-Å  +‘ö9n¡¤[Qð@Á£\Ũ½2?ÚÇ<š›µ`Îgà__xü"Ó8ù*ÿýï¥ endstream endobj 4 0 obj @@ -6094,10 +6644,10 @@ endobj /Subtype /Type0 /BaseFont /AAAAAA+SegoeUI /Encoding /Identity-H -/DescendantFonts [804 0 R] -/ToUnicode 805 0 R>> +/DescendantFonts [882 0 R] +/ToUnicode 883 0 R>> endobj -806 0 obj +884 0 obj <> stream @@ -6163,7 +6713,7 @@ pu,/ §mÍcB¹ÌX3¸�ˆ|—An ¡•ö„$þð’°³Öžó#¿œx¡‹Ëí€Z]ŽpÕYÂUg W-R£º,áª3ûyWú‹Ï‘¿úå?tÓÜKóæ þ¦§§¼¼Ç^÷Îõ˱ÜÝ ‘ÓÄ;CÙhÑš�YQ)¿c‰1&*åå¡R.(ÄKv ?ìž9oÐý3þÐûåÒ7¯{aùãgü¿[ÝòäæËWýªw!Õ�šDÝÆÞŸ¼ãÔXiÓ޽Ͽ´ÿÀKþ áéP endstream endobj -807 0 obj +885 0 obj <> +/FontFile2 884 0 R>> endobj -808 0 obj +886 0 obj <> endobj -809 0 obj +887 0 obj <> stream xœ]‘Ïj„0ÆïyŠ9î–$Öº$P"‚‡þ¡v@“Ñj 1|ûbb·ÐC?f¾|ßL¨lªÆšôÝϪѱÚã2¯^!ô8KxÚ¨pP¼ÕÔ9BeSµÛpjì0“² 8š%ø NÏzîñLè›×è�át“í™Ðvuî'´4„ʗνv�²K£Ñ¶ËM¶Ÿ›CÈ"ó”FÍ×)ô�‘”Œ1& ¬ëº­þW/’ªÔWçc÷ƒ€’±Œ‰�òN¿Ïm,Þ?ÇÍnWíç—ŠŠ/ @@ -6198,69 +6748,66 @@ endobj /Subtype /Type0 /BaseFont /BAAAAA+ArialMT /Encoding /Identity-H -/DescendantFonts [808 0 R] -/ToUnicode 809 0 R>> +/DescendantFonts [886 0 R] +/ToUnicode 887 0 R>> endobj -810 0 obj -<> stream -xœí¼i|UÚ7ü?µwW/U½¤·,Ýi’�¤“4Ih ¤M" 1  -âÆ2ˆFÄ%㸠ã¨ã­:gDEGÅ7TT\¢¢2˜T½wUw'uÞy><ϧ9õË9Ug»®s­ç:UàŒ©ÑŠIÙ]ÙéÐ6}줖 [V¿ -XÇìs·/-ØÍT”À®¹®®µp>�À\:é9‹Oo~ë ¨ 0Ï:§}ùRˆE‡r΢‹ç—ï=ç@ùÕ@Á :_ôòÊÇ€s`zwÁ¼öí«cwd€ª æµ»l¦32 À�‹W\T7Ã7Ä@TbÑ’¹í–Wè·ê]€ä/n¿h)3Äú@²Ïo_áºÙü¹/_²,›,OZ¾¶Æ­X;­‡la[»m»ööÇ$“”�VKïÈr§üüÏ^¦¯ýûË1�"']¿t½°ÃqO†XTå¿'&u·SGá莠ˆ®Áµ†8^­½Ät¡!ÓÆtaåÉã™.41]˜œyfï%T¦¤…1Æý�0³!l5î?ÅV¦[™aØÊ*˜À…°•º[éëb˱•ñ`+/¶rÍØÊɘÀ|‘*Ù8¶2—a£ �Ý�Íìt˜3ìpï`Ø/­‘™Œ8ó=6Òob¦ábã.ˆ‰hÇÅX‚•äEX‚s Œ‚˜‹%XŠ‹qA?¬`?îºý ¢°ÿ©ÅíX„¥X€ Æ£çsÌÅyé¾° ê�ÇJt+N­k`¡±–E¿ˆÏ|ƒ:}bµí5N\cjž%é• (+qæëÍPyÚ�A¬Äùè0¨Ä -,0ê&átL3¨³Ðw¾AßQÆøyF�yXŒ9µ;Œ<˜Æ(Ó7hÔ/7x»Kû¹8°½}Ú±‹°¥O"Êô€à æÌ—‰3MÖøþ²<Ù¯½žåɾô²¬À¥—ùö¾’åɾpU–'{ñÒ,Oö¢%YžìóÎÏ -œwþÚ ü+VºÜÙçœërgÏ_èrgÏ[à -Ì[°q™ß·<ë’z_èâz_(zª…ùQV…˜@Òy�9ò°UŽ'º™/¶‹®øãÚN櫇ùñÚS­ÌQ\Ë| ‚²tþ•�âg‹R¼ö¯¤îÛíäTÜINMX©c?P‘‘£?0‘nmçÃ?„Ãñnmg"çgVü³ƒtäà§T$ñ©Óñ™ú*Òü*2ö¯d ¦‘% È²h»–wÞ“ä|²˜œ -²ˆœ·�Ž4î ç��µ‰±·1‘;ne#·ÝÊD~{+麕‹ÜºÅiÿùÝf*rãf&rÃõläúÍtdówž478—:ív*rË{ÞÍ[èÈM[¨H·öA¶¥`h|ú²{ ùö{ÞÀ÷{O n”6{üq²�,H §#_v2‘/:éÈU�LäÊN.Ò¹ÁùÕZY·†‰¬]ÃDV¯á#k6ÐÆœ£æx}ñ9HäŠ $²i‰\¾��lÜÀEÖoà#�j··Êí®t;F¸í1·¥Âm*wsen:êF©;ïT 9Qr(2�4Â�&2KÉ„D”ùÚ~ø+Û¡Ûy‡‰xxÔáÆÃ9üãaV<2óÈUG~<¢µ¼Â"ÛÐ"{!ç�Õý—ö)æã|íS}w¢}ŠXª}‚…X¦}‚sq�ö ÎÃrí,ÂJíc,Æ…ÚÇ8ßÈ—`•ö±¾7Ð>Æ2\¬À¸T;€åF¾—i°«µ�p!ÖhýoœºNûa�ö!.Ưµq‰‘_Š Ú‡¸ µ±—k` 6i`-®Ð>À:\©íǯЩíǯqµ¶ëq�¶ðí}lÄo´ý¸×jïc®ÓÞǸA{Wb³ö:q£ö®Âí=\�›´wq nÖÞÅop«ö.®E—ö.®C—ö®ÇoµwpnÓÞÁfÜ®½ƒq‡ö6¶àNímÜ„»´·q3îÖÞÆ-ø½¶·b«¶]øƒ¶¿Å=Ú>܆?joáw¸W{ ·ã>í-Ü�?ioáNüI{wá´7q7ÔÞÄïñ�ö&¶b›öþ`ä÷`»öþˆ‡µ7p/Ö^Ç}xT{÷ã1íuü ÝÚëxÝÚkø<®½†±C{ á/Ú«Pð7íUl3òíxR{c§ö*ÁSÚ+ø3žÖ^Á£xF{�áYítãYm/ÇsÚ^ìÀóÚ^ü»µ½x/h/ã¯ø‡ö2þfäOb�ö2vb�öžÂKÚKx/k/á#ß…½Ú?ñ,^Õþ‰çðšöOü¯kÿÄóxCÛƒÝxSÛƒð–¶ÿÀ>m^ÄÛڋ؃wµñO# ïi/âe¼¯ý{ñ�ö¼‚µàU|¤ý¯á€ö^ÇÇÚ xŸh/àM|ª½€·pPÛ�}øLÛ�·ñ…¶ïàKm7ÞÅ—Úóx=Úóx‡µç±ßÈ?Àíïø_kÇGøV{ŒücÕžÃ'øN{Ÿâ{í9Ä1í9|†cÚ³øǵgñ~ԞŗF~}Ú.ôùahÚ.|Eˆ¶ GÑžÁׄ֞Á7Fþ-a´gp”°ÚÓøŽðÚÓøžÚÓø�˜´§qŒ˜µ§ð/"jOá8±hOáGbÕžB/±k;ÑG$m'T#׈¬í ¸QydÎ|À0úŒ¥‚JŽ,Ç Íòœhx�ç8�yð©�ÏòÃó4ÍÑfžçy†exÎÄqì@d¥Ÿq'E[|Ö_²€Å"œ„ –Ïôæ38 0qœÉİ'šL¼Iày“`pâxžÕqâiQljeYž7óÜ $Lÿ8¥®8ÀjRGtŽ,À°àãd‚‰ƒI€™çMf†x‹Ù,˜^0™¬¦ô<àNàYA`ž±‚ °+ðfž? ''&a—A8Ùíæœôe1xSj˜LÐ=4Ñ QD‘åÍ‚Í"šD³`Ívsª è¤ÓéÈŒÍd2™8žÓé( BB~0ž™9Ò%HÒˆ“Å$ˆ'»Õb¶˜M&‹(™aNOgÌ&ÎlfYk7›ÍfŽçÌ&«É4 Ë ð™dîÏúK�eÑ�«~œX‚9ÓÛ¬Oeáaa5™,VVM’Õj¶Šf³E”Å~œDA4ñ¢™eͬd6‹ºL™M¶ÿ3œÄ �NËNºü°1ÝA+¬¬ØÌf›�,f‡Ýf±YDÑfuZ @ú´“ÅÌ[D–YÙb±è\³˜í¢y¶Aàã™™#]š·Û6 ‚pL–Lo `‡Ý»vQ´K¼É&ºdÉ*Ù,»Ímƒ5½D�t‚ÕÊqÎiµZ­‚I°Š²E„„½ŸÉÚŸõ—fÀë•ÔA—Þ Ñ–Zl6ÝŠÉ"d;V‹ìDÉâq:ìÉj“%¯dÒ§³[ìV“ÝÆóV>Ën·ÛÍ¢ÉnuZ­–øò ðƒñÌÌ‘.E �pÒå‡a‘I–$À §N.›Íé6Y6¿Û%»vÉå8RÝ»l•ífY»à“dY-¢dϲÛ!á~0ž™9R:ƒrrœ*ªË�`�UNw�eÀ ·.'Üv»;ËduÚ³=YŽ,§$»�9ÎÌù§ä°9$Ñ! ‚$ô“V‹UtHI² ÀwŸIŽþ¬¿´Á {@tù1Yasdz;<6xÜðʲÇg¶¹¥<Ÿ×åu;œwÐ gz‰.»K¶¸œ&“Ôãt¹\V›Å)ûò ÂxúIq"í2s¤tR†B?ÅÉîLwt:áäÐq²»å ßçòe9�Þ¬PVz8\’Ëau¹tœr]:Nv«Ëáw8Æ;ˆ$'àäDH§‚ê2m¶Cr§;¸Ý€~ ~/.§?Û"y�áœlO¶×�ðx‘•žÛãð¸lž,Qt‹ùY�Ç.Ù²\¹.× $ƒÀ¦]fŽÔƒNÊáÃB—iQ†Ó›Z¼^ ¹ä�—••´:î¡¡ ?ðúr³‡gg΂=~—ß#ù}‹ÇRèóûý²CòyBÏ $rûÁ$¿žù?è *-ÍPQ]¦-N¸üé~¿ñfÄ…`ò½ÞPØîÊõ g‡sý�P^i.²S}9YÙ>Gv¶Õê·ÏÎÎÉv¸Ù¾Ÿ/k~høLÊîÏ�z9h0¨¢"˜6Fi™¶¹�•“î�“„ÎB8ˆ‚€H¡”ô— -Ì+ eç U„ŒÅë|Éóæœy¹6[¶­47//Ï•åÌ ÍxàIóopÊ˰ÿA'%{HgÛ¥/�í‚÷Ä1LziÚÁT®ÝhŸê0í;£?Ô½Ù.8©ñZݬs@ëÁ”„ôŸ±ø3>Á^£z{ºù·¸ wãu\ú‹!‹HÃ/¶þb"ÓH=)'aãþTRC"ý÷qÄ ýý<ÄF8¨øŸã¼‰opœpøÇð4¾ø™‰•A0–“ $LŽ£ßÿ¤ß x D«¸Wc56b^Å7øtðÆ<†¼‘”t¯Âcx—àWéÆ{Ñ‘¾»÷ào±‘áldjdÚW�q;p>Â=ëú˜ô“éÆ_jäªåd´«eö@æîÔ%¨O#cðn=?€ÞÁcÕùêd&6`:µ2†L"Ù8€}ø'va®Q¿Q¯è[Üw§¶^[Æfße^dmôo6á9¼‰õPðŽ@û¿¶úÿ¦ÿ¦ÿ¦ÿ¦ÿ¦ÿ¦ÿÛi=žÀ�¸QÛ¨=ˆf ã\xã0NmaÛp-6b#faƉX±Žä�XˆGNšåut�:ãíñ”ÔÎÀãxŒ� $ÎÜØ1sFrZó“'MlœpúøÓÆÕ×�š¨3ºfÔ)ñ‘ÕU•#båeÑÒ’âÈðaC‹ - †„óCÁ¼Üœì€ßçõd¹]N‡,ÙmV‹h6 <Ç24EPL¼Š·¾¥á\ÅWߦXÂcÃRP±L>2)ªÀ…å`,š,I÷R؈g£âjjÙ†ÄȤÂENî2Y¡ ¤oB -“Á…)P˜‚ð„öehsK(,½èoO&KŠ}K(P¨…*8]¡ º`B{°C‘šZBzƒQsº‚¦ý¯[ûhd( `d(PÐÜ¢äf“ÉŸCòq@Ûyš“I§´Íâ««Àµ –�¸õnGFBA�24¢P’‚c6DâúF!N…¸')pœBöÁÈŸ¡ACǹᆎ…Н¾£m€¦GR ;ƒ�Í-r, -H7*ÏOiÙ&šëÃõóÌÉ’bØfëÃõ¢^¡XÂK·ËbÜP–†S¶Q¬%ÅŠCG·Aÿ;WI\Õ¦PᱡP¨¤Xq´tk;¯ÜÅÉÜ9Sw)$®^áSH*‰vW·ï켺[œ¶ˆ¥#ÜÑ>«E¡Û“%ÅÛ@4,˜¦d76ÍhQè‚ý¯mAPg÷X#Ó™lXì �ÕÛ´)tAx¬Îôê;ÌkÓÅ„´…Ç–+¦ú–M¡�ÅQß²©A‘#Š5}æ"�" -zAÃ�0ѽ »©hOE´Ñ=åetØI”ÍßÏïU9r\q-y„ÚN]ž„¨IÎI¡H´Õ�cH¨2Dmï{� -“GÞÑ^ÒôV¶ 4 EÓt>*t°äÕBªŠ¢¨ a ÙDB„ÞÚ× ~Ju³]ÿºˆ»BÿMDƒv�9“ÝdÄÙü•�$‰iIrZ®LP¬ùÖ$ËÃvk>ÔFà­�oÔßãˆGÏžÝÚS^Æe !=£óe)V!KTƒ -â&<9ª~õõžÝ»|ÔKd%ÙÔW Þ¨^ƼÝ×§ÈQ¢ù¹R;ÈðìväcU¢Î/Šï•6[î• Žbœ§K Ì4ü¢Y4ßšÅ�;Dßš‘H¡M„„|v1Ó‡Û-Ýštó¨�ȈyuÄjcÑÙ­Ù�¸7jĨŽEu^ú{bÑ9�——UËY±ŠªÊ…ápe,X9"œÏËU±Š,·Äº³²Ü.&”¿òº�oúã /%Þ7¯»âæÝï~§¸EQßVûÞ�ç­m ¾ÙñP+¡&>w»zð4ÖùØÆÝ_èß04iŸ3Øí£�X”¨­»Ê1ò*ÁÍ -w -аS ‚C€ÿK”J¥ÁÒDéu¥¬™.-�4äËÜl,6ztž5oØmÉ<Ÿõ´Û’V>M~}5rÌ�æƒ�Gu9‰K=ROy™sĪº°°rÄ*V‘K¹]ŸK»]6*œ_J¸r©XŪrD)ηQΓž›Âãž¶ø¢†Kîë˜ÿ¥c×-wîø!6ýeÙ’¿lšH"¹#'••NÔË’É#ƒÅ�ÒÚð�1Ñ€?Z;¤°¶ÄG~]³äìFoÕ}ç4_=?Ÿ×9eþ«¼�mËFϺyqͨE7_X>¹*'·jrYdr™šTX_ž�]QWXT_ž�S^¯Ëådí SËnG.*М(ÎC'¬D¤­ÖÃ:Ý žw—Jw$­(%º´”õû‡Üšôó†´úÊàz\ÙXÔ/e¨+/#.ŠãÂùEÿ«‹8�0r¤ áN†©�v×g›•µËîø}7áÎ~ºeËâÑ6îX¶rÇúõ©ìŠñ‘a ÙÙ±ñÅÃÇ–hÇ“ê«//I˜ ï¿B]S·òîöe;.?}æÇMÕíㆠ©m‰�<«&/4r"¡PËÜËL�x"�!4ŽHtM-¥wÒM�ÒÊÆpe„�hëžX4¦[‚=ÒžÖeޏ#.;âåe¤’¸‰›0÷öΠïé›OuÕ’ûï&OVpêQP&2÷2ÓÀ£6‘Ï‚£‰kâ¨�áxƒe ¡ÓVÕ$öîça™H¥qé°¨Ûú:è{È÷êô"2$÷°:ÆhŸÓIv;"…‰‰av�X8·/ás<œô1‘(¡Ì,vŽ|¨l(M»sw­eVÊjíŽFV÷ ¯õè ô{¥¦ -Ýð�=»•¤ä¹z �TŽ—«ªRÒm£xíveyèü¢ÂÊÕU± -ý`‚çoCª†Ƈº²†�2ùÞÆI�¶·Þ¹ª>»ªiD¸2ì°Š+›*+++›Î1"6‚Üá?5§tbýèÜ`uõ¨!y•…Y§Ö‘’ÒÒa-W¶�žÛ2%’SQ^öVÈê„²Š±ã¢Ñhéiã£QPú;\öz¶ <ì¸2‘cç 8bá(Ád‰hµÙiÆÂˆf“�±Xºµc‰r“,,GÑ‚ÝN_Ÿ´Û-¦~zôãßt,?tñCK×®^Êv)w®x0Ÿq>±éÙƒÌêígÞÞ÷„zù‚Óçè–c+ÀÞfpBB4‘ ÓfYas’ÐÌê •X­Óšißnàg eø³$H/Õ«ž­þáñ;_ùªç ¶«¯Aݦ.e6÷.ïÝ·çKÝooMÿÎPÄi‰aœis’ãÌ1oNÅnNR4#0BZ¹¬œyMÆ«÷èj�Å¢ÑÉS^ -ÉýƒÞ­ô(U ¯«ÊÇv©ÿRŸR�«ÝiÈô‡Æîå”D¾‹x‡@6'ša2»$Š[äËxŠï™èˆëÀH?(úC•#{Õ¨úWz4³Y½S=Þ÷*Û‚ ÚAv4»>ÌJÄ`–Ìg""Å ãõlNz½N�rÞ�¤œ¢h¬7$ÆãqK¢ˆ5nw@ZÍ¦Ä n8ߌ“´\]Rg·¢µ€ ¡S¿Â#†ó)·++VQ­cÆŽ~E}^½G]F!ç~üà=Gv÷xjÅXõCjNÛÅd-i"ÍäþZuo›úãÛï}"^}ûdЇ]mp&žÈèë“Ç -×ç—ë0ÓmÂB¬³&È– -fЧ'†ÚÚZ�B'ó‚]­>Ñ÷ ¾Ÿ¤šÉXj|_7ÛÕ·‹ªIÃ"�½˜ô¨>­ƒ¢Q[K¢¦¦ õa5CÚAê8Û †%\'ÐÂõIÚ)Ò,kųÙf•ÓŠƒÚ4­Êˈ„´³’åu\ý®oYÛÔsÞ#uT\ý@ýg‰Ö’ñô´ôš'²]�pjbè0‰Äm$NˆÙ&–Õ…ƒ¶Û¥´d8̃%C·-q]4jžxyimmFHaQØX{¬ªš„;Q] Î¶øYc1–lr5ù•j¡–8F÷Õ±]}3²GPÓûÒXÐúY,O˜cè�níÈÃ27É(%£üìa[º´¦K‹Q~ð°˜.ÍéÒd”;6Ó�ñÏ ¨‘.Æý¿—¨­íç}¼÷~RO9Ù®¥9Äsl¨J ]U.ªÈL†òDv8hƯó,Çi•Öå2™’£­=ñ”0ÄQ[›!‡<¢:Ìñ$¤“%Ë­!Yƒ4<§>e|.UQ�©÷ÛòLVõ=²�„%.�K -ÈzÆU÷n8¥·œ~¶è®×îì=Èvõ>8ÿœU-tSFRÔ¿·À¨D¸ÚBŠÄj‘"¬ÝÁ˜M3MìX+Ën‘ÖMe&ÊÔ�^<6ˆa)~ VX)‡ØÕ}ÛF¸A}‰Ì¢âE!F åôÆ3†N¼­÷ÛÕ{ó¨S*6Ó>Ýrêzþwv;Dxôh Žë“pr–ë“cZt·Ûg_MGO²™lJi�œäs†Öê¶“¦ÔÕËH'i 1r©ºJ}åþ矿û�»þæ#ד:2�lUÏWSTç0Ö^yýØ×oì?–¶ß̆U“t½ñ»¤(Ò”ƒ6ÿ.IÓÜê ­ÌFÙl‘¬ Re©(§bJi³¦!(» [¬‘ÒÀãT®º[ííZK(U%‡UÛ¥V¿¥~G=¢žúÑ{)ÔrSÙíp££A‡K† d]ŸäêäpÈ.Ʋ:˜Oòó‹ü«™1úäxü¹AV<®ë,,*”¥êªPГ%K<§ NGçóœÛåÑ-[Uåˆ"ƒJO?ýì.2ŽÄþú·gy OÎSkþ6{î}ó:::îþãœ9gÏö=ÿ9•L}õ•ÝÏ«�ª½Ì[9õ÷Où˜?¯[ûÊë—]vÑ%¯¿¿ú²´ç;Ëøö'ÉDyÀIœ¦àjý«2"Š�!Óš„a¿EÚì!О¿Yô·'Eš˜�Õþ4hò÷;ªG¼U×.º”‡ÓôµQ¼;—ö9µ 0{–zÍ~_i4–{–úW -”¹tÚªÓƒ5#cî¾;®^P›ø�,^õõ½Ãv©—4®�?Á͘KjB4Ôe5£g<¡kÃ,í 3‚ÝŽJ\�Hš+ý•!ü0ÂúÜ>Šñº¼”h'&1ÊF69S©<„ÉŠùó²ònLf1Æ‚M4abÌ�ɘÓï/²Z&¥«ƒ&b2UŠ«[{¤×ôXÐ`žôœ:7rJ§ÎžÝг[Ó©ZÎÊÊJE™è*Ë#—Ò™hÁ“‰² -çœõâ‚Ñ3Gç–M½ îÞ?Ìøí‹,ýŸÓ‡œ9#9´zƘüÂqµÓ¯œ3bæm/-¿ðõj’8ýô¬¢Ê¼áu#GƽpíÒ»”²Õ×}…>‹»°24$+÷™2ýYý~^ñPý{/f³±Ç)Ixha9vs’£Á‚¥Ö”Ñ„¦ÓÛøžXE4ãskœ=³Y=G}B]Ȭ`6ÿ¸˜ÙLx�ƒl%Û+ŠÊt}’rZh–ÆQ´ók‚LC1)ƒÛ£»H]ˤPP–Crª`+ûîéë&c‰DDRO-ZE×ôîT·’&z¢Aß%O6ŸíêõOSßD¤Ÿíü1ÃÞŸž(¯ -�*)r‘"+)ÉPóH3Ui"EI‘"RM¨a "mN»ÆÑ€�hÚôg’‰„Ò;é 9Ó¶?U:ùcêFµë°“aLòQõ*uiÁÊqŒ�0dÆ—V3ÃÈÏéHÒ·ŒOΩí]Àvõ6Œ>gÒLú±ÞÑ•óΘBÿU§�þ‰z5Û7F$òŠÌ¤�"…„ˆ´É%2fQr¹9SG�ÉÀÑá‰G£ýˆ#üLýˆ…[­þê›�áýÇÔµd·:›\¹Çëd,¡�ɵ™¼êªWË©=Ôµ96nøTr_Dÿ¯Ì†%nL ‡ ”ÈQ1öÒžeXfs’¥ÁÐCSHm%x‘2B¹X -¯´=©Moúu… -…*u1t“óÀ�«©ý}Ó™‰}åÔÞô>Âÿ¹7¤[á¸v�ÞÇøàF®OŒx/O™8G‰~¡=ÄN‹žÓ’%‘²²bŽ“¸é6çæ$›µÑ®Ü}KÒ)ÙÅ,lL©: Ùý— ÑžxJ%bý»ÐHK™g�ÚkígØÏ¶/±¯µ_k¿Ãnj $ S®+�숟=»5=œ*+'úF5ª sáüÂJ© @?2ª¬ªŠe¶’O;?zŸú:sÎ [þDÚIÖ£�ý¡î“ÙäQõÍ]�‰äÒÍÜw ^ZpïâÃù#ÔÆ] ^תª†KõUoÔ2²‡ ! ‰¡´›¸íî-I{0¶$MËú ·ÌKy½y”ƒÛÐüY‘q€i¤3ú^v§vo± -‡[¢Âùt¿{çsäYFÝEj˜•o=÷Æñ½=÷‚ä¢U‹ç�½zÕ*öPß%«GiP_  çþú�·®½ö7º|Ž×Òל™Èu»�”sK’Ê26þ[’‚$f„SZŸÚö·ÆíøS›Ù.œ�Êþ}~ŠhÕô5ç½pH}—Ä ÷ç)s/¹âŽ[6^¸¬` Éýˆ°¤¤L=:Ꭻ¯øí�N㵃̒4�F&r騒d³ˆÛæÝ[’¢d‡L°ÞfËó®RÁG,ÖO£ÐݘÁDªrbž˜")¢¤Ä,Qw1‹öîü‚P{Ÿ›Ì�õ…­ /¼`^ÛÅ×ÜCìߪ¤â7T{/7©cîÛtCW«Æ´&ªÁPIJ,M<äö¤Ç&xn_&Ð7'…,›ë–¤MªåÇùò £ÌA9>Ù FÓ{9mMï(ŒH$å–ËËt1$¡¬PEµÛ £Ž½Ã­‹!Ç39}1Ý·î7Ž©‡Éз>øN}gûÄ%rÏþ¦�'ç÷®~ÿñèw×ÌÖyYÐ!Ž� ÓQHDäÌnÁÂZ­–›’V;\[’å ¶$„çË ÿØÂÚL‚fb6\‹î\ZiSZidCöŒ3›p¾Ûsë›…pe¬r„~2C‡F�¼å‹/Ôgxàã]m æ¸÷‹?ïýœö|¾ö¡7\ÕŠ˜gÝwý”ˆë3Â�ŠëVõšÒ~åÖ-ë¶Ü ¢ÿ×f{2Êbr[;³%i×6µ�§EØÐ¿»¯H;Ùú†¸Ê:�Ýéh,”™Yê³[§-04xÅßÉ,j܇kÚûºÙC}—mSgét\�w؃aÇÐD–Õm³s˜;“ƒ‰6Ñ– ©³·�=¼F¤“_hð)Ëíâœz QÐ4~Ó”yó HwŸÝpÚŒ§�Ÿõãl ´KÕ¼4 ¯~º('—ÇîÚ’´g{ÒÐh“l¢eˆ`VY•eàŠh?Ä´dû÷œÚE…ó‹*³b•ƒqxoCs]lË ˆ,= É=VðÃ¥i¼‰= â‰aÝf;‡ˆ…Xs¾X!R¢h³̆��߈|cÏUÈñV}W+/FH:ê%!ÂlR7ª�§ %)'«ÔëI¯Ê°‡zG‘}j^ -"yŠ=Y qSÀ†þØÔˆ‡9DžÒ'`¥úsûr1/GŽ”C‰1Én‡=›Ù’Ì–ü.‹×²%é•Ȇl‚lªsI 3-û… S^дahYê5Lê<»"B¼ÒQOJèuq× ‹eüm¿äôK�;¦Ÿ�zt1âö«Ïn�’÷½JòÔiê[t¢ëu‰’<Ã'«Ã˜$d>9�ñÉŒ�ó›üºWî÷ɹœƒúŸ|‚%Ò}rfå'ùdi°K~íïûú^yüÜ¥3­z¥ýÒU}ÛÙ7»V¿úÒðÈ#šÏ½ü�·Û攵Æ,10ÌÁ¨DÐê&�ŒG´ÛSþÐj“i�1þÐëW?c“3bƒgu‡xÞËO}I¨—ž˜‘rˆ3^´rvÇÅê0ªãbý–À°xŸ7w\ñ‡ÖßxSJNèã€]?‰åÝ‚Ý\KÊš9�’Í܆A'P†ËÛÓZa˜¡ÂÁ2¢{�øÄsV´i|¦"›:�wó¯Uƒ¿½lA�v�žÆøP�‹Å|±œÏd•o$„)gnI–gmôûs²rnIfI~~ñÆôFuÉß G{veÜí =¡¸Ä¿ÖOùv #ƒ6ƒz›UWîi"md)áZIÙO¼¬<VÁa)� Ý……? ë&ÿ¶aZ{qCsáèÖÚPãê»Î{õØš+ëòª‡{‡œrZ¸vþéEg¬ÿÓ¬ûÑÒÒhîÐ\¯ÝS9nVíôËÎ(p»Ž†Ã¢;äΚã±d�7ûÔ™¿šR kå0í u„­†s#ítM‰œ7%�N™§d}Ÿf6ó6Näyî¦$o¬QŽpVNì‚ ic–^Ú³·F3nTÖ=úÉ'¶\8(^½@Ö=¼+VQMw�ºýž{ȨO?][Qi) 3É럿7CÝý¹:çNã�»þη™AÚr¸i kÑ%UìvÃt˜"}ëלԖÍ8]:©åÓ¬>ˮܥÞFF=pæ|2ê¶?“‡¨sû¶ï[5Ÿš¢ÿ‰™Æè¿ÜL$†Ñ$N‘jB†‚Pn‘¶Áæ0ÄAñtfãjeèè㥹#ÞÚŠÚŠLh„ŸéˆŠ™¦®WoQ·�æí¹,Ãç>Ê  ú®<¯ñ´…Ôjÿ- \£ÿl«)«ò“"·€Šd¤™T›H•�Ë0�‘ÂÙ=´H™Ý§h?)þ¬�ÅjõHªupú3A¨3SrMê>õ‘›íÇ[ïV»Õý¤î3˱V…”Ü®ÿ]ܨãJµÔœ6¹¼o+ƒ¾Žhý¸2ê–¾ßÌSN¡nÓq ë®ÿÆ­91"n!…REÈ0BhÑí¶Ú9‹L«ôãüm§(ŠòØæXÍs -Å*‘£­=o_´ö> stream +xœí|y|EÚÿ·úžé9ºçÈLfrÌdHL’I2„0Ș1âű ˆ¢®â‘u½–õZ_mÐÕȺ+¸èŠÊz¬**YEe1éþmõLBD÷}ßß¿ß_[ýIUwÕSõ<õ(XgžÛ¶|)‚ˆÄF±œ»èây5áèÃ@Å�@æ·/¾èå•;³w `ywþܶvã«ãwd€¡óçÏmó8,gd&€ó¯¸hôøìƒ'LrÑ’9mþ‰Î€ù ‹Û.ZÊ °¿�¡óÛÏM<>5cæõ¥K–¯0&c@jhûÒ æ.=ï9`ɸR°�`…¢aÀ Ê›ë˜ß#„mÁ@A —̫֙àLh3é˜?“ ÝÝ£Îc?œwâE§nŽØ?]gÖðøKîžÞ9ÇYó-‚’Ùðð·5Óò“–�ÉÎëþ•S·Î�¥o–ëdž‰ïàã ¦KöÌc\ÏÈÃ1ðëú×—&L …B¨§–MŸLìÒÝ 1h¾ƒr> ÅÀÖÄꪃ+B(À ”¢q$PƒZÔ¡Óq ÞÅ|ŒïÐRzj ñQ‚↌Äé…éhûìHÃ0þÛëjãã +ãrcã`öý„“ÿ} +÷]�ý®Kp¯yíÂ~ìÇ$a^÷õ^ÌÌNóêbºØ{{'rí\;w·Ÿ·ó ø;øGùƒB‘°Tø³HÄQâzñC©AzÓB,•–ù–¿X-V‹uô�®Ý²[>K¾Sþ§­Á¶Ýö¹=hŸc¿Íþ¨#Ë1Áq•ã]ç`ç,ç‡J\Y¨Ü«òêLõQõ럻\ræŠüWMßuÖ)×3'/7UÁÁ¸§—YLUFžÆS?ÇLængŽÁÕ÷E1[ƒkÍ>W/qhèmã:°òÔþ\&q˜ØûÌßG˜Þ’ýFš÷wÂʇ±Í¼ÿÛ¸:lãa¯aœÆ6æJlc¯C˜¯À6·mâ}Ø&4a› b÷EºäØÆ]†™œ†|~/¶ðÓ`•¬pñ#!˜t¼ƒAÿNa¸‰Hpßa#ûÆpÇ0†›Š1¬ŠRóþldFc 3Ú¸”»Ø¼ß(NÅFî-lä>ÆÚ�±1ld7¢ŽÍÅ î-¬ä¦�Ú pçAâ&ÝìÈþß*0¥ÿTúþ·}v~1æ'uoýTV?¢AÀÆŸ«gw`Ó©¥à,¦˜�¹'PД¹g a\æžEå™{®ß=?ü™{ÔÏLÁ\œ‹%˜‹³0¥¨Ã,B;¦a..Àr,Àœ�ªP†jTôƒ™=B}=zËS!îG•(G%ªÂ,À\€%XŽ%˜‡¡Kp–šyVdp–!„Ó±‹Bà\ÌÇ +,7Ÿæb¹Iß…˜‹vÒ«ù7s1`.V!„3±sq>¦âbó.„ñhÃÅX‚•&æEX‚sMŠB˜ƒ%XŠ‹qA®PíÔ +‡PÔ÷T�“Ž6,ÂRÌGcІóÍ1æà¼ ì8,Á|“{c°íæŒÓóšŠùX`ÎeÑ¿¥gžÉÊߘ�Efm›É�Ï1=Î’ÌLC&–•¸sÌùöryÚÌ!¬Äùh7¹ +Ì7ë&`,¦šÜY`ö;ßäïp³ÿ\b.c¶Éív3e(ê… ™õËMÙ.ÀÒ>)žœm_�6,À",GÙSˆq] 8“; ‚$÷eò,‹=qàƒ,_Îëodùr.½,+xéeÙ¯¼šå˹pU–/gñÒ,_΢%Y¾œóÎÏ +žwþÚ +Vz¼9ç.ôxsæ-ðxsæÎ÷çÎ߸,�½<ë’úìðÅõÙáØé6îSÄx >à¾Éä!îè#v5‘ì侨!{O»¸¯ $jO·sÇ@p-÷ Ê3ùW&‰Ÿ="+‰Ú?‘ºµ;É鸓œž´3Ç¿g¢ßã£Ç¾ç¢�Æ®G¾�D�Æ®dî÷î¬Äg‡Øè¡O™hòS·71d7™òmz�‰ŽúY‚©d ²„,ÚaäŸ÷9„,&ç�A”,"çí`£�;Éy dmrÔm\ôŽ[ùèm·rÑ_ßÊD;n¢·nµFÛ~ÃE³…‰Þ¸…‹Þp=½~ ݲ՛¯Ì Íaθ�‰Þ²Õ™óV6zÓV&Úi|�tl-˜˜¶•ìÝJ¾ùN4éýÎL˜¥Ã™x‚, ó“ƒÙè—›¹è›ÙèU›¹è•›…èæ –è/Ö’èº5\tí.ºz�]³�5Ç>ÛŸ�˜½�D¯Ø@¢›6�èåøèÆ Btý1¬öú‡z½U^ׯ3îµUz-^¡ÜËÆ¼(óæŸn#g"FÎCÆ‘Fx1‰ŒÁR2.#Gÿá<ò•ãp—ã¼#D>2üHã‘?ùá/�qôª£?å³F~Q±c`±³HðGŸ óȹI·spÔQuD"μ|G(ß¹“´‘Ùdiò›SQm«lDÉÆr¼ „± ¬?ßÉÖ²g²Xî$¹v¿°{ŸÝÅyì± )©\3°¦¨f@MAM¨&¯&Xã¯ñÖ¸jœ5–¡†­AͤøT¢¹Ñ8µNs“F4N©ÓâÑÆN6Ô¤UF5ˤÍÛ ùUJ‹G5æŠN‚©wE'ƒ©š«~úŒæN’M›7Ÿ!Ð[7^“ŠFsµöÆ)ÍںܔVIo®ËM¡Q«œ¬#uÑSÓr3[~Jíö�E Úà†6­¤¡u” °B;Ü mXЦ�ŒÒŽ4,ÐŽ6´jG"éÖh¿ÈOpЄå+Nâë‡|y:ë­X]¾Ü¤fùŠåѨæ×j§ü ÑË·[(&5Õ5jRS£&Mš¡"u�ÚsM�ÚÐI34[¤æ~Ÿ€ÐŽK$X X V3—!:l°=°ÃaôÀ§Ñ '£ +T£*\ÆpÁcü·™{à3~€~ã²Ì܇lãü'��ãŸ ×ø'‚È3þ‰äÿD.BÆqä!lG> +ŒãÿŠcß#læ(4¾GEÆ÷€bã{b ñŠ0ÈøÅl|‡�ˆßbJŒo1eÆ·ˆ"fC Ê�c(E…q e¨4Ž!fæåb|ƒ +Tß C�oGµñ †`˜ñ5ª�0¾ÆPœf|�jÔ_ÓHÀø Œ0þ�Ó0Òø†£Öøjpºq#PgÅHŒ2Ž¢ ÆQ$Ñ`|…Ó1Úø +u8Ãø +õc|…QkAÆG0�Æœ�ñÆŒÁ£ cq¦Ñ…q˜dt¡“�.ŒÇdã0& É8Œ‰˜jÆ™8Ë8ŒI˜fÆdœm|‰&4_b +RÆ—˜ŠéÆ8 3Œ/0 3�/p6f_ ÙÌS8ÇøœÆ2Æç˜aæ31Çø -h7>Ã,Ì5>Ã9˜gB+Î5QÿbÂl3Ÿƒ…Æ!´ã<ãS꿌O1çŸÒ݉ñ)æc©ñ `™ñ â㜇åÆ'X„•ÆÇXŒ ��q¾™/Á*ãcº70>Æ2\lĸÔ8ˆåf¾—±«��p!Öý+^]g|„‹°Îøã—Ƈ¸ÄÌ/ÅãC\†�ƇX�Ë�°›Œ°W`®4àØlÀ/qµqëq�qð+ã}lįŒ¸×ïc®3ÞǸÁxWb‹ñ6ãFã=\…­Æ{¸7ïâÜl¼‹_áVã]\‹ã]\‡ã\�_ïàÜf¼ƒ-¸Ýx7âãïØŠ;�¿ã&Üeü7ãnã︿5öãVl3ö£¿3öã×¸ÇØ�Ûp¯ñ6~ƒûŒ·q;î7ÞÆø½ñ6îÄï�·pþËx wã!ã-üoa¶oâwf~voâ^Ç ã|�Œgð¥™F�±]f~†±_bìÁQBŒ¿à„5þ‚¯ÍüÂÁ1ÂOã["Oã;"Oã{b1žÆqb5vãŸD6vã±»ñ±»ÑMœÆ.ôÅØÝÌ ¢»¨n”e‘žŒðé ‰£g146J•‚H�xH"$A�$–Ù"‰’(’(‹ÓQ“ ò¢À‰"Ë +¬UE‘ã9Q°2²¢gAÂ)Ñ–Ø—õ•<`³I”&á$M·ËéRìUñ+&":œÓæ´[œQ´‹YN§Ói•-N»Ûn·�įöCߟÎÞ12¥ ƒ*¥)C£eØ@¡ÏЏá¶Á­Âãp¸½›ËðzT�Ë©x\AW pªvÕiUIrJÙŠªª²MVœYNg?"<ýÐ÷§³wŒôåNn®›ê•½ú#Ù`W3ª +xáµÃã†×éôfYìngŽ/Ë•åVT¯;×Ý{þ©¸.Ev©’¤HA—Ëå²Ùe—âSÇIüÞ~è{“«/ë+í@(ä¥z•¦úc±Ãáê…v>øðyáWU_¶ÕáUò³ý¿×åöyC^¸3Sô8=ªÍã¶X\–\·Çã±;ln5àRû1Æ×ÇŠó®wŒôee8üSšœî  ÛÝ�&¥ÉéUC�lOv–ÛíÏ +geÆ�Ë£x\v�‡Ò”ç¡49íWÀåêÇ?–üˆ&O?Fš4ú©®§�©N[�P¼¯   àGÐãäØ¿;’›ãËñ{³‚Ù…~deÆö¹|‡/K–½rA–Ïçs*Ž,OžÇÓ�ˆ`?ôýy×;Fú�²rðà Õ«4�T§enzVðû�<ä¹�D~VV^Èîz†C�PП�—38§÷,Øð|J ÛfóÙŠ²�€êR²}aŸ¯y}hO¦Í²û?P••åQ½ÊШ67<� @ `¾ñ ”‹¿?qzòü%"9‘¼@0œ_–‡œôpÙ¹Y9Ù®œ»=`œ““›ãò¸r² ³³³Nâ÷Cß›rú2¹½¬¬ Qc”¦:íð +7�› DÉB$„Â``@‘’ +”,Ê/ +çäW†ÍÉS¹äûóƒîü<‡#ÇQ–—ŸŸïÉrçæý'ñÈȯÊïe`ß嘊‰ï Tñðÿ¸—™šq(�7Æg€>ÈøÖ„‡¾ó$4ß73Æèb›¨Œ.ü¯’”ùãèÃð ^1«wdš�›p7ÞÀ¥ÿv€£diø·­ÿ6‘©¤žT�ˆy:©!Ѿû á†>8q:¾Æçøoákœ >Äq<�/~f`­Žåd‰�èÆw?�{Ϥ’(x Wàj¬ÆF,ÃkøŸöÃÇÔ7’ÖîUxâü"ÓxÚ3w×áü 2˜ï€Ê €ÊÂø +*c'nÃG¸çä¼þ?&z2ÝøïÅzNúíj¹}P…;©õd$>À�á@ãðƒèîßWŸ§Oäâ'M§ÑEF’ $±ÃìÇ5ú×ú=‹{î4ÖËø#ü»Ü‹¼ƒý5—�Mxoa=4|„£0þŸÍþ?é?é?é?é?é?éÿuZ�'q#n46¡ ƒÂhŒÖ›ùV\‹�؈™˜ŠÑD!v¬#ù„C#àÑSFyí¤Î|{<9½óðç'ɳ6¶Ï˜žšÚtæÄ ãÇ�sÆèúºÓ“µ#GÔ ?-1¬zhÕ�xeEy¬¬´$:xÐÀâ¢Â‘‚p(?/7'Èöû²¼·KUœ»M¶Z$Qà9–!(!~Í_ßܰPË®oÕl‘Q%¤Ù&�Óà +†#j(K•f 4>ªÁݨy&5oGrXJ¢§‚LÔØBåë°ׄ`¨Aã +5®02®­]ØÔŽ(oûÚS©Ò-Pß5¦Pc +Çjl¡ÆŽk µkʤæ0m0kÆj˜ÔLÿ:��†…ƒ†…SA MÍZ^ïc*õsD>»N!s"Ù¬l·e×�ÒàÙÛG¼ìè0h¨ÑF5¦PÑPcކ˜F<_kÄ­ï ®£ Ý>ö3±™Ú8¶ÝNòª¶�¶nö´îµ]Ý«ÿáÍŠfû. ‡Ãa*³c†•í­ )É Ûè4†6_5לêÕæÔÂá`¨aá(úG;†4œ¥ùë§77Ì�4œDÚi ilá©}Ãa-;J;nÞÜ@Ilk¯+-I“¬eGOÒO×D0J4¦°^KN5 L5ejÐ’m£R™ª ÀtÚ�¶´ŽJ¥Âi¹³…!M,ÜÄ—EB›éˆb¡æ‰*á=áÒ’]¥%�MÍ £‚æì5¦¾yD—?Ø•*-iœÔWMü�MÍ›c]Á4�§D'§µ`~oÖ:5½€™>ɇé ¼9ê>p_ª´dtdtëæÍ£#¡Ñ›[7·uëfGBJdóv›móÒ†Ö�¹òI[§±óª 6úꔦ´Î'§•–„¨¾�njÔÜ“gPñŒÍoK‹ÚHxX0¬¦za&ý»æÌ:ÓÄzM0×Ùfåpi‰f«oC£©yé4Ž jÊ0ºLCÎjîT0ÇÔY3kÓ0¥Yc‚t¥°©Â†S2 +†{†Ú½É™ÚTiI8L×ÐU�IÌ.- kë&7§ŸC˜Ü�d,šÒ˜VÚ²«·Å{mY×ÛÒ×½5.-ñÓ¯þ[�î¯Ï›Õˆ+”ˆ™ü7Ím»¶kjs§q|˜& ˈÛ]ßÌ™Ìdé�5QB5š/jv¤<ÑF7+‘ÐËM‰j|}ó®`M*¤¨\¤´D¥«†)T^Žì%Ôv£h¤F#Y´n�˜&�õ Óˆ»OyB ›[3ÚÕZÐ>ÿçç¦q…JD³}Lë®�ዦIËXêÂÑt-Ãiˆq)ÍAí±æ8lf¥%Z°¾9¤‘Ö “Í›PCh>¶ješ�T°u§ñAë(jöšC $˜QëT0­Ú§èÚÿ^Ã×]Ô~qujþi¥%Zrp¸´$T¥‘VsµLmÎpiX0³Š(®±t*?nïãb/ÌO¹Û8õGOýÆ¥!Ü8µï�Ž«�Žö•~>#ìÿ8æ”æ±½ÍИÂ�:–2µÓØ5,ø£º)ÍZ2]ÕØÔ¼:x õ' ©Û!WLÞž$WL™Þ¼�AÝ +ºbjó†0õ­u©íÈ“›ŸI³–¡µ´’>„èIcSóF2áƒO$�uf+gV˜Ïs: Ì:©·Ž`N'“®SÒˆŠLDI0˜ÓÉ¥[’½ÐætJéºuf�™¶ƒÎ?iå“RÒ’´1v&¸�Ъ|RÚI Á#6b'Áíë˜ú&³º“¬ÛnIÓë`!É4…WœuõYÓ›±ÁN‚fžJ¥êhú—¨ÖiLý$�P¶ÏÐò¨ÃE ö7+Ô\k©(5iŸP;¸`TiÉöBrŤþsš©y›f5’*C¿Åæ6ð‚…ˆ@R Ë�åy ‡Ø>W"¶±}µû*ÊãjX- «á{Ø÷»cëÇ_xbó�ÜD0xŠ=ÊÆùÍJ“Avï9XƉ3q_ÑCF ·WdVdQßWIb]®D¬eYWE9Q#æÅÆ?ÿígüƒú(ò¤>šìÁíúNæ ß %}„gyA !”Ó_ +ÈÒk!¶œeØXK—�µì£DÖî©('a¨Š™1u]ÿ©'Ð_Ñw’vF$ß’uúùz®žK¿�ré;™fsô¤›ðlLž‰í‹Çö©”Ê.Ô>Ûdâ2@*õ¿†ŒÒw’ËÉ'äCr£¾V·õôБ‹ †hè oÒÂ2ìv€ìeb]•±.ÄöU”²7Ѷ|7¯[È ÚãZò(³ƒ¹,|I™~�·H9aH¬Å•ˆ™}H¸*Ììèy�‰�Gß1^2\ì6¾,"Iòl*)cxòZ3”a˜^Æ€ +ÎB„ÝÖÓ Êtòÿ¼H¸‚þÞ¢Á8Ä�Åï€*âÉñJ(ŠÂȬ¢¸mW&ÞzkŠá¸5…lÔFá¯�,@wά–®Šr>¤*ÓŒ-P•x¥ª0 :ˆ—ˆä˜þÕ?öíݓͼDV’M=…ú�úeÜß{zô 9Fèפ+�CœÈï@V%ë²ìò_épä]™„æ½ÆÊ" [eë­)Y{Ãì­)…´ÖBH8Ûé"VÖåòz•[S^µQq?%¬6›ÕU]HøcfAÌêxŒÊ2Ð�u©‰X¢¢¼ZÍŠW­R‰TÅCUC"¢:4^™åUxoV–×Ã… V^·ëâM÷Þ°ñRâëº+nÞûî·úÁ[4ýïzÏû1â^0¿¥uþ×;n!Ìøgo×�Á»߸÷ ú]Ä$ãsn¿T£‹’µuW¹†]%yyéNI“vI¬KrI|‰2¥,T–,»®Œ·²ee|™„—�ÇGŒÈ·çº-•Ÿm?ã¶”]̰ŸÎF�»‰þrP‰Õ“„Ò¥tU”»‡Œdª‹Šª†Œdâ•yŒ×#ˆy¬×ã`"eL¡'�‰WŽdª†”1‘ã>åyRdô‚3_ÔpÉýíó¸tÔºe£Ž0nÓ—-ùã¦ñ$š7lByÙ„a!Z–N* –ÕFŒŒ±ÚEµ¥Ùä—5KÎiô½ÿܦ«ç%s7OžwïPcë²3o^\3|ÑÍVLš›7tbytb¢ ?1‘™PT_‘“SYWT\_‘“[QOõr¢qˆ«åw •hJ–äc3ìDfíö!ƒ6{“¢è-SîHÙQFllY ¸5MmÍîÇ(Sê ª²ñX@éåV¼¢œxAˆ›ò¯.(czÙU˜a„7îvê]ŸmÑÖ.»ã·�D8çéæ­‹GŒÛ¸sÙÊ�ëôÝ9•c¢ƒ*srâcJ�ª²®§ô×^^2ŒpãÞ•¹¦nåÝmËv^>vƃ',Õm£ ¨mŽ;»&?e_Ë2W•P]‰ŠòBRE¼ÄK¸ûº§³÷ôÌc:jÉw“§ŽèýL,ã¹û¸©Q›,à!0„ƒ"L˜]D"‚ç a3VÕ"™öîçqYH•yQ\Ìm=íì=ä;}Z‘9’wD#�ÏÙ¿Q Çøä §Dl‚7;™íz$•ÍaH²dˆ6£Ä=ìáò�,ëÍÛ²—Û»}„7fYêg^ï¢ ø•¿¥ jøÎ™ÕBÒú\=’M+ª ªC‡¦µÛÁˆÖëÉò±ÅEUCª‡Æ+éa‡(Ñ*» P”èÉ4|ÀÄû'<ÖÖrçªúœ¡“†Dª".»¼rRUUUÕ¤3‡ ‰!wNÏ-_?"/T]=|@~UQÖéu¤´¬lPó•­#æ4OŽæVVTGü•ª>®¼rÔèX,VvƘX ý‚¿žï€'®Læ:E�ØF²Xe"ÛN–³q²Õâàl¶Nãx²BÆ/0¬ät²×§œN›(°Ë ¢$ÛœO2Ö\åŠø¡<ÃÇZâÔ˜Wº| Ä|•µñD"F žW]‰¨ê‹—+›ø]»víR6Ñœò¬%fÃl˜„Y¶¨8"ˆ,½~ç<�™«ßÍXÉZW‡*J¼ç6R«ïæ;ºC>ÚX;RPëµ àöópÂGÓ‘,•üªêoK©j6Av[ +.¢´¥k¿Úë…munn�EÍ^“Ö¢XKWe¥+a:ø.5ñ£iæ>¢’£–)mh#¬jZâÞ²(²�±%Ìo.¹õqýÓcÿª}ùá‹^ºvõR¾C»sÅCœûÉMÏâÔl;ëöž'õËçOŸ6›ZŽm›) ±d,[(±Ò–a¹Õ!;±Û]–“df|»IŸI”éÏNAº™nýýwOÜùêW]oò= úv})·¥{y÷þ}_R¿½-óFg$ –-)A°2ĺ%E\ ¿%ŰœÄI™Åe¬kz½zePK<‹ý˜=åá°ÚwqèÞÆ×%ò†e²ùýŸúný„Þ™ÁÌ~hî^NK˜¸ItIdKJb9®w—ÄkBb¹Èˆ}(3] ŠŒô¡b?ÔòŠÓÿÄŽà¶èwê'z^ã;@0Î8Ä�àw 3“qX+#XˆÌˆÄÆù}[R~¿[bÜ7¤·,Û%û )‰óù¼Š,c�×TVói5H˜Î·×I÷›.ÕÔY-h)Â!PîWúÔ¢HãõdÅ+«)eüˆWõçô{ôeäQ²ðã‡î9º·çàî£ô™Ù­“µdi"Ô꯴ê?üý½¯ÃÄO·O&øÕ¦dɉ½>% ¼t}A9qñ.++°¬!Ä.qkB|¹¹ÀLþtÅQ[[K9tª,øÕú“=Ñý$ÓDF1cz:ùŽž=LM9dîÅ”Çè°.†Em-‰}˜‚¢ÝLn†�CÌ ¾6 JzAb¥ëS¬[fyÞŽ5V«Ã®fj3¼ª(' +2ÎJUÃÌ ýÛže­SÎ}�Ô1 ýýoÅ$VKưS3sÏw@ÁéÉ�ƒ’p�!V‡Bxž*ët*ÍpYûkµ- ªµ._¢¢œ´´´ "¤¨8bÎ=>´š„ ?^Ÿ¯Ï²xs2¶r5ù…nc–¸FôÔñ=Ós†0Óz2T°tŽ<–'-„3׋Nãè#ª0Á,³üìG¦´gJ›Y~ðˆœ)­™Òb–»’Ë€1€È�\FT�û~ƒQ[Û'3öD÷¤žqó?,ÊHHø14*ò õ0ÅV2P$ªËÅr*³\·]YRËUF�µt%ÒÊ�@mm/;Ô!ÕA$aÊ–,/EB²|&kDAßm“²=º¦×pä[ìú{d?)Œ(B0�’}ìô«îÛpZwûLñ]¯ßÙ}ˆïè~hÞ¹«šÙI½šúý†Ó‘j)–«e†ðNgµ¸¬,qb­ªze^Z²”[Ky‰x?�¥åu’°¢*5Ì?¤ïìÙ>ÄÃIúKd&“(s©`7ž9püm݇ùŽî›‡ŸV¹…ͦ–“®ó¿ò; ÃG£-¸®OÁ-Ø®O œeuÈK¼Þlçj6vŠÍäÓ‹ÖÌI�`®Zj;YFQ¿Œl& $N.ÕWé¯>ðÜswß»çÏÙäzRG¦’múùúãúCúlîÆ«oÿÇ›Žgì7÷¤iÕºneü&%Ë,ãb­¿I±¬°:ä(w0‡K&kBLy:Ê©ìGRƬQ&„T�iËCUCÒ+ð“§ïÕ»;ÖF×ÉÝÅwèÕoëß2�ê§ô^šµÂ~¼(ĈdÈåQ!IY×§$y”.ÕÃÙV‡ +HAAq`5—fF�šH<ÛÏŠ'èšåCÅEªR=4òe©Š(PÅ)ØQðz|Ô² ­Rlréé§ŸÙCF“øŸþüŒhÉyzÍŸg͹n{{ûÝ÷Ξ}άìçž'§“)¯½º÷9ý1ýá—E» ÿvw6÷‡uk_}ã²Ë.ºä�÷W_–ñ|g›ß •¬º‰ÛZM¿T# +a´¬Išö[f­nY’‚m)I +Xå@[Jf‰±xíOƒ¦@Ÿ£êr%ZèêbËØH$Ã_#zóXQÓŠðgë×È.‹ÅóÎÖÿÄ€±–M]56T3,îí¹ãêùµÉɲÁu±ìžwøý’ƵóÆy9kiMC˜…¾¬fÄô'éj˜iâ†ð;P…«“)kU Ša£DDølo6Ãù=~Fv‹ƒXÃ"‡È‚¥LÀeÅùYù7¦²8s–pqîÆTÜ” X­’²Õ! ±XªûÅÕ-]Êë44…§å‚ºû~7ý×/^°ô¿Æ8kzj`õô‘E£Ûk§]9{ÈŒÛ^Z~áÕ$9vlVqUþàºaC‚£Ÿ¿vé]ó+‚9úÙEÙ6oQUx@"^0yÞú³/úíÜ’� ô2n‹¹Ç)MúXá~KJ ¿à™5å,aÙÌ6¾+^ëõ¹µ'�=·E?WR_À­à¶ü°˜ÛBDÊ÷-Æ!¾Šï€ÅIc¹>Ÿm,Ïb�,;Å5!®œc¸´Áí¢.’®2%RÕ°š.øªž{z:É(¢™Ô3‹{.aV±5Ý»ômd;žb »ä‰¦G®Hæˤš%Ã@d‘aYÆÜî±CYºObcÔµ VëJd¼=¿èµ·üDݥߠûÉLõó‚è'ƒøŽóøŽîÀä‘õ“Ø�èÙ 7íýØdÅÐ ê!ÅRl'E2hfeª,¤X"ÃRLª 3Df­ט+›ø˘þÞd!áÌN:LÂîŒíO—nñ¸¾Qï8âæ8‹zL¿JßDÚž· —M82ýK»•ãÔg)‘ì-cR³k»çóÝ #Î�0ƒ}¼{DÕÜ3'³¢¢Ÿ½WóðbH2¿ØJŠRDˆÌZ<2g•�W°dhôYL]¾D,ÖGè ÒKŸ¥�°0á«õ_|ïprb฾–ìÕg‘+÷ùÝœ-ü1™¯7‘×£Ãõz³�Ù§7ÅGžBèI€ÐÿTÀ=hZâÆä`HŠÄÈ#s/íyŽç¶¤x+q,ƒôVB”3”‹§éÊØ“Ú̦Ÿ.¨p¸Šª¡—„¹XÍè™Æ�ï©`^ÙÉî'âºÃÔ +'ŒCì~.^äãúähIô‹ŒEÈ9à#¬�8YÙwF +²"3v^Îu/›ËçÞœâ³6:é㷤܊SÎÂÆôR'agàr)Ö•H/‰xß.4Úœtç;cÎZç™ÎsœKœk�×:ïpZZ‚)Ó”ÓE£ºçÌj‰‚†Så„nTÃ᪈)(ªR + é‘QÕСñ�ÊW‰çÇî×ßàÎ}~ëïIÉzìñßÕ}2‹<¦¿µ³£1™ZºåÁû¯!ƒË +ï[|¤`ˆÞ¸§ÁïY5´áR:ë�Æ!î!þ0ä¢!9�õ¯Ó»5åÌ‚–àÖ”Eá`[ò—û¿?Ÿq úŽ?+{`†èÞõ^ñ¦woñJ—Wa"lŸ{ŽäNßCj¸•o?ûæ‰Wþ´ð‚Ô¢U‹çž³zÕ*þpÏ%�èGПg’ æüòÞ[×^û+ªŸcŒCì5¦d†%ó¼^7ãÞšb²Ì�ÿÖ”¤È½Ê©¬Ooû[âývüéÍl¡)@Uß>?Í´jöšóž?¬¿KDøÃä9—\qÇ-/\V8’ä}DxRZ®wÇÕWüzåÓã·$çaÉ<6È·¦ø,âuxeïÖ”¬8¡¬w8òýë¥tð�÷ñÆ,¨3…ÈT A¼ÒWÃ$Í”4ƒ¸%únÑ+»¾ Ì+ÏNäH�þüŠ–^0·õâkî!ÎotRù+¦­[˜Ð¾áw×mº¡#CU.— >´$«Á0ÄÆó²AŽeö2j"Ö’ÙQ˜‘HÚ-W”S5$á¬peµ×d#¥Þå¥j(ˆ\nO»B,÷¯ûÕÁãú2ðí¾ÕßÙ1~‰�Üs`ÒÇã‰û;ƒ Ö¿ûxÄ»kfQY–lXààÁ´d +‘«W²ñv»í¦”Ý ÏÖÀ¸˜­)ÅrПÛx‡eCÈJ¬¦k¡Î¥¥ßjÊ,ÕÔ=óÌ&Ràõƽt³©ŠW ¡'3lxİ[¾øBæÁ?ÞÓšäNø·øóîÏYßçk~ÓcÊWÏç–qÙ -ÉÁÍ é¦›c/tÒõ�íôå{󷦼 +ïóYl�åA|ÁzW¬+N…íë#éGë�®vK¹�& ­×L•W*g«2ê ˜êPuŠ:,ÓÓÿúÒÅ·ßu§Æ-zmϧ¯ü±…ªÅsËg.¸è‚9³/^©Ôÿ:œXgÞýä‰ç3‘ÊëVõžÜvå¶­ë¶Þ Bÿ“ 7“? É ±xmœ“ÛšrÒŸbm Äm“6ôíî+3N6M¾©®*•±7�ÅC*7SfÛÔùæ +^ñW2“ýáš¶žNþpÏeÛõ™”�Kò2œ˜Ì²{Nsf°°Ö¶!}övr�¿é™rÊòz7 $ +'Í›7iòܹ�&¦»Ïi8cúô3ÆÌüa0Æ¥z~‡Ÿž.ªI—Ëãsz¶¦œ9¾ 6Ö¢ZXÕ¶!”UžÅd™¸2Ö‡1£Ù�}§ ö0‘‚⪬xeUÞ¥¡©.¾õG„,=¨Í;^ø'dx¼‰? É0á½V§€¨�Ø8k�\)3²ì°I܆“!¿ùÆŸ­T-tW¯(DH&ê%aÂmÒ7êO¤ %© «ôëI·Îñ‡»‡“ýz~#ÙÍ‹¬¤�x`C_ljÆŽƒˆ&»éüá4¼p€ËFæ&ÈUrY Õëræp[S9JÀcóÛ¶¦ü +Ù�„CR-ueTbeÕ€´!iÉY6 ,O¿†IŸgWF‰_9èJ+=UwÊØx¼×ßöiNŸyãôìÔGÕH8 ?³mâl}Ï]“ÛÌIVl_°Òʃd"3æÀåí=a&î_w~Ï_9ÜÙtîSOéíÈpy¶iëÒšluöêò¿ÓäÌrùG–ˆúäÞ™Ÿâ“•þ.ùõ¿îïyõ‰…Kg,ZõjÛ¥«zvðou<¢õ¥é‘‡4-¼üÞ[‰cKÚZâ–˜æbx2d÷’`¯Gt:ÓþÐîPY*˜“þÐï[~æ&'nÆÿ�¤ñ¼—wI˜—žœžvˆ3\´rVûÅú ¦ýbÿ†À´xŸ7µ_ñ»ÖßxSZOØ0ç‚“žÄŠ^Éi­ecï=�R­Â†~'P¦ËÛ×Riš¡¢þ:B½Fbü¹+LÞ4þ¥2‡9˜ó/u‡?¿lA�qˆ�Êe£%Kĵ€ËªØHWÁÝ’ªÈÚäfåÞ’ÊR�‚’�™�êR°A�uíéu·ýö„ò’ÀÚH:Œ�öÛ Ò6;]ÜI2‰´’¥Dh ¦T|‰òŠtt8Ô ËØÞàÐ[Tô“à°n⯦¶•44�h© 7®¾ëìQW�ª¹².¿z°ÀigDjç�->sýïgÞ$ˆ••Åòæù�¾ªÑ3k§]vf¡×s,‘½aoÎÀ\Ÿ-kÈèY§ÏøÅäBº*‡˜£|5ܘ�ædóYFܸ)åv«"£Ò}šÕ*:Y…›R¢°Ç"ØYrnq¤•[jxÏÞëu£*õè§žØ +‘�jzõB•zxO¼²š9:ú}Ç=÷�áŸ~º¶²ÊVHf�7>oº¾÷s}ö�æwúη‰CÆrxYo£šªHN§i:¬'"sï[9é-›pz(«Õ0פ?ïܣßF†?xÖ<2ü¶?�‡™…=;ö¯šÇŒ¡ßpS9úkÐdr`1K ©&d ã•Y§lBŒÈön\íÛg¾4w%ZZP[Ùšág&¢â¦êëõ[ô­¤iGωy�q臞+Ïk"8}¬ÌX½A·ì<%þ¬�Çki$ÕÒ? ý™ ÔÝ[ +“ôýú£7;A´ß­wêHÝ5V^àí)½�þ¨]ÞHieškΘXѳ�CO{¬~t9sKO{öŒÓNcn£´K¦u§¿›kJIØH‘� %d!¬ìõÚ�‚M%œÝ v¶yþ6ˆI0 Ãø³íÖÙEòP™‘c-]oš_´t=k¾¯ª­¤–?ÍG&üÓ•›­?D&é7ÞèÊæœ�­úV2]ÿ#9ÿ†\§·rЕž£Ä®\®Nt†Ñ?LÇâ„j”Ñ­ç›2ö`VrˆSÉW™SdYòðIA�l¬´5ÅæxlNžÈ•2)”‰¬(6O†ÑY¼Ý‹g^¬%ÔxK‹Jµ¾òä¶D¥ÕçÌ¢ L8½%©®î¯ +­7é¯.W;î’ò¡z+™õ”ËÊYü»9üð�¾,Ð]¸|-«÷\Ú™§M`–Qîf¬F?†ÁÄä`'Cd°æ‹B"Ý”"^ú/nJñN‰%¢Øû +‡p‰¥?^h‰Ç\‰úík3ÇT™ÀºŠÖ¬Ö½€aô +¶UÏ&_®gnüü¶ž�0Œô �X�" ˆˆk‰“¬†/igr}¼½�!¾Ѫ*­ª¢=ÌHœEצ@áY¦06Hò²L‰ú#xÓW›ðMi ¸ ™Ü€<ÖRÈ2á÷0-‚Ù£9Óã†t†pá ¤2$¯_êUŒCÜ ‡B,IŽ!¬?ÏbµZnNY­¬ßãÀnM Èò+[S~îü�–àú|úâ/¼Þâ Ñ «Ø½!ä)÷0žÌ@W¢+kéŠue^Q!½‡¢Oé.\ ,^Q^Øû½HqÕÐtmn«�Þ³Š^NõPžÒ2eÎŽ»—\šjìÔ÷×±ýÝ×.#çõ¼½@"BÕ‚™+6ñïIÍ™Úúí¹ìÄö΃—tp úc�þÓ¸»Ù©ü£½çðvÏ8—m÷ gÙŲÙÞ]åNâì;‰ËìvúïžÃýî™�õÓ¦Õן=­çëQÓšëF�uw÷Äá#ÆO¨©™pæi5&ÔŒ�ÿ.;0‚ endstream endobj -811 0 obj +889 0 obj <> +/FontFile2 888 0 R>> endobj -812 0 obj +890 0 obj <> -/W [0 [645.50781 0 0 275.87891] 11 12 369.14063 15 [270.99609 404.29688 0 443.35938] 19 28 575.19531 31 33 707.03125 34 [437.98828 0 703.125 641.11328 0 737.30469 532.22656 520.01953 710.9375 766.11328 316.89453 445.3125 648.92578 511.23047 957.03125 790.03906 758.30078 614.25781 758.30078 652.83203 560.54688 585.9375 723.14453 666.99219 1004.88281 655.27344 0 606.93359] 68 [538.08594 620.11719 479.98047 619.14063 541.01563 383.30078 619.14063 602.05078 284.17969 284.17969 559.08203 284.17969 916.01563 604.98047 611.32813 620.11719 619.14063 397.94922 439.94141 389.16016 604.98047 541.99219 797.36328 552.24609 538.08594 479.00391] 104 [723.14453 0 0 0 538.08594] 124 [610.83984] 129 [604.98047] 137 [627.92969]] +/W [0 [645.50781 0 0 275.87891 0 493.16406] 11 12 369.14063 15 [270.99609 404.29688 0 443.35938] 19 28 575.19531 31 33 707.03125 34 [437.98828 0 703.125 641.11328 0 737.30469 532.22656 520.01953 710.9375 766.11328 316.89453 445.3125 648.92578 511.23047 957.03125 790.03906 758.30078 614.25781 758.30078 652.83203 560.54688 585.9375 723.14453 666.99219 1004.88281 655.27344 0 606.93359] 68 [538.08594 620.11719 479.98047 619.14063 541.01563 383.30078 619.14063 602.05078 284.17969 284.17969 559.08203 284.17969 916.01563 604.98047 611.32813 620.11719 619.14063 397.94922 439.94141 389.16016 604.98047 541.99219 797.36328 552.24609 538.08594 479.00391] 104 [723.14453 0 0 0 538.08594] 124 [610.83984] 129 [604.98047] 137 [627.92969]] /DW 0>> endobj -813 0 obj +891 0 obj <> stream -xœ]’Ïnƒ0 ÆïyŠÛC•(¥Bê HöGc} -†E! -é�·Ÿ°»VÚ� ŸãÏú[äUQí¹øpS[ƒç½6�ƒyº¹øm˜ -x§['<Û±±LäUQ/³‡±2ýÄÒ”sñ ƒž½[øæÔMWØ2ñî:pÚ |sÉë-õÍÚÁx.Y–ñz&òׯ¾5#p�²]Õ�ñÚ/»K^?3¾ <@Vä¦�:˜mÓ‚kÌ,•RÊŒ§eY–Óý»?’êÚ·ß�Ãì0ã©”�ÌVR1R•D9RX íOHq‚TÐ]œ#�#¤Q#%Šˆ2“#éÈÝÝGòçêÙÄ ¦Iª$¨•äGI -RAPðÞGIA’+’‡$ÈH@‚ðLÁˆ‚{üEŠ‚J¡*uQæžž!V÷ÈòúÒëF<ÆØÞœãqmptëд�ÇfÙÉ®ªõûª ¯ß +/Length 344>> stream +xœ]’Ënƒ0E÷þ +/“Ed¡BJ!H,úPi>€ØE*gÁßWÌä!uÒ¹žkÝñŒÈ«¢²½çâÓ�ºÏÛÞóxuøºÞ2pÓk#üë¡™˜È«¢^fCeÛ‘¥)çâ º~önᛣ/°eâÃp½íøæœ×[&êë4ýÂÖsɲŒh™Èßšé½€ ´í*Ö÷~Ù�óúYñ½LÀdEiôh`ž ®±°TJ)3ž–eYf ¬ùw®$Ù.­þi–‡O¥ d†´' +�TŒ†D%QŽHû#Rœ tçH§é@TÆH‰"¢Êä…|ö–*¹g|öôŠe’n +ÊJy”$‘.T‰·®JɮȒ=P÷VQ<‘‘HÏ)TB·DÔUD•{z†XÝ Èëï ò˜ª¾:Öãá$×ö‹6�ÓêZ¿?ãϲ® endstream endobj 52 0 obj @@ -6299,52 +6845,49 @@ endobj /Subtype /Type0 /BaseFont /CAAAAA+SegoeUI-Bold /Encoding /Identity-H -/DescendantFonts [812 0 R] -/ToUnicode 813 0 R>> +/DescendantFonts [890 0 R] +/ToUnicode 891 0 R>> endobj -814 0 obj -<> stream -xœ¥z |åýþóα÷1{ïfsìf³¹6÷’ B²ä"$’  —œ‚àT ¨D j´–RK©µvÀ+µ(b½¨'¢õÂPŠG)�}ÿ�Ù ¤´Ÿßæ3ï¼Ç÷}ßçý^ï1@ ŒŸ��W×cº ýÚ'UŽkYÙr훀á5€?2kQÇ~br2À8<7kå -ϤÔj \0Ûæ,™»è±7 -߬" Þ0·cù¸áˆNêeîÂÕs¯yù; Uœ¥]�‹®úÀñãh ~ ~¿kvGç©Çî©È:]]³;Ì‚Þ �i’º­¸ê­ÍF5ÀgLháâY?±'þ0ï$qQÇUK¸ í;‰๢cÑlëøìòà@2–,^¾‚Va@J¤ò%Ëf/yO}Í×€ú,À½*h`�’R!ñf¹vl²1`ê àdjÐZ/µy‰‹ª�a@{×ÙɧOk;T ]@±MîƒdÿÒ¤¿ ›a,ùn•\ðÀóU#¤÷ç\3{vòÀ§ÚÍ,0PËôÒÅr­DB¥âûø ý€¸¥7–±¯ccV1Œ–g8†S3ì:H8‡®q<x<ÿf¸‘èU;Æò«Ã‡%>ñ}gd†1ˆÔ´‚•{µ‚ƒ U.WÁƒ4�‰ †££1õ˜Œ)˜‡%¸kð~ò”Êí¥žG9 -cP‡&LA`Ù%ýô¿Ü›é GpŽÿËsÉ»˰ wãn<8tÏ÷¬è½^¾û�igngža>gKÙR¶�m`¯aog?æb¢w'÷ -÷ïçkø­ò½ïü[áT,R<¡t*¯V>¢ŠWµ«v¨v¨^Rý¤^¨~JÖ´iÚ4¿Ö hÇhûÎÝ.{¿þ_îþ—[— óH‰)’„95€N\�˜�3С)g�aÑ8w^œ‡±Ñ¸’ýMÀlÌÅbÌÆDŒA&Æ`:°ó0 “0˰ó°WÀƒ|d¡¹çÕñȵ<Ô:?~1åïáAr�‡|x0N¦Y†ÅXŽÅ˜ƒð ‹± Kä°+¢}gÁƒQXˆ…ð  ó0]X�årj6–Ë8Wb6:‘ŧc× b1ÁË+³k™Å´FŠóWGT– âúKÑr ’�¼ôEž†ãü45©=7Ð;¹í¨åãp#¿µlµìW¨å×ãFƒ2-÷ -jÙ‡Q«Ø‚ZƒÚóÛãv£–= ?—�ýüõØÍ+pH¹ΕßB÷þ'lÜ$Ôs“PÆ^+¿ëÙÏQÏLƒ†›D?à®D.cF»<îc‘¸âärkQÌÕHôô¯2ÆÃ²i˜í˜É­ÂÌ‹û`ïýÏýÿ·KÂô­+ׯùÿ«þżŒÃü1Ø!yXç`ÈaƃÑÞ åôKzãP„Óè�2=ÂODÛ:H�󿆞©¡ß°­Ðô›Ëõ~p0¦Š>\$ÙÍ^}/°ë~.…ó®·ñöÿaø"v£'ß�ûÎåKñ»Ñu.}¶F‘E,åösÿûuG°Ÿ‘§ ó³²p€Ø�õ¨Å4òïñïá´`ZþÝǺóh_•Ci”WaÖ k°>Z¶^æä²EòûV¬Ç­Ø‚¸ƒ¼‰±X�NìjLá˘�E‹Ìà ؉u¸ ø>˜˜$˜XÐï°sÿÍ÷ÿûu fa;ö…7†×¢�X‰k˜Ÿ g=·�~�fTc>`¬r^8Ÿá)lÁF, 5}tÄîˆ}ë�Ý{õ5v÷Õ׸^Ãîˆ]¹Êîˆ]´Äîˆ]¸Øîˆ]p…Ý½àŠµËbV\iµÅÎ�oµÅΙgµÅÎgwm\ãZn_Sáò®®pyËþBÊA`$£°ƒŒC�<ü�´@q¨Ÿ„Yy'¥Jﲇ2²#oG¬ô²'Š¿8ÊBG3²ŠCGݱš愄â~º/dÙç+½›–^<¡‰ 4}Â<¢V_ü8a ¹™ÀÀYMàÌŸøÀÉO˜ÀþL ôw‡«ø½O˜@?Ý÷Ð'9¹r#®Oââ‹Co;Åß<Ížîcwõ1�¾^>ÐO�<ö­Õ^|k+ǰ؋�õr�§H5©ƒ©z´WèéMJè§GBÚYNWñœYd{¯ÔÁ‘‡zý©Åý„Á\|ð ̾Ç^ôùŠ_zAއ„Z}ñ××1�=bº.2¾7�f¹òŸSRå&c·ÆÇߨͺ7h[6°�õkIàÚë¸Àuäá…Jg:]Å37�Àæ $°i lÜ@×oà_mø×fÞâ.´9 l¶|›y˜Í´éòlê\›"ÇÆfÛ�eG†“0’"R ) …0@KŠ0‚¡îßÏˤ´¤#H¦’°Èp¢ØËÒ„Q^¢!Z‰Š¨a -¢„ ˆ -Z¢Â¢BÝ¿ßO¾!*œ!*( %L%l!°DÚÊÒ„äCjŠ1=`È}†$Ÿ1>ÁàI0.I?’Π„I¡¤%I;’8£`Ò©5Z�B©Ò±¯atÉŠØëL0²eìG,û+|ÆMâôNeŒÞ&8ôfΪÏv“Œ’ô’Ô’ä’¤’ÄOI|‰»ÄYb+1—KÔ%ж% Áf"šëP×\.ZHê&”‹Á@]?ëióu¢ºajËBnnƒ‘ÙÜOÐ,r›û4‹æŠ)S[ú‰K*Þè~„@¬kßxSk 'vÖMh×ŵŠyRd[\+êļFÑí+\|-—ƒåƒ©ÁØžÔä*1½ªC̨j¯” VôEÕ¼~¢©š×ÑO4¾Ê~¢Š¤Ûû‰ÊW­ÞO†K¹EUóÚûI‘D%§ ätA„ìÜEV\ù3@A p.ö_. »èËê&ül˜{Ô;šÊëDUS�¨j˜*ÆøÊëÄšêÄ‚†©¢ÎW.﹈tA‡S* -Ô4 544 �j¡¥aè £ÐÃ@`€‘ž…= &z&˜é˜a¥g`‘C+ô lpÒÓ°Ë¡.zNÄÐÓp!–þ 1ˆ£ÿ‚ñô_ˆEýâà¡§/=…$ÒSð ‰þ^9L„Ÿþ>$Ó" )ôŸð#•þ„d¤ÑŸ�‚tú“´s¢?" ôG¤#‹þˆ²éÈ@ý™È¥? yôdËa†Ñï‘‹|ú=òP@¿G…ô{ C=‰|Ó“(Àpz…(¡'Q$‡ÅIÿ!íÎè?0eô(Á(z#QNO •ôÊPEO „*úF¡š~‡rŒ¦ß¡5ô;Tb ýU¨¥ß¢uô[ŒÆXú-j0ŽÇŒ§ÇQ‹zuh¤Ç1�ôÆ¡‰C=šé1ŒÇDz ˜D�¡“é7hB ýÐJ¿A3¦Ð¯1Séט„iôkLÆtú5Zä°3èWÒŽ’~…©r8 ³è—hC'ýÓ1›~‰˜C�¢séQi.¦G1Sga>=ŠN, _`6Ñ/0WÐ/¤Ýý]XB?Ç<,¥Ÿc>–ÑϱËéçXˆ+égX„•ô3\!‡‹±Š~†%XM?ÃR¬¦Ÿb®¦Ÿb¹®À5ôS\‰ké'X‰ëè'X…uô\…uôc¬Æ/èÇX#‡Wcý×`#ý×âz×a=‚µØL�`n¤a=ºéGø¶Ò�p=n¢an¦b#n¦áÜB?Ä&l£b3n¥âFÜF?@7n§` zéØŠíô}Ü„;èû¸wÑ÷q úèû؆>úzp7}·âúnýô=ÜŽ_Ñ¿£;èß±¿¦ÇØIÿŽ;ñú.îÂ}ô]ôá·ô]Ü�]ô]܃ßÑwðKì¦ïà^üž¾ƒ_áôìÀèaü¤‡±ÒÃø þDã>ì¡oã·r¸ {éÛø¢oc7¢‡ð{’Ã#8AÿŠ�ñúW|‚ïéóøT?Ãôy|Žéóø?Ñçq§èóø§è|…Óô¾ÆzßÈá1 Ðçp\¿¥Ïá;Bès8AÝ�–îÇI9üžpt?~ <}?%}?}ÿ$jú,N }ÿ"Zú N}gˆž>ƒ³ÄH÷a€tÂrH‰‰î 5475Œ7¶®vLÍèêŠòQ¡²Ò‘%#†ä æåædgefÒÓRS’ýI¾D¯'!>.Öãr:ì6«ÅlŒ½N«Q«” -žc‚ â�-UóEWE»¨óUú�¨«?1.[„Ùíõ™<ÁìÖÌ(•ÈDXêDkCË„ŠZEEàb’z‘õ '½"ÌãÜž*‘ó‹œßWÛÑ)¦6µx}ÂÛîså­­™bLE‹×ë¿ÈøÇˆ¬_dýµžNQhhñJrÎ -ÒÓO?)òºEy[Ý"šZÄøÁdkë¥@>Ð}Á¬'ÝÂ�«¢R„utŸˆ°Id'Š ¢DL ˆŒ_Q"·†l‘XOŠÄ"Û8æ »�ª)ºª:çûª:牮ŠÎö!žžˆpÔëéöt7µ˜‚n¯W]'¾ÐزG«©ðUÌÖ´ff@ÎÀ�¶ÂW¡•2D�oÉ¢+%r„ÑU ßÃ@¥ÏÌÍÜ*é™/†¶´‹ŒßWéõz33DËPI?Ý·õü"ˆæÀ`̉E@ˆŠ -Qá™'†:Dlñìɨ׽µ_ÀÌö€®Ó×Ù1­Ed;Z33ö€õWu5‹±u SZDÖ_%=í]IÜ•r ÏSÕåéöUJe]í"ë÷UJB¿ ¿³kv»¤&¤ÝW™™!ª+Z6y÷¹EsE˦*Ñõ¾JQ¿æ37Û]åœç‘’ÝÝ›<âŽÆ–óK½RØÚÚêÌÌðtWùªºÚ+33ªæ—K"É>'6YÇtÊ méðˆëfÎ�è^ÇÖAý÷v ¢î'¯Ûëõz%ñÈ£¬ìlŸ/Ažß! ³j¾§{Ëly¨[å¡y½nOÕüJé‘*zªDL�SZªº|UCzº}‘õ_\×ë]©bww•±£³<3#Yt†ðK6á‘ñWˆ¡fù…fYž*1ÔQÙÍŠL‘ªI%í•­­ÞˆÜY¿GTú7ñY>O·Ô¢Ò/Z‚÷9ofƾ̌º¦–ªJ·Þš™Q×p.›8ëšZº³�»#<ª›à«kŒhA×`ÐÞ1`æœä½ÞÖ(½ÜêA§û`kfFµ¯º½»»Úç©înïîè§ëfú<‚¯{�N×½¤ªÝ#[>éè§Olq‹Õ[[E¡½‹ ÏÌðHúVÝT'Z§Jâ©ötuDœE™Ï[äöšZiþSqÔÎDe…¨�í¬[8–™!ê*Z¼nOµä^úé‰"·(Ifê1±¥_À,Ygå CÄ„‘qK–¶ú«æMˆ2ÈíTÉï5Fs[33¼^Ɇ¶ô‡033Ã+®kl‰¤=˜éÞ‹Pv UdÚ¥’}ƒ%¶‰RɺÁ’sÕÛ}ÞÌ §´5º¬NŸ¯ÏÝ&ŸÙSœ-ó_v·�â¾æ–~zªHTEÅm©haÝL4ƸY)¦ øO‰èÈ%žˆ©�nÁçyÍ' -‘¯hÙç.iõ&f’™!Ö$«aüÂk¾‰ä;aDR"»”‹Hd—Î:ŠDb9§<žªîö¨v�?¬èÐÙu鱉œ_ð‰ºŸÜz“Ù'�ðÙ¥E=µ¿Z²%·7BQÛ*$,ŽÉAf†è®hñˆ¤½JD£ñTyº$a‹žöJÙ ´ºÏÏî§GÚ+%·×â©’HÜQµnuGTû"]ûß5|Ý·¸~kk×ðÌ 1”îÍÌð䋤]¶–æ–(—ŠÜQ+’ú# åÂòs\¤ù9wëš/H�×®\VtÎð›[ÄêÀ`;‘ôè€ûüdÍEÅc‹!2~“¤bó=²�„Ú£Í^PÐØ"†:{nj¹Ö½FšW”ïñ‘Í�{Bdó„)-� €gssË^†0íå­{’ÈæÆ–Ç=@HÎe¤\)SJx¤êH]SË^F%Ó»ëäRNÎ�Ó³ú ä<Õ`Á¬~&’' æ1˜ÕÏEòBrž¼Ì`’ÎfµåзEVút9WVDr˜Èa³R¡Tñ¼ -,”¼Z:|Vð -•RsŽL¡à<«P°àYµB¡Çqrá!§—OG޵uZÕ&NúLÉŸOÍF0©”*µB!cRh¤ï^J…B¥ÒJßÂäK©ä• -N©d¡`5J…Ï)/�Iù?aÒëTçŽÜ%Lêh3Ê!LêALÒ6•B«‘p*”j•îÁä´ CRW*!D›Ña$K0št:0h­f §No2Úe¼2µ^£×)õzt -›^¯‡Z­Ò_¢S=.ŸŽHÛí2 aR©`‰6cŒr€0M½Þ%½Ý*áÔ,&×92£QgÔ«ŒF%ôJ‡Ñ`„F«–‹tvh¼€áç˜Ô@œÛ2¤‰j5¬Ñf„!LVÀl²Ø +T0é�vi0­fwd.�¨½`P ‚ -•K “p F¸|:"mO¼mH5Ø£ÍD;“8h¬f«CìPÃbŒ‘¾žZ“ݘ#d&“Á$¨Mf•Ûl2A«×˜/Á.ŸŽHÛ›p!&G“y“°YlNAp@ «ÑíŠ`rØd¹ÊÔfƒYИÍjêX‹Ù �^+·p‘°Ì¸|:"m¢sÈ:´Z¸¢ÍX#9’T]€ÃæŒ1›]ÐÀnŠ—þͰ›-.G"`‹�Y­‚Õ¬µÚ40k<6«z£Îv FXqùtDÚé)î!MÔëm&ú#ƒÄÁ8ÀítÇÛlqÐÂeIôpÚìq1)ѯà€ÃavXu‡6m’Óî€Ñd�[°\ء㤤_F +?¤‰rz½ômÊG�rn~/ÊP2óI}~ÿ»à±»ÝÝ'¸òûé‰�:'Ÿäççô�P¢ìx^v[Q$4g/–Æn`”¶xÖf50¾Ä,&¥0ž æ•2ùÃ’}¾ÂH,‹ñ%ea)Ì‹g8wÆô[g—tŽN)ßôò�…óÛêc}îºÉ3²çÝ<)IÜ»(aUׯÆŽh- ¶5U»cBõÓ‹fß<-�[Z³¾«ÎÌ© šæ—Nݹ¦Æèˆ3ÞcNr›‚­ÚrSú¸+*ãŠ�Îxã}›I[4u98èWdç€)ãE£à]”/;Á/áÎVÊHèØ‹Òd—9>ÕáH�7™¤wZ¼i¯)>í‚ v·J¹öÔ³9!õlŸ#5ÞlŽ›âÓBj±–»� %,óÏãqz@vQ^vQnŽ?ŸH·�Ô2×\ËNYÛKŠdæ�áø`è�w'ß%p„4L�Ýnä,8dg—™‹‹%ÙzY/ë#A INΖ?,ßg`•ÄË5°ãËçÙIâéð„p¬F§çÃ÷’ïHOx1ßwz·E£7èôjµË£¸¬ô?7‡ïƒ~ä 6dàÓ{Ì�“9¾ÇÌÊŒ»”ô½Ä›Ï(%qû":ÀJJ G¹9É㯞XÚVšÐ¸íÀòp-É&[&m˜’%:ó'Ž|½ó©Ië'¦�½õާç�¾¹5ÀuV\Ý9Fà4ùcg,þý²|_NóÒŽäÊü„pnjMçÈ�•óVœM»@ÒáéQ¾‰ß ?2C:«à±«ÕØã´@Ò^m²¥�ß“È] ¿¹9$‹•ôRòÄB¥B‘¼¹ )˜gwð™quSŒÜþ�ÝSË×Ü?·|á´Æä”ÆÇ—oþè—“V½G‚O®;PÉ=`IõXç?qæÖU�]2ºý6ÑŸ2å·_ÞüþÉu…>ÉÕüj¾¸ Ù‡˜ùž£Q3=�E�ÚLz4‘pfÇÈ>ÄËz•òC¼\öÀá.Þ0æ1cãT$›9Ì3aÇ�a‡¤uC-«áiù†Q)ͤG%7i.ÎjÎil>ÃxÂ�âÂaûÝ›ävn¤Ÿósø½ 'd±öØlɳ±'Æb„$%VØ#’¨’#¢*j+;ž—gŠtp¾° - --ÞB/;(¯RN²T_í�8gUEï×;'�ZóÇEu«‡M -?ì%§nšø·µ·}ùë‰9Ó·öº©ví¼¦8n—=Ýk�ÿØ©›®|âU.+ÙÙ;° ³dæ¾Ú´â�?ß½x¤9ÖkŒò”IáûÀBó13¬ìïƒ>üé’ý ôœL×ó}0Có�Ú¬‰Ðâ#ÉÉ)>É&Ù`AA! 2#ÉÉ×Ãõ -3ÏõJµoá´.-sÛgÌ›™ÌMZ�v`$ß70]£e–FÛe›ø>ðÐ?ÂõD{—,ÝK‚ÄËæ¸HöƒáÌ¾ï ¡WlãûàGlHÏ[=lŒ^ïJŠa‰ ÙÁ² ¹8Ûì(ÎÍñú,…²{ð±Yl¾O¡PÊžÃnwD€òí¿{E—ìâtI)åm: ZNá¶¾²“ä¼ð©ÑÄ(„¬$†ý�}¶¸g‚sDa†v …Ù¥Ë,î -Ü:ólˆï˜”Yß�Å슎D¡áû� sQˆpÈë#YlŠ„Cê�ijŽ`)[h rï>1ð«R)ˆ‚°Ï|·‹d¿HÎð�šåÇ)˜¯îç®U9bœJM\|œöÌ�|ß™»%÷¥Öy|‰:®&bs\�üO£1!ïésB�…Õš%f7Ÿï¿ìv‡ÅÇ&KÖç»Ø‡q=£–ÝÛ–=Ú~Uÿ|Çì ×^ÿ€äºæmoÏãKÛË?¸âùy·µ¥s…mÛŽRqÆöÆp>y`zËÀ½|_QÇú©9�#¼§òš�ÀO�r�çÚÄ�%`Í×pîð=Ã9or�[š‘–?Ø&Ké<}wÈþ•»pvÍbR¤ELd’r°¹ªÆOJoXT3¬©°´£ÒgL©œw{gÑŽƸ8OÓ´™9c�öÆo™ÛZ‘2òª=Wf¶6×Åqûͧ!³ª)){luujfKÛÜë”Iå©BŒWxБ–`N*›”—YS5:àkl_ZÞtÛâQZ‹C‚ý÷WyV2>Êš ߣ�Bž¤ü^â“ÖÜ®pWøäDÏð°ŸñÌé0ÏÜ ‚Ýô(ßÇ÷Á ᱘Þâa ’NÈþÐÀFŒº Ðd ì9ïl rÅO½åoÛ?¸²T«~ð�äÔJ.gâòЉ7ÌãüËLpë{ÛÇW¯ÙÕX˜ÃúÏ~î((È17¬¬OÉ™sïìjøÝ|ŒPïeX‚lY YIõ•’ò‘ Ó¼ûðƒ÷òËñz“Iɬ†ï;óËØÑ1z�×kàfIÚ|PÅÉv¦Þ«c5ƒ­$J¦DäöÑö†b|ÓÞi ÏršxaàÈcËöÖ2ÏñÁ¤b2û¦°ŒÔ£Ñ¨d Or) õ‰ž†¸3‡ù¾3O%Ö'’R’®òÌñc¿ßgàj"ý‡Ì§È^9?”dƒ ò)¾çóŒŽ'Çø³<ÓÎ eÄ]—/n[º´méRÉEy•ÞBIN|Ü™çÙï™×5\Þ€3�cøÅgÒî r¯Þ)Í_õô(çà\ð ö�VaÓåôšìI½q‚<¥È7°6_)+y•!—lw(““}‰.*C®�½QeÔ*ï'œRÉq ¡úöQ‹Îâ7í»®áþæ?û¦§MÞ8³"Õd TdåM[šçÓ’šäm vkQÉp[îäò䜷Ì~{ßm+ª�¦U*]aëŠÕ+sЧ†|iÕÓæ.ȃ2z”SñǃlÄ„ôɺ´^¥Ýìéu -zH4OšU¢3¯dS$È*d)óìÊÁÅ*k·K�9Uliû¦=K²fNŸä#ÃvÍÕ:´Œ§fÂŒ¢[¹Û–Y�W¶¢½Z¨Hœ[8zåôê,ÓWy÷]7/¥w&ÚùÝa{îÂô`Óð„ž,žJ¬]Ó×~Ɠݴpµ¼ú®§GÙ�œ ~d„L!G`Aô½V{Ht6d{=ÂÐl˜]Ô–›CÙj—¦BåEÓ Ûž¾ª¦jñ¤ÒTËu‹Êo.ó�Z_3}Ë´¬ÄŠ™kåÙ|0§¡kÉâœ[n/ ÜçK -¹«µù7=×´uV‡6*óõü1$¢®�^›×k²+lɽq‚Wæ¡Äƨ؇•2ËÝ$K~£R¯QÞÏ+U,—TÓ0¥ zÉøô„Q�Ý{¯(j÷uí ¿›â#¾Â ¼Å²;ØBM¬Ç'4µ:ü'½'çw•˜ ¦Y*§¯ííâ§ój¿`þ}[Îr/nyºåšú$� - ý œ [z -J�ö8Ôt_Ȫ3Ö¨µZ×ËÇšó{�ö@oÒ ÝKêÈÍñKÂON)”-†)¼´`†T¡ÉÕ´éù›gö”$”ÝÜÔzýŒ2›�KÓÐ’_µd| ¥vÁæß´µ=QÿçÄŽÂé÷,-³¤�Ê.l«™íQ×^õrï„,Ï]ÉÆ;uúŽ‘­#ârÛ·Mo} oýô|§qµJ7¹÷ù+ -¦•'g�í˜3+¹§“õØÒ:lJ[ŒÐëœQ?P]°>K)›•kdÅ&3’Ó)ÕZ~Õ®k9•‚]ZwE£°`©¼ïÎß2kÑðu˜°>¿d„uàU¦EHO÷iê'Õ­º­&,ðÇ’Š;F§Þíô$cãÁ¯„Â5Ë“@4Fs/‹ìãeoµÏÍñK*–�ôЍe[¬ÑÜ`ž�ìp•%ÌîÔh{wmW+3scRLSGffŒ•‘QÊ©4³'º*ó˜…éYBZ@¡à¾È •ee åA€?�¤IœšÑ*lŒMkTJL(+3™‹‹#ËÕèZ•ÉI2ÿé°È-—†z€#áCLÊÀ»LÜÀ§ü±³3É^yLnþ8lÐ=¬At(ç�ƒɹqœÃN°+L£èAs{ÏÔFAG°*®ä\#í;…òB6±wôH!רt� –•�;ò~.5î‰Â B¡ŒúõxÆ! Tq¥R«åVßw-§Rr•5É�ãF�H×,صVJWW§4Õ�‘¦Y°ë^•`а;x¯PrIÍÓ熦�ô°þ‰‹F®[wžÐMéi>Íø‰¾’†©3²Âš¡Œ‘�R†Žy/eâøJ{ÊĤôÔá3G§&WÍ,)ê�Ö ‚b€³s.dJZ¡´9lqFŸÐ›&{û²ÿ¤›?gWjÏé蘚ò_\1ÞpÑ|g-Y9sT ã°’¶sÚ:¶¥þªm¢,쓞VÛõ£§9WôÜÄ×ËÛ]½Fá?œ› Nœƒë5öô¸žWÑrÓ¬üÆÛ^3ù¦ÎÂÝžáMÁ–›gæ'OÖzóÌaÌÆÍ?<¶ h^ïô›~|dnѼÞ9£fWù§ÜöäÌÒÙ£“[o{ - ýkØÏ©äµ‡<éÜAi.7º’{c£|:^68•'§Dx”Ø,(8§då…3Ç©<å³n¸îˆå�9»N+ujÅn^¥b¹Ñ{çI3ÒnKFUÞ°©õ¡<ŸºÌœWP䬺²mtŽ“é«ýU_÷¼‘vcØÅíˆLJÃËF˜W¯Êiß6Gò8�šsæf†«ôEÖø‘ù=°n}âÃZ›É9‘\Èb¯á¤ÔÁ@^^v‘,m_òB6°Ñ5‰ƒ sÖQžáó'�2·ß·Mm6êØ�¬J¥b8Où˜¦œØB;Û¤sÔ]}ï„p9³;}Ú´æÄøŠ² ¡xÚ¨$­dU=Êœâ\ÈEjÈé5¤)8Ëœ¶7KøÎE\ñ½»´ýhÚH`òöÃn¿ðp¯@Þ}HÇL’èíæPæ’¢és-þbÿ’Y�é½ âkÆT¸¼ÖUuþÎYÆäÒì9YS»§Õ¬ÏdÇÆ%M—HuŒºqÒðŇ©‡ñC¬ÝÐ0:&##3¶tÓÄÒ¥“‡ÅÚ%þͤß2¯óÙðÃô‚^¯ê5Ù}$ÉÓgDÙñ`0/[ž…䈨¿9ÿ$§ Ð™ Y/³7^®Ðeæê’SSŒ ¾ÖÔ↠C«ZyÂî|.¿,Ÿ-# {åÀÇ 5ö`¦JgTl3Úâ -ÆåÄ�ó0™[N3F‹@¯GpåʤcèÈzX›Ük²gc�ò&ºVú - - - Λ ™Á �¼°”;ÕFÙHõÒ‡tÉHKÊg•{U=·*â‘ÆŒÉh™P[’®Yð[âKi®¿ÐDCzɘ™Ü�ݲ1×µ&�lœÚžA~ˆì Ø�8éÛFÒ#¼Ó[ƒ~úeHáI/gƒ²WeŒn�ó·ì¡0Õ gÕ±ø:�u²¯ž}jK>ÚBid'Àob’Q)_º/‘|ö´œßÍ@>¹?ÌígøM0ÂgHŸ`Ó>³„ÝÆ2F–°Èn“Nµåõ–> stream +xœ¥z|•ÕýþsÞq÷xïÎÍ͸777ëf_² $—,BÂHÂJ˜ K@ÄT ˆD jµÔRj­}A+ÑZ‹R­‹:-œ8@)ŽR ÷ü{Þ{Ã’Ú~~ÿ÷ý¼ç=ã{ÎyÎw�ñ¾ $À¸ñy…�=–Ò }R֕͘­×¾˜ÞÄów,­5}ö €‹ðòì•+¼“2ê¼€zÀm�»tÞâ=¯—¼ØûíúyË—Â?@ ¬—y‹VÏÝÖEn2‸•]�‹¯|Ïõý1 ©оÛ5§£óäž{j²@qWל«dôd€Ô®Å+®øûþsÿÿíb˜þ¯u•úõÿõÏ¿¸—pP< +'˜§� …¬x8ÖX@?§7� �H&ý^¡Gä‰X[ûé1ñ0rõô+¾ F€~õS}GŒib�MvDz—ÇÞ ,ÃÚKá¼ë-¼õ¾Œ�è‰Åwâ�³ù,~7ºÎ¦ïÀ沨¥Ü~ã¿ã0îÇ'ä)Âý¨ìFÜàYìÃ:4` +šÅCâ!܈VlEë¿ûX{í+JÈFy%Vá*tà*¬‹•­Sx¥l±ò¾ëp+6á~ÜAÞÀh¬@'vžkLåÇ X€Å�ÌÇóØŽµ¸ Å>X¸TXxÐo°óþÍ÷ÿûu fcöFnˆ¬A':±×p?ÀÈFaýP‡XˆÑêù‘|‚'± 7`Y¸åƒÃNW›œ®„«¯qz®¾ÆýÚëNWÂÊUNWÂâ¥NW¢%NWÂÂËœž…—­¹<~ÅvG¼vGÂÜùvGœ.»gN× ËâÝË�WU»}««Ý¾Ê?“*˜ÉÜOF€£‡ýGf°,ÜOÂ� ¯Ž¾S3Ø»ò‘ì¼èÛ•ÀÞÃÃδ`ÙgGø`øHvnYøˆ'¡,òQ~�Òˆû£Ä¤²ð[.WÙWOqÁ§ú¸à]}\°¯W öÓÃ{¾¶;Ëníá•øw6gÙÑ^!ø$©#µà$µ�õj‚=½©ÉýôpX?;Î]6w6ÙÖË:8üHo £¬Ÿ�Ç®å‚gé‚�“ +R¾› †ûIùîäÔ²~’·ûZ>ØOrYÏ_í'Ù á·]n”ö/)�²ð3.K=²7ÞÃÞ{öJÖ²ý/30{÷¼à÷—½ø¼KÇõƲ/¯ã‚»~Ï]t|o˜­Jå?¥g(M&lNJ*»©[v¯×7­çƒëÖ�àµ× ÁëÖ+à WÌŠs—ÍZO‚דà†õ$xÃz¼~½übý¿Ösó×O‰#®Øá(rX‡8Ì!‡¡Ð¡-p¨ò|ž¹Ž‰d(3)%e0‘bRô¤ÃH)ÿý¼DJ!@OŠ1Œc*)‰ !ªÝç!‰Æ8u¼Ñ!¹ŒVÁnÌó�ìò¬òŒò´òÔò”royR¹§<®ÜQn-7—kËUå|9Ê›BˆlmDã„*ÙFÑ8¾Jûyo‹\l”µMS[w²¥Menc?ÁYØØÏa‚l­ž2µµŸ¸Yñ žÇAäÆönn åÎÆñ­òÚÄ6¹�E¶&¶¡Q.l–=þªàÅ×r%X>˜ŒíÊH«•³j;äìÚö¥`E?QÕÎï'ºÚùýDç¯é'šhº½Ÿhü5±êýd(Ë-­�ßÞOJ•’.VÒÅQ²³YqÅ�]-ÄÙØ¹v9N®lÿ£aîÒ2v6µT5Êš–FYÓ4UŽ÷W5ÊÏ·4ÊÅMSeƒ¿JÙ{vÁ€“ + ´4-t4�ê¡§` 0ÂD`‚™ž�= zXéiXa§§aSB;\ô4ˆ£§àTBÜôâOOÁ�ú/Ä#‘þ $Ñ!Éô_H„—žD|ô$’‘BO‹TúOø”0úOø‘Fÿ‰T¤Ó"€ úÒ�I@:²èl÷D¿G&²é÷ÈB.ýAäÑï��|úrP@¿C. +éwÈSÂ| ¡ß¢Eô[¢˜~‹Jè·‚RzE(£'PŒ¡ôJPNO T Ë0œþƒíÐè?0 •ô(ÇzÃQE�£5ô8*QK�#ŒZú F Ž~ƒ*Œ¤ß õôÔ`ýµh _£�ôkŒÄhú5ê1†Ã(Œ£ÇЀ&z �h¦Ç0Íô(Æ …ÅXL G1éQ4a=ŠfL¦_¡­ô+ŒGý +0…~‰‰˜J¿Ä$L£_b2fÐ/Ѫ„m˜I¿`»Jú¦*á4̦Ÿc::éç˜�9ôsÌÄ\zí˜G�°¹˜Á,%œ�ô:±�~†9XL?Ã\\F?c» úº°”~ŠùXF?Å\N?ÅB,§Ÿb® Ÿ`1VÒOp™.Á*ú –b5ý˰š~ŒËq5ýË•p®¡ã +\K?ÂJ\G?Â*¬¥áJ¬¥b5~F?ÄUJx5ÖÓq n âZÜHã:l ‡±éa¬ÅMô¬C7ý?Ãfú®ÇÍô¬Çú>nÀúnÄ-ô}lÀVú>6âVú>nÂmô=tãvú6¡—¾‡ÍØFßÅ͸ƒ¾‹-¸‹¾‹[ÐGßÅVôÑCèÁÝônÅ=ônÃ}ônÇÏéßÑ‹ûéß± ¿ ÇØNÿŽ;ñKúîÂôôáWôÜ�ô܃_Ó·q/vÒ·q~C߯Ïñ[ú6îÇoéAü¿£±Óƒø%~Oâì¢oáWJ¸»é[ø5¡oa'¡ð¤/á |D_›ø˜¾ˆø„¾ˆ·ð)}ñ}oã}ïàsúþŽ/é 8„¯è x_ÑçñŽÑçñ>¾¦Ïã%<Œãô¯øÿ ÅGø–>‡�•ð|GŸÃ§øž>‡Ïð}Gp’>‡Ïq’>‹/pŠ>‹/qš>‹¯”ð(è_pL ¿¥Á7„пà8!tþAxº'”ð["Ð}øŽˆô|OÔôü@4ôü“hé38Itôiü‹èéÓ8E ôiœ&Fú4Î3Ý‹"ѽˆ(!%º7Ü4¡¥iܘÑ� £êGÖUW�WV /6´¬´¤¸hH¨° ?/7';˜•™‘žHõ§ø¼ÉI‰ žxwœËé°Û¬Él2ô:­F­ž#È&qr\ukíÙ]Ý.ü5~É+Æ“'Ãêñù-ÞP^[NŒJƒ2l�²½©uÂ¥m²*x1ÉX™H'|2¬c<ÞZYÈBÀßÐÑ)g´´úüÒ[ž³åmm9Ùr|u«Ï瑹€ÌFÉ|@æ ÞNYjjõ±%g”Œ¦VöôÓ�J}¥¾6�Œ–V9i0ÙÖv)��tïE0Ç’ni—Á]]#þ †�d8ÙñRÈ(—3‚2�d”+­!O&ö2±ÉÄ1F†õÂ.XµÃ¥—àAmçmç|Ù]ÝÙ~Ž§Ç£õy»½Ý-­–�ÇçS@7ÊÏ7·îÒëªýÕstm9ÙP2°K§¯öWëY†lð/ÝE D‰p†Ú¡»8hŒ9Ù²•Á­eÏ9¼©]æþŸÏ—“-ÛΕôÓ½›Ï/‚l ÆlÑX„¬ª–ÕQÞùr¸CÆ&ï®ì½Ý›û%Ìj:ý�ÓZe¾£-'{ø@m×9¡±iJ«ÌjÙÓÞåeâ®Q&à¯aB¿ ¿³kN;SÒî¯ÉÉ–µÕ­|{=²µºuC­l ÊF�l¼êß]7ßË’ÝݼòýÍ­ç—úXØÖÖ—“íí®õ×vµ×äd×.¨b"É;+6EGu* oêðÊkg-ˆê^ÇæAý÷uK²áŸÇçóù˜x”Š1Vv¶/`�t°aÖ.ðvoš£ u³24ŸÏã­]PÃVÑ[+c¢W=¥µ¶Ë_{®Co·¿Ã+ó�‹ëú|²;È*vw×2ˆ�U9ÙQȲ;x?³ O�È\ ZOP^˜ ÈÀ[+‡;jÚbY1‚)¬+i¯ikóEåμ²:°AÌõ{»Y‹ê€lJ¾¿ør²÷æd7¶´ÖÖx”ÑË\uëðcqžcm9Ù�Mg³I\cKkwÞ1O”G�ãý�ÍQ-è Ú'D ˜;+yŸ¯-F¯´º?γ¿-'»Î_×ÞÝ]ç÷Öu·wwôÓµ³ü^Éß½Ë`è^ZÛîU,ŸtôÓ'6yäºÍm²ÔÞE†æd{™¾Õµ4ʶæ©LKÛ MÓ*ŽÙ™¬®–UŠ�uKGs²eCu«Ïã­c/õÈR)3S¯Œ‰­ýf+:«2Æ·Êœ‡Y +ߨ�?>Æ �oPa˜ßkŽå¶ådû|̆6õ‡1+'Û'¯mn�¦½˜åÙ�p^°MæÚYÉÞÁÇDV²v°älõv¿/';Žm�~R§Ï×çn‹ßê-ËSø¯¸ÛNyï„Ö~z²TÖ”ÆÄm«nå=\,ÆyxÓý’·\v•ŠŒ'rF°[ò{_õËRP«[÷zÊÛ¼’E†•ädËõAf5\@zÕÿa¾vI&å2q²|Ød¢¸tÞU*ÛYåñÖv·Ç´ëüaÅ&€Î®K�M’_6üà‰Ò[¬~6——óÔ�:fK_”¢¡M61,›Ž*AN¶ì©nõʤ½VF³ñÖz»˜°eo{�âÚ<çg÷ÓÃí5Ìíµzk‰'¦Ömž¨j_¤kÿ»†¯Ýä‘×mnëš“-‡³|9ÙÞ"™´+Ö2¡5Æ¥ROÌŠX_£ØP.,?ËÅAšs·q©óÚUÊJÏþ„V¹.8ØN4=2è9?YQñ¨ÁbÈ\ÀÂTl�W±‘p{¬Ù +š[åpÇ`Ï-­×z®bó +‡ª]~²±yW˜l?¥õq ðnœÐº›#\u{UÛ®T²±¹õq/Vr9–Ë2YÂËh$�-­»9�Bïy< ¬UJ%CIÏî'Pò4ƒy³û¹hž4˜Çav¿Í +yÊ2€…�Íêujö¥0z˜Ì³O¨Ñ¨*z*ÉE›Õ*µF5ࡵìðY%ª4jÝY2•JT‰¼JÅCäµ*• +‚ (Eâ…‡œ*üt:z¬mÐkÎahbÍĨù(&�Z£U©L*ûî¥V©4=û¦\jµ¨V j5¯S«ÔDA} Lêÿ “Ñ Q>±bÒÆ¢ês˜´ƒ˜Ø6�J¯c8Uj­Æp&ÕYLzµZ 1†é¢N/Ætq:: +³IÇ0EëŠ"t±¨æ& Õêôjµ´jƒžáTktZ“‚W¡Ö¨5jA£ Œ�¢JÔ\¢S ~:Å$™/Ĥ�Eµç0é�V§g² SÙÿZ�F¯3Ÿ%ÓjÕZ�¨Õ +Ð&­VËL{ LZüt:ÊY‹¤gØÎb2Äš‰Q3=3z�Þ Ñ B§1ï4Zƒ^Rxx1&³ŽaR«´—`Äÿ†Éf50LQ *Œ±ftç0™%LZ­"ôZÉÄx§Õ V…‡ +µN£ÓªtzZQÒëtPkTúKtªÃO§£œuØM ›f“)�uÆÞÄ,ÁhÖéLPÁ¨³HŒw:½ÉhWx¨Pëµz�Jo¡­½j�Úp‰NõøétSœSbïèxÔjH±fŒç0IÌ̃ÁLz;û–k2-f§‚W¡6ꌵѨ‚Aå0�Ðj5ÆKtjÄO§£Òö¸- SˆF[¬s”‚é™ °˜-6£Ñ5$£ÓÎpM6‹û,™Ùl05f³FµËl2C§×*E† ;4_ÀôcLZ ÑccØ¢@´ZØcÍHç0Ù«Åæ0™ìÐÀbŒs²9Àd¶[=ѹ€QKFɤ•$ L·$I “t FHøétTÚÞ$âÓÁk&ÖÓ}'`·Ú]’ä„6s<ûzj“,N{û&o±˜,’ÖbÕ@Òx¬ ôF�õŒ°à§ÓQiû’/ÄäŠa²žÃä6Gœ$¹ …ÝìqG1¹ÉŠ\j«É*é¬V-$m‚Íj…Á¨WZ¸HXÿVp‰ß @ %Žñ+:½îX3ö(3B7àrÄÅ[­nèà´$±3œV›Û•8¢dv»d·êí¬:¯Ãn‡Ñlp\‚vüt:*í¬tìшÄX3±˜=&ž8O’Ñ=ܶ/€8‡31>=öp¹¬.»ÁåÒáO�sº`¶˜”lvèº0ÉÔââË ä“¶(“ Þ?ÝQ +�ò¯ã}.§$8ÒØ?Wœ71Èþ#ŠR»ín§Éo€Ë�ïvC²š•"Ç…ºñÓé¨Úæz™&FÇc6#%ÆOO”‚Ùc +àMô¦ºãR`D’+3�ñΟ’œ åFíqzâÌž#ÜÆ`‚Ç«]J¸c<øétLÚûÇEX/®d‹#QÈÛŸ·¿ ?dñY>‹oÿþ™Ç¸ÇÄ•§ºoÆ‚#Vþ÷˜Ø§Ô1>JD^Í£2´¿° Ÿøù{¸‡VinŠZ¡ïæ‘?GF�?³o5k"ø±èqðz/*+ ò‰JÇ9ìIœËŸË ±Z‹Køœkþºy´#«<ýæ¬Ê,GÃÆ}«Å¾«"g"_Floúå½·‡«z﹯ñw$Dœ+Ah}ä9kWâU±ví§Rû‹ã¹¢!¹\z(‰''nÚ·ú×<¿y´#³<}SV8ËÉ(òrä«�•Wž8Ip{ÓöûnQ½íž{Ù÷9¬‚Ð#%,q&>¬RW©µàŸ§"*äM?VV¶?ˆø8i̱‚|bñ[|E>KÈâsðîë# ȶëÉmœ5²˜Üv#¹-²øF\ONqû¸«ÁC»›Œç�Ç*úJ|ÜŽ�÷9?9µŽñÉO�q7*Q¶Š©}�À0§äu§ÓÓ'¹‹úéñ°6¿ˆå÷ S£òXaÞôÒhh)Ë;VÆÆnâÔŽ$Þa7qþ”\.½$‰VpECÒüþ’h,—ó§˜8uI*LâOöŒ[ç”wŽL¯ÚðÒM% ¦�Mð{'ÏÌ›¿eRª¼{qòª®Ÿ/*IÖVšÞRçI‰��Q:gË´,aYýº®F« -nYP1uûUõfW¢ùkªÇ¿°tÕ¦›³Æ\VS–bŽK2? sXô¥S—ƒƒ‹~Av.Ø�i�(›%¿ì¶¡òXå±(~†»hHÇÐñ¥ÉkR†Ë•‘d±°wf’e·%)ó‚ ~' Y®3#ÙjMÎ8ÓçÊH²ZcÅ–¤L€�¬FC Û£¢$Šxœ�WZ˜WZ�("ìv�îú�kù)kzI©ŠÌº3’4 ½îû † ®°Žëq:Í‚ŠíFòò*­eeL¶>ÞÇûIÈFÒÒŠ† )ò›x5ññGF Üÿùsü$ùTäB^g0Š‘ûÈ7¤'²Dì;5Wؤ‹7š F­Öí‰× ÜžýÇ%ÌûàBùH›Ä¬žädk°ÇbMê±ò +ã.%}ñ&qj&nTx¦JT˜›6îê‰Ó+’›·>»<Ò@òȦIë§äÊqE‡¿Öùä¤u³FßzÇS ŽÌØØ:«¯î% º¢Ñ3‹—üæòab_þ„ei5EÉ‘‚ŒúÎá+ç¯8“9z!Óá›è±EÜ�r»䵻ÝÜgÓ^}2òØŽQìI.Ðß‚|’Ë3½d�A,Q«TQÉ[‹SC…N—˜“Ø8eáðmÿØ9µêªçU-šÖœ–Þüøò�Ü;iÕ!úãÚgk„‡l^û‚'Nߺjϵa³'à�éS~õù–'ÉÐ�®+ñ3¿×ˆ«Å>˜à†´ÇÞ£±Úz´ü9ýÎrŽqËWXÁ‰«ƒm›Ÿ9}Od() ·lþì—SäN:Aô¿¡¿�ÌOZðúSÛWU‹}ã¶¼ýõÏNo[ôäiÆ&·&±Oñ!V±'Ìé´\O0_Õ£µ’]´Ã âòââã}jå!>!oà`_ó¹ÑI’ǹˆëΈ‹iݹ–µp…õbÇiÔVÒ£Qš´–å�kÎmlÇù"7<Ä"çÝ”vn¢ŸŠsÅÝ"?l³÷8i.«¹'Þf“Ïö&ª´¨¨J§W+,´D;8_XÅ%6_‰�”W…À,Õ%Öù&Î]UÝûåöI#®úÝâÆÕC&Eõ‘“7OüÛšÛ>ÿÅÄü›û?Þаf~K¢°Ã™å³/Øsòæ+žøY­ÛN¶÷,Ì)ŸõÛ/6¬xûOw/nMð™c<åÒ•ùG÷±r¼âïC~úá!’÷0ûyN¡«Ä>X¡{DkÕEiñ“´´t?³I>T\\BBÜprâµÈX•UzYí[½[ÏÝö ÷Æ@w³Þ«.ö Ì0Äë¹e±vù±"Œzb½3K÷‘ññn’÷pä87Lì;ÍEéU[Å>�6Šv/o4ºSãyâF^¨2d-˳ºÊ +ò}~[qq‰âü|._äW©ÔŠçp:]Q bû¯_6¤¹CjºW=@[sf“^Pyì/o'ùÏl¶p*)7•ãßçŸ)ë7¬$[?ÐÊí0ä” uo�u&,ö LÊ›˜Ô”Ëíˆ�D¥û�¬pQŠrÈç'¹|:ÃÁz'I¼+TÁ—ØBÂ;O |Ãk4*¢"¼ rßì y/�Ó¢N§å"*î‹…k5®ø8µ.1)QúN±ïôÝÌ}i ^ŠA¨�ڜУü @|Ø z{$ÉšÜcãõVÆŒcÖóý—Óé²ùù4f}þ‹}˜Ð3âòû¦ç�t^Ù¿À5güµ×?Ä\×ümí¹rRE{Õ{—=7ÿ¶éYBÉôm‹Fhs{s¤ˆ<4£uà>±¯´cÝÔüæa¾�“…-‹A G(smJØ´éO>Äž¡‚/­ÇÃf¤ý•ÇöOW¤tž¾»ÿ*\8»ærél�¤\üîÚq“²šW%Æi)©è¨ñ›ÓkæßÞYº¨£91ÑÛ2mVþèÅ#} CÛ†´U§¿r×9m…}Voœ)§¶%5ot]]FNëôyå�¶)“ª2¤xŸô°+3ÙšZ9©0§¾vdÐßܾ¬ªå¶%#ô6—ûá¯Ê¬d~Œ·±GÅB!S~ñ³µ†°#Ò9ñ‘"3½ü'"w*"rw‚`'="ö‰}ðAÚß#Ú¼¼‰é„âM|Ô¨‹Kl!ÞÄŸõζ�ðAÒÔ[þ¶uÉÃ++ôÚ‡÷;A«ò'.¯žxãÜQq~ˆ m>´m\ÝU;:‚‹òùÀ™O]ÅÅùÖ¦•cÓóçÞw¿q§Ø3´»9ž OQCž©¾š) qv|ø>QàÑh±¨¹uO‹}§ïMoôú|&a6ÓægM¢bgÚÝ^7ØJZq 3%¢´§Šµw.&¶ìžÆ‰¼ K’ï¹|w'ˆ‚h’,.§o +ϱÍf5gú£�ž<6ÅÛ”xú ØwúÉ”±É¦Ôô4I¨9ýhÂèd)ð›„z€°ÿ—ÅtÅ+…S€ãA>Æ·àâÅ,‘3ˆä¨xFäDÒ#X¡Žºë²ÊceÓ—-›¾lsQ>µ¯„ÉIL<ýŸì;ýšN(ˆK8qÉéÌ;CÂ+w²ùk,="¸7¼(�3¬W9 ù½gjo¢¤L)ŠÀM¼Ã_Á3¯rÎ%;]ê´4ŠIˆÉP(áoÒ˜õꉠV Brxlûˆê%MÁ¸²™7ï½®éÁ òÏÈœ|Ã¬ê ‹=X�[8ytE¡_OêÓfNorÚKˇ: +&W¥åϼeæÐÛûn[QgY¥1”´­X½2¿ljØŸY7mÞÂBp¨¤G�xñÈC|ؘfÈìU;­ÞÞ8ÉæA Ù¬›y™M‘¯R¤*tª«¼ÓÉ š„Šö »–æÎš1ÉO†ì˜§wé9oýø™¥·Þ»Ó‘SWX¹¢½NªN™W2r区\×Ws÷][�0Æ¥8Å�gÁ¢¬PËÐäçÿX6-œÒpU_Säi[|^Ë¢ÕÊê{,=Âß ¸@vØâ•ò%N’$ÉØkwV‚ÄfC¾×+�› óJ§ä“A¶:ÙT¨¾häÛ³VÕ×.™T‘a»nqÕ–Jÿˆuõ36MËM©žµæž©Á±áB3_å7u-]’Ëí%Áüéá¥wµMøeÏ5m!ƒÝ¥�É|�x)(ƒ;lÔöZœ*GZo¢äSxÈØû� +îb¹ÛBäbÉß 6êÔŠj /¤Ö7M)®[:.+yDg÷îËJÛý]Û#ï¤�Ï›|ÃìêL‹-X“?(ûaÞ)S›œ–²Š2ëжaI…·Lo¸¿¯»k¸YC¾¸Io,ž²|õy¥ÓªR³êg,X\ÓWþ)…«…(|ìçŽx½©Þ"Y,&±7/·2—ËÍõ™zÎÌ^Ÿ4¸œ�Îæ„Ò Ó •JP«öÁµÆE fË4¦!…ÿTýŽÈñ繤ÊÙ5µ¿jL.¹sƲ»gfeŒš{Í–ÑãV7gýzú˜á—·×I·<ÝP^j¾aæ¢7èµÅíõYEÛ½ùuWÜ5aʯ·®š�›5ª½¢²®húºÆÄÒf¦ºÈC|‹J€î°ÁdК{­fˆ½q•ÏU æÅ& •ZRû‰ŸøKBÊËéâKt ^¿ÔÒæ +œð�ˆœÚA4r²œi«™±jd`¤[œ!j5âÂl:]"¼°é©ÖkƦ4àè{‘dÅÒÓQŽÌÇ¡¥{Ãvƒ¹^+iµ†^1ÁZÔç ö¦Ú=SÇ`A~€ ?-½D±®äÒN€;§ +-î– Ïm™ÕSž\¹¥¥íú™•¿�6ª©µ¨vé¸`zÃÂ�¿œ>ý‰±Jé(™qϲJ[戼’éc‡çyµ W¾Ô;>×{WÚ�!sn�qÿð¶a‰í[g´=Ô·nFQœyµÆ0¹÷¹ËЧU¥åŽî˜;;€`PôØÖ»jG¼Ôë•âb~ 2¶àý¶ +¾(&×èŠMa¤`Pkõâª× +•0²!¼ö²fiáRóÀ=B uöâ¡k×scQù0ûÀ+\«”•å×��Ô¸ê¶úˆ$H-ë™q8´ÓœC<| …{¶7™$ëÌÖ^yÇ*ßœ~¬ ?ÀT,-6é©T1˶Ùc¹¡B'¹ß]™<§S§ïݱM«Î)ˆO·Lž“=bDvv… ÑÍ™è®)äž(ÉÊ•2ƒ*•ðYN¸27wè°‚âQ˜& ZN¯rp½Y͘PYi±–•E—«±µ* ‘dÁSYXΆú¬@"¸ô�w¸Ä��Å£gf‘Ý Ê˜<â18`xT‡ØPÎ ‘³ã8‹�`G„ÆÐ‚vŸnˆ�ŽbU]!¸1Ší;¥ª>¥wäp©À¬v‘ +UV†Ž¹ +,5ቒ�J¥Žùõ$Î¥Tu…Z¯V?p­ Q 5õiÍcFËÒ-ܱ†¥ëêÒ[ÆŽ–©[¸ã>�dÒñ÷‹&Q¥R'̘[ž6ÜË&v,¾víyB·deúuã&úË›¦ÎÌ�èÎe ofîPúÄq5Îô‰©YCg�ÌH«�U^Ú12³e€àÜÈaZ¡v¸‰f¿Ô›©xûÊÿ¤›?˜àTëÏêè¨úªŸ]6ÎtÑüg/^3kD2ó�òa޳Ú:ºuì•[«/DYÒ1*+³¡+æGO îØ¹‰¿Wtº{ÍÒ87œ8×kü©1=¯ü¬õæÙEÍ·í¿fòÍ�%;½C[B­[f%—�Ò¶eÖî†�ßíYX:¿wÆÍßÿa^éüÞ¹#æÔ¦ÜöÇYsF¦µÝö$8ú×H@Ð(ke2xBl.7»Ózb|:V98•§¥Gybl ŸKPóÊÂY4ÞªÙ7>8oØòàܧԭj§¨ÑðÂÈÝóÙŒ´Ó–][8dêØp¡_[i-,.�«½búÈü8®¯áç}Ýó‡;Í·ptRZ9̺zU~ûÖ¹ÌãëgÎ�—9¨1êT¹ãFç÷À{ô)�êsôDp a›³^` ¨ýÁ¼REÚþ´ „lâckì#¼CLam`«Öj6ðÛy�Fà ުQ-ù %N¾Åàj¼ú¾ñ‘*ngÖ´iR’ª+C¦²i#Rõ̪$z„;)¸Q€ŒpœÏ”©l‡qøÞ\é7q'õÚœlû1ýÜþƒ�Q)Û§óÂýbe÷ÁŽ™˜è�.î@ÎÒÒól�²ÀÒÙÁ½ “êGU»}öaµ��ÎÙæ´Š¼¹¹S»§Õ¯ËáG'¦N™˜Ìp�¸iÒÐ%‡h$—ùS‚ÓÔ42>;;'¡bÃÄŠe“‡$8ÿfѯ¹×Ä<à KFÉhÔôZœ~’ê�ïM4£òX(T˜§ÌBÊDÌßœ’S\b‹ÎŠ%¼�Û‰,Wr + iéæd[FYSȥ׬|0yg‘PTYÄWŽ¿bàÃäzg(Gc0«¶š‰ÅcòÇx¹œM§8³M"‘×¢¸Ž•ìø:ºÖ§õZœ¹æ³²‡‰­‡Õþââ’âó&CnpC£,,Yb»Ö¬©‘}€gFZ^5»Ê§Ñ…UQ�4jTvëø†ò,ÝÂ_ú„±šhØÈŒ™+Ø©sc[êðæ©íÙä»èÞ€ÿ@`ßDRÿ ƹêÑO?] õ"éP÷j̱í@0xþV€?0®.ùÌc_&óqü+gžÜTć7QÝ ˆ¸4Ô(ߥnÁK@4Ÿ?¥ä·ÄòRNü +ûødqÌð#.lLvèŸ^Êoå93OxäMg§ÚÊzK™3¢~D¼ø<6yhfÆP)Þos> +/FontFile2 892 0 R>> endobj -816 0 obj +894 0 obj <> -/W [0 [645.50781 0 0 274.90234] 11 12 304.19922 14 [685.05859 0 399.90234] 22 [539.0625] 29 [217.77344 0 0 0 685.05859 0 0 631.83594 573.24219 639.16016 711.91406 499.02344 488.76953 687.98828 0 266.11328 0 599.60938 462.89063 817.87109 750.97656 0 0 0 582.03125 497.07031 525.87891 688.96484 627.92969 929.19922 0 0 569.82422] 68 69 541.99219 70 [436.03516 541.99219 486.81641 294.92188 541.99219 557.12891 258.78906 0 490.23438 258.78906 857.91016 562.01172 535.15625 541.99219 0 354.98047 395.01953 323.24219 558.10547] 93 [452.14844] 108 [541.99219] 124 [535.15625]] +/W [0 [645.50781 0 0 274.90234 0 374.02344] 11 12 304.19922 14 [685.05859 0 399.90234] 22 [539.0625] 29 [217.77344 0 0 0 685.05859 0 0 631.83594 573.24219 639.16016 711.91406 499.02344 488.76953 687.98828 0 266.11328 0 599.60938 462.89063 817.87109 750.97656 0 0 0 582.03125 497.07031 525.87891 688.96484 627.92969 929.19922 0 0 569.82422] 68 69 541.99219 70 [436.03516 541.99219 486.81641 294.92188 541.99219 557.12891 258.78906 0 490.23438 258.78906 857.91016 562.01172 535.15625 541.99219 0 354.98047 395.01953 323.24219 558.10547] 93 [452.14844] 108 [541.99219] 124 [535.15625]] /DW 0>> endobj -817 0 obj +895 0 obj <> stream -xœ]’Ënƒ0E÷þ -/›EdóL*!¤‚Ä¢•樥b,ã,øûŠ™<¤.lé˜{ñψ¢.k£=Ÿnêð¼×F9˜§«ë€_`І!Wºó7½[ËDQ—Í2{kÓO,Ë8_0èÙ»…¿Ôt� N�Ófà/ç¢Ù0Ñ\­ý…Œç’å9WÐ3Q¼µö½� ´mkÆk¿lÏEóT|/xˆPšnR0Û¶ךX&¥”9ϪªªrFýûÜl—¾ûiÊ£œgR†2G:‘IT¥HQDT�€èDT ůH)R&D;¢””§iGT¥ý–qwOü¬ðˆ2IêpOwÆDº: C*'¢t1U%÷ä+ÄØì1ý3%{Lö„ž(%{BödOu„·¬”n}ñu2íì®Î�ñ8>ØÂµyÚÀcÂìdW׺þT±H +/Length 343>> stream +xœ]’Ënƒ0D÷þ +/›E„1�¤BJ H,úPi>€à E*gÁßWxò�ºéÀŒ=ãk/+óR÷–{Ÿfl*²¼íµ24�WÓ¿P×kæK®úÆÞȽ›¡ž˜—•yµÌ–†R·#Kν/êúÙš…¿Ôx¡ ó>Œ"Ó뎿œ³jüê:M¿4�¶\°4åŠZæeoõô^Ä=gÛ–Š´íí²=gÕSñ½LÄ¥cišQÑ<Õ ™ZwÄ!„HyRE‘2Òêß_Âvi›ŸÚ8y�òD)RGH‚N £#_€rPì(@9èàHú (s¾: + Œ Œ@;P å)t´±+rK¼»çö=:™€Zî±g:`kQ'@º­‚èžÜÅBñökư‡°G8°ööh�ò–éÖó_ïÉc¸ÍÕÒÖ]&7Ðu”½¦Ç}›Æiu­ÏÆÎ³ð endstream endobj 80 0 obj @@ -6380,18 +6924,18 @@ endobj /Subtype /Type0 /BaseFont /DAAAAA+SegoeUI-Italic /Encoding /Identity-H -/DescendantFonts [816 0 R] -/ToUnicode 817 0 R>> +/DescendantFonts [894 0 R] +/ToUnicode 895 0 R>> endobj xref -0 818 +0 896 0000000000 65535 f 0000000015 00000 n -0000096310 00000 n +0000101209 00000 n 0000000286 00000 n -0000186756 00000 n +0000198745 00000 n 0000000323 00000 n -0000202416 00000 n +0000214405 00000 n 0000000399 00000 n 0000000548 00000 n 0000000691 00000 n @@ -6436,777 +6980,855 @@ xref 0000008306 00000 n 0000008510 00000 n 0000008728 00000 n -0000096870 00000 n -0000217906 00000 n -0000011999 00000 n -0000012214 00000 n -0000012477 00000 n -0000012740 00000 n -0000013025 00000 n -0000013308 00000 n -0000013597 00000 n -0000013885 00000 n -0000014041 00000 n -0000014234 00000 n -0000014415 00000 n -0000014634 00000 n -0000014873 00000 n -0000015112 00000 n -0000015258 00000 n -0000015433 00000 n -0000015607 00000 n -0000015762 00000 n -0000015955 00000 n -0000016136 00000 n -0000016342 00000 n -0000016488 00000 n -0000016677 00000 n -0000016875 00000 n -0000097307 00000 n -0000021173 00000 n -0000020804 00000 n -0000230309 00000 n -0000028783 00000 n -0000097600 00000 n -0000032575 00000 n -0000032616 00000 n -0000032657 00000 n -0000097892 00000 n -0000034892 00000 n -0000050488 00000 n -0000098185 00000 n -0000052227 00000 n -0000058473 00000 n -0000098502 00000 n -0000060987 00000 n -0000068002 00000 n -0000098795 00000 n -0000071568 00000 n -0000082030 00000 n -0000087942 00000 n -0000099124 00000 n -0000091135 00000 n -0000099381 00000 n -0000094121 00000 n -0000099675 00000 n -0000099797 00000 n -0000099879 00000 n -0000099947 00000 n -0000166497 00000 n -0000161584 00000 n -0000105031 00000 n -0000104952 00000 n -0000127307 00000 n -0000127221 00000 n -0000105113 00000 n -0000105265 00000 n -0000105186 00000 n -0000127071 00000 n -0000107132 00000 n -0000105374 00000 n -0000105526 00000 n -0000105447 00000 n -0000106998 00000 n -0000105896 00000 n -0000105635 00000 n -0000105787 00000 n -0000105708 00000 n -0000106236 00000 n -0000105974 00000 n -0000106126 00000 n -0000106047 00000 n -0000106578 00000 n -0000106314 00000 n -0000106468 00000 n -0000106388 00000 n -0000106920 00000 n -0000106656 00000 n -0000106810 00000 n -0000106730 00000 n -0000110954 00000 n -0000107218 00000 n -0000107372 00000 n -0000107292 00000 n -0000110836 00000 n -0000108898 00000 n -0000107482 00000 n -0000107636 00000 n -0000107556 00000 n -0000108772 00000 n -0000108010 00000 n -0000107746 00000 n -0000107900 00000 n -0000107820 00000 n -0000108352 00000 n -0000108088 00000 n -0000108242 00000 n -0000108162 00000 n -0000108694 00000 n -0000108430 00000 n -0000108584 00000 n -0000108504 00000 n -0000110750 00000 n -0000108984 00000 n -0000109138 00000 n -0000109058 00000 n -0000110616 00000 n -0000109512 00000 n -0000109248 00000 n -0000109402 00000 n -0000109322 00000 n -0000109854 00000 n -0000109590 00000 n -0000109744 00000 n -0000109664 00000 n -0000110196 00000 n -0000109932 00000 n -0000110086 00000 n -0000110006 00000 n -0000110538 00000 n -0000110274 00000 n -0000110428 00000 n -0000110348 00000 n -0000115978 00000 n -0000111040 00000 n -0000111194 00000 n -0000111114 00000 n -0000115860 00000 n -0000112758 00000 n -0000111304 00000 n -0000111458 00000 n -0000111378 00000 n -0000112632 00000 n -0000111832 00000 n -0000111568 00000 n -0000111722 00000 n -0000111642 00000 n -0000112174 00000 n -0000111910 00000 n -0000112064 00000 n -0000111984 00000 n -0000112554 00000 n -0000112252 00000 n -0000112406 00000 n -0000112326 00000 n -0000115774 00000 n -0000112844 00000 n -0000112998 00000 n -0000112918 00000 n -0000115616 00000 n +0000101769 00000 n +0000230011 00000 n +0000012008 00000 n +0000012223 00000 n +0000012486 00000 n +0000012749 00000 n +0000013034 00000 n +0000013317 00000 n +0000013606 00000 n +0000013894 00000 n +0000014050 00000 n +0000014243 00000 n +0000014424 00000 n +0000014643 00000 n +0000014882 00000 n +0000015121 00000 n +0000015267 00000 n +0000015442 00000 n +0000015616 00000 n +0000015771 00000 n +0000015964 00000 n +0000016145 00000 n +0000016351 00000 n +0000016497 00000 n +0000016686 00000 n +0000016884 00000 n +0000102206 00000 n +0000021192 00000 n +0000020823 00000 n +0000242506 00000 n +0000028802 00000 n +0000102499 00000 n +0000032601 00000 n +0000032642 00000 n +0000032683 00000 n +0000102791 00000 n +0000034926 00000 n +0000050522 00000 n +0000103084 00000 n +0000053361 00000 n +0000059607 00000 n +0000103401 00000 n +0000062072 00000 n +0000103679 00000 n +0000066673 00000 n +0000073688 00000 n +0000103996 00000 n +0000077434 00000 n +0000087896 00000 n +0000093808 00000 n +0000104302 00000 n +0000096713 00000 n +0000104572 00000 n +0000099459 00000 n +0000104866 00000 n +0000104988 00000 n +0000105078 00000 n +0000105146 00000 n +0000178360 00000 n +0000172977 00000 n +0000110241 00000 n +0000110162 00000 n +0000132517 00000 n +0000132431 00000 n +0000110323 00000 n +0000110475 00000 n +0000110396 00000 n +0000132281 00000 n +0000112342 00000 n +0000110584 00000 n +0000110736 00000 n +0000110657 00000 n +0000112208 00000 n +0000111106 00000 n +0000110845 00000 n +0000110997 00000 n +0000110918 00000 n +0000111446 00000 n +0000111184 00000 n +0000111336 00000 n +0000111257 00000 n +0000111788 00000 n +0000111524 00000 n +0000111678 00000 n +0000111598 00000 n +0000112130 00000 n +0000111866 00000 n +0000112020 00000 n +0000111940 00000 n +0000116164 00000 n +0000112428 00000 n +0000112582 00000 n +0000112502 00000 n +0000116046 00000 n +0000114108 00000 n +0000112692 00000 n +0000112846 00000 n +0000112766 00000 n +0000113982 00000 n +0000113220 00000 n +0000112956 00000 n +0000113110 00000 n +0000113030 00000 n +0000113562 00000 n +0000113298 00000 n +0000113452 00000 n 0000113372 00000 n -0000113108 00000 n -0000113262 00000 n -0000113182 00000 n +0000113904 00000 n +0000113640 00000 n +0000113794 00000 n 0000113714 00000 n -0000113450 00000 n -0000113604 00000 n -0000113524 00000 n -0000114056 00000 n -0000113792 00000 n -0000113946 00000 n -0000113866 00000 n -0000114436 00000 n -0000114134 00000 n -0000114288 00000 n -0000114208 00000 n -0000114778 00000 n -0000114514 00000 n -0000114668 00000 n -0000114588 00000 n -0000115158 00000 n -0000114856 00000 n -0000115010 00000 n -0000114930 00000 n -0000115538 00000 n -0000115236 00000 n -0000115390 00000 n -0000115310 00000 n -0000121009 00000 n -0000116064 00000 n -0000116218 00000 n -0000116138 00000 n -0000120891 00000 n -0000118132 00000 n -0000116328 00000 n -0000116482 00000 n -0000116402 00000 n -0000117998 00000 n -0000116856 00000 n -0000116592 00000 n -0000116746 00000 n -0000116666 00000 n -0000117198 00000 n -0000116934 00000 n -0000117088 00000 n -0000117008 00000 n -0000117540 00000 n -0000117276 00000 n -0000117430 00000 n -0000117350 00000 n -0000117920 00000 n -0000117618 00000 n -0000117772 00000 n -0000117692 00000 n -0000120805 00000 n -0000118218 00000 n -0000118372 00000 n -0000118292 00000 n -0000120655 00000 n -0000118746 00000 n -0000118482 00000 n -0000118636 00000 n -0000118556 00000 n -0000119088 00000 n -0000118824 00000 n -0000118978 00000 n -0000118898 00000 n -0000119431 00000 n -0000119166 00000 n -0000119320 00000 n -0000119240 00000 n -0000119813 00000 n -0000119509 00000 n -0000119663 00000 n -0000119583 00000 n -0000120195 00000 n -0000119891 00000 n -0000120045 00000 n -0000119965 00000 n -0000120577 00000 n -0000120273 00000 n -0000120427 00000 n -0000120347 00000 n -0000124192 00000 n -0000121095 00000 n -0000121249 00000 n -0000121169 00000 n -0000124074 00000 n -0000122827 00000 n -0000121360 00000 n -0000121516 00000 n -0000121435 00000 n -0000122701 00000 n -0000121894 00000 n -0000121627 00000 n -0000121783 00000 n -0000121702 00000 n -0000122239 00000 n -0000121972 00000 n -0000122128 00000 n -0000122047 00000 n -0000122623 00000 n -0000122317 00000 n -0000122473 00000 n -0000122392 00000 n -0000123988 00000 n -0000122913 00000 n -0000123069 00000 n -0000122988 00000 n -0000123870 00000 n -0000123447 00000 n -0000123180 00000 n -0000123336 00000 n -0000123255 00000 n -0000123792 00000 n -0000123525 00000 n -0000123681 00000 n -0000123600 00000 n -0000126985 00000 n -0000124278 00000 n -0000124434 00000 n -0000124353 00000 n -0000126867 00000 n -0000125620 00000 n -0000124545 00000 n -0000124701 00000 n -0000124620 00000 n -0000125502 00000 n -0000125079 00000 n -0000124812 00000 n -0000124968 00000 n -0000124887 00000 n -0000125424 00000 n -0000125157 00000 n -0000125313 00000 n -0000125232 00000 n -0000126781 00000 n -0000125706 00000 n -0000125862 00000 n -0000125781 00000 n -0000126663 00000 n -0000126240 00000 n -0000125973 00000 n -0000126129 00000 n -0000126048 00000 n -0000126585 00000 n -0000126318 00000 n -0000126474 00000 n -0000126393 00000 n -0000127494 00000 n -0000127413 00000 n -0000127643 00000 n -0000127562 00000 n -0000127792 00000 n -0000127711 00000 n -0000127940 00000 n -0000127859 00000 n -0000128242 00000 n -0000128089 00000 n -0000128008 00000 n -0000128161 00000 n -0000128400 00000 n -0000128319 00000 n -0000128783 00000 n -0000128468 00000 n -0000128630 00000 n -0000128549 00000 n -0000128702 00000 n -0000129658 00000 n -0000129177 00000 n -0000128868 00000 n -0000129024 00000 n -0000128943 00000 n -0000129096 00000 n -0000129572 00000 n -0000129263 00000 n -0000129419 00000 n -0000129338 00000 n -0000129491 00000 n -0000129854 00000 n -0000129774 00000 n -0000130243 00000 n -0000129921 00000 n -0000130015 00000 n -0000130175 00000 n -0000130095 00000 n -0000130408 00000 n -0000130328 00000 n -0000130708 00000 n -0000130556 00000 n -0000130476 00000 n -0000130628 00000 n -0000130865 00000 n -0000130785 00000 n -0000131013 00000 n -0000130933 00000 n -0000131161 00000 n -0000131081 00000 n -0000131310 00000 n -0000131229 00000 n -0000134031 00000 n -0000131767 00000 n -0000131377 00000 n -0000131452 00000 n -0000131614 00000 n -0000131533 00000 n -0000131686 00000 n -0000132251 00000 n -0000131861 00000 n -0000131936 00000 n -0000132098 00000 n -0000132017 00000 n -0000132170 00000 n -0000132735 00000 n -0000132345 00000 n -0000132420 00000 n -0000132582 00000 n -0000132501 00000 n -0000132654 00000 n -0000133219 00000 n -0000132829 00000 n -0000132904 00000 n -0000133066 00000 n -0000132985 00000 n -0000133138 00000 n -0000133703 00000 n -0000133313 00000 n -0000133388 00000 n -0000133550 00000 n -0000133469 00000 n -0000133622 00000 n -0000133953 00000 n -0000133797 00000 n -0000133872 00000 n -0000134260 00000 n -0000134179 00000 n -0000134408 00000 n -0000134327 00000 n -0000134593 00000 n -0000134476 00000 n -0000134740 00000 n -0000134660 00000 n -0000134887 00000 n -0000134807 00000 n -0000135035 00000 n -0000134955 00000 n -0000135411 00000 n -0000135334 00000 n -0000135182 00000 n -0000135102 00000 n -0000135254 00000 n -0000135582 00000 n -0000135502 00000 n -0000135730 00000 n -0000135650 00000 n -0000136338 00000 n -0000135798 00000 n -0000135959 00000 n -0000135878 00000 n -0000136027 00000 n -0000136189 00000 n -0000136108 00000 n -0000136257 00000 n +0000115960 00000 n +0000114194 00000 n +0000114348 00000 n +0000114268 00000 n +0000115826 00000 n +0000114722 00000 n +0000114458 00000 n +0000114612 00000 n +0000114532 00000 n +0000115064 00000 n +0000114800 00000 n +0000114954 00000 n +0000114874 00000 n +0000115406 00000 n +0000115142 00000 n +0000115296 00000 n +0000115216 00000 n +0000115748 00000 n +0000115484 00000 n +0000115638 00000 n +0000115558 00000 n +0000121188 00000 n +0000116250 00000 n +0000116404 00000 n +0000116324 00000 n +0000121070 00000 n +0000117968 00000 n +0000116514 00000 n +0000116668 00000 n +0000116588 00000 n +0000117842 00000 n +0000117042 00000 n +0000116778 00000 n +0000116932 00000 n +0000116852 00000 n +0000117384 00000 n +0000117120 00000 n +0000117274 00000 n +0000117194 00000 n +0000117764 00000 n +0000117462 00000 n +0000117616 00000 n +0000117536 00000 n +0000120984 00000 n +0000118054 00000 n +0000118208 00000 n +0000118128 00000 n +0000120826 00000 n +0000118582 00000 n +0000118318 00000 n +0000118472 00000 n +0000118392 00000 n +0000118924 00000 n +0000118660 00000 n +0000118814 00000 n +0000118734 00000 n +0000119266 00000 n +0000119002 00000 n +0000119156 00000 n +0000119076 00000 n +0000119646 00000 n +0000119344 00000 n +0000119498 00000 n +0000119418 00000 n +0000119988 00000 n +0000119724 00000 n +0000119878 00000 n +0000119798 00000 n +0000120368 00000 n +0000120066 00000 n +0000120220 00000 n +0000120140 00000 n +0000120748 00000 n +0000120446 00000 n +0000120600 00000 n +0000120520 00000 n +0000126219 00000 n +0000121274 00000 n +0000121428 00000 n +0000121348 00000 n +0000126101 00000 n +0000123342 00000 n +0000121538 00000 n +0000121692 00000 n +0000121612 00000 n +0000123208 00000 n +0000122066 00000 n +0000121802 00000 n +0000121956 00000 n +0000121876 00000 n +0000122408 00000 n +0000122144 00000 n +0000122298 00000 n +0000122218 00000 n +0000122750 00000 n +0000122486 00000 n +0000122640 00000 n +0000122560 00000 n +0000123130 00000 n +0000122828 00000 n +0000122982 00000 n +0000122902 00000 n +0000126015 00000 n +0000123428 00000 n +0000123582 00000 n +0000123502 00000 n +0000125865 00000 n +0000123956 00000 n +0000123692 00000 n +0000123846 00000 n +0000123766 00000 n +0000124298 00000 n +0000124034 00000 n +0000124188 00000 n +0000124108 00000 n +0000124641 00000 n +0000124376 00000 n +0000124530 00000 n +0000124450 00000 n +0000125023 00000 n +0000124719 00000 n +0000124873 00000 n +0000124793 00000 n +0000125405 00000 n +0000125101 00000 n +0000125255 00000 n +0000125175 00000 n +0000125787 00000 n +0000125483 00000 n +0000125637 00000 n +0000125557 00000 n +0000129402 00000 n +0000126305 00000 n +0000126459 00000 n +0000126379 00000 n +0000129284 00000 n +0000128037 00000 n +0000126570 00000 n +0000126726 00000 n +0000126645 00000 n +0000127911 00000 n +0000127104 00000 n +0000126837 00000 n +0000126993 00000 n +0000126912 00000 n +0000127449 00000 n +0000127182 00000 n +0000127338 00000 n +0000127257 00000 n +0000127833 00000 n +0000127527 00000 n +0000127683 00000 n +0000127602 00000 n +0000129198 00000 n +0000128123 00000 n +0000128279 00000 n +0000128198 00000 n +0000129080 00000 n +0000128657 00000 n +0000128390 00000 n +0000128546 00000 n +0000128465 00000 n +0000129002 00000 n +0000128735 00000 n +0000128891 00000 n +0000128810 00000 n +0000132195 00000 n +0000129488 00000 n +0000129644 00000 n +0000129563 00000 n +0000132077 00000 n +0000130830 00000 n +0000129755 00000 n +0000129911 00000 n +0000129830 00000 n +0000130712 00000 n +0000130289 00000 n +0000130022 00000 n +0000130178 00000 n +0000130097 00000 n +0000130634 00000 n +0000130367 00000 n +0000130523 00000 n +0000130442 00000 n +0000131991 00000 n +0000130916 00000 n +0000131072 00000 n +0000130991 00000 n +0000131873 00000 n +0000131450 00000 n +0000131183 00000 n +0000131339 00000 n +0000131258 00000 n +0000131795 00000 n +0000131528 00000 n +0000131684 00000 n +0000131603 00000 n +0000132704 00000 n +0000132623 00000 n +0000132853 00000 n +0000132772 00000 n +0000133002 00000 n +0000132921 00000 n +0000133150 00000 n +0000133069 00000 n +0000133452 00000 n +0000133299 00000 n +0000133218 00000 n +0000133371 00000 n +0000133610 00000 n +0000133529 00000 n +0000133993 00000 n +0000133678 00000 n +0000133840 00000 n +0000133759 00000 n +0000133912 00000 n +0000134868 00000 n +0000134387 00000 n +0000134078 00000 n +0000134234 00000 n +0000134153 00000 n +0000134306 00000 n +0000134782 00000 n +0000134473 00000 n +0000134629 00000 n +0000134548 00000 n +0000134701 00000 n +0000135064 00000 n +0000134984 00000 n +0000135453 00000 n +0000135131 00000 n +0000135225 00000 n +0000135385 00000 n +0000135305 00000 n +0000135618 00000 n +0000135538 00000 n +0000135918 00000 n +0000135766 00000 n +0000135686 00000 n +0000135838 00000 n +0000136075 00000 n +0000135995 00000 n +0000136223 00000 n +0000136143 00000 n +0000136371 00000 n +0000136291 00000 n 0000136520 00000 n 0000136439 00000 n -0000137438 00000 n -0000136588 00000 n -0000136750 00000 n -0000136669 00000 n -0000136818 00000 n -0000136980 00000 n -0000136899 00000 n -0000137048 00000 n -0000137129 00000 n -0000137370 00000 n -0000137290 00000 n -0000137635 00000 n +0000139241 00000 n +0000136977 00000 n +0000136587 00000 n +0000136662 00000 n +0000136824 00000 n +0000136743 00000 n +0000136896 00000 n +0000137461 00000 n +0000137071 00000 n +0000137146 00000 n +0000137308 00000 n +0000137227 00000 n +0000137380 00000 n +0000137945 00000 n 0000137555 00000 n -0000138239 00000 n -0000137703 00000 n -0000137863 00000 n -0000137783 00000 n -0000137931 00000 n -0000138091 00000 n -0000138011 00000 n -0000138159 00000 n -0000138420 00000 n -0000138340 00000 n -0000139028 00000 n -0000138488 00000 n -0000138649 00000 n -0000138568 00000 n -0000138717 00000 n -0000138879 00000 n -0000138798 00000 n -0000138947 00000 n -0000139210 00000 n -0000139129 00000 n -0000139359 00000 n -0000139278 00000 n -0000139508 00000 n -0000139427 00000 n -0000139657 00000 n -0000139576 00000 n -0000141037 00000 n -0000139952 00000 n -0000139724 00000 n -0000139880 00000 n -0000139799 00000 n -0000140339 00000 n -0000140030 00000 n -0000140186 00000 n -0000140105 00000 n -0000140258 00000 n -0000140653 00000 n -0000140425 00000 n -0000140581 00000 n -0000140500 00000 n -0000140959 00000 n -0000140731 00000 n -0000140887 00000 n -0000140806 00000 n -0000141253 00000 n -0000141172 00000 n -0000141568 00000 n -0000141320 00000 n -0000141500 00000 n -0000141420 00000 n -0000141725 00000 n -0000141645 00000 n -0000141873 00000 n -0000141793 00000 n -0000142020 00000 n -0000141940 00000 n -0000142167 00000 n -0000142087 00000 n -0000142544 00000 n -0000142467 00000 n -0000142315 00000 n -0000142235 00000 n -0000142387 00000 n -0000142715 00000 n -0000142635 00000 n -0000142864 00000 n -0000142783 00000 n -0000143703 00000 n -0000142932 00000 n -0000143094 00000 n -0000143013 00000 n -0000143162 00000 n -0000143324 00000 n -0000143243 00000 n -0000143392 00000 n -0000143554 00000 n -0000143473 00000 n -0000143622 00000 n -0000143901 00000 n -0000143820 00000 n -0000144280 00000 n -0000143969 00000 n -0000144131 00000 n -0000144050 00000 n -0000144199 00000 n -0000144446 00000 n -0000144365 00000 n -0000144825 00000 n -0000144514 00000 n -0000144676 00000 n -0000144595 00000 n -0000144744 00000 n -0000144991 00000 n -0000144910 00000 n -0000145140 00000 n -0000145059 00000 n -0000145288 00000 n -0000145208 00000 n -0000145436 00000 n -0000145356 00000 n -0000145584 00000 n -0000145504 00000 n -0000145732 00000 n -0000145652 00000 n -0000145880 00000 n -0000145800 00000 n +0000137630 00000 n +0000137792 00000 n +0000137711 00000 n +0000137864 00000 n +0000138429 00000 n +0000138039 00000 n +0000138114 00000 n +0000138276 00000 n +0000138195 00000 n +0000138348 00000 n +0000138913 00000 n +0000138523 00000 n +0000138598 00000 n +0000138760 00000 n +0000138679 00000 n +0000138832 00000 n +0000139163 00000 n +0000139007 00000 n +0000139082 00000 n +0000139470 00000 n +0000139389 00000 n +0000139618 00000 n +0000139537 00000 n +0000139803 00000 n +0000139686 00000 n +0000139950 00000 n +0000139870 00000 n +0000140097 00000 n +0000140017 00000 n +0000140245 00000 n +0000140165 00000 n +0000140621 00000 n +0000140544 00000 n +0000140392 00000 n +0000140312 00000 n +0000140464 00000 n +0000140792 00000 n +0000140712 00000 n +0000140940 00000 n +0000140860 00000 n +0000141548 00000 n +0000141008 00000 n +0000141169 00000 n +0000141088 00000 n +0000141237 00000 n +0000141399 00000 n +0000141318 00000 n +0000141467 00000 n +0000141730 00000 n +0000141649 00000 n +0000142648 00000 n +0000141798 00000 n +0000141960 00000 n +0000141879 00000 n +0000142028 00000 n +0000142190 00000 n +0000142109 00000 n +0000142258 00000 n +0000142339 00000 n +0000142580 00000 n +0000142500 00000 n +0000142845 00000 n +0000142765 00000 n +0000143449 00000 n +0000142913 00000 n +0000143073 00000 n +0000142993 00000 n +0000143141 00000 n +0000143301 00000 n +0000143221 00000 n +0000143369 00000 n +0000143630 00000 n +0000143550 00000 n +0000144238 00000 n +0000143698 00000 n +0000143859 00000 n +0000143778 00000 n +0000143927 00000 n +0000144089 00000 n +0000144008 00000 n +0000144157 00000 n +0000144420 00000 n +0000144339 00000 n +0000145658 00000 n +0000144644 00000 n +0000144488 00000 n +0000144563 00000 n +0000144878 00000 n +0000144722 00000 n +0000144797 00000 n +0000145112 00000 n +0000144956 00000 n +0000145031 00000 n +0000145346 00000 n +0000145190 00000 n +0000145265 00000 n +0000145580 00000 n +0000145424 00000 n +0000145499 00000 n +0000145879 00000 n +0000145798 00000 n 0000146028 00000 n -0000145948 00000 n -0000147276 00000 n -0000146401 00000 n -0000146095 00000 n -0000146249 00000 n -0000146169 00000 n -0000146321 00000 n -0000146795 00000 n -0000146487 00000 n -0000146642 00000 n -0000146561 00000 n -0000146714 00000 n -0000147190 00000 n -0000146881 00000 n -0000147037 00000 n -0000146956 00000 n -0000147109 00000 n -0000147730 00000 n -0000147400 00000 n -0000147481 00000 n -0000147662 00000 n -0000147581 00000 n -0000147896 00000 n -0000147815 00000 n -0000148045 00000 n -0000147964 00000 n -0000148902 00000 n -0000148421 00000 n -0000148112 00000 n -0000148268 00000 n -0000148187 00000 n -0000148340 00000 n -0000148816 00000 n -0000148507 00000 n -0000148663 00000 n -0000148582 00000 n -0000148735 00000 n -0000149723 00000 n -0000149102 00000 n -0000149021 00000 n -0000149174 00000 n -0000149336 00000 n -0000149255 00000 n -0000149408 00000 n -0000149570 00000 n -0000149489 00000 n -0000149642 00000 n -0000149913 00000 n -0000149832 00000 n -0000150062 00000 n -0000149981 00000 n -0000150209 00000 n -0000150129 00000 n -0000150356 00000 n -0000150276 00000 n -0000150733 00000 n -0000150656 00000 n -0000150504 00000 n -0000150424 00000 n -0000150576 00000 n -0000150904 00000 n -0000150824 00000 n -0000151052 00000 n -0000150972 00000 n -0000151428 00000 n -0000151120 00000 n -0000151280 00000 n -0000151200 00000 n -0000151348 00000 n -0000153343 00000 n -0000151822 00000 n -0000151513 00000 n -0000151669 00000 n -0000151588 00000 n -0000151741 00000 n -0000152217 00000 n -0000151908 00000 n -0000152064 00000 n -0000151983 00000 n -0000152136 00000 n -0000152846 00000 n -0000152303 00000 n -0000152459 00000 n -0000152378 00000 n -0000152531 00000 n -0000152693 00000 n -0000152612 00000 n -0000152765 00000 n -0000153257 00000 n -0000152948 00000 n -0000153104 00000 n -0000153023 00000 n -0000153176 00000 n -0000153813 00000 n -0000153475 00000 n -0000153583 00000 n -0000153745 00000 n -0000153664 00000 n -0000154236 00000 n -0000153898 00000 n -0000154006 00000 n -0000154168 00000 n -0000154087 00000 n -0000154401 00000 n -0000154321 00000 n -0000154549 00000 n -0000154469 00000 n -0000154697 00000 n -0000154617 00000 n -0000154845 00000 n -0000154765 00000 n -0000154993 00000 n -0000154913 00000 n -0000155141 00000 n -0000155061 00000 n -0000155289 00000 n -0000155209 00000 n -0000155437 00000 n -0000155357 00000 n -0000155585 00000 n -0000155505 00000 n -0000155966 00000 n -0000155652 00000 n -0000155813 00000 n -0000155732 00000 n -0000155885 00000 n -0000156132 00000 n -0000156051 00000 n -0000156281 00000 n -0000156200 00000 n -0000156663 00000 n -0000156348 00000 n -0000156510 00000 n -0000156429 00000 n -0000156582 00000 n -0000156829 00000 n -0000156748 00000 n -0000157446 00000 n -0000156897 00000 n -0000157059 00000 n -0000156978 00000 n -0000157131 00000 n -0000157293 00000 n -0000157212 00000 n -0000157365 00000 n -0000157862 00000 n -0000157547 00000 n -0000157709 00000 n -0000157628 00000 n -0000157781 00000 n -0000158028 00000 n -0000157947 00000 n -0000158177 00000 n -0000158096 00000 n -0000158556 00000 n -0000158245 00000 n -0000158407 00000 n -0000158326 00000 n -0000158475 00000 n -0000158722 00000 n -0000158641 00000 n -0000159101 00000 n -0000158790 00000 n -0000158952 00000 n -0000158871 00000 n -0000159020 00000 n -0000159267 00000 n -0000159186 00000 n -0000159416 00000 n -0000159335 00000 n -0000159566 00000 n -0000159484 00000 n -0000159716 00000 n -0000159634 00000 n -0000159865 00000 n -0000159783 00000 n -0000160014 00000 n -0000159932 00000 n -0000160395 00000 n -0000160318 00000 n -0000160164 00000 n -0000160082 00000 n +0000145947 00000 n +0000146177 00000 n +0000146096 00000 n +0000147557 00000 n +0000146472 00000 n +0000146244 00000 n +0000146400 00000 n +0000146319 00000 n +0000146859 00000 n +0000146550 00000 n +0000146706 00000 n +0000146625 00000 n +0000146778 00000 n +0000147173 00000 n +0000146945 00000 n +0000147101 00000 n +0000147020 00000 n +0000147479 00000 n +0000147251 00000 n +0000147407 00000 n +0000147326 00000 n +0000147772 00000 n +0000147692 00000 n +0000148087 00000 n +0000147839 00000 n +0000148019 00000 n +0000147939 00000 n +0000148244 00000 n +0000148164 00000 n +0000148392 00000 n +0000148312 00000 n +0000148539 00000 n +0000148459 00000 n +0000148686 00000 n +0000148606 00000 n +0000149063 00000 n +0000148986 00000 n +0000148834 00000 n +0000148754 00000 n +0000148906 00000 n +0000149235 00000 n +0000149154 00000 n +0000149384 00000 n +0000149303 00000 n +0000150223 00000 n +0000149452 00000 n +0000149614 00000 n +0000149533 00000 n +0000149682 00000 n +0000149844 00000 n +0000149763 00000 n +0000149912 00000 n +0000150074 00000 n +0000149993 00000 n +0000150142 00000 n +0000150421 00000 n +0000150340 00000 n +0000150800 00000 n +0000150489 00000 n +0000150651 00000 n +0000150570 00000 n +0000150719 00000 n +0000150966 00000 n +0000150885 00000 n +0000151345 00000 n +0000151034 00000 n +0000151196 00000 n +0000151115 00000 n +0000151264 00000 n +0000151510 00000 n +0000151430 00000 n +0000151658 00000 n +0000151578 00000 n +0000151806 00000 n +0000151726 00000 n +0000151954 00000 n +0000151874 00000 n +0000152102 00000 n +0000152022 00000 n +0000152250 00000 n +0000152170 00000 n +0000153851 00000 n +0000152471 00000 n +0000152317 00000 n +0000152391 00000 n +0000152703 00000 n +0000152549 00000 n +0000152623 00000 n +0000153765 00000 n +0000152781 00000 n +0000152856 00000 n +0000153639 00000 n +0000153093 00000 n +0000152937 00000 n +0000153012 00000 n +0000153327 00000 n +0000153171 00000 n +0000153246 00000 n +0000153561 00000 n +0000153405 00000 n +0000153480 00000 n +0000154293 00000 n +0000153978 00000 n +0000154140 00000 n +0000154059 00000 n +0000154212 00000 n +0000154693 00000 n +0000154378 00000 n +0000154540 00000 n +0000154459 00000 n +0000154612 00000 n +0000155319 00000 n +0000154778 00000 n +0000154940 00000 n +0000154859 00000 n +0000155008 00000 n +0000155170 00000 n +0000155089 00000 n +0000155238 00000 n +0000155888 00000 n +0000155576 00000 n +0000155420 00000 n +0000155495 00000 n +0000155810 00000 n +0000155654 00000 n +0000155729 00000 n +0000156319 00000 n +0000156004 00000 n +0000156166 00000 n +0000156085 00000 n +0000156238 00000 n +0000156872 00000 n +0000156560 00000 n +0000156404 00000 n +0000156479 00000 n +0000156794 00000 n +0000156638 00000 n +0000156713 00000 n +0000157069 00000 n +0000156988 00000 n +0000157218 00000 n +0000157137 00000 n +0000157367 00000 n +0000157286 00000 n +0000158610 00000 n +0000157740 00000 n +0000157434 00000 n +0000157588 00000 n +0000157508 00000 n +0000157660 00000 n +0000158132 00000 n +0000157826 00000 n +0000157980 00000 n +0000157900 00000 n +0000158052 00000 n +0000158524 00000 n +0000158218 00000 n +0000158372 00000 n +0000158292 00000 n +0000158444 00000 n +0000159064 00000 n +0000158734 00000 n +0000158815 00000 n +0000158996 00000 n +0000158915 00000 n +0000159230 00000 n +0000159149 00000 n +0000159379 00000 n +0000159298 00000 n 0000160236 00000 n -0000160569 00000 n -0000160487 00000 n -0000160719 00000 n -0000160637 00000 n -0000161333 00000 n -0000160787 00000 n -0000160951 00000 n -0000160869 00000 n -0000161019 00000 n -0000161183 00000 n -0000161101 00000 n -0000161251 00000 n -0000161516 00000 n -0000161434 00000 n -0000162554 00000 n -0000163197 00000 n -0000163648 00000 n -0000163955 00000 n -0000164134 00000 n -0000164377 00000 n -0000164620 00000 n -0000164911 00000 n -0000165170 00000 n -0000165413 00000 n -0000165624 00000 n -0000166593 00000 n -0000166810 00000 n -0000185103 00000 n -0000185346 00000 n -0000186360 00000 n -0000186897 00000 n -0000201510 00000 n -0000201747 00000 n -0000202072 00000 n -0000202557 00000 n -0000216312 00000 n -0000216560 00000 n -0000217492 00000 n -0000218053 00000 n -0000228856 00000 n -0000229111 00000 n -0000229896 00000 n +0000159755 00000 n +0000159446 00000 n +0000159602 00000 n +0000159521 00000 n +0000159674 00000 n +0000160150 00000 n +0000159841 00000 n +0000159997 00000 n +0000159916 00000 n +0000160069 00000 n +0000161057 00000 n +0000160436 00000 n +0000160355 00000 n +0000160508 00000 n +0000160670 00000 n +0000160589 00000 n +0000160742 00000 n +0000160904 00000 n +0000160823 00000 n +0000160976 00000 n +0000161247 00000 n +0000161166 00000 n +0000161396 00000 n +0000161315 00000 n +0000161544 00000 n +0000161463 00000 n +0000161692 00000 n +0000161611 00000 n +0000162071 00000 n +0000161994 00000 n +0000161841 00000 n +0000161760 00000 n +0000161913 00000 n +0000162243 00000 n +0000162162 00000 n +0000162392 00000 n +0000162311 00000 n +0000162768 00000 n +0000162460 00000 n +0000162620 00000 n +0000162540 00000 n +0000162688 00000 n +0000164676 00000 n +0000163159 00000 n +0000162853 00000 n +0000163007 00000 n +0000162927 00000 n +0000163079 00000 n +0000163551 00000 n +0000163245 00000 n +0000163399 00000 n +0000163319 00000 n +0000163471 00000 n +0000164179 00000 n +0000163637 00000 n +0000163792 00000 n +0000163711 00000 n +0000163864 00000 n +0000164026 00000 n +0000163945 00000 n +0000164098 00000 n +0000164590 00000 n +0000164281 00000 n +0000164437 00000 n +0000164356 00000 n +0000164509 00000 n +0000165146 00000 n +0000164808 00000 n +0000164916 00000 n +0000165078 00000 n +0000164997 00000 n +0000165569 00000 n +0000165231 00000 n +0000165339 00000 n +0000165501 00000 n +0000165420 00000 n +0000165735 00000 n +0000165654 00000 n +0000165884 00000 n +0000165803 00000 n +0000166033 00000 n +0000165952 00000 n +0000166182 00000 n +0000166101 00000 n +0000166331 00000 n +0000166250 00000 n +0000166517 00000 n +0000166399 00000 n +0000166666 00000 n +0000166585 00000 n +0000166815 00000 n +0000166734 00000 n +0000166964 00000 n +0000166883 00000 n +0000167346 00000 n +0000167031 00000 n +0000167193 00000 n +0000167112 00000 n +0000167265 00000 n +0000167512 00000 n +0000167431 00000 n +0000167661 00000 n +0000167580 00000 n +0000168045 00000 n +0000167728 00000 n +0000167891 00000 n +0000167809 00000 n +0000167963 00000 n +0000168212 00000 n +0000168130 00000 n +0000168834 00000 n +0000168280 00000 n +0000168444 00000 n +0000168362 00000 n +0000168516 00000 n +0000168680 00000 n +0000168598 00000 n +0000168752 00000 n +0000169253 00000 n +0000168935 00000 n +0000169099 00000 n +0000169017 00000 n +0000169171 00000 n +0000169420 00000 n +0000169338 00000 n +0000169570 00000 n +0000169488 00000 n +0000169952 00000 n +0000169638 00000 n +0000169802 00000 n +0000169720 00000 n +0000169870 00000 n +0000170119 00000 n +0000170037 00000 n +0000170501 00000 n +0000170187 00000 n +0000170351 00000 n +0000170269 00000 n +0000170419 00000 n +0000170668 00000 n +0000170586 00000 n +0000170818 00000 n +0000170736 00000 n +0000170968 00000 n +0000170886 00000 n +0000171117 00000 n +0000171036 00000 n +0000171265 00000 n +0000171184 00000 n +0000171413 00000 n +0000171332 00000 n +0000171792 00000 n +0000171715 00000 n +0000171562 00000 n +0000171481 00000 n +0000171634 00000 n +0000171965 00000 n +0000171884 00000 n +0000172114 00000 n +0000172033 00000 n +0000172726 00000 n +0000172182 00000 n +0000172344 00000 n +0000172263 00000 n +0000172412 00000 n +0000172576 00000 n +0000172494 00000 n +0000172644 00000 n +0000172909 00000 n +0000172827 00000 n +0000174019 00000 n +0000174662 00000 n +0000175113 00000 n +0000175420 00000 n +0000175599 00000 n +0000175914 00000 n +0000176149 00000 n +0000176512 00000 n +0000176811 00000 n +0000177062 00000 n +0000177345 00000 n +0000177476 00000 n +0000178456 00000 n +0000178673 00000 n +0000197075 00000 n +0000197318 00000 n +0000198344 00000 n +0000198886 00000 n +0000213499 00000 n +0000213736 00000 n +0000214061 00000 n +0000214546 00000 n +0000228403 00000 n +0000228651 00000 n +0000229595 00000 n +0000230158 00000 n +0000241039 00000 n +0000241294 00000 n +0000242091 00000 n trailer -<> startxref -230458 +242655 %%EOF diff --git a/doc/kommandos.md b/doc/kommandos.md index 4da84b0..a7bd845 100644 --- a/doc/kommandos.md +++ b/doc/kommandos.md @@ -48,7 +48,11 @@ Gross-/Kleinschreibung spielt an der Kommandozeile keine Rolle. | `StandardVarioFoerderer3D` | Standardtyp aus einer gewaehlten 3D-Linie | | `EtageVarioFoerderer` | Etagentyp (AS/ES 30 Grad), Werte per DCL-Dialog | | `EtageVarioFoerderer3D` | Etagentyp aus einer gewaehlten 3D-Linie | -| `LinienzugVarioFoerderer` | Linienzug, fragt Modus 1/2/3 ab | +| `LinienzugVarioFoerdererManuell` | Streckengruppe, Modus 1 (manuelle Eingabe, Punkte klicken) | +| `LinienzugVarioFoerdererZielhoehe` | Streckengruppe, Modus 2 (3D-Objekte + Ziel-Hoehe, Randwert-Solver) | +| `LinienzugVarioFoerdererStueckweise` | Streckengruppe, Modus 3 (3D-Objekte stueckweise, in Arbeit) | +| `QcLinieMitGf` | Streckengruppe Modus 4 (QC-Linie mit GF, automatische Auf-Ab-Berechnung); Menue unter Gefaellestrecke | +| `QcLinieMitGfUForm` | Streckengruppe Modus 5 (QC-Linie mit GF und U-Form); Menue unter Gefaellestrecke | | `VARIOFOERDERER_EDIT` | VF_n-Block editieren (dispatcht per XDATA-Marker auf Standard/Etage/Linienzug); auch per Doppelklick | | `VARIOFOERDERER_NACHRUESTEN` / `VF_NACHRUESTEN` | Altbestand-VF_n-Bloecke ohne `SSG_VF_EDIT`-Marker editierbar machen | | `Vario_Kette_Merge` | Mehrere einzeln gebaute VF_n-Bloecke ab einem Start-Baustein zu einem Gesamt-Block zusammenfuehren | diff --git a/doc/lisp_methods.md b/doc/lisp_methods.md index 5bb2287..72c3163 100644 --- a/doc/lisp_methods.md +++ b/doc/lisp_methods.md @@ -23,7 +23,7 @@ Einheiten: mm und Grad. `hz` = Fahrtrichtung in der XY-Ebene, 0 = +X, | Eckrad | `ILS_Eckrad` | `ils-eckrad-insert` | `ECKRAD_n` | `KreiselInsert.lsp` | | VF Standard | `StandardVarioFoerderer`, `FOERDERANLAGE` | `berechne-standard` + `variofoerderer-einfuegen` + `vf-block-erstellen` | `VF_n` | `vf_standard.lsp`, `vf_core.lsp` | | VF Etage | `EtageVarioFoerderer` | `berechne-etage` + `etage-foerderanlage-einfuegen` + `vf-block-erstellen` | `VF_n` | `vf_etage.lsp`, `vf_core.lsp` | -| VF Linienzug | `LinienzugVarioFoerderer` | `vsp-bau-aus-spec` (Spec) bzw. `vfl-journal-replay-start` + `vf-linienzug-modus` | `VF_n` | `vf_linienzug.lsp`, `vf_spec.lsp` | +| VF Linienzug | `LinienzugVarioFoerdererManuell`/`-Zielhoehe`/`-Stueckweise`, `QcLinieMitGf`/`-UForm` | `vsp-bau-aus-spec` (Spec) bzw. `vfl-journal-replay-start` + `vf-linienzug-modus` | `VF_n` | `vf_linienzug.lsp`, `vf_spec.lsp` | | Gefaellestrecke | `GEFAELLESTRECKE_EINFACH`/`_3DLINIE` | `gf-rebuild` bzw. `gefaellestrecke-einfuegen` | `GF_n` | `Gefaellestrecke.lsp` | | Gefaellestrecke Linienzug | `GEFAELLESTRECKE_LINIENZUG` | - (nur interaktiv; Kern `gf-linienzug-einfuegen` braucht analysierte Segmente) | `GF_n` | `Gefaellestrecke.lsp` | | Separator, Scanner | `ILS_SEPARATOR_INSERT`, `ILS_SCANNER_INSERT` | - (Schleife mit `getpoint`); Kern: `ssg-ils-block-laden` + `_.INSERT` | Einzelblock | `SSG_LIB_Commands.lsp`, `ssg_core.lsp` | diff --git a/lang/de_DE.json b/lang/de_DE.json index 78d3d67..00ff065 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -946,13 +946,11 @@ "vfc-linienzug-modus-1": "\n 1 - Manuelle Eingabe (Punkte klicken)", "vfc-linienzug-modus-2": "\n 2 - 3D-Objekte + Ziel-Hoehe (Randwert-Solver, fertig)", "vfc-linienzug-modus-3": "\n 3 - 3D-Objekte stueckweise (Vorwaerts-Nachbau, in Arbeit)", - "vfc-linienzug-modus-4": "\n 4 - QC Linie mit GF (automatische Auf-Ab-Berechnung)", - "vfc-linienzug-modus-5": "\n 5 - QC Linie mit GF und U-Form", - "prompt-wahl-1-5": "\nIhre Wahl (1/2/3/4/5) [1]: ", + "prompt-wahl-1-3": "\nIhre Wahl (1/2/3) [1]: ", "vfl-qc-uform-nicht-implementiert": "\nFEHLER: 'QC Linie mit GF und U-Form' ist noch nicht implementiert - bitte Option 4 oder einen anderen Modus waehlen.", "vfc-typ-standard-beschreibung": "Standard VarioFoerderer (AS/ES 90 Grad, horizontal versetzt)", "vfc-typ-etage-beschreibung": "Etage VarioFoerderer (AS/ES 30 Grad, direkt uebereinander)", - "vfc-typ-linienzug-beschreibung": "3D-Linienzug (gemischte GF/VF-Kette; Modus 1 manuell / Modus 2 Ziel-Hoehe fertig / Modus 3 stueckweise in Arbeit)", + "vfc-typ-linienzug-beschreibung": "Streckengruppe (gemischte GF/VF-Kette; Modus 1 manuell / Modus 2 Ziel-Hoehe fertig / Modus 3 stueckweise in Arbeit)", "vfs-schritt6-horizontal": "\n\n6/11: Horizontale Zwischenstrecke (0 Grad, L=%1 mm)", "vfs-schritt6-steigung": "\n\n6/11: Steigungsstrecke (%1 Grad, L=%2 mm)", "vfs-schritt6-gefaelle": "\n\n6/11: Gefaellestrecke (%1 Grad, L=%2 mm)", diff --git a/lang/en_GB.json b/lang/en_GB.json index 8af50c3..04ca750 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -946,13 +946,11 @@ "vfc-linienzug-modus-1": "\n 1 - Manual entry (click points)", "vfc-linienzug-modus-2": "\n 2 - 3D objects + target height (boundary-value solver, finished)", "vfc-linienzug-modus-3": "\n 3 - 3D objects step by step (forward reconstruction, work in progress)", - "vfc-linienzug-modus-4": "\n 4 - QC line with GF (automatic up/down calculation)", - "vfc-linienzug-modus-5": "\n 5 - QC line with GF and U-shape", - "prompt-wahl-1-5": "\nYour choice (1/2/3/4/5) [1]: ", + "prompt-wahl-1-3": "\nYour choice (1/2/3) [1]: ", "vfl-qc-uform-nicht-implementiert": "\nERROR: 'QC line with GF and U-shape' is not yet implemented - please choose option 4 or a different mode.", "vfc-typ-standard-beschreibung": "Standard VarioFoerderer (AS/ES 90 degrees, offset horizontally)", "vfc-typ-etage-beschreibung": "Etage VarioFoerderer (AS/ES 30 degrees, directly stacked)", - "vfc-typ-linienzug-beschreibung": "3D line path (mixed GF/VF chain; mode 1 manual / mode 2 target height finished / mode 3 step by step work in progress)", + "vfc-typ-linienzug-beschreibung": "Route group (mixed GF/VF chain; mode 1 manual / mode 2 target height finished / mode 3 step by step work in progress)", "vfs-schritt6-horizontal": "\n\n6/11: Horizontal intermediate section (0 deg, L=%1 mm)", "vfs-schritt6-steigung": "\n\n6/11: Incline section (%1 deg, L=%2 mm)", "vfs-schritt6-gefaelle": "\n\n6/11: Slope section (%1 deg, L=%2 mm)", diff --git a/menu/SSG_LIB.cui b/menu/SSG_LIB.cui index 2bc9c00..db2be1c 100644 --- a/menu/SSG_LIB.cui +++ b/menu/SSG_LIB.cui @@ -92,10 +92,22 @@ ^C^C(ssg-ensure "VarioFoerderer") EtageVarioFoerderer3D - + - 3D-Linienzug - ^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerderer + Werte manuell + ^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererManuell + + + + + aus 3D Linie mit Zielhoehe + ^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererZielhoehe + + + + + 3D Objekte stueckweise (in Arbeit) + ^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererStueckweise @@ -128,6 +140,18 @@ ^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_LINIENZUG + + + QC Linie mit GF (automatische Auf-Ab-Berechnung) + ^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGf + + + + + QC Linie mit GF und U-Form + ^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGfUForm + + 90 @@ -920,12 +944,7 @@ Foerderer - - 3D-Linienzug - - - - + Vario_Kette_Merge @@ -969,6 +988,27 @@ + + Streckengruppe + + Werte manuell + + + + + + aus 3D Linie mit Zielhoehe + + + + + + 3D Objekte stueckweise (in Arbeit) + + + + + Gefaellestrecke @@ -989,6 +1029,18 @@ + + QC Linie mit GF (automatische Auf-Ab-Berechnung) + + + + + + QC Linie mit GF und U-Form + + + + Omniflo diff --git a/menu/SSG_LIB.mnu b/menu/SSG_LIB.mnu index 2f965cc..19be501 100644 --- a/menu/SSG_LIB.mnu +++ b/menu/SSG_LIB.mnu @@ -21,13 +21,18 @@ [->Etage] [Werte manuell]^C^C(ssg-ensure "VarioFoerderer") EtageVarioFoerderer [<-aus 3D-Linie]^C^C(ssg-ensure "VarioFoerderer") EtageVarioFoerderer3D -[3D-Linienzug]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerderer +[->Streckengruppe] +[Werte manuell]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererManuell +[aus 3D Linie mit Zielhoehe]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererZielhoehe +[<-3D Objekte stueckweise (in Arbeit)]^C^C(ssg-ensure "VarioFoerderer") LinienzugVarioFoerdererStueckweise [Vario_Kette_Merge]^C^C(ssg-ensure "VarioFoerderer") Vario_Kette_Merge [<-VarioFoerderer nachruesten (Marker)]^C^C(ssg-ensure "VarioFoerderer") VARIOFOERDERER_NACHRUESTEN [->Gefaellestrecke] [einfach]^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_EINFACH [aus 3D-Linie]^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_3DLINIE -[<-<-aus Linienzug (LINE + ARC)]^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_LINIENZUG +[aus Linienzug (LINE + ARC)]^C^C(ssg-ensure "Gefaellestrecke") GEFAELLESTRECKE_LINIENZUG +[QC Linie mit GF (automatische Auf-Ab-Berechnung)]^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGf +[<-QC Linie mit GF und U-Form]^C^C(ssg-ensure "VarioFoerderer") QcLinieMitGfUForm [->Omniflo] [->Boegen APB110] [90]^C^C(ssg-ensure "OmniModulInsert") OMNI_APB_630_90 diff --git a/tests/testdata/showroom_ils.json b/tests/testdata/showroom_ils.json index 69e9c24..e696de8 100644 --- a/tests/testdata/showroom_ils.json +++ b/tests/testdata/showroom_ils.json @@ -9,7 +9,7 @@ "rotation": 90.0, "typ": "STANDARD", "darstellung": "2D", - "drehrichtung": "UZS", + "drehrichtung": "GUZ", "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 3466.40) -> SP8 (Layer 1SP-800) (26997.93, 12498.90), Mittenabstand 9032.50, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.", "hoehe_quelle": "Anwender" }, @@ -23,7 +23,7 @@ "rotation": 90.0, "typ": "STANDARD", "darstellung": "2D", - "drehrichtung": "GUZ", + "drehrichtung": "UZS", "comment": "aus DXF: Radmitte AN8 (Layer 1ANTR-800) (26997.93, 13298.90) -> SP8 (Layer 1SP-800) (26997.93, 16298.90), Mittenabstand 3000.00, rotation 90.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=11039.9 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 2226.4 vom Anwender.", "hoehe_quelle": "Anwender" }, From a6f6fcb575ce0877559fc929fb06b1b0747b00e7 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Thu, 8 Oct 2026 14:42:06 +0200 Subject: [PATCH 20/38] [CHANGE] VF-Standard-Dialog: Geometrie-Reihenfolge angepasst (deltaL+Foerderrichtung, Einfuegehoehe+deltaH), Seite/Motorseite nebeneinander; nur Seite/Motorseite/Geruestoption bleiben Radio-Buttons, Rest wieder Combobox; Winkel/Verteilung-Dialog komplett auf Combobox zurueckgebaut (keine Radio-Variante mehr noetig) [CHANGE] VF-Linienzug-Wizard: horizontale Kurve (GF-Bogen/Vario-Kurve) direkt nach explizit eingefuegtem AS-Element ausgegraut, da dort zuerst ein gerades Segment folgen muss [ADD] doc/faq.md: Antworten zu VF/GF-Kombinationsfragen ergaenzt (Puffer-Umschleusung, Zielhoehe, Etagenfoerderer, Streckenueberbrueckung) + Screenshot gf-vf-kombination.png Co-Authored-By: Claude Sonnet 5 --- Lisp/vf_linienzug.lsp | 24 +++- Lisp/vf_standard.lsp | 205 ++++++++----------------------- dcl/variofoerderer.dcl | 50 ++++---- doc/faq.md | 11 ++ doc/images/gf-vf-kombination.png | Bin 0 -> 22836 bytes doc/images/vf-gui1.png | Bin 13327 -> 21697 bytes 6 files changed, 115 insertions(+), 175 deletions(-) create mode 100644 doc/images/gf-vf-kombination.png diff --git a/Lisp/vf_linienzug.lsp b/Lisp/vf_linienzug.lsp index 5700f6a..9670e33 100644 --- a/Lisp/vf_linienzug.lsp +++ b/Lisp/vf_linienzug.lsp @@ -1543,11 +1543,19 @@ ;; VF-Kette) macht "GF-Bogen"/"Neue Linie: GF" als DIREKTE Fortsetzung keinen ;; Sinn (kein GF-Baustein wird an dieser Stelle einfach an ein VF-Teil ;; angeflanscht) - diese beiden Optionen werden dann ausgegraut. +;; as-eben-eingefuegt: T, wenn der Anwender die AS-Frage ("AS-Element +;; setzen?") explizit mit Ja beantwortet hat (as-vorhanden in +;; vf-linienzug-modus) - das AS-Element braucht danach zuerst ein GERADES +;; Segment (Linie-GF/Linie-VF/Horizontal-VF), eine horizontale Kurve direkt +;; im Anschluss (GF-Bogen/Vario-Kurve) ergibt keinen Sinn und wird ebenfalls +;; ausgegraut. Greift nur, wenn familie nicht schon "VF" ist (dort ist +;; wahl_gfbogen bereits deaktiviert); nil, wenn der Startpunkt automatisch +;; auf einer bestehenden Kette erkannt wurde (as-vorhanden dann ohnehin nil). ;; "Neue Linie BIS Kettenende" ist kein Radio mehr, sondern der eigene Button ;; "abschliessen" (done_dialog 3) - er setzt slot direkt auf 6 und ignoriert ;; die aktuelle Radio-Auswahl (hat ihre eigene GF/VF-Erkennung, bleibt daher ;; immer waehlbar, auch wenn GF-Bogen/Neue Linie: GF ausgegraut sind). -(defun vflw-gruppe-naechstes-element-impl (kettenanfang familie / dat ergebnis slot gwahl) +(defun vflw-gruppe-naechstes-element-impl (kettenanfang familie as-eben-eingefuegt / dat ergebnis slot gwahl) (setq dat (load_dialog (vflw-dcl-pfad))) (if (not (new_dialog "vflw_naechstes_element" dat)) (if (and dat (>= dat 0)) (unload_dialog dat)) @@ -1560,6 +1568,17 @@ (mode_tile "wahl_gfbogen" 1) (mode_tile "wahl_liniegf" 1) (set_tile "wahl_variokurve" "1"))) + ;; Unmittelbar nach einem explizit eingefuegten AS-Element ergibt eine + ;; horizontale Kurve (GF-Bogen/Vario-Kurve) als DIREKTE Fortsetzung + ;; keinen Sinn - das AS-Element braucht zuerst ein gerades Segment + ;; (Linie-GF/Linie-VF/Horizontal-VF). Nur relevant am Kettenanfang und + ;; nur, wenn nicht schon durch familie="VF" abgedeckt (dort ist + ;; wahl_gfbogen bereits deaktiviert). + (if (and kettenanfang as-eben-eingefuegt (not (equal familie "VF"))) + (progn + (mode_tile "wahl_gfbogen" 1) + (mode_tile "wahl_variokurve" 1) + (set_tile "wahl_liniegf" "1"))) (action_tile "accept" "(setq slot (cond ((= (get_tile \"wahl_gfbogen\") \"1\") 1) ((= (get_tile \"wahl_variokurve\") \"1\") 2) @@ -6608,7 +6627,8 @@ (progn (if (vfl-wizard-aktiv) (vl-catch-all-apply 'vflw-gruppe-naechstes-element-impl - (list (null frame) (if (null frame) startpunkt-familie nil)))) + (list (null frame) (if (null frame) startpunkt-familie nil) + (if (null frame) as-vorhanden nil)))) (if frame (progn (princ (ssg-text "vfl-menu-gf-bogen-1")) diff --git a/Lisp/vf_standard.lsp b/Lisp/vf_standard.lsp index 9f11549..8c3b8e9 100644 --- a/Lisp/vf_standard.lsp +++ b/Lisp/vf_standard.lsp @@ -863,8 +863,8 @@ ;; Eintrag in "labels" (Tile-Keys "_0".."_(n-1)"). labels ;; sind bereits fertige, uebersetzte Strings (ssg-text/ssg-textf) - werden ;; hier nur noch fuer die DCL-Syntax escaped (ssg-dcl-label-escape). -;; Gemeinsam genutzt von vfs-dialog-eingabe-basis-radio UND -;; vfs-dialog-winkel-verteilung-radio. +;; Genutzt von vfs-dialog-eingabe-basis-radio fuer die drei verbleibenden +;; Radio-Gruppen (Seite, Motorseite, Geruestoption). (defun vfs-dcl-radio-gruppe-zeilen (prefix box-label labels / zeilen i) (setq zeilen (list ": boxed_radio_column {" @@ -1048,9 +1048,13 @@ ) ) -;; Basis-Eingabe (Dialog 1, Radio-Button-Variante) - siehe Kopfkommentar -;; des DCL-DIALOG-Abschnitts. Gleiche prefill-Struktur/Rueckgabe wie -;; -popup; 'FEHLER bei technischem Fehler (Dispatcher faellt dann zurueck). +;; Basis-Eingabe (Dialog 1, dynamische Variante) - siehe Kopfkommentar +;; des DCL-DIALOG-Abschnitts. Nur "Seite", "Motorseite" und "Geruestoption" +;; bleiben als Radio-Button-Gruppen (alle Optionen sofort sichtbar); alle +;; anderen Felder (Foerderrichtung, Fahrtrichtung, Darstellung 2D/3D) sind +;; wieder Comboboxen (popup_list), wie der uebrige Dialog. Gleiche +;; prefill-Struktur/Rueckgabe wie -popup; 'FEHLER bei technischem Fehler +;; (Dispatcher faellt dann zurueck). (defun vfs-dialog-eingabe-basis-radio (prefill / zeilen dcl-pfad dat ergebnis dlg-deltal dlg-deltah dlg-hoehe dlg-richtung-idx dlg-fahrt-idx dlg-seite-idx @@ -1089,31 +1093,26 @@ " label = \"Geometrie\";" " : row {" " : edit_box { key = \"deltal\"; label = \"Horizontale Distanz deltaL (mm):\"; edit_width = 10; }" + " : popup_list { key = \"richtung\"; label = \"Foerderrichtung:\"; width = 16; }" + " }" + " : row {" + " : edit_box { key = \"einfuegehoehe\"; label = \"Einfuegehoehe (mm):\"; edit_width = 10; }" " : edit_box { key = \"deltah\"; label = \"Hoehenunterschied deltaH (mm):\"; edit_width = 10; }" - " }")) - (setq zeilen (append zeilen - (vfs-dcl-radio-gruppe-zeilen "richtung" "Foerderrichtung:" - (list (ssg-text "vfs-dlg-richtung-auf") (ssg-text "vfs-dlg-richtung-ab"))))) - (setq zeilen (append zeilen (list - " : edit_box { key = \"einfuegehoehe\"; label = \"Einfuegehoehe (mm):\"; edit_width = 10; }" + " }" " }" " : boxed_column {" - " label = \"Ausrichtung\";"))) - (setq zeilen (append zeilen - (vfs-dcl-radio-gruppe-zeilen "fahrtrichtung" "Fahrtrichtung:" - (list (ssg-textf "gf-dlg-richtung-0" (list grad-zeichen)) - (ssg-textf "gf-dlg-richtung-90" (list grad-zeichen)) - (ssg-textf "gf-dlg-richtung-180" (list grad-zeichen)) - (ssg-textf "gf-dlg-richtung-270" (list grad-zeichen)))))) + " label = \"Ausrichtung\";" + " : popup_list { key = \"fahrtrichtung\"; label = \"Fahrtrichtung:\"; width = 30; }" + " : row {")) (setq zeilen (append zeilen (vfs-dcl-radio-gruppe-zeilen "seite" "Seite:" (list (ssg-text "gf-dlg-rechts") (ssg-text "gf-dlg-links"))))) (setq zeilen (append zeilen (vfs-dcl-radio-gruppe-zeilen "motorseite" "Motorseite:" (list (ssg-text "gf-dlg-rechts") (ssg-text "gf-dlg-links"))))) - (setq zeilen (append zeilen - (vfs-dcl-radio-gruppe-zeilen "dimension" "Darstellung (2D/3D):" (list "3D" "2D")))) (setq zeilen (append zeilen (list + " }" + " : popup_list { key = \"dimension\"; label = \"Darstellung (2D/3D):\"; width = 20; }" " }" " : boxed_column {" " label = \"Geruest\";" @@ -1141,11 +1140,30 @@ (set_tile "deltal" (if prefill (rtos (cdr (assoc "deltaL" prefill)) 2 0) "15000")) (set_tile "deltah" (if prefill (rtos (cdr (assoc "deltaH" prefill)) 2 0) "3000")) (set_tile "einfuegehoehe" (if prefill (rtos (cdr (assoc "einfuegehoehe" prefill)) 2 1) "0")) - (set_tile (strcat "richtung_" (itoa sel-richtung)) "1") - (set_tile (strcat "fahrtrichtung_" (itoa sel-fahrt)) "1") + + (start_list "richtung") + (add_list (ssg-text "vfs-dlg-richtung-auf")) + (add_list (ssg-text "vfs-dlg-richtung-ab")) + (end_list) + (set_tile "richtung" (itoa sel-richtung)) + + (start_list "fahrtrichtung") + (add_list (ssg-textf "gf-dlg-richtung-0" (list grad-zeichen))) + (add_list (ssg-textf "gf-dlg-richtung-90" (list grad-zeichen))) + (add_list (ssg-textf "gf-dlg-richtung-180" (list grad-zeichen))) + (add_list (ssg-textf "gf-dlg-richtung-270" (list grad-zeichen))) + (end_list) + (set_tile "fahrtrichtung" (itoa sel-fahrt)) + (set_tile (strcat "seite_" (itoa sel-seite)) "1") (set_tile (strcat "motorseite_" (itoa sel-motorseite)) "1") - (set_tile (strcat "dimension_" (itoa sel-dim)) "1") + + (start_list "dimension") + (add_list "3D") + (add_list "2D") + (end_list) + (set_tile "dimension" (itoa sel-dim)) + (set_tile "geruest_einzelmodul" (if (or (null prefill) (equal (cdr (assoc "geruest-einzelmodul" prefill)) "1")) "1" "0")) (set_tile (strcat "geruest_typ_" (itoa sel-geruest-typ)) "1") @@ -1155,11 +1173,11 @@ "(setq dlg-deltal (get_tile \"deltal\"))" "(setq dlg-deltah (get_tile \"deltah\"))" "(setq dlg-hoehe (get_tile \"einfuegehoehe\"))" - "(setq dlg-richtung-idx " (vfs-dcl-radio-idx-cond "richtung" 2) ")" - "(setq dlg-fahrt-idx " (vfs-dcl-radio-idx-cond "fahrtrichtung" 4) ")" + "(setq dlg-richtung-idx (atoi (get_tile \"richtung\")))" + "(setq dlg-fahrt-idx (atoi (get_tile \"fahrtrichtung\")))" "(setq dlg-seite-idx " (vfs-dcl-radio-idx-cond "seite" 2) ")" "(setq dlg-motorseite-idx " (vfs-dcl-radio-idx-cond "motorseite" 2) ")" - "(setq dlg-dim-idx " (vfs-dcl-radio-idx-cond "dimension" 2) ")" + "(setq dlg-dim-idx (atoi (get_tile \"dimension\")))" "(setq dlg-geruest-einzelmodul (get_tile \"geruest_einzelmodul\"))" "(setq dlg-geruest-typ-idx " (vfs-dcl-radio-idx-cond "geruest_typ" n-geruest-typ) ")" "(done_dialog 1)" @@ -1193,8 +1211,10 @@ ) ) -;; Dispatcher: bevorzugt die Radio-Button-Variante (siehe Kopfkommentar des -;; DCL-DIALOG-Abschnitts), Rueckfall auf -popup nur bei technischem Fehler. +;; Dispatcher: bevorzugt die dynamisch generierte Variante (Seite/ +;; Motorseite/Geruestoption als Radio, Rest als Combobox - siehe +;; Kopfkommentar des DCL-DIALOG-Abschnitts), Rueckfall auf die reine +;; Popup-Variante nur bei technischem Fehler. (defun vfs-dialog-eingabe-basis (prefill / ergebnis) (setq ergebnis (vfs-dialog-eingabe-basis-radio prefill)) (if (eq ergebnis 'FEHLER) (vfs-dialog-eingabe-basis-popup prefill) ergebnis) @@ -1289,129 +1309,12 @@ ) ) -;; Winkel/Verteilung-Eingabe (Dialog 2, Radio-Button-Variante) - siehe -;; Kopfkommentar des DCL-DIALOG-Abschnitts. Gleiche prefill-Struktur/ -;; Rueckgabe wie -popup; 'FEHLER bei technischem Fehler. -(defun vfs-dialog-winkel-verteilung-radio (gueltige-winkel ergebnis-liste staustrecke-basis prefill / - zeilen dcl-pfad dat ergebnis w eintrag labels - sel-winkel sel-verteilung idx toggle-zeile i - dlg-winkel-idx dlg-verteilung-idx dlg-lgf1 - best-winkel L_GF L_VF verteilung-modus L_GF1 L_GF2 lgf-paar) - ;; Winkel-Labels vorab aufloesen - gleiche Texte wie im Popup. - (setq labels nil) - (foreach w gueltige-winkel - (setq eintrag (assoc w ergebnis-liste)) - (setq labels (append labels (list - (if (= w 0) - (ssg-textf "vfs-dlg-winkel-horizontal" - (list (rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1))) - (ssg-textf "vfs-dlg-winkel-option" - (list (itoa w) grad-zeichen (rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1))) - ))) - ) - ) - - ;; Vorbelegung: Winkel aus prefill (falls noch gueltig), sonst erster - ;; (kleinster) gueltiger Winkel - analog der automatischen Konsolen-Wahl. - (setq sel-winkel 0 idx 0) - (if prefill - (foreach w gueltige-winkel - (if (equal w (cdr (assoc "winkel" prefill))) (setq sel-winkel idx)) - (setq idx (1+ idx)) - ) - ) - (setq sel-verteilung - (if prefill (atoi (cdr (assoc "verteilung-idx" prefill))) 0)) - - (setq zeilen (list - "vfs_winkel_dyn : dialog {" - " label = \"VarioFoerderer (Standard) - Winkel / Verteilung\";" - " : column {")) - (setq zeilen (append zeilen (vfs-dcl-radio-gruppe-zeilen "winkel" "Winkel:" labels))) - (setq zeilen (append zeilen (list - " : boxed_column {" - " label = \"Verteilung Gefaellestrecken (vorne/hinten)\";"))) - (setq zeilen (append zeilen - (vfs-dcl-radio-gruppe-zeilen "verteilung" "Modus:" - (list (ssg-text "vfs-dlg-verteilung-1") (ssg-text "vfs-dlg-verteilung-2") - (ssg-text "vfs-dlg-verteilung-3") (ssg-text "vfs-dlg-verteilung-4"))))) - (setq zeilen (append zeilen (list - " : edit_box { key = \"lgf1_manuell\"; label = \"L_GF1 vorne (mm):\"; edit_width = 10; }" - " }" - " }" - " ok_cancel;" - "}"))) - - (setq dcl-pfad (ssg-dcl-temp-schreiben "vfswinkel" zeilen)) - (if (null dcl-pfad) - 'FEHLER - (progn - (setq dat (load_dialog dcl-pfad)) - (if (not (new_dialog "vfs_winkel_dyn" dat)) - (progn - (if (and dat (>= dat 0)) (unload_dialog dat)) - (vl-file-delete dcl-pfad) - 'FEHLER - ) - (progn - (set_tile (strcat "winkel_" (itoa sel-winkel)) "1") - (set_tile (strcat "verteilung_" (itoa sel-verteilung)) "1") - (set_tile "lgf1_manuell" - (if (and prefill (cdr (assoc "lgf1" prefill))) - (rtos (cdr (assoc "lgf1" prefill)) 2 1) "0")) - (mode_tile "lgf1_manuell" (if (= sel-verteilung 3) 0 1)) - - ;; Jedes der 4 Verteilung-Radio-Tiles braucht sein EIGENES - ;; action_tile (haengt bei Radio-Buttons nicht am Gruppen-Key wie - ;; bisher am popup_list-Key "verteilung"). - (setq toggle-zeile - "(mode_tile \"lgf1_manuell\" (if (= (get_tile \"verteilung_3\") \"1\") 0 1))") - (setq i 0) - (while (< i 4) - (action_tile (strcat "verteilung_" (itoa i)) toggle-zeile) - (setq i (1+ i)) - ) - - (action_tile "accept" - (strcat - "(setq dlg-winkel-idx " (vfs-dcl-radio-idx-cond "winkel" (length gueltige-winkel)) ")" - "(setq dlg-verteilung-idx " (vfs-dcl-radio-idx-cond "verteilung" 4) ")" - "(setq dlg-lgf1 (get_tile \"lgf1_manuell\"))" - "(done_dialog 1)" - ) - ) - (action_tile "cancel" "(done_dialog 0)") - - (setq ergebnis (start_dialog)) - (unload_dialog dat) - (vl-file-delete dcl-pfad) - - (if (= ergebnis 1) - (progn - (setq best-winkel (nth dlg-winkel-idx gueltige-winkel)) - (setq eintrag (assoc best-winkel ergebnis-liste)) - (setq L_GF (nth 1 eintrag) L_VF (nth 2 eintrag)) - (setq verteilung-modus (itoa dlg-verteilung-idx)) - (setq lgf-paar (vfs-verteilung-berechnen verteilung-modus L_GF staustrecke-basis dlg-lgf1)) - (setq L_GF1 (car lgf-paar) L_GF2 (cadr lgf-paar)) - (list best-winkel L_GF L_VF L_GF1 L_GF2 verteilung-modus) - ) - nil - ) - ) - ) - ) - ) -) - -;; Dispatcher: bevorzugt die Radio-Button-Variante (siehe Kopfkommentar des -;; DCL-DIALOG-Abschnitts), Rueckfall auf -popup nur bei technischem Fehler. -(defun vfs-dialog-winkel-verteilung (gueltige-winkel ergebnis-liste staustrecke-basis prefill / ergebnis) - (setq ergebnis (vfs-dialog-winkel-verteilung-radio gueltige-winkel ergebnis-liste staustrecke-basis prefill)) - (if (eq ergebnis 'FEHLER) - (vfs-dialog-winkel-verteilung-popup gueltige-winkel ergebnis-liste staustrecke-basis prefill) - ergebnis - ) +;; Winkel/Verteilung-Eingabe: Dialog nutzt durchgaengig Comboboxen +;; (variofoerderer_winkel in dcl/variofoerderer.dcl) - keine Radio-Variante +;; mehr noetig, da weder "winkel" noch "verteilung" als Radio bleiben +;; (siehe Kopfkommentar des DCL-DIALOG-Abschnitts). +(defun vfs-dialog-winkel-verteilung (gueltige-winkel ergebnis-liste staustrecke-basis prefill) + (vfs-dialog-winkel-verteilung-popup gueltige-winkel ergebnis-liste staustrecke-basis prefill) ) ;; ============================================================ diff --git a/dcl/variofoerderer.dcl b/dcl/variofoerderer.dcl index 6ddd3ed..3e8dc24 100644 --- a/dcl/variofoerderer.dcl +++ b/dcl/variofoerderer.dcl @@ -11,11 +11,15 @@ // der Werteingabe (deltaL, deltaH, Foerderrichtung, Einfuegehoehe, // Fahrtrichtung, Seite, Motorseite, Dimension, Geruest, Winkel, // GF-Verteilung) - gemeinsam genutzt von Standard UND Etage. Die -// bevorzugten Radio-Button-Varianten (vfs_basis_dyn/vfs_winkel_dyn) -// werden zur Laufzeit generiert (vfs-dialog-eingabe-basis-radio/ -// vfs-dialog-winkel-verteilung-radio in vf_standard.lsp) und stehen -// NICHT in dieser Datei - diese beiden Dialoge hier sind nur noch der -// Fallback, falls das Schreiben/Laden der Temp-DCL-Datei mal scheitert. +// bevorzugte Variante (vfs_basis_dyn) wird zur Laufzeit generiert +// (vfs-dialog-eingabe-basis-radio in vf_standard.lsp) und steht NICHT +// in dieser Datei - NUR "Seite", "Motorseite" und "Geruestoption" +// bleiben dort Radio-Button-Gruppen (sofort sichtbare Optionen), alle +// anderen Felder sind Comboboxen wie hier. variofoerderer_basis hier +// ist nur noch der Fallback, falls das Schreiben/Laden der Temp-DCL +// mal scheitert. variofoerderer_winkel (Winkel/Verteilung) hat KEINE +// generierte Variante mehr und wird direkt verwendet (komplett +// Combobox, siehe vfs-dialog-winkel-verteilung in vf_standard.lsp). // Die 3D-Linie-Eingabe (Modus "3D-Linie"), der Etage-Typ und die // Linienzug-Kette selbst bleiben interaktiv (Kommandozeile bzw. eigener // Wizard in vf_linienzug_wizard.dcl). Der Linienzug-Modus (1/2/3/4/5) wird @@ -121,24 +125,24 @@ variofoerderer_basis : dialog { label = "Horizontale Distanz deltaL (mm):"; edit_width = 10; } - : edit_box { - key = "deltah"; - label = "Hoehenunterschied deltaH (mm):"; - edit_width = 10; - } - } - - : row { : popup_list { key = "richtung"; label = "Foerderrichtung:"; width = 16; } + } + + : row { : edit_box { key = "einfuegehoehe"; label = "Einfuegehoehe (mm):"; edit_width = 10; } + : edit_box { + key = "deltah"; + label = "Hoehenunterschied deltaH (mm):"; + edit_width = 10; + } } } @@ -150,15 +154,17 @@ variofoerderer_basis : dialog { label = "Fahrtrichtung:"; width = 30; } - : popup_list { - key = "seite"; - label = "Seite:"; - width = 16; - } - : popup_list { - key = "motorseite"; - label = "Motorseite:"; - width = 16; + : row { + : popup_list { + key = "seite"; + label = "Seite:"; + width = 16; + } + : popup_list { + key = "motorseite"; + label = "Motorseite:"; + width = 16; + } } : popup_list { key = "dimension"; diff --git a/doc/faq.md b/doc/faq.md index 39117ec..ae244c2 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -268,15 +268,26 @@ Unter *ILS -> Foerderer* stehen folgende Einfügemodi zur Verfügung: #### Wie baue ich einen VF in einem Puffer mit Gefällestrecken als Umschleusung? +Ich baue eine Gefällestrecke und kann dann mit einem Klick einen Varioförderer daneben bauen. +![Variofoerderer dialog2](images/gf-vf-kombination.png) +*Abbildung: Erzeugung eines Varioförderers passend zur Gefällestrecke* #### Wie baue ich einen VF zur Anfahrung einer bestimmten Höhe (Arbeitsplatz)? +Das macht man aus einer Streckengruppe aus aus mindestens einer GF und einer VF und den entsprechend nötigen Bögen. Eventuell noch die Verwendung eines horizontalen Anteils beim Varioförderer, um die Zielhöhe zu erreichen. + #### Wie baue ich einen VF als Übergang zwischen zwei verschiedenen Kreiseln (unterschiedliche Höhe und Position x/y/z) +Standardfall. Höhenunterschiede und Einfügehöhe einfach in Interface angeben. + #### Wie baue ich einen Förderer zu Ebenenüberquerung zwischen zwei Pufferblöcken, welche übereinander positioniert sind? +Dafür ist der sogenannte Etagenförderer vorgesehen. + #### Wie baue ich eine Strecke mit mehreren VF und Gefällestrecken hintereinander zur Überbrückung von großen Entfernungen? +Dies kann nur Stückweise erfolgen, indem man ausprobiert, welche GF VF Kombination welche Länge erreicht und dabei eine gewünschte Höhe nicht überschreitet. Danach kann man die einzelnen Einheiten zu einem Mergen. + ## 4. Scanner und Separator ### 4.1 Zusammensetzung, Abhängigkeiten, Randbedingungen diff --git a/doc/images/gf-vf-kombination.png b/doc/images/gf-vf-kombination.png new file mode 100644 index 0000000000000000000000000000000000000000..f37f8f12a16a0960017ce965d49aa93abc744a83 GIT binary patch literal 22836 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 literal 0 HcmV?d00001 diff --git a/doc/images/vf-gui1.png b/doc/images/vf-gui1.png index e6eff0600f3d97b66e9859c5cc22dd527170e9c5..431947b1e6d040c44cfb06830b1f645543ad0667 100644 GIT binary patch literal 21697 zcma%j1zc6zzV0HVC8Rs0Q>CO!NfD5cF6mB@Zln5{4=9+ViIsW;5-&pTozIc8gjRXw>f!vpomQ;p7;4vW(xF{4P@Rui0jS27r z)lT}gBLsrk2Kx^e&w@z`{)p@(qacO6iH3qfPuM`D69IuxL1ZMwUcF7(p7FFJ9rNV4 zE|F9xD5{-Z7&)5$Qez}17hQll$=jh#6O%3b;#VLe?a=d5gc%t@g`XXvDE%r(pEN%C z@irt?)=G9-Jj1@ifNOu@pEqPujE!EK`jh@W4;TJKXcNOr`h;aRy;5aC=Trf#LaRk$ zm2dI~7YO6+i*K6SNt+Y)OoM25clk{R#HVNG(i}@o!wz>#62v4WC115bZ?~r2Zje%2 z8O)11 z^&_I|t)IUKC44r$c5vqHN^Lq5RonpgtpcBNu5RGfJ&{IN$~af=2%S2Yl0=s?8=USs z=%`ok@@tO9)7+c44^M@rYn^dtmj*05&tvZ{1~ly|M{OMjyjB^7FPQSpIL$}XZ`yra zwoBR?ks+|tJ#M!3iwa~UB_Cez?ol-LcsqWkdi&BpDB*4u-s{X2>#N3#1A^cIvUZUh zBSBN0<3;aIU;p&H?~}tl5&CEwB{)I@A`pHEE3=C;4~U`&*jC78C8K zxfEHoY;(!B+U>DdrwGzjO&&)pM||MnzxZUTlimRaPc{>&XpugK8zrJy-mfTl%cy&? zD`lPB$a-@p=XKlAKDoRHoVUGLYpy3M5?}tUc4)x_+*oca^)j+Lq>X7&m7+sLF z*VRtd{ky%BbQx|oCP~Sy2;o1IL&QvX-#vPJ6j2EIK7&{1vNKvsHN1K{OEhv$|3QO?&DCe>Ljkt<@@&7<~af?>CY4N=_fY%JuaweWnk zXU#Fv^vvelqCKwO)zEDwT+}S#-9A?NyYBorwE>$>hWmF|dhb0Idt&EO9WDo;A04MR zz0!f(eLk9iKEIjc#KDO-A>tFfO3IpySh_r+TyPxl6s}`CipzywAT$xCi|9Iew7?cu z{cbDWya%`fR{EuoOdZ#HCtn`#0Lzj{(+`!~luO7)@^btEv3s zPM(eJoPSw}Ex!FBaL07FWqL;LGq5c$|Jz ztW#HELl8ecsaf7=k~Vu{L^gbv?g4vJ7Etd)l?SuHaz5Mzi`rO9dS&1~z59N8^+Ux= zoA?e6V#X$Td3RPJ*bxwt_wjfJx4lE~>vE$qDfIl>{u+d$kn6r4*rSI05^G&cyQ=4z zA2_*ERM)<^PA(wc?6WuCzRE$e*qwYxVl&mCH4Gmgk2jT`l)IM>Jt~p%&yV@Gx6~Wv z>zA<M^8e#s@Kezztc|qEA6(uaZ%-}IsT-DAv=x1kE$ijJ z*wm~z-x~&JeF3|ljn&0exW{@cG{UygL$|K^4oqkgx2o3m@y(RUS%U2tJB}^%rm~Xq zMrG$@OXQc0@ukz|qi9U|-f))luIIv;&RTg_zg$%lnQX_3XU=oI!!4cbL6B(1z3xjs zEbv~+9=@ZFCf!~h<9&AkwS>AyiIha}UJUQa1kF5@lq8KG6qU}h)godd{%v8^ZYup7 zIp@=k>0_VV<}N1&}kFhKDI09?UiAa5!T&qrE zRbx43<8h?rUFiHg#f>X^sF(aISpA?~KU=40s`_cX(%b z;vWDv`hC)I(=U0#nEm-1yPMk~{uAy)5N7sGy}2^tZ&pdwD~dxMx=D$z8c)5qE^l%j zYng}H{be`m-gUbLOXc6S0?$L{kN?%(yQc~F{mv8?Z7X)`A6)6a@GNk9eh+8xU1@!N zc%#TENhNb$b1UWDoDj>$3Mt^DJtui|*{E2vQ0hbuPEyBTNB?7Tp7hkvv~nVcrSeq$Fogf< zz4-Sq9lGGeu*)f*OY8Ehu>GLsBcsNfvCOxIRSEIm5s>+peb`pTm6b9W(eNIkj`glj z)+mMPhDW$j^VCv+lSp4q__k(Hq6D1qn&8apo4m$s{#+r+m%%N${Pm2wxY+T0-to)W z)#4-Z$-VZ&{FNUlC+9KJ=LWcld>+E!W&s{a-%r>upPc~5$PAs%)zi?>;FPa+Tzdg& zDxV2#%#1p+Keu|!m(LjObF5Iu5FlYhfH8T!9>Po%`-qL8kuOdd^4@$~hWVwkFv>0k z;_%!+z)yzPoEqhV9Q6wjLm|<(z357q%?3wCt6$(BCcbdZG4}i}rkKC<5P0JDusd|t z)8qj@1MPBYb2>yHi;5U22S-dYWc}CM=nuZ;?hpf}hG&AyelsHBZ|5kQc3Y@%Ag4_> zbFnw%kmZZT6}Z3|>{H0)m+Q@V4_qBA6lhZ7BOmG}LC@x}I7 z^r_F!4q?WZaa4zUYj5%^>ov!M!7|0N2-vNoLvGV(<}|U{)}_z6h&UQ_DI%yB?2A1R zc$pRB6U7QXUBlL+(yur)K4g}QZox-k-*Ri)mrgPSg&x6f91&&WzI3G9(WpDNDxGMW zo`K>A1Gmiec9|$h6}Iop5?pC+{q+jP6JQQ-kV?kT?_b$jSy@Zx(t({|7{NF4fB0={ z|9|T${|=3mk+d8_=cxa=&TNI^eWLC?vd$chy4P?xO^Q{rHX}}JyYjubalEDQQTc?zt&GaUGG-5+2pH( zFDY5RJ6-1*B_@$nX*;JIOF;5(B`3`z>mx+WLu@+pJUfTt6RT{af+?;Zq7R5Djm)Ol zVOLZr4}y4xy}LC}NFw(Hg57QoKeCNy-fXwlTwI@Y9%v38n~cVqpVaeMw{1~yYfJe` zG*cSZc&Aj{8Wlfx^Mi<;WzEo%x|9`vNP3s_wNB89>}HfPPCq_2PEL$biRCh?q432aT4o#{xr3MI+tFBUhJHeO~-pO8x3I*Vd^ zXgK2Ts=e!bT{u=S!t={NCx`wCH}_}LFN5)~DM^MFsZMDq_H?GoUb)<-%4d9ucTd&< zqOvQ$UrMp5t8R~Rih$s$igcej9}8i9?Rd@E_~MXMBMp7=2fj*UP|w`?gGjReWk-tk z*x0f}4)+_ROeiMIS3^i{R>t~sp!6HroYhcNg)8KkNAX^WLj5u+sX8scem!WJaW0-k zQo3rQUNaZMO*N&NqSiA>CD<_eRDYDdtX=RirZ+nNchri)n35IXlY;^|Y8x_nye)NFy*_WO`8zmu3 zN{pLzL{bIy#A;Vx2picf&>w?hB@Fn2fs?ckRsnitOjjx0 zZ3V9auq!e}*6evO)2#_|%SRCj4NX3ExASN)n3O4f6%1IqQImYUB3V=>9j`)|WyEwY zcpTq#V->dysg);JsY#FFa4>TAQB959V+_9Wvg5uw1Hf(x-$lkffHE}Wss zAAY3C+g`YS>`i$k>D}i|S_41-O9S+Odcn^ts_T^Y| zvqG1fcWPe?Th>WbHwA~&tKz||H^Npa#W18slN)S4o@1aLl9D6*Y;xoaTnKAYGG(ca zB5SP(Yh}?MtHVhX3Ttp5Fmy3Tl~cbeoh6~Dw4MqY%2ixy2}I{_ZjB)2wOeSpmm=&* zayIAf-FH@p)TkO`^Qi2Z<#8}Qme}|9dD)L40W2F;aci6-BgI#(AFyBHF^1x{KJ(83 zHgESl-jia5OhxLXAZwVF{;TzNmX1ORc`#3;y%!PT+_q%h3TLFp25I&6r`k)J*=?)f zdn?6rZ3X1G-zYj>K{gyK2c5eTV3r$LhA(=CLsn<YLH?7yB7lBref@7-Dsm9fPOBYUZV* zB^RaR`pJE-B6-$HCzSDA5N(s9HRLIoDBHj`m#R{U75>-6kceR?x=KObK=z8*7$Y(Z zo7-t&EAyj;K3-3=sqYWTIm?~(4>x+p7^gheJx&BM5%@fARjJAv`^Mg@59B@<{#fTF z@woO`k`Pv*P}KdNouI;L-;PU5zuhzZ64Vd46f<1QWiXA$R z(|tPoZVP{fb!3Q>o1mNG(1o+))9wMvc)`JvcsM5ms{AinkniM2qR{&mABuhH7HJ@H zDuj;d&v}BPvBNPXN>SGbm)OUqrt>os>ETcB6^LFb+!I-Tv(ip$~%F)X{y$v^Q<#*G5!cbHF49UZ3%a#jY zA}jHyYu#f7(?&11CZ$^mOBTjUcaw2wh0LA`g~#DGRUBu`s2Rg!kXdU>Z5ek)lA|EP zLtdV#+uJJPy?LzzYM!S4RDrEp3C+7@YShXJl@VwsoHP`1v;DNCDWdzd1)an0Lm@NB zq2XmlYBan4oZDafxSPLJ&AvldD^%5*g?eMp^%LiE`laOzttU31t?hf2r&l9E#@)Ax zI45FWB$Kq=a!_&1b?|U=2L@Amjla^&O7tl+Ql4m=JtB&>!uC*YL}cFepHFKMebklV zYnJ-{3bC4YQ@L^^Td7!gr$=ijVqZDu;`1K!$3tEOQA^5V-6GdM9ttGPSH8z%&kA=7 zqWxaRX$}X6s3qgQ%0ML5LAMCt-Y-G}Fp?(6zu`z`GZVGWEW6V+L+ch_SzLFgn@5XA z=1%!Le9aK}UA8r{3PsDAH8nN&mniRu_MmrOS%u$itfngO6Ud#Em@SQQy$=b=^HGv- zDu!M9QH1Zm7r9IG(godr7bzZnT!Y;uM~rc+pM8}}Fh=U4 z`k&y|WlAh z&?~L@BgaT|Qu_+j)|xcSKCPX~ns43`+g4gWe|S8W%r@?DT|u*TGWOYFOr%1?<|~#I5lYyN z+}wyAn`Hz&Q*!nB(fYGah#*fg`y*~snD0xBsFMTXY9ysn#NjVO^= zDb5v-ui$e6WyKfU+l_R-ciFmaOAXj^E3s>w_gE%n=_kz=iMElEE-mmL%6JlqiXd%G zXsX1I*^{20P z-!bR7=-^unr(C#pF)TaFv@MjK7{TLIk9;<{A5GAT6nm`iK@`JISSxix+0M*HI%1JxX+tG47QdWtboxe%f3}Yp%eaCoNK^ z>MnQNXw>_7VI$8^AJ*I#xYo$z93 z;WK^_*@7!r=Q)~W9ue{m+sz*35glSI!n(2+%LjyYX3e)`!c(j-@{5RN2n{=fsZ8Oq zEMMuAtn$j*zKWW5_<*2dceRNB(I{H?d0Mh~LZQGF-V?6C)1xGZ=}zCH%SQ@U$W)cD zxww)G)}fK3zSl=`b#6s1b2fv=*;|^4x{`Yr+cgw>3Q6O7*dP9?BsMZfUw@%8l6FAY zbSq&*aVdE<;7~&S4qw|8k};ns71D5ERcJLF>UE+tw|~b=SVF#1I^Sc}bWDSJ|^nBapbD=lULF4IR57Q@#>}1&y29)xw!a|{|x``bN@|;yF2|vbDn&RV+lSW2; z1BQn`FjK6Yghpe*tSJ1P$O`wXETg>wYl{M^U-Yq~gZF7dQ_iwa zwRXAbL~Luuh+Dr0QEmA96`vm8pI*OneVDv6sT9-7cbJ`P&kxOS`fX|OrE1W~*PKB# zC`{a1^{)pRJ&R7YdX6hTd}ycD_`%(2+l@A66nK`_32^v*?L zM^XGGXk}kuthu%izwvfvRiW@R4r`8Q9jP6JSYA#lC0#gnI(W7bfkJ zR$p>xlU8b&oGPkJ2u5{9Ru+y*;1zSBqr>r;WG+m;neTQAFa|~* zz>@G6WN|r(qSaG|O1PU!c@k2?;-hu^AtU5tw~^);6A^|iOX&mHU>6?`Q65S2zIa_W zCZm%6T1=H^sUizLc)+xndn0}OX7=|oc2`L$#l3MhFff1>qhWOWlaf%=+n{^dy;#Si&1oV61AYZ+!g)Lx}|Use%SIrz@m5Iy&mHEnnh+c7H@s z3cN;wpzUerLWiwF8+@JXJ@cK+K@>aSIEogLzl?1emkLF=&GE2fL1hRH-Xm*c@tJ3> zvppmlXY+tIW*>xAyK|5Bv-C0!&s%wtnMR9IKXK5fi>>skDp{n3rV6;4c*SyoI~d@6 zXh%3pQtFz0P;}1$Md%h&GM-BsvM5ZcJdQwjoyearikdT&@*|Giq1rbOUaEW5_1xKf zNf^acd_A^)KL{b@1hT-zA<2*UJW7oGLHnT=r`b^!ZGpag_cjBE$l4ASO=cgf``!R^ z;&OpTCfOmQp&d0VJa+1S^??4X(-zA(-SP|suj+eL1&Gx5{5M3KDMZub64WT9FyI1? z#Kf}kW$_{aPn0xnu+?!w2mjDaev1Mdk(cJDvpU{G>O9bi zGXw?7k4e@D6a^1sJcuX;mB!#x6_RG{1ht+7Gf;eFQSu-LO@Oo&bxCZy^9=9u2cT9`4th8kjMe_5G6ppFf|&2CQkCso$L>tsH_xlnzfJ*eJ-^zQjE{`DU7(Q# zUhB*Nu4Q2ZkRR0wlgIyH7*Ej2mZ_zGVQ)SS9=6!_2LpNX<{svU=u{8cycN8OYnqV$Yr7UDy|++|*W$rw;radnoT5KC&c`OsD5- zU7Fs>Dv4TPUyWS41b=%n{T^43QP&&XMZn^hDm9i&tr`ldL~Z9aPP$F#HedNiAL{f; zL+XD6ON8}yPg6en^Lf+~V9kXz3uAQ0mEphOSR0l~7m0l~SDU$-5KOf~zGOkPVGrLb zr=h9YvOOWgH!|uU^SJu06M>wZoW|wmlg5{JtrX2kxJ?tWGor3UWu^@FPh;tIOo(PK z1cv5@6{PR)KEG!>P#h<}A)mcP`ix3aL-5xv<#skEZ&AbrcbUykEb= z48s>fOtb|3W}aO!Dx17FV(z639vHM)!@e<@TXmryZSRu&pyi`|OViKT>xK zm+zcQU2p2k&lppRlIlJ6q}JYZ=-U}%=Q0c|8jB6TESA?l+z~Ff*s29hI=VL5Gc>m% z8~{^^qxtLc`NA4T9m`a+z@v3t`Tp;Hz9D&J|1YFML62S|xftzcs73%@zAqagpcw8r z-}QF%bh}R-I;$^oZ)ydn?WJ+Upl~-|j^FhmSx)#StXyduoa$|5M$o;%u{;>-3KDibE+4RdjaaHOoa+2wE> zR)d<^mKNtn6AP~*(9HB>YQU7b-q zRTCcjrO`9!{wgxJeF_KqI~TROngqQD7pFzU6osaJWulpdQv1ouNO?I~*Auw=ID_=x zjXE)5_=euirh0|5#m`cs&d5)@g*F~b;2hp!RmrU{Ge-0B zm8HPb5}h_X1E@?+q(#khyBd9c)3h3M?JXBmb|6BT!5y7iR_NgW^`pM6dF;+wU{U zQ-|$`+Wlm<7U!88q*j*h48?CcNFbsX`%dpfja`XaQ&%va$$PtJ*)J;)^EgOq-fCfA(o^T<-Xu zj-cIcfW-+7 zA-Fpm=`73hvQVR7HBt~@%RSEvSd6j{PsHwn3c#`ASX>-RpXZa_Q!5&elm4ypAwYX-&#X zAlLpoJ%B_3q42&wc%}}5J0o%(EZ6))QSx6~d80pN)CjL#w1geXgn21Bb&ZoIsDp0z zBwsaAqhNa+q&VBBLkzNya%R^E28=TAmlXT@4-ojXGfCz2*Bd$66!B&NFr%e}Nt$z;*gI_9VPgT+)2{F-~)hWXiWB9Ge@-Jiz% zRsZBvD&xtO#Aj*IPd+(q+JHCA+7P)t&!8k{S9fvj=UWWDoL~aCYeW zTtS9*N$~sHFWPM*wE>?soztJQat!R7#)kn->OKi}@Boj0Y$!acwBD0<;(TBF##viP zF{wro0y^ulae@^YKQy+fDCF1T6mega4J7ebK{7_%ACR|DEe4;?_c}oqgfkeBz6@}Q zJk3Pw_;Rc;w;CpaDl64rM6+=Tft6ZGNt(Kt%?o>?uZaB-sdkU31No5LC~%A9M*979 zMp$yyCu{I}wcjoZqxcDsiyrqGk>E%Mgs^8LGi@{JhFHZ>V1ptO&vxR3Mw2DnCUW&Q z=pmnwO|`WTLxHFyV}oW|XStA%9laVMR*n7{7A-{_)kYa<_SO`_IKsLLZWw`6)89=V z=L~ntQKH#QzLaR=)4AUu5u;$tf|E*~kk6OQNY9rUjLp;NnvD)axYiGp^&l>9=f7^D zQvX$co#>DVM!o0Bu0_Jcyveh5qZm3BGQ^bWzd6u8!E&Z*=>+&e*3d2%j@AB?c! z5M$x^tl+;V!%GJ_6H9Ttc!yXWhyvKPj?nD2E^8VDSKk&~tdWvDQ4YHjoFjv^3jbZXuc-r# z%y)IZRY!?{`WHIxEhdCf&VOFLDuwQdy~Xk(x?+P?XpT@#+P$^G8MM%hZ(2}fpAmn1 zy~e-gRdWs(bad%9(FMMKvs2%n7nQ90RUYeF<`Q+xTs?v7LM~>r5f&ES|wRAMI zvJ)I@R>7)}Je*AuKJC;y)!jhr4fg$J8oRTGW2hXZS+aNu7{d{?`$u}JAFnORtmZ;s z)F>0U+%Ti_eKPT-J!8UMPamDTUEcjm?}?}tsN+J1_Z6Z`#S?t(d53j|c9~l2vN!Z& z)RW6#xJp^WRqY15Gutf^Fpzy;jC=qC@s_>gurP%VI_Ju zU*@h2FIe&H$qFd|(oZ%<+u=l?<#k3$wqPYwHQ{`q4knw(HlX6CtCPe+;a&HO*3_2 zW4X7yY2R<%t*;bqZs4oWeAzu!Y~WButR|Q)zCYghag_KB2B^qw13<+Pg(^jaqg2R8 z*jZdwfmKl5l{H#v%@Q%&b3U zKfBeH!u0hBkb^CsmA0Qe5I(3-n!Z%UwbLv6_~i^2s#8zJgz^xrdIUYvOze3}RP%LV z)LRsGyw`f6?*`)}_5+Q-a5%^yZVx4zK4&dbf?18y=G3D8MNvKaH0C_72%_LI=l*=K zuQfE^`jFxp`?Nw><4YU{Q;4xXiA}R_G%Ix?hW;em^8ISrv!czhLWJtj2mk6~;PvH3wb)I<7F4R<5?2Z(>oUzX+9+<8+_BSn{R?EudFOq z;|}2=gZb4bwTE^g?S_dUJ*y}R1+JyJWA^p+ReN6Xtgfvcr0#hjr>3UzIV^Wsyb3gv z7);knznWevcVvl|J(#A+tj)V}Co}v;H0yomS*^|fgqN4lN>5w6En6<36f{tq9Ci*U zkrY&48(q`QA_`Z9FgI(Qm%DIU9a#v%!24+w*mjSc$(N#KvpKoB-w-{4h&nnxPIFr& zmVfcW(928MG?~`>QiuOlb)*@t@&H>_2Ap)d7JEV%nD@vlojT@@&QAODeS=o?GXF;e|Oatr&98CCJc)oW~cY#UKZFvl~eN_#SQUy~kg%qFLc zT)db@7PF(GLvZMdIh*y&JYkEMO`-{L#-|y1Y(z3s~bXGB6TV1s{N_BLH z3^qNP*1ReR$jB5`N+BXZL`e!G8+HPdWRPk9@ zSQrs8adWdjvgP+VwLPLtyVjW9fItp9TF)4{-^oP4&^&eNkMA}$8-B|uE5l7-*LhUm zl)qev#bdxXoc;sHBWLc2wN_k?QHf@8q7gA1|Ys0VwjTfu}rT`m2 zek~M&24UB04FB;%#>v$+tElKc8yg#VbZsYFV_d?*n1v%~2|cP4IM_u-BlQrpE}<$` zf-o1GhYwJ}eFoL#7*lKC8ub%GV<5)p|4J-9yTw@Wox`QGkR&E+a4t5x_SGy#X` zEo}Gn8lkVTu(n>23eUs*omUpiCxJ`+k@)`Cf~?TOZn>pJyl7KQ@+pV|W<>>jc8qIV zhLXk#2VwDVi6!{@%=9-!pqnHP=}!5;Hb_6UaZ>f$fVsDp^iC^ z^=x;>2v(#zunx)s{#{MKe(gi&r9o7&psn&JIy$Cvflr3Z!26F-Hi^Zx|W&-GhMiWL$?+K z1W602yMv0OB!HU0tyKOdRsN;bAVI>id`9Mf(*yt~UHQHil0LGs2Z0rLd_l^bC$GPl zz^PZEv<1Tzh0`JB=xWzsz@!|V^PlcK024nPK!1{JiYR^G5bC9)g8S|niH;%-O+jFH z9W#J1Vi6MGaoxOP1(-wbn*3w;oQDQo3_wy6vX&bgL?!Vz_n~(Dem3KWFf^W~goU#bjp2Lr;t2MZ)C8h$1xx=~okCTDAl5t&3RVsWYcW z0`vJ_tDkX?dvZAt6Y0VPA|F4R*t;A)L0W@s3x!Q&_g+qvB|1HNOGQ%<{2!7EEANpA zdl*HXD23)TPC6i{#Ij-Ha-!sxNm=&dUg(1WI;@4aQ2asp+B|0hrjT_Z5uf7TA=i4| zd%wjK4EBVED?AgHSFbW80SLi|NDM?@Hxr}&%aG7^$l)|zt@aFdn3cbvACdNYKXhZw zlK}DyE~FEcDVbl$Mw}=}1$A?jG=cgzr^5WvVP_qacDjhY*WglSG75fYkAXH&qYt@WqE*nhOjnQD6ka8S4*cV)rLr+oKhFA}2SxRLBR1{qfK25>(O zylc*h7#cy1Z})F`Lj|jr2>mgy@#EtwD{Dn$6o4rlZ}k9KH-Z0_hwVWIjmU`|B1Nv3 zDb2ejG`#lr24b?Vs$aiUkn3!&{ed1VP1Xw81DkIEEL9s$D`((DDEDhJvfpwjQER6F z00nmc6Hvfz7Y&mmM5+OTk_}1y`|*$<6?GmE?^>Nn!FkR>KbRNg6=Xt`%M$bW9LaJ@EL!)ReY1y7ai^diD?rZ!y9Jz$SXnvv;{6b z^1V$>8jQ3255EC~@8apf<1k)?&UL#@R!rj7^s|e3UV3M=A}mgYZGAmsA-omkr~Q#?#Y@p(BT* zTDHv=6(;K8#~D8^K2*N7dW*VH34jCjd zkWedf2&Wq$zVG^ey4-@H(<*EOq`ij2*?Qh+P@J1Xg<<& z<&%H1_JAe8AOF7)z{}SZZ|C6zZ_k$^iji<|xKaKa2tbXK&%wapGtLP>wKJWm*5Zdi z;FioTE%f_?M8LMJ{CCaN?=31ckBTyz#4!1(Q2b7pP<~VtCnU)>EuegcbEgN&&+=|e zvgK%m%0zS-Dc?+>%B0hNoK^3O3!D%B4Kk*`7ZvuY`0!}RKGNeJz`qndZ1Ii8D0)Nn zhb}qNLObqhKcp=QY{l`zApT4t@&Kgz2#W(S;K=}o)dEIt#deUn;2=XTgqLlGOpE)l zibaVEZi6ZVXjly(s3ImWm|yyBoS260HuHId`bX&v#si<~fndCUaUq`Atu;Jg#uicy zXIuF44yvq5_JI5$y+(zcLOvMi|7qGIK+_Jl4RR2Wo9~IgJc4#-anZ@HB)~cZ$OAvw-*m@H zivt*K-Yr@!vl`92&gcLHp5~IGGUN}~)HI10O$NAB#=KO-?2M2F9|Rui)b8B_V@=jC zix-`&K66OUuCQjB2J+Va7i|-pU%3t4D&Nj(!C56RB}RUpPoFN!$f3 zH#l41ZC(wk_pcjD<^nQs`64!;<@I1tnx#|zJT}MVN@yuDo!i&7p{2N2-JkARKD#pV z&Koc+Iq~Ftahqw3XoHGbD0uKya>=4+|qjJ@ShaHreR zL$HzOGrK=6wDgWPXzI5m%JC+tJ}6EatZ*KRTjPqr)Yv>A*z$W{-!UIwPt=o4kpe(9 zwgR_#Y`0r3NKeod@{K6fSEx)V%tZMWmoWp3&DaothSQ|?`Xl^}!?)`$%LTgtDv7_E zXDzX?=VZdkl&F&P{XdKxyf03;k3Q$WSzR7+jqO6=chF+?uwPp0`?%ph@HuDT<7elF z<>j#vRp{)hqN2FkrXvH`^p#c6v=Fj$*ZVqB@Q%o9f8Z|2R_{i=RS;M?CcbBRWUFa% zv&@N%;D)$-YT)CA&Tz+U^V<7|J=DKD>aS5Q0I&JeXAgPrBEH`EQ8{eQKNK{U*_fm+ z#YhmhysQc<08&uJ)N(lozWRf%Ilt|;;(N|Fh7_jG8H9k7H#rDjBF&z9KjOS!#eun8 z#4GFtTrQmX@@bCj+j-voqBVhoU=BqP;T(RT@LTOOWb|e7N1)J%OD1&qbdwMK#_kaCSe(MxL0s3X4 zw@6L6eQVHmb-MhOfrjQ+VL>~!!-;kH-4Tb~Q3+-uCdtzWT;bi2;asyDTx+pA?|gzF zn$XpRzx0C_3Wp;Fm5py?TuYoJJ2SYWzi!?FUeJQG19la`1HHK?GrxWkLar|qHX&4+ zKV$Zde)j4JarwVmRR>h#u0L-#NANuQ4+tG%JRSV0d2dhP%CMEUGfnWj`MnSm=z`MD z?a^Tm@KeDT(wS0((;Jb5jJNzCtLG@YsJBb>o#A^tRB{DjcXTj9ti07XL zbXx}iEyxoKz;-h|-@l}Aawg|JG2YF3ji($ruJc0Y)QD*ls`mH5^D#RiZbw{!I@Df? z%qQ%zE$rdm&4oIu0*nmB+aa+e85Z0byKO)cqsfdIV5Fb_Z(5qaFy_BDJ8ly2Ez7^r z;dDM>&Ue{dyJjlqj{uT+YX@i4KdC~F7fuD{peLR~_zgro=_5ckZx)*`H_y3_3~z9w zpccTJ`1+%Sof#Vr%o!DrfHR(UU*}$3Gu&PO<&CB$vGR1+rTJ_W{BDoSjJv^x3*mFJ ziBTNAcM>*U=>r*Z(HHo-udh&64EU0qk1_> z;)ly5sp066$x`~XJvpVrXQc6|#`2p&&VA6^2P|q`X-ofA_ezG@WD1_=m+9Fpg@GOv$F6sOY%NJL})(BJAeJE|^N>N1&)A^6rcCD9q zdV2tviFn!PZ>dwu{Kto=S_E=LWstt}D!GgDo{ITqB8JUnMBw#t{0$V(AcG;kQUObK z3GV~V?c&9jM1T6g3*%EwA%jVD_cb%Xgc;-YFq;WKz)7Pp|Aw>@j=F#Ju>1y#(fvQ3 zbJAQApy&vNlKUI*yPYf%fud&;g?Y0; zR{{2UDrA1T68Z}`9?32=)WK;WBDHjS2+Lc@mH&^8xtcSbd|#BAv}+vh9UUFPuonOd zu@azTlJWVBj*hd$2d}8C6mmCEa*!MW*J9K!&V64UmouF(c)dKTqZ;QufV%nS2oAM4i*WnY3@zQS+;O4(VbA``tBph{@=40h4Gy z6k82z870n-V^2WY^_`6Y$U;UocyWiuabJ`uT9ifR*shW*IYT$gS5${{ZKImGau`mO zhnS4S5aq~_L4>n%zEBG!!T36?3I_o?4qg6KuTxof$PbtrC+YW()juQU#06tI(WV*k|3AjZ|1E0olGy`QlBkjlT{LF|F|YVM95FF@==O{U6?pe zZXO2ShDSw}jNkiKT^$k=gF`0xwv=L|EBa?H_rV&@Z#v0rmA!yeojR)H7q3m$wF63H zG=`}7OBoo>SFf${0#m2QPtD8g+n;O-lBI3CF13&@`twqEn2)hSh z-)g6g4+i_C;9hbG?4Xe&DCf)es+xpA@T6g%3&3Z!IbVmL7Jk&pN8~}SavVv$5&C9m z^4ez$yG{P?rrbTy{y`?;LX*=wy9}xf(;V6%8vSU!atL6*Q}1)B^8uD%Ff2Chn5s2J zEHIOhLEwAm2R4y2B5N+f4`NIWb7sibmD>k&1w{kv)c!`SE$e(BzO+tdGIoEjEiEne z0g|ncz54VKo4{)mQ&J>dU3n)bCx3!%Tfh*(0+25)Edlt_u10%=94=e0|H*d11J=S= znCvItV)xA1bLAMshy8J*C<6}_l1wv)f=HDF!=()fSjev69zX?>6D@zsm9o3F3yPkCg*+WioaG41T=ev7Wg zny3lFV4*}&=mam#eU~3V=1ZqLQ!tR;weg7D$;D-{D~9&uD?Ci}_Hw3{`7d-m<*73o zz_*82v&_uReP?Vs^Hp-~z@9VhMvt0$za!IvX;z*sdt98sPs&y16}dS%^A0r_45bzz zCO#ez^anU>@4x_|6^Kvo5E?&6`$9lRAOW(>9|U~?-?YIBoC-i<`<3qaloJ4jdo_IL zQBnbL?^Fjm1uR%6)mHFyzK>pIK6GIt$;XbndfV{8JDn7`Uqa4JE zL0Sz<>K@Z*aWEKvn}nJsb8~n_3*UmXR9XEVWV+FF>QyaSZIk%#ZIk|S81l4!A=rZt zkEsHMd_YBi5(yLFQHb)1z(=q3t?(Mg={aToU*R50LRO*P<#`Y&6;x*It9H54c0irg z^`*9)4=^x`mnT~}zxw<7@aqRY)8e$6-DZ6gj55EXi1Rp-SVh$x^a?G<{$lb-<)wNe zbo)jQ1<+*e?-%@vgGur$XF-iXKl0Fy&u$(977)Fb>X40{-O$(=5tvBt>$zO+*1}(X zXLjV`URXhbBoZx40d&6$Z@cWe@5=$X8v2GjB9J^C`psLp|LlFkH$Ri>d3{@<;DvRq z!`X!`|KbE%fGw$%vl!aj;{bmFvJo~jd+Y`y=@z);`LR(qz~a+E9{B`_)b&w_IX(!DaT;1 zOw939>l6tu{v@Wdl?&#mWYCqrb52#e`d@gwSOqBjT3;}V@$3SxSbf=d(^y=RBJ8k? zLgBv61;XgkuWUI00bzn2nwY>z2fR+p?k5-0?BdQx=E)^7yaQE(rqch$-{IyruS>8= zyph${X4^RkMVdfMV&FaHzfW<^d8*}AI9mt0s!Wms%lUnV1RH9>+oKd`sP;9aRpjO# zjPHJ%e#r@6{O^Sd9y-ZkpsqLa?f3xmoXo9!d_?8wrUa-9jey4%_unz|nrYOcdz7L~ zdve_D{X(A1`MI?R8-)XUSMq7C{-pUMHdEQXXPzH1@<6l;2NC`Af$MklGvTIU?=#Z3 zH_+|Q!?_x}C8#HSo#rPrKV+eFfW9iHmNJD#CixMQcOm}XFa1lwCqBT^B#ze(R8Sh8 znq;f9eeBb9VdL+kmgciI5~MwjV}kdK((Vwa-9?gxq3v+wrDkQXWl$_i{3Ba)-QS%? zyc-5n_`yC1@osmO|8!#Jy$HYvi?XUmR{goVx8p;x74&H$2eW zrB9t;Q@6y$(0et_v?P#bVJhLrTUq3frNshx$$W$!pSZd_;s6#DwRu<+8vJRm2MOzJ zcM*IxNks0~JKd?B|}gSS#SVQ*_2pldCTZulC!1>=}e@J@i<#%&I;qq@QmzVUyWo@DgBvO3X=7 zgJ23Y4vW;)^PL$<0x_`5C#(J5KrY^`rDwyx!t4$O70Zr^p0yC&vANDe)wqO2-=|Mh zDI&5FNdL3g0UtkbH#d9JUhX_&54j6Xmf{=gE|Pl?T8lA(^aT0Idt`Mb^Yzh%Uv5~~ zs9*B13}U10D2W8I`zF(O4PpxqAS<7#vNhkA7kr4Jaxaw>8g$GCDt>ePsTL0MjRSfo`okxESFWTDL9RFCbYyy)Ueo^t-ysbOekyHD| zUJev(ziMP2f9>phcWvhXY2(Vnp@8_IHo=p<_~*6bmiEZHS7N)p1@ zE0H}WVl1V|G1<=8m+V4}k|9GPTV!YCyp!|K@49~1_5JxR@AG}ndwbGTUMPAjJtUC-iUN^aL z=5-ik)wR|}r{-L`+>GWiG$F-(q2d!RD{d^w<11K}Xi(9+j|RO%t)lIJ!@DamrxNJ_ zZ9v-YW=ClX7b$Pp5}XWPJoVA%tOPe3;BcX|wN846tEcDlEDSw8;_CM4(%Ypa z*<6i~*u@X!^lJ0jD|@NviU38bXmqa}Y(!`*LrDyy|p z=dYUot1>Gm7$1j3a^ z(2N4Frz0Dm%Zwj0_wp%xBtD={lr9XCe)zr$ zroHQO1H}~@A@hk!A?jHLHQTkXkCtL#eD|d`C(G8Amyie@bh6U`PkV%_xC%1;z7PD< zp5Bdi#3uA~N&UMuJwA1u0xydogBjnXIUMV=ozEv8Z>T!^+oO0FcFXCs;x$JDFIn|Q zjeYVzD+jOTx3`fztJTo=`d67Eo^v6QQtIzG-5yCU{+xIC;JgB2mK@e%H`G&8Nzf#I z{l&`O9?;NPN1b(v4;J(<)$rc7ka$Ql4RvLl%&-e6`{IEJ=#Vb+U`(*TOp-&RiBL<% zIN*t{{{E-K+0gnj>8%tB3ebv#KkMt+Z!5QVNWR(Q$(1{C>ikk%8#OXSC1Q=)B&4B{ zcHdttK^mCQ_2|sVkFBM^E%(aL2VN_>!X_SW+nOo?9b+q)?>}TUyB&Ue|H=&1@B7o5 zTV`+Omz1z6DJhX!KwC;{Umu5@W4)K`%oNzf{JJ$nyYg^y!yz{dL<-M3jHKxe)~2-E zszEAUjqmnoAJ?sfQl1E39|$*5R?zq!hpADo%PH-TVO}08w}73G4S7Cz>cMJa`PajD zIRc(vHNQQ2Bjh^l3;ipNIB_B|$`N36I+JA*xe+wf1E*J2RW)~Vg4azXTFKDm1?WK@ zpS+`vjm?Ll*Hg7OjGM>d#xGl1!)7J>k02t7MG3?tiiwJ!@q5X`fH2ZCFd%mK@bLJ% zsw$?Z=OX9{vTq1Z_q4WcZ_SHek=}gnXe=oJCN?abi#>jcu?2&x*KKdm%ODBAMwJAP zG-5c8a+&TJ=A3r~F;iQ?dH=ZBIDpn2@hO?ABuhxwFFC0HK=DxNT4oz>+H*>GwquTI? z&N9=MvxQuW{^arRE)$~I8%~p(LSxLr?@m@uIfsNG@p$~XkS*DluU=VLIQQ>67w6;% z0k{LCj8I*j(ZZChw|k%~+QYRI!W|xTfC@WI^&TOAWPlK){#vQCwZq*B``TRYSTVDV zo&NaxybU_}f{6(ysNC6PXfZ*otgP}#BtbHnOgrO1K+(P!$b?MSC9U;;7qqZ()mO}t z-NJ6AQ&Olqw>aQ&-X_-$0TIO3O(3ARGBFo%vb{UB^#OXbzY9F3OR;Bt8EOHmAQB`Z zV*|cwH4h&?srw$Gg~=9Wb+7A;GJpe|k0HrkbuU6t5JTPIdm31@YrsQd734 zR`e1o@KQ#{l_A7JOSUW~!@cV!zX^sjYf8+LtE`b#?}M9hAj&r(qx+nJbM#=GW;DX% z%LS{;U}9SurYt?+?8eI9paPlmwL5n5gC5S@cHK7=cEBmNQ998Q@y1-O!}i3CXbk4U zfPyMM1JUyUMc}_?tt4O8)o#k%lkU?O)CAF*??k03<_|8;4VHJ$Z^R83QNv8KvfoON z=v@Y5#zak>*z>ru_mhw)B>6`Kb9$JFWJ2McAct(M3gKXIL4bEpf;$ zhu7yKjS8|G(B3BrtTzzJa^UCxpv|O5h<~(rlA&;0iGx8y)63@MQzqrpf@`yW+3FF~ zo+ycEjM4nCEV7IGbe6r!1KhFkUA^Iza&@6-PGYICmQH--O^Ho|pow0Ps`8$<( zYYH|Rtlguwx>1LXcBgcY4^Fi=3*|`4amWOBYB>M{3Rb?Kr!e?hJL_~)E7)Y74 z5?pgXt57Vm9pEzM5%>>D<$VxRC%``FGIP4d+C=B$!wpP4!3%e1ql2|+S2?9AtUIk* zL_H`1wl$4Jvy4|*;Fo`ftvi`fU)2Z=yye60ZCq=g z@gM#qf5I$Ry#+wY0}T$e5mgvmm6Yo{LxwkXsFgo^TgA%-P-N!Ymr>Z{{t~i&djP6= z@K(kCg{u3-^W)>=A1Rdf-SxROuwyf4xyFgI0HVNAP+iUY+%)S}`TdJr;Hwr!#a-Ar z-8v-MTr*0Ox3HGZ+bx<~{h9t9&wJ)YbxqCMDis6ZC-nNzzVk^fgt@hK42h)5!l|Qj zB!S>O+Sd&Y?-fw$z=KCA@+3GUug_dwA#Ox)BZjn8=mNe5+Oh$d5t{bxn0%YhR807d}veRR910 literal 13327 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 Date: Thu, 8 Oct 2026 15:12:14 +0200 Subject: [PATCH 21/38] [FIX] Showroom ILS: Kreisel_Showroom_06 (Zeichnung KREISEL_5) um 180 Grad gedreht eingefuegt (AN8-Seite Osten, Einfuegepunkt 35705.93/13093.9). Der Export legt Bahn L links von AN8->SP8 (export_neighbors.kreisel_half_bboxes), material_flow/tro_flow setzen den Bahnwechsel (UZS: R->L) ans AN8-Ende - mit AN8 im Westen lagen die Zulaeufe von Kreisel_Showroom_05 auf L und die Ablaeufe nach Kreisel_Showroom_03 auf R, Bahn 0005-L wurde zur Sackgasse. Lage, Laenge, Hoehe und Drehrichtung unveraendert; Treiber-Kopf und Scanner-Aufruf angepasst Co-Authored-By: Claude Opus 5.5 --- tests/test_showroom_ils.lsp | 9 ++++++--- tests/testdata/showroom_ils.json | 6 +++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/test_showroom_ils.lsp b/tests/test_showroom_ils.lsp index e9f9f16..28c7ed9 100644 --- a/tests/test_showroom_ils.lsp +++ b/tests/test_showroom_ils.lsp @@ -8,12 +8,12 @@ ;; tests/testdata/showroom_ils.json --projekt Showroom \ ;; --flach --ohne-hoehen \ ;; --kreisel-achse 27797.93 16298.90 36705.93 16298.90 \ -;; --kreisel-achse 28772.93 13093.90 35305.93 13093.90 \ +;; --kreisel-achse 35305.93 13093.90 28772.93 13093.90 \ ;; --kreisel-hoehe 26997.93 3066.4 2226.4 \ ;; --kreisel-hoehe 26997.93 12898.9 2226.4 \ ;; --kreisel-hoehe 37105.93 9888.9 1700 \ ;; --kreisel-hoehe 27397.93 16298.9 2226.4 \ -;; --kreisel-hoehe 28372.93 13093.9 1970 +;; --kreisel-hoehe 35705.93 13093.9 1970 ;; 2. VON HAND (geht bei Stufe 1 verloren - danach neu eintragen): ;; Kreisel_Showroom_04 (vertikal, rechts) samt Separator/Scanner bei ;; y=14979 entfernt, dafuer VF_Showroom_01 (VarioFoerderer standard, @@ -28,7 +28,10 @@ ;; - in der gebauten Zeichnung KREISEL_1/2/4, KREISEL_5, KREISEL_3. ;; - Kreisel_Showroom_05/06 sind Schleifen ohne AN8/SP8 im Plan (an beiden ;; Enden Weichenboegen) - per --kreisel-achse als STANDARD-Kreisel -;; angenaehert (Radmitten = Mittelpunkte der PIN-Kreise). +;; angenaehert (Radmitten = Mittelpunkte der PIN-Kreise). Die AN8-Seite +;; ist NICHT beliebig: der Export legt Bahn L links von AN8->SP8, der +;; Materialfluss setzt den Bahnwechsel ans AN8-Ende. Kreisel_Showroom_06 +;; (UZS) hat AN8 darum im OSTEN, sonst wird Bahn L zur Sackgasse. ;; - Weichen (WB-*/WM-*/WL-*/WR-*) werden bewusst NICHT nachgebaut. ;; - GF: den Winkel ;; und die Staustreckenlaenge rechnet dematic_arvato:gf-geometrie aus diff --git a/tests/testdata/showroom_ils.json b/tests/testdata/showroom_ils.json index 69e9c24..4cf6576 100644 --- a/tests/testdata/showroom_ils.json +++ b/tests/testdata/showroom_ils.json @@ -58,15 +58,15 @@ { "id": "Kreisel_Showroom_06", "function": "insert", - "x": 28372.93, + "x": 35705.93, "y": 13093.9, "z": 1970.0, "abstand": 6533.0, - "rotation": 0.0, + "rotation": 180.0, "typ": "STANDARD", "darstellung": "2D", "drehrichtung": "UZS", - "comment": "aus DXF: Radmitte (manuell AN8) (Layer --kreisel-achse) (28772.93, 13093.90) -> (manuell SP8) (Layer --kreisel-achse) (35305.93, 13093.90), Mittenabstand 6533.00, rotation 0.00 Grad; x/y = AN8-Mitte minus Radius. ACHTUNG hoehe=0.0 ist NICHT belegt: AN8/SP8 sind flache 2D-Symbole auf Z=0 und nur 0 3D-Nachbarn in 3000 mm - zu wenige fuer eine belegbare Hoehe. Hoehe 1970 vom Anwender.", + "comment": "aus DXF: Schleife ohne AN8/SP8, Radmitten der Enden (35305.93, 13093.90) -> (28772.93, 13093.90) aus den PIN-Kreisen (--kreisel-achse), Mittenabstand 6533.00, rotation 180 - AN8-Seite bewusst OSTEN: der Export (export_neighbors.kreisel_half_bboxes) legt Bahn L links von AN8->SP8, und material_flow/tro_flow setzen den Bahnwechsel R->L (UZS) ans AN8-Ende. Mit AN8 im Westen lagen die Zulaeufe von Kreisel_Showroom_05 auf L und die Ablaeufe nach Kreisel_Showroom_03 auf R - Bahn 0005-L wurde zur Sackgasse. Hoehe 1970 vom Anwender.", "hoehe_quelle": "Anwender" }, { From a670db839edb4c2c6283ac7466ece26be173d59a Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Thu, 8 Oct 2026 16:01:46 +0200 Subject: [PATCH 22/38] [CHANGE] VarioFoerderer Standard/Etage: 3D-Linie-Eingabemodus laeuft jetzt ueber den bestehenden Basis-Dialog statt komplett interaktiv auf der Konsole Die Linie wird weiterhin gepickt (vfc-3dlinie-erfassen, aus vf-eingabe-abfragen herausgezogen), liefert aber deltaL/deltaH/Richtung/Einfuegehoehe/Fahrtrichtung nur noch als Prefill fuer vfs-dialog-eingabe-basis - Seite/Motorseite/Darstellung/Geruest bleiben wie bisher ueber die GUI einstellbar. c:VarioFoerderer dispatcht Standard/Etage dadurch immer in vfs-standard-dialog-ablauf/vfe-etage-dialog-ablauf; der alte rein konsolenbasierte Fallback-Pfad (Schritte 3-11, vf-eingabe-abfragen) ist als toter Code entfernt. Dead-Code-Aufraeumung: 35 nur noch vom entfernten Pfad genutzte Sprachschluessel aus lang/de_DE.json + lang/en_GB.json entfernt (Paritaet geprueft). Co-Authored-By: Claude Sonnet 5 --- Lisp/vf_core.lsp | 414 ++++++++++++------------------------------- Lisp/vf_standard.lsp | 12 +- doc/faq.md | 24 ++- lang/de_DE.json | 35 ---- lang/en_GB.json | 35 ---- 5 files changed, 133 insertions(+), 387 deletions(-) diff --git a/Lisp/vf_core.lsp b/Lisp/vf_core.lsp index e3802fc..f09c4af 100644 --- a/Lisp/vf_core.lsp +++ b/Lisp/vf_core.lsp @@ -708,37 +708,23 @@ (setq i (1+ i))) eingabe) -(defun vf-eingabe-abfragen ( / eingabe-modus line-points startpunkt endpunkt differenz - deltaL deltaH deltaX deltaY richtung antwort hz-winkel - hoehe-override) - ;; Eingabemodus: von einem Menue-Wrapper vorbelegt (dann keine Frage) oder - ;; interaktiv. Die Vorauswahl gilt nur EINMAL und wird hier verbraucht, - ;; damit ein spaeterer Direktaufruf wieder fragt. - (if *vf-vorauswahl-eingabemodus* - (setq antwort *vf-vorauswahl-eingabemodus* - *vf-vorauswahl-eingabemodus* nil) +;; 3D-Linie picken und daraus deltaL/deltaH/richtung/hz/startpunkt (inkl. Z) +;; ableiten - fuer den GUI-Ablauf (vf-dialog-ablauf): ersetzt dort die +;; separate Startpunkt-Auswahl UND liefert die Geometrie-Felder als Prefill +;; fuer den Basis-Dialog (vfs-dialog-eingabe-basis). Rueckgabe: (deltaL +;; deltaH richtung startpunkt hz) oder nil, wenn keine gueltige Linie +;; gewaehlt wurde (Aufrufer bricht dann ab, statt wie frueher per (exit) +;; die ganze Befehlssitzung zu beenden). +(defun vfc-3dlinie-erfassen ( / line-points startpunkt endpunkt differenz + deltaL deltaH deltaX deltaY richtung hz-winkel) + (princ (ssg-text "vfc-modus-3dlinie-header")) + (command "BKS" "W") + (princ (ssg-text "vfc-bks-weltkoordinaten")) + (setq line-points + (get-line-start-end-points (ssg-text "vfc-bitte-3dlinie-foerderstrecke"))) + (if (null line-points) + (progn (alert (ssg-text "vfc-alert-keine-gueltige-linie")) nil) (progn - (princ (ssg-text "vfc-eingabemodus-header")) - (princ (ssg-text "vfc-eingabemodus-3dlinie")) - (princ (ssg-text "vfc-eingabemodus-werte")) - (setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default"))) - ) - ) - (cond - ((= antwort "1") (setq eingabe-modus "Linie")) - ((= antwort "2") (setq eingabe-modus "Wert")) - (t (setq eingabe-modus "Linie") (princ (ssg-text "vfc-modus-3dlinie-fallback"))) - ) - (if (= eingabe-modus "Linie") - (progn - (princ (ssg-text "vfc-modus-3dlinie-header")) - (command "BKS" "W") - (princ (ssg-text "vfc-bks-weltkoordinaten")) - (setq line-points - (get-line-start-end-points (ssg-text "vfc-bitte-3dlinie-foerderstrecke"))) - (if (null line-points) - (progn (alert (ssg-text "vfc-alert-keine-gueltige-linie")) (exit)) - ) (setq startpunkt (car line-points) endpunkt (cadr line-points)) (setq differenz (punkt-differenz startpunkt endpunkt)) @@ -756,52 +742,14 @@ (progn (setq richtung "Ab") (setq deltaH (abs deltaH)) (princ (ssg-text "vfc-foerderrichtung-ab"))) ) - ;; Einfuegehoehe explizit abfragbar - ueberschreibt NUR die absolute - ;; Z-Hoehe des Startpunkts (Vorschlag = Z des Linien-Startpunkts, - ;; Enter uebernimmt ihn unveraendert). deltaH/Steigung bleiben davon - ;; unberuehrt, die kommen weiterhin aus der Geometrie der gepickten - ;; Linie selbst - nur WO die Anlage absolut eingefuegt wird, ist - ;; jetzt eingebbar (bisher ausschliesslich aus der Linie abgeleitet). - (setq hoehe-override - (getreal (ssg-textf "vfc-prompt-einfuegehoehe-3dlinie" - (list (rtos (caddr startpunkt) 2 1))))) - (if hoehe-override - (setq startpunkt (list (car startpunkt) (cadr startpunkt) hoehe-override))) - ) - (progn - (princ (ssg-text "vfc-modus-werteingabe-header")) - (setq deltaL (getreal (ssg-textf "vfc-prompt-delta-l" (list (chr 916))))) - (if (null deltaL) (setq deltaL 15000)) - (setq deltaH (getreal (ssg-textf "vfc-prompt-delta-h" (list (chr 916))))) - (if (null deltaH) (setq deltaH 3000)) - ;; Foerderrichtung bleibt eine einfache Auf/Ab-Frage - die horizontale - ;; Zwischenstrecke ist geometrisch NUR bei "Ab" ueberhaupt erreichbar - ;; (die festen 3-Grad-Elemente wirken immer absenkend) und wird daher - ;; erst SPAETER, nach Bibliotheks-Init, als Zusatzoption in der - ;; Winkel-Auswahl angeboten (siehe c:VarioFoerderer) - einheitlich fuer - ;; Werteingabe UND 3D-Linie. - (princ (ssg-text "vfc-foerderrichtung-menu")) - (setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default"))) - (if (= antwort "2") (setq richtung "Ab") (setq richtung "Auf")) - (setq startpunkt (getpoint (ssg-text "vfc-prompt-startpunkt-aus"))) - (if (null startpunkt) (setq startpunkt '(0 0 0))) - ;; Horizontale Fahrtrichtung waehlen (analog Gefaellestrecke Modus 1) - (princ (ssg-text "vfc-fahrtrichtung-header")) - (princ (ssg-textf "vfc-fahrtrichtung-0" (list grad-zeichen))) - (princ (ssg-textf "vfc-fahrtrichtung-90" (list grad-zeichen))) - (princ (ssg-textf "vfc-fahrtrichtung-180" (list grad-zeichen))) - (princ (ssg-textf "vfc-fahrtrichtung-270" (list grad-zeichen))) - (setq antwort (getstring (ssg-text "prompt-wahl-1-2-3-4"))) - (cond - ((= antwort "2") (setq hz-winkel 90.0)) - ((= antwort "3") (setq hz-winkel 180.0)) - ((= antwort "4") (setq hz-winkel 270.0)) - (t (setq hz-winkel 0.0)) - ) - (princ (ssg-textf "vfc-fahrtrichtung-ergebnis" (list (rtos hz-winkel 2 1) grad-zeichen))) + ;; Einfuegehoehe (Z des Startpunkts) wird NICHT mehr hier auf der + ;; Konsole abgefragt - sie geht als Prefill "einfuegehoehe" in den + ;; Basis-Dialog (vfs-dialog-eingabe-basis) ein, der dasselbe Feld + ;; ohnehin per GUI anzeigt und ueberschreibbar macht (Vorschlag = Z + ;; des Linien-Startpunkts, wie zuvor beim getreal-Prompt). + (list deltaL deltaH richtung startpunkt hz-winkel) ) ) - (list deltaL deltaH richtung startpunkt hz-winkel eingabe-modus) ) ;; ============================================================ @@ -1122,28 +1070,83 @@ ) ) -;; Neuanlage (Menue/Konsole -> Dialog) fuer einen Registry-Typ: Startpunkt -;; (X/Y) picken, Basis-Dialog, dann vf-dialog-berechnen-einfuegen. +;; Neuanlage (Menue/Konsole -> Dialog) fuer einen Registry-Typ. Zwei +;; Eingabemodi fuer die Geometrie (deltaL/deltaH/richtung/hz/Startpunkt): +;; "1" 3D-Linie: Linie picken (vfc-3dlinie-erfassen), die abgeleiteten +;; Werte gehen als Prefill in den Basis-Dialog - NUR Seite/ +;; Motorseite/Darstellung/Geruest bleiben dort fuer den Anwender offen. +;; "2" Werte: wie bisher Startpunkt (X/Y) picken, Basis-Dialog ohne +;; Geometrie-Prefill (Defaults). +;; Eingabemodus kommt per Vorauswahl (Menue-Wrapper c:StandardVarioFoerderer3D +;; / c:EtageVarioFoerderer3D setzen *vf-vorauswahl-eingabemodus* "1"/"2") oder +;; wird - wie zuvor im Konsolen-Ablauf - interaktiv erfragt; die Vorauswahl +;; gilt nur einmal. Ersetzt den frueheren Rueckfall auf den rein interaktiven +;; Konsolen-Ablauf (vf-eingabe-abfragen, entfernt) fuer die 3D-Linie: dieser +;; lief komplett an der GUI vorbei und fragte Seite/Fahrtrichtung/etc. erneut +;; auf der Kommandozeile ab, obwohl der Basis-Dialog dieselben Felder laengst +;; per GUI anbietet. (defun vf-dialog-ablauf (typ vf-nummer horizontal-p / eingabe deltaL deltaH richtung z-start hz seite startpunkt startpunkt-xy dim - geruest-einzelmodul geruest-typ motorseite) - (setq startpunkt-xy (vfc-dialog-startpunkt-waehlen "vfc-prompt-startpunkt-aus")) - (if (null startpunkt-xy) - (setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus")))) - (if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0))) - (setq eingabe (vfs-dialog-eingabe-basis nil)) - (if (null eingabe) + geruest-einzelmodul geruest-typ motorseite + antwort linie-erg basis-prefill abbruch) + (if *vf-vorauswahl-eingabemodus* + (setq antwort *vf-vorauswahl-eingabemodus* + *vf-vorauswahl-eingabemodus* nil) + (progn + (princ (ssg-text "vfc-eingabemodus-header")) + (princ (ssg-text "vfc-eingabemodus-3dlinie")) + (princ (ssg-text "vfc-eingabemodus-werte")) + (setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default"))) + ) + ) + (setq abbruch nil) + (if (= antwort "1") + (progn + (setq linie-erg (vfc-3dlinie-erfassen)) + (if (null linie-erg) + (setq abbruch t) + (progn + (setq deltaL (nth 0 linie-erg) + deltaH (nth 1 linie-erg) + richtung (nth 2 linie-erg) + startpunkt (nth 3 linie-erg) + hz (nth 4 linie-erg)) + (setq basis-prefill + (list (cons "deltaL" deltaL) (cons "deltaH" deltaH) (cons "richtung" richtung) + (cons "einfuegehoehe" (caddr startpunkt)) (cons "hz" hz))) + ) + ) + ) + (progn + (setq startpunkt-xy (vfc-dialog-startpunkt-waehlen "vfc-prompt-startpunkt-aus")) + (if (null startpunkt-xy) + (setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus")))) + (if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0))) + (setq startpunkt startpunkt-xy) + (setq basis-prefill nil) + ) + ) + (if abbruch (princ (ssg-text "vfc-vorgang-abgebrochen")) (progn - (vf-basis-eingabe-entpacken eingabe) - (setq startpunkt (list (car startpunkt-xy) (cadr startpunkt-xy) z-start)) - ;; Gewaehlte Dimension (2D/3D) + Motorseite fuer den Bau erzwingen, danach zurueck. - (setq *ssg-ils-dim* dim) - (setq *vf-motorseite* motorseite) - (vf-dialog-berechnen-einfuegen typ vf-nummer deltaL deltaH richtung startpunkt hz seite nil - geruest-einzelmodul geruest-typ horizontal-p) - (setq *ssg-ils-dim* nil) - (setq *vf-motorseite* nil) + (setq eingabe (vfs-dialog-eingabe-basis basis-prefill)) + (if (null eingabe) + (princ (ssg-text "vfc-vorgang-abgebrochen")) + (progn + (vf-basis-eingabe-entpacken eingabe) + ;; X/Y kommen aus dem Linien-Startpunkt (Modus 1) oder der + ;; separaten Punktwahl (Modus 2); Z immer aus dem Basis-Dialog + ;; (dort vorbelegt, aber ueberschreibbar). + (setq startpunkt (list (car startpunkt) (cadr startpunkt) z-start)) + ;; Gewaehlte Dimension (2D/3D) + Motorseite fuer den Bau erzwingen, danach zurueck. + (setq *ssg-ils-dim* dim) + (setq *vf-motorseite* motorseite) + (vf-dialog-berechnen-einfuegen typ vf-nummer deltaL deltaH richtung startpunkt hz seite nil + geruest-einzelmodul geruest-typ horizontal-p) + (setq *ssg-ils-dim* nil) + (setq *vf-motorseite* nil) + ) + ) ) ) ) @@ -1240,13 +1243,7 @@ ;; damit sie unabhaengig von der Lade-Reihenfolge existiert. (if (not (boundp '*vfl-forciere-qc-modus*)) (setq *vfl-forciere-qc-modus* nil)) (defun c:VarioFoerderer ( / typ-eintr anlage-typ berechne-fn einfuege-fn - eingabe deltaL deltaH richtung startpunkt seite hz - eingabe-modus ergebnis ergebnis-liste gueltige-winkel - horizontal-info - best-winkel L_GF L_GF1 L_GF2 L_VF - idx eintrag wahl antwort verteilung-modus - n-scanner vf-nummer hoehe-von hoehe-bis lastEnt - staustrecke-basis vf-insert dlg-typ zurueck-zu-typ) + idx wahl vf-nummer dlg-typ zurueck-zu-typ) (princ "\n=========================================") (princ (ssg-text "vfc-banner-titel")) @@ -1343,215 +1340,26 @@ (setq vf-nummer (vf-next-number)) (princ (ssg-textf "vfc-naechste-vf-nummer" (list (itoa vf-nummer)))) - ;; 2b. Standard- ODER Etage-Typ + Werteingabe -> DCL-Dialog - ;; (dcl/variofoerderer.dcl; Standard: vfs-standard-dialog-ablauf in - ;; vf_standard.lsp, Etage: vfe-etage-dialog-ablauf in vf_etage.lsp - beide - ;; nutzen dieselben Dialoge vfs-dialog-eingabe-basis/-winkel-verteilung). - ;; 3D-Linie-Eingabe und der Typ Linienzug bleiben unveraendert interaktiv - ;; (fallen unten in den Konsolen-Ablauf, der die Eingabemodus-Frage erneut - ;; stellt - siehe vf-eingabe-abfragen). + ;; 2b. Standard- ODER Etage-Typ -> DCL-Dialog (dcl/variofoerderer.dcl; + ;; Standard: vfs-standard-dialog-ablauf in vf_standard.lsp, Etage: + ;; vfe-etage-dialog-ablauf in vf_etage.lsp - beide duenne Wrapper um + ;; vf-dialog-ablauf). Die Eingabemodus-Frage (3D-Linie vs. Werte) stellt + ;; vf-dialog-ablauf selbst, VOR dem Basis-Dialog - bei 3D-Linie gehen + ;; deltaL/deltaH/Richtung/Einfuegehoehe als Prefill in denselben + ;; Basis-Dialog ein, den auch die Werteingabe nutzt (siehe dortiger + ;; Kopfkommentar). Damit entfaellt der fruehere rein interaktive + ;; Konsolen-Ablauf (Schritte 3-11, vf-eingabe-abfragen) komplett - er lief + ;; bei 3D-Linie an der GUI vorbei und fragte Seite/Fahrtrichtung/Verteilung + ;; erneut auf der Kommandozeile ab, obwohl der Dialog dieselben Felder + ;; laengst per GUI anbietet. (if (member anlage-typ '("standard" "etage")) (progn - ;; Eingabemodus: Vorauswahl (Menue-Wrapper) hat Vorrang, sonst fragen. - (if *vf-vorauswahl-eingabemodus* - (setq antwort *vf-vorauswahl-eingabemodus*) - (progn - (princ (ssg-text "vfc-eingabemodus-header")) - (princ (ssg-text "vfc-eingabemodus-3dlinie")) - (princ (ssg-text "vfc-eingabemodus-werte")) - (setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default"))) - ) - ) - (if (= antwort "2") - (progn - (if (= anlage-typ "etage") - (vfe-etage-dialog-ablauf vf-nummer) - (vfs-standard-dialog-ablauf vf-nummer)) - (exit) - ) - ) - ) - ) - - ;; 3. Gemeinsame Eingabe (deltaL, deltaH, richtung, startpunkt) - richtung - ;; steht bei beiden Eingabemodi (Werteingabe UND 3D-Linie) bereits fest. - (setq eingabe (vf-eingabe-abfragen)) - (setq deltaL (nth 0 eingabe) - deltaH (nth 1 eingabe) - richtung (nth 2 eingabe) - startpunkt (nth 3 eingabe) - hz (nth 4 eingabe) - eingabe-modus (nth 5 eingabe)) - - ;; 4. Seite-Auswahl (vor Berechnung, weil Etage-Typ sie fuer Geometrie braucht) - (princ (ssg-text "vfc-seite-header")) - (princ (ssg-text "vfc-seite-rechts")) - (princ (ssg-text "vfc-seite-links")) - (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) - (if (= antwort "2") (setq seite "links") (setq seite "rechts")) - (princ (ssg-textf "vfc-seite-gewaehlt" (list seite))) - - ;; 5. Typ-spezifische Berechnung (init + Winkelsuche) - (setq ergebnis (apply berechne-fn (list deltaL deltaH richtung seite))) - (setq ergebnis-liste (cadddr ergebnis)) - - ;; 5b. Horizontale Zwischenstrecke als Zusatzoption: geometrisch NUR bei - ;; "Ab" ueberhaupt erreichbar (die festen 3-Grad-Elemente wirken immer - ;; absenkend) - "Auf" wird deshalb gar nicht erst geprueft. Gilt einheitlich - ;; fuer Werteingabe UND 3D-Linie, da richtung hier in jedem Fall feststeht. - ;; Bibliothek ist durch den berechne-fn-Aufruf oben bereits initialisiert. - (if (and (= anlage-typ "standard") (= richtung "Ab")) - (progn - (setq horizontal-info (berechne-horizontale-mitte deltaL deltaH "Ab" nil)) - (if (and horizontal-info (caddr horizontal-info)) - (progn - (setq ergebnis-liste - (append ergebnis-liste - (list (list 0 (car horizontal-info) (cadr horizontal-info) T)))) - (princ (ssg-textf "vfc-hinweis-horizontal-moeglich" (list (chr 176) (chr 916)))) - ) - (setq horizontal-info nil) - ) - ) - ) - - ;; Konfiguration (nach ssg_core-Init verfuegbar). - (setq staustrecke-basis (ssg-cfg-or "vario" "staustrecke_basis" 1000)) - - ;; 7. Gueltige Winkel ermitteln - (setq gueltige-winkel - (mapcar 'car - (vl-remove-if-not - (function (lambda (e) (and (nth 3 e) - (numberp (nth 1 e)) (numberp (nth 2 e)) - (>= (nth 1 e) 0) (>= (nth 2 e) 0)))) - ergebnis-liste))) - (if (null gueltige-winkel) - (progn - (alert (ssg-textf "vfc-alert-kein-winkel" - (list (chr 916) (rtos deltaL 2 0) (rtos deltaH 2 0) richtung))) + (if (= anlage-typ "etage") + (vfe-etage-dialog-ablauf vf-nummer) + (vfs-standard-dialog-ablauf vf-nummer)) (exit) ) ) - - ;; 8. Winkelauswahl (automatisch oder interaktiv) - ;; Sentinel-Winkel 0 = horizontale Zwischenstrecke (Schritt 6/11 bei 0 - ;; Grad, Boegen fest auf_3/ab_3) - siehe berechne-horizontale-mitte. - (if (= (length gueltige-winkel) 1) - (progn - (setq best-winkel (car gueltige-winkel)) - (setq eintrag (assoc best-winkel ergebnis-liste)) - (setq L_GF (nth 1 eintrag) L_VF (nth 2 eintrag)) - (if (= best-winkel 0) - (princ (ssg-text "vfc-einzige-variante-horizontal")) - (princ (ssg-textf "vfc-einziger-winkel" (list (itoa best-winkel) (chr 176)))) - ) - ) - (progn - (princ (ssg-text "vfc-mehrere-winkel-header")) - (setq idx 1) - (foreach w gueltige-winkel - (setq eintrag (assoc w ergebnis-liste)) - (if (= w 0) - (princ (ssg-textf "vfc-winkel-option-horizontal" - (list idx (chr 176) - (rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1)))) - (princ (ssg-textf "vfc-winkel-option" - (list idx (itoa w) (chr 176) - (rtos (nth 1 eintrag) 2 1) (rtos (nth 2 eintrag) 2 1)))) - ) - (setq idx (1+ idx)) - ) - (setq wahl (getint (ssg-textf "vfc-prompt-winkel-waehlen" - (list (length gueltige-winkel))))) - (if (or (null wahl) (< wahl 1) (> wahl (length gueltige-winkel))) - (setq wahl 1)) - (setq best-winkel (nth (1- wahl) gueltige-winkel)) - (setq eintrag (assoc best-winkel ergebnis-liste)) - (setq L_GF (nth 1 eintrag) L_VF (nth 2 eintrag)) - ) - ) - (princ "\n\n=========================================") - (if (= best-winkel 0) - (princ (ssg-textf "vfc-zus-horizontal" - (list (rtos L_GF 2 2) (rtos L_VF 2 2)))) - (princ (ssg-textf "vfc-zus-winkel" - (list (itoa best-winkel) (chr 176) (rtos L_GF 2 2) (rtos L_VF 2 2)))) - ) - (princ "\n=========================================") - - ;; 9. L_GF Verteilung - (princ (ssg-text "vfc-gf-verteilung-header")) - (princ (ssg-text "vfc-gf-verteilung-1")) - (princ (ssg-text "vfc-gf-verteilung-2")) - (princ (ssg-text "vfc-gf-verteilung-3")) - (princ (ssg-text "vfc-gf-verteilung-4")) - (setq verteilung-modus (getstring (ssg-text "prompt-wahl-1-2-3-4"))) - (if (= verteilung-modus "") (setq verteilung-modus "1")) - (cond - ((= verteilung-modus "1") - (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0))) - ((= verteilung-modus "2") - (setq L_GF1 (float staustrecke-basis)) - (setq L_GF2 (max 0.0 (- L_GF (float staustrecke-basis))))) - ((= verteilung-modus "3") - (setq L_GF2 (float staustrecke-basis)) - (setq L_GF1 (max 0.0 (- L_GF (float staustrecke-basis))))) - ((= verteilung-modus "4") - (setq L_GF1 (getreal (ssg-textf "vfc-prompt-lgf1-vorne" - (list (rtos (/ L_GF 2.0) 2 2))))) - (if (null L_GF1) (setq L_GF1 (/ L_GF 2.0))) - (setq L_GF2 (max 0.0 (- L_GF L_GF1))) - (princ (ssg-textf "vfc-lgf2-hinten" (list (rtos L_GF2 2 2))))) - (t (setq L_GF1 (/ L_GF 2.0) L_GF2 (/ L_GF 2.0))) - ) - (princ (ssg-textf "vfc-zus-lgf" (list (rtos L_GF1 2 2) (rtos L_GF2 2 2)))) - - ;; Scanner-Anzahl wird nicht mehr abgefragt (Attribut ANZAHL_SCANNER bleibt 0). - (setq n-scanner 0) - - ;; 11. Bestaetigung - (princ (ssg-text "vfc-einfuegen-frage")) - (princ (ssg-text "vfc-einfuegen-optionen")) - (setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default"))) - - (if (= antwort "1") - (progn - ;; Hoehenangaben fuer Attribute und Beschriftung - (setq hoehe-von (caddr startpunkt)) - (setq hoehe-bis (cond - ((= richtung "Auf") (+ hoehe-von deltaH)) - ((= richtung "Ab") (- hoehe-von deltaH)) - (t hoehe-von))) - - ;; lastEnt VOR der Einfuegung merken - (setq lastEnt (ssg-lastent-ohne-attribute)) - - ;; Typ-spezifische Einfuegung - (apply einfuege-fn - (list deltaL deltaH richtung best-winkel L_GF1 L_GF2 L_VF startpunkt seite hz)) - - ;; Gemeinsame VF_*-Block-Erstellung - ;; Geruest fuer Einzelmodul/Geruestoption sind in diesem interaktiven - ;; Konsolen-Ablauf (Etage/Linienzug) nicht abfragbar - bleiben auf - ;; Schema-Default (analog Kreisel: nur ueber Dialog editierbar). - (setq vf-insert - (vf-block-erstellen anlage-typ seite vf-nummer n-scanner - hoehe-von hoehe-bis deltaH deltaL L_VF L_GF1 L_GF2 - richtung best-winkel startpunkt lastEnt hz - "0" "Schoenenberger Geruest")) - - ;; Standard- UND Etage-Bloecke aus dem interaktiven Konsolen-Ablauf mit der - ;; SSG_VF_EDIT-XDATA markieren - sie sind (wie die Dialog-Variante) aus - ;; Attributen + hz verlustfrei rekonstruierbar, also per Doppelklick - ;; (c:VARIOFOERDERER_EDIT) editierbar. Linienzug bleibt unmarkiert. - (if (and vf-insert (member anlage-typ '("standard" "etage"))) - (vf-edit-xdata-schreiben vf-insert anlage-typ hz)) - - (princ "\n=========================================") - ) - (princ (ssg-text "vfc-vorgang-abgebrochen")) - ) nil ) diff --git a/Lisp/vf_standard.lsp b/Lisp/vf_standard.lsp index 8c3b8e9..b5e10f0 100644 --- a/Lisp/vf_standard.lsp +++ b/Lisp/vf_standard.lsp @@ -803,11 +803,13 @@ ;; ============================================================ ;; DCL-DIALOG (Standardfall) - dcl/variofoerderer.dcl -;; Ersetzt die interaktive Werteingabe aus vf-eingabe-abfragen -;; (Konsolen-Modus "Werteingabe") fuer anlage-typ "standard" durch -;; zwei DCL-Dialoge: Basis-Eingabe und Winkel/Verteilung. Die -;; 3D-Linie-Eingabe sowie die Typen "etage"/"linienzug" bleiben -;; unveraendert interaktiv (siehe Verzweigung in c:VarioFoerderer). +;; Ersetzt die frueher komplett interaktive Werteingabe fuer anlage-typ +;; "standard" durch zwei DCL-Dialoge: Basis-Eingabe und Winkel/Verteilung. +;; Beide Eingabemodi (3D-Linie UND Werteingabe, siehe vf-dialog-ablauf in +;; vf_core.lsp) laufen seitdem ueber denselben Basis-Dialog - bei 3D-Linie +;; nur mit deltaL/deltaH/Richtung/Einfuegehoehe vorbelegt. Nur der Typ +;; "linienzug" bleibt unveraendert interaktiv (siehe Verzweigung in +;; c:VarioFoerderer). ;; ;; Beide Dialoge existieren je in zwei Varianten: ;; -popup (Dropdowns, urspruengliche Implementierung, unveraendert) und diff --git a/doc/faq.md b/doc/faq.md index ae244c2..e4a57c7 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -197,7 +197,7 @@ Varioförderer können auf verschiedene Arten gebaut werden: 1. Standard 2. Etage -3. Variabel +3. Streckengruppe - Manuelle Eingabe - 3D-OBjekte mit Ziel-höhe - 3D Objekte Stückweise (wird gerade noch implementiert bzw. ist expirementell) @@ -207,13 +207,13 @@ Der **"Standard Förderer"** ist die Verbindung von zwei Kreiseln mit einem defi Ein **Etagenförderer** hat 30° Aussschleuselemente und wird verwendet, um zwei Kreisel über eine Etage zu verbinden. Diese beiden Kreisel müssen dabei übereinander liegen. Standard und Etage können aufgerufen werden mit _"Werte manuell"_ oder _"3D - Linie"_. -- Bei "Werte Manuell" definiert man den Verlauf durch Höhe und Länge über die Eingabe in einer Oberfläche. -- bei "3D Linie" ist die Auswahl einer Gerade im Raum möglich. Damit wird Richtung, Länge und Höhendifferenz angegeben. Dadurch werden diese Werte in die Oberfläche übernommen. Der beliebige Winkel in der Ebene kann durch die Linie festgelegt werden und ist nicht auf die Raster 0,90,270 Grad festgelegt +- Bei "_Werte Manuell_" definiert man den Verlauf durch Höhe und Länge über die Eingabe in einer Oberfläche. +- bei "_3D Linie_" ist die Auswahl einer Gerade im Raum möglich. Damit wird Richtung, Länge und Höhendifferenz angegeben. Dadurch werden diese Werte in die Oberfläche übernommen. Der beliebige Winkel in der Ebene kann durch die Linie festgelegt werden und ist nicht auf die Raster 0,90,270 Grad festgelegt Die **Variablen Förderer** könne auf drei verschiedene Arten definiert werden: -- die manuelle Eingabe frägt nach der Definition des AS Elementes ab, ob man abwechselnd eine GF oder einen VF definieren möchte. Mit einem Knopf unten kann man den Assistenten abschliessen und das ES erzeugen -- Eine 3D Linie muss aus Geraden und Bögen (Winkel 30° mit dem Radius 500mm) bestehen. Wenn eine 3D Linie für Verlauf mit der korrekten Zielhöhe existiert, kann man iterativ die Einzelelemente (oder auch mehrere) dieser Einzellinien Linie anwählen, um den nächsten Förderer oder den nöchsten Gefälle-Anteil zu definieren. +- die _manuelle Eingabe_ frägt nach der Definition des AS Elementes ab, ob man abwechselnd eine GF oder einen VF definieren möchte. Mit einem Knopf unten kann man den Assistenten abschliessen und das ES erzeugen +- _Eine 3D Linie_ muss aus Geraden und Bögen (Winkel 30° mit dem Radius 500mm) bestehen. Wenn eine 3D Linie für Verlauf mit der korrekten Zielhöhe existiert, kann man iterativ die Einzelelemente (oder auch mehrere) dieser Einzellinien Linie anwählen, um den nächsten Förderer oder den nöchsten Gefälle-Anteil zu definieren. ### 3.1 Zusammensetzung, Abhängigkeiten, Randbedingungen @@ -268,7 +268,7 @@ Unter *ILS -> Foerderer* stehen folgende Einfügemodi zur Verfügung: #### Wie baue ich einen VF in einem Puffer mit Gefällestrecken als Umschleusung? -Ich baue eine Gefällestrecke und kann dann mit einem Klick einen Varioförderer daneben bauen. +Ich baue eine Gefällestrecke und kann dann mit einem Klick einen Varioförderer daneben bauen. Dazu die Gefällestrecke doppelklicken und dann auf den Knopf "VarioFoerderer daneben bauen" klicken. ![Variofoerderer dialog2](images/gf-vf-kombination.png) *Abbildung: Erzeugung eines Varioförderers passend zur Gefällestrecke* @@ -279,14 +279,18 @@ Das macht man aus einer Streckengruppe aus aus mindestens einer GF und einer VF #### Wie baue ich einen VF als Übergang zwischen zwei verschiedenen Kreiseln (unterschiedliche Höhe und Position x/y/z) Standardfall. Höhenunterschiede und Einfügehöhe einfach in Interface angeben. +![Variofoerderer dialog1](images/vf-gui1.png) +*Abbildung: Varioförderer Dialog zur Erzeugung* + #### Wie baue ich einen Förderer zu Ebenenüberquerung zwischen zwei Pufferblöcken, welche übereinander positioniert sind? Dafür ist der sogenannte Etagenförderer vorgesehen. +*ILS -> Foerderer-> Etage* #### Wie baue ich eine Strecke mit mehreren VF und Gefällestrecken hintereinander zur Überbrückung von großen Entfernungen? -Dies kann nur Stückweise erfolgen, indem man ausprobiert, welche GF VF Kombination welche Länge erreicht und dabei eine gewünschte Höhe nicht überschreitet. Danach kann man die einzelnen Einheiten zu einem Mergen. +Dies kann nur Stückweise erfolgen, indem man ausprobiert, welche GF VF Kombination welche Länge erreicht und dabei eine gewünschte Höhe nicht überschreitet. Danach kann man die einzelnen Einheiten zu Einem Mergen. ## 4. Scanner und Separator @@ -300,7 +304,7 @@ Es gibt hier **kein** Koordinatensystem-Verkettungssystem wie bei Gefällestreck #### In welchen Baugruppen sind Scanner und Separatoren bereits eingebaut (Blöcke)? -Innerhalb von Gefällestrecken- und Varioförderer-Ketten wird intern automatisch ein Separator eingefügt (als Trennsteg zwischen den Staustrecken-Segmenten). Diese verpackten Separatoren werden beim Export erkannt und in den Attributen "Anzahl Separator"/"Anzahl Scanner" der jeweiligen Baugruppe mitgezählt. +Innerhalb von **Gefällestrecken-** und **Varioförderer**-Ketten wird intern automatisch ein Separator eingefügt (als Trennsteg zwischen den Staustrecken-Segmenten). Diese verpackten Separatoren werden beim Export erkannt und in den Attributen "Anzahl Separator"/"Anzahl Scanner" der jeweiligen Baugruppe mitgezählt. Reine Scanner-Blöcke sind dagegen **nicht** standardmässig in Gefällestrecke/Varioförderer/Kreisel verbaut – sie kommen nur als frei platzierte Einzelblöcke vor. @@ -308,7 +312,9 @@ Reine Scanner-Blöcke sind dagegen **nicht** standardmässig in Gefällestrecke/ Es gibt **keine feste Verknüpfung** zum Zeitpunkt des Einfügens. Die Zuordnung erfolgt erst **nachträglich beim Export** über die geometrische Nähe: Scanner außerhalb einer Baugruppen-Umgrenzung werden per Abstand der nächstgelegenen Baugruppe zugeordnet; ist der Abstand zu mehreren Kandidaten nahezu gleich, wird das als "strittig" markiert und im Export entsprechend vermerkt. -Für Separatoren, die bereits in einer Kette verbaut sind, ist die Zuordnung dagegen von vornherein eindeutig. **Fazit**: Die Zuordnung frei platzierter Scanner/Separatoren ist rein geometrisch (Abstand), keine feste Verknüpfung. +Für Separatoren, die bereits in einer Kette verbaut sind, ist die Zuordnung dagegen von vornherein eindeutig. + +**Fazit**: Die Zuordnung frei platzierter Scanner/Separatoren ist rein geometrisch (Abstand), keine feste Verknüpfung. ### 4.2 Funktionen diff --git a/lang/de_DE.json b/lang/de_DE.json index f163985..f1d84dd 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -332,7 +332,6 @@ "vfc-delta-l-h-richtung": "\n %1L=%2 mm %1H=%3 mm Fahrtrichtung=%4%5", "vfc-endpunkt-xyz": "\n KS_AUS: X=%1 Y=%2 Z=%3", "vfc-endpunkt-xyz-dxdz": "\n KS_AUS: X=%1 Y=%2 Z=%3 (dx=%4 dz=%5)", - "vfc-fahrtrichtung-ergebnis": "\n>>> Fahrtrichtung: %1%2", "vfc-fehler-block-datei-fehlt": "\n FEHLER: Block-Datei nicht gefunden: %1", "vfc-fehler-block-nicht-in-bibliothek": "\n FEHLER: Block '%1' nicht in Bibliothek", "vfc-fehler-block-nicht-in-bibliothek-abgebrochen": "\n FEHLER: Block '%1' nicht in Bibliothek - abgebrochen", @@ -506,30 +505,14 @@ "vfc-eingabemodus-3dlinie": "\n 1 - 3D-Linie auswaehlen (Start- und Endpunkt mit Hoehe)", "vfc-eingabemodus-header": "\n\nEingabemodus waehlen:", "vfc-eingabemodus-werte": "\n 2 - Werte manuell eingeben", - "vfc-fahrtrichtung-0": "\n 1 - 0%1 (X-Achse +, Ost)", - "vfc-fahrtrichtung-180": "\n 3 - 180%1 (X-Achse -, West)", - "vfc-fahrtrichtung-270": "\n 4 - 270%1 (Y-Achse -, Sued)", - "vfc-fahrtrichtung-90": "\n 2 - 90%1 (Y-Achse +, Nord)", - "vfc-fahrtrichtung-header": "\n\nFahrtrichtung waehlen:", "vfc-fehler-keine-linie": "\n FEHLER: Keine Linie oder Polylinie ausgewaehlt!", "vfc-foerderrichtung-ab": "\n Foerderrichtung: AB", "vfc-foerderrichtung-auf": "Auf", - "vfc-foerderrichtung-menu": "\nFoerderrichtung:\n 1 - AUF\n 2 - AB", - "vfc-gf-verteilung-header": "\n\nVerteilung der Gefaellestrecken (vorne/hinten):", - "vfc-gf-verteilung-1": "\n 1 - Gleichmaessig (L_GF1 = L_GF2 = L_GF/2)", - "vfc-gf-verteilung-2": "\n 2 - Vorne Minimum, hinten Rest", - "vfc-gf-verteilung-3": "\n 3 - Hinten Minimum, vorne Rest", - "vfc-gf-verteilung-4": "\n 4 - Eigene Werte eingeben", "vfc-kein-objekt-gewaehlt": "\n Kein Objekt gewaehlt.", "vfc-label-von-bis": ": von %1mm bis %2mm, ", "vfc-linie-polylinie-waehlen": "\n >> 3D-Linie oder Polylinie waehlen: ", - "vfc-modus-3dlinie-fallback": "Linie", "vfc-modus-3dlinie-header": "\n\n>>> MODUS: 3D-Linie auswaehlen <<<", - "vfc-modus-werteingabe-header": "\n\n>>> MODUS: Manuelle Werteingabe <<<", "vfc-objekt-block-waehlen": "\n >> Objekt (Block) waehlen: ", - "vfc-prompt-delta-h": "\n%1H - Hoehenunterschied (mm): ", - "vfc-prompt-delta-l": "\n%1L - Horizontale Distanz (mm): ", - "vfc-prompt-einfuegehoehe-3dlinie": "\nEinfuegehoehe (mm) [%1 - Hoehe des Linien-Startpunkts]: ", "vfc-prompt-startpunkt-aus": "\nStartpunkt fuer AUS_Element waehlen: ", "vfc-prompt-wahl-1-2-ohne-default": "\nIhre Wahl (1/2): ", "vfc-status-ok": " OK", @@ -544,25 +527,7 @@ "vfc-prompt-wahl-1-n": "\nIhre Wahl (1-%1) [1]: ", "vfc-typ-gewaehlt": "\n>>> Typ: %1", "vfc-naechste-vf-nummer": "\n>>> Naechste VF-Nummer: VF%1", - "vfc-seite-header": "\n\nSeite waehlen:", - "vfc-seite-rechts": "\n 1 - Rechts", - "vfc-seite-links": "\n 2 - Links", - "vfc-seite-gewaehlt": "\n>>> Seite: %1", - "vfc-hinweis-horizontal-moeglich": "\n\n>>> Hinweis: Ein horizontale Variofoerderer ( 0%1) ist bei diesem %2L/%2H zusaetzlich moeglich!", "vfc-alert-kein-winkel": "Kein passender Winkel gefunden!\n%1L=%2 mm, %1H=%3 mm, Richtung=%4", - "vfc-einzige-variante-horizontal": "\n\n>>> Einzige gueltige Variante: Horizontale Variofoerderer", - "vfc-einziger-winkel": "\n\n>>> Einziger gueltiger Winkel: %1%2", - "vfc-mehrere-winkel-header": "\n\nMehrere gueltige Winkel verfuegbar. Bitte waehlen:", - "vfc-winkel-option-horizontal": "\n %1 - Horizontale Variofoerderer (0%2) (L_GF=%3 mm, L_VF=%4 mm)", - "vfc-winkel-option": "\n %1 - %2%3 (L_GF=%4 mm, L_VF=%5 mm)", - "vfc-prompt-winkel-waehlen": "Winkel waehlen (1-%1) [1]: ", - "vfc-zus-horizontal": "\n>>> Horizontale Variofoerderer L_GF: %1 mm L_VF: %2 mm", - "vfc-zus-winkel": "\n>>> Winkel: %1%2 L_GF: %3 mm L_VF: %4 mm", - "vfc-prompt-lgf1-vorne": "\nL_GF1 vorne (mm) [%1]: ", - "vfc-lgf2-hinten": "\n L_GF2 hinten: %1 mm", - "vfc-zus-lgf": "\n>>> L_GF1=%1 mm L_GF2=%2 mm", - "vfc-einfuegen-frage": "\n\nMoechten Sie die Foerderanlage einfuegen?", - "vfc-einfuegen-optionen": "\n 1 - Ja, Module einfuegen\n 2 - Nein, abbrechen", "vfc-vorgang-abgebrochen": "\nVorgang abgebrochen.", "vfs-dlg-richtung-auf": "Auf", "vfs-dlg-richtung-ab": "Ab", diff --git a/lang/en_GB.json b/lang/en_GB.json index 5d7eba5..5888297 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -332,7 +332,6 @@ "vfc-delta-l-h-richtung": "\n %1L=%2 mm %1H=%3 mm Travel direction=%4%5", "vfc-endpunkt-xyz": "\n KS_AUS: X=%1 Y=%2 Z=%3", "vfc-endpunkt-xyz-dxdz": "\n KS_AUS: X=%1 Y=%2 Z=%3 (dx=%4 dz=%5)", - "vfc-fahrtrichtung-ergebnis": "\n>>> Travel direction: %1%2", "vfc-fehler-block-datei-fehlt": "\n ERROR: block file not found: %1", "vfc-fehler-block-nicht-in-bibliothek": "\n ERROR: block '%1' not in library", "vfc-fehler-block-nicht-in-bibliothek-abgebrochen": "\n ERROR: block '%1' not in library - cancelled", @@ -506,30 +505,14 @@ "vfc-eingabemodus-3dlinie": "\n 1 - Select 3D line (start and end point with height)", "vfc-eingabemodus-header": "\n\nSelect input mode:", "vfc-eingabemodus-werte": "\n 2 - Enter values manually", - "vfc-fahrtrichtung-0": "\n 1 - 0%1 (X axis +, East)", - "vfc-fahrtrichtung-180": "\n 3 - 180%1 (X axis -, West)", - "vfc-fahrtrichtung-270": "\n 4 - 270%1 (Y axis -, South)", - "vfc-fahrtrichtung-90": "\n 2 - 90%1 (Y axis +, North)", - "vfc-fahrtrichtung-header": "\n\nSelect travel direction:", "vfc-fehler-keine-linie": "\n ERROR: No line or polyline selected!", "vfc-foerderrichtung-ab": "\n Conveying direction: DOWN", "vfc-foerderrichtung-auf": "Up", - "vfc-foerderrichtung-menu": "\nConveying direction:\n 1 - UP\n 2 - DOWN", - "vfc-gf-verteilung-header": "\n\nDistribution of slope sections (front/rear):", - "vfc-gf-verteilung-1": "\n 1 - Even (L_GF1 = L_GF2 = L_GF/2)", - "vfc-gf-verteilung-2": "\n 2 - Front minimum, rear remainder", - "vfc-gf-verteilung-3": "\n 3 - Rear minimum, front remainder", - "vfc-gf-verteilung-4": "\n 4 - Enter custom values", "vfc-kein-objekt-gewaehlt": "\n No object selected.", "vfc-label-von-bis": ": from %1mm to %2mm, ", "vfc-linie-polylinie-waehlen": "\n >> Select 3D line or polyline: ", - "vfc-modus-3dlinie-fallback": "Line", "vfc-modus-3dlinie-header": "\n\n>>> MODE: Select 3D line <<<", - "vfc-modus-werteingabe-header": "\n\n>>> MODE: Manual value entry <<<", "vfc-objekt-block-waehlen": "\n >> Select object (block): ", - "vfc-prompt-delta-h": "\n%1H - height difference (mm): ", - "vfc-prompt-delta-l": "\n%1L - horizontal distance (mm): ", - "vfc-prompt-einfuegehoehe-3dlinie": "\nInsertion height (mm) [%1 - height of the line start point]: ", "vfc-prompt-startpunkt-aus": "\nSelect start point for AUS_Element: ", "vfc-prompt-wahl-1-2-ohne-default": "\nYour choice (1/2): ", "vfc-status-ok": " OK", @@ -544,25 +527,7 @@ "vfc-prompt-wahl-1-n": "\nYour choice (1-%1) [1]: ", "vfc-typ-gewaehlt": "\n>>> Type: %1", "vfc-naechste-vf-nummer": "\n>>> Next VF number: VF%1", - "vfc-seite-header": "\n\nSelect side:", - "vfc-seite-rechts": "\n 1 - Right", - "vfc-seite-links": "\n 2 - Left", - "vfc-seite-gewaehlt": "\n>>> Side: %1", - "vfc-hinweis-horizontal-moeglich": "\n\n>>> Note: a horizontal VarioFoerderer ( 0%1) is additionally possible for this %2L/%2H!", "vfc-alert-kein-winkel": "No suitable angle found!\n%1L=%2 mm, %1H=%3 mm, direction=%4", - "vfc-einzige-variante-horizontal": "\n\n>>> Only valid variant: horizontal VarioFoerderer", - "vfc-einziger-winkel": "\n\n>>> Only valid angle: %1%2", - "vfc-mehrere-winkel-header": "\n\nSeveral valid angles available. Please choose:", - "vfc-winkel-option-horizontal": "\n %1 - Horizontal VarioFoerderer (0%2) (L_GF=%3 mm, L_VF=%4 mm)", - "vfc-winkel-option": "\n %1 - %2%3 (L_GF=%4 mm, L_VF=%5 mm)", - "vfc-prompt-winkel-waehlen": "Select angle (1-%1) [1]: ", - "vfc-zus-horizontal": "\n>>> Horizontal VarioFoerderer L_GF: %1 mm L_VF: %2 mm", - "vfc-zus-winkel": "\n>>> Angle: %1%2 L_GF: %3 mm L_VF: %4 mm", - "vfc-prompt-lgf1-vorne": "\nL_GF1 front (mm) [%1]: ", - "vfc-lgf2-hinten": "\n L_GF2 rear: %1 mm", - "vfc-zus-lgf": "\n>>> L_GF1=%1 mm L_GF2=%2 mm", - "vfc-einfuegen-frage": "\n\nDo you want to insert the conveyor system?", - "vfc-einfuegen-optionen": "\n 1 - Yes, insert modules\n 2 - No, cancel", "vfc-vorgang-abgebrochen": "\nProcess cancelled.", "vfs-dlg-richtung-auf": "Up", "vfs-dlg-richtung-ab": "Down", From 8eed3e438ff9d308924675bc0c98a5ccfba15110 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 10:15:58 +0200 Subject: [PATCH 23/38] [DOC] README.md auf aktuellen Stand gebracht (Menuestruktur, MENULOAD-Lademechanismus, Projektstruktur, Umgebungsvariablen) Veraltete Inhalte entfernt (alter on_start.lsp/startup.scr-Loader, fehlende Module wie Geruest/SPS/Connections/TRO, nicht mehr existierende Verzeichnisse/Variablen). Detaillierte Modul-/Befehlsdokumentation wird nicht mehr dupliziert, sondern per Verweis auf CLAUDE.md und Lisp/README.md gefuehrt. Co-Authored-By: Claude Sonnet 5 --- README.md | 229 ++++++++++++++++-------------------------------------- 1 file changed, 68 insertions(+), 161 deletions(-) diff --git a/README.md b/README.md index 9f9bdfc..61630db 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # dxfmakros -AutoLISP-Makros fuer BricsCAD Pro zur automatisierten Erstellung von Foerderanlagen- und Kreisel-Layouts. +AutoLISP-Makros (SSG_LIB) fuer BricsCAD Pro zur automatisierten Erstellung von Foerderanlagen-Layouts (ILS Kreisel, Omniflo, VarioFoerderer, Gefaellestrecke, Geruest). ## Menustruktur (SSG_LIB) @@ -14,164 +14,70 @@ SSG_LIB │ │ └── Eckrad → ILS_Eckrad │ ├── Zusatzmodul │ │ ├── BTMT-Beladung → ILS_BTMT_Beladung -│ │ └── BTMT-Entladung → ILS_BTMT_Entladung +│ │ ├── BTMT-Entladung → ILS_BTMT_Entladung +│ │ ├── Scanner einfuegen → ILS_SCANNER_INSERT +│ │ └── Separator einfuegen → ILS_SEPARATOR_INSERT │ ├── Foerderer -│ │ ├── VarioFoerderer → FOERDERANLAGE -│ │ └── Gefaellestrecke → ILS_G{K90,K60,K30}{L,R} -│ └── ILS Schliessen +│ │ ├── Standard → StandardVarioFoerderer / StandardVarioFoerderer3D +│ │ ├── Etage → EtageVarioFoerderer / EtageVarioFoerderer3D +│ │ ├── Streckengruppe (Linienzug) → LinienzugVarioFoerdererManuell / -Zielhoehe / -Stueckweise +│ │ └── Vario_Kette_Merge / VARIOFOERDERER_NACHRUESTEN +│ └── Gefaellestrecke +│ ├── einfach → GEFAELLESTRECKE_EINFACH +│ ├── aus 3D-Linie → GEFAELLESTRECKE_3DLINIE +│ └── aus Linienzug → GEFAELLESTRECKE_LINIENZUG ├── Omniflo -│ ├── Boegen -│ │ ├── 90 → OMNI_APB_630_90 -│ │ ├── 67.5 → OMNI_APB_550_675 -│ │ ├── 45 → OMNI_APB_630_45 -│ │ ├── 22.5 → OMNI_APB_550_225 -│ │ └── 180 → OMNI_APB_650_180 -│ ├── Aluprofil Gerade -│ │ ├── AP 60 → OMNI_AP60 -│ │ ├── AP 110 → OMNI_AP110 -│ │ └── APG 110 → OMNI_APG110 -│ ├── Weiche 90 Grad -│ │ ├── Einfach → OMNI_W90_Einfach -│ │ ├── Doppel → OMNI_W90_Doppel -│ │ └── Dreiwege → OMNI_W90_Dreiwege -│ ├── Weiche 45 Grad -│ │ ├── Einfach → OMNI_W45_Einfach -│ │ ├── Doppel → OMNI_W45_Doppel -│ │ └── Dreiwege → OMNI_W45_Dreiwege -│ ├── Weichen Parallel -│ │ ├── Einfach → OMNI_WP_Einfach -│ │ ├── Doppel → OMNI_WP_Doppel -│ │ └── Dreiwege → OMNI_WP_Dreiwege -│ ├── Weichenkoerper -│ │ ├── Einfach → OMNI_WK_Einfach -│ │ ├── Doppel → OMNI_WK_Doppel -│ │ └── Dreiwege → OMNI_WK_Dreiwege -│ ├── Weichenkombinationen -│ │ ├── Delta 1400/700 → OMNI_WKomb_Delta_1400 -│ │ ├── Delta 1600/800 → OMNI_WKomb_Delta_1600 -│ │ └── Star → OMNI_WKomb_Star -│ ├── TEF Elemente -│ │ ├── Umlenkspannst. rechts → OMNI_TEF_UmlenkR -│ │ ├── Umlenkspannst. links → OMNI_TEF_UmlenkL -│ │ ├── Antriebst. links → OMNI_TEF_AntriebL -│ │ ├── Antriebst. rechts → OMNI_TEF_AntriebR -│ │ └── TEF Gerade → OMNI_TEF_Gerade -│ ├── KettenFoerderer → OMNI_KettenFoerderer -│ └── Ladeschleifen -│ └── AP 110 → OMNI_LADESCHLEIFE_AP110 +│ ├── Boegen APB110/APB60 +│ ├── Aluprofil Gerade (AP60/AP110/APG110) +│ ├── Weichen (90/45/Parallel/Weichenkoerper/Weichenkombinationen) +│ ├── TEF Elemente, Anbaugruppen, Verbinder, Boegen fuer Weichen +│ ├── Element bearbeiten → OMNI_EDIT +│ └── Ladeschleifen (AP110) → OMNI_LADESCHLEIFE_AP110 +├── Geruest +│ ├── Rohr-Geruest-Traeger → GERUEST_TRAEGER +│ ├── Saeulen / Rohrabhaenger / Wandbefestigung → GERUEST +│ └── Funktionen ▸ Traeger beschriften → GERUEST_TRAEGER_BESCHRIFTEN +├── SPS +│ ├── TRO (Marker einfuegen/bearbeiten) → TRO_INSERT / TRO_EDIT +│ └── Connections (einfuegen/bearbeiten, Eingang/Ausgang) → CONNECTION_INSERT / CONNECTION_EDIT / ILS_EINGANG_INSERT / ILS_AUSGANG_INSERT +├── Export +│ ├── Export Sivas → EXPORTSIVAS +│ └── Export CSV → EXPORTCSV ├── Konfiguration │ ├── Umschalten 2D und 3D → SSG_DIM_SWITCH -│ └── Sprache → SSG_SPRACHE -└── External - ├── Call Python → CALLPYTHON - ├── Export Sivas → EXPORTSIVAS - └── Export CSV → EXPORTCSV +│ ├── Sprache → SSG_SPRACHE +│ └── Planquadrate an/aus → PLANQUADRATE_TOGGLE +├── Werkzeuge +│ ├── Bloecke zaehlen/loeschen, Attribute ersetzen → ssg_blocktools +│ └── Text ersetzen/parallel/Hoehe/Stil → ssg_texttools +└── Tests (Testsuiten ausfuehren und exportieren) ``` -## Befehle nach Modul +Vollstaendige, laufend aktualisierte Befehls-/Modulzuordnung: siehe `CLAUDE.md` (Abschnitt "Modulzuordnung im Menue") und `menu/SSG_LIB.mnu`. -### KreiselInsert.lsp - Kreisel Modul-Einfuegesystem +## Lademechanismus -Zeichnet ILS-Kreiselmodule als Compound-Bloecke mit konfigurierbarem Abstand, Typ und Attributen. +Module werden per Lazy-Loading ueber das Menuesystem geladen (`ssg-ensure` in `SSG_LIB.mnl`). Einmalige Einrichtung pro BricsCAD-Installation: -| Befehl | Beschreibung | -| --- | --- | -| `KreiselInsert` | Modul an manuell gewaehltem Punkt einfuegen (Abstand, Drehung, Hoehe, Typ interaktiv) | -| `KreiselConnect` | Smart Connect: Kreisel zwischen zwei parallelen Linien einfuegen, berechnet Position/Abstand/Rotation automatisch | -| `KreiselEdit` | Bestehenden Kreisel per DCL-Dialog bearbeiten (Name, Abstand, Hoehe, Ausrichtung, Drehrichtung, Typ) | -| `KreiselRedraw` | Kreisel mit optionalem neuem Abstand/Hoehe neu zeichnen, Attribute bleiben erhalten | -| `KreiselQuick` | Schnelleinfuegen mit Standardparametern (horizontal) | -| `KreiselParams` | Aktuelle Kreisel-Parameterkonfiguration anzeigen | -| `ILS_Eckrad` | Einzelnen AN8-Block (Antriebs-/Eckrad) an gewaehltem Punkt einfuegen | -| `KreiselLabelPos` | Label-Position (X/Y-Offset) konfigurieren | -| `KreiselLabelHoehe` | Label-Texthoehe konfigurieren | -| `KreiselLabelSetup` | Label-Darstellung konfigurieren (Hoehe, Farbe, Abstand, Schriftart) | +1. `bin/setenv.bat` ausfuehren (setzt `DXFM_LISP` u.a.) +2. BricsCAD starten +3. In der Kommandozeile `_MENULOAD` eingeben, `menu/SSG_LIB.mnu` auswaehlen -### OmniModulInsert.lsp - Omniflo Komponenten - -Einfuegen von Omniflo-Standardkomponenten (Boegen, Geraden, Weichen, TEF-Elemente). - -| Befehl | Beschreibung | -| --- | --- | -| `OMNI_LOAD` | Omniflo-Komponentendaten aus JSON-Dateien laden | -| `OMNI_INFO_BOGEN` | Info zu einem Omniflo-Bogen nach Sivas-ID anzeigen | -| `OMNI_INFO_WEICHE` | Info zu einer Omniflo-Weiche nach Sivas-ID anzeigen | -| `OMNI_APB_*` | Boegen einfuegen (90, 67.5, 45, 22.5, 180 Grad) | -| `OMNI_AP60/AP110/APG110` | Aluprofil-Geraden einfuegen | -| `OMNI_W90/W45/WP/WK_*` | Weichen einfuegen (Einfach, Doppel, Dreiwege) | -| `OMNI_WKomb_Delta_1400/1600, OMNI_WKomb_Star` | Weichenkombinationen einfuegen | -| `OMNI_TEF_*` | TEF-Elemente einfuegen (Umlenk-/Antriebsstationen, Gerade) | -| `OMNI_KettenFoerderer` | Kettenfoerderer einfuegen | -| `OMNI_LADESCHLEIFE_AP110` | Ladeschleife (AP 110) ueber DCL-Dialog einfuegen | - -### VarioFoerderer.lsp - Foerderanlage Generator (v24.4) - -Generiert komplette Vario-Foerderanlagen mit Vertikalboegen, Motor-/Spannstationen, Staustrecken und Ein-/Ausschleus-Elementen. - -| Befehl | Beschreibung | -| --- | --- | -| `FOERDERANLAGE` | Interaktiver Generator: Zwei Punkte oder manuelle Distanz/Hoehe, berechnet optimalen Bogenwinkel | -| `FOERDERTEST` | Automatischer Testlauf (Distanz=6000, Hoehe=2000, Richtung=Auf), speichert als DXF | - -Unterstuetzte Bogenwinkel: 3, 9, 12, 15, 24, 36, 48 Grad - -### ssg_layer.lsp - Layerverwaltung - -| Befehl | Beschreibung | -| --- | --- | -| `SSG-LayerSet` | Objekt anklicken, dessen Layer wird aktiv | -| `SSG-LayerInfo` | Layer eines angeklickten Objekts anzeigen | -| `SSG-LayerMove` | Selektierte Objekte auf Ziel-Layer verschieben | -| `SSG-LayerCopy` | Selektierte Objekte auf Ziel-Layer kopieren | -| `SSG-LayerMoveType` | Alle Objekte gleichen Typs von Referenz- auf Ziel-Layer verschieben | -| `SSG-LayerOff` | Layer per Klick ausschalten (mehrfach moeglich) | -| `SSG-LayerFreeze` | Layer per Klick einfrieren (mehrfach moeglich) | -| `SSG-FreezeAll` | Alle Layer ausser dem angeklickten einfrieren | -| `SSG-ThawAll` | Alle eingefrorenen Layer auftauen | -| `SSG-LayerOnAll` | Alle ausgeschalteten Layer einschalten | -| `SSG-LayerDelete` | Layer und alle Objekte darauf loeschen (mit Bestaetigung) | - -### SSG_LIB_Commands.lsp - Konfiguration - -| Befehl | Beschreibung | -| --- | --- | -| `SSG_DIM_SWITCH` | Schaltet zwischen 2D- und 3D-Bloecken um | -| `SSG_SPRACHE` | Sprache umschalten (Deutsch/Englisch), persistiert ueber `DXFM_LANG` | - -### tests.lsp - Export und Python-Integration - -| Befehl | Beschreibung | -| --- | --- | -| `CALLPYTHON` | Python-Skripte via CLI aufrufen, Ausgabe loggen | -| `EXPORTSIVAS` | Daten im Sivas-Format exportieren | -| `EXPORTCSV` | Zeichnungsdaten als CSV exportieren | - -## Kernbibliotheken (Lisp/) - -| Datei | Beschreibung | -| --- | --- | -| `ssg_core.lsp` | Kernel: Umgebung, Layer-Ops, Block-Ops, Attribut-Ops, Fehlerbehandlung | -| `ssg_lang.lsp` | Sprachumschaltung Deutsch/Englisch (`ssg-text`, `ssg-textf`, `*ssg-lang*`) | -| `ssg_dialog.lsp` | Dialog-Vorlagen: Slide-Preview, Modul-Dialog, Block-Einfuegesequenz | -| `ssg_layer.lsp` | Layer-Verwaltungsbefehle | -| `ssg_load.lsp` | Loader: Laedt alle SSG-Bibliotheken in korrekter Reihenfolge | -| `on_start.lsp` | Startup-Skript: Setzt Umgebung und laedt Libraries | +Details und die Core-Ladereihenfolge: siehe `CLAUDE.md` Abschnitt "Lademechanismus (Lazy Loading via MNL)". ## Projektstruktur ```text dxfmakros/ -├── Blocks/ # DWG-Bloecke (AN8, SP8, Vertikalboegen, etc.) -├── Lisp/ # AutoLISP-Makros und Kernbibliotheken -├── bin/ # Hilfs-Skripte (setenv, create_tests, etc.) -├── cfg/ # Konfigurationsdateien (export.cfg, block_suffix.cfg) -├── data/ # Quelldaten (JSON, DXF) - nicht im Git -├── dcl/ # DCL-Dialogdefinitionen (kreisel_edit.dcl) -├── doc/ # Dokumentation und Referenz-DXFs -├── examples/ # Beispieldateien -├── lib/ # Python-Skripte (export_csv.py, etc.) -├── logs/ # Logdateien - nicht im Git -├── menu/ # BricsCAD-Menudefinition (SSG_LIB.mnu) +├── Lisp/ # AutoLISP-Makros und Kernbibliotheken (Details: Lisp/README.md) +├── bin/ # Hilfs-Skripte (setenv.bat, start_briscad.bat) +├── cfg/ # Konfigurationsdateien +├── data/ # JSON-Daten, DXF-Quellen, Block-Libraries - nicht im Git +├── dcl/ # DCL-Dialogdefinitionen +├── doc/ # Dokumentation, Entwicklungsplan +├── lib/ # Python-Skripte (DXF-Bearbeitung, Export) +├── log/ # Logdateien - nicht im Git +├── menu/ # BricsCAD-Menudefinition (SSG_LIB.mnu, SSG_LIB.mnl) ├── results/ # Ergebnisse / Exporte - nicht im Git ├── tests/ # Testskripte und Referenzdaten ├── LICENSE @@ -181,33 +87,34 @@ dxfmakros/ ## Umgebungsvariablen +Werden via `bin/setenv.bat` gesetzt. Wichtigste: + | Variable | Beschreibung | | --- | --- | | `DXFMAKRO` | Wurzelverzeichnis des Projekts | -| `DXFM_BLOCKS` | Pfad zum Blocks-Verzeichnis | -| `DXFM_LISP` | Pfad zu den LISP-Dateien | -| `DXFM_RESULTS` | Pfad fuer DXF-Exporte | -| `DXFM_BIN` | Skriptverzeichnis | -| `DXFM_LIB` | Python-Quellcode | -| `DXFM_CFG` | Konfigurationsdateien | -| `DXFM_TESTS` | Testverzeichnis | -| `DXFM_DATA` | Datenverzeichnis | +| `DXFM_LISP` | Pfad zu den LISP-Dateien (benoetigt fuer `ssg-ensure`) | +| `DXFM_BLOCKS` | Pfad zu DWG-Bloecken | +| `DXFM_DATA` | Datenverzeichnis (JSON, DXF) | +| `DXFM_LOG` | Log-Verzeichnis | +| `DXFM_DCL` | Pfad zu DCL-Dialogdateien | +| `DXFM_CFG` | Konfigurationsverzeichnis | | `DXFM_LANG` | Aktive Sprache (`de_DE`/`en_GB`), persistiert von `SSG_SPRACHE`; Default `de_DE` | -| `BRICSCAD` | Pfad zur BricsCAD-Executable | - -## Einrichtung - -1. `bin\setenv.bat` ausfuehren (setzt alle Umgebungsvariablen) -2. BricsCAD starten - `on_start.lsp` laedt alle Libraries automatisch via `startup.scr` -3. Menu `SSG_LIB` nutzen oder Befehle in der Kommandozeile ausfuehren +| `DXFM_VF_SPEC` | Spec-Datei fuer `VF_SPEC_BAU` (optional) | +| `BRICSCAD` | Pfad zur BricsCAD-Executable (fuer headless Testlauf) | ## Tests +Headless-Unit-Tests (file- und zeichnungsfrei): + ```bat -bin\create_tests.bat +bin\run_tests.bat --lisp ``` -Erzeugt eine Test-DXF, fuehrt Kreisel-Einfuege- und Exportbefehle aus, und validiert die Ergebnisse gegen Referenzdateien in `tests/references/`. +Zeichnungs-/Szenario-Tests laufen interaktiv in BricsCAD ueber das Menue `Tests` bzw. `SSG_RUN_ALL_TESTS`. Details: `doc/LispTests.md`, `tests/README.md`. + +## Dokumentation + +Ausfuehrliche Modul- und Befehlsdokumentation: `CLAUDE.md` (Projektanweisungen) und `Lisp/README.md`. Weitere Themen in `doc/` (u.a. `variofoerderer.md`, `translate.md`, `csv-export.md`, `Entwicklungsplan.md`, `faq.md`, `kommandos.md`). ## Lizenz From 68ad56ec6c7b4c3ff0dee349a49de469996c18a9 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 10:26:10 +0200 Subject: [PATCH 24/38] [DOC] Lisp/README.md auf aktuellen Code-Stand gebracht Kern-Ladereihenfolge ergaenzt (ssg_id, ssg_ks_insert, ssg_input), Dummy-Status-Tabelle korrigiert (OMNI_TEF_* ist implementiert, nur OMNI_KettenFoerderer/OMNI_TV_*/OMNI_APBW_* und ein paar ILS-Kurven-Platzhalter sind noch Dummy). Fehlende Module ergaenzt: ssg_id.lsp, ssg_ks_insert.lsp, TEFInsert.lsp, GeruestInsert.lsp, Tro_Edit.lsp, Connection_Edit.lsp, DrawPlanquadrate.lsp. VarioFoerderer-Abschnitt an die Submodul-Aufsplittung (vf_core/vf_standard/vf_etage/vf_linienzug/vf_konstanten/vf_spec) und den Wizard/Journal/Headless-Mechanismus angepasst. SSG_BLOCKEDIT-Dispatchtabelle um GF_*/VF_*/GR_*/TRO_* ergaenzt. Co-Authored-By: Claude Sonnet 5 --- Lisp/README.md | 244 ++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 199 insertions(+), 45 deletions(-) diff --git a/Lisp/README.md b/Lisp/README.md index 463944b..05d5e12 100644 --- a/Lisp/README.md +++ b/Lisp/README.md @@ -15,14 +15,17 @@ _MENULOAD → menu/SSG_LIB.mnu auswaehlen ``` BricsCAD laedt daraufhin automatisch `SSG_LIB.mnl`, welches alle Module -per `ssg-ensure` initialisiert (Kern: ssg_core/lang/dbg/dialog/layer, dann -alle Feature-Module). Details: siehe `../CLAUDE.md` Abschnitt "Lademechanismus". +per `ssg-ensure` initialisiert. Kern-Reihenfolge (muss vor den Feature-Modulen +stehen): `ssg_core`, `ssg_lang`, `ssg_dbg`, `ssg_dialog`, `ssg_layer`, `ssg_id`, +`ssg_ks_insert` (Letzteres wird von Gefaellestrecke UND VarioFoerderer genutzt). +Details: siehe `../CLAUDE.md` Abschnitt "Lademechanismus". -**Manuell laden (Notfall / Entwicklung):** +**Manuell laden (Notfall / Entwicklung, z.B. fuer .scr-Testskripte):** ```lisp (load (strcat (getenv "DXFMAKRO") "/Lisp/ssg_load.lsp")) ``` -`ssg_load.lsp` laedt alle Module in der richtigen Reihenfolge ohne Menueabhaengigkeit. +`ssg_load.lsp` ist der Headless-Loader (genutzt von `tests/test_unit.scr` u.ae.) +und laedt dieselbe Kern-Reihenfolge wie `SSG_LIB.mnl`, ohne Menueabhaengigkeit. --- @@ -35,16 +38,22 @@ am Label-Anfang, bei Submenue-Schliessern hinter dem `<-` (`[<-~Label]`). | Menuebereich | Eintraege | Definiert in | | --- | --- | --- | -| ILS ▸ Foerderer | Durch TEF angetriebene Strecke; Kurven 90/60/30 links/rechts angetrieben Aussen + Innen (12) | `SSG_LIB_Commands.lsp` | -| ILS ▸ Gefaellestrecke | Kurven 90/60/30 links/rechts Gefaellestrecke (6) | `SSG_LIB_Commands.lsp` | -| Omniflo ▸ TEF Elemente | UmlenkR/L, AntriebL/R, TEF Gerade, KettenFoerderer (6) | `OmniModulInsert.lsp` | +| Omniflo ▸ Anbaugruppen | `OMNI_KettenFoerderer` | `OmniModulInsert.lsp` | | Omniflo ▸ Verbinder | alle `OMNI_TV_*` (18) | `OmniModulInsert.lsp` | | Omniflo ▸ Boegen fuer Weichen | alle `OMNI_APBW_*` (14) | `OmniModulInsert.lsp` | +| ILS ▸ Zusatzmodule/Kurven | `ILS_ETF_Etagenfoerderer`, `ILS_K{90,60,30}{L,R}{A,I}` (12), `ILS_Gefaellestrecke` | `SSG_LIB_Commands.lsp` | +| Geruest | `GERUEST` (Gattertraeger-Platzhalter, derselbe Befehl wie Saeulen/Rohrabhaenger/Wandbefestigung) | `GeruestInsert.lsp` | -Aktiv (implementiert) sind u.a.: Kreisel, Eckrad, VarioFoerderer, EtageVarioFoerderer, -Gefaellestrecke, BTMT Be-/Entladung, Scanner/Separator, Omniflo Boegen (APB), -Aluprofil-Geraden (AP), alle Weichen (W90/W45/WP/WK/WKomb), Export (Sivas/CSV) -und die Tests. +`OMNI_TEF_*` (UmlenkR/L, AntriebL/R, TEF Gerade) sind entgegen frueherem Stand +**implementiert** (echtes `omni:insert-dxf`), nur `OMNI_KettenFoerderer` ist +weiterhin Dummy. + +Aktiv (implementiert) sind u.a.: Kreisel, Eckrad, VarioFoerderer (Standard/Etage/ +Linienzug), Gefaellestrecke, Geruest (Saeulen/Rohrabhaenger/Wandbefestigung/ +Rohr-Geruest-Traeger), TRO-Marker, Connections, BTMT Be-/Entladung, Scanner/ +Separator, Omniflo Boegen (APB)/TEF-Elemente/Aluprofil-Geraden (AP)/alle Weichen +(W90/W45/WP/WK/WKomb)/Ladeschleifen, Export (Sivas/CSV), Werkzeuge (Block-/ +Text-Tools, Planquadrate) und die Tests. --- @@ -342,6 +351,42 @@ Hook (z.B. fuer ein Eingabe-Journal): `(setq *ssg-in-hook* 'meine-funktion)` mit --- +### `ssg_id.lsp` – Eindeutige Block-IDs + +Jedes exportierbare Element bekommt ein Attribut `ID` mit einer eindeutigen, +vierstelligen Nummer. Kern-Modul (nach `ssg_layer`, vor `ssg_ks_insert`). + +| Befehl / Funktion | Beschreibung | +| --- | --- | +| `c:IDGENERATE` | Weist dem zuletzt eingefuegten Block eine neue ID zu | +| `c:IDSCHECK` | Prueft alle Bloecke auf doppelte IDs und korrigiert sie | +| `ssg-id-format n` | Zahl als 4-stelligen String formatieren (`1` → `"0001"`) | +| `ssg-id-max` | Hoechste bereits vergebene ID in der Zeichnung | +| `ssg-id-generate ent` | Neue ID erzeugen und auf den Block setzen | +| `ssg-id-check-all` | Zeichnungsweit auf Doubletten pruefen und korrigieren | +| `ssg-id-collect-blocks` | Alle ID-faehigen INSERT-Entities sammeln (gleiche Muster wie `csv:collect-export-blocks`, inkl. Separator/Scanner/BTMT) | + +--- + +### `ssg_ks_insert.lsp` – KS-Extraktion und Block-Einfuegeprimitiven + +Gemeinsame Basis fuer VarioFoerderer (`vf_core.lsp`) UND Gefaellestrecke – +frueher in beiden Modulen dupliziert, jetzt einzige Quelle. Muss laut MNL **vor** +Gefaellestrecke/`vf_core` geladen sein; Kern-Modul. + +| Funktion | Beschreibung | +| --- | --- | +| `vec-length v` | Laenge eines 3er-Vektors | +| `ks-line-axis laenge` | Achsenkennung (X/Y/Z) aus Linienlaenge der KS-Hilfslinie | +| `ks-normalize-name nm` | Historische KS-Blocknamen (`KSYS_EIN`/`-AUS`) auf `KS_EIN`/`KS_AUS` normalisieren | +| `ks-relativize` / `ks-absolutize` | KS-Punkte zwischen relativem und Welt-Koordinatensystem umrechnen | +| `ensure-block-loaded name` | Block aus der Bibliothek einmalig ins aktive Dokument laden | +| `extract-ks-from-block[-raw] name` | KS_EIN/KS_AUS-Punkte eines Blocks ermitteln (Cache `*ks-cache*`) | +| `insert-block-by-ks name ks-nr pt` | Block anhand KS-Punkt einfuegen (nur Rz-Rotation) | +| `insert-inclined-scaled-block` / `insert-rotated-block-with-ks` | Geneigten/rotierten Block mit KS-Offset einfuegen (Rz*Ry) | + +--- + ### `ssg_blocktools.lsp` – Block-Werkzeuge Ursprung: ACADSST `TOOLS.LSP` (`BLKANZAHL`, `BLKENTF`), `DINGEN2` (`g-bli`), `ssg.lsp` (`suchen-aendern`). Arbeitet im **aktuellen Layout-Reiter**. Blocknamen werden ueber den wirksamen Namen verglichen (dynamische Bloecke); Muster mit `wcmatch` (`*`, `?`, `#`, ohne Gross-/Kleinschreibung). @@ -382,48 +427,60 @@ Nicht uebernommen aus Walz: `Export`/`Import` von Texten (besser per Python/ezdx ### `ssg_load.lsp` – Laderoutine -Lädt alle Module in der richtigen Reihenfolge. Ermittelt den Pfad automatisch über `findfile`. Ruft direkt nach `ssg_core.lsp` die Funktion `ssg-load-config` auf, damit die JSON-Konfiguration für alle nachfolgenden Module verfügbar ist. +Headless-Loader fuer .scr-Testskripte (z.B. `tests/test_unit.scr`). Laedt alle +Kern- und Feature-Module in derselben Reihenfolge wie `SSG_LIB.mnl`, ohne +Menueabhaengigkeit. Ermittelt den Pfad automatisch über `findfile`. Ruft direkt +nach `ssg_core.lsp` die Funktion `ssg-load-config` auf, damit die JSON-Konfiguration +für alle nachfolgenden Module verfügbar ist. --- -### `VarioFoerderer.lsp` – Vario-Förderer +### `VarioFoerderer.lsp` – Vario-Förderer (Wrapper) -Kompatibilitäts-Wrapper, der `vf_core.lsp` lädt (Plugin-Dispatcher-Architektur; lädt seinerseits `vf_standard.lsp`, `vf_etage.lsp`, `vf_linienzug.lsp`). Parametrischer Generator für ILS Vario-Förderanlagen. Liest Block-Geometrie aus einer DWG-Bibliothek (`DXFM_BLOCKS`). Alle Konstanten (Abstände, Winkel, Skalierung) werden via `ssg-cfg-or` aus `component_defaults.json` (Sektion `vario`) gelesen. +Kompatibilitäts-Wrapper, der `vf_core.lsp` lädt (Plugin-Dispatcher-Architektur +über `*vf-typ-registry*`; lädt seinerseits `vf_konstanten.lsp`, `vf_standard.lsp`, +`vf_etage.lsp`, `vf_linienzug.lsp`, danach `vf_spec.lsp`). Parametrischer Generator +für ILS Vario-Förderanlagen (Typen Standard/Etage/Linienzug). Liest Block-Geometrie +aus einer DWG-Bibliothek (`DXFM_BLOCKS`) über die Primitiven aus `ssg_ks_insert.lsp`. +Alle Konstanten (Abstände, Winkel, Skalierung) werden über `ssg-cfg-or` +(`component_defaults.json`, Sektion `vario`) bzw. die zentralen `*vfk-*`-Konstanten +aus `vf_konstanten.lsp` gelesen. **Befehl:** `c:FOERDERANLAGE` / `c:VarioFoerderer` – wählt zuerst den Anlagen-Typ (Standard/Etage/Linienzug): -- **Typ „standard“ + Werteingabe:** läuft über den DCL-Dialog - [`dcl/variofoerderer.dcl`](../dcl/variofoerderer.dcl) (zwei Dialoge, `vfs-standard-dialog-ablauf` - in `vf_standard.lsp`): Dialog 1 (`vfs-dialog-eingabe-basis`) erfasst deltaL, deltaH, - Förderrichtung (Auf/Ab), Einfügehöhe, Fahrtrichtung und Seite; anschließend berechnet - `berechne-standard` die gültigen Winkel-Varianten, und Dialog 2 - (`vfs-dialog-winkel-verteilung`) lässt Winkel und L_GF-Verteilung (vorne/hinten) wählen. - Startpunkt (X/Y) wird wie bei der Gefällestrecke vorher in der Zeichnung gepickt. -- **Typ „standard“ + 3D-Linie**, sowie **Typ „etage“** und **„linienzug“** bleiben - vollständig interaktiv (Kommandozeile), unverändert gegenüber dem bisherigen Ablauf. +- **Typ „standard“ und „etage“ + Werteingabe:** laufen über denselben, + typ-parametrisierten Dialog-Ablauf (`vf-dialog-ablauf` in `vf_core.lsp`; + `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne + Wrapper darauf) mit den Dialogen `vfs-dialog-eingabe-basis`/ + `vfs-dialog-winkel-verteilung` ([`dcl/variofoerderer.dcl`](../dcl/variofoerderer.dcl)): + Dialog 1 erfasst deltaL, Förderrichtung, Einfügehöhe/deltaH, Fahrtrichtung und + Seite/Motorseite; Dialog 2 lässt Winkel und L_GF-Verteilung (vorne/hinten) wählen. + Startpunkt (X/Y) wird vorher in der Zeichnung gepickt. +- **Typ „standard“/„etage“ + 3D-Linie** laufen ueber denselben Basis-Dialog statt + rein interaktiv auf der Konsole. +- **Typ „linienzug“** (Streckengruppe, `vf-linienzug-modus` in `vf_linienzug.lsp`) + hat drei Modi (manuell/Wizard, 3D-Objekte+Zielhoehe, Vorwaerts-Nachbau) und + zeichnet jede Eingabe in einem Journal auf (XDATA `SSG_VF_EDIT` am `VF_n`-Block); + Standard laeuft per Default ueber DCL-Dialoge (`VF_WIZARD_AN`/`VF_WIZARD_AUS` + schalten um). Details, Journal-Format, Headless-Modus (`*vfl-headless*`) und + Spec-basierter Bau ohne Dialog (`vf_spec.lsp`, `VF_SPEC_BAU`): siehe + [`../doc/variofoerderer.md`](../doc/variofoerderer.md) und `../CLAUDE.md`. **Bearbeiten (`c:VARIOFOERDERER_EDIT`):** Doppelklick auf einen `VF_n`-Block – bzw. -Rechtsklick-Kontextmenü/`SSG_BLOCKEDIT` – öffnet dieselben Dialoge, vorbelegt mit den -aktuellen Parametern, und baut die Strecke bei OK am selben Startpunkt neu auf (neue -`VF_n`-Nummer). Da `VF_n`-Blöcke auch von Etage- und Linienzug-Anlagen erzeugt werden -(deren komplexere Geometrie ein einfacher Neuaufbau zerstören würde), markiert -`vfs-xdata-schreiben` nur per Standard-Dialog erstellte Blöcke mit XDATA (App -`SSG_VF_EDIT`, Fahrtrichtung `hz`); Blöcke ohne diese Markierung weist -`c:VARIOFOERDERER_EDIT` mit einer Meldung ab, statt sie zu verändern. Winkel und L_GF1 -werden aus den Sivas-Attributen (`VF_WINKEL`, `L_GF_m`) vorbelegt (Verteilung stets als -„Eigene Werte“ mit dem exakten aktuellen L_GF1). +Rechtsklick-Kontextmenü/`SSG_BLOCKEDIT` – dispatcht per XDATA-Marker +(`"standard"`/`"etage"`/`"linienzug"`) in den passenden Neuaufbau-Zweig +(`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug) und öffnet dieselben +Dialoge, vorbelegt mit den aktuellen Parametern; der Block wird am selben +Startpunkt neu aufgebaut (neue `VF_n`-Nummer). Altbestand-Blöcke ohne +Marker werden mit einer Meldung abgewiesen, statt sie zu verändern. Winkel und +L_GF1 werden aus den Sivas-Attributen (`VF_WINKEL`, `L_GF_m`) vorbelegt. -**Wichtige interne Funktionen** (werden auch von `Gefaellestrecke.lsp` genutzt): - -| Funktion | Beschreibung | -| --- | --- | -| `init-bibliothek` | Block-Bibliothek aus DWG laden und Geometriedaten extrahieren | -| `ensure-block-loaded name` | Block aus Bibliothek in aktives Dokument laden (einmalig) | -| `insert-block-by-ks name ks-nr pt` | Block anhand Koordinatensystem-Punkt einfügen | -| `insert-inclined-scaled-block name laenge winkel pt` | Geneigten, skalierten Block einfügen | -| `insert-rotated-block-with-ks name rot pt` | Rotierten Block mit KS-Offset einfügen | -| `get-line-start-end-points ename` | Start- und Endpunkt einer LINE-Entity ermitteln | -| `punkt-differenz p1 p2` | Differenzvektor zweier Punkte | +Die Block-Einfuege-Primitiven (`ensure-block-loaded`, `insert-block-by-ks`, +`insert-inclined-scaled-block`, `insert-rotated-block-with-ks` u.a.) sind seit +der Konsolidierung zentral in [`ssg_ks_insert.lsp`](#ssg_ks_insertlsp--ks-extraktion-und-block-einfuegeprimitiven) +definiert (von `vf_core.lsp`, `Gefaellestrecke.lsp` und `TEFInsert.lsp` genutzt). +Weitere interne Helfer: `init-bibliothek` (Block-Bibliothek aus DWG laden), +`get-line-start-end-points ename`, `punkt-differenz p1 p2`. --- @@ -471,6 +528,19 @@ Der Neuaufbau läuft über `gf-rebuild` (nicht-interaktiv, ohne Konsolen-Rückfr --- +### `TEFInsert.lsp` – TEF-Geradenstuecke entlang einer Linie + +**Befehl:** `c:TEF_FOERDERER_LINIE`. Zeichnet eine Linie zwischen zwei gewaehlten +Punkten und reiht darauf 1000-mm-TEF-Geradenelemente (`0_B10030` aus +`DXFM_OMNIFLO`) aneinander; ist die Linienlaenge kein exaktes Vielfaches, +wird ein zusaetzliches, zurueckverschobenes Element eingefuegt, sodass der +Foerderer exakt am Linienende endet (keine Luecke, kein abgeschnittenes +Element). Die Linie darf geneigt sein (3D) – Elemente werden dann analog zu +`vf_core.lsp`/`ssg_ks_insert.lsp` (Rz*Ry-Rotation) gekippt eingefuegt. Nicht +zu verwechseln mit den einzelnen `OMNI_TEF_*`-Befehlen in `OmniModulInsert.lsp`. + +--- + ### `export.lsp` – Export-Funktionen Sammelt INSERT-Blöcke aus der Zeichnung und exportiert sie als JSON oder ruft Python-Skripte für den Sivas-Export auf. @@ -629,11 +699,16 @@ AutoLISP-Implementierung fuer alle Omniflo-Komponenten: Boegen, Weichen, Verbind | Weichen | `OMNI_W90_*`, `OMNI_W45_*`, `OMNI_WP_*`, `OMNI_WK_*`, `OMNI_WKomb_*` | Omniflo-Weichen (Einfach/Doppel/Dreiwege, Delta, Stern) | | Geraden | `OMNI_AP60`, `OMNI_AP110`, `OMNI_APG110` | Omniflo-Geradenstuecke | | Ladeschleifen | `OMNI_LADESCHLEIFE_AP110` | Ladeschleife aus `omniflo_ladeschleifen.json` ueber DCL-Dialog (`dcl/omniflo_ladeschleifen.dcl`) einfuegen; Daten per `ssg-json-laden` (Beschreibungen enthalten Kommas). Blockdatei `.dwg` unter `DXFM_OMNIFLO` (`omni:insert-dxf` faellt auf `.dwg` zurueck, wenn keine `.dxf` existiert). Per `OMNI_EDIT` editierbar | -| TEF ⚠� | `OMNI_TEF_UmlenkR/L`, `OMNI_TEF_AntriebL/R`, `OMNI_TEF_Gerade`, `OMNI_KettenFoerderer` | **Dummy** (noch nicht implementiert, im Menue ausgegraut) | +| TEF Elemente | `OMNI_TEF_UmlenkR/L`, `OMNI_TEF_AntriebL/R`, `OMNI_TEF_Gerade` | Feste TEF-Bauteile ohne Sivas-Auswahl, direkt per `omni:insert-dxf` an gewaehltem Punkt eingefuegt (Dateien unter `DXFM_OMNIFLO`) | +| Anbaugruppen ⚠� | `OMNI_KettenFoerderer` | **Dummy** (noch nicht implementiert, im Menue ausgegraut); `OMNI_STOPPER`/`OMNI_SCANNER`/`OMNI_BUERSTENBREMSE` sind implementiert | | Transferwagen ⚠� | `OMNI_TV_*` | **Dummy** (noch nicht implementiert, im Menue ausgegraut) | | Bogenweichen ⚠� | `OMNI_APBW_*` | **Dummy** (noch nicht implementiert, im Menue ausgegraut) | | Bearbeiten | `OMNI_EDIT` | Omniflo-Block selektieren und Attribute bearbeiten | +Daneben zeichnet [`TEFInsert.lsp`](#tefinsertlsp--tef-geradenstuecke-entlang-einer-linie) (`TEF_FOERDERER_LINIE`) eine +Kette von TEF-Geradenelementen (1000 mm) entlang einer frei gewaehlten Linie – +nicht zu verwechseln mit den einzelnen `OMNI_TEF_*`-Befehlen oben. + --- ### `SSG_LIB_Commands.lsp` – BTMT, Sensoren, Dummy-Befehle, Konfiguration und SSG_BLOCKEDIT @@ -680,6 +755,10 @@ Entladung" bzw. "BT - Beladung ..."/"Abwurf fuer Klammerbuegel ..."); im Sivas-Export zusaetzlich in den Summenzaehlern "Anzahl aller BTBeladung"/ "Anzahl aller Abwurfstationen" der ILS-Automation-Zeile. +**Eingang-/Ausgang-Symbol:** `ILS_EINGANG_INSERT`/`ILS_AUSGANG_INSERT` nutzen +dieselbe `ils-insert-station`-Routine wie BTMT Be-/Entladung (frei platzierbar, +Blöcke `Eingang_.dwg`/`Ausgang_.dwg` in `data/ils`). + Registrierte Dummy-Befehle: | Gruppe | Befehle | @@ -700,11 +779,86 @@ Registrierte Dummy-Befehle: **SSG_BLOCKEDIT** – Doppelklick/Kontextmenue-Dispatcher: -Erkennt den Blocktyp des selektierten INSERT-Blocks und ruft den passenden Bearbeitungsbefehl auf: +Erkennt den Blocktyp des selektierten INSERT-Blocks und ruft den passenden Bearbeitungsbefehl auf (Reihenfolge wichtig: `GR_*` **vor** dem Omniflo-Zweig, da Geruest-Bloecke ebenfalls ein TEILEART-Attribut tragen): | Blockmuster | Aktion | | --- | --- | | `KREISEL_*` | `KreiselEdit` | | `ECKRAD_*` | `BEDIT` (Block-Editor) | +| `GF_*` | `GEFAELLESTRECKE_EDIT` | +| `VF_*` | `VARIOFOERDERER_EDIT` | +| `GR_*` | Geruest – `BEDIT` (kein eigener Edit-Pfad; siehe `GeruestInsert.lsp`) | +| `TRO_*` | `TRO_EDIT` | | Omniflo (TEILEART-Attribut, AP110*, numerisch) | `OMNI_EDIT` | | Sonstige | `BEDIT` (Block-Editor) | + +--- + +### `GeruestInsert.lsp` – Geruest-Baugruppen + +Rohr-Geruest-Baugruppen (Saeulen, Rohrabhaenger, Wandbefestigung, Rohr-Geruest-Traeger) +aus [`data/json/geruest.json`](../data/json/geruest.json) bzw. +[`data/json/geruest_traeger.json`](../data/json/geruest_traeger.json) konfigurieren +und einfuegen. Die Dialogdefinition wird **zur Laufzeit erzeugt** +(`geruest-dcl-schreiben`, temporaere DCL-Datei) – es gibt keine feste +`dcl/geruest.dcl`, weil je Anbauteil ein eigenes Mengenfeld gebraucht wird. +Ausfuehrliche Beschreibung (Konfigurationen, Attribut-Schema, Querstreben/Muffe, +Traeger-Beschriftung): siehe `../CLAUDE.md` Abschnitt "AutoLISP-Module". + +| Befehl | Beschreibung | +| --- | --- | +| `c:GERUEST` | Dialog ohne Vorgabe-Bereich (Dropdown Rohrabhaenger/Saeulen/Wandbefestigung) | +| `c:GERUEST_SAEULEN` / `c:GERUEST_ROHRABHAENGER` / `c:GERUEST_WANDBEFESTIGUNG` | Dialog mit vorgewaehltem Bereich (derselbe Dialog wie `GERUEST`) | +| `c:GERUEST_TRAEGER` | Eigener fester Dialog (`dcl/geruest_traeger.dcl`): Rohr-Geruest-Traeger mit Linien-Logik (Start-/Endpunkt oder Laenge, Laengenabzuege, Querstreben/Muffe-Verteilung) | +| `c:GERUEST_TRAEGER_BESCHRIFTEN` | Alle Traeger der Zeichnung neu beschriften (eigenes TEXT-Objekt, verknuepft per XDATA `SSG_GR_BESCHR`) | + +Block-Praefix `GR__` – **nicht kosmetisch**: `SSG_BLOCKEDIT` muss +`GR_*` vor dem Omniflo-Zweig abfangen, da Geruest-Bloecke ebenfalls ein +TEILEART-Attribut tragen. Export-Pattern `pattern_geruest = GR_*` (`cfg/export.cfg`). + +--- + +### `Tro_Edit.lsp` – TRO-Marker + +TRO-Marker (Block `TRO_SYM_`) fuer `sps_skel`/`lib/tro_annotate.py`. + +| Befehl | Beschreibung | +| --- | --- | +| `c:TRO_INSERT` | Bestehende Blockdefinition an gewaehltem Punkt einfuegen, setzt ID/TYPE; bricht ab, wenn der Typ noch keine Blockdefinition in der Zeichnung hat (entsteht nur ueber `tro_annotate.py`) | +| `c:TRO_EDIT` | ID/TYPE eines bestehenden Markers per Dialog aendern | + +Typliste kommt aus [`tro_types.lsp`](../Lisp/tro_types.lsp) (von +`tro_annotate.py --emit-lisp` nach `DXFM_LISP` geschrieben). `SSG_BLOCKEDIT` +leitet Blocknamen `TRO_*` zu `TRO_EDIT`. + +--- + +### `Connection_Edit.lsp` – Verbindungen (SPS) + +Verbindungslinien zwischen zwei Punkten/Bausteinen fuer SPS-Dokumentation. + +| Befehl | Beschreibung | +| --- | --- | +| `c:CONNECTION_INSERT` | Verbindung zwischen zwei Punkten einfuegen (Laenge/Winkel/Mitte werden berechnet) | +| `c:CONNECTION_EDIT` | Bestehende Verbindung bearbeiten | + +--- + +### `DrawPlanquadrate.lsp` – Planquadrat-Raster + +Zeichnet auf Z=0 ein Planquadrat-Linienraster (senkrecht/waagerecht) im +Abstand/Zaehlschema der aktiven `[Planquadrate]`-Konfiguration aus +`cfg/export.cfg` – dieselbe Quelle wie `lib/export_planquadrat.py` fuer den +CSV-Export. Bereich und Ursprung kommen aus der **Bounding-Box** derselben +Blockmenge wie `EXPORTCSV` (`csv:collect-export-blocks`), nicht aus dem reinen +Einfuegepunkt oder den Zeichnungs-Extents. Lazy geladen ueber +`(ssg-ensure "DrawPlanquadrate")`, nicht Teil der Core-Ladereihenfolge. + +| Befehl | Beschreibung | +| --- | --- | +| `c:DRAW_PLANQUADRATE` | Raster neu aufbauen (entfernt zuerst einen evtl. vorhandenen Block) | +| `c:DELETE_PLANQUADRATE` | Raster-Block entfernen | +| `c:PLANQUADRATE_TOGGLE` | Dispatcht auf Zeichnen bzw. Loeschen, je nachdem ob der Block existiert | + +Das fertige Raster (Linien + Zaehl-Texte) wird zu einem einzigen Block +`ZZ_PLANQUADRATE` bei (0,0,0) zusammengefasst; Layer aus `cfg/layer.cfg`. From d0ec791bf8e909e9ec8bffbc19b3927ecfc0ed41 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 10:30:02 +0200 Subject: [PATCH 25/38] [DOC] VF-Doku: erledigte TODOs nachgetragen, toten Link entfernt TODO-plan-vf-interactive.md: TEST_HUNDM05 laeuft inzwischen aktiv in tests/alltests.json (kein disabled mehr), Status-Kopf und S1-Zeile entsprechend aktualisiert. vf_linienzug_modus1_anleitung.md: Verweis auf nicht existierende doc/VarioFoerderer_Linienzug_Prinzipien.md entfernt. Geprueft, unveraendert gelassen (noch zutreffend): doc/variofoerderer.md, doc/vf-parameter-struct-analyse.md, doc/TODO-modus2-achsenweise-bilanz.md. Co-Authored-By: Claude Sonnet 5 --- doc/TODO-plan-vf-interactive.md | 17 ++++++++++------- doc/vf_linienzug_modus1_anleitung.md | 5 ++--- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/doc/TODO-plan-vf-interactive.md b/doc/TODO-plan-vf-interactive.md index f27da22..b63210a 100644 --- a/doc/TODO-plan-vf-interactive.md +++ b/doc/TODO-plan-vf-interactive.md @@ -1,6 +1,9 @@ # TODO/Plan: VF-Linienzug ohne GUI/Konsole aufrufbar machen -**Stand:** 2026-09-02 · **Status:** Stufe 0 fertig (im CAD noch ungetestet) +**Stand:** 2026-09-02, Fortschrittsnotizen bis 2026-09-18 · +**Status:** Stufe 0 fertig und CAD-verifiziert; Stufe 1 (Modus 1) im CAD +verifiziert, `TEST_HUNDM05` aktiv in `tests/alltests.json`; Stufe 2 +Schritte 0-4 + 7-Assertion fertig, 5/6/8/9/10 offen, 11 zurueckgestellt. **Herkunft:** Planungslauf (Plan-Modus) vom 2026-09-02, hier eingecheckt zur Nachverfolgung. ## Fortschritt @@ -12,7 +15,7 @@ | P1 | `vfl-meldung` statt `alert` in den Bau-Pfaden | **erledigt** | | P2 | `*vfl-headless*`: leere Replay-Queue wird zum Fehler | **erledigt** | | P3 | Kleinkram (`*vfl-meldungen*`-Reset, `vfl-view-refresh`) | **erledigt** | -| S1 | Stufe 1: `Lisp/vf_spec.lsp` (Spec -> Journal -> Replay) | **Modus 1 fertig**, im CAD ungetestet | +| S1 | Stufe 1: `Lisp/vf_spec.lsp` (Spec -> Journal -> Replay) | **Modus 1 fertig, im CAD verifiziert** (`TEST_HUNDM05` aktiv in `tests/alltests.json`) | | S2 | Stufe 2: echte Funktionstrennung | **Schritte 0-4 + 7-Assertion fertig**, 5/6/8/9/10 offen, 11 zurueckgestellt | | PY | `lib/vf_journal_export.py`: Grammatik vervollstaendigen | **erledigt** | @@ -79,11 +82,11 @@ Block ist (danach entstehen noch Beschriftungstexte). Behoben: - `vfl-meldung` verkraftet jetzt `txt` = nil (fehlender i18n-Schluessel wuerde `strcat` genau dann abbrechen, wenn schon etwas schiefging). -**Noch offen** (braucht BricsCAD): `TEST_HUNDM05` muss 5x -`"status": "executed"` mit `prompts` 0 liefern, und eine interaktive -Gegenprobe (`FOERDERANLAGE` -> Linienzug Modus 1, Doppelklick-Edit, -`SSG_DIM_SWITCH`) muss unveraendert aussehen. Erst danach kann in -`tests/alltests.json` das `"disabled": true` der hundm05-Zeile weg. +**Erledigt**: `TEST_HUNDM05` liefert 5x `"status": "executed"` mit `prompts` +0; die interaktive Gegenprobe (`FOERDERANLAGE` -> Linienzug Modus 1, +Doppelklick-Edit, `SSG_DIM_SWITCH`) ist unveraendert. Das `"disabled": true` +der hundm05-Zeile in `tests/alltests.json` ist weg, der Test laeuft aktiv +mit. **Bewusst nicht umgestellt**: `vfl-konvertiere-ent` (Batch-2D/3D) laeuft weiter ohne `*vfl-headless*` - eine Live-Rueckfrage ist dort bisher gewolltes diff --git a/doc/vf_linienzug_modus1_anleitung.md b/doc/vf_linienzug_modus1_anleitung.md index 371b0ba..3312fb1 100644 --- a/doc/vf_linienzug_modus1_anleitung.md +++ b/doc/vf_linienzug_modus1_anleitung.md @@ -10,9 +10,8 @@ aufrufbar in BricsCAD ueber `TEST_LINIENZUG_STUFE2` (siehe diesen Testlauf jederzeit wiederholen. Fuer die Architektur-Details (Frame-Kette, Journal/XDATA, Wizard-Dialoge) -siehe `doc/variofoerderer.md` und `doc/VarioFoerderer_Linienzug_Prinzipien.md`. -Diese Anleitung konzentriert sich auf die Bedienung und die typischen -Stolperfallen. +siehe `doc/variofoerderer.md`. Diese Anleitung konzentriert sich auf die +Bedienung und die typischen Stolperfallen. ## 1. Was ist Modus 1? From 1e7e2c634998d07fcc3206961da9340cae6c3d35 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 10:34:20 +0200 Subject: [PATCH 26/38] [DOC] kommandos.md, faq.md, json-input-lisp.md: fehlende Eintraege ergaenzt kommandos.md: lib/dxf_anlage_export.py fehlte in der Python-Kommandozeilen-Liste. faq.md: FAQ-Eintrag fuer QcLinieMitGf/QcLinieMitGfUForm ergaenzt (bisher nur stichwortartig in der Gefaellestrecke-Liste erwaehnt, nirgends erklaert). json-input-lisp.md: tests/testdata/showroom_ils.json fehlte in der Testdaten-Uebersicht (Abschnitt 9), obwohl TEST_SHOWROOM_ILS dokumentiert ist. Alle anderen Befehle/Dateien/Testdaten in den drei Dokumenten gegen den aktuellen Code-Stand geprueft und bestaetigt aktuell. Co-Authored-By: Claude Sonnet 5 --- doc/faq.md | 15 +++++++++++++++ doc/json-input-lisp.md | 1 + doc/kommandos.md | 1 + 3 files changed, 17 insertions(+) diff --git a/doc/faq.md b/doc/faq.md index e4a57c7..31c0dc1 100644 --- a/doc/faq.md +++ b/doc/faq.md @@ -191,6 +191,21 @@ Durch einen Doppelklick auf die Gefällestrecke und Eingabe der neuen Länge im #### Wie baue ich eine Gefällestrecke mit manueller Höhenüberwindung ohne VF (QS-Platz Mubea) +#### Was sind "QC mit 30/90 Grad ES/AS" und "QC mit U-Form"? + +Zwei Spezialbefehle fürs Zeichnen eines Linienzugs vorab, bei denen die +komplette Kette danach **automatisch ohne weitere Rückfragen** gebaut wird +(`QcLinieMitGf`/`QcLinieMitGfUForm`, technisch über den Linienzug-Ablauf +(Streckengruppe) mit einem erzwungenen Modus gebaut, im Menü aber bewusst +unter *ILS -> Gefaellestrecke* eingeordnet, da das Ergebnis eine reine +Gefällestrecke von AS bis ES ist): Statt bei jedem Schritt zu fragen "Welches +Element als nächstes?", wird direkt die Gefällestrecke zwischen den beiden +gewählten Punkten gebaut. "QC mit U-Form" (`QcLinieMitGfUForm`) löst +zusätzlich eine gefaltete (U-förmige) Linienführung: zwei Gefällestrecken- +Abschnitte mit unterschiedlicher Neigung (3°/9°) werden über ein +Gleichungssystem aus Höhen- und Lagebilanz passend zur Zielgeometrie +berechnet, nur am Kettenanfang nutzbar. + ## 3. Varioförderer Varioförderer können auf verschiedene Arten gebaut werden: diff --git a/doc/json-input-lisp.md b/doc/json-input-lisp.md index da5fc03..eb69f7c 100644 --- a/doc/json-input-lisp.md +++ b/doc/json-input-lisp.md @@ -417,6 +417,7 @@ ueberspringt sie. Passende Primitive waere `insert-hz-scaled-block-by-ks` | `hundm05.json` | 5 HundM-Ketten als Spec + Kreisel, Separatoren, Scanner, BTMT | `TEST_HUNDM05`, `VF_SPEC_BAU` | | `mubea.json` | Gesamtanlage: Kreisel, VF Standard/Etage, GF-Template (20 Stueck), Separatoren, Scanner, BTMT, Eingang/Ausgang | `TEST_MUBEA` | | `dematic_arvato.json` | Vorlage aus `dxf_scan_components.py`: Kreisel, Einzelbloecke, `gerade` (Hoehen fehlen) | `TEST_DEMATIC_ARVATO` (abgeschaltet) | +| `showroom_ils.json` | ILS-3.0-Showroom-Vorlage aus `dxf_scan_components.py` (Kreisel, Gefaellestrecken; Hoehen teils Platzhalter), gleicher Treiber wie `dematic_arvato.json` | `TEST_SHOWROOM_ILS` | | `hundm05_linienzug_polylines.json` | Polylinien aus `extract_polylines.py` | kein Treiber (Analyse-Daten) | | `vfl_journal_hm05_abbruch.json` | rohes Journal (`kind`/`value`) eines abgebrochenen Baus | kein Treiber | diff --git a/doc/kommandos.md b/doc/kommandos.md index a7bd845..8a8417d 100644 --- a/doc/kommandos.md +++ b/doc/kommandos.md @@ -266,6 +266,7 @@ Reine Bibliotheken ohne eigene Kommandozeile: `export_blockpatterns.py`, | `python vf_journal_export.py [--csv ] [--kein-startpunkt-fix]` | `SSG_VF_EDIT`-Journale der VF_n-Bloecke als Frage-Antwort-Protokoll (z.B. `tests/testdata/hm_recformat.json`) | | `python vf_spec_export.py ` | Protokoll in eine Spec uebersetzen (z.B. `tests/testdata/hundm05.json`) | | `python dxf_vf_abbild.py [--spec S] [--json J] [--referenz R] [--schreibe-referenz] [--praefix VF_,GF_]` | Attribut-/Bausteinabbild der VF_/GF_-Bloecke; `--referenz` vergleicht (Exit 1 bei Abweichung) | +| `python dxf_anlage_export.py [--projekt NAME]` | Mit unseren Makros GEBAUTE (und von Hand nachbearbeitete) Anlage aus der Zeichnung in Nachbau-Testdaten zurueckschreiben (Gegenstueck zu `dxf_scan_components.py`); erzeugt z.B. `tests/testdata/dematic_arvato.json` | | `python dump_vf_wrapper_inhalt.py ` | Diagnose: Sub-INSERTs je VF_n/GF_n-Wrapper in Baureihenfolge | | `python dump_vf_kette_inhalt.py []` | Diagnose: Glied-Folge der Spec gegen die tatsaechliche Separatorliste | From aaf47ab3c1ee62be5569d7b2a6266e4a0941f6cd Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 10:43:09 +0200 Subject: [PATCH 27/38] [CHANGE] JSON-Testdaten-Feldnamen aus dxf_anlage_export.py in lib/testdata_schema.py zentralisiert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dxf_anlage_export.py und dxf_scan_components.py fuehrten dieselben Feldnamen (abstand, deltaL_mm, as_seite, ...) aus doc/json-input-lisp.md unabhaengig als lose String-Literale - ein Tippfehler oder eine Schema-Aenderung in nur einer Datei waere nicht aufgefallen. Neues Modul lib/testdata_schema.py buendelt die Feldnamen/festen Werte der dokumentierten Schemas (Kreisel, Einzelblock, VF Standard/Etage, Gefaellestrecke Modus 1) als benannte Konstanten; dxf_anlage_export.py nutzt sie jetzt durchgaengig. dxf_scan_components.py bewusst NICHT mitumgebaut: deutlich grösser/komplexer, mit zusaetzlichen Sonderfaellen (z.B. "startpunkt"/"gerade"-Form), ein vollstaendiger Umbau haette den Rahmen dieser Aenderung gesprengt und mehr Risiko als Nutzen gehabt. Verhaltensgleich: alle 9 Tests in tests/test_dxf_anlage_export.py laufen weiterhin gruen. Co-Authored-By: Claude Sonnet 5 --- doc/json-input-lisp.md | 8 ++++ lib/dxf_anlage_export.py | 87 ++++++++++++++++++++-------------------- lib/testdata_schema.py | 79 ++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 43 deletions(-) create mode 100644 lib/testdata_schema.py diff --git a/doc/json-input-lisp.md b/doc/json-input-lisp.md index eb69f7c..910a632 100644 --- a/doc/json-input-lisp.md +++ b/doc/json-input-lisp.md @@ -10,6 +10,14 @@ Die zugehoerigen LISP-Routinen mit Signaturen stehen in `tests/testdata/object_data.md` (geloescht in Commit `e147b89`, auf das Code- Kommentare teilweise noch verweisen). +**Feldnamen als Python-Konstanten**: `lib/testdata_schema.py` buendelt die +Feldnamen/festen Werte der Abschnitte 1 (Kreisel), 2 (Einzelbloecke), 3 (VF +Standard/Etage) und 4.1 (Gefaellestrecke Modus 1) als benannte Konstanten +(`sch.F_ABSTAND`, `sch.SEITE_LINKS`, ...), genutzt von `lib/dxf_anlage_export.py` +(eigene, mit unseren Makros gebaute Zeichnungen). `lib/dxf_scan_components.py` +(fremde Zeichnungen) hat dieselben Feldnamen weiterhin als eigene String- +Literale - gleiches Schema, noch nicht auf das gemeinsame Modul umgestellt. + --- ## 0. Uebersicht diff --git a/lib/dxf_anlage_export.py b/lib/dxf_anlage_export.py index f864696..62ad022 100644 --- a/lib/dxf_anlage_export.py +++ b/lib/dxf_anlage_export.py @@ -63,6 +63,7 @@ import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from vf_journal_export import TRENNER, gruppen # noqa: E402 from dxf_scan_components import arrays_einzeilig, kreisel_anschluss # noqa: E402 +import testdata_schema as sch # noqa: E402 PREFIX = "[dxf_anlage_export]" RUND = 2 @@ -204,17 +205,17 @@ def kreisel_eintrag(e, block_inhalt, projekt): quelle = "Blockdefinition (AN8 -> SP8)" nr = int(_float(a.get("NUMMER"))) or _nummer(e["name"]) return collections.OrderedDict([ - ("id", "Kreisel_%s_%02d" % (projekt, nr)), - ("function", "insert"), - ("x", _r(e["p"][0])), ("y", _r(e["p"][1])), ("z", _r(e["p"][2])), - ("abstand", _r(abstand)), - ("rotation", _r(e["rot"])), - ("typ", a.get("KREISELART") or "STANDARD"), + (sch.F_ID, "Kreisel_%s_%02d" % (projekt, nr)), + (sch.F_FUNCTION, sch.FUNC_INSERT), + (sch.F_X, _r(e["p"][0])), (sch.F_Y, _r(e["p"][1])), (sch.F_Z, _r(e["p"][2])), + (sch.F_ABSTAND, _r(abstand)), + (sch.F_ROTATION, _r(e["rot"])), + (sch.F_TYP, a.get("KREISELART") or sch.TYP_STANDARD), # Umlaufsinn: bestimmt die Reihenfolge im Kreisel-Umlauf und damit den # TRO-Fluss - ohne ihn kam jeder Nachbau als UZS heraus (Dematic 1/4: # GUZ). hundm05:bau-kreisel reicht ihn an kreisel-insert-script weiter. - ("drehrichtung", a.get("DREHRICHTUNG") or "UZS"), - ("comment", "aus Zeichnung: %s (ID %s), abstand aus %s" + (sch.F_DREHRICHTUNG, a.get("DREHRICHTUNG") or sch.DREHRICHTUNG_UZS), + (sch.F_COMMENT, "aus Zeichnung: %s (ID %s), abstand aus %s" % (e["name"], a.get("ID", "?"), quelle)), ]) @@ -251,15 +252,15 @@ def gf_eintrag(e, geo, projekt, hinweise): r = _richtung(hz) ende = (start[0] + deltaL * r[0], start[1] + deltaL * r[1]) eintrag = collections.OrderedDict([ - ("test_id", "GF_%s_%02d" % (projekt, _nummer(e["name"]))), - ("modus", 1), - ("deltaL_mm", _r(deltaL)), - ("hz_grad", _r(hz)), - ("start_mm", [_r(start[0]), _r(start[1]), _r(z_start)]), - ("as_seite", a.get("SEITE_AS") or "links"), - ("es_seite", a.get("SEITE_ES") or "links"), - ("as_winkel", xd[2] or "90"), - ("es_winkel", xd[3] or "90"), + (sch.F_TEST_ID, "GF_%s_%02d" % (projekt, _nummer(e["name"]))), + (sch.F_MODUS, sch.GF_MODUS_WERTEINGABE), + (sch.F_DELTAL_MM, _r(deltaL)), + (sch.F_HZ_GRAD, _r(hz)), + (sch.F_START_MM, [_r(start[0]), _r(start[1]), _r(z_start)]), + (sch.F_AS_SEITE, a.get("SEITE_AS") or sch.SEITE_LINKS), + (sch.F_ES_SEITE, a.get("SEITE_ES") or sch.SEITE_LINKS), + (sch.F_AS_WINKEL, xd[2] or sch.SCHLEUS_WINKEL_90), + (sch.F_ES_WINKEL, xd[3] or sch.SCHLEUS_WINKEL_90), ]) k_start = kreisel_an_punkt(start, r, geo) k_ende = kreisel_an_punkt(ende, (-r[0], -r[1]), geo) @@ -275,7 +276,7 @@ def gf_eintrag(e, geo, projekt, hinweise): else: eintrag["winkel_grad"] = round(winkel, 4) kommentar = "kein Kreisel am Ende - gebauter Winkel uebernommen" - eintrag["comment"] = "aus Zeichnung: %s (ID %s); %s" % ( + eintrag[sch.F_COMMENT] = "aus Zeichnung: %s (ID %s); %s" % ( e["name"], a.get("ID", "?"), kommentar) return eintrag @@ -286,18 +287,18 @@ def vf_standard_eintrag(e, projekt, typ): xd = e["xdata"].get("SSG_VF_EDIT") or [] l_gf = [t for t in (a.get("L_GF_m") or "").split(",") if t.strip()] eintrag = collections.OrderedDict([ - ("test_id", "VF_%s_%02d" % (projekt, _nummer(e["name"]))), - ("typ", typ), - ("richtung", a.get("ANTRIEBFAHRTRICHTUNG") or "Auf"), - ("deltaL", _r(_float(a.get("DELTA_L_mm")))), - ("deltaH", _r(_float(a.get("DELTA_H_mm")))), - ("winkel", int(_float(a.get("VF_WINKEL")))), - ("L_GF1", _r(1000.0 * _float(l_gf[0])) if l_gf else 0.0), - ("seite", a.get("SEITE_AS") or "rechts"), - ("motorseite", (a.get("MOTORSEITE") or "rechts").split(",")[0]), - ("hz", _r(_float(xd[1]) if len(xd) > 1 else 0.0)), - ("x", _r(e["p"][0])), ("y", _r(e["p"][1])), ("z", _r(e["p"][2])), - ("comment", "aus Zeichnung: %s (ID %s), Hoehe %s -> %s; deltaL/" + (sch.F_TEST_ID, "VF_%s_%02d" % (projekt, _nummer(e["name"]))), + (sch.F_VF_TYP, typ), + (sch.F_RICHTUNG, a.get("ANTRIEBFAHRTRICHTUNG") or sch.RICHTUNG_AUF), + (sch.F_DELTA_L, _r(_float(a.get("DELTA_L_mm")))), + (sch.F_DELTA_H, _r(_float(a.get("DELTA_H_mm")))), + (sch.F_WINKEL, int(_float(a.get("VF_WINKEL")))), + (sch.F_L_GF1, _r(1000.0 * _float(l_gf[0])) if l_gf else 0.0), + (sch.F_SEITE, a.get("SEITE_AS") or sch.SEITE_RECHTS), + (sch.F_MOTORSEITE, (a.get("MOTORSEITE") or sch.SEITE_RECHTS).split(",")[0]), + (sch.F_HZ, _r(_float(xd[1]) if len(xd) > 1 else 0.0)), + (sch.F_X, _r(e["p"][0])), (sch.F_Y, _r(e["p"][1])), (sch.F_Z, _r(e["p"][2])), + (sch.F_COMMENT, "aus Zeichnung: %s (ID %s), Hoehe %s -> %s; deltaL/" "deltaH aus den (ganzzahligen) Attributen" % (e["name"], a.get("ID", "?"), a.get("HOEHE_VON_mm", "?"), a.get("HOEHE_BIS_mm", "?"))), @@ -311,10 +312,10 @@ def vf_journal_eintrag(e, projekt, nr): roh = "".join(e["xdata"]["SSG_VF_EDIT"][1:]) tokens = [t for t in roh.split(TRENNER) if t] return collections.OrderedDict([ - ("test_id", "VF_%s_LZ_%02d" % (projekt, nr)), - ("typ", "linienzug_journal"), + (sch.F_TEST_ID, "VF_%s_LZ_%02d" % (projekt, nr)), + (sch.F_VF_TYP, "linienzug_journal"), ("journal", tokens), - ("comment", "aus Zeichnung: %s (ID %s), %d Eingaben, Hoehe %s -> %s; " + (sch.F_COMMENT, "aus Zeichnung: %s (ID %s), %d Eingaben, Hoehe %s -> %s; " "wird 1:1 abgespielt (vsp-bau-journal)" % (e["name"], a.get("ID", "?"), len(tokens), a.get("HOEHE_VON_mm", "?"), a.get("HOEHE_BIS_mm", "?"))), @@ -326,11 +327,11 @@ def einzel_eintrag(e): info = ", ".join("%s %s" % (k, a[k]) for k in ("ID", "ZUORDNUNG", "ARTINR") if a.get(k)) return collections.OrderedDict([ - ("function", "insert"), - ("block", DIM_SUFFIX.sub("", e["name"])), - ("x", _r(e["p"][0])), ("y", _r(e["p"][1])), ("z", _r(e["p"][2])), - ("rotation", _r(e["rot"])), - ("comment", "aus Zeichnung: %s%s" % (e["name"], + (sch.F_FUNCTION, sch.FUNC_INSERT), + (sch.F_BLOCK, DIM_SUFFIX.sub("", e["name"])), + (sch.F_X, _r(e["p"][0])), (sch.F_Y, _r(e["p"][1])), (sch.F_Z, _r(e["p"][2])), + (sch.F_ROTATION, _r(e["rot"])), + (sch.F_COMMENT, "aus Zeichnung: %s%s" % (e["name"], (" (%s)" % info) if info else "")), ]) @@ -390,11 +391,11 @@ def main(): eintraege, hinweise = baue_eintraege(inserts, block_inhalt, projekt) zaehler = collections.Counter( - "Kreisel" if "abstand" in e else - "GF" if "modus" in e else - "VF Linienzug" if e.get("typ") == "linienzug_journal" else - "VF %s" % e["typ"] if "typ" in e and "test_id" in e else - e.get("block", "?") for e in eintraege) + "Kreisel" if sch.F_ABSTAND in e else + "GF" if sch.F_MODUS in e else + "VF Linienzug" if e.get(sch.F_VF_TYP) == "linienzug_journal" else + "VF %s" % e[sch.F_VF_TYP] if sch.F_VF_TYP in e and sch.F_TEST_ID in e else + e.get(sch.F_BLOCK, "?") for e in eintraege) for k, v in sorted(zaehler.items()): print("%s %-22s %d" % (PREFIX, k, v)) for h in hinweise: diff --git a/lib/testdata_schema.py b/lib/testdata_schema.py new file mode 100644 index 0000000..a1e5e11 --- /dev/null +++ b/lib/testdata_schema.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +testdata_schema.py - Feldnamen und feste Werte der JSON-Testdaten-Schemas aus +doc/json-input-lisp.md, als einzige Quelle fuer alle Erzeuger. + +Bisher standen dieselben Feldnamen ("function", "abstand", "deltaL_mm", +"as_seite", ...) als lose String-Literale unabhaengig in dxf_scan_components.py +(fremde Zeichnungen) UND dxf_anlage_export.py (eigene, mit unseren Makros +gebaute Zeichnungen) - ein Tippfehler oder eine Schema-Aenderung in nur einer +der beiden Dateien waere nicht aufgefallen. Dieses Modul buendelt sie an +einer Stelle; die LISP-Treiber (tests/test_*.lsp) lesen die JSON-Keys direkt +als Strings und sind davon nicht betroffen. + +Nur Feldnamen/feste Werte, KEINE Validierung oder Default-Logik - die bleibt +bewusst in den jeweiligen Erzeugern, deren Kontext (fremde vs. eigene +Zeichnung) unterschiedliche Fallbacks braucht. +""" + +# --- Gemeinsame Felder --- +F_FUNCTION = "function" +F_ID = "id" +F_TEST_ID = "test_id" +F_BLOCK = "block" +F_X = "x" +F_Y = "y" +F_Z = "z" +F_ROTATION = "rotation" +F_COMMENT = "comment" + +FUNC_INSERT = "insert" +FUNC_CONNECT = "connect" + +# --- Abschnitt 1 (json-input-lisp.md): Kreisel --- +F_ABSTAND = "abstand" +F_TYP = "typ" +F_DREHRICHTUNG = "drehrichtung" + +TYP_STANDARD = "STANDARD" +TYP_PIN = "PIN" +DREHRICHTUNG_UZS = "UZS" +DREHRICHTUNG_GUZ = "GUZ" + +# --- Abschnitt 3: VarioFoerderer Standard und Etage --- +F_VF_TYP = "typ" +F_RICHTUNG = "richtung" +F_DELTA_L = "deltaL" +F_DELTA_H = "deltaH" +F_WINKEL = "winkel" +F_L_GF1 = "L_GF1" +F_GF_VERTEILUNG = "gf_verteilung" +F_SEITE = "seite" +F_MOTORSEITE = "motorseite" +F_HZ = "hz" + +VF_TYP_STANDARD = "standard" +VF_TYP_ETAGE = "etage" +RICHTUNG_AUF = "Auf" +RICHTUNG_AB = "Ab" +SEITE_LINKS = "links" +SEITE_RECHTS = "rechts" + +# --- Abschnitt 4.1: Gefaellestrecke Modus 1 --- +F_MODUS = "modus" +F_DELTAL_MM = "deltaL_mm" +F_WINKEL_GRAD = "winkel_grad" +F_HZ_GRAD = "hz_grad" +F_START_MM = "start_mm" +F_AS_SEITE = "as_seite" +F_ES_SEITE = "es_seite" +F_AS_WINKEL = "as_winkel" +F_ES_WINKEL = "es_winkel" + +GF_MODUS_WERTEINGABE = 1 +GF_MODUS_RICHTUNG_AUS_PUNKTEN = 2 +GF_MODUS_LINIENZUG = 3 + +SCHLEUS_WINKEL_90 = "90" +SCHLEUS_WINKEL_30 = "30" From b0322a4f3cd212407b57fa72534dc35cf108dda5 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 10:47:23 +0200 Subject: [PATCH 28/38] [CHANGE] Batch-Wrapper fuer dxf_anlage_export.py, dxf_scan_components.py, dxf_vf_abbild.py Drei neue bin/*.bat nach dem bestehenden Pass-Through-Muster (setenv.bat + python ... %*, siehe set_einfuegepunkt.bat/dbg2lsp.bat), damit diese lib/-Skripte wie die uebrigen Python-Kommandozeilen bequem ueber bin/ aufrufbar sind. doc/kommandos.md Abschnitt 3 ergaenzt. Co-Authored-By: Claude Sonnet 5 --- bin/dxf_anlage_export.bat | 13 +++++++++++++ bin/dxf_scan_components.bat | 14 ++++++++++++++ bin/dxf_vf_abbild.bat | 14 ++++++++++++++ doc/kommandos.md | 3 +++ 4 files changed, 44 insertions(+) create mode 100644 bin/dxf_anlage_export.bat create mode 100644 bin/dxf_scan_components.bat create mode 100644 bin/dxf_vf_abbild.bat diff --git a/bin/dxf_anlage_export.bat b/bin/dxf_anlage_export.bat new file mode 100644 index 0000000..40952ca --- /dev/null +++ b/bin/dxf_anlage_export.bat @@ -0,0 +1,13 @@ +@echo off +REM ================================================================ +REM Mit unseren Makros gebaute (und von Hand nachbearbeitete) Anlage +REM aus einer Zeichnung in Nachbau-Testdaten zurueckschreiben. +REM Siehe doc/kommandos.md, doc/json-input-lisp.md. +REM +REM Aufruf: +REM bin\dxf_anlage_export.bat [--projekt NAME] +REM ================================================================ + +call "%~dp0setenv.bat" + +python "%DXFM_LIB%\dxf_anlage_export.py" %* diff --git a/bin/dxf_scan_components.bat b/bin/dxf_scan_components.bat new file mode 100644 index 0000000..b8abe93 --- /dev/null +++ b/bin/dxf_scan_components.bat @@ -0,0 +1,14 @@ +@echo off +REM ================================================================ +REM Erkennt ILS-/Omniflo-Komponenten in einer FREMDEN Projektzeichnung +REM (ohne unsere Wrapper-Bloecke) und schreibt sie als Nachbau-JSON. +REM Siehe doc/kommandos.md, doc/json-input-lisp.md. +REM +REM Aufruf: +REM bin\dxf_scan_components.bat +REM [--fenster X0 Y0 X1 Y1] [--projekt NAME] +REM ================================================================ + +call "%~dp0setenv.bat" + +python "%DXFM_LIB%\dxf_scan_components.py" %* diff --git a/bin/dxf_vf_abbild.bat b/bin/dxf_vf_abbild.bat new file mode 100644 index 0000000..ee5fd21 --- /dev/null +++ b/bin/dxf_vf_abbild.bat @@ -0,0 +1,14 @@ +@echo off +REM ================================================================ +REM Attribut-/Bausteinabbild der VF_/GF_-Wrapperbloecke einer +REM Testzeichnung - Regressionsnetz fuer Umbauten am Bau-Ablauf. +REM Siehe doc/kommandos.md. +REM +REM Aufruf: +REM bin\dxf_vf_abbild.bat [--spec S] [--json J] [--referenz R] +REM [--schreibe-referenz] [--praefix VF_,GF_] +REM ================================================================ + +call "%~dp0setenv.bat" + +python "%DXFM_LIB%\dxf_vf_abbild.py" %* diff --git a/doc/kommandos.md b/doc/kommandos.md index 8a8417d..b903441 100644 --- a/doc/kommandos.md +++ b/doc/kommandos.md @@ -222,6 +222,9 @@ Alle Skripte rufen zuerst `setenv.bat` (bzw. `setenv.sh`) auf. | `set_coords.bat [schalter]` | Wrapper fuer `lib/set_koords.py` (siehe `doc/tools.md`) | | `dbg2lsp.bat [argumente]` | Wrapper fuer `lib/dbg2lsp.py` (siehe `doc/dbg2lsp.md`) | | `show_exportcsv.bat [csv] [flow] [mflow] [track]` | Export-CSV mit sps_skel als SVG darstellen; `flow` ohne VF/GF-Einzelbausteine, `mflow` Materialfluss-Graph, `track` Bahnzusammenhang (beide brauchen Graphviz) | +| `dxf_anlage_export.bat [--projekt NAME]` | Wrapper fuer `lib/dxf_anlage_export.py` | +| `dxf_scan_components.bat [--fenster X0 Y0 X1 Y1] [--projekt NAME]` | Wrapper fuer `lib/dxf_scan_components.py` | +| `dxf_vf_abbild.bat [--spec S] [--json J] [--referenz R] [--schreibe-referenz] [--praefix VF_,GF_]` | Wrapper fuer `lib/dxf_vf_abbild.py` | ### `run_tests.bat` From fe4637d7df7ac7e911e0cb0ed437b2319924d610 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 10:51:12 +0200 Subject: [PATCH 29/38] [FIX] doc/tools.md: veraltete Item-Zahlen korrigiert, Aufruf vereinheitlicht; set_coords.bat Copy-Paste-Kommentar behoben Datenbasis (data/json/omniflo_*.json) hat sich seit der letzten Doku-Pflege verschoben: Boegen 27->29, Delta 1->7, Sternweiche 1->2, Dreifachweiche 6->0 (Typ aktuell nicht mehr in den Daten vorhanden), Gesamt 107->110. Schalter/Filterkriterien selbst (SWITCH_FILTERS in lib/omniflo_utils.py) sind unveraendert und weiterhin korrekt dokumentiert. set_koords-Aufruf im Dokument auf bin\set_coords.bat vereinheitlicht (war inkonsistent zu set_einfuegepunkt.bat, das korrekt den bin\-Wrapper nennt). bin/set_coords.bat trug noch den Kopfkommentar von set_einfuegepunkt.bat (Copy-Paste-Fehler) - korrigiert auf den tatsaechlichen Zweck (K1-K4 setzen). Co-Authored-By: Claude Sonnet 5 --- bin/set_coords.bat | 2 +- doc/tools.md | 29 ++++++++++++++++++----------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/bin/set_coords.bat b/bin/set_coords.bat index 4bc3eee..7354666 100644 --- a/bin/set_coords.bat +++ b/bin/set_coords.bat @@ -1,6 +1,6 @@ @echo off REM ================================================================ -REM Setzt Einfuegepunkte fuer Omniflo DXF-Dateien +REM Setzt Koordinatensystem-Bloecke (K1-K4) in Omniflo DXF-Dateien REM ================================================================ call "%~dp0setenv.bat" diff --git a/doc/tools.md b/doc/tools.md index 92efe5d..5e01b66 100644 --- a/doc/tools.md +++ b/doc/tools.md @@ -70,7 +70,7 @@ Die JSON-Dateien liefern die IDs (Sivasnr) und Metadaten zur Filterung. Die DXF- ### --boegen -Alle Eintraege aus `omniflo_boegen.json` (27 Items, KurvenWinkel 22.5/45/67.5/90/180). +Alle Eintraege aus `omniflo_boegen.json` (29 Items, KurvenWinkel 22.5/45/67.5/90/180). **Kriterium:** Schnittpunkt der Tangenten am Anfangs- und Endpunkt der Bogenkurve. Bei 180-Grad-Boegen wird der Mittelpunkt zwischen Start und Ende verwendet. @@ -103,19 +103,21 @@ Einzel-, Doppel- und Dreiwegeweichen mit KurvenWinkel 0, ohne Sternweiche (8 Ite ### --delta -Deltaweichen (1 Item). +Deltaweichen (7 Items). **Kriterium:** Mittelpunkt der laengsten horizontalen Linie. ### --dreifachweiche -Dreifachweichen (6 Items). +Dreifachweichen (aktuell 0 Items in `omniflo_weichen.json` - Schalter und +Filterkriterium existieren weiter in `lib/omniflo_utils.py` fuer den Fall, +dass wieder Dreifachweichen-Daten gepflegt werden). **Kriterium:** Mittelpunkt der laengsten horizontalen Linie. ### --sternweiche -Sternweiche (1 Item). +Sternweiche (2 Items). **Kriterium:** Zentrum, berechnet als Mittelpunkt der laengsten horizontalen Linie (entspricht dem Schnittpunkt der horizontalen und vertikalen Mittelachse). @@ -135,21 +137,24 @@ Hier die Weichen ## Abdeckung -Alle 107 Items (27 Boegen + 80 Weichen) sind exklusiv genau einem Schalter zugeordnet. Keine Ueberlappungen, keine Luecken. +Alle 110 Items (29 Boegen + 81 Weichen, Stand aktuelle `data/json/omniflo_*.json`) +sind exklusiv genau einem Schalter zugeordnet. Keine Ueberlappungen, keine +Luecken. Die Zahlen je Schalter verschieben sich mit der Datenbasis; bei +Zweifel per `SWITCH_FILTERS` (`lib/omniflo_utils.py`) nachrechnen. ## Uebersicht aller Schalter | Schalter | Items | WeichenTyp | KurvenWinkel | Einfuegepunkt-Kriterium | | --- | --- | --- | --- | --- | -| `--boegen` | 27 | - | 22.5, 45, 67.5, 90, 180 | Tangentenschnittpunkt am Bogen (180: Mittelpunkt) | +| `--boegen` | 29 | - | 22.5, 45, 67.5, 90, 180 | Tangentenschnittpunkt am Bogen (180: Mittelpunkt) | | `--weichen45` | 32 | Einzel-, Doppel-, Dreiwegeweiche | 45 | Tangente oberer Bogenpunkt x laengste Vertikale | | `--weichen90` | 24 | Einzel-, Doppel-, Dreiwegeweiche | 90 | Tangente oberer Bogenpunkt x laengste Vertikale | | `--weichenkoerper` | 8 | Einzel-, Doppel-, Dreiwegeweiche | 22.5 | Laengste Diagonale x laengste Vertikale | | `--weichen-parallel` | 8 | Einzel-, Doppel-, Dreiwegeweiche | 0 | Laengste Diagonale x laengste Vertikale | -| `--dreifachweiche` | 6 | Dreifachweiche | 90 | Mittelpunkt laengste Horizontale | -| `--delta` | 1 | Deltaweiche | 90 | Mittelpunkt laengste Horizontale | -| `--sternweiche` | 1 | Sternweiche | 0 | Zentrum (Mittelpunkt laengste Horizontale) | -| **Gesamt** | **107** | | | | +| `--dreifachweiche` | 0 | Dreifachweiche | 90 | Mittelpunkt laengste Horizontale | +| `--delta` | 7 | Deltaweiche | 90 | Mittelpunkt laengste Horizontale | +| `--sternweiche` | 2 | Sternweiche | 0 | Zentrum (Mittelpunkt laengste Horizontale) | +| **Gesamt** | **110** | | | | ## Umgebungsvariablen @@ -169,9 +174,11 @@ Setzt Koordinatensystem-Bloecke (K1, K2, K3, K4) in Omniflo DXF-Dateien. Jeder B ## Aufruf ``` -python lib/set_koords.py [--schalter] [--number SIVASNR] [--force] +bin\set_coords.bat [--schalter] [--number SIVASNR] [--force] ``` +Das Batch-Skript ruft `setenv.bat` auf und startet `lib/set_koords.py` mit den uebergebenen Argumenten. + ## Datenquellen | Pfad | Inhalt | From 5aed90dd5603f32a8d1c4808bf16909bce78f75b Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 10:56:54 +0200 Subject: [PATCH 30/38] [CHANGE] doc/plan und doc/todo angelegt, interne Analyse-/TODO-Dokumente dorthin verschoben doc/todo/: TODO-plan-vf-interactive.md -> plan-vf-interactive.md, TODO-modus2-achsenweise-bilanz.md -> modus2-achsenweise-bilanz.md (offene Fahrplaene/TODOs). doc/plan/: KS-Frame-Architektur.md, vf-parameter-struct-analyse.md, translate.md, Entwicklungsplan.md (Architektur-Analysen und Planungsdokumente, kein Anwender-Material). Alle internen Verweise (CLAUDE.md, Lisp/README.md, README.md, doc/variofoerderer.md, Lisp/vf_spec.lsp, lib/dxf_vf_abbild.py, lib/vf_spec_export.py, tests/test_hm_recformat.lsp, tests/test_vf_geometrie.py, tests/test_vf_headless_statisch.py) auf die neuen Pfade angepasst. Reine Pfad-Updates in Kommentaren/Docstrings, keine funktionale Aenderung - Python-Syntax nach dem Umbau geprueft. Anwender-/Entwickler-Referenzdoku (faq.md, kommandos.md, tools.md, dbg2lsp.md, csv-export.md, json-input-lisp.md, lisp_methods.md, LispTests.md, variofoerderer.md, vf_linienzug_modus1_anleitung.md) bleibt direkt in doc/. Co-Authored-By: Claude Sonnet 5 --- CLAUDE.md | 8 ++++---- Lisp/README.md | 2 +- Lisp/vf_spec.lsp | 2 +- README.md | 4 ++-- doc/{ => plan}/Entwicklungsplan.md | 0 doc/{ => plan}/KS-Frame-Architektur.md | 0 doc/{ => plan}/translate.md | 0 doc/{ => plan}/vf-parameter-struct-analyse.md | 0 .../modus2-achsenweise-bilanz.md} | 0 .../plan-vf-interactive.md} | 0 doc/variofoerderer.md | 2 +- lib/dxf_vf_abbild.py | 2 +- lib/vf_spec_export.py | 2 +- tests/test_hm_recformat.lsp | 2 +- tests/test_vf_geometrie.py | 2 +- tests/test_vf_headless_statisch.py | 2 +- 16 files changed, 14 insertions(+), 14 deletions(-) rename doc/{ => plan}/Entwicklungsplan.md (100%) rename doc/{ => plan}/KS-Frame-Architektur.md (100%) rename doc/{ => plan}/translate.md (100%) rename doc/{ => plan}/vf-parameter-struct-analyse.md (100%) rename doc/{TODO-modus2-achsenweise-bilanz.md => todo/modus2-achsenweise-bilanz.md} (100%) rename doc/{TODO-plan-vf-interactive.md => todo/plan-vf-interactive.md} (100%) diff --git a/CLAUDE.md b/CLAUDE.md index 82cca61..f2ea156 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -104,8 +104,8 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `ssg_blocktools.lsp` | SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN | Block-Werkzeuge fuer das aktuelle Layout (Ursprung ACADSST `TOOLS.LSP`/`ssg.lsp`): Einfuegungen zaehlen (Pick, wcmatch-Muster oder Statistik aller Bloecke), alle Einfuegungen loeschen (Rueckfrage, gesperrte Layer bleiben), Attributwerte zeichnungsweit/in Auswahl suchen+ersetzen (Vorschau mit Anzahl, Teilstring oder Gesamtwert). Wirksamer Blockname (dynamische Bloecke). Reine Kerne `ssg-bt-name-passt-p`, `ssg-bt-zaehle-namen`, `ssg-bt-wert-neu` in `tests/test_unit.lsp` getestet | | `ssg_texttools.lsp` | SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL | Text-Werkzeuge (Ursprung ACADSST `CHGTEXT`/`PARTEXT`/`ALTHOEHE`/`ALTSTIL`): Suchen/Ersetzen in TEXT, MTEXT und Block-Attributen (nutzt `ssg-bt-*`, daher NACH `ssg_blocktools` laden), Text parallel zu Linie/Polylinie/Bogen (lesbar ausgerichtet, Abstand), Hoehe/Stil aendern. Arbeitet in der XY-Ebene des Welt-KS. Reine Kerne `ssg-tt-lesbarer-winkel`, `ssg-tt-versetzt` getestet | | `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad | ILS Kreisel und Eckrad komplett in AutoLISP | -| `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) bleibt bewusst reine Konsole (im Code selbst als Legacy/"wird umgebaut" markiert). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/TODO-plan-vf-interactive.md`. Details/Entscheidungsbaum: `doc/variofoerderer.md` | -| `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/TODO-plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus` (Replay-Kern `vsp-bau-journal` - nimmt auch ein unveraendert uebernommenes, aufgezeichnetes Journal, z.B. aus `dxf_anlage_export.py`). Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | +| `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) bleibt bewusst reine Konsole (im Code selbst als Legacy/"wird umgebaut" markiert). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/todo/plan-vf-interactive.md`. Details/Entscheidungsbaum: `doc/variofoerderer.md` | +| `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/todo/plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus` (Replay-Kern `vsp-bau-journal` - nimmt auch ein unveraendert uebernommenes, aufgezeichnetes Journal, z.B. aus `dxf_anlage_export.py`). Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | | `Gefaellestrecke.lsp` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN); Modus 1 per DCL-Dialog (Einfuegehoehe, Element-Winkel 30/90); Doppelklick auf GF_n-Block ruft GEFAELLESTRECKE_EDIT (Dialog vorbelegt, Neuaufbau) | | `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_UPDATE_ATTRIBS, CSV_EXPORT_KONFIG | JSON-Sammlung und Python-Export (Omniflo-Merkmale/Sum-Zeile via lib/export_csv.py). **Gefrorene Layer**: `csv:collect-export-blocks` laesst Bloecke auf gefrorenen Layern aus (ausgeschaltete Layer zaehlen NICHT), Schalter `*csv-gefrorene-ausschliessen*` (Standard an, Toggle im Dialog CSV_EXPORT_KONFIG). Die Hilfsobjekte eines gefrorenen VF_n/GF_n (Separator-/Element-Kopien, Einheiten-/AS-ES-Marker) liegen auf eigenen Layern und werden darum ueber `*csv-ausschluss-enames*` mit ausgelassen (gesetzt in `csv:export-vorbereiten` per `csv:hilfskopien-ausschluss`); erzeugt und nummeriert werden sie trotzdem, damit IDs stabil bleiben. DrawPlanquadrate nutzt dieselbe Sammlung und folgt dem Filter | | `OmniModulInsert.lsp` | OMNI_LOAD, OMNI_APB_*, OMNI_W*_*, OMNI_AP60/AP110, OMNI_TEF_*, OMNI_TV_*, OMNI_APBW_*, OMNI_LADESCHLEIFE_AP110, OMNI_EDIT | Omniflo-Komponenten: Boegen, Weichen, Verbinder, Transferwagen, Ladeschleifen (`data/json/omniflo_ladeschleifen.json`, per `ssg-json-laden`, da die Beschreibungen Kommas enthalten; Blockdatei darf `.dwg` statt `.dxf` sein), Edit-Dialog | @@ -174,7 +174,7 @@ Werden via `bin/setenv.bat` gesetzt. Wichtigste: - Die **Farbe** wirkt nur bei der Neuanlage des Layers (`ssg-make-layer` laesst bestehende Layer unveraendert, damit Kundenzeichnungen nicht umgefaerbt werden). Layer, die eine Blockdatei aus `data/ils` selbst mitbringt (z.B. `ILS_SP`/`_3D_ILS_SP`), legt BricsCAD schon beim Einfuegen des Blocks mit der Farbe **aus der DWG** an - dort greift die cfg-Farbe nicht, wohl aber der Layername des Wrappers. Fuer Layer ohne Baugruppen-Key gibt es zusaetzlich den Abschnitt `[farben]` (Layername = Farbe), gelesen von `ssg-layer-farbe-fuer-name`. - Komponentendaten (Masse, Sivas-IDs) liegen als JSON in `data/json/` - Sprache im Code und Kommentaren: Deutsch -- **Benutzermeldungen sind ZWEISPRACHIG (de/en)**: Jede an den Anwender gerichtete Meldung (`princ`/`alert`/`getstring`/`getint`/`getreal`/`getkword`-Prompts, auch per `strcat` zusammengesetzte) laeuft ueber `(ssg-text "key")` bzw. `(ssg-textf "key" (list args))`. Die Texte stehen in `lang/de_DE.json` UND `lang/en_GB.json` unter `"texts"` und muessen key-fuer-key synchron bleiben (Paritaets-Check vor dem Commit). Konventionen: Key-Prefix je Modul (`vfc-` vf_core, `gf-` Gefaellestrecke), geteilte Prompts ohne Prefix (`prompt-wahl-1-2` usw.) - vor dem Anlegen eines neuen Keys erst die JSONs nach dem deutschen String grep'en und wiederverwenden. Sonderzeichen wie Grad `(chr 176)` / Delta `(chr 916)` als `%n`-Platzhalter uebergeben, nicht in die (ASCII-)JSON einbetten. **Untranslatiert bleiben** (bewusst): Bracket-Diagnosen (`[vf_core]` o.ae.), die VOR dem garantierten Laden von `ssg_lang.lsp` feuern (Bootstrap-Fallbacks am Dateikopf - `ssg-text` existiert dort noch nicht), Lade-Banner (`>>> ... geladen`), reine `====`/`---`-Trenner und reine Entwickler-Diagnosebefehle (nicht im Menue). Details und Entscheidungsbaum: `doc/translate.md`. +- **Benutzermeldungen sind ZWEISPRACHIG (de/en)**: Jede an den Anwender gerichtete Meldung (`princ`/`alert`/`getstring`/`getint`/`getreal`/`getkword`-Prompts, auch per `strcat` zusammengesetzte) laeuft ueber `(ssg-text "key")` bzw. `(ssg-textf "key" (list args))`. Die Texte stehen in `lang/de_DE.json` UND `lang/en_GB.json` unter `"texts"` und muessen key-fuer-key synchron bleiben (Paritaets-Check vor dem Commit). Konventionen: Key-Prefix je Modul (`vfc-` vf_core, `gf-` Gefaellestrecke), geteilte Prompts ohne Prefix (`prompt-wahl-1-2` usw.) - vor dem Anlegen eines neuen Keys erst die JSONs nach dem deutschen String grep'en und wiederverwenden. Sonderzeichen wie Grad `(chr 176)` / Delta `(chr 916)` als `%n`-Platzhalter uebergeben, nicht in die (ASCII-)JSON einbetten. **Untranslatiert bleiben** (bewusst): Bracket-Diagnosen (`[vf_core]` o.ae.), die VOR dem garantierten Laden von `ssg_lang.lsp` feuern (Bootstrap-Fallbacks am Dateikopf - `ssg-text` existiert dort noch nicht), Lade-Banner (`>>> ... geladen`), reine `====`/`---`-Trenner und reine Entwickler-Diagnosebefehle (nicht im Menue). Details und Entscheidungsbaum: `doc/plan/translate.md`. - **Subagenten** sollten von Claude nur mit Rückfrage an den Nutzer gestartet werden. Dabei sollten wenn möglich die leichteren Modelle gewählt werden, da es sich dabei in der Regel um Code recherche handelt. ## Python-Bibliotheken @@ -211,7 +211,7 @@ Abhaengigkeiten: `ezdxf`, Standard-Library. Benoetigen Umgebungsvariablen (`DXFM ## Entwicklungsstand -Siehe `doc/Entwicklungsplan.md` fuer Meilensteinplanung und Aufwandsschaetzung. +Siehe `doc/plan/Entwicklungsplan.md` fuer Meilensteinplanung und Aufwandsschaetzung. Fertig (DONE): ILS Kreisel, ILS Eckrad, ILS Variofoerderer, ILS BTMT Be-/Entladung (Einfuegen), Omniflo Boegen, Omniflo Weichen. ## Debug diff --git a/Lisp/README.md b/Lisp/README.md index 05d5e12..48c6d1f 100644 --- a/Lisp/README.md +++ b/Lisp/README.md @@ -190,7 +190,7 @@ Interne Parser-Funktionen (nicht direkt aufrufen): ### `ssg_lang.lsp` – Sprachumschaltung (Deutsch/Englisch) -Zentrale Textverwaltung fuer benutzersichtbare Meldungen. Kern-Modul, wird direkt nach `ssg_core` geladen. Wird schrittweise auf weitere Module ausgerollt (siehe `doc/translate.md`). +Zentrale Textverwaltung fuer benutzersichtbare Meldungen. Kern-Modul, wird direkt nach `ssg_core` geladen. Wird schrittweise auf weitere Module ausgerollt (siehe `doc/plan/translate.md`). | Funktion | Beschreibung | | --- | --- | diff --git a/Lisp/vf_spec.lsp b/Lisp/vf_spec.lsp index 66609ff..bd8fe61 100644 --- a/Lisp/vf_spec.lsp +++ b/Lisp/vf_spec.lsp @@ -1,7 +1,7 @@ ;; ============================================================ ;; vf_spec.lsp - VF-Linienzug aus Eingabedaten bauen (ohne GUI/Konsole) ;; ============================================================ -;; Stufe 1 des Fahrplans in doc/TODO-plan-vf-interactive.md. +;; Stufe 1 des Fahrplans in doc/todo/plan-vf-interactive.md. ;; ;; Eine SPEC beschreibt eine Kette in Domaenenwerten ("links", "winkel", ;; "aussen", ja/nein) statt in Menue-Codes: lesbar, schreibbar, versionierbar. diff --git a/README.md b/README.md index 61630db..9715b25 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ dxfmakros/ ├── cfg/ # Konfigurationsdateien ├── data/ # JSON-Daten, DXF-Quellen, Block-Libraries - nicht im Git ├── dcl/ # DCL-Dialogdefinitionen -├── doc/ # Dokumentation, Entwicklungsplan +├── doc/ # Dokumentation (doc/plan Architektur/Analysen, doc/todo offene Fahrplaene) ├── lib/ # Python-Skripte (DXF-Bearbeitung, Export) ├── log/ # Logdateien - nicht im Git ├── menu/ # BricsCAD-Menudefinition (SSG_LIB.mnu, SSG_LIB.mnl) @@ -114,7 +114,7 @@ Zeichnungs-/Szenario-Tests laufen interaktiv in BricsCAD ueber das Menue `Tests` ## Dokumentation -Ausfuehrliche Modul- und Befehlsdokumentation: `CLAUDE.md` (Projektanweisungen) und `Lisp/README.md`. Weitere Themen in `doc/` (u.a. `variofoerderer.md`, `translate.md`, `csv-export.md`, `Entwicklungsplan.md`, `faq.md`, `kommandos.md`). +Ausfuehrliche Modul- und Befehlsdokumentation: `CLAUDE.md` (Projektanweisungen) und `Lisp/README.md`. Weitere Anwender-/Entwickler-Themen direkt in `doc/` (u.a. `variofoerderer.md`, `csv-export.md`, `faq.md`, `kommandos.md`). Architektur-Analysen und Planungsdokumente in `doc/plan/` (u.a. `translate.md`, `Entwicklungsplan.md`), offene Fahrplaene/TODOs in `doc/todo/`. ## Lizenz diff --git a/doc/Entwicklungsplan.md b/doc/plan/Entwicklungsplan.md similarity index 100% rename from doc/Entwicklungsplan.md rename to doc/plan/Entwicklungsplan.md diff --git a/doc/KS-Frame-Architektur.md b/doc/plan/KS-Frame-Architektur.md similarity index 100% rename from doc/KS-Frame-Architektur.md rename to doc/plan/KS-Frame-Architektur.md diff --git a/doc/translate.md b/doc/plan/translate.md similarity index 100% rename from doc/translate.md rename to doc/plan/translate.md diff --git a/doc/vf-parameter-struct-analyse.md b/doc/plan/vf-parameter-struct-analyse.md similarity index 100% rename from doc/vf-parameter-struct-analyse.md rename to doc/plan/vf-parameter-struct-analyse.md diff --git a/doc/TODO-modus2-achsenweise-bilanz.md b/doc/todo/modus2-achsenweise-bilanz.md similarity index 100% rename from doc/TODO-modus2-achsenweise-bilanz.md rename to doc/todo/modus2-achsenweise-bilanz.md diff --git a/doc/TODO-plan-vf-interactive.md b/doc/todo/plan-vf-interactive.md similarity index 100% rename from doc/TODO-plan-vf-interactive.md rename to doc/todo/plan-vf-interactive.md diff --git a/doc/variofoerderer.md b/doc/variofoerderer.md index fd97fca..0b0c20a 100644 --- a/doc/variofoerderer.md +++ b/doc/variofoerderer.md @@ -448,7 +448,7 @@ Optionen, bei "Eigene Werte" zusaetzlich L_GF1 als Zahl) -> Bestaetigung ## 8b. Nicht-interaktiver Betrieb (Headless) Fuer Tests, Batch-Nachbau und den geplanten Spec-Bau (Fahrplan: -`doc/TODO-plan-vf-interactive.md`) muss eine Kette **ohne** Dialog und ohne +`doc/todo/plan-vf-interactive.md`) muss eine Kette **ohne** Dialog und ohne Konsolenfrage laufen. Drei Schalter greifen dabei ineinander: | Schalter | Datei | Wirkung | diff --git a/lib/dxf_vf_abbild.py b/lib/dxf_vf_abbild.py index 88a62d6..6b1584f 100644 --- a/lib/dxf_vf_abbild.py +++ b/lib/dxf_vf_abbild.py @@ -5,7 +5,7 @@ dxf_vf_abbild.py - Abbild der VF_/GF_-Wrapperbloecke einer Testzeichnung: Attribute und Bausteinliste je Kette. Zweck: Regressionsnetz fuer Umbauten am Bau-Ablauf. Nach jedem Schritt der -Funktionstrennung (doc/TODO-plan-vf-interactive.md, Stufe 2) muss die +Funktionstrennung (doc/todo/plan-vf-interactive.md, Stufe 2) muss die gebaute Geometrie unveraendert sein - "unveraendert" heisst hier: gleiche Attribute (inklusive der reihenfolgeabhaengigen Komma-Listen L_VF_m/L_GF_m/ GF_WINKEL, die in der Zeichnung unsichtbar, im Sivas-Export aber falsch diff --git a/lib/vf_spec_export.py b/lib/vf_spec_export.py index a52abc4..861b0a4 100644 --- a/lib/vf_spec_export.py +++ b/lib/vf_spec_export.py @@ -7,7 +7,7 @@ uebersetzen und zurueck. Eine Spec beschreibt eine Kette in Domaenenwerten ("links", "winkel", "aussen", ja/nein) statt in Menue-Codes und Journal-Tokens: lesbar, schreibbar und damit die Eingabeform fuer den nicht-interaktiven Bau -(Lisp/vf_spec.lsp, siehe doc/TODO-plan-vf-interactive.md Stufe 1). +(Lisp/vf_spec.lsp, siehe doc/todo/plan-vf-interactive.md Stufe 1). Zwei Richtungen, die einander pruefen: diff --git a/tests/test_hm_recformat.lsp b/tests/test_hm_recformat.lsp index bbd5972..3347780 100644 --- a/tests/test_hm_recformat.lsp +++ b/tests/test_hm_recformat.lsp @@ -10,7 +10,7 @@ ;; roh aus der XDATA einer echten Zeichnung. Damit ist dies der einzige Test, ;; der belegt, dass ein BESTEHENDER VF_n-Block weiter abspielbar bleibt - ;; also dass Doppelklick-Editieren und 2D/3D-Konvertierung an Altbestand -;; funktionieren (Invariante I1 in doc/TODO-plan-vf-interactive.md). Ein +;; funktionieren (Invariante I1 in doc/todo/plan-vf-interactive.md). Ein ;; spec-gebautes Journal kann das nicht zeigen, es kommt aus dem Uebersetzer. ;; ;; Darum in tests/alltests.json auf "disabled": true - er baut dieselbe diff --git a/tests/test_vf_geometrie.py b/tests/test_vf_geometrie.py index f62b708..ac8cd37 100644 --- a/tests/test_vf_geometrie.py +++ b/tests/test_vf_geometrie.py @@ -7,7 +7,7 @@ HundM-Ketten. Warum zusaetzlich zu tests/test_hundm05.py: der Ergebnis-Record sagt "executed, kein Prompt, Journal aufgegangen" - er sagt NICHT, ob dieselbe Geometrie herauskam wie vorher. Genau das ist bei der Funktionstrennung in -Stufe 2 (doc/TODO-plan-vf-interactive.md) das Risiko: die Reihenfolge der +Stufe 2 (doc/todo/plan-vf-interactive.md) das Risiko: die Reihenfolge der dL-Subtraktionen und der vfl-acc-*-Aufrufe IST Geometrie, und eine falsche Reihenfolge faellt in der Zeichnung nicht auf - nur im Sivas-Export. diff --git a/tests/test_vf_headless_statisch.py b/tests/test_vf_headless_statisch.py index f098990..60419fe 100644 --- a/tests/test_vf_headless_statisch.py +++ b/tests/test_vf_headless_statisch.py @@ -11,7 +11,7 @@ einem selten erreichten Zweig ein neues (alert ...) oder ein rohes (getreal ...) hinzufuegt. Genau das haelt dieser Test fest: die Fundstellen sind eingecheckt, jede neue muss hier bewusst eingetragen werden. -Hintergrund und Fahrplan: doc/TODO-plan-vf-interactive.md, +Hintergrund und Fahrplan: doc/todo/plan-vf-interactive.md, Mechanik: doc/variofoerderer.md Abschnitt 8b. """ From 2ef8f319ab7c156afe32a1a0d0bd380429fba882 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 11:02:35 +0200 Subject: [PATCH 31/38] [FIX] vf_linienzug_modus1_anleitung.md: Fragen-Tabelle und Stufe-2-Zahlen an aktuelle Testdatei angepasst tests/testdata/linienzug_tests_stufe2.json hat sich seit Erstellung des Dokuments geaendert (62 statt 57 Eingabe-Eintraege, zusaetzliche Separator-Vor/Nach-Fragen, Kettenende-Frage vor statt nach der Gefaelle-Berechnung). Fragen-Tabelle in Abschnitt 3 komplett neu durchnummeriert und mit den tatsaechlichen JSON-Kommentaren abgeglichen. Stufe-2-Ergebnis war veraltet: GF2=86mm/VF=286mm ersetzt durch die tatsaechlichen GF2=319mm/L_VF=48mm aus der Datei; Hoehenrest-Beispielrechnung in Abschnitt 5.a entsprechend angepasst. Fehlerhafter Fakt in Abschnitt 5.c korrigiert: linienzug_tests.json hat ebenfalls erwartung_dx_mm=638 (nicht dY=637 wie behauptet) - beide Testfaelle zeigen denselben dX-Versatz. Code-Fakten verifiziert und unveraendert korrekt: Winkeltabelle 3/6/9/12/15/18/21/27/33/39/45/51 Grad (data/json/component_defaults.json), *vfk-feste-horizontal-kettenende*=800mm, *vfl-gf-min-laenge*=400mm, vfl-winkel-stufe-entscheidung/berechne-alle-winkel/berechne-horizontale-mitte/vfl-loesche-seit/vfl-modus-abbruch-sichern existieren alle weiterhin, TEST_LINIENZUG_STUFE2 liest weiterhin linienzug_tests_stufe2.json. Co-Authored-By: Claude Sonnet 5 --- doc/vf_linienzug_modus1_anleitung.md | 95 +++++++++++++++------------- 1 file changed, 51 insertions(+), 44 deletions(-) diff --git a/doc/vf_linienzug_modus1_anleitung.md b/doc/vf_linienzug_modus1_anleitung.md index 3312fb1..3645412 100644 --- a/doc/vf_linienzug_modus1_anleitung.md +++ b/doc/vf_linienzug_modus1_anleitung.md @@ -57,43 +57,48 @@ ist der interessante Teil (siehe Abschnitt 4, Stufe 1/Stufe 2). Diese Tabelle zitiert die tatsaechlichen Konsolen-Fragen aus dem Testfall (Kommentar-Spalte = `kommentar`-Feld im JSON) und erklaert, was jede Frage -bedeutet. +bedeutet. Die Datei hat aktuell 62 Eingabe-Eintraege (ohne das Kopf-Objekt); +mehrere Eintraege pro Zeile sind zu einem Schritt zusammengefasst, wo eine +Antwort mehrere JSON-Eintraege verbraucht (z.B. eine Vario-Kurve = Winkel + +Seite + Variante = 3 Eintraege). -| # | Frage (sinngemaess) | Antwort im Beispiel | Bedeutung | +| # (JSON-Eintraege) | Frage (sinngemaess) | Antwort im Beispiel | Bedeutung | |---|---|---|---| | 1 | Startpunkt der Kette | Klick (X/Y) | Beliebiger Punkt in der Zeichnung | | 2 | Hoehe (Z) Startpunkt | 2154 | Absolute Einbauhoehe des Kettenanfangs | | 3 | AS-Element setzen? | Ja | Umlenkstation am Anfang - "AS" = Ausgangs-/Anfangs-Element | | 4 | AS-Element Winkel | 90 Grad | Baugroesse des Umlenkstations-Blocks (90 oder 30 Grad Kurvenradius) | | 5 | AS-Seite | links | Auf welcher Seite die Umlenkstation seitlich ausschwenkt | -| 6 | Naechstes Element | Horizontal-VF | Kettenanfang-Menue hat 6 Optionen (GF-Bogen, Vario-Kurve, Linie-GF, Linie-VF, Horizontal-VF, Linienende) | -| 7 | Endpunkt Horizontal-VF | Klick | Laenge/Richtung der ersten VF-Einheit | -| 8 | Ziel-Hoehe Eingang GF1 | 1980 | Hoehe, auf die der Eingangs-GF-Anteil der VF-Einheit einregelt | -| 9 | Ist der Endpunkt der Foerderer? | Nein | Innerhalb der VF-Einheit: "geht die Kette hier zu Ende?" | -| 10-13 | Naechstes im VarioFoerderer -> Vario-Kurve 90 rechts innen | - | Grundriss-Schwenk INNERHALB der laufenden VF-Einheit | -| 14 | Ist der Endpunkt der Foerderer? | Nein | s.o. | -| 15-16 | Horizontaler Foerderer, Endpunkt | Klick | Weiteres gerades VF-Sub-Segment | -| 17 | Ist der Endpunkt der Foerderer? | Nein | s.o. | -| 18-21 | Vario-Kurve 90 rechts innen | - | Zweiter Grundriss-Schwenk | -| 22 | Ist der Endpunkt der Foerderer? | Ja, nur Motorstation | Schliesst die 1. VF-Einheit ab (Motorstation, kein ES) | -| 23 | Ist das Kettenende (ES-Element)? | Nein, weiterbauen | Nach der Motorstation: geht die Kette weiter? | -| 24 | Zusaetzlichen Separator hier? | Nein | Optionaler Separator direkt an der Motorstation | -| 25 | Naechstes Element | Neue Linie: GF | Jetzt folgt ein reines Gefaellestrecke-Element (kein VF) | -| 26 | Laenge bestimmen ueber | Endpunkt waehlen | Alternativ: Zielhoehe zuerst festlegen (siehe `vfl-gf-laenge-modus`) | -| 27 | Endpunkt Gefaellestrecke | Klick | Bestimmt deltaL der GF-Geraden | -| 28-29 | Separator VOR / NACH? | Ja / Ja | GF-Stuecke werden ueber Separatoren mechanisch begrenzt | -| 30-31 | Gefaelle festlegen -> Neigungswinkel | 3 Grad | Direkter Winkel (Alternative: Zielhoehe -> Winkel wird berechnet) | -| 32 | Ist das Kettenende? | Nein, weiterbauen | 3-Optionen-Menue: Ja+ES / Ja ohne ES / Nein | -| 33 | Naechstes Element | Horizontal-VF (2. Einheit) | Neue VF-Einheit beginnt direkt am GF-Ausgang (Separator als Eingang) | -| 34-49 | (wie oben: Vario-Kurven, Auf/Ab-Foerderer 27 Grad) | - | s.o. | -| 50 | Ist der Endpunkt der Foerderer? | Ja, Motorstation + Kettenende | Startet den automatischen Kettenende-Abschluss | -| 51-53 | ES-Element setzen? / Winkel / Seite | Ja / 90 / links | Ausgangs-Element, spiegelbildlich zum AS-Element | -| 54 | Endpunkt Kettenende | Klick | Letzter gewuenschter Punkt der Kette | -| 55 | Ziel-Hoehe Kettenende | 2154 | Muss wieder exakt die Starthoehe sein | -| 56 | (automatisch, keine Eingabe) | - | Stufe-1/Stufe-2-Loeser rechnet, siehe Abschnitt 4 | -| 57 | GF2=86mm unter Mindestlaenge - trotzdem bauen? | Ja | Sicherheitsfrage, siehe Abschnitt 4 | +| 6 | Naechstes Element | Neue VF mit horizontalem Anfang | Kettenanfang-Menue hat 6 Optionen (GF-Bogen, Vario-Kurve, Linie-GF, Linie-VF, Horizontal-VF, Linienende) | +| 7 | Endpunkt der Linie | Klick | Laenge/Richtung der ersten VF-Einheit | +| 8 | Ziel-Hoehe fuer den horizontalen VF-Anfang | 1980 | Hoehe, auf die der Eingangs-GF-Anteil der VF-Einheit einregelt | +| 9-10 | Zusaetzlichen Separator VOR/NACH dem horizontalen Stueck? | Nein / Nein | Optionale Separatoren direkt am VF-Einlauf | +| 11 | Ist der Endpunkt der Foerderer? | Nein | Innerhalb der VF-Einheit: "geht die Kette hier zu Ende?" | +| 12-15 | Naechstes im VarioFoerderer -> Vario-Kurve 90 rechts innen | - | Grundriss-Schwenk INNERHALB der laufenden VF-Einheit | +| 16 | Ist der Endpunkt der Foerderer? | Nein | s.o. | +| 17-18 | Horizontaler Foerderer, Endpunkt | Klick | Weiteres gerades VF-Sub-Segment | +| 19-20 | Zusaetzlichen Separator VOR/NACH? | Nein / Nein | s.o. | +| 21 | Ist der Endpunkt der Foerderer? | Nein | s.o. | +| 22-25 | Vario-Kurve 90 rechts innen | - | Zweiter Grundriss-Schwenk | +| 26 | Ist der Endpunkt der Foerderer? | Ja, nur Motorstation | Schliesst die 1. VF-Einheit ab (Motorstation, kein ES) | +| 27 | Ist das Kettenende (ES-Element)? | Nein, weiterbauen | Nach der Motorstation: geht die Kette weiter? | +| 28 | Zusaetzlichen Separator hier? | Nein | Optionaler Separator direkt an der Motorstation | +| 29 | Naechstes Element | Neue Linie: GF | Jetzt folgt ein reines Gefaellestrecke-Element (kein VF) | +| 30 | Laenge bestimmen ueber | Endpunkt waehlen | Alternativ: Zielhoehe zuerst festlegen (siehe `vfl-gf-laenge-modus`) | +| 31 | Ist das Kettenende? | Nein, weiterbauen | 3-Optionen-Menue: Ja+ES / Ja ohne ES / Nein - kommt VOR der Gefaelle-/Laengenberechnung | +| 32 | Endpunkt Gefaellestrecke | Klick | Bestimmt deltaL der GF-Geraden | +| 33-34 | Separator VOR / NACH? | Ja / Ja | GF-Stuecke werden ueber Separatoren mechanisch begrenzt | +| 35-36 | Gefaelle festlegen -> Neigungswinkel | 3 Grad | Direkter Winkel (Alternative: Zielhoehe -> Winkel wird berechnet) | +| 37 | Naechstes Element | Neue VF mit horizontalem Anfang (2. Einheit) | Neue VF-Einheit beginnt direkt am GF-Ausgang (Separator als Eingang) | +| 38-55 | (wie oben: Separatoren, Vario-Kurven, Auf/Ab-Foerderer 27 Grad) | - | s.o.; Auf/Ab-Foerderer nutzt Index 8 der gueltigen Winkeltabelle-Kandidaten = 27 Grad | +| 56 | Ist der Endpunkt der Foerderer? | Ja, Motorstation + Kettenende | Startet den automatischen Kettenende-Abschluss | +| 57-59 | ES-Element setzen? / Winkel / Seite | Ja / 90 / links | Ausgangs-Element, spiegelbildlich zum AS-Element | +| 60 | Endpunkt Kettenende | Klick | Letzter gewuenschter Punkt der Kette | +| 61 | Ziel-Hoehe Kettenende | 2154 | Muss wieder exakt die Starthoehe sein | +| 62 | GF2=319mm unter Mindestlaenge (400mm) - trotzdem bauen? | Ja | Sicherheitsfrage, siehe Abschnitt 4 - Stufe-1/Stufe-2-Loeser rechnet dazwischen automatisch | -**Wichtig zu Frage 9/14/17 ("Ist der Endpunkt der Foerderer?"):** Diese Frage +**Wichtig zu "Ist der Endpunkt der Foerderer?"** (Eintraege 11/16/21/26 usw.): +Diese Frage kommt IMMER, wenn Sie innerhalb einer laufenden VF-Einheit einen Punkt gepickt haben. "Nein" heisst: der gepickte Punkt ist nur eine Zwischen-Etappe, es geht in derselben VF-Einheit weiter (Vario-Kurve, @@ -102,7 +107,7 @@ Motorstation - optional zusaetzlich mit ES-Element (echtes Kettenende). ## 4. Stufe 1 / Stufe 2 - wie die letzte Strecke berechnet wird -Am Kettenende (Frage 55/56) ist die Aufgabe: von der aktuellen Position/ +Am Kettenende (Eintrag 61/62) ist die Aufgabe: von der aktuellen Position/ Hoehe zur gewuenschten Ziel-Hoehe kommen, UND dabei die feste Baugruppe Motorstation + Separator (+ ES-Element, falls gewaehlt) unterbringen. Das Programm versucht das in zwei Stufen (`vfl-winkel-stufe-entscheidung`, @@ -111,25 +116,25 @@ Programm versucht das in zwei Stufen (`vfl-winkel-stufe-entscheidung`, - **Stufe 1 - Winkeltabelle:** Es probiert der Reihe nach die festen Vario-Kurven-Winkel 3/6/9/12/15/18/21/27/33/39/45/51 Grad durch (`berechne-alle-winkel`) und prueft, ob einer davon eine PASSENDE, - positive VF-Laenge ergibt. Das ist der Normalfall (siehe die Zeilen - "34-49" in der Tabelle: der Auf/Ab-Foerderer in der 2. VF-Einheit findet + positive VF-Laenge ergibt. Das ist der Normalfall (siehe die Zeile + "38-55" in der Tabelle: der Auf/Ab-Foerderer in der 2. VF-Einheit findet so einen passenden Winkel, Auswahl-Index 8 = 27 Grad). - **Stufe 2 - Horizontale Mitte + GF-Ausgleich:** Wenn KEIN Tabellenwinkel - passt (wie im Beispiel: alle 12 Kandidaten ergeben eine negative - VF-Laenge, die Reststrecke ist einfach zu kurz fuer einen echten + passt (wie im Beispiel am Kettenende: alle 12 Kandidaten ergeben eine + negative VF-Laenge, die Reststrecke ist einfach zu kurz fuer einen echten Vertikalbogen), rechnet `berechne-horizontale-mitte` eine andere Loesung: ein HORIZONTALES VF-Stueck (winkel=0) plus eine kurze Gefaellestrecke (GF2), die exakt den fehlenden Hoehenunterschied ausgleicht. Im Beispiel: - GF2=86mm, VF=286mm. + GF2=319mm, L_VF=48mm. Die Formel dahinter ist simpel und lohnt sich zu verinnerlichen: bei einem FESTEN Neigungswinkel von 3 Grad braucht ein Hoehenausgleich von `H` -Millimetern eine GF-Laenge von `H / tan(3 Grad) ~= H * 19`. Ein winziger -Hoehenrest von z.B. 49mm braucht demnach bereits ~935mm GF-Laenge - siehe -Abschnitt 5.a. GF2 im Beispiel (86mm) ist kuerzer als die uebliche -Mindestlaenge (400mm, `*vfl-gf-min-laenge*`) - deshalb die Rueckfrage in -Schritt 57 ("trotzdem mit 86mm bauen?"). "Ja" baut trotzdem exakt mit dem -berechneten Wert; "Nein" wuerde den bis dahin gebauten Teil verwerfen (siehe +Millimetern eine GF-Laenge von `H / tan(3 Grad) ~= H * 19`. Ein Hoehenrest +von z.B. 17mm braucht demnach bereits ~320mm GF-Laenge - siehe Abschnitt +5.a. GF2 im Beispiel (319mm) liegt knapp unter der uebliche Mindestlaenge +(400mm, `*vfl-gf-min-laenge*`) - deshalb die Rueckfrage im letzten Eintrag +("trotzdem mit 319mm bauen?"). "Ja" baut trotzdem exakt mit dem berechneten +Wert; "Nein" wuerde den bis dahin gebauten Teil verwerfen (siehe `vfl-loesche-seit`/`vfl-modus-abbruch-sichern`). **Merksatz:** Stufe 1 sucht einen "sauberen" Standard-Winkel; Stufe 2 ist @@ -169,9 +174,11 @@ Fallback ausloest. Ein AS- oder ES-Element mit 90 Grad Bauform dreht die Fahrtrichtung nicht einfach "auf der Stelle" - sein Block hat eine reale Baugroesse mit einem -seitlichen (quer zur Fahrtrichtung liegenden) Versatz. Im Standard-Testfall -(`linienzug_tests.json`) betraegt dieser Versatz ca. 637mm (`dY`), im -Stufe-2-Testfall ca. 638mm (`dX`, da die Fahrtrichtung dort anders liegt). +seitlichen (quer zur Fahrtrichtung liegenden) Versatz. Sowohl im Standard- +Testfall (`linienzug_tests.json`) als auch im Stufe-2-Testfall +(`linienzug_tests_stufe2.json`) betraegt dieser Versatz ca. 638mm (dort als +`erwartung_dx_mm` dokumentiert, da die Fahrtrichtung am Kettenende auf der +Y-Achse liegt und sich der Versatz dadurch in X statt in Y zeigt). **Das ist kein Baufehler** - es ist die tatsaechliche Geometrie des 90-Grad-ES/AS-Blocks. Ein "Ist-Ziel-Report" mit einer Restabweichung von ca. 638mm quer zur letzten Fahrtrichtung, aber ~0mm in Laengs-/Hoehenrichtung, From 9a7907ab008d19e8c9419c62e9e869af61d3d7c7 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 11:38:15 +0200 Subject: [PATCH 32/38] [CHANGE] VF Standard/Etage 3D-Linie-Eingabemodus per Dialog statt Konsole (Teil A der GUI-Umstellung) Neuer Dialog vfc_eingabemodus (dcl/variofoerderer.dcl) + vfc-dialog-eingabemodus-waehlen (Lisp/vf_core.lsp), analog zum bestehenden vfc_typ-Muster: Radio-Buttons "3D-Linie auswaehlen" / "Werte manuell eingeben" ersetzen die fruehere getstring-Konsolenabfrage in vf-dialog-ablauf. Betrifft StandardVarioFoerderer3D und EtageVarioFoerderer3D (beide rufen denselben Ablauf). Die 3D-Linie-Objektauswahl selbst (vfc-3dlinie-erfassen) bleibt bewusst Zeichnung/Konsole - eine Linie laesst sich nicht durch ein Formularfeld ersetzen. Alle daraus abgeleiteten Werte (deltaL/deltaH/hz/Einfuegehoehe) gehen als Prefill in den bereits bestehenden Basis-Dialog (variofoerderer_basis), der sie ueberschreibbar anzeigt - identisch zum "Werte manuell"-Pfad. Rueckfall auf die alte Konsolenabfrage bleibt erhalten (GUI abgeschaltet, DXFM_LANG=en_GB), wie bei vfc_typ. doc/variofoerderer.md (Abschnitt 2, 8, Entscheidungsbaum) und CLAUDE.md entsprechend aktualisiert. Manuell in BricsCAD getestet (StandardVarioFoerderer3D + EtageVarioFoerderer3D, beide Dialogzweige inkl. Abbruch) - laeuft. Co-Authored-By: Claude Sonnet 5 --- CLAUDE.md | 2 +- Lisp/vf_core.lsp | 100 +++++++++++++++++++++++++++++------------ dcl/variofoerderer.dcl | 50 ++++++++++++++++++--- doc/variofoerderer.md | 44 +++++++++--------- 4 files changed, 139 insertions(+), 57 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index f2ea156..46393f6 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -104,7 +104,7 @@ Detaillierte Dokumentation aller Funktionen und Befehle: siehe `Lisp/README.md`. | `ssg_blocktools.lsp` | SSG_BLOCK_COUNT, SSG_BLOCK_DELETE, SSG_ATTR_ERSETZEN | Block-Werkzeuge fuer das aktuelle Layout (Ursprung ACADSST `TOOLS.LSP`/`ssg.lsp`): Einfuegungen zaehlen (Pick, wcmatch-Muster oder Statistik aller Bloecke), alle Einfuegungen loeschen (Rueckfrage, gesperrte Layer bleiben), Attributwerte zeichnungsweit/in Auswahl suchen+ersetzen (Vorschau mit Anzahl, Teilstring oder Gesamtwert). Wirksamer Blockname (dynamische Bloecke). Reine Kerne `ssg-bt-name-passt-p`, `ssg-bt-zaehle-namen`, `ssg-bt-wert-neu` in `tests/test_unit.lsp` getestet | | `ssg_texttools.lsp` | SSG_TEXT_ERSETZEN, SSG_TEXT_PARALLEL, SSG_TEXT_HOEHE, SSG_TEXT_STIL | Text-Werkzeuge (Ursprung ACADSST `CHGTEXT`/`PARTEXT`/`ALTHOEHE`/`ALTSTIL`): Suchen/Ersetzen in TEXT, MTEXT und Block-Attributen (nutzt `ssg-bt-*`, daher NACH `ssg_blocktools` laden), Text parallel zu Linie/Polylinie/Bogen (lesbar ausgerichtet, Abstand), Hoehe/Stil aendern. Arbeitet in der XY-Ebene des Welt-KS. Reine Kerne `ssg-tt-lesbarer-winkel`, `ssg-tt-versetzt` getestet | | `KreiselInsert.lsp` | KreiselInsert, KreiselConnect, KreiselRedraw, KreiselQuick, KreiselEdit, KreiselParams, KreiselLabelSetup, KreiselLabelPos, KreiselLabelHoehe, ILS_Eckrad | ILS Kreisel und Eckrad komplett in AutoLISP | -| `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) bleibt bewusst reine Konsole (im Code selbst als Legacy/"wird umgebaut" markiert). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/todo/plan-vf-interactive.md`. Details/Entscheidungsbaum: `doc/variofoerderer.md` | +| `VarioFoerderer.lsp` (Wrapper fuer `vf_core.lsp`/`vf_standard.lsp`/`vf_etage.lsp`/`vf_linienzug.lsp`) | FOERDERANLAGE, VARIOFOERDERER_EDIT, VARIOFOERDERER_NACHRUESTEN, Vario_Kette_Merge, VF_SEKTION_RESTORE, VF_WIZARD_AN, VF_WIZARD_AUS | Vario-Foerderanlagen Generator (Typen Standard/Etage/Linienzug); Standard- UND Etage-Typ: Werteingabe per DCL-Dialog, inkl. der vorgelagerten Eingabemodus-Wahl 3D-Linie/Werte manuell (`vfc_eingabemodus`, `vfc-dialog-eingabemodus-waehlen`) - beide Modi laufen seitdem in denselben Basis-/Winkel-Dialog, der Konsolen-Pfad ist nur noch Rueckfall bei abgeschalteter GUI/anderer Sprache. Der Dialog-Ablauf ist zentral in vf_core (`vf-dialog-ablauf`/`vf-dialog-berechnen-einfuegen`, parametrisiert ueber Typ-Registry `*vf-typ-registry*` + Flag `horizontal-p`); `vfs-standard-dialog-ablauf`/`vfe-etage-dialog-ablauf` sind nur noch duenne Wrapper darauf. Beide nutzen dieselben Dialoge `vfs-dialog-eingabe-basis`/`vfs-dialog-winkel-verteilung` und den gemeinsamen L_GF/L_VF-Solve `vf-winkel-solve` (vf_core; berechne-alle-winkel/berechne-winkel-etage teilen ihn); Doppelklick auf VF_n-Block ruft VARIOFOERDERER_EDIT, das per SSG_VF_EDIT-XDATA-Marker ("standard"/"etage"/"linienzug") in den passenden Neuaufbau-Zweig dispatcht (`vfe-edit-ent` fuer Etage, `vfl-edit-ent` fuer Linienzug); Altbestand-Bloecke ohne Marker werden abgewiesen. Linienzug (Modus 1, `vf-linienzug-modus`) zeichnet jede interaktive Eingabe in einem Journal auf (`vfl-in-point`/`-string`/`-real`/`-int`) und schreibt es als XDATA auf den fertigen `VF_n`-Block; ein Abbruch (ESC) loescht dadurch nichts mehr, sondern wickelt die bis dahin gebaute Teil-Geometrie ebenso zu einem Block (`vfl-modus-abbruch-sichern`) - sie bleibt stehen und ist sofort per Doppelklick weiter editierbar/fortsetzbar. Der komplette Linienzug-Hauptstrang (Menue-Fragen von AS-Element bis Kettenende, inkl. GF-Bogen/Vario-Kurve/VF-Einheit-Fortsetzung) laeuft per Default ueber DCL-Dialoge statt Konsole (`*vfl-wizard-mode*`, Befehle VF_WIZARD_AN/VF_WIZARD_AUS): `vfl-in-string`/`-int`/`-real` zeigen bei aktivem Wizard-Modus generische Dialoge aus `dcl/vf_linienzug_wizard.dcl` (Zahl-Eingabe bzw. Mehrfachauswahl aus `vfl-menu`/`vfl-menu-int`) statt `getstring`/`getint`/`getreal` aufzurufen; die ORIGINALEN Konsolen-Fragen (princ + get*, de/en ueber ssg-text) bleiben unveraendert im Code (Fallback bei Fehlern via `vl-catch-all-apply`, siehe `doc/variofoerderer.md`). `vfl-edit-ent` liest das Journal, zeigt die Sektionen ueber einen DCL-Dialog (`vfl-dlg-position`, `dcl/vfl_edit.dcl`) an, kuerzt bei Bedarf auf eine gewaehlte Sektion (stummer Replay der behaltenen Eingaben, umgeht den Wizard-Zweig komplett) und baut danach interaktiv weiter. Linienzug Modus 2 (Pfad+Zielhoehe-Solver, `vf-linienzug-modus2`) nutzt dieselben Wrapper PLUS die neue Objektauswahl-Wrapper-Funktion `vfl-in-selection` (Pfad-Objekte als stabile Entity-Handles journalisiert, neue Journal-Art `"OBJS"`) und schreibt sein Journal unter dem eigenen XDATA-Marker `"linienzug2"`; Doppelklick baut hier NICHT abschnittsweise, sondern per vollem Reset 1:1 aus dem Journal neu auf (`vfl-edit-ent2`, dispatcht aus `vfl-edit-ent` per Marker) - Modus 3 (Vorwaerts-Nachbau) bleibt bewusst reine Konsole (im Code selbst als Legacy/"wird umgebaut" markiert). `Vario_Kette_Merge` (in vf_linienzug.lsp) fuehrt mehrere einzeln gebaute VF_n-Bloecke ab einem gewaehlten Start-Baustein ueber die reale KS_AUS->KS_EIN-Nachbarschaft zu einem Gesamt-Block zusammen (aggregierte Attribute, Luecken-Erkennung). Die interaktiven Editier-Pfade (`vfl-edit-ent` Sektions-Zweig, `vfl-edit-ent2`) rufen den Neuaufbau BEWUSST direkt auf, NICHT ueber `vl-catch-all-apply`: der alte Block ist beim Neuaufbau schon per `entdel` weg, und ein Catch faengt den Abbruch VOR `*error*` ab - der Abbruch-Wickler `vfl-modus-abbruch-sichern` kaeme nie zum Zug und die ganze Kette bliebe als lose Einzelteile ohne Block liegen (Fehlerbild "VF-Block aufgebrochen"). Nur der nicht-interaktive Batch-Konverter `vfl-konvertiere-ent` behaelt den Catch (die Batch-Schleife muss weiterlaufen) und meldet den betroffenen Block. Die Abbruch-Handler setzen zusaetzlich `*ssg-ils-dim*` zurueck, weil der Aufrufer, der das sonst tut, nach einem Abbruch nicht mehr erreicht wird. Recovery-Pfad fuer bereits aufgebrochene Ketten: `VF_SEKTION_RESTORE` (vf_linienzug.lsp) setzt das Ketten-Journal aus der XDATA der losen Objekte zusammen - `SSG_VF_EDIT_SEG` traegt pro Entity den Journal-Abschnitt DER ITERATION, in der es entstand (indiziert mit dem ersten Glied-Index darin; eine VF-Einheit mit eingebetteten Vario-Kurven erzeugt mehrere Glieder in einer Iteration), `SSG_VF_EDIT_PRE` auf den Entities des ersten Gliedes die Praeambel (Startpunkt/Starthoehe/AS). Die `.dbg`-Dateien sind reine AUSGABE und werden von keinem Befehl gelesen (dbgopen legt sie bei jedem Lauf neu an) - Wiederherstellungs-Daten gehoeren in die XDATA. `vf_konstanten.lsp` (von vf_core.lsp vor den drei Submodulen geladen) sammelt alle Laengen-/Winkel-/Toleranz-Magic-Numbers aus dem VarioFoerderer-Cluster als dokumentierte `*vfk-*`-Konstanten. Die Migration ist abgeschlossen: vf_core/vf_standard/vf_etage/vf_linienzug referenzieren durchgaengig die zentralen Konstanten statt roher Literale (Winkel, Stations-/Separator-Laengen, Mindestlaengen, AS/ES-Fallback-Versaetze, Text-/Label-Masse) - Ausnahmen sind in `vf_konstanten.lsp` selbst dokumentiert (Werte mit fuehrender Config-Anbindung via `ssg-cfg-or`, itoa-/Integer-Kontexte, Blocknamen-Strings, die 2000.0-mm/m-Umrechnung). `*vfk-gf-bogen-winkel*` (30/60/90, GF-Bogen + Vario-Kurve) und `*vfk-as-es-winkel*` ("30"/"90", AS/ES; bewusst STRING, da 2-wertig und im Journal als STR gefuehrt) sind Beispiele; vf_linienzug hat fuer beide einen Fallback, falls vf_konstanten nicht geladen wurde. **Nicht-interaktiver Betrieb**: `*vfl-headless*` (+ `vfl-headless-p`/`-abbruch`/`-notausgang`, Diagnose `*vfl-headless-fehler*`, optionaler Antwort-Hook `*vfl-headless-antwort-fn*`) verbietet jede Live-Eingabe - eine erschoepfte Replay-Queue ist damit ein harter Abbruch MIT Fundstelle (Art der Eingabe, Glied- und Eingabe-Nummer) statt eines stillen Rueckfalls auf `getpoint`/`getreal`; eingebaut in `vfl-in-value`/`-value-p`/`-selection`/`-abstand`. Die Bau-Pfade melden abgewiesene Sektionen ueber `vfl-meldung` (sammelt nach `*vfl-meldungen*` + `dbgmsg`, `alert` nur bei erlaubter GUI, sonst `princ`) statt per blockierendem `alert`; reine Interaktiv-Alerts (fehlendes DCL, "nicht editierbar", "kein Journal") bleiben `alert`. Genutzt von `tests/test_hm_recformat.lsp` (Replay der echten Aufzeichnungen) und von `vf_spec.lsp`; Fahrplan in `doc/todo/plan-vf-interactive.md`. Details/Entscheidungsbaum: `doc/variofoerderer.md` | | `vf_spec.lsp` (von vf_core.lsp NACH vf_linienzug.lsp geladen) | VF_SPEC_BAU | Linienzug-Ketten aus **Eingabedaten** bauen, ohne Dialog und ohne Konsolenfrage (Stufe 1 aus `doc/todo/plan-vf-interactive.md`). Eine **Spec** beschreibt eine Kette in Domaenenwerten (`"links"`, `"winkel"`, `"aussen"`, ja/nein) statt in Menue-Codes; `vsp-journal` uebersetzt sie in ein Eingabe-Journal, `vsp-bau-aus-spec` spielt es per `vfl-journal-replay-start` durch den UNVERAENDERTEN `vf-linienzug-modus` (Replay-Kern `vsp-bau-journal` - nimmt auch ein unveraendert uebernommenes, aufgezeichnetes Journal, z.B. aus `dxf_anlage_export.py`). Damit traegt der fertige Block dasselbe `SSG_VF_EDIT`-Journal wie eine handgebaute Kette und bleibt per Doppelklick editier- und 2D/3D-konvertierbar - kein Journal-Konsument muss etwas von Specs wissen. Wichtige Regeln, die der Uebersetzer kennt: der Menue-Code haengt am Frame (erste Sektion 4 Optionen ohne GF-Bogen, danach 5), `hz` steht nur beim ERSTEN Segment im Journal, und `erst-hor` unterscheidet den horizontalen Erstkoerper einer VF-Einheit (Separator-/Endpunktfragen vorab) vom gewinkelten (keine Frage). Fehlerverhalten: fail fast - `vsp-pruefen` sammelt ALLE Spec-Fehler, gebaut wird dann nichts (nichts wird geraten). Ergebnis-Record je Kette mit `status` (`executed`/`warnung`/`desync`/`abbruch`/`spec-fehler`), Block/Handle/Einfuegepunkt/Attributen, `prompts` (muss 0 sein), `glieder_soll` vs. `glieder_ist` (Desync-Detektor, der auch bei aufgehender Queue greift) und den gesammelten `meldungen`. Headless-Rahmen `vsp-headless-an`/`-aus` (Save/Restore von `*vfl-headless*`, `*vfl-wizard-mode*`, `*ssg-gui-aus*` + zaehlende Eingabe-Stubs). Spec-Datei flach als JSON (`ssg-load-json` liest zeilenweise), erzeugt von `lib/vf_spec_export.py`. Gegenstueck/Referenz in Python: derselbe Emitter, gegen die 5 echten HundM-Ketten rundlaufgeprueft | | `Gefaellestrecke.lsp` | GEFAELLESTRECKE, GEFAELLESTRECKE_EDIT | Gefaelle-Foerderanlage (AUS -> Staustrecke skaliert -> Separator -> EIN); Modus 1 per DCL-Dialog (Einfuegehoehe, Element-Winkel 30/90); Doppelklick auf GF_n-Block ruft GEFAELLESTRECKE_EDIT (Dialog vorbelegt, Neuaufbau) | | `export.lsp` | EXPORTSIVAS, EXPORTCSV, OMNI_UPDATE_ATTRIBS, CSV_EXPORT_KONFIG | JSON-Sammlung und Python-Export (Omniflo-Merkmale/Sum-Zeile via lib/export_csv.py). **Gefrorene Layer**: `csv:collect-export-blocks` laesst Bloecke auf gefrorenen Layern aus (ausgeschaltete Layer zaehlen NICHT), Schalter `*csv-gefrorene-ausschliessen*` (Standard an, Toggle im Dialog CSV_EXPORT_KONFIG). Die Hilfsobjekte eines gefrorenen VF_n/GF_n (Separator-/Element-Kopien, Einheiten-/AS-ES-Marker) liegen auf eigenen Layern und werden darum ueber `*csv-ausschluss-enames*` mit ausgelassen (gesetzt in `csv:export-vorbereiten` per `csv:hilfskopien-ausschluss`); erzeugt und nummeriert werden sie trotzdem, damit IDs stabil bleiben. DrawPlanquadrate nutzt dieselbe Sammlung und folgt dem Filter | diff --git a/Lisp/vf_core.lsp b/Lisp/vf_core.lsp index f09c4af..4b6420e 100644 --- a/Lisp/vf_core.lsp +++ b/Lisp/vf_core.lsp @@ -1088,42 +1088,53 @@ (defun vf-dialog-ablauf (typ vf-nummer horizontal-p / eingabe deltaL deltaH richtung z-start hz seite startpunkt startpunkt-xy dim geruest-einzelmodul geruest-typ motorseite - antwort linie-erg basis-prefill abbruch) + antwort dlg-modus linie-erg basis-prefill abbruch) + (setq abbruch nil) (if *vf-vorauswahl-eingabemodus* (setq antwort *vf-vorauswahl-eingabemodus* *vf-vorauswahl-eingabemodus* nil) (progn - (princ (ssg-text "vfc-eingabemodus-header")) - (princ (ssg-text "vfc-eingabemodus-3dlinie")) - (princ (ssg-text "vfc-eingabemodus-werte")) - (setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default"))) - ) - ) - (setq abbruch nil) - (if (= antwort "1") - (progn - (setq linie-erg (vfc-3dlinie-erfassen)) - (if (null linie-erg) - (setq abbruch t) - (progn - (setq deltaL (nth 0 linie-erg) - deltaH (nth 1 linie-erg) - richtung (nth 2 linie-erg) - startpunkt (nth 3 linie-erg) - hz (nth 4 linie-erg)) - (setq basis-prefill - (list (cons "deltaL" deltaL) (cons "deltaH" deltaH) (cons "richtung" richtung) - (cons "einfuegehoehe" (caddr startpunkt)) (cons "hz" hz))) + (setq dlg-modus (vfc-dialog-eingabemodus-waehlen)) + (cond + ((eq dlg-modus 'ABBRUCH) (setq antwort "2" abbruch t)) + (dlg-modus (setq antwort dlg-modus)) + (t + ;; Dialog nicht verfuegbar/nicht erlaubt (GUI aus, andere Sprache) + ;; - alte Konsolen-Abfrage unveraendert. + (princ (ssg-text "vfc-eingabemodus-header")) + (princ (ssg-text "vfc-eingabemodus-3dlinie")) + (princ (ssg-text "vfc-eingabemodus-werte")) + (setq antwort (getstring (ssg-text "vfc-prompt-wahl-1-2-ohne-default"))) ) ) ) - (progn - (setq startpunkt-xy (vfc-dialog-startpunkt-waehlen "vfc-prompt-startpunkt-aus")) - (if (null startpunkt-xy) - (setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus")))) - (if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0))) - (setq startpunkt startpunkt-xy) - (setq basis-prefill nil) + ) + (if (not abbruch) + (if (= antwort "1") + (progn + (setq linie-erg (vfc-3dlinie-erfassen)) + (if (null linie-erg) + (setq abbruch t) + (progn + (setq deltaL (nth 0 linie-erg) + deltaH (nth 1 linie-erg) + richtung (nth 2 linie-erg) + startpunkt (nth 3 linie-erg) + hz (nth 4 linie-erg)) + (setq basis-prefill + (list (cons "deltaL" deltaL) (cons "deltaH" deltaH) (cons "richtung" richtung) + (cons "einfuegehoehe" (caddr startpunkt)) (cons "hz" hz))) + ) + ) + ) + (progn + (setq startpunkt-xy (vfc-dialog-startpunkt-waehlen "vfc-prompt-startpunkt-aus")) + (if (null startpunkt-xy) + (setq startpunkt-xy (getpoint (ssg-text "vfc-prompt-startpunkt-aus")))) + (if (null startpunkt-xy) (setq startpunkt-xy '(0 0 0))) + (setq startpunkt startpunkt-xy) + (setq basis-prefill nil) + ) ) ) (if abbruch @@ -1233,6 +1244,37 @@ ) ) +;; Eingabemodus (3D-Linie / Werte manuell) per Dialog waehlen - ersetzt die +;; fruehere getstring-Konsolenabfrage in vf-dialog-ablauf. Gleiches Muster/ +;; gleiche Einschraenkung wie vfc-dialog-typ-waehlen: nur bei aktiver GUI und +;; Deutsch, sonst nil (Aufrufer faellt dann auf die alte Konsolen-Abfrage +;; zurueck). Keine "Zurueck"-Taste noetig (direkt nach der Typ-Wahl, die +;; selbst schon ein "Zurueck" hat). Rueckgabe: "1" (3D-Linie), "2" (Werte) +;; oder 'ABBRUCH. +(defun vfc-dialog-eingabemodus-waehlen ( / dcl-pfad dat gmodus ergebnis) + (if (and (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p)) + (= *ssg-lang* "de_DE")) + (progn + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "vfc_eingabemodus" dat)) + (progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil) + (progn + (set_tile "modus_3dlinie" "1") + (action_tile "accept" + "(setq gmodus (if (= (get_tile \"modus_werte\") \"1\") \"2\" \"1\")) + (done_dialog 1)") + (action_tile "cancel" "(done_dialog 0)") + (setq ergebnis (start_dialog)) + (unload_dialog dat) + (if (= ergebnis 1) gmodus 'ABBRUCH) + ) + ) + ) + nil + ) +) + ;; ============================================================ ;; TEIL 12: DISPATCHER c:VarioFoerderer ;; ============================================================ diff --git a/dcl/variofoerderer.dcl b/dcl/variofoerderer.dcl index 3e8dc24..084aefe 100644 --- a/dcl/variofoerderer.dcl +++ b/dcl/variofoerderer.dcl @@ -20,12 +20,20 @@ // mal scheitert. variofoerderer_winkel (Winkel/Verteilung) hat KEINE // generierte Variante mehr und wird direkt verwendet (komplett // Combobox, siehe vfs-dialog-winkel-verteilung in vf_standard.lsp). -// Die 3D-Linie-Eingabe (Modus "3D-Linie"), der Etage-Typ und die -// Linienzug-Kette selbst bleiben interaktiv (Kommandozeile bzw. eigener -// Wizard in vf_linienzug_wizard.dcl). Der Linienzug-Modus (1/2/3/4/5) wird -// seit den Menue-Wrappern c:LinienzugVarioFoerderer*/c:QcLinieMitGf* nicht -// mehr per Dialog erfragt, sondern ist je Menuepunkt fest vorbelegt - der -// frueher hier gefuehrte Dialog vfc_linienzug_modus ist dadurch entfallen. +// vfc_eingabemodus: Eingabemodus (3D-Linie / Werte manuell) waehlen - +// ersetzt die Konsolen-Abfrage am Anfang von vf-dialog-ablauf fuer +// Standard UND Etage (vfc-dialog-eingabemodus-waehlen, vf_core.lsp). +// Die 3D-Linie SELBST (Objektauswahl) bleibt danach Zeichnung/Konsole +// (get-line-start-end-points) - eine Linie laesst sich nicht durch ein +// Formularfeld ersetzen; alle abgeleiteten Werte (deltaL/deltaH/hz/ +// Einfuegehoehe) landen danach als Prefill im bestehenden Basis-Dialog +// (variofoerderer_basis), der sie ganz normal ueberschreibbar anzeigt. +// Der Etage-Typ und die Linienzug-Kette selbst bleiben interaktiv +// (Kommandozeile bzw. eigener Wizard in vf_linienzug_wizard.dcl). Der +// Linienzug-Modus (1/2/3/4/5) wird seit den Menue-Wrappern +// c:LinienzugVarioFoerderer*/c:QcLinieMitGf* nicht mehr per Dialog erfragt, +// sondern ist je Menuepunkt fest vorbelegt - der frueher hier gefuehrte +// Dialog vfc_linienzug_modus ist dadurch entfallen. // ============================================================ // Anlagen-Typ waehlen (Standard/Etage/Linienzug). Radio-Buttons statt @@ -72,6 +80,36 @@ vfc_typ : dialog { } } +// Eingabemodus waehlen (3D-Linie / Werte manuell) - Radio-Buttons, gleiches +// Muster und dieselbe Sprach-/GUI-Einschraenkung wie vfc_typ oben (Labels +// hart deutsch, Rueckfall auf Konsolen-Liste bei DXFM_LANG=en_GB oder +// abgeschalteter GUI - siehe vfc-dialog-eingabemodus-waehlen, vf_core.lsp). +vfc_eingabemodus : dialog { + label = "VarioFoerderer - Eingabemodus"; + + : boxed_radio_column { + label = "Eingabemodus waehlen:"; + key = "modus"; + + : radio_button { + key = "modus_3dlinie"; + label = "3D-Linie auswaehlen (Start- und Endpunkt mit Hoehe)"; + value = "1"; + } + : radio_button { + key = "modus_werte"; + label = "Werte manuell eingeben"; + } + } + + : row { + alignment = centered; + : button { key = "accept"; label = "Ok Weiter"; is_default = true; fixed_width = true; width = 12; } + spacer; + : button { key = "cancel"; label = "Abbrechen"; is_cancel = true; fixed_width = true; width = 12; } + } +} + // Startpunkt der Anlage waehlen - Punktwahl-Button + Anzeige, analog // vflw_punkt_zahl (dcl/vf_linienzug_wizard.dcl): der Button schliesst den // Dialog (done_dialog 2), DANACH laeuft getpoint auf der Kommandozeile diff --git a/doc/variofoerderer.md b/doc/variofoerderer.md index 0b0c20a..9cf8146 100644 --- a/doc/variofoerderer.md +++ b/doc/variofoerderer.md @@ -185,12 +185,18 @@ Winkelberechnung befuellt, da seine Optionsliste von Dialog 1 abhaengt. | Verteilung Staustrecken | `verteilung` | Dropdown | Gleichmaessig (L_GF1=L_GF2) / Vorne Minimum, hinten Rest / Hinten Minimum, vorne Rest / Eigene Werte | Gleichmaessig | | L_GF1 vorne (manuell) | `lgf1_manuell` | Zahl (mm) | nur aktiv bei Verteilung "Eigene Werte" | L_GF / 2 | -Vorgelagert (Konsole, vor Dialog 1): Eingabemodus-Frage "3D-Linie" vs. "Werte -manuell" — nur bei Wahl "2" oeffnen sich obige Dialoge, sonst laeuft der -komplette [Legacy-Konsolen-Pfad](#8-legacy-konsolen-pfad). Direkt vor Dialog 1 -wird zusaetzlich der Startpunkt (X/Y) per Punktwahl gewaehlt -(`vfs-standard-dialog-ablauf`, `Lisp/vf_standard.lsp:1069`); die Z-Hoehe kommt -aus dem Feld "Einfuegehoehe". +Vorgelagert: Eingabemodus-Frage "3D-Linie" vs. "Werte manuell" per DCL-Dialog +(`vfc_eingabemodus`, `vfc-dialog-eingabemodus-waehlen` in `Lisp/vf_core.lsp`; +Radio-Buttons wie `vfc_typ`, Rueckfall auf die alte Konsolenfrage bei +abgeschalteter GUI oder `DXFM_LANG=en_GB`). **Beide** Antworten fuehren zu +Dialog 1/2 oben: bei "3D-Linie" wird zuerst die Linie gewaehlt +(`vfc-3dlinie-erfassen`, Objektauswahl bleibt Zeichnung/Konsole — eine Linie +laesst sich nicht durch ein Formularfeld ersetzen) und deltaL/deltaH/hz/ +Einfuegehoehe gehen als Prefill in Dialog 1; bei "Werte manuell" wird nur der +Startpunkt per Punktwahl-Dialog (`vfc-dialog-startpunkt-waehlen`) gewaehlt und +Dialog 1 startet ohne Geometrie-Prefill. Der +[Legacy-Konsolen-Pfad](#8-legacy-konsolen-pfad) existiert nur noch als +Rueckfall, wenn keiner der beiden Dialoge gezeigt werden kann/darf. --- @@ -419,9 +425,11 @@ Wiederherstellungs-Daten gehoeren ausschliesslich in die XDATA der Zeichnung. ## 8. Legacy-Konsolen-Pfad -Wird bei Standard/Etage durchlaufen, wenn auf die Eingabemodus-Frage *nicht* -"2" getippt wird (Enter/leer faellt ebenfalls hierher zurueck) — also aktuell -noch der Vorgabe-Pfad. Zwei Untermodi: +Reiner Rueckfall fuer Standard/Etage: greift nur noch, wenn der Dialog +`vfc_eingabemodus` nicht gezeigt werden kann/darf (GUI abgeschaltet, +`DXFM_LANG=en_GB`) — im Normalfall (GUI an, Deutsch) laufen beide +Eingabemodi inzwischen ueber den Dialog (Abschnitt 2, "Vorgelagert"). Zwei +Untermodi: **3D-Linie auswaehlen** @@ -585,19 +593,13 @@ eine bereits genannte, kleinere Nummer (z.B. 34 -> 35 -> 34) sind Schleifen |---|---|---|---| | 1 | Befehl waehlen | FOERDERANLAGE / GEFAELLESTRECKE | 2, 40 | | 2 | Anlagen-Typ | Standard / Etage / Linienzug | 3, 3, 30 | -| 3 | Eingabemodus (nur Standard/Etage) | Konsole / Dialog | 4, 10 | -| 4 | Startpunkt waehlen | Punktwahl | 5 | +| 3 | Eingabemodus (nur Standard/Etage) | Dialog `vfc_eingabemodus`: 3D-Linie / Werte manuell | 11, 4 | +| 4 | Startpunkt waehlen | Punktwahl-Dialog | 5 | | 5 | Dialog "Basis" | DeltaL, DeltaH, Auf/Ab, Einfuegehoehe, Fahrtrichtung, Seite, Motorseite, 2D/3D, Geruest | 6 | | 6 | Winkelberechnung (automatisch) | - | 7 | | 7 | Dialog "Winkel/Verteilung" | Winkel, Verteilung, ggf. L_GF1 | 8 | | 8 | Bau (automatisch) | - | ENDE | -| 10 | Eingabemodus Konsole | 3D-Linie / Werte | 11, 12 | -| 11 | 3D-Linie waehlen | Objektwahl -> DeltaL/DeltaH/Fahrtrichtung automatisch | 13 | -| 12 | Werte eingeben | DeltaL, DeltaH, Auf/Ab, Startpunkt, Fahrtrichtung | 13 | -| 13 | Seite waehlen | rechts/links | 14 | -| 14 | Winkel waehlen | automatisch bei 1 Treffer, sonst Liste | 16 | -| 16 | Staustrecken-Verteilung | 4 Optionen, ggf. L_GF1 manuell | 17 | -| 17 | Bestaetigung "Einfuegen?" | Ja/Nein | 8 | +| 11 | 3D-Linie waehlen | Objektwahl (Zeichnung) -> DeltaL/DeltaH/Fahrtrichtung automatisch, Prefill fuer Dialog 5 | 5 | | 30 | Linienzug-Modus | Manuell / Pfad+Zielhoehe / Vorwaerts-Nachbau | 31, 50, 55 | | 31 | Startpunkt + Starthoehe | Punktwahl + Zahl | 32 | | 32 | AS-Element setzen? | Ja/Nein | 33, 34 | @@ -645,9 +647,9 @@ eine bereits genannte, kleinere Nummer (z.B. 34 -> 35 -> 34) sind Schleifen ### Beispiel-Abfolgen -- Standard, Dialog-Pfad: `1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8` -- Standard, Legacy-Konsole mit 3D-Linie: `1 -> 2 -> 3 -> 10 -> 11 -> 13 -> 14 -> 16 -> 17 -> 8` -- Etage, Dialog-Pfad: `1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8` +- Standard, Werte manuell: `1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8` +- Standard, aus 3D-Linie: `1 -> 2 -> 3 -> 11 -> 5 -> 6 -> 7 -> 8` +- Etage, Werte manuell: `1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8` - Linienzug — AS-Element, GF, Auf/Ab-VF mit Zwischenkurve, Kettenende: `1 -> 2 -> 30 -> 31 -> 32 -> 33 -> 34 -> 36 -> 41 -> 34 -> 37 -> 42 -> 46 -> 42 -> 45` - Linienzug — horizontaler Anfang direkt bis Kettenende: From 57bb1e90570ec24ce39b56048ed7836ed8c04382 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 11:59:18 +0200 Subject: [PATCH 33/38] [CHANGE] VARIOFOERDERER_NACHRUESTEN: Baurichtung per Dialog statt Konsole (Teil C der GUI-Umstellung) Neuer Dialog vfs_nachruesten_hz (dcl/variofoerderer.dcl) + vfs-dialog-nachruesten-hz (Lisp/vf_standard.lsp) ersetzt den fruehren getreal-Prompt. Zeigt pro unmarkiertem VF_n-Fund Blockname/erkannten Typ und ein hz-Feld, vorbelegt mit dem zuletzt eingegebenen Wert (identisches Default-Fortpflanzungs-Verhalten wie vorher). "Abbrechen" im Dialog uebernimmt bewusst nur den Vorgabewert fuer DIESEN Fund (Rueckgabe 'ABBRUCH), statt die ganze Nachruesten-Schleife abzubrechen oder auf die Konsole zurueckzufallen - echter Konsolen-Rueckfall bleibt ausschliesslich fuer den Fall, dass der Dialog gar nicht gezeigt werden kann (GUI abgeschaltet). Die Objektauswahl (ssget) selbst bleibt unveraendert Zeichnung/Konsole. doc/variofoerderer.md um den Befehl ergaenzt (war dort bisher gar nicht erwaehnt). Manuell in BricsCAD getestet (unmarkierter VF_4-Block, Dialog erscheint, hz=0 markiert) - laeuft. Co-Authored-By: Claude Sonnet 5 --- Lisp/vf_standard.lsp | 42 ++++++++++++++++++++++++++++++++++++++++-- dcl/variofoerderer.dcl | 32 ++++++++++++++++++++++++++++++++ doc/variofoerderer.md | 12 ++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/Lisp/vf_standard.lsp b/Lisp/vf_standard.lsp index b5e10f0..658bf1f 100644 --- a/Lisp/vf_standard.lsp +++ b/Lisp/vf_standard.lsp @@ -1553,6 +1553,38 @@ ;; Neuanlage 0). Wer hz nicht kennt: der Wert steht in der urspruenglichen ;; Bau-Eingabe (z.B. mubea.json "hz") bzw. ergibt sich aus der Ausrichtung. ;; Bereits markierte Bloecke und Nicht-VF-Bloecke werden uebersprungen. + +;; Baurichtung (hz) fuer EINEN Fund per Dialog abfragen - ersetzt den +;; frueheren getreal-Prompt in c:VARIOFOERDERER_NACHRUESTEN. "kopf" per +;; set_tile aus ssg-text befuellt (Blockname + erkannter Typ), deshalb +;; sprachunabhaengig. Rueckgabe: hz (Real) bei OK, 'ABBRUCH wenn der Nutzer +;; bewusst abbricht (Aufrufer uebernimmt dann default-hz, OHNE nochmal auf +;; der Konsole zu fragen), nil wenn der Dialog gar nicht gezeigt werden +;; konnte/durfte (GUI aus) - NUR dann faellt der Aufrufer auf den alten +;; getreal-Prompt zurueck. +(defun vfs-dialog-nachruesten-hz (bname typ default-hz / dcl-pfad dat ergebnis hz) + (if (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p)) + (progn + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/variofoerderer.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "vfs_nachruesten_hz" dat)) + (progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil) + (progn + (set_tile "kopf" (ssg-textf "vfs-nachruesten-erkannt" (list bname typ))) + (set_tile "hz" (rtos default-hz 2 1)) + (action_tile "accept" + "(setq hz (distof (get_tile \"hz\") 2)) (done_dialog 1)") + (action_tile "cancel" "(done_dialog 0)") + (setq ergebnis (start_dialog)) + (unload_dialog dat) + (cond ((and (= ergebnis 1) hz) hz) (t 'ABBRUCH)) + ) + ) + ) + nil + ) +) + (defun c:VARIOFOERDERER_NACHRUESTEN ( / ss i ent ed bname attribs xd typ hz n-neu n-skip default-hz) (ssg-start "VARIOFOERDERER_NACHRUESTEN" nil) @@ -1580,8 +1612,14 @@ (if (or (assoc "GF_Bogen_R_60" attribs) (assoc "GF_Bogen_L_60" attribs)) "etage" "standard")) (princ (ssg-textf "vfs-nachruesten-erkannt" (list bname typ))) - (setq hz (getreal (ssg-textf "vfs-nachruesten-prompt-hz" (list (rtos default-hz 2 1))))) - (if (null hz) (setq hz default-hz)) + (setq hz (vfs-dialog-nachruesten-hz bname typ default-hz)) + (cond + ((eq hz 'ABBRUCH) (setq hz default-hz)) + ((null hz) + (setq hz (getreal (ssg-textf "vfs-nachruesten-prompt-hz" (list (rtos default-hz 2 1))))) + (if (null hz) (setq hz default-hz)) + ) + ) (setq default-hz hz) (vf-edit-xdata-schreiben ent typ hz) (princ (ssg-textf "vfs-nachruesten-markiert" (list (rtos hz 2 1)))) diff --git a/dcl/variofoerderer.dcl b/dcl/variofoerderer.dcl index 084aefe..6af94de 100644 --- a/dcl/variofoerderer.dcl +++ b/dcl/variofoerderer.dcl @@ -34,6 +34,16 @@ // c:LinienzugVarioFoerderer*/c:QcLinieMitGf* nicht mehr per Dialog erfragt, // sondern ist je Menuepunkt fest vorbelegt - der frueher hier gefuehrte // Dialog vfc_linienzug_modus ist dadurch entfallen. +// +// Dialog fuer c:VARIOFOERDERER_NACHRUESTEN (vf_standard.lsp): +// vfs_nachruesten_hz: Baurichtung (hz) je unmarkiertem VF_n-Fund abfragen +// - ersetzt den fruehren getreal-Prompt. Die Objektauswahl selbst +// (ssget) bleibt Zeichnung/Konsole; je Fund OHNE SSG_VF_EDIT-Marker +// zeigt der Befehl diesen Dialog einmal, mit dem zuletzt eingegebenen +// Wert als Vorgabe (vfs-dialog-nachruesten-hz in vf_standard.lsp). +// "Abbrechen" uebernimmt fuer diesen Fund den Vorgabewert, OHNE auf die +// alte Konsolenfrage zurueckzufallen (die bleibt reiner Rueckfall fuer +// den Fall, dass der Dialog gar nicht gezeigt werden kann/darf). // ============================================================ // Anlagen-Typ waehlen (Standard/Etage/Linienzug). Radio-Buttons statt @@ -261,3 +271,25 @@ variofoerderer_winkel : dialog { ok_cancel; } + +// Baurichtung (hz) je unmarkiertem VF_n-Fund abfragen (VARIOFOERDERER_ +// NACHRUESTEN). "kopf" per set_tile aus ssg-text befuellt (Blockname + +// erkannter Typ), deshalb sprachunabhaengig nutzbar - Button-Chrome bleibt +// hart deutsch wie der Rest dieser Datei. "Abbrechen" bricht nur den +// aktuellen Fund ab: der vorbelegte default-hz wird fuer DIESEN Fund +// uebernommen (Aufrufer sieht 'ABBRUCH, kein Rueckfall auf die Konsole) - +// die ganze Nachruesten-Schleife laeuft weiter, kein Gesamtabbruch. +vfs_nachruesten_hz : dialog { + label = "VarioFoerderer nachruesten - Baurichtung"; + + : column { + : text { key = "kopf"; label = ""; width = 50; } + : edit_box { + key = "hz"; + label = "Baurichtung hz (Grad):"; + edit_width = 10; + } + } + + ok_cancel; +} diff --git a/doc/variofoerderer.md b/doc/variofoerderer.md index 9cf8146..3d8a9aa 100644 --- a/doc/variofoerderer.md +++ b/doc/variofoerderer.md @@ -383,6 +383,18 @@ interaktive Linienzug-Ablauf weiter (Abschnitt 5). Einzige Eingabe — Rest laeuft automatisch (Attribute aggregiert, Luecken werden gemeldet). +**VARIOFOERDERER_NACHRUESTEN / VF_NACHRUESTEN** + +| Feld | Steuerelement | Werte | +|---|---|---| +| VF_n-Bloecke | Objektauswahl (`ssget`) | Altbestand ohne `SSG_VF_EDIT`-Marker | +| Baurichtung hz je Fund | Dialog `vfs_nachruesten_hz` (Zahl, Grad) | Vorgabe = zuletzt eingegebener Wert; Rueckfall auf Konsole nur, wenn der Dialog nicht gezeigt werden kann/darf | + +Typ (Standard/Etage) wird automatisch aus den Attributen erkannt +(`GF_Bogen_R/L_60` -> Etage). Nur die Baurichtung ist nicht rekonstruierbar +und wird je unmarkiertem Fund abgefragt; "Abbrechen" im Dialog uebernimmt +fuer diesen Fund den Vorgabewert, ohne die ganze Schleife abzubrechen. + **VF_SEKTION_RESTORE — lose Kette aus der Zeichnung wiederherstellen** | Feld | Steuerelement | Werte | From a9cdc127d98cac76c6cef30195edb88d747c38df Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 12:22:53 +0200 Subject: [PATCH 34/38] [CHANGE] GEFAELLESTRECKE_LINIENZUG: AS/ES-Auswahl und Gefaellewinkel per Dialog statt Konsole (Teil B der GUI-Umstellung) Zwei neue Dialoge (dcl/gefaellestrecke.dcl, Lisp/Gefaellestrecke.lsp): - gf-dialog-linienzug-aus-ein: AUS-/EIN-Element Winkel+Seite in EINEM Dialog, ersetzt die vier fruehen Konsolenfragen. Muss vor der Segmentlaengen-/Winkelberechnung laufen (haengt von AS-/ES-Masse ab), darum eigener, fruehzeitiger Dialog. - gf-dialog-linienzug-winkel: zeigt den automatisch aus der Segmentkette berechneten Gefaellewinkel-Vorschlag ueberschreibbar, mit kurzer Segment-Zusammenfassung und dem bereits gewaehlten AS/ES-Paar nur noch zur Kontrolle (disabled). Ersetzt zugleich die SPAETERE finale Einfuegen-Bestaetigung - nach der rein automatischen AS/ES-Korrekturschleife waere eine zweite Rueckfrage redundant. Objektauswahl (ssget LINE/ARC) und Start-/Endpunktwahl bleiben bewusst Zeichnung/Konsole. Rueckfall auf die alten Konsolenfragen bleibt erhalten, wenn ein Dialog nicht gezeigt werden kann/darf (GUI aus); ein bewusster Dialog-Abbruch bricht dagegen den ganzen Befehl ab statt auf Konsole zurueckzufallen - neu im Vergleich zum alten Verhalten, aber konsistent mit vfc_eingabemodus/vfs_nachruesten_hz aus Teil A/C. doc/variofoerderer.md (Abschnitt 4) aktualisiert und um einen bebilderten Beispiel-Walkthrough ergaenzt (gf-linienzug1-3.png: Ausgangslinie, Dialog mit Vorschlagswinkel, fertige Strecke neben der Original-Linie). Manuell in BricsCAD getestet (vollstaendiger Lauf inkl. Abbruch in beiden Dialogen) - laeuft. Co-Authored-By: Claude Sonnet 5 --- Lisp/Gefaellestrecke.lsp | 231 ++++++++++++++++++++++++++++++----- dcl/gefaellestrecke.dcl | 69 +++++++++++ doc/images/gf-linienzug1.png | Bin 0 -> 7617 bytes doc/images/gf-linienzug2.png | Bin 0 -> 22766 bytes doc/images/gf-linienzug3.png | Bin 0 -> 46188 bytes doc/variofoerderer.md | 42 ++++++- lang/de_DE.json | 1 + lang/en_GB.json | 1 + 8 files changed, 306 insertions(+), 38 deletions(-) create mode 100644 doc/images/gf-linienzug1.png create mode 100644 doc/images/gf-linienzug2.png create mode 100644 doc/images/gf-linienzug3.png diff --git a/Lisp/Gefaellestrecke.lsp b/Lisp/Gefaellestrecke.lsp index 162b30b..b0fe4e3 100644 --- a/Lisp/Gefaellestrecke.lsp +++ b/Lisp/Gefaellestrecke.lsp @@ -714,12 +714,150 @@ prev-hz ) +;; Dialog fuer Modus 3 (Linienzug), Teil 1: AUS-/EIN-Element Winkel+Seite - +;; ersetzt die vier Konsolenfragen (AUS-Winkel, AUS-Seite, EIN-Winkel, +;; EIN-Seite). Muss VOR der Segmentlaengen-Anpassung/Winkelberechnung +;; laufen (die braucht aus-dx/ein-dx aus vf-set-as-masse/-es-masse), darum +;; eigener, frueherer Dialog statt zusammen mit dem Winkel-Vorschlag. +;; Rueckgabe: (as-winkel as-seite es-winkel es-seite) bei OK, 'ABBRUCH wenn +;; der Nutzer bewusst abbricht (Aufrufer bricht dann den GANZEN Befehl ab, +;; KEIN Rueckfall auf die Konsole), nil wenn der Dialog gar nicht gezeigt +;; werden konnte/durfte (GUI aus) - NUR dann Konsolen-Rueckfall. +(defun gf-dialog-linienzug-aus-ein ( / dcl-pfad dat ergebnis + dlg-aus-winkel dlg-aus dlg-ein-winkel dlg-ein + as-seite es-seite as-winkel es-winkel) + (if (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p)) + (progn + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/gefaellestrecke.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "gefaellestrecke_linienzug" dat)) + (progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil) + (progn + (set_tile "zusammenfassung" (ssg-text "gf-dlg-linienzug-vorlauf")) + (mode_tile "winkel" 1) + + (start_list "aus_winkel") + (add_list "90") + (add_list "30") + (end_list) + (set_tile "aus_winkel" "0") + (start_list "aus_seite") + (add_list (ssg-text "gf-dlg-links")) + (add_list (ssg-text "gf-dlg-rechts")) + (end_list) + (set_tile "aus_seite" "0") + + (start_list "ein_winkel") + (add_list "90") + (add_list "30") + (end_list) + (set_tile "ein_winkel" "0") + (start_list "ein_seite") + (add_list (ssg-text "gf-dlg-links")) + (add_list (ssg-text "gf-dlg-rechts")) + (end_list) + (set_tile "ein_seite" "0") + + (action_tile "accept" + (strcat + "(setq dlg-aus-winkel (get_tile \"aus_winkel\"))" + "(setq dlg-aus (get_tile \"aus_seite\"))" + "(setq dlg-ein-winkel (get_tile \"ein_winkel\"))" + "(setq dlg-ein (get_tile \"ein_seite\"))" + "(done_dialog 1)" + ) + ) + (action_tile "cancel" "(done_dialog 0)") + (setq ergebnis (start_dialog)) + (unload_dialog dat) + + (cond + ((= ergebnis 1) + (setq as-winkel (if (= dlg-aus-winkel "1") "30" "90")) + (setq as-seite (if (= dlg-aus "1") "rechts" "links")) + (setq es-winkel (if (= dlg-ein-winkel "1") "30" "90")) + (setq es-seite (if (= dlg-ein "1") "rechts" "links")) + (list as-winkel as-seite es-winkel es-seite) + ) + (t 'ABBRUCH) + ) + ) + ) + ) + nil + ) +) + +;; Dialog fuer Modus 3, Teil 2: Gefaellewinkel-Bestaetigung VOR der +;; iterativen AS/ES-Korrekturschleife (die braucht den vom Nutzer +;; gewaehlten/bestaetigten Ausgangswinkel, berechnet selbst aber nicht +;; interaktiv weiter) - ersetzt die "Berechneten Winkel verwenden?"-Frage +;; samt optionalem manuellem Winkel. Ersetzt zugleich die SPAETERE finale +;; Einfuegen-Bestaetigung: nach diesem OK baut der Aufrufer direkt, ohne +;; weitere Rueckfrage (analog "dialog-bestaetigt" bei Modus 1/2) - die +;; Zusammenfassung mit dem Vorschlag genuegt als Entscheidungsgrundlage, +;; eine zweite Bestaetigung NACH der (rein automatischen) Korrekturschleife +;; waere redundant. Das AS/ES-Auswahlpaar wird hier nur noch ANGEZEIGT +;; (disabled), nicht erneut editierbar - es ist schon in die Segmentlaengen +;; eingerechnet. +;; zusammenfassung-zeilen: Liste bereits fertig formatierter Strings. +;; Rueckgabe: Gefaellewinkel (Grad) bei OK, 'ABBRUCH wenn der Nutzer bewusst +;; abbricht (Aufrufer bricht dann den GANZEN Befehl ab, KEIN Rueckfall auf +;; die Konsole), nil wenn der Dialog gar nicht gezeigt werden konnte/durfte +;; (GUI aus) - NUR dann Konsolen-Rueckfall (inkl. der spaeteren finalen +;; Einfuegen-Bestaetigung, die in diesem Fall unveraendert bleibt). +(defun gf-dialog-linienzug-winkel (zusammenfassung-zeilen winkel-vorschlag + as-winkel as-seite es-winkel es-seite / + dcl-pfad dat ergebnis dlg-winkel grade) + (if (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p)) + (progn + (setq dcl-pfad (strcat (getenv "DXFM_DCL") "/gefaellestrecke.dcl")) + (setq dat (load_dialog dcl-pfad)) + (if (not (new_dialog "gefaellestrecke_linienzug" dat)) + (progn (if (and dat (>= dat 0)) (unload_dialog dat)) nil) + (progn + (set_tile "zusammenfassung" (ssg-join zusammenfassung-zeilen " | ")) + + (start_list "aus_winkel") (add_list as-winkel) (end_list) + (set_tile "aus_winkel" "0") + (start_list "aus_seite") (add_list as-seite) (end_list) + (set_tile "aus_seite" "0") + (start_list "ein_winkel") (add_list es-winkel) (end_list) + (set_tile "ein_winkel" "0") + (start_list "ein_seite") (add_list es-seite) (end_list) + (set_tile "ein_seite" "0") + (mode_tile "aus_winkel" 1) (mode_tile "aus_seite" 1) + (mode_tile "ein_winkel" 1) (mode_tile "ein_seite" 1) + + (set_tile "winkel" (rtos winkel-vorschlag 2 3)) + + (action_tile "accept" + "(setq dlg-winkel (get_tile \"winkel\")) (done_dialog 1)") + (action_tile "cancel" "(done_dialog 0)") + (setq ergebnis (start_dialog)) + (unload_dialog dat) + + (cond + ((= ergebnis 1) + (setq grade (atof dlg-winkel)) + (if (<= grade 0) (setq grade winkel-vorschlag)) + grade + ) + (t 'ABBRUCH) + ) + ) + ) + ) + nil + ) +) + ;; Hauptfunktion Modus 3 (defun gf-linienzug-modus ( / ss n i j obj obj-liste kette segmente seg startpunkt endpunkt-ref deltaH grade antwort idx as-seite es-seite as-block es-block - gf-as-winkel gf-es-winkel + gf-as-winkel gf-es-winkel dlg-aus-ein dlg-winkel-erg entry-hz exit-hz first-idx last-idx neu-l aktuell-frame nach-aus-pt @@ -787,29 +925,41 @@ (setq entry-hz (cadr (car segmente))) (setq exit-hz (gf-exit-hz segmente)) - ;; AUS-Element: 30/90 (vor Seite), dann Seite (vor Winkelberechnung, da die - ;; Laengenanpassung von der AS/ES-Masse abhaengt). Masse fuer Variante setzen. - (princ (ssg-text "vf-winkel-aus-header")) - (princ (ssg-text "vf-winkel-90")) - (princ (ssg-text "vf-winkel-30")) - (setq gf-as-winkel (vf-frage-element-winkel "vf-winkel-aus-header")) - (princ (ssg-text "gf-seite-aus-header")) - (princ (ssg-text "gf-seite-links")) - (princ (ssg-text "gf-seite-rechts")) - (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) - (setq as-seite (if (= antwort "2") "rechts" "links")) - (vf-set-as-masse gf-as-winkel as-seite) + ;; AUS-/EIN-Element: 30/90 + Seite, in EINEM Dialog (vor Winkelberechnung, + ;; da die Laengenanpassung von der AS/ES-Masse abhaengt). Rueckfall auf die + ;; alten Konsolenfragen, wenn der Dialog nicht gezeigt werden kann/darf. + (setq dlg-aus-ein (gf-dialog-linienzug-aus-ein)) + (if (eq dlg-aus-ein 'ABBRUCH) + (progn (princ (ssg-text "vfc-vorgang-abgebrochen")) (exit)) + ) + (if dlg-aus-ein + (setq gf-as-winkel (nth 0 dlg-aus-ein) + as-seite (nth 1 dlg-aus-ein) + gf-es-winkel (nth 2 dlg-aus-ein) + es-seite (nth 3 dlg-aus-ein)) + (progn + (princ (ssg-text "vf-winkel-aus-header")) + (princ (ssg-text "vf-winkel-90")) + (princ (ssg-text "vf-winkel-30")) + (setq gf-as-winkel (vf-frage-element-winkel "vf-winkel-aus-header")) + (princ (ssg-text "gf-seite-aus-header")) + (princ (ssg-text "gf-seite-links")) + (princ (ssg-text "gf-seite-rechts")) + (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) + (setq as-seite (if (= antwort "2") "rechts" "links")) - ;; EIN-Element: 30/90 + Seite - (princ (ssg-text "vf-winkel-ein-header")) - (princ (ssg-text "vf-winkel-90")) - (princ (ssg-text "vf-winkel-30")) - (setq gf-es-winkel (vf-frage-element-winkel "vf-winkel-ein-header")) - (princ (ssg-text "gf-seite-ein-header")) - (princ (ssg-text "gf-seite-links")) - (princ (ssg-text "gf-seite-rechts")) - (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) - (setq es-seite (if (= antwort "2") "rechts" "links")) + (princ (ssg-text "vf-winkel-ein-header")) + (princ (ssg-text "vf-winkel-90")) + (princ (ssg-text "vf-winkel-30")) + (setq gf-es-winkel (vf-frage-element-winkel "vf-winkel-ein-header")) + (princ (ssg-text "gf-seite-ein-header")) + (princ (ssg-text "gf-seite-links")) + (princ (ssg-text "gf-seite-rechts")) + (setq antwort (getstring (ssg-text "prompt-wahl-1-2"))) + (setq es-seite (if (= antwort "2") "rechts" "links")) + ) + ) + (vf-set-as-masse gf-as-winkel as-seite) (vf-set-es-masse gf-es-winkel es-seite) (setq as-block (strcat "AS_Element_" gf-as-winkel "_" as-seite)) @@ -881,14 +1031,30 @@ (princ (ssg-text "gf-status-berechne-winkel")) (setq grade (gf-winkel-berechnen segmente deltaH 1)) - ;; Manuelle Anpassung - (setq antwort - (getstring (ssg-textf "gf-prompt-winkel-verwenden" - (list (rtos grade 2 3) grad-zeichen)))) - (if (= (strcase antwort) "N") + ;; Manuelle Anpassung per Dialog (ersetzt zugleich die SPAETERE finale + ;; Einfuegen-Bestaetigung, siehe gf-dialog-linienzug-winkel) - Rueckfall + ;; auf die alten Konsolenfragen, wenn der Dialog nicht gezeigt werden + ;; kann/darf; dann bleibt auch die spaetere Einfuegen-Bestaetigung aktiv. + (setq dlg-winkel-erg + (gf-dialog-linienzug-winkel + (list (ssg-textf "gf-status-zus-segmente" (list (length segmente))) + (ssg-textf "gf-status-zus-deltah" (list delta-sym (rtos deltaH 2 2)))) + grade gf-as-winkel as-seite gf-es-winkel es-seite)) + (if (eq dlg-winkel-erg 'ABBRUCH) + (progn (princ (ssg-text "vfc-vorgang-abgebrochen")) (exit)) + ) + (if dlg-winkel-erg + (setq grade dlg-winkel-erg) (progn - (setq grade (getreal (ssg-text "gf-prompt-gefaellewinkel"))) - (if (or (null grade) (<= grade 0)) (setq grade 3.0)) + (setq antwort + (getstring (ssg-textf "gf-prompt-winkel-verwenden" + (list (rtos grade 2 3) grad-zeichen)))) + (if (= (strcase antwort) "N") + (progn + (setq grade (getreal (ssg-text "gf-prompt-gefaellewinkel"))) + (if (or (null grade) (<= grade 0)) (setq grade 3.0)) + ) + ) ) ) (setq grade (float grade)) @@ -953,8 +1119,9 @@ (princ (ssg-textf "gf-status-zus-ein-element" (list es-block))) (princ "\n=========================================") - ;; Bestaetigung - (setq antwort (getstring (ssg-text "gf-prompt-einfuegen"))) + ;; Bestaetigung - entfaellt, wenn der Dialog oben bereits bestaetigt hat + ;; (dlg-winkel-erg ist dann eine Zahl, kein nil/'ABBRUCH). + (setq antwort (if dlg-winkel-erg "1" (getstring (ssg-text "gf-prompt-einfuegen")))) (if (not (= antwort "2")) (progn ;; GF-Nummer und Entity-Grenze vor erster Einfuegung sichern. diff --git a/dcl/gefaellestrecke.dcl b/dcl/gefaellestrecke.dcl index bfb6c12..a6610ec 100644 --- a/dcl/gefaellestrecke.dcl +++ b/dcl/gefaellestrecke.dcl @@ -6,6 +6,14 @@ // Eingaben entsprechen dem interaktiven Skript Gefaellestrecke.lsp: // Abstand deltaL, Gefaellewinkel, Fahrtrichtung, // Seite AUS-Element, Seite EIN-Element. +// +// gefaellestrecke_linienzug: Modus 3 (aus Linienzug LINE+ARC) - ersetzt die +// Konsolenfragen AUS-/EIN-Element Winkel+Seite, Winkelbestaetigung und die +// finale Einfuegen-Bestaetigung in EINEM Dialog (gf-dialog-linienzug in +// Gefaellestrecke.lsp). Die Objektauswahl (ssget LINE/ARC) UND die +// Start-/Endpunktwahl bleiben davor Zeichnung/Konsole - der automatisch +// berechnete Vorschlagswinkel wird als Vorbelegung des Winkel-Feldes +// gezeigt, mit einer kurzen Zusammenfassung der Segmentanalyse darueber. // ============================================================ gefaellestrecke : dialog { @@ -108,3 +116,64 @@ gefaellestrecke : dialog { ok_cancel; } + +// Modus 3 (aus Linienzug): AUS-/EIN-Element Winkel+Seite, Gefaellewinkel +// (Vorschlag vorbelegt, ueberschreibbar) und eine kurze Zusammenfassung der +// automatisch analysierten Segmentkette. "zusammenfassung" wird per +// set_tile aus mehreren ssg-textf-Zeilen zusammengesetzt (gf-dialog- +// linienzug, Gefaellestrecke.lsp) - sprachunabhaengig, nur das Label-Chrome +// bleibt hart deutsch wie der Rest dieser Datei. +gefaellestrecke_linienzug : dialog { + label = "Gefaellestrecke aus Linienzug"; + + : column { + + : boxed_column { + label = "Segmentanalyse"; + : text { key = "zusammenfassung"; label = ""; width = 55; } + } + + : boxed_row { + label = "AUS-Element"; + + : popup_list { + key = "aus_winkel"; + label = "Winkel:"; + width = 12; + } + : popup_list { + key = "aus_seite"; + label = "Seite:"; + width = 14; + } + } + + : boxed_row { + label = "EIN-Element"; + + : popup_list { + key = "ein_winkel"; + label = "Winkel:"; + width = 12; + } + : popup_list { + key = "ein_seite"; + label = "Seite:"; + width = 14; + } + } + + : boxed_column { + label = "Gefaellewinkel"; + + : edit_box { + key = "winkel"; + label = "Gefaellewinkel (Grad):"; + edit_width = 10; + } + } + + } + + ok_cancel; +} diff --git a/doc/images/gf-linienzug1.png b/doc/images/gf-linienzug1.png new file mode 100644 index 0000000000000000000000000000000000000000..3f86d3ddbd6c58867284b5a00e061a3d0f8b8060 GIT binary patch literal 7617 zcmeHLe^gUd9KR#Uf%0SQ99b$3Mc|amFHJPiS29rifflC7(O4N;kqDAS8hfh-hN z1Oy#wNApC2mWHWpO_ELpWK*e7*^h84f^V&{2ixB5-TQ`m>gYM0>L1Te2u+wvYEnZvcQ#@*K%?0C+M0JR;&h%FgVX(kEaaUO97?pWV0dU0ETM;@r`%sJMo%zHLEN85CP}D^Ki!sPfRGH*j$NRZ!sY<}xbo^uG^meQ(&-Tr^YOeA$`4F77X^Z}3AsL^ zbF(}5zg=`>hz3@sbj$X@flqB0=`_n^@rOR55;%-qc-DN*_DY>K^p;svLXl(5vWeL* zqeN>cZXfumu3&EQODP&ycxA)8DytSO@BOUd)zq(*pDlu>Q<@uSg#v?l_2 zKP1yC^^-!UEI_w@jEtQGi%;-%dlcjpX?g^h zR!)(Hrf%5_=|;1kmkQkcSOpaS7SFJmfY$T;7y`J$IFTZRf-4ZxV(e z^jU+4Ji`kv-LRGZw#gI?3ne@4nF*SvwERpB#HmHWlt^Q1Z z`?as(iFpRqHRJ8_F;}nYr^1UZW}hab^qK-2k9w ziX9yxjylPj?_g+~k&_Ng(augY)!=lj>`l0&HP?5(-dIp&7p)!Td?z-lt5AV;1nr0X z1nmX8?7((>6Im-v?AEqi8ppIEw(6)9E&SCGv&<@d{&E-Gqx}MAiThBBfp@l^hTn%e zhJI!Z>+RnxHjB~Z;czChj1q?oKqZZBYZt=u*|eX)Nrp4XcD1z$W(t@P32ZNcXhqHp zGdW!W<;Rk+&ALXG?#~2fx156^S|3OVc$5o1m4)Bgu2j)3_@y$o zd9gpWf33Z;h#P~k8tAjkf=f7OOe$=@ON_v^t~}aG2Hg=e$|WWzC>569fh#LGBf!=1 z4$LlUe77tjgd0D-i6X{k;g$s|s$6Q+*V?BmZ>vEd)d1Uxg-1GZ2I!`;^wPi6F^=`x zLbVL%hP>mb2^wAD{OdL?71Y}MMS3{5&(0|oaN7{P7>qdcmD1(~2bpGk%`pW@cQnUN zV;x0c5Ub%J7;|Jz8w9|@ZN<)2_Al7N#t=&Q7h!|irR`w%n7sI#rkQ8!@1gkp4j?Ku zY9Put^Tb#KAp57fstxSwD&vcUExO1Rt-H+N?A)@lrLEhg+=y3^QT&7e_aO-db})?Y z!=gJM-1+c-ej`b9k1ssgVy;)(MegQ9;!VZfeB6FOiQvAN5aW7q`@!u8HWBW3UdCTz zZh-q{6E%#7{m_oSBH`#2l$9ZpIi|)jpzTUJb2TJiW+D6p#}Vs z@8^5kUhrj0;{moCRlfVA@F1QPWLZCKv?^}jrmm|tZdg)^!VN&9-aL3UN8pM3+}%Cg afNzI+_iZElCM6w4eo9VEksO{SeeX}ikhWI< literal 0 HcmV?d00001 diff --git a/doc/images/gf-linienzug2.png b/doc/images/gf-linienzug2.png new file mode 100644 index 0000000000000000000000000000000000000000..8cd4a5d034eb9db13f65b650479afc41bceb8bba GIT binary patch literal 22766 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 HB{Ts5Tmo*t literal 0 HcmV?d00001 diff --git a/doc/images/gf-linienzug3.png b/doc/images/gf-linienzug3.png new file mode 100644 index 0000000000000000000000000000000000000000..b5e6af22b8267423a5a1faadc4c0f43a99803db6 GIT binary patch literal 46188 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�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 GF-Block erstellt: %1 (%2)", "gf-status-schritt1-aus": "\n\n1/4: %1 Fahrtrichtung=%2%3 KS_EIN-hz=%4%5 v=%6%7", "gf-status-schritt2-staustrecke": "\n\n2/4: Staustrecke L=%1 mm hz=%2%3 v=%4%5", diff --git a/lang/en_GB.json b/lang/en_GB.json index 5888297..1c4e2b9 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -815,6 +815,7 @@ "gf-dlg-richtung-270": "270%1 (Y-, South)", "gf-dlg-links": "Left", "gf-dlg-rechts": "Right", + "gf-dlg-linienzug-vorlauf": "Path selected - angle will be calculated after confirmation.", "gf-status-gf-block-erstellt": "\n>>> GF block created: %1 (%2)", "gf-status-schritt1-aus": "\n\n1/4: %1 travel dir=%2%3 KS_EIN-hz=%4%5 v=%6%7", "gf-status-schritt2-staustrecke": "\n\n2/4: Buffer section L=%1 mm hz=%2%3 v=%4%5", From 01fb2d29f228d056e7e41aa6f6fba01a73998b0f Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 13:16:55 +0200 Subject: [PATCH 35/38] [CHANGE] GEFAELLESTRECKE_LINIENZUG-Streckengruppen per Doppelklick editierbar machen Bisher brach GEFAELLESTRECKE_EDIT bei jeder Streckengruppe (TYP "Streckengruppe", d.h. mit mindestens einem Bogen) mit "Nur einfache Gefaellestrecken..." ab - Grund war nicht fehlende Technik, sondern dass gf-linienzug-modus schlicht keine Edit-XDATA schrieb (anders als Modus 1/2 ueber SSG_GF_EDIT). Neue XDATA-App SSG_GF_LZ (gf-lz-xdata-schreiben/-lesen in Lisp/Gefaellestrecke.lsp) sichert die Segmentliste (Typ/hz/Laenge/Winkel/Seite je Segment, bereits laengenfertig) + den Baustartpunkt - Serialisierung per gf-segmente->string/gf-string->segmente, Chunking ueber die bestehenden ssg-sepliste-chunk-string/-split-feld/-explode-chars-Helfer aus ssg_ks_insert.lsp (wiederverwendet statt dupliziert). Neue Funktion gf-linienzug-rebuild: baut die Kette am selben Startpunkt neu, AS-/EIN-Element und Gefaellewinkel bleiben ueber dieselben zwei Dialoge wie beim Bauen editierbar (gf-dialog-linienzug-aus-ein/-winkel, jetzt mit prefill-Parameter fuer den Edit-Fall statt Defaults) - die Segmentlaengen/-form selbst nicht (dafuer bleibt GEFAELLESTRECKE_LINIENZUG als Neubau). c:GEFAELLESTRECKE_EDIT dispatcht vor der bisherigen TYP-Sperre: Streckengruppe MIT SSG_GF_LZ-XDATA -> neuer Rebuild-Pfad, Streckengruppe OHNE (Altbestand/VF-Kombi) -> bleibt wie bisher abgewiesen. Alter Block wird erst NACH erfolgreichem Neuaufbau geloescht. doc/variofoerderer.md um den Edit-Ablauf ergaenzt. Manuell in BricsCAD getestet (Doppelklick auf Linienzug-Streckengruppe, beide Dialoge vorbelegt, Neuaufbau, erneuter Doppelklick auf das Ergebnis) - laeuft. Co-Authored-By: Claude Sonnet 5 --- Lisp/Gefaellestrecke.lsp | 425 ++++++++++++++++++++++++++++++++++++--- doc/variofoerderer.md | 19 ++ lang/de_DE.json | 1 + lang/en_GB.json | 1 + 4 files changed, 418 insertions(+), 28 deletions(-) diff --git a/Lisp/Gefaellestrecke.lsp b/Lisp/Gefaellestrecke.lsp index b0fe4e3..83a7871 100644 --- a/Lisp/Gefaellestrecke.lsp +++ b/Lisp/Gefaellestrecke.lsp @@ -719,11 +719,14 @@ ;; EIN-Seite). Muss VOR der Segmentlaengen-Anpassung/Winkelberechnung ;; laufen (die braucht aus-dx/ein-dx aus vf-set-as-masse/-es-masse), darum ;; eigener, frueherer Dialog statt zusammen mit dem Winkel-Vorschlag. +;; prefill: Alist (("as-winkel" . "90"|"30") ("as-seite" . "links"|"rechts") +;; ("es-winkel" . ...) ("es-seite" . ...)) fuer den Edit-Nachbau, oder nil +;; fuer die Defaults (90/links) beim Neu-Bauen. ;; Rueckgabe: (as-winkel as-seite es-winkel es-seite) bei OK, 'ABBRUCH wenn ;; der Nutzer bewusst abbricht (Aufrufer bricht dann den GANZEN Befehl ab, ;; KEIN Rueckfall auf die Konsole), nil wenn der Dialog gar nicht gezeigt ;; werden konnte/durfte (GUI aus) - NUR dann Konsolen-Rueckfall. -(defun gf-dialog-linienzug-aus-ein ( / dcl-pfad dat ergebnis +(defun gf-dialog-linienzug-aus-ein (prefill / dcl-pfad dat ergebnis dlg-aus-winkel dlg-aus dlg-ein-winkel dlg-ein as-seite es-seite as-winkel es-winkel) (if (or (not (car (atoms-family 1 '("SSG-GUI-P")))) (ssg-gui-p)) @@ -740,23 +743,27 @@ (add_list "90") (add_list "30") (end_list) - (set_tile "aus_winkel" "0") + (set_tile "aus_winkel" + (if (and prefill (equal (cdr (assoc "as-winkel" prefill)) "30")) "1" "0")) (start_list "aus_seite") (add_list (ssg-text "gf-dlg-links")) (add_list (ssg-text "gf-dlg-rechts")) (end_list) - (set_tile "aus_seite" "0") + (set_tile "aus_seite" + (if (and prefill (equal (cdr (assoc "as-seite" prefill)) "rechts")) "1" "0")) (start_list "ein_winkel") (add_list "90") (add_list "30") (end_list) - (set_tile "ein_winkel" "0") + (set_tile "ein_winkel" + (if (and prefill (equal (cdr (assoc "es-winkel" prefill)) "30")) "1" "0")) (start_list "ein_seite") (add_list (ssg-text "gf-dlg-links")) (add_list (ssg-text "gf-dlg-rechts")) (end_list) - (set_tile "ein_seite" "0") + (set_tile "ein_seite" + (if (and prefill (equal (cdr (assoc "es-seite" prefill)) "rechts")) "1" "0")) (action_tile "accept" (strcat @@ -861,7 +868,7 @@ entry-hz exit-hz first-idx last-idx neu-l aktuell-frame nach-aus-pt - gf-nummer last-ent + gf-nummer last-ent gf-lz-insert L-gf-str delta-l-gf laengen-liste first-l l-item bL90 bL60 bL30 bR90 bR60 bR30 ein-hz-as rad-h-as rad-v-as xu-entry @@ -928,7 +935,7 @@ ;; AUS-/EIN-Element: 30/90 + Seite, in EINEM Dialog (vor Winkelberechnung, ;; da die Laengenanpassung von der AS/ES-Masse abhaengt). Rueckfall auf die ;; alten Konsolenfragen, wenn der Dialog nicht gezeigt werden kann/darf. - (setq dlg-aus-ein (gf-dialog-linienzug-aus-ein)) + (setq dlg-aus-ein (gf-dialog-linienzug-aus-ein nil)) (if (eq dlg-aus-ein 'ABBRUCH) (progn (princ (ssg-text "vfc-vorgang-abgebrochen")) (exit)) ) @@ -1222,24 +1229,30 @@ ;; Block mit allen Attributen erstellen. Geruest fuer Einzelmodul/ ;; Geruestoption sind in diesem Linienzug-Ablauf (Modus 3, keine DCL- ;; Eingabe) nicht abfragbar - bleiben auf Schema-Default. - (gf-block-erstellen - "gruppe" as-seite gf-nummer - (caddr startpunkt) - (caddr endpunkt-ref) - deltaH - delta-l-gf - L-gf-str - grade - ;; n-separator/n-scanner = 0: interne Ketten-Separatoren zaehlen nicht; - ;; die echte Anzahl setzt der Export aus platzierten Symbolen. - 0 - 0 - bL90 bL60 bL30 - bR90 bR60 bR30 - startpunkt last-ent nach-aus-pt entry-hz - (caddr (nth first-idx segmente)) - es-seite "0" "Schoenenberger Geruest" - gf-as-winkel gf-es-winkel) + (setq gf-lz-insert + (gf-block-erstellen + "gruppe" as-seite gf-nummer + (caddr startpunkt) + (caddr endpunkt-ref) + deltaH + delta-l-gf + L-gf-str + grade + ;; n-separator/n-scanner = 0: interne Ketten-Separatoren zaehlen nicht; + ;; die echte Anzahl setzt der Export aus platzierten Symbolen. + 0 + 0 + bL90 bL60 bL30 + bR90 bR60 bR30 + startpunkt last-ent nach-aus-pt entry-hz + (caddr (nth first-idx segmente)) + es-seite "0" "Schoenenberger Geruest" + gf-as-winkel gf-es-winkel)) + + ;; Segmentliste + Startpunkt fuer den Doppelklick-Nachbau sichern (siehe + ;; c:GEFAELLESTRECKE_EDIT) - ohne diese XDATA war eine per Linienzug + ;; gebaute Streckengruppe bisher nicht editierbar. + (gf-lz-xdata-schreiben gf-lz-insert segmente startpunkt) (princ "\n\n=========================================") (princ (ssg-text "gf-status-fertig")) @@ -1249,6 +1262,215 @@ ) ) +;; Doppelklick-Nachbau fuer eine per GEFAELLESTRECKE_LINIENZUG (Modus 3) +;; gebaute Streckengruppe - Gegenstueck zu gf-rebuild (Modus 1/2), aufgerufen +;; aus c:GEFAELLESTRECKE_EDIT. Anders als beim Neu-Bauen (gf-linienzug-modus) +;; sind die Segmentlaengen hier bereits FINAL (AS-/ES-dx und Separator- +;; Abzuege sind laengst eingerechnet, siehe gf-lz-xdata-schreiben) - die +;; Segmentlisten-Anpassungsschleife aus gf-linienzug-modus entfaellt darum +;; komplett, nur AS-/ES-Winkel+Seite und der Gefaellewinkel bleiben ueber +;; dieselben zwei Dialoge editierbar (gf-dialog-linienzug-aus-ein/-winkel, +;; diesmal mit Prefill aus den Block-Attributen). Baut am gleichen +;; startpunkt neu, loescht den alten Block NACH erfolgreichem Neuaufbau. +;; segmente/startpunkt: aus gf-lz-xdata-lesen. alt-ent: der zu ersetzende +;; GF_n-Block. prefill: Alist wie gf-dialog-linienzug-aus-ein (AS/ES aus den +;; aktuellen Attributen des Blocks). +(defun gf-linienzug-rebuild (segmente startpunkt alt-ent prefill / + deltaH entry-hz exit-hz as-seite es-seite + gf-as-winkel gf-es-winkel as-block es-block + dlg-aus-ein dlg-winkel-erg grade + first-idx j seg end-z endpunkt-ref delta-l-gf + aktuell-frame nach-aus-pt ein-hz-as rad-h-as xu-entry + sep-endpunkt rad-h-es rad-v-es xu-exit sep-frame es-aus-frame + gf-nummer last-ent gf-lz-insert + L-gf-str laengen-liste first-l l-item + bL90 bL60 bL30 bR90 bR60 bR30 + rad-v-korr ein-hz-as-k rad-h-as-k xu-as-meas + rad-h-es-k xu-es-meas dz-as-ist dz-es-ist + dH-korr grade-prev iter) + (if (or (null segmente) (< (length segmente) 1)) + (progn (alert (ssg-text "gf-alert-keine-kette")) (exit)) + ) + + (setq entry-hz (cadr (car segmente))) + (setq exit-hz (gf-exit-hz segmente)) + + ;; AUS-/EIN-Element, vorbelegt aus den aktuellen Attributen + (setq dlg-aus-ein (gf-dialog-linienzug-aus-ein prefill)) + (if (eq dlg-aus-ein 'ABBRUCH) + (progn (princ (ssg-text "vfc-vorgang-abgebrochen")) (exit)) + ) + (if (null dlg-aus-ein) + (progn (alert (ssg-text "gf-alert-lz-edit-kein-dialog")) (exit)) + ) + (setq gf-as-winkel (nth 0 dlg-aus-ein) + as-seite (nth 1 dlg-aus-ein) + gf-es-winkel (nth 2 dlg-aus-ein) + es-seite (nth 3 dlg-aus-ein)) + (vf-set-as-masse gf-as-winkel as-seite) + (vf-set-es-masse gf-es-winkel es-seite) + + (setq as-block (strcat "AS_Element_" gf-as-winkel "_" as-seite)) + (setq es-block (strcat "ES_Element_" gf-es-winkel "_" es-seite)) + + ;; Index des ersten "Linie"-Segments (fuer die Label-Laenge) - KEINE + ;; Laengenanpassung, die Segmentlaengen sind bereits final. + (setq first-idx -1 j 0) + (while (and (< j (length segmente)) (< first-idx 0)) + (if (= (car (nth j segmente)) "Linie") (setq first-idx j)) + (setq j (1+ j)) + ) + (if (< first-idx 0) (setq first-idx 0)) + + ;; Ziel-Endhoehe aus dem Z-Attribut HOEHE_BIS_mm des alten Blocks (X/Y des + ;; wirklichen Endpunkts wird erst NACH dem Bau aus der Geometrie selbst + ;; bestimmt, siehe unten - sie ist nicht separat in der XDATA gespeichert + ;; und nur fuer die Zusammenfassung/das Label relevant, nicht fuer den Bau + ;; selbst, der komplett der Segmentliste folgt). + (setq end-z (atof (cond ((cdr (assoc "HOEHE_BIS_mm" (ssg-attrib-read alt-ent)))) ("0")))) + (setq deltaH (abs (- (caddr startpunkt) end-z))) + + (princ (ssg-text "gf-status-berechne-winkel")) + (setq grade (gf-winkel-berechnen segmente deltaH 1)) + + (setq dlg-winkel-erg + (gf-dialog-linienzug-winkel + (list (ssg-textf "gf-status-zus-segmente" (list (length segmente))) + (ssg-textf "gf-status-zus-deltah" (list delta-sym (rtos deltaH 2 2)))) + grade gf-as-winkel as-seite gf-es-winkel es-seite)) + (if (eq dlg-winkel-erg 'ABBRUCH) + (progn (princ (ssg-text "vfc-vorgang-abgebrochen")) (exit)) + ) + (if (null dlg-winkel-erg) + (progn (alert (ssg-text "gf-alert-lz-edit-kein-dialog")) (exit)) + ) + (setq grade (float dlg-winkel-erg)) + + ;; Winkelkorrektur (identisch zu gf-linienzug-modus) + (if (and *gf-L-ohne-as-es* (> *gf-L-ohne-as-es* 0.1)) + (progn + (princ (ssg-text "gf-status-messe-absenkung")) + (setq grade-prev -999.0 iter 0) + (while (and (< iter 4) (> (abs (- grade grade-prev)) 0.001)) + (setq grade-prev grade) + (setq rad-v-korr (* grade (/ pi 180.0))) + (setq ein-hz-as-k (- entry-hz + (vf-element-plan-turn (strcat "AS_Element_" gf-as-winkel "_" as-seite)))) + (setq rad-h-as-k (* (float ein-hz-as-k) (/ pi 180.0))) + (setq xu-as-meas (list (cos rad-h-as-k) (sin rad-h-as-k) 0.0)) + (setq rad-h-es-k (* (float exit-hz) (/ pi 180.0))) + (setq xu-es-meas (list (* (cos rad-h-es-k)(cos rad-v-korr)) + (* (sin rad-h-es-k)(cos rad-v-korr)) + (- (sin rad-v-korr)))) + (setq dz-as-ist (gf-messe-dz-block as-block xu-as-meas)) + (setq dz-es-ist (gf-messe-dz-block es-block xu-es-meas)) + (setq dH-korr (- (float deltaH) dz-as-ist dz-es-ist (float *gf-sum-dz-bogen*))) + (if (and (> dH-korr 0.0) (< (/ dH-korr *gf-L-ohne-as-es*) 1.0)) + (setq grade (* (asin (/ dH-korr *gf-L-ohne-as-es*)) (/ 180.0 pi))) + (progn + (princ (ssg-text "gf-warnung-korrektur-bereich")) + (setq grade-prev grade) + ) + ) + (setq iter (1+ iter)) + ) + (princ (ssg-textf "gf-status-korrigierter-winkel" + (list (rtos grade 2 3) grad-zeichen (itoa iter)))) + ) + ) + ;; Alten Block ERST NACH erfolgreichem Neuaufbau loeschen (siehe unten) - + ;; die GF-Nummer/last-ent-Grenze muss aber VOR dem Neu-Einfuegen stehen. + (setq gf-nummer (gf-next-number)) + (setq last-ent (ssg-lastent-ohne-attribute)) + + (setq ein-hz-as (- entry-hz + (vf-element-plan-turn (strcat "AS_Element_" gf-as-winkel "_" as-seite)))) + (setq rad-h-as (* (float ein-hz-as) (/ pi 180.0))) + (setq xu-entry (list (cos rad-h-as) (sin rad-h-as) 0.0)) + (setq aktuell-frame + (insert-block-mixed-to-ks as-block (make-frame-from-dir startpunkt xu-entry) + (caddr startpunkt) nil "KS_EIN")) + (setq nach-aus-pt (car aktuell-frame)) + + (setq aktuell-frame (gf-linienzug-einfuegen segmente grade aktuell-frame)) + + (setq sep-endpunkt + (gf-insert-hz-with-ks "Staustrecke_Separator_SP_300_mm" + (car aktuell-frame) exit-hz grade 300 0)) + (setq rad-h-es (* (float exit-hz) (/ pi 180.0))) + (setq rad-v-es (* (float grade) (/ pi 180.0))) + (setq xu-exit (list (* (cos rad-h-es)(cos rad-v-es)) + (* (sin rad-h-es)(cos rad-v-es)) + (- (sin rad-v-es)))) + (setq sep-frame (make-frame-from-dir sep-endpunkt xu-exit)) + (setq es-aus-frame + (insert-block-mixed-to-ks es-block sep-frame end-z "KS_EIN" "KS_AUS")) + + ;; Echter Endpunkt (fuer DELTA_L-Attribut/Label) erst jetzt aus der + ;; gebauten Geometrie bekannt - KS_AUS des ES-Elements. + (setq endpunkt-ref (car es-aus-frame)) + (setq delta-l-gf + (sqrt (+ (expt (- (car endpunkt-ref) (car startpunkt)) 2) + (expt (- (cadr endpunkt-ref) (cadr startpunkt)) 2)))) + + (setq laengen-liste '() first-l t) + (foreach seg segmente + (if (= (car seg) "Linie") + (setq laengen-liste + (append laengen-liste (list (rtos (/ (caddr seg) 1000.0) 2 3)))) + ) + ) + (setq L-gf-str "") + (foreach l-item laengen-liste + (if first-l + (progn (setq L-gf-str l-item) (setq first-l nil)) + (setq L-gf-str (strcat L-gf-str "," l-item)) + ) + ) + + (setq bL90 0 bL60 0 bL30 0 bR90 0 bR60 0 bR30 0) + (foreach seg segmente + (if (= (car seg) "Bogen") + (cond + ((and (= (nth 4 seg) "links") (= (nth 3 seg) 90)) (setq bL90 (1+ bL90))) + ((and (= (nth 4 seg) "links") (= (nth 3 seg) 60)) (setq bL60 (1+ bL60))) + ((and (= (nth 4 seg) "links") (= (nth 3 seg) 30)) (setq bL30 (1+ bL30))) + ((and (= (nth 4 seg) "rechts") (= (nth 3 seg) 90)) (setq bR90 (1+ bR90))) + ((and (= (nth 4 seg) "rechts") (= (nth 3 seg) 60)) (setq bR60 (1+ bR60))) + ((and (= (nth 4 seg) "rechts") (= (nth 3 seg) 30)) (setq bR30 (1+ bR30))) + ) + ) + ) + + (setq gf-lz-insert + (gf-block-erstellen + "gruppe" as-seite gf-nummer + (caddr startpunkt) + (caddr endpunkt-ref) + deltaH + delta-l-gf + L-gf-str + grade + 0 0 + bL90 bL60 bL30 + bR90 bR60 bR30 + startpunkt last-ent nach-aus-pt entry-hz + (caddr (nth first-idx segmente)) + es-seite "0" "Schoenenberger Geruest" + gf-as-winkel gf-es-winkel)) + + (gf-lz-xdata-schreiben gf-lz-insert segmente startpunkt) + + ;; Alten Block erst jetzt entfernen - der Neuaufbau ist bereits vollstaendig + ;; abgeschlossen, ein Fehler davor haette ihn stehen gelassen. + (if (and alt-ent (entget alt-ent)) (entdel alt-ent)) + + (princ "\n\n=========================================") + (princ (ssg-text "gf-status-fertig")) + (princ "\n=========================================") + gf-lz-insert +) + ;; ============================================================ ;; TEIL 4.5: GF-BLOCK-SYSTEM (Nummerierung, Label, Attribute) ;; ============================================================ @@ -1871,6 +2093,124 @@ ) ) +;; ============================================================ +;; XDATA fuer den Linienzug-Nachbau (Modus 3, App "SSG_GF_LZ"). +;; Die Segmentliste (gf-analysiere-kette) hat variable Laenge - anders als +;; gf-xdata-schreiben (feste Skalare fuer Modus 1/2) braucht sie ein eigenes +;; String-Format + Chunking (255-Byte-Limit je 1000-Gruppe), analog zur +;; Sepliste-XDATA in ssg_ks_insert.lsp (ssg-sepliste-chunk-string/-split-feld/ +;; -explode-chars werden von dort wiederverwendet statt dupliziert). +;; AS-/ES-Winkel+Seite stehen bereits als Attribute (WINKEL_AS/SEITE_AS/ +;; WINKEL_ES/SEITE_ES) auf dem Block - nur die Segmentliste UND der gebaute +;; Startpunkt (fuer den Neuaufbau-Ursprung) fehlen dort und muessen hier +;; gesichert werden. +;; ============================================================ +(if (null *gf-lz-xdata-app*) (setq *gf-lz-xdata-app* "SSG_GF_LZ")) + +;; Ein Segment "(Typ hz laenge winkel seite)" -> "Typ:hz:laenge:winkel:seite". +(defun gf-segment->string (seg) + (strcat (nth 0 seg) ":" (rtos (float (nth 1 seg)) 2 4) ":" + (rtos (float (nth 2 seg)) 2 4) ":" (itoa (fix (nth 3 seg))) ":" + (nth 4 seg)) +) + +;; Gegenstueck: "Typ:hz:laenge:winkel:seite" -> (Typ hz laenge winkel seite). +(defun gf-string->segment (s / feld) + (setq feld (ssg-sepliste-split-feld s ":")) + (if (= (length feld) 5) + (list (nth 0 feld) (atof (nth 1 feld)) (atof (nth 2 feld)) + (atoi (nth 3 feld)) (nth 4 feld)) + nil + ) +) + +;; Segmentliste -> ein einzelner kommagetrennter String. +(defun gf-segmente->string (segmente / out first) + (setq out "" first t) + (foreach seg segmente + (if first + (progn (setq out (gf-segment->string seg)) (setq first nil)) + (setq out (strcat out "," (gf-segment->string seg))) + ) + ) + out +) + +;; Gegenstueck zu gf-segmente->string - nutzt denselben Zeichen-Explode wie +;; die Sepliste (ssg_ks_insert.lsp), da Segment-Trenner "," mit dem inneren +;; Feld-Trenner ":" nicht kollidiert. +(defun gf-string->segmente (s / out teile eintraege seg) + (setq out '()) + (if (> (strlen s) 0) + (progn + (setq eintraege '() teile "") + (foreach c (ssg-sepliste-explode-chars s) + (if (= c ",") + (progn (setq eintraege (cons teile eintraege)) (setq teile "")) + (setq teile (strcat teile c)) + ) + ) + (setq eintraege (reverse (cons teile eintraege))) + (foreach eintrag eintraege + (if (setq seg (gf-string->segment eintrag)) (setq out (cons seg out))) + ) + ) + ) + (reverse out) +) + +;; Segmentliste + Nachbau-Startpunkt als XDATA schreiben. Marker "linienzug" +;; als erster Wert (Platz fuer kuenftige Varianten, analog SSG_VF_EDIT). +(defun gf-lz-xdata-schreiben (ent segmente startpunkt / chunks appentry) + (if (and ent segmente) + (progn + (regapp *gf-lz-xdata-app*) + (setq chunks + (ssg-sepliste-chunk-string + (strcat (rtos (car startpunkt) 2 4) ";" (rtos (cadr startpunkt) 2 4) ";" + (rtos (caddr startpunkt) 2 4) ";" (gf-segmente->string segmente)) + 250)) + (setq appentry + (cons *gf-lz-xdata-app* + (cons (cons 1000 "linienzug") + (mapcar (function (lambda (c) (cons 1000 c))) chunks)))) + (entmod (append (entget ent) (list (list -3 appentry)))) + ) + ) + ent +) + +;; XDATA lesen -> (startpunkt segmente) oder nil (kein/unbekanntes Linienzug- +;; XDATA am Entity). +(defun gf-lz-xdata-lesen (ent / xd app-data werte roh teile sp-x sp-y sp-z rest) + (setq xd (entget ent (list *gf-lz-xdata-app*))) + (setq app-data (cdr (assoc -3 xd))) + (if app-data + (progn + (setq werte (mapcar 'cdr (cdr (car app-data)))) + (if (and werte (= (car werte) "linienzug")) + (progn + (setq roh (apply 'strcat (cdr werte))) + (setq teile (ssg-sepliste-split-feld roh ";")) + (if (>= (length teile) 4) + (progn + (setq sp-x (atof (nth 0 teile)) sp-y (atof (nth 1 teile)) + sp-z (atof (nth 2 teile))) + ;; Rest nach dem 3. ";" wieder zusammenfuegen (Segmentliste + ;; selbst enthaelt kein ";"). + (setq rest (nth 3 teile)) + (list (list sp-x sp-y sp-z) (gf-string->segmente rest)) + ) + nil + ) + ) + nil + ) + ) + nil + ) +) + ;; ============================================================ ;; TEIL 6: HAUPTBEFEHL ;; ============================================================ @@ -2161,7 +2501,8 @@ (defun c:GEFAELLESTRECKE_EDIT ( / ss ent ed bname startpunkt attribs xd hz winkel as-winkel es-winkel z-start deltaL - as-seite hoehe-bis prefill dlg-werte) + as-seite hoehe-bis prefill dlg-werte + lz-xd lz-segmente lz-startpunkt lz-prefill) ;; Implied Selection VOR ssg-start pruefen (ssg-start hebt Selektion auf) (setq ss (ssget "I")) (if (and ss (= (sslength ss) 1) @@ -2189,9 +2530,37 @@ (setq startpunkt (cdr (assoc 10 ed))) (setq attribs (ssg-attrib-read ent)) + ;; Streckengruppe (mit Bogen) aus GEFAELLESTRECKE_LINIENZUG: eigener + ;; Rebuild-Pfad ueber die Segmentliste in SSG_GF_LZ-XDATA (siehe + ;; gf-linienzug-rebuild), NICHT ueber den einfachen gefaellestrecke-Dialog + ;; unten - der kennt keine Segmentliste/Boegen. Streckengruppe OHNE diese + ;; XDATA (Altbestand/VF-Kombi) bleibt wie bisher nicht editierbar. + (if (= (cond ((cdr (assoc "TYP" attribs))) ("")) "Streckengruppe") + (progn + (setq lz-xd (gf-lz-xdata-lesen ent)) + (cond + (lz-xd + (setq lz-startpunkt (nth 0 lz-xd)) + (setq lz-segmente (nth 1 lz-xd)) + (setq lz-prefill + (list (cons "as-winkel" (cond ((cdr (assoc "WINKEL_AS" attribs))) ("90"))) + (cons "as-seite" (cond ((cdr (assoc "SEITE_AS" attribs))) ("links"))) + (cons "es-winkel" (cond ((cdr (assoc "WINKEL_ES" attribs))) ("90"))) + (cons "es-seite" (cond ((cdr (assoc "SEITE_ES" attribs))) ("links"))))) + (gf-linienzug-rebuild lz-segmente lz-startpunkt ent lz-prefill) + ) + (t + (alert (ssg-textf "gf-edit-nur-einfach" + (list (cond ((cdr (assoc "TYP" attribs))) ("?"))))) + ) + ) + (ssg-end) + (exit) + ) + ) + ;; Nur einfache Gefaellestrecken (TYP "Gefaellestrecke") lassen sich ueber den - ;; Dialog verlustfrei nachbauen. Streckengruppen (mit Bogen / Linienzug / VF) - ;; wuerden beim Neuaufbau ihre Bogengeometrie verlieren -> abbrechen. + ;; Dialog verlustfrei nachbauen. (if (/= (cond ((cdr (assoc "TYP" attribs))) ("")) "Gefaellestrecke") (progn (alert (ssg-textf "gf-edit-nur-einfach" diff --git a/doc/variofoerderer.md b/doc/variofoerderer.md index f4897a6..ad0d2a8 100644 --- a/doc/variofoerderer.md +++ b/doc/variofoerderer.md @@ -280,6 +280,25 @@ Konsole zurueckzufallen. Kontrolle in der Zeichnung stehen: ![GF aus Linienzug - fertige Strecke neben der Ausgangslinie](images/gf-linienzug3.png) +**Bearbeiten (`c:GEFAELLESTRECKE_EDIT`):** Doppelklick auf einen per +Linienzug gebauten `GF_n`-Block (TEILEART `"Streckengruppe"`, enthaelt +mindestens einen Bogen) dispatcht auf `gf-linienzug-rebuild` statt auf den +einfachen Gefaellestrecke-Dialog — der kennt keine Segmentliste/Boegen und +wuerde beim Neuaufbau die Bogengeometrie verlieren. Die Segmentliste +(Typ/Fahrtrichtung/Laenge/Winkel/Seite je Segment, bereits laengenfertig) +UND der Baustartpunkt stehen als eigene XDATA (App `SSG_GF_LZ`, +`gf-lz-xdata-schreiben`/`-lesen`, variable Laenge + Chunking wie die +Sepliste-XDATA in `ssg_ks_insert.lsp`) auf dem Block — ohne sie bleibt eine +Streckengruppe wie zuvor nicht editierbar (Meldung "Nur einfache +Gefaellestrecken..."). Der Edit-Ablauf nutzt dieselben zwei Dialoge wie das +Bauen (`gf-dialog-linienzug-aus-ein`/`-winkel`), diesmal mit den aktuellen +Attributen (`WINKEL_AS`/`SEITE_AS`/`WINKEL_ES`/`SEITE_ES`) vorbelegt statt +mit Defaults — AS-/ES-Element und Gefaellewinkel bleiben damit nachtraeglich +aenderbar, die Segmentlaengen/-form (Geraden, Boegen) selbst nicht (dafuer +muss die Kette per `GEFAELLESTRECKE_LINIENZUG` neu gebaut werden). Baut am +selben Startpunkt neu und loescht den alten Block erst NACH erfolgreichem +Neuaufbau. + --- ## 5. VF Linienzug — Kette (Modus 1, frei zeichnend) diff --git a/lang/de_DE.json b/lang/de_DE.json index 89a83c5..21e5686 100644 --- a/lang/de_DE.json +++ b/lang/de_DE.json @@ -777,6 +777,7 @@ "gf-status-deltah-3dpunkte": "\n %1H aus 3D-Punkten: %2 mm", "gf-status-sortiere-segmente": "\n Sortiere Segmente ...", "gf-alert-keine-kette": "Keine verbundene Kette gefunden!", + "gf-alert-lz-edit-kein-dialog": "Bearbeiten einer Streckengruppe (Linienzug) braucht die GUI - bitte GUI einschalten (ssg-gui-an) und erneut versuchen.", "gf-status-segmente-gefunden": " %1 Segmente gefunden.", "gf-status-segment-analyse-header": "\n\n--- Segment-Analyse (Laengen nach Kuerzung) ---", "gf-status-segment-linie": "\n %1. Linie L=%2 mm hz=%3%4", diff --git a/lang/en_GB.json b/lang/en_GB.json index 1c4e2b9..87733d4 100644 --- a/lang/en_GB.json +++ b/lang/en_GB.json @@ -777,6 +777,7 @@ "gf-status-deltah-3dpunkte": "\n %1H from 3D points: %2 mm", "gf-status-sortiere-segmente": "\n Sorting segments ...", "gf-alert-keine-kette": "No connected chain found!", + "gf-alert-lz-edit-kein-dialog": "Editing a chain group (path-built) requires the GUI - please enable the GUI (ssg-gui-an) and try again.", "gf-status-segmente-gefunden": " %1 segments found.", "gf-status-segment-analyse-header": "\n\n--- Segment analysis (lengths after trimming) ---", "gf-status-segment-linie": "\n %1. Line L=%2 mm hz=%3%4", From 80e5e621607edc6bf54feed12a83526f4463be98 Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 13:29:40 +0200 Subject: [PATCH 36/38] [FIX] GEFAELLESTRECKE_LINIENZUG: ES-Element erhielt keinen Hoehenversatz bei flachem Endpunkt-Klick Das ES-Element wurde ueber insert-block-mixed-to-ks so platziert, dass sein KS_EIN exakt auf (caddr endpunkt-ref) landet - die Z-Koordinate des zweiten Mausklicks (Kettenende waehlen). Geraden und Boegen davor waren korrekt geneigt (grade wird separat berechnet/bestaetigt und fliesst in gf-linienzug-einfuegen ein), aber die anschliessende ES-Platzierung zog die Hoehe wieder auf den Klick-Wert zurueck - bei einem Klick in einer 2D-Draufsicht ohne 3D-Objektfang liegt der meist auf derselben Z wie der Startpunkt, das ES-Element landete dann faelschlich wieder auf Starthoehe trotz korrekt gefallener Kette. Fix: Ziel-Z fuer das ES-Element ist jetzt (caddr sep-endpunkt) - die tatsaechlich durch die Kette (Geraden/Boegen mit grade) aufgebaute Hoehe am Ende, nicht der Klick-Wert. endpunkt-ref dient weiterhin nur zur groben deltaH-Schaetzung fuer den Winkel-Vorschlag im Dialog (den der Nutzer ohnehin bestaetigt/ueberschreibt). Das Attribut HOEHE_BIS_mm wird aus demselben Grund jetzt ebenfalls aus der real gebauten Endhoehe (es-aus-frame) statt aus endpunkt-ref gelesen, damit es nicht von der sichtbaren Geometrie abweicht. Identischer Fix im neuen Rebuild-Pfad (gf-linienzug-rebuild) angewendet, der denselben Mechanismus nutzt. Manuell in BricsCAD verifiziert: ES-Element hat jetzt korrekten Hoehenversatz. Co-Authored-By: Claude Sonnet 5 --- Lisp/Gefaellestrecke.lsp | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/Lisp/Gefaellestrecke.lsp b/Lisp/Gefaellestrecke.lsp index 83a7871..afa655f 100644 --- a/Lisp/Gefaellestrecke.lsp +++ b/Lisp/Gefaellestrecke.lsp @@ -1180,13 +1180,19 @@ ;; EIN-Element: KS_EIN bleibt in X/Y auf dem Ketten-Pfad (sep-frame), ;; seine eigene Achse verlaeuft damit trivial durch diesen Punkt. - ;; Die Z-Hoehe wird jedoch an KS_AUS gemessen, damit KS_AUS.Z exakt - ;; auf endpunkt-ref.Z landet (garantiert die gewuenschte DeltaH). + ;; Die Z-Hoehe wird an KS_EIN des ES-Elements auf die TATSAECHLICH + ;; durch die Kette (Geraden/Boegen mit grade) aufgebaute Hoehe gesetzt + ;; (caddr sep-endpunkt) - NICHT auf endpunkt-ref.Z (die Z-Koordinate + ;; des zweiten Mausklicks). endpunkt-ref dient nur zur deltaH-Schaetzung + ;; fuer die Winkelberechnung (gf-winkel-berechnen); klickt der Nutzer + ;; beide Punkte auf derselben Hoehe (z.B. in einer 2D-Draufsicht ohne + ;; 3D-Objektfang), landete das ES-Element bisher trotz korrekt + ;; geneigter Kette wieder auf Starthoehe (realer Bug). (princ (ssg-textf "gf-status-ein-element-detail" - (list es-block (rtos (caddr endpunkt-ref) 2 1)))) + (list es-block (rtos (caddr sep-endpunkt) 2 1)))) (setq es-aus-frame (insert-block-mixed-to-ks es-block sep-frame - (caddr endpunkt-ref) "KS_EIN" "KS_AUS")) + (caddr sep-endpunkt) "KS_EIN" "KS_AUS")) (princ (ssg-textf "gf-status-z-hoehe-ks-aus" (list (rtos (caddr (car es-aus-frame)) 2 1)))) ;; --- GF_N-Block erstellen --- @@ -1226,14 +1232,18 @@ ) ;; delta-l-gf bereits vor der Zusammenfassung berechnet - ;; Block mit allen Attributen erstellen. Geruest fuer Einzelmodul/ - ;; Geruestoption sind in diesem Linienzug-Ablauf (Modus 3, keine DCL- - ;; Eingabe) nicht abfragbar - bleiben auf Schema-Default. + ;; Block mit allen Attributen erstellen. HOEHE_BIS_mm kommt aus der + ;; TATSAECHLICH gebauten Endhoehe (es-aus-frame), nicht aus der + ;; geklickten endpunkt-ref.Z - sonst wiche das Attribut von der + ;; echten Geometrie ab (derselbe Bug wie bei der ES-Platzierung oben). + ;; Geruest fuer Einzelmodul/Geruestoption sind in diesem Linienzug- + ;; Ablauf (Modus 3, keine DCL-Eingabe) nicht abfragbar - bleiben auf + ;; Schema-Default. (setq gf-lz-insert (gf-block-erstellen "gruppe" as-seite gf-nummer (caddr startpunkt) - (caddr endpunkt-ref) + (caddr (car es-aus-frame)) deltaH delta-l-gf L-gf-str @@ -1403,8 +1413,12 @@ (* (sin rad-h-es)(cos rad-v-es)) (- (sin rad-v-es)))) (setq sep-frame (make-frame-from-dir sep-endpunkt xu-exit)) + ;; Z-Ziel = tatsaechlich durch die Kette aufgebaute Hoehe (caddr + ;; sep-endpunkt), NICHT die gespeicherte Soll-Endhoehe end-z - identischer + ;; Fix wie in gf-linienzug-modus (end-z diente nur zur deltaH-Schaetzung + ;; fuer die Winkelberechnung oben). (setq es-aus-frame - (insert-block-mixed-to-ks es-block sep-frame end-z "KS_EIN" "KS_AUS")) + (insert-block-mixed-to-ks es-block sep-frame (caddr sep-endpunkt) "KS_EIN" "KS_AUS")) ;; Echter Endpunkt (fuer DELTA_L-Attribut/Label) erst jetzt aus der ;; gebauten Geometrie bekannt - KS_AUS des ES-Elements. From 1ace0a9a6dec1c91cc34710718bc6fd826cdc97f Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 13:34:49 +0200 Subject: [PATCH 37/38] [FIX] GEFAELLESTRECKE_LINIENZUG: ES-Element hatte Rest-Hoehenversatz (~65mm) nach dem vorigen Fix Der vorige Fix (80e5e62) nutzte insert-block-mixed-to-ks mit z-ref="KS_AUS" (sep-endpunkt als Ziel-Z) - das zwingt aber den BLOCKAUSGANG des ES-Elements auf diese Hoehe, nicht den Blockeingang, an dem die Kette tatsaechlich anschliesst. Der ganze Block wurde dadurch zusaetzlich um seine eigene KS_EIN<->KS_AUS-Innenhoehe nach oben verschoben. Modus 1/2 (gefaellestrecke-einfuegen) macht das bereits richtig: dort haengt das EIN-Element ueber reines insert-block-ks-to-ks (keine erzwungene Ziel-Z) an den Ketten-Pfad, die Endhoehe ergibt sich danach von selbst aus KS_AUS. GEFAELLESTRECKE_LINIENZUG (Modus 3) auf dasselbe Muster umgestellt - sowohl im normalen Bau (gf-linienzug-modus) als auch im Doppelklick-Rebuild (gf-linienzug-rebuild). Manuell in BricsCAD verifiziert: Hoehenversatz jetzt korrekt, kein Rest-Sprung mehr. Co-Authored-By: Claude Sonnet 5 --- Lisp/Gefaellestrecke.lsp | 35 ++++++++++++++++------------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/Lisp/Gefaellestrecke.lsp b/Lisp/Gefaellestrecke.lsp index afa655f..c03d27e 100644 --- a/Lisp/Gefaellestrecke.lsp +++ b/Lisp/Gefaellestrecke.lsp @@ -1178,21 +1178,20 @@ (- (sin rad-v-es)))) (setq sep-frame (make-frame-from-dir sep-endpunkt xu-exit)) - ;; EIN-Element: KS_EIN bleibt in X/Y auf dem Ketten-Pfad (sep-frame), - ;; seine eigene Achse verlaeuft damit trivial durch diesen Punkt. - ;; Die Z-Hoehe wird an KS_EIN des ES-Elements auf die TATSAECHLICH - ;; durch die Kette (Geraden/Boegen mit grade) aufgebaute Hoehe gesetzt - ;; (caddr sep-endpunkt) - NICHT auf endpunkt-ref.Z (die Z-Koordinate - ;; des zweiten Mausklicks). endpunkt-ref dient nur zur deltaH-Schaetzung - ;; fuer die Winkelberechnung (gf-winkel-berechnen); klickt der Nutzer - ;; beide Punkte auf derselben Hoehe (z.B. in einer 2D-Draufsicht ohne - ;; 3D-Objektfang), landete das ES-Element bisher trotz korrekt - ;; geneigter Kette wieder auf Starthoehe (realer Bug). + ;; EIN-Element: reine KS-zu-KS-Verkettung (wie bei Modus 1/2 in + ;; gefaellestrecke-einfuegen) statt insert-block-mixed-to-ks mit + ;; erzwungener Ziel-Z. sep-frame richtet KS_EIN des ES-Elements exakt + ;; am Ketten-Pfad (Position UND Neigung) aus; die Endhoehe ergibt sich + ;; danach von selbst aus KS_AUS, es wird nichts nachtraeglich + ;; verschoben. Zwei vorherige Versuche waren beide falsch: endpunkt-ref + ;; (Mausklick-Z, meist = Starthoehe) UND z-ref="KS_AUS" bei + ;; insert-block-mixed-to-ks (zwang den BLOCKAUSGANG statt -eingang auf + ;; die Zielhoehe, Rest-Versatz = Blockinnenhoehe KS_EIN<->KS_AUS, + ;; ~65mm). endpunkt-ref/der zweite Mausklick dient weiterhin nur zur + ;; groben deltaH-Schaetzung fuer den Winkel-Vorschlag im Dialog. + (setq es-aus-frame (insert-block-ks-to-ks es-block sep-frame)) (princ (ssg-textf "gf-status-ein-element-detail" (list es-block (rtos (caddr sep-endpunkt) 2 1)))) - (setq es-aus-frame - (insert-block-mixed-to-ks es-block sep-frame - (caddr sep-endpunkt) "KS_EIN" "KS_AUS")) (princ (ssg-textf "gf-status-z-hoehe-ks-aus" (list (rtos (caddr (car es-aus-frame)) 2 1)))) ;; --- GF_N-Block erstellen --- @@ -1413,12 +1412,10 @@ (* (sin rad-h-es)(cos rad-v-es)) (- (sin rad-v-es)))) (setq sep-frame (make-frame-from-dir sep-endpunkt xu-exit)) - ;; Z-Ziel = tatsaechlich durch die Kette aufgebaute Hoehe (caddr - ;; sep-endpunkt), NICHT die gespeicherte Soll-Endhoehe end-z - identischer - ;; Fix wie in gf-linienzug-modus (end-z diente nur zur deltaH-Schaetzung - ;; fuer die Winkelberechnung oben). - (setq es-aus-frame - (insert-block-mixed-to-ks es-block sep-frame (caddr sep-endpunkt) "KS_EIN" "KS_AUS")) + ;; Reine KS-zu-KS-Verkettung wie in gf-linienzug-modus (siehe dortiger + ;; Kommentar) - end-z (gespeicherte Soll-Endhoehe) wird nur zur + ;; deltaH-Schaetzung fuer die Winkelberechnung oben gebraucht, nicht hier. + (setq es-aus-frame (insert-block-ks-to-ks es-block sep-frame)) ;; Echter Endpunkt (fuer DELTA_L-Attribut/Label) erst jetzt aus der ;; gebauten Geometrie bekannt - KS_AUS des ES-Elements. From c353c34f2cc76c406f3e6e41c8467c14215562df Mon Sep 17 00:00:00 2001 From: Michael Stangl Date: Fri, 9 Oct 2026 14:14:35 +0200 Subject: [PATCH 38/38] [FIX] Eckrad-Export: Sivas-Merkmalnummern 3992/3993 statt Klartext-Keys Eckrad fuehrte "Geruest fuer Einzelmodul"/"Geruestoption fuer Einzelmodul" als beschreibende Klartext-Keys statt echter Merkmalnummern - details_mit_bezeichnung() loest aber nur numerische Keys gegen den Merkmalstamm auf, die Texte blieben im JSON unaufgeloest. Merkmalsstamm_in_Sivas.xlsx enthaelt beide Nummern bereits (dieselben wie bei Kreisel), jetzt in cfg/sivas.cfg uebernommen. Co-Authored-By: Claude Sonnet 5 --- cfg/sivas.cfg | 16 ++++++++-------- lib/export_sivas.py | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/cfg/sivas.cfg b/cfg/sivas.cfg index d3b1aa8..8a19a35 100644 --- a/cfg/sivas.cfg +++ b/cfg/sivas.cfg @@ -64,14 +64,14 @@ # Code (bedingte Umbenennung bzw. Umrechnung mm->m). [eckrad] -# Bewusst (noch) beschreibende Klartext-Keys statt Merkmalnummern (kein -# bekanntes Sivas-Merkmal fuer Eckrad-Geruest hinterlegt) - details_mit_ -# bezeichnung() in export_sivas.py laesst nicht-numerische Keys unveraendert. -# "ist_eins" liefert ein ECHTES bool (True/False), NICHT "Ja"/"Nein" wie -# ja_nein bei Kreisel/Gefaellestrecke - json.dumps schreibt dann true/false -# ohne Anfuehrungszeichen (bisheriges Verhalten von build_eckrad_details). -Geruest fuer Einzelmodul= GERUEST_EINZELMODUL : 0 | ist_eins -Geruestoption fuer Einzelmodul= GERUEST_TYP : Schoenenberger Geruest +# Dieselben Sivas-Merkmalnummern wie bei Kreisel (siehe oben), aus +# Merkmalsstamm_in_Sivas.xlsx: 3992 "Geruest fuer Einzelmodul", 3993 +# "Geruestoption fuer Einzelmodul". "ist_eins" liefert ein ECHTES bool +# (True/False), NICHT "Ja"/"Nein" wie ja_nein bei Kreisel/Gefaellestrecke - +# json.dumps schreibt dann true/false ohne Anfuehrungszeichen (bisheriges +# Verhalten von build_eckrad_details). +3992= GERUEST_EINZELMODUL : 0 | ist_eins +3993= GERUEST_TYP : Schoenenberger Geruest | geruest_typ_anzeige [geruest] Farbe= FARBE diff --git a/lib/export_sivas.py b/lib/export_sivas.py index ccb3ead..e62012f 100644 --- a/lib/export_sivas.py +++ b/lib/export_sivas.py @@ -907,9 +907,9 @@ def format_csv_line(item, details=None): def details_mit_bezeichnung(details, merkmalstamm): """Kopie von details, bei der jeder Merkmalnummer-Key durch seine Klartext-Bezeichnung aus dem Merkmalstamm ersetzt wird (Wert bleibt - unveraendert). Keys, die keine reine Zahl sind (aktuell nur beim - Eckrad, siehe build_eckrad_details - dort noch beschreibende - Klartext-Keys statt Merkmalnummern), bleiben unveraendert.""" + unveraendert). Keys, die keine reine Zahl sind, bleiben unveraendert + (aktuell kein Normalfall mehr - alle Sektionen in cfg/sivas.cfg nutzen + echte Merkmalnummern).""" neu = {} for key, value in details.items(): if key.isdigit():