Esempio n. 1
0
        public GraphLinked AsGraph()
        {
            GraphLinked graph = new GraphLinked();

            graph.Contour  = this;
            graph.links    = new List <GraphLinked.Link>();
            graph.segments = new List <List <GraphLinked.Link> >();

            /*for (int i = 0; i < contour.Count; ++i)
             * {
             *    graph.AddNode(contour[i], true);
             * }*/

            for (int i = 0; i < contour.Count; ++i)
            {
                GraphLinked.Link link = new GraphLinked.Link(contour[i], contour[(i + 1) % contour.Count], true);
                graph.links.Add(link);
                graph.segments.Add(new List <GraphLinked.Link>());
                graph.segments[i].Add(link);
            }
            return(graph);
        }
Esempio n. 2
0
    void Subdivide(int subdivision = 5)
    {
        blockContours = new List <GraphLinked.Cell>();
        if (subdivision == 1)
        {
            foreach (GraphLinked.Cell cell in regions)
            {
                blockContours.Add(cell);
            }
        }
        else
        {
            blocks = new List <GraphLinked>();
            foreach (GraphLinked.Cell region in regions)
            {
                GraphLinked regionGraph = region.AsGraph();
                blocks.Add(regionGraph);
                Bounds  bounds = region.Bounds;
                Vector3 delta  = bounds.size / subdivision;
                bool[,] valid             = new bool[subdivision + 1, subdivision + 1];
                GraphLinked.Node[,] nodes = new GraphLinked.Node[subdivision + 1, subdivision + 1];
                for (int x = 0; x <= subdivision; ++x)
                {
                    float u = x / (float)subdivision * bounds.size.x + bounds.min.x;
                    for (int z = 0; z <= subdivision; ++z)
                    {
                        float   v     = z / (float)subdivision * bounds.size.z + bounds.min.z;
                        Vector3 point = new Vector3(u, 0, v);
                        if (region.ContainsPoint(point))
                        {
                            valid[x, z] = true;
                            nodes[x, z] = regionGraph.AddNode(point);
                        }
                    }
                }

                // create internal nodes and links, divide shell edges when intersecting them
                for (int x = 0; x <= subdivision; ++x)
                {
                    float u = x / (float)subdivision * bounds.size.x + bounds.min.x;
                    for (int z = 0; z <= subdivision; ++z)
                    {
                        float v = z / (float)subdivision * bounds.size.z + bounds.min.z;
                        if (valid[x, z])
                        {
                            Vector3          fromPosition = new Vector3(u, 0, v);
                            GraphLinked.Node from         = nodes[x, z];
                            // RIGHT
                            int x2 = x + 1;
                            if (x2 > subdivision || !valid[x2, z])
                            {
                                float   u2             = x2 / (float)subdivision * bounds.size.x + bounds.min.x;
                                Vector3 targetPosition = new Vector3(u2, 0, v);
                                regionGraph.SegmentShell(from, targetPosition);
                            }
                            else
                            {
                                regionGraph.AddLink(nodes[x, z], nodes[x2, z]);
                                city.AddLink(city.AddNode(nodes[x, z].position), city.AddNode(nodes[x2, z].position));
                            }
                            // LEFT
                            x2 = x - 1;
                            if (x2 < 0 || !valid[x2, z])
                            {
                                float   u2             = x2 / (float)subdivision * bounds.size.x + bounds.min.x;
                                Vector3 targetPosition = new Vector3(u2, 0, v);
                                regionGraph.SegmentShell(from, targetPosition);
                            }
                            // no else: intersections with the edge are done only done right-wards

                            // UP
                            int z2 = z + 1;
                            if (z2 > subdivision || !valid[x, z2])
                            {
                                float   v2             = z2 / (float)subdivision * bounds.size.z + bounds.min.z;
                                Vector3 targetPosition = new Vector3(u, 0, v2);
                                regionGraph.SegmentShell(from, targetPosition);
                            }
                            else
                            {
                                regionGraph.AddLink(nodes[x, z], nodes[x, z2]);
                                city.AddLink(city.AddNode(nodes[x, z].position), city.AddNode(nodes[x, z2].position));
                            }

                            //DOWN
                            z2 = z - 1;
                            if (z2 < 0 || !valid[x, z2])
                            {
                                float   v2             = z2 / (float)subdivision * bounds.size.z + bounds.min.z;
                                Vector3 targetPosition = new Vector3(u, 0, v2);
                                regionGraph.SegmentShell(from, targetPosition);
                            }
                            // no else: intersections with the edge are done only done up-wards
                        }
                    }
                }
                for (int x = 0; x <= subdivision - 1; ++x)
                {
                    for (int z = 0; z <= subdivision - 1; ++z)
                    {
                        if (valid[x, z] && valid[x + 1, z] && valid[x, z + 1] && valid[x + 1, z + 1])
                        {
                            List <GraphLinked.Node> contour = new List <GraphLinked.Node>();
                            contour.Add(nodes[x, z]);
                            contour.Add(nodes[x + 1, z]);
                            contour.Add(nodes[x + 1, z + 1]);
                            contour.Add(nodes[x, z + 1]);
                            GraphLinked.Cell subcell = new GraphLinked.Cell(contour);
                            subcell.Parent = region;
                            blockContours.Add(subcell);
                        }
                    }
                }

                List <GraphLinked.Link> unused = new List <GraphLinked.Link>();
                foreach (var link in regionGraph.segments)
                {
                    unused.AddRange(link);
                }
                // get the cells at the edges
                regionGraph.ComputeNeighbours();
                while (unused.Count > 0)
                {
                    List <GraphLinked.Link> contour = new List <GraphLinked.Link>();
                    GraphLinked.Link        link    = unused[0];

                    unused.RemoveAt(0);
                    if (link == null)
                    {
                        continue;
                    }
                    contour.Add(link);

                    Queue <List <GraphLinked.Node> > queueNodes = new Queue <List <GraphLinked.Node> >();
                    Queue <List <GraphLinked.Link> > queueLinks = new Queue <List <GraphLinked.Link> >();
                    HashSet <GraphLinked.Node>       used       = new HashSet <GraphLinked.Node>();
                    var startNodes = new List <GraphLinked.Node>();
                    used.Add(link.from);
                    startNodes.Add(link.from);
                    startNodes.Add(link.to);
                    queueNodes.Enqueue(startNodes);
                    List <GraphLinked.Link> startLink = new List <GraphLinked.Link>();
                    startLink.Add(link);
                    queueLinks.Enqueue(startLink);
                    int count = 0;
                    List <GraphLinked.Node> solutionPath  = null;
                    List <GraphLinked.Link> solutionLinks = null;

                    var neighbours = regionGraph.ComputeNeighbours();
                    while (queueNodes.Count > 0 && count < 100 && solutionPath == null)
                    {
                        List <GraphLinked.Node> currentSolution      = queueNodes.Dequeue();
                        List <GraphLinked.Link> currentSolutionLinks = queueLinks.Dequeue();
                        GraphLinked.Node        current = currentSolution[currentSolution.Count - 1];

                        used.Add(current);
                        foreach (var nextLink in neighbours[current])
                        {
                            //flips the edge if needed
                            GraphLinked.Node next = current == nextLink.from ? nextLink.to : nextLink.from;

                            // is it a solution?
                            if (currentSolution.Count > 2 && next == link.from)
                            {
                                solutionPath  = currentSolution;
                                solutionLinks = currentSolutionLinks;
                            }
                            //no solution, but it can be navigated
                            else if (!used.Contains(next))
                            {
                                // single option, no need to create new solution
                                if (neighbours[current].Count == 1)
                                {
                                    currentSolution.Add(next);
                                    queueNodes.Enqueue(currentSolution);

                                    currentSolutionLinks.Add(nextLink);
                                    queueLinks.Enqueue(currentSolutionLinks);
                                }
                                // more than one edge, create a new solution for each
                                else if (neighbours[current].Count > 1)
                                {
                                    var newSolution = new List <GraphLinked.Node>(currentSolution);
                                    newSolution.Add(next);
                                    queueNodes.Enqueue(newSolution);

                                    var newSolutionLinks = new List <GraphLinked.Link>(currentSolutionLinks);
                                    newSolutionLinks.Add(nextLink);
                                    queueLinks.Enqueue(newSolutionLinks);
                                }
                            }
                            ++count;
                        }
                    }
                    {
                        if (solutionPath != null)
                        {
                            List <GraphLinked.Node> contourCell = new List <GraphLinked.Node>();
                            foreach (var entry in solutionPath)
                            {
                                if (contourCell.Count == 0 || Vector3.SqrMagnitude(entry.position - contourCell[contourCell.Count - 1].position) > float.Epsilon)
                                {
                                    contourCell.Add(entry);
                                }
                            }
                            if (contourCell.Count > 2)
                            {
                                GraphLinked.Cell building = new GraphLinked.Cell(contourCell);
                                if (building.Area > 0)
                                {
                                    foreach (var usedLink in solutionLinks)
                                    {
                                        if (unused.Contains(usedLink))
                                        {
                                            unused.Remove(usedLink);
                                        }
                                    }
                                    building.Parent = region;
                                    blockContours.Add(building);
                                }
                            }
                            else
                            {
                                string p = "";
                                foreach (var element in contourCell)
                                {
                                    p += element.ToString() + " ";
                                }
                                Debug.LogWarning("path:" + p);
                            }
                        }
                        else
                        {
                            Debug.Log("STATUS:" + (solutionPath != null ? solutionPath.Count.ToString() : "null") + ", in " + count + " steps");
                        }
                    }
                }
            }
        }

        /*foreach (Cell building in buildingContours)
         * {
         *  building.Deflate(0.1f);
         * }*/
    }