Exemplo n.º 1
0
    def transform(self, m: Matrix44) -> 'MText':
        """ Transform MTEXT entity by transformation matrix `m` inplace.

        .. versionadded:: 0.13

        """
        dxf = self.dxf
        old_extrusion = Vec3(dxf.extrusion)
        new_extrusion, _ = transform_extrusion(old_extrusion, m)

        if dxf.hasattr('rotation') and not dxf.hasattr('text_direction'):
            # MTEXT is not an OCS entity, but I don't know how else to convert
            # a rotation angle for an entity just defined by an extrusion vector.
            # It's correct for the most common case: extrusion=(0, 0, 1)
            ocs = OCS(old_extrusion)
            dxf.text_direction = ocs.to_wcs(Vec3.from_deg_angle(dxf.rotation))

        dxf.discard('rotation')

        old_text_direction = Vec3(dxf.text_direction)
        new_text_direction = m.transform_direction(old_text_direction)

        old_char_height_vec = old_extrusion.cross(
            old_text_direction).normalize(dxf.char_height)
        new_char_height_vec = m.transform_direction(old_char_height_vec)
        oblique = new_text_direction.angle_between(new_char_height_vec)
        dxf.char_height = new_char_height_vec.magnitude * math.sin(oblique)

        if dxf.hasattr('width'):
            width_vec = old_text_direction.normalize(dxf.width)
            dxf.width = m.transform_direction(width_vec).magnitude

        dxf.insert = m.transform(dxf.insert)
        dxf.text_direction = new_text_direction
        dxf.extrusion = new_extrusion
        return self
Exemplo n.º 2
0
 def text2(self, data: bytes):
     bs = ByteStream(data)
     start_point = Vec3(bs.read_vertex())
     normal = Vec3(bs.read_vertex())
     text_direction = Vec3(bs.read_vertex())
     text = bs.read_padded_string()
     ignore_length_of_string, raw = bs.read_struct('<2l')
     height, width_factor, oblique_angle, tracking_percentage = bs.read_struct(
         '<4d')
     is_backwards, is_upside_down, is_vertical, is_underline, is_overline = bs.read_struct(
         '<5L')
     font_filename = bs.read_padded_string()
     big_font_filename = bs.read_padded_string()
     attribs = self._build_dxf_attribs()
     attribs['insert'] = start_point
     attribs['text'] = text
     attribs['height'] = height
     attribs['width'] = width_factor
     attribs['rotation'] = text_direction.angle_deg
     attribs['oblique'] = math.degrees(oblique_angle)
     attribs['style'] = self._get_style(font_filename, big_font_filename)
     attribs['text_generation_flag'] = 2 * is_backwards + 4 * is_upside_down
     attribs['extrusion'] = normal
     return self._factory('TEXT', dxfattribs=attribs)
Exemplo n.º 3
0
def test_spatial_arc_from_3p():
    start_point_wcs = Vec3(0, 1, 0)
    end_point_wcs = Vec3(1, 0, 0)
    def_point_wcs = Vec3(0, 0, 1)

    ucs = UCS.from_x_axis_and_point_in_xy(origin=def_point_wcs,
                                          axis=end_point_wcs - def_point_wcs,
                                          point=start_point_wcs)
    start_point_ucs = ucs.from_wcs(start_point_wcs)
    end_point_ucs = ucs.from_wcs(end_point_wcs)
    def_point_ucs = Vec3(0, 0)

    arc = ConstructionArc.from_3p(start_point_ucs, end_point_ucs,
                                  def_point_ucs)
    dwg = ezdxf.new('R12')
    msp = dwg.modelspace()

    dxf_arc = arc.add_to_layout(msp, ucs)
    assert dxf_arc.dxftype() == 'ARC'
    assert isclose(dxf_arc.dxf.radius, 0.81649658, abs_tol=1e-9)
    assert isclose(dxf_arc.dxf.start_angle, 330)
    assert isclose(dxf_arc.dxf.end_angle, 210)
    assert dxf_arc.dxf.extrusion.isclose((0.57735027, 0.57735027, 0.57735027),
                                         abs_tol=1e-9)
Exemplo n.º 4
0
def translate(
    vertices: Iterable["Vertex"], vec: "Vertex" = (0, 0, 0)
) -> Iterable[Vec3]:
    """Translate `vertices` along `vec`, faster than a Matrix44 transformation.

    Args:
        vertices: iterable of vertices
        vec: translation vector

    Returns: yields transformed vertices

    """
    _vec = Vec3(vec)
    for p in vertices:
        yield _vec + p
Exemplo n.º 5
0
 def build():
     arc = Arc.new(
         dxfattribs={
             'start_angle': random.uniform(0, 360),
             'end_angle': random.uniform(0, 360),
         })
     vertices = list(arc.vertices(arc.angles(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(arc, vertices, m)
Exemplo n.º 6
0
 def __init__(
     self,
     center: "Vertex" = NULLVEC,
     major_axis: "Vertex" = X_AXIS,
     extrusion: "Vertex" = Z_AXIS,
     ratio: float = 1,
     start_param: float = 0,
     end_param: float = math.tau,
     ccw: bool = True,
 ):
     self.center = Vec3(center)
     self.major_axis = Vec3(major_axis)
     if self.major_axis.isclose(NULLVEC):
         raise ValueError(f"Invalid major axis (null vector).")
     self.extrusion = Vec3(extrusion)
     if self.major_axis.isclose(NULLVEC):
         raise ValueError(f"Invalid extrusion vector (null vector).")
     self.ratio = float(ratio)
     self.start_param = float(start_param)
     self.end_param = float(end_param)
     if not ccw:
         self.start_param, self.end_param = self.end_param, self.start_param
     self.minor_axis = minor_axis(self.major_axis, self.extrusion,
                                  self.ratio)
Exemplo n.º 7
0
    def set_location(self,
                     insert: 'Vertex',
                     rotation: float = None,
                     attachment_point: int = None) -> 'MText':
        """ Set attributes :attr:`dxf.insert`, :attr:`dxf.rotation` and
        :attr:`dxf.attachment_point`, ``None`` for :attr:`dxf.rotation` or
        :attr:`dxf.attachment_point` preserves the existing value.

        """
        self.dxf.insert = Vec3(insert)
        if rotation is not None:
            self.set_rotation(rotation)
        if attachment_point is not None:
            self.dxf.attachment_point = attachment_point
        return self  # fluent interface
Exemplo n.º 8
0
    def move_to(self, location: Vertex) -> None:
        """Start a new sub-path at `location`. This creates a gap between the
        current end-point and the start-point of the new sub-path. This converts
        the instance into a :term:`Multi-Path` object.

        If the :meth:`move_to` command is the first command, the start point of
        the path will be reset to `location`.

        .. versionadded:: 0.17

        """
        commands = self._commands
        if not commands:
            self._vertices[0] = Vec3(location)
            return
        self._has_sub_paths = True
        if commands[-1] == Command.MOVE_TO:
            # replace last move to command
            commands.pop()
            self._vertices.pop()
            self._start_index.pop()
        commands.append(Command.MOVE_TO)
        self._start_index.append(len(self._vertices))
        self._vertices.append(Vec3(location))
Exemplo n.º 9
0
def test_edge_path_transform_interface(hatch, m44):
    path = hatch.paths.add_edge_path()
    path.add_line((0, 0), (10, 0))
    path.add_arc((10, 5), radius=5, start_angle=270, end_angle=450, ccw=1)
    path.add_ellipse((5, 10),
                     major_axis=(5, 0),
                     ratio=0.2,
                     start_angle=0,
                     end_angle=180)
    spline = path.add_spline([(1, 1), (2, 2), (3, 3), (4, 4)],
                             degree=3,
                             periodic=1)
    # the following values do not represent a mathematically valid spline
    spline.control_points = [(1, 1), (2, 2), (3, 3), (4, 4)]
    spline.knot_values = [1, 2, 3, 4, 5, 6]
    spline.weights = [4, 3, 2, 1]
    spline.start_tangent = (10, 1)
    spline.end_tangent = (2, 20)

    chk = list(
        m44.transform_vertices([
            Vec3(0, 0),
            Vec3(10, 0),
            Vec3(10, 5),
            Vec3(5, 10),
            Vec3(1, 1),
            Vec3(2, 2),
            Vec3(3, 3),
            Vec3(4, 4),
        ]))

    hatch.transform(m44)
    line = path.edges[0]
    assert chk[0].isclose(line.start)
    assert chk[1].isclose(line.end)
    arc = path.edges[1]
    assert chk[2].isclose(arc.center)
    ellipse = path.edges[2]
    assert chk[3].isclose(ellipse.center)
    spline = path.edges[3]
    for c, v in zip(chk[4:], spline.control_points):
        assert c.isclose(v)
    for c, v in zip(chk[4:], spline.fit_points):
        assert c.isclose(v)
    assert m44.transform_direction((10, 1, 0)).isclose(spline.start_tangent)
    assert m44.transform_direction((2, 20, 0)).isclose(spline.end_tangent)
Exemplo n.º 10
0
def test_transformation():
    axis = Vec3.random()
    angle = 1.5
    ucs = UCS(origin=(3, 4, 5))
    m = Matrix44.axis_rotate(axis, angle)
    expected_origin = m.transform(ucs.origin)
    expected_ux = m.transform(ucs.ux)
    expected_uy = m.transform(ucs.uy)
    expected_uz = m.transform(ucs.uz)
    new = ucs.transform(m)

    assert new.origin.isclose(expected_origin)
    assert new.ux.isclose(expected_ux)
    assert new.uy.isclose(expected_uy)
    assert new.uz.isclose(expected_uz)
Exemplo n.º 11
0
    def translate(self, dx: float, dy: float, dz: float) -> 'Text':
        """ Optimized TEXT/ATTRIB/ATTDEF translation about `dx` in x-axis, `dy`
        in y-axis and `dz` in z-axis, returns `self` (floating interface).

        .. versionadded:: 0.13

        """
        ocs = self.ocs()
        dxf = self.dxf
        vec = Vec3(dx, dy, dz)

        dxf.insert = ocs.from_wcs(vec + ocs.to_wcs(dxf.insert))
        if dxf.hasattr('align_point'):
            dxf.align_point = ocs.from_wcs(vec + ocs.to_wcs(dxf.align_point))
        return self
Exemplo n.º 12
0
def test_random_block_reference_transformation(sx, sy, sz, doc1: "Drawing"):
    def insert():
        return (
            Insert.new(
                dxfattribs={
                    "name": "AXIS",
                    "insert": (0, 0, 0),
                    "xscale": 1,
                    "yscale": 1,
                    "zscale": 1,
                    "rotation": 0,
                    "layer": "insert",
                },
                doc=doc1,
            ),
            [Vec3(0, 0, 0), X_AXIS, Y_AXIS, Z_AXIS],
        )

    def check(lines, chk):
        origin, x, y, z = chk
        l1, l2, l3 = lines
        assert origin.isclose(l1.dxf.start)
        assert x.isclose(l1.dxf.end)
        assert origin.isclose(l2.dxf.start)
        assert y.isclose(l2.dxf.end)
        assert origin.isclose(l3.dxf.start)
        assert z.isclose(l3.dxf.end)

    entity0, vertices0 = insert()
    entity0, vertices0 = synced_scaling(entity0, vertices0, 1, 2, 3)

    m = Matrix44.chain(
        # Transformation order is important: scale - rotate - translate
        # Because scaling after rotation leads to a non orthogonal
        # coordinate system, which can not represented by the
        # INSERT entity.
        Matrix44.scale(sx, sy, sz),
        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),
        ),
    )
    entity, vertices = synced_transformation(entity0, vertices0, m)
    lines = list(entity.virtual_entities())
    check(lines, vertices)
Exemplo n.º 13
0
def to_lwpolylines(paths: Iterable[Path],
                   *,
                   distance: float = MAX_DISTANCE,
                   segments: int = MIN_SEGMENTS,
                   extrusion: 'Vertex' = Z_AXIS,
                   dxfattribs: Optional[Dict] = None) -> Iterable[LWPolyline]:
    """ Convert the given `paths` into :class:`~ezdxf.entities.LWPolyline`
    entities.
    The `extrusion` vector is applied to all paths, all vertices are projected
    onto the plane normal to this extrusion vector. The default extrusion vector
    is the WCS z-axis. The plane elevation is the distance from the WCS origin
    to the start point of the first path.

    Args:
        paths: iterable of :class:`Path` objects
        distance:  maximum distance, see :meth:`Path.flattening`
        segments: minimum segment count per Bézier curve
        extrusion: extrusion vector for all paths
        dxfattribs: additional DXF attribs

    Returns:
        iterable of :class:`~ezdxf.entities.LWPolyline` objects

    .. versionadded:: 0.16

    """
    if isinstance(paths, Path):
        paths = [paths]
    else:
        paths = list(paths)
    if len(paths) == 0:
        return []

    extrusion = Vec3(extrusion)
    reference_point = paths[0].start
    dxfattribs = dxfattribs or dict()
    if not extrusion.isclose(Z_AXIS):
        ocs, elevation = _get_ocs(extrusion, reference_point)
        paths = tools.transform_paths_to_ocs(paths, ocs)
        dxfattribs['elevation'] = elevation
        dxfattribs['extrusion'] = extrusion
    elif reference_point.z != 0:
        dxfattribs['elevation'] = reference_point.z

    for path in paths:
        p = LWPolyline.new(dxfattribs=dxfattribs)
        p.append_points(path.flattening(distance, segments), format='xy')
        yield p
Exemplo n.º 14
0
def ngon(
    count: int,
    length: float = None,
    radius: float = None,
    rotation: float = 0.0,
    elevation: float = 0.0,
    close: bool = False,
) -> Iterable[Vec3]:
    """Returns the corner vertices of a `regular polygon <https://en.wikipedia.org/wiki/Regular_polygon>`_.
    The polygon size is determined by the edge `length` or the circum `radius`
    argument. If both are given `length` has the higher priority.

    Args:
        count: count of polygon corners >= 3
        length: length of polygon side
        radius: circum radius
        rotation: rotation angle in radians
        elevation: z-axis for all vertices
        close: yields first vertex also as last vertex if ``True``.

    Returns:
        vertices as :class:`~ezdxf.math.Vec3` objects

    """
    if count < 3:
        raise ValueError("Argument `count` has to be greater than 2.")
    if length is not None:
        if length <= 0.0:
            raise ValueError("Argument `length` has to be greater than 0.")
        radius = length / 2.0 / sin(pi / count)
    elif radius is not None:
        if radius <= 0.0:
            raise ValueError("Argument `radius` has to be greater than 0.")
    else:
        raise ValueError("Argument `length` or `radius` required.")

    delta = 2.0 * pi / count
    angle = rotation
    first = None
    for _ in range(count):
        v = Vec3(radius * cos(angle), radius * sin(angle), elevation)
        if first is None:
            first = v
        yield v
        angle += delta

    if close:
        yield first
Exemplo n.º 15
0
def subdivide_ngons(
        faces: Iterable[Sequence[Union[Vec3, Vec2]]]) -> Iterable[List[Vec3]]:
    """ Yields only triangles or quad faces, subdivides ngons into triangles.

    Args:
        faces: iterable of faces as sequence of :class:`Vec2` and
            :class:`Vec3` objects

    """
    for face in faces:
        if len(face) < 5:
            yield face
        else:
            mid_pos = Vec3.sum(face) / len(face)
            for index, vertex in enumerate(face):
                yield face[index - 1], vertex, mid_pos
Exemplo n.º 16
0
 def _setup(self) -> None:
     """
     Calc setup values and determines the point order of the dimension line points.
     """
     self.measure_points = [Vec3(point) for point in self.measure_points
                            ]  # type: List[Vec3]
     dimlineray = ConstructionRay(self.dimlinepos,
                                  angle=radians(
                                      self.angle))  # Type: ConstructionRay
     self.dimline_points = [
         self._get_point_on_dimline(point, dimlineray)
         for point in self.measure_points
     ]  # type: List[Vec3]
     self.point_order = self._indices_of_sorted_points(
         self.dimline_points)  # type: List[int]
     self._build_vectors()
Exemplo n.º 17
0
def scene2(filename):
    doc = ezdxf.new('R2010', setup=True)
    msp = doc.modelspace()
    delta = 6
    for z in range(-2, 3):
        for y in range(-2, 3):
            for x in range(-2, 3):
                cx = x * delta
                cy = y * delta
                cz = z * delta
                ucs = UCS(origin=(cx, cy, cz)).rotate_local_z(math.radians(45)).rotate_local_x(
                    math.radians(30))
                add_excentric_text(msp, ucs, location=Vec3(1, 2, 3), text=f'Hallo\n(x={cx}, y={cy}, z={cz})')

    doc.set_modelspace_vport(5 * delta)
    doc.saveas(filename)
Exemplo n.º 18
0
 def insert():
     return (
         Insert.new(
             dxfattribs={
                 "name": "AXIS",
                 "insert": (0, 0, 0),
                 "xscale": 1,
                 "yscale": 1,
                 "zscale": 1,
                 "rotation": 0,
                 "layer": "insert",
             },
             doc=doc1,
         ),
         [Vec3(0, 0, 0), X_AXIS, Y_AXIS, Z_AXIS],
     )
Exemplo n.º 19
0
    def __init__(
        self,
        control_points: Iterable["Vertex"],
        degree: int = 2,
        closed: bool = True,
    ):
        """
        Args:
            control_points: B-spline control frame vertices
            degree: degree of B-spline, only 2 and 3 is supported
            closed: ``True`` for closed curve

        """
        self.control_points = Vec3.list(control_points)
        self.degree = degree
        self.closed = closed
Exemplo n.º 20
0
def test_if_nurbs_python_is_reliable():
    # Testing for some known values, just for the case
    # that NURBS-Python is incorrect.
    expected = [
        (0.0, 0.0, 0.0),
        (11.840000000000003, 13.760000000000002, 16.64),
        (22.72, 14.079999999999998, 22.719999999999995),
        (31.759999999999994, 11.2, 24.399999999999995),
        (39.92, 7.999999999999999, 26.0),
        (50.0, 0.0, 30.0)
    ]
    params = [0, .2, .4, .6, .8, 1.0]
    curve = BSpline(DEFPOINTS).to_nurbs_python_curve()
    points = curve.evaluate_list(params)
    for expect, point in zip(expected, points):
        assert Vec3(expect).isclose(point)
Exemplo n.º 21
0
    def point(self, t: float) -> Vec3:
        """
        Get point at distance `t` as :class.`Vec3`.

        """
        def term(length_power, curvature_power, const):
            return t**length_power / (const *
                                      self.curvature_powers[curvature_power])

        if t not in self._cache:
            y = term(3, 2, 6.) - term(7, 6, 336.) + term(11, 10, 42240.) - \
                term(15, 14, 9676800.) + term(19, 18, 3530096640.)
            x = t - term(5, 4, 40.) + term(9, 8, 3456.) - term(13, 12, 599040.) + \
                term(17, 16, 175472640.)
            self._cache[t] = Vec3(x, y)
        return self._cache[t]
Exemplo n.º 22
0
    def ucs_direction_from_wcs(self, wcs: Vec3) -> Vec3:
        """
        Returns UCS direction vector from WCS direction.

        Works only if matrix is used as cartesian UCS without scaling.

        (internal API)

        """
        m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, *_ = self.matrix
        x, y, z = wcs
        return Vec3(
            x * m0 + y * m1 + z * m2,
            x * m4 + y * m5 + z * m6,
            x * m8 + y * m9 + z * m10,
        )
Exemplo n.º 23
0
def spline_insert_knot():
    doc = ezdxf.new('R2000', setup=True)
    msp = doc.modelspace()

    def add_spline(control_points, color=3, knots=None):
        msp.add_polyline2d(control_points, dxfattribs={'color': color, 'linetype': 'DASHED'})
        msp.add_open_spline(control_points, degree=3, knots=knots, dxfattribs={'color': color})

    control_points = Vec3.list([(0, 0), (10, 20), (30, 10), (40, 10), (50, 0), (60, 20), (70, 50), (80, 70)])
    add_spline(control_points, color=3, knots=None)

    bspline = BSpline(control_points, order=4)
    bspline.insert_knot(bspline.max_t/2)
    add_spline(bspline.control_points, color=4, knots=bspline.knots())

    doc.saveas("Spline_R2000_spline_insert_knot.dxf")
Exemplo n.º 24
0
def test_random_ellipse_transformations(sx, sy, sz, start, end):
    vertex_count = 8

    for angle in linspace(0, math.tau, 19):
        for dx, dy, dz in product([2, 0, -2], repeat=3):
            axis = Vec3.random()  # TODO: fixed rotation axis

            config = f"CONFIG sx={sx}, sy={sy}, sz={sz}; " \
                     f"start={start:.4f}, end={end:.4f}; angle={angle};" \
                     f"dx={dx}, dy={dy}, dz={dz}; axis={str(axis)}"
            ellipse0, vertices0 = build(angle, dx, dy, dz, axis, start, end,
                                        vertex_count)
            assert check(ellipse0, vertices0, vertex_count) is True, config
            ellipse1, vertices1 = synced_scaling(ellipse0, vertices0, sx, sy,
                                                 sz)
            assert check(ellipse1, vertices1, vertex_count) is True, config
Exemplo n.º 25
0
def radius_3d(dxfversion='R2000', delta=10):
    doc = ezdxf.new(dxfversion, setup=True)
    msp = doc.modelspace()

    for x, y in multiple_locations(delta=delta):
        ucs = UCS(origin=(x, y, 0)).rotate_local_x(math.radians(45))
        angle = Vec3(x, y).angle_deg
        msp.add_circle((0, 0), radius=3).transform(ucs.matrix)
        dim = msp.add_radius_dim(center=(0, 0),
                                 radius=3,
                                 angle=angle,
                                 dimstyle='EZ_RADIUS')
        dim.render(discard=BRICSCAD, ucs=ucs)

    doc.set_modelspace_vport(height=3 * delta)
    doc.saveas(OUTDIR / f'dim_radius_{dxfversion}_3d.dxf')
Exemplo n.º 26
0
 def bulge_to(p1: Vec3, p2: Vec3, bulge: float):
     if p1.isclose(p2):
         return
     center, start_angle, end_angle, radius = bulge_to_arc(
         p1, p2, bulge)
     ellipse = ConstructionEllipse.from_arc(
         center,
         radius,
         Z_AXIS,
         math.degrees(start_angle),
         math.degrees(end_angle),
     )
     curves = list(cubic_bezier_from_ellipse(ellipse))
     if curves[0].control_points[0].isclose(p2):
         curves = _reverse_bezier_curves(curves)
     self.add_curves(curves)
Exemplo n.º 27
0
    def test_context_manager_interface(self):
        xdata = XData()
        with XDataUserList(xdata) as xlist:
            xlist.extend(["String", Vec3(1, 2, 3), 3.1415, 256])

        tags = xdata.get("EZDXF")
        assert tags == [
            dxftag(1001, "EZDXF"),
            dxftag(1000, "DefaultList"),
            dxftag(1002, "{"),
            dxftag(1000, "String"),
            dxftag(1010, (1, 2, 3)),
            dxftag(1040, 3.1415),
            dxftag(1071, 256),
            dxftag(1002, "}"),
        ]
Exemplo n.º 28
0
    def extend(self, vertices: Iterable["Vertex"]) -> None:
        """Append multiple vertices to the reference line.

        It is possible to work with 3D vertices, but all vertices have to be in
        the same plane and the normal vector of this plan is stored as
        extrusion vector in the MLINE entity.

        """
        vertices = Vec3.list(vertices)
        if not vertices:
            return
        all_vertices = []
        if len(self):
            all_vertices.extend(self.get_locations())
        all_vertices.extend(vertices)
        self.generate_geometry(all_vertices)
Exemplo n.º 29
0
 def test_commit_replaces_existing_XDATA(self, list1):
     xlist = XDataUserList(XData([list1]))
     xlist.clear()
     xlist.extend(["String", Vec3(1, 2, 3), 3.1415, 256])
     xlist.commit()
     tags = xlist.xdata.get("EZDXF")
     assert tags == [
         dxftag(1001, "EZDXF"),
         dxftag(1000, "DefaultList"),
         dxftag(1002, "{"),
         dxftag(1000, "String"),
         dxftag(1010, (1, 2, 3)),
         dxftag(1040, 3.1415),
         dxftag(1071, 256),
         dxftag(1002, "}"),
     ]
Exemplo n.º 30
0
 def test_to_edge_path_hatches(self, path):
     hatches = list(to_hatches(path, edge_path=True))
     assert len(hatches) == 1
     h0 = hatches[0]
     assert h0.dxftype() == "HATCH"
     assert len(h0.paths) == 1
     edge_path = h0.paths[0]
     assert edge_path.type == BoundaryPathType.EDGE
     line, spline = edge_path.edges
     assert line.type == EdgeType.LINE
     assert line.start == (0, 0)
     assert line.end == (4, 0)
     assert spline.type == EdgeType.SPLINE
     assert close_vectors(
         Vec3.generate(spline.control_points),
         [(4, 0), (3, 1), (1, 1), (0, 0)],
     )