Exemple #1
0
        ///***************************************************************************************
        /// CalcIK_2D_ConstraintRelaxation_ConvertToWorld
        /// This is a helper function to generate a world space bone chain for relaxation given
        /// a local space bone chain.
        ///***************************************************************************************
        public static void CalcIK_2D_ConstraintRelaxation_ConvertToWorld
        (
            out List <Bone_2D_ConstraintRelaxation_World> worldBones,            // Output world space bones
            List <Bone_2D_ConstraintRelaxation> localBones                       // Input local space bones
        )
        {
            int numBones = localBones.Count;

            //Debug.Assert (numBones > 0);

            // create the list to output
            worldBones = new List <Bone_2D_ConstraintRelaxation_World> ();

            // Start with the root bone.
            Bone_2D_ConstraintRelaxation_World rootWorldBone
                = new Bone_2D_ConstraintRelaxation_World();

            rootWorldBone.x      = 0;
            rootWorldBone.y      = 0;
            rootWorldBone.length = localBones [0].length;
            rootWorldBone.weight = localBones [0].weight;
            worldBones.Add(rootWorldBone);

            double prevAngle    = localBones [0].angle;
            double prevAngleCos = Math.Cos(prevAngle);
            double prevAngleSin = Math.Sin(prevAngle);

            // Convert child bones to world space.
            for (int boneIdx = 1; boneIdx < numBones; ++boneIdx)
            {
                Bone_2D_ConstraintRelaxation_World prevWorldBone = worldBones [boneIdx - 1];
                Bone_2D_ConstraintRelaxation       prevLocalBone = localBones [boneIdx - 1];

                Bone_2D_ConstraintRelaxation_World newWorldBone
                                    = new Bone_2D_ConstraintRelaxation_World();
                newWorldBone.x      = prevWorldBone.x + prevAngleCos * prevLocalBone.length;
                newWorldBone.y      = prevWorldBone.y + prevAngleSin * prevLocalBone.length;
                newWorldBone.length = localBones [boneIdx].length;
                newWorldBone.weight = localBones [boneIdx].weight;
                worldBones.Add(newWorldBone);

                prevAngle    = prevAngle + localBones [boneIdx].angle;
                prevAngleCos = Math.Cos(prevAngle);
                prevAngleSin = Math.Sin(prevAngle);
            }
        }
Exemple #2
0
        ///***************************************************************************************
        /// CalcIK_2D_ConstraintRelaxation
        /// Given a bone chain located at the origin, this function will perform a single
        /// relaxation iteration. This finds a solution of bone angles that places the final bone
        /// in the given chain at a target position. The supplied bone angles are used to prime
        /// the iteration. If a valid solution does not exist, the angles will move as close to
        /// the target as possible. The user should resupply the updated angles until a valid
        /// solution is found (or until an iteration limit is met).
        ///***************************************************************************************
        public static void CalcIK_2D_ConstraintRelaxation
        (
            ref List <Bone_2D_ConstraintRelaxation_World> bones, // Bone values to update
            double targetX,                                      // Target x position for the end effector
            double targetY                                       // Target y position for the end effector
        )
        {
            // Set an epsilon value to prevent division by small numbers.
            const double epsilon = 0.0001;

            int numBones = bones.Count;

            //Debug.Assert (numBones > 0);

            //===
            // Constrain the end bone to the target.
            {
                int    boneIdx        = numBones - 1;
                double toTargetX      = targetX - bones [boneIdx].x;
                double toTargetY      = targetY - bones [boneIdx].y;
                double toTargetLenSqr = toTargetX * toTargetX + toTargetY * toTargetY;
                if (toTargetLenSqr > epsilon)
                {
                    double toTargetLen   = Math.Sqrt(toTargetLenSqr);
                    double toTargetScale = (bones [boneIdx].length / toTargetLen) - 1.0;
                    bones [boneIdx].x -= toTargetScale * toTargetX;
                    bones [boneIdx].y -= toTargetScale * toTargetY;
                }
            }

            //===
            // Perform relaxation on the bones in a loop from the final bone to the first child
            // bone.
            for (int boneIdx = numBones - 2; boneIdx >= 1; --boneIdx)
            {
                Bone_2D_ConstraintRelaxation_World curBone   = bones [boneIdx];
                Bone_2D_ConstraintRelaxation_World childBone = bones [boneIdx + 1];

                // Get the vector from the current bone to the child bone.
                double toChildX = childBone.x - curBone.x;
                double toChildY = childBone.y - curBone.y;

                double toChildLenSqr = toChildX * toChildX + toChildY * toChildY;
                double totalWeight   = curBone.weight + childBone.weight;
                if (toChildLenSqr > epsilon && totalWeight > epsilon)
                {
                    double toChildLen   = Math.Sqrt(toChildLenSqr);
                    double toChildScale =
                        ((bones [boneIdx].length / toChildLen) - 1.0) / totalWeight;
                    double curBoneScale   = toChildScale * curBone.weight;
                    double childBoneScale = toChildScale * childBone.weight;

                    curBone.x -= curBoneScale * toChildX;
                    curBone.y -= curBoneScale * toChildY;

                    childBone.x += childBoneScale * toChildX;
                    childBone.y += childBoneScale * toChildY;
                }
            }

            //===
            // Constrain the first child joint to the root joint
            if (numBones > 1)
            {
                int boneIdx = 0;

                // Get the vector from the current bone to the child bone.
                double toChildX = bones [boneIdx + 1].x - bones [boneIdx].x;
                double toChildY = bones [boneIdx + 1].y - bones [boneIdx].y;

                double toChildLenSqr = toChildX * toChildX + toChildY * toChildY;
                if (toChildLenSqr > epsilon)
                {
                    double toChildLen   = Math.Sqrt(toChildLenSqr);
                    double toChildScale = (bones [boneIdx].length / toChildLen) - 1.0;

                    bones [boneIdx + 1].x += toChildScale * toChildX;
                    bones [boneIdx + 1].y += toChildScale * toChildY;
                }
            }
        }
Exemple #3
0
        ///***************************************************************************************
        /// CalcIK_2D_ConstraintRelaxation_ConvertToWorld
        /// This is a helper function to generate a world space bone chain for relaxation given
        /// a local space bone chain.
        ///***************************************************************************************
        public static void CalcIK_2D_ConstraintRelaxation_ConvertToWorld(
			out List<Bone_2D_ConstraintRelaxation_World> worldBones, // Output world space bones
			List<Bone_2D_ConstraintRelaxation>           localBones  // Input local space bones
		)
        {
            int numBones = localBones.Count;
            //Debug.Assert (numBones > 0);

            // create the list to output
            worldBones = new List<Bone_2D_ConstraintRelaxation_World> ();

            // Start with the root bone.
            Bone_2D_ConstraintRelaxation_World rootWorldBone
            = new Bone_2D_ConstraintRelaxation_World ();
            rootWorldBone.x = 0;
            rootWorldBone.y = 0;
            rootWorldBone.length = localBones [0].length;
            rootWorldBone.weight = localBones [0].weight;
            worldBones.Add (rootWorldBone);

            double prevAngle = localBones [0].angle;
            double prevAngleCos = Math.Cos (prevAngle);
            double prevAngleSin = Math.Sin (prevAngle);

            // Convert child bones to world space.
            for (int boneIdx = 1; boneIdx < numBones; ++boneIdx) {
                Bone_2D_ConstraintRelaxation_World prevWorldBone = worldBones [boneIdx - 1];
                Bone_2D_ConstraintRelaxation prevLocalBone = localBones [boneIdx - 1];

                Bone_2D_ConstraintRelaxation_World newWorldBone
                = new Bone_2D_ConstraintRelaxation_World ();
                newWorldBone.x = prevWorldBone.x + prevAngleCos * prevLocalBone.length;
                newWorldBone.y = prevWorldBone.y + prevAngleSin * prevLocalBone.length;
                newWorldBone.length = localBones [boneIdx].length;
                newWorldBone.weight = localBones [boneIdx].weight;
                worldBones.Add (newWorldBone);

                prevAngle = prevAngle + localBones [boneIdx].angle;
                prevAngleCos = Math.Cos (prevAngle);
                prevAngleSin = Math.Sin (prevAngle);
            }
        }