Check if a poly is a face
Moderators: jesterKing, stiv
Check if a poly is a face
I am writing a custom export script to parse all the objects in a blender file, filter them by name, then check to make sure that they are manifold.
I am using Blender 2.68a. I've created a blender file with some basic 2d and 3d meshes, as well as some that should fail my test criteria.
I've sorted how to iterate through the objects using a for loop and the D.objects iterator, then check for name matches using regular expressions, and then get a mesh from the object using:
mesh = obj.to_mesh(C.scene, True, 'RENDER')
mesh.update(True, True)
then i can get a list of polygons by access mesh.polygons[index] to know if there is a set of vertices with edges that form a polygon
What I can't sort out is how to determine from the python console if a poly is a face or just a poly. Is there a built in function, or what tests can i perform to programmatically determine this?
I apologize if this is a repeat post. Thanks for your help.
I am using Blender 2.68a. I've created a blender file with some basic 2d and 3d meshes, as well as some that should fail my test criteria.
I've sorted how to iterate through the objects using a for loop and the D.objects iterator, then check for name matches using regular expressions, and then get a mesh from the object using:
mesh = obj.to_mesh(C.scene, True, 'RENDER')
mesh.update(True, True)
then i can get a list of polygons by access mesh.polygons[index] to know if there is a set of vertices with edges that form a polygon
What I can't sort out is how to determine from the python console if a poly is a face or just a poly. Is there a built in function, or what tests can i perform to programmatically determine this?
I apologize if this is a repeat post. Thanks for your help.
If you start with a new blender file, delete the camera, lamp, and starter cube, and then add a mesh plane.CoDEmanX wrote:really dunno what you mean, a polygon is a face and vice versa. What's your definition of face? A triangle? A quad? Both of them, so everything which isn't an Ngon?
Then, go down to Mesh->Delete->Face Only.
You will have 4 vertices, 4 edges, and no face. Like, a window frame without any glass in it(except the window frame has no measurable size). But if you access this object, get a mesh from it, and then look at it's children, it will have polygons[0] and it will have 4 edges which connect vertices numbered 0 through 3.
I need to find a way to programatically determine if the bpy.data.object has a face (glass in the window) or if it is only edges and vertices. The polygons structure that it has just seem to be any ngons formed by the edges/vertices, according to what I found in the API reference, and not necessarily a face.
If i am misunderstanding terminology or what the data structure is telling me, please, give me a good smack upside the head and tell me firmly, "no. bad." Then, tell me the right way to do it.
The data structures involved in a mesh are:
* an array of vertices - X, Y, Z, and maybe a W if we are doing homogenous stuff
* a list of edges - an edge is between two points. Each point is represented as an index into the vertex array, so each element is two numbers
* a list of faces - a face is a list of edges, 3 if you are old school and believe the triangle is the One True polygon, 4 if we are talking quads and N if you are into new-fangled n-gons. Each edge in the list is an index into the edge list for this mesh.
If any of these arrays/lists is empty, then that mesh has none of those elements.
* an array of vertices - X, Y, Z, and maybe a W if we are doing homogenous stuff
* a list of edges - an edge is between two points. Each point is represented as an index into the vertex array, so each element is two numbers
* a list of faces - a face is a list of edges, 3 if you are old school and believe the triangle is the One True polygon, 4 if we are talking quads and N if you are into new-fangled n-gons. Each edge in the list is an index into the edge list for this mesh.
If any of these arrays/lists is empty, then that mesh has none of those elements.
Okay, well, via http://www.blender.org/documentation/bl ... 4_release/ theres no face access operator in 2.68a which I'm using. Does that mean polygons are faces now, 1:1? every polygon implies that the face is 'filled'? Or is the actual state of the object being modified when one uses the to_mesh() function, as in, does it create "polygons" even when there is no faces?stiv wrote:The data structures involved in a mesh are:
* an array of vertices - X, Y, Z, and maybe a W if we are doing homogenous stuff
* a list of edges - an edge is between two points. Each point is represented as an index into the vertex array, so each element is two numbers
* a list of faces - a face is a list of edges, 3 if you are old school and believe the triangle is the One True polygon, 4 if we are talking quads and N if you are into new-fangled n-gons. Each edge in the list is an index into the edge list for this mesh.
If any of these arrays/lists is empty, then that mesh has none of those elements.
[/url]
verts and edges are NOT faces, polygons are (triangles, quads and ngons).
Face access goes via .polygons
See my addon, it counts tris, quads and ngons separately:
https://svn.blender.org/svnroot/bf-exte ... _select.py
Face access goes via .polygons
See my addon, it counts tris, quads and ngons separately:
https://svn.blender.org/svnroot/bf-exte ... _select.py
I'm sitting, waiting, wishing, building Blender in superstition...
I'll give it a try on my test dataset. Looks like counting anything with greater than 2 edges should give me a boolean test like i'm looking for.CoDEmanX wrote:verts and edges are NOT faces, polygons are (triangles, quads and ngons).
Face access goes via .polygons
See my addon, it counts tris, quads and ngons separately:
https://svn.blender.org/svnroot/bf-exte ... _select.py
I'll let you know how it turns out. Thanks!
Okay, so, new problem now. I can select all of the faces with 3 or greater verts. then invert. In order to do this, I'm using the following code (frankensteined together from looking at CoDEmanX's script)
I encountered the problem that C.select_objects is always returning 1, even when the active object has faces, and no verts, edges, or faces are selected when it tries to compare C.selected_objects == 0.
So, I researched some, and found that I can in fact just iterate through every edge / vert in each mesh to determine if anything is selected.
This requires code similar to this:
My problem is, when I do this, I havent sorted out how to determine which meshes belong to which bpy.data.objects.
Code: Select all
def check_face(obj):
C.scene.objects.active = obj
if(obj.type == 'MESH'):
bpy.ops.object.editmode_toggle()
bpy.ops.mesh.select_all(action='DESELECT')
#bpy.ops.mesh.select_face_by_sides(number=3, type='EQUAL', extend=False)
bpy.ops.mesh.select_face_by_sides(number=3, type='GREATER', extend=True)
bpy.ops.mesh.select_mode(False, False, type='VERT', action='ENABLE')
bpy.ops.mesh.select_all(action='INVERT')
if(len(C.selected_objects)==0):
return true
return false
So, I researched some, and found that I can in fact just iterate through every edge / vert in each mesh to determine if anything is selected.
This requires code similar to this:
Code: Select all
def test_meshes()
selectededges = 0
selectedverts = 0
for thismesh in bpy.data.meshes:
for thisedge in thismesh.edges:
print(thisedge.select)
if(thisedge.select):
print("\tan edge was selected.")
selectededges += 1
print("Done testing edges.
for thisvert in thismesh.vertices
print(thisvert.select)
if(thisvert.select):
print("\ta vert was selected.")
selectedverts += 1
print("\tThere were " + str(selectededges) + " edges selected in mesh " + thismesh.name )
print("\tThere were " + str(selectedverts) + " verts selected in mesh " + thismesh.name )
selectededges = 0
selectedverts = 0
hm maybe you actually mean to analyse these two cases?

For the left cube, test should return True, for the right (no faces) False?

For the left cube, test should return True, for the right (no faces) False?
Code: Select all
[print(ob.name, len(ob.data.polygons) > 0) for ob in bpy.context.scene.objects]
I'm sitting, waiting, wishing, building Blender in superstition...
That sounds promising. I will have to test it against my data set tomorrow.CoDEmanX wrote:hm maybe you actually mean to analyse these two cases?
For the left cube, test should return True, for the right (no faces) False?
Code: Select all
[print(ob.name, len(ob.data.polygons) > 0) for ob in bpy.context.scene.objects]
You are correct in your understanding of my desired behavior for those two test cubes. But i need it to also fail if there are edges that do not belong to any polygons. I guess i'll just have to iterate through every edge and make sure they belong to a poly.
Thanks!
Hm dunno if there's a faster builtin way (other than using select loose operator), but should work:
Code: Select all
import bpy, bmesh
for ob in bpy.context.scene.objects:
if ob.type != 'MESH':
continue
bm = bmesh.new()
bm.from_object(ob, bpy.context.scene)
if len(bm.faces) > 0 and 0 not in (len(e.link_faces) for e in bm.edges):
print(ob.name, "is valid")
else:
print(ob.name, "has errors")
I'm sitting, waiting, wishing, building Blender in superstition...
So far, looks perfect against my minimal test dataset. I've got to look at some of my more complex datasets to verify there arent any other gotchas that I need to handle, but you've saved me a lot of time, and i've learned a fair bit. Thanks a bunch!CoDEmanX wrote:Hm dunno if there's a faster builtin way (other than using select loose operator), but should work:
Code: Select all
import bpy, bmesh for ob in bpy.context.scene.objects: if ob.type != 'MESH': continue bm = bmesh.new() bm.from_object(ob, bpy.context.scene) if len(bm.faces) > 0 and 0 not in (len(e.link_faces) for e in bm.edges): print(ob.name, "is valid") else: print(ob.name, "has errors")
Thanks so much. I'm plowing through this now.CoDEmanX wrote:it is easily overlooked, yet simple:
bpy.data.filepath
As long as you work with an unsaved blend, it will be a blank string
I followed a tutorial that uses the self, context arguments (for it to be an addon). I wondered, can I call my functions with self from the python console?
i.e. function_name(bpy.some.data.substructure.self, bpy.context)