Calculating center point of all mesh in scene

Hello, I’m trying to calculate the center point of all mesh objects in scene and this is what I’m doing right now.

import bpy
from mathutils import Vector

def calcBoundingBox(mesh_objs):
    cornerApointsX = []
    cornerApointsY = []
    cornerApointsZ = []
    cornerBpointsX = []
    cornerBpointsY = []
    cornerBpointsZ = []
    
    for ob in mesh_objs:
        ob.select_set(True)
        bpy.context.view_layer.objects.active = ob
        bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)
        bbox_corners = [ob.matrix_world @ Vector(corner)  for corner in ob.bound_box]
        cornerApointsX.append(bbox_corners[0].x)
        cornerApointsY.append(bbox_corners[0].y)
        cornerApointsZ.append(bbox_corners[0].z)
        cornerBpointsX.append(bbox_corners[6].x)
        cornerBpointsY.append(bbox_corners[6].y)
        cornerBpointsZ.append(bbox_corners[6].z)
        
    minA = Vector((min(cornerApointsX), min(cornerApointsY), min(cornerApointsZ)))
    maxB = Vector((max(cornerBpointsX), max(cornerBpointsY), max(cornerBpointsZ)))

    center_point = Vector(((minA.x + maxB.x)/2, (minA.y + maxB.y)/2, (minA.z + maxB.z)/2))
    dimensions =  Vector((maxB.x - minA.x, maxB.y - minA.y, maxB.z - minA.z))
    
    return center_point, dimensions

mesh_objs = [obj for obj in bpy.data.objects if obj.type == 'MESH'] 
center_point, dimensions = calcBoundingBox(mesh_objs)

It’s able to handle small amount(<2000) of mesh objects, but it freezes when there’re too many(-1mil) small mesh objects. Any idea how to improve it? Here’s an example w lots of mesh objects, script attached to the .blend file.

Hi! Just trying to figure out where stuff might go slow - We would need the linear for loop to go through the whole scene - or maybe we can optimize it to O(log N) using some form of binary tree structure (I am not sure - but it is a valid idea you can try) or maybe even octrees.

Deselecting the objects after working with it, seems to speed it up about one fourth the time.
Average times per mesh object before changes: 0.046002147197723386 sec
After changes average: 0.018564000129699706 sec
Obviously this isn’t too fast if you are doing this operation a million times - just do the math :slight_smile:

I will try and see if there are simpler ways than making octrees to optimize the process.

1 Like

The main areas where I think things go slow is at

    ob.select_set(True)
    bpy.context.view_layer.objects.active = ob
    bpy.ops.object.transform_apply(location=False, rotation=True, scale=False)

Is there a reason why you would want a copy of the object? Because as far as my experience goes in optimizing stuff - not much, I am just a student - copying stuff especially deep copies take a lot of time.

Removing them is extremely fast as a million instructions should be on any modern PC.

1 Like

the active object assignment is a reference, not a deep copy.

1 Like

Interesting…but those three lines bloat up the time taken by at least 3 orders. As without them, the average time step is around 6e-5 sec. Not sure if that reference assignment itself takes time.

1 Like

Those code are from my previous approach to join the objects together then use bounding box center. It causes problems in a lot of scenes for some reason, so I dropped it. I think Blender freezes with or without those lines, I can double check.

I tried a profile (but broke the loops on 200 objects): https://developer.blender.org/F9904012
Load the JSON on https://github.com/jlfwong/speedscope

Well. Not too sure, but without them it seems quite fast on my PC. This is the code that I used - I cut down on the code you had after that.

# Create a blend file for each obj in current directory
import bpy
from os.path import dirname, basename, join, exists
import glob, os
from mathutils import Vector
from time import time


def calcBoundingBox(mesh_objs):
    cornerApointsX = []
    cornerApointsY = []
    cornerApointsZ = []
    cornerBpointsX = []
    cornerBpointsY = []
    cornerBpointsZ = []
    
    for ob in mesh_objs:
        last_time = time()
        bbox_corners = [ob.matrix_world @ Vector(corner) for corner in ob.bound_box]
        cornerApointsX.append(bbox_corners[0].x)
        cornerApointsY.append(bbox_corners[0].y)
        cornerApointsZ.append(bbox_corners[0].z)
        cornerBpointsX.append(bbox_corners[6].x)
        cornerBpointsY.append(bbox_corners[6].y)
        cornerBpointsZ.append(bbox_corners[6].z)
        
    minA = Vector((min(cornerApointsX), min(cornerApointsY), min(cornerApointsZ)))
    maxB = Vector((max(cornerBpointsX), max(cornerBpointsY), max(cornerBpointsZ)))

    center_point = Vector(((minA.x + maxB.x)/2, (minA.y + maxB.y)/2, (minA.z + maxB.z)/2))
    dimensions =  Vector((maxB.x - minA.x, maxB.y - minA.y, maxB.z - minA.z))
    
    return center_point, dimensions
    

mesh_objs = [obj for obj in bpy.data.objects if obj.type == 'MESH']

last_time = time()
center_point, dimensions = calcBoundingBox(mesh_objs)
print((time() - last_time) / len(mesh_objs))

This was the time I got per iteration - 2.747326500330989e-05 sec. Even for a million iteration this should run decently well - around 30 sec.

1 Like

What will you do with the center of the bounding boxes after you calculate them? Depending on that, maybe you can use bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS') which works on all selected objects at once and sets the origin to the center of the bounding box for each.