Exemple #1
0
    // Get area data graph that contains the given area segments, with the respective center and polygon, and neighborhood information
    public Graph <AreaData> GetAreaDataGraph(IEnumerable <int> areaSegments)
    {
        if (!AreNeighbours(areaSegments))
        {
            return(null);
        }

        // Build polygons and gather roads for each site
        Dictionary <int, Vector2[]>         areaSegmentPolygonMap = new Dictionary <int, Vector2[]>();
        Dictionary <int, List <Vector2[]> > areaSegmentRoadMap    = new Dictionary <int, List <Vector2[]> >();

        foreach (int areaSegment in areaSegments)
        {
            var site = new Vector2f(_areaSegmentCenterMap[areaSegment]);
            areaSegmentPolygonMap.Add(areaSegment, GetSitePolygon(site));
            areaSegmentRoadMap.Add(areaSegment, GetSitePaths(site));
        }

        // Build graph
        Dictionary <int, int> graphMap      = new Dictionary <int, int>();
        Graph <AreaData>      areaDataGraph = new Graph <AreaData>();

        foreach (int areaSegment in areaSegments)
        {
            AreaData data = new AreaData
            {
                Center  = _areaSegmentCenterMap[areaSegment],
                Polygon = areaSegmentPolygonMap[areaSegment],
                Segment = AreaSegmentGraph.GetNodeData(areaSegment),
                Paths   = areaSegmentRoadMap[areaSegment]
            };
            int newID = areaDataGraph.AddNode(data);
            graphMap.Add(areaSegment, newID);
        }
        foreach (int areaSegment in areaSegments)
        {
            foreach (int neighbour in AreaSegmentGraph.GetNeighbours(areaSegment))
            {
                if (areaSegments.Contains(neighbour))
                {
                    areaDataGraph.AddEdge(graphMap[areaSegment], graphMap[neighbour], 0);
                }
            }
        }

        return(areaDataGraph);
    }
Exemple #2
0
 // Get closest AreaSegment to specified pos
 private AreaSegment GetClosestAreaSegment(Vector2 pos)
 {
     return(AreaSegmentGraph.GetNodeData(GetClosestAreaSegmentID(pos)));
 }
Exemple #3
0
    // Create border blocker polygon
    private void CreateBorderBlockerLines(float borderInlandOffset)
    {
        var segments = new List <KeyValuePair <Edge, Vector2> >();

        foreach (var edge in VoronoiDiagram.Edges)
        {
            //Check if this edge is visible before continuing
            if (!edge.Visible())
            {
                continue;
            }

            int         leftAreaSegmentID  = _siteAreaSegmentMap[edge.RightSite.Coord];
            int         rightAreaSegmentID = _siteAreaSegmentMap[edge.LeftSite.Coord];
            AreaSegment leftAreaSegment    = AreaSegmentGraph.GetNodeData(leftAreaSegmentID);
            AreaSegment rightAreaSegment   = AreaSegmentGraph.GetNodeData(rightAreaSegmentID);

            // Either one or the other must be a border type
            if (leftAreaSegment.Type != rightAreaSegment.Type &&
                (leftAreaSegment.Type == AreaSegment.EAreaSegmentType.Border || rightAreaSegment.Type == AreaSegment.EAreaSegmentType.Border))
            {
                // Add border edge with the biome center to scale inwards later
                segments.Add(new KeyValuePair <Edge, Vector2>(edge,
                                                              leftAreaSegment.Type == AreaSegment.EAreaSegmentType.Border ? edge.LeftSite.Coord.ToUnityVector2() : edge.RightSite.Coord.ToUnityVector2()));
            }
        }

        // Group connected segments
        var edgeGroups = new List <List <KeyValuePair <Edge, Vector2> > >();

        while (segments.Count > 0)
        {
            var edges     = new List <KeyValuePair <Edge, Vector2> >();
            var startEdge = segments[0];
            segments.Remove(startEdge);
            Vertex headPoint = startEdge.Key.RightVertex;
            Vertex tailPoint = startEdge.Key.LeftVertex;
            edges.Add(startEdge);

            // Find a polygon
            var polygonClosed = false;
            while (!polygonClosed && segments.Count > 0)
            {
                for (int i = 0; i < segments.Count; i++)
                {
                    var    currentElement = segments[i];
                    Vertex leftPoint      = currentElement.Key.LeftVertex;
                    Vertex rightPoint     = currentElement.Key.RightVertex;
                    if (leftPoint == headPoint)
                    {
                        edges.Add(currentElement);
                        segments.Remove(currentElement);
                        headPoint = rightPoint;
                    }
                    else if (rightPoint == headPoint)
                    {
                        edges.Add(currentElement);
                        segments.Remove(currentElement);
                        headPoint = leftPoint;
                    }

                    // Polygon has been closed
                    if (headPoint == tailPoint)
                    {
                        polygonClosed = true;
                        break;
                    }
                }
            }
            edgeGroups.Add(edges);
        }

        // Iterate over each polygon found previously
        foreach (var edges in edgeGroups)
        {
            var polygon     = new List <Vector2>();
            var borderLines = edges.Select(pair => pair.Key).ToList().EdgesToSortedLines();
            foreach (var line in borderLines)
            {
                // Offset borders towards biome center
                var left   = line[0];
                var right  = line[1];
                var center = Vector2.zero;
                edges.ForEach(e =>
                {
                    var l = e.Key.ClippedEnds[LR.LEFT].ToUnityVector2();
                    var r = e.Key.ClippedEnds[LR.RIGHT].ToUnityVector2();
                    if ((l == left || l == right) && (r == left || r == right))
                    {
                        center = e.Value;
                    }
                });

                left  += (center - left).normalized * borderInlandOffset;
                right += (center - right).normalized * borderInlandOffset;

                // Offsetting can give duplicated points
                if (!polygon.Contains(left))
                {
                    polygon.Add(left);
                }
                if (!polygon.Contains(right))
                {
                    polygon.Add(right);
                }
            }

            // Create border blocker lines
            BorderBlockerLines.AddRange(polygon.ToArray().PolygonToLines());
        }
    }
Exemple #4
0
    // Create a graph containing all connected empty areas
    private void CreateBaseGraph(int lloydIterations)
    {
        // Create uniform random point distribution and Voronoi Diagram
        var centers = new List <Vector2f>();

        for (int i = 0; i < _voronoiSamples; i++)
        {
            var x = Random.Range(0f, MapSize);
            var y = Random.Range(0f, MapSize);
            centers.Add(new Vector2f(x, y));
        }
        VoronoiDiagram = new Voronoi(centers, new Rectf(0, 0, MapSize, MapSize));

        // Apply Lloyd Relaxation
        VoronoiDiagram.LloydRelaxation(lloydIterations);

        // Assign area segments to initial areas
        foreach (var site in VoronoiDiagram.SiteCoords())
        {
            bool isOnBorder = false;
            var  segments   = VoronoiDiagram.VoronoiBoundaryForSite(site);

            foreach (var segment in segments)
            {
                if (!(segment.p0.x <= VoronoiDiagram.PlotBounds.left) &&
                    !(segment.p0.x >= VoronoiDiagram.PlotBounds.right) &&
                    !(segment.p0.y <= VoronoiDiagram.PlotBounds.top) &&
                    !(segment.p0.y >= VoronoiDiagram.PlotBounds.bottom) &&
                    !(segment.p1.x <= VoronoiDiagram.PlotBounds.left) &&
                    !(segment.p1.x >= VoronoiDiagram.PlotBounds.right) &&
                    !(segment.p1.y <= VoronoiDiagram.PlotBounds.top) &&
                    !(segment.p1.y >= VoronoiDiagram.PlotBounds.bottom))
                {
                    continue;
                }

                isOnBorder = true;
                break;
            }

            // Assign areaSegment to site and corresponding area
            var areaSegment = new AreaSegment(isOnBorder ? AreaSegment.EAreaSegmentType.Border : AreaSegment.EAreaSegmentType.Empty);

            var nodeID = AreaSegmentGraph.AddNode(areaSegment);
            _siteAreaSegmentMap.Add(site, nodeID);
            _areaSegmentCenterMap.Add(nodeID, site.ToUnityVector2());
        }

        // Create navigation graph - for each area segment that is not a border, add reachable neighbors
        foreach (var id in _siteAreaSegmentMap)
        {
            var areaSegment = AreaSegmentGraph.GetNodeData(id.Value);
            if (areaSegment.Type == AreaSegment.EAreaSegmentType.Border)
            {
                continue;
            }

            Vector2 center = _areaSegmentCenterMap[id.Value];
            foreach (var neighbor in VoronoiDiagram.NeighborSitesForSite(new Vector2f(center.x, center.y)))
            {
                var neighborSegment = AreaSegmentGraph.GetNodeData(_siteAreaSegmentMap[neighbor]);
                if (neighborSegment.Type != AreaSegment.EAreaSegmentType.Border)
                {
                    AreaSegmentGraph.AddEdge(_siteAreaSegmentMap[neighbor], id.Value, (int)AreaSegment.EAreaSegmentEdgeType.NonNavigable);
                }
            }
        }
    }