Create loops on corners

Hi

I wonder if there is a way to create loops or arcs around cornered shapes. The corners here have been extended to create a balloon shape so that the curve should be harmonious, is there a way to place an arc between the end points of the extended curves? Similar to this exemple from silhuette studio called
“smart loops”

Thanks


smart loops.gh (11.3 KB)

Hi,

You can simply draw arcs at the extended line ends.

smart loops v2.gh (11.6 KB)

3 Likes

Thank you so much! That does the trick!

Hi

Just a follow-up on this subject

If I only want the loops to be on the outside of the shape here, I used region difference to get rid of the internal loops, however, the curve is not connected anymore, how can I remove the inner loops while being able to reconnect it into one curve?


Loops connect.gh (8.9 KB)

Hi,

It’s been awhile. :slight_smile:

You can differentiate between convex and concave corners of a closed polyline by calculating the two-dimensional vector cross product of adjacent edges as vectors of a given corner.
The cross product returns a scalar value that if negative means that the corner is concave, and if positive, it is convex.

I failed to do this in Grasshopper with vanilla components because of too much tree shenanigans. My brain is currently fried by COVID-19. :face_with_medical_mask:

However, I succeeded with a GHPython script, which loops through the polyline vertices, which is much simpler than doing this with trees, where everything happens at once, so to speak:

prev_pt = rg.Point3d.Unset  # prev point to connect to
crv = rg.PolyCurve()

for i in range(P.Count-1):
    curr_vtx = P[i]

    vec1 = P[(i-1)%(P.Count-1)] - curr_vtx
    vec1.Unitize()
    vec2 = P[(i+1)%(P.Count-1)] - curr_vtx
    vec2.Unitize()

    cross = rg.Vector3d.CrossProduct(vec2, vec1)
    if cross.Z > 0.0:  # convex vertex/corner
        start_pt = curr_vtx - vec1 * O
        end_pt = curr_vtx - vec2 * O

        if prev_pt != rg.Point3d.Unset:
            ln = rg.Line(prev_pt, start_pt)
            crv.Append(ln)

        arc = rg.Arc(start_pt, -vec1, end_pt)
        crv.Append(arc)
        prev_pt = end_pt

    else:  # concave vertex/corner
        if prev_pt == rg.Point3d.Unset:
            prev_pt = curr_vtx
            continue

        ln = rg.Line(prev_pt, curr_vtx)
        crv.Append(ln)
        prev_pt = curr_vtx

crv.Append(rg.Line(crv.PointAtEnd, crv.PointAtStart))  # close the polycurve

# Output
C = crv

smart loops v3.gh (11.4 KB)

1 Like

Thank you, hope you feel better soon! This looks like it works, I work with Rhino 7 atm, so can’t open it, but it looks like what I was looking for

Thanks.

I don’t have Rhino 7 installed any more, but you can try the following to make it work.

You can simply create a GHPython component in Grasshopper in Rhino 7.
Rename inputs x and y to P and O. Then set the type hint of P to “Polyline” and that of O (i.e. offset) to “float” by right-clicking on the relevant input and selecting “Type Hint > …”.
Then rename output a to C, double-click the GHPython component to open the script editor, and copy and paste the following code inside:

import Rhino.Geometry as rg
import Grasshopper as gh


if P is not None:
    if O is not None and O > 0.0:   
        prev_pt = rg.Point3d.Unset  # prev point to connect to
        crv = rg.PolyCurve()

        for i in range(P.Count-1):
            curr_vtx = P[i]

            vec1 = P[(i-1)%(P.Count-1)] - curr_vtx
            vec1.Unitize()
            vec2 = P[(i+1)%(P.Count-1)] - curr_vtx
            vec2.Unitize()

            cross = rg.Vector3d.CrossProduct(vec2, vec1)
            if cross.Z > 0.0:  # convex vertex/corner
                start_pt = curr_vtx - vec1 * O
                end_pt = curr_vtx - vec2 * O

                if prev_pt != rg.Point3d.Unset:
                    ln = rg.Line(prev_pt, start_pt)
                    crv.Append(ln)

                arc = rg.Arc(start_pt, -vec1, end_pt)
                crv.Append(arc)
                prev_pt = end_pt

            else:  # concave vertex/corner
                if prev_pt == rg.Point3d.Unset:
                    prev_pt = curr_vtx
                    continue

                ln = rg.Line(prev_pt, curr_vtx)
                crv.Append(ln)
                prev_pt = curr_vtx

        crv.Append(rg.Line(crv.PointAtEnd, crv.PointAtStart))  # close the polycurve

        # Output
        C = crv
    else:
        # Output
        C = P
else:
    ghenv.Component.AddRuntimeMessage(
        gh.Kernel.GH_RuntimeMessageLevel.Warning, 
        "Parameter P failed to collect data"
    )

I hope this helps.

1 Like

Thank you, I will try this