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