3
$\begingroup$

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)
csv_f = csv.reader(f, delimiter=';')

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.objects.link(ob)
bpy.context.scene.update()

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

enter image description here

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

enter image description here

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

$\endgroup$
1
  • $\begingroup$ 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 $\endgroup$
    – zeffii
    Oct 13, 2015 at 20:20

2 Answers 2

3
$\begingroup$

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:

enter image description here

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  
    bpy.context.scene.objects.link(odata)  

    for cList in cLists:
        polyline = curvedata.splines.new('POLY')  
        polyline.points.add(len(cList)-1)  
        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.

enter image description here

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.

$\endgroup$
1
  • $\begingroup$ 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 :) $\endgroup$
    – yoric
    Oct 13, 2015 at 15:31
1
$\begingroup$

Simply use bmesh.ops.triangle_fill to accomplish your task:

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.

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

$\endgroup$
1
  • $\begingroup$ i think this should be the accepted answer. $\endgroup$
    – zeffii
    Apr 29, 2022 at 11:39

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .