Better style for getCenterPoint() function

I’ve been programming c and php long enough to know that this code is not good. It’s works fine, but I feel like I could do it the python way in a couple lines. I pass in a list of vertices and I want to find the center point. Is there a bpy function for this, or a cleaner way.


def getCenterPoint(self,verts):
        vertcount = 0
        vertsum = [0,0,0]
        for v in verts:
            vertcount = vertcount + 1
            vertsum[0] = vertsum[0] + v.co[0]
            vertsum[1] = vertsum[1] + v.co[1]
            vertsum[2] = vertsum[2] + v.co[2]
        
        if (vertcount > 0):                               
            vertsum[0] = vertsum[0] / vertcount
            vertsum[1] = vertsum[1] / vertcount
            vertsum[2] = vertsum[2] / vertcount
        
        return vertsum


If you wanna get really pythonic:

import bpy
from mathutils import Vector
from functools import reduce

ob = bpy.context.object
me = ob.data
verts = me.vertices

center = reduce(Vector.__add__, (v.co for v in verts))

try:
    bpy.context.scene.cursor_location = ob.matrix_world * (center / len(verts))
except ZeroDivisionError:
    print("%s has no vertices!" % me.name)

A bit less fancy would be:

import bpy
from mathutils import Vector

ob = bpy.context.object
me = ob.data
verts = me.vertices
assert len(verts) != 0, "%s has no vertices!" % me.name

center = Vector()
for v in verts:
    center += v.co

bpy.context.scene.cursor_location = ob.matrix_world * (center / len(verts))

And to stay as close as possible to your approach:

def get_center_point(self, verts):
    
    vertcount = len(verts)
    vertsum = [0, 0, 0]
    
    for v in verts:
        vertsum[0] += v.co[0]
        vertsum[1] += v.co[1]
        vertsum[2] += v.co[2]
    
    if (vertcount > 0):
        vertsum[0] /= vertcount
        vertsum[1] /= vertcount
        vertsum[2] /= vertcount
    
    return vertsum

That’s awesome! Thank you. I changed the function signature to pass in the object and then re-used center to hold the center instead of printing it, and returned it. It looks so much nicer. I added a comment in the code thanking and crediting you. The comments don’t line up in the code tags


def getCenterPoint(self,verts,myobj):
        center = reduce(Vector.__add__, (v.co for v in verts))       #Thanks to CoDEmanX 
        try:                                                                                 #For this great snippet
            center = myobj.matrix_world * (center / len(verts))
        except ZeroDivisionError:
            print("%s has no vertices!" % myobj.me.name)
        return center

thanks and you’re welcome :slight_smile:

Is myobj a regular Object reference?
print("%s has no vertices!" % myobj.me.name)

Shouldn’t it be myobj.data.name?

Ahh, yes, thank you. Change made. It was a runtime error, and I never have a divide by zero condition.

Here’s my latest function, which works, but it makes me sad to look at. :frowning: Any ideas on improvement? The last three lines should be accomplished in 1 line, something like:
total /= len(myverts)


def getVariance(self,myverts,myobj):
        center = self.getCenterPoint(myverts,myobj)
        print(center)
        total = [0.0,0.0,0.0]
        for v in myverts:
            total[0] += pow((v.co.x - center[0]),2)
            total[1] += pow((v.co.y - center[1]),2)
            total[2] += pow((v.co.z - center[2]),2)
            foo += 1
        
        total[0] = math.sqrt(total[0]) / len(myverts)
        total[1] = math.sqrt(total[1]) / len(myverts)
        total[2] = math.sqrt(total[2]) / len(myverts)

        return total[0];

Vector does not have a pow method, but since you seem to be interested into X variance only, it is simple to do:

import bpy
import math
from functools import reduce
from mathutils import Vector

def get_center_point(verts, ob):
    
    if len(verts) < 1:
        print("%s has no vertices, returning object origin" % ob.data.name)
        return ob.matrix_world.translation
        
    center = reduce(Vector.__add__, (v.co for v in verts))
    return ob.matrix_world * (center / len(verts))

def get_variance(verts, ob):
    
    center = get_center_point(verts, ob)
    try:
        return sum((v.co.x - center.x) ** 2 for v in verts) ** 0.5 / len(verts)
    except ZeroDivisionError:
        # suppress exception and let function return without value (=None)
        pass
    
ob = bpy.context.object
verts = ob.data.vertices

center = get_center_point(verts, ob)
bpy.context.scene.cursor_location = center

print("Center:", center)
print("Variance (X):", get_variance(verts, ob))


That’s great. It helps me a lot to look at good code, and make changes to it. I appreciate your time, and will make a comment in this function as well crediting and thanking you. Thanks again CoDEmanX.