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