Exemplo n.º 1
0
    def fill_holes(self):
        DEBUG = False
        self.time_it = BL_TOOLS.TimeIt()
        BL_DEBUG.clear_marks()
        self.bm.verts.ensure_lookup_table()
        self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()

        boundary_edges = [edge for edge in self.bm.edges if edge.is_boundary]
        print("%d boundary edge founds" % len(boundary_edges))

        self.update_bm()
        self.time_it.stop()
        print("[t] add_geometry(): ", self.time_it)
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))
Exemplo n.º 2
0
    def move_points(plane, terrain):
      
        DEBUG = False
        LIMIT = None
        MIN_FACE_DIST = 10

        BL_DEBUG.clear_marks()

        # build a table with the point and the face_idx, to speed up the thing
        # store the vertex only one time. use raycast to the Z down to check the
        # points, instead closest.
        # use side points, and center

        obj_s=  bpy.data.objects[plane]
        mesh_s = obj_s.data
        obj_t=  bpy.data.objects[terrain]

        BL_DEBUG.clear_marks()

        bm = bmesh.new()
        bm.from_mesh(obj_t.data)
        bm.verts.ensure_lookup_table()
        bm.edges.ensure_lookup_table()
        bm.faces.ensure_lookup_table()

        # here, I can flatten or move the thing
        #for f in  bm.faces:
        #    if f.select:
        #        for v in f.verts:
        #            bm.verts[v.index].co[2] += 5

        verts = []
        mesh_vertex = []
        for v in mesh_s.vertices:
            verts.append(v.index)
            mesh_vertex.append(v)

        current_faces = [f.index for f in bm.faces if f.select]

        LIMIT = None
        pc = 0
        idx = 0
        MESH_VERTEX_LEN = int(len(mesh_vertex)/2)-1

        # select faces & edges to subdivide
        process_point = {}

        for pc in range(MESH_VERTEX_LEN):
            
            # iterate about the number of quads
            
            edges = []
            if pc == 0:
                e_1 = ( mesh_vertex[0], mesh_vertex[1] ) # right
                e_2 = ( mesh_vertex[2], mesh_vertex[3] ) # left
                idx = 1
            elif pc == 1:
                e_1 = ( mesh_vertex[1], mesh_vertex[4] )  # right     
                e_2 = ( mesh_vertex[3], mesh_vertex[5] )  # left edge
                idx += 3
            else:
                e_1 = ( mesh_vertex[idx], mesh_vertex[idx+2] )       # right 
                e_2 = ( mesh_vertex[idx+1], mesh_vertex[idx+3] )     # left edge
                idx += 2

                
            # 0 is the right side
            # 1 is the left side 
            edges = [ e_1, e_2 ]  

            #for e in edges:
            #    BL_DEBUG.set_mark( obj_t.matrix_world @ e[0].co.xyz, kind='CUBE', scale=0.2 )
            #    BL_DEBUG.set_mark( obj_t.matrix_world @ e[1].co.xyz, kind='SPHERE', scale=0.2 )

            # calculate the nearest vertex for each point, get the minimum,
            # and build a face using it
            


            for edge_idx in range(len(edges)):
                edge =edges[edge_idx]       
                # for vertex0, vertex1. Pass the "left/right position"
                near_data = [ BL_FLATTEN.nearest(edge_idx), BL_FLATTEN.nearest(edge_idx) ] 
                bm.faces.ensure_lookup_table()
                for i in range(len(edge)):
                    # was sorround faces
                    for face_idx in current_faces: 
                        face = bm.faces[face_idx]

                        # get only faces for our "side"
                        # note that I use the Plane, not the projected ones.

                        A = obj_s.matrix_world @ edge[0].co
                        B = obj_s.matrix_world @ edge[1].co
                        C = obj_t.matrix_world @ face.calc_center_median()
                        normal_vec = Vector(B-A).cross(Vector(C-A))
                        normal_rl = normal_vec.z
                            
                        if near_data[i].pos == 'LEFT' and normal_rl < 0:
                            #print("badside left: normal: ", normal_rl, near_data[i].pos, idx) 
                            continue
                        if near_data[i].pos == 'RIGHT' and normal_rl > 0:
                            #print("badside right: normal: ", normal_rl, near_data[i].pos, idx) 
                            continue
                        
                        #print("normal: ", normal_rl, near_data[i].pos, idx, face_idx) 

                        # again, plane vs mesh
                        for facevertex in face.verts:
                            vpw = obj_s.matrix_world @ edge[i].co
                            vtw = obj_t.matrix_world @ facevertex.co                     
                            dist = (vpw.xyz - vtw.xyz).length

                            if dist < near_data[i].distance:
                                near_data[i].face = face_idx
                                near_data[i].vertex = facevertex.index
                                near_data[i].distance = dist
                                near_data[i].point = edge[i].index
                                # calculate the normal (first case, the we do the scond)

                    
                # select what vertex is near     
                near = 0 
                if near_data[1].distance < near_data[0].distance:
                    near = 1
                
                # now, build the array to work with. Store the points in the plane,
                # data about face,vertex and distance.
               
                process_point[near_data[i].point] =  (near_data[near].face, near_data[near].vertex, near_data[near].distance)
 
                
            #if idx >= 8: break
            if LIMIT and pc >= LIMIT:
                break

        # I get all the "nearest" vertex
        # look in current_faces faces all the edges, and 
        bm.verts.ensure_lookup_table()
        bm.faces.ensure_lookup_table()



        for point_idx in process_point.keys():
            
            face_idx, vertex_idx, distance = process_point[point_idx]
            #
            # calculate how much I have to move the face, to put it "near the point"
            # "far" are moved less than "near". use a vector to move the face.
            #

            for v in bm.faces[face_idx].verts:
                vpw = obj_s.matrix_world @ mesh_s.vertices[point_idx].co
                vtw = obj_t.matrix_world @ v.co
                dist = (vpw.xy - vtw.xy).length
                height = vpw.z - vtw.z

                # some tunning in this parameters
                # too high and you break the geometry
                
                delta = dist - (dist *0.8)
                deltah = height*0.1

                direction = delta * (vpw.xy - vtw.xy)
                direction.resize_3d()
                direction = delta * direction.normalized()
                direction += Vector((0,0,deltah))
                local_dir = obj_t.matrix_world.inverted() @ direction

                print(distance, dist, delta, deltah, local_dir, direction)
                bmesh.ops.translate(bm, verts=[v], vec = direction)

        ##############################################################
        #
        # End
        # update the meshes
        # free the bmesh
        # 
        ##############################################################  

        bm.calc_loop_triangles()
        bm.to_mesh(obj_t.data)
        obj_t.data.update()  
        bm.free()
  
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))        
Exemplo n.º 3
0
    def subdivide_nearest_faces(plane, terrain):
      
        DEBUG = False
        LIMIT = None
        MIN_FACE_DIST = 10

        BL_DEBUG.clear_marks()

        # build a table with the point and the face_idx, to speed up the thing
        # store the vertex only one time. use raycast to the Z down to check the
        # points, instead closest.
        # use side points, and center

        obj_s=  bpy.data.objects[plane]
        mesh_s = obj_s.data
        obj_t=  bpy.data.objects[terrain]

        BL_DEBUG.clear_marks()

        bm = bmesh.new()
        bm.from_mesh(obj_t.data)
        bm.verts.ensure_lookup_table()
        bm.edges.ensure_lookup_table()
        bm.faces.ensure_lookup_table()

        # here, I can flatten or move the thing
        #for f in  bm.faces:
        #    if f.select:
        #        for v in f.verts:
        #            bm.verts[v.index].co[2] += 5

        verts = []
        mesh_vertex = []
        for v in mesh_s.vertices:
            verts.append(v.index)
            mesh_vertex.append(v)

        
        current_faces = [f.index for f in bm.faces if f.select]

        LIMIT = None
        pc = 0
        idx = 0
        MESH_VERTEX_LEN = int(len(mesh_vertex)/2)-1

        # select faces & edges to subdivide
        process_vertex = []

        for pc in range(MESH_VERTEX_LEN):
            
            # iterate about the number of quads
            
            edges = []
            if pc == 0:
                e_1 = ( mesh_vertex[0], mesh_vertex[1] ) # right
                e_2 = ( mesh_vertex[2], mesh_vertex[3] ) # left
                idx = 1
            elif pc == 1:
                e_1 = ( mesh_vertex[1], mesh_vertex[4] )  # right     
                e_2 = ( mesh_vertex[3], mesh_vertex[5] )  # left edge
                idx += 3
            else:
                e_1 = ( mesh_vertex[idx], mesh_vertex[idx+2] )       # right 
                e_2 = ( mesh_vertex[idx+1], mesh_vertex[idx+3] )     # left edge
                idx += 2

                
            # 0 is the right side
            # 1 is the left side 
            edges = [ e_1, e_2 ]  

            #for e in edges:
            #    BL_DEBUG.set_mark( obj_t.matrix_world @ e[0].co.xyz, kind='CUBE', scale=0.2 )
            #    BL_DEBUG.set_mark( obj_t.matrix_world @ e[1].co.xyz, kind='SPHERE', scale=0.2 )

            # calculate the nearest vertex for each point, get the minimum,
            # and build a face using it
            


            for edge_idx in range(len(edges)):
                edge =edges[edge_idx]       
                # for vertex0, vertex1. Pass the "left/right position"
                near_data = [ BL_FLATTEN.nearest(edge_idx), BL_FLATTEN.nearest(edge_idx) ] 
                bm.faces.ensure_lookup_table()
                for i in range(len(edge)):
                    # was sorround faces
                    for face_idx in current_faces: 
                        face = bm.faces[face_idx]

                        # get only faces for our "side"
                        # note that I use the Plane, not the projected ones.

                        A = obj_s.matrix_world @ edge[0].co
                        B = obj_s.matrix_world @ edge[1].co
                        C = obj_t.matrix_world @ face.calc_center_median()
                        normal_vec = Vector(B-A).cross(Vector(C-A))
                        normal_rl = normal_vec.z
                            
                        if near_data[i].pos == 'LEFT' and normal_rl < 0:
                            #print("badside left: normal: ", normal_rl, near_data[i].pos, idx) 
                            continue
                        if near_data[i].pos == 'RIGHT' and normal_rl > 0:
                            #print("badside right: normal: ", normal_rl, near_data[i].pos, idx) 
                            continue
                        
                        #print("normal: ", normal_rl, near_data[i].pos, idx, face_idx) 

                        # again, plane vs mesh
                        for facevertex in face.verts:
                            vpw = obj_s.matrix_world @ edge[i].co
                            vtw = obj_t.matrix_world @ facevertex.co                     
                            dist = (vpw.xyz - vtw.xyz).length

                            if dist < near_data[i].distance:
                                near_data[i].face = face_idx
                                near_data[i].vertex = facevertex.index
                                near_data[i].distance = dist
                                #near_data[i].edges = BL_FLATTEN.face_edges_by_vert(face, facevertex) 
                                # calculate the normal (first case, the we do the scond)

                    
                # select what vertex is near     
                near = 0 
                if near_data[1].distance < near_data[0].distance:
                    near = 1
                
                # now, build the array to work with. Store unique faces
                
               
              
                
                process_vertex.append(near_data[near].vertex)
                # if not vertex_idx in process_faces.keys():                    
                #     process_vertex[face_idx] =  [ vertex_idx ]
                # else:
                #     # now, store vertex and edge info.
                #     if not vertex_idx in process_faces[face_idx]:
                #         process_faces[face_idx].append(vertex_idx)

                #     else:
                #         # vertex exist on face, so test the edge.
                #         for edge_idx in near_data[near].edges:
                #             if not edge_idx in process_faces[face_idx][vertex_idx]:
                #                 process_faces[face_idx][vertex_idx].append(edge_idx)
                #             else:
                #                 # duplicate.
                #                 pass

                #BL_DEBUG.set_mark( obj_t.matrix_world @ bm.faces[near_data[near].face].calc_center_median().xyz )
                #BL_DEBUG.set_mark( obj_t.matrix_world @ bm.verts[near_data[near].vertex].co.xyz, kind='PLAIN_AXES')

                # here, I want only the face data, and vertex.
                # create a funky face here.
                
            #if idx >= 8: break
            if LIMIT and pc >= LIMIT:
                break

        # I get all the "nearest" vertex
        # look in current_faces faces all the edges, and 
        bm.faces.ensure_lookup_table()

        process_vertex = list(set(process_vertex))
        active_faces = [ bm.faces[i] for i in current_faces ]
        active_edges = [ ]
        for f in active_faces:
            active_edges += f.edges

        for edge in active_edges:
            # check that all the vertex are in process_vertex.
            vertex_inside = 0
            for v in edge.verts:
                if v.index in process_vertex:
                    vertex_inside += 1

            if vertex_inside == len(edge.verts):
                bmesh.ops.subdivide_edges(bm, edges=[edge], use_grid_fill=False, cuts=1)

        ##############################################################
        #
        # End
        # update the meshes
        # free the bmesh
        # 
        ##############################################################  

        bm.calc_loop_triangles()
        bm.to_mesh(obj_t.data)
        obj_t.data.update()  
        bm.free()
  
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))    
Exemplo n.º 4
0
    def add_geometry(plane, terrain):
      
        DEBUG = False
        LIMIT = None
        MIN_FACE_DIST = 10

        BL_DEBUG.clear_marks()

        # build a table with the point and the face_idx, to speed up the thing
        # store the vertex only one time. use raycast to the Z down to check the
        # points, instead closest.
        # use side points, and center

        obj_s=  bpy.data.objects[plane]
        mesh_s = obj_s.data
        obj_t=  bpy.data.objects[terrain]

        BL_DEBUG.clear_marks()

        bm = bmesh.new()
        bm.from_mesh(obj_t.data)
        bm.verts.ensure_lookup_table()
        bm.edges.ensure_lookup_table()
        bm.faces.ensure_lookup_table()

        # here, I can flatten or move the thing
        #for f in  bm.faces:
        #    if f.select:
        #        for v in f.verts:
        #            bm.verts[v.index].co[2] += 5

        verts = []
        for v in mesh_s.vertices:
            verts.append(v.index)

        mesh_vertex = []
        for v_idx in verts:
            world_point = obj_s.matrix_world @ obj_s.data.vertices[v_idx].co
            local_point = obj_t.matrix_world.inverted() @ world_point

            #set_mark( obj_s.matrix_world @ obj_s.data.vertices[v_idx].co, kind='PLAIN_AXES', scale=0.2 )
            #set_mark( obj_t.matrix_world @ local_point,  scale=0.2 )
            
            vnew = bm.verts.new( local_point )
            mesh_vertex.append(vnew)

        # update the index of the new created verts. WTF ???
        bm.verts.index_update()
        bm.verts.ensure_lookup_table()

        current_faces = [f.index for f in bm.faces if f.select]

        LIMIT = None
        pc = 0
        idx = 0
        GEOM_TO_DO = []
        MESH_VERTEX_LEN = int(len(mesh_vertex)/2)-1
        for pc in range(MESH_VERTEX_LEN):
            
            # iterate about the number of quads
            
            edges = []
            if pc == 0:
                e_1 = ( mesh_vertex[0], mesh_vertex[1] ) # right
                e_2 = ( mesh_vertex[2], mesh_vertex[3] ) # left
                idx = 1
            elif pc == 1:
                e_1 = ( mesh_vertex[1], mesh_vertex[4] )  # right     
                e_2 = ( mesh_vertex[3], mesh_vertex[5] )  # left edge
                idx += 3
            else:
                e_1 = ( mesh_vertex[idx], mesh_vertex[idx+2] )       # right 
                e_2 = ( mesh_vertex[idx+1], mesh_vertex[idx+3] )     # left edge
                idx += 2

                
            # 0 is the right side
            # 1 is the left side 
            edges = [ e_1, e_2 ]  

            #for e in edges:
            #    BL_DEBUG.set_mark( obj_t.matrix_world @ e[0].co.xyz, kind='CUBE', scale=0.2 )
            #    BL_DEBUG.set_mark( obj_t.matrix_world @ e[1].co.xyz, kind='SPHERE', scale=0.2 )

            # calculate the nearest vertex for each point, get the minimum,
            # and build a face using it
            
            for edge_idx in range(len(edges)):
                edge =edges[edge_idx]       
                # for vertex0, vertex1. Pass the "left/right position"
                near_data = [ BL_FLATTEN.nearest(edge_idx), BL_FLATTEN.nearest(edge_idx) ] 
                bm.faces.ensure_lookup_table()
                for i in range(len(edge)):
                    # was sorround faces
                    for face_idx in current_faces: 
                        face = bm.faces[face_idx]

                        # get only faces for our "side"
                        A = obj_t.matrix_world @ edge[0].co
                        B = obj_t.matrix_world @ edge[1].co
                        C = obj_t.matrix_world @ face.calc_center_median()
                        normal_vec = Vector(B-A).cross(Vector(C-A))
                        normal_rl = normal_vec.z
                            
                        if near_data[i].pos == 'LEFT' and normal_rl < 0:
                            #print("badside left: normal: ", normal_rl, near_data[i].pos, idx) 
                            continue
                        if near_data[i].pos == 'RIGHT' and normal_rl > 0:
                            #print("badside right: normal: ", normal_rl, near_data[i].pos, idx) 
                            continue
                        
                        #print("normal: ", normal_rl, near_data[i].pos, idx, face_idx) 

                        for facevertex in face.verts:
                            vpw = obj_t.matrix_world @ edge[i].co
                            vtw = obj_t.matrix_world @ facevertex.co                     
                            dist = (vpw.xyz - vtw.xyz).length

                            if dist < near_data[i].distance:
                                near_data[i].face = face_idx
                                near_data[i].vertex = facevertex.index
                                near_data[i].distance = dist

                                # calculate the normal (first case, the we do the scond)

                    
                # select what vertex is near     
                near = 0 
                if near_data[1].distance < near_data[0].distance:
                    near = 1
                print(near_data)

                #BL_DEBUG.set_mark( obj_t.matrix_world @ bm.faces[near_data[near].face].calc_center_median().xyz )
                #BL_DEBUG.set_mark( obj_t.matrix_world @ bm.verts[near_data[near].vertex].co.xyz, kind='PLAIN_AXES')

                # create a funky face here.
                if True:
                    if near_data[near].face != None:

                        new_face = [edge[0], edge[1], bm.verts[near_data[near].vertex]]
                        GEOM_TO_DO.append(new_face)
                
                # if first, or last, join vertex to end the cap
                
            if pc == 0 or pc == (MESH_VERTEX_LEN-1):
                
                if pc == 0:
                    # use first
                    edge_cap= [  edges[0][0], edges[1][0] ] # edge from right to left
                else:
                    # use last
                    edge_cap= [  edges[0][1], edges[1][1] ] # edge from right to left
                bmesh.ops.contextual_create(bm, geom= edge_cap)
                bm.edges.index_update()
                
            #if idx >= 8: break
            if LIMIT and pc >= LIMIT:
                break
            
        ## do the geom
        for new_face in GEOM_TO_DO:
            #print(new_face)
            #print(near)
            newf=bmesh.ops.contextual_create(bm, geom= new_face)
            bm.faces.index_update()
            bm.faces.ensure_lookup_table()
            
            for f in newf['faces']:
                if f.normal.z < 0:
                    bm.faces[f.index].normal_flip()        

        ##############################################################
        #
        # End
        # update the meshes
        # free the bmesh
        # 
        ##############################################################  

        bm.calc_loop_triangles()
        bm.to_mesh(obj_t.data)
        obj_t.data.update()  
        bm.free()
  
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))
Exemplo n.º 5
0
    def extend_terrain(plane, terrain):
        """try to flatten a terrain, using the plane as reference plane must have ALL modifiers APPLIED"""

        EXTEND_TERRAIN = True
        TRIANGULATE = True
        EXTEND_DELETE_SELECTION = False

        DEBUG = False
        LIMIT = None
        MIN_FACE_DIST = 10

        BL_DEBUG.clear_marks()

        # build a table with the point and the face_idx, to speed up the thing
        # store the vertex only one time. use raycast to the Z down to check the
        # points, instead closest.
        # use side points, and center

        obj_s=  bpy.data.objects[plane]
        obj_t=  bpy.data.objects[terrain]
        vertices_to_raycast = BL_FLATTEN.plane_to_vertex(plane)

        point_data = BL_FLATTEN.get_raycast(plane, terrain, 
                                    vertices = vertices_to_raycast,
                                    DEBUG=DEBUG, LIMIT=LIMIT)
        
        # at this point XD point_data has 
        # terrain_up/down, face_index, point, location)

        BL_DEBUG.clear_marks()

        bm = bmesh.new()
        bm.from_mesh(obj_t.data)
        bm.verts.ensure_lookup_table()
        bm.edges.ensure_lookup_table()
        bm.faces.ensure_lookup_table()
        
        # unselect all
        for face in bm.faces: face.select = False
        for vert in bm.verts: vert.select = False
        for edge in bm.edges: edge.select = False

        # select faces tracked
  
        for point in point_data:
            terrain_down, index, point, location = point
            bm.faces[index].select = True

        # extend the faces
        # leave faces selected to process the
        # boundaries if needed

        #sel_verts = [v for v in bm.verts if v.select]
        #sel_edges = [e for e in bm.edges if e.select]
        sel_faces = [f for f in bm.faces if f.select]
        #geom = sel_verts + sel_edges + sel_faces
        geom = sel_faces
        
        if EXTEND_TERRAIN:
            ret_geom =  bmesh.ops.region_extend(bm, geom=geom,use_faces=True, use_face_step=False,use_contract=False)
            for f in ret_geom['geom']:
                if isinstance(f, bmesh.types.BMFace):
                    f.select = True

        if False:
            # subdivide too soon.
            sel_faces = [f for f in bm.faces if f.select]
            face_edges = []
            for f in sel_faces:
                for e in f.edges:
                    face_edges.append(e.index)
            face_edges = list(set(face_edges))
            face_edges_geom = [bm.edges[i] for i in face_edges]
            ret = bmesh.ops.subdivide_edges(bm, edges=face_edges_geom, cuts=2, use_grid_fill=True)
            for f in ret['geom']:
                if isinstance(f, bmesh.types.BMFace):
                    f.select = True

        if True:
            #triangulate
            geom = [f for f in bm.faces if f.select]
            ret_trig = bmesh.ops.triangulate(bm, faces=geom)        
            # select the new created triangles

            for f in ret_trig['faces']:
                    f.select = True
               


        # 0. at this point, faces are triangulated, and selected
 
        ##############################################################
        #
        # 1. delete the faces recalculate again the faces
        # this version only deletes the nearest faces from the 
        # road. Maybe it's a little narrow
        # 
        ##############################################################
        
        bm.calc_loop_triangles()
        bm.to_mesh(obj_t.data)
        obj_t.data.update()  

        #bm.verts.ensure_lookup_table()
        #bm.edges.ensure_lookup_table()
        bm.faces.ensure_lookup_table()
        
        #        
        # I have to CHANGE to OBJECT in order to keep working on that
        # and update the structure. After change, return to edit and
        # keep working, it works.
        # 
        bpy.ops.object.mode_set(mode = 'OBJECT')                 
        bpy.ops.object.mode_set(mode = 'EDIT')                 
                

        point_data = BL_FLATTEN.get_raycast(plane, terrain, 
                                    vertices = vertices_to_raycast,
                                    DEBUG=DEBUG, LIMIT=LIMIT)
        
        # at this point XD point_data has 
        # terrain_up/down, face_index, point, location)
        
        BL_DEBUG.clear_marks()

        faces_to_delete = {}
        
        selected_faces = [f for f in bm.faces if f.select]
        for f in bm.faces: f.select = False


        for item in point_data:
            terrain_down, index, point, location = item
            #print(terrain_down,index, point, location)
            #BL_DEBUG.set_mark( obj_t.matrix_world @ location.xyz, kind="PLAIN_AXES" )

            if index not in faces_to_delete.keys():
                faces_to_delete[index] = bm.faces[index]

            if True:
                # this calc takes TOO much in compute
                # select the bounding faces.
                local_faces =  bmesh.ops.region_extend(
                    bm, 
                    geom=[bm.faces[index]],
                    use_faces=True, 
                    use_face_step=False,
                    use_contract=False
                )

                # for each selected face, calculate the distance to the road point,
                # and mark for removal all the faces that meets the requerimient
                # distance = 10m
                for f in local_faces['geom']:
                    if isinstance(f, bmesh.types.BMFace) and f.index not in faces_to_delete.keys():
                        center = BL_FLATTEN.DummyVector(f.calc_center_median())
                        #for fv in f.verts:
                        for fv in [center]:
                            vpw = obj_s.matrix_world @ point.co
                            vtw = obj_t.matrix_world @ fv.co
                            dist = (vpw.xy - vtw.xy).length
                            if dist < MIN_FACE_DIST:
                                print("Face too near: ",f.index,dist)
                                faces_to_delete[f.index] = bm.faces[f.index]

        for f in selected_faces: f.select = True

        # extend the selection for faces to be removed.

        EXTEND_DELETE_SELECTION = False
        if EXTEND_DELETE_SELECTION:

            for face in bm.faces: face.select = False
 
            for f in faces_to_delete.keys():
                bm.faces[f].select = True        

            #sel_verts = [v for v in bm.verts if v.select]
            #sel_edges = [e for e in bm.edges if e.select]
            sel_faces = [f for f in bm.faces if f.select]
            geom = sel_faces

            ret_geom =  bmesh.ops.region_extend(bm, geom=geom,use_faces=True, use_face_step=False,use_contract=False)
            for f in ret_geom['geom']:
                if isinstance(f, bmesh.types.BMFace):
                    faces_to_delete[f.index] = bm.faces[f.index]


        # delete the result faces        

        faces_to_delete = list(faces_to_delete.values())
        deleted_geom_edges = []
        for f in faces_to_delete:
            deleted_geom_edges += [e for e in f.edges]

        bmesh.ops.delete(bm, geom=faces_to_delete, context='FACES_KEEP_BOUNDARY') # FACES_ONLY

        if True:
            # subdivide existing edges
            keep_edges = []
            for edge in deleted_geom_edges:
                if edge.is_valid:
                    keep_edges.append(edge)

            new_edges = []
            geom_created = bmesh.ops.subdivide_edges(bm, edges=keep_edges, cuts=1, use_grid_fill=False)
            for item in geom_created['geom_split']:
                if isinstance(item, bmesh.types.BMEdge):
                    #item.select = True
                    #print(item.index)
                    new_edges.append(item)

        ##############################################################
        #
        # End
        # update the meshes
        # free the bmesh
        # 
        ##############################################################  

        bm.calc_loop_triangles()
        bm.to_mesh(obj_t.data)
        obj_t.data.update()  
        bm.free()
  
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))
Exemplo n.º 6
0
    def do_holes(self):
        "get the plane, generate the info to raycast in the grid, select the matching faces"
        
        self.time_it = BL_TOOLS.TimeIt()

        EXTEND_SELECTION = True
        TRIANGULATE_FACES = False # True
        SUBDIVIDE_INNER_FACES = False
        EXTEND_DELETE_SELECTION = False
        SUBDIVIDE_INNER_EDGES = True
        CALCULATE_NEAR_FACES = True
        MIN_FACE_DIST = 3

        BL_DEBUG.clear_marks()

        # at this point XD point_data has 
        # terrain_up/down, face_index, point, location)
              
        self.unselect_all()

        self.selected_faces = []
        # select faces tracked
        for point in self.raycast_points:
            terrain_down, index, point, location = point
            self.bm.faces[index].select = True
            if self.bm.faces[index] not in self.selected_faces:
                self.selected_faces.append(self.bm.faces[index])
        
        if EXTEND_SELECTION:
            ret_geom =  bmesh.ops.region_extend(self.bm, 
                geom=self.selected_faces,
                use_faces=True, 
                use_face_step=False,
                use_contract=False)
            
            for f in ret_geom['geom']:
                if isinstance(f, bmesh.types.BMFace):
                    f.select = True
                    self.selected_faces.append(f)

        if SUBDIVIDE_INNER_FACES:
            # subdivide the inner faces
            #el_faces = [f for f in self.bm.faces if f.select]
            face_edges = []
            for f in self.selected_faces:
                for e in f.edges:
                    face_edges.append(e.index)
            face_edges = list(set(face_edges))
            face_edges_geom = [self.bm.edges[i] for i in face_edges]
            ret = bmesh.ops.subdivide_edges(self.bm, edges=face_edges_geom, cuts=2, use_grid_fill=True)
            for f in ret['geom']:
                if isinstance(f, bmesh.types.BMFace):
                    f.select = True
                    self.selected_faces.append(f)


        if TRIANGULATE_FACES:
            #triangulate
            geom = [f for f in self.bm.faces if f.select]
            ret_trig = bmesh.ops.triangulate(self.bm, faces=geom)        
            # select the new created triangles

            for f in ret_trig['faces']:
                    f.select = True
                    self.selected_faces.append(f)
               

        # 0. at this point, faces are triangulated, and selected
 
        ##############################################################
        #
        # 1. delete the faces recalculate again the faces
        # this version only deletes the nearest faces from the 
        # road. Maybe it's a little narrow
        # 
        ##############################################################
   
        self.update_bm()

        #self.bm.verts.ensure_lookup_table()
        #self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()
        
        #        
        # I have to CHANGE to OBJECT in order to keep working on that
        # and update the structure. After change, return to edit and
        # keep working, it works.
        # 
              
                

        # after triangulate, or adding more faces, there's a need of recalculate again the affected
        # faces to make the hole

        self.raycast_points =  BL_TOOLS.get_raycast(self.plane, self.terrain, 
                                    vertices = self.plane_points,
                                    DEBUG=self.DEBUG, LIMIT=self.LIMIT)
        
        # at this point XD point_data has 
        # terrain_up/down, face_index, point, location)
        
        BL_DEBUG.clear_marks()

        faces_to_delete = {}

        for item in self.raycast_points:
            terrain_down, index, point, location = item
            #print(terrain_down,index, point, location)
            #BL_DEBUG.set_mark( obj_t.matrix_world @ location.xyz, kind="PLAIN_AXES" )

            if index not in faces_to_delete.keys():
                faces_to_delete[index] = self.bm.faces[index]

        if EXTEND_DELETE_SELECTION:

            for face in self.bm.faces: face.select = False
 
            for f in faces_to_delete.keys():
                self.bm.faces[f].select = True        

            #sel_verts = [v for v in self.bm.verts if v.select]
            #sel_edges = [e for e in self.bm.edges if e.select]
            selected_faces_local = [f for f in self.bm.faces if f.select]
            geom = selected_faces_local

            ret_geom =  bmesh.ops.region_extend(self.bm, 
                        geom=selected_faces_local,
                        use_faces=True, 
                        use_face_step=False,
                        use_contract=False)

            for f in ret_geom['geom']:
                if isinstance(f, bmesh.types.BMFace):
                    faces_to_delete[f.index] = self.bm.faces[f.index]


        # delete the result faces        

        faces_to_delete = list(faces_to_delete.values())
        deleted_geom_edges = []
        for f in faces_to_delete:
            deleted_geom_edges += [e for e in f.edges]

        bmesh.ops.delete(self.bm, geom=faces_to_delete, context='FACES_KEEP_BOUNDARY') # FACES_ONLY

        # remove deleted faces from the selected container
        #temp_faces = [f for f in self.selected_faces if f.is_valid]
        #self.selected_faces = temp_faces
        

        # this creates a subdivision of the inner vertex.
        if SUBDIVIDE_INNER_EDGES:
            # subdivide existing edges
            keep_edges = []
            for edge in deleted_geom_edges:
                if edge.is_valid:
                    keep_edges.append(edge)

            self.inner_edges = []
            print("Inner edges: %d" % (len(keep_edges)*2))

            geom_created = bmesh.ops.subdivide_edges(self.bm, edges=keep_edges, cuts=1, use_grid_fill=True)
            for item in geom_created['geom_split']:
                if isinstance(item, bmesh.types.BMVert):
                    pass
                    #item.select = True
                    #print(item.index)
                    #self.inner_edges.append(item)                
                if isinstance(item, bmesh.types.BMEdge):
                    #item.select = True
                    #print(item.index)
                    self.inner_edges.append(item)
                if isinstance(item, bmesh.types.BMFace):
                    #item.select = True
                    print(item.index)
                    item.select = True
                    self.selected_faces.append(item)
           

            print("Inner edges Subdivide: %d" % (len(self.inner_edges)*2) )

        self.update_bm()

        # create a KD tree for faces. add the center, and get only faces that are "near" in radious

        if CALCULATE_NEAR_FACES:

            valid_faces = [face for face in self.selected_faces if face.is_valid]
            kd = kdtree.KDTree(len(valid_faces))
            for face in valid_faces:
                kd.insert(face.calc_center_median(), face.index)
            kd.balance()

            faces_to_delete = {}
            verts_to_delete = {}
            edges_to_delete = {}
            self.bm.faces.ensure_lookup_table()
            self.bm.verts.ensure_lookup_table()
            self.bm.edges.ensure_lookup_table()

            for item in self.raycast_points:
                terrain_down, index, point, location = item
                
                local_faces = []
                local_point = self.plane_to_terrain_point(point.co)
           
                for (co, index, dist) in kd.find_range(local_point, 200):
                    #print("face_local", index)
                    local_faces.append(self.bm.faces[index])

                for f in local_faces:
                    # check for deleted faces!
                    if f.is_valid and f.index not in faces_to_delete.keys():
                        #center = BL_FLATTEN.DummyVector(f.calc_center_median())
                        for fv in f.verts:
                        #for fv in [center]:
                            vpw = self.obj_s.matrix_world @ point.co
                            vtw = self.obj_t.matrix_world @ fv.co
                            dist = (vpw.xy - vtw.xy).length
                            if dist < MIN_FACE_DIST:
                                #print("Face too near: ",f.index,dist)
                                faces_to_delete[f.index] = self.bm.faces[f.index]        
                                for e in f.edges:
                                    edges_to_delete[e.index] = self.bm.edges[e.index]
                                for v in f.verts:
                                    verts_to_delete[v.index] = self.bm.verts[v.index]

            faces_to_delete = list(faces_to_delete.values())
            verts_to_delete = list(verts_to_delete.values())
            edges_to_delete = list(edges_to_delete.values())
            # FACES_ONLY
            bmesh.ops.delete(self.bm, geom=verts_to_delete + edges_to_delete + faces_to_delete, context='FACES') 

        self.update_bm()

        # now, just select the faces that are not select, but are in the edges.
        # also select all the vertex in the keep edges that are not selected by default.

        for e in self.inner_edges:
            if not e.is_valid:
                continue
            for v in e.verts: 
                if not v.is_valid: 
                    continue
                v.select = True
                for f in v.link_faces:
                    f.select = True
                    if f not in self.selected_faces:
                        self.selected_faces.append(f)

        # select vertex that are in a boundary (internal)
        self.selected_vertex = []
        for e in self.bm.edges:
            if e.is_valid and e.is_boundary:
                for v in e.verts:
                    self.selected_vertex.append(v)

        ##############################################################
        #
        # End
        # update the meshes
        # 
        ##############################################################  

        self.time_it.stop()
        self.update_bm()

        print("[t] do_holes(): ", self.time_it)

        
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))        
Exemplo n.º 7
0
    def add_geometry_edge(self):

        "try to match near edges"

        def edge_median(edge):
                v0,v1 = edge.verts
                median = v0.co + ((v0.co-v1.co)/2.0)
                return(median)

        def nearest_points(kd, edge, v0, side, Nitems=7):
            nearest = []
            for (co, index, dist) in kd.find_n(v0, Nitems):
                # calculate normals
                A = self.obj_t.matrix_world @ edge[0].co
                B = self.obj_t.matrix_world @ edge[1].co
                C = self.obj_t.matrix_world @ co
                normal_vec = Vector(B-A).cross(Vector(C-A))
                normal_rl = normal_vec.z
                if normal_rl < 0.0 and side.upper() == 'RIGHT':
                    nearest.append( (co, index, dist) )
                if normal_rl > 0.0 and side.upper() == 'LEFT':
                    nearest.append( (co, index, dist) )
            return(nearest)

        def nearest_edge(kd, edge, side, Nitems=7):
            
            nearest = []
            median = edge_median(edge)

            for (co, index, dist) in kd.find_n(self.obj_t.matrix_world @ median, Nitems):
                # calculate normals
                A = self.obj_t.matrix_world @ edge.verts[0].co
                B = self.obj_t.matrix_world @ edge.verts[1].co
                C = self.obj_t.matrix_world @ co
                normal_vec = Vector(B-A).cross(Vector(C-A))
                normal_rl = normal_vec.z
                if normal_rl < 0.0 and side.upper() == 'RIGHT':
                    nearest.append( (co, index, dist) )
                if normal_rl > 0.0 and side.upper() == 'LEFT':
                    nearest.append( (co, index, dist) )
            return(nearest)

        DEBUG = False
        self.time_it = BL_TOOLS.TimeIt()
        BL_DEBUG.clear_marks()
        self.bm.verts.ensure_lookup_table()
        self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()
        
        # create a kd tree with the median edge positions.

        median_edges = []
        for edge in self.inner_edges:
            if edge.is_valid and edge.is_boundary:
                median = edge_median(edge)
                median_edges.append( (median, edge.index) )
        
        kd = kdtree.KDTree(len(median_edges))
        for median,idx in median_edges:
            kd.insert(median, idx)
        kd.balance()

        # iterate my vertex, and find the nearest point my vertex

        side_keys = { 0: 'right', 1: 'left', 'right': 0, 'left': 1}
        
        count = 0
        for plane in self.mesh_vertex:
            print("plane", plane)
            nearest = {}
            # calculate the nearest point for each point, for each side
            for i in range(len(plane)):
                if i == 0:
                    #right ARROWS->CUBES
                    kind = 'ARROWS'
                else:
                    #left AXES->SPHERES
                    kind = 'PLAIN_AXES'
          

                #nearest[side_keys[i]] = [   
                #    nearest_points(kd, plane[i], self.obj_t.matrix_world @ plane[i][0].co, side_keys[i]),
                #    nearest_points(kd, plane[i], self.obj_t.matrix_world @ plane[i][1].co, side_keys[i]) 
                #]
                
                # create the working edge
                edge = [ plane[i][0], plane[i][1] ] 
                

                ret_geom = bmesh.ops.contextual_create(self.bm, geom= edge)
                self.bm.edges.index_update()
                self.update_bm()
                for f in ret_geom['edges']:
                    if isinstance(f, bmesh.types.BMEdge):
                        edge = f

                median = edge_median(edge)
                BL_DEBUG.set_mark(self.obj_t.matrix_world @ median,kind='CUBE') ## mesh edge

                n_edge = nearest_edge(kd, edge, side_keys[i])

                
              
                # build the face, rebuild the tree
                co,idx,_ = n_edge[0]
                self.bm.verts.ensure_lookup_table()
                self.bm.edges.ensure_lookup_table()
                self.bm.faces.ensure_lookup_table()

                BL_DEBUG.set_mark(self.obj_t.matrix_world @ co,kind='SPHERE') ## found edge



                #ret_geom = bmesh.ops.contextual_create(self.bm, geom= [edge, self.bm.edges[idx]])
                self.bm.edges.index_update()
                self.update_bm()
                # remove the edge from the table.

                edges_tmp = []
                for edge in self.inner_edges:
                    if edge.is_valid and edge.index != idx:
                        edges_tmp.append(edge)

                self.inner_edges = edges_tmp
                median_edges = []
                for edge in self.inner_edges:
                    if edge.is_valid and edge.is_boundary:
                        median = edge_median(edge)
                        median_edges.append( (median, edge.index) )
                
                kd = kdtree.KDTree(len(median_edges))
                for median,idx in median_edges:
                    kd.insert(median, idx)
                kd.balance()                
        
            # do just ones
            count +=1
            if count >=1:
                break



      # update the index of the new created verts. WTF ???
        self.update_bm()
        self.time_it.stop()
        print("[t] add_geometry_edges(): ", self.time_it)
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))
Exemplo n.º 8
0
    def add_geometry(self):
        
        DEBUG = False
        self.time_it = BL_TOOLS.TimeIt()
        BL_DEBUG.clear_marks()
        self.bm.verts.ensure_lookup_table()
        self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()
        
        # create a kd tree with the vertex positions



        vertex = []
        for v in self.selected_vertex:
            if v.is_valid:
                vertex.append(v.index)
        
        # remove dupes
        vertex = list(set(vertex))

        kd = kdtree.KDTree(len(vertex))
        for v in vertex:
            ##BL_DEBUG.set_mark(self.bm.verts[v].co,kind="CUBE",scale=0.2)
            kd.insert(self.bm.verts[v].co, v)
        kd.balance()

        def nearest_points(kd, edge, v0, side, Nitems=7):
            nearest = []
            for (co, index, dist) in kd.find_n(v0, Nitems):
                # calculate normals
                A = self.obj_t.matrix_world @ edge[0].co
                B = self.obj_t.matrix_world @ edge[1].co
                C = self.obj_t.matrix_world @ co
                normal_vec = Vector(B-A).cross(Vector(C-A))
                normal_rl = normal_vec.z
                if normal_rl < 0.0 and side.upper() == 'RIGHT':
                    nearest.append( (co, index, dist) )
                if normal_rl > 0.0 and side.upper() == 'LEFT':
                    nearest.append( (co, index, dist) )
            return(nearest)

        # iterate my vertex, and find the nearest point my vertex

        side_keys = { 0: 'right', 1: 'left', 'right': 0, 'left': 1}
        
        count = 0
        B = C = None

        for plane in self.mesh_vertex:
            print(plane)
            nearest = {}
            # calculate the nearest point for each point, for each side
            for i in range(len(plane)):
                if i == 0:
                    #right ARROWS->CUBES
                    kind = 'ARROWS'
                else:
                    #left AXES->SPHERES
                    kind = 'PLAIN_AXES'
                #BL_DEBUG.set_mark(self.obj_t.matrix_world @ plane[i][0].co,kind=kind)
                #BL_DEBUG.set_mark(self.obj_t.matrix_world @ plane[i][1].co,kind=kind)

                nearest[side_keys[i]] = [   
                    nearest_points(kd, plane[i], self.obj_t.matrix_world @ plane[i][0].co, side_keys[i]),
                    nearest_points(kd, plane[i], self.obj_t.matrix_world @ plane[i][1].co, side_keys[i]) 
                ]

            A = plane[0][1]
            D = plane[0][0]

            # lower point
            if not C:   
                _,C,_ = nearest['right'][0][0]
                _,B,_ = nearest['right'][1][0]
                if B == C:
                    _,B,_ = nearest['right'][1][1]

            else:
                C = B
                _,B,_ = nearest['right'][1][0]
                if B == C:
                    _,B,_ = nearest['right'][1][1]

            print(A,B,C,D)
            # if not B in used_points.keys(): used_points[B] = 1
            # if not C in used_points.keys(): used_points[C] = 1

            # if B in used_points.keys() and used_points[B] < 2:
            #      used_points[B] += 1
            # else:
            #     B = None

            # if C in used_points.keys() and used_points[C] < 2:
            #     used_points[C] += 1
            # else:
            #     C = None
            
          

            # first point: nearest from top, and in nearest of bottom one.

            a = nearest['right'][0]
            print("r0-")
            for i in a:
                co,idx,dist = i
                print(co,idx,dist)
                DEBUG and BL_DEBUG.set_mark(co,kind="ARROWS")

            a = nearest['right'][1]
            print("r1-")            
            for i in a:
                co,idx,dist = i
                print(co,idx,dist)
                DEBUG and BL_DEBUG.set_mark(co,kind="ARROWS")

            a = nearest['left'][0]
            print("l0-")            
            for i in a:
                co,idx,dist = i
                print(co,idx,dist)
                DEBUG and BL_DEBUG.set_mark(co,kind="PLAIN_AXES")

            a = nearest['left'][1]
            print("l1-")
            for i in a:
                co,idx,dist = i
                print(co,idx,dist)
                DEBUG and BL_DEBUG.set_mark(co,kind="PLAIN_AXES")


            ## right side

            # top_vertex_list = []
            # for _,idx,_ in nearest['right'][1]:
            #     top_vertex_list.append(idx)

            # bottom_vertex_list = []
            # for _,idx,_ in nearest['right'][0]:
            #     bottom_vertex_list.append(idx)
            
            # # default, first item
            # # bottom
            
            # pB = None
            # get_next = False
            # _,pA,_ = nearest['right'][0][0]
            # for data in nearest['right'][0]:
            #     co,idx,dist = data
            #     if get_next:
            #         pA = idx
            #         break
            #     if idx in top_vertex_list and not pB:
            #         pB = pA
            #         get_next = True
  
            # if not pB:
            #     _,pB,_ = nearest['right'][1][0]
            #     for data in nearest['right'][1]:
            #         co,idx,dist = data
            #         pB = idx
            #         break

            if B and C:
                pBv = self.bm.verts[B]
                pCv = self.bm.verts[C]
                DEBUG and BL_DEBUG.set_mark(pBv.co,kind="CUBE")
                DEBUG and BL_DEBUG.set_mark(pCv.co,kind="CUBE")

                bmesh.ops.contextual_create(self.bm, geom=[A, pBv, pCv, D])
                self.bm.faces.index_update()            

            # ## left side
            # top_vertex_list = []
            # for i in nearest['left'][1]:
            #     co,idx,dist = i
            #     top_vertex_list.append(idx)

            # bottom_vertex_list = []
            # for i in nearest['left'][0]:
            #     co,idx,dist = i
            #     bottom_vertex_list.append(idx)

            # # default, first item
            # # bottom
            
            # pD = None
            # get_next = False
            # _,pC,_ = nearest['left'][0][0]
            # for data in nearest['left'][0]:
            #     co,idx,dist = data
            #     if get_next:
            #         pC = idx
            #         break
            #     if idx in top_vertex_list and not pD:
            #         pD = pC
            #         get_next = True
  
            # if not pD:
            #     _,pD,_ = nearest['left'][1][0]
            #     for data in nearest['left'][1]:
            #         co,idx,dist = data
            #         pD = idx
            #         break
        
            # pCv = self.bm.verts[pC]
            # pDv = self.bm.verts[pD]
            # DEBUG and BL_DEBUG.set_mark(pCv.co,kind="SPHERE")
            # DEBUG and BL_DEBUG.set_mark(pDv.co,kind="SPHERE")

            # if plane[0][1] != pBv and  pBv != pAv and pAv != plane[0][0]:
            #     bmesh.ops.contextual_create(self.bm, geom=[plane[0][0], pAv, pBv, plane[0][1]])
            #     self.bm.faces.index_update()
            # if plane[1][1] != pCv and  pCv != pDv and pDv != plane[1][0]:
            #     bmesh.ops.contextual_create(self.bm, geom=[plane[1][1], plane[1][0], pDv, pCv])
            #     self.bm.faces.index_update()
            

            # do just ones
            count +=1
            if count > 5:
                break



      # update the index of the new created verts. WTF ???
        self.update_bm()
        self.time_it.stop()
        print("[t] add_geometry(): ", self.time_it)
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))
Exemplo n.º 9
0
    def project_vertex(self):
        
        self.time_it = BL_TOOLS.TimeIt()
        
        BL_DEBUG.clear_marks()
        self.bm.verts.ensure_lookup_table()
        self.bm.edges.ensure_lookup_table()
        self.bm.faces.ensure_lookup_table()

        # here, I can flatten or move the thing
        #for f in  bm.faces:
        #    if f.select:
        #        for v in f.verts:
        #            bm.verts[v.index].co[2] += 5


        self.mesh_vertex = []
        verts = []
        pc = 0
        for edge in self.plane_edges:
            e_1 = edge[0]    
            e_2 = edge[1]
            #verts += [v.index for v in e_1] + [v.index for v in e_2]

            #print(e_1,e_2)
            mesh_e1 = []
            for e in e_1:
                local_point = self.plane_to_terrain_point(e.co)
                #set_mark( obj_s.matrix_world @ obj_s.data.vertices[v_idx].co, kind='PLAIN_AXES', scale=0.2 )
                #set_mark( obj_t.matrix_world @ local_point,  scale=0.2 )
                vnew = self.bm.verts.new( local_point )
                mesh_e1.append(vnew)

            mesh_e2 = []
            for e in e_2:
                local_point = self.plane_to_terrain_point(e.co)
                #set_mark( obj_s.matrix_world @ obj_s.data.vertices[v_idx].co, kind='PLAIN_AXES', scale=0.2 )
                #set_mark( obj_t.matrix_world @ local_point,  scale=0.2 )
                vnew = self.bm.verts.new( local_point )
                mesh_e2.append(vnew)

            self.mesh_vertex.append( [ mesh_e1, mesh_e2 ] )

            if pc == 0 or pc == len(self.plane_edges)-1:
                if pc == 0:
                    # use first
                    edge_cap= [  mesh_e1[0], mesh_e2[0] ] # edge from right to left
                else:
                    # use last
                    edge_cap= [  mesh_e1[1], mesh_e2[1] ] # edge from right to left
                bmesh.ops.contextual_create(self.bm, geom= edge_cap)
                self.bm.edges.index_update()

            pc+=1


        # update the index of the new created verts. WTF ???
        self.update_bm()
        self.time_it.stop()
        print("[t] add_geometry(): ", self.time_it)
        #return(("ERROR", "Can't found terrain below the curve"))
        return(("INFO", "Done"))