Curve equal distance

Hello, i read in the old forum a post of @DavidRutten that Divide distance component places spheres on the curve which is very slow

I try another method to make it faster by using arcs and loop.
What i need now is help to improve this script to find all equal segments from the start to the end, so the loop will increase distance until the last point will equal or similar to the endpoint and break.
I don’t know if this will be easy or need more complex function?
I use k value to manually fix the problem

equal distance.gh (13.8 KB)

Something like that , it give more precise result but very slow

or this

equal distance.gh (12.4 KB)

Another way using extend curve but still very slow

Hi @anon39580149

Did you see this thread?

Hello @DanielPiker
Yes i use Kangaroo before from this thread, but because the actual component is very slow and i want try with Python or someone want try the ideas with c#.

This a little bit faster but the last value is not precise

import Rhino.Geometry as rg
import math
import rhinoscriptsyntax as rs

def intersection(A,B):
    events = rg.Intersect.Intersection.CurveCurve(A,B,0.001,0.001)
    for ccx in events:
        return ccx.PointA,ccx.ParameterB

def divide(curve,count):
    der = curve.DerivativeAt(0,1)[1]
    a = rg.Line(curve.PointAtStart,der).ToNurbsCurve()
    t = 0
    dist = 0
    points = []
    for i in range(count):
        dist = (curve.GetLength()/count)+k
        P = curve.FrameAt(t)[1]
        cir = rg.Circle(P,dist)
        intrv = rg.Interval(-math.pi/2,math.pi/2)
        a = rg.ArcCurve(rg.Arc(cir,intrv))
        intr = intersection(a ,curve)
        if not intr:
            break
        points.append(intr[0])
        t = intr[1]
            
    points.insert(0,curve.PointAtStart)
    points.Add(curve.PointAtEnd)
    return points

#points = divide(c,n)

k = 0
for i in range(100):
    points = divide(c,n+1)
    if len(points)-n == 2:
        k += 0.01

equal distance2.gh (6.4 KB)

Here as a cluster with the zombie solver inside. Takes less than 1ms to solve for segments equal to 7 digit accuracy.

equal_dist_pts.gh (10.8 KB)

image

2 Likes

Thank you @DanielPiker
Yes i already use kangaroo since long time and we talk about that in a thread about equal distance.
But i hope find another solution without Kangaroo to make it as python component.

Hi @anon39580149, sorry I misunderstood.

I thought you were saying solving this with Kangaroo was too slow and I wanted to show how to simplify it with the Zombie setup.

Anyway I think this should also be possible to solve quite fast with a Python script too.
If you find the distance error of the last segment, divide that by the segment count and add it to the radius and repeat the circle intersections, then just keep iterating that it should converge.

1 Like

Thanks , I tried with python to use loop but it stop , know there is a solution and i still trying.
This is a try to load Kangaroo component in Python, in Python it is very solw.

I’m not sure why calling it with NodeInCode in Python would be so slow.
Anyway, here’s an example of calling the solver directly in C#
equal_dist_pts_script.gh (19.8 KB)

image

//initialize the solver
    var ps = new KangarooSolver.PhysicalSystem();
    var goals = new List<IGoal>();

    var div = crv.DivideByCount(n, true);
    Polyline poly = new Polyline();
    for(int i = 0; i < n + 1;i++)
    {
      Point3d pt = crv.PointAt(div[i]);
      poly.Add(pt);
      ps.AddParticle(pt, 1);
    }
    goals.Add(new Anchor(crv.PointAtStart, 1e300));
    goals.Add(new Anchor(crv.PointAtEnd, 1e300));
    goals.Add(new OnCurve(poly.ToArray().ToList(), crv, 1));
    var segments = new List<Curve>();
    for(int i = 0; i < n;i++)
      segments.Add(poly.SegmentAt(i).ToNurbsCurve());
    goals.Add(new EqualLength(segments, 1));

    foreach(IGoal g in goals)
    {
      ps.AssignPIndex(g, 0.0001); 
//this combines coincident points into single particles and set the indexing for the goals
    }

    int counter = 0;
    int maxIter = 5000;
    double threshold = 1e-15;

    do
    {
      //Step forward, using these goals, stopping if the threshold or max iterations is reached
      ps.Step(goals, true, threshold);
      counter++;
    }
    while(ps.GetvSum() > threshold && counter < maxIter);

    A = new Polyline(ps.GetPositions());
3 Likes

Thank you @DanielPiker , appreciate your help.

Hi @DanielPiker
I remove counter, maxIter and change threshold to 1e-20, it work find and very precise result
Can you make it as component and add it to Kangaroo tab? this will be very useful.

Hi @anon39580149,

Glad to hear it is useful. Yes, we can look at adding this equal distance division as a standard component.

About removing maxIter - generally it’s safer to include some break out counter like this when calling Kangaroo from a script. In this example the system is simple and will probably always converge, but for other more complex setups with other goals there’s sometimes a danger that some input could result in a non-converging simulation that keeps oscillating forever (for example a simulation of a flag blowing in the wind).
With the regular Solver component you can just stop the solver in these situations, but if it is inside a While loop in a script, it would get stuck looping and you’d have to force quit Rhino.

You can choose to set this maxIter value to something huge to allow for long running simulations.

1 Like

Thank you @DanielPiker for the explanation, This also will be useful to study this equal distance division, i saw some researches about it long time ago but they don’t success to get precise equal segments.
I think Kangaroo is the first tool which solve this.

Hi @anon39580149 ,
Attached is a simple python script to find the distance for equi-division of the entire curve.
I hope it is useful to understand the basic concept.
Jess
DivideEntireCurveEquidistant_jM.py (1.5 KB)

1 Like

Thank you @Jess
I will try to convert it to GhPython code, and compare the result with Kangaroo result.


Hi @DanielPiker , I tried another method to load Kangaroo solver using Anders Deleuran example:

and it work fine, Python now looks faster than c#, i don’t use while in Python because it always block Grasshopper and Rhino.

equal dist kangaroo python.gh (11.0 KB)

2 Likes

When looking at timings of script components in gh, press f5 a couple of times. The first time a script runs after editing it, it will often take much longer. I get 5ms for both of those (and that’s to solve to 10 digit accuracy, which is surely far more than needed for any practical application).

This is a fairly simple sort of single value optimization though, so any iterative method will probably work well enough here.

1 Like

Hello @DanielPiker
The code work perfect with 3d curve but in this example with n = 4 the segments are not equal.

equal dist kangaroo python.gh (11.7 KB)

also with a curve from solution of @RIL (n = 216)

Grasshopper freeze and with less count the segments are not equal when the solution of @RIL work fine


Hi @Jess
I tried to use your script with GhPython but didn’t work , when i add output to the function return dist
the result always like regular divide distance component.
Can you show your result?

Yes, it’s easy enough to create curves with loops and bumps that are small relative to the size of the segments you are trying to divide it into where none of these methods will work.
I think there may also be curves/segment counts where absolutely no solution even exists.

The definition above that you say is freezing is your edited script with the counter and MaxIteration count removed. This is exactly why it was needed! (as explained in my earlier reply).
Running while loops with no breakout clause and with a condition that isn’t absolutely guaranteed to evaluate to true eventually is asking for trouble.

You can probably handle more of the pathological tightly kinking and looping cases with more checks on the parameter of the curve and choosing between multiple sphere-curve intersections (likely at some cost to the speed), but I don’t know if there’s any algorithm for this that would be guaranteed to work on any curve.

1 Like