Beispiel #1
0
 def test_multi_path_to_lwpolylines(self):
     path = Path()
     path.line_to((1, 0, 0))
     path.move_to((2, 0, 0))
     path.line_to((3, 0, 0))
     polylines = list(to_lwpolylines(path))
     assert len(polylines) == 2
     assert len(polylines[0]) == 2
     assert len(polylines[1]) == 2
Beispiel #2
0
def test_append_empty_path():
    path = Path((1, 0, 0))
    path.line_to((2, 0, 0))
    start = path.start
    end = path.end
    path.append_path(Path())
    assert start == path.start and end == path.end, "path should be unchanged"
Beispiel #3
0
def test_approximate_curves():
    path = Path()
    path.curve3_to((2, 0), (1, 1))
    path.curve4_to((3, 0), (2, 1), (3, 1))
    vertices = list(path.approximate(20))
    assert len(vertices) == 41
    assert vertices[0] == (0, 0)
    assert vertices[-1] == (3, 0)
Beispiel #4
0
    def path(self) -> Optional[Path]:
        """Create path representation on demand.

        :class:`Path` can not represent a point, a :class:`Path` with only a
        start point yields not vertices!

        """
        if self._path is None:
            self._path = Path(self.entity.dxf.location)
        return self._path
Beispiel #5
0
def test_reversing_multi_path():
    p = Path()
    p.line_to((1, 0, 0))
    p.move_to((2, 0, 0))
    p.line_to((3, 0, 0))
    r = p.reversed()
    assert r.has_sub_paths is True
    assert len(r) == 3
    assert r.start == (3, 0, 0)
    assert r.end == (0, 0, 0)

    r0, r1 = r.sub_paths()
    assert r0.start == (3, 0, 0)
    assert r0.end == (2, 0, 0)
    assert r1.start == (1, 0, 0)
    assert r1.end == (0, 0, 0)
Beispiel #6
0
    def _convert_entity(self):
        """ Calculates the rough border path for a single line text.

        Calculation is based on a mono-spaced font and therefore the border
        path is just an educated guess.

        Vertical text generation and oblique angle is ignored.

        """
        def get_text_rotation() -> float:
            if alignment in ('FIT', 'ALIGNED') and not p1.isclose(p2):
                return (p2 - p1).angle
            else:
                return math.degrees(text.dxf.rotation)

        def get_insert() -> Vec3:
            if alignment == 'LEFT':
                return p1
            elif alignment in ('FIT', 'ALIGNED'):
                return p1.lerp(p2, factor=0.5)
            else:
                return p2

        text = cast('Text', self.entity)
        if text.dxftype() == 'ATTDEF':
            # ATTDEF outside of a BLOCK renders the tag rather than the value
            content = text.dxf.tag
        else:
            content = text.dxf.text

        content = plain_text(content)
        if len(content) == 0:
            # empty path - does not render any vertices!
            self._path = Path()
            return

        p1: Vec3 = text.dxf.insert
        p2: Vec3 = text.dxf.align_point
        font = fonts.make_font(get_font_name(text), text.dxf.height,
                               text.dxf.width)
        text_line = TextLine(content, font)
        alignment: str = text.get_align()
        if text.dxf.halign > 2:  # ALIGNED=3, MIDDLE=4, FIT=5
            text_line.stretch(alignment, p1, p2)
        halign, valign = unified_alignment(text)
        corner_vertices = text_line.corner_vertices(get_insert(),
                                                    halign, valign,
                                                    get_text_rotation())

        ocs = text.ocs()
        self._path = from_vertices(
            ocs.points_to_wcs(corner_vertices),
            close=True,
        )
Beispiel #7
0
    def test_one_path_multiple_command(self):
        path = Path()
        path.line_to((1, 0))
        path.curve3_to((2, 0), (2.5, 1))
        path.curve4_to((3, 0), (2, 1), (3, 1))
        result = transform_paths([path], Matrix44())

        path0 = result[0]
        assert path0[0].type == Command.LINE_TO
        assert path0[1].type == Command.CURVE3_TO
        assert path0[2].type == Command.CURVE4_TO
        assert path0.start == (0, 0)
        assert path0.end == (3, 0)
Beispiel #8
0
def test_add_spline():
    from ezdxf.math import BSpline
    spline = BSpline.from_fit_points([(2, 0), (4, 1), (6, -1), (8, 0)])
    path = Path()
    tools.add_spline(path, spline)
    assert path.start == (2, 0)
    assert path.end == (8, 0)

    # set start point to end of spline
    path = Path(start=(8, 0))
    # add reversed spline, by default the start of
    # an empty path is set to the spline start
    tools.add_spline(path, spline, reset=False)
    assert path.start == (8, 0)
    assert path.end == (2, 0)

    path = Path()
    # add a line segment from (0, 0) to start of spline
    tools.add_spline(path, spline, reset=False)
    assert path.start == (0, 0)
    assert path.end == (8, 0)
Beispiel #9
0
def test_has_clockwise_orientation():
    # basic has_clockwise_orientation() function is tested in:
    # test_617_clockwise_orientation
    path = converter.from_vertices([(0, 0), (1, 0), (1, 1), (0, 1)])
    assert path.has_clockwise_orientation() is False

    path = Path()
    path.line_to((2, 0))
    path.curve4_to((4, 0), (2, 1), (4, 1))  # end, ctrl1, ctrl2
    assert path.has_clockwise_orientation() is True
Beispiel #10
0
 def test_move_to_creates_a_multi_path_object(self):
     path = Path(start=(1, 0, 0))
     path.line_to((2, 0, 0))
     path.move_to((3, 0, 0))
     assert len(path) == 2, "should add a MOVETO cmd as last cmd"
     assert path.has_sub_paths is True, "should be a multi path object"
     assert path.end.isclose((3, 0, 0)), "should end at the MOVETO location"
Beispiel #11
0
def test_reversing_multi_path_with_a_move_to_cmd_at_the_end():
    p = Path()
    p.line_to((1, 0, 0))
    p.move_to((2, 0, 0))
    # The last move_to will become the first move_to.
    # A move_to as first command just moves the start point.
    r = p.reversed()
    assert len(r) == 1
    assert r.start == (1, 0, 0)
    assert r.end == (0, 0, 0)
    assert r.has_sub_paths is False
Beispiel #12
0
 def test_multiple_first_move_to(self):
     path = Path(start=(1, 0, 0))
     path.move_to((2, 0, 0))
     path.move_to((3, 0, 0))
     path.move_to((4, 0, 0))
     assert path.start.isclose((4, 0, 0)), "should reset the start point"
     assert len(path) == 0, "should not add a MOVETO cmd as first cmd"
     assert path.has_sub_paths is False
Beispiel #13
0
    def test_two_paths_one_command(self):
        path_a = Path()
        path_a.line_to((1, 0))
        path_b = Path((2, 0))
        path_b.line_to((3, 0))
        result = transform_paths([path_a, path_b], Matrix44())

        path0 = result[0]
        assert path0[0].type == Command.LINE_TO
        assert path0.start == (0, 0)
        assert path0.end == (1, 0)

        path1 = result[1]
        assert path1[0].type == Command.LINE_TO
        assert path1.start == (2, 0)
        assert path1.end == (3, 0)
Beispiel #14
0
def test_control_vertices(p1):
    vertices = list(p1.control_vertices())
    assert close_vectors(vertices, [(0, 0), (2, 0), (2, 1), (4, 1), (4, 0),
                                    (5, -1), (6, 0)])
    path = Path()
    assert len(list(path.control_vertices())) == 0
    assert list(path.control_vertices()) == list(path.approximate(2))
    path = converter.from_vertices([(0, 0), (1, 0)])
    assert len(list(path.control_vertices())) == 2
Beispiel #15
0
 def test_multi_path_objects(self):
     path = Path()
     path.line_to((1, 0, 0))
     path.move_to((2, 0, 0))
     paths = transform_paths([path], Matrix44.translate(0, 1, 0))
     assert len(paths) == 1
     path2 = paths[0]
     assert path2.start.isclose((0, 1, 0))
     assert len(path2) == 2
     assert path2.end.isclose((2, 1, 0))
     assert path2.has_sub_paths is True
Beispiel #16
0
    def test_two_paths_multiple_commands(self):
        path_a = Path()
        path_a.line_to((1, 0))
        path_a.curve3_to((2, 0), (2.5, 1))
        path_a.curve4_to((3, 0), (2, 1), (3, 1))

        path_b = path_a.transform(Matrix44.translate(4, 0, 0))
        result = transform_paths([path_a, path_b], Matrix44())

        path0 = result[0]
        assert path0[0].type == Command.LINE_TO
        assert path0[1].type == Command.CURVE3_TO
        assert path0[2].type == Command.CURVE4_TO
        assert path0.start == (0, 0)
        assert path0.end == (3, 0)

        path1 = result[1]
        assert path1[0].type == Command.LINE_TO
        assert path1[1].type == Command.CURVE3_TO
        assert path1[2].type == Command.CURVE4_TO
        assert path1.start == (4, 0)
        assert path1.end == (7, 0)
Beispiel #17
0
    def draw_path(self, path: Path, properties: Properties) -> None:
        """ Draw an outline path (connected string of line segments and Bezier
        curves).

        The :meth:`draw_path` implementation is a fall-back implementation
        which approximates Bezier curves by flattening as line segments.
        Backends can override this method if better path drawing functionality
        is available for that backend.

        """
        if len(path):
            vertices = iter(
                path.flattening(distance=self.max_flattening_distance))
            prev = next(vertices)
            for vertex in vertices:
                self.draw_line(prev, vertex, properties)
                prev = vertex
Beispiel #18
0
def make_path_from_str(
    s: str,
    font: fonts.FontFace,
    size: float = 1.0,
    align=TextEntityAlignment.LEFT,
    length: float = 0,
    m: Matrix44 = None,
) -> Path:
    """Convert a single line string `s` into a :term:`Multi-Path` object.
    The text `size` is the height of the uppercase letter "X" (cap height).
    The paths are aligned about the insertion point at (0, 0).
    BASELINE means the bottom of the letter "X".

    Args:
         s: text to convert
         font: font face definition as :class:`~ezdxf.tools.fonts.FontFace` object
         size: text size (cap height) in drawing units
         align: alignment as :class:`ezdxf.enums.TextEntityAlignment`,
            default is :attr:`LEFT`
         length: target length for the :attr:`ALIGNED` and :attr:`FIT` alignments
         m: transformation :class:`~ezdxf.math.Matrix44`

    .. versionadded:: 0.17

    .. version changed: 0.17.2

        Enum :class:`ezdxf.enums.TextEntityAlignment` replaces string
        values.

    """
    if len(s) == 0:
        return Path()
    font_properties, font_measurements = _get_font_data(font)
    # scale font rendering units to drawing units:
    render_size = size / font_measurements.cap_height
    p = _str_to_path(s, font_properties, render_size)
    bbox = path.bbox([p], flatten=0)

    # Text is rendered in drawing units,
    # therefore do alignment in drawing units:
    draw_units_fm = font_measurements.scale_from_baseline(size)
    matrix = alignment_transformation(draw_units_fm, bbox, align, length)
    if m is not None:
        matrix *= m
    return p.transform(matrix)
Beispiel #19
0
 def test_remove_line_segments_of_zero_length_between_commands(self):
     # CURVE3_TO and CURVE4_TO can not process zero length segments
     path = Path()
     path.line_to((1, 0))
     path.line_to((1, 0))  # line segment of length==0 should be removed
     path.line_to((2, 0))
     path = lines_to_curve4(path)
     assert len(path) == 2
     assert path.start == (0, 0)
     assert path[0].type == Command.CURVE4_TO
     assert path[0].end == (1, 0)
     assert path[1].type == Command.CURVE4_TO
     assert path[1].end == (2, 0)
Beispiel #20
0
def test_line_to():
    path = Path()
    path.line_to((1, 2, 3))
    assert path[0] == (Vec3(1, 2, 3), )
    assert path.end == (1, 2, 3)
Beispiel #21
0
def test_add_curves4_reverse():
    path = Path(start=(0, 0, 0))
    c1 = Bezier4P(((2, 0, 0), (2, 1, 0), (0, 1, 0), (0, 0, 0)))
    tools.add_bezier4p(path, [c1])
    assert len(path) == 1
    assert path.end == (2, 0, 0)
Beispiel #22
0
def test_reversing_one_curve4():
    p = Path()
    p.curve4_to((3, 0), (1, 1), (2, 1))
    p2 = list(p.reversed().control_vertices())
    assert p2 == [(3, 0), (2, 1), (1, 1), (0, 0)]
Beispiel #23
0
def test_reversing_one_line():
    p = Path()
    p.line_to((1, 0))
    p2 = list(p.reversed().control_vertices())
    assert p2 == [(1, 0), (0, 0)]
Beispiel #24
0
def test_reversing_empty_path():
    p = Path()
    assert len(p.reversed()) == 0
Beispiel #25
0
def p1():
    path = Path()
    path.line_to((2, 0))
    path.curve4_to((4, 0), (2, 1), (4, 1))  # end, ctrl1, ctrl2
    path.curve3_to((6, 0), (5, -1))  # end, ctrl
    return path
Beispiel #26
0
def test_curve4_to():
    path = Path()
    path.curve4_to((1, 2, 3), (0, 1, 0), (0, 2, 0))
    assert path[0] == ((1, 2, 3), (0, 1, 0), (0, 2, 0))
    assert path.end == (1, 2, 3)
Beispiel #27
0
 def test_does_not_remove_a_line_representing_a_single_point(self):
     path = Path((1, 0))
     path.line_to((1, 0))  # represents the point (1, 0)
     path = lines_to_curve4(path)
     assert len(path) == 1
     assert path[0].type == Command.LINE_TO
Beispiel #28
0
def test_curve3_to():
    path = Path()
    path.curve3_to((10, 0), (5, 5))
    assert path[0] == ((10, 0), (5, 5))
    assert path.end == (10, 0)
Beispiel #29
0
def test_init():
    path = Path()
    assert path.start == (0, 0)
    assert len(path) == 0
    assert path.end == (0, 0)
Beispiel #30
0
def test_init_start():
    path = Path(start=(1, 2))
    assert path.start == (1, 2)