diff options
author | Nathan Letwory <nathan@letworyinteractive.com> | 2011-07-09 20:32:38 +0400 |
---|---|---|
committer | Nathan Letwory <nathan@letworyinteractive.com> | 2011-07-09 20:32:38 +0400 |
commit | d9275e4abffc6060dc07bb87382995cc27f68598 (patch) | |
tree | a0eb4d62558593929d40e91a1c0d2df21ddb89d2 /mesh_inset/__init__.py |
Tag for 2.58av2.58a
Diffstat (limited to 'mesh_inset/__init__.py')
-rw-r--r-- | mesh_inset/__init__.py | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/mesh_inset/__init__.py b/mesh_inset/__init__.py new file mode 100644 index 00000000..95a03830 --- /dev/null +++ b/mesh_inset/__init__.py @@ -0,0 +1,203 @@ +# ##### 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": "Inset Polygon", + "author": "Howard Trickey", + "version": (0, 3), + "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="Amount to move inset edges", + default=5.0, + min=0.0, + max=1000.0, + soft_min=0.0, + soft_max=100.0, + unit='LENGTH') + inset_height = FloatProperty(name="Height", + description="Amount to raise inset faces", + default=0.0, + min=-10000.0, + max=10000.0, + soft_min=-500.0, + soft_max=500.0, + unit='LENGTH') + region = BoolProperty(name="Region", + description="Inset selection as one region?", + default=True) + scale = EnumProperty(name="Scale", + description="Scale for amount", + items=[ + ('PERCENT', "Percent", + "Percentage of maximum inset amount"), + ('ABSOLUTE', "Absolute", + "Length in blender units") + ], + default='PERCENT') + + @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, "scale") + 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, + self.scale == 'PERCENT') + 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, as_percent): + 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)) + m.face_data.append(f.index) + orig_numv = len(m.points.pos) + orig_numf = len(m.faces) + model.BevelSelectionInModel(m, amount, pitch, True, region, as_percent) + 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 = [] + blender_old_face_index = [] + for i in range(orig_numf, len(m.faces)): + f = m.faces[i] + if len(f) == 3: + blender_faces.append(list(f) + [0]) + blender_old_face_index.append(m.face_data[i]) + elif len(f) == 4: + if f[3] == 0: + blender_faces.append([f[3], f[0], f[1], f[2]]) + else: + blender_faces.append(f) + blender_old_face_index.append(m.face_data[i]) + 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 + # copy face attributes from old face that it was derived from + bfi = blender_old_face_index[i] + if bfi and 0 <= bfi < start_faces: + bfacenew = mesh.faces[start_faces + i] + bface = mesh.faces[bfi] + bfacenew.material_index = bface.material_index + bfacenew.use_smooth = bface.use_smooth + 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() |