From e3494530ea58d2ca29244cc3b52c7801b30f7cd3 Mon Sep 17 00:00:00 2001 From: Paul Wolok Date: Wed, 10 Sep 2025 15:32:06 +0200 Subject: [PATCH] Inserts richtig in die Bounding box reingetan --- lib/dxf2lib.py | 260 +++++++++++++++---------------------------------- 1 file changed, 80 insertions(+), 180 deletions(-) diff --git a/lib/dxf2lib.py b/lib/dxf2lib.py index 46d05c8..f70717b 100644 --- a/lib/dxf2lib.py +++ b/lib/dxf2lib.py @@ -161,6 +161,8 @@ def create_block_library(input_dir, output_file, config, logger=None): max_blockspacing_y = 0 for filename in os.listdir(input_dir): + if filename =='821104043.dxf': + test = 2 if not filename.lower().endswith(".dxf"): continue @@ -213,8 +215,7 @@ def create_block_library(input_dir, output_file, config, logger=None): except Exception: pass - if filename == "0_BG090090_834372101_0_BG090090.dxf": - filetest =3 + # center, ausdehnung = get_bbox(entities) boundingbox, ausdehnung, center = calculate_block_bounding_box(filtered_entities, doc,src_doc, filename) if center is None: @@ -238,8 +239,8 @@ def create_block_library(input_dir, output_file, config, logger=None): for e in entities: cp = copy_entity(logger, error_files, filename, e, center) if cp: - copy_entity_to_block(cp,blk) - # blk.add_entity(cp) + blk.add_entity(cp) + add_bounding_box_to_modelspace(blk, boundingbox, centered=True) # Platzierung in Reihen und Spalten # Attribut-Definition (ATTDEF) hinzufügen blk.add_attdef( @@ -518,7 +519,8 @@ def calculate_block_bounding_box(block, doc, src_doc, filename): 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),Vec2(((bbox.extmax.x + bbox.extmin.x) / 2, (bbox.extmax.y + bbox.extmin.y) /2)) + + return bbox, (bbox.extmax.x -bbox.extmin.x, bbox.extmax.y -bbox.extmin.y),bbox.center def get_entity_bounding_box(e, doc,src_doc,filename, transform_matrix=None,): @@ -527,10 +529,7 @@ def get_entity_bounding_box(e, doc,src_doc,filename, transform_matrix=None,): Berücksichtigt INSERTs mit ihren Block-Inhalten """ - bbox = BoundingBox() - - - + bbox = BoundingBox() try: if e.dxftype() == 'LINE': start = Vec3(e.dxf.start) @@ -538,24 +537,24 @@ def get_entity_bounding_box(e, doc,src_doc,filename, transform_matrix=None,): if transform_matrix: start = transform_matrix.transform(start) end = transform_matrix.transform(end) - bbox.extend([start, end]) + bbox.extend([start]) + bbox.extend([end]) elif e.dxftype() == 'CIRCLE': # Kreis durch Punktabtastung (robust bei Transformationen) center = Vec3(e.dxf.center) radius = float(e.dxf.radius) - num = 72 - sampled = [] - for i in range(num): - ang = 2 * math.pi * (i / num) + angles = (0.0, math.pi / 2, math.pi, 3 * math.pi / 2) + points = [] + for ang in angles: px = center.x + radius * math.cos(ang) py = center.y + radius * math.sin(ang) p = Vec3(px, py, center.z) if transform_matrix: p = transform_matrix.transform(p) - sampled.append(p) - if sampled: - bbox.extend(sampled) + points.append(p) + if points: + bbox.extend(points) elif e.dxftype() == 'ARC': # Bogen durch Punktabtastung zwischen Start- und Endwinkel @@ -565,34 +564,28 @@ def get_entity_bounding_box(e, doc,src_doc,filename, transform_matrix=None,): end_deg = float(e.dxf.end_angle) start = math.radians(start_deg % 360) end = math.radians(end_deg % 360) - # Schritte abhängig vom Sweep - def sweep_steps(s, e_): + + def in_sweep(a: float, s: float, e_: float) -> bool: + # CCW sweep von s nach e_ mit Wrap-Handling if e_ >= s: - span = e_ - s - else: - span = (2 * math.pi - s) + e_ - return max(12, int(72 * span / (2 * math.pi))) - steps = sweep_steps(start, end) - sampled = [] - # CCW Sweeping - if end >= start: - angles = [start + (end - start) * (i / steps) for i in range(steps + 1)] - else: - angles = [] - span1 = 2 * math.pi - start - for i in range(int(steps * span1 / (2 * math.pi)) + 1): - angles.append(start + span1 * (i / max(1, int(steps * span1 / (2 * math.pi))))) - for i in range(1, steps - len(angles) + 2): - angles.append(0.0 + end * (i / (steps - len(angles) + 1))) + return s <= a <= e_ + return a >= s or a <= e_ + + angles = [start, end] + for ang in (0.0, math.pi / 2, math.pi, 3 * math.pi / 2): + if in_sweep(ang, start, end): + angles.append(ang) + + points = [] for ang in angles: px = center.x + radius * math.cos(ang) py = center.y + radius * math.sin(ang) p = Vec3(px, py, center.z) if transform_matrix: p = transform_matrix.transform(p) - sampled.append(p) - if sampled: - bbox.extend(sampled) + points.append(p) + if points: + bbox.extend(points) elif e.dxftype() == 'LWPOLYLINE': # Nutze virtuelle Entities (Linien/Bögen), inkl. Bulge-Unterstützung @@ -653,142 +646,30 @@ 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, -def get_entity_bounding_box_2(entity, doc,src_doc,filename, transform_matrix=None): - """ - Berechnet die Bounding Box einer einzelnen Entity - Berücksichtigt INSERTs mit ihren Block-Inhalten - """ - bbox = BoundingBox() - - - try: - if entity.dxftype() == 'LINE': - start = Vec3(entity.dxf.start) - end = Vec3(entity.dxf.end) - if transform_matrix: - start = transform_matrix.transform(start) - end = transform_matrix.transform(end) - bbox.extend([start, end]) - - elif entity.dxftype() == 'CIRCLE': - center = Vec3(entity.dxf.center) - radius = float(entity.dxf.radius) - num = 72 - sampled = [] - for i in range(num): - ang = 2 * math.pi * (i / num) - px = center.x + radius * math.cos(ang) - py = center.y + radius * math.sin(ang) - p = Vec3(px, py, center.z) - if transform_matrix: - p = transform_matrix.transform(p) - sampled.append(p) - if sampled: - bbox.extend(sampled) - - elif entity.dxftype() == 'ARC': - center = Vec3(entity.dxf.center) - radius = float(entity.dxf.radius) - start_deg = float(entity.dxf.start_angle) - end_deg = float(entity.dxf.end_angle) - start = math.radians(start_deg % 360) - end = math.radians(end_deg % 360) - def sweep_steps(s, e_): - if e_ >= s: - span = e_ - s - else: - span = (2 * math.pi - s) + e_ - return max(12, int(72 * span / (2 * math.pi))) - steps = sweep_steps(start, end) - sampled = [] - if end >= start: - angles = [start + (end - start) * (i / steps) for i in range(steps + 1)] - else: - angles = [] - span1 = 2 * math.pi - start - for i in range(int(steps * span1 / (2 * math.pi)) + 1): - angles.append(start + span1 * (i / max(1, int(steps * span1 / (2 * math.pi))))) - for i in range(1, steps - len(angles) + 2): - angles.append(0.0 + end * (i / (steps - len(angles) + 1))) - for ang in angles: - px = center.x + radius * math.cos(ang) - py = center.y + radius * math.sin(ang) - p = Vec3(px, py, center.z) - if transform_matrix: - p = transform_matrix.transform(p) - sampled.append(p) - if sampled: - bbox.extend(sampled) - - elif entity.dxftype() == 'LWPOLYLINE': - for ve in entity.virtual_entities(): - ve_bbox = get_entity_bounding_box_2(ve, doc, src_doc, filename, transform_matrix)[0] - if ve_bbox and ve_bbox.has_data: - bbox.extend(ve_bbox) - - elif entity.dxftype() == 'POLYLINE': - for ve in entity.virtual_entities(): - ve_bbox = get_entity_bounding_box_2(ve, doc, src_doc, filename, transform_matrix)[0] - if ve_bbox and ve_bbox.has_data: - bbox.extend(ve_bbox) - - elif entity.dxftype() == 'SPLINE': - try: - pts = list(entity.approximate(60)) - except Exception: - try: - pts = list(entity.flattening(1.0)) - except Exception: - pts = [] - sampled = [] - for pt in pts: - try: - vx, vy = pt.x, pt.y - except Exception: - vx, vy = pt[0], pt[1] - v = Vec3(vx, vy, 0) - if transform_matrix: - v = transform_matrix.transform(v) - sampled.append(v) - if sampled: - bbox.extend(sampled) - - elif entity.dxftype() == 'TEXT': - insert_point = Vec3(entity.dxf.insert) - if transform_matrix: - insert_point = transform_matrix.transform(insert_point) - bbox.extend([insert_point]) - - elif entity.dxftype() == 'INSERT': - insert_bbox = calculate_insert_bounding_box(entity, doc,src_doc,filename, 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},{filename}") - - return bbox, def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,parent_transform=None): """ Berechnet die Bounding Box eines INSERTs inklusive Block-Inhalt """ try: - if filename == "0_BG071090_834372404.dxf": - filetest = 3 - # Block-Definition finden + # Block-Definition finden block_name = insert_entity.dxf.name src_blk = src_doc.blocks[block_name] - + if block_name == "ccLab_2025312125317867_51": + print(filename) if block_name in doc.blocks: - return BoundingBox() + dst_blk = doc.blocks[block_name] + + new_insert = False + else: dst_blk = doc.blocks.new(name=block_name) - + new_insert = True if block_name not in src_doc.blocks: print(f"Warnung: Block '{block_name}' ") return BoundingBox() + block_def = src_blk @@ -806,10 +687,12 @@ def calculate_insert_bounding_box(insert_entity, doc,src_doc,filename,parent_tra for block_entity in block_def: - entity_bbox,= get_entity_bounding_box_2(block_entity, doc,src_doc,filename, combined_transform) + entity_bbox= get_entity_bounding_box(block_entity, doc,src_doc,filename, combined_transform) if entity_bbox and entity_bbox.has_data: - dst_blk.add_entity(block_entity.copy()) + if new_insert: + dst_blk.add_entity(block_entity.copy()) block_bbox.extend(entity_bbox) + return block_bbox except Exception as e: @@ -855,9 +738,11 @@ def copy_entity_to_block(entity, target_block): print(f"Fehler beim Kopieren von {entity.dxftype()}: {e}") -def add_bounding_box_to_modelspace(msp, bbox): +def add_bounding_box_to_modelspace(msp, bbox, centered=False): """ - Fügt die Bounding Box als Hilfslinien zum Modelspace hinzu + Fügt die Bounding Box als Hilfslinien zum Modelspace hinzu. + Wenn centered=True, wird das Rechteck um den Ursprung (0,0) zentriert und + ein roter Punkt in die Mitte gesetzt. """ if not bbox.has_data: return @@ -865,32 +750,47 @@ def add_bounding_box_to_modelspace(msp, bbox): # Bounding Box Rechteck zeichnen min_pt = bbox.extmin max_pt = bbox.extmax + width = max_pt.x - min_pt.x + height = max_pt.y - min_pt.y - # 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) - ] + if centered: + # Rechteck um (0,0) zentriert + left = -width / 2.0 + right = width / 2.0 + bottom = -height / 2.0 + top = height / 2.0 + bbox_points = [ + (left, bottom), + (right, bottom), + (right, top), + (left, top), + (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}) + else: + # Ursprüngliche, nicht-zentrierte Bounding Box + 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_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(min_pt.x, max_pt.y + 10, 0) + 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}) + dxfattribs={'insert': text_pos2, 'layer': "BOUNDING_BOX", 'color': 1}) def format_bounding_box(bbox):