[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [1065] contrib/py/scripts/addons/ mesh_bridge.py: Moved to contrib/py/scripts/addons/mesh_bridge.py
Brendon Murphy
meta.androcto1 at gmail.com
Sun Sep 19 15:53:12 CEST 2010
Revision: 1065
http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-extensions&revision=1065
Author: meta-androcto
Date: 2010-09-19 15:53:12 +0200 (Sun, 19 Sep 2010)
Log Message:
-----------
Moved to contrib/py/scripts/addons/mesh_bridge.py
Thanks to Crouch.
Added Paths:
-----------
contrib/py/scripts/addons/mesh_bridge.py
Added: contrib/py/scripts/addons/mesh_bridge.py
===================================================================
--- contrib/py/scripts/addons/mesh_bridge.py (rev 0)
+++ contrib/py/scripts/addons/mesh_bridge.py 2010-09-19 13:53:12 UTC (rev 1065)
@@ -0,0 +1,418 @@
+# ##### 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 #####
+
+# <pep8 compliant>
+
+
+"""
+Bridge
+
+How to use:
+- Select a mesh and go into editmode
+- Select two or more edge-loops
+- Press Ctrl+F
+- Select the Bridge option
+"""
+
+
+bl_addon_info = {
+ 'name': 'Bridge',
+ 'author': 'Bartius Crouch',
+ 'version': (1,1,0),
+ 'blender': (2,5,4),
+ 'api': 31878,
+ 'location': 'View3D > Ctrl+F > Bridge',
+ 'warning': '', # used for warning icon and text in addons panel
+ 'description': 'Connect two or more loops of vertices.',
+ 'wiki_url': 'http://wiki.blender.org/index.php/Extensions:Py/'\
+ 'Scripts/',
+ 'tracker_url': 'https://projects.blender.org/tracker/index.php?'\
+ 'func=detail&aid=23889&group_id=153&atid=467',
+ 'category': 'Mesh'}
+
+
+import bpy
+import mathutils
+
+
+# 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')
+ mesh = bpy.context.active_object.data
+ return global_undo, mesh
+
+
+# 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
+
+
+# return a list of 2 non-connected loops (vertex indices), or False
+def get_selection(mesh):
+ selected_edges = [edge.key for edge in mesh.edges if edge.select and not edge.hide]
+ vert_connections = {}
+ loops = []
+ # dict with vertex index as key, list of connected vertices as value
+ for key in selected_edges:
+ for i in range(2):
+ if key[i] not in vert_connections:
+ vert_connections[key[i]] = [key[1-i]]
+ else:
+ if len(vert_connections[key[i]]) == 2:
+ return False
+ vert_connections[key[i]].append(key[1-i])
+
+ while len(vert_connections) > 0:
+ loop = [iter(vert_connections.keys()).__next__()]
+ growing = True
+ sides_left = True
+
+ while growing:
+ # no more connection data for current vertex
+ if loop[-1] not in vert_connections:
+ if sides_left == True:
+ loop.reverse()
+ sides_left = False
+ else:
+ growing = False
+ # test first possible connection
+ elif vert_connections[loop[-1]][-1] not in loop:
+ new_vert = vert_connections[loop[-1]].pop()
+ if len(vert_connections[loop[-1]]) == 0:
+ del vert_connections[loop[-1]]
+ if new_vert in vert_connections:
+ # remove connection both ways
+ if loop[-1] in vert_connections[new_vert]:
+ if len(vert_connections[new_vert]) == 1:
+ del vert_connections[new_vert]
+ else:
+ vert_connections[new_vert].remove(loop[-1])
+ loop.append(new_vert)
+ # test second possible connection
+ elif len(vert_connections[loop[-1]]) > 1:
+ if vert_connections[loop[-1]][-2] not in loop:
+ new_vert = vert_connections[loop[-1]].pop(-2)
+ if len(vert_connections[loop[-1]]) == 0:
+ del vert_connections[loop[-1]]
+ if new_vert in vert_connections:
+ # remove connection both ways
+ if loop[-1] in vert_connections[new_vert]:
+ if len(vert_connections[new_vert]) == 1:
+ del vert_connections[new_vert]
+ else:
+ vert_connections[new_vert].remove(loop[-1])
+ loop.append(new_vert)
+ # found one end of the loop, continue with next
+ elif sides_left == True:
+ loop.reverse()
+ sides_left = False
+ # found both ends of the loop, stop growing
+ elif sides_left == False:
+ growing = False
+
+ # check for circular
+ if loop[0] in vert_connections:
+ if loop[-1] in vert_connections[loop[0]]:
+ # is circular
+ if len(vert_connections[loop[0]]) == 1:
+ del vert_connections[loop[0]]
+ else:
+ vert_connections[loop[0]].remove(loop[-1])
+ if len(vert_connections[loop[-1]]) == 1:
+ del vert_connections[loop[-1]]
+ loop = [loop, True]
+ else:
+ # not circular
+ loop = [loop, False]
+ else:
+ # not circular
+ loop = [loop, False]
+
+ loops.append(loop)
+
+ if len(loops) < 2:
+ # can't bridge if there is only 1 loop (or none)
+ return False
+ else:
+ return loops
+
+
+# sort loops, so they are connected in the correct order when lofting
+def 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
+
+
+# calculate faces (list of lists, vertex indices) that need to be added
+def calculate_faces(mesh, loops, mode, reverse):
+ faces = []
+ 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
+
+ # 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
+ distance_to_start1 = [(mathutils.Vector(mesh.vertices[loop1[i]].co) - mathutils.Vector(mesh.vertices[loop2[0]].co)).length for i in range(len(loop1))]
+ start1 = distance_to_start1.index(min(distance_to_start1))
+ loop1 = loop1[start1:] + loop1[:start1]
+ # if loop2 is also circular, check if loop2 also has to be shifted
+ if loop2_circular:
+ distance_to_start2 = [(mathutils.Vector(mesh.vertices[loop1[0]].co) - mathutils.Vector(mesh.vertices[loop2[i]].co)).length for i in range(len(loop2))]
+ start2 = distance_to_start2.index(min(distance_to_start2))
+ if min(distance_to_start2) < min(distance_to_start1):
+ loop2 = loop2[start2:] + loop2[:start2]
+ # make sure loop1 is the longest one
+ if len(loop2) > len(loop1):
+ loop1, loop2 = loop2, loop1
+ loop1_circular, loop2_circular = loop2_circular, loop1_circular
+ # have both loops face the same way
+ second_to_first, second_to_second, second_to_last = [(mathutils.Vector(mesh.vertices[loop1[1]].co) - mathutils.Vector(mesh.vertices[loop2[i]].co)).length for i in [0, 1, -1]]
+ last_to_first, last_to_second = [(mathutils.Vector(mesh.vertices[loop1[-1]].co) - mathutils.Vector(mesh.vertices[loop2[i]].co)).length for i in [0, 1]]
+ if (min(last_to_first, last_to_second) < min(second_to_first, second_to_second)) or \
+ (loop2_circular and second_to_last < min(second_to_first, second_to_second)):
+ if loop1_circular:
+ loop1.reverse()
+ loop1 = [loop1[-1]] + loop1[:-1]
+ else:
+ # set the circular loop to loop1 again
+ loop2.reverse()
+ loop2 = [loop2[-1]] + loop2[:-1]
+ loop1_circular, loop2_circular = True, False
+ loop1, loop2 = loop2, loop1
+
+ # both loops have same length
+ if len(loop1) == len(loop2):
+ if not circular: # circular loops are already aligned correctly
+ # have both loops face the same way
+ length1 = sum([(mathutils.Vector(mesh.vertices[loop1[i]].co) - mathutils.Vector(mesh.vertices[loop2[i]].co)).length for i in range(len(loop1))])
+ loop1.reverse()
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list