# BMesh polygons with holes

Is it possible to create a BMesh polygon (BMFace) with holes via Python?

Use case. I need that for my addons that import geographical data. A polygon for Rome has a hole for Vatican City.

Polygons in Mesh or BMesh aren't permitted to have holes in the sense of providing a perimeter and adding an internal part to subtract. This means considering alternatives.

1. You can construct an irregular polygon / Ngon.

But it will contain at least two duplicated vertices for that pathway between the cutout and the perimeter.

1. You could script a mesh.fill(), which could take two given edge outlines and fill from the outer edges inwards. (will add script when I have time)

1. Alternatively you might use a counter intuitive solution namely a 2D Curve (of straight parts) : code included in link
• The solution with the pathway could be tricky to realize for a general case: concave perimeter, multiple concave holes. – vvoovv Jul 2 '15 at 17:41
• How would you script that mesh.fill() for the general case: concave perimeter, multiple concave holes? – vvoovv Jul 2 '15 at 17:42
• I had to switch off the computer for an electric storm, maybe I can answer later. – zeffii Jul 3 '15 at 7:09

BMesh operator bmesh.ops.triangle_fill does the trick:

bmesh.ops.triangle_fill(bm, use_beauty=True, use_dissolve=False, edges=outer_and_inner_edges)


Here outer_and_inner_edges is the list of BMesh edges (both outer and inner) that constitute the polygon with holes.

The operator will create a bunch of triangles that cover the polygon in question.

yes, is possible.. you need your vertices and faces data...

here a fast template, you only need to modify your vertices and face data:

this addon set a button in order to add some cube with hole:

bl_info = {
"name": "bmesh with holes",
"author": "Diego Quevedo",
"version": (1, 0),
"blender": (2, 7, 3),
"location": "View3D > Add > Mesh > bmesh",
"description": "Adds a new Mesh Object using bmesh",
"warning": "",
"wiki_url": "",
"tracker_url": "",

import bpy
from bpy.types import Operator
from bpy.props import FloatVectorProperty
from mathutils import Vector

edges = []
verts = [(1.0, 0.9999999403953552, -1.0), (1.0, -1.0, -1.0), (-1.0000001192092896, -0.9999998211860657, -1.0), (-0.9999996423721313, 1.0000003576278687, -1.0), (-0.7993143200874329, 7.718172128079459e-07, -1.0), (-0.7839558124542236, -0.1559378057718277, -1.0), (-0.7384703755378723, -0.3058837354183197, -1.0), (-0.6646059155464172, -0.4440747797489166, -1.0), (-0.565200924873352, -0.5652002096176147, -1.0), (-0.44407564401626587, -0.6646053194999695, -1.0), (-0.3058846890926361, -0.7384699583053589, -1.0), (-0.15593880414962769, -0.7839556336402893, -1.0), (-2.6044966716654017e-07, -0.7993143200874329, -1.0), (0.1559382975101471, -0.7839557528495789, -1.0), (0.3058842122554779, -0.738470196723938, -1.0), (0.44407519698143005, -0.6646056175231934, -1.0), (0.5652005672454834, -0.5652005672454834, -1.0), (0.6646056175231934, -0.44407519698143005, -1.0), (0.7384701371192932, -0.3058842122554779, -1.0), (0.7839557528495789, -0.15593838691711426, -1.0), (0.7993143200874329, 6.034655086750718e-08, -1.0), (0.7839556932449341, 0.1559385061264038, -1.0), (0.7384701371192932, 0.30588433146476746, -1.0), (0.6646056175231934, 0.44407519698143005, -1.0), (0.5652005672454834, 0.5652005672454834, -1.0), (0.44407525658607483, 0.6646055579185486, -1.0), (0.30588436126708984, 0.7384701371192932, -1.0), (0.15593849122524261, 0.7839556932449341, -1.0), (0.0, 0.7993143200874329, -1.0), (-0.1559372842311859, 0.7839559316635132, -1.0), (-0.3058832585811615, 0.7384706139564514, -1.0), (-0.4440743327140808, 0.6646061539649963, -1.0), (-0.5651998519897461, 0.5652012825012207, -1.0), (-0.6646050214767456, 0.4440760612487793, -1.0), (-0.7384697794914246, 0.3058851659297943, -1.0), (-0.7839555740356445, 0.15593931078910828, -1.0), (1.0000004768371582, 0.999999463558197, 1.0), (-0.9999999403953552, 1.0, 1.0), (0.9999993443489075, -1.0000005960464478, 1.0), (-1.0000003576278687, -0.9999996423721313, 1.0), (-2.6044966716654017e-07, -0.7993143200874329, 1.0), (-0.15593880414962769, -0.7839556336402893, 1.0), (-0.3058846890926361, -0.7384699583053589, 1.0), (-0.44407564401626587, -0.6646053194999695, 1.0), (-0.565200924873352, -0.5652002096176147, 1.0), (-0.6646059155464172, -0.4440747797489166, 1.0), (-0.7384703755378723, -0.3058837354183197, 1.0), (-0.7839558124542236, -0.1559378057718277, 1.0), (-0.7993143200874329, 7.718172128079459e-07, 1.0), (-0.7839555740356445, 0.15593931078910828, 1.0), (-0.7384697794914246, 0.3058851659297943, 1.0), (-0.6646050214767456, 0.4440760612487793, 1.0), (-0.5651998519897461, 0.5652012825012207, 1.0), (-0.4440743327140808, 0.6646061539649963, 1.0), (-0.3058832585811615, 0.7384706139564514, 1.0), (-0.1559372842311859, 0.7839559316635132, 1.0), (0.0, 0.7993143200874329, 1.0), (0.15593849122524261, 0.7839556932449341, 1.0), (0.30588436126708984, 0.7384701371192932, 1.0), (0.44407525658607483, 0.6646055579185486, 1.0), (0.5652005672454834, 0.5652005672454834, 1.0), (0.6646056175231934, 0.44407519698143005, 1.0), (0.7384701371192932, 0.30588433146476746, 1.0), (0.7839556932449341, 0.1559385061264038, 1.0), (0.7993143200874329, 6.034655086750718e-08, 1.0), (0.7839557528495789, -0.15593838691711426, 1.0), (0.7384701371192932, -0.3058842122554779, 1.0), (0.6646056175231934, -0.44407519698143005, 1.0), (0.5652005672454834, -0.5652005672454834, 1.0), (0.44407519698143005, -0.6646056175231934, 1.0), (0.3058842122554779, -0.738470196723938, 1.0), (0.1559382975101471, -0.7839557528495789, 1.0)]
faces = [(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), (0, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 4, 3), (36, 0, 3, 37), (0, 36, 38, 1), (1, 38, 39, 2), (2, 39, 37, 3), (36, 37, 39, 38, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55), (36, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 40, 38), (28, 27, 57, 56), (29, 28, 56, 55), (27, 26, 58, 57), (30, 29, 55, 54), (26, 25, 59, 58), (31, 30, 54, 53), (25, 24, 60, 59), (32, 31, 53, 52), (24, 23, 61, 60), (33, 32, 52, 51), (23, 22, 62, 61), (34, 33, 51, 50), (22, 21, 63, 62), (35, 34, 50, 49), (21, 20, 64, 63), (4, 35, 49, 48), (20, 19, 65, 64), (5, 4, 48, 47), (19, 18, 66, 65), (6, 5, 47, 46), (18, 17, 67, 66), (7, 6, 46, 45), (17, 16, 68, 67), (8, 7, 45, 44), (16, 15, 69, 68), (9, 8, 44, 43), (15, 14, 70, 69), (10, 9, 43, 42), (14, 13, 71, 70), (11, 10, 42, 41), (13, 12, 40, 71), (12, 11, 41, 40)]

try:

mesh = bpy.data.meshes.new(name="New Object Mesh")
mesh.from_pydata(verts, edges, faces)
# useful for development when the mesh may be invalid.
# mesh.validate(verbose=True)
except:
print("error")

"""Create a new Mesh Object"""
bl_idname = "mesh.cube_hole"
bl_label = "Add Mesh Object"
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):

return {'FINISHED'}

#bl_category = "NN"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
#bl_context = "editmode"
@classmethod
def poll(cls, context):
return (context.mode == 'OBJECT' or context.mode == 'EDIT_MESH' )

def draw(self, context):
layout = self.layout

row = layout.row(align=True)

def register():
bpy.utils.register_module(__name__)

def unregister():
bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()

• Link only answers are discouraged as if the link goes down then so does the answer. Please include some of the steps within the answer itself. – Ray Mairlot Jul 2 '15 at 16:44
• @vvoovv I update the answer with some fast addon template that you can use – yhoyo Jul 2 '15 at 17:49
• @yhoyo I tried your addon. That approach could be very tricky for the general case: concave perimeter, multiple holes – vvoovv Jul 2 '15 at 18:12
• This doesn't appear to answer the question – zeffii Jul 3 '15 at 7:16