Пример #1
0
        public static void Subdivide(Spline spline, int num)
        /// Splits each segment in several shorter segments
        {
            Vector3[] newNodes = new Vector3[(spline.nodes.Length - 1) * num + 1];

            for (int n = 0; n < spline.nodes.Length - 1; n++)
            {
                Vector3 pos0 = spline.nodes[n];
                Vector3 dir0 = spline.GetTangent(n);
                Vector3 pos1 = spline.nodes[n + 1];
                Vector3 dir1 = spline.GetTangent(n + 1, true);

                for (int i = 0; i < num; i++)
                {
                    float percent = (float)i / num;

                    Vector3 split = BeizerPosition(pos0, dir0, pos1, dir1, percent);



                    newNodes[n * num + i] = split;

                    //float percent = 1f / (num-i);
                    //(Segment,Segment) split = currSegment.GetSplitted(percent);
                    //currSegment = split.Item2;
                }
            }

            newNodes[newNodes.Length - 1] = spline.nodes[spline.nodes.Length - 1];

            spline.nodes = newNodes;
        }
Пример #2
0
        public static IEnumerable <Vector3> UniformPositions(Spline spline, int n, int count)
        /// Iterates in a given number of positions
        /// Includes original point, but not includes final (n+1) point
        {
            if (n >= spline.nodes.Length - 1)
            {
                throw new Exception("Beizer positions should be calculated for n-1");
            }

            Vector3 pos0 = spline.nodes[n];
            Vector3 dir0 = spline.GetTangent(n);
            Vector3 pos1 = spline.nodes[n + 1];
            Vector3 dir1 = spline.GetTangent(n + 1, true);

            float[] lengths            = new float[64];
            float[] lengthToPercentLut = new float[8];

            LengthToPercentLut(pos0, dir0, pos1, dir1, lengths, lengthToPercentLut);

            for (int i = 0; i < count; i++)
            {
                float l = (float)i / count;
                float p = NormLengthToPercent(pos0, dir0, pos1, dir1, l, lengthToPercentLut);
                yield return(BeizerPosition(pos0, dir0, pos1, dir1, p));
            }
        }
Пример #3
0
        public static IEnumerable <Vector3> BeizerPositions(this Spline spline, int n, int count)
        /// Iterates in a given number of positions
        /// Includes original point, but not includes final (n+1) point
        {
            if (n >= spline.nodes.Length - 1)
            {
                throw new Exception("Beizer positions should be calculated for n-1");
            }

            Vector3 n0dir = spline.GetTangent(n);
            Vector3 n1dir = spline.GetTangent(n + 1, true);

            yield return(spline.nodes[n]);

            for (int i = 1; i < count; i++)
            {
                float p  = (float)i / count;
                float ip = 1f - p;

                yield return
                    (ip * ip * ip * spline.nodes[n] +
                     3 * p * ip * ip * (spline.nodes[n] + n0dir) +
                     3 * p * p * ip * (spline.nodes[n + 1] + n1dir) +
                     p * p * p * spline.nodes[n + 1]);
            }
        }
Пример #4
0
        public static void Optimize(Spline spline, float deviation)
        /// Removes those nodes that should not change the shape a lot
        /// Similar to Spline.Optimize, but takes tangents into account
        {
            int iterations = spline.nodes.Length - 2;           //in worst case should remove all but start/end

            if (iterations <= 0)
            {
                return;
            }
            for (int i = 0; i < iterations; i++)         //using recorded iterations since nodes count will change
            //for (int i=0; i<deviation; i++)
            {
                float minDeviation = float.MaxValue;
                int   minN         = -1;

                //Vector3 posM1 = spline.nodes[0];
                //Vector3 dirM1 = spline.GetTangent(0);

                for (int n = 1; n < spline.nodes.Length - 1; n++)
                {
                    Vector3 posM1 = spline.nodes[n - 1];
                    Vector3 dirM1 = spline.GetTangent(n - 1);
                    Vector3 pos0  = spline.nodes[n];
                    Vector3 dir0  = spline.GetTangent(n);
                    Vector3 pos1  = spline.nodes[n + 1];
                    Vector3 dir1  = spline.GetTangent(n + 1, true);

                    //checking how far point placed from tangent-tangent line
                    float currDistToLine = pos0.DistanceToLine(posM1 + dirM1, pos1 + dir1);
                    //float currLine = ((nodes[n-1].pos+nodes[n-1].outDir) - (nodes[n+1].pos+nodes[n+1].inDir)).magnitude;
                    //float currDeviation = (currDistToLine*currDistToLine) / currLine;
                    float currDeviation = currDistToLine;

                    if (currDeviation < minDeviation)
                    {
                        minN         = n;
                        minDeviation = currDeviation;
                    }

                    //posM1 = pos0;  dirM1 = dir0;
                }

                if (minDeviation > deviation)
                {
                    break;
                }
                ArrayTools.RemoveAt(ref spline.nodes, minN);
            }
        }
Пример #5
0
        public static Vector3 BeizerPosition(this Spline spline, int n, float p)
        /// Gets position at n segment and p percent
        /// Large overhead of getting tangents
        {
            Vector3 n0dir = spline.GetTangent(n);
            Vector3 n1dir = spline.GetTangent(n + 1, true);

            float ip = 1f - p;

            return
                (ip * ip * ip * spline.nodes[n] +
                 3 * p * ip * ip * (spline.nodes[n] + n0dir) +
                 3 * p * p * ip * (spline.nodes[n + 1] + n1dir) +
                 p * p * p * spline.nodes[n + 1]);
        }
Пример #6
0
        public static void SmartSubdivide(Spline spline, float maxDivisions, float minSegmentSize = 0)
        {
            List <Vector3> newNodes = new List <Vector3>();

            for (int n = 0; n < spline.nodes.Length - 1; n++)
            {
                Vector3 pos0 = spline.nodes[n];
                Vector3 dir0 = spline.GetTangent(n);
                Vector3 pos1 = spline.nodes[n + 1];
                Vector3 dir1 = spline.GetTangent(n + 1, true);

                float tangentalDist = dir0.magnitude + ((pos0 + dir0) - (pos1 + dir1)).magnitude + dir1.magnitude;
                float linearDist    = (pos0 - pos1).magnitude;

                float straightness = linearDist / tangentalDist;                 //epsilon (complex) to 1 (straight)

                int numSegs = (int)(maxDivisions * (1 - straightness));
                if (numSegs < 3)
                {
                    numSegs = 3;                              //whatewer, it should be a bit beizer
                }
                if (tangentalDist / numSegs < minSegmentSize)
                {
                    numSegs = (int)(tangentalDist / minSegmentSize);
                }

                for (int i = 0; i < numSegs; i++)
                {
                    float   percent = (float)i / numSegs;
                    Vector3 split   = BeizerPosition(pos0, dir0, pos1, dir1, percent);
                    newNodes.Add(split);
                }
            }
            newNodes.Add(spline.nodes[spline.nodes.Length - 1]);
            spline.nodes = newNodes.ToArray();
        }
Пример #7
0
        public static Vector3[] GetAllPoints(Spline spline, float resPerUnit = 0.1f, int minRes = 3, int maxRes = 20)
        /// Converts line into array of points to draw polyline
        /// Requires length updated
        /// Maybe rename to version of Subdivide?
        {
            //calculating lengths
            float[] lengths = new float[spline.nodes.Length - 1];
            for (int n = 0; n < lengths.Length; n++)
            {
                lengths[n] = ApproxLengthBeizer(spline, n);
            }

            //calculating number of points
            int numPoints = 0;

            for (int n = 0; n < lengths.Length; n++)
            {
                int modRes = (int)(lengths[n] * resPerUnit);
                if (modRes < minRes)
                {
                    modRes = minRes;
                }
                if (modRes > maxRes)
                {
                    modRes = maxRes;
                }

                numPoints += modRes;
            }

            Vector3[] points = new Vector3[numPoints + 1];

            int i = 0;

            for (int n = 0; n < lengths.Length; n++)
            {
                int modRes = (int)(lengths[n] * resPerUnit);
                if (modRes < minRes)
                {
                    modRes = minRes;
                }
                if (modRes > maxRes)
                {
                    modRes = maxRes;
                }

                Vector3 pos0 = spline.nodes[n];
                Vector3 dir0 = spline.GetTangent(n);
                Vector3 pos1 = spline.nodes[n + 1];
                Vector3 dir1 = spline.GetTangent(n + 1, true);

                for (int p = 0; p < modRes; p++)
                {
                    float percent = 1f * p / modRes;
                    points[i] = BeizerPosition(pos0, dir0, pos1, dir1, percent);
                    i++;
                }
            }

            //the last one
            points[points.Length - 1] = spline.nodes[spline.nodes.Length - 1];

            return(points);
        }
Пример #8
0
        /*
         *                      public float IntegralLength (float t=1, int iterations=8)
         *                      /// A variation of Legendre-Gauss solution from Primer (https://pomax.github.io/bezierinfo/#arclength)
         *                      {
         *                              float z = t / 2;
         *                              float sum = 0;
         *
         *                              double[] abscissaeLutArr = abscissaeLut[iterations];
         *                              double[] weightsLutArr = weightsLut[iterations];
         *
         *                              float correctedT;
         *                              for (int i=0; i<iterations; i++)
         *                              {
         *                                      correctedT = z * (float)abscissaeLutArr[i] + z;
         *
         *                                      Vector3 derivative = GetDerivative(correctedT);
         *                                      float b = Mathf.Sqrt(derivative.x*derivative.x + derivative.z*derivative.z);
         *                                      sum += (float)weightsLutArr[i] * b;
         *                              }
         *
         *                              return z * sum;
         *                      }
         *
         *
         *                      public void FillIntegralLengthLut (float fullLength=-1, int iterations=32)
         *                      /// Fills the distance for each length (i.e. if lengthPercents is 4 then finds dist for 0.25,0.5,075,1)
         *                      {
         *                              if (fullLength < 0) fullLength = IntegralLength();
         *
         *                              float pHalf = LengthToPercent(fullLength*0.5f, iterations:iterations);
         *                              float p025 = LengthToPercent(fullLength*0.25f, pFrom:0, pTo:pHalf, iterations:iterations/2);
         *                              float p075 = LengthToPercent(fullLength*0.75f, pFrom:pHalf, pTo:1, iterations:iterations/2);
         *                              float p0125 = LengthToPercent(fullLength*0.125f, pFrom:0, pTo:p025, iterations:iterations/4);
         *                              float p0375 = LengthToPercent(fullLength*0.375f, pFrom:p025, pTo:pHalf, iterations:iterations/4);
         *                              float p0625 = LengthToPercent(fullLength*0.625f, pFrom:pHalf, pTo:p075, iterations:iterations/4);
         *                              float p0875 = LengthToPercent(fullLength*0.875f, pFrom:p075, pTo:1, iterations:iterations/4);
         *
         *                              lengthToPercentLut.b0 = (byte)(p0125*255 + 0.5f);
         *                              lengthToPercentLut.b1 = (byte)(p025*255 + 0.5f);
         *                              lengthToPercentLut.b2 = (byte)(p0375*255 + 0.5f);
         *                              lengthToPercentLut.b3 = (byte)(pHalf*255 + 0.5f);
         *                              lengthToPercentLut.b4 = (byte)(p0625*255 + 0.5f);
         *                              lengthToPercentLut.b5 = (byte)(p075*255 + 0.5f);
         *                              lengthToPercentLut.b6 = (byte)(p0875*255 + 0.5f);
         *                      }
         *
         *
         *                      public float LengthToPercent (float length, float pFrom=0, float pTo=1, int iterations=8)
         *                      /// Converts world length to segments percent without using segment length LUT. Used to fill that LUT.
         *                      {
         *                              float pMid = (pFrom+pTo)/2;
         *                              float lengthMid = IntegralLength(pMid);
         *
         *                              if (length < lengthMid)
         *                              {
         *                                      if (iterations <= 1) return (pFrom+pMid) /2;
         *                                      else return LengthToPercent(length, pFrom:pFrom, pTo:pMid, iterations:iterations-1);
         *                              }
         *
         *                              else
         *                              {
         *                                      if (iterations <= 1) return (pMid+pTo) /2;
         *                                      else return LengthToPercent(length, pFrom:pMid, pTo:pTo, iterations:iterations-1);
         *                              }
         *                      }
         */
        #endregion


        #region Uniform Split

        // Operations related with the real spline distances (not distorted by beizer)
        // Requires length to percent lut - it's either approximate or linear LengthToPercentLut

        public static float NormLengthToPercent(Spline spline, int n, float normLength, float[] lengthToPercentLut) =>
        NormLengthToPercent(spline.nodes[n], spline.GetTangent(n), spline.nodes[n + 1], spline.GetTangent(n + 1, true), normLength, lengthToPercentLut);
Пример #9
0
 public static void LengthToPercentLut(this Spline spline, int n, float[] lengths, float[] lut) =>
 LengthToPercentLut(spline.nodes[n], spline.GetTangent(n), spline.nodes[n + 1], spline.GetTangent(n + 1, true), lengths, lut);
Пример #10
0
 public static float ApproxLengthBeizer(this Spline spline, int n, float pStart = 0, float pEnd = 1, int iterations = 32) =>
 ApproxLengthBeizer(spline.nodes[n], spline.GetTangent(n), spline.nodes[n + 1], spline.GetTangent(n + 1, true), pStart, pEnd, iterations);