From 4715444e6dc7ac76dcedff81c8026e1942654df4 Mon Sep 17 00:00:00 2001 From: Benedikt Schwab Date: Sun, 31 Mar 2024 20:40:43 +0200 Subject: [PATCH] added object remover for OpenDRIVE --- .../rtron/cli/SubcommandOpendriveToCitygml.kt | 4 + .../processor/OpendriveToCitygmlParameters.kt | 8 ++ .../processor/OpendriveToCitygmlProcessor.kt | 19 +++-- .../opendrive/additions/optics/Optics.kt | 6 +- .../remover/OpendriveObjectRemover.kt | 80 +++++++++++++++++++ .../OpendriveObjectRemoverParameters.kt | 34 ++++++++ .../remover/OpendriveObjectRemoverReport.kt | 27 +++++++ 7 files changed, 170 insertions(+), 8 deletions(-) create mode 100644 rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemover.kt create mode 100644 rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemoverParameters.kt create mode 100644 rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemoverReport.kt diff --git a/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandOpendriveToCitygml.kt b/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandOpendriveToCitygml.kt index 6563c406..ffd1cc95 100644 --- a/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandOpendriveToCitygml.kt +++ b/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandOpendriveToCitygml.kt @@ -26,6 +26,7 @@ import com.github.ajalt.clikt.parameters.options.multiple import com.github.ajalt.clikt.parameters.options.option import com.github.ajalt.clikt.parameters.options.pair import com.github.ajalt.clikt.parameters.options.triple +import com.github.ajalt.clikt.parameters.options.unique import com.github.ajalt.clikt.parameters.types.double import com.github.ajalt.clikt.parameters.types.enum import com.github.ajalt.clikt.parameters.types.int @@ -33,6 +34,7 @@ import com.github.ajalt.clikt.parameters.types.path import io.rtron.main.processor.CompressionFormat import io.rtron.main.processor.OpendriveToCitygmlParameters import io.rtron.main.processor.OpendriveToCitygmlProcessor +import io.rtron.model.opendrive.objects.EObjectType import io.rtron.transformer.converter.opendrive2roadspaces.Opendrive2RoadspacesParameters import io.rtron.transformer.converter.roadspaces2citygml.Roadspaces2CitygmlParameters import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters @@ -71,6 +73,7 @@ class SubcommandOpendriveToCitygml : CliktCommand(name = "opendrive-to-citygml", private val addOffset by option(help = "offset values by which the model is translated along the x, y, and z axis").double().triple() .default(Triple(OpendriveOffsetAdderParameters.DEFAULT_OFFSET_X, OpendriveOffsetAdderParameters.DEFAULT_OFFSET_Y, OpendriveOffsetAdderParameters.DEFAULT_OFFSET_Z)) private val cropPolygon by option(help = "2D polygon outline for cropping the OpenDRIVE dataset (experimental)").double().pair().multiple(default = emptyList()) + private val removeRoadObjectOfType by option(help = "Remove road object of a specific type").enum().multiple().unique() private val discretizationStepSize by option(help = "distance between each discretization step for curves and surfaces").double() .default(Roadspaces2CitygmlParameters.DEFAULT_DISCRETIZATION_STEP_SIZE) @@ -104,6 +107,7 @@ class SubcommandOpendriveToCitygml : CliktCommand(name = "opendrive-to-citygml", offsetZ = addOffset.third, cropPolygonX = cropPolygon.map { it.first }, cropPolygonY = cropPolygon.map { it.second }, + removeRoadObjectsOfTypes = removeRoadObjectOfType, discretizationStepSize = discretizationStepSize, sweepDiscretizationStepSize = sweepDiscretizationStepSize, diff --git a/rtron-main/src/main/kotlin/io/rtron/main/processor/OpendriveToCitygmlParameters.kt b/rtron-main/src/main/kotlin/io/rtron/main/processor/OpendriveToCitygmlParameters.kt index 613b55e5..bbcdd821 100644 --- a/rtron-main/src/main/kotlin/io/rtron/main/processor/OpendriveToCitygmlParameters.kt +++ b/rtron-main/src/main/kotlin/io/rtron/main/processor/OpendriveToCitygmlParameters.kt @@ -19,6 +19,7 @@ package io.rtron.main.processor import arrow.core.Either import arrow.core.left import arrow.core.right +import io.rtron.model.opendrive.objects.EObjectType import io.rtron.readerwriter.citygml.CitygmlVersion import io.rtron.transformer.converter.opendrive2roadspaces.Opendrive2RoadspacesParameters import io.rtron.transformer.converter.roadspaces2citygml.Roadspaces2CitygmlParameters @@ -26,6 +27,7 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.evaluator.roadspaces.RoadspacesEvaluatorParameters import io.rtron.transformer.modifiers.opendrive.cropper.OpendriveCropperParameters import io.rtron.transformer.modifiers.opendrive.offset.adder.OpendriveOffsetAdderParameters +import io.rtron.transformer.modifiers.opendrive.remover.OpendriveObjectRemoverParameters import kotlinx.serialization.Serializable @Serializable @@ -46,6 +48,7 @@ data class OpendriveToCitygmlParameters( val offsetZ: Double = OpendriveOffsetAdderParameters.DEFAULT_OFFSET_Z, val cropPolygonX: List = OpendriveCropperParameters.DEFAULT_CROP_POLYGON_X, val cropPolygonY: List = OpendriveCropperParameters.DEFAULT_CROP_POLYGON_Y, + val removeRoadObjectsOfTypes: Set = OpendriveObjectRemoverParameters.DEFAULT_REMOVE_ROAD_OBJECTS_OF_TYPES, val discretizationStepSize: Double = Roadspaces2CitygmlParameters.DEFAULT_DISCRETIZATION_STEP_SIZE, val sweepDiscretizationStepSize: Double = Roadspaces2CitygmlParameters.DEFAULT_SWEEP_DISCRETIZATION_STEP_SIZE, @@ -86,6 +89,11 @@ data class OpendriveToCitygmlParameters( planViewGeometryAngleWarningTolerance = planViewGeometryAngleWarningTolerance ) + fun deriveOpendriveObjectRemoverParameters() = OpendriveObjectRemoverParameters( + removeRoadObjectsWithoutType = OpendriveObjectRemoverParameters.DEFAULT_REMOVE_ROAD_OBJECTS_WITHOUT_TYPE, + removeRoadObjectsOfTypes = removeRoadObjectsOfTypes + ) + fun deriveOpendriveOffsetAdderParameters() = OpendriveOffsetAdderParameters( offsetX = offsetX, offsetY = offsetY, diff --git a/rtron-main/src/main/kotlin/io/rtron/main/processor/OpendriveToCitygmlProcessor.kt b/rtron-main/src/main/kotlin/io/rtron/main/processor/OpendriveToCitygmlProcessor.kt index ab7c902f..56a98c32 100644 --- a/rtron-main/src/main/kotlin/io/rtron/main/processor/OpendriveToCitygmlProcessor.kt +++ b/rtron-main/src/main/kotlin/io/rtron/main/processor/OpendriveToCitygmlProcessor.kt @@ -33,6 +33,7 @@ import io.rtron.transformer.evaluator.roadspaces.RoadspacesEvaluator import io.rtron.transformer.modifiers.opendrive.cropper.OpendriveCropper import io.rtron.transformer.modifiers.opendrive.offset.adder.OpendriveOffsetAdder import io.rtron.transformer.modifiers.opendrive.offset.resolver.OpendriveOffsetResolver +import io.rtron.transformer.modifiers.opendrive.remover.OpendriveObjectRemover import mu.KotlinLogging import java.nio.file.Path import kotlin.io.path.Path @@ -102,13 +103,18 @@ class OpendriveToCitygmlProcessor( return@processAllFiles } - // write offset OpenDRIVE model + // remove objects from OpenDRIVE model + val opendriveObjectRemover = OpendriveObjectRemover(parameters.deriveOpendriveObjectRemoverParameters()) + val opendriveRemovedObjectResult = opendriveObjectRemover.modify(opendriveCropped) + opendriveRemovedObjectResult.second.serializeToJsonFile(outputSubDirectoryPath / OPENDRIVE_OBJECT_REMOVER_REPORT_PATH) + + // write modified OpenDRIVE model val opendriveFilePath = outputSubDirectoryPath / ("opendrive.xodr" + parameters.compressionFormat.toFileExtension()) - OpendriveWriter.writeToFile(opendriveCropped, opendriveFilePath) + OpendriveWriter.writeToFile(opendriveRemovedObjectResult.first, opendriveFilePath) // transform OpenDRIVE model to Roadspaces model val opendrive2RoadspacesTransformer = Opendrive2RoadspacesTransformer(parameters.deriveOpendrive2RoadspacesParameters()) - val roadspacesModelResult = opendrive2RoadspacesTransformer.transform(opendriveCropped) + val roadspacesModelResult = opendrive2RoadspacesTransformer.transform(opendriveRemovedObjectResult.first) roadspacesModelResult.second.serializeToJsonFile(outputSubDirectoryPath / OPENDRIVE_TO_ROADSPACES_REPORT_PATH) val roadspacesModel = roadspacesModelResult.first.handleEmpty { logger.warn("Opendrive2RoadspacesTransformer: ${roadspacesModelResult.second.conversion.getTextSummary()}") @@ -142,8 +148,9 @@ class OpendriveToCitygmlProcessor( val OPENDRIVE_OFFSET_ADDER_REPORT_PATH = REPORTS_PATH / Path("03_opendrive_offset_adder_report.json") val OPENDRIVE_OFFSET_RESOLVER_REPORT_PATH = REPORTS_PATH / Path("04_opendrive_offset_resolver_report.json") val OPENDRIVE_CROP_REPORT_PATH = REPORTS_PATH / Path("05_opendrive_crop_report.json") - val OPENDRIVE_TO_ROADSPACES_REPORT_PATH = REPORTS_PATH / Path("06_opendrive_to_roadspaces_report.json") - val ROADSPACES_EVALUATOR_REPORT_PATH = REPORTS_PATH / Path("07_roadspaces_evaluator_report.json") - val ROADSPACES_TO_CITYGML_REPORT_PATH = REPORTS_PATH / Path("08_roadspaces_to_citygml_report.json") + val OPENDRIVE_OBJECT_REMOVER_REPORT_PATH = REPORTS_PATH / Path("06_opendrive_object_remover_report.json") + val OPENDRIVE_TO_ROADSPACES_REPORT_PATH = REPORTS_PATH / Path("07_opendrive_to_roadspaces_report.json") + val ROADSPACES_EVALUATOR_REPORT_PATH = REPORTS_PATH / Path("08_roadspaces_evaluator_report.json") + val ROADSPACES_TO_CITYGML_REPORT_PATH = REPORTS_PATH / Path("09_roadspaces_to_citygml_report.json") } } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/optics/Optics.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/optics/Optics.kt index eebacd8f..57f31a2e 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/optics/Optics.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/optics/Optics.kt @@ -73,8 +73,10 @@ val everyRoadLanesLaneSectionCenterLane = everyLaneSection compose RoadLanesLane val everyJunction = OpendriveModel.junction compose Traversal.list() val everyJunctionConnection = everyJunction compose Junction.connection compose Traversal.list() -val everyRoadObject = everyRoad compose Road.objects compose PPrism.some() compose RoadObjects.roadObject compose Traversal.list() +val everyRoadObjectContainer = everyRoad compose Road.objects compose PPrism.some() +val everyRoadObject = everyRoadObjectContainer compose RoadObjects.roadObject compose Traversal.list() val everyRoadObjectOutlineElement = everyRoadObject compose RoadObjectsObject.outlines compose PPrism.some() compose RoadObjectsObjectOutlines.outline compose Traversal.list() val everyRoadObjectRepeatElement = everyRoadObject compose RoadObjectsObject.repeat compose Traversal.list() -val everyRoadSignal = everyRoad compose Road.signals compose PPrism.some() compose RoadSignals.signal compose Traversal.list() +val everyRoadSignalContainer = everyRoad compose Road.signals compose PPrism.some() +val everyRoadSignal = everyRoadSignalContainer compose RoadSignals.signal compose Traversal.list() diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemover.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemover.kt new file mode 100644 index 00000000..cea81916 --- /dev/null +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemover.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2019-2024 Chair of Geoinformatics, Technical University of Munich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.rtron.transformer.modifiers.opendrive.remover + +import arrow.core.flattenOption +import io.rtron.model.opendrive.OpendriveModel +import io.rtron.model.opendrive.additions.extensions.updateAdditionalIdentifiers +import io.rtron.model.opendrive.additions.optics.everyRoadObjectContainer +import io.rtron.model.opendrive.objects.EObjectType + +class OpendriveObjectRemover( + val parameters: OpendriveObjectRemoverParameters +) { + fun modify(opendriveModel: OpendriveModel): Pair { + val report = OpendriveObjectRemoverReport(parameters) + var modifiedOpendriveModel = opendriveModel.copy() + modifiedOpendriveModel.updateAdditionalIdentifiers() + + if (parameters.removeRoadObjectsWithoutType) { + modifiedOpendriveModel = everyRoadObjectContainer.modify(modifiedOpendriveModel) { currentRoadObjectContainer -> + val numberOfRoadObjectsBefore = currentRoadObjectContainer.roadObject.count() + + currentRoadObjectContainer.roadObject = currentRoadObjectContainer.roadObject.filter { it.type.isSome() } + + report.numberOfRemovedRoadObjectsWithoutType += + currentRoadObjectContainer.roadObject.count() - numberOfRoadObjectsBefore + + currentRoadObjectContainer + } + } + + if (parameters.removeRoadObjectsOfTypes.isNotEmpty()) { + modifiedOpendriveModel = everyRoadObjectContainer.modify(modifiedOpendriveModel) { currentRoadObjectContainer -> + + val numberOfRoadObjectsBefore: Map = currentRoadObjectContainer.roadObject + .map { it.type } + .flattenOption() + .groupingBy { it } + .eachCount() + + currentRoadObjectContainer.roadObject = currentRoadObjectContainer.roadObject + .filter { currentRoadObject -> + currentRoadObject.type.fold({ true }, { !parameters.removeRoadObjectsOfTypes.contains(it) }) + } + + val roadObjectTypeCountAfter: Map = currentRoadObjectContainer.roadObject + .map { it.type } + .flattenOption() + .groupingBy { it } + .eachCount() + + numberOfRoadObjectsBefore + .map { it.key to it.value - roadObjectTypeCountAfter.getOrDefault(it.key, 0) } + .filter { it.second != 0 } + .forEach { + report.numberOfRemovedRoadObjectsWithType[it.first] = + report.numberOfRemovedRoadObjectsWithType.getOrDefault(it.first, 0) + it.second + } + + currentRoadObjectContainer + } + } + + return modifiedOpendriveModel to report + } +} diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemoverParameters.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemoverParameters.kt new file mode 100644 index 00000000..ad1ee555 --- /dev/null +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemoverParameters.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2019-2024 Chair of Geoinformatics, Technical University of Munich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.rtron.transformer.modifiers.opendrive.remover + +import io.rtron.model.opendrive.objects.EObjectType +import kotlinx.serialization.Serializable + +@Serializable +data class OpendriveObjectRemoverParameters( + /** remove road objects without type */ + val removeRoadObjectsWithoutType: Boolean, + /** remove road objects of type */ + val removeRoadObjectsOfTypes: Set +) { + + companion object { + val DEFAULT_REMOVE_ROAD_OBJECTS_WITHOUT_TYPE = false + val DEFAULT_REMOVE_ROAD_OBJECTS_OF_TYPES = emptySet() + } +} diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemoverReport.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemoverReport.kt new file mode 100644 index 00000000..8358cd99 --- /dev/null +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/remover/OpendriveObjectRemoverReport.kt @@ -0,0 +1,27 @@ +/* + * Copyright 2019-2024 Chair of Geoinformatics, Technical University of Munich + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.rtron.transformer.modifiers.opendrive.remover + +import io.rtron.model.opendrive.objects.EObjectType +import kotlinx.serialization.Serializable + +@Serializable +data class OpendriveObjectRemoverReport( + val parameters: OpendriveObjectRemoverParameters, + var numberOfRemovedRoadObjectsWithoutType: Int = 0, + val numberOfRemovedRoadObjectsWithType: MutableMap = mutableMapOf() +)