Skip to content

Commit

Permalink
Grids - rectangle grid (#121)
Browse files Browse the repository at this point in the history
* Ported turf grids squareGrid function

* Apply suggestions from code review

* Fixed MaxLineLength detect issue

---------

Co-authored-by: Derek Ellis <[email protected]>
  • Loading branch information
P72B and dellisd authored Feb 16, 2024
1 parent 4c738e1 commit e3fedb4
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.github.dellisd.spatialk.turf

import io.github.dellisd.spatialk.geojson.BoundingBox
import io.github.dellisd.spatialk.geojson.Feature
import io.github.dellisd.spatialk.geojson.FeatureCollection
import io.github.dellisd.spatialk.geojson.Polygon
import io.github.dellisd.spatialk.geojson.Position
import kotlin.math.abs
import kotlin.math.floor

/**
* Creates a rectangle grid within a [BoundingBox].
*
* @param [BoundingBox] bbox extent
* @param double cellWidth of each cell, in units
* @param double cellHeight of each cell, in units
* @param units The unit of measurement of the cellSide length
* @returns [FeatureCollection] a grid of polygons
*/
@ExperimentalTurfApi
fun rectangleGrid(
bbox: BoundingBox,
cellWidth: Double,
cellHeight: Double,
units: Units = Units.Kilometers
): FeatureCollection {
val featureList = mutableListOf<Feature>()
val west = bbox.southwest.longitude
val south = bbox.southwest.latitude
val east = bbox.northeast.longitude
val north = bbox.northeast.latitude

val bboxWidth = east - west
val cellWidthDeg = convertLength(cellWidth, units, Units.Degrees)

val bboxHeight = north - south;
val cellHeightDeg = convertLength(cellHeight, units, Units.Degrees);

val columns = floor(abs(bboxWidth) / cellWidthDeg)
val rows = floor(abs(bboxHeight) / cellHeightDeg)

val deltaX = (bboxWidth - columns * cellWidthDeg) / 2
val deltaY = (bboxHeight - rows * cellHeightDeg) / 2

var currentX = west + deltaX
repeat (columns.toInt()) {
var currentY = south + deltaY
repeat (rows.toInt()) {
val positions = mutableListOf<Position>().apply {
add(Position(currentX, currentY))
add(Position(currentX, currentY + cellHeightDeg))
add(Position(currentX + cellWidthDeg, currentY + cellHeightDeg))
add(Position(currentX + cellWidthDeg, currentY))
add(Position(currentX, currentY))
}
mutableListOf<List<Position>>().apply {
add(positions)
}.also {
featureList.add(Feature(Polygon(it)))
}
currentY += cellHeightDeg;
}
currentX += cellWidthDeg;
}
return FeatureCollection(featureList)
}
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ fun bbox(feature: Feature): BoundingBox = computeBbox(feature.coordAll() ?: empt
fun bbox(featureCollection: FeatureCollection): BoundingBox = computeBbox(featureCollection.coordAll())

@Suppress("MagicNumber")
private fun computeBbox(coordinates: List<Position>): BoundingBox {
fun computeBbox(coordinates: List<Position>): BoundingBox {
val result = doubleArrayOf(
Double.POSITIVE_INFINITY,
Double.POSITIVE_INFINITY,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package io.github.dellisd.spatialk.turf

import io.github.dellisd.spatialk.geojson.BoundingBox
import io.github.dellisd.spatialk.geojson.FeatureCollection
import io.github.dellisd.spatialk.geojson.Polygon
import io.github.dellisd.spatialk.geojson.Position
import io.github.dellisd.spatialk.turf.utils.readResource
import kotlin.test.BeforeTest
import kotlin.test.Test
import kotlin.test.assertEquals

class GridsTest {

private lateinit var box: BoundingBox

@BeforeTest
fun before() {
Polygon.fromJson(readResource("grids/bbox.json")).also {
box = computeBbox(it.coordinates[0])
}
}
@OptIn(ExperimentalTurfApi::class)
@Test
fun testRectangleGrid() {
rectangleGrid(bbox = box, cellWidth = 200.0, cellHeight = 200.0, units = Units.Meters).also {
verifyValidGrid(it)
}
}

@OptIn(ExperimentalTurfApi::class)
@Test
fun testRectangleGridSameCellSizeButDifferentUnitWillHaveSameResult() {
rectangleGrid(bbox = box, cellWidth = 0.2, cellHeight = 0.2, units = Units.Kilometers).also {
verifyValidGrid(it)
}
}

@OptIn(ExperimentalTurfApi::class)
@Test
fun defaultUnitsValueIsKilometers() {
rectangleGrid(bbox = box, cellWidth = 0.2, cellHeight = 0.2).also {
verifyValidGrid(it)
}
}

@OptIn(ExperimentalTurfApi::class)
private fun verifyValidGrid(grid: FeatureCollection) {
assertEquals(16, grid.features.size)
val expectedFistItem = mutableListOf(
Position(13.170147683370761, 52.515969323342695),
Position(13.170147683370761, 52.517765865),
Position(13.17194422502807, 52.517765865),
Position(13.17194422502807, 52.515969323342695),
Position(13.170147683370761, 52.515969323342695))
assertEquals(expectedFistItem, grid.features.first().geometry!!.coordAll())
val expectedLastItem = mutableListOf(
Position(13.18272347497193, 52.517765865),
Position(13.18272347497193, 52.51956240665731),
Position(13.18452001662924, 52.51956240665731),
Position(13.18452001662924, 52.517765865),
Position(13.18272347497193, 52.517765865))
assertEquals(expectedLastItem, grid.features.last().geometry!!.coordAll())
}

@OptIn(ExperimentalTurfApi::class)
@Test
fun cellSizeBiggerThanBboxExtendLeadIntoEmptyGrid() {
rectangleGrid(bbox = box, cellWidth = 2000.0, cellHeight = 2000.0, units = Units.Meters).also {
assertEquals(0, it.features.size)
}
}

@OptIn(ExperimentalTurfApi::class)
@Test
fun smallerCellSizeWillOutputMoreCellsInGrid() {
rectangleGrid(bbox = box, cellWidth = 0.1, cellHeight = 0.1).also {
assertEquals(85, it.features.size)
}
}

@OptIn(ExperimentalTurfApi::class)
@Test
fun increasedCellSizeWillOutputLessCellsInGrid() {
rectangleGrid(bbox = box, cellWidth = 0.3, cellHeight = 0.3).also {
assertEquals(5, it.features.size)
}
}
}
33 changes: 33 additions & 0 deletions turf/src/commonTest/resources/grids/bbox.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"type": "Polygon",
"coordinates": [
[
[
13.16949919,
52.51513922
],
[
13.16949919,
52.52039251
],
[
13.18516851,
52.52039251
],
[
13.18516851,
52.51513922
],
[
13.16949919,
52.51513922
]
]
],
"crs": {
"type": "name",
"properties": {
"name": "EPSG:3857"
}
}
}

0 comments on commit e3fedb4

Please sign in to comment.