If I have a mesh object, and the mesh data is made up of several disconnected islands of faces, and using Python I want to evaluate each island to check if it matches certain criteria, and if it does, store that island's median coordinate in a variable... how can that be achieved?
The example object in this screenshot has two circles I want to match. Each circle has 13 verts, 12 faces (which are all tris), and a total area of approximately 3. So if an island matches those criteria, we can consider it to qualify as the kind of circle we are after. Their medians would be [0,0,0]
(the world center), and [0,3,0]
(the 3D cursor location).
Now let's say we don't know how many such circles there will be in an object, or even how many objects to expect, and we have to identify each circle center programmatically and add those coords to a list. The fun begins!
I have solved some pieces of this puzzle already. I have written a simple script for finding the area of selected faces (as long as they're all tris, which they will be). Here is that script:
import bpy
import bmesh
obj = bpy.context.active_object
# make sure it's a mesh object
if obj.type != 'MESH':
print('Error: Object is not a mesh object!')
else:
bpy.ops.object.mode_set(mode='EDIT')
me = obj.data # mesh data
bm = bmesh.from_edit_mesh(me)
ta = 0.0 # total area
print('\n==== Area of selected faces ====')
for f in bm.faces:
if f.select: # selected faces only
print('Face ' + str(f.index) + ' area is ' + str(f.calc_area()))
ta = ta + f.calc_area() # add to total
print('Total area is ' + str(ta))
I have also put together a script for finding the median of a set of vertices. I'll include it too for reference, although in its present form it targets the verts of an object's Vertex Group, not selected verts. Needs minor modifications:
import bpy
import statistics
context = bpy.context
scene = context.scene
act_obj = context.active_object # get active object
v_x = []
v_y = []
v_z = []
def cursor_to_vgroup(mesh_obj, vgroup_name):
# This is an Object with a Mesh, see if it has the supported group name
groupIndex = -1
for i in range(0, len(mesh_obj.vertex_groups)):
group = mesh_obj.vertex_groups[i]
if group.name == vgroup_name:
groupIndex = i
# Now access the vertices that are assigned to this group
mesh = mesh_obj.data
for v in mesh.vertices:
for vertGroup in v.groups:
if vertGroup.group == groupIndex:
v_global = mesh_obj.matrix_world @ v.co # global vertex coordinates
v_x.append(v_global.x)
v_y.append(v_global.y)
v_z.append(v_global.z)
cur_x = statistics.mean(v_x)
cur_y = statistics.mean(v_y)
cur_z = statistics.mean(v_z)
scene.cursor.location = [cur_x, cur_y, cur_z]
cursor_to_vgroup(act_obj, 'Group')
And finally, I've found an interesting script someone wrote to get linked faces, but I'm not sure how / if I can customize it to sort the vertices into islands. And that's where I'm stuck - trying to figure out how to sort the geometry data into islands, so the island geometry can be checked for matches.
Would any Python wizards care to lend a hand?
.blend file contains the mesh object in the screenshot, and the area-getting script.