Пример #1
0
        public void DrawInspector()
        {
            Spline spline = path.spline;

            if (spline == null)
            {
                return;
            }

            path.Transform();
            EditorGUILayout.BeginVertical();
            bool bezier = path.spline.type == Spline.Type.Bezier;

            bezier                 = EditorGUILayout.Toggle("Bezier", bezier);
            path.spline.type       = bezier ? Spline.Type.Bezier : Spline.Type.Linear;
            path.seamlessEnds      = EditorGUILayout.Toggle("Seamless Ends", path.seamlessEnds);
            path.spline.sampleRate = EditorGUILayout.IntField("Precision", path.spline.sampleRate);
            string[] options = new string[spline.points.Length + 1];
            for (int i = 0; i < options.Length - 1; i++)
            {
                options[i + 1] = "Point " + (i + 1);
            }
            options[0] = "- None -";
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.Space();
            selectedPoint = EditorGUILayout.Popup("Select Point", selectedPoint + 1, options) - 1;
            if (selectedPoint > 0 && spline.points.Length > 2 && modifyWindow == null)
            {
                if (GUILayout.Button("X", GUILayout.Width(20)))
                {
                    ArrayUtility.Remove(ref spline.points, spline.points[selectedPoint]);
                    selectedPoint--;
                }
            }
            EditorGUILayout.EndHorizontal();
            if (selectedPoint >= 0 && selectedPoint < spline.points.Length)
            {
                EditorGUILayout.Space();
                EditorGUILayout.BeginHorizontal();
                if (tool == PathTool.Move)
                {
                    GUI.backgroundColor = ForeverPrefs.highlightColor;
                }
                else
                {
                    GUI.backgroundColor = Color.white;
                }
                if (GUILayout.Button("Move", EditorStyles.miniButtonLeft))
                {
                    tool = PathTool.Move;
                }

                if (tool == PathTool.Surface)
                {
                    GUI.backgroundColor = ForeverPrefs.highlightColor;
                }
                else
                {
                    GUI.backgroundColor = Color.white;
                }
                if (GUILayout.Button("Surface", EditorStyles.miniButtonMid))
                {
                    tool = PathTool.Surface;
                }

                if (tool == PathTool.Normal)
                {
                    GUI.backgroundColor = ForeverPrefs.highlightColor;
                }
                else
                {
                    GUI.backgroundColor = Color.white;
                }
                if (GUILayout.Button("Normals", EditorStyles.miniButtonRight))
                {
                    tool = PathTool.Normal;
                }

                EditorGUILayout.EndHorizontal();
                GUI.backgroundColor = Color.white;
                if (tool == PathTool.Surface)
                {
                    surfaceLayermask = DreamteckEditorGUI.LayermaskField("Layer Mask", surfaceLayermask);
                }
                EditorGUILayout.Space();

                SplinePoint avgPoint = spline.points[selectedPoint];

                avgPoint.SetPosition(EditorGUILayout.Vector3Field("Position", avgPoint.position));
                if (spline.type == Spline.Type.Bezier)
                {
                    EditorGUILayout.Space();
                    avgPoint.type = (SplinePoint.Type)EditorGUILayout.EnumPopup("Tangents Type", avgPoint.type);
                    avgPoint.SetTangent2Position(EditorGUILayout.Vector3Field("Front Tangent", avgPoint.tangent2));
                    avgPoint.SetTangentPosition(EditorGUILayout.Vector3Field("Back Tangent", avgPoint.tangent));
                    EditorGUILayout.Space();
                }
                else
                {
                    avgPoint.tangent  = avgPoint.position;
                    avgPoint.tangent2 = avgPoint.position;
                }
                avgPoint.normal = EditorGUILayout.Vector3Field("Normal", avgPoint.normal);
                avgPoint.normal.Normalize();

                EditorGUIUtility.labelWidth = 0f;
                avgPoint.size  = EditorGUILayout.FloatField("Size", avgPoint.size);
                avgPoint.color = EditorGUILayout.ColorField("Color", avgPoint.color);


                Undo.RecordObject(segment, "Edit Path " + path.name);
                spline.points[selectedPoint] = avgPoint;
                if (GUI.changed)
                {
                    path.InverseTransform();
                }
            }

            if (modifyWindow == null)
            {
                EditorGUILayout.Space();
                EditorGUILayout.LabelField("Insert Point", EditorStyles.boldLabel);
                EditorGUILayout.BeginHorizontal();
                if (GUILayout.Button("At Start"))
                {
                    SplineSample result        = spline.Evaluate(DMath.Lerp(0.0, 1.0 / (spline.points.Length - 1), 0.5));
                    float        tangentLength = Mathf.Lerp(Vector3.Distance(spline.points[0].position, spline.points[0].tangent), Vector3.Distance(spline.points[1].position, spline.points[1].tangent), 0.5f);
                    ArrayUtility.Insert(ref spline.points, 1, new SplinePoint(result.position, result.position - result.forward * tangentLength, result.up, result.size, result.color));
                    path.InverseTransform();
                    selectedPoint = 1;
                }
                if (GUILayout.Button("At End"))
                {
                    SplineSample result        = spline.Evaluate(DMath.Lerp((double)(spline.points.Length - 2) / (spline.points.Length - 1), 1.0, 0.5));
                    float        tangentLength = Mathf.Lerp(Vector3.Distance(spline.points[spline.points.Length - 2].position, spline.points[spline.points.Length - 2].tangent), Vector3.Distance(spline.points[spline.points.Length - 1].position, spline.points[spline.points.Length - 1].tangent), 0.5f);
                    ArrayUtility.Insert(ref spline.points, spline.points.Length - 2, new SplinePoint(result.position, result.position - result.forward * tangentLength, result.up, result.size, result.color));
                    path.InverseTransform();
                    selectedPoint = spline.points.Length - 2;
                }

                EditorGUILayout.EndHorizontal();
                if (GUILayout.Button("Modify Path"))
                {
                    modifyWindow = EditorWindow.GetWindow <ModifyWindow>(true);
                    modifyWindow.Init(this);
                }
            }
            EditorGUILayout.EndVertical();
        }
Пример #2
0
        protected virtual void OnSceneGUI()
        {
            Node node = (Node)target;

            Node.Connection[] connections = node.GetConnections();
            for (int i = 0; i < connections.Length; i++)
            {
                DSSplineDrawer.DrawSplineComputer(connections[i].spline, 0.0, 1.0, 0.5f);
            }

            bool update = false;

            if (position != node.transform.position)
            {
                position = node.transform.position;
                update   = true;
            }
            if (scale != node.transform.localScale)
            {
                scale  = node.transform.localScale;
                update = true;
            }
            if (rotation != node.transform.rotation)
            {
                rotation = node.transform.rotation;
                update   = true;
            }
            if (update)
            {
                node.UpdateConnectedComputers();
            }

            if (addComp == null)
            {
                if (connections.Length > 0)
                {
                    bool bezier = false;
                    for (int i = 0; i < connections.Length; i++)
                    {
                        if (connections[i].spline == null)
                        {
                            continue;
                        }
                        if (connections[i].spline.type == Spline.Type.Bezier)
                        {
                            bezier = true;
                            continue;
                        }
                    }
                    if (bezier && node.type == Node.Type.Smooth)
                    {
                        if (connections[0].spline != null)
                        {
                            SplinePoint point = node.GetPoint(0, true);
                            Handles.DrawDottedLine(node.transform.position, point.tangent, 6f);
                            Handles.DrawDottedLine(node.transform.position, point.tangent2, 6f);
                            Vector3 lastPos  = point.tangent;
                            bool    setPoint = false;
                            point.SetTangentPosition(Handles.PositionHandle(point.tangent, node.transform.rotation));
                            if (lastPos != point.tangent)
                            {
                                setPoint = true;
                            }
                            lastPos = point.tangent2;
                            point.SetTangent2Position(Handles.PositionHandle(point.tangent2, node.transform.rotation));
                            if (lastPos != point.tangent2)
                            {
                                setPoint = true;
                            }

                            if (setPoint)
                            {
                                node.SetPoint(0, point, true);
                                node.UpdateConnectedComputers();
                            }
                        }
                    }
                }
                return;
            }
            SplinePoint[] points       = addComp.GetPoints();
            Transform     camTransform = SceneView.currentDrawingSceneView.camera.transform;

            DSSplineDrawer.DrawSplineComputer(addComp, 0.0, 1.0, 0.5f);
            TextAnchor originalAlignment = GUI.skin.label.alignment;
            Color      originalColor     = GUI.skin.label.normal.textColor;

            GUI.skin.label.alignment        = TextAnchor.MiddleCenter;
            GUI.skin.label.normal.textColor = addComp.editorPathColor;
            for (int i = 0; i < availablePoints.Length; i++)
            {
                if (addComp.isClosed && i == points.Length - 1)
                {
                    break;
                }

                Handles.Label(points[i].position + Camera.current.transform.up * HandleUtility.GetHandleSize(points[i].position) * 0.3f, (i + 1).ToString());
                if (SplineEditorHandles.CircleButton(points[availablePoints[i]].position, Quaternion.LookRotation(-camTransform.forward, camTransform.up), HandleUtility.GetHandleSize(points[availablePoints[i]].position) * 0.1f, 2f, addComp.editorPathColor))
                {
                    AddConnection(addComp, availablePoints[i]);
                    break;
                }
            }
            GUI.skin.label.alignment        = originalAlignment;
            GUI.skin.label.normal.textColor = originalColor;
        }
Пример #3
0
        public void PlaceObjects()
        {
            // recreate and redistribute all prefabs if requested
            if (!prefabPainter.splineSettings.reusePrefabs)
            {
                RemoveAllPrefabInstances();
            }

            if (prefabPainter.splineSettings.controlPoints.Count < 2)
            {
                // remove all that's left in case control points were deleted
                RemoveAllPrefabInstances();

                // don't continue any further
                return;
            }

            // put the spline into a list of Vector3's instead of using the iterator
            IEnumerable <Vector3> spline       = CreateSpline();
            IEnumerator           iterator     = spline.GetEnumerator();
            List <SplinePoint>    splinePoints = new List <SplinePoint>();

            // limit the number of points; this has become necessary because with the loop there's an overlap multiple times
            // and this could result in an endless loop in the worst case
            int splinePointMaxIndex = (prefabPainter.splineSettings.curveResolution + 1) * prefabPainter.splineSettings.controlPoints.Count;
            int splinePointIndex    = 0;
            int segmentIndex        = 0;
            int controlPointIndex   = 0;

            while (iterator.MoveNext() && splinePointIndex <= splinePointMaxIndex)
            {
                SplinePoint splinePoint = new SplinePoint();
                splinePoint.position = (Vector3)iterator.Current;
                splinePoint.startControlPointIndex = controlPointIndex;

                splinePoints.Add(splinePoint);

                splinePointIndex++;
                segmentIndex++;

                if (segmentIndex > prefabPainter.splineSettings.curveResolution)
                {
                    controlPointIndex++;
                    segmentIndex = 0;
                }
            }


            //distanceToMove represents how much farther we need to progress down the spline before we place the next object
            int nextSplinePointIndex = 1;

            //our current position on the spline
            Vector3 positionIterator = splinePoints[0].position;

            // the algorithm skips the first control point, so we need to manually place the first object
            Vector3 direction = (splinePoints[nextSplinePointIndex].position - positionIterator);

            int prefabInstanceIndex = -1;

            // new prefab
            GameObject prefab = AddPrefab(ref prefabInstanceIndex, positionIterator, direction, splinePoints, nextSplinePointIndex - 1);

            float distanceToMove = GetDistanceToMove(prefab);

            while (nextSplinePointIndex < splinePoints.Count)
            {
                direction = (splinePoints[nextSplinePointIndex].position - positionIterator);
                direction = direction.normalized;

                float distanceToNextPoint = Vector3.Distance(positionIterator, splinePoints[nextSplinePointIndex].position);

                if (distanceToNextPoint >= distanceToMove)
                {
                    positionIterator += direction * distanceToMove;

                    // new prefab
                    prefab = AddPrefab(ref prefabInstanceIndex, positionIterator, direction, splinePoints, nextSplinePointIndex - 1);

                    distanceToMove = GetDistanceToMove(prefab);
                }
                else
                {
                    distanceToMove  -= distanceToNextPoint;
                    positionIterator = splinePoints[nextSplinePointIndex++].position;
                }
            }

            // remove prefab instances that aren't used anymore
            if (prefabPainter.splineSettings.reusePrefabs)
            {
                RemovePrefabInstances(prefabInstanceIndex);
            }
        }
 public float2 GetControlPoint(int i, SplinePoint point) => GetControlPoint2DLocal(i);
Пример #5
0
 public void RefreshTreeView(SplinePoint splinePoint)
 {
     GuiData.SplineListDisplay.UpdateToList(splinePoint);
 }
Пример #6
0
        public void DoMirror()
        {
            List <int> half   = GetHalf(ref originalPoints);
            int        welded = -1;

            if (half.Count > 0)
            {
                if (flip)
                {
                    if (IsWeldable(originalPoints[half[0]]))
                    {
                        welded = half[0];
                        half.RemoveAt(0);
                    }
                }
                else
                {
                    if (IsWeldable(originalPoints[half[half.Count - 1]]))
                    {
                        welded = half[half.Count - 1];
                        half.RemoveAt(half.Count - 1);
                    }
                }

                int offset         = welded >= 0 ? 1 : 0;
                int additionalSlot = isClosed && half.Count > 0 ? 1 : 0;
                if (additionalSlot > 0)
                {
                    if (flip)
                    {
                        if (IsWeldable(originalPoints[half[half.Count - 1]]))
                        {
                            additionalSlot = 0;
                        }
                    }
                    else
                    {
                        if (IsWeldable(originalPoints[half[0]]))
                        {
                            additionalSlot = 0;
                        }
                    }
                }
                int mirroredLength = half.Count * 2 + offset + additionalSlot;
                if (mirrored.Length != mirroredLength)
                {
                    mirrored = new SplinePoint[mirroredLength];
                }
                for (int i = 0; i < half.Count; i++)
                {
                    if (flip)
                    {
                        mirrored[i] = new SplinePoint(originalPoints[half[(half.Count - 1) - i]]);
                        mirrored[i + half.Count + offset] = GetMirrored(originalPoints[half[i]]);
                        SwapTangents(ref mirrored[i]);
                        SwapTangents(ref mirrored[i + half.Count + offset]);
                    }
                    else
                    {
                        mirrored[i] = new SplinePoint(originalPoints[half[i]]);
                        mirrored[i + half.Count + offset] = GetMirrored(originalPoints[half[(half.Count - 1) - i]]);
                    }
                }
                if (welded >= 0)
                {
                    mirrored[half.Count] = new SplinePoint(originalPoints[welded]);
                    if (flip)
                    {
                        SwapTangents(ref mirrored[half.Count]);
                    }
                    MakeMiddlePoint(ref mirrored[half.Count]);
                }

                if (isClosed && mirrored.Length > 0)
                {
                    if (additionalSlot == 0)
                    {
                        MakeMiddlePoint(ref mirrored[0]);
                    }
                    mirrored[mirrored.Length - 1] = new SplinePoint(mirrored[0]);
                }
            }
            else
            {
                mirrored = new SplinePoint[0];
            }
            points = mirrored;
            SetDirty();
        }
Пример #7
0
 public void AddSplinePoint(SplinePoint p)
 {
     points.Add(p);
 }
Пример #8
0
        public float3 GetControlPoint(ISimpleSpline3D spline, int index, SplinePoint pointType)
        {
            Assert.NotNull(spline);

            return(spline.GetControlPoint(index, pointType));
        }
Пример #9
0
        private void PathArcTo(string coords, bool relative)
        {
            // Get Arc Arguments
            float[] floats   = ParseFloat(coords);
            float   rx       = floats[0];
            float   ry       = floats[1];
            float   rotation = floats[2] * Mathf.Deg2Rad;
            bool    largeArc = floats[3] > 0.5f;
            bool    sweep    = floats[4] > 0.5f;
            float   x        = floats[5];
            float   y        = floats[6];

            // Set the last buffer point to broken
            SplinePoint p = buffer.GetLastPoint();

            p.type = SplinePoint.Type.Broken;

            // Get the start and end point. Note: Flip Y, as the Ellipse Parameters calculation assumes positive Y values
            Vector3 sp = p.position;

            sp.y *= -1;
            Vector3 ep = new Vector3(x, y, 0);

            if (relative)
            {
                ep += sp;
            }

            Vector2 c;
            float   theta1;
            float   sweepTheta;
            float   adjustedRx;
            float   adjustedRy;

            // Get the Ellipse Parameters
            CalculateEllipseParams(sp, ep, rotation, rx, ry, largeArc, sweep,
                                   out c, out theta1, out sweepTheta, out adjustedRx, out adjustedRy);

            // Flip the center Y back
            c.y *= -1;

            // Generate the ellipse primitive. Note: Rotated by -90 degrees and flipped, so first point starts at +X and goes clockwise
            Ellipse ellipse = new Ellipse();

            ellipse.offset   = c;
            ellipse.rotation = new Vector3(0, 0, -90 - rotation * Mathf.Rad2Deg);
            ellipse.xRadius  = adjustedRx;
            ellipse.yRadius  = adjustedRy;
            var ellipseSpline = ellipse.CreateSpline();
            var esp           = ellipseSpline.points;


            var tmpp = esp[1];

            esp[1] = esp[3];
            esp[3] = tmpp;
            for (int i = 0; i < esp.Length; i++)
            {
                FlipTangents(ref esp[i]);
            }

            // Find the percentages to sample the ellipse at
            var startP = theta1 / (Mathf.PI * 2);

            startP = ModP(startP, 1f);
            var sweepP = sweepTheta / (Mathf.PI * 2);
            var endP   = startP + sweepP;

            var percentages = GetArcSegmentPercentages(startP, endP);

            // Sample the ellipse and add points to buffer
            for (int i = 1; i < percentages.Length; ++i)
            {
                double pp  = percentages[i - 1];
                double pc  = percentages[i];
                double pr  = pc - pp;
                int    sgn = Math.Sign(pr); // This sign indicates a reversed range if < 0; The sampled tangents need to be flipped if this is the case
                pr *= sgn;
                if (pr < 0.0001d)
                {
                    continue;               // Sample error margin
                }
                double d = 0.75d / pr;
                pc = ModP(pc, 1d);
                pp = ModP(pp, 1d);

                // New point in buffer
                Vector3 posc = Vector3.zero, tanc = Vector3.zero, tanp = Vector3.zero;
                ellipseSpline.EvaluatePosition(ref posc, pc);
                ellipseSpline.EvaluateTangent(ref tanc, pc);
                tanc           *= sgn;
                tanc           /= (float)d;
                buffer.position = posc;
                buffer.tangent  = posc - tanc;

                // Modify tangent2 of last point in buffer
                ellipseSpline.EvaluateTangent(ref tanp, pp);
                tanp  *= sgn;
                tanp  /= (float)d;
                p      = buffer.GetLastPoint();
                p.type = SplinePoint.Type.Broken;
                p.SetTangent2Position(p.position + tanp);
                buffer.SetLastPoint(p);

                buffer.CreateBroken();
            }
        }
Пример #10
0
            internal void CreateClosingPoint()
            {
                SplinePoint p = new SplinePoint(points[0]);

                points.Add(p);
            }
 internal void UpdateToList(SplinePoint splinePoint)
 {
     this.SplineListDisplayControl.UpdateListDisplay(splinePoint);
 }
Пример #12
0
        private void UpdateVisualizer()
        {
            if (visualizer == null)
            {
                visualizer = new Spline(splineType);
            }
            visualizer.type       = splineType;
            visualizer.sampleRate = sampleRate;
            if (placementMode == PlacementMode.Insert)
            {
                visualizer.points = points;
                if (isClosed)
                {
                    visualizer.Close();
                }
                else if (visualizer.isClosed)
                {
                    visualizer.Break();
                }
                return;
            }

            if (visualizer.points.Length != points.Length + 1)
            {
                visualizer.points = new SplinePoint[points.Length + 1];
            }
            SplinePoint newPoint = new SplinePoint(createPoint, createPoint, createNormal, 1f, Color.white);

            if (appendMode == AppendMode.End)
            {
                if (isClosed)
                {
                    for (int i = 0; i < points.Length; i++)
                    {
                        visualizer.points[i] = points[i];
                    }
                    visualizer.points[visualizer.points.Length - 2] = newPoint;
                    visualizer.points[visualizer.points.Length - 1] = points[points.Length - 1];
                }
                else
                {
                    for (int i = 0; i < points.Length; i++)
                    {
                        visualizer.points[i] = points[i];
                    }
                    visualizer.points[visualizer.points.Length - 1] = newPoint;
                }
            }
            else
            {
                if (isClosed)
                {
                    for (int i = 1; i < points.Length; i++)
                    {
                        visualizer.points[i] = points[i - 1];
                    }
                    visualizer.points[1] = newPoint;
                    visualizer.points[0] = points[0];
                }
                else
                {
                    for (int i = 1; i < visualizer.points.Length; i++)
                    {
                        visualizer.points[i] = points[i - 1];
                    }
                    visualizer.points[0] = newPoint;
                }
            }
            if (isClosed && !visualizer.isClosed)
            {
                visualizer.Close();
            }
            else if (visualizer.isClosed)
            {
                visualizer.Break();
            }
            if (visualizer.isClosed)
            {
                visualizer.points[0].SetPosition(createPoint);
            }
        }
Пример #13
0
 public void HighlightNoCall(SplinePoint splinePoint)
 {
     mListDisplayWindow.HighlightObjectNoCall(splinePoint, false);
 }
Пример #14
0
        private void MouseGrabbingActivity()
        {
            Cursor cursor = GuiManager.Cursor;

            if (cursor.PrimaryPush && GuiManager.Cursor.WindowOver == null)
            {
                mCurrentSplinePoint = null;

                if (mReactiveHud.SplineMover.IsMouseOver == false)
                {
                    mSwitchedCurrentOnLastPush = mCurrentSpline != mSplineOver;

                    CurrentSpline = mSplineOver;
                    // Make sure we set the CurrentSplinePoint after setting the CurrentSpline so that
                    // the GUI for the CurrentSpline is already set.
                    CurrentSplinePoint  = mSplinePointOver;
                    mGrabbedSplinePoint = mSplinePointOver;

                    if (mGrabbedSplinePoint != null)
                    {
                        float cursorX = cursor.WorldXAt(mGrabbedSplinePoint.Position.Z);
                        float cursorY = cursor.WorldYAt(mGrabbedSplinePoint.Position.Z);

                        mXGrabOffset = mGrabbedSplinePoint.Position.X - cursorX;
                        mYGrabOffset = mGrabbedSplinePoint.Position.Y - cursorY;
                    }
                }
                // else if over the spline mover, let the current spline point stay at null
            }

            if (cursor.PrimaryDown && mGrabbedSplinePoint != null)
            {
                if (mHandleIndexOver0Base != -1)
                {
                    float cursorX = cursor.WorldXAt(mGrabbedSplinePoint.Position.Z);
                    float cursorY = cursor.WorldYAt(mGrabbedSplinePoint.Position.Z);

                    float differenceX = cursorX - mGrabbedSplinePoint.Position.X;
                    float differenceY = cursorY - mGrabbedSplinePoint.Position.Y;

                    differenceX *= 2;
                    differenceY *= 2;

                    if (mHandleIndexOver0Base == 0)
                    {
                        // Index 0 goes negative, index 1 goes positive
                        differenceX *= -1;
                        differenceY *= -1;
                    }

                    mGrabbedSplinePoint.Velocity.X = differenceX;
                    mGrabbedSplinePoint.Velocity.Y = differenceY;
                }
                else if (!mSwitchedCurrentOnLastPush)
                {
                    mGrabbedSplinePoint.Position = new Vector3(
                        cursor.WorldXAt(mGrabbedSplinePoint.Position.Z) + mXGrabOffset,
                        cursor.WorldYAt(mGrabbedSplinePoint.Position.Z) + mYGrabOffset,
                        mGrabbedSplinePoint.Position.Z);
                }
            }
            if (cursor.PrimaryClick)
            {
                mGrabbedSplinePoint = null;

                GuiData.PropertyGrid.Refresh();
            }
        }
Пример #15
0
        protected void BuildSegment(SplineSegment ss, SplinePoint p1, SplinePoint p2, SplinePoint p3, SplinePoint p4)
        {
            if (InterpolateType == SplineType.Linear)
            {
                PreparePoint(p1, p2, p3);
                PreparePoint(p2, p3, p4);

                ss.mStartpos  = p2.mPoint;
                ss.mEndpos    = p3.mPoint;
                ss.mStartctrl = ss.mStartpos + p2.mNextctrl;
                ss.mEndctrl   = ss.mEndpos + p3.mPrevctrl;
            }
            if (InterpolateType == SplineType.Bezier)
            {
                PreparePoint(p1, p2, p3);
                PreparePoint(p2, p3, p4);

                ss.mStartpos  = p2.mPoint;
                ss.mEndpos    = p3.mPoint;
                ss.mStartctrl = ss.mStartpos + p2.mNextctrl;
                ss.mEndctrl   = ss.mEndpos + p3.mPrevctrl;
            }
            else if (InterpolateType == SplineType.CatmullRom)
            {
                ss.mStartpos = p1.mPoint;
                ss.mEndpos   = p4.mPoint;

                ss.mStartctrl = p2.mPoint;
                ss.mEndctrl   = p3.mPoint;
            }



            ss.mStartlen = Length;
            float seglen = GetLength(ss);

            Length    += seglen;
            ss.mLength = seglen;
            ss.mEndlen = Length;

            switch (Reparam)
            {
            case ReparamType.None:
                ss.mParams   = null;
                ss.mPrecomps = null;
                break;

            case ReparamType.Simple:
            {
                mPrecompdiv = 1 / (float)StepCount;
                float param = 0, length = 0;

                Vector3 prev, next;

                ss.mParams   = new float[StepCount + 1];
                ss.mPrecomps = new float[StepCount + 1];
                for (int i = 1; i < StepCount + 1; ++i)
                {
                    prev            = GetPosition(ss, param);
                    param          += mPrecompdiv;
                    next            = GetPosition(ss, param);
                    length         += (next - prev).magnitude;
                    ss.mPrecomps[i] = length / seglen;
                    ss.mParams[i]   = param;
                }
                ss.mParams[0]           = 0;
                ss.mParams[StepCount]   = 1;
                ss.mPrecomps[0]         = 0;
                ss.mPrecomps[StepCount] = 1;
                mPrecompdiv             = 1 / (float)StepCount;
            }
            break;

            case ReparamType.RungeKutta:
                float dlen = seglen / (float)StepCount, lparam = 0;

                ss.mParams   = new float[StepCount + 1];
                ss.mPrecomps = new float[StepCount + 1];
                for (int i = 0; i < StepCount + 1; ++i)
                {
                    ss.mParams[i]   = GetReparamRungeKutta(ss, lparam);
                    ss.mPrecomps[i] = lparam / seglen;
                    lparam         += dlen;
                }
                ss.mParams[0]           = 0;
                ss.mParams[StepCount]   = 1;
                ss.mPrecomps[0]         = 0;
                ss.mPrecomps[StepCount] = 1;
                mPrecompdiv             = 1 / (float)StepCount;
                break;
            }
        }
Пример #16
0
        void PointMenu()
        {
            if (selectedPoints.Count == 0 || points.Length == 0)
            {
                return;
            }
            //Otherwise show the editing menu + the point selection menu
            Vector3 avgPos    = Vector3.zero;
            Vector3 avgTan    = Vector3.zero;
            Vector3 avgTan2   = Vector3.zero;
            Vector3 avgNormal = Vector3.zero;
            float   avgSize   = 0f;
            Color   avgColor  = Color.clear;

            for (int i = 0; i < selectedPoints.Count; i++)
            {
                avgPos    += points[selectedPoints[i]].position;
                avgNormal += points[selectedPoints[i]].normal;
                avgSize   += points[selectedPoints[i]].size;
                avgTan    += points[selectedPoints[i]].tangent;
                avgTan2   += points[selectedPoints[i]].tangent2;
                avgColor  += points[selectedPoints[i]].color;
            }

            avgPos   /= selectedPoints.Count;
            avgTan   /= selectedPoints.Count;
            avgTan2  /= selectedPoints.Count;
            avgSize  /= selectedPoints.Count;
            avgColor /= selectedPoints.Count;
            avgNormal.Normalize();

            SplinePoint avgPoint = new SplinePoint(avgPos, avgPos);

            avgPoint.tangent  = avgTan;
            avgPoint.tangent2 = avgTan2;
            avgPoint.size     = avgSize;
            avgPoint.color    = avgColor;
            avgPoint.type     = points[selectedPoints[0]].type;
            SplinePoint.Type lastType = avgPoint.type;

            avgPoint.normal = avgNormal;
            EditorGUI.BeginChangeCheck();
            SplineComputer.Space lastSpace = SplinePrefs.pointEditSpace;
            SplinePrefs.pointEditSpace = (SplineComputer.Space)EditorGUILayout.EnumPopup("Edit Space", SplinePrefs.pointEditSpace);
            if (lastSpace != SplinePrefs.pointEditSpace)
            {
                SplinePrefs.SavePrefs();
            }
            if (splineType == Spline.Type.Bezier)
            {
                if (is2D)
                {
                    avgPoint.SetTangentPosition(TransformedPositionField2D("Tangent 1", avgPoint.tangent));
                    avgPoint.SetTangent2Position(TransformedPositionField2D("Tangent 2", avgPoint.tangent2));
                }
                else
                {
                    avgPoint.SetTangentPosition(TransformedPositionField("Tangent 1", avgPoint.tangent));
                    avgPoint.SetTangent2Position(TransformedPositionField("Tangent 2", avgPoint.tangent2));
                }
            }
            if (is2D)
            {
                avgPoint.SetPosition(TransformedPositionField2D("Position", avgPoint.position));
            }
            else
            {
                avgPoint.SetPosition(TransformedPositionField("Position", avgPoint.position));
            }
            if (!is2D)
            {
                if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local)
                {
                    avgPoint.normal = _matrix.inverse.MultiplyVector(avgPoint.normal);
                }
                avgPoint.normal = TransformedPositionField("Normal", avgPoint.normal);
                if (SplinePrefs.pointEditSpace == SplineComputer.Space.Local)
                {
                    avgPoint.normal = _matrix.MultiplyVector(avgPoint.normal);
                }
            }
            avgPoint.size  = EditorGUILayout.FloatField("Size", avgPoint.size);
            avgPoint.color = EditorGUILayout.ColorField("Color", avgPoint.color);
            if (splineType == Spline.Type.Bezier)
            {
                avgPoint.type = (SplinePoint.Type)EditorGUILayout.EnumPopup("Point Type", avgPoint.type);
            }

            if (!EditorGUI.EndChangeCheck())
            {
                return;
            }
            RecordUndo("Edit Points");
            for (int i = 0; i < selectedPoints.Count; i++)
            {
                points[selectedPoints[i]].SetPosition(GetChangedVector(avgPos, avgPoint.position, points[selectedPoints[i]].position));
                points[selectedPoints[i]].normal = GetChangedVector(avgNormal, avgPoint.normal, points[selectedPoints[i]].normal);

                if (splineType == Spline.Type.Bezier)
                {
                    points[selectedPoints[i]].SetTangentPosition(GetChangedVector(avgTan, avgPoint.tangent, points[selectedPoints[i]].tangent));
                    points[selectedPoints[i]].SetTangent2Position(GetChangedVector(avgTan2, avgPoint.tangent2, points[selectedPoints[i]].tangent2));
                }
                if (avgPoint.size != avgSize)
                {
                    points[selectedPoints[i]].size = avgPoint.size;
                }
                if (avgColor != avgPoint.color)
                {
                    points[selectedPoints[i]].color = avgPoint.color;
                }
                if (lastType != avgPoint.type)
                {
                    points[selectedPoints[i]].type = avgPoint.type;
                }
            }
        }
Пример #17
0
 public void UpdateControlPointLocal(int index, float2 point, SplinePoint mode)
 {
     UpdateControlPointLocal(index, point, TranslateVariancePoint(mode));
 }
Пример #18
0
        public void UpdateControlPoint(ISimpleSpline3D spline, int index, float3 newPoint, SplinePoint pointType)
        {
            ISpline3DEditor spline3D = spline as ISpline3DEditor;

            Assert.NotNull(spline3D);

            spline3D.UpdateControlPointWorld(index, newPoint, pointType);
        }
Пример #19
0
 public float2 GetControlPoint(int i, SplinePoint point)
 {
     return(GetControlPoint(i, TranslateVariancePoint(point)));
 }
Пример #20
0
        private void AddGrindTriggers(GameObject go)
        {
            foreach (Transform transform in go.GetComponentsInChildren <Transform>())
            {
                if (transform.name.Contains("GrindSpline"))
                {
                    Transform grindColliders = new GameObject(transform.name + "Colliders").transform;
                    grindColliders.parent           = go.transform;
                    grindColliders.gameObject.layer = 12;

                    if (transform.name.Contains("Metal"))
                    {
                        transform.tag = "Metal";
                    }
                    if (transform.name.Contains("Wood"))
                    {
                        transform.tag = "Wood";
                    }
                    if (transform.name.Contains("Concrete"))
                    {
                        transform.tag = "Concrete";
                    }

                    Vector3[]     grindPoints  = new Vector3[transform.childCount];
                    SplinePoint[] splinePoints = new SplinePoint[grindPoints.Length];
                    for (int i = 0; i < grindPoints.Length; i++)
                    {
                        grindPoints[i]  = transform.GetChild(i).position;
                        splinePoints[i] = new SplinePoint(grindPoints[i]);
                    }

                    SplineComputer splineComputer = grindColliders.gameObject.AddComponent <SplineComputer>();
                    splineComputer.type = Spline.Type.Linear;
                    Vector3[] grindNormals = new Vector3[grindPoints.Length];
                    for (int i = 0; i < grindPoints.Length - 1; i++)
                    {
                        GameObject grindCollider = new GameObject("RailCol" + i);
                        grindCollider.layer = 12;
                        grindCollider.transform.position = grindPoints[i];
                        grindCollider.transform.LookAt(grindPoints[i + 1]);
                        BoxCollider boxCollider   = grindCollider.AddComponent <BoxCollider>();
                        float       segmentLength = Vector3.Distance(grindPoints[i], grindPoints[i + 1]);
                        boxCollider.size               = new Vector3(0.08f / go.transform.lossyScale.x, 0.08f / go.transform.lossyScale.y, segmentLength);
                        boxCollider.center             = Vector3.forward * segmentLength / 2f;
                        boxCollider.isTrigger          = true;
                        grindCollider.transform.parent = grindColliders;
                        grindNormals[i] = grindCollider.transform.up;

                        if (transform.name.Contains("Metal"))
                        {
                            grindCollider.tag = "Metal";
                        }
                        if (transform.name.Contains("Wood"))
                        {
                            grindCollider.tag = "Wood";
                        }
                        if (transform.name.Contains("Concrete"))
                        {
                            grindCollider.tag = "Concrete";
                        }
                    }

                    grindNormals[grindNormals.Length - 1] = grindNormals[grindNormals.Length - 2];
                    splineComputer.SetPoints(splinePoints);
                    splineComputer.Evaluate(0.9);
                    for (int i = 0; i < grindPoints.Length; i++)
                    {
                        splineComputer.SetPointNormal(i, splineComputer.GetPointNormal(i, SplineComputer.Space.World) + grindNormals[i], SplineComputer.Space.World);
                    }
                }
                if (transform.name.Contains("GrindCollider"))
                {
                    transform.localScale = new Vector3(1f / go.transform.lossyScale.x, 1f / go.transform.lossyScale.y, transform.localScale.z);
                }
            }
        }
Пример #21
0
 private SplinePointVariance TranslateVariancePoint(SplinePoint point)
 {
     return((SplinePointVariance)point);
 }
Пример #22
0
        void Merge(int index, MergeSide mergingSide)
        {
            RecordUndo("Merge Splines");
            SplineComputer mergedSpline = availableMergeComputers[index];

            SplinePoint[]      mergedPoints = mergedSpline.GetPoints();
            SplinePoint[]      original     = spline.GetPoints();
            List <SplinePoint> pointsList   = new List <SplinePoint>();

            SplinePoint[] points;
            if (!mergeEndpoints)
            {
                points = new SplinePoint[mergedPoints.Length + original.Length];
            }
            else
            {
                points = new SplinePoint[mergedPoints.Length + original.Length - 1];
            }

            if (mergeSide == MergeSide.End)
            {
                if (mergingSide == MergeSide.Start)
                {
                    for (int i = 0; i < original.Length; i++)
                    {
                        pointsList.Add(original[i]);
                    }
                    for (int i = mergeEndpoints ? 1 : 0; i < mergedPoints.Length; i++)
                    {
                        pointsList.Add(mergedPoints[i]);
                    }
                }
                else
                {
                    for (int i = 0; i < original.Length; i++)
                    {
                        pointsList.Add(original[i]);
                    }
                    for (int i = 0; i < mergedPoints.Length - (mergeEndpoints ? 1 : 0); i++)
                    {
                        pointsList.Add(mergedPoints[(mergedPoints.Length - 1) - i]);
                    }
                }
            }
            else
            {
                if (mergingSide == MergeSide.Start)
                {
                    for (int i = 0; i < mergedPoints.Length - (mergeEndpoints ? 1 : 0); i++)
                    {
                        pointsList.Add(mergedPoints[(mergedPoints.Length - 1) - i]);
                    }
                    for (int i = 0; i < original.Length; i++)
                    {
                        pointsList.Add(original[i]);
                    }
                }
                else
                {
                    for (int i = mergeEndpoints ? 1 : 0; i < mergedPoints.Length; i++)
                    {
                        pointsList.Add(mergedPoints[i]);
                    }
                    for (int i = 0; i < original.Length; i++)
                    {
                        pointsList.Add(original[i]);
                    }
                }
            }
            points = pointsList.ToArray();
            double mergedPercent = (double)(mergedPoints.Length - 1) / (points.Length - 1);
            double from          = 0.0;
            double to            = 1.0;

            if (mergeSide == MergeSide.End)
            {
                from = 1.0 - mergedPercent;
                to   = 1.0;
            }
            else
            {
                from = 0.0;
                to   = mergedPercent;
            }


            List <Node> mergedNodes   = new List <Node>();
            List <int>  mergedIndices = new List <int>();

            for (int i = 0; i < mergedSpline.pointCount; i++)
            {
                Node node = mergedSpline.GetNode(i);
                if (node != null)
                {
                    mergedNodes.Add(node);
                    mergedIndices.Add(i);
                    Undo.RecordObject(node, "Disconnect Node");
                    mergedSpline.DisconnectNode(i);
                    i--;
                }
            }

            SplineUser[] subs = mergedSpline.GetSubscribers();
            for (int i = 0; i < subs.Length; i++)
            {
                mergedSpline.Unsubscribe(subs[i]);
                subs[i].spline   = spline;
                subs[i].clipFrom = DMath.Lerp(from, to, subs[i].clipFrom);
                subs[i].clipTo   = DMath.Lerp(from, to, subs[i].clipTo);
            }
            spline.SetPoints(points);

            if (mergeSide == MergeSide.Start)
            {
                spline.ShiftNodes(0, spline.pointCount - 1, mergedSpline.pointCount);
                for (int i = 0; i < mergedNodes.Count; i++)
                {
                    spline.ConnectNode(mergedNodes[i], mergedIndices[i]);
                }
            }
            else
            {
                for (int i = 0; i < mergedNodes.Count; i++)
                {
                    int connectIndex = mergedIndices[i] + original.Length;
                    if (mergeEndpoints)
                    {
                        connectIndex--;
                    }
                    spline.ConnectNode(mergedNodes[i], connectIndex);
                }
            }
            if (EditorUtility.DisplayDialog("Keep merged computer's GameObject?", "Do you want to keep the merged computer's game object?", "Yes", "No"))
            {
                Undo.DestroyObjectImmediate(mergedSpline);
            }
            else
            {
                for (int i = 0; i < mergedNodes.Count; i++)
                {
                    if (TransformUtility.IsParent(mergedNodes[i].transform, mergedSpline.transform))
                    {
                        Undo.SetTransformParent(mergedNodes[i].transform, mergedSpline.transform.parent, "Reparent Node");
                    }
                }
                Undo.DestroyObjectImmediate(mergedSpline.gameObject);
            }

            FindAvailableComputers();
        }
Пример #23
0
 /// <summary>
 /// Get the control point at <paramref name="index"/> from <paramref name="spline"/>
 /// </summary>
 public abstract float3 GetControlPoint(T spline, int index, SplinePoint pointType);
Пример #24
0
        public virtual void DuplicateSelected()
        {
            if (selectedPoints.Count == 0)
            {
                return;
            }
            RecordUndo("Duplicate Points");
            SplinePoint[] newPoints  = new SplinePoint[points.Length + selectedPoints.Count];
            SplinePoint[] duplicated = new SplinePoint[selectedPoints.Count];
            int           index      = 0;

            for (int i = 0; i < selectedPoints.Count; i++)
            {
                duplicated[index++] = points[selectedPoints[i]];
            }
            int min = points.Length - 1, max = 0;

            for (int i = 0; i < selectedPoints.Count; i++)
            {
                if (selectedPoints[i] < min)
                {
                    min = selectedPoints[i];
                }
                if (selectedPoints[i] > max)
                {
                    max = selectedPoints[i];
                }
            }
            int[] selected = selectedPoints.ToArray();
            selectedPoints.Clear();
            if (duplicationDirection == Spline.Direction.Backward)
            {
                for (int i = 0; i < min; i++)
                {
                    newPoints[i] = points[i];
                }
                for (int i = 0; i < duplicated.Length; i++)
                {
                    newPoints[i + min] = duplicated[i];
                    selectedPoints.Add(i + min);
                }
                for (int i = min; i < points.Length; i++)
                {
                    newPoints[i + duplicated.Length] = points[i];
                }
            }
            else
            {
                for (int i = 0; i <= max; i++)
                {
                    newPoints[i] = points[i];
                }
                for (int i = 0; i < duplicated.Length; i++)
                {
                    newPoints[i + max + 1] = duplicated[i];
                    selectedPoints.Add(i + max + 1);
                }
                for (int i = max + 1; i < points.Length; i++)
                {
                    newPoints[i + duplicated.Length] = points[i];
                }
            }
            points = newPoints;
            if (onDuplicatePoint != null)
            {
                onDuplicatePoint(selected);
            }
        }
Пример #25
0
 /// <summary>
 /// Abstraction of updating an existing point so that 2D and 3D can share the same tests
 /// </summary>
 public abstract void UpdateControlPoint(T spline, int index, float3 newPoint, SplinePoint pointType);
Пример #26
0
        public static void ConvertBezdatToTubes(string bezdatFilePath, string tubesFilePath, bool generatePlainTextVersion = false)
        {
            System.IO.StreamReader file = null;

            try
            {
                file = new System.IO.StreamReader(bezdatFilePath);
            }
            catch (Exception e)
            {
                Console.WriteLine("ERROR: Could not open file '" + bezdatFilePath.ToString() + "'.");
                Console.WriteLine(e.Message);

                return;
            }

            var firstLine = file.ReadLine();
            if (firstLine == null && firstLine != "BezDatA 1.0")
            {
                Console.WriteLine("ERROR: Expected to read 'BezDatA 1.0' on first line, but read '" + firstLine + "' instead.");
                return;
            }

            var points = new System.Collections.Generic.List<Point>();
            var indices = new System.Collections.Generic.List<int>();

            var maxIndex = 0;
            var lineCounter = 1;
            string line;
            while ((line = file.ReadLine()) != null)
            {
                string[] strs = line.Split(null);

                var len = strs.Length;
                if (len > 0)
                {
                    if (strs[0] == "PT")
                    {
                        if (len != 8)
                        {
                            Console.WriteLine("ERROR: Expected 7 values on line " + lineCounter.ToString() + ", but read " + (len - 1).ToString() + " values instead.");
                            file.Close();
                            return;
                        }

                        try
                        {
                            var point = new Point();

                            point.Px = Convert.ToSingle(strs[1], System.Globalization.CultureInfo.InvariantCulture);
                            point.Py = Convert.ToSingle(strs[2], System.Globalization.CultureInfo.InvariantCulture);
                            point.Pz = Convert.ToSingle(strs[3], System.Globalization.CultureInfo.InvariantCulture);

                            point.R = Convert.ToSingle(strs[4], System.Globalization.CultureInfo.InvariantCulture);

                            point.Cr = (float)Math.Pow(Convert.ToDouble(strs[5], System.Globalization.CultureInfo.InvariantCulture) / 255.0, 2.2);
                            point.Cg = (float)Math.Pow(Convert.ToDouble(strs[6], System.Globalization.CultureInfo.InvariantCulture) / 255.0, 2.2);
                            point.Cb = (float)Math.Pow(Convert.ToDouble(strs[7], System.Globalization.CultureInfo.InvariantCulture) / 255.0, 2.2);

                            points.Add(point);
                        }
                        catch (FormatException e)
                        {
                            Console.WriteLine("ERROR: FormatException on line " + lineCounter.ToString() + ".");
                            Console.WriteLine(e.Message);
                            file.Close();
                            return;
                        }
                        catch (OverflowException e)
                        {
                            Console.WriteLine("ERROR: OverflowException on line " + lineCounter.ToString() + ".");
                            Console.WriteLine(e.Message);
                            file.Close();
                            return;
                        }
                    }
                    else
                        if (strs[0] == "BC")
                        {
                            if (len != 5)
                            {
                                Console.WriteLine("ERROR: Expected 4 values on line " + lineCounter.ToString() + ", but read " + (len - 1).ToString() + " values instead.");
                                file.Close();
                                return;
                            }

                            try
                            {
                                for (var i = 1; i <= 4; ++i)
                                {
                                    var index = Convert.ToInt32(strs[i]);

                                    if (index < 0)
                                    {
                                        Console.WriteLine("ERROR: Negative index on line " + lineCounter.ToString() + ".");
                                        file.Close();
                                        return;
                                    }

                                    indices.Add(index);

                                    if (index > maxIndex) maxIndex = index;
                                }
                            }
                            catch (FormatException e)
                            {
                                Console.WriteLine("ERROR: FormatException on line " + lineCounter.ToString() + ".");
                                Console.WriteLine(e.Message);
                                file.Close();
                                return;
                            }
                            catch (OverflowException e)
                            {
                                Console.WriteLine("ERROR: OverflowException on line " + lineCounter.ToString() + ".");
                                Console.WriteLine(e.Message);
                                file.Close();
                                return;
                            }
                        }
                        else
                        {
                            Console.WriteLine("ERROR: Expected 'PT' or 'BC' as first string on line " + lineCounter.ToString() + ", but read '" + strs[0] + "' instead.");
                            file.Close();
                            return;
                        }
                }

                lineCounter++;
            }

            if (maxIndex > points.Count - 1)
            {
                Console.WriteLine("ERROR: Largest Index (" + maxIndex.ToString() + ") does not reference point.");
                file.Close();
                return;
            }

            var indexLen = indices.Count;
            if (indexLen == 0)
            {
                Console.WriteLine("ERROR: File does not contain nodes.");
                file.Close();
                return;
            }

            Console.WriteLine("SUCCESS: File '" + bezdatFilePath.ToString() + "' read.");
            file.Close();

            var sPoints = new System.Collections.Generic.List<SplinePoint>();

            var nodeCountPerTube = new System.Collections.Generic.List<int>();
            nodeCountPerTube.Add(0);

            var currTubeId = 0;
            var tangentDiscCount = 0;

            for (var i = 0; i <= indexLen; i += 4)
            {
                var i0 = i != 0 ? i - 2 : i + 0;
                var i1 = i != 0 ? i - 1 : i + 1;

                var i2 = i != indexLen ? i + 0 : i0;
                var i3 = i != indexLen ? i + 1 : i1;

                var index0 = indices[i0];
                var index1 = indices[i1];
                var index2 = indices[i2];
                var index3 = indices[i3];

                var p0 = points[index0];
                var p1 = points[index1];

                var p2 = points[index2];
                var p3 = points[index3];

                var tan0 = new Point();
                tan0.Px = (p1.Px - p0.Px) * 3.0f;
                tan0.Py = (p1.Py - p0.Py) * 3.0f;
                tan0.Pz = (p1.Pz - p0.Pz) * 3.0f;

                tan0.R = (p1.R - p0.R) * 3.0f;

                tan0.Cr = (p1.Cr - p0.Cr) * 3.0f;
                tan0.Cg = (p1.Cg - p0.Cg) * 3.0f;
                tan0.Cb = (p1.Cb - p0.Cb) * 3.0f;

                var tan1 = new Point();
                tan1.Px = (p3.Px - p2.Px) * 3.0f;
                tan1.Py = (p3.Py - p2.Py) * 3.0f;
                tan1.Pz = (p3.Pz - p2.Pz) * 3.0f;

                tan1.R = (p3.R - p2.R) * 3.0f;

                tan1.Cr = (p3.Cr - p2.Cr) * 3.0f;
                tan1.Cg = (p3.Cg - p2.Cg) * 3.0f;
                tan1.Cb = (p3.Cb - p2.Cb) * 3.0f;

                var pTanDiff = Pow2(tan1.Px - tan0.Px) + Pow2(tan1.Py - tan0.Py) + Pow2(tan1.Pz - tan0.Pz);
                var rTanDiff = Pow2(tan1.R - tan0.R);
                //var cTanDiff = Pow2(tan1.Cr - tan0.Cr) + Pow2(tan1.Cg - tan0.Cg) + Pow2(tan1.Cb - tan0.Cb);

                var tanDiffDelta = 0.001;

                var deltaCond = pTanDiff < tanDiffDelta && rTanDiff < tanDiffDelta;// && cTanDiff < tanDiffDelta;// do not check color delta due to high quantization error? or errors in the data...*shrug*
                var sharedNodeCond = index1 == index2;
                var overwrittenNodesCond = index0 == index2 && index1 == index3;

                if (sharedNodeCond && !deltaCond)
                    ++tangentDiscCount;

                if ((sharedNodeCond || overwrittenNodesCond) && deltaCond)
                {
                    var sPoint = new SplinePoint();

                    sPoint.V = i != indexLen ? p2 : p3;

                    sPoint.T = new Point();
                    sPoint.T.Px = (tan0.Px + tan1.Px) * 0.5f;
                    sPoint.T.Py = (tan0.Py + tan1.Py) * 0.5f;
                    sPoint.T.Pz = (tan0.Pz + tan1.Pz) * 0.5f;

                    sPoint.T.R = (tan0.R + tan1.R) * 0.5f;

                    sPoint.T.Cr = (tan0.Cr + tan1.Cr) * 0.5f;
                    sPoint.T.Cg = (tan0.Cg + tan1.Cg) * 0.5f;
                    sPoint.T.Cb = (tan0.Cb + tan1.Cb) * 0.5f;

                    sPoints.Add(sPoint);

                    ++nodeCountPerTube[currTubeId];
                }
                else
                {
                    var sPoint0 = new SplinePoint();

                    sPoint0.V = p1;
                    sPoint0.T = tan0;

                    sPoints.Add(sPoint0);

                    ++nodeCountPerTube[currTubeId];

                    var sPoint1 = new SplinePoint();

                    sPoint1.V = p2;
                    sPoint1.T = tan1;

                    sPoints.Add(sPoint1);

                    nodeCountPerTube.Add(1);
                    ++currTubeId;
                }
            }

            Console.WriteLine("Number of Tangent Discontinuities: " + tangentDiscCount.ToString());

            // create binary file
            {
                System.IO.BinaryWriter newFile = null;

                try
                {
                    newFile = new System.IO.BinaryWriter(System.IO.File.Open(tubesFilePath, System.IO.FileMode.Create));
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERROR: Could not create/open file '" + tubesFilePath.ToString() + "'.");
                    Console.WriteLine(e.Message);

                    return;
                }

                try
                {
                    var formatVersion = 1;
                    newFile.Write(formatVersion);// 1 x Int32

                    var tubeCount = nodeCountPerTube.Count;
                    newFile.Write(tubeCount);// 1 x Int32

                    foreach (int nodeCount in nodeCountPerTube)// tubeCount x Int32
                        newFile.Write(nodeCount);

                    var totalNodeCount = sPoints.Count;
                    newFile.Write(totalNodeCount);// 1 x Int32

                    foreach (SplinePoint node in sPoints)// totalNodeCount x (3 + 1 + 3) * 2 x Single
                    {
                        newFile.Write(node.V.Px);
                        newFile.Write(node.V.Py);
                        newFile.Write(node.V.Pz);

                        newFile.Write(node.V.R);

                        newFile.Write(node.V.Cr);
                        newFile.Write(node.V.Cg);
                        newFile.Write(node.V.Cb);

                        newFile.Write(node.T.Px);
                        newFile.Write(node.T.Py);
                        newFile.Write(node.T.Pz);

                        newFile.Write(node.T.R);

                        newFile.Write(node.T.Cr);
                        newFile.Write(node.T.Cg);
                        newFile.Write(node.T.Cb);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERROR: Failed to write value to file '" + tubesFilePath.ToString() + "'.");
                    Console.WriteLine(e.Message);

                    newFile.Close();
                    return;
                }

                Console.WriteLine("SUCCESS: File '" + tubesFilePath.ToString() + "' generated.");
                newFile.Close();
            }

            // create plain text file for debugging purposes
            if(generatePlainTextVersion)
            {
                var tubesTxtFilePath = tubesFilePath + ".txt";

                System.IO.StreamWriter newFile = null;

                try
                {
                    newFile = new System.IO.StreamWriter(System.IO.File.Open(tubesTxtFilePath, System.IO.FileMode.Create));
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERROR: Could not create/open file '" + tubesTxtFilePath.ToString() + "'.");
                    Console.WriteLine(e.Message);

                    return;
                }

                try
                {
                    var formatVersion = 1;
                    newFile.Write("Version: ");
                    newFile.Write(formatVersion);// 1 x Int32
                    newFile.Write(Environment.NewLine);

                    var tubeCount = nodeCountPerTube.Count;
                    newFile.Write("Tube Count: ");
                    newFile.Write(tubeCount);// 1 x Int32
                    newFile.Write(Environment.NewLine);

                    newFile.Write("Node Counts per Tube: ");
                    foreach (int nodeCount in nodeCountPerTube)// tubeCount x Int32
                    { newFile.Write(nodeCount); newFile.Write(" "); }

                    newFile.Write(Environment.NewLine);

                    var totalNodeCount = sPoints.Count;
                    newFile.Write("Total Node Count: ");
                    newFile.Write(totalNodeCount);// 1 x Int32

                    var n = 0;
                    newFile.Write(Environment.NewLine);
                    foreach (SplinePoint node in sPoints)// totalNodeCount x (3 + 1 + 3) * 2 x Single
                    {
                        newFile.Write(Environment.NewLine);

                        newFile.Write("Node " + n.ToString() + ":");
                        newFile.Write(Environment.NewLine);
                        ++n;

                        newFile.Write(node.V.Px.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" ");
                        newFile.Write(node.V.Py.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" ");
                        newFile.Write(node.V.Pz.ToString(System.Globalization.CultureInfo.InvariantCulture));
                        newFile.Write(Environment.NewLine);

                        newFile.Write(node.V.R.ToString(System.Globalization.CultureInfo.InvariantCulture));
                        newFile.Write(Environment.NewLine);

                        newFile.Write(node.V.Cr.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" ");
                        newFile.Write(node.V.Cg.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" ");
                        newFile.Write(node.V.Cb.ToString(System.Globalization.CultureInfo.InvariantCulture));
                        newFile.Write(Environment.NewLine);

                        newFile.Write(node.T.Px.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" ");
                        newFile.Write(node.T.Py.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" ");
                        newFile.Write(node.T.Pz.ToString(System.Globalization.CultureInfo.InvariantCulture));
                        newFile.Write(Environment.NewLine);

                        newFile.Write(node.T.R.ToString(System.Globalization.CultureInfo.InvariantCulture));
                        newFile.Write(Environment.NewLine);

                        newFile.Write(node.T.Cr.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" ");
                        newFile.Write(node.T.Cg.ToString(System.Globalization.CultureInfo.InvariantCulture)); newFile.Write(" ");
                        newFile.Write(node.T.Cb.ToString(System.Globalization.CultureInfo.InvariantCulture));
                        newFile.Write(Environment.NewLine);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("ERROR: Failed to write value to file '" + tubesTxtFilePath.ToString() + "'.");
                    Console.WriteLine(e.Message);

                    newFile.Close();
                    return;
                }

                Console.WriteLine("SUCCESS: File '" + tubesTxtFilePath.ToString() + "' generated.");
                newFile.Close();
            }
        }
        void PointsGUI()
        {
            CustomPathGenerator generator = (CustomPathGenerator)target;

            generator.customPathType = (Spline.Type)EditorGUILayout.EnumPopup("Custom Path Type", generator.customPathType);
            if (generator.points.Length >= 4)
            {
                generator.loop = EditorGUILayout.Toggle("Loop", generator.loop);
            }
            else
            {
                generator.loop = false;
            }

            string[] options = new string[(generator.loop ? generator.points.Length - 1 : generator.points.Length) + 1];
            for (int i = 0; i < options.Length - 1; i++)
            {
                options[i + 1] = "Point " + (i + 1);
            }
            options[0] = "- None -";
            EditorGUILayout.BeginHorizontal();
            selectedPoint = EditorGUILayout.Popup("Select Point", selectedPoint + 1, options) - 1;
            if ((!generator.loop && generator.points.Length >= 1) || (generator.loop && generator.points.Length > 4))
            {
                if (GUILayout.Button("X", GUILayout.Width(20)))
                {
                    ArrayUtility.RemoveAt(ref generator.points, selectedPoint);
                    selectedPoint--;
                }
            }
            EditorGUILayout.EndHorizontal();
            if (selectedPoint >= 0 && selectedPoint < generator.points.Length)
            {
                SplinePoint avgPoint = generator.points[selectedPoint];

                avgPoint.SetPosition(EditorGUILayout.Vector3Field("Position", avgPoint.position));
                if (generator.customPathType == Splines.Spline.Type.Bezier)
                {
                    EditorGUILayout.Space();
                    avgPoint.type = (SplinePoint.Type)EditorGUILayout.EnumPopup("Tangents Type", avgPoint.type);
                    avgPoint.SetTangent2Position(EditorGUILayout.Vector3Field("Front Tangent", avgPoint.tangent2));
                    avgPoint.SetTangentPosition(EditorGUILayout.Vector3Field("Back Tangent", avgPoint.tangent));
                    EditorGUILayout.Space();
                }
                else
                {
                    avgPoint.tangent  = avgPoint.position;
                    avgPoint.tangent2 = avgPoint.position;
                }
                avgPoint.normal = EditorGUILayout.Vector3Field("Normal", avgPoint.normal);
                avgPoint.normal.Normalize();

                EditorGUIUtility.labelWidth = 0f;
                avgPoint.size  = EditorGUILayout.FloatField("Size", avgPoint.size);
                avgPoint.color = EditorGUILayout.ColorField("Color", avgPoint.color);

                if (generator.loop)
                {
                    generator.points[generator.points.Length - 1] = generator.points[0];
                }
                generator.points[selectedPoint] = avgPoint;
            }

            if (GUILayout.Button("Create Point"))
            {
                SplinePoint newPoint = new SplinePoint();
                newPoint.color  = Color.white;
                newPoint.size   = 1f;
                newPoint.normal = Vector3.up;
                ArrayUtility.Add(ref generator.points, newPoint);
                selectedPoint = generator.points.Length - 1;
            }
        }