Example #1
0
        /// <summary>
        /// Returns closest point on all the given edges. Edge positions are changed to world coordinates in reference to refTransform.
        /// </summary>
        public static Vector3 GetClosestPointOnEdge(Vector3 point, List<Node> nodes, List<Edge> edges, Transform refTransform, out Edge closestEdge)
        {
            Vector3 pointOnEdge = Vector3.zero;
            closestEdge = edges[0];
            float closestDist = Mathf.Infinity;

            for (int i = 0; i < edges.Count; i++)
            {
                Vector2 splitPointXZ;

                Node node1 = EdgeGraphUtility.GetNode(edges[i].Node1, ref nodes);
                if (node1 == null) continue;

                Vector3 n1Pos = node1.Position;
                n1Pos = refTransform.TransformPoint(n1Pos);

                Node node2 = EdgeGraphUtility.GetNode(edges[i].Node2, ref nodes);
                if (node2 == null) continue;

                Vector3 n2Pos = node2.Position;
                n2Pos = refTransform.TransformPoint(n2Pos);

                splitPointXZ = Edge.GetClosestPointOnEdge(point, n1Pos, n2Pos);

                Vector3 splitPoint = new Vector3(splitPointXZ.x, n1Pos.y, splitPointXZ.y);

                if (Vector3.Distance(point, splitPoint) < closestDist)
                {
                    closestEdge = edges[i];
                    pointOnEdge = splitPoint;
                    closestDist = Vector3.Distance(point, splitPoint);
                }
            }

            return pointOnEdge;
        }
Example #2
0
        /// <summary>
        /// Makes copies of edges and nodes
        /// New edges will have new IDs and new copies of nodes
        /// </summary>
        public static void CopyNodesAndEdges(List<Node> _nodes, List<Edge> _edges, out List<Node> _newNodes, out List<Edge> _newEdges, bool adjacentCheck = true, bool cleanUp = true)
        {
            _newNodes = new List<Node>();
            _newEdges = new List<Edge>();

            //Refresh adjacent nodes
            if (adjacentCheck)
                CheckAdjacentNodes(ref _nodes, ref _edges);
            if (cleanUp)
                CleanUpEdges(ref _nodes, ref _edges);

            //Calculate angle between adjacent nodes
            for (int i = 0; i < _nodes.Count; i++)
            {
                Node adj1 = null;
                Node adj2 = null;

                if (i == 0)
                {
                    adj1 = _nodes[_nodes.Count - 1];
                    adj2 = _nodes[i + 1];
                }
                else if (i == _nodes.Count - 1)
                {
                    adj1 = _nodes[i - 1];
                    adj2 = _nodes[0];
                }
                else
                {
                    adj1 = _nodes[i - 1];
                    adj2 = _nodes[i + 1];
                }

                Vector3 dirToNode1 = (adj1.Position - _nodes[i].Position).normalized;
                Vector3 dirToNode2 = (adj2.Position - _nodes[i].Position).normalized;

                Vector3 referenceForward = -dirToNode1;
                Vector3 referenceRight = Vector3.Cross(Vector3.up, referenceForward);

                float angleBetweenAdjs = Vector3.Angle(dirToNode1, dirToNode2);
                float angle = Vector3.Angle(dirToNode2, referenceForward);

                //Angles are in counter clockwise order, so positive dot product with right reference means angle is more than 180 degrees
                float sign = Mathf.Sign(Vector3.Dot(dirToNode2, referenceRight));

                //Center position of this node and adjacent nodes
                //Vector3 center = (adj1.Position + adj2.Position + _nodes[i].Position) / 3f;
                Vector3 center = _nodes[i].Position + (dirToNode1 + dirToNode2).normalized;

                Vector3 dirToCenter = (center - _nodes[i].Position).normalized;

                if (sign > 0)
                {
                    _nodes[i].Angle = 180f + angle;
                    _nodes[i].dirToInside = -dirToCenter;
                }
                else
                {
                    _nodes[i].Angle = angleBetweenAdjs;
                    _nodes[i].dirToInside = dirToCenter;
                }
            }

            //Save old and new IDs of nodes in order <old, new>
            Dictionary<string, string> nodeIDPairs = new Dictionary<string, string>();

            //Make new nodes and save the link to the old one
            for (int i = 0; i < _nodes.Count; i++)
            {
                Node oldNode = _nodes[i];
                Node newNode = new Node(oldNode.Position, oldNode.Angle);
                newNode.dirToInside = oldNode.dirToInside;

                if (!nodeIDPairs.ContainsKey(oldNode.ID))
                {
                    nodeIDPairs.Add(oldNode.ID, newNode.ID);
                    _newNodes.Add(newNode);
                }
            }

            //Now that we have all the links made, we can refresh adjacents for new nodes
            for (int i = 0; i < _nodes.Count; i++)
            {
                for (int j = 0; j < _nodes[i].adjacents.Count; j++)
                {
                    string oldAdj = _nodes[i].adjacents[j];
                    Node newNode = _newNodes.Find(n => n.ID == nodeIDPairs[_nodes[i].ID]);
                    if (nodeIDPairs.ContainsKey(oldAdj))
                        newNode.adjacents.Add(nodeIDPairs[oldAdj]);
                    else
                        newNode.adjacents.Add(oldAdj);
                }
            }

            //Make new edges
            for (int i = 0; i < _edges.Count; i++)
            {
                Edge e = _edges[i];
                if (e == null) continue;

                //New nodes retrieved by using old node IDs
                Node n1 = _newNodes.Find(n => n.ID == nodeIDPairs[e.Node1]);
                Node n2 = _newNodes.Find(n => n.ID == nodeIDPairs[e.Node2]);

                Edge newE = new Edge(n1.ID, n2.ID, e.Width);

                _newEdges.Add(newE);
            }
        }
Example #3
0
        void DrawPrimitiveHandles()
        {
            if (currentEditorState != GraphEditorState.Primitives) return;

            if (graph.mainPrimitives != null && graph.mainPrimitives.Count > 0)
            {
                Primitive p = null;
                Node n1 = null;
                Node n2 = null;
                for (int i = 0; i < graph.mainPrimitives.Count; i++)
                {
                    p = graph.mainPrimitives[i];

                    foreach (var edge in p.edges)
                    {
                        n1 = p.nodes.Find(x => x.ID == edge.Node1);
                        n2 = p.nodes.Find(x => x.ID == edge.Node2);

                        if (n1 != null && n2 != null)
                        {
                            Handles.color = Color.cyan;
                            Color singleSelectColor = new Color(Color.red.r - .3f, Color.red.g - .3f, Color.red.b - .3f);
                            Color multiSelectColor = Color.red;

                            int indexMask = 1 << i;

                            if (singleSelectedPrimitiveIdx == i)
                                Handles.color = singleSelectColor;
                            else if ((selectedPrimitiveMask & indexMask) == indexMask)
                                Handles.color = multiSelectColor;

                            Handles.DrawLine(graph.transform.TransformPoint(n1.Position), graph.transform.TransformPoint(n2.Position));
                        }
                    }

                    if (debugMode)
                    {
                        for (int j = 0; j < p.nodes.Count; j++)
                        {
                            Vector3 center = graph.transform.TransformPoint(p.nodes[j].Position + p.nodes[j].dirToInside);
                            Handles.color = Color.green;
                            Handles.DrawLine(graph.transform.TransformPoint(p.nodes[j].Position), center);

                            Handles.Label(center, j.ToString(), "box");
                        }
                    }
                }

                if (SinglePrimitiveIsSelected)
                {
                    // Root index
                    // ----------------------------------------------------------------------------------------
                    p = graph.mainPrimitives[singleSelectedPrimitiveIdx];

                    int idx = p.subEdgeRootIndex;
                    if (idx >= p.nodes.Count)
                    {
                        idx = p.nodes.Count - 1;
                    }

                    Handles.color = Color.yellow;
                    int nextIdx = UtilityTools.Helper.GetNextIndex<Node>(p.nodes, idx);
                    Vector3 toNext = (p.nodes[nextIdx].Position - p.nodes[idx].Position).normalized;
                    Vector3 rightNormal = -UtilityTools.MathHelper.LeftSideNormal(toNext);
                    Vector3 pos = graph.transform.TransformPoint(p.nodes[idx].Position);
                    float dist = 3f;
                    //Handles.SphereCap(i, pos, Quaternion.identity, HandleUtility.GetHandleSize(pos) * .2f);
                    Handles.Label(pos + rightNormal * dist, "Root", "box");
                    Handles.DrawLine(pos, pos + rightNormal * dist);

                    // Root node modification
                    if (shiftIsPressed && !controlIsPressed)
                    {
                        subEdgeRootNode = EdgeGraphUtility.GetClosestNode(cursorWorldPosition, graph.mainPrimitives[singleSelectedPrimitiveIdx].nodes, graph.transform);

                        Vector3 nodePos = graph.transform.TransformPoint(subEdgeRootNode.Position);
                        Vector3 arrowDir = (cursorWorldPosition - nodePos).normalized;
                        Vector3 arrowPos = nodePos + arrowDir;
                        arrowPos += arrowDir * HandleUtility.GetHandleSize(arrowPos);
                        Quaternion arrowRot = Quaternion.LookRotation((nodePos - arrowPos).normalized);
                        Handles.ArrowCap(0, arrowPos, arrowRot, HandleUtility.GetHandleSize(arrowPos));
                        Handles.DrawLine(arrowPos, cursorWorldPosition);
                    }
                    // ----------------------------------------------------------------------------------------
                    // Create new subedges
                    // ----------------------------------------------------------------------------------------
                    if (activeSubNode >= 0 && controlIsPressed && !shiftIsPressed && p.subNodes != null && p.subNodes.Count > 0)
                    {
                        Node _selected = p.subNodes[activeSubNode];
                        float toClosest;
                        Node closestNode = CheckClosestNode(p.subNodes, out toClosest, _selected);
                        float toSelected = Vector3.Distance(_selected.Position, cursorLocalPosition);

                        if (toClosest < toSelected)
                        {
                            Handles.color = Color.green;
                            Handles.DrawLine(graph.transform.TransformPoint(_selected.Position), graph.transform.TransformPoint(closestNode.Position));

                            // Add the new edge
                            creatingNewSubEdge = new Edge(_selected.ID, closestNode.ID, p.subEdgeWidth);
                        }
                        else
                            creatingNewSubEdge = null;
                    }
                    // ----------------------------------------------------------------------------------------
                }
            }

            // Subgraphs

            if (graph.subGraphs != null && graph.subGraphs.Count > 0)
            {
                Node n1 = null;
                Node n2 = null;
                Primitive p = null;
                Edge edge = null;

                for (int i = 0; i < graph.subGraphs.Count; i++)
                {
                    if (graph.subGraphs[i] == null) continue;

                    Handles.color = new Color(0f, 1f, .5f, 1f);
                    for (int j = 0; j < graph.subGraphs[i].mainPrimitives.Count; j++)
                    {
                        p = graph.subGraphs[i].mainPrimitives[j];
                        for (int k = 0; k < p.edges.Count; k++)
                        {
                            edge = p.edges[k];
                            n1 = p.nodes.Find(x => x.ID == edge.Node1);
                            n2 = p.nodes.Find(x => x.ID == edge.Node2);

                            if (n1 != null && n2 != null)
                            {
                                Handles.DrawLine(graph.transform.TransformPoint(n1.Position), graph.transform.TransformPoint(n2.Position));
                            }
                        }
                    }
                }
            }
        }
Example #4
0
        void DrawEdgeHandles()
        {
            if (currentEditorState != GraphEditorState.Edges) return;

            Handles.color = Color.green * new Color(1f, 1f, 1f, .5f);

            DrawNodePositionHandles(controlIsPressed);

            // Adding new edges
            if (controlIsPressed && !setEdgeWidth)
            {
                /// -----------------------------------
                /// Connect two closest nodes to the cursor
                /// Wasn't that intuitive
                /// -----------------------------------
                //List<Node> _nodes = new List<Node>();
                //_nodes.AddRange(graph.nodes);

                //// Sort nodes according to the distance from cursor
                //_nodes.Sort((n1, n2) =>
                //{
                //    Vector3 n1Pos = graph.transform.TransformPoint(n1.Position);
                //    Vector3 n2Pos = graph.transform.TransformPoint(n2.Position);
                //    float distN1 = Vector3.Distance(n1Pos, cursorWorldPosition);
                //    float distN2 = Vector3.Distance(n2Pos, cursorWorldPosition);

                //    return distN1.CompareTo(distN2);
                //});

                //// Draw lines to closest nodes from the cursor
                //Handles.color = Color.green * new Color(1f, 1f, 1f, .5f);
                //Handles.DrawLine(cursorWorldPosition, graph.transform.TransformPoint(_nodes[0].Position));
                //Handles.DrawLine(cursorWorldPosition, graph.transform.TransformPoint(_nodes[1].Position));

                //Handles.color = Color.yellow;
                //Handles.DrawLine(graph.transform.TransformPoint(_nodes[0].Position), graph.transform.TransformPoint(_nodes[1].Position));
                /// -----------------------------------

                /// -----------------------------------
                /// Connect selected node and closest other node to cursor
                /// -----------------------------------

                if (activeNode >= 0 && activeNode < graph.nodes.Count)
                {
                    Node _selected = graph.nodes[activeNode];
                    float toClosest;
                    Node closestNode = CheckClosestNode(graph.nodes, out toClosest, _selected);
                    float toSelected = Vector3.Distance(_selected.Position, cursorLocalPosition);

                    if (toClosest < toSelected)
                    {
                        Handles.color = Color.green;
                        Handles.DrawLine(graph.transform.TransformPoint(_selected.Position), graph.transform.TransformPoint(closestNode.Position));

                        // Add the new edge
                        creatingNewEdge = new Edge(_selected.ID, closestNode.ID);
                    }
                    else
                        creatingNewEdge = null;
                }
            }

            // Deleting edges
            Handles.color = new Color(1f, 0f, 0f, .5f);
            if (shiftIsPressed && !controlIsPressed && !setEdgeWidth)
            {
                //float toClosestNode;
                //Node closestNode = CheckClosestNode(graph.nodes, out toClosestNode);
                //float toClosestEdge = CheckClosestEdge();

                Handles.color = new Color(1f, 0f, 0f, .5f);
                Handles.SphereCap(0, graph.GetEdgePosition(closestEdge.ID), Quaternion.identity, HandleUtility.GetHandleSize(graph.GetEdgePosition(closestEdge.ID)) * .4f);

                Handles.color = Color.blue;

                for (int i = 0; i < graph.edges.Count; i++)
                {
                    Handles.CubeCap(i, graph.GetEdgePosition(graph.edges[i].ID), Quaternion.identity, HandleUtility.GetHandleSize(graph.GetEdgePosition(graph.edges[i].ID)) * .2f);
                }
            }

            // Edge width setting and debug information
            if (graph.edges != null && graph.edges.Count > 0)
            {
                edgesToSetWidth = new List<Edge>();

                for (int i = 0; i < graph.edges.Count; i++)
                {
                    Handles.color = Color.yellow;
                    Node n1 = graph[graph.edges[i].Node1];
                    Node n2 = graph[graph.edges[i].Node2];
                    if (n1 != null && n2 != null)
                    {

                        Handles.DrawLine(graph.transform.TransformPoint(n1.Position), graph.transform.TransformPoint(n2.Position));
                        Vector3 edgePos = graph.GetEdgePosition(graph.edges[i].ID);
                        float handleSize = HandleUtility.GetHandleSize(edgePos) * .2f;

                        if (setEdgeWidth)
                        {
                            if (Vector3.Distance(cursorWorldPosition, edgePos) <= setEdgeWidthBrushSize)
                            {
                                Handles.color = Color.green;
                                edgesToSetWidth.Add(graph.edges[i]);
                            }

                            Handles.CubeCap(i, edgePos, Quaternion.identity, handleSize);
                            Handles.DrawLine(edgePos, edgePos + Vector3.right + Vector3.back);
                            Handles.Label(edgePos + Vector3.right + Vector3.back, string.Format("{0:0.0}", graph.edges[i].Width), "box");
                        }

                        if (debugMode)
                        {
                            //Edge normals
                            Handles.color = Color.red;
                            Vector3 edgePerpLeft = Edge.GetLeftPerpendicular(n1.Position, n2.Position);
                            Handles.DrawLine(edgePos, edgePos + edgePerpLeft * .1f);

                            Handles.color = Color.blue;
                            Vector3 edgePerpRight = Edge.GetRightPerpendicular(n1.Position, n2.Position);
                            Handles.DrawLine(edgePos, edgePos + edgePerpRight * .1f);

                            //Edge widths visualized
                            Handles.color = Color.yellow;
                            float edgeWidth = graph.edges[i].Width / 2f;
                            Vector3 left1 = graph.transform.TransformPoint(n1.Position + edgePerpLeft.normalized * edgeWidth);
                            Vector3 left2 = graph.transform.TransformPoint(n2.Position + edgePerpLeft.normalized * edgeWidth);

                            Vector3 right1 = graph.transform.TransformPoint(n1.Position + edgePerpRight.normalized * edgeWidth);
                            Vector3 right2 = graph.transform.TransformPoint(n2.Position + edgePerpRight.normalized * edgeWidth);

                            Handles.DrawDottedLine(left1, left2, HandleUtility.GetHandleSize((left1 + left2) / 2f));
                            Handles.DrawDottedLine(right1, right2, HandleUtility.GetHandleSize((right1 + right2) / 2f));
                        }
                    }
                }
            }
        }
Example #5
0
        void PrimitiveTools()
        {
            if (currentEditorState != GraphEditorState.Primitives) return;

            if (mouseIsPressed && !shiftIsPressed && !controlIsPressed)
            {
                if (activeSubNode >= 0 && singleSelectedPrimitiveIdx >= 0 && singleSelectedPrimitiveIdx < graph.mainPrimitives.Count &&
                    activeSubNode >= 0 && activeSubNode < graph.mainPrimitives[singleSelectedPrimitiveIdx].subNodes.Count)
                {
                    graph.mainPrimitives[singleSelectedPrimitiveIdx].subNodes[activeSubNode].Position = cursorLocalPosition;
                }
            }

            //if (MouseClickedDown)
            //{

            //}

            if (mouseWasReleased)
            {
                // Adding new subedge
                if (controlIsPressed && !shiftIsPressed && SinglePrimitiveIsSelected && creatingNewSubEdge != null)
                {
                    graph.mainPrimitives[singleSelectedPrimitiveIdx].subEdges.Add(creatingNewSubEdge);
                    creatingNewSubEdge = null;
                }

                //Select primitive
                if (!shiftIsPressed && graph.mainPrimitives != null && graph.mainPrimitives.Count > 0 && activeSubNode == -1)
                {
                    singleSelectedPrimitiveIdx = -1;
                    int primitiveClicked = -1;

                    for (int i = 0; i < graph.mainPrimitives.Count; i++)
                    {
                        if (EdgeGraphUtility.PointIsInside(cursorLocalPosition, graph.mainPrimitives[i].nodes, graph.mainPrimitives[i].edges))
                        {
                            primitiveClicked = i;
                            break;
                        }
                    }

                    if (controlIsPressed && selectedPrimitiveMask != 0 && selectedPrimitiveMask != (1 << primitiveClicked))
                    {
                        selectedPrimitiveMask |= 1 << primitiveClicked;
                    }
                    else if (primitiveClicked != -1)
                    {
                        singleSelectedPrimitiveIdx = primitiveClicked;
                        selectedPrimitiveMask = 1 << primitiveClicked;
                    }
                    else
                    {
                        selectedPrimitiveMask = 0;
                    }

                    GUI.changed = true;
                }

                // Change subedge root index
                if (shiftIsPressed && !controlIsPressed && SinglePrimitiveIsSelected && subEdgeRootNode != null)
                {
                    //subEdgeRootNode = EdgeGraphUtility.GetClosestNode(cursorWorldPosition, graph.mainPrimitives[selectedPrimitiveIdx].nodes, graph.transform);

                    int subEdgeRootIdx = graph.mainPrimitives[singleSelectedPrimitiveIdx].nodes.IndexOf(subEdgeRootNode);

                    graph.mainPrimitives[singleSelectedPrimitiveIdx].subEdgeRootIndex = subEdgeRootIdx;
                }
            }
        }
Example #6
0
        void EdgeTools()
        {
            if (graph.nodes == null || graph.nodes.Count <= 0 || currentEditorState != GraphEditorState.Edges) return;

            if (mouseWasReleased)
            {
                // Edge removal
                float toClosest;
                Node closestNode = CheckClosestNode(graph.nodes, out toClosest);
                if (shiftIsPressed && !controlIsPressed && closestNode != null && !setEdgeWidth)
                {
                    graph.edges.Remove(closestEdge);
                }
                // Edge adding
                if (controlIsPressed && creatingNewEdge != null && !setEdgeWidth)
                {
                    graph.edges.Add(creatingNewEdge);
                    creatingNewEdge = null;
                }
            }

            // Edge width setting brush
            if (mouseIsPressed && setEdgeWidth)
            {
                foreach (var edge in edgesToSetWidth)
                    edge.Width = setEdgeToWidth;
            }
        }
Example #7
0
        /// Move selected node while dragging
        void NodeTools()
        {
            if (currentEditorState != GraphEditorState.Nodes) return;

            // Moving nodes
            if (mouseIsPressed && !shiftIsPressed && !controlIsPressed && activeNode >= 0 && activeNode < graph.nodes.Count)
            {
                graph.nodes[activeNode].Position = cursorLocalPosition;
            }

            if (mouseWasReleased)
            {
                // Node deleting
                float toClosest;
                Node closestNode = CheckClosestNode(graph.nodes, out toClosest);
                if (shiftIsPressed && !controlIsPressed && closestNode != null)
                {
                    graph.RemoveNode(closestNode.ID);
                }
            }

            if (MouseClickedDown)
            {
                // Node adding
                if (controlIsPressed)
                {
                    if (shiftIsPressed)
                    {
                        Vector3 splitPointLocal = graph.transform.InverseTransformPoint(EdgeGraphUtility.GetClosestPointOnEdge(cursorWorldPosition, graph.nodes, graph.edges, graph.transform, out closestEdge));

                        Node newNode = new Node(splitPointLocal);

                        graph.nodes.Add(newNode);
                        graph.edges.Add(new Edge(closestEdge.Node1, newNode.ID, closestEdge.Width));
                        graph.edges.Add(new Edge(newNode.ID, closestEdge.Node2, closestEdge.Width));

                        graph.edges.Remove(closestEdge);
                        closestEdge = null;
                    }
                    else
                    {
                        if (connectNewNode)
                        {
                            Node newNode = new Node(cursorLocalPosition);
                            graph.nodes.Add(newNode);
                            float toClosest;
                            Node closestNode = CheckClosestNode(graph.nodes, out toClosest);
                            if (closestNode != null)
                                graph.edges.Add(new Edge(closestNode.ID, newNode.ID));
                        }
                        else
                            graph.nodes.Add(new Node(cursorLocalPosition));
                    }
                }

            }
        }