Sort 3D lines so they can be joined eventualluy

i try to sort lines which are not entirely in one plane, so either polycurve or Group Curves node of archilab cannot be used, any insight?

if you should have any kind of help with these kind of information, you should share what you try and dataset…it will totally be impossible to help from there what you show and give us, just a good advice

But like almost? Maybe pull them on the same plane or isn’t that an option?

this is just simple case, basically they are combination of horizontal lines and vertical lines and sometimes sloped lines, in fact, i saw someone had solution before in this forum but i cannot dig it out, just wonder if there is anything like 3D polycurve?

@ning.zhouHNQLJ then share these curves as rvt and we can probably,help dont think the community build that sittuation up again, then you will have better luck…good luck

thanks sovitek, you are great help in this forum and very appreciated! uploaded RVT w/ curves FYI

lines.rvt (444 KB)

yeah thats the way :wink: lets hope someone take a look at that, i dont have time right now, maybe later, but now you at least have have a change for something help:) great

PolyCurve.ByGroupedCurves perhaps?

you could try play with something here, for shatter you could get one in ampersand package or try build your own as something here…


thanks all, mostly work well for sovitek’s solution, for instance, not work if some lines are relatively short and gaps between lines are big.

PolyCurve.ByGroupedCurves only works if those lines are joined already.

looks like Springs node LineLoop.Merge works well (only for IronPython2, not CPython3).

The later Dynamo versions should have a ‘join tolerance’ on it which should allow closing those gaps without the ‘extend’ aspect.

That said if some curves are ‘short’ you might have other issues to deal with. It may be more consistent to include the joints and fixtures in the selection, derive the L shapes therefrom based on the connector locations, and use those to close the sequence.

1 Like

thanks jacob, quick testing results in list of polycurves → one polycurve per curve, not sorted

Which build of Revit are you in?

2024

1 Like

So I still think you want to revise this workflow - the root selection (or creation) of the curves could (should) include the connectors as well.

Here is the OOTB workflow I was noting using the ByGroupedCurves method:

Note that as you have gaps exceeding the shorted line segment you’re getting pretty significant gaps - this is why I think you want to revist the initial generation method be it ‘routing’ or ‘from a selected system’.

Your alternative is to find a curve in the set and interate to find the ‘closest’ to one end or the other that is within yoru desired tolerance, and build the connection from there. It’s doable, but it’s slow and ugly.

1 Like

thanks jacob, i saw that alternative you mentioned in this forum but i just cannot dig it out :frowning:

Which specific build of Revit are you in? 2024.0? Should be 2024.3.4 if memory serves (away from the PC for a bit).

This bit of Python might help get things sorted for you @ning.zhouHNQLJ
EDIT: Updated this python to deal with obscenely short curves

########################################
############## Properties ##############
########################################
__author__ = 'Jacob Small'
__version__ = '0.1.0'
__description__ = "Sort a list of curves by the order in which they'd join into a polycurve with variable length connection"
__DynamoBuilds__ = "X.YY.Z, X.YY.Z..."
__ReleaseNotes__ = "POC only - not suitable for production environments without further testing and edge case handling. Currently doesn't handle branching curve sets."
__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
clr.AddReference('DSCoreNodes') #add the standard Dynamo library to the CLR
import DSCore # import the standard Dynamo classes to the Python environment
clr.AddReference('GeometryColor') #add the Geometry color library to the CLR
from Modifiers import GeometryColor #import the GeometryColor class to the Python environment



#########################################
###### Global variables and inputs ######
#########################################
crvs = IN[0] #the initial curve from IN[0] of the Dynamo environment
sortedCvs = [i for i in crvs] #output list to sort later
polyCurve = DG.PolyCurve.ByJoinedCurves([crvs.pop()]) #build a polycurve from one of the curves in the initial curve list



#########################################
############ Code goes here #############
#########################################
while crvs: #whiel there are curves
    #get the next curve
    crvs = sorted(crvs, key = lambda x: polyCurve.DistanceTo(x)) #sort the curves by the distance from the polycurve
    next = crvs.pop(0) #pop the first curve (closest to the polycurve)
    #because we are always going to remove a curve this shouldn't be an infinate loop
    
    #get the next point
    nextPoint = next.StartPoint #get the start point of the next curve
    if next.StartPoint.DistanceTo(polyCurve) > next.EndPoint.DistanceTo(polyCurve): #if the end point is closer to the polycurve than the next point
        nextPoint = next.EndPoint  #set the next point to the end point of the next curve
    
    #get the connection point
    connectPoint = polyCurve.StartPoint #set the connectPoint to the start point of the current polycurve
    if nextPoint.DistanceTo(connectPoint) > nextPoint.DistanceTo(polyCurve.EndPoint): #if the end point of the polycurve is closer to the nextPoint than the connectPoint
        connectPoint = polyCurve.EndPoint #set the connectPoint to the end point of the polycurve
    
    #get the original curve and the next curve, appending a connecting line if needed
    crvSet = [polyCurve, next] #build a list of the current polycurve and next curve
    if connectPoint.DistanceTo(nextPoint) > 0: #if the connect point and next point are not touching
        #connectPoint.Taunt("i'm not touching you", nextPoint)
        crvSet.append(DG.Line.ByStartPointEndPoint(nextPoint, connectPoint)) #append a line between the connect point and the next point to the crvSet
    
    #build the new polycurve
    polyCurve = DG.PolyCurve.ByJoinedCurves(crvSet) #build the polycurve from the curve set (which contains the current polyCurve and the curves found on this past

#note: you might want to just output the polycurve here, but your original question was 'sort the list of curves'
OUT = polyCurve #set OUT to the polycurve

OUT = sorted(sortedCvs, key = lambda x: polyCurve.ParameterAtPoint(x.StartPoint)) #set OUT to the sortedCrvs list, sorted by the parameter of the polyCurve at each respective curves start point
1 Like

2024.3.4

Interesting you don’t see the node surfaced; might be suppressed in your geometry preferences?