Group Parallel Lines by Direction and Distance

I used the Python Script by @viktor_kuzev from the topic (Group closest parallel lines which are equal in length) and it worked out well for majority of the lines.

But a few lines [orange and violet] although parallel (to the eye) are not being grouped appropriately.

I tried changing the code to check if reversing the direction would work but it didn’t.

What would you suggest I should try next?
Test_Revit2019.rvt (2.2 MB)

hello @AmolShah
try this

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

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication

import sys
sys.path.append(r'C:\Program Files (x86)\IronPython 2.7\Lib')
import random

def nearCond(lstelemb, elema):
	check = False
	midpta = elema.Location.Curve.Evaluate(0.5, True) 
	for elemb in lstelemb:
		midptb = elemb.Location.Curve.Evaluate(0.5, True)
		if midpta.DistanceTo(midptb) < margin:
			check = True
			break
	return check		

	
def colorRamdom(elements, view):
	TransactionManager.Instance.EnsureInTransaction(doc)
	rvtcolor = Color(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
	gSettings = OverrideGraphicSettings()
	gSettings.SetProjectionFillColor(rvtcolor)
	gSettings.SetProjectionLineColor(rvtcolor)
	gSettings.SetCutLineColor(rvtcolor)
	gSettings.SetCutFillColor(rvtcolor) 
	for element in elements:
		view.SetElementOverrides(element.Id, gSettings)
	TransactionManager.Instance.TransactionTaskDone()


margin = IN[0] #test at 0.5
collCond = FilteredElementCollector(doc, doc.ActiveView.Id).OfCategory(BuiltInCategory.OST_Conduit).WhereElementIsNotElementType().ToElements()


finalgroups = []
filterPassId = []
for conda in collCond:
	if conda.Id not in filterPassId:
		filterPassId.append(conda.Id)
		vecta = conda.Location.Curve.Direction
		templst = [conda]
		for condb in collCond:
			if conda.Id != condb.Id:
				vectb = condb.Location.Curve.Direction
				if vecta.IsAlmostEqualTo(vectb, 0.15) or vecta.IsAlmostEqualTo(vectb.Negate(), 0.15) :
					if nearCond(templst, condb):
						templst.append(condb)
						filterPassId.append(condb.Id)
		finalgroups.append(templst)		
		colorRamdom(templst, doc.ActiveView)		
			

OUT = finalgroups

you can delete the colorRamdom function if you don’t use it

3 Likes

Hi @c.poupin,

Thank you so much for taking time to help me solve this problem.
It works perfectly as intended on the file I shared.

However, it threw some unexpected results when I tested it on the other file shared below!


Test_Revit2019_2.rvt (2.4 MB)

corrected script
the margin is the max margin between conduits

#written by Cyril.P
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

clr.AddReference('RevitAPI')
import Autodesk
from Autodesk.Revit.DB import *
clr.AddReference('RevitServices')
import RevitServices
from RevitServices.Persistence import DocumentManager
from RevitServices.Transactions import TransactionManager
doc = DocumentManager.Instance.CurrentDBDocument
uiapp = DocumentManager.Instance.CurrentUIApplication

import sys
sys.path.append(r'C:\Program Files (x86)\IronPython 2.7\Lib')
import random

def nearCond(lstelemb, elema):
	global margin
	check = False
	curva = elema.Location.Curve
	midpta = elema.Location.Curve.Evaluate(0.5, True) 
	for elemb in lstelemb:
		curvb = elemb.Location.Curve
		if curvb.Project(midpta).Distance < margin:
			check = True
			break
	return check	

def getConduitParallal(collCond, conda):
	outLst = []
	curva = conda.Location.Curve
	vecta = conda.Location.Curve.Direction
	midptfun = lambda x : x.Location.Curve.Evaluate(0.5, True) 
	midpta = midptfun(conda)
	for condb in collCond:
		if conda.Id != condb.Id :
			vectb = condb.Location.Curve.Direction
			if vecta.IsAlmostEqualTo(vectb, 0.15) or vecta.IsAlmostEqualTo(vectb.Negate(), 0.15) :
				outLst.append(condb)
	if outLst:
		#sort element by distance
		outLst.sort(key = lambda x : curva.Project(midptfun(x)).Distance )	
	return outLst						
	
def colorRamdom(elements, view):
	TransactionManager.Instance.EnsureInTransaction(doc)
	rvtcolor = Color(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
	gSettings = OverrideGraphicSettings()
	gSettings.SetProjectionFillColor(rvtcolor)
	gSettings.SetProjectionLineColor(rvtcolor)
	gSettings.SetCutLineColor(rvtcolor)
	gSettings.SetCutFillColor(rvtcolor) 
	for element in elements:
		view.SetElementOverrides(element.Id, gSettings)
	TransactionManager.Instance.TransactionTaskDone()


margin = IN[0] #max margin between conduits
collCond = FilteredElementCollector(doc, doc.ActiveView.Id).OfCategory(BuiltInCategory.OST_Conduit).WhereElementIsNotElementType().ToElements()


finalgroups = []
filterPassId = []
for conda in collCond:
	if conda.Id not in filterPassId:
		filterPassId.append(conda.Id)
		vecta = conda.Location.Curve.Direction
		templst = [conda]
		elemsParall = getConduitParallal(collCond, conda)
		for condb in elemsParall:
			if nearCond(templst, condb):
				templst.append(condb)
				filterPassId.append(condb.Id)		
		finalgroups.append(templst)		
		colorRamdom(templst, doc.ActiveView)

OUT = finalgroups
2 Likes

Works like a charm.
Thank you :slight_smile: