Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormeta-androcto <meta.androcto1@gmail.com>2017-03-20 02:33:38 +0300
committermeta-androcto <meta.androcto1@gmail.com>2017-03-20 02:33:38 +0300
commit8e3bfa5506ea110fe6793401b53da17c61061167 (patch)
tree8e53f830a72b434928b07b99befe8762431a4ed3 /mesh_extra_tools/pkhg_faces.py
parent9007bcd10713e55168235e9e8420b17172674638 (diff)
initial commit mesh edit tools: T50680
Diffstat (limited to 'mesh_extra_tools/pkhg_faces.py')
-rw-r--r--mesh_extra_tools/pkhg_faces.py824
1 files changed, 824 insertions, 0 deletions
diff --git a/mesh_extra_tools/pkhg_faces.py b/mesh_extra_tools/pkhg_faces.py
new file mode 100644
index 00000000..10b0ca97
--- /dev/null
+++ b/mesh_extra_tools/pkhg_faces.py
@@ -0,0 +1,824 @@
+# gpl author: PHKG
+
+bl_info = {
+ "name": "PKHG faces",
+ "author": "PKHG",
+ "version": (0, 0, 5),
+ "blender": (2, 7, 1),
+ "location": "View3D > Tools > PKHG (tab)",
+ "description": "Faces selected will become added faces of different style",
+ "warning": "",
+ "wiki_url": "",
+ "category": "Mesh",
+}
+
+import bpy
+import bmesh
+from bpy.types import (
+ Operator,
+ Panel
+ )
+from mathutils import Vector
+from bpy.props import (
+ BoolProperty,
+ StringProperty,
+ IntProperty,
+ FloatProperty,
+ EnumProperty,
+ )
+
+
+class MESH_OT_add_faces_to_object(Operator):
+ bl_idname = "mesh.add_faces_to_object"
+ bl_label = "Face Extrude"
+ bl_description = "Set parameters and build object with added faces"
+ bl_options = {'REGISTER', 'UNDO', 'PRESET'}
+
+ reverse_faces = BoolProperty(
+ name="Reverse Faces",
+ default=False,
+ description="Revert the normals of selected faces"
+ )
+ name_source_object = StringProperty(
+ name="Mesh",
+ description="Choose a Source Mesh",
+ default="Cube"
+ )
+ remove_start_faces = BoolProperty(
+ name="Remove Start Faces",
+ default=True,
+ description="Make a choice about removal of Original Faces"
+ )
+ base_height = FloatProperty(
+ name="Base Height",
+ min=-20,
+ soft_max=10, max=20,
+ default=0.2,
+ description="Set general Base Height"
+ )
+ use_relative_base_height = BoolProperty(
+ name="rel.base_height",
+ default=False,
+ description="Relative or absolute Base Height"
+ )
+ second_height = FloatProperty(
+ name="2nd height", min=-5,
+ soft_max=5, max=20,
+ default=0.2,
+ description="Second height for various shapes"
+ )
+ width = FloatProperty(
+ name="Width Faces",
+ min=-20, max=20,
+ default=0.5,
+ description="Set general width"
+ )
+ repeat_extrude = IntProperty(
+ name="Repeat",
+ min=1,
+ soft_max=5, max=20,
+ description="For longer base"
+ )
+ move_inside = FloatProperty(
+ name="Move Inside",
+ min=0.0,
+ max=1.0,
+ default=0.5,
+ description="How much move to inside"
+ )
+ thickness = FloatProperty(
+ name="Thickness",
+ soft_min=0.01, min=0,
+ soft_max=5.0, max=20.0,
+ default=0
+ )
+ depth = FloatProperty(
+ name="Depth",
+ min=-5,
+ soft_max=5.0, max=20.0,
+ default=0
+ )
+ collapse_edges = BoolProperty(
+ name="Make Point",
+ default=False,
+ description="Collapse the vertices of edges"
+ )
+ spike_base_width = FloatProperty(
+ name="Spike Base Width",
+ default=0.4,
+ min=-4.0,
+ soft_max=1, max=20,
+ description="Base width of a spike"
+ )
+ base_height_inset = FloatProperty(
+ name="Base Height Inset",
+ default=0.0,
+ min=-5, max=5,
+ description="To elevate or drop the Base height Inset"
+ )
+ top_spike = FloatProperty(
+ name="Top Spike",
+ default=1.0,
+ min=-10.0, max=10.0,
+ description="The Base Height of a spike"
+ )
+
+ top_extra_height = FloatProperty(
+ name="Top Extra Height",
+ default=0.0,
+ min=-10.0, max=10.0,
+ description="Add extra height"
+ )
+ step_with_real_spike = BoolProperty(
+ name="Step with Real Spike",
+ default=False,
+ description="In stepped, use a real spike"
+ )
+ use_relative = BoolProperty(
+ name="Use Relative",
+ default=False,
+ description="Change size using area, min or max"
+ )
+ face_types = EnumProperty(
+ name="Face Types",
+ description="Different types of Faces",
+ default="no",
+ items=[
+ ('no', "Pick an Option", "Choose one of the available options"),
+ ('open_inset', "Open Inset", "Inset without closing faces (holes)"),
+ ('with_base', "With Base", "Base and ..."),
+ ('clsd_vertical', "Closed Vertical", "Closed Vertical"),
+ ('open_vertical', "Open Vertical", "Open Vertical"),
+ ('spiked', "Spiked", "Spike"),
+ ('stepped', "Stepped", "Stepped"),
+ ('boxed', "Boxed", "Boxed"),
+ ('bar', "Bar", "Bar"),
+ ]
+ )
+ strange_boxed_effect = BoolProperty(
+ name="Strange Effect",
+ default=False,
+ description="Do not show one extrusion"
+ )
+ use_boundary = BoolProperty(
+ name="Use Boundary",
+ default=True
+ )
+ use_even_offset = BoolProperty(
+ name="Even Offset",
+ default=True
+ )
+ use_relative_offset = BoolProperty(
+ name="Relative Offset",
+ default=True
+ )
+ use_edge_rail = BoolProperty(
+ name="Edge Rail",
+ default=False
+ )
+ use_outset = BoolProperty(
+ name="Outset",
+ default=False
+ )
+ use_select_inset = BoolProperty(
+ name="Inset",
+ default=False
+ )
+ use_interpolate = BoolProperty(
+ name="Interpolate",
+ default=True
+ )
+
+ @classmethod
+ def poll(cls, context):
+ result = False
+ active_object = context.active_object
+ if active_object:
+ mesh_objects_name = [el.name for el in bpy.data.objects if el.type == "MESH"]
+ if active_object.name in mesh_objects_name:
+ result = True
+
+ return result
+
+ def draw(self, context):
+ layout = self.layout
+ col = layout.column()
+
+ col.separator()
+ col.label(text="Using Active Object", icon="INFO")
+ col.separator()
+ col.label("Face Types:")
+ col.prop(self, "face_types", text="")
+ col.separator()
+ col.prop(self, "use_relative")
+
+ if self.face_types == "open_inset":
+ col.prop(self, "move_inside")
+ col.prop(self, "base_height")
+
+ elif self.face_types == "with_base":
+ col.prop(self, "move_inside")
+ col.prop(self, "base_height")
+ col.prop(self, "second_height")
+ col.prop(self, "width")
+
+ elif self.face_types == "clsd_vertical":
+ col.prop(self, "base_height")
+
+ elif self.face_types == "open_vertical":
+ col.prop(self, "base_height")
+
+ elif self.face_types == "boxed":
+ col.prop(self, "move_inside")
+ col.prop(self, "base_height")
+ col.prop(self, "top_spike")
+ col.prop(self, "strange_boxed_effect")
+
+ elif self.face_types == "spiked":
+ col.prop(self, "spike_base_width")
+ col.prop(self, "base_height_inset")
+ col.prop(self, "top_spike")
+
+ elif self.face_types == "bar":
+ col.prop(self, "spike_base_width")
+ col.prop(self, "top_spike")
+ col.prop(self, "top_extra_height")
+
+ elif self.face_types == "stepped":
+ col.prop(self, "spike_base_width")
+ col.prop(self, "base_height_inset")
+ col.prop(self, "top_extra_height")
+ col.prop(self, "second_height")
+ col.prop(self, "step_with_real_spike")
+
+ def execute(self, context):
+ obj_name = self.name_source_object
+ face_type = self.face_types
+
+ is_selected = check_is_selected()
+
+ if not is_selected:
+ self.report({'WARNING'},
+ "Operation Cancelled. No selected Faces found on the Active Object")
+ return {'CANCELLED'}
+
+ if face_type == "spiked":
+ Spiked(spike_base_width=self.spike_base_width,
+ base_height_inset=self.base_height_inset,
+ top_spike=self.top_spike, top_relative=self.use_relative)
+
+ elif face_type == "boxed":
+ startinfo = prepare(self, context, self.remove_start_faces)
+ bm = startinfo['bm']
+ top = self.top_spike
+ obj = startinfo['obj']
+ obj_matrix_local = obj.matrix_local
+
+ distance = None
+ base_heights = None
+ t = self.move_inside
+ areas = startinfo['areas']
+ base_height = self.base_height
+
+ if self.use_relative:
+ distance = [min(t * area, 1.0) for i, area in enumerate(areas)]
+ base_heights = [base_height * area for i, area in enumerate(areas)]
+ else:
+ distance = [t] * len(areas)
+ base_heights = [base_height] * len(areas)
+
+ rings = startinfo['rings']
+ centers = startinfo['centers']
+ normals = startinfo['normals']
+ for i in range(len(rings)):
+ make_one_inset(self, context, bm=bm, ringvectors=rings[i],
+ center=centers[i], normal=normals[i],
+ t=distance[i], base_height=base_heights[i])
+ bpy.ops.mesh.select_mode(type="EDGE")
+ bpy.ops.mesh.select_more()
+ bpy.ops.mesh.select_more()
+ bpy.ops.object.mode_set(mode='OBJECT')
+ # PKHG>INFO base extrusion done and set to the mesh
+
+ # PKHG>INFO if the extrusion is NOT done ... it'll look strange soon!
+ if not self.strange_boxed_effect:
+ bpy.ops.object.mode_set(mode='EDIT')
+ obj = context.active_object
+ bm = bmesh.from_edit_mesh(obj.data)
+ bmfaces = [face for face in bm.faces if face.select]
+ res = extrude_faces(self, context, bm=bm, face_l=bmfaces)
+ ring_edges = [face.edges[:] for face in res]
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # PKHG>INFO now the extruded facec have to move in normal direction
+ bpy.ops.object.mode_set(mode='EDIT')
+ obj = bpy.context.scene.objects.active
+ bm = bmesh.from_edit_mesh(obj.data)
+ todo_faces = [face for face in bm.faces if face.select]
+ for face in todo_faces:
+ bmesh.ops.translate(bm, vec=face.normal * top, space=obj_matrix_local,
+ verts=face.verts)
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ elif face_type == "stepped":
+ Stepped(spike_base_width=self.spike_base_width,
+ base_height_inset=self.base_height_inset,
+ top_spike=self.second_height,
+ top_extra_height=self.top_extra_height,
+ use_relative_offset=self.use_relative, with_spike=self.step_with_real_spike)
+
+ elif face_type == "open_inset":
+ startinfo = prepare(self, context, self.remove_start_faces)
+ bm = startinfo['bm']
+
+ # PKHG>INFO adjust for relative, via areas
+ t = self.move_inside
+ areas = startinfo['areas']
+ base_height = self.base_height
+ base_heights = None
+ distance = None
+ if self.use_relative:
+ distance = [min(t * area, 1.0) for i, area in enumerate(areas)]
+ base_heights = [base_height * area for i, area in enumerate(areas)]
+ else:
+ distance = [t] * len(areas)
+ base_heights = [base_height] * len(areas)
+
+ rings = startinfo['rings']
+ centers = startinfo['centers']
+ normals = startinfo['normals']
+ for i in range(len(rings)):
+ make_one_inset(self, context, bm=bm, ringvectors=rings[i],
+ center=centers[i], normal=normals[i],
+ t=distance[i], base_height=base_heights[i])
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ elif face_type == "with_base":
+ startinfo = prepare(self, context, self.remove_start_faces)
+ bm = startinfo['bm']
+ obj = startinfo['obj']
+ object_matrix = obj.matrix_local
+
+ # PKHG>INFO for relative (using areas)
+ t = self.move_inside
+ areas = startinfo['areas']
+ base_height = self.base_height
+ distance = None
+ base_heights = None
+
+ if self.use_relative:
+ distance = [min(t * area, 1.0) for i, area in enumerate(areas)]
+ base_heights = [base_height * area for i, area in enumerate(areas)]
+ else:
+ distance = [t] * len(areas)
+ base_heights = [base_height] * len(areas)
+
+ next_rings = []
+ rings = startinfo['rings']
+ centers = startinfo['centers']
+ normals = startinfo['normals']
+ for i in range(len(rings)):
+ next_rings.append(make_one_inset(self, context, bm=bm, ringvectors=rings[i],
+ center=centers[i], normal=normals[i],
+ t=distance[i], base_height=base_heights[i]))
+
+ prepare_ring = extrude_edges(self, context, bm=bm, edge_l_l=next_rings)
+
+ second_height = self.second_height
+ width = self.width
+ vectors = [[ele.verts[:] for ele in edge] for edge in prepare_ring]
+ n_ring_vecs = []
+
+ for rings in vectors:
+ v = []
+ for edgv in rings:
+ v.extend(edgv)
+ # PKHF>INFO no double verts allowed, coming from two adjacents edges!
+ bm.verts.ensure_lookup_table()
+ vv = list(set([ele.index for ele in v]))
+
+ vvv = [bm.verts[i].co for i in vv]
+ n_ring_vecs.append(vvv)
+
+ for i, ring in enumerate(n_ring_vecs):
+ make_one_inset(self, context, bm=bm, ringvectors=ring,
+ center=centers[i], normal=normals[i],
+ t=width, base_height=base_heights[i] + second_height)
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ else:
+ if face_type == "clsd_vertical":
+ obj_name = context.active_object.name
+ ClosedVertical(name=obj_name, base_height=self.base_height,
+ use_relative_base_height=self.use_relative)
+
+ elif face_type == "open_vertical":
+ obj_name = context.active_object.name
+ OpenVertical(name=obj_name, base_height=self.base_height,
+ use_relative_base_height=self.use_relative)
+
+ elif face_type == "bar":
+ startinfo = prepare(self, context, self.remove_start_faces)
+
+ result = []
+ bm = startinfo['bm']
+ rings = startinfo['rings']
+ centers = startinfo['centers']
+ normals = startinfo['normals']
+ spike_base_width = self.spike_base_width
+ for i, ring in enumerate(rings):
+ result.append(make_one_inset(self, context, bm=bm,
+ ringvectors=ring, center=centers[i],
+ normal=normals[i], t=spike_base_width))
+
+ next_ring_edges_list = extrude_edges(self, context, bm=bm,
+ edge_l_l=result)
+ top_spike = self.top_spike
+ fac = top_spike
+ object_matrix = startinfo['obj'].matrix_local
+ for i in range(len(next_ring_edges_list)):
+ translate_ONE_ring(self, context, bm=bm,
+ object_matrix=object_matrix,
+ ring_edges=next_ring_edges_list[i],
+ normal=normals[i], distance=fac)
+
+ next_ring_edges_list_2 = extrude_edges(self, context, bm=bm,
+ edge_l_l=next_ring_edges_list)
+
+ top_extra_height = self.top_extra_height
+ for i in range(len(next_ring_edges_list_2)):
+ move_corner_vecs_outside(self, context, bm=bm,
+ edge_list=next_ring_edges_list_2[i],
+ center=centers[i], normal=normals[i],
+ base_height_erlier=fac + top_extra_height,
+ distance=fac)
+ bpy.ops.mesh.select_mode(type="VERT")
+ bpy.ops.mesh.select_more()
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ return {'FINISHED'}
+
+
+class VIEW3D_Faces_Panel(Panel):
+ bl_label = "Face Extrude"
+ bl_space_type = "VIEW_3D"
+ bl_region_type = "TOOLS"
+ bl_category = "Tools"
+ bl_options = {"DEFAULT_CLOSED"}
+
+ @classmethod
+ def poll(cls, context):
+ result = False
+ active_object = context.active_object
+ if active_object:
+ mesh_objects_name = [el.name for el in bpy.data.objects if el.type == "MESH"]
+ if active_object.name in mesh_objects_name:
+ if active_object.mode == "OBJECT":
+ result = True
+ return result
+
+ def draw(self, context):
+ layout = self.layout
+
+ row = layout.split(0.8, align=True)
+ row.operator("mesh.add_faces_to_object", "Selected Faces")
+ row.operator("mesh.extra_tools_help",
+ icon="LAYER_USED").help_ids = "pkhg_faces"
+
+
+def find_one_ring(sel_vertices):
+ ring0 = sel_vertices.pop(0)
+ to_delete = []
+
+ for i, edge in enumerate(sel_vertices):
+ len_nu = len(ring0)
+ if len(ring0 - edge) < len_nu:
+ to_delete.append(i)
+ ring0 = ring0.union(edge)
+
+ to_delete.reverse()
+
+ for el in to_delete:
+ sel_vertices.pop(el)
+
+ return (ring0, sel_vertices)
+
+
+class Stepped:
+ def __init__(self, spike_base_width=0.5, base_height_inset=0.0, top_spike=0.2,
+ top_relative=False, top_extra_height=0, use_relative_offset=False, with_spike=False):
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
+ use_edge_rail=False, thickness=spike_base_width, depth=0, use_outset=True,
+ use_select_inset=False, use_individual=True, use_interpolate=True)
+
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=use_relative_offset,
+ use_edge_rail=False, thickness=top_extra_height, depth=base_height_inset,
+ use_outset=True, use_select_inset=False, use_individual=True, use_interpolate=True)
+
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=use_relative_offset,
+ use_edge_rail=False, thickness=spike_base_width, depth=0, use_outset=True,
+ use_select_inset=False, use_individual=True, use_interpolate=True)
+
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
+ use_edge_rail=False, thickness=0, depth=top_spike, use_outset=True,
+ use_select_inset=False, use_individual=True, use_interpolate=True)
+ if with_spike:
+ bpy.ops.mesh.merge(type='COLLAPSE')
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+class Spiked:
+ def __init__(self, spike_base_width=0.5, base_height_inset=0.0, top_spike=0.2, top_relative=False):
+
+ obj = bpy.context.active_object
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
+ use_edge_rail=False, thickness=spike_base_width, depth=base_height_inset,
+ use_outset=True, use_select_inset=False, use_individual=True, use_interpolate=True)
+
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=top_relative,
+ use_edge_rail=False, thickness=0, depth=top_spike, use_outset=True,
+ use_select_inset=False, use_individual=True, use_interpolate=True)
+
+ bm = bmesh.from_edit_mesh(obj.data)
+ bpy.ops.mesh.merge(type='COLLAPSE')
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+class ClosedVertical:
+ def __init__(self, name="Plane", base_height=1, use_relative_base_height=False):
+ obj = bpy.data.objects[name]
+
+ bm = bmesh.new()
+ bm.from_mesh(obj.data)
+ # PKHG>INFO deselect chosen faces
+ sel = [f for f in bm.faces if f.select]
+ for f in sel:
+ f.select = False
+ res = bmesh.ops.extrude_discrete_faces(bm, faces=sel)
+ # PKHG>INFO select extruded faces
+ for f in res['faces']:
+ f.select = True
+
+ factor = base_height
+ for face in res['faces']:
+ if use_relative_base_height:
+ area = face.calc_area()
+ factor = area * base_height
+ else:
+ factor = base_height
+ for el in face.verts:
+ tmp = el.co + face.normal * factor
+ el.co = tmp
+
+ me = bpy.data.meshes[name]
+ bm.to_mesh(me)
+ bm.free()
+
+
+class OpenVertical:
+ def __init__(self, name="Plane", base_height=1, use_relative_base_height=False):
+
+ obj = bpy.data.objects[name]
+ bm = bmesh.new()
+ bm.from_mesh(obj.data)
+ # PKHG>INFO deselect chosen faces
+ sel = [f for f in bm.faces if f.select]
+ for f in sel:
+ f.select = False
+ res = bmesh.ops.extrude_discrete_faces(bm, faces=sel)
+ # PKHG>INFO select extruded faces
+ for f in res['faces']:
+ f.select = True
+
+ # PKHG>INFO adjust extrusion by a vector
+ factor = base_height
+ for face in res['faces']:
+ if use_relative_base_height:
+ area = face.calc_area()
+ factor = area * base_height
+ else:
+ factor = base_height
+ for el in face.verts:
+ tmp = el.co + face.normal * factor
+ el.co = tmp
+
+ me = bpy.data.meshes[name]
+ bm.to_mesh(me)
+ bm.free()
+
+ bpy.ops.object.editmode_toggle()
+ bpy.ops.mesh.delete(type='FACE')
+ bpy.ops.object.editmode_toggle()
+
+
+class StripFaces:
+ def __init__(self, use_boundary=True, use_even_offset=True, use_relative_offset=False,
+ use_edge_rail=True, thickness=0.0, depth=0.0, use_outset=False,
+ use_select_inset=False, use_individual=True, use_interpolate=True):
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.ops.mesh.inset(use_boundary=use_boundary, use_even_offset=True, use_relative_offset=False,
+ use_edge_rail=True, thickness=thickness, depth=depth, use_outset=use_outset,
+ use_select_inset=use_select_inset, use_individual=use_individual,
+ use_interpolate=use_interpolate)
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+ # PKHG>IMFO only 3 parameters inc execution context supported!!
+ if False:
+ bpy.ops.mesh.inset(use_boundary, use_even_offset, use_relative_offset, use_edge_rail,
+ thickness, depth, use_outset, use_select_inset, use_individual, use_interpolate)
+ elif type == 0:
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
+ use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
+ use_select_inset=False, use_individual=True, use_interpolate=True)
+ elif type == 1:
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=True, use_relative_offset=False,
+ use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
+ use_select_inset=False, use_individual=True, use_interpolate=False)
+
+ bpy.ops.mesh.delete(type='FACE')
+
+ elif type == 2:
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=False, use_relative_offset=True,
+ use_edge_rail=True, thickness=thickness, depth=depth, use_outset=False,
+ use_select_inset=False, use_individual=True, use_interpolate=False)
+
+ bpy.ops.mesh.delete(type='FACE')
+
+ elif type == 3:
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=False, use_relative_offset=True,
+ use_edge_rail=True, thickness=depth, depth=thickness, use_outset=False,
+ use_select_inset=False, use_individual=True, use_interpolate=True)
+
+ bpy.ops.mesh.delete(type='FACE')
+ elif type == 4:
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=False, use_relative_offset=True,
+ use_edge_rail=True, thickness=thickness, depth=depth, use_outset=True,
+ use_select_inset=False, use_individual=True, use_interpolate=True)
+
+ bpy.ops.mesh.inset(use_boundary=True, use_even_offset=False, use_relative_offset=True,
+ use_edge_rail=True, thickness=thickness, depth=depth, use_outset=True,
+ use_select_inset=False, use_individual=True, use_interpolate=True)
+
+ bpy.ops.mesh.delete(type='FACE')
+
+ bpy.ops.object.mode_set(mode='OBJECT')
+
+
+def check_is_selected():
+ is_selected = False
+ for face in bpy.context.active_object.data.polygons:
+ if face.select:
+ is_selected = True
+ break
+ return is_selected
+
+
+def prepare(self, context, remove_start_faces=True):
+ """
+ Start for a face selected change of faces
+ select an object of type mesh, with activated several (all) faces
+ """
+ obj = bpy.context.scene.objects.active
+ bpy.ops.object.mode_set(mode='OBJECT')
+ selectedpolygons = [el for el in obj.data.polygons if el.select]
+
+ # PKHG>INFO copies of the vectors are needed, otherwise Blender crashes!
+ centers = [face.center for face in selectedpolygons]
+ centers_copy = [Vector((el[0], el[1], el[2])) for el in centers]
+ normals = [face.normal for face in selectedpolygons]
+ normals_copy = [Vector((el[0], el[1], el[2])) for el in normals]
+ vertindicesofpolgons = [[vert for vert in face.vertices] for face in selectedpolygons]
+ vertVectorsOfSelectedFaces = [[obj.data.vertices[ind].co for ind in vertIndiceofface]
+ for vertIndiceofface in vertindicesofpolgons]
+ vertVectorsOfSelectedFaces_copy = [[Vector((el[0], el[1], el[2])) for el in listofvecs]
+ for listofvecs in vertVectorsOfSelectedFaces]
+
+ bpy.ops.object.mode_set(mode='EDIT')
+ bm = bmesh.from_edit_mesh(obj.data)
+ selected_bm_faces = [ele for ele in bm.faces if ele.select]
+ selected_edges_per_face_ind = [[ele.index for ele in face.edges] for face in selected_bm_faces]
+ indices = [el.index for el in selectedpolygons]
+ selected_faces_areas = [bm.faces[:][i] for i in indices]
+ tmp_area = [el.calc_area() for el in selected_faces_areas]
+
+ # PKHG>INFO, selected faces are removed, only their edges are used!
+ if remove_start_faces:
+ bpy.ops.mesh.delete(type='ONLY_FACE')
+ bpy.ops.object.mode_set(mode='OBJECT')
+ obj.data.update()
+ bpy.ops.object.mode_set(mode='EDIT')
+ bm = bmesh.from_edit_mesh(obj.data)
+ bm.verts.ensure_lookup_table()
+ bm.faces.ensure_lookup_table()
+
+ start_ring_raw = [[bm.verts[ind].index for ind in vertIndiceofface]
+ for vertIndiceofface in vertindicesofpolgons]
+ start_ring = []
+
+ for el in start_ring_raw:
+ start_ring.append(set(el))
+ bm.edges.ensure_lookup_table()
+
+ bm_selected_edges_l_l = [[bm.edges[i] for i in bm_ind_list] for bm_ind_list in selected_edges_per_face_ind]
+
+ result = {'obj': obj, 'centers': centers_copy, 'normals': normals_copy,
+ 'rings': vertVectorsOfSelectedFaces_copy, 'bm': bm,
+ 'areas': tmp_area, 'startBMRingVerts': start_ring,
+ 'base_edges': bm_selected_edges_l_l}
+ return result
+
+
+def make_one_inset(self, context, bm=None, ringvectors=None, center=None,
+ normal=None, t=None, base_height=0):
+ # a face will get 'inserted' faces to create (normaly) a hole if t is > 0 and < 1)
+ tmp = []
+
+ for el in ringvectors:
+ tmp.append((el * (1 - t) + center * t) + normal * base_height)
+
+ tmp = [bm.verts.new(v) for v in tmp] # the new corner bmvectors
+ # PKHG>INFO so to say sentinells, to use ONE for ...
+ tmp.append(tmp[0])
+ vectorsFace_i = [bm.verts.new(v) for v in ringvectors]
+ vectorsFace_i.append(vectorsFace_i[0])
+ myres = []
+ for ii in range(len(vectorsFace_i) - 1):
+ # PKHG>INFO next line: sequence is important! for added edge
+ bmvecs = [vectorsFace_i[ii], vectorsFace_i[ii + 1], tmp[ii + 1], tmp[ii]]
+ res = bm.faces.new(bmvecs)
+ myres.append(res.edges[2])
+ myres[-1].select = True # PKHG>INFO to be used later selected!
+ return (myres)
+
+
+def extrude_faces(self, context, bm=None, face_l=None):
+ # to make a ring extrusion
+ res = bmesh.ops.extrude_discrete_faces(bm, faces=face_l)['faces']
+
+ for face in res:
+ face.select = True
+ return res
+
+
+def extrude_edges(self, context, bm=None, edge_l_l=None):
+ # to make a ring extrusion
+ all_results = []
+ for edge_l in edge_l_l:
+ for edge in edge_l:
+ edge.select = False
+ res = bmesh.ops.extrude_edge_only(bm, edges=edge_l)
+ tmp = [ele for ele in res['geom'] if isinstance(ele, bmesh.types.BMEdge)]
+ for edge in tmp:
+ edge.select = True
+ all_results.append(tmp)
+ return all_results
+
+
+def translate_ONE_ring(self, context, bm=None, object_matrix=None, ring_edges=None,
+ normal=(0, 0, 1), distance=0.5):
+ # translate a ring in given (normal?!) direction with given (global) amount
+ tmp = []
+ for edge in ring_edges:
+ tmp.extend(edge.verts[:])
+ # PKHG>INFO no double vertices allowed by bmesh!
+ tmp = set(tmp)
+ tmp = list(tmp)
+ bmesh.ops.translate(bm, vec=normal * distance, space=object_matrix, verts=tmp)
+ # PKHG>INFO relevant edges will stay selected
+ return ring_edges
+
+
+def move_corner_vecs_outside(self, context, bm=None, edge_list=None, center=None, normal=None,
+ base_height_erlier=0.5, distance=0.5):
+ # move corners (outside meant mostly) dependent on the parameters
+ tmp = []
+ for edge in edge_list:
+ tmp.extend([ele for ele in edge.verts if isinstance(ele, bmesh.types.BMVert)])
+ # PKHG>INFO to remove vertices, they are all used twice in the ring!
+ tmp = set(tmp)
+ tmp = list(tmp)
+
+ for i in range(len(tmp)):
+ vec = tmp[i].co
+ direction = vec + (vec - (normal * base_height_erlier + center)) * distance
+ tmp[i].co = direction
+
+
+def register():
+ bpy.utils.register_module(__name__)
+
+
+def unregister():
+ bpy.utils.unregister_module(__name__)
+
+
+if __name__ == "__main__":
+ register()