Beispiel #1
0
        public static void RunWateryScenario()
        {
            Bitmap          jranjana = new Bitmap("C:\\Users\\Justin Murray\\Desktop\\maps\\input\\rivers_lr.png");
            Field2d <float> field    = new Utils.FieldFromBitmap(jranjana);
            BrownianTree    tree     = BrownianTree.CreateFromOther(field, (x) => x > 0.5f ? BrownianTree.Availability.Available : BrownianTree.Availability.Unavailable);

            tree.RunDefaultTree();
            HydrologicalField hydro = new HydrologicalField(tree);
            var sets = hydro.FindContiguousSets();
            List <TreeNode <Point2d> > riverForest = new List <TreeNode <Point2d> >();

            foreach (var river in sets[HydrologicalField.LandType.Shore])
            {
                riverForest.Add(river.MakeTreeFromContiguousSet(pt =>
                {
                    // Warning: naive non-boundary-checking test-only implementation.  This will probably CRASH THE PROGRAM
                    // if a river happens to border the edge of the map.
                    return
                    (hydro[pt.y + 1, pt.x + 1] == HydrologicalField.LandType.Ocean ||
                     hydro[pt.y + 1, pt.x + 0] == HydrologicalField.LandType.Ocean ||
                     hydro[pt.y + 1, pt.x - 1] == HydrologicalField.LandType.Ocean ||
                     hydro[pt.y + 0, pt.x - 1] == HydrologicalField.LandType.Ocean ||
                     hydro[pt.y - 1, pt.x - 1] == HydrologicalField.LandType.Ocean ||
                     hydro[pt.y - 1, pt.x + 0] == HydrologicalField.LandType.Ocean ||
                     hydro[pt.y - 1, pt.x + 1] == HydrologicalField.LandType.Ocean ||
                     hydro[pt.y + 0, pt.x + 1] == HydrologicalField.LandType.Ocean);
                }));
            }
            DrainageField draino = new DrainageField(hydro, riverForest);
            List <TreeNode <TreeNode <Point2d> > > riverSets = new List <TreeNode <TreeNode <Point2d> > >();

            foreach (var river in riverForest)
            {
                riverSets.Add(river.GetMajorSubtrees(node => node.Depth() > 15));
            }

            using (var file = System.IO.File.OpenWrite("C:\\Users\\Justin Murray\\Desktop\\maps\\output\\report.txt"))
                using (var writer = new System.IO.StreamWriter(file))
                {
                    riverSets.OrderByDescending(set => set.Size()).Select(riverSet =>
                    {
                        writer.WriteLine("River of size " + riverSet.value.Size() + " with " + riverSet.Size() + " separate sub-rivers.");
                        foreach (var river in riverSet.ToArray().OrderByDescending(t => t.Depth()))
                        {
                            writer.WriteLine("\tPart of river with " + river.value.Depth() + " depth and " + (river.Size() - 1) + " tributaries.");
                        }
                        writer.WriteLine();
                        return(0);
                    }).ToArray();
                }

            Utils.OutputAsTributaryMap(sets, riverSets, draino, jranjana, "C:\\Users\\Justin Murray\\Desktop\\maps\\output\\tree.png");
        }
Beispiel #2
0
        public WaterTableField(
            IField2d <float> baseField,
            IField2d <HydrologicalField.LandType> hydroField,
            float shoreHeightAboveRiver = 0.01f,
            int blurIterations          = 10,
            int minWaterwayLength       = 5,
            float minGrade        = 0f,
            Func <float> getCarve = null)
            : base(baseField.Width, baseField.Height)
        {
            getCarve = getCarve ?? (() => { return(1f); });

            this.HydroField    = hydroField;
            GeographicFeatures = this.HydroField.FindContiguousSets();
            Waterways          = GeographicFeatures.GetRiverSystems(this.HydroField).Where(ww => ww.Depth() >= minWaterwayLength).ToList();
            RiverSystems       = Waterways.GetRivers();
            DrainageField      = new DrainageField(this.HydroField, Waterways);

            foreach (var sea in GeographicFeatures[HydrologicalField.LandType.Ocean])
            {
                foreach (var p in sea)
                {
                    this[p.y, p.x] = 0f;
                }
            }

            // Set the heights of all the river systems.
            foreach (var river in RiverSystems)
            {
                Queue <TreeNode <TreeNode <Point2d> > > mouths = new Queue <TreeNode <TreeNode <Point2d> > >();
                mouths.Enqueue(river);

                Point2d p = river.value.value;
                this[p.y, p.x] = 0f;

                while (mouths.Count > 0)
                {
                    var mouth = mouths.Dequeue();

                    // Discarded alternative approach: instead of using an incrementor, use a low pass filter
                    // against base field altitude (with a no-lowering caveat).  Produces some nice effects and
                    // leaves mountains remarkably well intact; however, abandoned because, when faced with a
                    // river that flows all the way through a mountain range, the filter will choose to extend
                    // the mountain range rather than carve a valley through it.

                    List <Point2d> points = new List <Point2d>();
                    mouth.IteratePrimarySubtree().Iterate(node => points.Add(node.value));
                    p = points[0];
                    float mouthAlti = this[p.y, p.x];
                    p = points[points.Count - 1];
                    float sourceAlti = Math.Max(baseField[p.y, p.x], mouthAlti + points.Count * minGrade);

                    float carve = getCarve();

                    Func <float, float> ceiling = t =>
                    {
                        float lrp = (float)Math.Pow(t, carve);
                        return(mouthAlti * (1f - lrp) + sourceAlti * lrp);
                    };

                    Func <float, float> floor = t =>
                    {
                        return(mouthAlti + points.Count * t * minGrade);
                    };

                    float val = mouthAlti;
                    for (int idx = 0; idx < points.Count; idx++)
                    {
                        float t = 1f * idx / points.Count;

                        p = points[idx];

                        val += minGrade;
                        val  = Math.Max(val, floor(t));
                        val  = Math.Max(val, baseField[p.y, p.x]);
                        val  = Math.Min(val, ceiling(t));

                        this[p.y, p.x] = val;
                    }

                    foreach (var child in mouth.children)
                    {
                        mouths.Enqueue(child);
                    }
                }
            }

            // At this point, all the water pixels have a defined height; set every
            // land pixel to be the same height as its drain iff it drains to a river.
            foreach (var land in GeographicFeatures[HydrologicalField.LandType.Land])
            {
                foreach (var p in land)
                {
                    Point2d drain = DrainageField[p.y, p.x];
                    if (this.HydroField[drain.y, drain.x] == HydrologicalField.LandType.Shore)
                    {
                        this[p.y, p.x] = this[drain.y, drain.x] + shoreHeightAboveRiver;
                    }
                    else
                    {
                        this[p.y, p.x] = baseField[p.y, p.x] + shoreHeightAboveRiver;
                    }
                }
            }

            for (int idx = 0; idx < blurIterations; idx++)
            {
                BlurredField bf = new BlurredField(this, 1);
                foreach (var land in GeographicFeatures[HydrologicalField.LandType.Land])
                {
                    foreach (var p in land)
                    {
                        this[p.y, p.x] = bf[p.y, p.x];
                    }
                }
            }

            //System.Diagnostics.Debug.Assert(Waterways.AreWaterwaysLegalForField(this));
        }