Exemple #1
0
    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
Exemple #2
0
    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
Exemple #3
0
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