Hello, I’m trying to create a script that adjust the length of a corridor based on a target volume.
First I was trying to get the volume from a TIN surface, but I had no luck getting that.
Then I thought of creating a solid from the surfaces (existing and proposed) but there is not a “Extract solid from surface” node.
Thanks,
@jduran you could create the solids between surfaces in Dynamo and then extract the volume.
You have to create a watertight solid using the surfaces from the TIN and creating the necessary lateral faces to connect them.
It’s not always straight forward as the surfaces may intersect in multiple places but it can be done.
Hi,
Could it possible to write a node that provides volumes using API (API?
thanks
@jduran did you extract the solids from the corridor in Civil 3D before running Dynamo?
I didn’t, That’s the issue
With a Great help from Paolo I Manage to create this Python Scrypt to get the surface volume:
#Get net Volume from volume surface
__author__ = 'Jesus A Duran - jduran@moffattnichol.com'
__version__ = '1.0.0'
# Load the Python Standard and DesignScript Libraries
import sys
import clr
# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')
clr.AddReference('AeccPressurePipesMgd')
clr.AddReference('acdbMgdbRep')
# Create an alias to the Autodesk.AutoCAD.ApplicationServices.Application class
import Autodesk.AutoCAD.ApplicationServices.Application as acapp
# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *
# Import references for PropertySets
from Autodesk.Aec.PropertyData import *
from Autodesk.Aec.PropertyData.DatabaseServices import *
# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *
# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN
adoc = acapp.DocumentManager.MdiActiveDocument
ed = adoc.Editor
def get_tinvolumesurface_Vol(vs_name):
global adoc
vsid = None
output = {}
with adoc.LockDocument():
with adoc.Database as db:
with db.TransactionManager.StartTransaction() as t:
bt = t.GetObject(db.BlockTableId, OpenMode.ForWrite)
btr = t.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite)
for oid in btr:
obj = t.GetObject(oid, OpenMode.ForRead)
if isinstance(obj, TinVolumeSurface):
if obj.Name == vs_name:
vsid = oid
if vsid is not None:
break
if vsid is None:
return "Surface not found"
vs = t.GetObject(vsid, OpenMode.ForRead)
props = vs.GetVolumeProperties()
for a in dir(props):
try:
output[a] = getattr(props, a)
except:
pass
t.Commit()
return output["UnadjustedNetVolume"]/27 #Converting to Cu. Yards
OUT = get_tinvolumesurface_Vol(IN[0])
Find the attached Dynamo file, you’ll have to change the “VOL-PG-FILL” for the name of the volume surface you want to get data from.
If you don’t have the volume surface created and you want dynamo to do it, check this Paolo script:
https://forum.dynamobim.com/t/getting-surface-information-from-c3d-using-python/44258/6?u=jduran
Get_Surface Vol.dyn (5.9 KB)
with adoc.LockDocument():
with adoc.Database as db:
with db.TransactionManager.StartTransaction() as t:
bt = t.GetObject(db.BlockTableId, OpenMode.ForWrite)
btrID = bt.get_Item("*Model_Space")
btr = t.GetObject(btrID, OpenMode.ForWrite)
I tried but still got the error. Can you help me fix the error?
Thank you!
import sys
import clr
# Load the Python Standard and DesignScript Libraries
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')
# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *
# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *
# The inputs to this node will be stored as a list in the IN variables.
dataEnteringNode = IN
adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor
def get_tinvolumesurface_Vol(vs_name):
global adoc
vsid = None
output = {}
with adoc.LockDocument():
with adoc.Database as db:
with db.TransactionManager.StartTransaction() as t:
bt = t.GetObject(db.BlockTableId, OpenMode.ForWrite)
btrID = bt.get_Item("*Model_Space")
btr = t.GetObject(btrID, OpenMode.ForWrite)
for oid in btr:
obj = t.GetObject(oid, OpenMode.ForWrite)
if isinstance(obj, TinVolumeSurface):
if obj.Name == vs_name:
vsid = oid
if vsid is not None:
break
if vsid is None:
return "Surface not found"
vs = t.GetObject(vsid, OpenMode.ForWrite)
props = vs.GetVolumeProperties()
for a in dir(props):
try:
output[a] = getattr(props, a)
except:
pass
t.Commit()
return output
OUT = get_tinvolumesurface_Vol(IN[0])```
There is an issue with the indentation. Try backspacing the code and using tab to get to the correct indentations.
This works for me:
VolumeSurface.dyn (7.4 KB)
# Load the Python Standard and DesignScript Libraries
import sys
import clr
# Add Assemblies for AutoCAD and Civil3D
clr.AddReference('AcMgd')
clr.AddReference('AcCoreMgd')
clr.AddReference('AcDbMgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')
# Import references from AutoCAD
from Autodesk.AutoCAD.Runtime import *
from Autodesk.AutoCAD.ApplicationServices import *
from Autodesk.AutoCAD.EditorInput import *
from Autodesk.AutoCAD.DatabaseServices import *
from Autodesk.AutoCAD.Geometry import *
# Import references from Civil3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *
# The inputs to this node will be stored as a list in the IN variables.
vs_name = IN[0]
adoc = Application.DocumentManager.MdiActiveDocument
editor = adoc.Editor
with adoc.LockDocument():
with adoc.Database as db:
with db.TransactionManager.StartTransaction() as t:
bt = t.GetObject(db.BlockTableId, OpenMode.ForWrite)
btrID = bt.get_Item("*Model_Space")
btr = t.GetObject(btrID, OpenMode.ForWrite)
for oid in btr:
obj = t.GetObject(oid, OpenMode.ForWrite)
if isinstance(obj, TinVolumeSurface) and obj.Name == vs_name:
volumeSurface = obj
props = volumeSurface.GetVolumeProperties()
adjustedCutVolume = "Adjusted Cut Volume = " + str(props.AdjustedCutVolume)
adjustedFillVolume = "Adjusted Fill Volume = " + str(props.AdjustedFillVolume)
adjustedNetVolume = "Adjusted Net Volume = " + str(props.AdjustedNetVolume)
#
#
# Commit before end transaction
t.Commit()
pass
# Assign your output to the OUT variable.
OUT = adjustedCutVolume, adjustedFillVolume, adjustedNetVolume
If you just want the integers and not strings then you can just remove the string addition and the “str()” command. If you add dir(props) to “OUT”, you can see all available properties.
Thank you very much !
como obtener el volumen de una superficie, a una elevación definida?
Please edit with google translate to english.
how to obtain the volume of a surface, at a defined elevation? could this be done with dynamo?
the normal thing is to compare 2 surfaces, but if after that, that total surface volume, I would like to know the volume at an elevation that I indicate. it could be using a flat surface that I could move in elevation “Z”, but to obtain the volume at that elevation level of that third surface (I leave image for better understanding).
Looks like you need to create a trimmed version of surface 2 and trimmed version of surface 3 and paste those into a surface 4. And compare that with surface 1 as a volume surface.
I see your intent is to create a combined surface that takes the lower elevation triangles. Next time im at my computer I can see if there is a way to achieve this.