Import images as planes: use Principled BSDF for emission mode
[blender-addons.git] / add_curve_extra_objects / add_curve_spirofit_bouncespline.py
blob41b8a6b5498e9f800b5d282547516e395e996c3a
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, 2),
24 "blender": (2, 80, 0),
25 "location": "Sidebar > Create Tab",
26 "description": "SpiroFit, BounceSpline and Catenary adds "
27 "splines to selected mesh or objects",
28 "warning": "",
29 "doc_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 random_seed : IntProperty(
248 name="Random Seed",
249 default=1,
250 min=0,
251 description="Random seed number"
253 origin_to_start : BoolProperty(
254 name="Origin at Start",
255 description="Set origin at first point of spline",
256 default=False
258 refresh : BoolProperty(
259 name="Refresh",
260 description="Refresh spline",
261 default=False
263 auto_refresh : BoolProperty(
264 name="Auto",
265 description="Auto refresh spline",
266 default=True
269 def draw(self, context):
270 layout = self.layout
271 col = layout.column(align=True)
272 row = col.row(align=True)
274 if self.auto_refresh is False:
275 self.refresh = False
276 elif self.auto_refresh is True:
277 self.refresh = True
279 row.prop(self, "auto_refresh", toggle=True, icon="AUTO", icon_only=True)
280 row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH", icon_only=True)
281 row.operator("object.add_spirofit_spline", text="Add")
282 row.prop(self, "origin_to_start", toggle=True, icon="CURVE_DATA", icon_only=True)
284 col = layout.column(align=True)
285 col.prop(self, "spline_name")
286 col.separator()
287 col.prop(self, "map_method")
288 col.separator()
289 col.prop(self, "spire_resolution")
290 row = col.row(align=True).split(factor=0.9, align=True)
291 row.prop(self, "spires")
292 row.prop(self, "direction", toggle=True, text="", icon='ARROW_LEFTRIGHT')
293 col.prop(self, "offset")
294 col.prop(self, "waves")
295 col.prop(self, "wave_iscale")
296 col.prop(self, "rndm_spire")
297 col.prop(self, "random_seed")
298 draw_spline_settings(self)
300 @classmethod
301 def poll(self, context):
302 ob = context.active_object
303 return ((ob is not None) and
304 (context.mode == 'OBJECT'))
306 def invoke(self, context, event):
307 self.refresh = True
308 return self.execute(context)
310 def execute(self, context):
311 if not self.refresh:
312 return {'PASS_THROUGH'}
314 obj = context.active_object
315 if obj.type != 'MESH':
316 self.report({'WARNING'},
317 "Active Object is not a Mesh. Operation Cancelled")
318 return {'CANCELLED'}
320 bpy.ops.object.select_all(action='DESELECT')
322 r.seed(self.random_seed)
324 points = spirofit_spline(
325 obj,
326 self.spire_resolution,
327 self.spires,
328 self.offset,
329 self.waves,
330 self.wave_iscale,
331 self.rndm_spire,
332 self.direction,
333 self.map_method
336 add_curve_object(
337 points,
338 obj.matrix_world,
339 self.spline_name,
340 self.spline_type,
341 self.resolution_u,
342 self.bevel,
343 self.bevel_res,
344 self.extrude,
345 self.random_radius,
346 self.twist_mode,
347 self.twist_smooth,
348 self.tilt
351 if self.origin_to_start is True:
352 move_origin_to_start()
354 if self.auto_refresh is False:
355 self.refresh = False
357 return {'FINISHED'}
360 # ------------------------------------------------------------
361 # Bounce spline / Fiber mesh
362 # Original script by Liero and Atom
363 # https://blenderartists.org/forum/showthread.php?331750-Fiber-Mesh-Emulation
364 # ------------------------------------------------------------
365 def noise(var=1):
366 rand = Vector((r.gauss(0, 1), r.gauss(0, 1), r.gauss(0, 1)))
367 vec = rand.normalized() * var
368 return vec
371 def bounce_spline(obj,
372 number=1000,
373 ang_noise=0.25,
374 offset=0.0,
375 extra=50,
376 active_face=False
379 dist, points = 1000, []
380 poly = obj.data.polygons
382 if active_face:
383 try:
384 n = poly.active
385 except:
386 print("No active face selected")
387 pass
388 else:
389 n = r.randint(0, len(poly) - 1)
391 end = poly[n].normal.copy() * -1
392 start = poly[n].center
393 points.append(start + offset * end)
395 for i in range(number):
396 for ray in range(extra + 1):
397 end += noise(ang_noise)
398 try:
399 hit, nor, index = obj.ray_cast(start, end * dist)[-3:]
400 except:
401 index = -1
402 if index != -1:
403 start = hit - nor / 10000
404 end = end.reflect(nor).normalized()
405 points.append(hit + offset * nor)
406 break
407 if index == -1:
408 return points
409 return points
412 class BounceSpline(Operator):
413 bl_idname = "object.add_bounce_spline"
414 bl_label = "Bounce Spline"
415 bl_description = "Fill selected mesh with a spline"
416 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
418 bounce_number : IntProperty(
419 name="Bounces",
420 default=1000,
421 min=1,
422 max=100000,
423 soft_max=10000,
424 description="Number of bounces"
426 ang_noise : FloatProperty(
427 name="Angular Noise",
428 default=0.25,
429 min=0.0,
430 precision=3,
431 description="Add some noise to ray direction"
433 offset : FloatProperty(
434 name="Offset",
435 default=0.0,
436 precision=3,
437 description="Use normal direction to offset spline"
439 extra : IntProperty(
440 name="Extra",
441 default=50,
442 min=0,
443 max=1000,
444 description="Number of extra tries if it fails to hit mesh"
446 active_face : BoolProperty(
447 name="Active Face",
448 default=False,
449 description="Starts from active face or a random one"
451 spline_name : StringProperty(
452 name="Name",
453 default="BounceSpline"
455 spline_type : EnumProperty(
456 name="Spline",
457 default='BEZIER',
458 description="Spline type",
459 items=[('POLY', "Poly", "Poly spline"),
460 ('BEZIER', "Bezier", "Bezier spline")]
462 resolution_u : IntProperty(
463 name="Resolution U",
464 default=12,
465 min=0,
466 max=64,
467 description="Curve resolution u"
469 bevel : FloatProperty(
470 name="Bevel Radius",
471 default=0.0,
472 min=0.0,
473 precision=3,
474 description="Bevel depth"
476 bevel_res : IntProperty(
477 name="Bevel Resolution",
478 default=0,
479 min=0,
480 max=32,
481 description="Bevel resolution"
483 extrude : FloatProperty(
484 name="Extrude",
485 default=0.0,
486 min=0.0,
487 precision=3,
488 description="Extrude amount"
490 twist_mode : EnumProperty(
491 name="Twisting",
492 default='MINIMUM',
493 description="Twist method, type of tilt calculation",
494 items=[('Z_UP', "Z-Up", 'Z Up'),
495 ('MINIMUM', "Minimum", 'Minimum'),
496 ('TANGENT', "Tangent", 'Tangent')]
498 twist_smooth : FloatProperty(
499 name="Smooth",
500 default=0.0,
501 min=0.0,
502 precision=3,
503 description="Twist smoothing amount for tangents"
505 tilt : FloatProperty(
506 name="Tilt",
507 default=0.0,
508 precision=3,
509 description="Spline handle tilt"
511 random_radius : FloatProperty(
512 name="Randomise",
513 default=0.0,
514 min=0.0,
515 precision=3,
516 description="Randomise radius of spline controlpoints"
518 random_seed : IntProperty(
519 name="Random Seed",
520 default=1,
521 min=0,
522 description="Random seed number"
524 origin_to_start : BoolProperty(
525 name="Origin at Start",
526 description="Set origin at first point of spline",
527 default=False
529 refresh : BoolProperty(
530 name="Refresh",
531 description="Refresh spline",
532 default=False
534 auto_refresh : BoolProperty(
535 name="Auto",
536 description="Auto refresh spline",
537 default=True
540 def draw(self, context):
541 layout = self.layout
542 col = layout.column(align=True)
543 row = col.row(align=True)
544 if self.auto_refresh is False:
545 self.refresh = False
546 elif self.auto_refresh is True:
547 self.refresh = True
549 row.prop(self, "auto_refresh", toggle=True, icon="AUTO", icon_only=True)
550 row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH", icon_only=True)
551 row.operator("object.add_bounce_spline", text="Add")
552 row.prop(self, "origin_to_start", toggle=True, icon="CURVE_DATA", icon_only=True)
554 col = layout.column(align=True)
555 col.prop(self, "spline_name")
556 col.separator()
557 col.prop(self, "bounce_number")
558 row = col.row(align=True).split(factor=0.9, align=True)
559 row.prop(self, "ang_noise")
560 row.prop(self, "active_face", toggle=True, text="", icon="SNAP_FACE")
561 col.prop(self, "offset")
562 col.prop(self, "extra")
563 col.prop(self, "random_seed")
564 draw_spline_settings(self)
566 @classmethod
567 def poll(self, context):
568 ob = context.active_object
569 return ((ob is not None) and
570 (context.mode == 'OBJECT'))
572 def invoke(self, context, event):
573 self.refresh = True
574 return self.execute(context)
576 def execute(self, context):
577 if not self.refresh:
578 return {'PASS_THROUGH'}
580 obj = context.active_object
581 if obj.type != 'MESH':
582 return {'CANCELLED'}
584 bpy.ops.object.select_all(action='DESELECT')
586 r.seed(self.random_seed)
588 points = bounce_spline(
589 obj,
590 self.bounce_number,
591 self.ang_noise,
592 self.offset,
593 self.extra,
594 self.active_face
597 add_curve_object(
598 points,
599 obj.matrix_world,
600 self.spline_name,
601 self.spline_type,
602 self.resolution_u,
603 self.bevel,
604 self.bevel_res,
605 self.extrude,
606 self.random_radius,
607 self.twist_mode,
608 self.twist_smooth,
609 self.tilt
612 if self.origin_to_start is True:
613 move_origin_to_start()
615 if self.auto_refresh is False:
616 self.refresh = False
618 return {'FINISHED'}
621 # ------------------------------------------------------------
622 # Hang Catenary curve between two selected objects
623 # ------------------------------------------------------------
624 def catenary_curve(
625 start=[-2, 0, 2],
626 end=[2, 0, 2],
627 steps=24,
628 a=2.0
631 points = []
632 lx = end[0] - start[0]
633 ly = end[1] - start[1]
634 lr = sqrt(pow(lx, 2) + pow(ly, 2))
635 lv = lr / 2 - (end[2] - start[2]) * a / lr
636 zv = start[2] - pow(lv, 2) / (2 * a)
637 slx = lx / steps
638 sly = ly / steps
639 slr = lr / steps
640 i = 0
641 while i <= steps:
642 x = start[0] + i * slx
643 y = start[1] + i * sly
644 z = zv + pow((i * slr) - lv, 2) / (2 * a)
645 points.append([x, y, z])
646 i += 1
647 return points
650 class CatenaryCurve(Operator):
651 bl_idname = "object.add_catenary_curve"
652 bl_label = "Catenary"
653 bl_description = "Hang a curve between two selected objects"
654 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
656 steps : IntProperty(
657 name="Steps",
658 description="Resolution of the curve",
659 default=24,
660 min=2,
661 max=1024,
663 var_a : FloatProperty(
664 name="a",
665 description="Catenary variable a",
666 precision=3,
667 default=2.0,
668 min=0.01,
669 max=100.0
671 spline_name : StringProperty(
672 name="Name",
673 default="Catenary"
675 spline_type : EnumProperty(
676 name="Spline",
677 default='BEZIER',
678 description="Spline type",
679 items=[('POLY', "Poly", "Poly spline"),
680 ('BEZIER', "Bezier", "Bezier spline")]
682 resolution_u : IntProperty(
683 name="Resolution U",
684 default=12,
685 min=0,
686 max=64,
687 description="Curve resolution u"
689 bevel : FloatProperty(
690 name="Bevel Radius",
691 default=0.0,
692 min=0.0,
693 precision=3,
694 description="Bevel depth"
696 bevel_res : IntProperty(
697 name="Bevel Resolution",
698 default=0,
699 min=0,
700 max=32,
701 description="Bevel resolution"
703 extrude : FloatProperty(
704 name="Extrude",
705 default=0.0,
706 min=0.0,
707 precision=3,
708 description="Extrude amount"
710 twist_mode : EnumProperty(
711 name="Twisting",
712 default='MINIMUM',
713 description="Twist method, type of tilt calculation",
714 items=[('Z_UP', "Z-Up", 'Z Up'),
715 ('MINIMUM', "Minimum", "Minimum"),
716 ('TANGENT', "Tangent", "Tangent")]
718 twist_smooth : FloatProperty(
719 name="Smooth",
720 default=0.0,
721 min=0.0,
722 precision=3,
723 description="Twist smoothing amount for tangents"
725 tilt : FloatProperty(
726 name="Tilt",
727 default=0.0,
728 precision=3,
729 description="Spline handle tilt"
731 random_radius : FloatProperty(
732 name="Randomise",
733 default=0.0,
734 min=0.0,
735 precision=3,
736 description="Randomise radius of spline controlpoints"
738 random_seed : IntProperty(
739 name="Random Seed",
740 default=1,
741 min=0,
742 description="Random seed number"
744 origin_to_start : BoolProperty(
745 name="Origin at Start",
746 description="Set origin at first point of spline",
747 default=False
749 refresh : BoolProperty(
750 name="Refresh",
751 description="Refresh spline",
752 default=False
754 auto_refresh : BoolProperty(
755 name="Auto",
756 description="Auto refresh spline",
757 default=True
760 def draw(self, context):
761 layout = self.layout
762 col = layout.column(align=True)
763 row = col.row(align=True)
765 if self.auto_refresh is False:
766 self.refresh = False
767 elif self.auto_refresh is True:
768 self.refresh = True
770 row.prop(self, "auto_refresh", toggle=True, icon="AUTO", icon_only=True)
771 row.prop(self, "refresh", toggle=True, icon="FILE_REFRESH", icon_only=True)
772 row.operator("object.add_catenary_curve", text="Add")
773 row.prop(self, "origin_to_start", toggle=True, icon="CURVE_DATA", icon_only=True)
775 col = layout.column(align=True)
776 col.prop(self, "spline_name")
777 col.separator()
778 col.prop(self, "steps")
779 col.prop(self, "var_a")
781 draw_spline_settings(self)
782 col = layout.column(align=True)
783 col.prop(self, "random_seed")
785 @classmethod
786 def poll(self, context):
787 ob = context.active_object
788 return ob is not None
790 def invoke(self, context, event):
791 self.refresh = True
792 return self.execute(context)
794 def execute(self, context):
795 if not self.refresh:
796 return {'PASS_THROUGH'}
798 try:
799 #ob1 = bpy.context.active_object
800 #ob1.select = False
801 ob1 = bpy.context.selected_objects[0]
802 ob2 = bpy.context.selected_objects[1]
804 start = ob1.location
805 end = ob2.location
806 if (start[0] == end[0]) and (start[1] == end[1]):
807 self.report({"WARNING"},
808 "Objects have the same X, Y location. Operation Cancelled")
810 return {'CANCELLED'}
811 except:
812 self.report({"WARNING"},
813 "Catenary could not be completed. Operation Cancelled")
814 return {'CANCELLED'}
816 bpy.ops.object.select_all(action='DESELECT')
818 r.seed(self.random_seed)
820 points = catenary_curve(
821 start,
822 end,
823 self.steps,
824 self.var_a
826 add_curve_object(
827 points,
828 Matrix(),
829 self.spline_name,
830 self.spline_type,
831 self.resolution_u,
832 self.bevel,
833 self.bevel_res,
834 self.extrude,
835 self.random_radius,
836 self.twist_mode,
837 self.twist_smooth,
838 self.tilt
841 if self.origin_to_start is True:
842 move_origin_to_start()
843 else:
844 bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
846 if self.auto_refresh is False:
847 self.refresh = False
849 return {'FINISHED'}
852 # ------------------------------------------------------------
853 # Generate curve object from given points
854 # ------------------------------------------------------------
855 def add_curve_object(
856 verts,
857 matrix,
858 spline_name="Spline",
859 spline_type='BEZIER',
860 resolution_u=12,
861 bevel=0.0,
862 bevel_resolution=0,
863 extrude=0.0,
864 spline_radius=0.0,
865 twist_mode='MINIMUM',
866 twist_smooth=0.0,
867 tilt=0.0
870 scene = bpy.context.scene
871 vl = bpy.context.view_layer
872 curve = bpy.data.curves.new(spline_name, 'CURVE')
873 curve.dimensions = '3D'
874 spline = curve.splines.new(spline_type)
875 cur = bpy.data.objects.new(spline_name, curve)
876 spline.radius_interpolation = 'BSPLINE'
877 spline.tilt_interpolation = 'BSPLINE'
879 if spline_type == 'BEZIER':
880 spline.bezier_points.add(int(len(verts) - 1))
881 for i in range(len(verts)):
882 spline.bezier_points[i].co = verts[i]
883 spline.bezier_points[i].handle_right_type = 'AUTO'
884 spline.bezier_points[i].handle_left_type = 'AUTO'
885 spline.bezier_points[i].radius += spline_radius * r.random()
886 spline.bezier_points[i].tilt = radians(tilt)
887 else:
888 spline.points.add(int(len(verts) - 1))
889 for i in range(len(verts)):
890 spline.points[i].co = verts[i][0], verts[i][1], verts[i][2], 1
892 scene.collection.objects.link(cur)
893 cur.data.resolution_u = resolution_u
894 cur.data.fill_mode = 'FULL'
895 cur.data.bevel_depth = bevel
896 cur.data.bevel_resolution = bevel_resolution
897 cur.data.extrude = extrude
898 cur.data.twist_mode = twist_mode
899 cur.data.twist_smooth = twist_smooth
900 cur.matrix_world = matrix
901 cur.select_set(True)
902 vl.objects.active = cur
903 return
906 def move_origin_to_start():
907 active = bpy.context.active_object
908 spline = active.data.splines[0]
910 if spline.type == 'BEZIER':
911 start = active.matrix_world @ spline.bezier_points[0].co
912 else:
913 start = active.matrix_world @ spline.points[0].co
914 start = start[:-1]
916 cursor = bpy.context.scene.cursor.location.copy()
917 bpy.context.scene.cursor.location = start
918 bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
919 bpy.context.scene.cursor.location = cursor
922 def draw_spline_settings(self):
923 layout = self.layout
924 col = layout.column(align=True)
926 col.prop(self, "spline_type")
927 col.separator()
928 col.prop(self, "resolution_u")
929 col.prop(self, "bevel")
930 col.prop(self, "bevel_res")
931 col.prop(self, "extrude")
933 if self.spline_type == 'BEZIER':
934 col.prop(self, "random_radius")
935 col.separator()
936 col.prop(self, "twist_mode")
937 col.separator()
939 if self.twist_mode == 'TANGENT':
940 col.prop(self, "twist_smooth")
942 if self.spline_type == 'BEZIER':
943 col.prop(self, "tilt")
946 # ------------------------------------------------------------
947 # Register
948 # ------------------------------------------------------------
949 def register():
950 bpy.utils.register_class(SpiroFitSpline)
951 bpy.utils.register_class(BounceSpline)
952 bpy.utils.register_class(CatenaryCurve)
955 def unregister():
956 bpy.utils.unregister_class(SpiroFitSpline)
957 bpy.utils.unregister_class(BounceSpline)
958 bpy.utils.unregister_class(CatenaryCurve)
961 if __name__ == "__main__":
962 register()