Merge branch 'blender-v2.92-release'
[blender-addons.git] / add_curve_extra_objects / add_curve_aceous_galore.py
blob463b05a03138b43ce44332ae6cbf0a25a9b9fa7c
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 #####
19 """
20 bl_info = {
21 "name": "Curveaceous Galore!",
22 "author": "Jimmy Hazevoet, testscreenings",
23 "version": (0, 2, 3),
24 "blender": (2, 80),
25 "location": "View3D > Add > Curve",
26 "description": "Adds many different types of Curves",
27 "warning": "",
28 "doc_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
29 "Scripts/Curve/Curves_Galore",
30 "category": "Add Curve",
32 """
34 import bpy
35 from bpy_extras import object_utils
36 from bpy.props import (
37 BoolProperty,
38 EnumProperty,
39 FloatProperty,
40 IntProperty,
41 FloatVectorProperty
43 from mathutils import Matrix, Vector
44 from bpy.types import Operator
45 from math import (
46 sin, cos, pi
48 import mathutils.noise as Noise
51 # ------------------------------------------------------------
52 # Some functions to use with others:
53 # ------------------------------------------------------------
55 # ------------------------------------------------------------
56 # Generate random number:
57 def randnum(low=0.0, high=1.0, seed=0):
58 """
59 randnum( low=0.0, high=1.0, seed=0 )
61 Create random number
62 Parameters:
63 low - lower range
64 (type=float)
65 high - higher range
66 (type=float)
67 seed - the random seed number, if seed == 0, the current time will be used instead
68 (type=int)
69 Returns:
70 a random number
71 (type=float)
72 """
74 Noise.seed_set(seed)
75 rnum = Noise.random()
76 rnum = rnum * (high - low)
77 rnum = rnum + low
78 return rnum
81 # ------------------------------------------------------------
82 # Make some noise:
83 def vTurbNoise(x, y, z, iScale=0.25, Size=1.0, Depth=6, Hard=False, Basis=0, Seed=0):
84 """
85 vTurbNoise((x,y,z), iScale=0.25, Size=1.0, Depth=6, Hard=0, Basis=0, Seed=0 )
87 Create randomised vTurbulence noise
89 Parameters:
90 xyz - (x,y,z) float values.
91 (type=3-float tuple)
92 iScale - noise intensity scale
93 (type=float)
94 Size - noise size
95 (type=float)
96 Depth - number of noise values added.
97 (type=int)
98 Hard - noise hardness: True - soft noise; False - hard noise
99 (type=int)
100 basis - type of noise used for turbulence
101 (type=int)
102 Seed - the random seed number, if seed == 0, the current time will be used instead
103 (type=int)
104 Returns:
105 the generated turbulence vector.
106 (type=3-float list)
108 rand = randnum(-100, 100, Seed)
109 if Basis == 9:
110 Basis = 14
111 vec = Vector((x / Size + rand, y / Size + rand, z / Size + rand))
112 vTurb = Noise.turbulence_vector(vec, Depth, Hard)
113 #mathutils.noise.turbulence_vector(position, octaves, hard, noise_basis='PERLIN_ORIGINAL', amplitude_scale=0.5, frequency_scale=2.0)
114 tx = vTurb[0] * iScale
115 ty = vTurb[1] * iScale
116 tz = vTurb[2] * iScale
117 return tx, ty, tz
120 # -------------------------------------------------------------------
121 # 2D Curve shape functions:
122 # -------------------------------------------------------------------
124 # ------------------------------------------------------------
125 # 2DCurve: Profile: L, H, T, U, Z
126 def ProfileCurve(type=0, a=0.25, b=0.25):
128 ProfileCurve( type=0, a=0.25, b=0.25 )
130 Create profile curve
132 Parameters:
133 type - select profile type, L, H, T, U, Z
134 (type=int)
135 a - a scaling parameter
136 (type=float)
137 b - b scaling parameter
138 (type=float)
139 Returns:
140 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
141 (type=list)
144 newpoints = []
145 if type == 1:
146 # H:
147 a *= 0.5
148 b *= 0.5
149 newpoints = [
150 [-1.0, 1.0, 0.0], [-1.0 + a, 1.0, 0.0],
151 [-1.0 + a, b, 0.0], [1.0 - a, b, 0.0], [1.0 - a, 1.0, 0.0],
152 [1.0, 1.0, 0.0], [1.0, -1.0, 0.0], [1.0 - a, -1.0, 0.0],
153 [1.0 - a, -b, 0.0], [-1.0 + a, -b, 0.0], [-1.0 + a, -1.0, 0.0],
154 [-1.0, -1.0, 0.0]
156 elif type == 2:
157 # T:
158 a *= 0.5
159 newpoints = [
160 [-1.0, 1.0, 0.0], [1.0, 1.0, 0.0],
161 [1.0, 1.0 - b, 0.0], [a, 1.0 - b, 0.0], [a, -1.0, 0.0],
162 [-a, -1.0, 0.0], [-a, 1.0 - b, 0.0], [-1.0, 1.0 - b, 0.0]
164 elif type == 3:
165 # U:
166 a *= 0.5
167 newpoints = [
168 [-1.0, 1.0, 0.0], [-1.0 + a, 1.0, 0.0],
169 [-1.0 + a, -1.0 + b, 0.0], [1.0 - a, -1.0 + b, 0.0], [1.0 - a, 1.0, 0.0],
170 [1.0, 1.0, 0.0], [1.0, -1.0, 0.0], [-1.0, -1.0, 0.0]
172 elif type == 4:
173 # Z:
174 a *= 0.5
175 newpoints = [
176 [-0.5, 1.0, 0.0], [a, 1.0, 0.0],
177 [a, -1.0 + b, 0.0], [1.0, -1.0 + b, 0.0], [1.0, -1.0, 0.0],
178 [-a, -1.0, 0.0], [-a, 1.0 - b, 0.0], [-1.0, 1.0 - b, 0.0],
179 [-1.0, 1.0, 0.0]
181 else:
182 # L:
183 newpoints = [
184 [-1.0, 1.0, 0.0], [-1.0 + a, 1.0, 0.0],
185 [-1.0 + a, -1.0 + b, 0.0], [1.0, -1.0 + b, 0.0],
186 [1.0, -1.0, 0.0], [-1.0, -1.0, 0.0]
188 return newpoints
191 # ------------------------------------------------------------
192 # 2DCurve: Arrow
193 def ArrowCurve(type=1, a=1.0, b=0.5):
195 ArrowCurve( type=1, a=1.0, b=0.5, c=1.0 )
197 Create arrow curve
199 Parameters:
200 type - select type, Arrow1, Arrow2
201 (type=int)
202 a - a scaling parameter
203 (type=float)
204 b - b scaling parameter
205 (type=float)
206 Returns:
207 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
208 (type=list)
211 newpoints = []
212 if type == 0:
213 # Arrow1:
214 a *= 0.5
215 b *= 0.5
216 newpoints = [
217 [-1.0, b, 0.0], [-1.0 + a, b, 0.0],
218 [-1.0 + a, 1.0, 0.0], [1.0, 0.0, 0.0],
219 [-1.0 + a, -1.0, 0.0], [-1.0 + a, -b, 0.0],
220 [-1.0, -b, 0.0]
222 elif type == 1:
223 # Arrow2:
224 newpoints = [[-a, b, 0.0], [a, 0.0, 0.0], [-a, -b, 0.0], [0.0, 0.0, 0.0]]
225 else:
226 # diamond:
227 newpoints = [[0.0, b, 0.0], [a, 0.0, 0.0], [0.0, -b, 0.0], [-a, 0.0, 0.0]]
228 return newpoints
231 # ------------------------------------------------------------
232 # 2DCurve: Square / Rectangle
233 def RectCurve(type=1, a=1.0, b=0.5, c=1.0):
235 RectCurve( type=1, a=1.0, b=0.5, c=1.0 )
237 Create square / rectangle curve
239 Parameters:
240 type - select type, Square, Rounded square 1, Rounded square 2
241 (type=int)
242 a - a scaling parameter
243 (type=float)
244 b - b scaling parameter
245 (type=float)
246 c - c scaling parameter
247 (type=float)
248 Returns:
249 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
250 (type=list)
253 newpoints = []
254 if type == 1:
255 # Rounded Rectangle:
256 newpoints = [
257 [-a, b - b * 0.2, 0.0], [-a + a * 0.05, b - b * 0.05, 0.0], [-a + a * 0.2, b, 0.0],
258 [a - a * 0.2, b, 0.0], [a - a * 0.05, b - b * 0.05, 0.0], [a, b - b * 0.2, 0.0],
259 [a, -b + b * 0.2, 0.0], [a - a * 0.05, -b + b * 0.05, 0.0], [a - a * 0.2, -b, 0.0],
260 [-a + a * 0.2, -b, 0.0], [-a + a * 0.05, -b + b * 0.05, 0.0], [-a, -b + b * 0.2, 0.0]
262 elif type == 2:
263 # Rounded Rectangle II:
264 newpoints = []
265 x = a
266 y = b
267 r = c
268 if r > x:
269 r = x - 0.0001
270 if r > y:
271 r = y - 0.0001
272 if r > 0:
273 newpoints.append([-x + r, y, 0])
274 newpoints.append([x - r, y, 0])
275 newpoints.append([x, y - r, 0])
276 newpoints.append([x, -y + r, 0])
277 newpoints.append([x - r, -y, 0])
278 newpoints.append([-x + r, -y, 0])
279 newpoints.append([-x, -y + r, 0])
280 newpoints.append([-x, y - r, 0])
281 else:
282 newpoints.append([-x, y, 0])
283 newpoints.append([x, y, 0])
284 newpoints.append([x, -y, 0])
285 newpoints.append([-x, -y, 0])
286 else:
287 # Rectangle:
288 newpoints = [[-a, b, 0.0], [a, b, 0.0], [a, -b, 0.0], [-a, -b, 0.0]]
289 return newpoints
292 # ------------------------------------------------------------
293 # 2DCurve: Star:
294 def StarCurve(starpoints=8, innerradius=0.5, outerradius=1.0, twist=0.0):
296 StarCurve( starpoints=8, innerradius=0.5, outerradius=1.0, twist=0.0 )
298 Create star shaped curve
300 Parameters:
301 starpoints - the number of points
302 (type=int)
303 innerradius - innerradius
304 (type=float)
305 outerradius - outerradius
306 (type=float)
307 twist - twist amount
308 (type=float)
309 Returns:
310 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
311 (type=list)
314 newpoints = []
315 step = 2.0 / starpoints
316 i = 0
317 while i < starpoints:
318 t = i * step
319 x1 = cos(t * pi) * outerradius
320 y1 = sin(t * pi) * outerradius
321 newpoints.append([x1, y1, 0])
322 x2 = cos(t * pi + (pi / starpoints + twist)) * innerradius
323 y2 = sin(t * pi + (pi / starpoints + twist)) * innerradius
324 newpoints.append([x2, y2, 0])
325 i += 1
326 return newpoints
329 # ------------------------------------------------------------
330 # 2DCurve: Flower:
331 def FlowerCurve(petals=8, innerradius=0.5, outerradius=1.0, petalwidth=2.0):
333 FlowerCurve( petals=8, innerradius=0.5, outerradius=1.0, petalwidth=2.0 )
335 Create flower shaped curve
337 Parameters:
338 petals - the number of petals
339 (type=int)
340 innerradius - innerradius
341 (type=float)
342 outerradius - outerradius
343 (type=float)
344 petalwidth - width of petals
345 (type=float)
346 Returns:
347 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
348 (type=list)
351 newpoints = []
352 step = 2.0 / petals
353 pet = (step / pi * 2) * petalwidth
354 i = 0
355 while i < petals:
356 t = i * step
357 x1 = cos(t * pi - (pi / petals)) * innerradius
358 y1 = sin(t * pi - (pi / petals)) * innerradius
359 newpoints.append([x1, y1, 0])
360 x2 = cos(t * pi - pet) * outerradius
361 y2 = sin(t * pi - pet) * outerradius
362 newpoints.append([x2, y2, 0])
363 x3 = cos(t * pi + pet) * outerradius
364 y3 = sin(t * pi + pet) * outerradius
365 newpoints.append([x3, y3, 0])
366 i += 1
367 return newpoints
370 # ------------------------------------------------------------
371 # 2DCurve: Arc,Sector,Segment,Ring:
372 def ArcCurve(sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradius=1.0, type=3):
374 ArcCurve( sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradius=1.0, type=3 )
376 Create arc shaped curve
378 Parameters:
379 sides - number of sides
380 (type=int)
381 startangle - startangle
382 (type=float)
383 endangle - endangle
384 (type=float)
385 innerradius - innerradius
386 (type=float)
387 outerradius - outerradius
388 (type=float)
389 type - select type Arc,Sector,Segment,Ring
390 (type=int)
391 Returns:
392 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
393 (type=list)
396 newpoints = []
397 sides += 1
398 angle = 2.0 * (1.0 / 360.0)
399 endangle -= startangle
400 step = (angle * endangle) / (sides - 1)
401 i = 0
402 while i < sides:
403 t = (i * step) + angle * startangle
404 x1 = sin(t * pi) * outerradius
405 y1 = cos(t * pi) * outerradius
406 newpoints.append([x1, y1, 0])
407 i += 1
409 # if type == 1:
410 # Arc: turn cyclic curve flag off!
412 # Segment:
413 if type == 2:
414 newpoints.append([0, 0, 0])
415 # Ring:
416 elif type == 3:
417 j = sides - 1
418 while j > -1:
419 t = (j * step) + angle * startangle
420 x2 = sin(t * pi) * innerradius
421 y2 = cos(t * pi) * innerradius
422 newpoints.append([x2, y2, 0])
423 j -= 1
424 return newpoints
427 # ------------------------------------------------------------
428 # 2DCurve: Cog wheel:
429 def CogCurve(theeth=8, innerradius=0.8, middleradius=0.95, outerradius=1.0, bevel=0.5):
431 CogCurve( theeth=8, innerradius=0.8, middleradius=0.95, outerradius=1.0, bevel=0.5 )
433 Create cog wheel shaped curve
435 Parameters:
436 theeth - number of theeth
437 (type=int)
438 innerradius - innerradius
439 (type=float)
440 middleradius - middleradius
441 (type=float)
442 outerradius - outerradius
443 (type=float)
444 bevel - bevel amount
445 (type=float)
446 Returns:
447 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
448 (type=list)
451 newpoints = []
452 step = 2.0 / theeth
453 pet = step / pi * 2
454 bevel = 1.0 - bevel
455 i = 0
456 while i < theeth:
457 t = i * step
458 x1 = cos(t * pi - (pi / theeth) - pet) * innerradius
459 y1 = sin(t * pi - (pi / theeth) - pet) * innerradius
460 newpoints.append([x1, y1, 0])
461 x2 = cos(t * pi - (pi / theeth) + pet) * innerradius
462 y2 = sin(t * pi - (pi / theeth) + pet) * innerradius
463 newpoints.append([x2, y2, 0])
464 x3 = cos(t * pi - pet) * middleradius
465 y3 = sin(t * pi - pet) * middleradius
466 newpoints.append([x3, y3, 0])
467 x4 = cos(t * pi - (pet * bevel)) * outerradius
468 y4 = sin(t * pi - (pet * bevel)) * outerradius
469 newpoints.append([x4, y4, 0])
470 x5 = cos(t * pi + (pet * bevel)) * outerradius
471 y5 = sin(t * pi + (pet * bevel)) * outerradius
472 newpoints.append([x5, y5, 0])
473 x6 = cos(t * pi + pet) * middleradius
474 y6 = sin(t * pi + pet) * middleradius
475 newpoints.append([x6, y6, 0])
476 i += 1
477 return newpoints
480 # ------------------------------------------------------------
481 # 2DCurve: nSide:
482 def nSideCurve(sides=6, radius=1.0):
484 nSideCurve( sides=6, radius=1.0 )
486 Create n-sided curve
488 Parameters:
489 sides - number of sides
490 (type=int)
491 radius - radius
492 (type=float)
493 Returns:
494 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
495 (type=list)
498 newpoints = []
499 step = 2.0 / sides
500 i = 0
501 while i < sides:
502 t = i * step
503 x = sin(t * pi) * radius
504 y = cos(t * pi) * radius
505 newpoints.append([x, y, 0])
506 i += 1
507 return newpoints
510 # ------------------------------------------------------------
511 # 2DCurve: Splat:
512 def SplatCurve(sides=24, scale=1.0, seed=0, basis=0, radius=1.0):
514 SplatCurve( sides=24, scale=1.0, seed=0, basis=0, radius=1.0 )
516 Create splat curve
518 Parameters:
519 sides - number of sides
520 (type=int)
521 scale - noise size
522 (type=float)
523 seed - noise random seed
524 (type=int)
525 basis - noise basis
526 (type=int)
527 radius - radius
528 (type=float)
529 Returns:
530 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
531 (type=list)
534 newpoints = []
535 step = 2.0 / sides
536 i = 0
537 while i < sides:
538 t = i * step
539 turb = vTurbNoise(t, t, t, 1.0, scale, 6, False, basis, seed)
540 turb = turb[2] * 0.5 + 0.5
541 x = sin(t * pi) * radius * turb
542 y = cos(t * pi) * radius * turb
543 newpoints.append([x, y, 0])
544 i += 1
545 return newpoints
548 # -----------------------------------------------------------
549 # Cycloid curve
550 def CycloidCurve(number=100, type=0, R=4.0, r=1.0, d=1.0):
552 CycloidCurve( number=100, type=0, a=4.0, b=1.0 )
554 Create a Cycloid, Hypotrochoid / Hypocycloid or Epitrochoid / Epycycloid type of curve
556 Parameters:
557 number - the number of points
558 (type=int)
559 type - types: Cycloid, Hypocycloid, Epicycloid
560 (type=int)
561 R = Radius a scaling parameter
562 (type=float)
563 r = Radius b scaling parameter
564 (type=float)
565 d = Distance scaling parameter
566 (type=float)
567 Returns:
568 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
569 (type=list)
572 a = R
573 b = r
574 newpoints = []
575 step = 2.0 / (number - 1)
576 i = 0
577 if type == 1:
578 # Hypotrochoid / Hypocycloid
579 while i < number:
580 t = i * step
581 x = ((a - b) * cos(t * pi)) + (d * cos(((a + b) / b) * t * pi))
582 y = ((a - b) * sin(t * pi)) - (d * sin(((a + b) / b) * t * pi))
583 z = 0
584 newpoints.append([x, y, z])
585 i += 1
586 elif type == 2:
587 # Epitrochoid / Epycycloid
588 while i < number:
589 t = i * step
590 x = ((a + b) * cos(t * pi)) - (d * cos(((a + b) / b) * t * pi))
591 y = ((a + b) * sin(t * pi)) - (d * sin(((a + b) / b) * t * pi))
592 z = 0
593 newpoints.append([x, y, z])
594 i += 1
595 else:
596 # Cycloid
597 while i < number:
598 t = (i * step * pi)
599 x = (t - sin(t) * b) * a / pi
600 y = (1 - cos(t) * b) * a / pi
601 z = 0
602 newpoints.append([x, y, z])
603 i += 1
604 return newpoints
607 # -----------------------------------------------------------
608 # 3D curve shape functions:
609 # -----------------------------------------------------------
611 # ------------------------------------------------------------
612 # 3DCurve: Helix:
613 def HelixCurve(number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0):
615 HelixCurve( number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0 )
617 Create helix curve
619 Parameters:
620 number - the number of points
621 (type=int)
622 height - height
623 (type=float)
624 startangle - startangle
625 (type=float)
626 endangle - endangle
627 (type=float)
628 width - width
629 (type=float)
630 a - a
631 (type=float)
632 b - b
633 (type=float)
634 Returns:
635 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
636 (type=list)
639 newpoints = []
640 angle = (2.0 / 360.0) * (endangle - startangle)
641 step = angle / (number - 1)
642 h = height / angle
643 start = startangle * 2.0 / 360.0
644 a /= angle
645 i = 0
646 while i < number:
647 t = (i * step + start)
648 x = sin((t * pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width)
649 y = cos((t * pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width)
650 z = (t * h) - h * start
651 newpoints.append([x, y, z])
652 i += 1
653 return newpoints
656 # -----------------------------------------------------------
657 # 3D Noise curve
658 def NoiseCurve(type=0, number=100, length=2.0, size=0.5,
659 scale=[0.5, 0.5, 0.5], octaves=2, basis=0, seed=0):
661 Create noise curve
663 Parameters:
664 number - number of points
665 (type=int)
666 length - curve length
667 (type=float)
668 size - noise size
669 (type=float)
670 scale - noise intensity scale x,y,z
671 (type=list)
672 basis - noise basis
673 (type=int)
674 seed - noise random seed
675 (type=int)
676 type - noise curve type
677 (type=int)
678 Returns:
679 a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
680 (type=list)
683 newpoints = []
684 step = (length / number)
685 i = 0
686 if type == 1:
687 # noise circle
688 while i < number:
689 t = i * step
690 v = vTurbNoise(t, t, t, 1.0, size, octaves, False, basis, seed)
691 x = sin(t * pi) + (v[0] * scale[0])
692 y = cos(t * pi) + (v[1] * scale[1])
693 z = v[2] * scale[2]
694 newpoints.append([x, y, z])
695 i += 1
696 elif type == 2:
697 # noise knot / ball
698 while i < number:
699 t = i * step
700 v = vTurbNoise(t, t, t, 1.0, 1.0, octaves, False, basis, seed)
701 x = v[0] * scale[0] * size
702 y = v[1] * scale[1] * size
703 z = v[2] * scale[2] * size
704 newpoints.append([x, y, z])
705 i += 1
706 else:
707 # noise linear
708 while i < number:
709 t = i * step
710 v = vTurbNoise(t, t, t, 1.0, size, octaves, False, basis, seed)
711 x = t + v[0] * scale[0]
712 y = v[1] * scale[1]
713 z = v[2] * scale[2]
714 newpoints.append([x, y, z])
715 i += 1
716 return newpoints
719 # get array of vertcoordinates according to splinetype
720 def vertsToPoints(Verts, splineType):
722 # main vars
723 vertArray = []
725 # array for BEZIER spline output (V3)
726 if splineType == 'BEZIER':
727 for v in Verts:
728 vertArray += v
730 # array for nonBEZIER output (V4)
731 else:
732 for v in Verts:
733 vertArray += v
734 if splineType == 'NURBS':
735 # for nurbs w=1
736 vertArray.append(1)
737 else:
738 # for poly w=0
739 vertArray.append(0)
740 return vertArray
743 # create new CurveObject from vertarray and splineType
744 def createCurve(context, vertArray, self):
745 # output splineType 'POLY' 'NURBS' 'BEZIER'
746 splineType = self.outputType
748 # GalloreType as name
749 name = self.ProfileType
751 # create object
752 if bpy.context.mode == 'EDIT_CURVE':
753 Curve = context.active_object
754 newSpline = Curve.data.splines.new(type=splineType) # spline
755 else:
756 # create curve
757 dataCurve = bpy.data.curves.new(name, type='CURVE') # curve data block
758 newSpline = dataCurve.splines.new(type=splineType) # spline
760 # create object with newCurve
761 Curve = object_utils.object_data_add(context, dataCurve, operator=self) # place in active scene
763 # set newSpline Options
764 newSpline.use_cyclic_u = self.use_cyclic_u
765 newSpline.use_endpoint_u = self.endp_u
766 newSpline.order_u = self.order_u
768 # set curve Options
769 Curve.data.dimensions = self.shape
770 Curve.data.use_path = True
771 if self.shape == '3D':
772 Curve.data.fill_mode = 'FULL'
773 else:
774 Curve.data.fill_mode = 'BOTH'
776 for spline in Curve.data.splines:
777 if spline.type == 'BEZIER':
778 for point in spline.bezier_points:
779 point.select_control_point = False
780 point.select_left_handle = False
781 point.select_right_handle = False
782 else:
783 for point in spline.points:
784 point.select = False
786 # create spline from vertarray
787 if splineType == 'BEZIER':
788 newSpline.bezier_points.add(int(len(vertArray) * 0.33))
789 newSpline.bezier_points.foreach_set('co', vertArray)
790 for point in newSpline.bezier_points:
791 point.handle_right_type = self.handleType
792 point.handle_left_type = self.handleType
793 point.select_control_point = True
794 point.select_left_handle = True
795 point.select_right_handle = True
796 else:
797 newSpline.points.add(int(len(vertArray) * 0.25 - 1))
798 newSpline.points.foreach_set('co', vertArray)
799 newSpline.use_endpoint_u = True
800 for point in newSpline.points:
801 point.select = True
803 # move and rotate spline in edit mode
804 if bpy.context.mode == 'EDIT_CURVE':
805 if self.align == "WORLD":
806 location = self.location - context.active_object.location
807 bpy.ops.transform.translate(value = location, orient_type='GLOBAL')
808 bpy.ops.transform.rotate(value = self.rotation[0], orient_axis = 'X', orient_type='GLOBAL')
809 bpy.ops.transform.rotate(value = self.rotation[1], orient_axis = 'Y', orient_type='GLOBAL')
810 bpy.ops.transform.rotate(value = self.rotation[2], orient_axis = 'Z', orient_type='GLOBAL')
812 elif self.align == "VIEW":
813 bpy.ops.transform.translate(value = self.location)
814 bpy.ops.transform.rotate(value = self.rotation[0], orient_axis = 'X')
815 bpy.ops.transform.rotate(value = self.rotation[1], orient_axis = 'Y')
816 bpy.ops.transform.rotate(value = self.rotation[2], orient_axis = 'Z')
818 elif self.align == "CURSOR":
819 location = context.active_object.location
820 self.location = bpy.context.scene.cursor.location - location
821 self.rotation = bpy.context.scene.cursor.rotation_euler
823 bpy.ops.transform.translate(value = self.location)
824 bpy.ops.transform.rotate(value = self.rotation[0], orient_axis = 'X')
825 bpy.ops.transform.rotate(value = self.rotation[1], orient_axis = 'Y')
826 bpy.ops.transform.rotate(value = self.rotation[2], orient_axis = 'Z')
828 return
831 # ------------------------------------------------------------
832 # Main Function
833 def main(context, self):
834 # options
835 proType = self.ProfileType
836 splineType = self.outputType
837 innerRadius = self.innerRadius
838 middleRadius = self.middleRadius
839 outerRadius = self.outerRadius
841 # get verts
842 if proType == 'Profile':
843 verts = ProfileCurve(
844 self.ProfileCurveType,
845 self.ProfileCurvevar1,
846 self.ProfileCurvevar2
848 if proType == 'Arrow':
849 verts = ArrowCurve(
850 self.MiscCurveType,
851 self.MiscCurvevar1,
852 self.MiscCurvevar2
854 if proType == 'Rectangle':
855 verts = RectCurve(
856 self.MiscCurveType,
857 self.MiscCurvevar1,
858 self.MiscCurvevar2,
859 self.MiscCurvevar3
861 if proType == 'Flower':
862 verts = FlowerCurve(
863 self.petals,
864 innerRadius,
865 outerRadius,
866 self.petalWidth
868 if proType == 'Star':
869 verts = StarCurve(
870 self.starPoints,
871 innerRadius,
872 outerRadius,
873 self.starTwist
875 if proType == 'Arc':
876 verts = ArcCurve(
877 self.arcSides,
878 self.startAngle,
879 self.endAngle,
880 innerRadius,
881 outerRadius,
882 self.arcType
884 if proType == 'Cogwheel':
885 verts = CogCurve(
886 self.teeth,
887 innerRadius,
888 middleRadius,
889 outerRadius,
890 self.bevel
892 if proType == 'Nsided':
893 verts = nSideCurve(
894 self.Nsides,
895 outerRadius
897 if proType == 'Splat':
898 verts = SplatCurve(
899 self.splatSides,
900 self.splatScale,
901 self.seed,
902 self.basis,
903 outerRadius
905 if proType == 'Cycloid':
906 verts = CycloidCurve(
907 self.cycloPoints,
908 self.cycloType,
909 self.cyclo_a,
910 self.cyclo_b,
911 self.cyclo_d
913 if proType == 'Helix':
914 verts = HelixCurve(
915 self.helixPoints,
916 self.helixHeight,
917 self.helixStart,
918 self.helixEnd,
919 self.helixWidth,
920 self.helix_a,
921 self.helix_b
923 if proType == 'Noise':
924 verts = NoiseCurve(
925 self.noiseType,
926 self.noisePoints,
927 self.noiseLength,
928 self.noiseSize,
929 [self.noiseScaleX, self.noiseScaleY, self.noiseScaleZ],
930 self.noiseOctaves,
931 self.noiseBasis,
932 self.noiseSeed
935 # turn verts into array
936 vertArray = vertsToPoints(verts, splineType)
938 # create object
939 createCurve(context, vertArray, self)
941 return
944 class Curveaceous_galore(Operator, object_utils.AddObjectHelper):
945 bl_idname = "curve.curveaceous_galore"
946 bl_label = "Curve Profiles"
947 bl_description = "Construct many types of curves"
948 bl_options = {'REGISTER', 'UNDO', 'PRESET'}
950 # general properties
951 ProfileType : EnumProperty(
952 name="Type",
953 description="Form of Curve to create",
954 items=[
955 ('Arc', "Arc", "Arc"),
956 ('Arrow', "Arrow", "Arrow"),
957 ('Cogwheel', "Cogwheel", "Cogwheel"),
958 ('Cycloid', "Cycloid", "Cycloid"),
959 ('Flower', "Flower", "Flower"),
960 ('Helix', "Helix (3D)", "Helix"),
961 ('Noise', "Noise (3D)", "Noise"),
962 ('Nsided', "Nsided", "Nsided"),
963 ('Profile', "Profile", "Profile"),
964 ('Rectangle', "Rectangle", "Rectangle"),
965 ('Splat', "Splat", "Splat"),
966 ('Star', "Star", "Star")]
968 outputType : EnumProperty(
969 name="Output splines",
970 description="Type of splines to output",
971 items=[
972 ('POLY', "Poly", "Poly Spline type"),
973 ('NURBS', "Nurbs", "Nurbs Spline type"),
974 ('BEZIER', "Bezier", "Bezier Spline type")]
976 # Curve Options
977 shape : EnumProperty(
978 name="2D / 3D",
979 description="2D or 3D Curve",
980 items=[
981 ('2D', "2D", "2D"),
982 ('3D', "3D", "3D")
985 use_cyclic_u : BoolProperty(
986 name="Cyclic",
987 default=True,
988 description="make curve closed"
990 endp_u : BoolProperty(
991 name="Use endpoint u",
992 default=True,
993 description="stretch to endpoints"
995 order_u : IntProperty(
996 name="Order u",
997 default=4,
998 min=2, soft_min=2,
999 max=6, soft_max=6,
1000 description="Order of nurbs spline"
1002 handleType : EnumProperty(
1003 name="Handle type",
1004 default='AUTO',
1005 description="Bezier handles type",
1006 items=[
1007 ('VECTOR', "Vector", "Vector type Bezier handles"),
1008 ('AUTO', "Auto", "Automatic type Bezier handles")]
1010 # ProfileCurve properties
1011 ProfileCurveType : IntProperty(
1012 name="Type",
1013 min=1,
1014 max=5,
1015 default=1,
1016 description="Type of Curve's Profile"
1018 ProfileCurvevar1 : FloatProperty(
1019 name="Variable 1",
1020 default=0.25,
1021 description="Variable 1 of Curve's Profile"
1023 ProfileCurvevar2 : FloatProperty(
1024 name="Variable 2",
1025 default=0.25,
1026 description="Variable 2 of Curve's Profile"
1028 # Arrow, Rectangle, MiscCurve properties
1029 MiscCurveType : IntProperty(
1030 name="Type",
1031 min=0,
1032 max=3,
1033 default=0,
1034 description="Type of Curve"
1036 MiscCurvevar1 : FloatProperty(
1037 name="Variable 1",
1038 default=1.0,
1039 description="Variable 1 of Curve"
1041 MiscCurvevar2 : FloatProperty(
1042 name="Variable 2",
1043 default=0.5,
1044 description="Variable 2 of Curve"
1046 MiscCurvevar3 : FloatProperty(
1047 name="Variable 3",
1048 default=0.1,
1049 min=0,
1050 description="Variable 3 of Curve"
1052 # Common properties
1053 innerRadius : FloatProperty(
1054 name="Inner radius",
1055 default=0.5,
1056 min=0,
1057 description="Inner radius"
1059 middleRadius : FloatProperty(
1060 name="Middle radius",
1061 default=0.95,
1062 min=0,
1063 description="Middle radius"
1065 outerRadius : FloatProperty(
1066 name="Outer radius",
1067 default=1.0,
1068 min=0,
1069 description="Outer radius"
1071 # Flower properties
1072 petals : IntProperty(
1073 name="Petals",
1074 default=8,
1075 min=2,
1076 description="Number of petals"
1078 petalWidth : FloatProperty(
1079 name="Petal width",
1080 default=2.0,
1081 min=0.01,
1082 description="Petal width"
1084 # Star properties
1085 starPoints : IntProperty(
1086 name="Star points",
1087 default=8,
1088 min=2,
1089 description="Number of star points"
1091 starTwist : FloatProperty(
1092 name="Twist",
1093 default=0.0,
1094 description="Twist"
1096 # Arc properties
1097 arcSides : IntProperty(
1098 name="Arc sides",
1099 default=6,
1100 min=1,
1101 description="Sides of arc"
1103 startAngle : FloatProperty(
1104 name="Start angle",
1105 default=0.0,
1106 description="Start angle"
1108 endAngle : FloatProperty(
1109 name="End angle",
1110 default=90.0,
1111 description="End angle"
1113 arcType : IntProperty(
1114 name="Arc type",
1115 default=3,
1116 min=1,
1117 max=3,
1118 description="Sides of arc"
1120 # Cogwheel properties
1121 teeth : IntProperty(
1122 name="Teeth",
1123 default=8,
1124 min=2,
1125 description="number of teeth"
1127 bevel : FloatProperty(
1128 name="Bevel",
1129 default=0.5,
1130 min=0,
1131 max=1,
1132 description="Bevel"
1134 # Nsided property
1135 Nsides : IntProperty(
1136 name="Sides",
1137 default=8,
1138 min=3,
1139 description="Number of sides"
1141 # Splat properties
1142 splatSides : IntProperty(
1143 name="Splat sides",
1144 default=24,
1145 min=3,
1146 description="Splat sides"
1148 splatScale : FloatProperty(
1149 name="Splat scale",
1150 default=1.0,
1151 min=0.0001,
1152 description="Splat scale"
1154 seed : IntProperty(
1155 name="Seed",
1156 default=0,
1157 min=0,
1158 description="Seed"
1160 basis : IntProperty(
1161 name="Basis",
1162 default=0,
1163 min=0,
1164 max=14,
1165 description="Basis"
1167 # Helix properties
1168 helixPoints : IntProperty(
1169 name="Resolution",
1170 default=100,
1171 min=3,
1172 description="Resolution"
1174 helixHeight : FloatProperty(
1175 name="Height",
1176 default=2.0,
1177 min=0,
1178 description="Helix height"
1180 helixStart : FloatProperty(
1181 name="Start angle",
1182 default=0.0,
1183 description="Helix start angle"
1185 helixEnd : FloatProperty(
1186 name="Endangle",
1187 default=360.0,
1188 description="Helix end angle"
1190 helixWidth : FloatProperty(
1191 name="Width",
1192 default=1.0,
1193 description="Helix width"
1195 helix_a : FloatProperty(
1196 name="Variable 1",
1197 default=0.0,
1198 description="Helix Variable 1"
1200 helix_b : FloatProperty(
1201 name="Variable 2",
1202 default=0.0,
1203 description="Helix Variable 2"
1205 # Cycloid properties
1206 cycloPoints : IntProperty(
1207 name="Resolution",
1208 default=100,
1209 min=3,
1210 soft_min=3,
1211 description="Resolution"
1213 cycloType : IntProperty(
1214 name="Type",
1215 default=1,
1216 min=0,
1217 max=2,
1218 description="Type: Cycloid , Hypocycloid / Hypotrochoid , Epicycloid / Epitrochoid"
1220 cyclo_a : FloatProperty(
1221 name="R",
1222 default=1.0,
1223 min=0.01,
1224 description="Cycloid: R radius a"
1226 cyclo_b : FloatProperty(
1227 name="r",
1228 default=0.25,
1229 min=0.01,
1230 description="Cycloid: r radius b"
1232 cyclo_d : FloatProperty(
1233 name="d",
1234 default=0.25,
1235 description="Cycloid: d distance"
1237 # Noise properties
1238 noiseType : IntProperty(
1239 name="Type",
1240 default=0,
1241 min=0,
1242 max=2,
1243 description="Noise curve type: Linear, Circular or Knot"
1245 noisePoints : IntProperty(
1246 name="Resolution",
1247 default=100,
1248 min=3,
1249 description="Resolution"
1251 noiseLength : FloatProperty(
1252 name="Length",
1253 default=2.0,
1254 min=0.01,
1255 description="Curve Length"
1257 noiseSize : FloatProperty(
1258 name="Noise size",
1259 default=1.0,
1260 min=0.0001,
1261 description="Noise size"
1263 noiseScaleX : FloatProperty(
1264 name="Noise x",
1265 default=1.0,
1266 min=0.0001,
1267 description="Noise x"
1269 noiseScaleY : FloatProperty(
1270 name="Noise y",
1271 default=1.0,
1272 min=0.0001,
1273 description="Noise y"
1275 noiseScaleZ : FloatProperty(
1276 name="Noise z",
1277 default=1.0,
1278 min=0.0001,
1279 description="Noise z"
1281 noiseOctaves : IntProperty(
1282 name="Octaves",
1283 default=2,
1284 min=1,
1285 max=16,
1286 description="Basis"
1288 noiseBasis : IntProperty(
1289 name="Basis",
1290 default=0,
1291 min=0,
1292 max=9,
1293 description="Basis"
1295 noiseSeed : IntProperty(
1296 name="Seed",
1297 default=1,
1298 min=0,
1299 description="Random Seed"
1302 edit_mode : BoolProperty(
1303 name="Show in edit mode",
1304 default=True,
1305 description="Show in edit mode"
1308 def draw(self, context):
1309 layout = self.layout
1311 # general options
1312 col = layout.column()
1313 col.prop(self, 'ProfileType')
1314 col.label(text=self.ProfileType + " Options:")
1316 # options per ProfileType
1317 box = layout.box()
1318 col = box.column(align=True)
1320 if self.ProfileType == 'Profile':
1321 col.prop(self, "ProfileCurveType")
1322 col.prop(self, "ProfileCurvevar1")
1323 col.prop(self, "ProfileCurvevar2")
1325 elif self.ProfileType == 'Arrow':
1326 col.prop(self, "MiscCurveType")
1327 col.prop(self, "MiscCurvevar1", text="Height")
1328 col.prop(self, "MiscCurvevar2", text="Width")
1330 elif self.ProfileType == 'Rectangle':
1331 col.prop(self, "MiscCurveType")
1332 col.prop(self, "MiscCurvevar1", text="Width")
1333 col.prop(self, "MiscCurvevar2", text="Height")
1334 if self.MiscCurveType == 2:
1335 col.prop(self, "MiscCurvevar3", text="Corners")
1337 elif self.ProfileType == 'Flower':
1338 col.prop(self, "petals")
1339 col.prop(self, "petalWidth")
1341 col = box.column(align=True)
1342 col.prop(self, "innerRadius")
1343 col.prop(self, "outerRadius")
1345 elif self.ProfileType == 'Star':
1346 col.prop(self, "starPoints")
1347 col.prop(self, "starTwist")
1349 col = box.column(align=True)
1350 col.prop(self, "innerRadius")
1351 col.prop(self, "outerRadius")
1353 elif self.ProfileType == 'Arc':
1354 col.prop(self, "arcType")
1355 col.prop(self, "arcSides")
1357 col = box.column(align=True)
1358 col.prop(self, "startAngle")
1359 col.prop(self, "endAngle")
1361 col = box.column(align=True)
1362 col.prop(self, "innerRadius")
1363 col.prop(self, "outerRadius")
1365 elif self.ProfileType == 'Cogwheel':
1366 col.prop(self, "teeth")
1367 col.prop(self, "bevel")
1369 col = box.column(align=True)
1370 col.prop(self, "innerRadius")
1371 col.prop(self, "middleRadius")
1372 col.prop(self, "outerRadius")
1374 elif self.ProfileType == 'Nsided':
1375 col.prop(self, "Nsides")
1376 col.prop(self, "outerRadius")
1378 elif self.ProfileType == 'Splat':
1379 col.prop(self, "splatSides")
1380 col.prop(self, "outerRadius")
1382 col = box.column(align=True)
1383 col.prop(self, "splatScale")
1384 col.prop(self, "seed")
1385 col.prop(self, "basis")
1387 elif self.ProfileType == 'Cycloid':
1388 col.prop(self, "cycloType")
1389 col.prop(self, "cycloPoints")
1391 col = box.column(align=True)
1392 col.prop(self, "cyclo_a")
1393 col.prop(self, "cyclo_b")
1394 if self.cycloType != 0:
1395 col.prop(self, "cyclo_d")
1397 elif self.ProfileType == 'Helix':
1398 col.prop(self, "helixPoints")
1399 col.prop(self, "helixHeight")
1400 col.prop(self, "helixWidth")
1402 col = box.column(align=True)
1403 col.prop(self, "helixStart")
1404 col.prop(self, "helixEnd")
1406 col = box.column(align=True)
1407 col.prop(self, "helix_a")
1408 col.prop(self, "helix_b")
1410 elif self.ProfileType == 'Noise':
1411 col.prop(self, "noiseType")
1412 col.prop(self, "noisePoints")
1413 col.prop(self, "noiseLength")
1415 col = box.column(align=True)
1416 col.prop(self, "noiseSize")
1417 col.prop(self, "noiseScaleX")
1418 col.prop(self, "noiseScaleY")
1419 col.prop(self, "noiseScaleZ")
1421 col = box.column(align=True)
1422 col.prop(self, "noiseOctaves")
1423 col.prop(self, "noiseBasis")
1424 col.prop(self, "noiseSeed")
1426 row = layout.row()
1427 row.prop(self, "shape", expand=True)
1429 # output options
1430 col = layout.column()
1431 col.label(text="Output Curve Type:")
1432 col.row().prop(self, "outputType", expand=True)
1434 if self.outputType == 'NURBS':
1435 col.prop(self, 'order_u')
1436 elif self.outputType == 'BEZIER':
1437 col.row().prop(self, 'handleType', expand=True)
1439 col = layout.column()
1440 col.row().prop(self, "use_cyclic_u", expand=True)
1442 col = layout.column()
1443 col.row().prop(self, "edit_mode", expand=True)
1445 col = layout.column()
1446 # AddObjectHelper props
1447 col.prop(self, "align")
1448 col.prop(self, "location")
1449 col.prop(self, "rotation")
1451 @classmethod
1452 def poll(cls, context):
1453 return context.scene is not None
1455 def execute(self, context):
1456 # turn off 'Enter Edit Mode'
1457 use_enter_edit_mode = bpy.context.preferences.edit.use_enter_edit_mode
1458 bpy.context.preferences.edit.use_enter_edit_mode = False
1460 # main function
1461 main(context, self)
1463 if use_enter_edit_mode:
1464 bpy.ops.object.mode_set(mode = 'EDIT')
1466 # restore pre operator state
1467 bpy.context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode
1469 if self.edit_mode:
1470 bpy.ops.object.mode_set(mode = 'EDIT')
1471 else:
1472 bpy.ops.object.mode_set(mode = 'OBJECT')
1474 return {'FINISHED'}
1476 def invoke(self, context, event):
1477 # deal with 2D - 3D curve differences
1478 if self.ProfileType in ['Helix', 'Cycloid', 'Noise']:
1479 self.shape = '3D'
1480 else:
1481 self.shape = '2D'
1483 if self.ProfileType in ['Helix', 'Noise', 'Cycloid']:
1484 self.use_cyclic_u = False
1485 if self.ProfileType in ['Cycloid']:
1486 if self.cycloType == 0:
1487 self.use_cyclic_u = False
1488 else:
1489 self.use_cyclic_u = True
1490 else:
1491 if self.ProfileType == 'Arc' and self.arcType == 1:
1492 self.use_cyclic_u = False
1493 else:
1494 self.use_cyclic_u = True
1496 self.execute(context)
1498 return {'FINISHED'}
1500 # Register
1501 classes = [
1502 Curveaceous_galore
1505 def register():
1506 from bpy.utils import register_class
1507 for cls in classes:
1508 register_class(cls)
1510 def unregister():
1511 from bpy.utils import unregister_class
1512 for cls in reversed(classes):
1513 unregister_class(cls)
1515 if __name__ == "__main__":
1516 register()