float GradientWRTShell(TelescopeShell shell, Vector3 targetPos)
        {
            // Changing the twist angle causes the end effector to move
            // along the tangent of the circle centered on the shell base.

            // First, compute the center of the circle.
            Vector3 shellBase    = shell.StartPointWS;
            Vector3 circleNormal = shell.StartTangentWS.normalized;

            Vector3 currentEndEff = segment.LastShell.EndPointWS;

            // The circle normal remains the same, but is shifted so that
            // the current end effector is in the plane.
            Vector3 fromEnd      = shellBase - currentEndEff;
            Vector3 nonPlanar    = Vector3.Dot(fromEnd, circleNormal) * circleNormal;
            Vector3 circleCenter = currentEndEff + (fromEnd - nonPlanar);

            // The gradient is then the cross product of the current end position
            // and the desired end position. This gives the axis of rotation
            // required to move it there.
            Vector3 centerToCurrent = currentEndEff - circleCenter;
            Vector3 currentToTarget = targetPos - currentEndEff;

            Vector3 axis = Vector3.Cross(centerToCurrent, currentToTarget);

            // We can only rotate about the fixed shell axis, however,
            // so the dot product gives the contribution from this axis.
            return(Vector3.Dot(circleNormal, axis));
        }
        void AddGradientToTelescope(List <float> angles)
        {
            // Apply first telescope separately
            float firstAngle = angles[0];

            if (FreezeFirst)
            {
                firstAngle = 0;
            }

            // Since the first telescope is free, we just apply rotation about the tangent
            Vector3    firstTangent  = segment.shells[0].transform.forward;
            Quaternion firstRotation = Quaternion.AngleAxis(firstAngle, firstTangent);

            segment.shells[0].transform.rotation = firstRotation * segment.shells[0].transform.rotation;

            // For the rest, just add to the twist angle
            for (int i = 1; i < angles.Count; i++)
            {
                TelescopeShell s = segment.shells[i];
                s.twistAngle = Mathf.Repeat(s.twistAngle - angles[i], 360);
                if (s.twistAngle > 180)
                {
                    s.twistAngle -= 360;
                }
            }
        }
        // Update is called once per frame
        void LateUpdate()
        {
            if (Input.GetKeyDown("i"))
            {
                meshRenderer.enabled = true;
                segment = FindObjectOfType <TelescopeSegment>();
                if (segment)
                {
                    TelescopeShell shell = segment.LastShell;
                    transform.parent = shell.transform;
                    segment.MinExt   = 0.35f;

                    segment.ExtendImmediate(0);
                }
            }

            if (Input.GetKeyDown("2"))
            {
                SplineCanvas c = FindObjectOfType <SplineCanvas>();
                c.ReloadFromFile("rescue.canvas");
            }

            if (Input.GetKeyDown("1"))
            {
                animator.SetTrigger("toggle-close");
                if (!rescued)
                {
                    rescued = true;
                    teddyBear.transform.parent = transform;
                }
                else
                {
                    teddyBear.transform.parent = null;
                    teddyBear.activate         = true;
                    CameraControl cc = Camera.main.GetComponent <CameraControl>();
                    cc.FreeMove();
                }
            }
        }