def multi_recursive(entities: Iterable['DXFEntity'], cache: Cache = None) -> Iterable[BoundingBox]: """ Yields all bounding boxes for the given `entities` **or** all bounding boxes for their sub entities. If an entity (INSERT) has sub entities, only the bounding boxes of these sub entities will be yielded, **not** the bounding box of entity (INSERT) itself. """ flat_entities = disassemble.recursive_decompose(entities) primitives = disassemble.to_primitives(flat_entities) for primitive in primitives: if primitive.is_empty: continue entity = primitive.entity if cache is not None: box = cache.get(entity) if box is None: box = BoundingBox(primitive.vertices()) if box.has_data: cache.store(entity, box) else: box = BoundingBox(primitive.vertices()) if box.has_data: yield box
def test_hatch_returns_multiple_primitives(): hatch = factory.new('HATCH') paths = hatch.paths # Conversion of boundary paths is tested in 708. paths.add_polyline_path([(0, 0), (1, 0), (1, 1)]) paths.add_polyline_path([(0, 2), (1, 2), (1, 3), (0, 3)]) res = list(disassemble.to_primitives([hatch])) assert len(res) == 2 assert len(list(res[0].vertices())) == 4, "expected closed triangle" assert len(list(res[1].vertices())) == 5, "expected closed box"
def test_hatch_returns_multiple_primitives(): hatch = factory.new("HATCH") paths = hatch.paths # Conversion of boundary paths is tested in 708. paths.add_polyline_path([(0, 0), (1, 0), (1, 1)]) paths.add_polyline_path([(0, 2), (1, 2), (1, 3), (0, 3)]) res = list(disassemble.to_primitives([hatch])) assert len(res) == 1 p = res[0] assert p.path is not None assert p.path.has_sub_paths is True p0, p1 = p.path.sub_paths() v0 = list(p0.approximate()) v1 = list(p1.approximate()) assert len(v0) == 4, "expected closed triangle" assert len(v1) == 5, "expected closed box"
def save(self, filename: str) -> None: # Convert entities to primitives primitives = disassemble.to_primitives(self.msp) # Collect paths from primitives: paths = [p.path for p in primitives if p.path] # Render this paths as HATCH entities path.render_hatches(self.msp, paths, dxfattribs={ "layer": "HATCHES", "color": 2 }) self.doc.set_modelspace_vport(15, (4, 4)) self.doc.saveas(DIR / f"{filename}.dxf")
def multi_recursive( entities: Iterable["DXFEntity"], *, flatten: float = MAX_FLATTENING_DISTANCE, cache: Cache = None, ) -> Iterable[BoundingBox]: """Yields all bounding boxes for the given `entities` **or** all bounding boxes for their sub entities. If an entity (INSERT) has sub entities, only the bounding boxes of these sub entities will be yielded, **not** the bounding box of entity (INSERT) itself. Calculate bounding boxes from flattened curves, if argument `flatten` is not 0 (max flattening distance), else from control points. """ def vertices(p: disassemble.Primitive) -> Iterable[Vec3]: if flatten: primitive.max_flattening_distance = abs(flatten) return primitive.vertices() else: return disassemble.to_control_vertices([p]) flat_entities = disassemble.recursive_decompose(entities) primitives = disassemble.to_primitives(flat_entities) for primitive in primitives: if primitive.is_empty: continue entity = primitive.entity if cache is not None: box = cache.get(entity) if box is None: box = BoundingBox(vertices(primitive)) if box.has_data: cache.store(entity, box) else: box = BoundingBox(vertices(primitive)) if box.has_data: yield box
def multi_recursive(entities: Iterable['DXFEntity'], *, flatten: bool = True, cache: Cache = None) -> Iterable[BoundingBox]: """ Yields all bounding boxes for the given `entities` **or** all bounding boxes for their sub entities. If an entity (INSERT) has sub entities, only the bounding boxes of these sub entities will be yielded, **not** the bounding box of entity (INSERT) itself. Calculate bounding boxes from flattened curves, if argument `flatten` is ``True``, else from control points. """ def vertices(p: disassemble.Primitive) -> Iterable[Vec3]: if not flatten: return disassemble.to_control_vertices([p]) return primitive.vertices() flat_entities = disassemble.recursive_decompose(entities) primitives = disassemble.to_primitives(flat_entities) for primitive in primitives: if primitive.is_empty: continue entity = primitive.entity if cache is not None: box = cache.get(entity) if box is None: box = BoundingBox(vertices(primitive)) if box.has_data: cache.store(entity, box) else: box = BoundingBox(vertices(primitive)) if box.has_data: yield box
doc.layers.new("FORMS", dxfattribs={"color": 1}) doc.layers.new("HATCHES") msp = doc.modelspace() attribs = {"layer": "FORMS"} # Create DXF primitives: msp.add_circle((2, 3), radius=2, dxfattribs=attribs) # Ellipse with hole: msp.add_ellipse((5, 0), major_axis=(3, 1), ratio=0.5, dxfattribs=attribs) msp.add_circle((5, 0), radius=1.5, dxfattribs=attribs) # Rectangle with a hole rect = translate(box(3, 2), (3, 6)) msp.add_lwpolyline(rect, close=True, dxfattribs=attribs) hole = translate(box(2, 1), (3.4, 6.4)) msp.add_lwpolyline(hole, close=True, dxfattribs=attribs) # Convert entities to primitives primitives = disassemble.to_primitives(msp) # Collect paths from primitives: paths = [p.path for p in primitives if p.path] # Render this paths as HATCH entities path.render_hatches(msp, paths, dxfattribs={"layer": "HATCHES", "color": 2}) doc.set_modelspace_vport(15, (4, 4)) doc.saveas(DIR / "hatches_from_entities.dxf")
def test_do_nothing(): assert list(disassemble.recursive_decompose([])) == [] assert list(disassemble.to_primitives([])) == [] assert list(disassemble.to_vertices([])) == []
def test_multiple_unsupported_entities_to_vertices(): w = factory.new("3DSOLID") primitives = list(disassemble.to_primitives([w, w, w])) assert len(primitives) == 3, "3 empty primitives expected" vertices = list(disassemble.to_vertices(primitives)) assert len(vertices) == 0, "no vertices expected"
# License: MIT License import pathlib import ezdxf from ezdxf import disassemble, zoom from ezdxf.tools import fonts DIR = pathlib.Path('~/Desktop/Outbox').expanduser() fonts.load() FILES = [ 'text_fonts.dxf', 'text_oblique_rotate.dxf', 'text_mirror_true_type_font.dxf', 'text_stacked_shx_font.dxf', ] for filename in FILES: print(f"Processing: {filename}") doc = ezdxf.readfile( pathlib.Path(__file__).parent.parent / 'examples_dxf' / filename) msp = doc.modelspace() # required to switch layer on/off doc.layers.new('TEXT_FRAME', dxfattribs={'color': 6}) for frame in disassemble.to_primitives(msp.query('TEXT')): msp.add_lwpolyline(frame.vertices(), close=True, dxfattribs={'layer': 'TEXT_FRAME'}) zoom.extents(msp, factor=1.1) doc.saveas(DIR / filename)
FILE1 = "text_mirror_true_type_font.dxf" FILE2 = "text_oblique_rotate.dxf" FILE = FILE2 doc = ezdxf.readfile(EXAMPLES / FILE) doc.layers.new('OUTLINE', dxfattribs={'color': 1}) doc.layers.new('BBOX', dxfattribs={'color': 5}) msp = doc.modelspace() text_entities = msp.query('TEXT') # Convert TEXT entities into SPLINE and POLYLINE entities: kind = text2path.Kind.SPLINES for text in text_entities: for e in text2path.virtual_entities(text, kind=kind): e.dxf.layer = 'OUTLINE' e.dxf.color = const.BYLAYER msp.add_entity(e) # Add bounding boxes attrib = {'layer': 'BBOX'} boxes = [] # The "primitive" representation for TEXT entities is the bounding box: for prim in disassemble.to_primitives(text_entities): p = msp.add_lwpolyline(prim.vertices(), dxfattribs=attrib) boxes.append(p) # Zoom on bounding boxes (fast): zoom.objects(msp, boxes,factor=1.1) doc.saveas(OUTBOX / FILE)
import pathlib import ezdxf from ezdxf import disassemble, zoom from ezdxf.tools import fonts DIR = pathlib.Path("~/Desktop/Outbox").expanduser() fonts.load() FILES = [ "text_fonts.dxf", "text_oblique_rotate.dxf", "text_mirror_true_type_font.dxf", "text_stacked_shx_font.dxf", ] for filename in FILES: print(f"Processing: {filename}") doc = ezdxf.readfile( pathlib.Path(__file__).parent.parent / "examples_dxf" / filename ) msp = doc.modelspace() # required to switch layer on/off doc.layers.add("TEXT_FRAME", color=6) for frame in disassemble.to_primitives(msp.query("TEXT")): msp.add_lwpolyline( frame.vertices(), close=True, dxfattribs={"layer": "TEXT_FRAME"} ) zoom.extents(msp, factor=1.1) doc.saveas(DIR / filename)