Skip to content

Commit

Permalink
added object remover for OpenDRIVE
Browse files Browse the repository at this point in the history
  • Loading branch information
benediktschwab committed Mar 31, 2024
1 parent 2df02e1 commit 4715444
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,15 @@ 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
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
Expand Down Expand Up @@ -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<EObjectType>().multiple().unique()

private val discretizationStepSize by option(help = "distance between each discretization step for curves and surfaces").double()
.default(Roadspaces2CitygmlParameters.DEFAULT_DISCRETIZATION_STEP_SIZE)
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ 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
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
Expand All @@ -46,6 +48,7 @@ data class OpendriveToCitygmlParameters(
val offsetZ: Double = OpendriveOffsetAdderParameters.DEFAULT_OFFSET_Z,
val cropPolygonX: List<Double> = OpendriveCropperParameters.DEFAULT_CROP_POLYGON_X,
val cropPolygonY: List<Double> = OpendriveCropperParameters.DEFAULT_CROP_POLYGON_Y,
val removeRoadObjectsOfTypes: Set<EObjectType> = OpendriveObjectRemoverParameters.DEFAULT_REMOVE_ROAD_OBJECTS_OF_TYPES,

val discretizationStepSize: Double = Roadspaces2CitygmlParameters.DEFAULT_DISCRETIZATION_STEP_SIZE,
val sweepDiscretizationStepSize: Double = Roadspaces2CitygmlParameters.DEFAULT_SWEEP_DISCRETIZATION_STEP_SIZE,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()}")
Expand Down Expand Up @@ -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")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Original file line number Diff line number Diff line change
@@ -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<OpendriveModel, OpendriveObjectRemoverReport> {
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<EObjectType, Int> = 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<EObjectType, Int> = 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
}
}
Original file line number Diff line number Diff line change
@@ -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<EObjectType>
) {

companion object {
val DEFAULT_REMOVE_ROAD_OBJECTS_WITHOUT_TYPE = false
val DEFAULT_REMOVE_ROAD_OBJECTS_OF_TYPES = emptySet<EObjectType>()
}
}
Original file line number Diff line number Diff line change
@@ -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<EObjectType, Int> = mutableMapOf()
)

0 comments on commit 4715444

Please sign in to comment.