-
Not sure if this is going to get you the selection that you need, but if you select one face and then press SHIFT + G you will see a menu called "Select Similar" try with one option and see if that works for you – Emir May 11 '21 at 12:54
-
@Emir nah, none of those work – Timur Nizamiev May 11 '21 at 13:04
3 Answers
This may be a naive answer, I'm no coder, but is there anything wrong with letting BMLoop.is_convex do this for you?
(Starting from Edit Mode):
import bpy
import bmesh
obj = bpy.context.edit_object
me = obj.data
bm = bmesh.from_edit_mesh(me)
bm.faces.active = None
for face in bm.faces:
face.select_set(False)
for loop in face.loops:
if not loop.is_convex:
face.select_set(True)
break
bmesh.update_edit_mesh(me, False)
- 76,260
- 8
- 77
- 190
-
Looks good to me. Could use
face.select_set(not any(loop.is_convex for loop in face.loops))as I'm led to believe it is quicker, although can't see it being any more than an bee's diaphragm. – batFINGER May 11 '21 at 17:35 -
@batFINGER there ya go! I knew there would be a snappier way of putting it! I'll just leave it in your comment. – Robin Betts May 11 '21 at 17:42
-
Good find, will make that edge angle answer easier too, https://blender.stackexchange.com/questions/203249/face-edges-angle-python in that can simply use
edge.angle(otheredge)and add pi if not convex. Consider adding as answer there too. Gives me that ",,,Whale oil beef hooked how did I miss thaaaaat" feeling. – batFINGER May 11 '21 at 17:50 -
@batFINGER wilco, when I have some time to grind through my incredibly slow beginner's testing-and-looking-stuff-up, unless you go in first. I can't remember when I spotted that property.. it was in a completely different context. – Robin Betts May 11 '21 at 18:01
-
1cool, this is kind of odd to me that although there is a parameter that straightly tells you, that the face is convex , there is no just button in GUI for common users – Timur Nizamiev May 11 '21 at 18:06
-
@Timur Agreed. It would seem a very obvious 'By Trait', or 'Clean Up'. – Robin Betts May 11 '21 at 18:08
ok, so I made a modification of this script: Face edges angle - python
I simply putted some selection commands at the end. it will do the work (you need to select the faces you want to check)
# based on the script by batFINGER: https://blender.stackexchange.com/questions/203249/face-edges-angle-python
import bpy
from mathutils import Matrix, Vector
from bpy import context
from math import degrees, atan2, pi
import bmesh
# project into XY plane,
up = Vector((0, 0, 1))
ob = context.object
me = ob.data
bm = bmesh.from_edit_mesh(me)
def edge_angle(e1, e2, face_normal):
b = set(e1.verts).intersection(e2.verts).pop()
a = e1.other_vert(b).co - b.co
c = e2.other_vert(b).co - b.co
a.negate()
axis = a.cross(c).normalized()
if axis.length < 1e-5:
return pi # inline vert
if axis.dot(face_normal) < 0:
axis.negate()
M = axis.rotation_difference(up).to_matrix().to_4x4()
a = (M @ a).xy.normalized()
c = (M @ c).xy.normalized()
return pi - atan2(a.cross(c), a.dot(c))
selected_faces = [f for f in bm.faces if f.select]
bpy.ops.mesh.select_all(action='TOGGLE')
for f in selected_faces:
edges = f.edges[:]
#print("Face", f.index, "Edges:", [e.index for e in edges])
edges.append(f.edges[0])
for e1, e2 in zip(edges, edges[1:]):
angle = edge_angle(e1, e2, f.normal)
#print("Edge Corner", e1.index, e2.index, "Angle:", degrees(angle))
if degrees(angle) >= 180:
f.select_set(True)
- 151
- 9
-
1Could possibly do something like
f.select_set(any(edge_angle(e1, e2, f.normal) > pi for e1, e2 in zip(edges, edges[1:]))– batFINGER May 11 '21 at 16:44 -
I see I'm late, though I ended up with simpler code:
import bpy
tolerance = 0 # increase to something like .01 or .1 to ignore small concavities
bpy.ops.object.mode_set(mode = 'EDIT')
bpy.ops.mesh.select_mode(type="FACE")
bpy.ops.mesh.select_all(action = 'DESELECT')
bpy.ops.object.mode_set(mode = 'OBJECT')
me = bpy.context.active_object.data
me.calc_loop_triangles()
poly_i_to_tris = {}
for tri in me.loop_triangles:
poly_i_to_tris.setdefault(tri.polygon_index, []).append(tri)
for i, tris in poly_i_to_tris.items():
try:
t1, t2 = tris
except ValueError:
continue # not a quad
dist = (t1.center - t2.center).length
tolerance = dist # makes tolerance relative
ray_len = dist/2 # making sure to not overshoot, but I don't think it would be possible
test1 = t1.center + t1.normalray_len
test2 = t2.center + t2.normal*ray_len
test_dist = (test1 - test2).length
if test_dist < dist - tolerance:
# concave
me.polygons[i].select = True
bpy.ops.object.mode_set(mode = 'EDIT')
- 36,563
- 3
- 30
- 99
-
If you decide to remove
ray_len, then usedistinstead of not multiplying the normals - or otherwise you will lose the relativity oftolerance. – Markus von Broady May 11 '21 at 14:28 -
Reading through the other answer's code, I now realize I misunderstood the question. What I thought of a concave quad, is a quad triangulated in such way, that the diagonal of the quad (the edge created by tessellation) falls down along the face normal. You can clearly see it in attached .blend file. – Markus von Broady May 11 '21 at 14:36
-
Wondered about that, Would you say this is looking for non-coplanar faces? – batFINGER May 11 '21 at 16:06
-
@batFINGER in short I'm checking if two segments starting at centers of triangles and going outside along normals, end up being closer than those centers. If so, those triangles look at each-other, and the quad is "concave". If the opposite is the case, the triangles are upset at each-other, and the quad is "convex". Otherwise the quad is "flat" or coplanar. (in my script I just select the "concave" because that was the question, but you could differentiate all three, and e.g. color the cube dynamically) – Markus von Broady May 11 '21 at 16:10
-
See also https://blender.stackexchange.com/questions/102440/left-right-test – batFINGER May 11 '21 at 16:33
-
1Also similarly to @RobinBetts answer above, looks like this test could be achieved very simply with
BMEdge.is_convex. – batFINGER May 11 '21 at 17:41 -
@batFINGER thanks, I didn't know of
is_convex. So the alternative to my solution would be to find which edge is added in tessellation and check if it's convex. Though this wouldn't allow for tolerance or 3-way split into convex/flat/concave, so I'll leave my answer as is. As for left-right-test, you overestimate my IQ. – Markus von Broady May 11 '21 at 18:54


