Sampling Elevations from Surface

I have been testing the various nodes available with a view to being able to sample surface elevations by either projecting points or polycurves or lines to allow for further computational design workflows.
Within the dynamo environment by creating dynamo surface (from a C3D TinSurface) and projecting constructed dynamo polycurves or lines, works but can be slow depending on complexity of surface - it would be great to have a way to save the generated 3d polylines, i guess i could save out points to excel after initial run, to allow for faster workflow from that stage onward.
I only managed to get this working by going creating my construction lines above the surface and then with my C3D TinSurface I used TinSurfaceExtensions.GetMesh then using ‘Springs Nodes’ Mesh.ToPolysurface. then use surface.ProjectInputOnto. It can be very slow, and does not always work depending on complexity of surface.

I guess An alternative would be to just use C3D tools to sample surface based on polylines and then bring these into dynamo for processing.

test _Surface_Points_Levels.dyn (77.3 KB)

I thought about automating this to alllow for more flexibility , make it more dynamic, but not many python examples of this, so I tried to convert this c# code into python:

https://civilizeddevelopment.typepad.com/civilized-development/surfaces/

It needs to be provided with points from the polylines or lines (i only have start and end points in this test code, will add more when i get it working), here is python script that I am having trouble with:

    # 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.
dataEnteringNode = IN
surf_name = IN[0]
pline_start = IN[1]
pline_end = IN[2]
samplepoints = []
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)
            btr = t.GetObject(bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite)

            for oid in btr:
                obj = t.GetObject(oid, OpenMode.ForRead)
                if isinstance(obj, TinSurface):
                    if obj.Name == surf_name:
                        surf =oid

                if surf is not None:
                    break

            for pls in pline_start:
                for ple in pline_end:
                    acPoly3d = Polyline3d()
                    btr.AppendEntity(acPoly3d)
                    t.AddNewlyCreatedDBObject(acPoly3d, True)
                    acPts3dPoly = Point3dCollection()
                    acPts3dPoly.Add(Point3d(pls[0],pls[1],pls[2]))
                    acPts3dPoly.Add(Point3d(ple[0],ple[1],ple[2]))
                    for i in list(range(0,acPts3dPoly.Count)):
                        acPolVer3d = PolylineVertex3d(acPts3dPoly.Item[i])
                        acPoly3d.AppendVertex(acPolVer3d)
                        t.AddNewlyCreatedDBObject(acPolVer3d, True)
                    cid = acPoly3d.ObjectId
                    samplepoints.append(surf.SampleElevations(cid))

            # Commit before end transaction
            t.Commit()
            pass

# Assign your output to the OUT variable.
OUT = samplepoints

Anyway - cant figure out the correct way to get items in the Points3dCollection() is there a more dynamic / pythonic way of doing this, i thought I had it with above code but not working, help OR appreciate OTHER ideas for streamlining this kind of workflow appreciated:

I did manage to get polylines to project onto a surface using Curve.Project , it depends on complexity of surface.

would still appreciate other ideas and possibly help with the python script.

Hi @cjm,

I think you could simplify this. The OOTB nodes Surface.SamplePoint or Surface.QuickProfileByObject should get you what you need. Here are some examples.

SampleSurfaceExample.dwg (467.0 KB)
SampleSurfaceExample.dyn (31.3 KB)


Thanks @mzjensen,
Appreciate the feedback.
I was still on 1.1 C3D Toolkit, these are great additions @Paolo_Emilio_Serra1 Keep up the good work!.
Still, I would appreciate any feedback on how to loop the Points3dCollection ‘unscriptable’ point object in python, just for my own future work.
Thanks again
cjm

The Surface.SamplePoint and Surface.QuickProfileByObject are part of Civil 3D Dynamo out-of-the-box, so no packages are needed! :wink:

Regarding the code, the issue is here:

acPts3dPoly.Add(Point3d(pls[0],pls[1],pls[2]))
acPts3dPoly.Add(Point3d(ple[0],ple[1],ple[2]))

I’m assuming that the intent is to create Point3d objects from DesignScript points. But these lines won’t work because the coordinates for the points are not accessible as a list using subscripts. You need to add a reference to the ProtoGeometry library and then access the members like this:

import clr

clr.AddReference('AcDbMgd')
clr.AddReference('ProtoGeometry')

from Autodesk.DesignScript.Geometry import *
from Autodesk.AutoCAD.Geometry import *

point = IN[0]

OUT = Point3d(point.X, point.Y, point.Z)

1 Like