All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.ru.casperix.math.intersection.Penetration.kt Maven / Gradle / Ivy

package ru.casperix.math.intersection

import ru.casperix.math.vector.float64.Vector2d
import kotlin.math.absoluteValue
import kotlin.math.sign

object Penetration {
	fun circleWithCircle(centerA: Vector2d, radiusA: Double, centerB: Vector2d, radiusB: Double): Vector2d? {
		val delta = centerB - centerA
		val dest = delta.length()
		val minDest = radiusA + radiusB
		if (dest >= minDest) return null

		return delta.normalize() * (minDest - dest)
	}

	fun rectangleWithRectangle(centerA: Vector2d, sizeA: Vector2d, centerB: Vector2d, sizeB: Vector2d): Vector2d? {
		val minX = sizeA.x * 0.5 + sizeB.x * 0.5
		val currentX = centerB.x - centerA.x
		val depthX = minX - currentX.absoluteValue
		if (depthX <= 0.0) return null

		val dimY = sizeA.y * 0.5 + sizeB.y * 0.5
		val deltaY = centerB.y - centerA.y
		val depthY = dimY - deltaY.absoluteValue
		if (depthY <= 0.0) return null

		if (depthX < depthY) {
			return Vector2d(depthX * currentX.sign, 0.0)
		} else {
			return Vector2d(0.0, depthY * deltaY.sign)
		}
	}

	fun rectangleWithCircle(rectanglePosition: Vector2d, rectangleSize: Vector2d, circlePosition: Vector2d, circleRadius: Double): Vector2d? {
		circleWithRectangle(circlePosition, circleRadius, rectanglePosition, rectangleSize)?.let {
			return -it
		}
		return null
	}

	fun circleWithRectangle(circlePosition: Vector2d, circleRadius: Double, rectanglePosition: Vector2d, rectangleSize: Vector2d): Vector2d? {
		val range = Vector2d(circleRadius)

		val rectangleMin = rectanglePosition - rectangleSize * 0.5
		val rectangleMax = rectanglePosition + rectangleSize * 0.5

		if (circlePosition.greater(rectangleMin) && circlePosition.less(rectangleMax)) {
			return rectangleWithRectangle(circlePosition, range + range, rectanglePosition, rectangleSize)
		}

		//	left-bottom-corner
		if (circlePosition.x < rectangleMin.x && circlePosition.y < rectangleMin.y) {
			val dir = rectangleMin - circlePosition
			if (dir.length() < circleRadius) return dir.normalize() * (circleRadius - dir.length())
		}

		//	left-top-corner
		if (circlePosition.x < rectangleMin.x && circlePosition.y > rectangleMax.y) {
			val dir = Vector2d(rectangleMin.x, rectangleMax.y) - circlePosition
			if (dir.length() < circleRadius) return dir.normalize() * (circleRadius - dir.length())
		}

		//	right-top-corner
		if (circlePosition.x > rectangleMax.x && circlePosition.y > rectangleMax.y) {
			val dir = rectangleMax - circlePosition
			if (dir.length() < circleRadius) return dir.normalize() * (circleRadius - dir.length())
		}

		//	right-bottom-corner
		if (circlePosition.x > rectangleMax.x && circlePosition.y < rectangleMin.y) {
			val dir = Vector2d(rectangleMax.x, rectangleMin.y) - circlePosition
			if (dir.length() < circleRadius) return dir.normalize() * (circleRadius - dir.length())
		}

		if (circlePosition.y >= rectangleMin.y && circlePosition.y <= rectangleMax.y) {
			val leftSpace = rectangleMin.x - circlePosition.x
			if (0.0 < leftSpace && leftSpace < circleRadius) {
				return Vector2d(circleRadius - leftSpace, 0.0)
			}

			val rightSpace = circlePosition.x - rectangleMax.x
			if (0.0 < rightSpace && rightSpace < circleRadius) {
				return Vector2d(rightSpace - circleRadius, 0.0)
			}
		}

		if (circlePosition.x >= rectangleMin.x && circlePosition.x <= rectangleMax.x) {
			val topSpace = circlePosition.y - rectangleMax.y
			if (0.0 < topSpace && topSpace < circleRadius) {
				return Vector2d(0.0, topSpace - circleRadius)
			}

			val bottomSpace = rectangleMin.y - circlePosition.y
			if (0.0 < bottomSpace && bottomSpace < circleRadius) {
				return Vector2d(0.0, circleRadius - bottomSpace)
			}
		}
		return null
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy