Пример #1
0
 public Spline(Spline src)
 {
     nodes = ArrayTools.Copy(src.nodes); count = src.count;
 }
Пример #2
0
        /*UI ui = new UI();
         * SplineObject so;
         *
         * public void OnSceneGUI ()
         * {
         *      if (so == null) so = (SplineObject)target;
         *      ui.DrawInspector(() => DrawSpline(so.splineSys));
         * }*/


        public static void DrawSpline(SplineObject obj)
        {
            using (Cell.LineStd)
                using (new Draw.FoldoutGroup(ref guiDisplay, "Display", isLeft: true))
                    if (guiDisplay)
                    {
                        using (Cell.LineStd) Draw.ToggleLeft(ref obj.drawNodes, "Draw Nodes");
                        using (Cell.LineStd) Draw.ToggleLeft(ref obj.drawLines, "Draw Segments");
                        using (Cell.LineStd) Draw.ToggleLeft(ref obj.drawBeizer, "Draw Beizer");

                        if (Cell.current.valChanged)
                        {
                            SceneView.lastActiveSceneView?.Repaint();
                        }
                    }

            Cell.EmptyLinePx(4);
            using (Cell.LineStd)
                using (new Draw.FoldoutGroup(ref guiLines, "Splines", isLeft: true))
                    if (guiLines)
                    {
                        using (Cell.LineStd) Draw.DualLabel("Lines Count", obj.splines.Length.ToString());

                        if (SplineEditor.selectedNodes.Count == 1)
                        {
                            (int l, int n) = SplineEditor.selectedNodes.Any();
                            Spline spline = obj.splines[l];

                            //using (Cell.LineStd) Draw.DualLabel("Length", spline.length.ToString());
                            using (Cell.LineStd) Draw.DualLabel("Node Counts", spline.nodes.Length.ToString());
                            //using (Cell.LineStd) Draw.Toggle(ref spline.looped, "Looped");

                            using (Cell.LineStd)
                                if (Draw.Button("Remove"))
                                {
                                    ArrayTools.RemoveAt(ref obj.splines, l);
                                    SplineEditor.selectedNodes.Clear();
                                    SplineEditor.dispSelectedNodes.Clear();
                                }
                        }

                        using (Cell.LineStd)
                            if (Draw.Button("Add"))
                            {
                                Spline newSpline = new Spline(
                                    SceneView.lastActiveSceneView.pivot - new Vector3(SceneView.lastActiveSceneView.cameraDistance / 10, 0, 0),
                                    SceneView.lastActiveSceneView.pivot + new Vector3(SceneView.lastActiveSceneView.cameraDistance / 10, 0, 0));
                                newSpline.nodes[0].y = 0;
                                newSpline.nodes[1].y = 0;

                                ArrayTools.Add(ref obj.splines, newSpline);
                            }
                    }

            Cell.EmptyLinePx(4);
            using (Cell.LineStd)
                using (new Draw.FoldoutGroup(ref guiKnobs, "Nodes", isLeft: true))
                    if (guiKnobs)
                    {
                        using (Cell.LineStd) Draw.DualLabel("Selected", SplineEditor.selectedNodes.Count.ToString());

                        if (SplineEditor.selectedNodes.Count == 1)
                        {
                            Cell.EmptyLinePx(4);
                            (int l, int n) = SplineEditor.selectedNodes.Any();
                            using (Cell.LinePx(0)) DrawNode(obj.splines, l, n);
                        }
                    }

            /*Cell.EmptyLinePx(4);
             * using (Cell.LineStd)
             *      if (Draw.Button("Update"))
             *      {
             *              sys.Update();
             *              SceneView.lastActiveSceneView?.Repaint();
             *      }*/
        }
Пример #3
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);
        }
Пример #4
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);
Пример #5
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);
Пример #6
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);
Пример #7
0
        /*private struct Segment
         * {
         *      public Vector3 pos0;
         *      public Vector3 dir0;
         *      public Vector3 pos1;
         *      public Vector3 dir1;
         *
         *
         *      public Vector3 BeizerPosition (float p)
         *      /// Gets position at n segment and p percent
         *      /// Large overhead of getting tangents
         *      {
         *              float ip = 1f-p;
         *              return
         *                      ip*ip*ip*pos0 +
         *                      3*p*ip*ip*(pos0+dir0) +
         *                      3*p*p*ip*(pos1+dir1) +
         *                      p*p*p*pos1;
         *      }
         * }*/

        public static Vector3 GetTangent(this Spline spline, int n, bool prev = false)
        /// Gets the auto-layouted direction of n node, looking towards next node
        /// Or prev node if prev enabled
        {
            //only two nodes
            if (spline.nodes.Length == 2)
            {
                if (n == 0)
                {
                    Vector3 dir = (spline.nodes[n + 1] - spline.nodes[n]) * 0.333f;
                    return(!prev ? dir : -dir);
                }

                else
                {
                    Vector3 dir = (spline.nodes[n] - spline.nodes[n - 1]) * 0.333f;
                    return(!prev ? dir : -dir);
                }
            }

            //first
            else if (n == 0)
            {
                Vector3 nextTan = GetTangent(spline, 1, true);
                Vector3 dir     = ((spline.nodes[n + 1] + nextTan) - spline.nodes[n]) * 0.333f;
                //Vector3 dir = (spline.nodes[n+1] - spline.nodes[n]) * 0.333f;
                return(!prev ? dir : -dir);
            }

            //last
            else if (n == spline.nodes.Length - 1)
            {
                Vector3 prevTan = GetTangent(spline, spline.nodes.Length - 2, false);
                Vector3 dir     = (spline.nodes[n] - (spline.nodes[n - 1] + prevTan)) * 0.333f;
                //Vector3 dir = (spline.nodes[n-1] - spline.nodes[n]) * 0.333f;
                return(!prev ? dir : -dir);
            }

            //common case
            else
            {
                Vector3 outDir       = spline.nodes[n + 1] - spline.nodes[n];
                float   outDirLength = outDir.magnitude;
                if (outDirLength > 0.00001f)                 //prevPos match with pos, usually on first segment
                {
                    outDir /= outDirLength;
                }
                else
                {
                    outDir = new Vector3();
                }

                Vector3 inDir       = spline.nodes[n - 1] - spline.nodes[n];
                float   inDirLength = inDir.magnitude;
                if (inDirLength > 0.00001f)
                {
                    inDir /= inDirLength;
                }
                else
                {
                    inDir = new Vector3();
                }

                Vector3 newInDir  = (inDir - outDir).normalized;
                Vector3 newOutDir = -newInDir;                 //(outDir - inDir).normalized;

                inDir  = newInDir.normalized * inDirLength * 0.35f;
                outDir = newOutDir.normalized * outDirLength * 0.35f;

                return(!prev ? outDir : inDir);
            }
        }