Пример #1
0
 public Node(Node node)
 {
     _id = node.ID;
     position = node.Position;
     adjacents = node.adjacents;
     angle = node.angle;
 }
Пример #2
0
        public EdgeBuilder(Node _root, List<Vector3> _targets, float _edgeWidth, float _segment, float _minAngle, float _minDistance, float _maxDistance, Action<List<Node>, List<Edge>> onFinished)
        {
            //m_rootNode = new Node(_root.Position);
            m_rootNode = _root;
            m_edgeWidth = _edgeWidth;
            m_segmentLength = _segment;
            m_minAngle = _minAngle;
            m_minDistance = _minDistance;
            m_maxDistance = _maxDistance;

            edges = new List<Edge>();
            nodes = new List<Node>();
            m_nodeGrowCounts = new Dictionary<string, int>();
            m_nodeGrowDirections = new Dictionary<string, Vector3>();
            m_nodeStack = new Stack<Node>();
            m_visitedTargets = new List<Target>();

            m_targets = new List<Target>();
            if (_targets.Count > 0)
            {
                _targets.ForEach((t) => m_targets.Add(new Target(t)));
                StartBuild(onFinished);
            }

        }
Пример #3
0
        void StartBuild(Action<List<Node>, List<Edge>> onFinished)
        {
            // Create first edge from root to first target
            float toClosest;
            Target initTarget = GetClosestNonVisitedTarget(m_rootNode, out toClosest, false);
            m_visitedTargets.Add(initTarget);

            m_currentNode = new Node(initTarget.position);
            nodes.Add(m_currentNode);
            m_nodeStack.Push(m_currentNode);

            m_currentNode.adjacents.Add(m_rootNode.ID);
            m_rootNode.adjacents.Add(m_currentNode.ID);

            edges.Add(new Edge(m_rootNode.ID, m_currentNode.ID, m_edgeWidth));

            // Get next target and advance to it
            Target currentTarget = GetClosestNonVisitedTarget(m_currentNode, out toClosest, false);

            AdvanceUntilClosest(ref m_currentNode, currentTarget, toClosest);

            // Build other edges
            BuildEdgesRecursive();

            EdgeGraphUtility.FixIntersectingEdges(ref nodes, ref edges);

            if (onFinished != null)
                onFinished(nodes, edges);
        }
Пример #4
0
        public string GetAdjacentNode(Node current)
        {
            if (current.ID == node1)
                return node2;
            if (current.ID == node2)
                return node1;

            return null;
        }
Пример #5
0
        public static Edge FindEdgeByNodes(Node n1, Node n2, List<Edge> _edges)
        {
            if (n1 == null || n2 == null) return null;

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

                if ((_edges[i].Node1 == n1.ID && _edges[i].Node2 == n2.ID)
                    || (_edges[i].Node1 == n2.ID && _edges[i].Node2 == n1.ID))
                {
                    return _edges[i];
                }
            }

            return null;
        }
Пример #6
0
        /// <summary>
        /// Gets closest node to point
        /// </summary>
        /// <param name="nodes"></param>
        /// <param name="point"></param>
        /// <returns></returns>
        public static Node GetClosestNode(List<Node> nodes, Node other)
        {
            Node closest = null;
            float toClosest = Mathf.Infinity;
            float toCurrent = Mathf.Infinity;
            for (int i = 0; i < nodes.Count; i++)
            {
                if (nodes[i] == other) continue;

                toCurrent = Vector3.Distance(nodes[i].Position, other.Position);
                if (toCurrent < toClosest)
                {
                    closest = nodes[i];
                    toClosest = toCurrent;
                }
            }

            return closest;
        }
Пример #7
0
        void CombineSubNodes(Node _rootNode, List<Node> _nodes, List<Edge> _edges, float _combineRange, bool ensureRootEdge = true)
        {
            if (_combineRange > 0f)
            {
                for (int safe = 0; safe < 100; safe++)
                {
                    bool wasCombined = false;

                    for (int i = 0; i < _nodes.Count; i++)
                    {
                        //Get closest node
                        Node closest = Node.GetClosestNode(_nodes, _nodes[i]);
                        if (closest == _nodes[i] || closest == null) continue;

                        if (Vector3.Distance(_nodes[i].Position, closest.Position) < _combineRange)
                        {
                            _nodes[i] = Node.CombineNodes(_nodes[i], closest, _edges, _nodes);
                            _nodes.Remove(closest);
                            wasCombined = true;
                        }
                    }
                    if (!wasCombined)
                        break;
                }
            }

            if (!ensureRootEdge) return;

            // Ensure the edge between first node and root node
            Edge rootEdge = null;
            for (int i = 0; i < _edges.Count; i++)
            {
                if ((_edges[i].Node1 == _rootNode.ID && _edges[i].Node2 == _nodes[0].ID) ||
                    (_edges[i].Node2 == _rootNode.ID && _edges[i].Node1 == _nodes[0].ID))
                {
                    rootEdge = _edges[i];
                }
            }

            if (rootEdge == null)
            {
                rootEdge = new Edge(_rootNode.ID, _nodes[0].ID, subEdgeWidth);
                _edges.Add(rootEdge);
            }
        }
Пример #8
0
        /// <summary>
        /// Combines two nodes into one
        /// </summary>
        /// <param name="node1">First node, this node is transformed into the combined node</param>
        /// <param name="node2">Second node</param>
        /// <param name="edges">List of edges in which the IDs are fixed</param>
        /// <returns>Combined node</returns>
        public static Node CombineNodes(Node node1, Node node2, List<Edge> edges, List<Node> nodes)
        {
            //Combine node positions
            node1.position = (node1.position + node2.position) / 2f;
            //Fix edges
            for (int i = 0; i < edges.Count; i++)
            {
                //Remove edges that end in the node2, which will be removed
                if (node2.adjacents.Count == 1 && (edges[i].Node1 == node2.ID || edges[i].Node2 == node2.ID))
                {
                    edges.RemoveAt(i);
                    i--;
                    continue;
                }

                if (edges[i].Node1 == node2.ID)
                    edges[i].Node1 = node1.ID;

                if (edges[i].Node2 == node2.ID)
                    edges[i].Node2 = node1.ID;
            }

            EdgeGraphUtility.CleanUpEdges(ref nodes, ref edges);

            //Fix node adjacents
            EdgeGraphUtility.CheckAdjacentNodes(ref nodes, ref edges);

            return node1;
        }
Пример #9
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));
                            }
                        }
                    }
                }
            }
        }
Пример #10
0
        public void CutAcuteAngles()
        {
            if (type != PrimitiveType.MinimalCycle) return;

            List<Node> _nodesToRemove = new List<Node>();
            List<Node> _newNodes = new List<Node>();
            List<Edge> _newEdges = new List<Edge>();

            // Old edges are kept in the edges list, but node changes are saved here and refreshed to the edges once all angles are checked
            Dictionary<string, List<NodePair>> nodesToSwitchInEdges = new Dictionary<string, List<NodePair>>();

            for (int i = 0; i < nodes.Count; i++)
            {
                Node prevNode = EdgeGraphUtility.GetNode(nodes[i].adjacents[0], ref nodes);
                Node nextNode = EdgeGraphUtility.GetNode(nodes[i].adjacents[1], ref nodes);

                Vector3 dirToPrev = (prevNode.Position - nodes[i].Position).normalized;
                Vector3 dirToNext = (nextNode.Position - nodes[i].Position).normalized;

                Edge prevEdge = EdgeGraphUtility.FindEdgeByNodes(nodes[i], prevNode, edges);
                Edge nextEdge = EdgeGraphUtility.FindEdgeByNodes(nodes[i], nextNode, edges);

                float angle = Vector3.Angle(dirToPrev, dirToNext);
                if (angle < 45f)
                {
                    // Move nodes so that the cut side is 1f wide
                    float distanceToMove = .55f / Mathf.Sin(Mathf.Deg2Rad * angle / 2f);

                    float distToPrev = Vector3.Distance(prevNode.Position, nodes[i].Position);
                    float distToNext = Vector3.Distance(nextNode.Position, nodes[i].Position);

                    if (distanceToMove > distToPrev)
                        distanceToMove = distToPrev * .8f;

                    if (distanceToMove > distToNext)
                        distanceToMove = distToNext * .8f;

                    Vector3 newNodePrevPos = (nodes[i].Position + dirToPrev * distanceToMove);
                    Vector3 newNodeNextPos = (nodes[i].Position + dirToNext * distanceToMove);

                    string oldNodeID = nodes[i].ID;

                    // Remove old node
                    _nodesToRemove.Add(nodes[i]);

                    // Make new nodes
                    Node newNodeToPrev = new Node(newNodePrevPos);

                    Node newNodeToNext = new Node(newNodeNextPos);

                    if (!nodesToSwitchInEdges.ContainsKey(prevEdge.ID))
                        nodesToSwitchInEdges.Add(prevEdge.ID, new List<NodePair>());

                    nodesToSwitchInEdges[prevEdge.ID].Add(new NodePair(oldNodeID, newNodeToPrev.ID));

                    if (!nodesToSwitchInEdges.ContainsKey(nextEdge.ID))
                        nodesToSwitchInEdges.Add(nextEdge.ID, new List<NodePair>());

                    nodesToSwitchInEdges[nextEdge.ID].Add(new NodePair(oldNodeID, newNodeToNext.ID));

                    // Add the new edge
                    Edge newEdge = new Edge(newNodeToNext.ID, newNodeToPrev.ID);

                    _newEdges.Add(newEdge);

                    // Add new nodes to the dict
                    _newNodes.Add(newNodeToPrev);
                    _newNodes.Add(newNodeToNext);
                }
            }

            foreach (var n in _nodesToRemove)
            {
                for (int i = 0; i < nodes.Count; i++)
                {
                    if (nodes[i].ID == n.ID)
                    {
                        nodes.RemoveAt(i);
                        i--;
                    }
                }
            }

            foreach (var kvp in nodesToSwitchInEdges)
            {
                for (int i = 0; i < edges.Count; i++)
                {
                    if (edges[i].ID == kvp.Key)
                    {
                        Edge e = edges[i];
                        for (int j = 0; j < kvp.Value.Count; j++)
                        {
                            NodePair pair = kvp.Value[j];
                            if (e.Node1 == pair.oldNode) e.Node1 = pair.newNode;
                            if (e.Node2 == pair.oldNode) e.Node2 = pair.newNode;
                        }
                    }
                }
            }

            _newEdges.ForEach((e) => edges.Add(e));
            _newNodes.ForEach((n) => nodes.Add(n));

            EdgeGraphUtility.CleanUpEdges(ref nodes, ref edges);
            EdgeGraphUtility.CheckAdjacentNodes(ref nodes, ref edges);

        }
Пример #11
0
 public static Edge RemoveEdgeAndCleanAdjacents(Node _n0, Node _n1, ref List<Node> _nodes, ref List<Edge> _edges)
 {
     Edge e = FindEdgeByNodes(_n0, _n1, _edges);
     if (e != null && _edges.Contains(e))
     {
         if (_edges.Remove(e))
         {
             CheckAdjacentNodes(ref _nodes, ref _edges);
         }
     }
     return e;
 }
Пример #12
0
        /// <summary>
        /// Splits given edge into two edges at given point
        /// If a node is given, it will be used to split the edges
        /// Otherwise make a new node
        /// </summary>
        public static Node SplitEdge(Edge edge, Vector3 point, List<Node> nodes, List<Edge> edges, Node node = null)
        {
            bool isNewNode = false;
            // Create new node
            if (node == null)
            {
                node = new Node(point);
                isNewNode = true;
            }

            // Get start and end nodes of the edge
            Node start = Node.GetNode(nodes, edge.Node1);
            Node end = Node.GetNode(nodes, edge.Node2);

            // Add new node between start and end
            start.adjacents.Remove(end.ID);
            end.adjacents.Remove(start.ID);

            start.adjacents.Add(node.ID);
            end.adjacents.Add(node.ID);

            int startIndex = nodes.IndexOf(start);

            if (startIndex == -1)
            {
                Debug.LogError("Edge::SplitEdge() - StartIndex not found. Are you sure you gave the right node list?");
                return null;
            }

            if (isNewNode)
            {
                if (startIndex == nodes.Count - 1)
                    nodes.Add(node);
                else
                    nodes.Insert(startIndex + 1, node);
            }

            // Remove original edge from edges
            edges.Remove(edge);

            // Create new edges
            Edge e1 = new Edge(start.ID, node.ID, edge.width);
            Edge e2 = new Edge(node.ID, end.ID, edge.width);

            edges.Add(e1);
            edges.Add(e2);

            return node;
        }
Пример #13
0
        Node CheckClosestNode(List<Node> nodes, out float toClosest, Node ignore = null)
        {
            toClosest = Mathf.Infinity;
            if (nodes == null || nodes.Count <= 0) return null;

            Node closestNode = nodes[0];
            for (int i = 0; i < nodes.Count; i++)
            {
                if (ignore != null && nodes[i] == ignore) continue;

                Vector3 currentPos = graph.transform.TransformPoint(nodes[i].Position);
                float toCurrent = Vector3.Distance(currentPos, cursorWorldPosition);
                Vector3 closestPos = graph.transform.TransformPoint(closestNode.Position);
                toClosest = Vector3.Distance(closestPos, cursorWorldPosition);

                if (toCurrent < toClosest)
                {
                    closestNode = nodes[i];
                    toClosest = toCurrent;
                }
            }

            return closestNode;
        }
Пример #14
0
 public static void RemoveNodeAndCleanAdjacents(Node n, ref List<Node> _nodes, ref List<Edge> _edges)
 {
     if (_nodes.Remove(n))
     {
         for (int i = 0; i < _nodes.Count; i++)
         {
             if (_nodes[i] != n && _nodes[i].adjacents.Contains(n.ID))
                 _nodes[i].adjacents.Remove(n.ID);
         }
     }
 }
Пример #15
0
        /// <summary>
        /// Get closest non visited target
        /// </summary>
        Target GetClosestNonVisitedTarget(Node node, out float toClosest, bool checkMaxDistance = true)
        {
            Vector3 nodePos = node.Position;
            Target closest = null;
            float _toClosest = Mathf.Infinity;
            foreach (var t in m_targets)
            {
                float toTarget = Vector3.Distance(nodePos, t.position);
                if (toTarget < _toClosest && !m_visitedTargets.Contains(t))
                {
                    if (checkMaxDistance && toTarget > m_maxDistance)
                        continue;

                    closest = t;
                    _toClosest = Vector3.Distance(nodePos, closest.position);
                }
            }

            toClosest = _toClosest;
            return closest;
        }
Пример #16
0
        public static Node GetCounterClockwiseMostAdjacent(Node prev, Node curr, ref List<Node> _nodes)
        {
            if (curr.adjacents == null || curr.adjacents.Count == 0) return null;

            Vector3 dirCurr = Vector3.zero;

            dirCurr = curr.Position - prev.Position;

            Node next = EdgeGraphUtility.GetNode(curr.GetAdjacent(prev.ID), ref _nodes);
            if (next == null) return null;

            Vector3 dirNext = next.Position - curr.Position;

            bool currIsConvex = DotPerp(dirNext, dirCurr) <= 0;

            foreach (var a in curr.adjacents)
            {
                var adj = EdgeGraphUtility.GetNode(a, ref _nodes);
                Vector3 dirAdj = adj.Position - curr.Position;
                if (currIsConvex)
                {
                    if (DotPerp(dirCurr, dirAdj) > 0 && DotPerp(dirNext, dirAdj) > 0)
                    {
                        next = adj;
                        dirNext = dirAdj;
                        currIsConvex = DotPerp(dirNext, dirCurr) <= 0;
                    }
                }
                else
                {
                    if (DotPerp(dirCurr, dirAdj) > 0 || DotPerp(dirNext, dirAdj) > 0)
                    {
                        next = adj;
                        dirNext = dirAdj;
                        currIsConvex = DotPerp(dirNext, dirCurr) <= 0;
                    }
                }
            }

            return next;
        }
Пример #17
0
        void AdvanceUntilClosest(ref Node currentNode, Target closest, float toClosest)
        {
            Vector3 currentDir = (closest.position - currentNode.Position).normalized;

            int counter = 0;
            float lastToClosest = 0f;

            while (counter < 100)
            {
                if (toClosest > m_minDistance)
                {
                    currentDir = (closest.position - currentNode.Position).normalized;

                    if (Advance(ref currentNode, currentDir))
                        m_nodeStack.Push(currentNode);

                    lastToClosest = toClosest;
                    toClosest = Vector3.Distance(currentNode.Position, closest.position);

                    // If we are suddenly going away from the closest node, end
                    if (toClosest > lastToClosest)
                        break;
                }
                else
                    break;
                counter++;
            }

            m_visitedTargets.Add(closest);
        }
Пример #18
0
        void ColonizeSpace()
        {
            //Process targets
            for (int i = 0; i < m_targets.Count; i++)
            {
                bool targetRemoved = false;

                m_targets[i].closestNode = null;
                Vector3 direction = Vector3.zero;

                //Find closest node for this target
                for (int j = 0; j < nodes.Count; j++)
                {
                    direction = m_targets[i].position - nodes[j].Position;
                    float distance = direction.magnitude;
                    direction.Normalize();

                    //If min distance is reached, we remove the target
                    if (distance <= m_minDistance)
                    {
                        m_targets.RemoveAt(i);
                        i--;
                        targetRemoved = true;
                        break;
                    }
                    //If target is in range, check if it is closest
                    else if (distance <= m_maxDistance)
                    {
                        if (m_targets[i].closestNode == null)
                            m_targets[i].closestNode = nodes[j];
                        else if ((m_targets[i].position - m_targets[i].closestNode.Position).magnitude > distance)
                            m_targets[i].closestNode = nodes[j];
                    }

                    //If target is not removed, set the grow parameters on all the closest nodes that are in range
                    if (!targetRemoved && m_targets[i].closestNode != null)
                    {
                        Vector3 dir = (m_targets[i].position - m_targets[i].closestNode.Position).normalized;
                        string closestID = m_targets[i].closestNode.ID;
                        if (m_nodeGrowDirections.ContainsKey(closestID))
                            m_nodeGrowDirections[closestID] += dir;
                        else
                            m_nodeGrowDirections.Add(closestID, dir);

                        if (m_nodeGrowCounts.ContainsKey(closestID))
                            m_nodeGrowCounts[closestID]++;
                        else
                            m_nodeGrowCounts.Add(closestID, 1);
                    }
                }
            }

            //Advance nodes towards nearest targets
            bool nodeAdded = false;
            for (int i = 0; i < nodes.Count; i++)
            {
                string nodeID = nodes[i].ID;
                //If at least one target is affecting the current node
                if (m_nodeGrowCounts.ContainsKey(nodeID) && m_nodeGrowCounts[nodeID] > 0)
                {
                    Vector3 avgDirection = m_nodeGrowDirections[nodeID] / (float)m_nodeGrowCounts[nodeID];
                    avgDirection.Normalize();

                    Node newNode = new Node(nodes[i].Position);
                    nodes.Add(newNode);
                    if (Advance(ref newNode, avgDirection))
                    {
                        m_nodeGrowCounts[nodeID] = 0;
                        m_nodeGrowDirections[nodeID] = Vector3.zero;
                        nodeAdded = true;
                    }
                }
            }

            //If no nodes were added, we are done
            if (!nodeAdded)
                m_isFinished = true;
        }
Пример #19
0
        void BuildEdges()
        {
            float toClosest;
            Target currentTarget = GetClosestNonVisitedTarget(m_currentNode, out toClosest);

            //If no target was found, trace back node stack
            if (currentTarget == null)
            {
                for (int i = 0; i < m_nodeStack.Count; i++)
                {
                    Node n = m_nodeStack.Pop();
                    currentTarget = GetClosestNonVisitedTarget(n, out toClosest);
                    if (currentTarget != null)
                    {
                        m_currentNode = n;
                        break;
                    }
                }

                /// If no target was found but there is still unvisited targets,
                /// connect one of these targets to the closest node from it
                if (currentTarget == null && m_visitedTargets.Count < m_targets.Count)
                {
                    //Empty the stack as we sort of start a new progress
                    m_nodeStack = new Stack<Node>();

                    Target nonVisitedTarget = null;
                    for (int j = 0; j < m_targets.Count; j++)
                    {
                        if (!m_visitedTargets.Contains(m_targets[j]))
                        {
                            nonVisitedTarget = m_targets[j];
                            break;
                        }
                    }

                    //Find closest node to this non-visited target
                    if (nonVisitedTarget != null)
                    {
                        Node closest = GetClosestNodeToTarget(nonVisitedTarget);
                        if (closest != null)
                        {
                            m_currentNode = closest;
                            //Get closest target to this node
                            currentTarget = GetClosestNonVisitedTarget(m_currentNode, out toClosest, false);
                        }
                    }
                }

                /// If current target is still null, we are finished
                if (currentTarget == null)
                {
                    m_isFinished = true;
                    return;
                }
            }

            AdvanceUntilClosest(ref m_currentNode, currentTarget, toClosest);
        }
Пример #20
0
        /// <summary>
        /// Advances forward by segmentLength from current node
        /// </summary>
        /// <param name="_node"></param>
        /// <param name="_dir"></param>
        /// <returns>True if new node was made</returns>
        bool Advance(ref Node _node, Vector3 _dir)
        {
            bool retval = false;

            Vector3 newPos = _node.Position + _dir * m_segmentLength;

            if (newPos == _node.Position)
                return retval;

            bool addNew = false;

            if (_node.adjacents.Count > 0)
            {
                Node adj = Node.GetNode(nodes, _node.adjacents[0]);
                if (adj != null)
                {
                    Vector3 dirToPrevious = (adj.Position - _node.Position).normalized;
                    // If direction stays the same, just move current node
                    float dot = Vector3.Dot(_dir.normalized, dirToPrevious);

                    if (Mathf.Approximately(dot, -1f))
                    {
                        _node.Position = newPos;
                    }
                    else
                    {
                        // If resulting angle is too sharp, make a 90 degree turn
                        Vector3 referenceRight = Vector3.Cross(Vector3.up, dirToPrevious);
                        // Pick adjacent with which current direction creates the smallest angle
                        float angle = Mathf.Infinity;
                        for (int i = 0; i < _node.adjacents.Count; i++)
                        {
                            adj = Node.GetNode(nodes, _node.adjacents[0]);
                            Vector3 dirToCur = (adj.Position - _node.Position).normalized;
                            float toCur = Vector3.Angle(dirToCur, _dir);
                            if (toCur < angle)
                            {
                                angle = toCur;
                                dirToPrevious = dirToCur;
                            }
                        }
                        if (angle < m_minAngle)
                        {
                            //Check if current direction points left or right from previous and make a 90 degree turn to that direction
                            if (Vector3.Dot(referenceRight, _dir) > 0) // Right
                                _dir = Vector3.Cross(Vector3.up, dirToPrevious);
                            else
                                _dir = Vector3.Cross(dirToPrevious, Vector3.up);

                            newPos = _node.Position + _dir * m_segmentLength;
                        }

                        addNew = true;
                    }
                }
                else
                    addNew = true;
            }
            else
                addNew = true;

            if (addNew)
            {
                Node newNode = new Node(newPos);
                nodes.Add(newNode);

                newNode.adjacents.Add(_node.ID);
                _node.adjacents.Add(newNode.ID);

                edges.Add(new Edge(_node.ID, newNode.ID, m_edgeWidth));

                _node = newNode;

                retval = true;
            }

            return retval;
        }
Пример #21
0
 public Target(Vector3 pos)
 {
     position = pos;
     closestNode = null;
 }
Пример #22
0
        /// <summary>
        /// Extracts filament consisting of nodes and edges
        /// </summary>
        public static void ExtractFilament(Node _n0, Node _n1, ref List<Node> _nodes, ref List<Edge> _edges, ref List<Primitive> _primitives)
        {
            Edge e = EdgeGraphUtility.FindEdgeByNodes(_n0, _n1, _edges);
            if (e != null && e.isPartOfCycle)
            {
                if (_n0.adjacents.Count >= 3)
                {
                    EdgeGraphUtility.RemoveEdgeAndCleanAdjacents(_n0, _n1, ref _nodes, ref _edges);
                    _n0 = _n1;
                    if (_n0.adjacents.Count == 1) _n1 = EdgeGraphUtility.GetNode(_n0.adjacents[0], ref _nodes);
                }

                while (_n0.adjacents.Count == 1)
                {
                    _n1 = EdgeGraphUtility.GetNode(_n0.adjacents[0], ref _nodes);
                    Edge ee = EdgeGraphUtility.FindEdgeByNodes(_n0, _n1, _edges);
                    if (ee != null && e.isPartOfCycle)
                    {
                        EdgeGraphUtility.RemoveNodeAndCleanAdjacents(_n0, ref _nodes, ref _edges);
                        EdgeGraphUtility.RemoveEdgeAndCleanAdjacents(_n0, _n1, ref _nodes, ref _edges);
                    }
                    else
                        break;
                }

                if (_n0.adjacents.Count == 0)
                {
                    EdgeGraphUtility.RemoveNodeAndCleanAdjacents(_n0, ref _nodes, ref _edges);
                }
            }
            else
            {
                Primitive primitive = new Primitive(Primitive.PrimitiveType.Filament);

                if (_n0.adjacents.Count >= 3)
                {
                    primitive.nodes.Add(_n0);
                    primitive.edges.Add(e);
                    EdgeGraphUtility.RemoveEdgeAndCleanAdjacents(_n0, _n1, ref _nodes, ref _edges);
                    _n0 = _n1;
                    if (_n0.adjacents.Count == 1) _n1 = EdgeGraphUtility.GetNode(_n0.adjacents[0], ref _nodes);
                }

                while (_n0.adjacents.Count == 1)
                {
                    primitive.nodes.Add(_n0);
                    _n1 = EdgeGraphUtility.GetNode(_n0.adjacents[0], ref _nodes);
                    EdgeGraphUtility.RemoveNodeAndCleanAdjacents(_n0, ref _nodes, ref _edges);
                    Edge _e = EdgeGraphUtility.RemoveEdgeAndCleanAdjacents(_n0, _n1, ref _nodes, ref _edges);
                    if (_e != null) primitive.edges.Add(_e);
                    _n0 = _n1;
                }

                primitive.nodes.Add(_n0);
                if (_n0.adjacents.Count == 0)
                {
                    EdgeGraphUtility.RemoveNodeAndCleanAdjacents(_n0, ref _nodes, ref _edges);
                }

                _primitives.Add(primitive);
            }
        }
Пример #23
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);
            }
        }
Пример #24
0
        // Algorithms from http://www.geometrictools.com/Documentation/MinimalCycleBasis.pdf
        // The Minimal Cycle Basis for a Planar Graph by David Eberly

        /// <summary>
        /// Attempts to find minimal cycles
        /// </summary>
        public static void ExtractPrimitive(Node _n0, ref List<Node> _nodes, ref List<Edge> _edges, ref List<Primitive> _primitives)
        {
            List<Node> visited = new List<Node>();
            List<Node> sequence = new List<Node>();

            EdgeGraphUtility.CheckAdjacentNodes(ref _nodes, ref _edges);

            if (_n0.adjacents.Count == 0)
            {
                EdgeGraphUtility.RemoveNodeAndCleanAdjacents(_n0, ref _nodes, ref _edges);
                return;
            }

            sequence.Add(_n0);
            Node _n1 = GetClockwiseMostAdjacent(null, _n0, ref _nodes);
            Node prev = _n0;
            Node curr = _n1;

            while (curr != null && curr != _n0 && !visited.Contains(curr))
            {
                sequence.Add(curr);
                visited.Add(curr);
                Node next = GetCounterClockwiseMostAdjacent(prev, curr, ref _nodes);
                prev = curr;
                curr = next;
            }

            if (curr == null)
            {
                // Filament found, not necessarily rooted at prev
                ExtractFilament(prev, EdgeGraphUtility.GetNode(prev.adjacents[0], ref _nodes), ref _nodes, ref _edges, ref _primitives);
            }
            else if (curr == _n0)
            {
                // Minimal cycle found
                Primitive primitive = new Primitive(Primitive.PrimitiveType.MinimalCycle);
                primitive.nodes.AddRange(sequence);

                for (int i = 0; i < sequence.Count; i++)
                {
                    Node n1;
                    Node n2;
                    if (i == sequence.Count - 1)
                    {
                        n1 = sequence[i];
                        n2 = sequence[0];
                    }
                    else
                    {
                        n1 = sequence[i];
                        n2 = sequence[i + 1];
                    }
                    Edge e = EdgeGraphUtility.FindEdgeByNodes(n1, n2, _edges);
                    if (e != null)
                    {
                        primitive.edges.Add(e);
                        e.isPartOfCycle = true;
                    }
                }

                EdgeGraphUtility.RemoveEdgeAndCleanAdjacents(_n0, _n1, ref _nodes, ref _edges);

                if (_n0.adjacents.Count == 1)
                {
                    // Remove the filament rooted at v0
                    ExtractFilament(_n0, EdgeGraphUtility.GetNode(_n0.adjacents[0], ref _nodes), ref _nodes, ref _edges, ref _primitives);
                }

                if (_n1.adjacents.Count == 1)
                {
                    // Remove the filament rooted at v1
                    ExtractFilament(_n1, EdgeGraphUtility.GetNode(_n1.adjacents[0], ref _nodes), ref _nodes, ref _edges, ref _primitives);
                }

                _primitives.Add(primitive);
            }
            else   // curr was visited earlier
            {
                // A cycle has been found, but is not guaranteed to be a minimal cycle.
                // This implies v0 is part of a filament
                // Locate the starting point for the filament by traversing from v0 away from the initial v1

                while (_n0.adjacents.Count == 2)
                {
                    if (_n0.adjacents[0] != _n1.ID)
                    {
                        _n1 = _n0;
                        _n0 = EdgeGraphUtility.GetNode(_n0.adjacents[0], ref _nodes);
                    }
                    else
                    {
                        _n1 = _n0;
                        _n0 = EdgeGraphUtility.GetNode(_n0.adjacents[1], ref _nodes);
                    }
                }

                ExtractFilament(_n0, _n1, ref _nodes, ref _edges, ref _primitives);
            }
        }
Пример #25
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));
                    }
                }

            }
        }