Multiple bounded Tin Volumesurfaces

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

I think you’re right. As written, the loop below will run through each boundary polyline and add the vertices to a one-dimensional list, right?

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

So then the GetBoundedVolumes method is trying to create a single polygon from all of the points, which fails. It seems like this block needs to be restructured so that you have a two-dimensional list with the points for each polyline as sublists.

1 Like

But how do i get these Point3D’s in a two dimensional list?

If I add the script below, i do get the coordinates of the vertices split per polyline.

            for i in pline_id:	
				pline_obj.append(t.GetObject(i, OpenMode.ForRead))
			for j in pline_obj:
				pline_indexvrt.append(int(j.EndParam))
				
			pline_obj_point_split = []				
			for k, l in zip(pline_indexvrt, pline_obj):
				pline_indexvrt_int.append(int(k))
				index = 0
				while index < k:
					pline_obj_point.append(l.GetPoint3dAt(index))
					index = index + 1
			
			total = 0
			pline_obj_point_split = []
			for j in range(len(pline_indexvrt_int)):
				chunck_mylist = pline_obj_point[total:total+pline_indexvrt_int[j]]
				pline_obj_point_split.append(chunck_mylist)
				total += pline_indexvrt_int[j]

Results in this output:
output

These are however ‘python’ objects and thus need to be converted to a Point3D collection, maintaining the same list structure. How can that be achieved?