Batch create volumetric surfaces

Hello guys, what i’m trying to achieve rn is exactly the topic name, batch creating volumetric surfaces between my already existing TINsurfaces. I’ve searched the forum and the closest I got from it was this post: Getting surface information from C3D using Python - #5 by jduran

but i can’t seen to do this operation for multiple inputs! any help around this issue?

thanks in advance

Hello,

Is not simple but you’ll have to create every volumetric surface that you need like this:

CommandMethod("CreateTinVolumeSurface")]
public void CreateTinVolumeSurface()
{
    using (Transaction ts = Application.DocumentManager.MdiActiveDocument.Database.TransactionManager.StartTransaction())
    {
        string surfaceName = "ExampleVolumeSurface";
        // Prompt user to select surfaces to use
        // promptForTinSurface uses Editor.GetEntity() to select a TIN surface
        ObjectId baseId = promptForTinSurface("Select the base surface");
        ObjectId comparisonId = promptForTinSurface("Select the comparison surface");

        try
        {
            // Create the surface
            ObjectId surfaceId = TinVolumeSurface.Create(surfaceName, baseId, comparisonId);
            TinVolumeSurface surface = surfaceId.GetObject(OpenMode.ForWrite) as TinVolumeSurface;
        }

        catch (System.Exception e)
        {
            editor.WriteMessage("Surface create failed: {0}", e.Message);
        }

        // commit the create action
        ts.Commit();
    }
}

You’ll need to adjust that for python if you want to do it in Dynamo.
Hope this helps

Hi, are you looking for solution how to repeat one function for multiple inputs stored in a list? I hope this can help you Create Profile - #26 by Drbohlav. Or google "For Loop“ and “List Comprehensions”.

Based on the topic you mentioned in the first post I created the following:

`#Get net Volume from volume surface

__author__ = 'Stan Bouwens'
__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 *
from Autodesk.AutoCAD.BoundaryRepresentation 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, boundaries):
    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]


    base_surf_id = []
    top_surf_id = []
    vsid = []
    vs = []
    props = []
    dict = {}
    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)
							
			    #get surfaces based on surface handle				
			    for oid in btr:
				    obj = t.GetObject(oid, OpenMode.ForRead)
				    if isinstance(obj, TinSurface):
					    for b_handle in base_surf:
						    if obj.Handle.ToString() == b_handle:
							    base_surf_id.append(oid)
					    for t_handle in top_surf:
						    if obj.Handle.ToString() == t_handle:
							    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 = (TinVolumeSurface.Create(a[0], a[1], a[2], vs_style))
				    vs.append(t.GetObject(vsid, OpenMode.ForWrite))
			
			    #create bounded volume surfaces and append properties in dictionary								
			    for j, k in zip(vs, boundary_p3dcol_split):
				    j.Rebuild()
				    vs_props = j.GetVolumeProperties()
				    maintask = {'Cut': int(vs_props.AdjustedCutVolume), "Fill": int(vs_props.AdjustedFillVolume), "Net": int(vs_props.AdjustedNetVolume), "Task name":j.Name}
				    output.append(maintask)
			   #delete the volume surfaces to prevent mess in Civil3D toolspace
				    j.Erase()
			    t.Commit()
    return output

OUT = get_tinvolumesurface_Vol(IN[0], IN[1], IN[2], IN[3], IN[4])

Not the most cleanest code but it is functional. It is however required to have some basic knowledge of python to start with this :slight_smile: .

6 Likes

Hi @stabouw, sorry for the late reply. I used your script and adapted it for my needs (I needed the volumetric surfaces created to make solids from them, exclusively) and it works perfectly.

Thank you very much for you help.

First thanks for your post!

When I use this script to retrieve volume of a iteratively generated TinVolumeSurface based on a corridor, as the subassembly parameters of the corridor varies. I met tow problems:

  1. “TinVolumeSurface.Create Method (surfaceName, baseSurfaceId, comparisonSurfaceId, styleId)”
    styleId is The ObjectId of the SurfaceStyle for the TinVolumeSurface, but I don’t know how to get a styleId.
  2. I want to get the volume info of the generated TinVolumeSurface every time the associated corridor is updated, how can I connect these two things, the corridor updates and create & retrieve info of the TinVolumeSurface?

Thanks very much!

For surface style
try this is

 cdoc = CivilApplication.ActiveDocument 
 styleId = cdoc.Styles.SurfaceStyles[0]
      

Thanks very much! I tried as your advice, it works.

from Autodesk.Civil.ApplicationServices import *
cdoc = CivilApplication.ActiveDocument

rst = []
for style in cdoc.Styles.SurfaceStyles:
	rst.append(style)
 	
OUT = rst

For selecting a surface style I used this Python code, the output is dictionary of all available surface styles.

"""
Copyright 2019 Autodesk, Inc. All rights reserved.

This file is part of the Civil 3D Python Module.

"""
__author__ = 'Paolo Emilio Serra - paolo.serra@autodesk.com'
__copyright__ = '2019'
__version__ = '1.0.0'

import clr

# Add Assemblies for AutoCAD and Civil 3D APIs
clr.AddReference('acmgd')
clr.AddReference('acdbmgd')
clr.AddReference('accoremgd')
clr.AddReference('AecBaseMgd')
clr.AddReference('AecPropDataMgd')
clr.AddReference('AeccDbMgd')
clr.AddReference('AeccPressurePipesMgd')
clr.AddReference('acdbmgdbrep')
clr.AddReference('System.Windows.Forms')
clr.AddReference('Civil3DNodes')

# Add standard Python references
import sys
sys.path.append('C:\Program Files\IronPython 2.7\Lib')
import os
import math

# Add references to manage arrays, collections and interact with the user
from System import *
from System.IO import *
from System.Collections.Specialized import *
from System.Windows.Forms import MessageBox

# 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 for Civil 3D
from Autodesk.Civil.ApplicationServices import *
from Autodesk.Civil.DatabaseServices import *

# Import references for Dynamo for Civil 3D
from Autodesk.Civil.DynamoNodes import Alignment as DynAlignment

adoc = acapp.DocumentManager.MdiActiveDocument
ed = adoc.Editor
civdoc = CivilApplication.ActiveDocument


def get_surface_styles():
    """
    This method creates gets the alignment style names in the current document.
    :return: A list of alignment style names
    """
       	
    surfacestyle_id = []
    surfacestyle_name = []
    output = {}
    
    # Get the active document in the AutoCAD session:
    with adoc.LockDocument():
        with adoc.Database as db:

            with db.TransactionManager.StartTransaction() as t:
                styleCol = civdoc.Styles.SurfaceStyles
                 
                for i in styleCol:
               		styleObj = t.GetObject(i, OpenMode.ForRead)
	               	surfacestyle_name.append(styleObj.AcadObject.Name)
    	output = dict(zip(surfacestyle_name, styleCol))
    return output

# Output	
OUT = get_surface_styles()

Running a dynamo script automatically is something which as far as I know cannot be done in Dynamo itself. You could probably pick up corridor updates in the Civil .NET API and then trigger the dynamo script, but I have no experience with that.

When I tried your script to get volume of a TinVolumeSurface, I encountered a problem,
I am not able to get these ID variables of “vs_name, base_surf, top_surf, vs_style”, could you give some advice?
Thanks a lot.

The following variables are output:

  • vs_name is the name of the to be created volume surface as a string
  • base_surf is the object handle (string) of the lowest TIN surface
  • top_surf is the object handle (string) of the top TIN surface
  • vs_style is the volume surface style, this is the object that is created as output in the python node above (posted 23 nov)

Object handles can be retrieved from a object with the DocumentExtensions.ObjectHandle node.

It works. Thanks very much for your help!