io.rtron.math.geometry.euclidean.threed.surface.LinearRing3D.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of rtron-math Show documentation
Show all versions of rtron-math Show documentation
Component 'rtron-math' of rtron.
The newest version!
/*
* Copyright 2019-2022 Chair of Geoinformatics, Technical University of Munich
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.rtron.math.geometry.euclidean.threed.surface
import com.github.kittinunf.result.Result
import io.rtron.math.geometry.euclidean.threed.Geometry3DVisitor
import io.rtron.math.geometry.euclidean.threed.point.Vector3D
import io.rtron.math.linear.dimensionOfSpan
import io.rtron.math.processing.isColinear
import io.rtron.math.processing.isPlanar
import io.rtron.math.processing.triangulation.ExperimentalTriangulator
import io.rtron.math.processing.triangulation.Triangulator
import io.rtron.math.range.Tolerable
import io.rtron.math.transform.AffineSequence3D
import io.rtron.std.filterWithNextEnclosing
import io.rtron.std.noneWithNextEnclosing
/**
* Linear ring of a list of [vertices]. The linear ring is not required to be planar.
*
* @param vertices vertices for constructing the linear ring
*/
data class LinearRing3D(
val vertices: List,
override val tolerance: Double,
override val affineSequence: AffineSequence3D = AffineSequence3D.EMPTY
) : AbstractSurface3D(), Tolerable {
// Properties and Initializers
private val numberOfVertices = vertices.size
/** list of edges between the first vertex and all other vertices */
private val innerEdges = vertices.filterIndexed { index, _ -> index != 0 }.map { it - vertices.first() }
/** dimension of the polygon's span used to check whether the polygon is planar */
private val dimensionSpan = innerEdges.map { it.toRealVector() }.dimensionOfSpan()
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)." }
}
// Methods
/** Returns true if the vertices are placed in a plane */
fun isPlanar() = vertices.isPlanar(tolerance)
@OptIn(ExperimentalTriangulator::class)
override fun calculatePolygonsLocalCS(): Result, Exception> =
Triangulator.triangulate(this, tolerance)
override fun accept(visitor: Geometry3DVisitor) = visitor.visit(this)
companion object {
val UNIT = LinearRing3D(listOf(-Vector3D.X_AXIS, Vector3D.X_AXIS, Vector3D.Y_AXIS), 0.0)
/**
* Creates a linear ring based on the provided [vertices].
*/
fun of(vararg vertices: Vector3D, tolerance: Double) =
LinearRing3D(vertices.toList(), tolerance)
/**
* Creates multiple linear rings from two lists of vertices [leftVertices] and [rightVertices].
* A list of linear rings are created by iterating over both lists jointly.
*
* @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): List {
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 { listOf(it.first.right, it.second.right, it.second.left, it.first.left) }
return linearRingVertices.map { LinearRing3D(it, tolerance) }
}
/**
* Creates multiple linear rings from two lists of vertices [leftVertices] and [rightVertices].
* A list of linear rings are created by iterating over both lists jointly.
* Possible consecutively following point duplicates are removed before construction.
*
* @param leftVertices left vertices for the linear rings construction
* @param rightVertices right vertices for the linear rings construction
*/
fun ofWithDuplicatesRemoval(leftVertices: List, rightVertices: List, tolerance: Double):
Result, Exception> {
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 { listOf(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 { LinearRing3D(it, tolerance) }
.toList()
return if (linearRings.isEmpty()) Result.error(IllegalArgumentException("Not enough valid linear rings could be constructed."))
else Result.success(linearRings)
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy