Example #1
0
def object_update(self, context):
    if self.target in bpy.data.objects:
        object = bpy.data.objects[self.target]
        wm = context.window_manager

        shape = wm.perfect_shape.shape
        shape.vertices.clear()
        shape.faces.clear()

        shape_bm = bmesh.new()
        shape_bm.from_object(object, context.scene)
        loops = prepare_loops(shape_bm.edges[:])
        if loops and len(loops) == 1:
            for vert in loops[0][0][0]:
                item = shape.vertices.add()
                item.co = vert.co
            shape_bm.clear()
            for vert in shape.vertices:
                shape_bm.verts.new(vert.co)
            shape_bm.faces.new(shape_bm.verts)
            #bmesh.ops.contextual_create(shape_bm, geom=shape_bm.verts)
            bmesh.ops.triangulate(shape_bm, faces=shape_bm.faces)
            for face in shape_bm.faces:
                item = shape.faces.add()
                item.indices = [v.index for v in face.verts]
            del shape_bm
Example #2
0
    def execute(self, context):
        object = context.object
        object.update_from_editmode()

        object_bm = bmesh.from_edit_mesh(object.data)
        selected_edges = [e for e in object_bm.edges if e.select]
        loops = prepare_loops(selected_edges[:])

        if not loops:
            self.report({'WARNING'}, "Please select boundary loop of selected area.")
            return {'CANCELLED'}

        if len(loops) > 1:
            self.report({'WARNING'}, "Please select one loop.")
            return {'CANCELLED'}

        loop_verts = loops[0][0][0]

        if len(loop_verts) < 2:
            self.report({'WARNING'}, "Please select more edges.")
            return {'CANCELLED'}

        object.perfect_pattern.vertices.clear()
        object.perfect_pattern.faces.clear()
        shape_bm = bmesh.new()
        for loop_vert in loop_verts:
            vert = object.perfect_pattern.vertices.add()
            vert.co = loop_vert.co.copy()
            shape_bm.verts.new(loop_vert.co.copy())

        forward = reduce(lambda v1, v2: v1.normal.copy() + v2.normal.copy() if isinstance(v1, bmesh.types.BMVert)
                         else v1.copy() + v2.normal.copy(), loop_verts).normalized()

        shape_bm.faces.new(shape_bm.verts)
        shape_bm.faces.ensure_lookup_table()
        center = shape_bm.faces[0].calc_center_median()
        bmesh.ops.triangulate(shape_bm, faces=shape_bm.faces)

        matrix_rotation = forward.to_track_quat('Z', 'X').to_matrix().to_4x4()
        matrix_rotation.transpose()
        matrix = matrix_rotation * Matrix.Translation(-center)

        for pattern_vert in object.perfect_pattern.vertices:
            pattern_vert.co = matrix * Vector(pattern_vert.co)

        pattern_faces = object.perfect_pattern.faces
        for face in shape_bm.faces:
            item = pattern_faces.add()
            item.indices = [v.index for v in face.verts]


        return {'FINISHED'}
Example #3
0
    def execute(self, context):
        object = context.object
        object.update_from_editmode()

        object_bm = bmesh.from_edit_mesh(object.data)
        selected_edges = [e for e in object_bm.edges if e.select]
        loops = prepare_loops(selected_edges[:])

        if loops is None:
            self.report({'WARNING'}, "Please select boundary loop of selected area.")
            return {'CANCELLED'}

        if len(loops) > 1:
            self.report({'WARNING'}, "Please select one loop.")
            return {'CANCELLED'}

        object.perfect_pattern.clear()
        loop_verts = loops[0][0][0]
        shape_bm = bmesh.new()
        for loop_vert in loop_verts:
            vert = object.perfect_pattern.add()
            vert.co = loop_vert.co.copy()
            shape_bm.verts.new(loop_vert.co.copy())


        forward = reduce(lambda v1, v2: v1.normal.copy() if isinstance(v1, bmesh.types.BMVert)
                         else v1.copy() + v2.normal.copy(), loop_verts).normalized()

        shape_bm.faces.new(shape_bm.verts)
        shape_bm.faces.ensure_lookup_table()
        center = shape_bm.faces[0].calc_center_median()
        matrix_rotation = forward.to_track_quat('Z', 'X').to_matrix().to_4x4()
        matrix_rotation.transpose()
        matrix = matrix_rotation * Matrix.Translation(-center)

        for pattern_vert in object.perfect_pattern:
            pattern_vert.co = matrix * Vector(pattern_vert.co)

        return {'FINISHED'}
Example #4
0
    def execute(self, context):
        object = context.object
        object.update_from_editmode()

        object_bm = bmesh.from_edit_mesh(object.data)

        selected_edges = [e for e in object_bm.edges if e.select]
        selected_verts = [v for v in object_bm.verts if v.select]
        selected_verts_fin = []

        if len(selected_edges) == 0:
            self.report({'WARNING'}, "Please select edges.")
            return {'CANCELLED'}

        loops = prepare_loops(selected_edges[:])

        if loops is None:
            self.report({'WARNING'}, "Please select boundary loop(s) of selected area(s).")
            return {'CANCELLED'}

        object_bvh = mathutils.bvhtree.BVHTree.FromObject(object, context.scene, deform=False)

        refresh_icons()

        for (loop_verts, loop_edges), is_loop_cyclic, is_loop_boundary in loops:
            if len(loop_edges) < 3:
                continue
            loop_verts_len = len(loop_verts)
            context.window_manager.perfect_shape.preview_verts_count = loop_verts_len
            if self.projection == "NORMAL":
                if is_loop_boundary:
                    forward = calculate_normal([v.co for v in loop_verts])
                else:
                    forward = reduce(
                        lambda v1, v2: v1.normal.copy() + v2.normal.copy() if isinstance(v1, bmesh.types.BMVert)
                        else v1.copy() + v2.normal.copy(), loop_verts).normalized()
            else:
                forward = Vector([v == self.projection for v in ["X", "Y", "Z"]])

            if self.invert_projection:
                forward.negate()

            shape_bm = bmesh.new()

            if context.space_data.pivot_point == "CURSOR":
                center = object.matrix_world.copy() * context.scene.cursor_location.copy()
            else:
                for loop_vert in loop_verts:
                    shape_bm.verts.new(loop_vert.co.copy())
                shape_bm.faces.new(shape_bm.verts)
                shape_bm.faces.ensure_lookup_table()
                if context.space_data.pivot_point == 'BOUNDING_BOX_CENTER':
                    center = shape_bm.faces[0].calc_center_bounds()
                else:
                    center = shape_bm.faces[0].calc_center_median()

                shape_bm.clear()

            matrix_rotation = forward.to_track_quat('Z', 'X').to_matrix().to_4x4()
            matrix_translation = Matrix.Translation(center)

            shape_bm = bmesh.new()
            shape_verts = None
            if self.shape == "CIRCLE":
                diameter = sum([e.calc_length() for e in loop_edges]) / (2*math.pi)
                diameter += self.offset
                shape_segments = loop_verts_len + self.span
                shape_verts = bmesh.ops.create_circle(shape_bm, segments=shape_segments,
                                                      diameter=diameter, matrix=matrix_translation*matrix_rotation)
                shape_verts = shape_verts["verts"]
            elif self.shape == "RECTANGLE":
                if loop_verts_len % 2 > 0:
                    self.report({'WARNING'}, "An odd number of edges.")
                    del shape_bm
                    return {'FINISHED'}
                size = sum([e.calc_length() for e in loop_edges])

                size_a = (size / 2) / (self.ratio_a + self.ratio_b) * self.ratio_a
                size_b = (size / 2) / (self.ratio_a + self.ratio_b) * self.ratio_b
                seg_a = (loop_verts_len / 2) / (self.ratio_a + self.ratio_b) * self.ratio_a
                seg_b = int((loop_verts_len / 2) / (self.ratio_a + self.ratio_b) * self.ratio_b)
                if seg_a % 1 > 0:
                    self.report({'WARNING'}, "Incorrect sides ratio.")
                    seg_a += 1
                    seg_b += 2
                seg_a = int(seg_a)
                if self.is_square:
                    size_a = (size_a + size_b) / 2
                    size_b = size_a
                seg_len_a = size_a / seg_a
                seg_len_b = size_b / seg_b

                for i in range(seg_a):
                    shape_bm.verts.new(Vector((size_b/2*-1, seg_len_a*i-(size_a/2), 0)))
                for i in range(seg_b):
                    shape_bm.verts.new(Vector((seg_len_b*i-(size_b/2), size_a/2, 0)))
                for i in range(seg_a, 0, -1):
                    shape_bm.verts.new(Vector((size_b/2, seg_len_a*i-(size_a/2), 0)))
                for i in range(seg_b, 0, -1):
                    shape_bm.verts.new(Vector((seg_len_b*i-(size_b/2), size_a/2*-1, 0)))

                shape_verts = shape_bm.verts[:]
                bmesh.ops.scale(shape_bm, vec=Vector((1, 1, 1))*(1+self.offset), verts=shape_verts)
                bmesh.ops.transform(shape_bm, verts=shape_verts, matrix=matrix_translation*matrix_rotation)
            elif self.shape == "PATTERN":
                if len(object.perfect_pattern.vertices) == 0:
                    self.report({'WARNING'}, "Empty Pattern Data.")
                    del shape_bm
                    return {'FINISHED'}
                if len(object.perfect_pattern.vertices) != len(loop_verts):
                    self.report({'WARNING'}, "Pattern and loop vertices count must be the same.")
                    del shape_bm
                    return {'FINISHED'}
                for pattern_vert in object.perfect_pattern.vertices:
                    shape_bm.verts.new(Vector(pattern_vert.co))
                shape_verts = shape_bm.verts[:]
                bmesh.ops.scale(shape_bm, vec=Vector((1, 1, 1))*(1+self.offset), verts=shape_verts)
                bmesh.ops.transform(shape_bm, verts=shape_verts, matrix=matrix_translation*matrix_rotation)
            elif self.shape == "OBJECT":
                if self.target in bpy.data.objects:
                    shape_object = bpy.data.objects[self.target]
                    shape_bm.from_object(shape_object, context.scene)
                    loops = prepare_loops(shape_bm.edges[:])
                    if not loops or len(loops) > 1:
                        self.report({'WARNING'}, "Wrong mesh data.")
                        del shape_bm
                        return {'FINISHED'}
                    if len(loops[0][0][0]) != len(loop_verts):
                        self.report({'WARNING'}, "Shape and loop vertices count must be the same.")
                        del shape_bm
                        return {'FINISHED'}

                    shape_verts = shape_bm.verts[:]
                    bmesh.ops.scale(shape_bm, vec=Vector((1, 1, 1))*(1+self.offset), verts=shape_verts)
                    bmesh.ops.transform(shape_bm, verts=shape_verts, matrix=matrix_translation*matrix_rotation)

            if shape_verts is not None and len(shape_verts) > 0:
                if not is_clockwise(forward, center, loop_verts):
                    loop_verts.reverse()
                    loop_edges.reverse()
                if not is_clockwise(forward, center, shape_verts):
                    shape_verts.reverse()

                loop_angle = box_fit_2d([(matrix_rotation.transposed() * v.co).to_2d() for v in loop_verts])
                shape_angle = box_fit_2d([(matrix_rotation.transposed() * v.co).to_2d() for v in shape_verts])

                if abs(abs(loop_angle) - abs(shape_angle)) <= 0.01:
                    loop_angle = 0
                correct_angle = loop_angle + self.rotation

                if self.shape_rotation:
                    correct_angle -= shape_angle

                if correct_angle != 0 and not self.active_as_first:
                    bmesh.ops.rotate(shape_bm, verts=shape_verts, cent=center,
                                     matrix=Matrix.Rotation(-correct_angle, 3, forward))

                active = object_bm.select_history.active
                if self.active_as_first and isinstance(active, bmesh.types.BMVert) and active in loop_verts:
                    shift = loop_verts.index(active)
                else:
                    kd_tree = mathutils.kdtree.KDTree(len(loop_verts))
                    for idx, loop_vert in enumerate(loop_verts):
                        kd_tree.insert(loop_vert.co, idx)
                    kd_tree.balance()
                    shape_first_idx = kd_tree.find(shape_verts[0].co)[1]
                    shift = shape_first_idx + self.shift
                if shift != 0:
                    loop_verts = loop_verts[shift % len(loop_verts):] + loop_verts[:shift % len(loop_verts)]

                if not is_loop_boundary and self.use_ray_cast:
                    for shape_vert in shape_verts:
                        co = shape_vert.co
                        ray_cast_data = object_bvh.ray_cast(co, forward)
                        if ray_cast_data[0] is None:
                            ray_cast_data = object_bvh.ray_cast(co, -forward)
                        if ray_cast_data[0] is not None:
                            shape_vert.co = ray_cast_data[0]

                for idx, vert in enumerate(loop_verts):
                    vert.co = vert.co.lerp(shape_verts[idx].co, self.factor/100)

                if not is_loop_boundary and is_loop_cyclic:
                    object_bm.select_flush_mode()
                    select_only(object_bm, loop_edges, {"EDGE"})
                    bpy.ops.mesh.loop_to_region()  # Ugly.
                    inset_faces = [f for f in object_bm.faces[:] if f.select]

                    if self.fill_type != "ORIGINAL":
                        smooth = inset_faces[0].smooth
                        bmesh.ops.delete(object_bm, geom=inset_faces, context=5)

                        inset_faces = []
                        center_vert = object_bm.verts.new(center)
                        if self.use_ray_cast:
                            ray_cast_data = object_bvh.ray_cast(center_vert.co, forward)
                            if ray_cast_data[0] is None:
                                ray_cast_data = object_bvh.ray_cast(center_vert.co, -forward)
                            if ray_cast_data[0] is not None:
                                center_vert.co = ray_cast_data[0]
                        for idx, vert in enumerate(loop_verts):
                            new_face = object_bm.faces.new((center_vert, vert, loop_verts[(idx+1) % loop_verts_len]))
                            new_face.smooth = smooth
                            inset_faces.append(new_face)
                        bmesh.ops.recalc_face_normals(object_bm, faces=inset_faces)

                    selected_co = []
                    for vert in selected_verts:
                        if vert.is_valid:
                            selected_co.append(vert.co.copy())

                    outset_region_faces = []
                    if self.outset > 0.0:
                        outset_region_faces = bmesh.ops.inset_region(object_bm, faces=inset_faces,
                                                                     thickness=self.outset, use_even_offset=True,
                                                                     use_interpolate=True, use_outset=True)
                        outset_region_faces = outset_region_faces["faces"]

                    inset_region_faces = []
                    if self.inset > 0.0:
                        inset_region_faces = bmesh.ops.inset_region(object_bm, faces=inset_faces, thickness=self.inset,
                                                                    use_even_offset=True, use_interpolate=True)
                        inset_region_faces = inset_region_faces["faces"]

                    new_selected_verts = []

                    for face in set(inset_region_faces+inset_faces):
                        for vert in face.verts:
                            if vert.co in selected_co:
                                new_selected_verts.append(vert)
                                selected_co.remove(vert.co)

                    selected_verts_fin.append(new_selected_verts)
                    select_only(object_bm, new_selected_verts, {"EDGE"})

                    if self.fill_type == "HOLE":
                        bmesh.ops.delete(object_bm, geom=inset_faces, context=5)
                        inset_faces = []
                    elif self.fill_type == "NGON":
                        inset_faces = [bmesh.utils.face_join(inset_faces)]

                    if self.fill_flatten and self.extrude == 0:
                        if len(inset_region_faces + inset_faces) > 0:
                            verts = list(set(reduce(lambda v1, v2: list(v1) + list(v2),
                                                    [v.verts for v in inset_region_faces + inset_faces])))
                            matrix = Matrix.Translation(-center)
                            bmesh.ops.rotate(object_bm, cent=center, matrix=matrix_rotation.transposed(), verts=verts)
                            bmesh.ops.scale(object_bm, vec=Vector((1, 1, +0)), space=matrix, verts=verts)
                            bmesh.ops.rotate(object_bm, cent=center, matrix=matrix_rotation, verts=verts)

                    bmesh.ops.recalc_face_normals(object_bm, faces=outset_region_faces+inset_region_faces+inset_faces)
                    if self.extrude != 0:
                        extrude_geom = bmesh.ops.extrude_face_region(object_bm, geom=inset_region_faces+inset_faces)
                        verts = [v for v in extrude_geom['geom'] if isinstance(v, bmesh.types.BMVert)]

                        if self.fill_flatten:
                            matrix = Matrix.Translation(-center)
                            bmesh.ops.rotate(object_bm, cent=center, matrix=matrix_rotation.transposed(), verts=verts)
                            bmesh.ops.scale(object_bm, vec=Vector((1.0, 1.0, 0.001)), space=matrix, verts=verts)
                            bmesh.ops.rotate(object_bm, cent=center, matrix=matrix_rotation, verts=verts)
                        bmesh.ops.delete(object_bm, geom=inset_region_faces+inset_faces, context=5)
                        bmesh.ops.translate(object_bm,
                                            verts=verts,
                                            vec=forward * self.extrude)
            del shape_bm
        if selected_verts_fin:
            select_only(object_bm, reduce(lambda x, y: x + y, selected_verts_fin), {"EDGE"})
        object_bm.select_flush(True)
        del object_bvh
        bmesh.update_edit_mesh(object.data)
        return {'FINISHED'}
Example #5
0
    def execute(self, context):
        object = context.object
        object.update_from_editmode()

        object_bm = bmesh.from_edit_mesh(object.data)

        selected_edges = [e for e in object_bm.edges if e.select]
        selected_verts = [v for v in object_bm.verts if v.select]
        selected_verts_fin = []

        if len(selected_edges) == 0:
            self.report({'WARNING'}, "Please select edges.")
            return {'CANCELLED'}

        loops = prepare_loops(selected_edges[:])

        if loops is None:
            self.report({'WARNING'}, "Please select boundary loop(s) of selected area(s).")
            return {'CANCELLED'}

        object_bvh = mathutils.bvhtree.BVHTree.FromObject(object, context.scene, deform=False)

        for (loop_verts, loop_edges), is_loop_cyclic, is_loop_boundary in loops:
            if len(loop_edges) < 3:
                continue
            loop_verts_len = len(loop_verts)
            if self.projection == "NORMAL":
                if is_loop_boundary:
                    forward = calculate_normal([v.co for v in loop_verts])
                else:
                    forward = reduce(
                        lambda v1, v2: v1.normal.copy() if isinstance(v1, bmesh.types.BMVert)
                        else v1.copy() + v2.normal.copy(), loop_verts).normalized()
            else:
                forward = Vector([v == self.projection for v in ["X", "Y", "Z"]])

            if self.invert_projection:
                forward.negate()

            shape_bm = bmesh.new()

            if context.space_data.pivot_point == "CURSOR":
                center = object.matrix_world.copy() * context.scene.cursor_location.copy()
            else:
                for loop_vert in loop_verts:
                    shape_bm.verts.new(loop_vert.co.copy())
                shape_bm.faces.new(shape_bm.verts)
                shape_bm.faces.ensure_lookup_table()
                if context.space_data.pivot_point == 'BOUNDING_BOX_CENTER':
                    center = shape_bm.faces[0].calc_center_bounds()
                else:
                    center = shape_bm.faces[0].calc_center_median()

                shape_bm.clear()

            matrix_rotation = forward.to_track_quat('Z', 'X').to_matrix().to_4x4()
            matrix_translation = Matrix.Translation(center)

            shape_bm = bmesh.new()
            shape_verts = None
            if self.shape == "CIRCLE":
                diameter = sum([e.calc_length() for e in loop_edges]) / (2*math.pi)
                diameter += self.offset
                shape_segments = loop_verts_len + self.span
                shape_verts = bmesh.ops.create_circle(shape_bm, segments=shape_segments,
                                                      diameter=diameter, matrix=matrix_translation*matrix_rotation)
                shape_verts = shape_verts["verts"]
            elif self.shape == "RECTANGLE":
                if loop_verts_len % 2 > 0:
                    self.report({'WARNING'}, "An odd number of edges.")
                    del shape_bm
                    return {'FINISHED'}
                size = sum([e.calc_length() for e in loop_edges])

                size_a = (size / 2) / (self.ratio_a + self.ratio_b) * self.ratio_a
                size_b = (size / 2) / (self.ratio_a + self.ratio_b) * self.ratio_b
                seg_a = (loop_verts_len / 2) / (self.ratio_a + self.ratio_b) * self.ratio_a
                seg_b = int((loop_verts_len / 2) / (self.ratio_a + self.ratio_b) * self.ratio_b)
                if seg_a % 1 > 0:
                    self.report({'WARNING'}, "Incorrect sides ratio.")
                    seg_a += 1
                    seg_b += 2
                seg_a = int(seg_a)
                if self.is_square:
                    size_a = (size_a + size_b) / 2
                    size_b = size_a
                seg_len_a = size_a / seg_a
                seg_len_b = size_b / seg_b

                for i in range(seg_a):
                    shape_bm.verts.new(Vector((size_b/2*-1, seg_len_a*i-(size_a/2), 0)))
                for i in range(seg_b):
                    shape_bm.verts.new(Vector((seg_len_b*i-(size_b/2), size_a/2, 0)))
                for i in range(seg_a, 0, -1):
                    shape_bm.verts.new(Vector((size_b/2, seg_len_a*i-(size_a/2), 0)))
                for i in range(seg_b, 0, -1):
                    shape_bm.verts.new(Vector((seg_len_b*i-(size_b/2), size_a/2*-1, 0)))

                shape_verts = shape_bm.verts[:]
                bmesh.ops.scale(shape_bm, vec=Vector((1, 1, 1))*(1+self.offset), verts=shape_verts)
                bmesh.ops.transform(shape_bm, verts=shape_verts, matrix=matrix_translation*matrix_rotation)
            elif self.shape == "PATTERN":
                if len(object.perfect_pattern) == 0:
                    self.report({'WARNING'}, "Empty Pattern Data.")
                    del shape_bm
                    return {'FINISHED'}
                if len(object.perfect_pattern) != len(loop_verts):
                    self.report({'WARNING'}, "Pattern and loop vertices count must be the same.")
                    del shape_bm
                    return {'FINISHED'}
                for pattern_vert in object.perfect_pattern:
                    shape_bm.verts.new(Vector(pattern_vert.co))
                shape_verts = shape_bm.verts[:]
                bmesh.ops.scale(shape_bm, vec=Vector((1, 1, 1))*(1+self.offset), verts=shape_verts)
                bmesh.ops.transform(shape_bm, verts=shape_verts, matrix=matrix_translation*matrix_rotation)
            elif self.shape == "OBJECT":
                if self.target in bpy.data.objects:
                    shape_object = bpy.data.objects[self.target]
                    shape_bm.from_object(shape_object, context.scene)
                    loops = prepare_loops(shape_bm.edges[:])
                    if loops is None or len(loops) > 1:
                        self.report({'WARNING'}, "Wrong mesh data.")
                        del shape_bm
                        return {'FINISHED'}

                    shape_verts = shape_bm.verts[:]
                    bmesh.ops.scale(shape_bm, vec=Vector((1, 1, 1))*(1+self.offset), verts=shape_verts)
                    bmesh.ops.transform(shape_bm, verts=shape_verts, matrix=matrix_translation*matrix_rotation)

            if shape_verts is not None and len(shape_verts) > 0:
                if not is_clockwise(forward, center, loop_verts):
                    loop_verts.reverse()
                    loop_edges.reverse()
                if not is_clockwise(forward, center, shape_verts):
                    shape_verts.reverse()

                loop_angle = box_fit_2d([(matrix_rotation.transposed() * v.co).to_2d() for v in loop_verts])
                shape_angle = box_fit_2d([(matrix_rotation.transposed() * v.co).to_2d() for v in shape_verts])

                if abs(abs(loop_angle) - abs(shape_angle)) <= 0.01:
                    loop_angle = 0
                correct_angle = loop_angle + self.rotation

                if self.shape_rotation:
                    correct_angle -= shape_angle

                if correct_angle != 0 and not self.active_as_first:
                    bmesh.ops.rotate(shape_bm, verts=shape_verts, cent=center,
                                     matrix=Matrix.Rotation(-correct_angle, 3, forward))

                active = object_bm.select_history.active
                if self.active_as_first and isinstance(active, bmesh.types.BMVert) and active in loop_verts:
                    shift = loop_verts.index(active)
                else:
                    kd_tree = mathutils.kdtree.KDTree(len(loop_verts))
                    for idx, loop_vert in enumerate(loop_verts):
                        kd_tree.insert(loop_vert.co, idx)
                    kd_tree.balance()
                    shape_first_idx = kd_tree.find(shape_verts[0].co)[1]
                    shift = shape_first_idx + self.shift
                if shift != 0:
                    loop_verts = loop_verts[shift % len(loop_verts):] + loop_verts[:shift % len(loop_verts)]

                if not is_loop_boundary and self.use_ray_cast:
                    for shape_vert in shape_verts:
                        co = shape_vert.co
                        ray_cast_data = object_bvh.ray_cast(co, forward)
                        if ray_cast_data[0] is None:
                            ray_cast_data = object_bvh.ray_cast(co, -forward)
                        if ray_cast_data[0] is not None:
                            shape_vert.co = ray_cast_data[0]

                for idx, vert in enumerate(loop_verts):
                    vert.co = vert.co.lerp(shape_verts[idx].co, self.factor)

                if not is_loop_boundary and is_loop_cyclic:
                    object_bm.select_flush_mode()
                    select_only(object_bm, loop_edges, {"EDGE"})
                    bpy.ops.mesh.loop_to_region()  # Ugly.
                    inset_faces = [f for f in object_bm.faces[:] if f.select]

                    if self.fill_type != "ORIGINAL":
                        smooth = inset_faces[0].smooth
                        bmesh.ops.delete(object_bm, geom=inset_faces, context=5)

                        inset_faces = []
                        center_vert = object_bm.verts.new(center)
                        if self.use_ray_cast:
                            ray_cast_data = object_bvh.ray_cast(center_vert.co, forward)
                            if ray_cast_data[0] is None:
                                ray_cast_data = object_bvh.ray_cast(center_vert.co, -forward)
                            if ray_cast_data[0] is not None:
                                center_vert.co = ray_cast_data[0]
                        for idx, vert in enumerate(loop_verts):
                            new_face = object_bm.faces.new((center_vert, vert, loop_verts[(idx+1) % loop_verts_len]))
                            new_face.smooth = smooth
                            inset_faces.append(new_face)
                        bmesh.ops.recalc_face_normals(object_bm, faces=inset_faces)

                    selected_co = []
                    for vert in selected_verts:
                        if vert.is_valid:
                            selected_co.append(vert.co.copy())

                    outset_region_faces = []
                    if self.outset > 0.0:
                        outset_region_faces = bmesh.ops.inset_region(object_bm, faces=inset_faces,
                                                                     thickness=self.outset, use_even_offset=True,
                                                                     use_interpolate=True, use_outset=True)
                        outset_region_faces = outset_region_faces["faces"]

                    inset_region_faces = []
                    if self.inset > 0.0:
                        inset_region_faces = bmesh.ops.inset_region(object_bm, faces=inset_faces, thickness=self.inset,
                                                                    use_even_offset=True, use_interpolate=True)
                        inset_region_faces = inset_region_faces["faces"]

                    new_selected_verts = []

                    for face in set(inset_region_faces+inset_faces):
                        for vert in face.verts:
                            if vert.co in selected_co:
                                new_selected_verts.append(vert)
                                selected_co.remove(vert.co)

                    selected_verts_fin.append(new_selected_verts)
                    select_only(object_bm, new_selected_verts, {"EDGE"})

                    if self.fill_type == "HOLE":
                        bmesh.ops.delete(object_bm, geom=inset_faces, context=5)
                        inset_faces = []
                    elif self.fill_type == "NGON":
                        inset_faces = [bmesh.utils.face_join(inset_faces)]

                    if self.fill_flatten and self.extrude == 0:
                        verts = list(set(reduce(lambda v1, v2: list(v1) + list(v2),
                                                [v.verts for v in inset_region_faces + inset_faces])))
                        matrix = Matrix.Translation(-center)
                        bmesh.ops.rotate(object_bm, cent=center, matrix=matrix_rotation.transposed(), verts=verts)
                        bmesh.ops.scale(object_bm, vec=Vector((1, 1, +0)), space=matrix, verts=verts)
                        bmesh.ops.rotate(object_bm, cent=center, matrix=matrix_rotation, verts=verts)

                    bmesh.ops.recalc_face_normals(object_bm, faces=outset_region_faces+inset_region_faces+inset_faces)
                    if self.extrude != 0:
                        extrude_geom = bmesh.ops.extrude_face_region(object_bm, geom=inset_region_faces+inset_faces)
                        verts = [v for v in extrude_geom['geom'] if isinstance(v, bmesh.types.BMVert)]

                        if self.fill_flatten:
                            matrix = Matrix.Translation(-center)
                            bmesh.ops.rotate(object_bm, cent=center, matrix=matrix_rotation.transposed(), verts=verts)
                            bmesh.ops.scale(object_bm, vec=Vector((1.0, 1.0, 0.001)), space=matrix, verts=verts)
                            bmesh.ops.rotate(object_bm, cent=center, matrix=matrix_rotation, verts=verts)
                        bmesh.ops.delete(object_bm, geom=inset_region_faces+inset_faces, context=5)
                        bmesh.ops.translate(object_bm,
                                            verts=verts,
                                            vec=forward * self.extrude)
            del shape_bm
        if selected_verts_fin:
            select_only(object_bm, reduce(lambda x, y: x + y, selected_verts_fin), {"EDGE"})
        object_bm.select_flush(True)
        del object_bvh
        bmesh.update_edit_mesh(object.data)
        return {'FINISHED'}