Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormeta-androcto <meta.androcto1@gmail.com>2017-04-25 13:54:55 +0300
committermeta-androcto <meta.androcto1@gmail.com>2017-04-25 13:54:55 +0300
commit83bdf81f5fda9d33960280d322207f361b74fe87 (patch)
treee2c66b4dc83c8bcdf8ef944fdf48547da17f2bd8 /add_curve_extra_objects/add_curve_spirofit_bouncespline.py
parent0ca01cc32d5543ecb77c9a91cbdcfd37eaa07b43 (diff)
curve extra objects: bounce spline, spirofit, catenary update
Diffstat (limited to 'add_curve_extra_objects/add_curve_spirofit_bouncespline.py')
-rw-r--r--add_curve_extra_objects/add_curve_spirofit_bouncespline.py869
1 files changed, 616 insertions, 253 deletions
diff --git a/add_curve_extra_objects/add_curve_spirofit_bouncespline.py b/add_curve_extra_objects/add_curve_spirofit_bouncespline.py
index 7be535ab..f40c7680 100644
--- a/add_curve_extra_objects/add_curve_spirofit_bouncespline.py
+++ b/add_curve_extra_objects/add_curve_spirofit_bouncespline.py
@@ -18,12 +18,12 @@
bl_info = {
- "name": "SpiroFit and BounceSpline",
+ "name": "SpiroFit, BounceSpline and Catenary",
"author": "Antonio Osprite, Liero, Atom, Jimmy Hazevoet",
"version": (0, 2, 0),
"blender": (2, 78, 0),
- "location": "Toolshelf > Misc Tab",
- "description": "SpiroFit and BounceSpline adds splines to Mesh",
+ "location": "Toolshelf > Create Tab",
+ "description": "SpiroFit and BounceSpline adds splines to selected mesh",
"warning": "",
"wiki_url": "",
"category": "Object",
@@ -37,6 +37,7 @@ from bpy.props import (
FloatProperty,
IntProperty,
)
+from bpy.types import Operator
from mathutils import (
Matrix,
Vector,
@@ -44,14 +45,14 @@ from mathutils import (
from math import (
sin,
cos,
- pi
+ pi,
+ sqrt,
+ pow
)
-from bpy.types import Operator
import random as r
-
# ------------------------------------------------------------
-#
+
def use_random_seed(seed):
r.seed(seed)
return
@@ -60,18 +61,26 @@ def use_random_seed(seed):
# Generate new curve object from given points
# ------------------------------------------------------------
-def add_curve_object(verts, matrix,
- x_ray=False,
- spline_type='BEZIER',
- spline_resolution=12,
- bevel=0.0,
- bevel_resolution=0,
- spline_random_radius=0.0):
-
- curve = bpy.data.curves.new('Spline','CURVE')
+def add_curve_object(
+ verts,
+ matrix,
+ spline_name="Spline",
+ x_ray=False,
+ spline_type='BEZIER',
+ spline_resolution=12,
+ bevel=0.0,
+ bevel_resolution=0,
+ extrude=0.0,
+ spline_random_radius=0.0,
+ twist_mode='MINIMUM',
+ twist_smooth=0.0,
+ tilt=0.0
+ ):
+
+ curve = bpy.data.curves.new(spline_name,'CURVE')
curve.dimensions = '3D'
spline = curve.splines.new(spline_type)
- cur = bpy.data.objects.new('Curve',curve)
+ cur = bpy.data.objects.new(spline_name,curve)
if spline_type == 'BEZIER':
spline.bezier_points.add(int(len(verts)-1))
@@ -80,6 +89,7 @@ def add_curve_object(verts, matrix,
spline.bezier_points[i].handle_right_type = 'AUTO'
spline.bezier_points[i].handle_left_type = 'AUTO'
spline.bezier_points[i].radius += r.random() * spline_random_radius
+ spline.bezier_points[i].tilt = tilt
else:
spline.points.add(int(len(verts)-1))
for i in range(len(verts)):
@@ -91,16 +101,44 @@ def add_curve_object(verts, matrix,
cur.data.fill_mode = 'FULL'
cur.data.bevel_depth = bevel
cur.data.bevel_resolution = bevel_resolution
- cur.matrix_world = matrix
- if x_ray:
+ cur.data.extrude = extrude
+ cur.data.twist_mode = twist_mode
+ cur.data.twist_smooth = twist_smooth
+ if matrix is None:
+ cur.select = True
+ bpy.ops.object.origin_set(type='ORIGIN_CENTER_OF_MASS')
+ cur.select = False
+ else:
+ cur.matrix_world = matrix
+ if x_ray is True:
cur.show_x_ray = x_ray
return
+#------------------------------------------------------------
+def draw_spline_settings(self, context):
+ layout = self.layout
+ col = layout.column(align=True)
+ col.prop(self, 'spline_type')
+ col.separator()
+ col.prop(self, 'resolution_u')
+ col.prop(self, 'bevel')
+ col.prop(self, 'bevel_res')
+ if self.spline_type == 'BEZIER':
+ col.prop(self, 'random_radius')
+ col.prop(self, 'extrude')
+ col.separator()
+ col.prop(self, 'twist_mode')
+ col.separator()
+ if self.twist_mode == 'TANGENT':
+ col.prop(self, 'twist_smooth')
+ col.prop(self, 'tilt')
+
# ------------------------------------------------------------
# Spirofit, original blender 2.45 script by: Antonio Osprite
# http://www.kino3d.com/forum/viewtopic.php?t=5374
# ------------------------------------------------------------
+# Build a spiral that fit the active object
def distance(v1, v2):
d = (Vector(v1) - Vector(v2)).length
@@ -114,26 +152,16 @@ def spiral_point(step, radius, z_coord, spires, waves, wave_height, rndm):
return [x, y, z]
-# ray cast
def object_mapping_ray_cast(obj, vert, center, offset):
- intersections = []
ray = Vector(vert)
orig = Vector(center)
direction = ray - orig
poly = obj.data.polygons
- for f in poly:
- foo, hit, nor, index = obj.ray_cast(orig, direction)
- if hit:
- intersections.append(hit + offset * nor)
-
- if len(intersections) > 0:
- mapped = min([(distance(i, vert), i) for i in intersections])[1]
- else:
- mapped = orig
+ foo, hit, nor, index = obj.ray_cast(orig, direction)
+ mapped = hit + offset * nor
return [mapped[0], mapped[1], mapped[2]]
-# closest point
def object_mapping_closest_point(obj, vert, offset):
cpom = obj.closest_point_on_mesh(vert)
mapped = cpom[1] + cpom[2] * offset
@@ -141,15 +169,15 @@ def object_mapping_closest_point(obj, vert, offset):
def spirofit_spline(obj,
- spires=4,
spire_resolution=4,
+ spires=4,
+ offset=0.0,
waves=0,
wave_height=0.0,
rndm_spire=0.0,
- offset=0.0,
+ direction=False,
map_method='RAYCAST'):
- points = []
bb = obj.bound_box
bb_xmin = min([ v[0] for v in bb ])
bb_ymin = min([ v[1] for v in bb ])
@@ -163,20 +191,16 @@ def spirofit_spline(obj,
cx = (bb_xmax + bb_xmin) / 2.0
cy = (bb_ymax + bb_ymin) / 2.0
center = [cx, cy, bb_zmin]
-
- cp = spiral_point(bb_zmin, radius, bb_zmin, spires, waves, wave_height, 0)
- if map_method == 'RAYCAST':
- cp = object_mapping_ray_cast(obj, cp, center, offset)
- elif map_method == 'CLOSESTPOINT':
- cp = object_mapping_closest_point(obj, cp, offset)
+ points = []
steps = spires * spire_resolution
- for i in range(1, steps + 1):
+ for i in range(steps + 1):
t = bb_zmin + (2 * pi / steps) * i
z = bb_zmin + (float(height) / steps) * i
center = [cx, cy, z]
-
- cp = spiral_point(t, radius, z, spires, waves, wave_height, rndm_spire)
+ if direction is True:
+ t = -t
+ cp = spiral_point(-t, radius, z, spires, waves, wave_height, rndm_spire)
if map_method == 'RAYCAST':
cp = object_mapping_ray_cast(obj, cp, center, offset)
elif map_method == 'CLOSESTPOINT':
@@ -185,7 +209,6 @@ def spirofit_spline(obj,
points.append(cp)
return points
-
# ------------------------------------------------------------
class SpiroFitSpline(bpy.types.Operator):
@@ -195,107 +218,148 @@ class SpiroFitSpline(bpy.types.Operator):
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
map_method = bpy.props.EnumProperty(
- name="Mapping Method",
- default='CLOSESTPOINT',
- description="Mapping method",
- items=[('RAYCAST', 'Ray cast', 'Ray cast'),
- ('CLOSESTPOINT', 'Closest point', 'Closest point')]
- )
-
+ name="Mapping Method",
+ default='RAYCAST',
+ description="Mapping method",
+ items=[('RAYCAST', 'Ray cast', 'Ray casting'),
+ ('CLOSESTPOINT', 'Closest point', 'Closest point on mesh')]
+ )
+ direction = bpy.props.BoolProperty(
+ name="Direction",
+ description="Spire direction",
+ default=False
+ )
spire_resolution = bpy.props.IntProperty(
- name="Spire Resolution",
- default=8,
- min=3,
- max=256,
- soft_max=128,
- description="Spire resolution for one turn"
- )
+ name="Spire Resolution",
+ default=8,
+ min=3,
+ max=256,
+ soft_max=128,
+ description="Number of steps for one turn"
+ )
spires = bpy.props.IntProperty(
- name="Spires",
- default=4,
- min=1,
- max=512,
- soft_max=256,
- description="Number of spire turns"
- )
+ name="Spires",
+ default=4,
+ min=1,
+ max=512,
+ soft_max=256,
+ description="Number of turns"
+ )
+ offset = bpy.props.FloatProperty(
+ name="Offset",
+ default=0.0,
+ precision=3,
+ description="Use normal direction to offset spline"
+ )
waves = bpy.props.IntProperty(
- name="Waves",
- default=0,
- min=0,
- description="Waves amount"
- )
+ name="Waves",
+ default=0,
+ min=0,
+ description="Waves amount"
+ )
wave_height = bpy.props.FloatProperty(
- name="Wave intensity",
- default=0.1,
- min=0.0,
- description="Wave intensity scale"
- )
+ name="Wave Intensity",
+ default=0.25,
+ min=0.0,
+ precision=3,
+ description="Wave intensity scale"
+ )
rndm_spire = bpy.props.FloatProperty(
- name="Randomize",
- default=0.0,
- min=0.0,
- description="Randomize spire"
- )
- offset = bpy.props.FloatProperty(
- name="Offset",
- default=0.0,
- description="Use normal direction to offset spline"
- )
+ name="Randomise",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Randomise spire"
+ )
+
+ spline_name = bpy.props.StringProperty(
+ name="Name",
+ default="SpiroFit"
+ )
spline_type = bpy.props.EnumProperty(
- name="Spline type",
- default='BEZIER',
- description="Spline type",
- items=[('POLY', 'Poly', 'POLY'),
- ('BEZIER', 'Bezier', 'BEZIER')]
- )
- spline_resolution = bpy.props.IntProperty(
- name="Resolution u",
- default=12,
- min=0,
- max=64,
- description="Curve resolution u"
- )
+ name="Spline Type",
+ default='BEZIER',
+ description="Spline type",
+ items=[('POLY', 'Poly', 'Poly spline'),
+ ('BEZIER', 'Bezier', 'Bezier spline')]
+ )
+ resolution_u = bpy.props.IntProperty(
+ name="Resolution U",
+ default=12,
+ min=0,
+ max=64,
+ description="Curve resolution u"
+ )
bevel = bpy.props.FloatProperty(
- name="Bevel radius",
- default=0.0,
- min=0.0,
- precision=3,
- description="Bevel depth"
- )
+ name="Bevel Radius",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Bevel depth"
+ )
bevel_res = bpy.props.IntProperty(
- name="Bevel resolution",
- default=0,
- min=0,
- max=32,
- description="Bevel resolution"
- )
- spline_random_radius = bpy.props.FloatProperty(
- name="Random bevel radius",
- default=0.0,
- min=0.0,
- description="Random radius amount"
- )
- random_seed = bpy.props.IntProperty(
- name="Random seed",
- default=2,
- min=0,
- description="Random seed number"
- )
+ name="Bevel Resolution",
+ default=0,
+ min=0,
+ max=32,
+ description="Bevel resolution"
+ )
+ random_radius = bpy.props.FloatProperty(
+ name="Randomise Radius",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Random radius amount"
+ )
+ extrude = bpy.props.FloatProperty(
+ name="Extrude",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Extrude amount"
+ )
+ twist_mode = bpy.props.EnumProperty(
+ name="Twisting",
+ default='MINIMUM',
+ description="Twist method, type of tilt calculation",
+ items=[('Z_UP', "Z-Up", 'Z Up'),
+ ('MINIMUM', "Minimum", 'Minimum'),
+ ('TANGENT', "Tangent", 'Tangent')]
+ )
+ twist_smooth = bpy.props.FloatProperty(
+ name="Smooth",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Twist smoothing amount for tangents"
+ )
+ tilt = bpy.props.FloatProperty(
+ name="Tilt",
+ default=0.0,
+ precision=3,
+ description="Spline handle tilt"
+ )
x_ray = bpy.props.BoolProperty(
- name="X-Ray",
- default=True,
- description = "Make the object draw in front of others"
- )
+ name="X-Ray",
+ default=True,
+ description = "Make the object draw in front of others"
+ )
+ random_seed = bpy.props.IntProperty(
+ name="Random Seed",
+ default=1,
+ min=0,
+ description="Random seed number"
+ )
refresh = bpy.props.BoolProperty(
- name="Refresh",
- description="Refresh spline",
- default=False
- )
+ name="Refresh",
+ description="Refresh spline",
+ default=False
+ )
auto_refresh = bpy.props.BoolProperty(
- name="Auto",
- description="Auto refresh spline",
- default=True
- )
+ name="Auto",
+ description="Auto refresh spline",
+ default=True
+ )
@classmethod
@@ -327,24 +391,32 @@ class SpiroFitSpline(bpy.types.Operator):
if self.random_seed:
use_random_seed(self.random_seed)
- points = spirofit_spline(obj,
- self.spires,
+ points = spirofit_spline(
+ obj,
self.spire_resolution,
+ self.spires,
+ self.offset,
self.waves,
self.wave_height,
self.rndm_spire,
- self.offset,
+ self.direction,
self.map_method
)
- add_curve_object(points,
+ add_curve_object(
+ points,
matrix,
+ self.spline_name,
self.x_ray,
self.spline_type,
- self.spline_resolution,
+ self.resolution_u,
self.bevel,
self.bevel_res,
- self.spline_random_radius
+ self.extrude,
+ self.random_radius,
+ self.twist_mode,
+ self.twist_smooth,
+ self.tilt
)
if self.auto_refresh is False:
@@ -367,27 +439,24 @@ class SpiroFitSpline(bpy.types.Operator):
row.prop(self, 'auto_refresh', toggle=True, icon='AUTO', text="")
row.prop(self, 'refresh', toggle=True, icon='FILE_REFRESH', text="")
row.separator()
- properties = row.operator('object.add_spirofit_spline', text="Add New")
+ row.operator('object.add_spirofit_spline', text="Add New")
+
+ col = layout.column(align=True)
+ col.prop(self, 'spline_name')
col.separator()
- col = layout.column(align=False)
col.prop(self, 'map_method')
- col = layout.column(align=True)
+ col.separator()
col.prop(self, 'spire_resolution')
- col.prop(self, 'spires')
+ row = col.row(align=True).split(0.9,align=True)
+ row.prop(self, 'spires')
+ row.prop(self, 'direction', toggle=True, text="", icon='ARROW_LEFTRIGHT')
col.prop(self, 'offset')
col.prop(self, 'waves')
col.prop(self, 'wave_height')
col.prop(self, 'rndm_spire')
col.prop(self, 'random_seed')
- col.separator()
- col = layout.column(align=True)
- col.prop(self, 'spline_type')
- col.separator()
- col.prop(self, 'spline_resolution')
- col.prop(self, 'bevel')
- if self.spline_type == 'BEZIER':
- col.prop(self, 'spline_random_radius')
- col.prop(self, 'bevel_res')
+
+ draw_spline_settings(self, context)
# ------------------------------------------------------------
@@ -395,6 +464,7 @@ class SpiroFitSpline(bpy.types.Operator):
# Original script by Liero and Atom
# https://blenderartists.org/forum/showthread.php?331750-Fiber-Mesh-Emulation
# ------------------------------------------------------------
+
def noise(var=1):
rand = Vector((r.gauss(0,1), r.gauss(0,1), r.gauss(0,1)))
vec = rand.normalized() * var
@@ -440,7 +510,6 @@ def bounce_spline(obj,
return points
return points
-
# ------------------------------------------------------------
class BounceSpline(bpy.types.Operator):
@@ -449,95 +518,131 @@ class BounceSpline(bpy.types.Operator):
bl_description="Fill selected mesh with a bounce spline"
bl_options = {'REGISTER', 'UNDO', 'PRESET'}
- random_seed = bpy.props.IntProperty(
- name="Random seed",
- default=1,
- min=0,
- description="Random seed number"
- )
bounce_number = bpy.props.IntProperty(
- name="Bounces",
- default=500,
- min=1,
- max=99999,
- soft_max=9999,
- description="Number of Bounces"
- )
+ name="Bounces",
+ default=500,
+ min=1,
+ max=99999,
+ soft_max=9999,
+ description="Number of bounces"
+ )
ang_noise = bpy.props.FloatProperty(
- name="Angular noise",
- default=0.25,
- min=0.0,
- description="Add some noise to ray direction"
- )
+ name="Angular Noise",
+ default=0.25,
+ min=0.0,
+ precision=3,
+ description="Add some noise to ray direction"
+ )
offset = bpy.props.FloatProperty(
- name="Offset",
- default=0.0,
- description="Use normal direction to offset spline"
- )
+ name="Offset",
+ default=0.0,
+ precision=3,
+ description="Use normal direction to offset spline"
+ )
extra = bpy.props.IntProperty(
- name="Extra",
- default=50,
- min=0,
- max=1000,
- soft_min=0,
- soft_max=500,
- description="Number of extra tries if it fails to hit mesh"
- )
+ name="Extra",
+ default=50,
+ min=0,
+ max=1000,
+ soft_min=0,
+ soft_max=500,
+ description="Number of extra tries if it fails to hit mesh"
+ )
active_face = bpy.props.BoolProperty(
- name="Active face",
- default=False,
- description = "Starts from active face or a random one"
- )
+ name="Active Face",
+ default=False,
+ description = "Starts from active face or a random one"
+ )
+
+ spline_name = bpy.props.StringProperty(
+ name="Name",
+ default="BounceSpline"
+ )
spline_type = bpy.props.EnumProperty(
- name="Spline type",
- default='BEZIER',
- description="Spline type",
- items=[('POLY', 'Poly', 'POLY'),
- ('BEZIER', 'Bezier', 'BEZIER')]
- )
- spline_resolution = bpy.props.IntProperty(
- name="Resolution u",
- default=12,
- min=0,
- max=64,
- description="Curve resolution u"
- )
+ name="Spline Type",
+ default='BEZIER',
+ description="Spline type",
+ items=[('POLY', 'Poly', 'Poly spline'),
+ ('BEZIER', 'Bezier', 'Bezier spline')]
+ )
+ resolution_u = bpy.props.IntProperty(
+ name="Resolution U",
+ default=12,
+ min=0,
+ max=64,
+ description="Curve resolution u"
+ )
bevel = bpy.props.FloatProperty(
- name="Bevel radius",
- default=0.0,
- min=0.0,
- precision=3,
- description="Bevel depth"
- )
-
+ name="Bevel Radius",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Bevel depth"
+ )
bevel_res = bpy.props.IntProperty(
- name="Bevel resolution",
- default=0,
- min=0,
- max=32,
- description="Bevel resolution"
- )
- spline_random_radius = bpy.props.FloatProperty(
- name="Random bevel radius",
- default=0.0,
- min=0.0,
- description="Random radius amount"
- )
+ name="Bevel Resolution",
+ default=0,
+ min=0,
+ max=32,
+ description="Bevel resolution"
+ )
+ random_radius = bpy.props.FloatProperty(
+ name="Randomise Radius",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Random radius amount"
+ )
+ extrude = bpy.props.FloatProperty(
+ name="Extrude",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Extrude amount"
+ )
+ twist_mode = bpy.props.EnumProperty(
+ name="Twisting",
+ default='MINIMUM',
+ description="Twist method, type of tilt calculation",
+ items=[('Z_UP', "Z-Up", 'Z Up'),
+ ('MINIMUM', "Minimum", 'Minimum'),
+ ('TANGENT', "Tangent", 'Tangent')]
+ )
+ twist_smooth = bpy.props.FloatProperty(
+ name="Smooth",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Twist smoothing amount for tangents"
+ )
+ tilt = bpy.props.FloatProperty(
+ name="Tilt",
+ default=0.0,
+ precision=3,
+ description="Spline handle tilt"
+ )
x_ray = bpy.props.BoolProperty(
- name="X-Ray",
- default=True,
- description = "Make the object draw in front of others"
- )
+ name="X-Ray",
+ default=True,
+ description = "Make the object draw in front of others"
+ )
+ random_seed = bpy.props.IntProperty(
+ name="Random Seed",
+ default=1,
+ min=0,
+ description="Random seed number"
+ )
refresh = bpy.props.BoolProperty(
- name="Refresh",
- description="Refresh spline",
- default=False
- )
+ name="Refresh",
+ description="Refresh spline",
+ default=False
+ )
auto_refresh = bpy.props.BoolProperty(
- name="Auto",
- description="Auto refresh spline",
- default=True
- )
+ name="Auto",
+ description="Auto refresh spline",
+ default=True
+ )
+
@classmethod
def poll(self, context):
@@ -567,21 +672,30 @@ class BounceSpline(bpy.types.Operator):
if self.random_seed:
use_random_seed(self.random_seed)
- points = bounce_spline(obj,
+ points = bounce_spline(
+ obj,
self.bounce_number,
self.ang_noise,
self.offset,
self.extra,
- self.active_face)
+ self.active_face
+ )
- add_curve_object(points,
+ add_curve_object(
+ points,
obj.matrix_world,
+ self.spline_name,
self.x_ray,
self.spline_type,
- self.spline_resolution,
+ self.resolution_u,
self.bevel,
self.bevel_res,
- self.spline_random_radius)
+ self.extrude,
+ self.random_radius,
+ self.twist_mode,
+ self.twist_smooth,
+ self.tilt
+ )
if self.auto_refresh is False:
self.refresh = False
@@ -594,7 +708,6 @@ class BounceSpline(bpy.types.Operator):
layout = self.layout
col = layout.column(align=True)
row = col.row(align=True)
-
row.prop(self, 'x_ray', toggle=True)
row.separator()
if self.auto_refresh is False:
@@ -604,26 +717,272 @@ class BounceSpline(bpy.types.Operator):
row.prop(self, 'auto_refresh', toggle=True, icon='AUTO', text="")
row.prop(self, 'refresh', toggle=True, icon='FILE_REFRESH', text="")
row.separator()
- properties = row.operator('object.add_bounce_spline', text="Add New")
- col.separator()
+ row.operator('object.add_bounce_spline', text="Add New")
+
col = layout.column(align=True)
- row = col.row(align=True)
+ col.prop(self, 'spline_name')
+ col.separator()
col.prop(self, 'bounce_number')
- col.prop(self, 'ang_noise')
+ row = col.row(align=True).split(0.9, align=True)
+ row.prop(self, 'ang_noise')
+ row.prop(self, 'active_face', toggle=True, text="", icon='FACESEL')
col.prop(self, 'offset')
col.prop(self, 'extra')
col.prop(self, 'random_seed')
- col.separator()
- col.prop(self, 'active_face', toggle=False)
+
+ draw_spline_settings(self, context)
+
+
+#------------------------------------------------------------
+# Hang Catenary curve between two selected objects
+#------------------------------------------------------------
+
+def catenary_curve(
+ start=[-2, 0, 2],
+ end=[2, 0, 2],
+ steps=24,
+ a=2.0
+ ):
+
+ points=[]
+ lx = end[0] - start[0]
+ ly = end[1] - start[1]
+ lr = sqrt(pow(lx, 2) + pow(ly, 2))
+ lv = lr / 2 - (end[2] - start[2]) * a / lr
+ zv = start[2] - pow(lv, 2) / (2 * a)
+ slx = lx / steps
+ sly = ly / steps
+ slr = lr / steps
+ i = 0
+ while i <= steps:
+ x = start[0] + i * slx
+ y = start[1] + i * sly
+ z = zv+pow((i * slr) - lv, 2) / (2 * a)
+ points.append([x, y, z])
+ i += 1
+ return points
+
+#------------------------------------------------------------
+class CatenaryCurve(bpy.types.Operator):
+ bl_idname = "object.add_catenary_curve"
+ bl_label = "Catenary"
+ bl_description="Hang a catenary curve between two selected objects"
+ bl_options = {'REGISTER', 'UNDO', 'PRESET'}
+
+ start_location = bpy.props.StringProperty(
+ name="Start",
+ default="",
+ description="Catenary start location",
+ )
+ end_location = bpy.props.StringProperty(
+ name="End",
+ default="",
+ description="Catenary end location",
+ )
+ steps = bpy.props.IntProperty(
+ name="Steps",
+ description="Resolution of the curve",
+ default=24,
+ min=2,
+ max=256,
+ )
+ var_a = bpy.props.FloatProperty(
+ name="a",
+ description="Catenary variable a",
+ precision=3,
+ default=2.0,
+ min=0.0, soft_min=0.01,
+ max=100.0, soft_max=10.0
+ )
+
+ spline_name = bpy.props.StringProperty(
+ name="Name",
+ default="Catenary"
+ )
+ spline_type = bpy.props.EnumProperty(
+ name="Spline Type",
+ default='BEZIER',
+ description="Spline type",
+ items=[('POLY', 'Poly', 'Poly spline'),
+ ('BEZIER', 'Bezier', 'Bezier spline')]
+ )
+ resolution_u = bpy.props.IntProperty(
+ name="Resolution U",
+ default=12,
+ min=0,
+ max=64,
+ description="Curve resolution u"
+ )
+ bevel = bpy.props.FloatProperty(
+ name="Bevel Radius",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Bevel depth"
+ )
+ bevel_res = bpy.props.IntProperty(
+ name="Bevel Resolution",
+ default=0,
+ min=0,
+ max=32,
+ description="Bevel resolution"
+ )
+ random_radius = bpy.props.FloatProperty(
+ name="Randomise Radius",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Random radius amount"
+ )
+ extrude = bpy.props.FloatProperty(
+ name="Extrude",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Extrude amount"
+ )
+ twist_mode = bpy.props.EnumProperty(
+ name="Twisting",
+ default='MINIMUM',
+ description="Twist method, type of tilt calculation",
+ items=[('Z_UP', "Z-Up", 'Z Up'),
+ ('MINIMUM', "Minimum", 'Minimum'),
+ ('TANGENT', "Tangent", 'Tangent')]
+ )
+ twist_smooth = bpy.props.FloatProperty(
+ name="Smooth",
+ default=0.0,
+ min=0.0,
+ precision=3,
+ description="Twist smoothing amount for tangents"
+ )
+ tilt = bpy.props.FloatProperty(
+ name="Tilt",
+ default=0.0,
+ precision=3,
+ description="Spline handle tilt"
+ )
+ x_ray = bpy.props.BoolProperty(
+ name="X-Ray",
+ default=False,
+ description = "Make the object draw in front of others"
+ )
+ random_seed = bpy.props.IntProperty(
+ name="Random Seed",
+ default=1,
+ min=0,
+ description="Random seed number"
+ )
+ refresh = bpy.props.BoolProperty(
+ name="Refresh",
+ description="Refresh spline",
+ default=False
+ )
+ auto_refresh = bpy.props.BoolProperty(
+ name="Auto",
+ description="Auto refresh spline",
+ default=True
+ )
+
+ def draw(self, context):
+ scene = bpy.context.scene
+ layout = self.layout
+ col = layout.column(align=True)
+ row = col.row(align=True)
+ row.prop(self, 'x_ray', toggle=True)
+ row.separator()
+ if self.auto_refresh is False:
+ self.refresh = False
+ elif self.auto_refresh is True:
+ self.refresh = True
+ row.prop(self, 'auto_refresh', toggle=True, icon='AUTO', text="")
+ row.prop(self, 'refresh', toggle=True, icon='FILE_REFRESH', text="")
+ row.separator()
+ row.operator('object.add_catenary_curve', text="Add New")
+
col = layout.column(align=True)
- col.prop(self, 'spline_type')
+ col.prop(self, 'spline_name')
+ col.separator()
+ col.prop_search(self, "start_location", scene, "objects")
+ col.prop_search(self, "end_location", scene, "objects")
col.separator()
- col.prop(self, 'spline_resolution')
- col.prop(self, 'bevel')
- if self.spline_type == 'BEZIER':
- col.prop(self, 'spline_random_radius')
- col.prop(self, 'bevel_res')
+ col.prop(self, 'steps')
+ col.prop(self, 'var_a')
+ draw_spline_settings(self, context)
+
+ col = layout.column(align=True)
+ col.prop(self, 'random_seed')
+
+
+ @classmethod
+ def poll(self, context):
+ ob = context.active_object
+ return (ob is not None)
+
+
+ def invoke(self, context, event):
+ self.refresh = True
+ return self.execute(context)
+
+
+ def execute(self, context):
+ if not self.refresh:
+ return {'PASS_THROUGH'}
+
+ undo = context.user_preferences.edit.use_global_undo
+ context.user_preferences.edit.use_global_undo = False
+
+ if self.random_seed:
+ use_random_seed(self.random_seed)
+
+ matrix = None
+
+ try:
+ ob1 = bpy.data.objects[self.start_location]
+ ob2 = bpy.data.objects[self.end_location]
+ start = ob1.location
+ end = ob2.location
+ if end == start:
+ start = [-2, 0, 2]
+ end= [2, 0, 2]
+ sel = bpy.context.selected_objects
+ for o in sel:
+ o.select = False
+ ob1.select = True
+ ob2.select = True
+ except:
+ start = [-2, 0, 2]
+ end= [2, 0, 2]
+
+ points = catenary_curve(
+ start,
+ end,
+ self.steps,
+ self.var_a
+ )
+
+ add_curve_object(
+ points,
+ matrix,
+ self.spline_name,
+ self.x_ray,
+ self.spline_type,
+ self.resolution_u,
+ self.bevel,
+ self.bevel_res,
+ self.extrude,
+ self.random_radius,
+ self.twist_mode,
+ self.twist_smooth,
+ self.tilt
+ )
+
+ if self.auto_refresh is False:
+ self.refresh = False
+
+ context.user_preferences.edit.use_global_undo = undo
+ return {'FINISHED'}
# ------------------------------------------------------------
# Tools Panel > Misc
@@ -643,8 +1002,9 @@ class SplinePanel( bpy.types.Panel ):
col = self.layout.column()
col.operator(SpiroFitSpline.bl_idname, icon="FORCE_MAGNETIC")
col.operator(BounceSpline.bl_idname, icon="FORCE_HARMONIC")
+ col.operator(CatenaryCurve.bl_idname, icon="FORCE_CURVE")
-# ------------------------------------------------------------ # icon="CURVE_DATA"
+# ------------------------------------------------------------
# Menu: Add > Curve >
# ------------------------------------------------------------
@@ -652,6 +1012,7 @@ class SplinePanel( bpy.types.Panel ):
def menu_func(self, context):
self.layout.operator(SpiroFitSpline.bl_idname, icon="PLUGIN")
self.layout.operator(BounceSpline.bl_idname, icon="PLUGIN")
+ self.layout.operator(CatenaryCurve.bl_idname, icon="PLUGIN")
'''
# ------------------------------------------------------------
@@ -659,15 +1020,17 @@ def menu_func(self, context):
# ------------------------------------------------------------
def register():
+ bpy.utils.register_class(SplinePanel)
bpy.utils.register_class(SpiroFitSpline)
bpy.utils.register_class(BounceSpline)
- bpy.utils.register_class(SplinePanel)
+ bpy.utils.register_class(CatenaryCurve)
#bpy.types.INFO_MT_curve_add.append(menu_func)
def unregister():
+ bpy.utils.unregister_class(SplinePanel)
bpy.utils.unregister_class(SpiroFitSpline)
bpy.utils.unregister_class(BounceSpline)
- bpy.utils.unregister_class(SplinePanel)
+ bpy.utils.unregister_class(CatenaryCurve)
#bpy.types.INFO_MT_curve_add.remove(menu_func)
if __name__ == "__main__":