Newer
Older
# ##### BEGIN GPL LICENSE BLOCK #####
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
bl_info = {
'name': "Kjartans Scripts",
'author': "Kjartan Tysdal",
'location': '"Shift+Q" and also in EditMode "W-Specials/ KTools"',
'description': "Adds my personal collection of small handy scripts (mostly modeling tools)",
'category': "Mesh",
'version': (0, 2, 8),
'wiki_url': 'http://www.kjartantysdal.com/scripts',
}
meta-androcto
committed
from bpy.props import (
StringProperty,
IntProperty,
FloatProperty,
EnumProperty,
BoolProperty,
BoolVectorProperty,
FloatVectorProperty,
)
def checkScale(): # check if scale is 0 on any of the axis, if it is then set it to 0.01
y = -1
for x in bpy.context.object.scale:
y += 1
if x == 0.0:
bpy.context.object.scale[y] = 0.01
class lattice_to_selection(bpy.types.Operator):
"""Add a lattice deformer to the selection"""
bl_idname = "object.lattice_to_selection"
bl_label = "Lattice to Selection"
bl_options = {'REGISTER', 'UNDO'}
meta-androcto
committed
name = "Local",
description = "Orient the lattice to the active object",
default = True
)
meta-androcto
committed
name = "Parent to Lattice",
description = "Parents all the objects to the Lattice",
default = False
)
move_first: BoolProperty(name = "First in Modifier Stack", description = "Moves the lattice modifier to be first in the stack", default = False)
interpolation: bpy.props.EnumProperty(
meta-androcto
committed
items= (('KEY_LINEAR', 'Linear', 'Linear Interpolation'),
('KEY_CARDINAL', 'Cardinal', 'Cardinal Interpolation'),
('KEY_CATMULL_ROM', 'Catmull Rom', 'Catmull Rom Interpolation'),
('KEY_BSPLINE', 'BSpline', 'BSpline Interpolation')),
name = "Interpolation", default = 'KEY_BSPLINE')
seg_u: IntProperty( name = "Lattice U", default = 2, soft_min = 2)
seg_v: IntProperty( name = "Lattice V", default = 2, soft_min = 2 )
seg_w: IntProperty( name = "Lattice W", default = 2, soft_min = 2 )
apply_rot = not self.apply_rot # Global vs Local
parent_to = self.parent_to # Parents all the objects to the Lattice
move_first = self.move_first # moves the lattice modifier to be first in the stack
interpolation = self.interpolation
# check if there exists an active object
if bpy.context.view_layer.objects.active:
active_obj = bpy.context.view_layer.objects.active.name
else:
for x in bpy.context.selected_objects:
if bpy.data.objects[x.name].type == 'MESH':
bpy.context.view_layer.objects.active = bpy.data.objects[x.name]
active_obj = bpy.context.view_layer.objects.active.name
if bpy.data.objects[active_obj].type != 'MESH':
self.report({'ERROR'}, "Make sure the active object is a Mesh")
return {'CANCELLED'}
mode = bpy.context.active_object.mode
# check if object type is not MESH and then deselect it
for x in bpy.context.selected_objects:
if bpy.data.objects[x.name].type != 'MESH':
bpy.data.objects[x.name].select_set(False)
org_objs = bpy.context.selected_objects
# remove any modifiers
if bpy.context.object.modifiers:
for x in bpy.context.object.modifiers:
bpy.ops.object.modifier_remove(modifier=x.name)
if len(bpy.context.selected_objects) > 1:
bpy.ops.object.join()
# create tmp:object and store its location, rotation and dimensions
bpy.ops.object.transform_apply(location=False, rotation=apply_rot, scale=True)
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS')
lattice_loc = bpy.context.object.location
lattice_rot = bpy.context.object.rotation_euler
bbox_size = bpy.context.object.dimensions
tmp_obj = bpy.context.object.name
# create the lattice object with the lattice_loc and rot
bpy.ops.object.add(radius=1, type='LATTICE', view_align=False, enter_editmode=False, location=lattice_loc, rotation=lattice_rot)
lattice_obj = bpy.context.object
# set dimensions / bounding box size
bpy.context.object.scale = bbox_size
bpy.ops.object.select_all(action='DESELECT')
# select and delete the tmp_object
bpy.data.objects[tmp_obj].select_set(True)
bpy.ops.object.delete(use_global=False)
# select all the original objects and assign the lattice deformer
for i in org_objs:
if bpy.data.objects[i.name].type == 'MESH' :
bpy.context.view_layer.objects.active = bpy.data.objects[i.name]
bpy.data.objects[i.name].select_set(True)
bpy.ops.object.modifier_add(type='LATTICE')
lattice_name = bpy.context.object.modifiers[len(bpy.context.object.modifiers)-1].name
bpy.context.object.modifiers[lattice_name].object = lattice_obj
if move_first == True:
for x in bpy.context.object.modifiers:
bpy.ops.object.modifier_move_up(modifier=lattice_name)
else:
bpy.data.objects[i.name].select_set(True)
bpy.data.objects[lattice_obj.name].select_set(True)
bpy.context.view_layer.objects.active = bpy.data.objects[lattice_obj.name]
bpy.ops.object.parent_set(type='OBJECT', keep_transform=True)
else:
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects[lattice_obj.name].select_set(True)
bpy.context.view_layer.objects.active = bpy.data.objects[lattice_obj.name]
bpy.context.object.data.interpolation_type_u = interpolation
bpy.context.object.data.interpolation_type_v = interpolation
bpy.context.object.data.interpolation_type_w = interpolation
bpy.context.object.data.points_u = self.seg_u
bpy.context.object.data.points_v = self.seg_v
bpy.context.object.data.points_w = self.seg_w
org_objs = bpy.context.selected_objects
# Add vertex group and store its name in a variable
bpy.ops.object.vertex_group_assign_new()
v_id = len(bpy.context.object.vertex_groups)-1
bpy.context.object.vertex_groups[v_id].name = 'tmp_lattice_to_selection'
v_group = bpy.context.object.vertex_groups[v_id].name
bpy.ops.mesh.duplicate()
bpy.ops.mesh.separate(type='SELECTED')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
for x in bpy.context.selected_objects:
if x not in org_objs:
tmp_obj = x.name
print(tmp_obj)
bpy.ops.object.select_all(action='DESELECT')
bpy.context.view_layer.objects.active = bpy.data.objects[tmp_obj]
bpy.data.objects[tmp_obj].select_set(True)
if bpy.context.object.modifiers:
for x in bpy.context.object.modifiers:
bpy.ops.object.modifier_remove(modifier=x.name)
bpy.ops.object.transform_apply(location=False, rotation=apply_rot, scale=True)
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS')
lattice_loc = bpy.context.object.location
lattice_rot = bpy.context.object.rotation_euler
bbox_size = bpy.context.object.dimensions
tmp_obj = bpy.context.object.name
bpy.ops.object.add(radius=1, type='LATTICE', view_align=False, enter_editmode=False, location=lattice_loc, rotation=lattice_rot)
lattice_obj = bpy.context.object
bpy.context.object.scale = bbox_size
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects[tmp_obj].select_set(True)
bpy.ops.object.delete(use_global=False)
bpy.context.view_layer.objects.active = bpy.data.objects[active_obj]
bpy.data.objects[active_obj].select_set(True)
bpy.ops.object.modifier_add(type='LATTICE')
lattice_name = bpy.context.object.modifiers[len(bpy.context.object.modifiers)-1].name
bpy.context.object.modifiers[lattice_name].object = lattice_obj
bpy.context.object.modifiers[lattice_name].vertex_group = v_group
if move_first == True:
for x in bpy.context.object.modifiers:
bpy.ops.object.modifier_move_up(modifier=lattice_name)
bpy.ops.object.select_all(action='DESELECT')
bpy.data.objects[lattice_obj.name].select_set(True)
bpy.context.view_layer.objects.active = bpy.data.objects[lattice_obj.name]
bpy.context.object.data.interpolation_type_u = interpolation
bpy.context.object.data.interpolation_type_v = interpolation
bpy.context.object.data.interpolation_type_w = interpolation
bpy.context.object.data.points_u = self.seg_u
bpy.context.object.data.points_v = self.seg_v
bpy.context.object.data.points_w = self.seg_w
def invoke( self, context, event ):
wm = context.window_manager
return wm.invoke_props_dialog( self )
#Adds Calculate Normals and Smooth to the Addon
class calc_normals(bpy.types.Operator):
"""Calculates and smooths normals."""
bl_idname = "mesh.calc_normals"
bl_label = "Calculate Normals"
bl_options = {'REGISTER', 'UNDO'}
invert: BoolProperty(name = "Invert Normals", description = "Inverts the normals.", default = False)
invert = self.invert
mode = bpy.context.active_object.mode
if mode == 'OBJECT':
sel = bpy.context.selected_objects
active = bpy.context.view_layer.objects.active.name
bpy.ops.object.shade_smooth()
for ob in sel:
ob = ob.name
bpy.context.view_layer.objects.active = bpy.data.objects[ob]
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.normals_make_consistent(inside=invert)
bpy.ops.object.editmode_toggle()
bpy.context.view_layer.objects.active = bpy.data.objects[active]
elif mode == 'EDIT':
bpy.ops.mesh.normals_make_consistent(inside=invert)
class snaptoaxis(bpy.types.Operator):
"""Snaps selected vertices to zero on the selected axis."""
bl_idname = "mesh.snaptoaxis"
bl_label = "Snap to Axis"
bl_options = {'REGISTER', 'UNDO'}
#worldspace = bpy.props.EnumProperty(items= (('OBJECT', 'Object Space', 'Snap to the object axis'),
# ('WORLD', 'World Space', 'Snap to the global axis')),
# name = "Object/World", default = 'OBJECT')
snap_x: BoolProperty(name = "Snap to X", description = "Snaps to zero in X. Also sets the axis for the mirror modifier if that button is turned on", default = True)
snap_y: BoolProperty(name = "Snap to Y", description = "Snaps to zero in Y. Also sets the axis for the mirror modifier if that button is turned on", default = False)
snap_z: BoolProperty(name = "Snap to Z", description = "Snaps to zero in Z. Also sets the axis for the mirror modifier if that button is turned on", default = False)
mirror_add: BoolProperty(name = "Add Mirror Modifier", description = "Adds a mirror modifer", default = False)
mirror_x: BoolProperty(name = "Mirror on X", description = "Sets the modifier to mirror on X", default = True)
mirror_y: BoolProperty(name = "Mirror on Y", description = "Sets the modifier to mirror on Y", default = False)
mirror_z: BoolProperty(name = "Mirror on Z", description = "Sets the modifier to mirror on Z", default = False)
clipping: BoolProperty(name = "Enable Clipping", description = "Prevents vertices from going through the mirror during transform", default = True)
def draw(self, context):
layout = self.layout
col = layout.column()
col_move = col.column(align=True)
row = col_move.row(align=True)
if self.snap_x:
row.prop(self, "snap_x", text = "X", icon='CHECKBOX_HLT')
else:
row.prop(self, "snap_x", text = "X", icon='CHECKBOX_DEHLT')
if self.snap_y:
row.prop(self, "snap_y", text = "Y", icon='CHECKBOX_HLT')
else:
row.prop(self, "snap_y", text = "Y", icon='CHECKBOX_DEHLT')
if self.snap_z:
row.prop(self, "snap_z", text = "Z", icon='CHECKBOX_HLT')
else:
row.prop(self, "snap_z", text = "Z", icon='CHECKBOX_DEHLT')
col_move = col.column(align=True)
col_move.prop(self, "mirror_add", icon = 'MODIFIER')
row = col_move.row(align=True)
row.active = self.mirror_add
if self.mirror_x:
row.prop(self, "mirror_x", text = "X", icon='CHECKBOX_HLT')
else:
row.prop(self, "mirror_x", text = "X", icon='CHECKBOX_DEHLT')
if self.mirror_y:
row.prop(self, "mirror_y", text = "Y", icon='CHECKBOX_HLT')
else:
row.prop(self, "mirror_y", text = "Y", icon='CHECKBOX_DEHLT')
if self.mirror_z:
row.prop(self, "mirror_z", text = "Z", icon='CHECKBOX_HLT')
else:
row.prop(self, "mirror_z", text = "Z", icon='CHECKBOX_DEHLT')
col = col.column()
col.active = self.mirror_add
def execute(self, context):
mode = bpy.context.active_object.mode
mirror_find = bpy.context.object.modifiers.find('Mirror')
run = True
if mode == 'EDIT':
loc = bpy.context.object.location
me = bpy.context.object.data
bm = bmesh.from_edit_mesh(me)
for v in bm.verts:
if v.select:
if self.snap_x == True:
v.co.x = 0
if self.snap_y == True:
v.co.y = 0
if self.snap_z == True:
v.co.z = 0
bmesh.update_edit_mesh(me, True, False)
if mirror_find <= -1:
bpy.ops.object.modifier_add(type='MIRROR')
bpy.context.object.modifiers['Mirror'].show_viewport = True
bpy.context.object.modifiers["Mirror"].use_clip = self.clipping
bpy.context.object.modifiers["Mirror"].use_x = self.mirror_x
bpy.context.object.modifiers["Mirror"].use_y = self.mirror_y
bpy.context.object.modifiers["Mirror"].use_z = self.mirror_z
return {'FINISHED'}
#Adds QuickBool to the Addon
class quickbool(bpy.types.Operator):
"""Quickly carves out the selected polygons. Works best with manifold meshes."""
bl_idname = "mesh.quickbool"
bl_label = "Quick Bool"
bl_options = {'REGISTER', 'UNDO'}
del_bool: BoolProperty(name="Delete BoolMesh", description="Deletes the objects used for the boolean operation.", default= True)
move_to: BoolProperty(name="Move to layer 10", description="Moves the objects used for the boolean operation to layer 10", default= False)
operation: EnumProperty(items= (('UNION', 'Union', 'Combines'),
('INTERSECT', 'Intersect', 'Keep the part that overlaps'),
('DIFFERENCE', 'Difference', 'Cuts out')),
name = "Operation", default = 'DIFFERENCE')
def draw(self, context):
layout = self.layout
col = layout.column()
col.prop(self, "del_bool")
col = col.column()
col.active = self.del_bool == False
col = layout.column()
col.prop(self, "operation")
del_bool = self.del_bool
move_to = self.move_to
mode = bpy.context.active_object.mode
if mode == 'EDIT':
#Boolean From Edit mode
bpy.ops.mesh.select_linked()
bpy.ops.mesh.separate(type='SELECTED')
bpy.ops.object.editmode_toggle()
#get name of Original+Bool object
original = bpy.context.selected_objects[1].name
bool = bpy.context.selected_objects[0].name
#perform boolean
bpy.ops.object.modifier_add(type='BOOLEAN')
bpy.context.object.modifiers["Boolean"].object = bpy.data.objects[bool]
bpy.context.object.modifiers["Boolean"].operation = self.operation
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
#delete Bool object
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=bool)
bpy.context.view_layer.objects.active = bpy.data.objects[bool]
#Delete all geo inside Shrink_Object
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.delete(type='VERT')
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.object.delete()
#re-enter edit mode on Original object
bpy.context.view_layer.objects.active = bpy.data.objects[original]
bpy.ops.object.select_pattern(pattern=original)
bpy.ops.object.editmode_toggle()
else:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
original = bpy.context.active_object.name
bool = bpy.context.selected_objects
for x in bool:
x = x.name
if x != original:
list.append(x)
for name in list:
#Perform Boolean
bpy.ops.object.modifier_add(type='BOOLEAN')
bpy.context.object.modifiers["Boolean"].object = bpy.data.objects[name]
bpy.context.object.modifiers["Boolean"].operation = self.operation
bpy.ops.object.modifier_apply(apply_as='DATA', modifier="Boolean")
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=name)
bpy.context.view_layer.objects.active = bpy.data.objects[name]
#Delete all geo inside Shrink_Object
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.delete(type='VERT')
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.object.delete(use_global=False)
bpy.context.view_layer.objects.active = bpy.data.objects[original]
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=name)
bpy.context.view_layer.objects.active = bpy.data.objects[name]
bpy.context.object.display_type = 'WIRE'
# Move to garbage layer
if move_to == True:
bpy.ops.object.move_to_layer(layers=(False, False, False, False, False, False, False, False, False, True, False, False, False, False, False, False, False, False, False, False))
bpy.context.view_layer.objects.active = bpy.data.objects[original]
bpy.ops.object.mode_set(mode=mode, toggle=False)
class autotubes(bpy.types.Operator):
"""Creates a spline tube based on selected edges"""
bl_idname = "mesh.autotubes"
bl_label = "Auto Tubes"
bl_options = {'REGISTER', 'UNDO'}
bevel: FloatProperty(name="Tube Width", description="Change width of the tube.", default=0.1, min = 0)
res: IntProperty(name="Tube Resolution", description="Change resolution of the tube.", default=2, min = 0, max = 20)
mode = bpy.context.active_object.mode
type = bpy.context.active_object.type
if mode == 'EDIT' and type == 'MESH':
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
bpy.ops.object.duplicate()
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.select_all(action='INVERT')
bpy.ops.mesh.delete(type='EDGE')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
bpy.ops.object.subdivision_set(level=0)
bpy.ops.object.convert(target='CURVE')
bpy.context.object.data.fill_mode = 'FULL'
bpy.context.object.data.bevel_depth = 0.1
bpy.context.object.data.splines[0].use_smooth = True
bpy.context.object.data.bevel_resolution = 2
bpy.ops.object.shade_smooth()
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.curve.spline_type_set(type='BEZIER')
bpy.context.object.data.bevel_depth = bevel
bpy.context.object.data.bevel_resolution = res
#bpy.ops.transform.transform(('INVOKE_DEFAULT'), mode='CURVE_SHRINKFATTEN')
bpy.context.object.data.bevel_depth = bevel
bpy.context.object.data.bevel_resolution = res
elif mode != 'EDIT' and type == 'MESH':
self.report({'ERROR'}, "This one only works in Edit mode")
return {'CANCELLED'}
class basicRename(bpy.types.Operator):
"""Renames everything to Banana"""
bl_idname = "object.basic_rename"
bl_label = "Basic Renamer"
bl_options = {'REGISTER', 'UNDO'}
name: StringProperty(name="Rename", description="Rename selected objects", default="banana")
padding: IntProperty(name = "Number Padding", description = "Adds how many padded numbers", default = 3, min = 1, max = 8)
prefix: StringProperty(name="Pre Fix", description="Adds a Prefix to the name", default="")
post_ob: StringProperty(name="Post Fix Object", description="Adds ending to object name", default="_MDL")
post_data: StringProperty(name="Post Fix Data", description="Adds ending to data name", default="_DATA")
# The original script
obj = bpy.context.selected_objects
name = self.name
padding = self.padding
prefix = self.prefix
post_ob = self.post_ob
post_data = self.post_data
number = 0
for item in obj:
number += 1
item.name = "%s%s_%s%s" %(str(prefix), str(name), str(number).zfill(padding), str(post_ob))
item.data.name = "%s%s_%s%s" %(str(prefix), str(name), str(number).zfill(padding), str(post_data))
return {'FINISHED'}
class cut_tool(bpy.types.Operator):
"""Context sensitive cut tool"""
bl_idname = "mesh.cut_tool"
bl_label = "Cut Tool"
bl_options = {'REGISTER', 'UNDO'}
cuts: IntProperty(name="Number of Cuts", description="Change the number of cuts.", default=1, min = 1, soft_max = 10)
loopcut: BoolProperty(name="Insert LoopCut", description="Makes a loop cut based on the selected edges", default= False)
smoothness: FloatProperty(name="Smoothness", description="Change the smoothness.", default=0, min = 0, soft_max = 1)
quad_corners: bpy.props.EnumProperty(items= (('INNERVERT', 'Inner Vert', 'How to subdivide quad corners'),
('PATH', 'Path', 'How to subdivide quad corners'),
('STRAIGHT_CUT', 'Straight Cut', 'How to subdivide quad corners'),
('FAN', 'Fan', 'How to subdivide quad corners')),
name = "Quad Corner Type", default = 'STRAIGHT_CUT')
quad_corners = self.quad_corners
cuts = self.cuts
loopcut = self.loopcut
smoothness = self.smoothness
mode = bpy.context.active_object.mode
if mode == 'EDIT':
sel_mode = bpy.context.tool_settings.mesh_select_mode[:]
#Checks and stores if any Vert, Edge or Face is selected.
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
bm = bmesh.new() # create an empty BMesh
bm.from_mesh(me) # fill it in from a Mesh
sel = []
edge_sel = []
vert_sel = []
for v in bm.faces:
if v.select:
sel.append(v.index)
for v in bm.edges:
if v.select:
edge_sel.append(v.index)
for v in bm.verts:
if v.select:
vert_sel.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
if len(sel) == 0 and len(edge_sel) == 0 and len(vert_sel) == 0 :
bpy.ops.mesh.knife_tool("INVOKE_DEFAULT")
if sel_mode[2] == True and len(sel) > 1:
vgrp = bpy.context.object.vertex_groups.active_index
#Store the Hidden Polygons
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.object.vertex_group_assign_new()
tmp_hidden = bpy.context.object.vertex_groups.active_index
bpy.ops.mesh.select_all(action='DESELECT')
#Select faces to be cut
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = bpy.context.active_object.data.polygons
for f in sel:
mesh[f].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.hide(unselected=True)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.region_to_loop()
#Store Boundry Edges
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
boundry_edge = []
for v in bm.edges:
if v.select:
boundry_edge.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
#Store Cut Edges
bpy.ops.mesh.select_all(action='INVERT')
bpy.ops.mesh.loop_multi_select(ring=True)
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
cut_edges = []
for v in bm.edges:
if v.select:
cut_edges.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
#Store Intersection edges
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='FACE')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
int_edges = []
for v in bm.edges:
if v.select:
int_edges.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
#Modify Lists
for x in int_edges:
if x in boundry_edge:
cut_edges.remove(x)
bpy.ops.mesh.select_all(action='DESELECT')
#Select the new edges to cut
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = bpy.context.active_object.data.edges
for f in cut_edges:
mesh[f].select = True
#Perform cut and select the cut line.
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.subdivide(number_cuts = cuts, smoothness = smoothness, quadcorner = quad_corners)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.region_to_loop()
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
bpy.ops.mesh.select_all(action='INVERT')
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='EDGE')
bpy.ops.mesh.loop_multi_select(ring=False)
#Store cut line.
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
me = bpy.context.object.data
cut_line = []
for v in bm.edges:
if v.select:
cut_line.append(v.index)
bm.to_mesh(me)
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.reveal()
bpy.ops.mesh.select_all(action='DESELECT')
bpy.context.object.vertex_groups.active_index = tmp_hidden
bpy.ops.object.vertex_group_select()
bpy.ops.mesh.hide(unselected=True)
bpy.ops.mesh.select_all(action='DESELECT')
#Select Cutline
if cuts <= 1:
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
mesh = bpy.context.active_object.data.edges
for f in cut_line:
mesh[f].select = True
bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.object.vertex_group_remove(all=False)
bpy.ops.mesh.select_mode(use_extend=True, use_expand=False, type='FACE')
elif sel_mode[0] == True and len(vert_sel) >= 2:
bpy.ops.mesh.vert_connect_path()
elif sel_mode[1] == True and loopcut == False and len(edge_sel) != 0:
bpy.ops.mesh.subdivide(number_cuts = cuts, smoothness = smoothness, quadcorner = quad_corners)
elif sel_mode[1] == True and loopcut == True and len(edge_sel) != 0:
bpy.ops.mesh.loop_multi_select(ring=True)
bpy.ops.mesh.subdivide(number_cuts = cuts, smoothness = smoothness, quadcorner = quad_corners)
else:
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.mesh.knife_tool("INVOKE_DEFAULT")
else:
self.report({'ERROR'}, "This one only works in Edit mode")
class customAutoSmooth(bpy.types.Operator):
"""Set AutoSmooth angle"""
bl_idname = "object.custom_autosmooth"
bl_label = "Autosmooth"
bl_options = {'REGISTER', 'UNDO'}
angle: FloatProperty(name="AutoSmooth Angle", description="Set AutoSmooth angle", default= 30.0, min = 0.0, max = 180.0)
mode = bpy.context.active_object.mode
if mode != 'OBJECT':
bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
ob = bpy.context.selected_objects
angle = self.angle
angle = angle * (3.14159265359/180)
bpy.ops.object.shade_smooth()
for x in ob:
x = x.name
bpy.data.objects[x].data.use_auto_smooth = True
bpy.data.objects[x].data.auto_smooth_angle = angle
bpy.ops.object.mode_set(mode=mode, toggle=False)
class shrinkwrapSmooth(bpy.types.Operator):
"""Smooths the selected vertices while trying to keep the original shape with a shrinkwrap modifier. """
bl_idname = "mesh.shrinkwrap_smooth"
bl_label = "Shrinkwrap Smooth"
bl_options = {'REGISTER', 'UNDO'}
pin: BoolProperty(name="Pin Selection Border", description="Pins the outer edge of the selection.", default = True)
subsurf: IntProperty(name="Subsurf Levels", description="More reliable, but slower results", default = 0, min = 0, soft_max = 4)
def execute(self, context):
iterate = 6
pin = self.pin
data = bpy.context.object.data.name
# Set up for vertex weight
bpy.context.scene.tool_settings.vertex_group_weight = 1
v_grps = len(bpy.context.object.vertex_groups.items())
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
org_ob = bpy.context.object.name
# Create intermediate object
bpy.ops.object.mode_set(mode = 'OBJECT', toggle = False)
bpy.ops.mesh.primitive_plane_add(radius=1, view_align=False, enter_editmode=False)
bpy.context.object.data = bpy.data.meshes[data]
tmp_ob = bpy.context.object.name
bpy.ops.object.duplicate(linked=False)
shrink_ob = bpy.context.object.name
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=tmp_ob)
bpy.context.view_layer.objects.active = bpy.data.objects[tmp_ob]
bpy.ops.object.mode_set(mode = 'EDIT', toggle = False)
bpy.ops.mesh.select_mode(use_extend=False, use_expand=False, type='VERT')
if v_grps >= 1:
for x in range(v_grps):
bpy.ops.object.vertex_group_add()
if pin == True:
bpy.ops.object.vertex_group_assign_new()
org_id = bpy.context.object.vertex_groups.active_index
bpy.ops.object.vertex_group_assign_new()
sel = bpy.context.object.vertex_groups.active.name
sel_id = bpy.context.object.vertex_groups.active_index
bpy.ops.mesh.region_to_loop()
bpy.ops.object.vertex_group_remove_from(use_all_groups=False, use_all_verts=False)
bpy.ops.mesh.select_all(action='SELECT')
bpy.ops.mesh.region_to_loop()
bpy.ops.object.vertex_group_remove_from(use_all_groups=False, use_all_verts=False)
bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.vertex_group_select(sel_id)
else:
bpy.ops.object.vertex_group_assign_new()
sel = bpy.context.object.vertex_groups.active.name