def test_complex_ellipse_with_spline_intersection(self):
     ellipse = ConstructionEllipse(center=(0, 0), major_axis=(3, 0), ratio=0.5)
     bspline = BSpline([(-4, -4), (-2, -1), (2, 1), (4, 4)])
     p1 = ellipse.flattening(distance=0.01)
     p2 = bspline.flattening(distance=0.01)
     res = intersect_polylines_2d(Vec2.list(p1), Vec2.list(p2))
     assert len(res) == 2
Ejemplo n.º 2
0
def test_rational_spline_from_elliptic_arc_has_expected_parameters():
    ellipse = ConstructionEllipse(
        center=(1, 1),
        major_axis=(2, 0),
        ratio=0.5,
        start_param=0,
        end_param=math.pi / 2,
    )
    spline = rational_bspline_from_ellipse(ellipse)
    assert spline.degree == 2

    cpoints = spline.control_points
    assert len(cpoints) == 3
    assert cpoints[0].isclose((3, 1, 0))
    assert cpoints[1].isclose((3, 2, 0))
    assert cpoints[2].isclose((1, 2, 0))

    weights = spline.weights()
    assert len(weights) == 3
    assert weights[0] == 1.0
    assert weights[1] == math.cos(math.pi / 4)
    assert weights[2] == 1.0

    # as BSpline constructor()
    s2 = BSpline.from_ellipse(ellipse)
    assert spline.control_points == s2.control_points
Ejemplo n.º 3
0
def test_add_ellipse():
    from ezdxf.math import ConstructionEllipse
    ellipse = ConstructionEllipse(center=(3, 0),
                                  major_axis=(1, 0),
                                  ratio=0.5,
                                  start_param=0,
                                  end_param=math.pi)
    path = Path()
    tools.add_ellipse(path, ellipse)
    assert path.start == (4, 0)
    assert path.end == (2, 0)

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

    path = Path()
    # add a line segment from (0, 0) to start of ellipse
    tools.add_ellipse(path, ellipse, reset=False)
    assert path.start == (0, 0)
    assert path.end == (2, 0)
Ejemplo n.º 4
0
def test_params_from_vertices_random():
    center = Vector.random(5)
    major_axis = Vector.random(5)
    extrusion = Vector.random()
    ratio = 0.75
    e = ConstructionEllipse(center, major_axis, extrusion, ratio)

    params = [random.uniform(0.0001, math.tau - 0.0001) for _ in range(20)]
    vertices = e.vertices(params)
    new_params = e.params_from_vertices(vertices)
    for expected, param in zip(params, new_params):
        assert math.isclose(expected, param)

    # This creates the same vertex as v1 and v2
    v1, v2 = e.vertices([0, math.tau])
    assert v1.isclose(v2)

    # This should create the same param for v1 and v2, but
    # floating point inaccuracy produces unpredictable results:
    p1, p2 = e.params_from_vertices((v1, v2))

    assert math.isclose(p1, 0, abs_tol=1e-9) or math.isclose(
        p1, math.tau, abs_tol=1e-9)
    assert math.isclose(p2, 0, abs_tol=1e-9) or math.isclose(
        p2, math.tau, abs_tol=1e-9)
Ejemplo n.º 5
0
def test_default_init():
    e = ConstructionEllipse()
    assert e.center == (0, 0, 0)
    assert e.major_axis == (1, 0, 0)
    assert e.minor_axis == (0, 1, 0)
    assert e.extrusion == (0, 0, 1)
    assert e.ratio == 1.0
    assert e.start_param == 0
    assert e.end_param == math.tau
Ejemplo n.º 6
0
def bezier4p_from_ellipse(func, count):
    ellipse = ConstructionEllipse(
        center=(1, 2),
        major_axis=(2, 0),
        ratio=0.5,
        start_param=0,
        end_param=math.tau,
    )
    for _ in range(count):
        list(func(ellipse))
Ejemplo n.º 7
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)
def test_dxfattribs():
    e = ConstructionEllipse()
    attribs = e.dxfattribs()
    assert attribs["center"] == (0, 0, 0)
    assert attribs["major_axis"] == (1, 0, 0)
    assert "minor_axis" not in attribs
    assert attribs["extrusion"] == (0, 0, 1)
    assert attribs["ratio"] == 1.0
    assert attribs["start_param"] == 0
    assert attribs["end_param"] == math.tau
Ejemplo n.º 9
0
def test_dxfattribs():
    e = ConstructionEllipse()
    attribs = e.dxfattribs()
    assert attribs['center'] == (0, 0, 0)
    assert attribs['major_axis'] == (1, 0, 0)
    assert 'minor_axis' not in attribs
    assert attribs['extrusion'] == (0, 0, 1)
    assert attribs['ratio'] == 1.0
    assert attribs['start_param'] == 0
    assert attribs['end_param'] == math.tau
Ejemplo n.º 10
0
 def construction_tool(self) -> ConstructionEllipse:
     """Returns construction tool :class:`ezdxf.math.ConstructionEllipse`."""
     dxf = self.dxf
     return ConstructionEllipse(
         dxf.center,
         dxf.major_axis,
         dxf.extrusion,
         dxf.ratio,
         dxf.start_param,
         dxf.end_param,
     )
Ejemplo n.º 11
0
 def add_ellipse_edge(edge):
     ocs_ellipse = edge.construction_tool()
     # ConstructionEllipse has WCS representation:
     ellipse = ConstructionEllipse(
         center=wcs(ocs_ellipse.center.replace(z=elevation)),
         major_axis=wcs(ocs_ellipse.major_axis),
         ratio=ocs_ellipse.ratio,
         extrusion=extrusion,
         start_param=ocs_ellipse.start_param,
         end_param=ocs_ellipse.end_param,
     )
     tools.add_ellipse(path, ellipse, reset=not bool(path))
Ejemplo n.º 12
0
 def construction_tool(self) -> ConstructionEllipse:
     """Returns ConstructionEllipse() for the OCS representation."""
     return ConstructionEllipse(
         center=Vec3(self.center),
         major_axis=Vec3(self.major_axis),
         extrusion=Vec3(0, 0, 1),
         ratio=self.ratio,
         # 1. ConstructionEllipse() is always in ccw orientation
         # 2. Start- and end params are always stored in ccw orientation
         start_param=self.start_param,
         end_param=self.end_param,
     )
Ejemplo n.º 13
0
def test_rational_spline_from_complex_elliptic_arc():
    ellipse = ConstructionEllipse(
        center=(49.64089977339618, 36.43095770602131, 0.0),
        major_axis=(16.69099826506408, 6.96203799241026, 0.0),
        ratio=0.173450304570581,
        start_param=5.427509144462117,
        end_param=7.927025930557775,
    )
    curves = list(cubic_bezier_from_ellipse(ellipse))

    assert curves[0].control_points[0].isclose(ellipse.start_point)
    assert curves[1].control_points[-1].isclose(ellipse.end_point)
Ejemplo n.º 14
0
def test_rational_spline_from_elliptic_arc_has_same_end_points():
    ellipse = ConstructionEllipse(
        center=(1, 1),
        major_axis=(2, 0),
        ratio=0.5,
        start_param=math.radians(30),
        end_param=math.radians(330),
    )
    start_point = ellipse.start_point
    end_point = ellipse.end_point
    spline = rational_bspline_from_ellipse(ellipse)
    assert start_point.isclose(spline.control_points[0])
    assert end_point.isclose(spline.control_points[-1])
Ejemplo n.º 15
0
def test_swap_axis_full_ellipse():
    ellipse = ConstructionEllipse(
        major_axis=(5, 0, 0),
        ratio=2,
    )
    assert ellipse.minor_axis.isclose((0, 10, 0))

    ellipse.swap_axis()
    assert ellipse.ratio == 0.5
    assert ellipse.major_axis == (0, 10, 0)
    assert ellipse.minor_axis == (-5, 0, 0)
    assert ellipse.start_param == 0
    assert ellipse.end_param == math.pi * 2
Ejemplo n.º 16
0
def test_tangents():
    e = ConstructionEllipse(center=(3, 3),
                            major_axis=(2, 0),
                            ratio=0.5,
                            start_param=0,
                            end_param=math.pi * 1.5)
    params = list(e.params(7))
    result = [(0.0, 1.0, 0.0), (-0.894427190999916, 0.447213595499958, 0.0),
              (-1.0, 3.061616997868383e-17, 0.0),
              (-0.894427190999916, -0.4472135954999579, 0.0),
              (-2.4492935982947064e-16, -1.0, 0.0),
              (0.8944271909999159, -0.44721359549995804, 0.0), (1.0, 0.0, 0.0)]
    for v, r in zip(e.tangents(params), result):
        assert v.isclose(r)
Ejemplo n.º 17
0
def test_rational_spline_from_elliptic_arc():
    ellipse = ConstructionEllipse(
        center=(1, 1),
        major_axis=(2, 0),
        ratio=0.5,
        start_param=0,
        end_param=math.pi / 2,
    )
    curves = list(cubic_bezier_from_ellipse(ellipse))
    assert len(curves) == 1

    p1, p2, p3, p4 = curves[0].control_points
    assert p1.isclose((3, 1, 0))
    assert p2.isclose((3.0, 1.5522847498307932, 0))
    assert p3.isclose((2.104569499661587, 2.0, 0))
    assert p4.isclose((1, 2, 0))
def test_vertices():
    e = ConstructionEllipse(center=(3, 3), major_axis=(2, 0), ratio=0.5, start_param=0, end_param=math.pi * 1.5)
    params = list(e.params(7))
    result = [
        (5.0, 3.0, 0.0),
        (4.414213562373095, 3.7071067811865475, 0.0),
        (3.0, 4.0, 0.0),
        (1.585786437626905, 3.7071067811865475, 0.0),
        (1.0, 3.0, 0.0),
        (1.5857864376269046, 2.2928932188134525, 0.0),
        (3.0, 2.0, 0.0),
    ]
    for v, r in zip(e.vertices(params), result):
        assert v.isclose(r)

    v1, v2 = e.vertices([0, math.tau])
    assert v1 == v2
Ejemplo n.º 19
0
 def ellipse(edge: EllipseEdge):
     ocs_ellipse = edge.construction_tool()
     # ConstructionEllipse has WCS representation:
     # Note: clockwise oriented ellipses are converted to counter
     # clockwise ellipses at the loading stage!
     # See: ezdxf.entities.boundary_paths.EllipseEdge.load_tags()
     ellipse = ConstructionEllipse(
         center=wcs(ocs_ellipse.center.replace(z=elevation)),
         major_axis=wcs_tangent(ocs_ellipse.major_axis),
         ratio=ocs_ellipse.ratio,
         extrusion=extrusion,
         start_param=ocs_ellipse.start_param,
         end_param=ocs_ellipse.end_param,
     )
     segment = Path()
     tools.add_ellipse(segment, ellipse, reset=True)
     return segment
def test_angle_to_param():
    random_tests_count = 100
    random.seed(0)

    angle = 1.23
    assert math.isclose(angle_to_param(1.0, angle), angle)

    angle = 1.23 + math.pi / 2
    assert math.isclose(angle_to_param(1.0, angle), angle)

    angle = 1.23 + math.pi
    assert math.isclose(angle_to_param(1.0, angle), angle)

    angle = 1.23 + 3 * math.pi / 2
    assert math.isclose(angle_to_param(1.0, angle), angle)

    angle = math.pi / 2 + 1e-15
    assert math.isclose(angle_to_param(1.0, angle), angle)

    for _ in range(random_tests_count):
        ratio = random.uniform(1e-6, 1)
        angle = random.uniform(0, math.tau)
        param = angle_to_param(ratio, angle)
        ellipse = ConstructionEllipse(
            # avoid (0, 0, 0) as major axis
            major_axis=(non_zero_random(), non_zero_random(), 0),
            ratio=ratio,
            start_param=0,
            end_param=param,
            extrusion=(0, 0, random.choice((1, -1))),
        )
        calculated_angle = ellipse.extrusion.angle_about(
            ellipse.major_axis, ellipse.end_point)
        calculated_angle_without_direction = ellipse.major_axis.angle_between(
            ellipse.end_point)
        assert math.isclose(calculated_angle, angle, abs_tol=1e-9)
        assert math.isclose(
            calculated_angle,
            calculated_angle_without_direction) or math.isclose(
                math.tau - calculated_angle,
                calculated_angle_without_direction)
Ejemplo n.º 21
0
def test_get_start_and_end_vertex():
    ellipse = ConstructionEllipse(
        center=(1, 2, 3),
        major_axis=(4, 3, 0),
        extrusion=(0, 0, -1),
        ratio=.7,
        start_param=math.pi / 2,
        end_param=math.pi,
    )

    start, end = list(ellipse.vertices([
        ellipse.start_param,
        ellipse.end_param,
    ]))
    # test values from BricsCAD
    assert start.isclose(Vec3(3.1, -0.8, 3), abs_tol=1e-6)
    assert end.isclose(Vec3(-3, -1, 3), abs_tol=1e-6)

    # for convenience, but vertices() is much more efficient:
    assert ellipse.start_point.isclose(Vec3(3.1, -0.8, 3), abs_tol=1e-6)
    assert ellipse.end_point.isclose(Vec3(-3, -1, 3), abs_tol=1e-6)
Ejemplo n.º 22
0
        def to_spline_edge(e: EllipseEdge) -> SplineEdge:
            # No OCS transformation needed, source ellipse and target spline
            # reside in the same OCS.
            ellipse = ConstructionEllipse(
                center=e.center,
                major_axis=e.major_axis,
                ratio=e.ratio,
                start_param=e.start_param,
                end_param=e.end_param,
            )
            count = max(int(float(num) * ellipse.param_span / math.tau), 3)
            tool = BSpline.ellipse_approximation(ellipse, count)
            spline = SplineEdge()
            spline.degree = tool.degree
            if not e.ccw:
                tool = tool.reverse()

            spline.control_points = Vec2.list(tool.control_points)
            spline.knot_values = tool.knots()  # type: ignore
            spline.weights = tool.weights()  # type: ignore
            return spline
Ejemplo n.º 23
0
def test_bezier_curves_ellipse_issue_708(ellipse):
    ellipse_ = ConstructionEllipse(
        center=(1.5, 0.375, 0.0),
        major_axis=(0.625, 0.0, 0.0),
        ratio=1.0,
        start_param=-2.498091544796509,
        end_param=-0.6435011087932844,
    )
    curves = list(ellipse(ellipse_))
    assert curves[0].control_points == (Vec3(0.9999999999999999,
                                             1.6653345369377348e-16, 0.0),
                                        Vec3(1.1180339887498947,
                                             -0.15737865166652631, 0.0),
                                        Vec3(1.3032766854168418,
                                             -0.2499999999999999, 0.0),
                                        Vec3(1.4999999999999998, -0.25, 0.0))
    assert curves[1].control_points == (Vec3(1.4999999999999998, -0.25, 0.0),
                                        Vec3(1.696723314583158, -0.25, 0.0),
                                        Vec3(1.881966011250105,
                                             -0.15737865166652654, 0.0),
                                        Vec3(2.0, -5.551115123125783e-17, 0.0))
Ejemplo n.º 24
0
def test_swap_axis_arbitrary_params():
    random_tests_count = 100
    random.seed(0)

    for _ in range(random_tests_count):
        ellipse = ConstructionEllipse(
            # avoid (0, 0, 0) as major axis
            major_axis=(non_zero_random(), non_zero_random(), 0),
            ratio=2,
            start_param=random.uniform(0, math.tau),
            end_param=random.uniform(0, math.tau),
            extrusion=(0, 0, random.choice((1, -1))),
        )

        # Test if coordinates of start- and end point stay at the same location
        # before and after swapping axis.
        start_point = ellipse.start_point
        end_point = ellipse.end_point
        minor_axis = ellipse.minor_axis
        ellipse.swap_axis()
        assert ellipse.major_axis.isclose(minor_axis, abs_tol=1e-9)
        assert ellipse.start_point.isclose(start_point, abs_tol=1e-9)
        assert ellipse.end_point.isclose(end_point, abs_tol=1e-9)
Ejemplo n.º 25
0
        def to_line_edges(edge):
            # Start- and end params are always stored in counter clockwise order!
            ellipse = ConstructionEllipse(
                center=edge.center,
                major_axis=edge.major_axis,
                ratio=edge.ratio,
                start_param=edge.start_param,
                end_param=edge.end_param,
            )
            segment_count = max(
                int(float(num) * ellipse.param_span / math.tau), 3
            )
            params = ellipse.params(segment_count + 1)

            # Reverse path if necessary!
            if not edge.ccw:
                params = reversed(list(params))
            vertices = list(ellipse.vertices(params))
            for v1, v2 in zip(vertices[:-1], vertices[1:]):
                line = LineEdge()
                line.start = v1.vec2
                line.end = v2.vec2
                yield line
Ejemplo n.º 26
0
def test_to_ocs():
    e = ConstructionEllipse().to_ocs()
    assert e.center == (0, 0)
Ejemplo n.º 27
0
def test_params():
    count = 9
    e = ConstructionEllipse(start_param=math.pi / 2, end_param=-math.pi / 2)
    params = list(e.params(count))
    expected = list(linspace(math.pi / 2, math.pi / 2.0 * 3.0, count))
    assert params == expected
Ejemplo n.º 28
0
 def test_no_ellipse(self, start, end):
     e = ConstructionEllipse(start_param=start, end_param=end)
     assert e.param_span == 0.0
Ejemplo n.º 29
0
 def test_full_ellipse(self, start, end):
     e = ConstructionEllipse(start_param=start, end_param=end)
     assert e.param_span == pytest.approx(math.tau)
Ejemplo n.º 30
0
 def test_elliptic_arc(self, start, end, expected):
     e = ConstructionEllipse(start_param=start, end_param=end)
     assert e.param_span == pytest.approx(expected)