def write(self, entity: DXFGraphic): """ Write a DXF entity from the source DXF file to the export file. Don't write entities from different documents than the source DXF file, dependencies and resources will not match, maybe it will work once, but not in a reliable way for different DXF documents. """ # remove all possible dependencies entity.xdata = None entity.appdata = None entity.extension_dict = None entity.reactors = None # reset text stream self.text.seek(0) self.text.truncate() entity.export_dxf(self.entity_writer) if entity.dxftype() == 'POLYLINE': polyline = cast('Polyline', entity) for vertex in polyline.vertices: vertex.export_dxf(self.entity_writer) polyline.seqend.export_dxf(self.entity_writer) elif entity.dxftype() == 'INSERT': insert = cast('Insert', entity) if insert.attribs_follow: for attrib in insert.attribs: attrib.export_dxf(self.entity_writer) insert.seqend.export_dxf(self.entity_writer) data = self.text.getvalue().encode(self.loader.encoding) self.file.write(data)
def draw_composite_entity(self, entity: DXFGraphic, properties: Properties) -> None: def set_opaque(entities: Iterable[DXFGraphic]): for child in entities: # todo: defaults to 1.0 (fully transparent)??? child.transparency = 0.0 yield child def draw_insert(insert: Insert): self.draw_entities(insert.attribs) # draw_entities() includes the visibility check: self.draw_entities( insert.virtual_entities( skipped_entity_callback=self.skip_entity)) dxftype = entity.dxftype() if dxftype == 'INSERT': entity = cast(Insert, entity) self.ctx.push_state(properties) if entity.mcount > 1: for virtual_insert in entity.multi_insert(): draw_insert(virtual_insert) else: draw_insert(entity) self.ctx.pop_state() # DIMENSION, ARC_DIMENSION, LARGE_RADIAL_DIMENSION, LEADER # todo: ACAD_TABLE, MLINE, MLEADER elif hasattr(entity, 'virtual_entities'): # draw_entities() includes the visibility check: self.draw_entities(set_opaque(entity.virtual_entities())) else: raise TypeError(dxftype)
def draw_entity(self, entity: DXFGraphic) -> None: dxftype = entity.dxftype() self.out.set_current_entity(entity, tuple(self.parent_stack)) if dxftype in {'LINE', 'XLINE', 'RAY'}: self.draw_line_entity(entity) elif dxftype in {'TEXT', 'MTEXT', 'ATTRIB'}: if is_spatial(Vector(entity.dxf.extrusion)): self.draw_text_entity_3d(entity) else: self.draw_text_entity_2d(entity) elif dxftype in {'CIRCLE', 'ARC', 'ELLIPSE'}: if is_spatial(Vector(entity.dxf.extrusion)): self.draw_elliptic_arc_entity_3d(entity) else: self.draw_elliptic_arc_entity_2d(entity) elif dxftype == 'SPLINE': self.draw_spline_entity(entity) elif dxftype == 'POINT': self.draw_point_entity(entity) elif dxftype == 'HATCH': self.draw_hatch_entity(entity) elif dxftype == 'MESH': self.draw_mesh_entity(entity) elif dxftype in {'3DFACE', 'SOLID', 'TRACE'}: self.draw_solid_entity(entity) elif dxftype in {'POLYLINE', 'LWPOLYLINE'}: self.draw_polyline_entity(entity) elif dxftype in COMPOSITE_ENTITY_TYPES: self.draw_composite_entity(entity) elif dxftype == 'VIEWPORT': self.draw_viewport_entity(entity) else: print(f'ignoring {dxftype} entity') self.out.set_current_entity(None)
def draw_viewport_entity(self, entity: DXFGraphic, properties: Properties) -> None: assert entity.dxftype() == "VIEWPORT" # Special VIEWPORT id == 1, this viewport defines the "active viewport" # which is the area currently shown in the layout tab by the CAD # application. # BricsCAD set id to -1 if the viewport is off and 'status' (group # code 68) is not present. if entity.dxf.id < 2 or entity.dxf.status < 1: return dxf = entity.dxf view_vector: Vec3 = dxf.view_direction_vector mag = view_vector.magnitude if math.isclose(mag, 0.0): self.log_message("Warning: viewport with null view vector") return view_vector /= mag if not math.isclose(view_vector.dot(Vec3(0, 0, 1)), 1.0): self.log_message( f"Cannot render viewport with non-perpendicular view direction:" f" {dxf.view_direction_vector}") return cx, cy = dxf.center.x, dxf.center.y dx = dxf.width / 2 dy = dxf.height / 2 bottom_left = cx - dx, cy - dy top_right = cx + dx, cy + dy self._draw_rect(bottom_left, top_right, VIEWPORT_COLOR)
def draw_elliptic_arc_entity(self, entity: DXFGraphic, properties: Properties) -> None: dxftype = entity.dxftype() if NULLVEC.isclose(entity.dxf.extrusion): self.skip_entity( f'Invalid extrusion (0, 0, 0) in entity: {str(entity)}') return if dxftype == 'CIRCLE': if entity.dxf.radius <= 0: self.skip_entity(f'Invalid radius in entity: {str(entity)}') return path = Path.from_circle(cast('Circle', entity)) elif dxftype == 'ARC': if entity.dxf.radius <= 0: self.skip_entity(f'Invalid radius in entity: {str(entity)}') return path = Path.from_arc(cast('Arc', entity)) elif dxftype == 'ELLIPSE': if NULLVEC.isclose(entity.dxf.major_axis): self.skip_entity( f'Invalid major axis (0, 0, 0) in entity: {str(entity)}') return path = Path.from_ellipse(cast('Ellipse', entity)) else: # API usage error raise TypeError(dxftype) self.out.draw_path(path, properties)
def draw_point_entity(self, entity: DXFGraphic, properties: Properties) -> None: point = cast(Point, entity) pdmode = self.config.pdmode pdsize = self.config.pdsize assert pdmode is not None assert pdsize is not None # Defpoints are regular POINT entities located at the "defpoints" layer: if properties.layer.lower() == "defpoints": if not self.config.show_defpoints: return else: # Render defpoints as dimensionless points: pdmode = 0 if pdmode == 0: self.out.draw_point(entity.dxf.location, properties) else: for entity in point.virtual_entities(pdsize, pdmode): dxftype = entity.dxftype() if dxftype == "LINE": start = Vec3(entity.dxf.start) end = entity.dxf.end if start.isclose(end): self.out.draw_point(start, properties) else: self.out.draw_line(start, end, properties) pass elif dxftype == "CIRCLE": self.draw_curve_entity(entity, properties) else: raise ValueError(dxftype)
def draw_composite_entity(self, entity: DXFGraphic, properties: Properties) -> None: def draw_insert(insert: Insert): self.draw_entities(insert.attribs) # draw_entities() includes the visibility check: self.draw_entities( insert.virtual_entities( skipped_entity_callback=self.skip_entity)) if isinstance(entity, Insert): self.ctx.push_state(properties) if entity.mcount > 1: for virtual_insert in entity.multi_insert(): draw_insert(virtual_insert) else: draw_insert(entity) self.ctx.pop_state() elif isinstance(entity, SupportsVirtualEntities): # draw_entities() includes the visibility check: try: self.draw_entities(virtual_entities(entity)) except ProxyGraphicError as e: print(str(e)) print(POST_ISSUE_MSG) else: raise TypeError(entity.dxftype())
def draw_composite_entity(self, entity: DXFGraphic, properties: Properties) -> None: def set_opaque(entity): for child in entity.virtual_entities(): child.transparency = 0.0 # todo: defaults to 1.0 (fully transparent)??? yield child dxftype = entity.dxftype() if dxftype == 'INSERT': entity = cast(Insert, entity) self.ctx.push_state(properties) self.parent_stack.append(entity) # draw_entities() includes the visibility check: self.draw_entities(entity.attribs) self.draw_entities(entity.virtual_entities()) self.parent_stack.pop() self.ctx.pop_state() # DIMENSION, ARC_DIMENSION, LARGE_RADIAL_DIMENSION, LEADER # todo: ACAD_TABLE, MLINE, MLEADER elif hasattr(entity, 'virtual_entities'): self.parent_stack.append(entity) # draw_entities() includes the visibility check: self.draw_entities(set_opaque(entity)) self.parent_stack.pop() else: raise TypeError(dxftype)
def draw_point_entity(self, entity: DXFGraphic, properties: Properties) -> None: point = cast('Point', entity) pdmode = self.out.pdmode # Defpoints are regular POINT entities located at the "defpoints" layer: if properties.layer.lower() == 'defpoints': if not self.out.show_defpoints: return else: # Render defpoints as dimensionless points: pdmode = 0 pdsize = self.out.pdsize if pdsize <= 0: # relative points size is not supported pdsize = DEFAULT_PDSIZE if pdmode == 0: self.out.draw_point(entity.dxf.location, properties) else: for entity in point.virtual_entities(pdsize, pdmode): if entity.dxftype() == 'LINE': start = Vec3(entity.dxf.start) end = entity.dxf.end if start.isclose(end): self.out.draw_point(start, properties) else: self.out.draw_line(start, end, properties) pass else: # CIRCLE self.draw_elliptic_arc_entity(entity, properties)
def draw_viewport_entity(self, entity: DXFGraphic, properties: Properties) -> None: assert entity.dxftype() == 'VIEWPORT' # Special VIEWPORT id == 1, this viewport defines the "active viewport" # which is the area currently shown in the layout tab by the CAD # application. # BricsCAD set id to -1 if the viewport is off and 'status' (group # code 68) is not present. if entity.dxf.id < 2 or entity.dxf.status < 1: return dxf = entity.dxf view_vector: Vec3 = dxf.view_direction_vector mag = view_vector.magnitude if math.isclose(mag, 0.0): self.log_message('Warning: viewport with null view vector') return view_vector /= mag if not math.isclose(view_vector.dot(Vec3(0, 0, 1)), 1.0): self.log_message( f'Cannot render viewport with non-perpendicular view direction:' f' {dxf.view_direction_vector}') return cx, cy = dxf.center.x, dxf.center.y dx = dxf.width / 2 dy = dxf.height / 2 minx, miny = cx - dx, cy - dy maxx, maxy = cx + dx, cy + dy points = [(minx, miny), (maxx, miny), (maxx, maxy), (minx, maxy), (minx, miny)] props = Properties() props.color = VIEWPORT_COLOR # Set default SOLID filling for VIEWPORT props.filling = Filling() self.out.draw_filled_polygon([Vec3(x, y, 0) for x, y in points], props)
def draw_viewport_entity(self, entity: DXFGraphic) -> None: assert entity.dxftype() == 'VIEWPORT' dxf = entity.dxf view_vector: Vector = dxf.view_direction_vector mag = view_vector.magnitude if math.isclose(mag, 0.0): self.log_message('Warning: viewport with null view vector') return view_vector /= mag if not math.isclose(view_vector.dot(Vector(0, 0, 1)), 1.0): self.log_message( f'Cannot render viewport with non-perpendicular view direction:' f' {dxf.view_direction_vector}') return cx, cy = dxf.center.x, dxf.center.y dx = dxf.width / 2 dy = dxf.height / 2 minx, miny = cx - dx, cy - dy maxx, maxy = cx + dx, cy + dy points = [(minx, miny), (maxx, miny), (maxx, maxy), (minx, maxy), (minx, miny)] props = Properties() props.color = VIEWPORT_COLOR # Set default SOLID filling for VIEWPORT props.filling = Filling() self.out.draw_filled_polygon([Vector(x, y, 0) for x, y in points], props)
def draw_elliptic_arc_entity_2d(self, entity: DXFGraphic) -> None: dxf, dxftype = entity.dxf, entity.dxftype() properties = self._resolve_properties(entity) if dxftype == 'CIRCLE': center = _get_arc_wcs_center(entity) diameter = 2 * dxf.radius self.out.draw_arc(center, diameter, diameter, 0, None, properties) elif dxftype == 'ARC': center = _get_arc_wcs_center(entity) diameter = 2 * dxf.radius draw_angles = get_draw_angles(radians(dxf.start_angle), radians(dxf.end_angle), Vector(dxf.extrusion)) self.out.draw_arc(center, diameter, diameter, 0, draw_angles, properties) elif dxftype == 'ELLIPSE': # 'param' angles are anticlockwise around the extrusion vector # 'param' angles are relative to the major axis angle # major axis angle always anticlockwise in global frame major_axis_angle = normalize_angle( math.atan2(dxf.major_axis.y, dxf.major_axis.x)) width = 2 * dxf.major_axis.magnitude height = dxf.ratio * width # ratio == height / width draw_angles = get_draw_angles(dxf.start_param, dxf.end_param, Vector(dxf.extrusion)) self.out.draw_arc(dxf.center, width, height, major_axis_angle, draw_angles, properties) else: raise TypeError(dxftype)
def draw_elliptic_arc_entity_3d(self, entity: DXFGraphic) -> None: dxf, dxftype = entity.dxf, entity.dxftype() properties = self._resolve_properties(entity) if dxftype in {'CIRCLE', 'ARC'}: center = dxf.center # ocs transformation in .from_arc() radius = dxf.radius if dxftype == 'CIRCLE': start_angle = 0 end_angle = 360 else: start_angle = dxf.start_angle end_angle = dxf.end_angle e = ConstructionEllipse.from_arc(center, radius, dxf.extrusion, start_angle, end_angle) elif dxftype == 'ELLIPSE': e = cast(Ellipse, entity).construction_tool() else: raise TypeError(dxftype) # Approximate as 3D polyline segments = int((e.end_param - e.start_param) / math.tau * self.circle_approximation_count) points = list( e.vertices( linspace(e.start_param, e.end_param, max(4, segments + 1)))) self.out.start_path() for a, b in zip(points, points[1:]): self.out.draw_line(a, b, properties) self.out.end_path()
def draw_text_entity_2d(self, entity: DXFGraphic, properties: Properties) -> None: if isinstance(entity, Text): for line, transform, cap_height in simplified_text_chunks( entity, self.out, font=properties.font): self.out.draw_text(line, transform, properties, cap_height) else: raise TypeError(entity.dxftype())
def draw_text_entity_2d(self, entity: DXFGraphic) -> None: d, dxftype = entity.dxf, entity.dxftype() properties = self._resolve_properties(entity) if dxftype in ('TEXT', 'MTEXT', 'ATTRIB'): entity = cast(Union[Text, MText, Attrib], entity) for line, transform, cap_height in simplified_text_chunks(entity, self.out): self.out.draw_text(line, transform, properties, cap_height) else: raise TypeError(dxftype)
def draw_text_entity_2d(self, entity: DXFGraphic, properties: Properties) -> None: d, dxftype = entity.dxf, entity.dxftype() if dxftype in ('TEXT', 'MTEXT', 'ATTRIB', 'ATTDEF'): entity = cast(Union[Text, MText, Attrib, AttDef], entity) for line, transform, cap_height in simplified_text_chunks( entity, self.out, font=properties.font): self.out.draw_text(line, transform, properties, cap_height) else: raise TypeError(dxftype)
def mapping( entity: DXFGraphic, distance: float = MAX_FLATTENING_DISTANCE, force_line_string: bool = False, ) -> Dict: """Create the compiled ``__geo_interface__`` mapping as :class:`dict` for the given DXF `entity`, all coordinates are :class:`Vec3` objects and represents "Polygon" always as tuple (exterior, holes) even without holes. Internal API - result is **not** a valid ``_geo_interface__`` mapping! Args: entity: DXF entity distance: maximum flattening distance for curve approximations force_line_string: by default this function returns Polygon objects for closed geometries like CIRCLE, SOLID, closed POLYLINE and so on, by setting argument `force_line_string` to ``True``, this entities will be returned as LineString objects. """ dxftype = entity.dxftype() if isinstance(entity, Point): return {TYPE: POINT, COORDINATES: entity.dxf.location} elif isinstance(entity, Line): return line_string_mapping([entity.dxf.start, entity.dxf.end]) elif isinstance(entity, Polyline): if entity.is_3d_polyline or entity.is_2d_polyline: # May contain arcs as bulge values: path = make_path(entity) points = list(path.flattening(distance)) return _line_string_or_polygon_mapping(points, force_line_string) else: raise TypeError("Polymesh and Polyface not supported.") elif isinstance(entity, LWPolyline): # May contain arcs as bulge values: path = make_path(entity) points = list(path.flattening(distance)) return _line_string_or_polygon_mapping(points, force_line_string) elif dxftype in {"CIRCLE", "ARC", "ELLIPSE", "SPLINE"}: return _line_string_or_polygon_mapping( list(entity.flattening(distance)), force_line_string # type: ignore ) elif dxftype in {"SOLID", "TRACE", "3DFACE"}: return _line_string_or_polygon_mapping( entity.wcs_vertices(close=True), force_line_string # type: ignore ) elif isinstance(entity, DXFPolygon): return _hatch_as_polygon(entity, distance, force_line_string) else: raise TypeError(dxftype)
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 override_properties(self, entity: DXFGraphic, properties: Properties) -> None: """ The :meth:`override_properties` filter can change the properties of an entity independent from the DXF attributes. This filter has access to the DXF attributes by the `entity` object, the current render context, and the resolved properties by the `properties` object. It is recommended to modify only the `properties` object in this filter. """ if entity.dxftype() == 'HATCH': properties.color = set_color_alpha(properties.color, 200)
def draw_elliptic_arc_entity(self, entity: DXFGraphic, properties: Properties) -> None: dxftype = entity.dxftype() if dxftype == 'CIRCLE': path = Path.from_circle(cast('Circle', entity)) elif dxftype == 'ARC': path = Path.from_arc(cast('Arc', entity)) elif dxftype == 'ELLIPSE': path = Path.from_ellipse(cast('Ellipse', entity)) else: # API usage error raise TypeError(dxftype) self.out.draw_path(path, properties)
def draw_solid_entity(self, entity: DXFGraphic) -> None: # Handles SOLID, TRACE and 3DFACE dxf, dxftype = entity.dxf, entity.dxftype() properties = self._resolve_properties(entity) 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(Path.from_vertices(points, close=True), properties) else: # SOLID, TRACE self.out.draw_filled_polygon(points, properties)
def draw_entity(self, entity: DXFGraphic, properties: Properties) -> None: """Draw a single DXF entity. Args: entity: DXF entity inherited from DXFGraphic() properties: resolved entity properties """ self.out.enter_entity(entity, properties) if (entity.proxy_graphic and self.config.proxy_graphic_policy == ProxyGraphicPolicy.PREFER): self.draw_proxy_graphic(entity.proxy_graphic, entity.doc) else: draw_method = self._dispatch.get(entity.dxftype(), None) if draw_method is not None: draw_method(entity, properties) # Composite entities (INSERT, DIMENSION, ...) have to implement the # __virtual_entities__() protocol. # Unsupported DXF types which have proxy graphic, are wrapped into # DXFGraphicProxy, which also implements the __virtual_entities__() # protocol. elif isinstance(entity, SupportsVirtualEntities): assert isinstance(entity, DXFGraphic) # The __virtual_entities__() protocol does not distinguish # content from DXF entities or from proxy graphic. # In the long run ACAD_PROXY_ENTITY should be the only # supported DXF entity which uses proxy graphic. Unsupported # DXF entities (DXFGraphicProxy) do not get to this point if # proxy graphic is ignored. if (self.config.proxy_graphic_policy != ProxyGraphicPolicy.IGNORE or entity.dxftype() not in self._proxy_graphic_only_entities): self.draw_composite_entity(entity, properties) else: self.skip_entity(entity, "unsupported") self.out.exit_entity(entity)
def write(self, entity: DXFGraphic): """Write a DXF entity from the source DXF file to the export file. Don't write entities from different documents than the source DXF file, dependencies and resources will not match, maybe it will work once, but not in a reliable way for different DXF documents. """ # Not necessary to remove this dependencies by copying # them into the same document frame # --------------------------------- # remove all possible dependencies # entity.xdata = None # entity.appdata = None # entity.extension_dict = None # entity.reactors = None # reset text stream self.text.seek(0) self.text.truncate() if entity.dxf.handle is None: # DXF R12 without handles self.entity_writer.write_handles = False entity.export_dxf(self.entity_writer) if entity.dxftype() == "POLYLINE": polyline = cast(Polyline, entity) for vertex in polyline.vertices: vertex.export_dxf(self.entity_writer) polyline.seqend.export_dxf(self.entity_writer) # type: ignore elif entity.dxftype() == "INSERT": insert = cast(Insert, entity) if insert.attribs_follow: for attrib in insert.attribs: attrib.export_dxf(self.entity_writer) insert.seqend.export_dxf(self.entity_writer) # type: ignore data = self.text.getvalue().encode(self.loader.encoding) self.file.write(data)
def draw_line_entity(self, entity: DXFGraphic) -> None: d, dxftype = entity.dxf, entity.dxftype() properties = self._resolve_properties(entity) if dxftype == 'LINE': self.out.draw_line(d.start, d.end, properties) elif dxftype in ('XLINE', 'RAY'): start = d.start delta = Vector(d.unit_vector.x, d.unit_vector.y, 0) * INFINITE_LINE_LENGTH if dxftype == 'XLINE': self.out.draw_line(start - delta / 2, start + delta / 2, properties) elif dxftype == 'RAY': self.out.draw_line(start, start + delta, properties) else: raise TypeError(dxftype)
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_line_entity(self, entity: DXFGraphic, properties: Properties) -> None: d, dxftype = entity.dxf, entity.dxftype() if dxftype == "LINE": self.out.draw_line(d.start, d.end, properties) elif dxftype in ("XLINE", "RAY"): start = d.start delta = d.unit_vector * self.config.infinite_line_length if dxftype == "XLINE": self.out.draw_line(start - delta / 2, start + delta / 2, properties) elif dxftype == "RAY": self.out.draw_line(start, start + delta, properties) else: raise TypeError(dxftype)
def write(self, entity: DXFGraphic): """ Write a DXF entity from the source DXF file to the export file. Don't write entities from different documents than the source DXF file, dependencies and resources will not match, maybe it will work once, but not in a reliable way for different DXF documents. """ # remove all possible dependencies entity.xdata = None entity.appdata = None entity.extension_dict = None entity.reactors = None entity.export_dxf(self.entity_writer) if entity.dxftype() == 'POLYLINE': polyline = cast('Polyline', entity) for vertex in polyline.vertices: vertex.export_dxf(self.entity_writer) polyline.seqend.export_dxf(self.entity_writer)
def draw_polyline_entity(self, entity: DXFGraphic, properties: Properties) -> None: dxftype = entity.dxftype() if dxftype == 'POLYLINE': e = cast(Polyface, entity) if e.is_polygon_mesh or e.is_poly_face_mesh: # draw 3D mesh or poly-face entity self.draw_mesh_builder_entity( MeshBuilder.from_polyface(e), properties, ) return entity = cast(Union[LWPolyline, Polyline], entity) is_lwpolyline = dxftype == 'LWPOLYLINE' if entity.has_width: # draw banded 2D polyline elevation = 0.0 ocs = entity.ocs() transform = ocs.transform if transform: if is_lwpolyline: # stored as float elevation = entity.dxf.elevation else: # stored as vector (0, 0, elevation) elevation = Vec3(entity.dxf.elevation).z trace = TraceBuilder.from_polyline( entity, segments=self.circle_approximation_count // 2 ) for polygon in trace.polygons(): # polygon is a sequence of Vec2() if transform: points = ocs.points_to_wcs( Vec3(v.x, v.y, elevation) for v in polygon ) else: points = Vec3.generate(polygon) # Set default SOLID filling for LWPOLYLINE properties.filling = Filling() self.out.draw_filled_polygon(points, properties) return path = Path.from_lwpolyline(entity) \ if is_lwpolyline else Path.from_polyline(entity) self.out.draw_path(path, properties)
def draw_polyline_entity(self, entity: DXFGraphic): dxftype = entity.dxftype() if dxftype == 'POLYLINE': e = cast(Polyface, entity) if e.is_polygon_mesh or e.is_poly_face_mesh: self.draw_mesh_builder_entity( MeshBuilder.from_polyface(e), self._resolve_properties(entity), ) return entity = cast(Union[LWPolyline, Polyline], entity) if not entity.has_arc: properties = self._resolve_properties(entity) if dxftype == 'LWPOLYLINE': self.out.draw_line_string(Vector.generate( entity.vertices_in_wcs()), close=entity.closed, properties=properties) else: # POLYLINE if entity.is_2d_polyline: ocs = entity.ocs() elevation = Vector(entity.dxf.elevation).z vertices = ocs.points_to_wcs( Vector(p[0], p[1], elevation) for p in entity.points()) else: vertices = Vector.generate(entity.points()) self.out.draw_line_string(vertices, close=entity.is_closed, properties=properties) return self.parent_stack.append(entity) self.out.set_current_entity(entity, tuple(self.parent_stack)) # todo: end points of virtual entities are not in correct order # can't use self.out.start_path() for child in entity.virtual_entities(): # all child entities have the same properties as the parent, # no visibility check required: self.draw_entity(child) # self.out.end_path() self.parent_stack.pop() self.out.set_current_entity(None)
def draw_entity(self, entity: DXFGraphic, properties: Properties) -> None: """ Draw a single DXF entity. Args: entity: DXF Entity properties: resolved entity properties """ dxftype = entity.dxftype() self.out.enter_entity(entity, properties) if entity.proxy_graphic and self.proxy_graphics == PREFER_PROXY_GRAPHICS: self.draw_proxy_graphic(entity) elif dxftype in {'LINE', 'XLINE', 'RAY'}: self.draw_line_entity(entity, properties) elif dxftype in {'TEXT', 'MTEXT', 'ATTRIB'}: if is_spatial(Vec3(entity.dxf.extrusion)): self.draw_text_entity_3d(entity, properties) else: self.draw_text_entity_2d(entity, properties) elif dxftype in {'CIRCLE', 'ARC', 'ELLIPSE'}: self.draw_elliptic_arc_entity(entity, properties) elif dxftype == 'SPLINE': self.draw_spline_entity(entity, properties) elif dxftype == 'POINT': self.draw_point_entity(entity, properties) elif dxftype == 'HATCH': self.draw_hatch_entity(entity, properties) elif dxftype == 'MESH': self.draw_mesh_entity(entity, properties) elif dxftype in {'3DFACE', 'SOLID', 'TRACE'}: self.draw_solid_entity(entity, properties) elif dxftype in {'POLYLINE', 'LWPOLYLINE'}: self.draw_polyline_entity(entity, properties) elif dxftype in COMPOSITE_ENTITY_TYPES: self.draw_composite_entity(entity, properties) elif dxftype == 'WIPEOUT': self.draw_wipeout_entity(entity, properties) elif dxftype == 'VIEWPORT': self.draw_viewport_entity(entity) elif entity.proxy_graphic and self.proxy_graphics == USE_PROXY_GRAPHICS: self.draw_proxy_graphic(entity) else: self.skip_entity(entity, 'Unsupported entity') self.out.exit_entity(entity)