def test_EdgeIsParallelOrAntiparallel(self): test_edge1 = Edge(0, 0, 0, 1, 1, 1.005) test_edge_parallel = Edge(1, 1, 1, 2, 2, 2) tolerance = 0.01 # implemented inside test_edge_anti_parallel = Edge(0, 0, 0, -1, -1, -1) self.assertTrue(Edge.are_parallel_or_anti_parallel(test_edge1, test_edge_parallel)) self.assertTrue(Edge.are_parallel_or_anti_parallel(test_edge1, test_edge_anti_parallel))
def test_EdgeIsParallel(self): test_edge1 = Edge(0, 0, 0, 1, 1, 1.005) test_edge_parallel = Edge(1, 1, 1, 2, 2, 2) tolerance = 0.01 test_edge_anti_parallel = Edge(0, 0, 0, -1, -1, -1) self.assertTrue(Edge.are_parallel(test_edge1, test_edge_parallel, tolerance)) self.assertFalse(Edge.are_parallel(test_edge1, test_edge_anti_parallel, tolerance))
def test_EdgeDot(self): test_edge1 = Edge(0, 0, 0, 1, 1, 1) test_edge2 = Edge(1, 1, 1, 0, 0, 0) test_edge3 = Edge(-1, -1, -1, 0, 0, 0) dot1 = Edge.dot(test_edge1, test_edge2) dot2 = Edge.dot(test_edge1, test_edge3) self.assertEqual(dot1, -3) self.assertEqual(dot2, 3)
def make_simple_boundary(outline_edge_group: UniqueEdgeList, all_edges: UniqueEdgeList): """ Step 3 recursive :param outline_edge_group: A list of edges, grouped by connectivity between edges. :param all_edges: :return: ??? """ while len(all_edges.edge_list) > 0: current_edge = all_edges.edge_list[0] work = False neighbors = all_edges.get_neighbor_indices_for_edge(current_edge) # Loop against all neighboring edges, gobble up the neighbors. for neighbor in neighbors: neighbor_edge = all_edges.edge_list[neighbor] if not Edge.same_edge(current_edge, neighbor_edge): shared_vertex = Edge.has_shared_vertex(current_edge, neighbor_edge) parallel = Edge.are_parallel_or_anti_parallel(current_edge, neighbor_edge) if shared_vertex is not None and parallel: # Case 1. start_vertex = [neighbor_edge.x1, neighbor_edge.y1, neighbor_edge.z1] # Case 2. if (neighbor_edge.x1 == shared_vertex[0] and neighbor_edge.y1 == shared_vertex[1] and neighbor_edge.z1 == shared_vertex[2]): start_vertex = [neighbor_edge.x2, neighbor_edge.y2, neighbor_edge.z2] # Case 3. end_vertex = [current_edge.x1, current_edge.y1, current_edge.z1] # Case 4. if (current_edge.x1 == shared_vertex[0] and current_edge.y1 == shared_vertex[1] and current_edge.z1 == shared_vertex[2]): end_vertex = [current_edge.x2, current_edge.y2, current_edge.z2] new_edge = Edge(start_vertex[0], start_vertex[1], start_vertex[2], # Edge Start end_vertex[0], end_vertex[1], end_vertex[2]) # Edge end all_edges.remove(current_edge) all_edges.remove(neighbor_edge) all_edges.add(new_edge) work = True break if not work and len(all_edges.edge_list) > 0: outline_edge_group.add(current_edge) all_edges.remove(current_edge) return outline_edge_group
def testAddTriangle(self): test_edge1 = Edge(-1, 1, 1, 1, 1, 1) test_edge2 = Edge(1, 1, 1, 1, 1, -1) test_edge3 = Edge(1, 1, -1, -1, 1, 1) triangle = Triangle(test_edge1, test_edge2, test_edge3, self.normal) triangles_count_before = self.face.count() self.face.add_triangle(triangle) triangles_count_after = self.face.count() change = triangles_count_after - triangles_count_before self.assertEqual(change, 1)
def is_closed_loop(self): """Determine if a triangle has all its edges connected. :return: True, if all it's edges are connected. """ start_edge = self.edges[0] first_check = Edge.has_shared_vertex(start_edge, self.edges[1]) second_check = Edge.has_shared_vertex(start_edge, self.edges[2]) third_check = Edge.has_shared_vertex(self.edges[1], self.edges[2]) return first_check and second_check and third_check
def find_outside_boundary(buckets): """ find_outside_boundary (put outside outline at index 0) :param buckets: :return: """ # output_step_3_part_3: Contains a list of "buckets", where each bucket contains a list of for bucket in buckets: outer_boundary_index = 0 max_dist_to_origin = -1.0 for i in range(len(bucket)): boundary = bucket[i] for edge in boundary.edge_list: origin_to_start = Edge(0, 0, 0, edge.x1, edge.y1, edge.z1) origin_to_end = Edge(0, 0, 0, edge.x2, edge.y2, edge.z2) if origin_to_start.length() > max_dist_to_origin: max_dist_to_origin = origin_to_start.length() outer_boundary_index = i if origin_to_end.length() > max_dist_to_origin: max_dist_to_origin = origin_to_end.length() outer_boundary_index = i if outer_boundary_index > 0: # Swap list[outer_boundary_index] and list[0] bucket[outer_boundary_index], bucket[0] = bucket[0], bucket[outer_boundary_index] return buckets
def get_mesh_triangles(mesh: Mesh): """ Converts the mesh to Triangle objects :return: List of Triangles """ mesh_triangles = [] # array of Triangles for data in mesh.data: normal = get_unit_normal(data[0]) # data[0] contains normal value eg: [0, 0, 4] vertex_1 = data[1][0] vertex_2 = data[1][1] vertex_3 = data[1][2] edge_1 = Edge(vertex_1[0], vertex_1[1], vertex_1[2], vertex_2[0], vertex_2[1], vertex_2[2]) edge_2 = Edge(vertex_2[0], vertex_2[1], vertex_2[2], vertex_3[0], vertex_3[1], vertex_3[2]) edge_3 = Edge(vertex_3[0], vertex_3[1], vertex_3[2], vertex_1[0], vertex_1[1], vertex_1[2]) mesh_triangles.append(Triangle(edge_1, edge_2, edge_3, normal=normal)) return mesh_triangles
def has_edge(self, check_edge): """ Checks if the triangle has the matching :param check_edge: Edge :return: True or False """ for edge in self.edges: if Edge.are_overlapping_edges(edge, check_edge): return True return False
def setUp(self): mesh = Mesh.from_file( Util.path_conversion("tests/test_models/2_holes.stl")) mesh_triangles = [] # array of Triangles self.triangles_count = 0 for data in mesh.data: normal = get_unit_normal(data[0]) vertex_1 = data[1][0] vertex_2 = data[1][1] vertex_3 = data[1][2] edge_1 = Edge(vertex_1[0], vertex_1[1], vertex_1[2], vertex_2[0], vertex_2[1], vertex_2[2]) edge_2 = Edge(vertex_2[0], vertex_2[1], vertex_2[2], vertex_3[0], vertex_3[1], vertex_3[2]) edge_3 = Edge(vertex_3[0], vertex_3[1], vertex_3[2], vertex_1[0], vertex_1[1], vertex_1[2]) self.triangles_count += 1 mesh_triangles.append( Triangle(edge_1, edge_2, edge_3, normal=normal)) self.face = Face(mesh_triangles) self.normal = [0, 0, 1]
def test_EdgeSameEdge(self): test_edge1 = Edge(0, 0, 0, 1, 1, 1) test_edge2 = Edge(1, 1, 1, 0, 0, 0) test_edge3 = Edge(0, 0, 0, 2, 2, 2) test_edge4 = Edge(2, 2, 2, 3, 3, 3) same_edge1 = Edge.same_edge(test_edge1, test_edge2) same_edge2 = Edge.same_edge(test_edge1, test_edge1) same_edge3 = Edge.same_edge(test_edge1, test_edge3) same_edge4 = Edge.same_edge(test_edge1, test_edge4) self.assertFalse(same_edge1) self.assertTrue(same_edge2) self.assertFalse(same_edge3) self.assertFalse(same_edge4)
def test_HasSharedVertex(self): test_edge1 = Edge(0, 0, 0, 1, 1, 1) test_edge2 = Edge(1, 1, 1, 0, 0, 0) test_edge3 = Edge(0, 0, 0, -1, -1, -1) test_edge4 = Edge(2, 2, 2, 3, 3, 3) shared_vertex1 = Edge.has_shared_vertex(test_edge1, test_edge2) shared_vertex2 = Edge.has_shared_vertex(test_edge1, test_edge3) shared_vertex3 = Edge.has_shared_vertex(test_edge1, test_edge4) shared_vertex4 = Edge.has_shared_vertex(test_edge1, test_edge1) self.assertTrue(shared_vertex1) self.assertTrue(shared_vertex2) self.assertFalse(shared_vertex3) self.assertTrue(shared_vertex4)
def split_boundary(unique_edge_lists: [], all_edges: UniqueEdgeList, i: int): """ Step 3 part 2 recursive :param unique_edge_lists: :param all_edges: :param i: :return: """ i = 0 j = 0 while len(all_edges.edge_list) > 0: current_edge_in_bucket = unique_edge_lists[i].edge_list[j] work = False for e in all_edges.edge_list: if (not Edge.same_edge(e, current_edge_in_bucket)) and \ (Edge.has_shared_vertex(e, current_edge_in_bucket) is not None): if unique_edge_lists[i].add(e): work = True # Remove all_edges from list that exist in bucket. for e in unique_edge_lists[i].edge_list: all_edges.remove(e) if work is False: if len(all_edges.edge_list) > 0: new_edge_list = UniqueEdgeList() new_edge_list.add(all_edges.edge_list[0]) all_edges.edge_list.pop(0) unique_edge_lists.append(new_edge_list) i += 1 j = 0 else: j += 1 return unique_edge_lists
def make_normal_groups(triangles: []): """ Group triangles by normal :param triangles: List of Triangles :return: List of List of Triangles """ triangles_groups = [] origin = (0.0, 0.0, 0.0) group_match = False for triangle in triangles: for group in triangles_groups: group_normal = group[0].normal # Normal of first triangle in the group triangle_normal = triangle.normal origin_group_normal_edge = Edge(origin[0], origin[1], origin[2], group_normal[0], group_normal[1], group_normal[2]) origin_triangle_normal_edge = Edge(origin[0], origin[1], origin[2], triangle_normal[0], triangle_normal[1], triangle_normal[2]) if Edge.are_parallel(origin_group_normal_edge, origin_triangle_normal_edge, tolerance=0.01): group_match = True group.append(triangle) break if not group_match: triangles_groups.append([triangle]) group_match = False return triangles_groups
def remove(self, edge_to_remove: Edge): """Attempt to remove an edge from the list of edges. :param edge_to_remove: The edge to search for. :return: True, if the edge was removed. """ index_found = -1 for i in range(len(self.edge_list)): if Edge.same_edge(self.edge_list[i], edge_to_remove): index_found = i if index_found != -1: del self.edge_list[index_found] return index_found is not -1
def are_neighbors(t1, t2): """Determine if two triangles have a shared edge. :param t1: The first triangle. :param t2: The second triangle. :return: True, if the triangles had a shared edge. """ result = False # x being an edge in the first triangle. for x in t1.edges: # y being an edge in the second triangle. for y in t2.edges: if Edge.same_edge(x, y): # We just need one shared edge to be true. result = True return result
def add(self, new_edge: Edge): """Add a new edge to this list, but only if it isn't in there already. :param new_edge: The new edge to add to the set. :return: True, if the new edge was added. """ found = False for e in self.edge_list: if Edge.are_overlapping_edges(new_edge, e): found = True break if not found: self.edge_list.append(new_edge) return not found
def test_AreOverlappingEdges(self): test_edge1 = Edge(0, 0, 0, 1, 1, 1) test_edge2 = Edge(1, 1, 1, 0, 0, 0) test_edge3 = Edge(2, 2, 2, 3, 3, 3) overlapping_edges1 = Edge.are_overlapping_edges(test_edge1, test_edge1) overlapping_edges2 = Edge.are_overlapping_edges(test_edge1, test_edge2) overlapping_edges3 = Edge.are_overlapping_edges(test_edge1, test_edge3) self.assertTrue(overlapping_edges1) self.assertTrue(overlapping_edges2) self.assertFalse(overlapping_edges3)
def set_difference(a, b): """This returns a list of edges in set 'a' that aren't in set 'b'. :param a: The first set. :param b: The second set. :return: A list of edges in set 'a' that aren't in set 'b'. """ result = UniqueEdgeList() new_edge_list = [] for edge_in_a in a.edge_list: found = False for edge_in_b in b.edge_list: if Edge.same_edge(edge_in_a, edge_in_b): found = True if not found: new_edge_list.append(edge_in_a) result.edge_list = new_edge_list return result
def make_face_boundaries(faces: []): """Step 2. Remove shared edges. :param faces: List of faces. :return: List of a list of edges where each list of edges is the edges that were not shared in that face. """ # Faces is a list of faces, where faces are composed of triangles on the same plane and # have some edge connecting them. # faces.count() should return the number of planes on an object IE: A cube has 6 faces. output = [] normals = [] k = -1 for face in faces: shared_edges = UniqueEdgeList() all_edges_in_face = face.get_edges() # len(face.triangles) should return the # of triangles in the face. while len(face.triangles) > 0: for m in range(len(face.triangles)): for n in range(len(face.triangles)): if m is not n: for i in range(3): for j in range(3): # Compare an edge in triangle "m" vs the 3 other edges in # triangle "n" if Edge.are_overlapping_edges(face.triangles[m].edges[i], face.triangles[n].edges[j]): shared_edges.add(face.triangles[m].edges[i]) face.triangles.pop(m) break k += 1 normals.append(face.get_normal()) output.append(UniqueEdgeList()) output[k] = UniqueEdgeList.set_difference(all_edges_in_face, shared_edges) return output, normals
def get_neighbor_indices_for_edge(self, edge: Edge): result = [] for i in range(len(self.edge_list)): if Edge.has_shared_vertex(edge, self.edge_list[i]): result.append(i) return result
def test_EdgeIsLengthIsSqrtThree(self): test_edge = Edge(0, 0, 0, 1, 1, 1) length = test_edge.length() self.assertTrue(length, math.sqrt(3))