diff --git a/build.gradle.kts b/build.gradle.kts index 7a5470c9..aaf19343 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,7 +20,7 @@ import org.jetbrains.dokka.gradle.DokkaMultiModuleTask if (!JavaVersion.current().isCompatibleWith(JavaVersion.VERSION_17)) { throw GradleException( "This build requires Java ${JavaVersion.VERSION_17}, " + - "but version ${JavaVersion.current()} is currently in use." + "but version ${JavaVersion.current()} is currently in use.", ) } diff --git a/buildSrc/src/main/kotlin/Plugins.kt b/buildSrc/src/main/kotlin/Plugins.kt index b970b6bd..6ecc1231 100644 --- a/buildSrc/src/main/kotlin/Plugins.kt +++ b/buildSrc/src/main/kotlin/Plugins.kt @@ -17,7 +17,7 @@ object PluginVersions { const val shadowjar = "8.1.1" - const val ktlint = "11.6.1" + const val ktlint = "12.1.1" const val xjc = "1.6" const val versionChecker = "0.51.0" const val dokka = "1.9.20" diff --git a/rtron-cli/src/main/kotlin/io/rtron/cli/Main.kt b/rtron-cli/src/main/kotlin/io/rtron/cli/Main.kt index 0f6cf320..371a18de 100644 --- a/rtron-cli/src/main/kotlin/io/rtron/cli/Main.kt +++ b/rtron-cli/src/main/kotlin/io/rtron/cli/Main.kt @@ -31,7 +31,8 @@ class MainCommand : CliktCommand(name = "rtron") { * * @param args arguments of the cli */ -fun main(args: Array) = MainCommand() - .versionOption("1.3.1") - .subcommands(SubcommandValidateOpendrive(), SubcommandOpendriveToCitygml()) - .main(args) +fun main(args: Array) = + MainCommand() + .versionOption("1.3.1") + .subcommands(SubcommandValidateOpendrive(), SubcommandOpendriveToCitygml()) + .main(args) 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 f1a9642c..55b947c8 100644 --- a/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandOpendriveToCitygml.kt +++ b/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandOpendriveToCitygml.kt @@ -40,88 +40,110 @@ import io.rtron.transformer.converter.roadspaces2citygml.Roadspaces2CitygmlParam import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.modifiers.opendrive.offset.adder.OpendriveOffsetAdderParameters -class SubcommandOpendriveToCitygml : CliktCommand(name = "opendrive-to-citygml", help = "Transform OpenDRIVE datasets to CityGML.", printHelpOnEmptyArgs = true) { - +class SubcommandOpendriveToCitygml : CliktCommand( + name = "opendrive-to-citygml", + help = "Transform OpenDRIVE datasets to CityGML.", + printHelpOnEmptyArgs = true, +) { // Properties and Initializers private val parametersPath by option( - help = "Path to a YAML file containing the parameters of the process." + help = "Path to a YAML file containing the parameters of the process.", ).path(mustExist = true) private val inputPath by argument( - help = "Path to the directory containing OpenDRIVE datasets" + help = "Path to the directory containing OpenDRIVE datasets", ).path(mustExist = true) private val outputPath by argument( - help = "Path to the output directory into which the transformed CityGML models are written" + help = "Path to the output directory into which the transformed CityGML models are written", ).path() - private val skipRoadShapeRemoval by option(help = "skip the removal of the road shape, if a lateral lane offset exists (not compliant to standard)").flag() + private val skipRoadShapeRemoval by option( + help = "skip the removal of the road shape, if a lateral lane offset exists (not compliant to standard)", + ).flag() private val convertToCitygml2 by option(help = "convert to CityGML 2.0 (otherwise CityGML 3.0)").flag() private val tolerance by option(help = "allowed tolerance when comparing double values").double() .default(Opendrive2RoadspacesParameters.DEFAULT_NUMBER_TOLERANCE) - private val planViewGeometryDistanceTolerance by option(help = "allowed distance tolerance between two geometry elements in the plan view").double() + private val planViewGeometryDistanceTolerance by option( + help = "allowed distance tolerance between two geometry elements in the plan view", + ).double() .default(OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_TOLERANCE) - private val planViewGeometryDistanceWarningTolerance by option(help = "warning distance tolerance between two geometry elements in the plan view").double() + private val planViewGeometryDistanceWarningTolerance by option( + help = "warning distance tolerance between two geometry elements in the plan view", + ).double() .default(OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_WARNING_TOLERANCE) - private val planViewGeometryAngleTolerance by option(help = "allowed angle tolerance between two geometry elements in the plan view").double() + private val planViewGeometryAngleTolerance by option( + help = "allowed angle tolerance between two geometry elements in the plan view", + ).double() .default(OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_TOLERANCE) - private val planViewGeometryAngleWarningTolerance by option(help = "warning angle tolerance between two geometry elements in the plan view").double() + private val planViewGeometryAngleWarningTolerance by option( + help = "warning angle tolerance between two geometry elements in the plan view", + ).double() .default(OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_WARNING_TOLERANCE) private val crsEpsg by option(help = "EPSG code of the coordinate reference system used in the OpenDRIVE datasets").int() .default(Opendrive2RoadspacesParameters.DEFAULT_CRS_EPSG) 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)) + .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").double().pair().multiple() 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) - private val sweepDiscretizationStepSize by option(help = "distance between each discretization step for solid geometries of ParametricSweep3D").double() + private val sweepDiscretizationStepSize by option( + help = "distance between each discretization step for solid geometries of ParametricSweep3D", + ).double() .default(Roadspaces2CitygmlParameters.DEFAULT_SWEEP_DISCRETIZATION_STEP_SIZE) private val circleSlices by option(help = "number of discretization points for a circle or cylinder").int() .default(Roadspaces2CitygmlParameters.DEFAULT_CIRCLE_SLICES) private val generateRandomGeometryIds by option(help = "true, if random ids shall be generated for the gml geometries").flag() - private val transformAdditionalRoadLines by option(help = "if true, additional road lines, such as the reference line, lane boundaries, etc., are also transformed").flag() + private val transformAdditionalRoadLines by option( + help = "if true, additional road lines, such as the reference line, lane boundaries, etc., are also transformed", + ).flag() - private val compressionFormat: CompressionFormat by option(help = "compress the output files with the respective compression format").enum() + private val compressionFormat: CompressionFormat by option( + help = "compress the output files with the respective compression format", + ).enum() .default(CompressionFormat.NONE) // Methods override fun run() { - val parameters = parametersPath.toOption().fold({ - OpendriveToCitygmlParameters( - convertToCitygml2 = convertToCitygml2, - - skipRoadShapeRemoval = skipRoadShapeRemoval, - - tolerance = tolerance, - planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, - planViewGeometryDistanceWarningTolerance = planViewGeometryDistanceWarningTolerance, - planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, - planViewGeometryAngleWarningTolerance = planViewGeometryAngleWarningTolerance, - crsEpsg = crsEpsg, - offsetX = addOffset.first, - offsetY = addOffset.second, - offsetZ = addOffset.third, - cropPolygonX = cropPolygon.map { it.first }, - cropPolygonY = cropPolygon.map { it.second }, - removeRoadObjectsOfTypes = removeRoadObjectOfType, - - discretizationStepSize = discretizationStepSize, - sweepDiscretizationStepSize = sweepDiscretizationStepSize, - circleSlices = circleSlices, - generateRandomGeometryIds = generateRandomGeometryIds, - transformAdditionalRoadLines = transformAdditionalRoadLines, - - compressionFormat = compressionFormat - ) - }, { parametersFilePath -> - val parametersText = parametersFilePath.toFile().readText() - - Yaml.default.decodeFromString(OpendriveToCitygmlParameters.serializer(), parametersText) - }) + val parameters = + parametersPath.toOption().fold({ + OpendriveToCitygmlParameters( + convertToCitygml2 = convertToCitygml2, + skipRoadShapeRemoval = skipRoadShapeRemoval, + tolerance = tolerance, + planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, + planViewGeometryDistanceWarningTolerance = planViewGeometryDistanceWarningTolerance, + planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, + planViewGeometryAngleWarningTolerance = planViewGeometryAngleWarningTolerance, + crsEpsg = crsEpsg, + offsetX = addOffset.first, + offsetY = addOffset.second, + offsetZ = addOffset.third, + cropPolygonX = cropPolygon.map { it.first }, + cropPolygonY = cropPolygon.map { it.second }, + removeRoadObjectsOfTypes = removeRoadObjectOfType, + discretizationStepSize = discretizationStepSize, + sweepDiscretizationStepSize = sweepDiscretizationStepSize, + circleSlices = circleSlices, + generateRandomGeometryIds = generateRandomGeometryIds, + transformAdditionalRoadLines = transformAdditionalRoadLines, + compressionFormat = compressionFormat, + ) + }, { parametersFilePath -> + val parametersText = parametersFilePath.toFile().readText() + + Yaml.default.decodeFromString(OpendriveToCitygmlParameters.serializer(), parametersText) + }) val processor = OpendriveToCitygmlProcessor(parameters) processor.process(inputPath, outputPath) diff --git a/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandValidateOpendrive.kt b/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandValidateOpendrive.kt index 072197b1..f7c1ce7d 100644 --- a/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandValidateOpendrive.kt +++ b/rtron-cli/src/main/kotlin/io/rtron/cli/SubcommandValidateOpendrive.kt @@ -33,29 +33,40 @@ import io.rtron.transformer.converter.opendrive2roadspaces.Opendrive2RoadspacesP import io.rtron.transformer.converter.roadspaces2citygml.Roadspaces2CitygmlParameters import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters -class SubcommandValidateOpendrive : CliktCommand(name = "validate-opendrive", help = "Validate OpenDRIVE datasets.", printHelpOnEmptyArgs = true) { - +class SubcommandValidateOpendrive : CliktCommand( + name = "validate-opendrive", + help = "Validate OpenDRIVE datasets.", + printHelpOnEmptyArgs = true, +) { // Properties and Initializers private val parametersPath by option( - help = "Path to a YAML file containing the parameters of the process." + help = "Path to a YAML file containing the parameters of the process.", ).path(mustExist = true) private val inputPath by argument( - help = "Path to the directory containing OpenDRIVE datasets" + help = "Path to the directory containing OpenDRIVE datasets", ).path(mustExist = true) private val outputPath by argument( - help = "Path to the output directory into which the reports are written" + help = "Path to the output directory into which the reports are written", ).path() private val tolerance by option(help = "allowed tolerance when comparing double values").double() .default(Opendrive2RoadspacesParameters.DEFAULT_NUMBER_TOLERANCE) - private val planViewGeometryDistanceTolerance by option(help = "allowed distance tolerance between two geometry elements in the plan view").double() + private val planViewGeometryDistanceTolerance by option( + help = "allowed distance tolerance between two geometry elements in the plan view", + ).double() .default(OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_TOLERANCE) - private val planViewGeometryDistanceWarningTolerance by option(help = "warning distance tolerance between two geometry elements in the plan view").double() + private val planViewGeometryDistanceWarningTolerance by option( + help = "warning distance tolerance between two geometry elements in the plan view", + ).double() .default(OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_WARNING_TOLERANCE) - private val planViewGeometryAngleTolerance by option(help = "allowed angle tolerance between two geometry elements in the plan view").double() + private val planViewGeometryAngleTolerance by option( + help = "allowed angle tolerance between two geometry elements in the plan view", + ).double() .default(OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_TOLERANCE) - private val planViewGeometryAngleWarningTolerance by option(help = "warning angle tolerance between two geometry elements in the plan view").double() + private val planViewGeometryAngleWarningTolerance by option( + help = "warning angle tolerance between two geometry elements in the plan view", + ).double() .default(OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_WARNING_TOLERANCE) private val discretizationStepSize by option(help = "distance between each discretization step for curves and surfaces").double() @@ -64,29 +75,31 @@ class SubcommandValidateOpendrive : CliktCommand(name = "validate-opendrive", he private val skipOpendriveExport by option(help = "skip the export of the adjusted OpenDRIVE dataset").flag() private val skipCitygmlExport by option(help = "skip the export of the CityGML dataset for visual inspection purposes").flag() - private val compressionFormat: CompressionFormat by option(help = "compress the output files with the respective compression format").enum() + private val compressionFormat: CompressionFormat by option( + help = "compress the output files with the respective compression format", + ).enum() .default(CompressionFormat.NONE) // Methods override fun run() { - val parameters = parametersPath.toOption().fold({ - ValidateOpendriveParameters( - tolerance = tolerance, - planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, - planViewGeometryDistanceWarningTolerance = planViewGeometryDistanceWarningTolerance, - planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, - planViewGeometryAngleWarningTolerance = planViewGeometryAngleWarningTolerance, - discretizationStepSize = discretizationStepSize, - writeOpendriveFile = !skipOpendriveExport, - writeCitygml2File = !skipCitygmlExport, - - compressionFormat = compressionFormat - ) - }, { parametersFilePath -> - val parametersText = parametersFilePath.toFile().readText() + val parameters = + parametersPath.toOption().fold({ + ValidateOpendriveParameters( + tolerance = tolerance, + planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, + planViewGeometryDistanceWarningTolerance = planViewGeometryDistanceWarningTolerance, + planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, + planViewGeometryAngleWarningTolerance = planViewGeometryAngleWarningTolerance, + discretizationStepSize = discretizationStepSize, + writeOpendriveFile = !skipOpendriveExport, + writeCitygml2File = !skipCitygmlExport, + compressionFormat = compressionFormat, + ) + }, { parametersFilePath -> + val parametersText = parametersFilePath.toFile().readText() - Yaml.default.decodeFromString(ValidateOpendriveParameters.serializer(), parametersText) - }) + Yaml.default.decodeFromString(ValidateOpendriveParameters.serializer(), parametersText) + }) val processor = ValidateOpendriveProcessor(parameters) processor.process(inputPath, outputPath) diff --git a/rtron-io/src/main/kotlin/io/rtron/io/csv/CSVPrinter.kt b/rtron-io/src/main/kotlin/io/rtron/io/csv/CSVPrinter.kt index 26d1acb5..9caf8b2c 100644 --- a/rtron-io/src/main/kotlin/io/rtron/io/csv/CSVPrinter.kt +++ b/rtron-io/src/main/kotlin/io/rtron/io/csv/CSVPrinter.kt @@ -30,7 +30,6 @@ import org.apache.commons.csv.CSVPrinter as CMCSVPrinter * @param header header of the csv file */ class CSVPrinter(filePath: Path, header: List) : Flushable { - // Properties and Initializers init { filePath.parent.createDirectories() @@ -38,12 +37,14 @@ class CSVPrinter(filePath: Path, header: List) : Flushable { private val writer = Files.newBufferedWriter(filePath) private val csvPrinter: CMCSVPrinter + init { val csvFormat = Builder.create().setHeader(*header.toTypedArray()).build() csvPrinter = CMCSVPrinter(writer, csvFormat) } // Methods + /** * Prints the given [values] as a single record. * diff --git a/rtron-io/src/main/kotlin/io/rtron/io/files/CompressedFileExtension.kt b/rtron-io/src/main/kotlin/io/rtron/io/files/CompressedFileExtension.kt index 73763220..1eacc6f2 100644 --- a/rtron-io/src/main/kotlin/io/rtron/io/files/CompressedFileExtension.kt +++ b/rtron-io/src/main/kotlin/io/rtron/io/files/CompressedFileExtension.kt @@ -22,5 +22,5 @@ package io.rtron.io.files enum class CompressedFileExtension(val extension: String, val extensionWithDot: String) { ZIP("zip", ".zip"), GZ("gz", ".gz"), - ZST("zst", ".zst") + ZST("zst", ".zst"), } diff --git a/rtron-io/src/main/kotlin/io/rtron/io/files/PathExtensions.kt b/rtron-io/src/main/kotlin/io/rtron/io/files/PathExtensions.kt index 3f67f3d0..757a2f8d 100644 --- a/rtron-io/src/main/kotlin/io/rtron/io/files/PathExtensions.kt +++ b/rtron-io/src/main/kotlin/io/rtron/io/files/PathExtensions.kt @@ -50,8 +50,7 @@ fun Path.getFileSizeToDisplay(): String = FileUtils.byteCountToDisplaySize(this. * @param maxDepth maximal depth to be traversed * @return sequence of [Path] */ -fun Path.walk(maxDepth: Int = Int.MAX_VALUE): Sequence = - Files.walk(this, maxDepth).asSequence().map { it } +fun Path.walk(maxDepth: Int = Int.MAX_VALUE): Sequence = Files.walk(this, maxDepth).asSequence().map { it } /** * Constructs a new InputStream of this file either directly or compressed. diff --git a/rtron-io/src/main/kotlin/io/rtron/io/issues/ContextIssueList.kt b/rtron-io/src/main/kotlin/io/rtron/io/issues/ContextIssueList.kt index b499b5e1..3d1cc7d9 100644 --- a/rtron-io/src/main/kotlin/io/rtron/io/issues/ContextIssueList.kt +++ b/rtron-io/src/main/kotlin/io/rtron/io/issues/ContextIssueList.kt @@ -18,7 +18,7 @@ package io.rtron.io.issues class ContextIssueList( val value: V, - val issueList: DefaultIssueList + val issueList: DefaultIssueList, ) { // Properties and Initializers diff --git a/rtron-io/src/main/kotlin/io/rtron/io/issues/DefaultIssue.kt b/rtron-io/src/main/kotlin/io/rtron/io/issues/DefaultIssue.kt index cab065c3..0fbe43c1 100644 --- a/rtron-io/src/main/kotlin/io/rtron/io/issues/DefaultIssue.kt +++ b/rtron-io/src/main/kotlin/io/rtron/io/issues/DefaultIssue.kt @@ -28,15 +28,15 @@ data class DefaultIssue( val location: String, val incidentSeverity: Severity, val wasFixed: Boolean, - val infoValues: Map = emptyMap() + val infoValues: Map = emptyMap(), ) { - // Properties and Initializers - val issueSeverity: Severity = when (Pair(incidentSeverity, wasFixed)) { - Pair(Severity.FATAL_ERROR, true) -> Severity.ERROR - Pair(Severity.ERROR, true) -> Severity.WARNING - else -> incidentSeverity - } + val issueSeverity: Severity = + when (Pair(incidentSeverity, wasFixed)) { + Pair(Severity.FATAL_ERROR, true) -> Severity.ERROR + Pair(Severity.ERROR, true) -> Severity.WARNING + else -> incidentSeverity + } companion object } diff --git a/rtron-io/src/main/kotlin/io/rtron/io/issues/IssueList.kt b/rtron-io/src/main/kotlin/io/rtron/io/issues/IssueList.kt index dfb6d7bd..40665f1c 100644 --- a/rtron-io/src/main/kotlin/io/rtron/io/issues/IssueList.kt +++ b/rtron-io/src/main/kotlin/io/rtron/io/issues/IssueList.kt @@ -21,7 +21,6 @@ import kotlinx.serialization.Serializable @Serializable @JvmInline value class IssueList(private val issues: MutableList = mutableListOf()) { - // Properties val size: Int get() = issues.size @@ -39,17 +38,24 @@ value class IssueList(private val issues: MutableList = mutableListOf()) { fun getIssues(): List = issues fun isEmpty(): Boolean = issues.isEmpty() + fun isNotEmpty(): Boolean = issues.isNotEmpty() - fun append(issues: T) { this.issues += issues } - fun append(issues: List) { this.issues += issues } + fun append(issues: T) { + this.issues += issues + } - companion object { + fun append(issues: List) { + this.issues += issues + } + companion object { fun of(issues: List): IssueList = IssueList(issues as MutableList) + fun of(issue: T): IssueList = IssueList(mutableListOf(issue)) } } fun List.mergeToReport(): IssueList = IssueList.of(this) + fun List>.merge(): IssueList = IssueList.of(flatMap { it.getIssues() }) diff --git a/rtron-io/src/main/kotlin/io/rtron/io/issues/Severity.kt b/rtron-io/src/main/kotlin/io/rtron/io/issues/Severity.kt index e30201dd..58533377 100644 --- a/rtron-io/src/main/kotlin/io/rtron/io/issues/Severity.kt +++ b/rtron-io/src/main/kotlin/io/rtron/io/issues/Severity.kt @@ -6,5 +6,5 @@ import kotlinx.serialization.Serializable enum class Severity { WARNING, ERROR, - FATAL_ERROR + FATAL_ERROR, } diff --git a/rtron-io/src/main/kotlin/io/rtron/io/logging/ProgressBar.kt b/rtron-io/src/main/kotlin/io/rtron/io/logging/ProgressBar.kt index 5dda8ba9..c4016eaa 100644 --- a/rtron-io/src/main/kotlin/io/rtron/io/logging/ProgressBar.kt +++ b/rtron-io/src/main/kotlin/io/rtron/io/logging/ProgressBar.kt @@ -32,15 +32,15 @@ import kotlin.time.toDuration class ProgressBar( private val taskName: String, private val completion: Int, - private var currentStatus: Int = 0 + private var currentStatus: Int = 0, ) { - // Properties and Initializers private val logger = KotlinLogging.logger {} private val startTime = System.currentTimeMillis() private var lastPrintUpdateTime: Long = 0 // Methods + /** Increments progress bar by one step. */ fun step() { currentStatus += 1 @@ -72,17 +72,13 @@ class ProgressBar( private fun getProgressPercent(): Double = 100.0 * (currentStatus.toDouble() / completion.toDouble()) - private fun getElapsedTime(): Duration = - (System.currentTimeMillis() - startTime).toDuration(DurationUnit.MILLISECONDS) + private fun getElapsedTime(): Duration = (System.currentTimeMillis() - startTime).toDuration(DurationUnit.MILLISECONDS) - private fun getTotalEstimatedElapsedTime(): Duration = - getElapsedTime() * completion.toDouble() / currentStatus.toDouble() + private fun getTotalEstimatedElapsedTime(): Duration = getElapsedTime() * completion.toDouble() / currentStatus.toDouble() - private fun getEstimatedTimeOfArrival(): Duration = - getElapsedTime() * ((completion.toDouble() / currentStatus.toDouble()) - 1.0) + private fun getEstimatedTimeOfArrival(): Duration = getElapsedTime() * ((completion.toDouble() / currentStatus.toDouble()) - 1.0) companion object { - /** * Starts printing the progress bar after the duration of [PRINT_AFTER]. */ diff --git a/rtron-io/src/main/kotlin/io/rtron/io/serialization/JsonSerializationExtensions.kt b/rtron-io/src/main/kotlin/io/rtron/io/serialization/JsonSerializationExtensions.kt index c08ac057..4b0e6b05 100644 --- a/rtron-io/src/main/kotlin/io/rtron/io/serialization/JsonSerializationExtensions.kt +++ b/rtron-io/src/main/kotlin/io/rtron/io/serialization/JsonSerializationExtensions.kt @@ -30,10 +30,11 @@ inline fun T.serializeToJsonFile(filePath: Path) { filePath.parent.createDirectories() } - val jsonFormatter = Json { - prettyPrint = true - encodeDefaults = true - } + val jsonFormatter = + Json { + prettyPrint = true + encodeDefaults = true + } val jsonFileContent = jsonFormatter.encodeToString(this) filePath.toFile().writeText(jsonFileContent) diff --git a/rtron-main/src/main/kotlin/io/rtron/main/processor/CompressionFormat.kt b/rtron-main/src/main/kotlin/io/rtron/main/processor/CompressionFormat.kt index 5d35b802..e98cacef 100644 --- a/rtron-main/src/main/kotlin/io/rtron/main/processor/CompressionFormat.kt +++ b/rtron-main/src/main/kotlin/io/rtron/main/processor/CompressionFormat.kt @@ -20,12 +20,13 @@ enum class CompressionFormat { NONE, GZ, ZIP, - ZST + ZST, } -fun CompressionFormat.toFileExtension(): String = when (this) { - CompressionFormat.NONE -> "" - CompressionFormat.GZ -> ".gz" - CompressionFormat.ZIP -> ".zip" - CompressionFormat.ZST -> ".zst" -} +fun CompressionFormat.toFileExtension(): String = + when (this) { + CompressionFormat.NONE -> "" + CompressionFormat.GZ -> ".gz" + CompressionFormat.ZIP -> ".zip" + CompressionFormat.ZST -> ".zst" + } 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 bbcdd821..c19609c5 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 @@ -33,15 +33,15 @@ import kotlinx.serialization.Serializable @Serializable data class OpendriveToCitygmlParameters( val convertToCitygml2: Boolean = false, - val skipRoadShapeRemoval: Boolean = OpendriveEvaluatorParameters.DEFAULT_SKIP_ROAD_SHAPE_REMOVAL, - val tolerance: Double = Opendrive2RoadspacesParameters.DEFAULT_NUMBER_TOLERANCE, val planViewGeometryDistanceTolerance: Double = OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_TOLERANCE, - val planViewGeometryDistanceWarningTolerance: Double = OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_WARNING_TOLERANCE, - val planViewGeometryAngleTolerance: Double = OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_TOLERANCE, - val planViewGeometryAngleWarningTolerance: Double = OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_WARNING_TOLERANCE, - + val planViewGeometryDistanceWarningTolerance: Double = + OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_WARNING_TOLERANCE, + val planViewGeometryAngleTolerance: Double = + OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_TOLERANCE, + val planViewGeometryAngleWarningTolerance: Double = + OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_WARNING_TOLERANCE, val crsEpsg: Int = Opendrive2RoadspacesParameters.DEFAULT_CRS_EPSG, val offsetX: Double = OpendriveOffsetAdderParameters.DEFAULT_OFFSET_X, val offsetY: Double = OpendriveOffsetAdderParameters.DEFAULT_OFFSET_Y, @@ -49,14 +49,12 @@ data class OpendriveToCitygmlParameters( 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, val circleSlices: Int = Roadspaces2CitygmlParameters.DEFAULT_CIRCLE_SLICES, val generateRandomGeometryIds: Boolean = Roadspaces2CitygmlParameters.DEFAULT_GENERATE_RANDOM_GEOMETRY_IDS, val transformAdditionalRoadLines: Boolean = Roadspaces2CitygmlParameters.DEFAULT_TRANSFORM_ADDITIONAL_ROAD_LINES, - - val compressionFormat: CompressionFormat = CompressionFormat.NONE + val compressionFormat: CompressionFormat = CompressionFormat.NONE, ) { // Methods fun isValid(): Either, Unit> { @@ -80,63 +78,69 @@ data class OpendriveToCitygmlParameters( fun getCitygmlWriteVersion(): CitygmlVersion = if (convertToCitygml2) CitygmlVersion.V2_0 else CitygmlVersion.V3_0 - fun deriveOpendriveEvaluatorParameters() = OpendriveEvaluatorParameters( - skipRoadShapeRemoval = skipRoadShapeRemoval, - numberTolerance = tolerance, - planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, - planViewGeometryDistanceWarningTolerance = planViewGeometryDistanceWarningTolerance, - planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, - planViewGeometryAngleWarningTolerance = planViewGeometryAngleWarningTolerance - ) - - fun deriveOpendriveObjectRemoverParameters() = OpendriveObjectRemoverParameters( - removeRoadObjectsWithoutType = OpendriveObjectRemoverParameters.DEFAULT_REMOVE_ROAD_OBJECTS_WITHOUT_TYPE, - removeRoadObjectsOfTypes = removeRoadObjectsOfTypes - ) - - fun deriveOpendriveOffsetAdderParameters() = OpendriveOffsetAdderParameters( - offsetX = offsetX, - offsetY = offsetY, - offsetZ = offsetZ, - offsetHeading = OpendriveOffsetAdderParameters.DEFAULT_OFFSET_HEADING - ) - - fun deriveOpendriveCropperParameters() = OpendriveCropperParameters( - numberTolerance = tolerance, - cropPolygonX = cropPolygonX, - cropPolygonY = cropPolygonY - ) - - fun deriveOpendrive2RoadspacesParameters() = Opendrive2RoadspacesParameters( - concurrentProcessing = false, - - numberTolerance = tolerance, - planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, - planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, - attributesPrefix = Opendrive2RoadspacesParameters.DEFAULT_ATTRIBUTES_PREFIX, - deriveCrsEpsgAutomatically = true, - crsEpsg = crsEpsg, - extrapolateLateralRoadShapes = Opendrive2RoadspacesParameters.DEFAULT_EXTRAPOLATE_LATERAL_ROAD_SHAPES - ) - - fun deriveRoadspacesEvaluatorParameters() = RoadspacesEvaluatorParameters( - numberTolerance = tolerance, - laneTransitionDistanceTolerance = RoadspacesEvaluatorParameters.DEFAULT_LANE_TRANSITION_DISTANCE_TOLERANCE - ) - - fun deriveRoadspaces2CitygmlParameters() = Roadspaces2CitygmlParameters( - concurrentProcessing = false, - gmlIdPrefix = Roadspaces2CitygmlParameters.DEFAULT_GML_ID_PREFIX, - xlinkPrefix = Roadspaces2CitygmlParameters.DEFAULT_XLINK_PREFIX, - identifierAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_IDENTIFIER_ATTRIBUTES_PREFIX, - geometryAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_GEOMETRY_ATTRIBUTES_PREFIX, - flattenGenericAttributeSets = Roadspaces2CitygmlParameters.DEFAULT_FLATTEN_GENERIC_ATTRIBUTE_SETS, - discretizationStepSize = discretizationStepSize, - sweepDiscretizationStepSize = sweepDiscretizationStepSize, - circleSlices = circleSlices, - generateRandomGeometryIds = generateRandomGeometryIds, - transformAdditionalRoadLines = transformAdditionalRoadLines, - generateLongitudinalFillerSurfaces = Roadspaces2CitygmlParameters.DEFAULT_GENERATE_LONGITUDINAL_FILLER_SURFACES, - mappingBackwardsCompatibility = convertToCitygml2 - ) + fun deriveOpendriveEvaluatorParameters() = + OpendriveEvaluatorParameters( + skipRoadShapeRemoval = skipRoadShapeRemoval, + numberTolerance = tolerance, + planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, + planViewGeometryDistanceWarningTolerance = planViewGeometryDistanceWarningTolerance, + planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, + planViewGeometryAngleWarningTolerance = planViewGeometryAngleWarningTolerance, + ) + + fun deriveOpendriveObjectRemoverParameters() = + OpendriveObjectRemoverParameters( + removeRoadObjectsWithoutType = OpendriveObjectRemoverParameters.DEFAULT_REMOVE_ROAD_OBJECTS_WITHOUT_TYPE, + removeRoadObjectsOfTypes = removeRoadObjectsOfTypes, + ) + + fun deriveOpendriveOffsetAdderParameters() = + OpendriveOffsetAdderParameters( + offsetX = offsetX, + offsetY = offsetY, + offsetZ = offsetZ, + offsetHeading = OpendriveOffsetAdderParameters.DEFAULT_OFFSET_HEADING, + ) + + fun deriveOpendriveCropperParameters() = + OpendriveCropperParameters( + numberTolerance = tolerance, + cropPolygonX = cropPolygonX, + cropPolygonY = cropPolygonY, + ) + + fun deriveOpendrive2RoadspacesParameters() = + Opendrive2RoadspacesParameters( + concurrentProcessing = false, + numberTolerance = tolerance, + planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, + planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, + attributesPrefix = Opendrive2RoadspacesParameters.DEFAULT_ATTRIBUTES_PREFIX, + deriveCrsEpsgAutomatically = true, + crsEpsg = crsEpsg, + extrapolateLateralRoadShapes = Opendrive2RoadspacesParameters.DEFAULT_EXTRAPOLATE_LATERAL_ROAD_SHAPES, + ) + + fun deriveRoadspacesEvaluatorParameters() = + RoadspacesEvaluatorParameters( + numberTolerance = tolerance, + laneTransitionDistanceTolerance = RoadspacesEvaluatorParameters.DEFAULT_LANE_TRANSITION_DISTANCE_TOLERANCE, + ) + + fun deriveRoadspaces2CitygmlParameters() = + Roadspaces2CitygmlParameters( + concurrentProcessing = false, + gmlIdPrefix = Roadspaces2CitygmlParameters.DEFAULT_GML_ID_PREFIX, + xlinkPrefix = Roadspaces2CitygmlParameters.DEFAULT_XLINK_PREFIX, + identifierAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_IDENTIFIER_ATTRIBUTES_PREFIX, + geometryAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_GEOMETRY_ATTRIBUTES_PREFIX, + flattenGenericAttributeSets = Roadspaces2CitygmlParameters.DEFAULT_FLATTEN_GENERIC_ATTRIBUTE_SETS, + discretizationStepSize = discretizationStepSize, + sweepDiscretizationStepSize = sweepDiscretizationStepSize, + circleSlices = circleSlices, + generateRandomGeometryIds = generateRandomGeometryIds, + transformAdditionalRoadLines = transformAdditionalRoadLines, + generateLongitudinalFillerSurfaces = Roadspaces2CitygmlParameters.DEFAULT_GENERATE_LONGITUDINAL_FILLER_SURFACES, + mappingBackwardsCompatibility = convertToCitygml2, + ) } 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 bfc475dc..d45f6300 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 @@ -41,18 +41,20 @@ import kotlin.io.path.createDirectories import kotlin.io.path.div class OpendriveToCitygmlProcessor( - private val parameters: OpendriveToCitygmlParameters + private val parameters: OpendriveToCitygmlParameters, ) { - // Methods - fun process(inputPath: Path, outputPath: Path) { + fun process( + inputPath: Path, + outputPath: Path, + ) { val logger = KotlinLogging.logger {} processAllFiles( inputDirectoryPath = inputPath, withFilenameEndings = OpendriveReader.supportedFilenameEndings, - outputDirectoryPath = outputPath + outputDirectoryPath = outputPath, ) { val outputSubDirectoryPath = outputDirectoryPath / "citygml_${parameters.getCitygmlWriteVersion()}" outputSubDirectoryPath.createDirectories() @@ -66,23 +68,32 @@ class OpendriveToCitygmlProcessor( (outputSubDirectoryPath / PARAMETERS_PATH).toFile().writeText(parametersText) // validate schema of OpenDRIVE model - val opendriveSchemaValidatorReport = OpendriveValidator.validateFromFile(inputFilePath).getOrElse { logger.warn { it.message }; return@processAllFiles } + val opendriveSchemaValidatorReport = + OpendriveValidator.validateFromFile(inputFilePath).getOrElse { + logger.warn { it.message } + return@processAllFiles + } opendriveSchemaValidatorReport.serializeToJsonFile(outputSubDirectoryPath / OPENDRIVE_SCHEMA_VALIDATOR_REPORT_PATH) if (opendriveSchemaValidatorReport.validationProcessAborted()) { return@processAllFiles } // read of OpenDRIVE model - val opendriveModel = OpendriveReader.readFromFile(inputFilePath) - .getOrElse { logger.warn { it.message }; return@processAllFiles } + val opendriveModel = + OpendriveReader.readFromFile(inputFilePath) + .getOrElse { + logger.warn { it.message } + return@processAllFiles + } // evaluate OpenDRIVE model val opendriveEvaluator = OpendriveEvaluator(parameters.deriveOpendriveEvaluatorParameters()) val opendriveEvaluatorResult = opendriveEvaluator.evaluate(opendriveModel) opendriveEvaluatorResult.second.serializeToJsonFile(outputSubDirectoryPath / OPENDRIVE_EVALUATOR_REPORT_PATH) - val modifiedOpendriveModel = opendriveEvaluatorResult.first.handleEmpty { - logger.warn { opendriveEvaluatorResult.second.getTextSummary() } - return@processAllFiles - } + val modifiedOpendriveModel = + opendriveEvaluatorResult.first.handleEmpty { + logger.warn { opendriveEvaluatorResult.second.getTextSummary() } + return@processAllFiles + } // offset OpenDRIVE model val opendriveOffsetAdder = OpendriveOffsetAdder(parameters.deriveOpendriveOffsetAdderParameters()) @@ -98,10 +109,11 @@ class OpendriveToCitygmlProcessor( val opendriveCropper = OpendriveCropper(parameters.deriveOpendriveCropperParameters()) val opendriveCroppedResult = opendriveCropper.modify(opendriveOffsetResolvedResult.first) opendriveCroppedResult.second.serializeToJsonFile(outputSubDirectoryPath / OPENDRIVE_CROP_REPORT_PATH) - val opendriveCropped = opendriveCroppedResult.first.handleEmpty { - logger.warn { "OpendriveCropper: ${opendriveCroppedResult.second.message}" } - return@processAllFiles - } + val opendriveCropped = + opendriveCroppedResult.first.handleEmpty { + logger.warn { "OpendriveCropper: ${opendriveCroppedResult.second.message}" } + return@processAllFiles + } // remove objects from OpenDRIVE model val opendriveObjectRemover = OpendriveObjectRemover(parameters.deriveOpendriveObjectRemoverParameters()) @@ -116,10 +128,11 @@ class OpendriveToCitygmlProcessor( val opendrive2RoadspacesTransformer = Opendrive2RoadspacesTransformer(parameters.deriveOpendrive2RoadspacesParameters()) 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()}" } - return@processAllFiles - } + val roadspacesModel = + roadspacesModelResult.first.handleEmpty { + logger.warn { "Opendrive2RoadspacesTransformer: ${roadspacesModelResult.second.conversion.getTextSummary()}" } + return@processAllFiles + } // evaluate Roadspaces model val roadspacesEvaluator = RoadspacesEvaluator(parameters.deriveRoadspacesEvaluatorParameters()) @@ -135,7 +148,7 @@ class OpendriveToCitygmlProcessor( CitygmlWriter.writeToFile( citygmlModelResult.first, parameters.getCitygmlWriteVersion(), - outputSubDirectoryPath / ("citygml_model.gml" + parameters.compressionFormat.toFileExtension()) + outputSubDirectoryPath / ("citygml_model.gml" + parameters.compressionFormat.toFileExtension()), ) } } diff --git a/rtron-main/src/main/kotlin/io/rtron/main/processor/ValidateOpendriveParameters.kt b/rtron-main/src/main/kotlin/io/rtron/main/processor/ValidateOpendriveParameters.kt index 1049b05d..4581be9c 100644 --- a/rtron-main/src/main/kotlin/io/rtron/main/processor/ValidateOpendriveParameters.kt +++ b/rtron-main/src/main/kotlin/io/rtron/main/processor/ValidateOpendriveParameters.kt @@ -26,75 +26,77 @@ import kotlinx.serialization.Serializable data class ValidateOpendriveParameters( val tolerance: Double = OpendriveEvaluatorParameters.DEFAULT_NUMBER_TOLERANCE, val planViewGeometryDistanceTolerance: Double = OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_TOLERANCE, - val planViewGeometryDistanceWarningTolerance: Double = OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_WARNING_TOLERANCE, + val planViewGeometryDistanceWarningTolerance: Double = + OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_WARNING_TOLERANCE, val planViewGeometryAngleTolerance: Double = OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_TOLERANCE, val planViewGeometryAngleWarningTolerance: Double = OpendriveEvaluatorParameters.DEFAULT_PLAN_VIEW_GEOMETRY_ANGLE_WARNING_TOLERANCE, - val discretizationStepSize: Double = Roadspaces2CitygmlParameters.DEFAULT_DISCRETIZATION_STEP_SIZE, - val writeOpendriveFile: Boolean = true, val writeCitygml2File: Boolean = true, val writeCitygml3File: Boolean = true, - - val compressionFormat: CompressionFormat = CompressionFormat.NONE + val compressionFormat: CompressionFormat = CompressionFormat.NONE, ) { - // Methods - fun deriveOpendriveEvaluatorParameters() = OpendriveEvaluatorParameters( - skipRoadShapeRemoval = OpendriveEvaluatorParameters.DEFAULT_SKIP_ROAD_SHAPE_REMOVAL, - numberTolerance = tolerance, - planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, - planViewGeometryDistanceWarningTolerance = planViewGeometryDistanceWarningTolerance, - planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, - planViewGeometryAngleWarningTolerance = planViewGeometryAngleWarningTolerance - ) + fun deriveOpendriveEvaluatorParameters() = + OpendriveEvaluatorParameters( + skipRoadShapeRemoval = OpendriveEvaluatorParameters.DEFAULT_SKIP_ROAD_SHAPE_REMOVAL, + numberTolerance = tolerance, + planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, + planViewGeometryDistanceWarningTolerance = planViewGeometryDistanceWarningTolerance, + planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, + planViewGeometryAngleWarningTolerance = planViewGeometryAngleWarningTolerance, + ) - fun deriveOpendrive2RoadspacesParameters() = Opendrive2RoadspacesParameters( - concurrentProcessing = false, - numberTolerance = tolerance, - planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, - planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, - attributesPrefix = Opendrive2RoadspacesParameters.DEFAULT_ATTRIBUTES_PREFIX, - deriveCrsEpsgAutomatically = false, - crsEpsg = Opendrive2RoadspacesParameters.DEFAULT_CRS_EPSG, - extrapolateLateralRoadShapes = Opendrive2RoadspacesParameters.DEFAULT_EXTRAPOLATE_LATERAL_ROAD_SHAPES - ) + fun deriveOpendrive2RoadspacesParameters() = + Opendrive2RoadspacesParameters( + concurrentProcessing = false, + numberTolerance = tolerance, + planViewGeometryDistanceTolerance = planViewGeometryDistanceTolerance, + planViewGeometryAngleTolerance = planViewGeometryAngleTolerance, + attributesPrefix = Opendrive2RoadspacesParameters.DEFAULT_ATTRIBUTES_PREFIX, + deriveCrsEpsgAutomatically = false, + crsEpsg = Opendrive2RoadspacesParameters.DEFAULT_CRS_EPSG, + extrapolateLateralRoadShapes = Opendrive2RoadspacesParameters.DEFAULT_EXTRAPOLATE_LATERAL_ROAD_SHAPES, + ) - fun deriveRoadspacesEvaluatorParameters() = RoadspacesEvaluatorParameters( - numberTolerance = tolerance, - laneTransitionDistanceTolerance = RoadspacesEvaluatorParameters.DEFAULT_LANE_TRANSITION_DISTANCE_TOLERANCE - ) + fun deriveRoadspacesEvaluatorParameters() = + RoadspacesEvaluatorParameters( + numberTolerance = tolerance, + laneTransitionDistanceTolerance = RoadspacesEvaluatorParameters.DEFAULT_LANE_TRANSITION_DISTANCE_TOLERANCE, + ) - fun deriveRoadspaces2Citygml2Parameters() = Roadspaces2CitygmlParameters( - concurrentProcessing = false, - gmlIdPrefix = Roadspaces2CitygmlParameters.DEFAULT_GML_ID_PREFIX, - xlinkPrefix = Roadspaces2CitygmlParameters.DEFAULT_XLINK_PREFIX, - identifierAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_IDENTIFIER_ATTRIBUTES_PREFIX, - geometryAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_GEOMETRY_ATTRIBUTES_PREFIX, - flattenGenericAttributeSets = Roadspaces2CitygmlParameters.DEFAULT_FLATTEN_GENERIC_ATTRIBUTE_SETS, - discretizationStepSize = discretizationStepSize, - sweepDiscretizationStepSize = Roadspaces2CitygmlParameters.DEFAULT_SWEEP_DISCRETIZATION_STEP_SIZE, - circleSlices = Roadspaces2CitygmlParameters.DEFAULT_CIRCLE_SLICES, - generateRandomGeometryIds = Roadspaces2CitygmlParameters.DEFAULT_GENERATE_RANDOM_GEOMETRY_IDS, - transformAdditionalRoadLines = true, - generateLongitudinalFillerSurfaces = false, - mappingBackwardsCompatibility = true - ) + fun deriveRoadspaces2Citygml2Parameters() = + Roadspaces2CitygmlParameters( + concurrentProcessing = false, + gmlIdPrefix = Roadspaces2CitygmlParameters.DEFAULT_GML_ID_PREFIX, + xlinkPrefix = Roadspaces2CitygmlParameters.DEFAULT_XLINK_PREFIX, + identifierAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_IDENTIFIER_ATTRIBUTES_PREFIX, + geometryAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_GEOMETRY_ATTRIBUTES_PREFIX, + flattenGenericAttributeSets = Roadspaces2CitygmlParameters.DEFAULT_FLATTEN_GENERIC_ATTRIBUTE_SETS, + discretizationStepSize = discretizationStepSize, + sweepDiscretizationStepSize = Roadspaces2CitygmlParameters.DEFAULT_SWEEP_DISCRETIZATION_STEP_SIZE, + circleSlices = Roadspaces2CitygmlParameters.DEFAULT_CIRCLE_SLICES, + generateRandomGeometryIds = Roadspaces2CitygmlParameters.DEFAULT_GENERATE_RANDOM_GEOMETRY_IDS, + transformAdditionalRoadLines = true, + generateLongitudinalFillerSurfaces = false, + mappingBackwardsCompatibility = true, + ) - fun deriveRoadspaces2Citygml3Parameters() = Roadspaces2CitygmlParameters( - concurrentProcessing = false, - gmlIdPrefix = Roadspaces2CitygmlParameters.DEFAULT_GML_ID_PREFIX, - xlinkPrefix = Roadspaces2CitygmlParameters.DEFAULT_XLINK_PREFIX, - identifierAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_IDENTIFIER_ATTRIBUTES_PREFIX, - geometryAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_GEOMETRY_ATTRIBUTES_PREFIX, - flattenGenericAttributeSets = Roadspaces2CitygmlParameters.DEFAULT_FLATTEN_GENERIC_ATTRIBUTE_SETS, - discretizationStepSize = discretizationStepSize, - sweepDiscretizationStepSize = Roadspaces2CitygmlParameters.DEFAULT_SWEEP_DISCRETIZATION_STEP_SIZE, - circleSlices = Roadspaces2CitygmlParameters.DEFAULT_CIRCLE_SLICES, - generateRandomGeometryIds = Roadspaces2CitygmlParameters.DEFAULT_GENERATE_RANDOM_GEOMETRY_IDS, - transformAdditionalRoadLines = true, - generateLongitudinalFillerSurfaces = false, - mappingBackwardsCompatibility = false - ) + fun deriveRoadspaces2Citygml3Parameters() = + Roadspaces2CitygmlParameters( + concurrentProcessing = false, + gmlIdPrefix = Roadspaces2CitygmlParameters.DEFAULT_GML_ID_PREFIX, + xlinkPrefix = Roadspaces2CitygmlParameters.DEFAULT_XLINK_PREFIX, + identifierAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_IDENTIFIER_ATTRIBUTES_PREFIX, + geometryAttributesPrefix = Roadspaces2CitygmlParameters.DEFAULT_GEOMETRY_ATTRIBUTES_PREFIX, + flattenGenericAttributeSets = Roadspaces2CitygmlParameters.DEFAULT_FLATTEN_GENERIC_ATTRIBUTE_SETS, + discretizationStepSize = discretizationStepSize, + sweepDiscretizationStepSize = Roadspaces2CitygmlParameters.DEFAULT_SWEEP_DISCRETIZATION_STEP_SIZE, + circleSlices = Roadspaces2CitygmlParameters.DEFAULT_CIRCLE_SLICES, + generateRandomGeometryIds = Roadspaces2CitygmlParameters.DEFAULT_GENERATE_RANDOM_GEOMETRY_IDS, + transformAdditionalRoadLines = true, + generateLongitudinalFillerSurfaces = false, + mappingBackwardsCompatibility = false, + ) } diff --git a/rtron-main/src/main/kotlin/io/rtron/main/processor/ValidateOpendriveProcessor.kt b/rtron-main/src/main/kotlin/io/rtron/main/processor/ValidateOpendriveProcessor.kt index 9085e579..266c70c9 100644 --- a/rtron-main/src/main/kotlin/io/rtron/main/processor/ValidateOpendriveProcessor.kt +++ b/rtron-main/src/main/kotlin/io/rtron/main/processor/ValidateOpendriveProcessor.kt @@ -37,32 +37,42 @@ import kotlin.io.path.Path import kotlin.io.path.div class ValidateOpendriveProcessor( - private val parameters: ValidateOpendriveParameters + private val parameters: ValidateOpendriveParameters, ) { - // Methods - fun process(inputPath: Path, outputPath: Path) { + fun process( + inputPath: Path, + outputPath: Path, + ) { val logger = KotlinLogging.logger {} processAllFiles( inputDirectoryPath = inputPath, withFilenameEndings = OpendriveReader.supportedFilenameEndings, - outputDirectoryPath = outputPath + outputDirectoryPath = outputPath, ) { // write the parameters as yaml file val parametersText = Yaml.default.encodeToString(ValidateOpendriveParameters.serializer(), parameters) (outputDirectoryPath / PARAMETERS_PATH).toFile().writeText(parametersText) // validate schema of OpenDRIVE model - val opendriveSchemaValidatorReport = OpendriveValidator.validateFromFile(inputFilePath).getOrElse { logger.warn { it.message }; return@processAllFiles } + val opendriveSchemaValidatorReport = + OpendriveValidator.validateFromFile(inputFilePath).getOrElse { + logger.warn { it.message } + return@processAllFiles + } opendriveSchemaValidatorReport.serializeToJsonFile(outputDirectoryPath / OPENDRIVE_SCHEMA_VALIDATOR_REPORT_PATH) if (opendriveSchemaValidatorReport.validationProcessAborted()) { return@processAllFiles } // read of OpenDRIVE model - val opendriveModel = OpendriveReader.readFromFile(inputFilePath) - .getOrElse { logger.warn { it.message }; return@processAllFiles } + val opendriveModel = + OpendriveReader.readFromFile(inputFilePath) + .getOrElse { + logger.warn { it.message } + return@processAllFiles + } // evaluate OpenDRIVE model val opendriveEvaluator = OpendriveEvaluator(parameters.deriveOpendriveEvaluatorParameters()) @@ -72,10 +82,11 @@ class ValidateOpendriveProcessor( logger.warn { opendriveEvaluatorResult.second.getTextSummary() } return@processAllFiles } - val modifiedOpendriveModel = opendriveEvaluatorResult.first.handleEmpty { - logger.warn { opendriveEvaluatorResult.second.getTextSummary() } - return@processAllFiles - } + val modifiedOpendriveModel = + opendriveEvaluatorResult.first.handleEmpty { + logger.warn { opendriveEvaluatorResult.second.getTextSummary() } + return@processAllFiles + } // write modified OpenDRIVE model if (parameters.writeOpendriveFile) { @@ -87,10 +98,11 @@ class ValidateOpendriveProcessor( val opendrive2RoadspacesTransformer = Opendrive2RoadspacesTransformer(parameters.deriveOpendrive2RoadspacesParameters()) val roadspacesModelResult = opendrive2RoadspacesTransformer.transform(modifiedOpendriveModel) roadspacesModelResult.second.serializeToJsonFile(outputDirectoryPath / OPENDRIVE_TO_ROADSPACES_REPORT_PATH) - val roadspacesModel = roadspacesModelResult.first.handleEmpty { - logger.warn { roadspacesModelResult.second.conversion.getTextSummary() } - return@processAllFiles - } + val roadspacesModel = + roadspacesModelResult.first.handleEmpty { + logger.warn { roadspacesModelResult.second.conversion.getTextSummary() } + return@processAllFiles + } // evaluate Roadspaces model val roadspacesEvaluator = RoadspacesEvaluator(parameters.deriveRoadspacesEvaluatorParameters()) diff --git a/rtron-main/src/main/kotlin/io/rtron/main/project/Project.kt b/rtron-main/src/main/kotlin/io/rtron/main/project/Project.kt index c48eda30..56161293 100644 --- a/rtron-main/src/main/kotlin/io/rtron/main/project/Project.kt +++ b/rtron-main/src/main/kotlin/io/rtron/main/project/Project.kt @@ -21,9 +21,8 @@ import kotlin.io.path.createDirectories data class Project( val inputFilePath: Path, - val outputDirectoryPath: Path + val outputDirectoryPath: Path, ) { - // Properties and Initializers init { outputDirectoryPath.createDirectories() diff --git a/rtron-main/src/main/kotlin/io/rtron/main/project/ProjectDSL.kt b/rtron-main/src/main/kotlin/io/rtron/main/project/ProjectDSL.kt index 297b3011..06ec14eb 100644 --- a/rtron-main/src/main/kotlin/io/rtron/main/project/ProjectDSL.kt +++ b/rtron-main/src/main/kotlin/io/rtron/main/project/ProjectDSL.kt @@ -35,7 +35,13 @@ import kotlin.time.measureTime * @param process user defined process to be executed */ @OptIn(ExperimentalTime::class) -fun processAllFiles(inputDirectoryPath: Path, withFilenameEndings: Set, outputDirectoryPath: Path, recursive: Boolean = true, process: Project.() -> Unit) { +fun processAllFiles( + inputDirectoryPath: Path, + withFilenameEndings: Set, + outputDirectoryPath: Path, + recursive: Boolean = true, + process: Project.() -> Unit, +) { val logger = KotlinLogging.logger {} if (!inputDirectoryPath.isDirectory()) { @@ -53,11 +59,12 @@ fun processAllFiles(inputDirectoryPath: Path, withFilenameEndings: Set, val recursiveDepth = if (recursive) Int.MAX_VALUE else 1 - val inputFilePaths = inputDirectoryPath - .walk(recursiveDepth) - .filter { path -> withFilenameEndings.any { path.fileName.toString().endsWith(it) } } - .toList() - .sorted() + val inputFilePaths = + inputDirectoryPath + .walk(recursiveDepth) + .filter { path -> withFilenameEndings.any { path.fileName.toString().endsWith(it) } } + .toList() + .sorted() if (inputFilePaths.isEmpty()) { logger.error { "No files have been found with $withFilenameEndings as extension in input directory: $outputDirectoryPath" } @@ -72,10 +79,11 @@ fun processAllFiles(inputDirectoryPath: Path, withFilenameEndings: Set, logger.info { "Starting project (${index + 1}/$totalNumber): $inputFileRelativePath" } - val timeElapsed = measureTime { - val project = Project(currentPath, projectOutputDirectoryPath) - project.apply(process) - } + val timeElapsed = + measureTime { + val project = Project(currentPath, projectOutputDirectoryPath) + project.apply(process) + } logger.info { "Completed project after $timeElapsed." + System.lineSeparator() } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/Fresnel.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/Fresnel.kt index 026954f2..7f8dc649 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/Fresnel.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/Fresnel.kt @@ -31,7 +31,6 @@ import kotlin.math.sin * y(l) = int_0^l sin( pi*t^2) / 2 ) dt */ object Fresnel { - /** * Evaluates both x(l) and y(l) of the normalized Fresnel integral. * @@ -78,97 +77,105 @@ object Fresnel { } } - /* S(x) for small x */ - private val sn = listOf( - 3.18016297876567817986E11, - -4.42979518059697779103E10, - 2.54890880573376359104E9, - -6.29741486205862506537E7, - 7.08840045257738576863E5, - -2.99181919401019853726E3 - ) - private val sd = listOf( - 6.07366389490084639049E11, - 2.24411795645340920940E10, - 4.19320245898111231129E8, - 5.17343888770096400730E6, - 4.55847810806532581675E4, - 2.81376268889994315696E2, - 1.00000000000000000000E0 - ) + // S(x) for small x + private val sn = + listOf( + 3.18016297876567817986E11, + -4.42979518059697779103E10, + 2.54890880573376359104E9, + -6.29741486205862506537E7, + 7.08840045257738576863E5, + -2.99181919401019853726E3, + ) + private val sd = + listOf( + 6.07366389490084639049E11, + 2.24411795645340920940E10, + 4.19320245898111231129E8, + 5.17343888770096400730E6, + 4.55847810806532581675E4, + 2.81376268889994315696E2, + 1.00000000000000000000E0, + ) - /* C(x) for small x */ - private val cn = listOf( - 9.99999999999999998822E-1, - -2.05525900955013891793E-1, - 1.88843319396703850064E-2, - -6.45191435683965050962E-4, - 9.50428062829859605134E-6, - -4.98843114573573548651E-8 - ) - private val cd = listOf( - 1.00000000000000000118E0, - 4.12142090722199792936E-2, - 8.68029542941784300606E-4, - 1.22262789024179030997E-5, - 1.25001862479598821474E-7, - 9.15439215774657478799E-10, - 3.99982968972495980367E-12 - ) + // C(x) for small x + private val cn = + listOf( + 9.99999999999999998822E-1, + -2.05525900955013891793E-1, + 1.88843319396703850064E-2, + -6.45191435683965050962E-4, + 9.50428062829859605134E-6, + -4.98843114573573548651E-8, + ) + private val cd = + listOf( + 1.00000000000000000118E0, + 4.12142090722199792936E-2, + 8.68029542941784300606E-4, + 1.22262789024179030997E-5, + 1.25001862479598821474E-7, + 9.15439215774657478799E-10, + 3.99982968972495980367E-12, + ) - /* Auxiliary function f(x) */ - private val fn = listOf( - 3.76329711269987889006E-20, - 1.34283276233062758925E-16, - 1.72010743268161828879E-13, - 1.02304514164907233465E-10, - 3.05568983790257605827E-8, - 4.63613749287867322088E-6, - 3.45017939782574027900E-4, - 1.15220955073585758835E-2, - 1.43407919780758885261E-1, - 4.21543555043677546506E-1 - ) - private val fd = listOf( - 1.25443237090011264384E-20, - 4.52001434074129701496E-17, - 5.88754533621578410010E-14, - 3.60140029589371370404E-11, - 1.12699224763999035261E-8, - 1.84627567348930545870E-6, - 1.55934409164153020873E-4, - 6.44051526508858611005E-3, - 1.16888925859191382142E-1, - 7.51586398353378947175E-1, - 1.00000000000000000000E0 - ) + // Auxiliary function f(x) + private val fn = + listOf( + 3.76329711269987889006E-20, + 1.34283276233062758925E-16, + 1.72010743268161828879E-13, + 1.02304514164907233465E-10, + 3.05568983790257605827E-8, + 4.63613749287867322088E-6, + 3.45017939782574027900E-4, + 1.15220955073585758835E-2, + 1.43407919780758885261E-1, + 4.21543555043677546506E-1, + ) + private val fd = + listOf( + 1.25443237090011264384E-20, + 4.52001434074129701496E-17, + 5.88754533621578410010E-14, + 3.60140029589371370404E-11, + 1.12699224763999035261E-8, + 1.84627567348930545870E-6, + 1.55934409164153020873E-4, + 6.44051526508858611005E-3, + 1.16888925859191382142E-1, + 7.51586398353378947175E-1, + 1.00000000000000000000E0, + ) - /* Auxiliary function g(x) */ - private val gn = listOf( - 1.86958710162783235106E-22, - 8.36354435630677421531E-19, - 1.37555460633261799868E-15, - 1.08268041139020870318E-12, - 4.45344415861750144738E-10, - 9.82852443688422223854E-8, - 1.15138826111884280931E-5, - 6.84079380915393090172E-4, - 1.87648584092575249293E-2, - 1.97102833525523411709E-1, - 5.04442073643383265887E-1 - ) - private val gd = listOf( - 1.86958710162783236342E-22, - 8.39158816283118707363E-19, - 1.38796531259578871258E-15, - 1.10273215066240270757E-12, - 4.60680728146520428211E-10, - 1.04314589657571990585E-7, - 1.27545075667729118702E-5, - 8.14679107184306179049E-4, - 2.53603741420338795122E-2, - 3.37748989120019970451E-1, - 1.47495759925128324529E0, - 1.00000000000000000000E0 - ) + // Auxiliary function g(x) + private val gn = + listOf( + 1.86958710162783235106E-22, + 8.36354435630677421531E-19, + 1.37555460633261799868E-15, + 1.08268041139020870318E-12, + 4.45344415861750144738E-10, + 9.82852443688422223854E-8, + 1.15138826111884280931E-5, + 6.84079380915393090172E-4, + 1.87648584092575249293E-2, + 1.97102833525523411709E-1, + 5.04442073643383265887E-1, + ) + private val gd = + listOf( + 1.86958710162783236342E-22, + 8.39158816283118707363E-19, + 1.38796531259578871258E-15, + 1.10273215066240270757E-12, + 4.60680728146520428211E-10, + 1.04314589657571990585E-7, + 1.27545075667729118702E-5, + 8.14679107184306179049E-4, + 2.53603741420338795122E-2, + 3.37748989120019970451E-1, + 1.47495759925128324529E0, + 1.00000000000000000000E0, + ) } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/BivariateFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/BivariateFunction.kt index f573933f..6776f51d 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/BivariateFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/BivariateFunction.kt @@ -24,7 +24,6 @@ import io.rtron.math.range.fuzzyContains * Function with exactly two parameters of the form z = f(x, y). */ abstract class BivariateFunction { - // Properties and Initializers /** function's domain for x */ @@ -34,7 +33,10 @@ abstract class BivariateFunction { abstract val domainY: Range // Methods - internal abstract fun valueUnbounded(x: Double, y: Double): Either + internal abstract fun valueUnbounded( + x: Double, + y: Double, + ): Either /** * Returns the value z = f(x, y). If [x] is not in [domainX] or [y] is not in [domainY] an error is returned. @@ -42,14 +44,17 @@ abstract class BivariateFunction { * @param x parameter x for the function evaluation * @param y parameter y for the function evaluation */ - fun value(x: Double, y: Double): Either { + fun value( + x: Double, + y: Double, + ): Either { return if (x in domainX && y in domainY) { valueUnbounded(x, y) } else { Either.Left( IllegalArgumentException( - "Value x=$x must be within in the defined $domainX and value y=$y within $domainY." - ) + "Value x=$x must be within in the defined $domainX and value y=$y within $domainY.", + ), ) } } @@ -62,12 +67,16 @@ abstract class BivariateFunction { * @param y parameter y for the function evaluation * @param tolerance allowed tolerance for fuzzy contains evaluation */ - fun valueInFuzzy(x: Double, y: Double, tolerance: Double): Either { + fun valueInFuzzy( + x: Double, + y: Double, + tolerance: Double, + ): Either { return if (!domainX.fuzzyContains(x, tolerance) || !domainY.fuzzyContains(y, tolerance)) { Either.Left( IllegalArgumentException( - "Value x=$x must be within in the defined $domainX and value y=$y within $domainY." - ) + "Value x=$x must be within in the defined $domainX and value y=$y within $domainY.", + ), ) } else { valueUnbounded(x, y) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/combination/SectionedBivariateFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/combination/SectionedBivariateFunction.kt index 153b6efd..91e6015c 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/combination/SectionedBivariateFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/combination/SectionedBivariateFunction.kt @@ -31,9 +31,8 @@ import io.rtron.math.range.shiftLowerEndpointTo class SectionedBivariateFunction( private val completeFunction: BivariateFunction, sectionX: Range, - sectionY: Range + sectionY: Range, ) : BivariateFunction() { - // Properties and Initializers override val domainX = if (sectionX.hasLowerBound()) sectionX.shiftLowerEndpointTo(0.0) else completeFunction.domainX @@ -45,6 +44,8 @@ class SectionedBivariateFunction( private val sectionYStart = sectionY.lowerEndpointOrNull() ?: 0.0 // Methods - override fun valueUnbounded(x: Double, y: Double) = - completeFunction.valueUnbounded(sectionXStart + x, sectionYStart + y) + override fun valueUnbounded( + x: Double, + y: Double, + ) = completeFunction.valueUnbounded(sectionXStart + x, sectionYStart + y) } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/pure/PlaneFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/pure/PlaneFunction.kt index dcdbe463..f12196a3 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/pure/PlaneFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/pure/PlaneFunction.kt @@ -32,9 +32,8 @@ class PlaneFunction( val slopeY: Double, val intercept: Double, override val domainX: Range = Range.all(), - override val domainY: Range = Range.all() + override val domainY: Range = Range.all(), ) : BivariateFunction() { - // Properties and Initializers init { require(slopeX.isFinite()) { "slopeX must be a finite value." } @@ -43,7 +42,10 @@ class PlaneFunction( } // Methods - override fun valueUnbounded(x: Double, y: Double): Either { + override fun valueUnbounded( + x: Double, + y: Double, + ): Either { return Either.Right(intercept + slopeX * x + slopeY * y) } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/pure/ShapeFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/pure/ShapeFunction.kt index 5da02cff..c4f95db7 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/pure/ShapeFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/bivariate/pure/ShapeFunction.kt @@ -38,9 +38,8 @@ import java.util.SortedMap class ShapeFunction( val functions: SortedMap, val extrapolateX: Boolean = false, - val extrapolateY: Boolean = false + val extrapolateY: Boolean = false, ) : BivariateFunction() { - // Properties and Initializers init { require(functions.isNotEmpty()) { "Must contain cross-sectional functions." } @@ -54,7 +53,10 @@ class ShapeFunction( // Methods - override fun valueUnbounded(x: Double, y: Double): Either { + override fun valueUnbounded( + x: Double, + y: Double, + ): Either { val xAdjusted = if (extrapolateX) x.coerceIn(minimumX, maximumX) else x if (xAdjusted in functions) { return calculateZ(xAdjusted, y) @@ -72,32 +74,39 @@ class ShapeFunction( /** * Returns the key of a function, which is located before [x]. */ - private fun getKeyBefore(x: Double): Either = functions - .filter { it.key < x } - .ifEmpty { return Either.Left(IllegalArgumentException("No relevant entry available.")) } - .toSortedMap() - .lastKey() - .let { Either.Right(it) } + private fun getKeyBefore(x: Double): Either = + functions + .filter { it.key < x } + .ifEmpty { return Either.Left(IllegalArgumentException("No relevant entry available.")) } + .toSortedMap() + .lastKey() + .let { Either.Right(it) } /** * Returns the key of a function, which is located after [x]. */ - private fun getKeyAfter(x: Double): Either = functions - .filter { x < it.key } - .ifEmpty { return Either.Left(IllegalArgumentException("No relevant entry available.")) } - .toSortedMap() - .firstKey() - .let { Either.Right(it) } + private fun getKeyAfter(x: Double): Either = + functions + .filter { x < it.key } + .ifEmpty { return Either.Left(IllegalArgumentException("No relevant entry available.")) } + .toSortedMap() + .firstKey() + .let { Either.Right(it) } - private fun calculateZ(key: Double, y: Double): Either = either { - val selectedFunction = functions.getValueEither(key).mapLeft { it.toIllegalArgumentException() }.bind() + private fun calculateZ( + key: Double, + y: Double, + ): Either = + either { + val selectedFunction = functions.getValueEither(key).mapLeft { it.toIllegalArgumentException() }.bind() - val yAdjusted = if (!extrapolateY) { - y - } else { - y.coerceIn(selectedFunction.domain.lowerEndpointOrNull(), selectedFunction.domain.upperEndpointOrNull()) - } + val yAdjusted = + if (!extrapolateY) { + y + } else { + y.coerceIn(selectedFunction.domain.lowerEndpointOrNull(), selectedFunction.domain.upperEndpointOrNull()) + } - selectedFunction.valueUnbounded(yAdjusted).bind() - } + selectedFunction.valueUnbounded(yAdjusted).bind() + } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/UnivariateFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/UnivariateFunction.kt index f9fd845e..d6cbc498 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/UnivariateFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/UnivariateFunction.kt @@ -26,8 +26,8 @@ import io.rtron.math.range.fuzzyContains * Function with exactly one parameter of the form z = f(x). */ abstract class UnivariateFunction : DefinableDomain { - // Properties and Initializers + /** * [startValue] = f(lowest endpoint of [domain]). */ @@ -40,11 +40,15 @@ abstract class UnivariateFunction : DefinableDomain { // Operators operator fun plus(other: UnivariateFunction) = StackedFunction.ofSum(this, other) + operator fun unaryMinus() = StackedFunction(this, { -it[0] }) + operator fun times(m: Double) = StackedFunction(this, { it[0] * m }) + operator fun div(m: Double) = StackedFunction(this, { it[0] / m }) // Methods + /** * Evaluation of z = f(x) without checking whether x is within the function's [domain]. * @@ -59,10 +63,11 @@ abstract class UnivariateFunction : DefinableDomain { * @param x parameter [x] of function * @return returns Result.Success(z) = f(x), if [x] is strictly contained in [domain] and evaluation was successful */ - fun value(x: Double): Either = either { - domain.containsResult(x).bind() - valueUnbounded(x).bind() - } + fun value(x: Double): Either = + either { + domain.containsResult(x).bind() + valueUnbounded(x).bind() + } /** * Evaluation of z = f(x) with fuzzy checking whether x is within the function's [domain]. @@ -71,7 +76,10 @@ abstract class UnivariateFunction : DefinableDomain { * @param tolerance allowed tolerance for fuzzy checking * @return returns Result.Success(z) = f(x), if [x] is fuzzily contained in [domain] and evaluation was successful */ - open fun valueInFuzzy(x: Double, tolerance: Double): Either { + open fun valueInFuzzy( + x: Double, + tolerance: Double, + ): Either { return if (!domain.fuzzyContains(x, tolerance)) { Either.Left(IllegalArgumentException("Value x=$x must be within in the defined $domain.")) } else { @@ -108,7 +116,10 @@ abstract class UnivariateFunction : DefinableDomain { * @return returns Result.Success(slope) = f(x), if [x] is fuzzily contained in [domain] and evaluation was * successful */ - fun slopeInFuzzy(x: Double, tolerance: Double): Either { + fun slopeInFuzzy( + x: Double, + tolerance: Double, + ): Either { return if (!domain.fuzzyContains(x, tolerance)) { Either.Left(IllegalArgumentException("Value x=$x must be within in the defined $domain.")) } else { diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/ConcatenatedFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/ConcatenatedFunction.kt index 6e2f4e03..922e36ad 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/ConcatenatedFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/ConcatenatedFunction.kt @@ -39,28 +39,33 @@ import io.rtron.std.isStrictlySorted class ConcatenatedFunction( memberFunctions: List, absoluteDomains: List>, - absoluteStarts: List + absoluteStarts: List, ) : UnivariateFunction() { - // Properties and Initializers private val container = ConcatenationContainer(memberFunctions, absoluteDomains, absoluteStarts) override val domain: Range get() = container.domain // Methods - override fun valueUnbounded(x: Double): Either = either { - val localMember = container.strictSelectMember(x).bind() - localMember.member.valueUnbounded(localMember.localParameter).bind() - } + override fun valueUnbounded(x: Double): Either = + either { + val localMember = container.strictSelectMember(x).bind() + localMember.member.valueUnbounded(localMember.localParameter).bind() + } - override fun slopeUnbounded(x: Double): Either = either { - val localMember = container.strictSelectMember(x).bind() - localMember.member.slopeUnbounded(localMember.localParameter).bind() - } + override fun slopeUnbounded(x: Double): Either = + either { + val localMember = container.strictSelectMember(x).bind() + localMember.member.slopeUnbounded(localMember.localParameter).bind() + } - override fun valueInFuzzy(x: Double, tolerance: Double): Either = either { - val localMember = container.fuzzySelectMember(x, tolerance).bind() - localMember.member.valueUnbounded(localMember.localParameter).bind() - } + override fun valueInFuzzy( + x: Double, + tolerance: Double, + ): Either = + either { + val localMember = container.fuzzySelectMember(x, tolerance).bind() + localMember.member.valueUnbounded(localMember.localParameter).bind() + } override fun equals(other: Any?): Boolean { if (this === other) return true @@ -76,7 +81,6 @@ class ConcatenatedFunction( } companion object { - /** * Creates a concatenated function of a list of linear functions, whereby the slopes are adjusted so that the * concatenated function is continuous. @@ -94,7 +98,7 @@ class ConcatenatedFunction( starts: List, intercepts: List, prependConstant: Boolean = false, - appendConstant: Boolean = true + appendConstant: Boolean = true, ): UnivariateFunction { require(starts.isNotEmpty() && intercepts.isNotEmpty()) { "List of starts and intercepts must not be empty." } require(starts.hasSameSizeAs(intercepts)) { "Equally sized starts and intercepts required." } @@ -107,49 +111,57 @@ class ConcatenatedFunction( // prepare linear functions val preparedStarts = starts.dropLast(1) - val preparedLinearFunctions = slopes.zip(intercepts) - .map { LinearFunction(it.first, it.second) } - val preparedAbsoluteDomains = starts - .zipWithNext() - .map { Range.closedOpen(it.first, it.second) } + val preparedLinearFunctions = + slopes.zip(intercepts) + .map { LinearFunction(it.first, it.second) } + val preparedAbsoluteDomains = + starts + .zipWithNext() + .map { Range.closedOpen(it.first, it.second) } // prepend function, if necessary - val prependedStart = if (prependConstant) { - listOf(Double.MIN_VALUE) - } else { - emptyList() - } - val prependedFunction = if (prependConstant) { - listOf(ConstantFunction(intercepts.first())) - } else { - emptyList() - } - val prependedAbsoluteDomain = if (prependConstant) { - listOf(Range.lessThan(starts.first())) - } else { - emptyList() - } + val prependedStart = + if (prependConstant) { + listOf(Double.MIN_VALUE) + } else { + emptyList() + } + val prependedFunction = + if (prependConstant) { + listOf(ConstantFunction(intercepts.first())) + } else { + emptyList() + } + val prependedAbsoluteDomain = + if (prependConstant) { + listOf(Range.lessThan(starts.first())) + } else { + emptyList() + } // append function, if necessary - val appendedStart = if (appendConstant) { - listOf(starts.last()) - } else { - emptyList() - } - val appendedFunction = if (appendConstant) { - listOf(ConstantFunction(intercepts.last())) - } else { - emptyList() - } - val appendedAbsoluteDomain = if (appendConstant) { - listOf(Range.atLeast(starts.last())) - } else { - emptyList() - } + val appendedStart = + if (appendConstant) { + listOf(starts.last()) + } else { + emptyList() + } + val appendedFunction = + if (appendConstant) { + listOf(ConstantFunction(intercepts.last())) + } else { + emptyList() + } + val appendedAbsoluteDomain = + if (appendConstant) { + listOf(Range.atLeast(starts.last())) + } else { + emptyList() + } return ConcatenatedFunction( prependedFunction + preparedLinearFunctions + appendedFunction, prependedAbsoluteDomain + preparedAbsoluteDomains + appendedAbsoluteDomain, - prependedStart + preparedStarts + appendedStart + prependedStart + preparedStarts + appendedStart, ) } @@ -169,45 +181,51 @@ class ConcatenatedFunction( starts: NonEmptyList, coefficients: NonEmptyList, prependConstant: Boolean = false, - prependConstantValue: Double = Double.NaN + prependConstantValue: Double = Double.NaN, ): UnivariateFunction { require(starts.hasSameSizeAs(coefficients)) { "Equally sized starts and coefficients required." } require(starts.isStrictlySorted()) { "Polynomials must be sorted in strict ascending order." } // prepare polynomial functions and domains - val polynomialFunctions = coefficients - .map { PolynomialFunction(it) } - val absoluteDomains = starts - .zipWithNext() - .map { Range.closedOpen(it.first, it.second) } + Range.atLeast(starts.last()) + val polynomialFunctions = + coefficients + .map { PolynomialFunction(it) } + val absoluteDomains = + starts + .zipWithNext() + .map { Range.closedOpen(it.first, it.second) } + Range.atLeast(starts.last()) // prepend function, if necessary - val prependedStart = if (prependConstant) { - listOf(Double.MIN_VALUE) - } else { - emptyList() - } - val prependedFunction = if (prependConstant) { - val prependValue = if (prependConstantValue.isFinite()) { - prependConstantValue + val prependedStart = + if (prependConstant) { + listOf(Double.MIN_VALUE) } else { - polynomialFunctions.first().value(0.0).getOrElse { throw it } + emptyList() + } + val prependedFunction = + if (prependConstant) { + val prependValue = + if (prependConstantValue.isFinite()) { + prependConstantValue + } else { + polynomialFunctions.first().value(0.0).getOrElse { throw it } + } + + listOf(ConstantFunction(prependValue)) + } else { + emptyList() + } + val prependedAbsoluteDomain = + if (prependConstant) { + listOf(Range.lessThan(starts.first())) + } else { + emptyList() } - - listOf(ConstantFunction(prependValue)) - } else { - emptyList() - } - val prependedAbsoluteDomain = if (prependConstant) { - listOf(Range.lessThan(starts.first())) - } else { - emptyList() - } return ConcatenatedFunction( prependedFunction + polynomialFunctions, prependedAbsoluteDomain + absoluteDomains, - prependedStart + starts + prependedStart + starts, ) } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/SectionedUnivariateFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/SectionedUnivariateFunction.kt index 6505310a..cedb7942 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/SectionedUnivariateFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/SectionedUnivariateFunction.kt @@ -31,17 +31,14 @@ import io.rtron.math.range.shiftLowerEndpointTo */ class SectionedUnivariateFunction( private val completeFunction: UnivariateFunction, - section: Range + section: Range, ) : UnivariateFunction() { - // Properties and Initializers override val domain: Range = section.shiftLowerEndpointTo(0.0) private val sectionStart = section.lowerEndpointResult().getOrElse { throw it } // Methods - override fun valueUnbounded(x: Double): Either = - completeFunction.valueUnbounded(sectionStart + x) + override fun valueUnbounded(x: Double): Either = completeFunction.valueUnbounded(sectionStart + x) - override fun slopeUnbounded(x: Double): Either = - completeFunction.slopeUnbounded(sectionStart + x) + override fun slopeUnbounded(x: Double): Either = completeFunction.slopeUnbounded(sectionStart + x) } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/StackedFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/StackedFunction.kt index 15385f37..7a83d8e9 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/StackedFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/combination/StackedFunction.kt @@ -33,9 +33,8 @@ import io.rtron.math.range.unionRanges class StackedFunction( private val memberFunctions: List, private val operation: (operands: List) -> Double, - private val defaultValue: Double = Double.NaN + private val defaultValue: Double = Double.NaN, ) : UnivariateFunction() { - // Properties and Initializers init { require(memberFunctions.isNotEmpty()) { "Must contain member functions." } @@ -52,7 +51,7 @@ class StackedFunction( constructor( memberFunction: UnivariateFunction, operation: (operands: List) -> Double, - defaultValue: Double = Double.NaN + defaultValue: Double = Double.NaN, ) : this(listOf(memberFunction), operation, defaultValue) @@ -92,15 +91,16 @@ class StackedFunction( } companion object { - /** * Creates a [StackedFunction] which serves sum of each [memberFunctions]. * * @param memberFunctions member functions to be summed * @param defaultValue used value if one of the [memberFunctions] is not defined at the requested parameter */ - fun ofSum(memberFunctions: List, defaultValue: Double = Double.NaN): StackedFunction = - StackedFunction(memberFunctions, { it.sum() }, defaultValue) + fun ofSum( + memberFunctions: List, + defaultValue: Double = Double.NaN, + ): StackedFunction = StackedFunction(memberFunctions, { it.sum() }, defaultValue) /** * Creates a [StackedFunction] which serves sum of each [memberFunctions]. @@ -108,7 +108,9 @@ class StackedFunction( * @param memberFunctions member functions to be summed * @param defaultValue used value if one of the [memberFunctions] is not defined at the requested parameter */ - fun ofSum(vararg memberFunctions: UnivariateFunction, defaultValue: Double = Double.NaN): StackedFunction = - StackedFunction(memberFunctions.toList(), { it.sum() }, defaultValue) + fun ofSum( + vararg memberFunctions: UnivariateFunction, + defaultValue: Double = Double.NaN, + ): StackedFunction = StackedFunction(memberFunctions.toList(), { it.sum() }, defaultValue) } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/ConstantFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/ConstantFunction.kt index d44e8a36..89fe5034 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/ConstantFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/ConstantFunction.kt @@ -28,9 +28,8 @@ import io.rtron.math.range.Range */ data class ConstantFunction( val value: Double, - override val domain: Range = Range.all() + override val domain: Range = Range.all(), ) : UnivariateFunction() { - // Properties and Initializers init { require(value.isFinite()) { "Value must be finite, but was $value." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/LinearFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/LinearFunction.kt index 99fac167..e8726a76 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/LinearFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/LinearFunction.kt @@ -36,9 +36,8 @@ import kotlin.math.sign data class LinearFunction( val slope: Double, val intercept: Double = 0.0, - override val domain: Range = Range.all() + override val domain: Range = Range.all(), ) : UnivariateFunction() { - // Properties and Initializers init { require(slope.isFinite()) { "Slope must be a finite value." } @@ -46,13 +45,11 @@ data class LinearFunction( } // Methods - override fun valueUnbounded(x: Double): Either = - Either.Right(slope * x + intercept) + override fun valueUnbounded(x: Double): Either = Either.Right(slope * x + intercept) override fun slopeUnbounded(x: Double): Either = Either.Right(slope) companion object { - /** * Linear function representing the x-axis. */ @@ -65,7 +62,10 @@ data class LinearFunction( * @param intercept linear function starting at (0.0, [intercept]) * @param pointY linear function stopping at ([pointY] - [intercept] , [pointY]) */ - fun ofInclusiveYValuesAndUnitSlope(intercept: Double, pointY: Double): LinearFunction { + fun ofInclusiveYValuesAndUnitSlope( + intercept: Double, + pointY: Double, + ): LinearFunction { require(intercept.isFinite()) { "Intercept must be a finite value." } require(pointY.isFinite()) { "PointY must be a finite value." } @@ -82,7 +82,11 @@ data class LinearFunction( * @param pointX linear function stopping at ([pointX], [pointY]) * @param pointY linear function stopping at ([pointX], [pointY]) */ - fun ofInclusiveInterceptAndPoint(intercept: Double, pointX: Double, pointY: Double): LinearFunction { + fun ofInclusiveInterceptAndPoint( + intercept: Double, + pointX: Double, + pointY: Double, + ): LinearFunction { require(intercept.isFinite()) { "Intercept must be finite." } require(pointX.isFinite() && pointX != 0.0) { "Point must not be located on the y axis." } require(pointY.isFinite()) { "PointY must be finite." } @@ -101,18 +105,24 @@ data class LinearFunction( * @param pointX linear function stopping at ([pointX], [pointY]) * @param pointY linear function stopping at ([pointX], [pointY]) */ - fun ofInclusiveInterceptAndPoint(intercept: Option, pointX: Double, pointY: Option): LinearFunction { + fun ofInclusiveInterceptAndPoint( + intercept: Option, + pointX: Double, + pointY: Option, + ): LinearFunction { require(intercept.isSome { it.isFinite() }) { "Intercept must be finite, if defined." } require(pointX.isFinite()) { "PointX must be finite." } require(pointY.isSome { it.isFinite() }) { "PointY must be finite, if defined." } require(intercept.isSome() || pointY.isSome()) { "Either intercept or pointY must be finite." } - val adjustedIntercept = intercept.getOrElse { - pointY.toEither { IllegalStateException("PointY must be set.") }.getOrElse { throw it } - } - val adjustedPointY = pointY.getOrElse { - intercept.toEither { IllegalStateException("Intercept must be set.") }.getOrElse { throw it } - } + val adjustedIntercept = + intercept.getOrElse { + pointY.toEither { IllegalStateException("PointY must be set.") }.getOrElse { throw it } + } + val adjustedPointY = + pointY.getOrElse { + intercept.toEither { IllegalStateException("Intercept must be set.") }.getOrElse { throw it } + } return ofInclusiveInterceptAndPoint(adjustedIntercept, pointX, adjustedPointY) } @@ -127,7 +137,12 @@ data class LinearFunction( * * @return linear function with inclusive starting and stopping points */ - fun ofInclusivePoints(point1X: Double, point1Y: Double, point2X: Double, point2Y: Double): LinearFunction { + fun ofInclusivePoints( + point1X: Double, + point1Y: Double, + point2X: Double, + point2Y: Double, + ): LinearFunction { require(!(point1X == point2X && point1Y == point2Y)) { "Points are required to be different." } val slope = (point2Y - point1Y) / (point2X - point1X) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/PolynomialFunction.kt b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/PolynomialFunction.kt index b2bc29a1..9ff89488 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/PolynomialFunction.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/analysis/function/univariate/pure/PolynomialFunction.kt @@ -32,9 +32,8 @@ fun CMPolynomialFunction.toPolynomialFunction() = PolynomialFunction(this.coeffi */ data class PolynomialFunction( val coefficients: DoubleArray, - override val domain: Range = Range.all() + override val domain: Range = Range.all(), ) : UnivariateFunction() { - // Properties and Initializers init { require(coefficients.isNotEmpty()) { "At least one coefficient must be given." } @@ -54,11 +53,9 @@ data class PolynomialFunction( constructor(coefficients: List) : this(coefficients.toDoubleArray()) // Methods - override fun valueUnbounded(x: Double): Either = - Either.Right(polynomialFunction.value(x)) + override fun valueUnbounded(x: Double): Either = Either.Right(polynomialFunction.value(x)) - override fun slopeUnbounded(x: Double): Either = - polynomialDerivative.valueUnbounded(x) + override fun slopeUnbounded(x: Double): Either = polynomialDerivative.valueUnbounded(x) /** * Returns the calculated value of f(x), if [x] is within the function's domain. Otherwise null is returned. @@ -90,7 +87,6 @@ data class PolynomialFunction( } companion object { - /** * Build a polynomial function with providing its length, which is used to construct the domain [0, [length] * @@ -98,8 +94,11 @@ data class PolynomialFunction( * @param length the length of the domain [0, length] * @param upperBoundType open or closed upper bound type */ - fun of(coefficients: DoubleArray, length: Double, upperBoundType: BoundType = BoundType.OPEN): - PolynomialFunction { + fun of( + coefficients: DoubleArray, + length: Double, + upperBoundType: BoundType = BoundType.OPEN, + ): PolynomialFunction { require(length > 0.0) { "Length must be greater than zero." } return when { diff --git a/rtron-math/src/main/kotlin/io/rtron/math/container/ConcatenationContainer.kt b/rtron-math/src/main/kotlin/io/rtron/math/container/ConcatenationContainer.kt index 5f85f8c2..7c4fede4 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/container/ConcatenationContainer.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/container/ConcatenationContainer.kt @@ -41,9 +41,8 @@ class ConcatenationContainer>( private val members: List, private val absoluteDomains: List>, private val absoluteStarts: List, - private val tolerance: Double = 0.0 + private val tolerance: Double = 0.0, ) { - // Properties and Initializers init { require(members.isNotEmpty()) { "Must contain members for concatenation." } @@ -63,7 +62,11 @@ class ConcatenationContainer>( } else { absoluteDomainsWithoutStart.dropLast(1) } - require(absoluteDomainsWithoutEndings.all { it.hasLowerBound() && it.hasUpperBound() }) { "All absolute domains (apart from the first and last one) must have an upper and lower bound." } + require( + absoluteDomainsWithoutEndings.all { + it.hasLowerBound() && it.hasUpperBound() + }, + ) { "All absolute domains (apart from the first and last one) must have an upper and lower bound." } require(absoluteDomainsWithoutEndings.isSortedBy { it.lowerEndpointOrNull()!! }) { "Provided absolute domains must be sorted." } // requirement: no intersecting domains @@ -74,7 +77,7 @@ class ConcatenationContainer>( members.zip(absoluteStarts) .map { it.first.domain.shift(it.second) } .zip(absoluteDomains) - .all { it.first.fuzzyEncloses(it.second, tolerance) } + .all { it.first.fuzzyEncloses(it.second, tolerance) }, ) { "The local domains must be defined everywhere where the absolute (shifted) domain is also defined." } } @@ -96,10 +99,11 @@ class ConcatenationContainer>( * @param parameter absolute parameter */ fun strictSelectMember(parameter: Double): Either> { - val selection = absoluteDomains - .withIndex() - .filter { parameter in it.value } - .map { it.index } + val selection = + absoluteDomains + .withIndex() + .filter { parameter in it.value } + .map { it.index } return handleSelection(parameter, selection) } @@ -110,13 +114,17 @@ class ConcatenationContainer>( * @param parameter absolute parameter * @param tolerance applied tolerance for the fuzzy selection */ - fun fuzzySelectMember(parameter: Double, tolerance: Double): Either> { + fun fuzzySelectMember( + parameter: Double, + tolerance: Double, + ): Either> { strictSelectMember(parameter).onRight { return it.right() } - val selection = absoluteDomains - .withIndex() - .filter { it.value.fuzzyContains(parameter, tolerance) } - .map { it.index } + val selection = + absoluteDomains + .withIndex() + .filter { it.value.fuzzyContains(parameter, tolerance) } + .map { it.index } return handleSelection(parameter, selection) } @@ -127,15 +135,19 @@ class ConcatenationContainer>( * @param parameter absolute parameter * @param selection list of selected members */ - private fun handleSelection(parameter: Double, selection: List): - Either> = when (selection.size) { - 0 -> Either.Left( - IllegalArgumentException("Parameter x=$parameter must be within in the domain $absoluteDomains.") - ) - 1 -> { - val localParameter = parameter - absoluteStarts[selection.first()] - Either.Right(LocalRequest(localParameter, members[selection.first()])) + private fun handleSelection( + parameter: Double, + selection: List, + ): Either> = + when (selection.size) { + 0 -> + Either.Left( + IllegalArgumentException("Parameter x=$parameter must be within in the domain $absoluteDomains."), + ) + 1 -> { + val localParameter = parameter - absoluteStarts[selection.first()] + Either.Right(LocalRequest(localParameter, members[selection.first()])) + } + else -> Either.Left(IllegalStateException("Parameter x=$parameter yields multiple members.")) } - else -> Either.Left(IllegalStateException("Parameter x=$parameter yields multiple members.")) - } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/GeometryException.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/GeometryException.kt index c8e4d629..fcc782a7 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/GeometryException.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/GeometryException.kt @@ -17,13 +17,24 @@ package io.rtron.math.geometry sealed class GeometryException(val message: String, val exceptionIdentifier: String) { + data class BoundaryRepresentationGenerationError( + val reason: String, + ) : GeometryException("Cannot generate bounding representation: $reason.", "BoundaryRepresentationGenerationError") - data class BoundaryRepresentationGenerationError(val reason: String) : GeometryException("Cannot generate bounding representation: $reason.", "BoundaryRepresentationGenerationError") + data class NotEnoughValidLinearRings(val suffix: String = "") : GeometryException( + "Not enough valid linear rings could be constructed$suffix.", + "NotEnoughValidLinearRings", + ) - data class NotEnoughValidLinearRings(val suffix: String = "") : GeometryException("Not enough valid linear rings could be constructed$suffix.", "NotEnoughValidLinearRings") + data class NotEnoughVertices(val suffix: String = "") : GeometryException( + "Not enough valid linear rings could be constructed$suffix.", + "NotEnoughVertices", + ) - data class NotEnoughVertices(val suffix: String = "") : GeometryException("Not enough valid linear rings could be constructed$suffix.", "NotEnoughVertices") - data class ValueNotContainedInDomain(val value: Double) : GeometryException("Value ($value) not contained in domain of geometry.", "ValueNotContainedInDomain") + data class ValueNotContainedInDomain(val value: Double) : GeometryException( + "Value ($value) not contained in domain of geometry.", + "ValueNotContainedInDomain", + ) } fun GeometryException.toIllegalStateException(): IllegalStateException = IllegalStateException(message) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/oned/point/CurveRelativeVector1D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/oned/point/CurveRelativeVector1D.kt index 6fb8b4a8..6a30316c 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/oned/point/CurveRelativeVector1D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/oned/point/CurveRelativeVector1D.kt @@ -26,9 +26,8 @@ import io.rtron.math.geometry.curved.twod.point.CurveRelativeVector2D * @param curvePosition distance between the start of the curve and the point to be referenced */ data class CurveRelativeVector1D( - val curvePosition: Double + val curvePosition: Double, ) : Comparable { - // Properties and Initializers init { require(curvePosition.isFinite()) { "Curve position value must be finite." } @@ -36,18 +35,22 @@ data class CurveRelativeVector1D( // Operators operator fun plus(v: CurveRelativeVector1D) = CurveRelativeVector1D(this.curvePosition + v.curvePosition) + operator fun minus(v: CurveRelativeVector1D) = CurveRelativeVector1D(this.curvePosition - v.curvePosition) + operator fun times(m: Double) = CurveRelativeVector1D(this.curvePosition * m) + operator fun div(m: Double) = CurveRelativeVector1D(this.curvePosition / m) override fun compareTo(other: CurveRelativeVector1D): Int = curvePosition.compareTo(other.curvePosition) // Conversions - fun toCurveRelative2D(lateralOffset: Double = 0.0) = - CurveRelativeVector2D(curvePosition, lateralOffset) + fun toCurveRelative2D(lateralOffset: Double = 0.0) = CurveRelativeVector2D(curvePosition, lateralOffset) - fun toCurveRelative3D(lateralOffset: Double = 0.0, heightOffset: Double = 0.0) = - CurveRelativeVector3D(curvePosition, lateralOffset, heightOffset) + fun toCurveRelative3D( + lateralOffset: Double = 0.0, + heightOffset: Double = 0.0, + ) = CurveRelativeVector3D(curvePosition, lateralOffset, heightOffset) companion object { val ZERO = CurveRelativeVector1D(0.0) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/curve/CurveRelativeLineSegment3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/curve/CurveRelativeLineSegment3D.kt index e2afec9f..aafef2cd 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/curve/CurveRelativeLineSegment3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/curve/CurveRelativeLineSegment3D.kt @@ -36,9 +36,8 @@ class CurveRelativeLineSegment3D( val start: CurveRelativeVector3D, val end: CurveRelativeVector3D, override val tolerance: Double, - val endBoundType: BoundType = BoundType.CLOSED + val endBoundType: BoundType = BoundType.CLOSED, ) : CurveRelativeAbstractGeometry3D(), Tolerable { - // Properties and Initializers init { require(start != end) { "Start and end vector must not be identical." } @@ -46,18 +45,22 @@ class CurveRelativeLineSegment3D( } companion object { - /** * Creates a [LineSegment3D], if [start] and [end] [Vector3D] are not fuzzily equal according to the [tolerance]. * */ - fun of(start: CurveRelativeVector3D, end: CurveRelativeVector3D, tolerance: Double, endBoundType: BoundType = BoundType.CLOSED): Either = + fun of( + start: CurveRelativeVector3D, + end: CurveRelativeVector3D, + tolerance: Double, + endBoundType: BoundType = BoundType.CLOSED, + ): Either = if (start.fuzzyEquals(end, tolerance)) { Either.Left( IllegalArgumentException( "Start and end vector of a line segment must be different " + - "according to the given tolerance." - ) + "according to the given tolerance.", + ), ) } else { Either.Right(CurveRelativeLineSegment3D(start, end, tolerance, endBoundType)) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/point/CurveRelativeVector3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/point/CurveRelativeVector3D.kt index 1e7e0c6a..7019cd85 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/point/CurveRelativeVector3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/point/CurveRelativeVector3D.kt @@ -34,9 +34,8 @@ import io.rtron.math.std.fuzzyEquals as doubleFuzzyEquals data class CurveRelativeVector3D( val curvePosition: Double, val lateralOffset: Double = 0.0, - val heightOffset: Double = 0.0 + val heightOffset: Double = 0.0, ) : CurveRelativeAbstractGeometry3D() { - // Properties and Initializers init { require(curvePosition.isFinite()) { "Curve position value must be finite." } @@ -50,18 +49,24 @@ data class CurveRelativeVector3D( * Returns true, if [curvePosition], [lateralOffset] and [heightOffset] are all fuzzily equal with a tolerance * of [tolerance]. */ - fun fuzzyEquals(o: CurveRelativeVector3D, tolerance: Double) = - doubleFuzzyEquals(this.curvePosition, o.curvePosition, tolerance) && - doubleFuzzyEquals(this.lateralOffset, o.lateralOffset, tolerance) && - doubleFuzzyEquals(this.heightOffset, o.heightOffset, tolerance) + fun fuzzyEquals( + o: CurveRelativeVector3D, + tolerance: Double, + ) = doubleFuzzyEquals(this.curvePosition, o.curvePosition, tolerance) && + doubleFuzzyEquals(this.lateralOffset, o.lateralOffset, tolerance) && + doubleFuzzyEquals(this.heightOffset, o.heightOffset, tolerance) - fun fuzzyUnequals(o: CurveRelativeVector3D, tolerance: Double) = !fuzzyEquals(o, tolerance) + fun fuzzyUnequals( + o: CurveRelativeVector3D, + tolerance: Double, + ) = !fuzzyEquals(o, tolerance) // Methods fun getCartesianCurveOffset() = Vector3D(0.0, lateralOffset, heightOffset) // Conversions fun toCurveRelative1D() = CurveRelativeVector1D(curvePosition) + fun toCurveRelative2D() = CurveRelativeVector2D(curvePosition, lateralOffset) companion object { @@ -71,8 +76,11 @@ data class CurveRelativeVector3D( * Creates a [CurveRelativeVector3D] by a [curvePosition], [lateralOffset] and [heightOffset]. If one of the * values is not finite, an error is returned. */ - fun of(curvePosition: Double, lateralOffset: Double, heightOffset: Double): - Either = + fun of( + curvePosition: Double, + lateralOffset: Double, + heightOffset: Double, + ): Either = if (!curvePosition.isFinite() || !lateralOffset.isFinite() || !heightOffset.isFinite()) { Either.Left(IllegalArgumentException("CurvePosition, lateralOffset, heightOffset must be finite.")) } else { diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/AbstractCurveRelativeSurface3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/AbstractCurveRelativeSurface3D.kt index 64412b2a..cf83d44b 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/AbstractCurveRelativeSurface3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/AbstractCurveRelativeSurface3D.kt @@ -31,7 +31,6 @@ import io.rtron.math.range.length * Abstract class for all geometric surface objects in an curve relative coordinate system in 3D. */ abstract class AbstractCurveRelativeSurface3D : DefinableDomain, Tolerable { - // Properties and Initializers /** length of the surface along the curve */ @@ -48,8 +47,10 @@ abstract class AbstractCurveRelativeSurface3D : DefinableDomain, Tolerab * @param addHeightOffset adds an additional height offset to the surface * @return point in cartesian coordinates */ - fun calculatePointGlobalCS(curveRelativePoint: CurveRelativeVector2D, addHeightOffset: Double = 0.0): - Either { + fun calculatePointGlobalCS( + curveRelativePoint: CurveRelativeVector2D, + addHeightOffset: Double = 0.0, + ): Either { if (!domain.fuzzyContains(curveRelativePoint.curvePosition, tolerance)) { return GeometryException.ValueNotContainedInDomain(curveRelativePoint.curvePosition).left() } @@ -65,5 +66,8 @@ abstract class AbstractCurveRelativeSurface3D : DefinableDomain, Tolerab * @param addHeightOffset adds an additional height offset to the surface * @return point in cartesian coordinates */ - abstract fun calculatePointGlobalCSUnbounded(curveRelativePoint: CurveRelativeVector2D, addHeightOffset: Double): Vector3D + abstract fun calculatePointGlobalCSUnbounded( + curveRelativePoint: CurveRelativeVector2D, + addHeightOffset: Double, + ): Vector3D } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/CurveRelativeParametricSurface3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/CurveRelativeParametricSurface3D.kt index d97feee0..a9842e69 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/CurveRelativeParametricSurface3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/CurveRelativeParametricSurface3D.kt @@ -34,24 +34,29 @@ import io.rtron.math.range.fuzzyEncloses */ class CurveRelativeParametricSurface3D( private val baseCurve: Curve3D, - private val heightFunction: BivariateFunction = PlaneFunction.ZERO + private val heightFunction: BivariateFunction = PlaneFunction.ZERO, ) : AbstractCurveRelativeSurface3D() { - // Properties and Initializers override val tolerance: Double get() = baseCurve.tolerance override val domain get() = baseCurve.domain init { - require(heightFunction.domainX.fuzzyEncloses(baseCurve.domain, tolerance)) { "The height function must be defined everywhere where the referenceLine is also defined." } + require(heightFunction.domainX.fuzzyEncloses(baseCurve.domain, tolerance)) { + "The height function must be defined everywhere where the referenceLine is also defined." + } require(length > tolerance) { "Length must be greater than zero as well as the tolerance threshold." } } // Methods - override fun calculatePointGlobalCSUnbounded(curveRelativePoint: CurveRelativeVector2D, addHeightOffset: Double): Vector3D { + override fun calculatePointGlobalCSUnbounded( + curveRelativePoint: CurveRelativeVector2D, + addHeightOffset: Double, + ): Vector3D { val affine = baseCurve.calculateAffine(curveRelativePoint.toCurveRelative1D()) - val surfaceHeight = heightFunction - .valueInFuzzy(curveRelativePoint.curvePosition, curveRelativePoint.lateralOffset, tolerance) - .getOrElse { throw it } + val surfaceHeight = + heightFunction + .valueInFuzzy(curveRelativePoint.curvePosition, curveRelativePoint.lateralOffset, tolerance) + .getOrElse { throw it } val offset = Vector3D(0.0, curveRelativePoint.lateralOffset, surfaceHeight + addHeightOffset) return affine.transform(offset) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/SectionedCurveRelativeParametricSurface3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/SectionedCurveRelativeParametricSurface3D.kt index 7f11f8f7..d1e6ed78 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/SectionedCurveRelativeParametricSurface3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/threed/surface/SectionedCurveRelativeParametricSurface3D.kt @@ -33,12 +33,13 @@ import io.rtron.math.range.shiftLowerEndpointTo */ class SectionedCurveRelativeParametricSurface3D( private val completeCurveRelativeSurface: AbstractCurveRelativeSurface3D, - section: Range + section: Range, ) : AbstractCurveRelativeSurface3D() { - // Properties and Initializers init { - require(completeCurveRelativeSurface.domain.fuzzyEncloses(section, tolerance)) { "The complete surface must be defined everywhere where the section is also defined." } + require(completeCurveRelativeSurface.domain.fuzzyEncloses(section, tolerance)) { + "The complete surface must be defined everywhere where the section is also defined." + } } override val domain: Range = section.shiftLowerEndpointTo(0.0) @@ -50,11 +51,15 @@ class SectionedCurveRelativeParametricSurface3D( } // Methods - override fun calculatePointGlobalCSUnbounded(curveRelativePoint: CurveRelativeVector2D, addHeightOffset: Double): Vector3D { - val pointOnCompleteSurface = CurveRelativeVector2D( - sectionStart + curveRelativePoint.curvePosition, - curveRelativePoint.lateralOffset - ) + override fun calculatePointGlobalCSUnbounded( + curveRelativePoint: CurveRelativeVector2D, + addHeightOffset: Double, + ): Vector3D { + val pointOnCompleteSurface = + CurveRelativeVector2D( + sectionStart + curveRelativePoint.curvePosition, + curveRelativePoint.lateralOffset, + ) return completeCurveRelativeSurface.calculatePointGlobalCSUnbounded(pointOnCompleteSurface, addHeightOffset) } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/twod/point/CurveRelativeVector2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/twod/point/CurveRelativeVector2D.kt index cef52a0c..131d3554 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/twod/point/CurveRelativeVector2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/curved/twod/point/CurveRelativeVector2D.kt @@ -28,9 +28,8 @@ import io.rtron.math.geometry.curved.threed.point.CurveRelativeVector3D */ data class CurveRelativeVector2D( val curvePosition: Double, - val lateralOffset: Double = 0.0 + val lateralOffset: Double = 0.0, ) { - // Properties and Initializers init { require(curvePosition.isFinite()) { "Curve position value must be finite." } @@ -39,8 +38,8 @@ data class CurveRelativeVector2D( // Conversions fun toCurveRelative1D() = CurveRelativeVector1D(this.curvePosition) - fun toCurveRelative3D(heightOffset: Double = 0.0) = - CurveRelativeVector3D(this.curvePosition, this.lateralOffset, heightOffset) + + fun toCurveRelative3D(heightOffset: Double = 0.0) = CurveRelativeVector3D(this.curvePosition, this.lateralOffset, heightOffset) companion object { val ZERO = CurveRelativeVector2D(0.0, 0.0) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/AbstractGeometry3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/AbstractGeometry3D.kt index 0d3f8ba6..b5bc7ebc 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/AbstractGeometry3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/AbstractGeometry3D.kt @@ -23,7 +23,6 @@ import io.rtron.math.transform.AffineSequence3D * Abstract class for all geometric objects in 3D. */ abstract class AbstractGeometry3D : AbstractGeometry() { - /** * List of affine transformation matrices to move and rotate the geometric object. */ diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Geometry3DVisitor.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Geometry3DVisitor.kt index 891d34d9..e26380e0 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Geometry3DVisitor.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Geometry3DVisitor.kt @@ -30,7 +30,6 @@ import io.rtron.math.geometry.euclidean.threed.surface.ParametricBoundedSurface3 * from the actual object structure of the 3D geometry. */ interface Geometry3DVisitor { - // point fun visit(vector3D: Vector3D) @@ -39,12 +38,16 @@ interface Geometry3DVisitor { // surface fun visit(abstractSurface3D: AbstractSurface3D) + fun visit(circle3D: Circle3D) + fun visit(parametricBoundedSurface3D: ParametricBoundedSurface3D) // solid fun visit(abstractSolid3D: AbstractSolid3D) + fun visit(cylinder3D: Cylinder3D) + fun visit(parametricSweep3D: ParametricSweep3D) // abstract geometry diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Pose3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Pose3D.kt index 2fd5b0fa..6c98356d 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Pose3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Pose3D.kt @@ -28,12 +28,10 @@ import io.rtron.math.geometry.euclidean.twod.Pose2D */ data class Pose3D( val point: Vector3D = Vector3D.ZERO, - val rotation: Rotation3D = Rotation3D.ZERO + val rotation: Rotation3D = Rotation3D.ZERO, ) { - // Conversions - fun toPose2D(dropAxis: Vector3D = Vector3D.Z_AXIS) = - Pose2D(point.toVector2D(dropAxis), rotation.toRotation2D(dropAxis)) + fun toPose2D(dropAxis: Vector3D = Vector3D.Z_AXIS) = Pose2D(point.toVector2D(dropAxis), rotation.toRotation2D(dropAxis)) override fun toString(): String { return "Pose3D(position=$point, rotation=$rotation)" diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Rotation3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Rotation3D.kt index 180b283c..67f09447 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Rotation3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/Rotation3D.kt @@ -39,9 +39,8 @@ import org.apache.commons.math3.geometry.euclidean.threed.Rotation as CMRotation class Rotation3D( heading: Double, pitch: Double = 0.0, - roll: Double = 0.0 + roll: Double = 0.0, ) { - // Properties and Initializers init { require(heading.isFinite()) { "Heading angle must be finite." } @@ -63,6 +62,7 @@ class Rotation3D( // Operators operator fun plus(v: Rotation3D) = Rotation3D(heading + v.heading, pitch + v.pitch, roll + v.roll) + operator fun minus(v: Rotation3D) = Rotation3D(heading - v.heading, pitch - v.pitch, roll - v.roll) // Methods @@ -96,7 +96,11 @@ class Rotation3D( /** * Returns a [Rotation3D] while replacing non-finite values for [heading], [roll] and [pitch] with 0.0. */ - fun of(heading: Double, roll: Double = 0.0, pitch: Double = 0.0): Rotation3D { + fun of( + heading: Double, + roll: Double = 0.0, + pitch: Double = 0.0, + ): Rotation3D { val adjustedHeading = if (heading.isFinite()) heading else 0.0 val adjustedRoll = if (roll.isFinite()) roll else 0.0 val adjustedPitch = if (pitch.isFinite()) pitch else 0.0 @@ -106,7 +110,10 @@ class Rotation3D( /** * Returns a [Rotation3D] while replacing non-finite values for [heading], [roll] and [pitch] with 0.0. */ - fun of(heading: Option, roll: Option, pitch: Option): Rotation3D = - Rotation3D(heading.getOrElse { 0.0 }, roll.getOrElse { 0.0 }, pitch.getOrElse { 0.0 }) + fun of( + heading: Option, + roll: Option, + pitch: Option, + ): Rotation3D = Rotation3D(heading.getOrElse { 0.0 }, roll.getOrElse { 0.0 }, pitch.getOrElse { 0.0 }) } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/AbstractCurve3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/AbstractCurve3D.kt index 67ef8dea..b08f4a1c 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/AbstractCurve3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/AbstractCurve3D.kt @@ -38,7 +38,6 @@ import io.rtron.math.range.length * Abstract class for all geometric curve objects in 3D. */ abstract class AbstractCurve3D : AbstractGeometry3D(), DefinableDomain, Tolerable { - // Properties /** Length of the curve */ @@ -117,23 +116,29 @@ abstract class AbstractCurve3D : AbstractGeometry3D(), DefinableDomain, * @param includeEndPoint true, if the endpoint shall be included * @return list of points on this curve */ - fun calculatePointListGlobalCS(step: Double, includeEndPoint: Boolean = true): - Either> = either { - domain.arrange(step, includeEndPoint, tolerance) - .map(::CurveRelativeVector1D) - .map { calculatePointGlobalCS(it).bind() } - .let { it.toNonEmptyListOrNull()!! } - } + fun calculatePointListGlobalCS( + step: Double, + includeEndPoint: Boolean = true, + ): Either> = + either { + domain.arrange(step, includeEndPoint, tolerance) + .map(::CurveRelativeVector1D) + .map { calculatePointGlobalCS(it).bind() } + .let { it.toNonEmptyListOrNull()!! } + } /** * Returns a discretized curve as a [LineString3D]. * * @param step step size between the points */ - fun calculateLineStringGlobalCS(step: Double): Either = either { - val point = calculatePointListGlobalCS(step, true).bind() - LineString3D.of(point, tolerance).bind() - } + fun calculateLineStringGlobalCS(step: Double): Either = + either { + val point = calculatePointListGlobalCS(step, true).bind() + LineString3D.of(point, tolerance).bind() + } - override fun accept(visitor: Geometry3DVisitor) { visitor.visit(this) } + override fun accept(visitor: Geometry3DVisitor) { + visitor.visit(this) + } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/CompositeCurve3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/CompositeCurve3D.kt index 14474f45..686da547 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/CompositeCurve3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/CompositeCurve3D.kt @@ -26,9 +26,8 @@ import io.rtron.math.range.Range data class CompositeCurve3D( val curveMembers: NonEmptyList, private val absoluteDomains: NonEmptyList>, - private val absoluteStarts: NonEmptyList + private val absoluteStarts: NonEmptyList, ) : AbstractCurve3D() { - // Properties and Initializers init { require(curveMembers.all { it.tolerance == this.tolerance }) { "All curveMembers must have the same tolerance." } @@ -42,9 +41,10 @@ data class CompositeCurve3D( // Methods override fun calculatePointLocalCSUnbounded(curveRelativePoint: CurveRelativeVector1D): Vector3D { - val localMember = container - .fuzzySelectMember(curveRelativePoint.curvePosition, tolerance) - .getOrElse { throw it } + val localMember = + container + .fuzzySelectMember(curveRelativePoint.curvePosition, tolerance) + .getOrElse { throw it } val localPoint = CurveRelativeVector1D(localMember.localParameter) return localMember.member.calculatePointGlobalCSUnbounded(localPoint) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/Curve3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/Curve3D.kt index 4fa2e87f..cb4d6afa 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/Curve3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/Curve3D.kt @@ -44,13 +44,16 @@ import io.rtron.math.transform.Affine3D data class Curve3D( val curveXY: AbstractCurve2D, val heightFunction: UnivariateFunction, - val torsionFunction: UnivariateFunction = LinearFunction.X_AXIS + val torsionFunction: UnivariateFunction = LinearFunction.X_AXIS, ) : AbstractCurve3D() { - // Properties and Initializers init { - require(heightFunction.domain.fuzzyEncloses(curveXY.domain, tolerance)) { "The height function must be defined everywhere where the curveXY is also defined." } - require(torsionFunction.domain.fuzzyEncloses(curveXY.domain, tolerance)) { "The torsion function must be defined everywhere where the curveXY is also defined." } + require(heightFunction.domain.fuzzyEncloses(curveXY.domain, tolerance)) { + "The height function must be defined everywhere where the curveXY is also defined." + } + require(torsionFunction.domain.fuzzyEncloses(curveXY.domain, tolerance)) { + "The torsion function must be defined everywhere where the curveXY is also defined." + } require(length > tolerance) { "Length must be greater than zero as well as the tolerance threshold." } } @@ -91,8 +94,7 @@ data class Curve3D( * @param curveRelativePoint affine transformation matrix is calculated on the [curveRelativePoint] * @return affine transformation matrix whereby the orientation is tangential to this curve and its torsion */ - fun calculateAffine(curveRelativePoint: CurveRelativeVector1D): Affine3D = - calculatePose(curveRelativePoint).let { Affine3D.of(it) } + fun calculateAffine(curveRelativePoint: CurveRelativeVector1D): Affine3D = calculatePose(curveRelativePoint).let { Affine3D.of(it) } /** * Transforms the [curveRelativePoint] (relative to this curve) to a [Vector3D] in cartesian coordinates. @@ -111,12 +113,13 @@ data class Curve3D( * @param curveRelativeLineSegment line segment in curve relative coordinates * @return line segment in cartesian coordinates */ - fun transform(curveRelativeLineSegment: CurveRelativeLineSegment3D): Either = either { - val start = transform(curveRelativeLineSegment.start) - val end = transform(curveRelativeLineSegment.end) + fun transform(curveRelativeLineSegment: CurveRelativeLineSegment3D): Either = + either { + val start = transform(curveRelativeLineSegment.start) + val end = transform(curveRelativeLineSegment.end) - LineSegment3D.of(start, end, curveRelativeLineSegment.tolerance, endBoundType).bind() - } + LineSegment3D.of(start, end, curveRelativeLineSegment.tolerance, endBoundType).bind() + } override fun equals(other: Any?): Boolean { if (this === other) return true diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/CurveOnParametricSurface3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/CurveOnParametricSurface3D.kt index c71e0b85..ceb42132 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/CurveOnParametricSurface3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/CurveOnParametricSurface3D.kt @@ -40,17 +40,17 @@ import io.rtron.math.range.intersectingRange data class CurveOnParametricSurface3D( private val baseSurface: AbstractCurveRelativeSurface3D, private val lateralOffsetFunction: UnivariateFunction, - private val heightOffsetFunction: UnivariateFunction = LinearFunction.X_AXIS + private val heightOffsetFunction: UnivariateFunction = LinearFunction.X_AXIS, ) : AbstractCurve3D() { - // Properties and Initializers override val tolerance: Double get() = baseSurface.tolerance - override val domain: Range = setOf( - baseSurface.domain, - lateralOffsetFunction.domain, - heightOffsetFunction.domain - ).intersectingRange() + override val domain: Range = + setOf( + baseSurface.domain, + lateralOffsetFunction.domain, + heightOffsetFunction.domain, + ).intersectingRange() init { require(domain.isNotEmpty()) { "Domain must not be empty." } @@ -59,17 +59,18 @@ data class CurveOnParametricSurface3D( // Methods override fun calculatePointLocalCSUnbounded(curveRelativePoint: CurveRelativeVector1D): Vector3D { - val lateralOffset = lateralOffsetFunction.valueInFuzzy(curveRelativePoint.curvePosition, tolerance) - .getOrElse { throw it } - val heightOffset = heightOffsetFunction.valueInFuzzy(curveRelativePoint.curvePosition, tolerance) - .getOrElse { throw it } + val lateralOffset = + lateralOffsetFunction.valueInFuzzy(curveRelativePoint.curvePosition, tolerance) + .getOrElse { throw it } + val heightOffset = + heightOffsetFunction.valueInFuzzy(curveRelativePoint.curvePosition, tolerance) + .getOrElse { throw it } val curveRelativePoint2D = curveRelativePoint.toCurveRelative2D(lateralOffset) return baseSurface.calculatePointGlobalCSUnbounded(curveRelativePoint2D, heightOffset) } companion object { - /** * Returns a [CurveOnParametricSurface3D]. Throws an error, if the [lateralOffsetFunction] or the * [heightOffsetFunction] is not defined everywhere, where the [baseSurface] is defined. @@ -77,10 +78,14 @@ data class CurveOnParametricSurface3D( fun onCompleteSurface( baseSurface: AbstractCurveRelativeSurface3D, lateralOffsetFunction: UnivariateFunction, - heightOffsetFunction: UnivariateFunction = LinearFunction.X_AXIS + heightOffsetFunction: UnivariateFunction = LinearFunction.X_AXIS, ): CurveOnParametricSurface3D { - require(lateralOffsetFunction.domain.fuzzyEncloses(baseSurface.domain, baseSurface.tolerance)) { "The lateral offset function must be defined everywhere where the baseSurface is also defined." } - require(heightOffsetFunction.domain.fuzzyEncloses(baseSurface.domain, baseSurface.tolerance)) { "The height offset function must be defined everywhere where the baseSurface is also defined." } + require(lateralOffsetFunction.domain.fuzzyEncloses(baseSurface.domain, baseSurface.tolerance)) { + "The lateral offset function must be defined everywhere where the baseSurface is also defined." + } + require(heightOffsetFunction.domain.fuzzyEncloses(baseSurface.domain, baseSurface.tolerance)) { + "The height offset function must be defined everywhere where the baseSurface is also defined." + } return CurveOnParametricSurface3D(baseSurface, lateralOffsetFunction, heightOffsetFunction) } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/Line3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/Line3D.kt index 06be99d3..292788fa 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/Line3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/Line3D.kt @@ -33,9 +33,8 @@ fun CMLine3D.toLine3D(tolerance: Double) = class Line3D( point1: Vector3D, point2: Vector3D, - private val tolerance: Double + private val tolerance: Double, ) { - // Properties and Initializers init { require(point1 != point2) { "Points must not be identical." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/LineSegment3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/LineSegment3D.kt index d96b2c7d..8f0c61b1 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/LineSegment3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/LineSegment3D.kt @@ -35,9 +35,8 @@ class LineSegment3D( val start: Vector3D, val end: Vector3D, override val tolerance: Double, - endBoundType: BoundType = BoundType.CLOSED + endBoundType: BoundType = BoundType.CLOSED, ) : AbstractCurve3D() { - // Properties and Initializers init { require(start != end) { "Start and end vector must not be identical." } @@ -103,14 +102,20 @@ class LineSegment3D( } companion object { - /** * Creates a [LineSegment3D], if [start] and [end] [Vector3D] are not fuzzily equal according to the [tolerance]. * */ - fun of(start: Vector3D, end: Vector3D, tolerance: Double, endBoundType: BoundType = BoundType.CLOSED): Either = + fun of( + start: Vector3D, + end: Vector3D, + tolerance: Double, + endBoundType: BoundType = BoundType.CLOSED, + ): Either = if (start.fuzzyEquals(end, tolerance)) { - Either.Left(IllegalArgumentException("Start and end vector of a line segment must be different according to the given tolerance.")) + Either.Left( + IllegalArgumentException("Start and end vector of a line segment must be different according to the given tolerance."), + ) } else { Either.Right(LineSegment3D(start, end, tolerance, endBoundType)) } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/LineString3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/LineString3D.kt index 83fb9ef0..c44c4f4e 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/LineString3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/curve/LineString3D.kt @@ -39,20 +39,27 @@ import io.rtron.std.noneWithNext */ class LineString3D( val vertices: NonEmptyList, - override val tolerance: Double + override val tolerance: Double, ) : AbstractCurve3D() { - // Properties and Initializers init { require(vertices.size >= 2) { "Must at least contain two vertices." } - require(vertices.noneWithNext { a, b -> a.fuzzyEquals(b, tolerance) }) { "Must not contain consecutively following point duplicates." } + require( + vertices.noneWithNext { + a, + b, + -> + a.fuzzyEquals(b, tolerance) + }, + ) { "Must not contain consecutively following point duplicates." } } private val segments = vertices.zipWithNext().map { LineSegment3D(it.first, it.second, tolerance) } private val lengths = segments.map { it.length } private val absoluteStarts = lengths.cumulativeSum().dropLast(1) - private val absoluteDomains = absoluteStarts.zipWithNext().map { Range.closedOpen(it.first, it.second) } + - Range.closed(absoluteStarts.last(), absoluteStarts.last() + lengths.last()) + private val absoluteDomains = + absoluteStarts.zipWithNext().map { Range.closedOpen(it.first, it.second) } + + Range.closed(absoluteStarts.last(), absoluteStarts.last() + lengths.last()) private val container = ConcatenationContainer(segments, absoluteDomains, absoluteStarts, tolerance) override val domain get() = container.domain @@ -60,27 +67,32 @@ class LineString3D( // Methods override fun calculatePointLocalCSUnbounded(curveRelativePoint: CurveRelativeVector1D): Vector3D { - val localMember = container.fuzzySelectMember(curveRelativePoint.curvePosition, tolerance) - .getOrElse { throw it } + val localMember = + container.fuzzySelectMember(curveRelativePoint.curvePosition, tolerance) + .getOrElse { throw it } val localPoint = CurveRelativeVector1D(localMember.localParameter) return localMember.member.calculatePointGlobalCSUnbounded(localPoint) } companion object { + fun of( + vertices: NonEmptyList, + tolerance: Double, + ): Either = + either { + val adjustedVertices = + vertices + .filterWithNext { a, b -> a.fuzzyUnequals(b, tolerance) } + .toNonEmptyListOrNone() + .toEither { GeometryException.NotEnoughVertices("No vertex for constructing a line segment") } + .bind() - fun of(vertices: NonEmptyList, tolerance: Double): Either = either { - val adjustedVertices = vertices - .filterWithNext { a, b -> a.fuzzyUnequals(b, tolerance) } - .toNonEmptyListOrNone() - .toEither { GeometryException.NotEnoughVertices("No vertex for constructing a line segment") } - .bind() + if (adjustedVertices.size < 2) { + GeometryException.NotEnoughVertices("Not enough vertices for constructing a line segment").left().bind() + } - if (adjustedVertices.size < 2) { - GeometryException.NotEnoughVertices("Not enough vertices for constructing a line segment").left().bind() + LineString3D(adjustedVertices, tolerance) } - - LineString3D(adjustedVertices, tolerance) - } } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/point/AbstractPoint3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/point/AbstractPoint3D.kt index 2804d60a..2a0c5055 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/point/AbstractPoint3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/point/AbstractPoint3D.kt @@ -22,7 +22,6 @@ import io.rtron.math.geometry.euclidean.threed.AbstractGeometry3D * Abstract class for all geometric point objects in 3D. */ abstract class AbstractPoint3D : AbstractGeometry3D() { - /** * Returns the point in the local coordinate system. */ diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/point/Vector3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/point/Vector3D.kt index 96922a2d..496672a2 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/point/Vector3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/point/Vector3D.kt @@ -46,9 +46,8 @@ data class Vector3D( val x: Double, val y: Double, val z: Double, - override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY + override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, ) : AbstractPoint3D() { - // Properties and Initializers init { require(x.isFinite()) { "X value must be finite." } @@ -66,16 +65,28 @@ data class Vector3D( // Operators operator fun plus(v: Vector3D) = vector3D.add(v.vector3D).toVector3D() + operator fun minus(v: Vector3D) = vector3D.subtract(v.vector3D).toVector3D() + operator fun times(m: Double) = scalarMultiply(m) + operator fun div(m: Double) = scalarDivide(m) + operator fun unaryPlus() = Vector3D(x, y, z) + operator fun unaryMinus() = Vector3D(-x, -y, -z) - fun fuzzyEquals(o: Vector3D, tolerance: Double) = doubleFuzzyEquals(this.x, o.x, tolerance) && + fun fuzzyEquals( + o: Vector3D, + tolerance: Double, + ) = doubleFuzzyEquals(this.x, o.x, tolerance) && doubleFuzzyEquals(this.y, o.y, tolerance) && doubleFuzzyEquals(this.z, o.z, tolerance) - fun fuzzyUnequals(o: Vector3D, tolerance: Double) = !fuzzyEquals(o, tolerance) + + fun fuzzyUnequals( + o: Vector3D, + tolerance: Double, + ) = !fuzzyEquals(o, tolerance) // Methods @@ -115,10 +126,15 @@ data class Vector3D( // Conversions fun toDoubleArray() = doubleArrayOf(x, y, z) + fun toDoubleList() = nonEmptyListOf(x, y, z) + fun toRealVector() = RealVector(doubleArrayOf(x, y, z)) + fun toVector3DCm() = this.vector3D + fun toVector3DJOML() = JOMLVector3D(this.x, this.y, this.z) + fun toVector4DJOML(w: Double = 0.0) = JOMLVector4D(this.x, this.y, this.z, w) /** @@ -144,7 +160,11 @@ data class Vector3D( * Creates a [Vector3D], if each component is finite. Otherwise it will return a Result.Error. * */ - fun of(x: Double, y: Double, z: Double): Either = + fun of( + x: Double, + y: Double, + z: Double, + ): Either = if (!x.isFinite() || !y.isFinite() || !z.isFinite()) { Either.Left(IllegalArgumentException("Values for x, y, z must be finite.")) } else { @@ -159,7 +179,10 @@ data class Vector3D( * @param other other list of vectors to be compared * @param tolerance allowed tolerance for fuzzy equal evaluation */ -fun List.fuzzyEquals(other: List, tolerance: Double): Boolean { +fun List.fuzzyEquals( + other: List, + tolerance: Double, +): Boolean { require(this.hasSameSizeAs(other)) { "Lists must have the same size." } return this.zip(other).all { it.first.fuzzyEquals(it.second, tolerance) } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/AbstractSolid3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/AbstractSolid3D.kt index fff40f1c..5b32215d 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/AbstractSolid3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/AbstractSolid3D.kt @@ -27,7 +27,6 @@ import io.rtron.math.range.Tolerable * Abstract class for all geometric solid objects in 3D. */ abstract class AbstractSolid3D : AbstractGeometry3D(), Tolerable { - /** * Calculates the polygons for the respective solid geometry within the local coordinate system of the surface. */ diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Cuboid3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Cuboid3D.kt index 4aa28175..4160691d 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Cuboid3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Cuboid3D.kt @@ -37,9 +37,8 @@ data class Cuboid3D( val width: Double, val height: Double, override val tolerance: Double, - override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY + override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, ) : AbstractSolid3D() { - // Properties and Initializers init { require(length.isFinite()) { "Length value must be finite." } @@ -64,53 +63,59 @@ data class Cuboid3D( private val vertexElevatedQuadrantIII = Vector3D(-halfLength, -halfWidth, height) private val vertexElevatedQuadrantIV = Vector3D(halfLength, -halfWidth, height) - private val basePolygon = Polygon3D.of( - vertexBaseQuadrantI, - vertexBaseQuadrantIV, - vertexBaseQuadrantIII, - vertexBaseQuadrantII, - tolerance = tolerance - ) - - private val elevatedPolygon = Polygon3D.of( - vertexElevatedQuadrantI, - vertexElevatedQuadrantII, - vertexElevatedQuadrantIII, - vertexElevatedQuadrantIV, - tolerance = tolerance - ) - - private val frontPolygon = Polygon3D.of( - vertexBaseQuadrantI, - vertexElevatedQuadrantI, - vertexElevatedQuadrantIV, - vertexBaseQuadrantIV, - tolerance = tolerance - ) - - private val leftPolygon = Polygon3D.of( - vertexBaseQuadrantI, - vertexBaseQuadrantII, - vertexElevatedQuadrantII, - vertexElevatedQuadrantI, - tolerance = tolerance - ) - - private val backPolygon = Polygon3D.of( - vertexBaseQuadrantII, - vertexBaseQuadrantIII, - vertexElevatedQuadrantIII, - vertexElevatedQuadrantII, - tolerance = tolerance - ) - - private val rightPolygon = Polygon3D.of( - vertexElevatedQuadrantIV, - vertexElevatedQuadrantIII, - vertexBaseQuadrantIII, - vertexBaseQuadrantIV, - tolerance = tolerance - ) + private val basePolygon = + Polygon3D.of( + vertexBaseQuadrantI, + vertexBaseQuadrantIV, + vertexBaseQuadrantIII, + vertexBaseQuadrantII, + tolerance = tolerance, + ) + + private val elevatedPolygon = + Polygon3D.of( + vertexElevatedQuadrantI, + vertexElevatedQuadrantII, + vertexElevatedQuadrantIII, + vertexElevatedQuadrantIV, + tolerance = tolerance, + ) + + private val frontPolygon = + Polygon3D.of( + vertexBaseQuadrantI, + vertexElevatedQuadrantI, + vertexElevatedQuadrantIV, + vertexBaseQuadrantIV, + tolerance = tolerance, + ) + + private val leftPolygon = + Polygon3D.of( + vertexBaseQuadrantI, + vertexBaseQuadrantII, + vertexElevatedQuadrantII, + vertexElevatedQuadrantI, + tolerance = tolerance, + ) + + private val backPolygon = + Polygon3D.of( + vertexBaseQuadrantII, + vertexBaseQuadrantIII, + vertexElevatedQuadrantIII, + vertexElevatedQuadrantII, + tolerance = tolerance, + ) + + private val rightPolygon = + Polygon3D.of( + vertexElevatedQuadrantIV, + vertexElevatedQuadrantIII, + vertexBaseQuadrantIII, + vertexBaseQuadrantIV, + tolerance = tolerance, + ) // Methods override fun calculatePolygonsLocalCS(): NonEmptyList { @@ -125,7 +130,13 @@ data class Cuboid3D( companion object { val UNIT = Cuboid3D(1.0, 1.0, 1.0, DEFAULT_TOLERANCE) - fun of(length: Option, width: Option, height: Option, tolerance: Double, affineSequence: AffineSequence3D = AffineSequence3D.EMPTY): Cuboid3D { + fun of( + length: Option, + width: Option, + height: Option, + tolerance: Double, + affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, + ): Cuboid3D { require(length.isSome()) { "Length must be defined." } require(width.isSome()) { "Width must be defined." } require(height.isSome()) { "Height must be defined." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Cylinder3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Cylinder3D.kt index 2d2eb29c..46286388 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Cylinder3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Cylinder3D.kt @@ -41,9 +41,8 @@ data class Cylinder3D( val height: Double, override val tolerance: Double, override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, - private val numberSlices: Int = DEFAULT_NUMBER_SLICES + private val numberSlices: Int = DEFAULT_NUMBER_SLICES, ) : AbstractSolid3D() { - // Properties and Initializers init { require(radius.isFinite()) { "Radius value must be finite." } @@ -64,17 +63,18 @@ data class Cylinder3D( val topPolygonVertices = circleVertices.map { it.toVector3D(z = height) }.let { it.toNonEmptyListOrNull()!! } val topPolygon = Polygon3D(topPolygonVertices, tolerance) - val sidePolygons = circleVertices - .zipWithNextEnclosing() - .map { - Polygon3D.of( - it.first.toVector3D(0.0), - it.second.toVector3D(0.0), - it.second.toVector3D(height), - it.first.toVector3D(height), - tolerance = tolerance - ) - } + val sidePolygons = + circleVertices + .zipWithNextEnclosing() + .map { + Polygon3D.of( + it.first.toVector3D(0.0), + it.second.toVector3D(0.0), + it.second.toVector3D(height), + it.first.toVector3D(height), + tolerance = tolerance, + ) + } return nonEmptyListOf(basePolygon, topPolygon) + sidePolygons } @@ -97,7 +97,13 @@ data class Cylinder3D( companion object { const val DEFAULT_NUMBER_SLICES: Int = 16 // used for tesselation - fun of(radius: Option, height: Option, tolerance: Double, affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, numberSlices: Int = DEFAULT_NUMBER_SLICES): Cylinder3D { + fun of( + radius: Option, + height: Option, + tolerance: Double, + affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, + numberSlices: Int = DEFAULT_NUMBER_SLICES, + ): Cylinder3D { require(radius.isSome()) { "Radius must be defined." } require(height.isSome()) { "Height must be defined." } return Cylinder3D(radius.getOrNull()!!, height.getOrNull()!!, tolerance, affineSequence, numberSlices) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/ParametricSweep3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/ParametricSweep3D.kt index 16858a6b..565218cf 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/ParametricSweep3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/ParametricSweep3D.kt @@ -54,14 +54,19 @@ data class ParametricSweep3D( val objectHeightFunction: LinearFunction, val objectWidthFunction: LinearFunction, override val tolerance: Double, - private val discretizationStepSize: Double + private val discretizationStepSize: Double, ) : AbstractSolid3D(), DefinableDomain, Tolerable { - // Properties and Initializers init { - require(absoluteHeight.domain.fuzzyEncloses(referenceCurveXY.domain, tolerance)) { "The absolute height function must be defined everywhere where the referenceCurveXY is also defined." } - require(objectHeightFunction.domain.fuzzyEncloses(referenceCurveXY.domain, tolerance)) { "The object height function must be defined everywhere where the referenceCurveXY is also defined." } - require(objectWidthFunction.domain.fuzzyEncloses(referenceCurveXY.domain, tolerance)) { "The object width function must be defined everywhere where the referenceCurveXY is also defined." } + require(absoluteHeight.domain.fuzzyEncloses(referenceCurveXY.domain, tolerance)) { + "The absolute height function must be defined everywhere where the referenceCurveXY is also defined." + } + require(objectHeightFunction.domain.fuzzyEncloses(referenceCurveXY.domain, tolerance)) { + "The object height function must be defined everywhere where the referenceCurveXY is also defined." + } + require(objectWidthFunction.domain.fuzzyEncloses(referenceCurveXY.domain, tolerance)) { + "The object width function must be defined everywhere where the referenceCurveXY is also defined." + } require(length >= tolerance) { "Length must be greater than zero as well as the tolerance threshold." } } @@ -102,33 +107,37 @@ data class ParametricSweep3D( /** lower left curve of the sweep as a list of points */ private val lowerLeftVertices by lazy { - val vertices = lowerLeftCurve.calculatePointListGlobalCS(discretizationStepSize) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } + val vertices = + lowerLeftCurve.calculatePointListGlobalCS(discretizationStepSize) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } vertices.toNonEmptyListOrNull()!! } /** lower right curve of the sweep as a list of points */ private val lowerRightVertices by lazy { - val vertices = lowerRightCurve.calculatePointListGlobalCS(discretizationStepSize) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } + val vertices = + lowerRightCurve.calculatePointListGlobalCS(discretizationStepSize) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } vertices.toNonEmptyListOrNull()!! } /** upper left curve of the sweep as a list of points */ private val upperLeftVertices by lazy { - val vertices = upperLeftCurve.calculatePointListGlobalCS(discretizationStepSize) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } + val vertices = + upperLeftCurve.calculatePointListGlobalCS(discretizationStepSize) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } vertices.toNonEmptyListOrNull()!! } /** upper right curve of the sweep as a list of points */ private val upperRightVertices by lazy { - val vertices = upperRightCurve.calculatePointListGlobalCS(discretizationStepSize) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } + val vertices = + upperRightCurve.calculatePointListGlobalCS(discretizationStepSize) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } vertices.toNonEmptyListOrNull()!! } @@ -148,44 +157,52 @@ data class ParametricSweep3D( val rightPolygons = createPolygons(lowerRightVertices, upperRightVertices).getOrElse { emptyList() } // calculate the start and end faces - val startPolygons = run { - val linearRing = LinearRing3D.of( - nonEmptyListOf( - upperLeftVertices.first(), - upperRightVertices.first(), - lowerRightVertices.first(), - lowerLeftVertices.first() - ), - tolerance = tolerance - ).getOrElse { return@run emptyList() } - linearRing.calculatePolygonsGlobalCS().getOrElse { emptyList() } - } - val endPolygons = run { - val linearRing = LinearRing3D.of( - nonEmptyListOf( - upperLeftVertices.last(), - lowerLeftVertices.last(), - lowerRightVertices.last(), - upperRightVertices.last() - ), - tolerance = tolerance - ).getOrElse { return@run emptyList() } - linearRing.calculatePolygonsGlobalCS().getOrElse { emptyList() } - } + val startPolygons = + run { + val linearRing = + LinearRing3D.of( + nonEmptyListOf( + upperLeftVertices.first(), + upperRightVertices.first(), + lowerRightVertices.first(), + lowerLeftVertices.first(), + ), + tolerance = tolerance, + ).getOrElse { return@run emptyList() } + linearRing.calculatePolygonsGlobalCS().getOrElse { emptyList() } + } + val endPolygons = + run { + val linearRing = + LinearRing3D.of( + nonEmptyListOf( + upperLeftVertices.last(), + lowerLeftVertices.last(), + lowerRightVertices.last(), + upperRightVertices.last(), + ), + tolerance = tolerance, + ).getOrElse { return@run emptyList() } + linearRing.calculatePolygonsGlobalCS().getOrElse { emptyList() } + } // combine all polygons - val allPolygons = basePolygons + topPolygons + leftPolygons + rightPolygons + - startPolygons + endPolygons + val allPolygons = + basePolygons + topPolygons + leftPolygons + rightPolygons + + startPolygons + endPolygons return allPolygons.toNonEmptyListOrNull()!! } - private fun createPolygons(leftVertices: NonEmptyList, rightVertices: NonEmptyList): - Either> = either { - LinearRing3D.ofWithDuplicatesRemoval(leftVertices, rightVertices, tolerance) - .bind() - .map { it.calculatePolygonsGlobalCS().bind() } - .flatten() - } + private fun createPolygons( + leftVertices: NonEmptyList, + rightVertices: NonEmptyList, + ): Either> = + either { + LinearRing3D.ofWithDuplicatesRemoval(leftVertices, rightVertices, tolerance) + .bind() + .map { it.calculatePolygonsGlobalCS().bind() } + .flatten() + } override fun accept(visitor: Geometry3DVisitor) = visitor.visit(this) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Polyhedron3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Polyhedron3D.kt index 1f24782c..9891ab83 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Polyhedron3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/solid/Polyhedron3D.kt @@ -28,9 +28,8 @@ import io.rtron.math.transform.AffineSequence3D data class Polyhedron3D( val polygons: NonEmptyList, override val tolerance: Double, - override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY + override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, ) : AbstractSolid3D() { - // Properties and Initializers init { require(polygons.size >= 4) { "Polyhedron must have at least four polygons." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/AbstractSurface3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/AbstractSurface3D.kt index f72fef91..4129e59a 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/AbstractSurface3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/AbstractSurface3D.kt @@ -28,7 +28,6 @@ import io.rtron.math.range.Tolerable * Abstract class for all geometric surface objects in 3D. */ abstract class AbstractSurface3D : AbstractGeometry3D(), Tolerable { - /** * Calculates the polygons for the respective surface geometry within the local coordinate system of the surface. */ @@ -37,9 +36,10 @@ abstract class AbstractSurface3D : AbstractGeometry3D(), Tolerable { /** * Calculates the polygons for the respective surface geometry and transforms it to the global coordinate system. */ - fun calculatePolygonsGlobalCS(): Either> = calculatePolygonsLocalCS() - .map { affineSequence.solve().transform(it) } - .map { it.toNonEmptyListOrNull()!! } + fun calculatePolygonsGlobalCS(): Either> = + calculatePolygonsLocalCS() + .map { affineSequence.solve().transform(it) } + .map { it.toNonEmptyListOrNull()!! } override fun accept(visitor: Geometry3DVisitor) = visitor.visit(this) } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Circle3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Circle3D.kt index be6c3778..3e1304cb 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Circle3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Circle3D.kt @@ -40,9 +40,8 @@ data class Circle3D( val radius: Double, override val tolerance: Double, override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, - private val numberSlices: Int = DEFAULT_NUMBER_SLICES + private val numberSlices: Int = DEFAULT_NUMBER_SLICES, ) : AbstractSurface3D() { - // Properties and Initializers init { require(radius.isFinite()) { "Radius value must be finite." } @@ -52,25 +51,29 @@ data class Circle3D( // Methods override fun calculatePolygonsLocalCS(): Either> { - val polygon = (0 until numberSlices) - .map { TWO_PI * it / numberSlices } - .map { calculatePoint(it) } - .let { it.toNonEmptyListOrNull()!! } - .let { Polygon3D(it, tolerance) } + val polygon = + (0 until numberSlices) + .map { TWO_PI * it / numberSlices } + .map { calculatePoint(it) } + .let { it.toNonEmptyListOrNull()!! } + .let { Polygon3D(it, tolerance) } return nonEmptyListOf(polygon).right() } /** Calculates a point the circle based on the [angle] around the origin. */ - private fun calculatePoint(angle: Double = 0.0) = - Vector3D(radius * cos(angle), radius * sin(angle), 0.0) + private fun calculatePoint(angle: Double = 0.0) = Vector3D(radius * cos(angle), radius * sin(angle), 0.0) override fun accept(visitor: Geometry3DVisitor) = visitor.visit(this) companion object { private const val DEFAULT_NUMBER_SLICES: Int = 16 // used for tesselation - fun of(radius: Option, tolerance: Double, affineSequence: AffineSequence3D = AffineSequence3D.EMPTY): Circle3D { + fun of( + radius: Option, + tolerance: Double, + affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, + ): Circle3D { require(radius.isSome()) { "Radius must be defined." } return Circle3D(radius.getOrNull()!!, tolerance, affineSequence) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/CompositeSurface3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/CompositeSurface3D.kt index 49929a83..a84db02c 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/CompositeSurface3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/CompositeSurface3D.kt @@ -29,13 +29,14 @@ import io.rtron.math.geometry.GeometryException * @param surfaceMembers surface members to be composited */ class CompositeSurface3D( - private val surfaceMembers: NonEmptyList + private val surfaceMembers: NonEmptyList, ) : AbstractSurface3D() { - // Properties and Initializers init { require(surfaceMembers.isNotEmpty()) { "Composite surface must contain members." } - require(surfaceMembers.all { surfaceMembers.first().tolerance == it.tolerance }) { "All surface members must have the same tolerance." } + require( + surfaceMembers.all { surfaceMembers.first().tolerance == it.tolerance }, + ) { "All surface members must have the same tolerance." } } override val tolerance: Double get() = surfaceMembers.first().tolerance @@ -44,8 +45,9 @@ class CompositeSurface3D( constructor(surfaceMember: AbstractSurface3D) : this(nonEmptyListOf(surfaceMember)) // Methods - override fun calculatePolygonsLocalCS(): Either> = either { - val polygons: List = surfaceMembers.map { it.calculatePolygonsGlobalCS().bind() }.flatten() - polygons.let { it.toNonEmptyListOrNull()!! } - } + override fun calculatePolygonsLocalCS(): Either> = + either { + val polygons: List = surfaceMembers.map { it.calculatePolygonsGlobalCS().bind() }.flatten() + polygons.let { it.toNonEmptyListOrNull()!! } + } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/LinearRing3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/LinearRing3D.kt index 8644c6fc..7854ba2f 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/LinearRing3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/LinearRing3D.kt @@ -44,9 +44,8 @@ import io.rtron.std.noneWithNextEnclosing data class LinearRing3D( val vertices: NonEmptyList, override val tolerance: Double, - override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY + override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, ) : AbstractSurface3D(), Tolerable { - // Properties and Initializers private val numberOfVertices = vertices.size @@ -58,8 +57,18 @@ data class LinearRing3D( init { require(numberOfVertices >= 3) { "Not enough vertices provided for constructing a linear ring." } - require(vertices.noneWithNextEnclosing { a, b -> a.fuzzyEquals(b, tolerance) }) { "Consecutively following point duplicates found." } - require(dimensionSpan >= 2) { "The dimension of the span is too low ($dimensionSpan), which might be caused by colinear vertices (all vertices located on a line)." } + require( + vertices.noneWithNextEnclosing { + a, + b, + -> + a.fuzzyEquals(b, tolerance) + }, + ) { "Consecutively following point duplicates found." } + require(dimensionSpan >= 2) { + "The dimension of the span is too low ($dimensionSpan), which might be " + + "caused by colinear vertices (all vertices located on a line)." + } } // Methods @@ -80,7 +89,10 @@ data class LinearRing3D( /** * Creates a linear ring based on the provided [vertices]. */ - fun of(vertices: NonEmptyList, tolerance: Double): Either { + fun of( + vertices: NonEmptyList, + tolerance: Double, + ): Either { // val vertices = vertices.toList().toNonEmptyListOrNull()!! val verticesAdjusted: List = vertices.filterWithNextEnclosing { a, b -> a.fuzzyUnequals(b, tolerance) } if (verticesAdjusted.size < 3) { @@ -97,16 +109,21 @@ data class LinearRing3D( * @param leftVertices left vertices for the linear rings construction * @param rightVertices right vertices for the linear rings construction */ - fun of(leftVertices: List, rightVertices: List, tolerance: Double): NonEmptyList { + fun of( + leftVertices: List, + rightVertices: List, + tolerance: Double, + ): NonEmptyList { require(leftVertices.size >= 2) { "At least two left vertices required." } require(rightVertices.size >= 2) { "At least two right vertices required." } data class VertexPair(val left: Vector3D, val right: Vector3D) val vertexPairs = leftVertices.zip(rightVertices).map { VertexPair(it.first, it.second) } - val linearRingVertices = vertexPairs.zipWithNext() - .map { nonEmptyListOf(it.first.right, it.second.right, it.second.left, it.first.left) } - .let { it.toNonEmptyListOrNull()!! } + val linearRingVertices = + vertexPairs.zipWithNext() + .map { nonEmptyListOf(it.first.right, it.second.right, it.second.left, it.first.left) } + .let { it.toNonEmptyListOrNull()!! } return linearRingVertices.map { LinearRing3D(it, tolerance) } } @@ -119,29 +136,35 @@ data class LinearRing3D( * @param leftVertices left vertices for the linear rings construction * @param rightVertices right vertices for the linear rings construction */ - fun ofWithDuplicatesRemoval(leftVertices: NonEmptyList, rightVertices: NonEmptyList, tolerance: Double): - Either> = either { - require(leftVertices.size >= 2) { "At least two left vertices required." } - require(rightVertices.size >= 2) { "At least two right vertices required." } - - data class VertexPair(val left: Vector3D, val right: Vector3D) - val vertexPairs = leftVertices.zip(rightVertices).map { VertexPair(it.first, it.second) } - - val linearRings: List = vertexPairs - .asSequence() - .zipWithNext() - .map { nonEmptyListOf(it.first.right, it.second.right, it.second.left, it.first.left) } - .map { currentVertices -> currentVertices.filterWithNextEnclosing { a, b -> a.fuzzyUnequals(b, tolerance) } } - .filter { it.distinct().count() >= 3 } - .filter { !it.isColinear(tolerance) } - .map { it.toNonEmptyListOrNull()!! } - .map { LinearRing3D(it, tolerance) } - .toList() - - val nonEmptyLinearRingsList = linearRings.toNonEmptyListOrNone() - .toEither { GeometryException.NotEnoughValidLinearRings("") } - .bind() - nonEmptyLinearRingsList - } + fun ofWithDuplicatesRemoval( + leftVertices: NonEmptyList, + rightVertices: NonEmptyList, + tolerance: Double, + ): Either> = + either { + require(leftVertices.size >= 2) { "At least two left vertices required." } + require(rightVertices.size >= 2) { "At least two right vertices required." } + + data class VertexPair(val left: Vector3D, val right: Vector3D) + val vertexPairs = leftVertices.zip(rightVertices).map { VertexPair(it.first, it.second) } + + val linearRings: List = + vertexPairs + .asSequence() + .zipWithNext() + .map { nonEmptyListOf(it.first.right, it.second.right, it.second.left, it.first.left) } + .map { currentVertices -> currentVertices.filterWithNextEnclosing { a, b -> a.fuzzyUnequals(b, tolerance) } } + .filter { it.distinct().count() >= 3 } + .filter { !it.isColinear(tolerance) } + .map { it.toNonEmptyListOrNull()!! } + .map { LinearRing3D(it, tolerance) } + .toList() + + val nonEmptyLinearRingsList = + linearRings.toNonEmptyListOrNone() + .toEither { GeometryException.NotEnoughValidLinearRings("") } + .bind() + nonEmptyLinearRingsList + } } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/ParametricBoundedSurface3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/ParametricBoundedSurface3D.kt index d785e015..d917cc5e 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/ParametricBoundedSurface3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/ParametricBoundedSurface3D.kt @@ -32,9 +32,8 @@ data class ParametricBoundedSurface3D( val leftBoundary: Curve3D, val rightBoundary: Curve3D, override val tolerance: Double, - private val discretizationStepSize: Double + private val discretizationStepSize: Double, ) : AbstractSurface3D(), DefinableDomain, Tolerable { - // Properties and Initializers init { require(leftBoundary.domain == rightBoundary.domain) { "Boundary curves must have the identical domain." } @@ -48,29 +47,32 @@ data class ParametricBoundedSurface3D( get() = leftBoundary.length private val leftVertices by lazy { - val vertices = leftBoundary.calculatePointListGlobalCS(discretizationStepSize) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } + val vertices = + leftBoundary.calculatePointListGlobalCS(discretizationStepSize) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } vertices.toNonEmptyListOrNull()!! } private val rightVertices by lazy { - val vertices = rightBoundary.calculatePointListGlobalCS(discretizationStepSize) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } + val vertices = + rightBoundary.calculatePointListGlobalCS(discretizationStepSize) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } vertices.toNonEmptyListOrNull()!! } // Methods - override fun calculatePolygonsLocalCS(): Either> = either { - LinearRing3D.ofWithDuplicatesRemoval(leftVertices, rightVertices, tolerance) - .mapLeft { GeometryException.BoundaryRepresentationGenerationError(it.message) } - .bind() - .map { it.calculatePolygonsGlobalCS().bind() } - .flatten() - .let { it.toNonEmptyListOrNull()!! } - } + override fun calculatePolygonsLocalCS(): Either> = + either { + LinearRing3D.ofWithDuplicatesRemoval(leftVertices, rightVertices, tolerance) + .mapLeft { GeometryException.BoundaryRepresentationGenerationError(it.message) } + .bind() + .map { it.calculatePolygonsGlobalCS().bind() } + .flatten() + .let { it.toNonEmptyListOrNull()!! } + } companion object { const val DEFAULT_STEP_SIZE: Double = 0.3 // used for tesselation diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Plane3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Plane3D.kt index 2693eb36..c7bb1168 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Plane3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Plane3D.kt @@ -32,9 +32,8 @@ import org.apache.commons.math3.geometry.euclidean.threed.Vector3D as CMVector3D data class Plane3D( val point: Vector3D = Vector3D.ZERO, val normal: Vector3D, - val tolerance: Double + val tolerance: Double, ) { - // Properties and Initializers init { require(normal.norm > tolerance) { "Norm of normal must be greater than zero and the tolerance threshold." } @@ -49,6 +48,7 @@ data class Plane3D( val vectorV by lazy { plane.v.toVector3D() } // Methods + /** Returns the oriented distance between the [point] and this plane. */ fun getOffset(point: Vector3D): Double = plane.getOffset(point.toVector3DCm()) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Polygon3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Polygon3D.kt index 604cdc03..429f8fde 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Polygon3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Polygon3D.kt @@ -38,9 +38,8 @@ import io.rtron.std.noneWithNextEnclosing data class Polygon3D( val vertices: NonEmptyList, override val tolerance: Double, - override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY + override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, ) : AbstractSurface3D() { - // Properties and Initializers private val numberOfVertices = vertices.size @@ -52,7 +51,14 @@ data class Polygon3D( init { require(numberOfVertices >= 3) { "Not enough vertices provided for constructing a polygon." } - require(vertices.noneWithNextEnclosing { a, b -> a.fuzzyEquals(b, tolerance) }) { "Consecutively following point duplicates found." } + require( + vertices.noneWithNextEnclosing { + a, + b, + -> + a.fuzzyEquals(b, tolerance) + }, + ) { "Consecutively following point duplicates found." } require(dimensionSpan >= 2) { "The dimension of the span is too low ($dimensionSpan) which might be caused by colinear vertices." } require(vertices.isPlanar(tolerance)) { "The vertices of a polygon must be located in a plane." } } @@ -60,36 +66,45 @@ data class Polygon3D( // Methods /** Returns the normal of the polygon. */ - fun getNormal(): Either = - this.vertices.calculateNormal().normalized().let { Either.Right(it) } + fun getNormal(): Either = this.vertices.calculateNormal().normalized().let { Either.Right(it) } /** Returns a new polygon with an opposite facing by reversing the vertices order */ fun reversed() = Polygon3D(vertices.reversed().toNonEmptyListOrNull()!!, tolerance, affineSequence) - override fun calculatePolygonsLocalCS(): Either> = nonEmptyListOf(this).right() + override fun calculatePolygonsLocalCS(): Either> = + nonEmptyListOf( + this, + ).right() // Conversions + /** Returns the coordinates of all vertices as a flattened list */ fun toVertexPositionElementList(): List = this.vertices.flatMap { it.toDoubleList() }.toList() companion object { - val TETRAGON = of( - Vector3D(-1.0, -1.0, 0.0), - Vector3D(-1.0, 1.0, 0.0), - Vector3D(1.0, 1.0, 0.0), - Vector3D(1.0, -1.0, 0.0), - tolerance = DEFAULT_TOLERANCE - ) + val TETRAGON = + of( + Vector3D(-1.0, -1.0, 0.0), + Vector3D(-1.0, 1.0, 0.0), + Vector3D(1.0, 1.0, 0.0), + Vector3D(1.0, -1.0, 0.0), + tolerance = DEFAULT_TOLERANCE, + ) /** * Constructs a polygon based on the [vectors]. */ - fun of(vararg vectors: Vector3D, tolerance: Double) = Polygon3D(vectors.toList().toNonEmptyListOrNull()!!, tolerance) + fun of( + vararg vectors: Vector3D, + tolerance: Double, + ) = Polygon3D(vectors.toList().toNonEmptyListOrNull()!!, tolerance) /** * Constructs a polygon based on a [Triple] of [vectors]. */ - fun of(vectors: Triple, tolerance: Double) = - Polygon3D(vectors.toList().toNonEmptyListOrNull()!!, tolerance) + fun of( + vectors: Triple, + tolerance: Double, + ) = Polygon3D(vectors.toList().toNonEmptyListOrNull()!!, tolerance) } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Rectangle3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Rectangle3D.kt index c101272c..007fff90 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Rectangle3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Rectangle3D.kt @@ -35,9 +35,8 @@ data class Rectangle3D( val length: Double, val width: Double, override val tolerance: Double, - override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY + override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, ) : AbstractSurface3D() { - // Properties and Initializers init { require(length.isFinite()) { "Length value must be finite." } @@ -61,8 +60,12 @@ data class Rectangle3D( } companion object { - - fun of(length: Option, width: Option, tolerance: Double, affineSequence: AffineSequence3D = AffineSequence3D.EMPTY): Rectangle3D { + fun of( + length: Option, + width: Option, + tolerance: Double, + affineSequence: AffineSequence3D = AffineSequence3D.EMPTY, + ): Rectangle3D { require(length.isSome()) { "Length must be defined." } require(width.isSome()) { "Width must be defined." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/AbstractGeometry2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/AbstractGeometry2D.kt index f5b1a609..7dac9508 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/AbstractGeometry2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/AbstractGeometry2D.kt @@ -23,7 +23,6 @@ import io.rtron.math.transform.AffineSequence2D * Abstract class for all geometric objects in 2D. */ abstract class AbstractGeometry2D : AbstractGeometry() { - /** * List of affine transformation matrices to move and rotate the geometric object. */ diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/Pose2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/Pose2D.kt index 9515b40e..acc7ba3c 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/Pose2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/Pose2D.kt @@ -27,13 +27,21 @@ import io.rtron.math.geometry.euclidean.twod.point.Vector2D */ data class Pose2D( val point: Vector2D, - val rotation: Rotation2D + val rotation: Rotation2D, ) { - // Operators - fun fuzzyEquals(o: Pose2D, distanceTolerance: Double, angleTolerance: Double) = this.point.fuzzyEquals(o.point, distanceTolerance) && + fun fuzzyEquals( + o: Pose2D, + distanceTolerance: Double, + angleTolerance: Double, + ) = this.point.fuzzyEquals(o.point, distanceTolerance) && this.rotation.fuzzyEquals(o.rotation, angleTolerance) - fun fuzzyUnequals(o: Pose2D, distanceTolerance: Double, angleTolerance: Double) = !fuzzyEquals(o, distanceTolerance, angleTolerance) + + fun fuzzyUnequals( + o: Pose2D, + distanceTolerance: Double, + angleTolerance: Double, + ) = !fuzzyEquals(o, distanceTolerance, angleTolerance) companion object { val ZERO = Pose2D(Vector2D.ZERO, Rotation2D.ZERO) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/Rotation2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/Rotation2D.kt index a3a90194..6b1447fa 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/Rotation2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/Rotation2D.kt @@ -32,9 +32,8 @@ import io.rtron.math.std.fuzzyEquals as doubleFuzzyEquals * @param angle angle in radians, whereas the angle 0.0 corresponds to the x-axis */ class Rotation2D( - angle: Double + angle: Double, ) { - // Properties and Initializers init { require(angle.isFinite()) { "Rotation angle must be finite." } @@ -46,21 +45,32 @@ class Rotation2D( // Operators operator fun plus(v: Rotation2D) = Rotation2D(angle + v.angle) + operator fun minus(v: Rotation2D) = Rotation2D(angle - v.angle) + operator fun times(m: Rotation2D) = Rotation2D(angle * m.angle) + operator fun div(m: Rotation2D) = Rotation2D(angle * m.angle) operator fun unaryPlus() = Rotation2D(this.angle) + operator fun unaryMinus() = Rotation2D(-this.angle) fun difference(v: Rotation2D): Double = normalizeAngle(normalizeAngle(angle, 0.0) - normalizeAngle(v.angle, 0.0), 0.0).absoluteValue - fun fuzzyEquals(o: Rotation2D, tolerance: Double): Boolean { + fun fuzzyEquals( + o: Rotation2D, + tolerance: Double, + ): Boolean { val adjustedThisAngle = if (doubleFuzzyEquals(this.angle, TWO_PI, tolerance)) this.angle - TWO_PI else this.angle val adjustedOtherAngle = if (doubleFuzzyEquals(o.angle, TWO_PI, tolerance)) o.angle - TWO_PI else o.angle return doubleFuzzyEquals(adjustedThisAngle, adjustedOtherAngle, tolerance) } - fun fuzzyUnequals(o: Rotation2D, tolerance: Double) = !fuzzyEquals(o, tolerance) + + fun fuzzyUnequals( + o: Rotation2D, + tolerance: Double, + ) = !fuzzyEquals(o, tolerance) // Methods @@ -82,9 +92,13 @@ class Rotation2D( // Conversions fun toAngleRadians() = this.angle + fun toAngleDegree() = this.angle * RAD_TO_DEG - fun toRotation3D(pitch: Double = 0.0, roll: Double = 0.0) = Rotation3D(angle, pitch, roll) + fun toRotation3D( + pitch: Double = 0.0, + roll: Double = 0.0, + ) = Rotation3D(angle, pitch, roll) companion object { val ZERO = Rotation2D(0.0) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/AbstractCurve2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/AbstractCurve2D.kt index c1b24cf1..cabec3b7 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/AbstractCurve2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/AbstractCurve2D.kt @@ -35,7 +35,6 @@ import io.rtron.math.range.length * Abstract class for all geometric curve objects in 2D. */ abstract class AbstractCurve2D : AbstractGeometry2D(), DefinableDomain, Tolerable { - // Properties /** length of the curve */ @@ -79,7 +78,9 @@ abstract class AbstractCurve2D : AbstractGeometry2D(), DefinableDomain, * @param curveRelativePoint point in curve relative coordinates for which the orientation is to be calculated * @return orientation tangential to this curve */ - fun calculateRotationLocalCS(curveRelativePoint: CurveRelativeVector1D): Either { + fun calculateRotationLocalCS( + curveRelativePoint: CurveRelativeVector1D, + ): Either { if (!domain.fuzzyContains(curveRelativePoint.curvePosition, tolerance)) { return GeometryException.ValueNotContainedInDomain(curveRelativePoint.curvePosition).left() } @@ -125,7 +126,9 @@ abstract class AbstractCurve2D : AbstractGeometry2D(), DefinableDomain, * @param curveRelativePoint point in curve relative coordinates for which the orientation is to be calculated * @return orientation tangential to this curve */ - fun calculateRotationGlobalCS(curveRelativePoint: CurveRelativeVector1D): Either { + fun calculateRotationGlobalCS( + curveRelativePoint: CurveRelativeVector1D, + ): Either { if (!domain.fuzzyContains(curveRelativePoint.curvePosition, tolerance)) { return GeometryException.ValueNotContainedInDomain(curveRelativePoint.curvePosition).left() } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Arc2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Arc2D.kt index c7b216dd..12337184 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Arc2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Arc2D.kt @@ -40,9 +40,8 @@ class Arc2D( length: Double, override val tolerance: Double, override val affineSequence: AffineSequence2D = AffineSequence2D.EMPTY, - endBoundType: BoundType = BoundType.OPEN + endBoundType: BoundType = BoundType.OPEN, ) : AbstractCurve2D() { - // Properties and Initializers init { require(curvature.isFinite()) { "Curvature must be finite." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CompositeCurve2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CompositeCurve2D.kt index 183f99ab..d35d4397 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CompositeCurve2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CompositeCurve2D.kt @@ -31,9 +31,8 @@ import io.rtron.math.range.Range data class CompositeCurve2D( val curveMembers: List, private val absoluteDomains: List>, - private val absoluteStarts: List + private val absoluteStarts: List, ) : AbstractCurve2D() { - // Properties and Initializers init { require(curveMembers.isNotEmpty()) { "Must contain at least one curve member." } @@ -74,7 +73,7 @@ data class CompositeCurve2D( absoluteDomains: List>, absoluteStarts: List, distanceTolerance: Double, - angleTolerance: Double + angleTolerance: Double, ): CompositeCurve2D { curveMembers.zipWithNext().forEach { val frontCurveMemberEndPose = it.first.calculatePoseGlobalCSUnbounded(CurveRelativeVector1D(it.first.length)) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CubicCurve2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CubicCurve2D.kt index c2a11067..191d90ff 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CubicCurve2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CubicCurve2D.kt @@ -37,9 +37,8 @@ class CubicCurve2D( length: Double, override val tolerance: Double, override val affineSequence: AffineSequence2D = AffineSequence2D.EMPTY, - endBoundType: BoundType = BoundType.OPEN + endBoundType: BoundType = BoundType.OPEN, ) : AbstractCurve2D() { - // Properties and Initializers init { diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/LateralTranslatedCurve2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/LateralTranslatedCurve2D.kt index ba587bf6..92bb5ca6 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/LateralTranslatedCurve2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/LateralTranslatedCurve2D.kt @@ -39,12 +39,13 @@ import io.rtron.math.transform.Affine2D data class LateralTranslatedCurve2D( private val baseCurve: AbstractCurve2D, private val lateralTranslationFunction: UnivariateFunction, - override val tolerance: Double + override val tolerance: Double, ) : AbstractCurve2D() { - // Properties and Initializers init { - require(lateralTranslationFunction.domain.fuzzyEncloses(baseCurve.domain, tolerance)) { "The lateral translation function must be defined everywhere where the curve is also defined." } + require(lateralTranslationFunction.domain.fuzzyEncloses(baseCurve.domain, tolerance)) { + "The lateral translation function must be defined everywhere where the curve is also defined." + } } override val domain: Range get() = baseCurve.domain @@ -52,8 +53,9 @@ data class LateralTranslatedCurve2D( // Methods override fun calculatePointLocalCSUnbounded(curveRelativePoint: CurveRelativeVector1D): Vector2D { - val curveAffine = baseCurve.calculatePoseGlobalCSUnbounded(curveRelativePoint) - .let { Affine2D.of(it) } + val curveAffine = + baseCurve.calculatePoseGlobalCSUnbounded(curveRelativePoint) + .let { Affine2D.of(it) } val translation = calculateTranslation(curveRelativePoint).getOrElse { throw it }.lateralOffset @@ -76,8 +78,10 @@ data class LateralTranslatedCurve2D( * @param multiplier multiplication factor, whereby 0.5 means that only 0.5 of the translation function is added * @return resulting [LateralTranslatedCurve2D] */ - fun addLateralTranslation(lateralTranslationFunction: UnivariateFunction, multiplier: Double = 1.0): - LateralTranslatedCurve2D { + fun addLateralTranslation( + lateralTranslationFunction: UnivariateFunction, + multiplier: Double = 1.0, + ): LateralTranslatedCurve2D { require(multiplier.isFinite()) { "Multiplier must be finite." } val lateralFunctions = listOf(this.lateralTranslationFunction, lateralTranslationFunction) @@ -88,13 +92,14 @@ data class LateralTranslatedCurve2D( /** * Returns the lateral translation at the [curveRelativePoint]. */ - private fun calculateTranslation(curveRelativePoint: CurveRelativeVector1D): - Either = either { - val translation = lateralTranslationFunction - .valueInFuzzy(curveRelativePoint.curvePosition, tolerance) - .bind() - .let { CurveRelativeVector2D(curveRelativePoint.curvePosition, it) } + private fun calculateTranslation(curveRelativePoint: CurveRelativeVector1D): Either = + either { + val translation = + lateralTranslationFunction + .valueInFuzzy(curveRelativePoint.curvePosition, tolerance) + .bind() + .let { CurveRelativeVector2D(curveRelativePoint.curvePosition, it) } - translation - } + translation + } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/LineSegment2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/LineSegment2D.kt index 68d5774e..738650d7 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/LineSegment2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/LineSegment2D.kt @@ -37,9 +37,8 @@ class LineSegment2D( length: Double, override val tolerance: Double, override val affineSequence: AffineSequence2D = AffineSequence2D.EMPTY, - endBoundType: BoundType = BoundType.OPEN + endBoundType: BoundType = BoundType.OPEN, ) : AbstractCurve2D() { - // Properties and Initializers init { require(length.isFinite()) { "Length value must be finite." } @@ -70,7 +69,6 @@ class LineSegment2D( fun toLineSegment2DCM() = segment2D companion object { - /** * Creates a [LineSegment2D] based on a [start] and a [end] point. * @@ -78,7 +76,11 @@ class LineSegment2D( * @param end end of line segment * @return returned [LineSegment2D] comprises an affine transformation matrix */ - fun of(start: Vector2D, end: Vector2D, tolerance: Double): LineSegment2D { + fun of( + start: Vector2D, + end: Vector2D, + tolerance: Double, + ): LineSegment2D { val length = end.distance(start) val pose = Pose2D(start, Vector2D.X_AXIS.angle(end - start)) val affineSequence = AffineSequence2D.of(Affine2D.of(pose)) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/ParameterTransformedCurve2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/ParameterTransformedCurve2D.kt index e1915cb7..6feeedea 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/ParameterTransformedCurve2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/ParameterTransformedCurve2D.kt @@ -37,9 +37,8 @@ import io.rtron.math.range.fuzzyEncloses data class ParameterTransformedCurve2D( private val baseCurve: AbstractCurve2D, private val transformationFunction: (CurveRelativeVector1D) -> CurveRelativeVector1D, - override val domain: Range + override val domain: Range, ) : AbstractCurve2D() { - // Properties and Initializers init { @@ -48,13 +47,16 @@ data class ParameterTransformedCurve2D( val lowerEndpoint = transformationFunction(CurveRelativeVector1D(domain.lowerEndpointOrNull()!!)) val upperEndpoint = transformationFunction(CurveRelativeVector1D(domain.upperEndpointOrNull()!!)) - val transformedDomain = Range.range( - domain.lowerBoundType(), - lowerEndpoint.curvePosition, - domain.upperBoundType(), - upperEndpoint.curvePosition - ) - require(baseCurve.domain.fuzzyEncloses(transformedDomain, tolerance)) { "The base curve must be defined everywhere where the parameter transformed curve is also defined." } + val transformedDomain = + Range.range( + domain.lowerBoundType(), + lowerEndpoint.curvePosition, + domain.upperBoundType(), + upperEndpoint.curvePosition, + ) + require(baseCurve.domain.fuzzyEncloses(transformedDomain, tolerance)) { + "The base curve must be defined everywhere where the parameter transformed curve is also defined." + } } override val tolerance: Double get() = baseCurve.tolerance diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/ParametricCubicCurve2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/ParametricCubicCurve2D.kt index c27c4dc8..33e3e11d 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/ParametricCubicCurve2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/ParametricCubicCurve2D.kt @@ -40,9 +40,8 @@ class ParametricCubicCurve2D( length: Double, override val tolerance: Double, override val affineSequence: AffineSequence2D = AffineSequence2D.EMPTY, - endBoundType: BoundType = BoundType.OPEN + endBoundType: BoundType = BoundType.OPEN, ) : AbstractCurve2D() { - // Properties and Initializers init { require(coefficientsX.size == 4) { "Requiring exactly four x coefficients for building a cubic curve." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SectionedCurve2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SectionedCurve2D.kt index bd04fcaa..5a2b92a6 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SectionedCurve2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SectionedCurve2D.kt @@ -33,12 +33,13 @@ import io.rtron.math.range.shiftLowerEndpointTo */ class SectionedCurve2D( private val completeCurve: AbstractCurve2D, - section: Range + section: Range, ) : AbstractCurve2D() { - // Properties and Initializers init { - require(completeCurve.domain.fuzzyEncloses(section, tolerance)) { "The complete function must be defined everywhere where the section is also defined." } + require(completeCurve.domain.fuzzyEncloses(section, tolerance)) { + "The complete function must be defined everywhere where the section is also defined." + } } override val domain: Range = section.shiftLowerEndpointTo(0.0) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Spiral2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Spiral2D.kt index 6c097001..ef6dc5cc 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Spiral2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Spiral2D.kt @@ -33,9 +33,8 @@ import kotlin.math.sqrt * @param cDot first derivative of curvature */ data class Spiral2D( - val cDot: Double + val cDot: Double, ) { - // Properties and Initializers val constantA: Double = 1.0 / sqrt(abs(cDot)) val constantAuxiliaryA: Double = constantA * sqrt(PI) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SpiralSegment2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SpiralSegment2D.kt index e51274f2..95e5573b 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SpiralSegment2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SpiralSegment2D.kt @@ -39,9 +39,8 @@ class SpiralSegment2D( private val curvatureFunction: LinearFunction, override val tolerance: Double, override val affineSequence: AffineSequence2D = AffineSequence2D.EMPTY, - endBoundType: BoundType = BoundType.OPEN + endBoundType: BoundType = BoundType.OPEN, ) : AbstractCurve2D() { - // Properties and Initializers private val lowerDomainEndpoint = @@ -52,7 +51,9 @@ class SpiralSegment2D( Range.closedX(lowerDomainEndpoint, upperDomainEndpoint, endBoundType) init { - require(lowerDomainEndpoint == 0.0) { "Lower endpoint of domain must be zero (for moving the spiral segment, the affine sequence is preferred)." } + require(lowerDomainEndpoint == 0.0) { + "Lower endpoint of domain must be zero (for moving the spiral segment, the affine sequence is preferred)." + } require(length.isFinite()) { "Length value must be finite." } require(length > tolerance) { "Length value must be greater than zero and the tolerance threshold." } require(curvatureFunction.slope.isFinite()) { "Curvature slope must be finite." } @@ -80,5 +81,8 @@ class SpiralSegment2D( } } -fun LinearFunction.Companion.ofSpiralCurvature(curvatureStart: Double, curvatureEnd: Double, length: Double): LinearFunction = - ofInclusiveInterceptAndPoint(curvatureStart, length, curvatureEnd) +fun LinearFunction.Companion.ofSpiralCurvature( + curvatureStart: Double, + curvatureEnd: Double, + length: Double, +): LinearFunction = ofInclusiveInterceptAndPoint(curvatureStart, length, curvatureEnd) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/point/Vector2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/point/Vector2D.kt index 6e307e82..300cc56c 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/point/Vector2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/point/Vector2D.kt @@ -36,9 +36,8 @@ fun JOMLVector2D.toVector2D() = Vector2D(this.x, this.y) */ data class Vector2D( val x: Double, - val y: Double + val y: Double, ) : AbstractPoint2D() { - // Properties and Initializers init { @@ -58,15 +57,27 @@ data class Vector2D( // Operators operator fun plus(v: Vector2D) = vector2D.add(v.vector2D).toVector2D() + operator fun minus(v: Vector2D) = vector2D.subtract(v.vector2D).toVector2D() + operator fun times(m: Double): Vector2D = scalarMultiply(m) + operator fun div(m: Double): Vector2D = scalarDivide(m) + operator fun unaryPlus() = Vector2D(x, y) + operator fun unaryMinus() = Vector2D(-x, -y) - fun fuzzyEquals(o: Vector2D, tolerance: Double) = doubleFuzzyEquals(this.x, o.x, tolerance) && + fun fuzzyEquals( + o: Vector2D, + tolerance: Double, + ) = doubleFuzzyEquals(this.x, o.x, tolerance) && doubleFuzzyEquals(this.y, o.y, tolerance) - fun fuzzyUnequals(o: Vector2D, tolerance: Double) = !fuzzyEquals(o, tolerance) + + fun fuzzyUnequals( + o: Vector2D, + tolerance: Double, + ) = !fuzzyEquals(o, tolerance) // Methods @@ -93,7 +104,9 @@ data class Vector2D( // Conversions fun toVector3D(z: Double = 0.0) = Vector3D(this.x, this.y, z) + fun toVector2DCm() = this.vector2D + fun toVector2DJOML() = JOMLVector2D(this.x, this.y) companion object { diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/surface/AbstractSurface2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/surface/AbstractSurface2D.kt index b1b2b038..cf967ebb 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/surface/AbstractSurface2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/surface/AbstractSurface2D.kt @@ -24,7 +24,6 @@ import io.rtron.math.range.Tolerable * Abstract class for all geometric surface objects in 2D. */ abstract class AbstractSurface2D : AbstractGeometry2D(), Tolerable { - /** * Returns true, if [point] is located within the surface. */ diff --git a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/surface/Polygon2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/surface/Polygon2D.kt index 95e2e007..baedd0df 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/surface/Polygon2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/geometry/euclidean/twod/surface/Polygon2D.kt @@ -28,14 +28,21 @@ import java.awt.geom.Path2D */ data class Polygon2D( val vertices: NonEmptyList, - override val tolerance: Double + override val tolerance: Double, ) : AbstractSurface2D() { - // Properties and Initializers private val numberOfVertices = vertices.size + init { require(numberOfVertices >= 3) { "Not enough vertices provided for constructing a polygon." } - require(vertices.noneWithNextEnclosing { a, b -> a.fuzzyEquals(b, tolerance) }) { "Consecutively following point duplicates found." } + require( + vertices.noneWithNextEnclosing { + a, + b, + -> + a.fuzzyEquals(b, tolerance) + }, + ) { "Consecutively following point duplicates found." } } private val awtPath by lazy { diff --git a/rtron-math/src/main/kotlin/io/rtron/math/linear/RealMatrix.kt b/rtron-math/src/main/kotlin/io/rtron/math/linear/RealMatrix.kt index d5a93614..340a5f0c 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/linear/RealMatrix.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/linear/RealMatrix.kt @@ -28,9 +28,8 @@ import org.apache.commons.math3.linear.RealMatrix as CMRealMatrix * @param rows the rows of the matrix represented as [DoubleArray] */ class RealMatrix( - rows: Array + rows: Array, ) { - // Properties and Initializers init { @@ -96,8 +95,10 @@ class RealMatrix( * @param selectedColumns selected column indices * @return submatrix */ - fun getSubMatrix(selectedRows: IntArray, selectedColumns: IntArray) = - RealMatrix(matrix.getSubMatrix(selectedRows, selectedColumns)) + fun getSubMatrix( + selectedRows: IntArray, + selectedColumns: IntArray, + ) = RealMatrix(matrix.getSubMatrix(selectedRows, selectedColumns)) /** * Returns a submatrix of the complete matrix by only selecting the [selectedRows] and [selectedColumns]. @@ -106,8 +107,10 @@ class RealMatrix( * @param selectedColumns selected column indices * @return submatrix */ - fun getSubMatrix(selectedRows: IntRange, selectedColumns: IntRange) = - getSubMatrix(selectedRows.toList().toIntArray(), selectedColumns.toList().toIntArray()) + fun getSubMatrix( + selectedRows: IntRange, + selectedColumns: IntRange, + ) = getSubMatrix(selectedRows.toList().toIntArray(), selectedColumns.toList().toIntArray()) /** Returns this matrix multiplied with [other] (return = this x [other]). */ fun multiply(other: RealMatrix) = RealMatrix(matrix.multiply(other.toRealMatrixCM())) @@ -133,7 +136,10 @@ class RealMatrix( /** Returns the inverse matrix of this matrix. */ fun inverse() = RealMatrix(MatrixUtils.inverse(matrix)) - fun normalize(rowIndex: Int, columnIndex: Int): RealMatrix { + fun normalize( + rowIndex: Int, + columnIndex: Int, + ): RealMatrix { require(this[rowIndex][columnIndex] != 0.0) { "Normalizing element must not be zero." } return scalarMultiply(1.0 / this[rowIndex][columnIndex]) } @@ -156,6 +162,7 @@ class RealMatrix( // Conversions fun toDoubleArray(): DoubleArray = matrix.data.flatMap { it.asIterable() }.toDoubleArray() + fun toDoubleList(): List = matrix.data.flatMap { it.asIterable() }.toList() /** Conversion to adapted Real Matrix class from Apache Commons Math. */ @@ -166,7 +173,6 @@ class RealMatrix( } companion object { - /** * Creates a [RealMatrix] from a list of column [RealVector]. * @@ -178,7 +184,13 @@ class RealMatrix( require(columnVectors.isNotEmpty()) { "No column vectors provided for building a matrix." } require(columnVectors.all { it.dimension == rowDimension }) { "Provided column vectors have different dimensions." } - val matrixValues = (0 until rowDimension).fold(emptyList()) { acc, currentRowIndex -> acc + columnVectors.map { it[currentRowIndex] }.toDoubleArray() } + val matrixValues = + (0 until rowDimension).fold(emptyList()) { acc, currentRowIndex -> + acc + + columnVectors.map { + it[currentRowIndex] + }.toDoubleArray() + } return RealMatrix(matrixValues.toTypedArray()) } @@ -189,8 +201,7 @@ class RealMatrix( * @param vectors list of 3D vectors whereby each vector will be represented as a row */ @JvmName("ofListVector3D") - fun of(vectors: List): RealMatrix = - RealMatrix(vectors.map { it.toRealVector() }) + fun of(vectors: List): RealMatrix = RealMatrix(vectors.map { it.toRealVector() }) /** * Creates an identity [RealMatrix] of the [dimension]. diff --git a/rtron-math/src/main/kotlin/io/rtron/math/linear/RealVector.kt b/rtron-math/src/main/kotlin/io/rtron/math/linear/RealVector.kt index 36352ba6..98812198 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/linear/RealVector.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/linear/RealVector.kt @@ -28,9 +28,8 @@ fun CMRealVector.toRealVector() = RealVector(this.toArray()!!) * @param entries entry values of the real vector */ class RealVector( - private val entries: DoubleArray + private val entries: DoubleArray, ) { - // Properties and Initializers /** adapted Apache Commons Math vector */ @@ -48,7 +47,9 @@ class RealVector( // Operators operator fun get(index: Int): Double = vector.getEntry(index) + operator fun plus(v: RealVector) = vector.add(v.vector).toRealVector() + operator fun minus(v: RealVector) = vector.subtract(v.vector).toRealVector() // Methods @@ -92,6 +93,7 @@ class RealVector( // Conversions fun toDoubleArray(): DoubleArray = vector.toArray()!! + fun toDoubleList(): List = toDoubleArray().toList() /** Conversion to adapted Real Vector class from Apache Commons Math. */ diff --git a/rtron-math/src/main/kotlin/io/rtron/math/linear/SingularValueDecomposition.kt b/rtron-math/src/main/kotlin/io/rtron/math/linear/SingularValueDecomposition.kt index ebb346dc..dbffe663 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/linear/SingularValueDecomposition.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/linear/SingularValueDecomposition.kt @@ -25,9 +25,8 @@ import org.apache.commons.math3.linear.SingularValueDecomposition as CMSingularV * @param matrix matrix to be decomposed */ class SingularValueDecomposition( - matrix: RealMatrix + matrix: RealMatrix, ) { - // Properties and Initializers private val singularValueDecomposition by lazy { CMSingularValueDecomposition(matrix.toRealMatrixCM()) } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/processing/Vector3DListExtensions.kt b/rtron-math/src/main/kotlin/io/rtron/math/processing/Vector3DListExtensions.kt index cb7b0181..7db0823f 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/processing/Vector3DListExtensions.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/processing/Vector3DListExtensions.kt @@ -51,11 +51,12 @@ fun Triple.isColinear(tolerance: Double): Boolean val distanceFirstThird = first.distance(third) if (distanceFirstSecond < tolerance || distanceFirstThird < tolerance) return true - val line = if (distanceFirstSecond < distanceFirstThird) { - Line3D(first, third, tolerance) - } else { - Line3D(first, second, tolerance) - } + val line = + if (distanceFirstSecond < distanceFirstThird) { + Line3D(first, third, tolerance) + } else { + Line3D(first, second, tolerance) + } val point = if (distanceFirstSecond < distanceFirstThird) second else third return line.distance(point) < tolerance @@ -103,16 +104,20 @@ fun List.calculateBestFittingPlane(tolerance: Double): Plane3D { * @param tolerance tolerated distance between points and the plane * @param dynamicToleranceAdjustment increases the tolerance when numbers are greater */ -fun List.isPlanar(tolerance: Double, dynamicToleranceAdjustment: Boolean = true): Boolean { +fun List.isPlanar( + tolerance: Double, + dynamicToleranceAdjustment: Boolean = true, +): Boolean { require(size >= 3) { "Planarity check requires the provision of at least three points." } - val adjustedTolerance = if (dynamicToleranceAdjustment) { - val u = Math.ulp(this.flatMap { it.toDoubleList() }.maxOf(::abs)) - val dynamicFactor = u / DBL_EPSILON - tolerance * dynamicFactor - } else { - tolerance - } + val adjustedTolerance = + if (dynamicToleranceAdjustment) { + val u = Math.ulp(this.flatMap { it.toDoubleList() }.maxOf(::abs)) + val dynamicFactor = u / DBL_EPSILON + tolerance * dynamicFactor + } else { + tolerance + } val bestFittingPlane = this.calculateBestFittingPlane(tolerance) return this.all { bestFittingPlane.getOffset(it) <= adjustedTolerance } @@ -131,8 +136,7 @@ fun List.calculateNormal(): Vector3D = * Calculates the centroid of a list of [Vector3D]. * See the wikipedia article of [Centroid](https://en.wikipedia.org/wiki/Centroid). */ -fun List.calculateCentroid(): Vector3D = - this.reduce { sum, point -> sum + point }.div(this.size.toDouble()) +fun List.calculateCentroid(): Vector3D = this.reduce { sum, point -> sum + point }.div(this.size.toDouble()) /** * Conversion to a string of coordinates. diff --git a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/FanTriangulationAlgorithm.kt b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/FanTriangulationAlgorithm.kt index ab37231f..e6f958a4 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/FanTriangulationAlgorithm.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/FanTriangulationAlgorithm.kt @@ -31,16 +31,19 @@ import io.rtron.math.processing.isColinear * See the wikipedia article on [fan triangulation](https://en.wikipedia.org/wiki/Fan_triangulation). */ class FanTriangulationAlgorithm : TriangulationAlgorithm() { - - override fun triangulate(vertices: NonEmptyList, tolerance: Double): Either> { + override fun triangulate( + vertices: NonEmptyList, + tolerance: Double, + ): Either> { if (vertices.tail.any { vertices.head.fuzzyEquals(it, tolerance) }) { return TriangulatorException.FirstVertexDuplicated().left() } - val polygons = vertices.tail - .zipWithNext() - .filter { !listOf(vertices.head, it.first, it.second).isColinear(tolerance) } - .map { Polygon3D(nonEmptyListOf(vertices.head, it.first, it.second), tolerance) } + val polygons = + vertices.tail + .zipWithNext() + .filter { !listOf(vertices.head, it.first, it.second).isColinear(tolerance) } + .map { Polygon3D(nonEmptyListOf(vertices.head, it.first, it.second), tolerance) } return polygons.right() } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/Poly2TriTriangulationAlgorithm.kt b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/Poly2TriTriangulationAlgorithm.kt index cd783bcb..6a3db638 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/Poly2TriTriangulationAlgorithm.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/Poly2TriTriangulationAlgorithm.kt @@ -36,15 +36,18 @@ import org.poly2tri.geometry.polygon.PolygonPoint as P2TPolygonPoint * Adapts the triangulation algorithm of [Poly2Tri](https://github.com/orbisgis/poly2tri.java). */ class Poly2TriTriangulationAlgorithm : TriangulationAlgorithm() { + override fun triangulate( + vertices: NonEmptyList, + tolerance: Double, + ): Either> = + either { + val polygon = P2TPolygon(vertices.toList().map { P2TPolygonPoint(it.x, it.y, it.z) }) - override fun triangulate(vertices: NonEmptyList, tolerance: Double): Either> = either { - val polygon = P2TPolygon(vertices.toList().map { P2TPolygonPoint(it.x, it.y, it.z) }) + poly2TriTriangulation(polygon).bind() + val triangles = polygonBackConversion(polygon, tolerance).bind() - poly2TriTriangulation(polygon).bind() - val triangles = polygonBackConversion(polygon, tolerance).bind() - - adjustOrientation(vertices, triangles) - } + adjustOrientation(vertices, triangles) + } /** * Performs the Poly2Tri triangulation, which runs on the mutable [polygon]. @@ -65,19 +68,23 @@ class Poly2TriTriangulationAlgorithm : TriangulationAlgorithm() { /** * Converts the Poly2Tri triangulation results back to a list of [Polygon3D]. */ - private fun polygonBackConversion(polygon: P2TPolygon, tolerance: Double): - Either> { - val triangles = polygon.triangles.map { delaunayTriangle -> + private fun polygonBackConversion( + polygon: P2TPolygon, + tolerance: Double, + ): Either> { + val triangles = + polygon.triangles.map { delaunayTriangle -> - val triangulatedVertices: NonEmptyList = delaunayTriangle.points - .map { point -> Vector3D(point.x, point.y, point.z) } - .let { it.toNonEmptyListOrNull()!! } + val triangulatedVertices: NonEmptyList = + delaunayTriangle.points + .map { point -> Vector3D(point.x, point.y, point.z) } + .let { it.toNonEmptyListOrNull()!! } - if (triangulatedVertices.isColinear(tolerance)) { - return TriangulatorException.ColinearVertices().left() + if (triangulatedVertices.isColinear(tolerance)) { + return TriangulatorException.ColinearVertices().left() + } + return@map Polygon3D(triangulatedVertices, tolerance) } - return@map Polygon3D(triangulatedVertices, tolerance) - } return Either.Right(triangles) } @@ -91,7 +98,10 @@ class Poly2TriTriangulationAlgorithm : TriangulationAlgorithm() { * @param triangles triangles for which the orientation is to be adjusted * @return triangles with adjusted orientation */ - private fun adjustOrientation(originalVertices: List, triangles: List): List { + private fun adjustOrientation( + originalVertices: List, + triangles: List, + ): List { val referenceNormal = originalVertices.calculateNormal() return triangles.map { val triangleNormal = it.vertices.calculateNormal() diff --git a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/ProjectedTriangulationAlgorithm.kt b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/ProjectedTriangulationAlgorithm.kt index e706858a..be66bcd3 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/ProjectedTriangulationAlgorithm.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/ProjectedTriangulationAlgorithm.kt @@ -34,27 +34,35 @@ import io.rtron.math.transform.AffineSequence3D * @param triangulationAlgorithm actual triangulation algorithm applied after plane projection */ class ProjectedTriangulationAlgorithm( - private val triangulationAlgorithm: TriangulationAlgorithm + private val triangulationAlgorithm: TriangulationAlgorithm, ) : TriangulationAlgorithm() { + override fun triangulate( + vertices: NonEmptyList, + tolerance: Double, + ): Either> = + either { + val projectedVertices = projectVertices(vertices, tolerance) + val projectedPolygonsTriangulated = + triangulationAlgorithm + .triangulate(projectedVertices, tolerance).bind() - override fun triangulate(vertices: NonEmptyList, tolerance: Double): Either> = either { - val projectedVertices = projectVertices(vertices, tolerance) - val projectedPolygonsTriangulated = triangulationAlgorithm - .triangulate(projectedVertices, tolerance).bind() - - projectedPolygonsTriangulated.map { constructPolygon(it, projectedVertices, vertices, tolerance).bind() } - } + projectedPolygonsTriangulated.map { constructPolygon(it, projectedVertices, vertices, tolerance).bind() } + } /** * Projects the [vertices] into a best fitting plane. */ - private fun projectVertices(vertices: NonEmptyList, tolerance: Double): NonEmptyList { - val affine = run { - val plane = vertices.calculateBestFittingPlane(tolerance) - val affineTranslation = Affine3D.of(plane.point) - val affineNewBasis = Affine3D.of(plane.vectorU, plane.vectorV, plane.normal) - AffineSequence3D.of(affineTranslation, affineNewBasis).solve() - } + private fun projectVertices( + vertices: NonEmptyList, + tolerance: Double, + ): NonEmptyList { + val affine = + run { + val plane = vertices.calculateBestFittingPlane(tolerance) + val affineTranslation = Affine3D.of(plane.point) + val affineNewBasis = Affine3D.of(plane.vectorU, plane.vectorV, plane.normal) + AffineSequence3D.of(affineTranslation, affineNewBasis).solve() + } return affine.transform(vertices) } @@ -72,16 +80,17 @@ class ProjectedTriangulationAlgorithm( projectedPolygon: Polygon3D, allProjectedVertices: List, allOriginalVertices: List, - tolerance: Double + tolerance: Double, ): Either { if (!allProjectedVertices.containsAll(projectedPolygon.vertices)) { return TriangulatorException.DifferentVertices().left() } - val constructedPolygon = projectedPolygon.vertices - .map { allProjectedVertices.indexOf(it) } - .map { allOriginalVertices[it] } - .let { Polygon3D(it, tolerance) } + val constructedPolygon = + projectedPolygon.vertices + .map { allProjectedVertices.indexOf(it) } + .map { allOriginalVertices[it] } + .let { Polygon3D(it, tolerance) } return Either.Right(constructedPolygon) } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/TriangulationAlgorithm.kt b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/TriangulationAlgorithm.kt index 0175f42d..fbaa8949 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/TriangulationAlgorithm.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/TriangulationAlgorithm.kt @@ -28,7 +28,6 @@ import io.rtron.math.geometry.euclidean.threed.surface.Polygon3D * See the wikipedia article of [polygon triangulation](https://en.wikipedia.org/wiki/Polygon_triangulation). */ abstract class TriangulationAlgorithm { - /** * Performs the triangulation operation and checks whether all input vertices are still represented * after triangulation. @@ -36,16 +35,20 @@ abstract class TriangulationAlgorithm { * @param vertices list of vertices representing the outline to be triangulated * @return list of triangulated [Polygon3D] */ - fun triangulateChecked(vertices: NonEmptyList, tolerance: Double): Either> = either { - val triangles = triangulate(vertices, tolerance).bind() + fun triangulateChecked( + vertices: NonEmptyList, + tolerance: Double, + ): Either> = + either { + val triangles = triangulate(vertices, tolerance).bind() - val newVertices = triangles.flatMap { it.vertices } - if (newVertices.any { it !in vertices }) { - TriangulatorException.DifferentVertices().left().bind>() - } + val newVertices = triangles.flatMap { it.vertices } + if (newVertices.any { it !in vertices }) { + TriangulatorException.DifferentVertices().left().bind>() + } - triangles - } + triangles + } /** * Triangulation algorithm implemented by concrete classes. @@ -53,5 +56,8 @@ abstract class TriangulationAlgorithm { * @param vertices list of vertices representing the outline to be triangulated * @return list of triangulated [Polygon3D] */ - internal abstract fun triangulate(vertices: NonEmptyList, tolerance: Double): Either> + internal abstract fun triangulate( + vertices: NonEmptyList, + tolerance: Double, + ): Either> } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/Triangulator.kt b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/Triangulator.kt index 9bc9e17c..a10b8cf4 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/Triangulator.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/Triangulator.kt @@ -27,7 +27,6 @@ import io.rtron.math.processing.isPlanar * See the wikipedia article of [polygon triangulation](https://en.wikipedia.org/wiki/Polygon_triangulation). */ object Triangulator { - private val standardTriangulationAlgorithm = Poly2TriTriangulationAlgorithm() private val fallbackTriangulationAlgorithm = ProjectedTriangulationAlgorithm(standardTriangulationAlgorithm) private val fanTriangulationAlgorithm = FanTriangulationAlgorithm() @@ -37,14 +36,18 @@ object Triangulator { * * @param linearRing linear ring to be triangulated */ - fun triangulate(linearRing: LinearRing3D, tolerance: Double): Either> { + fun triangulate( + linearRing: LinearRing3D, + tolerance: Double, + ): Either> { if (linearRing.vertices.isPlanar(tolerance)) { return Either.Right(listOf(Polygon3D(linearRing.vertices, tolerance))) } // run triangulation algorithms until one succeeds - val standardResult = standardTriangulationAlgorithm.triangulateChecked(linearRing.vertices, tolerance) - .onRight { return it.right() } + val standardResult = + standardTriangulationAlgorithm.triangulateChecked(linearRing.vertices, tolerance) + .onRight { return it.right() } fallbackTriangulationAlgorithm.triangulateChecked(linearRing.vertices, tolerance) .onRight { return it.right() } fanTriangulationAlgorithm.triangulateChecked(linearRing.vertices, tolerance) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/TriangulatorException.kt b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/TriangulatorException.kt index aa720a4c..b58fa208 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/TriangulatorException.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/processing/triangulation/TriangulatorException.kt @@ -18,7 +18,10 @@ package io.rtron.math.processing.triangulation sealed class TriangulatorException(val message: String) { data class Poly2TriException(val reason: String) : TriangulatorException("Poly2Tri-Triangulation failure: $reason") + data class DifferentVertices(val suffix: String = "") : TriangulatorException("Triangulation algorithm produced different vertices.") + data class ColinearVertices(val suffix: String = "") : TriangulatorException("Triangulation failure (colinear vertices).") + data class FirstVertexDuplicated(val suffix: String = "") : TriangulatorException("First vertex has duplicate vertices.") } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/projection/CoordinateReferenceSystem.kt b/rtron-math/src/main/kotlin/io/rtron/math/projection/CoordinateReferenceSystem.kt index c406bfa5..0356a4c8 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/projection/CoordinateReferenceSystem.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/projection/CoordinateReferenceSystem.kt @@ -30,9 +30,8 @@ import org.locationtech.proj4j.CoordinateReferenceSystem as ProjCoordinateRefere * @param crs adapted CRS class from PROJ */ class CoordinateReferenceSystem( - private val crs: ProjCoordinateReferenceSystem + private val crs: ProjCoordinateReferenceSystem, ) { - // Properties and Initializers /** Name of CRS */ @@ -50,7 +49,6 @@ class CoordinateReferenceSystem( // Methods companion object { - private val projCRSFactory = ProjCRSFactory() /** @@ -62,11 +60,12 @@ class CoordinateReferenceSystem( * Creates a [CoordinateReferenceSystem] based on the provided [crsName]. */ fun of(crsName: String): Either { - val crs = try { - projCRSFactory.createFromName(crsName) - } catch (e: Exception) { - return CoordinateReferenceSystemException.UnkownEpsgCode(e.toString()).left() - } + val crs = + try { + projCRSFactory.createFromName(crsName) + } catch (e: Exception) { + return CoordinateReferenceSystemException.UnkownEpsgCode(e.toString()).left() + } return when (crs) { null -> CoordinateReferenceSystemException.UnkownEpsgCode("Unknown EPSG code.").left() else -> CoordinateReferenceSystem(crs).right() @@ -78,14 +77,16 @@ class CoordinateReferenceSystem( * * @param parameters PROJ.4 projection parameter string */ - fun ofParameters(parameters: String): Either = either { - val epsgCode = parametersToEpsgCode(parameters).bind() - of(epsgCode).bind() - } + fun ofParameters(parameters: String): Either = + either { + val epsgCode = parametersToEpsgCode(parameters).bind() + of(epsgCode).bind() + } private fun parametersToEpsgCode(parameters: String): Either { - val result = projCRSFactory.readEpsgFromParameters(parameters) - ?: return CoordinateReferenceSystemException.UnkownEpsgCode("Cannot derive EPSG code from parameters.").left() + val result = + projCRSFactory.readEpsgFromParameters(parameters) + ?: return CoordinateReferenceSystemException.UnkownEpsgCode("Cannot derive EPSG code from parameters.").left() return result.toInt().right() } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/range/BoundType.kt b/rtron-math/src/main/kotlin/io/rtron/math/range/BoundType.kt index 04347161..f20e7143 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/range/BoundType.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/range/BoundType.kt @@ -30,20 +30,22 @@ enum class BoundType { CLOSED, /** no bound, such as the upper bound in [3, ∞) */ - NONE + NONE, } // Conversions /** Conversion from Guava Bound Type class. */ -fun GBoundType.toBoundType() = when (this) { - GBoundType.OPEN -> BoundType.OPEN - GBoundType.CLOSED -> BoundType.CLOSED -} +fun GBoundType.toBoundType() = + when (this) { + GBoundType.OPEN -> BoundType.OPEN + GBoundType.CLOSED -> BoundType.CLOSED + } /** Conversion to Guava Bound Type class. */ -fun BoundType.toBoundTypeG(): GBoundType? = when (this) { - BoundType.OPEN -> GBoundType.OPEN - BoundType.CLOSED -> GBoundType.CLOSED - BoundType.NONE -> null -} +fun BoundType.toBoundTypeG(): GBoundType? = + when (this) { + BoundType.OPEN -> GBoundType.OPEN + BoundType.CLOSED -> GBoundType.CLOSED + BoundType.NONE -> null + } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/range/DefinableDomain.kt b/rtron-math/src/main/kotlin/io/rtron/math/range/DefinableDomain.kt index efa57686..4082abfc 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/range/DefinableDomain.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/range/DefinableDomain.kt @@ -21,7 +21,6 @@ package io.rtron.math.range * See wikipedia article on [domain of a function](https://en.wikipedia.org/wiki/Domain_of_a_function). */ interface DefinableDomain> { - /** definable [domain] */ val domain: Range } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/range/DoubleRangeExtensions.kt b/rtron-math/src/main/kotlin/io/rtron/math/range/DoubleRangeExtensions.kt index 4c900236..d3269d05 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/range/DoubleRangeExtensions.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/range/DoubleRangeExtensions.kt @@ -30,7 +30,11 @@ import kotlin.math.sign * @param tolerance tolerance for checking whether endpoint is already included * @return [DoubleArray] of arranged values from lowerEndPoint to upperEndPoint of [Range] */ -fun Range.arrange(step: Double, includeClosedEndPoint: Boolean = false, tolerance: Double): DoubleArray { +fun Range.arrange( + step: Double, + includeClosedEndPoint: Boolean = false, + tolerance: Double, +): DoubleArray { val lowerEndpoint = lowerEndpointOrNull() requireNotNull(lowerEndpoint) { "Closed lower bound type required." } val upperEndpoint = upperEndpointOrNull() @@ -58,14 +62,18 @@ fun Range.arrange(step: Double, includeClosedEndPoint: Boolean = false, * @param tolerance allowed tolerance fuzziness * @return true, if [value] is contained */ -fun Range.fuzzyContains(value: Double, tolerance: Double): Boolean = when { - hasLowerBound() && !hasUpperBound() -> fuzzyLessThanOrEquals(lowerEndpointOrNull()!!, value, tolerance) - !hasLowerBound() && hasUpperBound() -> fuzzyLessThanOrEquals(value, upperEndpointOrNull()!!, tolerance) - !hasLowerBound() && !hasUpperBound() -> value in this - else -> - fuzzyLessThanOrEquals(lowerEndpointOrNull()!!, value, tolerance) && - fuzzyLessThanOrEquals(value, upperEndpointOrNull()!!, tolerance) -} +fun Range.fuzzyContains( + value: Double, + tolerance: Double, +): Boolean = + when { + hasLowerBound() && !hasUpperBound() -> fuzzyLessThanOrEquals(lowerEndpointOrNull()!!, value, tolerance) + !hasLowerBound() && hasUpperBound() -> fuzzyLessThanOrEquals(value, upperEndpointOrNull()!!, tolerance) + !hasLowerBound() && !hasUpperBound() -> value in this + else -> + fuzzyLessThanOrEquals(lowerEndpointOrNull()!!, value, tolerance) && + fuzzyLessThanOrEquals(value, upperEndpointOrNull()!!, tolerance) + } /** * Widens the lower bound of the [Range] by [lowerWideningValue] and the upper bound of the @@ -75,12 +83,16 @@ fun Range.fuzzyContains(value: Double, tolerance: Double): Boolean = whe * @param upperWideningValue the value for widening the upper bound * @return widened [Range] */ -fun Range.widened(lowerWideningValue: Double, upperWideningValue: Double): Range = Range.rangeOfNullable( - lowerBoundType = lowerBoundType(), - lowerEndpoint = lowerEndpointOrNull()?.let { it - lowerWideningValue }, - upperBoundType = upperBoundType(), - upperEndpoint = upperEndpointOrNull()?.let { it + upperWideningValue } -) +fun Range.widened( + lowerWideningValue: Double, + upperWideningValue: Double, +): Range = + Range.rangeOfNullable( + lowerBoundType = lowerBoundType(), + lowerEndpoint = lowerEndpointOrNull()?.let { it - lowerWideningValue }, + upperBoundType = upperBoundType(), + upperEndpoint = upperEndpointOrNull()?.let { it + upperWideningValue }, + ) /** * Widens the [Range] by [wideningValue] on the lower and upper bound. @@ -97,8 +109,10 @@ fun Range.widened(wideningValue: Double): Range = widened(wideni * @param tolerance allowed tolerance * @return true, if [other] is enclosed */ -fun Range.fuzzyEncloses(other: Range, tolerance: Double): Boolean = - this.widened(tolerance) encloses other +fun Range.fuzzyEncloses( + other: Range, + tolerance: Double, +): Boolean = this.widened(tolerance) encloses other /** * Difference between the upper and lower bound of the [Range]. @@ -122,12 +136,13 @@ val Range.length * @param value value the [Range] is to be shifted by * @return shifted [Range] */ -fun Range.shift(value: Double): Range = Range.rangeOfNullable( - lowerBoundType = this.lowerBoundType(), - lowerEndpoint = this.lowerEndpointOrNull()?.let { it + value }, - upperBoundType = this.upperBoundType(), - upperEndpoint = this.upperEndpointOrNull()?.let { it + value } -) +fun Range.shift(value: Double): Range = + Range.rangeOfNullable( + lowerBoundType = this.lowerBoundType(), + lowerEndpoint = this.lowerEndpointOrNull()?.let { it + value }, + upperBoundType = this.upperBoundType(), + upperEndpoint = this.upperEndpointOrNull()?.let { it + value }, + ) /** * Shift the [Range] so that the lower endpoint is represented by the [value]. @@ -135,9 +150,10 @@ fun Range.shift(value: Double): Range = Range.rangeOfNullable( * @param value new lower endpoint after shifting [Range] * @return shifted [Range] */ -fun Range.shiftLowerEndpointTo(value: Double): Range = Range.range( - lowerBoundType = this.lowerBoundType(), - lowerEndpoint = value, - upperBoundType = this.upperBoundType(), - upperEndpoint = value + this.length -) +fun Range.shiftLowerEndpointTo(value: Double): Range = + Range.range( + lowerBoundType = this.lowerBoundType(), + lowerEndpoint = value, + upperBoundType = this.upperBoundType(), + upperEndpoint = value + this.length, + ) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/range/DoubleRangeSetExtensions.kt b/rtron-math/src/main/kotlin/io/rtron/math/range/DoubleRangeSetExtensions.kt index 0abccd42..dc491d26 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/range/DoubleRangeSetExtensions.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/range/DoubleRangeSetExtensions.kt @@ -22,5 +22,4 @@ fun RangeSet.Companion.ofNonIntersectingRanges(ranges: Set>): Rang return rangeSets.unionRangeSets() } -fun RangeSet.Companion.ofNonIntersectingRanges(vararg ranges: Range): RangeSet = - ofNonIntersectingRanges(ranges.toSet()) +fun RangeSet.Companion.ofNonIntersectingRanges(vararg ranges: Range): RangeSet = ofNonIntersectingRanges(ranges.toSet()) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/range/Range.kt b/rtron-math/src/main/kotlin/io/rtron/math/range/Range.kt index 416644b0..8dafbbd2 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/range/Range.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/range/Range.kt @@ -29,7 +29,7 @@ fun > GRange.toRange() = Range(this) * @param range adapted guava range class */ class Range>( - private val range: GRange + private val range: GRange, ) { // Operators @@ -166,7 +166,6 @@ class Range>( override fun toString() = "Range($range)" companion object { - /** * Creates a [Range] based on bound type and endpoint values. If bound type is [BoundType.NONE] the * respective endpoint value must be null for consistency reasons. @@ -182,7 +181,7 @@ class Range>( lowerBoundType: BoundType, lowerEndpoint: T?, upperBoundType: BoundType, - upperEndpoint: T? + upperEndpoint: T?, ): Range { // consistency checks if (lowerBoundType == BoundType.NONE) { @@ -214,7 +213,7 @@ class Range>( lowerEndpoint!!, lowerBoundType.toBoundTypeG()!!, upperEndpoint!!, - upperBoundType.toBoundTypeG()!! + upperBoundType.toBoundTypeG()!!, ).toRange() } @@ -231,7 +230,7 @@ class Range>( lowerBoundType: BoundType, lowerEndpoint: T, upperBoundType: BoundType, - upperEndpoint: T + upperEndpoint: T, ): Range { val lowerEndpointNullable: T? = if (lowerBoundType == BoundType.NONE) null else lowerEndpoint val upperEndpointNullable: T? = if (upperBoundType == BoundType.NONE) null else upperEndpoint @@ -240,16 +239,28 @@ class Range>( } /** Creates a [Range] of the form ([lower], [upper]). */ - fun > open(lower: T, upper: T): Range = GRange.open(lower, upper).toRange() + fun > open( + lower: T, + upper: T, + ): Range = GRange.open(lower, upper).toRange() /** Creates a [Range] of the form [[lower], [upper]]. */ - fun > closed(lower: T, upper: T): Range = GRange.closed(lower, upper).toRange() + fun > closed( + lower: T, + upper: T, + ): Range = GRange.closed(lower, upper).toRange() /** Creates a [Range] of the form ([lower], [upper]]. */ - fun > openClosed(lower: T, upper: T): Range = GRange.openClosed(lower, upper).toRange() + fun > openClosed( + lower: T, + upper: T, + ): Range = GRange.openClosed(lower, upper).toRange() /** Creates a [Range] of the form [[lower], [upper]). */ - fun > closedOpen(lower: T, upper: T): Range = GRange.closedOpen(lower, upper).toRange() + fun > closedOpen( + lower: T, + upper: T, + ): Range = GRange.closedOpen(lower, upper).toRange() /** Creates a [Range] of the form ([endpoint], ∞). */ fun > greaterThan(endpoint: T): Range = GRange.greaterThan(endpoint).toRange() @@ -273,7 +284,10 @@ class Range>( * @param boundType type of bound which must not be [BoundType.NONE] * @return created [Range] */ - fun > downTo(endpoint: T, boundType: BoundType): Range { + fun > downTo( + endpoint: T, + boundType: BoundType, + ): Range { require(boundType != BoundType.NONE) { "Provided bound type must not be none." } return GRange.downTo(endpoint, boundType.toBoundTypeG()!!).toRange() } @@ -285,7 +299,10 @@ class Range>( * @param boundType type of bound which must not be [BoundType.NONE] * @return created [Range] */ - fun > upTo(endpoint: T, boundType: BoundType): Range { + fun > upTo( + endpoint: T, + boundType: BoundType, + ): Range { require(boundType != BoundType.NONE) { "Provided bound type must not be none." } return GRange.upTo(endpoint, boundType.toBoundTypeG()!!).toRange() } @@ -298,7 +315,11 @@ class Range>( * @param upperBoundType type of upper bound which must not be [BoundType.NONE] * @return created [Range] */ - fun > closedX(lower: T, upper: T, upperBoundType: BoundType): Range = + fun > closedX( + lower: T, + upper: T, + upperBoundType: BoundType, + ): Range = when (upperBoundType) { BoundType.CLOSED -> closed(lower, upper) BoundType.OPEN -> closedOpen(lower, upper) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/range/RangeExtensions.kt b/rtron-math/src/main/kotlin/io/rtron/math/range/RangeExtensions.kt index e1e8436c..23b71927 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/range/RangeExtensions.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/range/RangeExtensions.kt @@ -6,14 +6,12 @@ package io.rtron.math.range * @receiver provided set of ranges for which the intersecting range shall be found * @return maximum range that intersects all ranges within the set */ -fun > Set>.intersectingRange(): Range = - reduce { acc, element -> acc.intersection(element) } +fun > Set>.intersectingRange(): Range = reduce { acc, element -> acc.intersection(element) } /** * Union operation of a set of [Range] to a [RangeSet]. */ -fun > Set>.unionRanges(): RangeSet = - map { RangeSet.of(it) }.toSet().unionRangeSets() +fun > Set>.unionRanges(): RangeSet = map { RangeSet.of(it) }.toSet().unionRangeSets() /** * Returns true, if the set of ranges contains intersecting [Range]. diff --git a/rtron-math/src/main/kotlin/io/rtron/math/range/RangeSet.kt b/rtron-math/src/main/kotlin/io/rtron/math/range/RangeSet.kt index a3aa2e0c..a595748b 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/range/RangeSet.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/range/RangeSet.kt @@ -28,9 +28,8 @@ fun > GImmutableRangeSet.toRangeSet() = RangeSet(this) * @param rangeSet adapted Guava class */ class RangeSet>( - private val rangeSet: GImmutableRangeSet + private val rangeSet: GImmutableRangeSet, ) { - // Secondary Constructors constructor(ranges: Set>) : @@ -111,7 +110,6 @@ class RangeSet>( } companion object { - /** * Creates an empty [RangeSet]. */ diff --git a/rtron-math/src/main/kotlin/io/rtron/math/range/RangeSetExtensions.kt b/rtron-math/src/main/kotlin/io/rtron/math/range/RangeSetExtensions.kt index bfbd9215..1593ed08 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/range/RangeSetExtensions.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/range/RangeSetExtensions.kt @@ -5,8 +5,7 @@ import io.rtron.std.powerSet /** * Unions a set of [RangeSet] to a single [RangeSet]. */ -fun > Set>.unionRangeSets(): RangeSet = - reduce { acc, element -> acc.union(element) } +fun > Set>.unionRangeSets(): RangeSet = reduce { acc, element -> acc.union(element) } /** * Returns the intersecting [RangeSet]. @@ -14,8 +13,7 @@ fun > Set>.unionRangeSets(): RangeSet = * @receiver provided set of [RangeSet] for which the intersecting [RangeSet] is evaluated * @return minimum intersecting range set */ -fun > Set>.intersectionRangeSets(): RangeSet = - reduce { acc, element -> acc.intersection(element) } +fun > Set>.intersectionRangeSets(): RangeSet = reduce { acc, element -> acc.intersection(element) } /** * Returns true, if set of [RangeSet] contains intersecting [RangeSet] pairs. diff --git a/rtron-math/src/main/kotlin/io/rtron/math/std/DoubleArrayExtensions.kt b/rtron-math/src/main/kotlin/io/rtron/math/std/DoubleArrayExtensions.kt index dd7caa0c..d5301b3e 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/std/DoubleArrayExtensions.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/std/DoubleArrayExtensions.kt @@ -35,7 +35,9 @@ fun DoubleArray.reshapeByColumnDimension(columnDimension: Int): Array { - require(this.size.rem(rowDimension) == 0) { "Not fitting dimensions: Trying to reshape a DoubleArray of size ${this.size}) to rowDimension of $rowDimension." } + require(this.size.rem(rowDimension) == 0) { + "Not fitting dimensions: Trying to reshape a DoubleArray of size ${this.size}) to rowDimension of $rowDimension." + } PI return this.reshapeByColumnDimension(this.size / rowDimension) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/std/DoubleMathExtensions.kt b/rtron-math/src/main/kotlin/io/rtron/math/std/DoubleMathExtensions.kt index 8fd86f93..e2d85631 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/std/DoubleMathExtensions.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/std/DoubleMathExtensions.kt @@ -28,7 +28,11 @@ import com.google.common.math.DoubleMath as GDoubleMath * @param tolerance allowed tolerance * @return true, if abs(a - b) <= tolerance */ -fun fuzzyEquals(a: Double, b: Double, tolerance: Double): Boolean = +fun fuzzyEquals( + a: Double, + b: Double, + tolerance: Double, +): Boolean = if (tolerance == 0.0) { a == b } else { @@ -43,8 +47,11 @@ fun fuzzyEquals(a: Double, b: Double, tolerance: Double): Boolean = * @param tolerance allowed tolerance * @return 0 for a fuzzyEquals b; -1 for a < b; 1 for a > b */ -fun fuzzyCompare(a: Double, b: Double, tolerance: Double) = - GDoubleMath.fuzzyCompare(a, b, tolerance) +fun fuzzyCompare( + a: Double, + b: Double, + tolerance: Double, +) = GDoubleMath.fuzzyCompare(a, b, tolerance) /** * Returns true, if [a] <= [b] with a [tolerance]. @@ -54,8 +61,11 @@ fun fuzzyCompare(a: Double, b: Double, tolerance: Double) = * @param tolerance allowed tolerance * @return true, if [a] <= [b] with a [tolerance]; false otherwise */ -fun fuzzyLessThanOrEquals(a: Double, b: Double, tolerance: Double) = - a <= (b + abs(tolerance)) || a == b || a.isNaN() && b.isNaN() +fun fuzzyLessThanOrEquals( + a: Double, + b: Double, + tolerance: Double, +) = a <= (b + abs(tolerance)) || a == b || a.isNaN() && b.isNaN() /** * Returns true, if [a] >= [b] with a [tolerance]. @@ -65,8 +75,11 @@ fun fuzzyLessThanOrEquals(a: Double, b: Double, tolerance: Double) = * @param tolerance allowed tolerance * @return true, if [a] >= [b] with a [tolerance]; false otherwise */ -fun fuzzyMoreThanOrEquals(a: Double, b: Double, tolerance: Double) = - a >= (b + abs(tolerance)) || a == b || a.isNaN() && b.isNaN() +fun fuzzyMoreThanOrEquals( + a: Double, + b: Double, + tolerance: Double, +) = a >= (b + abs(tolerance)) || a == b || a.isNaN() && b.isNaN() /** * Normalizes an [angle] around the [center]. @@ -75,4 +88,7 @@ fun fuzzyMoreThanOrEquals(a: Double, b: Double, tolerance: Double) = * @param center center of the desired normalization interval * @return normalized angle */ -fun normalizeAngle(angle: Double, center: Double = PI) = MathUtils.normalizeAngle(angle, center) +fun normalizeAngle( + angle: Double, + center: Double = PI, +) = MathUtils.normalizeAngle(angle, center) diff --git a/rtron-math/src/main/kotlin/io/rtron/math/std/PositiveDouble.kt b/rtron-math/src/main/kotlin/io/rtron/math/std/PositiveDouble.kt index a39497b3..4cceed41 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/std/PositiveDouble.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/std/PositiveDouble.kt @@ -20,7 +20,6 @@ package io.rtron.math.std * Double number with value greater equals zero. */ class PositiveDouble(val value: Double) { - // Properties and Initializers init { require(0 <= value) { "Value must be positive (greater equals zero)." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/std/StrictlyPositiveDouble.kt b/rtron-math/src/main/kotlin/io/rtron/math/std/StrictlyPositiveDouble.kt index dcb0c32d..02241c5d 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/std/StrictlyPositiveDouble.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/std/StrictlyPositiveDouble.kt @@ -20,7 +20,6 @@ package io.rtron.math.std * Double number with value greater zero. */ class StrictlyPositiveDouble(val value: Double) { - // Properties and Initializers init { require(0 < value) { "Value must be positive (greater zero)." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/std/ZeroOneDouble.kt b/rtron-math/src/main/kotlin/io/rtron/math/std/ZeroOneDouble.kt index 6d4d83af..feb2d98d 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/std/ZeroOneDouble.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/std/ZeroOneDouble.kt @@ -20,7 +20,6 @@ package io.rtron.math.std * Double number with values between zero and one inclusive. */ class ZeroOneDouble(val value: Double) { - // Properties and Initializers init { require(0 <= value) { "Value must be greater equals zero." } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/transform/Affine2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/transform/Affine2D.kt index 4606ccac..980df064 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/transform/Affine2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/transform/Affine2D.kt @@ -27,6 +27,7 @@ import org.joml.Matrix3dc as JOMLMatrix3dc import org.joml.Vector3d as JOMLVector3d fun JOMLVector3d.toVector2D() = Vector2D(this.x, this.y) + fun JOMLVector3d.toRealVector() = RealVector.of(this.x, this.y, this.z) fun JOMLMatrix3dc.isAffine() = this.m02() == 0.0 && this.m12() == 0.0 && this.m22() == 1.0 @@ -37,9 +38,8 @@ fun JOMLMatrix3dc.isAffine() = this.m02() == 0.0 && this.m12() == 0.0 && this.m2 * @param matrix internal matrix of adapting library */ class Affine2D( - private val matrix: JOMLMatrix3dc + private val matrix: JOMLMatrix3dc, ) : AbstractAffine() { - // Properties and Initializers init { require(matrix.isAffine()) { "Matrix must be affine." } @@ -50,16 +50,16 @@ class Affine2D( private val matrixInverse by lazy { JOMLMatrix3d(matrix).invert() } // Methods: Transformation - fun transform(point: Vector2D) = - matrix.transform(point.x, point.y, 1.0, JOMLVector3d()).toVector2D() + fun transform(point: Vector2D) = matrix.transform(point.x, point.y, 1.0, JOMLVector3d()).toVector2D() - fun inverseTransform(point: Vector2D) = - matrixInverse.transform(point.x, point.y, 1.0, JOMLVector3d()).toVector2D() + fun inverseTransform(point: Vector2D) = matrixInverse.transform(point.x, point.y, 1.0, JOMLVector3d()).toVector2D() fun transform(rotation: Rotation2D) = rotation + extractRotation() + fun inverseTransform(rotation: Rotation2D) = rotation - extractRotation() fun transform(pose: Pose2D) = Pose2D(transform(pose.point), transform(pose.rotation)) + fun inverseTransform(pose: Pose2D) = Pose2D(inverseTransform(pose.point), inverseTransform(pose.rotation)) // Methods: Extraction @@ -117,7 +117,9 @@ class Affine2D( // Conversions fun toMatrix3JOML() = JOMLMatrix3d(this.matrix) + fun toMatrix() = RealMatrix(toDoubleArray(), 3) + fun toDoubleArray(): DoubleArray = this.matrixTransposed.get(DoubleArray(9)) companion object { @@ -171,11 +173,15 @@ class Affine2D( /** * Creates an [Affine2D] transformation matrix from first applying a [translation] and then a [rotation]. */ - fun of(translation: Vector2D, rotation: Rotation2D): Affine2D { - val matrix = JOMLMatrix3d().apply { - m20 = translation.x - m21 = translation.y - }.rotateZ(rotation.angle) + fun of( + translation: Vector2D, + rotation: Rotation2D, + ): Affine2D { + val matrix = + JOMLMatrix3d().apply { + m20 = translation.x + m21 = translation.y + }.rotateZ(rotation.angle) return Affine2D(matrix) } @@ -183,10 +189,11 @@ class Affine2D( * Creates an [Affine2D] transformation matrix from a [pose]. */ fun of(pose: Pose2D): Affine2D { - val matrix = JOMLMatrix3d().apply { - m20 = pose.point.x - m21 = pose.point.y - }.rotateZ(pose.rotation.angle) + val matrix = + JOMLMatrix3d().apply { + m20 = pose.point.x + m21 = pose.point.y + }.rotateZ(pose.rotation.angle) return Affine2D(matrix) } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/transform/Affine3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/transform/Affine3D.kt index 3517332b..9d32f659 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/transform/Affine3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/transform/Affine3D.kt @@ -40,9 +40,8 @@ fun JOMLMatrix4dc.toRealMatrix(): RealMatrix { * @param matrix internal matrix of adapting library */ class Affine3D( - private val matrix: JOMLMatrix4dc + private val matrix: JOMLMatrix4dc, ) : AbstractAffine() { - // Properties and Initializers init { require(matrix.isAffine) { "Matrix must be affine." } @@ -54,6 +53,7 @@ class Affine3D( // Methods: Transformation fun transform(point: Vector3D) = matrix.transformPosition(point.toVector3DJOML()).toVector3D() + fun inverseTransform(point: Vector3D) = matrixInverse.transformPosition(point.toVector3DJOML()).toVector3D() @JvmName("transformOfListVector3D") @@ -65,10 +65,9 @@ class Affine3D( @JvmName("inverseTransformOfListVector3D") fun inverseTransform(points: List) = points.map { inverseTransform(it) } - fun transform(polygon: Polygon3D) = - Polygon3D(polygon.vertices.map { transform(it) }, polygon.tolerance) - fun inverseTransform(polygon: Polygon3D) = - Polygon3D(polygon.vertices.map { inverseTransform(it) }, polygon.tolerance) + fun transform(polygon: Polygon3D) = Polygon3D(polygon.vertices.map { transform(it) }, polygon.tolerance) + + fun inverseTransform(polygon: Polygon3D) = Polygon3D(polygon.vertices.map { inverseTransform(it) }, polygon.tolerance) @JvmName("transformOfListPolygon3D") fun transform(polygons: List) = polygons.map { transform(it) } @@ -143,8 +142,11 @@ class Affine3D( // Conversions fun toMatrix4JOML() = JOMLMatrix4d(this.matrix) + fun toRealMatrix() = this.matrixTransposed.toRealMatrix() + fun toDoubleArray(): DoubleArray = this.matrixTransposed.get(DoubleArray(16)) + fun toDoubleList(): List = toDoubleArray().toList() override fun toString(): String { @@ -185,10 +187,11 @@ class Affine3D( * Creates an [Affine3D] transformation matrix from a [rotation]. */ fun of(rotation: Rotation3D): Affine3D { - val matrix = JOMLMatrix4d() - .rotateZ(rotation.heading) - .rotateY(rotation.pitch) - .rotateX(rotation.roll) + val matrix = + JOMLMatrix4d() + .rotateZ(rotation.heading) + .rotateY(rotation.pitch) + .rotateX(rotation.roll) return Affine3D(matrix) } @@ -223,13 +226,18 @@ class Affine3D( * @param basisY y-axis of new basis * @param basisZ z-axis of new basis */ - fun of(basisX: Vector3D, basisY: Vector3D, basisZ: Vector3D): Affine3D { - val matrix = JOMLMatrix4d().set( - basisX.toVector4DJOML(), - basisY.toVector4DJOML(), - basisZ.toVector4DJOML(), - Vector3D.ZERO.toVector4DJOML() - )!! + fun of( + basisX: Vector3D, + basisY: Vector3D, + basisZ: Vector3D, + ): Affine3D { + val matrix = + JOMLMatrix4d().set( + basisX.toVector4DJOML(), + basisY.toVector4DJOML(), + basisZ.toVector4DJOML(), + Vector3D.ZERO.toVector4DJOML(), + )!! return Affine3D(matrix.invertAffine()) } } diff --git a/rtron-math/src/main/kotlin/io/rtron/math/transform/AffineSequence2D.kt b/rtron-math/src/main/kotlin/io/rtron/math/transform/AffineSequence2D.kt index a2f03732..c54f8a2f 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/transform/AffineSequence2D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/transform/AffineSequence2D.kt @@ -22,7 +22,7 @@ package io.rtron.math.transform * @param affineList list of consecutively applied [Affine2D] transformation matrices */ data class AffineSequence2D( - val affineList: List + val affineList: List, ) { // Properties and Initializers @@ -34,6 +34,7 @@ data class AffineSequence2D( // Methods fun isEmpty() = affineList.isEmpty() + fun isNotEmpty() = affineList.isNotEmpty() /** diff --git a/rtron-math/src/main/kotlin/io/rtron/math/transform/AffineSequence3D.kt b/rtron-math/src/main/kotlin/io/rtron/math/transform/AffineSequence3D.kt index d62fefbb..c8ebc5de 100644 --- a/rtron-math/src/main/kotlin/io/rtron/math/transform/AffineSequence3D.kt +++ b/rtron-math/src/main/kotlin/io/rtron/math/transform/AffineSequence3D.kt @@ -22,7 +22,7 @@ package io.rtron.math.transform * @param affineList list of consecutively applied [AffineSequence3D] transformation matrices */ data class AffineSequence3D( - val affineList: List + val affineList: List, ) { // Properties and Initializers @@ -31,6 +31,7 @@ data class AffineSequence3D( // Methods fun isEmpty() = affineList.isEmpty() + fun isNotEmpty() = affineList.isNotEmpty() /** diff --git a/rtron-math/src/test/kotlin/io/rtron/math/SpiralSegment2DWriterTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/SpiralSegment2DWriterTest.kt index 01f42e3e..64d3c1ae 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/SpiralSegment2DWriterTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/SpiralSegment2DWriterTest.kt @@ -30,7 +30,6 @@ import io.rtron.math.transform.AffineSequence2D import kotlin.io.path.Path object SpiralSegment2DWriterTest { - fun writeSpiralSegment2DToCsvFile() { val path = Path("out/test_files/SpiralSegment2D/SpiralSegment2D-line.csv") val header = listOf("curvePosition", "x", "y") diff --git a/rtron-math/src/test/kotlin/io/rtron/math/analysis/FresnelTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/analysis/FresnelTest.kt index f6fff552..1b33bdfc 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/analysis/FresnelTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/analysis/FresnelTest.kt @@ -42,7 +42,10 @@ class FresnelTest : FunSpec({ } val fileReader = FileReader(filePath.toFile()) - val records: Iterable = CSVFormat.Builder.create().setDelimiter(",").setHeader("l", "x", "y").setSkipHeaderRecord(true).build().parse(fileReader) + val records: Iterable = + CSVFormat.Builder.create().setDelimiter( + ",", + ).setHeader("l", "x", "y").setSkipHeaderRecord(true).build().parse(fileReader) for (record in records) { val l: Double = record.get("l").toDouble() val x: Double = record.get("x").toDouble() diff --git a/rtron-math/src/test/kotlin/io/rtron/math/analysis/function/LinearFunctionTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/analysis/function/LinearFunctionTest.kt index 39cc99dd..01563315 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/analysis/function/LinearFunctionTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/analysis/function/LinearFunctionTest.kt @@ -49,11 +49,12 @@ class LinearFunctionTest : FunSpec({ context("TestFactoryMethodOfInclusivePoints") { test("basic creation of linear function with two points") { - val expectedLinearFunction = LinearFunction( - -3.0 / 2.0, - 13.0 / 2.0, - Range.closed(3.0, 7.0) - ) + val expectedLinearFunction = + LinearFunction( + -3.0 / 2.0, + 13.0 / 2.0, + Range.closed(3.0, 7.0), + ) val actualLinearFunction = LinearFunction.ofInclusivePoints(3.0, 2.0, 7.0, -4.0) @@ -73,11 +74,12 @@ class LinearFunctionTest : FunSpec({ context("TestFactoryMethodOfInclusiveYValueAndUnitSlope") { test("with positive unit slope") { - val expectedLinearFunction = LinearFunction( - 1.0, - 2.0, - Range.closed(0.0, 2.0) - ) + val expectedLinearFunction = + LinearFunction( + 1.0, + 2.0, + Range.closed(0.0, 2.0), + ) val actualLinearFunction = LinearFunction.ofInclusiveYValuesAndUnitSlope(2.0, 4.0) @@ -85,11 +87,12 @@ class LinearFunctionTest : FunSpec({ } test("with negative unit slope") { - val expectedLinearFunction = LinearFunction( - -1.0, - 17.0, - Range.closed(0.0, 3.0) - ) + val expectedLinearFunction = + LinearFunction( + -1.0, + 17.0, + Range.closed(0.0, 3.0), + ) val actualLinearFunction = LinearFunction.ofInclusiveYValuesAndUnitSlope(17.0, 14.0) diff --git a/rtron-math/src/test/kotlin/io/rtron/math/analysis/function/univariate/combination/ConcatenatedFunctionTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/analysis/function/univariate/combination/ConcatenatedFunctionTest.kt index 87d3c649..4995a50a 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/analysis/function/univariate/combination/ConcatenatedFunctionTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/analysis/function/univariate/combination/ConcatenatedFunctionTest.kt @@ -87,10 +87,11 @@ class ConcatenatedFunctionTest : FunSpec({ test("concatenated function with absolute start at 0") { val starts = nonEmptyListOf(0.0, 5.0) - val coefficients = nonEmptyListOf( - doubleArrayOf(2.0, 3.0, 4.0, 1.0), - doubleArrayOf(1.0, 2.0, 3.0, 4.0) - ) + val coefficients = + nonEmptyListOf( + doubleArrayOf(2.0, 3.0, 4.0, 1.0), + doubleArrayOf(1.0, 2.0, 3.0, 4.0), + ) val concatenatedFunction = ConcatenatedFunction.ofPolynomialFunctions(starts, coefficients) @@ -111,10 +112,11 @@ class ConcatenatedFunctionTest : FunSpec({ test("concatenated function with absolute start at -2") { val starts = nonEmptyListOf(-2.0, 3.0) - val coefficients = nonEmptyListOf( - doubleArrayOf(2.0, 3.0, 4.0, 1.0), - doubleArrayOf(1.0, 2.0, 3.0, 4.0) - ) + val coefficients = + nonEmptyListOf( + doubleArrayOf(2.0, 3.0, 4.0, 1.0), + doubleArrayOf(1.0, 2.0, 3.0, 4.0), + ) val concatenatedFunction = ConcatenatedFunction.ofPolynomialFunctions(starts, coefficients) @@ -135,10 +137,11 @@ class ConcatenatedFunctionTest : FunSpec({ test("concatenated function with absolute start at 2") { val starts = nonEmptyListOf(2.0, 7.0) - val coefficients = nonEmptyListOf( - doubleArrayOf(2.0, 3.0, 4.0, 1.0), - doubleArrayOf(1.0, 2.0, 3.0, 4.0) - ) + val coefficients = + nonEmptyListOf( + doubleArrayOf(2.0, 3.0, 4.0, 1.0), + doubleArrayOf(1.0, 2.0, 3.0, 4.0), + ) val concatenatedFunction = ConcatenatedFunction.ofPolynomialFunctions(starts, coefficients) diff --git a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Polygon3DTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Polygon3DTest.kt index a0e6d979..a8f5e6c4 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Polygon3DTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/threed/surface/Polygon3DTest.kt @@ -84,15 +84,16 @@ class Polygon3DTest : FunSpec({ } test("test planar quadrilateral polygon") { - val planarQuadrilateral = Polygon3D( - nonEmptyListOf( - Vector3D.ZERO, - Vector3D.X_AXIS, - Vector3D(1.0, 0.0, 1.0), - Vector3D.Z_AXIS - ), - 0.0 - ) + val planarQuadrilateral = + Polygon3D( + nonEmptyListOf( + Vector3D.ZERO, + Vector3D.X_AXIS, + Vector3D(1.0, 0.0, 1.0), + Vector3D.Z_AXIS, + ), + 0.0, + ) val expectedResult = Vector3D(0.0, -1.0, 0.0) val actualNormal = planarQuadrilateral.getNormal().shouldBeRight() diff --git a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CompositeCurve2DTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CompositeCurve2DTest.kt index ba4703e6..9d73c5ff 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CompositeCurve2DTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/CompositeCurve2DTest.kt @@ -46,40 +46,43 @@ class CompositeCurve2DTest : FunSpec({ val rotation2 = Rotation2D(7.8539816339001800e-01) val affine2 = Affine2D.of(point2, rotation2) val affineSequence2 = AffineSequence2D.of(affine2) - val curveMember2 = SpiralSegment2D( - LinearFunction.ofSpiralCurvature( - -0.0000000000000000e+00, - -1.2698412698412698e-01, - 3.1746031746031744e+00 - ), - tolerance, - affineSequence2 - ) + val curveMember2 = + SpiralSegment2D( + LinearFunction.ofSpiralCurvature( + -0.0000000000000000e+00, + -1.2698412698412698e-01, + 3.1746031746031744e+00, + ), + tolerance, + affineSequence2, + ) val point3 = Vector2D(-4.3409250448547327e+00, -4.6416930098216129e+00) val rotation3 = Rotation2D(5.8383605706600694e-01) val affine3 = Affine2D.of(point3, rotation3) val affineSequence3 = AffineSequence2D.of(affine3) - val curveMember3 = Arc2D( - -1.2698412698412698e-01, - 9.1954178989066371e+00, - tolerance, - affineSequence3 - ) + val curveMember3 = + Arc2D( + -1.2698412698412698e-01, + 9.1954178989066371e+00, + tolerance, + affineSequence3, + ) val point4 = Vector2D(4.3409256447834164e+00, -4.6416930099218154e+00) val rotation4 = Rotation2D(-5.8383605708086783e-01) val affine4 = Affine2D.of(point4, rotation4) val affineSequence4 = AffineSequence2D.of(affine4) - val curveMember4 = SpiralSegment2D( - LinearFunction.ofSpiralCurvature( - -1.2698412698412698e-01, - -0.0000000000000000e+00, - 3.1746031746031744e+00 - ), - tolerance, - affineSequence4 - ) + val curveMember4 = + SpiralSegment2D( + LinearFunction.ofSpiralCurvature( + -1.2698412698412698e-01, + -0.0000000000000000e+00, + 3.1746031746031744e+00, + ), + tolerance, + affineSequence4, + ) val point5 = Vector2D(6.7269902521255664e+00, -6.7269896521471884e+00) val rotation5 = Rotation2D(-7.8539816341104807e-01) diff --git a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Spiral2DTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Spiral2DTest.kt index 76bdf387..401da528 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Spiral2DTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/Spiral2DTest.kt @@ -90,7 +90,10 @@ class Spiral2DTest : FunSpec({ } val fileReader = FileReader(filePath.toFile()) - val records: Iterable = CSVFormat.Builder.create().setDelimiter(",").setHeader("cDot", "s", "x", "y", "t").setSkipHeaderRecord(true).build().parse(fileReader) + val records: Iterable = + CSVFormat.Builder.create().setDelimiter( + ",", + ).setHeader("cDot", "s", "x", "y", "t").setSkipHeaderRecord(true).build().parse(fileReader) for (record in records) { val cDot: Double = record.get("cDot").toDouble() val s: Double = record.get("s").toDouble() diff --git a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SpiralSegment2DTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SpiralSegment2DTest.kt index 77d2bc9a..5e7695c8 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SpiralSegment2DTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/curve/SpiralSegment2DTest.kt @@ -57,7 +57,7 @@ class SpiralSegment2DTest : FunSpec({ actualPose.point.y.shouldBe(9.8074617455403796e+00 plusOrMinus DBL_EPSILON_11) actualPose.rotation.angle.shouldBe( 5.3186972285460032e-01 - plusOrMinus DBL_EPSILON_4 + plusOrMinus DBL_EPSILON_4, ) } @@ -78,7 +78,12 @@ class SpiralSegment2DTest : FunSpec({ test("first spiral of the example dataset CrossingComplex8Course") { val pose = Pose2D(Vector2D(4.5002666984590900e+02, 5.2071081556728734e+02), Rotation2D(4.7173401120976974e+00)) val affine = Affine2D.of(pose) - val curvatureFunction = LinearFunction.ofSpiralCurvature(-0.0000000000000000e+00, -1.0126582278481013e-01, 4.9620253164556960e+00) + val curvatureFunction = + LinearFunction.ofSpiralCurvature( + -0.0000000000000000e+00, + -1.0126582278481013e-01, + 4.9620253164556960e+00, + ) val curve = SpiralSegment2D(curvatureFunction, DBL_EPSILON_2, AffineSequence2D.of(affine)) val curveRelativePoint = CurveRelativeVector1D(1.0507568316454000e+01 - 5.5455429999983039e+00) @@ -92,7 +97,12 @@ class SpiralSegment2DTest : FunSpec({ test("second spiral of the example dataset CrossingComplex8Course") { val pose = Pose2D(Vector2D(4.4256271579386976e+02, 5.0863294215453800e+02), Rotation2D(3.3977855734777722e+00)) val affine = Affine2D.of(pose) - val curvatureFunction = LinearFunction.ofSpiralCurvature(-1.0126582278481013e-01, -0.0000000000000000e+00, 4.9620253164556960e+00) + val curvatureFunction = + LinearFunction.ofSpiralCurvature( + -1.0126582278481013e-01, + -0.0000000000000000e+00, + 4.9620253164556960e+00, + ) val curve = SpiralSegment2D(curvatureFunction, DBL_EPSILON_2, AffineSequence2D.of(affine)) val curveRelativePoint = CurveRelativeVector1D(2.6019182043553606e+01 - 2.1057156727097912e+01) @@ -116,11 +126,22 @@ class SpiralSegment2DTest : FunSpec({ } val fileReader = FileReader(filePath.toFile()) - val records: Iterable = CSVFormat.Builder.create().setDelimiter(",").setHeader("s0", "x0", "y0", "hdg0", "curv0", "curv1", "length", "s1", "x1", "y1", "hdg1").setSkipHeaderRecord(true).build().parse(fileReader) + val records: Iterable = + CSVFormat.Builder.create().setDelimiter( + ",", + ).setHeader("s0", "x0", "y0", "hdg0", "curv0", "curv1", "length", "s1", "x1", "y1", "hdg1").setSkipHeaderRecord( + true, + ).build().parse(fileReader) for (record in records) { - val pose = Pose2D(Vector2D(record.get("x0").toDouble(), record.get("y0").toDouble()), Rotation2D(record.get("hdg0").toDouble())) + val pose = + Pose2D(Vector2D(record.get("x0").toDouble(), record.get("y0").toDouble()), Rotation2D(record.get("hdg0").toDouble())) val affine = Affine2D.of(pose) - val curvatureFunction = LinearFunction.ofSpiralCurvature(record.get("curv0").toDouble(), record.get("curv1").toDouble(), record.get("length").toDouble()) + val curvatureFunction = + LinearFunction.ofSpiralCurvature( + record.get("curv0").toDouble(), + record.get("curv1").toDouble(), + record.get("length").toDouble(), + ) val curve = SpiralSegment2D(curvatureFunction, DBL_EPSILON_5, AffineSequence2D.of(affine)) val curveRelativePoint = CurveRelativeVector1D(record.get("s1").toDouble() - record.get("s0").toDouble()) diff --git a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/surface/Polygon2DTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/surface/Polygon2DTest.kt index 9613335d..9254c3ea 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/surface/Polygon2DTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/geometry/euclidean/twod/surface/Polygon2DTest.kt @@ -36,11 +36,12 @@ class Polygon2DTest : FunSpec({ } test("basic triangle does not contain point") { - val vertices: NonEmptyList = listOf( - Vector2D.ZERO, - Vector2D.X_AXIS, - Vector2D.Y_AXIS - ).toNonEmptyListOrNull()!! + val vertices: NonEmptyList = + listOf( + Vector2D.ZERO, + Vector2D.X_AXIS, + Vector2D.Y_AXIS, + ).toNonEmptyListOrNull()!! val polygon = Polygon2D(vertices, 0.0) val actualReturn = polygon.contains(Vector2D(1.25, 1.25)) @@ -49,13 +50,14 @@ class Polygon2DTest : FunSpec({ } test("concave polygon does contain point") { - val vertices: NonEmptyList = listOf( - Vector2D.ZERO, - Vector2D(1.0, 1.0), - Vector2D(2.0, 0.0), - Vector2D(2.0, 3.0), - Vector2D(0.0, 3.0) - ).toNonEmptyListOrNull()!! + val vertices: NonEmptyList = + listOf( + Vector2D.ZERO, + Vector2D(1.0, 1.0), + Vector2D(2.0, 0.0), + Vector2D(2.0, 3.0), + Vector2D(0.0, 3.0), + ).toNonEmptyListOrNull()!! val polygon = Polygon2D(vertices, 0.0) val actualReturn = polygon.contains(Vector2D(1.0, 1.1)) diff --git a/rtron-math/src/test/kotlin/io/rtron/math/linear/RealMatrixTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/linear/RealMatrixTest.kt index afe9b839..8420e038 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/linear/RealMatrixTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/linear/RealMatrixTest.kt @@ -21,14 +21,14 @@ import io.kotest.matchers.shouldBe import io.rtron.math.std.DBL_EPSILON class RealMatrixTest { - fun normalize() { val matrixValues = arrayOf(doubleArrayOf(1.0, 0.0), doubleArrayOf(0.0, 4.0)) val matrix = RealMatrix(matrixValues) val toleratedOffset = DBL_EPSILON - val actualMatrix = matrix - .normalize(matrix.rowDimension - 1, matrix.columnDimension - 1) + val actualMatrix = + matrix + .normalize(matrix.rowDimension - 1, matrix.columnDimension - 1) actualMatrix[0][0].shouldBe(0.25 plusOrMinus toleratedOffset) actualMatrix[0][1].shouldBe(0.0 plusOrMinus toleratedOffset) diff --git a/rtron-math/src/test/kotlin/io/rtron/math/processing/Plane3DUtilTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/processing/Plane3DUtilTest.kt index eac57aa1..a8d2ac94 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/processing/Plane3DUtilTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/processing/Plane3DUtilTest.kt @@ -72,8 +72,9 @@ class Plane3DUtilTest : FunSpec({ val expectedNormal = Vector3D(2.0, 3.0, 1.0).normalized() val expectedPlane = Plane3D(expectedCentroid, expectedNormal, 0.0) - val actualBestFittingPlane = listOf(pointA, pointB, pointC, pointD) - .calculateBestFittingPlane(DBL_EPSILON_2) + val actualBestFittingPlane = + listOf(pointA, pointB, pointC, pointD) + .calculateBestFittingPlane(DBL_EPSILON_2) actualBestFittingPlane.normal.toDoubleArray().zip(expectedPlane.normal.toDoubleArray()).forEach { it.first.shouldBe(it.second plusOrMinus DBL_EPSILON_2) @@ -90,8 +91,9 @@ class Plane3DUtilTest : FunSpec({ val expectedCentroid = Vector3D(1.0, 1.0, 1.0) val expectedNormal = -Vector3D.X_AXIS val expectedPlane = Plane3D(expectedCentroid, expectedNormal, DBL_EPSILON_1) - val actualBestFittingPlane = listOf(pointA, pointB, pointC, pointD, pointE) - .calculateBestFittingPlane(DBL_EPSILON_1) + val actualBestFittingPlane = + listOf(pointA, pointB, pointC, pointD, pointE) + .calculateBestFittingPlane(DBL_EPSILON_1) actualBestFittingPlane shouldBe expectedPlane } diff --git a/rtron-math/src/test/kotlin/io/rtron/math/range/DoubleRangeExtensionsTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/range/DoubleRangeExtensionsTest.kt index d70d42d7..9928fb57 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/range/DoubleRangeExtensionsTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/range/DoubleRangeExtensionsTest.kt @@ -22,71 +22,81 @@ import io.kotest.matchers.shouldBe class DoubleRangeExtensionsTest : FunSpec({ context("ArrangeDoubleRange") { test("correct value spacing") { - val actualValues = Range.closed(0.0, 1.25) - .arrange(0.25, false, 0.0) + val actualValues = + Range.closed(0.0, 1.25) + .arrange(0.25, false, 0.0) doubleArrayOf(0.0, 0.25, 0.5, 0.75, 1.0, 1.25) shouldBe actualValues } test("non zero start") { - val actualValues = Range.closed(1.0, 1.25) - .arrange(0.25, false, 0.0) + val actualValues = + Range.closed(1.0, 1.25) + .arrange(0.25, false, 0.0) doubleArrayOf(1.0, 1.25) shouldBe actualValues } test("offset start") { - val actualValues = Range.closed(0.51, 1.25) - .arrange(0.25, false, 0.0) + val actualValues = + Range.closed(0.51, 1.25) + .arrange(0.25, false, 0.0) doubleArrayOf(0.51, 0.76, 1.01) shouldBe actualValues } test("with epsilon offset and endpoint") { - val actualValues = Range.closed(0.51, 1.25) - .arrange(0.25, true, 0.0) + val actualValues = + Range.closed(0.51, 1.25) + .arrange(0.25, true, 0.0) doubleArrayOf(0.51, 0.76, 1.01, 1.25) shouldBe actualValues } test("with endpoint") { - val actualValues = Range.closed(1.0, 1.25) - .arrange(0.25, true, 0.0) + val actualValues = + Range.closed(1.0, 1.25) + .arrange(0.25, true, 0.0) doubleArrayOf(1.0, 1.25) shouldBe actualValues } test("list with length zero") { - val actualValues = Range.closed(1.0, 1.0) - .arrange(0.25, false, 0.0) + val actualValues = + Range.closed(1.0, 1.0) + .arrange(0.25, false, 0.0) doubleArrayOf(1.0) shouldBe actualValues } test("list with length zero and endPoint") { - val actualValues = Range.closed(1.0, 1.0) - .arrange(0.25, true, 0.0) + val actualValues = + Range.closed(1.0, 1.0) + .arrange(0.25, true, 0.0) doubleArrayOf(1.0) shouldBe actualValues } test("smaller range than step size should nevertheless contain the start") { - val actualValues = Range.closed(1.0, 2.0) - .arrange(5.0, false, 0.0) + val actualValues = + Range.closed(1.0, 2.0) + .arrange(5.0, false, 0.0) doubleArrayOf(1.0) shouldBe actualValues } test("smaller range than step size should nevertheless contain the start and end") { - val actualValues = Range.closed(1.0, 2.0) - .arrange(5.0, true, 0.0) + val actualValues = + Range.closed(1.0, 2.0) + .arrange(5.0, true, 0.0) doubleArrayOf(1.0, 2.0) shouldBe actualValues } test("range with length under epsilon should nevertheless contain the start and end") { - val actualValues = Range.closed(0.0, 1.0E-8) - .arrange(0.5, true, 0.0) + val actualValues = + Range.closed(0.0, 1.0E-8) + .arrange(0.5, true, 0.0) doubleArrayOf(0.0, 1.0E-8) shouldBe actualValues } diff --git a/rtron-math/src/test/kotlin/io/rtron/math/std/DoubleArrayExtensionTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/std/DoubleArrayExtensionTest.kt index fcf404a7..96dd140a 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/std/DoubleArrayExtensionTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/std/DoubleArrayExtensionTest.kt @@ -25,18 +25,20 @@ class DoubleArrayExtensionTest : FunSpec({ context("TestReshapeByColumnDimension") { test("test reshape of square matrix") { - val expectedMatrix = arrayOf( - doubleArrayOf(1.0, 0.0, 0.0, 1.0), - doubleArrayOf(0.0, 1.0, 0.0, 2.0), - doubleArrayOf(0.0, 0.0, 1.0, 3.0), - doubleArrayOf(0.0, 0.0, 0.0, 1.0) - ) - val matrix = doubleArrayOf( - 1.0, 0.0, 0.0, 1.0, - 0.0, 1.0, 0.0, 2.0, - 0.0, 0.0, 1.0, 3.0, - 0.0, 0.0, 0.0, 1.0 - ) + val expectedMatrix = + arrayOf( + doubleArrayOf(1.0, 0.0, 0.0, 1.0), + doubleArrayOf(0.0, 1.0, 0.0, 2.0), + doubleArrayOf(0.0, 0.0, 1.0, 3.0), + doubleArrayOf(0.0, 0.0, 0.0, 1.0), + ) + val matrix = + doubleArrayOf( + 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 2.0, + 0.0, 0.0, 1.0, 3.0, + 0.0, 0.0, 0.0, 1.0, + ) val actualReshapedMatrix = matrix.reshapeByColumnDimension(4) @@ -53,18 +55,20 @@ class DoubleArrayExtensionTest : FunSpec({ } test("test reshape of square matrix") { - val expectedMatrix = arrayOf( - doubleArrayOf(0.0, 0.0, 1.0), - doubleArrayOf(1.0, 0.0, 2.0), - doubleArrayOf(0.0, 1.0, 3.0), - doubleArrayOf(0.0, 0.0, 1.0) - ) - val matrix = doubleArrayOf( - 0.0, 0.0, 1.0, - 1.0, 0.0, 2.0, - 0.0, 1.0, 3.0, - 0.0, 0.0, 1.0 - ) + val expectedMatrix = + arrayOf( + doubleArrayOf(0.0, 0.0, 1.0), + doubleArrayOf(1.0, 0.0, 2.0), + doubleArrayOf(0.0, 1.0, 3.0), + doubleArrayOf(0.0, 0.0, 1.0), + ) + val matrix = + doubleArrayOf( + 0.0, 0.0, 1.0, + 1.0, 0.0, 2.0, + 0.0, 1.0, 3.0, + 0.0, 0.0, 1.0, + ) val actualReshapedMatrix = matrix.reshapeByRowDimension(4) diff --git a/rtron-math/src/test/kotlin/io/rtron/math/transform/Affine2DTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/transform/Affine2DTest.kt index ce591a72..9179dd60 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/transform/Affine2DTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/transform/Affine2DTest.kt @@ -58,11 +58,12 @@ class Affine2DTest : FunSpec({ val affineA = Affine2D.of(translation) val scaling = RealVector.of(2.0, 3.0) val affineB = Affine2D.of(scaling) - val expectedValues = doubleArrayOf( - 2.0, 0.0, 1.0, - 0.0, 3.0, 2.0, - 0.0, 0.0, 1.0 - ) + val expectedValues = + doubleArrayOf( + 2.0, 0.0, 1.0, + 0.0, 3.0, 2.0, + 0.0, 0.0, 1.0, + ) val expectedMatrix = RealMatrix(expectedValues, 3) val actualAppended = affineA.append(affineB) diff --git a/rtron-math/src/test/kotlin/io/rtron/math/transform/Affine3DTest.kt b/rtron-math/src/test/kotlin/io/rtron/math/transform/Affine3DTest.kt index 701891e4..ef6e1ed4 100644 --- a/rtron-math/src/test/kotlin/io/rtron/math/transform/Affine3DTest.kt +++ b/rtron-math/src/test/kotlin/io/rtron/math/transform/Affine3DTest.kt @@ -54,12 +54,13 @@ class Affine3DTest : FunSpec({ } test("test translation from 3x4 matrix") { - val values = doubleArrayOf( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 3.0, - 0.0, 0.0, 1.0, 2.0, - 0.0, 0.0, 0.0, 1.0 - ) + val values = + doubleArrayOf( + 1.0, 0.0, 0.0, 0.0, + 0.0, 1.0, 0.0, 3.0, + 0.0, 0.0, 1.0, 2.0, + 0.0, 0.0, 0.0, 1.0, + ) val matrix = RealMatrix(values, 4) val affine = Affine3D.of(matrix) @@ -93,14 +94,15 @@ class Affine3DTest : FunSpec({ val rotation = Rotation3D(heading) val affine = Affine3D.of(Affine3D.of(scaling), Affine3D.of(translation), Affine3D.of(rotation)) - val expectedRotationMatrix = RealMatrix( - arrayOf( - doubleArrayOf(cos(heading), -sin(heading), 0.0, 0.0), - doubleArrayOf(sin(heading), cos(heading), 0.0, 0.0), - doubleArrayOf(0.0, 0.0, 1.0, 0.0), - doubleArrayOf(0.0, 0.0, 0.0, 1.0) + val expectedRotationMatrix = + RealMatrix( + arrayOf( + doubleArrayOf(cos(heading), -sin(heading), 0.0, 0.0), + doubleArrayOf(sin(heading), cos(heading), 0.0, 0.0), + doubleArrayOf(0.0, 0.0, 1.0, 0.0), + doubleArrayOf(0.0, 0.0, 0.0, 1.0), + ), ) - ) val actual = affine.extractRotationAffine().toRealMatrix() @@ -118,12 +120,13 @@ class Affine3DTest : FunSpec({ val affineA = Affine3D.of(translation) val scaling = RealVector.of(2.0, 3.0, 4.0) val affineB = Affine3D.of(scaling) - val expectedValues = doubleArrayOf( - 2.0, 0.0, 0.0, 1.0, - 0.0, 3.0, 0.0, 2.0, - 0.0, 0.0, 4.0, 3.0, - 0.0, 0.0, 0.0, 1.0 - ) + val expectedValues = + doubleArrayOf( + 2.0, 0.0, 0.0, 1.0, + 0.0, 3.0, 0.0, 2.0, + 0.0, 0.0, 4.0, 3.0, + 0.0, 0.0, 0.0, 1.0, + ) val expectedMatrix = RealMatrix(expectedValues, 4) val actualAppended = affineA.append(affineB) @@ -199,12 +202,13 @@ class Affine3DTest : FunSpec({ test("test to double array") { val translation = Vector3D(1.0, 2.0, 3.0) val affine = Affine3D.of(translation) - val expectedDoubleArray = doubleArrayOf( - 1.0, 0.0, 0.0, 1.0, - 0.0, 1.0, 0.0, 2.0, - 0.0, 0.0, 1.0, 3.0, - 0.0, 0.0, 0.0, 1.0 - ) + val expectedDoubleArray = + doubleArrayOf( + 1.0, 0.0, 0.0, 1.0, + 0.0, 1.0, 0.0, 2.0, + 0.0, 0.0, 1.0, 3.0, + 0.0, 0.0, 0.0, 1.0, + ) val actualDoubleArray = affine.toDoubleArray() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/citygml/CitygmlModel.kt b/rtron-model/src/main/kotlin/io/rtron/model/citygml/CitygmlModel.kt index 6cbb2510..99adcb50 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/citygml/CitygmlModel.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/citygml/CitygmlModel.kt @@ -32,5 +32,5 @@ import org.xmlobjects.gml.model.feature.BoundingShape class CitygmlModel( val name: Option, val boundingShape: BoundingShape, - val cityObjects: List + val cityObjects: List, ) : AbstractModel() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/citygml/code/AuxiliaryTrafficAreaFunctionCode.kt b/rtron-model/src/main/kotlin/io/rtron/model/citygml/code/AuxiliaryTrafficAreaFunctionCode.kt index bf07bbd1..912e00d4 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/citygml/code/AuxiliaryTrafficAreaFunctionCode.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/citygml/code/AuxiliaryTrafficAreaFunctionCode.kt @@ -37,5 +37,5 @@ enum class AuxiliaryTrafficAreaFunctionCode(val code: Code) { NOISE_PROTECTION_WALL(Code("1440")), NOISE_GUARD_BAR(Code("1500")), TOWPATH(Code("1600")), - OTHERS(Code("1700")) + OTHERS(Code("1700")), } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/citygml/code/TrafficArea.kt b/rtron-model/src/main/kotlin/io/rtron/model/citygml/code/TrafficArea.kt index aabfe0f3..b77aaa28 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/citygml/code/TrafficArea.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/citygml/code/TrafficArea.kt @@ -56,7 +56,7 @@ enum class TrafficAreaFunctionCode(val code: Code) { MOTORWAY_EXIT(Code("35")), MOTORWAY_EMERGENCY_LANE(Code("36")), PRIVATE_AREA(Code("37")), - UNKNOWN(Code("9999")) + UNKNOWN(Code("9999")), } enum class TrafficAreaUsageCode(val code: Code) { @@ -74,7 +74,7 @@ enum class TrafficAreaUsageCode(val code: Code) { HELICOPTER(Code("12")), TAXI(Code("13")), HORSE(Code("14")), - UNKNOWN(Code("9999")) + UNKNOWN(Code("9999")), } enum class TrafficAreaAndAuxiliaryTrafficAreaSurfaceMaterialCode(val code: Code) { @@ -91,5 +91,5 @@ enum class TrafficAreaAndAuxiliaryTrafficAreaSurfaceMaterialCode(val code: Code) WOOD(Code("11")), STEEL(Code("12")), MARBLE(Code("13")), - UNKNOWN(Code("9999")) + UNKNOWN(Code("9999")), } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/OpendriveModel.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/OpendriveModel.kt index 5f4719ce..1d3fd088 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/OpendriveModel.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/OpendriveModel.kt @@ -36,9 +36,8 @@ data class OpendriveModel( var header: Header = Header(), var road: List = emptyList(), var controller: List = emptyList(), - var junction: List = emptyList() + var junction: List = emptyList(), ) : AbstractModel() { - // Properties and Initializers val roadAsNonEmptyList: NonEmptyList get() = road.toNonEmptyListOrNull()!! diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/extensions/IdentifierUpdater.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/extensions/IdentifierUpdater.kt index 8d3a8df5..fe1cc555 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/extensions/IdentifierUpdater.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/extensions/IdentifierUpdater.kt @@ -62,9 +62,10 @@ fun OpendriveModel.updateAdditionalIdentifiers() { } everyLaneSection.modify(this) { currentLaneSection -> - val currentLaneSectionId = currentLaneSection.additionalId - .toEither { IllegalStateException("Additional ID not available.") } - .getOrElse { throw it } + val currentLaneSectionId = + currentLaneSection.additionalId + .toEither { IllegalStateException("Additional ID not available.") } + .getOrElse { throw it } currentLaneSection.center.lane.forEach { currentLane -> currentLane.additionalId = LaneIdentifier(currentLane.id, currentLaneSectionId).some() @@ -86,9 +87,10 @@ fun OpendriveModel.updateAdditionalIdentifiers() { } everyRoadLanesLaneSectionCenterLane.modify(this) { currentCenterLane -> - val currentLaneId = currentCenterLane.additionalId - .toEither { IllegalStateException("Additional ID not available.") } - .getOrElse { throw it } + val currentLaneId = + currentCenterLane.additionalId + .toEither { IllegalStateException("Additional ID not available.") } + .getOrElse { throw it } currentCenterLane.roadMark.forEachIndexed { index, currentRoadMark -> currentRoadMark.additionalId = LaneRoadMarkIdentifier(index, currentLaneId).some() @@ -98,9 +100,10 @@ fun OpendriveModel.updateAdditionalIdentifiers() { } everyRoadLanesLaneSectionLeftLane.modify(this) { currentLeftLane -> - val currentLaneId = currentLeftLane.additionalId - .toEither { IllegalStateException("Additional ID not available.") } - .getOrElse { throw it } + val currentLaneId = + currentLeftLane.additionalId + .toEither { IllegalStateException("Additional ID not available.") } + .getOrElse { throw it } currentLeftLane.roadMark.forEachIndexed { index, currentRoadMark -> currentRoadMark.additionalId = LaneRoadMarkIdentifier(index, currentLaneId).some() @@ -110,9 +113,10 @@ fun OpendriveModel.updateAdditionalIdentifiers() { } everyRoadLanesLaneSectionRightLane.modify(this) { currentRightLane -> - val currentLaneId = currentRightLane.additionalId - .toEither { IllegalStateException("Additional ID not available.") } - .getOrElse { throw it } + val currentLaneId = + currentRightLane.additionalId + .toEither { IllegalStateException("Additional ID not available.") } + .getOrElse { throw it } currentRightLane.roadMark.forEachIndexed { index, currentRoadMark -> currentRoadMark.additionalId = LaneRoadMarkIdentifier(index, currentLaneId).some() @@ -133,9 +137,10 @@ fun OpendriveModel.updateAdditionalIdentifiers() { } everyRoadObject.modify(this) { currentRoadObject -> - val currentRoadObjectId = currentRoadObject.additionalId - .toEither { IllegalStateException("Additional ID not available.") } - .getOrElse { throw it } + val currentRoadObjectId = + currentRoadObject.additionalId + .toEither { IllegalStateException("Additional ID not available.") } + .getOrElse { throw it } currentRoadObject.outlines.onSome { currentRoadObjectOutlines -> diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/AbstractOpendriveIdentifier.kt.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/AbstractOpendriveIdentifier.kt.kt index 8a2241e3..4702a0b7 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/AbstractOpendriveIdentifier.kt.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/AbstractOpendriveIdentifier.kt.kt @@ -19,7 +19,6 @@ package io.rtron.model.opendrive.additions.identifier import arrow.core.Option abstract class AbstractOpendriveIdentifier { - abstract fun toIdentifierText(): String } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/JunctionConnectionIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/JunctionConnectionIdentifier.kt index 636df7c8..bef5e585 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/JunctionConnectionIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/JunctionConnectionIdentifier.kt @@ -21,12 +21,13 @@ import arrow.core.Option interface JunctionConnectionIdentifierInterface { val connectionId: String } + data class JunctionConnectionIdentifier(override val connectionId: String, val junctionIdentifier: JunctionIdentifier) : AbstractOpendriveIdentifier(), JunctionConnectionIdentifierInterface, JunctionIdentifierInterface by junctionIdentifier { - // Conversions - override fun toIdentifierText() = "Connection: connectionId=$connectionId, " + - "junctionId=${junctionIdentifier.junctionId}" + override fun toIdentifierText() = + "Connection: connectionId=$connectionId, " + + "junctionId=${junctionIdentifier.junctionId}" } interface AdditionalJunctionConnectionIdentifier { diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/JunctionIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/JunctionIdentifier.kt index 1c3f8218..f9c60b72 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/JunctionIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/JunctionIdentifier.kt @@ -23,7 +23,6 @@ interface JunctionIdentifierInterface { } data class JunctionIdentifier(override val junctionId: String) : AbstractOpendriveIdentifier(), JunctionIdentifierInterface { - // Conversions override fun toIdentifierText() = "Junction: junctionId=$junctionId" } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneIdentifier.kt index d8e84e34..00e79148 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneIdentifier.kt @@ -24,11 +24,11 @@ interface LaneIdentifierInterface { data class LaneIdentifier(override val laneId: Int, val laneSectionIdentifier: LaneSectionIdentifier) : AbstractOpendriveIdentifier(), LaneIdentifierInterface, RoadLaneSectionIdentifierInterface by laneSectionIdentifier { - // Conversions - override fun toIdentifierText() = "Lane: laneId=$laneId, " + - "laneSectionIndex=${laneSectionIdentifier.laneSectionIndex}, " + - "roadId=${laneSectionIdentifier.roadIdentifier.roadId}" + override fun toIdentifierText() = + "Lane: laneId=$laneId, " + + "laneSectionIndex=${laneSectionIdentifier.laneSectionIndex}, " + + "roadId=${laneSectionIdentifier.roadIdentifier.roadId}" } interface AdditionalLaneIdentifier { diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneRoadMarkIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneRoadMarkIdentifier.kt index 333407cd..61869693 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneRoadMarkIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneRoadMarkIdentifier.kt @@ -24,11 +24,11 @@ interface LaneRoadMarkIdentifierInterface { data class LaneRoadMarkIdentifier(override val laneRoadMarkIndex: Int, val laneIdentifier: LaneIdentifier) : AbstractOpendriveIdentifier(), LaneRoadMarkIdentifierInterface, LaneIdentifierInterface by laneIdentifier { - // Conversions - override fun toIdentifierText() = "Lane road mark: laneRoadMarkIndex=$laneRoadMarkIndex, " + - "laneId=$laneId, laneSectionIndex=${laneIdentifier.laneSectionIndex}, " + - "roadId=${laneIdentifier.laneSectionIdentifier.roadIdentifier.roadId}" + override fun toIdentifierText() = + "Lane road mark: laneRoadMarkIndex=$laneRoadMarkIndex, " + + "laneId=$laneId, laneSectionIndex=${laneIdentifier.laneSectionIndex}, " + + "roadId=${laneIdentifier.laneSectionIdentifier.roadIdentifier.roadId}" } interface AdditionalLaneRoadMarkIdentifier { diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneSectionIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneSectionIdentifier.kt index 61e3530e..c1af3fc5 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneSectionIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/LaneSectionIdentifier.kt @@ -24,7 +24,6 @@ interface RoadLaneSectionIdentifierInterface { data class LaneSectionIdentifier(override val laneSectionIndex: Int, val roadIdentifier: RoadIdentifier) : AbstractOpendriveIdentifier(), RoadLaneSectionIdentifierInterface, RoadIdentifierInterface by roadIdentifier { - // Conversions override fun toIdentifierText() = "Lane section: laneSectionIndex=$laneSectionIndex, roadId=${roadIdentifier.roadId}" } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadIdentifier.kt index 717b708b..6bf19918 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadIdentifier.kt @@ -24,7 +24,6 @@ interface RoadIdentifierInterface { data class RoadIdentifier(override val roadId: String) : AbstractOpendriveIdentifier(), RoadIdentifierInterface { - // Conversions override fun toIdentifierText() = "Road: roadId=$roadId" } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectIdentifier.kt index e0545e51..39fb59d7 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectIdentifier.kt @@ -24,7 +24,6 @@ interface RoadObjectIdentifierInterface { data class RoadObjectIdentifier(override val roadObjectId: String, val roadIdentifier: RoadIdentifier) : AbstractOpendriveIdentifier(), RoadObjectIdentifierInterface, RoadIdentifierInterface by roadIdentifier { - // Conversions override fun toIdentifierText() = "Road object: roadObjectId=$roadObjectId, roadId=$roadId" } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectOutlineIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectOutlineIdentifier.kt index dd7db4f0..e1c764e5 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectOutlineIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectOutlineIdentifier.kt @@ -24,11 +24,11 @@ interface RoadObjectOutlineIdentifierInterface { data class RoadObjectOutlineIdentifier(override val outlineId: Int, val roadObjectIdentifier: RoadObjectIdentifier) : AbstractOpendriveIdentifier(), RoadObjectOutlineIdentifierInterface, RoadIdentifierInterface by roadObjectIdentifier { - // Conversions - override fun toIdentifierText() = "Road object outline: outlineId=$outlineId, " + - "roadObjectId=${roadObjectIdentifier.roadObjectId}, " + - "roadId=${roadObjectIdentifier.roadId}" + override fun toIdentifierText() = + "Road object outline: outlineId=$outlineId, " + + "roadObjectId=${roadObjectIdentifier.roadObjectId}, " + + "roadId=${roadObjectIdentifier.roadId}" } interface AdditionalRoadObjectOutlineIdentifier { diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectRepeatIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectRepeatIdentifier.kt index b680bcc5..94e3fe6c 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectRepeatIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadObjectRepeatIdentifier.kt @@ -24,11 +24,11 @@ interface RoadObjectRepeatInterface { data class RoadObjectRepeatIdentifier(override val repeatIndex: Int, val roadObjectIdentifier: RoadObjectIdentifier) : AbstractOpendriveIdentifier(), RoadObjectRepeatInterface, RoadIdentifierInterface by roadObjectIdentifier { - // Conversions - override fun toIdentifierText() = "Road object repeat element: repeatIndex=$repeatIndex, " + - "roadObjectId=${roadObjectIdentifier.roadObjectId}, " + - "roadId=${roadObjectIdentifier.roadId}" + override fun toIdentifierText() = + "Road object repeat element: repeatIndex=$repeatIndex, " + + "roadObjectId=${roadObjectIdentifier.roadObjectId}, " + + "roadId=${roadObjectIdentifier.roadId}" } interface AdditionalRoadObjectRepeatIdentifier { diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadSignalIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadSignalIdentifier.kt index d3db2ff3..2de77b3e 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadSignalIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/additions/identifier/RoadSignalIdentifier.kt @@ -24,7 +24,6 @@ interface RoadSignalIdentifierInterface { data class RoadSignalIdentifier(override val roadSignalId: String, val roadIdentifier: RoadIdentifier) : AbstractOpendriveIdentifier(), RoadSignalIdentifierInterface, RoadIdentifierInterface by roadIdentifier { - // Conversions override fun toIdentifierText() = "Road signal: roadSignalId=$roadSignalId, roadId=${roadIdentifier.roadId}" } 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 57f31a2e..4fcfaa6d 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 @@ -58,25 +58,40 @@ import io.rtron.model.opendrive.signal.signal val everyHeaderOffset = OpendriveModel.header compose Header.offset compose PPrism.some() +// road val everyRoad = OpendriveModel.road compose Traversal.list() val everyRoadPlanView = everyRoad compose Road.planView val everyRoadPlanViewGeometry = everyRoadPlanView compose RoadPlanView.geometry compose Traversal.list() val everyRoadElevationProfile = everyRoad compose Road.elevationProfile -val everyRoadElevationProfileElement = everyRoadElevationProfile compose PPrism.some() compose RoadElevationProfile.elevation compose Traversal.list() +val everyRoadElevationProfileElement = + everyRoadElevationProfile compose PPrism.some() compose RoadElevationProfile.elevation compose + Traversal.list() +// lane section val everyLaneSection = everyRoad compose Road.lanes compose RoadLanes.laneSection compose Traversal.list() -val everyRoadLanesLaneSectionLeftLane = everyLaneSection compose RoadLanesLaneSection.left compose PPrism.some() compose RoadLanesLaneSectionLeft.lane compose Traversal.list() -val everyRoadLanesLaneSectionRightLane = everyLaneSection compose RoadLanesLaneSection.right compose PPrism.some() compose RoadLanesLaneSectionRight.lane compose Traversal.list() -val everyRoadLanesLaneSectionCenterLane = everyLaneSection compose RoadLanesLaneSection.center compose RoadLanesLaneSectionCenter.lane compose Traversal.list() +val everyRoadLanesLaneSectionLeftLane = + everyLaneSection compose RoadLanesLaneSection.left compose PPrism.some() compose + RoadLanesLaneSectionLeft.lane compose Traversal.list() +val everyRoadLanesLaneSectionRightLane = + everyLaneSection compose RoadLanesLaneSection.right compose PPrism.some() compose + RoadLanesLaneSectionRight.lane compose Traversal.list() +val everyRoadLanesLaneSectionCenterLane = + everyLaneSection compose RoadLanesLaneSection.center compose + RoadLanesLaneSectionCenter.lane compose Traversal.list() +// junction val everyJunction = OpendriveModel.junction compose Traversal.list() val everyJunctionConnection = everyJunction compose Junction.connection compose Traversal.list() +// road object 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 everyRoadObjectOutlineElement = + everyRoadObject compose RoadObjectsObject.outlines compose PPrism.some() compose + RoadObjectsObjectOutlines.outline compose Traversal.list() val everyRoadObjectRepeatElement = everyRoadObject compose RoadObjectsObject.repeat compose Traversal.list() +// road signal val everyRoadSignalContainer = everyRoad compose Road.signals compose PPrism.some() val everyRoadSignal = everyRoadSignalContainer compose RoadSignals.signal compose Traversal.list() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/AdditionalData.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/AdditionalData.kt index 585b88fb..9922e8f1 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/AdditionalData.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/AdditionalData.kt @@ -22,5 +22,5 @@ import arrow.core.Option data class AdditionalData( var userData: List = emptyList(), var include: List = emptyList(), - var dataQuality: Option = None + var dataQuality: Option = None, ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQuality.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQuality.kt index d05571c1..db1e9a1f 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQuality.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQuality.kt @@ -21,5 +21,5 @@ import arrow.core.Option data class DataQuality( var error: Option = None, - var rawData: Option = None + var rawData: Option = None, ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQualityError.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQualityError.kt index 6e272b67..f8081d12 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQualityError.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQualityError.kt @@ -20,5 +20,5 @@ data class DataQualityError( var xyAbsolute: Double = Double.NaN, var xyRelative: Double = Double.NaN, var zAbsolute: Double = Double.NaN, - var zRelative: Double = Double.NaN + var zRelative: Double = Double.NaN, ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQualityRawData.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQualityRawData.kt index 0c7da65a..b8d246f5 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQualityRawData.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/DataQualityRawData.kt @@ -24,5 +24,5 @@ data class DataQualityRawData( var postProcessing: EDataQualityRawDataPostProcessing = EDataQualityRawDataPostProcessing.RAW, var postProcessingComment: Option = None, var source: EDataQualityRawDataSource = EDataQualityRawDataSource.CUSTOM, - var sourceComment: Option = None + var sourceComment: Option = None, ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Enumerations.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Enumerations.kt index 1922aef4..7db03769 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Enumerations.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Enumerations.kt @@ -17,18 +17,28 @@ package io.rtron.model.opendrive.core enum class EDataQualityRawDataPostProcessing { RAW, CLEANED, PROCESSED, FUSED } + enum class EDataQualityRawDataSource { SENSOR, CADASTER, CUSTOM } enum class EUnitDistance { METER, KILOMETER, FEET, MILE } + enum class EUnitSpeed { METER_PER_SECOND, MILES_PER_HOUR, KILOMETER_PER_HOUR } + enum class EUnitMass { KILOGRAM, TON } + enum class EUnitSlope { PERCENT } enum class EUnit { - METER, KILOMETER, FEET, MILE, // EUnitDistance - METER_PER_SECOND, MILES_PER_HOUR, KILOMETER_PER_HOUR, // EUnitSpeed - KILOGRAM, TON, // EUnitMass - PERCENT // EUnit + METER, + KILOMETER, + FEET, + MILE, // EUnitDistance + METER_PER_SECOND, + MILES_PER_HOUR, + KILOMETER_PER_HOUR, // EUnitSpeed + KILOGRAM, + TON, // EUnitMass + PERCENT, // EUnit } // see: https://github.com/lukes/ISO-3166-Countries-with-Regional-Codes/blob/master/all/all.csv @@ -281,5 +291,5 @@ enum class ECountryCode { EH, // Western Sahara YE, // Yemen ZM, // Zambia - ZW // Zimbabwe + ZW, // Zimbabwe } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Header.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Header.kt index 30196e50..5f43f299 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Header.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Header.kt @@ -24,7 +24,6 @@ import arrow.optics.optics data class Header( var geoReference: Option = None, var offset: Option = None, - var date: Option = None, var east: Option = None, var name: Option = None, @@ -34,8 +33,7 @@ data class Header( var south: Option = None, var vendor: Option = None, var version: Option = None, - var west: Option = None + var west: Option = None, ) : OpendriveElement() { - companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/HeaderGeoReference.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/HeaderGeoReference.kt index b20d0fb1..43c441a1 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/HeaderGeoReference.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/HeaderGeoReference.kt @@ -18,5 +18,5 @@ package io.rtron.model.opendrive.core data class HeaderGeoReference( var content: String, - var g_additionalData: List = emptyList() + var g_additionalData: List = emptyList(), ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/HeaderOffset.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/HeaderOffset.kt index de626372..eacd0ee2 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/HeaderOffset.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/HeaderOffset.kt @@ -20,5 +20,5 @@ data class HeaderOffset( var hdg: Double = 0.0, var x: Double = 0.0, var y: Double = 0.0, - var z: Double = 0.0 + var z: Double = 0.0, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Include.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Include.kt index b6f6b441..e4e449db 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Include.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/Include.kt @@ -17,5 +17,5 @@ package io.rtron.model.opendrive.core data class Include( - var file: String = "" + var file: String = "", ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/OpendriveElement.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/OpendriveElement.kt index 6a3b4f54..3de9e09d 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/OpendriveElement.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/OpendriveElement.kt @@ -17,5 +17,5 @@ package io.rtron.model.opendrive.core open class OpendriveElement( - var g_AdditionalData: List = emptyList() + var g_AdditionalData: List = emptyList(), ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/UserData.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/UserData.kt index 0a1a94a0..6ca49165 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/UserData.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/core/UserData.kt @@ -22,5 +22,5 @@ import arrow.core.Option data class UserData( // TODO: sequence var code: String = "", - var value: Option = None + var value: Option = None, ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/Enumerations.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/Enumerations.kt index 5911943d..95173089 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/Enumerations.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/Enumerations.kt @@ -17,10 +17,17 @@ package io.rtron.model.opendrive.junction enum class EConnectionType { DEFAULT, VIRTUAL } + enum class EContactPoint { START, END } + enum class EElementDir { PLUS, MINUS } + enum class EJunctionSurfaceCRGMode { GLOBAL } + enum class EJunctionType { DEFAULT, VIRTUAL, DIRECT } + enum class EJunctionGroupType { ROUNDABOUT, UNKNOWN } + enum class ERoadSurfaceCrgMode { ATTACHED, ATTACHED0, GENUINE, GLOBAL } + enum class ERoadSurfaceCrgPurpose { ELEVATION, FRICTION } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/Junction.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/Junction.kt index eea0274a..8050d86b 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/Junction.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/Junction.kt @@ -33,7 +33,6 @@ data class Junction( var priority: List = emptyList(), var controller: List = emptyList(), var surface: Option = None, - var id: String = "", var mainRoad: Option = None, var name: Option = None, @@ -41,10 +40,8 @@ data class Junction( var sEnd: Option = None, var sStart: Option = None, var type: Option = None, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalJunctionIdentifier { - // Properties and Initializers val connectionAsNonEmptyList: NonEmptyList get() = connection.toNonEmptyListOrNull()!! @@ -54,7 +51,9 @@ data class Junction( // Methods fun getConnectingRoadIds(): Set = connection.flatMap { it.incomingRoad.toList() }.toSet() + fun getIncomingRoadIds(): Set = connection.flatMap { it.incomingRoad.toList() }.toSet() + fun getNumberOfIncomingRoads(): Int = getIncomingRoadIds().size companion object diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionConnection.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionConnection.kt index 4bdec4cc..9b46bae6 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionConnection.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionConnection.kt @@ -26,13 +26,11 @@ data class JunctionConnection( var predecessor: Option = None, var successor: Option = None, var laneLink: List = emptyList(), - var connectingRoad: Option = None, var contactPoint: Option = None, var id: String = "", var incomingRoad: Option = None, var linkedRoad: Option = None, var type: Option = None, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalJunctionConnectionIdentifier diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionConnectionLaneLink.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionConnectionLaneLink.kt index 903fbb98..26cf2188 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionConnectionLaneLink.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionConnectionLaneLink.kt @@ -20,5 +20,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class JunctionConnectionLaneLink( var from: Int = Int.MIN_VALUE, - var to: Int = Int.MIN_VALUE + var to: Int = Int.MIN_VALUE, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionController.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionController.kt index dd9b2166..753535e6 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionController.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionController.kt @@ -23,5 +23,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class JunctionController( var id: String = "", var sequence: Option = None, - var type: Option = None + var type: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionPredecessorSuccessor.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionPredecessorSuccessor.kt index 89180790..8af15b6a 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionPredecessorSuccessor.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionPredecessorSuccessor.kt @@ -22,5 +22,5 @@ data class JunctionPredecessorSuccessor( var elementDir: EElementDir = EElementDir.PLUS, var elementId: String = "", var elementS: Double = Double.NaN, - var elementType: String = "" + var elementType: String = "", ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionPriority.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionPriority.kt index d4493717..52c2862f 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionPriority.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionPriority.kt @@ -22,5 +22,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class JunctionPriority( var high: Option = None, - var low: Option = None + var low: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionSurface.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionSurface.kt index eec5b155..8273f25e 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionSurface.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionSurface.kt @@ -19,5 +19,5 @@ package io.rtron.model.opendrive.junction import io.rtron.model.opendrive.core.OpendriveElement data class JunctionSurface( - var crg: List = emptyList() + var crg: List = emptyList(), ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionSurfaceCrg.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionSurfaceCrg.kt index 77cf492e..13a49c42 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionSurfaceCrg.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/junction/JunctionSurfaceCrg.kt @@ -25,5 +25,5 @@ data class JunctionSurfaceCrg( var mode: EJunctionSurfaceCRGMode = EJunctionSurfaceCRGMode.GLOBAL, var purpose: Option = None, var zOffset: Option = None, - var zScale: Option = None + var zScale: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/Enumerations.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/Enumerations.kt index 36e1bd02..c994ff75 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/Enumerations.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/Enumerations.kt @@ -17,13 +17,51 @@ package io.rtron.model.opendrive.lane enum class EAccessRestrictionType { - SIMULATOR, AUTONOMOUS_TRAFFIC, PEDESTRIAN, PASSENGER_CAR, BUS, DELIVERY, EMERGENCY, - TAXI, THROUGH_TRAFFIC, TRUCK, BICYCLE, MOTORCYCLE, NONE, TRUCKS + SIMULATOR, + AUTONOMOUS_TRAFFIC, + PEDESTRIAN, + PASSENGER_CAR, + BUS, + DELIVERY, + EMERGENCY, + TAXI, + THROUGH_TRAFFIC, + TRUCK, + BICYCLE, + MOTORCYCLE, + NONE, + TRUCKS, } + enum class ELaneType { - SHOULDER, BORDER, DRIVING, STOP, NONE, RESTRICTED, PARKING, MEDIAN, BIKING, SIDEWALK, CURB, EXIT, ENTRY, ON_RAMP, - OFF_RAMP, CONNECTING_RAMP, BIDIRECTIONAL, SPECIAL_1, SPECIAL_2, SPECIAL_3, ROAD_WORKS, TRAM, RAIL, BUS, TAXI, HOV, - MWY_ENTRY, MWY_EXIT + SHOULDER, + BORDER, + DRIVING, + STOP, + NONE, + RESTRICTED, + PARKING, + MEDIAN, + BIKING, + SIDEWALK, + CURB, + EXIT, + ENTRY, + ON_RAMP, + OFF_RAMP, + CONNECTING_RAMP, + BIDIRECTIONAL, + SPECIAL_1, + SPECIAL_2, + SPECIAL_3, + ROAD_WORKS, + TRAM, + RAIL, + BUS, + TAXI, + HOV, + MWY_ENTRY, + MWY_EXIT, } enum class ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange { INCREASE, DECREASE, BOTH, NONE } @@ -33,9 +71,20 @@ enum class ERoadLanesLaneSectionLRLaneAccessRule { ALLOW, DENY } enum class ERoadMarkColor { STANDARD, BLUE, GREEN, RED, WHITE, YELLOW, ORANGE } enum class ERoadMarkRule { NO_PASSING, CAUTION, NONE } + enum class ERoadMarkType { - NONE, SOLID, BROKEN, SOLID_SOLID, SOLID_BROKEN, BROKEN_SOLID, BROKEN_BROKEN, - BOTTS_DOTS, GRASS, CURB, CUSTOM, EDGE + NONE, + SOLID, + BROKEN, + SOLID_SOLID, + SOLID_BROKEN, + BROKEN_SOLID, + BROKEN_BROKEN, + BOTTS_DOTS, + GRASS, + CURB, + CUSTOM, + EDGE, } enum class ERoadMarkWeight { STANDARD, BOLD } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanes.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanes.kt index a3004739..e722417e 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanes.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanes.kt @@ -28,9 +28,8 @@ import io.rtron.model.opendrive.core.OpendriveElement @optics data class RoadLanes( var laneOffset: List = emptyList(), - var laneSection: List = emptyList() + var laneSection: List = emptyList(), ) : OpendriveElement() { - // Validation Properties val laneSectionAsNonEmptyList: NonEmptyList get() = laneSection.toNonEmptyListOrNull()!! @@ -52,8 +51,7 @@ data class RoadLanes( return (laneSectionRanges + lastLaneSectionRange).toNonEmptyListOrNull()!! } - fun getLaneSectionLengths(lastLaneSectionEnd: Double): NonEmptyList = - getLaneSectionRanges(lastLaneSectionEnd).map { it.length } + fun getLaneSectionLengths(lastLaneSectionEnd: Double): NonEmptyList = getLaneSectionRanges(lastLaneSectionEnd).map { it.length } fun getLaneSectionsWithRanges(lastLaneSectionEnd: Double): NonEmptyList, RoadLanesLaneSection>> = getLaneSectionRanges(lastLaneSectionEnd).zip(laneSection).toNonEmptyListOrNull()!! diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneOffset.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneOffset.kt index 1ad6027b..1b3a11cb 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneOffset.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneOffset.kt @@ -23,7 +23,7 @@ data class RoadLanesLaneOffset( var b: Double = Double.NaN, var c: Double = Double.NaN, var d: Double = Double.NaN, - var s: Double = Double.NaN + var s: Double = Double.NaN, ) : OpendriveElement() { // Properties and Initializers val coefficients get() = doubleArrayOf(a, b, c, d) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSection.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSection.kt index 1c29b403..cbd67f62 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSection.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSection.kt @@ -29,26 +29,28 @@ data class RoadLanesLaneSection( var left: Option = None, var center: RoadLanesLaneSectionCenter = RoadLanesLaneSectionCenter(), var right: Option = None, - var s: Double = Double.NaN, var singleSide: Option = None, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalLaneSectionIdentifier { - // Properties and Initializers val laneSectionStart get() = CurveRelativeVector1D(s) // Methods fun getNumberOfLeftLanes() = left.fold({ 0 }, { it.getNumberOfLanes() }) + fun getNumberOfRightLanes() = right.fold({ 0 }, { it.getNumberOfLanes() }) fun getNumberOfLeftRightLanes() = getNumberOfLeftLanes() + getNumberOfRightLanes() + fun getNumberOfLanes() = center.getNumberOfLanes() + getNumberOfLeftRightLanes() fun getCenterLane() = center.lane.first() + fun getLeftLanes(): Map = left.fold({ emptyMap() }, { it.getLanes() }) + fun getRightLanes(): Map = right.fold({ emptyMap() }, { it.getLanes() }) + fun getLeftRightLanes(): Map = getLeftLanes() + getRightLanes() companion object diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionCenter.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionCenter.kt index b3ff0986..6589cc79 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionCenter.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionCenter.kt @@ -21,14 +21,14 @@ import io.rtron.model.opendrive.core.OpendriveElement @optics data class RoadLanesLaneSectionCenter( - var lane: List = emptyList() + var lane: List = emptyList(), ) : OpendriveElement() { - // Methods fun getIndividualCenterLane(): RoadLanesLaneSectionCenterLane { check(lane.size == 1) { "Must contain exactly one center lane element." } return lane.first() } + fun getNumberOfLanes() = lane.size companion object diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionCenterLane.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionCenterLane.kt index e80f53be..b89a1db3 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionCenterLane.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionCenterLane.kt @@ -25,7 +25,6 @@ import io.rtron.model.opendrive.additions.identifier.LaneIdentifier @optics data class RoadLanesLaneSectionCenterLane( var id: Int = 0, - override var link: Option = None, override var border: List = emptyList(), override var width: List = emptyList(), @@ -35,12 +34,9 @@ data class RoadLanesLaneSectionCenterLane( override var access: List = emptyList(), override var height: List = emptyList(), override var rule: List = emptyList(), - override var level: Option = None, override var type: ELaneType = ELaneType.NONE, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : RoadLanesLaneSectionLRLane(), AdditionalLaneIdentifier { - companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneLink.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneLink.kt index 63cb32d9..6eb1d83c 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneLink.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneLink.kt @@ -20,5 +20,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadLanesLaneSectionLCRLaneLink( var predecessor: List = emptyList(), - var successor: List = emptyList() + var successor: List = emptyList(), ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneLinkPredecessorSuccessor.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneLinkPredecessorSuccessor.kt index 9d698aef..a6e3accf 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneLinkPredecessorSuccessor.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneLinkPredecessorSuccessor.kt @@ -19,5 +19,5 @@ package io.rtron.model.opendrive.lane import io.rtron.model.opendrive.core.OpendriveElement data class RoadLanesLaneSectionLCRLaneLinkPredecessorSuccessor( - var id: Int = Int.MIN_VALUE + var id: Int = Int.MIN_VALUE, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMark.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMark.kt index ef95834b..01da89c7 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMark.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMark.kt @@ -28,7 +28,6 @@ data class RoadLanesLaneSectionLCRLaneRoadMark( var sway: List = emptyList(), var type: Option = None, var explicit: Option = None, - var color: ERoadMarkColor = ERoadMarkColor.STANDARD, var height: Option = None, var laneChange: Option = None, @@ -37,9 +36,7 @@ data class RoadLanesLaneSectionLCRLaneRoadMark( var typeAttribute: ERoadMarkType = ERoadMarkType.NONE, var weight: Option = None, var width: Option = None, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalLaneRoadMarkIdentifier { - companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkExplicit.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkExplicit.kt index b79b336e..1a4dee89 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkExplicit.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkExplicit.kt @@ -19,5 +19,5 @@ package io.rtron.model.opendrive.lane import io.rtron.model.opendrive.core.OpendriveElement data class RoadLanesLaneSectionLCRLaneRoadMarkExplicit( - var line: List = emptyList() + var line: List = emptyList(), ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkExplicitLine.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkExplicitLine.kt index 73aa3fd0..8ffdbdf6 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkExplicitLine.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkExplicitLine.kt @@ -25,5 +25,5 @@ data class RoadLanesLaneSectionLCRLaneRoadMarkExplicitLine( var rule: Option = None, var sOffset: Double = Double.NaN, var tOffset: Double = Double.NaN, - var width: Option = None + var width: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkSway.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkSway.kt index a1fa8985..fe72509f 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkSway.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkSway.kt @@ -23,7 +23,7 @@ data class RoadLanesLaneSectionLCRLaneRoadMarkSway( var b: Double = Double.NaN, var c: Double = Double.NaN, var d: Double = Double.NaN, - var ds: Double = Double.NaN + var ds: Double = Double.NaN, ) : OpendriveElement() { // Properties and Initializers val coefficients get() = doubleArrayOf(a, b, c, d) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkType.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkType.kt index 52d6367b..e401c84a 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkType.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkType.kt @@ -20,7 +20,6 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadLanesLaneSectionLCRLaneRoadMarkType( var line: List = emptyList(), - var name: String = "", - var width: Double = Double.NaN + var width: Double = Double.NaN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkTypeLine.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkTypeLine.kt index a5f1666b..7d5e05e4 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkTypeLine.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLCRLaneRoadMarkTypeLine.kt @@ -27,5 +27,5 @@ data class RoadLanesLaneSectionLCRLaneRoadMarkTypeLine( var sOffset: Double = Double.NaN, var space: Double = Double.NaN, var tOffset: Double = Double.NaN, - var width: Option = None + var width: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLane.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLane.kt index 34dd2964..73b7de44 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLane.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLane.kt @@ -39,15 +39,14 @@ abstract class RoadLanesLaneSectionLRLane( open var access: List = emptyList(), open var height: List = emptyList(), open var rule: List = emptyList(), - open var level: Option = None, open var type: ELaneType = ELaneType.NONE, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalLaneIdentifier { - // Properties fun getLaneWidthEntries(): Option> = width.toNonEmptyListOrNone() + fun getLaneHeightEntries(): Option> = height.toNonEmptyListOrNone() + fun getLevelWithDefault() = level.getOrElse { false } } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneAccess.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneAccess.kt index 3c0678c9..2ebcb956 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneAccess.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneAccess.kt @@ -21,5 +21,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadLanesLaneSectionLRLaneAccess( var restriction: EAccessRestrictionType = EAccessRestrictionType.NONE, var rule: ERoadLanesLaneSectionLRLaneAccessRule = ERoadLanesLaneSectionLRLaneAccessRule.ALLOW, - var sOffset: Double = Double.NaN + var sOffset: Double = Double.NaN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneBorder.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneBorder.kt index 6b5e71fc..5d17457b 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneBorder.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneBorder.kt @@ -23,7 +23,7 @@ data class RoadLanesLaneSectionLRLaneBorder( var b: Double = Double.NaN, var c: Double = Double.NaN, var d: Double = Double.NaN, - var sOffset: Double = Double.NaN + var sOffset: Double = Double.NaN, ) : OpendriveElement() { // Properties and Initializers val coefficients get() = doubleArrayOf(a, b, c, d) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneHeight.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneHeight.kt index c871a500..3c4cde87 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneHeight.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneHeight.kt @@ -21,5 +21,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadLanesLaneSectionLRLaneHeight( var inner: Double = Double.NaN, var outer: Double = Double.NaN, - var sOffset: Double = Double.NaN + var sOffset: Double = Double.NaN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneMaterial.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneMaterial.kt index 64c79df7..227cb23e 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneMaterial.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneMaterial.kt @@ -22,5 +22,5 @@ data class RoadLanesLaneSectionLRLaneMaterial( var friction: Double = Double.NaN, var roughness: Double = Double.NaN, var sOffset: Double = Double.NaN, - var surface: String = "" + var surface: String = "", ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneRule.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneRule.kt index 63900512..2c8a72a6 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneRule.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneRule.kt @@ -20,5 +20,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadLanesLaneSectionLRLaneRule( var sOffset: Double = Double.NaN, - var value: String = "" + var value: String = "", ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneSpeed.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneSpeed.kt index 6d146bac..0202cb91 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneSpeed.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneSpeed.kt @@ -24,5 +24,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadLanesLaneSectionLRLaneSpeed( var max: Double = Double.NaN, var sOffset: Double = Double.NaN, - var unit: Option = None + var unit: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneWidth.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneWidth.kt index 7bc4027e..0acaa6df 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneWidth.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLRLaneWidth.kt @@ -23,12 +23,13 @@ data class RoadLanesLaneSectionLRLaneWidth( var b: Double = Double.NaN, var c: Double = Double.NaN, var d: Double = Double.NaN, - var sOffset: Double = Double.NaN + var sOffset: Double = Double.NaN, ) : OpendriveElement() { // Properties and Initializers val coefficients get() = doubleArrayOf(a, b, c, d) // Methods + /*fun getAsResult(): Either { if (!sOffset.isFinite() || sOffset < 0.0) return Either.Left(IllegalStateException("Value of sOffset must be finite and positive.")) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLeft.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLeft.kt index 7f2a5f0c..32e498c2 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLeft.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLeft.kt @@ -21,15 +21,17 @@ import io.rtron.model.opendrive.core.OpendriveElement @optics data class RoadLanesLaneSectionLeft( - var lane: List = emptyList() + var lane: List = emptyList(), ) : OpendriveElement() { - // Methods fun isEmpty() = lane.isEmpty() + fun isNotEmpty() = lane.isNotEmpty() + fun getNumberOfLanes() = lane.size fun getLanes() = lane.associateBy { it.id } + fun getLanesAscending() = lane.sortedBy { it.id } companion object diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLeftLane.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLeftLane.kt index 3fcb4ab9..10d4be12 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLeftLane.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionLeftLane.kt @@ -25,7 +25,6 @@ import io.rtron.model.opendrive.additions.identifier.LaneIdentifier @optics data class RoadLanesLaneSectionLeftLane( var id: Int = Int.MIN_VALUE, - override var link: Option = None, override var border: List = emptyList(), override var width: List = emptyList(), @@ -35,12 +34,9 @@ data class RoadLanesLaneSectionLeftLane( override var access: List = emptyList(), override var height: List = emptyList(), override var rule: List = emptyList(), - override var level: Option = None, override var type: ELaneType = ELaneType.NONE, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : RoadLanesLaneSectionLRLane(), AdditionalLaneIdentifier { - companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionRight.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionRight.kt index e0171a4a..ceefec58 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionRight.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionRight.kt @@ -21,15 +21,17 @@ import io.rtron.model.opendrive.core.OpendriveElement @optics data class RoadLanesLaneSectionRight( - var lane: List = emptyList() + var lane: List = emptyList(), ) : OpendriveElement() { - // Methods fun isEmpty() = lane.isEmpty() + fun isNotEmpty() = lane.isNotEmpty() + fun getNumberOfLanes() = lane.size fun getLanes() = lane.associateBy { it.id } + fun getLanesDescending() = lane.sortedByDescending { it.id } companion object diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionRightLane.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionRightLane.kt index 08bc8f2e..3e8a8e77 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionRightLane.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/lane/RoadLanesLaneSectionRightLane.kt @@ -25,7 +25,6 @@ import io.rtron.model.opendrive.additions.identifier.LaneIdentifier @optics data class RoadLanesLaneSectionRightLane( var id: Int = Int.MIN_VALUE, - override var link: Option = None, override var border: List = emptyList(), override var width: List = emptyList(), @@ -35,12 +34,9 @@ data class RoadLanesLaneSectionRightLane( override var access: List = emptyList(), override var height: List = emptyList(), override var rule: List = emptyList(), - override var level: Option = None, override var type: ELaneType = ELaneType.NONE, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : RoadLanesLaneSectionLRLane(), AdditionalLaneIdentifier { - companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/Enumerations.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/Enumerations.kt index 00777179..a2061218 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/Enumerations.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/Enumerations.kt @@ -24,8 +24,22 @@ enum class EBorderType { CONCRETE, CURB } enum class EBridgeType { CONCRETE, STEEL, BRICK, WOOD } enum class EObjectType { - NONE, OBSTACLE, POLE, TREE, VEGETATION, BARRIER, BUILDING, PARKING_SPACE, PATCH, - RAILING, TRAFFIC_ISLAND, CROSSWALK, STREET_LAMP, GANTRY, SOUND_BARRIER, ROAD_MARK + NONE, + OBSTACLE, + POLE, + TREE, + VEGETATION, + BARRIER, + BUILDING, + PARKING_SPACE, + PATCH, + RAILING, + TRAFFIC_ISLAND, + CROSSWALK, + STREET_LAMP, + GANTRY, + SOUND_BARRIER, + ROAD_MARK, } // deprecated: CAR, VAN, BUS, TRAILER, BIKE, MOTORBIKE, TRAM, TRAIN, PEDESTRIAN, WIND @@ -37,13 +51,14 @@ enum class EOrientation { MINUS, /** valid in both directions */ - NONE + NONE, } -fun EOrientation.toRotation2D() = when (this) { - EOrientation.MINUS -> Rotation2D(PI) - else -> Rotation2D(0.0) -} +fun EOrientation.toRotation2D() = + when (this) { + EOrientation.MINUS -> Rotation2D(PI) + else -> Rotation2D(0.0) + } enum class EOutlineFillType { GRASS, CONCRETE, COBBLE, ASPHALT, PAVEMENT, GRAVEL, SOIL } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjects.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjects.kt index 7e90e387..9ba08864 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjects.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjects.kt @@ -24,8 +24,7 @@ data class RoadObjects( var roadObject: List = emptyList(), var objectReference: List = emptyList(), var tunnel: List = emptyList(), - var bridge: List = emptyList() + var bridge: List = emptyList(), ) : OpendriveElement() { - companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsBridge.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsBridge.kt index 82ee49f4..1eab792e 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsBridge.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsBridge.kt @@ -22,10 +22,9 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsBridge( var validity: List = emptyList(), - var id: String = "", var length: Double = Double.NaN, var name: Option = None, var s: Double = Double.NaN, - var type: EBridgeType = EBridgeType.CONCRETE + var type: EBridgeType = EBridgeType.CONCRETE, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObject.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObject.kt index 71ed58ce..ca144ac0 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObject.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObject.kt @@ -40,7 +40,6 @@ data class RoadObjectsObject( var markings: Option = None, var borders: Option = None, var surface: Option = None, - var dynamic: Option = None, var hdg: Option = None, var height: Option = None, @@ -59,10 +58,8 @@ data class RoadObjectsObject( var validLength: Option = None, var width: Option = None, var zOffset: Double = 0.0, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalRoadObjectIdentifier { - // Validation Properties val heightValidated: Option diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectBorders.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectBorders.kt index 4af3bdeb..c5052520 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectBorders.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectBorders.kt @@ -19,5 +19,5 @@ package io.rtron.model.opendrive.objects import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectBorders( - var marking: List = emptyList() + var marking: List = emptyList(), ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectBordersBorder.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectBordersBorder.kt index 2da1d64a..e4cc3e0d 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectBordersBorder.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectBordersBorder.kt @@ -22,9 +22,8 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectBordersBorder( var cornerReference: List = emptyList(), - var outlineId: Int = Int.MIN_VALUE, var type: EBorderType = EBorderType.CONCRETE, var useCompleteOutline: Option = None, - var width: Double = Double.NaN + var width: Double = Double.NaN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectLaneValidity.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectLaneValidity.kt index 6892369f..4d09dd24 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectLaneValidity.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectLaneValidity.kt @@ -20,5 +20,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectLaneValidity( var fromLane: Int = Int.MIN_VALUE, - var toLane: Int = Int.MIN_VALUE + var toLane: Int = Int.MIN_VALUE, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkings.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkings.kt index 28109064..2c50fdb3 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkings.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkings.kt @@ -19,5 +19,5 @@ package io.rtron.model.opendrive.objects import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectMarkings( - var marking: List = emptyList() + var marking: List = emptyList(), ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkingsMarking.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkingsMarking.kt index fc5c68c9..249ab099 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkingsMarking.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkingsMarking.kt @@ -32,5 +32,5 @@ data class RoadObjectsObjectMarkingsMarking( var stopOffset: Double = Double.NaN, var weight: Option = None, var width: Option = None, - var zOffset: Option = None + var zOffset: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkingsMarkingCornerReference.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkingsMarkingCornerReference.kt index bf927330..3f1a66dc 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkingsMarkingCornerReference.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMarkingsMarkingCornerReference.kt @@ -19,5 +19,5 @@ package io.rtron.model.opendrive.objects import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectMarkingsMarkingCornerReference( - var id: Int = Int.MIN_VALUE + var id: Int = Int.MIN_VALUE, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMaterial.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMaterial.kt index 48586a13..8b3adf61 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMaterial.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectMaterial.kt @@ -23,5 +23,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectMaterial( var friction: Option = None, var roughness: Option = None, - var surface: Option = None + var surface: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlines.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlines.kt index 8e4554c3..2d008114 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlines.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlines.kt @@ -21,20 +21,23 @@ import io.rtron.model.opendrive.core.OpendriveElement @optics data class RoadObjectsObjectOutlines( - var outline: List = emptyList() + var outline: List = emptyList(), ) : OpendriveElement() { - // Methods fun getPolyhedronsDefinedByRoadCorners() = outline.filter { it.isPolyhedronDefinedByRoadCorners() } + fun getPolyhedronsDefinedByLocalCorners() = outline.filter { it.isPolyhedronDefinedByLocalCorners() } fun getLinearRingsDefinedByRoadCorners() = outline.filter { it.isLinearRingDefinedByRoadCorners() } + fun getLinearRingsDefinedByLocalCorners() = outline.filter { it.isLinearRingDefinedByLocalCorners() } fun numberOfPolyhedrons() = getPolyhedronsDefinedByRoadCorners().size + getPolyhedronsDefinedByLocalCorners().size + fun numberOfLinearRings() = getLinearRingsDefinedByRoadCorners().size + getLinearRingsDefinedByLocalCorners().size fun containsPolyhedrons() = numberOfPolyhedrons() > 0 + fun containsLinearRings() = numberOfLinearRings() > 0 fun containsGeometries() = containsPolyhedrons() || containsLinearRings() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutline.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutline.kt index fbd41c71..fdf60287 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutline.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutline.kt @@ -28,22 +28,21 @@ import io.rtron.model.opendrive.lane.ELaneType data class RoadObjectsObjectOutlinesOutline( var cornerRoad: List = emptyList(), var cornerLocal: List = emptyList(), - var closed: Option = None, var fillType: Option = None, var id: Option = None, var laneType: Option = None, var outer: Option = None, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalRoadObjectOutlineIdentifier { - // Methods - fun isPolyhedronUniquelyDefined() = (isPolyhedronDefinedByRoadCorners() && !isPolyhedronDefinedByLocalCorners()) || - (!isPolyhedronDefinedByRoadCorners() && isPolyhedronDefinedByLocalCorners()) + fun isPolyhedronUniquelyDefined() = + (isPolyhedronDefinedByRoadCorners() && !isPolyhedronDefinedByLocalCorners()) || + (!isPolyhedronDefinedByRoadCorners() && isPolyhedronDefinedByLocalCorners()) - fun isLinearRingUniquelyDefined() = (isLinearRingDefinedByRoadCorners() && !isLinearRingDefinedByLocalCorners()) || - (!isLinearRingDefinedByRoadCorners() && isLinearRingDefinedByLocalCorners()) + fun isLinearRingUniquelyDefined() = + (isLinearRingDefinedByRoadCorners() && !isLinearRingDefinedByLocalCorners()) || + (!isLinearRingDefinedByRoadCorners() && isLinearRingDefinedByLocalCorners()) /** Returns true, if the provided geometry information correspond to a polyhedron. */ fun isPolyhedron() = isPolyhedronDefinedByRoadCorners() || isPolyhedronDefinedByLocalCorners() @@ -51,15 +50,13 @@ data class RoadObjectsObjectOutlinesOutline( /** Returns true, if the provided geometry information correspond to a linear ring. */ fun isLinearRing() = isLinearRingDefinedByRoadCorners() || isLinearRingDefinedByLocalCorners() - fun isPolyhedronDefinedByRoadCorners() = - cornerRoad.isNotEmpty() && cornerRoad.any { it.hasPositiveHeight() } - fun isPolyhedronDefinedByLocalCorners() = - cornerLocal.isNotEmpty() && cornerLocal.any { it.hasPositiveHeight() } + fun isPolyhedronDefinedByRoadCorners() = cornerRoad.isNotEmpty() && cornerRoad.any { it.hasPositiveHeight() } + + fun isPolyhedronDefinedByLocalCorners() = cornerLocal.isNotEmpty() && cornerLocal.any { it.hasPositiveHeight() } + + fun isLinearRingDefinedByRoadCorners() = cornerRoad.isNotEmpty() && cornerRoad.all { it.hasZeroHeight() } - fun isLinearRingDefinedByRoadCorners() = - cornerRoad.isNotEmpty() && cornerRoad.all { it.hasZeroHeight() } - fun isLinearRingDefinedByLocalCorners() = - cornerLocal.isNotEmpty() && cornerLocal.all { it.hasZeroHeight() } + fun isLinearRingDefinedByLocalCorners() = cornerLocal.isNotEmpty() && cornerLocal.all { it.hasZeroHeight() } companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutlineCornerLocal.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutlineCornerLocal.kt index 76c7c3e7..e71ce3d3 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutlineCornerLocal.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutlineCornerLocal.kt @@ -27,14 +27,15 @@ data class RoadObjectsObjectOutlinesOutlineCornerLocal( var id: Option = None, var u: Double = Double.NaN, var v: Double = Double.NaN, - var z: Double = Double.NaN + var z: Double = Double.NaN, ) : OpendriveElement() { - // Methods fun hasZeroHeight(): Boolean = !height.isFinite() || height == 0.0 + fun hasPositiveHeight(): Boolean = !hasZeroHeight() && height > 0.0 fun getBasePoint() = Vector3D(u, v, z) + fun getHeadPoint(): Option = if (hasZeroHeight()) { None diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutlineCornerRoad.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutlineCornerRoad.kt index 1d03f2b4..b5810d58 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutlineCornerRoad.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectOutlinesOutlineCornerRoad.kt @@ -28,16 +28,18 @@ data class RoadObjectsObjectOutlinesOutlineCornerRoad( var height: Double = Double.NaN, var id: Option = None, var s: Double = Double.NaN, - var t: Double = Double.NaN + var t: Double = Double.NaN, ) : OpendriveElement() { // Properties and Initializers val curveRelativePosition get() = CurveRelativeVector1D(s) // Methods fun hasZeroHeight(): Boolean = !height.isFinite() || height == 0.0 + fun hasPositiveHeight(): Boolean = !hasZeroHeight() && height > 0.0 fun getBasePoint() = CurveRelativeVector3D(s, t, dz) + fun getHeadPoint(): Option = if (hasZeroHeight()) { None diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectParkingSpace.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectParkingSpace.kt index b94505e9..8615d6bf 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectParkingSpace.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectParkingSpace.kt @@ -22,5 +22,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectParkingSpace( var access: ERoadObjectsObjectParkingSpaceAccess = ERoadObjectsObjectParkingSpaceAccess.ALL, - var restrictions: Option = None + var restrictions: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectReference.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectReference.kt index 9ab3a5f0..a5ae51b1 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectReference.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectReference.kt @@ -22,11 +22,10 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectReference( var validity: List = emptyList(), - var id: String = "", var orientation: EOrientation = EOrientation.NONE, var s: Double = Double.NaN, var t: Double = Double.NaN, var validLength: Option = None, - var zOffset: Option = None + var zOffset: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectRepeat.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectRepeat.kt index 5098a60b..9ba04521 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectRepeat.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectRepeat.kt @@ -44,10 +44,8 @@ data class RoadObjectsObjectRepeat( var widthStart: Option = None, var zOffsetEnd: Double = Double.NaN, var zOffsetStart: Double = Double.NaN, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalRoadObjectRepeatIdentifier { - // Properties and Initializers val curveRelativeStartPosition get() = CurveRelativeVector1D(s) @@ -56,61 +54,80 @@ data class RoadObjectsObjectRepeat( // Methods fun isContinuous() = distance == 0.0 + fun isDiscrete() = !isContinuous() fun isLengthNonZero() = length != 0.0 fun isObjectWidthZero() = widthStart.isNone() && widthEnd.isNone() + fun isObjectLengthZero() = lengthStart.isNone() && lengthEnd.isNone() + fun isObjectHeightZero() = heightStart == 0.0 && heightEnd == 0.0 + fun isObjectRadiusZero() = radiusStart.isNone() && radiusEnd.isNone() fun isObjectWidthNonZero() = widthStart.isSome() || widthEnd.isSome() + fun isObjectLengthNonZero() = lengthStart.isSome() || lengthEnd.isSome() + fun isObjectHeightNonZero() = heightStart != 0.0 || heightEnd != 0.0 + fun isObjectRadiusNonZero() = radiusStart.isSome() || radiusEnd.isSome() fun getRoadReferenceLineParameterSection() = Range.closed(s, s + length) fun getLateralOffsetFunction() = LinearFunction.ofInclusiveInterceptAndPoint(tStart, length, tEnd) + fun getHeightOffsetFunction() = LinearFunction.ofInclusiveInterceptAndPoint(zOffsetStart, length, zOffsetEnd) fun getObjectWidthFunction() = LinearFunction.ofInclusiveInterceptAndPoint(widthStart, length, widthEnd) - fun getObjectLengthFunction() = LinearFunction.ofInclusiveInterceptAndPoint(lengthStart, length, lengthEnd) - fun getObjectHeightFunction() = LinearFunction.ofInclusiveInterceptAndPoint(heightStart, length, heightEnd) - fun getObjectRadiusFunction() = LinearFunction.ofInclusiveInterceptAndPoint(radiusStart, length, radiusEnd) - - fun containsParametricSweep() = isContinuous() && - isLengthNonZero() && - isObjectWidthNonZero() && isObjectHeightNonZero() - - fun containsCurve() = isContinuous() && - isLengthNonZero() && - isObjectWidthZero() && isObjectHeightZero() - fun containsHorizontalParametricBoundedSurface() = isContinuous() && - isLengthNonZero() && - isObjectWidthNonZero() && isObjectHeightZero() - - fun containsVerticalParametricBoundedSurface() = isContinuous() && - isLengthNonZero() && - isObjectWidthZero() && isObjectHeightNonZero() - - fun containsRepeatedCuboid() = isDiscrete() && - isLengthNonZero() && - isObjectHeightNonZero() && isObjectLengthNonZero() && isObjectWidthNonZero() + fun getObjectLengthFunction() = LinearFunction.ofInclusiveInterceptAndPoint(lengthStart, length, lengthEnd) - fun containsRepeatedRectangle() = isDiscrete() && - isLengthNonZero() && - isObjectHeightZero() && isObjectLengthNonZero() && isObjectWidthNonZero() + fun getObjectHeightFunction() = LinearFunction.ofInclusiveInterceptAndPoint(heightStart, length, heightEnd) - fun containsRepeatCylinder() = isDiscrete() && - isLengthNonZero() && - isObjectHeightNonZero() && isObjectRadiusNonZero() + fun getObjectRadiusFunction() = LinearFunction.ofInclusiveInterceptAndPoint(radiusStart, length, radiusEnd) - fun containsRepeatCircle() = isDiscrete() && - isLengthNonZero() && - isObjectHeightNonZero() && isObjectRadiusNonZero() + fun containsParametricSweep() = + isContinuous() && + isLengthNonZero() && + isObjectWidthNonZero() && isObjectHeightNonZero() + + fun containsCurve() = + isContinuous() && + isLengthNonZero() && + isObjectWidthZero() && isObjectHeightZero() + + fun containsHorizontalParametricBoundedSurface() = + isContinuous() && + isLengthNonZero() && + isObjectWidthNonZero() && isObjectHeightZero() + + fun containsVerticalParametricBoundedSurface() = + isContinuous() && + isLengthNonZero() && + isObjectWidthZero() && isObjectHeightNonZero() + + fun containsRepeatedCuboid() = + isDiscrete() && + isLengthNonZero() && + isObjectHeightNonZero() && isObjectLengthNonZero() && isObjectWidthNonZero() + + fun containsRepeatedRectangle() = + isDiscrete() && + isLengthNonZero() && + isObjectHeightZero() && isObjectLengthNonZero() && isObjectWidthNonZero() + + fun containsRepeatCylinder() = + isDiscrete() && + isLengthNonZero() && + isObjectHeightNonZero() && isObjectRadiusNonZero() + + fun containsRepeatCircle() = + isDiscrete() && + isLengthNonZero() && + isObjectHeightNonZero() && isObjectRadiusNonZero() companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectSurface.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectSurface.kt index 883ac9cf..86b1deb8 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectSurface.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectSurface.kt @@ -21,5 +21,5 @@ import arrow.core.Option import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectSurface( - var crg: Option = None + var crg: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectSurfaceCrg.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectSurfaceCrg.kt index 963aedb6..51a1a610 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectSurfaceCrg.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsObjectSurfaceCrg.kt @@ -23,5 +23,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsObjectSurfaceCrg( var file: Option = None, var hideRoadSurfaceCrg: Option = None, - var zScale: Option = None + var zScale: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsTunnel.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsTunnel.kt index 225bba44..5c4cc293 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsTunnel.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/objects/RoadObjectsTunnel.kt @@ -22,12 +22,11 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadObjectsTunnel( var validity: List = emptyList(), - var daylight: Option = None, var id: String = "", var length: Double = Double.NaN, var lighting: Option = None, var name: Option = None, var s: Double = Double.NaN, - var type: ETunnelType = ETunnelType.STANDARD + var type: ETunnelType = ETunnelType.STANDARD, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/railroad/RoadRailroad.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/railroad/RoadRailroad.kt index cfcf692c..c1fe1f85 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/railroad/RoadRailroad.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/railroad/RoadRailroad.kt @@ -18,5 +18,5 @@ package io.rtron.model.opendrive.railroad data class RoadRailroad( // TODO - var todo: String = "todo" + var todo: String = "todo", ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/Enumerations.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/Enumerations.kt index f8dcffa1..a62236df 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/Enumerations.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/Enumerations.kt @@ -25,8 +25,19 @@ enum class ParamPoly3PRange { ARC_LENGTH, NORMALIZED } enum class ERoadLinkElementType { ROAD, JUNCTION } enum class ERoadType { - UNKNOWN, RURAL, MOTORWAY, TOWN, LOW_SPEED, PEDESTRIAN, BICYCLE, TOWN_EXPRESSWAY, TOWN_COLLECTOR, - TOWN_ARTERIAL, TOWN_PRIVATE, TOWN_LOCAL, TOWN_PLAY_STREET + UNKNOWN, + RURAL, + MOTORWAY, + TOWN, + LOW_SPEED, + PEDESTRIAN, + BICYCLE, + TOWN_EXPRESSWAY, + TOWN_COLLECTOR, + TOWN_ARTERIAL, + TOWN_PRIVATE, + TOWN_LOCAL, + TOWN_PLAY_STREET, } enum class ETrafficRule { RIGHT_HAND_TRAFFIC, LEFT_HAND_TRAFFIC } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/Road.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/Road.kt index 9d59587a..f88f9c34 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/Road.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/Road.kt @@ -47,23 +47,24 @@ data class Road( var signals: Option = None, var surface: Option = None, var railroad: Option = None, - var id: String = "", var junction: String = "", var length: Double = Double.NaN, var name: Option = None, var rule: Option = None, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalRoadIdentifier { - // Methods - fun getJunctionOption(): Option = - if (junction.isNotEmpty() && junction != "-1") Some(junction) else None + fun getJunctionOption(): Option = if (junction.isNotEmpty() && junction != "-1") Some(junction) else None fun getElevationEntries(): Option> = elevationProfile.map { it.elevationAsNonEmptyList } - fun getSuperelevationEntries(): Option> = lateralProfile.flatMap { it.getSuperelevationEntries() } + + fun getSuperelevationEntries(): Option> = + lateralProfile.flatMap { + it.getSuperelevationEntries() + } + fun getShapeEntries(): Option> = lateralProfile.flatMap { it.getShapeEntries() } companion object diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadLink.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadLink.kt index 5cebc067..71a388c1 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadLink.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadLink.kt @@ -22,7 +22,7 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadLink( var predecessor: Option = None, - var successor: Option = None + var successor: Option = None, ) : OpendriveElement() { companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadLinkPredecessorSuccessor.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadLinkPredecessorSuccessor.kt index d9a9eea8..3c98d06b 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadLinkPredecessorSuccessor.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadLinkPredecessorSuccessor.kt @@ -28,9 +28,8 @@ data class RoadLinkPredecessorSuccessor( var elementDir: Option = None, var elementId: String = "", var elementS: Option = None, - var elementType: Option = None + var elementType: Option = None, ) : OpendriveElement() { - // Methods fun getRoadPredecessorSuccessor(): Option> = diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadSurface.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadSurface.kt index 78e29080..1421bac8 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadSurface.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadSurface.kt @@ -19,5 +19,5 @@ package io.rtron.model.opendrive.road import io.rtron.model.opendrive.core.OpendriveElement data class RoadSurface( - var crg: List = emptyList() + var crg: List = emptyList(), ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadSurfaceCrg.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadSurfaceCrg.kt index 5bc863e1..b0225698 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadSurfaceCrg.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadSurfaceCrg.kt @@ -33,5 +33,5 @@ data class RoadSurfaceCrg( var sStart: Double = Double.NaN, var tOffset: Option = None, var zOffset: Option = None, - var zScale: Option = None + var zScale: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadType.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadType.kt index eba779f9..98d8707f 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadType.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadType.kt @@ -23,8 +23,7 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadType( var speed: Option = None, - var country: Option = None, var s: Double = Double.NaN, - var type: ERoadType = ERoadType.UNKNOWN + var type: ERoadType = ERoadType.UNKNOWN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadTypeSpeed.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadTypeSpeed.kt index a80fd8ac..6659778f 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadTypeSpeed.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/RoadTypeSpeed.kt @@ -23,5 +23,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadTypeSpeed( var max: Double = Double.NaN, - var unit: Option = None + var unit: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/elevation/RoadElevationProfile.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/elevation/RoadElevationProfile.kt index b512f99a..01444cdb 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/elevation/RoadElevationProfile.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/elevation/RoadElevationProfile.kt @@ -23,9 +23,8 @@ import io.rtron.model.opendrive.core.OpendriveElement @optics data class RoadElevationProfile( - var elevation: List = emptyList() + var elevation: List = emptyList(), ) : OpendriveElement() { - val elevationAsNonEmptyList: NonEmptyList get() = elevation.toNonEmptyListOrNull()!! diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/elevation/RoadElevationProfileElevation.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/elevation/RoadElevationProfileElevation.kt index ad00e749..2a0db62c 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/elevation/RoadElevationProfileElevation.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/elevation/RoadElevationProfileElevation.kt @@ -25,8 +25,7 @@ data class RoadElevationProfileElevation( var b: Double = Double.NaN, var c: Double = Double.NaN, var d: Double = Double.NaN, - - var s: Double = Double.NaN + var s: Double = Double.NaN, ) : OpendriveElement() { // Properties and Initializers val coefficients get() = doubleArrayOf(a, b, c, d) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfile.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfile.kt index 3b618270..f38fdfe7 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfile.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfile.kt @@ -23,13 +23,14 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadLateralProfile( var superelevation: List = emptyList(), - var shape: List = emptyList() + var shape: List = emptyList(), ) : OpendriveElement() { - // Methods fun getSuperelevationEntries(): Option> = superelevation.toNonEmptyListOrNone() + fun getShapeEntries(): Option> = shape.toNonEmptyListOrNone() fun containsSuperelevationProfile() = superelevation.isNotEmpty() + fun containsShapeProfile() = shape.isNotEmpty() } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfileShape.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfileShape.kt index 6ae44599..1c7f0e03 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfileShape.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfileShape.kt @@ -24,7 +24,7 @@ data class RoadLateralProfileShape( var c: Double = Double.NaN, var d: Double = Double.NaN, var s: Double = Double.NaN, - var t: Double = Double.NaN + var t: Double = Double.NaN, ) : OpendriveElement() { // Properties and Initializers val coefficients get() = doubleArrayOf(a, b, c, d) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfileSuperelevation.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfileSuperelevation.kt index 8ff7b170..598bb6e8 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfileSuperelevation.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/lateral/RoadLateralProfileSuperelevation.kt @@ -23,7 +23,7 @@ data class RoadLateralProfileSuperelevation( var b: Double = Double.NaN, var c: Double = Double.NaN, var d: Double = Double.NaN, - var s: Double = Double.NaN + var s: Double = Double.NaN, ) : OpendriveElement() { // Properties and Initializers val coefficients get() = doubleArrayOf(a, b, c, d) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanView.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanView.kt index e5cbe56e..7aaf46f1 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanView.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanView.kt @@ -23,9 +23,8 @@ import io.rtron.model.opendrive.core.OpendriveElement @optics data class RoadPlanView( - var geometry: List = emptyList() + var geometry: List = emptyList(), ) : OpendriveElement() { - val geometryAsNonEmptyList: NonEmptyList get() = geometry.toNonEmptyListOrNull()!! diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometry.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometry.kt index 883bb74f..17766ffa 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometry.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometry.kt @@ -28,13 +28,11 @@ data class RoadPlanViewGeometry( var arc: Option = None, var poly3: Option = None, var paramPoly3: Option = None, - var hdg: Double = Double.NaN, var length: Double = Double.NaN, var s: Double = Double.NaN, var x: Double = Double.NaN, - var y: Double = Double.NaN + var y: Double = Double.NaN, ) : OpendriveElement() { - companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryArc.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryArc.kt index 72db4e6d..b22bd871 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryArc.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryArc.kt @@ -19,5 +19,5 @@ package io.rtron.model.opendrive.road.planview import io.rtron.model.opendrive.core.OpendriveElement data class RoadPlanViewGeometryArc( - var curvature: Double = Double.NaN + var curvature: Double = Double.NaN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryParamPoly3.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryParamPoly3.kt index 5be45dee..268c6f79 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryParamPoly3.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryParamPoly3.kt @@ -28,10 +28,8 @@ data class RoadPlanViewGeometryParamPoly3( var cV: Double = Double.NaN, var dU: Double = Double.NaN, var dV: Double = Double.NaN, - - var pRange: ParamPoly3PRange = ParamPoly3PRange.ARC_LENGTH + var pRange: ParamPoly3PRange = ParamPoly3PRange.ARC_LENGTH, ) : OpendriveElement() { - // Properties and Initializers val coefficientsU get() = doubleArrayOf(aU, bU, cU, dU) val coefficientsV get() = doubleArrayOf(aV, bV, cV, dV) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryPoly3.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryPoly3.kt index 5140a675..205c71a4 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryPoly3.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometryPoly3.kt @@ -22,9 +22,8 @@ data class RoadPlanViewGeometryPoly3( var a: Double = Double.NaN, var b: Double = Double.NaN, var c: Double = Double.NaN, - var d: Double = Double.NaN + var d: Double = Double.NaN, ) : OpendriveElement() { - // Properties and Initializers val coefficients get() = doubleArrayOf(a, b, c, d) } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometrySpiral.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometrySpiral.kt index 243e4b46..9619c32f 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometrySpiral.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/road/planview/RoadPlanViewGeometrySpiral.kt @@ -20,5 +20,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadPlanViewGeometrySpiral( var curvEnd: Double = Double.NaN, - var curvStart: Double = Double.NaN + var curvStart: Double = Double.NaN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/Controller.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/Controller.kt index 7ac073d5..b116bcb9 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/Controller.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/Controller.kt @@ -22,8 +22,7 @@ import io.rtron.model.opendrive.core.OpendriveElement data class Controller( var control: List = emptyList(), - var id: String = "", var name: Option = None, - var sequence: Option = None + var sequence: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/ControllerControl.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/ControllerControl.kt index 64bb7f01..312a0872 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/ControllerControl.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/ControllerControl.kt @@ -22,5 +22,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class ControllerControl( var signalId: String = "", - var type: Option = None + var type: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/ERoadSignalsSignalReferenceElementType.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/ERoadSignalsSignalReferenceElementType.kt index 14c459c2..420e48ae 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/ERoadSignalsSignalReferenceElementType.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/ERoadSignalsSignalReferenceElementType.kt @@ -18,5 +18,5 @@ package io.rtron.model.opendrive.signal enum class ERoadSignalsSignalReferenceElementType { OBJECT, - SIGNAL + SIGNAL, } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignals.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignals.kt index 02fa9c0b..a47946b3 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignals.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignals.kt @@ -22,8 +22,7 @@ import io.rtron.model.opendrive.core.OpendriveElement @optics data class RoadSignals( var signal: List = emptyList(), - var signalReference: List = emptyList() + var signalReference: List = emptyList(), ) : OpendriveElement() { - companion object } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignal.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignal.kt index 13509d80..84da24bc 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignal.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignal.kt @@ -38,10 +38,8 @@ data class RoadSignalsSignal( var validity: List = emptyList(), var dependency: List = emptyList(), var reference: List = emptyList(), - var positionInertial: Option = None, var positionRoad: Option = None, - var country: Option = None, var countryRevision: Option = None, var dynamic: Boolean = false, @@ -61,8 +59,7 @@ data class RoadSignalsSignal( var value: Option = None, var width: Option = None, var zOffset: Double = Double.NaN, - - override var additionalId: Option = None + override var additionalId: Option = None, ) : OpendriveElement(), AdditionalRoadSignalIdentifier { // Properties and Initializers val curveRelativePosition get() = CurveRelativeVector3D(s, t, zOffset) @@ -79,7 +76,9 @@ data class RoadSignalsSignal( // Methods fun containsRectangle() = width.isSome() && height.isSome() + fun containsVerticalLine() = width.isNone() && height.isSome() + fun containsHorizontalLine() = width.isSome() && height.isNone() companion object diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalDependency.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalDependency.kt index 347ab688..8f1a3475 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalDependency.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalDependency.kt @@ -22,5 +22,5 @@ import io.rtron.model.opendrive.core.OpendriveElement data class RoadSignalsSignalDependency( var id: String = "", - var type: Option = None + var type: Option = None, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalPositionInertial.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalPositionInertial.kt index 0198ed29..da29e4d3 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalPositionInertial.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalPositionInertial.kt @@ -26,5 +26,5 @@ data class RoadSignalsSignalPositionInertial( var roll: Option = None, var x: Double = Double.NaN, var y: Double = Double.NaN, - var z: Double = Double.NaN + var z: Double = Double.NaN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalPositionRoad.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalPositionRoad.kt index a56cd9e4..a2fd000c 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalPositionRoad.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalPositionRoad.kt @@ -27,5 +27,5 @@ data class RoadSignalsSignalPositionRoad( var roll: Option = None, var s: Double = Double.NaN, var t: Double = Double.NaN, - var zOffset: Double = Double.NaN + var zOffset: Double = Double.NaN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalReference.kt b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalReference.kt index 5b673f2e..24019399 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalReference.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/opendrive/signal/RoadSignalsSignalReference.kt @@ -27,7 +27,6 @@ data class RoadSignalsSignalReference( var elementId: String = "", var elementType: ERoadSignalsSignalReferenceElementType = ERoadSignalsSignalReferenceElementType.SIGNAL, var type: Option = None, - var s: Double = Double.NaN, - var t: Double = Double.NaN + var t: Double = Double.NaN, ) : OpendriveElement() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/Header.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/Header.kt index 47e0e380..12a6c375 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/Header.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/Header.kt @@ -24,13 +24,11 @@ import io.rtron.math.projection.CoordinateReferenceSystem */ data class Header( val coordinateReferenceSystem: Option, - val name: Option, val date: Option, val vendor: Option, - val north: Double = Double.NaN, val south: Double = Double.NaN, val east: Double = Double.NaN, - val west: Double = Double.NaN + val west: Double = Double.NaN, ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/RoadspacesModel.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/RoadspacesModel.kt index fc54d5c6..ea7902ff 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/RoadspacesModel.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/RoadspacesModel.kt @@ -54,12 +54,13 @@ import io.rtron.std.handleEmpty class RoadspacesModel( val header: Header, roadspaces: List, - junctions: List + junctions: List, ) : AbstractModel() { - // Properties and Initializers init { - require(roadspaces.distinctBy { it.id }.size == roadspaces.size) { "Each roadspace identifier must not be assigned more than once." } + require( + roadspaces.distinctBy { it.id }.size == roadspaces.size, + ) { "Each roadspace identifier must not be assigned more than once." } require(junctions.distinctBy { it.id }.size == junctions.size) { "Each junction identifier must not be assigned more than once." } } @@ -77,20 +78,28 @@ class RoadspacesModel( init { val linkedRoadspacesByRoads = roadspaces.flatMap { it.road.linkage.getAllUsedRoadspaceIds() }.distinct() - require(roadspaceIdentifiers.containsAll(linkedRoadspacesByRoads)) { "All roadspaces that are linked to from other roadspaces must exist." } + require( + roadspaceIdentifiers.containsAll(linkedRoadspacesByRoads), + ) { "All roadspaces that are linked to from other roadspaces must exist." } val linkedJunctionsByRoads = roadspaces.flatMap { it.road.linkage.getAllUsedJunctionIds() }.distinct() - require(junctionIdentifiers.containsAll(linkedJunctionsByRoads)) { "All junctions that are linked to from other roadspaces must exist." } + require( + junctionIdentifiers.containsAll(linkedJunctionsByRoads), + ) { "All junctions that are linked to from other roadspaces must exist." } require(linkedJunctionsByRoads.size == numberOfJunctions) { "All junctions must be referenced by at least one roadspace." } } // Methods /** Returns the [Roadspace] with specific [roadspaceIdentifier]. */ - fun getRoadspace(roadspaceIdentifier: RoadspaceIdentifier): Either = roadspaces.getValueEither(roadspaceIdentifier).mapLeft { it.toIllegalArgumentException() } + fun getRoadspace(roadspaceIdentifier: RoadspaceIdentifier): Either = + roadspaces.getValueEither( + roadspaceIdentifier, + ).mapLeft { it.toIllegalArgumentException() } /** Returns the [Junction] with specific [junctionIdentifier]. */ - fun getJunction(junctionIdentifier: JunctionIdentifier): Either = junctions.getValueEither(junctionIdentifier).mapLeft { it.toIllegalArgumentException() } + fun getJunction(junctionIdentifier: JunctionIdentifier): Either = + junctions.getValueEither(junctionIdentifier).mapLeft { it.toIllegalArgumentException() } /** Returns a sorted list of all raodspace names. */ fun getAllRoadspaceNames(): List = getAllRoadspaces().map { it.name }.distinct().sorted() @@ -127,11 +136,12 @@ class RoadspacesModel( .distinct() /** Returns a list of [Roadspace]s that belong to the junction with [junctionIdentifier]. */ - fun getRoadspacesWithinJunction(junctionIdentifier: JunctionIdentifier): Either> = either { - val junction = getJunction(junctionIdentifier).bind() - val connectingRoadspaces = junction.getConnectingRoadspaceIds().map { getRoadspace(it).bind() } - connectingRoadspaces - } + fun getRoadspacesWithinJunction(junctionIdentifier: JunctionIdentifier): Either> = + either { + val junction = getJunction(junctionIdentifier).bind() + val connectingRoadspaces = junction.getConnectingRoadspaceIds().map { getRoadspace(it).bind() } + connectingRoadspaces + } /** * Returns an identifier list of lanes that precede this lane. @@ -139,8 +149,9 @@ class RoadspacesModel( * @param laneId lane identifier for which the predecessor lanes shall be found */ fun getPredecessorLaneIdentifiers(laneId: LaneIdentifier): Either> { - val road = roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) - .getOrElse { throw it.toIllegalArgumentException() }.road + val road = + roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) + .getOrElse { throw it.toIllegalArgumentException() }.road return when { road.isInFirstLaneSection(laneId) && road.linkage.predecessorRoadspaceContactPointId.isSome() -> @@ -158,8 +169,9 @@ class RoadspacesModel( * @param laneId lane identifier for which the successor lanes shall be found */ fun getSuccessorLaneIdentifiers(laneId: LaneIdentifier): Either> { - val road = roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) - .getOrElse { throw it.toIllegalArgumentException() }.road + val road = + roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) + .getOrElse { throw it.toIllegalArgumentException() }.road return when { road.isInLastLaneSection(laneId) && road.linkage.successorRoadspaceContactPointId.isSome() -> @@ -171,12 +183,13 @@ class RoadspacesModel( } } - fun getLongitudinalFillerSurfaces(laneId: LaneIdentifier): Either> = either { - val successorLaneIds = getSuccessorLaneIdentifiers(laneId).bind() + fun getLongitudinalFillerSurfaces(laneId: LaneIdentifier): Either> = + either { + val successorLaneIds = getSuccessorLaneIdentifiers(laneId).bind() - val fillerSurfaces = successorLaneIds.map { getLongitudinalFillerSurface(laneId, it) }.flattenOption() - fillerSurfaces - } + val fillerSurfaces = successorLaneIds.map { getLongitudinalFillerSurface(laneId, it) }.flattenOption() + fillerSurfaces + } /** * Returns the filler surface which is located between the lane of [laneId] and [successorLaneId]. @@ -184,21 +197,26 @@ class RoadspacesModel( * @param laneId identifier of the first lane * @param successorLaneId identifier of the second lane */ - private fun getLongitudinalFillerSurface(laneId: LaneIdentifier, successorLaneId: LaneIdentifier): - Option { - val road = roadspaces - .getValueEither(laneId.laneSectionIdentifier.roadspaceIdentifier) - .getOrElse { throw it.toIllegalArgumentException() }.road - val successorRoad = roadspaces - .getValueEither(successorLaneId.laneSectionIdentifier.roadspaceIdentifier) - .getOrElse { throw it.toIllegalArgumentException() }.road + private fun getLongitudinalFillerSurface( + laneId: LaneIdentifier, + successorLaneId: LaneIdentifier, + ): Option { + val road = + roadspaces + .getValueEither(laneId.laneSectionIdentifier.roadspaceIdentifier) + .getOrElse { throw it.toIllegalArgumentException() }.road + val successorRoad = + roadspaces + .getValueEither(successorLaneId.laneSectionIdentifier.roadspaceIdentifier) + .getOrElse { throw it.toIllegalArgumentException() }.road val surface = buildLongitudinalFillerSurfaceGeometry(laneId, successorLaneId, road, successorRoad).handleEmpty { return None } val longitudinalFillerSurfaceId = LongitudinalLaneRangeIdentifier(laneId, successorLaneId) - val fillerSurface = when { - laneId.isWithinSameRoad(successorLaneId) -> LongitudinalFillerSurface.ofWithinRoad(longitudinalFillerSurfaceId, surface) - else -> LongitudinalFillerSurface.ofBetweenRoad(longitudinalFillerSurfaceId, surface) - } + val fillerSurface = + when { + laneId.isWithinSameRoad(successorLaneId) -> LongitudinalFillerSurface.ofWithinRoad(longitudinalFillerSurfaceId, surface) + else -> LongitudinalFillerSurface.ofBetweenRoad(longitudinalFillerSurfaceId, surface) + } return Some(fillerSurface) } @@ -214,12 +232,15 @@ class RoadspacesModel( laneId: LaneIdentifier, successorLaneId: LaneIdentifier, road: Road, - successorRoad: Road - ): - Option { - val currentVertices = listOf(road.getLeftLaneBoundary(laneId), road.getRightLaneBoundary(laneId)) - .map { currentCurve -> currentCurve.getOrElse { throw it } } - .map { currentCurve -> currentCurve.calculateEndPointGlobalCS().mapLeft { it.toIllegalStateException() }.getOrElse { throw it } } + successorRoad: Road, + ): Option { + val currentVertices = + listOf(road.getLeftLaneBoundary(laneId), road.getRightLaneBoundary(laneId)) + .map { currentCurve -> currentCurve.getOrElse { throw it } } + .map { + currentCurve -> + currentCurve.calculateEndPointGlobalCS().mapLeft { it.toIllegalStateException() }.getOrElse { throw it } + } // false, if the successor lane is connected by its end (leads to swapping of the vertices) val successorContactStart = @@ -234,15 +255,26 @@ class RoadspacesModel( listOf(successorRoad.getRightLaneBoundary(successorLaneId), successorRoad.getLeftLaneBoundary(successorLaneId)) .map { it.getOrElse { return None } } - val successorVertices = when (successorContactStart) { - true -> successorLaneBoundaries.map { it.calculateStartPointGlobalCS().mapLeft { it.toIllegalStateException() }.getOrElse { throw it } } - false -> successorLaneBoundaries.map { it.calculateEndPointGlobalCS().mapLeft { it.toIllegalStateException() }.getOrElse { throw it } }.reversed() - } + val successorVertices = + when (successorContactStart) { + true -> + successorLaneBoundaries + .map { + it.calculateStartPointGlobalCS() + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } + } + false -> + successorLaneBoundaries.map { + it.calculateEndPointGlobalCS().mapLeft { it.toIllegalStateException() }.getOrElse { throw it } + }.reversed() + } val tolerance = minOf(road.surface.tolerance, successorRoad.surface.tolerance) - val fillerSurfaceVertices = (currentVertices + successorVertices) - .filterWithNextEnclosing { a, b -> a.fuzzyUnequals(b, tolerance) } - .removeRedundantVerticesOnLineSegmentsEnclosing(tolerance) + val fillerSurfaceVertices = + (currentVertices + successorVertices) + .filterWithNextEnclosing { a, b -> a.fuzzyUnequals(b, tolerance) } + .removeRedundantVerticesOnLineSegmentsEnclosing(tolerance) return if (fillerSurfaceVertices.size < 3 || fillerSurfaceVertices.isColinear(tolerance)) { None @@ -256,10 +288,10 @@ class RoadspacesModel( * * @param laneId lane identifier, which must not be located within the last section of the road */ - private fun getPredecessorLanesWithinRoad(laneId: LaneIdentifier): - Either> { - val road = roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) - .getOrElse { throw it.toIllegalArgumentException() }.road + private fun getPredecessorLanesWithinRoad(laneId: LaneIdentifier): Either> { + val road = + roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) + .getOrElse { throw it.toIllegalArgumentException() }.road check(!road.isInFirstLaneSection(laneId)) { "Current lane must not be located in the first lane section of the road." } return road.getLane(laneId) @@ -274,10 +306,10 @@ class RoadspacesModel( * * @param laneId lane identifier, which must not be located within the last section of the road */ - private fun getSuccessorLanesWithinRoad(laneId: LaneIdentifier): - Either> { - val road = roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) - .getOrElse { throw it.toIllegalArgumentException() }.road + private fun getSuccessorLanesWithinRoad(laneId: LaneIdentifier): Either> { + val road = + roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) + .getOrElse { throw it.toIllegalArgumentException() }.road check(!road.isInLastLaneSection(laneId)) { "Current lane must not be located in the last lane section of the road." } return road.getLane(laneId) @@ -293,16 +325,18 @@ class RoadspacesModel( * @param laneId lane identifier, which must be located at the first lane section on a road which follows another * road */ - private fun getPredecessorLanesBetweenRoads(laneId: LaneIdentifier): - Either> { - val road = roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) - .getOrElse { throw it.toIllegalArgumentException() }.road - val roadPredecessorRoadspaceContactPoint = road.linkage - .predecessorRoadspaceContactPointId - .handleEmpty { throw IllegalArgumentException("Current road must have a predecessor road.") } - - val predecessorRoad = roadspaces.getValueEither(roadPredecessorRoadspaceContactPoint.roadspaceIdentifier) - .getOrElse { return Either.Right(emptyList()) }.road + private fun getPredecessorLanesBetweenRoads(laneId: LaneIdentifier): Either> { + val road = + roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) + .getOrElse { throw it.toIllegalArgumentException() }.road + val roadPredecessorRoadspaceContactPoint = + road.linkage + .predecessorRoadspaceContactPointId + .handleEmpty { throw IllegalArgumentException("Current road must have a predecessor road.") } + + val predecessorRoad = + roadspaces.getValueEither(roadPredecessorRoadspaceContactPoint.roadspaceIdentifier) + .getOrElse { return Either.Right(emptyList()) }.road val predecessorLaneSectionIdentifier = predecessorRoad.getLaneSectionIdentifier(roadPredecessorRoadspaceContactPoint) return road.getLane(laneId) @@ -318,16 +352,18 @@ class RoadspacesModel( * @param laneId lane identifier, which must be located at the last lane section on a road which leads into * another road */ - private fun getSuccessorLanesBetweenRoads(laneId: LaneIdentifier): - Either> { - val road = roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) - .getOrElse { throw it.toIllegalArgumentException() }.road - val roadSuccessorRoadspaceContactPoint = road.linkage - .successorRoadspaceContactPointId - .handleEmpty { throw IllegalArgumentException("Current road must have a successor road.") } - - val successorRoad = roadspaces.getValueEither(roadSuccessorRoadspaceContactPoint.roadspaceIdentifier) - .getOrElse { return Either.Right(emptyList()) }.road + private fun getSuccessorLanesBetweenRoads(laneId: LaneIdentifier): Either> { + val road = + roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) + .getOrElse { throw it.toIllegalArgumentException() }.road + val roadSuccessorRoadspaceContactPoint = + road.linkage + .successorRoadspaceContactPointId + .handleEmpty { throw IllegalArgumentException("Current road must have a successor road.") } + + val successorRoad = + roadspaces.getValueEither(roadSuccessorRoadspaceContactPoint.roadspaceIdentifier) + .getOrElse { return Either.Right(emptyList()) }.road val successorLaneSectionIdentifier = successorRoad.getLaneSectionIdentifier(roadSuccessorRoadspaceContactPoint) return road.getLane(laneId) @@ -343,16 +379,20 @@ class RoadspacesModel( * @param laneId lane identifier, which must be located at the first lane section on a road which is followed into * a junction */ - private fun getPredecessorLanesBetweenRoadsInJunction(laneId: LaneIdentifier): - Either> { - val road = roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) - .getOrElse { throw it.toIllegalArgumentException() }.road + private fun getPredecessorLanesBetweenRoadsInJunction(laneId: LaneIdentifier): Either> { + val road = + roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) + .getOrElse { throw it.toIllegalArgumentException() }.road check(road.isInFirstLaneSection(laneId)) { "Current lane must be located in the last lane section of the road." } - val predecessorJunctionId = road.linkage.predecessorJunctionId.handleEmpty { throw IllegalStateException("Current road must have a predecessor junction.") } + val predecessorJunctionId = + road.linkage.predecessorJunctionId.handleEmpty { + throw IllegalStateException("Current road must have a predecessor junction.") + } - val predecessorJunction = junctions - .getValueEither(predecessorJunctionId) - .getOrElse { return Either.Right(emptyList()) } + val predecessorJunction = + junctions + .getValueEither(predecessorJunctionId) + .getOrElse { return Either.Right(emptyList()) } return predecessorJunction .getSuccessorLane(laneId) @@ -365,16 +405,20 @@ class RoadspacesModel( * @param laneId lane identifier, which must be located at the last lane section on a road which leads into * a junction */ - private fun getSuccessorLanesBetweenRoadsInJunction(laneId: LaneIdentifier): - Either> { - val road = roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) - .getOrElse { throw it.toIllegalArgumentException() }.road + private fun getSuccessorLanesBetweenRoadsInJunction(laneId: LaneIdentifier): Either> { + val road = + roadspaces.getValueEither(laneId.toRoadspaceIdentifier()) + .getOrElse { throw it.toIllegalArgumentException() }.road check(road.isInLastLaneSection(laneId)) { "Current lane must be located in the last lane section of the road." } - val successorJunctionId = road.linkage.successorJunctionId.handleEmpty { throw IllegalStateException("Current road must have a successor junction.") } + val successorJunctionId = + road.linkage.successorJunctionId.handleEmpty { + throw IllegalStateException("Current road must have a successor junction.") + } - val successorJunction = junctions - .getValueEither(successorJunctionId) - .getOrElse { return Either.Right(emptyList()) } + val successorJunction = + junctions + .getValueEither(successorJunctionId) + .getOrElse { return Either.Right(emptyList()) } return successorJunction .getSuccessorLane(laneId) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/common/LateralFillerSurface.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/common/LateralFillerSurface.kt index 04ba494d..9f29935a 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/common/LateralFillerSurface.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/common/LateralFillerSurface.kt @@ -21,7 +21,6 @@ import io.rtron.math.range.difference import io.rtron.model.roadspaces.identifier.LateralLaneRangeIdentifier data class LateralFillerSurface(val id: LateralLaneRangeIdentifier, val surface: AbstractSurface3D) { - // Properties and Initializers init { require(id.laneIdRange.difference == 1) { "Lane identifiers must be laterally adjacent." } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/common/LongitudinalFillerSurface.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/common/LongitudinalFillerSurface.kt index 714c97b8..75093728 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/common/LongitudinalFillerSurface.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/common/LongitudinalFillerSurface.kt @@ -24,16 +24,21 @@ import io.rtron.model.roadspaces.identifier.LongitudinalLaneRangeIdentifier */ data class LongitudinalFillerSurface( val id: LongitudinalLaneRangeIdentifier, - val surface: AbstractSurface3D + val surface: AbstractSurface3D, ) { - companion object { - fun ofWithinRoad(id: LongitudinalLaneRangeIdentifier, surface: AbstractSurface3D): LongitudinalFillerSurface { + fun ofWithinRoad( + id: LongitudinalLaneRangeIdentifier, + surface: AbstractSurface3D, + ): LongitudinalFillerSurface { require(id.isWithinSameRoad()) { "Lane identifiers must be located within the same road." } return LongitudinalFillerSurface(id, surface) } - fun ofBetweenRoad(id: LongitudinalLaneRangeIdentifier, surface: AbstractSurface3D): LongitudinalFillerSurface { + fun ofBetweenRoad( + id: LongitudinalLaneRangeIdentifier, + surface: AbstractSurface3D, + ): LongitudinalFillerSurface { require(!id.isWithinSameRoad()) { "Lane identifiers must not be located within the same road." } return LongitudinalFillerSurface(id, surface) } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/ConnectionIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/ConnectionIdentifier.kt index fe537f0b..0f6da286 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/ConnectionIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/ConnectionIdentifier.kt @@ -34,9 +34,8 @@ interface ConnectionIdentifierInterface { */ data class ConnectionIdentifier( override val connectionId: String, - val junctionIdentifier: JunctionIdentifier + val junctionIdentifier: JunctionIdentifier, ) : AbstractRoadspacesIdentifier(), ConnectionIdentifierInterface, JunctionIdentifierInterface by junctionIdentifier { - // Conversions val hashKey get() = "Connection_${connectionId}_${junctionIdentifier.junctionId}" @@ -47,8 +46,7 @@ data class ConnectionIdentifier( } + connectionIdentifier.junctionIdentifier.toAttributes(prefix) } - override fun toStringMap(): Map = - mapOf("connectionId" to connectionId) + junctionIdentifier.toStringMap() + override fun toStringMap(): Map = mapOf("connectionId" to connectionId) + junctionIdentifier.toStringMap() override fun toIdentifierText(): String { return "ConnectionIdentifier(connectionId=$connectionId, junctionId=$junctionId)" diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/JunctionIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/JunctionIdentifier.kt index d5fe94af..ddd0196f 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/JunctionIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/JunctionIdentifier.kt @@ -33,9 +33,8 @@ interface JunctionIdentifierInterface { * @param modelIdentifier identifier of the model */ data class JunctionIdentifier( - override val junctionId: String + override val junctionId: String, ) : AbstractRoadspacesIdentifier(), JunctionIdentifierInterface { - // Properties and Initializers val hashKey get() = "Junction_$junctionId" @@ -47,8 +46,7 @@ data class JunctionIdentifier( } } - override fun toStringMap(): Map = - mapOf("junctionId" to junctionId) + override fun toStringMap(): Map = mapOf("junctionId" to junctionId) override fun toIdentifierText(): String { return "JunctionIdentifier(junctionId=$junctionId)" diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LaneIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LaneIdentifier.kt index 0bc334cb..c4df1111 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LaneIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LaneIdentifier.kt @@ -29,21 +29,23 @@ import kotlin.math.abs */ data class LaneIdentifier( val laneId: Int, - val laneSectionIdentifier: LaneSectionIdentifier + val laneSectionIdentifier: LaneSectionIdentifier, ) : AbstractRoadspacesIdentifier(), LaneSectionIdentifierInterface by laneSectionIdentifier { - // Properties and Initializers val hashKey get() = "Lane_${laneId}_${laneSectionIdentifier.laneSectionId}_${laneSectionIdentifier.roadspaceIdentifier.roadspaceId}" // Methods - fun getRoadSide(): RoadSide = when { - laneId > 0 -> RoadSide.LEFT - laneId == 0 -> RoadSide.CENTER - else -> RoadSide.RIGHT - } + fun getRoadSide(): RoadSide = + when { + laneId > 0 -> RoadSide.LEFT + laneId == 0 -> RoadSide.CENTER + else -> RoadSide.RIGHT + } fun isLeft() = laneId > 0 + fun isCenter() = laneId == 0 + fun isRight() = laneId < 0 /** Returns true, if lane id is in the direction of the reference line. */ @@ -55,14 +57,12 @@ data class LaneIdentifier( /** Returns the [LaneIdentifier] of the lane which is located adjacently inner (towards the reference line) to the * lane of this identifier. */ - fun getAdjacentInnerLaneIdentifier(): LaneIdentifier = - LaneIdentifier(sign(laneId) * (abs(laneId) - 1), laneSectionIdentifier) + fun getAdjacentInnerLaneIdentifier(): LaneIdentifier = LaneIdentifier(sign(laneId) * (abs(laneId) - 1), laneSectionIdentifier) /** Returns the [LaneIdentifier] of the lane which is located adjacently outer (in the opposite direction of the * reference line) to the lane of this identifier. */ - fun getAdjacentOuterLaneIdentifier(): LaneIdentifier = - LaneIdentifier(sign(laneId) * (abs(laneId) + 1), laneSectionIdentifier) + fun getAdjacentOuterLaneIdentifier(): LaneIdentifier = LaneIdentifier(sign(laneId) * (abs(laneId) + 1), laneSectionIdentifier) /** Returns the identifier for the adjacent lane to the left. */ fun getAdjacentLeftLaneIdentifier(): LaneIdentifier = LaneIdentifier(laneId + 1, laneSectionIdentifier) @@ -85,15 +85,17 @@ data class LaneIdentifier( } + laneIdentifier.laneSectionIdentifier.toAttributes(prefix) } - override fun toStringMap(): Map = - mapOf("laneId" to laneId.toString()) + laneSectionIdentifier.toStringMap() + override fun toStringMap(): Map = mapOf("laneId" to laneId.toString()) + laneSectionIdentifier.toStringMap() override fun toIdentifierText() = "LaneIdentifier(laneId=$laneId, laneSectionId=$laneSectionId, roadId=$roadspaceId)" + fun toRoadspaceIdentifier() = laneSectionIdentifier.roadspaceIdentifier companion object { - - fun of(laneId: Int, laneSectionId: Int, roadspaceIdentifier: RoadspaceIdentifier) = - LaneIdentifier(laneId, LaneSectionIdentifier(laneSectionId, roadspaceIdentifier)) + fun of( + laneId: Int, + laneSectionId: Int, + roadspaceIdentifier: RoadspaceIdentifier, + ) = LaneIdentifier(laneId, LaneSectionIdentifier(laneSectionId, roadspaceIdentifier)) } } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LaneSectionIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LaneSectionIdentifier.kt index 84d7d43f..12103903 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LaneSectionIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LaneSectionIdentifier.kt @@ -34,9 +34,8 @@ interface LaneSectionIdentifierInterface : RoadspaceIdentifierInterface { */ data class LaneSectionIdentifier( override val laneSectionId: Int, - val roadspaceIdentifier: RoadspaceIdentifier + val roadspaceIdentifier: RoadspaceIdentifier, ) : AbstractRoadspacesIdentifier(), LaneSectionIdentifierInterface, RoadspaceIdentifierInterface by roadspaceIdentifier { - // Properties and Initializers init { require(laneSectionId >= 0) { "Lane section id must be non-negative." } @@ -45,12 +44,10 @@ data class LaneSectionIdentifier( // Methods /** Returns the identifier for the previous lane section. */ - fun getPreviousLaneSectionIdentifier() = - LaneSectionIdentifier(this.laneSectionId - 1, this.roadspaceIdentifier) + fun getPreviousLaneSectionIdentifier() = LaneSectionIdentifier(this.laneSectionId - 1, this.roadspaceIdentifier) /** Returns the identifier for the next lane section. */ - fun getNextLaneSectionIdentifier() = - LaneSectionIdentifier(this.laneSectionId + 1, this.roadspaceIdentifier) + fun getNextLaneSectionIdentifier() = LaneSectionIdentifier(this.laneSectionId + 1, this.roadspaceIdentifier) // Conversions override fun toAttributes(prefix: String): AttributeList { @@ -60,8 +57,7 @@ data class LaneSectionIdentifier( } + laneSectionIdentifier.roadspaceIdentifier.toAttributes(prefix) } - override fun toStringMap(): Map = - mapOf("laneSectionId" to laneSectionId.toString()) + roadspaceIdentifier.toStringMap() + override fun toStringMap(): Map = mapOf("laneSectionId" to laneSectionId.toString()) + roadspaceIdentifier.toStringMap() override fun toIdentifierText(): String { return "LaneSectionIdentifier(laneSectionId=$laneSectionId, roadSpaceId=$roadspaceId)" diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LateralLaneRangeIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LateralLaneRangeIdentifier.kt index c8126432..5f916d63 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LateralLaneRangeIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LateralLaneRangeIdentifier.kt @@ -30,7 +30,7 @@ import kotlin.math.min */ data class LateralLaneRangeIdentifier( val laneIdRange: Range, - val laneSectionIdentifier: LaneSectionIdentifier + val laneSectionIdentifier: LaneSectionIdentifier, ) : AbstractRoadspacesIdentifier(), LaneSectionIdentifierInterface by laneSectionIdentifier { // Properties and Initializers init { @@ -38,7 +38,10 @@ data class LateralLaneRangeIdentifier( require(laneIdRange.hasUpperBound()) { "laneIdRange must have a upper bound." } // require(laneIdRange.lowerEndpointOrNull()!! != laneIdRange.upperEndpointOrNull()!!) { "lowerEndpoint and upperEndpoint must be different ." } } - val hashKey get() = "LateralLaneRange_${laneIdRange.lowerEndpointOrNull()!!}_${laneIdRange.upperEndpointOrNull()!!}_${laneSectionIdentifier.laneSectionId}_${laneSectionIdentifier.roadspaceIdentifier.roadspaceId}" + + val hashKey get() = + "LateralLaneRange_${laneIdRange.lowerEndpointOrNull()!!}_${laneIdRange.upperEndpointOrNull()!!}_" + + "${laneSectionIdentifier.laneSectionId}_${laneSectionIdentifier.roadspaceIdentifier.roadspaceId}" val lowerLaneId get() = LaneIdentifier(laneIdRange.lowerEndpointOrNull()!!, laneSectionIdentifier) val upperLaneId get() = LaneIdentifier(laneIdRange.upperEndpointOrNull()!!, laneSectionIdentifier) @@ -46,10 +49,14 @@ data class LateralLaneRangeIdentifier( // Methods /** Returns all lane identifiers contained in this range. */ - fun getAllLeftRightLaneIdentifiers(): List = (laneIdRange.lowerEndpointOrNull()!!..laneIdRange.upperEndpointOrNull()!!).filter { it != 0 }.map { LaneIdentifier(it, this.laneSectionIdentifier) } + fun getAllLeftRightLaneIdentifiers(): List = + (laneIdRange.lowerEndpointOrNull()!!..laneIdRange.upperEndpointOrNull()!!).filter { + it != 0 + }.map { LaneIdentifier(it, this.laneSectionIdentifier) } /** Returns true, if the [laneIdentifier] is contained in this range. */ - fun contains(laneIdentifier: LaneIdentifier) = this.laneSectionIdentifier == laneIdentifier.laneSectionIdentifier && this.laneIdRange.contains(laneIdentifier.laneId) + fun contains(laneIdentifier: LaneIdentifier) = + this.laneSectionIdentifier == laneIdentifier.laneSectionIdentifier && this.laneIdRange.contains(laneIdentifier.laneId) // Conversions override fun toAttributes(prefix: String): AttributeList { @@ -61,13 +68,20 @@ data class LateralLaneRangeIdentifier( } override fun toStringMap(): Map = - mapOf("lowerLaneId" to laneIdRange.lowerEndpointOrNull()!!.toString(), "upperLaneId" to laneIdRange.upperEndpointOrNull()!!.toString()) + laneSectionIdentifier.toStringMap() + mapOf( + "lowerLaneId" to laneIdRange.lowerEndpointOrNull()!!.toString(), + "upperLaneId" to laneIdRange.upperEndpointOrNull()!!.toString(), + ) + laneSectionIdentifier.toStringMap() - override fun toIdentifierText() = "LateralLaneRangeIdentifier(lowerLaneId=${laneIdRange.lowerEndpointOrNull()!!}, upperLaneId=${laneIdRange.upperEndpointOrNull()!!}, laneSectionId=$laneSectionId, roadId=$roadspaceId)" + override fun toIdentifierText() = + "LateralLaneRangeIdentifier(lowerLaneId=${laneIdRange.lowerEndpointOrNull()!!}, " + + "upperLaneId=${laneIdRange.upperEndpointOrNull()!!}, laneSectionId=$laneSectionId, roadId=$roadspaceId)" companion object { - - fun of(fromLaneId: LaneIdentifier, toLaneId: LaneIdentifier): LateralLaneRangeIdentifier { + fun of( + fromLaneId: LaneIdentifier, + toLaneId: LaneIdentifier, + ): LateralLaneRangeIdentifier { require(fromLaneId.laneSectionIdentifier == toLaneId.laneSectionIdentifier) { "Must have the same laneSectionId" } val lowerLaneId = min(fromLaneId.laneId, toLaneId.laneId) val upperLaneId = max(fromLaneId.laneId, toLaneId.laneId) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LongitudinalLaneRangeIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LongitudinalLaneRangeIdentifier.kt index f1ff7297..4d920e75 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LongitudinalLaneRangeIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/LongitudinalLaneRangeIdentifier.kt @@ -26,13 +26,13 @@ import io.rtron.model.roadspaces.roadspace.attribute.AttributeList */ data class LongitudinalLaneRangeIdentifier( val fromLaneId: LaneIdentifier, - val toLaneId: LaneIdentifier + val toLaneId: LaneIdentifier, ) : AbstractRoadspacesIdentifier() { - // Properties and Initializers init { require(fromLaneId != toLaneId) { "Lane identifier and lane identifier of successor must not be the same." } } + val hashKey get() = "LongitudinalLaneRange_${fromLaneId.hashKey}_${toLaneId.hashKey}" // Methods @@ -41,11 +41,10 @@ data class LongitudinalLaneRangeIdentifier( fun isWithinSameRoad() = fromLaneId.toRoadspaceIdentifier() == toLaneId.toRoadspaceIdentifier() // Conversions - override fun toAttributes(prefix: String): AttributeList = - fromLaneId.toAttributes("from$prefix") + toLaneId.toAttributes("to$prefix") + override fun toAttributes(prefix: String): AttributeList = fromLaneId.toAttributes("from$prefix") + toLaneId.toAttributes("to$prefix") - override fun toStringMap(): Map = - fromLaneId.toStringMap() + toLaneId.toStringMap() + override fun toStringMap(): Map = fromLaneId.toStringMap() + toLaneId.toStringMap() - override fun toIdentifierText() = "LongitudinalLaneRangeIdentifier(fromLaneId=${fromLaneId.toIdentifierText()}, toLaneId=${toLaneId.toIdentifierText()})" + override fun toIdentifierText() = + "LongitudinalLaneRangeIdentifier(fromLaneId=${fromLaneId.toIdentifierText()}, toLaneId=${toLaneId.toIdentifierText()})" } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadSide.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadSide.kt index 6e13e900..f324bc72 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadSide.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadSide.kt @@ -19,11 +19,12 @@ package io.rtron.model.roadspaces.identifier enum class RoadSide { LEFT, CENTER, - RIGHT + RIGHT, } -fun RoadSide.opposite() = when (this) { - RoadSide.LEFT -> RoadSide.RIGHT - RoadSide.CENTER -> RoadSide.CENTER - RoadSide.RIGHT -> RoadSide.LEFT -} +fun RoadSide.opposite() = + when (this) { + RoadSide.LEFT -> RoadSide.RIGHT + RoadSide.CENTER -> RoadSide.CENTER + RoadSide.RIGHT -> RoadSide.LEFT + } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadspaceIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadspaceIdentifier.kt index 5cd1417e..23ace0bd 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadspaceIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadspaceIdentifier.kt @@ -34,9 +34,8 @@ interface RoadspaceIdentifierInterface { * @param modelIdentifier identifier of the model */ data class RoadspaceIdentifier( - override val roadspaceId: String + override val roadspaceId: String, ) : AbstractRoadspacesIdentifier(), RoadspaceIdentifierInterface { - // Properties and Initializers val hashKey get() = "Roadspace_$roadspaceId" @@ -48,8 +47,7 @@ data class RoadspaceIdentifier( } } - override fun toStringMap(): Map = - mapOf("roadspaceId" to roadspaceId) + override fun toStringMap(): Map = mapOf("roadspaceId" to roadspaceId) override fun toIdentifierText(): String { return "RoadspaceIdentifier(roadspaceId=$roadspaceId)" diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadspaceObjectIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadspaceObjectIdentifier.kt index c2aa9dc2..d86eb256 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadspaceObjectIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/identifier/RoadspaceObjectIdentifier.kt @@ -32,9 +32,8 @@ data class RoadspaceObjectIdentifier( val roadspaceObjectId: String, val roadspaceObjectRepeatIndex: Option, val roadspaceObjectName: Option, - val roadspaceIdentifier: RoadspaceIdentifier + val roadspaceIdentifier: RoadspaceIdentifier, ) : AbstractRoadspacesIdentifier(), RoadspaceIdentifierInterface by roadspaceIdentifier { - // Properties and Initializers val hashKey get() = "RoadspaceObject_${roadspaceObjectId}_${roadspaceObjectRepeatIndex}_${roadspaceIdentifier.roadspaceId}" @@ -52,8 +51,7 @@ data class RoadspaceObjectIdentifier( } + roadspaceObjectIdentifier.roadspaceIdentifier.toAttributes(prefix) } - override fun toStringMap(): Map = - mapOf("roadspaceObjectId" to roadspaceObjectId) + roadspaceIdentifier.toStringMap() + override fun toStringMap(): Map = mapOf("roadspaceObjectId" to roadspaceObjectId) + roadspaceIdentifier.toStringMap() // Conversions override fun toIdentifierText(): String { diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/junction/Connection.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/junction/Connection.kt index 0281d5c8..3ef5de48 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/junction/Connection.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/junction/Connection.kt @@ -35,9 +35,8 @@ data class Connection( val id: ConnectionIdentifier, val incomingRoadspaceContactPointId: RoadspaceContactPointIdentifier, val connectingRoadspaceContactPointId: RoadspaceContactPointIdentifier, - val laneLinks: Map + val laneLinks: Map, ) { - // Properties and Initializers init { require(laneLinks.isNotEmpty()) { "Lane links must not be empty." } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/junction/Junction.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/junction/Junction.kt index d3ad4341..5beda782 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/junction/Junction.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/junction/Junction.kt @@ -28,7 +28,7 @@ import io.rtron.model.roadspaces.identifier.LaneIdentifier */ data class Junction( val id: JunctionIdentifier, - val connections: List + val connections: List, ) { // Properties and Initializers init { @@ -37,9 +37,10 @@ data class Junction( // Methods - fun getConnectingRoadspaceIds() = connections - .map { it.connectingRoadspaceContactPointId.roadspaceIdentifier } - .distinct() + fun getConnectingRoadspaceIds() = + connections + .map { it.connectingRoadspaceContactPointId.roadspaceIdentifier } + .distinct() /*fun getConnection(incomingRoadspace: RoadspaceContactPointIdentifier): Option { connections.filter { it.incomingRoadspaceContactPointId == incomingRoadspace } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/Roadspace.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/Roadspace.kt index f9dd5f00..d80e1b0b 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/Roadspace.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/Roadspace.kt @@ -31,5 +31,5 @@ data class Roadspace( val referenceLine: Curve3D, val road: Road, val roadspaceObjects: List = emptyList(), - val attributes: AttributeList = AttributeList() + val attributes: AttributeList = AttributeList(), ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/RoadspaceContactPointIdentifier.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/RoadspaceContactPointIdentifier.kt index ff399f6c..e89a7669 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/RoadspaceContactPointIdentifier.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/RoadspaceContactPointIdentifier.kt @@ -21,7 +21,7 @@ import io.rtron.model.roadspaces.identifier.RoadspaceIdentifierInterface enum class ContactPoint(val relativeIndex: Int) { START(0), - END(-1) + END(-1), } /** @@ -32,9 +32,8 @@ enum class ContactPoint(val relativeIndex: Int) { */ data class RoadspaceContactPointIdentifier( val roadspaceContactPoint: ContactPoint, - val roadspaceIdentifier: RoadspaceIdentifier + val roadspaceIdentifier: RoadspaceIdentifier, ) : RoadspaceIdentifierInterface by roadspaceIdentifier { - // Conversions override fun toString(): String { return "RoadspaceObjectIdentifier(roadspaceContactPoint=$roadspaceContactPoint, roadspaceId=$roadspaceId)" diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/AttributeDSL.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/AttributeDSL.kt index 1c2e51ca..497c3a11 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/AttributeDSL.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/AttributeDSL.kt @@ -22,44 +22,65 @@ import arrow.core.Option * Environment for describing and building attribute lists. */ class AttributeListBuilder( - private var namePrefix: String = "" + private var namePrefix: String = "", ) { - private val attributes = mutableListOf() operator fun Attribute.unaryPlus() { attributes += this } - fun attribute(name: String, value: String) { + fun attribute( + name: String, + value: String, + ) { StringAttribute.of(namePrefix + name, value).onSome { attributes += it } } - fun attribute(name: String, value: Int) { + fun attribute( + name: String, + value: Int, + ) { attributes += IntAttribute(namePrefix + name, value) } - fun attribute(name: String, value: Double) { + fun attribute( + name: String, + value: Double, + ) { DoubleAttribute.of(namePrefix + name, value).onSome { attributes += it } } - fun attribute(name: String, value: Boolean) { + fun attribute( + name: String, + value: Boolean, + ) { attributes += BooleanAttribute(namePrefix + name, value) } - fun attribute(name: String, value: Double, unitOfMeasure: UnitOfMeasure) { + fun attribute( + name: String, + value: Double, + unitOfMeasure: UnitOfMeasure, + ) { MeasureAttribute.of(namePrefix + name, value, unitOfMeasure).onSome { attributes += it } } @JvmName("OptionalDoubleAttribute") - fun attribute(name: String, optionalValue: Option) { + fun attribute( + name: String, + optionalValue: Option, + ) { optionalValue.onSome { attributes += DoubleAttribute(namePrefix + name, it) } } @JvmName("OptionalStringAttribute") - fun attribute(name: String, optionalValue: Option) { + fun attribute( + name: String, + optionalValue: Option, + ) { optionalValue.onSome { if (it.isNotBlank()) { attributes += StringAttribute(namePrefix + name, it) @@ -70,13 +91,17 @@ class AttributeListBuilder( /** * Environment for building a nested attribute list within this attribute list. */ - fun attributes(name: String = "", setup: AttributeListBuilder.() -> Unit) { + fun attributes( + name: String = "", + setup: AttributeListBuilder.() -> Unit, + ) { val attributeListBuilder = AttributeListBuilder(namePrefix + name) attributeListBuilder.setup() attributes += attributeListBuilder.toAttributeList(namePrefix + name) } fun build() = AttributeList(attributes) + private fun toAttributeList(name: String) = AttributeList(attributes, name) } @@ -86,7 +111,10 @@ class AttributeListBuilder( * @param namePrefix each attribute's name is prefixed with this variable * @param setup DSL environment for describing attribute lists */ -fun attributes(namePrefix: String = "", setup: AttributeListBuilder.() -> Unit): AttributeList { +fun attributes( + namePrefix: String = "", + setup: AttributeListBuilder.() -> Unit, +): AttributeList { val attributeListBuilder = AttributeListBuilder(namePrefix) attributeListBuilder.setup() return attributeListBuilder.build() diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/Attributes.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/Attributes.kt index d18a6444..d5fe9554 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/Attributes.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/Attributes.kt @@ -30,14 +30,16 @@ sealed class Attribute(val name: String) * Attribute with a [name] containing a certain string [value]. */ class StringAttribute(name: String, val value: String) : Attribute(name) { - // Properties and Initializers init { require(value.isNotBlank()) { "String value must not be blank." } } companion object { - fun of(name: String, value: String): Option = + fun of( + name: String, + value: String, + ): Option = if (value.isEmpty()) { None } else { @@ -55,14 +57,16 @@ class IntAttribute(name: String, val value: Int) : Attribute(name) * Attribute with a [name] containing a certain double [value]. */ class DoubleAttribute(name: String, val value: Double) : Attribute(name) { - // Properties and Initializers init { require(value.isFinite()) { "Value must be finite." } } companion object { - fun of(name: String, value: Double): Option = + fun of( + name: String, + value: Double, + ): Option = if (!value.isFinite()) { None } else { @@ -82,14 +86,17 @@ class BooleanAttribute(name: String, val value: Boolean) : Attribute(name) * @param uom unit of measure of the value */ class MeasureAttribute(name: String, val value: Double, val uom: UnitOfMeasure) : Attribute(name) { - // Properties and Initializers init { require(value.isFinite()) { "Value must be finite." } } companion object { - fun of(name: String, value: Double, uom: UnitOfMeasure): Option = + fun of( + name: String, + value: Double, + uom: UnitOfMeasure, + ): Option = if (value.isNaN()) { None } else { @@ -104,7 +111,6 @@ class MeasureAttribute(name: String, val value: Double, val uom: UnitOfMeasure) * @param name name of the list */ class AttributeList(val attributes: List = emptyList(), name: String = "") : Attribute(name) { - // Operators operator fun plus(other: AttributeList): AttributeList { require(this.name == other.name) { "Merging of attribute lists requires the same name." } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/UnitOfMeasure.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/UnitOfMeasure.kt index b4e95ea7..be794d38 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/UnitOfMeasure.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/attribute/UnitOfMeasure.kt @@ -17,7 +17,11 @@ package io.rtron.model.roadspaces.roadspace.attribute enum class UnitOfMeasure { - METER, KILOMETER, - METER_PER_SECOND, MILES_PER_HOUR, KILOMETER_PER_HOUR, - NONE, UNKNOWN + METER, + KILOMETER, + METER_PER_SECOND, + MILES_PER_HOUR, + KILOMETER_PER_HOUR, + NONE, + UNKNOWN, } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/objects/RoadObjectType.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/objects/RoadObjectType.kt index 37b80337..57b48de1 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/objects/RoadObjectType.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/objects/RoadObjectType.kt @@ -33,5 +33,5 @@ enum class RoadObjectType { GANTRY, SOUND_BARRIER, ROAD_MARK, - SIGNAL + SIGNAL, } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/objects/RoadspaceObject.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/objects/RoadspaceObject.kt index 40abd633..16e69215 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/objects/RoadspaceObject.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/objects/RoadspaceObject.kt @@ -38,9 +38,8 @@ data class RoadspaceObject( val boundingBoxGeometry: Option, val complexGeometry: Option, val laneRelations: List, - val attributes: AttributeList + val attributes: AttributeList, ) { - // Properties and Initializers val name get() = id.roadspaceObjectName diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/Lane.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/Lane.kt index db063ce3..4d05d87c 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/Lane.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/Lane.kt @@ -47,9 +47,8 @@ data class Lane( val successors: List, val type: LaneType, val laneMaterial: Option, - val attributes: AttributeList + val attributes: AttributeList, ) { - // Properties and Initializers init { require(id.isLeft() || id.isRight()) { "Identifier must be either for a left or right lane." } @@ -62,14 +61,15 @@ data class Lane( } val laneChangeSet = roadMarkings.map { it.laneChange }.toSet() - val combinedLaneChange = when { - laneChangeSet.size == 1 -> laneChangeSet.first() - laneChangeSet.contains(LaneChange.BOTH) -> LaneChange.BOTH - laneChangeSet.contains(LaneChange.INCREASE) && laneChangeSet.contains(LaneChange.DECREASE) -> LaneChange.BOTH - laneChangeSet.contains(LaneChange.INCREASE) -> LaneChange.INCREASE - laneChangeSet.contains(LaneChange.DECREASE) -> LaneChange.DECREASE - else -> LaneChange.NONE - } + val combinedLaneChange = + when { + laneChangeSet.size == 1 -> laneChangeSet.first() + laneChangeSet.contains(LaneChange.BOTH) -> LaneChange.BOTH + laneChangeSet.contains(LaneChange.INCREASE) && laneChangeSet.contains(LaneChange.DECREASE) -> LaneChange.BOTH + laneChangeSet.contains(LaneChange.INCREASE) -> LaneChange.INCREASE + laneChangeSet.contains(LaneChange.DECREASE) -> LaneChange.DECREASE + else -> LaneChange.NONE + } return Some(combinedLaneChange) } } @@ -89,7 +89,7 @@ data class CenterLane( val roadMarkings: List = emptyList(), val type: LaneType = LaneType.NONE, val laneMaterial: Option, - val attributes: AttributeList = AttributeList.EMPTY + val attributes: AttributeList = AttributeList.EMPTY, ) { // Properties and Initializers init { diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneChange.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneChange.kt index 10f79e1e..b77a4a65 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneChange.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneChange.kt @@ -17,5 +17,8 @@ package io.rtron.model.roadspaces.roadspace.road enum class LaneChange { - BOTH, DECREASE, INCREASE, NONE + BOTH, + DECREASE, + INCREASE, + NONE, } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneMaterial.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneMaterial.kt index 0aa3387f..41d2a3bd 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneMaterial.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneMaterial.kt @@ -19,5 +19,5 @@ package io.rtron.model.roadspaces.roadspace.road data class LaneMaterial( var friction: Double = Double.NaN, var roughness: Double = Double.NaN, - var surface: String = "" + var surface: String = "", ) diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneSection.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneSection.kt index f3f75d01..e7e1d1fe 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneSection.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneSection.kt @@ -42,9 +42,8 @@ data class LaneSection( val id: LaneSectionIdentifier, val curvePositionDomain: Range, val lanes: Map, - val centerLane: CenterLane + val centerLane: CenterLane, ) { - // Properties and Initializers init { require(curvePositionDomain.hasLowerBound()) { "Curve position domain must have a lower bound." } @@ -52,9 +51,10 @@ data class LaneSection( require(lanes.isNotEmpty()) { "LaneSection must contain lanes." } require(lanes.all { it.key == it.value.id.laneId }) { "Lane elements must be positioned according to their lane id on the map." } - val expectedLaneIds = (lanes.keys.minOrNull()!!..lanes.keys.maxOrNull()!!) - .toMutableList() - .also { it.remove(0) } + val expectedLaneIds = + (lanes.keys.minOrNull()!!..lanes.keys.maxOrNull()!!) + .toMutableList() + .also { it.remove(0) } require(lanes.keys.containsAll(expectedLaneIds)) { "There must be no gaps within the given laneIds." } } @@ -66,12 +66,14 @@ data class LaneSection( id: LaneSectionIdentifier, curvePositionDomain: Range, lanes: List, - centerLane: CenterLane + centerLane: CenterLane, ) : this(id, curvePositionDomain, lanes.associateBy { it.id.laneId }, centerLane) // Methods - fun getLane(laneId: Int): Either = lanes.getValueEither(laneId).mapLeft { it.toIllegalArgumentException() } + fun getLane(laneId: Int): Either = + lanes.getValueEither(laneId).mapLeft { it.toIllegalArgumentException() } + fun getLane(laneIdentifier: LaneIdentifier): Either = lanes.getValueEither(laneIdentifier.laneId).mapLeft { it.toIllegalArgumentException() } @@ -88,21 +90,27 @@ data class LaneSection( * @param factor if the [factor] is 0.0 the inner lane boundary is returned. If the [factor] is 1.0 the outer lane * boundary is returned. An offset function within the middle of the lane is achieved by a [factor] of 0.5. */ - fun getLateralLaneOffset(laneId: Int, factor: Double): Either = either { - val selectedLanes = (1..abs(laneId)).toList() - .map { sign(laneId) * it } - .map { getLane(it).bind() } + fun getLateralLaneOffset( + laneId: Int, + factor: Double, + ): Either = + either { + val selectedLanes = + (1..abs(laneId)).toList() + .map { sign(laneId) * it } + .map { getLane(it).bind() } - val currentLane = selectedLanes.last() - val innerLaneBoundaryOffset = selectedLanes.dropLast(1) - .map { it.width } - .let { if (it.isEmpty()) LinearFunction.X_AXIS else StackedFunction.ofSum(it) } + val currentLane = selectedLanes.last() + val innerLaneBoundaryOffset = + selectedLanes.dropLast(1) + .map { it.width } + .let { if (it.isEmpty()) LinearFunction.X_AXIS else StackedFunction.ofSum(it) } - StackedFunction( - listOf(innerLaneBoundaryOffset, currentLane.width), - { sign(laneId) * (it[0] + factor * it[1]) } - ) - } + StackedFunction( + listOf(innerLaneBoundaryOffset, currentLane.width), + { sign(laneId) * (it[0] + factor * it[1]) }, + ) + } /** * Returns the height offset function located on lane with [laneIdentifier]. @@ -112,19 +120,20 @@ data class LaneSection( * is 1.0 the height offset of the outer lane boundary is returned. A height offset function within the middle * of the lane is achieved by a [factor] of 0.5. */ - fun getLaneHeightOffset(laneIdentifier: LaneIdentifier, factor: Double): - Either = either { - val inner = getInnerLaneHeightOffset(laneIdentifier).bind() - val outer = getOuterLaneHeightOffset(laneIdentifier).bind() - val laneHeightOffset = StackedFunction(listOf(inner, outer), { it[0] * (1.0 - factor) + it[1] * factor }) - laneHeightOffset - } + fun getLaneHeightOffset( + laneIdentifier: LaneIdentifier, + factor: Double, + ): Either = + either { + val inner = getInnerLaneHeightOffset(laneIdentifier).bind() + val outer = getOuterLaneHeightOffset(laneIdentifier).bind() + val laneHeightOffset = StackedFunction(listOf(inner, outer), { it[0] * (1.0 - factor) + it[1] * factor }) + laneHeightOffset + } - private fun getOuterLaneHeightOffset(laneIdentifier: LaneIdentifier): - Either = + private fun getOuterLaneHeightOffset(laneIdentifier: LaneIdentifier): Either = getLane(laneIdentifier).map { it.outerHeightOffset } - private fun getInnerLaneHeightOffset(laneIdentifier: LaneIdentifier): - Either = + private fun getInnerLaneHeightOffset(laneIdentifier: LaneIdentifier): Either = getLane(laneIdentifier).map { it.innerHeightOffset } } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneType.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneType.kt index a3e6652b..e829cb24 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneType.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/LaneType.kt @@ -17,7 +17,32 @@ package io.rtron.model.roadspaces.roadspace.road enum class LaneType { - NONE, DRIVING, STOP, SHOULDER, BIKING, SIDEWALK, BORDER, RESTRICTED, PARKING, CURB, BIDIRECTIONAL, - MEDIAN, SPECIAL_1, SPECIAL_2, SPECIAL_3, ROAD_WORKS, TRAM, RAIL, ENTRY, EXIT, OFF_RAMP, ON_RAMP, CONNECTING_RAMP, - BUS, TAXI, HOV, MWY_ENTRY, MWY_EXIT + NONE, + DRIVING, + STOP, + SHOULDER, + BIKING, + SIDEWALK, + BORDER, + RESTRICTED, + PARKING, + CURB, + BIDIRECTIONAL, + MEDIAN, + SPECIAL_1, + SPECIAL_2, + SPECIAL_3, + ROAD_WORKS, + TRAM, + RAIL, + ENTRY, + EXIT, + OFF_RAMP, + ON_RAMP, + CONNECTING_RAMP, + BUS, + TAXI, + HOV, + MWY_ENTRY, + MWY_EXIT, } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/Road.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/Road.kt index 50cab550..398bb77a 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/Road.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/Road.kt @@ -74,9 +74,8 @@ class Road( val surfaceWithoutTorsion: AbstractCurveRelativeSurface3D, val laneOffset: UnivariateFunction, val laneSections: NonEmptyList, - val linkage: RoadLinkage + val linkage: RoadLinkage, ) { - // Properties and Initializers init { require(surface.domain == surfaceWithoutTorsion.domain) { "Domains of provided surfaces must have the same domain." } @@ -86,22 +85,30 @@ class Road( require( laneOffset.domain.fuzzyEncloses( surface.domain, - surface.tolerance - ) + surface.tolerance, + ), ) { "The lane offset function must be defined everywhere where the surface is also defined." } require( laneSections.mapIndexed { index, laneSection -> index to laneSection } - .all { it.first == it.second.id.laneSectionId } + .all { it.first == it.second.id.laneSectionId }, ) { "LaneSection elements must be positioned according to their laneSection id on the list." } require( laneSections.dropLast(1) - .all { it.curvePositionDomain.lowerBoundType() == BoundType.CLOSED && it.curvePositionDomain.upperBoundType() == BoundType.OPEN } + .all { + it.curvePositionDomain.lowerBoundType() == BoundType.CLOSED && + it.curvePositionDomain.upperBoundType() == BoundType.OPEN + }, ) { "CurvePositionDomain of all LaneSections apart from the last must have a closed lower and open upper bound." } - require(laneSections.last().curvePositionDomain.lowerBoundType() == BoundType.CLOSED && laneSections.last().curvePositionDomain.upperBoundType() == BoundType.CLOSED) { "CurvePositionDomain of the last LaneSection must have a closed lower and upper bound." } + require( + laneSections.last().curvePositionDomain.lowerBoundType() == BoundType.CLOSED && + laneSections.last().curvePositionDomain.upperBoundType() == BoundType.CLOSED, + ) { + "CurvePositionDomain of the last LaneSection must have a closed lower and upper bound." + } val expectedLaneIds = laneSections.indices.toList() require( - laneSections.indices.toList().containsAll(expectedLaneIds) + laneSections.indices.toList().containsAll(expectedLaneIds), ) { "There must be no gaps within the given laneSectionIds." } require(laneSections.isSortedBy { it.id.laneSectionId }) { "LaneSections have to be sorted." } @@ -120,7 +127,7 @@ class Road( getLaneSectionCurvePositionDomains().map { SectionedCurveRelativeParametricSurface3D( surfaceWithoutTorsion, - it + it, ) } @@ -165,12 +172,13 @@ class Road( throw IllegalArgumentException("Domains of lane sections must close flush.") } - val fuzzySelectedLaneSections = laneSections.filter { - it.curvePositionDomain.fuzzyContains( - curveRelativePoint.curvePosition, - geometricalTolerance - ) - } + val fuzzySelectedLaneSections = + laneSections.filter { + it.curvePositionDomain.fuzzyContains( + curveRelativePoint.curvePosition, + geometricalTolerance, + ) + } return when (fuzzySelectedLaneSections.size) { 1 -> fuzzySelectedLaneSections.first().right() 0 -> IllegalArgumentException("No laneSection found").left() @@ -179,10 +187,11 @@ class Road( } /** Returns an individual lane referenced by [laneIdentifier]; if it does not exist, an [Either.Left] is returned. */ - fun getLane(laneIdentifier: LaneIdentifier): Either = either { - val laneSection = getLaneSection(laneIdentifier.laneSectionIdentifier).bind() - laneSection.getLane(laneIdentifier.laneId).bind() - } + fun getLane(laneIdentifier: LaneIdentifier): Either = + either { + val laneSection = getLaneSection(laneIdentifier.laneSectionIdentifier).bind() + laneSection.getLane(laneIdentifier.laneId).bind() + } /** Returns true, if road belongs to a junction. */ fun isLocatedInJunction() = linkage.belongsToJunctionId.isSome() @@ -190,19 +199,21 @@ class Road( /** Returns the contact point of the roadspace which connects to the junction with the [junctionIdentifier]. */ fun getRoadspaceContactPointToJunction(junctionIdentifier: JunctionIdentifier): Option = when { - linkage.predecessorJunctionId.isSome { it == junctionIdentifier } -> Some( - RoadspaceContactPointIdentifier( - ContactPoint.START, - id + linkage.predecessorJunctionId.isSome { it == junctionIdentifier } -> + Some( + RoadspaceContactPointIdentifier( + ContactPoint.START, + id, + ), ) - ) - linkage.successorJunctionId.isSome { it == junctionIdentifier } -> Some( - RoadspaceContactPointIdentifier( - ContactPoint.END, - id + linkage.successorJunctionId.isSome { it == junctionIdentifier } -> + Some( + RoadspaceContactPointIdentifier( + ContactPoint.END, + id, + ), ) - ) else -> None } @@ -210,7 +221,9 @@ class Road( /** Returns the [LaneSectionIdentifier] (first or last lane section) of the roadspace which is referenced by the * [roadspaceContactPointIdentifier]. */ fun getLaneSectionIdentifier(roadspaceContactPointIdentifier: RoadspaceContactPointIdentifier): LaneSectionIdentifier { - require(roadspaceContactPointIdentifier.roadspaceIdentifier == id) { "RoadspaceContactIdentifier ($roadspaceContactPointIdentifier) must reference this road (id=$id)." } + require(roadspaceContactPointIdentifier.roadspaceIdentifier == id) { + "RoadspaceContactIdentifier ($roadspaceContactPointIdentifier) must reference this road (id=$id)." + } return when (roadspaceContactPointIdentifier.roadspaceContactPoint) { ContactPoint.START -> laneSections.first().id @@ -219,12 +232,10 @@ class Road( } /** Returns true, if the lane with [laneIdentifier] is contained in the last lane section of the road. */ - fun isInFirstLaneSection(laneIdentifier: LaneIdentifier) = - laneIdentifier.laneSectionIdentifier == laneSections.first().id + fun isInFirstLaneSection(laneIdentifier: LaneIdentifier) = laneIdentifier.laneSectionIdentifier == laneSections.first().id /** Returns true, if the lane with [laneIdentifier] is contained in the last lane section of the road. */ - fun isInLastLaneSection(laneIdentifier: LaneIdentifier) = - laneIdentifier.laneSectionIdentifier == laneSections.last().id + fun isInLastLaneSection(laneIdentifier: LaneIdentifier) = laneIdentifier.laneSectionIdentifier == laneSections.last().id /** Returns the number of contained lane sections. */ fun numberOfLaneSections(): Int = laneSections.size @@ -289,12 +300,10 @@ class Road( } /** Returns the inner lane boundary of an individual lane with [laneIdentifier]. */ - fun getInnerLaneBoundary(laneIdentifier: LaneIdentifier): Either = - getCurveOnLane(laneIdentifier, 0.0) + fun getInnerLaneBoundary(laneIdentifier: LaneIdentifier): Either = getCurveOnLane(laneIdentifier, 0.0) /** Returns the outer lane boundary of an individual lane with [laneIdentifier]. */ - fun getOuterLaneBoundary(laneIdentifier: LaneIdentifier): Either = - getCurveOnLane(laneIdentifier, 1.0) + fun getOuterLaneBoundary(laneIdentifier: LaneIdentifier): Either = getCurveOnLane(laneIdentifier, 1.0) /** Returns the curve of the center lane with [laneSectionIdentifier]. */ fun getCurveOfCenterLane(laneSectionIdentifier: LaneSectionIdentifier): Either = @@ -316,49 +325,51 @@ class Road( fun getCurveOnLane( laneIdentifier: LaneIdentifier, factor: Double, - addLateralOffset: UnivariateFunction = ConstantFunction.ZERO - ): - Either = either { - require(laneIdentifier.isLeft() || laneIdentifier.isRight()) { "Identifier of lane must represent a left or a right lane." } - - // select the requested lane - val selectedLaneSection = getLaneSection(laneIdentifier.laneSectionIdentifier).bind() - val selectedLane = selectedLaneSection.getLane(laneIdentifier.laneId).bind() - - // select the correct surface and section it - val sectionedSurface = - if (selectedLane.level) { - sectionedSurfacesWithoutTorsion[laneIdentifier.laneSectionId] - } else { - sectionedSurfaces[laneIdentifier.laneSectionId] - } - - // calculate the total lateral offset function to the road's reference line - val sectionedLaneReferenceOffset = sectionedLaneOffset[laneIdentifier.laneSectionId] - val lateralLaneOffset = selectedLaneSection - .getLateralLaneOffset(laneIdentifier.laneId, factor) - .bind() - val lateralOffset = StackedFunction.ofSum( - sectionedLaneReferenceOffset, - lateralLaneOffset, - addLateralOffset - ) + addLateralOffset: UnivariateFunction = ConstantFunction.ZERO, + ): Either = + either { + require(laneIdentifier.isLeft() || laneIdentifier.isRight()) { "Identifier of lane must represent a left or a right lane." } + + // select the requested lane + val selectedLaneSection = getLaneSection(laneIdentifier.laneSectionIdentifier).bind() + val selectedLane = selectedLaneSection.getLane(laneIdentifier.laneId).bind() + + // select the correct surface and section it + val sectionedSurface = + if (selectedLane.level) { + sectionedSurfacesWithoutTorsion[laneIdentifier.laneSectionId] + } else { + sectionedSurfaces[laneIdentifier.laneSectionId] + } + + // calculate the total lateral offset function to the road's reference line + val sectionedLaneReferenceOffset = sectionedLaneOffset[laneIdentifier.laneSectionId] + val lateralLaneOffset = + selectedLaneSection + .getLateralLaneOffset(laneIdentifier.laneId, factor) + .bind() + val lateralOffset = + StackedFunction.ofSum( + sectionedLaneReferenceOffset, + lateralLaneOffset, + addLateralOffset, + ) - // calculate the additional height offset for the specific factor - val heightLaneOffset = selectedLaneSection - .getLaneHeightOffset(laneIdentifier, factor) - .bind() + // calculate the additional height offset for the specific factor + val heightLaneOffset = + selectedLaneSection + .getLaneHeightOffset(laneIdentifier, factor) + .bind() - // combine it to a curve on the sectioned road surface - CurveOnParametricSurface3D(sectionedSurface, lateralOffset, heightLaneOffset) - } + // combine it to a curve on the sectioned road surface + CurveOnParametricSurface3D(sectionedSurface, lateralOffset, heightLaneOffset) + } private fun getCurveOnLaneSectionSurface( laneSectionIdentifier: LaneSectionIdentifier, level: Boolean, - addLateralOffset: UnivariateFunction = ConstantFunction.ZERO - ): - Either { + addLateralOffset: UnivariateFunction = ConstantFunction.ZERO, + ): Either { // select the correct surface and section it val sectionedSurface = if (level) { @@ -378,43 +389,50 @@ class Road( /** * Returns the surface of an individual lane with [laneIdentifier] and a certain discretization [step] size. */ - fun getLaneSurface(laneIdentifier: LaneIdentifier, step: Double): Either = + fun getLaneSurface( + laneIdentifier: LaneIdentifier, + step: Double, + ): Either = either { - val laneSection = getLaneSection(laneIdentifier.laneSectionIdentifier) - .getOrElse { throw it } + val laneSection = + getLaneSection(laneIdentifier.laneSectionIdentifier) + .getOrElse { throw it } if (laneSection.curvePositionDomain.length < geometricalTolerance) { Either.Left( IllegalStateException( "${laneIdentifier.toIdentifierText()}: The length of the lane is almost zero " + - "(below tolerance) and thus no surface can be constructed." - ) + "(below tolerance) and thus no surface can be constructed.", + ), ).bind() } - val leftBoundary = getLeftLaneBoundary(laneIdentifier) - .getOrElse { throw it } - .calculatePointListGlobalCS(step) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } - val rightBoundary = getRightLaneBoundary(laneIdentifier) - .getOrElse { throw it } - .calculatePointListGlobalCS(step) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } + val leftBoundary = + getLeftLaneBoundary(laneIdentifier) + .getOrElse { throw it } + .calculatePointListGlobalCS(step) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } + val rightBoundary = + getRightLaneBoundary(laneIdentifier) + .getOrElse { throw it } + .calculatePointListGlobalCS(step) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } if (leftBoundary.zip(rightBoundary).all { it.first.fuzzyEquals(it.second, geometricalTolerance) }) { Either.Left( IllegalStateException( "${laneIdentifier.toIdentifierText()}: Lane has zero width (when discretized) and " + - "thus no surface can be constructed." - ) + "thus no surface can be constructed.", + ), ).bind() } - val surface = LinearRing3D.ofWithDuplicatesRemoval(leftBoundary, rightBoundary, geometricalTolerance) - .mapLeft { IllegalStateException(it.message) } - .bind() - .let { CompositeSurface3D(it) } + val surface = + LinearRing3D.ofWithDuplicatesRemoval(leftBoundary, rightBoundary, geometricalTolerance) + .mapLeft { IllegalStateException(it.message) } + .bind() + .let { CompositeSurface3D(it) } surface } @@ -427,56 +445,63 @@ class Road( * @param laneIdentifier lane identifier for which the lateral filler surfaces to the left shall be created * @param step discretization step size */ - fun getLateralFillerSurface(laneIdentifier: LaneIdentifier, step: Double): - Either> = either { - require(laneIdentifier.isLeft() || laneIdentifier.isRight()) { "Identifier of lane must represent a left or a right lane." } - - val innerLaneBoundaryOfThisLaneSampled = getInnerLaneBoundary(laneIdentifier).bind() - .calculatePointListGlobalCS(step) - .mapLeft { it.toIllegalStateException() } - .bind() - - val innerLaneIdentifier = laneIdentifier.getAdjacentInnerLaneIdentifier() - - val outerLaneBoundaryOfInnerLane = - if (innerLaneIdentifier.isCenter()) { - getCurveOfCenterLane(innerLaneIdentifier.laneSectionIdentifier) - } else { - getOuterLaneBoundary( - innerLaneIdentifier - ) + fun getLateralFillerSurface( + laneIdentifier: LaneIdentifier, + step: Double, + ): Either> = + either { + require(laneIdentifier.isLeft() || laneIdentifier.isRight()) { "Identifier of lane must represent a left or a right lane." } + + val innerLaneBoundaryOfThisLaneSampled = + getInnerLaneBoundary(laneIdentifier).bind() + .calculatePointListGlobalCS(step) + .mapLeft { it.toIllegalStateException() } + .bind() + + val innerLaneIdentifier = laneIdentifier.getAdjacentInnerLaneIdentifier() + + val outerLaneBoundaryOfInnerLane = + if (innerLaneIdentifier.isCenter()) { + getCurveOfCenterLane(innerLaneIdentifier.laneSectionIdentifier) + } else { + getOuterLaneBoundary( + innerLaneIdentifier, + ) + } + val outerLaneBoundaryOfInnerLaneSampled = + outerLaneBoundaryOfInnerLane.bind() + .calculatePointListGlobalCS(step) + .mapLeft { it.toIllegalStateException() } + .bind() + + // return no lateral filler surface, if there is no gap between the lane surfaces + if (innerLaneBoundaryOfThisLaneSampled.fuzzyEquals(outerLaneBoundaryOfInnerLaneSampled, geometricalTolerance)) { + return@either None } - val outerLaneBoundaryOfInnerLaneSampled = outerLaneBoundaryOfInnerLane.bind() - .calculatePointListGlobalCS(step) - .mapLeft { it.toIllegalStateException() } - .bind() - - // return no lateral filler surface, if there is no gap between the lane surfaces - if (innerLaneBoundaryOfThisLaneSampled.fuzzyEquals(outerLaneBoundaryOfInnerLaneSampled, geometricalTolerance)) { - return@either None - } - val leftLaneBoundary = - if (laneIdentifier.isLeft()) outerLaneBoundaryOfInnerLaneSampled else innerLaneBoundaryOfThisLaneSampled - val rightLaneBoundary = - if (laneIdentifier.isLeft()) innerLaneBoundaryOfThisLaneSampled else outerLaneBoundaryOfInnerLaneSampled + val leftLaneBoundary = + if (laneIdentifier.isLeft()) outerLaneBoundaryOfInnerLaneSampled else innerLaneBoundaryOfThisLaneSampled + val rightLaneBoundary = + if (laneIdentifier.isLeft()) innerLaneBoundaryOfThisLaneSampled else outerLaneBoundaryOfInnerLaneSampled - LinearRing3D.ofWithDuplicatesRemoval(rightLaneBoundary, leftLaneBoundary, geometricalTolerance) - .mapLeft { IllegalStateException(it.message) } - .bind() - .let { CompositeSurface3D(it) } - .let { LateralFillerSurface(LateralLaneRangeIdentifier.of(laneIdentifier, innerLaneIdentifier), it) } - .let { Some(it) } - } + LinearRing3D.ofWithDuplicatesRemoval(rightLaneBoundary, leftLaneBoundary, geometricalTolerance) + .mapLeft { IllegalStateException(it.message) } + .bind() + .let { CompositeSurface3D(it) } + .let { LateralFillerSurface(LateralLaneRangeIdentifier.of(laneIdentifier, innerLaneIdentifier), it) } + .let { Some(it) } + } - fun getRoadMarkings(laneIdentifier: LaneIdentifier, step: Double): - List>> = + fun getRoadMarkings( + laneIdentifier: LaneIdentifier, + step: Double, + ): List>> = if (laneIdentifier.isCenter()) { getCenterRoadMarkings(laneIdentifier, step) } else { getLeftRightRoadMarkings( laneIdentifier, - step + step, ) } @@ -486,8 +511,10 @@ class Road( * @param laneIdentifier identifier of lane (must represent a center lane) for which the road markings shall be returned * @param step discretization step size */ - private fun getCenterRoadMarkings(laneIdentifier: LaneIdentifier, step: Double): - List>> { + private fun getCenterRoadMarkings( + laneIdentifier: LaneIdentifier, + step: Double, + ): List>> { require(laneIdentifier.isCenter()) { "Identifier of lane must represent a center lane." } val centerLane = getLaneSection(laneIdentifier.laneSectionIdentifier).getOrElse { throw it }.centerLane @@ -505,8 +532,11 @@ class Road( * @return either a [AbstractCurve3D], if the road marking has zero width, or a [AbstractSurface3D], if the width * is not zero */ - private fun getCenterRoadMarkingGeometry(centerLane: CenterLane, roadMarking: RoadMarking, step: Double): - AbstractGeometry3D { + private fun getCenterRoadMarkingGeometry( + centerLane: CenterLane, + roadMarking: RoadMarking, + step: Double, + ): AbstractGeometry3D { if (roadMarking.width.value < geometricalTolerance) { return getCurveOnLaneSectionSurface(centerLane.id.laneSectionIdentifier, centerLane.level) .getOrElse { throw it } @@ -530,7 +560,7 @@ class Road( return LinearRing3D.ofWithDuplicatesRemoval( leftRoadMarkingBoundary, rightRoadMarkingBoundary, - geometricalTolerance + geometricalTolerance, ) .getOrElse { throw IllegalStateException(it.message) } .let { CompositeSurface3D(it) } @@ -542,16 +572,19 @@ class Road( * @param laneIdentifier lane identifier for which the road markings shall be returned * @param step discretization step size */ - private fun getLeftRightRoadMarkings(laneIdentifier: LaneIdentifier, step: Double): - List>> { + private fun getLeftRightRoadMarkings( + laneIdentifier: LaneIdentifier, + step: Double, + ): List>> { require(laneIdentifier.isLeft() || laneIdentifier.isRight()) { "Identifier of lane must represent a left or a right lane." } return getLane(laneIdentifier) .getOrElse { throw it } .roadMarkings .map { currentRoadMarking -> - val geometry: AbstractGeometry3D = getRoadMarkingGeometry(laneIdentifier, currentRoadMarking, step) - .getOrElse { return@map it.left() } + val geometry: AbstractGeometry3D = + getRoadMarkingGeometry(laneIdentifier, currentRoadMarking, step) + .getOrElse { return@map it.left() } Either.Right(currentRoadMarking to geometry) } } @@ -564,13 +597,17 @@ class Road( * @return either a [AbstractCurve3D], if the road marking has zero width, or a [AbstractSurface3D], if the width * is not zero */ - private fun getRoadMarkingGeometry(laneIdentifier: LaneIdentifier, roadMarking: RoadMarking, step: Double): - Either { + private fun getRoadMarkingGeometry( + laneIdentifier: LaneIdentifier, + roadMarking: RoadMarking, + step: Double, + ): Either { if (roadMarking.width.domain.length < geometricalTolerance) { return Either.Left( IllegalStateException( - "${laneIdentifier.toIdentifierText()}: Road marking's length is zero (or below tolerance threshold) and thus no surface can be constructed." - ) + "${laneIdentifier.toIdentifierText()}: Road marking's length is zero (or below tolerance threshold) and " + + "thus no surface can be constructed.", + ), ) } @@ -579,17 +616,19 @@ class Road( } val leftOffsetFunction = roadMarking.width timesValue 0.5 - val leftRoadMarkBoundary = getCurveOnLane(laneIdentifier, 1.0, leftOffsetFunction) - .getOrElse { throw it } - .calculatePointListGlobalCS(step) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } + val leftRoadMarkBoundary = + getCurveOnLane(laneIdentifier, 1.0, leftOffsetFunction) + .getOrElse { throw it } + .calculatePointListGlobalCS(step) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } val rightOffsetFunction = roadMarking.width timesValue -0.5 - val rightRoadMarkBoundary = getCurveOnLane(laneIdentifier, 1.0, rightOffsetFunction) - .getOrElse { throw it } - .calculatePointListGlobalCS(step) - .mapLeft { it.toIllegalStateException() } - .getOrElse { throw it } + val rightRoadMarkBoundary = + getCurveOnLane(laneIdentifier, 1.0, rightOffsetFunction) + .getOrElse { throw it } + .calculatePointListGlobalCS(step) + .mapLeft { it.toIllegalStateException() } + .getOrElse { throw it } return LinearRing3D.ofWithDuplicatesRemoval(leftRoadMarkBoundary, rightRoadMarkBoundary, geometricalTolerance) .getOrElse { return IllegalStateException(it.message).left() } @@ -599,16 +638,18 @@ class Road( /** Returns the curve position domains of each lane section. */ private fun getLaneSectionCurvePositionDomains(): List> { - val laneSectionDomains = laneSections - .map { it.curvePositionStart.curvePosition } - .zipWithNext() - .map { Range.closed(it.first, it.second) } - - val lastLaneSectionDomain = Range.closedX( - laneSections.last().curvePositionStart.curvePosition, - curvePositionDomain.upperEndpointOrNull()!!, - curvePositionDomain.upperBoundType() - ) + val laneSectionDomains = + laneSections + .map { it.curvePositionStart.curvePosition } + .zipWithNext() + .map { Range.closed(it.first, it.second) } + + val lastLaneSectionDomain = + Range.closedX( + laneSections.last().curvePositionStart.curvePosition, + curvePositionDomain.upperEndpointOrNull()!!, + curvePositionDomain.upperBoundType(), + ) return laneSectionDomains + lastLaneSectionDomain } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/RoadLinkage.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/RoadLinkage.kt index 73e66324..67ec666d 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/RoadLinkage.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/RoadLinkage.kt @@ -29,12 +29,16 @@ data class RoadLinkage( val predecessorRoadspaceContactPointId: Option, val predecessorJunctionId: Option, val successorRoadspaceContactPointId: Option, - val successorJunctionId: Option + val successorJunctionId: Option, ) { // Properties and Initializers init { - require(!(predecessorRoadspaceContactPointId.isSome() && predecessorJunctionId.isSome())) { "Predecessor must be either a roadspace or junction or neither." } - require(!(successorRoadspaceContactPointId.isSome() && successorJunctionId.isSome())) { "Successor must be either a roadspace or junction or neither." } + require(!(predecessorRoadspaceContactPointId.isSome() && predecessorJunctionId.isSome())) { + "Predecessor must be either a roadspace or junction or neither." + } + require(!(successorRoadspaceContactPointId.isSome() && successorJunctionId.isSome())) { + "Successor must be either a roadspace or junction or neither." + } belongsToJunctionId.onSome { require(predecessorJunctionId.isNone()) { "If a road belongs to a junction (id=$it), a predecessing junction must not exist." } diff --git a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/RoadMarking.kt b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/RoadMarking.kt index f3f8cfa1..d22f2db3 100644 --- a/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/RoadMarking.kt +++ b/rtron-model/src/main/kotlin/io/rtron/model/roadspaces/roadspace/road/RoadMarking.kt @@ -28,9 +28,8 @@ import io.rtron.model.roadspaces.roadspace.attribute.AttributeList data class RoadMarking( val width: ConstantFunction, val laneChange: LaneChange, - val attributes: AttributeList + val attributes: AttributeList, ) { - // Properties and Initializers init { require(width.domain.isNotEmpty()) { "The domain of the road marking's width must not be empty." } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/citygml/CitygmlVersion.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/citygml/CitygmlVersion.kt index 0cf516b2..e21a2285 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/citygml/CitygmlVersion.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/citygml/CitygmlVersion.kt @@ -21,11 +21,12 @@ import org.citygml4j.core.model.CityGMLVersion as GmlCitygmlVersion enum class CitygmlVersion { V1_0, V2_0, - V3_0 + V3_0, } -fun CitygmlVersion.toGmlCitygml(): GmlCitygmlVersion = when (this) { - CitygmlVersion.V1_0 -> GmlCitygmlVersion.v1_0 - CitygmlVersion.V2_0 -> GmlCitygmlVersion.v2_0 - CitygmlVersion.V3_0 -> GmlCitygmlVersion.v3_0 -} +fun CitygmlVersion.toGmlCitygml(): GmlCitygmlVersion = + when (this) { + CitygmlVersion.V1_0 -> GmlCitygmlVersion.v1_0 + CitygmlVersion.V2_0 -> GmlCitygmlVersion.v2_0 + CitygmlVersion.V3_0 -> GmlCitygmlVersion.v3_0 + } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/citygml/CitygmlWriter.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/citygml/CitygmlWriter.kt index d1f0f575..7d19677f 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/citygml/CitygmlWriter.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/citygml/CitygmlWriter.kt @@ -27,7 +27,6 @@ import java.nio.charset.StandardCharsets import java.nio.file.Path object CitygmlWriter { - // Properties and Initializers private val logger = KotlinLogging.logger {} @@ -35,7 +34,11 @@ object CitygmlWriter { // Methods - fun writeToFile(model: CitygmlModel, version: CitygmlVersion, filePath: Path) { + fun writeToFile( + model: CitygmlModel, + version: CitygmlVersion, + filePath: Path, + ) { val outputStream = filePath.outputStreamDirectOrCompressed() writeToStream(model, version, outputStream) outputStream.close() @@ -43,7 +46,11 @@ object CitygmlWriter { logger.info { "Completed writing of file ${filePath.fileName} (around ${filePath.getFileSizeToDisplay()})." } } - fun writeToStream(model: CitygmlModel, version: CitygmlVersion, outputStream: OutputStream) { + fun writeToStream( + model: CitygmlModel, + version: CitygmlVersion, + outputStream: OutputStream, + ) { val citygmlVersion = version.toGmlCitygml() val out = citygmlContext.createCityGMLOutputFactory(citygmlVersion)!! diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveReader.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveReader.kt index 24ce9d12..d86c8037 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveReader.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveReader.kt @@ -37,81 +37,103 @@ import java.nio.file.Path import kotlin.io.path.isRegularFile object OpendriveReader { - // Properties and Initializers private val logger = KotlinLogging.logger {} // Methods - fun readFromFile(filePath: Path): Either = either { - if (!filePath.isRegularFile()) { - OpendriveReaderException.FileNotFound(filePath).left().bind() - } - if (!supportedFilenameEndings.any { filePath.fileName.toString().endsWith(it) }) { - OpendriveReaderException.FileEndingNotSupported(filePath).left().bind() - } + fun readFromFile(filePath: Path): Either = + either { + if (!filePath.isRegularFile()) { + OpendriveReaderException.FileNotFound(filePath).left().bind() + } + if (!supportedFilenameEndings.any { filePath.fileName.toString().endsWith(it) }) { + OpendriveReaderException.FileEndingNotSupported(filePath).left().bind() + } - val fileInputStreamForVersion = filePath.inputStreamFromDirectOrCompressedFile() - val opendriveVersion = OpendriveVersionUtils.getOpendriveVersion(fileInputStreamForVersion).bind() - fileInputStreamForVersion.close() + val fileInputStreamForVersion = filePath.inputStreamFromDirectOrCompressedFile() + val opendriveVersion = OpendriveVersionUtils.getOpendriveVersion(fileInputStreamForVersion).bind() + fileInputStreamForVersion.close() - val fileInputStream = filePath.inputStreamFromDirectOrCompressedFile() - val opendriveModelResult = readFromStream(opendriveVersion, fileInputStream) - fileInputStream.close() + val fileInputStream = filePath.inputStreamFromDirectOrCompressedFile() + val opendriveModelResult = readFromStream(opendriveVersion, fileInputStream) + fileInputStream.close() - val opendriveModel = opendriveModelResult.bind() - logger.info { "Completed read-in of file ${filePath.fileName} (around ${filePath.getFileSizeToDisplay()})." } - opendriveModel - } - fun readFromStream(opendriveVersion: OpendriveVersion, inputStream: InputStream): Either = + val opendriveModel = opendriveModelResult.bind() + logger.info { "Completed read-in of file ${filePath.fileName} (around ${filePath.getFileSizeToDisplay()})." } + opendriveModel + } + + fun readFromStream( + opendriveVersion: OpendriveVersion, + inputStream: InputStream, + ): Either = either { - val unmarshallerOpendriveVersion = when (opendriveVersion) { - OpendriveVersion.V0_7 -> OpendriveVersion.V1_4 - OpendriveVersion.V1_1 -> OpendriveVersion.V1_4 - OpendriveVersion.V1_2 -> OpendriveVersion.V1_4 - OpendriveVersion.V1_3 -> OpendriveVersion.V1_4 - OpendriveVersion.V1_4 -> OpendriveVersion.V1_4 - OpendriveVersion.V1_5 -> OpendriveVersion.V1_4 - OpendriveVersion.V1_6 -> OpendriveVersion.V1_6 - OpendriveVersion.V1_7 -> OpendriveVersion.V1_6 - } + val unmarshallerOpendriveVersion = + when (opendriveVersion) { + OpendriveVersion.V0_7 -> OpendriveVersion.V1_4 + OpendriveVersion.V1_1 -> OpendriveVersion.V1_4 + OpendriveVersion.V1_2 -> OpendriveVersion.V1_4 + OpendriveVersion.V1_3 -> OpendriveVersion.V1_4 + OpendriveVersion.V1_4 -> OpendriveVersion.V1_4 + OpendriveVersion.V1_5 -> OpendriveVersion.V1_4 + OpendriveVersion.V1_6 -> OpendriveVersion.V1_6 + OpendriveVersion.V1_7 -> OpendriveVersion.V1_6 + } if (opendriveVersion != unmarshallerOpendriveVersion) { - logger.warn { "No dedicated reader available for OpenDRIVE $opendriveVersion. Using reader for OpenDRIVE $unmarshallerOpendriveVersion as fallback." } + logger.warn { + "No dedicated reader available for OpenDRIVE $opendriveVersion. " + + "Using reader for OpenDRIVE $unmarshallerOpendriveVersion as fallback." + } } val unmarshaller = OpendriveUnmarshaller.of(unmarshallerOpendriveVersion).bind() val opendriveVersionSpecificModel = unmarshaller.jaxbUnmarshaller.unmarshal(inputStream) - val opendriveModel = when (unmarshallerOpendriveVersion) { - OpendriveVersion.V1_4 -> { - val converter = Mappers.getMapper(Opendrive14Mapper::class.java) - converter.mapModel(opendriveVersionSpecificModel as org.asam.opendrive14.OpenDRIVE) + val opendriveModel = + when (unmarshallerOpendriveVersion) { + OpendriveVersion.V1_4 -> { + val converter = Mappers.getMapper(Opendrive14Mapper::class.java) + converter.mapModel(opendriveVersionSpecificModel as org.asam.opendrive14.OpenDRIVE) + } + OpendriveVersion.V1_6 -> { + val converter = Mappers.getMapper(Opendrive16Mapper::class.java) + converter.mapModel(opendriveVersionSpecificModel as org.asam.opendrive16.OpenDRIVE) + } + else -> throw IllegalStateException("Mapper must be implemented") } - OpendriveVersion.V1_6 -> { - val converter = Mappers.getMapper(Opendrive16Mapper::class.java) - converter.mapModel(opendriveVersionSpecificModel as org.asam.opendrive16.OpenDRIVE) - } - else -> throw IllegalStateException("Mapper must be implemented") - } opendriveModel.updateAdditionalIdentifiers() opendriveModel } - val supportedFilenameEndings: Set = setOf( - ".xodr", - ".xodr.${CompressedFileExtension.ZIP.extension}", - ".xodr.${CompressedFileExtension.GZ.extension}", - ".xodr.${CompressedFileExtension.ZST.extension}" - ) + val supportedFilenameEndings: Set = + setOf( + ".xodr", + ".xodr.${CompressedFileExtension.ZIP.extension}", + ".xodr.${CompressedFileExtension.GZ.extension}", + ".xodr.${CompressedFileExtension.ZST.extension}", + ) } sealed class OpendriveReaderException(message: String) : BaseException(message) { data class FileNotFound(val path: Path) : OpendriveReaderException("File not found at $path") + data class FileEndingNotSupported(val path: Path) : OpendriveReaderException("File not found at $path") + data class MalformedXmlDocument(val reason: String) : OpendriveReaderException("OpenDRIVE file cannot be parsed: $reason") - data class HeaderElementNotFound(val reason: String) : OpendriveReaderException("Header element of OpenDRIVE dataset not found: $reason") + + data class HeaderElementNotFound(val reason: String) : OpendriveReaderException( + "Header element of OpenDRIVE dataset not found: $reason", + ) + data class VersionNotIdentifiable(val reason: String) : OpendriveReaderException("Version of OpenDRIVE dataset not deducible: $reason") - data class NoDedicatedUnmarshallerAvailable(val version: OpendriveVersion) : OpendriveReaderException("No dedicated unmarshaller available for $version") + data class NoDedicatedUnmarshallerAvailable(val version: OpendriveVersion) : OpendriveReaderException( + "No dedicated unmarshaller available for $version", + ) + data class FatalSchemaValidationError(val reason: String) : OpendriveReaderException("Fatal error during schema validation: $reason") - data class NumberFormatException(val reason: String) : OpendriveReaderException("Invalid formatting of a number in the dataset: $reason") + + data class NumberFormatException(val reason: String) : OpendriveReaderException( + "Invalid formatting of a number in the dataset: $reason", + ) } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveValidator.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveValidator.kt index 2d8702d7..9d50c61c 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveValidator.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveValidator.kt @@ -32,40 +32,48 @@ import java.io.InputStream import java.nio.file.Path object OpendriveValidator { - // Properties and Initializers private val logger = KotlinLogging.logger {} - fun validateFromFile(filePath: Path): Either = either { - val opendriveVersion = OpendriveVersionUtils.getOpendriveVersion(filePath.inputStreamFromDirectOrCompressedFile()).bind() + fun validateFromFile(filePath: Path): Either = + either { + val opendriveVersion = OpendriveVersionUtils.getOpendriveVersion(filePath.inputStreamFromDirectOrCompressedFile()).bind() - val fileInputStream = filePath.inputStreamFromDirectOrCompressedFile() - val reportResult = validateFromStream(opendriveVersion, fileInputStream) - fileInputStream.close() + val fileInputStream = filePath.inputStreamFromDirectOrCompressedFile() + val reportResult = validateFromStream(opendriveVersion, fileInputStream) + fileInputStream.close() - reportResult.bind() - } + reportResult.bind() + } - fun validateFromStream(opendriveVersion: OpendriveVersion, inputStream: InputStream): Either = either { - val issueList = runValidation(opendriveVersion, inputStream) - .getOrElse { - logger.warn { "Schema validation was aborted due the following error: ${it.message}" } - return@either SchemaValidationReport( - opendriveVersion, - completedSuccessfully = false, - validationAbortIssue = it.message - ) + fun validateFromStream( + opendriveVersion: OpendriveVersion, + inputStream: InputStream, + ): Either = + either { + val issueList = + runValidation(opendriveVersion, inputStream) + .getOrElse { + logger.warn { "Schema validation was aborted due the following error: ${it.message}" } + return@either SchemaValidationReport( + opendriveVersion, + completedSuccessfully = false, + validationAbortIssue = it.message, + ) + } + if (!issueList.isEmpty()) { + logger.warn { "Schema validation for OpenDRIVE $opendriveVersion found ${issueList.size} incidents." } + } else { + logger.info { "Schema validation report for OpenDRIVE $opendriveVersion: Everything ok." } } - if (!issueList.isEmpty()) { - logger.warn { "Schema validation for OpenDRIVE $opendriveVersion found ${issueList.size} incidents." } - } else { - logger.info { "Schema validation report for OpenDRIVE $opendriveVersion: Everything ok." } - } - SchemaValidationReport(opendriveVersion, issueList) - } + SchemaValidationReport(opendriveVersion, issueList) + } - private fun runValidation(opendriveVersion: OpendriveVersion, inputStream: InputStream): Either> = + private fun runValidation( + opendriveVersion: OpendriveVersion, + inputStream: InputStream, + ): Either> = either { val unmarshaller = OpendriveUnmarshaller.of(opendriveVersion).bind() diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveWriter.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveWriter.kt index e4d62032..886384e1 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveWriter.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/OpendriveWriter.kt @@ -34,15 +34,22 @@ object OpendriveWriter { private val opendriveMarshaller by lazy { OpendriveMarshaller() } // Methods - fun writeToFile(model: OpendriveModel, filePath: Path): Either = either { - val outputStream: OutputStream = filePath.outputStreamDirectOrCompressed() - writeToStream(model, outputStream) - outputStream.close() - - logger.info { "Completed writing of file ${filePath.fileName} (around ${filePath.getFileSizeToDisplay()})." } - } - - fun writeToStream(model: OpendriveModel, outputStream: OutputStream) { + fun writeToFile( + model: OpendriveModel, + filePath: Path, + ): Either = + either { + val outputStream: OutputStream = filePath.outputStreamDirectOrCompressed() + writeToStream(model, outputStream) + outputStream.close() + + logger.info { "Completed writing of file ${filePath.fileName} (around ${filePath.getFileSizeToDisplay()})." } + } + + fun writeToStream( + model: OpendriveModel, + outputStream: OutputStream, + ) { opendriveMarshaller.writeToStream(model, outputStream) } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/OpendriveUnmarshaller.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/OpendriveUnmarshaller.kt index ca7bd3e4..c2e36ada 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/OpendriveUnmarshaller.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/OpendriveUnmarshaller.kt @@ -28,7 +28,6 @@ import javax.xml.XMLConstants import javax.xml.validation.SchemaFactory class OpendriveUnmarshaller(val opendriveVersion: OpendriveVersion) { - // Properties and Initializers val jaxbUnmarshaller: Unmarshaller val validationEventHandler = OpendriveValidationEventHandler() @@ -49,27 +48,33 @@ class OpendriveUnmarshaller(val opendriveVersion: OpendriveVersion) { } companion object { - private val OPENDRIVE_MODEL_CLASSES: Map> = mapOf( - OpendriveVersion.V1_1 to org.asam.opendrive11.OpenDRIVE::class.java, - OpendriveVersion.V1_2 to org.asam.opendrive12.OpenDRIVE::class.java, - OpendriveVersion.V1_3 to org.asam.opendrive13.OpenDRIVE::class.java, - OpendriveVersion.V1_4 to org.asam.opendrive14.OpenDRIVE::class.java, - OpendriveVersion.V1_5 to org.asam.opendrive15.OpenDRIVE::class.java, - OpendriveVersion.V1_6 to org.asam.opendrive16.OpenDRIVE::class.java, - OpendriveVersion.V1_7 to org.asam.opendrive17.OpenDRIVE::class.java - ) - private val OPENDRIVE_SCHEMA_LOCATIONS: Map = mapOf( - OpendriveVersion.V1_1 to "schemas/opendrive11/OpenDRIVE_1.1D.xsd", - OpendriveVersion.V1_2 to "schemas/opendrive12/OpenDRIVE_1.2A.xsd", - OpendriveVersion.V1_3 to "schemas/opendrive13/OpenDRIVE_1.3D.xsd", - OpendriveVersion.V1_4 to "schemas/opendrive14/OpenDRIVE_1.4H.xsd", - OpendriveVersion.V1_5 to "schemas/opendrive15/OpenDRIVE_1.5M.xsd", - OpendriveVersion.V1_6 to "schemas/opendrive16/opendrive_16_core.xsd", - OpendriveVersion.V1_7 to "schemas/opendrive17/opendrive_17_core.xsd" - ) + private val OPENDRIVE_MODEL_CLASSES: Map> = + mapOf( + OpendriveVersion.V1_1 to org.asam.opendrive11.OpenDRIVE::class.java, + OpendriveVersion.V1_2 to org.asam.opendrive12.OpenDRIVE::class.java, + OpendriveVersion.V1_3 to org.asam.opendrive13.OpenDRIVE::class.java, + OpendriveVersion.V1_4 to org.asam.opendrive14.OpenDRIVE::class.java, + OpendriveVersion.V1_5 to org.asam.opendrive15.OpenDRIVE::class.java, + OpendriveVersion.V1_6 to org.asam.opendrive16.OpenDRIVE::class.java, + OpendriveVersion.V1_7 to org.asam.opendrive17.OpenDRIVE::class.java, + ) + private val OPENDRIVE_SCHEMA_LOCATIONS: Map = + mapOf( + OpendriveVersion.V1_1 to "schemas/opendrive11/OpenDRIVE_1.1D.xsd", + OpendriveVersion.V1_2 to "schemas/opendrive12/OpenDRIVE_1.2A.xsd", + OpendriveVersion.V1_3 to "schemas/opendrive13/OpenDRIVE_1.3D.xsd", + OpendriveVersion.V1_4 to "schemas/opendrive14/OpenDRIVE_1.4H.xsd", + OpendriveVersion.V1_5 to "schemas/opendrive15/OpenDRIVE_1.5M.xsd", + OpendriveVersion.V1_6 to "schemas/opendrive16/opendrive_16_core.xsd", + OpendriveVersion.V1_7 to "schemas/opendrive17/opendrive_17_core.xsd", + ) + init { - check(OPENDRIVE_MODEL_CLASSES.keys == OPENDRIVE_SCHEMA_LOCATIONS.keys) { "All model classes must have a correspondent schema location defined." } + check(OPENDRIVE_MODEL_CLASSES.keys == OPENDRIVE_SCHEMA_LOCATIONS.keys) { + "All model classes must have a correspondent schema location defined." + } } + val SUPPORTED_SCHEMA_VERSIONS: Set = OPENDRIVE_MODEL_CLASSES.keys fun of(version: OpendriveVersion): Either { diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/common/OpendriveCommonMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/common/OpendriveCommonMapper.kt index 65d1108a..6115048a 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/common/OpendriveCommonMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/common/OpendriveCommonMapper.kt @@ -29,17 +29,18 @@ import org.mapstruct.ValueMapping /** * Returns upper case string variations (with or without '_') of string. */ -fun String.toUpperCaseVariations(): List = - listOf(uppercase(), replace("_", "").uppercase()) +fun String.toUpperCaseVariations(): List = listOf(uppercase(), replace("_", "").uppercase()) @Mapper( - nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, ) abstract class OpendriveCommonMapper { - fun mapNullableToOption(source: T?): Option = Option.fromNullable(source) - fun mapCountryCodeStringToOption(source: String?): Option = source?.let { Option.fromNullable(mapCountryCodeString(it)) } ?: None + fun mapCountryCodeStringToOption(source: String?): Option = + source?.let { + Option.fromNullable(mapCountryCodeString(it)) + } ?: None @ValueMapping(source = "Austria", target = "AU") @ValueMapping(source = "Brazil", target = "BR") @@ -60,9 +61,11 @@ abstract class OpendriveCommonMapper { abstract fun mapCountryCodeString(source: String): ECountryCode? fun mapOrientationStringToOption(source: String?): Option = source?.let { mapOrientationString(it).some() } ?: None - fun mapOrientationString(source: String): EOrientation = when (source) { - "+" -> EOrientation.PLUS - "-" -> EOrientation.MINUS - else -> EOrientation.NONE - } + + fun mapOrientationString(source: String): EOrientation = + when (source) { + "+" -> EOrientation.PLUS + "-" -> EOrientation.MINUS + else -> EOrientation.NONE + } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14CoreMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14CoreMapper.kt index b9352e86..9b961e74 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14CoreMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14CoreMapper.kt @@ -31,10 +31,9 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive14CoreMapper { - // // Header // @@ -50,29 +49,33 @@ abstract class Opendrive14CoreMapper { // Enumerations // fun mapUnitToOptionEUnitSpeed(source: Unit?): Option = source?.let { mapUnit(it).some() } ?: None - fun mapUnit(source: Unit): EUnitSpeed = when (source) { - Unit.M___S -> EUnitSpeed.METER_PER_SECOND - Unit.MPH -> EUnitSpeed.MILES_PER_HOUR - Unit.KM___H -> EUnitSpeed.KILOMETER_PER_HOUR - else -> EUnitSpeed.KILOMETER_PER_HOUR - } + + fun mapUnit(source: Unit): EUnitSpeed = + when (source) { + Unit.M___S -> EUnitSpeed.METER_PER_SECOND + Unit.MPH -> EUnitSpeed.MILES_PER_HOUR + Unit.KM___H -> EUnitSpeed.KILOMETER_PER_HOUR + else -> EUnitSpeed.KILOMETER_PER_HOUR + } fun mapUnitToOptionEUnit(source: Unit?): Option = source?.let { mapUnitToEUnit(it).some() } ?: None - fun mapUnitToEUnit(source: Unit): EUnit = when (source) { - Unit.M -> EUnit.METER - Unit.KM -> EUnit.KILOMETER - Unit.FT -> EUnit.FEET - Unit.MILE -> EUnit.MILE - Unit.M___S -> EUnit.METER_PER_SECOND - Unit.MPH -> EUnit.MILES_PER_HOUR - Unit.KM___H -> EUnit.KILOMETER_PER_HOUR + fun mapUnitToEUnit(source: Unit): EUnit = + when (source) { + Unit.M -> EUnit.METER + Unit.KM -> EUnit.KILOMETER + Unit.FT -> EUnit.FEET + Unit.MILE -> EUnit.MILE - Unit.KG -> EUnit.KILOGRAM - Unit.T -> EUnit.TON + Unit.M___S -> EUnit.METER_PER_SECOND + Unit.MPH -> EUnit.MILES_PER_HOUR + Unit.KM___H -> EUnit.KILOMETER_PER_HOUR - Unit.PERCENT -> EUnit.PERCENT - } + Unit.KG -> EUnit.KILOGRAM + Unit.T -> EUnit.TON + + Unit.PERCENT -> EUnit.PERCENT + } fun mapDynamicToBoolean(source: Dynamic): Boolean = source == Dynamic.YES } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14JunctionMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14JunctionMapper.kt index 6d6c3de4..796e5016 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14JunctionMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14JunctionMapper.kt @@ -30,15 +30,15 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive14CoreMapper::class, Opendrive14ObjectMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive14JunctionMapper { - abstract fun mapJunction(source: OpenDRIVE.Junction): Junction // // Enumerations // fun mapContactPointToOption(source: ContactPoint?): Option = source?.let { mapContactPoint(it).some() } ?: None + abstract fun mapContactPoint(source: ContactPoint): EContactPoint } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14LaneMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14LaneMapper.kt index 995c3212..ad2de5fc 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14LaneMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14LaneMapper.kt @@ -48,22 +48,24 @@ import org.mapstruct.ValueMapping @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive14CoreMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive14LaneMapper { - // // Lane Section // abstract fun mapRoadLanesLaneSection(source: OpenDRIVE.Road.Lanes.LaneSection): RoadLanesLaneSection abstract fun mapRoadLanesLaneSectionLeft(source: OpenDRIVE.Road.Lanes.LaneSection.Left): RoadLanesLaneSectionLeft + abstract fun mapRoadLanesLaneSectionRight(source: OpenDRIVE.Road.Lanes.LaneSection.Right): RoadLanesLaneSectionRight // // Lane // - fun mapRoadLanesLaneSectionCenterLanes(source: CenterLane?): List = source?.let { listOf(mapRoadLanesLaneSectionCenterLane(it)) } ?: emptyList() + fun mapRoadLanesLaneSectionCenterLanes(source: CenterLane?): List = + source?.let { listOf(mapRoadLanesLaneSectionCenterLane(it)) } ?: emptyList() + abstract fun mapRoadLanesLaneSectionCenterLane(source: CenterLane): RoadLanesLaneSectionCenterLane // @@ -73,42 +75,54 @@ abstract class Opendrive14LaneMapper { fun mapCenterLaneLinkPredecessor(source: CenterLane.Link.Predecessor?): List = source?.let { listOf(mapPredecessor(it)) } ?: emptyList() + abstract fun mapPredecessor(source: CenterLane.Link.Predecessor): RoadLanesLaneSectionLCRLaneLinkPredecessorSuccessor fun mapCenterLaneLinkSuccessor(source: CenterLane.Link.Successor?): List = source?.let { listOf(mapSuccessor(it)) } ?: emptyList() + abstract fun mapSuccessor(source: CenterLane.Link.Successor): RoadLanesLaneSectionLCRLaneLinkPredecessorSuccessor abstract fun mapLaneLink(source: Lane.Link): RoadLanesLaneSectionLCRLaneLink fun mapLaneLinkPredecessor(source: Lane.Link.Predecessor?): List = source?.let { listOf(mapPredecessor(it)) } ?: emptyList() + abstract fun mapPredecessor(source: Lane.Link.Predecessor): RoadLanesLaneSectionLCRLaneLinkPredecessorSuccessor fun mapLaneLinkSuccessor(source: Lane.Link.Successor?): List = source?.let { listOf(mapSuccessor(it)) } ?: emptyList() + abstract fun mapSuccessor(source: Lane.Link.Successor): RoadLanesLaneSectionLCRLaneLinkPredecessorSuccessor // // Road Mark // abstract fun mapLaneRoadMarkType(source: Lane.RoadMark.Type): RoadLanesLaneSectionLCRLaneRoadMarkType + abstract fun mapCenterLaneRoadMarkType(source: CenterLane.RoadMark.Type): RoadLanesLaneSectionLCRLaneRoadMarkType fun mapRoadMarkWeightToOption(source: Weight?): Option = source?.let { mapRoadMarkWeight(it).some() } ?: None + abstract fun mapRoadMarkWeight(source: Weight): ERoadMarkWeight - fun mapLaneChangeToOption(source: LaneChange?): Option = source?.let { mapLaneChange(it).some() } ?: None + fun mapLaneChangeToOption(source: LaneChange?): Option = + source?.let { + mapLaneChange(it).some() + } ?: None + abstract fun mapLaneChange(source: LaneChange): ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange // // Enumerations // fun mapSingleSideToOption(source: SingleSide?): Option = source?.let { mapSingleSide(it).some() } ?: None - fun mapSingleSide(source: SingleSide): Boolean = when (source) { - SingleSide.TRUE -> true - SingleSide.FALSE -> false - } + + fun mapSingleSide(source: SingleSide): Boolean = + when (source) { + SingleSide.TRUE -> true + SingleSide.FALSE -> false + } @ValueMapping(source = "AUTONOMOUS___TRAFFIC", target = "AUTONOMOUS_TRAFFIC") abstract fun map(source: Restriction): EAccessRestrictionType diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14Mapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14Mapper.kt index 9191d879..85638ba9 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14Mapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14Mapper.kt @@ -24,9 +24,11 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, - uses = [OpendriveCommonMapper::class, Opendrive14CoreMapper::class, Opendrive14LaneMapper::class, Opendrive14ObjectMapper::class, Opendrive14RoadMapper::class, Opendrive14SignalMapper::class, Opendrive14JunctionMapper::class] + uses = [ + OpendriveCommonMapper::class, Opendrive14CoreMapper::class, Opendrive14LaneMapper::class, Opendrive14ObjectMapper::class, + Opendrive14RoadMapper::class, Opendrive14SignalMapper::class, Opendrive14JunctionMapper::class, + ], ) abstract class Opendrive14Mapper { - abstract fun mapModel(model: OpenDRIVE): OpendriveModel } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14ObjectMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14ObjectMapper.kt index 27c7bf64..f2fc88d5 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14ObjectMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14ObjectMapper.kt @@ -37,10 +37,9 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive14ObjectMapper { - // // Road Objects // @@ -57,10 +56,12 @@ abstract class Opendrive14ObjectMapper { val outlines = listOf(mapRoadObjectsObjectOutlinesOutline(source)) return RoadObjectsObjectOutlines(outlines) } + abstract fun mapRoadObjectsObjectOutlinesOutline(source: OpenDRIVE.Road.Objects.Object.Outline): RoadObjectsObjectOutlinesOutline fun mapMaterialList(source: OpenDRIVE.Road.Objects.Object.Material?): List = source?.let { listOf(mapRoadObjectsObjectMaterial(it)) } ?: emptyList() + abstract fun mapRoadObjectsObjectMaterial(source: OpenDRIVE.Road.Objects.Object.Material): RoadObjectsObjectMaterial abstract fun mapParkingSpace(source: ParkingSpace): RoadObjectsObjectParkingSpace @@ -70,23 +71,25 @@ abstract class Opendrive14ObjectMapper { // fun mapRoadObjectTypeToOption(source: String?): Option = source?.let { mapRoadObjectType(it).some() } ?: None - fun mapRoadObjectType(source: String): EObjectType = when (source.uppercase()) { - in EObjectType.NONE.name.toUpperCaseVariations() -> EObjectType.NONE - in EObjectType.OBSTACLE.name.toUpperCaseVariations() -> EObjectType.OBSTACLE - in EObjectType.POLE.name.toUpperCaseVariations() -> EObjectType.POLE - in EObjectType.TREE.name.toUpperCaseVariations() -> EObjectType.TREE - in EObjectType.VEGETATION.name.toUpperCaseVariations() -> EObjectType.VEGETATION - in EObjectType.BARRIER.name.toUpperCaseVariations() -> EObjectType.BARRIER - in EObjectType.BUILDING.name.toUpperCaseVariations() -> EObjectType.BUILDING - in EObjectType.PARKING_SPACE.name.toUpperCaseVariations() -> EObjectType.PARKING_SPACE - in EObjectType.PATCH.name.toUpperCaseVariations() -> EObjectType.PATCH - in EObjectType.RAILING.name.toUpperCaseVariations() -> EObjectType.RAILING - in EObjectType.TRAFFIC_ISLAND.name.toUpperCaseVariations() -> EObjectType.TRAFFIC_ISLAND - in EObjectType.CROSSWALK.name.toUpperCaseVariations() -> EObjectType.CROSSWALK - in EObjectType.STREET_LAMP.name.toUpperCaseVariations() -> EObjectType.STREET_LAMP - in EObjectType.GANTRY.name.toUpperCaseVariations() -> EObjectType.GANTRY - in EObjectType.SOUND_BARRIER.name.toUpperCaseVariations() -> EObjectType.SOUND_BARRIER - in EObjectType.ROAD_MARK.name.toUpperCaseVariations() -> EObjectType.ROAD_MARK - else -> EObjectType.NONE - } + + fun mapRoadObjectType(source: String): EObjectType = + when (source.uppercase()) { + in EObjectType.NONE.name.toUpperCaseVariations() -> EObjectType.NONE + in EObjectType.OBSTACLE.name.toUpperCaseVariations() -> EObjectType.OBSTACLE + in EObjectType.POLE.name.toUpperCaseVariations() -> EObjectType.POLE + in EObjectType.TREE.name.toUpperCaseVariations() -> EObjectType.TREE + in EObjectType.VEGETATION.name.toUpperCaseVariations() -> EObjectType.VEGETATION + in EObjectType.BARRIER.name.toUpperCaseVariations() -> EObjectType.BARRIER + in EObjectType.BUILDING.name.toUpperCaseVariations() -> EObjectType.BUILDING + in EObjectType.PARKING_SPACE.name.toUpperCaseVariations() -> EObjectType.PARKING_SPACE + in EObjectType.PATCH.name.toUpperCaseVariations() -> EObjectType.PATCH + in EObjectType.RAILING.name.toUpperCaseVariations() -> EObjectType.RAILING + in EObjectType.TRAFFIC_ISLAND.name.toUpperCaseVariations() -> EObjectType.TRAFFIC_ISLAND + in EObjectType.CROSSWALK.name.toUpperCaseVariations() -> EObjectType.CROSSWALK + in EObjectType.STREET_LAMP.name.toUpperCaseVariations() -> EObjectType.STREET_LAMP + in EObjectType.GANTRY.name.toUpperCaseVariations() -> EObjectType.GANTRY + in EObjectType.SOUND_BARRIER.name.toUpperCaseVariations() -> EObjectType.SOUND_BARRIER + in EObjectType.ROAD_MARK.name.toUpperCaseVariations() -> EObjectType.ROAD_MARK + else -> EObjectType.NONE + } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14RoadMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14RoadMapper.kt index 0307f405..92818dd9 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14RoadMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14RoadMapper.kt @@ -45,12 +45,14 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, - uses = [OpendriveCommonMapper::class, Opendrive14CoreMapper::class, Opendrive14LaneMapper::class, Opendrive14ObjectMapper::class, Opendrive14SignalMapper::class], + uses = [ + OpendriveCommonMapper::class, Opendrive14CoreMapper::class, Opendrive14LaneMapper::class, Opendrive14ObjectMapper::class, + Opendrive14SignalMapper::class, + ], imports = [Option::class], - injectionStrategy = InjectionStrategy.CONSTRUCTOR + injectionStrategy = InjectionStrategy.CONSTRUCTOR, ) abstract class Opendrive14RoadMapper { - private val logger = KotlinLogging.logger {} // @@ -59,21 +61,27 @@ abstract class Opendrive14RoadMapper { abstract fun mapRoadLink(source: OpenDRIVE.Road.Link): RoadLink abstract fun mapRoadLinkPredecessor(source: OpenDRIVE.Road.Link.Predecessor): RoadLinkPredecessorSuccessor + abstract fun mapRoadLinkSuccessor(source: OpenDRIVE.Road.Link.Successor): RoadLinkPredecessorSuccessor // // Plan View // abstract fun mapPlanViewGeometryLine(source: OpenDRIVE.Road.PlanView.Geometry.Line): RoadPlanViewGeometryLine + abstract fun mapPlanViewGeometrySpiral(source: OpenDRIVE.Road.PlanView.Geometry.Spiral): RoadPlanViewGeometrySpiral + abstract fun mapPlanViewGeometryArc(source: OpenDRIVE.Road.PlanView.Geometry.Arc): RoadPlanViewGeometryArc + abstract fun mapPlanViewGeometryPoly3(source: OpenDRIVE.Road.PlanView.Geometry.Poly3): RoadPlanViewGeometryPoly3 + abstract fun mapPlanViewGeometryParamPoly3(source: OpenDRIVE.Road.PlanView.Geometry.ParamPoly3): RoadPlanViewGeometryParamPoly3 // // Profiles // abstract fun mapElevationProfile(source: OpenDRIVE.Road.ElevationProfile): RoadElevationProfile + abstract fun mapLateralProfile(source: OpenDRIVE.Road.LateralProfile): RoadLateralProfile @BeforeMapping @@ -90,15 +98,22 @@ abstract class Opendrive14RoadMapper { // Other Road Attributes // abstract fun mapRoadTypeSpeed(source: OpenDRIVE.Road.Type.Speed): RoadTypeSpeed + abstract fun mapRoadSurface(source: OpenDRIVE.Road.Surface): RoadSurface + abstract fun mapRoadRailroad(source: OpenDRIVE.Road.Railroad): RoadRailroad // // Enumerations // fun mapContactPointToOption(source: ContactPoint?): Option = source?.let { mapContactPoint(it).some() } ?: None + abstract fun mapContactPoint(source: ContactPoint): EContactPoint - fun mapERoadLinkElementTypeToOption(source: ElementType?): Option = source?.let { mapERoadLinkElementType(it).some() } ?: None + fun mapERoadLinkElementTypeToOption(source: ElementType?): Option = + source?.let { + mapERoadLinkElementType(it).some() + } ?: None + abstract fun mapERoadLinkElementType(source: ElementType): ERoadLinkElementType } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14SignalMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14SignalMapper.kt index 8ba18785..44f28d7e 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14SignalMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive14/Opendrive14SignalMapper.kt @@ -26,10 +26,9 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive14CoreMapper::class, Opendrive14ObjectMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive14SignalMapper { - // // Signal // diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16CoreMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16CoreMapper.kt index 41ef6eb2..1c51c2e2 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16CoreMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16CoreMapper.kt @@ -39,10 +39,9 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive16CoreMapper { - private val logger = KotlinLogging.logger {} // @@ -52,7 +51,9 @@ abstract class Opendrive16CoreMapper { return HeaderGeoReference(content = source.content.joinToString()).some() } - fun mapHeaderOffsetToOptionHeaderOffset(source: T_Header_Offset?): Option = source?.let { mapHeaderOffset(it).some() } ?: None + fun mapHeaderOffsetToOptionHeaderOffset(source: T_Header_Offset?): Option = + source?.let { mapHeaderOffset(it).some() } ?: None + abstract fun mapHeaderOffset(source: T_Header_Offset): HeaderOffset fun mapAdditionalData(source: List): List { @@ -63,36 +64,42 @@ abstract class Opendrive16CoreMapper { // Enumerations // fun mapEUnitSpeedToOption(source: E_UnitSpeed?): Option = source?.let { mapEUnitSpeed(it).some() } ?: None - fun mapEUnitSpeed(source: E_UnitSpeed): EUnitSpeed = when (source) { - E_UnitSpeed.M___S -> EUnitSpeed.METER_PER_SECOND - E_UnitSpeed.MPH -> EUnitSpeed.MILES_PER_HOUR - E_UnitSpeed.KM___H -> EUnitSpeed.KILOMETER_PER_HOUR - } + + fun mapEUnitSpeed(source: E_UnitSpeed): EUnitSpeed = + when (source) { + E_UnitSpeed.M___S -> EUnitSpeed.METER_PER_SECOND + E_UnitSpeed.MPH -> EUnitSpeed.MILES_PER_HOUR + E_UnitSpeed.KM___H -> EUnitSpeed.KILOMETER_PER_HOUR + } fun mapUnitToOptionEUnit(source: String?): Option = source?.let { mapUnitToEUnit(it).some() } ?: None - fun mapUnitToEUnit(source: String): EUnit = when (source) { - E_UnitDistance.M.value() -> EUnit.METER - E_UnitDistance.KM.value() -> EUnit.KILOMETER - E_UnitDistance.FT.value() -> EUnit.FEET - E_UnitDistance.MILE.value() -> EUnit.MILE - - E_UnitSpeed.M___S.value() -> EUnit.METER_PER_SECOND - E_UnitSpeed.MPH.value() -> EUnit.MILES_PER_HOUR - E_UnitSpeed.KM___H.value() -> EUnit.KILOMETER_PER_HOUR - - E_UnitMass.KG.value() -> EUnit.KILOGRAM - E_UnitMass.T.value() -> EUnit.TON - - E_UnitSlope.PERCENT.value() -> EUnit.PERCENT - else -> { - logger.error { "Unknown mapping of $source to EUnit (falling back to PERCENT)" } - EUnit.PERCENT + + fun mapUnitToEUnit(source: String): EUnit = + when (source) { + E_UnitDistance.M.value() -> EUnit.METER + E_UnitDistance.KM.value() -> EUnit.KILOMETER + E_UnitDistance.FT.value() -> EUnit.FEET + E_UnitDistance.MILE.value() -> EUnit.MILE + + E_UnitSpeed.M___S.value() -> EUnit.METER_PER_SECOND + E_UnitSpeed.MPH.value() -> EUnit.MILES_PER_HOUR + E_UnitSpeed.KM___H.value() -> EUnit.KILOMETER_PER_HOUR + + E_UnitMass.KG.value() -> EUnit.KILOGRAM + E_UnitMass.T.value() -> EUnit.TON + + E_UnitSlope.PERCENT.value() -> EUnit.PERCENT + else -> { + logger.error { "Unknown mapping of $source to EUnit (falling back to PERCENT)" } + EUnit.PERCENT + } } - } fun mapYesNoToOption(source: T_YesNo?): Option = source?.let { mapYesNo(it).some() } ?: None - fun mapYesNo(source: T_YesNo): Boolean = when (source) { - T_YesNo.YES -> true - T_YesNo.NO -> false - } + + fun mapYesNo(source: T_YesNo): Boolean = + when (source) { + T_YesNo.YES -> true + T_YesNo.NO -> false + } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16JunctionMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16JunctionMapper.kt index e35d8c56..07b3874f 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16JunctionMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16JunctionMapper.kt @@ -37,10 +37,9 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive16CoreMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive16JunctionMapper { - private val logger = KotlinLogging.logger {} fun mapJunctionSurfaceToOption(source: T_Junction_Surface?): Option = @@ -50,6 +49,7 @@ abstract class Opendrive16JunctionMapper { fun mapJunctionPredecessorSuccessorToOption(source: T_Junction_PredecessorSuccessor?): Option = source?.let { mapJunctionPredecessorSuccessor(it).some() } ?: None + abstract fun mapJunctionPredecessorSuccessor(source: T_Junction_PredecessorSuccessor): JunctionPredecessorSuccessor // @@ -57,28 +57,30 @@ abstract class Opendrive16JunctionMapper { // fun mapJunctionTypeToOptionEJunctionType(source: E_Junction_Type?): Option = source?.let { mapJunctionType(it).some() } ?: None + abstract fun mapJunctionType(source: E_Junction_Type): EJunctionType // This is an error in the schema of version 1.6, which is fixed by this mapping (enum attributes are the same) fun mapJunctionTypeToOptionEConnectionType(source: E_Junction_Type?): Option = source?.let { mapConnectionType(it).some() } ?: None + abstract fun mapConnectionType(source: E_Junction_Type): EConnectionType - fun mapContactPointToOption(source: String?): Option = - source?.let { mapContactPoint(it).some() } ?: None + fun mapContactPointToOption(source: String?): Option = source?.let { mapContactPoint(it).some() } ?: None - fun mapContactPoint(source: String): EContactPoint = when (source.uppercase()) { - in EContactPoint.START.name.toUpperCaseVariations() -> EContactPoint.START - in EContactPoint.END.name.toUpperCaseVariations() -> EContactPoint.END - else -> EContactPoint.START - } + fun mapContactPoint(source: String): EContactPoint = + when (source.uppercase()) { + in EContactPoint.START.name.toUpperCaseVariations() -> EContactPoint.START + in EContactPoint.END.name.toUpperCaseVariations() -> EContactPoint.END + else -> EContactPoint.START + } - fun mapElementDirToOption(source: String?): Option = - source?.let { mapElementDir(it).some() } ?: None + fun mapElementDirToOption(source: String?): Option = source?.let { mapElementDir(it).some() } ?: None - fun mapElementDir(source: String): EElementDir = when (source.uppercase()) { - in "+" -> EElementDir.PLUS - in "-" -> EElementDir.MINUS - else -> EElementDir.PLUS - } + fun mapElementDir(source: String): EElementDir = + when (source.uppercase()) { + in "+" -> EElementDir.PLUS + in "-" -> EElementDir.MINUS + else -> EElementDir.PLUS + } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16LaneMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16LaneMapper.kt index 1fe981b0..ba893c8f 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16LaneMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16LaneMapper.kt @@ -70,10 +70,9 @@ import org.mapstruct.ValueMapping @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive16CoreMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive16LaneMapper { - abstract fun mapRoadLanes(sources: T_Road_Lanes): RoadLanes // @@ -85,37 +84,67 @@ abstract class Opendrive16LaneMapper { // Lane // abstract fun mapRoadLanesLaneSectionCenter(source: T_Road_Lanes_LaneSection_Center): RoadLanesLaneSectionCenter + abstract fun mapRoadLanesLaneSectionLeft(source: T_Road_Lanes_LaneSection_Left): RoadLanesLaneSectionLeft + abstract fun mapRoadLanesLaneSectionRight(source: T_Road_Lanes_LaneSection_Right): RoadLanesLaneSectionRight abstract fun mapRoadLanesLaneSectionCenterLane(source: T_Road_Lanes_LaneSection_Center_Lane): RoadLanesLaneSectionCenterLane @AfterMapping - open fun afterMappingRoadLanesLaneSectionCenterLane(source: T_Road_Lanes_LaneSection_Center_Lane, @MappingTarget target: RoadLanesLaneSectionCenterLane) { - target.border = source.borderOrWidth.filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Border::class.java).map { mapLrLaneBorder(it) } - target.width = source.borderOrWidth.filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Width::class.java).map { mapLrLaneWidth(it) } + open fun afterMappingRoadLanesLaneSectionCenterLane( + source: T_Road_Lanes_LaneSection_Center_Lane, + @MappingTarget target: RoadLanesLaneSectionCenterLane, + ) { + target.border = + source.borderOrWidth + .filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Border::class.java) + .map { mapLrLaneBorder(it) } + target.width = + source.borderOrWidth + .filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Width::class.java) + .map { mapLrLaneWidth(it) } } abstract fun mapRoadLanesLaneSectionLeftLane(source: T_Road_Lanes_LaneSection_Left_Lane): RoadLanesLaneSectionLeftLane @AfterMapping - open fun afterMappingRoadLanesLaneSectionLeftLane(source: T_Road_Lanes_LaneSection_Left_Lane, @MappingTarget target: RoadLanesLaneSectionLeftLane) { - target.border = source.borderOrWidth.filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Border::class.java).map { mapLrLaneBorder(it) } - target.width = source.borderOrWidth.filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Width::class.java).map { mapLrLaneWidth(it) } + open fun afterMappingRoadLanesLaneSectionLeftLane( + source: T_Road_Lanes_LaneSection_Left_Lane, + @MappingTarget target: RoadLanesLaneSectionLeftLane, + ) { + target.border = + source.borderOrWidth + .filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Border::class.java) + .map { mapLrLaneBorder(it) } + target.width = + source.borderOrWidth + .filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Width::class.java) + .map { mapLrLaneWidth(it) } } abstract fun mapRoadLanesLaneSectionRightLane(source: T_Road_Lanes_LaneSection_Right_Lane): RoadLanesLaneSectionRightLane @AfterMapping - open fun afterMappingRoadLanesLaneSectionRightLane(source: T_Road_Lanes_LaneSection_Right_Lane, @MappingTarget target: RoadLanesLaneSectionRightLane) { - target.border = source.borderOrWidth.filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Border::class.java).map { mapLrLaneBorder(it) } - target.width = source.borderOrWidth.filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Width::class.java).map { mapLrLaneWidth(it) } + open fun afterMappingRoadLanesLaneSectionRightLane( + source: T_Road_Lanes_LaneSection_Right_Lane, + @MappingTarget target: RoadLanesLaneSectionRightLane, + ) { + target.border = + source.borderOrWidth + .filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Border::class.java) + .map { mapLrLaneBorder(it) } + target.width = + source.borderOrWidth + .filterIsInstance(T_Road_Lanes_LaneSection_Lr_Lane_Width::class.java) + .map { mapLrLaneWidth(it) } } // // Lane Border and Width // abstract fun mapLrLaneWidth(source: T_Road_Lanes_LaneSection_Lr_Lane_Width): RoadLanesLaneSectionLRLaneWidth + abstract fun mapLrLaneBorder(source: T_Road_Lanes_LaneSection_Lr_Lane_Border): RoadLanesLaneSectionLRLaneBorder // @@ -129,20 +158,28 @@ abstract class Opendrive16LaneMapper { abstract fun mapLaneRoadMark(source: T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark): RoadLanesLaneSectionLCRLaneRoadMark abstract fun mapLaneRoadMarkType(source: T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Type): RoadLanesLaneSectionLCRLaneRoadMarkType - abstract fun mapLaneRoadMarkTypeLine(source: T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Type_Line): RoadLanesLaneSectionLCRLaneRoadMarkTypeLine - abstract fun mapLaneRoadMarkExplicit(source: T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Explicit): RoadLanesLaneSectionLCRLaneRoadMarkExplicit + abstract fun mapLaneRoadMarkTypeLine( + source: T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Type_Line, + ): RoadLanesLaneSectionLCRLaneRoadMarkTypeLine + + abstract fun mapLaneRoadMarkExplicit( + source: T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Explicit, + ): RoadLanesLaneSectionLCRLaneRoadMarkExplicit // // Enumerations // fun mapBoolToOption(source: T_Bool?): Option = source?.let { mapBool(it).some() } ?: None - fun mapBool(source: T_Bool): Boolean = when (source) { - T_Bool.TRUE -> true - T_Bool.FALSE -> false - } + + fun mapBool(source: T_Bool): Boolean = + when (source) { + T_Bool.TRUE -> true + T_Bool.FALSE -> false + } fun mapERoadMarkColorToOption(source: E_RoadMarkColor?): Option = source?.let { mapRoadMarkColor(it).some() } ?: None + abstract fun mapRoadMarkColor(source: E_RoadMarkColor): ERoadMarkColor fun mapERoadMarkRuleToOption(source: E_RoadMarkRule?): Option = source?.let { mapRoadMarkRule(it).some() } ?: None @@ -150,10 +187,19 @@ abstract class Opendrive16LaneMapper { @ValueMapping(source = "NO___PASSING", target = "NO_PASSING") abstract fun mapRoadMarkRule(source: E_RoadMarkRule): ERoadMarkRule - fun mapRoadMarkLaneChangeToOption(source: E_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_LaneChange?): Option = source?.let { mapRoadMarkLaneChange(it).some() } ?: None - abstract fun mapRoadMarkLaneChange(source: E_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_LaneChange): ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange + fun mapRoadMarkLaneChangeToOption( + source: E_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_LaneChange?, + ): Option = + source?.let { + mapRoadMarkLaneChange(it).some() + } ?: None + + abstract fun mapRoadMarkLaneChange( + source: E_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_LaneChange, + ): ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange fun mapRoadMarkWeightToOption(source: E_RoadMarkWeight?): Option = source?.let { mapRoadMarkWeight(it).some() } ?: None + abstract fun mapRoadMarkWeight(source: E_RoadMarkWeight): ERoadMarkWeight @ValueMapping(source = "SOLID___SOLID", target = "SOLID_SOLID") diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16Mapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16Mapper.kt index e1342106..c6dd7db9 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16Mapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16Mapper.kt @@ -26,10 +26,9 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive16CoreMapper::class, Opendrive16JunctionMapper::class, Opendrive16RoadMapper::class], - imports = [arrow.core.Option::class] + imports = [arrow.core.Option::class], ) abstract class Opendrive16Mapper { - private val logger = KotlinLogging.logger {} abstract fun mapModel(model: OpenDRIVE): OpendriveModel diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16ObjectMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16ObjectMapper.kt index ee2dd72f..966b2d01 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16ObjectMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16ObjectMapper.kt @@ -53,10 +53,9 @@ import org.mapstruct.ValueMapping @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive16CoreMapper::class, Opendrive16LaneMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive16ObjectMapper { - // // Road Objects // @@ -66,15 +65,19 @@ abstract class Opendrive16ObjectMapper { abstract fun mapRoadObjectsObject(source: T_Road_Objects_Object): RoadObjectsObject @AfterMapping - open fun afterMappingRoadObjectsObject(source: T_Road_Objects_Object, @MappingTarget target: RoadObjectsObject) { + open fun afterMappingRoadObjectsObject( + source: T_Road_Objects_Object, + @MappingTarget target: RoadObjectsObject, + ) { // after mapping deprecated outline element by creating a new container or // appending it to preexisting outlines container source.outline.toOption().onSome { sourceOutline -> val outline = mapRoadObjectsObjectOutlinesOutline(sourceOutline) - target.outlines = target.outlines.fold( - { RoadObjectsObjectOutlines(outline = listOf(outline)) }, - { RoadObjectsObjectOutlines(outline = it.outline + outline) } - ).some() + target.outlines = + target.outlines.fold( + { RoadObjectsObjectOutlines(outline = listOf(outline)) }, + { RoadObjectsObjectOutlines(outline = it.outline + outline) }, + ).some() } } @@ -82,11 +85,14 @@ abstract class Opendrive16ObjectMapper { // Outline // abstract fun mapRoadObjectsObjectOutlines(source: T_Road_Objects_Object_Outlines): RoadObjectsObjectOutlines + abstract fun mapRoadObjectsObjectOutlinesOutline(source: T_Road_Objects_Object_Outlines_Outline): RoadObjectsObjectOutlinesOutline // abstract fun mapRoadObjectsObjectParkingSpace(source: T_Road_Objects_Object_ParkingSpace): RoadObjectsObjectParkingSpace + abstract fun mapRoadObjectsObjectMarkings(source: T_Road_Objects_Object_Markings): RoadObjectsObjectMarkings + abstract fun mapRoadObjectsObjectBorders(source: T_Road_Objects_Object_Borders): RoadObjectsObjectBorders // @@ -94,18 +100,18 @@ abstract class Opendrive16ObjectMapper { // fun mapOutlineFileTypeToOption(source: E_OutlineFillType?): Option = source?.let { mapOutlineFileType(it).some() } ?: None + abstract fun mapOutlineFileType(source: E_OutlineFillType): EOutlineFillType - fun mapLaneTypeToOption(source: E_LaneType?): Option = - source?.let { mapLaneType(it).some() } ?: None + fun mapLaneTypeToOption(source: E_LaneType?): Option = source?.let { mapLaneType(it).some() } ?: None + abstract fun mapLaneType(source: E_LaneType): ELaneType - fun mapSideTypeToOption(source: E_SideType?): Option = - source?.let { mapSideType(it).some() } ?: None + fun mapSideTypeToOption(source: E_SideType?): Option = source?.let { mapSideType(it).some() } ?: None + abstract fun mapSideType(source: E_SideType): ESideType - fun mapObjectTypeToOption(source: E_ObjectType?): Option = - source?.let { mapObjectType(it).some() } ?: None + fun mapObjectTypeToOption(source: E_ObjectType?): Option = source?.let { mapObjectType(it).some() } ?: None @ValueMapping(source = "CAR", target = "NONE") @ValueMapping(source = "VAN", target = "NONE") diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16RoadMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16RoadMapper.kt index 6ea0f5c6..03d35ea0 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16RoadMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16RoadMapper.kt @@ -58,18 +58,21 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, - uses = [OpendriveCommonMapper::class, Opendrive16CoreMapper::class, Opendrive16LaneMapper::class, Opendrive16ObjectMapper::class, Opendrive16JunctionMapper::class, Opendrive16SignalMapper::class], + uses = [ + OpendriveCommonMapper::class, Opendrive16CoreMapper::class, Opendrive16LaneMapper::class, Opendrive16ObjectMapper::class, + Opendrive16JunctionMapper::class, Opendrive16SignalMapper::class, + ], imports = [Option::class], - injectionStrategy = InjectionStrategy.CONSTRUCTOR + injectionStrategy = InjectionStrategy.CONSTRUCTOR, ) abstract class Opendrive16RoadMapper { - abstract fun mapRoad(source: T_Road): Road // // Road Link // abstract fun mapRoadLink(source: T_Road_Link): RoadLink + abstract fun mapRoadLinkPredecessorSuccessor(source: T_Road_Link_PredecessorSuccessor): RoadLinkPredecessorSuccessor // @@ -83,15 +86,20 @@ abstract class Opendrive16RoadMapper { abstract fun mapPlanViewGeometry(source: T_Road_PlanView_Geometry): RoadPlanViewGeometry abstract fun mapPlanViewGeometryLine(source: T_Road_PlanView_Geometry_Line): RoadPlanViewGeometryLine + abstract fun mapPlanViewGeometrySpiral(source: T_Road_PlanView_Geometry_Spiral): RoadPlanViewGeometrySpiral + abstract fun mapPlanViewGeometryArc(source: T_Road_PlanView_Geometry_Arc): RoadPlanViewGeometryArc + abstract fun mapPlanViewGeometryPoly3(source: T_Road_PlanView_Geometry_Poly3): RoadPlanViewGeometryPoly3 + abstract fun mapPlanViewGeometryParamPoly3(source: T_Road_PlanView_Geometry_ParamPoly3): RoadPlanViewGeometryParamPoly3 // // Profiles // abstract fun mapElevationProfile(source: T_Road_ElevationProfile): RoadElevationProfile + abstract fun mapLateralProfile(source: T_Road_LateralProfile): RoadLateralProfile // @@ -107,20 +115,20 @@ abstract class Opendrive16RoadMapper { // // Enumerations // - fun mapElementTypeToOption(source: String?): Option = - source?.let { mapElementType(it).some() } ?: None - - fun mapElementType(source: String): ERoadLinkElementType = when (source.uppercase()) { - in ERoadLinkElementType.ROAD.name.toUpperCaseVariations() -> ERoadLinkElementType.ROAD - in ERoadLinkElementType.JUNCTION.name.toUpperCaseVariations() -> ERoadLinkElementType.JUNCTION - else -> ERoadLinkElementType.ROAD - } - - fun mapTrafficRuleToOption(source: E_TrafficRule?): Option = - source?.let { mapTrafficRule(it).some() } ?: None - - fun mapTrafficRule(source: E_TrafficRule): ETrafficRule = when (source) { - E_TrafficRule.RHT -> ETrafficRule.RIGHT_HAND_TRAFFIC - E_TrafficRule.LHT -> ETrafficRule.LEFT_HAND_TRAFFIC - } + fun mapElementTypeToOption(source: String?): Option = source?.let { mapElementType(it).some() } ?: None + + fun mapElementType(source: String): ERoadLinkElementType = + when (source.uppercase()) { + in ERoadLinkElementType.ROAD.name.toUpperCaseVariations() -> ERoadLinkElementType.ROAD + in ERoadLinkElementType.JUNCTION.name.toUpperCaseVariations() -> ERoadLinkElementType.JUNCTION + else -> ERoadLinkElementType.ROAD + } + + fun mapTrafficRuleToOption(source: E_TrafficRule?): Option = source?.let { mapTrafficRule(it).some() } ?: None + + fun mapTrafficRule(source: E_TrafficRule): ETrafficRule = + when (source) { + E_TrafficRule.RHT -> ETrafficRule.RIGHT_HAND_TRAFFIC + E_TrafficRule.LHT -> ETrafficRule.LEFT_HAND_TRAFFIC + } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16SignalMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16SignalMapper.kt index 8bc737b6..80243b4a 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16SignalMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive16/Opendrive16SignalMapper.kt @@ -30,15 +30,15 @@ import org.mapstruct.NullValueCheckStrategy @Mapper( nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive16CoreMapper::class, Opendrive16ObjectMapper::class], - imports = [Option::class] + imports = [Option::class], ) abstract class Opendrive16SignalMapper { - // // Signal // abstract fun mapSignals(source: T_Road_Signals): RoadSignals abstract fun mapSignalsSignalPositionInertial(source: T_Road_Signals_Signal_PositionInertial): RoadSignalsSignalPositionInertial + abstract fun mapSignalsSignalPositionRoad(source: T_Road_Signals_Signal_PositionRoad): RoadSignalsSignalPositionRoad } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive17/Opendrive17Mapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive17/Opendrive17Mapper.kt index 2e2cac0b..32016b44 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive17/Opendrive17Mapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/mapper/opendrive17/Opendrive17Mapper.kt @@ -24,7 +24,6 @@ import org.mapstruct.NullValueCheckStrategy @Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS) abstract class Opendrive17Mapper { - @Mapping(target = "header", ignore = true) @Mapping(target = "road", ignore = true) @Mapping(target = "controller", ignore = true) diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/validation/OpendriveValidationEventHandler.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/validation/OpendriveValidationEventHandler.kt index 7e7d0249..6b9a2027 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/validation/OpendriveValidationEventHandler.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/reader/validation/OpendriveValidationEventHandler.kt @@ -23,7 +23,6 @@ import jakarta.xml.bind.ValidationEvent import jakarta.xml.bind.ValidationEventHandler class OpendriveValidationEventHandler : ValidationEventHandler { - // Properties and Initializers val validationEvents: MutableList = mutableListOf() diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/ReportExtensions.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/ReportExtensions.kt index 0529e915..6ba4cf92 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/ReportExtensions.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/ReportExtensions.kt @@ -21,12 +21,13 @@ import jakarta.xml.bind.ValidationEvent fun ValidationEvent.toIssue(): SchemaValidationIssue { val text = this.message ?: "" - val severity = when (this.severity) { - ValidationEvent.WARNING -> Severity.WARNING - ValidationEvent.ERROR -> Severity.ERROR - ValidationEvent.FATAL_ERROR -> Severity.FATAL_ERROR - else -> Severity.WARNING - } + val severity = + when (this.severity) { + ValidationEvent.WARNING -> Severity.WARNING + ValidationEvent.ERROR -> Severity.ERROR + ValidationEvent.FATAL_ERROR -> Severity.FATAL_ERROR + else -> Severity.WARNING + } val lineNumber = this.locator.lineNumber val columnNumber = this.locator.columnNumber diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/SchemaValidationIssue.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/SchemaValidationIssue.kt index 5beb65ed..1c9c5ad9 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/SchemaValidationIssue.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/SchemaValidationIssue.kt @@ -24,5 +24,5 @@ data class SchemaValidationIssue( val description: String, val severity: Severity, val lineNumber: Int, - val columnNumber: Int + val columnNumber: Int, ) diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/SchemaValidationReport.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/SchemaValidationReport.kt index 9648d059..95fd0216 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/SchemaValidationReport.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/report/SchemaValidationReport.kt @@ -24,15 +24,11 @@ import kotlinx.serialization.Serializable @Serializable class SchemaValidationReport( val opendriveVersion: OpendriveVersion, - val validationIssues: IssueList = IssueList(), - val completedSuccessfully: Boolean = true, - val validationAbortIssue: String = "" + val validationAbortIssue: String = "", ) { - fun validationProcessAborted() = !completedSuccessfully - fun containsFatalErrorIssues(): Boolean = - validationIssues.getIssues().any { it.severity == Severity.FATAL_ERROR } + fun containsFatalErrorIssues(): Boolean = validationIssues.getIssues().any { it.severity == Severity.FATAL_ERROR } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/version/OpendriveVersion.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/version/OpendriveVersion.kt index c9e0c426..1e075671 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/version/OpendriveVersion.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/version/OpendriveVersion.kt @@ -27,7 +27,6 @@ import io.rtron.std.getValueEither * Wikipedia: https://en.wikipedia.org/wiki/OpenDRIVE_(specification) */ enum class OpendriveVersion(val rev: Pair) { - /** * OpenDRIVE version 0.7 released 2005 by VIRES Simulationstechnologie GmbH. */ @@ -66,7 +65,8 @@ enum class OpendriveVersion(val rev: Pair) { /** * OpenDRIVE version 1.7.0 released on the 03 Aug 2021 by ASAM e.V. */ - V1_7(Pair(1, 7)); + V1_7(Pair(1, 7)), + ; // Methods override fun toString() = "v.${rev.first}.${rev.second}" @@ -74,9 +74,13 @@ enum class OpendriveVersion(val rev: Pair) { companion object { private val map = OpendriveVersion.entries.associateBy(OpendriveVersion::rev) - fun ofRevision(revMajor: Int, revMinor: Int): Either = + fun ofRevision( + revMajor: Int, + revMinor: Int, + ): Either = map.getValueEither(Pair(revMajor, revMinor)).mapLeft { UnknownOpendriveVersion(it.message) } - data class UnknownOpendriveVersion(val message: String) // : OpendriveReaderException("Version of OpenDRIVE dataset not deducible: $reason") + data class UnknownOpendriveVersion(val message: String) + // : OpendriveReaderException("Version of OpenDRIVE dataset not deducible: $reason") } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/version/OpendriveVersionUtils.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/version/OpendriveVersionUtils.kt index 03fcc850..ab639da0 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/version/OpendriveVersionUtils.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/version/OpendriveVersionUtils.kt @@ -25,27 +25,30 @@ import java.io.InputStream import javax.xml.parsers.DocumentBuilderFactory object OpendriveVersionUtils { + fun getOpendriveVersion(filePath: InputStream): Either = + either { + val xmlDoc: Document = + Either.catch { DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(filePath) } + .mapLeft { OpendriveReaderException.MalformedXmlDocument(it.message ?: "") } + .bind() - fun getOpendriveVersion(filePath: InputStream): Either = either { - val xmlDoc: Document = Either.catch { DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(filePath) } - .mapLeft { OpendriveReaderException.MalformedXmlDocument(it.message ?: "") } - .bind() + val header = xmlDoc.getElementsByTagName("header") + if (header.length <= 0) { + OpendriveReaderException.HeaderElementNotFound("No header element available").left().bind() + } + if (header.length > 1) { + OpendriveReaderException.HeaderElementNotFound("Multiple header elements available").left().bind() + } - val header = xmlDoc.getElementsByTagName("header") - if (header.length <= 0) { - OpendriveReaderException.HeaderElementNotFound("No header element available").left().bind() - } - if (header.length > 1) { - OpendriveReaderException.HeaderElementNotFound("Multiple header elements available").left().bind() - } + val revMajor = + Either.catch { header.item(0).attributes.getNamedItem("revMajor").nodeValue.toInt() } + .mapLeft { OpendriveReaderException.VersionNotIdentifiable("Major version is not identifiable") } + .bind() + val revMinor = + Either.catch { header.item(0).attributes.getNamedItem("revMinor").nodeValue.toInt() } + .mapLeft { OpendriveReaderException.VersionNotIdentifiable("Minor version is not identifiable") } + .bind() - val revMajor = Either.catch { header.item(0).attributes.getNamedItem("revMajor").nodeValue.toInt() } - .mapLeft { OpendriveReaderException.VersionNotIdentifiable("Major version is not identifiable") } - .bind() - val revMinor = Either.catch { header.item(0).attributes.getNamedItem("revMinor").nodeValue.toInt() } - .mapLeft { OpendriveReaderException.VersionNotIdentifiable("Minor version is not identifiable") } - .bind() - - OpendriveVersion.ofRevision(revMajor, revMinor).mapLeft { OpendriveReaderException.VersionNotIdentifiable(it.message) }.bind() - } + OpendriveVersion.ofRevision(revMajor, revMinor).mapLeft { OpendriveReaderException.VersionNotIdentifiable(it.message) }.bind() + } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/OpendriveMarshaller.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/OpendriveMarshaller.kt index e0a7ea6a..2eafb722 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/OpendriveMarshaller.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/OpendriveMarshaller.kt @@ -26,7 +26,6 @@ import java.io.OutputStream import kotlin.io.path.div class OpendriveMarshaller { - // Properties and Initializers val supportedVersion: OpendriveVersion = OpendriveVersion.V1_7 private val jaxbMarshaller: Marshaller @@ -40,7 +39,10 @@ class OpendriveMarshaller { // Methods - fun writeToStream(model: OpendriveModel, outputStream: OutputStream) { + fun writeToStream( + model: OpendriveModel, + outputStream: OutputStream, + ) { val converter = Mappers.getMapper(Opendrive17Mapper::class.java) val opendrive17Model = converter.mapModel(model) diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/common/OpendriveCommonMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/common/OpendriveCommonMapper.kt index b518eb71..e2408361 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/common/OpendriveCommonMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/common/OpendriveCommonMapper.kt @@ -23,10 +23,11 @@ import org.mapstruct.NullValueCheckStrategy @Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS) abstract class OpendriveCommonMapper { - fun mapNullableToOption(source: T?): Option = Option.fromNullable(source) fun mapOptionDoubleToNullableDouble(source: Option): Double? = source.getOrElse { return null } + fun mapOptionStringToNullableString(source: Option): String? = source.getOrElse { return null } + fun mapOptionIntegerToNullableInteger(source: Option): Int? = source.getOrElse { return null } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17CoreMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17CoreMapper.kt index 7e6a898a..5c864209 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17CoreMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17CoreMapper.kt @@ -37,13 +37,13 @@ import org.mapstruct.NullValueCheckStrategy @Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class]) abstract class Opendrive17CoreMapper { - // // Header // abstract fun mapHeader(source: Header): T_Header fun mapOptionGeoReference(source: Option): T_Header_GeoReference? = source.fold({ null }, { mapGeoReference(it) }) + fun mapGeoReference(source: HeaderGeoReference): T_Header_GeoReference { return T_Header_GeoReference().apply { content.add("![CDATA[${source.content}]]") // TODO @@ -51,38 +51,45 @@ abstract class Opendrive17CoreMapper { } fun mapOptionHeaderOffset(source: Option): T_Header_Offset? = source.fold({ null }, { mapHeaderOffset(it) }) + abstract fun mapHeaderOffset(source: HeaderOffset): T_Header_Offset // // Enumerations // fun mapOptionEUnitToString(source: Option): String? = source.fold({ null }, { mapEUnitToString(it) }) - fun mapEUnitToString(source: EUnit): String = when (source) { - EUnit.METER -> E_UnitDistance.M.value()!! - EUnit.KILOMETER -> E_UnitDistance.KM.value()!! - EUnit.FEET -> E_UnitDistance.FT.value()!! - EUnit.MILE -> E_UnitDistance.M.value()!! - EUnit.METER_PER_SECOND -> E_UnitSpeed.M___S.value()!! - EUnit.MILES_PER_HOUR -> E_UnitSpeed.MPH.value()!! - EUnit.KILOMETER_PER_HOUR -> E_UnitSpeed.KM___H.value()!! + fun mapEUnitToString(source: EUnit): String = + when (source) { + EUnit.METER -> E_UnitDistance.M.value()!! + EUnit.KILOMETER -> E_UnitDistance.KM.value()!! + EUnit.FEET -> E_UnitDistance.FT.value()!! + EUnit.MILE -> E_UnitDistance.M.value()!! - EUnit.KILOGRAM -> E_UnitMass.KG.value()!! - EUnit.TON -> E_UnitMass.T.value()!! + EUnit.METER_PER_SECOND -> E_UnitSpeed.M___S.value()!! + EUnit.MILES_PER_HOUR -> E_UnitSpeed.MPH.value()!! + EUnit.KILOMETER_PER_HOUR -> E_UnitSpeed.KM___H.value()!! - EUnit.PERCENT -> E_UnitSlope.PERCENT.value()!! - } + EUnit.KILOGRAM -> E_UnitMass.KG.value()!! + EUnit.TON -> E_UnitMass.T.value()!! + + EUnit.PERCENT -> E_UnitSlope.PERCENT.value()!! + } fun mapOptionEUnitSpeed(source: Option): E_UnitSpeed? = source.fold({ null }, { mapEUnitSpeed(it) }) - fun mapEUnitSpeed(source: EUnitSpeed): E_UnitSpeed = when (source) { - EUnitSpeed.METER_PER_SECOND -> E_UnitSpeed.M___S - EUnitSpeed.MILES_PER_HOUR -> E_UnitSpeed.MPH - EUnitSpeed.KILOMETER_PER_HOUR -> E_UnitSpeed.KM___H - } + + fun mapEUnitSpeed(source: EUnitSpeed): E_UnitSpeed = + when (source) { + EUnitSpeed.METER_PER_SECOND -> E_UnitSpeed.M___S + EUnitSpeed.MILES_PER_HOUR -> E_UnitSpeed.MPH + EUnitSpeed.KILOMETER_PER_HOUR -> E_UnitSpeed.KM___H + } fun mapOptionBooleanToBool(source: Option): T_Bool? = source.fold({ null }, { mapBooleanToBool(it) }) + fun mapBooleanToBool(source: Boolean): T_Bool = if (source) T_Bool.TRUE else T_Bool.FALSE fun mapOptionBooleanToYesNo(source: Option): T_YesNo? = source.fold({ null }, { mapBooleanToYesNo(it) }) + fun mapBooleanToYesNo(source: Boolean): T_YesNo = if (source) T_YesNo.YES else T_YesNo.NO } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17JunctionMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17JunctionMapper.kt index ff196133..e7cd039c 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17JunctionMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17JunctionMapper.kt @@ -33,19 +33,22 @@ import org.asam.opendrive17.T_Junction_Surface import org.mapstruct.Mapper import org.mapstruct.NullValueCheckStrategy -@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive17CoreMapper::class, Opendrive17ObjectMapper::class]) +@Mapper( + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + uses = [OpendriveCommonMapper::class, Opendrive17CoreMapper::class, Opendrive17ObjectMapper::class], +) abstract class Opendrive17JunctionMapper { - // // Junction // abstract fun mapJunction(source: Junction): T_Junction - fun mapOptionJunctionSurface(source: Option): T_Junction_Surface? = - source.fold({ null }, { mapJunctionSurface(it) }) + fun mapOptionJunctionSurface(source: Option): T_Junction_Surface? = source.fold({ null }, { mapJunctionSurface(it) }) + abstract fun mapJunctionSurface(source: JunctionSurface): T_Junction_Surface fun mapOptionEJunctionType(source: Option): E_Junction_Type? = source.fold({ null }, { mapEJunctionType(it) }) + abstract fun mapEJunctionType(source: EJunctionType): E_Junction_Type // @@ -53,14 +56,18 @@ abstract class Opendrive17JunctionMapper { // fun mapOptionJunctionPredecessorSuccessor(source: Option): T_Junction_PredecessorSuccessor? = source.fold({ null }, { mapJunctionPredecessorSuccessor(it) }) + abstract fun mapJunctionPredecessorSuccessor(source: JunctionPredecessorSuccessor): T_Junction_PredecessorSuccessor fun mapOptionEContactPoint(source: Option): E_ContactPoint? = source.fold({ null }, { mapEContactPoint(it) }) - fun mapEContactPoint(source: EContactPoint): E_ContactPoint = when (source) { - EContactPoint.START -> E_ContactPoint.START - EContactPoint.END -> E_ContactPoint.END - } + + fun mapEContactPoint(source: EContactPoint): E_ContactPoint = + when (source) { + EContactPoint.START -> E_ContactPoint.START + EContactPoint.END -> E_ContactPoint.END + } fun mapOptionConnectionType(source: Option): E_Connection_Type? = source.fold({ null }, { mapConnectionType(it) }) + abstract fun mapConnectionType(source: EConnectionType): E_Connection_Type } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17LaneMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17LaneMapper.kt index 8f42d5c2..bef4cf0e 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17LaneMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17LaneMapper.kt @@ -57,7 +57,11 @@ import org.mapstruct.MappingTarget import org.mapstruct.NullValueCheckStrategy import org.mapstruct.ValueMapping -@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive17CoreMapper::class], imports = [Option::class]) +@Mapper( + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + uses = [OpendriveCommonMapper::class, Opendrive17CoreMapper::class], + imports = [Option::class], +) abstract class Opendrive17LaneMapper { // // Lane Section @@ -66,10 +70,12 @@ abstract class Opendrive17LaneMapper { fun mapRoadLanesLaneSectionLeft(source: Option): T_Road_Lanes_LaneSection_Left? = source.fold({ null }, { mapRoadLanesLaneSectionLeft(it) }) + abstract fun mapRoadLanesLaneSectionLeft(source: RoadLanesLaneSectionLeft): T_Road_Lanes_LaneSection_Left fun mapOptionRoadLanesLaneSectionRight(source: Option): T_Road_Lanes_LaneSection_Right? = source.fold({ null }, { mapRoadLanesLaneSectionRight(it) }) + abstract fun mapRoadLanesLaneSectionRight(source: RoadLanesLaneSectionRight): T_Road_Lanes_LaneSection_Right // @@ -79,7 +85,10 @@ abstract class Opendrive17LaneMapper { abstract fun mapRoadLanesLaneSectionCenterLane(source: RoadLanesLaneSectionCenterLane): T_Road_Lanes_LaneSection_Center_Lane @AfterMapping - fun afterRoadLanesLaneSectionCenterLane(source: RoadLanesLaneSectionCenterLane, @MappingTarget target: T_Road_Lanes_LaneSection_Center_Lane) { + fun afterRoadLanesLaneSectionCenterLane( + source: RoadLanesLaneSectionCenterLane, + @MappingTarget target: T_Road_Lanes_LaneSection_Center_Lane, + ) { target.borderOrWidth += source.border.map { mapRoadLanesLaneSectionLRLaneBorder(it) } } @@ -87,7 +96,10 @@ abstract class Opendrive17LaneMapper { abstract fun mapRoadLanesLaneSectionLeftLane(source: RoadLanesLaneSectionLeftLane): T_Road_Lanes_LaneSection_Left_Lane @AfterMapping - fun afterRoadLanesLaneSectionLeftLane(source: RoadLanesLaneSectionLeftLane, @MappingTarget target: T_Road_Lanes_LaneSection_Left_Lane) { + fun afterRoadLanesLaneSectionLeftLane( + source: RoadLanesLaneSectionLeftLane, + @MappingTarget target: T_Road_Lanes_LaneSection_Left_Lane, + ) { target.borderOrWidth += source.border.map { mapRoadLanesLaneSectionLRLaneBorder(it) } } @@ -95,35 +107,53 @@ abstract class Opendrive17LaneMapper { abstract fun mapRoadLanesLaneSectionLeftRight(source: RoadLanesLaneSectionRightLane): T_Road_Lanes_LaneSection_Right_Lane @AfterMapping - fun afterRoadLanesLaneSectionRightLane(source: RoadLanesLaneSectionRightLane, @MappingTarget target: T_Road_Lanes_LaneSection_Right_Lane) { + fun afterRoadLanesLaneSectionRightLane( + source: RoadLanesLaneSectionRightLane, + @MappingTarget target: T_Road_Lanes_LaneSection_Right_Lane, + ) { target.borderOrWidth += source.border.map { mapRoadLanesLaneSectionLRLaneBorder(it) } } fun mapOptionRoadLanesLaneSectionLCRLaneLink(source: Option): T_Road_Lanes_LaneSection_Lcr_Lane_Link? = source.fold({ null }, { mapRoadLanesLaneSectionLCRLaneLink(it) }) + abstract fun mapRoadLanesLaneSectionLCRLaneLink(source: RoadLanesLaneSectionLCRLaneLink): T_Road_Lanes_LaneSection_Lcr_Lane_Link abstract fun mapRoadLanesLaneSectionLRLaneWidth(source: RoadLanesLaneSectionLRLaneWidth): T_Road_Lanes_LaneSection_Lr_Lane_Width + abstract fun mapRoadLanesLaneSectionLRLaneBorder(source: RoadLanesLaneSectionLRLaneBorder): T_Road_Lanes_LaneSection_Lr_Lane_Border // // Road Mark // - fun mapOptionRoadLanesLaneSectionLCRLaneRoadMarkType(source: Option): T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Type? = - source.fold({ null }, { mapRoadLanesLaneSectionLCRLaneRoadMarkType(it) }) - abstract fun mapRoadLanesLaneSectionLCRLaneRoadMarkType(source: RoadLanesLaneSectionLCRLaneRoadMarkType): T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Type + fun mapOptionRoadLanesLaneSectionLCRLaneRoadMarkType( + source: Option, + ): T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Type? = source.fold({ null }, { mapRoadLanesLaneSectionLCRLaneRoadMarkType(it) }) + + abstract fun mapRoadLanesLaneSectionLCRLaneRoadMarkType( + source: RoadLanesLaneSectionLCRLaneRoadMarkType, + ): T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Type + + fun mapOptionRoadMarkWeight(source: Option): E_RoadMarkWeight? = source.fold({ null }, { mapRoadMarkWeight(it) }) - fun mapOptionRoadMarkWeight(source: Option): E_RoadMarkWeight? = - source.fold({ null }, { mapRoadMarkWeight(it) }) abstract fun mapRoadMarkWeight(source: ERoadMarkWeight): E_RoadMarkWeight - fun mapOptionRoadLanesLaneSectionLCRLaneRoadMarkLaneChange(source: Option): E_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_LaneChange? = + fun mapOptionRoadLanesLaneSectionLCRLaneRoadMarkLaneChange( + source: Option, + ): E_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_LaneChange? = source.fold({ null }, { mapRoadLanesLaneSectionLCRLaneRoadMarkLaneChange(it) }) - abstract fun mapRoadLanesLaneSectionLCRLaneRoadMarkLaneChange(source: ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange): E_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_LaneChange - fun mapOptionRoadLanesLaneSectionLCRLaneRoadMarkExplicit(source: Option): T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Explicit? = - source.fold({ null }, { mapRoadLanesLaneSectionLCRLaneRoadMarkExplicit(it) }) - abstract fun mapRoadLanesLaneSectionLCRLaneRoadMarkExplicit(source: RoadLanesLaneSectionLCRLaneRoadMarkExplicit): T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Explicit + abstract fun mapRoadLanesLaneSectionLCRLaneRoadMarkLaneChange( + source: ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange, + ): E_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_LaneChange + + fun mapOptionRoadLanesLaneSectionLCRLaneRoadMarkExplicit( + source: Option, + ): T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Explicit? = source.fold({ null }, { mapRoadLanesLaneSectionLCRLaneRoadMarkExplicit(it) }) + + abstract fun mapRoadLanesLaneSectionLCRLaneRoadMarkExplicit( + source: RoadLanesLaneSectionLCRLaneRoadMarkExplicit, + ): T_Road_Lanes_LaneSection_Lcr_Lane_RoadMark_Explicit @ValueMapping(source = "SOLID_SOLID", target = "SOLID___SOLID") @ValueMapping(source = "SOLID_BROKEN", target = "SOLID___BROKEN") @@ -138,5 +168,6 @@ abstract class Opendrive17LaneMapper { abstract fun mapRoadMarkRule(source: ERoadMarkRule): E_RoadMarkRule fun mapOptionRoadMarkColor(source: Option): E_RoadMarkColor? = source.fold({ null }, { mapRoadMarkColor(it) }) + abstract fun mapRoadMarkColor(source: ERoadMarkColor): E_RoadMarkColor } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17Mapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17Mapper.kt index f5f9e840..1e80bd17 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17Mapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17Mapper.kt @@ -22,8 +22,13 @@ import org.asam.opendrive17.OpenDRIVE import org.mapstruct.Mapper import org.mapstruct.NullValueCheckStrategy -@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive17CoreMapper::class, Opendrive17RoadMapper::class, Opendrive17ObjectMapper::class, Opendrive17SignalMapper::class, Opendrive17JunctionMapper::class]) +@Mapper( + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + uses = [ + OpendriveCommonMapper::class, Opendrive17CoreMapper::class, Opendrive17RoadMapper::class, Opendrive17ObjectMapper::class, + Opendrive17SignalMapper::class, Opendrive17JunctionMapper::class, + ], +) abstract class Opendrive17Mapper { - abstract fun mapModel(source: OpendriveModel): OpenDRIVE } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17ObjectMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17ObjectMapper.kt index f10eaa35..28d9f916 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17ObjectMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17ObjectMapper.kt @@ -47,7 +47,6 @@ import org.mapstruct.NullValueCheckStrategy @Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive17CoreMapper::class]) abstract class Opendrive17ObjectMapper { - // // Road objects // @@ -61,43 +60,64 @@ abstract class Opendrive17ObjectMapper { // abstract fun mapRoadObjectsObject(source: RoadObjectsObject): T_Road_Objects_Object - fun mapOptionRoadObjectsObjectParkingSpace(source: Option): T_Road_Objects_Object_ParkingSpace? = source.fold({ null }, { mapRoadObjectsObjectParkingSpace(it) }) + fun mapOptionRoadObjectsObjectParkingSpace(source: Option): T_Road_Objects_Object_ParkingSpace? = + source.fold({ + null + }, { mapRoadObjectsObjectParkingSpace(it) }) + abstract fun mapRoadObjectsObjectParkingSpace(source: RoadObjectsObjectParkingSpace): T_Road_Objects_Object_ParkingSpace - fun mapOptionRoadObjectsObjectMarkings(source: Option): T_Road_Objects_Object_Markings? = source.fold({ null }, { mapRoadObjectsObjectMarkings(it) }) + fun mapOptionRoadObjectsObjectMarkings(source: Option): T_Road_Objects_Object_Markings? = + source.fold({ + null + }, { mapRoadObjectsObjectMarkings(it) }) + abstract fun mapRoadObjectsObjectMarkings(source: RoadObjectsObjectMarkings): T_Road_Objects_Object_Markings fun mapOptionEOrientation(source: Option): String? = source.fold({ null }, { mapEOrientation(it) }) - fun mapEOrientation(source: EOrientation): String = when (source) { - EOrientation.PLUS -> "+" - EOrientation.MINUS -> "-" - EOrientation.NONE -> "none" - } + + fun mapEOrientation(source: EOrientation): String = + when (source) { + EOrientation.PLUS -> "+" + EOrientation.MINUS -> "-" + EOrientation.NONE -> "none" + } fun mapOptionFillType(source: Option): E_OutlineFillType? = source.fold({ null }, { mapFillType(it) }) + abstract fun mapFillType(source: EOutlineFillType): E_OutlineFillType fun mapOptionEObjectType(source: Option): E_ObjectType? = source.fold({ null }, { mapEObjectType(it) }) + abstract fun mapEObjectType(source: EObjectType): E_ObjectType - fun mapOptionRoadObjectsObjectBorders(source: Option): T_Road_Objects_Object_Borders? = source.fold({ null }, { mapRoadObjectsObjectBorders(it) }) + fun mapOptionRoadObjectsObjectBorders(source: Option): T_Road_Objects_Object_Borders? = + source.fold({ + null + }, { mapRoadObjectsObjectBorders(it) }) + abstract fun mapRoadObjectsObjectBorders(source: RoadObjectsObjectBorders): T_Road_Objects_Object_Borders // // Outlines // - fun mapOptionRoadObjectsObjectOutlines(source: Option): T_Road_Objects_Object_Outlines? = source.fold({ null }, { mapRoadObjectsObjectOutlines(it) }) + fun mapOptionRoadObjectsObjectOutlines(source: Option): T_Road_Objects_Object_Outlines? = + source.fold({ null }, { mapRoadObjectsObjectOutlines(it) }) + abstract fun mapRoadObjectsObjectOutlines(source: RoadObjectsObjectOutlines): T_Road_Objects_Object_Outlines fun mapOptionELaneType(source: Option): E_LaneType? = source.fold({ null }, { mapELaneType(it) }) + abstract fun mapELaneType(source: ELaneType): E_LaneType // // Markings // fun mapOptionESideType(source: Option): E_SideType? = source.fold({ null }, { mapESideType(it) }) + abstract fun mapESideType(source: ESideType): E_SideType fun mapOptionERoadMarkWeight(source: Option): E_RoadMarkWeight? = source.fold({ null }, { mapERoadMarkWeight(it) }) + abstract fun mapERoadMarkWeight(source: ERoadMarkWeight): E_RoadMarkWeight } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17RoadMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17RoadMapper.kt index efbb23ec..f9e04288 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17RoadMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17RoadMapper.kt @@ -55,9 +55,14 @@ import org.asam.opendrive17.T_Road_Type_Speed import org.mapstruct.Mapper import org.mapstruct.NullValueCheckStrategy -@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive17CoreMapper::class, Opendrive17LaneMapper::class, Opendrive17ObjectMapper::class, Opendrive17SignalMapper::class]) +@Mapper( + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + uses = [ + OpendriveCommonMapper::class, Opendrive17CoreMapper::class, Opendrive17LaneMapper::class, Opendrive17ObjectMapper::class, + Opendrive17SignalMapper::class, + ], +) abstract class Opendrive17RoadMapper { - // // Road // @@ -67,76 +72,113 @@ abstract class Opendrive17RoadMapper { // Road link // fun mapOptionRoadLink(source: Option): T_Road_Link? = source.fold({ null }, { mapRoadLink(it) }) + abstract fun mapRoadLink(source: RoadLink): T_Road_Link - fun mapOptionRoadLinkPredecessorSuccessor(source: Option): T_Road_Link_PredecessorSuccessor? = source.fold({ null }, { mapRoadLinkPredecessorSuccessor(it) }) + fun mapOptionRoadLinkPredecessorSuccessor(source: Option): T_Road_Link_PredecessorSuccessor? = + source.fold({ + null + }, { mapRoadLinkPredecessorSuccessor(it) }) + abstract fun mapRoadLinkPredecessorSuccessor(source: RoadLinkPredecessorSuccessor): T_Road_Link_PredecessorSuccessor fun mapOptionEContactPoint(source: Option): E_ContactPoint? = source.fold({ null }, { mapEContactPoint(it) }) + abstract fun mapEContactPoint(source: EContactPoint): E_ContactPoint - fun mapOptionERoadLinkElementType(source: Option): E_Road_Link_ElementType? = source.fold({ null }, { mapERoadLinkElementType(it) }) + fun mapOptionERoadLinkElementType(source: Option): E_Road_Link_ElementType? = + source.fold({ + null + }, { mapERoadLinkElementType(it) }) + abstract fun mapERoadLinkElementType(source: ERoadLinkElementType): E_Road_Link_ElementType // // Road type // fun mapOptionRoadTypeSpeed(source: Option): T_Road_Type_Speed? = source.fold({ null }, { mapRoadTypeSpeed(it) }) + abstract fun mapRoadTypeSpeed(source: RoadTypeSpeed): T_Road_Type_Speed // // Plan view // - fun mapOptionRoadPlanViewGeometryLine(source: Option): T_Road_PlanView_Geometry_Line? = source.fold({ null }, { mapRoadPlanViewGeometryLine(it) }) + fun mapOptionRoadPlanViewGeometryLine(source: Option): T_Road_PlanView_Geometry_Line? = + source.fold({ null }, { mapRoadPlanViewGeometryLine(it) }) + abstract fun mapRoadPlanViewGeometryLine(source: RoadPlanViewGeometryLine): T_Road_PlanView_Geometry_Line - fun mapOptionRoadPlanViewGeometrySpiral(source: Option): T_Road_PlanView_Geometry_Spiral? = source.fold({ null }, { mapRoadPlanViewGeometrySpiral(it) }) + fun mapOptionRoadPlanViewGeometrySpiral(source: Option): T_Road_PlanView_Geometry_Spiral? = + source.fold({ + null + }, { mapRoadPlanViewGeometrySpiral(it) }) + abstract fun mapRoadPlanViewGeometrySpiral(source: RoadPlanViewGeometrySpiral): T_Road_PlanView_Geometry_Spiral - fun mapOptionRoadPlanViewGeometryArc(source: Option): T_Road_PlanView_Geometry_Arc? = source.fold({ null }, { mapRoadPlanViewGeometryArc(it) }) + fun mapOptionRoadPlanViewGeometryArc(source: Option): T_Road_PlanView_Geometry_Arc? = + source.fold({ + null + }, { mapRoadPlanViewGeometryArc(it) }) + abstract fun mapRoadPlanViewGeometryArc(source: RoadPlanViewGeometryArc): T_Road_PlanView_Geometry_Arc - fun mapOptionRoadPlanViewGeometryPoly3(source: Option): T_Road_PlanView_Geometry_Poly3? = source.fold({ null }, { mapRoadPlanViewGeometryPoly3(it) }) + fun mapOptionRoadPlanViewGeometryPoly3(source: Option): T_Road_PlanView_Geometry_Poly3? = + source.fold({ + null + }, { mapRoadPlanViewGeometryPoly3(it) }) + abstract fun mapRoadPlanViewGeometryPoly3(source: RoadPlanViewGeometryPoly3): T_Road_PlanView_Geometry_Poly3 - fun mapOptionRoadPlanViewGeometryParamPoly3(source: Option): T_Road_PlanView_Geometry_ParamPoly3? = source.fold({ null }, { mapRoadPlanViewGeometryParamPoly3(it) }) + fun mapOptionRoadPlanViewGeometryParamPoly3(source: Option): T_Road_PlanView_Geometry_ParamPoly3? = + source.fold({ + null + }, { mapRoadPlanViewGeometryParamPoly3(it) }) + abstract fun mapRoadPlanViewGeometryParamPoly3(source: RoadPlanViewGeometryParamPoly3): T_Road_PlanView_Geometry_ParamPoly3 // // Elevation profile // - fun mapOptionRoadElevationProfile(source: Option): T_Road_ElevationProfile? = source.fold({ null }, { mapRoadElevationProfile(it) }) + fun mapOptionRoadElevationProfile(source: Option): T_Road_ElevationProfile? = + source.fold({ null }, { mapRoadElevationProfile(it) }) + abstract fun mapRoadElevationProfile(source: RoadElevationProfile): T_Road_ElevationProfile // // Lateral profile // fun mapLateralProfile(source: Option): T_Road_LateralProfile? = source.fold({ null }, { mapLateralProfile(it) }) + abstract fun mapLateralProfile(source: RoadLateralProfile): T_Road_LateralProfile // // Surface // fun mapOptionRoadSurface(source: Option): T_Road_Surface? = source.fold({ null }, { mapRoadSurface(it) }) + abstract fun mapRoadSurface(source: RoadSurface): T_Road_Surface // // Railroad // fun mapOptionRoadRailroad(source: Option): T_Road_Railroad? = source.fold({ null }, { mapRoadRailroad(it) }) + abstract fun mapRoadRailroad(source: RoadRailroad): T_Road_Railroad // // Enumerations // fun mapOptionETrafficRule(source: Option): E_TrafficRule? = source.fold({ null }, { mapETrafficRule(it) }) - fun mapETrafficRule(source: ETrafficRule): E_TrafficRule = when (source) { - ETrafficRule.RIGHT_HAND_TRAFFIC -> E_TrafficRule.RHT - ETrafficRule.LEFT_HAND_TRAFFIC -> E_TrafficRule.LHT - } - - fun mapOptionEElementDir(source: Option): String = when (source.getOrElse { EElementDir.PLUS }) { - EElementDir.PLUS -> "+" - EElementDir.MINUS -> "-" - } + + fun mapETrafficRule(source: ETrafficRule): E_TrafficRule = + when (source) { + ETrafficRule.RIGHT_HAND_TRAFFIC -> E_TrafficRule.RHT + ETrafficRule.LEFT_HAND_TRAFFIC -> E_TrafficRule.LHT + } + + fun mapOptionEElementDir(source: Option): String = + when (source.getOrElse { EElementDir.PLUS }) { + EElementDir.PLUS -> "+" + EElementDir.MINUS -> "-" + } } diff --git a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17SignalMapper.kt b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17SignalMapper.kt index e42dff37..69522746 100644 --- a/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17SignalMapper.kt +++ b/rtron-readerwriter/src/main/kotlin/io/rtron/readerwriter/opendrive/writer/mapper/opendrive17/Opendrive17SignalMapper.kt @@ -30,25 +30,35 @@ import org.asam.opendrive17.T_Road_Signals_Signal_PositionRoad import org.mapstruct.Mapper import org.mapstruct.NullValueCheckStrategy -@Mapper(nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, uses = [OpendriveCommonMapper::class, Opendrive17CoreMapper::class, Opendrive17ObjectMapper::class]) +@Mapper( + nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS, + uses = [OpendriveCommonMapper::class, Opendrive17CoreMapper::class, Opendrive17ObjectMapper::class], +) abstract class Opendrive17SignalMapper { - // // Signal // fun mapOptionRoadSignals(source: Option): T_Road_Signals? = source.fold({ null }, { mapRoadSignals(it) }) + abstract fun mapRoadSignals(source: RoadSignals): T_Road_Signals abstract fun mapRoadSignalsSignal(source: RoadSignalsSignal): T_Road_Signals_Signal fun mapOptionECountryCode(source: Option): String? = source.fold({ null }, { mapECountryCode(it) }) + abstract fun mapECountryCode(source: ECountryCode): String - fun mapOptionRoadSignalsSignalPositionInertial(source: Option): T_Road_Signals_Signal_PositionInertial? = source - .fold({ null }, { mapRoadSignalsSignalPositionInertial(it) }) + fun mapOptionRoadSignalsSignalPositionInertial( + source: Option, + ): T_Road_Signals_Signal_PositionInertial? = + source + .fold({ null }, { mapRoadSignalsSignalPositionInertial(it) }) + abstract fun mapRoadSignalsSignalPositionInertial(source: RoadSignalsSignalPositionInertial): T_Road_Signals_Signal_PositionInertial - fun mapOptionRoadSignalsSignalPositionRoad(source: Option): T_Road_Signals_Signal_PositionRoad? = source - .fold({ null }, { mapRoadSignalsSignalPositionRoad(it) }) + fun mapOptionRoadSignalsSignalPositionRoad(source: Option): T_Road_Signals_Signal_PositionRoad? = + source + .fold({ null }, { mapRoadSignalsSignalPositionRoad(it) }) + abstract fun mapRoadSignalsSignalPositionRoad(source: RoadSignalsSignalPositionRoad): T_Road_Signals_Signal_PositionRoad } diff --git a/rtron-std/src/main/kotlin/io/rtron/std/Collections.kt b/rtron-std/src/main/kotlin/io/rtron/std/Collections.kt index 6971b364..5a54e6f1 100644 --- a/rtron-std/src/main/kotlin/io/rtron/std/Collections.kt +++ b/rtron-std/src/main/kotlin/io/rtron/std/Collections.kt @@ -102,8 +102,10 @@ inline fun Iterable.filterToSorting(predicate: (first: T, second: T) -> B * @param step the number of elements to move on * @return the sequence of sublists */ -fun Sequence.windowedEnclosing(size: Int, step: Int = 1): Sequence> = - (this + this.take(size - 1)).windowed(size, step) +fun Sequence.windowedEnclosing( + size: Int, + step: Int = 1, +): Sequence> = (this + this.take(size - 1)).windowed(size, step) /** * Returns true, if all lists have the same number of elements. diff --git a/rtron-std/src/main/kotlin/io/rtron/std/Either.kt b/rtron-std/src/main/kotlin/io/rtron/std/Either.kt index 5083c4d1..d637b59c 100644 --- a/rtron-std/src/main/kotlin/io/rtron/std/Either.kt +++ b/rtron-std/src/main/kotlin/io/rtron/std/Either.kt @@ -57,6 +57,9 @@ inline fun Iterable>.handleLeftAndFilter(block: (Either.Left fold(emptyList()) { acc, result -> when (result) { is Either.Right -> acc + result.value - is Either.Left -> { block(result); acc } + is Either.Left -> { + block(result) + acc + } } } diff --git a/rtron-std/src/main/kotlin/io/rtron/std/Iterable.kt b/rtron-std/src/main/kotlin/io/rtron/std/Iterable.kt index 3b825a9e..c411f934 100644 --- a/rtron-std/src/main/kotlin/io/rtron/std/Iterable.kt +++ b/rtron-std/src/main/kotlin/io/rtron/std/Iterable.kt @@ -19,8 +19,7 @@ package io.rtron.std /** * Returns either the size of [T] or the [default] value. */ -internal fun Iterable.collectionSizeOrDefault(default: Int): Int = - if (this is Collection<*>) this.size else default +internal fun Iterable.collectionSizeOrDefault(default: Int): Int = if (this is Collection<*>) this.size else default /** * Returns the cumulative sum. @@ -57,8 +56,10 @@ fun Iterable.cumulativeSum(): List = scan(0) { acc, element -> acc + e * @param otherB array to be combined * @return list of [Triple] having the length of the shortest collection */ -fun Iterable.zip(otherA: Iterable, otherB: Iterable): List> = - zip(otherA, otherB) { t1, t2, t3 -> Triple(t1, t2, t3) } +fun Iterable.zip( + otherA: Iterable, + otherB: Iterable, +): List> = zip(otherA, otherB) { t1, t2, t3 -> Triple(t1, t2, t3) } /** * Returns a list of values built from [this] collection and the [otherA] as well as [otherB] array with the same index. @@ -68,17 +69,22 @@ fun Iterable.zip(otherA: Iterable, otherB: Iterable): List Iterable.zip(otherA: Iterable, otherB: Iterable, transform: (a: T, b: R, c: S) -> V): List { +fun Iterable.zip( + otherA: Iterable, + otherB: Iterable, + transform: (a: T, b: R, c: S) -> V, +): List { val first = iterator() val second = otherA.iterator() val third = otherB.iterator() - val list = ArrayList( - minOf( - collectionSizeOrDefault(10), - otherA.collectionSizeOrDefault(10), - otherB.collectionSizeOrDefault(10) + val list = + ArrayList( + minOf( + collectionSizeOrDefault(10), + otherA.collectionSizeOrDefault(10), + otherB.collectionSizeOrDefault(10), + ), ) - ) while (first.hasNext() && second.hasNext() && third.hasNext()) { list.add(transform(first.next(), second.next(), third.next())) } @@ -90,8 +96,7 @@ fun Iterable.zip(otherA: Iterable, otherB: Iterable, trans * * @return list of triples */ -fun Iterable.zipWithNextToTriples(): List> = - this.windowed(3, 1, false).map { Triple(it[0], it[1], it[2]) } +fun Iterable.zipWithNextToTriples(): List> = this.windowed(3, 1, false).map { Triple(it[0], it[1], it[2]) } /** * Returns true, if the list is sorted ascending according to the [selector]. @@ -117,8 +122,7 @@ inline fun > Iterable.isStrictlySortedBy(crossinline sel * @receiver list to be evaluated * @return true, if the list is sorted in weak ascending order */ -fun > Iterable.isSorted(): Boolean = - this.asSequence().zipWithNext { a, b -> a <= b }.all { it } +fun > Iterable.isSorted(): Boolean = this.asSequence().zipWithNext { a, b -> a <= b }.all { it } /** * Returns true, if list is sorted in strict ascending order. @@ -126,8 +130,7 @@ fun > Iterable.isSorted(): Boolean = * @receiver list to be evaluated * @return true, if the list is sorted in strict ascending order */ -fun > Iterable.isStrictlySorted(): Boolean = - this.asSequence().zipWithNext { a, b -> a < b }.all { it } +fun > Iterable.isStrictlySorted(): Boolean = this.asSequence().zipWithNext { a, b -> a < b }.all { it } /** * Returns true, if list is sorted in weak descending order. @@ -135,8 +138,7 @@ fun > Iterable.isStrictlySorted(): Boolean = * @receiver list to be evaluated * @return true, if the list is sorted in weak descending order */ -fun > Iterable.isSortedDescending(): Boolean = - this.asSequence().zipWithNext { a, b -> a >= b }.all { it } +fun > Iterable.isSortedDescending(): Boolean = this.asSequence().zipWithNext { a, b -> a >= b }.all { it } /** * Returns true, if list is sorted in strict descending order. @@ -144,5 +146,4 @@ fun > Iterable.isSortedDescending(): Boolean = * @receiver list to be evaluated * @return true, if the list is sorted in strict descending order */ -fun > Iterable.isStrictlySortedDescending(): Boolean = - this.asSequence().zipWithNext { a, b -> a > b }.all { it } +fun > Iterable.isStrictlySortedDescending(): Boolean = this.asSequence().zipWithNext { a, b -> a > b }.all { it } diff --git a/rtron-std/src/main/kotlin/io/rtron/std/Lists.kt b/rtron-std/src/main/kotlin/io/rtron/std/Lists.kt index da110c5f..888b9632 100644 --- a/rtron-std/src/main/kotlin/io/rtron/std/Lists.kt +++ b/rtron-std/src/main/kotlin/io/rtron/std/Lists.kt @@ -26,7 +26,7 @@ enum class MovingWindowShape { FULL, /** Same size of returning list like the base list. */ - SAME + SAME, } /** @@ -47,14 +47,15 @@ fun List.moveWindow( window: List, multiplication: (baseElement: S, otherElement: T) -> K, addition: (K, K) -> K, - shape: MovingWindowShape = MovingWindowShape.FULL + shape: MovingWindowShape = MovingWindowShape.FULL, ): List { require(this.isNotEmpty()) { "Base list requires elements and thus must not be empty." } require(window.isNotEmpty()) { "Other list requires elements and thus must not be empty." } - val multipliedSubLists = this.fold(emptyList>()) { acc, s -> - acc + listOf(window.map { multiplication(s, it) }) - } + val multipliedSubLists = + this.fold(emptyList>()) { acc, s -> + acc + listOf(window.map { multiplication(s, it) }) + } val rowIndices = window.indices.reversed().toList() @@ -65,14 +66,15 @@ fun List.moveWindow( val relevantRowIndices = rowIndices.drop(rowIndices.size - relevantColIndices.size) val indices = relevantColIndices.zip(relevantRowIndices) val startValue = multipliedSubLists[indices.first().first][indices.first().second] - val resultElement = indices.drop(0).fold(startValue) { sum, pair -> - val curRow = multipliedSubLists.getOrNull(pair.first) - if (curRow.isNullOrEmpty()) { - sum - } else { - addition(sum, curRow[pair.second]) + val resultElement = + indices.drop(0).fold(startValue) { sum, pair -> + val curRow = multipliedSubLists.getOrNull(pair.first) + if (curRow.isNullOrEmpty()) { + sum + } else { + addition(sum, curRow[pair.second]) + } } - } acc + listOf(resultElement) } } @@ -87,13 +89,15 @@ fun List.moveWindow( * @return an element of the returned list is true, if the multiplication of at least one element of the receiver * and [window] list is true */ -fun List.moveWindow(window: List, shape: MovingWindowShape = MovingWindowShape.FULL) = - this.moveWindow( - window, - { baseElement, otherElement -> baseElement && otherElement }, - { a, b -> a || b }, - shape - ) +fun List.moveWindow( + window: List, + shape: MovingWindowShape = MovingWindowShape.FULL, +) = this.moveWindow( + window, + { baseElement, otherElement -> baseElement && otherElement }, + { a, b -> a || b }, + shape, +) /** * Returns a list containing all elements not matching the given [predicate]. The predicate is operated on a sublist @@ -111,7 +115,10 @@ fun List.moveWindow(window: List, shape: MovingWindowShape = M * @param predicate if the [predicate] returns true, the indices are dropped according to the [dropIndices] * @return list without elements which match the [predicate] */ -fun List.filterWindowed(dropIndices: List, predicate: (List) -> Boolean): List { +fun List.filterWindowed( + dropIndices: List, + predicate: (List) -> Boolean, +): List { require(dropIndices.size <= this.size) { "Dropping indices list must be smaller than base list." } if (isEmpty()) return emptyList() @@ -129,7 +136,10 @@ fun List.filterWindowed(dropIndices: List, predicate: (List) * @param predicate if the [predicate] returns true, all elements are filtered out * @return list without elements which match the [predicate] */ -fun List.filterWindowedEnclosing(windowSize: Int, predicate: (List) -> Boolean): List { +fun List.filterWindowedEnclosing( + windowSize: Int, + predicate: (List) -> Boolean, +): List { val dropIndices = List(windowSize) { true } return this.filterWindowedEnclosing(dropIndices, predicate) } @@ -149,7 +159,10 @@ fun List.filterWindowedEnclosing(windowSize: Int, predicate: (List) -> * @param predicate if the [predicate] returns true, the indices are dropped according to the [dropIndices] * @return list without elements which match the [predicate] */ -fun List.filterWindowedEnclosing(dropIndices: List, predicate: (List) -> Boolean): List { +fun List.filterWindowedEnclosing( + dropIndices: List, + predicate: (List) -> Boolean, +): List { require(dropIndices.size <= this.size) { "Dropping indices list must be smaller than base list." } if (isEmpty()) return emptyList() diff --git a/rtron-std/src/main/kotlin/io/rtron/std/Option.kt b/rtron-std/src/main/kotlin/io/rtron/std/Option.kt index 2b545fc2..53e1bce7 100644 --- a/rtron-std/src/main/kotlin/io/rtron/std/Option.kt +++ b/rtron-std/src/main/kotlin/io/rtron/std/Option.kt @@ -19,5 +19,4 @@ package io.rtron.std import arrow.core.Option /** Handle the None of [Option] with [block] and return the [V]. */ -inline fun Option.handleEmpty(block: (Option) -> Nothing): V = - if (isSome()) getOrNull()!! else block(this) +inline fun Option.handleEmpty(block: (Option) -> Nothing): V = if (isSome()) getOrNull()!! else block(this) diff --git a/rtron-std/src/main/kotlin/io/rtron/std/Property.kt b/rtron-std/src/main/kotlin/io/rtron/std/Property.kt index fe113391..2d0b92bb 100644 --- a/rtron-std/src/main/kotlin/io/rtron/std/Property.kt +++ b/rtron-std/src/main/kotlin/io/rtron/std/Property.kt @@ -26,7 +26,6 @@ import kotlin.reflect.KProperty * @param isDefault true, if value constitutes a default value */ open class Property(value: T, isDefault: Boolean = false) { - // Properties and Initializers var value: T = value protected set @@ -35,10 +34,14 @@ open class Property(value: T, isDefault: Boolean = false) { val isNotDefault get() = !isDefault // Methods + /** * Read method for property delegation. */ - operator fun getValue(thisRef: Any?, prop: KProperty<*>): T { + operator fun getValue( + thisRef: Any?, + prop: KProperty<*>, + ): T { return value } @@ -62,15 +65,19 @@ open class Property(value: T, isDefault: Boolean = false) { * @param isDefault true, if value constitutes a default value and is set to false, when [value] is overwritten */ class SettableProperty(value: T, isDefault: Boolean = false) : Property(value, isDefault) { - // Secondary Constructors constructor(property: Property) : this(property.value, property.isDefault) // Methods + /** * Set method for property delegation. */ - operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) { + operator fun setValue( + thisRef: Any?, + property: KProperty<*>, + value: T, + ) { this.value = value this.isDefault = false } diff --git a/rtron-std/src/main/kotlin/io/rtron/std/date/DateTime.kt b/rtron-std/src/main/kotlin/io/rtron/std/date/DateTime.kt index ce040c14..ef1d67d9 100644 --- a/rtron-std/src/main/kotlin/io/rtron/std/date/DateTime.kt +++ b/rtron-std/src/main/kotlin/io/rtron/std/date/DateTime.kt @@ -32,9 +32,8 @@ annotation class ExperimentalDateTime */ @ExperimentalDateTime class DateTime( - private val localDateTime: LocalDateTime + private val localDateTime: LocalDateTime, ) { - // Properties and Initializers companion object { diff --git a/rtron-std/src/test/kotlin/io/rtron/std/CollectionsKtTest.kt b/rtron-std/src/test/kotlin/io/rtron/std/CollectionsKtTest.kt index dc709683..ca98b147 100644 --- a/rtron-std/src/test/kotlin/io/rtron/std/CollectionsKtTest.kt +++ b/rtron-std/src/test/kotlin/io/rtron/std/CollectionsKtTest.kt @@ -125,12 +125,13 @@ class CollectionsKtTest : FunSpec({ test("test basic enclosed windowing of character sequence") { val baseSequence = sequenceOf("a", "b", "c", "d") - val expectedSequence = sequenceOf( - listOf("a", "b", "c"), - listOf("b", "c", "d"), - listOf("c", "d", "a"), - listOf("d", "a", "b") - ) + val expectedSequence = + sequenceOf( + listOf("a", "b", "c"), + listOf("b", "c", "d"), + listOf("c", "d", "a"), + listOf("d", "a", "b"), + ) val actualSequence = baseSequence.windowedEnclosing(3) @@ -139,14 +140,15 @@ class CollectionsKtTest : FunSpec({ test("test basic enclosed windowing of integer sequence") { val baseSequence = sequenceOf(1, 2, 3, 4, 5, 6) - val expectedSequence = sequenceOf( - listOf(1, 2, 3), - listOf(2, 3, 4), - listOf(3, 4, 5), - listOf(4, 5, 6), - listOf(5, 6, 1), - listOf(6, 1, 2) - ) + val expectedSequence = + sequenceOf( + listOf(1, 2, 3), + listOf(2, 3, 4), + listOf(3, 4, 5), + listOf(4, 5, 6), + listOf(5, 6, 1), + listOf(6, 1, 2), + ) val actualValues = baseSequence.windowedEnclosing(3) diff --git a/rtron-std/src/test/kotlin/io/rtron/std/ListsKtTest.kt b/rtron-std/src/test/kotlin/io/rtron/std/ListsKtTest.kt index f2571ed6..71e35f09 100644 --- a/rtron-std/src/test/kotlin/io/rtron/std/ListsKtTest.kt +++ b/rtron-std/src/test/kotlin/io/rtron/std/ListsKtTest.kt @@ -28,11 +28,12 @@ class ListsKtTest : FunSpec({ val listB = listOf(true, true, false) val expectedList = listOf(false, false, true, true, false, false, false) - val actualList = listA.moveWindow( - listB, - { baseElement, otherElement -> baseElement && otherElement }, - { a, b -> a || b } - ) + val actualList = + listA.moveWindow( + listB, + { baseElement, otherElement -> baseElement && otherElement }, + { a, b -> a || b }, + ) actualList shouldBe expectedList } @@ -45,7 +46,7 @@ class ListsKtTest : FunSpec({ listA.moveWindow( listB, { baseElement, otherElement -> baseElement && otherElement }, - { a, b -> a || b } + { a, b -> a || b }, ) } } @@ -58,7 +59,7 @@ class ListsKtTest : FunSpec({ listA.moveWindow( listB, { baseElement, otherElement -> baseElement && otherElement }, - { a, b -> a || b } + { a, b -> a || b }, ) } } @@ -68,12 +69,13 @@ class ListsKtTest : FunSpec({ val listB = listOf(true, true, false) val expectedList = listOf(false, false, true, true, false) - val actualList = listA.moveWindow( - listB, - { baseElement, otherElement -> baseElement && otherElement }, - { a, b -> a || b }, - shape = MovingWindowShape.SAME - ) + val actualList = + listA.moveWindow( + listB, + { baseElement, otherElement -> baseElement && otherElement }, + { a, b -> a || b }, + shape = MovingWindowShape.SAME, + ) actualList shouldBe expectedList } @@ -83,11 +85,12 @@ class ListsKtTest : FunSpec({ val listB = listOf(1.0, 1.0, 0.0) val expectedList = listOf(0.0, 2.0, 3.0, 1.0, 0.0, 0.0, 0.0) - val actualList = listA.moveWindow( - listB, - { baseElement, otherElement -> baseElement * otherElement }, - { a, b -> a + b } - ) + val actualList = + listA.moveWindow( + listB, + { baseElement, otherElement -> baseElement * otherElement }, + { a, b -> a + b }, + ) actualList shouldBe expectedList } diff --git a/rtron-std/src/test/kotlin/io/rtron/std/SequencesKtTest.kt b/rtron-std/src/test/kotlin/io/rtron/std/SequencesKtTest.kt index ffcada8f..e1c2ab1d 100644 --- a/rtron-std/src/test/kotlin/io/rtron/std/SequencesKtTest.kt +++ b/rtron-std/src/test/kotlin/io/rtron/std/SequencesKtTest.kt @@ -113,11 +113,12 @@ class SequencesKtTest : FunSpec({ val pair5 = Pair(3, "b") val pair6 = Pair(1, "b") val startList = listOf(pair1, pair2, pair3, pair4, pair5, pair6) - val expectedZips = listOf( - listOf(pair6, pair1, pair2), - listOf(pair3), - listOf(pair4, pair5) - ) + val expectedZips = + listOf( + listOf(pair6, pair1, pair2), + listOf(pair3), + listOf(pair4, pair5), + ) val actualZips = startList.zipWithConsecutivesEnclosing { it.first } diff --git a/rtron-std/src/test/kotlin/io/rtron/std/SetsKtTest.kt b/rtron-std/src/test/kotlin/io/rtron/std/SetsKtTest.kt index 34e3ce55..681486d3 100644 --- a/rtron-std/src/test/kotlin/io/rtron/std/SetsKtTest.kt +++ b/rtron-std/src/test/kotlin/io/rtron/std/SetsKtTest.kt @@ -24,11 +24,12 @@ class SetsKtTest : FunSpec({ test("test basic combination generation") { val startSet = setOf("a", "b", "c") - val expectedCombinations = setOf( - setOf("a", "b"), - setOf("a", "c"), - setOf("b", "c") - ) + val expectedCombinations = + setOf( + setOf("a", "b"), + setOf("a", "c"), + setOf("b", "c"), + ) val actualCombinations = startSet.combinations(2) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/Opendrive2RoadspacesParameters.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/Opendrive2RoadspacesParameters.kt index 2e16a4c1..37663731 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/Opendrive2RoadspacesParameters.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/Opendrive2RoadspacesParameters.kt @@ -38,9 +38,8 @@ data class Opendrive2RoadspacesParameters( /** [EPSG code](https://en.wikipedia.org/wiki/EPSG_Geodetic_Parameter_Dataset) of the coordinate reference system (obligatory for working with GIS applications) */ val crsEpsg: Int, /** linear extrapolation of lateral road shapes if they are not defined at the position (otherwise errors are thrown) */ - val extrapolateLateralRoadShapes: Boolean + val extrapolateLateralRoadShapes: Boolean, ) { - companion object { const val DEFAULT_NUMBER_TOLERANCE = 1E-7 const val DEFAULT_PLAN_VIEW_GEOMETRY_DISTANCE_TOLERANCE = 1E0 diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/Opendrive2RoadspacesTransformer.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/Opendrive2RoadspacesTransformer.kt index 43781709..1e454ee9 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/Opendrive2RoadspacesTransformer.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/Opendrive2RoadspacesTransformer.kt @@ -42,9 +42,8 @@ import kotlinx.coroutines.runBlocking * @param parameters parameters for the transformation */ class Opendrive2RoadspacesTransformer( - val parameters: Opendrive2RoadspacesParameters + val parameters: Opendrive2RoadspacesParameters, ) { - // Properties and Initializers private val logger = KotlinLogging.logger {} @@ -79,9 +78,10 @@ class Opendrive2RoadspacesTransformer( val roadspaces = roadspacesWithContextReports.mergeIssueLists().handleIssueList { report.conversion += it } - val junctions = opendriveModel.junction - .filter { it.typeValidated == EJunctionType.DEFAULT } - .map { junctionBuilder.buildDefaultJunction(it, roadspaces) } + val junctions = + opendriveModel.junction + .filter { it.typeValidated == EJunctionType.DEFAULT } + .map { junctionBuilder.buildDefaultJunction(it, roadspaces) } val roadspacesModel = RoadspacesModel(header, roadspaces, junctions) @@ -91,7 +91,7 @@ class Opendrive2RoadspacesTransformer( private fun transformRoadspacesSequentially( opendriveModel: OpendriveModel, - progressBar: ProgressBar + progressBar: ProgressBar, ): List> = opendriveModel.roadAsNonEmptyList.map { roadspaceBuilder.buildRoadspace(it).also { progressBar.step() } @@ -100,13 +100,14 @@ class Opendrive2RoadspacesTransformer( @OptIn(DelicateCoroutinesApi::class) private fun transformRoadspacesConcurrently( opendriveModel: OpendriveModel, - progressBar: ProgressBar + progressBar: ProgressBar, ): List> { - val roadspacesDeferred = opendriveModel.roadAsNonEmptyList.map { - GlobalScope.async { - roadspaceBuilder.buildRoadspace(it).also { progressBar.step() } + val roadspacesDeferred = + opendriveModel.roadAsNonEmptyList.map { + GlobalScope.async { + roadspaceBuilder.buildRoadspace(it).also { progressBar.step() } + } } - } return runBlocking { roadspacesDeferred.map { it.await() } } } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/analysis/FunctionBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/analysis/FunctionBuilder.kt index 8fc8eef7..cc7824ff 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/analysis/FunctionBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/analysis/FunctionBuilder.kt @@ -33,7 +33,6 @@ import io.rtron.std.isStrictlySortedBy * Builder for functions of the OpenDRIVE data model. */ object FunctionBuilder { - // Methods /** @@ -48,7 +47,7 @@ object FunctionBuilder { superelevation.map { it.s }, superelevation.map { it.coefficients }, prependConstant = true, - prependConstantValue = 0.0 + prependConstantValue = 0.0, ) } @@ -58,13 +57,21 @@ object FunctionBuilder { * @param roadLateralProfileShape the cross-sectional profile of a road at a certain curve position */ fun buildLateralShape(roadLateralProfileShape: NonEmptyList): UnivariateFunction { - require(roadLateralProfileShape.all { it.s == roadLateralProfileShape.first().s }) { "All lateral profile shape elements must have the same curve position." } - require(roadLateralProfileShape.isStrictlySortedBy { it.t }) { "Lateral profile shape entries must be sorted in strict order according to t." } + require( + roadLateralProfileShape.all { + it.s == roadLateralProfileShape.first().s + }, + ) { "All lateral profile shape elements must have the same curve position." } + require( + roadLateralProfileShape.isStrictlySortedBy { + it.t + }, + ) { "Lateral profile shape entries must be sorted in strict order according to t." } return ConcatenatedFunction.ofPolynomialFunctions( roadLateralProfileShape.map { it.t }, roadLateralProfileShape.map { it.coefficients }, - prependConstant = true + prependConstant = true, ) } @@ -78,7 +85,7 @@ object FunctionBuilder { laneOffsets.map { it.s }, laneOffsets.map { it.coefficients }, prependConstant = true, - prependConstantValue = 0.0 + prependConstantValue = 0.0, ) } @@ -88,15 +95,20 @@ object FunctionBuilder { * @param laneWidthEntries entries containing coefficients for polynomial functions * @return function describing the width of a lane */ - fun buildLaneWidth(laneWidthEntries: NonEmptyList, numberTolerance: Double): UnivariateFunction { - require(laneWidthEntries.isStrictlySortedBy { it.sOffset }) { "Width entries of lane must be strictly sorted according to sOffset." } + fun buildLaneWidth( + laneWidthEntries: NonEmptyList, + numberTolerance: Double, + ): UnivariateFunction { + require( + laneWidthEntries.isStrictlySortedBy { it.sOffset }, + ) { "Width entries of lane must be strictly sorted according to sOffset." } require(laneWidthEntries.head.sOffset < numberTolerance) { "First width entry must start with sOffset=0.0." } return ConcatenatedFunction.ofPolynomialFunctions( laneWidthEntries.map { it.sOffset }, laneWidthEntries.map { it.coefficients }, prependConstant = true, - prependConstantValue = 0.0 + prependConstantValue = 0.0, ) } @@ -108,12 +120,15 @@ object FunctionBuilder { * @param roadReferenceLine road's height * @return function of the object's absolute height */ - fun buildStackedHeightFunctionFromRepeat(repeat: RoadObjectsObjectRepeat, roadReferenceLine: Curve3D): - StackedFunction { - val heightFunctionSection = SectionedUnivariateFunction( - roadReferenceLine.heightFunction, - repeat.getRoadReferenceLineParameterSection() - ) + fun buildStackedHeightFunctionFromRepeat( + repeat: RoadObjectsObjectRepeat, + roadReferenceLine: Curve3D, + ): StackedFunction { + val heightFunctionSection = + SectionedUnivariateFunction( + roadReferenceLine.heightFunction, + repeat.getRoadReferenceLineParameterSection(), + ) return StackedFunction.ofSum(heightFunctionSection, repeat.getHeightOffsetFunction()) } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Curve2DBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Curve2DBuilder.kt index 3fd2fb1a..a004407f 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Curve2DBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Curve2DBuilder.kt @@ -48,7 +48,6 @@ import io.rtron.std.isStrictlySortedBy * Builder for curves in 2D from the OpenDRIVE data model. */ object Curve2DBuilder { - // Methods /** @@ -60,10 +59,16 @@ object Curve2DBuilder { planViewGeometryList: NonEmptyList, numberTolerance: Double, distanceTolerance: Double, - angleTolerance: Double + angleTolerance: Double, ): CompositeCurve2D { - require(planViewGeometryList.all { it.length > numberTolerance }) { "All plan view geometry elements must have a length greater than zero (above the tolerance threshold)." } - require(planViewGeometryList.isStrictlySortedBy { it.s }) { "Plan view geometry elements must be sorted in strict order according to s." } + require( + planViewGeometryList.all { + it.length > numberTolerance + }, + ) { "All plan view geometry elements must have a length greater than zero (above the tolerance threshold)." } + require( + planViewGeometryList.isStrictlySortedBy { it.s }, + ) { "Plan view geometry elements must be sorted in strict order according to s." } val (curveMembers, absoluteDomains, absoluteStarts) = prepareCurveMembers(planViewGeometryList, numberTolerance) @@ -74,21 +79,25 @@ object Curve2DBuilder { /** * Prepares the list of [RoadPlanViewGeometry] for constructing the composite curve. */ - fun prepareCurveMembers(planViewGeometryList: NonEmptyList, numberTolerance: Double): - Triple, List>, List> { + fun prepareCurveMembers( + planViewGeometryList: NonEmptyList, + numberTolerance: Double, + ): Triple, List>, List> { // absolute positions for each curve member val absoluteStarts: List = planViewGeometryList.map { it.s } // domains for each curve member - val absoluteDomains: List> = absoluteStarts - .zipWithNext().map { Range.closedOpen(it.first, it.second) } + - Range.closed(absoluteStarts.last(), absoluteStarts.last() + planViewGeometryList.last().length) + val absoluteDomains: List> = + absoluteStarts + .zipWithNext().map { Range.closedOpen(it.first, it.second) } + + Range.closed(absoluteStarts.last(), absoluteStarts.last() + planViewGeometryList.last().length) // length derived from absolute values to increase robustness val lengths: List = absoluteDomains.map { it.length } // construct individual curve members - val curveMembers = planViewGeometryList.zip(lengths).dropLast(1) - .map { buildPlanViewGeometry(it.first, it.second, BoundType.OPEN, numberTolerance) } + - buildPlanViewGeometry(planViewGeometryList.last(), lengths.last(), BoundType.CLOSED, numberTolerance) + val curveMembers = + planViewGeometryList.zip(lengths).dropLast(1) + .map { buildPlanViewGeometry(it.first, it.second, BoundType.OPEN, numberTolerance) } + + buildPlanViewGeometry(planViewGeometryList.last(), lengths.last(), BoundType.CLOSED, numberTolerance) return Triple(curveMembers, absoluteDomains, absoluteStarts) } @@ -104,25 +113,29 @@ object Curve2DBuilder { geometry: RoadPlanViewGeometry, length: Double, endBoundType: BoundType = BoundType.OPEN, - numberTolerance: Double + numberTolerance: Double, ): AbstractCurve2D { require( fuzzyEquals( geometry.length, length, - numberTolerance - ) - ) { "Plan view geometry element (s=${geometry.s}) contains a length value that does not match the start value of the next geometry element." } + numberTolerance, + ), + ) { + "Plan view geometry element (s=${geometry.s}) contains a length value that does not match " + + "the start value of the next geometry element." + } val startPose = Pose2D(Vector2D(geometry.x, geometry.y), Rotation2D(geometry.hdg)) val affineSequence = AffineSequence2D(Affine2D.of(startPose)) geometry.spiral.onSome { - val curvatureFunction = LinearFunction.ofInclusiveInterceptAndPoint( - it.curvStart, - length, - it.curvEnd - ) + val curvatureFunction = + LinearFunction.ofInclusiveInterceptAndPoint( + it.curvStart, + length, + it.curvEnd, + ) return SpiralSegment2D(curvatureFunction, numberTolerance, affineSequence, endBoundType) } @@ -132,7 +145,7 @@ object Curve2DBuilder { length, numberTolerance, affineSequence, - endBoundType + endBoundType, ) } @@ -142,7 +155,7 @@ object Curve2DBuilder { length, numberTolerance, affineSequence, - endBoundType + endBoundType, ) } @@ -150,18 +163,19 @@ object Curve2DBuilder { return if (it.isNormalized()) { val parameterTransformation: (CurveRelativeVector1D) -> CurveRelativeVector1D = { curveRelativePoint -> curveRelativePoint / length } - val baseCurve = ParametricCubicCurve2D( - it.coefficientsU, - it.coefficientsV, - 1.0, - numberTolerance, - affineSequence, - endBoundType - ) + val baseCurve = + ParametricCubicCurve2D( + it.coefficientsU, + it.coefficientsV, + 1.0, + numberTolerance, + affineSequence, + endBoundType, + ) ParameterTransformedCurve2D( baseCurve, parameterTransformation, - Range.closedX(0.0, length, endBoundType) + Range.closedX(0.0, length, endBoundType), ) } else { ParametricCubicCurve2D( @@ -170,7 +184,7 @@ object Curve2DBuilder { length, numberTolerance, affineSequence, - endBoundType + endBoundType, ) } } @@ -185,15 +199,18 @@ object Curve2DBuilder { fun buildLateralTranslatedCurve( repeat: RoadObjectsObjectRepeat, roadReferenceLine: Curve3D, - numberTolerance: Double + numberTolerance: Double, ): LateralTranslatedCurve2D { val repeatObjectDomain = repeat.getRoadReferenceLineParameterSection() require( roadReferenceLine.curveXY.domain.fuzzyEncloses( repeatObjectDomain, - numberTolerance - ) - ) { "Domain of repeat road object ($repeatObjectDomain) is not enclosed by the domain of the reference line (${roadReferenceLine.curveXY.domain}) according to the tolerance." } + numberTolerance, + ), + ) { + "Domain of repeat road object ($repeatObjectDomain) is not enclosed by the domain of the reference line (" + + "${roadReferenceLine.curveXY.domain}) according to the tolerance." + } val section = SectionedCurve2D(roadReferenceLine.curveXY, repeatObjectDomain) return LateralTranslatedCurve2D(section, repeat.getLateralOffsetFunction(), numberTolerance) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Curve3DBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Curve3DBuilder.kt index 78e86af9..654ee11d 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Curve3DBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Curve3DBuilder.kt @@ -32,7 +32,6 @@ import io.rtron.transformer.converter.opendrive2roadspaces.analysis.FunctionBuil * Builder for curves in 3D from the OpenDRIVE data model. */ object Curve3DBuilder { - // Methods /** @@ -43,14 +42,15 @@ object Curve3DBuilder { elevationProfiles: Option>, numberTolerance: Double, distanceTolerance: Double, - angleTolerance: Double + angleTolerance: Double, ): Curve3D { - val planViewCurve2D = Curve2DBuilder.buildCurve2DFromPlanViewGeometries( - planViewGeometries, - numberTolerance, - distanceTolerance, - angleTolerance - ) + val planViewCurve2D = + Curve2DBuilder.buildCurve2DFromPlanViewGeometries( + planViewGeometries, + numberTolerance, + distanceTolerance, + angleTolerance, + ) val heightFunction = elevationProfiles.fold({ LinearFunction.X_AXIS }, { buildHeightFunction(it) }) return Curve3D(planViewCurve2D, heightFunction) @@ -66,20 +66,30 @@ object Curve3DBuilder { elevationProfiles.map { it.s }, elevationProfiles.map { it.coefficients }, prependConstant = true, - prependConstantValue = 0.0 + prependConstantValue = 0.0, ) } /** * Builds a curve in 3D from OpenDRIVE's road object entry [roadObject]. */ - fun buildCurve3D(roadObject: RoadObjectsObject, roadReferenceLine: Curve3D, numberTolerance: Double): List { + fun buildCurve3D( + roadObject: RoadObjectsObject, + roadReferenceLine: Curve3D, + numberTolerance: Double, + ): List { if (roadObject.repeat.isEmpty()) return emptyList() // TODO fix repeat list handling if (!roadObject.repeat.first().containsCurve()) return emptyList() // TODO fix repeat list handling - val curve2D = Curve2DBuilder.buildLateralTranslatedCurve(roadObject.repeat.first(), roadReferenceLine, numberTolerance) // TODO fix repeat list handling - val heightFunction = FunctionBuilder - .buildStackedHeightFunctionFromRepeat(roadObject.repeat.first(), roadReferenceLine) // TODO fix repeat list handling + val curve2D = + Curve2DBuilder.buildLateralTranslatedCurve( + roadObject.repeat.first(), + roadReferenceLine, + numberTolerance, + ) // TODO fix repeat list handling + val heightFunction = + FunctionBuilder + .buildStackedHeightFunctionFromRepeat(roadObject.repeat.first(), roadReferenceLine) // TODO fix repeat list handling val curve3D = Curve3D(curve2D, heightFunction) return listOf(curve3D) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/GeometryBuilderException.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/GeometryBuilderException.kt index a84e0659..c0785087 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/GeometryBuilderException.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/GeometryBuilderException.kt @@ -19,12 +19,14 @@ package io.rtron.transformer.converter.opendrive2roadspaces.geometry import io.rtron.model.opendrive.additions.identifier.AbstractOpendriveIdentifier sealed class GeometryBuilderException(val message: String, open val location: AbstractOpendriveIdentifier) { - data class NotEnoughValidOutlineElementsForPolyhedron(override val location: AbstractOpendriveIdentifier) : GeometryBuilderException("A polyhedron requires at least three valid outline elements.", location) data class ColinearOutlineElementsForPolyhedron(override val location: AbstractOpendriveIdentifier) : - GeometryBuilderException("A polyhedron requires at least three valid outline elements, which are not colinear (located on a line).", location) + GeometryBuilderException( + "A polyhedron requires at least three valid outline elements, which are not colinear (located on a line).", + location, + ) data class TriangulationException(val reason: String, override val location: AbstractOpendriveIdentifier) : GeometryBuilderException("Triangulation algorithm failed: $reason", location) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/LinearRing3DFactory.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/LinearRing3DFactory.kt index ae3b8f43..836e64eb 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/LinearRing3DFactory.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/LinearRing3DFactory.kt @@ -39,54 +39,79 @@ import io.rtron.transformer.issues.opendrive.of * heterogeneous input. */ object LinearRing3DFactory { - /** * Builds a [LinearRing3D] from a list of vertices by filtering and preparing the vertices. */ - fun buildFromVertices(outlineId: RoadObjectOutlineIdentifier, vertices: NonEmptyList, tolerance: Double): Either> = either { - val issueList = DefaultIssueList() + fun buildFromVertices( + outlineId: RoadObjectOutlineIdentifier, + vertices: NonEmptyList, + tolerance: Double, + ): Either> = + either { + val issueList = DefaultIssueList() - // remove end element, if start and end element are equal - val verticesWithoutClosing = if (vertices.first() == vertices.last()) { - vertices.dropLast(1) - } else { - vertices - } + // remove end element, if start and end element are equal + val verticesWithoutClosing = + if (vertices.first() == vertices.last()) { + vertices.dropLast(1) + } else { + vertices + } - // remove consecutively following point duplicates - val verticesWithoutPointDuplicates = verticesWithoutClosing.filterWithNextEnclosing { a, b -> a.fuzzyUnequals(b, tolerance) } - if (verticesWithoutPointDuplicates.size < verticesWithoutClosing.size) { - issueList += DefaultIssue.of("OutlineContainsConsecutivelyFollowingElementDuplicates", "Ignoring at least one consecutively following point duplicate.", outlineId, Severity.WARNING, wasFixed = true) - } + // remove consecutively following point duplicates + val verticesWithoutPointDuplicates = verticesWithoutClosing.filterWithNextEnclosing { a, b -> a.fuzzyUnequals(b, tolerance) } + if (verticesWithoutPointDuplicates.size < verticesWithoutClosing.size) { + issueList += + DefaultIssue.of( + "OutlineContainsConsecutivelyFollowingElementDuplicates", + "Ignoring at least one consecutively following point duplicate.", outlineId, Severity.WARNING, wasFixed = true, + ) + } - // remove consecutively following side duplicates - val verticesWithoutSideDuplicates = verticesWithoutPointDuplicates.removeConsecutiveSideDuplicates() - if (verticesWithoutSideDuplicates.size != verticesWithoutPointDuplicates.size) { - issueList += DefaultIssue.of("OutlineContainsConsecutivelyFollowingSideDuplicates", "Ignoring at least one consecutively following side duplicate of the form (…, A, B, A,…).", outlineId, Severity.WARNING, wasFixed = true) - } + // remove consecutively following side duplicates + val verticesWithoutSideDuplicates = verticesWithoutPointDuplicates.removeConsecutiveSideDuplicates() + if (verticesWithoutSideDuplicates.size != verticesWithoutPointDuplicates.size) { + issueList += + DefaultIssue.of( + "OutlineContainsConsecutivelyFollowingSideDuplicates", + "Ignoring at least one consecutively following side duplicate of the form (…, A, B, A,…).", + outlineId, Severity.WARNING, wasFixed = true, + ) + } - // remove vertices that are located on a line anyway - val preparedVertices = verticesWithoutSideDuplicates - .removeRedundantVerticesOnLineSegmentsEnclosing(tolerance) - if (preparedVertices.size < verticesWithoutSideDuplicates.size) { - issueList += DefaultIssue.of("OutlineContainsLinearlyRedundantVertices", "Ignoring at least one vertex due to linear redundancy.", outlineId, Severity.WARNING, wasFixed = true) - } + // remove vertices that are located on a line anyway + val preparedVertices = + verticesWithoutSideDuplicates + .removeRedundantVerticesOnLineSegmentsEnclosing(tolerance) + if (preparedVertices.size < verticesWithoutSideDuplicates.size) { + issueList += + DefaultIssue.of( + "OutlineContainsLinearlyRedundantVertices", + "Ignoring at least one vertex due to linear redundancy.", outlineId, Severity.WARNING, wasFixed = true, + ) + } - // if there are not enough points to construct a linear ring - if (preparedVertices.size <= 2) { - GeometryBuilderException.NotEnoughValidOutlineElementsForLinearRing(outlineId).left().bind>() - } + // if there are not enough points to construct a linear ring + if (preparedVertices.size <= 2) { + GeometryBuilderException.NotEnoughValidOutlineElementsForLinearRing(outlineId).left().bind>() + } - // if the outline elements are ordered clockwise yielding a wrong polygon orientation - val projectedVertices = preparedVertices.map { it.toVector2D(Vector3D.Z_AXIS) } - val orderedVertices = if (projectedVertices.distinct().size > 2 && projectedVertices.isClockwiseOrdered()) { - issueList += DefaultIssue.of("IncorrectOutlineOrientation", "Outline elements are ordered clockwise but should be ordered counter-clockwise.", outlineId, Severity.ERROR, wasFixed = true) - preparedVertices.reversed() - } else { - preparedVertices - } + // if the outline elements are ordered clockwise yielding a wrong polygon orientation + val projectedVertices = preparedVertices.map { it.toVector2D(Vector3D.Z_AXIS) } + val orderedVertices = + if (projectedVertices.distinct().size > 2 && projectedVertices.isClockwiseOrdered()) { + issueList += + DefaultIssue.of( + "IncorrectOutlineOrientation", + "Outline elements are ordered clockwise but should be ordered counter-clockwise.", + outlineId, Severity.ERROR, wasFixed = true, + ) + preparedVertices.reversed() + } else { + preparedVertices + } - val linearRing = LinearRing3D(orderedVertices.toNonEmptyListOrNull()!!, tolerance) - ContextIssueList(linearRing, issueList) - } + val linearRing = LinearRing3D(orderedVertices.toNonEmptyListOrNull()!!, tolerance) + ContextIssueList(linearRing, issueList) + } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Polyhedron3DFactory.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Polyhedron3DFactory.kt index c4eae6df..9b7b138e 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Polyhedron3DFactory.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Polyhedron3DFactory.kt @@ -52,38 +52,45 @@ import kotlin.collections.flatten * heterogeneous input. */ object Polyhedron3DFactory { - /** * Builds a [Polyhedron3D] from a list of [VerticalOutlineElement], which define the boundary of the [Polyhedron3D]. * * @param outlineElements vertical line segments or points bounding the polyhedron */ - fun buildFromVerticalOutlineElements(outlineId: RoadObjectOutlineIdentifier, outlineElements: NonEmptyList, tolerance: Double): - Either> = either { - val issueList = DefaultIssueList() - - // prepare vertical outline elements - val preparedOutlineElements = prepareOutlineElements(outlineId, outlineElements, tolerance) - .bind() - .handleIssueList { issueList += it } - - // construct faces - val baseFace = LinearRing3D(preparedOutlineElements.reversed().map { it.basePoint }.let { it.toNonEmptyListOrNull()!! }, tolerance) - val topFace = LinearRing3D(preparedOutlineElements.flatMap { it.getHighestPointAdjacentToTheTop() }, tolerance) - val sideFaces: List = preparedOutlineElements - .zipWithNextEnclosing() - .flatMap { buildSideFace(it.first, it.second, tolerance).toList() } - - // triangulate faces - val triangulatedFaces = (sideFaces + baseFace + topFace) - .map { currentFace -> Triangulator.triangulate(currentFace, tolerance) } - .handleLeftAndFilter { GeometryBuilderException.TriangulationException(it.value.message, outlineId).left().bind() } - .flatten() - .let { it.toNonEmptyListOrNull()!! } - - val polyhedron = Polyhedron3D(triangulatedFaces, tolerance) - ContextIssueList(polyhedron, issueList) - } + fun buildFromVerticalOutlineElements( + outlineId: RoadObjectOutlineIdentifier, + outlineElements: NonEmptyList, + tolerance: Double, + ): Either> = + either { + val issueList = DefaultIssueList() + + // prepare vertical outline elements + val preparedOutlineElements = + prepareOutlineElements(outlineId, outlineElements, tolerance) + .bind() + .handleIssueList { issueList += it } + + // construct faces + val baseFace = + LinearRing3D(preparedOutlineElements.reversed().map { it.basePoint }.let { it.toNonEmptyListOrNull()!! }, tolerance) + val topFace = LinearRing3D(preparedOutlineElements.flatMap { it.getHighestPointAdjacentToTheTop() }, tolerance) + val sideFaces: List = + preparedOutlineElements + .zipWithNextEnclosing() + .flatMap { buildSideFace(it.first, it.second, tolerance).toList() } + + // triangulate faces + val triangulatedFaces = + (sideFaces + baseFace + topFace) + .map { currentFace -> Triangulator.triangulate(currentFace, tolerance) } + .handleLeftAndFilter { GeometryBuilderException.TriangulationException(it.value.message, outlineId).left().bind() } + .flatten() + .let { it.toNonEmptyListOrNull()!! } + + val polyhedron = Polyhedron3D(triangulatedFaces, tolerance) + ContextIssueList(polyhedron, issueList) + } /** * A vertical outline element is represented by a [basePoint] and an optional [leftHeadPoint] and [rightHeadPoint]. @@ -97,9 +104,8 @@ object Polyhedron3DFactory { val basePoint: Vector3D, val leftHeadPoint: Option, val rightHeadPoint: Option = None, - override val tolerance: Double + override val tolerance: Double, ) : Tolerable { - // Properties and Initializers init { rightHeadPoint.onSome { @@ -110,22 +116,22 @@ object Polyhedron3DFactory { require( basePoint.fuzzyUnequals( currentLeftHeadPoint, - tolerance - ) + tolerance, + ), ) { "Left head point must be fuzzily unequal to base point." } rightHeadPoint.onSome { currentRightHeadPoint -> require( basePoint.fuzzyUnequals( currentRightHeadPoint, - tolerance - ) + tolerance, + ), ) { "Right head point must be fuzzily unequal to base point." } require( currentLeftHeadPoint.fuzzyUnequals( currentRightHeadPoint, - tolerance - ) + tolerance, + ), ) { "Left head point must be fuzzily unequal to the right point." } } } @@ -136,14 +142,16 @@ object Polyhedron3DFactory { // Methods fun containsHeadPoint() = leftHeadPoint.isSome() || rightHeadPoint.isSome() + fun containsOneHeadPoint() = leftHeadPoint.isSome() && rightHeadPoint.isNone() fun getVerticesAsLeftBoundary(): List { - val midPoint = if (containsOneHeadPoint() || leftLength < rightLength) { - leftHeadPoint.toList() - } else { - emptyList() - } + val midPoint = + if (containsOneHeadPoint() || leftLength < rightLength) { + leftHeadPoint.toList() + } else { + emptyList() + } return listOf(basePoint) + midPoint + rightHeadPoint.toList() } @@ -162,12 +170,11 @@ object Polyhedron3DFactory { } companion object { - fun of( basePoint: Vector3D, leftHeadPoint: Option, rightHeadPoint: Option, - tolerance: Double + tolerance: Double, ): ContextIssueList { val issueList = DefaultIssueList() val headPoints = leftHeadPoint.toList() + rightHeadPoint.toList() @@ -175,13 +182,12 @@ object Polyhedron3DFactory { // remove head points that are fuzzily equal to base point val prepHeadPoints = headPoints.filter { it.fuzzyUnequals(basePoint, tolerance) } if (prepHeadPoints.size < headPoints.size) { - issueList += DefaultIssue( - "", - "Height of outline element must be above tolerance.", - "", - Severity.WARNING, - true - ) + issueList += + DefaultIssue( + "", + "Height of outline element must be above tolerance.", + "", Severity.WARNING, true, + ) } if (prepHeadPoints.size <= 1) { @@ -205,7 +211,11 @@ object Polyhedron3DFactory { * @param headPoints a maximum number of two head points must be provided * @param tolerance allowed tolerance */ - fun of(basePoint: Vector3D, headPoints: List, tolerance: Double): VerticalOutlineElement { + fun of( + basePoint: Vector3D, + headPoints: List, + tolerance: Double, + ): VerticalOutlineElement { require(headPoints.size <= 2) { "Must contain not more than two head points." } val leftHeadPoint = if (headPoints.isNotEmpty()) Some(headPoints.first()) else None @@ -222,12 +232,12 @@ object Polyhedron3DFactory { */ fun of( elements: List, - tolerance: Double + tolerance: Double, ): ContextIssueList { require(elements.isNotEmpty()) { "List of elements must not be empty." } require( elements.drop(1) - .all { it.basePoint == elements.first().basePoint } + .all { it.basePoint == elements.first().basePoint }, ) { "All elements must have the same base point." } val issueList = DefaultIssueList() @@ -236,13 +246,12 @@ object Polyhedron3DFactory { } if (elements.size > 2) { - issueList += DefaultIssue( - "OutlineContainsConsecutivelyFollowingElementDuplicates", - "Contains more than two consecutively following outline element duplicates.", - "", - Severity.WARNING, - wasFixed = false - ) + issueList += + DefaultIssue( + "OutlineContainsConsecutivelyFollowingElementDuplicates", + "Contains more than two consecutively following outline element duplicates.", + "", Severity.WARNING, wasFixed = false, + ) } val basePoint = elements.first().basePoint @@ -266,7 +275,7 @@ object Polyhedron3DFactory { private fun buildSideFace( leftElement: VerticalOutlineElement, rightElement: VerticalOutlineElement, - tolerance: Double + tolerance: Double, ): Option { if (!leftElement.containsHeadPoint() && !rightElement.containsHeadPoint()) { return None @@ -280,50 +289,88 @@ object Polyhedron3DFactory { /** * Preparation and cleanup of [verticalOutlineElements] including the removal of duplicates and error messaging. */ - private fun prepareOutlineElements(outlineId: RoadObjectOutlineIdentifier, verticalOutlineElements: NonEmptyList, tolerance: Double): - Either>> = either { - val issueList = DefaultIssueList() - - // remove consecutively following line segment duplicates - val elementsWithoutDuplicates = verticalOutlineElements.filterWithNextEnclosing { a, b -> a.basePoint.fuzzyUnequals(b.basePoint, tolerance) } - if (elementsWithoutDuplicates.size < verticalOutlineElements.size) { - issueList += DefaultIssue.of("OutlineContainsConsecutivelyFollowingLineSegmentDuplicates", "Ignoring at least one consecutively following line segment duplicate.", outlineId, Severity.WARNING, wasFixed = true) - } + private fun prepareOutlineElements( + outlineId: RoadObjectOutlineIdentifier, + verticalOutlineElements: NonEmptyList, + tolerance: Double, + ): Either>> = + either { + val issueList = DefaultIssueList() + + // remove consecutively following line segment duplicates + val elementsWithoutDuplicates = + verticalOutlineElements.filterWithNextEnclosing { + a, + b, + -> + a.basePoint.fuzzyUnequals(b.basePoint, tolerance) + } + if (elementsWithoutDuplicates.size < verticalOutlineElements.size) { + issueList += + DefaultIssue.of( + "OutlineContainsConsecutivelyFollowingLineSegmentDuplicates", + "Ignoring at least one consecutively following line segment duplicate.", + outlineId, Severity.WARNING, wasFixed = true, + ) + } - // if there are not enough points to construct a polyhedron - if (elementsWithoutDuplicates.size < 3) { - GeometryBuilderException.NotEnoughValidOutlineElementsForPolyhedron(outlineId).left().bind>>() - } + // if there are not enough points to construct a polyhedron + if (elementsWithoutDuplicates.size < 3) { + GeometryBuilderException.NotEnoughValidOutlineElementsForPolyhedron( + outlineId, + ).left().bind>>() + } - // remove consecutively following side duplicates of the form (…, A, B, A, …) - val cleanedElements = elementsWithoutDuplicates - .filterWindowedEnclosing(listOf(false, true, true)) { it[0].basePoint == it[2].basePoint } - if (cleanedElements.size < elementsWithoutDuplicates.size) { - issueList += DefaultIssue.of("OutlineContainsConsecutivelyFollowingSideDuplicates", "Ignoring consecutively following side duplicates of the form (…, A, B, A, …).", outlineId, Severity.WARNING, wasFixed = true) - } + // remove consecutively following side duplicates of the form (…, A, B, A, …) + val cleanedElements = + elementsWithoutDuplicates + .filterWindowedEnclosing(listOf(false, true, true)) { it[0].basePoint == it[2].basePoint } + if (cleanedElements.size < elementsWithoutDuplicates.size) { + issueList += + DefaultIssue.of( + "OutlineContainsConsecutivelyFollowingSideDuplicates", + "Ignoring consecutively following side duplicates of the form (…, A, B, A, …).", + outlineId, Severity.WARNING, wasFixed = true, + ) + } - // if the base points of the outline element are located on a line (or point) - val innerBaseEdges = cleanedElements.map { it.basePoint }.filterIndexed { index, _ -> index != 0 }.map { it - cleanedElements.first().basePoint } - val dimensionOfSpan = innerBaseEdges.map { it.toRealVector() }.dimensionOfSpan() - if (dimensionOfSpan < 2) { - GeometryBuilderException.ColinearOutlineElementsForPolyhedron(outlineId).left().bind>>() - } + // if the base points of the outline element are located on a line (or point) + val innerBaseEdges = + cleanedElements.map { it.basePoint }.filterIndexed { + index, + _, + -> + index != 0 + }.map { it - cleanedElements.first().basePoint } + val dimensionOfSpan = innerBaseEdges.map { it.toRealVector() }.dimensionOfSpan() + if (dimensionOfSpan < 2) { + GeometryBuilderException.ColinearOutlineElementsForPolyhedron( + outlineId, + ).left().bind>>() + } - // if the outline elements are ordered clockwise yielding a wrong polygon orientation - val projectedBasePoints = cleanedElements.map { it.basePoint.toVector2D(Vector3D.Z_AXIS) } - val orderedElements = if (projectedBasePoints.distinct().size > 2 && projectedBasePoints.isClockwiseOrdered()) { - issueList += DefaultIssue.of("IncorrectOutlineOrientation", "Outline elements are ordered clockwise but should be ordered counter-clockwise.", outlineId, Severity.ERROR, wasFixed = true) - cleanedElements.reversed() - } else { - cleanedElements - } + // if the outline elements are ordered clockwise yielding a wrong polygon orientation + val projectedBasePoints = cleanedElements.map { it.basePoint.toVector2D(Vector3D.Z_AXIS) } + val orderedElements = + if (projectedBasePoints.distinct().size > 2 && projectedBasePoints.isClockwiseOrdered()) { + issueList += + DefaultIssue.of( + "IncorrectOutlineOrientation", + "Outline elements are ordered clockwise but should be ordered counter-clockwise.", + outlineId, Severity.ERROR, wasFixed = true, + ) + cleanedElements.reversed() + } else { + cleanedElements + } - val elements: ContextIssueList> = orderedElements - .zipWithConsecutivesEnclosing { it.basePoint } - .map { VerticalOutlineElement.of(it, tolerance) } - .mergeIssueLists() - .map { it.toNonEmptyListOrNull()!! } + val elements: ContextIssueList> = + orderedElements + .zipWithConsecutivesEnclosing { it.basePoint } + .map { VerticalOutlineElement.of(it, tolerance) } + .mergeIssueLists() + .map { it.toNonEmptyListOrNull()!! } - elements - } + elements + } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Solid3DBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Solid3DBuilder.kt index a321ac7d..bb7ae364 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Solid3DBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Solid3DBuilder.kt @@ -48,14 +48,17 @@ import io.rtron.transformer.issues.opendrive.of * Builder for solid geometries in 3D from the OpenDRIVE data model. */ object Solid3DBuilder { - // Methods /** * Builds a list of cuboids from the OpenDRIVE road object class ([RoadObjectsObject]) directly or from the * repeated entries defined in [RoadObjectsObjectRepeat]. */ - fun buildCuboids(roadObject: RoadObjectsObject, curveAffine: Affine3D, numberTolerance: Double): Cuboid3D { + fun buildCuboids( + roadObject: RoadObjectsObject, + curveAffine: Affine3D, + numberTolerance: Double, + ): Cuboid3D { require(roadObject.containsCuboid()) { "Road object must contain cuboid." } val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose) @@ -66,7 +69,7 @@ object Solid3DBuilder { roadObject.width, roadObject.heightValidated, numberTolerance, - affineSequence + affineSequence, ) } @@ -74,7 +77,11 @@ object Solid3DBuilder { * Builds a list of cylinders from the OpenDRIVE road object class ([RoadObjectsObject]) directly or from the * repeated entries defined in [RoadObjectsObjectRepeat]. */ - fun buildCylinders(roadObject: RoadObjectsObject, curveAffine: Affine3D, numberTolerance: Double): Cylinder3D { + fun buildCylinders( + roadObject: RoadObjectsObject, + curveAffine: Affine3D, + numberTolerance: Double, + ): Cylinder3D { require(roadObject.containsCylinder()) { "Road object must contain cylinder." } val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose) @@ -89,15 +96,26 @@ object Solid3DBuilder { * @param roadReferenceLine road reference line for transforming curve relative coordinates * @return list of polyhedrons */ - fun buildPolyhedronsByRoadCorners(roadObject: RoadObjectsObject, roadReferenceLine: Curve3D, numberTolerance: Double): ContextIssueList> { + fun buildPolyhedronsByRoadCorners( + roadObject: RoadObjectsObject, + roadReferenceLine: Curve3D, + numberTolerance: Double, + ): ContextIssueList> { val issueList = DefaultIssueList() - val (builderExceptions, polyhedronsWithContext) = roadObject - .getPolyhedronsDefinedByRoadCorners() - .map { buildPolyhedronByRoadCorners(it, roadReferenceLine, numberTolerance) } - .separateEither() + val (builderExceptions, polyhedronsWithContext) = + roadObject + .getPolyhedronsDefinedByRoadCorners() + .map { buildPolyhedronByRoadCorners(it, roadReferenceLine, numberTolerance) } + .separateEither() - issueList += builderExceptions.map { DefaultIssue.of("PolyhedronNotConstructableFromRoadCornerOutlines", it.message, it.location, Severity.WARNING, wasFixed = true) }.mergeToReport() + issueList += + builderExceptions.map { + DefaultIssue.of( + "PolyhedronNotConstructableFromRoadCornerOutlines", it.message, it.location, + Severity.WARNING, wasFixed = true, + ) + }.mergeToReport() val polyhedrons = polyhedronsWithContext.handleIssueList { issueList += it.issueList } return ContextIssueList(polyhedrons, issueList) @@ -106,15 +124,28 @@ object Solid3DBuilder { /** * Builds a single polyhedron from an OpenDRIVE road object defined by road corner outlines. */ - private fun buildPolyhedronByRoadCorners(outline: RoadObjectsObjectOutlinesOutline, referenceLine: Curve3D, numberTolerance: Double): - Either> { + private fun buildPolyhedronByRoadCorners( + outline: RoadObjectsObjectOutlinesOutline, + referenceLine: Curve3D, + numberTolerance: Double, + ): Either> { require(outline.isPolyhedronDefinedByRoadCorners()) { "Outline does not contain a polyhedron represented by road corners." } - require(outline.cornerLocal.all { it.height == 0.0 || numberTolerance <= it.height }) { "All cornerRoad elements must have a height of either zero or above the tolerance threshold." } - val outlineId = outline.additionalId.toEither { IllegalStateException("Additional outline ID must be available.") }.getOrElse { throw it } + require( + outline.cornerLocal.all { + it.height == 0.0 || numberTolerance <= it.height + }, + ) { "All cornerRoad elements must have a height of either zero or above the tolerance threshold." } + val outlineId = + outline.additionalId.toEither { + IllegalStateException( + "Additional outline ID must be available.", + ) + }.getOrElse { throw it } - val verticalOutlineElements = outline.cornerRoad - .map { buildVerticalOutlineElement(it, referenceLine, numberTolerance) } - .let { it.toNonEmptyListOrNull()!! } + val verticalOutlineElements = + outline.cornerRoad + .map { buildVerticalOutlineElement(it, referenceLine, numberTolerance) } + .let { it.toNonEmptyListOrNull()!! } return Polyhedron3DFactory.buildFromVerticalOutlineElements(outlineId, verticalOutlineElements, numberTolerance) } @@ -125,13 +156,17 @@ object Solid3DBuilder { * @param cornerRoad road corner element of OpenDRIVE which defines one corner of a road object * @param roadReferenceLine road reference line for transforming curve relative coordinates */ - private fun buildVerticalOutlineElement(cornerRoad: RoadObjectsObjectOutlinesOutlineCornerRoad, roadReferenceLine: Curve3D, numberTolerance: Double): - Polyhedron3DFactory.VerticalOutlineElement { + private fun buildVerticalOutlineElement( + cornerRoad: RoadObjectsObjectOutlinesOutlineCornerRoad, + roadReferenceLine: Curve3D, + numberTolerance: Double, + ): Polyhedron3DFactory.VerticalOutlineElement { val curveRelativeOutlineElementGeometry = cornerRoad.getPoints() val basePoint = roadReferenceLine.transform(curveRelativeOutlineElementGeometry.first) - val headPoint = curveRelativeOutlineElementGeometry.second - .map { point -> roadReferenceLine.transform(point) } + val headPoint = + curveRelativeOutlineElementGeometry.second + .map { point -> roadReferenceLine.transform(point) } return Polyhedron3DFactory.VerticalOutlineElement(basePoint, headPoint, tolerance = numberTolerance) } @@ -143,23 +178,34 @@ object Solid3DBuilder { * @param curveAffine affine transformation matrix from the curve * @return list of polyhedrons */ - fun buildPolyhedronsByLocalCorners(roadObject: RoadObjectsObject, curveAffine: Affine3D, numberTolerance: Double): - ContextIssueList> { + fun buildPolyhedronsByLocalCorners( + roadObject: RoadObjectsObject, + curveAffine: Affine3D, + numberTolerance: Double, + ): ContextIssueList> { val issueList = DefaultIssueList() val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose) val affineSequence = AffineSequence3D.of(curveAffine, objectAffine) - val (builderExceptions, polyhedronsWithContext) = roadObject - .getPolyhedronsDefinedByLocalCorners() - .map { buildPolyhedronByLocalCorners(it, numberTolerance) } - .separateEither() + val (builderExceptions, polyhedronsWithContext) = + roadObject + .getPolyhedronsDefinedByLocalCorners() + .map { buildPolyhedronByLocalCorners(it, numberTolerance) } + .separateEither() - issueList += builderExceptions - .map { DefaultIssue.of("PolyhedronNotConstructableFromLocalCornerOutlines", it.message, it.location, Severity.WARNING, wasFixed = true) } - .mergeToReport() - val polyhedrons = polyhedronsWithContext - .handleIssueList { issueList += it.issueList } - .map { it.copy(affineSequence = affineSequence) } + issueList += + builderExceptions + .map { + DefaultIssue.of( + "PolyhedronNotConstructableFromLocalCornerOutlines", it.message, it.location, + Severity.WARNING, wasFixed = true, + ) + } + .mergeToReport() + val polyhedrons = + polyhedronsWithContext + .handleIssueList { issueList += it.issueList } + .map { it.copy(affineSequence = affineSequence) } return ContextIssueList(polyhedrons, issueList) } @@ -167,22 +213,40 @@ object Solid3DBuilder { /** * Builds a single polyhedron from an OpenDRIVE road object defined by local corner outlines. */ - private fun buildPolyhedronByLocalCorners(outline: RoadObjectsObjectOutlinesOutline, numberTolerance: Double): - Either> = either { - require(outline.isPolyhedronDefinedByLocalCorners()) { "Outline does not contain a polyhedron represented by local corners." } - require(outline.cornerLocal.all { it.height == 0.0 || numberTolerance <= it.height }) { "All cornerLocal elements must have a height of either zero or above the tolerance threshold." } - val outlineId = outline.additionalId.toEither { IllegalStateException("Additional outline ID must be available.") }.getOrElse { throw it } + private fun buildPolyhedronByLocalCorners( + outline: RoadObjectsObjectOutlinesOutline, + numberTolerance: Double, + ): Either> = + either { + require(outline.isPolyhedronDefinedByLocalCorners()) { "Outline does not contain a polyhedron represented by local corners." } + require( + outline.cornerLocal.all { + it.height == 0.0 || numberTolerance <= it.height + }, + ) { "All cornerLocal elements must have a height of either zero or above the tolerance threshold." } + val outlineId = + outline.additionalId.toEither { + IllegalStateException( + "Additional outline ID must be available.", + ) + }.getOrElse { throw it } - val issueList = DefaultIssueList() + val issueList = DefaultIssueList() - val verticalOutlineElements = outline.cornerLocal - .map { Polyhedron3DFactory.VerticalOutlineElement.of(it.getBasePoint(), it.getHeadPoint(), None, numberTolerance) } - .handleIssueList { issueList += it.issueList } - .let { it.toNonEmptyListOrNull()!! } + val verticalOutlineElements = + outline.cornerLocal + .map { Polyhedron3DFactory.VerticalOutlineElement.of(it.getBasePoint(), it.getHeadPoint(), None, numberTolerance) } + .handleIssueList { issueList += it.issueList } + .let { it.toNonEmptyListOrNull()!! } - val polyhedronWithContextIssueList = Polyhedron3DFactory.buildFromVerticalOutlineElements(outlineId, verticalOutlineElements, numberTolerance).bind() - polyhedronWithContextIssueList - } + val polyhedronWithContextIssueList = + Polyhedron3DFactory.buildFromVerticalOutlineElements( + outlineId, + verticalOutlineElements, + numberTolerance, + ).bind() + polyhedronWithContextIssueList + } /** * Builds a parametric sweep from OpenDRIVE road objects defined by the repeat entries. @@ -190,7 +254,11 @@ object Solid3DBuilder { * @param roadObjectRepeat repeated road object of OpenDRIVE * @param roadReferenceLine road reference line for transforming curve relative coordinates */ - fun buildParametricSweep(roadObjectRepeat: RoadObjectsObjectRepeat, roadReferenceLine: Curve3D, numberTolerance: Double): Option { + fun buildParametricSweep( + roadObjectRepeat: RoadObjectsObjectRepeat, + roadReferenceLine: Curve3D, + numberTolerance: Double, + ): Option { if (!roadObjectRepeat.containsParametricSweep()) return None // curve over which the object is moved @@ -201,14 +269,15 @@ object Solid3DBuilder { val heightFunction = roadObjectRepeat.getObjectHeightFunction() val widthFunction = roadObjectRepeat.getObjectWidthFunction() - val parametricSweep3D = ParametricSweep3D( - objectReferenceCurve2D, - objectReferenceHeight, - heightFunction, - widthFunction, - numberTolerance, - ParametricSweep3D.DEFAULT_STEP_SIZE - ) + val parametricSweep3D = + ParametricSweep3D( + objectReferenceCurve2D, + objectReferenceHeight, + heightFunction, + widthFunction, + numberTolerance, + ParametricSweep3D.DEFAULT_STEP_SIZE, + ) return parametricSweep3D.some() } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Surface3DBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Surface3DBuilder.kt index 71b49580..b51f81c2 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Surface3DBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Surface3DBuilder.kt @@ -49,11 +49,14 @@ import io.rtron.transformer.issues.opendrive.of * Builder for surface geometries in 3D from the OpenDRIVE data model. */ object Surface3DBuilder { - // Methods /** Builds a rectangle from an [RoadObjectsObject] with [curveAffine] being the affine transformation at respective curve. */ - fun buildRectangle(roadObject: RoadObjectsObject, curveAffine: Affine3D, numberTolerance: Double): Rectangle3D { + fun buildRectangle( + roadObject: RoadObjectsObject, + curveAffine: Affine3D, + numberTolerance: Double, + ): Rectangle3D { require(roadObject.containsRectangle()) { "Road object must contain rectangle." } val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose) @@ -62,7 +65,11 @@ object Surface3DBuilder { } /** Builds a rectangle from an [RoadSignalsSignal] with [curveAffine] being the affine transformation at respective curve. */ - fun buildRectangle(roadObject: RoadSignalsSignal, curveAffine: Affine3D, numberTolerance: Double): Rectangle3D { + fun buildRectangle( + roadObject: RoadSignalsSignal, + curveAffine: Affine3D, + numberTolerance: Double, + ): Rectangle3D { require(roadObject.containsRectangle()) { "Road signal must contain rectangle." } val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose) @@ -76,7 +83,11 @@ object Surface3DBuilder { /** Builds a circle from an [RoadObjectsObject] with [curveAffine] being the affine transformation at respective curve. */ - fun buildCircle(roadObject: RoadObjectsObject, curveAffine: Affine3D, numberTolerance: Double): Circle3D { + fun buildCircle( + roadObject: RoadObjectsObject, + curveAffine: Affine3D, + numberTolerance: Double, + ): Circle3D { require(roadObject.containsCircle()) { "Road object must contain circle." } val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose) @@ -87,14 +98,25 @@ object Surface3DBuilder { /** * Builds a list of linear rings from an OpenDRIVE road object defined by road corner outlines. */ - fun buildLinearRingsByRoadCorners(roadObject: RoadObjectsObject, referenceLine: Curve3D, numberTolerance: Double): ContextIssueList> { + fun buildLinearRingsByRoadCorners( + roadObject: RoadObjectsObject, + referenceLine: Curve3D, + numberTolerance: Double, + ): ContextIssueList> { val issueList = DefaultIssueList() - val (builderExceptions, linearRingsWithContext) = roadObject.getLinearRingsDefinedByRoadCorners() - .map { buildLinearRingByRoadCorners(it, referenceLine, numberTolerance) } - .separateEither() - - issueList += builderExceptions.map { DefaultIssue.of("LinearRingNotConstructableFromRoadCornerOutlines", it.message, it.location, Severity.WARNING, wasFixed = true) }.mergeToReport() + val (builderExceptions, linearRingsWithContext) = + roadObject.getLinearRingsDefinedByRoadCorners() + .map { buildLinearRingByRoadCorners(it, referenceLine, numberTolerance) } + .separateEither() + + issueList += + builderExceptions.map { + DefaultIssue.of( + "LinearRingNotConstructableFromRoadCornerOutlines", it.message, it.location, + Severity.WARNING, wasFixed = true, + ) + }.mergeToReport() val linearRings = linearRingsWithContext.handleIssueList { issueList += it.issueList } return ContextIssueList(linearRings, issueList) @@ -103,15 +125,24 @@ object Surface3DBuilder { /** * Builds a single linear ring from an OpenDRIVE road object defined by road corner outlines. */ - private fun buildLinearRingByRoadCorners(outline: RoadObjectsObjectOutlinesOutline, referenceLine: Curve3D, numberTolerance: Double): - Either> { + private fun buildLinearRingByRoadCorners( + outline: RoadObjectsObjectOutlinesOutline, + referenceLine: Curve3D, + numberTolerance: Double, + ): Either> { require(outline.isLinearRingDefinedByRoadCorners()) { "Outline does not contain a linear ring represented by road corners." } require(outline.cornerRoad.all { it.height == 0.0 }) { "All cornerRoad elements must have a zero height." } - val outlineId = outline.additionalId.toEither { IllegalStateException("Additional outline ID must be available.") }.getOrElse { throw it } - - val vertices = outline.cornerRoad - .map { buildVertices(it, referenceLine) } - .let { it.toNonEmptyListOrNull()!! } + val outlineId = + outline.additionalId.toEither { + IllegalStateException( + "Additional outline ID must be available.", + ) + }.getOrElse { throw it } + + val vertices = + outline.cornerRoad + .map { buildVertices(it, referenceLine) } + .let { it.toNonEmptyListOrNull()!! } return LinearRing3DFactory.buildFromVertices(outlineId, vertices, numberTolerance) } @@ -119,7 +150,10 @@ object Surface3DBuilder { /** * Builds a vertex from the OpenDRIVE road corner element. */ - private fun buildVertices(cornerRoad: RoadObjectsObjectOutlinesOutlineCornerRoad, referenceLine: Curve3D): Vector3D { + private fun buildVertices( + cornerRoad: RoadObjectsObjectOutlinesOutlineCornerRoad, + referenceLine: Curve3D, + ): Vector3D { val affine = referenceLine.calculateAffine(cornerRoad.curveRelativePosition) val basePoint = cornerRoad.getBasePoint() @@ -129,22 +163,34 @@ object Surface3DBuilder { /** * Builds a list of linear rings from an OpenDRIVE road object defined by local corner outlines. */ - fun buildLinearRingsByLocalCorners(roadObject: RoadObjectsObject, curveAffine: Affine3D, numberTolerance: Double): ContextIssueList> { + fun buildLinearRingsByLocalCorners( + roadObject: RoadObjectsObject, + curveAffine: Affine3D, + numberTolerance: Double, + ): ContextIssueList> { val issueList = DefaultIssueList() val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose) val affineSequence = AffineSequence3D.of(curveAffine, objectAffine) - val (builderExceptions, linearRingsWithContext) = roadObject - .getLinearRingsDefinedByLocalCorners() - .map { buildLinearRingByLocalCorners(it, numberTolerance) } - .separateEither() - - issueList += builderExceptions - .map { DefaultIssue.of("LinearRingNotConstructableFromLocalCornerOutlines", it.message, it.location, Severity.WARNING, wasFixed = true) } - .mergeToReport() - val linearRings = linearRingsWithContext - .handleIssueList { issueList += it.issueList } - .map { it.copy(affineSequence = affineSequence) } + val (builderExceptions, linearRingsWithContext) = + roadObject + .getLinearRingsDefinedByLocalCorners() + .map { buildLinearRingByLocalCorners(it, numberTolerance) } + .separateEither() + + issueList += + builderExceptions + .map { + DefaultIssue.of( + "LinearRingNotConstructableFromLocalCornerOutlines", it.message, it.location, + Severity.WARNING, wasFixed = true, + ) + } + .mergeToReport() + val linearRings = + linearRingsWithContext + .handleIssueList { issueList += it.issueList } + .map { it.copy(affineSequence = affineSequence) } return ContextIssueList(linearRings, issueList) } @@ -152,12 +198,21 @@ object Surface3DBuilder { /** * Builds a single linear ring from an OpenDRIVE road object defined by local corner outlines. */ - private fun buildLinearRingByLocalCorners(outline: RoadObjectsObjectOutlinesOutline, numberTolerance: Double): Either> { - val outlineId = outline.additionalId.toEither { IllegalStateException("Additional outline ID must be available.") }.getOrElse { throw it } - - val vertices = outline.cornerLocal - .map { it.getBasePoint() } - .let { it.toNonEmptyListOrNull()!! } + private fun buildLinearRingByLocalCorners( + outline: RoadObjectsObjectOutlinesOutline, + numberTolerance: Double, + ): Either> { + val outlineId = + outline.additionalId.toEither { + IllegalStateException( + "Additional outline ID must be available.", + ) + }.getOrElse { throw it } + + val vertices = + outline.cornerLocal + .map { it.getBasePoint() } + .let { it.toNonEmptyListOrNull()!! } return LinearRing3DFactory.buildFromVertices(outlineId, vertices, numberTolerance) } @@ -168,7 +223,7 @@ object Surface3DBuilder { fun buildParametricBoundedSurfacesByHorizontalRepeat( roadObjectRepeat: RoadObjectsObjectRepeat, roadReferenceLine: Curve3D, - numberTolerance: Double + numberTolerance: Double, ): List { if (!roadObjectRepeat.containsHorizontalParametricBoundedSurface()) return emptyList() @@ -185,7 +240,8 @@ object Surface3DBuilder { val rightBoundaryCurve2D = objectReferenceCurve2D.addLateralTranslation(widthFunction, +0.5) val rightBoundary = Curve3D(rightBoundaryCurve2D, objectReferenceHeight) - val parametricBoundedSurface = ParametricBoundedSurface3D(leftBoundary, rightBoundary, numberTolerance, ParametricBoundedSurface3D.DEFAULT_STEP_SIZE) + val parametricBoundedSurface = + ParametricBoundedSurface3D(leftBoundary, rightBoundary, numberTolerance, ParametricBoundedSurface3D.DEFAULT_STEP_SIZE) return listOf(parametricBoundedSurface) } @@ -195,7 +251,7 @@ object Surface3DBuilder { fun buildParametricBoundedSurfacesByVerticalRepeat( roadObjectRepeat: RoadObjectsObjectRepeat, roadReferenceLine: Curve3D, - numberTolerance: Double + numberTolerance: Double, ): List { if (!roadObjectRepeat.containsVerticalParametricBoundedSurface()) return emptyList() @@ -211,7 +267,8 @@ object Surface3DBuilder { val upperBoundaryHeight = StackedFunction.ofSum(objectReferenceHeight, heightFunction, defaultValue = 0.0) val upperBoundary = Curve3D(objectReferenceCurve2D, upperBoundaryHeight) - val parametricBoundedSurface = ParametricBoundedSurface3D(lowerBoundary, upperBoundary, numberTolerance, ParametricBoundedSurface3D.DEFAULT_STEP_SIZE) + val parametricBoundedSurface = + ParametricBoundedSurface3D(lowerBoundary, upperBoundary, numberTolerance, ParametricBoundedSurface3D.DEFAULT_STEP_SIZE) return listOf(parametricBoundedSurface) } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Vector3DBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Vector3DBuilder.kt index 4c23665b..915da4bd 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Vector3DBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/geometry/Vector3DBuilder.kt @@ -26,7 +26,6 @@ import io.rtron.model.opendrive.signal.RoadSignalsSignal * Builder for vectors in 3D from the OpenDRIVE data model. */ object Vector3DBuilder { - // Methods /** @@ -36,7 +35,10 @@ object Vector3DBuilder { * @param roadObject road object of OpenDRIVE * @param curveAffine affine transformation matrix at the reference curve */ - fun buildVector3Ds(roadObject: RoadObjectsObject, curveAffine: Affine3D): Vector3D { + fun buildVector3Ds( + roadObject: RoadObjectsObject, + curveAffine: Affine3D, + ): Vector3D { val objectAffine = Affine3D.of(roadObject.referenceLinePointRelativePose) return Vector3D.ZERO.copy(affineSequence = AffineSequence3D.of(curveAffine, objectAffine)) } @@ -49,7 +51,10 @@ 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): Vector3D { + fun buildVector3Ds( + roadSignal: RoadSignalsSignal, + curveAffine: Affine3D, + ): Vector3D { val objectAffine = Affine3D.of(roadSignal.referenceLinePointRelativePose) return Vector3D.ZERO.copy(affineSequence = AffineSequence3D.of(curveAffine, objectAffine)) } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/header/HeaderBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/header/HeaderBuilder.kt index 206a038b..bc88ae86 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/header/HeaderBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/header/HeaderBuilder.kt @@ -31,7 +31,7 @@ import io.rtron.transformer.converter.opendrive2roadspaces.Opendrive2RoadspacesP import io.rtron.model.opendrive.core.Header as OdrHeader class HeaderBuilder( - private val parameters: Opendrive2RoadspacesParameters + private val parameters: Opendrive2RoadspacesParameters, ) { // Methods fun buildHeader(header: OdrHeader): ContextIssueList
{ @@ -52,7 +52,13 @@ class HeaderBuilder( CoordinateReferenceSystem.of(parameters.crsEpsg).onRight { return ContextIssueList(it.some(), issueList) } if (parameters.deriveCrsEpsgAutomatically) { CoordinateReferenceSystem.of(geoReference.content).onRight { return ContextIssueList(it.some(), issueList) } - issueList += DefaultIssue("AutomaticCrsEpsgCodeDerivationFailed", "EPSG code of the coordinate reference system cannot be derived automatically from the OpenDRIVE header element; add the code explicitly as a command line argument if correct georeferencing is required.", "Header element", Severity.WARNING, wasFixed = false) + issueList += + DefaultIssue( + "AutomaticCrsEpsgCodeDerivationFailed", + "EPSG code of the coordinate reference system cannot be derived automatically from the OpenDRIVE header element; " + + "add the code explicitly as a command line argument if correct georeferencing is required.", + "Header element", Severity.WARNING, wasFixed = false, + ) } return ContextIssueList(None, issueList) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/junction/JunctionBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/junction/JunctionBuilder.kt index 9a8166fc..7f88c3a5 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/junction/JunctionBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/junction/JunctionBuilder.kt @@ -33,26 +33,36 @@ import io.rtron.transformer.converter.opendrive2roadspaces.roadspaces.toContactP import io.rtron.model.opendrive.junction.Junction as OpendriveJunction class JunctionBuilder( - private val parameters: Opendrive2RoadspacesParameters + private val parameters: Opendrive2RoadspacesParameters, ) { // Methods - fun buildDefaultJunction(junction: OpendriveJunction, roadspaces: List): Junction { + fun buildDefaultJunction( + junction: OpendriveJunction, + roadspaces: List, + ): Junction { val junctionId = JunctionIdentifier(junction.id) val connections = junction.connection.map { buildConnection(junctionId, it, roadspaces) } return Junction(junctionId, connections) } - private fun buildConnection(id: JunctionIdentifier, connection: JunctionConnection, roadspaces: List): Connection { + private fun buildConnection( + id: JunctionIdentifier, + connection: JunctionConnection, + roadspaces: List, + ): Connection { val connectionId = ConnectionIdentifier(connection.id, id) val incomingRoadspaceId = RoadspaceIdentifier.of(connection.incomingRoad) val connectingRoadspaceId = RoadspaceIdentifier.of(connection.connectingRoad) check(roadspaces.count { it.id == incomingRoadspaceId } == 1) { "Incoming roadspace with $incomingRoadspaceId does not exist." } val incomingRoadspace = roadspaces.find { it.id == incomingRoadspaceId }!! - val incomingRoadspaceContactPointId = incomingRoadspace.road.getRoadspaceContactPointToJunction(id) - .handleEmpty { throw Exception("Incoming roadspace with $incomingRoadspaceId must be connected to junction ($id).") } + val incomingRoadspaceContactPointId = + incomingRoadspace.road.getRoadspaceContactPointToJunction(id) + .handleEmpty { throw Exception("Incoming roadspace with $incomingRoadspaceId must be connected to junction ($id).") } - check(roadspaces.count { it.id == connectingRoadspaceId } == 1) { "Connecting roadspace with $connectingRoadspaceId does not exist." } + check( + roadspaces.count { it.id == connectingRoadspaceId } == 1, + ) { "Connecting roadspace with $connectingRoadspaceId does not exist." } val connectingRoadspace = roadspaces.find { it.id == connectingRoadspaceId }!! val connectingRoadspaceContactPoint = connection.contactPoint.getOrElse { EContactPoint.START }.toContactPoint() val connectingRoadspaceContactPointId = @@ -62,9 +72,10 @@ class JunctionBuilder( val connectingLaneSectionId = connectingRoadspace.road.getLaneSectionIdentifier(connectingRoadspaceContactPointId) - val laneLinks = connection.laneLink.associate { - LaneIdentifier(it.from, incomingLaneSectionId) to LaneIdentifier(it.to, connectingLaneSectionId) - } + val laneLinks = + connection.laneLink.associate { + LaneIdentifier(it.from, incomingLaneSectionId) to LaneIdentifier(it.to, connectingLaneSectionId) + } return Connection(connectionId, incomingRoadspaceContactPointId, connectingRoadspaceContactPointId, laneLinks) } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/report/Opendrive2RoadspacesReport.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/report/Opendrive2RoadspacesReport.kt index 2d483ee3..707698a9 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/report/Opendrive2RoadspacesReport.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/report/Opendrive2RoadspacesReport.kt @@ -24,10 +24,8 @@ import kotlinx.serialization.Serializable @Serializable data class Opendrive2RoadspacesReport( val parameters: Opendrive2RoadspacesParameters, - - val conversion: DefaultIssueList = DefaultIssueList() + val conversion: DefaultIssueList = DefaultIssueList(), ) { - // Methods fun getTextSummary(): String = conversion.getTextSummary() } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/Attributes.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/Attributes.kt index fb0d4b74..d06d0e03 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/Attributes.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/Attributes.kt @@ -24,42 +24,44 @@ import io.rtron.model.roadspaces.roadspace.road.LaneType /** * Transforms units of the OpenDRIVE data model to units of the RoadSpaces data model. */ -fun EUnitSpeed.toUnitOfMeasure(): UnitOfMeasure = when (this) { - EUnitSpeed.METER_PER_SECOND -> UnitOfMeasure.METER_PER_SECOND - EUnitSpeed.MILES_PER_HOUR -> UnitOfMeasure.MILES_PER_HOUR - EUnitSpeed.KILOMETER_PER_HOUR -> UnitOfMeasure.KILOMETER_PER_HOUR -} +fun EUnitSpeed.toUnitOfMeasure(): UnitOfMeasure = + when (this) { + EUnitSpeed.METER_PER_SECOND -> UnitOfMeasure.METER_PER_SECOND + EUnitSpeed.MILES_PER_HOUR -> UnitOfMeasure.MILES_PER_HOUR + EUnitSpeed.KILOMETER_PER_HOUR -> UnitOfMeasure.KILOMETER_PER_HOUR + } /** * Transforms lane types of the OpenDRIVE data model to the lane types of the RoadSpaces data model. */ -fun ELaneType.toLaneType(): LaneType = when (this) { - ELaneType.SHOULDER -> LaneType.SHOULDER - ELaneType.BORDER -> LaneType.BORDER - ELaneType.DRIVING -> LaneType.DRIVING - ELaneType.STOP -> LaneType.STOP - ELaneType.NONE -> LaneType.NONE - ELaneType.RESTRICTED -> LaneType.RESTRICTED - ELaneType.PARKING -> LaneType.PARKING - ELaneType.MEDIAN -> LaneType.MEDIAN - ELaneType.BIKING -> LaneType.BIKING - ELaneType.SIDEWALK -> LaneType.SIDEWALK - ELaneType.CURB -> LaneType.CURB - ELaneType.BIDIRECTIONAL -> LaneType.BIDIRECTIONAL - ELaneType.SPECIAL_1 -> LaneType.SPECIAL_1 - ELaneType.SPECIAL_2 -> LaneType.SPECIAL_2 - ELaneType.SPECIAL_3 -> LaneType.SPECIAL_3 - ELaneType.ROAD_WORKS -> LaneType.ROAD_WORKS - ELaneType.TRAM -> LaneType.TRAM - ELaneType.RAIL -> LaneType.RAIL - ELaneType.ENTRY -> LaneType.ENTRY - ELaneType.EXIT -> LaneType.EXIT - ELaneType.OFF_RAMP -> LaneType.OFF_RAMP - ELaneType.ON_RAMP -> LaneType.ON_RAMP - ELaneType.CONNECTING_RAMP -> LaneType.CONNECTING_RAMP - ELaneType.BUS -> LaneType.BUS - ELaneType.TAXI -> LaneType.TAXI - ELaneType.HOV -> LaneType.HOV - ELaneType.MWY_ENTRY -> LaneType.MWY_ENTRY - ELaneType.MWY_EXIT -> LaneType.MWY_EXIT -} +fun ELaneType.toLaneType(): LaneType = + when (this) { + ELaneType.SHOULDER -> LaneType.SHOULDER + ELaneType.BORDER -> LaneType.BORDER + ELaneType.DRIVING -> LaneType.DRIVING + ELaneType.STOP -> LaneType.STOP + ELaneType.NONE -> LaneType.NONE + ELaneType.RESTRICTED -> LaneType.RESTRICTED + ELaneType.PARKING -> LaneType.PARKING + ELaneType.MEDIAN -> LaneType.MEDIAN + ELaneType.BIKING -> LaneType.BIKING + ELaneType.SIDEWALK -> LaneType.SIDEWALK + ELaneType.CURB -> LaneType.CURB + ELaneType.BIDIRECTIONAL -> LaneType.BIDIRECTIONAL + ELaneType.SPECIAL_1 -> LaneType.SPECIAL_1 + ELaneType.SPECIAL_2 -> LaneType.SPECIAL_2 + ELaneType.SPECIAL_3 -> LaneType.SPECIAL_3 + ELaneType.ROAD_WORKS -> LaneType.ROAD_WORKS + ELaneType.TRAM -> LaneType.TRAM + ELaneType.RAIL -> LaneType.RAIL + ELaneType.ENTRY -> LaneType.ENTRY + ELaneType.EXIT -> LaneType.EXIT + ELaneType.OFF_RAMP -> LaneType.OFF_RAMP + ELaneType.ON_RAMP -> LaneType.ON_RAMP + ELaneType.CONNECTING_RAMP -> LaneType.CONNECTING_RAMP + ELaneType.BUS -> LaneType.BUS + ELaneType.TAXI -> LaneType.TAXI + ELaneType.HOV -> LaneType.HOV + ELaneType.MWY_ENTRY -> LaneType.MWY_ENTRY + ELaneType.MWY_EXIT -> LaneType.MWY_EXIT + } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/LaneBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/LaneBuilder.kt index 924319ce..bb83e9fd 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/LaneBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/LaneBuilder.kt @@ -58,7 +58,7 @@ import io.rtron.transformer.issues.opendrive.of * Builder for [Lane] objects of the RoadSpaces data model. */ class LaneBuilder( - private val parameters: Opendrive2RoadspacesParameters + private val parameters: Opendrive2RoadspacesParameters, ) { // Methods @@ -70,14 +70,21 @@ class LaneBuilder( * @param lrLane lane object of the OpenDRIVE data model * @param baseAttributes attributes attached to the transformed [Lane] object */ - fun buildLane(id: LaneIdentifier, curvePositionDomain: Range, lrLane: RoadLanesLaneSectionLRLane, baseAttributes: AttributeList): ContextIssueList { + fun buildLane( + id: LaneIdentifier, + curvePositionDomain: Range, + lrLane: RoadLanesLaneSectionLRLane, + baseAttributes: AttributeList, + ): ContextIssueList { val issueList = DefaultIssueList() // build lane geometry - val width = lrLane.getLaneWidthEntries() - .fold({ LinearFunction.X_AXIS }, { FunctionBuilder.buildLaneWidth(it, parameters.numberTolerance) }) - val laneHeightOffsets = lrLane.getLaneHeightEntries() - .fold({ LaneHeightOffset(LinearFunction.X_AXIS, LinearFunction.X_AXIS) }, { buildLaneHeightOffset(it) }) + val width = + lrLane.getLaneWidthEntries() + .fold({ LinearFunction.X_AXIS }, { FunctionBuilder.buildLaneWidth(it, parameters.numberTolerance) }) + val laneHeightOffsets = + lrLane.getLaneHeightEntries() + .fold({ LaneHeightOffset(LinearFunction.X_AXIS, LinearFunction.X_AXIS) }, { buildLaneHeightOffset(it) }) // build road markings val roadMarkings: List = @@ -97,10 +104,11 @@ class LaneBuilder( val attributes = baseAttributes + buildAttributes(lrLane) // build up lane object - val lane = Lane( - id, width, laneHeightOffsets.inner, laneHeightOffsets.outer, lrLane.getLevelWithDefault(), roadMarkings, - predecessors, successors, type, laneMaterial, attributes - ) + val lane = + Lane( + id, width, laneHeightOffsets.inner, laneHeightOffsets.outer, lrLane.getLevelWithDefault(), roadMarkings, + predecessors, successors, type, laneMaterial, attributes, + ) return ContextIssueList(lane, issueList) } @@ -116,7 +124,7 @@ class LaneBuilder( id: LaneSectionIdentifier, curvePositionDomain: Range, centerLane: RoadLanesLaneSectionCenterLane, - baseAttributes: AttributeList + baseAttributes: AttributeList, ): ContextIssueList { require(centerLane.id == 0) { "Center lane must have id 0, but has ${centerLane.id}." } @@ -153,17 +161,19 @@ class LaneBuilder( require(laneHeights.isStrictlySortedBy { it.sOffset }) { "Height entries must be sorted in strict order according to sOffset." } require(laneHeights.all { it.inner.isFinite() && it.outer.isFinite() }) { "Inner and outer values must be finite." } - val inner = ConcatenatedFunction.ofLinearFunctions( - laneHeights.map { it.sOffset }, - laneHeights.map { it.inner }, - prependConstant = true - ) + val inner = + ConcatenatedFunction.ofLinearFunctions( + laneHeights.map { it.sOffset }, + laneHeights.map { it.inner }, + prependConstant = true, + ) - val outer = ConcatenatedFunction.ofLinearFunctions( - laneHeights.map { it.sOffset }, - laneHeights.map { it.outer }, - prependConstant = true - ) + val outer = + ConcatenatedFunction.ofLinearFunctions( + laneHeights.map { it.sOffset }, + laneHeights.map { it.outer }, + prependConstant = true, + ) return LaneHeightOffset(inner, outer) } @@ -176,32 +186,36 @@ class LaneBuilder( */ private fun buildRoadMarkings( curvePositionDomain: Range, - roadMark: NonEmptyList + roadMark: NonEmptyList, ): ContextIssueList> { require(curvePositionDomain.hasUpperBound()) { "curvePositionDomain must have an upper bound." } - val roadMarkId = roadMark.head.additionalId.toEither { IllegalStateException("Additional outline ID must be available.") }.getOrElse { throw it } + val roadMarkId = + roadMark.head.additionalId.toEither { + IllegalStateException("Additional outline ID must be available.") + }.getOrElse { throw it } val issueList = DefaultIssueList() val curvePositionDomainEnd = curvePositionDomain.upperEndpointOrNull()!! - val adjustedSrcRoadMark = roadMark - .filter { it.sOffset in curvePositionDomain } - .filter { !fuzzyEquals(it.sOffset, curvePositionDomainEnd, parameters.numberTolerance) } + val adjustedSrcRoadMark = + roadMark + .filter { it.sOffset in curvePositionDomain } + .filter { !fuzzyEquals(it.sOffset, curvePositionDomainEnd, parameters.numberTolerance) } if (adjustedSrcRoadMark.size < roadMark.size) { - issueList += DefaultIssue.of( - "RoadMarkEntriesNotLocatedWithinSRange", - "Road mark entries have been removed, as the sOffset is not located within " + - "the local curve position domain ($curvePositionDomain) of the lane section.", - roadMarkId, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "RoadMarkEntriesNotLocatedWithinSRange", + "Road mark entries have been removed, as the sOffset is not located within " + + "the local curve position domain ($curvePositionDomain) of the lane section.", + roadMarkId, Severity.WARNING, wasFixed = true, + ) } if (adjustedSrcRoadMark.isEmpty()) return ContextIssueList(emptyList(), issueList) - val roadMarkings = adjustedSrcRoadMark.zipWithNext() - .map { buildRoadMarking(it.first, it.second.sOffset.some()) } + - listOf(buildRoadMarking(adjustedSrcRoadMark.last())) + val roadMarkings = + adjustedSrcRoadMark.zipWithNext() + .map { buildRoadMarking(it.first, it.second.sOffset.some()) } + + listOf(buildRoadMarking(adjustedSrcRoadMark.last())) return ContextIssueList(roadMarkings, issueList) } @@ -212,28 +226,33 @@ class LaneBuilder( * @param roadMark road mark entry of the OpenDRIVE data model * @param domainEndpoint upper domain endpoint for the domain of the road mark */ - private fun buildRoadMarking(roadMark: RoadLanesLaneSectionLCRLaneRoadMark, domainEndpoint: Option = None): RoadMarking { + private fun buildRoadMarking( + roadMark: RoadLanesLaneSectionLCRLaneRoadMark, + domainEndpoint: Option = None, + ): RoadMarking { val domain = domainEndpoint.fold({ Range.atLeast(roadMark.sOffset) }, { Range.closed(roadMark.sOffset, it) }) require(domain.length > parameters.numberTolerance) { "Length of road marking must be above zero and the tolerance threshold." } val width = roadMark.width.fold({ ConstantFunction.ZERO }, { ConstantFunction(it, domain) }) - val attributes = attributes("${parameters.attributesPrefix}roadMarking") { - attribute("_curvePositionStart", roadMark.sOffset) - attribute("_width", roadMark.width) - attribute("_type", roadMark.typeAttribute.toString()) - attribute("_weight", roadMark.weight.map { it.toString() }) - attribute("_laneChange", roadMark.laneChange.map { it.toString() }) - attribute("_color", roadMark.color.toString()) - attribute("_material", roadMark.material) - } + val attributes = + attributes("${parameters.attributesPrefix}roadMarking") { + attribute("_curvePositionStart", roadMark.sOffset) + attribute("_width", roadMark.width) + attribute("_type", roadMark.typeAttribute.toString()) + attribute("_weight", roadMark.weight.map { it.toString() }) + attribute("_laneChange", roadMark.laneChange.map { it.toString() }) + attribute("_color", roadMark.color.toString()) + attribute("_material", roadMark.material) + } - val laneChange = when (roadMark.laneChange.getOrElse { ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.BOTH }) { - ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.INCREASE -> LaneChange.INCREASE - ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.DECREASE -> LaneChange.DECREASE - ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.BOTH -> LaneChange.BOTH - ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.NONE -> LaneChange.NONE - } + val laneChange = + when (roadMark.laneChange.getOrElse { ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.BOTH }) { + ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.INCREASE -> LaneChange.INCREASE + ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.DECREASE -> LaneChange.DECREASE + ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.BOTH -> LaneChange.BOTH + ERoadLanesLaneSectionLCRLaneRoadMarkLaneChange.NONE -> LaneChange.NONE + } return RoadMarking(width, laneChange, attributes) } @@ -250,10 +269,10 @@ class LaneBuilder( // return none, if different entries if (laneMaterials.any { - !fuzzyEquals(it.friction, firstEntry.friction, parameters.numberTolerance) || - !fuzzyEquals(it.roughness, firstEntry.roughness, parameters.numberTolerance) || - it.surface != firstEntry.surface - } + !fuzzyEquals(it.friction, firstEntry.friction, parameters.numberTolerance) || + !fuzzyEquals(it.roughness, firstEntry.roughness, parameters.numberTolerance) || + it.surface != firstEntry.surface + } ) { return None } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadBuilder.kt index c44179e6..784034a5 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadBuilder.kt @@ -45,9 +45,8 @@ import io.rtron.model.opendrive.road.Road as OpendriveRoad * Builder for [Road] objects of the RoadSpaces data model. */ class RoadBuilder( - val parameters: Opendrive2RoadspacesParameters + val parameters: Opendrive2RoadspacesParameters, ) { - // Properties and Initializers private val laneBuilder = LaneBuilder(parameters) @@ -67,22 +66,27 @@ class RoadBuilder( road: OpendriveRoad, roadSurface: CurveRelativeParametricSurface3D, roadSurfaceWithoutTorsion: CurveRelativeParametricSurface3D, - baseAttributes: AttributeList + baseAttributes: AttributeList, ): ContextIssueList { - require(road.lanes.getLaneSectionLengths(road.length).all { it >= parameters.numberTolerance }) { "All lane sections must have a length above the tolerance threshold." } + require( + road.lanes.getLaneSectionLengths(road.length).all { + it >= parameters.numberTolerance + }, + ) { "All lane sections must have a length above the tolerance threshold." } val issueList = DefaultIssueList() val laneOffset = road.lanes.getLaneOffsetEntries().fold({ LinearFunction.X_AXIS }, { FunctionBuilder.buildLaneOffset(it) }) - val laneSections: NonEmptyList = road.lanes.getLaneSectionsWithRanges(road.length) - .mapIndexed { currentId, currentLaneSection -> - buildLaneSection( - LaneSectionIdentifier(currentId, id), - currentLaneSection.first, - currentLaneSection.second, - baseAttributes - ).handleIssueList { issueList += it } - } - .let { it.toNonEmptyListOrNull()!! } + val laneSections: NonEmptyList = + road.lanes.getLaneSectionsWithRanges(road.length) + .mapIndexed { currentId, currentLaneSection -> + buildLaneSection( + LaneSectionIdentifier(currentId, id), + currentLaneSection.first, + currentLaneSection.second, + baseAttributes, + ).handleIssueList { issueList += it } + } + .let { it.toNonEmptyListOrNull()!! } val roadLinkage = buildRoadLinkage(id, road) @@ -97,63 +101,75 @@ class RoadBuilder( laneSectionIdentifier: LaneSectionIdentifier, curvePositionDomain: Range, laneSection: RoadLanesLaneSection, - baseAttributes: AttributeList + baseAttributes: AttributeList, ): ContextIssueList { require(laneSection.center.lane.size == 1) { "Lane section ($laneSectionIdentifier) must contain exactly one center lane." } - require(laneSection.getNumberOfLeftLanes() + laneSection.getNumberOfRightLanes() >= 1) { "Lane section ($laneSectionIdentifier) must contain at least one left or right lane." } + require(laneSection.getNumberOfLeftLanes() + laneSection.getNumberOfRightLanes() >= 1) { + "Lane section ($laneSectionIdentifier) must contain at least one left or right lane." + } val issueList = DefaultIssueList() val localCurvePositionDomain = curvePositionDomain.shiftLowerEndpointTo(0.0) val laneSectionAttributes = buildAttributes(laneSection) - val lanes = laneSection.getLeftRightLanes() - .map { (currentLaneId, currentSrcLane) -> - val laneIdentifier = LaneIdentifier(currentLaneId, laneSectionIdentifier) - val attributes = baseAttributes + laneSectionAttributes - laneBuilder.buildLane(laneIdentifier, localCurvePositionDomain, currentSrcLane, attributes) - .handleIssueList { issueList += it } - } - - val centerLane = laneBuilder.buildCenterLane( - laneSectionIdentifier, - localCurvePositionDomain, - laneSection.center.getIndividualCenterLane(), - baseAttributes - ).handleIssueList { issueList += it } + val lanes = + laneSection.getLeftRightLanes() + .map { (currentLaneId, currentSrcLane) -> + val laneIdentifier = LaneIdentifier(currentLaneId, laneSectionIdentifier) + val attributes = baseAttributes + laneSectionAttributes + laneBuilder.buildLane(laneIdentifier, localCurvePositionDomain, currentSrcLane, attributes) + .handleIssueList { issueList += it } + } + + val centerLane = + laneBuilder.buildCenterLane( + laneSectionIdentifier, + localCurvePositionDomain, + laneSection.center.getIndividualCenterLane(), + baseAttributes, + ).handleIssueList { issueList += it } val roadspaceLaneSection = LaneSection(laneSectionIdentifier, curvePositionDomain, lanes, centerLane) return ContextIssueList(roadspaceLaneSection, issueList) } - private fun buildRoadLinkage(id: RoadspaceIdentifier, road: OpendriveRoad): RoadLinkage { - val belongsToJunctionId = road.getJunctionOption() - .map { JunctionIdentifier(it) } - - val predecessorRoadspaceContactPointId = road.link - .flatMap { it.predecessor } - .flatMap { it.getRoadPredecessorSuccessor() } - .map { RoadspaceContactPointIdentifier(it.second.toContactPoint(), RoadspaceIdentifier(it.first)) } - val predecessorJunctionId = road.link - .flatMap { it.predecessor } - .flatMap { it.getJunctionPredecessorSuccessor() } - .map { JunctionIdentifier(it) } - - val successorRoadspaceContactPointId = road.link - .flatMap { it.successor } - .flatMap { it.getRoadPredecessorSuccessor() } - .map { RoadspaceContactPointIdentifier(it.second.toContactPoint(), RoadspaceIdentifier(it.first)) } - val successorJunctionId = road.link - .flatMap { it.successor } - .flatMap { it.getJunctionPredecessorSuccessor() } - .map { JunctionIdentifier(it) } + private fun buildRoadLinkage( + id: RoadspaceIdentifier, + road: OpendriveRoad, + ): RoadLinkage { + val belongsToJunctionId = + road.getJunctionOption() + .map { JunctionIdentifier(it) } + + val predecessorRoadspaceContactPointId = + road.link + .flatMap { it.predecessor } + .flatMap { it.getRoadPredecessorSuccessor() } + .map { RoadspaceContactPointIdentifier(it.second.toContactPoint(), RoadspaceIdentifier(it.first)) } + val predecessorJunctionId = + road.link + .flatMap { it.predecessor } + .flatMap { it.getJunctionPredecessorSuccessor() } + .map { JunctionIdentifier(it) } + + val successorRoadspaceContactPointId = + road.link + .flatMap { it.successor } + .flatMap { it.getRoadPredecessorSuccessor() } + .map { RoadspaceContactPointIdentifier(it.second.toContactPoint(), RoadspaceIdentifier(it.first)) } + val successorJunctionId = + road.link + .flatMap { it.successor } + .flatMap { it.getJunctionPredecessorSuccessor() } + .map { JunctionIdentifier(it) } return RoadLinkage( belongsToJunctionId, predecessorRoadspaceContactPointId, predecessorJunctionId, successorRoadspaceContactPointId, - successorJunctionId + successorJunctionId, ) } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadspaceBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadspaceBuilder.kt index 7728f5f2..3b3deb45 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadspaceBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadspaceBuilder.kt @@ -40,7 +40,7 @@ import io.rtron.model.opendrive.road.Road as OpendriveRoad * Builder of [Roadspace] (RoadSpaces data model) to the Road class of the OpenDRIVE data model. */ class RoadspaceBuilder( - private val parameters: Opendrive2RoadspacesParameters + private val parameters: Opendrive2RoadspacesParameters, ) { // Properties and Initializers private val roadBuilder = RoadBuilder(parameters) @@ -60,70 +60,81 @@ class RoadspaceBuilder( val roadspaceId = RoadspaceIdentifier(road.id) // build up road reference line - val roadReferenceLine = Curve3DBuilder.buildCurve3D( - road.planView.geometryAsNonEmptyList, - road.getElevationEntries(), - parameters.numberTolerance, - parameters.planViewGeometryDistanceTolerance, - parameters.planViewGeometryAngleTolerance - ) - val torsionFunction = road.getSuperelevationEntries().fold( - { LinearFunction.X_AXIS }, - { FunctionBuilder.buildCurveTorsion(it) } - ) + val roadReferenceLine = + Curve3DBuilder.buildCurve3D( + road.planView.geometryAsNonEmptyList, + road.getElevationEntries(), + parameters.numberTolerance, + parameters.planViewGeometryDistanceTolerance, + parameters.planViewGeometryAngleTolerance, + ) + val torsionFunction = + road.getSuperelevationEntries().fold( + { LinearFunction.X_AXIS }, + { FunctionBuilder.buildCurveTorsion(it) }, + ) // build attributes for the road val attributes = buildAttributes(road) // build up road's surface geometries - val lateralProfileRoadShape = road.getShapeEntries() - .fold({ PlaneFunction.ZERO }, { buildLateralRoadShape(roadspaceId, it) }) - - val roadSurface = CurveRelativeParametricSurface3D( - roadReferenceLine.copy(torsionFunction = torsionFunction), - lateralProfileRoadShape - ) + val lateralProfileRoadShape = + road.getShapeEntries() + .fold({ PlaneFunction.ZERO }, { buildLateralRoadShape(roadspaceId, it) }) + + val roadSurface = + CurveRelativeParametricSurface3D( + roadReferenceLine.copy(torsionFunction = torsionFunction), + lateralProfileRoadShape, + ) val roadSurfaceWithoutTorsion = CurveRelativeParametricSurface3D(roadReferenceLine, lateralProfileRoadShape) // build up the road containing only lane sections, lanes (no roadside objects) - val roadspaceRoad = roadBuilder - .buildRoad(roadspaceId, road, roadSurface, roadSurfaceWithoutTorsion, attributes) - .handleIssueList { issueList += it } + val roadspaceRoad = + roadBuilder + .buildRoad(roadspaceId, road, roadSurface, roadSurfaceWithoutTorsion, attributes) + .handleIssueList { issueList += it } // build up the road space objects (OpenDRIVE: road objects & signals) - val roadspaceObjectsFromRoadObjects = road.objects.fold({ emptyList() }, { roadObjects -> - roadObjectBuilder.buildRoadspaceObjects(roadspaceId, roadObjects, roadReferenceLine, roadspaceRoad, attributes) - .handleIssueList { issueList += it } - }) - val roadspaceObjectsFromRoadSignals: List = road.signals.fold({ emptyList() }, { roadSignals -> - roadObjectBuilder.buildRoadspaceObjects(roadspaceId, roadSignals, roadReferenceLine, roadspaceRoad, attributes) - .handleIssueList { issueList += it } - }) + val roadspaceObjectsFromRoadObjects = + road.objects.fold({ emptyList() }, { roadObjects -> + roadObjectBuilder.buildRoadspaceObjects(roadspaceId, roadObjects, roadReferenceLine, roadspaceRoad, attributes) + .handleIssueList { issueList += it } + }) + val roadspaceObjectsFromRoadSignals: List = + road.signals.fold({ emptyList() }, { roadSignals -> + roadObjectBuilder.buildRoadspaceObjects(roadspaceId, roadSignals, roadReferenceLine, roadspaceRoad, attributes) + .handleIssueList { issueList += it } + }) // combine the models into a road space object - val roadspace = Roadspace( - id = roadspaceId, - name = road.name.getOrElse { "" }, - referenceLine = roadReferenceLine, - road = roadspaceRoad, - roadspaceObjects = roadspaceObjectsFromRoadObjects + roadspaceObjectsFromRoadSignals, - attributes = attributes - ) + val roadspace = + Roadspace( + id = roadspaceId, + name = road.name.getOrElse { "" }, + referenceLine = roadReferenceLine, + road = roadspaceRoad, + roadspaceObjects = roadspaceObjectsFromRoadObjects + roadspaceObjectsFromRoadSignals, + attributes = attributes, + ) return ContextIssueList(roadspace, issueList) } - private fun buildLateralRoadShape(id: RoadspaceIdentifier, lateralProfileShapeList: NonEmptyList): - BivariateFunction { - val lateralFunctions = lateralProfileShapeList - .groupBy { it.s } - .mapValues { it.value.toNonEmptyListOrNull()!! } - .mapValues { FunctionBuilder.buildLateralShape(it.value) } - .toSortedMap() + private fun buildLateralRoadShape( + id: RoadspaceIdentifier, + lateralProfileShapeList: NonEmptyList, + ): BivariateFunction { + val lateralFunctions = + lateralProfileShapeList + .groupBy { it.s } + .mapValues { it.value.toNonEmptyListOrNull()!! } + .mapValues { FunctionBuilder.buildLateralShape(it.value) } + .toSortedMap() return ShapeFunction( lateralFunctions, extrapolateX = true, - extrapolateY = parameters.extrapolateLateralRoadShapes + extrapolateY = parameters.extrapolateLateralRoadShapes, ) } @@ -138,7 +149,7 @@ class RoadspaceBuilder( attribute("predecessor_road", predecessor.getRoadPredecessorSuccessor().map { it.first }) attribute( "predecessor_contactPoint", - predecessor.getRoadPredecessorSuccessor().map { it.second.toString() } + predecessor.getRoadPredecessorSuccessor().map { it.second.toString() }, ) attribute("predecessor_junction", predecessor.getJunctionPredecessorSuccessor()) } @@ -147,7 +158,7 @@ class RoadspaceBuilder( attribute("successor_road", successor.getRoadPredecessorSuccessor().map { it.first }) attribute( "successor_contactPoint", - successor.getRoadPredecessorSuccessor().map { it.second.toString() } + successor.getRoadPredecessorSuccessor().map { it.second.toString() }, ) attribute("successor_junction", successor.getJunctionPredecessorSuccessor()) } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadspaceObjectBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadspaceObjectBuilder.kt index b24b7c6f..801acfac 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadspaceObjectBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/opendrive2roadspaces/roadspaces/RoadspaceObjectBuilder.kt @@ -64,10 +64,10 @@ import io.rtron.model.roadspaces.roadspace.road.Road as RoadspaceRoad * Builder for [RoadspaceObject] which correspond to the OpenDRIVE road object class. */ class RoadspaceObjectBuilder( - private val parameters: Opendrive2RoadspacesParameters + private val parameters: Opendrive2RoadspacesParameters, ) { - // Methods + /** * Builds up a list of [RoadspaceObject]. * @@ -79,7 +79,7 @@ class RoadspaceObjectBuilder( roadObjects: OpendriveRoadObjects, roadReferenceLine: Curve3D, road: RoadspaceRoad, - baseAttributes: AttributeList + baseAttributes: AttributeList, ): ContextIssueList> { return roadObjects.roadObject .map { buildRoadObject(roadspaceId, it, roadReferenceLine, road, baseAttributes) } @@ -92,7 +92,7 @@ class RoadspaceObjectBuilder( roadObject: OpendriveRoadObject, roadReferenceLine: Curve3D, road: RoadspaceRoad, - baseAttributes: AttributeList + baseAttributes: AttributeList, ): ContextIssueList> { val issueList = DefaultIssueList() @@ -100,45 +100,30 @@ class RoadspaceObjectBuilder( val type = getObjectType(roadObject) // build attributes - val attributes = baseAttributes + - buildAttributes(roadObject) + - buildAttributes(roadObject.curveRelativePosition) + - buildAttributes(roadObject.referenceLinePointRelativeRotation) + val attributes = + baseAttributes + + buildAttributes(roadObject) + + buildAttributes(roadObject.curveRelativePosition) + + buildAttributes(roadObject.referenceLinePointRelativeRotation) val laneRelations = buildLaneRelations(roadObject, road) - 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.some(), roadObject.name, id) - - val pointGeometry = buildPointGeometry(currentRoadObjectRepeat, roadReferenceLine) - val boundingBoxGeometry = buildBoundingBoxGeometry(roadObject, roadReferenceLine) - val complexGeometry = buildComplexGeometry( - roadObject, - currentRoadObjectRepeat.some(), - roadReferenceLine - ).handleIssueList { issueList += it } - RoadspaceObject( - roadspaceObjectId, - type, - pointGeometry, - boundingBoxGeometry, - complexGeometry, - laneRelations, - attributes - ) - } - - val roadObjects = if (roadObjectsFromRepeat.isEmpty()) { - val roadspaceObjectId = RoadspaceObjectIdentifier(roadObject.id, None, roadObject.name, id) - val pointGeometry = buildPointGeometry(roadObject, roadReferenceLine) - val boundingBoxGeometry = buildBoundingBoxGeometry(roadObject, roadReferenceLine) - val complexGeometry = - buildComplexGeometry(roadObject, None, roadReferenceLine).handleIssueList { issueList += it } - nonEmptyListOf( + 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.some(), roadObject.name, id) + + val pointGeometry = buildPointGeometry(currentRoadObjectRepeat, roadReferenceLine) + val boundingBoxGeometry = buildBoundingBoxGeometry(roadObject, roadReferenceLine) + val complexGeometry = + buildComplexGeometry( + roadObject, + currentRoadObjectRepeat.some(), + roadReferenceLine, + ).handleIssueList { issueList += it } RoadspaceObject( roadspaceObjectId, type, @@ -146,12 +131,31 @@ class RoadspaceObjectBuilder( boundingBoxGeometry, complexGeometry, laneRelations, - attributes + attributes, ) - ) - } else { - roadObjectsFromRepeat.toNonEmptyListOrNull()!! - } + } + + val roadObjects = + if (roadObjectsFromRepeat.isEmpty()) { + val roadspaceObjectId = RoadspaceObjectIdentifier(roadObject.id, None, roadObject.name, id) + val pointGeometry = buildPointGeometry(roadObject, roadReferenceLine) + val boundingBoxGeometry = buildBoundingBoxGeometry(roadObject, roadReferenceLine) + val complexGeometry = + buildComplexGeometry(roadObject, None, roadReferenceLine).handleIssueList { issueList += it } + nonEmptyListOf( + RoadspaceObject( + roadspaceObjectId, + type, + pointGeometry, + boundingBoxGeometry, + complexGeometry, + laneRelations, + attributes, + ), + ) + } else { + roadObjectsFromRepeat.toNonEmptyListOrNull()!! + } // build roadspace object return ContextIssueList(roadObjects, issueList) @@ -179,12 +183,18 @@ class RoadspaceObjectBuilder( } }) - private fun buildPointGeometry(roadObject: OpendriveRoadObject, roadReferenceLine: Curve3D): Vector3D { + private fun buildPointGeometry( + roadObject: OpendriveRoadObject, + roadReferenceLine: Curve3D, + ): Vector3D { val curveAffine = roadReferenceLine.calculateAffine(roadObject.curveRelativePosition.toCurveRelative1D()) return Vector3DBuilder.buildVector3Ds(roadObject, curveAffine) } - private fun buildPointGeometry(roadObjectRepeat: OpendriveRoadObjectRepeat, roadReferenceLine: Curve3D): Vector3D { + private fun buildPointGeometry( + roadObjectRepeat: OpendriveRoadObjectRepeat, + roadReferenceLine: Curve3D, + ): Vector3D { val curveAffine = roadReferenceLine.calculateAffine(roadObjectRepeat.curveRelativeStartPosition) val affineSequence = AffineSequence3D.of(curveAffine) return roadObjectRepeat.referenceLinePointRelativePosition.copy(affineSequence = affineSequence) @@ -192,13 +202,13 @@ class RoadspaceObjectBuilder( private fun buildBoundingBoxGeometry( roadObject: OpendriveRoadObject, - roadReferenceLine: Curve3D + roadReferenceLine: Curve3D, ): Option { check( roadObject.containsCuboid().toInt() + roadObject.containsCylinder().toInt() + roadObject.containsRectangle().toInt() + - roadObject.containsCircle().toInt() <= 1 + roadObject.containsCircle().toInt() <= 1, ) { "Bounding box must only be derived for a single geometry." } // affine transformation matrix at the curve point of the object @@ -229,7 +239,7 @@ class RoadspaceObjectBuilder( private fun buildComplexGeometry( roadObject: OpendriveRoadObject, roadObjectRepeat: Option, - roadReferenceLine: Curve3D + roadReferenceLine: Curve3D, ): ContextIssueList> { val issueList = DefaultIssueList() @@ -238,78 +248,81 @@ class RoadspaceObjectBuilder( // build up solid geometrical representations val geometries = mutableListOf() - geometries += Solid3DBuilder.buildPolyhedronsByRoadCorners( - roadObject, - roadReferenceLine, - parameters.numberTolerance - ).handleIssueList { issueList += it } - geometries += Solid3DBuilder.buildPolyhedronsByLocalCorners(roadObject, curveAffine, parameters.numberTolerance) - .handleIssueList { issueList += it } + geometries += + Solid3DBuilder.buildPolyhedronsByRoadCorners( + roadObject, + roadReferenceLine, + parameters.numberTolerance, + ).handleIssueList { issueList += it } + geometries += + Solid3DBuilder.buildPolyhedronsByLocalCorners(roadObject, curveAffine, parameters.numberTolerance) + .handleIssueList { issueList += it } // build up surface geometrical representations - geometries += Surface3DBuilder.buildLinearRingsByRoadCorners( - roadObject, - roadReferenceLine, - parameters.numberTolerance - ).handleIssueList { issueList += it } - geometries += Surface3DBuilder.buildLinearRingsByLocalCorners( - roadObject, - curveAffine, - parameters.numberTolerance - ).handleIssueList { issueList += it } + geometries += + Surface3DBuilder.buildLinearRingsByRoadCorners( + roadObject, + roadReferenceLine, + parameters.numberTolerance, + ).handleIssueList { issueList += it } + geometries += + Surface3DBuilder.buildLinearRingsByLocalCorners( + roadObject, + curveAffine, + parameters.numberTolerance, + ).handleIssueList { issueList += it } roadObjectRepeat.onSome { currentRepeat -> - geometries += Solid3DBuilder.buildParametricSweep( - currentRepeat, - roadReferenceLine, - parameters.numberTolerance - ).toList() - geometries += Surface3DBuilder.buildParametricBoundedSurfacesByHorizontalRepeat( - currentRepeat, - roadReferenceLine, - parameters.numberTolerance - ) - geometries += Surface3DBuilder.buildParametricBoundedSurfacesByVerticalRepeat( - currentRepeat, - roadReferenceLine, - parameters.numberTolerance - ) + geometries += + Solid3DBuilder.buildParametricSweep( + currentRepeat, + roadReferenceLine, + parameters.numberTolerance, + ).toList() + geometries += + Surface3DBuilder.buildParametricBoundedSurfacesByHorizontalRepeat( + currentRepeat, + roadReferenceLine, + parameters.numberTolerance, + ) + geometries += + Surface3DBuilder.buildParametricBoundedSurfacesByVerticalRepeat( + currentRepeat, + roadReferenceLine, + parameters.numberTolerance, + ) if (currentRepeat.containsRepeatedCuboid()) { - issueList += DefaultIssue.of( - "RepeatCuboidNotSupported", - "Cuboid geometries in the repeat elements are currently not supported.", - roadObject.additionalId, - Severity.WARNING, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "RepeatCuboidNotSupported", + "Cuboid geometries in the repeat elements are currently not supported.", + roadObject.additionalId, Severity.WARNING, wasFixed = false, + ) } if (currentRepeat.containsRepeatCylinder()) { - issueList += DefaultIssue.of( - "RepeatCylinderNotSupported", - "Cylinder geometries in the repeat elements are currently not supported.", - roadObject.additionalId, - Severity.WARNING, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "RepeatCylinderNotSupported", + "Cylinder geometries in the repeat elements are currently not supported.", + roadObject.additionalId, Severity.WARNING, wasFixed = false, + ) } if (currentRepeat.containsRepeatedRectangle()) { - issueList += DefaultIssue.of( - "RepeatRectangleNotSupported", - "Rectangle geometries in the repeat elements are currently not supported.", - roadObject.additionalId, - Severity.WARNING, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "RepeatRectangleNotSupported", + "Rectangle geometries in the repeat elements are currently not supported.", + roadObject.additionalId, Severity.WARNING, wasFixed = false, + ) } if (currentRepeat.containsRepeatCircle()) { - issueList += DefaultIssue.of( - "RepeatCircleNotSupported", - "Circle geometries in the repeat elements are currently not supported.", - roadObject.additionalId, - Severity.WARNING, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "RepeatCircleNotSupported", + "Circle geometries in the repeat elements are currently not supported.", + roadObject.additionalId, Severity.WARNING, wasFixed = false, + ) } } @@ -317,13 +330,12 @@ class RoadspaceObjectBuilder( geometries += Curve3DBuilder.buildCurve3D(roadObject, roadReferenceLine, parameters.numberTolerance) if (geometries.size > 1) { - issueList += DefaultIssue.of( - "MultipleComplexGeometriesNotSupported", - "Conversion of road objects with multiple complex geometries is currently not supported.", - roadObject.additionalId, - Severity.WARNING, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "MultipleComplexGeometriesNotSupported", + "Conversion of road objects with multiple complex geometries is currently not supported.", + roadObject.additionalId, Severity.WARNING, wasFixed = false, + ) } val builtGeometry = if (geometries.isEmpty()) None else Some(geometries.first()) return ContextIssueList(builtGeometry, issueList) @@ -370,7 +382,7 @@ class RoadspaceObjectBuilder( roadSignals: RoadSignals, roadReferenceLine: Curve3D, road: RoadspaceRoad, - baseAttributes: AttributeList + baseAttributes: AttributeList, ): ContextIssueList> { return roadSignals.signal.map { buildRoadSignalsSignal(id, it, roadReferenceLine, road, baseAttributes) } .mergeIssueLists() @@ -381,7 +393,7 @@ class RoadspaceObjectBuilder( roadSignal: RoadSignalsSignal, roadReferenceLine: Curve3D, road: RoadspaceRoad, - baseAttributes: AttributeList + baseAttributes: AttributeList, ): ContextIssueList { val issueList = DefaultIssueList() @@ -391,20 +403,22 @@ class RoadspaceObjectBuilder( val complexGeometry = buildComplexGeometry(roadSignal, roadReferenceLine).handleIssueList { issueList += it } val laneRelations = buildLaneRelations(roadSignal, road) - val attributes = baseAttributes + - buildAttributes(roadSignal) + - buildAttributes(roadSignal.curveRelativePosition) + - buildAttributes(roadSignal.referenceLinePointRelativeRotation) - - val roadspaceObject = RoadspaceObject( - objectId, - RoadObjectType.SIGNAL, - pointGeometry, - None, - complexGeometry, - laneRelations, - attributes - ) + val attributes = + baseAttributes + + buildAttributes(roadSignal) + + buildAttributes(roadSignal.curveRelativePosition) + + buildAttributes(roadSignal.referenceLinePointRelativeRotation) + + val roadspaceObject = + RoadspaceObject( + objectId, + RoadObjectType.SIGNAL, + pointGeometry, + None, + complexGeometry, + laneRelations, + attributes, + ) return ContextIssueList(roadspaceObject, issueList) } @@ -425,14 +439,17 @@ class RoadspaceObjectBuilder( } } - private fun buildPointGeometry(signal: RoadSignalsSignal, roadReferenceLine: Curve3D): Vector3D { + private fun buildPointGeometry( + signal: RoadSignalsSignal, + roadReferenceLine: Curve3D, + ): Vector3D { val curveAffine = roadReferenceLine.calculateAffine(signal.curveRelativePosition.toCurveRelative1D()) return Vector3DBuilder.buildVector3Ds(signal, curveAffine) } private fun buildComplexGeometry( signal: RoadSignalsSignal, - roadReferenceLine: Curve3D + roadReferenceLine: Curve3D, ): ContextIssueList> { val issueList = DefaultIssueList() @@ -442,26 +459,24 @@ class RoadspaceObjectBuilder( if (signal.containsRectangle()) { return ContextIssueList( Surface3DBuilder.buildRectangle(signal, curveAffine, parameters.numberTolerance).some(), - issueList + issueList, ) } if (signal.containsHorizontalLine()) { - issueList += DefaultIssue.of( - "SignalHorizontalLineNotSupported", - "Horizontal line geometry in road signal is currently not supported.", - signal.additionalId, - Severity.WARNING, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "SignalHorizontalLineNotSupported", + "Horizontal line geometry in road signal is currently not supported.", + signal.additionalId, Severity.WARNING, wasFixed = false, + ) } if (signal.containsVerticalLine()) { - issueList += DefaultIssue.of( - "SignalVerticalLineNotSupported", - "Vertical line geometry in road signal is currently not supported.", - signal.additionalId, - Severity.WARNING, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "SignalVerticalLineNotSupported", + "Vertical line geometry in road signal is currently not supported.", + signal.additionalId, Severity.WARNING, wasFixed = false, + ) } return ContextIssueList(None, issueList) @@ -469,7 +484,7 @@ class RoadspaceObjectBuilder( private fun buildLaneRelations( roadObject: OpendriveRoadObject, - road: RoadspaceRoad + road: RoadspaceRoad, ): List { val laneSection = road.getLaneSection(roadObject.curveRelativePosition.toCurveRelative1D()).getOrElse { throw it } @@ -483,7 +498,7 @@ class RoadspaceObjectBuilder( private fun buildLaneRelations( roadSignal: RoadSignalsSignal, - road: RoadspaceRoad + road: RoadspaceRoad, ): List { val laneSection = road.getLaneSection(roadSignal.curveRelativePosition.toCurveRelative1D()).getOrElse { throw it } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/Roadspaces2CitygmlParameters.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/Roadspaces2CitygmlParameters.kt index fd92988c..b7afbb43 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/Roadspaces2CitygmlParameters.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/Roadspaces2CitygmlParameters.kt @@ -48,9 +48,8 @@ data class Roadspaces2CitygmlParameters( /** if true, filler surfaces are generated to close gaps at lane transitions */ val generateLongitudinalFillerSurfaces: Boolean, /** if true, only classes are populated that are also available in CityGML2 */ - val mappingBackwardsCompatibility: Boolean + val mappingBackwardsCompatibility: Boolean, ) { - init { require(PATTERN_NCNAME.matcher(gmlIdPrefix).matches()) { "Provided gmlIdPrefix ($gmlIdPrefix) requires valid NCName pattern." } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/Roadspaces2CitygmlTransformer.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/Roadspaces2CitygmlTransformer.kt index 43f2fce7..f09e5362 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/Roadspaces2CitygmlTransformer.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/Roadspaces2CitygmlTransformer.kt @@ -54,9 +54,8 @@ import org.xmlobjects.gml.model.geometry.Envelope * @param parameters parameters for the transformation */ class Roadspaces2CitygmlTransformer( - val parameters: Roadspaces2CitygmlParameters + val parameters: Roadspaces2CitygmlParameters, ) { - // Properties and Initializers private val logger = KotlinLogging.logger {} @@ -92,118 +91,129 @@ class Roadspaces2CitygmlTransformer( return citygmlModel to report } - private fun transformRoadspacesSequentially( - roadspacesModel: RoadspacesModel - ): ContextIssueList> { + private fun transformRoadspacesSequentially(roadspacesModel: RoadspacesModel): ContextIssueList> { val issueList = DefaultIssueList() // build objects val roadFeaturesProgressBar = ProgressBar("Transforming road", roadspacesModel.getAllRoadspaceNames().size) - val roadFeatures = roadspacesModel - .getAllRoadspaceNames() - .map { roadLanesTransformer.transformRoad(it, roadspacesModel).also { roadFeaturesProgressBar.step() } } - .mergeIssueLists() - .handleIssueList { issueList += it } - .flattenOption() + val roadFeatures = + roadspacesModel + .getAllRoadspaceNames() + .map { roadLanesTransformer.transformRoad(it, roadspacesModel).also { roadFeaturesProgressBar.step() } } + .mergeIssueLists() + .handleIssueList { issueList += it } + .flattenOption() val roadspaceObjectsProgressBar = ProgressBar("Transforming roadspace objects", roadspacesModel.numberOfRoadspaces) - val roadspaceObjects: List = roadspacesModel - .getAllRoadspaces() - .map { - roadObjectTransformer.transformRoadspaceObjects(it.roadspaceObjects) - .also { roadspaceObjectsProgressBar.step() } - } - .mergeIssueLists() - .handleIssueList { issueList += it } - .flatten() + val roadspaceObjects: List = + roadspacesModel + .getAllRoadspaces() + .map { + roadObjectTransformer.transformRoadspaceObjects(it.roadspaceObjects) + .also { roadspaceObjectsProgressBar.step() } + } + .mergeIssueLists() + .handleIssueList { issueList += it } + .flatten() - val additionalRoadLines: List = if (parameters.transformAdditionalRoadLines) { - val additionalRoadLinesProgressBar = - ProgressBar("Transforming additional road lines", roadspacesModel.numberOfRoadspaces) - roadspacesModel.getAllRoadspaces().map { - roadLanesTransformer.transformAdditionalRoadLines(it).also { additionalRoadLinesProgressBar.step() } - }.mergeIssueLists().handleIssueList { issueList += it }.flatten() - } else { - emptyList() - } + val additionalRoadLines: List = + if (parameters.transformAdditionalRoadLines) { + val additionalRoadLinesProgressBar = + ProgressBar("Transforming additional road lines", roadspacesModel.numberOfRoadspaces) + roadspacesModel.getAllRoadspaces().map { + roadLanesTransformer.transformAdditionalRoadLines(it).also { additionalRoadLinesProgressBar.step() } + }.mergeIssueLists().handleIssueList { issueList += it }.flatten() + } else { + emptyList() + } addLaneTopology(roadspacesModel, roadFeatures) val cityObjects: List = roadFeatures + roadspaceObjects + additionalRoadLines return ContextIssueList(cityObjects, issueList) } - private fun transformRoadspacesConcurrently( - roadspacesModel: RoadspacesModel - ): ContextIssueList> { + private fun transformRoadspacesConcurrently(roadspacesModel: RoadspacesModel): ContextIssueList> { val issueList = DefaultIssueList() // build objects val roadFeaturesProgressBar = ProgressBar("Transforming road", roadspacesModel.getAllRoadspaceNames().size) - val roadFeaturesDeferred = roadspacesModel - .getAllRoadspaceNames() - .map { - GlobalScope.async { - roadLanesTransformer.transformRoad(it, roadspacesModel).also { roadFeaturesProgressBar.step() } + val roadFeaturesDeferred = + roadspacesModel + .getAllRoadspaceNames() + .map { + GlobalScope.async { + roadLanesTransformer.transformRoad(it, roadspacesModel).also { roadFeaturesProgressBar.step() } + } } - } val roadspaceObjectsProgressBar = ProgressBar("Transforming roadspace objects", roadspacesModel.numberOfRoadspaces) - val roadspaceObjectsDeferred = roadspacesModel.getAllRoadspaces().map { - GlobalScope.async { - roadObjectTransformer.transformRoadspaceObjects(it.roadspaceObjects) - .also { roadspaceObjectsProgressBar.step() } - } - } - - val additionalRoadLinesDeferred = if (parameters.transformAdditionalRoadLines) { - val additionalRoadLinesProgressBar = - ProgressBar("Transforming additional road lines", roadspacesModel.numberOfRoadspaces) + val roadspaceObjectsDeferred = roadspacesModel.getAllRoadspaces().map { GlobalScope.async { - roadLanesTransformer.transformAdditionalRoadLines(it).also { additionalRoadLinesProgressBar.step() } + roadObjectTransformer.transformRoadspaceObjects(it.roadspaceObjects) + .also { roadspaceObjectsProgressBar.step() } } } - } else { - emptyList() - } - val roadFeatures = runBlocking { - roadFeaturesDeferred.map { currentRoadFeature -> - currentRoadFeature.await().handleIssueList { issueList += it } - }.flattenOption() - } - val roadspaceObjects = runBlocking { - roadspaceObjectsDeferred.map { currentRoadSpaceObject -> - currentRoadSpaceObject.await().handleIssueList { issueList += it } - }.flatten() - } - val additionalRoadLines = runBlocking { - additionalRoadLinesDeferred.flatMap { currentRoadLines -> - currentRoadLines.await().handleIssueList { issueList += it } + val additionalRoadLinesDeferred = + if (parameters.transformAdditionalRoadLines) { + val additionalRoadLinesProgressBar = + ProgressBar("Transforming additional road lines", roadspacesModel.numberOfRoadspaces) + roadspacesModel.getAllRoadspaces().map { + GlobalScope.async { + roadLanesTransformer.transformAdditionalRoadLines(it).also { additionalRoadLinesProgressBar.step() } + } + } + } else { + emptyList() + } + + val roadFeatures = + runBlocking { + roadFeaturesDeferred.map { currentRoadFeature -> + currentRoadFeature.await().handleIssueList { issueList += it } + }.flattenOption() + } + val roadspaceObjects = + runBlocking { + roadspaceObjectsDeferred.map { currentRoadSpaceObject -> + currentRoadSpaceObject.await().handleIssueList { issueList += it } + }.flatten() + } + val additionalRoadLines = + runBlocking { + additionalRoadLinesDeferred.flatMap { currentRoadLines -> + currentRoadLines.await().handleIssueList { issueList += it } + } } - } addLaneTopology(roadspacesModel, roadFeatures) val cityObjects: List = roadFeatures + roadspaceObjects + additionalRoadLines return ContextIssueList(cityObjects, issueList) } - private fun addLaneTopology(roadspacesModel: RoadspacesModel, dstTransportationSpaces: List) { - val trafficSpaceProperties = dstTransportationSpaces.flatMap { it.trafficSpaces } + - dstTransportationSpaces.flatMap { it.sections }.filter { it.isSetObject } - .flatMap { it.`object`.trafficSpaces } + - dstTransportationSpaces.flatMap { it.intersections }.filter { it.isSetObject } - .flatMap { it.`object`.trafficSpaces } + private fun addLaneTopology( + roadspacesModel: RoadspacesModel, + dstTransportationSpaces: List, + ) { + val trafficSpaceProperties = + dstTransportationSpaces.flatMap { it.trafficSpaces } + + dstTransportationSpaces.flatMap { it.sections }.filter { it.isSetObject } + .flatMap { it.`object`.trafficSpaces } + + dstTransportationSpaces.flatMap { it.intersections }.filter { it.isSetObject } + .flatMap { it.`object`.trafficSpaces } // TODO: trace the traffic space created without id - val trafficSpacePropertyMap: Map = trafficSpaceProperties - .filter { it.`object`.id != null } - .associateBy { it.`object`.id } + val trafficSpacePropertyMap: Map = + trafficSpaceProperties + .filter { it.`object`.id != null } + .associateBy { it.`object`.id } - val lanesMap: Map = roadspacesModel - .getAllLeftRightLanes() - .associateBy { it.id.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier(parameters.gmlIdPrefix) } + val lanesMap: Map = + roadspacesModel + .getAllLeftRightLanes() + .associateBy { it.id.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier(parameters.gmlIdPrefix) } trafficSpacePropertyMap.values.forEach { currentTrafficSpace -> val currentLane: Lane = lanesMap.getValueEither(currentTrafficSpace.`object`.id).getOrElse { return@forEach } @@ -218,14 +228,16 @@ class Roadspaces2CitygmlTransformer( } else { roadspacesModel.getSuccessorLaneIdentifiers(currentLane.id).getOrElse { throw it } } - currentTrafficSpace.`object`.predecessors = predecessorLaneIds - .map { - TrafficSpaceReference( - parameters.xlinkPrefix + it.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier( - parameters.gmlIdPrefix + currentTrafficSpace.`object`.predecessors = + predecessorLaneIds + .map { + TrafficSpaceReference( + parameters.xlinkPrefix + + it.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier( + parameters.gmlIdPrefix, + ), ) - ) - } + } // successor val successorLaneIds = @@ -237,14 +249,16 @@ class Roadspaces2CitygmlTransformer( } else { roadspacesModel.getPredecessorLaneIdentifiers(currentLane.id).getOrElse { throw it } } - currentTrafficSpace.`object`.successors = successorLaneIds - .map { - TrafficSpaceReference( - parameters.xlinkPrefix + it.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier( - parameters.gmlIdPrefix + currentTrafficSpace.`object`.successors = + successorLaneIds + .map { + TrafficSpaceReference( + parameters.xlinkPrefix + + it.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier( + parameters.gmlIdPrefix, + ), ) - ) - } + } // lateral lane changes val outerLaneId = currentLane.id.getAdjacentOuterLaneIdentifier() @@ -269,7 +283,7 @@ class Roadspaces2CitygmlTransformer( relationAdder.addLaneChangeRelation( currentLane, laneChangeDirection.opposite(), - outerTrafficSpace.`object` + outerTrafficSpace.`object`, ) } } @@ -278,7 +292,7 @@ class Roadspaces2CitygmlTransformer( private fun calculateBoundingShape( abstractCityObjects: List, - crs: Option + crs: Option, ): BoundingShape { val envelope = Envelope() crs.onSome { envelope.srsName = it.srsName } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/AbstractSpaceExtensions.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/AbstractSpaceExtensions.kt index 1914f6a8..3431a2e5 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/AbstractSpaceExtensions.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/AbstractSpaceExtensions.kt @@ -27,14 +27,15 @@ import org.citygml4j.core.model.core.AbstractSpace * @param geometryTransformer source geometries * @return [Either.Right] is returned, if a geometry has been populated; [Either.Left], if no adequate geometry could be assigned */ -fun AbstractSpace.populateLod0Geometry(geometryTransformer: GeometryTransformer): Either = either { - geometryTransformer.getPoint().onSome { - lod0Point = it - return@either - } +fun AbstractSpace.populateLod0Geometry(geometryTransformer: GeometryTransformer): Either = + either { + geometryTransformer.getPoint().onSome { + lod0Point = it + return@either + } - GeometryTransformerException.NoSuiteableSourceGeometry("LOD0 geometry of the abstract space.").left().bind() -} + GeometryTransformerException.NoSuiteableSourceGeometry("LOD0 geometry of the abstract space.").left().bind() + } /** * Populates the LOD1 geometry of an [AbstractSpace] object with the source geometries of the [GeometryTransformer]. @@ -43,14 +44,15 @@ fun AbstractSpace.populateLod0Geometry(geometryTransformer: GeometryTransformer) * @param geometryTransformer source geometries * @return [Either.Right] is returned, if a geometry has been populated; [Either.Left], if no adequate geometry could be assigned */ -fun AbstractSpace.populateLod1Geometry(geometryTransformer: GeometryTransformer): Either = either { - geometryTransformer.getSolid().onSome { - lod1Solid = it - return@either - } +fun AbstractSpace.populateLod1Geometry(geometryTransformer: GeometryTransformer): Either = + either { + geometryTransformer.getSolid().onSome { + lod1Solid = it + return@either + } - GeometryTransformerException.NoSuiteableSourceGeometry("LOD1 geometry of the abstract space.").left().bind() -} + GeometryTransformerException.NoSuiteableSourceGeometry("LOD1 geometry of the abstract space.").left().bind() + } /** * Populates the LOD2 geometry of an [AbstractSpace] object with the source geometries of the [GeometryTransformer]. @@ -59,24 +61,25 @@ fun AbstractSpace.populateLod1Geometry(geometryTransformer: GeometryTransformer) * @param geometryTransformer source geometries * @return [Either.Right] is returned, if a geometry has been populated; [Either.Left], if no adequate geometry could be assigned */ -fun AbstractSpace.populateLod2Geometry(geometryTransformer: GeometryTransformer): Either = either { - geometryTransformer.getSolid().onSome { - lod2Solid = it - return@either - } +fun AbstractSpace.populateLod2Geometry(geometryTransformer: GeometryTransformer): Either = + either { + geometryTransformer.getSolid().onSome { + lod2Solid = it + return@either + } - geometryTransformer.getMultiSurface().onSome { currentMultiSurface -> - lod2MultiSurface = currentMultiSurface.mapLeft { it.toGeometryGenerationException() }.bind() - return@either - } + geometryTransformer.getMultiSurface().onSome { currentMultiSurface -> + lod2MultiSurface = currentMultiSurface.mapLeft { it.toGeometryGenerationException() }.bind() + return@either + } - geometryTransformer.getMultiCurve().onSome { currentMultiSurfaceResult -> - lod2MultiCurve = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() - return@either - } + geometryTransformer.getMultiCurve().onSome { currentMultiSurfaceResult -> + lod2MultiCurve = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() + return@either + } - GeometryTransformerException.NoSuiteableSourceGeometry("LOD2 geometry of the abstract space.").left().bind() -} + GeometryTransformerException.NoSuiteableSourceGeometry("LOD2 geometry of the abstract space.").left().bind() + } /** * Populates the LOD2 geometry of an [AbstractSpace] object with the source geometries of the [GeometryTransformer]. @@ -85,21 +88,22 @@ fun AbstractSpace.populateLod2Geometry(geometryTransformer: GeometryTransformer) * @param geometryTransformer source geometries * @return [Either.Right] is returned, if a geometry has been populated; [Either.Left], if no adequate geometry could be assigned */ -fun AbstractSpace.populateLod3Geometry(geometryTransformer: GeometryTransformer): Either = either { - geometryTransformer.getSolid().onSome { - lod3Solid = it - return@either - } +fun AbstractSpace.populateLod3Geometry(geometryTransformer: GeometryTransformer): Either = + either { + geometryTransformer.getSolid().onSome { + lod3Solid = it + return@either + } - geometryTransformer.getMultiSurface().onSome { currentMultiSurfaceResult -> - lod3MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() - return@either - } + geometryTransformer.getMultiSurface().onSome { currentMultiSurfaceResult -> + lod3MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() + return@either + } - geometryTransformer.getMultiCurve().onSome { currentMultiCurveResult -> - lod3MultiCurve = currentMultiCurveResult.mapLeft { it.toGeometryGenerationException() }.bind() - return@either - } + geometryTransformer.getMultiCurve().onSome { currentMultiCurveResult -> + lod3MultiCurve = currentMultiCurveResult.mapLeft { it.toGeometryGenerationException() }.bind() + return@either + } - GeometryTransformerException.NoSuiteableSourceGeometry("LOD3 geometry of the abstract space").left().bind() -} + GeometryTransformerException.NoSuiteableSourceGeometry("LOD3 geometry of the abstract space").left().bind() + } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/AbstractThematicSurfaceExtensions.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/AbstractThematicSurfaceExtensions.kt index 70f371ed..94698a25 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/AbstractThematicSurfaceExtensions.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/AbstractThematicSurfaceExtensions.kt @@ -22,11 +22,15 @@ import arrow.core.raise.either import arrow.core.right import org.citygml4j.core.model.core.AbstractThematicSurface -fun AbstractThematicSurface.populateLod2MultiSurfaceOrLod0Geometry(geometryTransformer: GeometryTransformer): Either { +fun AbstractThematicSurface.populateLod2MultiSurfaceOrLod0Geometry( + geometryTransformer: GeometryTransformer, +): Either { val lod2MultiSurfaceError = populateLod2MultiSurface(geometryTransformer).fold({ it }, { return it.right() }) val lod0GeometryError = populateLod0Geometry(geometryTransformer).fold({ it }, { return it.right() }) - return GeometryTransformerException.NoSuiteableSourceGeometry("LOD2 multi surface or LOD0 geometry of the abstract thematic surface.").left() + return GeometryTransformerException.NoSuiteableSourceGeometry( + "LOD2 multi surface or LOD0 geometry of the abstract thematic surface.", + ).left() } /** @@ -35,20 +39,21 @@ fun AbstractThematicSurface.populateLod2MultiSurfaceOrLod0Geometry(geometryTrans * @param geometryTransformer source geometries * @return [Either.Right] is returned, if a geometry has been populated; [Either.Left], if no adequate geometry could be assigned */ -fun AbstractThematicSurface.populateLod0Geometry(geometryTransformer: GeometryTransformer): Either = either { - geometryTransformer.getMultiSurface().onSome { currentMultiCurveResult -> - lod0MultiSurface = currentMultiCurveResult.mapLeft { it.toGeometryGenerationException() }.bind() - return@either - } +fun AbstractThematicSurface.populateLod0Geometry(geometryTransformer: GeometryTransformer): Either = + either { + geometryTransformer.getMultiSurface().onSome { currentMultiCurveResult -> + lod0MultiSurface = currentMultiCurveResult.mapLeft { it.toGeometryGenerationException() }.bind() + return@either + } - geometryTransformer.getMultiCurve().onSome { currentMultiCurveResult -> - lod0MultiCurve = currentMultiCurveResult.mapLeft { it.toGeometryGenerationException() }.bind() - return@either - } + geometryTransformer.getMultiCurve().onSome { currentMultiCurveResult -> + lod0MultiCurve = currentMultiCurveResult.mapLeft { it.toGeometryGenerationException() }.bind() + return@either + } - GeometryTransformerException.NoSuiteableSourceGeometry("LOD0 geometry of the abstract thematic surface.").left() - .bind() -} + GeometryTransformerException.NoSuiteableSourceGeometry("LOD0 geometry of the abstract thematic surface.").left() + .bind() + } /** * Populates the LOD1 geometry of an [AbstractThematicSurface] object with the source geometries of the [GeometryTransformer]. @@ -56,15 +61,16 @@ fun AbstractThematicSurface.populateLod0Geometry(geometryTransformer: GeometryTr * @param geometryTransformer source geometries * @return [Either.Right] is returned, if a geometry has been populated; [Either.Left], if no adequate geometry could be assigned */ -fun AbstractThematicSurface.populateLod1MultiSurface(geometryTransformer: GeometryTransformer): Either = either { - geometryTransformer.getMultiSurface().onSome { currentMultiSurfaceResult -> - lod1MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() - return@either - } +fun AbstractThematicSurface.populateLod1MultiSurface(geometryTransformer: GeometryTransformer): Either = + either { + geometryTransformer.getMultiSurface().onSome { currentMultiSurfaceResult -> + lod1MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() + return@either + } - GeometryTransformerException.NoSuiteableSourceGeometry("LOD1 multi surface of the abstract thematic surface.") - .left().bind() -} + GeometryTransformerException.NoSuiteableSourceGeometry("LOD1 multi surface of the abstract thematic surface.") + .left().bind() + } /** * Populates the LOD2 geometry of an [AbstractThematicSurface] object with the source geometries of the [GeometryTransformer]. @@ -72,15 +78,16 @@ fun AbstractThematicSurface.populateLod1MultiSurface(geometryTransformer: Geomet * @param geometryTransformer source geometries * @return [Either.Right] is returned, if a geometry has been populated; [Either.Left], if no adequate geometry could be assigned */ -fun AbstractThematicSurface.populateLod2MultiSurface(geometryTransformer: GeometryTransformer): Either = either { - geometryTransformer.getMultiSurface().onSome { currentMultiSurfaceResult -> - lod2MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() - return@either - } +fun AbstractThematicSurface.populateLod2MultiSurface(geometryTransformer: GeometryTransformer): Either = + either { + geometryTransformer.getMultiSurface().onSome { currentMultiSurfaceResult -> + lod2MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() + return@either + } - GeometryTransformerException.NoSuiteableSourceGeometry("LOD2 multi surface of the abstract thematic surface.") - .left().bind() -} + GeometryTransformerException.NoSuiteableSourceGeometry("LOD2 multi surface of the abstract thematic surface.") + .left().bind() + } /** * Populates the LOD3 geometry of an [AbstractThematicSurface] object with the source geometries of the [GeometryTransformer]. @@ -88,23 +95,28 @@ fun AbstractThematicSurface.populateLod2MultiSurface(geometryTransformer: Geomet * @param geometryTransformer source geometries * @return [Either.Right] is returned, if a geometry has been populated; [Either.Left], if no adequate geometry could be assigned */ -fun AbstractThematicSurface.populateLod3MultiSurface(geometryTransformer: GeometryTransformer): Either = either { - geometryTransformer.getMultiSurface().onSome { currentMultiSurfaceResult -> - lod3MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() - return@either - } - - GeometryTransformerException.NoSuiteableSourceGeometry("LOD3 multi surface of the abstract thematic surface.") - .left().bind() -} - -fun AbstractThematicSurface.populateLod2MultiSurfaceFromSolidCutoutOrSurface(geometryTransformer: GeometryTransformer, solidFaceSelection: List): Either = either { - geometryTransformer.getSolidCutoutOrSurface(*solidFaceSelection.toTypedArray()) - .onSome { currentMultiSurfaceResult -> - lod2MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() +fun AbstractThematicSurface.populateLod3MultiSurface(geometryTransformer: GeometryTransformer): Either = + either { + geometryTransformer.getMultiSurface().onSome { currentMultiSurfaceResult -> + lod3MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() return@either } - GeometryTransformerException.NoSuiteableSourceGeometry("LOD2 multi surface of the abstract thematic surface.") - .left().bind() -} + GeometryTransformerException.NoSuiteableSourceGeometry("LOD3 multi surface of the abstract thematic surface.") + .left().bind() + } + +fun AbstractThematicSurface.populateLod2MultiSurfaceFromSolidCutoutOrSurface( + geometryTransformer: GeometryTransformer, + solidFaceSelection: List, +): Either = + either { + geometryTransformer.getSolidCutoutOrSurface(*solidFaceSelection.toTypedArray()) + .onSome { currentMultiSurfaceResult -> + lod2MultiSurface = currentMultiSurfaceResult.mapLeft { it.toGeometryGenerationException() }.bind() + return@either + } + + GeometryTransformerException.NoSuiteableSourceGeometry("LOD2 multi surface of the abstract thematic surface.") + .left().bind() + } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/GeometryTransformer.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/GeometryTransformer.kt index a086b089..a2d4d2e0 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/GeometryTransformer.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/GeometryTransformer.kt @@ -69,9 +69,8 @@ import org.xmlobjects.gml.model.geometry.primitives.SurfaceProperty * @param parameters parameters for the geometry transformation, such as discretization step sizes */ class GeometryTransformer( - val parameters: Roadspaces2CitygmlParameters + val parameters: Roadspaces2CitygmlParameters, ) : Geometry3DVisitor { - // Properties and Initializers private var polygonsOfSolidResult: Option> = None private var polygonsOfSurfaceResult: Option>> = @@ -94,11 +93,12 @@ class GeometryTransformer( fun getSolid(): Option { val polygonsOfSolid = polygonsOfSolidResult.handleEmpty { return None } - val gmlPolygons = polygonsOfSolid.map { - val polygonGml = geometryFactory.createPolygon(it.toVertexPositionElementList(), DIMENSION)!! - if (parameters.generateRandomGeometryIds) polygonGml.id = generateRandomUUID(parameters.gmlIdPrefix) - SurfaceProperty(polygonGml) - } + val gmlPolygons = + polygonsOfSolid.map { + val polygonGml = geometryFactory.createPolygon(it.toVertexPositionElementList(), DIMENSION)!! + if (parameters.generateRandomGeometryIds) polygonGml.id = generateRandomUUID(parameters.gmlIdPrefix) + SurfaceProperty(polygonGml) + } val solid = Solid(Shell(gmlPolygons)) if (parameters.generateRandomGeometryIds) solid.id = generateRandomUUID(parameters.gmlIdPrefix) @@ -136,10 +136,11 @@ class GeometryTransformer( fun getPoint(): Option { val point = pointResult.handleEmpty { return None } - val gmlPoint = Point().apply { - pos = createDirectPosition(point) - if (parameters.generateRandomGeometryIds) id = generateRandomUUID(parameters.gmlIdPrefix) - } + val gmlPoint = + Point().apply { + pos = createDirectPosition(point) + if (parameters.generateRandomGeometryIds) id = generateRandomUUID(parameters.gmlIdPrefix) + } return PointProperty(gmlPoint).some() } @@ -170,7 +171,7 @@ class GeometryTransformer( TOP, SIDE, BASE, - NONE + NONE, } /** @@ -193,7 +194,9 @@ class GeometryTransformer( * @param solidFaceSelection list of [FaceType] to be cutout of a solid geometry * @return cutout of a solid geometry or a [MultiSurfaceProperty] */ - fun getSolidCutoutOrSurface(vararg solidFaceSelection: FaceType): Option> { + fun getSolidCutoutOrSurface( + vararg solidFaceSelection: FaceType, + ): Option> { getSolidCutout(*solidFaceSelection).onSome { return it.right().some() } @@ -276,8 +279,9 @@ class GeometryTransformer( } override fun visit(parametricSweep3D: ParametricSweep3D) { - val adjustedParametricSweep = parametricSweep3D - .copy(discretizationStepSize = parameters.sweepDiscretizationStepSize) + val adjustedParametricSweep = + parametricSweep3D + .copy(discretizationStepSize = parameters.sweepDiscretizationStepSize) visit(adjustedParametricSweep as AbstractSolid3D) } @@ -286,11 +290,12 @@ class GeometryTransformer( } private fun polygonsToMultiSurfaceProperty(polygons: NonEmptyList): MultiSurfaceProperty { - val surfaceProperties = polygons.map { - val gmlPolygon = geometryFactory.createPolygon(it.toVertexPositionElementList(), DIMENSION)!! - if (parameters.generateRandomGeometryIds) gmlPolygon.id = generateRandomUUID(parameters.gmlIdPrefix) - SurfaceProperty(gmlPolygon) - } + val surfaceProperties = + polygons.map { + val gmlPolygon = geometryFactory.createPolygon(it.toVertexPositionElementList(), DIMENSION)!! + if (parameters.generateRandomGeometryIds) gmlPolygon.id = generateRandomUUID(parameters.gmlIdPrefix) + SurfaceProperty(gmlPolygon) + } val multiSurface = MultiSurface(surfaceProperties) if (parameters.generateRandomGeometryIds) multiSurface.id = generateRandomUUID(parameters.gmlIdPrefix) @@ -304,11 +309,17 @@ class GeometryTransformer( private val geometryFactory = GeometryFactory.newInstance() private const val DIMENSION = 3 - fun of(point: AbstractPoint3D, parameters: Roadspaces2CitygmlParameters): GeometryTransformer { + fun of( + point: AbstractPoint3D, + parameters: Roadspaces2CitygmlParameters, + ): GeometryTransformer { return GeometryTransformer(parameters).also { point.accept(it) } } - fun of(point: AbstractGeometry3D, parameters: Roadspaces2CitygmlParameters): GeometryTransformer { + fun of( + point: AbstractGeometry3D, + parameters: Roadspaces2CitygmlParameters, + ): GeometryTransformer { return GeometryTransformer(parameters).also { point.accept(it) } } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/GeometryTransformerException.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/GeometryTransformerException.kt index 638cf6ef..249ee0cd 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/GeometryTransformerException.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/geometry/GeometryTransformerException.kt @@ -19,8 +19,14 @@ package io.rtron.transformer.converter.roadspaces2citygml.geometry import io.rtron.math.geometry.GeometryException sealed class GeometryTransformerException(val message: String) { - data class NoSelectedPolygonsAvailable(val reason: String = "") : GeometryTransformerException("No MultiSurface geometry available. $reason") - data class NoSuiteableSourceGeometry(val targetGeometry: String) : GeometryTransformerException("No suitable source geometry found for populating the $targetGeometry") + data class NoSelectedPolygonsAvailable( + val reason: String = "", + ) : GeometryTransformerException("No MultiSurface geometry available. $reason") + + data class NoSuiteableSourceGeometry(val targetGeometry: String) : GeometryTransformerException( + "No suitable source geometry found for populating the $targetGeometry", + ) + data class GeometryGenerationException(val reason: String) : GeometryTransformerException("Error when generating the geometry. $reason") } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/AttributesAdder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/AttributesAdder.kt index 3f566e03..ee1f4dcc 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/AttributesAdder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/AttributesAdder.kt @@ -49,44 +49,63 @@ import org.citygml4j.core.model.generics.StringAttribute as GmlStringAttribute * Adds [Attribute] and [AttributeList] classes (RoadSpaces model) to an [AbstractCityObject] (CityGML model). */ class AttributesAdder( - private val parameters: Roadspaces2CitygmlParameters + private val parameters: Roadspaces2CitygmlParameters, ) { - // Methods /** * Adds the angle values of a [Rotation3D] in radians to the [dstCityObject]. */ - fun addRotationAttributes(rotation: Rotation3D, dstCityObject: AbstractCityObject) { - val attributeList = attributes("${parameters.geometryAttributesPrefix}rotation_") { - attribute("z", rotation.heading) - attribute("y", rotation.pitch) - attribute("x", rotation.roll) - } + fun addRotationAttributes( + rotation: Rotation3D, + dstCityObject: AbstractCityObject, + ) { + val attributeList = + attributes("${parameters.geometryAttributesPrefix}rotation_") { + attribute("z", rotation.heading) + attribute("y", rotation.pitch) + attribute("x", rotation.roll) + } addAttributes(attributeList, dstCityObject) } - fun addAttributes(lane: Lane, dstCityObject: AbstractCityObject) { + fun addAttributes( + lane: Lane, + dstCityObject: AbstractCityObject, + ) { val attributes = lane.id.toAttributes(parameters.identifierAttributesPrefix) + lane.attributes addAttributes(attributes, dstCityObject) } - fun addAttributes(roadspaceObject: RoadspaceObject, dstCityObject: AbstractCityObject) { + fun addAttributes( + roadspaceObject: RoadspaceObject, + dstCityObject: AbstractCityObject, + ) { val attributes = roadspaceObject.id.toAttributes(parameters.identifierAttributesPrefix) + roadspaceObject.attributes addAttributes(attributes, dstCityObject) } - fun addAttributes(longitudinalFillerSurface: LongitudinalFillerSurface, dstCityObject: AbstractCityObject) { + fun addAttributes( + longitudinalFillerSurface: LongitudinalFillerSurface, + dstCityObject: AbstractCityObject, + ) { val attributes = longitudinalFillerSurface.id.toAttributes(parameters.identifierAttributesPrefix) addAttributes(attributes, dstCityObject) } - fun addAttributes(lateralFillerSurface: LateralFillerSurface, dstCityObject: AbstractCityObject) { + fun addAttributes( + lateralFillerSurface: LateralFillerSurface, + dstCityObject: AbstractCityObject, + ) { val attributes = lateralFillerSurface.id.toAttributes(parameters.identifierAttributesPrefix) addAttributes(attributes, dstCityObject) } - fun addAttributes(laneId: LaneIdentifier, roadMarking: RoadMarking, dstCityObject: AbstractCityObject) { + fun addAttributes( + laneId: LaneIdentifier, + roadMarking: RoadMarking, + dstCityObject: AbstractCityObject, + ) { val attributes = laneId.toAttributes(parameters.identifierAttributesPrefix) + roadMarking.attributes addAttributes(attributes, dstCityObject) } @@ -94,19 +113,27 @@ class AttributesAdder( /** * Adds an [attributeList] to the [dstCityObject]. */ - fun addAttributes(attributeList: AttributeList, dstCityObject: AbstractCityObject) { - dstCityObject.genericAttributes = dstCityObject.genericAttributes + attributeList.attributes - .flatMap { convertAttribute(it) } - .map { AbstractGenericAttributeProperty(it) } + fun addAttributes( + attributeList: AttributeList, + dstCityObject: AbstractCityObject, + ) { + dstCityObject.genericAttributes = dstCityObject.genericAttributes + + attributeList.attributes + .flatMap { convertAttribute(it) } + .map { AbstractGenericAttributeProperty(it) } } /** * Adds the attributes of an [id] to the [dstRelation]. */ - fun addAttributes(id: AbstractRoadspacesIdentifier, dstRelation: CityObjectRelation) { - dstRelation.genericAttributes = dstRelation.genericAttributes + id.toAttributes(parameters.identifierAttributesPrefix).attributes - .flatMap { convertAttribute(it) } - .map { AbstractGenericAttributeProperty(it) } + fun addAttributes( + id: AbstractRoadspacesIdentifier, + dstRelation: CityObjectRelation, + ) { + dstRelation.genericAttributes = dstRelation.genericAttributes + + id.toAttributes(parameters.identifierAttributesPrefix).attributes + .flatMap { convertAttribute(it) } + .map { AbstractGenericAttributeProperty(it) } } /** @@ -143,12 +170,13 @@ class AttributesAdder( /** * Returns a unit of measurement as string. */ -fun UnitOfMeasure.toGmlString(): String = when (this) { - UnitOfMeasure.METER -> "#m" - UnitOfMeasure.KILOMETER -> "km" - UnitOfMeasure.METER_PER_SECOND -> "mps" - UnitOfMeasure.KILOMETER_PER_HOUR -> "kmph" - UnitOfMeasure.MILES_PER_HOUR -> "mph" - UnitOfMeasure.NONE -> TODO("Conversion of $this is not yet implemented.") - UnitOfMeasure.UNKNOWN -> TODO("Conversion of $this is not yet implemented.") -} +fun UnitOfMeasure.toGmlString(): String = + when (this) { + UnitOfMeasure.METER -> "#m" + UnitOfMeasure.KILOMETER -> "km" + UnitOfMeasure.METER_PER_SECOND -> "mps" + UnitOfMeasure.KILOMETER_PER_HOUR -> "kmph" + UnitOfMeasure.MILES_PER_HOUR -> "mph" + UnitOfMeasure.NONE -> TODO("Conversion of $this is not yet implemented.") + UnitOfMeasure.UNKNOWN -> TODO("Conversion of $this is not yet implemented.") + } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/BuildingModuleBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/BuildingModuleBuilder.kt index 12fdc94d..68e71cf9 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/BuildingModuleBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/BuildingModuleBuilder.kt @@ -42,7 +42,7 @@ import org.citygml4j.core.model.core.AbstractSpaceBoundaryProperty * Builder for city objects of the CityGML Building module. */ class BuildingModuleBuilder( - private val parameters: Roadspaces2CitygmlParameters + private val parameters: Roadspaces2CitygmlParameters, ) { // Properties and Initializers private val relationAdder = RelationAdder(parameters) @@ -65,13 +65,11 @@ class BuildingModuleBuilder( val geometryTransformer = GeometryTransformer.of(currentBoundingBoxGeometry, parameters) buildingFeature.populateLod1Geometry(geometryTransformer) .mapLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForBuildingLod1", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForBuildingLod1", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } } @@ -95,58 +93,54 @@ class BuildingModuleBuilder( private fun addLod2BuildingInformation( id: RoadspaceObjectIdentifier, geometryTransformer: GeometryTransformer, - dstBuildingFeature: Building + dstBuildingFeature: Building, ): ContextIssueList { require(geometryTransformer.getSolid().isSome()) { "Solid geometry is required to create an LOD2 building." } val issueList = DefaultIssueList() dstBuildingFeature.populateLod2Geometry(geometryTransformer) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForBuildingLod2", - it.message, - id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForBuildingLod2", + it.message, id, Severity.WARNING, wasFixed = true, + ) } val roofSurfaceFeature = RoofSurface() geometryTransformer.getSolidCutout(GeometryTransformer.FaceType.TOP).onSome { roofSurfaceFeature.lod2MultiSurface = it }.onNone { - issueList += DefaultIssue.of( - "NoSuitableGeometryForRoofSurfaceLod2", - "No LOD2 MultiSurface for roof feature available.", - id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForRoofSurfaceLod2", + "No LOD2 MultiSurface for roof feature available.", + id, Severity.WARNING, wasFixed = true, + ) } dstBuildingFeature.addBoundary(AbstractSpaceBoundaryProperty(roofSurfaceFeature)) IdentifierAdder.addIdentifier( id.deriveLod2RoofGmlIdentifier(parameters.gmlIdPrefix), "RoofSurface", - dstCityObject = roofSurfaceFeature + dstCityObject = roofSurfaceFeature, ) val groundSurfaceFeature = GroundSurface() geometryTransformer.getSolidCutout(GeometryTransformer.FaceType.BASE).onSome { groundSurfaceFeature.lod2MultiSurface = it }.onNone { - issueList += DefaultIssue.of( - "NoSuitableGeometryForGroundSurfaceLod2", - "No LOD2 MultiSurface for ground feature available.", - id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForGroundSurfaceLod2", + "No LOD2 MultiSurface for ground feature available.", + id, Severity.WARNING, wasFixed = true, + ) } dstBuildingFeature.addBoundary(AbstractSpaceBoundaryProperty(groundSurfaceFeature)) IdentifierAdder.addIdentifier( id.deriveLod2GroundGmlIdentifier(parameters.gmlIdPrefix), "GroundSurface", - dstCityObject = groundSurfaceFeature + dstCityObject = groundSurfaceFeature, ) geometryTransformer.getIndividualSolidCutouts(GeometryTransformer.FaceType.SIDE).onSome { wallSurfaceResult -> @@ -157,17 +151,16 @@ class BuildingModuleBuilder( IdentifierAdder.addIdentifier( id.deriveLod2WallGmlIdentifier(parameters.gmlIdPrefix, index), "WallSurface", - dstCityObject = wallSurfaceFeature + dstCityObject = wallSurfaceFeature, ) } }.onNone { - issueList += DefaultIssue.of( - "NoSuitableGeometryForWallSurfaceLod2", - "No LOD2 MultiSurface for wall feature available.", - id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForWallSurfaceLod2", + "No LOD2 MultiSurface for wall feature available.", + id, Severity.WARNING, wasFixed = true, + ) } return ContextIssueList(dstBuildingFeature, issueList) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/CityFurnitureModuleBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/CityFurnitureModuleBuilder.kt index f8c4c8e2..f4e95393 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/CityFurnitureModuleBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/CityFurnitureModuleBuilder.kt @@ -34,7 +34,7 @@ import org.citygml4j.core.model.cityfurniture.CityFurniture * Builder for city objects of the CityGML CityFurniture module. */ class CityFurnitureModuleBuilder( - private val parameters: Roadspaces2CitygmlParameters + private val parameters: Roadspaces2CitygmlParameters, ) { // Properties and Initializers private val relationAdder = RelationAdder(parameters) @@ -56,13 +56,11 @@ class CityFurnitureModuleBuilder( val geometryTransformer = GeometryTransformer.of(currentBoundingBoxGeometry, parameters) cityFurnitureFeature.populateLod1Geometry(geometryTransformer) .mapLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForCityFurnitureLod1", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForCityFurnitureLod1", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } } @@ -70,13 +68,11 @@ class CityFurnitureModuleBuilder( val geometryTransformer = GeometryTransformer.of(currentComplexGeometry, parameters) cityFurnitureFeature.populateLod2Geometry(geometryTransformer) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForCityFurnitureLod2", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForCityFurnitureLod2", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } } @@ -84,7 +80,7 @@ class CityFurnitureModuleBuilder( IdentifierAdder.addIdentifier( roadspaceObject.id.deriveGmlIdentifier(parameters.gmlIdPrefix), roadspaceObject.name, - cityFurnitureFeature + cityFurnitureFeature, ) relationAdder.addBelongToRelations(roadspaceObject, cityFurnitureFeature) attributesAdder.addAttributes(roadspaceObject, cityFurnitureFeature) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/CodeAdder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/CodeAdder.kt index 173d5763..64c22b44 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/CodeAdder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/CodeAdder.kt @@ -28,7 +28,6 @@ import io.rtron.model.roadspaces.roadspace.road.LaneMaterial import io.rtron.model.roadspaces.roadspace.road.LaneType object CodeAdder { - // Methods /** @@ -136,7 +135,9 @@ object CodeAdder { LaneType.MWY_EXIT -> listOf(TrafficAreaUsageCode.CAR) } - fun mapToTrafficAreaAndAuxiliaryTrafficAreaSurfaceMaterialCode(laneMaterial: LaneMaterial): Option = + fun mapToTrafficAreaAndAuxiliaryTrafficAreaSurfaceMaterialCode( + laneMaterial: LaneMaterial, + ): Option = when (laneMaterial.surface.uppercase()) { in "ASPHALT" -> TrafficAreaAndAuxiliaryTrafficAreaSurfaceMaterialCode.ASPHALT.some() in "GRASS" -> TrafficAreaAndAuxiliaryTrafficAreaSurfaceMaterialCode.GRASS.some() diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/GenericsModuleBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/GenericsModuleBuilder.kt index 83ebc042..ed0a83bf 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/GenericsModuleBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/GenericsModuleBuilder.kt @@ -45,7 +45,7 @@ import org.citygml4j.core.model.generics.GenericOccupiedSpace * Builder for city objects of the CityGML Generics module. */ class GenericsModuleBuilder( - private val parameters: Roadspaces2CitygmlParameters + private val parameters: Roadspaces2CitygmlParameters, ) { // Properties and Initializers private val relationAdder = RelationAdder(parameters) @@ -68,13 +68,11 @@ class GenericsModuleBuilder( val geometryTransformer = GeometryTransformer.of(currentBoundingBoxGeometry, parameters) genericOccupiedSpaceFeature.populateLod1Geometry(geometryTransformer) .mapLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForGenericOccupiedSpaceLod1", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForGenericOccupiedSpaceLod1", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } } @@ -82,20 +80,18 @@ class GenericsModuleBuilder( val geometryTransformer = GeometryTransformer.of(currentComplexGeometry, parameters) genericOccupiedSpaceFeature.populateLod2Geometry(geometryTransformer) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForGenericOccupiedSpaceLod2", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForGenericOccupiedSpaceLod2", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } } // semantics IdentifierAdder.addIdentifier( roadspaceObject.id.deriveGmlIdentifier(parameters.gmlIdPrefix), - genericOccupiedSpaceFeature + genericOccupiedSpaceFeature, ) relationAdder.addBelongToRelations(roadspaceObject, genericOccupiedSpaceFeature) attributesAdder.addAttributes(roadspaceObject, genericOccupiedSpaceFeature) @@ -106,20 +102,21 @@ class GenericsModuleBuilder( fun createRoadReferenceLine( id: RoadspaceIdentifier, abstractGeometry: AbstractGeometry3D, - attributes: AttributeList + attributes: AttributeList, ): ContextIssueList { val issueList = DefaultIssueList() - val genericLogicalSpace = createLogicalOccupiedSpaceFeature(id, abstractGeometry) - .handleIssueList { issueList += it } + val genericLogicalSpace = + createLogicalOccupiedSpaceFeature(id, abstractGeometry) + .handleIssueList { issueList += it } IdentifierAdder.addIdentifier( id.deriveRoadReferenceLineGmlIdentifier(parameters.gmlIdPrefix), "RoadReferenceLine", - genericLogicalSpace + genericLogicalSpace, ) attributesAdder.addAttributes( id.toAttributes(parameters.identifierAttributesPrefix) + attributes, - genericLogicalSpace + genericLogicalSpace, ) return ContextIssueList(genericLogicalSpace, issueList) @@ -128,20 +125,21 @@ class GenericsModuleBuilder( fun createRoadCenterLaneLine( id: LaneIdentifier, abstractGeometry: AbstractGeometry3D, - attributes: AttributeList + attributes: AttributeList, ): ContextIssueList { val issueList = DefaultIssueList() - val genericLogicalSpace = createLogicalOccupiedSpaceFeature(id, abstractGeometry) - .handleIssueList { issueList += it } + val genericLogicalSpace = + createLogicalOccupiedSpaceFeature(id, abstractGeometry) + .handleIssueList { issueList += it } IdentifierAdder.addIdentifier( id.deriveRoadCenterLaneLineGmlIdentifier(parameters.gmlIdPrefix), "RoadCenterLaneLine", - genericLogicalSpace + genericLogicalSpace, ) attributesAdder.addAttributes( id.toAttributes(parameters.identifierAttributesPrefix) + attributes, - genericLogicalSpace + genericLogicalSpace, ) return ContextIssueList(genericLogicalSpace, issueList) @@ -149,20 +147,21 @@ class GenericsModuleBuilder( fun createCenterLaneLine( id: LaneIdentifier, - abstractGeometry: AbstractGeometry3D + abstractGeometry: AbstractGeometry3D, ): ContextIssueList { val issueList = DefaultIssueList() - val genericLogicalSpace = createLogicalOccupiedSpaceFeature(id, abstractGeometry) - .handleIssueList { issueList += it } + val genericLogicalSpace = + createLogicalOccupiedSpaceFeature(id, abstractGeometry) + .handleIssueList { issueList += it } IdentifierAdder.addIdentifier( id.deriveLaneCenterLineGmlIdentifier(parameters.gmlIdPrefix), "LaneCenterLine", - genericLogicalSpace + genericLogicalSpace, ) attributesAdder.addAttributes( id.toAttributes(parameters.identifierAttributesPrefix), - genericLogicalSpace + genericLogicalSpace, ) return ContextIssueList(genericLogicalSpace, issueList) @@ -170,20 +169,21 @@ class GenericsModuleBuilder( fun createLeftLaneBoundary( id: LaneIdentifier, - abstractGeometry: AbstractGeometry3D + abstractGeometry: AbstractGeometry3D, ): ContextIssueList { val issueList = DefaultIssueList() - val genericLogicalSpace = createLogicalOccupiedSpaceFeature(id, abstractGeometry) - .handleIssueList { issueList += it } + val genericLogicalSpace = + createLogicalOccupiedSpaceFeature(id, abstractGeometry) + .handleIssueList { issueList += it } IdentifierAdder.addIdentifier( id.deriveLeftLaneBoundaryGmlIdentifier(parameters.gmlIdPrefix), "LeftLaneBoundary", - genericLogicalSpace + genericLogicalSpace, ) attributesAdder.addAttributes( id.toAttributes(parameters.identifierAttributesPrefix), - genericLogicalSpace + genericLogicalSpace, ) return ContextIssueList(genericLogicalSpace, issueList) @@ -191,20 +191,21 @@ class GenericsModuleBuilder( fun createRightLaneBoundary( id: LaneIdentifier, - abstractGeometry: AbstractGeometry3D + abstractGeometry: AbstractGeometry3D, ): ContextIssueList { val issueList = DefaultIssueList() - val genericLogicalSpace = createLogicalOccupiedSpaceFeature(id, abstractGeometry) - .handleIssueList { issueList += it } + val genericLogicalSpace = + createLogicalOccupiedSpaceFeature(id, abstractGeometry) + .handleIssueList { issueList += it } IdentifierAdder.addIdentifier( id.deriveRightLaneBoundaryGmlIdentifier(parameters.gmlIdPrefix), "RightLaneBoundary", - genericLogicalSpace + genericLogicalSpace, ) attributesAdder.addAttributes( id.toAttributes(parameters.identifierAttributesPrefix), - genericLogicalSpace + genericLogicalSpace, ) return ContextIssueList(genericLogicalSpace, issueList) @@ -212,24 +213,22 @@ class GenericsModuleBuilder( private fun createLogicalOccupiedSpaceFeature( id: AbstractRoadspacesIdentifier, - abstractGeometry: AbstractGeometry3D - ): - ContextIssueList { + abstractGeometry: AbstractGeometry3D, + ): ContextIssueList { val issueList = DefaultIssueList() val genericLogicalSpaceFeature = GenericLogicalSpace() - val geometryTransformer = GeometryTransformer(parameters) - .also { abstractGeometry.accept(it) } + val geometryTransformer = + GeometryTransformer(parameters) + .also { abstractGeometry.accept(it) } // geometry genericLogicalSpaceFeature.populateLod2Geometry(geometryTransformer) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForLogicalOccupiedSpaceFeatureLod2", - it.message, - id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForLogicalOccupiedSpaceFeatureLod2", + it.message, id, Severity.WARNING, wasFixed = true, + ) } return ContextIssueList(genericLogicalSpaceFeature, issueList) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/IdentifierAdder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/IdentifierAdder.kt index 1b21fba6..1da32622 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/IdentifierAdder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/IdentifierAdder.kt @@ -24,16 +24,22 @@ import org.xmlobjects.gml.model.basictypes.Code * Adds object identifiers from the RoadSpaces model to an [AbstractCityObject] (CityGML model). */ object IdentifierAdder { - // Methods /** Adds the [gmlId] to the [dstCityObject]. */ - fun addIdentifier(gmlId: String, dstCityObject: AbstractCityObject) { + fun addIdentifier( + gmlId: String, + dstCityObject: AbstractCityObject, + ) { dstCityObject.id = gmlId } /** Adds the [gmlId] and optionally the [name] to the [dstCityObject]. */ - fun addIdentifier(gmlId: String, name: Option, dstCityObject: AbstractCityObject) { + fun addIdentifier( + gmlId: String, + name: Option, + dstCityObject: AbstractCityObject, + ) { dstCityObject.id = gmlId name.onSome { dstCityObject.names = listOf(Code(it)) @@ -41,7 +47,11 @@ object IdentifierAdder { } /** Adds the [gmlId] and the [name] to the [dstCityObject]. */ - fun addIdentifier(gmlId: String, name: String, dstCityObject: AbstractCityObject) { + fun addIdentifier( + gmlId: String, + name: String, + dstCityObject: AbstractCityObject, + ) { dstCityObject.id = gmlId dstCityObject.names = listOf(Code(name)) } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/RelationAdder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/RelationAdder.kt index 076bb09b..b4a0de96 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/RelationAdder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/RelationAdder.kt @@ -34,31 +34,47 @@ import org.xmlobjects.gml.model.basictypes.Code * Adds relations to and from an object to an [AbstractCityObject] (CityGML model). */ class RelationAdder( - private val parameters: Roadspaces2CitygmlParameters + private val parameters: Roadspaces2CitygmlParameters, ) { // Properties and Initializers private val attributesAdder = AttributesAdder(parameters) // Methods - fun addRelatedToRelation(roadspaceObject: RoadspaceObject, dstTrafficSpace: TrafficSpace) { - val relationType = "related" + when (RoadspaceObjectRouter.route(roadspaceObject)) { - RoadspaceObjectRouter.CitygmlTargetFeatureType.BUILDING_BUILDING -> "Building" - RoadspaceObjectRouter.CitygmlTargetFeatureType.CITYFURNITURE_CITYFURNITURE -> "Furniture" - RoadspaceObjectRouter.CitygmlTargetFeatureType.GENERICS_GENERICOCCUPIEDSPACE -> "OccupiedSpace" - RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_TRAFFICSPACE -> return - RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_AUXILIARYTRAFFICSPACE -> return - RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_MARKING -> return - RoadspaceObjectRouter.CitygmlTargetFeatureType.VEGETATION_SOLITARYVEGETATIONOBJECT -> "Vegetation" - } + fun addRelatedToRelation( + roadspaceObject: RoadspaceObject, + dstTrafficSpace: TrafficSpace, + ) { + val relationType = + "related" + + when (RoadspaceObjectRouter.route(roadspaceObject)) { + RoadspaceObjectRouter.CitygmlTargetFeatureType.BUILDING_BUILDING -> "Building" + RoadspaceObjectRouter.CitygmlTargetFeatureType.CITYFURNITURE_CITYFURNITURE -> "Furniture" + RoadspaceObjectRouter.CitygmlTargetFeatureType.GENERICS_GENERICOCCUPIEDSPACE -> "OccupiedSpace" + RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_TRAFFICSPACE -> return + RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_AUXILIARYTRAFFICSPACE -> return + RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_MARKING -> return + RoadspaceObjectRouter.CitygmlTargetFeatureType.VEGETATION_SOLITARYVEGETATIONOBJECT -> "Vegetation" + } - val relation = createCityObjectRelation(roadspaceObject.id.deriveGmlIdentifier(parameters.gmlIdPrefix), relationType, roadspaceObject.id) + val relation = + createCityObjectRelation(roadspaceObject.id.deriveGmlIdentifier(parameters.gmlIdPrefix), relationType, roadspaceObject.id) dstTrafficSpace.relatedTo.add(relation) } - fun addBelongToRelations(roadspaceObject: RoadspaceObject, dstCityObject: AbstractCityObject) { - val relations = roadspaceObject.laneRelations - .flatMap { it.getAllLeftRightLaneIdentifiers() } - .map { createCityObjectRelation(it.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier(parameters.gmlIdPrefix), "belongsTo", it) } + fun addBelongToRelations( + roadspaceObject: RoadspaceObject, + dstCityObject: AbstractCityObject, + ) { + val relations = + roadspaceObject.laneRelations + .flatMap { it.getAllLeftRightLaneIdentifiers() } + .map { + createCityObjectRelation( + it.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier(parameters.gmlIdPrefix), + "belongsTo", + it, + ) + } dstCityObject.relatedTo.addAll(relations) } @@ -66,18 +82,27 @@ class RelationAdder( /** * Adds a lane change relation to the [dstTrafficSpace] object */ - fun addLaneChangeRelation(lane: Lane, direction: RoadSide, dstTrafficSpace: TrafficSpace) { + fun addLaneChangeRelation( + lane: Lane, + direction: RoadSide, + dstTrafficSpace: TrafficSpace, + ) { val gmlId = lane.id.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier(parameters.gmlIdPrefix) - val relationType = when (direction) { - RoadSide.LEFT -> "leftLaneChange" - RoadSide.RIGHT -> "rightLaneChange" - RoadSide.CENTER -> throw IllegalArgumentException("Direction of a laneChange relation must not be center.") - } + val relationType = + when (direction) { + RoadSide.LEFT -> "leftLaneChange" + RoadSide.RIGHT -> "rightLaneChange" + RoadSide.CENTER -> throw IllegalArgumentException("Direction of a laneChange relation must not be center.") + } val relation: CityObjectRelationProperty = createCityObjectRelation(gmlId, relationType, lane.id) dstTrafficSpace.relatedTo.add(relation) } - private fun createCityObjectRelation(gmlId: String, type: String, id: AbstractRoadspacesIdentifier): CityObjectRelationProperty { + private fun createCityObjectRelation( + gmlId: String, + type: String, + id: AbstractRoadspacesIdentifier, + ): CityObjectRelationProperty { val relation = CityObjectRelation(parameters.xlinkPrefix + gmlId) relation.relationType = Code(type) attributesAdder.addAttributes(id, relation) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/TransportationModuleBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/TransportationModuleBuilder.kt index 99eb718e..de0e6610 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/TransportationModuleBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/TransportationModuleBuilder.kt @@ -60,16 +60,17 @@ import org.citygml4j.core.model.transportation.TrafficSpaceProperty enum class TransportationGranularityValue { LANE, WAY } -fun TransportationGranularityValue.toGmlGranularityValue(): GranularityValue = when (this) { - TransportationGranularityValue.LANE -> GranularityValue.LANE - TransportationGranularityValue.WAY -> GranularityValue.WAY -} +fun TransportationGranularityValue.toGmlGranularityValue(): GranularityValue = + when (this) { + TransportationGranularityValue.LANE -> GranularityValue.LANE + TransportationGranularityValue.WAY -> GranularityValue.WAY + } /** * Builder for city objects of the CityGML Transportation module. */ class TransportationModuleBuilder( - val parameters: Roadspaces2CitygmlParameters + val parameters: Roadspaces2CitygmlParameters, ) { // Properties and Initializers private val relationAdder = RelationAdder(parameters) @@ -77,8 +78,11 @@ class TransportationModuleBuilder( // Methods fun createRoad() = Road() + fun createSection() = Section() + fun createIntersection() = Intersection() + fun createMarking() = Marking() /** @@ -92,7 +96,7 @@ class TransportationModuleBuilder( lateralFillerSurface: Option, longitudinalFillerSurfaces: List, relatedObjects: List, - dstTransportationSpace: AbstractTransportationSpace + dstTransportationSpace: AbstractTransportationSpace, ): DefaultIssueList { val issueList = DefaultIssueList() @@ -100,7 +104,7 @@ class TransportationModuleBuilder( // semantics IdentifierAdder.addIdentifier( lane.id.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier(parameters.gmlIdPrefix), - trafficSpaceFeature + trafficSpaceFeature, ) trafficSpaceFeature.usages = CodeAdder.mapToTrafficAreaUsageCodes(lane.type).map { it.code } trafficSpaceFeature.functions = CodeAdder.mapToTrafficAreaFunctionCodes(lane.type).map { it.code } @@ -118,7 +122,7 @@ class TransportationModuleBuilder( IdentifierAdder.addIdentifier( lane.id.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier(parameters.gmlIdPrefix), "Lane", - trafficAreaFeature + trafficAreaFeature, ) trafficAreaFeature.usages = CodeAdder.mapToTrafficAreaUsageCodes(lane.type).map { it.code } trafficAreaFeature.functions = CodeAdder.mapToTrafficAreaFunctionCodes(lane.type).map { it.code } @@ -129,17 +133,18 @@ class TransportationModuleBuilder( // filler surface features lateralFillerSurface.onSome { fillerSurface -> - val fillerTrafficArea = createTrafficAreaFeature( - fillerSurface.id, - fillerSurface.surface - ).handleIssueList { issueList += it } + val fillerTrafficArea = + createTrafficAreaFeature( + fillerSurface.id, + fillerSurface.surface, + ).handleIssueList { issueList += it } IdentifierAdder.addIdentifier( fillerSurface.id.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier( - parameters.gmlIdPrefix + parameters.gmlIdPrefix, ), "LateralFillerSurface", - fillerTrafficArea + fillerTrafficArea, ) attributesAdder.addAttributes(fillerSurface, fillerTrafficArea) trafficSpaceFeature.addBoundary(AbstractSpaceBoundaryProperty(fillerTrafficArea)) @@ -150,10 +155,10 @@ class TransportationModuleBuilder( IdentifierAdder.addIdentifier( fillerSurface.id.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier( - parameters.gmlIdPrefix + parameters.gmlIdPrefix, ), "LongitudinalFillerSurface", - fillerTrafficArea + fillerTrafficArea, ) attributesAdder.addAttributes(fillerSurface, fillerTrafficArea) trafficSpaceFeature.addBoundary(AbstractSpaceBoundaryProperty(fillerTrafficArea)) @@ -176,7 +181,7 @@ class TransportationModuleBuilder( centerLine: AbstractCurve3D, lateralFillerSurface: Option, longitudinalFillerSurfaces: List, - dstTransportationSpace: AbstractTransportationSpace + dstTransportationSpace: AbstractTransportationSpace, ): DefaultIssueList { val issueList = DefaultIssueList() @@ -184,7 +189,7 @@ class TransportationModuleBuilder( // semantics IdentifierAdder.addIdentifier( lane.id.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier(parameters.gmlIdPrefix), - auxiliaryTrafficSpaceFeature + auxiliaryTrafficSpaceFeature, ) auxiliaryTrafficSpaceFeature.functions = CodeAdder.mapToAuxiliaryTrafficAreaFunctionCodes(lane.type).map { it.code } @@ -194,12 +199,13 @@ class TransportationModuleBuilder( auxiliaryTrafficSpaceFeature.populateLod2Geometry(centerLineGeometryTransformer) // auxiliary traffic area feature - val auxiliaryTrafficAreaFeature = createAuxiliaryTrafficAreaFeature(lane.id, surface) - .handleIssueList { issueList += it } + val auxiliaryTrafficAreaFeature = + createAuxiliaryTrafficAreaFeature(lane.id, surface) + .handleIssueList { issueList += it } IdentifierAdder.addIdentifier( lane.id.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier(parameters.gmlIdPrefix), "Lane", - auxiliaryTrafficAreaFeature + auxiliaryTrafficAreaFeature, ) auxiliaryTrafficAreaFeature.functions = CodeAdder.mapToAuxiliaryTrafficAreaFunctionCodes(lane.type).map { it.code } @@ -210,31 +216,33 @@ class TransportationModuleBuilder( // filler surface features lateralFillerSurface.onSome { fillerSurface -> - val fillerAuxiliaryTrafficArea = createAuxiliaryTrafficAreaFeature( - fillerSurface.id, - fillerSurface.surface - ).handleIssueList { issueList += it } + val fillerAuxiliaryTrafficArea = + createAuxiliaryTrafficAreaFeature( + fillerSurface.id, + fillerSurface.surface, + ).handleIssueList { issueList += it } IdentifierAdder.addIdentifier( fillerSurface.id.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier( - parameters.gmlIdPrefix + parameters.gmlIdPrefix, ), "LateralFillerSurface", - fillerAuxiliaryTrafficArea + fillerAuxiliaryTrafficArea, ) attributesAdder.addAttributes(fillerSurface, fillerAuxiliaryTrafficArea) auxiliaryTrafficSpaceFeature.addBoundary(AbstractSpaceBoundaryProperty(fillerAuxiliaryTrafficArea)) } longitudinalFillerSurfaces.forEach { fillerSurface -> - val fillerAuxiliaryTrafficArea = createAuxiliaryTrafficAreaFeature(lane.id, fillerSurface.surface) - .handleIssueList { issueList += it } + val fillerAuxiliaryTrafficArea = + createAuxiliaryTrafficAreaFeature(lane.id, fillerSurface.surface) + .handleIssueList { issueList += it } IdentifierAdder.addIdentifier( fillerSurface.id.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier( - parameters.gmlIdPrefix + parameters.gmlIdPrefix, ), "LongitudinalFillerSurface", - fillerAuxiliaryTrafficArea + fillerAuxiliaryTrafficArea, ) attributesAdder.addAttributes(fillerSurface, fillerAuxiliaryTrafficArea) auxiliaryTrafficSpaceFeature.addBoundary(AbstractSpaceBoundaryProperty(fillerAuxiliaryTrafficArea)) @@ -249,16 +257,16 @@ class TransportationModuleBuilder( fun addTrafficSpaceFeature( roadspaceObject: RoadspaceObject, - dstTransportationSpace: AbstractTransportationSpace + dstTransportationSpace: AbstractTransportationSpace, ): DefaultIssueList { val issueList = DefaultIssueList() val trafficSpaceFeature = createTrafficSpaceFeature(TransportationGranularityValue.LANE) IdentifierAdder.addIdentifier( roadspaceObject.id.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier( - parameters.gmlIdPrefix + parameters.gmlIdPrefix, ), - trafficSpaceFeature + trafficSpaceFeature, ) trafficSpaceFeature.usages = CodeAdder.mapToTrafficAreaUsageCodes(roadspaceObject.type).map { it.code } trafficSpaceFeature.functions = CodeAdder.mapToTrafficAreaFunctionCodes(roadspaceObject.type).map { it.code } @@ -270,9 +278,9 @@ class TransportationModuleBuilder( // semantics IdentifierAdder.addIdentifier( roadspaceObject.id.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier( - parameters.gmlIdPrefix + parameters.gmlIdPrefix, ), - trafficAreaFeature + trafficAreaFeature, ) trafficAreaFeature.usages = CodeAdder.mapToTrafficAreaUsageCodes(roadspaceObject.type).map { it.code } trafficAreaFeature.functions = CodeAdder.mapToTrafficAreaFunctionCodes(roadspaceObject.type).map { it.code } @@ -283,13 +291,11 @@ class TransportationModuleBuilder( val solidFaceSelection = listOf(GeometryTransformer.FaceType.TOP, GeometryTransformer.FaceType.SIDE) trafficAreaFeature.populateLod2MultiSurfaceFromSolidCutoutOrSurface(geometryTransformer, solidFaceSelection) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForTrafficAreaLod2", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForTrafficAreaLod2", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } trafficSpaceFeature.addBoundary(AbstractSpaceBoundaryProperty(trafficAreaFeature)) @@ -304,16 +310,16 @@ class TransportationModuleBuilder( fun addAuxiliaryTrafficSpaceFeature( roadspaceObject: RoadspaceObject, - dstTransportationSpace: AbstractTransportationSpace + dstTransportationSpace: AbstractTransportationSpace, ): DefaultIssueList { val issueList = DefaultIssueList() val auxiliaryTrafficSpaceFeature = createAuxiliaryTrafficSpaceFeature(TransportationGranularityValue.LANE) IdentifierAdder.addIdentifier( roadspaceObject.id.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier( - parameters.gmlIdPrefix + parameters.gmlIdPrefix, ), - auxiliaryTrafficSpaceFeature + auxiliaryTrafficSpaceFeature, ) auxiliaryTrafficSpaceFeature.functions = CodeAdder.mapToAuxiliaryTrafficAreaFunctionCodes(roadspaceObject.type).map { it.code } @@ -324,9 +330,9 @@ class TransportationModuleBuilder( // semantics IdentifierAdder.addIdentifier( roadspaceObject.id.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier( - parameters.gmlIdPrefix + parameters.gmlIdPrefix, ), - auxiliaryTrafficAreaFeature + auxiliaryTrafficAreaFeature, ) auxiliaryTrafficAreaFeature.functions = CodeAdder.mapToAuxiliaryTrafficAreaFunctionCodes(roadspaceObject.type).map { it.code } @@ -337,16 +343,14 @@ class TransportationModuleBuilder( val solidFaceSelection = listOf(GeometryTransformer.FaceType.TOP, GeometryTransformer.FaceType.SIDE) auxiliaryTrafficAreaFeature.populateLod2MultiSurfaceFromSolidCutoutOrSurface( geometryTransformer, - solidFaceSelection + solidFaceSelection, ) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForAuxiliaryTrafficAreaLod2", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForAuxiliaryTrafficAreaLod2", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } auxiliaryTrafficSpaceFeature.addBoundary(AbstractSpaceBoundaryProperty(auxiliaryTrafficAreaFeature)) @@ -364,7 +368,7 @@ class TransportationModuleBuilder( roadMarkingIndex: Int, roadMarking: RoadMarking, geometry: AbstractGeometry3D, - dstTransportationSpace: AbstractTransportationSpace + dstTransportationSpace: AbstractTransportationSpace, ): DefaultIssueList { val issueList = DefaultIssueList() val markingFeature = if (parameters.mappingBackwardsCompatibility) AuxiliaryTrafficArea() else createMarking() @@ -373,20 +377,18 @@ class TransportationModuleBuilder( val geometryTransformer = GeometryTransformer(parameters).also { geometry.accept(it) } markingFeature.populateLod2MultiSurfaceOrLod0Geometry(geometryTransformer) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForMarkingLod2", - it.message, - id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForMarkingLod2", + it.message, id, Severity.WARNING, wasFixed = true, + ) } // semantics IdentifierAdder.addIdentifier( id.deriveRoadMarkingGmlIdentifier(parameters.gmlIdPrefix, roadMarkingIndex), "RoadMarking", - markingFeature + markingFeature, ) attributesAdder.addAttributes(id, roadMarking, markingFeature) @@ -397,7 +399,7 @@ class TransportationModuleBuilder( fun addMarkingFeature( roadspaceObject: RoadspaceObject, - dstTransportationSpace: AbstractTransportationSpace + dstTransportationSpace: AbstractTransportationSpace, ): DefaultIssueList { val issueList = DefaultIssueList() val markingFeature = if (parameters.mappingBackwardsCompatibility) AuxiliaryTrafficArea() else createMarking() @@ -407,13 +409,11 @@ class TransportationModuleBuilder( val geometryTransformer = GeometryTransformer.of(currentComplexGeometry, parameters) markingFeature.populateLod2MultiSurfaceOrLod0Geometry(geometryTransformer) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForMarkingLod2", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForMarkingLod2", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } } @@ -440,23 +440,22 @@ class TransportationModuleBuilder( private fun createTrafficAreaFeature( id: AbstractRoadspacesIdentifier, - abstractGeometry: AbstractGeometry3D + abstractGeometry: AbstractGeometry3D, ): ContextIssueList { val issueList = DefaultIssueList() val trafficAreaFeature = TrafficArea() - val geometryTransformer = GeometryTransformer(parameters) - .also { abstractGeometry.accept(it) } + val geometryTransformer = + GeometryTransformer(parameters) + .also { abstractGeometry.accept(it) } val solidFaceSelection = listOf(GeometryTransformer.FaceType.TOP, GeometryTransformer.FaceType.SIDE) trafficAreaFeature.populateLod2MultiSurfaceFromSolidCutoutOrSurface(geometryTransformer, solidFaceSelection) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForTrafficAreaLod2", - it.message, - id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForTrafficAreaLod2", + it.message, id, Severity.WARNING, wasFixed = true, + ) } return ContextIssueList(trafficAreaFeature, issueList) @@ -464,27 +463,26 @@ class TransportationModuleBuilder( private fun createAuxiliaryTrafficAreaFeature( id: AbstractRoadspacesIdentifier, - abstractGeometry: AbstractGeometry3D + abstractGeometry: AbstractGeometry3D, ): ContextIssueList { val issueList = DefaultIssueList() val auxiliaryTrafficAreaFeature = AuxiliaryTrafficArea() - val geometryTransformer = GeometryTransformer(parameters) - .also { abstractGeometry.accept(it) } + val geometryTransformer = + GeometryTransformer(parameters) + .also { abstractGeometry.accept(it) } val solidFaceSelection = listOf(GeometryTransformer.FaceType.TOP, GeometryTransformer.FaceType.SIDE) auxiliaryTrafficAreaFeature.populateLod2MultiSurfaceFromSolidCutoutOrSurface( geometryTransformer, - solidFaceSelection + solidFaceSelection, ) .onLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForAuxiliaryTrafficAreaLod2", - it.message, - id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForAuxiliaryTrafficAreaLod2", + it.message, id, Severity.WARNING, wasFixed = true, + ) } return ContextIssueList(auxiliaryTrafficAreaFeature, issueList) @@ -495,7 +493,7 @@ class TransportationModuleBuilder( */ private fun addMarkingFeature( markingFeature: AbstractThematicSurface, - dstTransportationSpace: AbstractTransportationSpace + dstTransportationSpace: AbstractTransportationSpace, ) { when (markingFeature) { is Marking -> { diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/VegetationModuleBuilder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/VegetationModuleBuilder.kt index 5afd28a7..b92eacf9 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/VegetationModuleBuilder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/module/VegetationModuleBuilder.kt @@ -39,7 +39,7 @@ import org.xmlobjects.gml.model.measures.Length * Builder for city objects of the CityGML Vegetation module. */ class VegetationModuleBuilder( - private val parameters: Roadspaces2CitygmlParameters + private val parameters: Roadspaces2CitygmlParameters, ) { // Properties and Initializers private val relationAdder = RelationAdder(parameters) @@ -63,13 +63,11 @@ class VegetationModuleBuilder( val geometryTransformer = GeometryTransformer.of(currentBoundingBoxGeometry, parameters) solitaryVegetationObjectFeature.populateLod1Geometry(geometryTransformer) .mapLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForSolitaryVegetationObjectLod1", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForSolitaryVegetationObjectLod1", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } addAttributes(solitaryVegetationObjectFeature, geometryTransformer).getOrElse { throw it } @@ -79,20 +77,18 @@ class VegetationModuleBuilder( val geometryTransformer = GeometryTransformer.of(currentComplexGeometry, parameters) solitaryVegetationObjectFeature.populateLod2Geometry(geometryTransformer) .mapLeft { - issueList += DefaultIssue.of( - "NoSuitableGeometryForSolitaryVegetationObjectLod2", - it.message, - roadspaceObject.id, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "NoSuitableGeometryForSolitaryVegetationObjectLod2", + it.message, roadspaceObject.id, Severity.WARNING, wasFixed = true, + ) } } // semantics IdentifierAdder.addIdentifier( roadspaceObject.id.deriveGmlIdentifier(parameters.gmlIdPrefix), - solitaryVegetationObjectFeature + solitaryVegetationObjectFeature, ) relationAdder.addBelongToRelations(roadspaceObject, solitaryVegetationObjectFeature) attributesAdder.addAttributes(roadspaceObject, solitaryVegetationObjectFeature) @@ -102,18 +98,19 @@ class VegetationModuleBuilder( private fun addAttributes( solitaryVegetationObjectFeature: SolitaryVegetationObject, - geometryTransformer: GeometryTransformer - ): Either = either { - geometryTransformer.diameter.onSome { - solitaryVegetationObjectFeature.trunkDiameter = Length(it) - solitaryVegetationObjectFeature.trunkDiameter.uom = UnitOfMeasure.METER.toGmlString() - } + geometryTransformer: GeometryTransformer, + ): Either = + either { + geometryTransformer.diameter.onSome { + solitaryVegetationObjectFeature.trunkDiameter = Length(it) + solitaryVegetationObjectFeature.trunkDiameter.uom = UnitOfMeasure.METER.toGmlString() + } - geometryTransformer.height.onSome { - solitaryVegetationObjectFeature.height = Length(it) - solitaryVegetationObjectFeature.height.uom = UnitOfMeasure.METER.toGmlString() - } + geometryTransformer.height.onSome { + solitaryVegetationObjectFeature.height = Length(it) + solitaryVegetationObjectFeature.height.uom = UnitOfMeasure.METER.toGmlString() + } - Unit - } + Unit + } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/report/Roadspaces2CitygmlReport.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/report/Roadspaces2CitygmlReport.kt index b2defaa9..3d11b365 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/report/Roadspaces2CitygmlReport.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/report/Roadspaces2CitygmlReport.kt @@ -24,10 +24,8 @@ import kotlinx.serialization.Serializable @Serializable data class Roadspaces2CitygmlReport( val parameters: Roadspaces2CitygmlParameters, - - val conversion: DefaultIssueList = DefaultIssueList() + val conversion: DefaultIssueList = DefaultIssueList(), ) { - // Methods fun getTextSummary(): String = conversion.getTextSummary() } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/router/LaneRouter.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/router/LaneRouter.kt index 51c45f37..5b93d197 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/router/LaneRouter.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/router/LaneRouter.kt @@ -23,10 +23,9 @@ import io.rtron.model.roadspaces.roadspace.road.LaneType * Feature router of [Lane] (RoadSpace model) to the [CitygmlTargetFeatureType] (CityGML model). */ object LaneRouter { - enum class CitygmlTargetFeatureType { TRANSPORTATION_TRAFFICSPACE, - TRANSPORTATION_AUXILIARYTRAFFICSPACE + TRANSPORTATION_AUXILIARYTRAFFICSPACE, } /** diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/router/RoadspaceObjectRouter.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/router/RoadspaceObjectRouter.kt index 323bbabd..556c54fd 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/router/RoadspaceObjectRouter.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/router/RoadspaceObjectRouter.kt @@ -24,7 +24,6 @@ import io.rtron.transformer.converter.roadspaces2citygml.router.RoadspaceObjectR * Feature router of [RoadspaceObject] (RoadSpace model) to the [CitygmlTargetFeatureType] (CityGML model). */ object RoadspaceObjectRouter { - enum class CitygmlTargetFeatureType { BUILDING_BUILDING, CITYFURNITURE_CITYFURNITURE, @@ -32,7 +31,7 @@ object RoadspaceObjectRouter { TRANSPORTATION_TRAFFICSPACE, TRANSPORTATION_AUXILIARYTRAFFICSPACE, TRANSPORTATION_MARKING, - VEGETATION_SOLITARYVEGETATIONOBJECT + VEGETATION_SOLITARYVEGETATIONOBJECT, } /** diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/IdentifierTransformer.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/IdentifierTransformer.kt index 391e06a2..33b06772 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/IdentifierTransformer.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/IdentifierTransformer.kt @@ -22,10 +22,9 @@ import io.rtron.model.roadspaces.identifier.LateralLaneRangeIdentifier import io.rtron.model.roadspaces.identifier.LongitudinalLaneRangeIdentifier import io.rtron.model.roadspaces.identifier.RoadspaceIdentifier import io.rtron.model.roadspaces.identifier.RoadspaceObjectIdentifier -import java.util.* +import java.util.UUID -fun RoadspaceObjectIdentifier.deriveGmlIdentifier(prefix: String): String = - generateGmlIdentifier(prefix, this.hashKey) +fun RoadspaceObjectIdentifier.deriveGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, this.hashKey) fun RoadspaceObjectIdentifier.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "TrafficSpaceOrAuxiliaryTrafficSpace_${this.hashKey}") @@ -39,8 +38,10 @@ fun RoadspaceObjectIdentifier.deriveLod2RoofGmlIdentifier(prefix: String): Strin fun RoadspaceObjectIdentifier.deriveLod2GroundGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "Lod2GroundSurface_${this.hashKey}") -fun RoadspaceObjectIdentifier.deriveLod2WallGmlIdentifier(prefix: String, wallIndex: Int): String = - generateGmlIdentifier(prefix, "Lod2WallSurface_${wallIndex}_${this.hashKey}") +fun RoadspaceObjectIdentifier.deriveLod2WallGmlIdentifier( + prefix: String, + wallIndex: Int, +): String = generateGmlIdentifier(prefix, "Lod2WallSurface_${wallIndex}_${this.hashKey}") fun JunctionIdentifier.deriveIntersectionGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "Intersection_${this.hashKey}") @@ -51,8 +52,10 @@ fun LaneIdentifier.deriveTrafficSpaceOrAuxiliaryTrafficSpaceGmlIdentifier(prefix fun LaneIdentifier.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "TrafficAreaOrAuxiliaryTrafficArea_${this.hashKey}") -fun LaneIdentifier.deriveRoadMarkingGmlIdentifier(prefix: String, roadMarkingIndex: Int): String = - generateGmlIdentifier(prefix, "RoadMarking_${roadMarkingIndex}_${this.hashKey}") +fun LaneIdentifier.deriveRoadMarkingGmlIdentifier( + prefix: String, + roadMarkingIndex: Int, +): String = generateGmlIdentifier(prefix, "RoadMarking_${roadMarkingIndex}_${this.hashKey}") fun LateralLaneRangeIdentifier.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "LateralFillerSurface_${this.hashKey}") @@ -60,11 +63,11 @@ fun LateralLaneRangeIdentifier.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentif fun LongitudinalLaneRangeIdentifier.deriveTrafficAreaOrAuxiliaryTrafficAreaGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "LongitudinalFillerSurface_${this.hashKey}") -fun RoadspaceIdentifier.deriveSectionGmlIdentifier(prefix: String): String = - generateGmlIdentifier(prefix, "Section_${this.hashKey}") +fun RoadspaceIdentifier.deriveSectionGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "Section_${this.hashKey}") fun RoadspaceIdentifier.deriveRoadReferenceLineGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "RoadReferenceLine_${this.hashKey}") + fun LaneIdentifier.deriveRoadCenterLaneLineGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "RoadCenterLaneLine_${this.hashKey}") @@ -77,10 +80,15 @@ fun LaneIdentifier.deriveLeftLaneBoundaryGmlIdentifier(prefix: String): String = fun LaneIdentifier.deriveRightLaneBoundaryGmlIdentifier(prefix: String): String = generateGmlIdentifier(prefix, "RightLaneBoundary_${this.hashKey}") -fun generateRoadIdentifier(roadName: String, prefix: String): String = - generateGmlIdentifier(prefix, "Road_$roadName") +fun generateRoadIdentifier( + roadName: String, + prefix: String, +): String = generateGmlIdentifier(prefix, "Road_$roadName") -private fun generateGmlIdentifier(prefix: String, hashKey: String): String { +private fun generateGmlIdentifier( + prefix: String, + hashKey: String, +): String { val uuid = UUID.nameUUIDFromBytes(hashKey.toByteArray()).toString() return prefix + uuid } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/RoadsTransformer.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/RoadsTransformer.kt index 503702af..61af9543 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/RoadsTransformer.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/RoadsTransformer.kt @@ -52,16 +52,18 @@ import org.citygml4j.core.model.transportation.Road as CitygmlRoad * Transforms [Road] classes (RoadSpaces model) to the [CityModel] (CityGML model). */ class RoadsTransformer( - private val parameters: Roadspaces2CitygmlParameters + private val parameters: Roadspaces2CitygmlParameters, ) { - // Properties and Initializers private val genericsModuleBuilder = GenericsModuleBuilder(parameters) private val transportationModuleBuilder = TransportationModuleBuilder(parameters) // Methods - fun transformRoad(roadspaceName: String, roadspacesModel: RoadspacesModel): ContextIssueList> { + fun transformRoad( + roadspaceName: String, + roadspacesModel: RoadspacesModel, + ): ContextIssueList> { val issueList = DefaultIssueList() val roadFeature = transportationModuleBuilder.createRoad() @@ -83,12 +85,18 @@ class RoadsTransformer( return ContextIssueList(Some(roadFeature), issueList) } - private fun addIntersectionOrLink(junctionId: JunctionIdentifier, roadspaceName: String, roadspacesModel: RoadspacesModel, dstRoad: CitygmlRoad): DefaultIssueList { + private fun addIntersectionOrLink( + junctionId: JunctionIdentifier, + roadspaceName: String, + roadspacesModel: RoadspacesModel, + dstRoad: CitygmlRoad, + ): DefaultIssueList { val issueList = DefaultIssueList() - val roadspacesInJunction = roadspacesModel.getRoadspacesWithinJunction(junctionId) - .getOrElse { throw it } - .sortedBy { it.name } + val roadspacesInJunction = + roadspacesModel.getRoadspacesWithinJunction(junctionId) + .getOrElse { throw it } + .sortedBy { it.name } if (roadspacesInJunction.first().name == roadspaceName && parameters.mappingBackwardsCompatibility) { roadspacesInJunction.forEach { @@ -108,7 +116,11 @@ class RoadsTransformer( return issueList } - private fun addSection(roadspaceId: RoadspaceIdentifier, roadspacesModel: RoadspacesModel, dstRoad: CitygmlRoad): DefaultIssueList { + private fun addSection( + roadspaceId: RoadspaceIdentifier, + roadspacesModel: RoadspacesModel, + dstRoad: CitygmlRoad, + ): DefaultIssueList { val issueList = DefaultIssueList() val roadspace = roadspacesModel.getRoadspace(roadspaceId).getOrElse { throw it } @@ -129,35 +141,46 @@ class RoadsTransformer( val issueList = DefaultIssueList() // transforms the road reference line - val roadReferenceLine = genericsModuleBuilder - .createRoadReferenceLine(roadspace.id, roadspace.referenceLine, roadspace.attributes) - .handleIssueList { issueList += it } + val roadReferenceLine = + genericsModuleBuilder + .createRoadReferenceLine(roadspace.id, roadspace.referenceLine, roadspace.attributes) + .handleIssueList { issueList += it } // transforms the lines of the center lane (id=0) - val roadCenterLaneLines = roadspace.road.getAllCenterLanes() - .map { genericsModuleBuilder.createRoadCenterLaneLine(it.first, it.second, it.third) } - .mergeIssueLists() - .handleIssueList { issueList += it } + val roadCenterLaneLines = + roadspace.road.getAllCenterLanes() + .map { genericsModuleBuilder.createRoadCenterLaneLine(it.first, it.second, it.third) } + .mergeIssueLists() + .handleIssueList { issueList += it } // transforms lane boundaries and center lines of the lanes - val leftLaneBoundaries = roadspace.road.getAllLeftLaneBoundaries() - .map { genericsModuleBuilder.createLeftLaneBoundary(it.first, it.second) } - .mergeIssueLists() - .handleIssueList { issueList += it } - val rightLaneBoundaries = roadspace.road.getAllRightLaneBoundaries() - .map { genericsModuleBuilder.createRightLaneBoundary(it.first, it.second) } - .mergeIssueLists() - .handleIssueList { issueList += it } - val laneCenterLines = roadspace.road.getAllCurvesOnLanes(0.5) - .map { genericsModuleBuilder.createCenterLaneLine(it.first, it.second) } - .mergeIssueLists() - .handleIssueList { issueList += it } - - val additionalRoadLines = listOf(roadReferenceLine) + roadCenterLaneLines + leftLaneBoundaries + rightLaneBoundaries + laneCenterLines + val leftLaneBoundaries = + roadspace.road.getAllLeftLaneBoundaries() + .map { genericsModuleBuilder.createLeftLaneBoundary(it.first, it.second) } + .mergeIssueLists() + .handleIssueList { issueList += it } + val rightLaneBoundaries = + roadspace.road.getAllRightLaneBoundaries() + .map { genericsModuleBuilder.createRightLaneBoundary(it.first, it.second) } + .mergeIssueLists() + .handleIssueList { issueList += it } + val laneCenterLines = + roadspace.road.getAllCurvesOnLanes(0.5) + .map { genericsModuleBuilder.createCenterLaneLine(it.first, it.second) } + .mergeIssueLists() + .handleIssueList { issueList += it } + + val additionalRoadLines = + listOf(roadReferenceLine) + roadCenterLaneLines + leftLaneBoundaries + + rightLaneBoundaries + laneCenterLines return ContextIssueList(additionalRoadLines, issueList) } - private fun addRoadspace(roadspace: Roadspace, roadspacesModel: RoadspacesModel, dstTransportationSpace: AbstractTransportationSpace): DefaultIssueList { + private fun addRoadspace( + roadspace: Roadspace, + roadspacesModel: RoadspacesModel, + dstTransportationSpace: AbstractTransportationSpace, + ): DefaultIssueList { val issueList = DefaultIssueList() roadspace.road.getAllLeftRightLaneIdentifiers().forEach { laneId -> @@ -179,31 +202,79 @@ class RoadsTransformer( return issueList } - private fun addSingleLane(id: LaneIdentifier, road: Road, longitudinalFillerSurfaces: List, relatedObjects: List, dstTransportationSpace: AbstractTransportationSpace): DefaultIssueList { + private fun addSingleLane( + id: LaneIdentifier, + road: Road, + longitudinalFillerSurfaces: List, + relatedObjects: List, + dstTransportationSpace: AbstractTransportationSpace, + ): DefaultIssueList { val issueList = DefaultIssueList() - val lane = road.getLane(id) - .getOrElse { issueList += DefaultIssue.of("LaneNotConstructable", "${it.message} Ignoring lane.", id, Severity.WARNING, wasFixed = true); return issueList } - val surface = road.getLaneSurface(id, parameters.discretizationStepSize) - .getOrElse { issueList += DefaultIssue.of("LaneSurfaceNotConstructable", "${it.message} Ignoring lane.", id, Severity.WARNING, wasFixed = true); return issueList } - val centerLine = road.getCurveOnLane(id, 0.5) - .getOrElse { issueList += DefaultIssue.of("CenterLineNotConstructable", "${it.message} Ignoring lane.", id, Severity.WARNING, wasFixed = true); return issueList } - val lateralFillerSurface = road.getLateralFillerSurface(id, parameters.discretizationStepSize) - .getOrElse { issueList += DefaultIssue.of("LateralFillerSurfaceNotConstructable", "${it.message} Ignoring lane.", id, Severity.WARNING, wasFixed = true); return issueList } - - issueList += when (LaneRouter.route(lane)) { - LaneRouter.CitygmlTargetFeatureType.TRANSPORTATION_TRAFFICSPACE -> { - transportationModuleBuilder.addTrafficSpaceFeature(lane, surface, centerLine, lateralFillerSurface, longitudinalFillerSurfaces, relatedObjects, dstTransportationSpace) - } + val lane = + road.getLane(id) + .getOrElse { + issueList += + DefaultIssue.of( + "LaneNotConstructable", "${it.message} Ignoring lane.", id, + Severity.WARNING, wasFixed = true, + ) + return issueList + } + val surface = + road.getLaneSurface(id, parameters.discretizationStepSize) + .getOrElse { + issueList += + DefaultIssue.of( + "LaneSurfaceNotConstructable", "${it.message} Ignoring lane.", id, + Severity.WARNING, wasFixed = true, + ) + return issueList + } + val centerLine = + road.getCurveOnLane(id, 0.5) + .getOrElse { + issueList += + DefaultIssue.of( + "CenterLineNotConstructable", "${it.message} Ignoring lane.", id, + Severity.WARNING, wasFixed = true, + ) + return issueList + } + val lateralFillerSurface = + road.getLateralFillerSurface(id, parameters.discretizationStepSize) + .getOrElse { + issueList += + DefaultIssue.of( + "LateralFillerSurfaceNotConstructable", "${it.message} Ignoring lane.", id, + Severity.WARNING, wasFixed = true, + ) + return issueList + } - LaneRouter.CitygmlTargetFeatureType.TRANSPORTATION_AUXILIARYTRAFFICSPACE -> { - transportationModuleBuilder.addAuxiliaryTrafficSpaceFeature(lane, surface, centerLine, lateralFillerSurface, longitudinalFillerSurfaces, dstTransportationSpace) + issueList += + when (LaneRouter.route(lane)) { + LaneRouter.CitygmlTargetFeatureType.TRANSPORTATION_TRAFFICSPACE -> { + transportationModuleBuilder.addTrafficSpaceFeature( + lane, surface, centerLine, lateralFillerSurface, + longitudinalFillerSurfaces, relatedObjects, dstTransportationSpace, + ) + } + + LaneRouter.CitygmlTargetFeatureType.TRANSPORTATION_AUXILIARYTRAFFICSPACE -> { + transportationModuleBuilder.addAuxiliaryTrafficSpaceFeature( + lane, surface, centerLine, lateralFillerSurface, + longitudinalFillerSurfaces, dstTransportationSpace, + ) + } } - } return issueList } - private fun addSingleRoadspaceObject(roadspaceObject: RoadspaceObject, dstTransportationSpace: AbstractTransportationSpace): DefaultIssueList { + private fun addSingleRoadspaceObject( + roadspaceObject: RoadspaceObject, + dstTransportationSpace: AbstractTransportationSpace, + ): DefaultIssueList { val issueList = DefaultIssueList() when (RoadspaceObjectRouter.route(roadspaceObject)) { @@ -225,10 +296,16 @@ class RoadsTransformer( return issueList } - private fun addRoadMarkings(id: LaneIdentifier, road: Road, dstTransportationSpace: AbstractTransportationSpace): DefaultIssueList { + private fun addRoadMarkings( + id: LaneIdentifier, + road: Road, + dstTransportationSpace: AbstractTransportationSpace, + ): DefaultIssueList { val issueList = DefaultIssueList() road.getRoadMarkings(id, parameters.discretizationStepSize) - .handleLeftAndFilter { issueList += DefaultIssue.of("RoadMarkingNotConstructable", it.value.message!!, id, Severity.WARNING, wasFixed = true) } + .handleLeftAndFilter { + issueList += DefaultIssue.of("RoadMarkingNotConstructable", it.value.message!!, id, Severity.WARNING, wasFixed = true) + } .forEachIndexed { index, (roadMarking, geometry) -> issueList += transportationModuleBuilder.addMarkingFeature(id, index, roadMarking, geometry, dstTransportationSpace) } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/RoadspaceObjectTransformer.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/RoadspaceObjectTransformer.kt index 62e0c3a3..063a12d7 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/RoadspaceObjectTransformer.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/converter/roadspaces2citygml/transformer/RoadspaceObjectTransformer.kt @@ -37,9 +37,8 @@ import org.citygml4j.core.model.core.CityModel * Transforms [RoadspaceObject] classes (RoadSpaces model) to the [CityModel] (CityGML model). */ class RoadspaceObjectTransformer( - private val parameters: Roadspaces2CitygmlParameters + private val parameters: Roadspaces2CitygmlParameters, ) { - // Properties and Initializers private val genericsModuleBuilder = GenericsModuleBuilder(parameters) private val buildingModuleBuilder = BuildingModuleBuilder(parameters) @@ -68,15 +67,36 @@ class RoadspaceObjectTransformer( private fun transformSingleRoadspaceObject(roadspaceObject: RoadspaceObject): ContextIssueList> { val issueList = DefaultIssueList() - val cityObjects: Option = when (RoadspaceObjectRouter.route(roadspaceObject)) { - RoadspaceObjectRouter.CitygmlTargetFeatureType.BUILDING_BUILDING -> buildingModuleBuilder.createBuildingFeature(roadspaceObject).handleIssueList { issueList += it }.some() - RoadspaceObjectRouter.CitygmlTargetFeatureType.CITYFURNITURE_CITYFURNITURE -> cityFurnitureModuleBuilder.createCityFurnitureFeature(roadspaceObject).handleIssueList { issueList += it }.some() - RoadspaceObjectRouter.CitygmlTargetFeatureType.GENERICS_GENERICOCCUPIEDSPACE -> genericsModuleBuilder.createGenericOccupiedSpaceFeature(roadspaceObject).handleIssueList { issueList += it }.some() - RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_TRAFFICSPACE -> None - RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_AUXILIARYTRAFFICSPACE -> None - RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_MARKING -> None - RoadspaceObjectRouter.CitygmlTargetFeatureType.VEGETATION_SOLITARYVEGETATIONOBJECT -> vegetationModuleBuilder.createSolitaryVegetationObjectFeature(roadspaceObject).handleIssueList { issueList += it }.some() - } + val cityObjects: Option = + when (RoadspaceObjectRouter.route(roadspaceObject)) { + RoadspaceObjectRouter.CitygmlTargetFeatureType.BUILDING_BUILDING -> + buildingModuleBuilder.createBuildingFeature( + roadspaceObject, + ).handleIssueList { + issueList += it + }.some() + RoadspaceObjectRouter.CitygmlTargetFeatureType.CITYFURNITURE_CITYFURNITURE -> + cityFurnitureModuleBuilder.createCityFurnitureFeature( + roadspaceObject, + ).handleIssueList { + issueList += it + }.some() + RoadspaceObjectRouter.CitygmlTargetFeatureType.GENERICS_GENERICOCCUPIEDSPACE -> + genericsModuleBuilder.createGenericOccupiedSpaceFeature( + roadspaceObject, + ).handleIssueList { + issueList += it + }.some() + RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_TRAFFICSPACE -> None + RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_AUXILIARYTRAFFICSPACE -> None + RoadspaceObjectRouter.CitygmlTargetFeatureType.TRANSPORTATION_MARKING -> None + RoadspaceObjectRouter.CitygmlTargetFeatureType.VEGETATION_SOLITARYVEGETATIONOBJECT -> + vegetationModuleBuilder.createSolitaryVegetationObjectFeature( + roadspaceObject, + ).handleIssueList { + issueList += it + }.some() + } return ContextIssueList(cityObjects, issueList) } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/OpendriveEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/OpendriveEvaluator.kt index 5c7c4f7a..5d4d45fa 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/OpendriveEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/OpendriveEvaluator.kt @@ -29,7 +29,7 @@ import io.rtron.transformer.evaluator.opendrive.plans.modelingrules.ModelingRule import io.rtron.transformer.evaluator.opendrive.report.OpendriveEvaluationReport class OpendriveEvaluator( - val parameters: OpendriveEvaluatorParameters + val parameters: OpendriveEvaluatorParameters, ) { // Properties and Initializers private val logger = KotlinLogging.logger {} diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/OpendriveEvaluatorParameters.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/OpendriveEvaluatorParameters.kt index 1387c281..6bf91643 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/OpendriveEvaluatorParameters.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/OpendriveEvaluatorParameters.kt @@ -34,12 +34,15 @@ data class OpendriveEvaluatorParameters( /** angle tolerance between two geometry elements of the plan view */ val planViewGeometryAngleTolerance: Double, /** warning tolerance for angles between two geometry elements of the plan view */ - val planViewGeometryAngleWarningTolerance: Double + val planViewGeometryAngleWarningTolerance: Double, ) { - init { - require(planViewGeometryDistanceTolerance >= planViewGeometryDistanceWarningTolerance) { "Distance tolerance must be greater or equal to the warning distance tolerance." } - require(planViewGeometryAngleTolerance >= planViewGeometryAngleWarningTolerance) { "Angle difference tolerance must be greater or equal to the warning angle difference tolerance." } + require(planViewGeometryDistanceTolerance >= planViewGeometryDistanceWarningTolerance) { + "Distance tolerance must be greater or equal to the warning distance tolerance." + } + require(planViewGeometryAngleTolerance >= planViewGeometryAngleWarningTolerance) { + "Angle difference tolerance must be greater or equal to the warning angle difference tolerance." + } } companion object { diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/modifiers/BasicDataTypeModifier.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/modifiers/BasicDataTypeModifier.kt index bb93e954..7812d721 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/modifiers/BasicDataTypeModifier.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/modifiers/BasicDataTypeModifier.kt @@ -27,110 +27,206 @@ import io.rtron.std.filterToSortingBy import io.rtron.std.filterToStrictSortingBy object BasicDataTypeModifier { - - fun > filterToStrictlySorted(elementList: List, selector: (T) -> K, location: String, attributeName: String, issueList: DefaultIssueList): List { + fun > filterToStrictlySorted( + elementList: List, + selector: (T) -> K, + location: String, + attributeName: String, + issueList: DefaultIssueList, + ): List { val elementListFiltered = elementList.filterToStrictSortingBy(selector) val numberOfIgnoredElements = elementList.size - elementListFiltered.size if (numberOfIgnoredElements > 0) { - issueList += DefaultIssue("NonStrictlyAscendingSortedList", "The list entries of the attribute '$attributeName' are not sorted in strictly ascending order. $numberOfIgnoredElements elements are removed to adhere to strictly ascending order.", location, Severity.WARNING, true) + issueList += + DefaultIssue( + "NonStrictlyAscendingSortedList", + "The list entries of the attribute '$attributeName' are not sorted in strictly ascending order. " + + "$numberOfIgnoredElements elements are removed to adhere to strictly ascending order.", + location, + Severity.WARNING, true, + ) } return elementListFiltered } - fun > filterToStrictlySorted(elementList: List, selector: (T) -> K, location: Option, attributeName: String, issueList: DefaultIssueList): List { + fun > filterToStrictlySorted( + elementList: List, + selector: (T) -> K, + location: Option, + attributeName: String, + issueList: DefaultIssueList, + ): List { return filterToStrictlySorted(elementList, selector, location.toIdentifierText(), attributeName, issueList) } - fun > filterToSorted(elementList: List, selector: (T) -> K, location: String, attributeName: String, issueList: DefaultIssueList): List { + fun > filterToSorted( + elementList: List, + selector: (T) -> K, + location: String, + attributeName: String, + issueList: DefaultIssueList, + ): List { val elementListFiltered = elementList.filterToSortingBy(selector) val numberOfIgnoredElements = elementList.size - elementListFiltered.size if (numberOfIgnoredElements > 0) { - issueList += DefaultIssue("NonAscendingSortedList", "The list entries of the attribute '$attributeName' are not sorted in ascending order. $numberOfIgnoredElements elements are removed to adhere to ascending order.", location, Severity.WARNING, true) + issueList += + DefaultIssue( + "NonAscendingSortedList", + "The list entries of the attribute '$attributeName' are not sorted in ascending order. " + + "$numberOfIgnoredElements elements are removed to adhere to ascending order.", + location, + Severity.WARNING, true, + ) } return elementListFiltered } - fun > filterToSorted(elementList: List, selector: (T) -> K, location: Option, attributeName: String, issueList: DefaultIssueList): List { + fun > filterToSorted( + elementList: List, + selector: (T) -> K, + location: Option, + attributeName: String, + issueList: DefaultIssueList, + ): List { return filterToSorted(elementList, selector, location.toIdentifierText(), attributeName, issueList) } - fun modifyToNonBlankString(element: String, location: Option, attributeName: String, issueList: DefaultIssueList, fallbackValue: String): String { + fun modifyToNonBlankString( + element: String, + location: Option, + attributeName: String, + issueList: DefaultIssueList, + fallbackValue: String, + ): String { if (element.isBlank()) { - issueList += DefaultIssue("BlankStringAttributeValue", "The value of the attribute '$attributeName' is blank. The attribute is set to '$fallbackValue'.", location.toIdentifierText(), Severity.WARNING, wasFixed = true) + issueList += + DefaultIssue( + "BlankStringAttributeValue", + "The value of the attribute '$attributeName' is blank. The attribute is set to '$fallbackValue'.", + location.toIdentifierText(), Severity.WARNING, wasFixed = true, + ) return fallbackValue } return element } - fun modifyToOptionalString(optionalElement: Option, location: Option, attributeName: String, issueList: DefaultIssueList): Option = - modifyToOptionalString(optionalElement, location.toIdentifierText(), attributeName, issueList) - - fun modifyToOptionalString(optionalElement: Option, location: String, attributeName: String, issueList: DefaultIssueList): Option { + fun modifyToOptionalString( + optionalElement: Option, + location: Option, + attributeName: String, + issueList: DefaultIssueList, + ): Option = modifyToOptionalString(optionalElement, location.toIdentifierText(), attributeName, issueList) + + fun modifyToOptionalString( + optionalElement: Option, + location: String, + attributeName: String, + issueList: DefaultIssueList, + ): Option { if (optionalElement.isSome { it.isBlank() }) { - issueList += DefaultIssue( - "BlankStringAttributeValueForOptionalAttribute", - "The value of the attribute '$attributeName' is blank. The attribute is unset as it is optional.", - location, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue( + "BlankStringAttributeValueForOptionalAttribute", + "The value of the attribute '$attributeName' is blank. The attribute is unset as it is optional.", + location, Severity.WARNING, wasFixed = true, + ) return None } return optionalElement } - fun modifyToOptionalFiniteDouble(optionalElement: Option, location: Option, attributeName: String, issueList: DefaultIssueList): Option = - modifyToOptionalFiniteDouble(optionalElement, location.toIdentifierText(), attributeName, issueList) - - fun modifyToOptionalFiniteDouble(optionalElement: Option, location: String, attributeName: String, issueList: DefaultIssueList): Option { + fun modifyToOptionalFiniteDouble( + optionalElement: Option, + location: Option, + attributeName: String, + issueList: DefaultIssueList, + ): Option = modifyToOptionalFiniteDouble(optionalElement, location.toIdentifierText(), attributeName, issueList) + + fun modifyToOptionalFiniteDouble( + optionalElement: Option, + location: String, + attributeName: String, + issueList: DefaultIssueList, + ): Option { if (optionalElement.isSome { !it.isFinite() }) { - issueList += DefaultIssue( - "NonFiniteDoubleAttributeValue", - "The value of the attribute '$attributeName' is not finite. The attribute is unset as it is optional.", - location, - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue( + "NonFiniteDoubleAttributeValue", + "The value of the attribute '$attributeName' is not finite. The attribute is unset as it is optional.", + location, Severity.WARNING, wasFixed = true, + ) return None } return optionalElement } - fun modifyToOptionalFinitePositiveDouble(optionalElement: Option, location: Option, attributeName: String, issueList: DefaultIssueList, tolerance: Double = 0.0): Option { + fun modifyToOptionalFinitePositiveDouble( + optionalElement: Option, + location: Option, + attributeName: String, + issueList: DefaultIssueList, + tolerance: Double = 0.0, + ): Option { if (optionalElement.isSome { !it.isFinite() || it < tolerance }) { - issueList += DefaultIssue( - "NonFinitePositiveDoubleAttributeValue", - "The value of the attribute '$attributeName' is not finite or not positive (applied tolerance: $tolerance). The attribute is unset as it is optional.", - location.toIdentifierText(), - Severity.WARNING, - wasFixed = true - ) + issueList += + DefaultIssue( + "NonFinitePositiveDoubleAttributeValue", + "The value of the attribute '$attributeName' is not finite or not positive (applied tolerance: $tolerance). " + + "The attribute is unset as it is optional.", + location.toIdentifierText(), Severity.WARNING, wasFixed = true, + ) return None } return optionalElement } - fun modifyToFinitePositiveDouble(element: Double, location: Option, attributeName: String, issueList: DefaultIssueList): Double { + fun modifyToFinitePositiveDouble( + element: Double, + location: Option, + attributeName: String, + issueList: DefaultIssueList, + ): Double { if (!element.isFinite() || element < 0.0) { - issueList += DefaultIssue("NonFinitePositiveDoubleAttributeValue", "The value of the attribute '$attributeName' is not finite or not positive (applied tolerance: 0.0). The attribute value is set to 0.0.", location.toIdentifierText(), Severity.WARNING, wasFixed = true) + issueList += + DefaultIssue( + "NonFinitePositiveDoubleAttributeValue", + "The value of the attribute '$attributeName' is not finite or not positive (applied tolerance: 0.0). " + + "The attribute value is set to 0.0.", + location.toIdentifierText(), Severity.WARNING, wasFixed = true, + ) return 0.0 } return element } - fun modifyToFiniteDouble(element: Double, location: Option, attributeName: String, issueList: DefaultIssueList): Double = - modifyToFiniteDouble(element, location.toIdentifierText(), attributeName, issueList) - - fun modifyToFiniteDouble(element: Double, location: String, attributeName: String, issueList: DefaultIssueList): Double { + fun modifyToFiniteDouble( + element: Double, + location: Option, + attributeName: String, + issueList: DefaultIssueList, + ): Double = modifyToFiniteDouble(element, location.toIdentifierText(), attributeName, issueList) + + fun modifyToFiniteDouble( + element: Double, + location: String, + attributeName: String, + issueList: DefaultIssueList, + ): Double { if (!element.isFinite()) { - issueList += DefaultIssue("NonFiniteAttributeValue", "The value of the attribute '$attributeName' is not finite. The attribute value is set to 0.0.", location, Severity.WARNING, wasFixed = true) + issueList += + DefaultIssue( + "NonFiniteAttributeValue", + "The value of the attribute '$attributeName' is not finite. " + + "The attribute value is set to 0.0.", + location, Severity.WARNING, wasFixed = true, + ) return 0.0 } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/AbstractOpendriveEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/AbstractOpendriveEvaluator.kt index a3893997..53380a63 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/AbstractOpendriveEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/AbstractOpendriveEvaluator.kt @@ -20,7 +20,6 @@ import io.rtron.io.issues.ContextIssueList import io.rtron.model.opendrive.OpendriveModel abstract class AbstractOpendriveEvaluator { - // Methods abstract fun evaluate(opendriveModel: OpendriveModel): ContextIssueList } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/BasicDataTypeEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/BasicDataTypeEvaluator.kt index e4f1b5a5..fcc8cdc2 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/BasicDataTypeEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/BasicDataTypeEvaluator.kt @@ -23,7 +23,6 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.evaluator.opendrive.plans.AbstractOpendriveEvaluator class BasicDataTypeEvaluator(val parameters: OpendriveEvaluatorParameters) : AbstractOpendriveEvaluator() { - // Methods override fun evaluate(opendriveModel: OpendriveModel): ContextIssueList { val issueList = DefaultIssueList() diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/CoreEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/CoreEvaluator.kt index 65d3ce96..e7005aef 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/CoreEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/CoreEvaluator.kt @@ -26,52 +26,105 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.evaluator.opendrive.modifiers.BasicDataTypeModifier object CoreEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() if (modifiedOpendriveModel.road.isEmpty()) { - issueList += DefaultIssue("NoRoadsContained", "Document does not contain any roads.", "", Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue( + "NoRoadsContained", "Document does not contain any roads.", "", + Severity.FATAL_ERROR, wasFixed = false, + ) } val duplicateRoadIds = modifiedOpendriveModel.road.map { it.id }.groupingBy { it }.eachCount().filter { it.value > 1 } if (duplicateRoadIds.isNotEmpty()) { - issueList += DefaultIssue("DuplicateRoadIds", "Multiple road elements are using the same ID (affected IDs: ${duplicateRoadIds.keys.joinToString()}).", "", Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue( + "DuplicateRoadIds", + "Multiple road elements are using the same ID (affected IDs: ${duplicateRoadIds.keys.joinToString()}).", "", + Severity.FATAL_ERROR, wasFixed = false, + ) } OpendriveModel.header.get(modifiedOpendriveModel).also { header -> if (header.revMajor < 0) { - issueList += DefaultIssue("UnkownOpendriveMajorVersionNumber", "", "Header element", Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue( + "UnkownOpendriveMajorVersionNumber", "", "Header element", Severity.FATAL_ERROR, wasFixed = false, + ) } if (header.revMinor < 0) { - issueList += DefaultIssue("UnkownOpendriveMinorVersionNumber", "", "Header element", Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue( + "UnkownOpendriveMinorVersionNumber", "", "Header element", Severity.FATAL_ERROR, wasFixed = false, + ) } } - modifiedOpendriveModel = OpendriveModel.header.modify(modifiedOpendriveModel) { header -> - header.name = BasicDataTypeModifier.modifyToOptionalString(header.name, "Header element", "name", issueList) - header.date = BasicDataTypeModifier.modifyToOptionalString(header.date, "Header element", "date", issueList) - header.vendor = BasicDataTypeModifier.modifyToOptionalString(header.vendor, "Header element", "vendor", issueList) + modifiedOpendriveModel = + OpendriveModel.header.modify(modifiedOpendriveModel) { header -> + header.name = + BasicDataTypeModifier.modifyToOptionalString( + header.name, "Header element", "name", issueList, + ) + header.date = + BasicDataTypeModifier.modifyToOptionalString( + header.date, "Header element", "date", issueList, + ) + header.vendor = + BasicDataTypeModifier.modifyToOptionalString( + header.vendor, "Header element", "vendor", issueList, + ) - header.east = BasicDataTypeModifier.modifyToOptionalFiniteDouble(header.east, "Header element", "east", issueList) - header.north = BasicDataTypeModifier.modifyToOptionalFiniteDouble(header.north, "Header element", "north", issueList) - header.south = BasicDataTypeModifier.modifyToOptionalFiniteDouble(header.south, "Header element", "south", issueList) - header.west = BasicDataTypeModifier.modifyToOptionalFiniteDouble(header.south, "Header element", "west", issueList) + header.east = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + header.east, "Header element", "east", issueList, + ) + header.north = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + header.north, "Header element", "north", issueList, + ) + header.south = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + header.south, "Header element", "south", issueList, + ) + header.west = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + header.south, "Header element", "west", issueList, + ) - header - } + header + } - modifiedOpendriveModel = everyHeaderOffset.modify(modifiedOpendriveModel) { currentHeaderOffset -> + modifiedOpendriveModel = + everyHeaderOffset.modify(modifiedOpendriveModel) { currentHeaderOffset -> - currentHeaderOffset.x = BasicDataTypeModifier.modifyToFiniteDouble(currentHeaderOffset.x, "Header element", "x", issueList) - currentHeaderOffset.y = BasicDataTypeModifier.modifyToFiniteDouble(currentHeaderOffset.y, "Header element", "y", issueList) - currentHeaderOffset.z = BasicDataTypeModifier.modifyToFiniteDouble(currentHeaderOffset.z, "Header element", "z", issueList) - currentHeaderOffset.hdg = BasicDataTypeModifier.modifyToFiniteDouble(currentHeaderOffset.hdg, "Header element", "hdg", issueList) + currentHeaderOffset.x = + BasicDataTypeModifier.modifyToFiniteDouble( + currentHeaderOffset.x, "Header element", "x", issueList, + ) + currentHeaderOffset.y = + BasicDataTypeModifier.modifyToFiniteDouble( + currentHeaderOffset.y, "Header element", "y", issueList, + ) + currentHeaderOffset.z = + BasicDataTypeModifier.modifyToFiniteDouble( + currentHeaderOffset.z, "Header element", "z", issueList, + ) + currentHeaderOffset.hdg = + BasicDataTypeModifier.modifyToFiniteDouble( + currentHeaderOffset.hdg, "Header element", "hdg", issueList, + ) - currentHeaderOffset - } + currentHeaderOffset + } return modifiedOpendriveModel } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/JunctionEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/JunctionEvaluator.kt index 178c9326..587ac12e 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/JunctionEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/JunctionEvaluator.kt @@ -27,19 +27,30 @@ import io.rtron.transformer.evaluator.opendrive.modifiers.BasicDataTypeModifier import io.rtron.transformer.issues.opendrive.of object JunctionEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() everyJunction.modify(modifiedOpendriveModel) { currentJunction -> if (currentJunction.connection.isEmpty()) { - issueList += DefaultIssue.of("EmptyList", "List for attribute 'connection' is empty, but it has to contain at least one element.", currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue.of( + "EmptyList", "List for attribute 'connection' is empty, but it has to contain at least one element.", + currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) } if (currentJunction.id.isBlank()) { - issueList += DefaultIssue.of("MissingValue", "Missing value for attribute 'ID'.", currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue.of( + "MissingValue", "Missing value for attribute 'ID'.", currentJunction.additionalId, + Severity.FATAL_ERROR, wasFixed = false, + ) } currentJunction @@ -48,30 +59,59 @@ object JunctionEvaluator { everyJunctionConnection.modify(modifiedOpendriveModel) { currentJunctionConnection -> if (currentJunctionConnection.id.isBlank()) { - issueList += DefaultIssue.of("MissingValue", "Missing value for attribute 'ID'.", currentJunctionConnection.additionalId, Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue.of( + "MissingValue", "Missing value for attribute 'ID'.", currentJunctionConnection.additionalId, + Severity.FATAL_ERROR, wasFixed = false, + ) } currentJunctionConnection } - modifiedOpendriveModel = everyJunction.modify(modifiedOpendriveModel) { currentJunction -> - currentJunction.mainRoad = BasicDataTypeModifier.modifyToOptionalString(currentJunction.mainRoad, currentJunction.additionalId, "mainRoad", issueList) - currentJunction.name = BasicDataTypeModifier.modifyToOptionalString(currentJunction.name, currentJunction.additionalId, "name", issueList) - - currentJunction.sEnd = BasicDataTypeModifier.modifyToOptionalFiniteDouble(currentJunction.sEnd, currentJunction.additionalId, "sEnd", issueList) - currentJunction.sStart = BasicDataTypeModifier.modifyToOptionalFiniteDouble(currentJunction.sStart, currentJunction.additionalId, "sStart", issueList) - - currentJunction - } - - modifiedOpendriveModel = everyJunctionConnection.modify(modifiedOpendriveModel) { currentJunctionConnection -> - - currentJunctionConnection.connectingRoad = BasicDataTypeModifier.modifyToOptionalString(currentJunctionConnection.connectingRoad, currentJunctionConnection.additionalId, "connectingRoad", issueList) - currentJunctionConnection.incomingRoad = BasicDataTypeModifier.modifyToOptionalString(currentJunctionConnection.incomingRoad, currentJunctionConnection.additionalId, "incomingRoad", issueList) - currentJunctionConnection.linkedRoad = BasicDataTypeModifier.modifyToOptionalString(currentJunctionConnection.linkedRoad, currentJunctionConnection.additionalId, "linkedRoad", issueList) + modifiedOpendriveModel = + everyJunction.modify(modifiedOpendriveModel) { currentJunction -> + currentJunction.mainRoad = + BasicDataTypeModifier.modifyToOptionalString( + currentJunction.mainRoad, currentJunction.additionalId, "mainRoad", issueList, + ) + currentJunction.name = + BasicDataTypeModifier.modifyToOptionalString( + currentJunction.name, currentJunction.additionalId, "name", issueList, + ) + + currentJunction.sEnd = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + currentJunction.sEnd, currentJunction.additionalId, "sEnd", issueList, + ) + currentJunction.sStart = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + currentJunction.sStart, currentJunction.additionalId, "sStart", issueList, + ) + + currentJunction + } - currentJunctionConnection - } + modifiedOpendriveModel = + everyJunctionConnection.modify(modifiedOpendriveModel) { currentJunctionConnection -> + + currentJunctionConnection.connectingRoad = + BasicDataTypeModifier.modifyToOptionalString( + currentJunctionConnection.connectingRoad, currentJunctionConnection.additionalId, "connectingRoad", + issueList, + ) + currentJunctionConnection.incomingRoad = + BasicDataTypeModifier.modifyToOptionalString( + currentJunctionConnection.incomingRoad, currentJunctionConnection.additionalId, "incomingRoad", + issueList, + ) + currentJunctionConnection.linkedRoad = + BasicDataTypeModifier.modifyToOptionalString( + currentJunctionConnection.linkedRoad, currentJunctionConnection.additionalId, "linkedRoad", issueList, + ) + + currentJunctionConnection + } return modifiedOpendriveModel } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadEvaluator.kt index 17927da3..06664669 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadEvaluator.kt @@ -30,115 +30,139 @@ import io.rtron.transformer.evaluator.opendrive.modifiers.BasicDataTypeModifier import io.rtron.transformer.issues.opendrive.of object RoadEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() everyRoad.modify(modifiedOpendriveModel) { currentRoad -> if (currentRoad.planView.geometry.isEmpty()) { - issueList += DefaultIssue.of("NoPlanViewGeometryElements", "Plan view of road does not contain any geometry elements.", currentRoad.additionalId, Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue.of( + "NoPlanViewGeometryElements", "Plan view of road does not contain any geometry elements.", + currentRoad.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) } if (currentRoad.lanes.laneSection.isEmpty()) { - issueList += DefaultIssue.of("NoLaneSections", "Road does not contain any lane sections.", currentRoad.additionalId, Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue.of( + "NoLaneSections", "Road does not contain any lane sections.", currentRoad.additionalId, + Severity.FATAL_ERROR, wasFixed = false, + ) } currentRoad } - modifiedOpendriveModel = everyRoad.modify(modifiedOpendriveModel) { currentRoad -> - - if (currentRoad.elevationProfile.isSome { it.elevation.isEmpty() }) { - issueList += DefaultIssue.of( - "NoElevationProfileElements", - "Elevation profile contains no elements.", - currentRoad.additionalId, - Severity.WARNING, - wasFixed = true - ) - currentRoad.elevationProfile = None - } + modifiedOpendriveModel = + everyRoad.modify(modifiedOpendriveModel) { currentRoad -> + + if (currentRoad.elevationProfile.isSome { it.elevation.isEmpty() }) { + issueList += + DefaultIssue.of( + "NoElevationProfileElements", + "Elevation profile contains no elements.", + currentRoad.additionalId, + Severity.WARNING, + wasFixed = true, + ) + currentRoad.elevationProfile = None + } - currentRoad.elevationProfile.onSome { elevationProfile -> - elevationProfile.elevation = BasicDataTypeModifier.filterToStrictlySorted( - elevationProfile.elevation, - { it.s }, - currentRoad.additionalId, - "elevation", - issueList - ) - } + currentRoad.elevationProfile.onSome { elevationProfile -> + elevationProfile.elevation = + BasicDataTypeModifier.filterToStrictlySorted( + elevationProfile.elevation, + { it.s }, + currentRoad.additionalId, + "elevation", + issueList, + ) + } - currentRoad.lateralProfile.onSome { currentLateralProfile -> - if (currentLateralProfile.containsShapeProfile() && currentRoad.lanes.containsLaneOffset()) { - issueList += DefaultIssue.of( - "UnexpectedValue", - "Unexpected value for attribute 'lateralProfile.shape'", - currentRoad.additionalId, - Severity.WARNING, - wasFixed = true - ) - if (!parameters.skipRoadShapeRemoval) { - currentLateralProfile.shape = emptyList() + currentRoad.lateralProfile.onSome { currentLateralProfile -> + if (currentLateralProfile.containsShapeProfile() && currentRoad.lanes.containsLaneOffset()) { + issueList += + DefaultIssue.of( + "UnexpectedValue", + "Unexpected value for attribute 'lateralProfile.shape'", + currentRoad.additionalId, + Severity.WARNING, + wasFixed = true, + ) + if (!parameters.skipRoadShapeRemoval) { + currentLateralProfile.shape = emptyList() + } } - } - currentLateralProfile.superelevation = BasicDataTypeModifier.filterToStrictlySorted( - currentLateralProfile.superelevation, - { it.s }, - currentRoad.additionalId, - "superelevation", - issueList - ) - currentLateralProfile.shape = BasicDataTypeModifier.filterToSorted( - currentLateralProfile.shape, - { it.s }, - currentRoad.additionalId, - "shape", - issueList - ) - - val shapeEntriesFilteredByT: List = - currentLateralProfile.shape.groupBy { it.s }.flatMap { currentShapeSubEntries -> - currentShapeSubEntries.value.filterToStrictSortingBy { it.t } + currentLateralProfile.superelevation = + BasicDataTypeModifier.filterToStrictlySorted( + currentLateralProfile.superelevation, + { it.s }, + currentRoad.additionalId, + "superelevation", + issueList, + ) + currentLateralProfile.shape = + BasicDataTypeModifier.filterToSorted( + currentLateralProfile.shape, + { it.s }, + currentRoad.additionalId, + "shape", + issueList, + ) + + val shapeEntriesFilteredByT: List = + currentLateralProfile.shape.groupBy { it.s }.flatMap { currentShapeSubEntries -> + currentShapeSubEntries.value.filterToStrictSortingBy { it.t } + } + if (shapeEntriesFilteredByT.size < currentLateralProfile.shape.size) { + // OpendriveException.NonStrictlySortedList("shape", + // "Ignoring ${it.shape.size - shapeEntriesFilteredByT.size} shape entries which are not placed + // in ascending order according to t for each s group.").toIssue(currentRoad.additionalId, + // isFatal = false, wasFixed = true) + issueList += + DefaultIssue.of( + "NonStrictlySortedList", + "Ignoring ${currentLateralProfile.shape.size - shapeEntriesFilteredByT.size} shape entries " + + "which are not placed in ascending order according to t for each s group.", + currentRoad.additionalId, + Severity.WARNING, + wasFixed = true, + ) + currentLateralProfile.shape = shapeEntriesFilteredByT } - if (shapeEntriesFilteredByT.size < currentLateralProfile.shape.size) { - // OpendriveException.NonStrictlySortedList("shape", "Ignoring ${it.shape.size - shapeEntriesFilteredByT.size} shape entries which are not placed in ascending order according to t for each s group.").toIssue(currentRoad.additionalId, isFatal = false, wasFixed = true) - issueList += DefaultIssue.of( - "NonStrictlySortedList", - "Ignoring ${currentLateralProfile.shape.size - shapeEntriesFilteredByT.size} shape entries which are not placed in ascending order according to t for each s group.", + } + + currentRoad.lanes.laneOffset = + BasicDataTypeModifier.filterToStrictlySorted( + currentRoad.lanes.laneOffset, + { it.s }, currentRoad.additionalId, - Severity.WARNING, - wasFixed = true + "shape", + issueList, ) - currentLateralProfile.shape = shapeEntriesFilteredByT + + if (!currentRoad.lanes.laneSection.isSortedBy { it.s }) { + issueList += + DefaultIssue.of( + "NonSortedList", + "Sorting lane sections according to s.", + currentRoad.additionalId, + Severity.WARNING, + wasFixed = true, + ) + currentRoad.lanes.laneSection = currentRoad.lanes.laneSection.sortedBy { it.s } } - } - currentRoad.lanes.laneOffset = BasicDataTypeModifier.filterToStrictlySorted( - currentRoad.lanes.laneOffset, - { it.s }, - currentRoad.additionalId, - "shape", - issueList - ) - - if (!currentRoad.lanes.laneSection.isSortedBy { it.s }) { - issueList += DefaultIssue.of( - "NonSortedList", - "Sorting lane sections according to s.", - currentRoad.additionalId, - Severity.WARNING, - wasFixed = true - ) - currentRoad.lanes.laneSection = currentRoad.lanes.laneSection.sortedBy { it.s } + currentRoad } - currentRoad - } - return modifiedOpendriveModel } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadLanesEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadLanesEvaluator.kt index 10a00492..84ea656f 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadLanesEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadLanesEvaluator.kt @@ -32,12 +32,11 @@ import io.rtron.transformer.evaluator.opendrive.modifiers.BasicDataTypeModifier import io.rtron.transformer.issues.opendrive.of object RoadLanesEvaluator { - // Methods fun evaluate( opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, - issueList: DefaultIssueList + issueList: DefaultIssueList, ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() @@ -51,70 +50,70 @@ object RoadLanesEvaluator { currentRightLane } - modifiedOpendriveModel = everyLaneSection.modify(modifiedOpendriveModel) { currentLaneSection -> + modifiedOpendriveModel = + everyLaneSection.modify(modifiedOpendriveModel) { currentLaneSection -> + + currentLaneSection.left.onSome { + if (it.lane.isEmpty()) { + issueList += + DefaultIssue.of( + "EmptyValueForOptionalAttribute", + "Attribute 'left' is set with an empty value even though the attribute itself is optional.", + currentLaneSection.additionalId, Severity.WARNING, wasFixed = true, + ) + currentLaneSection.left = None + } + } - currentLaneSection.left.onSome { - if (it.lane.isEmpty()) { - issueList += DefaultIssue.of( - "EmptyValueForOptionalAttribute", - "Attribute 'left' is set with an empty value even though the attribute itself is optional.", - currentLaneSection.additionalId, - Severity.WARNING, - wasFixed = true - ) - currentLaneSection.left = None + currentLaneSection.right.onSome { + if (it.lane.isEmpty()) { + issueList += + DefaultIssue.of( + "EmptyValueForOptionalAttribute", + "Attribute 'right' is set with an empty value even though the attribute itself is optional.", + currentLaneSection.additionalId, Severity.WARNING, wasFixed = true, + ) + currentLaneSection.right = None + } } - } - currentLaneSection.right.onSome { - if (it.lane.isEmpty()) { - issueList += DefaultIssue.of( - "EmptyValueForOptionalAttribute", - "Attribute 'right' is set with an empty value even though the attribute itself is optional.", - currentLaneSection.additionalId, - Severity.WARNING, - wasFixed = true - ) - currentLaneSection.right = None + if (currentLaneSection.center.lane.isEmpty()) { + issueList += + DefaultIssue.of( + "NoLanesInLaneSection", + "Lane section does not contain lanes.", + currentLaneSection.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) + currentLaneSection.center.lane += RoadLanesLaneSectionCenterLane() } - } - if (currentLaneSection.center.lane.isEmpty()) { - issueList += DefaultIssue.of( - "NoLanesInLaneSection", - "Lane section does not contain lanes.", - currentLaneSection.additionalId, - Severity.FATAL_ERROR, - wasFixed = false - ) - currentLaneSection.center.lane += RoadLanesLaneSectionCenterLane() + currentLaneSection } - currentLaneSection - } - modifiedOpendriveModel = everyRoadLanesLaneSectionCenterLane.modify(modifiedOpendriveModel) { currentCenterLane -> issueList += evaluateNonFatalViolations(currentCenterLane, parameters) currentCenterLane } - modifiedOpendriveModel = everyRoadLanesLaneSectionLeftLane.modify(modifiedOpendriveModel) { currentLeftLane -> - issueList += evaluateNonFatalViolations(currentLeftLane, parameters) - currentLeftLane - } + modifiedOpendriveModel = + everyRoadLanesLaneSectionLeftLane.modify(modifiedOpendriveModel) { currentLeftLane -> + issueList += evaluateNonFatalViolations(currentLeftLane, parameters) + currentLeftLane + } - modifiedOpendriveModel = everyRoadLanesLaneSectionRightLane.modify(modifiedOpendriveModel) { currentRightLane -> - issueList += evaluateNonFatalViolations(currentRightLane, parameters) - currentRightLane - } + modifiedOpendriveModel = + everyRoadLanesLaneSectionRightLane.modify(modifiedOpendriveModel) { currentRightLane -> + issueList += evaluateNonFatalViolations(currentRightLane, parameters) + currentRightLane + } return modifiedOpendriveModel } private fun evaluateFatalViolations( lane: RoadLanesLaneSectionLRLane, - parameters: OpendriveEvaluatorParameters + parameters: OpendriveEvaluatorParameters, ): DefaultIssueList { val issueList = DefaultIssueList() return issueList @@ -122,103 +121,107 @@ object RoadLanesEvaluator { private fun evaluateNonFatalViolations( lane: RoadLanesLaneSectionLRLane, - parameters: OpendriveEvaluatorParameters + parameters: OpendriveEvaluatorParameters, ): DefaultIssueList { val issueList = DefaultIssueList() lane.getLaneWidthEntries().onSome { if (it.head.sOffset > parameters.numberTolerance) { - issueList += DefaultIssue.of( - "LaneWidthEntriesNotDefinedFromStart", - "The width of the lane shall be defined for the full length of the lane section starting with a element for s=0. The first available element is copied and positioned at s=0.", - lane.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "LaneWidthEntriesNotDefinedFromStart", + "The width of the lane shall be defined for the full length of the lane section starting with a " + + " element for s=0. The first available element is copied and positioned at s=0.", + lane.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) val firstEntry = it.head.copy().apply { sOffset = 0.0 } lane.width = listOf(firstEntry) + lane.width } } - lane.width = BasicDataTypeModifier.filterToStrictlySorted( - lane.width, - { it.sOffset }, - lane.additionalId, - "width", - issueList - ) + lane.width = + BasicDataTypeModifier.filterToStrictlySorted( + lane.width, + { it.sOffset }, + lane.additionalId, + "width", + issueList, + ) val widthEntriesFilteredBySOffsetFinite = lane.width.filter { currentWidth -> currentWidth.sOffset.isFinite() && currentWidth.sOffset >= 0.0 } if (widthEntriesFilteredBySOffsetFinite.size < lane.width.size) { - issueList += DefaultIssue.of( - "UnexpectedValues", - "Ignoring ${lane.width.size - widthEntriesFilteredBySOffsetFinite.size} width entries where sOffset is not-finite and positive.", - lane.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "UnexpectedValues", + "Ignoring ${lane.width.size - widthEntriesFilteredBySOffsetFinite.size} width entries where sOffset is " + + "not-finite and positive.", + lane.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) lane.width = widthEntriesFilteredBySOffsetFinite } val widthEntriesFilteredByCoefficientsFinite = lane.width.filter { currentWidth -> currentWidth.coefficients.all { it.isFinite() } } if (widthEntriesFilteredByCoefficientsFinite.size < lane.width.size) { - issueList += DefaultIssue.of( - "UnexpectedValues", - "Ignoring ${lane.width.size - widthEntriesFilteredByCoefficientsFinite.size} width entries where coefficients \"a, b, c, d\", are not finite.", - lane.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "UnexpectedValues", + "Ignoring ${lane.width.size - widthEntriesFilteredByCoefficientsFinite.size} width entries where " + + "coefficients \"a, b, c, d\", are not finite.", + lane.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) lane.width = widthEntriesFilteredByCoefficientsFinite } - lane.height = BasicDataTypeModifier.filterToStrictlySorted( - lane.height, - { it.sOffset }, - lane.additionalId, - "height", - issueList - ) + lane.height = + BasicDataTypeModifier.filterToStrictlySorted( + lane.height, + { it.sOffset }, + lane.additionalId, + "height", + issueList, + ) val heightEntriesFilteredByCoefficientsFinite = lane.height.filter { it.inner.isFinite() && it.outer.isFinite() } if (heightEntriesFilteredByCoefficientsFinite.size < lane.height.size) { - issueList += DefaultIssue.of( - "UnexpectedValues", - "Ignoring ${lane.height.size - heightEntriesFilteredByCoefficientsFinite.size} height entries where inner or outer is not finite.", - lane.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) + issueList += + DefaultIssue.of( + "UnexpectedValues", + "Ignoring ${lane.height.size - heightEntriesFilteredByCoefficientsFinite.size} height entries where inner or " + + "outer is not finite.", + lane.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) lane.height = heightEntriesFilteredByCoefficientsFinite } - lane.roadMark = BasicDataTypeModifier.filterToStrictlySorted( - lane.roadMark, - { it.sOffset }, - lane.additionalId, - "roadMark", - issueList - ) + lane.roadMark = + BasicDataTypeModifier.filterToStrictlySorted( + lane.roadMark, + { it.sOffset }, + lane.additionalId, + "roadMark", + issueList, + ) return issueList } private fun evaluateNonFatalViolations( lane: RoadLanesLaneSectionCenterLane, - parameters: OpendriveEvaluatorParameters + parameters: OpendriveEvaluatorParameters, ): DefaultIssueList { val issueList = DefaultIssueList() - lane.roadMark = BasicDataTypeModifier.filterToStrictlySorted( - lane.roadMark, - { it.sOffset }, - lane.additionalId, - "roadMark", - issueList - ) + lane.roadMark = + BasicDataTypeModifier.filterToStrictlySorted( + lane.roadMark, + { it.sOffset }, + lane.additionalId, + "roadMark", + issueList, + ) return issueList } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadObjectsEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadObjectsEvaluator.kt index 897d600f..312ee6b8 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadObjectsEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadObjectsEvaluator.kt @@ -32,189 +32,277 @@ import kotlin.math.max import kotlin.math.min object RoadObjectsEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() - modifiedOpendriveModel = everyRoadObject.modify(modifiedOpendriveModel) { currentRoadObject -> - - currentRoadObject.s = BasicDataTypeModifier.modifyToFinitePositiveDouble( - currentRoadObject.s, - currentRoadObject.additionalId, - "s", - issueList - ) - currentRoadObject.t = BasicDataTypeModifier.modifyToFiniteDouble( - currentRoadObject.t, - currentRoadObject.additionalId, - "t", - issueList - ) - currentRoadObject.zOffset = BasicDataTypeModifier.modifyToFiniteDouble( - currentRoadObject.zOffset, - currentRoadObject.additionalId, - "zOffset", - issueList - ) - currentRoadObject.hdg = BasicDataTypeModifier.modifyToOptionalFiniteDouble( - currentRoadObject.hdg, - currentRoadObject.additionalId, - "hdg", - issueList - ) - currentRoadObject.roll = BasicDataTypeModifier.modifyToOptionalFiniteDouble( - currentRoadObject.roll, - currentRoadObject.additionalId, - "roll", - issueList - ) - currentRoadObject.pitch = BasicDataTypeModifier.modifyToOptionalFiniteDouble( - currentRoadObject.pitch, - currentRoadObject.additionalId, - "pitch", - issueList - ) - currentRoadObject.height = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( - currentRoadObject.height, - currentRoadObject.additionalId, - "height", - issueList - ) - - if (currentRoadObject.height.isSome { 0.0 < it && it < parameters.numberTolerance }) { - currentRoadObject.height = parameters.numberTolerance.some() - } + modifiedOpendriveModel = + everyRoadObject.modify(modifiedOpendriveModel) { currentRoadObject -> - currentRoadObject.radius = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( - currentRoadObject.radius, - currentRoadObject.additionalId, - "radius", - issueList, - parameters.numberTolerance - ) - currentRoadObject.length = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( - currentRoadObject.length, - currentRoadObject.additionalId, - "length", - issueList, - parameters.numberTolerance - ) - currentRoadObject.width = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( - currentRoadObject.width, - currentRoadObject.additionalId, - "width", - issueList, - parameters.numberTolerance - ) - - currentRoadObject.validity.filter { it.fromLane > it.toLane }.forEach { currentValidity -> - issueList += DefaultIssue.of( - "LaneValidityElementNotOrdered", - "The value of the @fromLane attribute shall be lower than or equal to the value of the @toLane attribute.", - currentRoadObject.additionalId, - Severity.ERROR, - wasFixed = true - ) - currentValidity.fromLane = min(currentValidity.fromLane, currentValidity.toLane) - currentValidity.toLane = max(currentValidity.fromLane, currentValidity.toLane) - } + currentRoadObject.s = + BasicDataTypeModifier.modifyToFinitePositiveDouble( + currentRoadObject.s, + currentRoadObject.additionalId, + "s", + issueList, + ) + currentRoadObject.t = + BasicDataTypeModifier.modifyToFiniteDouble( + currentRoadObject.t, + currentRoadObject.additionalId, + "t", + issueList, + ) + currentRoadObject.zOffset = + BasicDataTypeModifier.modifyToFiniteDouble( + currentRoadObject.zOffset, + currentRoadObject.additionalId, + "zOffset", + issueList, + ) + currentRoadObject.hdg = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + currentRoadObject.hdg, + currentRoadObject.additionalId, + "hdg", + issueList, + ) + currentRoadObject.roll = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + currentRoadObject.roll, + currentRoadObject.additionalId, + "roll", + issueList, + ) + currentRoadObject.pitch = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + currentRoadObject.pitch, + currentRoadObject.additionalId, + "pitch", + issueList, + ) + currentRoadObject.height = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRoadObject.height, + currentRoadObject.additionalId, + "height", + issueList, + ) - if (currentRoadObject.outlines.isSome { it.outline.isEmpty() }) { - issueList += DefaultIssue( - "EmptyValueForOptionalAttribute", - "Attribute 'outlines' is set with an empty value even though the attribute itself is optional.", - "Header element", - Severity.WARNING, - wasFixed = true - ) - currentRoadObject.outlines = None - } + if (currentRoadObject.height.isSome { 0.0 < it && it < parameters.numberTolerance }) { + currentRoadObject.height = parameters.numberTolerance.some() + } - val repeatElementsFiltered = - currentRoadObject.repeat.filter { it.s.isFinite() && it.tStart.isFinite() && it.zOffsetStart.isFinite() } - if (repeatElementsFiltered.size < currentRoadObject.repeat.size) { - issueList += DefaultIssue.of( - "UnexpectedValues", - "Ignoring ${currentRoadObject.repeat.size - repeatElementsFiltered.size} repeat entries which do not have a finite s, tStart, zOffsetStart value.", - currentRoadObject.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) - // issueList += OpendriveException.UnexpectedValues("s, tStart, zOffsetStart", "Ignoring ${currentRoadObject.repeat.size - repeatElementsFiltered.size} repeat entries which do not have a finite s, tStart and zOffsetStart value.").toIssue(currentRoadObject.additionalId, isFatal = false, wasFixed: Boolean) - currentRoadObject.repeat = repeatElementsFiltered - } + currentRoadObject.radius = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRoadObject.radius, + currentRoadObject.additionalId, + "radius", + issueList, + parameters.numberTolerance, + ) + currentRoadObject.length = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRoadObject.length, + currentRoadObject.additionalId, + "length", + issueList, + parameters.numberTolerance, + ) + currentRoadObject.width = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRoadObject.width, + currentRoadObject.additionalId, + "width", + issueList, + parameters.numberTolerance, + ) - currentRoadObject - } + currentRoadObject.validity.filter { it.fromLane > it.toLane }.forEach { currentValidity -> + issueList += + DefaultIssue.of( + "LaneValidityElementNotOrdered", + "The value of the @fromLane attribute shall be lower than or equal to the value of the @toLane attribute.", + currentRoadObject.additionalId, Severity.ERROR, wasFixed = true, + ) + currentValidity.fromLane = min(currentValidity.fromLane, currentValidity.toLane) + currentValidity.toLane = max(currentValidity.fromLane, currentValidity.toLane) + } - modifiedOpendriveModel = everyRoadObjectOutlineElement.modify(modifiedOpendriveModel) { currentOutlineElement -> + if (currentRoadObject.outlines.isSome { it.outline.isEmpty() }) { + issueList += + DefaultIssue( + "EmptyValueForOptionalAttribute", + "Attribute 'outlines' is set with an empty value even though the attribute itself is optional.", + "Header element", Severity.WARNING, wasFixed = true, + ) + currentRoadObject.outlines = None + } - val cornerRoadElementsFiltered = currentOutlineElement.cornerRoad.filter { it.s.isFinite() && it.t.isFinite() && it.dz.isFinite() } - if (cornerRoadElementsFiltered.size < currentOutlineElement.cornerRoad.size) { - // issueList += OpendriveException.UnexpectedValues("s, t, dz", "Ignoring ${currentOutlineElement.cornerRoad.size - cornerRoadElementsFiltered.size} cornerRoad entries which do not have a finite s, t and dz value.").toIssue(currentOutlineElement.additionalId, isFatal = false, wasFixed: Boolean) - issueList += DefaultIssue.of("UnexpectedValues", "Ignoring ${currentOutlineElement.cornerRoad.size - cornerRoadElementsFiltered.size} cornerRoad entries which do not have a finite s, t and dz value.", currentOutlineElement.additionalId, Severity.FATAL_ERROR, wasFixed = true) + val repeatElementsFiltered = + currentRoadObject.repeat.filter { it.s.isFinite() && it.tStart.isFinite() && it.zOffsetStart.isFinite() } + if (repeatElementsFiltered.size < currentRoadObject.repeat.size) { + issueList += + DefaultIssue.of( + "UnexpectedValues", + "Ignoring ${currentRoadObject.repeat.size - repeatElementsFiltered.size} repeat entries which do not " + + "have a finite s, tStart, zOffsetStart value.", + currentRoadObject.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) + // issueList += OpendriveException.UnexpectedValues("s, tStart, zOffsetStart", + // "Ignoring ${currentRoadObject.repeat.size - repeatElementsFiltered.size} repeat entries which do not have a + // finite s, tStart and zOffsetStart value.").toIssue(currentRoadObject.additionalId, + // isFatal = false, wasFixed: Boolean) + currentRoadObject.repeat = repeatElementsFiltered + } - currentOutlineElement.cornerRoad = cornerRoadElementsFiltered + currentRoadObject } - currentOutlineElement.cornerRoad.forEach { currentCornerRoad -> - if (!currentCornerRoad.height.isFinite() || currentCornerRoad.height < 0.0) { - issueList += DefaultIssue.of("UnexpectedValue", "Unexpected value for attribute 'height'", currentOutlineElement.additionalId, Severity.WARNING, wasFixed = true) - currentCornerRoad.height = 0.0 - } + modifiedOpendriveModel = + everyRoadObjectOutlineElement.modify(modifiedOpendriveModel) { currentOutlineElement -> + + val cornerRoadElementsFiltered = + currentOutlineElement.cornerRoad.filter { it.s.isFinite() && it.t.isFinite() && it.dz.isFinite() } + if (cornerRoadElementsFiltered.size < currentOutlineElement.cornerRoad.size) { + // issueList += OpendriveException.UnexpectedValues("s, t, dz", + // "Ignoring ${currentOutlineElement.cornerRoad.size - cornerRoadElementsFiltered.size} cornerRoad entries which + // do not have a finite s, t and dz value.").toIssue(currentOutlineElement.additionalId, + // isFatal = false, wasFixed: Boolean) + issueList += + DefaultIssue.of( + "UnexpectedValues", + "Ignoring ${currentOutlineElement.cornerRoad.size - cornerRoadElementsFiltered.size} cornerRoad entries " + + "which do not have a finite s, t and dz value.", + currentOutlineElement.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) - if (0.0 < currentCornerRoad.height && currentCornerRoad.height <= parameters.numberTolerance) { - currentCornerRoad.height = 0.0 + currentOutlineElement.cornerRoad = cornerRoadElementsFiltered } - } - val cornerLocalElementsFiltered = currentOutlineElement.cornerLocal.filter { it.u.isFinite() && it.v.isFinite() && it.z.isFinite() } - if (cornerLocalElementsFiltered.size < currentOutlineElement.cornerLocal.size) { - // issueList += OpendriveException.UnexpectedValues("s, t, dz", "Ignoring ${currentOutlineElement.cornerLocal.size - cornerLocalElementsFiltered.size} cornerLocal entries which do not have a finite u, v and z value.").toIssue(currentOutlineElement.additionalId, isFatal = false, wasFixed = true) - issueList += DefaultIssue.of("UnexpectedValues", "Ignoring ${currentOutlineElement.cornerRoad.size - cornerRoadElementsFiltered.size} cornerRoad entries which do not have a finite s, t and dz value.", currentOutlineElement.additionalId, Severity.FATAL_ERROR, wasFixed = true) + currentOutlineElement.cornerRoad.forEach { currentCornerRoad -> + if (!currentCornerRoad.height.isFinite() || currentCornerRoad.height < 0.0) { + issueList += + DefaultIssue.of( + "UnexpectedValue", "Unexpected value for attribute 'height'", + currentOutlineElement.additionalId, Severity.WARNING, wasFixed = true, + ) + currentCornerRoad.height = 0.0 + } - currentOutlineElement.cornerLocal = cornerLocalElementsFiltered - } + if (0.0 < currentCornerRoad.height && currentCornerRoad.height <= parameters.numberTolerance) { + currentCornerRoad.height = 0.0 + } + } - currentOutlineElement.cornerLocal.forEach { currentCornerLocal -> - if (!currentCornerLocal.height.isFinite() || currentCornerLocal.height < 0.0) { - issueList += DefaultIssue.of("UnexpectedValue", "Unexpected value for attribute 'height'", currentOutlineElement.additionalId, Severity.WARNING, wasFixed = true) - currentCornerLocal.height = 0.0 + val cornerLocalElementsFiltered = + currentOutlineElement.cornerLocal.filter { it.u.isFinite() && it.v.isFinite() && it.z.isFinite() } + if (cornerLocalElementsFiltered.size < currentOutlineElement.cornerLocal.size) { + // issueList += OpendriveException.UnexpectedValues("s, t, dz", + // "Ignoring ${currentOutlineElement.cornerLocal.size - cornerLocalElementsFiltered.size} cornerLocal entries which + // do not have a finite u, v and z value.").toIssue(currentOutlineElement.additionalId, + // isFatal = false, wasFixed = true) + issueList += + DefaultIssue.of( + "UnexpectedValues", + "Ignoring ${currentOutlineElement.cornerRoad.size - cornerRoadElementsFiltered.size} cornerRoad entries " + + "which do not have a finite s, t and dz value.", + currentOutlineElement.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) + + currentOutlineElement.cornerLocal = cornerLocalElementsFiltered } - if (0.0 < currentCornerLocal.height && currentCornerLocal.height <= parameters.numberTolerance) { - currentCornerLocal.height = 0.0 + currentOutlineElement.cornerLocal.forEach { currentCornerLocal -> + if (!currentCornerLocal.height.isFinite() || currentCornerLocal.height < 0.0) { + issueList += + DefaultIssue.of( + "UnexpectedValue", "Unexpected value for attribute 'height'", + currentOutlineElement.additionalId, Severity.WARNING, wasFixed = true, + ) + currentCornerLocal.height = 0.0 + } + + if (0.0 < currentCornerLocal.height && currentCornerLocal.height <= parameters.numberTolerance) { + currentCornerLocal.height = 0.0 + } } - } - currentOutlineElement - } - - modifiedOpendriveModel = everyRoadObjectRepeatElement.modify(modifiedOpendriveModel) { currentRepeatElement -> - require(currentRepeatElement.s.isFinite()) { "Must already be filtered." } - require(currentRepeatElement.tStart.isFinite()) { "Must already be filtered." } - require(currentRepeatElement.zOffsetStart.isFinite()) { "Must already be filtered." } - - currentRepeatElement.distance = BasicDataTypeModifier.modifyToFinitePositiveDouble(currentRepeatElement.distance, currentRepeatElement.additionalId, "distance", issueList) - currentRepeatElement.heightEnd = BasicDataTypeModifier.modifyToFinitePositiveDouble(currentRepeatElement.heightEnd, currentRepeatElement.additionalId, "heightEnd", issueList) - currentRepeatElement.heightStart = BasicDataTypeModifier.modifyToFinitePositiveDouble(currentRepeatElement.heightStart, currentRepeatElement.additionalId, "heightStart", issueList) - currentRepeatElement.length = BasicDataTypeModifier.modifyToFinitePositiveDouble(currentRepeatElement.length, currentRepeatElement.additionalId, "length", issueList) - currentRepeatElement.lengthEnd = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble(currentRepeatElement.lengthEnd, currentRepeatElement.additionalId, "lengthEnd", issueList, parameters.numberTolerance) - currentRepeatElement.lengthStart = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble(currentRepeatElement.lengthStart, currentRepeatElement.additionalId, "lengthStart", issueList, parameters.numberTolerance) - currentRepeatElement.radiusEnd = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble(currentRepeatElement.radiusEnd, currentRepeatElement.additionalId, "radiusEnd", issueList, parameters.numberTolerance) - currentRepeatElement.radiusStart = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble(currentRepeatElement.radiusStart, currentRepeatElement.additionalId, "radiusStart", issueList, parameters.numberTolerance) - - if (!currentRepeatElement.tEnd.isFinite()) { - issueList += DefaultIssue.of("UnexpectedValue", "Unexpected value for attribute 'tEnd'", currentRepeatElement.additionalId, Severity.WARNING, wasFixed = true) - currentRepeatElement.tEnd = currentRepeatElement.tStart + currentOutlineElement } - currentRepeatElement.widthEnd = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble(currentRepeatElement.widthEnd, currentRepeatElement.additionalId, "widthEnd", issueList, parameters.numberTolerance) - currentRepeatElement.widthStart = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble(currentRepeatElement.widthStart, currentRepeatElement.additionalId, "widthStart", issueList, parameters.numberTolerance) - currentRepeatElement.zOffsetEnd = BasicDataTypeModifier.modifyToFiniteDouble(currentRepeatElement.zOffsetEnd, currentRepeatElement.additionalId, "zOffsetEnd", issueList) - currentRepeatElement - } + modifiedOpendriveModel = + everyRoadObjectRepeatElement.modify(modifiedOpendriveModel) { currentRepeatElement -> + require(currentRepeatElement.s.isFinite()) { "Must already be filtered." } + require(currentRepeatElement.tStart.isFinite()) { "Must already be filtered." } + require(currentRepeatElement.zOffsetStart.isFinite()) { "Must already be filtered." } + + currentRepeatElement.distance = + BasicDataTypeModifier.modifyToFinitePositiveDouble( + currentRepeatElement.distance, currentRepeatElement.additionalId, "distance", issueList, + ) + currentRepeatElement.heightEnd = + BasicDataTypeModifier.modifyToFinitePositiveDouble( + currentRepeatElement.heightEnd, currentRepeatElement.additionalId, "heightEnd", issueList, + ) + currentRepeatElement.heightStart = + BasicDataTypeModifier.modifyToFinitePositiveDouble( + currentRepeatElement.heightStart, currentRepeatElement.additionalId, "heightStart", issueList, + ) + currentRepeatElement.length = + BasicDataTypeModifier.modifyToFinitePositiveDouble( + currentRepeatElement.length, currentRepeatElement.additionalId, "length", issueList, + ) + currentRepeatElement.lengthEnd = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRepeatElement.lengthEnd, currentRepeatElement.additionalId, "lengthEnd", issueList, + parameters.numberTolerance, + ) + currentRepeatElement.lengthStart = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRepeatElement.lengthStart, currentRepeatElement.additionalId, "lengthStart", issueList, + parameters.numberTolerance, + ) + currentRepeatElement.radiusEnd = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRepeatElement.radiusEnd, currentRepeatElement.additionalId, "radiusEnd", issueList, + parameters.numberTolerance, + ) + currentRepeatElement.radiusStart = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRepeatElement.radiusStart, currentRepeatElement.additionalId, "radiusStart", issueList, + parameters.numberTolerance, + ) + + if (!currentRepeatElement.tEnd.isFinite()) { + issueList += + DefaultIssue.of( + "UnexpectedValue", "Unexpected value for attribute 'tEnd'", + currentRepeatElement.additionalId, Severity.WARNING, wasFixed = true, + ) + currentRepeatElement.tEnd = currentRepeatElement.tStart + } + currentRepeatElement.widthEnd = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRepeatElement.widthEnd, currentRepeatElement.additionalId, "widthEnd", issueList, + parameters.numberTolerance, + ) + currentRepeatElement.widthStart = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRepeatElement.widthStart, currentRepeatElement.additionalId, "widthStart", issueList, + parameters.numberTolerance, + ) + currentRepeatElement.zOffsetEnd = + BasicDataTypeModifier.modifyToFiniteDouble( + currentRepeatElement.zOffsetEnd, currentRepeatElement.additionalId, "zOffsetEnd", issueList, + ) + + currentRepeatElement + } return modifiedOpendriveModel } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadSignalsEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadSignalsEvaluator.kt index c6b38ace..8dcabc57 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadSignalsEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/basicdatatype/RoadSignalsEvaluator.kt @@ -30,38 +30,87 @@ import kotlin.math.max import kotlin.math.min object RoadSignalsEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() - modifiedOpendriveModel = everyRoadSignal.modify(modifiedOpendriveModel) { currentRoadSignal -> + modifiedOpendriveModel = + everyRoadSignal.modify(modifiedOpendriveModel) { currentRoadSignal -> - currentRoadSignal.height = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble(currentRoadSignal.height, currentRoadSignal.additionalId, "height", issueList, parameters.numberTolerance) - currentRoadSignal.hOffset = BasicDataTypeModifier.modifyToOptionalFiniteDouble(currentRoadSignal.hOffset, currentRoadSignal.additionalId, "hOffset", issueList) - currentRoadSignal.pitch = BasicDataTypeModifier.modifyToOptionalFiniteDouble(currentRoadSignal.pitch, currentRoadSignal.additionalId, "pitch", issueList) - currentRoadSignal.roll = BasicDataTypeModifier.modifyToOptionalFiniteDouble(currentRoadSignal.roll, currentRoadSignal.additionalId, "roll", issueList) - currentRoadSignal.s = BasicDataTypeModifier.modifyToFinitePositiveDouble(currentRoadSignal.s, currentRoadSignal.additionalId, "s", issueList) - currentRoadSignal.subtype = BasicDataTypeModifier.modifyToNonBlankString(currentRoadSignal.subtype, currentRoadSignal.additionalId, "subtype", issueList, fallbackValue = "-1") - currentRoadSignal.t = BasicDataTypeModifier.modifyToFiniteDouble(currentRoadSignal.t, currentRoadSignal.additionalId, "t", issueList) - currentRoadSignal.type = BasicDataTypeModifier.modifyToNonBlankString(currentRoadSignal.type, currentRoadSignal.additionalId, "type", issueList, fallbackValue = "-1") - currentRoadSignal.value = BasicDataTypeModifier.modifyToOptionalFiniteDouble(currentRoadSignal.value, currentRoadSignal.additionalId, "value", issueList) + currentRoadSignal.height = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRoadSignal.height, currentRoadSignal.additionalId, "height", issueList, parameters.numberTolerance, + ) + currentRoadSignal.hOffset = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + currentRoadSignal.hOffset, currentRoadSignal.additionalId, "hOffset", issueList, + ) + currentRoadSignal.pitch = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + currentRoadSignal.pitch, currentRoadSignal.additionalId, "pitch", issueList, + ) + currentRoadSignal.roll = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + currentRoadSignal.roll, currentRoadSignal.additionalId, "roll", issueList, + ) + currentRoadSignal.s = + BasicDataTypeModifier.modifyToFinitePositiveDouble( + currentRoadSignal.s, currentRoadSignal.additionalId, "s", issueList, + ) + currentRoadSignal.subtype = + BasicDataTypeModifier.modifyToNonBlankString( + currentRoadSignal.subtype, currentRoadSignal.additionalId, "subtype", issueList, fallbackValue = "-1", + ) + currentRoadSignal.t = + BasicDataTypeModifier.modifyToFiniteDouble( + currentRoadSignal.t, currentRoadSignal.additionalId, "t", issueList, + ) + currentRoadSignal.type = + BasicDataTypeModifier.modifyToNonBlankString( + currentRoadSignal.type, currentRoadSignal.additionalId, "type", issueList, fallbackValue = "-1", + ) + currentRoadSignal.value = + BasicDataTypeModifier.modifyToOptionalFiniteDouble( + currentRoadSignal.value, currentRoadSignal.additionalId, "value", issueList, + ) - if (currentRoadSignal.value.isSome() && currentRoadSignal.unit.isNone()) { - issueList += DefaultIssue.of("UnitAttributeMustBeDefinedWhenValueAttributeIsDefined", "Attribute 'unit' shall be defined, when attribute 'value' is defined.", currentRoadSignal.additionalId, Severity.WARNING, wasFixed = true) - currentRoadSignal.unit = EUnit.KILOMETER_PER_HOUR.some() - } - currentRoadSignal.width = BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble(currentRoadSignal.width, currentRoadSignal.additionalId, "width", issueList, parameters.numberTolerance) - currentRoadSignal.zOffset = BasicDataTypeModifier.modifyToFiniteDouble(currentRoadSignal.zOffset, currentRoadSignal.additionalId, "zOffset", issueList) + if (currentRoadSignal.value.isSome() && currentRoadSignal.unit.isNone()) { + issueList += + DefaultIssue.of( + "UnitAttributeMustBeDefinedWhenValueAttributeIsDefined", + "Attribute 'unit' shall be defined, when attribute 'value' is defined.", + currentRoadSignal.additionalId, Severity.WARNING, wasFixed = true, + ) + currentRoadSignal.unit = EUnit.KILOMETER_PER_HOUR.some() + } + currentRoadSignal.width = + BasicDataTypeModifier.modifyToOptionalFinitePositiveDouble( + currentRoadSignal.width, + currentRoadSignal.additionalId, "width", issueList, parameters.numberTolerance, + ) + currentRoadSignal.zOffset = + BasicDataTypeModifier.modifyToFiniteDouble( + currentRoadSignal.zOffset, + currentRoadSignal.additionalId, "zOffset", issueList, + ) - currentRoadSignal.validity.filter { it.fromLane > it.toLane }.forEach { currentValidity -> - issueList += DefaultIssue.of("LaneValidityElementNotOrdered", "The value of the @fromLane attribute shall be lower than or equal to the value of the @toLane attribute.", currentRoadSignal.additionalId, Severity.ERROR, wasFixed = true) - currentValidity.fromLane = min(currentValidity.fromLane, currentValidity.toLane) - currentValidity.toLane = max(currentValidity.fromLane, currentValidity.toLane) - } + currentRoadSignal.validity.filter { it.fromLane > it.toLane }.forEach { currentValidity -> + issueList += + DefaultIssue.of( + "LaneValidityElementNotOrdered", + "The value of the @fromLane attribute shall be lower than or equal to the value of the @toLane attribute.", + currentRoadSignal.additionalId, Severity.ERROR, wasFixed = true, + ) + currentValidity.fromLane = min(currentValidity.fromLane, currentValidity.toLane) + currentValidity.toLane = max(currentValidity.fromLane, currentValidity.toLane) + } - currentRoadSignal - } + currentRoadSignal + } return modifiedOpendriveModel } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/conversionrequirements/ConversionRequirementsEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/conversionrequirements/ConversionRequirementsEvaluator.kt index 3b64190f..217fb315 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/conversionrequirements/ConversionRequirementsEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/conversionrequirements/ConversionRequirementsEvaluator.kt @@ -23,7 +23,6 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.evaluator.opendrive.plans.AbstractOpendriveEvaluator class ConversionRequirementsEvaluator(val parameters: OpendriveEvaluatorParameters) : AbstractOpendriveEvaluator() { - // Methods override fun evaluate(opendriveModel: OpendriveModel): ContextIssueList { val issueList = DefaultIssueList() diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/conversionrequirements/JunctionEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/conversionrequirements/JunctionEvaluator.kt index 61b03ac2..1e71a959 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/conversionrequirements/JunctionEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/conversionrequirements/JunctionEvaluator.kt @@ -26,23 +26,41 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.issues.opendrive.of object JunctionEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() - modifiedOpendriveModel = everyJunction.modify(modifiedOpendriveModel) { currentJunction -> + modifiedOpendriveModel = + everyJunction.modify(modifiedOpendriveModel) { currentJunction -> - if (currentJunction.typeValidated == EJunctionType.DEFAULT && currentJunction.connection.any { it.incomingRoad.isNone() }) { - issueList += DefaultIssue.of("DefaultJunctionWithoutIncomingRoad", "Junction of type default has no connection with an incoming road.", currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = false) - } + if (currentJunction.typeValidated == EJunctionType.DEFAULT && + currentJunction.connection.any { it.incomingRoad.isNone() } + ) { + issueList += + DefaultIssue.of( + "DefaultJunctionWithoutIncomingRoad", + "Junction of type default has no connection with an incoming road.", + currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) + } - if (currentJunction.typeValidated == EJunctionType.DEFAULT && currentJunction.connection.any { it.connectingRoad.isNone() }) { - issueList += DefaultIssue.of("DefaultJunctionWithoutConnectingRoad", "Junction of type default has no connection with a connecting road.", currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = false) - } + if (currentJunction.typeValidated == EJunctionType.DEFAULT && + currentJunction.connection.any { it.connectingRoad.isNone() } + ) { + issueList += + DefaultIssue.of( + "DefaultJunctionWithoutConnectingRoad", + "Junction of type default has no connection with a connecting road.", + currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) + } - currentJunction - } + currentJunction + } return modifiedOpendriveModel } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/JunctionEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/JunctionEvaluator.kt index fbba4b94..0446d431 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/JunctionEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/JunctionEvaluator.kt @@ -28,9 +28,12 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.issues.opendrive.of object JunctionEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() modifiedOpendriveModel = evaluateAllJunctions(modifiedOpendriveModel, parameters, issueList) @@ -39,115 +42,141 @@ object JunctionEvaluator { return modifiedOpendriveModel } - private fun evaluateAllJunctions(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + private fun evaluateAllJunctions( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() - modifiedOpendriveModel = everyJunction.modify(modifiedOpendriveModel) { currentJunction -> - - // It is deprecated to omit the element. - val junctionConnectionsFiltered = currentJunction.connection.filter { it.laneLink.isNotEmpty() } - if (currentJunction.connection.size > junctionConnectionsFiltered.size) { - issueList += DefaultIssue.of("JunctionConnectionWithoutLaneLinks", "Junction connections (number of connections: ${currentJunction.connection.size - junctionConnectionsFiltered.size}) were removed since they did not contain any laneLinks.", currentJunction.additionalId, Severity.ERROR, wasFixed = true) - } - currentJunction.connection = junctionConnectionsFiltered - - // The @mainRoad, @orientation, @sStart and @sEnd attributes shall only be specified for virtual junctions. - if (currentJunction.typeValidated != EJunctionType.VIRTUAL) { - currentJunction.mainRoad.onSome { - issueList += DefaultIssue.of( - "InvalidJunctionAttribute", - "Attribute 'mainRoad' shall only be specified for virtual junctions", - currentJunction.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) - currentJunction.mainRoad = None + modifiedOpendriveModel = + everyJunction.modify(modifiedOpendriveModel) { currentJunction -> + + // It is deprecated to omit the element. + val junctionConnectionsFiltered = currentJunction.connection.filter { it.laneLink.isNotEmpty() } + if (currentJunction.connection.size > junctionConnectionsFiltered.size) { + issueList += + DefaultIssue.of( + "JunctionConnectionWithoutLaneLinks", + "Junction connections (number of connections: ${currentJunction.connection.size - + junctionConnectionsFiltered.size}) were removed since they did not contain any laneLinks.", + currentJunction.additionalId, Severity.ERROR, wasFixed = true, + ) } - - currentJunction.orientation.onSome { - issueList += DefaultIssue.of( - "InvalidJunctionAttribute", - "Attribute 'orientation' shall only be specified for virtual junctions", - currentJunction.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) - currentJunction.orientation = None + currentJunction.connection = junctionConnectionsFiltered + + // The @mainRoad, @orientation, @sStart and @sEnd attributes shall only be specified for virtual junctions. + if (currentJunction.typeValidated != EJunctionType.VIRTUAL) { + currentJunction.mainRoad.onSome { + issueList += + DefaultIssue.of( + "InvalidJunctionAttribute", + "Attribute 'mainRoad' shall only be specified for virtual junctions", + currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) + currentJunction.mainRoad = None + } + + currentJunction.orientation.onSome { + issueList += + DefaultIssue.of( + "InvalidJunctionAttribute", + "Attribute 'orientation' shall only be specified for virtual junctions", + currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) + currentJunction.orientation = None + } + + currentJunction.sStart.onSome { + issueList += + DefaultIssue.of( + "InvalidJunctionAttribute", + "Attribute 'sStart' shall only be specified for virtual junctions", + currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) + currentJunction.sStart = None + } + + currentJunction.sEnd.onSome { + issueList += + DefaultIssue.of( + "InvalidJunctionAttribute", + "Attribute 'sEnd' shall only be specified for virtual junctions", + currentJunction.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) + currentJunction.sEnd = None + } } - currentJunction.sStart.onSome { - issueList += DefaultIssue.of( - "InvalidJunctionAttribute", - "Attribute 'sStart' shall only be specified for virtual junctions", - currentJunction.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) - currentJunction.sStart = None - } - - currentJunction.sEnd.onSome { - issueList += DefaultIssue.of( - "InvalidJunctionAttribute", - "Attribute 'sEnd' shall only be specified for virtual junctions", - currentJunction.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) - currentJunction.sEnd = None - } + currentJunction } - currentJunction - } - return modifiedOpendriveModel } - private fun evaluateDirectJunctions(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + private fun evaluateDirectJunctions( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() - modifiedOpendriveModel = everyJunction.modify(modifiedOpendriveModel) { currentJunction -> - if (currentJunction.typeValidated != EJunctionType.DIRECT) { - return@modify currentJunction - } + modifiedOpendriveModel = + everyJunction.modify(modifiedOpendriveModel) { currentJunction -> + if (currentJunction.typeValidated != EJunctionType.DIRECT) { + return@modify currentJunction + } - // Each connecting road shall be represented by exactly one element. A connecting road may contain as many lanes as required. - val connectingRoadIdsRepresentedByMultipleConnections = currentJunction.connection.map { it.connectingRoad }.flattenOption().groupingBy { it }.eachCount().filter { it.value > 1 } - if (connectingRoadIdsRepresentedByMultipleConnections.isNotEmpty()) { - issueList += DefaultIssue.of( - "MultipleConnectionsRepresentingSameConnectionRoad", - "Junctions contains multiple connections representing the same connecting road (affected connecting roads: ${connectingRoadIdsRepresentedByMultipleConnections.keys.joinToString()} )", - currentJunction.additionalId, - Severity.ERROR, - wasFixed = false - ) - } + // Each connecting road shall be represented by exactly one element. A connecting road may + // contain as many lanes as required. + val connectingRoadIdsRepresentedByMultipleConnections = + currentJunction.connection.map { + it.connectingRoad + }.flattenOption().groupingBy { it }.eachCount().filter { it.value > 1 } + if (connectingRoadIdsRepresentedByMultipleConnections.isNotEmpty()) { + issueList += + DefaultIssue.of( + "MultipleConnectionsRepresentingSameConnectionRoad", + "Junctions contains multiple connections representing the same connecting road (affected " + + "connecting roads: ${connectingRoadIdsRepresentedByMultipleConnections.keys.joinToString()} )", + currentJunction.additionalId, Severity.ERROR, wasFixed = false, + ) + } - // Junctions shall only be used when roads cannot be linked directly. They clarify ambiguities for the linking. Ambiguities are caused when a road has two or more possible predecessor or successor roads. - // see: https://github.com/tum-gis/rtron/issues/24 - data class ConnectionRoadIds(val connectingRoadId: String, val predecessorRoadId: String, val successorRoadId: String) - val junctionConnectionRoadIds = currentJunction.connection - .map { it.connectingRoad } - .flattenOption() - .map { opendriveModel.getRoad(it) } - .flattenOption() - .map { - ConnectionRoadIds( - connectingRoadId = it.id, - predecessorRoadId = it.link.flatMap { it.predecessor }.flatMap { it.getRoadPredecessorSuccessor() } - .getOrNull()!!.first, - successorRoadId = it.link.flatMap { it.successor }.flatMap { it.getRoadPredecessorSuccessor() } - .getOrNull()!!.first - ) + // Junctions shall only be used when roads cannot be linked directly. They clarify ambiguities for the linking. + // Ambiguities are caused when a road has two or more possible predecessor or successor roads. + // see: https://github.com/tum-gis/rtron/issues/24 + data class ConnectionRoadIds(val connectingRoadId: String, val predecessorRoadId: String, val successorRoadId: String) + val junctionConnectionRoadIds = + currentJunction.connection + .map { it.connectingRoad } + .flattenOption() + .map { opendriveModel.getRoad(it) } + .flattenOption() + .map { + ConnectionRoadIds( + connectingRoadId = it.id, + predecessorRoadId = + it.link.flatMap { it.predecessor }.flatMap { it.getRoadPredecessorSuccessor() } + .getOrNull()!!.first, + successorRoadId = + it.link.flatMap { it.successor }.flatMap { it.getRoadPredecessorSuccessor() } + .getOrNull()!!.first, + ) + } + val predecessorSuccessorRoadIds = junctionConnectionRoadIds.flatMap { listOf(it.predecessorRoadId, it.successorRoadId) } + if (predecessorSuccessorRoadIds.distinct().size < predecessorSuccessorRoadIds.size) { + issueList += + DefaultIssue.of( + "InvalidJunctionUsage", + "Junction shall not be used, since all roads can be " + + "directly linked without ambiguities. The connecting roads do not share a predecessor or successor road.", + currentJunction.additionalId, Severity.ERROR, wasFixed = false, + ) } - val predecessorSuccessorRoadIds = junctionConnectionRoadIds.flatMap { listOf(it.predecessorRoadId, it.successorRoadId) } - if (predecessorSuccessorRoadIds.distinct().size < predecessorSuccessorRoadIds.size) { - issueList += DefaultIssue.of("InvalidJunctionUsage", "Junction shall not be used, since all roads can be directly linked without ambiguities. The connecting roads do not share a predecessor or successor road.", currentJunction.additionalId, Severity.ERROR, wasFixed = false) - } - currentJunction - } + currentJunction + } return modifiedOpendriveModel } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/ModelingRulesEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/ModelingRulesEvaluator.kt index 9eccb40b..169c0833 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/ModelingRulesEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/ModelingRulesEvaluator.kt @@ -23,7 +23,6 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.evaluator.opendrive.plans.AbstractOpendriveEvaluator class ModelingRulesEvaluator(val parameters: OpendriveEvaluatorParameters) : AbstractOpendriveEvaluator() { - // Methods override fun evaluate(opendriveModel: OpendriveModel): ContextIssueList { val issueList = DefaultIssueList() diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadEvaluator.kt index 9d4dc5e9..aed43c44 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadEvaluator.kt @@ -29,189 +29,215 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.issues.opendrive.of object RoadEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() everyRoad.modify(modifiedOpendriveModel) { currentRoad -> if (currentRoad.planView.geometry.any { it.s > currentRoad.length + parameters.numberTolerance }) { - issueList += DefaultIssue.of("PlanViewGeometrySValueExceedsRoadLength", "Road contains geometry elements in the plan view, where s exceeds the total length of the road (${currentRoad.length}).", currentRoad.additionalId, Severity.WARNING, wasFixed = false) + issueList += + DefaultIssue.of( + "PlanViewGeometrySValueExceedsRoadLength", + "Road contains geometry elements in the plan view, where s exceeds the total length of the road " + + "(${currentRoad.length}).", + currentRoad.additionalId, Severity.WARNING, wasFixed = false, + ) } currentRoad } - modifiedOpendriveModel = everyRoad.modify(modifiedOpendriveModel) { currentRoad -> - // TODO: consolidate location handling - - if (currentRoad.planView.geometry.any { it.length <= parameters.numberTolerance }) { - issueList += DefaultIssue.of( - "PlanViewGeometryElementZeroLength", - "Plan view contains geometry elements with a length of zero (below tolerance threshold), which are removed.", - currentRoad.additionalId, - Severity.WARNING, - wasFixed = true - ) - currentRoad.planView.geometry = - currentRoad.planView.geometry.filter { it.length > parameters.numberTolerance } - } + modifiedOpendriveModel = + everyRoad.modify(modifiedOpendriveModel) { currentRoad -> + // TODO: consolidate location handling + + if (currentRoad.planView.geometry.any { it.length <= parameters.numberTolerance }) { + issueList += + DefaultIssue.of( + "PlanViewGeometryElementZeroLength", + "Plan view contains geometry elements with a length of zero (below tolerance threshold), " + + "which are removed.", + currentRoad.additionalId, Severity.WARNING, wasFixed = true, + ) + currentRoad.planView.geometry = + currentRoad.planView.geometry.filter { it.length > parameters.numberTolerance } + } - currentRoad - } + currentRoad + } - modifiedOpendriveModel.road = modifiedOpendriveModel.road.filter { currentRoad -> - if (currentRoad.planView.geometry.isEmpty()) { - issueList += DefaultIssue.of( - "RoadWithoutValidPlanViewGeometryElement", - "Road does not contain any valid geometry element in the planView.", - currentRoad.additionalId, - Severity.FATAL_ERROR, - wasFixed = false - ) + modifiedOpendriveModel.road = + modifiedOpendriveModel.road.filter { currentRoad -> + if (currentRoad.planView.geometry.isEmpty()) { + issueList += + DefaultIssue.of( + "RoadWithoutValidPlanViewGeometryElement", + "Road does not contain any valid geometry element in the planView.", + currentRoad.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) + } + currentRoad.planView.geometry.isNotEmpty() } - currentRoad.planView.geometry.isNotEmpty() - } - modifiedOpendriveModel = everyRoad.modify(modifiedOpendriveModel) { currentRoad -> - val location = currentRoad.additionalId.fold({ "" }, { it.toIdentifierText() }) + modifiedOpendriveModel = + everyRoad.modify(modifiedOpendriveModel) { currentRoad -> + val location = currentRoad.additionalId.fold({ "" }, { it.toIdentifierText() }) /*val planViewGeometryLengthsSum = road.planView.geometry.sumOf { it.length } if (!fuzzyEquals(planViewGeometryLengthsSum, road.length, parameters.numberTolerance)) { - healedViolations += OpendriveException.UnexpectedValue("length", road.length.toString(), ", as the sum of the individual plan view elements is different") + healedViolations += OpendriveException.UnexpectedValue("length", road.length.toString(), ", as the sum of the + individual plan view elements is different") road.length = planViewGeometryLengthsSum }*/ - currentRoad.planView.geometry.zipWithNext().forEach { - val actualLength = it.second.s - it.first.s - if (!fuzzyEquals(it.first.length, actualLength, parameters.numberTolerance)) { - issueList += DefaultIssue.of("PlanViewGeometryElementLengthNotMatchingNextElement", "Length attribute (length=${it.first.length}) of the geometry element (s=${it.first.s}) does not match the start position (s=${it.second.s}) of the next geometry element.", currentRoad.additionalId, Severity.WARNING, wasFixed = true) - it.first.length = actualLength + currentRoad.planView.geometry.zipWithNext().forEach { + val actualLength = it.second.s - it.first.s + if (!fuzzyEquals(it.first.length, actualLength, parameters.numberTolerance)) { + issueList += + DefaultIssue.of( + "PlanViewGeometryElementLengthNotMatchingNextElement", + "Length attribute (length=${it.first.length}) of the geometry element (s=${it.first.s}) " + + "does not match the start position (s=${it.second.s}) of the next geometry element.", + currentRoad.additionalId, Severity.WARNING, wasFixed = true, + ) + it.first.length = actualLength + } } - } - if (!fuzzyEquals(currentRoad.planView.geometry.last().s + currentRoad.planView.geometry.last().length, currentRoad.length, parameters.numberTolerance)) { - issueList += DefaultIssue.of("LastPlanPlanViewGeometryElementNotMatchingRoadLength", "Length attribute (length=${currentRoad.planView.geometry.last().length}) of the last geometry element (s=${currentRoad.planView.geometry.last().s}) does not match the total road length (length=${currentRoad.length}).", currentRoad.additionalId, Severity.WARNING, wasFixed = true) - currentRoad.planView.geometry.last().length = currentRoad.length - currentRoad.planView.geometry.last().s - } - - // check gaps and kinks of reference line curve - - val (curveMembers, _, _) = Curve2DBuilder.prepareCurveMembers( - currentRoad.planView.geometryAsNonEmptyList, - parameters.numberTolerance - ) - curveMembers.zipWithNext().forEach { - val frontCurveMemberEndPose = it.first.calculatePoseGlobalCSUnbounded(CurveRelativeVector1D(it.first.length)) - val backCurveMemberStartPose = it.second.calculatePoseGlobalCSUnbounded(CurveRelativeVector1D.ZERO) - - val distance = frontCurveMemberEndPose.point.distance(backCurveMemberStartPose.point) - if (distance > parameters.planViewGeometryDistanceTolerance) { - issueList += DefaultIssue( - "GapBetweenPlanViewGeometryElements", - "Geometry elements contain a gap " + - "from ${frontCurveMemberEndPose.point} to ${backCurveMemberStartPose.point} with an euclidean distance " + - "of $distance above the tolerance of ${parameters.planViewGeometryDistanceTolerance}.", - location, - Severity.FATAL_ERROR, - wasFixed = false - ) - } else if (distance > parameters.planViewGeometryDistanceWarningTolerance) { - issueList += DefaultIssue( - "GapBetweenPlanViewGeometryElements", - "Geometry elements contain a gap " + - "from ${frontCurveMemberEndPose.point} to ${backCurveMemberStartPose.point} with an euclidean distance " + - "of $distance above the warning tolerance of ${parameters.planViewGeometryDistanceWarningTolerance}.", - location, - Severity.WARNING, - wasFixed = false + if (!fuzzyEquals( + currentRoad.planView.geometry.last().s + currentRoad.planView.geometry.last().length, + currentRoad.length, parameters.numberTolerance, ) + ) { + issueList += + DefaultIssue.of( + "LastPlanPlanViewGeometryElementNotMatchingRoadLength", + "Length attribute (length=${currentRoad.planView.geometry.last().length}) of the last geometry " + + "element (s=${currentRoad.planView.geometry.last().s}) does not match the total road length " + + "(length=${currentRoad.length}).", + currentRoad.additionalId, Severity.WARNING, wasFixed = true, + ) + currentRoad.planView.geometry.last().length = currentRoad.length - currentRoad.planView.geometry.last().s } - val angleDifference = frontCurveMemberEndPose.rotation.difference(backCurveMemberStartPose.rotation) - if (angleDifference > parameters.planViewGeometryAngleTolerance) { - issueList += DefaultIssue( - "KinkBetweenPlanViewGeometryElements", - "Geometry elements contain a kink " + - "from ${frontCurveMemberEndPose.point} to ${backCurveMemberStartPose.point} with an angle difference " + - "of $angleDifference above the tolerance of ${parameters.planViewGeometryAngleTolerance}.", - location, - Severity.FATAL_ERROR, - wasFixed = false - ) - } else if (angleDifference > parameters.planViewGeometryAngleWarningTolerance) { - issueList += DefaultIssue( - "KinkBetweenPlanViewGeometryElements", - "Geometry elements contain a gap " + - "from ${frontCurveMemberEndPose.point} to ${backCurveMemberStartPose.point} with an angle difference " + - "of $angleDifference above the warning tolerance of ${parameters.planViewGeometryAngleWarningTolerance}.", - location, - Severity.WARNING, - wasFixed = false + // check gaps and kinks of reference line curve + + val (curveMembers, _, _) = + Curve2DBuilder.prepareCurveMembers( + currentRoad.planView.geometryAsNonEmptyList, + parameters.numberTolerance, ) + curveMembers.zipWithNext().forEach { + val frontCurveMemberEndPose = it.first.calculatePoseGlobalCSUnbounded(CurveRelativeVector1D(it.first.length)) + val backCurveMemberStartPose = it.second.calculatePoseGlobalCSUnbounded(CurveRelativeVector1D.ZERO) + + val distance = frontCurveMemberEndPose.point.distance(backCurveMemberStartPose.point) + if (distance > parameters.planViewGeometryDistanceTolerance) { + issueList += + DefaultIssue( + "GapBetweenPlanViewGeometryElements", + "Geometry elements contain a gap " + + "from ${frontCurveMemberEndPose.point} to ${backCurveMemberStartPose.point} with an euclidean " + + "distance of $distance above the tolerance of ${parameters.planViewGeometryDistanceTolerance}.", + location, Severity.FATAL_ERROR, wasFixed = false, + ) + } else if (distance > parameters.planViewGeometryDistanceWarningTolerance) { + issueList += + DefaultIssue( + "GapBetweenPlanViewGeometryElements", + "Geometry elements contain a gap " + + "from ${frontCurveMemberEndPose.point} to ${backCurveMemberStartPose.point} with an euclidean " + + "distance of $distance above the warning tolerance " + + "of ${parameters.planViewGeometryDistanceWarningTolerance}.", + location, Severity.WARNING, wasFixed = false, + ) + } + + val angleDifference = frontCurveMemberEndPose.rotation.difference(backCurveMemberStartPose.rotation) + if (angleDifference > parameters.planViewGeometryAngleTolerance) { + issueList += + DefaultIssue( + "KinkBetweenPlanViewGeometryElements", + "Geometry elements contain a kink " + + "from ${frontCurveMemberEndPose.point} to ${backCurveMemberStartPose.point} with an angle difference " + + "of $angleDifference above the tolerance of ${parameters.planViewGeometryAngleTolerance}.", + location, Severity.FATAL_ERROR, wasFixed = false, + ) + } else if (angleDifference > parameters.planViewGeometryAngleWarningTolerance) { + issueList += + DefaultIssue( + "KinkBetweenPlanViewGeometryElements", + "Geometry elements contain a gap " + + "from ${frontCurveMemberEndPose.point} to ${backCurveMemberStartPose.point} with an angle difference " + + "of $angleDifference above the warning tolerance of " + + "${parameters.planViewGeometryAngleWarningTolerance}.", + location, Severity.WARNING, wasFixed = false, + ) + } } - } - currentRoad - } + currentRoad + } val junctionIdentifiers = modifiedOpendriveModel.junction.map { it.id } - modifiedOpendriveModel = everyRoad.modify(modifiedOpendriveModel) { currentRoad -> - currentRoad.getJunctionOption().onSome { currentJunctionId -> - if (currentJunctionId !in junctionIdentifiers) { - issueList += DefaultIssue( - "RoadBelongsToNonExistingJunction", - "Road belongs to a junction (id=${currentRoad.junction}) that does not exist.", - currentRoad.id, - Severity.ERROR, - wasFixed = true - ) - currentRoad.junction = "" + modifiedOpendriveModel = + everyRoad.modify(modifiedOpendriveModel) { currentRoad -> + currentRoad.getJunctionOption().onSome { currentJunctionId -> + if (currentJunctionId !in junctionIdentifiers) { + issueList += + DefaultIssue( + "RoadBelongsToNonExistingJunction", + "Road belongs to a junction (id=${currentRoad.junction}) that does not exist.", + currentRoad.id, Severity.ERROR, wasFixed = true, + ) + currentRoad.junction = "" + } } - } - currentRoad.link.onSome { currentLink -> - if (currentLink.predecessor.isSome { currentPredecessor -> - currentPredecessor.getJunctionPredecessorSuccessor() - .isSome { !junctionIdentifiers.contains(it) } - } - ) { - issueList += DefaultIssue( - "RoadLinkPredecessorRefersToNonExistingJunction", - "Road link predecessor references a junction (id=${ - currentLink.predecessor.fold( - { "" }, - { it.elementId } - ) - }) that does not exist.", - currentRoad.id, - Severity.ERROR, - wasFixed = true - ) - currentLink.predecessor = None + currentRoad.link.onSome { currentLink -> + if (currentLink.predecessor.isSome { currentPredecessor -> + currentPredecessor.getJunctionPredecessorSuccessor() + .isSome { !junctionIdentifiers.contains(it) } + } + ) { + issueList += + DefaultIssue( + "RoadLinkPredecessorRefersToNonExistingJunction", + "Road link predecessor references a junction (id=${ + currentLink.predecessor.fold( + { "" }, + { it.elementId }, + ) + }) that does not exist.", + currentRoad.id, Severity.ERROR, wasFixed = true, + ) + currentLink.predecessor = None + } + if (currentLink.successor.isSome { currentSuccessor -> + currentSuccessor.getJunctionPredecessorSuccessor().isSome { !junctionIdentifiers.contains(it) } + } + ) { + issueList += + DefaultIssue( + "RoadLinkSuccessorRefersToNonExistingJunction", + "Road link successor references a junction (id=${ + currentLink.successor.fold( + { "" }, + { it.elementId }, + ) + }) that does not exist.", + currentRoad.id, Severity.ERROR, wasFixed = true, + ) + currentLink.successor = None + } } - if (currentLink.successor.isSome { currentSuccessor -> - currentSuccessor.getJunctionPredecessorSuccessor().isSome { !junctionIdentifiers.contains(it) } - } - ) { - issueList += DefaultIssue( - "RoadLinkSuccessorRefersToNonExistingJunction", - "Road link successor references a junction (id=${ - currentLink.successor.fold( - { "" }, - { it.elementId } - ) - }) that does not exist.", - currentRoad.id, - Severity.ERROR, - wasFixed = true - ) - currentLink.successor = None - } - } - currentRoad - } + currentRoad + } return modifiedOpendriveModel } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadLanesEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadLanesEvaluator.kt index ddf3b9a7..36c591ed 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadLanesEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadLanesEvaluator.kt @@ -32,15 +32,23 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.issues.opendrive.of object RoadLanesEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() everyRoad.modify(modifiedOpendriveModel) { currentRoad -> if (currentRoad.lanes.getLaneSectionLengths(currentRoad.length).any { it <= parameters.numberTolerance }) { - issueList += DefaultIssue.of("LaneSectionLengthBelowTolerance", "Lane sections has a length of zero or below the tolerance.", currentRoad.additionalId, Severity.FATAL_ERROR, wasFixed = false) + issueList += + DefaultIssue.of( + "LaneSectionLengthBelowTolerance", + "Lane sections has a length of zero or below the tolerance.", currentRoad.additionalId, + Severity.FATAL_ERROR, wasFixed = false, + ) } currentRoad @@ -48,23 +56,21 @@ object RoadLanesEvaluator { everyLaneSection.modify(modifiedOpendriveModel) { currentLaneSection -> if (currentLaneSection.center.getNumberOfLanes() != 1) { - issueList += DefaultIssue.of( - "LaneSectionContainsNoCenterLane", - "Lane section contains no center lane.", - currentLaneSection.additionalId, - Severity.FATAL_ERROR, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "LaneSectionContainsNoCenterLane", + "Lane section contains no center lane.", + currentLaneSection.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) } if (currentLaneSection.getNumberOfLeftRightLanes() == 0) { - issueList += DefaultIssue.of( - "LaneSectionContainsNoLeftOrRightLane", - "Lane section contains neither a left nor a right lane.", - currentLaneSection.additionalId, - Severity.FATAL_ERROR, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "LaneSectionContainsNoLeftOrRightLane", + "Lane section contains neither a left nor a right lane.", + currentLaneSection.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) } currentLaneSection.left.onSome { currentLaneSectionLeft -> @@ -72,22 +78,20 @@ object RoadLanesEvaluator { val expectedIds = (currentLaneSectionLeft.getNumberOfLanes() downTo 1).toList() if (leftLaneIds.distinct().size < leftLaneIds.size) { - issueList += DefaultIssue.of( - "LaneIdDuplicatesWithinLeftLaneSection", - "Lane ids are not unique within the left lane section.", - currentLaneSection.additionalId, - Severity.FATAL_ERROR, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "LaneIdDuplicatesWithinLeftLaneSection", + "Lane ids are not unique within the left lane section.", + currentLaneSection.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) } if (!leftLaneIds.containsAll(expectedIds)) { - issueList += DefaultIssue.of( - "NonConsecutiveLaneIdsWithinLeftLaneSection", - "Lane numbering shall be consecutive without any gaps.", - currentLaneSection.additionalId, - Severity.FATAL_ERROR, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "NonConsecutiveLaneIdsWithinLeftLaneSection", + "Lane numbering shall be consecutive without any gaps.", + currentLaneSection.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) } } @@ -96,50 +100,75 @@ object RoadLanesEvaluator { val expectedIds = (-1 downTo -currentLaneSectionRight.getNumberOfLanes()).toList() if (rightLaneIds.distinct().size < rightLaneIds.size) { - issueList += DefaultIssue.of( - "LaneIdDuplicatesWithinRightLaneSection", - "Lane ids are not unique within the right lane section.", - currentLaneSection.additionalId, - Severity.FATAL_ERROR, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "LaneIdDuplicatesWithinRightLaneSection", + "Lane ids are not unique within the right lane section.", + currentLaneSection.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) } if (!rightLaneIds.containsAll(expectedIds)) { - issueList += DefaultIssue.of( - "NonConsecutiveLaneIdsWithinRightLaneSection", - "Lane numbering shall be consecutive without any gaps.", - currentLaneSection.additionalId, - Severity.FATAL_ERROR, - wasFixed = false - ) + issueList += + DefaultIssue.of( + "NonConsecutiveLaneIdsWithinRightLaneSection", + "Lane numbering shall be consecutive without any gaps.", + currentLaneSection.additionalId, Severity.FATAL_ERROR, wasFixed = false, + ) } } currentLaneSection } - modifiedOpendriveModel = everyRoadLanesLaneSectionCenterLane.modify(modifiedOpendriveModel) { currentCenterLane -> - currentCenterLane.roadMark = filterToNonZeroLengthRoadMarks(currentCenterLane.roadMark, currentCenterLane.additionalId, parameters, issueList) - currentCenterLane - } - modifiedOpendriveModel = everyRoadLanesLaneSectionLeftLane.modify(modifiedOpendriveModel) { currentLeftLane -> - currentLeftLane.roadMark = filterToNonZeroLengthRoadMarks(currentLeftLane.roadMark, currentLeftLane.additionalId, parameters, issueList) - currentLeftLane - } - modifiedOpendriveModel = everyRoadLanesLaneSectionRightLane.modify(modifiedOpendriveModel) { currentRightLane -> - currentRightLane.roadMark = filterToNonZeroLengthRoadMarks(currentRightLane.roadMark, currentRightLane.additionalId, parameters, issueList) - currentRightLane - } + modifiedOpendriveModel = + everyRoadLanesLaneSectionCenterLane.modify(modifiedOpendriveModel) { currentCenterLane -> + currentCenterLane.roadMark = + filterToNonZeroLengthRoadMarks( + currentCenterLane.roadMark, + currentCenterLane.additionalId, parameters, issueList, + ) + currentCenterLane + } + modifiedOpendriveModel = + everyRoadLanesLaneSectionLeftLane.modify(modifiedOpendriveModel) { currentLeftLane -> + currentLeftLane.roadMark = + filterToNonZeroLengthRoadMarks( + currentLeftLane.roadMark, currentLeftLane.additionalId, + parameters, issueList, + ) + currentLeftLane + } + modifiedOpendriveModel = + everyRoadLanesLaneSectionRightLane.modify(modifiedOpendriveModel) { currentRightLane -> + currentRightLane.roadMark = + filterToNonZeroLengthRoadMarks( + currentRightLane.roadMark, currentRightLane.additionalId, + parameters, issueList, + ) + currentRightLane + } return modifiedOpendriveModel } - private fun filterToNonZeroLengthRoadMarks(roadMarks: List, location: Option, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): List { + private fun filterToNonZeroLengthRoadMarks( + roadMarks: List, + location: Option, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): List { if (roadMarks.isEmpty()) return emptyList() - val roadMarksFiltered: List = roadMarks.zipWithNext().map { it.first to it.second.sOffset - it.first.sOffset }.filter { it.second >= parameters.numberTolerance }.map { it.first } + roadMarks.last() + val roadMarksFiltered: List = + roadMarks.zipWithNext().map { + it.first to it.second.sOffset - it.first.sOffset + }.filter { it.second >= parameters.numberTolerance }.map { it.first } + roadMarks.last() if (roadMarksFiltered.size < roadMarks.size) { - issueList += DefaultIssue.of("RoadMarkWithLengthBelowThreshold", "Center lane contains roadMarks with length zero (or below threshold).", location, Severity.ERROR, wasFixed = true) + issueList += + DefaultIssue.of( + "RoadMarkWithLengthBelowThreshold", + "Center lane contains roadMarks with length zero (or below threshold).", location, Severity.ERROR, wasFixed = true, + ) } return roadMarksFiltered diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadObjectsEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadObjectsEvaluator.kt index 0ac2dc61..d1f33c3c 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadObjectsEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadObjectsEvaluator.kt @@ -28,81 +28,85 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.issues.opendrive.of object RoadObjectsEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() - modifiedOpendriveModel = everyRoad.modify(modifiedOpendriveModel) { currentRoad -> + modifiedOpendriveModel = + everyRoad.modify(modifiedOpendriveModel) { currentRoad -> - currentRoad.objects.onSome { currentRoadObjects -> - val roadObjectsFiltered = - currentRoadObjects.roadObject.filter { it.s <= currentRoad.length + parameters.numberTolerance } - if (currentRoadObjects.roadObject.size > roadObjectsFiltered.size) { - issueList += DefaultIssue.of( - "RoadObjectPositionNotInSValueRange", - "Road object (number of objects affected: ${currentRoadObjects.roadObject.size - roadObjectsFiltered.size}) were removed since they were positioned outside the defined length of the road.", - currentRoad.additionalId, - Severity.ERROR, - wasFixed = true - ) + currentRoad.objects.onSome { currentRoadObjects -> + val roadObjectsFiltered = + currentRoadObjects.roadObject.filter { it.s <= currentRoad.length + parameters.numberTolerance } + if (currentRoadObjects.roadObject.size > roadObjectsFiltered.size) { + issueList += + DefaultIssue.of( + "RoadObjectPositionNotInSValueRange", + "Road object (number of objects affected: ${currentRoadObjects.roadObject.size - + roadObjectsFiltered.size}) were removed since they were positioned outside the " + + "defined length of the road.", + currentRoad.additionalId, Severity.ERROR, wasFixed = true, + ) + } + currentRoadObjects.roadObject = roadObjectsFiltered } - currentRoadObjects.roadObject = roadObjectsFiltered + + currentRoad } - currentRoad - } + modifiedOpendriveModel = + everyRoadObject.modify(modifiedOpendriveModel) { currentRoadObject -> - modifiedOpendriveModel = everyRoadObject.modify(modifiedOpendriveModel) { currentRoadObject -> + // adding ids for outline elements + currentRoadObject.outlines.onSome { currentOutlinesElement -> + val outlineElementsWithoutId = currentOutlinesElement.outline.filter { it.id.isNone() } - // adding ids for outline elements - currentRoadObject.outlines.onSome { currentOutlinesElement -> - val outlineElementsWithoutId = currentOutlinesElement.outline.filter { it.id.isNone() } + if (outlineElementsWithoutId.isNotEmpty()) { + val startId: Int = currentOutlinesElement.outline.map { it.id }.flattenOption().maxOrNull() ?: 0 + issueList += + DefaultIssue.of( + "MissingValue", + "Missing value for attribute 'id'.", + currentRoadObject.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) + outlineElementsWithoutId.forEachIndexed { index, outlineElement -> + outlineElement.id = Some(startId + index) + } + } + } - if (outlineElementsWithoutId.isNotEmpty()) { - val startId: Int = currentOutlinesElement.outline.map { it.id }.flattenOption().maxOrNull() ?: 0 - issueList += DefaultIssue.of( - "MissingValue", - "Missing value for attribute 'id'.", - currentRoadObject.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) - outlineElementsWithoutId.forEachIndexed { index, outlineElement -> - outlineElement.id = Some(startId + index) + currentRoadObject.outlines.onSome { currentRoadObjectOutline -> + if (currentRoadObjectOutline.outline.any { it.isPolyhedron() && !it.isPolyhedronUniquelyDefined() }) { + issueList += + DefaultIssue.of( + "SimultaneousDefinitionCornerRoadCornerLocal", + "An element shall be followed by one or more elements or by one or more " + + " element. Since both are defined, the elements are removed.", + currentRoadObject.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) + currentRoadObjectOutline.outline.forEach { it.cornerLocal = emptyList() } } } - } - currentRoadObject.outlines.onSome { currentRoadObjectOutline -> - if (currentRoadObjectOutline.outline.any { it.isPolyhedron() && !it.isPolyhedronUniquelyDefined() }) { - issueList += DefaultIssue.of( - "SimultaneousDefinitionCornerRoadCornerLocal", - "An element shall be followed by one or more elements or by one or more element. Since both are defined, the elements are removed.", - currentRoadObject.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) - currentRoadObjectOutline.outline.forEach { it.cornerLocal = emptyList() } + val repeatElementsFiltered = currentRoadObject.repeat.filter { it.length >= parameters.numberTolerance } + if (repeatElementsFiltered.size < currentRoadObject.repeat.size) { + // TODO: double check handling + issueList += + DefaultIssue.of( + "RepeatElementHasZeroLength", + "A repeat element should have a length higher than zero and tolerance.", + currentRoadObject.additionalId, Severity.FATAL_ERROR, wasFixed = true, + ) + currentRoadObject.repeat = repeatElementsFiltered } - } - val repeatElementsFiltered = currentRoadObject.repeat.filter { it.length >= parameters.numberTolerance } - if (repeatElementsFiltered.size < currentRoadObject.repeat.size) { - // TODO: double check handling - issueList += DefaultIssue.of( - "RepeatElementHasZeroLength", - "A repeat element should have a length higher than zero and tolerance.", - currentRoadObject.additionalId, - Severity.FATAL_ERROR, - wasFixed = true - ) - currentRoadObject.repeat = repeatElementsFiltered + currentRoadObject } - currentRoadObject - } - return modifiedOpendriveModel } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadSignalsEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadSignalsEvaluator.kt index 31d89dfd..4469211c 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadSignalsEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/plans/modelingrules/RoadSignalsEvaluator.kt @@ -25,30 +25,35 @@ import io.rtron.transformer.evaluator.opendrive.OpendriveEvaluatorParameters import io.rtron.transformer.issues.opendrive.of object RoadSignalsEvaluator { - // Methods - fun evaluate(opendriveModel: OpendriveModel, parameters: OpendriveEvaluatorParameters, issueList: DefaultIssueList): OpendriveModel { + fun evaluate( + opendriveModel: OpendriveModel, + parameters: OpendriveEvaluatorParameters, + issueList: DefaultIssueList, + ): OpendriveModel { var modifiedOpendriveModel = opendriveModel.copy() - modifiedOpendriveModel = everyRoad.modify(modifiedOpendriveModel) { currentRoad -> + modifiedOpendriveModel = + everyRoad.modify(modifiedOpendriveModel) { currentRoad -> - currentRoad.signals.onSome { currentRoadSignals -> - val signalsFiltered = - currentRoadSignals.signal.filter { it.s <= currentRoad.length + parameters.numberTolerance } - if (currentRoadSignals.signal.size > signalsFiltered.size) { - issueList += DefaultIssue.of( - "RoadSignalPositionNotInSValueRange", - "Road signals (number of objects affected: ${currentRoadSignals.signal.size - signalsFiltered.size}) were removed since they were positioned outside the defined length of the road.", - currentRoad.additionalId, - Severity.ERROR, - wasFixed = true - ) + currentRoad.signals.onSome { currentRoadSignals -> + val signalsFiltered = + currentRoadSignals.signal.filter { it.s <= currentRoad.length + parameters.numberTolerance } + if (currentRoadSignals.signal.size > signalsFiltered.size) { + issueList += + DefaultIssue.of( + "RoadSignalPositionNotInSValueRange", + "Road signals (number of objects affected: ${currentRoadSignals.signal.size - + signalsFiltered.size}) were removed since they were positioned outside the defined " + + "length of the road.", + currentRoad.additionalId, Severity.ERROR, wasFixed = true, + ) + } + currentRoadSignals.signal = signalsFiltered } - currentRoadSignals.signal = signalsFiltered - } - currentRoad - } + currentRoad + } return modifiedOpendriveModel } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/report/OpendriveEvaluationReport.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/report/OpendriveEvaluationReport.kt index a5af9d7e..af1d86c8 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/report/OpendriveEvaluationReport.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/opendrive/report/OpendriveEvaluationReport.kt @@ -25,12 +25,10 @@ import kotlinx.serialization.Serializable @Serializable data class OpendriveEvaluationReport( val parameters: OpendriveEvaluatorParameters, - var basicDataTypePlan: DefaultIssueList = DefaultIssueList(), var modelingRulesPlan: DefaultIssueList = DefaultIssueList(), - var conversionRequirementsPlan: DefaultIssueList = DefaultIssueList() + var conversionRequirementsPlan: DefaultIssueList = DefaultIssueList(), ) { - /** * Returns a summary of the message numbers depending on the severity. */ @@ -39,6 +37,7 @@ data class OpendriveEvaluationReport( "modeling rules plan: ${modelingRulesPlan.getTextSummary()}, " + "conversion requirements plan: ${conversionRequirementsPlan.getTextSummary()}" - fun containsFatalErrors(): Boolean = basicDataTypePlan.containsFatalErrors() || - modelingRulesPlan.containsFatalErrors() || conversionRequirementsPlan.containsFatalErrors() + fun containsFatalErrors(): Boolean = + basicDataTypePlan.containsFatalErrors() || + modelingRulesPlan.containsFatalErrors() || conversionRequirementsPlan.containsFatalErrors() } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/RoadspacesEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/RoadspacesEvaluator.kt index 3485fac7..3ccf7257 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/RoadspacesEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/RoadspacesEvaluator.kt @@ -22,7 +22,7 @@ import io.rtron.transformer.evaluator.roadspaces.plans.modelingrules.ModelingRul import io.rtron.transformer.evaluator.roadspaces.report.RoadspacesEvaluationReport class RoadspacesEvaluator( - val parameters: RoadspacesEvaluatorParameters + val parameters: RoadspacesEvaluatorParameters, ) { // Properties and Initializers private val logger = KotlinLogging.logger {} diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/RoadspacesEvaluatorParameters.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/RoadspacesEvaluatorParameters.kt index 49da5a5f..2625b817 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/RoadspacesEvaluatorParameters.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/RoadspacesEvaluatorParameters.kt @@ -24,9 +24,8 @@ import kotlinx.serialization.Serializable @Serializable data class RoadspacesEvaluatorParameters( val numberTolerance: Double, - val laneTransitionDistanceTolerance: Double + val laneTransitionDistanceTolerance: Double, ) { - companion object { const val DEFAULT_LANE_TRANSITION_DISTANCE_TOLERANCE = 1E-3 } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/plans/AbstractRoadspacesEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/plans/AbstractRoadspacesEvaluator.kt index 0a52d810..9273d06a 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/plans/AbstractRoadspacesEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/plans/AbstractRoadspacesEvaluator.kt @@ -20,7 +20,6 @@ import io.rtron.io.issues.DefaultIssueList import io.rtron.model.roadspaces.RoadspacesModel abstract class AbstractRoadspacesEvaluator { - // Methods abstract fun evaluate(roadspacesModel: RoadspacesModel): DefaultIssueList } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/plans/modelingrules/ModelingRulesEvaluator.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/plans/modelingrules/ModelingRulesEvaluator.kt index 7335d09e..0c3c331e 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/plans/modelingrules/ModelingRulesEvaluator.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/plans/modelingrules/ModelingRulesEvaluator.kt @@ -32,7 +32,6 @@ import io.rtron.transformer.evaluator.roadspaces.RoadspacesEvaluatorParameters import io.rtron.transformer.evaluator.roadspaces.plans.AbstractRoadspacesEvaluator class ModelingRulesEvaluator(val parameters: RoadspacesEvaluatorParameters) : AbstractRoadspacesEvaluator() { - // Methods override fun evaluate(roadspacesModel: RoadspacesModel): DefaultIssueList { val issueList = DefaultIssueList() @@ -42,7 +41,10 @@ class ModelingRulesEvaluator(val parameters: RoadspacesEvaluatorParameters) : Ab return issueList } - private fun evaluateRoadLinkages(roadspace: Roadspace, roadspacesModel: RoadspacesModel): DefaultIssueList { + private fun evaluateRoadLinkages( + roadspace: Roadspace, + roadspacesModel: RoadspacesModel, + ): DefaultIssueList { val issueList = DefaultIssueList() roadspace.road.getAllLeftRightLaneIdentifiers() @@ -50,36 +52,56 @@ class ModelingRulesEvaluator(val parameters: RoadspacesEvaluatorParameters) : Ab .forEach { laneId -> val successorLaneIds = roadspacesModel.getSuccessorLaneIdentifiers(laneId).getOrElse { throw it } - issueList += successorLaneIds.map { successorLaneId -> - evaluateLaneTransition(laneId, successorLaneId, roadspace.road, roadspacesModel.getRoadspace(successorLaneId.toRoadspaceIdentifier()).getOrElse { throw it }.road, roadspacesModel) - }.merge() + issueList += + successorLaneIds.map { successorLaneId -> + evaluateLaneTransition( + laneId, successorLaneId, roadspace.road, + roadspacesModel.getRoadspace(successorLaneId.toRoadspaceIdentifier()).getOrElse { + throw it + }.road, + roadspacesModel, + ) + }.merge() } return issueList } - private fun evaluateLaneTransition(laneId: LaneIdentifier, successorLaneId: LaneIdentifier, road: Road, successorRoad: Road, roadspacesModel: RoadspacesModel): DefaultIssueList { + private fun evaluateLaneTransition( + laneId: LaneIdentifier, + successorLaneId: LaneIdentifier, + road: Road, + successorRoad: Road, + roadspacesModel: RoadspacesModel, + ): DefaultIssueList { require(laneId !== successorLaneId) { "Lane identifiers of current and of successor lane must be different." } - require(laneId.roadspaceId !== successorLaneId.roadspaceId) { "Lane identifiers of current and of successor lane must be different regarding their roadspaceId." } + require(laneId.roadspaceId !== successorLaneId.roadspaceId) { + "Lane identifiers of current and of successor lane must be different regarding their roadspaceId." + } require(road.id !== successorRoad.id) { "Road and successor road must be different." } val issueList = DefaultIssueList() - val laneLeftLaneBoundaryPoint: Vector3D = road.getLeftLaneBoundary(laneId).getOrElse { throw it } - .calculateEndPointGlobalCS().mapLeft { it.toIllegalStateException() }.getOrElse { throw it } - val laneRightLaneBoundaryPoint: Vector3D = road.getRightLaneBoundary(laneId).getOrElse { throw it } - .calculateEndPointGlobalCS().mapLeft { it.toIllegalStateException() }.getOrElse { throw it } + val laneLeftLaneBoundaryPoint: Vector3D = + road.getLeftLaneBoundary(laneId).getOrElse { throw it } + .calculateEndPointGlobalCS().mapLeft { it.toIllegalStateException() }.getOrElse { throw it } + val laneRightLaneBoundaryPoint: Vector3D = + road.getRightLaneBoundary(laneId).getOrElse { throw it } + .calculateEndPointGlobalCS().mapLeft { it.toIllegalStateException() }.getOrElse { throw it } // false, if the successor lane is connected by its end (leads to swapping of the vertices) - val successorContactStart = !road.linkage.successorRoadspaceContactPointId - .map { it.roadspaceContactPoint } - .isSome { it == ContactPoint.END } + val successorContactStart = + !road.linkage.successorRoadspaceContactPointId + .map { it.roadspaceContactPoint } + .isSome { it == ContactPoint.END } // TODO: identify inconsistencies in the topology of the model - val successorLeftLaneBoundary = successorRoad.getLeftLaneBoundary(successorLaneId) - .fold({ return issueList }, { it }) - val successorRightLaneBoundary = successorRoad.getRightLaneBoundary(successorLaneId) - .fold({ return issueList }, { it }) + val successorLeftLaneBoundary = + successorRoad.getLeftLaneBoundary(successorLaneId) + .fold({ return issueList }, { it }) + val successorRightLaneBoundary = + successorRoad.getRightLaneBoundary(successorLaneId) + .fold({ return issueList }, { it }) // if contact of successor at the start, normal connecting // if contact of the successor at the end, the end positions have to be calculated and left and right boundary have to be swapped @@ -105,28 +127,26 @@ class ModelingRulesEvaluator(val parameters: RoadspacesEvaluatorParameters) : Ab val leftLaneBoundaryTransitionDistance = laneLeftLaneBoundaryPoint.distance(laneLeftLaneBoundarySuccessorPoint) if (leftLaneBoundaryTransitionDistance >= parameters.laneTransitionDistanceTolerance) { val infoValues = mapOf("euclideanDistance" to leftLaneBoundaryTransitionDistance) - issueList += DefaultIssue( - "LeftLaneBoundaryTransitionGap", - "Left boundary of lane should be connected to its successive lane (euclidean distance: $leftLaneBoundaryTransitionDistance).", - location, - Severity.WARNING, - wasFixed = false, - infoValues - ) + issueList += + DefaultIssue( + "LeftLaneBoundaryTransitionGap", + "Left boundary of lane should be connected to its successive lane (euclidean distance: " + + "$leftLaneBoundaryTransitionDistance).", + location, Severity.WARNING, wasFixed = false, infoValues, + ) } val rightLaneBoundaryTransitionDistance = laneRightLaneBoundaryPoint.distance(laneRightLaneBoundarySuccessorPoint) if (rightLaneBoundaryTransitionDistance >= parameters.laneTransitionDistanceTolerance) { val infoValues = mapOf("euclideanDistance" to rightLaneBoundaryTransitionDistance) - issueList += DefaultIssue( - "RightLaneBoundaryTransitionGap", - "Right boundary of lane should be connected to its successive lane (euclidean distance: $rightLaneBoundaryTransitionDistance).", - location, - Severity.WARNING, - wasFixed = false, - infoValues - ) + issueList += + DefaultIssue( + "RightLaneBoundaryTransitionGap", + "Right boundary of lane should be connected to its successive lane (euclidean distance: " + + "$rightLaneBoundaryTransitionDistance).", + location, Severity.WARNING, wasFixed = false, infoValues, + ) } return issueList diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/report/RoadspacesEvaluationReport.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/report/RoadspacesEvaluationReport.kt index 10d2e435..254380e4 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/report/RoadspacesEvaluationReport.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/evaluator/roadspaces/report/RoadspacesEvaluationReport.kt @@ -23,6 +23,5 @@ import kotlinx.serialization.Serializable @Serializable data class RoadspacesEvaluationReport( val parameters: RoadspacesEvaluatorParameters, - - var modelingRulesEvaluation: DefaultIssueList = DefaultIssueList() + var modelingRulesEvaluation: DefaultIssueList = DefaultIssueList(), ) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/issues/opendrive/DefaultIssueExtensions.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/issues/opendrive/DefaultIssueExtensions.kt index 069af54b..8124a6aa 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/issues/opendrive/DefaultIssueExtensions.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/issues/opendrive/DefaultIssueExtensions.kt @@ -22,10 +22,22 @@ import io.rtron.io.issues.Severity import io.rtron.model.opendrive.additions.identifier.AbstractOpendriveIdentifier import io.rtron.model.opendrive.additions.identifier.toIdentifierText -fun DefaultIssue.Companion.of(type: String, info: String, location: AbstractOpendriveIdentifier, incidentSeverity: Severity, wasFixed: Boolean): DefaultIssue { +fun DefaultIssue.Companion.of( + type: String, + info: String, + location: AbstractOpendriveIdentifier, + incidentSeverity: Severity, + wasFixed: Boolean, +): DefaultIssue { return DefaultIssue(type, info, location.toIdentifierText(), incidentSeverity, wasFixed) } -fun DefaultIssue.Companion.of(type: String, info: String, location: Option, incidentSeverity: Severity, wasFixed: Boolean): DefaultIssue { +fun DefaultIssue.Companion.of( + type: String, + info: String, + location: Option, + incidentSeverity: Severity, + wasFixed: Boolean, +): DefaultIssue { return DefaultIssue(type, info, location.toIdentifierText(), incidentSeverity, wasFixed) } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/issues/roadspaces/DefaultIssueExtensions.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/issues/roadspaces/DefaultIssueExtensions.kt index 613a0a0b..6a6df354 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/issues/roadspaces/DefaultIssueExtensions.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/issues/roadspaces/DefaultIssueExtensions.kt @@ -22,10 +22,22 @@ import io.rtron.io.issues.Severity import io.rtron.model.roadspaces.identifier.AbstractRoadspacesIdentifier import io.rtron.model.roadspaces.identifier.toIdentifierText -fun DefaultIssue.Companion.of(type: String, info: String, location: AbstractRoadspacesIdentifier, incidentSeverity: Severity, wasFixed: Boolean): DefaultIssue { +fun DefaultIssue.Companion.of( + type: String, + info: String, + location: AbstractRoadspacesIdentifier, + incidentSeverity: Severity, + wasFixed: Boolean, +): DefaultIssue { return DefaultIssue(type, info, location.toIdentifierText(), incidentSeverity, wasFixed) } -fun DefaultIssue.Companion.of(type: String, info: String, location: Option, incidentSeverity: Severity, wasFixed: Boolean): DefaultIssue { +fun DefaultIssue.Companion.of( + type: String, + info: String, + location: Option, + incidentSeverity: Severity, + wasFixed: Boolean, +): DefaultIssue { return DefaultIssue(type, info, location.toIdentifierText(), incidentSeverity, wasFixed) } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropper.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropper.kt index f919db16..1d5c6f2e 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropper.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropper.kt @@ -28,23 +28,24 @@ import io.rtron.model.opendrive.additions.optics.everyJunction import io.rtron.model.opendrive.additions.optics.everyRoad class OpendriveCropper( - val parameters: OpendriveCropperParameters + val parameters: OpendriveCropperParameters, ) { - fun modify(opendriveModel: OpendriveModel): Pair, OpendriveCropperReport> { val report = OpendriveCropperReport(parameters) val modifiedOpendriveModel = opendriveModel.copy() modifiedOpendriveModel.updateAdditionalIdentifiers() - val cropPolygon: Polygon2D = parameters.getPolygon().getOrElse { - report.message = "No cropping polygon available." - return modifiedOpendriveModel.some() to report - } + val cropPolygon: Polygon2D = + parameters.getPolygon().getOrElse { + report.message = "No cropping polygon available." + return modifiedOpendriveModel.some() to report + } // remove all roads for which the reference line lies in the crop polygon - val roadsFiltered = modifiedOpendriveModel.road.filter { currentRoad -> - currentRoad.planView.geometry.any { cropPolygon.contains(Vector2D(it.x, it.y)) } - } + val roadsFiltered = + modifiedOpendriveModel.road.filter { currentRoad -> + currentRoad.planView.geometry.any { cropPolygon.contains(Vector2D(it.x, it.y)) } + } report.numberOfRoadsOriginally = modifiedOpendriveModel.road.size report.numberOfRoadsRemaining = roadsFiltered.size if (roadsFiltered.isEmpty()) { @@ -56,11 +57,12 @@ class OpendriveCropper( // remove all the connections in the junctions, which have links to removed roads everyJunction.modify(modifiedOpendriveModel) { currentJunction -> - val connectionsFiltered = currentJunction.connection.filter { currentConnection -> - currentConnection.incomingRoad.fold({ true }, { it in remainingRoadIds }) && - currentConnection.connectingRoad.fold({ true }, { it in remainingRoadIds }) && - currentConnection.linkedRoad.fold({ true }, { it in remainingRoadIds }) - } + val connectionsFiltered = + currentJunction.connection.filter { currentConnection -> + currentConnection.incomingRoad.fold({ true }, { it in remainingRoadIds }) && + currentConnection.connectingRoad.fold({ true }, { it in remainingRoadIds }) && + currentConnection.linkedRoad.fold({ true }, { it in remainingRoadIds }) + } currentJunction.connection = connectionsFiltered currentJunction } @@ -73,7 +75,11 @@ class OpendriveCropper( // remove roads belonging to a junction, which was removed val remainingJunctionIds = junctionsFiltered.map { it.id }.toSet() - val roadsFilteredFiltered = roadsFiltered.filter { currentRoad -> currentRoad.getJunctionOption().fold({ true }, { remainingJunctionIds.contains(it) }) } + val roadsFilteredFiltered = + roadsFiltered.filter { + currentRoad -> + currentRoad.getJunctionOption().fold({ true }, { remainingJunctionIds.contains(it) }) + } modifiedOpendriveModel.road = roadsFilteredFiltered // adjust the links of each road @@ -82,32 +88,32 @@ class OpendriveCropper( currentRoad.link.onSome { currentLink -> // remove the predecessor link, if it is a junction, which is not contained in the remaining junctions if (currentLink.predecessor.isSome { currentPredecessor -> - currentPredecessor.getJunctionPredecessorSuccessor().isSome { it !in remainingJunctionsIds } - } + currentPredecessor.getJunctionPredecessorSuccessor().isSome { it !in remainingJunctionsIds } + } ) { currentLink.predecessor = None } // remove the predecessor link, if it is a road, which is not contained in the remaining roads if (currentLink.predecessor.isSome { currentPredecessor -> - currentPredecessor.getRoadPredecessorSuccessor().isSome { it.first !in remainingRoadIds } - } + currentPredecessor.getRoadPredecessorSuccessor().isSome { it.first !in remainingRoadIds } + } ) { currentLink.predecessor = None } // remove the successor link, if it is a junction, which is not contained in the remaining junctions if (currentLink.successor.isSome { currentPredecessor -> - currentPredecessor.getJunctionPredecessorSuccessor().isSome { it !in remainingJunctionsIds } - } + currentPredecessor.getJunctionPredecessorSuccessor().isSome { it !in remainingJunctionsIds } + } ) { currentLink.successor = None } // remove the successor link, if it is a junction, which is not contained in the remaining junctions if (currentLink.successor.isSome { currentPredecessor -> - currentPredecessor.getRoadPredecessorSuccessor().isSome { it.first !in remainingRoadIds } - } + currentPredecessor.getRoadPredecessorSuccessor().isSome { it.first !in remainingRoadIds } + } ) { currentLink.successor = None } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropperParameters.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropperParameters.kt index 2164e11c..459eb49f 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropperParameters.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropperParameters.kt @@ -30,9 +30,8 @@ data class OpendriveCropperParameters( /** x values of cropping polygon */ val cropPolygonX: List, /** y values of cropping polygon */ - val cropPolygonY: List + val cropPolygonY: List, ) { - // Properties and Initializers init { require(cropPolygonX.isEmpty() || cropPolygonX.size >= 3) { "cropPolygonX must be empty or have at least three values." } @@ -42,10 +41,11 @@ data class OpendriveCropperParameters( // Methods fun getPolygon(): Option { - val vertices = cropPolygonX.zip(cropPolygonY) - .map { Vector2D(it.first, it.second) } - .toNonEmptyListOrNull() - .toOption() + val vertices = + cropPolygonX.zip(cropPolygonY) + .map { Vector2D(it.first, it.second) } + .toNonEmptyListOrNull() + .toOption() return vertices.map { Polygon2D(it, numberTolerance) } } diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropperReport.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropperReport.kt index de1cb5d2..35d2a38e 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropperReport.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/cropper/OpendriveCropperReport.kt @@ -25,5 +25,5 @@ data class OpendriveCropperReport( var numberOfRoadsOriginally: Int = 0, var numberOfRoadsRemaining: Int = 0, var numberOfJunctionsOriginally: Int = 0, - var numberOfJunctionsRemaining: Int = 0 + var numberOfJunctionsRemaining: Int = 0, ) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdder.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdder.kt index 966bad8b..73b1be88 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdder.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdder.kt @@ -23,9 +23,8 @@ import io.rtron.model.opendrive.additions.extensions.updateAdditionalIdentifiers import io.rtron.model.opendrive.core.HeaderOffset class OpendriveOffsetAdder( - val parameters: OpendriveOffsetAdderParameters + val parameters: OpendriveOffsetAdderParameters, ) { - /** * Adds the offset values to the OpenDRIVE header. */ diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdderParameters.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdderParameters.kt index 49faef33..afdc5877 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdderParameters.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdderParameters.kt @@ -27,7 +27,7 @@ data class OpendriveOffsetAdderParameters( /** offset by which the model is translated along the z-axis */ val offsetZ: Double, /** offset by which the model is rotated */ - val offsetHeading: Double + val offsetHeading: Double, ) { fun isZeroOffset() = offsetX == 0.0 && offsetY == 0.0 && offsetZ == 0.0 && offsetHeading == 0.0 diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdderReport.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdderReport.kt index ecebd668..4333e167 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdderReport.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/adder/OpendriveOffsetAdderReport.kt @@ -20,5 +20,5 @@ import kotlinx.serialization.Serializable @Serializable data class OpendriveOffsetAdderReport( - val parameters: OpendriveOffsetAdderParameters + val parameters: OpendriveOffsetAdderParameters, ) diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/resolver/OpendriveOffsetResolver.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/resolver/OpendriveOffsetResolver.kt index 0930e68f..07ba9937 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/resolver/OpendriveOffsetResolver.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/resolver/OpendriveOffsetResolver.kt @@ -32,7 +32,6 @@ import io.rtron.model.opendrive.road.elevation.RoadElevationProfileElevation * This resolution is implemented as a transformer, since most software tools are not supporting this feature yet. */ class OpendriveOffsetResolver { - fun modify(opendriveModel: OpendriveModel): Pair { val report = OpendriveOffsetResolverReport(emptyList()) @@ -47,13 +46,14 @@ class OpendriveOffsetResolver { modifiedOpendriveModel.header.offset = None // XY axes - modifiedOpendriveModel = everyRoadPlanViewGeometry.modify(modifiedOpendriveModel) { currentPlanViewGeometry -> - val modifiedPlanViewGeometry = currentPlanViewGeometry.copy() - modifiedPlanViewGeometry.x = modifiedPlanViewGeometry.x + headerOffset.x - modifiedPlanViewGeometry.y = modifiedPlanViewGeometry.y + headerOffset.y + modifiedOpendriveModel = + everyRoadPlanViewGeometry.modify(modifiedOpendriveModel) { currentPlanViewGeometry -> + val modifiedPlanViewGeometry = currentPlanViewGeometry.copy() + modifiedPlanViewGeometry.x = modifiedPlanViewGeometry.x + headerOffset.x + modifiedPlanViewGeometry.y = modifiedPlanViewGeometry.y + headerOffset.y - modifiedPlanViewGeometry - } + modifiedPlanViewGeometry + } // Z axis modifiedOpendriveModel = @@ -63,21 +63,22 @@ class OpendriveOffsetResolver { modifiedElevationProfileElement } - modifiedOpendriveModel = everyRoad.modify(modifiedOpendriveModel) { currentRoad -> - val modifiedRoad = currentRoad.copy() + modifiedOpendriveModel = + everyRoad.modify(modifiedOpendriveModel) { currentRoad -> + val modifiedRoad = currentRoad.copy() - if (modifiedRoad.elevationProfile.isNone()) { - modifiedRoad.elevationProfile = RoadElevationProfile(emptyList()).some() - } + if (modifiedRoad.elevationProfile.isNone()) { + modifiedRoad.elevationProfile = RoadElevationProfile(emptyList()).some() + } - modifiedRoad.elevationProfile.onSome { - if (it.elevation.isEmpty()) { - it.elevation += RoadElevationProfileElevation(headerOffset.z, 0.0, 0.0, 0.0, 0.0) + modifiedRoad.elevationProfile.onSome { + if (it.elevation.isEmpty()) { + it.elevation += RoadElevationProfileElevation(headerOffset.z, 0.0, 0.0, 0.0, 0.0) + } } - } - modifiedRoad - } + modifiedRoad + } report.messages += "Offset of x=${headerOffset.x}, y=${headerOffset.y}, z=${headerOffset.z} resolved." diff --git a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/resolver/OpendriveOffsetResolverReport.kt b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/resolver/OpendriveOffsetResolverReport.kt index 8f60b6c8..25cf15ec 100644 --- a/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/resolver/OpendriveOffsetResolverReport.kt +++ b/rtron-transformer/src/main/kotlin/io/rtron/transformer/modifiers/opendrive/offset/resolver/OpendriveOffsetResolverReport.kt @@ -20,5 +20,5 @@ import kotlinx.serialization.Serializable @Serializable data class OpendriveOffsetResolverReport( - var messages: List = emptyList() + var messages: List = emptyList(), ) 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 index cea81916..a74b691d 100644 --- 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 @@ -23,7 +23,7 @@ import io.rtron.model.opendrive.additions.optics.everyRoadObjectContainer import io.rtron.model.opendrive.objects.EObjectType class OpendriveObjectRemover( - val parameters: OpendriveObjectRemoverParameters + val parameters: OpendriveObjectRemoverParameters, ) { fun modify(opendriveModel: OpendriveModel): Pair { val report = OpendriveObjectRemoverReport(parameters) @@ -31,48 +31,53 @@ class OpendriveObjectRemover( modifiedOpendriveModel.updateAdditionalIdentifiers() if (parameters.removeRoadObjectsWithoutType) { - modifiedOpendriveModel = everyRoadObjectContainer.modify(modifiedOpendriveModel) { currentRoadObjectContainer -> - val numberOfRoadObjectsBefore = currentRoadObjectContainer.roadObject.count() + modifiedOpendriveModel = + everyRoadObjectContainer.modify(modifiedOpendriveModel) { currentRoadObjectContainer -> + val numberOfRoadObjectsBefore = currentRoadObjectContainer.roadObject.count() - currentRoadObjectContainer.roadObject = currentRoadObjectContainer.roadObject.filter { it.type.isSome() } + currentRoadObjectContainer.roadObject = currentRoadObjectContainer.roadObject.filter { it.type.isSome() } - report.numberOfRemovedRoadObjectsWithoutType += - currentRoadObjectContainer.roadObject.count() - numberOfRoadObjectsBefore + report.numberOfRemovedRoadObjectsWithoutType += + currentRoadObjectContainer.roadObject.count() - numberOfRoadObjectsBefore - currentRoadObjectContainer - } + currentRoadObjectContainer + } } if (parameters.removeRoadObjectsOfTypes.isNotEmpty()) { - modifiedOpendriveModel = everyRoadObjectContainer.modify(modifiedOpendriveModel) { currentRoadObjectContainer -> + modifiedOpendriveModel = + everyRoadObjectContainer.modify(modifiedOpendriveModel) { currentRoadObjectContainer -> - val numberOfRoadObjectsBefore: Map = currentRoadObjectContainer.roadObject - .map { it.type } - .flattenOption() - .groupingBy { it } - .eachCount() + 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) }) - } + 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() + 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 - } + 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 - } + 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 index ad1ee555..ffd68489 100644 --- 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 @@ -24,9 +24,8 @@ data class OpendriveObjectRemoverParameters( /** remove road objects without type */ val removeRoadObjectsWithoutType: Boolean, /** remove road objects of type */ - val removeRoadObjectsOfTypes: Set + 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 index 8358cd99..72173cde 100644 --- 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 @@ -23,5 +23,5 @@ import kotlinx.serialization.Serializable data class OpendriveObjectRemoverReport( val parameters: OpendriveObjectRemoverParameters, var numberOfRemovedRoadObjectsWithoutType: Int = 0, - val numberOfRemovedRoadObjectsWithType: MutableMap = mutableMapOf() + val numberOfRemovedRoadObjectsWithType: MutableMap = mutableMapOf(), )