Refectoring vom Kreisel
This commit is contained in:
+155
-46
@@ -19,6 +19,8 @@ from ezdxf import bbox
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import math
|
import math
|
||||||
import re
|
import re
|
||||||
|
from pydantic import BaseModel, Field, field_validator
|
||||||
|
from typing import Optional
|
||||||
from utils import check_environment_var, setup_logger
|
from utils import check_environment_var, setup_logger
|
||||||
|
|
||||||
# global_zaehler = 0
|
# global_zaehler = 0
|
||||||
@@ -67,6 +69,126 @@ def get_shape_cfg(teileart, cfg_path, logger=None):
|
|||||||
ATTR_TAG = "TeileId" # Attributtag im Block
|
ATTR_TAG = "TeileId" # Attributtag im Block
|
||||||
RADIUS = 400 # Radius der Kreiselkreise (mm)
|
RADIUS = 400 # Radius der Kreiselkreise (mm)
|
||||||
|
|
||||||
|
# --------------------------------------------------------- Pydantic Modelle
|
||||||
|
class Kreisel(BaseModel):
|
||||||
|
"""Pydantic-Modell für Kreisel-Komponenten."""
|
||||||
|
teileid: str
|
||||||
|
x: float = Field(description="X-Koordinate des Kreisel-Zentrums")
|
||||||
|
y: float = Field(description="Y-Koordinate des Kreisel-Zentrums")
|
||||||
|
hoehe: float = Field(description="Höhe in mm")
|
||||||
|
drehung: float = Field(default=0.0, description="Drehung/Winkel in Grad")
|
||||||
|
drehrichtung: Optional[str] = Field(default=None, description="Drehrichtung: UZS oder GUZS")
|
||||||
|
abstand: float = Field(default=20000.0, description="Abstand zwischen Kreiselachsen in mm")
|
||||||
|
kreiselart: Optional[str] = Field(default=None, description="Kreiselart, z.B. 'Pin'")
|
||||||
|
anzahl_scanner: float = Field(default=0.0, description="Anzahl der Scanner")
|
||||||
|
anzahl_separatoren: float = Field(default=0.0, description="Anzahl der Separatoren")
|
||||||
|
|
||||||
|
@field_validator('abstand')
|
||||||
|
@classmethod
|
||||||
|
def validate_abstand(cls, v):
|
||||||
|
"""Konvertiert Abstand von Meter zu mm, falls nötig."""
|
||||||
|
if isinstance(v, str):
|
||||||
|
v = v.replace(",", ".")
|
||||||
|
try:
|
||||||
|
v = float(v) * 1000 # Meter → mm
|
||||||
|
except ValueError:
|
||||||
|
v = 10000.0 # Fallback 10 m
|
||||||
|
return v
|
||||||
|
|
||||||
|
@field_validator('hoehe')
|
||||||
|
@classmethod
|
||||||
|
def validate_hoehe(cls, v):
|
||||||
|
"""Konvertiert Höhe von Meter zu mm, falls nötig."""
|
||||||
|
if isinstance(v, str):
|
||||||
|
v = v.replace(",", ".")
|
||||||
|
try:
|
||||||
|
v = float(v) * 1000 # Meter → mm
|
||||||
|
except ValueError:
|
||||||
|
v = 0.0
|
||||||
|
return v
|
||||||
|
|
||||||
|
@property
|
||||||
|
def halbabstand(self) -> float:
|
||||||
|
"""Halbabstand zwischen den beiden Blöcken."""
|
||||||
|
return self.abstand / 2
|
||||||
|
|
||||||
|
@property
|
||||||
|
def winkel_rad(self) -> float:
|
||||||
|
"""Winkel in Radianten für Berechnungen."""
|
||||||
|
if self.drehung == 270 or self.drehung == 90:
|
||||||
|
return math.radians(self.drehung)
|
||||||
|
else:
|
||||||
|
return math.radians(self.drehung - 180)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def richtung_rad(self) -> float:
|
||||||
|
"""Richtung in Radianten (für am_kreisel_direct_verbunden)."""
|
||||||
|
# Wird aus drehung abgeleitet oder separat gesetzt
|
||||||
|
return math.radians(self.drehung)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pos1(self) -> tuple[float, float, float]:
|
||||||
|
"""Position des ersten Blocks (x, y, z)."""
|
||||||
|
dx = self.halbabstand * math.cos(self.winkel_rad)
|
||||||
|
dy = self.halbabstand * math.sin(self.winkel_rad)
|
||||||
|
return (self.x - dx, self.y - dy, self.hoehe)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def pos2(self) -> tuple[float, float, float]:
|
||||||
|
"""Position des zweiten Blocks (x, y, z)."""
|
||||||
|
dx = self.halbabstand * math.cos(self.winkel_rad)
|
||||||
|
dy = self.halbabstand * math.sin(self.winkel_rad)
|
||||||
|
return (self.x + dx, self.y + dy, self.hoehe)
|
||||||
|
return (self.x + dx, self.y + dy, self.hoehe)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def z(self) -> float:
|
||||||
|
"""Z-Koordinate (gleich der Höhe)."""
|
||||||
|
return self.hoehe
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Kreisel':
|
||||||
|
"""Erstellt ein Kreisel-Objekt aus einem merkmale-Dictionary."""
|
||||||
|
hoehe_m = merkmale.get("Höhe in m", "0").replace(",", ".")
|
||||||
|
try:
|
||||||
|
hoehe = float(hoehe_m) * 1000
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
hoehe = 0.0
|
||||||
|
|
||||||
|
abstand_m = merkmale.get("Abstand (Kreiselachse A - Kreiselachse) in Meter", "20").replace(",", ".")
|
||||||
|
try:
|
||||||
|
abstand = float(abstand_m) * 1000
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
abstand = 10000.0
|
||||||
|
|
||||||
|
try:
|
||||||
|
drehung = float(merkmale.get("Drehung", "0"))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
drehung = 0.0
|
||||||
|
|
||||||
|
try:
|
||||||
|
anzahl_scanner = float(merkmale.get("Anzahl der Scanner", "0"))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
anzahl_scanner = 0.0
|
||||||
|
|
||||||
|
try:
|
||||||
|
anzahl_separatoren = float(merkmale.get("Anzahl der Separatoren", "0"))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
anzahl_separatoren = 0.0
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
teileid=teileid,
|
||||||
|
x=x,
|
||||||
|
y=y,
|
||||||
|
hoehe=hoehe,
|
||||||
|
drehung=drehung,
|
||||||
|
drehrichtung=merkmale.get("Drehrichtung"),
|
||||||
|
abstand=abstand,
|
||||||
|
kreiselart=merkmale.get("Kreiselart"),
|
||||||
|
anzahl_scanner=anzahl_scanner,
|
||||||
|
anzahl_separatoren=anzahl_separatoren
|
||||||
|
)
|
||||||
|
|
||||||
# --------------------------------------------------------- Hilfsfunktionen
|
# --------------------------------------------------------- Hilfsfunktionen
|
||||||
def extract_coords(planquadrat: str) -> tuple[float, float]:
|
def extract_coords(planquadrat: str) -> tuple[float, float]:
|
||||||
"""Extrahiert X/Y Koordinaten aus PlanquadratString."""
|
"""Extrahiert X/Y Koordinaten aus PlanquadratString."""
|
||||||
@@ -213,57 +335,39 @@ def handle_ils_2_0_kreisel_mit_pin(msp, teileid, merkmale, x, y, doc, lib_doc, v
|
|||||||
handle_ils_2_0_kreisel(msp, teileid, merkmale, x, y, doc, lib_doc, verbose, symbols,strecken_nachbarn,config,config_allgemein)
|
handle_ils_2_0_kreisel(msp, teileid, merkmale, x, y, doc, lib_doc, verbose, symbols,strecken_nachbarn,config,config_allgemein)
|
||||||
|
|
||||||
def handle_ils_2_0_kreisel(msp, teileid, merkmale, x, y, doc, lib_doc, verbose, symbols,strecken_nachbarn,config,config_allgemein):
|
def handle_ils_2_0_kreisel(msp, teileid, merkmale, x, y, doc, lib_doc, verbose, symbols,strecken_nachbarn,config,config_allgemein):
|
||||||
scanner = float(merkmale.get("Anzahl der Scanner"))
|
# Erstelle Kreisel-Objekt aus merkmale
|
||||||
separatoren = float(merkmale.get("Anzahl der Separatoren"))
|
kreisel = Kreisel.from_merkmale(teileid, x, y, merkmale)
|
||||||
|
|
||||||
block_scanner = "SCAN"
|
block_scanner = "SCAN"
|
||||||
block_separatoren = "S-LP"
|
block_separatoren = "S-LP"
|
||||||
scanner_x = x
|
scanner_x = kreisel.x
|
||||||
scanner_y = y
|
scanner_y = kreisel.y
|
||||||
separatoren_x = x
|
separatoren_x = kreisel.x
|
||||||
separatoren_y = y + 160
|
separatoren_y = kreisel.y + 160
|
||||||
import_block(block_scanner,lib_doc,doc)
|
import_block(block_scanner,lib_doc,doc)
|
||||||
import_block(block_separatoren,lib_doc,doc)
|
import_block(block_separatoren,lib_doc,doc)
|
||||||
i = 0
|
i = 0
|
||||||
while i < scanner:
|
while i < kreisel.anzahl_scanner:
|
||||||
msp.add_blockref(block_scanner, (scanner_x,scanner_y,float(merkmale.get("Höhe in m"))* 1000))
|
msp.add_blockref(block_scanner, (scanner_x,scanner_y, kreisel.hoehe))
|
||||||
scanner_x = scanner_x + 300
|
scanner_x = scanner_x + 300
|
||||||
i = i+1
|
i = i+1
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
while i < separatoren:
|
while i < kreisel.anzahl_separatoren:
|
||||||
msp.add_blockref(block_separatoren, (separatoren_x,separatoren_y,float(merkmale.get("Höhe in m"))* 1000))
|
msp.add_blockref(block_separatoren, (separatoren_x,separatoren_y, kreisel.hoehe))
|
||||||
separatoren_x = separatoren_x + 300
|
separatoren_x = separatoren_x + 300
|
||||||
i = i +1
|
i = i +1
|
||||||
abstand_m = merkmale.get(
|
|
||||||
"Abstand (Kreiselachse A - Kreiselachse) in Meter", "20"
|
|
||||||
).replace(",", ".")
|
|
||||||
try:
|
|
||||||
abstand = float(abstand_m) * 1000 # Meter → mm
|
|
||||||
except ValueError:
|
|
||||||
abstand = 10000 # Fallback 10 m
|
|
||||||
|
|
||||||
# Drehung (Winkel in Grad, Standard 0) aus Merkmale
|
|
||||||
try:
|
|
||||||
winkel = float(merkmale.get("Drehung"))
|
|
||||||
except (ValueError, TypeError):
|
|
||||||
winkel = 0.0
|
|
||||||
if winkel== 270 or winkel == 90:
|
|
||||||
winkel_rad = math.radians(winkel)
|
|
||||||
else:
|
|
||||||
winkel_rad = math.radians(winkel -180)
|
|
||||||
# Die Koordinaten (x, y) sind die Mitte zwischen den beiden Blöcken (bereits transformiert)
|
# Die Koordinaten (x, y) sind die Mitte zwischen den beiden Blöcken (bereits transformiert)
|
||||||
halbabstand = abstand / 2
|
pos1 = kreisel.pos1
|
||||||
dx = halbabstand * math.cos(winkel_rad)
|
pos2 = kreisel.pos2
|
||||||
dy = halbabstand * math.sin(winkel_rad)
|
|
||||||
pos1 = (x - dx, y - dy,float(merkmale.get("Höhe in m"))* 1000)
|
|
||||||
pos2 = (x + dx, y + dy, float(merkmale.get("Höhe in m"))* 1000)
|
|
||||||
positions = [pos1, pos2]
|
positions = [pos1, pos2]
|
||||||
for i, sym in enumerate(symbols):
|
for i, sym in enumerate(symbols):
|
||||||
blockname = sym["name"]
|
blockname = sym["name"]
|
||||||
offset = sym["offset"]
|
offset = sym["offset"]
|
||||||
rotation = sym["rotation"]
|
rotation = sym["rotation"]
|
||||||
if i < len(positions):
|
if i < len(positions):
|
||||||
pos = (positions[i][0] + offset[0], positions[i][1] + offset[1],float(merkmale.get("Höhe in m"))*1000)
|
pos = (positions[i][0] + offset[0], positions[i][1] + offset[1], kreisel.hoehe)
|
||||||
import_block(blockname, lib_doc, doc)
|
import_block(blockname, lib_doc, doc)
|
||||||
blockref_layer = get_layer(doc, lib_doc, blockname)
|
blockref_layer = get_layer(doc, lib_doc, blockname)
|
||||||
bref = msp.add_blockref(blockname, pos, dxfattribs={"layer" : blockref_layer})
|
bref = msp.add_blockref(blockname, pos, dxfattribs={"layer" : blockref_layer})
|
||||||
@@ -273,12 +377,12 @@ def handle_ils_2_0_kreisel(msp, teileid, merkmale, x, y, doc, lib_doc, verbose,
|
|||||||
f"({pos[0]:.1f}, {pos[1]:.1f}), rot={rotation}")
|
f"({pos[0]:.1f}, {pos[1]:.1f}), rot={rotation}")
|
||||||
# Linien zeichnen
|
# Linien zeichnen
|
||||||
import_block("Pinbereich",lib_doc,doc)
|
import_block("Pinbereich",lib_doc,doc)
|
||||||
draw_kreisel_lines(msp, pos1, pos2,merkmale)
|
draw_kreisel_lines(msp, pos1, pos2, kreisel)
|
||||||
draw_kreisel_drehrichtung_markierung(msp, pos1, pos2, merkmale, lib_doc, doc, verbose)
|
draw_kreisel_drehrichtung_markierung(msp, pos1, pos2, kreisel, lib_doc, doc, verbose)
|
||||||
|
|
||||||
def draw_kreisel_lines(msp, pos1, pos2,merkmale):
|
def draw_kreisel_lines(msp, pos1, pos2, kreisel: Kreisel):
|
||||||
"""Zeichnet tangentiale Linien zwischen zwei Kreiselblöcken, unabhängig vom Winkel."""
|
"""Zeichnet tangentiale Linien zwischen zwei Kreiselblöcken, unabhängig vom Winkel."""
|
||||||
rotation = float(merkmale.get("Drehung"))
|
rotation = kreisel.drehung
|
||||||
x1, y1, z1 = pos1
|
x1, y1, z1 = pos1
|
||||||
x2, y2, z1 = pos2
|
x2, y2, z1 = pos2
|
||||||
# Verbindungsvektor
|
# Verbindungsvektor
|
||||||
@@ -297,7 +401,7 @@ def draw_kreisel_lines(msp, pos1, pos2,merkmale):
|
|||||||
p1b = (x1 - nx, y1 - ny,z1)
|
p1b = (x1 - nx, y1 - ny,z1)
|
||||||
p2a = (x2 + nx, y2 + ny,z1)
|
p2a = (x2 + nx, y2 + ny,z1)
|
||||||
p2b = (x2 - nx, y2 - ny,z1)
|
p2b = (x2 - nx, y2 - ny,z1)
|
||||||
if merkmale.get("Kreiselart") == "Pin":
|
if kreisel.kreiselart == "Pin":
|
||||||
if rotation == 0.0:
|
if rotation == 0.0:
|
||||||
p1a2 = p1a[0] - RADIUS - 50, p1a[1] + 50, z1
|
p1a2 = p1a[0] - RADIUS - 50, p1a[1] + 50, z1
|
||||||
p1b2 = p1b[0] - RADIUS - 50, p1b[1] - 50, z1
|
p1b2 = p1b[0] - RADIUS - 50, p1b[1] - 50, z1
|
||||||
@@ -339,8 +443,8 @@ def draw_kreisel_lines(msp, pos1, pos2,merkmale):
|
|||||||
msp.add_line(p1a, p2a)
|
msp.add_line(p1a, p2a)
|
||||||
msp.add_line(p1b, p2b)
|
msp.add_line(p1b, p2b)
|
||||||
|
|
||||||
def draw_kreisel_drehrichtung_markierung(msp, pos1, pos2, merkmale, lib_doc, doc, verbose):
|
def draw_kreisel_drehrichtung_markierung(msp, pos1, pos2, kreisel: Kreisel, lib_doc, doc, verbose):
|
||||||
drehrichtung = merkmale.get("Drehrichtung", "").upper()
|
drehrichtung = (kreisel.drehrichtung or "").upper()
|
||||||
if drehrichtung not in ("UZS", "GUZS"):
|
if drehrichtung not in ("UZS", "GUZS"):
|
||||||
return
|
return
|
||||||
x1, y1,z1= pos1
|
x1, y1,z1= pos1
|
||||||
@@ -2585,13 +2689,18 @@ def get_rotations_of_strecken(csv_path:Path) -> dict:
|
|||||||
planquadrat = row["Planquadrat"]
|
planquadrat = row["Planquadrat"]
|
||||||
x, y = extract_coords(planquadrat)
|
x, y = extract_coords(planquadrat)
|
||||||
merkmale = parse_merkmale(row.get("Merkmale", ""))
|
merkmale = parse_merkmale(row.get("Merkmale", ""))
|
||||||
drehung = merkmale.get("Drehrichtung")
|
# Erstelle Kreisel-Objekt
|
||||||
rotation = merkmale.get("Drehung")
|
kreisel_obj = Kreisel.from_merkmale(Id, x, y, merkmale)
|
||||||
hight = float(merkmale.get("Höhe in m")) *1000
|
# Für Kompatibilität auch als Dict speichern (für bestehende Code-Stellen)
|
||||||
abstand_m = merkmale.get(
|
kreisel.append({
|
||||||
"Abstand (Kreiselachse A - Kreiselachse) in Meter", "20"
|
"Id": Id,
|
||||||
).replace(",", ".")
|
"drehung": kreisel_obj.drehrichtung,
|
||||||
kreisel.append({"Id":Id, "drehung":drehung, "höhe":hight,"x": x, "y": y, "rotation": rotation,"abstand":abstand_m})
|
"höhe": kreisel_obj.hoehe,
|
||||||
|
"x": kreisel_obj.x,
|
||||||
|
"y": kreisel_obj.y,
|
||||||
|
"rotation": kreisel_obj.drehung,
|
||||||
|
"abstand": str(kreisel_obj.abstand / 1000) # Zurück in Meter als String
|
||||||
|
})
|
||||||
if bezeichner =="ILS 2.0 VarioFoerderer":
|
if bezeichner =="ILS 2.0 VarioFoerderer":
|
||||||
Id = row["TeileId"].strip()
|
Id = row["TeileId"].strip()
|
||||||
NachbarIds = row["NachbarIds"].strip()
|
NachbarIds = row["NachbarIds"].strip()
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
ezdxf==1.4.1
|
ezdxf==1.4.1
|
||||||
svg.path==7.0
|
svg.path==7.0
|
||||||
|
pydantic>=2.0.0
|
||||||
Reference in New Issue
Block a user