diff --git a/Lisp/ssg_core.lsp b/Lisp/ssg_core.lsp index a2792b0..63af5d1 100644 --- a/Lisp/ssg_core.lsp +++ b/Lisp/ssg_core.lsp @@ -352,7 +352,7 @@ (cons 2 (car def)) '(70 . 1) )) - (setq ypos (- ypos (* text-height 2.0))) + (setq ypos (- ypos (* text-height (ssg-cfg-or "infrastruktur" "attdef_y_spacing_factor" 2.0)))) ) ) @@ -501,5 +501,219 @@ ) +;; ------------------------------------------------------------ +;; KONFIGURATION AUS JSON LADEN +;; Liest data/json/component_defaults.json und stellt Werte +;; ueber (ssg-cfg "section" "key") bereit. +;; Struktur: {"section": {"key": wert, ...}, ...} +;; Ergebnis: *ssg-config* = (("section" ("key" . wert) ...) ...) +;; ------------------------------------------------------------ + +(setq *ssg-config* nil) + +;; Datei zeilenweise einlesen (wie omni:read-file-lines) +(defun ssg-read-file-lines (datei / f zeile ergebnis) + (setq f (open datei "r")) + (if (null f) + nil + (progn + (setq ergebnis nil) + (while (setq zeile (read-line f)) + (setq ergebnis (cons zeile ergebnis)) + ) + (close f) + (reverse ergebnis) + ) + ) +) + +;; Whitespace und Komma trimmen +(defun ssg-cfg-trim (s / len) + (setq s (vl-string-trim " \t\r\n" s)) + (setq len (strlen s)) + (if (and (> len 0) (= (substr s len 1) ",")) + (setq s (substr s 1 (1- len))) + ) + (vl-string-trim " \t\r\n" s) +) + +;; JSON-Wert parsen (String, Zahl, null, true, false, Array) +(defun ssg-cfg-parse-value (val-str / len) + (setq val-str (ssg-cfg-trim val-str)) + (cond + ((= val-str "null") nil) + ((= val-str "true") T) + ((= val-str "false") nil) + ;; String + ((= (substr val-str 1 1) "\"") + (setq len (strlen val-str)) + (if (and (> len 1) (= (substr val-str len 1) "\"")) + (substr val-str 2 (- len 2)) + val-str + ) + ) + ;; Array [...] -> Liste von Werten parsen + ((= (substr val-str 1 1) "[") + (ssg-cfg-parse-array val-str) + ) + ;; Zahl + (T + (if (vl-string-search "." val-str) + (atof val-str) + (atoi val-str) + ) + ) + ) +) + +;; Einfaches JSON-Array parsen: [1, 2, 3.5, "text"] +(defun ssg-cfg-parse-array (arr-str / inhalt teile ergebnis item) + (setq inhalt (ssg-cfg-trim arr-str)) + ;; Klammern entfernen + (setq inhalt (substr inhalt 2 (- (strlen inhalt) 2))) + ;; An Kommas aufteilen (einfach: kein verschachteltes Array) + (setq teile (ssg-cfg-split-comma inhalt)) + (setq ergebnis nil) + (foreach item teile + (setq ergebnis (cons (ssg-cfg-parse-value item) ergebnis)) + ) + (reverse ergebnis) +) + +;; String an Kommas aufteilen -> Liste von Strings +(defun ssg-cfg-split-comma (s / result current i ch) + (setq result nil current "" i 1) + (repeat (strlen s) + (setq ch (substr s i 1)) + (if (= ch ",") + (progn + (setq result (cons current result)) + (setq current "") + ) + (setq current (strcat current ch)) + ) + (setq i (1+ i)) + ) + (if (> (strlen (vl-string-trim " " current)) 0) + (setq result (cons current result)) + ) + (reverse result) +) + +;; Key-Value-Zeile parsen: "key": wert -> ("key" . wert) +(defun ssg-cfg-parse-kv (zeile / pos key rest pos2 val) + (setq zeile (ssg-cfg-trim zeile)) + (if (and (> (strlen zeile) 0) (= (substr zeile 1 1) "\"")) + (progn + (setq pos (vl-string-search "\"" zeile 1)) + (if pos + (progn + (setq key (substr zeile 2 (1- pos))) + (setq rest (substr zeile (+ pos 2))) + (setq pos2 (vl-string-search ":" rest)) + (if pos2 + (cons key (ssg-cfg-parse-value (substr rest (+ pos2 2)))) + ) + ) + ) + ) + ) +) + +;; Verschachteltes JSON-Objekt parsen (1 Ebene tief) +;; {"section": {"key": val, ...}, ...} +;; -> (("section" ("key" . val) ...) ...) +(defun ssg-cfg-parse-nested (zeilen / ergebnis section section-data + trimmed kv in-section in-inner) + (setq ergebnis nil + section nil + section-data nil + in-section nil + in-inner nil + ) + (foreach zeile zeilen + (setq trimmed (ssg-cfg-trim zeile)) + (cond + ;; Aeusseres { oder } ignorieren (Wurzel-Objekt) + ((and (not in-section) (= trimmed "{")) nil) + ((and (not in-section) (= trimmed "}")) nil) + + ;; Section-Start: "name": { + ((and (not in-inner) (vl-string-search ": {" trimmed)) + (setq kv (ssg-cfg-parse-kv + (substr trimmed 1 (vl-string-search ": {" trimmed)))) + ;; kv ist hier nur der Key-Teil, der Rest ist ": {" + ;; Einfacher: Key direkt extrahieren + (setq section (substr trimmed 2 + (1- (vl-string-search "\"" trimmed 1)))) + (setq section-data nil) + (setq in-section T in-inner T) + ) + + ;; Section-Ende: } + ((and in-inner (or (= trimmed "}") (= trimmed "},"))) + (if section + (setq ergebnis (cons (cons section (reverse section-data)) ergebnis)) + ) + (setq in-section nil in-inner nil section nil section-data nil) + ) + + ;; Key-Value innerhalb einer Section + (in-inner + (setq kv (ssg-cfg-parse-kv trimmed)) + (if kv (setq section-data (cons kv section-data))) + ) + ) + ) + (reverse ergebnis) +) + +;; Konfiguration laden +;; Sucht data/json/component_defaults.json ueber DXFM_DATA +(defun ssg-load-config ( / data-pfad cfg-datei zeilen) + (setq data-pfad (getenv "DXFM_DATA")) + (if (null data-pfad) + (princ "\n[CFG] WARNUNG: DXFM_DATA nicht gesetzt, Config nicht geladen.") + (progn + (setq cfg-datei (strcat data-pfad "/json/component_defaults.json")) + (if (not (findfile cfg-datei)) + (princ (strcat "\n[CFG] WARNUNG: " cfg-datei " nicht gefunden.")) + (progn + (setq zeilen (ssg-read-file-lines cfg-datei)) + (if zeilen + (progn + (setq *ssg-config* (ssg-cfg-parse-nested zeilen)) + (princ (strcat "\n[CFG] Config geladen: " + (itoa (length *ssg-config*)) " Sektionen.")) + ) + (princ (strcat "\n[CFG] WARNUNG: Leere Config-Datei: " cfg-datei)) + ) + ) + ) + ) + ) + (princ) +) + +;; Wert aus Config lesen: (ssg-cfg "section" "key") +;; Gibt den Wert oder nil zurueck. +(defun ssg-cfg (section key / sec-data) + (if *ssg-config* + (progn + (setq sec-data (cdr (assoc section *ssg-config*))) + (if sec-data + (cdr (assoc key sec-data)) + ) + ) + ) +) + +;; Wert mit Fallback: (ssg-cfg-or "section" "key" default) +(defun ssg-cfg-or (section key default / val) + (setq val (ssg-cfg section key)) + (if val val default) +) + + (prompt "\nssg_core.lsp geladen.") (princ) diff --git a/Lisp/ssg_load.lsp b/Lisp/ssg_load.lsp index ec45a59..2d3fba3 100644 --- a/Lisp/ssg_load.lsp +++ b/Lisp/ssg_load.lsp @@ -21,6 +21,7 @@ ) ) (load (strcat base-path "ssg_core.lsp") "ssg_core.lsp nicht gefunden") + (ssg-load-config) (load (strcat base-path "ssg_dialog.lsp") "ssg_dialog.lsp nicht gefunden") (load (strcat base-path "ssg_layer.lsp") "ssg_layer.lsp nicht gefunden") ;; KreiselInsert.lsp entfernt - ersetzt durch Python/PyRx (lib/elemente/kreisel.py, eckrad.py) diff --git a/data/json/component_defaults.json b/data/json/component_defaults.json new file mode 100644 index 0000000..d35a647 --- /dev/null +++ b/data/json/component_defaults.json @@ -0,0 +1,56 @@ +{ + "kreisel": { + "durchmesser": 800.0, + "pin_abstand": 100.0, + "default_laenge": 2300.0, + "default_hoehe": 2000.0, + "label_hoehe": 100.0, + "label_farbe": 7, + "label_abstand_oben": 0.0, + "color_linie_1": 5, + "color_linie_2": 1, + "color_pin": 3, + "toleranz_kollinear": 0.01, + "toleranz_winkel": 1.0, + "toleranz_min_distanz": 0.001 + }, + "eckrad": { + "default_hoehe": 2000.0 + }, + "omniflo": { + "text_height": 100.0, + "text_gap": 20.0, + "default_hoehe": "2000", + "default_drehung": "0", + "laengemax_ap60": 7000.0, + "laengemax_ap110": 6000.0, + "laengemax_apg110": 6000.0, + "default_gerade_laenge": "2000", + "bogen_winkel": [180, 90, 67.5, 45, 22.5], + "weichen_winkel_90": 90, + "weichen_winkel_45": 45, + "weichen_winkel_parallel": 0, + "weichen_winkel_koerper": 22.5 + }, + "vario": { + "staustrecke_basis": 1000, + "feste_horizontal": 1600, + "bogen_winkel": [3, 6, 9, 12, 15, 18, 21, 27, 33, 39, 45, 51], + "gefaelle_winkel": 3, + "separator_block_dx": 300, + "separator_block_dz": 0, + "station_block_dx": 499, + "station_block_dz": -26, + "skalierung_basis": 1000.0 + }, + "gefaelle": { + "default_delta_l": 5000.0, + "default_winkel": 3.0, + "separator_breite": 300.0 + }, + "infrastruktur": { + "attdef_y_spacing_factor": 2.0, + "dialog_preview_bg_color": -18, + "mm_pro_meter": 1000.0 + } +} \ No newline at end of file