def test_params_from_vertices_random(): center = Vec3.random(5) major_axis = Vec3.random(5) extrusion = Vec3.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_intersection_ray_ray_3d_random(): for _ in range(5): intersection_point = Vec3.random(5) ray1 = (intersection_point, intersection_point + Vec3.random()) ray2 = (intersection_point, intersection_point - Vec3.random()) result = intersection_ray_ray_3d(ray1, ray2) assert len(result) == 1 assert result[0].isclose(intersection_point)
def build(): circle = Circle() vertices = list(circle.vertices(linspace(0, 360, vertex_count, endpoint=False))) 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(circle, vertices, m)
def test_split_strategies(strategy): points = [Vec3.random(100) for _ in range(100)] nodes = strategy(points, 5) assert len(nodes) == 5 for node in nodes: assert len(node) == 20 assert isinstance(node, rtree.InnerNode) is True assert len(node.children) == 5
def test_circle_fast_translation(): circle = Circle.new(dxfattribs={ "center": (2, 3, 4), "extrusion": Vec3.random() }) ocs = circle.ocs() offset = Vec3(1, 2, 3) center = ocs.to_wcs(circle.dxf.center) + offset circle.translate(*offset) assert ocs.to_wcs(circle.dxf.center).isclose(center, abs_tol=1e-9)
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)
def build(): ellipse = Ellipse.new(dxfattribs={ 'start_param': start, 'end_param': end, }) vertices = list(ellipse.vertices(ellipse.params(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(ellipse, vertices, m)
def main_ellipse(layout): entity, vertices, axis_vertices = ellipse(start=math.pi / 2, end=-math.pi / 2) axis = Vec3.random() angle = random_angle() entity, vertices, axis_vertices = synced_rotation(entity, vertices, axis_vertices, axis=axis, angle=angle) entity, vertices, axis_vertices = synced_translation( entity, vertices, axis_vertices, dx=random.uniform(-2, 2), dy=random.uniform(-2, 2), dz=random.uniform(-2, 2), ) for sx, sy, sz in UNIFORM_SCALING + NON_UNIFORM_SCALING: entity0, vertices0, axis0 = synced_scaling(entity, vertices, axis_vertices, sx, sy, sz) add(layout, entity0, vertices0, layer=f"new ellipse") layout.add_line( axis0[0], axis0[2], dxfattribs={ "color": 6, "linetype": "DASHED", "layer": "old axis" }, ) layout.add_line( axis0[1], axis0[3], dxfattribs={ "color": 6, "linetype": "DASHED", "layer": "old axis" }, ) p = list(entity0.vertices([0, math.pi / 2, math.pi, math.pi * 1.5])) layout.add_line(p[0], p[2], dxfattribs={ "color": 1, "layer": "new axis" }) layout.add_line(p[1], p[3], dxfattribs={ "color": 3, "layer": "new axis" })
def main_insert(layout): entity, vertices = insert() entity, vertices = synced_translation(entity, vertices, dx=1, dy=0, dz=0) axis = Vec3.random() angle = random_angle() for sx, sy, sz in NON_UNIFORM_SCALING: # 1. scale entity0, vertices0 = synced_scaling(entity, vertices, sx=sx, sy=sy, sz=sz) # 2. rotate entity0, vertices0 = synced_rotation(entity0, vertices0, axis=axis, angle=angle) # 3. translate entity0, vertices0 = synced_translation( entity0, vertices0, dx=random.uniform(-2, 2), dy=random.uniform(-2, 2), dz=random.uniform(-2, 2), ) layout.entitydb.add(entity0) layout.add_entity(entity0) origin, x, y, z = list(vertices0) layout.add_line(origin, x, dxfattribs={ "color": 2, "layer": "new axis" }) layout.add_line(origin, y, dxfattribs={ "color": 4, "layer": "new axis" }) layout.add_line(origin, z, dxfattribs={ "color": 6, "layer": "new axis" }) for line in entity0.virtual_entities(): line.dxf.layer = "exploded axis" line.dxf.color = 7 layout.entitydb.add(line) layout.add_entity(line)
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)
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)
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
def test_random_ellipse_transformations(sx, sy, sz, start, end): vertex_count = 8 def build(angle, dx, dy, dz, axis): ellipse = Ellipse.new(dxfattribs={ "start_param": start, "end_param": end, }) vertices = list(ellipse.vertices(ellipse.params(vertex_count))) m = Matrix44.chain( Matrix44.axis_rotate(axis=axis, angle=angle), Matrix44.translate(dx=dx, dy=dy, dz=dz), ) return synced_transformation(ellipse, vertices, m) def check(ellipse, vertices): ellipse_vertices = list(ellipse.vertices(ellipse.params(vertex_count))) # Ellipse vertices may appear in reverse order if not vertices[0].isclose(ellipse_vertices[0], abs_tol=1e-5): ellipse_vertices.reverse() for vtx, chk in zip(ellipse_vertices, vertices): assert vtx.isclose(chk, abs_tol=1e-5) is True, config for _ in range(10): angle = random.uniform(0, math.tau) dx = random.uniform(-2, 2) dy = random.uniform(-2, 2) dz = random.uniform(-2, 2) axis = Vec3.random() config = ( f"CONFIG sx={sx}, sy={sy}, sz={sz}; " f"start={start:.4f}, end={end:.4f}; " f"angle={angle}; dx={dx}, dy={dy}, dz={dz}; axis={str(axis)}") ellipse0, vertices0 = build(angle, dx, dy, dz, axis) check(ellipse0, vertices0) check(*synced_scaling(ellipse0, vertices0, sx, sy, sz))
def test_contains_all_random_points(self): points = [Vec3.random(50) for _ in range(100)] tree = RTree(points, 5) for point in points: assert tree.contains(point) is True
def test_avg_nn_distance_of_random_points(): tree = RTree([Vec3.random(100) for _ in range(100)]) nn_dist = tree.avg_nn_distance() assert nn_dist > 10.0
def test_avg_spherical_envelope_radius_of_random_points(): tree = RTree([Vec3.random(100) for _ in range(100)]) radius = tree.avg_spherical_envelope_radius() assert radius > 10.0
def test_average_leaf_size_of_random_points(): tree = RTree([Vec3.random(100) for _ in range(100)]) size = tree.avg_leaf_size() assert size > 10.0
def test_collect_leafs(): tree = RTree([Vec3.random(100) for _ in range(100)]) assert sum(len(leaf) for leaf in rtree.collect_leafs(tree._root)) == 100
def random_points(n, size=1.0): return [Vec3.random() * size for _ in range(n)]
# Copyright (c) 2022, Manfred Moitzi # License: MIT License import pytest from ezdxf.math import Vec3, k_means, average_cluster_radius, average_intra_cluster_distance POINTS = [Vec3.random(100) for _ in range(100)] @pytest.mark.parametrize("k", [4, 5, 6]) def test_cluster_random_points(k): clusters = k_means(POINTS, k, max_iter=5) assert len(clusters) == k assert sum(map(len, clusters)) == 100 def test_measure_average_cluster_radius(): clusters = k_means(POINTS, 5, max_iter=5) assert average_cluster_radius(clusters) > 10.0 def test_measure_average_intra_cluster_distance(): clusters = k_means(POINTS, 5, max_iter=5) assert average_intra_cluster_distance(clusters) > 10.0 if __name__ == "__main__": pytest.main([__file__])