-
Campbell Barton authored
See T95597
Campbell Barton authoredSee T95597
add_curve_aceous_galore.py 43.94 KiB
# SPDX-License-Identifier: GPL-2.0-or-later
"""
bl_info = {
"name": "Curveaceous Galore!",
"author": "Jimmy Hazevoet, testscreenings",
"version": (0, 2, 3),
"blender": (2, 80),
"location": "View3D > Add > Curve",
"description": "Adds many different types of Curves",
"warning": "",
"doc_url": "{BLENDER_MANUAL_URL}/addons/add_curve/extra_objects.html",
"category": "Add Curve",
}
"""
import bpy
from bpy_extras import object_utils
from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
IntProperty,
FloatVectorProperty
)
from mathutils import Matrix, Vector
from bpy.types import Operator
from math import (
sin, cos, pi
)
import mathutils.noise as Noise
# ------------------------------------------------------------
# Some functions to use with others:
# ------------------------------------------------------------
# ------------------------------------------------------------
# Generate random number:
def randnum(low=0.0, high=1.0, seed=0):
"""
randnum( low=0.0, high=1.0, seed=0 )
Create random number
Parameters:
low - lower range
(type=float)
high - higher range
(type=float)
seed - the random seed number, if seed == 0, the current time will be used instead
(type=int)
Returns:
a random number
(type=float)
"""
Noise.seed_set(seed)
rnum = Noise.random()
rnum = rnum * (high - low)
rnum = rnum + low
return rnum
# ------------------------------------------------------------
# Make some noise:
def vTurbNoise(x, y, z, iScale=0.25, Size=1.0, Depth=6, Hard=False, Basis=0, Seed=0):
"""
vTurbNoise((x,y,z), iScale=0.25, Size=1.0, Depth=6, Hard=0, Basis=0, Seed=0 )
Create randomised vTurbulence noise
Parameters:
xyz - (x,y,z) float values.
(type=3-float tuple)
iScale - noise intensity scale
(type=float)
Size - noise size
(type=float)
Depth - number of noise values added.
(type=int)
Hard - noise hardness: True - soft noise; False - hard noise
(type=int)
basis - type of noise used for turbulence
(type=int)
Seed - the random seed number, if seed == 0, the current time will be used instead
(type=int)
Returns:
the generated turbulence vector.
(type=3-float list)
"""
rand = randnum(-100, 100, Seed)
if Basis == 9:
Basis = 14
vec = Vector((x / Size + rand, y / Size + rand, z / Size + rand))
vTurb = Noise.turbulence_vector(vec, Depth, Hard)
#mathutils.noise.turbulence_vector(position, octaves, hard, noise_basis='PERLIN_ORIGINAL', amplitude_scale=0.5, frequency_scale=2.0)
tx = vTurb[0] * iScale
ty = vTurb[1] * iScale
tz = vTurb[2] * iScale
return tx, ty, tz
# -------------------------------------------------------------------
# 2D Curve shape functions:
# -------------------------------------------------------------------
# ------------------------------------------------------------
# 2DCurve: Profile: L, H, T, U, Z
def ProfileCurve(type=0, a=0.25, b=0.25):
"""
ProfileCurve( type=0, a=0.25, b=0.25 )
Create profile curve
Parameters:
type - select profile type, L, H, T, U, Z
(type=int)
a - a scaling parameter
(type=float)
b - b scaling parameter
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
if type == 1:
# H:
a *= 0.5
b *= 0.5
newpoints = [
[-1.0, 1.0, 0.0], [-1.0 + a, 1.0, 0.0],
[-1.0 + a, b, 0.0], [1.0 - a, b, 0.0], [1.0 - a, 1.0, 0.0],
[1.0, 1.0, 0.0], [1.0, -1.0, 0.0], [1.0 - a, -1.0, 0.0],
[1.0 - a, -b, 0.0], [-1.0 + a, -b, 0.0], [-1.0 + a, -1.0, 0.0],
[-1.0, -1.0, 0.0]
]
elif type == 2:
# T:
a *= 0.5
newpoints = [
[-1.0, 1.0, 0.0], [1.0, 1.0, 0.0],
[1.0, 1.0 - b, 0.0], [a, 1.0 - b, 0.0], [a, -1.0, 0.0],
[-a, -1.0, 0.0], [-a, 1.0 - b, 0.0], [-1.0, 1.0 - b, 0.0]
]
elif type == 3:
# U:
a *= 0.5
newpoints = [
[-1.0, 1.0, 0.0], [-1.0 + a, 1.0, 0.0],
[-1.0 + a, -1.0 + b, 0.0], [1.0 - a, -1.0 + b, 0.0], [1.0 - a, 1.0, 0.0],
[1.0, 1.0, 0.0], [1.0, -1.0, 0.0], [-1.0, -1.0, 0.0]
]
elif type == 4:
# Z:
a *= 0.5
newpoints = [
[-0.5, 1.0, 0.0], [a, 1.0, 0.0],
[a, -1.0 + b, 0.0], [1.0, -1.0 + b, 0.0], [1.0, -1.0, 0.0],
[-a, -1.0, 0.0], [-a, 1.0 - b, 0.0], [-1.0, 1.0 - b, 0.0],
[-1.0, 1.0, 0.0]
]
else:
# L:
newpoints = [
[-1.0, 1.0, 0.0], [-1.0 + a, 1.0, 0.0],
[-1.0 + a, -1.0 + b, 0.0], [1.0, -1.0 + b, 0.0],
[1.0, -1.0, 0.0], [-1.0, -1.0, 0.0]
]
return newpoints
# ------------------------------------------------------------
# 2DCurve: Arrow
def ArrowCurve(type=1, a=1.0, b=0.5):
"""
ArrowCurve( type=1, a=1.0, b=0.5, c=1.0 )
Create arrow curve
Parameters:
type - select type, Arrow1, Arrow2
(type=int)
a - a scaling parameter
(type=float)
b - b scaling parameter
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
if type == 0:
# Arrow1:
a *= 0.5
b *= 0.5
newpoints = [
[-1.0, b, 0.0], [-1.0 + a, b, 0.0],
[-1.0 + a, 1.0, 0.0], [1.0, 0.0, 0.0],
[-1.0 + a, -1.0, 0.0], [-1.0 + a, -b, 0.0],
[-1.0, -b, 0.0]
]
elif type == 1:
# Arrow2:
newpoints = [[-a, b, 0.0], [a, 0.0, 0.0], [-a, -b, 0.0], [0.0, 0.0, 0.0]]
else:
# diamond:
newpoints = [[0.0, b, 0.0], [a, 0.0, 0.0], [0.0, -b, 0.0], [-a, 0.0, 0.0]]
return newpoints
# ------------------------------------------------------------
# 2DCurve: Square / Rectangle
def RectCurve(type=1, a=1.0, b=0.5, c=1.0):
"""
RectCurve( type=1, a=1.0, b=0.5, c=1.0 )
Create square / rectangle curve
Parameters:
type - select type, Square, Rounded square 1, Rounded square 2
(type=int)
a - a scaling parameter
(type=float)
b - b scaling parameter
(type=float)
c - c scaling parameter
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
if type == 1:
# Rounded Rectangle:
newpoints = [
[-a, b - b * 0.2, 0.0], [-a + a * 0.05, b - b * 0.05, 0.0], [-a + a * 0.2, b, 0.0],
[a - a * 0.2, b, 0.0], [a - a * 0.05, b - b * 0.05, 0.0], [a, b - b * 0.2, 0.0],
[a, -b + b * 0.2, 0.0], [a - a * 0.05, -b + b * 0.05, 0.0], [a - a * 0.2, -b, 0.0],
[-a + a * 0.2, -b, 0.0], [-a + a * 0.05, -b + b * 0.05, 0.0], [-a, -b + b * 0.2, 0.0]
]
elif type == 2:
# Rounded Rectangle II:
newpoints = []
x = a
y = b
r = c
if r > x:
r = x - 0.0001
if r > y:
r = y - 0.0001
if r > 0:
newpoints.append([-x + r, y, 0])
newpoints.append([x - r, y, 0])
newpoints.append([x, y - r, 0])
newpoints.append([x, -y + r, 0])
newpoints.append([x - r, -y, 0])
newpoints.append([-x + r, -y, 0])
newpoints.append([-x, -y + r, 0])
newpoints.append([-x, y - r, 0])
else:
newpoints.append([-x, y, 0])
newpoints.append([x, y, 0])
newpoints.append([x, -y, 0])
newpoints.append([-x, -y, 0])
else:
# Rectangle:
newpoints = [[-a, b, 0.0], [a, b, 0.0], [a, -b, 0.0], [-a, -b, 0.0]]
return newpoints
# ------------------------------------------------------------
# 2DCurve: Star:
def StarCurve(starpoints=8, innerradius=0.5, outerradius=1.0, twist=0.0):
"""
StarCurve( starpoints=8, innerradius=0.5, outerradius=1.0, twist=0.0 )
Create star shaped curve
Parameters:
starpoints - the number of points
(type=int)
innerradius - innerradius
(type=float)
outerradius - outerradius
(type=float)
twist - twist amount
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
step = 2.0 / starpoints
i = 0
while i < starpoints:
t = i * step
x1 = cos(t * pi) * outerradius
y1 = sin(t * pi) * outerradius
newpoints.append([x1, y1, 0])
x2 = cos(t * pi + (pi / starpoints + twist)) * innerradius
y2 = sin(t * pi + (pi / starpoints + twist)) * innerradius
newpoints.append([x2, y2, 0])
i += 1
return newpoints
# ------------------------------------------------------------
# 2DCurve: Flower:
def FlowerCurve(petals=8, innerradius=0.5, outerradius=1.0, petalwidth=2.0):
"""
FlowerCurve( petals=8, innerradius=0.5, outerradius=1.0, petalwidth=2.0 )
Create flower shaped curve
Parameters:
petals - the number of petals
(type=int)
innerradius - innerradius
(type=float)
outerradius - outerradius
(type=float)
petalwidth - width of petals
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
step = 2.0 / petals
pet = (step / pi * 2) * petalwidth
i = 0
while i < petals:
t = i * step
x1 = cos(t * pi - (pi / petals)) * innerradius
y1 = sin(t * pi - (pi / petals)) * innerradius
newpoints.append([x1, y1, 0])
x2 = cos(t * pi - pet) * outerradius
y2 = sin(t * pi - pet) * outerradius
newpoints.append([x2, y2, 0])
x3 = cos(t * pi + pet) * outerradius
y3 = sin(t * pi + pet) * outerradius
newpoints.append([x3, y3, 0])
i += 1
return newpoints
# ------------------------------------------------------------
# 2DCurve: Arc,Sector,Segment,Ring:
def ArcCurve(sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradius=1.0, type=3):
"""
ArcCurve( sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradius=1.0, type=3 )
Create arc shaped curve
Parameters:
sides - number of sides
(type=int)
startangle - startangle
(type=float)
endangle - endangle
(type=float)
innerradius - innerradius
(type=float)
outerradius - outerradius
(type=float)
type - select type Arc,Sector,Segment,Ring
(type=int)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
sides += 1
angle = 2.0 * (1.0 / 360.0)
endangle -= startangle
step = (angle * endangle) / (sides - 1)
i = 0
while i < sides:
t = (i * step) + angle * startangle
x1 = sin(t * pi) * outerradius
y1 = cos(t * pi) * outerradius
newpoints.append([x1, y1, 0])
i += 1
# if type == 1:
# Arc: turn cyclic curve flag off!
# Segment:
if type == 2:
newpoints.append([0, 0, 0])
# Ring:
elif type == 3:
j = sides - 1
while j > -1:
t = (j * step) + angle * startangle
x2 = sin(t * pi) * innerradius
y2 = cos(t * pi) * innerradius
newpoints.append([x2, y2, 0])
j -= 1
return newpoints
# ------------------------------------------------------------
# 2DCurve: Cog wheel:
def CogCurve(theeth=8, innerradius=0.8, middleradius=0.95, outerradius=1.0, bevel=0.5):
"""
CogCurve( theeth=8, innerradius=0.8, middleradius=0.95, outerradius=1.0, bevel=0.5 )
Create cog wheel shaped curve
Parameters:
theeth - number of theeth
(type=int)
innerradius - innerradius
(type=float)
middleradius - middleradius
(type=float)
outerradius - outerradius
(type=float)
bevel - bevel amount
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
step = 2.0 / theeth
pet = step / pi * 2
bevel = 1.0 - bevel
i = 0
while i < theeth:
t = i * step
x1 = cos(t * pi - (pi / theeth) - pet) * innerradius
y1 = sin(t * pi - (pi / theeth) - pet) * innerradius
newpoints.append([x1, y1, 0])
x2 = cos(t * pi - (pi / theeth) + pet) * innerradius
y2 = sin(t * pi - (pi / theeth) + pet) * innerradius
newpoints.append([x2, y2, 0])
x3 = cos(t * pi - pet) * middleradius
y3 = sin(t * pi - pet) * middleradius
newpoints.append([x3, y3, 0])
x4 = cos(t * pi - (pet * bevel)) * outerradius
y4 = sin(t * pi - (pet * bevel)) * outerradius
newpoints.append([x4, y4, 0])
x5 = cos(t * pi + (pet * bevel)) * outerradius
y5 = sin(t * pi + (pet * bevel)) * outerradius
newpoints.append([x5, y5, 0])
x6 = cos(t * pi + pet) * middleradius
y6 = sin(t * pi + pet) * middleradius
newpoints.append([x6, y6, 0])
i += 1
return newpoints
# ------------------------------------------------------------
# 2DCurve: nSide:
def nSideCurve(sides=6, radius=1.0):
"""
nSideCurve( sides=6, radius=1.0 )
Create n-sided curve
Parameters:
sides - number of sides
(type=int)
radius - radius
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
step = 2.0 / sides
i = 0
while i < sides:
t = i * step
x = sin(t * pi) * radius
y = cos(t * pi) * radius
newpoints.append([x, y, 0])
i += 1
return newpoints
# ------------------------------------------------------------
# 2DCurve: Splat:
def SplatCurve(sides=24, scale=1.0, seed=0, basis=0, radius=1.0):
"""
SplatCurve( sides=24, scale=1.0, seed=0, basis=0, radius=1.0 )
Create splat curve
Parameters:
sides - number of sides
(type=int)
scale - noise size
(type=float)
seed - noise random seed
(type=int)
basis - noise basis
(type=int)
radius - radius
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
step = 2.0 / sides
i = 0
while i < sides:
t = i * step
turb = vTurbNoise(t, t, t, 1.0, scale, 6, False, basis, seed)
turb = turb[2] * 0.5 + 0.5
x = sin(t * pi) * radius * turb
y = cos(t * pi) * radius * turb
newpoints.append([x, y, 0])
i += 1
return newpoints
# -----------------------------------------------------------
# Cycloid curve
def CycloidCurve(number=100, type=0, R=4.0, r=1.0, d=1.0):
"""
CycloidCurve( number=100, type=0, a=4.0, b=1.0 )
Create a Cycloid, Hypotrochoid / Hypocycloid or Epitrochoid / Epycycloid type of curve
Parameters:
number - the number of points
(type=int)
type - types: Cycloid, Hypocycloid, Epicycloid
(type=int)
R = Radius a scaling parameter
(type=float)
r = Radius b scaling parameter
(type=float)
d = Distance scaling parameter
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
a = R
b = r
newpoints = []
step = 2.0 / (number - 1)
i = 0
if type == 1:
# Hypotrochoid / Hypocycloid
while i < number:
t = i * step
x = ((a - b) * cos(t * pi)) + (d * cos(((a + b) / b) * t * pi))
y = ((a - b) * sin(t * pi)) - (d * sin(((a + b) / b) * t * pi))
z = 0
newpoints.append([x, y, z])
i += 1
elif type == 2:
# Epitrochoid / Epycycloid
while i < number:
t = i * step
x = ((a + b) * cos(t * pi)) - (d * cos(((a + b) / b) * t * pi))
y = ((a + b) * sin(t * pi)) - (d * sin(((a + b) / b) * t * pi))
z = 0
newpoints.append([x, y, z])
i += 1
else:
# Cycloid
while i < number:
t = (i * step * pi)
x = (t - sin(t) * b) * a / pi
y = (1 - cos(t) * b) * a / pi
z = 0
newpoints.append([x, y, z])
i += 1
return newpoints
# -----------------------------------------------------------
# 3D curve shape functions:
# -----------------------------------------------------------
# ------------------------------------------------------------
# 3DCurve: Helix:
def HelixCurve(number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0):
"""
HelixCurve( number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0 )
Create helix curve
Parameters:
number - the number of points
(type=int)
height - height
(type=float)
startangle - startangle
(type=float)
endangle - endangle
(type=float)
width - width
(type=float)
a - a
(type=float)
b - b
(type=float)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
angle = (2.0 / 360.0) * (endangle - startangle)
step = angle / (number - 1)
h = height / angle
start = startangle * 2.0 / 360.0
a /= angle
i = 0
while i < number:
t = (i * step + start)
x = sin((t * pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width)
y = cos((t * pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width)
z = (t * h) - h * start
newpoints.append([x, y, z])
i += 1
return newpoints
# -----------------------------------------------------------
# 3D Noise curve
def NoiseCurve(type=0, number=100, length=2.0, size=0.5,
scale=[0.5, 0.5, 0.5], octaves=2, basis=0, seed=0):
"""
Create noise curve
Parameters:
number - number of points
(type=int)
length - curve length
(type=float)
size - noise size
(type=float)
scale - noise intensity scale x,y,z
(type=list)
basis - noise basis
(type=int)
seed - noise random seed
(type=int)
type - noise curve type
(type=int)
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
step = (length / number)
i = 0
if type == 1:
# noise circle
while i < number:
t = i * step
v = vTurbNoise(t, t, t, 1.0, size, octaves, False, basis, seed)
x = sin(t * pi) + (v[0] * scale[0])
y = cos(t * pi) + (v[1] * scale[1])
z = v[2] * scale[2]
newpoints.append([x, y, z])
i += 1
elif type == 2:
# noise knot / ball
while i < number:
t = i * step
v = vTurbNoise(t, t, t, 1.0, 1.0, octaves, False, basis, seed)
x = v[0] * scale[0] * size
y = v[1] * scale[1] * size
z = v[2] * scale[2] * size
newpoints.append([x, y, z])
i += 1
else:
# noise linear
while i < number:
t = i * step
v = vTurbNoise(t, t, t, 1.0, size, octaves, False, basis, seed)
x = t + v[0] * scale[0]
y = v[1] * scale[1]
z = v[2] * scale[2]
newpoints.append([x, y, z])
i += 1
return newpoints
# get array of vertcoordinates according to splinetype
def vertsToPoints(Verts, splineType):
# main vars
vertArray = []
# array for BEZIER spline output (V3)
if splineType == 'BEZIER':
for v in Verts:
vertArray += v
# array for nonBEZIER output (V4)
else:
for v in Verts:
vertArray += v
if splineType == 'NURBS':
# for nurbs w=1
vertArray.append(1)
else:
# for poly w=0
vertArray.append(0)
return vertArray
# create new CurveObject from vertarray and splineType
def createCurve(context, vertArray, self):
# output splineType 'POLY' 'NURBS' 'BEZIER'
splineType = self.outputType
# GalloreType as name
name = self.ProfileType
# create object
if bpy.context.mode == 'EDIT_CURVE':
Curve = context.active_object
newSpline = Curve.data.splines.new(type=splineType) # spline
else:
# create curve
dataCurve = bpy.data.curves.new(name, type='CURVE') # curve data block
newSpline = dataCurve.splines.new(type=splineType) # spline
# create object with newCurve
Curve = object_utils.object_data_add(context, dataCurve, operator=self) # place in active scene
# set newSpline Options
newSpline.use_cyclic_u = self.use_cyclic_u
newSpline.use_endpoint_u = self.endp_u
newSpline.order_u = self.order_u
# set curve Options
Curve.data.dimensions = self.shape
Curve.data.use_path = True
if self.shape == '3D':
Curve.data.fill_mode = 'FULL'
else:
Curve.data.fill_mode = 'BOTH'
for spline in Curve.data.splines:
if spline.type == 'BEZIER':
for point in spline.bezier_points:
point.select_control_point = False
point.select_left_handle = False
point.select_right_handle = False
else:
for point in spline.points:
point.select = False
# create spline from vertarray
if splineType == 'BEZIER':
newSpline.bezier_points.add(int(len(vertArray) * 0.33))
newSpline.bezier_points.foreach_set('co', vertArray)
for point in newSpline.bezier_points:
point.handle_right_type = self.handleType
point.handle_left_type = self.handleType
point.select_control_point = True
point.select_left_handle = True
point.select_right_handle = True
else:
newSpline.points.add(int(len(vertArray) * 0.25 - 1))
newSpline.points.foreach_set('co', vertArray)
newSpline.use_endpoint_u = True
for point in newSpline.points:
point.select = True
# move and rotate spline in edit mode
if bpy.context.mode == 'EDIT_CURVE':
if self.align == "WORLD":
location = self.location - context.active_object.location
bpy.ops.transform.translate(value = location, orient_type='GLOBAL')
bpy.ops.transform.rotate(value = self.rotation[0], orient_axis = 'X', orient_type='GLOBAL')
bpy.ops.transform.rotate(value = self.rotation[1], orient_axis = 'Y', orient_type='GLOBAL')
bpy.ops.transform.rotate(value = self.rotation[2], orient_axis = 'Z', orient_type='GLOBAL')
elif self.align == "VIEW":
bpy.ops.transform.translate(value = self.location)
bpy.ops.transform.rotate(value = self.rotation[0], orient_axis = 'X')
bpy.ops.transform.rotate(value = self.rotation[1], orient_axis = 'Y')
bpy.ops.transform.rotate(value = self.rotation[2], orient_axis = 'Z')
elif self.align == "CURSOR":
location = context.active_object.location
self.location = bpy.context.scene.cursor.location - location
self.rotation = bpy.context.scene.cursor.rotation_euler
bpy.ops.transform.translate(value = self.location)
bpy.ops.transform.rotate(value = self.rotation[0], orient_axis = 'X')
bpy.ops.transform.rotate(value = self.rotation[1], orient_axis = 'Y')
bpy.ops.transform.rotate(value = self.rotation[2], orient_axis = 'Z')
return
# ------------------------------------------------------------
# Main Function
def main(context, self):
# options
proType = self.ProfileType
splineType = self.outputType
innerRadius = self.innerRadius
middleRadius = self.middleRadius
outerRadius = self.outerRadius
# get verts
if proType == 'Profile':
verts = ProfileCurve(
self.ProfileCurveType,
self.ProfileCurvevar1,
self.ProfileCurvevar2
)
if proType == 'Arrow':
verts = ArrowCurve(
self.MiscCurveType,
self.MiscCurvevar1,
self.MiscCurvevar2
)
if proType == 'Rectangle':
verts = RectCurve(
self.MiscCurveType,
self.MiscCurvevar1,
self.MiscCurvevar2,
self.MiscCurvevar3
)
if proType == 'Flower':
verts = FlowerCurve(
self.petals,
innerRadius,
outerRadius,
self.petalWidth
)
if proType == 'Star':
verts = StarCurve(
self.starPoints,
innerRadius,
outerRadius,
self.starTwist
)
if proType == 'Arc':
verts = ArcCurve(
self.arcSides,
self.startAngle,
self.endAngle,
innerRadius,
outerRadius,
self.arcType
)
if proType == 'Cogwheel':
verts = CogCurve(
self.teeth,
innerRadius,
middleRadius,
outerRadius,
self.bevel
)
if proType == 'Nsided':
verts = nSideCurve(
self.Nsides,
outerRadius
)
if proType == 'Splat':
verts = SplatCurve(
self.splatSides,
self.splatScale,
self.seed,
self.basis,
outerRadius
)
if proType == 'Cycloid':
verts = CycloidCurve(
self.cycloPoints,
self.cycloType,
self.cyclo_a,
self.cyclo_b,
self.cyclo_d
)
if proType == 'Helix':
verts = HelixCurve(
self.helixPoints,
self.helixHeight,
self.helixStart,
self.helixEnd,
self.helixWidth,
self.helix_a,
self.helix_b
)
if proType == 'Noise':
verts = NoiseCurve(
self.noiseType,
self.noisePoints,
self.noiseLength,
self.noiseSize,
[self.noiseScaleX, self.noiseScaleY, self.noiseScaleZ],
self.noiseOctaves,
self.noiseBasis,
self.noiseSeed
)
# turn verts into array
vertArray = vertsToPoints(verts, splineType)
# create object
createCurve(context, vertArray, self)
return
class Curveaceous_galore(Operator, object_utils.AddObjectHelper):
bl_idname = "curve.curveaceous_galore"
bl_label = "Curve Profiles"
bl_description = "Construct many types of curves"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
# general properties
ProfileType : EnumProperty(
name="Type",
description="Form of Curve to create",
items=[
('Arc', "Arc", "Arc"),
('Arrow', "Arrow", "Arrow"),
('Cogwheel', "Cogwheel", "Cogwheel"),
('Cycloid', "Cycloid", "Cycloid"),
('Flower', "Flower", "Flower"),
('Helix', "Helix (3D)", "Helix"),
('Noise', "Noise (3D)", "Noise"),
('Nsided', "Nsided", "Nsided"),
('Profile', "Profile", "Profile"),
('Rectangle', "Rectangle", "Rectangle"),
('Splat', "Splat", "Splat"),
('Star', "Star", "Star")]
)
outputType : EnumProperty(
name="Output splines",
description="Type of splines to output",
items=[
('POLY', "Poly", "Poly Spline type"),
('NURBS', "Nurbs", "Nurbs Spline type"),
('BEZIER', "Bezier", "Bezier Spline type")]
)
# Curve Options
shape : EnumProperty(
name="2D / 3D",
description="2D or 3D Curve",
items=[
('2D', "2D", "2D"),
('3D', "3D", "3D")
]
)
use_cyclic_u : BoolProperty(
name="Cyclic",
default=True,
description="make curve closed"
)
endp_u : BoolProperty(
name="Use endpoint u",
default=True,
description="stretch to endpoints"
)
order_u : IntProperty(
name="Order u",
default=4,
min=2, soft_min=2,
max=6, soft_max=6,
description="Order of nurbs spline"
)
handleType : EnumProperty(
name="Handle type",
default='AUTO',
description="Bezier handles type",
items=[
('VECTOR', "Vector", "Vector type Bezier handles"),
('AUTO', "Auto", "Automatic type Bezier handles")]
)
# ProfileCurve properties
ProfileCurveType : IntProperty(
name="Type",
min=1,
max=5,
default=1,
description="Type of Curve's Profile"
)
ProfileCurvevar1 : FloatProperty(
name="Variable 1",
default=0.25,
description="Variable 1 of Curve's Profile"
)
ProfileCurvevar2 : FloatProperty(
name="Variable 2",
default=0.25,
description="Variable 2 of Curve's Profile"
)
# Arrow, Rectangle, MiscCurve properties
MiscCurveType : IntProperty(
name="Type",
min=0,
max=3,
default=0,
description="Type of Curve"
)
MiscCurvevar1 : FloatProperty(
name="Variable 1",
default=1.0,
description="Variable 1 of Curve"
)
MiscCurvevar2 : FloatProperty(
name="Variable 2",
default=0.5,
description="Variable 2 of Curve"
)
MiscCurvevar3 : FloatProperty(
name="Variable 3",
default=0.1,
min=0,
description="Variable 3 of Curve"
)
# Common properties
innerRadius : FloatProperty(
name="Inner radius",
default=0.5,
min=0,
description="Inner radius"
)
middleRadius : FloatProperty(
name="Middle radius",
default=0.95,
min=0,
description="Middle radius"
)
outerRadius : FloatProperty(
name="Outer radius",
default=1.0,
min=0,
description="Outer radius"
)
# Flower properties
petals : IntProperty(
name="Petals",
default=8,
min=2,
description="Number of petals"
)
petalWidth : FloatProperty(
name="Petal width",
default=2.0,
min=0.01,
description="Petal width"
)
# Star properties
starPoints : IntProperty(
name="Star points",
default=8,
min=2,
description="Number of star points"
)
starTwist : FloatProperty(
name="Twist",
default=0.0,
description="Twist"
)
# Arc properties
arcSides : IntProperty(
name="Arc sides",
default=6,
min=1,
description="Sides of arc"
)
startAngle : FloatProperty(
name="Start angle",
default=0.0,
description="Start angle"
)
endAngle : FloatProperty(
name="End angle",
default=90.0,
description="End angle"
)
arcType : IntProperty(
name="Arc type",
default=3,
min=1,
max=3,
description="Sides of arc"
)
# Cogwheel properties
teeth : IntProperty(
name="Teeth",
default=8,
min=2,
description="number of teeth"
)
bevel : FloatProperty(
name="Bevel",
default=0.5,
min=0,
max=1,
description="Bevel"
)
# Nsided property
Nsides : IntProperty(
name="Sides",
default=8,
min=3,
description="Number of sides"
)
# Splat properties
splatSides : IntProperty(
name="Splat sides",
default=24,
min=3,
description="Splat sides"
)
splatScale : FloatProperty(
name="Splat scale",
default=1.0,
min=0.0001,
description="Splat scale"
)
seed : IntProperty(
name="Seed",
default=0,
min=0,
description="Seed"
)
basis : IntProperty(
name="Basis",
default=0,
min=0,
max=14,
description="Basis"
)
# Helix properties
helixPoints : IntProperty(
name="Resolution",
default=100,
min=3,
description="Resolution"
)
helixHeight : FloatProperty(
name="Height",
default=2.0,
min=0,
description="Helix height"
)
helixStart : FloatProperty(
name="Start angle",
default=0.0,
description="Helix start angle"
)
helixEnd : FloatProperty(
name="Endangle",
default=360.0,
description="Helix end angle"
)
helixWidth : FloatProperty(
name="Width",
default=1.0,
description="Helix width"
)
helix_a : FloatProperty(
name="Variable 1",
default=0.0,
description="Helix Variable 1"
)
helix_b : FloatProperty(
name="Variable 2",
default=0.0,
description="Helix Variable 2"
)
# Cycloid properties
cycloPoints : IntProperty(
name="Resolution",
default=100,
min=3,
soft_min=3,
description="Resolution"
)
cycloType : IntProperty(
name="Type",
default=1,
min=0,
max=2,
description="Type: Cycloid , Hypocycloid / Hypotrochoid , Epicycloid / Epitrochoid"
)
cyclo_a : FloatProperty(
name="R",
default=1.0,
min=0.01,
description="Cycloid: R radius a"
)
cyclo_b : FloatProperty(
name="r",
default=0.25,
min=0.01,
description="Cycloid: r radius b"
)
cyclo_d : FloatProperty(
name="d",
default=0.25,
description="Cycloid: d distance"
)
# Noise properties
noiseType : IntProperty(
name="Type",
default=0,
min=0,
max=2,
description="Noise curve type: Linear, Circular or Knot"
)
noisePoints : IntProperty(
name="Resolution",
default=100,
min=3,
description="Resolution"
)
noiseLength : FloatProperty(
name="Length",
default=2.0,
min=0.01,
description="Curve Length"
)
noiseSize : FloatProperty(
name="Noise size",
default=1.0,
min=0.0001,
description="Noise size"
)
noiseScaleX : FloatProperty(
name="Noise x",
default=1.0,
min=0.0001,
description="Noise x"
)
noiseScaleY : FloatProperty(
name="Noise y",
default=1.0,
min=0.0001,
description="Noise y"
)
noiseScaleZ : FloatProperty(
name="Noise z",
default=1.0,
min=0.0001,
description="Noise z"
)
noiseOctaves : IntProperty(
name="Octaves",
default=2,
min=1,
max=16,
description="Basis"
)
noiseBasis : IntProperty(
name="Basis",
default=0,
min=0,
max=9,
description="Basis"
)
noiseSeed : IntProperty(
name="Seed",
default=1,
min=0,
description="Random Seed"
)
edit_mode : BoolProperty(
name="Show in edit mode",
default=True,
description="Show in edit mode"
)
def draw(self, context):
layout = self.layout
# general options
col = layout.column()
col.prop(self, 'ProfileType')
col.label(text=self.ProfileType + " Options:")
# options per ProfileType
box = layout.box()
col = box.column(align=True)
if self.ProfileType == 'Profile':
col.prop(self, "ProfileCurveType")
col.prop(self, "ProfileCurvevar1")
col.prop(self, "ProfileCurvevar2")
elif self.ProfileType == 'Arrow':
col.prop(self, "MiscCurveType")
col.prop(self, "MiscCurvevar1", text="Height")
col.prop(self, "MiscCurvevar2", text="Width")
elif self.ProfileType == 'Rectangle':
col.prop(self, "MiscCurveType")
col.prop(self, "MiscCurvevar1", text="Width")
col.prop(self, "MiscCurvevar2", text="Height")
if self.MiscCurveType == 2:
col.prop(self, "MiscCurvevar3", text="Corners")
elif self.ProfileType == 'Flower':
col.prop(self, "petals")
col.prop(self, "petalWidth")
col = box.column(align=True)
col.prop(self, "innerRadius")
col.prop(self, "outerRadius")
elif self.ProfileType == 'Star':
col.prop(self, "starPoints")
col.prop(self, "starTwist")
col = box.column(align=True)
col.prop(self, "innerRadius")
col.prop(self, "outerRadius")
elif self.ProfileType == 'Arc':
col.prop(self, "arcType")
col.prop(self, "arcSides")
col = box.column(align=True)
col.prop(self, "startAngle")
col.prop(self, "endAngle")
col = box.column(align=True)
col.prop(self, "innerRadius")
col.prop(self, "outerRadius")
elif self.ProfileType == 'Cogwheel':
col.prop(self, "teeth")
col.prop(self, "bevel")
col = box.column(align=True)
col.prop(self, "innerRadius")
col.prop(self, "middleRadius")
col.prop(self, "outerRadius")
elif self.ProfileType == 'Nsided':
col.prop(self, "Nsides")
col.prop(self, "outerRadius")
elif self.ProfileType == 'Splat':
col.prop(self, "splatSides")
col.prop(self, "outerRadius")
col = box.column(align=True)
col.prop(self, "splatScale")
col.prop(self, "seed")
col.prop(self, "basis")
elif self.ProfileType == 'Cycloid':
col.prop(self, "cycloType")
col.prop(self, "cycloPoints")
col = box.column(align=True)
col.prop(self, "cyclo_a")
col.prop(self, "cyclo_b")
if self.cycloType != 0:
col.prop(self, "cyclo_d")
elif self.ProfileType == 'Helix':
col.prop(self, "helixPoints")
col.prop(self, "helixHeight")
col.prop(self, "helixWidth")
col = box.column(align=True)
col.prop(self, "helixStart")
col.prop(self, "helixEnd")
col = box.column(align=True)
col.prop(self, "helix_a")
col.prop(self, "helix_b")
elif self.ProfileType == 'Noise':
col.prop(self, "noiseType")
col.prop(self, "noisePoints")
col.prop(self, "noiseLength")
col = box.column(align=True)
col.prop(self, "noiseSize")
col.prop(self, "noiseScaleX")
col.prop(self, "noiseScaleY")
col.prop(self, "noiseScaleZ")
col = box.column(align=True)
col.prop(self, "noiseOctaves")
col.prop(self, "noiseBasis")
col.prop(self, "noiseSeed")
row = layout.row()
row.prop(self, "shape", expand=True)
# output options
col = layout.column()
col.label(text="Output Curve Type:")
col.row().prop(self, "outputType", expand=True)
if self.outputType == 'NURBS':
col.prop(self, 'order_u')
elif self.outputType == 'BEZIER':
col.row().prop(self, 'handleType', expand=True)
col = layout.column()
col.row().prop(self, "use_cyclic_u", expand=True)
col = layout.column()
col.row().prop(self, "edit_mode", expand=True)
col = layout.column()
# AddObjectHelper props
col.prop(self, "align")
col.prop(self, "location")
col.prop(self, "rotation")
@classmethod
def poll(cls, context):
return context.scene is not None
def execute(self, context):
# turn off 'Enter Edit Mode'
use_enter_edit_mode = bpy.context.preferences.edit.use_enter_edit_mode
bpy.context.preferences.edit.use_enter_edit_mode = False
# main function
main(context, self)
if use_enter_edit_mode:
bpy.ops.object.mode_set(mode = 'EDIT')
# restore pre operator state
bpy.context.preferences.edit.use_enter_edit_mode = use_enter_edit_mode
if self.edit_mode:
bpy.ops.object.mode_set(mode = 'EDIT')
else:
bpy.ops.object.mode_set(mode = 'OBJECT')
return {'FINISHED'}
def invoke(self, context, event):
# deal with 2D - 3D curve differences
if self.ProfileType in ['Helix', 'Cycloid', 'Noise']:
self.shape = '3D'
else:
self.shape = '2D'
if self.ProfileType in ['Helix', 'Noise', 'Cycloid']:
self.use_cyclic_u = False
if self.ProfileType in ['Cycloid']:
if self.cycloType == 0:
self.use_cyclic_u = False
else:
self.use_cyclic_u = True
else:
if self.ProfileType == 'Arc' and self.arcType == 1:
self.use_cyclic_u = False
else:
self.use_cyclic_u = True
self.execute(context)
return {'FINISHED'}
# Register
classes = [
Curveaceous_galore
]
def register():
from bpy.utils import register_class
for cls in classes:
register_class(cls)
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
if __name__ == "__main__":
register()