alles neu mit black formatiert. handler_context.py impl. um weniger Übergabeparameter zu haben

This commit is contained in:
2026-01-27 16:09:52 +01:00
parent 4d09aee02b
commit 19282888ee
16 changed files with 4228 additions and 1682 deletions
+11 -6
View File
@@ -1,6 +1,6 @@
from pydantic import BaseModel, Field, field_validator
class Angetriebene_Kurve(BaseModel):
teileid: str
x: float
@@ -9,7 +9,9 @@ class Angetriebene_Kurve(BaseModel):
hoehe0: float = Field(default=0.0, description="Hoehe Anfang der Kurve")
hoehe1: float = Field(default=0.0, description="Hoehe Ende der Kurve")
kurvenrichtung: str = Field(description="Kurvenrichtung der Kurve")
antriebNebenStrecke: str =Field(description="wo die Angetriebene Strecke ist abhängig von der kurvenrichtung")
antriebNebenStrecke: str = Field(
description="wo die Angetriebene Strecke ist abhängig von der kurvenrichtung"
)
winkel: int = Field(description="Der Winkel der Kurve")
@property
@@ -19,11 +21,15 @@ class Angetriebene_Kurve(BaseModel):
elif self.antriebNebenStrecke == "Innen":
self.antriebNebenStrecke = "innen"
return self.antriebNebenStrecke
@property
def hight_zwischen(self):
return ((self.hoehe0 + self.hoehe1) /2)
return (self.hoehe0 + self.hoehe1) / 2
@classmethod
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Angetriebene_Kurve':
def from_merkmale(
cls, teileid: str, x: float, y: float, merkmale: dict
) -> "Angetriebene_Kurve":
hoehe0 = float(merkmale.get("Höhe Anfang")) * 1000
hoehe1 = float(merkmale.get("Höhe Ende")) * 1000
winkel = int(merkmale.get("Kurvenwinkel"))
@@ -43,6 +49,5 @@ class Angetriebene_Kurve(BaseModel):
hoehe1=hoehe1,
kurvenrichtung=kurvenrichtung,
antriebNebenStrecke=antriebNebenstrecke,
winkel = winkel
winkel=winkel,
)
+6 -8
View File
@@ -1,14 +1,18 @@
from pydantic import BaseModel, Field, field_validator
from typing import Optional
class Bt_element(BaseModel):
"""Das sind beide BTMT Elemente"""
teileid: str
drehung: Optional[float] = Field(default=0.0, description="Rotation des Elements")
hoehe: Optional[float] = Field(default=0.0, description="Hoehe des Elements")
@classmethod
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Bt_element':
def from_merkmale(
cls, teileid: str, x: float, y: float, merkmale: dict
) -> "Bt_element":
try:
hoehe = float(merkmale.get("Höhe in Meter"))
except Exception as e:
@@ -18,10 +22,4 @@ class Bt_element(BaseModel):
except Exception as e:
drehung = 0.0
return cls(
teileid = teileid,
x = x,
y = y,
hoehe = hoehe,
drehung = drehung
)
return cls(teileid=teileid, x=x, y=y, hoehe=hoehe, drehung=drehung)
+17 -11
View File
@@ -1,15 +1,22 @@
from pydantic import BaseModel, Field, field_validator
from typing import Optional
import block_methoden
RADIUS = 400
class Eckrad(BaseModel):
teileid: str
drehung: Optional[float] = Field(default=0.0, description="Rotation des Elements")
hoehe: Optional[float] = Field(default=0.0, description="Hoehe des Elements")
drehrichtung: Optional [str] =Field(default=None,description="Richtung des Eckrads")
drehrichtung: Optional[str] = Field(
default=None, description="Richtung des Eckrads"
)
@classmethod
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Eckrad':
def from_merkmale(
cls, teileid: str, x: float, y: float, merkmale: dict
) -> "Eckrad":
try:
hoehe = float(merkmale.get("Höhe in Meter")) * 1000
except Exception as e:
@@ -22,13 +29,8 @@ class Eckrad(BaseModel):
drehrichtung = merkmale.get("Drehrichtung")
except Exception as e:
drehrichtung = None
return cls(
teileid = teileid,
x = x,
y = y,
hoehe = hoehe,
drehrichtung = drehrichtung
)
return cls(teileid=teileid, x=x, y=y, hoehe=hoehe, drehrichtung=drehrichtung)
def erstellung_eckrad_richtung(merkmale, doc, lib_doc):
block_methoden.import_block("AN8", lib_doc, doc)
block_methoden.import_block("Richtungspfeil", lib_doc, doc)
@@ -42,7 +44,11 @@ class Eckrad(BaseModel):
block_rechts.add_blockref("AN8", (0, 0, 0))
block_links.add_blockref("AN8", (0, 0, 0))
block_rechts.add_blockref("Richtungspfeil", (0 + 200, 0 + RADIUS, 0))
block_rechts.add_blockref("Richtungspfeil",(0-200,0- RADIUS,0),dxfattribs={"rotation": 180})
block_rechts.add_blockref(
"Richtungspfeil", (0 - 200, 0 - RADIUS, 0), dxfattribs={"rotation": 180}
)
block_links.add_blockref("Richtungspfeil", (0 + 200, 0 - RADIUS, 0))
block_links.add_blockref("Richtungspfeil",(0-200,0+ RADIUS,0),dxfattribs={"rotation": 180})
block_links.add_blockref(
"Richtungspfeil", (0 - 200, 0 + RADIUS, 0), dxfattribs={"rotation": 180}
)
return eckrad_rechts, eckrad_links, hight
+26 -26
View File
@@ -38,11 +38,11 @@ class Gefaellestrecke(BaseModel):
anzahl_scanner = int(merkmale.get("Anzahl der Scanner")),
anzahl_separatoren = int(merkmale.get("Anzahl der Separatoren"))
)
def erstehlung_von_gefalle_ohne_aussnahmen(msp, x, y, upper_hoehe_gefaehlle, lower_hoehe_gefaehlle, halbe_laenge, winkel):
def erstehlung_von_gefalle_ohne_aussnahmen(msp, x, y, upper_hoehe_gefaelle, lower_hoehe_gefaelle, halbe_laenge, winkel):
dx = halbe_laenge *math.sin(winkel * -1)
dy = halbe_laenge * math.cos(winkel)
start = x +dx, y + dy,upper_hoehe_gefaehlle
ende = x -dx, y - dy,lower_hoehe_gefaehlle
start = x +dx, y + dy,upper_hoehe_gefaelle
ende = x -dx, y - dy,lower_hoehe_gefaelle
line =msp.add_line(start,ende)
line.dxf.layer = "6-SP"
def rotation_mit_zwei_verbunden(gefaellestrecke_nachbarn,richtung2, richtung0, am_kreisel, kreisel_verbunden, hight_position):
@@ -137,7 +137,7 @@ class Gefaellestrecke(BaseModel):
elif gefaelle == "rechts" :
rotation = 270
return rotation,drehung0,drehung1,hight_position
def ein_motor_oder_eine_umlenk(x, y,start,ende, doc, lib_doc, hoehe_gefaehlle, block_Vario_Umlenkstation_500mm, block_Vario_Motorstation_500mm, blockname_motor_links, blockname_umlenk_links, hat_motor_0, hat_umlenk_0, tefkurve_0, block,umlenk_gerade,motor_gerade):
def ein_motor_oder_eine_umlenk(x, y,start,ende, doc, lib_doc, hoehe_gefaelle, block_Vario_Umlenkstation_500mm, block_Vario_Motorstation_500mm, blockname_motor_links, blockname_umlenk_links, hat_motor_0, hat_umlenk_0, tefkurve_0, block,umlenk_gerade,motor_gerade):
block_Vario_Bogen_auf = (f"Vario_Bogen_auf_3°")
block_Vario_Bogen_ab = (f"Vario_Bogen_ab_3°")
@@ -165,48 +165,48 @@ class Gefaellestrecke(BaseModel):
if hat_motor_0 == True:
if tefkurve_0 == "links":
if motor_gerade == False:
block.add_blockref(block_Vario_Bogen_ab_links,(start[0]-x,start[1]-Vario_Bogen_ab_Delta_SP_0[0]-y,start[2]- Vario_Bogen_ab_Delta_SP_0[2]-hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref(block_Vario_Bogen_ab_links,(start[0]-x,start[1]-Vario_Bogen_ab_Delta_SP_0[0]-y,start[2]- Vario_Bogen_ab_Delta_SP_0[2]-hoehe_gefaelle),dxfattribs={"rotation": 270})
start = [start[0],start[1]-Vario_Bogen_ab_Delta_SP_0[0]- Vario_Bogen_ab_Delta_SP_1[0],start[2]-Vario_Bogen_ab_Delta_SP_0[2]- Vario_Bogen_ab_Delta_SP_1[2]]
block.add_blockref(blockname_motor_links, (start[0]-x,start[1] - 250* math.cos(math.radians(3))-y,start[2] - 250* math.sin(math.radians(3))-hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref(blockname_motor_links, (start[0]-x,start[1] - 250* math.cos(math.radians(3))-y,start[2] - 250* math.sin(math.radians(3))-hoehe_gefaelle),dxfattribs={"rotation": 270})
start[1]= start[1] - 500* math.cos(math.radians(3))
start[2] = start[2] - 500* math.sin(math.radians(3))
else:
block.add_blockref("Vario_Motorstation_500mm_links", (start[0]-x,start[1] -250 -y,start[2] -hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref("Vario_Motorstation_500mm_links", (start[0]-x,start[1] -250 -y,start[2] -hoehe_gefaelle),dxfattribs={"rotation": 270})
start[1]= start[1] - 500
else:
if motor_gerade == False:
block.add_blockref(block_Vario_Bogen_ab,(start[0]-x,start[1]-Vario_Bogen_ab_Delta_SP_0[0]-y,start[2]- Vario_Bogen_ab_Delta_SP_0[2]-hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref(block_Vario_Bogen_ab,(start[0]-x,start[1]-Vario_Bogen_ab_Delta_SP_0[0]-y,start[2]- Vario_Bogen_ab_Delta_SP_0[2]-hoehe_gefaelle),dxfattribs={"rotation": 270})
start = [start[0],start[1]-Vario_Bogen_ab_Delta_SP_0[0]- Vario_Bogen_ab_Delta_SP_1[0],start[2]-Vario_Bogen_ab_Delta_SP_0[2]- Vario_Bogen_ab_Delta_SP_1[2]]
block.add_blockref(block_Vario_Motorstation_500mm, (start[0]-x,start[1] - 250* math.cos(math.radians(3))-y,start[2] - 250* math.sin(math.radians(3))-hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref(block_Vario_Motorstation_500mm, (start[0]-x,start[1] - 250* math.cos(math.radians(3))-y,start[2] - 250* math.sin(math.radians(3))-hoehe_gefaelle),dxfattribs={"rotation": 270})
start[1]= start[1] - 500* math.cos(math.radians(3))
start[2] = start[2] - 500* math.sin(math.radians(3))
else:
block.add_blockref("Vario_Motorstation_500mm", (start[0]-x,start[1]- 250 -y,start[2] -hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref("Vario_Motorstation_500mm", (start[0]-x,start[1]- 250 -y,start[2] -hoehe_gefaelle),dxfattribs={"rotation": 270})
start[1]= start[1] - 500
if hat_umlenk_0 == True:
if tefkurve_0 == "links":
if umlenk_gerade == False:
block.add_blockref(block_Vario_Bogen_auf,(ende[0]-x,ende[1]+Vario_Bogen_auf_Delta_SP_0[0]-y,ende[2] + Vario_Bogen_auf_Delta_SP_0[2]-hoehe_gefaehlle),dxfattribs={"rotation": 90})
block.add_blockref(block_Vario_Bogen_auf,(ende[0]-x,ende[1]+Vario_Bogen_auf_Delta_SP_0[0]-y,ende[2] + Vario_Bogen_auf_Delta_SP_0[2]-hoehe_gefaelle),dxfattribs={"rotation": 90})
ende = [ende[0],ende[1]+ Vario_Bogen_auf_Delta_SP_0[0]+ Vario_Bogen_auf_Delta_SP_1[0],ende[2]+Vario_Bogen_auf_Delta_SP_0[2]+ Vario_Bogen_auf_Delta_SP_1[2]]
block.add_blockref(blockname_umlenk_links, (ende[0]-x,ende[1] + 250* math.cos(math.radians(3))-y,ende[2] + 250* math.sin(math.radians(3))-hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref(blockname_umlenk_links, (ende[0]-x,ende[1] + 250* math.cos(math.radians(3))-y,ende[2] + 250* math.sin(math.radians(3))-hoehe_gefaelle),dxfattribs={"rotation": 270})
ende [1]= ende[1] + 500* math.cos(math.radians(3))
ende[2] = ende[2] + 500* math.sin(math.radians(3))
else:
block.add_blockref("Vario_Umlenkstation_500mm_links", (ende[0]-x,ende[1] + 250-y,ende[2] -hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref("Vario_Umlenkstation_500mm_links", (ende[0]-x,ende[1] + 250-y,ende[2] -hoehe_gefaelle),dxfattribs={"rotation": 270})
ende [1]= ende[1] + 500
else:
if umlenk_gerade == False:
block.add_blockref(block_Vario_Bogen_auf_links,(ende[0]-x,ende[1]+Vario_Bogen_auf_Delta_SP_0[0]-y,ende[2] + Vario_Bogen_auf_Delta_SP_0[2]-hoehe_gefaehlle),dxfattribs={"rotation": 90})
block.add_blockref(block_Vario_Bogen_auf_links,(ende[0]-x,ende[1]+Vario_Bogen_auf_Delta_SP_0[0]-y,ende[2] + Vario_Bogen_auf_Delta_SP_0[2]-hoehe_gefaelle),dxfattribs={"rotation": 90})
ende = [ende[0],ende[1]+ Vario_Bogen_auf_Delta_SP_0[0]+ Vario_Bogen_auf_Delta_SP_1[0],ende[2]+Vario_Bogen_auf_Delta_SP_0[2]+ Vario_Bogen_auf_Delta_SP_1[2]]
block.add_blockref(block_Vario_Umlenkstation_500mm, (ende[0]-x,ende[1] + 250* math.cos(math.radians(3))-y,ende[2] + 250* math.sin(math.radians(3))-hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref(block_Vario_Umlenkstation_500mm, (ende[0]-x,ende[1] + 250* math.cos(math.radians(3))-y,ende[2] + 250* math.sin(math.radians(3))-hoehe_gefaelle),dxfattribs={"rotation": 270})
ende [1]= ende[1] + 500* math.cos(math.radians(3))
ende[2] = ende[2] + 500* math.sin(math.radians(3))
else:
block.add_blockref("Vario_Umlenkstation_500mm", (ende[0]-x,ende[1] + 250-y,ende[2] -hoehe_gefaehlle),dxfattribs={"rotation": 270})
block.add_blockref("Vario_Umlenkstation_500mm", (ende[0]-x,ende[1] + 250-y,ende[2] -hoehe_gefaelle),dxfattribs={"rotation": 270})
ende [1]= ende[1] + 500
return start,ende
def hat_motor_umlenk_station (gefaelle_objekt, gefaellestrecke_nachbarn):
@@ -218,8 +218,8 @@ class Gefaellestrecke(BaseModel):
tefkurve_1 = None
umlenk_gerade = False
motor_gerade = False
upper_hoehe_gefaehlle = gefaelle_objekt.h1
lower_hoehe_gefaehlle = gefaelle_objekt.h0
upper_hoehe_gefaelle = gefaelle_objekt.h1
lower_hoehe_gefaelle = gefaelle_objekt.h0
rotation = gefaelle_objekt.drehung
x = gefaelle_objekt.x
y = gefaelle_objekt.y
@@ -238,13 +238,13 @@ class Gefaellestrecke(BaseModel):
else:
tefkurve_0 = "links"
if upper_hoehe_gefaehlle > lower_hoehe_gefaehlle:
if vario_hoehe_0 == upper_hoehe_gefaehlle or vario_hoehe_1 == upper_hoehe_gefaehlle:
if upper_hoehe_gefaelle > lower_hoehe_gefaelle:
if vario_hoehe_0 == upper_hoehe_gefaelle or vario_hoehe_1 == upper_hoehe_gefaelle:
hat_motor_0 = True
else:
hat_umlenk_0 = True
elif upper_hoehe_gefaehlle < lower_hoehe_gefaehlle:
if vario_hoehe_0 == lower_hoehe_gefaehlle or vario_hoehe_1 == lower_hoehe_gefaehlle:
elif upper_hoehe_gefaelle < lower_hoehe_gefaelle:
if vario_hoehe_0 == lower_hoehe_gefaelle or vario_hoehe_1 == lower_hoehe_gefaelle:
hat_motor_0 = True
else:
hat_umlenk_0 = True
@@ -270,13 +270,13 @@ class Gefaellestrecke(BaseModel):
tefkurve_1 = "rechts"
else:
tefkurve_1 = "links"
if upper_hoehe_gefaehlle > lower_hoehe_gefaehlle:
if vario_hoehe_0_1 == upper_hoehe_gefaehlle or vario_hoehe_1_1 == upper_hoehe_gefaehlle:
if upper_hoehe_gefaelle > lower_hoehe_gefaelle:
if vario_hoehe_0_1 == upper_hoehe_gefaelle or vario_hoehe_1_1 == upper_hoehe_gefaelle:
hat_motor_1 = True
else:
hat_umlenk_1 = True
elif upper_hoehe_gefaehlle < lower_hoehe_gefaehlle:
if vario_hoehe_0_1 == lower_hoehe_gefaehlle or vario_hoehe_1_1 == lower_hoehe_gefaehlle:
elif upper_hoehe_gefaelle < lower_hoehe_gefaelle:
if vario_hoehe_0_1 == lower_hoehe_gefaelle or vario_hoehe_1_1 == lower_hoehe_gefaelle:
hat_motor_1 = True
else:
hat_umlenk_1 = True
+75 -26
View File
@@ -1,4 +1,3 @@
from ezdxf.entities import Line
import math
from pydantic import BaseModel, Field, field_validator
@@ -10,20 +9,28 @@ import block_methoden
ATTR_TAG = "TeileId" # Attributtag im Block
RADIUS = 400 # Radius der Kreiselkreise (mm)
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'")
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')
@field_validator("abstand")
@classmethod
def validate_abstand(cls, v):
"""Konvertiert Abstand von Meter zu mm, falls nötig."""
@@ -35,7 +42,7 @@ class Kreisel(BaseModel):
v = 10000.0 # Fallback 10 m
return v
@field_validator('hoehe')
@field_validator("hoehe")
@classmethod
def validate_hoehe(cls, v):
"""Konvertiert Höhe von Meter zu mm, falls nötig."""
@@ -86,7 +93,9 @@ class Kreisel(BaseModel):
return self.hoehe
@classmethod
def from_merkmale(cls, teileid: str, x: float, y: float, merkmale: dict) -> 'Kreisel':
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:
@@ -94,7 +103,9 @@ class Kreisel(BaseModel):
except (ValueError, TypeError):
hoehe = 0.0
abstand_m = merkmale.get("Abstand (Kreiselachse A - Kreiselachse) in Meter", "20").replace(",", ".")
abstand_m = merkmale.get(
"Abstand (Kreiselachse A - Kreiselachse) in Meter", "20"
).replace(",", ".")
try:
abstand = float(abstand_m) * 1000
except (ValueError, TypeError):
@@ -125,7 +136,7 @@ class Kreisel(BaseModel):
abstand=abstand,
kreiselart=merkmale.get("Kreiselart"),
anzahl_scanner=anzahl_scanner,
anzahl_separatoren=anzahl_separatoren
anzahl_separatoren=anzahl_separatoren,
)
def draw_kreisel_lines(msp, pos1, pos2, kreisel):
@@ -155,8 +166,12 @@ class Kreisel(BaseModel):
p1b2 = p1b[0] - RADIUS - 50, p1b[1] - 50, z1
p2a2 = p2a[0] + RADIUS + 50, p2a[1] + 50, z1
p2b2 = p2b[0] + RADIUS + 50, p2b[1] - 50, z1
Line1 = Line.new(dxfattribs={"start": p1a2,"end": p2a2,"layer": "Pinbereich"})
Line2 = Line.new(dxfattribs={"start": p1b2,"end": p2b2,"layer": "Pinbereich"})
Line1 = Line.new(
dxfattribs={"start": p1a2, "end": p2a2, "layer": "Pinbereich"}
)
Line2 = Line.new(
dxfattribs={"start": p1b2, "end": p2b2, "layer": "Pinbereich"}
)
msp.add_entity(Line1)
msp.add_entity(Line2)
elif rotation == 180.0:
@@ -164,8 +179,12 @@ class Kreisel(BaseModel):
p1b2 = p1b[0] + RADIUS + 50, p1b[1] + 50, z1
p2a2 = p2a[0] - RADIUS - 50, p2a[1] - 50, z1
p2b2 = p2b[0] - RADIUS - 50, p2b[1] + 50, z1
Line1 = Line.new(dxfattribs={"start": p1a2,"end": p2a2,"layer": "Pinbereich"})
Line2 = Line.new(dxfattribs={"start": p1b2,"end": p2b2,"layer": "Pinbereich"})
Line1 = Line.new(
dxfattribs={"start": p1a2, "end": p2a2, "layer": "Pinbereich"}
)
Line2 = Line.new(
dxfattribs={"start": p1b2, "end": p2b2, "layer": "Pinbereich"}
)
msp.add_entity(Line1)
msp.add_entity(Line2)
elif rotation == 90.0:
@@ -173,8 +192,12 @@ class Kreisel(BaseModel):
p1b2 = p1b[0] - 50, p1b[1] - 50 + RADIUS, z1
p2a2 = p2a[0] + 50, p2a[1] + 50 - RADIUS, z1
p2b2 = p2b[0] - 50, p2b[1] + 50 - RADIUS, z1
Line1 = Line.new(dxfattribs={"start": p1a2,"end": p2a2,"layer": "Pinbereich"})
Line2 = Line.new(dxfattribs={"start": p1b2,"end": p2b2,"layer": "Pinbereich"})
Line1 = Line.new(
dxfattribs={"start": p1a2, "end": p2a2, "layer": "Pinbereich"}
)
Line2 = Line.new(
dxfattribs={"start": p1b2, "end": p2b2, "layer": "Pinbereich"}
)
msp.add_entity(Line1)
msp.add_entity(Line2)
elif rotation == 270.0:
@@ -182,8 +205,12 @@ class Kreisel(BaseModel):
p1b2 = p1b[0] + 50, p1b[1] + 50 - RADIUS, z1
p2a2 = p2a[0] - 50, p2a[1] - 50 + RADIUS, z1
p2b2 = p2b[0] + 50, p2b[1] - 50 + RADIUS, z1
Line1 = Line.new(dxfattribs={"start": p1a2,"end": p2a2,"layer": "Pinbereich"})
Line2 = Line.new(dxfattribs={"start": p1b2,"end": p2b2,"layer": "Pinbereich"})
Line1 = Line.new(
dxfattribs={"start": p1a2, "end": p2a2, "layer": "Pinbereich"}
)
Line2 = Line.new(
dxfattribs={"start": p1b2, "end": p2b2, "layer": "Pinbereich"}
)
msp.add_entity(Line1)
msp.add_entity(Line2)
@@ -191,7 +218,9 @@ class Kreisel(BaseModel):
msp.add_line(p1a, p2a)
msp.add_line(p1b, p2b)
def draw_kreisel_drehrichtung_markierung(msp, pos1, pos2, kreisel, lib_doc, doc, verbose):
def draw_kreisel_drehrichtung_markierung(
msp, pos1, pos2, kreisel, lib_doc, doc, verbose
):
drehrichtung = (kreisel.drehrichtung or "").upper()
if drehrichtung not in ("UZS", "GUZS"):
return
@@ -216,24 +245,44 @@ class Kreisel(BaseModel):
t = i / 4 # 1/4, 2/4, 3/4
px = p1_oben[0] + t * (p2_oben[0] - p1_oben[0])
py = p1_oben[1] + t * (p2_oben[1] - p1_oben[1])
rotation = math.degrees(math.atan2(p2_oben[1] - p1_oben[1], p2_oben[0] - p1_oben[0]))
rotation = math.degrees(
math.atan2(p2_oben[1] - p1_oben[1], p2_oben[0] - p1_oben[0])
)
if drehrichtung == "GUZS":
rotation += 180
block_methoden.import_block("Richtungspfeil", lib_doc, doc)
blockref_layer, color = block_methoden.get_insert_color_layer(lib_doc, "Richtungspfeil")
bref = msp.add_blockref("Richtungspfeil", (px, py,z1), dxfattribs={"rotation": rotation,"layer": blockref_layer})
blockref_layer, color = block_methoden.get_insert_color_layer(
lib_doc, "Richtungspfeil"
)
bref = msp.add_blockref(
"Richtungspfeil",
(px, py, z1),
dxfattribs={"rotation": rotation, "layer": blockref_layer},
)
if verbose:
print(f"[INFO] Drehrichtung '{drehrichtung}': Richtungspfeil oben bei ({px:.1f}, {py:.1f}), rot={rotation:.1f}")
print(
f"[INFO] Drehrichtung '{drehrichtung}': Richtungspfeil oben bei ({px:.1f}, {py:.1f}), rot={rotation:.1f}"
)
# S-LP auf unterer Linie (Drehrichtung invertiert)
for i in range(1, 4):
t = i / 4
px = p1_unten[0] + t * (p2_unten[0] - p1_unten[0])
py = p1_unten[1] + t * (p2_unten[1] - p1_unten[1])
rotation = math.degrees(math.atan2(p2_unten[1] - p1_unten[1], p2_unten[0] - p1_unten[0]))
rotation = math.degrees(
math.atan2(p2_unten[1] - p1_unten[1], p2_unten[0] - p1_unten[0])
)
if drehrichtung == "UZS":
rotation += 180
block_methoden.import_block("Richtungspfeil", lib_doc, doc)
blockref_layer, color = block_methoden.get_insert_color_layer( lib_doc, "Richtungspfeil")
bref = msp.add_blockref("Richtungspfeil", (px, py, z1), dxfattribs={"rotation": rotation , "layer": blockref_layer})
blockref_layer, color = block_methoden.get_insert_color_layer(
lib_doc, "Richtungspfeil"
)
bref = msp.add_blockref(
"Richtungspfeil",
(px, py, z1),
dxfattribs={"rotation": rotation, "layer": blockref_layer},
)
if verbose:
print(f"[INFO] Drehrichtung '{drehrichtung}':Richtungspfeil unten bei ({px:.1f}, {py:.1f}), rot={rotation:.1f}")
print(
f"[INFO] Drehrichtung '{drehrichtung}':Richtungspfeil unten bei ({px:.1f}, {py:.1f}), rot={rotation:.1f}"
)
+17 -8
View File
@@ -1,10 +1,11 @@
from ezdxf.entities import Line
import math
from pydantic import BaseModel, Field, field_validator
from typing import Optional
import plant2dxf
import block_methoden
class Omniflo(BaseModel):
teileid: str
x: float
@@ -16,16 +17,21 @@ class Omniflo(BaseModel):
h0: Optional[float] = Field(default=0.0, description="Höhe unten im CSV")
h1: Optional[float] = Field(default=0.0, description="Höhe Oben im CSV")
anzahl_scanner: Optional[int] = Field(default=0, description="Anzahl der Scanner")
anzahl_stopper: Optional [int] = Field(default=0, description="Anzahl der Separatoren")
anzahl_stopper: Optional[int] = Field(
default=0, description="Anzahl der Separatoren"
)
@property
def hight_zwischen(self):
return ((self.h0 + self.h1) /2)
return (self.h0 + self.h1) / 2
@classmethod
def from_merkmale(cls, teileid, x, y, merkmale):
sivasnummer = merkmale.get("SivasNummer")
try:
laenge = float(merkmale.get("Länge in Meter", "0").replace(",", ".")) * 1000 # Meter → mm
laenge = (
float(merkmale.get("Länge in Meter", "0").replace(",", ".")) * 1000
) # Meter → mm
except Exception:
laenge = 0
try:
@@ -63,8 +69,9 @@ class Omniflo(BaseModel):
h0=h0,
h1=h1,
anzahl_scanner=anzahl_scanner,
anzahl_stopper = anzahl_separatoren
anzahl_stopper=anzahl_separatoren,
)
def Omniflo_geraden_erstellung(msp, doc, tefsivas, omniflo_objekt):
"""Erstellung der Tef gerade und Omniflo gerade"""
winkel_rad = math.radians(omniflo_objekt.drehung)
@@ -85,6 +92,7 @@ class Omniflo(BaseModel):
linie.dxf.layer = "F-1"
else:
linie.dxf.layer = "A-2"
def omniflo_foerdererstellung(msp, doc, lib_doc, omniflo_objekt):
""" "Erstellung des Kettenförderers aktuell nur grundriss"""
block_methoden.import_block("bogen1", lib_doc, doc)
@@ -96,7 +104,7 @@ class Omniflo(BaseModel):
h0 = omniflo_objekt.h0
h1 = omniflo_objekt.h1
h_zwischen = omniflo_objekt.hight_zwischen
blockname = (f"OF_Förderer_{laenge}_{h_zwischen}")
blockname = f"OF_Förderer_{laenge}_{h_zwischen}"
winkel_rad = math.radians(rotation)
halbe_laenge = laenge / 2
# Man muss bei sin -1 machen wegen des links koordinaten system
@@ -112,5 +120,6 @@ class Omniflo(BaseModel):
copy = line.copy()
copy.translate(-x, -y, -h_zwischen)
block.add_entity(copy)
msp.add_blockref(blockname,(x,y,h_zwischen),dxfattribs={"rotation": rotation})
msp.add_blockref(
blockname, (x, y, h_zwischen), dxfattribs={"rotation": rotation}
)
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -6,7 +6,7 @@ import re
import configparser
from pathlib import Path
from utils import check_environment_var, setup_logger
from Elemente import Kreisel, VarioFoerderer,Gefaehllestrecke,Angetriebene_Kurve,Bt_element,Omniflo, Eckrad
from Elemente import Kreisel, VarioFoerderer,Gefaellestrecke,Angetriebene_Kurve,Bt_element,Omniflo, Eckrad
# --------------------------------------------------------- CFG-Leser für shapes.cfg
def get_shape_cfg(teileart, cfg_path, logger=None):
parser = configparser.ConfigParser()
+640 -232
View File
File diff suppressed because it is too large Load Diff
+59 -17
View File
@@ -4,21 +4,31 @@ from ezdxf import units
from ezdxf.entities import Line
from ezdxf.addons import importer
from ezdxf.math import Matrix44, X_AXIS, Y_AXIS, Z_AXIS
def dreh_block(block_name: str, to_doc, lib_doc, winkel):
"""Nimmt ein schon importierten Block und erstellt einen neuen der an der y_axis oder x_axis gedreht wird
"""
"""Nimmt ein schon importierten Block und erstellt einen neuen der an der y_axis oder x_axis gedreht wird"""
dreh_block_name = block_name + f"_{math.degrees(winkel)}"
layer, color = get_insert_color_layer(lib_doc, block_name)
if (dreh_block_name in to_doc.blocks):
if dreh_block_name in to_doc.blocks:
return dreh_block_name
block_zwischen = to_doc.blocks.new(name=block_name + f"zwischenschrit_{winkel}", base_point=(0,0,0))
block_zwischen = to_doc.blocks.new(
name=block_name + f"zwischenschrit_{winkel}", base_point=(0, 0, 0)
)
block = to_doc.blocks.new(name=dreh_block_name, base_point=(0, 0, 0))
if block_name == "200000146_ES-Element_90_rechts" or block_name =="400102632_ES-Element_90_links" or block_name =="200000241_AS-Element_90_rechts" or block_name =="200000217_AS-Element_90_links":
if (
block_name == "200000146_ES-Element_90_rechts"
or block_name == "400102632_ES-Element_90_links"
or block_name == "200000241_AS-Element_90_rechts"
or block_name == "200000217_AS-Element_90_links"
):
rotation_matrix = Matrix44.axis_rotate(X_AXIS, winkel)
else:
rotation_matrix = Matrix44.axis_rotate(Y_AXIS, winkel)
block_zwischen.add_blockref(block_name,(0,0,0),dxfattribs={"layer":layer,"color": color})
block_zwischen.add_blockref(
block_name, (0, 0, 0), dxfattribs={"layer": layer, "color": color}
)
for e in block_zwischen:
copy = e.copy()
copy.transform(rotation_matrix)
@@ -41,7 +51,7 @@ def import_block(block_name: str, from_doc, to_doc, winkel = None) -> None:
# Alle Linientypen importieren
imp.import_table("linetypes")
if ((block_name in to_doc.blocks)):
if block_name in to_doc.blocks:
# speichern der attdef elemente in eine Liste falks diese verhanden sind und gibt diese zurück
for ent in src:
copy = ent.copy()
@@ -100,6 +110,7 @@ def import_block(block_name: str, from_doc, to_doc, winkel = None) -> None:
if att_def != {}:
return att_def
def get_insert_color_layer(lib_doc, blockname):
"""Gibt den Layer und die Color für den Jeweiligen block in der Libary datei zurück"""
msp_lib = lib_doc.modelspace()
@@ -111,6 +122,7 @@ def get_insert_color_layer(lib_doc, blockname):
layer = insert.dxf.layer
return layer, color
def rotatate_and_left_motor_umlenk(doc, lib_doc, config):
motor_rotation = float(config.get("Ils 2.0 core winkel", "winkel_motor"))
umlenk_rotation = float(config.get("Ils 2.0 core winkel", "winkel_umlenk"))
@@ -120,21 +132,51 @@ def rotatate_and_left_motor_umlenk(doc, lib_doc,config):
blockname_umlenk_links = block_Vario_Umlenkstation_500mm + "_links"
import_block(block_Vario_Umlenkstation_500mm, lib_doc, doc)
import_block(block_Vario_Motorstation_500mm, lib_doc, doc)
turn_two_blocks_left(doc, block_Vario_Umlenkstation_500mm, block_Vario_Motorstation_500mm, blockname_motor_links, blockname_umlenk_links)
turn_two_blocks_left(
doc,
block_Vario_Umlenkstation_500mm,
block_Vario_Motorstation_500mm,
blockname_motor_links,
blockname_umlenk_links,
)
block_Vario_Umlenkstation_500mm =dreh_block(block_Vario_Umlenkstation_500mm,doc,lib_doc,math.radians(umlenk_rotation))
block_Vario_Motorstation_500mm =dreh_block(block_Vario_Motorstation_500mm,doc,lib_doc,math.radians(motor_rotation))
blockname_motor_links =dreh_block(blockname_motor_links,doc,lib_doc,math.radians(umlenk_rotation))
blockname_umlenk_links =dreh_block(blockname_umlenk_links,doc,lib_doc,math.radians(motor_rotation))
return block_Vario_Umlenkstation_500mm,block_Vario_Motorstation_500mm,blockname_motor_links,blockname_umlenk_links
block_Vario_Umlenkstation_500mm = dreh_block(
block_Vario_Umlenkstation_500mm, doc, lib_doc, math.radians(umlenk_rotation)
)
block_Vario_Motorstation_500mm = dreh_block(
block_Vario_Motorstation_500mm, doc, lib_doc, math.radians(motor_rotation)
)
blockname_motor_links = dreh_block(
blockname_motor_links, doc, lib_doc, math.radians(umlenk_rotation)
)
blockname_umlenk_links = dreh_block(
blockname_umlenk_links, doc, lib_doc, math.radians(motor_rotation)
)
return (
block_Vario_Umlenkstation_500mm,
block_Vario_Motorstation_500mm,
blockname_motor_links,
blockname_umlenk_links,
)
def turn_two_blocks_left(doc, block_1_name_zwischen, block_2_name_zwischen, block_2_left_name, block_1_left_name):
def turn_two_blocks_left(
doc,
block_1_name_zwischen,
block_2_name_zwischen,
block_2_left_name,
block_1_left_name,
):
blockname1 = block_1_name_zwischen
blockname2 = block_2_name_zwischen
if block_2_left_name not in doc.blocks:
matrix = Matrix44.scale(1, -1, 1)
block1_zwischen = doc.blocks.new(name=block_1_name_zwischen + "zwischenschrit", base_point=(0,0,0))
block2_zwischen = doc.blocks.new(name=block_2_name_zwischen + "zwischenschrit", base_point=(0,0,0))
block1_zwischen = doc.blocks.new(
name=block_1_name_zwischen + "zwischenschrit", base_point=(0, 0, 0)
)
block2_zwischen = doc.blocks.new(
name=block_2_name_zwischen + "zwischenschrit", base_point=(0, 0, 0)
)
block_2 = doc.blocks.new(name=block_2_left_name, base_point=(0, 0, 0))
block_1_left_name = doc.blocks.new(name=block_1_left_name, base_point=(0, 0, 0))
block1_zwischen.add_blockref(blockname1, (0, 0, 0))
@@ -149,8 +191,8 @@ def turn_two_blocks_left(doc, block_1_name_zwischen, block_2_name_zwischen, bloc
copy.transform(matrix)
block_1_left_name.add_entity(copy)
def add_attributes_to_block(block, attributes):
def add_attributes_to_block(block, attributes):
"""
Fügt einem bestehenden ezdxf-Block Attribut-Definitionen hinzu.
+152 -78
View File
@@ -4,12 +4,12 @@ from ezdxf.math import Matrix44, Vec3, BoundingBox, Vec2
import math
import argparse
import sys
import shutil
import configparser
from utils import check_environment_var, setup_logger
from pathlib import Path
import logging
def create_block_library(input_dir, output_file, config, logger=None):
"""
Erstellt eine DXF-Block-Bibliothek aus einzelnen DXF-Dateien.
@@ -84,17 +84,16 @@ def create_block_library(input_dir, output_file, config, logger=None):
for attrib in insert.attribs:
att_def[attrib.dxf.tag] = attrib.dxf.text
for e in entities:
if e.dxftype() in allowed_types:
filtered_entities.append(e)
else:
logger.info(f"{e.dxftype()} is nicht in der erlaubten Liste. Diese befindet sich in {filename}")
logger.info(
f"{e.dxftype()} is nicht in der erlaubten Liste. Diese befindet sich in {filename}"
)
entities = filtered_entities
except Exception as e:
error_msg = f"Fehler beim Lesen von {filename}: {e}"
if logger:
@@ -106,7 +105,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
# Sicherstellen, dass die im Quell-DXF verwendeten Layer im Zieldokument existieren
try:
used_layer_names = {e.dxf.layer for e in entities if hasattr(e.dxf, "layer")}
used_layer_names = {
e.dxf.layer for e in entities if hasattr(e.dxf, "layer")
}
for layer_name in used_layer_names:
if layer_name and layer_name not in doc.layers:
try:
@@ -123,7 +124,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
except Exception:
pass
boundingbox, ausdehnung, center = calculate_block_bounding_box(filtered_entities, doc,src_doc, filename,config)
boundingbox, ausdehnung, center = calculate_block_bounding_box(
filtered_entities, doc, src_doc, filename, config
)
if center is None:
error_msg = f"Keine gültige Geometrie in {filename}"
if logger:
@@ -146,7 +149,6 @@ def create_block_library(input_dir, output_file, config, logger=None):
# Platzierung in Reihen und Spalten
# Attribut-Definition (ATTDEF) hinzufügen
# Blockreferenz-Layer bestimmen
blockref_layer = None
try:
@@ -186,9 +188,15 @@ def create_block_library(input_dir, output_file, config, logger=None):
blockref_layer = None
section = "dxf2lib"
text_height = get_cfg_value(section, "text_height", DEFAULTS["text_height"])
extra_block_space_x = get_cfg_value(section, "extra_block_space_x", DEFAULTS["extra_block_space_x"])
blocks_per_row = get_cfg_value(section, "blocks_per_row", DEFAULTS["blocks_per_row"])
extra_text_space_y = get_cfg_value(section, "extra_text_space_y", DEFAULTS["extra_text_space_y"])
extra_block_space_x = get_cfg_value(
section, "extra_block_space_x", DEFAULTS["extra_block_space_x"]
)
blocks_per_row = get_cfg_value(
section, "blocks_per_row", DEFAULTS["blocks_per_row"]
)
extra_text_space_y = get_cfg_value(
section, "extra_text_space_y", DEFAULTS["extra_text_space_y"]
)
ausdehnung_x, ausdehung_y = ausdehnung[0], ausdehnung[1]
@@ -199,7 +207,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
x_offset += max_blockspacing_x
# Blockreferenz mit optionalem Layer einfügen (Entity-Layer bleiben erhalten)
if blockref_layer:
test =msp.add_blockref(name, insert=(x_offset, y_offset), dxfattribs={"layer": blockref_layer})
test = msp.add_blockref(
name, insert=(x_offset, y_offset), dxfattribs={"layer": blockref_layer}
)
else:
test = msp.add_blockref(name, insert=(x_offset, y_offset))
# Text mit Blocknamen über dem Block
@@ -215,7 +225,16 @@ def create_block_library(input_dir, output_file, config, logger=None):
a.is_invisible = True
# Werte aus Config holen (Block: [dxf2lib])
msp.add_text(name, dxfattribs={'height': text_height, 'insert': (x_offset -ausdehnung_x/2 , y_offset + ausdehung_y/2 + extra_text_space_y)})
msp.add_text(
name,
dxfattribs={
"height": text_height,
"insert": (
x_offset - ausdehnung_x / 2,
y_offset + ausdehung_y / 2 + extra_text_space_y,
),
},
)
processed_files.append(filename)
blocks_in_row += 1
@@ -234,7 +253,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
logger.info(f"Fehlerhafte Dateien: {len(error_files)}")
if error_files:
logger.warning(f"{len(error_files)} Dateien konnten nicht verarbeitet werden:")
logger.warning(
f"{len(error_files)} Dateien konnten nicht verarbeitet werden:"
)
for filename, error_msg in error_files:
logger.error(f"{filename}: {error_msg}")
else:
@@ -245,7 +266,9 @@ def create_block_library(input_dir, output_file, config, logger=None):
print(f"Fehlerhafte Dateien: {len(error_files)}")
if error_files:
print(f"Warnung: {len(error_files)} Dateien konnten nicht verarbeitet werden.")
print(
f"Warnung: {len(error_files)} Dateien konnten nicht verarbeitet werden."
)
output_dir = output_file.parent
if not output_dir.exists():
@@ -267,7 +290,9 @@ def copy_entity(logger, error_files, filename, e, center):
return cp
except Exception as err:
error_msg = f"Fehler beim Verarbeiten von Entity {e.dxftype()} in {filename}: {err}"
error_msg = (
f"Fehler beim Verarbeiten von Entity {e.dxftype()} in {filename}: {err}"
)
if logger:
logger.error(error_msg)
else:
@@ -276,15 +301,15 @@ def copy_entity(logger, error_files, filename, e, center):
return None
# Standardwerte (falls nicht in der Config)
DEFAULTS = {
"text_height": 20, # Schriftgröße des Texts (in DXF-Einheiten)
"blocks_per_row": 20, # Anzahl Blöcke pro Zeile im Raster
"extra_block_space_x": 50, # Extra Platz damit sich Blöcke nicht überlappen
"extra_text_space_y" : 50 # Abstand der Überschrift über dem Symbol
"extra_text_space_y": 50, # Abstand der Überschrift über dem Symbol
}
def get_cfg_value(section, key, fallback):
try:
return int(config.get(section, key))
@@ -292,9 +317,9 @@ def get_cfg_value(section, key, fallback):
return fallback
def convert_dxf_to_block_with_inserts(input_filename, output_filename, block_name="CONVERTED_BLOCK"):
def convert_dxf_to_block_with_inserts(
input_filename, output_filename, block_name="CONVERTED_BLOCK"
):
"""
Konvertiert alle Entities einer DXF-Datei in einen neuen Block
INSERTs werden als Referenzen beibehalten (nicht explodiert)
@@ -305,8 +330,8 @@ def convert_dxf_to_block_with_inserts(input_filename, output_filename, block_nam
print(f"Lade DXF-Datei: {input_filename}")
# Neue Ausgabe-DXF erstellen
output_doc = ezdxf.new('R2010')
output_doc.header['$INSUNITS'] = 4 # Millimeter
output_doc = ezdxf.new("R2010")
output_doc.header["$INSUNITS"] = 4 # Millimeter
# Zuerst alle Block-Definitionen kopieren
copied_blocks = copy_block_definitions(input_doc, output_doc)
@@ -322,7 +347,7 @@ def convert_dxf_to_block_with_inserts(input_filename, output_filename, block_nam
insert_count = 0
for entity in msp:
if entity.dxftype() == 'INSERT':
if entity.dxftype() == "INSERT":
# INSERT direkt kopieren (nicht explodieren)
copy_entity_to_block(entity, new_block)
insert_count += 1
@@ -373,7 +398,7 @@ def copy_block_definitions(source_doc, target_doc):
for block_name in source_doc.blocks:
# Standard-Blöcke (MODEL_SPACE, PAPER_SPACE) überspringen
if block_name.startswith('*'):
if block_name.startswith("*"):
continue
source_block = source_doc.blocks[block_name]
@@ -407,11 +432,16 @@ def calculate_block_bounding_box(block, doc, src_doc, filename,config):
if entity_bbox and entity_bbox.has_data:
bbox.extend(entity_bbox)
return bbox, (bbox.extmax.x - bbox.extmin.x, bbox.extmax.y - bbox.extmin.y), bbox.center
return (
bbox,
(bbox.extmax.x - bbox.extmin.x, bbox.extmax.y - bbox.extmin.y),
bbox.center,
)
def _bbox_from_virtual_entities(entity, doc, src_doc, filename, config, transform_matrix=None):
def _bbox_from_virtual_entities(
entity, doc, src_doc, filename, config, transform_matrix=None
):
"""
Nutzt virtual_entities(), um komplexe Objekte (z.B. SURFACE) in
auswertbare Geometrie zu zerlegen und darauf eine Bounding Box zu
@@ -440,7 +470,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
bbox = BoundingBox()
try:
if e.dxftype() == 'LINE':
if e.dxftype() == "LINE":
start = Vec3(e.dxf.start)
end = Vec3(e.dxf.end)
if transform_matrix:
@@ -449,7 +479,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
bbox.extend([start])
bbox.extend([end])
elif e.dxftype() == 'CIRCLE':
elif e.dxftype() == "CIRCLE":
# Kreis durch Punktabtastung (robust bei Transformationen)
center = Vec3(e.dxf.center)
radius = float(e.dxf.radius)
@@ -465,7 +495,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
if points:
bbox.extend(points)
elif e.dxftype() == 'ARC':
elif e.dxftype() == "ARC":
# Bogen durch Punktabtastung zwischen Start- und Endwinkel
center = Vec3(e.dxf.center)
radius = float(e.dxf.radius)
@@ -496,7 +526,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
if points:
bbox.extend(points)
elif e.dxftype() == 'LWPOLYLINE':
elif e.dxftype() == "LWPOLYLINE":
# Nutze virtuelle Entities (Linien/Bögen), inkl. Bulge-Unterstützung
ve_bbox = _bbox_from_virtual_entities(
e, doc, src_doc, filename, config, transform_matrix
@@ -504,7 +534,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
if ve_bbox.has_data:
bbox.extend(ve_bbox)
elif e.dxftype() == 'POLYLINE':
elif e.dxftype() == "POLYLINE":
# 2D/3D Polylines ebenfalls über virtuelle Entities
ve_bbox = _bbox_from_virtual_entities(
e, doc, src_doc, filename, config, transform_matrix
@@ -512,7 +542,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
if ve_bbox.has_data:
bbox.extend(ve_bbox)
elif e.dxftype() == '3DFACE':
elif e.dxftype() == "3DFACE":
# 3DFace: direkte Eckpunkte verwenden
pts = []
try:
@@ -527,7 +557,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
if pts:
bbox.extend(pts)
elif e.dxftype() in {'MESH', 'POLYFACE', 'POLYFACEMESH'}:
elif e.dxftype() in {"MESH", "POLYFACE", "POLYFACEMESH"}:
# Mesh/Polyface über virtuelle Geometrie auswerten
ve_bbox = _bbox_from_virtual_entities(
e, doc, src_doc, filename, config, transform_matrix
@@ -535,7 +565,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
if ve_bbox.has_data:
bbox.extend(ve_bbox)
elif e.dxftype() == 'SPLINE':
elif e.dxftype() == "SPLINE":
# Approximation der Spline-Kurve
try:
pts = list(e.approximate(60))
@@ -557,18 +587,20 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
if sampled:
bbox.extend(sampled)
elif e.dxftype() == 'ATTDEF':
elif e.dxftype() == "ATTDEF":
insert_point = Vec3(e.dxf.insert)
if transform_matrix:
insert_point = transform_matrix.transform(insert_point)
elif e.dxftype() == 'TEXT':
elif e.dxftype() == "TEXT":
insert_point = Vec3(e.dxf.insert)
height = float(getattr(e.dxf, "height", 1.0))
width_factor = float(getattr(e.dxf, "width", 1.0))
rotation = math.radians(getattr(e.dxf, "rotation", 0.0))
text_content = getattr(e.dxf, "text", "") or ""
est_width = max(len(text_content) * height * 0.6 * width_factor, height * 0.5)
est_width = max(
len(text_content) * height * 0.6 * width_factor, height * 0.5
)
corners = [
insert_point,
insert_point + Vec3(est_width, 0, 0),
@@ -590,7 +622,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
pt = transform_matrix.transform(pt)
bbox.extend([pt])
elif e.dxftype() == 'MTEXT':
elif e.dxftype() == "MTEXT":
insert_point = Vec3(e.dxf.insert)
char_height = float(getattr(e.dxf, "char_height", 1.0))
width = float(getattr(e.dxf, "width", 0.0))
@@ -610,7 +642,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
pt = transform_matrix.transform(pt)
bbox.extend([pt])
elif e.dxftype() == 'REGION':
elif e.dxftype() == "REGION":
# Region: Begrenzungsgeometrie über virtual_entities()
ve_bbox = _bbox_from_virtual_entities(
e, doc, src_doc, filename, config, transform_matrix
@@ -618,7 +650,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
if ve_bbox.has_data:
bbox.extend(ve_bbox)
elif e.dxftype().endswith('SURFACE'):
elif e.dxftype().endswith("SURFACE"):
# Viele Surface-Typen liefern ihre Proxy-Geometrie über virtual_entities()
ve_bbox = _bbox_from_virtual_entities(
e, doc, src_doc, filename, config, transform_matrix
@@ -626,24 +658,36 @@ def get_entity_bounding_box(e, doc,src_doc,filename,config, transform_matrix=Non
if ve_bbox.has_data:
bbox.extend(ve_bbox)
elif e.dxftype() == 'INSERT':
elif e.dxftype() == "INSERT":
# INSERT: Block-Inhalt mit Transformation berücksichtigen
insert_bbox = calculate_insert_bounding_box(e, doc,src_doc,filename,config, transform_matrix)
if insert_bbox and insert_bbox.has_data and e.dxf.layer not in config.get("dxf2lib","automation_layer"):
insert_bbox = calculate_insert_bounding_box(
e, doc, src_doc, filename, config, transform_matrix
)
if (
insert_bbox
and insert_bbox.has_data
and e.dxf.layer not in config.get("dxf2lib", "automation_layer")
):
bbox.extend(insert_bbox)
except Exception as e:
print(f"Fehler bei Bounding Box Berechnung für {e.dxftype()}: {e}")
return bbox
def extract_scaling(matrix):
sx = math.sqrt(matrix[0, 0] ** 2 + matrix[0, 1] ** 2 + matrix[0, 2] ** 2)
sy = math.sqrt(matrix[1, 0] ** 2 + matrix[1, 1] ** 2 + matrix[1, 2] ** 2)
return sx, sy,
return (
sx,
sy,
)
def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,config,parent_transform=None):
def calculate_insert_bounding_box(
insert_entity, doc, src_doc, filename, config, parent_transform=None
):
"""
Berechnet die Bounding Box eines INSERTs inklusive Block-Inhalt
"""
@@ -667,7 +711,6 @@ def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,config,par
block_def = src_blk
# Transformation der INSERT-Entity berechnen
insert_transform = get_insert_transform_matrix(insert_entity)
@@ -682,7 +725,9 @@ def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,config,par
for block_entity in block_def:
entity_bbox= get_entity_bounding_box(block_entity, doc,src_doc,filename, config,combined_transform)
entity_bbox = get_entity_bounding_box(
block_entity, doc, src_doc, filename, config, combined_transform
)
if entity_bbox and entity_bbox.has_data:
if new_insert:
dst_blk.add_entity(block_entity.copy())
@@ -703,18 +748,18 @@ def get_insert_transform_matrix(insert_entity):
insert_point = Vec3(insert_entity.dxf.insert)
# Skalierung
xscale = getattr(insert_entity.dxf, 'xscale', 1.0)
yscale = getattr(insert_entity.dxf, 'yscale', 1.0)
zscale = getattr(insert_entity.dxf, 'zscale', 1.0)
xscale = getattr(insert_entity.dxf, "xscale", 1.0)
yscale = getattr(insert_entity.dxf, "yscale", 1.0)
zscale = getattr(insert_entity.dxf, "zscale", 1.0)
# Rotation (in Radiant umwandeln)
rotation = math.radians(getattr(insert_entity.dxf, 'rotation', 0.0))
rotation = math.radians(getattr(insert_entity.dxf, "rotation", 0.0))
# Transformationsmatrix erstellen
matrix = Matrix44.chain(
Matrix44.scale(xscale, yscale, zscale),
Matrix44.z_rotate(rotation),
Matrix44.translate(insert_point.x, insert_point.y, insert_point.z)
Matrix44.translate(insert_point.x, insert_point.y, insert_point.z),
)
return matrix
@@ -759,11 +804,14 @@ def add_bounding_box_to_modelspace(msp, bbox, centered=False):
(right, bottom),
(right, top),
(left, top),
(left, bottom)
(left, bottom),
]
# Roter Punkt in der Mitte
msp.add_circle(center=(0.0, 0.0), radius=max(0.5, min(width, height) * 0.01),
dxfattribs={"layer": "BOUNDING_BOX", "color": 1})
msp.add_circle(
center=(0.0, 0.0),
radius=max(0.5, min(width, height) * 0.01),
dxfattribs={"layer": "BOUNDING_BOX", "color": 1},
)
else:
# Ursprüngliche, nicht-zentrierte Bounding Box
bbox_points = [
@@ -771,7 +819,7 @@ def add_bounding_box_to_modelspace(msp, bbox, centered=False):
(max_pt.x, min_pt.y),
(max_pt.x, max_pt.y),
(min_pt.x, max_pt.y),
(min_pt.x, min_pt.y)
(min_pt.x, min_pt.y),
]
bbox_poly = msp.add_lwpolyline(bbox_points)
@@ -779,13 +827,23 @@ def add_bounding_box_to_modelspace(msp, bbox, centered=False):
bbox_poly.dxf.color = 1 # Rot
# Text mit Abmessungen
text_pos = Vec3(bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 5, 0)
msp.add_text(f"Breite: {width:.2f} mm", height=3,
dxfattribs={'insert': text_pos, 'layer': "BOUNDING_BOX", 'color': 1})
text_pos = Vec3(
bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 5, 0
)
msp.add_text(
f"Breite: {width:.2f} mm",
height=3,
dxfattribs={"insert": text_pos, "layer": "BOUNDING_BOX", "color": 1},
)
text_pos2 = Vec3(bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 10, 0)
msp.add_text(f"Höhe: {height:.2f} mm", height=3,
dxfattribs={'insert': text_pos2, 'layer': "BOUNDING_BOX", 'color': 1})
text_pos2 = Vec3(
bbox_points[0][0], (bbox_points[2][1] if centered else max_pt.y) + 10, 0
)
msp.add_text(
f"Höhe: {height:.2f} mm",
height=3,
dxfattribs={"insert": text_pos2, "layer": "BOUNDING_BOX", "color": 1},
)
def format_bounding_box(bbox):
@@ -801,9 +859,11 @@ def format_bounding_box(bbox):
height = max_pt.y - min_pt.y
depth = max_pt.z - min_pt.z
return (f"Min: ({min_pt.x:.2f}, {min_pt.y:.2f}, {min_pt.z:.2f}) "
return (
f"Min: ({min_pt.x:.2f}, {min_pt.y:.2f}, {min_pt.z:.2f}) "
f"Max: ({max_pt.x:.2f}, {max_pt.y:.2f}, {max_pt.z:.2f}) "
f"Größe: {width:.2f} × {height:.2f} × {depth:.2f} mm")
f"Größe: {width:.2f} × {height:.2f} × {depth:.2f} mm"
)
def analyze_source_dxf_with_blocks(filename):
@@ -824,16 +884,16 @@ def analyze_source_dxf_with_blocks(filename):
entity_type = entity.dxftype()
entity_types[entity_type] = entity_types.get(entity_type, 0) + 1
layer = getattr(entity.dxf, 'layer', '0')
layer = getattr(entity.dxf, "layer", "0")
layer_count[layer] = layer_count.get(layer, 0) + 1
if entity_type == 'INSERT':
if entity_type == "INSERT":
block_name = entity.dxf.name
insert_blocks[block_name] = insert_blocks.get(block_name, 0) + 1
# Block-Definitionen analysieren
for block_name in doc.blocks:
if not block_name.startswith('*'): # Keine Standard-Blöcke
if not block_name.startswith("*"): # Keine Standard-Blöcke
block_def = doc.blocks[block_name]
entity_count = len(list(block_def))
block_definitions[block_name] = entity_count
@@ -864,11 +924,21 @@ def analyze_source_dxf_with_blocks(filename):
print(f"Fehler bei der Analyse: {e}")
return {}, {}, {}, {}
if __name__ == "__main__":
# Argumentparser für Kommandozeilenoptionen
parser = argparse.ArgumentParser(description="SVG/XML zu DXF Konverter")
parser.add_argument('-i', '--input', type=str, help='Input-Verzeichnis mit SVG/XML-Dateien')
parser.add_argument('-n', '--name', required=False, type=str, help='Name der zu erzeugenden Bibliothek (optional, wird sonst abgefragt)', default="test")
parser.add_argument(
"-i", "--input", type=str, help="Input-Verzeichnis mit SVG/XML-Dateien"
)
parser.add_argument(
"-n",
"--name",
required=False,
type=str,
help="Name der zu erzeugenden Bibliothek (optional, wird sonst abgefragt)",
default="test",
)
if len(sys.argv) == 2 and sys.argv[1] in ("-h", "--help"):
parser.print_help()
@@ -877,7 +947,9 @@ if __name__ == "__main__":
args = parser.parse_args()
if not args.name:
args.name = input("Bitte Namen der zu erzeugenden Bibliothek eingeben: ").strip()
args.name = input(
"Bitte Namen der zu erzeugenden Bibliothek eingeben: "
).strip()
if not args.name:
print("Fehler: Kein Name angegeben. Beende.")
sys.exit(1)
@@ -890,7 +962,9 @@ if __name__ == "__main__":
INPUT_DIR = check_environment_var("PROJECT_DATA") / "omniflo"
print(f"Kein Input-Verzeichnis angegeben, verwende Standard: {INPUT_DIR} \n")
OUTPUT_FILE = check_environment_var("PROJECT_DATA") / "block_libraries" / f"{args.name}.dxf"
OUTPUT_FILE = (
check_environment_var("PROJECT_DATA") / "block_libraries" / f"{args.name}.dxf"
)
# Prüfe und erstelle log-Verzeichnis falls nötig
log_dir = check_environment_var("PROJECT_LOG")
@@ -899,9 +973,9 @@ if __name__ == "__main__":
print(f"Log-Verzeichnis erstellt: {log_dir}")
# Logger Setup
log_file = Path(os.environ['PROJECT_LOG']) / 'dxf2lib.log'
file_handler = logging.FileHandler(str(log_file), 'a', 'utf-8')
logger = setup_logger(log_dir, name='dxf2lib')
log_file = Path(os.environ["PROJECT_LOG"]) / "dxf2lib.log"
file_handler = logging.FileHandler(str(log_file), "a", "utf-8")
logger = setup_logger(log_dir, name="dxf2lib")
logger.info("=== DXF2LIB Verarbeitung gestartet ===")
logger.info(f"Input-Verzeichnis: {INPUT_DIR}")
logger.info(f"Output-Datei: {OUTPUT_FILE}")
+214
View File
@@ -0,0 +1,214 @@
"""
Handler Context für DXF-Elementgenerierung.
Vereinfacht die Aufrufe der handle-Funktionen und bietet Debug-Unterstützung.
"""
class HandlerContext:
"""
Kontextobjekt für Handler-Funktionsaufrufe.
Speichert alle Parameter für handle-Funktionen und bietet:
- Vereinfachte Aufrufe
- Schöne String-Repräsentation für Debugging
- Einfachen Zugriff auf alle Parameter
"""
def __init__(
self,
msp,
teileid,
merkmale,
x,
y,
doc,
lib_doc,
verbose=False,
symbols=None,
strecken_nachbarn=None,
config=None,
config_allgemein=None,
):
self.msp = msp
self.teileid = teileid
self.merkmale = merkmale if merkmale is not None else {}
self.x = x
self.y = y
self.doc = doc
self.lib_doc = lib_doc
self.verbose = verbose
self.symbols = symbols if symbols is not None else []
self.strecken_nachbarn = (
strecken_nachbarn if strecken_nachbarn is not None else []
)
self.config = config
self.config_allgemein = config_allgemein
def call(self, handler_func):
"""
Ruft eine Handler-Funktion mit allen gespeicherten Parametern auf.
Args:
handler_func: Die Handler-Funktion (z.B. handle_ils_2_0_kreisel)
Returns:
Rückgabewert der Handler-Funktion
"""
return handler_func(
self.msp,
self.teileid,
self.merkmale,
self.x,
self.y,
self.doc,
self.lib_doc,
self.verbose,
self.symbols,
self.strecken_nachbarn,
self.config,
self.config_allgemein,
)
def __str__(self):
"""String-Repräsentation für Debugging."""
lines = [
"=" * 80,
"HandlerContext:",
"=" * 80,
f"TeileId: {self.teileid}",
f"Position: x={self.x:.2f}, y={self.y:.2f}",
f"Verbose: {self.verbose}",
"-" * 80,
"Merkmale:",
]
if self.merkmale:
for key, value in self.merkmale.items():
lines.append(f" {key:20s}: {value}")
else:
lines.append(" (keine)")
lines.append("-" * 80)
lines.append(f"Symbols: {len(self.symbols)} Einträge")
if self.symbols:
for i, sym in enumerate(self.symbols, 1):
lines.append(f" [{i}] {sym}")
lines.append("-" * 80)
lines.append(f"Nachbarn: {len(self.strecken_nachbarn)} Einträge")
lines.append("-" * 80)
lines.append(f"doc: {type(self.doc).__name__}")
lines.append(
f"lib_doc: {type(self.lib_doc).__name__ if self.lib_doc else 'None'}"
)
lines.append(f"msp: {type(self.msp).__name__}")
lines.append(f"config: {'vorhanden' if self.config else 'None'}")
lines.append(f"config_allg: {'vorhanden' if self.config_allgemein else 'None'}")
lines.append("=" * 80)
return "\n".join(lines)
def __repr__(self):
"""Kurze Repräsentation."""
return (
f"HandlerContext(teileid={self.teileid!r}, "
f"x={self.x:.2f}, y={self.y:.2f}, "
f"merkmale={len(self.merkmale)} items)"
)
def to_dict(self):
"""
Gibt alle Parameter als Dictionary zurück (ohne Objekt-Referenzen).
Nützlich für Logging oder Serialisierung.
"""
return {
"teileid": self.teileid,
"x": self.x,
"y": self.y,
"verbose": self.verbose,
"merkmale": self.merkmale.copy(),
"symbols_count": len(self.symbols),
"symbols": self.symbols,
"nachbarn_count": len(self.strecken_nachbarn),
"has_config": self.config is not None,
"has_config_allgemein": self.config_allgemein is not None,
"has_lib_doc": self.lib_doc is not None,
}
@property
def position(self):
"""Gibt Position als Tuple zurück."""
return (self.x, self.y)
@property
def has_library(self):
"""Prüft, ob eine Bibliothek verfügbar ist."""
return self.lib_doc is not None
def get_merkmal(self, key, default=None):
"""
Holt ein Merkmal mit Fallback-Wert.
Args:
key: Merkmal-Schlüssel
default: Standardwert, falls Merkmal nicht existiert
Returns:
Merkmalwert oder default
"""
return self.merkmale.get(key, default)
def create_context_from_row(
row,
msp,
doc,
lib_doc,
strecken_nachbarn,
config,
config_allgemein,
symbols=None,
verbose=False,
):
"""
Factory-Funktion: Erstellt HandlerContext aus einer CSV-Zeile.
Args:
row: Dictionary mit CSV-Daten
msp: Modelspace
doc: DXF-Dokument
lib_doc: Bibliotheks-Dokument
strecken_nachbarn: Liste der Nachbarn
config: Config-Parser
config_allgemein: Allgemeine Config
symbols: Symbol-Liste (optional)
verbose: Debug-Modus (optional)
Returns:
HandlerContext-Instanz
"""
from arbeiten_mit_csv import parse_merkmale, extract_coords
bezeichner = row["Bezeichnung"].strip()
teileid = row["TeileId"].strip()
planquadrat = row["Planquadrat"]
merkmale = parse_merkmale(row.get("Merkmale", ""))
merkmale["bezeichner"] = bezeichner
x, y = extract_coords(planquadrat)
return HandlerContext(
msp=msp,
teileid=teileid,
merkmale=merkmale,
x=x,
y=y,
doc=doc,
lib_doc=lib_doc,
verbose=verbose,
symbols=symbols if symbols is not None else [],
strecken_nachbarn=strecken_nachbarn,
config=config,
config_allgemein=config_allgemein,
)
+1 -1
View File
@@ -7,7 +7,7 @@ def inspect_blocks(dxf_path):
print(f"Datei: {dxf_path}")
print("Gefundene Blöcke und Attribute:\n")
for block in doc.blocks:
if block.name.startswith('*'): # Überspringe anonyme/Standardblöcke
if block.name.startswith("*"): # Überspringe anonyme/Standardblöcke
continue
print(f"Block: {block.name}")
attribs = [e for e in block if e.dxftype() == "ATTDEF"]
+1049 -315
View File
File diff suppressed because it is too large Load Diff
+196 -51
View File
@@ -4,6 +4,7 @@ import difflib
from utils import check_environment_var, setup_logger
import plant2dxf
class TestDXFGeometry(unittest.TestCase):
testordner_path = Path(check_environment_var("PROJECT_TEST"))
lib_path = Path(check_environment_var("PROJECT_DATA"))
@@ -13,7 +14,25 @@ class TestDXFGeometry(unittest.TestCase):
cfg_path = config_dir / "shapes.cfg"
allgemein_cfg_path = config_dir / "allgemein.cfg"
GEOM_CODES = {"0", "8", "10", "20", "30", "11", "21", "31", "41", "42", "43", "70", "71", "72", "73", "74", "75"}
GEOM_CODES = {
"0",
"8",
"10",
"20",
"30",
"11",
"21",
"31",
"41",
"42",
"43",
"70",
"71",
"72",
"73",
"74",
"75",
}
def extract_geometry_lines(self, file_path):
"""
@@ -39,125 +58,251 @@ class TestDXFGeometry(unittest.TestCase):
geom1 = self.extract_geometry_lines(file1)
geom2 = self.extract_geometry_lines(file2)
if geom1 != geom2:
diff = "".join(difflib.unified_diff(geom1, geom2, fromfile=str(file1), tofile=str(file2)))
diff = "".join(
difflib.unified_diff(
geom1, geom2, fromfile=str(file1), tofile=str(file2)
)
)
raise AssertionError(f"Geometrische Daten unterscheiden sich:\n{diff}")
def test_omniflobogen_dxf_file(self):
omniflo_bogen = "omniflo_bogen"
omniflo_bogen_csv = self.testordner_path / f"{omniflo_bogen}.csv"
omniflo_bogen_dxf = f"{omniflo_bogen}.dxf"
omniflo_bogen_jason = self.work_dir / f"{omniflo_bogen}.jason"
omniflo_bogen_json = self.work_dir / f"{omniflo_bogen}.json"
omniflo_bogen_output = self.work_dir / omniflo_bogen_dxf
omniflo_bogen_reference = self.testordner_path / omniflo_bogen_dxf
plant2dxf.main(omniflo_bogen_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, omniflo_bogen_output,omniflo_bogen_jason)
plant2dxf.main(
omniflo_bogen_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
omniflo_bogen_output,
omniflo_bogen_json,
)
self.assert_dxf_geometry_equal(omniflo_bogen_output, omniflo_bogen_reference)
def test_weiche_90_dxf_file(self):
weiche_90 = "weiche_90"
weiche_90_csv = self.testordner_path / f"{weiche_90}.csv"
weiche_90_dxf = f"{weiche_90}.dxf"
weiche_90_jason = self.work_dir /f"{weiche_90}.jason"
weiche_90_json = self.work_dir / f"{weiche_90}.json"
weiche_90_output = self.work_dir / weiche_90_dxf
weiche_90_reference = self.testordner_path / weiche_90_dxf
plant2dxf.main(weiche_90_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weiche_90_output,weiche_90_jason)
plant2dxf.main(
weiche_90_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
weiche_90_output,
weiche_90_json,
)
self.assert_dxf_geometry_equal(weiche_90_output, weiche_90_reference)
def test_weiche_45_simple_dxf_file(self):
weiche_45_simple = "weiche_45_simple"
weiche_45_simple_csv = self.testordner_path / f"{weiche_45_simple}.csv"
weiche_45_simple_dxf = f"{weiche_45_simple}.dxf"
weiche_45_simple_jason = self.work_dir/ f"{weiche_45_simple}.jason"
weiche_45_simple_json = self.work_dir / f"{weiche_45_simple}.json"
weiche_45_simple_output = self.work_dir / weiche_45_simple_dxf
weiche_45_simple_reference = self.testordner_path / weiche_45_simple_dxf
plant2dxf.main(weiche_45_simple_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weiche_45_simple_output,weiche_45_simple_jason)
self.assert_dxf_geometry_equal(weiche_45_simple_output, weiche_45_simple_reference)
plant2dxf.main(
weiche_45_simple_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
weiche_45_simple_output,
weiche_45_simple_json,
)
self.assert_dxf_geometry_equal(
weiche_45_simple_output, weiche_45_simple_reference
)
def test_weiche_45_doppel_dxf_file(self):
weiche_45_doppel = "weiche_45_doppel"
weiche_45_doppel_csv = self.testordner_path / f"{weiche_45_doppel}.csv"
weiche_45_doppel_dxf = f"{weiche_45_doppel}.dxf"
weiche_45_doppel_jason = self.work_dir /f"{weiche_45_doppel}.jason"
weiche_45_doppel_json = self.work_dir / f"{weiche_45_doppel}.json"
weiche_45_doppel_output = self.work_dir / weiche_45_doppel_dxf
weiche_45_doppel_reference = self.testordner_path / weiche_45_doppel_dxf
plant2dxf.main(weiche_45_doppel_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weiche_45_doppel_output,weiche_45_doppel_jason)
self.assert_dxf_geometry_equal(weiche_45_doppel_output, weiche_45_doppel_reference)
plant2dxf.main(
weiche_45_doppel_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
weiche_45_doppel_output,
weiche_45_doppel_json,
)
self.assert_dxf_geometry_equal(
weiche_45_doppel_output, weiche_45_doppel_reference
)
def test_weiche_45_dreiwege_dxf_file(self):
weiche_45_dreiwege = "weiche_45_dreiwege"
weiche_45_dreiwege_csv = self.testordner_path / f"{weiche_45_dreiwege}.csv"
weiche_45_dreiwege_dxf = f"{weiche_45_dreiwege}.dxf"
weiche_45_dreiwege_jason = self.work_dir /f"{weiche_45_dreiwege}.jason"
weiche_45_dreiwege_json = self.work_dir / f"{weiche_45_dreiwege}.json"
weiche_45_dreiwege_output = self.work_dir / weiche_45_dreiwege_dxf
weiche_45_dreiwege_reference = self.testordner_path / weiche_45_dreiwege_dxf
plant2dxf.main(weiche_45_dreiwege_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weiche_45_dreiwege_output,weiche_45_dreiwege_jason)
self.assert_dxf_geometry_equal(weiche_45_dreiwege_output, weiche_45_dreiwege_reference)
plant2dxf.main(
weiche_45_dreiwege_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
weiche_45_dreiwege_output,
weiche_45_dreiwege_json,
)
self.assert_dxf_geometry_equal(
weiche_45_dreiwege_output, weiche_45_dreiwege_reference
)
def test_weichenkoerper_dxf_file(self):
weichenkoerper = "weichenkoerper"
weichenkoerper_csv = self.testordner_path / f"{weichenkoerper}.csv"
weichenkoerper_dxf = f"{weichenkoerper}.dxf"
weichenkoerper_jason = self.work_dir /f"{weichenkoerper}.jason"
weichenkoerper_json = self.work_dir / f"{weichenkoerper}.json"
weichenkoerper_output = self.work_dir / weichenkoerper_dxf
weichenkoerper_reference = self.testordner_path / weichenkoerper_dxf
plant2dxf.main(weichenkoerper_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weichenkoerper_output,weichenkoerper_jason)
plant2dxf.main(
weichenkoerper_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
weichenkoerper_output,
weichenkoerper_json,
)
self.assert_dxf_geometry_equal(weichenkoerper_output, weichenkoerper_reference)
def test_weichenkombination_dxf_file(self):
weichenkombination = "weichenkombination"
weichenkombination_csv = self.testordner_path / f"{weichenkombination}.csv"
weichenkombination_dxf = f"{weichenkombination}.dxf"
weichenkombination_jason = self.work_dir /f"{weichenkombination}.jason"
weichenkombination_json = self.work_dir / f"{weichenkombination}.json"
weichenkombination_output = self.work_dir / weichenkombination_dxf
weichenkombination_reference = self.testordner_path / weichenkombination_dxf
plant2dxf.main(weichenkombination_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weichenkombination_output,weichenkombination_jason)
self.assert_dxf_geometry_equal(weichenkombination_output, weichenkombination_reference)
plant2dxf.main(
weichenkombination_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
weichenkombination_output,
weichenkombination_json,
)
self.assert_dxf_geometry_equal(
weichenkombination_output, weichenkombination_reference
)
def test_gefaelle_dxf_file(self):
gefaelle = "gefaelle"
gefaelle_csv = self.testordner_path / f"{gefaelle}.csv"
gefaelle_dxf = f"{gefaelle}.dxf"
gefaelle_jason = self.work_dir /f"{gefaelle}.jason"
gefaelle_json = self.work_dir / f"{gefaelle}.json"
weichenkombination_output = self.work_dir / gefaelle_dxf
weichenkombination_reference = self.testordner_path / gefaelle_dxf
plant2dxf.main(gefaelle_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, weichenkombination_output,gefaelle_jason)
self.assert_dxf_geometry_equal(weichenkombination_output, weichenkombination_reference)
plant2dxf.main(
gefaelle_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
weichenkombination_output,
gefaelle_json,
)
self.assert_dxf_geometry_equal(
weichenkombination_output, weichenkombination_reference
)
def test_gefaelle_ausnahme_gleiche_orientierung_dxf_file(self):
gefaelle_ausnahme_gleiche_orientierung= "gefaelle_ausnahme_gleiche_orientierung"
gefaelle_ausnahme_gleiche_orientierung_csv = self.testordner_path / f"{gefaelle_ausnahme_gleiche_orientierung}.csv"
gefaelle_ausnahme_gleiche_orientierung_dxf = f"{gefaelle_ausnahme_gleiche_orientierung}.dxf"
gefaelle_ausnahme_gleiche_orientierung_jason = self.work_dir /f"{gefaelle_ausnahme_gleiche_orientierung}.jason"
gefaelle_ausnahme_gleiche_orientierung_output = self.work_dir / gefaelle_ausnahme_gleiche_orientierung_dxf
gefaelle_ausnahme_gleiche_orientierung_reference = self.testordner_path / gefaelle_ausnahme_gleiche_orientierung_dxf
plant2dxf.main(gefaelle_ausnahme_gleiche_orientierung_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, gefaelle_ausnahme_gleiche_orientierung_output,gefaelle_ausnahme_gleiche_orientierung_jason)
self.assert_dxf_geometry_equal(gefaelle_ausnahme_gleiche_orientierung_output, gefaelle_ausnahme_gleiche_orientierung_reference)
gefaelle_ausnahme_gleiche_orientierung = (
"gefaelle_ausnahme_gleiche_orientierung"
)
gefaelle_ausnahme_gleiche_orientierung_csv = (
self.testordner_path / f"{gefaelle_ausnahme_gleiche_orientierung}.csv"
)
gefaelle_ausnahme_gleiche_orientierung_dxf = (
f"{gefaelle_ausnahme_gleiche_orientierung}.dxf"
)
gefaelle_ausnahme_gleiche_orientierung_json = (
self.work_dir / f"{gefaelle_ausnahme_gleiche_orientierung}.json"
)
gefaelle_ausnahme_gleiche_orientierung_output = (
self.work_dir / gefaelle_ausnahme_gleiche_orientierung_dxf
)
gefaelle_ausnahme_gleiche_orientierung_reference = (
self.testordner_path / gefaelle_ausnahme_gleiche_orientierung_dxf
)
plant2dxf.main(
gefaelle_ausnahme_gleiche_orientierung_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
gefaelle_ausnahme_gleiche_orientierung_output,
gefaelle_ausnahme_gleiche_orientierung_json,
)
self.assert_dxf_geometry_equal(
gefaelle_ausnahme_gleiche_orientierung_output,
gefaelle_ausnahme_gleiche_orientierung_reference,
)
def test_gefaelle_ausnahme_unterschiedlich_orientierung_dxf_file(self):
gefaelle_ausnahme_unterschiedlich_orientierung= "gefaelle_ausnahme_unterschiedlich_orientierung"
gefaelle_ausnahme_unterschiedlich_orientierung_csv = self.testordner_path / f"{gefaelle_ausnahme_unterschiedlich_orientierung}.csv"
gefaelle_ausnahme_unterschiedlich_orientierung_dxf = f"{gefaelle_ausnahme_unterschiedlich_orientierung}.dxf"
gefaelle_ausnahme_unterschiedlich_orientierung_jason = self.work_dir /f"{gefaelle_ausnahme_unterschiedlich_orientierung}.jason"
gefaelle_ausnahme_unterschiedlich_orientierung_output = self.work_dir / gefaelle_ausnahme_unterschiedlich_orientierung_dxf
gefaelle_ausnahme_unterschiedlich_orientierung_reference = self.testordner_path / gefaelle_ausnahme_unterschiedlich_orientierung_dxf
plant2dxf.main(gefaelle_ausnahme_unterschiedlich_orientierung_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, gefaelle_ausnahme_unterschiedlich_orientierung_output,gefaelle_ausnahme_unterschiedlich_orientierung_jason)
self.assert_dxf_geometry_equal(gefaelle_ausnahme_unterschiedlich_orientierung_output, gefaelle_ausnahme_unterschiedlich_orientierung_reference)
gefaelle_ausnahme_unterschiedlich_orientierung = (
"gefaelle_ausnahme_unterschiedlich_orientierung"
)
gefaelle_ausnahme_unterschiedlich_orientierung_csv = (
self.testordner_path
/ f"{gefaelle_ausnahme_unterschiedlich_orientierung}.csv"
)
gefaelle_ausnahme_unterschiedlich_orientierung_dxf = (
f"{gefaelle_ausnahme_unterschiedlich_orientierung}.dxf"
)
gefaelle_ausnahme_unterschiedlich_orientierung_json = (
self.work_dir / f"{gefaelle_ausnahme_unterschiedlich_orientierung}.json"
)
gefaelle_ausnahme_unterschiedlich_orientierung_output = (
self.work_dir / gefaelle_ausnahme_unterschiedlich_orientierung_dxf
)
gefaelle_ausnahme_unterschiedlich_orientierung_reference = (
self.testordner_path / gefaelle_ausnahme_unterschiedlich_orientierung_dxf
)
plant2dxf.main(
gefaelle_ausnahme_unterschiedlich_orientierung_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
gefaelle_ausnahme_unterschiedlich_orientierung_output,
gefaelle_ausnahme_unterschiedlich_orientierung_json,
)
self.assert_dxf_geometry_equal(
gefaelle_ausnahme_unterschiedlich_orientierung_output,
gefaelle_ausnahme_unterschiedlich_orientierung_reference,
)
def test_gefaelle_einzeln_verbunden_dxf_file(self):
gefaelle_einzeln_verbunden = "gefaelle_einzeln_verbunden"
gefaelle_einzeln_verbunden_csv = self.testordner_path / f"{gefaelle_einzeln_verbunden}.csv"
gefaelle_einzeln_verbunden_csv = (
self.testordner_path / f"{gefaelle_einzeln_verbunden}.csv"
)
gefaelle_einzeln_verbunden_dxf = f"{gefaelle_einzeln_verbunden}.dxf"
gefaelle_einzeln_verbunden_jason = self.work_dir /f"{gefaelle_einzeln_verbunden}.jason"
gefaelle_einzeln_verbunden_output = self.work_dir / gefaelle_einzeln_verbunden_dxf
gefaelle_einzeln_verbunden_reference = self.testordner_path / gefaelle_einzeln_verbunden_dxf
plant2dxf.main(gefaelle_einzeln_verbunden_csv , self.default_lib_path, self.cfg_path, self.allgemein_cfg_path, gefaelle_einzeln_verbunden_output,gefaelle_einzeln_verbunden_jason)
self.assert_dxf_geometry_equal(gefaelle_einzeln_verbunden_output, gefaelle_einzeln_verbunden_reference)
gefaelle_einzeln_verbunden_json = (
self.work_dir / f"{gefaelle_einzeln_verbunden}.json"
)
gefaelle_einzeln_verbunden_output = (
self.work_dir / gefaelle_einzeln_verbunden_dxf
)
gefaelle_einzeln_verbunden_reference = (
self.testordner_path / gefaelle_einzeln_verbunden_dxf
)
plant2dxf.main(
gefaelle_einzeln_verbunden_csv,
self.default_lib_path,
self.cfg_path,
self.allgemein_cfg_path,
gefaelle_einzeln_verbunden_output,
gefaelle_einzeln_verbunden_json,
)
self.assert_dxf_geometry_equal(
gefaelle_einzeln_verbunden_output, gefaelle_einzeln_verbunden_reference
)
if __name__ == "__main__":
unittest.main()
+4 -3
View File
@@ -14,7 +14,7 @@ def check_environment_var(env_str: str) -> Path:
sys.exit(1)
def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
def setup_logger(log_dir: Path, name: str = "app") -> logging.Logger:
"""
Erstellt und konfiguriert einen Logger, der sowohl in eine Datei als auch auf die Konsole schreibt.
Die Logdatei erhält einen Zeitstempel im Namen und ist UTF-8 kodiert.
@@ -26,6 +26,7 @@ def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
logging.Logger: Konfigurierter Logger
"""
from datetime import datetime
logger = logging.getLogger(name)
logger.setLevel(logging.INFO)
@@ -38,7 +39,7 @@ def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
# Logdatei mit Zeitstempel im Namen erzeugen
log_file = log_dir / f"{name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}.log"
file_handler = logging.FileHandler(log_file, encoding='utf-8')
file_handler = logging.FileHandler(log_file, encoding="utf-8")
file_handler.setLevel(logging.INFO)
# Handler für die Konsole
@@ -46,7 +47,7 @@ def setup_logger(log_dir: Path, name: str = 'app') -> logging.Logger:
console_handler.setLevel(logging.INFO)
# Einheitliches Log-Format definieren
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)