12
$\begingroup$

With Object > Transform > Origin to Geometry, an object's origin is moved to its geometry's center. How can I get this center in script? I don't want to move its origin, I just need to get its center.

$\endgroup$

2 Answers 2

14
$\begingroup$

Here's a low level way to calculate the bounding box center of an object:

import bpy

o = bpy.context.object
vcos = [ o.matrix_world * v.co for v in o.data.vertices ]
findCenter = lambda l: ( max(l) + min(l) ) / 2

x,y,z  = [ [ v[i] for v in vcos ] for i in range(3) ]
center = [ findCenter(axis) for axis in [x,y,z] ]

print( center )

EDITED:

@batFINGER proposed a much shorter and more efficient way to calculate the bounding box center (thanks!). Multiplication by the object's world matrix gives a global coordinate:

import bpy
from mathutils import Vector
o = bpy.context.object
local_bbox_center = 0.125 * sum((Vector(b) for b in o.bound_box), Vector())
global_bbox_center = o.matrix_world * local_bbox_center

It will find the center of the active object. The bounding box center (or "range" center) is calculated as the center between the minimum and maximum value in each axis.

It does not give you the same result that origin to geometry or origin to center of mass gives, but it is the center.

enter image description here

$\endgroup$
12
  • $\begingroup$ I don't get it : if an object is set "origin to geometry" and if the object location is (0, 0, 0), this calculation will return (0, 0, 0) ? $\endgroup$
    – lemon
    Aug 31, 2016 at 12:12
  • $\begingroup$ Origin to geometry doesn't move the origin to the absolute center, for that you have the origin to center of mass option. $\endgroup$
    – TLousky
    Aug 31, 2016 at 12:19
  • 1
    $\begingroup$ is this the same as bbox_centre = 1 / 8 * sum((Vector(b) for b in ob.bound_box), Vector()) $\endgroup$
    – batFINGER
    Aug 31, 2016 at 13:03
  • 2
    $\begingroup$ Can do the matrix mult once ob.matrix_world * (1 / 8 * sum((Vector(b) for b in ob.bound_box), Vector())) ie matrix_world * local_centre Which gives you the global coord of the centre of bounding box. The local centre is what you would subtract from each vert.co to change the origin to bbox centre. $\endgroup$
    – batFINGER
    Aug 31, 2016 at 14:39
  • 5
    $\begingroup$ TypeError: Element-wise multiplication: not supported between 'Matrix' and 'Vector' types so global_bbox_center = o.matrix_world @ local_bbox_center replace Star multiply with AT @ matrix multiply. $\endgroup$ Oct 11, 2021 at 2:26
7
$\begingroup$

You can set the cursor to the object position, then set the origin to geometry, take this position and set back the origin to the cursor.

cursorLoc = bpy.context.scene.cursor_location.copy()
bpy.context.scene.cursor_location = obj.location
bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
loc = obj.location.copy()
bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
bpy.context.scene.cursor_location = cursorLoc

Here loc contains the geometry center position.

Edit : following some tests, it seems that 'origin to geometry center' is the average value of the vertices coordinates, so:

x, y, z = [ sum( [v.co[i] for v in obj.data.vertices] ) for i in range(3)]

count = float(len(obj.data.vertices))

center = obj.matrix_world * (Vector( (x, y, z ) ) / count )

For Blender 3.2 (use ops):

import bpy


def get_objcenter(obj):
    # save cursor location
    cursorLoc = bpy.context.scene.cursor.location.copy()
    #To undo this later, the cursor must be aligned with the location of the object.
    bpy.context.scene.cursor.location = obj.location
    # Align the object's origin with the object's center.
    bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY')
    # Master the center vector
    loc = obj.location.copy()
    # Align the object's origin with the object's location for later undo
    bpy.ops.object.origin_set(type='ORIGIN_CURSOR')
    # Undo the cursor location
    bpy.context.scene.cursor.location = cursorLoc
    
    return loc

# test
obj= bpy.context.object
print(get_objcenter(obj))

For Blender 3.2 (use mathutils):

import bpy
from mathutils import Vector

def get_objcenter(obj):
    # Total value of each vertex
    x, y, z = [ sum( [v.co[i] for v in obj.data.vertices] ) for i in range(3)]
    # number of vertices
    count = float(len(obj.data.vertices))
    # Divide the sum of each vector by the number of vertices
    # And make the position a world reference.
    center = obj.matrix_world @ (Vector( (x, y, z ) ) / count )
    
    return center

# test
obj = bpy.context.object
print(get_objcenter(obj))
$\endgroup$
6
  • $\begingroup$ That's what I think of at first but it's more of a work around. Thanks anyway. $\endgroup$
    – user2100
    Aug 31, 2016 at 11:22
  • $\begingroup$ @animel, yes... did not found any accurate definition of the center calculation $\endgroup$
    – lemon
    Aug 31, 2016 at 11:28
  • 7
    $\begingroup$ lemon you can (1.0 / count) * sum([v.co for v in verts], Vector()) $\endgroup$
    – batFINGER
    Aug 31, 2016 at 12:46
  • $\begingroup$ @batFINGER, definitively Python is a different way of thinking than other languages I know : ). Thanks ! $\endgroup$
    – lemon
    Aug 31, 2016 at 12:51
  • $\begingroup$ No idea why average coordinate is the center of the object but it's seems to be the way that Blender does it with "Origin to Geometry". Previously tried to use bounding box method but results didn't match with "Origin to Geometry" $\endgroup$ May 21, 2023 at 12:17

You must log in to answer this question.