2
\$\begingroup\$

I am trying to update the path of a chain (currently being stored in my code as a array of points) by moving one end of it up. I need the start of the chain to remain fixed in its location and the end up will be moving upwards.

The chain is a series of links that are rigid and have roughly 20-30 degrees of available bend/movement between each link. The array of points is ordered so that the first entry is the point that will be moving up, and the last point is fixed.

I started by creating the chain in its default state: Initial chain link locations

I've created a method moveUp that takes in the points, how high to move the last point up to and a step for how much movement per iteration of the loop defined in the method. My logic for the method is basically:

  1. Loop until the first point has reached the correct height
  2. If it's the very first point, just move it up by step
  3. If the distance between the previous point and next point is step then I break the loop.
  4. If the distance between the previous point and the next point is greater than step*2 then I move the point to be a distance of step from the previous point
  5. If the distance between the previous and next is less than step*2 then I create a circle on previous and next with a radius of step and use the intersection of these circles to find where to move the point to. (since there can be 2 intersects, I just pick the one that is closer to the original point). Once this step has ran I tell the loop to break after updating the point, since everything after that should not need to move.

Until the chain uncoils a bit on the right side, everything works: Moved up 10 inches But once I go much more then this, the chain starts to "pull away" from the fixed point on the left: Pulling away

How can I update my logic/method to make it so this won't pull away from the fixed point and give me a decent looking path for my chain? Here is the code below for the moveUp method (note this uses a custom programming language, so if something is not clear in the below snippet, let me know I can clarify):

private point2D[] moveUp( point2D[] original, double height, double step=0.75inch ) {
    if ( original.any() ) {
        int count = 0;
        while( height - original.first.y >= step ) {
            count++;
            if ( count > 100 ) {
                pln("Too many iterations...");
                break;
            }
            bool shouldStop = false;
            for( p in original, index=i ) {
                point2D old = p;

                if ( i=0 ) {
                    p = p + (0,step);
                } else {
                    if ( !last ) {
                        point2D prev = original[i-1];
                        point2D next = original[i+1];

                        line2D l( prev, next );

                        if ( l.length() == step ) {
                            break;
                        } else if ( l.length() > step*2 ) {
                            l.extendP0(-step);
                            p = l.p0;
                        } else {
                            circle prevC( prev, 0.75inch );
                            circle nextC( next, 0.75inch );

                            var intersect = this.ins(prevC,nextC);

                            if ( intersect.count == 0 ) {
                                pln("No intersection found...".eAngry);
                            } else {
                                point2D choice = intersect.p0;
                                if ( intersect.count > 1 ) {
                                    double distP0 = p.distance(choice);
                                    double distP1 = p.distance(intersect.p1);
                                    if ( distP1 < distP0 ) {
                                        choice = intersect.p1;
                                    }
                                }

                                p = choice;
                                shouldStop = true;
                            }
                        }
                    }
                }

                original[i] = p;
                if ( shouldStop ) { break; }
            }
        }
    }

    return original;
}
\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

You need to consider how your algorithm handles tension in the chain — when it's stretched, what happens?

If the distance between the previous point and the next point is greater than step*2 then I move the point to be a distance of step from the previous point

This element of the algorithm always favors "previous" points. The last point never gets to contribute any "force" towards itself, so all the other points pull away from it.

Instead, try moving the point to be at the midpoint between the adjacent points. This will give a closer to realistic result.


Another factor causing asymmetry in your algorithm is that when you are checking the points' positions, the "previous" point is always one that has already been updated, and the "next" point is always one that has not yet been updated.

To fix this, don't assign to the points in original — only read positions from it, and use a separate array to return the new positions. Thus, the order in which you compute the points' updates doesn't affect the result.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .