diff --git a/add_curve_extra_objects/__init__.py b/add_curve_extra_objects/__init__.py
index 05a8e8733aa3fdf47b083200ca652db43f679866..f328ed9d47ace06418f50edb92f0255a4756295c 100644
--- a/add_curve_extra_objects/__init__.py
+++ b/add_curve_extra_objects/__init__.py
@@ -43,6 +43,7 @@ if "bpy" in locals():
     importlib.reload(add_curve_celtic_links)
     importlib.reload(add_curve_braid)
     importlib.reload(add_curve_simple)
+    importlib.reload(add_curve_spirofit_bouncespline)
 
 else:
     from . import add_curve_aceous_galore
@@ -54,6 +55,7 @@ else:
     from . import add_curve_celtic_links
     from . import add_curve_braid
     from . import add_curve_simple
+    from . import add_curve_spirofit_bouncespline
 
 import bpy
 from bpy.types import Menu, AddonPreferences
diff --git a/add_curve_extra_objects/add_curve_aceous_galore.py b/add_curve_extra_objects/add_curve_aceous_galore.py
index 6a7ac654d727121fcc692311f98f176555315fa2..649bf5595a2c09dcdc69b2db45a0b5d550f06dab 100644
--- a/add_curve_extra_objects/add_curve_aceous_galore.py
+++ b/add_curve_extra_objects/add_curve_aceous_galore.py
@@ -51,6 +51,7 @@ from math import (
         )
 import mathutils.noise as Noise
 from bpy.types import Operator
+
 # ------------------------------------------------------------
 # Some functions to use with others:
 # ------------------------------------------------------------
@@ -118,20 +119,6 @@ def vTurbNoise(x, y, z, iScale=0.25, Size=1.0, Depth=6, Hard=0, Basis=0, Seed=0)
     tz = vTurb[2]*iScale
     return tx, ty, tz
 
-
-#------------------------------------------------------------
-# Axis: ( used in 3DCurve Turbulence )
-def AxisFlip(x, y, z, x_axis=1, y_axis=1, z_axis=1, flip=0):
-    if flip != 0:
-        flip *= -1
-    else:
-        flip = 1
-    x *= x_axis*flip
-    y *= y_axis*flip
-    z *= z_axis*flip
-    return x, y, z
-
-
 # -------------------------------------------------------------------
 # 2D Curve shape functions:
 # -------------------------------------------------------------------
@@ -193,12 +180,12 @@ def ProfileCurve(type=0, a=0.25, b=0.25):
     return newpoints
 
 # ------------------------------------------------------------
-# 2DCurve: Arrows
+# 2DCurve: Arrow
 def ArrowCurve(type=1, a=1.0, b=0.5):
     """
     ArrowCurve( type=1, a=1.0, b=0.5, c=1.0 )
 
-    Create arrow curves
+    Create arrow curve
 
         Parameters:
             type - select type, Arrow1, Arrow2
@@ -235,7 +222,7 @@ def RectCurve(type=1, a=1.0, b=0.5, c=1.0):
     """
     RectCurve( type=1, a=1.0, b=0.5, c=1.0 )
 
-    Create square / rectangle curves
+    Create square / rectangle curve
 
         Parameters:
             type - select type, Square, Rounded square 1, Rounded square 2
@@ -402,7 +389,7 @@ def ArcCurve(sides=6, startangle=0.0, endangle=90.0, innerradius=0.5, outerradiu
         newpoints.append([x1, y1, 0])
         i += 1
 
-    # if type ==0:
+    # if type == 1:
         # Arc: turn cyclic curve flag off!
 
     # Segment:
@@ -538,57 +525,8 @@ def SplatCurve(sides=24, scale=1.0, seed=0, basis=0, radius=1.0):
         i += 1
     return newpoints
 
-# -----------------------------------------------------------
-# 3D curve shape functions:
-# -----------------------------------------------------------
-
-# ------------------------------------------------------------
-# 3DCurve: Helix:
-def HelixCurve(number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0):
-    """
-    HelixCurve( number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0 )
-
-    Create helix curve
-
-        Parameters:
-            number - the number of points
-                (type=int)
-            height - height
-                (type=float)
-            startangle - startangle
-                (type=float)
-            endangle - endangle
-                (type=float)
-            width - width
-                (type=float)
-            a - a
-                (type=float)
-            b - b
-                (type=float)
-        Returns:
-            a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
-            (type=list)
-    """
-
-    newpoints = []
-    angle = (2.0/360.0)*(endangle-startangle)
-    step = angle/(number-1)
-    h = height/angle
-    start = (startangle*2.0/360.0)
-    a /= angle
-    i = 0
-    while i < number:
-        t = (i*step+start)
-        x = sin((t*pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width)
-        y = cos((t*pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width)
-        z = (t * h) - h*start
-        newpoints.append([x, y, z])
-        i += 1
-    return newpoints
-
 #------------------------------------------------------------
 # Cycloid curve
-
 def CycloidCurve(number=100, type=0, R=4.0, r=1.0, d=1.0):
     """
     CycloidCurve( number=100, type=0, a=4.0, b=1.0 )
@@ -645,12 +583,58 @@ def CycloidCurve(number=100, type=0, R=4.0, r=1.0, d=1.0):
             i+=1
     return newpoints
 
+# -----------------------------------------------------------
+# 3D curve shape functions:
+# -----------------------------------------------------------
+
+# ------------------------------------------------------------
+# 3DCurve: Helix:
+def HelixCurve(number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0):
+    """
+    HelixCurve( number=100, height=2.0, startangle=0.0, endangle=360.0, width=1.0, a=0.0, b=0.0 )
+
+    Create helix curve
+
+        Parameters:
+            number - the number of points
+                (type=int)
+            height - height
+                (type=float)
+            startangle - startangle
+                (type=float)
+            endangle - endangle
+                (type=float)
+            width - width
+                (type=float)
+            a - a
+                (type=float)
+            b - b
+                (type=float)
+        Returns:
+            a list with lists of x,y,z coordinates for curve points, [[x,y,z],[x,y,z],...n]
+            (type=list)
+    """
+
+    newpoints = []
+    angle = (2.0/360.0)*(endangle-startangle)
+    step = angle/(number-1)
+    h = height/angle
+    start = (startangle*2.0/360.0)
+    a /= angle
+    i = 0
+    while i < number:
+        t = (i*step+start)
+        x = sin((t*pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width)
+        y = cos((t*pi)) * (1.0 + cos(t * pi * a - (b * pi))) * (0.25 * width)
+        z = (t * h) - h*start
+        newpoints.append([x, y, z])
+        i += 1
+    return newpoints
+
 #------------------------------------------------------------
 # 3D Noise curve
-def NoiseCurve(number=100, length=2.0, scale=1.0, octaves=6, basis=1, seed=0, type=0):
+def NoiseCurve(type=0, number=100, length=2.0, size=0.5, scale=[0.5,0.5,0.5], taper=0.0, octaves=2, basis=0, seed=0):
     """
-    NoiseCurve( number=100, length=2.0, scale=1.0, octaves=2, basis=1, seed=0, type=1 )
-
     Create noise curve
 
         Parameters:
@@ -658,7 +642,11 @@ def NoiseCurve(number=100, length=2.0, scale=1.0, octaves=6, basis=1, seed=0, ty
                 (type=int)
             length - curve length
                 (type=float)
-            scale - noise scale
+            size - noise size
+                (type=float)
+            scale - noise intensity scale x,y,z
+                (type=list)
+            taper - taper scale
                 (type=float)
             basis - noise basis
                 (type=int)
@@ -671,31 +659,39 @@ def NoiseCurve(number=100, length=2.0, scale=1.0, octaves=6, basis=1, seed=0, ty
             (type=list)
     """
 
-    rand = randnum(-100,100,seed)
     newpoints = []
     step = (length/number)
     i = 0
     if type == 1:
-        # noise knot
+        # noise circle / arc
         while i < number:
-            t = ((i*step)+rand)
-            v = vTurbNoise(t,t,t, scale, 1.0, octaves, 0, basis, seed)
+            t = i*step
+            v = vTurbNoise(t, t, t, 1.0, size, octaves, 0, basis, seed)
+            x = sin(t*pi)*2.0 + (v[0] * scale[0])
+            y = cos(t*pi)*2.0 + (v[1] * scale[1])
+            z = v[2]*scale[2]
+            newpoints.append([x, y, z])
+            i += 1
+    elif type == 2:
+        # noise knot / ball
+        while i < number:
+            t = i*step
+            v = vTurbNoise(t,t,t, scale[2], 1.0, octaves, 0, basis, seed)
             newpoints.append([v[0], v[1], v[2]])
             i+=1
     else:
         # noise linear
         while i < number:
             t = i*step
-            tt = t+rand
-            v = vTurbNoise(t,t,t, scale, 1.0, octaves, 0, basis, seed)
-            x = t
-            y = v[1]
-            z = v[2]
+            tap = length-taper*t
+            v = vTurbNoise(t,t,t, 1.0, size, octaves, 0, basis, seed)
+            x = t + v[0] * (scale[0]/length)
+            y = v[1] * (scale[1]/length) * tap
+            z = v[2] * (scale[2]/length) * tap
             newpoints.append([x,y,z])
             i+=1
     return newpoints
 
-
 # ------------------------------------------------------------
 # calculates the matrix for the new object
 # depending on user pref
@@ -841,6 +837,12 @@ def main(context, self, align_matrix):
                             self.seed,
                             self.basis,
                             outerRadius)
+    if proType == 'Cycloid':
+        verts = CycloidCurve(self.cycloPoints,
+                            self.cycloType,
+                            self.cyclo_a,
+                            self.cyclo_b,
+                            self.cyclo_d)
     if proType == 'Helix':
         verts = HelixCurve(self.helixPoints,
                             self.helixHeight,
@@ -849,20 +851,16 @@ def main(context, self, align_matrix):
                             self.helixWidth,
                             self.helix_a,
                             self.helix_b)
-    if proType == 'Cycloid':
-        verts = CycloidCurve(self.cycloPoints,
-                            self.cycloType,
-                            self.cyclo_a,
-                            self.cyclo_b,
-                            self.cyclo_d)
     if proType == 'Noise':
-        verts = NoiseCurve(self.noisePoints,
+        verts = NoiseCurve(self.noiseType,
+                            self.noisePoints,
                             self.noiseLength,
-                            self.noiseScale,
+                            self.noiseSize,
+                            [self.noiseScaleX, self.noiseScaleY, self.noiseScaleZ],
+                            self.noiseTaper,
                             self.noiseOctaves,
                             self.noiseBasis,
-                            self.noiseSeed,
-                            self.noiseType)
+                            self.noiseSeed)
 
     # turn verts into array
     vertArray = vertsToPoints(verts, splineType)
@@ -928,6 +926,7 @@ class Curveaceous_galore(Operator):
                 ('VECTOR', 'Vector', 'VECTOR'),
                 ('AUTOMATIC', 'Auto', 'AUTOMATIC')]
     handleType = EnumProperty(name="Handle type",
+                default='AUTOMATIC',
                 description="bezier handles type",
                 items=bezHandles)
 
@@ -1078,7 +1077,7 @@ class Curveaceous_galore(Operator):
                             min=3, soft_min=3,
                             description="Resolution")
     cycloType = IntProperty(name="Type",
-                            default=0,
+                            default=1,
                             min=0, soft_min=0,
                             max=2, soft_max=2,
                             description="Type: Cycloid , Hypocycloid / Hypotrochoid , Epicycloid / Epitrochoid")
@@ -1095,6 +1094,11 @@ class Curveaceous_galore(Operator):
                             description="Cycloid: d distance")
 
     # Noise properties
+    noiseType = IntProperty(name="Type",
+                            default=0,
+                            min=0, soft_min=0,
+                            max=2, soft_max=2,
+                            description="Noise curve type: Linear, Circular or Knot")
     noisePoints = IntProperty(name="Resolution",
                             default=100,
                             min=3, soft_min=3,
@@ -1103,29 +1107,42 @@ class Curveaceous_galore(Operator):
                             default=2.0,
                             min=0.01, soft_min=0.01,
                             description="Curve Length")
-    noiseScale = FloatProperty(name="Noise scale",
-                            default=1.0,
+    noiseSize = FloatProperty(name="Noise size",
+                            default=0.25,
+                            min=0.0001, soft_min=0.0001,
+                            description="Noise size")
+    noiseScaleX = FloatProperty(name="Noise x",
+                            default=0.5,
                             min=0.0001, soft_min=0.0001,
-                            description="Noise scale")
+                            description="Noise x")
+    noiseScaleY = FloatProperty(name="Noise y",
+                            default=0.5,
+                            min=0.0001, soft_min=0.0001,
+                            description="Noise y")
+    noiseScaleZ = FloatProperty(name="Noise z",
+                            default=0.5,
+                            min=0.0001, soft_min=0.0001,
+                            description="Noise z")
+    noiseTaper = FloatProperty(name="Noise taper",
+                            default=0.0,
+                            min=0.0001, soft_min=0.0001,
+                            max=1.0, soft_max=1.0,
+                            description="Noise taper")
     noiseOctaves = IntProperty(name="Octaves",
                             default=2,
-                            min=0, soft_min=0,
+                            min=1, soft_min=1,
                             max=16, soft_max=16,
                             description="Basis")
     noiseBasis = IntProperty(name="Basis",
                             default=0,
                             min=0, soft_min=0,
-                            max=14, soft_max=14,
+                            max=9, soft_max=9,
                             description="Basis")
     noiseSeed = IntProperty(name="Seed",
                             default=1,
                             min=0, soft_min=0,
                             description="Random Seed")
-    noiseType = IntProperty(name="Type",
-                            default=0,
-                            min=0, soft_min=0,
-                            max=1, soft_max=1,
-                            description="Noise curve type: Linear or Knot")
+
 
     ##### DRAW #####
     def draw(self, context):
@@ -1193,6 +1210,14 @@ class Curveaceous_galore(Operator):
             box.prop(self, 'seed')
             box.prop(self, 'basis')
 
+        elif self.ProfileType == 'Cycloid':
+            box.prop(self, 'cycloPoints')
+            box.prop(self, 'cycloType')
+            box.prop(self, 'cyclo_a')
+            box.prop(self, 'cyclo_b')
+            if self.cycloType != 0:
+                box.prop(self, 'cyclo_d')
+
         elif self.ProfileType == 'Helix':
             box.prop(self, 'helixPoints')
             box.prop(self, 'helixHeight')
@@ -1202,18 +1227,17 @@ class Curveaceous_galore(Operator):
             box.prop(self, 'helix_a')
             box.prop(self, 'helix_b')
 
-        elif self.ProfileType == 'Cycloid':
-            box.prop(self, 'cycloPoints')
-            box.prop(self, 'cycloType')
-            box.prop(self, 'cyclo_a')
-            box.prop(self, 'cyclo_b')
-            box.prop(self, 'cyclo_d')
-
         elif self.ProfileType == 'Noise':
-            box.prop(self, 'noisePoints')
             box.prop(self, 'noiseType')
+            box.prop(self, 'noisePoints')
             box.prop(self, 'noiseLength')
-            box.prop(self, 'noiseScale')
+            if self.noiseType in [0,1]:
+                box.prop(self, 'noiseSize')
+                box.prop(self, 'noiseScaleX')
+                box.prop(self, 'noiseScaleY')
+            box.prop(self, 'noiseScaleZ')
+            if self.noiseType == 0:
+                box.prop(self, 'noiseTaper')
             box.prop(self, 'noiseOctaves')
             box.prop(self, 'noiseBasis')
             box.prop(self, 'noiseSeed')
@@ -1223,11 +1247,10 @@ class Curveaceous_galore(Operator):
         col.row().prop(self, 'outputType', expand=True)
 
         # output options
-        box = layout.box()
         if self.outputType == 'NURBS':
-            box.prop(self, 'order_u')
+            col.prop(self, 'order_u')
         elif self.outputType == 'BEZIER':
-            box.row().prop(self, 'handleType', expand=True)
+            col.row().prop(self, 'handleType', expand=True)
 
     ##### POLL #####
     @classmethod
@@ -1254,7 +1277,10 @@ class Curveaceous_galore(Operator):
                 else:
                     self.use_cyclic_u = True
         else:
-            self.use_cyclic_u = True
+            if self.ProfileType == 'Arc' and self.arcType == 1:
+                self.use_cyclic_u = False
+            else:
+                self.use_cyclic_u = True
 
         # main function
         main(context, self, self.align_matrix or Matrix())
diff --git a/add_curve_extra_objects/add_curve_spirofit_bouncespline.py b/add_curve_extra_objects/add_curve_spirofit_bouncespline.py
new file mode 100644
index 0000000000000000000000000000000000000000..9b5d7aee3176cdad413424449fb22b9472a38b1f
--- /dev/null
+++ b/add_curve_extra_objects/add_curve_spirofit_bouncespline.py
@@ -0,0 +1,630 @@
+# ##### 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 #####
+
+
+bl_info = {
+    "name": "SpiroFit and BounceSpline",
+    "author": "Jimmy Hazevoet, Antonio Osprite, Liero, Atom",
+    "version": (0, 2, 0),
+    "blender": (2, 78, 0),
+    "location": "Toolshelf > Misc Tab",
+    "description": "SpiroFit and BounceSpline adds splines to Mesh",
+    "warning": "",
+    "wiki_url": "",
+    "category": "Object",
+}
+
+
+import bpy
+from bpy.props import (
+        BoolProperty,
+        EnumProperty,
+        FloatProperty,
+        IntProperty,
+        )
+from mathutils import (
+        Matrix,
+        Vector,
+        )
+from math import (
+        sin,
+        cos,
+        pi
+        )
+from bpy.types import Operator
+import random as r
+
+
+# ------------------------------------------------------------
+#
+def use_random_seed(seed):
+    r.seed(seed)
+    return
+
+# ------------------------------------------------------------
+# 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')
+    curve.dimensions = '3D'
+    spline = curve.splines.new(spline_type)
+    cur = bpy.data.objects.new('Curve',curve)
+
+    if spline_type == 'BEZIER':
+        spline.bezier_points.add(int(len(verts)-1))
+        for i in range(len(verts)):
+            spline.bezier_points[i].co = verts[i]
+            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
+    else:
+        spline.points.add(int(len(verts)-1))
+        for i in range(len(verts)):
+            spline.points[i].co = verts[i][0], verts[i][1], verts[i][2], 1
+
+    bpy.context.scene.objects.link(cur)
+    cur.data.use_uv_as_generated = True
+    cur.data.resolution_u = spline_resolution
+    cur.data.fill_mode = 'FULL'
+    cur.data.bevel_depth = bevel
+    cur.data.bevel_resolution = bevel_resolution
+    cur.matrix_world = matrix
+    if x_ray:
+        cur.show_x_ray = x_ray
+    return
+
+
+# ------------------------------------------------------------
+# Spirofit, original blender 2.45 script by: Antonio Osprite
+# http://www.kino3d.com/forum/viewtopic.php?t=5374
+# ------------------------------------------------------------
+
+def distance(v1, v2):
+    d = (Vector(v1) - Vector(v2)).length
+    return d
+
+
+def spiral_point(step, radius, z_coord, spires, waves, wave_height, rndm):
+    x = radius * cos(spires*step) + r.random()*rndm
+    y = radius * sin(spires*step) + r.random()*rndm
+    z = z_coord + (cos(waves*step*pi)*wave_height) + r.random()*rndm
+    return [x, y, z]
+
+
+def do_object_mapping(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
+
+    return [mapped[0], mapped[1], mapped[2]]
+
+
+def spirofit_spline(obj,
+                    spires=4,
+                    spire_resolution=4,
+                    waves=0,
+                    wave_height=0.0,
+                    rndm_spire=0.0,
+                    offset=0.0):
+
+    points = []
+    bb = obj.bound_box
+    bb_xmin = min([ v[0] for v in bb ])
+    bb_ymin = min([ v[1] for v in bb ])
+    bb_zmin = min([ v[2] for v in bb ])
+    bb_xmax = max([ v[0] for v in bb ])
+    bb_ymax = max([ v[1] for v in bb ])
+    bb_zmax = max([ v[2] for v in bb ])
+
+    radius = distance([bb_xmax, bb_ymax, bb_zmin], [bb_xmin, bb_ymin, bb_zmin]) / 2.0
+    height = bb_zmax - bb_zmin
+    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)
+    cp = do_object_mapping(obj, cp, center, offset)
+
+    steps = spires * spire_resolution
+    for i in range(1, 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)
+        cp = do_object_mapping(obj, cp, center, offset)
+
+        points.append(cp)
+    return points
+
+
+# ------------------------------------------------------------
+
+class SpiroFitSpline(bpy.types.Operator):
+    bl_idname = "wm.add_spirofit_spline"
+    bl_label = "SpiroFit"
+    bl_description="Adds a spirofit to selected mesh"
+    bl_options = {'REGISTER', 'UNDO', 'PRESET'}
+
+    spire_resolution = bpy.props.IntProperty(name="Spire Resolution",
+            default=4,
+            min=3, soft_min=3,
+            max=128, soft_max=128,
+            description="Spire Resolution")
+
+    spires = bpy.props.IntProperty(name="Spires",
+            default=4,
+            min=1, soft_min=1,
+            max=512, soft_max=512,
+            description="Number of Spire Turns")
+
+    waves = bpy.props.IntProperty(name="Waves Amount",
+            default=0,
+            min=0, soft_min=0,
+            description="Waves amount")
+
+    wave_height = bpy.props.FloatProperty(name="Wave Intensity",
+            default=0.1,
+            min=0.0, soft_min=0.0,
+            description="Wave intensity scale")
+
+    rndm_spire = bpy.props.FloatProperty(name="Randomize",
+            default=0.0,
+            min=0.0, soft_min=0.0,
+            description="Randomize spire")
+
+    offset = bpy.props.FloatProperty(name="Offset",
+            default=0.0,
+            description="Use normal direction to offset spline")
+
+
+    splineTypes = [
+            ('POLY', 'Poly', 'POLY'),
+            ('BEZIER', 'Bezier', 'BEZIER')]
+    spline_type = bpy.props.EnumProperty(name="Spline type",
+            default='BEZIER',
+            description="Spline type",
+            items=splineTypes)
+
+    spline_resolution = bpy.props.IntProperty(name="Resolution u",
+            default=12,
+            min=0, soft_min=0,
+            max=64, soft_max=64,
+            description="Curve resolution u")
+
+    bevel = bpy.props.FloatProperty(name="Bevel radius",
+            default=0.0,
+            min=0.0, soft_min=0.0,
+            description="Bevel depth")
+
+    bevel_res = bpy.props.IntProperty(name="Bevel resolution",
+            default=0,
+            min=0, soft_min=0,
+            max=32, soft_max=32,
+            description="Bevel resolution")
+
+    spline_random_radius = bpy.props.FloatProperty(name="Random bevel radius",
+            default=0.0,
+            min=0.0, soft_min=0.0,
+            description="Random radius amount")
+
+    random_seed = bpy.props.IntProperty(name="Random seed",
+            default=1,
+            min=0, soft_min=0,
+            description="Random seed number")
+
+    x_ray = bpy.props.BoolProperty(name="X-Ray",
+            default=True,
+            description = "Make the object draw in front of others")
+
+    updateSpline = bpy.props.BoolProperty(name="Update", description="Update spline", default=False)
+
+
+    @classmethod
+    def poll(self, context):
+        ob = context.active_object
+        return ((ob is not None) and
+                (ob.type == 'MESH') and
+                (context.mode == 'OBJECT'))
+
+
+    def invoke(self, context, event):
+        self.updateSpline = True
+        return self.execute(context)
+
+
+    def execute(self, context):
+        if not self.updateSpline:
+            return {'PASS_THROUGH'}
+
+        undo = context.user_preferences.edit.use_global_undo
+        context.user_preferences.edit.use_global_undo = False
+
+        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+        obj = context.active_object
+        matrix = obj.matrix_world
+
+        if self.random_seed:
+            use_random_seed(self.random_seed)
+
+        points = spirofit_spline(obj,
+                        self.spires,
+                        self.spire_resolution,
+                        self.waves,
+                        self.wave_height,
+                        self.rndm_spire,
+                        self.offset)
+
+        add_curve_object(points,
+                        matrix,
+                        self.x_ray,
+                        self.spline_type,
+                        self.spline_resolution,
+                        self.bevel,
+                        self.bevel_res,
+                        self.spline_random_radius)
+
+        context.user_preferences.edit.use_global_undo = undo
+        return {'FINISHED'}
+
+
+    def draw(self, context):
+        layout = self.layout
+
+        col = layout.column(align=True)
+        row = col.row(align=True)
+
+        row.prop(self, 'x_ray', toggle=True)
+        row.separator()
+
+        row.prop(self, 'updateSpline', toggle=True) #, icon='FILE_REFRESH')
+        row.separator()
+
+        properties = row.operator('wm.add_spirofit_spline', text="Add New")
+        col.separator()
+
+        properties.x_ray = self.x_ray
+
+        properties.spire_resolution = self.spire_resolution
+        properties.spires = self.spires
+        properties.waves = self.waves
+        properties.wave_height = self.wave_height
+        properties.offset = self.offset
+        properties.rndm_spire = self.rndm_spire
+        properties.random_seed = self.random_seed
+
+        properties.spline_type = self.spline_type
+        properties.spline_resolution = self.spline_resolution
+        properties.bevel = self.bevel
+        properties.bevel_res = self.bevel_res
+        properties.spline_random_radius = self.spline_random_radius
+
+        col = layout.column(align=True)
+        col.prop(self, 'spire_resolution')
+        col.prop(self, 'spires')
+        col.prop(self, 'waves')
+        col.prop(self, 'wave_height')
+        col.prop(self, 'offset')
+        col.prop(self, 'rndm_spire')
+        col.prop(self, 'random_seed')
+        col.separator()
+
+        col = layout.column(align=True)
+        col.prop(self, 'spline_type', text="")
+        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')
+
+
+# ------------------------------------------------------------
+# Bounce spline / Fiber mesh
+# 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
+    return vec
+
+
+def bounce_spline(obj,
+                number=1000,
+                ang_noise=0.25,
+                offset=0.0,
+                extra=50,
+                active_face=False):
+
+    dist, points = 1000, []
+    poly = obj.data.polygons
+
+    if active_face:
+        try:
+            n = poly.active
+        except:
+            print("No active face selected")
+            pass
+    else:
+        n = r.randint(0, len(poly)-1)
+
+    end = poly[n].normal.copy() * -1
+    start = poly[n].center
+    points.append(start + offset * end)
+
+    for i in range(number):
+        for ray in range(extra + 1):
+            end += noise(ang_noise)
+            try:
+                foo, hit, nor, index = obj.ray_cast(start, end * dist)
+            except:
+                index = -1
+            if index != -1:
+                start = hit - nor / 10000
+                end = end.reflect(nor).normalized()
+                points.append(hit + offset * nor)
+                break
+        if index == -1:
+            return points
+    return points
+
+# ------------------------------------------------------------
+
+class BounceSpline(bpy.types.Operator):
+    bl_idname = "wm.add_bounce_spline"
+    bl_label = "BounceSpline"
+    bl_description="Adds a bounce spline to selected mesh"
+    bl_options = {'REGISTER', 'UNDO', 'PRESET'}
+
+    random_seed = bpy.props.IntProperty(name="Random seed",
+            default=0,
+            min=0, soft_min=0,
+            description="Random seed number")
+
+    bounce_number = bpy.props.IntProperty(name="Bounces",
+            default=100,
+            min=1, soft_min=1,
+            max=9999, soft_max=9999,
+            description="Number of Bounces")
+
+    ang_noise = bpy.props.FloatProperty(name="Angular noise",
+            default=0.25,
+            min=0.0, soft_min=0.0,
+            description="Add some noise to ray direction")
+
+    offset = bpy.props.FloatProperty(name="Offset",
+            default=0.0,
+            description="Use normal direction to offset spline")
+
+    extra = bpy.props.IntProperty(name="Extra",
+            default=50,
+            min=0, soft_min=0,
+            max=999, soft_max=999,
+            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")
+
+    splineTypes = [
+            ('POLY', 'Poly', 'POLY'),
+            ('BEZIER', 'Bezier', 'BEZIER')]
+    spline_type = bpy.props.EnumProperty(name="Spline type",
+            default='BEZIER',
+            description="Spline type",
+            items=splineTypes)
+
+    spline_resolution = bpy.props.IntProperty(name="Resolution u",
+            default=12,
+            min=0, soft_min=0,
+            max=64, soft_max=64,
+            description="Curve resolution u")
+
+    bevel = bpy.props.FloatProperty(name="Bevel radius",
+            default=0.0,
+            min=0.0, soft_min=0.0,
+            description="Bevel depth")
+
+    bevel_res = bpy.props.IntProperty(name="Bevel resolution",
+            default=0,
+            min=0, soft_min=0,
+            max=32, soft_max=32,
+            description="Bevel resolution")
+
+    spline_random_radius = bpy.props.FloatProperty(name="Random bevel radius",
+            default=0.0,
+            min=0.0, soft_min=0.0,
+            description="Random radius amount")
+
+    x_ray = bpy.props.BoolProperty(name="X-Ray",
+            default=True,
+            description = "Make the object draw in front of others")
+
+    updateSpline = bpy.props.BoolProperty(name="Update", default=False)
+
+
+    @classmethod
+    def poll(self, context):
+        ob = context.active_object
+        return ((ob is not None) and
+                (ob.type == 'MESH') and
+                (context.mode == 'OBJECT'))
+
+
+    def invoke(self, context, event):
+        self.updateSpline = True
+        return self.execute(context)
+
+
+    def execute(self, context):
+        if not self.updateSpline:
+            return {'PASS_THROUGH'}
+
+        undo = context.user_preferences.edit.use_global_undo
+        context.user_preferences.edit.use_global_undo = False
+
+        bpy.ops.object.mode_set(mode='EDIT', toggle=False)
+        bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
+
+        obj = context.active_object
+
+        if self.random_seed:
+            use_random_seed(self.random_seed)
+
+        points = bounce_spline(obj,
+                        self.bounce_number,
+                        self.ang_noise,
+                        self.offset,
+                        self.extra,
+                        self.active_face)
+
+        add_curve_object(points,
+                        obj.matrix_world,
+                        self.x_ray,
+                        self.spline_type,
+                        self.spline_resolution,
+                        self.bevel,
+                        self.bevel_res,
+                        self.spline_random_radius)
+
+        context.user_preferences.edit.use_global_undo = undo
+        return {'FINISHED'}
+
+
+    def draw(self, context):
+        layout = self.layout
+        col = layout.column(align=True)
+        row = col.row(align=True)
+
+        row.prop(self, 'x_ray', toggle=True)
+        row.separator()
+
+        row.prop(self, 'updateSpline', toggle=True) #, icon='FILE_REFRESH')
+        row.separator()
+
+        properties = row.operator('wm.add_bounce_spline', text="Add New")
+        col.separator()
+
+        properties.x_ray = self.x_ray
+
+        properties.bounce_number = self.bounce_number
+        properties.ang_noise = self.ang_noise
+        properties.offset = self.offset
+        properties.extra = self.extra
+        properties.random_seed = self.random_seed
+        properties.active_face = self.active_face
+
+        properties.spline_type = self.spline_type
+        properties.spline_resolution = self.spline_resolution
+        properties.bevel = self.bevel
+        properties.bevel_res = self.bevel_res
+        properties.spline_random_radius = self.spline_random_radius
+
+        col = layout.column(align=True)
+        row = col.row(align=True)
+        col.prop(self, 'bounce_number')
+        col.prop(self, 'ang_noise')
+        col.prop(self, 'offset')
+        col.prop(self, 'extra')
+        col.prop(self, 'random_seed')
+        col.separator()
+        col.prop(self, 'active_face', toggle=False)
+
+        col = layout.column(align=True)
+        col.prop(self, 'spline_type', text="")
+        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')
+
+
+# ------------------------------------------------------------
+# Tools Panel > Misc
+# ------------------------------------------------------------
+
+class SplinePanel( bpy.types.Panel ):
+    bl_space_type = "VIEW_3D"
+    bl_context = "objectmode"
+    bl_region_type = "TOOLS"
+    bl_label = "Add Spline to Mesh"
+    bl_category = "Create"
+    bl_options = {'DEFAULT_CLOSED'}
+
+    def draw( self, context ):
+        scn = context.scene
+        layout = self.layout
+        col = self.layout.column()
+        col.operator(SpiroFitSpline.bl_idname, icon="FORCE_MAGNETIC")
+        col.separator()
+        col.operator(BounceSpline.bl_idname, icon="FORCE_HARMONIC")
+
+# ------------------------------------------------------------ # icon="CURVE_DATA"
+# Menu: Add > Curve >
+# ------------------------------------------------------------
+
+'''
+def menu_func(self, context):
+    self.layout.operator(SpiroFitSpline.bl_idname, icon="PLUGIN")
+    self.layout.operator(BounceSpline.bl_idname, icon="PLUGIN")
+'''
+
+# ------------------------------------------------------------
+# Register
+# ------------------------------------------------------------
+
+def register():
+    bpy.utils.register_class(SpiroFitSpline)
+    bpy.utils.register_class(BounceSpline)
+    bpy.utils.register_class(SplinePanel)
+
+    #bpy.types.INFO_MT_curve_add.append(menu_func)
+
+def unregister():
+    bpy.utils.unregister_class(SpiroFitSpline)
+    bpy.utils.unregister_class(BounceSpline)
+    bpy.utils.unregister_class(SplinePanel)
+    #bpy.types.INFO_MT_curve_add.remove(menu_func)
+
+if __name__ == "__main__":
+    register()