Newer
Older
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
4488
4489
4490
4491
4492
4493
4494
4495
4496
4497
4498
4499
4500
4501
4502
4503
4504
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
# 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
4649
4650
4651
4652
4653
4654
4655
4656
4657
4658
4659
4660
4661
4662
4663
4664
4665
4666
4667
4668
4669
4670
4671
4672
4673
4674
4675
4676
4677
4678
4679
4680
4681
4682
4683
4684
4685
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
4721
4722
4723
4724
4725
4726
4727
4728
4729
4730
4731
4732
4733
4734
4735
4736
4737
4738
4739
4740
4741
4742
4743
4744
# 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()
4781
4782
4783
4784
4785
4786
4787
4788
4789
4790
4791
4792
4793
4794
4795
4796
4797
4798
4799
4800
4801
4802
4803
4804
4805
4806
4807
## Addons Preferences Update Panel
def update_panel(self, context):
try:
bpy.utils.unregister_class(VIEW3D_PT_tools_looptools)
except:
pass
VIEW3D_PT_tools_looptools.bl_category = context.user_preferences.addons[__name__].preferences.category
bpy.utils.register_class(VIEW3D_PT_tools_looptools)
class LoopPreferences(bpy.types.AddonPreferences):
# this must match the addon name, use '__package__'
# when defining this in a submodule of a python package.
bl_idname = __name__
category = bpy.props.StringProperty(
name="Tab Category",
description="Choose a name for the category of the panel",
default="Tools",
update=update_panel)
def draw(self, context):
layout = self.layout
row = layout.row()
col = row.column()
col.label(text="Tab Category:")
col.prop(self, "category", text="")
# define classes for registration
classes = [
VIEW3D_MT_edit_mesh_looptools,
VIEW3D_PT_tools_looptools,
LoopToolsProps,
Bridge,
Circle,
Curve,
Flatten,
Space,
LoopPreferences,
]
4823
4824
4825
4826
4827
4828
4829
4830
4831
4832
4833
4834
4835
4836
4837
4838
4839
4840
4841
4842
4843
4844
4845
4846
# 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()