[Bf-extensions-cvs] SVN commit: /data/svn/bf-extensions [1900] contrib/py/scripts/addons: Initial contrib version of script to inset a polygon or region of polygons .
Howard Trickey
howard.trickey at gmail.com
Sat May 7 15:24:15 CEST 2011
Revision: 1900
http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-extensions&revision=1900
Author: howardt
Date: 2011-05-07 13:24:14 +0000 (Sat, 07 May 2011)
Log Message:
-----------
Initial contrib version of script to inset a polygon or region of polygons.
Added Paths:
-----------
contrib/py/scripts/addons/mesh_inset/
contrib/py/scripts/addons/mesh_inset/__init__.py
contrib/py/scripts/addons/mesh_inset/geom.py
contrib/py/scripts/addons/mesh_inset/model.py
contrib/py/scripts/addons/mesh_inset/offset.py
contrib/py/scripts/addons/mesh_inset/triquad.py
Added: contrib/py/scripts/addons/mesh_inset/__init__.py
===================================================================
--- contrib/py/scripts/addons/mesh_inset/__init__.py (rev 0)
+++ contrib/py/scripts/addons/mesh_inset/__init__.py 2011-05-07 13:24:14 UTC (rev 1900)
@@ -0,0 +1,177 @@
+# ##### 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": "Inset Polygon",
+ "author": "Howard Trickey",
+ "version": (0, 2),
+ "blender": (2, 5, 7),
+ "api": 36147,
+ "location": "View3D > Tools",
+ "description": "Make an inset polygon inside selection.",
+ "warning": "",
+ "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/Scripts/Modeling/Inset-Polygon",
+ "tracker_url": "http://projects.blender.org/tracker/index.php?func=detail&aid=27290&group_id=153&atid=468",
+ "category": "Mesh"}
+
+if "bpy" in locals():
+ import imp
+else:
+ from . import geom
+ from . import model
+ from . import offset
+ from . import triquad
+
+import math
+import bpy
+import mathutils
+from bpy.props import *
+
+
+class Inset(bpy.types.Operator):
+ bl_idname = "mesh.inset"
+ bl_label = "Inset"
+ bl_description = "Make an inset polygon inside selection"
+ bl_options = {'REGISTER', 'UNDO'}
+
+ inset_amount = FloatProperty(name="Amount",
+ description="Distance of inset edges from outer ones",
+ default = 0.05,
+ min = 0.0,
+ max = 1000.0,
+ soft_min = 0.0,
+ soft_max = 1.0,
+ unit = 'LENGTH')
+ inset_height = FloatProperty(name="Height",
+ description="Distance to raise inset faces",
+ default = 0.0,
+ min = -1000.0,
+ max = 1000.0,
+ soft_min = -1.0,
+ soft_max = 1.0,
+ unit = 'LENGTH')
+ region = BoolProperty(name="Region",
+ description="Inset selection as one region?",
+ 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("Inset Options")
+ box.prop(self, "inset_amount")
+ box.prop(self, "inset_height")
+ box.prop(self, "region")
+
+ def invoke(self, context, event):
+ self.action(context)
+ return {'FINISHED'}
+
+ def execute(self, context):
+ self.action(context)
+ return {'FINISHED'}
+
+ def action(self, context):
+ save_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')
+ obj = bpy.context.active_object
+ mesh = obj.data
+ do_inset(mesh, self.inset_amount, self.inset_height, self.region)
+ bpy.ops.object.mode_set(mode='EDIT')
+ bpy.context.user_preferences.edit.use_global_undo = save_global_undo
+
+
+def do_inset(mesh, amount, height, region):
+ if amount <= 0.0:
+ return
+ pitch = math.atan(height / amount)
+ selfaces = []
+ selface_indices = []
+ for face in mesh.faces:
+ if face.select and not face.hide:
+ selfaces.append(face)
+ selface_indices.append(face.index)
+ m = geom.Model()
+ # if add all mesh.vertices, coord indices will line up
+ # Note: not using Points.AddPoint which does dup elim
+ # because then would have to map vertices in and out
+ m.points.pos = [ v.co.to_tuple() for v in mesh.vertices ]
+ for f in selfaces:
+ m.faces.append(list(f.vertices))
+ orig_numv = len(m.points.pos)
+ orig_numf = len(m.faces)
+ model.BevelSelectionInModel(m, m.faces, amount, pitch, True, region)
+ if len(m.faces) == orig_numf:
+ # something went wrong with Bevel - just treat as no-op
+ return
+ # blender_faces: newfaces but all 4-tuples and no 0
+ # in 4th position if a 4-sided poly
+ blender_faces = []
+ for i in range(orig_numf, len(m.faces)):
+ f = m.faces[i]
+ if len(f) == 3:
+ blender_faces.append(list(f) + [0])
+ elif len(f) == 4:
+ if f[3] == 0:
+ blender_faces.append([f[3], f[0], f[1], f[2]])
+ else:
+ blender_faces.append(f)
+ num_new_vertices = len(m.points.pos) - orig_numv
+ mesh.vertices.add(num_new_vertices)
+ for i in range(orig_numv, len(m.points.pos)):
+ mesh.vertices[i].co = mathutils.Vector(m.points.pos[i])
+ start_faces = len(mesh.faces)
+ mesh.faces.add(len(blender_faces))
+ for i, newf in enumerate(blender_faces):
+ mesh.faces[start_faces + i].vertices_raw = newf
+ mesh.update(calc_edges = True)
+ # remove original faces
+ bpy.ops.object.mode_set(mode='EDIT')
+ save_select_mode = bpy.context.tool_settings.mesh_select_mode
+ bpy.context.tool_settings.mesh_select_mode = [False, False, True]
+ bpy.ops.mesh.select_all(action = 'DESELECT')
+ bpy.ops.object.mode_set(mode = 'OBJECT')
+ for fi in selface_indices:
+ mesh.faces[fi].select = True
+ bpy.ops.object.mode_set(mode = 'EDIT')
+ bpy.ops.mesh.delete(type = 'FACE')
+ bpy.context.tool_settings.mesh_select_mode = save_select_mode
+
+
+def panel_func(self, context):
+ self.layout.label(text="Inset:")
+ self.layout.operator("mesh.inset", text="Inset")
+
+
+def register():
+ bpy.utils.register_class(Inset)
+ bpy.types.VIEW3D_PT_tools_meshedit.append(panel_func)
+
+
+def unregister():
+ bpy.utils.unregister_class(Inset)
+ bpy.types.VIEW3D_PT_tools_meshedit.remove(panel_func)
+
+
+if __name__ == "__main__":
+ register()
Added: contrib/py/scripts/addons/mesh_inset/geom.py
===================================================================
--- contrib/py/scripts/addons/mesh_inset/geom.py (rev 0)
+++ contrib/py/scripts/addons/mesh_inset/geom.py 2011-05-07 13:24:14 UTC (rev 1900)
@@ -0,0 +1,696 @@
+# ##### 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 #####
+
+"""Geometry classes and operations.
+Also, vector file representation (Art).
+"""
+
+__author__ = "howard.trickey at gmail.com"
+
+import math
+
+# distances less than about DISTTOL will be considered
+# essentially zero
+DISTTOL = 1e-3
+INVDISTTOL = 1e3
+
+
+class Points(object):
+ """Container of points without duplication, each mapped to an int.
+
+ Points are either have dimension at least 2, maybe more.
+
+ Implementation:
+ In order to efficiently find duplicates, we quantize the points
+ to triples of ints and map from quantized triples to vertex
+ index.
+
+ Attributes:
+ pos: list of tuple of float - coordinates indexed by
+ vertex number
+ invmap: dict of (int, int, int) to int - quantized coordinates
+ to vertex number map
+ """
+
+ def __init__(self, initlist = []):
+ self.pos = []
+ self.invmap = dict()
+ for p in initlist:
+ self.AddPoint(p)
+
+ @staticmethod
+ def Quantize(p):
+ """Quantize the float tuple into an int tuple.
+
+ Args:
+ p: tuple of float
+ Returns:
+ tuple of int - scaled by INVDISTTOL and rounded p
+ """
+
+ return tuple([int(round(v*INVDISTTOL)) for v in p])
+
+ def AddPoint(self, p):
+ """Add point p to the Points set and return vertex number.
+
+ If there is an existing point which quantizes the same,,
+ don't add a new one but instead return existing index.
+
+ Args:
+ p: tuple of float - coordinates (2-tuple or 3-tuple)
+ Returns:
+ int - the vertex number of added (or existing) point
+ """
+
+ qp = Points.Quantize(p)
+ if qp in self.invmap:
+ return self.invmap[qp]
+ else:
+ self.invmap[qp] = len(self.pos)
+ self.pos.append(p)
+ return len(self.pos)-1
+
+ def AddPoints(self, points):
+ """Add another set of points to this set.
+
+ We need to return a mapping from indices
+ in the argument points space into indices
+ in this point space.
+
+ Args:
+ points: Points - to union into this set
+ Returns:
+ list of int: maps added indices to new ones
+ """
+
+ vmap = [ 0 ] * len(points.pos)
+ for i in range(len(points.pos)):
+ vmap[i] = self.AddPoint(points.pos[i])
+ return vmap
+
+ def AddZCoord(self, z):
+ """Change this in place to have a z coordinate, with value z.
+
+ Assumes the coordinates are currently 2d.
+
+ Args:
+ z: the value of the z coordinate to add
+ Side Effect:
+ self now has a z-coordinate added
+ """
+
+ assert(len(self.pos) == 0 or len(self.pos[0]) == 2)
+ newinvmap = dict()
+ for i, (x,y) in enumerate(self.pos):
+ newp = (x, y, z)
+ self.pos[i] = newp
+ newinvmap[self.Quantize(newp)] = i
+ self.invmap = newinvmap
+
+ def AddToZCoord(self, i, delta):
+ """Change the z-coordinate of point with index i to add delta.
+
+ Assumes the coordinates are currently 3d.
+
+ Args:
+ i: int - index of a point
+ delta: float - value to add to z-coord
+ """
+
+ (x, y, z) = self.pos[i]
+ self.pos[i] = (x, y, z + delta)
+
+
+class PolyArea(object):
+ """Contains a Polygonal Area (polygon with possible holes).
+
+ A polygon is a list of vertex ids, each an index given by
+ a Points object. The list represents a CCW-oriented
+ outer boundary (implicitly closed).
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-extensions-cvs
mailing list