/// <summary>
    /// Returns the number of polygons that have to be traversed (through water or land neighbour) to get from p1 to p2 (neighbouring polygons have distance = 1)
    /// </summary>
    public static int GetRegionDistance(GraphPolygon p1, GraphPolygon p2)
    {
        int range = 0;
        List <GraphPolygon> rangePolygons = new List <GraphPolygon>()
        {
            p1
        };

        while (!rangePolygons.Contains(p2) && range < 50)
        {
            range++;
            List <GraphPolygon> polygonsToAdd = new List <GraphPolygon>();
            foreach (GraphPolygon poly in rangePolygons)
            {
                foreach (GraphPolygon neighbour in poly.Neighbours)
                {
                    if (!rangePolygons.Contains(neighbour) && !polygonsToAdd.Contains(neighbour))
                    {
                        polygonsToAdd.Add(neighbour);
                    }
                }
            }
            rangePolygons.AddRange(polygonsToAdd);
        }
        return(range);
    }
    /// <summary>
    /// Takes a list of regions as an input and splits them into clusters. A cluster is defined as each region is reachable from each other region in the cluster through direct land connections.
    /// </summary>
    public static List <List <GraphPolygon> > FindClusters(List <GraphPolygon> polygons, bool landConnectionsOnly = true)
    {
        List <List <GraphPolygon> > clusters = new List <List <GraphPolygon> >();

        List <GraphPolygon> polygonsWithoutCluster = new List <GraphPolygon>();

        polygonsWithoutCluster.AddRange(polygons);

        while (polygonsWithoutCluster.Count > 0)
        {
            List <GraphPolygon>  cluster       = new List <GraphPolygon>();
            Queue <GraphPolygon> polygonsToAdd = new Queue <GraphPolygon>();
            polygonsToAdd.Enqueue(polygonsWithoutCluster[0]);
            while (polygonsToAdd.Count > 0)
            {
                GraphPolygon polygonToAdd = polygonsToAdd.Dequeue();
                cluster.Add(polygonToAdd);
                List <GraphPolygon> neighbouringPolygons = landConnectionsOnly ? polygonToAdd.LandNeighbours.Where(x => polygons.Contains(x)).ToList() : polygonToAdd.Neighbours.Where(x => polygons.Contains(x)).ToList();
                foreach (GraphPolygon neighbourPolygon in neighbouringPolygons)
                {
                    if (!cluster.Contains(neighbourPolygon) && !polygonsToAdd.Contains(neighbourPolygon))
                    {
                        polygonsToAdd.Enqueue(neighbourPolygon);
                    }
                }
            }
            clusters.Add(cluster);
            foreach (GraphPolygon p in cluster)
            {
                polygonsWithoutCluster.Remove(p);
            }
        }

        return(clusters);
    }
示例#3
0
 private void Form1_Load(object sender, EventArgs e)
 {
     B = new Bitmap(pictureBox1.Width, pictureBox1.Height);
     pictureBox1.Image = B;
     G           = Graphics.FromImage(B);
     Polygons    = new List <GraphPolygon>();
     ClipPolygon = new GraphPolygon(B, G, new Pen(pnlCuttingRect.BackColor));
     Polygons.Add(new GraphPolygon(B, G, new Pen(pnlLine.BackColor)));
 }
示例#4
0
    public void Init(GraphPolygon p)
    {
        Id              = p.Id;
        Polygon         = p;
        BorderPoints    = p.Nodes.Select(x => x.BorderPoint).ToList();
        Borders         = p.Connections.Select(x => x.Border).ToList();
        AdjacentRegions = p.AdjacentPolygons.Select(x => x.Region).ToList();
        LandNeighbours  = p.LandNeighbours.Select(x => x.Region).ToList();
        WaterNeighbours = p.WaterNeighbours.Select(x => x.Region).ToList();
        Neighbours      = LandNeighbours.Concat(WaterNeighbours).ToList();
        SetRegionBorders();

        Width     = p.Width;
        Height    = p.Height;
        XPos      = p.Nodes.Min(x => x.Vertex.x);
        YPos      = p.Nodes.Min(x => x.Vertex.y);
        Centroid  = p.Centroid;
        CenterPoi = p.CenterPoi;

        Area               = p.Area;
        Jaggedness         = p.Jaggedness;
        TotalBorderLength  = p.TotalBorderLength;
        InlandBorderLength = p.InlandBorderLength;
        InlandBorderRatio  = InlandBorderLength / TotalBorderLength;
        CoastLength        = p.Coastline;
        CoastRatio         = CoastLength / TotalBorderLength;

        Temperature   = p.Temperature;
        Precipitation = p.Precipitation;
        Biome         = p.Biome;

        IsWater                  = p.IsWater;
        IsNextToWater            = p.IsNextToWater;
        IsEdgeRegion             = p.IsEdgePolygon;
        IsOuterOcean             = p.IsOuterPolygon;
        DistanceFromNearestWater = p.DistanceFromNearestWater;

        GetComponent <Renderer>().material = MapDisplayResources.Singleton.DefaultMaterial;

        // Coast
        OceanCoastLength = RegionBorders.Where(x => x.Key.WaterBody != null && !x.Key.WaterBody.IsLake).Sum(x => x.Value.Sum(y => y.Length));
        OceanCoastRatio  = OceanCoastLength / TotalBorderLength;
        LakeCoastLength  = RegionBorders.Where(x => x.Key.WaterBody != null && x.Key.WaterBody.IsLake).Sum(x => x.Value.Sum(y => y.Length));
        LakeCoastRatio   = LakeCoastLength / TotalBorderLength;

        // Border surrounding the region
        Border = MeshGenerator.CreateSinglePolygonBorder(p.Nodes, PolygonMapGenerator.DefaultRegionBorderWidth, Color.black, layer: PolygonMapGenerator.LAYER_REGION_BORDER);
        Border.transform.SetParent(transform);

        // Connection overlays (lines to neighbouring regions)
        ConnectionOverlays = InitConnectionOverlays();
        ShowConnectionOverlays(false);
    }
示例#5
0
 private void ClipAndDraw()
 {
     if (curstep == 0)
     {
         Result = new GraphPolygon(B, G, new Pen(pnlCuttingLine.BackColor, 2));
     }
     for (int i = 0; i < Polygons.Count - 1; i++)
     {
         if (PolygonClip(Polygons[i], ref Result, ClipPolygon))
         {
             Result.Draw();
         }
     }
 }
    /// <summary>
    /// Returns the shortest distance between two polygons (distance between two closest points)
    /// </summary>
    public static float GetPolygonDistance(GraphPolygon p1, GraphPolygon p2)
    {
        float shortestDistance = float.MaxValue;

        foreach (GraphNode fromNode in p1.Nodes)
        {
            foreach (GraphNode toNode in p2.Nodes)
            {
                float distance = Vector2.Distance(fromNode.Vertex, toNode.Vertex);
                if (distance < shortestDistance)
                {
                    shortestDistance = distance;
                }
            }
        }
        return(shortestDistance);
    }
    /// <summary>
    /// Returns a list containing the two graphnodes that are the closest to each other from p1 and p2. The first element is a node from p1, the second element a node from p2.
    /// if ignoreMultiNodes is true, only nodes that have exactly 2 polygons are considered
    /// if shoreOnly is true, only nodes that have at least one water polygon will be considered
    /// </summary>
    public static List <GraphNode> GetClosestPolygonNodes(GraphPolygon p1, GraphPolygon p2, bool ignoreMultiNodes, bool shoreOnly)
    {
        float     shortestDistance = float.MaxValue;
        GraphNode n1 = null;
        GraphNode n2 = null;

        List <GraphNode> p1Nodes = p1.Nodes;
        List <GraphNode> p2Nodes = p2.Nodes;

        if (ignoreMultiNodes)
        {
            p1Nodes = p1Nodes.Where(x => x.Polygons.Count == 2).ToList();
            p2Nodes = p2Nodes.Where(x => x.Polygons.Count == 2).ToList();
        }
        if (shoreOnly)
        {
            p1Nodes = p1Nodes.Where(x => x.Type == BorderPointType.Shore).ToList();
            p2Nodes = p2Nodes.Where(x => x.Type == BorderPointType.Shore).ToList();
        }

        foreach (GraphNode fromNode in p1Nodes)
        {
            foreach (GraphNode toNode in p2Nodes)
            {
                float distance = Vector2.Distance(fromNode.Vertex, toNode.Vertex);
                if (distance < shortestDistance)
                {
                    shortestDistance = distance;
                    n1 = fromNode;
                    n2 = toNode;
                }
            }
        }
        return(new List <GraphNode>()
        {
            n1, n2
        });
    }
示例#8
0
    public static Map LoadMapFromHash(PolygonMapGenerator PMG, string mapHash)
    {
        string[] lines     = mapHash.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
        int      lineIndex = 0;

        // Line 0: MapGenerationSettings: seed;width;height;minPolygonArea;maxPolygonArea;minContinentSize;maxContinentSize;mapType;continentSizeScale
        int debugI = 0;

        Debug.Log(debugI++);
        string[] mgsLine            = lines[lineIndex++].Split(';');
        int      seed               = int.Parse(mgsLine[0]);
        int      width              = int.Parse(mgsLine[1]);
        int      height             = int.Parse(mgsLine[2]);
        float    minPolygonArea     = float.Parse(mgsLine[3]);
        float    maxPolygonArea     = float.Parse(mgsLine[4]);
        int      minContinentSize   = int.Parse(mgsLine[5]);
        int      maxContinentSize   = int.Parse(mgsLine[6]);
        MapType  mapType            = (MapType)int.Parse(mgsLine[7]);
        float    continentSizeScale = float.Parse(mgsLine[8]);

        PMG.GenerationSettings = new MapGenerationSettings(seed, width, height, minPolygonArea, maxPolygonArea, minContinentSize, maxContinentSize, mapType, continentSizeScale);

        Debug.Log(debugI++);
        // Line 1: n_nodes;n_ingraphconnections;n_egdeconnections;n_polygons;n_paths;n_landmasses;n_waterbodies;n_continents
        string[] line1   = lines[lineIndex++].Split(';');
        int      n_nodes = int.Parse(line1[0]);
        int      n_inGraphConnections = int.Parse(line1[1]);
        int      n_edgeConnections    = int.Parse(line1[2]);
        int      n_polygons           = int.Parse(line1[3]);
        int      n_riverPaths         = int.Parse(line1[4]);
        int      n_landmasses         = int.Parse(line1[5]);
        int      n_waterBodies        = int.Parse(line1[6]);
        int      n_continents         = int.Parse(line1[7]);

        Debug.Log(debugI++);
        // Node Lines: id;positionX;positionY;riverWidth;distanceFromNearestOcean
        PMG.Nodes.Clear();
        Dictionary <int, GraphNode> nodeMap = new Dictionary <int, GraphNode>();

        for (int i = 0; i < n_nodes; i++)
        {
            string[]  attributes = lines[lineIndex++].Split(';');
            int       id         = int.Parse(attributes[0]);
            float     x          = float.Parse(attributes[1]);
            float     y          = float.Parse(attributes[2]);
            float     riverWidth = float.Parse(attributes[3]);
            int       distanceFromNearestOcean = int.Parse(attributes[4]);
            GraphNode node = new GraphNode(id, x, y, riverWidth, distanceFromNearestOcean);
            nodeMap.Add(id, node);
            PMG.Nodes.Add(node);
        }

        Debug.Log(debugI++);
        // InGraphConnection Lines: id;fromNodeId;toNodeId;riverWidth
        PMG.InGraphConnections.Clear();
        Dictionary <int, GraphConnection> connectionMap = new Dictionary <int, GraphConnection>();

        for (int i = 0; i < n_inGraphConnections; i++)
        {
            string[]        attributes  = lines[lineIndex++].Split(';');
            int             id          = int.Parse(attributes[0]);
            int             startNodeId = int.Parse(attributes[1]);
            int             endNodeId   = int.Parse(attributes[2]);
            float           riverWidth  = float.Parse(attributes[3]);
            GraphConnection connection  = new GraphConnection(id, nodeMap[startNodeId], nodeMap[endNodeId], riverWidth);
            connectionMap.Add(id, connection);
            PMG.InGraphConnections.Add(connection);
        }

        Debug.Log(debugI++);
        // EdgeConnection Lines: id;fromNodeId;toNodeId;riverWidth
        PMG.EdgeConnections.Clear();
        for (int i = 0; i < n_edgeConnections; i++)
        {
            string[]        attributes  = lines[lineIndex++].Split(';');
            int             id          = int.Parse(attributes[0]);
            int             startNodeId = int.Parse(attributes[1]);
            int             endNodeId   = int.Parse(attributes[2]);
            float           riverWidth  = float.Parse(attributes[3]);
            GraphConnection connection  = new GraphConnection(id, nodeMap[startNodeId], nodeMap[endNodeId], riverWidth);
            connectionMap.Add(id, connection);
            PMG.EdgeConnections.Add(connection);
        }

        Debug.Log(debugI++);
        // Polygon Lines: id;[nodeIds];[connectionIds]
        PMG.Polygons.Clear();
        Dictionary <int, GraphPolygon> polygonMap = new Dictionary <int, GraphPolygon>();

        for (int i = 0; i < n_polygons; i++)
        {
            string[] attributes = lines[lineIndex++].Split(';');
            int      id         = int.Parse(attributes[0]);

            List <GraphNode> nodes   = new List <GraphNode>();
            string[]         nodeIds = attributes[1].Split(',');
            foreach (string s in nodeIds)
            {
                nodes.Add(nodeMap[int.Parse(s)]);
            }

            List <GraphConnection> connections = new List <GraphConnection>();
            string[] connectionIds             = attributes[2].Split(',');
            foreach (string s in connectionIds)
            {
                connections.Add(connectionMap[int.Parse(s)]);
            }

            GraphPolygon polygon = new GraphPolygon(id, nodes, connections);
            polygonMap.Add(id, polygon);
            PMG.Polygons.Add(polygon);
        }

        Debug.Log(debugI++);
        // River Path Lines: id;[nodeIds];[connectionIds];[polygonIds]
        PMG.RiverPaths.Clear();
        for (int i = 0; i < n_riverPaths; i++)
        {
            string[] attributes = lines[lineIndex++].Split(';');
            int      id         = int.Parse(attributes[0]);

            List <GraphNode> nodes   = new List <GraphNode>();
            string[]         nodeIds = attributes[1].Split(',');
            foreach (string s in nodeIds)
            {
                nodes.Add(nodeMap[int.Parse(s)]);
            }

            List <GraphConnection> connections = new List <GraphConnection>();
            string[] connectionIds             = attributes[2].Split(',');
            foreach (string s in connectionIds)
            {
                connections.Add(connectionMap[int.Parse(s)]);
            }

            List <GraphPolygon> polygons   = new List <GraphPolygon>();
            string[]            polygonIds = attributes[3].Split(',');
            foreach (string s in polygonIds)
            {
                polygons.Add(polygonMap[int.Parse(s)]);
            }

            GraphPath path = new GraphPath(id, nodes, connections, polygons);
            PMG.RiverPaths.Add(path);
        }

        Debug.Log(debugI++);
        // Landmass Lines: [polygonIds]
        PMG.Landmasses.Clear();
        for (int i = 0; i < n_landmasses; i++)
        {
            string[]            attributes = lines[lineIndex++].Split(';');
            List <GraphPolygon> polygons   = new List <GraphPolygon>();
            string[]            polygonIds = attributes[0].Split(',');
            foreach (string s in polygonIds)
            {
                polygons.Add(polygonMap[int.Parse(s)]);
            }
            PMG.Landmasses.Add(polygons);
        }

        Debug.Log(debugI++);
        // WaterBody Lines: [polygonIds]
        PMG.WaterBodies.Clear();
        for (int i = 0; i < n_waterBodies; i++)
        {
            string[]            attributes = lines[lineIndex++].Split(';');
            List <GraphPolygon> polygons   = new List <GraphPolygon>();
            string[]            polygonIds = attributes[0].Split(',');
            foreach (string s in polygonIds)
            {
                polygons.Add(polygonMap[int.Parse(s)]);
            }
            PMG.WaterBodies.Add(polygons);
        }

        Debug.Log(debugI++);
        // Continent Lines: [polygonIds]
        PMG.Continents.Clear();
        for (int i = 0; i < n_continents; i++)
        {
            string[]            attributes = lines[lineIndex++].Split(';');
            List <GraphPolygon> polygons   = new List <GraphPolygon>();
            string[]            polygonIds = attributes[0].Split(',');
            foreach (string s in polygonIds)
            {
                polygons.Add(polygonMap[int.Parse(s)]);
            }
            PMG.Continents.Add(polygons);
        }


        return(PMG.DrawMap());
    }
示例#9
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();
            }
            
        }
示例#10
0
        public bool PolygonClip(GraphPolygon Source, ref GraphPolygon Result, GraphPolygon Clipper)
        {
            if ((Clipper.Count < 3) || (Clipper.Convexity == -1))
            {
                MessageBox.Show("Polygon is not convex");
                return(false);
            }

            int           i, j;
            PointD        R;
            PointD        S = new PointD(), F = new PointD();
            List <PointD> TempSource = new List <PointD>();

            if (curstep == 0)
            {
                Result.Vertexes = new List <PointD>(Source.Vertexes);
            }
            Result.Closed = true;
            int t;

            if (Clipper.Square > 0)
            {
                t = 1;
            }
            else
            {
                t = -1;
            }
            Clipper.Add(Clipper[0]);


            for (i = curstep; i < Clipper.Count - 1; i++)
            {
                TempSource.Clear();
                F = Result.Vertexes[0];                 // end vertex
                S = Result.Vertexes[0];                 // begin vertex
                if (Geom2d.Square(S, Clipper.Vertexes[i], Clipper.Vertexes[i + 1]) * t >= 0)
                {
                    TempSource.Add(S);
                }
                for (j = 1; j < Result.Vertexes.Count; j++)
                {
                    if (Geom2d.SegmentLineIntersect(S, Result.Vertexes[j], Clipper.Vertexes[i], Clipper.Vertexes[i + 1], out R) == 1)
                    {
                        TempSource.Add(R);
                    }

                    S = Result.Vertexes[j];
                    if (Geom2d.Square(S, Clipper.Vertexes[i], Clipper.Vertexes[i + 1]) * t > 0)
                    {
                        TempSource.Add(S);
                    }
                }

                if ((TempSource.Count != 0) && (Geom2d.SegmentLineIntersect(S, F, Clipper.Vertexes[i], Clipper.Vertexes[i + 1], out R) == 1))
                {
                    TempSource.Add(R);
                }

                Result.Clear();
                Result.Vertexes.AddRange(TempSource);
                if (step)
                {
                    curstep = i + 1;
                    step    = false;
                    Clipper.RemoveLast();
                    return(true);
                }
            }

            Clipper.RemoveLast();
            return(true);
        }
示例#11
0
 public KargerGraphVertex(GraphPolygon poly)
 {
     ContainedPolygons.Add(poly);
 }