예제 #1
0
    //public void GenHighway() {
    public IEnumerator GenHighwayCoroutine()
    {
        WorldManager.GenHighwayState = true;
        Dictionary <Vector2, float> densityLookup = new Dictionary <Vector2, float>();

        // cluster nearby points with DBScan
        List <Vector2> features = new List <Vector2>();// = new MyFeatureDataSource().GetFeatureData();

        for (int i = 0; i < patchDensityCenters.Count; i++)
        {
            (Vector2, float)cd = ((Vector2, float))patchDensityCenters[i];
            features.Add(cd.Item1);
            densityLookup[cd.Item1] = cd.Item2;
        }

        var result = RunOfflineDbscan(features);

        // Build highway graph
        var points = new List <Vertex>();

        foreach (int i in result.Clusters.Keys)
        {
            points.Add(new Vertex(result.Clusters[i][0].Feature.x, result.Clusters[i][0].Feature.y));
        }

        // Generate a default mesher
        var mesher = new GenericMesher(new Dwyer());

        // Generate mesh (Delaunay Triangulation)
        mesh = mesher.Triangulate(points);

        // Init edge/vertex lists for mutation
        foreach (Vertex v in mesh.Vertices)
        {
            vertices.Add(v);
        }
        foreach (Edge e in mesh.Edges)
        {
            edges.Add(e);

            // build neighbor map
            Vertex v0 = (Vertex)vertices[e.P0];
            Vertex v1 = (Vertex)vertices[e.P1];
            if (!neighbors.ContainsKey(v0))
            {
                neighbors[v0] = new List <Vertex>();
            }
            neighbors[v0].Add(v1);
        }

        // Remove unecessary edges on cost basis
        foreach (Edge e in mesh.Edges)
        {
            Vertex v0 = (Vertex)vertices[e.P0];
            Vertex v1 = (Vertex)vertices[e.P1];
            (Vector2, Vector2)tup1 = (Util.VertexToVector2(v0), Util.VertexToVector2(v1));
            (Vector2, Vector2)tup2 = (Util.VertexToVector2(v1), Util.VertexToVector2(v0));

            if (!InPatchBounds(regionIdx, tup1.Item1, tup1.Item2))
            {
                RemoveEdge(e);
                continue;
            }

            if (!WorldManager.edgeState.ContainsKey(tup1)) //needs removal check
            {
                if (ShouldRemoveEdge(e, densityLookup))
                {
                    // remove edge for first time
                    WorldManager.edgeState[tup1] = false;
                    WorldManager.edgeState[tup2] = false;
                    RemoveEdge(e);
                }
                else
                {
                    // keep edge, register with edgeState
                    WorldManager.edgeState[tup1] = true;
                    WorldManager.edgeState[tup2] = true;
                }
            }
            else // remove if removed before
            {
                if (!WorldManager.edgeState[tup1])
                {
                    RemoveEdge(e);
                }
            }
        }

        // Generate final highway segments for each edge
        // Uses A* search to pathfind
        int hwCount = 0;

        foreach (Edge e in edges)
        {
            hwCount++;
            (Vector2Int, Vector2Int)eVec = (Util.VertexToVector2Int((Vertex)vertices[e.P0]), Util.VertexToVector2Int((Vertex)vertices[e.P1]));
            Vertex v0 = (Vertex)vertices[e.P0];
            Vertex v1 = (Vertex)vertices[e.P1];

            // Skip pathfinding for edges that have been generated/built already
            if (WorldBuilder.builtHighways.ContainsKey((Util.VertexToVector2(v0), Util.VertexToVector2(v0))) &&
                WorldBuilder.builtHighways[(Util.VertexToVector2(v0), Util.VertexToVector2(v0))])
            {
                //Debug.Log("Aborting pathfind since already built!");
                continue;
            }

            // A* pathfind from v0 to v1
            ArrayList segments = pathfinding.FindPath(Util.VertexToVector2(v0), Util.VertexToVector2(v1));

            // Removal of redundant paths
            int firstIdx = -1, secondIdx = -1;
            List <(Vector2, (Vector2Int, Vector2Int))> vertListFirst = null, vertListSecond = null;
            // traverse from beginning
            for (int i = 0; i < segments.Count - 1; i++)
            {
                Vector2 v = (Vector2)segments[i];

                if (WorldBuilder.DoesChunkContainHighway(v))
                {
                    firstIdx      = i;
                    vertListFirst = WorldBuilder.GetHighwayVertList(v);
                    break;
                }
            }
            // traverse from end
            if (firstIdx >= 0)
            {
                for (int i = segments.Count - 1; i > 0; i--)
                {
                    Vector2 v = (Vector2)segments[i];
                    if (WorldBuilder.DoesChunkContainHighway(v))
                    {
                        secondIdx      = i;
                        vertListSecond = WorldBuilder.GetHighwayVertList(v);
                        break;
                    }
                }
            }

            // segment join logic
            if (vertListFirst != null && vertListSecond != null && firstIdx >= 0 && secondIdx >= 0)
            {
                // Direct connection with existing path
                bool done = false;
                // *--|____/*
                foreach ((Vector2, (Vector2Int, Vector2Int))tup in vertListFirst)
                {
                    if (eVec.Item2 == tup.Item2.Item2 || eVec.Item2 == tup.Item2.Item1)
                    {
                        segments.RemoveRange(firstIdx, segments.Count - firstIdx);
                        segments.Insert(firstIdx, tup.Item1);
                        done = true;
                        break;
                    }
                }
                if (!done)
                {
                    // *\____|--*
                    foreach ((Vector2, (Vector2Int, Vector2Int))tup in vertListSecond)
                    {
                        if (eVec.Item1 == tup.Item2.Item2 || eVec.Item1 == tup.Item2.Item1)
                        {
                            segments.RemoveRange(0, secondIdx);

                            segments.Insert(0, tup.Item1);
                            done = true;
                            break;
                        }
                    }
                }

                if (!done)
                {
                    // No direct connection cases (needs paths from start and end)
                    (bool, (Vector2Int, Vector2Int))sameEdgeRes = DoListsContainSameEdge(vertListFirst, vertListSecond);
                    if (sameEdgeRes.Item1)
                    {
                        Vector2 con1 = FindVecWithEdge(sameEdgeRes.Item2, vertListFirst), con2 = FindVecWithEdge(sameEdgeRes.Item2, vertListSecond);
                        if (con1 == con2) // same vert
                                          // *--|-----* pass through path
                        {
                            segments.RemoveAt(firstIdx);
                            segments.Insert(firstIdx, con1);
                        }
                        else // diff vert
                             // *--|__|--* join at existing path
                             //Debug.Log(firstIdx + " " + secondIdx);
                        {
                            segments.RemoveRange(firstIdx, secondIdx - firstIdx + 1);
                            segments.Insert(firstIdx, con2);
                            segments.Insert(firstIdx, WorldBuilder.SignalVector);
                            segments.Insert(firstIdx, con1);
                        }
                    }
                    else// not matched so edges different!
                    {
                        Vector2 con1 = vertListFirst[0].Item1, con2 = vertListSecond[0].Item1;
                        //neighbor or not
                        if (DoListsContainNeighbors(vertListFirst, vertListSecond))
                        {
                            // *--\./---*
                            segments.RemoveRange(firstIdx, secondIdx - firstIdx + 1);
                            segments.Insert(firstIdx, con2);
                            segments.Insert(firstIdx, WorldBuilder.SignalVector);
                            segments.Insert(firstIdx, con1);
                        }
                        else
                        {
                            // *--|--|--* pass through paths
                            segments.RemoveAt(secondIdx);
                            segments.RemoveAt(firstIdx);
                            segments.Insert(firstIdx, con1);
                            segments.Insert(secondIdx, con2);
                        }
                    }
                }
            }

            foreach (Vector2 v in segments)
            {
                WorldBuilder.AddHighwayVertToChunkHash(v, eVec);
            }

            if (segments != null)
            {
                highways.Add(segments);
            }

            if (hwCount % Settings.hwPathfindingIncrement == 0)
            {
                yield return(null);
            }
        }
        WorldManager.GenHighwayState = false;
    }