def test_flattening_by_ellipse(lwpolyline1: LWPolyline):
    entities = list(lwpolyline1.virtual_entities())
    for e in entities:
        if e.dxftype() == "ARC":
            ellipse = Ellipse.from_arc(e)
            points = list(ellipse.flattening(MAX_SAGITTA))
            assert len(points) > 0
Exemple #2
0
 def transform(entities):
     for entity in entities:
         try:
             entity.transform(m)
         except NotImplementedError:
             skipped_entity_callback(entity, "non transformable")
         except NonUniformScalingError:
             dxftype = entity.dxftype()
             if dxftype in {"ARC", "CIRCLE"}:
                 if abs(entity.dxf.radius) > ABS_TOL:
                     yield Ellipse.from_arc(entity).transform(m)
                 else:
                     skipped_entity_callback(
                         entity, f"Invalid radius in entity {str(entity)}.")
             elif dxftype in {"LWPOLYLINE", "POLYLINE"}:  # has arcs
                 yield from transform(entity.virtual_entities())
             else:
                 skipped_entity_callback(entity,
                                         "unsupported non-uniform scaling")
         except InsertTransformationError:
             # INSERT entity can not represented in the target coordinate
             # system defined by transformation matrix `m`.
             # Yield transformed sub-entities of the INSERT entity:
             yield from transform(
                 virtual_block_reference_entities(entity,
                                                  skipped_entity_callback))
         else:
             yield entity
Exemple #3
0
def _from_ellipse(ellipse: Ellipse, **kwargs) -> 'Path':
    segments = kwargs.get('segments', 1)
    path = Path()
    tools.add_ellipse(path,
                      ellipse.construction_tool(),
                      segments=segments,
                      reset=True)
    return path
Exemple #4
0
def build(angle, dx, dy, dz, axis, start, end, count):
    ellipse = Ellipse.new(dxfattribs={
        'start_param': start,
        'end_param': end,
    })
    vertices = list(ellipse.vertices(ellipse.params(count)))
    m = Matrix44.chain(Matrix44.axis_rotate(axis=axis, angle=angle),
                       Matrix44.translate(dx=dx, dy=dy, dz=dz))
    return synced_transformation(ellipse, vertices, m)
Exemple #5
0
def test_from_ellipse():
    from ezdxf.entities import Ellipse
    from ezdxf.math import ConstructionEllipse
    e = ConstructionEllipse(center=(3, 0), major_axis=(1, 0), ratio=0.5,
                            start_param=0, end_param=math.pi)
    ellipse = Ellipse.new()
    ellipse.apply_construction_tool(e)
    path = Path.from_ellipse(ellipse)
    assert path.start == (4, 0)
    assert path.end == (2, 0)
Exemple #6
0
def _virtual_edge_path(path: EdgePath, dxfattribs: Dict, ocs: OCS,
                       elevation: float) -> List["DXFGraphic"]:
    from ezdxf.entities import Line, Arc, Ellipse, Spline

    def pnt_to_wcs(v):
        return ocs.to_wcs(Vec3(v).replace(z=elevation))

    def dir_to_wcs(v):
        return ocs.to_wcs(v)

    edges: List["DXFGraphic"] = []
    for edge in path.edges:
        attribs = dict(dxfattribs)
        if isinstance(edge, LineEdge):
            attribs["start"] = pnt_to_wcs(edge.start)
            attribs["end"] = pnt_to_wcs(edge.end)
            edges.append(Line.new(dxfattribs=attribs))
        elif isinstance(edge, ArcEdge):
            attribs["center"] = edge.center
            attribs["radius"] = edge.radius
            attribs["elevation"] = elevation
            # Arcs angles are always stored in counter clockwise orientation
            # around the extrusion vector!
            attribs["start_angle"] = edge.start_angle
            attribs["end_angle"] = edge.end_angle
            attribs["extrusion"] = ocs.uz
            edges.append(Arc.new(dxfattribs=attribs))
        elif isinstance(edge, EllipseEdge):
            attribs["center"] = pnt_to_wcs(edge.center)
            attribs["major_axis"] = dir_to_wcs(edge.major_axis)
            attribs["ratio"] = edge.ratio
            # Ellipse angles are always stored in counter clockwise orientation
            # around the extrusion vector!
            attribs["start_param"] = edge.start_param
            attribs["end_param"] = edge.end_param
            attribs["extrusion"] = ocs.uz
            edges.append(Ellipse.new(dxfattribs=attribs))
        elif isinstance(edge, SplineEdge):
            spline = Spline.new(dxfattribs=attribs)
            spline.dxf.degree = edge.degree
            spline.knots = edge.knot_values
            spline.control_points = [
                pnt_to_wcs(v) for v in edge.control_points
            ]
            if edge.weights:
                spline.weights = edge.weights
            if edge.fit_points:
                spline.fit_points = [pnt_to_wcs(v) for v in edge.fit_points]
            if edge.start_tangent is not None:
                spline.dxf.start_tangent = dir_to_wcs(edge.start_tangent)
            if edge.end_tangent is not None:
                spline.dxf.end_tangent = dir_to_wcs(edge.end_tangent)
            edges.append(spline)
    return edges
Exemple #7
0
 def build():
     ellipse = Ellipse.new(dxfattribs={
         'start_param': start,
         'end_param': end,
     })
     vertices = list(ellipse.vertices(ellipse.params(vertex_count)))
     m = Matrix44.chain(
         Matrix44.axis_rotate(axis=Vec3.random(), angle=random.uniform(0, math.tau)),
         Matrix44.translate(dx=random.uniform(-2, 2), dy=random.uniform(-2, 2), dz=random.uniform(-2, 2)),
     )
     return synced_transformation(ellipse, vertices, m)
def ellipse1():
    return Ellipse.new(dxfattribs={
        "center": (
            298998.9237372455,
            105908.98587737791,
            0.0218015606544459,
        ),
        "major_axis": (-2.005925505480262, 9.590684825374422e-13, 0.0),
        "ratio":
        0.6052078628034204,
        "start_param":
        7.898e-13,
        "end_param":
        7.878142582740111e-13,
        "extrusion": (0.0, -0.0, 1.0),
    }, )
Exemple #9
0
def test_from_ellipse():
    from ezdxf.entities import Ellipse
    spline = Spline.from_arc(Ellipse.new(dxfattribs={
        'center': (1, 1),
        'major_axis': (2, 0),
        'ratio': 0.5,
        'start_param': 0.5,  # radians
        'end_param': 3,
        'layer': 'ellipse',
    }))
    assert spline.dxf.layer == 'ellipse'
    assert spline.dxf.degree == 2
    assert len(spline.control_points) > 2
    assert len(spline.weights) > 2
    assert len(spline.fit_points) == 0
    assert len(spline.knots) == required_knot_values(len(spline.control_points), spline.dxf.degree + 1)
def ellipse(major_axis=(1, 0),
            ratio: float = 0.5,
            start: float = 0,
            end: float = math.tau,
            count: int = 8):
    major_axis = Vector(major_axis).replace(z=0)
    ellipse_ = Ellipse.new(dxfattribs={
        'center': (0, 0, 0),
        'major_axis': major_axis,
        'ratio': min(max(ratio, 1e-6), 1),
        'start_param': start,
        'end_param': end
    },
                           doc=doc)
    control_vertices = list(ellipse_.vertices(ellipse_.params(count)))
    axis_vertices = list(
        ellipse_.vertices([0, math.pi / 2, math.pi, math.pi * 1.5]))
    return ellipse_, control_vertices, axis_vertices
Exemple #11
0
def test_upright_ellipse():
    ellipse = Ellipse.new(
        dxfattribs={
            "center": (5, 5, 5),
            "major_axis": (5, 0, 0),
            "ratio": 0.5,
            "start_param": 0.5,
            "end_param": 1.5,
            "extrusion": (0, 0, -1),
        })
    p0 = path.make_path(ellipse)
    assert p0.has_curves is True

    upright(ellipse)
    assert ellipse.dxf.extrusion.isclose(Z_AXIS)
    p1 = path.make_path(ellipse)
    # has reversed vertex order of source entity:
    assert path.have_close_control_vertices(p0, p1.reversed())
Exemple #12
0
def test_from_ellipse():
    from ezdxf.entities import Ellipse

    spline = Spline.from_arc(
        Ellipse.new(
            dxfattribs={
                "center": (1, 1),
                "major_axis": (2, 0),
                "ratio": 0.5,
                "start_param": 0.5,  # radians
                "end_param": 3,
                "layer": "ellipse",
            }))
    assert spline.dxf.layer == "ellipse"
    assert spline.dxf.degree == 2
    assert len(spline.control_points) > 2
    assert len(spline.weights) > 2
    assert len(spline.fit_points) == 0
    assert len(spline.knots) == required_knot_values(
        len(spline.control_points), spline.dxf.degree + 1)
def ellipse(
    major_axis=(1, 0),
    ratio: float = 0.5,
    start: float = 0,
    end: float = math.tau,
    count: int = 8,
):
    major_axis = Vec3(major_axis).replace(z=0)
    ellipse_ = Ellipse.new(
        dxfattribs={
            "center": (0, 0, 0),
            "major_axis": major_axis,
            "ratio": min(max(ratio, 1e-6), 1),
            "start_param": start,
            "end_param": end,
        },
        doc=doc,
    )
    control_vertices = list(ellipse_.vertices(ellipse_.params(count)))
    axis_vertices = list(
        ellipse_.vertices([0, math.pi / 2, math.pi, math.pi * 1.5]))
    return ellipse_, control_vertices, axis_vertices
def test_flattening_ellipse(ellipse1: Ellipse):
    points = list(ellipse1.flattening(MAX_SAGITTA))
    assert len(points) > 0
Exemple #15
0
def virtual_entities(block_ref: 'Insert') -> Iterable['DXFGraphic']:
    """
    Yields 'virtual' entities 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
    are not assigned to any layout. It is possible to convert this entities into regular drawing entities, this lines
    show how to add the virtual `entity` to the entity database and assign this entity to the modelspace::

        doc.entitydb.add(entity)
        msp = doc.modelspace()
        msp.add_entity(entity)

    To explode the whole block reference use :meth:`~ezdxf.entities.Insert.explode`.

    Args:
        block_ref: Block reference entity (:class:`~ezdxf.entities.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.

    """
    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
            # How to handle non uniform scaling? -> Ellipse
            copy.dxf.radius = entity.dxf.radius * uniform_scaling
        elif dxftype == 'ELLIPSE':
            if non_uniform_scaling:
                # ELLIPSE -> ELLIPSE
                if entity.dxftype() == 'ELLIPSE':
                    ellipse = cast('Ellipse', entity)
                    major_axis = Vector(ellipse.dxf.major_axis)
                    minor_axis = ellipse.minor_axis
                    major_axis_length = brcs.direction_to_wcs(
                        major_axis).magnitude
                    minor_axis_length = brcs.direction_to_wcs(
                        minor_axis).magnitude
                    copy.dxf.ratio = max(minor_axis_length / major_axis_length,
                                         1e-6)
                else:  # ARC -> ELLIPSE
                    scale = max(min((yscale / xscale), 1.0), 1e-6)
                    copy.dxf.ratio = scale
        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