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

commonMain.earth.worldwind.geom.Line.kt Maven / Gradle / Ivy

Go to download

The WorldWind Kotlin SDK (WWK) includes the library, examples and tutorials for building multiplatform 3D virtual globe applications for Android, Web and Java.

The newest version!
package earth.worldwind.geom

import earth.worldwind.util.Logger.ERROR
import earth.worldwind.util.Logger.logMessage

/**
 * Represents a line in Cartesian coordinates.
 */
open class Line {
    /**
     * This line's origin.
     */
    val origin = Vec3()
    /**
     * This line's direction.
     */
    val direction = Vec3()

    /**
     * Constructs a line with origin and direction both zero.
     */
    constructor()

    /**
     * Constructs a line with a specified origin and direction.
     *
     * @param origin    the line's origin
     * @param direction the line's direction
     */
    constructor(origin: Vec3, direction: Vec3): this() { set(origin, direction) }

    /**
     * Constructs a line with the origin and direction from a specified line.
     *
     * @param line the line specifying origin and direction
     */
    constructor(line: Line): this(line.origin, line.direction)

    /**
     * Sets this line to a specified origin and direction.
     *
     * @param origin    the line's new origin
     * @param direction the line's new direction
     *
     * @return this line, set to the new origin and direction
     */
    fun set(origin: Vec3, direction: Vec3) = apply {
        this.origin.copy(origin)
        this.direction.copy(direction)
    }

    /**
     * Sets this line to the specified segment. This line has its origin at the first endpoint and its direction
     * extending from the first endpoint to the second.
     *
     * @param pointA the segment's first endpoint
     * @param pointB the segment's second endpoint
     *
     * @return this line, set to the specified segment
     */
    fun setToSegment(pointA: Vec3, pointB: Vec3) = apply {
        origin.copy(pointA)
        direction.set(pointB.x - pointA.x, pointB.y - pointA.y, pointB.z - pointA.z)
    }

    /**
     * Computes a Cartesian point a specified distance along this line.
     *
     * @param distance The distance from this line's origin at which to compute the point.
     * @param result   A pre-allocated [Vec3] instance in which to return the computed point.
     *
     * @return The specified result argument containing the computed point.
     */
    fun pointAt(distance: Double, result: Vec3): Vec3 {
        result.x = origin.x + direction.x * distance
        result.y = origin.y + direction.y * distance
        result.z = origin.z + direction.z * distance
        return result
    }

    /**
     * Computes the first intersection of a triangle strip with this line. This line is interpreted as a ray;
     * intersection points behind the line's origin are ignored.
     * 
* The triangle strip is specified by a list of vertex points and a list of elements indicating the triangle strip * tessellation of those vertices. The triangle strip elements are interpreted in the same manner as OpenGL, where * each index indicates a vertex position rather than an actual index into the points array (e.g. a triangle strip * index of 1 indicates the XYZ tuple starting at array index 3). * * @param points an array of points containing XYZ tuples * @param stride the number of coordinates between the first coordinate of adjacent points - must be at least 3 * @param elements an array of indices into the points defining the triangle strip organization * @param count the number of indices to consider * @param result a pre-allocated Vec3 in which to return the nearest intersection point, if any * * @return true if this line intersects the triangle strip, otherwise false * * @throws IllegalArgumentException If array is empty, if the stride is less than 3, * if the count is less than 0 */ fun triStripIntersection(points: FloatArray, stride: Int, elements: ShortArray, count: Int, result: Vec3): Boolean { require(points.size >= stride) { logMessage(ERROR, "Line", "triStripIntersection", "missingArray") } require(stride >= 3) { logMessage(ERROR, "Line", "triStripIntersection", "invalidStride") } require(elements.isNotEmpty()) { logMessage(ERROR, "Line", "triStripIntersection", "missingArray") } require(count >= 0) { logMessage(ERROR, "Line", "triStripIntersection", "invalidCount") } // Taken from Moller and Trumbore // http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf // Adapted from the original ray-triangle intersection algorithm to optimize for ray-triangle strip // intersection. We optimize by reusing constant terms, replacing use of Vec3 with inline primitives, and // exploiting the triangle strip organization to reuse computations common to adjacent triangles. These // optimizations reduced worst-case terrain picking performance for Web WorldWind by approximately 50% in // Chrome on a 2010 iMac and a Nexus 9. val vx = direction.x val vy = direction.y val vz = direction.z val sx = origin.x val sy = origin.y val sz = origin.z var tMin = Double.POSITIVE_INFINITY val epsilon = 0.00001 // Get the triangle strip's first vertex. var vertex = elements[0] * stride var vert1x = points[vertex++] var vert1y = points[vertex++] var vert1z = points[vertex] // Get the triangle strip's second vertex. vertex = elements[1] * stride var vert2x = points[vertex++] var vert2y = points[vertex++] var vert2z = points[vertex] // Compute the intersection of each triangle with the specified ray. for (idx in 2 until count) { // Move the last two vertices into the first two vertices. This takes advantage of the triangle strip's // structure and avoids redundant reads from points and elements. During the first iteration this places the // triangle strip's first three vertices in vert0, vert1 and vert2, respectively. val vert0x = vert1x val vert0y = vert1y val vert0z = vert1z vert1x = vert2x vert1y = vert2y vert1z = vert2z // Get the triangle strip's next vertex. vertex = elements[idx] * stride vert2x = points[vertex++] vert2y = points[vertex++] vert2z = points[vertex] // find vectors for two edges sharing point a: vert1 - vert0 and vert2 - vert0 val edge1x = vert1x - vert0x val edge1y = vert1y - vert0y val edge1z = vert1z - vert0z val edge2x = vert2x - vert0x val edge2y = vert2y - vert0y val edge2z = vert2z - vert0z // Compute cross product of line direction and edge2 val px = vy * edge2z - vz * edge2y val py = vz * edge2x - vx * edge2z val pz = vx * edge2y - vy * edge2x // Get determinant val det = edge1x * px + edge1y * py + edge1z * pz // edge1 dot p // if det is near zero then ray lies in plane of triangle if (det > -epsilon && det < epsilon) continue val invDet = 1.0 / det // Compute distance for vertex A to ray origin: origin - vert0 val tx = sx - vert0x val ty = sy - vert0y val tz = sz - vert0z // Calculate u parameter and test bounds: 1/det * t dot p val u = invDet * (tx * px + ty * py + tz * pz) if (u < -epsilon || u > 1 + epsilon) continue // Prepare to test v parameter: tvec cross edge1 val qx = ty * edge1z - tz * edge1y val qy = tz * edge1x - tx * edge1z val qz = tx * edge1y - ty * edge1x // Calculate v parameter and test bounds: 1/det * dir dot q val v = invDet * (vx * qx + vy * qy + vz * qz) if (v < -epsilon || u + v > 1 + epsilon) continue // Calculate the point of intersection on the line: t = 1/det * edge2 dot q val t = invDet * (edge2x * qx + edge2y * qy + edge2z * qz) if (t >= 0 && t < tMin) tMin = t } if (tMin != Double.POSITIVE_INFINITY) result.set(sx + vx * tMin, sy + vy * tMin, sz + vz * tMin) return tMin != Double.POSITIVE_INFINITY } override fun equals(other: Any?): Boolean { if (this === other) return true if (other !is Line) return false return origin == other.origin && direction == other.direction } override fun hashCode(): Int { var result = origin.hashCode() result = 31 * result + direction.hashCode() return result } override fun toString() = "Line(origin=$origin, direction=$direction)" }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy