1 # SPDX-FileCopyrightText: 2010-2022 Blender Foundation
3 # SPDX-License-Identifier: GPL-2.0-or-later
7 "name": "Curveaceous Galore!",
8 "author": "Jimmy Hazevoet, testscreenings",
11 "location": "View3D > Add > Curve",
12 "description": "Adds many different types of Curves",
14 "doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
15 "category": "Add Curve",
20 from bpy_extras
import object_utils
21 from bpy
.props
import (
28 from mathutils
import Matrix
, Vector
29 from bpy
.types
import Operator
33 import mathutils
.noise
as Noise
36 # ------------------------------------------------------------
37 # Some functions to use with others:
38 # ------------------------------------------------------------
40 # ------------------------------------------------------------
41 # Generate random number:
42 def randnum(low
=0.0, high
=1.0, seed
=0):
44 randnum( low=0.0, high=1.0, seed=0 )
52 seed - the random seed number, if seed == 0, the current time will be used instead
61 rnum
= rnum
* (high
- low
)
66 # ------------------------------------------------------------
68 def vTurbNoise(x
, y
, z
, iScale
=0.25, Size
=1.0, Depth
=6, Hard
=False, Basis
=0, Seed
=0):
70 vTurbNoise((x,y,z), iScale=0.25, Size=1.0, Depth=6, Hard=0, Basis=0, Seed=0 )
72 Create randomised vTurbulence noise
75 xyz - (x,y,z) float values.
77 iScale - noise intensity scale
81 Depth - number of noise values added.
83 Hard - noise hardness: True - soft noise; False - hard noise
85 basis - type of noise used for turbulence
87 Seed - the random seed number, if seed == 0, the current time will be used instead
90 the generated turbulence vector.
93 rand
= randnum(-100, 100, Seed
)
96 vec
= Vector((x
/ Size
+ rand
, y
/ Size
+ rand
, z
/ Size
+ rand
))
97 vTurb
= Noise
.turbulence_vector(vec
, Depth
, Hard
)
98 #mathutils.noise.turbulence_vector(position, octaves, hard, noise_basis='PERLIN_ORIGINAL', amplitude_scale=0.5, frequency_scale=2.0)
99 tx
= vTurb
[0] * iScale
100 ty
= vTurb
[1] * iScale
101 tz
= vTurb
[2] * iScale
105 # -------------------------------------------------------------------
106 # 2D Curve shape functions:
107 # -------------------------------------------------------------------
109 # ------------------------------------------------------------
110 # 2DCurve: Profile: L, H, T, U, Z
111 def ProfileCurve(type=0, a
=0.25, b
=0.25):
113 ProfileCurve( type=0, a=0.25, b=0.25 )
118 type - select profile type, L, H, T, U, Z
120 a - a scaling parameter
122 b - b scaling parameter
125 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
135 [-1.0, 1.0, 0.0], [-1.0 + a
, 1.0, 0.0],
136 [-1.0 + a
, b
, 0.0], [1.0 - a
, b
, 0.0], [1.0 - a
, 1.0, 0.0],
137 [1.0, 1.0, 0.0], [1.0, -1.0, 0.0], [1.0 - a
, -1.0, 0.0],
138 [1.0 - a
, -b
, 0.0], [-1.0 + a
, -b
, 0.0], [-1.0 + a
, -1.0, 0.0],
145 [-1.0, 1.0, 0.0], [1.0, 1.0, 0.0],
146 [1.0, 1.0 - b
, 0.0], [a
, 1.0 - b
, 0.0], [a
, -1.0, 0.0],
147 [-a
, -1.0, 0.0], [-a
, 1.0 - b
, 0.0], [-1.0, 1.0 - b
, 0.0]
153 [-1.0, 1.0, 0.0], [-1.0 + a
, 1.0, 0.0],
154 [-1.0 + a
, -1.0 + b
, 0.0], [1.0 - a
, -1.0 + b
, 0.0], [1.0 - a
, 1.0, 0.0],
155 [1.0, 1.0, 0.0], [1.0, -1.0, 0.0], [-1.0, -1.0, 0.0]
161 [-0.5, 1.0, 0.0], [a
, 1.0, 0.0],
162 [a
, -1.0 + b
, 0.0], [1.0, -1.0 + b
, 0.0], [1.0, -1.0, 0.0],
163 [-a
, -1.0, 0.0], [-a
, 1.0 - b
, 0.0], [-1.0, 1.0 - b
, 0.0],
169 [-1.0, 1.0, 0.0], [-1.0 + a
, 1.0, 0.0],
170 [-1.0 + a
, -1.0 + b
, 0.0], [1.0, -1.0 + b
, 0.0],
171 [1.0, -1.0, 0.0], [-1.0, -1.0, 0.0]
176 # ------------------------------------------------------------
178 def ArrowCurve(type=1, a
=1.0, b
=0.5):
180 ArrowCurve( type=1, a=1.0, b=0.5, c=1.0 )
185 type - select type, Arrow1, Arrow2
187 a - a scaling parameter
189 b - b scaling parameter
192 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
202 [-1.0, b
, 0.0], [-1.0 + a
, b
, 0.0],
203 [-1.0 + a
, 1.0, 0.0], [1.0, 0.0, 0.0],
204 [-1.0 + a
, -1.0, 0.0], [-1.0 + a
, -b
, 0.0],
209 newpoints
= [[-a
, b
, 0.0], [a
, 0.0, 0.0], [-a
, -b
, 0.0], [0.0, 0.0, 0.0]]
212 newpoints
= [[0.0, b
, 0.0], [a
, 0.0, 0.0], [0.0, -b
, 0.0], [-a
, 0.0, 0.0]]
216 # ------------------------------------------------------------
217 # 2DCurve: Square / Rectangle
218 def RectCurve(type=1, a
=1.0, b
=0.5, c
=1.0):
220 RectCurve( type=1, a=1.0, b=0.5, c=1.0 )
222 Create square / rectangle curve
225 type - select type, Square, Rounded square 1, Rounded square 2
227 a - a scaling parameter
229 b - b scaling parameter
231 c - c scaling parameter
234 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
242 [-a
, b
- b
* 0.2, 0.0], [-a
+ a
* 0.05, b
- b
* 0.05, 0.0], [-a
+ a
* 0.2, b
, 0.0],
243 [a
- a
* 0.2, b
, 0.0], [a
- a
* 0.05, b
- b
* 0.05, 0.0], [a
, b
- b
* 0.2, 0.0],
244 [a
, -b
+ b
* 0.2, 0.0], [a
- a
* 0.05, -b
+ b
* 0.05, 0.0], [a
- a
* 0.2, -b
, 0.0],
245 [-a
+ a
* 0.2, -b
, 0.0], [-a
+ a
* 0.05, -b
+ b
* 0.05, 0.0], [-a
, -b
+ b
* 0.2, 0.0]
248 # Rounded Rectangle II:
258 newpoints
.append([-x
+ r
, y
, 0])
259 newpoints
.append([x
- r
, y
, 0])
260 newpoints
.append([x
, y
- r
, 0])
261 newpoints
.append([x
, -y
+ r
, 0])
262 newpoints
.append([x
- r
, -y
, 0])
263 newpoints
.append([-x
+ r
, -y
, 0])
264 newpoints
.append([-x
, -y
+ r
, 0])
265 newpoints
.append([-x
, y
- r
, 0])
267 newpoints
.append([-x
, y
, 0])
268 newpoints
.append([x
, y
, 0])
269 newpoints
.append([x
, -y
, 0])
270 newpoints
.append([-x
, -y
, 0])
273 newpoints
= [[-a
, b
, 0.0], [a
, b
, 0.0], [a
, -b
, 0.0], [-a
, -b
, 0.0]]
277 # ------------------------------------------------------------
279 def StarCurve(starpoints
=8, innerradius
=0.5, outerradius
=1.0, twist
=0.0):
281 StarCurve( starpoints=8, innerradius=0.5, outerradius=1.0, twist=0.0 )
283 Create star shaped curve
286 starpoints - the number of points
288 innerradius - innerradius
290 outerradius - outerradius
295 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
300 step
= 2.0 / starpoints
302 while i
< starpoints
:
304 x1
= cos(t
* pi
) * outerradius
305 y1
= sin(t
* pi
) * outerradius
306 newpoints
.append([x1
, y1
, 0])
307 x2
= cos(t
* pi
+ (pi
/ starpoints
+ twist
)) * innerradius
308 y2
= sin(t
* pi
+ (pi
/ starpoints
+ twist
)) * innerradius
309 newpoints
.append([x2
, y2
, 0])
314 # ------------------------------------------------------------
316 def FlowerCurve(petals
=8, innerradius
=0.5, outerradius
=1.0, petalwidth
=2.0):
318 FlowerCurve( petals=8, innerradius=0.5, outerradius=1.0, petalwidth=2.0 )
320 Create flower shaped curve
323 petals - the number of petals
325 innerradius - innerradius
327 outerradius - outerradius
329 petalwidth - width of petals
332 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
338 pet
= (step
/ pi
* 2) * petalwidth
342 x1
= cos(t
* pi
- (pi
/ petals
)) * innerradius
343 y1
= sin(t
* pi
- (pi
/ petals
)) * innerradius
344 newpoints
.append([x1
, y1
, 0])
345 x2
= cos(t
* pi
- pet
) * outerradius
346 y2
= sin(t
* pi
- pet
) * outerradius
347 newpoints
.append([x2
, y2
, 0])
348 x3
= cos(t
* pi
+ pet
) * outerradius
349 y3
= sin(t
* pi
+ pet
) * outerradius
350 newpoints
.append([x3
, y3
, 0])
355 # ------------------------------------------------------------
356 # 2DCurve: Arc,Sector,Segment,Ring:
357 def ArcCurve(sides
=6, startangle
=0.0, endangle
=90.0, innerradius
=0.5, outerradius
=1.0, type=3):
359 ArcCurve( sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradius=1.0, type=3 )
361 Create arc shaped curve
364 sides - number of sides
366 startangle - startangle
370 innerradius - innerradius
372 outerradius - outerradius
374 type - select type Arc,Sector,Segment,Ring
377 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
383 angle
= 2.0 * (1.0 / 360.0)
384 endangle
-= startangle
385 step
= (angle
* endangle
) / (sides
- 1)
388 t
= (i
* step
) + angle
* startangle
389 x1
= sin(t
* pi
) * outerradius
390 y1
= cos(t
* pi
) * outerradius
391 newpoints
.append([x1
, y1
, 0])
395 # Arc: turn cyclic curve flag off!
399 newpoints
.append([0, 0, 0])
404 t
= (j
* step
) + angle
* startangle
405 x2
= sin(t
* pi
) * innerradius
406 y2
= cos(t
* pi
) * innerradius
407 newpoints
.append([x2
, y2
, 0])
412 # ------------------------------------------------------------
413 # 2DCurve: Cog wheel:
414 def CogCurve(theeth
=8, innerradius
=0.8, middleradius
=0.95, outerradius
=1.0, bevel
=0.5):
416 CogCurve( theeth=8, innerradius=0.8, middleradius=0.95, outerradius=1.0, bevel=0.5 )
418 Create cog wheel shaped curve
421 theeth - number of theeth
423 innerradius - innerradius
425 middleradius - middleradius
427 outerradius - outerradius
432 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
443 x1
= cos(t
* pi
- (pi
/ theeth
) - pet
) * innerradius
444 y1
= sin(t
* pi
- (pi
/ theeth
) - pet
) * innerradius
445 newpoints
.append([x1
, y1
, 0])
446 x2
= cos(t
* pi
- (pi
/ theeth
) + pet
) * innerradius
447 y2
= sin(t
* pi
- (pi
/ theeth
) + pet
) * innerradius
448 newpoints
.append([x2
, y2
, 0])
449 x3
= cos(t
* pi
- pet
) * middleradius
450 y3
= sin(t
* pi
- pet
) * middleradius
451 newpoints
.append([x3
, y3
, 0])
452 x4
= cos(t
* pi
- (pet
* bevel
)) * outerradius
453 y4
= sin(t
* pi
- (pet
* bevel
)) * outerradius
454 newpoints
.append([x4
, y4
, 0])
455 x5
= cos(t
* pi
+ (pet
* bevel
)) * outerradius
456 y5
= sin(t
* pi
+ (pet
* bevel
)) * outerradius
457 newpoints
.append([x5
, y5
, 0])
458 x6
= cos(t
* pi
+ pet
) * middleradius
459 y6
= sin(t
* pi
+ pet
) * middleradius
460 newpoints
.append([x6
, y6
, 0])
465 # ------------------------------------------------------------
467 def nSideCurve(sides
=6, radius
=1.0):
469 nSideCurve( sides=6, radius=1.0 )
474 sides - number of sides
479 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
488 x
= sin(t
* pi
) * radius
489 y
= cos(t
* pi
) * radius
490 newpoints
.append([x
, y
, 0])
495 # ------------------------------------------------------------
497 def SplatCurve(sides
=24, scale
=1.0, seed
=0, basis
=0, radius
=1.0):
499 SplatCurve( sides=24, scale=1.0, seed=0, basis=0, radius=1.0 )
504 sides - number of sides
508 seed - noise random seed
515 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
524 turb
= vTurbNoise(t
, t
, t
, 1.0, scale
, 6, False, basis
, seed
)
525 turb
= turb
[2] * 0.5 + 0.5
526 x
= sin(t
* pi
) * radius
* turb
527 y
= cos(t
* pi
) * radius
* turb
528 newpoints
.append([x
, y
, 0])
533 # -----------------------------------------------------------
535 def CycloidCurve(number
=100, type=0, R
=4.0, r
=1.0, d
=1.0):
537 CycloidCurve( number=100, type=0, a=4.0, b=1.0 )
539 Create a Cycloid, Hypotrochoid / Hypocycloid or Epitrochoid / Epycycloid type of curve
542 number - the number of points
544 type - types: Cycloid, Hypocycloid, Epicycloid
546 R = Radius a scaling parameter
548 r = Radius b scaling parameter
550 d = Distance scaling parameter
553 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
560 step
= 2.0 / (number
- 1)
563 # Hypotrochoid / Hypocycloid
566 x
= ((a
- b
) * cos(t
* pi
)) + (d
* cos(((a
+ b
) / b
) * t
* pi
))
567 y
= ((a
- b
) * sin(t
* pi
)) - (d
* sin(((a
+ b
) / b
) * t
* pi
))
569 newpoints
.append([x
, y
, z
])
572 # Epitrochoid / Epycycloid
575 x
= ((a
+ b
) * cos(t
* pi
)) - (d
* cos(((a
+ b
) / b
) * t
* pi
))
576 y
= ((a
+ b
) * sin(t
* pi
)) - (d
* sin(((a
+ b
) / b
) * t
* pi
))
578 newpoints
.append([x
, y
, z
])
584 x
= (t
- sin(t
) * b
) * a
/ pi
585 y
= (1 - cos(t
) * b
) * a
/ pi
587 newpoints
.append([x
, y
, z
])
592 # -----------------------------------------------------------
593 # 3D curve shape functions:
594 # -----------------------------------------------------------
596 # ------------------------------------------------------------
598 def HelixCurve(number
=100, height
=2.0, startangle
=0.0, endangle
=360.0, width
=1.0, a
=0.0, b
=0.0):
600 HelixCurve( number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0 )
605 number - the number of points
609 startangle - startangle
620 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
625 angle
= (2.0 / 360.0) * (endangle
- startangle
)
626 step
= angle
/ (number
- 1)
628 start
= startangle
* 2.0 / 360.0
632 t
= (i
* step
+ start
)
633 x
= sin((t
* pi
)) * (1.0 + cos(t
* pi
* a
- (b
* pi
))) * (0.25 * width
)
634 y
= cos((t
* pi
)) * (1.0 + cos(t
* pi
* a
- (b
* pi
))) * (0.25 * width
)
635 z
= (t
* h
) - h
* start
636 newpoints
.append([x
, y
, z
])
641 # -----------------------------------------------------------
643 def NoiseCurve(type=0, number
=100, length
=2.0, size
=0.5,
644 scale
=[0.5, 0.5, 0.5], octaves
=2, basis
=0, seed
=0):
649 number - number of points
651 length - curve length
655 scale - noise intensity scale x,y,z
659 seed - noise random seed
661 type - noise curve type
664 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
669 step
= (length
/ number
)
675 v
= vTurbNoise(t
, t
, t
, 1.0, size
, octaves
, False, basis
, seed
)
676 x
= sin(t
* pi
) + (v
[0] * scale
[0])
677 y
= cos(t
* pi
) + (v
[1] * scale
[1])
679 newpoints
.append([x
, y
, z
])
685 v
= vTurbNoise(t
, t
, t
, 1.0, 1.0, octaves
, False, basis
, seed
)
686 x
= v
[0] * scale
[0] * size
687 y
= v
[1] * scale
[1] * size
688 z
= v
[2] * scale
[2] * size
689 newpoints
.append([x
, y
, z
])
695 v
= vTurbNoise(t
, t
, t
, 1.0, size
, octaves
, False, basis
, seed
)
696 x
= t
+ v
[0] * scale
[0]
699 newpoints
.append([x
, y
, z
])
704 # get array of vertcoordinates according to splinetype
705 def vertsToPoints(Verts
, splineType
):
710 # array for BEZIER spline output (V3)
711 if splineType
== 'BEZIER':
715 # array for nonBEZIER output (V4)
719 if splineType
== 'NURBS':
728 # create new CurveObject from vertarray and splineType
729 def createCurve(context
, vertArray
, self
):
730 # output splineType 'POLY' 'NURBS' 'BEZIER'
731 splineType
= self
.outputType
733 # GalloreType as name
734 name
= self
.ProfileType
737 if bpy
.context
.mode
== 'EDIT_CURVE':
738 Curve
= context
.active_object
739 newSpline
= Curve
.data
.splines
.new(type=splineType
) # spline
742 dataCurve
= bpy
.data
.curves
.new(name
, type='CURVE') # curve data block
743 newSpline
= dataCurve
.splines
.new(type=splineType
) # spline
745 # create object with newCurve
746 Curve
= object_utils
.object_data_add(context
, dataCurve
, operator
=self
) # place in active scene
748 # set newSpline Options
749 newSpline
.use_cyclic_u
= self
.use_cyclic_u
750 newSpline
.use_endpoint_u
= self
.endp_u
751 newSpline
.order_u
= self
.order_u
754 Curve
.data
.dimensions
= self
.shape
755 Curve
.data
.use_path
= True
756 if self
.shape
== '3D':
757 Curve
.data
.fill_mode
= 'FULL'
759 Curve
.data
.fill_mode
= 'BOTH'
761 for spline
in Curve
.data
.splines
:
762 if spline
.type == 'BEZIER':
763 for point
in spline
.bezier_points
:
764 point
.select_control_point
= False
765 point
.select_left_handle
= False
766 point
.select_right_handle
= False
768 for point
in spline
.points
:
771 # create spline from vertarray
772 if splineType
== 'BEZIER':
773 newSpline
.bezier_points
.add(int(len(vertArray
) * 0.33))
774 newSpline
.bezier_points
.foreach_set('co', vertArray
)
775 for point
in newSpline
.bezier_points
:
776 point
.handle_right_type
= self
.handleType
777 point
.handle_left_type
= self
.handleType
778 point
.select_control_point
= True
779 point
.select_left_handle
= True
780 point
.select_right_handle
= True
782 newSpline
.points
.add(int(len(vertArray
) * 0.25 - 1))
783 newSpline
.points
.foreach_set('co', vertArray
)
784 newSpline
.use_endpoint_u
= True
785 for point
in newSpline
.points
:
788 # move and rotate spline in edit mode
789 if bpy
.context
.mode
== 'EDIT_CURVE':
790 if self
.align
== "WORLD":
791 location
= self
.location
- context
.active_object
.location
792 bpy
.ops
.transform
.translate(value
= location
, orient_type
='GLOBAL')
793 bpy
.ops
.transform
.rotate(value
= self
.rotation
[0], orient_axis
= 'X', orient_type
='GLOBAL')
794 bpy
.ops
.transform
.rotate(value
= self
.rotation
[1], orient_axis
= 'Y', orient_type
='GLOBAL')
795 bpy
.ops
.transform
.rotate(value
= self
.rotation
[2], orient_axis
= 'Z', orient_type
='GLOBAL')
797 elif self
.align
== "VIEW":
798 bpy
.ops
.transform
.translate(value
= self
.location
)
799 bpy
.ops
.transform
.rotate(value
= self
.rotation
[0], orient_axis
= 'X')
800 bpy
.ops
.transform
.rotate(value
= self
.rotation
[1], orient_axis
= 'Y')
801 bpy
.ops
.transform
.rotate(value
= self
.rotation
[2], orient_axis
= 'Z')
803 elif self
.align
== "CURSOR":
804 location
= context
.active_object
.location
805 self
.location
= bpy
.context
.scene
.cursor
.location
- location
806 self
.rotation
= bpy
.context
.scene
.cursor
.rotation_euler
808 bpy
.ops
.transform
.translate(value
= self
.location
)
809 bpy
.ops
.transform
.rotate(value
= self
.rotation
[0], orient_axis
= 'X')
810 bpy
.ops
.transform
.rotate(value
= self
.rotation
[1], orient_axis
= 'Y')
811 bpy
.ops
.transform
.rotate(value
= self
.rotation
[2], orient_axis
= 'Z')
816 # ------------------------------------------------------------
818 def main(context
, self
):
820 proType
= self
.ProfileType
821 splineType
= self
.outputType
822 innerRadius
= self
.innerRadius
823 middleRadius
= self
.middleRadius
824 outerRadius
= self
.outerRadius
827 if proType
== 'Profile':
828 verts
= ProfileCurve(
829 self
.ProfileCurveType
,
830 self
.ProfileCurvevar1
,
831 self
.ProfileCurvevar2
833 if proType
== 'Arrow':
839 if proType
== 'Rectangle':
846 if proType
== 'Flower':
853 if proType
== 'Star':
869 if proType
== 'Cogwheel':
877 if proType
== 'Nsided':
882 if proType
== 'Splat':
890 if proType
== 'Cycloid':
891 verts
= CycloidCurve(
898 if proType
== 'Helix':
908 if proType
== 'Noise':
914 [self
.noiseScaleX
, self
.noiseScaleY
, self
.noiseScaleZ
],
920 # turn verts into array
921 vertArray
= vertsToPoints(verts
, splineType
)
924 createCurve(context
, vertArray
, self
)
929 class Curveaceous_galore(Operator
, object_utils
.AddObjectHelper
):
930 bl_idname
= "curve.curveaceous_galore"
931 bl_label
= "Curve Profiles"
932 bl_description
= "Construct many types of curves"
933 bl_options
= {'REGISTER', 'UNDO', 'PRESET'}
936 ProfileType
: EnumProperty(
938 description
="Form of Curve to create",
940 ('Arc', "Arc", "Arc"),
941 ('Arrow', "Arrow", "Arrow"),
942 ('Cogwheel', "Cogwheel", "Cogwheel"),
943 ('Cycloid', "Cycloid", "Cycloid"),
944 ('Flower', "Flower", "Flower"),
945 ('Helix', "Helix (3D)", "Helix"),
946 ('Noise', "Noise (3D)", "Noise"),
947 ('Nsided', "Nsided", "Nsided"),
948 ('Profile', "Profile", "Profile"),
949 ('Rectangle', "Rectangle", "Rectangle"),
950 ('Splat', "Splat", "Splat"),
951 ('Star', "Star", "Star")]
953 outputType
: EnumProperty(
954 name
="Output splines",
955 description
="Type of splines to output",
957 ('POLY', "Poly", "Poly Spline type"),
958 ('NURBS', "Nurbs", "Nurbs Spline type"),
959 ('BEZIER', "Bezier", "Bezier Spline type")]
962 shape
: EnumProperty(
964 description
="2D or 3D Curve",
970 use_cyclic_u
: BoolProperty(
973 description
="make curve closed"
975 endp_u
: BoolProperty(
976 name
="Use endpoint u",
978 description
="stretch to endpoints"
980 order_u
: IntProperty(
985 description
="Order of nurbs spline"
987 handleType
: EnumProperty(
990 description
="Bezier handles type",
992 ('VECTOR', "Vector", "Vector type Bezier handles"),
993 ('AUTO', "Auto", "Automatic type Bezier handles")]
995 # ProfileCurve properties
996 ProfileCurveType
: IntProperty(
1001 description
="Type of Curve's Profile"
1003 ProfileCurvevar1
: FloatProperty(
1006 description
="Variable 1 of Curve's Profile"
1008 ProfileCurvevar2
: FloatProperty(
1011 description
="Variable 2 of Curve's Profile"
1013 # Arrow, Rectangle, MiscCurve properties
1014 MiscCurveType
: IntProperty(
1019 description
="Type of Curve"
1021 MiscCurvevar1
: FloatProperty(
1024 description
="Variable 1 of Curve"
1026 MiscCurvevar2
: FloatProperty(
1029 description
="Variable 2 of Curve"
1031 MiscCurvevar3
: FloatProperty(
1035 description
="Variable 3 of Curve"
1038 innerRadius
: FloatProperty(
1039 name
="Inner radius",
1042 description
="Inner radius"
1044 middleRadius
: FloatProperty(
1045 name
="Middle radius",
1048 description
="Middle radius"
1050 outerRadius
: FloatProperty(
1051 name
="Outer radius",
1054 description
="Outer radius"
1057 petals
: IntProperty(
1061 description
="Number of petals"
1063 petalWidth
: FloatProperty(
1067 description
="Petal width"
1070 starPoints
: IntProperty(
1074 description
="Number of star points"
1076 starTwist
: FloatProperty(
1082 arcSides
: IntProperty(
1086 description
="Sides of arc"
1088 startAngle
: FloatProperty(
1091 description
="Start angle"
1093 endAngle
: FloatProperty(
1096 description
="End angle"
1098 arcType
: IntProperty(
1103 description
="Sides of arc"
1105 # Cogwheel properties
1106 teeth
: IntProperty(
1110 description
="number of teeth"
1112 bevel
: FloatProperty(
1120 Nsides
: IntProperty(
1124 description
="Number of sides"
1127 splatSides
: IntProperty(
1131 description
="Splat sides"
1133 splatScale
: FloatProperty(
1137 description
="Splat scale"
1145 basis
: IntProperty(
1153 helixPoints
: IntProperty(
1157 description
="Resolution"
1159 helixHeight
: FloatProperty(
1163 description
="Helix height"
1165 helixStart
: FloatProperty(
1168 description
="Helix start angle"
1170 helixEnd
: FloatProperty(
1173 description
="Helix end angle"
1175 helixWidth
: FloatProperty(
1178 description
="Helix width"
1180 helix_a
: FloatProperty(
1183 description
="Helix Variable 1"
1185 helix_b
: FloatProperty(
1188 description
="Helix Variable 2"
1190 # Cycloid properties
1191 cycloPoints
: IntProperty(
1196 description
="Resolution"
1198 cycloType
: IntProperty(
1203 description
="Type: Cycloid , Hypocycloid / Hypotrochoid , Epicycloid / Epitrochoid"
1205 cyclo_a
: FloatProperty(
1209 description
="Cycloid: R radius a"
1211 cyclo_b
: FloatProperty(
1215 description
="Cycloid: r radius b"
1217 cyclo_d
: FloatProperty(
1220 description
="Cycloid: d distance"
1223 noiseType
: IntProperty(
1228 description
="Noise curve type: Linear, Circular or Knot"
1230 noisePoints
: IntProperty(
1234 description
="Resolution"
1236 noiseLength
: FloatProperty(
1240 description
="Curve Length"
1242 noiseSize
: FloatProperty(
1246 description
="Noise size"
1248 noiseScaleX
: FloatProperty(
1252 description
="Noise x"
1254 noiseScaleY
: FloatProperty(
1258 description
="Noise y"
1260 noiseScaleZ
: FloatProperty(
1264 description
="Noise z"
1266 noiseOctaves
: IntProperty(
1273 noiseBasis
: IntProperty(
1280 noiseSeed
: IntProperty(
1284 description
="Random Seed"
1287 edit_mode
: BoolProperty(
1288 name
="Show in edit mode",
1290 description
="Show in edit mode"
1293 def draw(self
, context
):
1294 layout
= self
.layout
1297 col
= layout
.column()
1298 col
.prop(self
, 'ProfileType')
1299 col
.label(text
=self
.ProfileType
+ " Options:")
1301 # options per ProfileType
1303 col
= box
.column(align
=True)
1305 if self
.ProfileType
== 'Profile':
1306 col
.prop(self
, "ProfileCurveType")
1307 col
.prop(self
, "ProfileCurvevar1")
1308 col
.prop(self
, "ProfileCurvevar2")
1310 elif self
.ProfileType
== 'Arrow':
1311 col
.prop(self
, "MiscCurveType")
1312 col
.prop(self
, "MiscCurvevar1", text
="Height")
1313 col
.prop(self
, "MiscCurvevar2", text
="Width")
1315 elif self
.ProfileType
== 'Rectangle':
1316 col
.prop(self
, "MiscCurveType")
1317 col
.prop(self
, "MiscCurvevar1", text
="Width")
1318 col
.prop(self
, "MiscCurvevar2", text
="Height")
1319 if self
.MiscCurveType
== 2:
1320 col
.prop(self
, "MiscCurvevar3", text
="Corners")
1322 elif self
.ProfileType
== 'Flower':
1323 col
.prop(self
, "petals")
1324 col
.prop(self
, "petalWidth")
1326 col
= box
.column(align
=True)
1327 col
.prop(self
, "innerRadius")
1328 col
.prop(self
, "outerRadius")
1330 elif self
.ProfileType
== 'Star':
1331 col
.prop(self
, "starPoints")
1332 col
.prop(self
, "starTwist")
1334 col
= box
.column(align
=True)
1335 col
.prop(self
, "innerRadius")
1336 col
.prop(self
, "outerRadius")
1338 elif self
.ProfileType
== 'Arc':
1339 col
.prop(self
, "arcType")
1340 col
.prop(self
, "arcSides")
1342 col
= box
.column(align
=True)
1343 col
.prop(self
, "startAngle")
1344 col
.prop(self
, "endAngle")
1346 col
= box
.column(align
=True)
1347 col
.prop(self
, "innerRadius")
1348 col
.prop(self
, "outerRadius")
1350 elif self
.ProfileType
== 'Cogwheel':
1351 col
.prop(self
, "teeth")
1352 col
.prop(self
, "bevel")
1354 col
= box
.column(align
=True)
1355 col
.prop(self
, "innerRadius")
1356 col
.prop(self
, "middleRadius")
1357 col
.prop(self
, "outerRadius")
1359 elif self
.ProfileType
== 'Nsided':
1360 col
.prop(self
, "Nsides")
1361 col
.prop(self
, "outerRadius")
1363 elif self
.ProfileType
== 'Splat':
1364 col
.prop(self
, "splatSides")
1365 col
.prop(self
, "outerRadius")
1367 col
= box
.column(align
=True)
1368 col
.prop(self
, "splatScale")
1369 col
.prop(self
, "seed")
1370 col
.prop(self
, "basis")
1372 elif self
.ProfileType
== 'Cycloid':
1373 col
.prop(self
, "cycloType")
1374 col
.prop(self
, "cycloPoints")
1376 col
= box
.column(align
=True)
1377 col
.prop(self
, "cyclo_a")
1378 col
.prop(self
, "cyclo_b")
1379 if self
.cycloType
!= 0:
1380 col
.prop(self
, "cyclo_d")
1382 elif self
.ProfileType
== 'Helix':
1383 col
.prop(self
, "helixPoints")
1384 col
.prop(self
, "helixHeight")
1385 col
.prop(self
, "helixWidth")
1387 col
= box
.column(align
=True)
1388 col
.prop(self
, "helixStart")
1389 col
.prop(self
, "helixEnd")
1391 col
= box
.column(align
=True)
1392 col
.prop(self
, "helix_a")
1393 col
.prop(self
, "helix_b")
1395 elif self
.ProfileType
== 'Noise':
1396 col
.prop(self
, "noiseType")
1397 col
.prop(self
, "noisePoints")
1398 col
.prop(self
, "noiseLength")
1400 col
= box
.column(align
=True)
1401 col
.prop(self
, "noiseSize")
1402 col
.prop(self
, "noiseScaleX")
1403 col
.prop(self
, "noiseScaleY")
1404 col
.prop(self
, "noiseScaleZ")
1406 col
= box
.column(align
=True)
1407 col
.prop(self
, "noiseOctaves")
1408 col
.prop(self
, "noiseBasis")
1409 col
.prop(self
, "noiseSeed")
1412 row
.prop(self
, "shape", expand
=True)
1415 col
= layout
.column()
1416 col
.label(text
="Output Curve Type:")
1417 col
.row().prop(self
, "outputType", expand
=True)
1419 if self
.outputType
== 'NURBS':
1420 col
.prop(self
, 'order_u')
1421 elif self
.outputType
== 'BEZIER':
1422 col
.row().prop(self
, 'handleType', expand
=True)
1424 col
= layout
.column()
1425 col
.row().prop(self
, "use_cyclic_u", expand
=True)
1427 col
= layout
.column()
1428 col
.row().prop(self
, "edit_mode", expand
=True)
1430 col
= layout
.column()
1431 # AddObjectHelper props
1432 col
.prop(self
, "align")
1433 col
.prop(self
, "location")
1434 col
.prop(self
, "rotation")
1437 def poll(cls
, context
):
1438 return context
.scene
is not None
1440 def execute(self
, context
):
1441 # turn off 'Enter Edit Mode'
1442 use_enter_edit_mode
= bpy
.context
.preferences
.edit
.use_enter_edit_mode
1443 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= False
1448 if use_enter_edit_mode
:
1449 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1451 # restore pre operator state
1452 bpy
.context
.preferences
.edit
.use_enter_edit_mode
= use_enter_edit_mode
1455 bpy
.ops
.object.mode_set(mode
= 'EDIT')
1457 bpy
.ops
.object.mode_set(mode
= 'OBJECT')
1461 def invoke(self
, context
, event
):
1462 # deal with 2D - 3D curve differences
1463 if self
.ProfileType
in ['Helix', 'Cycloid', 'Noise']:
1468 if self
.ProfileType
in ['Helix', 'Noise', 'Cycloid']:
1469 self
.use_cyclic_u
= False
1470 if self
.ProfileType
in ['Cycloid']:
1471 if self
.cycloType
== 0:
1472 self
.use_cyclic_u
= False
1474 self
.use_cyclic_u
= True
1476 if self
.ProfileType
== 'Arc' and self
.arcType
== 1:
1477 self
.use_cyclic_u
= False
1479 self
.use_cyclic_u
= True
1481 self
.execute(context
)
1491 from bpy
.utils
import register_class
1496 from bpy
.utils
import unregister_class
1497 for cls
in reversed(classes
):
1498 unregister_class(cls
)
1500 if __name__
== "__main__":