Skip to content

Commit

Permalink
differentiating road object geometries
Browse files Browse the repository at this point in the history
  • Loading branch information
benediktschwab committed Jul 20, 2023
1 parent 5abcf0f commit 5ec028e
Show file tree
Hide file tree
Showing 15 changed files with 119 additions and 153 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,16 @@ data class RoadObjectsObject(
outlines.fold({ emptyList() }, { it.getLinearRingsDefinedByLocalCorners() })

/** Returns true, if the provided geometry information correspond to a cuboid. */
fun isCuboid() = length.isDefined() && width.isDefined() && heightValidated.isDefined() && outlines.isEmpty() && repeat.isEmpty()
fun containsCuboid() = length.isDefined() && width.isDefined() && heightValidated.isDefined()

/** Returns true, if the provided geometry information correspond to a rectangle. */
fun isRectangle() = length.isDefined() && width.isDefined() && heightValidated.isEmpty() && outlines.isEmpty() && repeat.isEmpty()
fun containsRectangle() = length.isDefined() && width.isDefined() && heightValidated.isEmpty()

/** Returns true, if the provided geometry information correspond to a cylinder. */
fun isCylinder() = radius.isDefined() && heightValidated.isDefined() && outlines.isEmpty() && repeat.isEmpty()
fun containsCylinder() = radius.isDefined() && heightValidated.isDefined()

/** Returns true, if the provided geometry information correspond to a circle. */
fun isCircle() = radius.isDefined() && heightValidated.isEmpty() && outlines.isEmpty() && repeat.isEmpty()

/** Returns true, if the provided geometry information correspond to a point. */
fun isPoint() = !isCuboid() && !isRectangle() && !isCylinder() && outlines.isEmpty() && repeat.isEmpty()
fun containsCircle() = radius.isDefined() && heightValidated.isEmpty()

companion object
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ data class RoadSignalsSignal(
fun isPolygon() = width.isDefined() && height.isDefined()
fun isVerticalLine() = width.isEmpty() && height.isDefined()
fun isHorizontalLine() = width.isDefined() && height.isEmpty()
fun isPoint() = !isPolygon() && !isVerticalLine() && !isHorizontalLine()

companion object
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,25 @@ import io.rtron.model.roadspaces.roadspace.attribute.attributes
*/
data class RoadspaceObjectIdentifier(
val roadspaceObjectId: String,
val roadspaceObjectRepeatIndex: Option<Int>,
val roadspaceObjectName: Option<String>,
val roadspaceIdentifier: RoadspaceIdentifier
) : AbstractRoadspacesIdentifier(), RoadspaceIdentifierInterface by roadspaceIdentifier {

// Properties and Initializers
val hashKey get() = "RoadspaceObject_${roadspaceObjectId}_${roadspaceIdentifier.roadspaceId}"
val hashKey get() = "RoadspaceObject_${roadspaceObjectId}_${roadspaceObjectRepeatIndex}_${roadspaceIdentifier.roadspaceId}"

// Conversions
override fun toAttributes(prefix: String): AttributeList {
val roadspaceObjectIdentifier = this
return attributes(prefix) {
attribute("roadObjectId", roadspaceObjectIdentifier.roadspaceObjectId)
attribute("roadObjectName", roadspaceObjectIdentifier.roadspaceObjectName)
roadspaceObjectIdentifier.roadspaceObjectRepeatIndex.tap {
attribute("roadObjectRepeatIndex", it)
}
roadspaceObjectIdentifier.roadspaceObjectName.tap {
attribute("roadObjectName", it)
}
} + roadspaceObjectIdentifier.roadspaceIdentifier.toAttributes(prefix)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ import io.rtron.model.roadspaces.roadspace.attribute.AttributeList
data class RoadspaceObject(
val id: RoadspaceObjectIdentifier,
val type: RoadObjectType = RoadObjectType.NONE,
val pointGeometry: Option<AbstractPoint3D>,
val boundingBoxGeometry: Option<AbstractPoint3D>,
val pointGeometry: AbstractPoint3D,
val boundingBoxGeometry: Option<AbstractGeometry3D>,
val complexGeometry: Option<AbstractGeometry3D>,
val laneRelations: List<LateralLaneRangeIdentifier>,
val attributes: AttributeList
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ object Solid3DBuilder {
val cuboidList = mutableListOf<Cuboid3D>()
val messageList = DefaultMessageList()

if (roadObject.isCuboid()) {
if (roadObject.containsCuboid()) {
val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose)
val affineSequence = AffineSequence3D.of(curveAffine, objectAffine)
cuboidList += Cuboid3D.of(roadObject.length, roadObject.width, roadObject.heightValidated, numberTolerance, affineSequence)
Expand All @@ -80,7 +80,7 @@ object Solid3DBuilder {
val cylinderList = mutableListOf<Cylinder3D>()
val messageList = DefaultMessageList()

if (roadObject.isCylinder()) {
if (roadObject.containsCylinder()) {
val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose)
val affineSequence = AffineSequence3D.of(curveAffine, objectAffine)
cylinderList += Cylinder3D.of(roadObject.radius, roadObject.height, numberTolerance, affineSequence)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ object Surface3DBuilder {
val rectangleList = mutableListOf<Rectangle3D>()
val messageList = DefaultMessageList()

if (roadObject.isRectangle()) {
if (roadObject.containsRectangle()) {
val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose)
val affineSequence = AffineSequence3D.of(curveAffine, objectAffine)
rectangleList += Rectangle3D.of(roadObject.length, roadObject.width, numberTolerance, affineSequence)
Expand All @@ -78,7 +78,7 @@ object Surface3DBuilder {
val circleList = mutableListOf<Circle3D>()
val messageList = DefaultMessageList()

if (roadObject.isCircle()) {
if (roadObject.containsCircle()) {
val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose)
val affineSequence = AffineSequence3D.of(curveAffine, objectAffine)
circleList += Circle3D.of(roadObject.radius, numberTolerance, affineSequence)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,8 @@ object Vector3DBuilder {
*
* @param roadObject road object of OpenDRIVE
* @param curveAffine affine transformation matrix at the reference curve
* @param force true, if the point generation shall be forced
*/
fun buildVector3Ds(roadObject: RoadObjectsObject, curveAffine: Affine3D, force: Boolean = false): Vector3D {
require(roadObject.isPoint() || force) { "Not a point geometry." }

fun buildVector3Ds(roadObject: RoadObjectsObject, curveAffine: Affine3D): Vector3D {
val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose)
return Vector3D.ZERO.copy(affineSequence = AffineSequence3D.of(curveAffine, objectAffine))
}
Expand All @@ -52,9 +49,7 @@ object Vector3DBuilder {
* @param curveAffine affine transformation matrix at the reference curve
* @param force true, if the point generation shall be forced
*/
fun buildVector3Ds(roadSignal: RoadSignalsSignal, curveAffine: Affine3D, force: Boolean = false): Vector3D {
require(roadSignal.isPoint() || force) { "Not a point geometry." }

fun buildVector3Ds(roadSignal: RoadSignalsSignal, curveAffine: Affine3D): Vector3D {
val objectAffine = Affine3D.of(roadSignal.referenceLinePointRelativePose)
return Vector3D.ZERO.copy(affineSequence = AffineSequence3D.of(curveAffine, objectAffine))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,18 +103,19 @@ class RoadspaceObjectBuilder(
val roadObjectsFromRepeat = roadObject.repeat.map { currentRoadObjectRepeat ->
val repeatIdentifier = currentRoadObjectRepeat.additionalId.toEither { IllegalStateException("Additional outline ID must be available.") }.getOrElse { throw it }

val roadspaceObjectId = RoadspaceObjectIdentifier("${roadObject.id}_${repeatIdentifier.repeatIndex}", roadObject.name, id)
val roadspaceObjectId = RoadspaceObjectIdentifier(roadObject.id, repeatIdentifier.repeatIndex.some(), roadObject.name, id)
val pointGeometry = buildPointGeometry(roadObject, roadReferenceLine)
val p = pointGeometry.calculatePointGlobalCS()
val buildBoundingBoxGeometry = buildBoundingBoxGeometry(roadObject, roadReferenceLine).handleMessageList { messageList += it }
val complexGeometry = buildComplexGeometry(roadObject, currentRoadObjectRepeat.some(), roadReferenceLine).handleMessageList { messageList += it }
RoadspaceObject(roadspaceObjectId, type, None, None, complexGeometry, laneRelations, attributes)
RoadspaceObject(roadspaceObjectId, type, pointGeometry, buildBoundingBoxGeometry, complexGeometry, laneRelations, attributes)
}

val roadObjects = if (roadObjectsFromRepeat.isEmpty()) {
val roadspaceObjectId = RoadspaceObjectIdentifier(roadObject.id, roadObject.name, id)
val roadspaceObjectId = RoadspaceObjectIdentifier(roadObject.id, None, roadObject.name, id)
val pointGeometry = buildPointGeometry(roadObject, roadReferenceLine)
val buildBoundingBoxGeometry = buildBoundingBoxGeometry(roadObject, roadReferenceLine).handleMessageList { messageList += it }
val complexGeometry = buildComplexGeometry(roadObject, None, roadReferenceLine).handleMessageList { messageList += it }
nonEmptyListOf(RoadspaceObject(roadspaceObjectId, type, pointGeometry.some(), None, complexGeometry, laneRelations, attributes))
nonEmptyListOf(RoadspaceObject(roadspaceObjectId, type, pointGeometry, buildBoundingBoxGeometry, complexGeometry, laneRelations, attributes))
} else {
roadObjectsFromRepeat.toNonEmptyListOrNull()!!
}
Expand Down Expand Up @@ -144,6 +145,31 @@ class RoadspaceObjectBuilder(
}
})

private fun buildPointGeometry(roadObject: OpendriveRoadObject, roadReferenceLine: Curve3D): Vector3D {
val curveAffine = roadReferenceLine.calculateAffine(roadObject.curveRelativePosition.toCurveRelative1D())
return Vector3DBuilder.buildVector3Ds(roadObject, curveAffine)
}

private fun buildBoundingBoxGeometry(roadObject: OpendriveRoadObject, roadReferenceLine: Curve3D): ContextMessageList<Option<AbstractGeometry3D>> {
val messageList = DefaultMessageList()

// affine transformation matrix at the curve point of the object
val curveAffine = roadReferenceLine.calculateAffine(roadObject.curveRelativePosition.toCurveRelative1D())

// build up solid geometrical representations
val geometries = mutableListOf<AbstractGeometry3D>()
geometries += Solid3DBuilder.buildCuboids(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }
geometries += Solid3DBuilder.buildCylinders(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }

// build up surface geometrical representations
geometries += Surface3DBuilder.buildRectangles(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }
geometries += Surface3DBuilder.buildCircles(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }

check(geometries.size <= 1) { "Multiple geometries must not be derived." }
val builtGeometry = if (geometries.isEmpty()) None else Some(geometries.first())
return ContextMessageList(builtGeometry, messageList)
}

/**
* Reads in the OpenDRIVE road object geometries and builds up the implemented geometries of [AbstractGeometry3D].
*
Expand All @@ -163,14 +189,10 @@ class RoadspaceObjectBuilder(

// build up solid geometrical representations
val geometries = mutableListOf<AbstractGeometry3D>()
geometries += Solid3DBuilder.buildCuboids(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }
geometries += Solid3DBuilder.buildCylinders(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }
geometries += Solid3DBuilder.buildPolyhedronsByRoadCorners(roadObject, roadReferenceLine, parameters.numberTolerance).handleMessageList { messageList += it }
geometries += Solid3DBuilder.buildPolyhedronsByLocalCorners(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }

// build up surface geometrical representations
geometries += Surface3DBuilder.buildRectangles(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }
geometries += Surface3DBuilder.buildCircles(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }
geometries += Surface3DBuilder.buildLinearRingsByRoadCorners(roadObject, roadReferenceLine, parameters.numberTolerance).handleMessageList { messageList += it }
geometries += Surface3DBuilder.buildLinearRingsByLocalCorners(roadObject, curveAffine, parameters.numberTolerance).handleMessageList { messageList += it }

Expand All @@ -183,26 +205,23 @@ class RoadspaceObjectBuilder(
// build up curve geometrical representations
geometries += Curve3DBuilder.buildCurve3D(roadObject, roadReferenceLine, parameters.numberTolerance)

// if no other geometrical representation has been found, use a point instead
/*if (geometries.isEmpty()) {
geometries += Vector3DBuilder.buildVector3Ds(roadObject, curveAffine, force = true)
}*/

check(geometries.size <= 1) { "Multiple geometries must not be derived." }

val builtGeometry = if (geometries.isEmpty()) None else Some(geometries.first())
return ContextMessageList(builtGeometry, messageList)
}

private fun buildPointGeometry(roadObject: OpendriveRoadObject, roadReferenceLine: Curve3D): Vector3D {
val curveAffine = roadReferenceLine.calculateAffine(roadObject.curveRelativePosition.toCurveRelative1D())
return Vector3DBuilder.buildVector3Ds(roadObject, curveAffine, force = true)
}

private fun buildAttributes(roadObject: OpendriveRoadObject) =
attributes("${parameters.attributesPrefix}roadObject_") {
attribute("type", roadObject.type.toString())
attribute("subtype", roadObject.subtype)
roadObject.name.tap {
attribute("name", it)
}
roadObject.type.tap {
attribute("type", it.toString())
}
roadObject.subtype.tap {
attribute("subtype", it)
}
roadObject.dynamic.tap {
attribute("dynamic", it)
}
Expand Down Expand Up @@ -245,35 +264,43 @@ class RoadspaceObjectBuilder(
road: RoadspaceRoad,
baseAttributes: AttributeList
): RoadspaceObject {
val objectId = RoadspaceObjectIdentifier(roadSignal.id, roadSignal.name, id)
val objectId = RoadspaceObjectIdentifier(roadSignal.id, None, roadSignal.name, id)

val pointGeometry = buildPointGeometry(roadSignal, roadReferenceLine)
val buildBoundingBoxGeometry = buildBoundingBoxGeometry(roadSignal, roadReferenceLine)
val laneRelations = buildLaneRelations(roadSignal, road)
val attributes = baseAttributes +
buildAttributes(roadSignal) +
buildAttributes(roadSignal.curveRelativePosition) +
buildAttributes(roadSignal.referenceLinePointRelativeRotation)

return RoadspaceObject(objectId, RoadObjectType.SIGNAL, pointGeometry.some(), None, None, laneRelations, attributes)
return RoadspaceObject(objectId, RoadObjectType.SIGNAL, pointGeometry, buildBoundingBoxGeometry, None, laneRelations, attributes)
}

private fun buildAttributes(signal: RoadSignalsSignal): AttributeList =
attributes("${parameters.attributesPrefix}roadSignal_") {
signal.name.tap {
attribute("name", it)
}
attribute("type", signal.type)
attribute("subtype", signal.subtype)
attribute("dynamic", signal.dynamic)
attribute("orientation", signal.orientation.toString())
signal.country.tap {
attribute("countryCode", it.toString())
}
attribute("type", signal.type)
attribute("subtype", signal.subtype)
signal.value.tap {
attribute("value", it)
}
}

private fun buildPointGeometry(signal: RoadSignalsSignal, roadReferenceLine: Curve3D): Vector3D {
val curveAffine = roadReferenceLine.calculateAffine(signal.curveRelativePosition.toCurveRelative1D())
return Vector3DBuilder.buildVector3Ds(signal, curveAffine, force = true)
return Vector3DBuilder.buildVector3Ds(signal, curveAffine)
}

private fun buildBoundingBoxGeometry(signal: RoadSignalsSignal, roadReferenceLine: Curve3D): Option<AbstractGeometry3D> {
return None
}

private fun buildLaneRelations(roadObject: OpendriveRoadObject, road: RoadspaceRoad): List<LateralLaneRangeIdentifier> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,57 +16,16 @@

package io.rtron.transformer.converter.roadspaces2citygml.geometry

import arrow.core.Either
import arrow.core.continuations.either
import arrow.core.left
import arrow.core.right
import org.citygml4j.core.model.core.AbstractOccupiedSpace

/**
* Populates the [lod] geometry of an [AbstractOccupiedSpace], if available. Otherwise, the [lod] implicit geometry of the [GeometryTransformer] is populated.
*
* @param geometryTransformer source geometries
* @param lod target level of detail
* @return [Either.Right] is returned, if a geometry or implicit geometry has been populated; [Either.Left], if no geometry could be assigned
*/
fun AbstractOccupiedSpace.populateGeometryOrImplicitGeometry(geometryTransformer: GeometryTransformer, lod: LevelOfDetail): Either<GeometryTransformerException, Unit> = either.eager {
val geometryErrorMessage: String = populateGeometry(geometryTransformer, lod)
.onRight { right().bind() }
.fold({ it.message }, { "" })
val implicitGeometryErrorMessage: String = populateImplicitGeometry(geometryTransformer, lod)
.onRight { right().bind() }
.fold({ it.message }, { "" })

GeometryTransformerException.NoSuiteableSourceGeometry(
"No suitable source geometry found for populating the $lod geometry ($geometryErrorMessage) " +
"or implicit geometry ($implicitGeometryErrorMessage) of the abstract occupied space."
).left().bind()
}

/**
* Populates the [lod] implicit geometry of an [AbstractOccupiedSpace] object with the source geometries of the [GeometryTransformer].
*
* @param geometryTransformer source geometries
* @param lod target level of detail
* @return [Either.Right] is returned, if an implicit geometry has been populated; [Either.Left], if no implicit geometry could be assigned
*/
fun AbstractOccupiedSpace.populateImplicitGeometry(geometryTransformer: GeometryTransformer, lod: LevelOfDetail): Either<GeometryTransformerException, Unit> = either.eager {
require(lod != LevelOfDetail.ZERO) { "An implicit geometry can not be assigned to an AbstractOccupiedSpace at level 0." }

geometryTransformer.getImplicitGeometry().tap { currentImplicitGeometryProperty ->
if (lod == LevelOfDetail.ONE) {
lod1ImplicitRepresentation = currentImplicitGeometryProperty
return@eager
}
if (lod == LevelOfDetail.TWO) {
lod2ImplicitRepresentation = currentImplicitGeometryProperty
return@eager
}
if (lod == LevelOfDetail.THREE) {
lod3ImplicitRepresentation = currentImplicitGeometryProperty
return@eager
}
}
fun AbstractOccupiedSpace.populateLod1ImplicitGeometry(geometryTransformer: GeometryTransformer) {
val implicitGeometryPropertyResult = geometryTransformer.getImplicitGeometry()
require(implicitGeometryPropertyResult.isDefined()) { "Must contain implicit geometry." }

GeometryTransformerException.NoSuiteableSourceGeometry("No suitable source geometry found for populating the LoD $lod implicit geometry of the abstract occupied space.").left().bind()
lod1ImplicitRepresentation = implicitGeometryPropertyResult.orNull()!!
}
Loading

0 comments on commit 5ec028e

Please sign in to comment.