diff options
Diffstat (limited to 'archipack/bmesh_utils.py')
-rw-r--r-- | archipack/bmesh_utils.py | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/archipack/bmesh_utils.py b/archipack/bmesh_utils.py new file mode 100644 index 00000000..b49f4683 --- /dev/null +++ b/archipack/bmesh_utils.py @@ -0,0 +1,249 @@ +# -*- coding:utf-8 -*- + +# ##### 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> + +# ---------------------------------------------------------- +# Author: Stephen Leger (s-leger) +# +# ---------------------------------------------------------- +import bpy +import bmesh + + +class BmeshEdit(): + @staticmethod + def _start(context, o): + """ + private, start bmesh editing of active object + """ + o.select = True + context.scene.objects.active = o + bpy.ops.object.mode_set(mode='EDIT') + bm = bmesh.from_edit_mesh(o.data) + bm.verts.ensure_lookup_table() + bm.faces.ensure_lookup_table() + return bm + + @staticmethod + def _end(bm, o): + """ + private, end bmesh editing of active object + """ + bm.normal_update() + bmesh.update_edit_mesh(o.data, True) + bpy.ops.object.mode_set(mode='OBJECT') + bm.free() + + @staticmethod + def _matids(bm, matids): + for i, matid in enumerate(matids): + bm.faces[i].material_index = matid + + @staticmethod + def _uvs(bm, uvs): + layer = bm.loops.layers.uv.verify() + l_i = len(uvs) + for i, face in enumerate(bm.faces): + if i > l_i: + raise RuntimeError("Missing uvs for face {}".format(i)) + l_j = len(uvs[i]) + for j, loop in enumerate(face.loops): + if j > l_j: + raise RuntimeError("Missing uv {} for face {}".format(j, i)) + loop[layer].uv = uvs[i][j] + + @staticmethod + def _verts(bm, verts): + for i, v in enumerate(verts): + bm.verts[i].co = v + + @staticmethod + def buildmesh(context, o, verts, faces, matids=None, uvs=None, weld=False, clean=False, auto_smooth=True): + bm = BmeshEdit._start(context, o) + bm.clear() + for v in verts: + bm.verts.new(v) + bm.verts.ensure_lookup_table() + for f in faces: + bm.faces.new([bm.verts[i] for i in f]) + bm.faces.ensure_lookup_table() + if matids is not None: + BmeshEdit._matids(bm, matids) + if uvs is not None: + BmeshEdit._uvs(bm, uvs) + if weld: + bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001) + BmeshEdit._end(bm, o) + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + if auto_smooth: + bpy.ops.mesh.faces_shade_smooth() + o.data.use_auto_smooth = True + else: + bpy.ops.mesh.faces_shade_flat() + if clean: + bpy.ops.mesh.delete_loose() + bpy.ops.object.mode_set(mode='OBJECT') + + @staticmethod + def addmesh(context, o, verts, faces, matids=None, uvs=None, weld=False, clean=False, auto_smooth=True): + bm = BmeshEdit._start(context, o) + nv = len(bm.verts) + nf = len(bm.faces) + + for v in verts: + bm.verts.new(v) + + bm.verts.ensure_lookup_table() + + for f in faces: + bm.faces.new([bm.verts[nv + i] for i in f]) + + bm.faces.ensure_lookup_table() + + if matids is not None: + for i, matid in enumerate(matids): + bm.faces[nf + i].material_index = matid + + if uvs is not None: + layer = bm.loops.layers.uv.verify() + for i, face in enumerate(bm.faces[nf:]): + for j, loop in enumerate(face.loops): + loop[layer].uv = uvs[i][j] + + if weld: + bmesh.ops.remove_doubles(bm, verts=bm.verts, dist=0.001) + BmeshEdit._end(bm, o) + bpy.ops.object.mode_set(mode='EDIT') + bpy.ops.mesh.select_all(action='SELECT') + if auto_smooth: + bpy.ops.mesh.faces_shade_smooth() + o.data.use_auto_smooth = True + else: + bpy.ops.mesh.faces_shade_flat() + if clean: + bpy.ops.mesh.delete_loose() + bpy.ops.object.mode_set(mode='OBJECT') + + @staticmethod + def bevel(context, o, + offset, + offset_type=0, + segments=1, + profile=0.5, + vertex_only=False, + clamp_overlap=True, + material=-1, + use_selection=True): + """ + /* Bevel offset_type slot values */ + enum { + BEVEL_AMT_OFFSET, + BEVEL_AMT_WIDTH, + BEVEL_AMT_DEPTH, + BEVEL_AMT_PERCENT + }; + """ + bm = bmesh.new() + bm.from_mesh(o.data) + bm.verts.ensure_lookup_table() + if use_selection: + geom = [v for v in bm.verts if v.select] + geom.extend([ed for ed in bm.edges if ed.select]) + else: + geom = bm.verts[:] + geom.extend(bm.edges[:]) + + bmesh.ops.bevel(bm, + geom=geom, + offset=offset, + offset_type=offset_type, + segments=segments, + profile=profile, + vertex_only=vertex_only, + clamp_overlap=clamp_overlap, + material=material) + + bm.to_mesh(o.data) + bm.free() + + @staticmethod + def bissect(context, o, + plane_co, + plane_no, + dist=0.001, + use_snap_center=False, + clear_outer=True, + clear_inner=False + ): + + bm = bmesh.new() + bm.from_mesh(o.data) + bm.verts.ensure_lookup_table() + geom = bm.verts[:] + geom.extend(bm.edges[:]) + geom.extend(bm.faces[:]) + + bmesh.ops.bisect_plane(bm, + geom=geom, + dist=dist, + plane_co=plane_co, + plane_no=plane_no, + use_snap_center=False, + clear_outer=clear_outer, + clear_inner=clear_inner + ) + + bm.to_mesh(o.data) + bm.free() + + @staticmethod + def solidify(context, o, amt, floor_bottom=False, altitude=0): + bm = bmesh.new() + bm.from_mesh(o.data) + bm.verts.ensure_lookup_table() + geom = bm.faces[:] + bmesh.ops.solidify(bm, geom=geom, thickness=amt) + if floor_bottom: + for v in bm.verts: + if not v.select: + v.co.z = altitude + bm.to_mesh(o.data) + bm.free() + + @staticmethod + def verts(context, o, verts): + """ + update vertex position of active object + """ + bm = BmeshEdit._start(context, o) + BmeshEdit._verts(bm, verts) + BmeshEdit._end(bm, o) + + @staticmethod + def aspect(context, o, matids, uvs): + """ + update material id and uvmap of active object + """ + bm = BmeshEdit._start(context, o) + BmeshEdit._matids(bm, matids) + BmeshEdit._uvs(bm, uvs) + BmeshEdit._end(bm, o) |