private static SparseField2d <List <SplineTree> > InitializeSplines(WaterTableField wtf, Random random) { var splines = new SparseField2d <List <SplineTree> >(wtf.Width, wtf.Height, null); foreach (var system in wtf.RiverSystems) { SplineTree tree = null; foreach (var p in system.value) { if (splines[p.value.y, p.value.x] == null) { splines[p.value.y, p.value.x] = new List <SplineTree>(); } splines[p.value.y, p.value.x].Add(tree ?? (tree = new SplineTree(system.value, wtf, random))); } } return(splines); }
public static void RunZoomedInScenario() { // 32x32 up to 1024x1024 will, from the fifth-of-a-mile-per-pixel source, get us approximately 10m per pixel. // 16x16 would get us 5 // 8x8 would get us 2.5 // 4x4 would get us 1.25 // 2x2 would get us .75 // 1x1 would get us .375, which is slightly over 1 foot. // I think 16x16 is the sweet spot. That's just over 9 square miles per small map. const int SMALL_MAP_SIDE_LEN = 64; const float STARTING_SCALE = 0.005f * SMALL_MAP_SIDE_LEN / 32; const int SMALL_MAP_RESIZED_LEN = 1024; Random random = new Random(); WaterTableArgs args = new WaterTableArgs(); Bitmap bmp = new Bitmap(args.inputPath + "rivers.png"); IField2d <float> baseMap = new Utils.FieldFromBitmap(new Bitmap(args.inputPath + "base_heights.png")); baseMap = new ReResField(baseMap, (float)bmp.Width / baseMap.Width); var wtf = Utils.GenerateWaters(bmp, baseMap); Utils.OutputAsColoredMap(wtf, wtf.RiverSystems, bmp, args.outputPath + "colored_map.png"); var hasWater = new Transformation2d <HydrologicalField.LandType, float>(wtf.HydroField, t => t == HydrologicalField.LandType.Land ? 0f : 1f); var noiseDamping = new Transformation2d(new BlurredField(hasWater, 2f), v => 3.5f * v); // Create the spline map. SparseField2d <List <SplineTree> > relevantSplines = new SparseField2d <List <SplineTree> >(wtf.Width, wtf.Height, null); { //HashSet<TreeNode<Point2d>> relevantRivers = new HashSet<TreeNode<Point2d>>(); foreach (var system in wtf.RiverSystems) { SplineTree tree = null; foreach (var p in system.value) { if (relevantSplines[p.value.y, p.value.x] == null) { relevantSplines[p.value.y, p.value.x] = new List <SplineTree>(); } relevantSplines[p.value.y, p.value.x].Add(tree ?? (tree = new SplineTree(system.value, wtf, random))); } } } Rectangle rect = new Rectangle(518 + 15, 785 + 45, SMALL_MAP_SIDE_LEN, SMALL_MAP_SIDE_LEN); var smallMap = new SubField <float>(wtf, rect); var scaledUp = new BlurredField(new ReResField(smallMap, SMALL_MAP_RESIZED_LEN / smallMap.Width), SMALL_MAP_RESIZED_LEN / (4 * SMALL_MAP_SIDE_LEN)); var smallDamp = new SubField <float>(noiseDamping, rect); var scaledDamp = new BlurredField(new ReResField(smallDamp, SMALL_MAP_RESIZED_LEN / smallMap.Width), SMALL_MAP_RESIZED_LEN / (4 * SMALL_MAP_SIDE_LEN)); // Do spline-y things. Field2d <float> riverbeds; List <SplineTree> splines = new List <SplineTree>(); { // Collect a comprehensive list of the spline trees for the local frame. for (int y = rect.Top - 1; y <= rect.Bottom + 1; y++) { for (int x = rect.Left - 1; x <= rect.Right + 1; x++) { List <SplineTree> trees = relevantSplines[y, x]; if (trees != null) { splines.AddRange(trees); } } } // Crafts the actual river kernel. Probably not the best way to go about this. riverbeds = new Field2d <float>(new ConstantField <float>(SMALL_MAP_RESIZED_LEN, SMALL_MAP_RESIZED_LEN, float.MaxValue)); foreach (var s in splines) { var samples = s.GetSamplesPerControlPoint(1f * SMALL_MAP_RESIZED_LEN / SMALL_MAP_SIDE_LEN); int priorX = int.MinValue; int priorY = int.MinValue; foreach (var p in samples) { int x = (int)((p[0] - rect.Left) * SMALL_MAP_RESIZED_LEN / SMALL_MAP_SIDE_LEN); int y = (int)((p[1] - rect.Top) * SMALL_MAP_RESIZED_LEN / SMALL_MAP_SIDE_LEN); if (x == priorX && y == priorY) { continue; } else { priorX = x; priorY = y; } if (0 <= x && x < SMALL_MAP_RESIZED_LEN && 0 <= y && y < SMALL_MAP_RESIZED_LEN) { const int r = 1024 / SMALL_MAP_SIDE_LEN; for (int j = -r; j <= r; j++) { for (int i = -r; i <= r; i++) { int xx = x + i; int yy = y + j; if (0 <= xx && xx < SMALL_MAP_RESIZED_LEN && 0 <= yy && yy < SMALL_MAP_RESIZED_LEN) { float dSq = i * i + j * j; riverbeds[yy, xx] = Math.Min(riverbeds[yy, xx], p[2] + dSq / (512f * 32 / SMALL_MAP_SIDE_LEN)); //scaledDamp[yy, xx] = 1f; //scaledUp[yy, xx] = Math.Min(scaledUp[yy, xx], p[2] + (float)Math.Sqrt(xx * xx + yy * yy) / 1f); } } } } } } //Utils.OutputField(riverbeds, new Bitmap(riverbeds.Width, riverbeds.Height), args.outputPath + "river_field.png"); } var mountainous = new ScaleTransform(new MountainNoise(1024, 1024, STARTING_SCALE), 1f); var hilly = new ScaleTransform(new Simplex2D(1024, 1024, STARTING_SCALE * 4), 0.1f); var terrainNoise = new Transformation2d <float, float, float>(mountainous, hilly, (x, y, m, h) => { float a = scaledUp[y, x]; float sh = Math.Max(-2f * Math.Abs(a - 0.2f) / 3f + 1f, 0f); float sm = Math.Min(1.3f * a, 1f); return(h * sh + m * sm); }); IField2d <float> combined = new NormalizedComposition2d <float>( new Transformation2d <float, float, float>(riverbeds, new Composition2d <float>(scaledUp, new Transformation2d <float, float, float>(scaledDamp, terrainNoise, (s, m) => (1 - Math.Min(1, s)) * m) ), (r, c) => r == float.MaxValue ? c : Math.Min(r, c)) ); Bitmap img = new Bitmap(combined.Width, combined.Height); Utils.OutputField(combined, img, args.outputPath + "combined.png"); Utils.OutputAsOBJ(combined, splines, rect, img, args.outputPath); }