Cleanup: quiet warnings with descriptions ending with a '.'
[blender-addons.git] / mesh_tissue / curves_tools.py
blob7a81ebe7acbf71ea0c6190e2846b1d536b8e37bf
1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # #
4 # (c) Alessandro Zomparelli #
5 # (2017) #
6 # #
7 # http://www.co-de-it.com/ #
8 # #
9 # ############################################################################ #
12 import bpy, bmesh
13 from bpy.types import Operator
14 from bpy.props import (
15 IntProperty,
16 BoolProperty,
17 EnumProperty,
18 PointerProperty,
19 StringProperty,
20 FloatProperty
22 from bpy.types import (
23 Operator,
24 Panel,
25 PropertyGroup,
28 import numpy as np
29 from mathutils import Vector
30 from math import pi
31 from .utils import (
32 find_curves,
33 update_curve_from_pydata,
34 simple_to_mesh,
35 convert_object_to_mesh,
36 get_weight_numpy,
37 loops_from_bmesh,
38 get_mesh_before_subs
40 import time
43 def anim_curve_active(self, context):
44 ob = context.object
45 props = ob.tissue_to_curve
46 try:
47 props.object.name
48 if not ob.tissue.bool_lock:
49 bpy.ops.object.tissue_convert_to_curve_update()
50 except: pass
53 class tissue_to_curve_prop(PropertyGroup):
54 object : PointerProperty(
55 type=bpy.types.Object,
56 name="",
57 description="Source object",
58 update = anim_curve_active
60 bool_smooth : BoolProperty(
61 name="Smooth Shading",
62 default=True,
63 description="Output faces with smooth shading rather than flat shaded",
64 update = anim_curve_active
66 bool_lock : BoolProperty(
67 name="Lock",
68 description="Prevent automatic update on settings changes or if other objects have it in the hierarchy",
69 default=False,
70 update = anim_curve_active
72 bool_dependencies : BoolProperty(
73 name="Update Dependencies",
74 description="Automatically updates source object as well, when possible",
75 default=False,
76 update = anim_curve_active
78 bool_run : BoolProperty(
79 name="Animatable Curve",
80 description="Automatically recompute the conversion when the frame is changed",
81 default = False
83 use_modifiers : BoolProperty(
84 name="Use Modifiers",
85 default=True,
86 description="Automatically apply Modifiers and Shape Keys",
87 update = anim_curve_active
89 subdivision_mode : EnumProperty(
90 items=(
91 ('ALL', "All", ""),
92 ('CAGE', "Cage", ""),
93 ('INNER', "Inner", "")
95 default='CAGE',
96 name="Subdivided Edges",
97 update = anim_curve_active
99 use_endpoint_u : BoolProperty(
100 name="Endpoint U",
101 default=True,
102 description="Make all open nurbs curve meet the endpoints",
103 update = anim_curve_active
105 clean_distance : FloatProperty(
106 name="Merge Distance", default=0, min=0, soft_max=10,
107 description="Merge Distance",
108 update = anim_curve_active
110 nurbs_order : IntProperty(
111 name="Order", default=4, min=2, max=6,
112 description="Nurbs order",
113 update = anim_curve_active
115 system : IntProperty(
116 name="System", default=0, min=0,
117 description="Particle system index",
118 update = anim_curve_active
120 bounds_selection : EnumProperty(
121 items=(
122 ('ALL', "All", ""),
123 ('BOUNDS', "Boundaries", ""),
124 ('INNER', "Inner", "")
126 default='ALL',
127 name="Boundary Selection",
128 update = anim_curve_active
130 periodic_selection : EnumProperty(
131 items=(
132 ('ALL', "All", ""),
133 ('OPEN', "Open", ""),
134 ('CLOSED', "Closed", "")
136 default='ALL',
137 name="Periodic Selection",
138 update = anim_curve_active
140 spline_type : EnumProperty(
141 items=(
142 ('POLY', "Poly", ""),
143 ('BEZIER', "Bezier", ""),
144 ('NURBS', "NURBS", "")
146 default='POLY',
147 name="Spline Type",
148 update = anim_curve_active
150 mode : EnumProperty(
151 items=(
152 ('LOOPS', "Loops", ""),
153 ('EDGES', "Edges", ""),
154 ('PARTICLES', "Particles", "")
156 default='LOOPS',
157 name="Conversion Mode",
158 update = anim_curve_active
160 vertex_group : StringProperty(
161 name="Radius", default='',
162 description="Vertex Group used for variable radius",
163 update = anim_curve_active
165 invert_vertex_group : BoolProperty(default=False,
166 description='Inverte the value of the Vertex Group',
167 update = anim_curve_active
169 vertex_group_factor : FloatProperty(
170 name="Factor",
171 default=0,
172 min=0,
173 max=1,
174 description="Depth bevel factor to use for zero vertex group influence",
175 update = anim_curve_active
177 only_sharp : BoolProperty(
178 default=False,
179 name="Only Sharp Edges",
180 description='Convert only Sharp edges',
181 update = anim_curve_active
183 pattern_depth : FloatProperty(
184 name="Depth",
185 default=0.02,
186 min=0,
187 soft_max=10,
188 description="Displacement pattern depth",
189 update = anim_curve_active
191 pattern_offset : FloatProperty(
192 name="Offset",
193 default=0,
194 soft_min=-1,
195 soft_max=1,
196 description="Displacement pattern offset",
197 update = anim_curve_active
199 pattern0 : IntProperty(
200 name="Step 0",
201 default=0,
202 min=0,
203 soft_max=10,
204 description="Pattern step 0",
205 update = anim_curve_active
207 pattern1 : IntProperty(
208 name="Step 1",
209 default=0,
210 min=0,
211 soft_max=10,
212 description="Pattern step 1",
213 update = anim_curve_active
216 class tissue_convert_to_curve(Operator):
217 bl_idname = "object.tissue_convert_to_curve"
218 bl_label = "Tissue Convert to Curve"
219 bl_description = "Convert selected mesh to Curve object"
220 bl_options = {'REGISTER', 'UNDO'}
222 object : StringProperty(
223 name="",
224 description="Source object",
225 default = ""
227 bool_smooth : BoolProperty(
228 name="Smooth Shading",
229 default=True,
230 description="Output faces with smooth shading rather than flat shaded"
232 use_modifiers : BoolProperty(
233 name="Use Modifiers",
234 default=True,
235 description="Automatically apply Modifiers and Shape Keys"
237 subdivision_mode : EnumProperty(
238 items=(
239 ('ALL', "All", ""),
240 ('CAGE', "Cage", ""),
241 ('INNER', "Inner", "")
243 default='CAGE',
244 name="Subdivided Edges"
246 use_endpoint_u : BoolProperty(
247 name="Endpoint U",
248 default=True,
249 description="Make all open nurbs curve meet the endpoints"
251 nurbs_order : IntProperty(
252 name="Order", default=4, min=2, max=6,
253 description="Nurbs order"
255 system : IntProperty(
256 name="System", default=0, min=0,
257 description="Particle system index"
259 clean_distance : FloatProperty(
260 name="Merge Distance", default=0, min=0, soft_max=10,
261 description="Merge Distance"
263 spline_type : EnumProperty(
264 items=(
265 ('POLY', "Poly", ""),
266 ('BEZIER', "Bezier", ""),
267 ('NURBS', "NURBS", "")
269 default='POLY',
270 name="Spline Type"
272 bounds_selection : EnumProperty(
273 items=(
274 ('ALL', "All", ""),
275 ('BOUNDS', "Boundaries", ""),
276 ('INNER', "Inner", "")
278 default='ALL',
279 name="Boundary Selection"
281 periodic_selection : EnumProperty(
282 items=(
283 ('ALL', "All", ""),
284 ('OPEN', "Open", ""),
285 ('CLOSED', "Closed", "")
287 default='ALL',
288 name="Periodic Selection"
290 mode : EnumProperty(
291 items=(
292 ('LOOPS', "Loops", ""),
293 ('EDGES', "Edges", ""),
294 ('PARTICLES', "Particles", "")
296 default='LOOPS',
297 name="Conversion Mode"
299 vertex_group : StringProperty(
300 name="Radius", default='',
301 description="Vertex Group used for variable radius"
303 invert_vertex_group : BoolProperty(default=False,
304 description='Inverte the value of the Vertex Group'
306 vertex_group_factor : FloatProperty(
307 name="Factor",
308 default=0,
309 min=0,
310 max=1,
311 description="Depth bevel factor to use for zero vertex group influence"
313 only_sharp : BoolProperty(
314 default=False,
315 name="Only Sharp Edges",
316 description='Convert only Sharp edges'
318 pattern_depth : FloatProperty(
319 name="Depth",
320 default=0.02,
321 min=0,
322 soft_max=10,
323 description="Displacement pattern depth"
325 pattern_offset : FloatProperty(
326 name="Offset",
327 default=0,
328 soft_min=-1,
329 soft_max=1,
330 description="Displacement pattern offset"
332 pattern0 : IntProperty(
333 name="Step 0",
334 default=0,
335 min=0,
336 soft_max=10,
337 description="Pattern step 0"
339 pattern1 : IntProperty(
340 name="Step 1",
341 default=0,
342 min=0,
343 soft_max=10,
344 description="Pattern step 1"
347 @classmethod
348 def poll(cls, context):
349 try:
350 #bool_tessellated = context.object.tissue_tessellate.generator != None
351 ob = context.object
352 return ob.type in ('MESH','CURVE','SURFACE','FONT') and ob.mode == 'OBJECT'# and bool_tessellated
353 except:
354 return False
356 def invoke(self, context, event):
357 self.object = context.object.name
358 return context.window_manager.invoke_props_dialog(self)
360 def draw(self, context):
361 ob = context.object
362 ob0 = bpy.data.objects[self.object]
363 #props = ob.tissue_to_curve
364 layout = self.layout
365 col = layout.column(align=True)
366 row = col.row(align=True)
367 #row.label(text='Object: ' + self.object)
368 #row.prop_search(self, "object", context.scene, "objects")
369 #row.prop(self, "use_modifiers")#, icon='MODIFIER', text='')
370 col.separator()
371 col.label(text='Conversion Mode:')
372 row = col.row(align=True)
373 row.prop(
374 self, "mode", text="Conversion Mode", icon='NONE', expand=True,
375 slider=False, toggle=False, icon_only=False, event=False,
376 full_event=False, emboss=True, index=-1)
377 if self.mode == 'PARTICLES':
378 col.separator()
379 col.prop(self, "system")
380 col.separator()
381 if self.mode in ('LOOPS', 'EDGES'):
382 row = col.row(align=True)
383 row.prop(self, "use_modifiers")
384 col2 = row.column(align=True)
385 if self.use_modifiers:
386 col2.prop(self, "subdivision_mode", text='', icon='NONE', expand=False,
387 slider=True, toggle=False, icon_only=False, event=False,
388 full_event=False, emboss=True, index=-1)
389 col2.enabled = False
390 for m in bpy.data.objects[self.object].modifiers:
391 if m.type in ('SUBSURF','MULTIRES'): col2.enabled = True
392 col.separator()
393 row = col.row(align=True)
394 row.label(text='Filter Edges:')
395 col2 = row.column(align=True)
396 col2.prop(self, "bounds_selection", text='', icon='NONE', expand=False,
397 slider=True, toggle=False, icon_only=False, event=False,
398 full_event=False, emboss=True, index=-1)
399 col2.prop(self, 'only_sharp')
400 col.separator()
401 if self.mode == 'LOOPS':
402 row = col.row(align=True)
403 row.label(text='Filter Loops:')
404 row.prop(self, "periodic_selection", text='', icon='NONE', expand=False,
405 slider=True, toggle=False, icon_only=False, event=False,
406 full_event=False, emboss=True, index=-1)
407 col.separator()
408 col.label(text='Spline Type:')
409 row = col.row(align=True)
410 row.prop(
411 self, "spline_type", text="Spline Type", icon='NONE', expand=True,
412 slider=False, toggle=False, icon_only=False, event=False,
413 full_event=False, emboss=True, index=-1)
414 if self.spline_type == 'NURBS':
415 col.separator()
416 col.label(text='Nurbs splines:')
417 row = col.row(align=True)
418 row.prop(self, "use_endpoint_u")
419 row.prop(self, "nurbs_order")
420 col.separator()
421 col.prop(self, "bool_smooth")
422 if ob0.type == 'MESH' and self.mode != 'PARTICLES':
423 col.separator()
424 col.label(text='Variable Radius:')
425 row = col.row(align=True)
426 row.prop_search(self, 'vertex_group', ob0, "vertex_groups", text='')
427 row.prop(self, "invert_vertex_group", text="", toggle=True, icon='ARROW_LEFTRIGHT')
428 row.prop(self, "vertex_group_factor")
429 col.separator()
430 col.label(text='Clean curves:')
431 col.prop(self, "clean_distance")
432 col.separator()
433 col.label(text='Displacement Pattern:')
434 row = col.row(align=True)
435 row.prop(self, "pattern0")
436 row.prop(self, "pattern1")
437 row = col.row(align=True)
438 row.prop(self, "pattern_depth")
439 row.prop(self, "pattern_offset")
441 def execute(self, context):
442 ob = context.active_object
444 crv = bpy.data.curves.new(ob.name + '_Curve', type='CURVE')
445 crv.dimensions = '3D'
446 new_ob = bpy.data.objects.new(ob.name + '_Curve', crv)
447 bpy.context.collection.objects.link(new_ob)
448 context.view_layer.objects.active = new_ob
450 new_ob.select_set(True)
451 ob.select_set(False)
452 new_ob.matrix_world = ob.matrix_world
454 new_ob.tissue.tissue_type = 'TO_CURVE'
455 new_ob.tissue.bool_lock = True
457 props = new_ob.tissue_to_curve
458 props.object = ob
459 props.use_modifiers = self.use_modifiers
460 props.subdivision_mode = self.subdivision_mode
461 props.clean_distance = self.clean_distance
462 props.spline_type = self.spline_type
463 props.mode = self.mode
464 props.use_endpoint_u = self.use_endpoint_u
465 props.nurbs_order = self.nurbs_order
466 props.vertex_group = self.vertex_group
467 props.vertex_group_factor = self.vertex_group_factor
468 props.invert_vertex_group = self.invert_vertex_group
469 props.bool_smooth = self.bool_smooth
470 props.system = self.system
471 props.periodic_selection = self.periodic_selection
472 props.bounds_selection = self.bounds_selection
473 props.only_sharp = self.only_sharp
474 props.pattern0 = self.pattern0
475 props.pattern1 = self.pattern1
476 props.pattern_depth = self.pattern_depth
477 props.pattern_offset = self.pattern_offset
479 new_ob.tissue.bool_lock = False
481 bpy.ops.object.tissue_convert_to_curve_update()
483 return {'FINISHED'}
485 class tissue_convert_to_curve_update(Operator):
486 bl_idname = "object.tissue_convert_to_curve_update"
487 bl_label = "Tissue Update Curve"
488 bl_description = "Update Curve object"
489 bl_options = {'REGISTER', 'UNDO'}
491 @classmethod
492 def poll(cls, context):
493 try:
494 ob = context.object
495 bool_curve = ob.tissue_to_curve.object != None
496 return ob.type == 'CURVE' and ob.mode == 'OBJECT' and bool_curve
497 except:
498 return False
500 def execute(self, context):
501 start_time = time.time()
503 ob = context.object
504 props = ob.tissue_to_curve
505 ob0 = props.object
506 if props.mode == 'PARTICLES':
507 eval_ob = ob0.evaluated_get(context.evaluated_depsgraph_get())
508 system_id = min(props.system, len(eval_ob.particle_systems))
509 psystem = eval_ob.particle_systems[system_id]
510 ob.data.splines.clear()
511 particles = psystem.particles
512 for id,p in enumerate(particles):
513 s = ob.data.splines.new('POLY')
514 if psystem.settings.type == 'HAIR':
515 n_pts = len(p.hair_keys)
516 pts = [0]*3*n_pts
517 p.hair_keys.foreach_get('co',pts)
518 co = np.array(pts).reshape((-1,3))
519 else:
520 n_pts = 2**psystem.settings.display_step + 1
521 pts = []
522 for i in range(n_pts):
523 vec = psystem.co_hair(eval_ob, particle_no=id,step=i)
524 vec = ob0.matrix_world.inverted() @ vec
525 pts.append(vec)
526 co = np.array(pts)
527 w = np.ones(n_pts).reshape((n_pts,1))
528 co = np.concatenate((co,w),axis=1).reshape((n_pts*4))
529 s.points.add(n_pts-1)
530 s.points.foreach_set('co',co)
532 else:
533 _ob0 = ob0
534 ob0 = convert_object_to_mesh(ob0, apply_modifiers=props.use_modifiers)
535 me = ob0.data
536 n_verts = len(me.vertices)
537 verts = [0]*n_verts*3
538 me.vertices.foreach_get('co',verts)
539 verts = np.array(verts).reshape((-1,3))
541 normals = [0]*n_verts*3
542 me.vertices.foreach_get('normal',normals)
543 normals = np.array(normals).reshape((-1,3))
544 #tilt = np.degrees(np.arcsin(normals[:,2]))
545 #tilt = np.arccos(normals[:,2])/2
547 verts = np.array(verts).reshape((-1,3))
548 if props.mode in ('LOOPS','EDGES'):
549 bm = bmesh.new()
550 bm.from_mesh(me)
551 bm.verts.ensure_lookup_table()
552 bm.edges.ensure_lookup_table()
553 bm.faces.ensure_lookup_table()
554 todo_edges = list(bm.edges)
555 if props.use_modifiers and props.subdivision_mode != 'ALL':
556 me0, subs = get_mesh_before_subs(_ob0)
557 n_edges0 = len(me0.edges)
558 bpy.data.meshes.remove(me0)
559 if props.subdivision_mode == 'CAGE':
560 todo_edges = todo_edges[:n_edges0*(2**subs)]
561 elif props.subdivision_mode == 'INNER':
562 todo_edges = todo_edges[n_edges0*(2**subs):]
564 if props.only_sharp:
565 _todo_edges = []
566 sharp_verts = []
567 for e in todo_edges:
568 edge = me.edges[e.index]
569 if edge.use_edge_sharp:
570 _todo_edges.append(e)
571 sharp_verts.append(edge.vertices[0])
572 sharp_verts.append(edge.vertices[1])
573 todo_edges = _todo_edges
575 if props.bounds_selection == 'BOUNDS': todo_edges = [e for e in todo_edges if len(e.link_faces)<2]
576 elif props.bounds_selection == 'INNER': todo_edges = [e for e in todo_edges if len(e.link_faces)>1]
578 if props.mode == 'EDGES':
579 ordered_points = [[e.verts[0].index, e.verts[1].index] for e in todo_edges]
580 elif props.mode == 'LOOPS':
581 vert_loops, edge_loops = loops_from_bmesh(todo_edges)
582 if props.only_sharp:
583 ordered_points = []
584 for loop in vert_loops:
585 loop_points = []
586 for v in loop:
587 if v.index in sharp_verts:
588 loop_points.append(v.index)
589 else:
590 if len(loop_points)>1:
591 ordered_points.append(loop_points)
592 loop_points = []
593 if len(loop_points)>1:
594 ordered_points.append(loop_points)
595 #ordered_points = [[v.index for v in loop if v.index in sharp_verts] for loop in vert_loops]
596 else:
597 ordered_points = [[v.index for v in loop] for loop in vert_loops]
598 if props.periodic_selection == 'CLOSED':
599 ordered_points = [points for points in ordered_points if points[0] == points[-1]]
600 elif props.periodic_selection == 'OPEN':
601 ordered_points = [points for points in ordered_points if points[0] != points[-1]]
602 else:
603 try:
604 ordered_points = find_curves(edges, n_verts)
605 except:
606 bpy.data.objects.remove(ob0)
607 return {'CANCELLED'}
609 try:
610 weight = get_weight_numpy(ob0.vertex_groups[props.vertex_group], n_verts)
611 if props.invert_vertex_group: weight = 1-weight
612 fact = props.vertex_group_factor
613 if fact > 0:
614 weight = weight*(1-fact) + fact
615 except:
616 weight = None
618 # Set curves Tilt
620 tilt = []
621 for points in ordered_points:
622 if points[0] == points[-1]: # Closed curve
623 pts0 = [points[-1]] + points[:-1] # i-1
624 pts1 = points[:] # i
625 pts2 = points[1:] + [points[0]] # 1+1
626 else: # Open curve
627 pts0 = [points[0]] + points[:-1] # i-1
628 pts1 = points[:] # i
629 pts2 = points[1:] + [points[-1]] # i+1
630 curve_tilt = []
631 for i0, i1, i2 in zip(pts0, pts1, pts2):
632 pt0 = Vector(verts[i0])
633 pt1 = Vector(verts[i1])
634 pt2 = Vector(verts[i2])
635 tan1 = (pt1-pt0).normalized()
636 tan2 = (pt2-pt1).normalized()
637 vec_tan = -(tan1 + tan2).normalized()
638 vec2 = vec_tan.cross(Vector((0,0,1)))
639 vec_z = vec_tan.cross(vec2)
640 nor = normals[i1]
641 if vec_z.length == 0:
642 vec_z = Vector(nor)
643 ang = vec_z.angle(nor)
644 if nor[2] < 0: ang = 2*pi-ang
645 #if vec_tan[0] > vec_tan[1] and nor[0]>0: ang = -ang
646 #if vec_tan[0] > vec_tan[2] and nor[0]>0: ang = -ang
647 #if vec_tan[0] < vec_tan[1] and nor[1]>0: ang = -ang
648 #if nor[0]*nor[1]*nor[2] < 0: ang = -ang
649 if nor[2] == 0: ang = -5*pi/4
650 #ang = max(ang, np.arccos(nor[2]))
651 curve_tilt.append(ang)
652 #curve_tilt.append(np.arccos(nor[2]))
653 tilt.append(curve_tilt)
655 depth = props.pattern_depth
656 offset = props.pattern_offset
657 pattern = [props.pattern0,props.pattern1]
658 update_curve_from_pydata(ob.data, verts, normals, weight, ordered_points, merge_distance=props.clean_distance, pattern=pattern, depth=depth, offset=offset)
661 bpy.data.objects.remove(ob0)
662 for s in ob.data.splines:
663 s.type = props.spline_type
664 if s.type == 'NURBS':
665 s.use_endpoint_u = props.use_endpoint_u
666 s.order_u = props.nurbs_order
667 ob.data.splines.update()
668 if not props.bool_smooth: bpy.ops.object.shade_flat()
670 end_time = time.time()
671 print('Tissue: object "{}" converted to Curve in {:.4f} sec'.format(ob.name, end_time-start_time))
673 return {'FINISHED'}
676 class TISSUE_PT_convert_to_curve(Panel):
677 bl_space_type = 'PROPERTIES'
678 bl_region_type = 'WINDOW'
679 bl_context = "data"
680 bl_label = "Tissue Convert to Curve"
681 bl_options = {'DEFAULT_CLOSED'}
683 @classmethod
684 def poll(cls, context):
685 try:
686 #bool_curve = context.object.tissue_to_curve.object != None
687 ob = context.object
688 return ob.type == 'CURVE' and ob.tissue.tissue_type == 'TO_CURVE'
689 except:
690 return False
692 def draw(self, context):
693 ob = context.object
694 props = ob.tissue_to_curve
696 layout = self.layout
697 #layout.use_property_split = True
698 #layout.use_property_decorate = False
699 col = layout.column(align=True)
700 row = col.row(align=True)
701 #col.operator("object.tissue_convert_to_curve_update", icon='FILE_REFRESH', text='Refresh')
702 row.operator("object.tissue_update_tessellate_deps", icon='FILE_REFRESH', text='Refresh') ####
703 lock_icon = 'LOCKED' if ob.tissue.bool_lock else 'UNLOCKED'
704 #lock_icon = 'PINNED' if props.bool_lock else 'UNPINNED'
705 deps_icon = 'LINKED' if ob.tissue.bool_dependencies else 'UNLINKED'
706 row.prop(ob.tissue, "bool_dependencies", text="", icon=deps_icon)
707 row.prop(ob.tissue, "bool_lock", text="", icon=lock_icon)
708 col2 = row.column(align=True)
709 col2.prop(ob.tissue, "bool_run", text="",icon='TIME')
710 col2.enabled = not ob.tissue.bool_lock
712 col.separator()
713 row = col.row(align=True)
714 row.prop_search(props, "object", context.scene, "objects")
715 row.prop(props, "use_modifiers", icon='MODIFIER', text='')
716 col.separator()
717 col.label(text='Conversion Mode:')
718 row = col.row(align=True)
719 row.prop(
720 props, "mode", icon='NONE', expand=True,
721 slider=False, toggle=False, icon_only=False, event=False,
722 full_event=False, emboss=True, index=-1)
723 if props.mode == 'PARTICLES':
724 col.separator()
725 col.prop(props, "system")
726 col.separator()
728 if props.mode in ('LOOPS', 'EDGES'):
729 row = col.row(align=True)
730 row.prop(props, "use_modifiers")
731 col2 = row.column(align=True)
732 if props.use_modifiers:
733 col2.prop(props, "subdivision_mode", text='', icon='NONE', expand=False,
734 slider=True, toggle=False, icon_only=False, event=False,
735 full_event=False, emboss=True, index=-1)
736 col2.enabled = False
737 for m in props.object.modifiers:
738 if m.type in ('SUBSURF','MULTIRES'): col2.enabled = True
739 col.separator()
740 row = col.row(align=True)
741 row.label(text='Filter Edges:')
742 col2 = row.column(align=True)
743 col2.prop(props, "bounds_selection", text='', icon='NONE', expand=False,
744 slider=True, toggle=False, icon_only=False, event=False,
745 full_event=False, emboss=True, index=-1)
746 col2.prop(props, 'only_sharp')
747 col.separator()
748 if props.mode == 'LOOPS':
749 row = col.row(align=True)
750 row.label(text='Filter Loops:')
751 row.prop(props, "periodic_selection", text='', icon='NONE', expand=False,
752 slider=True, toggle=False, icon_only=False, event=False,
753 full_event=False, emboss=True, index=-1)
754 col.separator()
756 col.label(text='Spline Type:')
757 row = col.row(align=True)
758 row.prop(
759 props, "spline_type", text="Spline Type", icon='NONE', expand=True,
760 slider=False, toggle=False, icon_only=False, event=False,
761 full_event=False, emboss=True, index=-1)
762 if props.spline_type == 'NURBS':
763 col.separator()
764 col.label(text='Nurbs Splines:')
765 row = col.row(align=True)
766 row.prop(props, "use_endpoint_u")
767 row.prop(props, "nurbs_order")
768 col.separator()
769 col.prop(props, "bool_smooth")
770 if props.object.type == 'MESH':
771 col.separator()
772 col.label(text='Variable Radius:')
773 row = col.row(align=True)
774 row.prop_search(props, 'vertex_group', props.object, "vertex_groups", text='')
775 row.prop(props, "invert_vertex_group", text="", toggle=True, icon='ARROW_LEFTRIGHT')
776 row.prop(props, "vertex_group_factor")
777 col.separator()
778 col.label(text='Clean Curves:')
779 col.prop(props, "clean_distance")
780 col.separator()
781 col.label(text='Displacement Pattern:')
782 row = col.row(align=True)
783 row.prop(props, "pattern0")
784 row.prop(props, "pattern1")
785 row = col.row(align=True)
786 row.prop(props, "pattern_depth")
787 row.prop(props, "pattern_offset")