# Starting point along closed line for numbering

Hi, I’m trying to make numbering really easy. I collect the windows or curtain walls and get them as points. Then use convexhull to create a line to number off, hopefully this would work for strange shaped buildings too. However I want to select an element and use that element to be the starting point to number off the created line. I’m just not sure how to do that. Get the element and the point then order it from there somehow?

also its going anti clockwise, not sure how to make it clockwise, could reverse the list but what if it decides to go clockwise another time. Does turning the closed line into the surface then getting the perimeter curves ensure clockwise rotation?

one last thing… is there a way to change the tolerance of a convexhull?

Thanks for any help!

I have a definition that does this, starts at a specified point within a point data set an makes a line through the remaining points based on a nearest neighbour argument. Not sure if it is posted in one of the ‘shortest path’ topics or not. Will see if I can post later on as I am waiting for a flight just now.

For the clockwise / anticlockwise argument you will need a center reference to compare the ’ travelling’ vector.

1 Like

Opps I wondered why your nodes wernt coming up. Didnt have the package installed in new version of dynamo

Is this what your talking about? Not sure why i’m getting that error

Your other node needs an end point. Ill try pull the insides out and see if it helps

Nope, didn’t mean those but by all means pull them apart

I meant a python definition I have been using for ‘shortest path’ that might not be inside that last node.

The ‘sort as perimeter’ node won’t work for when you have re-entrant corners, so a different angle comparison is required, based on the direction of the last line segment created.

Still waiting for that plane…

This one?

hope your plane comes soon and you have a safe flight.

I’m thinking. Get the point of the selected element to start the numbering. Then figure out how to get the closest point on the convexhull curve to the selected point. Then use that point to break the line somehow and reorder the points following it after

That seemed to work… clockwise too

1 Like

For a shape that translates to a convex hull, a geometry.ClosestPointTo followed by a Curve.ParameterAtPoint will allow easy sorting. To fix the ‘start point’ you would just have to add a value of 1 to any number below the parameter of the given start point. Reversing the order can be done via List.Reverse.

Convex hulls do not have a tolerance. More info here: Convex hull - Wikipedia

I would likely use an exterior room to get the boundaries of the building at a given level, sort the curve loops accordingly and toss the ‘outter container’, and use that as my enclosure loop. Restart the loop by adding 1 to values below the threshold and reverse the list as noted before to go in the other order.

It’s funny all the stuff you can do with curve parameterization.

2 Likes

Thanks Jacob. Do you think on any building you could do all this in the background for the user and it still run alright? would need to make sure a room and boundary is created outside the building on each level and deleted after. Might be slow?

I used to keep the ‘exterior’ room in the model as it has many uses, but it may be doable by just querying walls with a type ‘exterior’, masses, areas, or other elements.

This will take a list of points, and from a start point, generate a polycurve through the remaining points. This is then reversed to get the opposite sorting direction polycurve.

From there, it should be as simple as sorting the points on the curve by their parameter, as this will differ based on the direction of the polycurve chosen.

3 Likes

Thank Ewan! looking forward to trying this

wow this is very fancy. Works really well testing it out. Dont mean to be a pest but the age old question… How do I get it accept lists to create lines across multiple levels Never know if an upper level building shape might change. Trying to cover all the bases. Do I need to make it into a node?

Hi @vanman ,

Can you post the python node internals so I can tweak, again not at the PC…

I know hardly working but I have been working hard.

1 Like

to kind! thanks

# Load the Python Standard and DesignScript Libraries
import sys
import clr
from Autodesk.DesignScript.Geometry import *

import DSCore
from DSCore import *

# Flatten a list
def flat(lst):
return DSCore.List.Flatten(lst,2)

## Convert an instance/list to a list
def tolist(obj1):
if hasattr(obj1,"__iter__"): return obj1
else: return [obj1]

## Return the difference between two lists
def diff(list1, list2):
c = set(list1).union(set(list2))
d = set(list1).intersection(set(list2))
return list(c - d)

## Get the Indexes of Sorted Values
def indexbyvalue(data):
sdata = sorted(data)
indices = []
for s in sdata:
i = data.index(s)
indices.append(i)
return indices

## For creating lines through points based on the shortest distance to the next point
def newL(startPt,plist):
dist1 = []
Li =[]
dlist = []
dlist1 = []
dlist.append(startPt)
plistNew = diff(tolist(startPt),plist)
for p in plistNew:
x = Geometry.DistanceTo(p,startPt)
dist1.append(x)
dSort = indexbyvalue(dist1)
cp = DSCore.List.FirstItem(dSort)
cp1 = DSCore.List.GetItemAtIndex(plistNew,cp)
l = Line.ByStartPointEndPoint(startPt,cp1)
Li.append(l)
newOut = diff(dlist,plist)
return Li,newOut,cp1

start_pt = IN[0]
pt_list = IN[1]

lines_to_keep = []

while len(pt_list)>1:
ss = DSCore.List.FirstItem(start_pt)
x = newL(ss,pt_list)
x0a = DSCore.List.GetItemAtIndex(x,0)
x1a = DSCore.List.GetItemAtIndex(x,1)
x2a = tolist(DSCore.List.GetItemAtIndex(x,2))
pt_list [:] = x1a
start_pt [:] = x2a
lines_to_keep.append(x0a)
else:
pass

direction1_poly = PolyCurve.ByJoinedCurves(flat(lines_to_keep))
direction2_poly = Curve.Reverse(direction1_poly)
OUT = direction1_poly,direction2_poly
# Load the Python Standard and DesignScript Libraries
import sys
import clr
from Autodesk.DesignScript.Geometry import *

import DSCore
from DSCore import *

# Flatten a list
def flat(lst):
return DSCore.List.Flatten(lst,2)

## Convert an instance/list to a list
def tolist(obj1):
if hasattr(obj1,"__iter__"): return obj1
else: return [obj1]

## Return the difference between two lists
def diff(list1, list2):
c = set(list1).union(set(list2))
d = set(list1).intersection(set(list2))
return list(c - d)

## Get the Indexes of Sorted Values
def indexbyvalue(data):
sdata = sorted(data)
indices = []
for s in sdata:
i = data.index(s)
indices.append(i)
return indices

## For creating lines through points based on the shortest distance to the next point
def newL(startPt,plist):
dist1 = []
Li =[]
dlist = []
dlist1 = []
dlist.append(startPt)
plistNew = diff(tolist(startPt),plist)
for p in plistNew:
x = Geometry.DistanceTo(p,startPt)
dist1.append(x)
dSort = indexbyvalue(dist1)
cp = DSCore.List.FirstItem(dSort)
cp1 = DSCore.List.GetItemAtIndex(plistNew,cp)
l = Line.ByStartPointEndPoint(startPt,cp1)
Li.append(l)
newOut = diff(dlist,plist)
return Li,newOut,cp1

start_pt_lists = IN[0]
pt_lists = IN[1]

final_lines = []

for start_pt, pt_list in zip(start_pt_list,pt_lists):

lines_to_keep = []

while len(pt_list)>1:
ss = DSCore.List.FirstItem(start_pt)
x = newL(ss,pt_list)
x0a = DSCore.List.GetItemAtIndex(x,0)
x1a = DSCore.List.GetItemAtIndex(x,1)
x2a = tolist(DSCore.List.GetItemAtIndex(x,2))
pt_list [:] = x1a
start_pt [:] = x2a
lines_to_keep.append(x0a)
else:
pass

direction1_poly = PolyCurve.ByJoinedCurves(flat(lines_to_keep))
direction2_poly = Curve.Reverse(direction1_poly)
final_lines.append([direction1_poly,direction2_poly])

OUT = final_lines

My indents might be a bit funny, typing on the phone. So will fix when I’m at the PC later.

3 Likes