CheckAdjacentNodes() public static method

public static CheckAdjacentNodes ( List &_nodes, List &_edges ) : void
_nodes List
_edges List
return void
Ejemplo n.º 1
0
        public void ProcessMinimalCycles()
        {
            if (GraphID == -1)
            {
                GraphID = Guid.NewGuid().GetHashCode();
            }

            // Use different lists of nodes and edges for processing time, so the serialized lists won't change
            m_edges      = new List <Edge>();
            m_nodes      = new List <Node>();
            m_primitives = new List <Primitive>();

            UtilityTools.Helper.DestroyChildren(transform);

            EdgeGraphUtility.CopyNodesAndEdges(nodes, edges, out m_nodes, out m_edges);

            EdgeGraphUtility.CheckAdjacentNodes(ref m_nodes, ref m_edges);

            MinimalCycle.Extract(ref m_nodes, ref m_edges, ref m_primitives);

            // Serialize and process primitives
            mainPrimitives = m_primitives;

            try
            {
                ProcessPrimitives();
            }
            catch (Exception e)
            {
                Debug.LogWarning("Graph::ProcessMinimalCycles() - Error while processing primitives: " + e.Message);
            }
        }
Ejemplo n.º 2
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);
        }
Ejemplo n.º 3
0
        void ConnectEndPoints(List <Node> _nodes, List <Edge> _edges)
        {
            // Find endpoints
            List <Node> endNodes = new List <Node>();

            for (int i = 1; i < _nodes.Count; i++)
            {
                if (_nodes[i].adjacents.Count == 1)
                {
                    endNodes.Add(_nodes[i]);
                }
            }

            // Connect endpoints to edges or other nodes
            for (int i = 0; i < endNodes.Count; i++)
            {
                // End node direction
                Node    adjacent = Node.GetNode(_nodes, endNodes[i].adjacents[0]);
                Vector3 nodeDir  = (endNodes[i].Position - adjacent.Position).normalized;

                //Check if there is any nodes in the rough direction of the end node
                float       roughAngle = 30f;
                List <Node> nodesInDir = new List <Node>();

                for (int j = 0; j < _nodes.Count; j++)
                {
                    if (_nodes[j] == endNodes[i])
                    {
                        continue;
                    }

                    Vector3 dirToNode = (_nodes[j].Position - endNodes[i].Position).normalized;
                    if (Vector3.Angle(nodeDir, dirToNode) < roughAngle && Vector3.Angle(nodeDir, dirToNode) > 30f)
                    {
                        nodesInDir.Add(_nodes[j]);
                    }
                }

                // The node with which this endpoint is connected to
                Node connectTo = null;

                // If there are some nodes in the rough direction, pick the one that is closest
                if (nodesInDir.Count > 0)
                {
                    float toClosest = Mathf.Infinity;
                    Node  closest   = null;
                    for (int j = 0; j < nodesInDir.Count; j++)
                    {
                        float toCurrent = Vector3.Distance(endNodes[i].Position, nodesInDir[j].Position);
                        if (toCurrent < toClosest)
                        {
                            toClosest = toCurrent;
                            closest   = nodesInDir[j];
                        }
                    }

                    if (toClosest < subEdgeEndConnectionRange)
                    {
                        connectTo = closest;
                    }
                }
                // Else get intersection with closest edge in the direction of this endpoint
                if (connectTo == null)
                {
                    // Ending point for tested segment in the direction of this endpoint
                    Vector3 segmentEnd = endNodes[i].Position + nodeDir * 1000f;

                    // Get the intersection
                    Vector3 intersectPoint = Vector3.zero;
                    // Convert all used points to XZ space
                    Vector3 intersectPointXZ = Vector2.zero;
                    Vector2 endPointXZ       = new Vector2(endNodes[i].Position.x, endNodes[i].Position.z);
                    Vector2 segmentEndXZ     = new Vector2(segmentEnd.x, segmentEnd.z);

                    List <Edge>    intersectedEdges = new List <Edge>();
                    List <Vector3> intersectPoints  = new List <Vector3>();

                    // Ignore the edge that starts on this endpoint
                    Edge endEdge = _edges.Find(e => (e.Node1 == endNodes[i].ID || e.Node2 == endNodes[i].ID));

                    for (int j = 0; j < _edges.Count; j++)
                    {
                        if (_edges[j] == endEdge)
                        {
                            continue;
                        }

                        Node n1 = Node.GetNode(_nodes, _edges[j].Node1);
                        Node n2 = Node.GetNode(_nodes, _edges[j].Node2);

                        Vector2 node1XZ = new Vector2(n1.Position.x, n1.Position.z);
                        Vector2 node2XZ = new Vector2(n2.Position.x, n2.Position.z);

                        if (UtilityTools.MathHelper.AreIntersecting(out intersectPointXZ, endPointXZ, segmentEndXZ, node1XZ, node2XZ) == 1)
                        {
                            intersectPoints.Add(new Vector3(intersectPointXZ.x, n1.Position.y, intersectPointXZ.y));
                            intersectedEdges.Add(_edges[j]);
                        }
                    }

                    // Get closest intersect point
                    float toClosest = Mathf.Infinity;
                    Edge  closestIntersectedEdge = null;
                    for (int j = 0; j < intersectPoints.Count; j++)
                    {
                        float toPoint = Vector3.Distance(endNodes[i].Position, intersectPoints[j]);
                        if (toPoint < toClosest)
                        {
                            toClosest              = toPoint;
                            intersectPoint         = intersectPoints[j];
                            closestIntersectedEdge = intersectedEdges[j];
                        }
                    }

                    // Split the intersected edge on the intersection
                    if (closestIntersectedEdge == null || intersectPoint == Vector3.zero)
                    {
                        Debug.Log("Primitive::ConnectEndPoints() - Intersect point not found.");
                        continue;
                    }
                    else
                    {
                        connectTo = Edge.SplitEdge(closestIntersectedEdge, intersectPoint, _nodes, _edges);
                    }
                }

                _edges.Add(new Edge(endNodes[i].ID, connectTo.ID, subEdgeWidth));
            }

            // Refresh adjacent nodes after all the endpoint connections
            EdgeGraphUtility.CheckAdjacentNodes(ref _nodes, ref _edges);
        }
Ejemplo n.º 4
0
        void GenerateSubEdges()
        {
            // Save hard copies of this primitive's original nodes and edges
            List <Node> nodeCopies = new List <Node>();
            List <Edge> edgeCopies = new List <Edge>();

            EdgeGraphUtility.CopyNodesAndEdges(nodes, edges, out nodeCopies, out edgeCopies, false, false);

            if (subEdgeSegmentLength <= 0f || subEdgeTargets == null || subEdgeTargets.Count <= 0)
            {
                return;
            }

            if (subEdgeRootIndex >= nodeCopies.Count)
            {
                subEdgeRootIndex = nodeCopies.Count - 1;
            }

            Node rootNode = nodeCopies[subEdgeRootIndex];

            //EdgeBuilder builder = null;

            if (subEdgeSegmentLength == 0f)
            {
                subEdgeSegmentLength = .5f;
            }

            List <Node> _builtSubNodes = new List <Node>();
            List <Edge> _builtSubEdges = new List <Edge>();

            new EdgeBuilder(rootNode, subEdgeTargets, subEdgeWidth, subEdgeSegmentLength, subEdgeMinAngle, subEdgeMinDistance, subEdgeMaxDistance, (_nodes, _edges) =>
            {
                if (_nodes == null || _nodes.Count <= 0)
                {
                    Debug.Log("Primitive::GenerateSubEdges() - Builder nodes null / empty.");
                    return;
                }

                _builtSubNodes = _nodes;

                if (_edges == null || _edges.Count <= 0)
                {
                    Debug.Log("Primitive::GenerateSubEdges() - Builder edges null / empty.");
                    return;
                }
                _builtSubEdges = _edges;

                CombineSubNodes(rootNode, _builtSubNodes, _builtSubEdges, subEdgeNodeCombineRange);
            });

            nodeCopies.AddRange(_builtSubNodes);
            edgeCopies.AddRange(_builtSubEdges);

            ConnectEndPoints(nodeCopies, edgeCopies);
            CombineSubNodes(rootNode, nodeCopies, edgeCopies, subEdgeNodeCombineRange, false);

            List <Node> _copiedSubNodes = new List <Node>();
            List <Edge> _copiedSubEdges = new List <Edge>();

            EdgeGraphUtility.CopyNodesAndEdges(nodeCopies, edgeCopies, out _copiedSubNodes, out _copiedSubEdges);

            EdgeGraphUtility.CheckAdjacentNodes(ref nodeCopies, ref edgeCopies);

            EdgeGraphUtility.CleanUpEdges(ref nodeCopies, ref edgeCopies);

            subNodes = nodeCopies;
            subEdges = edgeCopies;
        }
Ejemplo n.º 5
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);
        }
Ejemplo n.º 6
0
        void ProcessSubPrimitives(Primitive p)
        {
            if (p.subEdges == null || p.subEdges.Count <= 0)
            {
                return;
            }

            // Copy local lists from primitive's sub nodes and edges
            List <Node> _nodes = new List <Node>();
            List <Edge> _edges = new List <Edge>();

            EdgeGraphUtility.CopyNodesAndEdges(p.subNodes, p.subEdges, out _nodes, out _edges);

            EdgeGraphUtility.CheckAdjacentNodes(ref _nodes, ref _edges);

            //subPrimitives = new List<Primitive>();
            List <Primitive> _subPrimitives = new List <Primitive>();

            // Extract primitives inside main primitives
            try
            {
                MinimalCycle.Extract(ref _nodes, ref _edges, ref _subPrimitives);
            }
            catch (Exception e)
            {
                Debug.LogWarning("Graph::GeneratePrimitiveSubPrimitives() - Error while extracting primitives: " + e.Message);
                return;
            }

            _subPrimitives.ForEach((sp) =>
            {
                sp.Process();
            });

            for (int i = _subPrimitives.Count - 1; i >= 0; i--)
            {
                if (!_subPrimitives[i].EvaluationResult)
                {
                    _subPrimitives.RemoveAt(i);
                }
            }

            _subPrimitives.ForEach((sp) =>
            {
                sp.parent = p.ID;

                GameObject subGraphObj = new GameObject("SubGraph");
                subGraphObj.transform.SetParent(transform);
                subGraphObj.transform.localPosition = Vector3.zero;
                subGraphObj.transform.localScale    = Vector3.one;

                Graph subGraph    = subGraphObj.AddComponent <Graph>();
                subGraph.GraphID  = Guid.NewGuid().GetHashCode();
                subGraphObj.name += subGraph.GraphID;

                subGraph.nodes = new List <Node>();
                foreach (var node in sp.nodes)
                {
                    subGraph.nodes.Add(node);
                }
                subGraph.edges = new List <Edge>();
                foreach (var edge in sp.edges)
                {
                    edge.Width = 0f;
                    subGraph.edges.Add(edge);
                }

                subGraph.ProcessMinimalCycles();

                subGraph.mainPrimitives[0].parent = p.ID;

                subGraphs.Add(subGraph);

                //subPrimitives.Add(subGraph.mainPrimitives[0]);

                FacadeBuilder builder = GetComponent <FacadeBuilder>();
                if (builder != null)
                {
                    FacadeBuilder subBuilder       = subGraph.gameObject.AddComponent <FacadeBuilder>();
                    subBuilder.inSet               = builder.inSet;
                    subBuilder.facadeStretchPrefab = builder.facadeStretchPrefab;
                    subBuilder.facadePrefabs       = builder.facadePrefabs;
                    subBuilder.roofMiddleMaterial  = builder.roofMiddleMaterial;
                    subBuilder.roofSideMaterial    = builder.roofSideMaterial;
                    subBuilder.roofHeight          = builder.roofHeight;
                    subBuilder.roofMiddleAddHeight = builder.roofMiddleAddHeight;
                    subBuilder.roofAccentWidth     = builder.roofAccentWidth;
                }

                FootprintPlacer placer = GetComponent <FootprintPlacer>();
                if (placer != null)
                {
                    FootprintPlacer _placer        = subGraph.gameObject.AddComponent <FootprintPlacer>();
                    _placer.footprintPrefabsOnEdge = placer.footprintPrefabsOnEdge;
                    _placer.footprintPrefabsInside = placer.footprintPrefabsInside;
                    _placer.UpdateData();
                }
            });
        }
Ejemplo n.º 7
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);
            }
        }