Newer
Older
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 "
"stroke",
CoDEmanX
committed
@classmethod
def poll(cls, context):
ob = context.active_object
return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
CoDEmanX
committed
looptools = context.window_manager.looptools
CoDEmanX
committed
col_conv = col.column(align=True)
col_conv.prop(self, "conversion", text="")
if self.conversion == 'distance':
col_conv.prop(self, "conversion_distance")
elif self.conversion == 'limit_vertices':
row = col_conv.row(align=True)
row.prop(self, "conversion_min", text="Min")
row.prop(self, "conversion_max", text="Max")
elif self.conversion == 'vertices':
col_conv.prop(self, "conversion_vertices")
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')
row.prop(self, "lock_x", text="X", icon='UNLOCKED')
row.prop(self, "lock_y", text="Y", icon='LOCKED')
row.prop(self, "lock_y", text="Y", icon='UNLOCKED')
row.prop(self, "lock_z", text="Z", icon='LOCKED')
row.prop(self, "lock_z", text="Z", icon='UNLOCKED')
if looptools.gstretch_use_guide == "Annotation":
col.operator("remove.annotation", text="Delete annotation strokes")
if looptools.gstretch_use_guide == "GPencil":
col.operator("remove.gp", text="Delete GPencil strokes")
CoDEmanX
committed
# flush cached strokes
if 'Gstretch' in looptools_cache:
looptools_cache['Gstretch']['single_loops'] = []
# load custom settings
settings_load(self)
return self.execute(context)
CoDEmanX
committed
object, bm = initialise()
CoDEmanX
committed
cached, safe_strokes, loops, derived, mapping = cache_read("Gstretch",
if safe_strokes:
strokes = gstretch_safe_to_true_strokes(safe_strokes)
# cached strokes were flushed (see operator's invoke function)
elif get_strokes(self, context):
strokes = gstretch_get_strokes(self, context)
# straightening function (no GP) -> loops ignore modifiers
straightening = True
derived = False
bm_mod = bm.copy()
bm_mod.verts.ensure_lookup_table()
bm_mod.edges.ensure_lookup_table()
bm_mod.faces.ensure_lookup_table()
strokes = gstretch_get_fake_strokes(object, bm_mod, loops)
Vladimir Spivak(cwolf3d)
committed
derived, bm_mod = get_derived_bmesh(object, bm, False)
if get_strokes(self, context):
Vladimir Spivak(cwolf3d)
committed
derived, bm_mod, loops = get_connected_input(object, bm, False, input='selected')
mapping = get_mapping(derived, bm, bm_mod, False, False, loops)
loops = check_loops(loops, mapping, bm_mod)
# get strokes
strokes = gstretch_get_strokes(self, context)
# straightening function (no GP) -> loops ignore modifiers
derived = False
mapping = False
bm_mod = bm.copy()
bm_mod.verts.ensure_lookup_table()
bm_mod.edges.ensure_lookup_table()
bm_mod.faces.ensure_lookup_table()
edge_keys = [
edgekey(edge) for edge in bm_mod.edges if
edge.select and not edge.hide
]
loops = get_connected_selections(edge_keys)
loops = check_loops(loops, mapping, bm_mod)
# create fake strokes
strokes = gstretch_get_fake_strokes(object, bm_mod, loops)
CoDEmanX
committed
# saving cache for faster execution next time
if not cached:
if strokes:
safe_strokes = gstretch_true_to_safe_strokes(strokes)
else:
safe_strokes = []
cache_write("Gstretch", object, bm, False, False,
safe_strokes, loops, derived, mapping)
# pair loops and strokes
ls_pairs = gstretch_match_loops_strokes(loops, strokes, object, bm_mod)
ls_pairs = gstretch_align_pairs(ls_pairs, object, bm_mod, self.method)
CoDEmanX
committed
if not loops:
# no selected geometry, convert GP to verts
if strokes:
move.append(gstretch_create_verts(object, bm, strokes,
self.method, self.conversion, self.conversion_distance,
self.conversion_max, self.conversion_min,
self.conversion_vertices))
for stroke in strokes:
gstretch_erase_stroke(stroke, context)
elif ls_pairs:
for (loop, stroke) in ls_pairs:
move.append(gstretch_calculate_verts(loop, stroke, object,
bm_mod, self.method))
if self.delete_strokes:
if type(stroke) != bpy.types.GPencilStroke:
# in case of cached fake stroke, get the real one
if get_strokes(self, context):
strokes = gstretch_get_strokes(self, context)
if loops and strokes:
ls_pairs = gstretch_match_loops_strokes(loops,
strokes, object, bm_mod)
ls_pairs = gstretch_align_pairs(ls_pairs,
object, bm_mod, self.method)
for (l, s) in ls_pairs:
if l == loop:
stroke = s
break
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
bmesh.update_edit_mesh(object.data, loop_triangles=True, destructive=True)
move_verts(object, bm, mapping, move, lock, self.influence)
CoDEmanX
committed
# cleaning up
CoDEmanX
committed
bl_idname = "mesh.looptools_relax"
bl_label = "Relax"
bl_description = "Relax the loop, so it is smoother"
bl_options = {'REGISTER', 'UNDO'}
CoDEmanX
committed
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'
)
name="Interpolation",
items=(("cubic", "Cubic", "Natural cubic spline, smooth results"),
("linear", "Linear", "Simple and fast linear algorithm")),
description="Algorithm used for interpolation",
default='cubic'
)
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"
)
name="Regular",
description="Distribute vertices at constant distances along the loop",
default=True
)
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.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
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:
Vladimir Spivak(cwolf3d)
committed
derived, bm_mod = get_derived_bmesh(object, bm, False)
else:
# find loops
Vladimir Spivak(cwolf3d)
committed
derived, bm_mod, loops = get_connected_input(object, bm, False, 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()
CoDEmanX
committed
return{'FINISHED'}
# space operator
bl_idname = "mesh.looptools_space"
bl_label = "Space"
bl_description = "Space the vertices in a regular distribution on the loop"
bl_options = {'REGISTER', 'UNDO'}
CoDEmanX
committed
name="Influence",
description="Force of the tool",
default=100.0,
min=0.0,
max=100.0,
precision=1,
subtype='PERCENTAGE'
)
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'
)
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'
)
name="Lock X",
description="Lock editing of the x-coordinate",
default=False
)
name="Lock Y",
description="Lock editing of the y-coordinate",
default=False
)
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')
row.prop(self, "lock_x", text="X", icon='UNLOCKED')
row.prop(self, "lock_y", text="Y", icon='LOCKED')
row.prop(self, "lock_y", text="Y", icon='UNLOCKED')
row.prop(self, "lock_z", text="Z", icon='LOCKED')
row.prop(self, "lock_z", text="Z", icon='UNLOCKED')
CoDEmanX
committed
def invoke(self, context, event):
# load custom settings
settings_load(self)
return self.execute(context)
CoDEmanX
committed
def execute(self, context):
# initialise
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:
Vladimir Spivak(cwolf3d)
committed
derived, bm_mod = get_derived_bmesh(object, bm, True)
else:
# find loops
Vladimir Spivak(cwolf3d)
committed
derived, bm_mod, loops = get_connected_input(object, bm, True, 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
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()
CoDEmanX
committed
return{'FINISHED'}
# ########################################
# ##### GUI and registration #############
# ########################################
# menu containing all tools
class VIEW3D_MT_edit_mesh_looptools(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(Panel):
bl_space_type = 'VIEW_3D'
bl_category = 'Edit'
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
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()
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.prop(lt, "bridge_twist")
row.prop(lt, "bridge_reverse")
CoDEmanX
committed
# circle - first line
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')
row.prop(lt, "circle_lock_x", text="X", icon='UNLOCKED')
row.prop(lt, "circle_lock_y", text="Y", icon='LOCKED')
row.prop(lt, "circle_lock_y", text="Y", icon='UNLOCKED')
row.prop(lt, "circle_lock_z", text="Z", icon='LOCKED')
row.prop(lt, "circle_lock_z", text="Z", icon='UNLOCKED')
col_move.prop(lt, "circle_influence")
CoDEmanX
committed
# curve - first line
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')
row.prop(lt, "curve_lock_x", text="X", icon='UNLOCKED')
row.prop(lt, "curve_lock_y", text="Y", icon='LOCKED')
row.prop(lt, "curve_lock_y", text="Y", icon='UNLOCKED')
row.prop(lt, "curve_lock_z", text="Z", icon='LOCKED')
row.prop(lt, "curve_lock_z", text="Z", icon='UNLOCKED')
col_move.prop(lt, "curve_influence")
CoDEmanX
committed
# flatten - first line
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")
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')
row.prop(lt, "flatten_lock_x", text="X", icon='UNLOCKED')
row.prop(lt, "flatten_lock_y", text="Y", icon='LOCKED')
row.prop(lt, "flatten_lock_y", text="Y", icon='UNLOCKED')
row.prop(lt, "flatten_lock_z", text="Z", icon='LOCKED')
row.prop(lt, "flatten_lock_z", text="Z", icon='UNLOCKED')
col_move.prop(lt, "flatten_influence")
CoDEmanX
committed
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_use_guide")
if lt.gstretch_use_guide == "GPencil":
box.prop(lt, "gstretch_guide")
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')
row.prop(lt, "gstretch_lock_x", text="X", icon='UNLOCKED')
row.prop(lt, "gstretch_lock_y", text="Y", icon='LOCKED')
row.prop(lt, "gstretch_lock_y", text="Y", icon='UNLOCKED')
row.prop(lt, "gstretch_lock_z", text="Z", icon='LOCKED')
row.prop(lt, "gstretch_lock_z", text="Z", icon='UNLOCKED')
col_move.prop(lt, "gstretch_influence")
if lt.gstretch_use_guide == "Annotation":
box.operator("remove.annotation", text="Delete Annotation Strokes")
if lt.gstretch_use_guide == "GPencil":
box.operator("remove.gp", text="Delete GPencil Strokes")
CoDEmanX
committed
# loft - first line
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()
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.prop(lt, "bridge_twist")
row.prop(lt, "bridge_reverse")
CoDEmanX
committed
# relax - first line
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
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')
row.prop(lt, "space_lock_x", text="X", icon='UNLOCKED')
row.prop(lt, "space_lock_y", text="Y", icon='LOCKED')
row.prop(lt, "space_lock_y", text="Y", icon='UNLOCKED')
row.prop(lt, "space_lock_z", text="Z", icon='LOCKED')
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(PropertyGroup):
"""
Fake module like class
bpy.context.window_manager.looptools
"""
# general display properties
name="Bridge settings",
description="Display settings of the Bridge tool",
default=False
)
name="Circle settings",
description="Display settings of the Circle tool",
default=False
)
name="Curve settings",
description="Display settings of the Curve tool",
default=False
)
name="Flatten settings",
description="Display settings of the Flatten tool",
default=False
)
name="Gstretch settings",
description="Display settings of the Gstretch tool",
default=False
)
name="Loft settings",
description="Display settings of the Loft tool",
default=False
)
name="Relax settings",
description="Display settings of the Relax tool",
default=False
)
name="Space settings",
description="Display settings of the Space tool",
default=False
)
CoDEmanX
committed
# bridge properties
name="Strength",
description="Higher strength results in more fluid curves",
default=1.0,
soft_min=-3.0,
soft_max=3.0
)
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'
)
name="Loft",
description="Loft multiple loops, instead of considering them as "
"a multi-input for bridging",
default=False
)
name="Loop",
description="Connect the first and the last loop with each other",
default=False
)
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'
)
name="Mode",
items=(('basic', "Basic", "Fast algorithm"),
('shortest', "Shortest edge", "Slower algorithm with "
"better vertex matching")),
description="Algorithm used for bridging",
default='shortest'
)
name="Remove faces",
description="Remove faces that are internal after bridging",
default=True
)
name="Reverse",
description="Manually override the direction in which the loops "
"are bridged. Only use if the tool gives the wrong result",
default=False
)
name="Segments",
description="Number of segments used to bridge the gap (0=automatic)",
default=1,
min=0,
soft_max=20
)
name="Twist",
description="Twist what vertices are connected to each other",
default=0
)
CoDEmanX
committed
# circle properties
name="Radius",
description="Force a custom radius",
default=False
)
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'
)
name="Flatten",
description="Flatten the circle, instead of projecting it on the mesh",
default=True
)
name="Influence",
description="Force of the tool",
default=100.0,
min=0.0,
max=100.0,
precision=1,
subtype='PERCENTAGE'
)
name="Lock X",
description="Lock editing of the x-coordinate",
default=False
)
name="Lock Y",
description="Lock editing of the y-coordinate",
default=False
)
name="Lock Z",
description="Lock editing of the z-coordinate",
default=False
)
name="Radius",
description="Custom radius for circle",
default=1.0,
min=0.0,
soft_max=1000.0
)
name="Regular",
description="Distribute vertices at constant distances along the circle",
default=True
)
Vladimir Spivak(cwolf3d)
committed
circle_angle: FloatProperty(
name="Angle",
description="Rotate a circle by an angle",
unit='ROTATION',
default=math.radians(0.0),
soft_min=math.radians(-360.0),
soft_max=math.radians(360.0)
)
# curve properties
name="Boundaries",
description="Limit the tool to work within the boundaries of the "
"selected vertices",
default=False
)
name="Influence",
description="Force of the tool",
default=100.0,
min=0.0,
max=100.0,
precision=1,
subtype='PERCENTAGE'
)
name="Interpolation",
items=(("cubic", "Cubic", "Natural cubic spline, smooth results"),
("linear", "Linear", "Simple and fast linear algorithm")),
description="Algorithm used for interpolation",
default='cubic'
)
name="Lock X",
description="Lock editing of the x-coordinate",
default=False
)
name="Lock Y",
description="Lock editing of the y-coordinate",
default=False
)
name="Lock Z",
description="Lock editing of the z-coordinate",
default=False
)
name="Regular",
description="Distribute vertices at constant distances along the curve",
default=True
)
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
name="Influence",
description="Force of the tool",
default=100.0,
min=0.0,
max=100.0,
precision=1,
subtype='PERCENTAGE'
)
name="Lock X",
description="Lock editing of the x-coordinate",
default=False)
description="Lock editing of the y-coordinate",
default=False
)
name="Lock Z",
description="Lock editing of the z-coordinate",
default=False
)
name="Plane",
items=(("best_fit", "Best fit", "Calculate a best fitting plane"),
("normal", "Normal", "Derive plane from averaging vertex "
("view", "View", "Flatten on a plane perpendicular to the "
"viewing angle")),
description="Plane on which vertices are flattened",
default='best_fit'
)
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
name="Conversion",
items=(("distance", "Distance", "Set the distance between vertices "
"of the converted 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 strokes will have. Short strokes "
"with few points may contain less vertices than this number."),
("none", "No simplification", "Convert each point "
description="If strokes are converted to geometry, "
"use this simplification method",
default='limit_vertices'
)
name="Distance",
description="Absolute distance between vertices along the converted "
"stroke",
default=0.1,
min=0.000001,
soft_min=0.01,
soft_max=100
)