Sort points by untangled lines

Hello Dynamo Community,

I need help with my current python script please.
I would like to annotate my 3D ortho view with tags but I don’t want to untangle all the tags after placement. I have added my python code below as well as snapshots of my dynamo script and 3D preview. My logic is to shuffle the lists until I get the right combination where the lines do not intersect and then OUT out those points, however I think this might be a bit extreme on memory. I have tried using iterations and started with the top right point and work my way down but that did not work unfortunately. If there is anybody who might have some good logic on how to do this, any feedback is greatly appreciated. I am currently studying python scripting so I am still a newbie.

Thanks


import clr
import random
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import Line

point1 = IN[0]
point2 = IN[1]

#if inputs are not lists, convert to list
if isinstance(point1, list):
	pointlist1 = point1
else:
	pointlist1 = [point1]

if isinstance(point2, list):
	pointlist2 = point2
else:
	pointlist2 = [point2]
	
new_point_list = []
while_count = 0
while while_count < 1000:	#count used to not enter infinite loop
	lines = []	#reset line list
	for p1, p2 in zip(pointlist1, pointlist2):
		lines.append(Line.ByStartPointEndPoint(p1,p2))	#create lines from points in both lists
		
	for line1 in lines:
		for line2 in lines:
			if line1 != line2: #filter out lines that intersect itself
				if line1.DoesIntersect(line2):
					random.shuffle(pointlist2)	#shuffle list2 if there is a clash
					continue	#start loop again
				else:
					new_point_list = pointlist2
					break	

	while_count += 1
OUT = new_point_list

Hello,
Your initial points hooked to your elements must be classified in Z descending

Cordially
christian.stan

Hi Christian,

Thanks I have tried this but cannot sort the points by Z value as the plane is on all 3 axis.

You could the coordinatesystem of the plane to get all points residing on this plane.
From there you should be able to sort them by Z-value.

1 Like

Hi @Daan ,

I am able to do this but unfortunately this does not solve my problem. Because I have my leader tail points at different vertical positions, I cannot sort the points by coordinate Z value or surface V value. The snapshot below illustrates why:

The first 3 points are fine.
The next point in the Z or V value is the blue point, which casts to the 4th point on the right.
The next point in the Z or V value is the red point, which casts to the 5th point on the right causing the lines to cross.

I have managed to find a solution using the angles in relation to a fixed reference line.
Thanks for the help all.

import clr

clr.AddReference('ProtoGeometry')

from Autodesk.DesignScript.Geometry import *

point1 = IN[0]
point2 = IN[1]

#if inputs are not lists, convert to list
if isinstance(point1, list):
	pointlist1 = point1
else:
	pointlist1 = [point1]

if isinstance(point2, list):
	pointlist2 = point2
else:
	pointlist2 = [point2]

# get first and last point in the start list (Leader elbow)
start_point = pointlist1[0]
end_point = pointlist1[-1]
# create a line from the last point to the first and get the vector of that line
ref_line = Line.ByStartPointEndPoint(end_point,start_point)
ref_line_vector = Line.NormalAtParameter(ref_line,0)
# create result list
new_point_list = []
# iterate for each leader elbow point
# used range instead of items in list because I want to remove items in the list for each iteration
for a in range(len(pointlist1)):
	# Set the first point as the active point
	sp = pointlist1[0]
	# create/reset lists
	line_list = []
	vector_list = []
	angle_vector = []
	# for each endpoint
	for ep in pointlist2:
		# create a line
		ep_line = Line.ByStartPointEndPoint(sp,ep)
		# get the vector of the line
		ep_vector = Line.NormalAtParameter(ep_line,0)
		# add the line to a list
		line_list.append(ep_line)
		# add the vector to a list
		vector_list.append(ep_vector)
	# for each vector in the vector list
	for vec in vector_list:
	# get the angle against the reference line vector and add to the list
		angle_vector.append(Vector.AngleWithVector(ref_line_vector,vec))
	# get the vector with the smallest angle
	vector_min = min(angle_vector)
	# index the minimum vector
	vector_index = angle_vector.index(vector_min)
	# add the point associated with the minimum angle to the output list
	new_point_list.append(pointlist2[vector_index])
	# remove the first index from the leader elbow list
	pointlist1.pop(0)
	#remove the returned point from the endpoint list so it does not get used again
	pointlist2.pop(vector_index)

OUT = new_point_list
5 Likes

Glad to hear that! Wouldn’t have come up with a solution involving relative angles!