0
\$\begingroup\$

I have some problems with hinge joint chain movement calculations...

Here is my algorithm for segments location/rotation adjustments after a previous segment update (C#):

void AdjustLocation()
{
    float halfWidth = Size.Width / 2;
    
    // Translations
    Vector parentBack = PrevSegment.Center - (halfWidth * new Vector(Cos(PrevSegment.Rotation), Sin(PrevSegment.Rotation))); // Green on the pic
    Vector front = this.Center + (halfWidth * new Vector(Cos(this.Rotation), Sin(this.Rotation))); // Blue on the pic
    
    // Const spacing between segments
    float spacing = *some_value*;
    
    Vector dv = parentBack - front;
    float k = spacing / dv.Length;
    
    // New front location
    front = parentBack - (dv * k);
    // New rotation
    dv = front - this.Center;
    this.Rotation = Atan2(dv.Y, dv.X);
    
    // Translate back to the center
    this.Center = front - (halfWidth * new Vector(Cos(this.Rotation), Sin(this.Rotation)));
    
    NextSegment?.AdjustLocation();
}

It's working (partially), but it seems I'm missing something as it doesn't behave like a chain. Segments always move one by another although they should not always do this. Also overlapped sections of a long chain form a "knot" going all the way to the end of the chain before its "untangling". What am I missing?

Btw: everything screws up with negative spacing values.

P.S. Tried to visualize the algorithm on the picture: img

\$\endgroup\$
0
1
\$\begingroup\$

I figured it out myself.

void AdjustLocation()
{
    float halfWidth = Size.Width / 2;

    // Current segment back positions
    Vector offset = (halfWidth * new Vector(Cos(this.Rotation), Sin(this.Rotation)));
    Vector backPos = this.Center - offset;

    Vector newFrontPos;
    if (SegmentsSpacing > 0)
    {
        // Current segment front position
        Vector frontPos = this.Center + offset;

        // Parent segment back position
        offset = (halfWidth * new Vector(Cos(PrevSegment.Rotation), Sin(PrevSegment.Rotation)));
        Vector parentBackPos = PrevSegment.Center - offset;

        // Find delta
        Vector dv = parentBackPos - frontPos;
        float k = SegmentsSpacing / dv.Length;

        // Calculate new front position
        newFrontPos = parentBackPos - (dv * k);
    }
    else
    {
        // Calculate new front position
        offset = ((halfWidth + SegmentsSpacing) * new Vector(Cos(PrevSegment.Rotation), Sin(PrevSegment.Rotation)));
        newFrontPos = PrevSegment.Center - offset;
    }

    // Calculate new rotation
    Vector dv = newFrontPos - backPos;
    this.Rotation = Atan2(dv.Y, dv.X);
    // Translate back to center
    this.Center = newFrontPos - (halfWidth * new Vector(Cos(this.Rotation), Sin(this.Rotation)));

    NextSegment?.AdjustLocation();
}

My mistake was that I calculated the rotation using wrong points (it should be equal to the angle between the new front position and the old back position of a segment).
As for spacing, everything's much simplier with negative values (because you can simply move the front position of a segment to the joint position), otherwise, you must find the correct point on the line between the front position of a segment and the back position of its parent segment.

\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.