# How to draw a PostGIS Polygon with holes into Blender using Python

i would like to draw polygons in Blender. The vertices positions are given as a text in PostGIS format. Example :

POLYGON((0 0, 1 0, 1 1, 0 1, 0 0))


I already came up with a script working pretty well for any polygon without holes. However i also need to draw some polygons with holes. Example (the second polygon defines the hole) :

POLYGON((0 0, 10 0, 10 10, 0 10, 0 0),(1 1, 1 2, 2 2, 2 1, 1 1))


Here is the python script so far to draw any sequence of polygons without holes :

import io
import csv
import bmesh
data="""
0;2;POLYGON((0 0,30 0,30 30,0 30,0 0))
0;2;POLYGON((4 4,26 4,26 26,4 26,4 4))
"""

f = io.StringIO(data)

i = 0
for row in csv_f:
i+=1
if (len(row)>2):
verts = eval('['+row[2].replace(',','),(').replace(' ',',')[8:-1]+']')
bm = bmesh.new()
for v in verts:
bm.verts.new((v[0], v[1], float(row[0])))
bm.faces.new(bm.verts)
bm.normal_update()
me = bpy.data.meshes.new(row[0])
bm.to_mesh(me)
ob = bpy.data.objects.new(row[0], me)
bpy.context.scene.update()


Executing this script into Blender will create two squares, one inside the other :

My question is : how to remove the inner square from the big square (and resulting into a hole)

I tried to Add a Boolean modifier on the big square, applied to the inner square object, but i get a "Cannot execute boolean operation".

Is there any other way doing this from Blender and that can be scripted into Python ?

• Boolean modifier doesn't work on 2d geometry, hence that error - luckily you don't need to rely on the boolean modifier to achieve the desired result. See the answer below – zeffii Oct 13 '15 at 20:20

Polygons can't have holes without a pathway between the hole and the perimeter. ( see: BMesh polygons with holes )

It is perhaps more convenient to use a 2D Curve. They can represent a face with holes easily using a Spline type called 'POLY'. For Example:

Then later Convert to a Polygon based Mesh and let Blender take care of how it arranges the tessellation.

here a script you could use:

import bpy

# weight
w = 1

def MakeFilledPolyLine(objname, curvename, cLists):
curvedata = bpy.data.curves.new(name=curvename, type='CURVE')
curvedata.dimensions = '2D'

odata = bpy.data.objects.new(objname, curvedata)
odata.location = (0,0,0) # object origin

for cList in cLists:
polyline = curvedata.splines.new('POLY')
for num in range(len(cList)):
polyline.points[num].co = cList[num][0], cList[num][1], 0, w

polyline.order_u = len(polyline.points)-1
polyline.use_endpoint_u = True
polyline.use_cyclic_u = True

# using the cyclic switch auto closes the loops, notice i've
# dropped the last coordinates.
vectors = [
[[0,0], [10,0], [10,10], [0,10]],
[[1,1], [1,2], [2,2], [2,1]]
]
MakeFilledPolyLine("NameOfMyCurveObject", "NameOfMyCurve", vectors)


The upside of this is it would handle polygons with no holes, or with any number of holes using the same code.

If you've come this far, I expect it will be a trivial matter to convert the strings of that PostGIS file into the appropriately formatted nested lists for the MakeFilledPolyLine function.

• Thank you so much zeffii for your awsome illustrated answer. This is exacly what i as aiming at. I definitely needs to practice more to get used with those concepts. Your script will be a very nice starting point for this. Now i can parse my PostGIS export and feed your function with it. Next I will probably turn the curve object into a mesh object and extrude it on the z axis. This is so geat :) – yoric Oct 13 '15 at 15:31

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 your polygon with holes.