diff --git a/Terrain2/Algorithms/DiamondSquare.swift b/Terrain2/Algorithms/DiamondSquare.swift index 8055630..66da4ee 100644 --- a/Terrain2/Algorithms/DiamondSquare.swift +++ b/Terrain2/Algorithms/DiamondSquare.swift @@ -85,7 +85,7 @@ public class DiamondSquareGenerator: TerrainGenerator { } var subdivisions: [Box] { - guard size.w > 2 && size.h > 2 else { + guard size.w > 3 && size.h > 3 else { return [] } let halfSize = size.half @@ -159,16 +159,21 @@ public class DiamondSquareGenerator: TerrainGenerator { heightMap[convert(pointToIndex: midpoint)] = midpointValue // 2. Square step. For each of the side midpoints of this box, compute its value. - for pt in box.sideMidpoints { - let corners = diamondCorners(forPoint: pt, diamondSize: box.size) - let cornerValues = corners.map { (pt: Point) -> Float in - let idx = self.convert(pointToIndex: pt) - return heightMap[idx] - } - let ptValue = Float.random(in: spread) + self.average(ofPoints: cornerValues) - heightMap[convert(pointToIndex: pt)] = ptValue + + func updateHeight(for p: Point, a: Point, b: Point) { + let aValue = heightMap[convert(pointToIndex: a)] + let bValue = heightMap[convert(pointToIndex: b)] + let avg = 0.5 * (aValue + bValue) + let rand = Float.random(in: spread) + let value = avg + rand + heightMap[convert(pointToIndex: p)] = value } + updateHeight(for: box.north, a: box.northeast, b: box.northwest) + updateHeight(for: box.west, a: box.northwest, b: box.southwest) + updateHeight(for: box.south, a: box.southwest, b: box.southeast) + updateHeight(for: box.east, a: box.southeast, b: box.northeast) + if box.size != boxSize { // Reduce the spread as we recurse down to smaller squares. spread = -(spread.lowerBound * 0.5)...(spread.upperBound * 0.5) @@ -182,25 +187,30 @@ public class DiamondSquareGenerator: TerrainGenerator { } /// Find our diamond's corners, wrapping around the grid if needed. - func diamondCorners(forPoint pt: Point, diamondSize: Size) -> [Point] { - let halfSize = diamondSize.half - var corners = [Point(x: pt.x, y: pt.y - halfSize.h), - Point(x: pt.x - halfSize.w, y: pt.y), - Point(x: pt.x, y: pt.y + halfSize.h), - Point(x: pt.x + halfSize.w, y: pt.y)] - for i in 0..= grid.size.w { - corners[i].x -= grid.size.w - 1 - } else if corners[i].y < 0 { - corners[i].y += grid.size.h - 1 - } else if corners[i].y >= grid.size.h { - corners[i].y -= grid.size.h - 1 - } - } - return corners - } +// func diamondCorners(forPoint pt: Point, diamondSize: Size) -> [Point] { +// let halfSize = diamondSize.half +// +// func ptIsValid(pt: Point) -> Bool { +// return pt.x >= origin.x && pt.x < size.w && pt.y >= origin.y && pt.y < size.h +// } +// +// var corners = [Point(x: pt.x, y: pt.y - halfSize.h), +// Point(x: pt.x - halfSize.w, y: pt.y), +// Point(x: pt.x, y: pt.y + halfSize.h), +// Point(x: pt.x + halfSize.w, y: pt.y)].filter(ptIsValid) +// for i in 0..= grid.size.w { +// corners[i].x -= grid.size.w - 1 +// } else if corners[i].y < 0 { +// corners[i].y += grid.size.h - 1 +// } else if corners[i].y >= grid.size.h { +// corners[i].y -= grid.size.h - 1 +// } +// } +// return corners +// } func average(ofPoints pts: [Float]) -> Float { let scale: Float = 1.0 / Float(pts.count) diff --git a/Terrain2Tests/AlgorithmsTests.swift b/Terrain2Tests/AlgorithmsTests.swift index db875f7..8e8468f 100644 --- a/Terrain2Tests/AlgorithmsTests.swift +++ b/Terrain2Tests/AlgorithmsTests.swift @@ -38,41 +38,41 @@ class DiamondSquareAlgorithmTests: XCTestCase { // MARK: Diamond Corners - func testDiamondCornersNorth() { - let corners = alg.diamondCorners(forPoint: Point(x: 2, y: 0), diamondSize: grid.size) - XCTAssertEqual(corners.count, 4) - XCTAssertEqual(corners[0], Point(x: 2, y: 2)) - XCTAssertEqual(corners[1], Point(x: 0, y: 0)) - XCTAssertEqual(corners[2], Point(x: 2, y: 2)) - XCTAssertEqual(corners[3], Point(x: 4, y: 0)) - } - - func testDiamondCornersWest() { - let corners = alg.diamondCorners(forPoint: Point(x: 0, y: 2), diamondSize: grid.size) - XCTAssertEqual(corners.count, 4) - XCTAssertEqual(corners[0], Point(x: 0, y: 0)) - XCTAssertEqual(corners[1], Point(x: 2, y: 2)) - XCTAssertEqual(corners[2], Point(x: 0, y: 4)) - XCTAssertEqual(corners[3], Point(x: 2, y: 2)) - } - - func testDiamondCornersSouth() { - let corners = alg.diamondCorners(forPoint: Point(x: 2, y: 4), diamondSize: grid.size) - XCTAssertEqual(corners.count, 4) - XCTAssertEqual(corners[0], Point(x: 2, y: 2)) - XCTAssertEqual(corners[1], Point(x: 0, y: 4)) - XCTAssertEqual(corners[2], Point(x: 2, y: 2)) - XCTAssertEqual(corners[3], Point(x: 4, y: 4)) - } - - func testDiamondCornersEast() { - let corners = alg.diamondCorners(forPoint: Point(x: 4, y: 2), diamondSize: grid.size) - XCTAssertEqual(corners.count, 4) - XCTAssertEqual(corners[0], Point(x: 4, y: 0)) - XCTAssertEqual(corners[1], Point(x: 2, y: 2)) - XCTAssertEqual(corners[2], Point(x: 4, y: 4)) - XCTAssertEqual(corners[3], Point(x: 2, y: 2)) - } +// func testDiamondCornersNorth() { +// let corners = alg.diamondCorners(forPoint: Point(x: 2, y: 0), diamondSize: grid.size) +// XCTAssertEqual(corners.count, 4) +// XCTAssertEqual(corners[0], Point(x: 2, y: 2)) +// XCTAssertEqual(corners[1], Point(x: 0, y: 0)) +// XCTAssertEqual(corners[2], Point(x: 2, y: 2)) +// XCTAssertEqual(corners[3], Point(x: 4, y: 0)) +// } +// +// func testDiamondCornersWest() { +// let corners = alg.diamondCorners(forPoint: Point(x: 0, y: 2), diamondSize: grid.size) +// XCTAssertEqual(corners.count, 4) +// XCTAssertEqual(corners[0], Point(x: 0, y: 0)) +// XCTAssertEqual(corners[1], Point(x: 2, y: 2)) +// XCTAssertEqual(corners[2], Point(x: 0, y: 4)) +// XCTAssertEqual(corners[3], Point(x: 2, y: 2)) +// } +// +// func testDiamondCornersSouth() { +// let corners = alg.diamondCorners(forPoint: Point(x: 2, y: 4), diamondSize: grid.size) +// XCTAssertEqual(corners.count, 4) +// XCTAssertEqual(corners[0], Point(x: 2, y: 2)) +// XCTAssertEqual(corners[1], Point(x: 0, y: 4)) +// XCTAssertEqual(corners[2], Point(x: 2, y: 2)) +// XCTAssertEqual(corners[3], Point(x: 4, y: 4)) +// } +// +// func testDiamondCornersEast() { +// let corners = alg.diamondCorners(forPoint: Point(x: 4, y: 2), diamondSize: grid.size) +// XCTAssertEqual(corners.count, 4) +// XCTAssertEqual(corners[0], Point(x: 4, y: 0)) +// XCTAssertEqual(corners[1], Point(x: 2, y: 2)) +// XCTAssertEqual(corners[2], Point(x: 4, y: 4)) +// XCTAssertEqual(corners[3], Point(x: 2, y: 2)) +// } } class DiamondSquareBoxTests: XCTestCase { @@ -102,25 +102,25 @@ class DiamondSquareBoxTests: XCTestCase { Box(origin: Point(x: 0, y: 2), size: Size(w: 3, h: 3)), Box(origin: Point(x: 2, y: 2), size: Size(w: 3, h: 3)), - Box(origin: Point(x: 0, y: 0), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 1, y: 0), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 0, y: 1), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 1, y: 1), size: Size(w: 2, h: 2)), - - Box(origin: Point(x: 2, y: 0), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 3, y: 0), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 2, y: 1), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 3, y: 1), size: Size(w: 2, h: 2)), - - Box(origin: Point(x: 0, y: 2), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 1, y: 2), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 0, y: 3), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 1, y: 3), size: Size(w: 2, h: 2)), - - Box(origin: Point(x: 2, y: 2), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 3, y: 2), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 2, y: 3), size: Size(w: 2, h: 2)), - Box(origin: Point(x: 3, y: 3), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 0, y: 0), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 1, y: 0), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 0, y: 1), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 1, y: 1), size: Size(w: 2, h: 2)), +// +// Box(origin: Point(x: 2, y: 0), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 3, y: 0), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 2, y: 1), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 3, y: 1), size: Size(w: 2, h: 2)), +// +// Box(origin: Point(x: 0, y: 2), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 1, y: 2), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 0, y: 3), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 1, y: 3), size: Size(w: 2, h: 2)), +// +// Box(origin: Point(x: 2, y: 2), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 3, y: 2), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 2, y: 3), size: Size(w: 2, h: 2)), +// Box(origin: Point(x: 3, y: 3), size: Size(w: 2, h: 2)), ].reversed() let prog = Progress(totalUnitCount: 1)