Skip to content

Commit 13b7d95

Browse files
committed
Add GeoPackage file for buffered failed stop-to-stop segments.
1 parent 9274d87 commit 13b7d95

File tree

6 files changed

+80
-25
lines changed

6 files changed

+80
-25
lines changed

profiles/dev/config.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,5 +39,5 @@ digitransit.subscription.key=
3939
# the CSV file.
4040
test.routes.csvfile=
4141

42-
# The output directory to which the resulting GeoJSON file is written.
42+
# The output directory to which the resulting GeoJSON and GeoPackage files are written.
4343
test.output.dir=

profiles/prod/config.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,5 @@ digitransit.subscription.key=
3131
# the CSV file.
3232
test.routes.csvfile=
3333

34-
# The output directory to which the resulting GeoJSON file is written.
34+
# The output directory to which the resulting GeoJSON and GeoPackage files are written.
3535
test.output.dir=

src/main/kotlin/fi/hsl/jore4/mapmatching/service/matching/test/GeoPackageUtils.kt

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,47 @@
11
package fi.hsl.jore4.mapmatching.service.matching.test
22

3+
import fi.hsl.jore4.mapmatching.util.GeoToolsUtils.transformCRS
34
import org.geolatte.geom.jts.JTS
45
import org.geotools.api.feature.simple.SimpleFeature
56
import org.geotools.api.feature.simple.SimpleFeatureType
67
import org.geotools.data.collection.ListFeatureCollection
78
import org.geotools.feature.simple.SimpleFeatureBuilder
89
import org.geotools.feature.simple.SimpleFeatureTypeBuilder
10+
import org.geotools.geometry.jts.Geometries
911
import org.geotools.geopkg.FeatureEntry
1012
import org.geotools.geopkg.GeoPackage
1113
import org.geotools.referencing.crs.DefaultGeographicCRS
14+
import org.locationtech.jts.geom.Geometry
1215
import org.locationtech.jts.geom.LineString
1316
import java.io.File
1417

1518
object GeoPackageUtils {
19+
private const val GEOMETRY_COLUMN_NAME = "geometry"
20+
1621
fun createGeoPackage(
1722
file: File,
18-
failedSegments: List<SegmentMatchFailure>
23+
failedSegments: List<SegmentMatchFailure>,
24+
isBufferPolygonInsteadOfLineString: Boolean
1925
): GeoPackage {
2026
val geoPkg = GeoPackage(file)
2127
geoPkg.init()
2228

2329
try {
2430
failedSegments.forEach { segment ->
2531
val featureTypeName: String = segment.routeId
26-
val featureType: SimpleFeatureType = createFeatureTypeForFailedSegment(featureTypeName)
32+
val featureType: SimpleFeatureType =
33+
createFeatureTypeForFailedSegment(featureTypeName, isBufferPolygonInsteadOfLineString)
2734

2835
val entry = FeatureEntry()
2936
entry.identifier = segment.routeId
30-
entry.description = "Failed segment within map-matching"
37+
entry.description =
38+
if (isBufferPolygonInsteadOfLineString) {
39+
"Buffered geometry for failed ${segment.routeId} segment within map-matching"
40+
} else {
41+
"LineString for failed ${segment.routeId} segment within map-matching"
42+
}
3143

32-
geoPkg.add(entry, createFeatureCollection(segment, featureType))
44+
geoPkg.add(entry, createFeatureCollection(segment, featureType, isBufferPolygonInsteadOfLineString))
3345

3446
// Not sure, if this is really needed.
3547
geoPkg.createSpatialIndex(entry)
@@ -42,12 +54,16 @@ object GeoPackageUtils {
4254
}
4355
}
4456

45-
private fun createFeatureTypeForFailedSegment(name: String): SimpleFeatureType {
57+
private fun createFeatureTypeForFailedSegment(
58+
name: String,
59+
isBufferPolygonInsteadOfLineString: Boolean
60+
): SimpleFeatureType {
4661
val builder = SimpleFeatureTypeBuilder()
4762
builder.name = name
48-
builder.crs = DefaultGeographicCRS.WGS84
4963

50-
builder.add("geometry", LineString::class.java)
64+
val geomType = if (isBufferPolygonInsteadOfLineString) Geometries.POLYGON else Geometries.LINESTRING
65+
66+
builder.add(GEOMETRY_COLUMN_NAME, geomType.binding, DefaultGeographicCRS.WGS84)
5167
builder.add("length", Double::class.java)
5268
builder.add("startStopId", String::class.java)
5369
builder.add("endStopId", String::class.java)
@@ -61,23 +77,34 @@ object GeoPackageUtils {
6177

6278
private fun createFeatureCollection(
6379
failedSegment: SegmentMatchFailure,
64-
featureType: SimpleFeatureType
80+
featureType: SimpleFeatureType,
81+
isBufferPolygonInsteadOfLineString: Boolean
6582
): ListFeatureCollection {
66-
val feature: SimpleFeature = createFeature(failedSegment, featureType)
83+
val feature: SimpleFeature = createFeature(failedSegment, featureType, isBufferPolygonInsteadOfLineString)
6784

6885
return ListFeatureCollection(featureType, feature)
6986
}
7087

7188
private fun createFeature(
7289
failedSegment: SegmentMatchFailure,
73-
type: SimpleFeatureType
90+
type: SimpleFeatureType,
91+
isBufferPolygonInsteadOfLineString: Boolean
7492
): SimpleFeature {
7593
val builder = SimpleFeatureBuilder(type)
7694

7795
failedSegment.run {
7896
val lineString: LineString = JTS.to(sourceRouteGeometry)
7997

80-
builder.add(lineString)
98+
if (isBufferPolygonInsteadOfLineString) {
99+
val lineString3067: Geometry = transformCRS(lineString, 4326, 3067)
100+
val bufferPolygon3067: Geometry = lineString3067.buffer(bufferRadius.value)
101+
val bufferPolygon: Geometry = transformCRS(bufferPolygon3067, 3067, 4326)
102+
103+
builder.add(bufferPolygon)
104+
} else {
105+
builder.add(lineString)
106+
}
107+
81108
builder.add(sourceRouteLength)
82109
builder.add(startStopId)
83110
builder.add(endStopId)

src/main/kotlin/fi/hsl/jore4/mapmatching/service/matching/test/MapMatchingBulkTestResultsPublisherImpl.kt

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class MapMatchingBulkTestResultsPublisherImpl(
7474
"Worst $limit successful route matches: $worstResults"
7575
}
7676

77-
val outputFile: File = writeGeoJsonToFile(getFailedRoutesAsGeoJson(failed), "failed_routes.geojson")
77+
val outputFile: File = writeGeoJsonToFile(getFailedRoutesAsGeoJson(failed), FILENAME_FAILED_ROUTES_GEOJSON)
7878
LOGGER.info { "Wrote failed routes to file: ${outputFile.absolutePath}" }
7979
}
8080

@@ -109,11 +109,29 @@ class MapMatchingBulkTestResultsPublisherImpl(
109109
"Worst $limit successful stop-to-stop segment matches: $worstResults"
110110
}
111111

112-
val outputFile: File =
113-
writeGeoJsonToFile(getFailedSegmentsAsGeoJson(failed), "failed_stop-to-stop_segments.geojson")
114-
LOGGER.info { "Wrote failed stop-to-stop segments to file: ${outputFile.absolutePath}" }
112+
val geojsonFile: File =
113+
writeGeoJsonToFile(getFailedSegmentsAsGeoJson(failed), FILENAME_FAILED_SEGMENTS_GEOJSON)
114+
LOGGER.info { "Wrote failed stop-to-stop segments to GeoJSON file: ${geojsonFile.absolutePath}" }
115115

116-
createGeoPackage(failed)
116+
val failedSegmentsGeoPackageFile = File(outputDir, FILENAME_FAILED_SEGMENTS_GPKG)
117+
failedSegmentsGeoPackageFile.delete()
118+
GeoPackageUtils.createGeoPackage(failedSegmentsGeoPackageFile, failed, false)
119+
120+
LOGGER.info {
121+
"Wrote failed stop-to-stop segments to GeoPackage file: ${
122+
failedSegmentsGeoPackageFile.absolutePath
123+
}"
124+
}
125+
126+
val failureBuffersGeoPackageFile = File(outputDir, FILENAME_FAILED_SEGMENT_BUFFERS_GPKG)
127+
failureBuffersGeoPackageFile.delete()
128+
GeoPackageUtils.createGeoPackage(failureBuffersGeoPackageFile, failed, true)
129+
130+
LOGGER.info {
131+
"Wrote failed stop-to-stop segment buffers to GeoPackage file: ${
132+
failureBuffersGeoPackageFile.absolutePath
133+
}"
134+
}
117135
}
118136

119137
private fun writeGeoJsonToFile(
@@ -128,6 +146,12 @@ class MapMatchingBulkTestResultsPublisherImpl(
128146
}
129147

130148
companion object {
149+
private const val FILENAME_FAILED_ROUTES_GEOJSON = "failed_routes.geojson"
150+
private const val FILENAME_FAILED_SEGMENTS_GEOJSON = "failed_segments.geojson"
151+
152+
private const val FILENAME_FAILED_SEGMENTS_GPKG = "failed_segments.gpkg"
153+
private const val FILENAME_FAILED_SEGMENT_BUFFERS_GPKG = "failed_segment_buffers.gpkg"
154+
131155
private fun partitionBySuccess(
132156
results: List<MatchResult>
133157
): Pair<List<SuccessfulRouteMatchResult>, List<RouteMatchFailure>> {
@@ -340,10 +364,5 @@ class MapMatchingBulkTestResultsPublisherImpl(
340364
}
341365
}
342366
}
343-
344-
private fun createGeoPackage(matchResults: List<SegmentMatchFailure>) {
345-
val file = File.createTempFile("geopkg", "db", File("target"))
346-
GeoPackageUtils.createGeoPackage(file, matchResults)
347-
}
348367
}
349368
}

src/main/kotlin/fi/hsl/jore4/mapmatching/service/matching/test/MapMatchingBulkTester.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ class MapMatchingBulkTester(
129129
segmentId,
130130
geometry,
131131
result.sourceRouteLength,
132+
result.bufferRadius,
132133
segment.startStopId,
133134
segment.endStopId,
134135
numRoutePoints,
@@ -178,7 +179,13 @@ class MapMatchingBulkTester(
178179
}
179180

180181
return when (lengthsOfMatchedRoutes.size) {
181-
0 -> RouteMatchFailure(routeId, geometry, lengthOfSourceRoute)
182+
0 ->
183+
RouteMatchFailure(
184+
routeId,
185+
geometry,
186+
lengthOfSourceRoute,
187+
BufferRadius(sortedBufferRadiuses.last())
188+
)
182189
else ->
183190
SuccessfulRouteMatchResult(
184191
routeId,

src/main/kotlin/fi/hsl/jore4/mapmatching/service/matching/test/MatchResult.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ data class SuccessfulRouteMatchResult(
9191
data class RouteMatchFailure(
9292
override val routeId: String,
9393
override val sourceRouteGeometry: LineString<G2D>,
94-
override val sourceRouteLength: Double
94+
override val sourceRouteLength: Double,
95+
val bufferRadius: BufferRadius
9596
) : MatchResult {
9697
override val matchFound = false
9798
}
@@ -114,6 +115,7 @@ data class SegmentMatchFailure(
114115
override val routeId: String,
115116
override val sourceRouteGeometry: LineString<G2D>,
116117
override val sourceRouteLength: Double,
118+
val bufferRadius: BufferRadius,
117119
override val startStopId: String,
118120
override val endStopId: String,
119121
override val numberOfRoutePoints: Int,

0 commit comments

Comments
 (0)