Cleanup: quiet strict name warnings for addons a..h.
[blender-addons.git] / add_curve_extra_objects / add_curve_spirofit_bouncespline.py
blobd0c1c747a3d90069c72aedffdc583cd9ae17fe83
1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
20 bl_info = {
21 "name": "SpiroFit, BounceSpline and Catenary",
22 "author": "Antonio Osprite, Liero, Atom, Jimmy Hazevoet",
23 "version": (0, 2, 1),
24 "blender": (2, 78, 0),
25 "location": "Toolshelf > Create Tab",
26 "description": "SpiroFit, BounceSpline and Catenary adds "
27 "splines to selected mesh or objects",
28 "warning": "",
29 "wiki_url": "",
30 "category": "Object",
33 import bpy
34 from bpy.types import (
35 Operator,
36 Panel,
38 from bpy.props import (
39 BoolProperty,
40 EnumProperty,
41 FloatProperty,
42 IntProperty,
43 StringProperty,
45 from mathutils import (
46 Matrix,
47 Vector,
49 from math import (
50 sin, cos,
51 pi, sqrt,
52 pow, radians
54 import random as r
57 # ------------------------------------------------------------
58 # "Build a spiral that fit the active object"
59 # Spirofit, original blender 2.45 script by: Antonio Osprite
60 # http://www.kino3d.com/forum/viewtopic.php?t=5374
61 # ------------------------------------------------------------
62 def distance(v1, v2):
63 d = (Vector(v1) - Vector(v2)).length
64 return d
67 def spiral_point(step, radius, z_coord, spires, waves, wave_iscale, rndm):
68 x = radius * cos(spires * step) + (r.random() - 0.5) * rndm
69 y = radius * sin(spires * step) + (r.random() - 0.5) * rndm
70 z = z_coord + (cos(waves * step * pi) * wave_iscale) + (r.random() - 0.5) * rndm
71 return [x, y, z]
74 def spirofit_spline(obj,
75 spire_resolution=4,
76 spires=4,
77 offset=0.0,
78 waves=0,
79 wave_iscale=0.0,
80 rndm_spire=0.0,
81 direction=False,
82 map_method='RAYCAST'
85 points = []
86 bb = obj.bound_box
87 bb_xmin = min([v[0] for v in bb])
88 bb_ymin = min([v[1] for v in bb])
89 bb_zmin = min([v[2] for v in bb])
90 bb_xmax = max([v[0] for v in bb])
91 bb_ymax = max([v[1] for v in bb])
92 bb_zmax = max([v[2] for v in bb])
94 radius = distance([bb_xmax, bb_ymax, bb_zmin], [bb_xmin, bb_ymin, bb_zmin]) / 2.0
95 height = bb_zmax - bb_zmin
96 cx = (bb_xmax + bb_xmin) / 2.0
97 cy = (bb_ymax + bb_ymin) / 2.0
98 steps = spires * spire_resolution
100 for i in range(steps + 1):
101 t = bb_zmin + (2 * pi / steps) * i
102 z = bb_zmin + (float(height) / steps) * i
103 if direction:
104 t = -t
105 cp = spiral_point(t, radius, z, spires, waves, wave_iscale, rndm_spire)
107 if map_method == 'RAYCAST':
108 success, hit, nor, index = obj.ray_cast(Vector(cp), (Vector([cx, cy, z]) - Vector(cp)))
109 if success:
110 points.append((hit + offset * nor))
112 elif map_method == 'CLOSESTPOINT':
113 success, hit, nor, index = obj.closest_point_on_mesh(cp)
114 if success:
115 points.append((hit + offset * nor))
117 return points
120 class SpiroFitSpline(Operator):
121 bl_idname = "object.add_spirofit_spline"
122 bl_label = "SpiroFit"
123 bl_description = "Wrap selected mesh in a spiral"
124 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
126 map_method = EnumProperty(
127 name="Mapping",
128 default='RAYCAST',
129 description="Mapping method",
130 items=[('RAYCAST', 'Ray cast', 'Ray casting'),
131 ('CLOSESTPOINT', 'Closest point', 'Closest point on mesh')]
133 direction = BoolProperty(
134 name="Direction",
135 description="Spire direction",
136 default=False
138 spire_resolution = IntProperty(
139 name="Spire Resolution",
140 default=8,
141 min=3,
142 max=1024,
143 soft_max=128,
144 description="Number of steps for one turn"
146 spires = IntProperty(
147 name="Spires",
148 default=4,
149 min=1,
150 max=1024,
151 soft_max=128,
152 description="Number of turns"
154 offset = FloatProperty(
155 name="Offset",
156 default=0.0,
157 precision=3,
158 description="Use normal direction to offset spline"
160 waves = IntProperty(
161 name="Wave",
162 default=0,
163 min=0,
164 description="Wave amount"
166 wave_iscale = FloatProperty(
167 name="Wave Intensity",
168 default=0.0,
169 min=0.0,
170 precision=3,
171 description="Wave intensity scale"
173 rndm_spire = FloatProperty(
174 name="Randomise",
175 default=0.0,
176 min=0.0,
177 precision=3,
178 description="Randomise spire"
180 spline_name = StringProperty(
181 name="Name",
182 default="SpiroFit"
184 spline_type = EnumProperty(
185 name="Spline",
186 default='BEZIER',
187 description="Spline type",
188 items=[('POLY', 'Poly', 'Poly spline'),
189 ('BEZIER', 'Bezier', 'Bezier spline')]
191 resolution_u = IntProperty(
192 name="Resolution U",
193 default=12,
194 min=0,
195 max=64,
196 description="Curve resolution u"
198 bevel = FloatProperty(
199 name="Bevel Radius",
200 default=0.0,
201 min=0.0,
202 precision=3,
203 description="Bevel depth"
205 bevel_res = IntProperty(
206 name="Bevel Resolution",
207 default=0,
208 min=0,
209 max=32,
210 description="Bevel resolution"
212 extrude = FloatProperty(
213 name="Extrude",
214 default=0.0,
215 min=0.0,
216 precision=3,
217 description="Extrude amount"
219 twist_mode = EnumProperty(
220 name="Twisting",
221 default='MINIMUM',
222 description="Twist method, type of tilt calculation",
223 items=[('Z_UP', "Z-Up", 'Z Up'),
224 ('MINIMUM', "Minimum", 'Minimum'),
225 ('TANGENT', "Tangent", 'Tangent')]
227 twist_smooth = FloatProperty(
228 name="Smooth",
229 default=0.0,
230 min=0.0,
231 precision=3,
232 description="Twist smoothing amount for tangents"
234 tilt = FloatProperty(
235 name="Tilt",
236 default=0.0,
237 precision=3,
238 description="Spline handle tilt"
240 random_radius = FloatProperty(
241 name="Randomise",
242 default=0.0,
243 min=0.0,
244 precision=3,
245 description="Randomise radius of spline controlpoints"
247 x_ray = BoolProperty(
248 name="X-Ray",
249 default=False,
250 description="X-Ray - make the object draw in front of others"
252 random_seed = IntProperty(
253 name="Random Seed",
254 default=1,
255 min=0,
256 description="Random seed number"
258 origin_to_start = BoolProperty(
259 name="Origin at Start",
260 description="Set origin at first point of spline",
261 default=False
263 refresh = BoolProperty(
264 name="Refresh",
265 description="Refresh spline",
266 default=False
268 auto_refresh = BoolProperty(
269 name="Auto",
270 description="Auto refresh spline",
271 default=True
274 def draw(self, context):
275 layout = self.layout
276 col = layout.column(align=True)
277 row = col.row(align=True)
279 if self.auto_refresh is False:
280 self.refresh = False
281 elif self.auto_refresh is True:
282 self.refresh = True
284 row.prop(self, "auto_refresh", toggle=True, icon="AUTO", icon_only=True)
285 row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH", icon_only=True)
286 row.operator("object.add_spirofit_spline", text="Add")
287 row.prop(self, "x_ray", toggle=True, icon_only=True, icon="RESTRICT_VIEW_OFF")
288 row.prop(self, "origin_to_start", toggle=True, icon="CURVE_DATA", icon_only=True)
290 col = layout.column(align=True)
291 col.prop(self, "spline_name")
292 col.separator()
293 col.prop(self, "map_method")
294 col.separator()
295 col.prop(self, "spire_resolution")
296 row = col.row(align=True).split(0.9, align=True)
297 row.prop(self, "spires")
298 row.prop(self, "direction", toggle=True, text="", icon="ARROW_LEFTRIGHT")
299 col.prop(self, "offset")
300 col.prop(self, "waves")
301 col.prop(self, "wave_iscale")
302 col.prop(self, "rndm_spire")
303 col.prop(self, "random_seed")
304 draw_spline_settings(self)
306 @classmethod
307 def poll(self, context):
308 ob = context.active_object
309 return ((ob is not None) and
310 (context.mode == 'OBJECT'))
312 def invoke(self, context, event):
313 self.refresh = True
314 return self.execute(context)
316 def execute(self, context):
317 if not self.refresh:
318 return {'PASS_THROUGH'}
320 obj = context.active_object
321 if obj.type != 'MESH':
322 self.report({'WARNING'},
323 "Active Object is not a Mesh. Operation Cancelled")
324 return {'CANCELLED'}
326 undo = context.user_preferences.edit.use_global_undo
327 context.user_preferences.edit.use_global_undo = False
329 bpy.ops.object.select_all(action='DESELECT')
331 r.seed(self.random_seed)
333 points = spirofit_spline(
334 obj,
335 self.spire_resolution,
336 self.spires,
337 self.offset,
338 self.waves,
339 self.wave_iscale,
340 self.rndm_spire,
341 self.direction,
342 self.map_method
345 add_curve_object(
346 points,
347 obj.matrix_world,
348 self.spline_name,
349 self.spline_type,
350 self.resolution_u,
351 self.bevel,
352 self.bevel_res,
353 self.extrude,
354 self.random_radius,
355 self.twist_mode,
356 self.twist_smooth,
357 self.tilt,
358 self.x_ray
361 if self.origin_to_start is True:
362 move_origin_to_start()
364 if self.auto_refresh is False:
365 self.refresh = False
367 context.user_preferences.edit.use_global_undo = undo
368 return {'FINISHED'}
371 # ------------------------------------------------------------
372 # Bounce spline / Fiber mesh
373 # Original script by Liero and Atom
374 # https://blenderartists.org/forum/showthread.php?331750-Fiber-Mesh-Emulation
375 # ------------------------------------------------------------
376 def noise(var=1):
377 rand = Vector((r.gauss(0, 1), r.gauss(0, 1), r.gauss(0, 1)))
378 vec = rand.normalized() * var
379 return vec
382 def bounce_spline(obj,
383 number=1000,
384 ang_noise=0.25,
385 offset=0.0,
386 extra=50,
387 active_face=False
390 dist, points = 1000, []
391 poly = obj.data.polygons
393 if active_face:
394 try:
395 n = poly.active
396 except:
397 print("No active face selected")
398 pass
399 else:
400 n = r.randint(0, len(poly) - 1)
402 end = poly[n].normal.copy() * -1
403 start = poly[n].center
404 points.append(start + offset * end)
406 for i in range(number):
407 for ray in range(extra + 1):
408 end += noise(ang_noise)
409 try:
410 hit, nor, index = obj.ray_cast(start, end * dist)[-3:]
411 except:
412 index = -1
413 if index != -1:
414 start = hit - nor / 10000
415 end = end.reflect(nor).normalized()
416 points.append(hit + offset * nor)
417 break
418 if index == -1:
419 return points
420 return points
423 class BounceSpline(Operator):
424 bl_idname = "object.add_bounce_spline"
425 bl_label = "Bounce Spline"
426 bl_description = "Fill selected mesh with a spline"
427 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
429 bounce_number = IntProperty(
430 name="Bounces",
431 default=1000,
432 min=1,
433 max=100000,
434 soft_max=10000,
435 description="Number of bounces"
437 ang_noise = FloatProperty(
438 name="Angular Noise",
439 default=0.25,
440 min=0.0,
441 precision=3,
442 description="Add some noise to ray direction"
444 offset = FloatProperty(
445 name="Offset",
446 default=0.0,
447 precision=3,
448 description="Use normal direction to offset spline"
450 extra = IntProperty(
451 name="Extra",
452 default=50,
453 min=0,
454 max=1000,
455 description="Number of extra tries if it fails to hit mesh"
457 active_face = BoolProperty(
458 name="Active Face",
459 default=False,
460 description="Starts from active face or a random one"
462 spline_name = StringProperty(
463 name="Name",
464 default="BounceSpline"
466 spline_type = EnumProperty(
467 name="Spline",
468 default='BEZIER',
469 description="Spline type",
470 items=[('POLY', "Poly", "Poly spline"),
471 ('BEZIER', "Bezier", "Bezier spline")]
473 resolution_u = IntProperty(
474 name="Resolution U",
475 default=12,
476 min=0,
477 max=64,
478 description="Curve resolution u"
480 bevel = FloatProperty(
481 name="Bevel Radius",
482 default=0.0,
483 min=0.0,
484 precision=3,
485 description="Bevel depth"
487 bevel_res = IntProperty(
488 name="Bevel Resolution",
489 default=0,
490 min=0,
491 max=32,
492 description="Bevel resolution"
494 extrude = FloatProperty(
495 name="Extrude",
496 default=0.0,
497 min=0.0,
498 precision=3,
499 description="Extrude amount"
501 twist_mode = EnumProperty(
502 name="Twisting",
503 default='MINIMUM',
504 description="Twist method, type of tilt calculation",
505 items=[('Z_UP', "Z-Up", 'Z Up'),
506 ('MINIMUM', "Minimum", 'Minimum'),
507 ('TANGENT', "Tangent", 'Tangent')]
509 twist_smooth = FloatProperty(
510 name="Smooth",
511 default=0.0,
512 min=0.0,
513 precision=3,
514 description="Twist smoothing amount for tangents"
516 tilt = FloatProperty(
517 name="Tilt",
518 default=0.0,
519 precision=3,
520 description="Spline handle tilt"
522 random_radius = FloatProperty(
523 name="Randomise",
524 default=0.0,
525 min=0.0,
526 precision=3,
527 description="Randomise radius of spline controlpoints"
529 x_ray = BoolProperty(
530 name="X-Ray",
531 default=False,
532 description="X-Ray - make the object draw in front of others"
534 random_seed = IntProperty(
535 name="Random Seed",
536 default=1,
537 min=0,
538 description="Random seed number"
540 origin_to_start = BoolProperty(
541 name="Origin at Start",
542 description="Set origin at first point of spline",
543 default=False
545 refresh = BoolProperty(
546 name="Refresh",
547 description="Refresh spline",
548 default=False
550 auto_refresh = BoolProperty(
551 name="Auto",
552 description="Auto refresh spline",
553 default=True
556 def draw(self, context):
557 layout = self.layout
558 col = layout.column(align=True)
559 row = col.row(align=True)
560 if self.auto_refresh is False:
561 self.refresh = False
562 elif self.auto_refresh is True:
563 self.refresh = True
565 row.prop(self, "auto_refresh", toggle=True, icon="AUTO", icon_only=True)
566 row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH", icon_only=True)
567 row.operator("object.add_bounce_spline", text="Add")
568 row.prop(self, "x_ray", toggle=True, icon_only=True, icon="RESTRICT_VIEW_OFF")
569 row.prop(self, "origin_to_start", toggle=True, icon="CURVE_DATA", icon_only=True)
571 col = layout.column(align=True)
572 col.prop(self, "spline_name")
573 col.separator()
574 col.prop(self, "bounce_number")
575 row = col.row(align=True).split(0.9, align=True)
576 row.prop(self, "ang_noise")
577 row.prop(self, "active_face", toggle=True, text="", icon="SNAP_FACE")
578 col.prop(self, "offset")
579 col.prop(self, "extra")
580 col.prop(self, "random_seed")
581 draw_spline_settings(self)
583 @classmethod
584 def poll(self, context):
585 ob = context.active_object
586 return ((ob is not None) and
587 (context.mode == 'OBJECT'))
589 def invoke(self, context, event):
590 self.refresh = True
591 return self.execute(context)
593 def execute(self, context):
594 if not self.refresh:
595 return {'PASS_THROUGH'}
597 obj = context.active_object
598 if obj.type != 'MESH':
599 return {'CANCELLED'}
601 undo = context.user_preferences.edit.use_global_undo
602 context.user_preferences.edit.use_global_undo = False
604 bpy.ops.object.select_all(action='DESELECT')
606 r.seed(self.random_seed)
608 points = bounce_spline(
609 obj,
610 self.bounce_number,
611 self.ang_noise,
612 self.offset,
613 self.extra,
614 self.active_face
617 add_curve_object(
618 points,
619 obj.matrix_world,
620 self.spline_name,
621 self.spline_type,
622 self.resolution_u,
623 self.bevel,
624 self.bevel_res,
625 self.extrude,
626 self.random_radius,
627 self.twist_mode,
628 self.twist_smooth,
629 self.tilt,
630 self.x_ray
633 if self.origin_to_start is True:
634 move_origin_to_start()
636 if self.auto_refresh is False:
637 self.refresh = False
639 context.user_preferences.edit.use_global_undo = undo
640 return {'FINISHED'}
643 # ------------------------------------------------------------
644 # Hang Catenary curve between two selected objects
645 # ------------------------------------------------------------
646 def catenary_curve(
647 start=[-2, 0, 2],
648 end=[2, 0, 2],
649 steps=24,
650 a=2.0
653 points = []
654 lx = end[0] - start[0]
655 ly = end[1] - start[1]
656 lr = sqrt(pow(lx, 2) + pow(ly, 2))
657 lv = lr / 2 - (end[2] - start[2]) * a / lr
658 zv = start[2] - pow(lv, 2) / (2 * a)
659 slx = lx / steps
660 sly = ly / steps
661 slr = lr / steps
662 i = 0
663 while i <= steps:
664 x = start[0] + i * slx
665 y = start[1] + i * sly
666 z = zv + pow((i * slr) - lv, 2) / (2 * a)
667 points.append([x, y, z])
668 i += 1
669 return points
672 class CatenaryCurve(Operator):
673 bl_idname = "object.add_catenary_curve"
674 bl_label = "Catenary"
675 bl_description = "Hang a curve between two selected objects"
676 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
678 steps = IntProperty(
679 name="Steps",
680 description="Resolution of the curve",
681 default=24,
682 min=2,
683 max=1024,
685 var_a = FloatProperty(
686 name="a",
687 description="Catenary variable a",
688 precision=3,
689 default=2.0,
690 min=0.01,
691 max=100.0
693 spline_name = StringProperty(
694 name="Name",
695 default="Catenary"
697 spline_type = EnumProperty(
698 name="Spline",
699 default='BEZIER',
700 description="Spline type",
701 items=[('POLY', "Poly", "Poly spline"),
702 ('BEZIER', "Bezier", "Bezier spline")]
704 resolution_u = IntProperty(
705 name="Resolution U",
706 default=12,
707 min=0,
708 max=64,
709 description="Curve resolution u"
711 bevel = FloatProperty(
712 name="Bevel Radius",
713 default=0.0,
714 min=0.0,
715 precision=3,
716 description="Bevel depth"
718 bevel_res = IntProperty(
719 name="Bevel Resolution",
720 default=0,
721 min=0,
722 max=32,
723 description="Bevel resolution"
725 extrude = FloatProperty(
726 name="Extrude",
727 default=0.0,
728 min=0.0,
729 precision=3,
730 description="Extrude amount"
732 twist_mode = EnumProperty(
733 name="Twisting",
734 default='MINIMUM',
735 description="Twist method, type of tilt calculation",
736 items=[('Z_UP', "Z-Up", 'Z Up'),
737 ('MINIMUM', "Minimum", "Minimum"),
738 ('TANGENT', "Tangent", "Tangent")]
740 twist_smooth = FloatProperty(
741 name="Smooth",
742 default=0.0,
743 min=0.0,
744 precision=3,
745 description="Twist smoothing amount for tangents"
747 tilt = FloatProperty(
748 name="Tilt",
749 default=0.0,
750 precision=3,
751 description="Spline handle tilt"
753 random_radius = FloatProperty(
754 name="Randomise",
755 default=0.0,
756 min=0.0,
757 precision=3,
758 description="Randomise radius of spline controlpoints"
760 x_ray = BoolProperty(
761 name="X-Ray",
762 default=False,
763 description="X-Ray - make the object draw in front of others"
765 random_seed = IntProperty(
766 name="Random Seed",
767 default=1,
768 min=0,
769 description="Random seed number"
771 origin_to_start = BoolProperty(
772 name="Origin at Start",
773 description="Set origin at first point of spline",
774 default=False
776 refresh = BoolProperty(
777 name="Refresh",
778 description="Refresh spline",
779 default=False
781 auto_refresh = BoolProperty(
782 name="Auto",
783 description="Auto refresh spline",
784 default=True
787 def draw(self, context):
788 layout = self.layout
789 col = layout.column(align=True)
790 row = col.row(align=True)
792 if self.auto_refresh is False:
793 self.refresh = False
794 elif self.auto_refresh is True:
795 self.refresh = True
797 row.prop(self, "auto_refresh", toggle=True, icon="AUTO", icon_only=True)
798 row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH", icon_only=True)
799 row.operator("object.add_catenary_curve", text="Add")
800 row.prop(self, "x_ray", toggle=True, icon_only=True, icon="RESTRICT_VIEW_OFF")
801 row.prop(self, "origin_to_start", toggle=True, icon="CURVE_DATA", icon_only=True)
803 col = layout.column(align=True)
804 col.prop(self, "spline_name")
805 col.separator()
806 col.prop(self, "steps")
807 col.prop(self, "var_a")
809 draw_spline_settings(self)
810 col = layout.column(align=True)
811 col.prop(self, "random_seed")
813 @classmethod
814 def poll(self, context):
815 ob = context.active_object
816 return ob is not None
818 def invoke(self, context, event):
819 self.refresh = True
820 return self.execute(context)
822 def execute(self, context):
823 if not self.refresh:
824 return {'PASS_THROUGH'}
826 try:
827 ob1 = bpy.context.active_object
828 ob1.select = False
829 ob2 = bpy.context.selected_objects[0]
830 start = ob1.location
831 end = ob2.location
832 if (start[0] == end[0]) and (start[1] == end[1]):
833 self.report({"WARNING"},
834 "Objects have the same X, Y location. Operation Cancelled")
836 return {'CANCELLED'}
837 except:
838 self.report({"WARNING"},
839 "Catenary could not be completed. Operation Cancelled")
840 return {'CANCELLED'}
842 bpy.ops.object.select_all(action='DESELECT')
844 undo = context.user_preferences.edit.use_global_undo
845 context.user_preferences.edit.use_global_undo = False
847 r.seed(self.random_seed)
849 points = catenary_curve(
850 start,
851 end,
852 self.steps,
853 self.var_a
855 add_curve_object(
856 points,
857 Matrix(),
858 self.spline_name,
859 self.spline_type,
860 self.resolution_u,
861 self.bevel,
862 self.bevel_res,
863 self.extrude,
864 self.random_radius,
865 self.twist_mode,
866 self.twist_smooth,
867 self.tilt,
868 self.x_ray
871 if self.origin_to_start is True:
872 move_origin_to_start()
873 else:
874 bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
876 if self.auto_refresh is False:
877 self.refresh = False
879 context.user_preferences.edit.use_global_undo = undo
880 return {'FINISHED'}
883 # ------------------------------------------------------------
884 # Generate curve object from given points
885 # ------------------------------------------------------------
886 def add_curve_object(
887 verts,
888 matrix,
889 spline_name="Spline",
890 spline_type='BEZIER',
891 resolution_u=12,
892 bevel=0.0,
893 bevel_resolution=0,
894 extrude=0.0,
895 spline_radius=0.0,
896 twist_mode='MINIMUM',
897 twist_smooth=0.0,
898 tilt=0.0,
899 x_ray=False
902 curve = bpy.data.curves.new(spline_name, 'CURVE')
903 curve.dimensions = '3D'
904 spline = curve.splines.new(spline_type)
905 cur = bpy.data.objects.new(spline_name, curve)
907 spline.radius_interpolation = 'BSPLINE'
908 spline.tilt_interpolation = 'BSPLINE'
910 if spline_type == 'BEZIER':
911 spline.bezier_points.add(int(len(verts) - 1))
912 for i in range(len(verts)):
913 spline.bezier_points[i].co = verts[i]
914 spline.bezier_points[i].handle_right_type = 'AUTO'
915 spline.bezier_points[i].handle_left_type = 'AUTO'
916 spline.bezier_points[i].radius += spline_radius * r.random()
917 spline.bezier_points[i].tilt = radians(tilt)
918 else:
919 spline.points.add(int(len(verts) - 1))
920 for i in range(len(verts)):
921 spline.points[i].co = verts[i][0], verts[i][1], verts[i][2], 1
923 bpy.context.scene.objects.link(cur)
924 cur.data.use_uv_as_generated = True
925 cur.data.resolution_u = resolution_u
926 cur.data.fill_mode = 'FULL'
927 cur.data.bevel_depth = bevel
928 cur.data.bevel_resolution = bevel_resolution
929 cur.data.extrude = extrude
930 cur.data.twist_mode = twist_mode
931 cur.data.twist_smooth = twist_smooth
932 cur.matrix_world = matrix
933 bpy.context.scene.objects.active = cur
934 cur.select = True
935 if x_ray is True:
936 cur.show_x_ray = x_ray
937 return
940 def move_origin_to_start():
941 active = bpy.context.active_object
942 spline = active.data.splines[0]
943 if spline.type == 'BEZIER':
944 start = active.matrix_world * spline.bezier_points[0].co
945 else:
946 start = active.matrix_world * spline.points[0].co
947 start = start[:-1]
948 cursor = bpy.context.scene.cursor_location.copy()
949 bpy.context.scene.cursor_location = start
950 bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
951 bpy.context.scene.cursor_location = cursor
954 def draw_spline_settings(self):
955 layout = self.layout
956 col = layout.column(align=True)
958 col.prop(self, "spline_type")
959 col.separator()
960 col.prop(self, "resolution_u")
961 col.prop(self, "bevel")
962 col.prop(self, "bevel_res")
963 col.prop(self, "extrude")
965 if self.spline_type == 'BEZIER':
966 col.prop(self, "random_radius")
967 col.separator()
968 col.prop(self, "twist_mode")
969 col.separator()
971 if self.twist_mode == 'TANGENT':
972 col.prop(self, "twist_smooth")
974 if self.spline_type == 'BEZIER':
975 col.prop(self, "tilt")
978 # ------------------------------------------------------------
979 # Tools Panel > Create
980 # ------------------------------------------------------------
981 class SplinePanel(Panel):
982 bl_idname = "VIEW3D_PT_spirofit_spline"
983 bl_space_type = "VIEW_3D"
984 bl_context = "objectmode"
985 bl_region_type = "TOOLS"
986 bl_label = "Spline"
987 bl_category = "Create"
988 bl_options = {'DEFAULT_CLOSED'}
990 def draw(self, context):
991 col = self.layout.column(align=True)
992 col.operator(SpiroFitSpline.bl_idname, icon="FORCE_MAGNETIC")
993 col.operator(BounceSpline.bl_idname, icon="FORCE_HARMONIC")
994 col.operator(CatenaryCurve.bl_idname, icon="FORCE_CURVE")
997 # ------------------------------------------------------------
998 # Register
999 # ------------------------------------------------------------
1000 def register():
1001 bpy.utils.register_class(SplinePanel)
1002 bpy.utils.register_class(SpiroFitSpline)
1003 bpy.utils.register_class(BounceSpline)
1004 bpy.utils.register_class(CatenaryCurve)
1007 def unregister():
1008 bpy.utils.unregister_class(SplinePanel)
1009 bpy.utils.unregister_class(SpiroFitSpline)
1010 bpy.utils.unregister_class(BounceSpline)
1011 bpy.utils.unregister_class(CatenaryCurve)
1014 if __name__ == "__main__":
1015 register()