Surface Outline without inner cutouts / holes / whatsover

Hi everyone,
I try to get the outline of a surface. This one is the uppermost surface of a “ceiling-solid”. It is my goal to get just the ceiling outlines, but the Element.Sketch Node does not work the way I would like it to work :slight_smile:

I get a list of curves which looks like this:


Unfortunately the “Polycurve.ByJoinedCurves” cannot figure out which curves have to be connected.
For this reason I compare Start and End Points to match connecting Lines into a List and Split the list by index.

After that I get the area of every surface and take the one with the largest area.

This whole process is really heavy, unpractial und does not work really nice. Has anyone an idea how to solve this in a better way?

Thanks and kind regards,
Jannis
_surface_problem.dyn (27.5 KB)

I did a similar task a while back using python set operations to find the lines that share a point (set intersection) and grouping them. Another similar approach can be finding the lines that physically intersect and grouping them. Your solution is good enough though; I would use Curve Length node on the polycurves to find the outer polycurve instead of patching surfaces and getting the area of the surface.

1 Like

If your floor is flat than you could get loops separately from the top face of the element.
I suspect the first loop is the main outline, but you could check lengths to be sure.

import clr

#The inputs to this node will be stored as a list in the IN variables.
floors = UnwrapElement(IN[0])

clr.AddReference("RevitAPI")
from Autodesk.Revit.DB import *

clr.AddReference("RevitServices")
import RevitServices
from RevitServices.Persistence import DocumentManager

clr.AddReference("RevitNodes")
import Revit
clr.ImportExtensions(Revit.GeometryConversion)

doc = DocumentManager.Instance.CurrentDBDocument

output = []

for f in floors:
	curve_list = []
	top_face_refs = HostObjectUtils.GetTopFaces(f)
	#get all edges
	for face_ref in top_face_refs:
		face = doc.GetElement(face_ref).GetGeometryObjectFromReference(face_ref)
		if not face is None:
			loops = []
			edge_arrays = face.EdgeLoops
			for edges in edge_arrays:
				loop = []
				for e in edges:
					c = e.AsCurve()
					loop.append(c.ToProtoType())
				loops.append(loop)
			curve_list.append(loops)	
			
	output.append(curve_list)				


#Assign your output to the OUT variable.
OUT = output
2 Likes

Hey :slight_smile: Thanks for your help. In 99.999% of the cases you are correct, but if someone creates a real complex inner cutting it could be possible that the line is longer than the outline.

Awesooomme :wink: Thanks a lot. This works way better than the Element.Sketch :slight_smile: Element.Sketch created some outlines on false heights in there was an offset from surface.

Kind regards,
Jannis

Edit:
Actually it´s not the first line, but after joining them to polylines I sorted them by length and took the longest (I take the risk of complex cutouts which are longer than the outer curve as supposed by habdirad.
This is my code to sort by length and take the first item :slight_smile:

curves = IN[0]
length = IN[1]
OUT = []
for c,l in zip(curves,length):
	curveLength = l[:]
	curveLength.sort()
	curveLength.reverse()
	index = l.index(curveLength[0])
	OUT.append(c[index])
1 Like