Ejemplo n.º 1
0
class SuperSeashell:
    def __init__(self, parameters):
        self.parameters = parameters
        self.u_res = parameters['cross_section_resolution']
        self.v_res = parameters['coil_resolution']
        self.topology = parameters['topology']
        self.rows = empty_grid(self.v_res + 1, self.u_res)
        self.start_cap = None
        self.end_cap = None
        self.mesh = Mesh()

    def generate_mesh(self):
        self.generate_vertices()
        self.generate_faces()
        return self.mesh

    def generate_vertices(self):
        if self.topology == 'torus':
            self.generate_torus_vertices()
        elif self.topology == 'cone':
            self.generate_cone_vertices()
        elif self.topology == 'reverse_cone':
            self.generate_reverse_cone_vertices()
        elif self.topology == 'cylinder':
            self.generate_cylinder_vertices()
        else:
            raise RuntimeError(f'Not a valid topology: {self.topology}')

    def generate_torus_vertices(self):
        for j in range(self.v_res):
            v = float(j) / (self.v_res)
            for i in range(self.u_res):
                u = float(i) / (self.u_res)
                vertex = self(u, v)
                idx = self.mesh.add_vertex(vertex)
                self.rows[j][i] = idx

    def generate_cone_vertices(self):
        start_cap = self.coil(0.0)
        self.start_cap = self.mesh.add_vertex(start_cap)

        for i in range(self.v_res):
            v = float(i) / (self.v_res)
            for j in range(self.u_res):
                u = float(j) / (self.u_res)
                vertex = self(u, v)
                idx = self.mesh.add_vertex(vertex)
                self.rows[i][j] = idx

        end_point = self(0.0, 1.0)
        end_idx = self.mesh.add_vertex(end_point)
        self.rows[-1][0] = end_idx

    def generate_reverse_cone_vertices(self):
        start_point = self(0.0, 0.0)
        start_idx = self.mesh.add_vertex(start_point)
        self.rows[0][0] = start_idx

        for i in range(1, self.v_res + 1):
            v = float(i) / (self.v_res)
            for j in range(self.u_res):
                u = float(j) / (self.u_res)
                vertex = self(u, v)
                idx = self.mesh.add_vertex(vertex)
                self.rows[i][j] = idx

        end_cap = self.coil(1.0)
        self.end_cap = self.mesh.add_vertex(end_cap)

    def generate_cylinder_vertices(self):
        start_cap = self.coil(0.0)
        self.start_cap = self.mesh.add_vertex(start_cap)

        for i in range(self.v_res + 1):
            v = float(i) / (self.v_res)
            for j in range(self.u_res):
                u = float(j) / (self.u_res)
                vertex = self(u, v)
                idx = self.mesh.add_vertex(vertex)
                self.rows[i][j] = idx

        end_cap = self.coil(1.0)
        self.end_cap = self.mesh.add_vertex(end_cap)

    def generate_faces(self):
        if self.topology == 'torus':
            self.generate_torus_faces()
        elif self.topology == 'cone':
            self.generate_cone_faces()
        elif self.topology == 'reverse_cone':
            self.generate_reverse_cone_faces()
        elif self.topology == 'cylinder':
            self.generate_cylinder_faces()
        else:
            raise RuntimeError(f'Not a valid topology: {self.topology}')

    def generate_torus_faces(self):
        for i in range(self.v_res - 1):
            for j in range(self.u_res - 1):
                v1 = self.rows[i][j]
                v2 = self.rows[i][j + 1]
                v3 = self.rows[i + 1][j + 1]
                v4 = self.rows[i + 1][j]

                # This is intentionally clockwise to ensure normals are
                # pointing outwards
                self.mesh.add_face([v1, v4, v3])
                self.mesh.add_face([v1, v3, v2])

        # Fill the seam
        for i in range(self.v_res - 1):
            v1 = self.rows[i][-1]
            v2 = self.rows[i][0]
            v3 = self.rows[i + 1][0]
            v4 = self.rows[i + 1][-1]

            # This is intentionally clockwise to ensure normals are
            # pointing outwards
            self.mesh.add_face([v1, v4, v3])
            self.mesh.add_face([v1, v3, v2])

        # loop the end back to the start
        for j in range(self.u_res - 1):
            v1 = self.rows[-2][j]
            v2 = self.rows[-2][j + 1]
            v3 = self.rows[0][j + 1]
            v4 = self.rows[0][j]

            # This is intentionally clockwise to ensure normals are
            # pointing outwards
            self.mesh.add_face([v1, v4, v3])
            self.mesh.add_face([v1, v3, v2])

        # Add the last quad where the seam meets the loop row
        v1 = self.rows[-2][-1]
        v2 = self.rows[-2][0]
        v3 = self.rows[0][0]
        v4 = self.rows[0][-1]

        # This is intentionally clockwise to ensure normals are
        # pointing outwards
        self.mesh.add_face([v1, v4, v3])
        self.mesh.add_face([v1, v3, v2])

    def generate_cone_faces(self):
        for i in range(self.v_res - 1):
            for j in range(self.u_res - 1):
                v1 = self.rows[i][j]
                v2 = self.rows[i][j + 1]
                v3 = self.rows[i + 1][j + 1]
                v4 = self.rows[i + 1][j]

                # This is intentionally clockwise to ensure normals are
                # pointing outwards
                self.mesh.add_face([v1, v4, v3])
                self.mesh.add_face([v1, v3, v2])

        # Fill the seam
        for i in range(self.v_res - 1):
            v1 = self.rows[i][-1]
            v2 = self.rows[i][0]
            v3 = self.rows[i + 1][0]
            v4 = self.rows[i + 1][-1]

            # This is intentionally clockwise to ensure normals are
            # pointing outwards
            self.mesh.add_face([v1, v4, v3])
            self.mesh.add_face([v1, v3, v2])

        # Add cap at the start end
        for j in range(self.u_res - 1):
            v1 = self.rows[0][j]
            v2 = self.rows[0][j + 1]
            self.mesh.add_face([self.start_cap, v1, v2])

        # start cap seam
        v1 = self.rows[0][-1]
        v2 = self.rows[0][0]
        self.mesh.add_face([self.start_cap, v1, v2])

        # End comes to a point
        for j in range(self.u_res - 1):
            point = self.rows[-1][0]
            v1 = self.rows[-2][j]
            v2 = self.rows[-2][j + 1]
            self.mesh.add_face([point, v2, v1])

        # point seam
        point = self.rows[-1][0]
        v1 = self.rows[-2][-1]
        v2 = self.rows[-2][0]
        self.mesh.add_face([point, v2, v1])

    def generate_reverse_cone_faces(self):
        for i in range(1, self.v_res):
            for j in range(self.u_res - 1):
                v1 = self.rows[i][j]
                v2 = self.rows[i][j + 1]
                v3 = self.rows[i + 1][j + 1]
                v4 = self.rows[i + 1][j]

                # This is intentionally clockwise to ensure normals are
                # pointing outwards
                self.mesh.add_face([v1, v4, v3])
                self.mesh.add_face([v1, v3, v2])

        # Fill the seam
        for i in range(1, self.v_res):
            v1 = self.rows[i][-1]
            v2 = self.rows[i][0]
            v3 = self.rows[i + 1][0]
            v4 = self.rows[i + 1][-1]

            # This is intentionally clockwise to ensure normals are
            # pointing outwards
            self.mesh.add_face([v1, v4, v3])
            self.mesh.add_face([v1, v3, v2])

        # Add cap at the end
        for j in range(self.u_res - 1):
            v1 = self.rows[-1][j]
            v2 = self.rows[-1][j + 1]
            self.mesh.add_face([self.end_cap, v2, v1])

        # end cap seam
        v1 = self.rows[-1][-1]
        v2 = self.rows[-1][0]
        self.mesh.add_face([self.end_cap, v2, v1])

        # start comes to a point
        for j in range(self.u_res - 1):
            point = self.rows[0][0]
            v1 = self.rows[1][j]
            v2 = self.rows[1][j + 1]
            self.mesh.add_face([point, v1, v2])

        # point seam
        point = self.rows[0][0]
        v1 = self.rows[1][-1]
        v2 = self.rows[1][0]
        self.mesh.add_face([point, v1, v2])

    def generate_cylinder_faces(self):
        for i in range(self.v_res):
            for j in range(self.u_res - 1):
                v1 = self.rows[i][j]
                v2 = self.rows[i][j + 1]
                v3 = self.rows[i + 1][j + 1]
                v4 = self.rows[i + 1][j]

                # This is intentionally clockwise to ensure normals are
                # pointing outwards
                self.mesh.add_face([v1, v4, v3])
                self.mesh.add_face([v1, v3, v2])

        # Fill the seam
        for i in range(self.v_res):
            v1 = self.rows[i][-1]
            v2 = self.rows[i][0]
            v3 = self.rows[i + 1][0]
            v4 = self.rows[i + 1][-1]

            # This is intentionally clockwise to ensure normals are
            # pointing outwards
            self.mesh.add_face([v1, v4, v3])
            self.mesh.add_face([v1, v3, v2])

        # Add cap at the start end
        for j in range(self.u_res - 1):
            v1 = self.rows[0][j]
            v2 = self.rows[0][j + 1]
            self.mesh.add_face([self.start_cap, v1, v2])

        # start cap seam
        v1 = self.rows[0][-1]
        v2 = self.rows[0][0]
        self.mesh.add_face([self.start_cap, v1, v2])

        # end cap
        for j in range(self.u_res - 1):
            v1 = self.rows[-1][j]
            v2 = self.rows[-1][j + 1]
            self.mesh.add_face([self.end_cap, v2, v1])

        # end cap seam
        v1 = self.rows[-1][-1]
        v2 = self.rows[-1][0]
        self.mesh.add_face([self.end_cap, v2, v1])

    def __call__(self, u, v):
        return add_vecs(self.coil(v), self.cross_section(u, v))

    def lerp_params(self, param_name, t):
        [a, b] = self.parameters[param_name]
        return lerp(a, b, t)

    def loglerp_params(self, param_name, t):
        [a, b] = self.parameters[param_name]
        return loglerp(a, b, t)

    def coil_shape(self, v):
        phi = self.lerp_params('coil_angle', v) * 2.0 * math.pi
        p = self.loglerp_params('coil_p', v)
        q = self.loglerp_params('coil_q', v)

        return superellipse(phi, p, q)

    def coil(self, v):
        z = self.lerp_params('coil_z', v)
        b = self.loglerp_params('coil_logarithm', v)
        R = self.lerp_params('coil_radius', v)
        radius = R * math.exp(b * v)

        (shape_x, shape_y) = self.coil_shape(v)
        return (radius * shape_x, radius * shape_y, z)

    def cross_section(self, u, v):
        (shape_x, shape_y) = self.coil_shape(v)
        (twist_s, twist_z) = self.twisted(u, v)
        return (twist_s * shape_x, twist_s * shape_y, twist_z)

    def twisted(self, u, v):
        m = self.loglerp_params('cross_section_m', v)
        n = self.loglerp_params('cross_section_n', v)
        delta = self.lerp_params('cross_section_twist', v) * 2.0 * math.pi
        r = self.lerp_params('cross_section_radius', v)
        theta = 2.0 * math.pi * u

        shape = superellipse(theta, m, n)
        return scale(rotate(shape, delta), r)
Ejemplo n.º 2
0
def combine(mesh1, inverted1, mesh2, inverted2, tolerance = 0.000001):
    class FaceRemoveException(Exception):
        pass
    possible_overlaps = list(mesh1.possible_face_collisions(mesh2))
    
    replaced_faces1 = {}
    replaced_faces2 = {}
    print "Mesh1", mesh1.vertices
    print "Mesh2", mesh2.vertices
    print len(possible_overlaps)
    n=40
    m=300
    while possible_overlaps:
        face1, face2 = possible_overlaps.pop()
        assert n > 0
        assert m > 0
        try:
            if replaced_faces1.has_key(face1):
                for new_face1 in replaced_faces1[face1]:
                    possible_overlaps.append((new_face1, face2))
                raise FaceRemoveException
            if replaced_faces2.has_key(face2):
                for new_face in replaced_faces2[face2]:
                    possible_overlaps.append((face1, new_face))
                raise FaceRemoveException
            if face1.normal.cross(face2.normal).magnitude() < tolerance and abs(face1.normal.dot(face1.vertices[0]) - face1.normal.dot(face2.vertices[0])) < tolerance: 
                for vertex1 in face1.vertices:
                    if point_in_face(vertex1, face2, tolerance) and vertex1 not in mesh2.vertices:
                        vertex2 = mesh2.add_vertex(vertex1.x, vertex1.y, vertex1.z)
                        possible_overlaps.append((face1, face2)) #There may be more than one face intersection for this pair of points
                        replaced_faces2[face2] = mesh2.split_face(vertex2, face2)
                        raise FaceRemoveException
                for vertex2 in face2.vertices:
                    if point_in_face(vertex2, face1, tolerance) and vertex2 not in mesh1.vertices:
                        vertex1 = mesh1.add_vertex(vertex2.x, vertex2.y, vertex2.z)
                        possible_overlaps.append((face1, face2)) #There may be more than one face intersection for this pair of points
                        replaced_faces1[face1] = mesh1.split_face(vertex1, face1)
                        raise FaceRemoveException      
        except FaceRemoveException:
            m = m - 1
    possible_overlaps = list(mesh1.possible_face_collisions(mesh2))
    replaced_faces1 = {}
    replaced_faces2 = {}
    print "Mesh1", mesh1.vertices
    print "Mesh2", mesh2.vertices
    print len(possible_overlaps)
    fileio.write_ply(mesh1, "/home/martin/m1.ply")
    fileio.write_ply(mesh2, "/home/martin/m2.ply")
    n=40
    m=300
    while possible_overlaps:
        face1, face2 = possible_overlaps.pop()
        fileio.write_ply(mesh1, "/home/martin/m1.ply")
        fileio.write_ply(mesh2, "/home/martin/m2.ply")
        assert n > 0
        assert m > 0
        try:
            if replaced_faces1.has_key(face1):
                for new_face1 in replaced_faces1[face1]:
                    if replaced_faces2.has_key(face2):
                        for new_face2 in replaced_faces2[face2]:
                            possible_overlaps.append((new_face1, new_face2))
                    else:
                        possible_overlaps.append((new_face1, face2))
                raise FaceRemoveException
            if replaced_faces2.has_key(face2):
                for new_face in replaced_faces2[face2]:
                    possible_overlaps.append((face1, new_face))
                raise FaceRemoveException
            if face1.normal.cross(face2.normal).magnitude() < tolerance and abs(face1.normal.dot(face1.vertices[0]) - face1.normal.dot(face2.vertices[0])) < tolerance: 
              for edge1 in face1.edges:
                for edge2 in face2.edges:
                    try:
                        ip, s1, s2 = line_intersection_and_proportion((edge1.v1, edge1.v2), (edge2.v1, edge2.v2))
                        #print "Lines Cross?", edge1.v1, edge1.v2, edge2.v1, edge2.v2, ip, s1, s2
                        if s1 > tolerance and 1-s1 > tolerance and s2 > tolerance and 1- s2 > tolerance:
                            n = n -1
                            #print "Crossed", edge1, edge2, s1, s2, ip
                            faces1_to_be_replaced = edge1.faces()
                            new_vertex1 = mesh1.add_vertex(ip)
                            new_faces1 = mesh1.split_edge(new_vertex1, edge1)
                            for face1_to_be_replaced in faces1_to_be_replaced:
                                replaced_faces1[face1_to_be_replaced] = new_faces1
                            faces2_to_be_replaced = edge2.faces()
                            new_vertex2 = mesh2.add_vertex(ip)
                            origvol = mesh2.volume()
                            new_faces2 = mesh2.split_edge(new_vertex2, edge2)
                            if abs(origvol - mesh2.volume()) > tolerance:
                                #print ip, s1, s2
                                assert False
                            for face2_to_be_replaced in faces2_to_be_replaced:
                                replaced_faces2[face2_to_be_replaced] = new_faces2
                            print "EDGE SPLIT"
                            raise FaceRemoveException
                    except (ParallelLinesException, LinesDoNotCrossException): 
                        pass  
        except FaceRemoveException:
            m = m - 1
#    possible_overlaps = list(mesh1.possible_face_collisions(mesh2))
#    replaced_faces1 = {}
#    replaced_faces2 = {}
#    while possible_overlaps:
 #       face1, face2 = possible_overlaps.pop()
#        try:
#            if replaced_faces1.has_key(face1):
#                for new_face in replaced_faces1[face1]:
#                    possible_overlaps.append((new_face, face2))
#                raise FaceRemoveException
#            if replaced_faces2.has_key(face2):
#                for new_face in replaced_faces2[face2]:
#                    possible_overlaps.append((face1, new_face))
#                raise FaceRemoveException
#            for edge1 in face1.edges:
#                for edge2 in face2.edges:
#                    try:
#                        ip, s1, s2 = line_intersection_and_proportion((edge1.v1, edge1.v2), (edge2.v1, edge2.v2))
#                        if s1 > tolerance and 1-s1 > tolerance and s2 > tolerance and 1-s2 > tolerance:
#                            print edge1, edge2, s1, s2
#                            faces1_to_be_replaced = edge1.faces()
#                            new_vertex1 = mesh1.add_vertex(ip)
#                            new_faces1 = mesh1.split_edge(new_vertex1, edge1)
#                            for face1_to_be_replaced in faces1_to_be_replaced:
#                                replaced_faces1[face1_to_be_replaced] = new_faces1
#                            faces2_to_be_replaced = edge2.faces()
#                            new_vertex2 = mesh2.add_vertex(ip)
#                            new_faces2 = mesh2.split_edge(new_vertex2, edge2)
#                            for face2_to_be_replaced in faces2_to_be_replaced:
#                                replaced_faces2[face2_to_be_replaced] = new_faces2
#                            raise FaceRemoveException
#                    except ValueError:
#                        pass    
#        except FaceRemoveException:
#            pass
    #fileio.write_stl(mesh1, "/home/martin/m1.ply")
    #fileio.write_stl(mesh2, "/home/martin/m2.ply")
    print "M1V", mesh1.vertices
    print "M1V", mesh1.vertices
    print "M1F", len(mesh1.faces)
    print "M2F", len(mesh2.faces)
    print "M1Vol", mesh1.volume()#Check mesh is closed
    print "M2Vol", mesh2.volume()#Check mesh is closed
    m = Mesh()
    vertex1_map = {}
    for v in mesh1.vertices:
        new_vertex = m.get_vertex(v)
        if new_vertex is None: #Vertex does not exist
            new_vertex = m.add_vertex(v.x, v.y, v.z)
        vertex1_map[v] = new_vertex
    for face in mesh1.faces:
        vertices = [vertex1_map[vertex] for vertex in face.vertices]
        if mesh2.contains_point(face.centroid() + face.normal * tolerance * {True: -1, False: 1}[inverted1]) != (not inverted2):
            if inverted1:
                m.add_triangle_face(vertices[0], vertices[2], vertices[1])
            else:
                m.add_triangle_face(vertices[0], vertices[1], vertices[2])
    vertex2_map = {}
    for v in mesh2.vertices:
        new_vertex = m.get_vertex(v)
        #print "?", m.get_vertex(v), m.get_vertex(v.x, v.y, v.z), v.x, v.y, v.z	
        if new_vertex is None: #Vertex does not exist
            #print "Adding"
            new_vertex = m.add_vertex(v.x, v.y, v.z)
            #print "added"
        vertex2_map[v] = new_vertex
    edge_splits = {}
    for face in mesh2.faces:
        vertices = [vertex2_map[vertex] for vertex in face.vertices]
        if mesh1.contains_point(face.centroid() + face.normal * tolerance * {True: -1, False: 1}[inverted2]) != (not inverted1):
            if inverted2:
                add_splits_and_face(m, vertices[0], vertices[2], vertices[1], edge_splits)      
            else:
                add_splits_and_face(m, vertices[0], vertices[1], vertices[2], edge_splits)
    #clean up verticies
    m.clean()
    
    fileio.write_ply(m, "/home/martin/m3.ply")
    return m
Ejemplo n.º 3
0
def combine(mesh1, inverted1, mesh2, inverted2, tolerance=0.000001):
    class FaceRemoveException(Exception):
        pass

    possible_overlaps = list(mesh1.possible_face_collisions(mesh2))

    replaced_faces1 = {}
    replaced_faces2 = {}
    print "Mesh1", mesh1.vertices
    print "Mesh2", mesh2.vertices
    print len(possible_overlaps)
    n = 40
    m = 300
    while possible_overlaps:
        face1, face2 = possible_overlaps.pop()
        assert n > 0
        assert m > 0
        try:
            if replaced_faces1.has_key(face1):
                for new_face1 in replaced_faces1[face1]:
                    possible_overlaps.append((new_face1, face2))
                raise FaceRemoveException
            if replaced_faces2.has_key(face2):
                for new_face in replaced_faces2[face2]:
                    possible_overlaps.append((face1, new_face))
                raise FaceRemoveException
            if face1.normal.cross(
                    face2.normal).magnitude() < tolerance and abs(
                        face1.normal.dot(face1.vertices[0]) -
                        face1.normal.dot(face2.vertices[0])) < tolerance:
                for vertex1 in face1.vertices:
                    if point_in_face(
                            vertex1, face2,
                            tolerance) and vertex1 not in mesh2.vertices:
                        vertex2 = mesh2.add_vertex(vertex1.x, vertex1.y,
                                                   vertex1.z)
                        possible_overlaps.append(
                            (face1, face2)
                        )  #There may be more than one face intersection for this pair of points
                        replaced_faces2[face2] = mesh2.split_face(
                            vertex2, face2)
                        raise FaceRemoveException
                for vertex2 in face2.vertices:
                    if point_in_face(
                            vertex2, face1,
                            tolerance) and vertex2 not in mesh1.vertices:
                        vertex1 = mesh1.add_vertex(vertex2.x, vertex2.y,
                                                   vertex2.z)
                        possible_overlaps.append(
                            (face1, face2)
                        )  #There may be more than one face intersection for this pair of points
                        replaced_faces1[face1] = mesh1.split_face(
                            vertex1, face1)
                        raise FaceRemoveException
        except FaceRemoveException:
            m = m - 1
    possible_overlaps = list(mesh1.possible_face_collisions(mesh2))
    replaced_faces1 = {}
    replaced_faces2 = {}
    print "Mesh1", mesh1.vertices
    print "Mesh2", mesh2.vertices
    print len(possible_overlaps)
    fileio.write_ply(mesh1, "/home/martin/m1.ply")
    fileio.write_ply(mesh2, "/home/martin/m2.ply")
    n = 40
    m = 300
    while possible_overlaps:
        face1, face2 = possible_overlaps.pop()
        fileio.write_ply(mesh1, "/home/martin/m1.ply")
        fileio.write_ply(mesh2, "/home/martin/m2.ply")
        assert n > 0
        assert m > 0
        try:
            if replaced_faces1.has_key(face1):
                for new_face1 in replaced_faces1[face1]:
                    if replaced_faces2.has_key(face2):
                        for new_face2 in replaced_faces2[face2]:
                            possible_overlaps.append((new_face1, new_face2))
                    else:
                        possible_overlaps.append((new_face1, face2))
                raise FaceRemoveException
            if replaced_faces2.has_key(face2):
                for new_face in replaced_faces2[face2]:
                    possible_overlaps.append((face1, new_face))
                raise FaceRemoveException
            if face1.normal.cross(
                    face2.normal).magnitude() < tolerance and abs(
                        face1.normal.dot(face1.vertices[0]) -
                        face1.normal.dot(face2.vertices[0])) < tolerance:
                for edge1 in face1.edges:
                    for edge2 in face2.edges:
                        try:
                            ip, s1, s2 = line_intersection_and_proportion(
                                (edge1.v1, edge1.v2), (edge2.v1, edge2.v2))
                            #print "Lines Cross?", edge1.v1, edge1.v2, edge2.v1, edge2.v2, ip, s1, s2
                            if s1 > tolerance and 1 - s1 > tolerance and s2 > tolerance and 1 - s2 > tolerance:
                                n = n - 1
                                #print "Crossed", edge1, edge2, s1, s2, ip
                                faces1_to_be_replaced = edge1.faces()
                                new_vertex1 = mesh1.add_vertex(ip)
                                new_faces1 = mesh1.split_edge(
                                    new_vertex1, edge1)
                                for face1_to_be_replaced in faces1_to_be_replaced:
                                    replaced_faces1[
                                        face1_to_be_replaced] = new_faces1
                                faces2_to_be_replaced = edge2.faces()
                                new_vertex2 = mesh2.add_vertex(ip)
                                origvol = mesh2.volume()
                                new_faces2 = mesh2.split_edge(
                                    new_vertex2, edge2)
                                if abs(origvol - mesh2.volume()) > tolerance:
                                    #print ip, s1, s2
                                    assert False
                                for face2_to_be_replaced in faces2_to_be_replaced:
                                    replaced_faces2[
                                        face2_to_be_replaced] = new_faces2
                                print "EDGE SPLIT"
                                raise FaceRemoveException
                        except (ParallelLinesException,
                                LinesDoNotCrossException):
                            pass
        except FaceRemoveException:
            m = m - 1


#    possible_overlaps = list(mesh1.possible_face_collisions(mesh2))
#    replaced_faces1 = {}
#    replaced_faces2 = {}
#    while possible_overlaps:
#       face1, face2 = possible_overlaps.pop()
#        try:
#            if replaced_faces1.has_key(face1):
#                for new_face in replaced_faces1[face1]:
#                    possible_overlaps.append((new_face, face2))
#                raise FaceRemoveException
#            if replaced_faces2.has_key(face2):
#                for new_face in replaced_faces2[face2]:
#                    possible_overlaps.append((face1, new_face))
#                raise FaceRemoveException
#            for edge1 in face1.edges:
#                for edge2 in face2.edges:
#                    try:
#                        ip, s1, s2 = line_intersection_and_proportion((edge1.v1, edge1.v2), (edge2.v1, edge2.v2))
#                        if s1 > tolerance and 1-s1 > tolerance and s2 > tolerance and 1-s2 > tolerance:
#                            print edge1, edge2, s1, s2
#                            faces1_to_be_replaced = edge1.faces()
#                            new_vertex1 = mesh1.add_vertex(ip)
#                            new_faces1 = mesh1.split_edge(new_vertex1, edge1)
#                            for face1_to_be_replaced in faces1_to_be_replaced:
#                                replaced_faces1[face1_to_be_replaced] = new_faces1
#                            faces2_to_be_replaced = edge2.faces()
#                            new_vertex2 = mesh2.add_vertex(ip)
#                            new_faces2 = mesh2.split_edge(new_vertex2, edge2)
#                            for face2_to_be_replaced in faces2_to_be_replaced:
#                                replaced_faces2[face2_to_be_replaced] = new_faces2
#                            raise FaceRemoveException
#                    except ValueError:
#                        pass
#        except FaceRemoveException:
#            pass
#fileio.write_stl(mesh1, "/home/martin/m1.ply")
#fileio.write_stl(mesh2, "/home/martin/m2.ply")
    print "M1V", mesh1.vertices
    print "M1V", mesh1.vertices
    print "M1F", len(mesh1.faces)
    print "M2F", len(mesh2.faces)
    print "M1Vol", mesh1.volume()  #Check mesh is closed
    print "M2Vol", mesh2.volume()  #Check mesh is closed
    m = Mesh()
    vertex1_map = {}
    for v in mesh1.vertices:
        new_vertex = m.get_vertex(v)
        if new_vertex is None:  #Vertex does not exist
            new_vertex = m.add_vertex(v.x, v.y, v.z)
        vertex1_map[v] = new_vertex
    for face in mesh1.faces:
        vertices = [vertex1_map[vertex] for vertex in face.vertices]
        if mesh2.contains_point(face.centroid() + face.normal * tolerance * {
                True: -1,
                False: 1
        }[inverted1]) != (not inverted2):
            if inverted1:
                m.add_triangle_face(vertices[0], vertices[2], vertices[1])
            else:
                m.add_triangle_face(vertices[0], vertices[1], vertices[2])
    vertex2_map = {}
    for v in mesh2.vertices:
        new_vertex = m.get_vertex(v)
        #print "?", m.get_vertex(v), m.get_vertex(v.x, v.y, v.z), v.x, v.y, v.z
        if new_vertex is None:  #Vertex does not exist
            #print "Adding"
            new_vertex = m.add_vertex(v.x, v.y, v.z)
            #print "added"
        vertex2_map[v] = new_vertex
    edge_splits = {}
    for face in mesh2.faces:
        vertices = [vertex2_map[vertex] for vertex in face.vertices]
        if mesh1.contains_point(face.centroid() + face.normal * tolerance * {
                True: -1,
                False: 1
        }[inverted2]) != (not inverted1):
            if inverted2:
                add_splits_and_face(m, vertices[0], vertices[2], vertices[1],
                                    edge_splits)
            else:
                add_splits_and_face(m, vertices[0], vertices[1], vertices[2],
                                    edge_splits)
    #clean up verticies
    m.clean()

    fileio.write_ply(m, "/home/martin/m3.ply")
    return m