def to_ellipse(self, replace=True) -> 'Ellipse': """ Convert CIRCLE/ARC to an :class:`~ezdxf.entities.Ellipse` entity. Adds the new ELLIPSE entity to the entity database and to the same layout as the source entity. Args: replace: replace (delete) source entity by ELLIPSE entity if ``True`` .. versionadded:: 0.13 """ from ezdxf.entities import Ellipse ellipse = Ellipse.from_arc(self) if replace: replace_entity(self, ellipse) else: add_entity(self, ellipse) return ellipse
def to_ellipse(self, replace=True) -> "Ellipse": """Convert CIRCLE/ARC to an :class:`~ezdxf.entities.Ellipse` entity. Adds the new ELLIPSE entity to the entity database and to the same layout as the source entity. Args: replace: replace (delete) source entity by ELLIPSE entity if ``True`` """ from ezdxf.entities import Ellipse layout = self.get_layout() if layout is None: raise DXFValueError("valid layout required") ellipse = Ellipse.from_arc(self) if replace: replace_entity(self, ellipse, layout) else: add_entity(ellipse, layout) return ellipse
def virtual_block_reference_entities( block_ref: 'Insert') -> Iterable['DXFGraphic']: """ Yields 'virtual' parts of block reference `block_ref`. This method is meant to examine the the block reference entities without the need to explode the block reference. This entities are located at the 'exploded' positions, but are not stored in the entity database, have no handle and are not assigned to any layout. Args: block_ref: Block reference entity (INSERT) .. warning:: **Non uniform scaling** returns incorrect results for text entities (TEXT, MTEXT, ATTRIB) and some other entities like ELLIPSE, SHAPE, HATCH with arc or ellipse path segments and POLYLINE/LWPOLYLINE with arc segments. (internal API) """ assert block_ref.dxftype() == 'INSERT' brcs = block_ref.brcs() # Non uniform scaling will produce incorrect results for some entities! xscale = block_ref.dxf.xscale yscale = block_ref.dxf.yscale uniform_scaling = max(abs(xscale), abs(yscale)) non_uniform_scaling = xscale != yscale block_layout = block_ref.block() if block_layout is None: raise DXFStructureError( f'Required block definition for "{block_ref.dxf.name}" does not exist.' ) for entity in block_layout: dxftype = entity.dxftype() if dxftype == 'ATTDEF': # do not explode ATTDEF entities continue # Copy entity with all DXF attributes try: copy = entity.copy() except DXFTypeError: continue # non copyable entities will be ignored if non_uniform_scaling and dxftype in {'ARC', 'CIRCLE'}: from ezdxf.entities import Ellipse copy = Ellipse.from_arc(entity) dxftype = copy.dxftype() # Basic transformation from BRCS to WCS try: copy.transform_to_wcs(brcs) except NotImplementedError: # entities without 'transform_to_ucs' support will be ignored continue # Apply DXF attribute scaling: # 1. simple entities without properties to scale if dxftype in { 'LINE', 'POINT', 'LWPOLYLINE', 'POLYLINE', 'MESH', 'HATCH', 'SPLINE', 'SOLID', '3DFACE', 'TRACE', 'IMAGE', 'WIPEOUT', 'XLINE', 'RAY', 'LIGHT', 'HELIX' }: pass # nothing else to do elif dxftype in {'CIRCLE', 'ARC'}: # simple uniform scaling of radius # Non uniform scaling: ARC, CIRCLE -> ELLIPSE copy.dxf.radius = entity.dxf.radius * uniform_scaling elif dxftype == 'ELLIPSE': if non_uniform_scaling: if entity.dxftype( ) == 'ELLIPSE': # original entity is an ELLIPSE ellipse = cast('Ellipse', entity) # transform axis conjugated_major_axis = brcs.direction_to_wcs( ellipse.dxf.major_axis) conjugated_minor_axis = brcs.direction_to_wcs( ellipse.minor_axis) major_axis, _, ratio = rytz_axis_construction( conjugated_major_axis, conjugated_minor_axis) copy.dxf.major_axis = major_axis copy.dxf.ratio = max(ratio, 1e-6) # adjusting start- and end parameter center = copy.dxf.center # transformed center point start_point, end_point = ellipse.vertices( (ellipse.dxf.start_param, ellipse.dxd.end_param)) start_vec = brcs.to_wcs(start_point) - center end_vec = brcs.to_wcs(end_point) - center # The dot product (scalar product) is the angle between two vectors. # https://en.wikipedia.org/wiki/Dot_product # Not sure if this is the correct way to adjust start- and end parameter copy.dxf.start_param = normalize_angle( major_axis.dot(start_vec)) copy.dxf.end_param = normalize_angle( major_axis.dot(end_vec)) if copy.dxf.ratio > 1: copy.swap_axis() else: # converted from ARC to ELLIPSE ellipse = cast('Ellipse', copy) ellipse.dxf.ratio = max(yscale / xscale, 1e-6) if ellipse.dxf.ratio > 1: ellipse.swap_axis() elif dxftype == 'MTEXT': # Scale MTEXT height/width just by uniform_scaling, how to handle non uniform scaling? copy.dxf.char_height *= uniform_scaling copy.dxf.width *= uniform_scaling elif dxftype in {'TEXT', 'ATTRIB'}: # Scale TEXT height just by uniform_scaling, how to handle non uniform scaling? copy.dxf.height *= uniform_scaling elif dxftype == 'INSERT': # Set scaling of child INSERT to scaling of parent INSERT for scale in ('xscale', 'yscale', 'zscale'): if block_ref.dxf.hasattr(scale): original_scale = copy.dxf.get_default(scale) block_ref_scale = block_ref.dxf.get(scale) copy.dxf.set(scale, original_scale * block_ref_scale) if uniform_scaling != 1: # Scale attached ATTRIB entities: # Scale height just by uniform_scaling, how to handle non uniform scaling? for attrib in copy.attribs: attrib.dxf.height *= uniform_scaling elif dxftype == 'SHAPE': # Scale SHAPE size just by uniform_scaling, how to handle non uniform scaling? copy.dxf.size *= uniform_scaling else: # unsupported entity will be ignored continue yield copy