diff --git a/mesh_looptools.py b/mesh_looptools.py
deleted file mode 100644
index 639b9d7d117ee687cf309708e7c3dc5ebc2e7269..0000000000000000000000000000000000000000
--- a/mesh_looptools.py
+++ /dev/null
@@ -1,3728 +0,0 @@
-# ##### 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': "LoopTools",
-    'author': "Bart Crouch",
-    'version': (3, 2, 4),
-    'blender': (2, 6, 2),
-    'location': "View3D > Toolbar and View3D > Specials (W-key)",
-    'warning': "Bridge & Loft functions removed",
-    'description': "Mesh modelling toolkit. Several tools to aid modelling",
-    'wiki_url': "http://wiki.blender.org/index.php/Extensions:2.5/Py/"\
-        "Scripts/Modeling/LoopTools",
-    'tracker_url': "http://projects.blender.org/tracker/index.php?"\
-        "func=detail&aid=26189",
-    'category': 'Mesh'}
-
-
-import bpy
-import mathutils
-import math
-
-
-##########################################
-####### General functions ################
-##########################################
-
-
-# used by all tools to improve speed on reruns
-looptools_cache = {}
-
-
-# force a full recalculation next time
-def cache_delete(tool):
-    if tool in looptools_cache:
-        del looptools_cache[tool]
-
-
-# check cache for stored information
-def cache_read(tool, object, mesh, input_method, boundaries):
-    # current tool not cached yet
-    if tool not in looptools_cache:
-        return(False, False, False, False, False)
-    # check if selected object didn't change
-    if object.name != looptools_cache[tool]["object"]:
-        return(False, False, False, False, False)
-    # check if input didn't change
-    if input_method != looptools_cache[tool]["input_method"]:
-        return(False, False, False, False, False)
-    if boundaries != looptools_cache[tool]["boundaries"]:
-        return(False, False, False, False, False)
-    modifiers = [mod.name for mod in object.modifiers if mod.show_viewport \
-        and mod.type == 'MIRROR']
-    if modifiers != looptools_cache[tool]["modifiers"]:
-        return(False, False, False, False, False)
-    input = [v.index for v in mesh.vertices if v.select and not v.hide]
-    if input != looptools_cache[tool]["input"]:
-        return(False, False, False, False, False)
-    # reading values
-    single_loops = looptools_cache[tool]["single_loops"]
-    loops = looptools_cache[tool]["loops"]
-    derived = looptools_cache[tool]["derived"]
-    mapping = looptools_cache[tool]["mapping"]
-    
-    return(True, single_loops, loops, derived, mapping)
-
-
-# store information in the cache
-def cache_write(tool, object, mesh, input_method, boundaries, single_loops,
-loops, derived, mapping):
-    # clear cache of current tool
-    if tool in looptools_cache:
-        del looptools_cache[tool]
-    # prepare values to be saved to cache
-    input = [v.index for v in mesh.vertices if v.select and not v.hide]
-    modifiers = [mod.name for mod in object.modifiers if mod.show_viewport \
-        and mod.type == 'MIRROR']
-    # update cache
-    looptools_cache[tool] = {"input": input, "object": object.name,
-        "input_method": input_method, "boundaries": boundaries,
-        "single_loops": single_loops, "loops": loops,
-        "derived": derived, "mapping": mapping, "modifiers": modifiers}
-
-
-# calculates natural cubic splines through all given knots
-def calculate_cubic_splines(mesh_mod, tknots, knots):
-    # hack for circular loops
-    if knots[0] == knots[-1] and len(knots) > 1:
-        circular = True
-        k_new1 = []
-        for k in range(-1, -5, -1):
-            if k - 1 < -len(knots):
-                k += len(knots)
-            k_new1.append(knots[k-1])
-        k_new2 = []
-        for k in range(4):
-            if k + 1 > len(knots) - 1:
-                k -= len(knots)
-            k_new2.append(knots[k+1])
-        for k in k_new1:
-            knots.insert(0, k)
-        for k in k_new2:
-            knots.append(k)
-        t_new1 = []
-        total1 = 0
-        for t in range(-1, -5, -1):
-            if t - 1 < -len(tknots):
-                t += len(tknots)
-            total1 += tknots[t] - tknots[t-1]
-            t_new1.append(tknots[0] - total1)
-        t_new2 = []
-        total2 = 0
-        for t in range(4):
-            if t + 1 > len(tknots) - 1:
-                t -= len(tknots)
-            total2 += tknots[t+1] - tknots[t]
-            t_new2.append(tknots[-1] + total2)
-        for t in t_new1:
-            tknots.insert(0, t)
-        for t in t_new2:
-            tknots.append(t)
-    else:
-        circular = False
-    # end of hack
-    
-    n = len(knots)
-    if n < 2:
-        return False
-    x = tknots[:]
-    locs = [mesh_mod.vertices[k].co[:] for k in knots]
-    result = []
-    for j in range(3):
-        a = []
-        for i in locs:
-            a.append(i[j])
-        h = []
-        for i in range(n-1):
-            if x[i+1] - x[i] == 0:
-                h.append(1e-8)
-            else:
-                h.append(x[i+1] - x[i])
-        q = [False]
-        for i in range(1, n-1):
-            q.append(3/h[i]*(a[i+1]-a[i]) - 3/h[i-1]*(a[i]-a[i-1]))
-        l = [1.0]
-        u = [0.0]
-        z = [0.0]
-        for i in range(1, n-1):
-            l.append(2*(x[i+1]-x[i-1]) - h[i-1]*u[i-1])
-            if l[i] == 0:
-                l[i] = 1e-8
-            u.append(h[i] / l[i])
-            z.append((q[i] - h[i-1] * z[i-1]) / l[i])
-        l.append(1.0)
-        z.append(0.0)
-        b = [False for i in range(n-1)]
-        c = [False for i in range(n)]
-        d = [False for i in range(n-1)]
-        c[n-1] = 0.0
-        for i in range(n-2, -1, -1):
-            c[i] = z[i] - u[i]*c[i+1]
-            b[i] = (a[i+1]-a[i])/h[i] - h[i]*(c[i+1]+2*c[i])/3
-            d[i] = (c[i+1]-c[i]) / (3*h[i])
-        for i in range(n-1):
-            result.append([a[i], b[i], c[i], d[i], x[i]])
-    splines = []
-    for i in range(len(knots)-1):
-        splines.append([result[i], result[i+n-1], result[i+(n-1)*2]])
-    if circular: # cleaning up after hack
-        knots = knots[4:-4]
-        tknots = tknots[4:-4]
-    
-    return(splines)
-
-
-# calculates linear splines through all given knots
-def calculate_linear_splines(mesh_mod, tknots, knots):
-    splines = []
-    for i in range(len(knots)-1):
-        a = mesh_mod.vertices[knots[i]].co
-        b = mesh_mod.vertices[knots[i+1]].co
-        d = b-a
-        t = tknots[i]
-        u = tknots[i+1]-t
-        splines.append([a, d, t, u]) # [locStart, locDif, tStart, tDif]
-    
-    return(splines)
-
-
-# calculate a best-fit plane to the given vertices
-def calculate_plane(mesh_mod, loop, method="best_fit", object=False):
-    # getting the vertex locations
-    locs = [mesh_mod.vertices[v].co.copy() for v in loop[0]]
-    
-    # calculating the center of masss
-    com = mathutils.Vector()
-    for loc in locs:
-        com += loc
-    com /= len(locs)
-    x, y, z = com
-    
-    if method == 'best_fit':
-        # creating the covariance matrix
-        mat = mathutils.Matrix(((0.0, 0.0, 0.0),
-                                (0.0, 0.0, 0.0),
-                                (0.0, 0.0, 0.0),
-                                ))
-        for loc in locs:
-            mat[0][0] += (loc[0]-x)**2
-            mat[1][0] += (loc[0]-x)*(loc[1]-y)
-            mat[2][0] += (loc[0]-x)*(loc[2]-z)
-            mat[0][1] += (loc[1]-y)*(loc[0]-x)
-            mat[1][1] += (loc[1]-y)**2
-            mat[2][1] += (loc[1]-y)*(loc[2]-z)
-            mat[0][2] += (loc[2]-z)*(loc[0]-x)
-            mat[1][2] += (loc[2]-z)*(loc[1]-y)
-            mat[2][2] += (loc[2]-z)**2
-        
-        # calculating the normal to the plane
-        normal = False
-        try:
-            mat.invert()
-        except:
-            if sum(mat[0]) == 0.0:
-                normal = mathutils.Vector((1.0, 0.0, 0.0))
-            elif sum(mat[1]) == 0.0:
-                normal = mathutils.Vector((0.0, 1.0, 0.0))
-            elif sum(mat[2]) == 0.0:
-                normal = mathutils.Vector((0.0, 0.0, 1.0))
-        if not normal:
-            # warning! this is different from .normalize()
-            itermax = 500
-            iter = 0
-            vec = mathutils.Vector((1.0, 1.0, 1.0))
-            vec2 = (mat * vec)/(mat * vec).length
-            while vec != vec2 and iter<itermax:
-                iter+=1
-                vec = vec2
-                vec2 = mat * vec
-                if vec2.length != 0:
-                    vec2 /= vec2.length
-            if vec2.length == 0:
-                vec2 = mathutils.Vector((1.0, 1.0, 1.0))
-            normal = vec2
-    
-    elif method == 'normal':
-        # averaging the vertex normals
-        v_normals = [mesh_mod.vertices[v].normal for v in loop[0]]
-        normal = mathutils.Vector()
-        for v_normal in v_normals:
-            normal += v_normal
-        normal /= len(v_normals)
-        normal.normalize()
-        
-    elif method == 'view':
-        # calculate view normal
-        rotation = bpy.context.space_data.region_3d.view_matrix.to_3x3().\
-            inverted()
-        normal = rotation * mathutils.Vector((0.0, 0.0, 1.0))
-        if object:
-            normal = object.matrix_world.inverted().to_euler().to_matrix() * \
-                     normal
-    
-    return(com, normal)
-
-
-# calculate splines based on given interpolation method (controller function)
-def calculate_splines(interpolation, mesh_mod, tknots, knots):
-    if interpolation == 'cubic':
-        splines = calculate_cubic_splines(mesh_mod, tknots, knots[:])
-    else: # interpolations == 'linear'
-        splines = calculate_linear_splines(mesh_mod, tknots, knots[:])
-    
-    return(splines)
-
-
-# check loops and only return valid ones
-def check_loops(loops, mapping, mesh_mod):
-    valid_loops = []
-    for loop, circular in loops:
-        # loop needs to have at least 3 vertices
-        if len(loop) < 3:
-            continue
-        # loop needs at least 1 vertex in the original, non-mirrored mesh
-        if mapping:
-            all_virtual = True
-            for vert in loop:
-                if mapping[vert] > -1:
-                    all_virtual = False
-                    break
-            if all_virtual:
-                continue
-        # vertices can not all be at the same location
-        stacked = True
-        for i in range(len(loop) - 1):
-            if (mesh_mod.vertices[loop[i]].co - \
-            mesh_mod.vertices[loop[i+1]].co).length > 1e-6:
-                stacked = False
-                break
-        if stacked:
-            continue    
-        # passed all tests, loop is valid
-        valid_loops.append([loop, circular])
-    
-    return(valid_loops)
-
-
-# input: mesh, output: dict with the edge-key as key and face-index as value
-def dict_edge_faces(mesh):
-    edge_faces = dict([[edge.key, []] for edge in mesh.edges if not edge.hide])
-    for face in mesh.faces:
-        if face.hide:
-            continue
-        for key in face.edge_keys:
-            edge_faces[key].append(face.index)
-    
-    return(edge_faces)
-
-# input: mesh (edge-faces optional), output: dict with face-face connections
-def dict_face_faces(mesh, edge_faces=False):
-    if not edge_faces:
-        edge_faces = dict_edge_faces(mesh)
-    
-    connected_faces = dict([[face.index, []] for face in mesh.faces if \
-        not face.hide])
-    for face in mesh.faces:
-        if face.hide:
-            continue
-        for edge_key in face.edge_keys:
-            for connected_face in edge_faces[edge_key]:
-                if connected_face == face.index:
-                    continue
-                connected_faces[face.index].append(connected_face)
-    
-    return(connected_faces)
-
-
-# input: mesh, output: dict with the vert index as key and edge-keys as value
-def dict_vert_edges(mesh):
-    vert_edges = dict([[v.index, []] for v in mesh.vertices if not v.hide])
-    for edge in mesh.edges:
-        if edge.hide:
-            continue
-        for vert in edge.key:
-            vert_edges[vert].append(edge.key)
-    
-    return(vert_edges)
-
-
-# input: mesh, output: dict with the vert index as key and face index as value
-def dict_vert_faces(mesh):
-    vert_faces = dict([[v.index, []] for v in mesh.vertices if not v.hide])
-    for face in mesh.faces:
-        if not face.hide:
-            for vert in face.vertices:
-                vert_faces[vert].append(face.index)
-                
-    return(vert_faces)
-
-
-# input: list of edge-keys, output: dictionary with vertex-vertex connections
-def dict_vert_verts(edge_keys):
-    # create connection data
-    vert_verts = {}
-    for ek in edge_keys:
-        for i in range(2):
-            if ek[i] in vert_verts:
-                vert_verts[ek[i]].append(ek[1-i])
-            else:
-                vert_verts[ek[i]] = [ek[1-i]]
-    
-    return(vert_verts)
-
-
-# calculate input loops
-def get_connected_input(object, mesh, scene, input):
-    # get mesh with modifiers applied
-    derived, mesh_mod = get_derived_mesh(object, mesh, scene)
-    
-    # calculate selected loops
-    edge_keys = [edge.key for edge in mesh_mod.edges if \
-        edge.select and not edge.hide]
-    loops = get_connected_selections(edge_keys)
-    
-    # if only selected loops are needed, we're done
-    if input == 'selected':
-        return(derived, mesh_mod, loops)
-    # elif input == 'all':    
-    loops = get_parallel_loops(mesh_mod, loops)
-    
-    return(derived, mesh_mod, loops)
-
-
-# sorts all edge-keys into a list of loops
-def get_connected_selections(edge_keys):
-    # create connection data
-    vert_verts = dict_vert_verts(edge_keys)
-    
-    # find loops consisting of connected selected edges
-    loops = []
-    while len(vert_verts) > 0:
-        loop = [iter(vert_verts.keys()).__next__()]
-        growing = True
-        flipped = False
-        
-        # extend loop
-        while growing:
-            # no more connection data for current vertex
-            if loop[-1] not in vert_verts:
-                if not flipped:
-                    loop.reverse()
-                    flipped = True
-                else:
-                    growing = False
-            else:
-                extended = False
-                for i, next_vert in enumerate(vert_verts[loop[-1]]):
-                    if next_vert not in loop:
-                        vert_verts[loop[-1]].pop(i)
-                        if len(vert_verts[loop[-1]]) == 0:
-                            del vert_verts[loop[-1]]
-                        # remove connection both ways
-                        if next_vert in vert_verts:
-                            if len(vert_verts[next_vert]) == 1:
-                                del vert_verts[next_vert]
-                            else:
-                                vert_verts[next_vert].remove(loop[-1])
-                        loop.append(next_vert)
-                        extended = True
-                        break
-                if not extended:
-                    # found one end of the loop, continue with next
-                    if not flipped:
-                        loop.reverse()
-                        flipped = True
-                    # found both ends of the loop, stop growing
-                    else:
-                        growing = False
-        
-        # check if loop is circular
-        if loop[0] in vert_verts:
-            if loop[-1] in vert_verts[loop[0]]:
-                # is circular
-                if len(vert_verts[loop[0]]) == 1:
-                    del vert_verts[loop[0]]
-                else:
-                    vert_verts[loop[0]].remove(loop[-1])
-                if len(vert_verts[loop[-1]]) == 1:
-                    del vert_verts[loop[-1]]
-                else:
-                    vert_verts[loop[-1]].remove(loop[0])
-                loop = [loop, True]
-            else:
-                # not circular
-                loop = [loop, False]
-        else:
-            # not circular
-            loop = [loop, False]
-        
-        loops.append(loop)
-    
-    return(loops)
-
-
-# get the derived mesh data, if there is a mirror modifier
-def get_derived_mesh(object, mesh, scene):
-    # check for mirror modifiers
-    if 'MIRROR' in [mod.type for mod in object.modifiers if mod.show_viewport]:
-        derived = True
-        # disable other modifiers
-        show_viewport = [mod.name for mod in object.modifiers if \
-            mod.show_viewport]
-        for mod in object.modifiers:
-            if mod.type != 'MIRROR':
-                mod.show_viewport = False
-        # get derived mesh
-        mesh_mod = object.to_mesh(scene, True, 'PREVIEW')
-        # re-enable other modifiers
-        for mod_name in show_viewport:
-            object.modifiers[mod_name].show_viewport = True
-    # no mirror modifiers, so no derived mesh necessary
-    else:
-        derived = False
-        mesh_mod = mesh
-    
-    return(derived, mesh_mod)
-
-
-# return a mapping of derived indices to indices
-def get_mapping(derived, mesh, mesh_mod, single_vertices, full_search, loops):
-    if not derived:
-        return(False)
-    
-    if full_search:
-        verts = [v for v in mesh.vertices if not v.hide]
-    else:
-        verts = [v for v in mesh.vertices if v.select and not v.hide]
-    
-    # non-selected vertices around single vertices also need to be mapped
-    if single_vertices:
-        mapping = dict([[vert, -1] for vert in single_vertices])
-        verts_mod = [mesh_mod.vertices[vert] for vert in single_vertices]
-        for v in verts:
-            for v_mod in verts_mod:
-                if (v.co - v_mod.co).length < 1e-6:
-                    mapping[v_mod.index] = v.index
-                    break
-        real_singles = [v_real for v_real in mapping.values() if v_real>-1]
-        
-        verts_indices = [vert.index for vert in verts]
-        for face in [face for face in mesh.faces if not face.select \
-        and not face.hide]:
-            for vert in face.vertices:
-                if vert in real_singles:
-                    for v in face.vertices:
-                        if not v in verts_indices:
-                            if mesh.vertices[v] not in verts:
-                                verts.append(mesh.vertices[v])
-                    break
-    
-    # create mapping of derived indices to indices
-    mapping = dict([[vert, -1] for loop in loops for vert in loop[0]])
-    if single_vertices:
-        for single in single_vertices:
-            mapping[single] = -1
-    verts_mod = [mesh_mod.vertices[i] for i in mapping.keys()]
-    for v in verts:
-        for v_mod in verts_mod:
-            if (v.co - v_mod.co).length < 1e-6:
-                mapping[v_mod.index] = v.index
-                verts_mod.remove(v_mod)
-                break
-    
-    return(mapping)
-
-
-# returns a list of all loops parallel to the input, input included
-def get_parallel_loops(mesh_mod, loops):
-    # get required dictionaries
-    edge_faces = dict_edge_faces(mesh_mod)
-    connected_faces = dict_face_faces(mesh_mod, edge_faces)
-    # turn vertex loops into edge loops
-    edgeloops = []
-    for loop in loops:
-        edgeloop = [[sorted([loop[0][i], loop[0][i+1]]) for i in \
-            range(len(loop[0])-1)], loop[1]]
-        if loop[1]: # circular
-            edgeloop[0].append(sorted([loop[0][-1], loop[0][0]]))
-        edgeloops.append(edgeloop[:])
-    # variables to keep track while iterating
-    all_edgeloops = []
-    has_branches = False
-    
-    for loop in edgeloops:
-        # initialise with original loop
-        all_edgeloops.append(loop[0])
-        newloops = [loop[0]]
-        verts_used = []
-        for edge in loop[0]:
-            if edge[0] not in verts_used:
-                verts_used.append(edge[0])
-            if edge[1] not in verts_used:
-                verts_used.append(edge[1])
-        
-        # find parallel loops
-        while len(newloops) > 0:
-            side_a = []
-            side_b = []
-            for i in newloops[-1]:
-                i = tuple(i)
-                forbidden_side = False
-                if not i in edge_faces:
-                    # weird input with branches
-                    has_branches = True
-                    break
-                for face in edge_faces[i]:
-                    if len(side_a) == 0 and forbidden_side != "a":
-                        side_a.append(face)
-                        if forbidden_side:
-                            break
-                        forbidden_side = "a"
-                        continue
-                    elif side_a[-1] in connected_faces[face] and \
-                    forbidden_side != "a":
-                        side_a.append(face)
-                        if forbidden_side:
-                            break
-                        forbidden_side = "a"
-                        continue
-                    if len(side_b) == 0 and forbidden_side != "b":
-                        side_b.append(face)
-                        if forbidden_side:
-                            break
-                        forbidden_side = "b"
-                        continue
-                    elif side_b[-1] in connected_faces[face] and \
-                    forbidden_side != "b":
-                        side_b.append(face)
-                        if forbidden_side:
-                            break
-                        forbidden_side = "b"
-                        continue
-            
-            if has_branches:
-                # weird input with branches
-                break
-            
-            newloops.pop(-1)
-            sides = []
-            if side_a:
-                sides.append(side_a)
-            if side_b:
-                sides.append(side_b)
-            
-            for side in sides:
-                extraloop = []
-                for fi in side:
-                    for key in mesh_mod.faces[fi].edge_keys:
-                        if key[0] not in verts_used and key[1] not in \
-                        verts_used:
-                            extraloop.append(key)
-                            break
-                if extraloop:
-                    for key in extraloop:
-                        for new_vert in key:
-                            if new_vert not in verts_used:
-                                verts_used.append(new_vert)
-                    newloops.append(extraloop)
-                    all_edgeloops.append(extraloop)
-    
-    # input contains branches, only return selected loop
-    if has_branches:
-        return(loops)
-    
-    # change edgeloops into normal loops
-    loops = []
-    for edgeloop in all_edgeloops:
-        loop = []
-        # grow loop by comparing vertices between consecutive edge-keys
-        for i in range(len(edgeloop)-1):
-            for vert in range(2):
-                if edgeloop[i][vert] in edgeloop[i+1]:
-                    loop.append(edgeloop[i][vert])
-                    break
-        if loop:
-            # add starting vertex
-            for vert in range(2):
-                if edgeloop[0][vert] != loop[0]:
-                    loop = [edgeloop[0][vert]] + loop
-                    break
-            # add ending vertex
-            for vert in range(2):
-                if edgeloop[-1][vert] != loop[-1]:
-                    loop.append(edgeloop[-1][vert])
-                    break
-            # check if loop is circular
-            if loop[0] == loop[-1]:
-                circular = True
-                loop = loop[:-1]
-            else:
-                circular = False
-        loops.append([loop, circular])
-    
-    return(loops)
-
-
-# gather initial data
-def initialise():
-    global_undo = bpy.context.user_preferences.edit.use_global_undo
-    bpy.context.user_preferences.edit.use_global_undo = False
-    bpy.ops.object.mode_set(mode='OBJECT')
-    object = bpy.context.active_object
-    mesh = bpy.context.active_object.data
-    
-    return(global_undo, object, mesh)
-
-
-# move the vertices to their new locations
-def move_verts(mesh, mapping, move, influence):
-    for loop in move:
-        for index, loc in loop:
-            if mapping:
-                if mapping[index] == -1:
-                    continue
-                else:
-                    index = mapping[index]
-            if influence >= 0:
-                mesh.vertices[index].co = loc*(influence/100) + \
-                    mesh.vertices[index].co*((100-influence)/100)
-            else:
-                mesh.vertices[index].co = loc
-
-
-# load custom tool settings 
-def settings_load(self):
-    lt = bpy.context.window_manager.looptools
-    tool = self.name.split()[0].lower()
-    keys = self.as_keywords().keys()
-    for key in keys:
-        setattr(self, key, getattr(lt, tool + "_" + key))
-
-
-# store custom tool settings
-def settings_write(self):
-    lt = bpy.context.window_manager.looptools
-    tool = self.name.split()[0].lower()
-    keys = self.as_keywords().keys()
-    for key in keys:
-        setattr(lt, tool + "_" + key, getattr(self, key))
-
-
-# clean up and set settings back to original state
-def terminate(global_undo):
-    bpy.ops.object.mode_set(mode='EDIT')
-    bpy.context.user_preferences.edit.use_global_undo = global_undo
-
-
-##########################################
-####### Bridge functions #################
-##########################################
-
-# calculate a cubic spline through the middle section of 4 given coordinates
-def bridge_calculate_cubic_spline(mesh, coordinates):
-    result = []
-    x = [0, 1, 2, 3]
-    
-    for j in range(3):
-        a = []
-        for i in coordinates:
-            a.append(float(i[j]))
-        h = []
-        for i in range(3):
-            h.append(x[i+1]-x[i])
-        q = [False]
-        for i in range(1,3):
-            q.append(3.0/h[i]*(a[i+1]-a[i])-3.0/h[i-1]*(a[i]-a[i-1]))
-        l = [1.0]
-        u = [0.0]
-        z = [0.0]
-        for i in range(1,3):
-            l.append(2.0*(x[i+1]-x[i-1])-h[i-1]*u[i-1])
-            u.append(h[i]/l[i])
-            z.append((q[i]-h[i-1]*z[i-1])/l[i])
-        l.append(1.0)
-        z.append(0.0)
-        b = [False for i in range(3)]
-        c = [False for i in range(4)]
-        d = [False for i in range(3)]
-        c[3] = 0.0
-        for i in range(2,-1,-1):
-            c[i] = z[i]-u[i]*c[i+1]
-            b[i] = (a[i+1]-a[i])/h[i]-h[i]*(c[i+1]+2.0*c[i])/3.0
-            d[i] = (c[i+1]-c[i])/(3.0*h[i])
-        for i in range(3):
-            result.append([a[i], b[i], c[i], d[i], x[i]])
-    spline = [result[1], result[4], result[7]]
-
-    return(spline)
-
-
-# return a list with new vertex location vectors, a list with face vertex 
-# integers, and the highest vertex integer in the virtual mesh
-def bridge_calculate_geometry(mesh, lines, vertex_normals, segments,
-interpolation, cubic_strength, min_width, max_vert_index):
-    new_verts = []
-    faces = []
-    
-    # calculate location based on interpolation method
-    def get_location(line, segment, splines):
-        v1 = mesh.vertices[lines[line][0]].co
-        v2 = mesh.vertices[lines[line][1]].co
-        if interpolation == 'linear':
-            return v1 + (segment/segments) * (v2-v1)
-        else: # interpolation == 'cubic'
-            m = (segment/segments)
-            ax,bx,cx,dx,tx = splines[line][0]
-            x = ax+bx*m+cx*m**2+dx*m**3
-            ay,by,cy,dy,ty = splines[line][1]
-            y = ay+by*m+cy*m**2+dy*m**3
-            az,bz,cz,dz,tz = splines[line][2]
-            z = az+bz*m+cz*m**2+dz*m**3
-            return mathutils.Vector((x, y, z))
-        
-    # no interpolation needed
-    if segments == 1:
-        for i, line in enumerate(lines):
-            if i < len(lines)-1:
-                faces.append([line[0], lines[i+1][0], lines[i+1][1], line[1]])
-    # more than 1 segment, interpolate
-    else:
-        # calculate splines (if necessary) once, so no recalculations needed
-        if interpolation == 'cubic':
-            splines = []
-            for line in lines:
-                v1 = mesh.vertices[line[0]].co
-                v2 = mesh.vertices[line[1]].co
-                size = (v2-v1).length * cubic_strength
-                splines.append(bridge_calculate_cubic_spline(mesh,
-                    [v1+size*vertex_normals[line[0]], v1, v2,
-                    v2+size*vertex_normals[line[1]]]))
-        else:
-            splines = False
-        
-        # create starting situation
-        virtual_width = [(mesh.vertices[lines[i][0]].co -
-                          mesh.vertices[lines[i+1][0]].co).length for i
-                          in range(len(lines)-1)]
-        new_verts = [get_location(0, seg, splines) for seg in range(1,
-            segments)]
-        first_line_indices = [i for i in range(max_vert_index+1,
-            max_vert_index+segments)]
-        
-        prev_verts = new_verts[:] # vertex locations of verts on previous line
-        prev_vert_indices = first_line_indices[:]
-        max_vert_index += segments - 1 # highest vertex index in virtual mesh
-        next_verts = [] # vertex locations of verts on current line
-        next_vert_indices = []
-        
-        for i, line in enumerate(lines):
-            if i < len(lines)-1:
-                v1 = line[0]
-                v2 = lines[i+1][0]
-                end_face = True
-                for seg in range(1, segments):
-                    loc1 = prev_verts[seg-1]
-                    loc2 = get_location(i+1, seg, splines)
-                    if (loc1-loc2).length < (min_width/100)*virtual_width[i] \
-                    and line[1]==lines[i+1][1]:
-                        # triangle, no new vertex
-                        faces.append([v1, v2, prev_vert_indices[seg-1],
-                            prev_vert_indices[seg-1]])
-                        next_verts += prev_verts[seg-1:]
-                        next_vert_indices += prev_vert_indices[seg-1:]
-                        end_face = False
-                        break
-                    else:
-                        if i == len(lines)-2 and lines[0] == lines[-1]:
-                            # quad with first line, no new vertex
-                            faces.append([v1, v2, first_line_indices[seg-1],
-                                prev_vert_indices[seg-1]])
-                            v2 = first_line_indices[seg-1]
-                            v1 = prev_vert_indices[seg-1]
-                        else:
-                            # quad, add new vertex
-                            max_vert_index += 1
-                            faces.append([v1, v2, max_vert_index,
-                                prev_vert_indices[seg-1]])
-                            v2 = max_vert_index
-                            v1 = prev_vert_indices[seg-1]
-                            new_verts.append(loc2)
-                            next_verts.append(loc2)
-                            next_vert_indices.append(max_vert_index)
-                if end_face:
-                    faces.append([v1, v2, lines[i+1][1], line[1]])
-                
-                prev_verts = next_verts[:]
-                prev_vert_indices = next_vert_indices[:]
-                next_verts = []
-                next_vert_indices = []
-    
-    return(new_verts, faces, max_vert_index)
-
-
-# calculate lines (list of lists, vertex indices) that are used for bridging
-def bridge_calculate_lines(mesh, loops, mode, twist, reverse):
-    lines = []
-    loop1, loop2 = [i[0] for i in loops]
-    loop1_circular, loop2_circular = [i[1] for i in loops]
-    circular = loop1_circular or loop2_circular
-    circle_full = False
-    
-    # calculate loop centers
-    centers = []
-    for loop in [loop1, loop2]:
-        center = mathutils.Vector()
-        for vertex in loop:
-            center += mesh.vertices[vertex].co
-        center /= len(loop)
-        centers.append(center)
-    for i, loop in enumerate([loop1, loop2]):
-        for vertex in loop:
-            if mesh.vertices[vertex].co == centers[i]:
-                # prevent zero-length vectors in angle comparisons
-                centers[i] += mathutils.Vector((0.01, 0, 0))
-                break
-    center1, center2 = centers
-    
-    # calculate the normals of the virtual planes that the loops are on
-    normals = []
-    normal_plurity = False
-    for i, loop in enumerate([loop1, loop2]):
-        # covariance matrix
-        mat = mathutils.Matrix(((0.0, 0.0, 0.0),
-                                (0.0, 0.0, 0.0),
-                                (0.0, 0.0, 0.0)))
-        x, y, z = centers[i]
-        for loc in [mesh.vertices[vertex].co for vertex in loop]:
-            mat[0][0] += (loc[0]-x)**2
-            mat[1][0] += (loc[0]-x)*(loc[1]-y)
-            mat[2][0] += (loc[0]-x)*(loc[2]-z)
-            mat[0][1] += (loc[1]-y)*(loc[0]-x)
-            mat[1][1] += (loc[1]-y)**2
-            mat[2][1] += (loc[1]-y)*(loc[2]-z)
-            mat[0][2] += (loc[2]-z)*(loc[0]-x)
-            mat[1][2] += (loc[2]-z)*(loc[1]-y)
-            mat[2][2] += (loc[2]-z)**2
-        # plane normal
-        normal = False
-        if sum(mat[0]) < 1e-6 or sum(mat[1]) < 1e-6 or sum(mat[2]) < 1e-6:
-            normal_plurity = True
-        try:
-            mat.invert()
-        except:
-            if sum(mat[0]) == 0:
-                normal = mathutils.Vector((1.0, 0.0, 0.0))
-            elif sum(mat[1]) == 0:
-                normal = mathutils.Vector((0.0, 1.0, 0.0))
-            elif sum(mat[2]) == 0:
-                normal = mathutils.Vector((0.0, 0.0, 1.0))
-        if not normal:
-            # warning! this is different from .normalize()
-            itermax = 500
-            iter = 0
-            vec = mathutils.Vector((1.0, 1.0, 1.0))
-            vec2 = (mat * vec)/(mat * vec).length
-            while vec != vec2 and iter<itermax:
-                iter+=1
-                vec = vec2
-                vec2 = mat * vec
-                if vec2.length != 0:
-                    vec2 /= vec2.length
-            if vec2.length == 0:
-                vec2 = mathutils.Vector((1.0, 1.0, 1.0))
-            normal = vec2
-        normals.append(normal)
-    # have plane normals face in the same direction (maximum angle: 90 degrees)
-    if ((center1 + normals[0]) - center2).length < \
-    ((center1 - normals[0]) - center2).length:
-        normals[0].negate()
-    if ((center2 + normals[1]) - center1).length > \
-    ((center2 - normals[1]) - center1).length:
-        normals[1].negate()
-    
-    # rotation matrix, representing the difference between the plane normals
-    axis = normals[0].cross(normals[1])
-    axis = mathutils.Vector([loc if abs(loc) > 1e-8 else 0 for loc in axis])
-    if axis.angle(mathutils.Vector((0, 0, 1)), 0) > 1.5707964:
-        axis.negate()
-    angle = normals[0].dot(normals[1])
-    rotation_matrix = mathutils.Matrix.Rotation(angle, 4, axis)
-    
-    # if circular, rotate loops so they are aligned
-    if circular:
-        # make sure loop1 is the circular one (or both are circular)
-        if loop2_circular and not loop1_circular:
-            loop1_circular, loop2_circular = True, False
-            loop1, loop2 = loop2, loop1
-        
-        # match start vertex of loop1 with loop2
-        target_vector = mesh.vertices[loop2[0]].co - center2
-        dif_angles = [[(rotation_matrix * (mesh.vertices[vertex].co - center1)
-                       ).angle(target_vector, 0), False, i] for
-                       i, vertex in enumerate(loop1)]
-        dif_angles.sort()
-        if len(loop1) != len(loop2):
-            angle_limit = dif_angles[0][0] * 1.2 # 20% margin
-            dif_angles = [[(mesh.vertices[loop2[0]].co - \
-                mesh.vertices[loop1[index]].co).length, angle, index] for \
-                angle, distance, index in dif_angles if angle <= angle_limit]
-            dif_angles.sort()
-        loop1 = loop1[dif_angles[0][2]:] + loop1[:dif_angles[0][2]]
-    
-    # have both loops face the same way
-    if normal_plurity and not circular:
-        second_to_first, second_to_second, second_to_last = \
-            [(mesh.vertices[loop1[1]].co - center1).\
-            angle(mesh.vertices[loop2[i]].co - center2) for i in [0, 1, -1]]
-        last_to_first, last_to_second = [(mesh.vertices[loop1[-1]].co - \
-            center1).angle(mesh.vertices[loop2[i]].co - center2) for \
-            i in [0, 1]]
-        if (min(last_to_first, last_to_second)*1.1 < min(second_to_first, \
-        second_to_second)) or (loop2_circular and second_to_last*1.1 < \
-        min(second_to_first, second_to_second)):
-            loop1.reverse()
-            if circular:
-                loop1 = [loop1[-1]] + loop1[:-1]
-    else:
-        angle = (mesh.vertices[loop1[0]].co - center1).\
-            cross(mesh.vertices[loop1[1]].co - center1).angle(normals[0], 0)
-        target_angle = (mesh.vertices[loop2[0]].co - center2).\
-            cross(mesh.vertices[loop2[1]].co - center2).angle(normals[1], 0)
-        limit = 1.5707964 # 0.5*pi, 90 degrees
-        if not ((angle > limit and target_angle > limit) or \
-        (angle < limit and target_angle < limit)):
-            loop1.reverse()
-            if circular:
-                loop1 = [loop1[-1]] + loop1[:-1]
-        elif normals[0].angle(normals[1]) > limit:
-            loop1.reverse()
-            if circular:
-                loop1 = [loop1[-1]] + loop1[:-1]
-    
-    # both loops have the same length
-    if len(loop1) == len(loop2):
-        # manual override
-        if twist:
-            if abs(twist) < len(loop1):
-                loop1 = loop1[twist:]+loop1[:twist]
-        if reverse:
-            loop1.reverse()
-        
-        lines.append([loop1[0], loop2[0]])
-        for i in range(1, len(loop1)):
-            lines.append([loop1[i], loop2[i]])
-    
-    # loops of different lengths
-    else:
-        # make loop1 longest loop
-        if len(loop2) > len(loop1):
-            loop1, loop2 = loop2, loop1
-            loop1_circular, loop2_circular = loop2_circular, loop1_circular
-        
-        # manual override
-        if twist:
-            if abs(twist) < len(loop1):
-                loop1 = loop1[twist:]+loop1[:twist]
-        if reverse:
-            loop1.reverse()
-            
-        # shortest angle difference doesn't always give correct start vertex
-        if loop1_circular and not loop2_circular:
-            shifting = 1
-            while shifting:
-                if len(loop1) - shifting < len(loop2):
-                    shifting = False
-                    break
-                to_last, to_first = [(rotation_matrix *
-                    (mesh.vertices[loop1[-1]].co - center1)).angle((mesh.\
-                    vertices[loop2[i]].co - center2), 0) for i in [-1, 0]]
-                if to_first < to_last:
-                    loop1 = [loop1[-1]] + loop1[:-1]
-                    shifting += 1
-                else:
-                    shifting = False
-                    break
-        
-        # basic shortest side first
-        if mode == 'basic':
-            lines.append([loop1[0], loop2[0]])
-            for i in range(1, len(loop1)):
-                if i >= len(loop2) - 1:
-                    # triangles
-                    lines.append([loop1[i], loop2[-1]])
-                else:
-                    # quads
-                    lines.append([loop1[i], loop2[i]])
-        
-        # shortest edge algorithm
-        else: # mode == 'shortest'
-            lines.append([loop1[0], loop2[0]])
-            prev_vert2 = 0
-            for i in range(len(loop1) -1):
-                if prev_vert2 == len(loop2) - 1 and not loop2_circular:
-                    # force triangles, reached end of loop2
-                    tri, quad = 0, 1
-                elif prev_vert2 == len(loop2) - 1 and loop2_circular:
-                    # at end of loop2, but circular, so check with first vert
-                    tri, quad = [(mesh.vertices[loop1[i+1]].co -
-                                  mesh.vertices[loop2[j]].co).length
-                                 for j in [prev_vert2, 0]]
-
-                    circle_full = 2
-                elif len(loop1) - 1 - i == len(loop2) - 1 - prev_vert2 and \
-                not circle_full:
-                    # force quads, otherwise won't make it to end of loop2
-                    tri, quad = 1, 0
-                else:
-                    # calculate if tri or quad gives shortest edge
-                    tri, quad = [(mesh.vertices[loop1[i+1]].co -
-                                  mesh.vertices[loop2[j]].co).length
-                                 for j in range(prev_vert2, prev_vert2+2)]
-                
-                # triangle
-                if tri < quad:
-                    lines.append([loop1[i+1], loop2[prev_vert2]])
-                    if circle_full == 2:
-                        circle_full = False
-                # quad
-                elif not circle_full:
-                    lines.append([loop1[i+1], loop2[prev_vert2+1]])
-                    prev_vert2 += 1
-                # quad to first vertex of loop2
-                else:
-                    lines.append([loop1[i+1], loop2[0]])
-                    prev_vert2 = 0
-                    circle_full = True
-    
-    # final face for circular loops
-    if loop1_circular and loop2_circular:
-        lines.append([loop1[0], loop2[0]])
-    
-    return(lines)
-
-
-# calculate number of segments needed
-def bridge_calculate_segments(mesh, lines, loops, segments):
-    # return if amount of segments is set by user
-    if segments != 0:
-        return segments
-    
-    # edge lengths
-    average_edge_length = [(mesh.vertices[vertex].co - \
-        mesh.vertices[loop[0][i+1]].co).length for loop in loops for \
-        i, vertex in enumerate(loop[0][:-1])]
-    # closing edges of circular loops
-    average_edge_length += [(mesh.vertices[loop[0][-1]].co - \
-        mesh.vertices[loop[0][0]].co).length for loop in loops if loop[1]] 
-    
-    # average lengths
-    average_edge_length = sum(average_edge_length) / len(average_edge_length)
-    average_bridge_length = sum([(mesh.vertices[v1].co - \
-        mesh.vertices[v2].co).length for v1, v2 in lines]) / len(lines)
-    
-    segments = max(1, round(average_bridge_length / average_edge_length))
-        
-    return(segments)
-
-
-# return dictionary with vertex index as key, and the normal vector as value
-def bridge_calculate_virtual_vertex_normals(mesh, lines, loops, edge_faces,
-edgekey_to_edge):
-    if not edge_faces: # interpolation isn't set to cubic
-        return False
-    
-    # pity reduce() isn't one of the basic functions in python anymore
-    def average_vector_dictionary(dic):
-        for key, vectors in dic.items():
-            #if type(vectors) == type([]) and len(vectors) > 1:
-            if len(vectors) > 1:
-                average = mathutils.Vector()
-                for vector in vectors:
-                    average += vector
-                average /= len(vectors)
-                dic[key] = [average]
-        return dic
-    
-    # get all edges of the loop
-    edges = [[edgekey_to_edge[tuple(sorted([loops[j][0][i],
-        loops[j][0][i+1]]))] for i in range(len(loops[j][0])-1)] for \
-        j in [0,1]]
-    edges = edges[0] + edges[1]
-    for j in [0, 1]:
-        if loops[j][1]: # circular
-            edges.append(edgekey_to_edge[tuple(sorted([loops[j][0][0],
-                loops[j][0][-1]]))])
-    
-    """
-    calculation based on face topology (assign edge-normals to vertices)
-    
-    edge_normal = face_normal x edge_vector
-    vertex_normal = average(edge_normals)
-    """
-    vertex_normals = dict([(vertex, []) for vertex in loops[0][0]+loops[1][0]])
-    for edge in edges:
-        faces = edge_faces[edge.key] # valid faces connected to edge
-        
-        if faces:
-            # get edge coordinates
-            v1, v2 = [mesh.vertices[edge.key[i]].co for i in [0,1]]
-            edge_vector = v1 - v2
-            if edge_vector.length < 1e-4:
-                # zero-length edge, vertices at same location
-                continue
-            edge_center = (v1 + v2) / 2
-            
-            # average face coordinates, if connected to more than 1 valid face
-            if len(faces) > 1:
-                face_normal = mathutils.Vector()
-                face_center = mathutils.Vector()
-                for face in faces:
-                    face_normal += face.normal
-                    face_center += face.center
-                face_normal /= len(faces)
-                face_center /= len(faces)
-            else:
-                face_normal = faces[0].normal
-                face_center = faces[0].center
-            if face_normal.length < 1e-4:
-                # faces with a surface of 0 have no face normal
-                continue
-            
-            # calculate virtual edge normal
-            edge_normal = edge_vector.cross(face_normal)
-            edge_normal.length = 0.01
-            if (face_center - (edge_center + edge_normal)).length > \
-            (face_center - (edge_center - edge_normal)).length:
-                # make normal face the correct way
-                edge_normal.negate()
-            edge_normal.normalize()
-            # add virtual edge normal as entry for both vertices it connects
-            for vertex in edge.key:
-                vertex_normals[vertex].append(edge_normal)
-    
-    """ 
-    calculation based on connection with other loop (vertex focused method) 
-    - used for vertices that aren't connected to any valid faces
-    
-    plane_normal = edge_vector x connection_vector
-    vertex_normal = plane_normal x edge_vector
-    """
-    vertices = [vertex for vertex, normal in vertex_normals.items() if not \
-        normal]
-    
-    if vertices:
-        # edge vectors connected to vertices
-        edge_vectors = dict([[vertex, []] for vertex in vertices])
-        for edge in edges:
-            for v in edge.key:
-                if v in edge_vectors:
-                    edge_vector = mesh.vertices[edge.key[0]].co - \
-                        mesh.vertices[edge.key[1]].co
-                    if edge_vector.length < 1e-4:
-                        # zero-length edge, vertices at same location
-                        continue
-                    edge_vectors[v].append(edge_vector)
-    
-        # connection vectors between vertices of both loops
-        connection_vectors = dict([[vertex, []] for vertex in vertices])
-        connections = dict([[vertex, []] for vertex in vertices])
-        for v1, v2 in lines:
-            if v1 in connection_vectors or v2 in connection_vectors:
-                new_vector = mesh.vertices[v1].co - mesh.vertices[v2].co
-                if new_vector.length < 1e-4:
-                    # zero-length connection vector,
-                    # vertices in different loops at same location
-                    continue
-                if v1 in connection_vectors:
-                    connection_vectors[v1].append(new_vector)
-                    connections[v1].append(v2)
-                if v2 in connection_vectors:
-                    connection_vectors[v2].append(new_vector)
-                    connections[v2].append(v1)
-        connection_vectors = average_vector_dictionary(connection_vectors)
-        connection_vectors = dict([[vertex, vector[0]] if vector else \
-            [vertex, []] for vertex, vector in connection_vectors.items()])
-        
-        for vertex, values in edge_vectors.items():
-            # vertex normal doesn't matter, just assign a random vector to it
-            if not connection_vectors[vertex]:
-                vertex_normals[vertex] = [mathutils.Vector((1, 0, 0))]
-                continue
-            
-            # calculate to what location the vertex is connected, 
-            # used to determine what way to flip the normal
-            connected_center = mathutils.Vector()
-            for v in connections[vertex]:
-                connected_center += mesh.vertices[v].co
-            if len(connections[vertex]) > 1:
-                connected_center /= len(connections[vertex])
-            if len(connections[vertex]) == 0:
-                # shouldn't be possible, but better safe than sorry
-                vertex_normals[vertex] = [mathutils.Vector((1, 0, 0))]
-                continue
-            
-            # can't do proper calculations, because of zero-length vector
-            if not values:
-                if (connected_center - (mesh.vertices[vertex].co + \
-                connection_vectors[vertex])).length < (connected_center - \
-                (mesh.vertices[vertex].co - connection_vectors[vertex])).\
-                length:
-                    connection_vectors[vertex].negate()
-                vertex_normals[vertex] = [connection_vectors[vertex].\
-                    normalized()]
-                continue
-            
-            # calculate vertex normals using edge-vectors,
-            # connection-vectors and the derived plane normal
-            for edge_vector in values:
-                plane_normal = edge_vector.cross(connection_vectors[vertex])
-                vertex_normal = edge_vector.cross(plane_normal)
-                vertex_normal.length = 0.1
-                if (connected_center - (mesh.vertices[vertex].co + \
-                vertex_normal)).length < (connected_center - \
-                (mesh.vertices[vertex].co - vertex_normal)).length:
-                # make normal face the correct way
-                    vertex_normal.negate()
-                vertex_normal.normalize()
-                vertex_normals[vertex].append(vertex_normal)
-    
-    # average virtual vertex normals, based on all edges it's connected to
-    vertex_normals = average_vector_dictionary(vertex_normals)
-    vertex_normals = dict([[vertex, vector[0]] for vertex, vector in \
-        vertex_normals.items()])
-    
-    return(vertex_normals)
-
-
-# add vertices to mesh
-def bridge_create_vertices(mesh, vertices):
-    start_index = len(mesh.vertices)
-    mesh.vertices.add(len(vertices))
-    for i in range(len(vertices)):
-        mesh.vertices[start_index + i].co = vertices[i]
-
-
-# add faces to mesh
-def bridge_create_faces(mesh, faces, twist):
-    # have the normal point the correct way
-    if twist < 0:
-        [face.reverse() for face in faces]
-        faces = [face[2:]+face[:2] if face[0]==face[1] else face for \
-            face in faces]
-    
-    # eekadoodle prevention
-    for i in range(len(faces)):
-        if not faces[i][-1]:
-            if faces[i][0] == faces[i][-1]:
-                faces[i] = [faces[i][1], faces[i][2], faces[i][3], faces[i][1]]
-            else:
-                faces[i] = [faces[i][-1]] + faces[i][:-1]
-    
-    start_faces = len(mesh.faces)
-    mesh.faces.add(len(faces))
-    for i in range(len(faces)):
-        mesh.faces[start_faces + i].vertices_raw = faces[i]
-    mesh.update(calc_edges = True) # calc_edges prevents memory-corruption
-
-
-# calculate input loops
-def bridge_get_input(mesh):
-    # create list of internal edges, which should be skipped
-    eks_of_selected_faces = [item for sublist in [face.edge_keys for face \
-        in mesh.faces if face.select and not face.hide] for item in sublist]
-    edge_count = {}
-    for ek in eks_of_selected_faces:
-        if ek in edge_count:
-            edge_count[ek] += 1
-        else:
-            edge_count[ek] = 1
-    internal_edges = [ek for ek in edge_count if edge_count[ek] > 1]
-    
-    # sort correct edges into loops
-    selected_edges = [edge.key for edge in mesh.edges if edge.select \
-        and not edge.hide and edge.key not in internal_edges]
-    loops = get_connected_selections(selected_edges)
-    
-    return(loops)
-
-
-# return values needed by the bridge operator
-def bridge_initialise(mesh, interpolation):
-    if interpolation == 'cubic':
-        # dict with edge-key as key and list of connected valid faces as value
-        face_blacklist = [face.index for face in mesh.faces if face.select or \
-            face.hide]
-        edge_faces = dict([[edge.key, []] for edge in mesh.edges if not \
-            edge.hide])
-        for face in mesh.faces:
-            if face.index in face_blacklist:
-                continue
-            for key in face.edge_keys:
-                edge_faces[key].append(face)
-        # dictionary with the edge-key as key and edge as value
-        edgekey_to_edge = dict([[edge.key, edge] for edge in mesh.edges if \
-            edge.select and not edge.hide])
-    else:
-        edge_faces = False
-        edgekey_to_edge = False
-    
-    # selected faces input
-    old_selected_faces = [face.index for face in mesh.faces if face.select \
-        and not face.hide]
-    
-    # find out if faces created by bridging should be smoothed
-    smooth = False
-    if mesh.faces:
-        if sum([face.use_smooth for face in mesh.faces])/len(mesh.faces) \
-        >= 0.5:
-            smooth = True
-    
-    return(edge_faces, edgekey_to_edge, old_selected_faces, smooth)
-
-
-# return a string with the input method
-def bridge_input_method(loft, loft_loop):
-    method = ""
-    if loft:
-        if loft_loop:
-            method = "Loft loop"
-        else:
-            method = "Loft no-loop"
-    else:
-        method = "Bridge"
-    
-    return(method)
-
-
-# match up loops in pairs, used for multi-input bridging
-def bridge_match_loops(mesh, loops):
-    # calculate average loop normals and centers
-    normals = []
-    centers = []
-    for vertices, circular in loops:
-        normal = mathutils.Vector()
-        center = mathutils.Vector()
-        for vertex in vertices:
-            normal += mesh.vertices[vertex].normal
-            center += mesh.vertices[vertex].co
-        normals.append(normal / len(vertices) / 10)
-        centers.append(center / len(vertices))
-    
-    # possible matches if loop normals are faced towards the center
-    # of the other loop
-    matches = dict([[i, []] for i in range(len(loops))])
-    matches_amount = 0
-    for i in range(len(loops) + 1):
-        for j in range(i+1, len(loops)):
-            if (centers[i] - centers[j]).length > (centers[i] - (centers[j] \
-            + normals[j])).length and (centers[j] - centers[i]).length > \
-            (centers[j] - (centers[i] + normals[i])).length:
-                matches_amount += 1
-                matches[i].append([(centers[i] - centers[j]).length, i, j])
-                matches[j].append([(centers[i] - centers[j]).length, j, i])
-    # if no loops face each other, just make matches between all the loops
-    if matches_amount == 0:
-        for i in range(len(loops) + 1):
-            for j in range(i+1, len(loops)):
-                matches[i].append([(centers[i] - centers[j]).length, i, j])
-                matches[j].append([(centers[i] - centers[j]).length, j, i])
-    for key, value in matches.items():
-        value.sort()
-    
-    # matches based on distance between centers and number of vertices in loops
-    new_order = []
-    for loop_index in range(len(loops)):
-        if loop_index in new_order:
-            continue
-        loop_matches = matches[loop_index]
-        if not loop_matches:
-            continue
-        shortest_distance = loop_matches[0][0]
-        shortest_distance *= 1.1
-        loop_matches = [[abs(len(loops[loop_index][0]) - \
-            len(loops[loop[2]][0])), loop[0], loop[1], loop[2]] for loop in \
-            loop_matches if loop[0] < shortest_distance]
-        loop_matches.sort()
-        for match in loop_matches:
-            if match[3] not in new_order:
-                new_order += [loop_index, match[3]]
-                break
-    
-    # reorder loops based on matches
-    if len(new_order) >= 2:
-        loops = [loops[i] for i in new_order]
-    
-    return(loops)
-
-
-# have normals of selection face outside
-def bridge_recalculate_normals():
-    bpy.ops.object.mode_set(mode = 'EDIT')
-    bpy.ops.mesh.normals_make_consistent()
-
-
-# remove old_selected_faces
-def bridge_remove_internal_faces(mesh, old_selected_faces):
-    select_mode = [i for i in bpy.context.tool_settings.mesh_select_mode]
-    bpy.context.tool_settings.mesh_select_mode = [False, False, True]
-    
-    # hack to keep track of the current selection
-    for edge in mesh.edges:
-        if edge.select and not edge.hide:
-            edge.bevel_weight = (edge.bevel_weight/3) + 0.2
-        else:
-            edge.bevel_weight = (edge.bevel_weight/3) + 0.6
-    
-    # remove faces
-    bpy.ops.object.mode_set(mode = 'EDIT')
-    bpy.ops.mesh.select_all(action = 'DESELECT')
-    bpy.ops.object.mode_set(mode = 'OBJECT')
-    for face in old_selected_faces:
-        mesh.faces[face].select = True
-    bpy.ops.object.mode_set(mode = 'EDIT')
-    bpy.ops.mesh.delete(type = 'FACE')
-    
-    # restore old selection, using hack
-    bpy.ops.object.mode_set(mode = 'OBJECT')
-    bpy.context.tool_settings.mesh_select_mode = [False, True, False]
-    for edge in mesh.edges:
-        if edge.bevel_weight < 0.6:
-            edge.bevel_weight = (edge.bevel_weight-0.2) * 3
-            edge.select = True
-        else:
-            edge.bevel_weight = (edge.bevel_weight-0.6) * 3
-    bpy.ops.object.mode_set(mode = 'EDIT')
-    bpy.ops.object.mode_set(mode = 'OBJECT')
-    bpy.context.tool_settings.mesh_select_mode = select_mode
-
-
-# update list of internal faces that are flagged for removal
-def bridge_save_unused_faces(mesh, old_selected_faces, loops):
-    # key: vertex index, value: lists of selected faces using it
-    vertex_to_face = dict([[i, []] for i in range(len(mesh.vertices))])
-    [[vertex_to_face[vertex_index].append(face) for vertex_index in \
-        mesh.faces[face].vertices] for face in old_selected_faces]
-    
-    # group selected faces that are connected
-    groups = []
-    grouped_faces = []
-    for face in old_selected_faces:
-        if face in grouped_faces:
-            continue
-        grouped_faces.append(face)
-        group = [face]
-        new_faces = [face]
-        while new_faces:
-            grow_face = new_faces[0]
-            for vertex in mesh.faces[grow_face].vertices:
-                vertex_face_group = [face for face in vertex_to_face[vertex] \
-                    if face not in grouped_faces]
-                new_faces += vertex_face_group
-                grouped_faces += vertex_face_group
-                group += vertex_face_group
-            new_faces.pop(0)
-        groups.append(group)
-    
-    # key: vertex index, value: True/False (is it in a loop that is used)
-    used_vertices = dict([[i, 0] for i in range(len(mesh.vertices))])
-    for loop in loops:
-        for vertex in loop[0]:
-            used_vertices[vertex] = True
-    
-    # check if group is bridged, if not remove faces from internal faces list
-    for group in groups:
-        used = False
-        for face in group:
-            if used:
-                break
-            for vertex in mesh.faces[face].vertices:
-                if used_vertices[vertex]:
-                    used = True
-                    break
-        if not used:
-            for face in group:
-                old_selected_faces.remove(face)
-
-
-# add the newly created faces to the selection
-def bridge_select_new_faces(mesh, amount, smooth):
-    select_mode = [i for i in bpy.context.tool_settings.mesh_select_mode]
-    bpy.context.tool_settings.mesh_select_mode = [False, False, True]
-    for i in range(amount):
-        mesh.faces[-(i+1)].select = True
-        mesh.faces[-(i+1)].use_smooth = smooth
-    bpy.ops.object.mode_set(mode = 'EDIT')
-    bpy.ops.object.mode_set(mode = 'OBJECT')
-    bpy.context.tool_settings.mesh_select_mode = select_mode
-
-
-# sort loops, so they are connected in the correct order when lofting
-def bridge_sort_loops(mesh, loops, loft_loop):
-    # simplify loops to single points, and prepare for pathfinding
-    x, y, z = [[sum([mesh.vertices[i].co[j] for i in loop[0]]) / \
-        len(loop[0]) for loop in loops] for j in range(3)]
-    nodes = [mathutils.Vector((x[i], y[i], z[i])) for i in range(len(loops))]
-    
-    active_node = 0
-    open = [i for i in range(1, len(loops))]
-    path = [[0,0]]
-    # connect node to path, that is shortest to active_node
-    while len(open) > 0:
-        distances = [(nodes[active_node] - nodes[i]).length for i in open]
-        active_node = open[distances.index(min(distances))]
-        open.remove(active_node)
-        path.append([active_node, min(distances)])
-    # check if we didn't start in the middle of the path
-    for i in range(2, len(path)):
-        if (nodes[path[i][0]]-nodes[0]).length < path[i][1]:
-            temp = path[:i]
-            path.reverse()
-            path = path[:-i] + temp
-            break
-    
-    # reorder loops
-    loops = [loops[i[0]] for i in path]
-    # if requested, duplicate first loop at last position, so loft can loop
-    if loft_loop:
-        loops = loops + [loops[0]]
-    
-    return(loops)
-
-
-##########################################
-####### Circle functions #################
-##########################################
-
-# convert 3d coordinates to 2d coordinates on plane
-def circle_3d_to_2d(mesh_mod, loop, com, normal):
-    # project vertices onto the plane
-    verts = [mesh_mod.vertices[v] for v in loop[0]]
-    verts_projected = [[v.co - (v.co - com).dot(normal) * normal, v.index]
-                       for v in verts]
-
-    # calculate two vectors (p and q) along the plane
-    m = mathutils.Vector((normal[0] + 1.0, normal[1], normal[2]))
-    p = m - (m.dot(normal) * normal)
-    if p.dot(p) == 0.0:
-        m = mathutils.Vector((normal[0], normal[1] + 1.0, normal[2]))
-        p = m - (m.dot(normal) * normal)
-    q = p.cross(normal)
-    
-    # change to 2d coordinates using perpendicular projection
-    locs_2d = []
-    for loc, vert in verts_projected:
-        vloc = loc - com
-        x = p.dot(vloc) / p.dot(p)
-        y = q.dot(vloc) / q.dot(q)
-        locs_2d.append([x, y, vert])
-    
-    return(locs_2d, p, q)
-
-
-# calculate a best-fit circle to the 2d locations on the plane
-def circle_calculate_best_fit(locs_2d):
-    # initial guess
-    x0 = 0.0
-    y0 = 0.0
-    r = 1.0
-    
-    # calculate center and radius (non-linear least squares solution)
-    for iter in range(500):
-        jmat = []
-        k = []
-        for v in locs_2d:
-            d = (v[0]**2-2.0*x0*v[0]+v[1]**2-2.0*y0*v[1]+x0**2+y0**2)**0.5
-            jmat.append([(x0-v[0])/d, (y0-v[1])/d, -1.0])
-            k.append(-(((v[0]-x0)**2+(v[1]-y0)**2)**0.5-r))
-        jmat2 = mathutils.Matrix(((0.0, 0.0, 0.0),
-                                  (0.0, 0.0, 0.0),
-                                  (0.0, 0.0, 0.0),
-                                  ))
-        k2 = mathutils.Vector((0.0, 0.0, 0.0))
-        for i in range(len(jmat)):
-            k2 += mathutils.Vector(jmat[i])*k[i]
-            jmat2[0][0] += jmat[i][0]**2
-            jmat2[1][0] += jmat[i][0]*jmat[i][1]
-            jmat2[2][0] += jmat[i][0]*jmat[i][2]
-            jmat2[1][1] += jmat[i][1]**2
-            jmat2[2][1] += jmat[i][1]*jmat[i][2]
-            jmat2[2][2] += jmat[i][2]**2
-        jmat2[0][1] = jmat2[1][0]
-        jmat2[0][2] = jmat2[2][0]
-        jmat2[1][2] = jmat2[2][1]
-        try:
-            jmat2.invert()
-        except:
-            pass
-        dx0, dy0, dr = jmat2 * k2
-        x0 += dx0
-        y0 += dy0
-        r += dr
-        # stop iterating if we're close enough to optimal solution
-        if abs(dx0)<1e-6 and abs(dy0)<1e-6 and abs(dr)<1e-6:
-            break
-    
-    # return center of circle and radius
-    return(x0, y0, r)
-
-
-# calculate circle so no vertices have to be moved away from the center
-def circle_calculate_min_fit(locs_2d):
-    # center of circle
-    x0 = (min([i[0] for i in locs_2d])+max([i[0] for i in locs_2d]))/2.0
-    y0 = (min([i[1] for i in locs_2d])+max([i[1] for i in locs_2d]))/2.0
-    center = mathutils.Vector([x0, y0])
-    # radius of circle
-    r = min([(mathutils.Vector([i[0], i[1]])-center).length for i in locs_2d])
-    
-    # return center of circle and radius
-    return(x0, y0, r)
-
-
-# calculate the new locations of the vertices that need to be moved
-def circle_calculate_verts(flatten, mesh_mod, locs_2d, com, p, q, normal):
-    # changing 2d coordinates back to 3d coordinates
-    locs_3d = []
-    for loc in locs_2d:
-        locs_3d.append([loc[2], loc[0]*p + loc[1]*q + com])
-    
-    if flatten: # flat circle
-        return(locs_3d)
-    
-    else: # project the locations on the existing mesh
-        vert_edges = dict_vert_edges(mesh_mod)
-        vert_faces = dict_vert_faces(mesh_mod)
-        faces = [f for f in mesh_mod.faces if not f.hide]
-        rays = [normal, -normal]
-        new_locs = []
-        for loc in locs_3d:
-            projection = False
-            if mesh_mod.vertices[loc[0]].co == loc[1]: # vertex hasn't moved
-                projection = loc[1]
-            else:
-                dif = normal.angle(loc[1]-mesh_mod.vertices[loc[0]].co)
-                if -1e-6 < dif < 1e-6 or math.pi-1e-6 < dif < math.pi+1e-6:
-                    # original location is already along projection normal
-                    projection = mesh_mod.vertices[loc[0]].co
-                else:
-                    # quick search through adjacent faces
-                    for face in vert_faces[loc[0]]:
-                        verts = [mesh_mod.vertices[v].co for v in \
-                            mesh_mod.faces[face].vertices]
-                        if len(verts) == 3: # triangle
-                            v1, v2, v3 = verts
-                            v4 = False
-                        else: # quad
-                            v1, v2, v3, v4 = verts
-                        for ray in rays:
-                            intersect = mathutils.geometry.\
-                            intersect_ray_tri(v1, v2, v3, ray, loc[1])
-                            if intersect:
-                                projection = intersect
-                                break
-                            elif v4:
-                                intersect = mathutils.geometry.\
-                                intersect_ray_tri(v1, v3, v4, ray, loc[1])
-                                if intersect:
-                                    projection = intersect
-                                    break
-                        if projection:
-                            break
-            if not projection:
-                # check if projection is on adjacent edges
-                for edgekey in vert_edges[loc[0]]:
-                    line1 = mesh_mod.vertices[edgekey[0]].co
-                    line2 = mesh_mod.vertices[edgekey[1]].co
-                    intersect, dist = mathutils.geometry.intersect_point_line(\
-                        loc[1], line1, line2)
-                    if 1e-6 < dist < 1 - 1e-6:
-                        projection = intersect
-                        break
-            if not projection:
-                # full search through the entire mesh
-                hits = []
-                for face in faces:
-                    verts = [mesh_mod.vertices[v].co for v in face.vertices]
-                    if len(verts) == 3: # triangle
-                        v1, v2, v3 = verts
-                        v4 = False
-                    else: # quad
-                        v1, v2, v3, v4 = verts
-                    for ray in rays:
-                        intersect = mathutils.geometry.intersect_ray_tri(\
-                            v1, v2, v3, ray, loc[1])
-                        if intersect:
-                            hits.append([(loc[1] - intersect).length,
-                                intersect])
-                            break
-                        elif v4:
-                            intersect = mathutils.geometry.intersect_ray_tri(\
-                                v1, v3, v4, ray, loc[1])
-                            if intersect:
-                                hits.append([(loc[1] - intersect).length,
-                                    intersect])
-                                break
-                if len(hits) >= 1:
-                    # if more than 1 hit with mesh, closest hit is new loc
-                    hits.sort()
-                    projection = hits[0][1]
-            if not projection:
-                # nothing to project on, remain at flat location
-                projection = loc[1]
-            new_locs.append([loc[0], projection])
-        
-        # return new positions of projected circle
-        return(new_locs)
-
-
-# check loops and only return valid ones
-def circle_check_loops(single_loops, loops, mapping, mesh_mod):
-    valid_single_loops = {}
-    valid_loops = []
-    for i, [loop, circular] in enumerate(loops):
-        # loop needs to have at least 3 vertices
-        if len(loop) < 3:
-            continue
-        # loop needs at least 1 vertex in the original, non-mirrored mesh
-        if mapping:
-            all_virtual = True
-            for vert in loop:
-                if mapping[vert] > -1:
-                    all_virtual = False
-                    break
-            if all_virtual:
-                continue
-        # loop has to be non-collinear
-        collinear = True
-        loc0 = mathutils.Vector(mesh_mod.vertices[loop[0]].co[:])
-        loc1 = mathutils.Vector(mesh_mod.vertices[loop[1]].co[:])
-        for v in loop[2:]:
-            locn = mathutils.Vector(mesh_mod.vertices[v].co[:])
-            if loc0 == loc1 or loc1 == locn:
-                loc0 = loc1
-                loc1 = locn
-                continue
-            d1 = loc1-loc0
-            d2 = locn-loc1
-            if -1e-6 < d1.angle(d2, 0) < 1e-6:
-                loc0 = loc1
-                loc1 = locn
-                continue
-            collinear = False
-            break
-        if collinear:
-            continue
-        # passed all tests, loop is valid
-        valid_loops.append([loop, circular])
-        valid_single_loops[len(valid_loops)-1] = single_loops[i]
-    
-    return(valid_single_loops, valid_loops)
-
-
-# calculate the location of single input vertices that need to be flattened
-def circle_flatten_singles(mesh_mod, com, p, q, normal, single_loop):
-    new_locs = []
-    for vert in single_loop:
-        loc = mathutils.Vector(mesh_mod.vertices[vert].co[:])
-        new_locs.append([vert,  loc - (loc-com).dot(normal)*normal])
-    
-    return(new_locs)
-
-
-# calculate input loops
-def circle_get_input(object, mesh, scene):
-    # get mesh with modifiers applied
-    derived, mesh_mod = get_derived_mesh(object, mesh, scene)
-    
-    # create list of edge-keys based on selection state
-    faces = False
-    for face in mesh.faces:
-        if face.select and not face.hide:
-            faces = True
-            break
-    if faces:
-        # get selected, non-hidden , non-internal edge-keys
-        eks_selected = [key for keys in [face.edge_keys for face in \
-            mesh_mod.faces if face.select and not face.hide] for key in keys]
-        edge_count = {}
-        for ek in eks_selected:
-            if ek in edge_count:
-                edge_count[ek] += 1
-            else:
-                edge_count[ek] = 1
-        edge_keys = [edge.key for edge in mesh_mod.edges if edge.select \
-            and not edge.hide and edge_count.get(edge.key, 1)==1]
-    else:
-        # no faces, so no internal edges either
-        edge_keys = [edge.key for edge in mesh_mod.edges if edge.select \
-            and not edge.hide]
-    
-    # add edge-keys around single vertices
-    verts_connected = dict([[vert, 1] for edge in [edge for edge in \
-        mesh_mod.edges if edge.select and not edge.hide] for vert in edge.key])
-    single_vertices = [vert.index for vert in mesh_mod.vertices if \
-        vert.select and not vert.hide and not \
-        verts_connected.get(vert.index, False)]
-    
-    if single_vertices and len(mesh.faces)>0:
-        vert_to_single = dict([[v.index, []] for v in mesh_mod.vertices \
-            if not v.hide])
-        for face in [face for face in mesh_mod.faces if not face.select \
-        and not face.hide]:
-            for vert in face.vertices:
-                if vert in single_vertices:
-                    for ek in face.edge_keys:
-                        if not vert in ek:
-                            edge_keys.append(ek)
-                            if vert not in vert_to_single[ek[0]]:
-                                vert_to_single[ek[0]].append(vert)
-                            if vert not in vert_to_single[ek[1]]:
-                                vert_to_single[ek[1]].append(vert)
-                    break
-    
-    # sort edge-keys into loops
-    loops = get_connected_selections(edge_keys)
-    
-    # find out to which loops the single vertices belong
-    single_loops = dict([[i, []] for i in range(len(loops))])
-    if single_vertices and len(mesh.faces)>0:
-        for i, [loop, circular] in enumerate(loops):
-            for vert in loop:
-                if vert_to_single[vert]:
-                    for single in vert_to_single[vert]:
-                        if single not in single_loops[i]:
-                            single_loops[i].append(single)
-    
-    return(derived, mesh_mod, single_vertices, single_loops, loops)
-
-
-# recalculate positions based on the influence of the circle shape
-def circle_influence_locs(locs_2d, new_locs_2d, influence):
-    for i in range(len(locs_2d)):
-        oldx, oldy, j = locs_2d[i]
-        newx, newy, k = new_locs_2d[i]
-        altx = newx*(influence/100)+ oldx*((100-influence)/100)
-        alty = newy*(influence/100)+ oldy*((100-influence)/100)
-        locs_2d[i] = [altx, alty, j]
-    
-    return(locs_2d)
-
-
-# project 2d locations on circle, respecting distance relations between verts
-def circle_project_non_regular(locs_2d, x0, y0, r):
-    for i in range(len(locs_2d)):
-        x, y, j = locs_2d[i]
-        loc = mathutils.Vector([x-x0, y-y0])
-        loc.length = r
-        locs_2d[i] = [loc[0], loc[1], j]
-    
-    return(locs_2d)
-
-
-# project 2d locations on circle, with equal distance between all vertices
-def circle_project_regular(locs_2d, x0, y0, r):
-    # find offset angle and circling direction
-    x, y, i = locs_2d[0]
-    loc = mathutils.Vector([x-x0, y-y0])
-    loc.length = r
-    offset_angle = loc.angle(mathutils.Vector([1.0, 0.0]), 0.0)
-    loca = mathutils.Vector([x-x0, y-y0, 0.0])
-    if loc[1] < -1e-6:
-        offset_angle *= -1
-    x, y, j = locs_2d[1]
-    locb = mathutils.Vector([x-x0, y-y0, 0.0])
-    if loca.cross(locb)[2] >= 0:
-        ccw = 1
-    else:
-        ccw = -1
-    # distribute vertices along the circle
-    for i in range(len(locs_2d)):
-        t = offset_angle + ccw * (i / len(locs_2d) * 2 * math.pi)
-        x = math.cos(t) * r
-        y = math.sin(t) * r
-        locs_2d[i] = [x, y, locs_2d[i][2]]
-    
-    return(locs_2d)
-
-
-# shift loop, so the first vertex is closest to the center
-def circle_shift_loop(mesh_mod, loop, com):
-    verts, circular = loop
-    distances = [[(mesh_mod.vertices[vert].co - com).length, i] \
-        for i, vert in enumerate(verts)]
-    distances.sort()
-    shift = distances[0][1]
-    loop = [verts[shift:] + verts[:shift], circular]
-    
-    return(loop)
-
-
-##########################################
-####### Curve functions ##################
-##########################################
-
-# create lists with knots and points, all correctly sorted
-def curve_calculate_knots(loop, verts_selected):
-    knots = [v for v in loop[0] if v in verts_selected]
-    points = loop[0][:]
-    # circular loop, potential for weird splines
-    if loop[1]:
-        offset = int(len(loop[0]) / 4)
-        kpos = []
-        for k in knots:
-            kpos.append(loop[0].index(k))
-        kdif = []
-        for i in range(len(kpos) - 1):
-            kdif.append(kpos[i+1] - kpos[i])
-        kdif.append(len(loop[0]) - kpos[-1] + kpos[0])
-        kadd = []
-        for k in kdif:
-            if k > 2 * offset:
-                kadd.append([kdif.index(k), True])
-            # next 2 lines are optional, they insert
-            # an extra control point in small gaps
-            #elif k > offset:
-            #   kadd.append([kdif.index(k), False])
-        kins = []
-        krot = False
-        for k in kadd: # extra knots to be added
-            if k[1]: # big gap (break circular spline)
-                kpos = loop[0].index(knots[k[0]]) + offset
-                if kpos > len(loop[0]) - 1:
-                    kpos -= len(loop[0])
-                kins.append([knots[k[0]], loop[0][kpos]])
-                kpos2 = k[0] + 1
-                if kpos2 > len(knots)-1:
-                    kpos2 -= len(knots)
-                kpos2 = loop[0].index(knots[kpos2]) - offset
-                if kpos2 < 0:
-                    kpos2 += len(loop[0])
-                kins.append([loop[0][kpos], loop[0][kpos2]])
-                krot = loop[0][kpos2]
-            else: # small gap (keep circular spline)
-                k1 = loop[0].index(knots[k[0]])
-                k2 = k[0] + 1
-                if k2 > len(knots)-1:
-                    k2 -= len(knots)
-                k2 = loop[0].index(knots[k2])
-                if k2 < k1:
-                    dif = len(loop[0]) - 1 - k1 + k2
-                else:
-                    dif = k2 - k1
-                kn = k1 + int(dif/2)
-                if kn > len(loop[0]) - 1:
-                    kn -= len(loop[0])
-                kins.append([loop[0][k1], loop[0][kn]])
-        for j in kins: # insert new knots
-            knots.insert(knots.index(j[0]) + 1, j[1])
-        if not krot: # circular loop
-            knots.append(knots[0])
-            points = loop[0][loop[0].index(knots[0]):]
-            points += loop[0][0:loop[0].index(knots[0]) + 1]
-        else: # non-circular loop (broken by script)
-            krot = knots.index(krot)
-            knots = knots[krot:] + knots[0:krot]
-            if loop[0].index(knots[0]) > loop[0].index(knots[-1]):
-                points = loop[0][loop[0].index(knots[0]):]
-                points += loop[0][0:loop[0].index(knots[-1])+1]
-            else:
-                points = loop[0][loop[0].index(knots[0]):\
-                    loop[0].index(knots[-1]) + 1]
-    # non-circular loop, add first and last point as knots
-    else:
-        if loop[0][0] not in knots:
-            knots.insert(0, loop[0][0])
-        if loop[0][-1] not in knots:
-            knots.append(loop[0][-1])
-    
-    return(knots, points)
-
-
-# calculate relative positions compared to first knot
-def curve_calculate_t(mesh_mod, knots, points, pknots, regular, circular):
-    tpoints = []
-    loc_prev = False
-    len_total = 0
-    
-    for p in points:
-        if p in knots:
-            loc = pknots[knots.index(p)] # use projected knot location
-        else:
-            loc = mathutils.Vector(mesh_mod.vertices[p].co[:])
-        if not loc_prev:
-            loc_prev = loc
-        len_total += (loc-loc_prev).length
-        tpoints.append(len_total)
-        loc_prev = loc
-    tknots = []
-    for p in points:
-        if p in knots:
-            tknots.append(tpoints[points.index(p)])
-    if circular:
-        tknots[-1] = tpoints[-1]
-    
-    # regular option
-    if regular:
-        tpoints_average = tpoints[-1] / (len(tpoints) - 1)
-        for i in range(1, len(tpoints) - 1):
-            tpoints[i] = i * tpoints_average
-        for i in range(len(knots)):
-            tknots[i] = tpoints[points.index(knots[i])]
-        if circular:
-            tknots[-1] = tpoints[-1]
-    
-    
-    return(tknots, tpoints)
-
-
-# change the location of non-selected points to their place on the spline
-def curve_calculate_vertices(mesh_mod, knots, tknots, points, tpoints, splines,
-interpolation, restriction):
-    newlocs = {}
-    move = []
-    
-    for p in points:
-        if p in knots:
-            continue
-        m = tpoints[points.index(p)]
-        if m in tknots:
-            n = tknots.index(m)
-        else:
-            t = tknots[:]
-            t.append(m)
-            t.sort()
-            n = t.index(m) - 1
-        if n > len(splines) - 1:
-            n = len(splines) - 1
-        elif n < 0:
-            n = 0
-        
-        if interpolation == 'cubic':
-            ax, bx, cx, dx, tx = splines[n][0]
-            x = ax + bx*(m-tx) + cx*(m-tx)**2 + dx*(m-tx)**3
-            ay, by, cy, dy, ty = splines[n][1]
-            y = ay + by*(m-ty) + cy*(m-ty)**2 + dy*(m-ty)**3
-            az, bz, cz, dz, tz = splines[n][2]
-            z = az + bz*(m-tz) + cz*(m-tz)**2 + dz*(m-tz)**3
-            newloc = mathutils.Vector([x,y,z])
-        else: # interpolation == 'linear'
-            a, d, t, u = splines[n]
-            newloc = ((m-t)/u)*d + a
-
-        if restriction != 'none': # vertex movement is restricted
-            newlocs[p] = newloc
-        else: # set the vertex to its new location
-            move.append([p, newloc])
-        
-    if restriction != 'none': # vertex movement is restricted
-        for p in points:
-            if p in newlocs:
-                newloc = newlocs[p]
-            else:
-                move.append([p, mesh_mod.vertices[p].co])
-                continue
-            oldloc = mesh_mod.vertices[p].co
-            normal = mesh_mod.vertices[p].normal
-            dloc = newloc - oldloc
-            if dloc.length < 1e-6:
-                move.append([p, newloc])
-            elif restriction == 'extrude': # only extrusions
-                if dloc.angle(normal, 0) < 0.5 * math.pi + 1e-6:
-                    move.append([p, newloc])
-            else: # restriction == 'indent' only indentations
-                if dloc.angle(normal) > 0.5 * math.pi - 1e-6:
-                    move.append([p, newloc])
-
-    return(move)
-
-
-# trim loops to part between first and last selected vertices (including)
-def curve_cut_boundaries(mesh_mod, loops):
-    cut_loops = []
-    for loop, circular in loops:
-        if circular:
-            # don't cut
-            cut_loops.append([loop, circular])
-            continue
-        selected = [mesh_mod.vertices[v].select for v in loop]
-        first = selected.index(True)
-        selected.reverse()
-        last = -selected.index(True)
-        if last == 0:
-            cut_loops.append([loop[first:], circular])
-        else:
-            cut_loops.append([loop[first:last], circular])
-    
-    return(cut_loops)
-
-
-# calculate input loops
-def curve_get_input(object, mesh, boundaries, scene):
-    # get mesh with modifiers applied
-    derived, mesh_mod = get_derived_mesh(object, mesh, scene)
-    
-    # vertices that still need a loop to run through it
-    verts_unsorted = [v.index for v in mesh_mod.vertices if \
-        v.select and not v.hide]
-    # necessary dictionaries
-    vert_edges = dict_vert_edges(mesh_mod)
-    edge_faces = dict_edge_faces(mesh_mod)
-    correct_loops = []
-    
-    # find loops through each selected vertex
-    while len(verts_unsorted) > 0:
-        loops = curve_vertex_loops(mesh_mod, verts_unsorted[0], vert_edges,
-            edge_faces)
-        verts_unsorted.pop(0)
-        
-        # check if loop is fully selected
-        search_perpendicular = False
-        i = -1
-        for loop, circular in loops:
-            i += 1
-            selected = [v for v in loop if mesh_mod.vertices[v].select]
-            if len(selected) < 2:
-                # only one selected vertex on loop, don't use
-                loops.pop(i)
-                continue
-            elif len(selected) == len(loop):
-                search_perpendicular = loop
-                break
-        # entire loop is selected, find perpendicular loops
-        if search_perpendicular:
-            for vert in loop:
-                if vert in verts_unsorted:
-                    verts_unsorted.remove(vert)
-            perp_loops = curve_perpendicular_loops(mesh_mod, loop,
-                vert_edges, edge_faces)
-            for perp_loop in perp_loops:
-                correct_loops.append(perp_loop)
-        # normal input
-        else:
-            for loop, circular in loops:
-                correct_loops.append([loop, circular])
-    
-    # boundaries option
-    if boundaries:
-        correct_loops = curve_cut_boundaries(mesh_mod, correct_loops)
-    
-    return(derived, mesh_mod, correct_loops)
-
-
-# return all loops that are perpendicular to the given one
-def curve_perpendicular_loops(mesh_mod, start_loop, vert_edges, edge_faces):
-    # find perpendicular loops
-    perp_loops = []
-    for start_vert in start_loop:
-        loops = curve_vertex_loops(mesh_mod, start_vert, vert_edges,
-            edge_faces)
-        for loop, circular in loops:
-            selected = [v for v in loop if mesh_mod.vertices[v].select]
-            if len(selected) == len(loop):
-                continue
-            else:
-                perp_loops.append([loop, circular, loop.index(start_vert)])
-    
-    # trim loops to same lengths
-    shortest = [[len(loop[0]), i] for i, loop in enumerate(perp_loops)\
-        if not loop[1]]
-    if not shortest:
-        # all loops are circular, not trimming
-        return([[loop[0], loop[1]] for loop in perp_loops])
-    else:
-        shortest = min(shortest)
-    shortest_start = perp_loops[shortest[1]][2]
-    before_start = shortest_start
-    after_start = shortest[0] - shortest_start - 1
-    bigger_before = before_start > after_start
-    trimmed_loops = []
-    for loop in perp_loops:
-        # have the loop face the same direction as the shortest one
-        if bigger_before:
-            if loop[2] < len(loop[0]) / 2:
-                loop[0].reverse()
-                loop[2] = len(loop[0]) - loop[2] - 1
-        else:
-            if loop[2] > len(loop[0]) / 2:
-                loop[0].reverse()
-                loop[2] = len(loop[0]) - loop[2] - 1
-        # circular loops can shift, to prevent wrong trimming
-        if loop[1]:
-            shift = shortest_start - loop[2]
-            if loop[2] + shift > 0 and loop[2] + shift < len(loop[0]):
-                loop[0] = loop[0][-shift:] + loop[0][:-shift]
-            loop[2] += shift
-            if loop[2] < 0:
-                loop[2] += len(loop[0])
-            elif loop[2] > len(loop[0]) -1:
-                loop[2] -= len(loop[0])
-        # trim
-        start = max(0, loop[2] - before_start)
-        end = min(len(loop[0]), loop[2] + after_start + 1)
-        trimmed_loops.append([loop[0][start:end], False])
-    
-    return(trimmed_loops)
-
-
-# project knots on non-selected geometry
-def curve_project_knots(mesh_mod, verts_selected, knots, points, circular):
-    # function to project vertex on edge
-    def project(v1, v2, v3):
-        # v1 and v2 are part of a line
-        # v3 is projected onto it
-        v2 -= v1
-        v3 -= v1
-        p = v3.project(v2)
-        return(p + v1)
-    
-    if circular: # project all knots
-        start = 0
-        end = len(knots)
-        pknots = []
-    else: # first and last knot shouldn't be projected
-        start = 1
-        end = -1
-        pknots = [mathutils.Vector(mesh_mod.vertices[knots[0]].co[:])]
-    for knot in knots[start:end]:
-        if knot in verts_selected:
-            knot_left = knot_right = False
-            for i in range(points.index(knot)-1, -1*len(points), -1):
-                if points[i] not in knots:
-                    knot_left = points[i]
-                    break
-            for i in range(points.index(knot)+1, 2*len(points)):
-                if i > len(points) - 1:
-                    i -= len(points)
-                if points[i] not in knots:
-                    knot_right = points[i]
-                    break
-            if knot_left and knot_right and knot_left != knot_right:
-                knot_left = mathutils.Vector(\
-                    mesh_mod.vertices[knot_left].co[:])
-                knot_right = mathutils.Vector(\
-                    mesh_mod.vertices[knot_right].co[:])
-                knot = mathutils.Vector(mesh_mod.vertices[knot].co[:])
-                pknots.append(project(knot_left, knot_right, knot))
-            else:
-                pknots.append(mathutils.Vector(mesh_mod.vertices[knot].co[:]))
-        else: # knot isn't selected, so shouldn't be changed
-            pknots.append(mathutils.Vector(mesh_mod.vertices[knot].co[:]))
-    if not circular:
-        pknots.append(mathutils.Vector(mesh_mod.vertices[knots[-1]].co[:]))
-    
-    return(pknots)
-
-
-# find all loops through a given vertex
-def curve_vertex_loops(mesh_mod, start_vert, vert_edges, edge_faces):
-    edges_used = []
-    loops = []
-        
-    for edge in vert_edges[start_vert]:
-        if edge in edges_used:
-            continue
-        loop = []
-        circular = False
-        for vert in edge:
-            active_faces = edge_faces[edge]
-            new_vert = vert
-            growing = True
-            while growing:
-                growing = False
-                new_edges = vert_edges[new_vert]
-                loop.append(new_vert)
-                if len(loop) > 1:
-                    edges_used.append(tuple(sorted([loop[-1], loop[-2]])))
-                if len(new_edges) < 3 or len(new_edges) > 4:
-                    # pole
-                    break
-                else:
-                    # find next edge
-                    for new_edge in new_edges:
-                        if new_edge in edges_used:
-                            continue
-                        eliminate = False
-                        for new_face in edge_faces[new_edge]:
-                            if new_face in active_faces:
-                                eliminate = True
-                                break
-                        if eliminate:
-                            continue
-                        # found correct new edge
-                        active_faces = edge_faces[new_edge]
-                        v1, v2 = new_edge
-                        if v1 != new_vert:
-                            new_vert = v1
-                        else:
-                            new_vert = v2
-                        if new_vert == loop[0]:
-                            circular = True
-                        else:
-                            growing = True
-                        break
-            if circular:
-                break
-            loop.reverse()
-        loops.append([loop, circular])
-    
-    return(loops)
-
-
-##########################################
-####### Flatten functions ################
-##########################################
-
-# sort input into loops
-def flatten_get_input(mesh):
-    vert_verts = dict_vert_verts([edge.key for edge in mesh.edges \
-        if edge.select and not edge.hide])
-    verts = [v.index for v in mesh.vertices if v.select and not v.hide]
-    
-    # no connected verts, consider all selected verts as a single input
-    if not vert_verts:
-        return([[verts, False]])
-    
-    loops = []
-    while len(verts) > 0:
-        # start of loop
-        loop = [verts[0]]
-        verts.pop(0)
-        if loop[-1] in vert_verts:
-            to_grow = vert_verts[loop[-1]]
-        else:
-            to_grow = []
-        # grow loop
-        while len(to_grow) > 0:
-            new_vert = to_grow[0]
-            to_grow.pop(0)
-            if new_vert in loop:
-                continue
-            loop.append(new_vert)
-            verts.remove(new_vert)
-            to_grow += vert_verts[new_vert]
-        # add loop to loops
-        loops.append([loop, False])
-    
-    return(loops)
-
-
-# calculate position of vertex projections on plane
-def flatten_project(mesh, loop, com, normal):
-    verts = [mesh.vertices[v] for v in loop[0]]
-    verts_projected = [[v.index, mathutils.Vector(v.co[:]) - \
-        (mathutils.Vector(v.co[:])-com).dot(normal)*normal] for v in verts]
-    
-    return(verts_projected)
-
-
-##########################################
-####### Relax functions ##################
-##########################################
-
-# create lists with knots and points, all correctly sorted
-def relax_calculate_knots(loops):
-    all_knots = []
-    all_points = []
-    for loop, circular in loops:
-        knots = [[], []]
-        points = [[], []]
-        if circular:
-            if len(loop)%2 == 1: # odd
-                extend = [False, True, 0, 1, 0, 1]
-            else: # even
-                extend = [True, False, 0, 1, 1, 2]
-        else:
-            if len(loop)%2 == 1: # odd
-                extend = [False, False, 0, 1, 1, 2]
-            else: # even
-                extend = [False, False, 0, 1, 1, 2]
-        for j in range(2):
-            if extend[j]:
-                loop = [loop[-1]] + loop + [loop[0]]
-            for i in range(extend[2+2*j], len(loop), 2):
-                knots[j].append(loop[i])
-            for i in range(extend[3+2*j], len(loop), 2):
-                if loop[i] == loop[-1] and not circular:
-                    continue
-                if len(points[j]) == 0:
-                    points[j].append(loop[i])
-                elif loop[i] != points[j][0]:
-                    points[j].append(loop[i])
-            if circular:
-                if knots[j][0] != knots[j][-1]:
-                    knots[j].append(knots[j][0])
-        if len(points[1]) == 0:
-            knots.pop(1)
-            points.pop(1)
-        for k in knots:
-            all_knots.append(k)
-        for p in points:
-            all_points.append(p)
-    
-    return(all_knots, all_points)
-
-
-# calculate relative positions compared to first knot
-def relax_calculate_t(mesh_mod, knots, points, regular):
-    all_tknots = []
-    all_tpoints = []
-    for i in range(len(knots)):
-        amount = len(knots[i]) + len(points[i])
-        mix  = []
-        for j in range(amount):
-            if j%2 == 0:
-                mix.append([True, knots[i][round(j/2)]])
-            elif j == amount-1:
-                mix.append([True, knots[i][-1]])
-            else:
-                mix.append([False, points[i][int(j/2)]])
-        len_total = 0
-        loc_prev = False
-        tknots = []
-        tpoints = []
-        for m in mix:
-            loc = mathutils.Vector(mesh_mod.vertices[m[1]].co[:])
-            if not loc_prev:
-                loc_prev = loc
-            len_total += (loc - loc_prev).length
-            if m[0]:
-                tknots.append(len_total)
-            else:
-                tpoints.append(len_total)
-            loc_prev = loc
-        if regular:
-            tpoints = []
-            for p in range(len(points[i])):
-                tpoints.append((tknots[p] + tknots[p+1]) / 2)
-        all_tknots.append(tknots)
-        all_tpoints.append(tpoints)
-    
-    return(all_tknots, all_tpoints)
-
-
-# change the location of the points to their place on the spline
-def relax_calculate_verts(mesh_mod, interpolation, tknots, knots, tpoints,
-points, splines):
-    change = []
-    move = []
-    for i in range(len(knots)):
-        for p in points[i]:
-            m = tpoints[i][points[i].index(p)]
-            if m in tknots[i]:
-                n = tknots[i].index(m)
-            else:
-                t = tknots[i][:]
-                t.append(m)
-                t.sort()
-                n = t.index(m)-1
-            if n > len(splines[i]) - 1:
-                n = len(splines[i]) - 1
-            elif n < 0:
-                n = 0
-            
-            if interpolation == 'cubic':
-                ax, bx, cx, dx, tx = splines[i][n][0]
-                x = ax + bx*(m-tx) + cx*(m-tx)**2 + dx*(m-tx)**3
-                ay, by, cy, dy, ty = splines[i][n][1]
-                y = ay + by*(m-ty) + cy*(m-ty)**2 + dy*(m-ty)**3
-                az, bz, cz, dz, tz = splines[i][n][2]
-                z = az + bz*(m-tz) + cz*(m-tz)**2 + dz*(m-tz)**3
-                change.append([p, mathutils.Vector([x,y,z])])
-            else: # interpolation == 'linear'
-                a, d, t, u = splines[i][n]
-                if u == 0:
-                    u = 1e-8
-                change.append([p, ((m-t)/u)*d + a])
-    for c in change:
-        move.append([c[0], (mesh_mod.vertices[c[0]].co + c[1]) / 2])
-    
-    return(move)
-
-
-##########################################
-####### Space functions ##################
-##########################################
-
-# calculate relative positions compared to first knot
-def space_calculate_t(mesh_mod, knots):
-    tknots = []
-    loc_prev = False
-    len_total = 0
-    for k in knots:
-        loc = mathutils.Vector(mesh_mod.vertices[k].co[:])
-        if not loc_prev:
-            loc_prev = loc
-        len_total += (loc - loc_prev).length
-        tknots.append(len_total)
-        loc_prev = loc
-    amount = len(knots)
-    t_per_segment = len_total / (amount - 1)
-    tpoints = [i * t_per_segment for i in range(amount)]
-    
-    return(tknots, tpoints)
-
-
-# change the location of the points to their place on the spline
-def space_calculate_verts(mesh_mod, interpolation, tknots, tpoints, points,
-splines):
-    move = []
-    for p in points:
-        m = tpoints[points.index(p)]
-        if m in tknots:
-            n = tknots.index(m)
-        else:
-            t = tknots[:]
-            t.append(m)
-            t.sort()
-            n = t.index(m) - 1
-        if n > len(splines) - 1:
-            n = len(splines) - 1
-        elif n < 0:
-            n = 0
-        
-        if interpolation == 'cubic':
-            ax, bx, cx, dx, tx = splines[n][0]
-            x = ax + bx*(m-tx) + cx*(m-tx)**2 + dx*(m-tx)**3
-            ay, by, cy, dy, ty = splines[n][1]
-            y = ay + by*(m-ty) + cy*(m-ty)**2 + dy*(m-ty)**3
-            az, bz, cz, dz, tz = splines[n][2]
-            z = az + bz*(m-tz) + cz*(m-tz)**2 + dz*(m-tz)**3
-            move.append([p, mathutils.Vector([x,y,z])])
-        else: # interpolation == 'linear'
-            a, d, t, u = splines[n]
-            move.append([p, ((m-t)/u)*d + a])
-    
-    return(move)
-
-
-##########################################
-####### Operators ########################
-##########################################
-
-# bridge operator
-class Bridge(bpy.types.Operator):
-    bl_idname = 'mesh.looptools_bridge'
-    bl_label = "Bridge / Loft"
-    bl_description = "Bridge two, or loft several, loops of vertices"
-    bl_options = {'REGISTER', 'UNDO'}
-    
-    cubic_strength = bpy.props.FloatProperty(name = "Strength",
-        description = "Higher strength results in more fluid curves",
-        default = 1.0,
-        soft_min = -3.0,
-        soft_max = 3.0)
-    interpolation = bpy.props.EnumProperty(name = "Interpolation mode",
-        items = (('cubic', "Cubic", "Gives curved results"),
-            ('linear', "Linear", "Basic, fast, straight interpolation")),
-        description = "Interpolation mode: algorithm used when creating "\
-            "segments",
-        default = 'cubic')
-    loft = bpy.props.BoolProperty(name = "Loft",
-        description = "Loft multiple loops, instead of considering them as "\
-            "a multi-input for bridging",
-        default = False)
-    loft_loop = bpy.props.BoolProperty(name = "Loop",
-        description = "Connect the first and the last loop with each other",
-        default = False)
-    min_width = bpy.props.IntProperty(name = "Minimum width",
-        description = "Segments with an edge smaller than this are merged "\
-            "(compared to base edge)",
-        default = 0,
-        min = 0,
-        max = 100,
-        subtype = 'PERCENTAGE')
-    mode = bpy.props.EnumProperty(name = "Mode",
-        items = (('basic', "Basic", "Fast algorithm"), ('shortest',
-            "Shortest edge", "Slower algorithm with better vertex matching")),
-        description = "Algorithm used for bridging",
-        default = 'shortest')
-    remove_faces = bpy.props.BoolProperty(name = "Remove faces",
-        description = "Remove faces that are internal after bridging",
-        default = True)
-    reverse = bpy.props.BoolProperty(name = "Reverse",
-        description = "Manually override the direction in which the loops "\
-                      "are bridged. Only use if the tool gives the wrong " \
-                      "result",
-        default = False)
-    segments = bpy.props.IntProperty(name = "Segments",
-        description = "Number of segments used to bridge the gap "\
-            "(0 = automatic)",
-        default = 1,
-        min = 0,
-        soft_max = 20)
-    twist = bpy.props.IntProperty(name = "Twist",
-        description = "Twist what vertices are connected to each other",
-        default = 0)
-    
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return (ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
-    
-    def draw(self, context):
-        layout = self.layout
-        #layout.prop(self, "mode") # no cases yet where 'basic' mode is needed
-        
-        # top row
-        col_top = layout.column(align=True)
-        row = col_top.row(align=True)
-        col_left = row.column(align=True)
-        col_right = row.column(align=True)
-        col_right.active = self.segments != 1
-        col_left.prop(self, "segments")
-        col_right.prop(self, "min_width", text="")
-        # bottom row
-        bottom_left = col_left.row()
-        bottom_left.active = self.segments != 1
-        bottom_left.prop(self, "interpolation", text="")
-        bottom_right = col_right.row()
-        bottom_right.active = self.interpolation == 'cubic'
-        bottom_right.prop(self, "cubic_strength")
-        # boolean properties
-        col_top.prop(self, "remove_faces")
-        if self.loft:
-            col_top.prop(self, "loft_loop")
-        
-        # override properties
-        col_top.separator()
-        row = layout.row(align = True)
-        row.prop(self, "twist")
-        row.prop(self, "reverse")
-    
-    def invoke(self, context, event):
-        # load custom settings
-        context.window_manager.looptools.bridge_loft = self.loft
-        settings_load(self)
-        return self.execute(context)
-    
-    def execute(self, context):
-        # initialise
-        global_undo, object, mesh = initialise()
-        edge_faces, edgekey_to_edge, old_selected_faces, smooth = \
-            bridge_initialise(mesh, self.interpolation)
-        settings_write(self)
-        
-        # check cache to see if we can save time
-        input_method = bridge_input_method(self.loft, self.loft_loop)
-        cached, single_loops, loops, derived, mapping = cache_read("Bridge",
-            object, mesh, input_method, False)
-        if not cached:
-            # get loops
-            loops = bridge_get_input(mesh)
-            if loops:
-                # reorder loops if there are more than 2
-                if len(loops) > 2:
-                    if self.loft:
-                        loops = bridge_sort_loops(mesh, loops, self.loft_loop)
-                    else:
-                        loops = bridge_match_loops(mesh, loops)
-        
-        # saving cache for faster execution next time
-        if not cached:
-            cache_write("Bridge", object, mesh, input_method, False, False,
-                loops, False, False)
-        
-        if loops:
-            # calculate new geometry
-            vertices = []
-            faces = []
-            max_vert_index = len(mesh.vertices)-1
-            for i in range(1, len(loops)):
-                if not self.loft and i%2 == 0:
-                    continue
-                lines = bridge_calculate_lines(mesh, loops[i-1:i+1],
-                    self.mode, self.twist, self.reverse)
-                vertex_normals = bridge_calculate_virtual_vertex_normals(mesh,
-                    lines, loops[i-1:i+1], edge_faces, edgekey_to_edge)
-                segments = bridge_calculate_segments(mesh, lines,
-                    loops[i-1:i+1], self.segments)
-                new_verts, new_faces, max_vert_index = \
-                    bridge_calculate_geometry(mesh, lines, vertex_normals,
-                    segments, self.interpolation, self.cubic_strength,
-                    self.min_width, max_vert_index)
-                if new_verts:
-                    vertices += new_verts
-                if new_faces:
-                    faces += new_faces
-            # make sure faces in loops that aren't used, aren't removed
-            if self.remove_faces and old_selected_faces:
-                bridge_save_unused_faces(mesh, old_selected_faces, loops)
-            # create vertices
-            if vertices:
-                bridge_create_vertices(mesh, vertices)
-            # create faces
-            if faces:
-                bridge_create_faces(mesh, faces, self.twist)
-                bridge_select_new_faces(mesh, len(faces), smooth)
-            # edge-data could have changed, can't use cache next run
-            if faces and not vertices:
-                cache_delete("Bridge")
-            # delete internal faces
-            if self.remove_faces and old_selected_faces:
-                bridge_remove_internal_faces(mesh, old_selected_faces)
-            # make sure normals are facing outside
-            bridge_recalculate_normals()
-        
-        terminate(global_undo)
-        return{'FINISHED'}
-
-
-# circle operator
-class Circle(bpy.types.Operator):
-    bl_idname = "mesh.looptools_circle"
-    bl_label = "Circle"
-    bl_description = "Move selected vertices into a circle shape"
-    bl_options = {'REGISTER', 'UNDO'}
-    
-    custom_radius = bpy.props.BoolProperty(name = "Radius",
-        description = "Force a custom radius",
-        default = False)
-    fit = bpy.props.EnumProperty(name = "Method",
-        items = (("best", "Best fit", "Non-linear least squares"),
-            ("inside", "Fit inside","Only move vertices towards the center")),
-        description = "Method used for fitting a circle to the vertices",
-        default = 'best')
-    flatten = bpy.props.BoolProperty(name = "Flatten",
-        description = "Flatten the circle, instead of projecting it on the " \
-            "mesh",
-        default = True)
-    influence = bpy.props.FloatProperty(name = "Influence",
-        description = "Force of the tool",
-        default = 100.0,
-        min = 0.0,
-        max = 100.0,
-        precision = 1,
-        subtype = 'PERCENTAGE')
-    radius = bpy.props.FloatProperty(name = "Radius",
-        description = "Custom radius for circle",
-        default = 1.0,
-        min = 0.0,
-        soft_max = 1000.0)
-    regular = bpy.props.BoolProperty(name = "Regular",
-        description = "Distribute vertices at constant distances along the " \
-            "circle",
-        default = True)
-    
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
-    
-    def draw(self, context):
-        layout = self.layout
-        col = layout.column()
-        
-        col.prop(self, "fit")
-        col.separator()
-        
-        col.prop(self, "flatten")
-        row = col.row(align=True)
-        row.prop(self, "custom_radius")
-        row_right = row.row(align=True)
-        row_right.active = self.custom_radius
-        row_right.prop(self, "radius", text="")
-        col.prop(self, "regular")
-        col.separator()
-                
-        col.prop(self, "influence")
-    
-    def invoke(self, context, event):
-        # load custom settings
-        settings_load(self)
-        return self.execute(context)
-    
-    def execute(self, context):
-        # initialise
-        global_undo, object, mesh = initialise()
-        settings_write(self)
-        # check cache to see if we can save time
-        cached, single_loops, loops, derived, mapping = cache_read("Circle",
-            object, mesh, False, False)
-        if cached:
-            derived, mesh_mod = get_derived_mesh(object, mesh, context.scene)
-        else:
-            # find loops
-            derived, mesh_mod, single_vertices, single_loops, loops = \
-                circle_get_input(object, mesh, context.scene)
-            mapping = get_mapping(derived, mesh, mesh_mod, single_vertices,
-                False, loops)
-            single_loops, loops = circle_check_loops(single_loops, loops,
-                mapping, mesh_mod)
-        
-        # saving cache for faster execution next time
-        if not cached:
-            cache_write("Circle", object, mesh, False, False, single_loops,
-                loops, derived, mapping)
-        
-        move = []
-        for i, loop in enumerate(loops):
-            # best fitting flat plane
-            com, normal = calculate_plane(mesh_mod, loop)
-            # if circular, shift loop so we get a good starting vertex
-            if loop[1]:
-                loop = circle_shift_loop(mesh_mod, loop, com)
-            # flatten vertices on plane
-            locs_2d, p, q = circle_3d_to_2d(mesh_mod, loop, com, normal)
-            # calculate circle
-            if self.fit == 'best':
-                x0, y0, r = circle_calculate_best_fit(locs_2d)
-            else: # self.fit == 'inside'
-                x0, y0, r = circle_calculate_min_fit(locs_2d)
-            # radius override
-            if self.custom_radius:
-                r = self.radius / p.length
-            # calculate positions on circle
-            if self.regular:
-                new_locs_2d = circle_project_regular(locs_2d[:], x0, y0, r)
-            else:
-                new_locs_2d = circle_project_non_regular(locs_2d[:], x0, y0, r)
-            # take influence into account
-            locs_2d = circle_influence_locs(locs_2d, new_locs_2d,
-                self.influence)
-            # calculate 3d positions of the created 2d input
-            move.append(circle_calculate_verts(self.flatten, mesh_mod,
-                locs_2d, com, p, q, normal))
-            # flatten single input vertices on plane defined by loop
-            if self.flatten and single_loops:
-                move.append(circle_flatten_singles(mesh_mod, com, p, q,
-                    normal, single_loops[i]))
-        
-        # move vertices to new locations
-        move_verts(mesh, mapping, move, -1)
-        
-        # cleaning up 
-        if derived:
-            bpy.context.blend_data.meshes.remove(mesh_mod)
-        terminate(global_undo)
-        
-        return{'FINISHED'}
-
-
-# curve operator
-class Curve(bpy.types.Operator):
-    bl_idname = "mesh.looptools_curve"
-    bl_label = "Curve"
-    bl_description = "Turn a loop into a smooth curve"
-    bl_options = {'REGISTER', 'UNDO'}
-    
-    boundaries = bpy.props.BoolProperty(name = "Boundaries",
-        description = "Limit the tool to work within the boundaries of the "\
-            "selected vertices",
-        default = False)
-    influence = bpy.props.FloatProperty(name = "Influence",
-        description = "Force of the tool",
-        default = 100.0,
-        min = 0.0,
-        max = 100.0,
-        precision = 1,
-        subtype = 'PERCENTAGE')
-    interpolation = bpy.props.EnumProperty(name = "Interpolation",
-        items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
-            ("linear", "Linear", "Simple and fast linear algorithm")),
-        description = "Algorithm used for interpolation",
-        default = 'cubic')
-    regular = bpy.props.BoolProperty(name = "Regular",
-        description = "Distribute vertices at constant distances along the" \
-            "curve",
-        default = True)
-    restriction = bpy.props.EnumProperty(name = "Restriction",
-        items = (("none", "None", "No restrictions on vertex movement"),
-            ("extrude", "Extrude only","Only allow extrusions (no "\
-                "indentations)"),
-            ("indent", "Indent only", "Only allow indentation (no "\
-                "extrusions)")),
-        description = "Restrictions on how the vertices can be moved",
-        default = 'none')
-    
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
-    
-    def draw(self, context):
-        layout = self.layout
-        col = layout.column()
-        
-        col.prop(self, "interpolation")
-        col.prop(self, "restriction")
-        col.prop(self, "boundaries")
-        col.prop(self, "regular")
-        col.separator()
-        
-        col.prop(self, "influence")
-    
-    def invoke(self, context, event):
-        # load custom settings
-        settings_load(self)
-        return self.execute(context)
-    
-    def execute(self, context):
-        # initialise
-        global_undo, object, mesh = initialise()
-        settings_write(self)
-        # check cache to see if we can save time
-        cached, single_loops, loops, derived, mapping = cache_read("Curve",
-            object, mesh, False, self.boundaries)
-        if cached:
-            derived, mesh_mod = get_derived_mesh(object, mesh, context.scene)
-        else:
-            # find loops
-            derived, mesh_mod, loops = curve_get_input(object, mesh,
-                self.boundaries, context.scene)
-            mapping = get_mapping(derived, mesh, mesh_mod, False, True, loops)
-            loops = check_loops(loops, mapping, mesh_mod)
-        verts_selected = [v.index for v in mesh_mod.vertices if v.select \
-            and not v.hide]
-        
-        # saving cache for faster execution next time
-        if not cached:
-            cache_write("Curve", object, mesh, False, self.boundaries, False,
-                loops, derived, mapping)
-        
-        move = []
-        for loop in loops:
-            knots, points = curve_calculate_knots(loop, verts_selected)
-            pknots = curve_project_knots(mesh_mod, verts_selected, knots,
-                points, loop[1])
-            tknots, tpoints = curve_calculate_t(mesh_mod, knots, points,
-                pknots, self.regular, loop[1])
-            splines = calculate_splines(self.interpolation, mesh_mod,
-                tknots, knots)
-            move.append(curve_calculate_vertices(mesh_mod, knots, tknots,
-                points, tpoints, splines, self.interpolation,
-                self.restriction))
-        
-        # move vertices to new locations
-        move_verts(mesh, mapping, move, self.influence)
-        
-        # cleaning up 
-        if derived:
-            bpy.context.blend_data.meshes.remove(mesh_mod)
-        
-        terminate(global_undo)
-        return{'FINISHED'}
-
-
-# flatten operator
-class Flatten(bpy.types.Operator):
-    bl_idname = "mesh.looptools_flatten"
-    bl_label = "Flatten"
-    bl_description = "Flatten vertices on a best-fitting plane"
-    bl_options = {'REGISTER', 'UNDO'}
-    
-    influence = bpy.props.FloatProperty(name = "Influence",
-        description = "Force of the tool",
-        default = 100.0,
-        min = 0.0,
-        max = 100.0,
-        precision = 1,
-        subtype = 'PERCENTAGE')
-    plane = bpy.props.EnumProperty(name = "Plane",
-        items = (("best_fit", "Best fit", "Calculate a best fitting plane"),
-            ("normal", "Normal", "Derive plane from averaging vertex "\
-            "normals"),
-            ("view", "View", "Flatten on a plane perpendicular to the "\
-            "viewing angle")),
-        description = "Plane on which vertices are flattened",
-        default = 'best_fit')
-    restriction = bpy.props.EnumProperty(name = "Restriction",
-        items = (("none", "None", "No restrictions on vertex movement"),
-            ("bounding_box", "Bounding box", "Vertices are restricted to "\
-            "movement inside the bounding box of the selection")),
-        description = "Restrictions on how the vertices can be moved",
-        default = 'none')
-    
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
-    
-    def draw(self, context):
-        layout = self.layout
-        col = layout.column()
-        
-        col.prop(self, "plane")
-        #col.prop(self, "restriction")
-        col.separator()
-        
-        col.prop(self, "influence")
-    
-    def invoke(self, context, event):
-        # load custom settings
-        settings_load(self)
-        return self.execute(context)
-    
-    def execute(self, context):
-        # initialise
-        global_undo, object, mesh = initialise()
-        settings_write(self)
-        # check cache to see if we can save time
-        cached, single_loops, loops, derived, mapping = cache_read("Flatten",
-            object, mesh, False, False)
-        if not cached:
-            # order input into virtual loops
-            loops = flatten_get_input(mesh)
-            loops = check_loops(loops, mapping, mesh)
-        
-        # saving cache for faster execution next time
-        if not cached:
-            cache_write("Flatten", object, mesh, False, False, False, loops,
-                False, False)
-        
-        move = []
-        for loop in loops:
-            # calculate plane and position of vertices on them
-            com, normal = calculate_plane(mesh, loop, method=self.plane,
-                object=object)
-            to_move = flatten_project(mesh, loop, com, normal)
-            if self.restriction == 'none':
-                move.append(to_move)
-            else:
-                move.append(to_move)
-        move_verts(mesh, False, move, self.influence)
-        
-        terminate(global_undo)
-        return{'FINISHED'}
-
-
-# relax operator
-class Relax(bpy.types.Operator):
-    bl_idname = "mesh.looptools_relax"
-    bl_label = "Relax"
-    bl_description = "Relax the loop, so it is smoother"
-    bl_options = {'REGISTER', 'UNDO'}
-    
-    input = bpy.props.EnumProperty(name = "Input",
-        items = (("all", "Parallel (all)", "Also use non-selected "\
-                "parallel loops as input"),
-            ("selected", "Selection","Only use selected vertices as input")),
-        description = "Loops that are relaxed",
-        default = 'selected')
-    interpolation = bpy.props.EnumProperty(name = "Interpolation",
-        items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
-            ("linear", "Linear", "Simple and fast linear algorithm")),
-        description = "Algorithm used for interpolation",
-        default = 'cubic')
-    iterations = bpy.props.EnumProperty(name = "Iterations",
-        items = (("1", "1", "One"),
-            ("3", "3", "Three"),
-            ("5", "5", "Five"),
-            ("10", "10", "Ten"),
-            ("25", "25", "Twenty-five")),
-        description = "Number of times the loop is relaxed",
-        default = "1")
-    regular = bpy.props.BoolProperty(name = "Regular",
-        description = "Distribute vertices at constant distances along the" \
-            "loop",
-        default = True)
-    
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
-    
-    def draw(self, context):
-        layout = self.layout
-        col = layout.column()
-        
-        col.prop(self, "interpolation")
-        col.prop(self, "input")
-        col.prop(self, "iterations")
-        col.prop(self, "regular")
-    
-    def invoke(self, context, event):
-        # load custom settings
-        settings_load(self)
-        return self.execute(context)
-    
-    def execute(self, context):
-        # initialise
-        global_undo, object, mesh = initialise()
-        settings_write(self)
-        # check cache to see if we can save time
-        cached, single_loops, loops, derived, mapping = cache_read("Relax",
-            object, mesh, self.input, False)
-        if cached:
-            derived, mesh_mod = get_derived_mesh(object, mesh, context.scene)
-        else:
-            # find loops
-            derived, mesh_mod, loops = get_connected_input(object, mesh,
-                context.scene, self.input)
-            mapping = get_mapping(derived, mesh, mesh_mod, False, False, loops)
-            loops = check_loops(loops, mapping, mesh_mod)
-        knots, points = relax_calculate_knots(loops)
-        
-        # saving cache for faster execution next time
-        if not cached:
-            cache_write("Relax", object, mesh, self.input, False, False, loops,
-                derived, mapping)
-        
-        for iteration in range(int(self.iterations)):
-            # calculate splines and new positions
-            tknots, tpoints = relax_calculate_t(mesh_mod, knots, points,
-                self.regular)
-            splines = []
-            for i in range(len(knots)):
-                splines.append(calculate_splines(self.interpolation, mesh_mod,
-                    tknots[i], knots[i]))
-            move = [relax_calculate_verts(mesh_mod, self.interpolation,
-                tknots, knots, tpoints, points, splines)]
-            move_verts(mesh, mapping, move, -1)
-        
-        # cleaning up 
-        if derived:
-            bpy.context.blend_data.meshes.remove(mesh_mod)
-        terminate(global_undo)
-        
-        return{'FINISHED'}
-
-
-# space operator
-class Space(bpy.types.Operator):
-    bl_idname = "mesh.looptools_space"
-    bl_label = "Space"
-    bl_description = "Space the vertices in a regular distrubtion on the loop"
-    bl_options = {'REGISTER', 'UNDO'}
-    
-    influence = bpy.props.FloatProperty(name = "Influence",
-        description = "Force of the tool",
-        default = 100.0,
-        min = 0.0,
-        max = 100.0,
-        precision = 1,
-        subtype = 'PERCENTAGE')
-    input = bpy.props.EnumProperty(name = "Input",
-        items = (("all", "Parallel (all)", "Also use non-selected "\
-                "parallel loops as input"),
-            ("selected", "Selection","Only use selected vertices as input")),
-        description = "Loops that are spaced",
-        default = 'selected')
-    interpolation = bpy.props.EnumProperty(name = "Interpolation",
-        items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
-            ("linear", "Linear", "Vertices are projected on existing edges")),
-        description = "Algorithm used for interpolation",
-        default = 'cubic')
-    
-    @classmethod
-    def poll(cls, context):
-        ob = context.active_object
-        return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
-    
-    def draw(self, context):
-        layout = self.layout
-        col = layout.column()
-        
-        col.prop(self, "interpolation")
-        col.prop(self, "input")
-        col.separator()
-        
-        col.prop(self, "influence")
-    
-    def invoke(self, context, event):
-        # load custom settings
-        settings_load(self)
-        return self.execute(context)
-    
-    def execute(self, context):
-        # initialise
-        global_undo, object, mesh = initialise()
-        settings_write(self)
-        # check cache to see if we can save time
-        cached, single_loops, loops, derived, mapping = cache_read("Space",
-            object, mesh, self.input, False)
-        if cached:
-            derived, mesh_mod = get_derived_mesh(object, mesh, context.scene)
-        else:
-            # find loops
-            derived, mesh_mod, loops = get_connected_input(object, mesh,
-                context.scene, self.input)
-            mapping = get_mapping(derived, mesh, mesh_mod, False, False, loops)
-            loops = check_loops(loops, mapping, mesh_mod)
-        
-        # saving cache for faster execution next time
-        if not cached:
-            cache_write("Space", object, mesh, self.input, False, False, loops,
-                derived, mapping)
-        
-        move = []
-        for loop in loops:
-            # calculate splines and new positions
-            if loop[1]: # circular
-                loop[0].append(loop[0][0])
-            tknots, tpoints = space_calculate_t(mesh_mod, loop[0][:])
-            splines = calculate_splines(self.interpolation, mesh_mod,
-                tknots, loop[0][:])
-            move.append(space_calculate_verts(mesh_mod, self.interpolation,
-                tknots, tpoints, loop[0][:-1], splines))
-        
-        # move vertices to new locations
-        move_verts(mesh, mapping, move, self.influence)
-        
-        # cleaning up 
-        if derived:
-            bpy.context.blend_data.meshes.remove(mesh_mod)
-        terminate(global_undo)
-        
-        return{'FINISHED'}
-
-
-##########################################
-####### GUI and registration #############
-##########################################
-
-# menu containing all tools
-class VIEW3D_MT_edit_mesh_looptools(bpy.types.Menu):
-    bl_label = "LoopTools"
-    
-    def draw(self, context):
-        layout = self.layout
-        
-#        layout.operator("mesh.looptools_bridge", text="Bridge").loft = False
-        layout.operator("mesh.looptools_circle")
-        layout.operator("mesh.looptools_curve")
-        layout.operator("mesh.looptools_flatten")
-#        layout.operator("mesh.looptools_bridge", text="Loft").loft = True
-        layout.operator("mesh.looptools_relax")
-        layout.operator("mesh.looptools_space")
-
-
-# panel containing all tools
-class VIEW3D_PT_tools_looptools(bpy.types.Panel):
-    bl_space_type = 'VIEW_3D'
-    bl_region_type = 'TOOLS'
-    bl_context = "mesh_edit"
-    bl_label = "LoopTools"
-
-    def draw(self, context):
-        layout = self.layout
-        col = layout.column(align=True)
-        lt = context.window_manager.looptools
-        
-        # bridge - first line
-#        split = col.split(percentage=0.15)
-#        if lt.display_bridge:
-#            split.prop(lt, "display_bridge", text="", icon='DOWNARROW_HLT')
-#        else:
-#            split.prop(lt, "display_bridge", text="", icon='RIGHTARROW')
-#        split.operator("mesh.looptools_bridge", text="Bridge").loft = False
-        # bridge - settings
-#        if lt.display_bridge:
-#            box = col.column(align=True).box().column()
-            #box.prop(self, "mode")
-            
-            # top row
-#            col_top = box.column(align=True)
-#            row = col_top.row(align=True)
-#            col_left = row.column(align=True)
-#            col_right = row.column(align=True)
-#            col_right.active = lt.bridge_segments != 1
-#            col_left.prop(lt, "bridge_segments")
-#            col_right.prop(lt, "bridge_min_width", text="")
-#            # bottom row
-#            bottom_left = col_left.row()
-#            bottom_left.active = lt.bridge_segments != 1
-#            bottom_left.prop(lt, "bridge_interpolation", text="")
-#            bottom_right = col_right.row()
-#            bottom_right.active = lt.bridge_interpolation == 'cubic'
-#            bottom_right.prop(lt, "bridge_cubic_strength")
-            # boolean properties
-#            col_top.prop(lt, "bridge_remove_faces")
-            
-            # override properties
-#            col_top.separator()
-#            row = box.row(align = True)
-#            row.prop(lt, "bridge_twist")
-#            row.prop(lt, "bridge_reverse")
-        
-        # circle - first line
-        split = col.split(percentage=0.15)
-        if lt.display_circle:
-            split.prop(lt, "display_circle", text="", icon='DOWNARROW_HLT')
-        else:
-            split.prop(lt, "display_circle", text="", icon='RIGHTARROW')
-        split.operator("mesh.looptools_circle")
-        # circle - settings
-        if lt.display_circle:
-            box = col.column(align=True).box().column()
-            box.prop(lt, "circle_fit")
-            box.separator()
-            
-            box.prop(lt, "circle_flatten")
-            row = box.row(align=True)
-            row.prop(lt, "circle_custom_radius")
-            row_right = row.row(align=True)
-            row_right.active = lt.circle_custom_radius
-            row_right.prop(lt, "circle_radius", text="")
-            box.prop(lt, "circle_regular")
-            box.separator()
-            
-            box.prop(lt, "circle_influence")
-        
-        # curve - first line
-        split = col.split(percentage=0.15)
-        if lt.display_curve:
-            split.prop(lt, "display_curve", text="", icon='DOWNARROW_HLT')
-        else:
-            split.prop(lt, "display_curve", text="", icon='RIGHTARROW')
-        split.operator("mesh.looptools_curve")
-        # curve - settings
-        if lt.display_curve:
-            box = col.column(align=True).box().column()
-            box.prop(lt, "curve_interpolation")
-            box.prop(lt, "curve_restriction")
-            box.prop(lt, "curve_boundaries")
-            box.prop(lt, "curve_regular")
-            box.separator()
-            
-            box.prop(lt, "curve_influence")
-        
-        # flatten - first line
-        split = col.split(percentage=0.15)
-        if lt.display_flatten:
-            split.prop(lt, "display_flatten", text="", icon='DOWNARROW_HLT')
-        else:
-            split.prop(lt, "display_flatten", text="", icon='RIGHTARROW')
-        split.operator("mesh.looptools_flatten")
-        # flatten - settings
-        if lt.display_flatten:
-            box = col.column(align=True).box().column()
-            box.prop(lt, "flatten_plane")
-            #box.prop(lt, "flatten_restriction")
-            box.separator()
-            
-            box.prop(lt, "flatten_influence")
-        
-        # loft - first line
-#        split = col.split(percentage=0.15)
-#        if lt.display_loft:
-#            split.prop(lt, "display_loft", text="", icon='DOWNARROW_HLT')
-#        else:
-#            split.prop(lt, "display_loft", text="", icon='RIGHTARROW')
-#        split.operator("mesh.looptools_bridge", text="Loft").loft = True
-#        # loft - settings
-#        if lt.display_loft:
-#            box = col.column(align=True).box().column()
-#            #box.prop(self, "mode")
-#            
-#            # top row
-#            col_top = box.column(align=True)
-#            row = col_top.row(align=True)
-#            col_left = row.column(align=True)
-#            col_right = row.column(align=True)
-#            col_right.active = lt.bridge_segments != 1
-#            col_left.prop(lt, "bridge_segments")
-#            col_right.prop(lt, "bridge_min_width", text="")
-#            # bottom row
-#            bottom_left = col_left.row()
-#            bottom_left.active = lt.bridge_segments != 1
-#            bottom_left.prop(lt, "bridge_interpolation", text="")
-#            bottom_right = col_right.row()
-#            bottom_right.active = lt.bridge_interpolation == 'cubic'
-#            bottom_right.prop(lt, "bridge_cubic_strength")
-#            # boolean properties
-#            col_top.prop(lt, "bridge_remove_faces")
-#            col_top.prop(lt, "bridge_loft_loop")
-#            
-#            # override properties
-#            col_top.separator()
-#            row = box.row(align = True)
-#            row.prop(lt, "bridge_twist")
-#            row.prop(lt, "bridge_reverse")
-        
-        # relax - first line
-        split = col.split(percentage=0.15)
-        if lt.display_relax:
-            split.prop(lt, "display_relax", text="", icon='DOWNARROW_HLT')
-        else:
-            split.prop(lt, "display_relax", text="", icon='RIGHTARROW')
-        split.operator("mesh.looptools_relax")
-        # relax - settings
-        if lt.display_relax:
-            box = col.column(align=True).box().column()
-            box.prop(lt, "relax_interpolation")
-            box.prop(lt, "relax_input")
-            box.prop(lt, "relax_iterations")
-            box.prop(lt, "relax_regular")
-        
-        # space - first line
-        split = col.split(percentage=0.15)
-        if lt.display_space:
-            split.prop(lt, "display_space", text="", icon='DOWNARROW_HLT')
-        else:
-            split.prop(lt, "display_space", text="", icon='RIGHTARROW')
-        split.operator("mesh.looptools_space")
-        # space - settings
-        if lt.display_space:
-            box = col.column(align=True).box().column()
-            box.prop(lt, "space_interpolation")
-            box.prop(lt, "space_input")
-            box.separator()
-            
-            box.prop(lt, "space_influence")
-
-
-# property group containing all properties for the gui in the panel
-class LoopToolsProps(bpy.types.PropertyGroup):
-    """
-    Fake module like class
-    bpy.context.window_manager.looptools
-    """
-    
-    # general display properties
-#    display_bridge = bpy.props.BoolProperty(name = "Bridge settings",
-#        description = "Display settings of the Bridge tool",
-#        default = False)
-    display_circle = bpy.props.BoolProperty(name = "Circle settings",
-        description = "Display settings of the Circle tool",
-        default = False)
-    display_curve = bpy.props.BoolProperty(name = "Curve settings",
-        description = "Display settings of the Curve tool",
-        default = False)
-    display_flatten = bpy.props.BoolProperty(name = "Flatten settings",
-        description = "Display settings of the Flatten tool",
-        default = False)
-#    display_loft = bpy.props.BoolProperty(name = "Loft settings",
-#        description = "Display settings of the Loft tool",
-#        default = False)
-    display_relax = bpy.props.BoolProperty(name = "Relax settings",
-        description = "Display settings of the Relax tool",
-        default = False)
-    display_space = bpy.props.BoolProperty(name = "Space settings",
-        description = "Display settings of the Space tool",
-        default = False)
-    
-    # bridge properties
-    bridge_cubic_strength = bpy.props.FloatProperty(name = "Strength",
-        description = "Higher strength results in more fluid curves",
-        default = 1.0,
-        soft_min = -3.0,
-        soft_max = 3.0)
-    bridge_interpolation = bpy.props.EnumProperty(name = "Interpolation mode",
-        items = (('cubic', "Cubic", "Gives curved results"),
-            ('linear', "Linear", "Basic, fast, straight interpolation")),
-        description = "Interpolation mode: algorithm used when creating "\
-            "segments",
-        default = 'cubic')
-    bridge_loft = bpy.props.BoolProperty(name = "Loft",
-        description = "Loft multiple loops, instead of considering them as "\
-            "a multi-input for bridging",
-        default = False)
-    bridge_loft_loop = bpy.props.BoolProperty(name = "Loop",
-        description = "Connect the first and the last loop with each other",
-        default = False)
-    bridge_min_width = bpy.props.IntProperty(name = "Minimum width",
-        description = "Segments with an edge smaller than this are merged "\
-            "(compared to base edge)",
-        default = 0,
-        min = 0,
-        max = 100,
-        subtype = 'PERCENTAGE')
-    bridge_mode = bpy.props.EnumProperty(name = "Mode",
-        items = (('basic', "Basic", "Fast algorithm"),
-                 ('shortest', "Shortest edge", "Slower algorithm with " \
-                                               "better vertex matching")),
-        description = "Algorithm used for bridging",
-        default = 'shortest')
-    bridge_remove_faces = bpy.props.BoolProperty(name = "Remove faces",
-        description = "Remove faces that are internal after bridging",
-        default = True)
-    bridge_reverse = bpy.props.BoolProperty(name = "Reverse",
-        description = "Manually override the direction in which the loops "\
-                      "are bridged. Only use if the tool gives the wrong " \
-                      "result",
-        default = False)
-    bridge_segments = bpy.props.IntProperty(name = "Segments",
-        description = "Number of segments used to bridge the gap "\
-            "(0 = automatic)",
-        default = 1,
-        min = 0,
-        soft_max = 20)
-    bridge_twist = bpy.props.IntProperty(name = "Twist",
-        description = "Twist what vertices are connected to each other",
-        default = 0)
-    
-    # circle properties
-    circle_custom_radius = bpy.props.BoolProperty(name = "Radius",
-        description = "Force a custom radius",
-        default = False)
-    circle_fit = bpy.props.EnumProperty(name = "Method",
-        items = (("best", "Best fit", "Non-linear least squares"),
-            ("inside", "Fit inside","Only move vertices towards the center")),
-        description = "Method used for fitting a circle to the vertices",
-        default = 'best')
-    circle_flatten = bpy.props.BoolProperty(name = "Flatten",
-        description = "Flatten the circle, instead of projecting it on the " \
-            "mesh",
-        default = True)
-    circle_influence = bpy.props.FloatProperty(name = "Influence",
-        description = "Force of the tool",
-        default = 100.0,
-        min = 0.0,
-        max = 100.0,
-        precision = 1,
-        subtype = 'PERCENTAGE')
-    circle_radius = bpy.props.FloatProperty(name = "Radius",
-        description = "Custom radius for circle",
-        default = 1.0,
-        min = 0.0,
-        soft_max = 1000.0)
-    circle_regular = bpy.props.BoolProperty(name = "Regular",
-        description = "Distribute vertices at constant distances along the " \
-            "circle",
-        default = True)
-    
-    # curve properties
-    curve_boundaries = bpy.props.BoolProperty(name = "Boundaries",
-        description = "Limit the tool to work within the boundaries of the "\
-            "selected vertices",
-        default = False)
-    curve_influence = bpy.props.FloatProperty(name = "Influence",
-        description = "Force of the tool",
-        default = 100.0,
-        min = 0.0,
-        max = 100.0,
-        precision = 1,
-        subtype = 'PERCENTAGE')
-    curve_interpolation = bpy.props.EnumProperty(name = "Interpolation",
-        items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
-            ("linear", "Linear", "Simple and fast linear algorithm")),
-        description = "Algorithm used for interpolation",
-        default = 'cubic')
-    curve_regular = bpy.props.BoolProperty(name = "Regular",
-        description = "Distribute vertices at constant distances along the" \
-            "curve",
-        default = True)
-    curve_restriction = bpy.props.EnumProperty(name = "Restriction",
-        items = (("none", "None", "No restrictions on vertex movement"),
-            ("extrude", "Extrude only","Only allow extrusions (no "\
-                "indentations)"),
-            ("indent", "Indent only", "Only allow indentation (no "\
-                "extrusions)")),
-        description = "Restrictions on how the vertices can be moved",
-        default = 'none')
-    
-    # flatten properties
-    flatten_influence = bpy.props.FloatProperty(name = "Influence",
-        description = "Force of the tool",
-        default = 100.0,
-        min = 0.0,
-        max = 100.0,
-        precision = 1,
-        subtype = 'PERCENTAGE')
-    flatten_plane = bpy.props.EnumProperty(name = "Plane",
-        items = (("best_fit", "Best fit", "Calculate a best fitting plane"),
-            ("normal", "Normal", "Derive plane from averaging vertex "\
-            "normals"),
-            ("view", "View", "Flatten on a plane perpendicular to the "\
-            "viewing angle")),
-        description = "Plane on which vertices are flattened",
-        default = 'best_fit')
-    flatten_restriction = bpy.props.EnumProperty(name = "Restriction",
-        items = (("none", "None", "No restrictions on vertex movement"),
-            ("bounding_box", "Bounding box", "Vertices are restricted to "\
-            "movement inside the bounding box of the selection")),
-        description = "Restrictions on how the vertices can be moved",
-        default = 'none')
-    
-    # relax properties
-    relax_input = bpy.props.EnumProperty(name = "Input",
-        items = (("all", "Parallel (all)", "Also use non-selected "\
-                "parallel loops as input"),
-            ("selected", "Selection","Only use selected vertices as input")),
-        description = "Loops that are relaxed",
-        default = 'selected')
-    relax_interpolation = bpy.props.EnumProperty(name = "Interpolation",
-        items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
-            ("linear", "Linear", "Simple and fast linear algorithm")),
-        description = "Algorithm used for interpolation",
-        default = 'cubic')
-    relax_iterations = bpy.props.EnumProperty(name = "Iterations",
-        items = (("1", "1", "One"),
-            ("3", "3", "Three"),
-            ("5", "5", "Five"),
-            ("10", "10", "Ten"),
-            ("25", "25", "Twenty-five")),
-        description = "Number of times the loop is relaxed",
-        default = "1")
-    relax_regular = bpy.props.BoolProperty(name = "Regular",
-        description = "Distribute vertices at constant distances along the" \
-            "loop",
-        default = True)
-    
-    # space properties
-    space_influence = bpy.props.FloatProperty(name = "Influence",
-        description = "Force of the tool",
-        default = 100.0,
-        min = 0.0,
-        max = 100.0,
-        precision = 1,
-        subtype = 'PERCENTAGE')
-    space_input = bpy.props.EnumProperty(name = "Input",
-        items = (("all", "Parallel (all)", "Also use non-selected "\
-                "parallel loops as input"),
-            ("selected", "Selection","Only use selected vertices as input")),
-        description = "Loops that are spaced",
-        default = 'selected')
-    space_interpolation = bpy.props.EnumProperty(name = "Interpolation",
-        items = (("cubic", "Cubic", "Natural cubic spline, smooth results"),
-            ("linear", "Linear", "Vertices are projected on existing edges")),
-        description = "Algorithm used for interpolation",
-        default = 'cubic')
-
-
-# draw function for integration in menus
-def menu_func(self, context):
-    self.layout.menu("VIEW3D_MT_edit_mesh_looptools")
-    self.layout.separator()
-
-
-# define classes for registration
-classes = [VIEW3D_MT_edit_mesh_looptools,
-    VIEW3D_PT_tools_looptools,
-    LoopToolsProps,
-    Bridge,
-    Circle,
-    Curve,
-    Flatten,
-    Relax,
-    Space]
-
-
-# registering and menu integration
-def register():
-    for c in classes:
-        bpy.utils.register_class(c)
-    bpy.types.VIEW3D_MT_edit_mesh_specials.prepend(menu_func)
-    bpy.types.WindowManager.looptools = bpy.props.PointerProperty(\
-        type = LoopToolsProps)
-
-
-# unregistering and removing menus
-def unregister():
-    for c in classes:
-        bpy.utils.unregister_class(c)
-    bpy.types.VIEW3D_MT_edit_mesh_specials.remove(menu_func)
-    try:
-        del bpy.types.WindowManager.looptools
-    except:
-        pass
-
-
-if __name__ == "__main__":
-    register()