예제 #1
0
    /// <summary>
    /// Returns the middle point and angle of a border to an adjacent region. The angle always points to the direction of this region.
    /// </summary>
    public Tuple <Vector2, float> GetBorderCenterPositionTo(Region otherRegion)
    {
        if (!AdjacentRegions.Contains(otherRegion))
        {
            throw new Exception("Other region is not adjacent to this region");
        }

        // Find all borders between the two regions
        List <Border> borders = Borders.Where(x => x.Regions.Contains(otherRegion)).ToList();

        // Split borders into clusters and take longest cluster
        List <List <Border> > clusters       = PolygonMapFunctions.FindBorderClusters(borders);
        List <Border>         longestCluster = clusters.OrderByDescending(x => x.Sum(y => y.Length)).First();

        // Find center of longest cluster
        Tuple <Vector2, float> center = PolygonMapFunctions.FindBorderCenter(longestCluster);

        // Swap angle if the border was reversed
        Vector2 testPoint = center.Item1 + new Vector2(Mathf.Sin(Mathf.Deg2Rad * center.Item2) * 0.01f, Mathf.Cos(Mathf.Deg2Rad * center.Item2) * 0.01f);

        if (!GeometryFunctions.IsPointInPolygon4(Polygon.Nodes.Select(x => x.Vertex).ToList(), testPoint))
        {
            center = new Tuple <Vector2, float>(center.Item1, center.Item2 + 180);
        }

        return(center);
    }
예제 #2
0
 public void Label()
 {
     foreach (List <Region> cluster in Clusters)
     {
         List <List <GraphNode> > clusterBorders = PolygonMapFunctions.FindOutsideNodes(cluster.Select(x => x.Polygon).ToList());
         GameObject clusterLabel = CenterlineLabler.LabelPolygon(clusterBorders, Name, SecondaryColor);
         RegionLabels.Add(clusterLabel);
     }
 }
예제 #3
0
    public void Init(List <Region> regions)
    {
        Name    = "Continent XYZ";
        Regions = regions;
        Size    = regions.Count;
        Area    = regions.Sum(x => x.Area);

        List <List <Region> > clusters = PolygonMapFunctions.FindClusters(regions);

        foreach (List <Region> cluster in clusters)
        {
            List <GameObject> clusterBorders = MeshGenerator.CreatePolygonGroupBorder(cluster.Select(x => x.Polygon).ToList(), PolygonMapGenerator.DefaulContinentBorderWidth, Color.black, onOutside: false, yPos: PolygonMapGenerator.LAYER_CONTINENT);
            foreach (GameObject clusterBorder in clusterBorders)
            {
                Borders.Add(clusterBorder);
            }
        }
        foreach (GameObject border in Borders)
        {
            border.transform.SetParent(transform);
        }
    }
예제 #4
0
    public void UpdateProperties()
    {
        DestroyAllObjects();
        if (Regions.Count == 0)
        {
            return;
        }

        // Border
        Area     = Regions.Sum(x => x.Area);
        Clusters = PolygonMapFunctions.FindClusters(Regions);
        foreach (List <Region> cluster in Clusters)
        {
            List <GameObject> clusterBorders = MeshGenerator.CreatePolygonGroupBorder(cluster.Select(x => x.Polygon).ToList(), PolygonMapGenerator.DefaultShorelineBorderWidth, SecondaryColor, onOutside: false, yPos: 0.0002f);
            foreach (GameObject clusterBorder in clusterBorders)
            {
                Borders.Add(clusterBorder);
            }
        }

        // Label
        Label();
    }
예제 #5
0
    /// <summary>
    /// Creates a GameObject with a mesh that represents the bounds of multiple polygons. onOutside means the border will be drawn on the outside of the polygons.
    /// All given polygons must be connected by land for this function to work! If they are not, first split it into clusters with PolygonMapFunctions.FindClusters()
    /// </summary>
    public static List <GameObject> CreatePolygonGroupBorder(List <GraphPolygon> polygons, float width, Color c, bool onOutside, float yPos)
    {
        List <GameObject> borders = new List <GameObject>();

        // Find outer mesh vertices
        List <List <GraphNode> > outerNodes    = PolygonMapFunctions.FindOutsideNodes(polygons);
        List <GraphNode>         outsideBorder = outerNodes.First(x => x.Count == outerNodes.Max(y => y.Count));

        foreach (List <GraphNode> border in outerNodes)
        {
            List <Vector2> outerVertices = border.Select(x => x.Vertex).ToList();
            bool           isClockwise   = GeometryFunctions.IsClockwise(outerVertices);
            if (border == outsideBorder)
            {
                borders.Add(CreateSinglePolygonBorder(border, width, c, yPos, onOutside ? !isClockwise : isClockwise));
            }
            else
            {
                borders.Add(CreateSinglePolygonBorder(border, width, c, yPos, onOutside ? isClockwise : !isClockwise));
            }
        }

        return(borders);
    }
예제 #6
0
        public static void CreateContinents(PolygonMapGenerator PMG)
        {
            PMG.Continents = new List<List<GraphPolygon>>();

            // 1. Create one continent per landmass
            foreach (List<GraphPolygon> landmass in PMG.Landmasses)
            {
                List<GraphPolygon> continentPolygons = new List<GraphPolygon>();
                continentPolygons.AddRange(landmass);
                foreach (GraphPolygon landmassPoly in landmass) landmassPoly.Continent = continentPolygons;
                PMG.Continents.Add(continentPolygons);
            }

            // 2. Split big landmasses into mutliple continents
            List<GraphPolygon> biggestContinent = PMG.Continents.OrderByDescending(x => x.Count).First();
            while(biggestContinent.Count > PMG.GenerationSettings.MaxContinentSize)
            {
                int minCuts = int.MaxValue;
                int minCutMinRegions = int.MaxValue;
                KargerGraph bestGraph = null;
                int cyclesWithoutImprovement = 0;
                while(cyclesWithoutImprovement < 50 || bestGraph == null)
                {
                    cyclesWithoutImprovement++;
                    KargerGraph graph = SplitClusterOnce(biggestContinent);
                    if(graph.Vertices[0].ContainedPolygons.Count >= PMG.GenerationSettings.MinContinentSize && graph.Vertices[1].ContainedPolygons.Count >= PMG.GenerationSettings.MinContinentSize)
                    {
                        int graphMinCutMinRegions = Mathf.Min(graph.Vertices[0].ContainedPolygons.Count, graph.Vertices[1].ContainedPolygons.Count);
                        if (graph.CutSize < minCuts || (graph.CutSize == minCuts && graphMinCutMinRegions > minCutMinRegions))
                        {
                            minCuts = graph.CutSize;
                            minCutMinRegions = graphMinCutMinRegions;
                            bestGraph = graph;
                            cyclesWithoutImprovement = 0;
                        }
                    }
                }

                List<GraphPolygon> newContinent = new List<GraphPolygon>();
                foreach (GraphPolygon splittedPolygon in bestGraph.Vertices[0].ContainedPolygons)
                {
                    newContinent.Add(splittedPolygon);
                    biggestContinent.Remove(splittedPolygon);
                    splittedPolygon.Continent = newContinent;
                }
                PMG.Continents.Add(newContinent);

                biggestContinent = PMG.Continents.OrderByDescending(x => x.Count).First();
            }

            
            // 3. Assign islands that are too small to the nearest continent
            List<GraphPolygon> smallestContinent = PMG.Continents.OrderBy(x => x.Count).First();
            while(smallestContinent.Count < PMG.GenerationSettings.MinContinentSize)
            {
                float shortestDistance = float.MaxValue;
                GraphPolygon shortestDistancePolygon = null;
                foreach(GraphPolygon continentPoly in smallestContinent)
                {
                    foreach(GraphPolygon waterNeighbour in continentPoly.WaterNeighbours)
                    {
                        if(!smallestContinent.Contains(waterNeighbour))
                        {
                            float distance = PolygonMapFunctions.GetPolygonDistance(continentPoly, waterNeighbour);
                            if (distance < shortestDistance)
                            {
                                shortestDistance = distance;
                                shortestDistancePolygon = waterNeighbour;
                            }
                        }
                    }
                }

                foreach (GraphPolygon continentPoly in smallestContinent)
                {
                    continentPoly.Continent = shortestDistancePolygon.Continent;
                    shortestDistancePolygon.Continent.Add(continentPoly);
                }
                smallestContinent.Clear();
                PMG.Continents.Remove(smallestContinent);

                smallestContinent = PMG.Continents.OrderBy(x => x.Count).First();
            }
            
        }