Example #1
0
            public static void GetMaxError(KeyAnalyzer line, KeyAnalyzer newKeys, out float error, out int index)
            {
                var fcount = Math.Min(newKeys.FrameCount, line.FrameCount);

                error = 0;
                index = -1;

                for (int i = 0; i < fcount; i++)
                {
                    var orgValue = line.GetValue(i);
                    var newValue = newKeys.GetValue(i);
                    var er       = Math.Abs(newValue - orgValue);

                    if (er > error)
                    {
                        error = er;
                        index = i;
                    }
                }
            }
Example #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="values"></param>
        public static List <FOBJKey> Simplify(List <FOBJKey> keys, float maxError)
        {
            // check constant key track{
            {
                bool keyTrack = true;
                for (int i = 1; i < keys.Count; i++)
                {
                    if (Math.Abs(keys[i].Value - keys[0].Value) > 0.001f)
                    {
                        keyTrack = false;
                        break;
                    }
                }
                if (keyTrack)
                {
                    var key = keys[0];
                    key.InterpolationType = HSDRaw.Common.Animation.GXInterpolationType.HSD_A_OP_KEY;
                    keys.Clear();
                    keys.Add(key);
                    return(keys);
                }
            }


            CalculateSlopes(keys);
            var newKeys = new List <FOBJKey>();

            // find constant and linear keys
            {
                newKeys.Add(CloneKey(keys[0]));
                for (int i = 1; i < keys.Count - 2; i++)
                {
                    // this key is constant, so skip
                    if (Math.Abs(keys[i].Value - keys[i - 1].Value) < 0.00001f)
                    {
                        continue;
                    }

                    // step check
                    if (Math.Abs(keys[i].Value - keys[i + 1].Value) < 0.00001f)
                    {
                        /*var nkey = CloneKey(keys[i]);
                         * nkey.InterpolationType = HSDRaw.Common.Animation.GXInterpolationType.HSD_A_OP_CON;
                         * nkey.Tan = 0;
                         * newKeys.Add(nkey);*/
                        continue;
                    }

                    //TODO: lerp detection
                    // linear check

                    /*float FrameDiff = (i + 1) - keys[i].Frame;
                     * float Weight = FrameDiff / (keys[i + 1].Frame - keys[i].Frame);
                     *
                     * var lerpIndex = i + 1;
                     * while (lerpIndex < keys.Count - 1 && AnimationInterpolationHelper.Lerp(keys[i].Value, keys[lerpIndex].Value, Weight) == keys[lerpIndex].Value)
                     * {
                     *  lerpIndex++;
                     *  FrameDiff = lerpIndex - keys[i].Frame;
                     *  Weight = FrameDiff / (keys[lerpIndex].Frame - keys[i].Frame);
                     * }
                     *
                     * // if this key is linear then skip linear keys and change interpolation type
                     * if (lerpIndex > i + 2)
                     * {
                     *  System.Diagnostics.Debug.WriteLine("Linear");
                     *  var nkey = CloneKey(keys[i]);
                     *  nkey.InterpolationType = HSDRaw.Common.Animation.GXInterpolationType.HSD_A_OP_LIN;
                     *  nkey.Tan = 0;
                     *  i = lerpIndex - 1;
                     *  newKeys.Add(nkey);
                     * }*/
                }
                newKeys.Add(CloneKey(keys[keys.Count - 1]));
            }

            // prepare analyzing
            var analyzer1 = new KeyAnalyzer(keys);
            var analyzer2 = new KeyAnalyzer(newKeys);

            // insert keys until error is reduced within threshold
            float error     = float.MaxValue;
            var   index     = 0;
            int   prevIndex = 0;

            while (error > maxError)
            {
                KeyAnalyzer.GetMaxError(analyzer1, analyzer2, out error, out index);

                if (index == prevIndex || index >= keys.Count || index < 0)
                {
                    break;
                }

                var loc = newKeys.FindIndex(e => keys[index].Frame <= e.Frame);

                if (loc != -1)
                {
                    newKeys.Insert(loc, CloneKey(keys[index]));
                }
                else
                {
                    break;
                }

                prevIndex = index;
            }

            int removedLinear = 0;

            // use linear where possible
            {
                for (int j = 0; j < newKeys.Count - 1; j++)
                {
                    var k = newKeys[j];

                    if ((newKeys[j + 1].Frame - k.Frame) <= 2)
                    {
                        k.InterpolationType = HSDRaw.Common.Animation.GXInterpolationType.HSD_A_OP_LIN;
                        removedLinear++;
                    }
                }
                //Console.WriteLine($"Removed {removed} keys");
            }

            int removed = 0;
            // cleanup pass, make sure all frames are necessary
            List <FOBJKey> finalKeys = new List <FOBJKey>();

            finalKeys.Add(keys[0]);
            for (int j = 1; j < newKeys.Count - 1; j++)
            {
                var k = newKeys[j];
                analyzer1 = new KeyAnalyzer(newKeys.Where(e => e != k).ToList());

                KeyAnalyzer.GetMaxError(analyzer1, analyzer2, out error, out index);

                if (error < maxError)
                {
                    removed++;
                }
                else
                {
                    finalKeys.Add(k);
                }
            }
            finalKeys.Add(keys[keys.Count - 1]);
            newKeys = finalKeys;

            Debug.WriteLine($"Removed {removed} keys converted {removedLinear} to linear");

            // make sure to always have final key
            //if (!newKeys.Contains(keys[keys.Count - 1]))
            //    newKeys.Add(keys[keys.Count - 1]);

            return(newKeys);
        }