Skip to content

Commit b971e84

Browse files
committed
Fix writing failed segments.
Let's make a fixed version of the `GeoPackage.add()` method, which originally worked, but at some point broke when the GeoTools libraries were updated. The current version of the method throws a `NullPointException` exception for a missing `fid` property. Debugging the `gt-geopkg` library has revealed that it probably has a bug. The fact that the documentation is notoriously incomplete has not helped in solving the problem.
1 parent 539043b commit b971e84

File tree

1 file changed

+57
-3
lines changed

1 file changed

+57
-3
lines changed

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

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@ package fi.hsl.jore4.mapmatching.service.matching.test
22

33
import fi.hsl.jore4.mapmatching.util.GeoToolsUtils.transformCRS
44
import org.geolatte.geom.jts.JTS
5+
import org.geotools.api.data.SimpleFeatureWriter
6+
import org.geotools.api.data.Transaction
57
import org.geotools.api.feature.simple.SimpleFeature
68
import org.geotools.api.feature.simple.SimpleFeatureType
9+
import org.geotools.data.DefaultTransaction
710
import org.geotools.data.collection.ListFeatureCollection
11+
import org.geotools.data.simple.SimpleFeatureIterator
812
import org.geotools.feature.simple.SimpleFeatureBuilder
913
import org.geotools.feature.simple.SimpleFeatureTypeBuilder
1014
import org.geotools.geometry.jts.Geometries
@@ -14,6 +18,7 @@ import org.geotools.referencing.crs.DefaultGeographicCRS
1418
import org.locationtech.jts.geom.Geometry
1519
import org.locationtech.jts.geom.LineString
1620
import java.io.File
21+
import java.io.IOException
1722

1823
object GeoPackageUtils {
1924
private const val GEOMETRY_COLUMN_NAME = "geometry"
@@ -32,16 +37,24 @@ object GeoPackageUtils {
3237
val featureType: SimpleFeatureType =
3338
createFeatureTypeForFailedSegment(featureTypeName, isBufferPolygonInsteadOfLineString)
3439

40+
val featureCollection: ListFeatureCollection =
41+
createFeatureCollection(segment, featureType, isBufferPolygonInsteadOfLineString)
42+
3543
val entry = FeatureEntry()
36-
entry.identifier = segment.routeId
44+
// entry.identifier = segment.routeId
45+
entry.geometryColumn = GEOMETRY_COLUMN_NAME
46+
entry.geometryType =
47+
if (isBufferPolygonInsteadOfLineString) Geometries.POLYGON else Geometries.LINESTRING
48+
entry.bounds = featureCollection.bounds
49+
3750
entry.description =
3851
if (isBufferPolygonInsteadOfLineString) {
3952
"Buffered geometry for failed ${segment.routeId} segment within map-matching"
4053
} else {
4154
"LineString for failed ${segment.routeId} segment within map-matching"
4255
}
4356

44-
geoPkg.add(entry, createFeatureCollection(segment, featureType, isBufferPolygonInsteadOfLineString))
57+
writeEntryToGeoPackage(geoPkg, entry, featureCollection)
4558

4659
// Not sure, if this is really needed.
4760
geoPkg.createSpatialIndex(entry)
@@ -114,6 +127,47 @@ object GeoPackageUtils {
114127
builder.add(referencingRoutes.joinToString(separator = " "))
115128
}
116129

117-
return builder.buildFeature(failedSegment.routeId)
130+
// This works because every feature is put into a separate table.
131+
builder.featureUserData("fid", "1")
132+
133+
return builder.buildFeature(null)
134+
}
135+
136+
private fun writeEntryToGeoPackage(
137+
geoPkg: GeoPackage,
138+
entry: FeatureEntry,
139+
featureCollection: ListFeatureCollection
140+
) {
141+
// Create an SQLite table for FeatureCollection.
142+
geoPkg.create(entry, featureCollection.schema)
143+
144+
val tx: Transaction = DefaultTransaction()
145+
val it: SimpleFeatureIterator = featureCollection.features()
146+
147+
try {
148+
val writer: SimpleFeatureWriter = geoPkg.writer(entry, true, null, tx)
149+
150+
val source = it.next()
151+
val target: SimpleFeature = writer.next()
152+
153+
target.attributes = source.attributes
154+
155+
// This if-block is the missing piece not done in the GeoPackage.add() method.
156+
if (source.hasUserData()) {
157+
target.userData.putAll(source.userData)
158+
}
159+
160+
writer.write()
161+
writer.close()
162+
163+
tx.commit()
164+
} catch (ex: Exception) {
165+
tx.rollback()
166+
167+
throw ex as? IOException ?: IOException(ex)
168+
} finally {
169+
tx.close()
170+
it.close()
171+
}
118172
}
119173
}

0 commit comments

Comments
 (0)