public void ChangeLength(float newLength)
        {
            if (!rope.isLoaded)
            {
                return;
            }

            var solver = rope.solver;

            // clamp new length to sane limits:
            newLength = Mathf.Clamp(newLength, 0, (rope.sourceBlueprint.particleCount - 1) * rope.ropeBlueprint.interParticleDistance);

            // calculate the change in rope length:
            float lengthChange = newLength - rope.restLength;

            // remove:
            if (lengthChange < 0)
            {
                lengthChange = -lengthChange;

                while (lengthChange > m_CursorElement.restLength)
                {
                    lengthChange -= m_CursorElement.restLength;

                    int index = rope.elements.IndexOf(m_CursorElement);

                    if (index >= 0)
                    {
                        // positive direction:
                        if (direction)
                        {
                            RemoveParticleAt(solver.particleToActor[m_CursorElement.particle2].indexInActor);
                            rope.elements.RemoveAt(index);

                            if (index < rope.elements.Count)
                            {
                                if (rope.elements[index].particle1 == m_CursorElement.particle2)
                                {
                                    rope.elements[index].particle1 = m_CursorElement.particle1;
                                }

                                m_CursorElement = rope.elements[index];
                            }
                            else
                            {
                                m_CursorElement = rope.elements[Mathf.Max(0, index - 1)];
                            }
                        }
                        else // negative direction:
                        {
                            RemoveParticleAt(solver.particleToActor[m_CursorElement.particle1].indexInActor);
                            rope.elements.RemoveAt(index);

                            if (index > 0)
                            {
                                if (rope.elements[index - 1].particle2 == m_CursorElement.particle1)
                                {
                                    rope.elements[index - 1].particle2 = m_CursorElement.particle2;
                                }
                                m_CursorElement = rope.elements[index - 1];
                            }
                            else
                            {
                                m_CursorElement = rope.elements[0];
                            }
                        }
                    }
                }

                // the remaining length is subtracted from the current constraint:
                if (lengthChange > 0)
                {
                    m_CursorElement.restLength = Mathf.Max(0, m_CursorElement.restLength - lengthChange);
                }
            }
            // add
            else
            {
                float lengthDelta = Mathf.Min(lengthChange, Mathf.Max(0, rope.ropeBlueprint.interParticleDistance - m_CursorElement.restLength));

                // extend the current element, if possible:
                if (lengthDelta > 0)
                {
                    m_CursorElement.restLength += lengthDelta;
                    lengthChange -= lengthDelta;
                }

                // once the current element has been extended, see if we must add new elements, if there's enough particles left:
                while (rope.activeParticleCount < rope.sourceBlueprint.particleCount &&
                       m_CursorElement.restLength + lengthChange > rope.ropeBlueprint.interParticleDistance)
                {
                    // calculate added length:
                    lengthDelta   = Mathf.Min(lengthChange, rope.ropeBlueprint.interParticleDistance);
                    lengthChange -= lengthDelta;

                    if (direction)
                    {
                        // add new particle:
                        int newParticleSolverIndex = AddParticleAt(solver.particleToActor[m_CursorElement.particle1].indexInActor);

                        // set position of the new particle:
                        solver.positions[newParticleSolverIndex] = solver.positions[m_CursorElement.particle1] +
                                                                   (solver.positions[m_CursorElement.particle2] - solver.positions[m_CursorElement.particle1]) * lengthDelta;

                        // insert a new element:
                        ObiStructuralElement newElement = new ObiStructuralElement();
                        newElement.restLength     = lengthDelta;
                        newElement.particle1      = m_CursorElement.particle1;
                        newElement.particle2      = newParticleSolverIndex;
                        m_CursorElement.particle1 = newParticleSolverIndex;
                        int index = rope.elements.IndexOf(m_CursorElement);
                        rope.elements.Insert(index, newElement);

                        m_CursorElement = newElement;
                    }
                    else
                    {
                        // add new particle:
                        int newParticleSolverIndex = AddParticleAt(solver.particleToActor[m_CursorElement.particle2].indexInActor);

                        // set position of the new particle:
                        solver.positions[newParticleSolverIndex] = solver.positions[m_CursorElement.particle2] +
                                                                   (solver.positions[m_CursorElement.particle1] - solver.positions[m_CursorElement.particle2]) * lengthDelta;

                        // insert a new element:
                        ObiStructuralElement newElement = new ObiStructuralElement();
                        newElement.restLength     = lengthDelta;
                        newElement.particle1      = newParticleSolverIndex;
                        newElement.particle2      = m_CursorElement.particle2;
                        m_CursorElement.particle2 = newParticleSolverIndex;
                        int index = rope.elements.IndexOf(m_CursorElement);
                        rope.elements.Insert(index + 1, newElement);

                        m_CursorElement = newElement;
                    }
                }

                // the remaining length is added to the current constraint:
                if (lengthChange > 0)
                {
                    m_CursorElement.restLength += lengthChange;
                }
            }

            // recalculate rest positions and length prior to constraints (bend constraints need rest positions):
            rope.RecalculateRestPositions();
            rope.RecalculateRestLength();

            // rebuild constraints:
            rope.RebuildConstraintsFromElements();
        }