Hello all,
I’ve been busy with implementing the Volume Dashboard functionality in Dynamo through Python as suggested in Getting surface information from C3D using Python topic and extending this with the method of Surface.GetBoundedVolumes.
So far I’ve managed to create a single bounded Tin VolumeSurface. It however gets problematic when I want to split one Tin Volumesurface with multiple polylines.
I’m running the following script:
__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, base_surf, top_surf, vs_style, lay_name):
global adoc
if not isinstance(base_surf, list):
base_surf = [base_surf]
if not isinstance(top_surf, list):
top_surf = [top_surf]
if not isinstance(vs_name, list):
vs_name = [vs_name]
pline_id = []
pline_obj = []
pline_indexvrt = []
pline_indexvrt_int = []
pline_obj_point = []
pline_obj_point_col = Point3dCollection()
base_surf_id = []
top_surf_id = []
vsid = []
vs = []
props = []
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)
#find polylines and determine vertices of those
for oid in btr:
pl = t.GetObject(oid, OpenMode.ForRead)
if isinstance(pl, Polyline):
if pl.Layer == lay_name:
pline_id.append(oid)
for i in pline_id:
pline_obj.append(t.GetObject(i, OpenMode.ForRead))
for j in pline_obj:
pline_indexvrt.append(int(j.EndParam))
for k, l in zip(pline_indexvrt, pline_obj):
index = 0
while index < k:
pline_obj_point_col.Add(l.GetPoint3dAt(index))
index = index + 1
for oid in btr:
obj = t.GetObject(oid, OpenMode.ForRead)
if isinstance(obj, TinSurface):
for b_name in base_surf:
if obj.Name == b_name:
base_surf_id.append(oid)
for t_name in top_surf:
if obj.Name == t_name:
top_surf_id.append(oid)
if len(base_surf_id+top_surf_id) is len(base_surf+top_surf):
break
if len(base_surf_id) is 0 or len(top_surf_id) is 0:
return "Surface is not a TIN surface"
for a in list(zip(vs_name, base_surf_id , top_surf_id)):
vsid.append(TinVolumeSurface.Create(a[0], a[1], a[2], vs_style))
for b in vsid:
vs.append(t.GetObject(b, OpenMode.ForWrite))
for c in vs:
c.Rebuild()
props.append(c.GetVolumeProperties())
vs_bound = vs[0].GetBoundedVolumes(pline_obj_point_col)
output = [{'Cut': vs_bound.Cut, "Fill": vs_bound.Fill, "Net": vs_bound.Net}]
t.Commit()
return vs_bound
OUT = get_tinvolumesurface_Vol(IN[0], IN[1], IN[2], IN[3], IN[4])`
However, when I run this script with multiple polylines it gives the error “Unable to calculate volume, possibly illegal bounding polygon”. I guess this is due that the Point3dCollection has the points of two polylines, and not a single.
How can I create multiple bounded Tin VolumeSurfaces with multiple polylines?
Files can be found here
With kind regards,
Stan