Exemple #1
0
def test_add_curves3():
    path = Path()
    c1 = Bezier3P(((0, 0), (1, 1), (2, 0)))
    c2 = Bezier3P(((2, 0), (1, -1), (0, 0)))
    tools.add_bezier3p(path, [c1, c2])
    assert len(path) == 2
    assert path.end == (0, 0)
Exemple #2
0
def test_add_curves3_with_gap():
    path = Path()
    c1 = Bezier3P(((0, 0), (1, 1), (2, 0)))
    c2 = Bezier3P(((2, -1), (3, -2), (0, -1)))
    tools.add_bezier3p(path, [c1, c2])
    assert len(path) == 3  # added a line segment between curves
    assert path.end == (0, -1)
Exemple #3
0
def quadratic_bezier_from_3p(p1: Vertex, p2: Vertex, p3: Vertex) -> Bezier3P:
    """Returns a quadratic Bèzier curve :class:`Bezier3P` from three points.
    The curve starts at `p1`, goes through `p2` and ends at `p3`.
    (source: `pomax-2`_)

    .. versionadded:: 0.17.2

    .. _pomax-2: https://pomax.github.io/bezierinfo/#pointcurves

    """
    def u_func(t: float) -> float:
        mt = 1.0 - t
        mt2 = mt * mt
        return mt2 / (t * t + mt2)

    def ratio(t: float) -> float:
        t2 = t * t
        mt = 1.0 - t
        mt2 = mt * mt
        return abs((t2 + mt2 - 1.0) / (t2 + mt2))

    s = Vec3(p1)
    b = Vec3(p2)
    e = Vec3(p3)
    d1 = (s - b).magnitude
    d2 = (e - b).magnitude
    t = d1 / (d1 + d2)
    u = u_func(t)
    c = s * u + e * (1.0 - u)
    a = b + (b - c) / ratio(t)
    return Bezier3P([s, a, e])
Exemple #4
0
def test_quadratic_to_cubic_bezier():
    r = random.Random(0)

    def random_vec() -> Vec3:
        return Vec3(r.uniform(-10, 10), r.uniform(-10, 10), r.uniform(-10, 10))

    for i in range(1000):
        quadratic = Bezier3P((random_vec(), random_vec(), random_vec()))
        quadratic_approx = list(quadratic.approximate(10))
        cubic = quadratic_to_cubic_bezier(quadratic)
        cubic_approx = list(cubic.approximate(10))

        assert len(quadratic_approx) == len(cubic_approx)
        for p1, p2 in zip(quadratic_approx, cubic_approx):
            assert p1.isclose(p2)
Exemple #5
0
    def test_curve3_to(self):
        bez3 = Bezier3P([(0, 0), (2, 1), (4, 0)])
        p = path.Path()
        p.curve3_to(bez3.control_points[2], bez3.control_points[1])
        qpath = path.to_qpainter_path([p])
        # Qt converts quadratic bezier curves unto cubic bezier curves
        assert qpath.elementCount() == 4
        bez4 = quadratic_to_cubic_bezier(bez3)

        q1 = qpath.elementAt(1)
        assert q1.isCurveTo()  # start of cure
        assert q1.x, q1.y == bez4.control_points[1]

        q2 = qpath.elementAt(2)
        assert q2.type == 3  # curve data element
        assert q2.x, q2.y == bez4.control_points[2]

        q3 = qpath.elementAt(3)
        assert q3.type == 3  # curve data element
        assert q3.x, q3.y == bez4.control_points[2]
Exemple #6
0
def test_add_curves3_reverse():
    path = Path(start=(0, 0))
    c1 = Bezier3P(((2, 0), (1, 1), (0, 0)))
    tools.add_bezier3p(path, [c1])
    assert len(path) == 1
    assert path.end == (2, 0, 0)
Exemple #7
0
def to_bsplines_and_vertices(path: Path,
                             g1_tol: float = G1_TOL) -> Iterable[PathParts]:
    """ Convert a :class:`Path` object into multiple cubic B-splines and
    polylines as lists of vertices. Breaks adjacent Bèzier without G1
    continuity into separated B-splines.

    Args:
        path: :class:`Path` objects
        g1_tol: tolerance for G1 continuity check

    Returns:
        :class:`~ezdxf.math.BSpline` and lists of :class:`~ezdxf.math.Vec3`

    .. versionadded:: 0.16

    """
    from ezdxf.math import bezier_to_bspline

    def to_vertices():
        points = [polyline[0][0]]
        for line in polyline:
            points.append(line[1])
        return points

    def to_bspline():
        b1 = bezier[0]
        _g1_continuity_curves = [b1]
        for b2 in bezier[1:]:
            if have_bezier_curves_g1_continuity(b1, b2, g1_tol):
                _g1_continuity_curves.append(b2)
            else:
                yield bezier_to_bspline(_g1_continuity_curves)
                _g1_continuity_curves = [b2]
            b1 = b2

        if _g1_continuity_curves:
            yield bezier_to_bspline(_g1_continuity_curves)

    prev = path.start
    curves = []
    for cmd in path:
        if cmd.type == Command.CURVE3_TO:
            curve = Bezier3P([prev, cmd.ctrl, cmd.end])
        elif cmd.type == Command.CURVE4_TO:
            curve = Bezier4P([prev, cmd.ctrl1, cmd.ctrl2, cmd.end])
        elif cmd.type == Command.LINE_TO:
            curve = (prev, cmd.end)
        else:
            raise ValueError
        curves.append(curve)
        prev = cmd.end

    bezier = []
    polyline = []
    for curve in curves:
        if isinstance(curve, tuple):
            if bezier:
                yield from to_bspline()
                bezier.clear()
            polyline.append(curve)
        else:
            if polyline:
                yield to_vertices()
                polyline.clear()
            bezier.append(curve)

    if bezier:
        yield from to_bspline()
    if polyline:
        yield to_vertices()
Exemple #8
0
 def approx_curve3(s, c, e) -> Iterable[Vec3]:
     return Bezier3P((s, c, e)).flattening(distance, segments)
Exemple #9
0
 def approx_curve3(s, c, e) -> Iterable[Vec3]:
     return Bezier3P((s, c, e)).approximate(segments)
 def approx(self):
     return ApproxParamT(Bezier3P([(0, 0), (1, 2), (2, 4)]))
 def curve(self):
     return Bezier3P([(0, 0), (1, 2), (2, 4)])