# 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.

## 3 Answers

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. Jul 2, 2015 at 17:41
• How would you script that mesh.fill() for the general case: concave perimeter, multiple concave holes? Jul 2, 2015 at 17:42
• I had to switch off the computer for an electric storm, maybe I can answer later. Jul 3, 2015 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": "",
"category": "Add Mesh"}

import bpy
from bpy.types import Operator
from bpy.props import FloatVectorProperty
from bpy_extras.object_utils import AddObjectHelper, object_data_add
from mathutils import Vector

def add_object(self, context):
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)
object_data_add(context, mesh, operator=self)
except:
print("error")

class OBJECT_OT_add_object(Operator, AddObjectHelper):
"""Create a new Mesh Object"""
bl_idname = "mesh.cube_hole"
bl_label = "Add Mesh Object"
bl_options = {'REGISTER', 'UNDO'}

def execute(self, context):

add_object(self, context)

return {'FINISHED'}

class OBJECT_OT_add_objectPanel(bpy.types.Panel):
#bl_category = "NN"
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
#bl_context = "editmode"
bl_label = "ADD_OBJ"
@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)
row.operator(OBJECT_OT_add_object.bl_idname) #THE OPERATOR

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. Jul 2, 2015 at 16:44
• @vvoovv I update the answer with some fast addon template that you can use Jul 2, 2015 at 17:49
• @yhoyo I tried your addon. That approach could be very tricky for the general case: concave perimeter, multiple holes Jul 2, 2015 at 18:12
• This doesn't appear to answer the question Jul 3, 2015 at 7:16