[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [4200] contrib/py/scripts/addons/ mesh_f2.py: Committing F2 to svn.

Bart Crouch bartius.crouch at gmail.com
Thu Jan 24 14:25:52 CET 2013


Revision: 4200
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=4200
Author:   crouch
Date:     2013-01-24 13:25:40 +0000 (Thu, 24 Jan 2013)
Log Message:
-----------
Committing F2 to svn.

Added Paths:
-----------
    contrib/py/scripts/addons/mesh_f2.py

Added: contrib/py/scripts/addons/mesh_f2.py
===================================================================
--- contrib/py/scripts/addons/mesh_f2.py	                        (rev 0)
+++ contrib/py/scripts/addons/mesh_f2.py	2013-01-24 13:25:40 UTC (rev 4200)
@@ -0,0 +1,298 @@
+# ##### 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>
+
+bl_info = {
+    'name': "F2",
+    'author': "Bart Crouch",
+    'version': (1, 4, 0),
+    'blender': (2, 65, 9),
+    'location': "Editmode > F",
+    'warning': "",
+    'description': "Extends the 'Make Edge/Face' functionality",
+    'wiki_url': "http://wiki.blender.org/index.php/Extensions:2.6/Py/"\
+        "Scripts/Modeling/F2",
+    'tracker_url': "http://projects.blender.org/tracker/index.php?"\
+        "func=detail&aid=33979",
+    'category': 'Mesh'}
+
+
+import bmesh
+import bpy
+import itertools
+import mathutils
+from bpy_extras import view3d_utils
+
+
+# create a face from a single selected edge
+def quad_from_edge(bm, edge_sel, context, event):
+    ob = context.active_object
+    region = context.region
+    region_3d = context.space_data.region_3d
+
+    # find linked edges that are open (<2 faces connected) and not part of
+    # the face the selected edge belongs to
+    all_edges = [[edge for edge in edge_sel.verts[i].link_edges if \
+        len(edge.link_faces) < 2 and edge != edge_sel and \
+        sum([face in edge_sel.link_faces for face in edge.link_faces]) == 0] \
+        for i in range(2)]
+    if not all_edges[0] or not all_edges[1]:
+        return
+
+    # determine which edges to use, based on mouse cursor position
+    mouse_pos = mathutils.Vector([event.mouse_region_x, event.mouse_region_y])
+    optimal_edges = []
+    for edges in all_edges:
+        min_dist = False
+        for edge in edges:
+            vert = [vert for vert in edge.verts if not vert.select][0]
+            world_pos = ob.matrix_world * vert.co.copy()
+            screen_pos = view3d_utils.location_3d_to_region_2d(region,
+                region_3d, world_pos)
+            dist = (mouse_pos - screen_pos).length
+            if not min_dist or dist < min_dist[0]:
+                min_dist = (dist, edge, vert)
+        optimal_edges.append(min_dist)
+
+    # determine the vertices, which make up the quad
+    v1 = edge_sel.verts[0]
+    v2 = edge_sel.verts[1]
+    edge_1 = optimal_edges[0][1]
+    edge_2 = optimal_edges[1][1]
+    v3 = optimal_edges[0][2]
+    v4 = optimal_edges[1][2]
+
+    # normal detection
+    flip_align = True
+    normal_edge = edge_1
+    if not normal_edge.link_faces:
+        normal_edge = edge_2
+        if not normal_edge.link_faces:
+            normal_edge = edge_sel
+            if not normal_edge.link_faces:
+                # no connected faces, so no need to flip the face normal
+                flip_align = False
+    if flip_align: # there is a face to which the normal can be aligned
+        ref_verts = [v for v in normal_edge.link_faces[0].verts]
+        if v3 in ref_verts:
+            va_1 = v3
+            va_2 = v1
+        elif normal_edge == edge_sel:
+            va_1 = v1
+            va_2 = v2
+        else:
+            va_1 = v2
+            va_2 = v4
+        if (va_1 == ref_verts[0] and va_2 == ref_verts[-1]) or \
+        (va_2 == ref_verts[0] and va_1 == ref_verts[-1]):
+            # reference verts are at start and end of the list -> shift list
+            ref_verts = ref_verts[1:] + [ref_verts[0]]
+        if ref_verts.index(va_1) > ref_verts.index(va_2):
+            # connected face has same normal direction, so don't flip
+            flip_align = False
+
+    # material index detection
+    ref_faces = edge_sel.link_faces
+    if not ref_faces:
+        ref_faces = edge_sel.verts[0].link_faces
+    if not ref_faces:
+        ref_faces = edge_sel.verts[1].link_faces
+    if not ref_faces:
+        mat_index = False
+        smooth = False
+    else:
+        mat_index = ref_faces[0].material_index
+        smooth = ref_faces[0].smooth
+
+    # create quad
+    try:
+        verts = [v3, v1, v2, v4]
+        if flip_align:
+            verts.reverse()
+        face = bm.faces.new(verts)
+        if mat_index:
+            face.material_index = mat_index
+        face.smooth = smooth
+    except:
+        # face already exists
+        return
+
+    # change selection
+    edge_sel.select = False
+    for vert in edge_sel.verts:
+        vert.select = False
+    for edge in face.edges:
+        if edge.index < 0:
+            edge.select = True
+    v3.select = True
+    v4.select = True
+
+    # toggle mode, to force correct drawing
+    bpy.ops.object.mode_set(mode='OBJECT')
+    bpy.ops.object.mode_set(mode='EDIT')
+
+
+# create a face from a single selected vertex, if it is an open vertex
+def quad_from_vertex(bm, vert_sel, context, event):
+    ob = context.active_object
+    region = context.region
+    region_3d = context.space_data.region_3d
+
+    # find linked edges that are open (<2 faces connected)
+    edges = [edge for edge in vert_sel.link_edges if len(edge.link_faces) < 2]
+    if len(edges) < 2:
+        return
+
+    # determine which edges to use, based on mouse cursor position
+    min_dist = False
+    mouse_pos = mathutils.Vector([event.mouse_region_x, event.mouse_region_y])
+    for a, b in itertools.combinations(edges, 2):
+        other_verts = [vert for edge in [a, b] for vert in edge.verts \
+            if not vert.select]
+        mid_other = (other_verts[0].co.copy() + other_verts[1].co.copy()) \
+            / 2
+        new_pos = 2 * (mid_other - vert_sel.co.copy()) + vert_sel.co.copy()
+        world_pos = ob.matrix_world * new_pos
+        screen_pos = view3d_utils.location_3d_to_region_2d(region, region_3d,
+            world_pos)
+        dist = (mouse_pos - screen_pos).length
+        if not min_dist or dist < min_dist[0]:
+            min_dist = (dist, (a, b), other_verts, new_pos)
+
+    # create vertex at location mirrored in the line, connecting the open edges
+    edges = min_dist[1]
+    other_verts = min_dist[2]
+    new_pos = min_dist[3]
+    vert_new = bm.verts.new(new_pos)
+
+    # normal detection
+    flip_align = True
+    normal_edge = edges[0]
+    if not normal_edge.link_faces:
+        normal_edge = edges[1]
+        if not normal_edge.link_faces:
+            # no connected faces, so no need to flip the face normal
+                flip_align = False
+    if flip_align: # there is a face to which the normal can be aligned
+        ref_verts = [v for v in normal_edge.link_faces[0].verts]
+        if other_verts[0] in ref_verts:
+            va_1 = other_verts[0]
+            va_2 = vert_sel
+        else:
+            va_1 = vert_sel
+            va_2 = other_verts[1]
+        if (va_1 == ref_verts[0] and va_2 == ref_verts[-1]) or \
+        (va_2 == ref_verts[0] and va_1 == ref_verts[-1]):
+            # reference verts are at start and end of the list -> shift list
+            ref_verts = ref_verts[1:] + [ref_verts[0]]
+        if ref_verts.index(va_1) > ref_verts.index(va_2):
+            # connected face has same normal direction, so don't flip
+            flip_align = False
+
+    # material index detection
+    ref_faces = vert_sel.link_faces
+    if not ref_faces:
+        mat_index = False
+        smooth = False
+    else:
+        mat_index = ref_faces[0].material_index
+        smooth = ref_faces[0].smooth
+
+    # create face between all 4 vertices involved
+    verts = [other_verts[0], vert_sel, other_verts[1], vert_new]
+    if flip_align:
+        verts.reverse()
+    face = bm.faces.new(verts)
+    if mat_index:
+        face.material_index = mat_index
+    face.smooth = smooth
+
+    # change selection
+    vert_new.select = True
+    vert_sel.select = False
+
+    # toggle mode, to force correct drawing
+    bpy.ops.object.mode_set(mode='OBJECT')
+    bpy.ops.object.mode_set(mode='EDIT')
+
+
+class MeshF2(bpy.types.Operator):
+    """Tooltip"""
+    bl_idname = "mesh.f2"
+    bl_label = "Make Edge/Face"
+    bl_description = "Extends the 'Make Edge/Face' functionality"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    @classmethod
+    def poll(cls, context):
+        # check we are in mesh editmode
+        ob = context.active_object
+        return(ob and ob.type == 'MESH' and context.mode == 'EDIT_MESH')
+
+    def invoke(self, context, event):
+        bm = bmesh.from_edit_mesh(context.active_object.data)
+        sel = [v for v in bm.verts if v.select]
+        if len(sel) > 2:
+            # original 'Make Edge/Face' behaviour
+            bpy.ops.mesh.edge_face_add()
+        elif len(sel) == 1:
+            # single vertex selected -> mirror vertex and create new face
+            quad_from_vertex(bm, sel[0], context, event)
+        elif len(sel) == 2:
+            edges_sel = [ed for ed in bm.edges if ed.select]
+            if len(edges_sel) != 1:
+                # 2 vertices selected, but not on the same edge
+                bpy.ops.mesh.edge_face_add()
+            else:
+                # single edge selected -> new face from linked open edges
+                quad_from_edge(bm, edges_sel[0], context, event)
+
+        return {'FINISHED'}
+
+
+# registration
+classes = [MeshF2]
+addon_keymaps = []
+
+
+def register():
+    # add operator
+    for c in classes:
+        bpy.utils.register_class(c)
+
+    # add keymap entry
+    km = bpy.context.window_manager.keyconfigs.addon.keymaps.new(\
+        name='Mesh', space_type='EMPTY')
+    kmi = km.keymap_items.new("mesh.f2", 'F', 'PRESS')
+    addon_keymaps.append(km)
+
+
+def unregister():
+    # remove operator
+    for c in classes:
+        bpy.utils.unregister_class(c)
+
+    # remove keymap entry
+    for km in addon_keymaps:

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-extensions-cvs mailing list