Files
plant2dxf/doc/plant2dxf_dokumentation.md
T

32 KiB

plant2dxf - Dokumentation

⚠️ Wichtiger Hinweis

Zukünftige Anpassungen erforderlich:

Aufgrund möglicher Änderungen im CSV-Dateiformat von RuleDesigner müssen in Zukunft möglicherweise folgende Berechnungen und Logiken angepasst werden:

AS/ES-Element-Berechnungen

Die Logik zur Bestimmung und Platzierung von AS- und ES-Elementen bei Gefällestrecken und Vario-Förderern basiert auf dem aktuellen CSV-Format. Bei Änderungen der Datenstruktur oder der verfügbaren Informationen müssen folgende Methoden in as_es_methoden.py überprüft und angepasst werden:

  • erstellung_gefaelle_block_verbunden_an_einen(): Erstellt AS/ES-Elemente für Gefällestrecken, die mit einem Kreisel verbunden sind
  • gefaellegerade_erstellung(): Erstellt AS/ES-Elemente für Gefällestrecken, die mit zwei Kreiseln verbunden sind
  • am_kreisel_direct_verbunden(): Prüft, ob eine Gefällestrecke/Vario-Förderer direkt mit einem Kreisel verbunden ist (ohne Stahlband)

Höhenvergleiche für Kreisel-Logik

Die Höhenvergleiche zur Bestimmung der Verbindungsart zwischen Gefällestrecken/Vario-Förderern und Kreiseln (z.B. ob die Gefällestrecke mit dem höheren oder niedrigeren Teil des Kreisels verbunden ist) basieren auf den aktuellen CSV-Datenfeldern. Änderungen in der Struktur der Höheninformationen erfordern Anpassungen in:

Handler-Funktionen (lib/plant2dxf.py):

  • handle_ils_2_0_gefaellestrecke(): Haupt-Handler für Gefällestrecken
  • handle_ils_2_0_variofoerderer(): Haupt-Handler für Vario-Förderer

Gefällestrecke-Methoden (lib/Elemente/Gefaellestrecke.py):

  • rotation_mit_zwei_verbunden(): Berechnet Rotation bei Verbindung mit zwei Kreiseln (verwendet Höhenvergleiche)

Vario-Förderer-Methoden (lib/Elemente/VarioFoerderer.py):

  • vario_verbuden_am_kreisel(): Erstellt Gefällestrecken-Komponenten bei direkter Kreisel-Verbindung (verwendet Höhenvergleiche mit Kreiseln)

Betroffene Dateien:

  • lib/as_es_methoden.py: AS/ES-Element-Berechnungen
  • lib/plant2dxf.py: Handler-Funktionen für Gefällestrecken und Vario-Förderer
  • lib/Elemente/Gefaellestrecke.py: Höhenvergleiche und Verbindungslogik
  • lib/Elemente/VarioFoerderer.py: Höhenvergleiche und Verbindungslogik

Übersicht

plant2dxf ist ein Python-Skript, das aus einer RuleDesigner-CSV-Datei DXF-Elemente erzeugt. Das Skript liest eine CSV-Datei mit Angaben über alle in einer Anlage enthaltenen Elemente und generiert daraus eine DXF-Datei der kompletten Anlage.

Hauptfunktionalität

Das Skript verarbeitet CSV-Dateien mit folgenden Informationen:

  • TeileArt: Typ der Komponente (z.B. "ILS 2.0 Kreisel", "ILS 2.0 Gefällestrecke")
  • TeileId: Eindeutige Identifikation des Elements
  • Planquadrat: Koordinaten im Format X:<Wert> Y:<Wert>
  • Merkmale: JSON-String mit spezifischen Eigenschaften des Elements
  • NachbarIds: Kommagetrennte Liste von IDs benachbarter Elemente

Benötigte Dateien und Verzeichnisse

Umgebungsvariablen

Das Skript benötigt folgende Umgebungsvariablen (werden durch bin/setenv.bat gesetzt):

  • PROJECT_DATA: Verzeichnis für Bibliotheksdateien (DXF-Blockbibliotheken)

    • Standard: <PROJECT>/data
    • Enthält Unterverzeichnis block_libraries/ mit DXF-Bibliotheken
  • PROJECT_WORK: Arbeitsverzeichnis für CSV-Eingabedateien und DXF-Ausgabedateien

    • Standard: <PROJECT>/work
  • PROJECT_CFG: Verzeichnis für Konfigurationsdateien

    • Standard: <PROJECT>/cfg
    • Enthält: allgemein.cfg, shapes.cfg
  • PROJECT_LOG: Verzeichnis für Log-Dateien

    • Standard: <PROJECT>/log

Konfigurationsdateien

1. cfg/allgemein.cfg

Allgemeine Konfigurationsdatei, die die Zuweisung von Block-Bibliotheken zu bestimmten Bauteil-Familien steuert.

Struktur:

[LOG]
log_level = INFO
log_format = %%(asctime)s - %%(levelname)s - %%(message)s
screen_format = %%(message)s

[ILS]
libfile = ils_lib.dxf

[Omniflo]
libfile = omniflo_lib.dxf

[BT]
libfile = ils_lib.dxf

[TEF]
libfile = omniflo_lib.dxf

Zweck:

  • Definiert, welche DXF-Bibliotheksdatei für welche TeileArt verwendet wird
  • Bibliotheksdateien werden aus PROJECT_DATA/block_libraries/ geladen
  • Falls keine Zuordnung gefunden wird, wird die Standard-Bibliothek (blocks.dxf) verwendet

2. cfg/shapes.cfg

Definiert für jede TeileArt die zu verwendenden Blöcke aus der Bibliotheks-DXF und deren Eigenschaften.

Struktur:

[ILS 2.0 Kreisel]
items = SP8, AN8
offset_symb1 = 0,0
offset_symb2 = 0,0
rot_symb1 = 0.0
rot_symb2 = 0.0

[ILS 2.0 Gefällestrecke]
items = EE DS, AE DS
offset_symb1 = 0,-330
offset_symb2 = 0,1000
rot_symb1 = 0.0
rot_symb2 = 0.0
asoffset = 537.90 
esoffset = 479.95

[ILS 2.0 Variofoerderer]
Umlenkstation = 500.0, 0.0, 0.0
Motorstation = 500.0, 0.0, 0.0
vario_abstand = 66.5

[Ils 2.0 core winkel]
winkel_boegen = 3
winkel_motor = 3.0
winkel_umlenk = 3.0
winkel_as = 3.0
winkel_es = 3.0

[Omniflo]
OFgeradesivas = 821106002
Tefgeradesivas = 0_B10030
OFfoerderer = 2

Parameter:

  • [TeileArt]: Abschnittsname muss exakt dem Wert aus der CSV-Spalte TeileArt entsprechen
  • items: Kommagetrennte Liste der Blocknamen aus der Bibliothek
  • offset_symbX: Offset (x,y) für den X-ten Block relativ zur berechneten Position
  • rot_symbX: Rotation (in Grad) für den X-ten Block
  • asoffset/esoffset: Offsets für AS/ES-Elemente bei Gefällestrecken
  • winkel_*: Winkel für verschiedene Komponenten (Bögen, Motor, Umlenkstation, AS/ES)

DXF-Bibliotheken

DXF-Bibliotheken enthalten die Blockdefinitionen für die verschiedenen Komponenten. Sie werden aus PROJECT_DATA/block_libraries/ geladen.

Bibliotheksdateien:

  • ils_lib.dxf: Blöcke für ILS 2.0 Komponenten
  • omniflo_lib.dxf: Blöcke für Omniflo-Komponenten
  • blocks.dxf: Standard-Bibliothek (Fallback)

Wichtige Blöcke:

  • SCAN: Scanner-Block
  • S-LP: Separator-Block
  • Pinbereich: Pinbereich-Block für Kreisel
  • AN8, SP8: Standard-Blöcke für Kreisel
  • 200000241_AS-Element_90_rechts, 200000217_AS-Element_90_links: AS-Elemente
  • 200000146_ES-Element_90_rechts, 400102632_ES-Element_90_links: ES-Elemente
  • Verschiedene Omniflo-Blöcke (identifiziert über SivasNummer)

Unterstützte Elementtypen

1. ILS 2.0 Kreisel

Handler: handle_ils_2_0_kreisel()

Funktionalität:

  • Erstellt einen Kreisel mit Scanner und Separatoren
  • Positioniert Blöcke basierend auf Anzahl der Scanner/Separatoren
  • Zeichnet Kreisel-Linien und Drehrichtung-Markierung
  • Verwendet Blöcke aus shapes.cfg (z.B. SP8, AN8)

Merkmale:

  • Abstand (Kreiselachse A - Kreiselachse) in Meter: Abstand zwischen den beiden Kreiselachsen
  • Anzahl der Separatoren: Anzahl der Separator-Blöcke
  • Anzahl der Scanner: Anzahl der Scanner-Blöcke
  • Anzahl der Rampen: Anzahl der Rampen
  • Höhe in m: Höhe des Kreisels
  • Drehrichtung: UZS (Uhrzeigersinn) oder GUZS (Gegen-Uhrzeigersinn)

2. ILS 2.0 Gefällestrecke

Handler: handle_ils_2_0_gefaellestrecke()

Funktionalität:

  • Erstellt eine Gefällestrecke zwischen verschiedenen Höhen
  • Berücksichtigt Verbindungen zu Kreiseln, Kurven und anderen Elementen
  • Fügt AS/ES-Elemente ein, wenn nötig
  • Erstellt Blöcke dynamisch basierend auf Verbindungen

Merkmale:

  • Länge in Meter: Länge der Gefällestrecke
  • Höhe Anfang: Start-Höhe in Metern
  • Höhe Ende: End-Höhe in Metern
  • Drehung: Rotation der Strecke
  • Anzahl der Zusatzseparatoren: Zusätzliche Separatoren

Besonderheiten:

  • Unterscheidet zwischen Verbindung mit einem oder zwei Kreiseln
  • Prüft, ob direkte Verbindung zum Kreisel (ohne Stahlband)
  • Fügt Motor-/Umlenkstationen ein, wenn mit angetriebenen Kurven verbunden
  • Erstellt AS/ES-Elemente basierend auf Drehrichtung der benachbarten Kreisel

3. ILS 2.0 VarioFoerderer

Handler: handle_ils_2_0_variofoerderer()

Funktionalität:

  • Erstellt einen Vario-Förderer mit verschiedenen Konfigurationen
  • Unterstützt Verbindungen zu Kreiseln, Eckrädern und anderen Vario-Förderern
  • Berücksichtigt Motor- und Umlenkstationen
  • Erstellt Gefälle-Komponenten innerhalb des Förderers

Merkmale:

  • Winkel: Winkel des Förderers
  • Förderrichtung: Auf, Ab oder Horizontal
  • Motorseite: links oder rechts
  • Höhe Anfang, Höhe Ende: Höhen der Endpunkte
  • Gefälle: Gefälle-Länge und -Winkel
  • Motor vorhanden, Umlenk vorhanden: Boolean-Werte

Besonderheiten:

  • Unterscheidet zwischen Verbindung mit einem oder zwei Kreiseln/Eckrädern
  • Erstellt spezielle Blöcke für direkte Kreisel-Verbindungen
  • Berücksichtigt horizontale Ausrichtung bei Eckrad-Verbindungen
  • Fügt Gefällestrecken ein, wenn mit Kreiseln verbunden

4. ILS 2.0 Kurve angetrieben

Handler: handle_ils_2_0_kurve_angetrieben()

Funktionalität:

  • Erstellt eine angetriebene Kurve (Förderer-Kurve)
  • Verwendet Blocknamen basierend auf Kurvenrichtung, Winkel und Antrieb

Merkmale:

  • Kurvenrichtung: Links oder Rechts
  • Kurvenwinkel: Winkel der Kurve in Grad
  • Antrieb: TEF-Kurve oder ähnlich
  • Höhe Anfang, Höhe Ende: Höhen der Endpunkte

5. ILS 2.0 Kurve (Gefälle-Kurve)

Handler: handle_ils_2_0_kurve()

Funktionalität:

  • Erstellt eine Gefälle-Kurve
  • Verwendet Blocknamen basierend auf Kurvenrichtung und Winkel

Merkmale:

  • Kurvenrichtung: Links oder Rechts
  • Kurvenwinkel: Winkel der Kurve in Grad
  • Höhe Anfang, Höhe Ende: Höhen der Endpunkte

6. ILS 2.0 Eckrad

Handler: handle_ils_2_0_eckrad()

Funktionalität:

  • Erstellt ein Eckrad basierend auf Drehrichtung
  • Verwendet unterschiedliche Blöcke für UZS/GUZS

Merkmale:

  • Drehrichtung: UZS oder GUZS
  • Höhe: Höhe des Eckrads

7. BT Elemente (Beladung/Entladung)

Handler: handle_bt___beladung(), handle_bt___entladung()

Funktionalität:

  • Erstellt BT-Elemente für Beladung oder Entladung
  • Verwendet Standard-Block "AN8"

Merkmale:

  • Höhe: Höhe des Elements
  • Drehung: Rotation

8. Omniflo

Handler: handle_omniflo()

Funktionalität:

  • Erstellt Omniflo-Komponenten basierend auf SivasNummer
  • Unterstützt Geraden, Förderer und spezielle Blöcke
  • Verwendet Blocknamen direkt aus der SivasNummer

Merkmale:

  • SivasNummer: Identifikation des Omniflo-Blocks
  • Höhe: Höhe des Elements
  • Drehung: Rotation
  • Länge: Länge (für Geraden)

Besonderheiten:

  • Spezielle Behandlung für Geraden (SivasNummer aus Config)
  • Erstellt Linien für Geraden statt Blöcke
  • Unterstützt Förderer-Komponenten

CSV-Dateiformat

Die CSV-Datei muss folgende Spalten enthalten (Semikolon-getrennt):

Elementnummer;TeileArt;TeileId;NachbarIds;Bezeichnung;Planquadrat;Merkmale

Spalten:

  • Elementnummer: Fortlaufende Nummer
  • TeileArt: Typ der Komponente (muss exakt mit Config übereinstimmen)
  • TeileId: Eindeutige ID (z.B. "shape_...")
  • NachbarIds: Kommagetrennte Liste von IDs benachbarter Elemente
  • Bezeichnung: Beschreibung des Elements
  • Planquadrat: Koordinaten im Format X:<Wert> Y:<Wert> (in mm)
  • Merkmale: JSON-String mit spezifischen Eigenschaften

Beispiel:

1;"ILS 2.0 Kreisel";"shape_f81e5c4b-a976-a3c0-3304-d2b30da1ab29";"shape_d76e250a-0a46-f6d0-df52-943ab572cc63";"Kreisel:1";"X:9174.15 Y:12039.11";{"Abstand (Kreiselachse A - Kreiselachse) in Meter":"20.265","Anzahl der Separatoren":"2","Anzahl der Scanner":"0","Höhe in m":"2"}

Verwendung

Kommandozeilen-Syntax

python plant2dxf.py -f <csv-datei> [Optionen]

Optionen:

  • -f, --file: CSV-Datei (Pfad oder Dateiname im WORK-Verzeichnis) [erforderlich]
  • -c, --config: Pfad zur shapes.cfg (Standard: PROJECT_CFG/shapes.cfg)
  • -l, --lib: Pfad zur DXF-Bibliothek (Standard: PROJECT_DATA/blocks.dxf)
  • -o, --output: Ausgabe-DXF-Datei (Standard: <csv-name>.dxf im WORK-Verzeichnis)
  • -v, --verbose: Ausführliche Ausgaben

Beispiele:

# Einfache Verwendung
python plant2dxf.py -f anlage.csv

# Mit expliziten Pfaden
python plant2dxf.py -f anlage.csv -c cfg/shapes.cfg -l data/blocks.dxf -o output.dxf

# Mit verbose-Ausgabe
python plant2dxf.py -f anlage.csv -v

Batch-Datei (Windows)

Verwende bin/plant2dxf.bat für einfache Ausführung:

plant2dxf.bat <csv-datei>

Verarbeitungslogik

1. Initialisierung

  1. Laden der Konfigurationsdateien (shapes.cfg, allgemein.cfg)
  2. Erstellen einer neuen DXF-Datei (DXF R2018, Einheit: Millimeter)
  3. Laden der Block-Bibliotheken (mit Caching)

2. CSV-Verarbeitung

Für jede Zeile in der CSV-Datei:

  1. Parsen der CSV-Zeile:

    • Extraktion von TeileArt, TeileId, Koordinaten, Merkmalen
    • Parsen des Planquadrats zu X/Y-Koordinaten
    • Parsen der Merkmale (JSON)
  2. Nachbar-Informationen:

    • Analyse der NachbarIds
    • Bestimmung der Verbindungen zu Kreiseln, Kurven, Eckrädern
    • Berechnung von Drehrichtungen, Höhen, Abständen
  3. Bibliothekszuordnung:

    • Bestimmung der Bibliotheksdatei aus allgemein.cfg
    • Laden der Bibliothek (mit Cache)
  4. Handler-Aufruf:

    • Normalisierung des TeileArt-Namens zu Funktionsname
    • Aufruf der entsprechenden handle_*-Funktion
    • Erstellung der DXF-Elemente

3. Element-Erstellung

Jeder Handler:

  • Erstellt Objekte aus den Element-Klassen (Kreisel, Gefaellestrecke, etc.)
  • Analysiert Verbindungen zu Nachbarn
  • Erstellt dynamische Blöcke basierend auf Konfiguration
  • Fügt Blöcke, Linien und andere DXF-Entitäten ein
  • Setzt Attribute (z.B. TeileId)

4. Speicherung

  • Speicherung der DXF-Datei im angegebenen Ausgabepfad
  • Logging der Verarbeitung

Wichtige Module und Klassen

Element-Klassen (lib/Elemente/)

  • Kreisel: Repräsentiert einen Kreisel mit allen Eigenschaften
  • Gefaellestrecke: Repräsentiert eine Gefällestrecke
  • VarioFoerderer: Repräsentiert einen Vario-Förderer
  • Angetriebene_Kurve: Repräsentiert eine angetriebene Kurve
  • Eckrad: Repräsentiert ein Eckrad
  • Bt_element: Repräsentiert BT-Elemente
  • Omniflo: Repräsentiert Omniflo-Komponenten

Hilfsmodule

  • arbeiten_mit_csv.py: CSV-Parsing, Koordinaten-Extraktion, Nachbar-Analyse
  • block_methoden.py: Block-Import, Rotation, Layer-Verwaltung
  • as_es_methoden.py: AS/ES-Element-Erstellung, Höhen-Vertauschung
  • utils.py: Umgebungsvariablen, Logger-Setup

Wichtige ezdxf-Methoden

Das Skript verwendet verschiedene Methoden der ezdxf-Bibliothek zur Erstellung und Manipulation von DXF-Elementen. Die wichtigsten Methoden sind:

1. Block-Referenz in Block einfügen

block.add_blockref(blockname, (x, y, z), dxfattribs={"rotation": rotation, "layer": layer, "color": color})

Beschreibung: Fügt eine Block-Referenz (INSERT) in einen bestehenden Block ein.

Parameter:

  • blockname (str): Name des Blocks, der eingefügt werden soll
  • (x, y, z) (tuple): Koordinaten der Einfügeposition (3D-Tupel)
  • dxfattribs (dict): Dictionary mit DXF-Attributen:
    • rotation (float): Rotationswinkel in Grad
    • layer (str): Layer-Name
    • color (int): Farbe (optional)

Verwendung: Wird verwendet, um Blöcke innerhalb von anderen Blöcken zu platzieren (z.B. Motorstationen in Gefällestrecken-Blöcken).

Beispiel:

block.add_blockref("Vario_Motorstation_500mm", (0, 250, 0), dxfattribs={"rotation": 270, "layer": "VARIO"})

2. Block-Referenz ins Modelspace einfügen

msp.add_blockref(blockname, (x, y, z), dxfattribs={"rotation": rotation, "layer": layer, "color": color})

Beschreibung: Fügt eine Block-Referenz direkt in den Modelspace (die Hauptzeichnung) ein.

Parameter:

  • blockname (str): Name des Blocks, der eingefügt werden soll
  • (x, y, z) (tuple): Koordinaten der Einfügeposition (3D-Tupel)
  • dxfattribs (dict): Dictionary mit DXF-Attributen (siehe oben)

Verwendung: Wird verwendet, um fertige Blöcke in die Zeichnung zu platzieren. Dies ist der häufigste Weg, um Elemente in die DXF-Datei einzufügen.

Beispiel:

msp.add_blockref("ILS_2.0_Gefaellestrecke_8200_2000_UZS_higher", 
                  (x, y, hoehe_gefaelle), 
                  dxfattribs={"rotation": rotation, "layer": "6-SP"})

3. Neuen Block erstellen

block = doc.blocks.new(name=blockname, base_point=(0, 0, 0))

Beschreibung: Erstellt einen neuen Block im DXF-Dokument.

Parameter:

  • name (str): Name des neuen Blocks (muss eindeutig sein)
  • base_point (tuple): Basis-Punkt des Blocks (meist (0, 0, 0))

Rückgabewert: Block-Objekt, das verwendet werden kann, um Entitäten hinzuzufügen

Wichtiger Hinweis: Ein Block mit demselben Namen kann nur einmal erstellt werden. Vor der Erstellung sollte geprüft werden:

if blockname not in doc.blocks:
    block = doc.blocks.new(name=blockname, base_point=(0, 0, 0))

Verwendung: Wird verwendet, um dynamische Blöcke zu erstellen, die aus mehreren Komponenten bestehen (z.B. Gefällestrecken mit Motorstationen, Vario-Förderer mit verschiedenen Konfigurationen).

Beispiel:

blockname = f"Ils_2.0_Gefaellestrecke_{laenge}_{hoehe_gefaelle}_{hat_motor_0}_{hat_umlenk_0}"
if blockname not in doc.blocks:
    block = doc.blocks.new(name=blockname, base_point=(0, 0, 0))
    # Füge Komponenten zum Block hinzu
    block.add_blockref("Vario_Motorstation_500mm", (0, 0, 0))
    line = Line.new(dxfattribs={"start": start, "end": ende})
    line.translate(-x, -y, -hoehe_gefaelle)
    block.add_entity(line)

4. DXF-Objekte aus Modelspace abfragen

entities = msp.query("INSERT")

Beschreibung: Holt alle spezifischen DXF-Objekte vom Modelspace.

Parameter:

  • "INSERT" (str): DXF-Typ des Objekts (z.B. "INSERT" für Block-Referenzen, "LINE" für Linien, "CIRCLE" für Kreise)

Rückgabewert: Liste von DXF-Entitäten des angegebenen Typs

Verwendung: Wird verwendet, um bestimmte Objekte aus der Zeichnung zu finden oder zu analysieren. Meistens wird dies für INSERT-Objekte (Block-Referenzen) verwendet.

Beispiel:

# Alle Block-Referenzen im Modelspace finden
inserts = msp.query("INSERT")
for insert in inserts:
    print(f"Block: {insert.dxf.name} an Position {insert.dxf.insert}")

Weitere DXF-Typen:

  • "LINE": Linien
  • "CIRCLE": Kreise
  • "ARC": Bögen
  • "TEXT": Text
  • "ATTDEF": Attribut-Definitionen
  • "INSERT": Block-Referenzen

5. Weitere wichtige ezdxf-Methoden

Linie erstellen und hinzufügen

# Linie direkt im Modelspace
line = msp.add_line(start=(x1, y1, z1), end=(x2, y2, z2))
line.dxf.layer = "6-SP"

# Linie in Block erstellen
line = Line.new(dxfattribs={"start": (x1, y1, z1), "end": (x2, y2, z2)})
line.translate(-x, -y, -z)  # Relativ zum Block-Ursprung verschieben
block.add_entity(line)

Layer erstellen

if "LAYER_NAME" not in doc.layers:
    doc.layers.add(name="LAYER_NAME", color=7)

Block-Attribute hinzufügen

bref = msp.add_blockref(blockname, (x, y, z))
bref.add_attrib(tag="NAME", text="Bezeichnung", insert=(x, y))
bref.add_auto_attribs({ATTR_TAG: teileid})  # Automatische Attribute aus Block-Definition

Entität transformieren

entity.translate(dx, dy, dz)  # Verschieben
entity.rotate_z(angle)        # Rotation um Z-Achse
entity.scale(factor)          # Skalierung

Konstante Parameter

  • ATTR_TAG: "TeileId" - Attributtag im Block
  • RADIUS: 400 - Radius der Kreiselkreise (in mm)

Layer-Verwaltung

Das Skript erstellt automatisch folgende Layer:

  • VARIO: Für Vario-Förderer (Farbe: 3)
  • 6-SP: Für Gefällestrecken (Farbe: 7)
  • Weitere Layer werden aus den Bibliotheks-Blöcken übernommen

Fehlerbehandlung

  • Fehlende Umgebungsvariablen führen zum Programmabbruch
  • Fehlende Bibliotheksdateien werden geloggt, Verarbeitung wird fortgesetzt
  • Fehlerhafte CSV-Zeilen werden übersprungen (mit Warnung)
  • Fehlende Handler für TeileArt werden geloggt, Element wird übersprungen

Logging

  • Log-Dateien werden in PROJECT_LOG/ gespeichert
  • Format: plant2dxf_YYYYMMDD_HHMMSS.log
  • Logging erfolgt sowohl in Datei als auch auf Konsole
  • Format: %(asctime)s - %(levelname)s - %(message)s

Detaillierte Funktionsbeschreibungen

NachbarId-Entnahme und -Analyse

Die Funktion get_nachbar_information() in arbeiten_mit_csv.py analysiert die CSV-Datei und erstellt ein Dictionary mit allen Nachbar-Informationen für Gefällestrecken und Vario-Förderer.

Ablauf der Nachbar-Analyse

  1. Erste Durchlauf - Sammeln aller Elemente:

    • Gefällestrecken: Speichert ID und NachbarIds
    • Kreisel: Erstellt Kreisel-Objekte und speichert:
      • drehung: Drehrichtung (UZS/GUZS)
      • höhe: Höhe des Kreisels
      • x, y: Koordinaten
      • rotation: Rotationswinkel
      • abstand: Abstand zwischen Kreiselachsen (in Metern)
    • Vario-Förderer: Speichert ID, NachbarIds, Winkel, Höhen, Förderrichtung, Koordinaten
    • Angetriebene Kurven: Speichert ID, Höhen, Kurvenrichtung, TEF-Kurve-Status, Winkel, Koordinaten
    • Eckräder: Speichert ID, Höhe, Koordinaten
  2. Zweiter Durchlauf - Zuordnung der Nachbarn: Für jede Gefällestrecke oder Vario-Förderer:

    a) Angetriebene Kurven (TEF-Kurven):

    • Prüft, ob Kurven-IDs in den NachbarIds enthalten sind
    • Speichert für erste Kurve (voerder_anweisung == 0):
      • X_angetrieben, Y_angetrieben: Koordinaten
      • vario_hoehe_0, vario_hoehe_1: Höhen der Kurve
      • Kurvenrichtung: Links oder Rechts
      • Tefkurve: Antriebsart (außen/innen)
      • Kurvenwinkel: Winkel der Kurve
    • Speichert für zweite Kurve (voerder_anweisung == 1):
      • Gleiche Felder mit Suffix _1

    b) Eckräder:

    • Prüft, ob Eckrad-IDs in den NachbarIds enthalten sind
    • Speichert für erstes Eckrad (eckrad_anweisung == 0):
      • Eckrad_x, Eckrad_y: Koordinaten
      • Eckrad_höhe: Höhe des Eckrads
    • Speichert für zweites Eckrad (eckrad_anweisung == 1):
      • Gleiche Felder mit Suffix _1

    c) Kreisel:

    • Prüft, ob Kreisel-IDs in den NachbarIds enthalten sind
    • Speichert für ersten Kreisel (anweisungen == 0):
      • Drehung0: Drehrichtung (UZS/GUZS)
      • Hoehe0: Höhe des Kreisels
      • x0, y0: Koordinaten
      • rotation0: Rotationswinkel
      • abstand0: Abstand zwischen Kreiselachsen (in Metern)
    • Speichert für zweiten Kreisel (anweisungen == 1):
      • Gleiche Felder mit Suffix 1 statt 0

    d) Vario-Förderer (nur für Vario-Förderer):

    • Prüft, ob andere Vario-Förderer in den NachbarIds enthalten sind
    • Speichert für ersten Vario-Förderer (geraden_anweisung == 0):
      • X_foerderer, Y_foerderer: Koordinaten
      • Winkel: Winkel des Förderers
      • h0, h1: Höhen
      • Foerderrichtung: Auf/Ab/Horizontal
    • Speichert für zweiten Vario-Förderer (geraden_anweisung == 1):
      • Gleiche Felder mit Suffix _2

Verwendung der Nachbar-Informationen

Die Nachbar-Informationen werden verwendet für:

  • Gefällestrecken: Bestimmung der AS/ES-Elemente, Motor/Umlenkstationen, direkte Kreisel-Verbindungen
  • Vario-Förderer: Bestimmung der Verbindungsart, Gefälle-Komponenten, Offset-Berechnungen

Gefällestrecke mit Motor/Umlenkstation - Detaillierte Erstellung

Die Erstellung einer Gefällestrecke mit Motor- oder Umlenkstation erfolgt in mehreren Schritten:

1. Prüfung auf Motor/Umlenkstation-Bedarf

Die Methode hat_motor_umlenk_station() prüft, ob eine Gefällestrecke eine Motor- oder Umlenkstation benötigt:

Logik:

  • Prüft, ob Kurvenrichtung in den Nachbar-Informationen vorhanden ist (d.h. verbunden mit angetriebener Kurve)
  • Bestimmt tefkurve_0 basierend auf Kurvenrichtung und Antriebsart:
    • kurvenrichtung == "links" und Tefkurve == "außen"tefkurve_0 = "rechts"
    • kurvenrichtung == "rechts" und Tefkurve == "innen"tefkurve_0 = "rechts"
    • Sonst → tefkurve_0 = "links"

Höhen-basierte Bestimmung:

  • Wenn upper_hoehe_gefaelle > lower_hoehe_gefaelle:
    • Wenn vario_hoehe_0 oder vario_hoehe_1 == upper_hoehe_gefaellehat_motor_0 = True
    • Sonst → hat_umlenk_0 = True
  • Wenn upper_hoehe_gefaelle < lower_hoehe_gefaelle:
    • Wenn vario_hoehe_0 oder vario_hoehe_1 == lower_hoehe_gefaellehat_motor_0 = True
    • Sonst → hat_umlenk_0 = True

Rotations-basierte Bestimmung (bei gleicher Höhe):

  • Wenn beide Höhen gleich sind, wird die Position relativ zur Kurve geprüft
  • Basierend auf Rotation und Koordinaten wird entschieden:
    • hat_umlenk_0 = True + umlenk_gerade = True (wenn bestimmte Bedingungen erfüllt)
    • Oder hat_motor_0 = True + motor_gerade = True

2. Erstellung des Blocks mit Motor/Umlenkstation

Die Methode ein_motor_oder_eine_umlenk() erstellt die Motor- oder Umlenkstation im Block:

Schritte:

  1. Import der Vario-Bögen:

    • Vario_Bogen_auf_3°: Bogen für Aufwärts-Bewegung
    • Vario_Bogen_ab_3°: Bogen für Abwärts-Bewegung
    • Erstellung der Links-Versionen durch turn_two_blocks_left()
  2. Auslesen der Delta-Werte:

    • DELTA_SP_0, DELTA_SP_1: Delta-Werte für Startpunkt
    • DELTA_VP_0, DELTA_VP_1: Delta-Werte für Verbindungspunkt
    • Negative Werte werden in positive umgewandelt
  3. Motor-Station einfügen (hat_motor_0 == True):

    • Wenn tefkurve_0 == "links":
      • Wenn motor_gerade == False:
        • Fügt Vario_Bogen_ab_links ein (Rotation 270°)
        • Berechnet neuen Startpunkt basierend auf Delta-Werten
        • Fügt blockname_motor_links ein (250mm Offset)
        • Verschiebt Startpunkt um 500mm * cos(3°) und sin(3°)
      • Wenn motor_gerade == True:
        • Fügt Vario_Motorstation_500mm_links direkt ein
        • Verschiebt Startpunkt um 500mm
    • Wenn tefkurve_0 == "rechts":
      • Gleiche Logik mit rechts-Versionen der Blöcke
  4. Umlenk-Station einfügen (hat_umlenk_0 == True):

    • Wenn tefkurve_0 == "links":
      • Wenn umlenk_gerade == False:
        • Fügt Vario_Bogen_auf ein (Rotation 90°)
        • Berechnet neuen Endpunkt basierend auf Delta-Werten
        • Fügt blockname_umlenk_links ein (250mm Offset)
        • Verschiebt Endpunkt um 500mm * cos(3°) und sin(3°)
      • Wenn umlenk_gerade == True:
        • Fügt Vario_Umlenkstation_500mm_links direkt ein
        • Verschiebt Endpunkt um 500mm
    • Wenn tefkurve_0 == "rechts":
      • Gleiche Logik mit rechts-Versionen der Blöcke
  5. Rückgabe:

    • Gibt modifizierte start und ende Koordinaten zurück

3. Blockname-Generierung

Der Blockname wird dynamisch generiert:

Ils_2.0_Gefaellestrecke_{laenge}_{hoehe_gefaelle}_{hat_umlenk_0}_{hat_motor_0}_{tefkurve_0}_{umlenk_gerade}_{motor_gerade}

4. Block-Erstellung

  1. Prüft, ob Block bereits existiert (Caching)
  2. Erstellt neuen Block mit Basis-Punkt (0,0,0)
  3. Ruft ein_motor_oder_eine_umlenk() auf, um Motor/Umlenkstation einzufügen
  4. Erstellt Linie zwischen modifiziertem Start- und Endpunkt
  5. Verschiebt Linie relativ zum Block-Ursprung
  6. Fügt Block-Referenz in Modelspace ein

Vario-Förderer ohne Verbindung - Detaillierte Erstellung

Wenn ein Vario-Förderer nicht mit einem Kreisel oder Eckrad verbunden ist, wird der einfachste Fall behandelt:

1. Vorbereitung

halbe_laenge = laenge / 2
dy = halbe_laenge * math.cos(0)  # dy = halbe_laenge (da cos(0) = 1)

2. Blockname-Generierung

Rechts-Version:

Vario_Foerderer_{winkel}_{voerder_richtung}_{laenge}_{hoehe_vario}_rechts_{motor_vorhanden}_{umlenk_vorhanden}_{gefaelle}_{gefahellewinkel}

Links-Version:

Vario_Foerderer_{winkel}_{voerder_richtung}_{laenge}_{hoehe_vario}_links_{motor_vorhanden}_{umlenk_vorhanden}_{gefaelle}_{gefahellewinkel}

Parameter:

  • winkel: Winkel des Förderers (z.B. 3, 6, 9)
  • voerder_richtung: Auf, Ab oder Horizontal
  • laenge: Länge in mm
  • hoehe_vario: Mittlere Höhe ((h0 + h1) / 2)
  • motor_vorhanden: True/False
  • umlenk_vorhanden: True/False
  • gefaelle: Länge der Gefällestrecke (falls vorhanden)
  • gefahellewinkel: Winkel der Gefällestrecke (falls vorhanden)

3. Block-Erstellung

  1. Prüfung auf existierenden Block:

    • Wenn Block bereits existiert, wird nur Block-Referenz eingefügt
    • Auswahl zwischen Links- und Rechts-Version basierend auf Motorseite
  2. Neuer Block wird erstellt:

    block = doc.blocks.new(blockname, base_point=(0,0,0))
    
  3. Start- und Endpunkt berechnen:

    start = (x, y + dy, upper_hoehe_vario)
    ende = (x, y - dy, lower_hoehe_vario)
    
    • Startpunkt: Mitte + halbe Länge in Y-Richtung, obere Höhe
    • Endpunkt: Mitte - halbe Länge in Y-Richtung, untere Höhe
  4. Vario-Erstellung aufrufen:

    VarioFoerderer.VarioFoerderer.vario_erstellung(
        foerderer, doc, lib_doc, config, 
        block, block_name_links, 
        start, ende, 
        voerder_richtung, 
        winkel_VP_offset_vorne,  # None, da keine Verbindung
        winkel_VP_offset_hinten   # None, da keine Verbindung
    )
    

4. Vario-Erstellung (vario_erstellung())

Schritte:

  1. Konfiguration auslesen:

    • winkel_motor: Winkel für Motorstation (aus Config, z.B. 3.0°)
    • winkel_umlenk: Winkel für Umlenkstation (aus Config, z.B. 3.0°)
    • umlenk_laenge: Länge der Umlenkstation (aus Config, z.B. 500.0mm)
    • motor_laenge: Länge der Motorstation (aus Config, z.B. 500.0mm)
    • vario_abstand: Abstand zwischen Vario-Komponenten (aus Config, z.B. 66.5mm)
  2. Offset-Berechnung:

    motor_offset_x = umlenk_laenge[0] * math.cos(math.radians(winkel_motor))
    motor_offset_z = umlenk_laenge[0] * math.sin(math.radians(winkel_motor))
    umlenk_offset_x = motor_laenge[0] * math.cos(math.radians(winkel_umlenk))
    umlenk_offset_z = motor_laenge[0] * math.sin(math.radians(winkel_umlenk))
    
  3. Gefälle-Länge anpassen:

    • Wenn Motor vorhanden: gefaelle = gefaelle - motor_offset_x
    • Wenn Umlenk vorhanden: gefaelle = gefaelle - umlenk_offset_x
  4. Förderrichtung "Auf" oder "Horizontal":

    • Erstellt Vario-Komponenten von Start zu Ende
    • Fügt Motorstation am Start ein (falls vorhanden)
    • Fügt Gefälle-Komponenten ein (falls vorhanden)
    • Fügt Umlenkstation am Ende ein (falls vorhanden)
  5. Förderrichtung "Ab":

    • Erstellt Vario-Komponenten von Ende zu Start
    • Fügt Umlenkstation am Ende ein (falls vorhanden)
    • Fügt Gefälle-Komponenten ein (falls vorhanden)
    • Fügt Motorstation am Start ein (falls vorhanden)
  6. Links-Version erstellen:

    • Erstellt gespiegelte Version des Blocks für Links-Motorseite
    • Verwendet turn_two_blocks_left() für Spiegelung

5. Block-Referenz einfügen

Basierend auf Motorseite aus Merkmalen:

  • Motorseite == "links" → Fügt block_name_links ein
  • Motorseite == "rechts" → Fügt blockname ein

Position: (x, y, hoehe_vario)
Rotation: rotation aus Merkmalen

Erweiterbarkeit

Neue TeileArt hinzufügen

  1. Config hinzufügen (shapes.cfg):

    [Neue TeileArt]
    items = Block1, Block2
    offset_symb1 = 0,0
    rot_symb1 = 0.0
    
  2. Handler-Funktion erstellen (plant2dxf.py):

    def handle_neue_teileart(msp, teileid, merkmale, x, y, doc, lib_doc, verbose, symbols, strecken_nachbarn, config, config_allgemein):
        """Erstellt eine neue TeileArt in der neuen Dxf"""
        # Implementierung
    
  3. Bibliothekszuordnung (allgemein.cfg):

    [Neue TeileArt]
    libfile = bibliothek.dxf
    
  4. Element-Klasse (optional, lib/Elemente/):

    • Falls komplexe Logik benötigt wird, eigene Klasse erstellen

Abhängigkeiten

Siehe lib/requirements.txt:

  • ezdxf==1.4.1: DXF-Bibliothek
  • svg.path==7.0: SVG-Pfad-Verarbeitung
  • pydantic>=2.0.0: Datenvalidierung

Bekannte Einschränkungen

  • CSV muss UTF-8 kodiert sein
  • Koordinaten müssen im Format X:<Wert> Y:<Wert> vorliegen
  • Bibliotheksdateien müssen im DXF-Format vorliegen
  • Blocknamen müssen exakt mit Bibliothek übereinstimmen