Join Point at Borders

Hello everyone. How can I make this polyline with 90-degree and external borders? I tried to make it with clockwise. But I can not.
Thanks

Hi @yaseminV2XL5 ,

You probably want to use an alpha shape algorithm

3 Likes

Hello @yaseminV2XL5 - Just curious, do you have the grey surface already? If so, that should be easy to pull with the Surface.PerimeterCurves node, if it’s a PolySurface made of multiple surfaces, you can then Thicken it, and intersect with a Plane to get the combined surface, and then pull the PerimeterCurves.

1 Like

Hallo @solamour .Yes, I have the grey surface. But I don’t want areas that are triangular.

Ah gotcha - Here is one way to do it :slight_smile:

  • Get Perimeter curves of original surface
  • Run a Python based Delaunay algorithm that uses Numpy and Scipy
  • FIlter out all diagonal lines, leaving only vertical and horizontal
  • Use TSplines to build surfaces from these individual, unorganized pipes

This doesn’t automate the process though, and requires you to tweak on two places - the Delaunay alpha threshold, and the TSpline maxFaceValence.

YaseminV2XL5_AlphaShape_to_remove_Diagonal_Lines.dyn (50.4 KB)

2 Likes

Hi @solamour ,

Nice solution!! If you don’t mind, I’d like to sharpen your explanation a bit :slight_smile:
A delaunay triangulation is a completely separate thing from an alpha shape algorithm.

A Delaunay triangulation, as it says, triangulates points in such a way that no points fall within the circumcircle of three points making up a triangle. This would then ideally result in a triangulation with ‘nicer’ triangles, meaning not long/ stretched.

The alpha shape algorithm uses the threshold you’re talking about. This would be the radius of the search circle that you’re using to cut away the shape. I always think of it like a foam shape where the points are rocks that cannot be cut away. Having a really big alpha shape threshold therefore actually results in the convex hull.

3 Likes

It’s amazing. It works very well. Thank you very much @solamour for your answer and for your time. It shows how important the methods in geometry are.

2 Likes

Thanks @Daan for your answer

You are most welcome @yaseminV2XL5 :smiley: Glad it works for you!

1 Like

Here is an alternative implementation in Python, a brute force approach nonetheless, returning the boundary that minimizes the ratio between perimeter and enclosed area.

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


points = [
    Point.ByCoordinates(1, 0),
    Point.ByCoordinates(2, 0),
    Point.ByCoordinates(2, 1),
    Point.ByCoordinates(3, 1),
    Point.ByCoordinates(3, 2),
    Point.ByCoordinates(3, 3),
    Point.ByCoordinates(2, 3),
    Point.ByCoordinates(2, 2),
    Point.ByCoordinates(1, 2),
    Point.ByCoordinates(0, 2),
    Point.ByCoordinates(0, 1),
    Point.ByCoordinates(1, 1)
]

def sort(data: Iterable[Point], i: int = 0) -> Iterable[Point]:
    current = data.pop(i)
    ret = [current]
    xaxis = Vector.ByCoordinates(1, 0).Normalized()
    vec = xaxis
    length = 0
    while len(data) > 0:
        closest = {}
        for p in data:
            d = p.DistanceTo(current)
            closest.setdefault(d, []).append(p)
        q = min(closest)
        candidates = closest[q]
        if len(candidates) > 1:            
            target = sorted(candidates, key=lambda k: Vector.ByTwoPoints(current, k).Dot(vec) * vec.Dot(xaxis))[0]
        else:
            target = candidates[0]
        data.pop(data.index(target))        
        vec = Vector.ByTwoPoints(current, target)
        length += vec.Length
        current = target
        
        ret.append(current)
        
    
    return ret, length


def main(data: Iterable[Point]) -> PolyCurve:
    pts = [p for p in data]
    random.shuffle(pts)    
    
    solutions = {}
    for i in range(len(pts)):
        sequence, length = sort([p for p in pts], i)
        c = Polygon.ByPoints(sequence)
        if len(c.SelfIntersections()) > 0:
            continue
        s = 0
        try:
            s = c.Patch().Area
        except:
            continue
        if s == 0:
            continue
                
        solutions.setdefault(length / s, []).append(sequence)
    length = min(k for k in solutions)
    candidates = solutions[length][0]
    return length, candidates, PolyCurve.ByPoints(candidates, True)



OUT = main(points)
4 Likes