Create surface with polycurves

Hi,

I am struggling with something I expected to be super simple. I have two 3D polylines, that I pick and I want to create a surface between them. In fact they are ditch bottom and top of backslope. Neither Polysurface.ByLoft (the output loft body self intersects), Surface.ByLoft nor Surface.ByPerimeterPoints (can’t create a polygon, API failed - operation unsuccessful) works.

I expected a solution that would work in the same way as creating a TIN surface in Civil3D with featurelines.

The script is meant to serve for people not familiar with Civil3D features, so I want to work on 3D polylines.

Can you share the DWG?

If the node is giving you the warning the output loft body self intersects this means you need to clean up the 3d poly prior to lofting. You could use MAPCLEAN to fix the lines.

Sorry, I can’t. Apparently I am a new user since I changed work (and email adress…). But I would like it to work on any file. The 3Dpolylines should be more or less parallel (ditch top and bottom or two lines on the ditch, as in the picture below).

@willyoungMF8K3 unfortunately it didn’t work

I bumped your trust level so you should be able to post a dwg now. Just delete everything other than a few pairs of curves that represent common situations, otherwise I’m likely to select the wrong two as I have no idea what “ditch top and bottom” mean in this context.

My guess is that since line 1 appears to be significantly longer than line 2 in your illustration you’re going to have to explicitly define the path of the missing edges. You can draw a line from the end of line 1 to the end of line 2 to confirm.

export_dynamobim.dwg (128.1 KB)

I have left only the two lines I pick to create the surface.

You might be right that it is caused by the difference in length of 2 polylines. Is there another way to create a surface built with 3d polylines or points on these lines in Dynamo? It might be a set of 3d faces between these points or something like that. I imagine something like two feature lines in Civil 3D that build a TIN Surface.

My final goal is to find the point where a given 3Dpolyline crosses this geometry.

How does Civil 3D build the resulting surface given just those two lines and nothing else?

It is a triangulated surface where points of the feature lines are vertices.

Maybe in this case I need something else in Dynamo? A mesh? But then with Geometry.Intersect I cannot find a point of intersection between a line and a mesh.

Out of the box triangulation with Dynamo isn’t available to my knowledge, but you can do something like this solution to create a surface: Create surface from Polyline point - Civil 3D - Dynamo

That script fails because it doesn’t pick up the COGO point group it creates, you could try something like the below:

Tin Surface - Create From Polyline (Selection).dyn (24.3 KB)

@willyoungMF8K3 triangulation is available, but it won’t do things the same way as C3D as it’s generic mesh tooling. Mesh.ByGeometry from modern builds (2026+) should exist in the native library. Those builds alap expose tools for editing and interacting with meshes (which would help @rafal.labrygaHLF22 as it should cover his specific intersection issue). If you are in an older build you can leverage the graphics pipeline to generate meshes shockingly fast. If there is interest I can look at getting a sample together, but again it won’t mimic C3D as it doesn’t apply the limits of what you can do with terrain, but the limits of the display pipeline.

All of that said, I think my previous question might have been misinterpreted a bit. What would the exterior edges of the resulting surface be? I’ll be tying a Dynamo geometry solution shortly.

This is what I meant by “the edges” of the surface which Civil 3D generates. There is a bunch of code in Civil 3D to ensure the resulting shape is ‘closed’ well.

I never had success with triangulation so it would be good to know what’s available. I tried the Delaunay node but it seems to cross-lace by default and make a big tangle of lines. The mesh.ByGeometry node doesn’t accept points directly, is there another step involved?

Points to mesh won’t work as there isn’t a surface. Points > Surface > Mesh will. The Delaunay method in Dynamo is intended for 3d volumes, not 2D surfaces, and as such you won’t likely get the results you expect as a ‘surface’ expert, but they make sense from a computational design standpoint. Everything I posted on above was assuming you had a surface to start with.

The use case of points to mesh means a separate thread though as it’ll be pretty far from this topic. :slight_smile:

Ok, I have results for 3 methods of building the requested surface.

The first is directly in Civil 3D. It’s seven clicks and some typing, and will produce a workflow that will be editable by everyone else after the fact, and maintains some degree of association over time. Surface section of prospector, new surface, definition, contours, add, name it, select and hit return.

Second and third were developed with this graph:


Both of these push a polygon for each triangle of the tessellation, not surfaces. As such you won’t be able to project onto them or whatnot. If you wanted to convert to surfaces you could, but the built in tools don’t allow it. Also any change in the curves would break the tessellation so you’d have to delete everything and build it over again or manage your element bindings (and if users don’t know Civil 3D they won’t learn enough Dynamo for managing bindings). As such using the Civil 3D tools is my recommended workflow.

the Python node's contents
########################################
############## Properties ##############
########################################
__author__ = 'Jacob Small'
__version__ = '0.1.0'
__description__ = "Uses Dynamo's display pipeline to tessellate a surface into triangles"
__DynamoBuilds__ = "4.1"
__ReleaseNotes__ = "POC only, not for production use"
__Dependancies__ = "none"
__Copyright__ = "2026, Autodesk Inc."
__license__ = "Apache 2"



########################################
### Configure the Python environment ###
########################################
### standard imports ###
import sys #add the sys class to the Python environment so we can work with the sys objects
import clr #add the CLR (common language runtime) class to the Python environment so we can work with .net libraries

### basic Dynamo imports ###
clr.AddReference('ProtoGeometry') #add the Dynamo geometry library to the CLR
from Autodesk.DesignScript import Geometry as DG #add the Dynamo geometry class using the alias DG, to ensure no overlap between class calls in Revit or Dynamo
import Dynamo.Visualization as DV #import the Dynamo visualization class so we can use it to tessellate



#########################################
###### Global variables and inputs ######
#########################################
srfs = IN[0] #data from the IN[0] port of the Dynamo environment
if not isinstance(srfs, list): srfs = [srfs] #ensure the surfaces are a list
srfs = [i for i in srfs if isinstance(i, DG.Surface)] #remove any non surfaces from the input list
srfsOut = IN[1] #boolean control for returning surfaces (if true) or polygons (if false)
if not srfsOut: srfsOut == False #enforce a false value for srfsOut if none provided
OUT = [] #set OUT to an empty list into which we'll append the results

#########################################
############## Code begins ##############
#########################################
for srf in srfs: #for each surface
    ### extract basic properties of the surface ###
    nrml = srf.NormalAtParameter(0.5,0.5) #the normal of the surface
    perim = DG.PolySurface.ByJoinedSurfaces([i.Extrude(nrml) for i in srf.PerimeterCurves()]) #the perimeter curves of the surface as a polysurface
    
    ### build the render package to tessellate the Dynamo geometry ###
    renderPackageFactory = DV.DefaultRenderPackageFactory() #buld a render package factor
    renderPackage = renderPackageFactory.CreateRenderPackage() #create the render package
    tessellationParams = renderPackageFactory.TessellationParameters #get the tessellation parameters
    tessellate = srf.Tessellate(renderPackage, tessellationParams) #tessellate the surface
    
    ### get the verticies from the tessellation results
    verts = list(renderPackage.MeshVertices) #get the verticies from the tessellation in the render package
    verts = [verts[i:i+3] for i in range(0, len(verts), 3)] #slice the tessellation into tripples
    verts = [DG.Point.ByCoordinates(i[0],i[1],i[2]) for i in verts] #generate points from the tripples
    
    ### convert the verticies into triangles
    tris = [verts[i:i+3] for i in range(0, len(verts), 3)] #slice the verts into tripples
    tris = [DG.Polygon.ByPoints(i) for i in tris] #generate polygons from the tripples
    if srfsOut: tris = [i.Patch() for i in tris] #generate surfaces from the polygons if srfsOut is True
    
    OUT.append(tris) #append the tris list to the OUT list so it is returned to the Dynamo environment after the Python finishes executing

if len(srfs) == 1: OUT = OUT[0] #set OUT to the first item in the list if only one item was processed

The output of the mesh resulted in this:


Elevation and extents wise this is closer than what C3D produced, but it isn’t something you can edit readily, and things fall apart at the ends - perhaps a geometry scaling bug, a geometry accuracy issue on the mesh, or a bug with Civil 3D conversion.

The output of the tessellation resulted in this:

As far as I can tell, every end point of the result falls on one of the two source curves or midway between the two, so it would be the most accurate of the three.

That said, the built in tools in Civil are going to be a better option here - it isn’t THAT much to learn and they’ll have to spend awhile learning the limits of the Dynamo workaround and deal with that fallout as well.