Newer
Older
def poll(cls, context):
ob = context.active_object
return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
CoDEmanX
committed
def draw(self, context):
layout = self.layout
col = layout.column()
CoDEmanX
committed
col.prop(self, "interpolation")
col.prop(self, "input")
col.prop(self, "iterations")
col.prop(self, "regular")
CoDEmanX
committed
def invoke(self, context, event):
# load custom settings
settings_load(self)
return self.execute(context)
CoDEmanX
committed
def execute(self, context):
# initialise
global_undo, object, bm = initialise()
settings_write(self)
# check cache to see if we can save time
cached, single_loops, loops, derived, mapping = cache_read("Relax",
object, bm, self.input, False)
if cached:
derived, bm_mod = get_derived_bmesh(object, bm, context.scene)
else:
# find loops
derived, bm_mod, loops = get_connected_input(object, bm,
context.scene, self.input)
mapping = get_mapping(derived, bm, bm_mod, False, False, loops)
loops = check_loops(loops, mapping, bm_mod)
knots, points = relax_calculate_knots(loops)
CoDEmanX
committed
# saving cache for faster execution next time
if not cached:
cache_write("Relax", object, bm, self.input, False, False, loops,
derived, mapping)
CoDEmanX
committed
for iteration in range(int(self.iterations)):
# calculate splines and new positions
tknots, tpoints = relax_calculate_t(bm_mod, knots, points,
self.regular)
splines = []
for i in range(len(knots)):
splines.append(calculate_splines(self.interpolation, bm_mod,
tknots[i], knots[i]))
move = [relax_calculate_verts(bm_mod, self.interpolation,
tknots, knots, tpoints, points, splines)]
move_verts(object, bm, mapping, move, False, -1)
CoDEmanX
committed
# cleaning up
if derived:
bm_mod.free()
terminate(global_undo)
CoDEmanX
committed
return{'FINISHED'}
# space operator
class Space(bpy.types.Operator):
bl_idname = "mesh.looptools_space"
bl_label = "Space"
bl_description = "Space the vertices in a regular distrubtion on the loop"
bl_options = {'REGISTER', 'UNDO'}
CoDEmanX
committed
influence = bpy.props.FloatProperty(name = "Influence",
description = "Force of the tool",
default = 100.0,
min = 0.0,
max = 100.0,
precision = 1,
subtype = 'PERCENTAGE')
input = bpy.props.EnumProperty(name = "Input",
items = (("all", "Parallel (all)", "Also use non-selected "\
"parallel loops as input"),
("selected", "Selection","Only use selected vertices as input")),
description = "Loops that are spaced",
default = 'selected')
interpolation = bpy.props.EnumProperty(name = "Interpolation",
items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
("linear", "Linear", "Vertices are projected on existing edges")),
description = "Algorithm used for interpolation",
default = 'cubic')
lock_x = bpy.props.BoolProperty(name = "Lock X",
description = "Lock editing of the x-coordinate",
default = False)
lock_y = bpy.props.BoolProperty(name = "Lock Y",
description = "Lock editing of the y-coordinate",
default = False)
lock_z = bpy.props.BoolProperty(name = "Lock Z",
description = "Lock editing of the z-coordinate",
default = False)
CoDEmanX
committed
@classmethod
def poll(cls, context):
ob = context.active_object
return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
CoDEmanX
committed
def draw(self, context):
layout = self.layout
col = layout.column()
CoDEmanX
committed
col.prop(self, "interpolation")
col.prop(self, "input")
col.separator()
CoDEmanX
committed
col_move = col.column(align=True)
row = col_move.row(align=True)
if self.lock_x:
row.prop(self, "lock_x", text = "X", icon='LOCKED')
else:
row.prop(self, "lock_x", text = "X", icon='UNLOCKED')
if self.lock_y:
row.prop(self, "lock_y", text = "Y", icon='LOCKED')
else:
row.prop(self, "lock_y", text = "Y", icon='UNLOCKED')
if self.lock_z:
row.prop(self, "lock_z", text = "Z", icon='LOCKED')
else:
row.prop(self, "lock_z", text = "Z", icon='UNLOCKED')
col_move.prop(self, "influence")
CoDEmanX
committed
def invoke(self, context, event):
# load custom settings
settings_load(self)
return self.execute(context)
CoDEmanX
committed
def execute(self, context):
# initialise
global_undo, object, bm = initialise()
settings_write(self)
# check cache to see if we can save time
cached, single_loops, loops, derived, mapping = cache_read("Space",
object, bm, self.input, False)
if cached:
derived, bm_mod = get_derived_bmesh(object, bm, context.scene)
else:
# find loops
derived, bm_mod, loops = get_connected_input(object, bm,
context.scene, self.input)
mapping = get_mapping(derived, bm, bm_mod, False, False, loops)
loops = check_loops(loops, mapping, bm_mod)
CoDEmanX
committed
# saving cache for faster execution next time
if not cached:
cache_write("Space", object, bm, self.input, False, False, loops,
derived, mapping)
CoDEmanX
committed
move = []
for loop in loops:
# calculate splines and new positions
if loop[1]: # circular
loop[0].append(loop[0][0])
tknots, tpoints = space_calculate_t(bm_mod, loop[0][:])
splines = calculate_splines(self.interpolation, bm_mod,
tknots, loop[0][:])
move.append(space_calculate_verts(bm_mod, self.interpolation,
tknots, tpoints, loop[0][:-1], splines))
# move vertices to new locations
if self.lock_x or self.lock_y or self.lock_z:
lock = [self.lock_x, self.lock_y, self.lock_z]
else:
lock = False
move_verts(object, bm, mapping, move, lock, self.influence)
CoDEmanX
committed
# cleaning up
if derived:
bm_mod.free()
terminate(global_undo)
CoDEmanX
committed
return{'FINISHED'}
##########################################
####### GUI and registration #############
##########################################
# menu containing all tools
class VIEW3D_MT_edit_mesh_looptools(bpy.types.Menu):
bl_label = "LoopTools"
CoDEmanX
committed
def draw(self, context):
layout = self.layout
CoDEmanX
committed
layout.operator("mesh.looptools_bridge", text="Bridge").loft = False
layout.operator("mesh.looptools_circle")
layout.operator("mesh.looptools_curve")
layout.operator("mesh.looptools_flatten")
layout.operator("mesh.looptools_bridge", text="Loft").loft = True
layout.operator("mesh.looptools_relax")
layout.operator("mesh.looptools_space")
# panel containing all tools
class VIEW3D_PT_tools_looptools(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'
bl_context = "mesh_edit"
bl_label = "LoopTools"
def draw(self, context):
layout = self.layout
col = layout.column(align=True)
lt = context.window_manager.looptools
CoDEmanX
committed
# bridge - first line
split = col.split(percentage=0.15, align=True)
if lt.display_bridge:
split.prop(lt, "display_bridge", text="", icon='DOWNARROW_HLT')
else:
split.prop(lt, "display_bridge", text="", icon='RIGHTARROW')
split.operator("mesh.looptools_bridge", text="Bridge").loft = False
# bridge - settings
if lt.display_bridge:
box = col.column(align=True).box().column()
#box.prop(self, "mode")
CoDEmanX
committed
# top row
col_top = box.column(align=True)
row = col_top.row(align=True)
col_left = row.column(align=True)
col_right = row.column(align=True)
col_right.active = lt.bridge_segments != 1
col_left.prop(lt, "bridge_segments")
col_right.prop(lt, "bridge_min_width", text="")
# bottom row
bottom_left = col_left.row()
bottom_left.active = lt.bridge_segments != 1
bottom_left.prop(lt, "bridge_interpolation", text="")
bottom_right = col_right.row()
bottom_right.active = lt.bridge_interpolation == 'cubic'
bottom_right.prop(lt, "bridge_cubic_strength")
# boolean properties
col_top.prop(lt, "bridge_remove_faces")
CoDEmanX
committed
# override properties
col_top.separator()
row = box.row(align = True)
row.prop(lt, "bridge_twist")
row.prop(lt, "bridge_reverse")
CoDEmanX
committed
# circle - first line
split = col.split(percentage=0.15, align=True)
if lt.display_circle:
split.prop(lt, "display_circle", text="", icon='DOWNARROW_HLT')
else:
split.prop(lt, "display_circle", text="", icon='RIGHTARROW')
split.operator("mesh.looptools_circle")
# circle - settings
if lt.display_circle:
box = col.column(align=True).box().column()
box.prop(lt, "circle_fit")
box.separator()
CoDEmanX
committed
box.prop(lt, "circle_flatten")
row = box.row(align=True)
row.prop(lt, "circle_custom_radius")
row_right = row.row(align=True)
row_right.active = lt.circle_custom_radius
row_right.prop(lt, "circle_radius", text="")
box.prop(lt, "circle_regular")
box.separator()
CoDEmanX
committed
col_move = box.column(align=True)
row = col_move.row(align=True)
if lt.circle_lock_x:
row.prop(lt, "circle_lock_x", text = "X", icon='LOCKED')
else:
row.prop(lt, "circle_lock_x", text = "X", icon='UNLOCKED')
if lt.circle_lock_y:
row.prop(lt, "circle_lock_y", text = "Y", icon='LOCKED')
else:
row.prop(lt, "circle_lock_y", text = "Y", icon='UNLOCKED')
if lt.circle_lock_z:
row.prop(lt, "circle_lock_z", text = "Z", icon='LOCKED')
else:
row.prop(lt, "circle_lock_z", text = "Z", icon='UNLOCKED')
col_move.prop(lt, "circle_influence")
CoDEmanX
committed
# curve - first line
split = col.split(percentage=0.15, align=True)
if lt.display_curve:
split.prop(lt, "display_curve", text="", icon='DOWNARROW_HLT')
else:
split.prop(lt, "display_curve", text="", icon='RIGHTARROW')
split.operator("mesh.looptools_curve")
# curve - settings
if lt.display_curve:
box = col.column(align=True).box().column()
box.prop(lt, "curve_interpolation")
box.prop(lt, "curve_restriction")
box.prop(lt, "curve_boundaries")
box.prop(lt, "curve_regular")
box.separator()
CoDEmanX
committed
col_move = box.column(align=True)
row = col_move.row(align=True)
if lt.curve_lock_x:
row.prop(lt, "curve_lock_x", text = "X", icon='LOCKED')
else:
row.prop(lt, "curve_lock_x", text = "X", icon='UNLOCKED')
if lt.curve_lock_y:
row.prop(lt, "curve_lock_y", text = "Y", icon='LOCKED')
else:
row.prop(lt, "curve_lock_y", text = "Y", icon='UNLOCKED')
if lt.curve_lock_z:
row.prop(lt, "curve_lock_z", text = "Z", icon='LOCKED')
else:
row.prop(lt, "curve_lock_z", text = "Z", icon='UNLOCKED')
col_move.prop(lt, "curve_influence")
CoDEmanX
committed
# flatten - first line
split = col.split(percentage=0.15, align=True)
if lt.display_flatten:
split.prop(lt, "display_flatten", text="", icon='DOWNARROW_HLT')
else:
split.prop(lt, "display_flatten", text="", icon='RIGHTARROW')
split.operator("mesh.looptools_flatten")
# flatten - settings
if lt.display_flatten:
box = col.column(align=True).box().column()
box.prop(lt, "flatten_plane")
#box.prop(lt, "flatten_restriction")
box.separator()
CoDEmanX
committed
col_move = box.column(align=True)
row = col_move.row(align=True)
if lt.flatten_lock_x:
row.prop(lt, "flatten_lock_x", text = "X", icon='LOCKED')
else:
row.prop(lt, "flatten_lock_x", text = "X", icon='UNLOCKED')
if lt.flatten_lock_y:
row.prop(lt, "flatten_lock_y", text = "Y", icon='LOCKED')
else:
row.prop(lt, "flatten_lock_y", text = "Y", icon='UNLOCKED')
if lt.flatten_lock_z:
row.prop(lt, "flatten_lock_z", text = "Z", icon='LOCKED')
else:
row.prop(lt, "flatten_lock_z", text = "Z", icon='UNLOCKED')
col_move.prop(lt, "flatten_influence")
CoDEmanX
committed
split = col.split(percentage=0.15, align=True)
if lt.display_gstretch:
split.prop(lt, "display_gstretch", text="", icon='DOWNARROW_HLT')
else:
split.prop(lt, "display_gstretch", text="", icon='RIGHTARROW')
split.operator("mesh.looptools_gstretch")
# gstretch settings
if lt.display_gstretch:
box = col.column(align=True).box().column()
box.prop(lt, "gstretch_method")
box.prop(lt, "gstretch_delete_strokes")
CoDEmanX
committed
col_conv = box.column(align=True)
col_conv.prop(lt, "gstretch_conversion", text="")
if lt.gstretch_conversion == 'distance':
col_conv.prop(lt, "gstretch_conversion_distance")
elif lt.gstretch_conversion == 'limit_vertices':
row = col_conv.row(align=True)
row.prop(lt, "gstretch_conversion_min", text="Min")
row.prop(lt, "gstretch_conversion_max", text="Max")
elif lt.gstretch_conversion == 'vertices':
col_conv.prop(lt, "gstretch_conversion_vertices")
box.separator()
CoDEmanX
committed
col_move = box.column(align=True)
row = col_move.row(align=True)
if lt.gstretch_lock_x:
row.prop(lt, "gstretch_lock_x", text = "X", icon='LOCKED')
else:
row.prop(lt, "gstretch_lock_x", text = "X", icon='UNLOCKED')
if lt.gstretch_lock_y:
row.prop(lt, "gstretch_lock_y", text = "Y", icon='LOCKED')
else:
row.prop(lt, "gstretch_lock_y", text = "Y", icon='UNLOCKED')
if lt.gstretch_lock_z:
row.prop(lt, "gstretch_lock_z", text = "Z", icon='LOCKED')
else:
row.prop(lt, "gstretch_lock_z", text = "Z", icon='UNLOCKED')
col_move.prop(lt, "gstretch_influence")
CoDEmanX
committed
# loft - first line
split = col.split(percentage=0.15, align=True)
if lt.display_loft:
split.prop(lt, "display_loft", text="", icon='DOWNARROW_HLT')
else:
split.prop(lt, "display_loft", text="", icon='RIGHTARROW')
split.operator("mesh.looptools_bridge", text="Loft").loft = True
# loft - settings
if lt.display_loft:
box = col.column(align=True).box().column()
#box.prop(self, "mode")
CoDEmanX
committed
# top row
col_top = box.column(align=True)
row = col_top.row(align=True)
col_left = row.column(align=True)
col_right = row.column(align=True)
col_right.active = lt.bridge_segments != 1
col_left.prop(lt, "bridge_segments")
col_right.prop(lt, "bridge_min_width", text="")
# bottom row
bottom_left = col_left.row()
bottom_left.active = lt.bridge_segments != 1
bottom_left.prop(lt, "bridge_interpolation", text="")
bottom_right = col_right.row()
bottom_right.active = lt.bridge_interpolation == 'cubic'
bottom_right.prop(lt, "bridge_cubic_strength")
# boolean properties
col_top.prop(lt, "bridge_remove_faces")
col_top.prop(lt, "bridge_loft_loop")
CoDEmanX
committed
# override properties
col_top.separator()
row = box.row(align = True)
row.prop(lt, "bridge_twist")
row.prop(lt, "bridge_reverse")
CoDEmanX
committed
# relax - first line
split = col.split(percentage=0.15, align=True)
if lt.display_relax:
split.prop(lt, "display_relax", text="", icon='DOWNARROW_HLT')
else:
split.prop(lt, "display_relax", text="", icon='RIGHTARROW')
split.operator("mesh.looptools_relax")
# relax - settings
if lt.display_relax:
box = col.column(align=True).box().column()
box.prop(lt, "relax_interpolation")
box.prop(lt, "relax_input")
box.prop(lt, "relax_iterations")
box.prop(lt, "relax_regular")
CoDEmanX
committed
# space - first line
split = col.split(percentage=0.15, align=True)
if lt.display_space:
split.prop(lt, "display_space", text="", icon='DOWNARROW_HLT')
else:
split.prop(lt, "display_space", text="", icon='RIGHTARROW')
split.operator("mesh.looptools_space")
# space - settings
if lt.display_space:
box = col.column(align=True).box().column()
box.prop(lt, "space_interpolation")
box.prop(lt, "space_input")
box.separator()
CoDEmanX
committed
col_move = box.column(align=True)
row = col_move.row(align=True)
if lt.space_lock_x:
row.prop(lt, "space_lock_x", text = "X", icon='LOCKED')
else:
row.prop(lt, "space_lock_x", text = "X", icon='UNLOCKED')
if lt.space_lock_y:
row.prop(lt, "space_lock_y", text = "Y", icon='LOCKED')
else:
row.prop(lt, "space_lock_y", text = "Y", icon='UNLOCKED')
if lt.space_lock_z:
row.prop(lt, "space_lock_z", text = "Z", icon='LOCKED')
else:
row.prop(lt, "space_lock_z", text = "Z", icon='UNLOCKED')
col_move.prop(lt, "space_influence")
# property group containing all properties for the gui in the panel
class LoopToolsProps(bpy.types.PropertyGroup):
"""
Fake module like class
bpy.context.window_manager.looptools
"""
CoDEmanX
committed
# general display properties
display_bridge = bpy.props.BoolProperty(name = "Bridge settings",
description = "Display settings of the Bridge tool",
default = False)
display_circle = bpy.props.BoolProperty(name = "Circle settings",
description = "Display settings of the Circle tool",
default = False)
display_curve = bpy.props.BoolProperty(name = "Curve settings",
description = "Display settings of the Curve tool",
default = False)
display_flatten = bpy.props.BoolProperty(name = "Flatten settings",
description = "Display settings of the Flatten tool",
default = False)
display_gstretch = bpy.props.BoolProperty(name = "Gstretch settings",
description = "Display settings of the Gstretch tool",
default = False)
display_loft = bpy.props.BoolProperty(name = "Loft settings",
description = "Display settings of the Loft tool",
default = False)
display_relax = bpy.props.BoolProperty(name = "Relax settings",
description = "Display settings of the Relax tool",
default = False)
display_space = bpy.props.BoolProperty(name = "Space settings",
description = "Display settings of the Space tool",
default = False)
CoDEmanX
committed
4505
4506
4507
4508
4509
4510
4511
4512
4513
4514
4515
4516
4517
4518
4519
4520
4521
4522
4523
4524
4525
4526
4527
4528
4529
4530
4531
4532
4533
4534
4535
4536
4537
4538
4539
4540
4541
4542
4543
4544
4545
4546
4547
4548
4549
4550
4551
4552
4553
# bridge properties
bridge_cubic_strength = bpy.props.FloatProperty(name = "Strength",
description = "Higher strength results in more fluid curves",
default = 1.0,
soft_min = -3.0,
soft_max = 3.0)
bridge_interpolation = bpy.props.EnumProperty(name = "Interpolation mode",
items = (('cubic', "Cubic", "Gives curved results"),
('linear', "Linear", "Basic, fast, straight interpolation")),
description = "Interpolation mode: algorithm used when creating "\
"segments",
default = 'cubic')
bridge_loft = bpy.props.BoolProperty(name = "Loft",
description = "Loft multiple loops, instead of considering them as "\
"a multi-input for bridging",
default = False)
bridge_loft_loop = bpy.props.BoolProperty(name = "Loop",
description = "Connect the first and the last loop with each other",
default = False)
bridge_min_width = bpy.props.IntProperty(name = "Minimum width",
description = "Segments with an edge smaller than this are merged "\
"(compared to base edge)",
default = 0,
min = 0,
max = 100,
subtype = 'PERCENTAGE')
bridge_mode = bpy.props.EnumProperty(name = "Mode",
items = (('basic', "Basic", "Fast algorithm"),
('shortest', "Shortest edge", "Slower algorithm with " \
"better vertex matching")),
description = "Algorithm used for bridging",
default = 'shortest')
bridge_remove_faces = bpy.props.BoolProperty(name = "Remove faces",
description = "Remove faces that are internal after bridging",
default = True)
bridge_reverse = bpy.props.BoolProperty(name = "Reverse",
description = "Manually override the direction in which the loops "\
"are bridged. Only use if the tool gives the wrong " \
"result",
default = False)
bridge_segments = bpy.props.IntProperty(name = "Segments",
description = "Number of segments used to bridge the gap "\
"(0 = automatic)",
default = 1,
min = 0,
soft_max = 20)
bridge_twist = bpy.props.IntProperty(name = "Twist",
description = "Twist what vertices are connected to each other",
default = 0)
CoDEmanX
committed
# circle properties
circle_custom_radius = bpy.props.BoolProperty(name = "Radius",
description = "Force a custom radius",
default = False)
circle_fit = bpy.props.EnumProperty(name = "Method",
items = (("best", "Best fit", "Non-linear least squares"),
("inside", "Fit inside","Only move vertices towards the center")),
description = "Method used for fitting a circle to the vertices",
default = 'best')
circle_flatten = bpy.props.BoolProperty(name = "Flatten",
description = "Flatten the circle, instead of projecting it on the " \
"mesh",
default = True)
circle_influence = bpy.props.FloatProperty(name = "Influence",
description = "Force of the tool",
default = 100.0,
min = 0.0,
max = 100.0,
precision = 1,
subtype = 'PERCENTAGE')
circle_lock_x = bpy.props.BoolProperty(name = "Lock X",
description = "Lock editing of the x-coordinate",
default = False)
circle_lock_y = bpy.props.BoolProperty(name = "Lock Y",
description = "Lock editing of the y-coordinate",
default = False)
circle_lock_z = bpy.props.BoolProperty(name = "Lock Z",
description = "Lock editing of the z-coordinate",
default = False)
circle_radius = bpy.props.FloatProperty(name = "Radius",
description = "Custom radius for circle",
default = 1.0,
min = 0.0,
soft_max = 1000.0)
circle_regular = bpy.props.BoolProperty(name = "Regular",
description = "Distribute vertices at constant distances along the " \
"circle",
default = True)
CoDEmanX
committed
# curve properties
curve_boundaries = bpy.props.BoolProperty(name = "Boundaries",
description = "Limit the tool to work within the boundaries of the "\
"selected vertices",
default = False)
curve_influence = bpy.props.FloatProperty(name = "Influence",
description = "Force of the tool",
default = 100.0,
min = 0.0,
max = 100.0,
precision = 1,
subtype = 'PERCENTAGE')
curve_interpolation = bpy.props.EnumProperty(name = "Interpolation",
items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
("linear", "Linear", "Simple and fast linear algorithm")),
description = "Algorithm used for interpolation",
default = 'cubic')
curve_lock_x = bpy.props.BoolProperty(name = "Lock X",
description = "Lock editing of the x-coordinate",
default = False)
curve_lock_y = bpy.props.BoolProperty(name = "Lock Y",
description = "Lock editing of the y-coordinate",
default = False)
curve_lock_z = bpy.props.BoolProperty(name = "Lock Z",
description = "Lock editing of the z-coordinate",
default = False)
curve_regular = bpy.props.BoolProperty(name = "Regular",
description = "Distribute vertices at constant distances along the " \
"curve",
default = True)
curve_restriction = bpy.props.EnumProperty(name = "Restriction",
items = (("none", "None", "No restrictions on vertex movement"),
("extrude", "Extrude only","Only allow extrusions (no "\
"indentations)"),
("indent", "Indent only", "Only allow indentation (no "\
"extrusions)")),
description = "Restrictions on how the vertices can be moved",
default = 'none')
CoDEmanX
committed
# flatten properties
flatten_influence = bpy.props.FloatProperty(name = "Influence",
description = "Force of the tool",
default = 100.0,
min = 0.0,
max = 100.0,
precision = 1,
subtype = 'PERCENTAGE')
flatten_lock_x = bpy.props.BoolProperty(name = "Lock X",
description = "Lock editing of the x-coordinate",
default = False)
flatten_lock_y = bpy.props.BoolProperty(name = "Lock Y",
description = "Lock editing of the y-coordinate",
default = False)
flatten_lock_z = bpy.props.BoolProperty(name = "Lock Z",
description = "Lock editing of the z-coordinate",
default = False)
flatten_plane = bpy.props.EnumProperty(name = "Plane",
items = (("best_fit", "Best fit", "Calculate a best fitting plane"),
("normal", "Normal", "Derive plane from averaging vertex "\
"normals"),
("view", "View", "Flatten on a plane perpendicular to the "\
"viewing angle")),
description = "Plane on which vertices are flattened",
default = 'best_fit')
flatten_restriction = bpy.props.EnumProperty(name = "Restriction",
items = (("none", "None", "No restrictions on vertex movement"),
("bounding_box", "Bounding box", "Vertices are restricted to "\
"movement inside the bounding box of the selection")),
description = "Restrictions on how the vertices can be moved",
default = 'none')
CoDEmanX
committed
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
4686
4687
4688
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699
4700
4701
4702
gstretch_conversion = bpy.props.EnumProperty(name = "Conversion",
items = (("distance", "Distance", "Set the distance between vertices "\
"of the converted grease pencil stroke"),
("limit_vertices", "Limit vertices", "Set the minimum and maximum "\
"number of vertices that converted GP strokes will have"),
("vertices", "Exact vertices", "Set the exact number of vertices "\
"that converted grease pencil strokes will have. Short strokes "\
"with few points may contain less vertices than this number."),
("none", "No simplification", "Convert each grease pencil point "\
"to a vertex")),
description = "If grease pencil strokes are converted to geometry, "\
"use this simplification method",
default = 'limit_vertices')
gstretch_conversion_distance = bpy.props.FloatProperty(name = "Distance",
description = "Absolute distance between vertices along the converted "\
"grease pencil stroke",
default = 0.1,
min = 0.000001,
soft_min = 0.01,
soft_max = 100)
gstretch_conversion_max = bpy.props.IntProperty(name = "Max Vertices",
description = "Maximum number of vertices grease pencil strokes will "\
"have, when they are converted to geomtery",
default = 32,
min = 3,
soft_max = 500,
update = gstretch_update_min)
gstretch_conversion_min = bpy.props.IntProperty(name = "Min Vertices",
description = "Minimum number of vertices grease pencil strokes will "\
"have, when they are converted to geomtery",
default = 8,
min = 3,
soft_max = 500,
update = gstretch_update_max)
gstretch_conversion_vertices = bpy.props.IntProperty(name = "Vertices",
description = "Number of vertices grease pencil strokes will "\
"have, when they are converted to geometry. If strokes have less "\
"points than required, the 'Spread evenly' method is used",
default = 32,
min = 3,
soft_max = 500)
gstretch_delete_strokes = bpy.props.BoolProperty(name="Delete strokes",
description = "Remove Grease Pencil strokes if they have been used "\
"for Gstretch. WARNING: DOES NOT SUPPORT UNDO",
CoDEmanX
committed
default = False)
gstretch_influence = bpy.props.FloatProperty(name = "Influence",
description = "Force of the tool",
default = 100.0,
min = 0.0,
max = 100.0,
precision = 1,
subtype = 'PERCENTAGE')
gstretch_lock_x = bpy.props.BoolProperty(name = "Lock X",
description = "Lock editing of the x-coordinate",
default = False)
gstretch_lock_y = bpy.props.BoolProperty(name = "Lock Y",
description = "Lock editing of the y-coordinate",
default = False)
gstretch_lock_z = bpy.props.BoolProperty(name = "Lock Z",
description = "Lock editing of the z-coordinate",
default = False)
gstretch_method = bpy.props.EnumProperty(name = "Method",
items = (("project", "Project", "Project vertices onto the stroke, "\
"using vertex normals and connected edges"),
("irregular", "Spread", "Distribute vertices along the full "\
"stroke, retaining relative distances between the vertices"),
("regular", "Spread evenly", "Distribute vertices at regular "\
"distances along the full stroke")),
description = "Method of distributing the vertices over the Grease "\
"Pencil stroke",
default = 'regular')
CoDEmanX
committed
4738
4739
4740
4741
4742
4743
4744
4745
4746
4747
4748
4749
4750
4751
4752
4753
4754
4755
4756
4757
4758
4759
4760
4761
# relax properties
relax_input = bpy.props.EnumProperty(name = "Input",
items = (("all", "Parallel (all)", "Also use non-selected "\
"parallel loops as input"),
("selected", "Selection","Only use selected vertices as input")),
description = "Loops that are relaxed",
default = 'selected')
relax_interpolation = bpy.props.EnumProperty(name = "Interpolation",
items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
("linear", "Linear", "Simple and fast linear algorithm")),
description = "Algorithm used for interpolation",
default = 'cubic')
relax_iterations = bpy.props.EnumProperty(name = "Iterations",
items = (("1", "1", "One"),
("3", "3", "Three"),
("5", "5", "Five"),
("10", "10", "Ten"),
("25", "25", "Twenty-five")),
description = "Number of times the loop is relaxed",
default = "1")
relax_regular = bpy.props.BoolProperty(name = "Regular",
description = "Distribute vertices at constant distances along the" \
"loop",
default = True)
CoDEmanX
committed
# space properties
space_influence = bpy.props.FloatProperty(name = "Influence",
description = "Force of the tool",
default = 100.0,
min = 0.0,
max = 100.0,
precision = 1,
subtype = 'PERCENTAGE')
space_input = bpy.props.EnumProperty(name = "Input",
items = (("all", "Parallel (all)", "Also use non-selected "\
"parallel loops as input"),
("selected", "Selection","Only use selected vertices as input")),
description = "Loops that are spaced",
default = 'selected')
space_interpolation = bpy.props.EnumProperty(name = "Interpolation",
items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
("linear", "Linear", "Vertices are projected on existing edges")),
description = "Algorithm used for interpolation",
default = 'cubic')
space_lock_x = bpy.props.BoolProperty(name = "Lock X",
description = "Lock editing of the x-coordinate",
default = False)
space_lock_y = bpy.props.BoolProperty(name = "Lock Y",
description = "Lock editing of the y-coordinate",
default = False)
space_lock_z = bpy.props.BoolProperty(name = "Lock Z",
description = "Lock editing of the z-coordinate",
default = False)
# draw function for integration in menus
def menu_func(self, context):
self.layout.menu("VIEW3D_MT_edit_mesh_looptools")
self.layout.separator()
# define classes for registration
classes = [VIEW3D_MT_edit_mesh_looptools,
VIEW3D_PT_tools_looptools,
LoopToolsProps,
Bridge,
Circle,
Curve,
Flatten,
4808
4809
4810
4811
4812
4813
4814
4815
4816
4817
4818
4819
4820
4821
4822
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
Relax,
Space]
# registering and menu integration
def register():
for c in classes:
bpy.utils.register_class(c)
bpy.types.VIEW3D_MT_edit_mesh_specials.prepend(menu_func)
bpy.types.WindowManager.looptools = bpy.props.PointerProperty(\
type = LoopToolsProps)
# unregistering and removing menus
def unregister():
for c in classes:
bpy.utils.unregister_class(c)
bpy.types.VIEW3D_MT_edit_mesh_specials.remove(menu_func)
try:
del bpy.types.WindowManager.looptools
except:
pass
if __name__ == "__main__":
register()