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

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

package ru.casperix.math.intersection

import ru.casperix.math.axis_aligned.int32.Axis3i
import ru.casperix.math.axis_aligned.float64.Box3d
import ru.casperix.math.geometry.Line3d
import ru.casperix.math.geometry.Quad3d
import ru.casperix.math.geometry.Triangle3d
import ru.casperix.math.geometry.delta
import ru.casperix.math.vector.float64.Vector3d


fun intersectionLineWithTriangle(ray: Line3d, triangle: Triangle3d): Vector3d? {
	val edge1 = triangle.v1 - triangle.v0
	val edge2 = triangle.v2 - triangle.v0

	val direction = ray.delta()
	val pVec = direction.cross(edge2)
	val determinant = edge1.dot(pVec)

	if (determinant == 0.0) {
		return null
	}

	val tVec = ray.v0 - triangle.v0
	val bv = tVec.dot(pVec) / determinant

	if (bv < 0 || bv > 1.0) {
		return null
	}

	val qVec = tVec.cross(edge1)

	val bw = direction.dot(qVec) / determinant;

	if (bw < 0 || bv + bw > 1.0) {
		return null
	}

	//check if the distance is longer than the predefined length.
	val distance = edge2.dot(qVec) / determinant;
	if (0.0 > distance || distance > 1.0 || !distance.isFinite()) {
		return null
	}

	return ray.v0 + (direction * distance)
}

fun intersectionLineWithQuad(ray: Line3d, quad: Quad3d): Vector3d? {
	for (partId in 0..1) {
		val part = intersectionLineWithTriangle(ray, quad.getFace(partId))
		if (part != null) return part
	}
	return null
}

data class FaceIntersection(val side: Axis3i, val point: Vector3d)

class BoxIntersection(val line: Line3d, val faces: List)

fun intersectionLineWithBox(ray: Line3d, box: Box3d): BoxIntersection? {
	val isFirstInside = box.isInside(ray.v0)
	val isLastInside = box.isInside(ray.v1)
	val faces = mutableListOf()

	if (isFirstInside && isLastInside) return BoxIntersection(ray, faces)

	val maxIntersectionAmount = if (isFirstInside != isLastInside) 1 else 2

	val list = ArrayList()
	for (faceId in Axis3i.values()) {
		val intersection = intersectionLineWithQuad(ray, box.getSideByDirection(faceId))
		if (intersection != null) {
			list.add(intersection)
			faces.add(FaceIntersection(faceId, intersection))

			if (list.size == maxIntersectionAmount) {
				break
			}
		}
	}

	val intersectionCount = list.size

	if ((maxIntersectionAmount == 1 && intersectionCount != 1) || (intersectionCount > 2)) {
		throw Error("Invalid intersection count: $intersectionCount; must be not bigger than: $maxIntersectionAmount; for $ray")
	}

	if (intersectionCount == 0) {
		return null
	} else if (intersectionCount == 1) {
		if (isFirstInside) {
			return BoxIntersection(Line3d(ray.v0, list[0]), faces)
		} else if (isLastInside) {
			return BoxIntersection(Line3d(ray.v1, list[0]), faces)
		} else {
			return BoxIntersection(Line3d(list[0], list[0]), faces)
		}
	}
	return BoxIntersection(Line3d(list[0], list[1]), faces)
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy