def draw_solid_entity(self, entity: DXFGraphic, properties: Properties) -> None: if isinstance(entity, Face3d): dxf = entity.dxf try: # this implementation supports all features of example file: # examples_dxf/3dface.dxf without changing the behavior of # Face3d.wcs_vertices() which removes the last vertex if # duplicated. points = [dxf.vtx0, dxf.vtx1, dxf.vtx2, dxf.vtx3, dxf.vtx0] except AttributeError: # all 4 vertices are required, otherwise the entity is invalid # for AutoCAD self.skip_entity(entity, "missing required vertex attribute") return edge_visibility = entity.get_edges_visibility() if all(edge_visibility): self.out.draw_path(from_vertices(points), properties) else: for a, b, visible in zip(points, points[1:], edge_visibility): if visible: self.out.draw_line(a, b, properties) elif isinstance(entity, Solid): # set solid fill type for SOLID and TRACE properties.filling = Filling() self.out.draw_filled_polygon(entity.wcs_vertices(close=False), properties) else: raise TypeError( "API error, requires a SOLID, TRACE or 3DFACE entity")
def test_backend_default_draw_path(): backend = BasicBackend() path = from_vertices([(0, 0), (1, 0), (2, 0)]) backend.draw_path(path, Properties()) result = backend.collector assert len(result) == 2 assert result[0][0] == "line"
def _convert_entity(self): """ Calculates the rough border path for a single line text. Calculation is based on a mono-spaced font and therefore the border path is just an educated guess. Vertical text generation and oblique angle is ignored. """ def get_text_rotation() -> float: if alignment in ('FIT', 'ALIGNED') and not p1.isclose(p2): return (p2 - p1).angle else: return math.degrees(text.dxf.rotation) def get_insert() -> Vec3: if alignment == 'LEFT': return p1 elif alignment in ('FIT', 'ALIGNED'): return p1.lerp(p2, factor=0.5) else: return p2 text = cast('Text', self.entity) if text.dxftype() == 'ATTDEF': # ATTDEF outside of a BLOCK renders the tag rather than the value content = text.dxf.tag else: content = text.dxf.text content = plain_text(content) if len(content) == 0: # empty path - does not render any vertices! self._path = Path() return p1: Vec3 = text.dxf.insert p2: Vec3 = text.dxf.align_point font = fonts.make_font(get_font_name(text), text.dxf.height, text.dxf.width) text_line = TextLine(content, font) alignment: str = text.get_align() if text.dxf.halign > 2: # ALIGNED=3, MIDDLE=4, FIT=5 text_line.stretch(alignment, p1, p2) halign, valign = unified_alignment(text) corner_vertices = text_line.corner_vertices(get_insert(), halign, valign, get_text_rotation()) ocs = text.ocs() self._path = from_vertices( ocs.points_to_wcs(corner_vertices), close=True, )
def draw_solid_entity(self, entity: DXFGraphic, properties: Properties) -> None: assert isinstance(entity, (Solid, Face3d)), \ "API error, requires a SOLID, TRACE or 3DFACE entity" dxf, dxftype = entity.dxf, entity.dxftype() points = entity.wcs_vertices() if dxftype == '3DFACE': self.out.draw_path(from_vertices(points, close=True), properties) else: # set solid fill type for SOLID and TRACE properties.filling = Filling() self.out.draw_filled_polygon(points, properties)
def draw_solid_entity(self, entity: DXFGraphic, properties: Properties) -> None: # Handles SOLID, TRACE and 3DFACE dxf, dxftype = entity.dxf, entity.dxftype() points = get_tri_or_quad_points(entity, adjust_order=dxftype != '3DFACE') # TRACE is an OCS entity if dxftype == 'TRACE' and dxf.hasattr('extrusion'): ocs = entity.ocs() points = list(ocs.points_to_wcs(points)) if dxftype == '3DFACE': self.out.draw_path(from_vertices(points, close=True), properties) else: # Set default SOLID filling for SOLID and TRACE properties.filling = Filling() self.out.draw_filled_polygon(points, properties)
def draw_mesh_builder_entity(self, builder: MeshBuilder, properties: Properties) -> None: for face in builder.faces_as_vertices(): self.out.draw_path(from_vertices(face, close=True), properties=properties)
def test_only_vertices(self): p = from_vertices([(1, 0), (2, 0), (3, 1)]) result = list(to_bsplines_and_vertices(p)) assert len(result) == 1, "expected one list of vertices" assert len(result[0]) == 3, "expected 3 vertices"
def _convert_entity(self): """Calculates the rough border path for a MTEXT entity. Calculation is based on a mono-spaced font and therefore the border path is just an educated guess. Most special features of MTEXT is not supported. """ def get_content() -> List[str]: text = mtext.plain_text(split=False) return text_wrap(text, box_width, font.text_width) # type: ignore def get_max_str() -> str: return max(content, key=lambda s: len(s)) def get_rect_width() -> float: if box_width: return box_width s = get_max_str() if len(s) == 0: s = " " return font.text_width(s) def get_rect_height() -> float: line_height = font.measurements.total_height cap_height = font.measurements.cap_height # Line spacing factor: Percentage of default (3-on-5) line # spacing to be applied. # thx to mbway: multiple of cap_height between the baseline of the # previous line and the baseline of the next line # 3-on-5 line spacing = 5/3 = 1.67 line_spacing = cap_height * mtext.dxf.line_spacing_factor * 1.67 spacing = line_spacing - line_height line_count = len(content) return line_height * line_count + spacing * (line_count - 1) def get_ucs() -> UCS: """Create local coordinate system: origin = insertion point z-axis = extrusion vector x-axis = text_direction or text rotation, text rotation requires extrusion vector == (0, 0, 1) or treatment like an OCS? """ origin = mtext.dxf.insert z_axis = mtext.dxf.extrusion # default is Z_AXIS x_axis = X_AXIS if mtext.dxf.hasattr("text_direction"): x_axis = mtext.dxf.text_direction elif mtext.dxf.hasattr("rotation"): # TODO: what if extrusion vector is not (0, 0, 1) x_axis = Vec3.from_deg_angle(mtext.dxf.rotation) z_axis = Z_AXIS return UCS(origin=origin, ux=x_axis, uz=z_axis) def get_shift_factors(): halign, valign = unified_alignment(mtext) shift_x = 0 shift_y = 0 if halign == const.CENTER: shift_x = -0.5 elif halign == const.RIGHT: shift_x = -1.0 if valign == const.MIDDLE: shift_y = 0.5 elif valign == const.BOTTOM: shift_y = 1.0 return shift_x, shift_y def get_corner_vertices() -> Iterable[Vec3]: """Create corner vertices in the local working plan, where the insertion point is the origin. """ if columns: rect_width = columns.total_width rect_height = columns.total_height # TODO: this works only for reliable sources like AutoCAD, # BricsCAD and ezdxf! So far no known column support from # other DXF exporters. else: rect_width = mtext.dxf.get("rect_width", get_rect_width()) rect_height = mtext.dxf.get("rect_height", get_rect_height()) # TOP LEFT alignment: vertices = [ Vec3(0, 0), Vec3(rect_width, 0), Vec3(rect_width, -rect_height), Vec3(0, -rect_height), ] sx, sy = get_shift_factors() shift = Vec3(sx * rect_width, sy * rect_height) return (v + shift for v in vertices) mtext: "MText" = cast("MText", self.entity) columns = mtext.columns if columns is None: box_width = mtext.dxf.get("width", 0) font = fonts.make_font(get_font_name(mtext), mtext.dxf.char_height, 1.0) content: List[str] = get_content() if len(content) == 0: # empty path - does not render any vertices! self._path = Path() return ucs = get_ucs() corner_vertices = get_corner_vertices() self._path = from_vertices( ucs.points_to_wcs(corner_vertices), close=True, )
def _convert_entity(self): """Calculates the rough border path for a single line text. Calculation is based on a mono-spaced font and therefore the border path is just an educated guess. Vertical text generation and oblique angle is ignored. """ def text_rotation(): if fit_or_aligned and not p1.isclose(p2): return (p2 - p1).angle else: return math.radians(text.dxf.rotation) def location(): if fit_or_aligned: return p1.lerp(p2, factor=0.5) return p1 text = cast("Text", self.entity) if text.dxftype() == "ATTDEF": # ATTDEF outside of a BLOCK renders the tag rather than the value content = text.dxf.tag else: content = text.dxf.text content = plain_text(content) if len(content) == 0: # empty path - does not render any vertices! self._path = Path() return font = fonts.make_font(get_font_name(text), text.dxf.height, text.dxf.width) text_line = TextLine(content, font) alignment, p1, p2 = text.get_placement() if p2 is None: p2 = p1 fit_or_aligned = (alignment == TextEntityAlignment.FIT or alignment == TextEntityAlignment.ALIGNED) if text.dxf.halign > 2: # ALIGNED=3, MIDDLE=4, FIT=5 text_line.stretch(alignment, p1, p2) halign, valign = unified_alignment(text) mirror_x = -1 if text.is_backward else 1 mirror_y = -1 if text.is_upside_down else 1 oblique: float = math.radians(text.dxf.oblique) corner_vertices = text_line.corner_vertices( location(), halign, valign, angle=text_rotation(), scale=(mirror_x, mirror_y), oblique=oblique, ) ocs = text.ocs() self._path = from_vertices( ocs.points_to_wcs(corner_vertices), close=True, )
# Copyright (c) 2020, Manfred Moitzi # License: MIT License import pytest from ezdxf.render.forms import square, translate from ezdxf.path import Path, nesting, from_vertices EXTERIOR = list(translate(square(10), (-5, -5))) EXT1_PATH = from_vertices(EXTERIOR) EXT2_PATH = from_vertices(translate(EXTERIOR, (11, 0))) CENTER_HOLE1 = list(translate(square(8), (-4, -4))) CH1_PATH = from_vertices(CENTER_HOLE1) CENTER_HOLE2 = list(translate(square(6), (-3, -3))) CH2_PATH = from_vertices(CENTER_HOLE2) LEFT_HOLE = list(translate(square(2.1), (-3, -1))) LH_PATH = from_vertices(LEFT_HOLE) RIGHT_HOLE = list(translate(square(2.0), (3, -1))) RH_PATH = from_vertices(RIGHT_HOLE) DETECTION_DATA = [ pytest.param( # Each polygon is a list of paths [EXT1_PATH], [[EXT1_PATH]], id="1 path", ), pytest.param(