Skip to content

Commit ed11992

Browse files
authored
RTree spatial index (#283)
1 parent 3f9d7e6 commit ed11992

File tree

7 files changed

+1301
-2
lines changed

7 files changed

+1301
-2
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ jobs:
3939
name: Generate coverage summary
4040
run: |
4141
echo '## Coverage' >> $GITHUB_STEP_SUMMARY
42-
./gradlew -q :koverLog >> $GITHUB_STEP_SUMMARY
42+
./gradlew -q :koverLog | tee $GITHUB_STEP_SUMMARY
4343
4444
benchmark:
4545
runs-on: ubuntu-latest
@@ -56,7 +56,7 @@ jobs:
5656
- name: Run benchmark
5757
run: |
5858
echo '## Benchmark' >> $GITHUB_STEP_SUMMARY
59-
./gradlew -q benchmark -PbenchmarkIterations=1 >> $GITHUB_STEP_SUMMARY
59+
./gradlew -q benchmark -PbenchmarkWarmups=1 -PbenchmarkIterations=1 | tee $GITHUB_STEP_SUMMARY
6060
6161
build-docs:
6262
runs-on: ubuntu-latest

benchmark/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ benchmark {
2424
configurations {
2525
named("main") {
2626
iterations = project.findProperty("benchmarkIterations")?.toString()?.toInt() ?: 5
27+
warmups = project.findProperty("benchmarkWarmups")?.toString()?.toInt() ?: 5
2728
}
2829
}
2930

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package org.maplibre.spatialk.turf
2+
3+
import kotlin.random.Random
4+
import kotlinx.benchmark.Benchmark
5+
import kotlinx.benchmark.BenchmarkMode
6+
import kotlinx.benchmark.BenchmarkTimeUnit
7+
import kotlinx.benchmark.Mode
8+
import kotlinx.benchmark.OutputTimeUnit
9+
import kotlinx.benchmark.Scope
10+
import kotlinx.benchmark.Setup
11+
import kotlinx.benchmark.State
12+
import kotlinx.serialization.json.JsonObject
13+
import org.maplibre.spatialk.geojson.BoundingBox
14+
import org.maplibre.spatialk.geojson.Feature
15+
import org.maplibre.spatialk.geojson.FeatureCollection
16+
import org.maplibre.spatialk.geojson.Geometry
17+
import org.maplibre.spatialk.geojson.Point
18+
import org.maplibre.spatialk.geojson.Position
19+
import org.maplibre.spatialk.geojson.dsl.addFeature
20+
import org.maplibre.spatialk.geojson.dsl.buildFeatureCollection
21+
import org.maplibre.spatialk.turf.other.RTree
22+
23+
@State(Scope.Benchmark)
24+
@BenchmarkMode(Mode.AverageTime)
25+
@OutputTimeUnit(BenchmarkTimeUnit.MILLISECONDS)
26+
open class RTreeBenchmark {
27+
private lateinit var featureCollection: FeatureCollection<Geometry?, JsonObject?>
28+
private lateinit var rtree16: RTree<Feature<Geometry?, JsonObject?>>
29+
private lateinit var rtree128: RTree<Feature<Geometry?, JsonObject?>>
30+
31+
private val random = Random(0)
32+
33+
private fun generateDataset() = buildFeatureCollection {
34+
repeat(100000) {
35+
addFeature(
36+
geometry =
37+
Point(
38+
longitude = random.nextDouble(360.0) - 180,
39+
latitude = random.nextDouble(180.0) - 90,
40+
)
41+
) {
42+
properties = null
43+
}
44+
}
45+
}
46+
47+
@Setup
48+
fun setup() {
49+
featureCollection = generateDataset()
50+
rtree16 = RTree(featureCollection.features, 16)
51+
rtree128 = RTree(featureCollection.features, 128)
52+
}
53+
54+
@Benchmark
55+
fun insertion128() {
56+
val rtree = RTree(featureCollection.features, 128)
57+
require(rtree.size == featureCollection.features.size)
58+
}
59+
60+
@Benchmark
61+
fun insertion16() {
62+
val rtree = RTree(featureCollection.features, 16)
63+
require(rtree.size == featureCollection.features.size)
64+
}
65+
66+
@Benchmark
67+
fun search128() {
68+
val result = rtree128.search(BoundingBox(Position(10.0, 10.0), Position(20.0, 20.0)))
69+
require(result.size == 149) { "Wrong number of results (${result.size})" }
70+
}
71+
72+
@Benchmark
73+
fun search16() {
74+
val result = rtree16.search(BoundingBox(Position(10.0, 10.0), Position(20.0, 20.0)))
75+
require(result.size == 149) { "Wrong number of results (${result.size})" }
76+
}
77+
}

turf/api/turf.api

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,34 @@ public final class org/maplibre/spatialk/turf/misc/NearestPointProps$Companion {
205205
public final fun serializer ()Lkotlinx/serialization/KSerializer;
206206
}
207207

208+
public final class org/maplibre/spatialk/turf/other/RTree : java/util/Collection, kotlin/jvm/internal/markers/KMappedMarker {
209+
public fun <init> ()V
210+
public fun <init> (Ljava/util/List;I)V
211+
public synthetic fun <init> (Ljava/util/List;IILkotlin/jvm/internal/DefaultConstructorMarker;)V
212+
public synthetic fun add (Ljava/lang/Object;)Z
213+
public fun add (Lorg/maplibre/spatialk/geojson/GeoJsonObject;)Z
214+
public fun addAll (Ljava/util/Collection;)Z
215+
public final fun clear ()V
216+
public final fun collides (Lorg/maplibre/spatialk/geojson/BoundingBox;)Z
217+
public final fun contains (Ljava/lang/Object;)Z
218+
public fun contains (Lorg/maplibre/spatialk/geojson/GeoJsonObject;)Z
219+
public fun containsAll (Ljava/util/Collection;)Z
220+
public fun getSize ()I
221+
public final fun insert (Ljava/util/List;)V
222+
public final fun insert (Lorg/maplibre/spatialk/geojson/GeoJsonObject;)V
223+
public fun isEmpty ()Z
224+
public fun iterator ()Ljava/util/Iterator;
225+
public final fun remove (Ljava/lang/Object;)Z
226+
public final fun remove (Lorg/maplibre/spatialk/geojson/GeoJsonObject;)Z
227+
public fun removeAll (Ljava/util/Collection;)Z
228+
public fun removeIf (Ljava/util/function/Predicate;)Z
229+
public fun retainAll (Ljava/util/Collection;)Z
230+
public final fun search (Lorg/maplibre/spatialk/geojson/BoundingBox;)Ljava/util/List;
231+
public final fun size ()I
232+
public fun toArray ()[Ljava/lang/Object;
233+
public fun toArray ([Ljava/lang/Object;)[Ljava/lang/Object;
234+
}
235+
208236
public final class org/maplibre/spatialk/turf/transformation/Transformation {
209237
public static final fun bezierSpline (Lorg/maplibre/spatialk/geojson/LineString;ID)Lorg/maplibre/spatialk/geojson/LineString;
210238
public static synthetic fun bezierSpline$default (Lorg/maplibre/spatialk/geojson/LineString;IDILjava/lang/Object;)Lorg/maplibre/spatialk/geojson/LineString;

turf/api/turf.klib.api

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,24 @@
66
// - Show declarations: true
77

88
// Library unique name: <org.maplibre.spatialk:turf>
9+
final class <#A: org.maplibre.spatialk.geojson/GeoJsonObject> org.maplibre.spatialk.turf.other/RTree : kotlin.collections/Collection<#A> { // org.maplibre.spatialk.turf.other/RTree|null[0]
10+
constructor <init>(kotlin.collections/List<#A> = ..., kotlin/Int = ...) // org.maplibre.spatialk.turf.other/RTree.<init>|<init>(kotlin.collections.List<1:0>;kotlin.Int){}[0]
11+
12+
final val size // org.maplibre.spatialk.turf.other/RTree.size|{}size[0]
13+
final fun <get-size>(): kotlin/Int // org.maplibre.spatialk.turf.other/RTree.size.<get-size>|<get-size>(){}[0]
14+
15+
final fun clear() // org.maplibre.spatialk.turf.other/RTree.clear|clear(){}[0]
16+
final fun collides(org.maplibre.spatialk.geojson/BoundingBox): kotlin/Boolean // org.maplibre.spatialk.turf.other/RTree.collides|collides(org.maplibre.spatialk.geojson.BoundingBox){}[0]
17+
final fun contains(#A): kotlin/Boolean // org.maplibre.spatialk.turf.other/RTree.contains|contains(1:0){}[0]
18+
final fun containsAll(kotlin.collections/Collection<#A>): kotlin/Boolean // org.maplibre.spatialk.turf.other/RTree.containsAll|containsAll(kotlin.collections.Collection<1:0>){}[0]
19+
final fun insert(#A) // org.maplibre.spatialk.turf.other/RTree.insert|insert(1:0){}[0]
20+
final fun insert(kotlin.collections/List<#A>) // org.maplibre.spatialk.turf.other/RTree.insert|insert(kotlin.collections.List<1:0>){}[0]
21+
final fun isEmpty(): kotlin/Boolean // org.maplibre.spatialk.turf.other/RTree.isEmpty|isEmpty(){}[0]
22+
final fun iterator(): kotlin.collections/Iterator<#A> // org.maplibre.spatialk.turf.other/RTree.iterator|iterator(){}[0]
23+
final fun remove(#A): kotlin/Boolean // org.maplibre.spatialk.turf.other/RTree.remove|remove(1:0){}[0]
24+
final fun search(org.maplibre.spatialk.geojson/BoundingBox): kotlin.collections/List<#A> // org.maplibre.spatialk.turf.other/RTree.search|search(org.maplibre.spatialk.geojson.BoundingBox){}[0]
25+
}
26+
927
final class org.maplibre.spatialk.turf.misc/NearestPointOnLineProps { // org.maplibre.spatialk.turf.misc/NearestPointOnLineProps|null[0]
1028
final val distance // org.maplibre.spatialk.turf.misc/NearestPointOnLineProps.distance|{}distance[0]
1129
final fun <get-distance>(): org.maplibre.spatialk.units/Length // org.maplibre.spatialk.turf.misc/NearestPointOnLineProps.distance.<get-distance>|<get-distance>(){}[0]

0 commit comments

Comments
 (0)