Add Curve Extra Objects: Cleanup, refactor some code

Bumped version to 0.1.2
Pep8 cleanup
Consistent property definitions
Remove star imports
Some small UI fixes
Reorder the submenu items types Alphabetically
Add Curve braid: merge in the bpybraid and braid scripts
since they are relatively small
Add Simple Curve - use a property group for scene props
Add list of Menus and Panels available in the User Preferences
This commit is contained in:
Vuk Gardašević 2017-06-03 13:37:35 +02:00
parent 77a836a245
commit 9c045fdd88
13 changed files with 3199 additions and 2649 deletions

View File

@ -15,19 +15,20 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# Contributed to by
# Contributed to by:
# testscreenings, Alejandro Omar Chocano Vasquez, Jimmy Hazevoet, meta-androcto #
# Cmomoney, Jared Forsyth, Adam Newgas, Spivak Vladimir
# Cmomoney, Jared Forsyth, Adam Newgas, Spivak Vladimir, Jared Forsyth, Atom #
# Antonio Osprite, Marius Giurgi (DolphinDream)
bl_info = {
"name": "Extra Objects",
"author": "Multiple Authors",
"version": (0, 1),
"version": (0, 1, 2),
"blender": (2, 76, 0),
"location": "View3D > Add > Curve > Extra Objects",
"description": "Add extra curve object types",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/Curve/Curve_Objects",
"category": "Add Curve"
}
@ -58,11 +59,21 @@ else:
from . import add_curve_spirofit_bouncespline
import bpy
from bpy.types import Menu, AddonPreferences
from bpy.props import StringProperty, IntProperty, BoolProperty
from bpy.types import (
Menu,
AddonPreferences,
)
from bpy.props import (
StringProperty,
BoolProperty,
)
def convert_old_presets(data_path, msg_data_path, old_preset_subdir, new_preset_subdir, fixdic={}, ext=".py"):
''' convert old presets '''
def convert_old_presets(data_path, msg_data_path, old_preset_subdir,
new_preset_subdir, fixdic={}, ext=".py"):
"""
convert old presets
"""
def convert_presets(self, context):
if not getattr(self, data_path, False):
@ -104,6 +115,7 @@ def convert_old_presets(data_path, msg_data_path, old_preset_subdir, new_preset_
file_preset = open(new_file_path, 'w')
file_preset.write("import bpy\n")
file_preset.write("op = bpy.context.active_operator\n")
for prop, value in vars(op).items():
if isinstance(value, str):
file_preset.write("op.%s = '%s'\n" % (prop, str(value)))
@ -114,37 +126,106 @@ def convert_old_presets(data_path, msg_data_path, old_preset_subdir, new_preset_
setattr(self, msg_data_path, "Converted %d old presets" % len(files))
return None
return convert_presets
# Addons Preferences
class CurveExtraObjectsAddonPreferences(AddonPreferences):
bl_idname = __name__
spiral_fixdic = {"spiral_type": ['ARCH', 'ARCH', 'LOG', 'SPHERE', 'TORUS'],
"curve_type": ['POLY', 'NURBS'],
"spiral_direction": ['COUNTER_CLOCKWISE', 'CLOCKWISE']
}
update_spiral_presets_msg = StringProperty(default="Nothing to do")
spiral_fixdic = {
"spiral_type": ['ARCH', 'ARCH', 'LOG', 'SPHERE', 'TORUS'],
"curve_type": ['POLY', 'NURBS'],
"spiral_direction": ['COUNTER_CLOCKWISE', 'CLOCKWISE']
}
update_spiral_presets_msg = StringProperty(
default="Nothing to do"
)
update_spiral_presets = BoolProperty(
name="Update Old Presets",
description="Update presets to reflect data changes",
default=False,
update=convert_old_presets("update_spiral_presets", # this props name
"update_spiral_presets_msg", # message prop
"operator/curve.spirals",
"curve_extras/curve.spirals",
fixdic=spiral_fixdic)
update=convert_old_presets(
"update_spiral_presets", # this props name
"update_spiral_presets_msg", # message prop
"operator/curve.spirals",
"curve_extras/curve.spirals",
fixdic=spiral_fixdic
)
)
show_menu_list = BoolProperty(
name="Menu List",
description="Show/Hide the Add Menu items",
default=False
)
show_panel_list = BoolProperty(
name="Panels List",
description="Show/Hide the Panel items",
default=False
)
def draw(self, context):
layout = self.layout
layout.label(text="Spirals")
if self.update_spiral_presets:
layout.label(self.update_spiral_presets_msg, icon='FILE_TICK')
else:
layout.prop(self, "update_spiral_presets")
box = layout.box()
box.label(text="Spirals:")
class INFO_MT_curve_knots_add1(bpy.types.Menu):
if self.update_spiral_presets:
box.label(self.update_spiral_presets_msg, icon="FILE_TICK")
else:
box.prop(self, "update_spiral_presets")
icon_1 = "TRIA_RIGHT" if not self.show_menu_list else "TRIA_DOWN"
box = layout.box()
box.prop(self, "show_menu_list", emboss=False, icon=icon_1)
if self.show_menu_list:
box.label(text="Items located in the Add Menu > Curve (default shortcut Ctrl + A):",
icon="LAYER_USED")
box.label(text="2D Objects:", icon="LAYER_ACTIVE")
box.label(text="Angle, Arc, Circle, Distance, Ellipse, Line, Point, Polygon,",
icon="LAYER_USED")
box.label(text="Polygon ab, Rectangle, Rhomb, Sector, Segment, Trapezoid",
icon="LAYER_USED")
box.label(text="Curve Profiles:", icon="LAYER_ACTIVE")
box.label(text="Arc, Arrow, Cogwheel, Cycloid, Flower, Helix (3D),",
icon="LAYER_USED")
box.label(text="Noise (3D), Nsided, Profile, Rectangle, Splat, Star",
icon="LAYER_USED")
box.label(text="Curve Spirals:", icon="LAYER_ACTIVE")
box.label(text="Archemedian, Logarithmic, Spheric, Torus",
icon="LAYER_USED")
box.label(text="Knots:", icon="LAYER_ACTIVE")
box.label(text="Torus Knots Plus, Celtic Links, Braid Knot",
icon="LAYER_USED")
box.label(text="Curly Curve", icon="LAYER_ACTIVE")
box.label(text="Bevel/Taper:", icon="LAYER_ACTIVE")
box.label(text="Add Curve as Bevel, Add Curve as Taper",
icon="LAYER_USED")
box.label(text="Items located in the Add Menu > Surface (default shortcut Ctrl + A):",
icon="LAYER_USED")
box.label(text="Wedge, Cone, Star, Plane",
icon="LAYER_ACTIVE")
icon_2 = "TRIA_RIGHT" if not self.show_panel_list else "TRIA_DOWN"
box = layout.box()
box.prop(self, "show_panel_list", emboss=False, icon=icon_2)
if self.show_panel_list:
box.label(text="Panel located in 3D View Tools Region > Create:",
icon="LAYER_ACTIVE")
box.label(text="Spline:", icon="LAYER_ACTIVE")
box.label(text="SpiroFit, Bounce Spline, Catenary", icon="LAYER_USED")
box.label(text="Panel located in 3D View Tools Region > Tools:",
icon="LAYER_ACTIVE")
box.label(text="Simple Curve:", icon="LAYER_ACTIVE")
box.label(text="Available if the Active Object is a Curve was created with 2D Objects",
icon="LAYER_USED")
class INFO_MT_curve_knots_add1(Menu):
# Define the "Extras" menu
bl_idname = "curve_knots_add"
bl_label = "Plants"
@ -152,13 +233,10 @@ class INFO_MT_curve_knots_add1(bpy.types.Menu):
def draw(self, context):
layout = self.layout
layout.operator_context = 'INVOKE_REGION_WIN'
layout.operator("curve.torus_knot_plus",
text="Torus Knot Plus")
layout.operator("curve.celtic_links",
text="Celtic Links")
layout.operator("mesh.add_braid",
text="Braid Knot")
layout.operator("curve.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
@ -166,31 +244,38 @@ def menu_func(self, context):
if context.mode != 'OBJECT':
# fix in D2142 will allow to work in EDIT_CURVE
return None
layout = self.layout
layout.operator_menu_enum("mesh.curveaceous_galore",
"ProfileType",
icon='CURVE_DATA')
layout.operator_menu_enum("curve.spirals",
"spiral_type",
icon='CURVE_DATA')
layout.operator_menu_enum("mesh.curveaceous_galore", "ProfileType",
icon='CURVE_DATA')
layout.operator_menu_enum("curve.spirals", "spiral_type",
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')
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
self.layout.separator()
if context.mode == 'EDIT_SURFACE':
self.layout.operator("curve.smooth_x_times", text="Special Smooth", icon="MOD_CURVE")
self.layout.operator("curve.smooth_x_times",
text="Special Smooth", icon="MOD_CURVE")
elif context.mode == 'OBJECT':
self.layout.operator("object.add_surface_wedge", text="Wedge", icon="MOD_CURVE")
self.layout.operator("object.add_surface_cone", text="Cone", icon="MOD_CURVE")
self.layout.operator("object.add_surface_star", text="Star", icon="MOD_CURVE")
self.layout.operator("object.add_surface_plane", text="Plane", icon="MOD_CURVE")
self.layout.operator("object.add_surface_wedge", text="Wedge",
icon="SURFACE_DATA")
self.layout.operator("object.add_surface_cone", text="Cone",
icon="SURFACE_DATA")
self.layout.operator("object.add_surface_star", text="Star",
icon="SURFACE_DATA")
self.layout.operator("object.add_surface_plane", text="Plane",
icon="SURFACE_DATA")
def register():
add_curve_simple.register()
@ -201,8 +286,8 @@ def register():
# Add "Extras" menu to the "Add Surface" menu
bpy.types.INFO_MT_surface_add.append(menu_surface)
def unregister():
def unregister():
add_curve_simple.unregister()
# Remove "Extras" menu from the "Add Curve" menu.
bpy.types.INFO_MT_curve_add.remove(menu_func)
@ -211,5 +296,6 @@ def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()

File diff suppressed because it is too large Load Diff

View File

@ -1,88 +1,261 @@
# gpl: author Jared Forsyth <github.com/jaredly>
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),
"version": (1, 0, 2),
"blender": (2, 6, 0),
"location": "View3D > Add > Mesh > New Braid",
"description": "Adds a new Braid",
"warning": "",
"wiki_url": "",
"tracker_url": "",
"category": "Add Mesh"}
'''
"""
import bpy
from bpy.props import (
FloatProperty,
IntProperty,
BoolProperty,
)
from bpy.types import Operator
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
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
for i in range(num):
x, y = angle_point((0, 0), i * dt + t0, radius + sin(i * dr) * mr)
z = cos(i * dz) * mz
yield x, y, z
def make_strands(strands, humps, radius=1, mr=1, mz=.2, resolution=2):
positions = [0 for x in range(humps)]
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
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
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 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 = make_strands(strands, sides, **kwds)
types = {True: 'POLY', False: 'NURBS'}[pointy]
return poly_lines('Braid', 'Braid_c', lines, bevel=bevel, joins=True, ctype=types)
class Braid(Operator):
'''Add a Braid'''
bl_idname = 'mesh.add_braid'
bl_label = 'New Braid'
bl_description = 'Create a new braid'
bl_idname = "mesh.add_braid"
bl_label = "New Braid"
bl_description = ("Construct a new Braid\n"
"Creates two objects - the hidden one is used as the Bevel control")
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)
strands = IntProperty(
name="Strands",
description="Number of Strands",
min=2, max=100,
default=3
)
sides = IntProperty(
name="Sides",
description="Number of Knot sides",
min=2, max=100,
default=5
)
radius = FloatProperty(
name="Radius",
description="Increase / decrease the diameter in X,Y axis",
default=1
)
thickness = FloatProperty(
name="Thickness",
description="The ratio between inner and outside diameters",
default=.3
)
strandsize = FloatProperty(
name="Bevel Depth",
description="Individual strand diameter (similar to Curve's Bevel depth)",
default=.3,
min=.01, max=10
)
width = FloatProperty(
name="Width",
description="Stretch the Braids along the Z axis",
default=.2
)
resolution = IntProperty(
name="Bevel Resolution",
description="Resolution of the Created curve\n"
"Increasing this value, will produce heavy geometry",
min=1,
max=100, soft_max=24,
default=2
)
pointy = BoolProperty(
name="Pointy",
description="Switch between round and sharp corners",
default=False
)
def draw(self, context):
layout = self.layout
box = layout.box()
col = box.column(align=True)
col.label("Settings:")
col.prop(self, "strands")
col.prop(self, "sides")
col = box.column(align=True)
col.prop(self, "radius")
col.prop(self, "thickness")
col.prop(self, "width")
col = box.column()
col.prop(self, "pointy")
box = layout.box()
col = box.column(align=True)
col.label("Geometry Options:")
col.prop(self, "strandsize")
col.prop(self, "resolution")
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)
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

@ -1,5 +1,4 @@
# Blender plugin for generating celtic knot curves from 3d meshes
# See README for more information
#
# The MIT License (MIT)
#
@ -27,7 +26,7 @@ bl_info = {
"name": "Celtic Knot",
"description": "",
"author": "Adam Newgas",
"version": (0, 1, 1),
"version": (0, 1, 2),
"blender": (2, 74, 0),
"location": "View3D > Add > Curve",
"warning": "",
@ -36,45 +35,65 @@ bl_info = {
import bpy
import bmesh
from bpy.types import Operator
from bpy.props import (
EnumProperty,
FloatProperty,
)
from collections import defaultdict
from mathutils import Vector
from math import pi, sin, cos
from math import (
pi, sin,
cos,
)
class CelticKnotOperator(bpy.types.Operator):
class CelticKnotOperator(Operator):
bl_idname = "curve.celtic_links"
bl_label = "Celtic Links"
bl_description = 'Select low poly Mesh Object to cover with Knitted Links'
bl_description = "Select a 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")
weave_up = FloatProperty(
name="Weave Up",
description="Distance to shift curve upwards over knots",
subtype="DISTANCE",
unit="LENGTH"
)
weave_down = 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 = EnumProperty(
items=handle_types,
name="Handle Type",
description="Controls what type the bezier control points use",
default='AUTO'
)
handle_type_map = {"AUTO": "AUTOMATIC", "ALIGNED": "ALIGNED"}
geo_bDepth = bpy.props.FloatProperty(
crossing_angle = 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 = FloatProperty(
name="Crossing Strength",
description="Aligned only: strenth of bezier control points",
soft_min=0,
subtype="DISTANCE",
unit="LENGTH"
)
geo_bDepth = FloatProperty(
name="Bevel Depth",
default=0.04,
min=0, soft_min=0,
@ -84,11 +103,23 @@ class CelticKnotOperator(bpy.types.Operator):
@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"))
return ((ob is not None) and (ob.mode == "OBJECT") and
(ob.type == "MESH") and (context.mode == "OBJECT"))
def draw(self, context):
layout = self.layout
layout.prop(self, "handle_type")
col = layout.column(align=True)
col.prop(self, "weave_up")
col.prop(self, "weave_down")
col = layout.column(align=True)
col.active = False if self.handle_type == 'AUTO' else True
col.prop(self, "crossing_angle")
col.prop(self, "crossing_strength")
layout.prop(self, "geo_bDepth")
def execute(self, context):
# Cache some values
@ -97,6 +128,7 @@ class CelticKnotOperator(bpy.types.Operator):
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")
@ -108,6 +140,7 @@ class CelticKnotOperator(bpy.types.Operator):
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]]
@ -124,6 +157,7 @@ class CelticKnotOperator(bpy.types.Operator):
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
@ -150,7 +184,7 @@ class CelticKnotOperator(bpy.types.Operator):
loop = loop.link_loop_next
if not ignorable_loop(loop):
break
assert loops_entered[loop] == False
assert loops_entered[loop] is False
loops_entered[loop] = True
v = loop.vert.index
prev_loop = loop
@ -168,13 +202,14 @@ class CelticKnotOperator(bpy.types.Operator):
loop = loop.link_loop_prev
if not ignorable_loop(loop):
break
assert loops_exited[loop] == False
assert loops_exited[loop] is 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
@ -184,6 +219,7 @@ class CelticKnotOperator(bpy.types.Operator):
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()
@ -196,6 +232,7 @@ class CelticKnotOperator(bpy.types.Operator):
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":
@ -211,6 +248,7 @@ class CelticKnotOperator(bpy.types.Operator):
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)
@ -223,27 +261,24 @@ class CelticKnotOperator(bpy.types.Operator):
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
# apply the bevel setting since it was unused
try:
curve_obj.data.bevel_depth = self.geo_bDepth
except:
pass
context.scene.objects.active = orig_obj
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)
bpy.utils.register_class(CelticKnotOperator)
def unregister():
bpy.types.INFO_MT_curve_add.remove(menu_func)
bpy.utils.unregister_module(__name__)
bpy.utils.unregister_class(CelticKnotOperator)
if __name__ == "__main__":
register()

View File

@ -1,50 +1,65 @@
# gpl: author Cmomoney
# DevBo Task https://developer.blender.org/T37299
bl_info = {
"name": "Curly Curves",
"author": "Cmomoney",
"version": (1, 17),
"version": (1, 1, 8),
"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",
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
"Py/Scripts/Curve/Curly_Curves",
"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
from bpy.props import (
FloatProperty,
IntProperty,
)
from bpy_extras.object_utils import (
AddObjectHelper,
object_data_add,
)
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)]]
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)
@ -52,26 +67,36 @@ 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)]]
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)
@ -79,33 +104,39 @@ 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)]]
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)
@ -113,27 +144,33 @@ 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)]]
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)
@ -141,25 +178,31 @@ 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)]]
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)
@ -167,30 +210,36 @@ 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)]]
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)
@ -198,30 +247,36 @@ 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)]]
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)
@ -229,33 +284,39 @@ 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)]]
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)
@ -263,18 +324,24 @@ 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)]]
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)
@ -282,40 +349,46 @@ 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)]]
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
types = self.types
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'
@ -323,64 +396,96 @@ def make_curve(self, context, verts, lh, rh):
bp.handle_right.xyz = rh[p][c]
c += 1
# something weird with this one
if type == 1 or type == 2 or type == 3:
if types == 1 or types == 2 or types == 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_description = "Create a 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)
types = 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 draw(self, context):
layout = self.layout
col = layout.column(align=True)
# AddObjectHelper props
col.prop(self, "view_align")
col.prop(self, "location")
col.prop(self, "rotation")
col = layout.column()
col.label("Curve:")
col.prop(self, "types")
col = layout.column(align=True)
col.label("Resize:")
col.prop(self, "scale_x")
col.prop(self, "scale_y")
def execute(self, context):
if self.type == 1:
if self.types == 1:
add_type1(self, context)
if self.type == 2:
if self.types == 2:
add_type2(self, context)
if self.type == 3:
if self.types == 3:
add_type3(self, context)
if self.type == 4:
if self.types == 4:
add_type4(self, context)
if self.type == 5:
if self.types == 5:
add_type5(self, context)
if self.type == 6:
if self.types == 6:
add_type6(self, context)
if self.type == 7:
if self.types == 7:
add_type7(self, context)
if self.type == 8:
if self.types == 8:
add_type8(self, context)
if self.type == 9:
if self.types == 9:
add_type9(self, context)
if self.type == 10:
if self.types == 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')
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

@ -1,19 +1,24 @@
'''bl_info = {
# gpl: author Alejandro Omar Chocano Vasquez
"""
bl_info = {
"name": "Spirals",
"description": "Make spirals",
"author": "Alejandro Omar Chocano Vasquez",
"version": (1, 2),
"version": (1, 2, 1),
"blender": (2, 62, 0),
"location": "View3D > Add > Curve",
"warning": "", # used for warning icon and text in addons panel
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.4/Py/"
"warning": "",
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.4/Py/"
"Scripts/Object/Spirals",
"tracker_url": "http://alexvaqp.googlepages.com?"
"func=detail&aid=<number>",
"category": "Add Curve",
}
'''
import bpy, time
"""
import bpy
import time
from bpy.props import (
EnumProperty,
BoolProperty,
@ -21,62 +26,59 @@ from bpy.props import (
IntProperty,
)
from math import (
sin,
cos,
pi,
exp
sin, cos, pi
)
from bpy_extras.object_utils import object_data_add
from bpy.types import (
Operator,
Menu,
)
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from bpy.types import Operator, Menu
from bl_operators.presets import AddPresetBase
# make normal spiral
# ----------------------------------------------------------------------------
def make_spiral(props, context):
# archemedian and logarithmic can be plottet in zylindrical coordinates
# if props.spiral_type != 1 and props.spiral_type != 2:
# return None
# archemedian and logarithmic can be plotted in cylindrical coordinates
# INPUT: turns->degree->max_phi, steps, direction
# Initialise Polar Coordinate Enviroment
# -------------------------------
props.degree = 360*props.turns # If you want to make the slider for degree
steps = props.steps * props.turns # props.steps[per turn] -> steps[for the whole spiral]
props.degree = 360 * props.turns # If you want to make the slider for degree
steps = props.steps * props.turns # props.steps[per turn] -> steps[for the whole spiral]
props.z_scale = props.dif_z * props.turns
max_phi = pi*props.degree/180 # max angle in radian
step_phi = max_phi/steps # angle in radians between two vertices
max_phi = pi * props.degree / 180 # max angle in radian
step_phi = max_phi / steps # angle in radians between two vertices
if props.spiral_direction == 'CLOCKWISE':
step_phi *= -1 # flip direction
max_phi *= -1
step_z = props.z_scale/(steps-1) # z increase in one step
step_z = props.z_scale / (steps - 1) # z increase in one step
verts = []
verts.extend([props.radius, 0, 0, 1])
cur_phi = 0
cur_z = 0
# ------------------------------
# Archemedean: dif_radius, radius
# Archemedean: dif_radius, radius
cur_rad = props.radius
step_rad = props.dif_radius/(steps * 360/props.degree)
# radius increase per angle for archemedean spiral| (steps * 360/props.degree)...Steps needed for 360 deg
# Logarithmic: radius, B_force, ang_div, dif_z
step_rad = props.dif_radius / (steps * 360 / props.degree)
# radius increase per angle for archemedean spiral|
# (steps * 360/props.degree)...Steps needed for 360 deg
# Logarithmic: radius, B_force, ang_div, dif_z
# print("max_phi:",max_phi,"step_phi:",step_phi,"step_rad:",step_rad,"step_z:",step_z)
while abs(cur_phi) <= abs(max_phi):
cur_phi += step_phi
cur_z += step_z
# ------------------------------
if props.spiral_type == 'ARCH':
cur_rad += step_rad
if props.spiral_type == 'LOG':
# r = a*e^{|theta| * b}
cur_rad = props.radius * pow(props.B_force, abs(cur_phi))
# ------------------------------
px = cur_rad * cos(cur_phi)
py = cur_rad * sin(cur_phi)
@ -87,26 +89,25 @@ def make_spiral(props, context):
# make Spheric spiral
# ----------------------------------------------------------------------------
def make_spiral_spheric(props, context):
# INPUT: turns, steps[per turn], radius
# use spherical Coordinates
step_phi = (2*pi) / props.steps # Step of angle in radians for one turn
step_phi = (2 * pi) / props.steps # Step of angle in radians for one turn
steps = props.steps * props.turns # props.steps[per turn] -> steps[for the whole spiral]
max_phi = 2*pi*props.turns # max angle in radian
step_phi = max_phi/steps # angle in radians between two vertices
max_phi = 2 * pi * props.turns # max angle in radian
step_phi = max_phi / steps # angle in radians between two vertices
if props.spiral_direction == 'CLOCKWISE': # flip direction
step_phi *= -1
max_phi *= -1
step_theta = pi / (steps-1) # theta increase in one step (pi == 180 deg)
step_theta = pi / (steps - 1) # theta increase in one step (pi == 180 deg)
verts = []
verts.extend([0, 0, -props.radius, 1]) # First vertex at south pole
#cur_rad = props.radius = CONST
cur_phi = 0
cur_theta = -pi/2 # Beginning at south pole
cur_theta = -pi / 2 # Beginning at south pole
while abs(cur_phi) <= abs(max_phi):
# Coordinate Transformation sphere->rect
@ -120,17 +121,21 @@ def make_spiral_spheric(props, context):
return verts
# make torus spiral
# ----------------------------------------------------------------------------
def make_spiral_torus(props, context):
# INPUT: turns, steps, inner_radius, curves_number, mul_height, dif_inner_radius, cycles
max_phi = 2*pi*props.turns * props.cycles # max angle in radian
step_phi = 2*pi/props.steps # Step of angle in radians between two vertices
# INPUT: turns, steps, inner_radius, curves_number,
# mul_height, dif_inner_radius, cycles
max_phi = 2 * pi * props.turns * props.cycles # max angle in radian
step_phi = 2 * pi / props.steps # Step of angle in radians between two vertices
if props.spiral_direction == 'CLOCKWISE': # flip direction
step_phi *= -1
max_phi *= -1
step_theta = (2*pi / props.turns) / props.steps
step_theta = (2 * pi / props.turns) / props.steps
step_rad = props.dif_radius / (props.steps * props.turns)
step_inner_rad = props.dif_inner_radius / props.steps
step_z = props.dif_z / (props.steps * props.turns)
@ -146,14 +151,17 @@ def make_spiral_torus(props, context):
while abs(cur_phi) <= abs(max_phi):
# Torus Coordinates -> Rect
px = (cur_rad + cur_inner_rad * cos(cur_phi)) * cos(props.curves_number * cur_theta)
py = (cur_rad + cur_inner_rad * cos(cur_phi)) * sin(props.curves_number * cur_theta)
px = (cur_rad + cur_inner_rad * cos(cur_phi)) * \
cos(props.curves_number * cur_theta)
py = (cur_rad + cur_inner_rad * cos(cur_phi)) * \
sin(props.curves_number * cur_theta)
pz = cur_inner_rad * sin(cur_phi) + cur_z
verts.extend([px, py, pz, 1])
if props.touch and cur_phi >= n_cycle * 2*pi:
step_z = ((n_cycle+1) * props.dif_inner_radius + props.inner_radius) * 2 / (props.steps * props.turns)
if props.touch and cur_phi >= n_cycle * 2 * pi:
step_z = ((n_cycle + 1) * props.dif_inner_radius +
props.inner_radius) * 2 / (props.steps * props.turns)
n_cycle += 1
cur_theta += step_theta
@ -163,7 +171,7 @@ def make_spiral_torus(props, context):
cur_z += step_z
return verts
# ----------------------------------------------------------------------------
def draw_curve(props, context):
if props.spiral_type == 'ARCH':
@ -179,132 +187,203 @@ def draw_curve(props, context):
curve_data.dimensions = '3D'
spline = curve_data.splines.new(type=props.curve_type)
'''
"""
if props.curve_type == 0:
spline = curve_data.splines.new(type='POLY')
elif props.curve_type == 1:
spline = curve_data.splines.new(type='NURBS')
'''
spline.points.add(len(verts)*0.25-1)
# Add only one quarter of points as elements in verts, because verts looks like: "x,y,z,?,x,y,z,?,x,..."
"""
spline.points.add(len(verts) * 0.25 - 1)
# Add only one quarter of points as elements in verts,
# because verts looks like: "x,y,z,?,x,y,z,?,x,..."
spline.points.foreach_set('co', verts)
new_obj = object_data_add(context, curve_data)
class CURVE_OT_spirals(Operator):
bl_idname = "curve.spirals"
bl_label = "Add Curve: Spirals"
bl_label = "Curve Spirals"
bl_description = "Create different types of spirals"
bl_options = {'REGISTER', 'UNDO'}
# UNDO needed for operator redo and therefore also to let the addobjecthelp appear!!!
bl_description = "Create different types of spirals"
spiral_type = EnumProperty(items=[('ARCH', "Archemedian", "Archemedian"),
("LOG", "Logarithmic", "Logarithmic"),
("SPHERE", "Spheric", "Spheric"),
("TORUS", "Torus", "Torus")],
default='ARCH',
name="Spiral Type",
description="Type of spiral to add")
curve_type = EnumProperty(items=[('POLY', "Poly", "PolyLine"),
("NURBS", "NURBS", "NURBS")],
default='POLY',
name="Curve Type",
description="Type of spline to use")
spiral_direction = EnumProperty(items=[('COUNTER_CLOCKWISE', "Counter Clockwise", "Wind in a counter clockwise direction"),
("CLOCKWISE", "Clockwise", "Wind in a clockwise direction")],
default='COUNTER_CLOCKWISE',
name="Spiral Direction",
description="Direction of winding")
turns = IntProperty(default=1, min=1, max=1000, description="Length of Spiral in 360 deg")
steps = IntProperty(default=24, min=2, max=1000, description="Number of Vertices per turn")
radius = FloatProperty(default=1.00, min=0.00, max=100.00, description="radius for first turn")
dif_z = FloatProperty(default=0, min=-10.00, max=100.00, description="increase in z axis per turn")
# needed for 1 and 2 spiral_type
# ARCHMEDEAN variables
dif_radius = FloatProperty(default=0.00, min=-50.00, max=50.00, description="radius increment in each turn")
# step between turns(one turn equals 360 deg)
# LOG variables
B_force = FloatProperty(default=1.00, min=0.00, max=30.00, description="factor of exponent")
# TORUS variables
inner_radius = FloatProperty(default=0.20, min=0.00, max=100, description="Inner Radius of Torus")
dif_inner_radius = FloatProperty(default=0, min=-10, max=100, description="Increase of inner Radius per Cycle")
dif_radius = FloatProperty(default=0, min=-10, max=100, description="Increase of Torus Radius per Cycle")
cycles = FloatProperty(default=1, min=0.00, max=1000, description="Number of Cycles")
curves_number = IntProperty(default=1, min=1, max=400, description="Number of curves of spiral")
touch = BoolProperty(default=False, description="No empty spaces between cycles")
spiral_type = EnumProperty(
items=[('ARCH', "Archemedian", "Archemedian"),
("LOG", "Logarithmic", "Logarithmic"),
("SPHERE", "Spheric", "Spheric"),
("TORUS", "Torus", "Torus")],
default='ARCH',
name="Spiral Type",
description="Type of spiral to add"
)
curve_type = EnumProperty(
items=[('POLY', "Poly", "PolyLine"),
("NURBS", "NURBS", "NURBS")],
default='POLY',
name="Curve Type",
description="Type of spline to use"
)
spiral_direction = EnumProperty(
items=[('COUNTER_CLOCKWISE', "Counter Clockwise",
"Wind in a counter clockwise direction"),
("CLOCKWISE", "Clockwise",
"Wind in a clockwise direction")],
default='COUNTER_CLOCKWISE',
name="Spiral Direction",
description="Direction of winding"
)
turns = IntProperty(
default=1,
min=1, max=1000,
description="Length of Spiral in 360 deg"
)
steps = IntProperty(
default=24,
min=2, max=1000,
description="Number of Vertices per turn"
)
radius = FloatProperty(
default=1.00,
min=0.00, max=100.00,
description="Radius for first turn"
)
dif_z = FloatProperty(
default=0,
min=-10.00, max=100.00,
description="Increase in Z axis per turn"
)
# needed for 1 and 2 spiral_type
# Archemedian variables
dif_radius = FloatProperty(
default=0.00,
min=-50.00, max=50.00,
description="Radius increment in each turn"
)
# step between turns(one turn equals 360 deg)
# Log variables
B_force = FloatProperty(
default=1.00,
min=0.00, max=30.00,
description="Factor of exponent"
)
# Torus variables
inner_radius = FloatProperty(
default=0.20,
min=0.00, max=100,
description="Inner Radius of Torus"
)
dif_inner_radius = FloatProperty(
default=0,
min=-10, max=100,
description="Increase of inner Radius per Cycle"
)
dif_radius = FloatProperty(
default=0,
min=-10, max=100,
description="Increase of Torus Radius per Cycle"
)
cycles = FloatProperty(
default=1,
min=0.00, max=1000,
description="Number of Cycles"
)
curves_number = IntProperty(
default=1,
min=1, max=400,
description="Number of curves of spiral"
)
touch = BoolProperty(
default=False,
description="No empty spaces between cycles"
)
def draw(self, context):
layout = self.layout
col = layout.column_flow(align=True)
col.label('Presets:')
col.label("Presets:")
row = col.row(align=True)
row.menu("OBJECT_MT_spiral_curve_presets", text=bpy.types.OBJECT_MT_spiral_curve_presets.bl_label)
row.menu("OBJECT_MT_spiral_curve_presets",
text=bpy.types.OBJECT_MT_spiral_curve_presets.bl_label)
row.operator("curve_extras.spiral_presets", text="", icon='ZOOMIN')
#op = row.operator("curve.spiral_presets", text="SAVE")
#op.name = bpy.types.OBJECT_MT_spiral_curve_presets.bl_label
op = row.operator("curve_extras.spiral_presets", text="", icon='ZOOMOUT')
op.remove_active = True
layout.prop(self, 'spiral_type')
layout.prop(self, 'curve_type')
layout.prop(self, 'spiral_direction')
layout.prop(self, "spiral_type")
layout.prop(self, "curve_type")
layout.prop(self, "spiral_direction")
layout.label(text="Spiral Parameters:")
layout.prop(self, 'turns', text="Turns")
layout.prop(self, 'steps', text="Steps")
col = layout.column(align=True)
col.label(text="Spiral Parameters:")
col.prop(self, "turns", text="Turns")
col.prop(self, "steps", text="Steps")
box = layout.box()
if self.spiral_type == 'ARCH':
box.prop(self, 'dif_radius', text="Radius Growth")
box.prop(self, 'radius', text="Radius")
box.prop(self, 'dif_z', text="Height")
box.label("Archemedian Settings:")
col = box.column(align=True)
col.prop(self, "dif_radius", text="Radius Growth")
col.prop(self, "radius", text="Radius")
col.prop(self, "dif_z", text="Height")
if self.spiral_type == 'LOG':
box.prop(self, 'radius', text="Radius")
box.prop(self, 'B_force', text="Expansion Force")
box.prop(self, 'dif_z', text="Height")
box.label("Logarithmic Settings:")
col = box.column(align=True)
col.prop(self, "radius", text="Radius")
col.prop(self, "B_force", text="Expansion Force")
col.prop(self, "dif_z", text="Height")
if self.spiral_type == 'SPHERE':
box.prop(self, 'radius', text="Radius")
box.label("Spheric Settings:")
box.prop(self, "radius", text="Radius")
if self.spiral_type == 'TORUS':
box.prop(self, 'cycles', text="Number of Cycles")
box.label("Torus Settings:")
col = box.column(align=True)
col.prop(self, "cycles", text="Number of Cycles")
if self.dif_inner_radius == 0 and self.dif_z == 0:
self.cycles = 1
box.prop(self, 'radius', text="Radius")
col.prop(self, "radius", text="Radius")
if self.dif_z == 0:
box.prop(self, 'dif_z', text="Height per Cycle")
col.prop(self, "dif_z", text="Height per Cycle")
else:
box2 = box.box()
box2.prop(self, 'dif_z', text="Height per Cycle")
box2.prop(self, 'touch', text="Make Snail")
box.prop(self, 'inner_radius', text="Inner Radius")
box.prop(self, 'curves_number', text="Curves Number")
box.prop(self, 'dif_radius', text="Increase of Torus Radius")
box.prop(self, 'dif_inner_radius', text="Increase of Inner Radius")
col2 = box2.column(align=True)
col2.prop(self, "dif_z", text="Height per Cycle")
col2.prop(self, "touch", text="Make Snail")
col = box.column(align=True)
col.prop(self, "curves_number", text="Curves Number")
col.prop(self, "inner_radius", text="Inner Radius")
col.prop(self, "dif_radius", text="Increase of Torus Radius")
col.prop(self, "dif_inner_radius", text="Increase of Inner Radius")
@classmethod
def poll(cls, context):
# method called by blender to check if the operator can be run
return context.scene is not None
def execute(self, context):
time_start = time.time()
draw_curve(self, context)
print("Drawing Spiral Finished: %.4f sec" % (time.time() - time_start))
self.report({'INFO'},
"Drawing Spiral Finished: %.4f sec" % (time.time() - time_start))
return {'FINISHED'}
class CURVE_EXTRAS_OT_spirals_presets(AddPresetBase, Operator):
'''Spirals Presets'''
bl_idname = "curve_extras.spiral_presets"
bl_label = "Spirals"
bl_description = "Spirals Presets"
preset_menu = "OBJECT_MT_spiral_curve_presets"
preset_subdir = "curve_extras/curve.spirals"
preset_defines = [
"op = bpy.context.active_operator",
]
"op = bpy.context.active_operator",
]
preset_values = [
"op.spiral_type",
"op.curve_type",
@ -320,10 +399,11 @@ class CURVE_EXTRAS_OT_spirals_presets(AddPresetBase, Operator):
"op.cycles",
"op.curves_number",
"op.touch",
]
]
class OBJECT_MT_spiral_curve_presets(Menu):
'''Presets for curve.spiral.'''
'''Presets for curve.spiral'''
bl_label = "Spiral Curve Presets"
bl_idname = "OBJECT_MT_spiral_curve_presets"
preset_subdir = "curve_extras/curve.spirals"
@ -331,5 +411,14 @@ class OBJECT_MT_spiral_curve_presets(Menu):
draw = bpy.types.Menu.draw_preset
if __name__ == "__main__":
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()

File diff suppressed because it is too large Load Diff

View File

@ -16,7 +16,7 @@
#
# ##### END GPL LICENSE BLOCK #####
'''
"""
bl_info = {
"name": "Torus Knots",
"author": "Marius Giurgi (DolphinDream), testscreenings",
@ -25,14 +25,11 @@ bl_info = {
"location": "View3D > Add > Curve",
"description": "Adds many types of (torus) knots",
"warning": "",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/Curve/Torus_Knot",
"category": "Add Curve"}
'''
"""
# ------------------------------------------------------------------------------
#### import modules
import bpy
from bpy.props import (
BoolProperty,
@ -41,18 +38,21 @@ from bpy.props import (
IntProperty
)
from math import (
sin,
cos,
pi,
sqrt
sin, cos,
pi, sqrt
)
from mathutils import *
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import (
Vector,
Matrix,
)
from bpy_extras.object_utils import AddObjectHelper
from random import random
from bpy.types import Operator
# Globals:
DEBUG = False
# greatest common denominator
def gcd(a, b):
if b == 0:
@ -61,9 +61,9 @@ def gcd(a, b):
return gcd(b, a % b)
########################################################################
####################### Knot Definitions ###############################
########################################################################
# #######################################################################
# ###################### Knot Definitions ###############################
# #######################################################################
def Torus_Knot(self, linkIndex=0):
p = self.torus_p # revolution count (around the torus center)
q = self.torus_q # spin count (around the torus tube)
@ -85,19 +85,19 @@ def Torus_Knot(self, linkIndex=0):
R = self.torus_R * s # major radius (scaled)
r = self.torus_r * s # minor radius (scaled)
# number of decoupled links when (p,q) are NOT co-primes
# number of decoupled links when (p,q) are NOT co-primes
links = gcd(p, q) # = 1 when (p,q) are co-primes
# parametrized angle increment (cached outside of the loop for performance)
# NOTE: the total angle is divided by number of decoupled links to ensure
# the curve does not overlap with itself when (p,q) are not co-primes
da = 2*pi/links/(N-1)
# parametrized angle increment (cached outside of the loop for performance)
# NOTE: the total angle is divided by number of decoupled links to ensure
# the curve does not overlap with itself when (p,q) are not co-primes
da = 2 * pi / links / (N - 1)
# link phase : each decoupled link is phased equally around the torus center
# NOTE: linkIndex value is in [0, links-1]
linkPhase = 2*pi/q * linkIndex # = 0 when there is just ONE link
# link phase : each decoupled link is phased equally around the torus center
# NOTE: linkIndex value is in [0, links-1]
linkPhase = 2 * pi / q * linkIndex # = 0 when there is just ONE link
# user defined phasing
# user defined phasing
if self.options_plus:
rPhase = self.torus_rP # user defined revolution phase
sPhase = self.torus_sP # user defined spin phase
@ -113,35 +113,37 @@ def Torus_Knot(self, linkIndex=0):
print("gcd = %i" % links)
print("p = %i" % p)
print("q = %i" % q)
print("link phase = %.2f deg" % (linkPhase * 180/pi))
print("link phase = %.2f deg" % (linkPhase * 180 / pi))
print("link phase = %.2f rad" % linkPhase)
# flip directions ? NOTE: flipping both is equivalent to no flip
# flip directions ? NOTE: flipping both is equivalent to no flip
if self.flip_p:
p *= -1
if self.flip_q:
q *= -1
# create the 3D point array for the current link
# create the 3D point array for the current link
newPoints = []
for n in range(N-1):
# t = 2*pi / links * n/(N-1) with: da = 2*pi/links/(N-1) => t = n * da
for n in range(N - 1):
# t = 2 * pi / links * n/(N-1) with: da = 2*pi/links/(N-1) => t = n * da
t = n * da
theta = p*t*u + rPhase # revolution angle
phi = q*t*v + sPhase # spin angle
theta = p * t * u + rPhase # revolution angle
phi = q * t * v + sPhase # spin angle
x = (R + r*cos(phi)) * cos(theta)
y = (R + r*cos(phi)) * sin(theta)
z = r*sin(phi) * h
x = (R + r * cos(phi)) * cos(theta)
y = (R + r * cos(phi)) * sin(theta)
z = r * sin(phi) * h
# append 3D point
# NOTE : the array is adjusted later as needed to 4D for POLY and NURBS
# append 3D point
# NOTE : the array is adjusted later as needed to 4D for POLY and NURBS
newPoints.append([x, y, z])
return newPoints
# ------------------------------------------------------------------------------
# Calculate the align matrix for the new object (based on user preferences)
def align_matrix(self, context):
if self.absolute_location:
loc = Matrix.Translation(Vector((0, 0, 0)))
@ -161,8 +163,10 @@ def align_matrix(self, context):
align_matrix = userLoc * loc * rot * userRot
return align_matrix
# ------------------------------------------------------------------------------
# Set curve BEZIER handles to auto
def setBezierHandles(obj, mode='AUTOMATIC'):
scene = bpy.context.scene
if obj.type != 'CURVE':
@ -173,18 +177,20 @@ def setBezierHandles(obj, mode='AUTOMATIC'):
bpy.ops.curve.handle_type_set(type=mode)
bpy.ops.object.mode_set(mode='OBJECT', toggle=True)
# ------------------------------------------------------------------------------
# Convert array of vert coordinates to points according to spline type
def vertsToPoints(Verts, splineType):
# main vars
vertArray = []
# array for BEZIER spline output (V3)
# array for BEZIER spline output (V3)
if splineType == 'BEZIER':
for v in Verts:
vertArray += v
# array for non-BEZIER output (V4)
# array for non-BEZIER output (V4)
else:
for v in Verts:
vertArray += v
@ -195,20 +201,22 @@ def vertsToPoints(Verts, splineType):
return vertArray
# ------------------------------------------------------------------------------
# Create the Torus Knot curve and object and add it to the scene
def create_torus_knot(self, context):
# pick a name based on (p,q) parameters
aName = "Torus Knot %i x %i" % (self.torus_p, self.torus_q)
# create curve
# create curve
curve_data = bpy.data.curves.new(name=aName, type='CURVE')
# setup materials to be used for the TK links
# setup materials to be used for the TK links
if self.use_colors:
addLinkColors(self, curve_data)
# create torus knot link(s)
# create torus knot link(s)
if self.multiple_links:
links = gcd(self.torus_p, self.torus_q)
else:
@ -218,34 +226,34 @@ def create_torus_knot(self, context):
# get vertices for the current link
verts = Torus_Knot(self, l)
# output splineType 'POLY' 'NURBS' or 'BEZIER'
# output splineType 'POLY' 'NURBS' or 'BEZIER'
splineType = self.outputType
# turn verts into proper array (based on spline type)
# turn verts into proper array (based on spline type)
vertArray = vertsToPoints(verts, splineType)
# create spline from vertArray (based on spline type)
# create spline from vertArray (based on spline type)
spline = curve_data.splines.new(type=splineType)
if splineType == 'BEZIER':
spline.bezier_points.add(int(len(vertArray)*1.0/3-1))
spline.bezier_points.add(int(len(vertArray) * 1.0 / 3 - 1))
spline.bezier_points.foreach_set('co', vertArray)
else:
spline.points.add(int(len(vertArray)*1.0/4 - 1))
spline.points.add(int(len(vertArray) * 1.0 / 4 - 1))
spline.points.foreach_set('co', vertArray)
spline.use_endpoint_u = True
# set curve options
# set curve options
spline.use_cyclic_u = True
spline.order_u = 4
# set a color per link
# set a color per link
if self.use_colors:
spline.material_index = l
curve_data.dimensions = '3D'
curve_data.resolution_u = self.segment_res
# create surface ?
# create surface ?
if self.geo_surface:
curve_data.fill_mode = 'FULL'
curve_data.bevel_depth = self.geo_bDepth
@ -255,21 +263,23 @@ def create_torus_knot(self, context):
new_obj = bpy.data.objects.new(aName, curve_data)
# set object in the scene
# set object in the scene
scene = bpy.context.scene
scene.objects.link(new_obj) # place in active scene
new_obj.select = True # set as selected
scene.objects.active = new_obj # set as active
new_obj.matrix_world = self.align_matrix # apply matrix
# set BEZIER handles
# set BEZIER handles
if splineType == 'BEZIER':
setBezierHandles(new_obj, self.handleType)
return
# ------------------------------------------------------------------------------
# Create materials to be assigned to each TK link
def addLinkColors(self, curveData):
# some predefined colors for the torus knot links
colors = []
@ -295,13 +305,12 @@ def addLinkColors(self, curveData):
colors += [[1.0, 0.0, 0.0]]
me = curveData
mat_offset = len(me.materials)
links = gcd(self.torus_p, self.torus_q)
mats = []
for i in range(links):
matName = "TorusKnot-Link-%i" % i
matListNames = bpy.data.materials.keys()
# create the material
# create the material
if matName not in matListNames:
if DEBUG:
print("Creating new material : %s" % matName)
@ -311,7 +320,7 @@ def addLinkColors(self, curveData):
print("Material %s already exists" % matName)
mat = bpy.data.materials[matName]
# set material color
# set material color
if self.options_plus and self.random_colors:
mat.diffuse_color = random(), random(), random()
else:
@ -325,10 +334,11 @@ def addLinkColors(self, curveData):
me.materials.append(mat)
# ------------------------------------------------------------------------------
# Main Torus Knot class
class torus_knot_plus(Operator, AddObjectHelper):
""""""
bl_idname = "curve.torus_knot_plus"
bl_label = "Torus Knot +"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
@ -341,10 +351,10 @@ class torus_knot_plus(Operator, AddObjectHelper):
self.torus_eR = self.torus_R + self.torus_r
self.torus_iR = self.torus_R - self.torus_r
# align_matrix for the invoke
# align_matrix for the invoke
align_matrix = None
# GENERAL options
# GENERAL options
options_plus = BoolProperty(
name="Extra Options",
default=False,
@ -355,8 +365,7 @@ class torus_knot_plus(Operator, AddObjectHelper):
default=False,
description="Set absolute location instead of relative to 3D cursor",
)
# COLOR options
# COLOR options
use_colors = BoolProperty(
name="Use Colors",
default=False,
@ -364,8 +373,8 @@ class torus_knot_plus(Operator, AddObjectHelper):
)
colorSet = EnumProperty(
name="Color Set",
items=(('1', 'RGBish', 'RGBsish ordered colors'),
('2', 'Rainbow', 'Rainbow ordered colors')),
items=(('1', "RGBish", "RGBsish ordered colors"),
('2', "Rainbow", "Rainbow ordered colors")),
)
random_colors = BoolProperty(
name="Randomize Colors",
@ -378,8 +387,7 @@ class torus_knot_plus(Operator, AddObjectHelper):
min=0.0, max=1.0,
description="Color saturation",
)
# SURFACE Options
# SURFACE Options
geo_surface = BoolProperty(
name="Surface",
default=True,
@ -410,46 +418,45 @@ class torus_knot_plus(Operator, AddObjectHelper):
min=0, soft_min=0,
description="Offset the surface relative to the curve"
)
# TORUS KNOT Options
# TORUS KNOT Options
torus_p = IntProperty(
name="p",
default=2,
min=1, soft_min=1,
description="Number of REVOLUTIONs around the torus hole before closing the knot"
description="Number of Revolutions around the torus hole before closing the knot"
)
torus_q = IntProperty(
name="q",
default=3,
min=1, soft_min=1,
description="Number of SPINs through the torus hole before closing the knot"
description="Number of Spins through the torus hole before closing the knot"
)
flip_p = BoolProperty(
name="Flip p",
default=False,
description="Flip REVOLUTION direction"
description="Flip Revolution direction"
)
flip_q = BoolProperty(
name="Flip q",
default=False,
description="Flip SPIN direction"
description="Flip Spin direction"
)
multiple_links = BoolProperty(
name="Multiple Links",
default=True,
description="Generate ALL links or just ONE link when q and q are not co-primes"
description="Generate all links or just one link when q and q are not co-primes"
)
torus_u = IntProperty(
name="p multiplier",
name="Rev. Multiplier",
default=1,
min=1, soft_min=1,
description="p multiplier"
description="Revolutions Multiplier"
)
torus_v = IntProperty(
name="q multiplier",
name="Spin Multiplier",
default=1,
min=1, soft_min=1,
description="q multiplier"
description="Spin multiplier"
)
torus_rP = FloatProperty(
name="Revolution Phase",
@ -463,8 +470,7 @@ class torus_knot_plus(Operator, AddObjectHelper):
min=0.0, soft_min=0.0,
description="Phase spins by this radian amount"
)
# TORUS DIMENSIONS options
# TORUS DIMENSIONS options
mode = EnumProperty(
name="Torus Dimensions",
items=(("MAJOR_MINOR", "Major/Minor",
@ -517,8 +523,7 @@ class torus_knot_plus(Operator, AddObjectHelper):
min=0.0, max=100.0,
description="Scale along the local Z axis"
)
# CURVE options
# CURVE options
torus_res = IntProperty(
name="Curve Resolution",
default=100,
@ -532,9 +537,9 @@ class torus_knot_plus(Operator, AddObjectHelper):
description="Curve subdivisions per segment"
)
SplineTypes = [
('POLY', 'Poly', 'POLY'),
('NURBS', 'Nurbs', 'NURBS'),
('BEZIER', 'Bezier', 'BEZIER')]
('POLY', "Poly", "Poly type"),
('NURBS', "Nurbs", "Nurbs type"),
('BEZIER', "Bezier", "Bezier type")]
outputType = EnumProperty(
name="Output splines",
default='BEZIER',
@ -542,8 +547,8 @@ class torus_knot_plus(Operator, AddObjectHelper):
items=SplineTypes,
)
bezierHandles = [
('VECTOR', 'Vector', 'VECTOR'),
('AUTOMATIC', 'Auto', 'AUTOMATIC'),
('VECTOR', "Vector", "Bezier Hanles type - Vector"),
('AUTOMATIC', "Auto", "Bezier Hanles type - Automatic"),
]
handleType = EnumProperty(
name="Handle type",
@ -557,122 +562,127 @@ class torus_knot_plus(Operator, AddObjectHelper):
description="Auto adjust curve resolution based on TK length",
)
##### DRAW #####
def draw(self, context):
layout = self.layout
# extra parameters toggle
layout.prop(self, 'options_plus')
# extra parameters toggle
layout.prop(self, "options_plus")
# TORUS KNOT Parameters
# TORUS KNOT Parameters
col = layout.column()
col.label(text="Torus Knot Parameters:")
box = layout.box()
row = box.row()
row.column().prop(self, 'torus_p')
row.column().prop(self, 'flip_p')
row = box.row()
row.column().prop(self, 'torus_q')
row.column().prop(self, 'flip_q')
split = box.split(percentage=0.85, align=True)
split.prop(self, "torus_p", text="Revolutions")
split.prop(self, "flip_p", toggle=True, text="",
icon="ARROW_LEFTRIGHT")
split = box.split(percentage=0.85, align=True)
split.prop(self, "torus_q", text="Spins")
split.prop(self, "flip_q", toggle=True, text="",
icon="ARROW_LEFTRIGHT")
links = gcd(self.torus_p, self.torus_q)
info = "Multiple Links"
if links > 1:
info += " ( " + str(links) + " )"
box.prop(self, 'multiple_links', text=info)
if self.options_plus:
box = box.box()
box.prop(self, 'torus_u')
box.prop(self, 'torus_v')
box.prop(self, 'torus_rP')
box.prop(self, 'torus_sP')
col = box.column(align=True)
col.prop(self, "torus_u")
col.prop(self, "torus_v")
# TORUS DIMENSIONS options
col = box.column(align=True)
col.prop(self, "torus_rP")
col.prop(self, "torus_sP")
# TORUS DIMENSIONS options
col = layout.column(align=True)
col.label(text="Torus Dimensions:")
box = layout.box()
col = box.column(align=True)
col.row().prop(self, "mode", expand=True)
if self.mode == 'MAJOR_MINOR':
if self.mode == "MAJOR_MINOR":
col = box.column(align=True)
col.prop(self, "torus_R")
col = box.column(align=True)
col.prop(self, "torus_r")
else: # EXTERIOR-INTERIOR
col = box.column(align=True)
col.prop(self, "torus_eR")
col = box.column(align=True)
col.prop(self, "torus_iR")
if self.options_plus:
box = box.box()
box.prop(self, 'torus_s')
box.prop(self, 'torus_h')
col = box.column(align=True)
col.prop(self, "torus_s")
col.prop(self, "torus_h")
# CURVE options
# CURVE options
col = layout.column(align=True)
col.label(text="Curve Options:")
box = layout.box()
col = box.column()
col.label(text="Output Curve Type:")
col.row().prop(self, 'outputType', expand=True)
col.row().prop(self, "outputType", expand=True)
depends = box.column()
depends.prop(self, 'torus_res')
# deactivate the "curve resolution" if "adaptive resolution" is enabled
depends.prop(self, "torus_res")
# deactivate the "curve resolution" if "adaptive resolution" is enabled
depends.enabled = not self.adaptive_resolution
box.prop(self, 'adaptive_resolution')
box.prop(self, 'segment_res')
box.prop(self, "adaptive_resolution")
box.prop(self, "segment_res")
# SURFACE options
# SURFACE options
col = layout.column()
col.label(text="Geometry Options:")
box = layout.box()
box.prop(self, 'geo_surface')
box.prop(self, "geo_surface")
if self.geo_surface:
box.prop(self, 'geo_bDepth')
box.prop(self, 'geo_bRes')
box.prop(self, 'geo_extrude')
box.prop(self, 'geo_offset')
col = box.column(align=True)
col.prop(self, "geo_bDepth")
col.prop(self, "geo_bRes")
# COLOR options
col = box.column(align=True)
col.prop(self, "geo_extrude")
col.prop(self, "geo_offset")
# COLOR options
col = layout.column()
col.label(text="Color Options:")
box = layout.box()
box.prop(self, 'use_colors')
box.prop(self, "use_colors")
if self.use_colors and self.options_plus:
box = box.box()
box.prop(self, 'colorSet')
box.prop(self, 'random_colors')
box.prop(self, 'saturation')
box.prop(self, "colorSet")
box.prop(self, "random_colors")
box.prop(self, "saturation")
# TRANSFORM options
# TRANSFORM options
col = layout.column()
col.label(text="Transform Options:")
box = col.box()
box.prop(self, 'location')
box.prop(self, 'absolute_location')
box.prop(self, 'rotation')
box.prop(self, "location")
box.prop(self, "absolute_location")
box.prop(self, "rotation")
##### POLL #####
@classmethod
def poll(cls, context):
if context.mode != "OBJECT":
return False
return context.scene is not None
##### EXECUTE #####
def execute(self, context):
if self.mode == 'EXT_INT':
# adjust the equivalent radii pair : (R,r) <=> (eR,iR)
self.torus_R = (self.torus_eR + self.torus_iR)*0.5
self.torus_r = (self.torus_eR - self.torus_iR)*0.5
self.torus_R = (self.torus_eR + self.torus_iR) * 0.5
self.torus_r = (self.torus_eR - self.torus_iR) * 0.5
if self.adaptive_resolution:
# adjust curve resolution automatically based on (p,q,R,r) values
@ -681,30 +691,35 @@ class torus_knot_plus(Operator, AddObjectHelper):
R = self.torus_R
r = self.torus_r
links = gcd(p, q)
# get an approximate length of the whole TK curve
maxTKLen = 2*pi*sqrt(p*p*(R+r)*(R+r) + q*q*r*r) # upper bound approximation
minTKLen = 2*pi*sqrt(p*p*(R-r)*(R-r) + q*q*r*r) # lower bound approximation
avgTKLen = (minTKLen + maxTKLen)/2 # average approximation
# get an approximate length of the whole TK curve
# upper bound approximation
maxTKLen = 2 * pi * sqrt(p * p * (R + r) * (R + r) + q * q * r * r)
# lower bound approximation
minTKLen = 2 * pi * sqrt(p * p * (R - r) * (R - r) + q * q * r * r)
avgTKLen = (minTKLen + maxTKLen) / 2 # average approximation
if DEBUG:
print("Approximate average TK length = %.2f" % avgTKLen)
self.torus_res = max(3, avgTKLen/links * 8) # x N factor = control points per unit length
# update align matrix
# x N factor = control points per unit length
self.torus_res = max(3, avgTKLen / links * 8)
# update align matrix
self.align_matrix = align_matrix(self, context)
# turn off undo
# turn off undo
undo = bpy.context.user_preferences.edit.use_global_undo
bpy.context.user_preferences.edit.use_global_undo = False
# create the curve
# create the curve
create_torus_knot(self, context)
# restore pre operator undo state
# restore pre operator undo state
bpy.context.user_preferences.edit.use_global_undo = undo
return {'FINISHED'}
##### INVOKE #####
def invoke(self, context, event):
self.execute(context)

View File

@ -1,91 +1,99 @@
# gpl: author Folkert de Vries
bl_info = {
"name": "Surface: plane/cone/star/wedge",
"description": "create a NURBS surface plane.",
"name": "Surface: Plane / Cone/ Star / Wedge",
"description": "Create a NURBS surface plane",
"author": "Folkert de Vries",
"version": (1, 0),
"version": (1, 0, 1),
"blender": (2, 5, 9),
"api": 31236,
"location": "View3D > Add> Surface",
"warning": '', # used for warning icon and text in addons panel
"wiki_url": " "\
" ",
"tracker_url": " "\
" ",
"location": "View3D > Add > Surface",
"warning": "",
"wiki_url": "",
"category": "Add Mesh"
}
# info:
'''
to add a surface star, plane or cone, go to add menu>surface>star,plane or cone
next parameters like scale and u and v resolution can be adjusted in the toolshelf.
have fun using this addon
'''
"""
Info:
to add a surface star, plane or cone, go to add Menu > Surface > Star, Plane or Cone
next parameters like scale and u and v resolution can be adjusted in the toolshelf
have fun using this add-on
"""
import bpy
from bpy.props import (
FloatProperty,
IntProperty,
)
from bpy.types import Operator
from bpy.utils import register_class, unregister_class
class MakeSurfaceWedge(Operator):
bl_idname = 'object.add_surface_wedge'
bl_label = 'Add Surface Wedge'
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_context = "object"
bl_options = {'REGISTER', 'UNDO'}
# get input for size and resolution
# generic class for inheritance
class MakeSurfaceHelpers:
# get input for size and resolution
size = FloatProperty(
name="Size",
description="Size of the object",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH",
)
name="Size",
description="Size of the object",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH",
)
res_u = IntProperty(
name="Resolution U",
description="Surface resolution in u direction",
default=1,
min=1,
max=500,
)
name="Resolution U",
description="Surface resolution in u direction",
default=1,
min=1,
max=500,
)
res_v = IntProperty(
name="Resolution V",
description="Surface resolution in v direction",
default=1,
min=1,
max=500,
)
name="Resolution V",
description="Surface resolution in v direction",
default=1,
min=1,
max=500,
)
@classmethod
def poll(cls, context):
return context.mode == 'OBJECT'
def draw(self, context):
layout = self.layout
layout.prop(self, "size")
col = layout.column(align=True)
col.prop(self, "res_u")
col.prop(self, "res_v")
class MakeSurfaceWedge(Operator, MakeSurfaceHelpers):
bl_idname = "object.add_surface_wedge"
bl_label = "Add Surface Wedge"
bl_description = "Construct a Surface Wedge"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
# variables
size = self.size
res_u = self.res_u
res_v = self.res_v
# add a surface Plane
bpy.ops.object.add_surface_plane()
# save some time, by getting instant acces to those values.
# save some time, by getting instant acces to those values
ao = context.active_object
point = ao.data.splines[0].points
# rotate 90 degrees on the z axis
ao.rotation_euler[0] = 0.0
ao.rotation_euler[1] = 0.0
ao.rotation_euler[2] = 1.570796
# go into edit mode and deselect
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.curve.select_all(action='DESELECT')
# select points 0 and 1, and extrudde them
# declaring ao and point again seems necesary...
ao = context.active_object
@ -124,44 +132,13 @@ class MakeSurfaceWedge(Operator):
return{'FINISHED'}
positions = [(1.0, 1.0, -1.0, 1.0), (1.0, -1.0, -1.0, 1.0), (-1.0, -1.0, -1.0, 1.0), (-1.0, 1.0, -1.0, 1.0), (1.0, 0.0, 1.0, 1.0), (-1.0, 0.0, 1.0, 1.0)]
class MakeSurfaceCone(Operator):
bl_idname = 'object.add_surface_cone'
bl_label = 'Add Surface Cone'
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_context = "object"
class MakeSurfaceCone(Operator, MakeSurfaceHelpers):
bl_idname = "object.add_surface_cone"
bl_label = "Add Surface Cone"
bl_description = "Construct a Surface Cone"
bl_options = {'REGISTER', 'UNDO'}
size = FloatProperty(
name="Size",
description="Size of the object",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH",
)
res_u = IntProperty(
name="Resolution U",
description="Surface resolution in u direction",
default=4,
min=1,
max=500,
)
res_v = IntProperty(
name="Resolution V",
description="Surface resolution in v direction",
default=4,
min=1,
max=500,
)
@classmethod
def poll(cls, context):
return context.mode == 'OBJECT'
def execute(self, context):
size = self.size
res_u = self.res_u
@ -170,8 +147,9 @@ class MakeSurfaceCone(Operator):
# add basemesh, a nurbs torus
bpy.ops.surface.primitive_nurbs_surface_torus_add(location=(0, 0, 0))
# get active object and active object name
ao = context.active_object
aoname = context.active_object.name
# go to edit mode
bpy.ops.object.mode_set(mode='EDIT')
# deselect all
@ -194,6 +172,7 @@ class MakeSurfaceCone(Operator):
ToKeep = [1, 3, 5, 7, 9, 11, 13, 15, 17]
for i in range(0, len(ToKeep) - 1):
point[ToKeep[i]].select = True
bpy.ops.transform.resize(value=(0, 0, 0))
bpy.ops.curve.cyclic_toggle(direction='CYCLIC_U')
bpy.ops.transform.translate(value=(0, 0, 2))
@ -218,41 +197,12 @@ class MakeSurfaceCone(Operator):
return{'FINISHED'}
class MakeSurfaceStar(Operator):
bl_idname = 'object.add_surface_star'
bl_label = 'Add Surface Star'
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_context = "object"
class MakeSurfaceStar(Operator, MakeSurfaceHelpers):
bl_idname = "object.add_surface_star"
bl_label = "Add Surface Star"
bl_description = "Contruct a Surface Star"
bl_options = {'REGISTER', 'UNDO'}
size = FloatProperty(
name="Size",
description="Size of the object",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH",
)
res_u = IntProperty(
name="Resolution U",
description="Surface resolution in u direction",
default=1,
min=1,
max=500,
)
res_v = IntProperty(
name="Resolution V",
description="Surface resolution in v direction",
default=1,
min=1,
max=500,
)
@classmethod
def poll(cls, context):
return context.mode == 'OBJECT'
def execute(self, context):
size = self.size
res_u = self.res_u
@ -281,16 +231,18 @@ class MakeSurfaceStar(Operator):
bpy.ops.curve.subdivide()
bpy.ops.curve.select_all(action='DESELECT')
ListOfCoords = [(0.5, 0.0, 0.25, 1.0),
(0.80901700258255, 0.5877853035926819, 0.25, 1.0),
(0.1545085906982422, 0.4755282402038574, 0.25, 1.0),
(-0.30901703238487244, 0.9510565400123596, 0.25, 1.0),
(-0.4045085608959198, 0.293892502784729, 0.2499999850988388, 1.0),
(-1.0, 0.0, 0.25, 1.0),
(-0.4045085608959198, -0.293892502784729, 0.2499999850988388, 1.0),
(-0.30901703238487244, -0.9510565400123596, 0.25, 1.0),
(0.1545085906982422, -0.4755282402038574, 0.25, 1.0),
(0.8090166449546814, -0.5877856612205505, 0.2499999850988388, 1.0)]
ListOfCoords = [
(0.5, 0.0, 0.25, 1.0),
(0.80901700258255, 0.5877853035926819, 0.25, 1.0),
(0.1545085906982422, 0.4755282402038574, 0.25, 1.0),
(-0.30901703238487244, 0.9510565400123596, 0.25, 1.0),
(-0.4045085608959198, 0.293892502784729, 0.2499999850988388, 1.0),
(-1.0, 0.0, 0.25, 1.0),
(-0.4045085608959198, -0.293892502784729, 0.2499999850988388, 1.0),
(-0.30901703238487244, -0.9510565400123596, 0.25, 1.0),
(0.1545085906982422, -0.4755282402038574, 0.25, 1.0),
(0.8090166449546814, -0.5877856612205505, 0.2499999850988388, 1.0)
]
for i in range(0, 10):
context.active_object.data.splines[0].points[i].co = ListOfCoords[i]
@ -303,7 +255,10 @@ class MakeSurfaceStar(Operator):
# extrude the star
bpy.ops.curve.extrude(mode='TRANSLATION')
# bring extruded part up
bpy.ops.transform.translate(value=(0, 0, 0.5), constraint_axis=(False, False, True))
bpy.ops.transform.translate(
value=(0, 0, 0.5),
constraint_axis=(False, False, True)
)
# flip normals
bpy.ops.curve.switch_direction()
# go back to object mode
@ -324,41 +279,12 @@ class MakeSurfaceStar(Operator):
return{'FINISHED'}
class MakeSurfacePlane(Operator):
bl_idname = 'object.add_surface_plane'
bl_label = 'Add Surface Plane'
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_context = "object"
class MakeSurfacePlane(Operator, MakeSurfaceHelpers):
bl_idname = "object.add_surface_plane"
bl_label = "Add Surface Plane"
bl_description = "Contruct a Surface Plane"
bl_options = {'REGISTER', 'UNDO'}
size = FloatProperty(
name="Size",
description="Size of the object",
default=1.0,
min=0.01,
max=100.0,
unit="LENGTH",
)
res_u = IntProperty(
name="Resolution U",
description="Surface resolution in u direction",
default=1,
min=1,
max=500,
)
res_v = IntProperty(
name="Resolution V",
description="Surface resolution in v direction",
default=1,
min=1,
max=500,
)
@classmethod
def poll(cls, context):
return context.mode == 'OBJECT'
def execute(self, context):
size = self.size
res_u = self.res_u
@ -366,11 +292,14 @@ class MakeSurfacePlane(Operator):
bpy.ops.surface.primitive_nurbs_surface_surface_add() # add the base mesh, a NURBS Surface
bpy.ops.transform.resize(value=(1, 1, 0.0001), constraint_axis=(False, False, True)) # make it flat
ao = context.active_object.name # get the active object' s name
bpy.ops.transform.resize(
value=(1, 1, 0.0001),
constraint_axis=(False, False, True)
) # make it flat
# added surface has 16 points
# deleting points to get plane shape.
# deleting points to get plane shape
bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.curve.select_all(action='DESELECT')
@ -394,7 +323,7 @@ class MakeSurfacePlane(Operator):
bpy.ops.curve.delete(type='VERT')
# assigning name
context.active_object.name = 'SurfacePlane'
context.active_object.name = "SurfacePlane"
# select all
bpy.ops.curve.select_all(action='SELECT')
# bringing origin to center:
@ -402,7 +331,8 @@ class MakeSurfacePlane(Operator):
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='MEDIAN')
# transform scale
bpy.ops.object.transform_apply(scale=True)
# bring object to 3d cursor.
# bring object to 3d cursor
bpy.ops.object.mode_set(mode='OBJECT')
context.active_object.location = context.scene.cursor_location
bpy.ops.transform.resize(value=(size, size, size))
@ -415,81 +345,53 @@ class MakeSurfacePlane(Operator):
class SmoothXtimes(Operator):
bl_idname = 'curve.smooth_x_times'
bl_label = 'Smooth X Times'
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_context = "object"
bl_idname = "curve.smooth_x_times"
bl_label = "Smooth X Times"
bl_space_type = "VIEW_3D"
bl_options = {'REGISTER', 'UNDO'}
'''use of this class:
lets you smooth till a thousand times. this is normally difficult, because
you have to press w, click, press w, click ect.'''
# use of this class:
# lets you smooth till a thousand times. this is normally difficult, because
# you have to press w, click, press w, click etc.
# get values
times = IntProperty(name='smooth x times',
min=1,
max=1000,
default=1,
description='amount of smooths')
times = IntProperty(
name="Smooth x Times",
min=1,
max=1000,
default=1,
description="Smooth amount"
)
@classmethod
def poll(cls, context):
return context.mode == 'EDIT_SURFACE'
def execute(self, context):
# smooth times time(s).
# smooth times
times = self.times
for i in range(1, times):
bpy.ops.curve.smooth()
return{'FINISHED'}
def Surface_plane_button(self, context):
self.layout.operator(MakeSurfacePlane.bl_idname, text="surface plane", icon="MOD_CURVE")
def Surface_cone_button(self, context):
self.layout.operator(MakeSurfaceCone.bl_idname, text="surface cone", icon="MOD_CURVE")
def Surface_star_button(self, context):
self.layout.operator(MakeSurfaceStar.bl_idname, text="surface star", icon="MOD_CURVE")
def Surface_wedge_button(self, context):
self.layout.operator(MakeSurfaceWedge.bl_idname, text="surface wedge", icon="MOD_CURVE")
def SmoothXtimes_button(self, context):
self.layout.operator(SmoothXtimes.bl_idname, text="smooth x times", icon="MOD_CURVE")
def register():
register_class(UserInterface)
register_class(MakeSurfacePlane)
register_class(MakeSurfaceCone)
register_class(MakeSurfaceStar)
register_class(MakeSurfaceWedge)
register_class(SmoothXtimes)
bpy.types.INFO_MT_surface_add.append(Surface_plane_button)
bpy.types.INFO_MT_surface_add.append(Surface_cone_button)
bpy.types.INFO_MT_surface_add.append(Surface_star_button)
bpy.types.INFO_MT_surface_add.append(Surface_wedge_button)
bpy.types.VIEW3D_MT_edit_curve_specials.append(SmoothXtimes_button)
bpy.utils.register_class(MakeSurfaceHelpers)
bpy.utils.register_class(MakeSurfacePlane)
bpy.utils.register_class(MakeSurfaceCone)
bpy.utils.register_class(MakeSurfaceStar)
bpy.utils.register_class(MakeSurfaceWedge)
bpy.utils.register_class(SmoothXtimes)
def unregister():
unregister_class(UserInterface)
unregister_class(MakeSurfacePlane)
unregister_class(MakeSurfaceCone)
unregister_class(MakeSurfaceStar)
unregister_class(MakeSurfaceWedge)
unregister_class(SmoothXtimes)
bpy.types.INFO_MT_surface_add.remove(Surface_plane_button)
bpy.types.INFO_MT_surface_add.remove(Surface_cone_button)
bpy.types.INFO_MT_surface_add.remove(Surface_star_button)
bpy.types.INFO_MT_surface_add.remove(Surface_wedge_button)
bpy.types.VIEW3D_MT_edit_curve_specials.remove(SmoothXtimes_button)
bpy.utils.unregister_class(MakeSurfaceHelpers)
bpy.utils.unregister_class(MakeSurfacePlane)
bpy.utils.unregister_class(MakeSurfaceCone)
bpy.utils.unregister_class(MakeSurfaceStar)
bpy.utils.unregister_class(MakeSurfaceWedge)
bpy.utils.unregister_class(SmoothXtimes)
if __name__ == "__main__":

View File

@ -1,3 +1,22 @@
# ##### 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 #####
# DevBo Task: https://developer.blender.org/T37377
bl_info = {
"name": "Bevel/Taper Curve",
"author": "Cmomoney",
@ -6,234 +25,374 @@ bl_info = {
"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",
"wiki_url": "https://wiki.blender.org/index.php/Extensions:2.6/"
"Py/Scripts/Curve/Bevel_-Taper_Curve",
"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
from bpy.types import (
Operator,
Menu,
)
from bpy.props import (
BoolProperty,
FloatProperty,
IntProperty,
)
from bpy_extras.object_utils import (
AddObjectHelper,
object_data_add,
)
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)]
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):
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)]]
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)]]
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)]]
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)]]
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)]]
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):
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))
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
def make_curve(self, context, verts, lh, rh):
target = bpy.context.scene.objects.active
curve_data = bpy.data.curves.new(name=target.name +'_Bevel', type='CURVE')
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.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"""
class add_tapercurve(Operator):
bl_idname = "curve.tapercurve"
bl_label = "Add Curve as Taper"
bl_description = ("Add taper curve to Active Curve\n"
"Needs an existing Active Curve")
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",
description="Link the End Width Left / Right settings\n"
"End Width Left will be editable ",
default=True
)
link2 = BoolProperty(
name="Link Ends / Center",
description="Link the End Widths with the Center Width",
default=False
)
diff = FloatProperty(
name="Difference",
default=1,
description="Difference between ends and center while linked"
)
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')
@classmethod
def poll(cls, context):
obj = context.active_object
return context.mode == 'OBJECT' and obj and obj.type == "CURVE"
def draw(self, context):
layout = self.layout
col = layout.column(align=True)
col.label("Settings:")
split = layout.split(percentage=0.95, align=True)
split.active = not self.link2
col = split.column(align=True)
col.prop(self, "scale_ends1")
row = split.row(align=True)
row.scale_y = 2.0
col_sub = col.column(align=True)
col_sub.active = not self.link1
col_sub.prop(self, "scale_ends2")
row.prop(self, "link1", toggle=True, text="", icon="LINKED")
split = layout.split(percentage=0.95, align=True)
col = split.column(align=True)
col.prop(self, "scale_mid")
row = split.row(align=True)
row.scale_y = 2.0
col_sub = col.column(align=True)
col_sub.active = self.link2
row.prop(self, "link2", toggle=True, text="", icon="LINKED")
col_sub.prop(self, "diff")
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
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_description = ("Add bevel curve to Active Curve\n"
"Needs an existing Active Curve")
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)
types = 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",
description="Link the Scale on X/Y axis",
default=True
)
@classmethod
def poll(cls, context):
obj = context.active_object
return context.mode == 'OBJECT' and obj and obj.type == "CURVE"
def draw(self, context):
layout = self.layout
col = layout.column(align=True)
# AddObjectHelper props
col.prop(self, "view_align")
col.prop(self, "location")
col.prop(self, "rotation")
col = layout.column(align=True)
col.label("Settings:")
col.prop(self, "types")
split = layout.split(percentage=0.95, align=True)
col = split.column(align=True)
col.prop(self, "scale_x")
row = split.row(align=True)
row.scale_y = 2.0
col.prop(self, "scale_y")
row.prop(self, "link", toggle=True, text="", icon="LINKED")
def execute(self, context):
if self.link:
self.scale_y = self.scale_x
if self.type == 1:
if self.types == 1:
add_type1(self, context)
if self.type == 2:
if self.types == 2:
add_type2(self, context)
if self.type == 3:
if self.types == 3:
add_type3(self, context)
if self.type == 4:
if self.types == 4:
add_type4(self, context)
if self.type == 5:
if self.types == 5:
add_type5(self, context)
return {'FINISHED'}
class Bevel_Taper_Curve_Menu(bpy.types.Menu):
class Bevel_Taper_Curve_Menu(Menu):
bl_label = "Bevel/Taper"
bl_idname = "OBJECT_MT_bevel_taper_curve_menu"
@ -243,17 +402,21 @@ class Bevel_Taper_Curve_Menu(bpy.types.Menu):
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

@ -1,84 +0,0 @@
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

@ -1,60 +0,0 @@
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