def find_intersections(verts, edges): """ Initializing of searching intersection algorithm, read Computational Geometry by Mark de Berg :param verts: [(x, y) or (x, y, z), ...] :param edges: [(1, 5), ...] :return: [(3d dimensional intersection point, [edge1 involved in intersection, edge2, ...]), ...] """ status = AVLTree() event_queue = AVLTree() for edge in edges: upper_vert = get_upper_vert(verts, edge) lower_vert = (upper_vert + 1) % 2 up_node = event_queue.insert(EventPoint(verts[edge[upper_vert]], edge[upper_vert])) up_node.key.up_edges += [edge] event_queue.insert(EventPoint(verts[edge[lower_vert]], edge[lower_vert])) # event_queue = AVLTree([(co[y], co[x]) for co in v]) # print(event_queue.as_list(0)) out = [] while event_queue: event_node = event_queue.find_smallest() intersection = handle_event_point(status, event_queue, event_node.key, verts) if intersection: out.append(intersection) event_queue.remove_node(event_node) return out
def get_custom_tree(): """ 10 / \ 5 15 \ 9 / 6 """ tree = AVLTree([10]) root = tree.rootNode n5 = Node(5) n5.parent = root root.leftChild = n5 n15 = Node(15) n15.parent = root root.rightChild = n15 n9 = Node(9) n9.parent = n5 n5.rightChild = n9 n6 = Node(6) n6.parent = n9 n9.leftChild = n6 return tree
def make_monotone(verts, hole_v=None, hole_f=None): """ Splits polygon on monotone pieces optionally with holes :param verts: [[x1, y2, z1], [x2, y2, z2], ...] :param hole_v: [[x1, y2, z1], [x2, y2, z2], ...] :param hole_f: [[index1, index2, ....], [...], ...] :return (vertices of main polygon and vertices of holes, faces of new polygons) - in SV format """ #debug_data_clear() points, half_edges, faces = create_half_edges(verts) if hole_f: hole_v, hole_he, hole_f = create_hedges_from_faces(hole_v, hole_f) points, half_edges, faces = add_holes((points, half_edges, faces), hole_f) status = AVLTree() q = sorted(points)[::-1] while q: event_point = q.pop() EdgeSweepLine.global_event_point = event_point #print([(i, p.type) for i, p in enumerate(points)]) #print_p(event_point, 'event point {} - '.format(event_point.type)) new_hedges = handle_functions[event_point.type](event_point, status) if new_hedges: half_edges.extend(new_hedges) #print_e(status.as_list(0)) return to_sv_mesh_from_faces(points, build_face_list(half_edges))
def get_huge_random_tree(): values = [ 1, 14, 27, 31, 45, 55, 77, 103, 141, 175, 230, 231, 239, 251, 267, 298, 306, 310, 311, 316, 356, 367, 451, 457, 482, 483, 518, 533, 553, 615, 634, 674, 688, 708, 711, 728, 737, 771, 789, 798, 820, 833, 862, 864, 919, 928, 985, 994, 997, 999 ] return AVLTree(values)
def get_custom2_tree(): """ ****************************************55(3)******************************************* **************************16(2)**********************86(2)****************************** ****************7(1)************53(1)***********75(1)***********94(1)******************* ********2(0)*****13(0)****26(0)****54(0)****73(0)****78(0)****93(0)****96(0)************ """ val = [2, 7, 13, 16, 26, 53, 54, 55, 73, 75, 78, 86, 93, 94, 96] return AVLTree(val)
def make_monotone(face): """ Splits polygon into monotone pieces optionally with holes :param face: face of half edge data structure :return new half edges Probably approach of implemetation of monotone algorithm should be reconsidered according new DCEL data structure """ face.mesh.Point.monotone_current_face = face status = AVLTree() q = sorted(build_points_list(face))[::-1] _ = [p.type for p in q] # not very cool but this will set type for all points before main algorithm while q: event_point = q.pop() Edge.global_event_point = event_point handle_functions[event_point.type](event_point, status, find_hedge(event_point))
def find_intersections(dcel_mesh, accuracy=1e-6, face_overlapping=False): """ Initializing of searching intersection algorithm, read Computational Geometry by Mark de Berg Only half edges have correct data after the algorithm. Use build faces from half edges method for updating faces if necessary. :param dcel_mesh: inner DCELMesh data structure :param accuracy: two floats figures are equal if their difference is lower then accuracy value, float :param face_overlapping: if True detect in which faces new face is inside """ status = AVLTree() event_queue = AVLTree() accuracy = accuracy if isinstance(accuracy, float) else 1 / 10**accuracy Edge.set_accuracy(accuracy) init_event_queue(event_queue, dcel_mesh) while event_queue: event_node = event_queue.find_smallest() handle_event_point(status, event_queue, event_node.key, dcel_mesh, accuracy, face_overlapping) event_queue.remove_node(event_node) dcel_mesh.hedges = [hedge for hedge in dcel_mesh.hedges if hedge.edge]
def setUp(self): self.custom_tree = self.get_custom_tree() self.empty_tree = AVLTree() self.only_root_tree = AVLTree([10]) self.huge_tree = self.get_huge_random_tree()
class AVLTreeTest(SverchokTestCase): def setUp(self): self.custom_tree = self.get_custom_tree() self.empty_tree = AVLTree() self.only_root_tree = AVLTree([10]) self.huge_tree = self.get_huge_random_tree() def test_avl_tree_search(self): with self.subTest(tree="custom tree"): self.assertEqual(self.custom_tree.find(6).key, 6) with self.subTest(tree="empty tree"): self.assertIsNone(self.empty_tree.find(6)) with self.subTest(tree="only root tree (10)"): self.assertIsNone(self.empty_tree.find(6)) with self.subTest(tree="huge tree"): self.assertIsNone(self.huge_tree.find(500)) self.assertIsNone(self.huge_tree.find(1000)) self.assertIsNone(self.huge_tree.find(100)) self.assertEqual(self.huge_tree.find(533).key, 533) self.assertEqual(self.huge_tree.find(367).key, 367) def test_avl_tree_find_nearest_left(self): values = [6, 5.5, 12, 500] expect_custom_tree = [6, 5, 10, 15] expect_only_root_tree = [None, None, 10, 10] expect_huge_tree = [1, 1, 1, 483] for val, ex, ro, hu in zip(values, expect_custom_tree, expect_only_root_tree, expect_huge_tree): with self.subTest(tree="custom tree", value=val, expected=ex): node = self.custom_tree.find_nearest_left(val) self.assertEqual(node.key, ex) with self.subTest(tree="empty tree", value=val): self.assertIsNone(self.empty_tree.find_nearest_left(val)) for tree, expect in zip([self.only_root_tree, self.huge_tree], [ro, hu]): with self.subTest(tree="root tree or huge tree", value=val, expected=expect): res = tree.find_nearest_left(val) if isinstance(res, Node): self.assertEqual(res.key, expect) else: self.assertIsNone(res) @staticmethod def get_custom_tree(): """ 10 / \ 5 15 \ 9 / 6 """ tree = AVLTree([10]) root = tree.rootNode n5 = Node(5) n5.parent = root root.leftChild = n5 n15 = Node(15) n15.parent = root root.rightChild = n15 n9 = Node(9) n9.parent = n5 n5.rightChild = n9 n6 = Node(6) n6.parent = n9 n9.leftChild = n6 return tree @staticmethod def get_huge_random_tree(): values = [ 1, 14, 27, 31, 45, 55, 77, 103, 141, 175, 230, 231, 239, 251, 267, 298, 306, 310, 311, 316, 356, 367, 451, 457, 482, 483, 518, 533, 553, 615, 634, 674, 688, 708, 711, 728, 737, 771, 789, 798, 820, 833, 862, 864, 919, 928, 985, 994, 997, 999 ] return AVLTree(values) @staticmethod def get_custom2_tree(): """ ****************************************55(3)******************************************* **************************16(2)**********************86(2)****************************** ****************7(1)************53(1)***********75(1)***********94(1)******************* ********2(0)*****13(0)****26(0)****54(0)****73(0)****78(0)****93(0)****96(0)************ """ val = [2, 7, 13, 16, 26, 53, 54, 55, 73, 75, 78, 86, 93, 94, 96] return AVLTree(val)