197 lines
6.5 KiB
Python
197 lines
6.5 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
Omniflo — Modell und Erstellungsfunktionen für Omniflo-Kettenförderer.
|
|
|
|
Refactoring-Änderungen:
|
|
- 8x try/except-Boilerplate durch _safe_float/_safe_int Hilfsfunktionen ersetzt
|
|
- @staticmethod auf Omniflo_geraden_erstellung und omniflo_foerdererstellung
|
|
- Bug fix: omniflo_foerdererstellung nutzte rotation (Grad) statt winkel_rad in sin/cos
|
|
- Duplizierte dx/dy-Berechnung vereinheitlicht
|
|
"""
|
|
import math
|
|
|
|
from ezdxf.entities import Line
|
|
from pydantic import BaseModel, Field
|
|
from typing import Optional
|
|
|
|
from lib import block_methoden
|
|
|
|
|
|
# ============================================================================
|
|
# HILFSFUNKTIONEN
|
|
# ============================================================================
|
|
|
|
|
|
def _safe_float(value, default=0.0):
|
|
"""
|
|
Konvertiert einen Wert zu float mit Fallback.
|
|
|
|
Behandelt automatisch Komma-als-Dezimaltrennzeichen (z.B. "3,5" → 3.5).
|
|
|
|
Args:
|
|
value: Zu konvertierender Wert (str, int, float oder None)
|
|
default: Rückgabewert bei Konvertierungsfehler
|
|
|
|
Returns:
|
|
Float-Wert oder default
|
|
"""
|
|
try:
|
|
if value is None:
|
|
return default
|
|
if isinstance(value, str):
|
|
value = value.replace(",", ".")
|
|
return float(value)
|
|
except (TypeError, ValueError):
|
|
return default
|
|
|
|
|
|
def _safe_int(value, default=0):
|
|
"""
|
|
Konvertiert einen Wert zu int mit Fallback (über float-Zwischenschritt).
|
|
|
|
Args:
|
|
value: Zu konvertierender Wert
|
|
default: Rückgabewert bei Konvertierungsfehler
|
|
|
|
Returns:
|
|
Int-Wert oder default
|
|
"""
|
|
try:
|
|
if value is None:
|
|
return default
|
|
return int(float(value))
|
|
except (TypeError, ValueError):
|
|
return default
|
|
|
|
|
|
# ============================================================================
|
|
# OMNIFLO KLASSE
|
|
# ============================================================================
|
|
|
|
|
|
class Omniflo(BaseModel):
|
|
"""Modell für Omniflo-Kettenförderer."""
|
|
|
|
teileid: str
|
|
x: float
|
|
y: float
|
|
sivasnummer: str
|
|
laenge: Optional[float]
|
|
drehung: float
|
|
hoehe: Optional[float]
|
|
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"
|
|
)
|
|
|
|
@property
|
|
def hight_zwischen(self):
|
|
"""Mittlere Höhe zwischen h0 und h1."""
|
|
return (self.h0 + self.h1) / 2
|
|
|
|
@classmethod
|
|
def from_merkmale(cls, teileid, x, y, merkmale):
|
|
"""
|
|
Erstellt Omniflo aus einem Merkmale-Dictionary.
|
|
|
|
Verwendet _safe_float/_safe_int für robuste Konvertierung
|
|
statt 8x wiederholtem try/except-Muster.
|
|
|
|
Args:
|
|
teileid: Teile-Identifikator
|
|
x, y: Koordinaten in mm
|
|
merkmale: Dictionary mit Eigenschaftswerten
|
|
|
|
Returns:
|
|
Omniflo-Instanz
|
|
"""
|
|
return cls(
|
|
teileid=teileid,
|
|
x=x,
|
|
y=y,
|
|
sivasnummer=merkmale.get("SivasNummer"),
|
|
laenge=_safe_float(merkmale.get("Länge in Meter"), 0.0) * 1000, # Meter → mm
|
|
drehung=_safe_float(merkmale.get("Drehung"), 0.0),
|
|
hoehe=_safe_float(merkmale.get("Höhe"), 0.0),
|
|
h0=_safe_float(merkmale.get("Höhe unten"), 0.0),
|
|
h1=_safe_float(merkmale.get("Höhe oben"), 0.0),
|
|
anzahl_scanner=_safe_int(merkmale.get("Anzahl der Scanner"), 0),
|
|
anzahl_stopper=_safe_int(merkmale.get("Anzahl der Separatoren"), 0),
|
|
)
|
|
|
|
@staticmethod
|
|
def Omniflo_geraden_erstellung(msp, doc, tefsivas, omniflo_objekt):
|
|
"""
|
|
Erstellung der Tef gerade und Omniflo gerade.
|
|
|
|
Zeichnet eine Linie zwischen Start- und Endpunkt basierend auf
|
|
Länge und Drehung des Omniflo-Objekts.
|
|
|
|
Args:
|
|
msp: DXF-Modelspace
|
|
doc: DXF-Dokument
|
|
tefsivas: Sivas-Nummer der Tef-Strecke
|
|
omniflo_objekt: Omniflo-Instanz
|
|
"""
|
|
winkel_rad = math.radians(omniflo_objekt.drehung)
|
|
halbe_laenge = omniflo_objekt.laenge / 2
|
|
x = omniflo_objekt.x
|
|
y = omniflo_objekt.y
|
|
# Koordinatensystem: sin mit -1 wegen links-Koordinatensystem
|
|
dx = halbe_laenge * math.sin(winkel_rad * -1)
|
|
dy = halbe_laenge * math.cos(winkel_rad)
|
|
start = (x + dx, y + dy, omniflo_objekt.h1)
|
|
ende = (x - dx, y - dy, omniflo_objekt.h0)
|
|
if "A-2" not in doc.layers:
|
|
doc.layers.add(name="A-2", color=2)
|
|
if "F-1" not in doc.layers:
|
|
doc.layers.add(name="F-1", color=1)
|
|
linie = msp.add_line(start, ende)
|
|
if omniflo_objekt.sivasnummer == tefsivas:
|
|
linie.dxf.layer = "F-1"
|
|
else:
|
|
linie.dxf.layer = "A-2"
|
|
|
|
@staticmethod
|
|
def omniflo_foerdererstellung(msp, doc, lib_doc, omniflo_objekt):
|
|
"""
|
|
Erstellung des Kettenförderers (aktuell nur Grundriss).
|
|
|
|
Args:
|
|
msp: DXF-Modelspace
|
|
doc: DXF-Dokument
|
|
lib_doc: Bibliotheks-Dokument
|
|
omniflo_objekt: Omniflo-Instanz
|
|
"""
|
|
block_methoden.import_block("bogen1", lib_doc, doc)
|
|
block_methoden.import_block("bogen2", lib_doc, doc)
|
|
x = omniflo_objekt.x
|
|
y = omniflo_objekt.y
|
|
rotation = omniflo_objekt.drehung
|
|
laenge = omniflo_objekt.laenge
|
|
h0 = omniflo_objekt.h0
|
|
h1 = omniflo_objekt.h1
|
|
h_zwischen = omniflo_objekt.hight_zwischen
|
|
blockname = f"OF_Förderer_{laenge}_{h_zwischen}"
|
|
winkel_rad = math.radians(rotation)
|
|
halbe_laenge = laenge / 2
|
|
# BUG FIX: war `math.sin(rotation * -1)` — rotation ist in Grad!
|
|
# Muss winkel_rad (Radianten) verwenden wie in Omniflo_geraden_erstellung
|
|
dx = halbe_laenge * math.sin(winkel_rad * -1)
|
|
dy = halbe_laenge * math.cos(winkel_rad)
|
|
start = (x + dx, y + dy, h1)
|
|
ende = (x - dx, y - dy, h0)
|
|
if blockname not in doc.blocks:
|
|
block = doc.blocks.new(blockname, base_point=(0, 0, 0))
|
|
block.add_blockref("bogen1", start)
|
|
block.add_blockref("bogen2", ende)
|
|
line = Line.new(dxfattribs={"start": start, "end": ende})
|
|
copy = line.copy()
|
|
copy.translate(-x, -y, -h_zwischen)
|
|
block.add_entity(copy)
|
|
msp.add_blockref(
|
|
blockname, (x, y, h_zwischen), dxfattribs={"rotation": rotation}
|
|
)
|