1 module intersection_d; 2 3 import std.math: isNaN; 4 5 import Math = math; 6 7 import vector_2d; 8 import vector_3d; 9 import vector_4d; 10 11 /* 12 * The MIT License 13 * 14 * Copyright (c) 2015-2021 Kai Burjack 15 * 16 * Permission is hereby granted, free of charge, to any person obtaining a copy 17 * of this software and associated documentation files (the "Software"), to deal 18 * in the Software without restriction, including without limitation the rights 19 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 20 * copies of the Software, and to permit persons to whom the Software is 21 * furnished to do so, subject to the following conditions: 22 * 23 * The above copyright notice and this permission notice shall be included in 24 * all copies or substantial portions of the Software. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 27 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 29 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 31 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 32 * THE SOFTWARE. 33 */ 34 35 /** 36 * Contains intersection and distance tests for some 2D and 3D geometric primitives. 37 * 38 * @author Kai Burjack 39 */ 40 41 /** 42 * Return value of 43 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)}, 44 * {@link #findClosestPointOnTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d)}, 45 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and 46 * {@link #findClosestPointOnTriangle(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} or 47 * {@link #intersectSweptSphereTriangle} 48 * to signal that the closest point is the first vertex of the triangle. 49 */ 50 public static immutable int POINT_ON_TRIANGLE_VERTEX_0 = 1; 51 /** 52 * Return value of 53 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)}, 54 * {@link #findClosestPointOnTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d)}, 55 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and 56 * {@link #findClosestPointOnTriangle(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} or 57 * {@link #intersectSweptSphereTriangle} 58 * to signal that the closest point is the second vertex of the triangle. 59 */ 60 public static immutable int POINT_ON_TRIANGLE_VERTEX_1 = 2; 61 /** 62 * Return value of 63 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)}, 64 * {@link #findClosestPointOnTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d)}, 65 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and 66 * {@link #findClosestPointOnTriangle(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} or 67 * {@link #intersectSweptSphereTriangle} 68 * to signal that the closest point is the third vertex of the triangle. 69 */ 70 public static immutable int POINT_ON_TRIANGLE_VERTEX_2 = 3; 71 72 /** 73 * Return value of 74 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)}, 75 * {@link #findClosestPointOnTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d)}, 76 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and 77 * {@link #findClosestPointOnTriangle(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} or 78 * {@link #intersectSweptSphereTriangle} 79 * to signal that the closest point lies on the edge between the first and second vertex of the triangle. 80 */ 81 public static immutable int POINT_ON_TRIANGLE_EDGE_01 = 4; 82 /** 83 * Return value of 84 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)}, 85 * {@link #findClosestPointOnTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d)}, 86 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and 87 * {@link #findClosestPointOnTriangle(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} or 88 * {@link #intersectSweptSphereTriangle} 89 * to signal that the closest point lies on the edge between the second and third vertex of the triangle. 90 */ 91 public static immutable int POINT_ON_TRIANGLE_EDGE_12 = 5; 92 /** 93 * Return value of 94 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)}, 95 * {@link #findClosestPointOnTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d)}, 96 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and 97 * {@link #findClosestPointOnTriangle(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} or 98 * {@link #intersectSweptSphereTriangle} 99 * to signal that the closest point lies on the edge between the third and first vertex of the triangle. 100 */ 101 public static immutable int POINT_ON_TRIANGLE_EDGE_20 = 6; 102 103 /** 104 * Return value of 105 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, double, double, double, double, Vector3d)}, 106 * {@link #findClosestPointOnTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d)}, 107 * {@link #findClosestPointOnTriangle(double, double, double, double, double, double, double, double, Vector2d)} and 108 * {@link #findClosestPointOnTriangle(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} or 109 * {@link #intersectSweptSphereTriangle} 110 * to signal that the closest point lies on the face of the triangle. 111 */ 112 public static immutable int POINT_ON_TRIANGLE_FACE = 7; 113 114 /** 115 * Return value of {@link #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d)} and 116 * {@link #intersectRayAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} 117 * to indicate that the ray intersects the side of the axis-aligned rectangle with the minimum x coordinate. 118 */ 119 public static immutable int AAR_SIDE_MINX = 0; 120 /** 121 * Return value of {@link #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d)} and 122 * {@link #intersectRayAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} 123 * to indicate that the ray intersects the side of the axis-aligned rectangle with the minimum y coordinate. 124 */ 125 public static immutable int AAR_SIDE_MINY = 1; 126 /** 127 * Return value of {@link #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d)} and 128 * {@link #intersectRayAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} 129 * to indicate that the ray intersects the side of the axis-aligned rectangle with the maximum x coordinate. 130 */ 131 public static immutable int AAR_SIDE_MAXX = 2; 132 /** 133 * Return value of {@link #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d)} and 134 * {@link #intersectRayAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} 135 * to indicate that the ray intersects the side of the axis-aligned rectangle with the maximum y coordinate. 136 */ 137 public static immutable int AAR_SIDE_MAXY = 3; 138 139 /** 140 * Return value of {@link #intersectLineSegmentAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d)} and 141 * {@link #intersectLineSegmentAab(Vector3d, Vector3d, Vector3d, Vector3d, Vector2d)} to indicate that the line segment does not intersect the axis-aligned box; 142 * or return value of {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)} and 143 * {@link #intersectLineSegmentAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} to indicate that the line segment does not intersect the axis-aligned rectangle. 144 */ 145 public static immutable int OUTSIDE = -1; 146 /** 147 * Return value of {@link #intersectLineSegmentAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d)} and 148 * {@link #intersectLineSegmentAab(Vector3d, Vector3d, Vector3d, Vector3d, Vector2d)} to indicate that one end point of the line segment lies inside of the axis-aligned box; 149 * or return value of {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)} and 150 * {@link #intersectLineSegmentAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} to indicate that one end point of the line segment lies inside of the axis-aligned rectangle. 151 */ 152 public static immutable int ONE_INTERSECTION = 1; 153 /** 154 * Return value of {@link #intersectLineSegmentAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d)} and 155 * {@link #intersectLineSegmentAab(Vector3d, Vector3d, Vector3d, Vector3d, Vector2d)} to indicate that the line segment intersects two sides of the axis-aligned box 156 * or lies on an edge or a side of the box; 157 * or return value of {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)} and 158 * {@link #intersectLineSegmentAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} to indicate that the line segment intersects two edges of the axis-aligned rectangle 159 * or lies on an edge of the rectangle. 160 */ 161 public static immutable int TWO_INTERSECTION = 2; 162 /** 163 * Return value of {@link #intersectLineSegmentAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d)} and 164 * {@link #intersectLineSegmentAab(Vector3d, Vector3d, Vector3d, Vector3d, Vector2d)} to indicate that the line segment lies completely inside of the axis-aligned box; 165 * or return value of {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)} and 166 * {@link #intersectLineSegmentAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d)} to indicate that the line segment lies completely inside of the axis-aligned rectangle. 167 */ 168 public static immutable int INSIDE = 3; 169 170 /** 171 * Test whether the plane with the general plane equation <i>a*x + b*y + c*z + d = 0</i> intersects the sphere with center 172 * <code>(centerX, centerY, centerZ)</code> and <code>radius</code>. 173 * <p> 174 * Reference: <a href="http://math.stackexchange.com/questions/943383/determine-circle-of-intersection-of-plane-and-sphere">http://math.stackexchange.com</a> 175 * 176 * @param a 177 * the x factor in the plane equation 178 * @param b 179 * the y factor in the plane equation 180 * @param c 181 * the z factor in the plane equation 182 * @param d 183 * the constant in the plane equation 184 * @param centerX 185 * the x coordinate of the sphere's center 186 * @param centerY 187 * the y coordinate of the sphere's center 188 * @param centerZ 189 * the z coordinate of the sphere's center 190 * @param radius 191 * the radius of the sphere 192 * @return <code>true</code> iff the plane intersects the sphere; <code>false</code> otherwise 193 */ 194 public static bool testPlaneSphere( 195 double a, double b, double c, double d, 196 double centerX, double centerY, double centerZ, double radius) { 197 double denom = Math.sqrt(a * a + b * b + c * c); 198 double dist = (a * centerX + b * centerY + c * centerZ + d) / denom; 199 return -radius <= dist && dist <= radius; 200 } 201 202 /** 203 * Test whether the plane with the general plane equation <i>a*x + b*y + c*z + d = 0</i> intersects the sphere with center 204 * <code>(centerX, centerY, centerZ)</code> and <code>radius</code>, and store the center of the circle of 205 * intersection in the <code>(x, y, z)</code> components of the supplied vector and the radius of that circle in the w component. 206 * <p> 207 * Reference: <a href="http://math.stackexchange.com/questions/943383/determine-circle-of-intersection-of-plane-and-sphere">http://math.stackexchange.com</a> 208 * 209 * @param a 210 * the x factor in the plane equation 211 * @param b 212 * the y factor in the plane equation 213 * @param c 214 * the z factor in the plane equation 215 * @param d 216 * the constant in the plane equation 217 * @param centerX 218 * the x coordinate of the sphere's center 219 * @param centerY 220 * the y coordinate of the sphere's center 221 * @param centerZ 222 * the z coordinate of the sphere's center 223 * @param radius 224 * the radius of the sphere 225 * @param intersectionCenterAndRadius 226 * will hold the center of the circle of intersection in the <code>(x, y, z)</code> components and the radius in the w component 227 * @return <code>true</code> iff the plane intersects the sphere; <code>false</code> otherwise 228 */ 229 public static bool intersectPlaneSphere( 230 double a, double b, double c, double d, 231 double centerX, double centerY, double centerZ, double radius, 232 Vector4d intersectionCenterAndRadius) { 233 double invDenom = Math.invsqrt(a * a + b * b + c * c); 234 double dist = (a * centerX + b * centerY + c * centerZ + d) * invDenom; 235 if (-radius <= dist && dist <= radius) { 236 intersectionCenterAndRadius.x = centerX + dist * a * invDenom; 237 intersectionCenterAndRadius.y = centerY + dist * b * invDenom; 238 intersectionCenterAndRadius.z = centerZ + dist * c * invDenom; 239 intersectionCenterAndRadius.w = Math.sqrt(radius * radius - dist * dist); 240 return true; 241 } 242 return false; 243 } 244 245 /** 246 * Test whether the plane with the general plane equation <i>a*x + b*y + c*z + d = 0</i> intersects the moving sphere with center 247 * <code>(cX, cY, cZ)</code>, <code>radius</code> and velocity <code>(vX, vY, vZ)</code>, and store the point of intersection 248 * in the <code>(x, y, z)</code> components of the supplied vector and the time of intersection in the w component. 249 * <p> 250 * The normal vector <code>(a, b, c)</code> of the plane equation needs to be normalized. 251 * <p> 252 * Reference: Book "Real-Time Collision Detection" chapter 5.5.3 "Intersecting Moving Sphere Against Plane" 253 * 254 * @param a 255 * the x factor in the plane equation 256 * @param b 257 * the y factor in the plane equation 258 * @param c 259 * the z factor in the plane equation 260 * @param d 261 * the constant in the plane equation 262 * @param cX 263 * the x coordinate of the center position of the sphere at t=0 264 * @param cY 265 * the y coordinate of the center position of the sphere at t=0 266 * @param cZ 267 * the z coordinate of the center position of the sphere at t=0 268 * @param radius 269 * the sphere's radius 270 * @param vX 271 * the x component of the velocity of the sphere 272 * @param vY 273 * the y component of the velocity of the sphere 274 * @param vZ 275 * the z component of the velocity of the sphere 276 * @param pointAndTime 277 * will hold the point and time of intersection (if any) 278 * @return <code>true</code> iff the sphere intersects the plane; <code>false</code> otherwise 279 */ 280 public static bool intersectPlaneSweptSphere( 281 double a, double b, double c, double d, 282 double cX, double cY, double cZ, double radius, 283 double vX, double vY, double vZ, 284 Vector4d pointAndTime) { 285 // Compute distance of sphere center to plane 286 double dist = a * cX + b * cY + c * cZ - d; 287 if (Math.abs(dist) <= radius) { 288 // The sphere is already overlapping the plane. Set time of 289 // intersection to zero and q to sphere center 290 pointAndTime.set(cX, cY, cZ, 0.0); 291 return true; 292 } 293 double denom = a * vX + b * vY + c * vZ; 294 if (denom * dist >= 0.0) { 295 // No intersection as sphere moving parallel to or away from plane 296 return false; 297 } 298 // Sphere is moving towards the plane 299 // Use +r in computations if sphere in front of plane, else -r 300 double r = dist > 0.0 ? radius : -radius; 301 double t = (r - dist) / denom; 302 pointAndTime.set( 303 cX + t * vX - r * a, 304 cY + t * vY - r * b, 305 cZ + t * vZ - r * c, 306 t); 307 return true; 308 } 309 310 /** 311 * Test whether the plane with the general plane equation <i>a*x + b*y + c*z + d = 0</i> intersects the sphere moving from center 312 * position <code>(t0X, t0Y, t0Z)</code> to <code>(t1X, t1Y, t1Z)</code> and having the given <code>radius</code>. 313 * <p> 314 * The normal vector <code>(a, b, c)</code> of the plane equation needs to be normalized. 315 * <p> 316 * Reference: Book "Real-Time Collision Detection" chapter 5.5.3 "Intersecting Moving Sphere Against Plane" 317 * 318 * @param a 319 * the x factor in the plane equation 320 * @param b 321 * the y factor in the plane equation 322 * @param c 323 * the z factor in the plane equation 324 * @param d 325 * the constant in the plane equation 326 * @param t0X 327 * the x coordinate of the start position of the sphere 328 * @param t0Y 329 * the y coordinate of the start position of the sphere 330 * @param t0Z 331 * the z coordinate of the start position of the sphere 332 * @param r 333 * the sphere's radius 334 * @param t1X 335 * the x coordinate of the end position of the sphere 336 * @param t1Y 337 * the y coordinate of the end position of the sphere 338 * @param t1Z 339 * the z coordinate of the end position of the sphere 340 * @return <code>true</code> if the sphere intersects the plane; <code>false</code> otherwise 341 */ 342 public static bool testPlaneSweptSphere( 343 double a, double b, double c, double d, 344 double t0X, double t0Y, double t0Z, double r, 345 double t1X, double t1Y, double t1Z) { 346 // Get the distance for both a and b from plane p 347 double adist = t0X * a + t0Y * b + t0Z * c - d; 348 double bdist = t1X * a + t1Y * b + t1Z * c - d; 349 // Intersects if on different sides of plane (distances have different signs) 350 if (adist * bdist < 0.0) return true; 351 // Intersects if start or end position within radius from plane 352 if (Math.abs(adist) <= r || Math.abs(bdist) <= r) return true; 353 // No intersection 354 return false; 355 } 356 357 /** 358 * Test whether the axis-aligned box with minimum corner <code>(minX, minY, minZ)</code> and maximum corner <code>(maxX, maxY, maxZ)</code> 359 * intersects the plane with the general equation <i>a*x + b*y + c*z + d = 0</i>. 360 * <p> 361 * Reference: <a href="http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/">http://www.lighthouse3d.com</a> ("Geometric Approach - Testing Boxes II") 362 * 363 * @param minX 364 * the x coordinate of the minimum corner of the axis-aligned box 365 * @param minY 366 * the y coordinate of the minimum corner of the axis-aligned box 367 * @param minZ 368 * the z coordinate of the minimum corner of the axis-aligned box 369 * @param maxX 370 * the x coordinate of the maximum corner of the axis-aligned box 371 * @param maxY 372 * the y coordinate of the maximum corner of the axis-aligned box 373 * @param maxZ 374 * the z coordinate of the maximum corner of the axis-aligned box 375 * @param a 376 * the x factor in the plane equation 377 * @param b 378 * the y factor in the plane equation 379 * @param c 380 * the z factor in the plane equation 381 * @param d 382 * the constant in the plane equation 383 * @return <code>true</code> iff the axis-aligned box intersects the plane; <code>false</code> otherwise 384 */ 385 public static bool testAabPlane( 386 double minX, double minY, double minZ, 387 double maxX, double maxY, double maxZ, 388 double a, double b, double c, double d) { 389 double pX, pY, pZ, nX, nY, nZ; 390 if (a > 0.0) { 391 pX = maxX; 392 nX = minX; 393 } else { 394 pX = minX; 395 nX = maxX; 396 } 397 if (b > 0.0) { 398 pY = maxY; 399 nY = minY; 400 } else { 401 pY = minY; 402 nY = maxY; 403 } 404 if (c > 0.0) { 405 pZ = maxZ; 406 nZ = minZ; 407 } else { 408 pZ = minZ; 409 nZ = maxZ; 410 } 411 double distN = d + a * nX + b * nY + c * nZ; 412 double distP = d + a * pX + b * pY + c * pZ; 413 return distN <= 0.0 && distP >= 0.0; 414 } 415 416 /** 417 * Test whether the axis-aligned box with minimum corner <code>min</code> and maximum corner <code>max</code> 418 * intersects the plane with the general equation <i>a*x + b*y + c*z + d = 0</i>. 419 * <p> 420 * Reference: <a href="http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/">http://www.lighthouse3d.com</a> ("Geometric Approach - Testing Boxes II") 421 * 422 * @param min 423 * the minimum corner of the axis-aligned box 424 * @param max 425 * the maximum corner of the axis-aligned box 426 * @param a 427 * the x factor in the plane equation 428 * @param b 429 * the y factor in the plane equation 430 * @param c 431 * the z factor in the plane equation 432 * @param d 433 * the constant in the plane equation 434 * @return <code>true</code> iff the axis-aligned box intersects the plane; <code>false</code> otherwise 435 */ 436 public static bool testAabPlane(Vector3d min, Vector3d max, double a, double b, double c, double d) { 437 return testAabPlane(min.x, min.y, min.z, max.x, max.y, max.z, a, b, c, d); 438 } 439 440 /** 441 * Test whether the axis-aligned box with minimum corner <code>(minXA, minYA, minZA)</code> and maximum corner <code>(maxXA, maxYA, maxZA)</code> 442 * intersects the axis-aligned box with minimum corner <code>(minXB, minYB, minZB)</code> and maximum corner <code>(maxXB, maxYB, maxZB)</code>. 443 * 444 * @param minXA 445 * the x coordinate of the minimum corner of the first axis-aligned box 446 * @param minYA 447 * the y coordinate of the minimum corner of the first axis-aligned box 448 * @param minZA 449 * the z coordinate of the minimum corner of the first axis-aligned box 450 * @param maxXA 451 * the x coordinate of the maximum corner of the first axis-aligned box 452 * @param maxYA 453 * the y coordinate of the maximum corner of the first axis-aligned box 454 * @param maxZA 455 * the z coordinate of the maximum corner of the first axis-aligned box 456 * @param minXB 457 * the x coordinate of the minimum corner of the second axis-aligned box 458 * @param minYB 459 * the y coordinate of the minimum corner of the second axis-aligned box 460 * @param minZB 461 * the z coordinate of the minimum corner of the second axis-aligned box 462 * @param maxXB 463 * the x coordinate of the maximum corner of the second axis-aligned box 464 * @param maxYB 465 * the y coordinate of the maximum corner of the second axis-aligned box 466 * @param maxZB 467 * the z coordinate of the maximum corner of the second axis-aligned box 468 * @return <code>true</code> iff both axis-aligned boxes intersect; <code>false</code> otherwise 469 */ 470 public static bool testAabAab( 471 double minXA, double minYA, double minZA, 472 double maxXA, double maxYA, double maxZA, 473 double minXB, double minYB, double minZB, 474 double maxXB, double maxYB, double maxZB) { 475 return maxXA >= minXB && maxYA >= minYB && maxZA >= minZB && 476 minXA <= maxXB && minYA <= maxYB && minZA <= maxZB; 477 } 478 479 /** 480 * Test whether the axis-aligned box with minimum corner <code>minA</code> and maximum corner <code>maxA</code> 481 * intersects the axis-aligned box with minimum corner <code>minB</code> and maximum corner <code>maxB</code>. 482 * 483 * @param minA 484 * the minimum corner of the first axis-aligned box 485 * @param maxA 486 * the maximum corner of the first axis-aligned box 487 * @param minB 488 * the minimum corner of the second axis-aligned box 489 * @param maxB 490 * the maximum corner of the second axis-aligned box 491 * @return <code>true</code> iff both axis-aligned boxes intersect; <code>false</code> otherwise 492 */ 493 public static bool testAabAab(Vector3d minA, Vector3d maxA, Vector3d minB, Vector3d maxB) { 494 return testAabAab(minA.x, minA.y, minA.z, maxA.x, maxA.y, maxA.z, minB.x, minB.y, minB.z, maxB.x, maxB.y, maxB.z); 495 } 496 497 /** 498 * Test whether two oriented boxes given via their center position, orientation and half-size, intersect. 499 * <p> 500 * The orientation of a box is given as three unit vectors spanning the local orthonormal basis of the box. 501 * <p> 502 * The size is given as the half-size along each of the unit vectors defining the orthonormal basis. 503 * <p> 504 * Reference: Book "Real-Time Collision Detection" chapter 4.4.1 "OBB-OBB Intersection" 505 * 506 * @param b0c 507 * the center of the first box 508 * @param b0uX 509 * the local X unit vector of the first box 510 * @param b0uY 511 * the local Y unit vector of the first box 512 * @param b0uZ 513 * the local Z unit vector of the first box 514 * @param b0hs 515 * the half-size of the first box 516 * @param b1c 517 * the center of the second box 518 * @param b1uX 519 * the local X unit vector of the second box 520 * @param b1uY 521 * the local Y unit vector of the second box 522 * @param b1uZ 523 * the local Z unit vector of the second box 524 * @param b1hs 525 * the half-size of the second box 526 * @return <code>true</code> if both boxes intersect; <code>false</code> otherwise 527 */ 528 public static bool testObOb( 529 Vector3d b0c, Vector3d b0uX, Vector3d b0uY, Vector3d b0uZ, Vector3d b0hs, 530 Vector3d b1c, Vector3d b1uX, Vector3d b1uY, Vector3d b1uZ, Vector3d b1hs) { 531 return testObOb( 532 b0c.x, b0c.y, b0c.z, b0uX.x, b0uX.y, b0uX.z, b0uY.x, b0uY.y, b0uY.z, b0uZ.x, b0uZ.y, b0uZ.z, b0hs.x, b0hs.y, b0hs.z, 533 b1c.x, b1c.y, b1c.z, b1uX.x, b1uX.y, b1uX.z, b1uY.x, b1uY.y, b1uY.z, b1uZ.x, b1uZ.y, b1uZ.z, b1hs.x, b1hs.y, b1hs.z); 534 } 535 536 /** 537 * Test whether two oriented boxes given via their center position, orientation and half-size, intersect. 538 * <p> 539 * The orientation of a box is given as three unit vectors spanning the local orthonormal basis of the box. 540 * <p> 541 * The size is given as the half-size along each of the unit vectors defining the orthonormal basis. 542 * <p> 543 * Reference: Book "Real-Time Collision Detection" chapter 4.4.1 "OBB-OBB Intersection" 544 * 545 * @param b0cX 546 * the x coordinate of the center of the first box 547 * @param b0cY 548 * the y coordinate of the center of the first box 549 * @param b0cZ 550 * the z coordinate of the center of the first box 551 * @param b0uXx 552 * the x coordinate of the local X unit vector of the first box 553 * @param b0uXy 554 * the y coordinate of the local X unit vector of the first box 555 * @param b0uXz 556 * the z coordinate of the local X unit vector of the first box 557 * @param b0uYx 558 * the x coordinate of the local Y unit vector of the first box 559 * @param b0uYy 560 * the y coordinate of the local Y unit vector of the first box 561 * @param b0uYz 562 * the z coordinate of the local Y unit vector of the first box 563 * @param b0uZx 564 * the x coordinate of the local Z unit vector of the first box 565 * @param b0uZy 566 * the y coordinate of the local Z unit vector of the first box 567 * @param b0uZz 568 * the z coordinate of the local Z unit vector of the first box 569 * @param b0hsX 570 * the half-size of the first box along its local X axis 571 * @param b0hsY 572 * the half-size of the first box along its local Y axis 573 * @param b0hsZ 574 * the half-size of the first box along its local Z axis 575 * @param b1cX 576 * the x coordinate of the center of the second box 577 * @param b1cY 578 * the y coordinate of the center of the second box 579 * @param b1cZ 580 * the z coordinate of the center of the second box 581 * @param b1uXx 582 * the x coordinate of the local X unit vector of the second box 583 * @param b1uXy 584 * the y coordinate of the local X unit vector of the second box 585 * @param b1uXz 586 * the z coordinate of the local X unit vector of the second box 587 * @param b1uYx 588 * the x coordinate of the local Y unit vector of the second box 589 * @param b1uYy 590 * the y coordinate of the local Y unit vector of the second box 591 * @param b1uYz 592 * the z coordinate of the local Y unit vector of the second box 593 * @param b1uZx 594 * the x coordinate of the local Z unit vector of the second box 595 * @param b1uZy 596 * the y coordinate of the local Z unit vector of the second box 597 * @param b1uZz 598 * the z coordinate of the local Z unit vector of the second box 599 * @param b1hsX 600 * the half-size of the second box along its local X axis 601 * @param b1hsY 602 * the half-size of the second box along its local Y axis 603 * @param b1hsZ 604 * the half-size of the second box along its local Z axis 605 * @return <code>true</code> if both boxes intersect; <code>false</code> otherwise 606 */ 607 public static bool testObOb( 608 double b0cX, double b0cY, double b0cZ, double b0uXx, double b0uXy, double b0uXz, double b0uYx, double b0uYy, double b0uYz, double b0uZx, double b0uZy, double b0uZz, double b0hsX, double b0hsY, double b0hsZ, 609 double b1cX, double b1cY, double b1cZ, double b1uXx, double b1uXy, double b1uXz, double b1uYx, double b1uYy, double b1uYz, double b1uZx, double b1uZy, double b1uZz, double b1hsX, double b1hsY, double b1hsZ) { 610 double ra, rb; 611 // Compute rotation matrix expressing b in a's coordinate frame 612 double rm00 = b0uXx * b1uXx + b0uYx * b1uYx + b0uZx * b1uZx; 613 double rm10 = b0uXx * b1uXy + b0uYx * b1uYy + b0uZx * b1uZy; 614 double rm20 = b0uXx * b1uXz + b0uYx * b1uYz + b0uZx * b1uZz; 615 double rm01 = b0uXy * b1uXx + b0uYy * b1uYx + b0uZy * b1uZx; 616 double rm11 = b0uXy * b1uXy + b0uYy * b1uYy + b0uZy * b1uZy; 617 double rm21 = b0uXy * b1uXz + b0uYy * b1uYz + b0uZy * b1uZz; 618 double rm02 = b0uXz * b1uXx + b0uYz * b1uYx + b0uZz * b1uZx; 619 double rm12 = b0uXz * b1uXy + b0uYz * b1uYy + b0uZz * b1uZy; 620 double rm22 = b0uXz * b1uXz + b0uYz * b1uYz + b0uZz * b1uZz; 621 // Compute common subexpressions. Add in an epsilon term to 622 // counteract arithmetic errors when two edges are parallel and 623 // their cross product is (near) null (see text for details) 624 double EPSILON = 1E-8; 625 double arm00 = Math.abs(rm00) + EPSILON; 626 double arm01 = Math.abs(rm01) + EPSILON; 627 double arm02 = Math.abs(rm02) + EPSILON; 628 double arm10 = Math.abs(rm10) + EPSILON; 629 double arm11 = Math.abs(rm11) + EPSILON; 630 double arm12 = Math.abs(rm12) + EPSILON; 631 double arm20 = Math.abs(rm20) + EPSILON; 632 double arm21 = Math.abs(rm21) + EPSILON; 633 double arm22 = Math.abs(rm22) + EPSILON; 634 // Compute translation vector t 635 double tx = b1cX - b0cX, ty = b1cY - b0cY, tz = b1cZ - b0cZ; 636 // Bring translation into a's coordinate frame 637 double tax = tx * b0uXx + ty * b0uXy + tz * b0uXz; 638 double tay = tx * b0uYx + ty * b0uYy + tz * b0uYz; 639 double taz = tx * b0uZx + ty * b0uZy + tz * b0uZz; 640 // Test axes L = A0, L = A1, L = A2 641 ra = b0hsX; 642 rb = b1hsX * arm00 + b1hsY * arm01 + b1hsZ * arm02; 643 if (Math.abs(tax) > ra + rb) return false; 644 ra = b0hsY; 645 rb = b1hsX * arm10 + b1hsY * arm11 + b1hsZ * arm12; 646 if (Math.abs(tay) > ra + rb) return false; 647 ra = b0hsZ; 648 rb = b1hsX * arm20 + b1hsY * arm21 + b1hsZ * arm22; 649 if (Math.abs(taz) > ra + rb) return false; 650 // Test axes L = B0, L = B1, L = B2 651 ra = b0hsX * arm00 + b0hsY * arm10 + b0hsZ * arm20; 652 rb = b1hsX; 653 if (Math.abs(tax * rm00 + tay * rm10 + taz * rm20) > ra + rb) return false; 654 ra = b0hsX * arm01 + b0hsY * arm11 + b0hsZ * arm21; 655 rb = b1hsY; 656 if (Math.abs(tax * rm01 + tay * rm11 + taz * rm21) > ra + rb) return false; 657 ra = b0hsX * arm02 + b0hsY * arm12 + b0hsZ * arm22; 658 rb = b1hsZ; 659 if (Math.abs(tax * rm02 + tay * rm12 + taz * rm22) > ra + rb) return false; 660 // Test axis L = A0 x B0 661 ra = b0hsY * arm20 + b0hsZ * arm10; 662 rb = b1hsY * arm02 + b1hsZ * arm01; 663 if (Math.abs(taz * rm10 - tay * rm20) > ra + rb) return false; 664 // Test axis L = A0 x B1 665 ra = b0hsY * arm21 + b0hsZ * arm11; 666 rb = b1hsX * arm02 + b1hsZ * arm00; 667 if (Math.abs(taz * rm11 - tay * rm21) > ra + rb) return false; 668 // Test axis L = A0 x B2 669 ra = b0hsY * arm22 + b0hsZ * arm12; 670 rb = b1hsX * arm01 + b1hsY * arm00; 671 if (Math.abs(taz * rm12 - tay * rm22) > ra + rb) return false; 672 // Test axis L = A1 x B0 673 ra = b0hsX * arm20 + b0hsZ * arm00; 674 rb = b1hsY * arm12 + b1hsZ * arm11; 675 if (Math.abs(tax * rm20 - taz * rm00) > ra + rb) return false; 676 // Test axis L = A1 x B1 677 ra = b0hsX * arm21 + b0hsZ * arm01; 678 rb = b1hsX * arm12 + b1hsZ * arm10; 679 if (Math.abs(tax * rm21 - taz * rm01) > ra + rb) return false; 680 // Test axis L = A1 x B2 681 ra = b0hsX * arm22 + b0hsZ * arm02; 682 rb = b1hsX * arm11 + b1hsY * arm10; 683 if (Math.abs(tax * rm22 - taz * rm02) > ra + rb) return false; 684 // Test axis L = A2 x B0 685 ra = b0hsX * arm10 + b0hsY * arm00; 686 rb = b1hsY * arm22 + b1hsZ * arm21; 687 if (Math.abs(tay * rm00 - tax * rm10) > ra + rb) return false; 688 // Test axis L = A2 x B1 689 ra = b0hsX * arm11 + b0hsY * arm01; 690 rb = b1hsX * arm22 + b1hsZ * arm20; 691 if (Math.abs(tay * rm01 - tax * rm11) > ra + rb) return false; 692 // Test axis L = A2 x B2 693 ra = b0hsX * arm12 + b0hsY * arm02; 694 rb = b1hsX * arm21 + b1hsY * arm20; 695 if (Math.abs(tay * rm02 - tax * rm12) > ra + rb) return false; 696 // Since no separating axis is found, the OBBs must be intersecting 697 return true; 698 } 699 700 /** 701 * Test whether the one sphere with center <code>(aX, aY, aZ)</code> and square radius <code>radiusSquaredA</code> intersects the other 702 * sphere with center <code>(bX, bY, bZ)</code> and square radius <code>radiusSquaredB</code>, and store the center of the circle of 703 * intersection in the <code>(x, y, z)</code> components of the supplied vector and the radius of that circle in the w component. 704 * <p> 705 * The normal vector of the circle of intersection can simply be obtained by subtracting the center of either sphere from the other. 706 * <p> 707 * Reference: <a href="http://gamedev.stackexchange.com/questions/75756/sphere-sphere-intersection-and-circle-sphere-intersection">http://gamedev.stackexchange.com</a> 708 * 709 * @param aX 710 * the x coordinate of the first sphere's center 711 * @param aY 712 * the y coordinate of the first sphere's center 713 * @param aZ 714 * the z coordinate of the first sphere's center 715 * @param radiusSquaredA 716 * the square of the first sphere's radius 717 * @param bX 718 * the x coordinate of the second sphere's center 719 * @param bY 720 * the y coordinate of the second sphere's center 721 * @param bZ 722 * the z coordinate of the second sphere's center 723 * @param radiusSquaredB 724 * the square of the second sphere's radius 725 * @param centerAndRadiusOfIntersectionCircle 726 * will hold the center of the circle of intersection in the <code>(x, y, z)</code> components and the radius in the w component 727 * @return <code>true</code> iff both spheres intersect; <code>false</code> otherwise 728 */ 729 public static bool intersectSphereSphere( 730 double aX, double aY, double aZ, double radiusSquaredA, 731 double bX, double bY, double bZ, double radiusSquaredB, 732 Vector4d centerAndRadiusOfIntersectionCircle) { 733 double dX = bX - aX, dY = bY - aY, dZ = bZ - aZ; 734 double distSquared = dX * dX + dY * dY + dZ * dZ; 735 double h = 0.5 + (radiusSquaredA - radiusSquaredB) / (2.0 * distSquared); 736 double r_i = radiusSquaredA - h * h * distSquared; 737 if (r_i >= 0.0) { 738 centerAndRadiusOfIntersectionCircle.x = aX + h * dX; 739 centerAndRadiusOfIntersectionCircle.y = aY + h * dY; 740 centerAndRadiusOfIntersectionCircle.z = aZ + h * dZ; 741 centerAndRadiusOfIntersectionCircle.w = Math.sqrt(r_i); 742 return true; 743 } 744 return false; 745 } 746 747 /** 748 * Test whether the one sphere with center <code>centerA</code> and square radius <code>radiusSquaredA</code> intersects the other 749 * sphere with center <code>centerB</code> and square radius <code>radiusSquaredB</code>, and store the center of the circle of 750 * intersection in the <code>(x, y, z)</code> components of the supplied vector and the radius of that circle in the w component. 751 * <p> 752 * The normal vector of the circle of intersection can simply be obtained by subtracting the center of either sphere from the other. 753 * <p> 754 * Reference: <a href="http://gamedev.stackexchange.com/questions/75756/sphere-sphere-intersection-and-circle-sphere-intersection">http://gamedev.stackexchange.com</a> 755 * 756 * @param centerA 757 * the first sphere's center 758 * @param radiusSquaredA 759 * the square of the first sphere's radius 760 * @param centerB 761 * the second sphere's center 762 * @param radiusSquaredB 763 * the square of the second sphere's radius 764 * @param centerAndRadiusOfIntersectionCircle 765 * will hold the center of the circle of intersection in the <code>(x, y, z)</code> components and the radius in the w component 766 * @return <code>true</code> iff both spheres intersect; <code>false</code> otherwise 767 */ 768 public static bool intersectSphereSphere(Vector3d centerA, double radiusSquaredA, Vector3d centerB, double radiusSquaredB, Vector4d centerAndRadiusOfIntersectionCircle) { 769 return intersectSphereSphere(centerA.x, centerA.y, centerA.z, radiusSquaredA, centerB.x, centerB.y, centerB.z, radiusSquaredB, centerAndRadiusOfIntersectionCircle); 770 } 771 772 /** 773 * Test whether the given sphere with center <code>(sX, sY, sZ)</code> intersects the triangle given by its three vertices, and if they intersect 774 * store the point of intersection into <code>result</code>. 775 * <p> 776 * This method also returns whether the point of intersection is on one of the triangle's vertices, edges or on the face. 777 * <p> 778 * Reference: Book "Real-Time Collision Detection" chapter 5.2.7 "Testing Sphere Against Triangle" 779 * 780 * @param sX 781 * the x coordinate of the sphere's center 782 * @param sY 783 * the y coordinate of the sphere's center 784 * @param sZ 785 * the z coordinate of the sphere's center 786 * @param sR 787 * the sphere's radius 788 * @param v0X 789 * the x coordinate of the first vertex of the triangle 790 * @param v0Y 791 * the y coordinate of the first vertex of the triangle 792 * @param v0Z 793 * the z coordinate of the first vertex of the triangle 794 * @param v1X 795 * the x coordinate of the second vertex of the triangle 796 * @param v1Y 797 * the y coordinate of the second vertex of the triangle 798 * @param v1Z 799 * the z coordinate of the second vertex of the triangle 800 * @param v2X 801 * the x coordinate of the third vertex of the triangle 802 * @param v2Y 803 * the y coordinate of the third vertex of the triangle 804 * @param v2Z 805 * the z coordinate of the third vertex of the triangle 806 * @param result 807 * will hold the point of intersection 808 * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2}, 809 * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or 810 * {@link #POINT_ON_TRIANGLE_FACE} or <code>0</code> 811 */ 812 public static int intersectSphereTriangle( 813 double sX, double sY, double sZ, double sR, 814 double v0X, double v0Y, double v0Z, 815 double v1X, double v1Y, double v1Z, 816 double v2X, double v2Y, double v2Z, 817 Vector3d result) { 818 int closest = findClosestPointOnTriangle(v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z, sX, sY, sZ, result); 819 double vX = result.x - sX, vY = result.y - sY, vZ = result.z - sZ; 820 double dot = vX * vX + vY * vY + vZ * vZ; 821 if (dot <= sR * sR) { 822 return closest; 823 } 824 return 0; 825 } 826 827 /** 828 * Test whether the one sphere with center <code>(aX, aY, aZ)</code> and square radius <code>radiusSquaredA</code> intersects the other 829 * sphere with center <code>(bX, bY, bZ)</code> and square radius <code>radiusSquaredB</code>. 830 * <p> 831 * Reference: <a href="http://gamedev.stackexchange.com/questions/75756/sphere-sphere-intersection-and-circle-sphere-intersection">http://gamedev.stackexchange.com</a> 832 * 833 * @param aX 834 * the x coordinate of the first sphere's center 835 * @param aY 836 * the y coordinate of the first sphere's center 837 * @param aZ 838 * the z coordinate of the first sphere's center 839 * @param radiusSquaredA 840 * the square of the first sphere's radius 841 * @param bX 842 * the x coordinate of the second sphere's center 843 * @param bY 844 * the y coordinate of the second sphere's center 845 * @param bZ 846 * the z coordinate of the second sphere's center 847 * @param radiusSquaredB 848 * the square of the second sphere's radius 849 * @return <code>true</code> iff both spheres intersect; <code>false</code> otherwise 850 */ 851 public static bool testSphereSphere( 852 double aX, double aY, double aZ, double radiusSquaredA, 853 double bX, double bY, double bZ, double radiusSquaredB) { 854 double dX = bX - aX, dY = bY - aY, dZ = bZ - aZ; 855 double distSquared = dX * dX + dY * dY + dZ * dZ; 856 double h = 0.5 + (radiusSquaredA - radiusSquaredB) / (2.0 * distSquared); 857 double r_i = radiusSquaredA - h * h * distSquared; 858 return r_i >= 0.0; 859 } 860 861 /** 862 * Test whether the one sphere with center <code>centerA</code> and square radius <code>radiusSquaredA</code> intersects the other 863 * sphere with center <code>centerB</code> and square radius <code>radiusSquaredB</code>. 864 * <p> 865 * Reference: <a href="http://gamedev.stackexchange.com/questions/75756/sphere-sphere-intersection-and-circle-sphere-intersection">http://gamedev.stackexchange.com</a> 866 * 867 * @param centerA 868 * the first sphere's center 869 * @param radiusSquaredA 870 * the square of the first sphere's radius 871 * @param centerB 872 * the second sphere's center 873 * @param radiusSquaredB 874 * the square of the second sphere's radius 875 * @return <code>true</code> iff both spheres intersect; <code>false</code> otherwise 876 */ 877 public static bool testSphereSphere(Vector3d centerA, double radiusSquaredA, Vector3d centerB, double radiusSquaredB) { 878 return testSphereSphere(centerA.x, centerA.y, centerA.z, radiusSquaredA, centerB.x, centerB.y, centerB.z, radiusSquaredB); 879 } 880 881 /** 882 * Determine the signed distance of the given point <code>(pointX, pointY, pointZ)</code> to the plane specified via its general plane equation 883 * <i>a*x + b*y + c*z + d = 0</i>. 884 * 885 * @param pointX 886 * the x coordinate of the point 887 * @param pointY 888 * the y coordinate of the point 889 * @param pointZ 890 * the z coordinate of the point 891 * @param a 892 * the x factor in the plane equation 893 * @param b 894 * the y factor in the plane equation 895 * @param c 896 * the z factor in the plane equation 897 * @param d 898 * the constant in the plane equation 899 * @return the distance between the point and the plane 900 */ 901 public static double distancePointPlane(double pointX, double pointY, double pointZ, double a, double b, double c, double d) { 902 double denom = Math.sqrt(a * a + b * b + c * c); 903 return (a * pointX + b * pointY + c * pointZ + d) / denom; 904 } 905 906 /** 907 * Determine the signed distance of the given point <code>(pointX, pointY, pointZ)</code> to the plane of the triangle specified by its three points 908 * <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code>. 909 * <p> 910 * If the point lies on the front-facing side of the triangle's plane, that is, if the triangle has counter-clockwise winding order 911 * as seen from the point, then this method returns a positive number. 912 * 913 * @param pointX 914 * the x coordinate of the point 915 * @param pointY 916 * the y coordinate of the point 917 * @param pointZ 918 * the z coordinate of the point 919 * @param v0X 920 * the x coordinate of the first vertex of the triangle 921 * @param v0Y 922 * the y coordinate of the first vertex of the triangle 923 * @param v0Z 924 * the z coordinate of the first vertex of the triangle 925 * @param v1X 926 * the x coordinate of the second vertex of the triangle 927 * @param v1Y 928 * the y coordinate of the second vertex of the triangle 929 * @param v1Z 930 * the z coordinate of the second vertex of the triangle 931 * @param v2X 932 * the x coordinate of the third vertex of the triangle 933 * @param v2Y 934 * the y coordinate of the third vertex of the triangle 935 * @param v2Z 936 * the z coordinate of the third vertex of the triangle 937 * @return the signed distance between the point and the plane of the triangle 938 */ 939 public static double distancePointPlane(double pointX, double pointY, double pointZ, 940 double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z) { 941 double v1Y0Y = v1Y - v0Y; 942 double v2Z0Z = v2Z - v0Z; 943 double v2Y0Y = v2Y - v0Y; 944 double v1Z0Z = v1Z - v0Z; 945 double v2X0X = v2X - v0X; 946 double v1X0X = v1X - v0X; 947 double a = v1Y0Y * v2Z0Z - v2Y0Y * v1Z0Z; 948 double b = v1Z0Z * v2X0X - v2Z0Z * v1X0X; 949 double c = v1X0X * v2Y0Y - v2X0X * v1Y0Y; 950 double d = -(a * v0X + b * v0Y + c * v0Z); 951 return distancePointPlane(pointX, pointY, pointZ, a, b, c, d); 952 } 953 954 /** 955 * Test whether the ray with given origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code> intersects the plane 956 * containing the given point <code>(pointX, pointY, pointZ)</code> and having the normal <code>(normalX, normalY, normalZ)</code>, and return the 957 * value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point. 958 * <p> 959 * This method returns <code>-1.0</code> if the ray does not intersect the plane, because it is either parallel to the plane or its direction points 960 * away from the plane or the ray's origin is on the <i>negative</i> side of the plane (i.e. the plane's normal points away from the ray's origin). 961 * <p> 962 * Reference: <a href="https://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm">https://www.siggraph.org/</a> 963 * 964 * @param originX 965 * the x coordinate of the ray's origin 966 * @param originY 967 * the y coordinate of the ray's origin 968 * @param originZ 969 * the z coordinate of the ray's origin 970 * @param dirX 971 * the x coordinate of the ray's direction 972 * @param dirY 973 * the y coordinate of the ray's direction 974 * @param dirZ 975 * the z coordinate of the ray's direction 976 * @param pointX 977 * the x coordinate of a point on the plane 978 * @param pointY 979 * the y coordinate of a point on the plane 980 * @param pointZ 981 * the z coordinate of a point on the plane 982 * @param normalX 983 * the x coordinate of the plane's normal 984 * @param normalY 985 * the y coordinate of the plane's normal 986 * @param normalZ 987 * the z coordinate of the plane's normal 988 * @param epsilon 989 * some small epsilon for when the ray is parallel to the plane 990 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point, if the ray 991 * intersects the plane; <code>-1.0</code> otherwise 992 */ 993 public static double intersectRayPlane(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 994 double pointX, double pointY, double pointZ, double normalX, double normalY, double normalZ, double epsilon) { 995 double denom = normalX * dirX + normalY * dirY + normalZ * dirZ; 996 if (denom < epsilon) { 997 double t = ((pointX - originX) * normalX + (pointY - originY) * normalY + (pointZ - originZ) * normalZ) / denom; 998 if (t >= 0.0) 999 return t; 1000 } 1001 return -1.0; 1002 } 1003 1004 /** 1005 * Test whether the ray with given <code>origin</code> and direction <code>dir</code> intersects the plane 1006 * containing the given <code>point</code> and having the given <code>normal</code>, and return the 1007 * value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point. 1008 * <p> 1009 * This method returns <code>-1.0</code> if the ray does not intersect the plane, because it is either parallel to the plane or its direction points 1010 * away from the plane or the ray's origin is on the <i>negative</i> side of the plane (i.e. the plane's normal points away from the ray's origin). 1011 * <p> 1012 * Reference: <a href="https://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm">https://www.siggraph.org/</a> 1013 * 1014 * @param origin 1015 * the ray's origin 1016 * @param dir 1017 * the ray's direction 1018 * @param point 1019 * a point on the plane 1020 * @param normal 1021 * the plane's normal 1022 * @param epsilon 1023 * some small epsilon for when the ray is parallel to the plane 1024 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point, if the ray 1025 * intersects the plane; <code>-1.0</code> otherwise 1026 */ 1027 public static double intersectRayPlane(Vector3d origin, Vector3d dir, Vector3d point, Vector3d normal, double epsilon) { 1028 return intersectRayPlane(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, point.x, point.y, point.z, normal.x, normal.y, normal.z, epsilon); 1029 } 1030 1031 /** 1032 * Test whether the ray with given origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code> intersects the plane 1033 * given as the general plane equation <i>a*x + b*y + c*z + d = 0</i>, and return the 1034 * value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point. 1035 * <p> 1036 * This method returns <code>-1.0</code> if the ray does not intersect the plane, because it is either parallel to the plane or its direction points 1037 * away from the plane or the ray's origin is on the <i>negative</i> side of the plane (i.e. the plane's normal points away from the ray's origin). 1038 * <p> 1039 * Reference: <a href="https://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm">https://www.siggraph.org/</a> 1040 * 1041 * @param originX 1042 * the x coordinate of the ray's origin 1043 * @param originY 1044 * the y coordinate of the ray's origin 1045 * @param originZ 1046 * the z coordinate of the ray's origin 1047 * @param dirX 1048 * the x coordinate of the ray's direction 1049 * @param dirY 1050 * the y coordinate of the ray's direction 1051 * @param dirZ 1052 * the z coordinate of the ray's direction 1053 * @param a 1054 * the x factor in the plane equation 1055 * @param b 1056 * the y factor in the plane equation 1057 * @param c 1058 * the z factor in the plane equation 1059 * @param d 1060 * the constant in the plane equation 1061 * @param epsilon 1062 * some small epsilon for when the ray is parallel to the plane 1063 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point, if the ray 1064 * intersects the plane; <code>-1.0</code> otherwise 1065 */ 1066 public static double intersectRayPlane(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 1067 double a, double b, double c, double d, double epsilon) { 1068 double denom = a * dirX + b * dirY + c * dirZ; 1069 if (denom < 0.0) { 1070 double t = -(a * originX + b * originY + c * originZ + d) / denom; 1071 if (t >= 0.0) 1072 return t; 1073 } 1074 return -1.0; 1075 } 1076 1077 /** 1078 * Test whether the axis-aligned box with minimum corner <code>(minX, minY, minZ)</code> and maximum corner <code>(maxX, maxY, maxZ)</code> 1079 * intersects the sphere with the given center <code>(centerX, centerY, centerZ)</code> and square radius <code>radiusSquared</code>. 1080 * <p> 1081 * Reference: <a href="http://stackoverflow.com/questions/4578967/cube-sphere-intersection-test#answer-4579069">http://stackoverflow.com</a> 1082 * 1083 * @param minX 1084 * the x coordinate of the minimum corner of the axis-aligned box 1085 * @param minY 1086 * the y coordinate of the minimum corner of the axis-aligned box 1087 * @param minZ 1088 * the z coordinate of the minimum corner of the axis-aligned box 1089 * @param maxX 1090 * the x coordinate of the maximum corner of the axis-aligned box 1091 * @param maxY 1092 * the y coordinate of the maximum corner of the axis-aligned box 1093 * @param maxZ 1094 * the z coordinate of the maximum corner of the axis-aligned box 1095 * @param centerX 1096 * the x coordinate of the sphere's center 1097 * @param centerY 1098 * the y coordinate of the sphere's center 1099 * @param centerZ 1100 * the z coordinate of the sphere's center 1101 * @param radiusSquared 1102 * the square of the sphere's radius 1103 * @return <code>true</code> iff the axis-aligned box intersects the sphere; <code>false</code> otherwise 1104 */ 1105 public static bool testAabSphere( 1106 double minX, double minY, double minZ, 1107 double maxX, double maxY, double maxZ, 1108 double centerX, double centerY, double centerZ, double radiusSquared) { 1109 double radius2 = radiusSquared; 1110 if (centerX < minX) { 1111 double d = (centerX - minX); 1112 radius2 -= d * d; 1113 } else if (centerX > maxX) { 1114 double d = (centerX - maxX); 1115 radius2 -= d * d; 1116 } 1117 if (centerY < minY) { 1118 double d = (centerY - minY); 1119 radius2 -= d * d; 1120 } else if (centerY > maxY) { 1121 double d = (centerY - maxY); 1122 radius2 -= d * d; 1123 } 1124 if (centerZ < minZ) { 1125 double d = (centerZ - minZ); 1126 radius2 -= d * d; 1127 } else if (centerZ > maxZ) { 1128 double d = (centerZ - maxZ); 1129 radius2 -= d * d; 1130 } 1131 return radius2 >= 0.0; 1132 } 1133 1134 /** 1135 * Test whether the axis-aligned box with minimum corner <code>min</code> and maximum corner <code>max</code> 1136 * intersects the sphere with the given <code>center</code> and square radius <code>radiusSquared</code>. 1137 * <p> 1138 * Reference: <a href="http://stackoverflow.com/questions/4578967/cube-sphere-intersection-test#answer-4579069">http://stackoverflow.com</a> 1139 * 1140 * @param min 1141 * the minimum corner of the axis-aligned box 1142 * @param max 1143 * the maximum corner of the axis-aligned box 1144 * @param center 1145 * the sphere's center 1146 * @param radiusSquared 1147 * the squared of the sphere's radius 1148 * @return <code>true</code> iff the axis-aligned box intersects the sphere; <code>false</code> otherwise 1149 */ 1150 public static bool testAabSphere(Vector3d min, Vector3d max, Vector3d center, double radiusSquared) { 1151 return testAabSphere(min.x, min.y, min.z, max.x, max.y, max.z, center.x, center.y, center.z, radiusSquared); 1152 } 1153 1154 /** 1155 * Find the point on the given plane which is closest to the specified point <code>(pX, pY, pZ)</code> and store the result in <code>result</code>. 1156 * 1157 * @param aX 1158 * the x coordinate of one point on the plane 1159 * @param aY 1160 * the y coordinate of one point on the plane 1161 * @param aZ 1162 * the z coordinate of one point on the plane 1163 * @param nX 1164 * the x coordinate of the unit normal of the plane 1165 * @param nY 1166 * the y coordinate of the unit normal of the plane 1167 * @param nZ 1168 * the z coordinate of the unit normal of the plane 1169 * @param pX 1170 * the x coordinate of the point 1171 * @param pY 1172 * the y coordinate of the point 1173 * @param pZ 1174 * the z coordinate of the point 1175 * @param result 1176 * will hold the result 1177 * @return result 1178 */ 1179 public static Vector3d findClosestPointOnPlane(double aX, double aY, double aZ, double nX, double nY, double nZ, double pX, double pY, double pZ, ref Vector3d result) { 1180 double d = -(nX * aX + nY * aY + nZ * aZ); 1181 double t = nX * pX + nY * pY + nZ * pZ - d; 1182 result.x = pX - t * nX; 1183 result.y = pY - t * nY; 1184 result.z = pZ - t * nZ; 1185 return result; 1186 } 1187 1188 /** 1189 * Find the point on the given line segment which is closest to the specified point <code>(pX, pY, pZ)</code>, and store the result in <code>result</code>. 1190 * 1191 * @param aX 1192 * the x coordinate of the first end point of the line segment 1193 * @param aY 1194 * the y coordinate of the first end point of the line segment 1195 * @param aZ 1196 * the z coordinate of the first end point of the line segment 1197 * @param bX 1198 * the x coordinate of the second end point of the line segment 1199 * @param bY 1200 * the y coordinate of the second end point of the line segment 1201 * @param bZ 1202 * the z coordinate of the second end point of the line segment 1203 * @param pX 1204 * the x coordinate of the point 1205 * @param pY 1206 * the y coordinate of the point 1207 * @param pZ 1208 * the z coordinate of the point 1209 * @param result 1210 * will hold the result 1211 * @return result 1212 */ 1213 public static Vector3d findClosestPointOnLineSegment(double aX, double aY, double aZ, double bX, double bY, double bZ, double pX, double pY, double pZ, ref Vector3d result) { 1214 double abX = bX - aX, abY = bY - aY, abZ = bZ - aZ; 1215 double t = ((pX - aX) * abX + (pY - aY) * abY + (pZ - aZ) * abZ) / (abX * abX + abY * abY + abZ * abZ); 1216 if (t < 0.0) t = 0.0; 1217 if (t > 1.0) t = 1.0; 1218 result.x = aX + t * abX; 1219 result.y = aY + t * abY; 1220 result.z = aZ + t * abZ; 1221 return result; 1222 } 1223 1224 /** 1225 * Find the closest points on the two line segments, store the point on the first line segment in <code>resultA</code> and 1226 * the point on the second line segment in <code>resultB</code>, and return the square distance between both points. 1227 * <p> 1228 * Reference: Book "Real-Time Collision Detection" chapter 5.1.9 "Closest Points of Two Line Segments" 1229 * 1230 * @param a0X 1231 * the x coordinate of the first line segment's first end point 1232 * @param a0Y 1233 * the y coordinate of the first line segment's first end point 1234 * @param a0Z 1235 * the z coordinate of the first line segment's first end point 1236 * @param a1X 1237 * the x coordinate of the first line segment's second end point 1238 * @param a1Y 1239 * the y coordinate of the first line segment's second end point 1240 * @param a1Z 1241 * the z coordinate of the first line segment's second end point 1242 * @param b0X 1243 * the x coordinate of the second line segment's first end point 1244 * @param b0Y 1245 * the y coordinate of the second line segment's first end point 1246 * @param b0Z 1247 * the z coordinate of the second line segment's first end point 1248 * @param b1X 1249 * the x coordinate of the second line segment's second end point 1250 * @param b1Y 1251 * the y coordinate of the second line segment's second end point 1252 * @param b1Z 1253 * the z coordinate of the second line segment's second end point 1254 * @param resultA 1255 * will hold the point on the first line segment 1256 * @param resultB 1257 * will hold the point on the second line segment 1258 * @return the square distance between the two closest points 1259 */ 1260 public static double findClosestPointsLineSegments( 1261 double a0X, double a0Y, double a0Z, double a1X, double a1Y, double a1Z, 1262 double b0X, double b0Y, double b0Z, double b1X, double b1Y, double b1Z, 1263 Vector3d resultA, Vector3d resultB) { 1264 double d1x = a1X - a0X, d1y = a1Y - a0Y, d1z = a1Z - a0Z; 1265 double d2x = b1X - b0X, d2y = b1Y - b0Y, d2z = b1Z - b0Z; 1266 double rX = a0X - b0X, rY = a0Y - b0Y, rZ = a0Z - b0Z; 1267 double a = d1x * d1x + d1y * d1y + d1z * d1z; 1268 double e = d2x * d2x + d2y * d2y + d2z * d2z; 1269 double f = d2x * rX + d2y * rY + d2z * rZ; 1270 double EPSILON = 1E-8; 1271 double s, t; 1272 if (a <= EPSILON && e <= EPSILON) { 1273 // Both segments degenerate into points 1274 resultA.set(a0X, a0Y, a0Z); 1275 resultB.set(b0X, b0Y, b0Z); 1276 return resultA.dot(resultB); 1277 } 1278 if (a <= EPSILON) { 1279 // First segment degenerates into a point 1280 s = 0.0; 1281 t = f / e; 1282 t = Math.min(Math.max(t, 0.0), 1.0); 1283 } else { 1284 double c = d1x * rX + d1y * rY + d1z * rZ; 1285 if (e <= EPSILON) { 1286 // Second segment degenerates into a point 1287 t = 0.0; 1288 s = Math.min(Math.max(-c / a, 0.0), 1.0); 1289 } else { 1290 // The general nondegenerate case starts here 1291 double b = d1x * d2x + d1y * d2y + d1z * d2z; 1292 double denom = a * e - b * b; 1293 // If segments not parallel, compute closest point on L1 to L2 and 1294 // clamp to segment S1. Else pick arbitrary s (here 0) 1295 if (denom != 0.0) 1296 s = Math.min(Math.max((b*f - c*e) / denom, 0.0), 1.0); 1297 else 1298 s = 0.0; 1299 // Compute point on L2 closest to S1(s) using 1300 // t = Dot((P1 + D1*s) - P2,D2) / Dot(D2,D2) = (b*s + f) / e 1301 t = (b * s + f) / e; 1302 // If t in [0,1] done. Else clamp t, recompute s for the new value 1303 // of t using s = Dot((P2 + D2*t) - P1,D1) / Dot(D1,D1)= (t*b - c) / a 1304 // and clamp s to [0, 1] 1305 if (t < 0.0) { 1306 t = 0.0; 1307 s = Math.min(Math.max(-c / a, 0.0), 1.0); 1308 } else if (t > 1.0) { 1309 t = 1.0; 1310 s = Math.min(Math.max((b - c) / a, 0.0), 1.0); 1311 } 1312 } 1313 } 1314 resultA.set(a0X + d1x * s, a0Y + d1y * s, a0Z + d1z * s); 1315 resultB.set(b0X + d2x * t, b0Y + d2y * t, b0Z + d2z * t); 1316 double dX = resultA.x - resultB.x, dY = resultA.y - resultB.y, dZ = resultA.z - resultB.z; 1317 return dX*dX + dY*dY + dZ*dZ; 1318 } 1319 1320 /** 1321 * Find the closest points on a line segment and a triangle. 1322 * <p> 1323 * Reference: Book "Real-Time Collision Detection" chapter 5.1.10 "Closest Points of a Line Segment and a Triangle" 1324 * 1325 * @param aX 1326 * the x coordinate of the line segment's first end point 1327 * @param aY 1328 * the y coordinate of the line segment's first end point 1329 * @param aZ 1330 * the z coordinate of the line segment's first end point 1331 * @param bX 1332 * the x coordinate of the line segment's second end point 1333 * @param bY 1334 * the y coordinate of the line segment's second end point 1335 * @param bZ 1336 * the z coordinate of the line segment's second end point 1337 * @param v0X 1338 * the x coordinate of the triangle's first vertex 1339 * @param v0Y 1340 * the y coordinate of the triangle's first vertex 1341 * @param v0Z 1342 * the z coordinate of the triangle's first vertex 1343 * @param v1X 1344 * the x coordinate of the triangle's second vertex 1345 * @param v1Y 1346 * the y coordinate of the triangle's second vertex 1347 * @param v1Z 1348 * the z coordinate of the triangle's second vertex 1349 * @param v2X 1350 * the x coordinate of the triangle's third vertex 1351 * @param v2Y 1352 * the y coordinate of the triangle's third vertex 1353 * @param v2Z 1354 * the z coordinate of the triangle's third vertex 1355 * @param lineSegmentResult 1356 * will hold the closest point on the line segment 1357 * @param triangleResult 1358 * will hold the closest point on the triangle 1359 * @return the square distance of the closest points 1360 */ 1361 public static double findClosestPointsLineSegmentTriangle( 1362 double aX, double aY, double aZ, double bX, double bY, double bZ, 1363 double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z, 1364 Vector3d lineSegmentResult, Vector3d triangleResult) { 1365 double min, d; 1366 double minlsX, minlsY, minlsZ, mintX, mintY, mintZ; 1367 // AB -> V0V1 1368 d = findClosestPointsLineSegments(aX, aY, aZ, bX, bY, bZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, lineSegmentResult, triangleResult); 1369 min = d; 1370 minlsX = lineSegmentResult.x; minlsY = lineSegmentResult.y; minlsZ = lineSegmentResult.z; 1371 mintX = triangleResult.x; mintY = triangleResult.y; mintZ = triangleResult.z; 1372 // AB -> V1V2 1373 d = findClosestPointsLineSegments(aX, aY, aZ, bX, bY, bZ, v1X, v1Y, v1Z, v2X, v2Y, v2Z, lineSegmentResult, triangleResult); 1374 if (d < min) { 1375 min = d; 1376 minlsX = lineSegmentResult.x; minlsY = lineSegmentResult.y; minlsZ = lineSegmentResult.z; 1377 mintX = triangleResult.x; mintY = triangleResult.y; mintZ = triangleResult.z; 1378 } 1379 // AB -> V2V0 1380 d = findClosestPointsLineSegments(aX, aY, aZ, bX, bY, bZ, v2X, v2Y, v2Z, v0X, v0Y, v0Z, lineSegmentResult, triangleResult); 1381 if (d < min) { 1382 min = d; 1383 minlsX = lineSegmentResult.x; minlsY = lineSegmentResult.y; minlsZ = lineSegmentResult.z; 1384 mintX = triangleResult.x; mintY = triangleResult.y; mintZ = triangleResult.z; 1385 } 1386 // segment endpoint A and plane of triangle (when A projects inside V0V1V2) 1387 bool computed = false; 1388 double a = double.nan, b = double.nan, c = double.nan, nd = double.nan; 1389 if (testPointInTriangle(aX, aY, aZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z)) { 1390 double v1Y0Y = v1Y - v0Y; 1391 double v2Z0Z = v2Z - v0Z; 1392 double v2Y0Y = v2Y - v0Y; 1393 double v1Z0Z = v1Z - v0Z; 1394 double v2X0X = v2X - v0X; 1395 double v1X0X = v1X - v0X; 1396 a = v1Y0Y * v2Z0Z - v2Y0Y * v1Z0Z; 1397 b = v1Z0Z * v2X0X - v2Z0Z * v1X0X; 1398 c = v1X0X * v2Y0Y - v2X0X * v1Y0Y; 1399 computed = true; 1400 double invLen = Math.invsqrt(a*a + b*b + c*c); 1401 a *= invLen; b *= invLen; c *= invLen; 1402 nd = -(a * v0X + b * v0Y + c * v0Z); 1403 d = (a * aX + b * aY + c * aZ + nd); 1404 double l = d; 1405 d *= d; 1406 if (d < min) { 1407 min = d; 1408 minlsX = aX; minlsY = aY; minlsZ = aZ; 1409 mintX = aX - a*l; mintY = aY - b*l; mintZ = aZ - c*l; 1410 } 1411 } 1412 // segment endpoint B and plane of triangle (when B projects inside V0V1V2) 1413 if (testPointInTriangle(bX, bY, bZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z)) { 1414 if (!computed) { 1415 double v1Y0Y = v1Y - v0Y; 1416 double v2Z0Z = v2Z - v0Z; 1417 double v2Y0Y = v2Y - v0Y; 1418 double v1Z0Z = v1Z - v0Z; 1419 double v2X0X = v2X - v0X; 1420 double v1X0X = v1X - v0X; 1421 a = v1Y0Y * v2Z0Z - v2Y0Y * v1Z0Z; 1422 b = v1Z0Z * v2X0X - v2Z0Z * v1X0X; 1423 c = v1X0X * v2Y0Y - v2X0X * v1Y0Y; 1424 double invLen = Math.invsqrt(a*a + b*b + c*c); 1425 a *= invLen; b *= invLen; c *= invLen; 1426 nd = -(a * v0X + b * v0Y + c * v0Z); 1427 } 1428 d = (a * bX + b * bY + c * bZ + nd); 1429 double l = d; 1430 d *= d; 1431 if (d < min) { 1432 min = d; 1433 minlsX = bX; minlsY = bY; minlsZ = bZ; 1434 mintX = bX - a*l; mintY = bY - b*l; mintZ = bZ - c*l; 1435 } 1436 } 1437 lineSegmentResult.set(minlsX, minlsY, minlsZ); 1438 triangleResult.set(mintX, mintY, mintZ); 1439 return min; 1440 } 1441 1442 /** 1443 * Determine the closest point on the triangle with the given vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code>, <code>(v2X, v2Y, v2Z)</code> 1444 * between that triangle and the given point <code>(pX, pY, pZ)</code> and store that point into the given <code>result</code>. 1445 * <p> 1446 * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2}) 1447 * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20}) 1448 * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle. 1449 * <p> 1450 * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point" 1451 * 1452 * @param v0X 1453 * the x coordinate of the first vertex of the triangle 1454 * @param v0Y 1455 * the y coordinate of the first vertex of the triangle 1456 * @param v0Z 1457 * the z coordinate of the first vertex of the triangle 1458 * @param v1X 1459 * the x coordinate of the second vertex of the triangle 1460 * @param v1Y 1461 * the y coordinate of the second vertex of the triangle 1462 * @param v1Z 1463 * the z coordinate of the second vertex of the triangle 1464 * @param v2X 1465 * the x coordinate of the third vertex of the triangle 1466 * @param v2Y 1467 * the y coordinate of the third vertex of the triangle 1468 * @param v2Z 1469 * the z coordinate of the third vertex of the triangle 1470 * @param pX 1471 * the x coordinate of the point 1472 * @param pY 1473 * the y coordinate of the point 1474 * @param pZ 1475 * the y coordinate of the point 1476 * @param result 1477 * will hold the closest point 1478 * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2}, 1479 * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or 1480 * {@link #POINT_ON_TRIANGLE_FACE} 1481 */ 1482 public static int findClosestPointOnTriangle( 1483 double v0X, double v0Y, double v0Z, 1484 double v1X, double v1Y, double v1Z, 1485 double v2X, double v2Y, double v2Z, 1486 double pX, double pY, double pZ, 1487 Vector3d result) { 1488 double abX = v1X - v0X, abY = v1Y - v0Y, abZ = v1Z - v0Z; 1489 double acX = v2X - v0X, acY = v2Y - v0Y, acZ = v2Z - v0Z; 1490 double apX = pX - v0X, apY = pY - v0Y, apZ = pZ - v0Z; 1491 double d1 = abX * apX + abY * apY + abZ * apZ; 1492 double d2 = acX * apX + acY * apY + acZ * apZ; 1493 if (d1 <= 0.0 && d2 <= 0.0) { 1494 result.x = v0X; 1495 result.y = v0Y; 1496 result.z = v0Z; 1497 return POINT_ON_TRIANGLE_VERTEX_0; 1498 } 1499 double bpX = pX - v1X, bpY = pY - v1Y, bpZ = pZ - v1Z; 1500 double d3 = abX * bpX + abY * bpY + abZ * bpZ; 1501 double d4 = acX * bpX + acY * bpY + acZ * bpZ; 1502 if (d3 >= 0.0 && d4 <= d3) { 1503 result.x = v1X; 1504 result.y = v1Y; 1505 result.z = v1Z; 1506 return POINT_ON_TRIANGLE_VERTEX_1; 1507 } 1508 double vc = d1 * d4 - d3 * d2; 1509 if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) { 1510 double v = d1 / (d1 - d3); 1511 result.x = v0X + v * abX; 1512 result.y = v0Y + v * abY; 1513 result.z = v0Z + v * abZ; 1514 return POINT_ON_TRIANGLE_EDGE_01; 1515 } 1516 double cpX = pX - v2X, cpY = pY - v2Y, cpZ = pZ - v2Z; 1517 double d5 = abX * cpX + abY * cpY + abZ * cpZ; 1518 double d6 = acX * cpX + acY * cpY + acZ * cpZ; 1519 if (d6 >= 0.0 && d5 <= d6) { 1520 result.x = v2X; 1521 result.y = v2Y; 1522 result.z = v2Z; 1523 return POINT_ON_TRIANGLE_VERTEX_2; 1524 } 1525 double vb = d5 * d2 - d1 * d6; 1526 if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) { 1527 double w = d2 / (d2 - d6); 1528 result.x = v0X + w * acX; 1529 result.y = v0Y + w * acY; 1530 result.z = v0Z + w * acZ; 1531 return POINT_ON_TRIANGLE_EDGE_20; 1532 } 1533 double va = d3 * d6 - d5 * d4; 1534 if (va <= 0.0 && d4 - d3 >= 0.0 && d5 - d6 >= 0.0) { 1535 double w = (d4 - d3) / (d4 - d3 + d5 - d6); 1536 result.x = v1X + w * (v2X - v1X); 1537 result.y = v1Y + w * (v2Y - v1Y); 1538 result.z = v1Z + w * (v2Z - v1Z); 1539 return POINT_ON_TRIANGLE_EDGE_12; 1540 } 1541 double denom = 1.0 / (va + vb + vc); 1542 double v = vb * denom; 1543 double w = vc * denom; 1544 result.x = v0X + abX * v + acX * w; 1545 result.y = v0Y + abY * v + acY * w; 1546 result.z = v0Z + abZ * v + acZ * w; 1547 return POINT_ON_TRIANGLE_FACE; 1548 } 1549 1550 /** 1551 * Determine the closest point on the triangle with the vertices <code>v0</code>, <code>v1</code>, <code>v2</code> 1552 * between that triangle and the given point <code>p</code> and store that point into the given <code>result</code>. 1553 * <p> 1554 * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2}) 1555 * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20}) 1556 * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle. 1557 * <p> 1558 * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point" 1559 * 1560 * @param v0 1561 * the first vertex of the triangle 1562 * @param v1 1563 * the second vertex of the triangle 1564 * @param v2 1565 * the third vertex of the triangle 1566 * @param p 1567 * the point 1568 * @param result 1569 * will hold the closest point 1570 * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2}, 1571 * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or 1572 * {@link #POINT_ON_TRIANGLE_FACE} 1573 */ 1574 public static int findClosestPointOnTriangle(Vector3d v0, Vector3d v1, Vector3d v2, Vector3d p, Vector3d result) { 1575 return findClosestPointOnTriangle(v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, p.x, p.y, p.z, result); 1576 } 1577 1578 /** 1579 * Find the point on a given rectangle, specified via three of its corners, which is closest to the specified point 1580 * <code>(pX, pY, pZ)</code> and store the result into <code>res</code>. 1581 * <p> 1582 * Reference: Book "Real-Time Collision Detection" chapter 5.1.4.2 "Closest Point on 3D Rectangle to Point" 1583 * 1584 * @param aX 1585 * the x coordinate of the first corner point of the rectangle 1586 * @param aY 1587 * the y coordinate of the first corner point of the rectangle 1588 * @param aZ 1589 * the z coordinate of the first corner point of the rectangle 1590 * @param bX 1591 * the x coordinate of the second corner point of the rectangle 1592 * @param bY 1593 * the y coordinate of the second corner point of the rectangle 1594 * @param bZ 1595 * the z coordinate of the second corner point of the rectangle 1596 * @param cX 1597 * the x coordinate of the third corner point of the rectangle 1598 * @param cY 1599 * the y coordinate of the third corner point of the rectangle 1600 * @param cZ 1601 * the z coordinate of the third corner point of the rectangle 1602 * @param pX 1603 * the x coordinate of the point 1604 * @param pY 1605 * the y coordinate of the point 1606 * @param pZ 1607 * the z coordinate of the point 1608 * @param res 1609 * will hold the result 1610 * @return res 1611 */ 1612 public static Vector3d findClosestPointOnRectangle( 1613 double aX, double aY, double aZ, 1614 double bX, double bY, double bZ, 1615 double cX, double cY, double cZ, 1616 double pX, double pY, double pZ, ref Vector3d res) { 1617 double abX = bX - aX, abY = bY - aY, abZ = bZ - aZ; 1618 double acX = cX - aX, acY = cY - aY, acZ = cZ - aZ; 1619 double dX = pX - aX, dY = pY - aY, dZ = pZ - aZ; 1620 double qX = aX, qY = aY, qZ = aZ; 1621 double dist = dX * abX + dY * abY + dZ * abZ; 1622 double maxdist = abX * abX + abY * abY + abZ * abZ; 1623 if (dist >= maxdist) { 1624 qX += abX; 1625 qY += abY; 1626 qZ += abZ; 1627 } else if (dist > 0.0) { 1628 qX += (dist / maxdist) * abX; 1629 qY += (dist / maxdist) * abY; 1630 qZ += (dist / maxdist) * abZ; 1631 } 1632 dist = dX * acX + dY * acY + dZ * acZ; 1633 maxdist = acX * acX + acY * acY + acZ * acZ; 1634 if (dist >= maxdist) { 1635 qX += acX; 1636 qY += acY; 1637 qZ += acZ; 1638 } else if (dist > 0.0) { 1639 qX += (dist / maxdist) * acX; 1640 qY += (dist / maxdist) * acY; 1641 qZ += (dist / maxdist) * acZ; 1642 } 1643 res.x = qX; 1644 res.y = qY; 1645 res.z = qZ; 1646 return res; 1647 } 1648 1649 /** 1650 * Determine the point of intersection between a sphere with the given center <code>(centerX, centerY, centerZ)</code> and <code>radius</code> moving 1651 * with the given velocity <code>(velX, velY, velZ)</code> and the triangle specified via its three vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code>, <code>(v2X, v2Y, v2Z)</code>. 1652 * <p> 1653 * The vertices of the triangle must be specified in counter-clockwise winding order. 1654 * <p> 1655 * An intersection is only considered if the time of intersection is smaller than the given <code>maxT</code> value. 1656 * <p> 1657 * Reference: <a href="http://www.peroxide.dk/papers/collision/collision.pdf">Improved Collision detection and Response</a> 1658 * 1659 * @param centerX 1660 * the x coordinate of the sphere's center 1661 * @param centerY 1662 * the y coordinate of the sphere's center 1663 * @param centerZ 1664 * the z coordinate of the sphere's center 1665 * @param radius 1666 * the radius of the sphere 1667 * @param velX 1668 * the x component of the velocity of the sphere 1669 * @param velY 1670 * the y component of the velocity of the sphere 1671 * @param velZ 1672 * the z component of the velocity of the sphere 1673 * @param v0X 1674 * the x coordinate of the first triangle vertex 1675 * @param v0Y 1676 * the y coordinate of the first triangle vertex 1677 * @param v0Z 1678 * the z coordinate of the first triangle vertex 1679 * @param v1X 1680 * the x coordinate of the second triangle vertex 1681 * @param v1Y 1682 * the y coordinate of the second triangle vertex 1683 * @param v1Z 1684 * the z coordinate of the second triangle vertex 1685 * @param v2X 1686 * the x coordinate of the third triangle vertex 1687 * @param v2Y 1688 * the y coordinate of the third triangle vertex 1689 * @param v2Z 1690 * the z coordinate of the third triangle vertex 1691 * @param epsilon 1692 * a small epsilon when testing spheres that move almost parallel to the triangle 1693 * @param maxT 1694 * the maximum intersection time 1695 * @param pointAndTime 1696 * iff the moving sphere and the triangle intersect, this will hold the point of intersection in the <code>(x, y, z)</code> components 1697 * and the time of intersection in the <code>w</code> component 1698 * @return {@link #POINT_ON_TRIANGLE_FACE} if the intersection point lies on the triangle's face, 1699 * or {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1} or {@link #POINT_ON_TRIANGLE_VERTEX_2} if the intersection point is a vertex, 1700 * or {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12} or {@link #POINT_ON_TRIANGLE_EDGE_20} if the intersection point lies on an edge; 1701 * or <code>0</code> if no intersection 1702 */ 1703 public static int intersectSweptSphereTriangle( 1704 double centerX, double centerY, double centerZ, double radius, double velX, double velY, double velZ, 1705 double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z, 1706 double epsilon, double maxT, Vector4d pointAndTime) { 1707 double v10X = v1X - v0X; 1708 double v10Y = v1Y - v0Y; 1709 double v10Z = v1Z - v0Z; 1710 double v20X = v2X - v0X; 1711 double v20Y = v2Y - v0Y; 1712 double v20Z = v2Z - v0Z; 1713 // build triangle plane 1714 double a = v10Y * v20Z - v20Y * v10Z; 1715 double b = v10Z * v20X - v20Z * v10X; 1716 double c = v10X * v20Y - v20X * v10Y; 1717 double d = -(a * v0X + b * v0Y + c * v0Z); 1718 double invLen = Math.invsqrt(a * a + b * b + c * c); 1719 double signedDist = (a * centerX + b * centerY + c * centerZ + d) * invLen; 1720 double dot = (a * velX + b * velY + c * velZ) * invLen; 1721 if (dot < epsilon && dot > -epsilon) 1722 return 0; 1723 double pt0 = (radius - signedDist) / dot; 1724 if (pt0 > maxT) 1725 return 0; 1726 double pt1 = (-radius - signedDist) / dot; 1727 double p0X = centerX - radius * a * invLen + velX * pt0; 1728 double p0Y = centerY - radius * b * invLen + velY * pt0; 1729 double p0Z = centerZ - radius * c * invLen + velZ * pt0; 1730 bool insideTriangle = testPointInTriangle(p0X, p0Y, p0Z, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z); 1731 if (insideTriangle) { 1732 pointAndTime.x = p0X; 1733 pointAndTime.y = p0Y; 1734 pointAndTime.z = p0Z; 1735 pointAndTime.w = pt0; 1736 return POINT_ON_TRIANGLE_FACE; 1737 } 1738 int isect = 0; 1739 double t0 = maxT; 1740 double A = velX * velX + velY * velY + velZ * velZ; 1741 double radius2 = radius * radius; 1742 // test against v0 1743 double centerV0X = centerX - v0X; 1744 double centerV0Y = centerY - v0Y; 1745 double centerV0Z = centerZ - v0Z; 1746 double B0 = 2.0 * (velX * centerV0X + velY * centerV0Y + velZ * centerV0Z); 1747 double C0 = centerV0X * centerV0X + centerV0Y * centerV0Y + centerV0Z * centerV0Z - radius2; 1748 double root0 = computeLowestRoot(A, B0, C0, t0); 1749 if (root0 < t0) { 1750 pointAndTime.x = v0X; 1751 pointAndTime.y = v0Y; 1752 pointAndTime.z = v0Z; 1753 pointAndTime.w = root0; 1754 t0 = root0; 1755 isect = POINT_ON_TRIANGLE_VERTEX_0; 1756 } 1757 // test against v1 1758 double centerV1X = centerX - v1X; 1759 double centerV1Y = centerY - v1Y; 1760 double centerV1Z = centerZ - v1Z; 1761 double centerV1Len = centerV1X * centerV1X + centerV1Y * centerV1Y + centerV1Z * centerV1Z; 1762 double B1 = 2.0 * (velX * centerV1X + velY * centerV1Y + velZ * centerV1Z); 1763 double C1 = centerV1Len - radius2; 1764 double root1 = computeLowestRoot(A, B1, C1, t0); 1765 if (root1 < t0) { 1766 pointAndTime.x = v1X; 1767 pointAndTime.y = v1Y; 1768 pointAndTime.z = v1Z; 1769 pointAndTime.w = root1; 1770 t0 = root1; 1771 isect = POINT_ON_TRIANGLE_VERTEX_1; 1772 } 1773 // test against v2 1774 double centerV2X = centerX - v2X; 1775 double centerV2Y = centerY - v2Y; 1776 double centerV2Z = centerZ - v2Z; 1777 double B2 = 2.0 * (velX * centerV2X + velY * centerV2Y + velZ * centerV2Z); 1778 double C2 = centerV2X * centerV2X + centerV2Y * centerV2Y + centerV2Z * centerV2Z - radius2; 1779 double root2 = computeLowestRoot(A, B2, C2, t0); 1780 if (root2 < t0) { 1781 pointAndTime.x = v2X; 1782 pointAndTime.y = v2Y; 1783 pointAndTime.z = v2Z; 1784 pointAndTime.w = root2; 1785 t0 = root2; 1786 isect = POINT_ON_TRIANGLE_VERTEX_2; 1787 } 1788 double velLen = velX * velX + velY * velY + velZ * velZ; 1789 // test against edge10 1790 double len10 = v10X * v10X + v10Y * v10Y + v10Z * v10Z; 1791 double baseTo0Len = centerV0X * centerV0X + centerV0Y * centerV0Y + centerV0Z * centerV0Z; 1792 double v10Vel = (v10X * velX + v10Y * velY + v10Z * velZ); 1793 double A10 = len10 * -velLen + v10Vel * v10Vel; 1794 double v10BaseTo0 = v10X * -centerV0X + v10Y * -centerV0Y + v10Z * -centerV0Z; 1795 double velBaseTo0 = velX * -centerV0X + velY * -centerV0Y + velZ * -centerV0Z; 1796 double B10 = len10 * 2 * velBaseTo0 - 2 * v10Vel * v10BaseTo0; 1797 double C10 = len10 * (radius2 - baseTo0Len) + v10BaseTo0 * v10BaseTo0; 1798 double root10 = computeLowestRoot(A10, B10, C10, t0); 1799 double f10 = (v10Vel * root10 - v10BaseTo0) / len10; 1800 if (f10 >= 0.0 && f10 <= 1.0 && root10 < t0) { 1801 pointAndTime.x = v0X + f10 * v10X; 1802 pointAndTime.y = v0Y + f10 * v10Y; 1803 pointAndTime.z = v0Z + f10 * v10Z; 1804 pointAndTime.w = root10; 1805 t0 = root10; 1806 isect = POINT_ON_TRIANGLE_EDGE_01; 1807 } 1808 // test against edge20 1809 double len20 = v20X * v20X + v20Y * v20Y + v20Z * v20Z; 1810 double v20Vel = (v20X * velX + v20Y * velY + v20Z * velZ); 1811 double A20 = len20 * -velLen + v20Vel * v20Vel; 1812 double v20BaseTo0 = v20X * -centerV0X + v20Y * -centerV0Y + v20Z * -centerV0Z; 1813 double B20 = len20 * 2 * velBaseTo0 - 2 * v20Vel * v20BaseTo0; 1814 double C20 = len20 * (radius2 - baseTo0Len) + v20BaseTo0 * v20BaseTo0; 1815 double root20 = computeLowestRoot(A20, B20, C20, t0); 1816 double f20 = (v20Vel * root20 - v20BaseTo0) / len20; 1817 if (f20 >= 0.0 && f20 <= 1.0 && root20 < pt1) { 1818 pointAndTime.x = v0X + f20 * v20X; 1819 pointAndTime.y = v0Y + f20 * v20Y; 1820 pointAndTime.z = v0Z + f20 * v20Z; 1821 pointAndTime.w = root20; 1822 t0 = root20; 1823 isect = POINT_ON_TRIANGLE_EDGE_20; 1824 } 1825 // test against edge21 1826 double v21X = v2X - v1X; 1827 double v21Y = v2Y - v1Y; 1828 double v21Z = v2Z - v1Z; 1829 double len21 = v21X * v21X + v21Y * v21Y + v21Z * v21Z; 1830 double baseTo1Len = centerV1Len; 1831 double v21Vel = (v21X * velX + v21Y * velY + v21Z * velZ); 1832 double A21 = len21 * -velLen + v21Vel * v21Vel; 1833 double v21BaseTo1 = v21X * -centerV1X + v21Y * -centerV1Y + v21Z * -centerV1Z; 1834 double velBaseTo1 = velX * -centerV1X + velY * -centerV1Y + velZ * -centerV1Z; 1835 double B21 = len21 * 2 * velBaseTo1 - 2 * v21Vel * v21BaseTo1; 1836 double C21 = len21 * (radius2 - baseTo1Len) + v21BaseTo1 * v21BaseTo1; 1837 double root21 = computeLowestRoot(A21, B21, C21, t0); 1838 double f21 = (v21Vel * root21 - v21BaseTo1) / len21; 1839 if (f21 >= 0.0 && f21 <= 1.0 && root21 < t0) { 1840 pointAndTime.x = v1X + f21 * v21X; 1841 pointAndTime.y = v1Y + f21 * v21Y; 1842 pointAndTime.z = v1Z + f21 * v21Z; 1843 pointAndTime.w = root21; 1844 t0 = root21; 1845 isect = POINT_ON_TRIANGLE_EDGE_12; 1846 } 1847 return isect; 1848 } 1849 1850 /** 1851 * Compute the lowest root for <code>t</code> in the quadratic equation <code>a*t*t + b*t + c = 0</code>. 1852 * <p> 1853 * This is a helper method for {@link #intersectSweptSphereTriangle} 1854 * 1855 * @param a 1856 * the quadratic factor 1857 * @param b 1858 * the linear factor 1859 * @param c 1860 * the constant 1861 * @param maxR 1862 * the maximum expected root 1863 * @return the lowest of the two roots of the quadratic equation; or {@link Double#POSITIVE_INFINITY} 1864 */ 1865 private static double computeLowestRoot(double a, double b, double c, double maxR) { 1866 double determinant = b * b - 4.0 * a * c; 1867 if (determinant < 0.0) 1868 return double.infinity; 1869 double sqrtD = Math.sqrt(determinant); 1870 double r1 = (-b - sqrtD) / (2.0 * a); 1871 double r2 = (-b + sqrtD) / (2.0 * a); 1872 if (r1 > r2) { 1873 double temp = r2; 1874 r2 = r1; 1875 r1 = temp; 1876 } 1877 if (r1 > 0.0 && r1 < maxR) { 1878 return r1; 1879 } 1880 if (r2 > 0.0 && r2 < maxR) { 1881 return r2; 1882 } 1883 return double.infinity; 1884 } 1885 1886 /** 1887 * Test whether the projection of the given point <code>(pX, pY, pZ)</code> lies inside of the triangle defined by the three vertices 1888 * <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code>. 1889 * <p> 1890 * Reference: <a href="http://www.peroxide.dk/papers/collision/collision.pdf">Improved Collision detection and Response</a> 1891 * 1892 * @param pX 1893 * the x coordinate of the point to test 1894 * @param pY 1895 * the y coordinate of the point to test 1896 * @param pZ 1897 * the z coordinate of the point to test 1898 * @param v0X 1899 * the x coordinate of the first vertex 1900 * @param v0Y 1901 * the y coordinate of the first vertex 1902 * @param v0Z 1903 * the z coordinate of the first vertex 1904 * @param v1X 1905 * the x coordinate of the second vertex 1906 * @param v1Y 1907 * the y coordinate of the second vertex 1908 * @param v1Z 1909 * the z coordinate of the second vertex 1910 * @param v2X 1911 * the x coordinate of the third vertex 1912 * @param v2Y 1913 * the y coordinate of the third vertex 1914 * @param v2Z 1915 * the z coordinate of the third vertex 1916 * @return <code>true</code> if the projection of the given point lies inside of the given triangle; <code>false</code> otherwise 1917 */ 1918 public static bool testPointInTriangle(double pX, double pY, double pZ, double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z) { 1919 double e10X = v1X - v0X; 1920 double e10Y = v1Y - v0Y; 1921 double e10Z = v1Z - v0Z; 1922 double e20X = v2X - v0X; 1923 double e20Y = v2Y - v0Y; 1924 double e20Z = v2Z - v0Z; 1925 double a = e10X * e10X + e10Y * e10Y + e10Z * e10Z; 1926 double b = e10X * e20X + e10Y * e20Y + e10Z * e20Z; 1927 double c = e20X * e20X + e20Y * e20Y + e20Z * e20Z; 1928 double ac_bb = a * c - b * b; 1929 double vpX = pX - v0X; 1930 double vpY = pY - v0Y; 1931 double vpZ = pZ - v0Z; 1932 double d = vpX * e10X + vpY * e10Y + vpZ * e10Z; 1933 double e = vpX * e20X + vpY * e20Y + vpZ * e20Z; 1934 double x = d * c - e * b; 1935 double y = e * a - d * b; 1936 double z = x + y - ac_bb; 1937 return ((Math.doubleToLongBits(z) & ~(Math.doubleToLongBits(x) | Math.doubleToLongBits(y))) & 0x8000000000000000L) != 0L; 1938 } 1939 1940 /** 1941 * Test whether the given ray with the origin <code>(originX, originY, originZ)</code> and normalized direction <code>(dirX, dirY, dirZ)</code> 1942 * intersects the given sphere with center <code>(centerX, centerY, centerZ)</code> and square radius <code>radiusSquared</code>, 1943 * and store the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> for both points (near 1944 * and far) of intersections into the given <code>result</code> vector. 1945 * <p> 1946 * This method returns <code>true</code> for a ray whose origin lies inside the sphere. 1947 * <p> 1948 * Reference: <a href="http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection">http://www.scratchapixel.com/</a> 1949 * 1950 * @param originX 1951 * the x coordinate of the ray's origin 1952 * @param originY 1953 * the y coordinate of the ray's origin 1954 * @param originZ 1955 * the z coordinate of the ray's origin 1956 * @param dirX 1957 * the x coordinate of the ray's normalized direction 1958 * @param dirY 1959 * the y coordinate of the ray's normalized direction 1960 * @param dirZ 1961 * the z coordinate of the ray's normalized direction 1962 * @param centerX 1963 * the x coordinate of the sphere's center 1964 * @param centerY 1965 * the y coordinate of the sphere's center 1966 * @param centerZ 1967 * the z coordinate of the sphere's center 1968 * @param radiusSquared 1969 * the sphere radius squared 1970 * @param result 1971 * a vector that will contain the values of the parameter <i>t</i> in the ray equation 1972 * <i>p(t) = origin + t * dir</i> for both points (near, far) of intersections with the sphere 1973 * @return <code>true</code> if the ray intersects the sphere; <code>false</code> otherwise 1974 */ 1975 public static bool intersectRaySphere(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 1976 double centerX, double centerY, double centerZ, double radiusSquared, Vector2d result) { 1977 double Lx = centerX - originX; 1978 double Ly = centerY - originY; 1979 double Lz = centerZ - originZ; 1980 double tca = Lx * dirX + Ly * dirY + Lz * dirZ; 1981 double d2 = Lx * Lx + Ly * Ly + Lz * Lz - tca * tca; 1982 if (d2 > radiusSquared) 1983 return false; 1984 double thc = Math.sqrt(radiusSquared - d2); 1985 double t0 = tca - thc; 1986 double t1 = tca + thc; 1987 if (t0 < t1 && t1 >= 0.0) { 1988 result.x = t0; 1989 result.y = t1; 1990 return true; 1991 } 1992 return false; 1993 } 1994 1995 /** 1996 * Test whether the ray with the given <code>origin</code> and normalized direction <code>dir</code> 1997 * intersects the sphere with the given <code>center</code> and square radius <code>radiusSquared</code>, 1998 * and store the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> for both points (near 1999 * and far) of intersections into the given <code>result</code> vector. 2000 * <p> 2001 * This method returns <code>true</code> for a ray whose origin lies inside the sphere. 2002 * <p> 2003 * Reference: <a href="http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection">http://www.scratchapixel.com/</a> 2004 * 2005 * @param origin 2006 * the ray's origin 2007 * @param dir 2008 * the ray's normalized direction 2009 * @param center 2010 * the sphere's center 2011 * @param radiusSquared 2012 * the sphere radius squared 2013 * @param result 2014 * a vector that will contain the values of the parameter <i>t</i> in the ray equation 2015 * <i>p(t) = origin + t * dir</i> for both points (near, far) of intersections with the sphere 2016 * @return <code>true</code> if the ray intersects the sphere; <code>false</code> otherwise 2017 */ 2018 public static bool intersectRaySphere(Vector3d origin, Vector3d dir, Vector3d center, double radiusSquared, Vector2d result) { 2019 return intersectRaySphere(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, center.x, center.y, center.z, radiusSquared, result); 2020 } 2021 2022 /** 2023 * Test whether the given ray with the origin <code>(originX, originY, originZ)</code> and normalized direction <code>(dirX, dirY, dirZ)</code> 2024 * intersects the given sphere with center <code>(centerX, centerY, centerZ)</code> and square radius <code>radiusSquared</code>. 2025 * <p> 2026 * This method returns <code>true</code> for a ray whose origin lies inside the sphere. 2027 * <p> 2028 * Reference: <a href="http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection">http://www.scratchapixel.com/</a> 2029 * 2030 * @param originX 2031 * the x coordinate of the ray's origin 2032 * @param originY 2033 * the y coordinate of the ray's origin 2034 * @param originZ 2035 * the z coordinate of the ray's origin 2036 * @param dirX 2037 * the x coordinate of the ray's normalized direction 2038 * @param dirY 2039 * the y coordinate of the ray's normalized direction 2040 * @param dirZ 2041 * the z coordinate of the ray's normalized direction 2042 * @param centerX 2043 * the x coordinate of the sphere's center 2044 * @param centerY 2045 * the y coordinate of the sphere's center 2046 * @param centerZ 2047 * the z coordinate of the sphere's center 2048 * @param radiusSquared 2049 * the sphere radius squared 2050 * @return <code>true</code> if the ray intersects the sphere; <code>false</code> otherwise 2051 */ 2052 public static bool testRaySphere(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 2053 double centerX, double centerY, double centerZ, double radiusSquared) { 2054 double Lx = centerX - originX; 2055 double Ly = centerY - originY; 2056 double Lz = centerZ - originZ; 2057 double tca = Lx * dirX + Ly * dirY + Lz * dirZ; 2058 double d2 = Lx * Lx + Ly * Ly + Lz * Lz - tca * tca; 2059 if (d2 > radiusSquared) 2060 return false; 2061 double thc = Math.sqrt(radiusSquared - d2); 2062 double t0 = tca - thc; 2063 double t1 = tca + thc; 2064 return t0 < t1 && t1 >= 0.0; 2065 } 2066 2067 /** 2068 * Test whether the ray with the given <code>origin</code> and normalized direction <code>dir</code> 2069 * intersects the sphere with the given <code>center</code> and square radius. 2070 * <p> 2071 * This method returns <code>true</code> for a ray whose origin lies inside the sphere. 2072 * <p> 2073 * Reference: <a href="http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection">http://www.scratchapixel.com/</a> 2074 * 2075 * @param origin 2076 * the ray's origin 2077 * @param dir 2078 * the ray's normalized direction 2079 * @param center 2080 * the sphere's center 2081 * @param radiusSquared 2082 * the sphere radius squared 2083 * @return <code>true</code> if the ray intersects the sphere; <code>false</code> otherwise 2084 */ 2085 public static bool testRaySphere(Vector3d origin, Vector3d dir, Vector3d center, double radiusSquared) { 2086 return testRaySphere(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, center.x, center.y, center.z, radiusSquared); 2087 } 2088 2089 /** 2090 * Test whether the line segment with the end points <code>(p0X, p0Y, p0Z)</code> and <code>(p1X, p1Y, p1Z)</code> 2091 * intersects the given sphere with center <code>(centerX, centerY, centerZ)</code> and square radius <code>radiusSquared</code>. 2092 * <p> 2093 * Reference: <a href="http://paulbourke.net/geometry/circlesphere/index.html#linesphere">http://paulbourke.net/</a> 2094 * 2095 * @param p0X 2096 * the x coordinate of the line segment's first end point 2097 * @param p0Y 2098 * the y coordinate of the line segment's first end point 2099 * @param p0Z 2100 * the z coordinate of the line segment's first end point 2101 * @param p1X 2102 * the x coordinate of the line segment's second end point 2103 * @param p1Y 2104 * the y coordinate of the line segment's second end point 2105 * @param p1Z 2106 * the z coordinate of the line segment's second end point 2107 * @param centerX 2108 * the x coordinate of the sphere's center 2109 * @param centerY 2110 * the y coordinate of the sphere's center 2111 * @param centerZ 2112 * the z coordinate of the sphere's center 2113 * @param radiusSquared 2114 * the sphere radius squared 2115 * @return <code>true</code> if the line segment intersects the sphere; <code>false</code> otherwise 2116 */ 2117 public static bool testLineSegmentSphere(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z, 2118 double centerX, double centerY, double centerZ, double radiusSquared) { 2119 double dX = p1X - p0X; 2120 double dY = p1Y - p0Y; 2121 double dZ = p1Z - p0Z; 2122 double nom = (centerX - p0X) * dX + (centerY - p0Y) * dY + (centerZ - p0Z) * dZ; 2123 double den = dX * dX + dY * dY + dZ * dZ; 2124 double u = nom / den; 2125 if (u < 0.0) { 2126 dX = p0X - centerX; 2127 dY = p0Y - centerY; 2128 dZ = p0Z - centerZ; 2129 } else if (u > 1.0) { 2130 dX = p1X - centerX; 2131 dY = p1Y - centerY; 2132 dZ = p1Z - centerZ; 2133 } else { // has to be >= 0 and <= 1 2134 double pX = p0X + u * dX; 2135 double pY = p0Y + u * dY; 2136 double pZ = p0Z + u * dZ; 2137 dX = pX - centerX; 2138 dY = pY - centerY; 2139 dZ = pZ - centerZ; 2140 } 2141 double dist = dX * dX + dY * dY + dZ * dZ; 2142 return dist <= radiusSquared; 2143 } 2144 2145 /** 2146 * Test whether the line segment with the end points <code>p0</code> and <code>p1</code> 2147 * intersects the given sphere with center <code>center</code> and square radius <code>radiusSquared</code>. 2148 * <p> 2149 * Reference: <a href="http://paulbourke.net/geometry/circlesphere/index.html#linesphere">http://paulbourke.net/</a> 2150 * 2151 * @param p0 2152 * the line segment's first end point 2153 * @param p1 2154 * the line segment's second end point 2155 * @param center 2156 * the sphere's center 2157 * @param radiusSquared 2158 * the sphere radius squared 2159 * @return <code>true</code> if the line segment intersects the sphere; <code>false</code> otherwise 2160 */ 2161 public static bool testLineSegmentSphere(Vector3d p0, Vector3d p1, Vector3d center, double radiusSquared) { 2162 return testLineSegmentSphere(p0.x, p0.y, p0.z, p1.x, p1.y, p1.z, center.x, center.y, center.z, radiusSquared); 2163 } 2164 2165 /** 2166 * Test whether the given ray with the origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code> 2167 * intersects the axis-aligned box given as its minimum corner <code>(minX, minY, minZ)</code> and maximum corner <code>(maxX, maxY, maxZ)</code>, 2168 * and return the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the near and far point of intersection. 2169 * <p> 2170 * This method returns <code>true</code> for a ray whose origin lies inside the axis-aligned box. 2171 * <p> 2172 * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient. 2173 * <p> 2174 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 2175 * 2176 * @see #intersectRayAab(Vector3d, Vector3d, Vector3d, Vector3d, Vector2d) 2177 * @see RayAabIntersection 2178 * 2179 * @param originX 2180 * the x coordinate of the ray's origin 2181 * @param originY 2182 * the y coordinate of the ray's origin 2183 * @param originZ 2184 * the z coordinate of the ray's origin 2185 * @param dirX 2186 * the x coordinate of the ray's direction 2187 * @param dirY 2188 * the y coordinate of the ray's direction 2189 * @param dirZ 2190 * the z coordinate of the ray's direction 2191 * @param minX 2192 * the x coordinate of the minimum corner of the axis-aligned box 2193 * @param minY 2194 * the y coordinate of the minimum corner of the axis-aligned box 2195 * @param minZ 2196 * the z coordinate of the minimum corner of the axis-aligned box 2197 * @param maxX 2198 * the x coordinate of the maximum corner of the axis-aligned box 2199 * @param maxY 2200 * the y coordinate of the maximum corner of the axis-aligned box 2201 * @param maxZ 2202 * the y coordinate of the maximum corner of the axis-aligned box 2203 * @param result 2204 * a vector which will hold the resulting values of the parameter 2205 * <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the near and far point of intersection 2206 * iff the ray intersects the axis-aligned box 2207 * @return <code>true</code> if the given ray intersects the axis-aligned box; <code>false</code> otherwise 2208 */ 2209 public static bool intersectRayAab(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 2210 double minX, double minY, double minZ, double maxX, double maxY, double maxZ, ref Vector2d result) { 2211 double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY, invDirZ = 1.0 / dirZ; 2212 double tNear, tFar, tymin, tymax, tzmin, tzmax; 2213 if (invDirX >= 0.0) { 2214 tNear = (minX - originX) * invDirX; 2215 tFar = (maxX - originX) * invDirX; 2216 } else { 2217 tNear = (maxX - originX) * invDirX; 2218 tFar = (minX - originX) * invDirX; 2219 } 2220 if (invDirY >= 0.0) { 2221 tymin = (minY - originY) * invDirY; 2222 tymax = (maxY - originY) * invDirY; 2223 } else { 2224 tymin = (maxY - originY) * invDirY; 2225 tymax = (minY - originY) * invDirY; 2226 } 2227 if (tNear > tymax || tymin > tFar) 2228 return false; 2229 if (invDirZ >= 0.0) { 2230 tzmin = (minZ - originZ) * invDirZ; 2231 tzmax = (maxZ - originZ) * invDirZ; 2232 } else { 2233 tzmin = (maxZ - originZ) * invDirZ; 2234 tzmax = (minZ - originZ) * invDirZ; 2235 } 2236 if (tNear > tzmax || tzmin > tFar) 2237 return false; 2238 tNear = tymin > tNear || isNaN(tNear) ? tymin : tNear; 2239 tFar = tymax < tFar || isNaN(tFar) ? tymax : tFar; 2240 tNear = tzmin > tNear ? tzmin : tNear; 2241 tFar = tzmax < tFar ? tzmax : tFar; 2242 if (tNear < tFar && tFar >= 0.0) { 2243 result.x = tNear; 2244 result.y = tFar; 2245 return true; 2246 } 2247 return false; 2248 } 2249 2250 /** 2251 * Test whether the ray with the given <code>origin</code> and direction <code>dir</code> 2252 * intersects the axis-aligned box specified as its minimum corner <code>min</code> and maximum corner <code>max</code>, 2253 * and return the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the near and far point of intersection.. 2254 * <p> 2255 * This method returns <code>true</code> for a ray whose origin lies inside the axis-aligned box. 2256 * <p> 2257 * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient. 2258 * <p> 2259 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 2260 * 2261 * @see #intersectRayAab(double, double, double, double, double, double, double, double, double, double, double, double, Vector2d) 2262 * @see RayAabIntersection 2263 * 2264 * @param origin 2265 * the ray's origin 2266 * @param dir 2267 * the ray's direction 2268 * @param min 2269 * the minimum corner of the axis-aligned box 2270 * @param max 2271 * the maximum corner of the axis-aligned box 2272 * @param result 2273 * a vector which will hold the resulting values of the parameter 2274 * <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the near and far point of intersection 2275 * iff the ray intersects the axis-aligned box 2276 * @return <code>true</code> if the given ray intersects the axis-aligned box; <code>false</code> otherwise 2277 */ 2278 public static bool intersectRayAab(Vector3d origin, Vector3d dir, Vector3d min, Vector3d max, ref Vector2d result) { 2279 return intersectRayAab(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, min.x, min.y, min.z, max.x, max.y, max.z, result); 2280 } 2281 2282 /** 2283 * Determine whether the undirected line segment with the end points <code>(p0X, p0Y, p0Z)</code> and <code>(p1X, p1Y, p1Z)</code> 2284 * intersects the axis-aligned box given as its minimum corner <code>(minX, minY, minZ)</code> and maximum corner <code>(maxX, maxY, maxZ)</code>, 2285 * and return the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + p0 * (p1 - p0)</i> of the near and far point of intersection. 2286 * <p> 2287 * This method returns <code>true</code> for a line segment whose either end point lies inside the axis-aligned box. 2288 * <p> 2289 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 2290 * 2291 * @see #intersectLineSegmentAab(Vector3d, Vector3d, Vector3d, Vector3d, Vector2d) 2292 * 2293 * @param p0X 2294 * the x coordinate of the line segment's first end point 2295 * @param p0Y 2296 * the y coordinate of the line segment's first end point 2297 * @param p0Z 2298 * the z coordinate of the line segment's first end point 2299 * @param p1X 2300 * the x coordinate of the line segment's second end point 2301 * @param p1Y 2302 * the y coordinate of the line segment's second end point 2303 * @param p1Z 2304 * the z coordinate of the line segment's second end point 2305 * @param minX 2306 * the x coordinate of one corner of the axis-aligned box 2307 * @param minY 2308 * the y coordinate of one corner of the axis-aligned box 2309 * @param minZ 2310 * the z coordinate of one corner of the axis-aligned box 2311 * @param maxX 2312 * the x coordinate of the opposite corner of the axis-aligned box 2313 * @param maxY 2314 * the y coordinate of the opposite corner of the axis-aligned box 2315 * @param maxZ 2316 * the y coordinate of the opposite corner of the axis-aligned box 2317 * @param result 2318 * a vector which will ing values of the parameter 2319 * <i>t</i> in the ray equation <i>p(t) = p0 + t * (p1 - p0)</i> of the near and far point of intersection 2320 * iff the line segment intersects the axis-aligned box 2321 * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned box; or 2322 * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned box; or 2323 * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned box; or 2324 * {@link #TWO_INTERSECTION} if the line segment intersects two sides of the axis-aligned box 2325 * or lies on an edge or a side of the box 2326 */ 2327 public static int intersectLineSegmentAab(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z, 2328 double minX, double minY, double minZ, double maxX, double maxY, double maxZ, Vector2d result) { 2329 double dirX = p1X - p0X, dirY = p1Y - p0Y, dirZ = p1Z - p0Z; 2330 double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY, invDirZ = 1.0 / dirZ; 2331 double tNear, tFar, tymin, tymax, tzmin, tzmax; 2332 if (invDirX >= 0.0) { 2333 tNear = (minX - p0X) * invDirX; 2334 tFar = (maxX - p0X) * invDirX; 2335 } else { 2336 tNear = (maxX - p0X) * invDirX; 2337 tFar = (minX - p0X) * invDirX; 2338 } 2339 if (invDirY >= 0.0) { 2340 tymin = (minY - p0Y) * invDirY; 2341 tymax = (maxY - p0Y) * invDirY; 2342 } else { 2343 tymin = (maxY - p0Y) * invDirY; 2344 tymax = (minY - p0Y) * invDirY; 2345 } 2346 if (tNear > tymax || tymin > tFar) 2347 return OUTSIDE; 2348 if (invDirZ >= 0.0) { 2349 tzmin = (minZ - p0Z) * invDirZ; 2350 tzmax = (maxZ - p0Z) * invDirZ; 2351 } else { 2352 tzmin = (maxZ - p0Z) * invDirZ; 2353 tzmax = (minZ - p0Z) * invDirZ; 2354 } 2355 if (tNear > tzmax || tzmin > tFar) 2356 return OUTSIDE; 2357 tNear = tymin > tNear || isNaN(tNear) ? tymin : tNear; 2358 tFar = tymax < tFar || isNaN(tFar) ? tymax : tFar; 2359 tNear = tzmin > tNear ? tzmin : tNear; 2360 tFar = tzmax < tFar ? tzmax : tFar; 2361 int type = OUTSIDE; 2362 if (tNear <= tFar && tNear <= 1.0f && tFar >= 0.0f) { 2363 if (tNear >= 0.0f && tFar > 1.0f) { 2364 tFar = tNear; 2365 type = ONE_INTERSECTION; 2366 } else if (tNear < 0.0f && tFar <= 1.0f) { 2367 tNear = tFar; 2368 type = ONE_INTERSECTION; 2369 } else if (tNear < 0.0f && tFar > 1.0f) { 2370 type = INSIDE; 2371 } else { 2372 type = TWO_INTERSECTION; 2373 } 2374 result.x = tNear; 2375 result.y = tFar; 2376 } 2377 return type; 2378 } 2379 2380 /** 2381 * Determine whether the undirected line segment with the end points <code>p0</code> and <code>p1</code> 2382 * intersects the axis-aligned box given as its minimum corner <code>min</code> and maximum corner <code>max</code>, 2383 * and return the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + p0 * (p1 - p0)</i> of the near and far point of intersection. 2384 * <p> 2385 * This method returns <code>true</code> for a line segment whose either end point lies inside the axis-aligned box. 2386 * <p> 2387 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 2388 * 2389 * @see #intersectLineSegmentAab(Vector3d, Vector3d, Vector3d, Vector3d, Vector2d) 2390 * 2391 * @param p0 2392 * the line segment's first end point 2393 * @param p1 2394 * the line segment's second end point 2395 * @param min 2396 * the minimum corner of the axis-aligned box 2397 * @param max 2398 * the maximum corner of the axis-aligned box 2399 * @param result 2400 * a vector which will hold the resulting values of the parameter 2401 * <i>t</i> in the ray equation <i>p(t) = p0 + t * (p1 - p0)</i> of the near and far point of intersection 2402 * iff the line segment intersects the axis-aligned box 2403 * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned box; or 2404 * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned box; or 2405 * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned box; or 2406 * {@link #TWO_INTERSECTION} if the line segment intersects two sides of the axis-aligned box 2407 * or lies on an edge or a side of the box 2408 */ 2409 public static int intersectLineSegmentAab(Vector3d p0, Vector3d p1, Vector3d min, Vector3d max, ref Vector2d result) { 2410 return intersectLineSegmentAab(p0.x, p0.y, p0.z, p1.x, p1.y, p1.z, min.x, min.y, min.z, max.x, max.y, max.z, result); 2411 } 2412 2413 /** 2414 * Test whether the given ray with the origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code> 2415 * intersects the axis-aligned box given as its minimum corner <code>(minX, minY, minZ)</code> and maximum corner <code>(maxX, maxY, maxZ)</code>. 2416 * <p> 2417 * This method returns <code>true</code> for a ray whose origin lies inside the axis-aligned box. 2418 * <p> 2419 * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient. 2420 * <p> 2421 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 2422 * 2423 * @see #testRayAab(Vector3d, Vector3d, Vector3d, Vector3d) 2424 * @see RayAabIntersection 2425 * 2426 * @param originX 2427 * the x coordinate of the ray's origin 2428 * @param originY 2429 * the y coordinate of the ray's origin 2430 * @param originZ 2431 * the z coordinate of the ray's origin 2432 * @param dirX 2433 * the x coordinate of the ray's direction 2434 * @param dirY 2435 * the y coordinate of the ray's direction 2436 * @param dirZ 2437 * the z coordinate of the ray's direction 2438 * @param minX 2439 * the x coordinate of the minimum corner of the axis-aligned box 2440 * @param minY 2441 * the y coordinate of the minimum corner of the axis-aligned box 2442 * @param minZ 2443 * the z coordinate of the minimum corner of the axis-aligned box 2444 * @param maxX 2445 * the x coordinate of the maximum corner of the axis-aligned box 2446 * @param maxY 2447 * the y coordinate of the maximum corner of the axis-aligned box 2448 * @param maxZ 2449 * the y coordinate of the maximum corner of the axis-aligned box 2450 * @return <code>true</code> if the given ray intersects the axis-aligned box; <code>false</code> otherwise 2451 */ 2452 public static bool testRayAab(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 2453 double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { 2454 double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY, invDirZ = 1.0 / dirZ; 2455 double tNear, tFar, tymin, tymax, tzmin, tzmax; 2456 if (invDirX >= 0.0) { 2457 tNear = (minX - originX) * invDirX; 2458 tFar = (maxX - originX) * invDirX; 2459 } else { 2460 tNear = (maxX - originX) * invDirX; 2461 tFar = (minX - originX) * invDirX; 2462 } 2463 if (invDirY >= 0.0) { 2464 tymin = (minY - originY) * invDirY; 2465 tymax = (maxY - originY) * invDirY; 2466 } else { 2467 tymin = (maxY - originY) * invDirY; 2468 tymax = (minY - originY) * invDirY; 2469 } 2470 if (tNear > tymax || tymin > tFar) 2471 return false; 2472 if (invDirZ >= 0.0) { 2473 tzmin = (minZ - originZ) * invDirZ; 2474 tzmax = (maxZ - originZ) * invDirZ; 2475 } else { 2476 tzmin = (maxZ - originZ) * invDirZ; 2477 tzmax = (minZ - originZ) * invDirZ; 2478 } 2479 if (tNear > tzmax || tzmin > tFar) 2480 return false; 2481 tNear = tymin > tNear || isNaN(tNear) ? tymin : tNear; 2482 tFar = tymax < tFar || isNaN(tFar) ? tymax : tFar; 2483 tNear = tzmin > tNear ? tzmin : tNear; 2484 tFar = tzmax < tFar ? tzmax : tFar; 2485 return tNear < tFar && tFar >= 0.0; 2486 } 2487 2488 /** 2489 * Test whether the ray with the given <code>origin</code> and direction <code>dir</code> 2490 * intersects the axis-aligned box specified as its minimum corner <code>min</code> and maximum corner <code>max</code>. 2491 * <p> 2492 * This method returns <code>true</code> for a ray whose origin lies inside the axis-aligned box. 2493 * <p> 2494 * If many boxes need to be tested against the same ray, then the {@link RayAabIntersection} class is likely more efficient. 2495 * <p> 2496 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 2497 * 2498 * @see #testRayAab(double, double, double, double, double, double, double, double, double, double, double, double) 2499 * @see RayAabIntersection 2500 * 2501 * @param origin 2502 * the ray's origin 2503 * @param dir 2504 * the ray's direction 2505 * @param min 2506 * the minimum corner of the axis-aligned box 2507 * @param max 2508 * the maximum corner of the axis-aligned box 2509 * @return <code>true</code> if the given ray intersects the axis-aligned box; <code>false</code> otherwise 2510 */ 2511 public static bool testRayAab(Vector3d origin, Vector3d dir, Vector3d min, Vector3d max) { 2512 return testRayAab(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, min.x, min.y, min.z, max.x, max.y, max.z); 2513 } 2514 2515 /** 2516 * Test whether the given ray with the origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code> 2517 * intersects the frontface of the triangle consisting of the three vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code>. 2518 * <p> 2519 * This is an implementation of the <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 2520 * Fast, Minimum Storage Ray/Triangle Intersection</a> method. 2521 * <p> 2522 * This test implements backface culling, that is, it will return <code>false</code> when the triangle is in clockwise 2523 * winding order assuming a <i>right-handed</i> coordinate system when seen along the ray's direction, even if the ray intersects the triangle. 2524 * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings. 2525 * 2526 * @see #testRayTriangleFront(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d, double) 2527 * 2528 * @param originX 2529 * the x coordinate of the ray's origin 2530 * @param originY 2531 * the y coordinate of the ray's origin 2532 * @param originZ 2533 * the z coordinate of the ray's origin 2534 * @param dirX 2535 * the x coordinate of the ray's direction 2536 * @param dirY 2537 * the y coordinate of the ray's direction 2538 * @param dirZ 2539 * the z coordinate of the ray's direction 2540 * @param v0X 2541 * the x coordinate of the first vertex 2542 * @param v0Y 2543 * the y coordinate of the first vertex 2544 * @param v0Z 2545 * the z coordinate of the first vertex 2546 * @param v1X 2547 * the x coordinate of the second vertex 2548 * @param v1Y 2549 * the y coordinate of the second vertex 2550 * @param v1Z 2551 * the z coordinate of the second vertex 2552 * @param v2X 2553 * the x coordinate of the third vertex 2554 * @param v2Y 2555 * the y coordinate of the third vertex 2556 * @param v2Z 2557 * the z coordinate of the third vertex 2558 * @param epsilon 2559 * a small epsilon when testing rays that are almost parallel to the triangle 2560 * @return <code>true</code> if the given ray intersects the frontface of the triangle; <code>false</code> otherwise 2561 */ 2562 public static bool testRayTriangleFront(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 2563 double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z, 2564 double epsilon) { 2565 double edge1X = v1X - v0X; 2566 double edge1Y = v1Y - v0Y; 2567 double edge1Z = v1Z - v0Z; 2568 double edge2X = v2X - v0X; 2569 double edge2Y = v2Y - v0Y; 2570 double edge2Z = v2Z - v0Z; 2571 double pvecX = dirY * edge2Z - dirZ * edge2Y; 2572 double pvecY = dirZ * edge2X - dirX * edge2Z; 2573 double pvecZ = dirX * edge2Y - dirY * edge2X; 2574 double det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ; 2575 if (det < epsilon) 2576 return false; 2577 double tvecX = originX - v0X; 2578 double tvecY = originY - v0Y; 2579 double tvecZ = originZ - v0Z; 2580 double u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ); 2581 if (u < 0.0 || u > det) 2582 return false; 2583 double qvecX = tvecY * edge1Z - tvecZ * edge1Y; 2584 double qvecY = tvecZ * edge1X - tvecX * edge1Z; 2585 double qvecZ = tvecX * edge1Y - tvecY * edge1X; 2586 double v = (dirX * qvecX + dirY * qvecY + dirZ * qvecZ); 2587 if (v < 0.0 || u + v > det) 2588 return false; 2589 double invDet = 1.0 / det; 2590 double t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet; 2591 return t >= epsilon; 2592 } 2593 2594 /** 2595 * Test whether the ray with the given <code>origin</code> and the given <code>dir</code> intersects the frontface of the triangle consisting of the three vertices 2596 * <code>v0</code>, <code>v1</code> and <code>v2</code>. 2597 * <p> 2598 * This is an implementation of the <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 2599 * Fast, Minimum Storage Ray/Triangle Intersection</a> method. 2600 * <p> 2601 * This test implements backface culling, that is, it will return <code>false</code> when the triangle is in clockwise 2602 * winding order assuming a <i>right-handed</i> coordinate system when seen along the ray's direction, even if the ray intersects the triangle. 2603 * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings. 2604 * 2605 * @see #testRayTriangleFront(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) 2606 * 2607 * @param origin 2608 * the ray's origin 2609 * @param dir 2610 * the ray's direction 2611 * @param v0 2612 * the position of the first vertex 2613 * @param v1 2614 * the position of the second vertex 2615 * @param v2 2616 * the position of the third vertex 2617 * @param epsilon 2618 * a small epsilon when testing rays that are almost parallel to the triangle 2619 * @return <code>true</code> if the given ray intersects the frontface of the triangle; <code>false</code> otherwise 2620 */ 2621 public static bool testRayTriangleFront(Vector3d origin, Vector3d dir, Vector3d v0, Vector3d v1, Vector3d v2, double epsilon) { 2622 return testRayTriangleFront(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, epsilon); 2623 } 2624 2625 /** 2626 * Test whether the given ray with the origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code> 2627 * intersects the triangle consisting of the three vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code>. 2628 * <p> 2629 * This is an implementation of the <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 2630 * Fast, Minimum Storage Ray/Triangle Intersection</a> method. 2631 * <p> 2632 * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle. 2633 * 2634 * @see #testRayTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d, double) 2635 * 2636 * @param originX 2637 * the x coordinate of the ray's origin 2638 * @param originY 2639 * the y coordinate of the ray's origin 2640 * @param originZ 2641 * the z coordinate of the ray's origin 2642 * @param dirX 2643 * the x coordinate of the ray's direction 2644 * @param dirY 2645 * the y coordinate of the ray's direction 2646 * @param dirZ 2647 * the z coordinate of the ray's direction 2648 * @param v0X 2649 * the x coordinate of the first vertex 2650 * @param v0Y 2651 * the y coordinate of the first vertex 2652 * @param v0Z 2653 * the z coordinate of the first vertex 2654 * @param v1X 2655 * the x coordinate of the second vertex 2656 * @param v1Y 2657 * the y coordinate of the second vertex 2658 * @param v1Z 2659 * the z coordinate of the second vertex 2660 * @param v2X 2661 * the x coordinate of the third vertex 2662 * @param v2Y 2663 * the y coordinate of the third vertex 2664 * @param v2Z 2665 * the z coordinate of the third vertex 2666 * @param epsilon 2667 * a small epsilon when testing rays that are almost parallel to the triangle 2668 * @return <code>true</code> if the given ray intersects the frontface of the triangle; <code>false</code> otherwise 2669 */ 2670 public static bool testRayTriangle(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 2671 double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z, 2672 double epsilon) { 2673 double edge1X = v1X - v0X; 2674 double edge1Y = v1Y - v0Y; 2675 double edge1Z = v1Z - v0Z; 2676 double edge2X = v2X - v0X; 2677 double edge2Y = v2Y - v0Y; 2678 double edge2Z = v2Z - v0Z; 2679 double pvecX = dirY * edge2Z - dirZ * edge2Y; 2680 double pvecY = dirZ * edge2X - dirX * edge2Z; 2681 double pvecZ = dirX * edge2Y - dirY * edge2X; 2682 double det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ; 2683 if (det > -epsilon && det < epsilon) 2684 return false; 2685 double tvecX = originX - v0X; 2686 double tvecY = originY - v0Y; 2687 double tvecZ = originZ - v0Z; 2688 double invDet = 1.0 / det; 2689 double u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ) * invDet; 2690 if (u < 0.0 || u > 1.0) 2691 return false; 2692 double qvecX = tvecY * edge1Z - tvecZ * edge1Y; 2693 double qvecY = tvecZ * edge1X - tvecX * edge1Z; 2694 double qvecZ = tvecX * edge1Y - tvecY * edge1X; 2695 double v = (dirX * qvecX + dirY * qvecY + dirZ * qvecZ) * invDet; 2696 if (v < 0.0 || u + v > 1.0) 2697 return false; 2698 double t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet; 2699 return t >= epsilon; 2700 } 2701 2702 /** 2703 * Test whether the ray with the given <code>origin</code> and the given <code>dir</code> intersects the frontface of the triangle consisting of the three vertices 2704 * <code>v0</code>, <code>v1</code> and <code>v2</code>. 2705 * <p> 2706 * This is an implementation of the <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 2707 * Fast, Minimum Storage Ray/Triangle Intersection</a> method. 2708 * <p> 2709 * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle. 2710 * 2711 * @see #testRayTriangle(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) 2712 * 2713 * @param origin 2714 * the ray's origin 2715 * @param dir 2716 * the ray's direction 2717 * @param v0 2718 * the position of the first vertex 2719 * @param v1 2720 * the position of the second vertex 2721 * @param v2 2722 * the position of the third vertex 2723 * @param epsilon 2724 * a small epsilon when testing rays that are almost parallel to the triangle 2725 * @return <code>true</code> if the given ray intersects the frontface of the triangle; <code>false</code> otherwise 2726 */ 2727 public static bool testRayTriangle(Vector3d origin, Vector3d dir, Vector3d v0, Vector3d v1, Vector3d v2, double epsilon) { 2728 return testRayTriangle(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, epsilon); 2729 } 2730 2731 /** 2732 * Determine whether the given ray with the origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code> 2733 * intersects the frontface of the triangle consisting of the three vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code> 2734 * and return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the point of intersection. 2735 * <p> 2736 * This is an implementation of the <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 2737 * Fast, Minimum Storage Ray/Triangle Intersection</a> method. 2738 * <p> 2739 * This test implements backface culling, that is, it will return <code>false</code> when the triangle is in clockwise 2740 * winding order assuming a <i>right-handed</i> coordinate system when seen along the ray's direction, even if the ray intersects the triangle. 2741 * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings. 2742 * 2743 * @see #testRayTriangleFront(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d, double) 2744 * 2745 * @param originX 2746 * the x coordinate of the ray's origin 2747 * @param originY 2748 * the y coordinate of the ray's origin 2749 * @param originZ 2750 * the z coordinate of the ray's origin 2751 * @param dirX 2752 * the x coordinate of the ray's direction 2753 * @param dirY 2754 * the y coordinate of the ray's direction 2755 * @param dirZ 2756 * the z coordinate of the ray's direction 2757 * @param v0X 2758 * the x coordinate of the first vertex 2759 * @param v0Y 2760 * the y coordinate of the first vertex 2761 * @param v0Z 2762 * the z coordinate of the first vertex 2763 * @param v1X 2764 * the x coordinate of the second vertex 2765 * @param v1Y 2766 * the y coordinate of the second vertex 2767 * @param v1Z 2768 * the z coordinate of the second vertex 2769 * @param v2X 2770 * the x coordinate of the third vertex 2771 * @param v2Y 2772 * the y coordinate of the third vertex 2773 * @param v2Z 2774 * the z coordinate of the third vertex 2775 * @param epsilon 2776 * a small epsilon when testing rays that are almost parallel to the triangle 2777 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the point of intersection 2778 * if the ray intersects the frontface of the triangle; <code>-1.0</code> otherwise 2779 */ 2780 public static double intersectRayTriangleFront(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 2781 double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z, 2782 double epsilon) { 2783 double edge1X = v1X - v0X; 2784 double edge1Y = v1Y - v0Y; 2785 double edge1Z = v1Z - v0Z; 2786 double edge2X = v2X - v0X; 2787 double edge2Y = v2Y - v0Y; 2788 double edge2Z = v2Z - v0Z; 2789 double pvecX = dirY * edge2Z - dirZ * edge2Y; 2790 double pvecY = dirZ * edge2X - dirX * edge2Z; 2791 double pvecZ = dirX * edge2Y - dirY * edge2X; 2792 double det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ; 2793 if (det <= epsilon) 2794 return -1.0; 2795 double tvecX = originX - v0X; 2796 double tvecY = originY - v0Y; 2797 double tvecZ = originZ - v0Z; 2798 double u = tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ; 2799 if (u < 0.0 || u > det) 2800 return -1.0; 2801 double qvecX = tvecY * edge1Z - tvecZ * edge1Y; 2802 double qvecY = tvecZ * edge1X - tvecX * edge1Z; 2803 double qvecZ = tvecX * edge1Y - tvecY * edge1X; 2804 double v = dirX * qvecX + dirY * qvecY + dirZ * qvecZ; 2805 if (v < 0.0 || u + v > det) 2806 return -1.0; 2807 double invDet = 1.0 / det; 2808 double t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet; 2809 return t; 2810 } 2811 2812 /** 2813 * Determine whether the ray with the given <code>origin</code> and the given <code>dir</code> intersects the frontface of the triangle consisting of the three vertices 2814 * <code>v0</code>, <code>v1</code> and <code>v2</code> and return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the point of intersection. 2815 * <p> 2816 * This is an implementation of the <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 2817 * Fast, Minimum Storage Ray/Triangle Intersection</a> method. 2818 * <p> 2819 * This test implements backface culling, that is, it will return <code>false</code> when the triangle is in clockwise 2820 * winding order assuming a <i>right-handed</i> coordinate system when seen along the ray's direction, even if the ray intersects the triangle. 2821 * This is in compliance with how OpenGL handles backface culling with default frontface/backface settings. 2822 * 2823 * @see #intersectRayTriangleFront(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) 2824 * 2825 * @param origin 2826 * the ray's origin 2827 * @param dir 2828 * the ray's direction 2829 * @param v0 2830 * the position of the first vertex 2831 * @param v1 2832 * the position of the second vertex 2833 * @param v2 2834 * the position of the third vertex 2835 * @param epsilon 2836 * a small epsilon when testing rays that are almost parallel to the triangle 2837 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the point of intersection 2838 * if the ray intersects the frontface of the triangle; <code>-1.0</code> otherwise 2839 */ 2840 public static double intersectRayTriangleFront(Vector3d origin, Vector3d dir, Vector3d v0, Vector3d v1, Vector3d v2, double epsilon) { 2841 return intersectRayTriangleFront(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, epsilon); 2842 } 2843 2844 /** 2845 * Determine whether the given ray with the origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code> 2846 * intersects the triangle consisting of the three vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code> 2847 * and return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the point of intersection. 2848 * <p> 2849 * This is an implementation of the <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 2850 * Fast, Minimum Storage Ray/Triangle Intersection</a> method. 2851 * <p> 2852 * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle. 2853 * 2854 * @see #testRayTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d, double) 2855 * 2856 * @param originX 2857 * the x coordinate of the ray's origin 2858 * @param originY 2859 * the y coordinate of the ray's origin 2860 * @param originZ 2861 * the z coordinate of the ray's origin 2862 * @param dirX 2863 * the x coordinate of the ray's direction 2864 * @param dirY 2865 * the y coordinate of the ray's direction 2866 * @param dirZ 2867 * the z coordinate of the ray's direction 2868 * @param v0X 2869 * the x coordinate of the first vertex 2870 * @param v0Y 2871 * the y coordinate of the first vertex 2872 * @param v0Z 2873 * the z coordinate of the first vertex 2874 * @param v1X 2875 * the x coordinate of the second vertex 2876 * @param v1Y 2877 * the y coordinate of the second vertex 2878 * @param v1Z 2879 * the z coordinate of the second vertex 2880 * @param v2X 2881 * the x coordinate of the third vertex 2882 * @param v2Y 2883 * the y coordinate of the third vertex 2884 * @param v2Z 2885 * the z coordinate of the third vertex 2886 * @param epsilon 2887 * a small epsilon when testing rays that are almost parallel to the triangle 2888 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the point of intersection 2889 * if the ray intersects the triangle; <code>-1.0</code> otherwise 2890 */ 2891 public static double intersectRayTriangle(double originX, double originY, double originZ, double dirX, double dirY, double dirZ, 2892 double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z, 2893 double epsilon) { 2894 double edge1X = v1X - v0X; 2895 double edge1Y = v1Y - v0Y; 2896 double edge1Z = v1Z - v0Z; 2897 double edge2X = v2X - v0X; 2898 double edge2Y = v2Y - v0Y; 2899 double edge2Z = v2Z - v0Z; 2900 double pvecX = dirY * edge2Z - dirZ * edge2Y; 2901 double pvecY = dirZ * edge2X - dirX * edge2Z; 2902 double pvecZ = dirX * edge2Y - dirY * edge2X; 2903 double det = edge1X * pvecX + edge1Y * pvecY + edge1Z * pvecZ; 2904 if (det > -epsilon && det < epsilon) 2905 return -1.0; 2906 double tvecX = originX - v0X; 2907 double tvecY = originY - v0Y; 2908 double tvecZ = originZ - v0Z; 2909 double invDet = 1.0 / det; 2910 double u = (tvecX * pvecX + tvecY * pvecY + tvecZ * pvecZ) * invDet; 2911 if (u < 0.0 || u > 1.0) 2912 return -1.0; 2913 double qvecX = tvecY * edge1Z - tvecZ * edge1Y; 2914 double qvecY = tvecZ * edge1X - tvecX * edge1Z; 2915 double qvecZ = tvecX * edge1Y - tvecY * edge1X; 2916 double v = (dirX * qvecX + dirY * qvecY + dirZ * qvecZ) * invDet; 2917 if (v < 0.0 || u + v > 1.0) 2918 return -1.0; 2919 double t = (edge2X * qvecX + edge2Y * qvecY + edge2Z * qvecZ) * invDet; 2920 return t; 2921 } 2922 2923 /** 2924 * Determine whether the ray with the given <code>origin</code> and the given <code>dir</code> intersects the triangle consisting of the three vertices 2925 * <code>v0</code>, <code>v1</code> and <code>v2</code> and return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the point of intersection. 2926 * <p> 2927 * This is an implementation of the <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 2928 * Fast, Minimum Storage Ray/Triangle Intersection</a> method. 2929 * <p> 2930 * This test does not take into account the winding order of the triangle, so a ray will intersect a front-facing triangle as well as a back-facing triangle. 2931 * 2932 * @see #intersectRayTriangle(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) 2933 * 2934 * @param origin 2935 * the ray's origin 2936 * @param dir 2937 * the ray's direction 2938 * @param v0 2939 * the position of the first vertex 2940 * @param v1 2941 * the position of the second vertex 2942 * @param v2 2943 * the position of the third vertex 2944 * @param epsilon 2945 * a small epsilon when testing rays that are almost parallel to the triangle 2946 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the point of intersection 2947 * if the ray intersects the triangle; <code>-1.0</code> otherwise 2948 */ 2949 public static double intersectRayTriangle(Vector3d origin, Vector3d dir, Vector3d v0, Vector3d v1, Vector3d v2, double epsilon) { 2950 return intersectRayTriangle(origin.x, origin.y, origin.z, dir.x, dir.y, dir.z, v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, epsilon); 2951 } 2952 2953 /** 2954 * Test whether the line segment with the end points <code>(p0X, p0Y, p0Z)</code> and <code>(p1X, p1Y, p1Z)</code> 2955 * intersects the triangle consisting of the three vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code>, 2956 * regardless of the winding order of the triangle or the direction of the line segment between its two end points. 2957 * <p> 2958 * Reference: <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 2959 * Fast, Minimum Storage Ray/Triangle Intersection</a> 2960 * 2961 * @see #testLineSegmentTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d, double) 2962 * 2963 * @param p0X 2964 * the x coordinate of the line segment's first end point 2965 * @param p0Y 2966 * the y coordinate of the line segment's first end point 2967 * @param p0Z 2968 * the z coordinate of the line segment's first end point 2969 * @param p1X 2970 * the x coordinate of the line segment's second end point 2971 * @param p1Y 2972 * the y coordinate of the line segment's second end point 2973 * @param p1Z 2974 * the z coordinate of the line segment's second end point 2975 * @param v0X 2976 * the x coordinate of the first vertex 2977 * @param v0Y 2978 * the y coordinate of the first vertex 2979 * @param v0Z 2980 * the z coordinate of the first vertex 2981 * @param v1X 2982 * the x coordinate of the second vertex 2983 * @param v1Y 2984 * the y coordinate of the second vertex 2985 * @param v1Z 2986 * the z coordinate of the second vertex 2987 * @param v2X 2988 * the x coordinate of the third vertex 2989 * @param v2Y 2990 * the y coordinate of the third vertex 2991 * @param v2Z 2992 * the z coordinate of the third vertex 2993 * @param epsilon 2994 * a small epsilon when testing line segments that are almost parallel to the triangle 2995 * @return <code>true</code> if the given line segment intersects the triangle; <code>false</code> otherwise 2996 */ 2997 public static bool testLineSegmentTriangle(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z, 2998 double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z, 2999 double epsilon) { 3000 double dirX = p1X - p0X; 3001 double dirY = p1Y - p0Y; 3002 double dirZ = p1Z - p0Z; 3003 double t = intersectRayTriangle(p0X, p0Y, p0Z, dirX, dirY, dirZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z, epsilon); 3004 return t >= 0.0 && t <= 1.0; 3005 } 3006 3007 /** 3008 * Test whether the line segment with the end points <code>p0</code> and <code>p1</code> 3009 * intersects the triangle consisting of the three vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code>, 3010 * regardless of the winding order of the triangle or the direction of the line segment between its two end points. 3011 * <p> 3012 * Reference: <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 3013 * Fast, Minimum Storage Ray/Triangle Intersection</a> 3014 * 3015 * @see #testLineSegmentTriangle(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double) 3016 * 3017 * @param p0 3018 * the line segment's first end point 3019 * @param p1 3020 * the line segment's second end point 3021 * @param v0 3022 * the position of the first vertex 3023 * @param v1 3024 * the position of the second vertex 3025 * @param v2 3026 * the position of the third vertex 3027 * @param epsilon 3028 * a small epsilon when testing line segments that are almost parallel to the triangle 3029 * @return <code>true</code> if the given line segment intersects the triangle; <code>false</code> otherwise 3030 */ 3031 public static bool testLineSegmentTriangle(Vector3d p0, Vector3d p1, Vector3d v0, Vector3d v1, Vector3d v2, double epsilon) { 3032 return testLineSegmentTriangle(p0.x, p0.y, p0.z, p1.x, p1.y, p1.z, v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, epsilon); 3033 } 3034 3035 /** 3036 * Determine whether the line segment with the end points <code>(p0X, p0Y, p0Z)</code> and <code>(p1X, p1Y, p1Z)</code> 3037 * intersects the triangle consisting of the three vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code>, 3038 * regardless of the winding order of the triangle or the direction of the line segment between its two end points, 3039 * and return the point of intersection. 3040 * <p> 3041 * Reference: <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 3042 * Fast, Minimum Storage Ray/Triangle Intersection</a> 3043 * 3044 * @see #intersectLineSegmentTriangle(Vector3d, Vector3d, Vector3d, Vector3d, Vector3d, double, Vector3d) 3045 * 3046 * @param p0X 3047 * the x coordinate of the line segment's first end point 3048 * @param p0Y 3049 * the y coordinate of the line segment's first end point 3050 * @param p0Z 3051 * the z coordinate of the line segment's first end point 3052 * @param p1X 3053 * the x coordinate of the line segment's second end point 3054 * @param p1Y 3055 * the y coordinate of the line segment's second end point 3056 * @param p1Z 3057 * the z coordinate of the line segment's second end point 3058 * @param v0X 3059 * the x coordinate of the first vertex 3060 * @param v0Y 3061 * the y coordinate of the first vertex 3062 * @param v0Z 3063 * the z coordinate of the first vertex 3064 * @param v1X 3065 * the x coordinate of the second vertex 3066 * @param v1Y 3067 * the y coordinate of the second vertex 3068 * @param v1Z 3069 * the z coordinate of the second vertex 3070 * @param v2X 3071 * the x coordinate of the third vertex 3072 * @param v2Y 3073 * the y coordinate of the third vertex 3074 * @param v2Z 3075 * the z coordinate of the third vertex 3076 * @param epsilon 3077 * a small epsilon when testing line segments that are almost parallel to the triangle 3078 * @param intersectionPoint 3079 * the point of intersection 3080 * @return <code>true</code> if the given line segment intersects the triangle; <code>false</code> otherwise 3081 */ 3082 public static bool intersectLineSegmentTriangle(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z, 3083 double v0X, double v0Y, double v0Z, double v1X, double v1Y, double v1Z, double v2X, double v2Y, double v2Z, 3084 double epsilon, Vector3d intersectionPoint) { 3085 double dirX = p1X - p0X; 3086 double dirY = p1Y - p0Y; 3087 double dirZ = p1Z - p0Z; 3088 double t = intersectRayTriangle(p0X, p0Y, p0Z, dirX, dirY, dirZ, v0X, v0Y, v0Z, v1X, v1Y, v1Z, v2X, v2Y, v2Z, epsilon); 3089 if (t >= 0.0 && t <= 1.0) { 3090 intersectionPoint.x = p0X + dirX * t; 3091 intersectionPoint.y = p0Y + dirY * t; 3092 intersectionPoint.z = p0Z + dirZ * t; 3093 return true; 3094 } 3095 return false; 3096 } 3097 3098 /** 3099 * Determine whether the line segment with the end points <code>p0</code> and <code>p1</code> 3100 * intersects the triangle consisting of the three vertices <code>(v0X, v0Y, v0Z)</code>, <code>(v1X, v1Y, v1Z)</code> and <code>(v2X, v2Y, v2Z)</code>, 3101 * regardless of the winding order of the triangle or the direction of the line segment between its two end points, 3102 * and return the point of intersection. 3103 * <p> 3104 * Reference: <a href="http://www.graphics.cornell.edu/pubs/1997/MT97.pdf"> 3105 * Fast, Minimum Storage Ray/Triangle Intersection</a> 3106 * 3107 * @see #intersectLineSegmentTriangle(double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, double, Vector3d) 3108 * 3109 * @param p0 3110 * the line segment's first end point 3111 * @param p1 3112 * the line segment's second end point 3113 * @param v0 3114 * the position of the first vertex 3115 * @param v1 3116 * the position of the second vertex 3117 * @param v2 3118 * the position of the third vertex 3119 * @param epsilon 3120 * a small epsilon when testing line segments that are almost parallel to the triangle 3121 * @param intersectionPoint 3122 * the point of intersection 3123 * @return <code>true</code> if the given line segment intersects the triangle; <code>false</code> otherwise 3124 */ 3125 public static bool intersectLineSegmentTriangle(Vector3d p0, Vector3d p1, Vector3d v0, Vector3d v1, Vector3d v2, double epsilon, Vector3d intersectionPoint) { 3126 return intersectLineSegmentTriangle(p0.x, p0.y, p0.z, p1.x, p1.y, p1.z, v0.x, v0.y, v0.z, v1.x, v1.y, v1.z, v2.x, v2.y, v2.z, epsilon, intersectionPoint); 3127 } 3128 3129 /** 3130 * Determine whether the line segment with the end points <code>(p0X, p0Y, p0Z)</code> and <code>(p1X, p1Y, p1Z)</code> 3131 * intersects the plane given as the general plane equation <i>a*x + b*y + c*z + d = 0</i>, 3132 * and return the point of intersection. 3133 * 3134 * @param p0X 3135 * the x coordinate of the line segment's first end point 3136 * @param p0Y 3137 * the y coordinate of the line segment's first end point 3138 * @param p0Z 3139 * the z coordinate of the line segment's first end point 3140 * @param p1X 3141 * the x coordinate of the line segment's second end point 3142 * @param p1Y 3143 * the y coordinate of the line segment's second end point 3144 * @param p1Z 3145 * the z coordinate of the line segment's second end point 3146 * @param a 3147 * the x factor in the plane equation 3148 * @param b 3149 * the y factor in the plane equation 3150 * @param c 3151 * the z factor in the plane equation 3152 * @param d 3153 * the constant in the plane equation 3154 * @param intersectionPoint 3155 * the point of intersection 3156 * @return <code>true</code> if the given line segment intersects the plane; <code>false</code> otherwise 3157 */ 3158 public static bool intersectLineSegmentPlane(double p0X, double p0Y, double p0Z, double p1X, double p1Y, double p1Z, 3159 double a, double b, double c, double d, Vector3d intersectionPoint) { 3160 double dirX = p1X - p0X; 3161 double dirY = p1Y - p0Y; 3162 double dirZ = p1Z - p0Z; 3163 double denom = a * dirX + b * dirY + c * dirZ; 3164 double t = -(a * p0X + b * p0Y + c * p0Z + d) / denom; 3165 if (t >= 0.0 && t <= 1.0) { 3166 intersectionPoint.x = p0X + t * dirX; 3167 intersectionPoint.y = p0Y + t * dirY; 3168 intersectionPoint.z = p0Z + t * dirZ; 3169 return true; 3170 } 3171 return false; 3172 } 3173 3174 /** 3175 * Test whether the line with the general line equation <i>a*x + b*y + c = 0</i> intersects the circle with center 3176 * <code>(centerX, centerY)</code> and <code>radius</code>. 3177 * <p> 3178 * Reference: <a href="http://math.stackexchange.com/questions/943383/determine-circle-of-intersection-of-plane-and-sphere">http://math.stackexchange.com</a> 3179 * 3180 * @param a 3181 * the x factor in the line equation 3182 * @param b 3183 * the y factor in the line equation 3184 * @param c 3185 * the constant in the line equation 3186 * @param centerX 3187 * the x coordinate of the circle's center 3188 * @param centerY 3189 * the y coordinate of the circle's center 3190 * @param radius 3191 * the radius of the circle 3192 * @return <code>true</code> iff the line intersects the circle; <code>false</code> otherwise 3193 */ 3194 public static bool testLineCircle(double a, double b, double c, double centerX, double centerY, double radius) { 3195 double denom = Math.sqrt(a * a + b * b); 3196 double dist = (a * centerX + b * centerY + c) / denom; 3197 return -radius <= dist && dist <= radius; 3198 } 3199 3200 /** 3201 * Test whether the line with the general line equation <i>a*x + b*y + c = 0</i> intersects the circle with center 3202 * <code>(centerX, centerY)</code> and <code>radius</code>, and store the center of the line segment of 3203 * intersection in the <code>(x, y)</code> components of the supplied vector and the half-length of that line segment in the z component. 3204 * <p> 3205 * Reference: <a href="http://math.stackexchange.com/questions/943383/determine-circle-of-intersection-of-plane-and-sphere">http://math.stackexchange.com</a> 3206 * 3207 * @param a 3208 * the x factor in the line equation 3209 * @param b 3210 * the y factor in the line equation 3211 * @param c 3212 * the constant in the line equation 3213 * @param centerX 3214 * the x coordinate of the circle's center 3215 * @param centerY 3216 * the y coordinate of the circle's center 3217 * @param radius 3218 * the radius of the circle 3219 * @param intersectionCenterAndHL 3220 * will hold the center of the line segment of intersection in the <code>(x, y)</code> components and the half-length in the z component 3221 * @return <code>true</code> iff the line intersects the circle; <code>false</code> otherwise 3222 */ 3223 public static bool intersectLineCircle(double a, double b, double c, double centerX, double centerY, double radius, Vector3d intersectionCenterAndHL) { 3224 double invDenom = Math.invsqrt(a * a + b * b); 3225 double dist = (a * centerX + b * centerY + c) * invDenom; 3226 if (-radius <= dist && dist <= radius) { 3227 intersectionCenterAndHL.x = centerX + dist * a * invDenom; 3228 intersectionCenterAndHL.y = centerY + dist * b * invDenom; 3229 intersectionCenterAndHL.z = Math.sqrt(radius * radius - dist * dist); 3230 return true; 3231 } 3232 return false; 3233 } 3234 3235 /** 3236 * Test whether the line defined by the two points <code>(x0, y0)</code> and <code>(x1, y1)</code> intersects the circle with center 3237 * <code>(centerX, centerY)</code> and <code>radius</code>, and store the center of the line segment of 3238 * intersection in the <code>(x, y)</code> components of the supplied vector and the half-length of that line segment in the z component. 3239 * <p> 3240 * Reference: <a href="http://math.stackexchange.com/questions/943383/determine-circle-of-intersection-of-plane-and-sphere">http://math.stackexchange.com</a> 3241 * 3242 * @param x0 3243 * the x coordinate of the first point on the line 3244 * @param y0 3245 * the y coordinate of the first point on the line 3246 * @param x1 3247 * the x coordinate of the second point on the line 3248 * @param y1 3249 * the y coordinate of the second point on the line 3250 * @param centerX 3251 * the x coordinate of the circle's center 3252 * @param centerY 3253 * the y coordinate of the circle's center 3254 * @param radius 3255 * the radius of the circle 3256 * @param intersectionCenterAndHL 3257 * will hold the center of the line segment of intersection in the <code>(x, y)</code> components and the half-length in the z component 3258 * @return <code>true</code> iff the line intersects the circle; <code>false</code> otherwise 3259 */ 3260 public static bool intersectLineCircle(double x0, double y0, double x1, double y1, double centerX, double centerY, double radius, Vector3d intersectionCenterAndHL) { 3261 // Build general line equation from two points and use the other method 3262 return intersectLineCircle(y0 - y1, x1 - x0, (x0 - x1) * y0 + (y1 - y0) * x0, centerX, centerY, radius, intersectionCenterAndHL); 3263 } 3264 3265 /** 3266 * Test whether the axis-aligned rectangle with minimum corner <code>(minX, minY)</code> and maximum corner <code>(maxX, maxY)</code> 3267 * intersects the line with the general equation <i>a*x + b*y + c = 0</i>. 3268 * <p> 3269 * Reference: <a href="http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/">http://www.lighthouse3d.com</a> ("Geometric Approach - Testing Boxes II") 3270 * 3271 * @param minX 3272 * the x coordinate of the minimum corner of the axis-aligned rectangle 3273 * @param minY 3274 * the y coordinate of the minimum corner of the axis-aligned rectangle 3275 * @param maxX 3276 * the x coordinate of the maximum corner of the axis-aligned rectangle 3277 * @param maxY 3278 * the y coordinate of the maximum corner of the axis-aligned rectangle 3279 * @param a 3280 * the x factor in the line equation 3281 * @param b 3282 * the y factor in the line equation 3283 * @param c 3284 * the constant in the plane equation 3285 * @return <code>true</code> iff the axis-aligned rectangle intersects the line; <code>false</code> otherwise 3286 */ 3287 public static bool testAarLine(double minX, double minY, double maxX, double maxY, double a, double b, double c) { 3288 double pX, pY, nX, nY; 3289 if (a > 0.0) { 3290 pX = maxX; 3291 nX = minX; 3292 } else { 3293 pX = minX; 3294 nX = maxX; 3295 } 3296 if (b > 0.0) { 3297 pY = maxY; 3298 nY = minY; 3299 } else { 3300 pY = minY; 3301 nY = maxY; 3302 } 3303 double distN = c + a * nX + b * nY; 3304 double distP = c + a * pX + b * pY; 3305 return distN <= 0.0 && distP >= 0.0; 3306 } 3307 3308 /** 3309 * Test whether the axis-aligned rectangle with minimum corner <code>min</code> and maximum corner <code>max</code> 3310 * intersects the line with the general equation <i>a*x + b*y + c = 0</i>. 3311 * <p> 3312 * Reference: <a href="http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/">http://www.lighthouse3d.com</a> ("Geometric Approach - Testing Boxes II") 3313 * 3314 * @param min 3315 * the minimum corner of the axis-aligned rectangle 3316 * @param max 3317 * the maximum corner of the axis-aligned rectangle 3318 * @param a 3319 * the x factor in the line equation 3320 * @param b 3321 * the y factor in the line equation 3322 * @param c 3323 * the constant in the line equation 3324 * @return <code>true</code> iff the axis-aligned rectangle intersects the line; <code>false</code> otherwise 3325 */ 3326 public static bool testAarLine(Vector2d min, Vector2d max, double a, double b, double c) { 3327 return testAarLine(min.x, min.y, max.x, max.y, a, b, c); 3328 } 3329 3330 /** 3331 * Test whether the axis-aligned rectangle with minimum corner <code>(minX, minY)</code> and maximum corner <code>(maxX, maxY)</code> 3332 * intersects the line defined by the two points <code>(x0, y0)</code> and <code>(x1, y1)</code>. 3333 * <p> 3334 * Reference: <a href="http://www.lighthouse3d.com/tutorials/view-frustum-culling/geometric-approach-testing-boxes-ii/">http://www.lighthouse3d.com</a> ("Geometric Approach - Testing Boxes II") 3335 * 3336 * @param minX 3337 * the x coordinate of the minimum corner of the axis-aligned rectangle 3338 * @param minY 3339 * the y coordinate of the minimum corner of the axis-aligned rectangle 3340 * @param maxX 3341 * the x coordinate of the maximum corner of the axis-aligned rectangle 3342 * @param maxY 3343 * the y coordinate of the maximum corner of the axis-aligned rectangle 3344 * @param x0 3345 * the x coordinate of the first point on the line 3346 * @param y0 3347 * the y coordinate of the first point on the line 3348 * @param x1 3349 * the x coordinate of the second point on the line 3350 * @param y1 3351 * the y coordinate of the second point on the line 3352 * @return <code>true</code> iff the axis-aligned rectangle intersects the line; <code>false</code> otherwise 3353 */ 3354 public static bool testAarLine(double minX, double minY, double maxX, double maxY, double x0, double y0, double x1, double y1) { 3355 double a = y0 - y1; 3356 double b = x1 - x0; 3357 double c = -b * y0 - a * x0; 3358 return testAarLine(minX, minY, maxX, maxY, a, b, c); 3359 } 3360 3361 /** 3362 * Test whether the axis-aligned rectangle with minimum corner <code>(minXA, minYA)</code> and maximum corner <code>(maxXA, maxYA)</code> 3363 * intersects the axis-aligned rectangle with minimum corner <code>(minXB, minYB)</code> and maximum corner <code>(maxXB, maxYB)</code>. 3364 * 3365 * @param minXA 3366 * the x coordinate of the minimum corner of the first axis-aligned rectangle 3367 * @param minYA 3368 * the y coordinate of the minimum corner of the first axis-aligned rectangle 3369 * @param maxXA 3370 * the x coordinate of the maximum corner of the first axis-aligned rectangle 3371 * @param maxYA 3372 * the y coordinate of the maximum corner of the first axis-aligned rectangle 3373 * @param minXB 3374 * the x coordinate of the minimum corner of the second axis-aligned rectangle 3375 * @param minYB 3376 * the y coordinate of the minimum corner of the second axis-aligned rectangle 3377 * @param maxXB 3378 * the x coordinate of the maximum corner of the second axis-aligned rectangle 3379 * @param maxYB 3380 * the y coordinate of the maximum corner of the second axis-aligned rectangle 3381 * @return <code>true</code> iff both axis-aligned rectangles intersect; <code>false</code> otherwise 3382 */ 3383 public static bool testAarAar(double minXA, double minYA, double maxXA, double maxYA, double minXB, double minYB, double maxXB, double maxYB) { 3384 return maxXA >= minXB && maxYA >= minYB && minXA <= maxXB && minYA <= maxYB; 3385 } 3386 3387 /** 3388 * Test whether the axis-aligned rectangle with minimum corner <code>minA</code> and maximum corner <code>maxA</code> 3389 * intersects the axis-aligned rectangle with minimum corner <code>minB</code> and maximum corner <code>maxB</code>. 3390 * 3391 * @param minA 3392 * the minimum corner of the first axis-aligned rectangle 3393 * @param maxA 3394 * the maximum corner of the first axis-aligned rectangle 3395 * @param minB 3396 * the minimum corner of the second axis-aligned rectangle 3397 * @param maxB 3398 * the maximum corner of the second axis-aligned rectangle 3399 * @return <code>true</code> iff both axis-aligned rectangles intersect; <code>false</code> otherwise 3400 */ 3401 public static bool testAarAar(Vector2d minA, Vector2d maxA, Vector2d minB, Vector2d maxB) { 3402 return testAarAar(minA.x, minA.y, maxA.x, maxA.y, minB.x, minB.y, maxB.x, maxB.y); 3403 } 3404 3405 /** 3406 * Test whether a given circle with center <code>(aX, aY)</code> and radius <code>aR</code> and travelled distance vector <code>(maX, maY)</code> 3407 * intersects a given static circle with center <code>(bX, bY)</code> and radius <code>bR</code>. 3408 * <p> 3409 * Note that the case of two moving circles can always be reduced to this case by expressing the moved distance of one of the circles relative 3410 * to the other. 3411 * <p> 3412 * Reference: <a href="https://www.gamasutra.com/view/feature/131424/pool_hall_lessons_fast_accurate_.php?page=2">https://www.gamasutra.com</a> 3413 * 3414 * @param aX 3415 * the x coordinate of the first circle's center 3416 * @param aY 3417 * the y coordinate of the first circle's center 3418 * @param maX 3419 * the x coordinate of the first circle's travelled distance vector 3420 * @param maY 3421 * the y coordinate of the first circle's travelled distance vector 3422 * @param aR 3423 * the radius of the first circle 3424 * @param bX 3425 * the x coordinate of the second circle's center 3426 * @param bY 3427 * the y coordinate of the second circle's center 3428 * @param bR 3429 * the radius of the second circle 3430 * @return <code>true</code> if both circle intersect; <code>false</code> otherwise 3431 */ 3432 public static bool testMovingCircleCircle(double aX, double aY, double maX, double maY, double aR, double bX, double bY, double bR) { 3433 double aRbR = aR + bR; 3434 double dist = Math.sqrt((aX - bX) * (aX - bX) + (aY - bY) * (aY - bY)) - aRbR; 3435 double mLen = Math.sqrt(maX * maX + maY * maY); 3436 if (mLen < dist) 3437 return false; 3438 double invMLen = 1.0 / mLen; 3439 double nX = maX * invMLen; 3440 double nY = maY * invMLen; 3441 double cX = bX - aX; 3442 double cY = bY - aY; 3443 double nDotC = nX * cX + nY * cY; 3444 if (nDotC <= 0.0) 3445 return false; 3446 double cLen = Math.sqrt(cX * cX + cY * cY); 3447 double cLenNdotC = cLen * cLen - nDotC * nDotC; 3448 double aRbR2 = aRbR * aRbR; 3449 if (cLenNdotC >= aRbR2) 3450 return false; 3451 double t = aRbR2 - cLenNdotC; 3452 if (t < 0.0) 3453 return false; 3454 double distance = nDotC - Math.sqrt(t); 3455 double mag = mLen; 3456 if (mag < distance) 3457 return false; 3458 return true; 3459 } 3460 3461 /** 3462 * Test whether a given circle with center <code>centerA</code> and radius <code>aR</code> and travelled distance vector <code>moveA</code> 3463 * intersects a given static circle with center <code>centerB</code> and radius <code>bR</code>. 3464 * <p> 3465 * Note that the case of two moving circles can always be reduced to this case by expressing the moved distance of one of the circles relative 3466 * to the other. 3467 * <p> 3468 * Reference: <a href="https://www.gamasutra.com/view/feature/131424/pool_hall_lessons_fast_accurate_.php?page=2">https://www.gamasutra.com</a> 3469 * 3470 * @param centerA 3471 * the coordinates of the first circle's center 3472 * @param moveA 3473 * the coordinates of the first circle's travelled distance vector 3474 * @param aR 3475 * the radius of the first circle 3476 * @param centerB 3477 * the coordinates of the second circle's center 3478 * @param bR 3479 * the radius of the second circle 3480 * @return <code>true</code> if both circle intersect; <code>false</code> otherwise 3481 */ 3482 public static bool testMovingCircleCircle(Vector2d centerA, Vector2d moveA, double aR, Vector2d centerB, double bR) { 3483 return testMovingCircleCircle(centerA.x, centerA.y, moveA.x, moveA.y, aR, centerB.x, centerB.y, bR); 3484 } 3485 3486 /** 3487 * Test whether the one circle with center <code>(aX, aY)</code> and square radius <code>radiusSquaredA</code> intersects the other 3488 * circle with center <code>(bX, bY)</code> and square radius <code>radiusSquaredB</code>, and store the center of the line segment of 3489 * intersection in the <code>(x, y)</code> components of the supplied vector and the half-length of that line segment in the z component. 3490 * <p> 3491 * This method returns <code>false</code> when one circle contains the other circle. 3492 * <p> 3493 * Reference: <a href="http://gamedev.stackexchange.com/questions/75756/sphere-sphere-intersection-and-circle-sphere-intersection">http://gamedev.stackexchange.com</a> 3494 * 3495 * @param aX 3496 * the x coordinate of the first circle's center 3497 * @param aY 3498 * the y coordinate of the first circle's center 3499 * @param radiusSquaredA 3500 * the square of the first circle's radius 3501 * @param bX 3502 * the x coordinate of the second circle's center 3503 * @param bY 3504 * the y coordinate of the second circle's center 3505 * @param radiusSquaredB 3506 * the square of the second circle's radius 3507 * @param intersectionCenterAndHL 3508 * will hold the center of the circle of intersection in the <code>(x, y, z)</code> components and the radius in the w component 3509 * @return <code>true</code> iff both circles intersect; <code>false</code> otherwise 3510 */ 3511 public static bool intersectCircleCircle(double aX, double aY, double radiusSquaredA, double bX, double bY, double radiusSquaredB, Vector3d intersectionCenterAndHL) { 3512 double dX = bX - aX, dY = bY - aY; 3513 double distSquared = dX * dX + dY * dY; 3514 double h = 0.5 + (radiusSquaredA - radiusSquaredB) / distSquared; 3515 double r_i = Math.sqrt(radiusSquaredA - h * h * distSquared); 3516 if (r_i >= 0.0) { 3517 intersectionCenterAndHL.x = aX + h * dX; 3518 intersectionCenterAndHL.y = aY + h * dY; 3519 intersectionCenterAndHL.z = r_i; 3520 return true; 3521 } 3522 return false; 3523 } 3524 3525 /** 3526 * Test whether the one circle with center <code>centerA</code> and square radius <code>radiusSquaredA</code> intersects the other 3527 * circle with center <code>centerB</code> and square radius <code>radiusSquaredB</code>, and store the center of the line segment of 3528 * intersection in the <code>(x, y)</code> components of the supplied vector and the half-length of that line segment in the z component. 3529 * <p> 3530 * This method returns <code>false</code> when one circle contains the other circle. 3531 * <p> 3532 * Reference: <a href="http://gamedev.stackexchange.com/questions/75756/sphere-sphere-intersection-and-circle-sphere-intersection">http://gamedev.stackexchange.com</a> 3533 * 3534 * @param centerA 3535 * the first circle's center 3536 * @param radiusSquaredA 3537 * the square of the first circle's radius 3538 * @param centerB 3539 * the second circle's center 3540 * @param radiusSquaredB 3541 * the square of the second circle's radius 3542 * @param intersectionCenterAndHL 3543 * will hold the center of the line segment of intersection in the <code>(x, y)</code> components and the half-length in the z component 3544 * @return <code>true</code> iff both circles intersect; <code>false</code> otherwise 3545 */ 3546 public static bool intersectCircleCircle(Vector2d centerA, double radiusSquaredA, Vector2d centerB, double radiusSquaredB, Vector3d intersectionCenterAndHL) { 3547 return intersectCircleCircle(centerA.x, centerA.y, radiusSquaredA, centerB.x, centerB.y, radiusSquaredB, intersectionCenterAndHL); 3548 } 3549 3550 /** 3551 * Test whether the one circle with center <code>(aX, aY)</code> and radius <code>rA</code> intersects the other circle with center <code>(bX, bY)</code> and radius <code>rB</code>. 3552 * <p> 3553 * This method returns <code>true</code> when one circle contains the other circle. 3554 * <p> 3555 * Reference: <a href="http://math.stackexchange.com/questions/275514/two-circles-overlap">http://math.stackexchange.com/</a> 3556 * 3557 * @param aX 3558 * the x coordinate of the first circle's center 3559 * @param aY 3560 * the y coordinate of the first circle's center 3561 * @param rA 3562 * the square of the first circle's radius 3563 * @param bX 3564 * the x coordinate of the second circle's center 3565 * @param bY 3566 * the y coordinate of the second circle's center 3567 * @param rB 3568 * the square of the second circle's radius 3569 * @return <code>true</code> iff both circles intersect; <code>false</code> otherwise 3570 */ 3571 public static bool testCircleCircle(double aX, double aY, double rA, double bX, double bY, double rB) { 3572 double d = (aX - bX) * (aX - bX) + (aY - bY) * (aY - bY); 3573 return d <= (rA + rB) * (rA + rB); 3574 } 3575 3576 /** 3577 * Test whether the one circle with center <code>centerA</code> and square radius <code>radiusSquaredA</code> intersects the other 3578 * circle with center <code>centerB</code> and square radius <code>radiusSquaredB</code>. 3579 * <p> 3580 * This method returns <code>true</code> when one circle contains the other circle. 3581 * <p> 3582 * Reference: <a href="http://gamedev.stackexchange.com/questions/75756/sphere-sphere-intersection-and-circle-sphere-intersection">http://gamedev.stackexchange.com</a> 3583 * 3584 * @param centerA 3585 * the first circle's center 3586 * @param radiusSquaredA 3587 * the square of the first circle's radius 3588 * @param centerB 3589 * the second circle's center 3590 * @param radiusSquaredB 3591 * the square of the second circle's radius 3592 * @return <code>true</code> iff both circles intersect; <code>false</code> otherwise 3593 */ 3594 public static bool testCircleCircle(Vector2d centerA, double radiusSquaredA, Vector2d centerB, double radiusSquaredB) { 3595 return testCircleCircle(centerA.x, centerA.y, radiusSquaredA, centerB.x, centerB.y, radiusSquaredB); 3596 } 3597 3598 /** 3599 * Determine the signed distance of the given point <code>(pointX, pointY)</code> to the line specified via its general plane equation 3600 * <i>a*x + b*y + c = 0</i>. 3601 * <p> 3602 * Reference: <a href="http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html">http://mathworld.wolfram.com</a> 3603 * 3604 * @param pointX 3605 * the x coordinate of the point 3606 * @param pointY 3607 * the y coordinate of the point 3608 * @param a 3609 * the x factor in the plane equation 3610 * @param b 3611 * the y factor in the plane equation 3612 * @param c 3613 * the constant in the plane equation 3614 * @return the distance between the point and the line 3615 */ 3616 public static double distancePointLine(double pointX, double pointY, double a, double b, double c) { 3617 double denom = Math.sqrt(a * a + b * b); 3618 return (a * pointX + b * pointY + c) / denom; 3619 } 3620 3621 /** 3622 * Determine the signed distance of the given point <code>(pointX, pointY)</code> to the line defined by the two points <code>(x0, y0)</code> and <code>(x1, y1)</code>. 3623 * <p> 3624 * Reference: <a href="http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html">http://mathworld.wolfram.com</a> 3625 * 3626 * @param pointX 3627 * the x coordinate of the point 3628 * @param pointY 3629 * the y coordinate of the point 3630 * @param x0 3631 * the x coordinate of the first point on the line 3632 * @param y0 3633 * the y coordinate of the first point on the line 3634 * @param x1 3635 * the x coordinate of the second point on the line 3636 * @param y1 3637 * the y coordinate of the second point on the line 3638 * @return the distance between the point and the line 3639 */ 3640 public static double distancePointLine(double pointX, double pointY, double x0, double y0, double x1, double y1) { 3641 double dx = x1 - x0; 3642 double dy = y1 - y0; 3643 double denom = Math.sqrt(dx * dx + dy * dy); 3644 return (dx * (y0 - pointY) - (x0 - pointX) * dy) / denom; 3645 } 3646 3647 /** 3648 * Compute the distance of the given point <code>(pX, pY, pZ)</code> to the line defined by the two points <code>(x0, y0, z0)</code> and <code>(x1, y1, z1)</code>. 3649 * <p> 3650 * Reference: <a href="http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html">http://mathworld.wolfram.com</a> 3651 * 3652 * @param pX 3653 * the x coordinate of the point 3654 * @param pY 3655 * the y coordinate of the point 3656 * @param pZ 3657 * the z coordinate of the point 3658 * @param x0 3659 * the x coordinate of the first point on the line 3660 * @param y0 3661 * the y coordinate of the first point on the line 3662 * @param z0 3663 * the z coordinate of the first point on the line 3664 * @param x1 3665 * the x coordinate of the second point on the line 3666 * @param y1 3667 * the y coordinate of the second point on the line 3668 * @param z1 3669 * the z coordinate of the second point on the line 3670 * @return the distance between the point and the line 3671 */ 3672 public static double distancePointLine(double pX, double pY, double pZ, 3673 double x0, double y0, double z0, double x1, double y1, double z1) { 3674 double d21x = x1 - x0, d21y = y1 - y0, d21z = z1 - z0; 3675 double d10x = x0 - pX, d10y = y0 - pY, d10z = z0 - pZ; 3676 double cx = d21y * d10z - d21z * d10y, cy = d21z * d10x - d21x * d10z, cz = d21x * d10y - d21y * d10x; 3677 return Math.sqrt((cx*cx + cy*cy + cz*cz) / (d21x*d21x + d21y*d21y + d21z*d21z)); 3678 } 3679 3680 /** 3681 * Test whether the ray with given origin <code>(originX, originY)</code> and direction <code>(dirX, dirY)</code> intersects the line 3682 * containing the given point <code>(pointX, pointY)</code> and having the normal <code>(normalX, normalY)</code>, and return the 3683 * value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point. 3684 * <p> 3685 * This method returns <code>-1.0</code> if the ray does not intersect the line, because it is either parallel to the line or its direction points 3686 * away from the line or the ray's origin is on the <i>negative</i> side of the line (i.e. the line's normal points away from the ray's origin). 3687 * 3688 * @param originX 3689 * the x coordinate of the ray's origin 3690 * @param originY 3691 * the y coordinate of the ray's origin 3692 * @param dirX 3693 * the x coordinate of the ray's direction 3694 * @param dirY 3695 * the y coordinate of the ray's direction 3696 * @param pointX 3697 * the x coordinate of a point on the line 3698 * @param pointY 3699 * the y coordinate of a point on the line 3700 * @param normalX 3701 * the x coordinate of the line's normal 3702 * @param normalY 3703 * the y coordinate of the line's normal 3704 * @param epsilon 3705 * some small epsilon for when the ray is parallel to the line 3706 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point, if the ray 3707 * intersects the line; <code>-1.0</code> otherwise 3708 */ 3709 public static double intersectRayLine(double originX, double originY, double dirX, double dirY, double pointX, double pointY, double normalX, double normalY, double epsilon) { 3710 double denom = normalX * dirX + normalY * dirY; 3711 if (denom < epsilon) { 3712 double t = ((pointX - originX) * normalX + (pointY - originY) * normalY) / denom; 3713 if (t >= 0.0) 3714 return t; 3715 } 3716 return -1.0; 3717 } 3718 3719 /** 3720 * Test whether the ray with given <code>origin</code> and direction <code>dir</code> intersects the line 3721 * containing the given <code>point</code> and having the given <code>normal</code>, and return the 3722 * value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point. 3723 * <p> 3724 * This method returns <code>-1.0</code> if the ray does not intersect the line, because it is either parallel to the line or its direction points 3725 * away from the line or the ray's origin is on the <i>negative</i> side of the line (i.e. the line's normal points away from the ray's origin). 3726 * 3727 * @param origin 3728 * the ray's origin 3729 * @param dir 3730 * the ray's direction 3731 * @param point 3732 * a point on the line 3733 * @param normal 3734 * the line's normal 3735 * @param epsilon 3736 * some small epsilon for when the ray is parallel to the line 3737 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point, if the ray 3738 * intersects the line; <code>-1.0</code> otherwise 3739 */ 3740 public static double intersectRayLine(Vector2d origin, Vector2d dir, Vector2d point, Vector2d normal, double epsilon) { 3741 return intersectRayLine(origin.x, origin.y, dir.x, dir.y, point.x, point.y, normal.x, normal.y, epsilon); 3742 } 3743 3744 /** 3745 * Determine whether the ray with given origin <code>(originX, originY)</code> and direction <code>(dirX, dirY)</code> intersects the undirected line segment 3746 * given by the two end points <code>(aX, bY)</code> and <code>(bX, bY)</code>, and return the value of the parameter <i>t</i> in the ray equation 3747 * <i>p(t) = origin + t * dir</i> of the intersection point, if any. 3748 * <p> 3749 * This method returns <code>-1.0</code> if the ray does not intersect the line segment. 3750 * 3751 * @see #intersectRayLineSegment(Vector2d, Vector2d, Vector2d, Vector2d) 3752 * 3753 * @param originX 3754 * the x coordinate of the ray's origin 3755 * @param originY 3756 * the y coordinate of the ray's origin 3757 * @param dirX 3758 * the x coordinate of the ray's direction 3759 * @param dirY 3760 * the y coordinate of the ray's direction 3761 * @param aX 3762 * the x coordinate of the line segment's first end point 3763 * @param aY 3764 * the y coordinate of the line segment's first end point 3765 * @param bX 3766 * the x coordinate of the line segment's second end point 3767 * @param bY 3768 * the y coordinate of the line segment's second end point 3769 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point, if the ray 3770 * intersects the line segment; <code>-1.0</code> otherwise 3771 */ 3772 public static double intersectRayLineSegment(double originX, double originY, double dirX, double dirY, double aX, double aY, double bX, double bY) { 3773 double v1X = originX - aX; 3774 double v1Y = originY - aY; 3775 double v2X = bX - aX; 3776 double v2Y = bY - aY; 3777 double invV23 = 1.0 / (v2Y * dirX - v2X * dirY); 3778 double t1 = (v2X * v1Y - v2Y * v1X) * invV23; 3779 double t2 = (v1Y * dirX - v1X * dirY) * invV23; 3780 if (t1 >= 0.0 && t2 >= 0.0 && t2 <= 1.0) 3781 return t1; 3782 return -1.0; 3783 } 3784 3785 /** 3786 * Determine whether the ray with given <code>origin</code> and direction <code>dir</code> intersects the undirected line segment 3787 * given by the two end points <code>a</code> and <code>b</code>, and return the value of the parameter <i>t</i> in the ray equation 3788 * <i>p(t) = origin + t * dir</i> of the intersection point, if any. 3789 * <p> 3790 * This method returns <code>-1.0</code> if the ray does not intersect the line segment. 3791 * 3792 * @see #intersectRayLineSegment(double, double, double, double, double, double, double, double) 3793 * 3794 * @param origin 3795 * the ray's origin 3796 * @param dir 3797 * the ray's direction 3798 * @param a 3799 * the line segment's first end point 3800 * @param b 3801 * the line segment's second end point 3802 * @return the value of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the intersection point, if the ray 3803 * intersects the line segment; <code>-1.0</code> otherwise 3804 */ 3805 public static double intersectRayLineSegment(Vector2d origin, Vector2d dir, Vector2d a, Vector2d b) { 3806 return intersectRayLineSegment(origin.x, origin.y, dir.x, dir.y, a.x, a.y, b.x, b.y); 3807 } 3808 3809 /** 3810 * Test whether the axis-aligned rectangle with minimum corner <code>(minX, minY)</code> and maximum corner <code>(maxX, maxY)</code> 3811 * intersects the circle with the given center <code>(centerX, centerY)</code> and square radius <code>radiusSquared</code>. 3812 * <p> 3813 * Reference: <a href="http://stackoverflow.com/questions/4578967/cube-sphere-intersection-test#answer-4579069">http://stackoverflow.com</a> 3814 * 3815 * @param minX 3816 * the x coordinate of the minimum corner of the axis-aligned rectangle 3817 * @param minY 3818 * the y coordinate of the minimum corner of the axis-aligned rectangle 3819 * @param maxX 3820 * the x coordinate of the maximum corner of the axis-aligned rectangle 3821 * @param maxY 3822 * the y coordinate of the maximum corner of the axis-aligned rectangle 3823 * @param centerX 3824 * the x coordinate of the circle's center 3825 * @param centerY 3826 * the y coordinate of the circle's center 3827 * @param radiusSquared 3828 * the square of the circle's radius 3829 * @return <code>true</code> iff the axis-aligned rectangle intersects the circle; <code>false</code> otherwise 3830 */ 3831 public static bool testAarCircle(double minX, double minY, double maxX, double maxY, double centerX, double centerY, double radiusSquared) { 3832 double radius2 = radiusSquared; 3833 if (centerX < minX) { 3834 double d = (centerX - minX); 3835 radius2 -= d * d; 3836 } else if (centerX > maxX) { 3837 double d = (centerX - maxX); 3838 radius2 -= d * d; 3839 } 3840 if (centerY < minY) { 3841 double d = (centerY - minY); 3842 radius2 -= d * d; 3843 } else if (centerY > maxY) { 3844 double d = (centerY - maxY); 3845 radius2 -= d * d; 3846 } 3847 return radius2 >= 0.0; 3848 } 3849 3850 /** 3851 * Test whether the axis-aligned rectangle with minimum corner <code>min</code> and maximum corner <code>max</code> 3852 * intersects the circle with the given <code>center</code> and square radius <code>radiusSquared</code>. 3853 * <p> 3854 * Reference: <a href="http://stackoverflow.com/questions/4578967/cube-sphere-intersection-test#answer-4579069">http://stackoverflow.com</a> 3855 * 3856 * @param min 3857 * the minimum corner of the axis-aligned rectangle 3858 * @param max 3859 * the maximum corner of the axis-aligned rectangle 3860 * @param center 3861 * the circle's center 3862 * @param radiusSquared 3863 * the squared of the circle's radius 3864 * @return <code>true</code> iff the axis-aligned rectangle intersects the circle; <code>false</code> otherwise 3865 */ 3866 public static bool testAarCircle(Vector2d min, Vector2d max, Vector2d center, double radiusSquared) { 3867 return testAarCircle(min.x, min.y, max.x, max.y, center.x, center.y, radiusSquared); 3868 } 3869 3870 /** 3871 * Determine the closest point on the triangle with the given vertices <code>(v0X, v0Y)</code>, <code>(v1X, v1Y)</code>, <code>(v2X, v2Y)</code> 3872 * between that triangle and the given point <code>(pX, pY)</code> and store that point into the given <code>result</code>. 3873 * <p> 3874 * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2}) 3875 * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20}) 3876 * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle. 3877 * <p> 3878 * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point" 3879 * 3880 * @param v0X 3881 * the x coordinate of the first vertex of the triangle 3882 * @param v0Y 3883 * the y coordinate of the first vertex of the triangle 3884 * @param v1X 3885 * the x coordinate of the second vertex of the triangle 3886 * @param v1Y 3887 * the y coordinate of the second vertex of the triangle 3888 * @param v2X 3889 * the x coordinate of the third vertex of the triangle 3890 * @param v2Y 3891 * the y coordinate of the third vertex of the triangle 3892 * @param pX 3893 * the x coordinate of the point 3894 * @param pY 3895 * the y coordinate of the point 3896 * @param result 3897 * will hold the closest point 3898 * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2}, 3899 * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or 3900 * {@link #POINT_ON_TRIANGLE_FACE} 3901 */ 3902 public static int findClosestPointOnTriangle(double v0X, double v0Y, double v1X, double v1Y, double v2X, double v2Y, double pX, double pY, Vector2d result) { 3903 double abX = v1X - v0X, abY = v1Y - v0Y; 3904 double acX = v2X - v0X, acY = v2Y - v0Y; 3905 double apX = pX - v0X, apY = pY - v0Y; 3906 double d1 = abX * apX + abY * apY; 3907 double d2 = acX * apX + acY * apY; 3908 if (d1 <= 0.0 && d2 <= 0.0) { 3909 result.x = v0X; 3910 result.y = v0Y; 3911 return POINT_ON_TRIANGLE_VERTEX_0; 3912 } 3913 double bpX = pX - v1X, bpY = pY - v1Y; 3914 double d3 = abX * bpX + abY * bpY; 3915 double d4 = acX * bpX + acY * bpY; 3916 if (d3 >= 0.0 && d4 <= d3) { 3917 result.x = v1X; 3918 result.y = v1Y; 3919 return POINT_ON_TRIANGLE_VERTEX_1; 3920 } 3921 double vc = d1 * d4 - d3 * d2; 3922 if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) { 3923 double v = d1 / (d1 - d3); 3924 result.x = v0X + v * abX; 3925 result.y = v0Y + v * abY; 3926 return POINT_ON_TRIANGLE_EDGE_01; 3927 } 3928 double cpX = pX - v2X, cpY = pY - v2Y; 3929 double d5 = abX * cpX + abY * cpY; 3930 double d6 = acX * cpX + acY * cpY; 3931 if (d6 >= 0.0 && d5 <= d6) { 3932 result.x = v2X; 3933 result.y = v2Y; 3934 return POINT_ON_TRIANGLE_VERTEX_2; 3935 } 3936 double vb = d5 * d2 - d1 * d6; 3937 if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) { 3938 double w = d2 / (d2 - d6); 3939 result.x = v0X + w * acX; 3940 result.y = v0Y + w * acY; 3941 return POINT_ON_TRIANGLE_EDGE_20; 3942 } 3943 double va = d3 * d6 - d5 * d4; 3944 if (va <= 0.0 && d4 - d3 >= 0.0 && d5 - d6 >= 0.0) { 3945 double w = (d4 - d3) / (d4 - d3 + d5 - d6); 3946 result.x = v1X + w * (v2X - v1X); 3947 result.y = v1Y + w * (v2Y - v1Y); 3948 return POINT_ON_TRIANGLE_EDGE_12; 3949 } 3950 double denom = 1.0 / (va + vb + vc); 3951 double v = vb * denom; 3952 double w = vc * denom; 3953 result.x = v0X + abX * v + acX * w; 3954 result.y = v0Y + abY * v + acY * w; 3955 return POINT_ON_TRIANGLE_FACE; 3956 } 3957 3958 /** 3959 * Determine the closest point on the triangle with the vertices <code>v0</code>, <code>v1</code>, <code>v2</code> 3960 * between that triangle and the given point <code>p</code> and store that point into the given <code>result</code>. 3961 * <p> 3962 * Additionally, this method returns whether the closest point is a vertex ({@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2}) 3963 * of the triangle, lies on an edge ({@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20}) 3964 * or on the {@link #POINT_ON_TRIANGLE_FACE face} of the triangle. 3965 * <p> 3966 * Reference: Book "Real-Time Collision Detection" chapter 5.1.5 "Closest Point on Triangle to Point" 3967 * 3968 * @param v0 3969 * the first vertex of the triangle 3970 * @param v1 3971 * the second vertex of the triangle 3972 * @param v2 3973 * the third vertex of the triangle 3974 * @param p 3975 * the point 3976 * @param result 3977 * will hold the closest point 3978 * @return one of {@link #POINT_ON_TRIANGLE_VERTEX_0}, {@link #POINT_ON_TRIANGLE_VERTEX_1}, {@link #POINT_ON_TRIANGLE_VERTEX_2}, 3979 * {@link #POINT_ON_TRIANGLE_EDGE_01}, {@link #POINT_ON_TRIANGLE_EDGE_12}, {@link #POINT_ON_TRIANGLE_EDGE_20} or 3980 * {@link #POINT_ON_TRIANGLE_FACE} 3981 */ 3982 public static int findClosestPointOnTriangle(Vector2d v0, Vector2d v1, Vector2d v2, Vector2d p, Vector2d result) { 3983 return findClosestPointOnTriangle(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y, p.x, p.y, result); 3984 } 3985 3986 /** 3987 * Test whether the given ray with the origin <code>(originX, originY)</code> and direction <code>(dirX, dirY)</code> 3988 * intersects the given circle with center <code>(centerX, centerY)</code> and square radius <code>radiusSquared</code>, 3989 * and store the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> for both points (near 3990 * and far) of intersections into the given <code>result</code> vector. 3991 * <p> 3992 * This method returns <code>true</code> for a ray whose origin lies inside the circle. 3993 * <p> 3994 * Reference: <a href="http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection">http://www.scratchapixel.com/</a> 3995 * 3996 * @param originX 3997 * the x coordinate of the ray's origin 3998 * @param originY 3999 * the y coordinate of the ray's origin 4000 * @param dirX 4001 * the x coordinate of the ray's direction 4002 * @param dirY 4003 * the y coordinate of the ray's direction 4004 * @param centerX 4005 * the x coordinate of the circle's center 4006 * @param centerY 4007 * the y coordinate of the circle's center 4008 * @param radiusSquared 4009 * the circle radius squared 4010 * @param result 4011 * a vector that will contain the values of the parameter <i>t</i> in the ray equation 4012 * <i>p(t) = origin + t * dir</i> for both points (near, far) of intersections with the circle 4013 * @return <code>true</code> if the ray intersects the circle; <code>false</code> otherwise 4014 */ 4015 public static bool intersectRayCircle(double originX, double originY, double dirX, double dirY, 4016 double centerX, double centerY, double radiusSquared, Vector2d result) { 4017 double Lx = centerX - originX; 4018 double Ly = centerY - originY; 4019 double tca = Lx * dirX + Ly * dirY; 4020 double d2 = Lx * Lx + Ly * Ly - tca * tca; 4021 if (d2 > radiusSquared) 4022 return false; 4023 double thc = Math.sqrt(radiusSquared - d2); 4024 double t0 = tca - thc; 4025 double t1 = tca + thc; 4026 if (t0 < t1 && t1 >= 0.0) { 4027 result.x = t0; 4028 result.y = t1; 4029 return true; 4030 } 4031 return false; 4032 } 4033 4034 /** 4035 * Test whether the ray with the given <code>origin</code> and direction <code>dir</code> 4036 * intersects the circle with the given <code>center</code> and square radius <code>radiusSquared</code>, 4037 * and store the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> for both points (near 4038 * and far) of intersections into the given <code>result</code> vector. 4039 * <p> 4040 * This method returns <code>true</code> for a ray whose origin lies inside the circle. 4041 * <p> 4042 * Reference: <a href="http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection">http://www.scratchapixel.com/</a> 4043 * 4044 * @param origin 4045 * the ray's origin 4046 * @param dir 4047 * the ray's direction 4048 * @param center 4049 * the circle's center 4050 * @param radiusSquared 4051 * the circle radius squared 4052 * @param result 4053 * a vector that will contain the values of the parameter <i>t</i> in the ray equation 4054 * <i>p(t) = origin + t * dir</i> for both points (near, far) of intersections with the circle 4055 * @return <code>true</code> if the ray intersects the circle; <code>false</code> otherwise 4056 */ 4057 public static bool intersectRayCircle(Vector2d origin, Vector2d dir, Vector2d center, double radiusSquared, Vector2d result) { 4058 return intersectRayCircle(origin.x, origin.y, dir.x, dir.y, center.x, center.y, radiusSquared, result); 4059 } 4060 4061 /** 4062 * Test whether the given ray with the origin <code>(originX, originY)</code> and direction <code>(dirX, dirY)</code> 4063 * intersects the given circle with center <code>(centerX, centerY)</code> and square radius <code>radiusSquared</code>. 4064 * <p> 4065 * This method returns <code>true</code> for a ray whose origin lies inside the circle. 4066 * <p> 4067 * Reference: <a href="http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection">http://www.scratchapixel.com/</a> 4068 * 4069 * @param originX 4070 * the x coordinate of the ray's origin 4071 * @param originY 4072 * the y coordinate of the ray's origin 4073 * @param dirX 4074 * the x coordinate of the ray's direction 4075 * @param dirY 4076 * the y coordinate of the ray's direction 4077 * @param centerX 4078 * the x coordinate of the circle's center 4079 * @param centerY 4080 * the y coordinate of the circle's center 4081 * @param radiusSquared 4082 * the circle radius squared 4083 * @return <code>true</code> if the ray intersects the circle; <code>false</code> otherwise 4084 */ 4085 public static bool testRayCircle(double originX, double originY, double dirX, double dirY, 4086 double centerX, double centerY, double radiusSquared) { 4087 double Lx = centerX - originX; 4088 double Ly = centerY - originY; 4089 double tca = Lx * dirX + Ly * dirY; 4090 double d2 = Lx * Lx + Ly * Ly - tca * tca; 4091 if (d2 > radiusSquared) 4092 return false; 4093 double thc = Math.sqrt(radiusSquared - d2); 4094 double t0 = tca - thc; 4095 double t1 = tca + thc; 4096 return t0 < t1 && t1 >= 0.0; 4097 } 4098 4099 /** 4100 * Test whether the ray with the given <code>origin</code> and direction <code>dir</code> 4101 * intersects the circle with the given <code>center</code> and square radius. 4102 * <p> 4103 * This method returns <code>true</code> for a ray whose origin lies inside the circle. 4104 * <p> 4105 * Reference: <a href="http://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection">http://www.scratchapixel.com/</a> 4106 * 4107 * @param origin 4108 * the ray's origin 4109 * @param dir 4110 * the ray's direction 4111 * @param center 4112 * the circle's center 4113 * @param radiusSquared 4114 * the circle radius squared 4115 * @return <code>true</code> if the ray intersects the circle; <code>false</code> otherwise 4116 */ 4117 public static bool testRayCircle(Vector2d origin, Vector2d dir, Vector2d center, double radiusSquared) { 4118 return testRayCircle(origin.x, origin.y, dir.x, dir.y, center.x, center.y, radiusSquared); 4119 } 4120 4121 /** 4122 * Determine whether the given ray with the origin <code>(originX, originY)</code> and direction <code>(dirX, dirY)</code> 4123 * intersects the axis-aligned rectangle given as its minimum corner <code>(minX, minY)</code> and maximum corner <code>(maxX, maxY)</code>, 4124 * and return the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the near and far point of intersection 4125 * as well as the side of the axis-aligned rectangle the ray intersects. 4126 * <p> 4127 * This method also detects an intersection for a ray whose origin lies inside the axis-aligned rectangle. 4128 * <p> 4129 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 4130 * 4131 * @see #intersectRayAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d) 4132 * 4133 * @param originX 4134 * the x coordinate of the ray's origin 4135 * @param originY 4136 * the y coordinate of the ray's origin 4137 * @param dirX 4138 * the x coordinate of the ray's direction 4139 * @param dirY 4140 * the y coordinate of the ray's direction 4141 * @param minX 4142 * the x coordinate of the minimum corner of the axis-aligned rectangle 4143 * @param minY 4144 * the y coordinate of the minimum corner of the axis-aligned rectangle 4145 * @param maxX 4146 * the x coordinate of the maximum corner of the axis-aligned rectangle 4147 * @param maxY 4148 * the y coordinate of the maximum corner of the axis-aligned rectangle 4149 * @param result 4150 * a vector which will hold the values of the parameter <i>t</i> in the ray equation 4151 * <i>p(t) = origin + t * dir</i> of the near and far point of intersection 4152 * @return the side on which the near intersection occurred as one of 4153 * {@link #AAR_SIDE_MINX}, {@link #AAR_SIDE_MINY}, {@link #AAR_SIDE_MAXX} or {@link #AAR_SIDE_MAXY}; 4154 * or <code>-1</code> if the ray does not intersect the axis-aligned rectangle; 4155 */ 4156 public static int intersectRayAar(double originX, double originY, double dirX, double dirY, 4157 double minX, double minY, double maxX, double maxY, Vector2d result) { 4158 double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY; 4159 double tNear, tFar, tymin, tymax; 4160 if (invDirX >= 0.0) { 4161 tNear = (minX - originX) * invDirX; 4162 tFar = (maxX - originX) * invDirX; 4163 } else { 4164 tNear = (maxX - originX) * invDirX; 4165 tFar = (minX - originX) * invDirX; 4166 } 4167 if (invDirY >= 0.0) { 4168 tymin = (minY - originY) * invDirY; 4169 tymax = (maxY - originY) * invDirY; 4170 } else { 4171 tymin = (maxY - originY) * invDirY; 4172 tymax = (minY - originY) * invDirY; 4173 } 4174 if (tNear > tymax || tymin > tFar) 4175 return OUTSIDE; 4176 tNear = tymin > tNear || isNaN(tNear) ? tymin : tNear; 4177 tFar = tymax < tFar || isNaN(tFar) ? tymax : tFar; 4178 int side = -1; // no intersection side 4179 if (tNear < tFar && tFar >= 0.0) { 4180 double px = originX + tNear * dirX; 4181 double py = originY + tNear * dirY; 4182 result.x = tNear; 4183 result.y = tFar; 4184 double daX = Math.abs(px - minX); 4185 double daY = Math.abs(py - minY); 4186 double dbX = Math.abs(px - maxX); 4187 double dbY = Math.abs(py - maxY); 4188 side = 0; // min x coordinate 4189 double min = daX; 4190 if (daY < min) { 4191 min = daY; 4192 side = 1; // min y coordinate 4193 } 4194 if (dbX < min) { 4195 min = dbX; 4196 side = 2; // max xcoordinate 4197 } 4198 if (dbY < min) 4199 side = 3; // max y coordinate 4200 } 4201 return side; 4202 } 4203 4204 /** 4205 * Determine whether the given ray with the given <code>origin</code> and direction <code>dir</code> 4206 * intersects the axis-aligned rectangle given as its minimum corner <code>min</code> and maximum corner <code>max</code>, 4207 * and return the values of the parameter <i>t</i> in the ray equation <i>p(t) = origin + t * dir</i> of the near and far point of intersection 4208 * as well as the side of the axis-aligned rectangle the ray intersects. 4209 * <p> 4210 * This method also detects an intersection for a ray whose origin lies inside the axis-aligned rectangle. 4211 * <p> 4212 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 4213 * 4214 * @see #intersectRayAar(double, double, double, double, double, double, double, double, Vector2d) 4215 * 4216 * @param origin 4217 * the ray's origin 4218 * @param dir 4219 * the ray's direction 4220 * @param min 4221 * the minimum corner of the axis-aligned rectangle 4222 * @param max 4223 * the maximum corner of the axis-aligned rectangle 4224 * @param result 4225 * a vector which will hold the values of the parameter <i>t</i> in the ray equation 4226 * <i>p(t) = origin + t * dir</i> of the near and far point of intersection 4227 * @return the side on which the near intersection occurred as one of 4228 * {@link #AAR_SIDE_MINX}, {@link #AAR_SIDE_MINY}, {@link #AAR_SIDE_MAXX} or {@link #AAR_SIDE_MAXY}; 4229 * or <code>-1</code> if the ray does not intersect the axis-aligned rectangle; 4230 */ 4231 public static int intersectRayAar(Vector2d origin, Vector2d dir, Vector2d min, Vector2d max, Vector2d result) { 4232 return intersectRayAar(origin.x, origin.y, dir.x, dir.y, min.x, min.y, max.x, max.y, result); 4233 } 4234 4235 /** 4236 * Determine whether the undirected line segment with the end points <code>(p0X, p0Y)</code> and <code>(p1X, p1Y)</code> 4237 * intersects the axis-aligned rectangle given as its minimum corner <code>(minX, minY)</code> and maximum corner <code>(maxX, maxY)</code>, 4238 * and store the values of the parameter <i>t</i> in the ray equation <i>p(t) = p0 + t * (p1 - p0)</i> of the near and far point of intersection 4239 * into <code>result</code>. 4240 * <p> 4241 * This method also detects an intersection of a line segment whose either end point lies inside the axis-aligned rectangle. 4242 * <p> 4243 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 4244 * 4245 * @see #intersectLineSegmentAar(Vector2d, Vector2d, Vector2d, Vector2d, Vector2d) 4246 * 4247 * @param p0X 4248 * the x coordinate of the line segment's first end point 4249 * @param p0Y 4250 * the y coordinate of the line segment's first end point 4251 * @param p1X 4252 * the x coordinate of the line segment's second end point 4253 * @param p1Y 4254 * the y coordinate of the line segment's second end point 4255 * @param minX 4256 * the x coordinate of the minimum corner of the axis-aligned rectangle 4257 * @param minY 4258 * the y coordinate of the minimum corner of the axis-aligned rectangle 4259 * @param maxX 4260 * the x coordinate of the maximum corner of the axis-aligned rectangle 4261 * @param maxY 4262 * the y coordinate of the maximum corner of the axis-aligned rectangle 4263 * @param result 4264 * a vector which will hold the values of the parameter <i>t</i> in the ray equation 4265 * <i>p(t) = p0 + t * (p1 - p0)</i> of the near and far point of intersection 4266 * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned rectangle; or 4267 * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned rectangle; or 4268 * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned rectangle; or 4269 * {@link #TWO_INTERSECTION} if the line segment intersects two edges of the axis-aligned rectangle or lies on one edge of the rectangle 4270 */ 4271 public static int intersectLineSegmentAar(double p0X, double p0Y, double p1X, double p1Y, 4272 double minX, double minY, double maxX, double maxY, Vector2d result) { 4273 double dirX = p1X - p0X, dirY = p1Y - p0Y; 4274 double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY; 4275 double tNear, tFar, tymin, tymax; 4276 if (invDirX >= 0.0) { 4277 tNear = (minX - p0X) * invDirX; 4278 tFar = (maxX - p0X) * invDirX; 4279 } else { 4280 tNear = (maxX - p0X) * invDirX; 4281 tFar = (minX - p0X) * invDirX; 4282 } 4283 if (invDirY >= 0.0) { 4284 tymin = (minY - p0Y) * invDirY; 4285 tymax = (maxY - p0Y) * invDirY; 4286 } else { 4287 tymin = (maxY - p0Y) * invDirY; 4288 tymax = (minY - p0Y) * invDirY; 4289 } 4290 if (tNear > tymax || tymin > tFar) 4291 return OUTSIDE; 4292 tNear = tymin > tNear || isNaN(tNear) ? tymin : tNear; 4293 tFar = tymax < tFar || isNaN(tFar) ? tymax : tFar; 4294 int type = OUTSIDE; 4295 if (tNear <= tFar && tNear <= 1.0f && tFar >= 0.0f) { 4296 if (tNear >= 0.0f && tFar > 1.0f) { 4297 tFar = tNear; 4298 type = ONE_INTERSECTION; 4299 } else if (tNear < 0.0f && tFar <= 1.0f) { 4300 tNear = tFar; 4301 type = ONE_INTERSECTION; 4302 } else if (tNear < 0.0f && tFar > 1.0f) { 4303 type = INSIDE; 4304 } else { 4305 type = TWO_INTERSECTION; 4306 } 4307 result.x = tNear; 4308 result.y = tFar; 4309 } 4310 return type; 4311 } 4312 4313 /** 4314 * Determine whether the undirected line segment with the end points <code>p0</code> and <code>p1</code> 4315 * intersects the axis-aligned rectangle given as its minimum corner <code>min</code> and maximum corner <code>max</code>, 4316 * and store the values of the parameter <i>t</i> in the ray equation <i>p(t) = p0 + t * (p1 - p0)</i> of the near and far point of intersection 4317 * into <code>result</code>. 4318 * <p> 4319 * This method also detects an intersection of a line segment whose either end point lies inside the axis-aligned rectangle. 4320 * <p> 4321 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 4322 * 4323 * #see {@link #intersectLineSegmentAar(double, double, double, double, double, double, double, double, Vector2d)} 4324 * 4325 * @param p0 4326 * the line segment's first end point 4327 * @param p1 4328 * the line segment's second end point 4329 * @param min 4330 * the minimum corner of the axis-aligned rectangle 4331 * @param max 4332 * the maximum corner of the axis-aligned rectangle 4333 * @param result 4334 * a vector which will hold the values of the parameter <i>t</i> in the ray equation 4335 * <i>p(t) = p0 + t * (p1 - p0)</i> of the near and far point of intersection 4336 * @return {@link #INSIDE} if the line segment lies completely inside of the axis-aligned rectangle; or 4337 * {@link #OUTSIDE} if the line segment lies completely outside of the axis-aligned rectangle; or 4338 * {@link #ONE_INTERSECTION} if one of the end points of the line segment lies inside of the axis-aligned rectangle; or 4339 * {@link #TWO_INTERSECTION} if the line segment intersects two edges of the axis-aligned rectangle 4340 */ 4341 public static int intersectLineSegmentAar(Vector2d p0, Vector2d p1, Vector2d min, Vector2d max, Vector2d result) { 4342 return intersectLineSegmentAar(p0.x, p0.y, p1.x, p1.y, min.x, min.y, max.x, max.y, result); 4343 } 4344 4345 /** 4346 * Test whether the given ray with the origin <code>(originX, originY)</code> and direction <code>(dirX, dirY)</code> 4347 * intersects the given axis-aligned rectangle given as its minimum corner <code>(minX, minY)</code> and maximum corner <code>(maxX, maxY)</code>. 4348 * <p> 4349 * This method returns <code>true</code> for a ray whose origin lies inside the axis-aligned rectangle. 4350 * <p> 4351 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 4352 * 4353 * @see #testRayAar(Vector2d, Vector2d, Vector2d, Vector2d) 4354 * 4355 * @param originX 4356 * the x coordinate of the ray's origin 4357 * @param originY 4358 * the y coordinate of the ray's origin 4359 * @param dirX 4360 * the x coordinate of the ray's direction 4361 * @param dirY 4362 * the y coordinate of the ray's direction 4363 * @param minX 4364 * the x coordinate of the minimum corner of the axis-aligned rectangle 4365 * @param minY 4366 * the y coordinate of the minimum corner of the axis-aligned rectangle 4367 * @param maxX 4368 * the x coordinate of the maximum corner of the axis-aligned rectangle 4369 * @param maxY 4370 * the y coordinate of the maximum corner of the axis-aligned rectangle 4371 * @return <code>true</code> if the given ray intersects the axis-aligned rectangle; <code>false</code> otherwise 4372 */ 4373 public static bool testRayAar(double originX, double originY, double dirX, double dirY, double minX, double minY, double maxX, double maxY) { 4374 double invDirX = 1.0 / dirX, invDirY = 1.0 / dirY; 4375 double tNear, tFar, tymin, tymax; 4376 if (invDirX >= 0.0) { 4377 tNear = (minX - originX) * invDirX; 4378 tFar = (maxX - originX) * invDirX; 4379 } else { 4380 tNear = (maxX - originX) * invDirX; 4381 tFar = (minX - originX) * invDirX; 4382 } 4383 if (invDirY >= 0.0) { 4384 tymin = (minY - originY) * invDirY; 4385 tymax = (maxY - originY) * invDirY; 4386 } else { 4387 tymin = (maxY - originY) * invDirY; 4388 tymax = (minY - originY) * invDirY; 4389 } 4390 if (tNear > tymax || tymin > tFar) 4391 return false; 4392 tNear = tymin > tNear || isNaN(tNear) ? tymin : tNear; 4393 tFar = tymax < tFar || isNaN(tFar) ? tymax : tFar; 4394 return tNear < tFar && tFar >= 0.0; 4395 } 4396 4397 /** 4398 * Test whether the ray with the given <code>origin</code> and direction <code>dir</code> 4399 * intersects the given axis-aligned rectangle specified as its minimum corner <code>min</code> and maximum corner <code>max</code>. 4400 * <p> 4401 * This method returns <code>true</code> for a ray whose origin lies inside the axis-aligned rectangle. 4402 * <p> 4403 * Reference: <a href="https://dl.acm.org/citation.cfm?id=1198748">An Efficient and Robust Ray–Box Intersection</a> 4404 * 4405 * @see #testRayAar(double, double, double, double, double, double, double, double) 4406 * 4407 * @param origin 4408 * the ray's origin 4409 * @param dir 4410 * the ray's direction 4411 * @param min 4412 * the minimum corner of the axis-aligned rectangle 4413 * @param max 4414 * the maximum corner of the axis-aligned rectangle 4415 * @return <code>true</code> if the given ray intersects the axis-aligned rectangle; <code>false</code> otherwise 4416 */ 4417 public static bool testRayAar(Vector2d origin, Vector2d dir, Vector2d min, Vector2d max) { 4418 return testRayAar(origin.x, origin.y, dir.x, dir.y, min.x, min.y, max.x, max.y); 4419 } 4420 4421 /** 4422 * Test whether the given point <code>(pX, pY)</code> lies inside the triangle with the vertices <code>(v0X, v0Y)</code>, <code>(v1X, v1Y)</code>, <code>(v2X, v2Y)</code>. 4423 * 4424 * @param pX 4425 * the x coordinate of the point 4426 * @param pY 4427 * the y coordinate of the point 4428 * @param v0X 4429 * the x coordinate of the first vertex of the triangle 4430 * @param v0Y 4431 * the y coordinate of the first vertex of the triangle 4432 * @param v1X 4433 * the x coordinate of the second vertex of the triangle 4434 * @param v1Y 4435 * the y coordinate of the second vertex of the triangle 4436 * @param v2X 4437 * the x coordinate of the third vertex of the triangle 4438 * @param v2Y 4439 * the y coordinate of the third vertex of the triangle 4440 * @return <code>true</code> iff the point lies inside the triangle; <code>false</code> otherwise 4441 */ 4442 public static bool testPointTriangle(double pX, double pY, double v0X, double v0Y, double v1X, double v1Y, double v2X, double v2Y) { 4443 bool b1 = (pX - v1X) * (v0Y - v1Y) - (v0X - v1X) * (pY - v1Y) < 0.0; 4444 bool b2 = (pX - v2X) * (v1Y - v2Y) - (v1X - v2X) * (pY - v2Y) < 0.0; 4445 if (b1 != b2) 4446 return false; 4447 bool b3 = (pX - v0X) * (v2Y - v0Y) - (v2X - v0X) * (pY - v0Y) < 0.0; 4448 return b2 == b3; 4449 } 4450 4451 /** 4452 * Test whether the given <code>point</code> lies inside the triangle with the vertices <code>v0</code>, <code>v1</code>, <code>v2</code>. 4453 * 4454 * @param v0 4455 * the first vertex of the triangle 4456 * @param v1 4457 * the second vertex of the triangle 4458 * @param v2 4459 * the third vertex of the triangle 4460 * @param point 4461 * the point 4462 * @return <code>true</code> iff the point lies inside the triangle; <code>false</code> otherwise 4463 */ 4464 public static bool testPointTriangle(Vector2d point, Vector2d v0, Vector2d v1, Vector2d v2) { 4465 return testPointTriangle(point.x, point.y, v0.x, v0.y, v1.x, v1.y, v2.x, v2.y); 4466 } 4467 4468 /** 4469 * Test whether the given point <code>(pX, pY)</code> lies inside the axis-aligned rectangle with the minimum corner <code>(minX, minY)</code> 4470 * and maximum corner <code>(maxX, maxY)</code>. 4471 * 4472 * @param pX 4473 * the x coordinate of the point 4474 * @param pY 4475 * the y coordinate of the point 4476 * @param minX 4477 * the x coordinate of the minimum corner of the axis-aligned rectangle 4478 * @param minY 4479 * the y coordinate of the minimum corner of the axis-aligned rectangle 4480 * @param maxX 4481 * the x coordinate of the maximum corner of the axis-aligned rectangle 4482 * @param maxY 4483 * the y coordinate of the maximum corner of the axis-aligned rectangle 4484 * @return <code>true</code> iff the point lies inside the axis-aligned rectangle; <code>false</code> otherwise 4485 */ 4486 public static bool testPointAar(double pX, double pY, double minX, double minY, double maxX, double maxY) { 4487 return pX >= minX && pY >= minY && pX <= maxX && pY <= maxY; 4488 } 4489 4490 /** 4491 * Test whether the point <code>(pX, pY)</code> lies inside the circle with center <code>(centerX, centerY)</code> and square radius <code>radiusSquared</code>. 4492 * 4493 * @param pX 4494 * the x coordinate of the point 4495 * @param pY 4496 * the y coordinate of the point 4497 * @param centerX 4498 * the x coordinate of the circle's center 4499 * @param centerY 4500 * the y coordinate of the circle's center 4501 * @param radiusSquared 4502 * the square radius of the circle 4503 * @return <code>true</code> iff the point lies inside the circle; <code>false</code> otherwise 4504 */ 4505 public static bool testPointCircle(double pX, double pY, double centerX, double centerY, double radiusSquared) { 4506 double dx = pX - centerX; 4507 double dy = pY - centerY; 4508 double dx2 = dx * dx; 4509 double dy2 = dy * dy; 4510 return dx2 + dy2 <= radiusSquared; 4511 } 4512 4513 /** 4514 * Test whether the circle with center <code>(centerX, centerY)</code> and square radius <code>radiusSquared</code> intersects the triangle with counter-clockwise vertices 4515 * <code>(v0X, v0Y)</code>, <code>(v1X, v1Y)</code>, <code>(v2X, v2Y)</code>. 4516 * <p> 4517 * The vertices of the triangle must be specified in counter-clockwise order. 4518 * <p> 4519 * Reference: <a href="http://www.phatcode.net/articles.php?id=459">http://www.phatcode.net/</a> 4520 * 4521 * @param centerX 4522 * the x coordinate of the circle's center 4523 * @param centerY 4524 * the y coordinate of the circle's center 4525 * @param radiusSquared 4526 * the square radius of the circle 4527 * @param v0X 4528 * the x coordinate of the first vertex of the triangle 4529 * @param v0Y 4530 * the y coordinate of the first vertex of the triangle 4531 * @param v1X 4532 * the x coordinate of the second vertex of the triangle 4533 * @param v1Y 4534 * the y coordinate of the second vertex of the triangle 4535 * @param v2X 4536 * the x coordinate of the third vertex of the triangle 4537 * @param v2Y 4538 * the y coordinate of the third vertex of the triangle 4539 * @return <code>true</code> iff the circle intersects the triangle; <code>false</code> otherwise 4540 */ 4541 public static bool testCircleTriangle(double centerX, double centerY, double radiusSquared, double v0X, double v0Y, double v1X, double v1Y, double v2X, double v2Y) { 4542 double c1x = centerX - v0X, c1y = centerY - v0Y; 4543 double c1sqr = c1x * c1x + c1y * c1y - radiusSquared; 4544 if (c1sqr <= 0.0) 4545 return true; 4546 double c2x = centerX - v1X, c2y = centerY - v1Y; 4547 double c2sqr = c2x * c2x + c2y * c2y - radiusSquared; 4548 if (c2sqr <= 0.0) 4549 return true; 4550 double c3x = centerX - v2X, c3y = centerY - v2Y; 4551 double c3sqr = c3x * c3x + c3y * c3y - radiusSquared; 4552 if (c3sqr <= 0.0) 4553 return true; 4554 double e1x = v1X - v0X, e1y = v1Y - v0Y; 4555 double e2x = v2X - v1X, e2y = v2Y - v1Y; 4556 double e3x = v0X - v2X, e3y = v0Y - v2Y; 4557 if (e1x * c1y - e1y * c1x >= 0.0 && e2x * c2y - e2y * c2x >= 0.0 && e3x * c3y - e3y * c3x >= 0.0) 4558 return true; 4559 double k = c1x * e1x + c1y * e1y; 4560 if (k >= 0.0) { 4561 double len = e1x * e1x + e1y * e1y; 4562 if (k <= len) { 4563 if (c1sqr * len <= k * k) 4564 return true; 4565 } 4566 } 4567 k = c2x * e2x + c2y * e2y; 4568 if (k > 0.0) { 4569 double len = e2x * e2x + e2y * e2y; 4570 if (k <= len) { 4571 if (c2sqr * len <= k * k) 4572 return true; 4573 } 4574 } 4575 k = c3x * e3x + c3y * e3y; 4576 if (k >= 0.0) { 4577 double len = e3x * e3x + e3y * e3y; 4578 if (k < len) { 4579 if (c3sqr * len <= k * k) 4580 return true; 4581 } 4582 } 4583 return false; 4584 } 4585 4586 /** 4587 * Test whether the circle with given <code>center</code> and square radius <code>radiusSquared</code> intersects the triangle with counter-clockwise vertices 4588 * <code>v0</code>, <code>v1</code>, <code>v2</code>. 4589 * <p> 4590 * The vertices of the triangle must be specified in counter-clockwise order. 4591 * <p> 4592 * Reference: <a href="http://www.phatcode.net/articles.php?id=459">http://www.phatcode.net/</a> 4593 * 4594 * @param center 4595 * the circle's center 4596 * @param radiusSquared 4597 * the square radius of the circle 4598 * @param v0 4599 * the first vertex of the triangle 4600 * @param v1 4601 * the second vertex of the triangle 4602 * @param v2 4603 * the third vertex of the triangle 4604 * @return <code>true</code> iff the circle intersects the triangle; <code>false</code> otherwise 4605 */ 4606 public static bool testCircleTriangle(Vector2d center, double radiusSquared, Vector2d v0, Vector2d v1, Vector2d v2) { 4607 return testCircleTriangle(center.x, center.y, radiusSquared, v0.x, v0.y, v1.x, v1.y, v2.x, v2.y); 4608 } 4609 4610 /** 4611 * Determine whether the polygon specified by the given sequence of <code>(x, y)</code> coordinate pairs intersects with the ray 4612 * with given origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code>, and store the point of intersection 4613 * into the given vector <code>p</code>. 4614 * <p> 4615 * If the polygon intersects the ray, this method returns the index of the polygon edge intersecting the ray, that is, the index of the 4616 * first vertex of the directed line segment. The second vertex is always that index + 1, modulus the number of polygon vertices. 4617 * 4618 * @param verticesXY 4619 * the sequence of <code>(x, y)</code> coordinate pairs of all vertices of the polygon 4620 * @param originX 4621 * the x coordinate of the ray's origin 4622 * @param originY 4623 * the y coordinate of the ray's origin 4624 * @param dirX 4625 * the x coordinate of the ray's direction 4626 * @param dirY 4627 * the y coordinate of the ray's direction 4628 * @param p 4629 * will hold the point of intersection 4630 * @return the index of the first vertex of the polygon edge that intersects the ray; or <code>-1</code> if the ray does not intersect the polygon 4631 */ 4632 public static int intersectPolygonRay(double[] verticesXY, double originX, double originY, double dirX, double dirY, Vector2d p) { 4633 double nearestT = double.infinity; 4634 int count = cast(int)(verticesXY.length >> 1); 4635 int edgeIndex = -1; 4636 double aX = verticesXY[(count-1)<<1], aY = verticesXY[((count-1)<<1) + 1]; 4637 for (int i = 0; i < count; i++) { 4638 double bX = verticesXY[i << 1], bY = verticesXY[(i << 1) + 1]; 4639 double doaX = originX - aX, doaY = originY - aY; 4640 double dbaX = bX - aX, dbaY = bY - aY; 4641 double invDbaDir = 1.0 / (dbaY * dirX - dbaX * dirY); 4642 double t = (dbaX * doaY - dbaY * doaX) * invDbaDir; 4643 if (t >= 0.0 && t < nearestT) { 4644 double t2 = (doaY * dirX - doaX * dirY) * invDbaDir; 4645 if (t2 >= 0.0 && t2 <= 1.0) { 4646 edgeIndex = (i - 1 + count) % count; 4647 nearestT = t; 4648 p.x = originX + t * dirX; 4649 p.y = originY + t * dirY; 4650 } 4651 } 4652 aX = bX; 4653 aY = bY; 4654 } 4655 return edgeIndex; 4656 } 4657 4658 /** 4659 * Determine whether the polygon specified by the given sequence of <code>vertices</code> intersects with the ray 4660 * with given origin <code>(originX, originY, originZ)</code> and direction <code>(dirX, dirY, dirZ)</code>, and store the point of intersection 4661 * into the given vector <code>p</code>. 4662 * <p> 4663 * If the polygon intersects the ray, this method returns the index of the polygon edge intersecting the ray, that is, the index of the 4664 * first vertex of the directed line segment. The second vertex is always that index + 1, modulus the number of polygon vertices. 4665 * 4666 * @param vertices 4667 * the sequence of <code>(x, y)</code> coordinate pairs of all vertices of the polygon 4668 * @param originX 4669 * the x coordinate of the ray's origin 4670 * @param originY 4671 * the y coordinate of the ray's origin 4672 * @param dirX 4673 * the x coordinate of the ray's direction 4674 * @param dirY 4675 * the y coordinate of the ray's direction 4676 * @param p 4677 * will hold the point of intersection 4678 * @return the index of the first vertex of the polygon edge that intersects the ray; or <code>-1</code> if the ray does not intersect the polygon 4679 */ 4680 public static int intersectPolygonRay(Vector2d[] vertices, double originX, double originY, double dirX, double dirY, Vector2d p) { 4681 double nearestT = double.infinity; 4682 int count = cast(int)vertices.length; 4683 int edgeIndex = -1; 4684 double aX = vertices[count-1].x, aY = vertices[count-1].y; 4685 for (int i = 0; i < count; i++) { 4686 Vector2d b = vertices[i]; 4687 double bX = b.x, bY = b.y; 4688 double doaX = originX - aX, doaY = originY - aY; 4689 double dbaX = bX - aX, dbaY = bY - aY; 4690 double invDbaDir = 1.0 / (dbaY * dirX - dbaX * dirY); 4691 double t = (dbaX * doaY - dbaY * doaX) * invDbaDir; 4692 if (t >= 0.0 && t < nearestT) { 4693 double t2 = (doaY * dirX - doaX * dirY) * invDbaDir; 4694 if (t2 >= 0.0 && t2 <= 1.0) { 4695 edgeIndex = (i - 1 + count) % count; 4696 nearestT = t; 4697 p.x = originX + t * dirX; 4698 p.y = originY + t * dirY; 4699 } 4700 } 4701 aX = bX; 4702 aY = bY; 4703 } 4704 return edgeIndex; 4705 } 4706 4707 /** 4708 * Determine whether the two lines, specified via two points lying on each line, intersect each other, and store the point of intersection 4709 * into the given vector <code>p</code>. 4710 * 4711 * @param ps1x 4712 * the x coordinate of the first point on the first line 4713 * @param ps1y 4714 * the y coordinate of the first point on the first line 4715 * @param pe1x 4716 * the x coordinate of the second point on the first line 4717 * @param pe1y 4718 * the y coordinate of the second point on the first line 4719 * @param ps2x 4720 * the x coordinate of the first point on the second line 4721 * @param ps2y 4722 * the y coordinate of the first point on the second line 4723 * @param pe2x 4724 * the x coordinate of the second point on the second line 4725 * @param pe2y 4726 * the y coordinate of the second point on the second line 4727 * @param p 4728 * will hold the point of intersection 4729 * @return <code>true</code> iff the two lines intersect; <code>false</code> otherwise 4730 */ 4731 public static bool intersectLineLine(double ps1x, double ps1y, double pe1x, double pe1y, double ps2x, double ps2y, double pe2x, double pe2y, Vector2d p) { 4732 double d1x = ps1x - pe1x; 4733 double d1y = pe1y - ps1y; 4734 double d1ps1 = d1y * ps1x + d1x * ps1y; 4735 double d2x = ps2x - pe2x; 4736 double d2y = pe2y - ps2y; 4737 double d2ps2 = d2y * ps2x + d2x * ps2y; 4738 double det = d1y * d2x - d2y * d1x; 4739 if (det == 0.0) 4740 return false; 4741 p.x = (d2x * d1ps1 - d1x * d2ps2) / det; 4742 p.y = (d1y * d2ps2 - d2y * d1ps1) / det; 4743 return true; 4744 } 4745 4746 private static bool separatingAxis(Vector2d[] v1s, Vector2d[] v2s, double aX, double aY) { 4747 double minA = double.infinity, maxA = -double.infinity; 4748 double minB = double.infinity, maxB = -double.infinity; 4749 int maxLen = cast(int)Math.max(v1s.length, v2s.length); 4750 /* Project both polygons on axis */ 4751 for (int k = 0; k < maxLen; k++) { 4752 if (k < v1s.length) { 4753 Vector2d v1 = v1s[k]; 4754 double d = v1.x * aX + v1.y * aY; 4755 if (d < minA) minA = d; 4756 if (d > maxA) maxA = d; 4757 } 4758 if (k < v2s.length) { 4759 Vector2d v2 = v2s[k]; 4760 double d = v2.x * aX + v2.y * aY; 4761 if (d < minB) minB = d; 4762 if (d > maxB) maxB = d; 4763 } 4764 /* Early-out if overlap found */ 4765 if (minA <= maxB && minB <= maxA) { 4766 return false; 4767 } 4768 } 4769 return true; 4770 } 4771 4772 /** 4773 * Test if the two convex polygons, given via their vertices, intersect. 4774 * 4775 * @param v1s 4776 * the vertices of the first convex polygon 4777 * @param v2s 4778 * the vertices of the second convex polygon 4779 * @return <code>true</code> if the convex polygons intersect; <code>false</code> otherwise 4780 */ 4781 public static bool testPolygonPolygon(Vector2d[] v1s, Vector2d[] v2s) { 4782 /* Try to find a separating axis using the first polygon's edges */ 4783 for (int i = 0, j = cast(int)v1s.length - 1; i < v1s.length; j = i, i++) { 4784 Vector2d s = v1s[i], t = v1s[j]; 4785 if (separatingAxis(v1s, v2s, s.y - t.y, t.x - s.x)) 4786 return false; 4787 } 4788 /* Try to find a separating axis using the second polygon's edges */ 4789 for (int i = 0, j = cast(int)v2s.length - 1; i < v2s.length; j = i, i++) { 4790 Vector2d s = v2s[i], t = v2s[j]; 4791 if (separatingAxis(v1s, v2s, s.y - t.y, t.x - s.x)) 4792 return false; 4793 } 4794 return true; 4795 }