Object Centroid Script - works on all objects based on bounding box cen

VolumeCentroid Won’t work with curves.

Is there a script or option to get it work based on bounding box. Thanks

The Gumball center should be the bb center of selected curves… Or make a bounding box and use volume centroid on that.

Hi Mitch thank you for writing on this.

I mean a command that would create VolumeCentroids despite the object as with planar curves this approach would not work.

Just a Center/Centroid function for all — no concept of Area Centroid or Volume Centroid - just automatic based on context.

Thank you

The problem is that all of these are potentially different.

A closed surface/polysurface can have

  • a volume centroid
  • an area centroid
  • a bounding box center

All three of those can be different points.

An open surface/polysurface can have

  • an area centroid
  • a bounding box center

Both of those can be different points.

An planar curve can have

  • an area centroid
  • a bounding box center
    And if it is a polyline it can also have
  • the average of its vertices
  • the average of its edges

All of those can be different points.

An arbitrary 3D curve can have

  • a bounding box center

So you can see that the only one that is common to all of the above is the bounding box center - which is what Gumball uses. And for the objects that have multiple possibilities - practically all of the above - which method should Rhino choose?

Edit - if you want a simple script you can put on an alias to create a point at selected objects’ bounding box center, here you go:

import rhinoscriptsyntax as rs

obj_ids=rs.GetObjects("Select objects for bounding box centroid",preselect=True)
if obj_ids:
    bb=rs.BoundingBox(obj_ids)
    if bb: rs.AddPoint((bb[0]+bb[6])/2)
1 Like

Mitch! So good, we have to mention for newbies to take the script data and paste them into a text file and name it ObjectCentroid.py and move it into the scripts folder and bind an Alias to it as OC

Thanks a lot for this works like a charm!

Well, there are a number of ways to install and run scripts:
https://wiki.mcneel.com/rhino/macroscriptsetup

Well, that might be a bit of a misnomer, as it doesn’t find the object centroid, it only finds the bounding box center (as mentioned above).

1 Like

Hey Mitch, as always — sharp as a katana.

Hi everyone,

Does someone know why you can’t properly compute the Boundingbox’s center of a block or of an object if it is inside a block? Is this a new Rhino8 issue?

For example: below is a snapshot from a file with circles in blocks and outside of blocks. The centroids are incorrectly placed for the blocks and the objects inside blocks. You can see the 4 centroid (2 blocks + 2 circles in the blocks) floating near the World origin. The “free” circles have correct centroid dots.

Below is the script I used:

#! python 3

import rhinoscriptsyntax as rs

def loopBlock(block):
    objectsInBlock = rs.BlockObjects(rs.BlockInstanceName(block))

    for obj in objectsInBlock:
        if rs.ObjectType(obj) != 4096:
            action(obj)
        else:
            loopBlock(obj)

def action(object):
    bb=rs.BoundingBox(object)
    if bb: center = (bb[0]+bb[6])/2
    rs.AddTextDot("Centroid!",center)


objs = rs.AllObjects(include_lights=False, include_grips=False)
if objs:
    for obj in objs:
        if rs.ObjectType(obj) == 4096: #block
           loopBlock(obj)
        else:
            action(obj)
else:
    print("No objects selectable.")

rs.Redraw()

The test file is attached.
testfile_centroid.3dm (2.6 MB)

I suspect because the centroids are calculated based on the positions of the original objects in the block, not of the individual instances - which may have been moved. For each instance you will probably need to transform the centroid points based on the block instance transformation.

Thanks for the hint, I had that in mind too. I managed to make it work by gradually adding all the block instances transformation data to the centroid of the bounding box. It’s a bit tedious, but it works.

image

Here’s the complete script, for future reference:

#! python 3

import rhinoscriptsyntax as rs
import Rhino

def dotIt(centroid):
    rs.AddTextDot("Centroid!",centroid)

def getBlockOrigin(block):
    irefObj = rs.coercerhinoobject(block)
    idef = irefObj.InstanceDefinition
    blockOrigin = irefObj.InsertionPoint
    return blockOrigin

def getCentroid(obj): #cannot be directly applied to a block
    bb=rs.BoundingBox(obj)
    if bb:
        centroid = ((bb[0]+bb[6])/2)
    return centroid

def loopBlock(block, origin):
    blockOrigin = getBlockOrigin(block) + origin

    blockCentroid = origin + getCentroid(block)
    dotIt(blockCentroid)

    objectsInBlock = rs.BlockObjects(rs.BlockInstanceName(block))
    for obj in objectsInBlock:
        if rs.ObjectType(obj) != 4096: #is not a block
            objCentroid = blockOrigin + getCentroid(obj)
            dotIt(objCentroid)
        else:
            loopBlock(obj, blockOrigin)

objs = rs.AllObjects(include_lights=False, include_grips=False)

if objs:
    for obj in objs:
        if rs.ObjectType(obj) == 4096: #is a block
           loopBlock(obj, Rhino.Geometry.Point3d.Origin)
        else:
            dotIt(getCentroid(obj))
else:
    print("Could not select all objects.")

rs.Redraw()