Update add curve extra objects Re: T50943

This commit is contained in:
Brendon Murphy 2017-03-17 14:46:03 +11:00
parent f14b4f40c1
commit fcf5f2842a
Notes: blender-bot 2023-02-14 20:14:15 +01:00
Referenced by issue #50943, Update: Add Curve Extra Objects
Referenced by issue #37377, This addon adds a bevel and/or taper curve to the currently active curve.
Referenced by issue #37299, Adds curled curves for use in scrollwork or flourish designs
Referenced by issue #36460, Add a Braided Torus
9 changed files with 3015 additions and 127 deletions

View File

@ -17,6 +17,7 @@
# ##### END GPL LICENSE BLOCK #####
# Contributed to by
# testscreenings, Alejandro Omar Chocano Vasquez, Jimmy Hazevoet, meta-androcto #
# Cmomoney, Jared Forsyth, Adam Newgas, Spivak Vladimir
bl_info = {
"name": "Extra Objects",
@ -37,12 +38,22 @@ if "bpy" in locals():
importlib.reload(add_curve_spirals)
importlib.reload(add_curve_torus_knots)
importlib.reload(add_surface_plane_cone)
importlib.reload(add_curve_curly)
importlib.reload(beveltaper_curve)
importlib.reload(add_curve_celtic_links)
importlib.reload(add_curve_braid)
importlib.reload(add_curve_simple)
else:
from . import add_curve_aceous_galore
from . import add_curve_spirals
from . import add_curve_torus_knots
from . import add_surface_plane_cone
from . import add_curve_curly
from . import beveltaper_curve
from . import add_curve_celtic_links
from . import add_curve_braid
from . import add_curve_simple
import bpy
from bpy.types import Menu, AddonPreferences
@ -131,24 +142,22 @@ class CurveExtraObjectsAddonPreferences(AddonPreferences):
else:
layout.prop(self, "update_spiral_presets")
# TODO check if this is even used.
class INFO_MT_curve_extras_add(Menu):
class INFO_MT_curve_knots_add1(bpy.types.Menu):
# Define the "Extras" menu
bl_idname = "curve_extra_objects_add"
bl_label = "Extra Objects"
bl_idname = "curve_knots_add"
bl_label = "Plants"
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator_menu_enum("mesh.curveaceous_galore",
"ProfileType",
)
layout.operator_menu_enum("curve.spirals",
"spiral_type",
icon='FORCE_VORTEX')
layout.operator("curve.torus_knot_plus",
text="Torus Knot Plus")
text="Torus Knot Plus")
layout.operator("curve.celtic_links",
text="Celtic Links")
layout.operator("mesh.add_braid",
text="Braid Knot")
# Define "Extras" menus
def menu_func(self, context):
@ -156,14 +165,19 @@ def menu_func(self, context):
# fix in D2142 will allow to work in EDIT_CURVE
return None
layout = self.layout
layout.separator()
layout.operator_menu_enum("mesh.curveaceous_galore",
"ProfileType",
)
icon='CURVE_DATA')
layout.operator_menu_enum("curve.spirals",
"spiral_type",
icon='FORCE_VORTEX')
layout.operator("curve.torus_knot_plus", text="Torus Knot Plus")
icon='CURVE_DATA')
layout.separator()
layout.menu("curve_knots_add", text="Knots", icon='CURVE_DATA')
layout.separator()
layout.operator("curve.curlycurve", text="Curly Curve", icon='CURVE_DATA')
layout.menu("OBJECT_MT_bevel_taper_curve_menu", text="Bevel/Taper", icon='CURVE_DATA')
def menu_surface(self, context):
layout = self.layout
@ -177,6 +191,7 @@ def menu_surface(self, context):
self.layout.operator("object.add_surface_plane", text="Plane", icon="MOD_CURVE")
def register():
add_curve_simple.register()
bpy.utils.register_module(__name__)
# Add "Extras" menu to the "Add Curve" menu
@ -185,12 +200,14 @@ def register():
bpy.types.INFO_MT_surface_add.append(menu_surface)
def unregister():
bpy.utils.unregister_module(__name__)
add_curve_simple.unregister()
# Remove "Extras" menu from the "Add Curve" menu.
bpy.types.INFO_MT_curve_add.remove(menu_func)
# Remove "Extras" menu from the "Add Surface" menu.
bpy.types.INFO_MT_surface_add.remove(menu_surface)
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()

View File

@ -20,7 +20,7 @@ bl_info = {
"name": "Curveaceous Galore!",
"author": "Jimmy Hazevoet, testscreenings",
"version": (0, 2),
"blender": (2, 59, 0),
"blender": (2, 59),
"location": "View3D > Add > Curve",
"description": "Adds many different types of Curves",
"warning": "", # used for warning icon and text in addons panel
@ -193,15 +193,52 @@ def ProfileCurve(type=0, a=0.25, b=0.25):
return newpoints
# ------------------------------------------------------------
# 2DCurve: Miscellaneous.: Diamond, Arrow1, Arrow2, Square, ....
def MiscCurve(type=1, a=1.0, b=0.5, c=1.0):
# 2DCurve: Arrows
def ArrowCurve(type=1, a=1.0, b=0.5):
"""
MiscCurve( type=1, a=1.0, b=0.5, c=1.0 )
ArrowCurve( type=1, a=1.0, b=0.5, c=1.0 )
Create miscellaneous curves
Create arrow curves
Parameters:
type - select type, Diamond, Arrow1, Arrow2, Square
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 curves
Parameters:
type - select type, Square, Rounded square 1, Rounded square 2
(type=int)
a - a scaling parameter
(type=float)
@ -209,45 +246,28 @@ def MiscCurve(type=1, a=1.0, b=0.5, c=1.0):
(type=float)
c - c scaling parameter
(type=float)
doesn't seem to do anything
Returns:
a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
(type=list)
"""
newpoints = []
a *= 0.5
b *= 0.5
if type == 1:
# diamond:
newpoints = [[0.0, b, 0.0], [a, 0.0, 0.0], [0.0, -b, 0.0], [-a, 0.0, 0.0]]
elif type == 2:
# Arrow1:
newpoints = [[-a, b, 0.0], [a, 0.0, 0.0], [-a, -b, 0.0], [0.0, 0.0, 0.0]]
elif type == 3:
# Arrow2:
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 == 4:
# Rounded square:
# 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 == 5:
elif type == 2:
# Rounded Rectangle II:
newpoints = []
x = a / 2
y = b / 2
r = c / 2
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])
@ -262,9 +282,8 @@ def MiscCurve(type=1, a=1.0, b=0.5, c=1.0):
newpoints.append([x, y, 0])
newpoints.append([x, -y, 0])
newpoints.append([-x, -y, 0])
else:
# Square:
# Rectangle:
newpoints = [[-a, b, 0.0], [a, b, 0.0], [a, -b, 0.0], [-a, -b, 0.0]]
return newpoints
@ -567,47 +586,116 @@ def HelixCurve(number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0
i += 1
return newpoints
# ------------------------------------------------------------ ?
# 3DCurve: Cycloid: Cycloid, Epicycloid, Hypocycloid
def CycloidCurve(number=24, length=2.0, type=0, a=1.0, b=1.0, startangle=0.0, endangle=360.0):
"""
CycloidCurve( number=24, length=2.0, type=0, a=1.0, b=1.0, startangle=0.0, endangle=360.0 )
#------------------------------------------------------------
# Cycloid curve
Create a Cycloid, Epicycloid or Hypocycloid 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)
length - length of curve
type - types: Cycloid, Hypocycloid, Epicycloid
(type=int)
R = Radius a scaling parameter
(type=float)
type - types: Cycloid, Epicycloid, Hypocycloid
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)*a
x = (t-sin(t)*b)
y = (1-cos(t)*b)
z = 0
newpoints.append([x,y,z])
i+=1
return newpoints
#------------------------------------------------------------
# 3D Noise curve
def NoiseCurve(number=100, length=2.0, scale=1.0, octaves=6, basis=1, seed=0, type=0):
"""
NoiseCurve( number=100, length=2.0, scale=1.0, octaves=2, basis=1, seed=0, type=1 )
Create noise curve
Parameters:
number - number of points
(type=int)
length - curve length
(type=float)
scale - noise scale
(type=float)
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)
"""
rand = randnum(-100,100,seed)
newpoints = []
angle = (2.0/360.0)*(endangle-startangle)
step = angle/(number-1)
#h = height/angle
d = length
start = (startangle*2.0/360.0)
a /= angle
step = (length/number)
i = 0
if type == 0: # Epitrochoid
if type == 1:
# noise knot
while i < number:
t = (i*step+start)
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 # ( t * h ) -h*start
newpoints.append([x, y, z])
i += 1
t = ((i*step)+rand)
v = vTurbNoise(t,t,t, scale, 1.0, octaves, 0, basis, seed)
newpoints.append([v[0], v[1], v[2]])
i+=1
else:
newpoints = [[-1, -1, 0], [-1, 1, 0], [1, 1, 0], [1, -1, 0]]
# noise linear
while i < number:
t = i*step
tt = t+rand
v = vTurbNoise(t,t,t, scale, 1.0, octaves, 0, basis, seed)
x = t
y = v[1]
z = v[2]
newpoints.append([x,y,z])
i+=1
return newpoints
# ------------------------------------------------------------
# calculates the matrix for the new object
# depending on user pref
@ -712,8 +800,12 @@ def main(context, self, align_matrix):
verts = ProfileCurve(self.ProfileCurveType,
self.ProfileCurvevar1,
self.ProfileCurvevar2)
if proType == 'Miscellaneous':
verts = MiscCurve(self.MiscCurveType,
if proType == 'Arrow':
verts = ArrowCurve(self.MiscCurveType,
self.MiscCurvevar1,
self.MiscCurvevar2)
if proType == 'Rectangle':
verts = RectCurve(self.MiscCurveType,
self.MiscCurvevar1,
self.MiscCurvevar2,
self.MiscCurvevar3)
@ -759,12 +851,18 @@ def main(context, self, align_matrix):
self.helix_b)
if proType == 'Cycloid':
verts = CycloidCurve(self.cycloPoints,
self.cyclo_d,
self.cycloType,
self.cyclo_a,
self.cyclo_b,
self.cycloStart,
self.cycloEnd)
self.cyclo_d)
if proType == 'Noise':
verts = NoiseCurve(self.noisePoints,
self.noiseLength,
self.noiseScale,
self.noiseOctaves,
self.noiseBasis,
self.noiseSeed,
self.noiseType)
# turn verts into array
vertArray = vertsToPoints(verts, splineType)
@ -777,7 +875,7 @@ def main(context, self, align_matrix):
class Curveaceous_galore(Operator):
"""Add many types of curves"""
bl_idname = "mesh.curveaceous_galore"
bl_label = "Curve Profiles"
bl_label = "2D Profiles"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
# align_matrix for the invoke
@ -786,7 +884,8 @@ class Curveaceous_galore(Operator):
# general properties
ProfileTypes = [
('Profile', 'Profile', 'Profile'),
('Miscellaneous', 'Miscellaneous', 'Miscellaneous'),
('Arrow', 'Arrow', 'Arrow'),
('Rectangle', 'Rectangle', 'Rectangle'),
('Flower', 'Flower', 'Flower'),
('Star', 'Star', 'Star'),
('Arc', 'Arc', 'Arc'),
@ -794,7 +893,8 @@ class Curveaceous_galore(Operator):
('Nsided', 'Nsided', 'Nsided'),
('Splat', 'Splat', 'Splat'),
('Cycloid', 'Cycloid', 'Cycloid'),
('Helix', 'Helix (3D)', 'Helix')]
('Helix', 'Helix (3D)', 'Helix'),
('Noise', 'Noise (3D)', 'Noise')]
ProfileType = EnumProperty(name="Type",
description="Form of Curve to create",
items=ProfileTypes)
@ -844,22 +944,22 @@ class Curveaceous_galore(Operator):
default=0.25,
description="var2 of ProfileCurve")
# MiscCurve properties
# Arrow, Rectangle, MiscCurve properties
MiscCurveType = IntProperty(name="Type",
min=1, soft_min=1,
max=6, soft_max=6,
default=1,
description="Type of MiscCurve")
min=0, soft_min=0,
max=3, soft_max=3,
default=0,
description="Type of Curve")
MiscCurvevar1 = FloatProperty(name="var_1",
default=1.0,
description="var1 of MiscCurve")
description="var1 of Curve")
MiscCurvevar2 = FloatProperty(name="var_2",
default=0.5,
description="var2 of MiscCurve")
description="var2 of Curve")
MiscCurvevar3 = FloatProperty(name="var_3",
default=0.1,
min=0, soft_min=0,
description="var3 of MiscCurve")
description="var3 of Curve")
# Common properties
innerRadius = FloatProperty(name="Inner radius",
@ -977,28 +1077,55 @@ class Curveaceous_galore(Operator):
default=100,
min=3, soft_min=3,
description="Resolution")
cyclo_d = FloatProperty(name="var_3",
default=1.5,
description="Cycloid var3")
cycloType = IntProperty(name="Type",
default=0,
min=0, soft_min=0,
max=0, soft_max=0,
description="resolution")
cyclo_a = FloatProperty(name="var_1",
default=5.0,
max=2, soft_max=2,
description="Type: Cycloid , Hypocycloid / Hypotrochoid , Epicycloid / Epitrochoid")
cyclo_a = FloatProperty(name="R",
default=4.0,
min=0.01, soft_min=0.01,
description="Cycloid var1")
cyclo_b = FloatProperty(name="var_2",
default=0.5,
description="Cycloid: R radius a")
cyclo_b = FloatProperty(name="r",
default=1.0,
min=0.01, soft_min=0.01,
description="Cycloid var2")
cycloStart = FloatProperty(name="Start angle",
default=0.0,
description="Cycloid start angle")
cycloEnd = FloatProperty(name="End angle",
default=360.0,
description="Cycloid end angle")
description="Cycloid: r radius b")
cyclo_d = FloatProperty(name="d",
default=1.0,
description="Cycloid: d distance")
# Noise properties
noisePoints = IntProperty(name="Resolution",
default=100,
min=3, soft_min=3,
description="Resolution")
noiseLength = FloatProperty(name="Length",
default=2.0,
min=0.01, soft_min=0.01,
description="Curve Length")
noiseScale = FloatProperty(name="Noise scale",
default=1.0,
min=0.0001, soft_min=0.0001,
description="Noise scale")
noiseOctaves = IntProperty(name="Octaves",
default=2,
min=0, soft_min=0,
max=16, soft_max=16,
description="Basis")
noiseBasis = IntProperty(name="Basis",
default=0,
min=0, soft_min=0,
max=14, soft_max=14,
description="Basis")
noiseSeed = IntProperty(name="Seed",
default=1,
min=0, soft_min=0,
description="Random Seed")
noiseType = IntProperty(name="Type",
default=0,
min=0, soft_min=0,
max=1, soft_max=1,
description="Noise curve type: Linear or Knot")
##### DRAW #####
def draw(self, context):
@ -1016,12 +1143,17 @@ class Curveaceous_galore(Operator):
box.prop(self, 'ProfileCurvevar1')
box.prop(self, 'ProfileCurvevar2')
elif self.ProfileType == 'Miscellaneous':
elif self.ProfileType == 'Arrow':
box.prop(self, 'MiscCurveType')
box.prop(self, 'MiscCurvevar1', text='Height')
box.prop(self, 'MiscCurvevar2', text='Width')
elif self.ProfileType == 'Rectangle':
box.prop(self, 'MiscCurveType')
box.prop(self, 'MiscCurvevar1', text='Width')
box.prop(self, 'MiscCurvevar2', text='Height')
if self.MiscCurveType == 5:
box.prop(self, 'MiscCurvevar3', text='Rounded')
if self.MiscCurveType == 2:
box.prop(self, 'MiscCurvevar3', text='Corners')
elif self.ProfileType == 'Flower':
box.prop(self, 'petals')
@ -1037,10 +1169,10 @@ class Curveaceous_galore(Operator):
elif self.ProfileType == 'Arc':
box.prop(self, 'arcSides')
box.prop(self, 'arcType') # has only one Type?
box.prop(self, 'arcType')
box.prop(self, 'startAngle')
box.prop(self, 'endAngle')
box.prop(self, 'innerRadius') # doesn't seem to do anything
box.prop(self, 'innerRadius')
box.prop(self, 'outerRadius')
elif self.ProfileType == 'Cogwheel':
@ -1052,7 +1184,7 @@ class Curveaceous_galore(Operator):
elif self.ProfileType == 'Nsided':
box.prop(self, 'Nsides')
box.prop(self, 'outerRadius', text='Radius')
box.prop(self, 'outerRadius')
elif self.ProfileType == 'Splat':
box.prop(self, 'splatSides')
@ -1072,34 +1204,30 @@ class Curveaceous_galore(Operator):
elif self.ProfileType == 'Cycloid':
box.prop(self, 'cycloPoints')
# box.prop(self, 'cycloType') # needs the other types first
box.prop(self, 'cycloStart')
box.prop(self, 'cycloEnd')
box.prop(self, 'cycloType')
box.prop(self, 'cyclo_a')
box.prop(self, 'cyclo_b')
box.prop(self, 'cyclo_d')
elif self.ProfileType == 'Noise':
box.prop(self, 'noisePoints')
box.prop(self, 'noiseType')
box.prop(self, 'noiseLength')
box.prop(self, 'noiseScale')
box.prop(self, 'noiseOctaves')
box.prop(self, 'noiseBasis')
box.prop(self, 'noiseSeed')
col = layout.column()
col.label(text="Output Curve Type:")
col.row().prop(self, 'outputType', expand=True)
col.label(text="Curve Options:")
# output options
box = layout.box()
if self.outputType == 'NURBS':
box.row().prop(self, 'shape', expand=True)
#box.prop(self, 'use_cyclic_u')
#box.prop(self, 'endp_u')
box.prop(self, 'order_u')
elif self.outputType == 'POLY':
box.row().prop(self, 'shape', expand=True)
#box.prop(self, 'use_cyclic_u')
elif self.outputType == 'BEZIER':
box.row().prop(self, 'shape', expand=True)
box.row().prop(self, 'handleType', expand=True)
#box.prop(self, 'use_cyclic_u')
##### POLL #####
@classmethod
@ -1113,13 +1241,18 @@ class Curveaceous_galore(Operator):
context.user_preferences.edit.use_global_undo = False
# deal with 2D - 3D curve differences
if self.ProfileType in ['Helix', 'Cycloid']:
if self.ProfileType in ['Helix', 'Cycloid', 'Noise']:
self.shape = '3D'
# else:
# self.shape = '2D' # someone decide if we want this
else:
self.shape = '2D'
if self.ProfileType in ['Helix']:
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:
self.use_cyclic_u = True

View File

@ -0,0 +1,88 @@
import bpy
from bpy.props import (FloatProperty,
FloatVectorProperty,
IntProperty,
BoolProperty,
StringProperty)
from .bpybraid import awesome_braid, defaultCircle
'''
bl_info = {
"name": "New Braid",
"author": "Jared Forsyth <github.com/jaredly>",
"version": (1, 0),
"blender": (2, 6, 0),
"location": "View3D > Add > Mesh > New Braid",
"description": "Adds a new Braid",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Add Mesh"}
'''
from bpy.types import Operator
class Braid(Operator):
'''Add a Braid'''
bl_idname = 'mesh.add_braid'
bl_label = 'New Braid'
bl_description = 'Create a new braid'
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
strands = IntProperty(name='strands', min=2, max=100, default=3)
sides = IntProperty(name='sides', min=2, max=100, default=5)
radius = FloatProperty(name='radius', default=1)
thickness = FloatProperty(name='thickness', default=.3)
strandsize = FloatProperty(name='strandsize', default=.3, min=.01, max=10)
width = FloatProperty(name='width', default=.2)
resolution = IntProperty(name='resolution', min=1, default=2, max=100)
pointy = BoolProperty(name='pointy', default=False)
def execute(self, context):
circle = defaultCircle(self.strandsize)
context.scene.objects.link(circle)
braid = awesome_braid(self.strands, self.sides,
bevel=circle.name,
pointy=self.pointy,
radius=self.radius,
mr=self.thickness,
mz=self.width,
resolution=self.resolution)
base = context.scene.objects.link(braid)
for ob in context.scene.objects:
ob.select = False
base.select = True
context.scene.objects.active = braid
return {'FINISHED'}
def draw(self, context):
layout = self.layout
box = layout.box()
box.prop(self, 'strands')
box.prop(self, 'sides')
box.prop(self, 'radius')
box.prop(self, 'thickness')
box.prop(self, 'strandsize')
box.prop(self, 'width')
box.prop(self, 'resolution')
box.prop(self, 'pointy')
def add_object_button(self, context):
self.layout.operator(Braid.bl_idname, text="Add Braid", icon='PLUGIN')
def register():
bpy.utils.register_class(Braid)
bpy.types.INFO_MT_mesh_add.append(add_object_button)
def unregister():
bpy.utils.unregister_class(Braid)
bpy.types.INFO_MT_mesh_add.remove(add_object_button)
if __name__ == "__main__":
register()

View File

@ -0,0 +1,249 @@
# Blender plugin for generating celtic knot curves from 3d meshes
# See README for more information
#
# The MIT License (MIT)
#
# Copyright (c) 2013 Adam Newgas
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
bl_info = {
"name": "Celtic Knot",
"description": "",
"author": "Adam Newgas",
"version": (0, 1, 1),
"blender": (2, 74, 0),
"location": "View3D > Add > Curve",
"warning": "",
"wiki_url": "https://github.com/BorisTheBrave/celtic-knot/wiki",
"category": "Add Curve"}
import bpy
import bmesh
from collections import defaultdict
from mathutils import Vector
from math import pi, sin, cos
class CelticKnotOperator(bpy.types.Operator):
bl_idname = "curve.celtic_links"
bl_label = "Celtic Links"
bl_description = 'Select low poly Mesh Object to cover with Knitted Links'
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
weave_up = bpy.props.FloatProperty(name="Weave Up",
description="Distance to shift curve upwards over knots",
subtype="DISTANCE",
unit="LENGTH")
weave_down = bpy.props.FloatProperty(name="Weave Down",
description="Distance to shift curve downward under knots",
subtype="DISTANCE",
unit="LENGTH")
handle_types = [("ALIGNED", "Aligned", "Points at a fixed crossing angle"),
("AUTO", "Auto", "Automatic control points")]
handle_type = bpy.props.EnumProperty(items=handle_types,
name="Handle Type",
description="Controls what type the bezier control points use",
default="AUTO")
crossing_angle = bpy.props.FloatProperty(name="Crossing Angle",
description="Aligned only: the angle between curves in a knot",
default=pi / 4,
min=0, max=pi / 2,
subtype="ANGLE",
unit="ROTATION")
crossing_strength = bpy.props.FloatProperty(name="Crossing Strength",
description="Aligned only: strenth of bezier control points",
soft_min=0,
subtype="DISTANCE",
unit="LENGTH")
handle_type_map = {"AUTO": "AUTOMATIC", "ALIGNED": "ALIGNED"}
geo_bDepth = bpy.props.FloatProperty(
name="Bevel Depth",
default=0.04,
min=0, soft_min=0,
description="Bevel Depth",
)
@classmethod
def poll(cls, context):
ob = context.active_object
# return True
return ((ob is not None) and
(ob.mode == "OBJECT") and
(ob.type == "MESH") and
(context.mode == "OBJECT"))
def execute(self, context):
# Cache some values
s = sin(self.crossing_angle) * self.crossing_strength
c = cos(self.crossing_angle) * self.crossing_strength
handle_type = self.handle_type
weave_up = self.weave_up
weave_down = self.weave_down
# Create the new object
orig_obj = obj = context.active_object
curve = bpy.data.curves.new("Celtic", "CURVE")
curve.dimensions = "3D"
curve.twist_mode = "MINIMUM"
curve.fill_mode = "FULL"
curve.bevel_depth = 0.015
curve.extrude = 0.003
curve.bevel_resolution = 4
obj = obj.data
midpoints = []
# Compute all the midpoints of each edge
for e in obj.edges.values():
v1 = obj.vertices[e.vertices[0]]
v2 = obj.vertices[e.vertices[1]]
m = (v1.co + v2.co) / 2.0
midpoints.append(m)
bm = bmesh.new()
bm.from_mesh(obj)
# Stores which loops the curve has already passed through
loops_entered = defaultdict(lambda: False)
loops_exited = defaultdict(lambda: False)
# Loops on the boundary of a surface
def ignorable_loop(loop):
return len(loop.link_loops) == 0
# Starting at loop, build a curve one vertex at a time
# until we start where we came from
# Forward means that for any two edges the loop crosses
# sharing a face, it is passing through in clockwise order
# else anticlockwise
def make_loop(loop, forward):
current_spline = curve.splines.new("BEZIER")
current_spline.use_cyclic_u = True
first = True
# Data for the spline
# It's faster to store in an array and load into blender
# at once
cos = []
handle_lefts = []
handle_rights = []
while True:
if forward:
if loops_exited[loop]:
break
loops_exited[loop] = True
# Follow the face around, ignoring boundary edges
while True:
loop = loop.link_loop_next
if not ignorable_loop(loop):
break
assert loops_entered[loop] == False
loops_entered[loop] = True
v = loop.vert.index
prev_loop = loop
# Find next radial loop
assert loop.link_loops[0] != loop
loop = loop.link_loops[0]
forward = loop.vert.index == v
else:
if loops_entered[loop]:
break
loops_entered[loop] = True
# Follow the face around, ignoring boundary edges
while True:
v = loop.vert.index
loop = loop.link_loop_prev
if not ignorable_loop(loop):
break
assert loops_exited[loop] == False
loops_exited[loop] = True
prev_loop = loop
# Find next radial loop
assert loop.link_loops[-1] != loop
loop = loop.link_loops[-1]
forward = loop.vert.index == v
if not first:
current_spline.bezier_points.add()
first = False
midpoint = midpoints[loop.edge.index]
normal = loop.calc_normal() + prev_loop.calc_normal()
normal.normalize()
offset = weave_up if forward else weave_down
midpoint = midpoint + offset * normal
cos.extend(midpoint)
if handle_type != "AUTO":
tangent = loop.link_loop_next.vert.co - loop.vert.co
tangent.normalize()
binormal = normal.cross(tangent).normalized()
if not forward:
tangent *= -1
s_binormal = s * binormal
c_tangent = c * tangent
handle_left = midpoint - s_binormal - c_tangent
handle_right = midpoint + s_binormal + c_tangent
handle_lefts.extend(handle_left)
handle_rights.extend(handle_right)
points = current_spline.bezier_points
points.foreach_set("co", cos)
if handle_type != "AUTO":
points.foreach_set("handle_left", handle_lefts)
points.foreach_set("handle_right", handle_rights)
# Attempt to start a loop at each untouched loop in the entire mesh
for face in bm.faces:
for loop in face.loops:
if ignorable_loop(loop):
continue
if not loops_exited[loop]:
make_loop(loop, True)
if not loops_entered[loop]:
make_loop(loop, False)
# Create an object from the curve
from bpy_extras import object_utils
object_utils.object_data_add(context, curve, operator=None)
# Set the handle type (this is faster than setting it pointwise)
bpy.ops.object.editmode_toggle()
bpy.ops.curve.select_all(action="SELECT")
bpy.ops.curve.handle_type_set(type=self.handle_type_map[handle_type])
# Some blender versions lack the default
bpy.ops.curve.radius_set(radius=1.0)
bpy.ops.object.editmode_toggle()
# Restore active selection
curve_obj = context.active_object
context.scene.objects.active = orig_obj
# If thick, then give it a bevel_object and convert to mesh
return {'FINISHED'}
def menu_func(self, context):
self.layout.operator(CelticKnotOperator.bl_idname,
text="Celtic Knot From Mesh",
icon='PLUGIN')
def register():
bpy.utils.register_module(__name__)
bpy.types.INFO_MT_curve_add.append(menu_func)
def unregister():
bpy.types.INFO_MT_curve_add.remove(menu_func)
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()

View File

@ -0,0 +1,386 @@
bl_info = {
"name": "Curly Curves",
"author": "Cmomoney",
"version": (1, 17),
"blender": (2, 69, 0),
"location": "View3D > Add > Curve > Curly Curve",
"description": "Adds a new Curly Curve",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Curve/Curly_Curves",
"tracker_url": "https://projects.blender.org/tracker/index.php?func=detail&aid=37299&group_id=153&atid=467",
"category": "Add Curve"}
import bpy
from bpy.types import Operator
from bpy.props import *
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector
def add_type6(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[0.047131 * scale_x, 0.065832 * scale_y,
0.0, 0.010396 * scale_x, -0.186771 * scale_y,
0.0, 0.076107 * scale_x, 0.19414 * scale_y,
0.0, 0.0 * scale_x, -1.0 * scale_y, 0.0],
[0.451396 * scale_x, -0.48376 * scale_y,
0.0, 0.433623 * scale_x, -0.587557 * scale_y,
0.0, 0.525837 * scale_x, -0.423363 * scale_y,
0.0, 0.15115 * scale_x, -0.704345 * scale_y, 0.0]]
lhandles = [[(-0.067558 * scale_x, 0.078418 * scale_y, 0.0),
(0.168759 * scale_x, -0.154334 * scale_y, 0.0),
(-0.236823 * scale_x, 0.262436 * scale_y, 0.0),
(0.233116 * scale_x, -0.596115 * scale_y, 0.0)],
[(0.498001 * scale_x, -0.493434 * scale_y, 0.0),
(0.375618 * scale_x, -0.55465 * scale_y, 0.0),
(0.634373 * scale_x, -0.49873 * scale_y, 0.0),
(0.225277 * scale_x, -0.526814 * scale_y, 0.0)]]
rhandles = [[(0.161825 * scale_x, 0.053245 * scale_y, 0.0),
(-0.262003 * scale_x, -0.242566 * scale_y, 0.0),
(0.519691 * scale_x, 0.097329 * scale_y, 0.0),
(-0.233116 * scale_x, -1.403885 * scale_y, 0.0)],
[(0.404788 * scale_x, -0.474085 * scale_y, 0.0),
(0.533397 * scale_x, -0.644158 * scale_y, 0.0),
(0.371983 * scale_x, -0.316529 * scale_y, 0.0),
(0.077022 * scale_x, -0.881876 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type5(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[0.047131 * scale_x, 0.065832 * scale_y, 0.0, 0.010396 * scale_x, -0.186771 * scale_y,
0.0, 0.076107 * scale_x, 0.19414 * scale_y, 0.0, 0.0 * scale_x, -1.0 * scale_y, 0.0],
[0.086336 * scale_x, -0.377611 * scale_y, 0.0, 0.022417 * scale_x, -0.461301 * scale_y, 0.0,
0.079885 * scale_x, -0.281968 * scale_y, 0.0, 0.129212 * scale_x, -0.747702 * scale_y, 0.0]]
lhandles = [[(-0.067558 * scale_x, 0.078419 * scale_y, 0.0),
(0.168759 * scale_x, -0.154335 * scale_y, 0.0),
(-0.236823 * scale_x, 0.262436 * scale_y, 0.0),
(0.233116 * scale_x, -0.596115 * scale_y, 0.0)],
[(0.047518 * scale_x, -0.350065 * scale_y, 0.0),
(0.086012 * scale_x, -0.481379 * scale_y, 0.0),
(-0.049213 * scale_x, -0.253793 * scale_y, 0.0),
(0.208763 * scale_x, -0.572534 * scale_y, 0.0)]]
rhandles = [[(0.161825 * scale_x, 0.053245 * scale_y, 0.0),
(-0.262003 * scale_x, -0.242566 * scale_y, 0.0),
(0.519691 * scale_x, 0.097329 * scale_y, 0.0),
(-0.233116 * scale_x, -1.403885 * scale_y, 0.0)],
[(0.125156 * scale_x, -0.405159 * scale_y, 0.0),
(-0.086972 * scale_x, -0.426766 * scale_y, 0.0),
(0.262886 * scale_x, -0.321908 * scale_y, 0.0),
(0.049661 * scale_x, -0.92287 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type8(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.850431 * scale_x, -0.009091 * scale_y,
0.0, -0.818807 * scale_x, -0.130518 * scale_y,
0.0, -0.944931 * scale_x, 0.055065 * scale_y,
0.0, -0.393355 * scale_x, -0.035521 * scale_y,
0.0, 0.0 * scale_x, 0.348298 * scale_y,
0.0, 0.393355 * scale_x, -0.035521 * scale_y,
0.0, 0.978373 * scale_x, 0.185638 * scale_y,
0.0, 0.771617 * scale_x, 0.272819 * scale_y,
0.0, 0.864179 * scale_x, 0.188103 * scale_y, 0.0]]
lhandles = [[(-0.90478 * scale_x, -0.025302 * scale_y, 0.0),
(-0.753279 * scale_x, -0.085571 * scale_y, 0.0),
(-1.06406 * scale_x, -0.047879 * scale_y, 0.0),
(-0.622217 * scale_x, -0.022501 * scale_y, 0.0),
(0.181 * scale_x, 0.34879 * scale_y, 0.0),
(-0.101464 * scale_x, -0.063669 * scale_y, 0.0),
(0.933064 * scale_x, 0.03001 * scale_y, 0.0),
(0.82418 * scale_x, 0.39899 * scale_y, 0.0),
(0.827377 * scale_x, 0.144945 * scale_y, 0.0)]]
rhandles = [[(-0.796079 * scale_x, 0.007121 * scale_y, 0.0),
(-0.931521 * scale_x, -0.207832 * scale_y, 0.0),
(-0.822288 * scale_x, 0.161045 * scale_y, 0.0),
(0.101464 * scale_x, -0.063671 * scale_y, 0.0),
(-0.181193 * scale_x, 0.347805 * scale_y, 0.0),
(0.622217 * scale_x, -0.022502 * scale_y, 0.0),
(1.022383 * scale_x, 0.336808 * scale_y, 0.0),
(0.741059 * scale_x, 0.199468 * scale_y, 0.0),
(0.900979 * scale_x, 0.231258 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type3(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.78652 * scale_x, -0.070157 * scale_y,
0.0, -0.697972 * scale_x, -0.247246 * scale_y,
0.0, -0.953385 * scale_x, -0.002048 * scale_y,
0.0, 0.0 * scale_x, 0.0 * scale_y,
0.0, 0.917448 * scale_x, 0.065788 * scale_y,
0.0, 0.448535 * scale_x, 0.515947 * scale_y,
0.0, 0.6111 * scale_x, 0.190831 * scale_y, 0.0]]
lhandles = [[(-0.86511 * scale_x, -0.112965 * scale_y, 0.0),
(-0.61153 * scale_x, -0.156423 * scale_y, 0.0),
(-1.103589 * scale_x, -0.199934 * scale_y, 0.0),
(-0.446315 * scale_x, 0.135163 * scale_y, 0.0),
(0.669383 * scale_x, -0.254463 * scale_y, 0.0),
(0.721512 * scale_x, 0.802759 * scale_y, 0.0),
(0.466815 * scale_x, 0.112232 * scale_y, 0.0)]]
rhandles = [[(-0.707927 * scale_x, -0.027348 * scale_y, 0.0),
(-0.846662 * scale_x, -0.40347 * scale_y, 0.0),
(-0.79875 * scale_x, 0.201677 * scale_y, 0.0),
(0.446315 * scale_x, -0.135163 * scale_y, 0.0),
(1.196752 * scale_x, 0.42637 * scale_y, 0.0),
(0.289834 * scale_x, 0.349204 * scale_y, 0.0),
(0.755381 * scale_x, 0.269428 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type2(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.719632 * scale_x, -0.08781 * scale_y,
0.0, -0.605138 * scale_x, -0.31612 * scale_y,
0.0, -0.935392 * scale_x, 0.0, 0.0, 0.0, 0.0,
0.0, 0.935392 * scale_x, 0.0, 0.0, 0.605138 * scale_x,
-0.316119 * scale_y, 0.0, 0.719632 * scale_x, -0.08781 * scale_y, 0.0]]
lhandles = [[(-0.82125 * scale_x, -0.142999 * scale_y, 0.0),
(-0.493366 * scale_x, -0.199027 * scale_y, 0.0),
(-1.129601 * scale_x, -0.25513 * scale_y, 0.0),
(-0.467584 * scale_x, 0.00044 * scale_y, 0.0),
(0.735439 * scale_x, 0.262646 * scale_y, 0.0),
(0.797395 * scale_x, -0.517531 * scale_y, 0.0),
(0.618012 * scale_x, -0.032614 * scale_y, 0.0)]]
rhandles = [[(-0.618009 * scale_x, -0.032618 * scale_y, 0.0),
(-0.797396 * scale_x, -0.517532 * scale_y, 0.0),
(-0.735445 * scale_x, 0.262669 * scale_y, 0.0),
(0.468041 * scale_x, -0.00044 * scale_y, 0.0),
(1.129616 * scale_x, -0.255119 * scale_y, 0.0),
(0.493365 * scale_x, -0.199025 * scale_y, 0.0),
(0.821249 * scale_x, -0.143004 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type10(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.999637 * scale_x, 0.000348 * scale_y,
0.0, 0.259532 * scale_x, -0.017841 * scale_y,
0.0, 0.482303 * scale_x, 0.780429 * scale_y,
0.0, 0.573183 * scale_x, 0.506898 * scale_y, 0.0],
[0.259532 * scale_x, -0.017841 * scale_y,
0.0, 0.554919 * scale_x, -0.140918 * scale_y,
0.0, 0.752264 * scale_x, -0.819275 * scale_y,
0.0, 0.824152 * scale_x, -0.514881 * scale_y, 0.0]]
lhandles = [[(-1.258333 * scale_x, -0.258348 * scale_y, 0.0),
(-0.240006 * scale_x, -0.15259 * scale_y, 0.0),
(0.79037 * scale_x, 0.857575 * scale_y, 0.0),
(0.376782 * scale_x, 0.430157 * scale_y, 0.0)],
[(0.224917 * scale_x, -0.010936 * scale_y, 0.0),
(0.514858 * scale_x, -0.122809 * scale_y, 0.0),
(1.057957 * scale_x, -0.886925 * scale_y, 0.0),
(0.61945 * scale_x, -0.464285 * scale_y, 0.0)]]
rhandles = [[(-0.74094 * scale_x, 0.259045 * scale_y, 0.0),
(0.768844 * scale_x, 0.119545 * scale_y, 0.0),
(0.279083 * scale_x, 0.729538 * scale_y, 0.0),
(0.643716 * scale_x, 0.534458 * scale_y, 0.0)],
[(0.294147 * scale_x, -0.024746 * scale_y, 0.0),
(1.03646 * scale_x, -0.358598 * scale_y, 0.0),
(0.547718 * scale_x, -0.774008 * scale_y, 0.0),
(0.897665 * scale_x, -0.533051 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type9(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[0.260968 * scale_x, -0.668118 * scale_y,
0.0, 0.108848 * scale_x, -0.381587 * scale_y,
0.0, 0.537002 * scale_x, -0.77303 * scale_y,
0.0, -0.600421 * scale_x, -0.583106 * scale_y,
0.0, -0.600412 * scale_x, 0.583103 * scale_y,
0.0, 0.537002 * scale_x, 0.773025 * scale_y,
0.0, 0.108854 * scale_x, 0.381603 * scale_y,
0.0, 0.260966 * scale_x, 0.668129 * scale_y, 0.0]]
lhandles = [[(0.387973 * scale_x, -0.594856 * scale_y, 0.0),
(-0.027835 * scale_x, -0.532386 * scale_y, 0.0),
(0.775133 * scale_x, -0.442883 * scale_y, 0.0),
(-0.291333 * scale_x, -1.064385 * scale_y, 0.0),
(-0.833382 * scale_x, 0.220321 * scale_y, 0.0),
(0.291856 * scale_x, 1.112891 * scale_y, 0.0),
(0.346161 * scale_x, 0.119777 * scale_y, 0.0),
(0.133943 * scale_x, 0.741389 * scale_y, 0.0)]]
rhandles = [[(0.133951 * scale_x, -0.741386 * scale_y, 0.0),
(0.346154 * scale_x, -0.119772 * scale_y, 0.0),
(0.291863 * scale_x, -1.112896 * scale_y, 0.0),
(-0.833407 * scale_x, -0.220324 * scale_y, 0.0),
(-0.29134 * scale_x, 1.064389 * scale_y, 0.0),
(0.775125 * scale_x, 0.442895 * scale_y, 0.0),
(-0.029107 * scale_x, 0.533819 * scale_y, 0.0),
(0.387981 * scale_x, 0.594873 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type7(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.850431 * scale_x, -0.009091 * scale_y,
0.0, -0.818807 * scale_x, -0.130518 * scale_y,
0.0, -0.944931 * scale_x, 0.055065 * scale_y, 0.0,
-0.393355 * scale_x, -0.035521 * scale_y,
0.0, 0.0 * scale_x, 0.348298 * scale_y,
0.0, 0.393355 * scale_x, -0.035521 * scale_y,
0.0, 0.944931 * scale_x, 0.055065 * scale_y,
0.0, 0.818807 * scale_x, -0.130518 * scale_y,
0.0, 0.850431 * scale_x, -0.009091 * scale_y,0.0]]
lhandles = [[(-0.90478 * scale_x, -0.025302 * scale_y, 0.0),
(-0.753279 * scale_x, -0.085571 * scale_y, 0.0),
(-1.06406 * scale_x, -0.047879 * scale_y, 0.0),
(-0.622217 * scale_x, -0.022502 * scale_y, 0.0),
(0.181 * scale_x, 0.348791 * scale_y, 0.0),
(-0.101464 * scale_x, -0.063671 * scale_y, 0.0),
(0.822288 * scale_x, 0.161045 * scale_y, 0.0),
(0.931521 * scale_x, -0.207832 * scale_y, 0.0),
(0.796079 * scale_x, 0.007121 * scale_y, 0.0)]]
rhandles = [[(-0.796079 * scale_x, 0.007121 * scale_y, 0.0),
(-0.931521 * scale_x, -0.207832 * scale_y, 0.0),
(-0.822288 * scale_x, 0.161045 * scale_y, 0.0),
(0.101464 * scale_x, -0.063671 * scale_y, 0.0),
(-0.181193 * scale_x, 0.347805 * scale_y, 0.0),
(0.622217 * scale_x, -0.022502 * scale_y, 0.0),
(1.06406 * scale_x, -0.047879 * scale_y, 0.0),
(0.753279 * scale_x, -0.085571 * scale_y, 0.0),
(0.90478 * scale_x, -0.025302 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type4(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[0.072838 * scale_x, -0.071461 * scale_y,
0.0, -0.175451 * scale_x, -0.130711 * scale_y,
0.0, 0.207269 * scale_x, 0.118064 * scale_y,
0.0, 0 * scale_x, -1.0 * scale_y, 0.0]]
lhandles = [[(0.042135 * scale_x, 0.039756 * scale_y, 0),
(-0.086769 * scale_x, -0.265864 * scale_y, 0),
(0.002865 * scale_x, 0.364657 * scale_y, 0),
(0.233116 * scale_x, -0.596115 * scale_y, 0)]]
rhandles = [[(0.103542 * scale_x, -0.182683 * scale_y, 0),
(-0.327993 * scale_x, 0.101765 * scale_y, 0),
(0.417702 * scale_x, -0.135803 * scale_y, 0),
(-0.233116 * scale_x, -1.403885 * scale_y, 0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type1(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.71753 * scale_x, -0.08781 * scale_y,
0, -0.60337 * scale_x, -0.31612 * scale_y, 0,
-0.93266 * scale_x, 0, 0, 0, 0, 0, 0.93266 * scale_x,
0, 0, 0.60337 * scale_x, 0.31612 * scale_y,
0, 0.71753 * scale_x, 0.08781 * scale_y, 0]]
lhandles = [[(-0.81885 * scale_x, -0.143002 * scale_y, 0),
(-0.491926 * scale_x, -0.199026 * scale_y, 0),
(-1.126316 * scale_x, -0.255119 * scale_y, 0),
(-0.446315 * scale_x, 0.135164 * scale_y, 0),
(0.733297 * scale_x, -0.26265 * scale_y, 0),
(0.795065 * scale_x, 0.517532 * scale_y, 0),
(0.616204 * scale_x, 0.03262 * scale_y, 0)]]
rhandles = [[(-0.616204 * scale_x, -0.032618 * scale_y, 0),
(-0.795067 * scale_x, -0.517532 * scale_y, 0),
(-0.733297 * scale_x, 0.262651 * scale_y, 0),
(0.446315 * scale_x, -0.135163 * scale_y, 0),
(1.126316 * scale_x, 0.255119 * scale_y, 0),
(0.491924 * scale_x, 0.199026 * scale_y, 0),
(0.81885 * scale_x, 0.143004 * scale_y, 0)]]
make_curve(self, context, verts, lhandles, rhandles)
def make_curve(self, context, verts, lh, rh):
scale_x = self.scale_x
scale_y = self.scale_y
type = self.type
curve_data = bpy.data.curves.new(name='CurlyCurve', type='CURVE')
curve_data.dimensions = '3D'
for p in range(len(verts)):
c = 0
spline = curve_data.splines.new(type='BEZIER')
spline.bezier_points.add(len(verts[p]) / 3 - 1)
spline.bezier_points.foreach_set('co', verts[p])
for bp in spline.bezier_points:
bp.handle_left_type = 'ALIGNED'
bp.handle_right_type = 'ALIGNED'
bp.handle_left.xyz = lh[p][c]
bp.handle_right.xyz = rh[p][c]
c += 1
# something weird with this one
if type == 1 or type == 2 or type == 3:
spline.bezier_points[3].handle_left.xyz = lh[p][3]
object_data_add(context, curve_data, operator=self)
class add_curlycurve(Operator, AddObjectHelper):
"""Create a Curly Curve"""
bl_idname = "curve.curlycurve"
bl_label = "Add Curly Curve"
bl_options = {'REGISTER', 'UNDO'}
type = IntProperty(name='Type', description='Type of curly curve', default=1, min=1, max=10)
scale_x = FloatProperty(name="scale x", description="scale on x axis", default=1.0)
scale_y = FloatProperty(name="scale y", description="scale on y axis", default=1.0)
def execute(self, context):
if self.type == 1:
add_type1(self, context)
if self.type == 2:
add_type2(self, context)
if self.type == 3:
add_type3(self, context)
if self.type == 4:
add_type4(self, context)
if self.type == 5:
add_type5(self, context)
if self.type == 6:
add_type6(self, context)
if self.type == 7:
add_type7(self, context)
if self.type == 8:
add_type8(self, context)
if self.type == 9:
add_type9(self, context)
if self.type == 10:
add_type10(self, context)
return {'FINISHED'}
# Registration
def add_curlycurve_button(self, context):
self.layout.operator(
add_curlycurve.bl_idname,
text="Add Curly Curve",
icon='PLUGIN')
def register():
bpy.utils.register_class(add_curlycurve)
# bpy.utils.register_manual_map(add_object_manual_map)
bpy.types.INFO_MT_curve_add.append(add_curlycurve_button)
def unregister():
bpy.utils.unregister_class(add_curlycurve)
# bpy.utils.unregister_manual_map(add_object_manual_map)
bpy.types.INFO_MT_curve_add.remove(add_curlycurve_button)
if __name__ == "__main__":
register()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,259 @@
bl_info = {
"name": "Bevel/Taper Curve",
"author": "Cmomoney",
"version": (1, 1),
"blender": (2, 69, 0),
"location": "View3D > Object > Bevel/Taper",
"description": "Adds bevel and/or taper curve to active curve",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Curve/Bevel_-Taper_Curve",
"tracker_url": "https://projects.blender.org/tracker/index.php?func=detail&aid=37377&group_id=153&atid=467",
"category": "Curve"}
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# ***** END GPL LICENSE BLOCK *****
import bpy
from bpy.types import Operator
from bpy.props import *
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector
def add_taper(self, context):
scale_ends1 = self.scale_ends1
scale_ends2 = self.scale_ends2
scale_mid = self.scale_mid
verts = [(-2.0, 1.0 * scale_ends1, 0.0, 1.0),
(-1.0, 0.75 * scale_mid, 0.0, 1.0),
(0.0, 1.5 * scale_mid, 0.0, 1.0),
(1.0, 0.75 * scale_mid, 0.0, 1.0),
(2.0, 1.0 * scale_ends2, 0.0, 1.0)]
make_path(self, context, verts)
def add_type5(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[0.0 * scale_x, 0.049549 * scale_y,
0.0, 0.031603 * scale_x, 0.047013 * scale_y,
0.0, 0.05 * scale_x, 0.0 * scale_y, 0.0,
0.031603 * scale_x, -0.047013 * scale_y,
0.0, 0.0 * scale_x, -0.049549 * scale_y,
0.0, -0.031603 * scale_x, -0.047013 * scale_y,
0.0, -0.05 * scale_x, -0.0 * scale_y, 0.0,
-0.031603 * scale_x, 0.047013 * scale_y, 0.0]]
lhandles = [[(-0.008804 * scale_x, 0.049549 * scale_y, 0.0),
(0.021304 * scale_x, 0.02119 * scale_y, 0.0),
(0.05 * scale_x, 0.051228 * scale_y, 0.0),
(0.036552 * scale_x, -0.059423 * scale_y, 0.0),
(0.008804 * scale_x, -0.049549 * scale_y, 0.0),
(-0.021304 * scale_x, -0.02119 * scale_y, 0.0),
(-0.05 * scale_x, -0.051228 * scale_y, 0.0),
(-0.036552 * scale_x, 0.059423 * scale_y, 0.0)]]
rhandles = [[(0.008803 * scale_x, 0.049549 * scale_y, 0.0),
(0.036552 * scale_x, 0.059423 * scale_y, 0.0),
(0.05 * scale_x, -0.051228 * scale_y, 0.0),
(0.021304 * scale_x, -0.02119 * scale_y, 0.0),
(-0.008803 * scale_x, -0.049549 * scale_y, 0.0),
(-0.036552 * scale_x, -0.059423 * scale_y, 0.0),
(-0.05 * scale_x, 0.051228 * scale_y, 0.0),
(-0.021304 * scale_x, 0.02119 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type4(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.0 * scale_x, 0.017183 * scale_y,
0.0, 0.05 * scale_x, 0.0 * scale_y,
0.0, 0.0 * scale_x, -0.017183 * scale_y,
0.0, -0.05 * scale_x, -0.0 * scale_y, 0.0]]
lhandles = [[(-0.017607 * scale_x, 0.017183 * scale_y, 0.0),
(0.05 * scale_x, 0.102456 * scale_y, 0.0),
(0.017607 * scale_x, -0.017183 * scale_y, 0.0),
(-0.05 * scale_x, -0.102456 * scale_y, 0.0)]]
rhandles = [[(0.017607 * scale_x, 0.017183 * scale_y, 0.0),
(0.05 * scale_x, -0.102456 * scale_y, 0.0),
(-0.017607 * scale_x, -0.017183 * scale_y, 0.0),
(-0.05 * scale_x, 0.102456 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type3(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.017183 * scale_x, 0.0 * scale_y,
0.0, 0.0 * scale_x, 0.05 * scale_y,
0.0, 0.017183 * scale_x, 0.0 * scale_y,
0.0, 0.0 * scale_x, -0.05 * scale_y, 0.0]]
lhandles = [[(-0.017183 * scale_x, -0.017607 * scale_y, 0.0),
(-0.102456 * scale_x, 0.05 * scale_y, 0.0),
(0.017183 * scale_x, 0.017607 * scale_y, 0.0),
(0.102456 * scale_x, -0.05 * scale_y, 0.0)]]
rhandles = [[(-0.017183 * scale_x, 0.017607 * scale_y, 0.0),
(0.102456 * scale_x, 0.05 * scale_y, 0.0),
(0.017183 * scale_x, -0.017607 * scale_y, 0.0),
(-0.102456 * scale_x, -0.05 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type2(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.05 * scale_x, 0.0 * scale_y,
0.0, 0.0 * scale_x, 0.05 * scale_y,
0.0, 0.05 * scale_x, 0.0 * scale_y,
0.0, 0.0 * scale_x, -0.05 * scale_y, 0.0]]
lhandles = [[(-0.05 * scale_x, -0.047606 * scale_y, 0.0),
(-0.047606 * scale_x, 0.05 * scale_y, 0.0),
(0.05 * scale_x, 0.047607 * scale_y, 0.0),
(0.047606 * scale_x, -0.05 * scale_y, 0.0)]]
rhandles = [[(-0.05 * scale_x, 0.047607 * scale_y, 0.0),
(0.047607 * scale_x, 0.05 * scale_y, 0.0),
(0.05 * scale_x, -0.047607 * scale_y, 0.0),
(-0.047607 * scale_x, -0.05 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def add_type1(self, context):
scale_x = self.scale_x
scale_y = self.scale_y
verts = [[-0.05 * scale_x, 0.0 * scale_y,
0.0, 0.0 * scale_x, 0.05 * scale_y,
0.0, 0.05 * scale_x, 0.0 * scale_y,
0.0, 0.0 * scale_x, -0.05 * scale_y, 0.0]]
lhandles = [[(-0.05 * scale_x, -0.027606 * scale_y, 0.0),
(-0.027606 * scale_x, 0.05 * scale_y, 0.0),
(0.05 * scale_x, 0.027606 * scale_y, 0.0),
(0.027606 * scale_x, -0.05 * scale_y, 0.0)]]
rhandles = [[(-0.05 * scale_x, 0.027607 * scale_y, 0.0),
(0.027607 * scale_x, 0.05 * scale_y, 0.0),
(0.05 * scale_x, -0.027607 * scale_y, 0.0),
(-0.027607 * scale_x, -0.05 * scale_y, 0.0)]]
make_curve(self, context, verts, lhandles, rhandles)
def make_path(self, context, verts):
target = bpy.context.scene.objects.active
bpy.ops.curve.primitive_nurbs_path_add(view_align=False, enter_editmode=False, location=(0, 0, 0))
target.data.taper_object = bpy.context.scene.objects.active
taper = bpy.context.scene.objects.active
taper.name = target.name + '_Taper'
bpy.context.scene.objects.active = target
points = taper.data.splines[0].points
for i in range(len(verts)):
points[i].co = verts[i]
def make_curve(self, context, verts, lh, rh):
scale_x = self.scale_x
scale_y = self.scale_y
type = self.type
target = bpy.context.scene.objects.active
curve_data = bpy.data.curves.new(name=target.name +'_Bevel', type='CURVE')
curve_data.dimensions = '3D'
for p in range(len(verts)):
c = 0
spline = curve_data.splines.new(type='BEZIER')
spline.use_cyclic_u = True
spline.bezier_points.add( len(verts[p])/3-1 )
spline.bezier_points.foreach_set('co', verts[p])
for bp in spline.bezier_points:
bp.handle_left_type = 'ALIGNED'
bp.handle_right_type = 'ALIGNED'
bp.handle_left.xyz = lh[p][c]
bp.handle_right.xyz = rh[p][c]
c += 1
object_data_add(context, curve_data, operator=self)
target.data.bevel_object = bpy.context.scene.objects.active
bpy.context.scene.objects.active = target
class add_tapercurve(Operator, AddObjectHelper):
"""Add taper curve to active curve"""
bl_idname = "curve.tapercurve"
bl_label = "Add Curve as Taper"
bl_options = {'REGISTER', 'UNDO'}
scale_ends1 = FloatProperty(name="End Width Left", description="Adjust left end taper", default=0.0, min=0.0)
scale_ends2 = FloatProperty(name="End Width Right", description="Adjust right end taper", default=0.0, min=0.0)
scale_mid = FloatProperty(name="Center Width", description="Adjust taper at center", default=1.0, min=0.0)
link1 = BoolProperty(name='link ends', default=True)
link2 = BoolProperty(name='link ends/center', default=False)
if link2:
diff = FloatProperty(name='Difference', default=1, description='Difference between ends and center while linked')
def execute(self, context):
if self.link1:
self.scale_ends2 = self.scale_ends1
if self.link2:
self.scale_ends2 = self.scale_ends1 = self.scale_mid-self.diff
add_taper(self, context)
return {'FINISHED'}
class add_bevelcurve(Operator, AddObjectHelper):
"""Add bevel curve to active curve"""
bl_idname = "curve.bevelcurve"
bl_label = "Add Curve as Bevel"
bl_options = {'REGISTER', 'UNDO'}
type = IntProperty(name='Type', description='Type of bevel curve', default=1, min=1, max=5)
scale_x = FloatProperty(name="scale x", description="scale on x axis", default=1.0)
scale_y = FloatProperty(name="scale y", description="scale on y axis", default=1.0)
link = BoolProperty(name='link xy', default=True)
def execute(self, context):
if self.link:
self.scale_y = self.scale_x
if self.type == 1:
add_type1(self, context)
if self.type == 2:
add_type2(self, context)
if self.type == 3:
add_type3(self, context)
if self.type == 4:
add_type4(self, context)
if self.type == 5:
add_type5(self, context)
return {'FINISHED'}
class Bevel_Taper_Curve_Menu(bpy.types.Menu):
bl_label = "Bevel/Taper"
bl_idname = "OBJECT_MT_bevel_taper_curve_menu"
def draw(self, context):
layout = self.layout
layout.operator("curve.bevelcurve")
layout.operator("curve.tapercurve")
def menu_funcs(self, context):
if bpy.context.scene.objects.active.type == "CURVE":
self.layout.menu("OBJECT_MT_bevel_taper_curve_menu")
def register():
bpy.utils.register_module(__name__)
bpy.types.VIEW3D_MT_object.append(menu_funcs)
def unregister():
bpy.utils.unregister_module(__name__)
bpy.types.VIEW3D_MT_object.remove(menu_funcs)
if __name__ == "__main__":
register()

View File

@ -0,0 +1,84 @@
from math import sin, cos, pi
from . import braid
from .braid import angle_point
import bpy
def poly_line(curve, points, join=True, type='NURBS'):
polyline = curve.splines.new(type)
polyline.points.add(len(points) - 1)
for num in range(len(points)):
polyline.points[num].co = (points[num]) + (1,)
polyline.order_u = len(polyline.points) - 1
if join:
polyline.use_cyclic_u = True
def poly_lines(objname, curvename, lines, bevel=None, joins=False, ctype='NURBS'):
curve = bpy.data.curves.new(name=curvename, type='CURVE')
curve.dimensions = '3D'
obj = bpy.data.objects.new(objname, curve)
obj.location = (0, 0, 0) # object origin
# ctx.scene.objects.link(obj)
for i, line in enumerate(lines):
poly_line(curve, line, joins if type(joins) == bool else joins[i], type=ctype)
if bevel:
curve.bevel_object = bpy.data.objects[bevel]
return obj
def nurbs_circle(name, w, h):
pts = [(-w / 2, 0, 0), (0, -h / 2, 0), (w / 2, 0, 0), (0, h / 2, 0)]
return poly_lines(name, name + '_curve', [pts], joins=True)
def star_pts(r=1, ir=None, points=5, center=(0, 0)):
'''Create points for a star. They are 2d - z is always zero
r: the outer radius
ir: the inner radius
'''
if not ir:
ir = r / 5
pts = []
dt = pi * 2 / points
for i in range(points):
t = i * dt
ti = (i + .5) * dt
pts.append(angle_point(center, t, r) + (0,))
pts.append(angle_point(center, ti, ir) + (0,))
return pts
def clear():
for obj in bpy.data.objects:
if obj.type not in ('CAMERA', 'LAMP'):
obj.select = True
else:
obj.select = False
bpy.ops.object.delete()
def defaultCircle(w=.6):
circle = nurbs_circle('braid_circle', w, w)
circle.hide = True
return circle
def defaultStar():
star = poly_lines('star', 'staz', [tuple(star_pts(points=5, r=.5, ir=.05))], type='NURBS')
star.hide = True
return star
def awesome_braid(strands=3, sides=5, bevel='braid_circle', pointy=False, **kwds):
lines = braid.strands(strands, sides, **kwds)
type = {True: 'POLY', False: 'NURBS'}[pointy]
return poly_lines('Braid', 'Braid_c', lines, bevel=bevel, joins=True, ctype=type)

View File

@ -0,0 +1,60 @@
import math
from math import sin, cos, pi
def angle_point(center, angle, distance):
cx, cy = center
x = cos(angle) * distance
y = sin(angle) * distance
return x + cx, y + cy
def flat_hump(strands, mx=1, my=1, mz=1, resolution=2):
num = 4 * resolution
dy = 2 * pi / num
dz = 2 * pi * (strands - 1) / num
for i in range(num):
x = i * mx
y = cos(i * dy) * my
z = sin(i * dz) * mz
# print(i, x, y, z)
yield x, y, z
def circle_hump(pos, strands, humps, radius=1, mr=1, mz=.2, resolution=2):
num = 5 * resolution
dt = 2 * pi / humps * strands / num
dr = 2 * pi * (strands - 1) / num
dz = 2 * pi / num
t0 = 2 * pi / humps * pos
# print('ds', dt, dr, dz)
for i in range(num):
# i += pos
rdi = sin(i * dr) * mr
# print('rdi', rdi, radius, i*dt, i*dz, cos(i*dz) * mz)
x, y = angle_point((0, 0), i * dt + t0, radius + sin(i * dr) * mr)
z = cos(i * dz) * mz
yield x, y, z
def strands(strands, humps, radius=1, mr=1, mz=.2, resolution=2):
positions = [0 for x in range(humps)]
made = 0
last = None
lines = []
at = 0
while 0 in positions:
if positions[at]:
at = positions.index(0)
last = None
hump = list(circle_hump(at, strands, humps, radius, mr, mz, resolution))
if last is None:
last = hump
lines.append(last)
else:
last.extend(hump)
positions[at] = 1
at += strands
at %= humps
return lines