def test_cylinder_centroids(self): for (r, h, n) in [(10, 100, 50)]: m = mesh.Mesh() mesh.primitives.add_cylinder(m, r, h, n) v = mesh.Vector(0, 0, h / 2) self.assertAlmostEqualVector(m.solid_centroid(), v) self.assertAlmostEqualVector(m.surface_centroid(), v)
def test_cube_centroids(self): m = mesh.Mesh() mesh.primitives.add_cube(m, 100) centroid0 = mesh.Vector(50.0, 50.0, 50.0) centroid1 = m.solid_centroid() centroid2 = m.surface_centroid() self.assertAlmostEqualVector(centroid1, centroid0) self.assertAlmostEqualVector(centroid2, centroid0)
def test_sphere_centroids(self): m = mesh.Mesh() v = mesh.Vector(23, 45, 67) mesh.primitives.add_sphere(m, 2.0, origin=v, model="octa", detail_level=3) self.assertAlmostEqualVector(m.solid_centroid(), v) self.assertAlmostEqualVector(m.surface_centroid(), v)
def test_torus_centroids(self): m = mesh.Mesh() v = mesh.Vector(1, 2, 3) mesh.primitives.add_torus(m, 3, 1, 20, 20, offset=v) self.assertAlmostEqualVector(m.solid_centroid(), v) self.assertAlmostEqualVector(m.surface_centroid(), v)
def intersect(m1, m2): '''Compute the intersection of m1 and m2. :returns: A new mesh with m2 cut out of m1. ''' # check the algorithm assumptions are satisfied if not m1.closed(): raise ValueError("Mesh 'm1' is not a closed surface") if not m2.closed(): raise ValueError("Mesh 'm2' is not a closed surface") # algorithm: # classify vertices in m1 into inside and outside m2 # classify vertices in m2 into inside and outside m1 # for each face in m1 # for each face in m2 # if there is an intersection, record the intersection line # output all vertices # where intersections exists, add extra vertices # for each face in m1 and m2 # if intersections are recorded # partition the face along the intersection lines # if a partition contains an original vertex included in the output, # output the partition # recursively classify paritions to output based on crossing of # intersections # for each partition to output # output the face, triangulating if necessary new_vertices = {} new_name = {0: 0} # hack to be visible in the inner function m1_vertices = {} m2_vertices = {} include_vertex = {} # determine if m1 vertex is inside or outside m2 for v in m1.vertices: count = 0 # XXX: this is going to break at some point! Fix with octrees p = [ v, v.normal() + mesh.Vector(uniform(-0.1, 0.1), uniform(-0.1, 0.1), uniform(-0.1, 0.1)) ] for f2 in m2.faces: vs = f2.vertices s = mesh.triangle_segment_intersect(p, vs, 1) if isinstance(s, mesh.Vector): count += 1 if count % 2 == 0: # even number of crossing => outside m1_vertices[v] = 1 else: m1_vertices[v] = 0 # determine if m2 vertex is inside or outside m1 for v in m2.vertices: count = 0 # XXX: this is going to break at some point! Fix with octrees p = [ v, v.normal() + mesh.Vector(uniform(-0.1, 0.1), uniform(-0.1, 0.1), uniform(-0.1, 0.1)) ] for f1 in m1.faces: vs = f1.vertices s = mesh.triangle_segment_intersect(p, vs, 1) if isinstance(s, mesh.Vector): count += 1 if count % 2 == 0: # even number of crossing => outside m2_vertices[v] = 0 else: m2_vertices[v] = 1 # add vertices to the new vertex list, reusing existing vertices # if extant def add_vertex(v, include): s = [k for k, ve in new_vertices.iteritems() if ve == v] if len(s) == 0: new_vertices[new_name[0]] = v include_vertex[new_name[0]] = include r = new_name[0] new_name[0] += 1 elif len(s) > 1: raise ValueError("Should be at most 1 point") else: r = s[0] return r # create Polygons to represent faces m1_polygons = {} for f1 in m1.faces: m1_polygons[f1] = {} (vs, u, v, undo) = f1.project2d() #vs.reverse() p = mesh.Polygon((vs, [(0, 2), (2, 1), (1, 0)])) m1_polygons[f1]["p"] = p m1_polygons[f1]["u"] = u m1_polygons[f1]["v"] = v m1_polygons[f1]["undo"] = undo # add vertices and record mapping m1_polygons[f1]["map"] = [] for i in range(3): m1_polygons[f1]["map"].append( add_vertex(f1.vertices[i], m1_vertices[f1.vertices[i]])) m2_polygons = {} for f2 in m2.faces: m2_polygons[f2] = {} (vs, u, v, undo) = f2.project2d() p = mesh.Polygon((vs, [(0, 2), (2, 1), (1, 0)])) m2_polygons[f2]["p"] = p m2_polygons[f2]["u"] = u m2_polygons[f2]["v"] = v m2_polygons[f2]["undo"] = undo # add vertices and record mapping m2_polygons[f2]["map"] = [] for i in range(3): m2_polygons[f2]["map"].append( add_vertex(f2.vertices[i], m2_vertices[f2.vertices[i]])) # determine all face/face intersections # XXX: optimise this using octrees for f1 in m1.faces: for f2 in m2.faces: s = mesh.triangle_triangle_intersect(list(f2.vertices), list(f1.vertices)) if isinstance(s, list): # these two faces intersect # add the vertices to the list # marry vertices with existing vertices for i_s in range(len(s)): s[i_s] = add_vertex(s[i_s], 2) u1 = m1_polygons[f1]["u"] v1 = m1_polygons[f1]["v"] u2 = m2_polygons[f2]["u"] v2 = m2_polygons[f2]["v"] # record m1 and m2 vertices verts1 = [0] * len(s) verts2 = [0] * len(s) for i_s in range(len(s)): verts1[i_s] = m1_polygons[f1]["p"].add_vertex( new_vertices[s[i_s]].project2dvector(u1, v1)) #if verts1[i_s].name == len(m1_polygons[f1]["map"]): m1_polygons[f1]["map"].append(s[i_s]) #elif verts1[i_s].name > len(m1_polygons[f1]["map"]): # raise ValueError verts2[i_s] = m2_polygons[f2]["p"].add_vertex( new_vertices[s[i_s]].project2dvector(u2, v2)) #if verts2[i_s].name == len(m2_polygons[f2]["map"]): m2_polygons[f2]["map"].append(s[i_s]) #elif verts2[i_s].name > len(m2_polygons[f2]["map"]): # raise ValueError # record m1 and m2 lines for i_s in range(len(s) - 1): m1_polygons[f1]["p"].add_line(verts1[i_s - 1], verts1[i_s]) m2_polygons[f2]["p"].add_line(verts2[i_s - 1], verts2[i_s]) # create new output mesh m = mesh.Mesh() # add all the vertices nv = [] for k, v in new_vertices.items(): if include_vertex[k]: nv.append(m.add_vertex(v)) else: nv.append(v) print "output" # output faces for the outer mesh output_faces(m1_polygons, include_vertex, new_vertices, m, nv) # output faces for the inner mesh output_faces(m2_polygons, include_vertex, new_vertices, m, nv, True) return m