/// <summary> /// Calculates the height of the specified midpoint against its Von Neumann neighborhood. /// </summary> /// <param name="t">Playground.</param> /// <param name="M">Midpoint in question.</param> /// <param name="SS">Section step.</param> /// <returns>Transformed midpoint.</returns> private static double GetMidpointHeight(Terrain t, HeightPoint M, int SS) { // T // L M R // B HeightPoint L, R, T, B; int size; // No error checking here bacuse it is called from an inner loop. size = t.Size.Width; L = M + (HeightPoint.LeftVector * SS / 2); R = M + (HeightPoint.RightVector * SS / 2); T = M + (HeightPoint.TopVector * SS / 2); B = M + (HeightPoint.BottomVector * SS / 2); if (L.X < 0) { L.X = size - 1; } if (R.X >= size) { R.X = 0; } if (T.Y < 0) { T.Y = size - 1; } if (B.Y >= size) { B.Y = 0; } L.Height = t[L.X, L.Y]; R.Height = t[R.X, R.Y]; T.Height = t[T.X, T.Y]; B.Height = t[B.X, B.Y]; M = HeightPoint.Midpoint(L, R, T, B); return(M.Height); }
/// <summary> /// Strict, iterative implementation of the Diamond-Square terrain generation algorithm. /// Terrain must be a square with edges in the form of 2^I + 1, where I is the number of required iteraions. /// </summary> /// <param name="t">Terrain to use.</param> /// <param name="H">Jag parameter.</param> public static void DiamondSquare_Strict(Terrain t, [AttributeDouble("Jag Parameter", 1.0, 0.0, 10.0, 2, 0.1)] double H) { // A e B e:AB f:AC g:BD h:CD // f M g M:AD // C h D VerifyNotNull(t, "t"); VerifyValidDouble(H, "H"); if (t.Size.Width != t.Size.Height) { throw new ArgumentException("Terrain height and width must be equal.", "t"); } if (Math.Log(t.Size.Width - 1, 2) != (int)Math.Log(t.Size.Width - 1, 2)) { throw new ArgumentException("Terrain size must be in the form of 2^I + 1.", "t"); } HeightPoint A, B, C, D; HeightPoint M, e, f, g, h; int size; int SP, I, SC, SS, Sx, Sy; double R, r; Random rg; // Get terrain size, initialize RNG and randomize the four terrain corners. size = t.Size.Width; rg = new Random(); r = 0; // GetRandom(rg, 1); t[0, 0] = r; t[size - 1, 0] = r; t[0, size - 1] = r; t[size - 1, size - 1] = r; #region REPORT INIT if (t.PBW != null) { t.PBW.Report("Diamond Square (Strict)", (int)((2.0 / 3.0) * (double)(size * size - 2 * size))); if (t.PBW.CancellationPending) { return; } } #endregion SP = (int)Math.Log(size - 1, 2); for (I = 0; I < SP; I++) { SS = (int)Math.Pow(2, SP - I); SC = (int)Math.Pow(2, I); R = Math.Pow(2, (-H * I)); // Diamond step for (Sx = 0; Sx < SC; Sx++) { for (Sy = 0; Sy < SC; Sy++) { #region REPORT if (t.PBW != null) { t.PBW.Report(); if (t.PBW.CancellationPending) { return; } } #endregion // Find the four corners and thier heights. A = new HeightPoint(SS * Sx, SS * Sy); B = new HeightPoint(SS * (Sx + 1), SS * Sy); C = new HeightPoint(SS * Sx, SS * (Sy + 1)); D = new HeightPoint(SS * (Sx + 1), SS * (Sy + 1)); A.Height = t[A.X, A.Y]; B.Height = t[B.X, B.Y]; C.Height = t[C.X, C.Y]; D.Height = t[D.X, D.Y]; // Find the center and calculate its height. M = A % D; r = GetRandom(rg, R); M.Height = (A.Height + B.Height + C.Height + D.Height) / 4 + r; // Store the results. t[M.X, M.Y] = M.Height; } } // Square step for (Sx = 0; Sx < SC; Sx++) { for (Sy = 0; Sy < SC; Sy++) { #region REPORT if (t.PBW != null) { t.PBW.Report(); if (t.PBW.CancellationPending) { return; } } #endregion // Find the four corners and their heights. A = new HeightPoint(SS * Sx, SS * Sy); B = new HeightPoint(SS * (Sx + 1), SS * Sy); C = new HeightPoint(SS * Sx, SS * (Sy + 1)); D = new HeightPoint(SS * (Sx + 1), SS * (Sy + 1)); // For each midpoint, find its coordinates, calculate height and store the result. e = A % B; e.Height = GetMidpointHeight(t, e, SS); t[e.X, e.Y] = e.Height; f = A % C; f.Height = GetMidpointHeight(t, f, SS); t[f.X, f.Y] = f.Height; if (Sx == (SC - 1)) { g = B % D; g.Height = GetMidpointHeight(t, g, SS); t[g.X, g.Y] = g.Height; } if (Sy == (SC - 1)) { h = C % D; h.Height = GetMidpointHeight(t, h, SS); t[h.X, h.Y] = h.Height; } } } } t.Normalize(); }