test mit blöcken erstellen
This commit is contained in:
+506
-111
@@ -1,6 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import ezdxf
|
import ezdxf
|
||||||
from ezdxf.math import Vec2, BoundingBox
|
from ezdxf.math import Matrix44, Vec3, BoundingBox, Vec2
|
||||||
import math
|
import math
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
@@ -11,115 +11,120 @@ from pathlib import Path
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
||||||
def get_bbox(entities):
|
# def get_bbox(entities, transform_matrix=None):
|
||||||
"""
|
# """
|
||||||
Berechnet die Bounding Box für eine Liste von DXF-Entities.
|
# Berechnet die Bounding Box für eine Liste von DXF-Entities.
|
||||||
|
|
||||||
Args:
|
# Args:
|
||||||
entities: Liste von DXF-Entities (ezdxf entities)
|
# entities: Liste von DXF-Entities (ezdxf entities)
|
||||||
|
|
||||||
Returns:
|
# Returns:
|
||||||
Vec2 or None: Zentrum der Bounding Box als Vec2-Objekt oder None,
|
# Vec2 or None: Zentrum der Bounding Box als Vec2-Objekt oder None,
|
||||||
falls keine gültige Geometrie gefunden wurde
|
# falls keine gültige Geometrie gefunden wurde
|
||||||
|
|
||||||
Note:
|
# Note:
|
||||||
Unterstützt POLYLINE, LWPOLYLINE und andere Entity-Typen.
|
# Unterstützt POLYLINE, LWPOLYLINE und andere Entity-Typen.
|
||||||
Fehlerhafte Entities werden übersprungen und protokolliert.
|
# Fehlerhafte Entities werden übersprungen und protokolliert.
|
||||||
"""
|
# """
|
||||||
min_x, min_y = float('inf'), float('inf')
|
# min_x, min_y = float('inf'), float('inf')
|
||||||
max_x, max_y = float('-inf'), float('-inf')
|
# max_x, max_y = float('-inf'), float('-inf')
|
||||||
for e in entities:
|
# for e in entities:
|
||||||
try:
|
# try:
|
||||||
if e.dxftype() == "POLYLINE":
|
# if e.dxftype() == "POLYLINE":
|
||||||
for vertex in e.vertices:
|
# for vertex in e.vertices:
|
||||||
if hasattr(vertex.dxf, 'location'):
|
# if hasattr(vertex.dxf, 'location'):
|
||||||
x, y = vertex.dxf.location.x, vertex.dxf.location.y
|
# x, y = vertex.dxf.location.x, vertex.dxf.location.y
|
||||||
min_x, min_y = min(min_x, x), min(min_y, y)
|
# min_x, min_y = min(min_x, x), min(min_y, y)
|
||||||
max_x, max_y = max(max_x, x), max(max_y, y)
|
# max_x, max_y = max(max_x, x), max(max_y, y)
|
||||||
elif e.dxftype() == "LWPOLYLINE":
|
# elif e.dxftype() == "LWPOLYLINE":
|
||||||
for x, y, *_ in e.get_points("xy"):
|
# for x, y, *_ in e.get_points("xy"):
|
||||||
min_x, min_y = min(min_x, x), min(min_y, y)
|
# min_x, min_y = min(min_x, x), min(min_y, y)
|
||||||
max_x, max_y = max(max_x, x), max(max_y, y)
|
# max_x, max_y = max(max_x, x), max(max_y, y)
|
||||||
elif e.dxftype() == "ARC":
|
# elif e.dxftype() == "ARC":
|
||||||
# Handle ARC entities: consider endpoints and cardinal extrema
|
# # Handle ARC entities: consider endpoints and cardinal extrema
|
||||||
try:
|
# try:
|
||||||
cx, cy = e.dxf.center.x, e.dxf.center.y
|
# cx, cy = e.dxf.center.x, e.dxf.center.y
|
||||||
except Exception:
|
# except Exception:
|
||||||
cx, cy = e.dxf.center
|
# cx, cy = e.dxf.center
|
||||||
r = float(e.dxf.radius)
|
# r = float(e.dxf.radius)
|
||||||
start_deg = float(e.dxf.start_angle)
|
# start_deg = float(e.dxf.start_angle)
|
||||||
end_deg = float(e.dxf.end_angle)
|
# end_deg = float(e.dxf.end_angle)
|
||||||
start = math.radians(start_deg % 360)
|
# start = math.radians(start_deg % 360)
|
||||||
end = math.radians(end_deg % 360)
|
# end = math.radians(end_deg % 360)
|
||||||
|
|
||||||
def in_sweep(a: float, s: float, e_: float) -> bool:
|
# def in_sweep(a: float, s: float, e_: float) -> bool:
|
||||||
# CCW sweep from s to e_ with wrap handling
|
# # CCW sweep from s to e_ with wrap handling
|
||||||
if e_ >= s:
|
# if e_ >= s:
|
||||||
return s <= a <= e_
|
# return s <= a <= e_
|
||||||
return a >= s or a <= e_
|
# return a >= s or a <= e_
|
||||||
|
|
||||||
candidates = []
|
# candidates = []
|
||||||
# Endpoints
|
# # Endpoints
|
||||||
candidates.append((cx + r * math.cos(start), cy + r * math.sin(start)))
|
# candidates.append((cx + r * math.cos(start), cy + r * math.sin(start)))
|
||||||
candidates.append((cx + r * math.cos(end), cy + r * math.sin(end)))
|
# candidates.append((cx + r * math.cos(end), cy + r * math.sin(end)))
|
||||||
# Cardinal angles 0, 90, 180, 270 deg
|
# # Cardinal angles 0, 90, 180, 270 deg
|
||||||
for ang in (0.0, math.pi/2, math.pi, 3*math.pi/2):
|
# for ang in (0.0, math.pi/2, math.pi, 3*math.pi/2):
|
||||||
if in_sweep(ang, start, end):
|
# if in_sweep(ang, start, end):
|
||||||
candidates.append((cx + r * math.cos(ang), cy + r * math.sin(ang)))
|
# candidates.append((cx + r * math.cos(ang), cy + r * math.sin(ang)))
|
||||||
for px, py in candidates:
|
# for px, py in candidates:
|
||||||
min_x, min_y = min(min_x, px), min(min_y, py)
|
# min_x, min_y = min(min_x, px), min(min_y, py)
|
||||||
max_x, max_y = max(max_x, px), max(max_y, py)
|
# max_x, max_y = max(max_x, px), max(max_y, py)
|
||||||
elif e.dxftype() == "CIRCLE":
|
# elif e.dxftype() == "CIRCLE":
|
||||||
# Handle CIRCLE entities via center and radius
|
# # Handle CIRCLE entities via center and radius
|
||||||
try:
|
# try:
|
||||||
cx, cy = e.dsf.center.x, e.dsf.center.y
|
# cx, cy = e.dsf.center.x, e.dsf.center.y
|
||||||
except Exception:
|
# except Exception:
|
||||||
cx, cy = e.dxf.center
|
# cx, cy = e.dxf.center
|
||||||
r = float(e.dxf.radius)
|
# r = float(e.dxf.radius)
|
||||||
min_x, min_y = min(min_x, cx - r), min(min_y, cy - r)
|
# min_x, min_y = min(min_x, cx - r), min(min_y, cy - r)
|
||||||
max_x, max_y = max(max_x, cx + r), max(max_y, cy + r)
|
# max_x, max_y = max(max_x, cx + r), max(max_y, cy + r)
|
||||||
elif e.dxftype() == "LINE" or e.dxftype()== "Line":
|
# elif e.dxftype() == "LINE" or e.dxftype()== "Line":
|
||||||
# Handle simple line entities by their start/end points
|
# # Handle simple line entities by their start/end points
|
||||||
try:
|
# try:
|
||||||
sx, sy = e.dxf.start.x, e.dxf.start.y
|
# sx, sy = e.dxf.start.x, e.dxf.start.y
|
||||||
ex, ey = e.dxf.end.x, e.dxf.end.y
|
# ex, ey = e.dxf.end.x, e.dxf.end.y
|
||||||
except Exception:
|
# except Exception:
|
||||||
# Some ezdxf versions provide tuples
|
# # Some ezdxf versions provide tuples
|
||||||
(sx, sy), (ex, ey) = e.dxf.start, e.dxf.end
|
# (sx, sy), (ex, ey) = e.dxf.start, e.dxf.end
|
||||||
min_x, min_y = min(min_x, sx, ex ), min(min_y, sy, ey)
|
# min_x, min_y = min(min_x, sx, ex ), min(min_y, sy, ey)
|
||||||
max_x, max_y = max(max_x, sx, ex), max(max_y, sy, ey)
|
# max_x, max_y = max(max_x, sx, ex), max(max_y, sy, ey)
|
||||||
elif e.dxftype() == "SPLINE":
|
# elif e.dxftype() == "SPLINE":
|
||||||
# Approximate spline to compute bounding box
|
# # Approximate spline to compute bounding box
|
||||||
points = []
|
# points = []
|
||||||
try:
|
# try:
|
||||||
points = e.approximate(60)
|
# points = e.approximate(60)
|
||||||
except Exception:
|
# except Exception:
|
||||||
try:
|
# try:
|
||||||
points = list(e.flattening(1.0))
|
# points = list(e.flattening(1.0))
|
||||||
except Exception:
|
# except Exception:
|
||||||
points = []
|
# points = []
|
||||||
if points:
|
# if points:
|
||||||
for pt in points:
|
# for pt in points:
|
||||||
try:
|
# try:
|
||||||
px, py = pt.x, pt.y
|
# px, py = pt.x, pt.y
|
||||||
except Exception:
|
# except Exception:
|
||||||
px, py = pt[0], pt[1]
|
# px, py = pt[0], pt[1]
|
||||||
min_x, min_y = min(min_x, px), min(min_y, py)
|
# min_x, min_y = min(min_x, px), min(min_y, py)
|
||||||
max_x, max_y = max(max_x, px), max(max_y, py)
|
# max_x, max_y = max(max_x, px), max(max_y, py)
|
||||||
else:
|
# elif e.dxftype() == 'INSERT':
|
||||||
box = e.bbox()
|
# # INSERT: Block-Inhalt mit Transformation berücksichtigen
|
||||||
if box:
|
# insert_bbox = calculate_insert_bounding_box(e, doc, transform_matrix)
|
||||||
(x1, y1), (x2, y2) = box.extmin, box.extmax
|
# if insert_bbox and insert_bbox.has_data:
|
||||||
min_x, min_y = min(min_x, x1), min(min_y, y1)
|
# bbox.extend(insert_bbox)
|
||||||
max_x, max_y = max(max_x, x2), max(max_y, y2)
|
# else:
|
||||||
except Exception as err:
|
# box = e.bbox()
|
||||||
print(f" BBox Fehler für {e.dxftype()}: {err}")
|
# if box:
|
||||||
continue
|
# (x1, y1), (x2, y2) = box.extmin, box.extmax
|
||||||
|
# min_x, min_y = min(min_x, x1), min(min_y, y1)
|
||||||
|
# max_x, max_y = max(max_x, x2), max(max_y, y2)
|
||||||
|
# except Exception as err:
|
||||||
|
# print(f" BBox Fehler für {e.dxftype()}: {err}")
|
||||||
|
# continue
|
||||||
|
|
||||||
if min_x == float('inf'):
|
# if min_x == float('inf'):
|
||||||
return None, (0,0)
|
# return None, (0,0)
|
||||||
|
|
||||||
return Vec2((min_x + max_x) / 2, (min_y + max_y) / 2), (max_x -min_x, max_y -min_y)
|
# return Vec2((min_x + max_x) / 2, (min_y + max_y) / 2), (max_x -min_x, max_y -min_y)
|
||||||
|
|
||||||
|
|
||||||
def create_block_library(input_dir, output_file, config, logger=None):
|
def create_block_library(input_dir, output_file, config, logger=None):
|
||||||
@@ -209,7 +214,8 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
center, ausdehnung = get_bbox(entities)
|
# center, ausdehnung = get_bbox(entities)
|
||||||
|
center, ausdehnung = get_entity_bounding_box(entities, doc, transform_matrix=None)
|
||||||
if center is None:
|
if center is None:
|
||||||
error_msg = f"Keine gültige Geometrie in {filename}"
|
error_msg = f"Keine gültige Geometrie in {filename}"
|
||||||
if logger:
|
if logger:
|
||||||
@@ -224,13 +230,13 @@ def create_block_library(input_dir, output_file, config, logger=None):
|
|||||||
|
|
||||||
blk = doc.blocks.new(name=name, base_point=(0,0))
|
blk = doc.blocks.new(name=name, base_point=(0,0))
|
||||||
|
|
||||||
for e in entities:
|
# for e in entities:
|
||||||
# Sicherstellen, dass referenzierte Blöcke für INSERT verfügbar sind
|
# # Sicherstellen, dass referenzierte Blöcke für INSERT verfügbar sind
|
||||||
if e.dxftype() == "INSERT":
|
# if e.dxftype() == "INSERT":
|
||||||
handle_insert_entities(doc, src_doc, e)
|
# handle_insert_entities(doc, src_doc, e)
|
||||||
cp = copy_entity(logger, error_files, filename, e, center)
|
cp = copy_entity(logger, error_files, filename, e, center)
|
||||||
if cp:
|
if cp:
|
||||||
blk.add_entity(cp)
|
blk.add_entity(cp)
|
||||||
# Platzierung in Reihen und Spalten
|
# Platzierung in Reihen und Spalten
|
||||||
# Attribut-Definition (ATTDEF) hinzufügen
|
# Attribut-Definition (ATTDEF) hinzufügen
|
||||||
blk.add_attdef(
|
blk.add_attdef(
|
||||||
@@ -394,6 +400,395 @@ def get_cfg_value(section, key, fallback):
|
|||||||
return fallback
|
return fallback
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Eingabe-DXF laden
|
||||||
|
input_doc = ezdxf.readfile(input_filename)
|
||||||
|
print(f"Lade DXF-Datei: {input_filename}")
|
||||||
|
|
||||||
|
# Neue Ausgabe-DXF erstellen
|
||||||
|
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)
|
||||||
|
print(f"Block-Definitionen kopiert: {len(copied_blocks)}")
|
||||||
|
|
||||||
|
# Neuen Hauptblock erstellen
|
||||||
|
new_block = output_doc.blocks.new(name=block_name)
|
||||||
|
print(f"Erstelle neuen Block: {block_name}")
|
||||||
|
|
||||||
|
# Alle Entities aus dem Modelspace kopieren
|
||||||
|
msp = input_doc.modelspace()
|
||||||
|
entity_count = 0
|
||||||
|
insert_count = 0
|
||||||
|
|
||||||
|
for entity in msp:
|
||||||
|
if entity.dxftype() == 'INSERT':
|
||||||
|
# INSERT direkt kopieren (nicht explodieren)
|
||||||
|
copy_entity_to_block(entity, new_block)
|
||||||
|
insert_count += 1
|
||||||
|
else:
|
||||||
|
# Normale Entity kopieren
|
||||||
|
copy_entity_to_block(entity, new_block)
|
||||||
|
|
||||||
|
entity_count += 1
|
||||||
|
|
||||||
|
# Bounding Box berechnen
|
||||||
|
bbox = calculate_block_bounding_box(new_block, output_doc)
|
||||||
|
|
||||||
|
# Block im Modelspace der neuen Datei platzieren
|
||||||
|
output_msp = output_doc.modelspace()
|
||||||
|
output_msp.add_blockref(block_name, insert=(0, 0))
|
||||||
|
|
||||||
|
# Bounding Box als Hilfslinien hinzufügen (optional)
|
||||||
|
if bbox.has_data:
|
||||||
|
add_bounding_box_to_modelspace(output_msp, bbox)
|
||||||
|
|
||||||
|
# Speichern
|
||||||
|
output_doc.saveas(output_filename)
|
||||||
|
|
||||||
|
print(f"Konvertierung abgeschlossen:")
|
||||||
|
print(f" - {entity_count} Entities übertragen")
|
||||||
|
print(f" - {insert_count} INSERTs als Referenzen beibehalten")
|
||||||
|
print(f" - Bounding Box: {format_bounding_box(bbox)}")
|
||||||
|
print(f" - Ausgabe: {output_filename}")
|
||||||
|
|
||||||
|
return bbox
|
||||||
|
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f"Fehler: Datei {input_filename} nicht gefunden")
|
||||||
|
return None
|
||||||
|
except ezdxf.DXFStructureError as e:
|
||||||
|
print(f"DXF-Strukturfehler: {e}")
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Unerwarteter Fehler: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def copy_block_definitions(source_doc, target_doc):
|
||||||
|
"""
|
||||||
|
Kopiert alle Block-Definitionen vom Quell- zum Ziel-Dokument
|
||||||
|
"""
|
||||||
|
copied_blocks = []
|
||||||
|
|
||||||
|
for block_name in source_doc.blocks:
|
||||||
|
# Standard-Blöcke (MODEL_SPACE, PAPER_SPACE) überspringen
|
||||||
|
if block_name.startswith('*'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
source_block = source_doc.blocks[block_name]
|
||||||
|
|
||||||
|
# Prüfen ob Block bereits existiert
|
||||||
|
if block_name in target_doc.blocks:
|
||||||
|
print(f"Warnung: Block '{block_name}' existiert bereits, wird übersprungen")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Neuen Block in Ziel-Dokument erstellen
|
||||||
|
target_block = target_doc.blocks.new(name=block_name)
|
||||||
|
|
||||||
|
# Alle Entities des Quell-Blocks kopieren
|
||||||
|
for entity in source_block:
|
||||||
|
copy_entity_to_block(entity, target_block)
|
||||||
|
|
||||||
|
copied_blocks.append(block_name)
|
||||||
|
|
||||||
|
return copied_blocks
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_block_bounding_box(block, doc):
|
||||||
|
"""
|
||||||
|
Berechnet die Bounding Box eines Blocks inklusive aller INSERTs
|
||||||
|
"""
|
||||||
|
bbox = BoundingBox()
|
||||||
|
|
||||||
|
for entity in block:
|
||||||
|
entity_bbox = get_entity_bounding_box(entity, doc)
|
||||||
|
if entity_bbox and entity_bbox.has_data:
|
||||||
|
bbox.extend(entity_bbox)
|
||||||
|
|
||||||
|
return bbox
|
||||||
|
|
||||||
|
|
||||||
|
def get_entity_bounding_box(entity, doc, transform_matrix=None):
|
||||||
|
"""
|
||||||
|
Berechnet die Bounding Box einer einzelnen Entity
|
||||||
|
Berücksichtigt INSERTs mit ihren Block-Inhalten
|
||||||
|
"""
|
||||||
|
bbox = BoundingBox()
|
||||||
|
for e in entity:
|
||||||
|
try:
|
||||||
|
if e.dxftype() == 'LINE':
|
||||||
|
start = Vec3(e.dxf.start)
|
||||||
|
end = Vec3(e.dxf.end)
|
||||||
|
if transform_matrix:
|
||||||
|
start = transform_matrix.transform(start)
|
||||||
|
end = transform_matrix.transform(end)
|
||||||
|
bbox.extend([start, end])
|
||||||
|
|
||||||
|
elif e.dxftype() == 'CIRCLE':
|
||||||
|
center = Vec3(e.dxf.center)
|
||||||
|
radius = e.dxf.radius
|
||||||
|
if transform_matrix:
|
||||||
|
center = transform_matrix.transform(center)
|
||||||
|
# Radius mit durchschnittlicher Skalierung anpassen
|
||||||
|
scale_factor = (transform_matrix.scale_x + transform_matrix.scale_y) / 2
|
||||||
|
radius *= abs(scale_factor)
|
||||||
|
|
||||||
|
bbox.extend([
|
||||||
|
Vec3(center.x - radius, center.y - radius, center.z),
|
||||||
|
Vec3(center.x + radius, center.y + radius, center.z)
|
||||||
|
])
|
||||||
|
|
||||||
|
elif e.dxftype() == 'ARC':
|
||||||
|
# Vereinfachung: Bounding Box des vollständigen Kreises
|
||||||
|
center = Vec3(e.dxf.center)
|
||||||
|
radius = e.dxf.radius
|
||||||
|
if transform_matrix:
|
||||||
|
center = transform_matrix.transform(center)
|
||||||
|
scale_factor = (transform_matrix.scale_x + transform_matrix.scale_y) / 2
|
||||||
|
radius *= abs(scale_factor)
|
||||||
|
|
||||||
|
bbox.extend([
|
||||||
|
Vec3(center.x - radius, center.y - radius, center.z),
|
||||||
|
Vec3(center.x + radius, center.y + radius, center.z)
|
||||||
|
])
|
||||||
|
|
||||||
|
elif e.dxftype() == 'LWPOLYLINE':
|
||||||
|
points = []
|
||||||
|
for point in e.get_points():
|
||||||
|
pt = Vec3(point[0], point[1], 0)
|
||||||
|
if transform_matrix:
|
||||||
|
pt = transform_matrix.transform(pt)
|
||||||
|
points.append(pt)
|
||||||
|
if points:
|
||||||
|
bbox.extend(points)
|
||||||
|
|
||||||
|
elif e.dxftype() == 'POLYLINE':
|
||||||
|
points = []
|
||||||
|
for vertex in e.vertices:
|
||||||
|
pt = Vec3(vertex.dxf.location)
|
||||||
|
if transform_matrix:
|
||||||
|
pt = transform_matrix.transform(pt)
|
||||||
|
points.append(pt)
|
||||||
|
if points:
|
||||||
|
bbox.extend(points)
|
||||||
|
|
||||||
|
elif e.dxftype() == 'TEXT':
|
||||||
|
# Vereinfachung: Nur Insert-Point berücksichtigen
|
||||||
|
insert_point = Vec3(e.dxf.insert)
|
||||||
|
if transform_matrix:
|
||||||
|
insert_point = transform_matrix.transform(insert_point)
|
||||||
|
bbox.extend([insert_point])
|
||||||
|
|
||||||
|
elif e.dxftype() == 'INSERT':
|
||||||
|
# INSERT: Block-Inhalt mit Transformation berücksichtigen
|
||||||
|
insert_bbox = calculate_insert_bounding_box(e, doc, transform_matrix)
|
||||||
|
if insert_bbox and insert_bbox.has_data:
|
||||||
|
bbox.extend(insert_bbox)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler bei Bounding Box Berechnung für {entity.dxftype()}: {e}")
|
||||||
|
|
||||||
|
return bbox,( bbox.extmax.x - bbox.extmin.x,bbox.extmax.y -bbox.extmin.y)
|
||||||
|
|
||||||
|
|
||||||
|
def calculate_insert_bounding_box(insert_entity, doc, parent_transform=None):
|
||||||
|
"""
|
||||||
|
Berechnet die Bounding Box eines INSERTs inklusive Block-Inhalt
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Block-Definition finden
|
||||||
|
block_name = insert_entity.dxf.name
|
||||||
|
if block_name not in doc.blocks:
|
||||||
|
print(f"Warnung: Block '{block_name}' nicht gefunden")
|
||||||
|
return BoundingBox()
|
||||||
|
|
||||||
|
block_def = doc.blocks[block_name]
|
||||||
|
|
||||||
|
# Transformation der INSERT-Entity berechnen
|
||||||
|
insert_transform = get_insert_transform_matrix(insert_entity)
|
||||||
|
|
||||||
|
# Mit übergeordneter Transformation kombinieren
|
||||||
|
if parent_transform:
|
||||||
|
combined_transform = parent_transform * insert_transform
|
||||||
|
else:
|
||||||
|
combined_transform = insert_transform
|
||||||
|
|
||||||
|
# Bounding Box aller Entities im Block berechnen
|
||||||
|
block_bbox = BoundingBox()
|
||||||
|
|
||||||
|
for block_entity in block_def:
|
||||||
|
entity_bbox = get_entity_bounding_box(block_entity, doc, combined_transform)
|
||||||
|
if entity_bbox and entity_bbox.has_data:
|
||||||
|
block_bbox.extend(entity_bbox)
|
||||||
|
|
||||||
|
return block_bbox
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler bei INSERT Bounding Box: {e}")
|
||||||
|
return BoundingBox()
|
||||||
|
|
||||||
|
|
||||||
|
def get_insert_transform_matrix(insert_entity):
|
||||||
|
"""
|
||||||
|
Berechnet die Transformationsmatrix für einen INSERT
|
||||||
|
"""
|
||||||
|
# Position
|
||||||
|
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)
|
||||||
|
|
||||||
|
# Rotation (in Radiant umwandeln)
|
||||||
|
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)
|
||||||
|
)
|
||||||
|
|
||||||
|
return matrix
|
||||||
|
|
||||||
|
|
||||||
|
def copy_entity_to_block(entity, target_block):
|
||||||
|
"""
|
||||||
|
Kopiert eine Entity in einen Zielblock
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Entity kopieren und zum Block hinzufügen
|
||||||
|
entity_copy = entity.copy()
|
||||||
|
target_block.add_entity(entity_copy)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler beim Kopieren von {entity.dxftype()}: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
def add_bounding_box_to_modelspace(msp, bbox):
|
||||||
|
"""
|
||||||
|
Fügt die Bounding Box als Hilfslinien zum Modelspace hinzu
|
||||||
|
"""
|
||||||
|
if not bbox.has_data:
|
||||||
|
return
|
||||||
|
|
||||||
|
# Bounding Box Rechteck zeichnen
|
||||||
|
min_pt = bbox.extmin
|
||||||
|
max_pt = bbox.extmax
|
||||||
|
|
||||||
|
# Rechteck als LWPOLYLINE
|
||||||
|
bbox_points = [
|
||||||
|
(min_pt.x, min_pt.y),
|
||||||
|
(max_pt.x, min_pt.y),
|
||||||
|
(max_pt.x, max_pt.y),
|
||||||
|
(min_pt.x, max_pt.y),
|
||||||
|
(min_pt.x, min_pt.y)
|
||||||
|
]
|
||||||
|
|
||||||
|
bbox_poly = msp.add_lwpolyline(bbox_points)
|
||||||
|
bbox_poly.dxf.layer = "BOUNDING_BOX"
|
||||||
|
bbox_poly.dxf.color = 1 # Rot
|
||||||
|
|
||||||
|
# Bemaßungen hinzufügen
|
||||||
|
width = max_pt.x - min_pt.x
|
||||||
|
height = max_pt.y - min_pt.y
|
||||||
|
|
||||||
|
# Text mit Abmessungen
|
||||||
|
text_pos = Vec3(min_pt.x, 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(min_pt.x, 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):
|
||||||
|
"""
|
||||||
|
Formatiert Bounding Box Information für Ausgabe
|
||||||
|
"""
|
||||||
|
if not bbox.has_data:
|
||||||
|
return "Keine gültigen Geometriedaten gefunden"
|
||||||
|
|
||||||
|
min_pt = bbox.extmin
|
||||||
|
max_pt = bbox.extmax
|
||||||
|
width = max_pt.x - min_pt.x
|
||||||
|
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}) "
|
||||||
|
f"Max: ({max_pt.x:.2f}, {max_pt.y:.2f}, {max_pt.z:.2f}) "
|
||||||
|
f"Größe: {width:.2f} × {height:.2f} × {depth:.2f} mm")
|
||||||
|
|
||||||
|
|
||||||
|
def analyze_source_dxf_with_blocks(filename):
|
||||||
|
"""
|
||||||
|
Analysiert die Quell-DXF inklusive Block-Definitionen
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
doc = ezdxf.readfile(filename)
|
||||||
|
msp = doc.modelspace()
|
||||||
|
|
||||||
|
entity_types = {}
|
||||||
|
layer_count = {}
|
||||||
|
insert_blocks = {}
|
||||||
|
block_definitions = {}
|
||||||
|
|
||||||
|
# Modelspace analysieren
|
||||||
|
for entity in msp:
|
||||||
|
entity_type = entity.dxftype()
|
||||||
|
entity_types[entity_type] = entity_types.get(entity_type, 0) + 1
|
||||||
|
|
||||||
|
layer = getattr(entity.dxf, 'layer', '0')
|
||||||
|
layer_count[layer] = layer_count.get(layer, 0) + 1
|
||||||
|
|
||||||
|
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
|
||||||
|
block_def = doc.blocks[block_name]
|
||||||
|
entity_count = len(list(block_def))
|
||||||
|
block_definitions[block_name] = entity_count
|
||||||
|
|
||||||
|
print(f"\nAnalyse von {filename}:")
|
||||||
|
print("=" * 50)
|
||||||
|
print("Entity-Typen im Modelspace:")
|
||||||
|
for etype, count in sorted(entity_types.items()):
|
||||||
|
print(f" {etype}: {count}")
|
||||||
|
|
||||||
|
print(f"\nLayer ({len(layer_count)}):")
|
||||||
|
for layer, count in sorted(layer_count.items()):
|
||||||
|
print(f" {layer}: {count} entities")
|
||||||
|
|
||||||
|
if insert_blocks:
|
||||||
|
print(f"\nINSERT-Verwendungen ({sum(insert_blocks.values())} total):")
|
||||||
|
for block, count in sorted(insert_blocks.items()):
|
||||||
|
print(f" {block}: {count}× verwendet")
|
||||||
|
|
||||||
|
if block_definitions:
|
||||||
|
print(f"\nBlock-Definitionen ({len(block_definitions)}):")
|
||||||
|
for block, count in sorted(block_definitions.items()):
|
||||||
|
print(f" {block}: {count} entities")
|
||||||
|
|
||||||
|
return entity_types, layer_count, insert_blocks, block_definitions
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Fehler bei der Analyse: {e}")
|
||||||
|
return {}, {}, {}, {}
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# Argumentparser für Kommandozeilenoptionen
|
# Argumentparser für Kommandozeilenoptionen
|
||||||
parser = argparse.ArgumentParser(description="SVG/XML zu DXF Konverter")
|
parser = argparse.ArgumentParser(description="SVG/XML zu DXF Konverter")
|
||||||
|
|||||||
Reference in New Issue
Block a user