[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [3245] contrib/py/scripts/addons/ mesh_bevel_round.py: Initial commit of bmesh bevel, based on Ruby code for Sketchup by Fredo6.

Howard Trickey howard.trickey at gmail.com
Wed Apr 11 16:07:27 CEST 2012


Revision: 3245
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=3245
Author:   howardt
Date:     2012-04-11 14:07:27 +0000 (Wed, 11 Apr 2012)
Log Message:
-----------
Initial commit of bmesh bevel, based on Ruby code for Sketchup by Fredo6.

Not very well tested, and a few known bugs, but wanted to get something
out there for people to try.
As well as bugs, still have to put in code to interpolate UVs, etc.

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

Added: contrib/py/scripts/addons/mesh_bevel_round.py
===================================================================
--- contrib/py/scripts/addons/mesh_bevel_round.py	                        (rev 0)
+++ contrib/py/scripts/addons/mesh_bevel_round.py	2012-04-11 14:07:27 UTC (rev 3245)
@@ -0,0 +1,2798 @@
+# ##### 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>
+
+# Ported from RoundCorner Ruby program for Sketchup by Fredo6
+# Fredo6 gave permission to port and distribute with Blender
+
+bl_info = {
+    "name": "Bevel Round",
+    "author": "Fredo6, Howard Trickey",
+    "version": (0, 1),
+    "blender": (2, 6, 3),
+    "location": "View3D > Tools",
+    "description": "Bevel selected edges, possibly rounded",
+    "warning": "",
+    "wiki_url": \
+      "TODO",
+    "tracker_url": \
+      "TODO",
+    "category": "Mesh"}
+
+import math
+import functools
+import bpy
+import bmesh
+import mathutils
+from bpy.props import (BoolProperty,
+                       EnumProperty,
+                       IntProperty,
+                       FloatProperty,
+                       )
+from mathutils import Vector
+
+EPSILON = 1e-6
+
+class BevelRound(bpy.types.Operator):
+    bl_idname = "mesh.bevel_round"
+    bl_label = "Bevel Round"
+    bl_description = "Bevel selected edges, possibly rounded"
+    bl_options = {'REGISTER', 'UNDO'}
+
+    bevel_kind = EnumProperty(name="Bevel Kind",
+        description="Style for beveling edges and corners",
+        items=[
+            ('ROUND', "Round",
+                "Round edges and corners"),
+            ('SHARP', "Sharp",
+                "Round edges, peaked corners"),
+            ('BEVEL', "Bevel",
+                "Flat edges and corners")
+            ],
+        default='BEVEL')
+
+    offset_amount = FloatProperty(name="Offset",
+        description="Amount to offset edges along faces",
+        default=0.2,
+        min=0.0,
+        max=1000.0,
+        soft_min=0.0,
+        soft_max=10.0,
+        unit='LENGTH')
+
+    segments = IntProperty(name="Segments",
+        description="How many segments on bevel profile",
+        min=1,
+        max=100,
+        default=1)
+
+    strict_offset = BoolProperty(name="Strict Offset",
+        description="Keep offset the same on all faces",
+        default=True)
+
+    rounding = BoolProperty(name="Inner Rounding",
+        description="Round inside faces at concave corners",
+        default=True)
+
+    @classmethod
+    def poll(cls, context):
+        obj = context.active_object
+        return (obj and obj.type == 'MESH' and context.mode == 'EDIT_MESH')
+
+    def draw(self, context):
+        layout = self.layout
+        box = layout.box()
+        box.label("Bevel Round Options:")
+        box.prop(self, "bevel_kind")
+        box.prop(self, "offset_amount")
+        box.prop(self, "segments")
+        box.prop(self, "strict_offset")
+        box.prop(self, "rounding")
+
+    def invoke(self, context, event):
+        self.action(context)
+        return {'FINISHED'}
+
+    def execute(self, context):
+        self.action(context)
+        return {'FINISHED'}
+
+    def action(self, context):
+        obj = bpy.context.active_object
+        bm = bmesh.from_edit_mesh(obj.data)
+        # make sure vert, edge, face indexes match their positions
+        bm.verts.index_update()
+        bm.edges.index_update()
+        bm.faces.index_update()
+        algo = BevelRoundAlgo(bm, self.bevel_kind, self.offset_amount,
+            self.segments, self.strict_offset, self.rounding)
+        algo.execute()
+        # Force mesh data recalculation
+        bpy.ops.object.editmode_toggle()
+        bpy.ops.object.editmode_toggle()
+
+
+class BevelRoundAlgo(object):
+    def __init__(self, bm, kind, offset, num_seg, strict, round):
+        # The bmesh object
+        self.bm = bm
+
+        # How much to move offset edges
+        # (projected onto 90deg angle planes, unless strict_offset)
+        self.offset = offset
+
+        # How many segments in the profile of an edge
+        self.num_seg = num_seg
+
+        # Cache of profiles in standard position, keyed by "kind-numseg"
+        # Kind will be one of 'C' or 'P', for now
+        self.hsh_profile_pts = {}
+
+        # bmesh Edge index -> BEdge for it
+        # Will have one for all the edges in the bevel selection
+        self.hsh_ed = {}
+
+        # bmesh Vertex index -> BCorner for it
+        # Will have one for all ends of edges in hsh_ed
+        self.hsh_corners = {}
+
+        # bmesh Face index -> BFace for it
+        self.hsh_faces = {}
+
+        # List of [Vector, Vector], each a border line segment (for display only?)
+        self.lpt_borders = []
+
+        # Catenas are chains of edges with related offsets
+        # Each has eds, a list of BEdges;
+        #  chain, a list of [BEdge, face index]l
+        #  nbsmall: seems to be some kind of edge count
+        self.lst_catenas = []
+
+        # List of Vector, pivot points for star corners
+        self.lst_mark_points = []
+
+        # lst_triangulate is list of [vd, ed1, ed2, seg1, seg2]
+        # for each vd for a vert with only two edges and >=3 pairs
+        self.lst_triangulated = []
+
+        # List of BCorner, those signaled as errors (pair lines don't cross (?))
+        self.hsh_error_vertex = {}
+
+        # Edge index -> bmesh Edge for edges to bevel
+        self.hash_edges = {}
+
+        # hash_edges_extra : Edge index -> bmesh Edge added for valence >= 4 reasons
+        self.hash_edges_extra = {}
+
+        # Vertex index -> list of bmesh edges to bevel attached
+        self.hsh_vertex_edges = {}
+
+        # Vertex index -> list of all bmesh edges attached to it
+        self.hsh_vertex_info = {}
+
+        # Map from point to BMVert
+        self.points = Points(self.bm)
+
+        # Used to orient asymmetric corner mesh patterns
+        self.golden_axis = Vector([0.0, 0.0, 1.0])
+
+        # Profile spec for edges: [string, number]
+        # where string is 'C' for quarter circle, 'CR' for concave quarter circle,
+        # 'BZ' for Bezier, 'P' for 'perso' (?, some kind of multi-bezier).
+        # number is number of line segments in profile (so 1 means just
+        # a single straight line from start to end)
+        if kind == 'BEVEL':
+            self.profile_type = ['C', 1]
+            self.num_seg = 1
+        else:
+            self.profile_type = ['C', num_seg]
+
+        # Controls whether or not to use a round profile in certain disagreeing cases (?)
+        self.mode_profile = 1
+
+        # Corners come to peaks if mode_sharp
+        self.mode_sharp = True if kind == 'SHARP' else False
+
+        # Forces offset along faces to  be uniform rather than adjusted
+        # to make them uniform when projected on 90deg-meeting-faces
+        self.strict_offset = strict
+
+        # Should we round the edges in the faces themselves too?
+        self.mode_rounding = round
+
+    def execute(self):
+        bm = self.bm
+
+        # Add the bmesh edges and compute everything
+        # needed for bevel
+        self.build_model(bm)
+
+        # print("after build:")
+        # self.print()
+
+        # Initialization for geometry making
+        self.prepare_geometry()
+
+        # print("after prepare_geometry")
+        # self.print()
+
+        self.lst_corners = list(self.hsh_corners.values())
+        self.nb_corners = len(self.lst_corners) - 1
+        self.lst_eds = list(self.hsh_ed.values())
+        self.nb_eds = len(self.lst_eds) - 1
+        self.hsh_edge_erase = {}
+        self.nb_borders = len(self.lpt_borders) // 2 - 1
+
+        # Process geometry
+
+        self.lst_edge_erase = []
+        self.nb_edge_erase = -1
+
+        # Creating the rounding faces
+        for k in range(0, self.nb_eds + 1):
+            ed = self.lst_eds[k]
+            if ed.vmesh:
+                self.create_geometry_vmesh(ed.vmesh)
+
+        # Creating the triangulated  vmesh if any
+        self.create_geometry_vmesh(self.lst_vmesh_triangulated)
+        self.create_geometry_vborders(self.lst_vborders_triangulated)
+
+        # Creating the corner round faces
+        for k in range(0, self.nb_corners + 1):
+           vd = self.lst_corners[k]
+           if vd.vmesh:
+               self.create_geometry_vmesh(vd.vmesh)
+
+        # Creating the new faces
+        for fc in self.hsh_faces.values():
+            lv = []
+            for i in range(len(fc.bmverts)):
+                npl = fc.newpts[i]
+                if npl:
+                    lv.extend(self.get_bmverts(npl))
+                else:
+                    lv.append(fc.bmverts[i])
+            self.bm.faces.new(lv)
+
+        # Deleting the unneeded geometry
+        for f in self.hsh_faces.values():
+            if f.face.is_valid:
+                fedges = f.face.edges[::]
+                self.bm.faces.remove(f.face)
+                for e in fedges:
+                    if e.is_valid:
+                        if e.is_wire:
+                            self.bm.edges.remove(e)
+        for k in range(0, self.nb_corners + 1):
+            vd = self.lst_corners[k]
+            if len(vd.leds) == 1:
+                edge = vd.leds[0].edge
+                if edge.is_valid:
+                    self.bm.edges.remove(edge)
+            else:
+                # print("remove edges:", vd.vertex.link_edges)
+                pass  # is there stuff to do here?
+            if vd.vertex.is_valid:
+                self.bm.verts.remove(vd.vertex)
+
+    # Prepare the geometry
+    def prepare_geometry(self):
+        # Compute the corners
+        for vd in self.hsh_corners.values():
+            self.corner_compute(vd)
+
+        # Compute the edge roundings

@@ Diff output truncated at 10240 characters. @@


More information about the Bf-extensions-cvs mailing list