Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
commonMain.ru.casperix.math.geometry.float32.Geometry2Float.kt Maven / Gradle / Ivy
package ru.casperix.math.geometry.float32
import ru.casperix.math.geometry.GeometryApi
import ru.casperix.math.geometry.*
import ru.casperix.math.intersection.float32.Intersection2Float
import ru.casperix.math.straight_line.float32.LineSegment2f
import ru.casperix.math.vector.float32.Vector2f
import kotlin.math.*
object Geometry2Float : GeometryApi {
fun distPointToSegment(point: Vector2f, segment: LineSegment2f): Float {
return distPointToSegment(point, segment.toLine())
}
fun projectionByLine(source: Vector2f, segment: Line2f): Vector2f {
val direction = segment.delta()
return segment.v0 + projectionByDirection(source - segment.v0, direction)
}
fun projectionBySegment(source: Vector2f, segment: Line2f): Vector2f? {
val direction = segment.delta()
val length = projectionByDirectionLength(source - segment.v0, direction)
if (length < 0 || length > direction.length()) return null
return segment.v0 + direction.normalize() * length
}
fun projectionBySegmentAsSegment(source: Vector2f, segment: Line2f): Line2f? {
val projection = projectionBySegment(source, segment) ?: return null
return Line2f(source, projection)
}
fun projectionByLineAsSegment(source: Vector2f, segment: Line2f): Line2f {
val projection = projectionByLine(source, segment)
return Line2f(source, projection)
}
fun projectionBySegmentAsSegment(source: Vector2f, segmentStart: Vector2f, segmentFinish: Vector2f): Line2f? {
return projectionBySegmentAsSegment(source, Line2f(segmentStart, segmentFinish))
}
fun projectionByLineAsSegment(source: Vector2f, segmentStart: Vector2f, segmentFinish: Vector2f): Line2f {
return projectionByLineAsSegment(source, Line2f(segmentStart, segmentFinish))
}
override fun getPointAroundRay(
start: Vector2f,
finish: Vector2f,
point: Vector2f,
error: Float
): PointAroundRay {
val D = calculateDeterminant(start, finish, point)
if (D > error) return PointAroundRay.LEFT
if (D < -error) return PointAroundRay.RIGHT
return PointAroundRay.INSIDE
}
override fun calculateDeterminant(start: Vector2f, finish: Vector2f, point: Vector2f): Float {
return (finish.x - start.x) * (point.y - start.y) - (finish.y - start.y) * (point.x - start.x)
}
override fun distPointToQuad(P: Vector2f, quad: Quad2f): Float {
if (Intersection2Float.hasPointWithQuad(P, quad)) return 0f
return quad.getEdgeList().minOf { edge ->
distPointToSegment(P, edge)
}
}
override fun distPointToLine(P: Vector2f, T: Line2f): Float {
val x0 = P.x
val y0 = P.y
val x1 = T.v0.x
val y1 = T.v0.y
val x2 = T.v1.x
val y2 = T.v1.y
val f = (x2 - x1) * (y1 - y0) - (x1 - x0) * (y2 - y1)
val d = sqrt((x2 - x1).pow(2) + (y2 - y1).pow(2))
if (d == 0f) {
return P.distTo(T.v0)
}
return (f.absoluteValue / d)
}
/**
* https://www.geeksforgeeks.org/minimum-distance-from-a-point-to-the-line-segment-using-vectors/
*/
override fun distPointToSegment(P: Vector2f, A: Vector2f, B: Vector2f): Float {
val AB = B - A
val BP = P - B
val AP = P - A
// Variables to store dot product
// Calculating the dot product
val AB_BP = AB.dot(BP)
val AB_AP = AB.dot(AP)
// Minimum distance from
// point E to the line segment
return if (AB_BP > 0) {
// Case 1
val x = P.x - B.x
val y = P.y - B.y
sqrt(x * x + y * y)
} else if (AB_AP < 0) {
// Case 2
val x = P.x - A.x
val y = P.y - A.y
sqrt(x * x + y * y)
} else {
// Case 3
// Finding the perpendicular distance
val x1 = AB.x
val y1 = AB.y
val x2 = AP.x
val y2 = AP.y
val mod = sqrt(x1 * x1 + y1 * y1)
abs(x1 * y2 - y1 * x2) / mod
}
}
override fun projectionByDirection(source: Vector2f, direction: Vector2f): Vector2f {
val normalized = direction.normalize()
val length = source.dot(normalized)
return normalized * length
}
override fun projectionByDirectionLength(source: Vector2f, direction: Vector2f): Float {
val normalized = direction.normalize()
return source.dot(normalized)
}
fun closestSegmentPoint(line: Line2f, target: Vector2f): Vector2f {
val lineLength = line.length()
val lineDirection = line.delta()
val localOffset = Geometry2Float.projectionByDirectionLength(target - line.v0, lineDirection)
return if (localOffset < 0f) {
line.v0
} else if (localOffset <= lineLength) {
line.v0 + lineDirection * localOffset / lineLength
} else {
line.v1
}
}
fun closestConnectionBetweenSegments(aSegment: Line2f, bSegment: Line2f): Line2f {
val pivot = Intersection2Float.getSegmentWithSegment(aSegment, bSegment)
if (pivot != null) {
return Line2f(pivot, pivot)
}
val (l1, d1) = nearToSegmentAndDist(aSegment, bSegment.v0)
val (l2, d2) = nearToSegmentAndDist(aSegment, bSegment.v1)
val (l3, d3) = nearToSegmentAndDist(bSegment, aSegment.v0)
val (l4, d4) = nearToSegmentAndDist(bSegment, aSegment.v1)
val d = minOf(d1, d2, d3, d4)
if (d == d1) {
return l1
} else if (d == d2) {
return l2
} else if (d == d3) {
return l3
} else {
return l4
}
}
private fun nearToSegmentAndDist(line: Line2f, point: Vector2f): Pair {
val result = closestSegmentPoint(line, point)
return Pair(Line2f(point, result), result.distTo(point))
}
}