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.scene.objects.active:
active_obj = bpy.context.scene.objects.active.name
else:
for x in bpy.context.selected_objects:
if bpy.data.objects[x.name].type == 'MESH':
bpy.context.scene.objects.active = bpy.data.objects[x.name]
active_obj = bpy.context.scene.objects.active.name
break
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.scene.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.scene.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.scene.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.scene.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.scene.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.scene.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.scene.objects.active.name
bpy.ops.object.shade_smooth()
for ob in sel:
ob = ob.name
bpy.context.scene.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.scene.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
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
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.scene.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.scene.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.scene.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.scene.objects.active = bpy.data.objects[original]
else:
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_pattern(pattern=name)
bpy.context.scene.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.scene.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.scene.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