Beispiel #1
0
        private List <GraphicsPath> GenerateTerrainOutline()
        {
            // travel around an ellipse, with noise applied to it

            // 0.001 to 0.01 seems to work best for noise frequency, 100 works well for noise amplitude
            float frequency     = 0.005f;
            float amplitude     = Math.Min(Width, Height) / 2;
            var   terrainNoiseX = new PerlinNoise(Random.Next(), frequency, amplitude, 4);
            var   terrainNoiseY = new PerlinNoise(Random.Next(), frequency, amplitude, 4);

            var landmasses = new List <List <PointF> >();

            var mainland = new List <PointF>();

            landmasses.Add(mainland);

            var prevPoint = new PointF(Width / 2f, Height / 2f);

            float ellipseWidth  = Width * 0.75f;
            float ellipseHeight = Height * 0.75f;

            int step = 0;

            for (float angle = (float)Math.PI * 2; angle > 0; angle -= 0.01f /* roughly 500 steps */)
            {
                step++;

                float ellipseX = Width / 2f + (float)Math.Cos(angle) * ellipseWidth / 2;
                float ellipseY = Height / 2f + (float)Math.Sin(angle) * ellipseHeight / 2;

                float placeX = ellipseX + terrainNoiseX.GetValue(ellipseX, ellipseY);
                float placeY = ellipseY + terrainNoiseY.GetValue(ellipseX, ellipseY);

                var nextPoint = new PointF(placeX, placeY);

                // See if prevPoint - nextPoint crosses ANY of the previous lines. If it does, we have a loop / dangler.
                // Ignore the first line and the most recent line, cos we may well touch those.

                for (int i = mainland.Count - 3; i > 1; i--)
                {
                    var testEnd   = mainland[i - 1];
                    var testStart = mainland[i];

                    if (LineSegmentsCross(prevPoint, nextPoint, testStart, testEnd))
                    {
                        // Because we are ALWAYS working our way anticlockwise around the main landmass:
                        // "outties" always have the "older" line cross the "newer" one from left to right.
                        // "innies" always have the "older" line cross the "newer" one from right to left.
                        // UNLESS we are dealing with "nested" outties or innies, in which case the direction swaps.
                        // But maybe its ok to swap what we do there, as we will get larger islands / inlets that way,
                        // as opposed to "chains" of smaller ones, which are perhaps less important - especially on a political map.

                        bool chopOff = IsLeftOfLine(prevPoint, nextPoint, testEnd);
                        HandleTerrainBoundaryLoop(landmasses, mainland, i, chopOff);
                        break;
                    }
                }

                mainland.Add(nextPoint);
                prevPoint = nextPoint;
            }

            ScaleToFitBounds(landmasses);

            Landmasses = landmasses
                         .Select(points =>
            {
                var types = new byte[points.Count];
                for (var i = types.Length - 1; i >= 0; i--)
                {
                    types[i] = 1;
                }

                return(new GraphicsPath(points.Select(p => new System.Drawing.PointF(p.X, p.Y)).ToArray(), types));
            })
                         .ToList();

            return(Landmasses);
        }