# List of vertices per face

I'm trying to write a script in blender that will take an object and save it to PostgreSQL db. All I need to do is to get the list of vertices per face in a clockwise manner (how postgis knows inside vs outside). I am starting with a simple cube example. The syntax I need for a cube follows:

NOTE: the first node is repeated to close the face

SELECT ST_GeomFromText('POLYHEDRALSURFACE Z(
((0 0 0, 0 0 1, 0 1 1, 0 1 0, 0 0 0)),
((0 0 0, 0 1 0, 1 1 0, 1 0 0, 0 0 0)),
((0 0 0, 1 0 0, 1 0 1, 0 0 1, 0 0 0)),
((1 1 0, 1 1 1, 1 0 1, 1 0 0, 1 1 0)),
((0 1 0, 0 1 1, 1 1 1, 1 1 0, 0 1 0)),
((0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)) )');


So far I can access a list of faces and a list of vertices, how can I get a list of vertices per face (clockwise) so it prints as above. Here is my current effort:

import bpy

ob = bpy.context.active_object
me = ob.data
bm = bmesh.from_edit_mesh(me)

for f in bm.faces:
if f.select:
print(f.index)
for v in bm.verts:
print(v.co.x, v.co.y, v.co.z)


### @@@### EDIT ###@@@

OK, so here is where I am now, getting close. I've included rounding to make it easier to understand.

print("SELECT ST_GeomFromText('POLYHEDRALSURFACE Z( ")
#print("="*40) # printing marker
for polygon in current_obj.data.polygons:
verts_in_face = polygon.vertices[:]
#print("face index", polygon.index, end=" ")
#print("normal", polygon.normal)
print ("((", end=" ")
#
for vert in verts_in_face:

print(
str(round(current_obj.data.vertices[vert].co.x, 1)),
str(round(current_obj.data.vertices[vert].co.y, 1)),
str(round(current_obj.data.vertices[vert].co.z, 1)),",", end=" ")
print (")),")


So it still needs the first vertex to be repeated and if it is the last 'print' exclude the last commas. I have commented out the normals indicator incase extra needs to be added to ensure the clockwise construction direction. Result:

(( 1.0 1.0 0.0 , 1.0 0.0 0.0 , 0.0 0.0 0.0 , 0.0 1.0 0.0 , )),
(( 1.0 1.0 1.0 , 0.0 1.0 1.0 , 0.0 0.0 1.0 , 1.0 -0.0 1.0 , )),
(( 1.0 1.0 0.0 , 1.0 1.0 1.0 , 1.0 -0.0 1.0 , 1.0 0.0 0.0 , )),
(( 1.0 0.0 0.0 , 1.0 -0.0 1.0 , 0.0 0.0 1.0 , 0.0 0.0 0.0 , )),
(( 0.0 0.0 0.0 , 0.0 0.0 1.0 , 0.0 1.0 1.0 , 0.0 1.0 0.0 , )),
(( 1.0 1.0 1.0 , 1.0 1.0 0.0 , 0.0 1.0 0.0 , 0.0 1.0 1.0 , )),

• Maybe you should be looking at loops rather than vertices? Note they are ordered anti-clockwise, so lists would need reversing. – Robin Betts Nov 1 '19 at 9:18

This way starts with mesh loops rather than vertices, because, although it seems true, I can find no guarantee that polygons list their vertices in order with respect to their normals. (Maybe someone can correct me on that.) So there's a bit of extra wrangling.

As is typical of 3D applications, loops are ordered anticlockwise with respect to forward-facing normals, so have to be reversed, and the (formerly) last element repeated.

import bpy

me = bpy.context.object.data

# per-poly lists of loop indices
pli = (p.loop_indices for p in me.polygons)
# .. to per-poly lists of vertex indices
pvi = ([me.loops[l].vertex_index for l in ll] for ll in pli)
# ..to per-poly lists of vertices
p_verts = ([me.vertices[id] for id in idl] for idl in pvi)

# floating point precision
prec = 2

co_lists =[]

for v_list in p_verts:
co_str = '    (('
co_strs = []
for v in [*v_list[::-1],v_list[-1]]:
co_strs.append(f'{v.co[0]: .{prec}f} '
f'{v.co[1]: .{prec}f} '
f'{v.co[2]: .{prec}f}')
co_str += ', '.join(co_strs)
co_str += '))'
co_lists.append(co_str)

DBstr =  "SELECT ST_GeomFromText('POLYHEDRALSURFACE Z(\n"
DBstr += ",\n".join(co_lists)
DBstr += " )');"

print(DBstr)


If nothing else, maybe you can pick the slice [::-1]... [-1] out of it for reversing and repeating your elements, and/or the str.join() for dealing with your extra terminal comma.

• Thank you, I've been amending this because I get the error  File "\Text", line 21 co_strs.append(f"{v.co[0]: .{prec}f} "+ it does not like the final double quotation mark. – Spatial Digger Nov 2 '19 at 9:50
• I'm in edit mode and using it on the default cube. – Spatial Digger Nov 2 '19 at 9:52
• @SpatialDigger yeah f string formatting f"{foo}" needs python 3.6 or greater. Both 2.8 and 2.79x are shipped with at least 3.6.x. What version of blender are you using. For python 3.5 or prior use "%3.1f" % foo for example. RobinBetts pretty sure the face verts are in winding order as it has come up before re the "bowtie" effect for poorly ordered quads. (Definitely isn't arbitrary) – batFINGER Nov 2 '19 at 13:19
• @batFINGER I was just reading up on the append function and saw that stated about the f-string, I'll see if I can use one of the other methods. – Spatial Digger Nov 2 '19 at 13:24
• I upgraded blender, the script works, although wrapping it in a PostGIS volume query gives a result of -1 rather than 1. Does this mean the construction direction is backwards? SELECT ST_Volume(ST_MakeSolid(ST_GeomFromText('POLYHEDRALSURFACE Z( – Spatial Digger Nov 2 '19 at 13:41