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