So I Created This Coil Script

I got a little curious about what could be done with quaternions and I came up with this. Basically, it’s a coil script that uses the whole idea for making bezier springs and spirals. Hope you folks like it. Feedback welcome and desired. Cheers.


# ##### 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 2
#  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, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####


import bpy
from mathutils import Quaternion, Vector
from math import pi
from bpy.props import IntProperty, FloatProperty


bl_info = {
    "name": "Coil Curve Gen",
    "author": "Phil Cote, cotejrp1",
    "version": (0, 0, 1),
    "blender": (2, 6, 3),
    "location": "View3D > Add > Curve",
    "description": "Add a coiled bezier curve to the scene.",
    "warning": "",
    "category": "Add Curve"}


def get_mesh_data(rad=5, point_count=10, turn_width=.5, turn_height=0.0,
                    points_per_turn=5, h_taper=0.0, w_taper=0.0):
    
    axis = [0,0,-1]
    cur_z = 0
    PI_2 = pi * 2
    ppt = points_per_turn-1
    num_of_turns = 0
    point_count -= 1 #offset for the one point already in the new curve.
    
    x_vals = [x for x in range(1, point_count+2)]
    x_vals = [(x/ppt)*PI_2 for x in x_vals]
    quats = [Quaternion(axis, x) for x in x_vals]
    
    def taper_values(turn_factor, taper):
        """Adjust heights or widths for tapering as needed"""
        new_list = []
        for i, q in enumerate(quats):
            if i % points_per_turn == 0:
                turn_factor -= taper
            new_list.append(turn_factor)
                
        return new_list        
    
    turn_heights = taper_values(turn_height, h_taper)
    turn_widths = taper_values(turn_width, w_taper)
    
    vecs = []
    for i, q in enumerate(quats):
        vec = q * Vector((rad,0,cur_z))
        vecs.append(vec)
        rad+=turn_widths[i]
        cur_z+=turn_heights[i]
        
    coords = [(v.x,v.y,v.z) for v in vecs]
    return coords


class QuatOperator(bpy.types.Operator):
    bl_idname = "mesh.primitive_quat_add"
    bl_label = "Add Quat"
    bl_options = {'REGISTER', 'UNDO'}
    
    pc = IntProperty(
        name = "Point Count", description = "Point Count",
        min = 3, max = 50, default = 5)
    radius = FloatProperty(
        name = "Radius", description = "Radius",
        min = .1, max = 10, default = 1)
    turn_width = FloatProperty(name="Turn Width",
                   min = -1.0, max=1.0, default=0)
    turn_height = FloatProperty(name="Turn Height",
                    min=-1.0, max=1.0,default=0)
    points_per_turn = IntProperty(name="Points Per Turn",
                    min=3,max=30,default=5)
    h_taper = FloatProperty(name="Height Taper", 
                        description="How much to decrease each turn height",
                        min=-1, max=1,default=0)
    w_taper = FloatProperty(name="Width Taper", 
                        description="How much to decrease each turn height",
                        min=-1, max=1,default=0)
    

    def execute(self, context):
        
        # set up the mesh data to be more suitable for curve objects.
        mesh_data = get_mesh_data(rad=self.radius, 
                                  point_count=self.pc,
                                  turn_width=self.turn_width,
                                  turn_height=self.turn_height,
                                  points_per_turn=self.points_per_turn,
                                  h_taper=self.h_taper, w_taper=self.w_taper)
        flat_list = []
        for md in mesh_data:
            flat_list.extend(md)
            
        # build the curve
        crv = bpy.data.curves.new("crv", type="CURVE")
        spln = crv.splines.new(type="BEZIER")
        points = spln.bezier_points
        points.add(self.pc-1)
        points.foreach_set("co", flat_list)
        
        for i, point in enumerate(points):
            if i > 0:
                point.handle_left_type = point.handle_right_type = "AUTO"
         
        ob = bpy.data.objects.new("quat_ob", crv)        
        bpy.context.scene.objects.link(ob)
        
        return {'FINISHED'}
        
        

def menu_func(self, context):
    self.layout.operator(QuatOperator.bl_idname,
                            text="Add Coil Curve",
                            icon = "PLUGIN")


def register():
    bpy.utils.register_class(QuatOperator)
    bpy.types.INFO_MT_curve_add.append(menu_func)


def unregister():
    bpy.utils.unregister_class(QuatOperator)
    bpy.types.INFO_MT_mesh_add.remove(menu_func)

if __name__ == "__main__":
    register()

Dont know what Id use it for but it looks useful. lack of feedback may be due to lack of detail on your part.

maybe A offer the script as a .py download for people who do not know how to convert to script & B a picture of what can be done with it

@@mrjynx
Lack of detail on my part was on account of the fact that this was an experimental thing I did to teach myself something about quaternions that I thought had turned into something kind of neat.

There’s not really an appropriate place for scripts like this since there’s no place in this forum for work-in-progress scripts. Not really a “I need help” item for the coding/support but not a finished product either. I hope I picked the right forum.

@Atom
Holy crap, I didn’t see that one coming! I downloaded the blend and saw you did some interesting stuff with it. As for the broken turn attribute, I’ll take a look at it and see what I can do.

Here’s an update. Added beveling and extrusion to make it look more interesting at creation time.


# ##### 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 2
#  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, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####


import bpy
from mathutils import Quaternion, Vector
from math import pi
from bpy.props import IntProperty, FloatProperty


bl_info = {
    "name": "Coil Curve Gen",
    "author": "Phil Cote, cotejrp1",
    "version": (0, 0, 1),
    "blender": (2, 6, 3),
    "location": "View3D > Add > Curve",
    "description": "Add a coiled bezier curve to the scene.",
    "warning": "",
    "category": "Add Curve"}


def get_mesh_data(rad=5, point_count=10, turn_width=.5, turn_height=0.0,
                    points_per_turn=5, h_taper=0.0, w_taper=0.0):
    
    axis = [0,0,-1]
    cur_z = 0
    PI_2 = pi * 2
    ppt = points_per_turn-1
    num_of_turns = 0
    point_count -= 1 #offset for the one point already in the new curve.
    
    x_vals = [x for x in range(1, point_count+2)]
    x_vals = [(x/ppt)*PI_2 for x in x_vals]
    quats = [Quaternion(axis, x) for x in x_vals]
    
    def taper_values(turn_factor, taper):
        """Adjust heights or widths for tapering as needed"""
        new_list = []
        for i, q in enumerate(quats):
            if i % points_per_turn == 0:
                turn_factor -= taper
            new_list.append(turn_factor)
                
        return new_list        
    
    turn_heights = taper_values(turn_height, h_taper)
    turn_widths = taper_values(turn_width, w_taper)
    
    vecs = []
    for i, q in enumerate(quats):
        vec = q * Vector((rad,0,cur_z))
        vecs.append(vec)
        rad+=turn_widths[i]
        cur_z+=turn_heights[i]
        
    coords = [(v.x,v.y,v.z) for v in vecs]
    return coords


class QuatOperator(bpy.types.Operator):
    bl_idname = "mesh.primitive_quat_add"
    bl_label = "Add Quat"
    bl_options = {'REGISTER', 'UNDO'}
    
    pc = IntProperty(
        name = "Point Count", description = "Point Count",
        min = 3, max = 50, default = 5)
    radius = FloatProperty(
        name = "Radius", description = "Radius",
        min = .1, max = 10, default = 1)
    turn_width = FloatProperty(name="Turn Width",
                   min = -1.0, max=1.0, default=0)
    turn_height = FloatProperty(name="Turn Height",
                    min=-1.0, max=1.0,default=0)
    points_per_turn = IntProperty(name="Points Per Turn",
                    min=3,max=30,default=5)
    h_taper = FloatProperty(name="Height Taper", 
                        description="How much to decrease each turn height",
                        min=-1, max=1,default=0)
    w_taper = FloatProperty(name="Width Taper", 
                        description="How much to decrease each turn height",
                        min=-1, max=1,default=0)
    bevel_depth = FloatProperty(name="Bevel Depth",
                            description = "Amount of Bevel",
                            min = 0, max = 1, default = 0)
    extrude_mod = FloatProperty(name="Extrude",
                            description = "Amount of Extrude",
                            min = 0, max = 1, default = 0)
    

    def execute(self, context):
        
        # set up the mesh data to be more suitable for curve objects.
        mesh_data = get_mesh_data(rad=self.radius, 
                                  point_count=self.pc,
                                  turn_width=self.turn_width,
                                  turn_height=self.turn_height,
                                  points_per_turn=self.points_per_turn,
                                  h_taper=self.h_taper, w_taper=self.w_taper)
        flat_list = []
        for md in mesh_data:
            flat_list.extend(md)
            
        # build the curve
        crv = bpy.data.curves.new("crv", type="CURVE")
        spln = crv.splines.new(type="BEZIER")
        points = spln.bezier_points
        points.add(self.pc-1)
        points.foreach_set("co", flat_list)
        
        for i, point in enumerate(points):
            if i > 0:
                point.handle_left_type = point.handle_right_type = "AUTO"
        
        crv.bevel_depth = self.bevel_depth
        crv.extrude = self.extrude_mod
        ob = bpy.data.objects.new("quat_ob", crv)        
        bpy.context.scene.objects.link(ob)
        
        return {'FINISHED'}
        
        

def menu_func(self, context):
    self.layout.operator(QuatOperator.bl_idname,
                            text="Add Coil Curve",
                            icon = "PLUGIN")


def register():
    bpy.utils.register_class(QuatOperator)
    bpy.types.INFO_MT_curve_add.append(menu_func)


def unregister():
    bpy.utils.unregister_class(QuatOperator)
    bpy.types.INFO_MT_mesh_add.remove(menu_func)

if __name__ == "__main__":
    register()

And the demo video…

I hope you guys like it.

nice one :slight_smile:
try to drop into irc one day, so we can add this/merge & discuss your other addons :wink: