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)
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
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)
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