Subtract lines

A few hundred shouldn’t be too taxing. The gpt code you got looks fine, a neat gpt trick is to feed the code back into gpt and ask it to parallelize it. Also there is some optimization to be had if you can preprocess the line list in smaller search buckets, e.g. group them by z, group them by direction, only run the intersection check n/k^n/k times rather than n^n (where k is number of groups)

throw the optimization suggestions in gpt, it should be able to handle the changes fine.

1 Like

Ah - you’re right. Surface.ByUnion might be a better solution here. I do recall having a fox for such issues via topology methods, just not entirely sure what it was.

I also find with GPT that it varys from day to day… It’s like a human. Some days I get great responses, other days I end up swearing at it and writing the code all myself. :rofl:

1 Like

Gave it a test and it looks like the PolySurface.ByJoinedSurfaces will in fact split the edges the condition you outlined.

If you disable the highlighting cylinder (rightmost nodes) for either the ‘bounding two faces’ or the ‘bounding one face’ curves the result is pretty clear.

My guess is that in your case there were slight gaps or perhaps errors in the modeling / geometry conversion (perhaps large units at play?), which lead to conditions where you had overlapping our unconnected vertices. If they deviate from the adjacent curve in any way you get the error you described.

3 Likes

So I tried asking GPT to parallelise it…

And this happened:


(It opened a second Revit)

:rofl: :rofl: :rofl:

Well… I suppose that’s one way of doing it.

1 Like

NICE! I wish I had known this earlier. I’m for sure filing this away, this is super helpful for my work.

2 Likes

Interesting topic

here my solution

# Load the Python Standard and DesignScript Libraries
import sys
import clr
clr.AddReference('ProtoGeometry')
from Autodesk.DesignScript.Geometry import *

import itertools


def group_lines(lines, incr = 0):
    """
    Group overlapping lines together.

    Parameters:
    lines (list): List of Autodesk.DesignScript.Geometry.Line objects to group.
    incr (int): Recursion increment counter.

    Returns:
    list: List of grouped lines.
    """
    if len(lines) == 0 or incr > 1000 :
        return []
    group = [lines.pop(0)]
    idx_to_remove = []
    for idx, line in enumerate(lines):
        if any(lines_are_overlap(line, x) for x in group):
            group.append(line)
            idx_to_remove.append(idx)
    rest = [line for idx, line in enumerate(lines) if idx not in idx_to_remove]
    return [group] + group_lines(rest, incr + 1)

def lines_are_overlap(lineA, lineB):
    """
    Check if two lines overlap with each other.

    Parameters:
    lineA (Autodesk.DesignScript.Geometry.Line): First line to check for overlap.
    lineB (Autodesk.DesignScript.Geometry.Line): Second line to check for overlap.

    Returns:
    bool: True if lines overlap, False otherwise.
    """
    # make sure the lineA is the longest
    if lineB.Length > lineA.Length:
        lineA, lineB = lineB, lineA
    if abs(lineA.Direction.Cross(lineB.Direction).Z) < 0.01:
        lstptsB = [lineB.StartPoint, lineB.EndPoint]
        for pt in lstptsB:
            # if lines are overlapped
            if abs((pt.DistanceTo(lineA.EndPoint) + pt.DistanceTo(lineA.StartPoint)) - lineA.Length) < 0.001:
                return True
    return False
    
def subract_lines_overlap2(lines):
    """
    Subtract overlapping lines from the input list.

    Parameters:
    lines (list): List of Autodesk.DesignScript.Geometry.Line objects to process.

    Returns:
    list: List of non-overlapping lines.
    """
    out = []
    groups_lines = group_lines(lines)
    #return groups_lines
    for group_line in groups_lines:
        if len(group_line) > 1:
            pts = [[l.StartPoint, l.EndPoint] for l in group_line]
            # flat the list
            pts = sum(pts, [])
            base_line = Line.ByBestFitThroughPoints(pts)
            pts.sort(key = lambda p : base_line.ParameterAtPoint(p))
            iter_pts = iter(pts)
            for pta, ptb in zip(iter_pts, iter_pts):
                if pta.DistanceTo(ptb) > 0.01:
                    out.append(Line.ByStartPointEndPoint(pta, ptb))
        else:
            out.extend(group_line)
    return out
    
lines = IN[0]

OUT = subract_lines_overlap2(lines)
4 Likes

Maybe you could try using Shapely.

Here’s a different solution:


4 Likes

loop1 = Polygon.ByPoints(Point.ByCoordinates([0,0,20,20],[0,20,20,0]));
loop2 = Polygon.ByPoints(Point.ByCoordinates([0,0,50,50],[0,50,50,0]));
lines3 = List.Flatten([loop1.Explode(),loop2.Explode()],-1);
vertex1 = List.Flatten(lines3<1>.PointAtParameter(0..1),-1);
vertex2 = List.Flatten(Point.PruneDuplicates(vertex1,0.01),-1);
lines4 = List.Flatten(lines3.SplitByPoints(vertex2),-1);
lines5 = List.GroupByKey(lines4,lines4.StartPoint)["groups"];
lines6 = List.GroupByKey(lines5<1>,lines5.EndPoint<1>)["groups"];
lines7 = List.FilterByBoolMask(lines6,List.Count(lines6<1><2>)>1)["out"];
nonOverlappingLines = List.Flatten(lines7,-1);
6 Likes