Get volume of each object in a file using python

Hi! I am trying to get the volume of each block in my file (they are extrusions/polysurfaces). I have the following code:
import rhinoscriptsyntax as rs

tolerance = 170 #m3


#pick an object
object_id = rs.GetObjects()

#Loop between my objects
for object_i in object_id:
#deselect any objects
rs.Command("-_selnone")
#get block id
#print object_i
object_i = str(object_i)
print type(object_i)
block = rs.Command("-_SelID " + object_i)
#get volume
blockVolume = rs.Command("-_Volume ")
blockVolume = str(blockVolume)
print "the volume is " + blockVolume
#print type(volume)
#delete if too small
if blockVolume < tolerance:
    rs.Command("-_Delete")
    print "Deleting block"

However the for loop does not work since blockVolume initially is a boolean. I changed it to a string just to print it out in a way that is easy for me to read.
How can I get rhino to return the volume in a way that is not a boolean? It prints to the console fine.
Thank you!!!

import rhinoscriptsyntax as rs

tolerance = 170

object_id = rs.GetObjects()

for object_i in object_id:

    i = rs.coercebrep(object_i)

    blockVolume = i.GetVolume()
    if blockVolume < tolerance:
        rs.DeleteObject(object_i)

so Brep has a method called .GetVolume()
see if this works for you

1 Like

One mistake is this:

blockVolume = rs.Command("-_Volume ")

rs.Command only returns a boolean value which indicates if the command succeeded or not.

However, while you can script many Rhino commands that return objects with rs.Command(), scripting _Volume just prints out some command-line strings. You would have to parse the command history to get those, which is painful. Just to note here that to get actual objects that may (or may not) have been created by rs.Command(), you need to use objs=rs.LastCreatedObjects(boolSelect). But let’s do it differently -

Better to start with some “native” rhinoscriptsyntax commands:

import rhinoscriptsyntax as rs

tolerance = 170.0 #m3
#pick a series of objects
object_ids = rs.GetObjects("Select some closed surfaces or polysurfaces",8+16)
#loop between objects
for object_id in object_ids:
    #check to see if the object is closed before calculating volume
    if rs.IsObjectSolid(object_id):
        blockVolume=rs.SurfaceVolume(object_id)
        #this method returns a tuple of (volume,calculation error)
        #to get volume, you need the index 0
        print "The volume is " + str(blockVolume[0])
        if blockVolume[0] < tolerance:
            print "Volume less than tolerance, deleting block"
            rs.DeleteObject(object_id)
    else:
        print "Object is not closed"
1 Like

Thanks! I just implemented this and it works! Thank you very much for your time!!

If anyone ever needs it, here is my code that suppresses user interaction for this:

import rhinoscriptsyntax as rs

#def zero_vol_rigid_blocks():
tolerance = 200 #1e-4
rs.Command("-_SelAll ")
object_id = rs.GetObjects(message="Bla", preselect=True)
count = 0

for object_i in object_id:
    #deselect any objects
    rs.Command("-_selnone")
    
    #get block id
    object_i = str(object_i)
    block = rs.Command("-_SelID " + object_i)
    
    #getvolume
    i = rs.coercebrep(object_i)

    blockVolume = i.GetVolume()
    
    #delete where appropriate
    if blockVolume < tolerance:
        rs.Command("-_Delete")
        print "Deleting block"
        count += 1

rs.Command("-_SelNone ")        
count = str(count) + " zero volume blocks were deleted"
print count

Hey, thank you for last post. It really helped me to get behind this python-script. Since i have no experience in programming at all, the comments in this code made my day.

I took your code and expanded it a little, so that the script will now (in Rhino 6) give out Volume and Weight, and write this in each UserText of the object. This might help with bigger objects (of the same density).

My Problem now is, that Blocks in the file just crash the script for me. Is there some way i can tell the “rs.GetObjects(…)” to pick each single part of the Block? And by any chance then to force the “rs.SetUserText()” to write the Values into the Block itself? I looked a little in this syntax-description, but in my code this does not help to pick the parts of the block.

Nontheless, thank you for your documentation. I will set my code attached, too.

import rhinoscriptsyntax as rs
dens = rs.RealBox(message=“Density of Material in kg/m^3”, default_number=8000, title=“Density of Material”, minimum=None, maximum=None) #Textbox to Pick Density of Material Used.
rs.Command("-_SelAll “)
object_id = rs.GetObjects(message=“Bla”, preselect=True)#Select an Object. Is there some way to pick parts of a block?
sum = 0 #Sum of the weight of all Objects.Has to be Zero Before the For command.
float(sum)#Has to be a float (i guess)
for object_i in object_id: #Loop between the objects
rs.Command(”-_selnone") #deselect any objects
#Define Volume
object_i = str(object_i)
block = rs.Command("-_SelID " + object_i) #get block id
i = rs.coercebrep(object_i)
blockVolume = i.GetVolume()#getvolume
Vol1 = ("%.2f" % blockVolume)#Set Value behind comma
Vol = str(Vol1)#change into str
rs.SetUserText(object_i, “Volumen in mm^3”, value=Vol)#Write Volume into Usertext. Some way to write this into the Block?
#Define Weight
dens1 = (dens*0.000000001) # Density from kg/m^3 in kg/mm
weight1 = (dens1 * blockVolume) #Weight of the Part
weight2 = ("%.2f" % weight1)#Set Value behind comma
weight = str(weight2)#weight into str
rs.SetUserText(object_i, “Gewicht in kg”, value=weight)#write value into User Text.Some way to write this into the Block?
weight3 = float(weight)#make weight a float
sum += weight3 #add weight of the part to the total weight
print sum # print the total weight after every part.find out how to change that