00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef HAVE_CONFIG_H
00019 # include <simgear_config.h>
00020 #endif
00021
00022 #include <cstdlib>
00023 #include <iostream>
00024
00025 #include "SGGeometry.hxx"
00026 #include "sg_random.h"
00027
00028 template<typename T>
00029 SGVec3<T> rndVec3(void)
00030 {
00031 return SGVec3<T>(sg_random(), sg_random(), sg_random());
00032 }
00033
00034 template<typename T>
00035 bool
00036 TriangleClosestPointIntersectionTest(void)
00037 {
00038 unsigned nTests = 100000;
00039 unsigned failedCount = 0;
00040 for (unsigned i = 0; i < nTests; ++i) {
00041
00042 SGTriangle<T> triangle(rndVec3<T>(), rndVec3<T>(), rndVec3<T>());
00043 T triangleEps = 100*SGLimits<T>::epsilon();
00044
00045
00046 T u = 4*sg_random() - 2;
00047 T v = 4*sg_random() - 2;
00048 if (1 < u + v) {
00049 v = T(0.5)*(v + 1 - u);
00050 u = 1 - v;
00051 }
00052 u = SGMisc<T>::clip(u, 0, 1);
00053 v = SGMisc<T>::clip(v, 0, 1);
00054
00055 SGVec3<T> testClosest;
00056 testClosest = triangle.getBaseVertex();
00057 testClosest += u*triangle.getEdge(0) + v*triangle.getEdge(1);
00058
00059 SGVec3<T> n = triangle.getNormal();
00060 SGVec3<T> e0 = triangle.getEdge(0);
00061 SGVec3<T> e1 = triangle.getEdge(1);
00062
00063
00064 SGVec3<T> a0 = cross(e0, n);
00065 SGVec3<T> a1 = cross(e1 - e0, n);
00066 SGVec3<T> a2 = cross(n, e1);
00067
00068 SGVec3<T> testPoint = testClosest;
00069
00070 if (u == 0) {
00071 if (v == 0) {
00072 testPoint += sg_random()*a0 + sg_random()*a2;
00073 } else if (v == 1) {
00074 testPoint += sg_random()*a1 + sg_random()*a2;
00075 } else {
00076 testPoint += sg_random()*a2;
00077 }
00078 } else if (u == 1) {
00079 testPoint += sg_random()*a0 + sg_random()*a1;
00080 } else {
00081 if (v == 0) {
00082 testPoint += sg_random()*a0;
00083 } else if (u + v == 1) {
00084 testPoint += sg_random()*a1;
00085 }
00086 }
00087 testPoint += (2*sg_random() - 1)*n;
00088
00089
00090 SGVec3<T> closest = closestPoint(triangle, testPoint);
00091 if (!equivalent(closest, testClosest, triangleEps)) {
00092 std::cout << "Failed closest point test #" << i
00093 << ": not equivalent!\nu = "
00094 << u << ", v = " << v
00095 << "\ntestPoint = " << testPoint
00096 << ", testClosest = " << testClosest
00097 << ", closest = " << closest << "\n"
00098 << triangle << std::endl;
00099 ++failedCount;
00100 }
00101
00102
00103 SGSphere<T> sphere(testPoint, sg_random());
00104 bool exactIntersection = intersects(sphere, testClosest);
00105
00106 bool sphereTriangleIntersection = intersects(sphere, triangle);
00107
00108 if (sphereTriangleIntersection != exactIntersection) {
00109 std::cout << "Failed triangle sphere intersection test #" << i
00110 << ": not equivalent!\nu = "
00111 << u << ", v = " << v
00112 << "\ntestPoint = " << testPoint
00113 << ", testClosest = " << testClosest
00114 << ", closest = " << closest << "\n"
00115 << triangle << std::endl;
00116 ++failedCount;
00117 }
00118 }
00119
00120 if (nTests < 100*failedCount) {
00121 std::cout << "Failed box line intersection tests: " << failedCount
00122 << " tests out of " << nTests
00123 << " went wrong. Abort!" << std::endl;
00124 return false;
00125 }
00126
00127 return true;
00128 }
00129
00130 template<typename T>
00131 bool
00132 TriangleLineIntersectionTest(void)
00133 {
00134 unsigned nTests = 100000;
00135 unsigned failedCount = 0;
00136 for (unsigned i = 0; i < nTests; ++i) {
00137 SGVec3<T> v0 = rndVec3<T>();
00138 SGVec3<T> v1 = rndVec3<T>();
00139 SGVec3<T> v2 = rndVec3<T>();
00140
00141 SGTriangle<T> tri(v0, v1, v2);
00142
00143 T triangleEps = 100*SGLimits<T>::epsilon();
00144
00145
00146 T u = 4*sg_random() - 2;
00147 T v = 4*sg_random() - 2;
00148 T t = 4*sg_random() - 2;
00149
00150 SGVec3<T> isectpt = v0 + u*(v1 - v0) + v*(v2 - v0);
00151
00152 SGLineSegment<T> lineSegment;
00153 SGVec3<T> dir = rndVec3<T>();
00154
00155 SGVec3<T> isectres;
00156 lineSegment.set(isectpt - t*dir, isectpt + (1 - t)*dir);
00157
00158 if (intersects(isectres, tri, lineSegment)) {
00159 if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t && t <= 1) {
00160 if (!equivalent(isectres, isectpt, triangleEps)) {
00161 std::cout << "Failed line segment intersection test #" << i
00162 << ": not equivalent!\nu = "
00163 << u << ", v = " << v << ", t = " << t
00164 << "\n" << tri << "\n" << lineSegment << std::endl;
00165 ++failedCount;
00166 }
00167 } else {
00168 std::cout << "Failed line segment intersection test #" << i
00169 << ": false positive!\nu = "
00170 << u << ", v = " << v << ", t = " << t
00171 << "\n" << tri << "\n" << lineSegment << std::endl;
00172 ++failedCount;
00173 }
00174 } else {
00175 if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t && t <= 1) {
00176 std::cout << "Failed line segment intersection test #" << i
00177 << ": false negative!\nu = "
00178 << u << ", v = " << v << ", t = " << t
00179 << "\n" << tri << "\n" << lineSegment << std::endl;
00180 ++failedCount;
00181 }
00182 }
00183
00184 SGRay<T> ray;
00185 ray.set(isectpt - t*dir, dir);
00186 if (intersects(isectres, tri, ray)) {
00187 if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t) {
00188 if (!equivalent(isectres, isectpt, triangleEps)) {
00189 std::cout << "Failed ray intersection test #" << i
00190 << ": not equivalent!\nu = "
00191 << u << ", v = " << v << ", t = " << t
00192 << "\n" << tri << "\n" << ray << std::endl;
00193 ++failedCount;
00194 }
00195 } else {
00196 std::cout << "Failed ray intersection test #" << i
00197 << ": false positive!\nu = "
00198 << u << ", v = " << v << ", t = " << t
00199 << "\n" << tri << "\n" << ray << std::endl;
00200 ++failedCount;
00201 }
00202 } else {
00203 if (0 <= u && 0 <= v && u+v <= 1 && 0 <= t) {
00204 std::cout << "Failed ray intersection test #" << i
00205 << ": false negative !\nu = "
00206 << u << ", v = " << v << ", t = " << t
00207 << "\n" << tri << "\n" << ray << std::endl;
00208 ++failedCount;
00209 }
00210 }
00211 }
00212
00213 if (nTests < 100*failedCount) {
00214 std::cout << "Failed ray intersection tests: " << failedCount
00215 << " tests out of " << nTests
00216 << " went wrong. Abort!" << std::endl;
00217 return false;
00218 }
00219
00221 SGVec3<T> v0 = SGVec3<T>(0, 0, 0);
00222 SGVec3<T> v1 = SGVec3<T>(1, 0, 0);
00223 SGVec3<T> v2 = SGVec3<T>(0, 1, 0);
00224
00225 SGTriangle<T> tri(v0, v1, v2);
00226
00227 SGRay<T> ray;
00228 ray.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0.1, 0.1, -1));
00229 if (!intersects(tri, ray)) {
00230 std::cout << "Failed test #1!" << std::endl;
00231 return false;
00232 }
00233
00234 ray.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 0, -1));
00235 if (!intersects(tri, ray)) {
00236 std::cout << "Failed test #2!" << std::endl;
00237 return false;
00238 }
00239
00240 SGLineSegment<T> lineSegment;
00241 lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0.1, 0.1, -1));
00242 if (!intersects(tri, lineSegment)) {
00243 std::cout << "Failed test #3!" << std::endl;
00244 return false;
00245 }
00246
00247 lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 0, -1));
00248 if (!intersects(tri, lineSegment)) {
00249 std::cout << "Failed test #4!" << std::endl;
00250 return false;
00251 }
00252
00253 lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, 1, -1));
00254 if (!intersects(tri, lineSegment)) {
00255 std::cout << "Failed test #5!" << std::endl;
00256 return false;
00257 }
00258
00259 lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 0, -1));
00260 if (!intersects(tri, lineSegment)) {
00261 std::cout << "Failed test #6!" << std::endl;
00262 return false;
00263 }
00264
00265 lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 1, -1));
00266 if (!intersects(tri, lineSegment)) {
00267 std::cout << "Failed test #7!" << std::endl;
00268 return false;
00269 }
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295
00296 lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(1, 1, -0.9));
00297 if (intersects(tri, lineSegment)) {
00298 std::cout << "Failed test #11!" << std::endl;
00299 return false;
00300 }
00301
00302 lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(0, -0.1, -1));
00303 if (intersects(tri, lineSegment)) {
00304 std::cout << "Failed test #12!" << std::endl;
00305 return false;
00306 }
00307
00308 lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(-0.1, -0.1, -1));
00309 if (intersects(tri, lineSegment)) {
00310 std::cout << "Failed test #13!" << std::endl;
00311 return false;
00312 }
00313
00314 lineSegment.set(SGVec3<T>(0, 0, 1), SGVec3<T>(-0.1, 0, -1));
00315 if (intersects(tri, lineSegment)) {
00316 std::cout << "Failed test #14!" << std::endl;
00317 return false;
00318 }
00319
00320 return true;
00321 }
00322
00323 template<typename T>
00324 bool
00325 SphereLineIntersectionTest(void)
00326 {
00327 unsigned nTests = 100000;
00328 unsigned failedCount = 0;
00329 for (unsigned i = 0; i < nTests; ++i) {
00330 SGVec3<T> center = rndVec3<T>();
00331 T radius = 2*sg_random();
00332 SGSphere<T> sphere(center, radius);
00333
00334 SGVec3<T> offset = normalize(rndVec3<T>());
00335 T t = 4*sg_random();
00336
00337
00338 SGVec3<T> base = center + t*offset;
00339
00340 SGVec3<T> per = perpendicular(offset);
00341 SGVec3<T> start = base + 4*sg_random()*per;
00342 SGVec3<T> end = base - 4*sg_random()*per;
00343
00344 SGLineSegment<T> lineSegment;
00345 lineSegment.set(start, end);
00346 if (intersects(sphere, lineSegment)) {
00347 if (radius < t) {
00348 std::cout << "Failed sphere line intersection test #" << i
00349 << ": false positive!\nt = " << t << "\n"
00350 << sphere << "\n" << lineSegment << std::endl;
00351 ++failedCount;
00352 }
00353 } else {
00354 if (t <= radius) {
00355 std::cout << "Failed sphere line intersection test #" << i
00356 << ": false negative!\nt = " << t << "\n"
00357 << sphere << "\n" << lineSegment << std::endl;
00358 ++failedCount;
00359 }
00360 }
00361
00362 SGRay<T> ray;
00363 ray.set(start, end - start);
00364 if (intersects(sphere, ray)) {
00365 if (radius < t) {
00366 std::cout << "Failed sphere line intersection test #" << i
00367 << ": false positive!\nt = " << t << "\n"
00368 << sphere << "\n" << ray << std::endl;
00369 ++failedCount;
00370 }
00371 } else {
00372 if (t <= radius) {
00373 std::cout << "Failed sphere line intersection test #" << i
00374 << ": false negative!\nt = " << t << "\n"
00375 << sphere << "\n" << ray << std::endl;
00376 ++failedCount;
00377 }
00378 }
00379 }
00380
00381 if (nTests < 100*failedCount) {
00382 std::cout << "Failed sphere line intersection tests: " << failedCount
00383 << " tests out of " << nTests
00384 << " went wrong. Abort!" << std::endl;
00385 return false;
00386 }
00387
00388 failedCount = 0;
00389 for (unsigned i = 0; i < nTests; ++i) {
00390 SGVec3<T> center = rndVec3<T>();
00391 T radius = 2*sg_random();
00392 SGSphere<T> sphere(center, radius);
00393
00394 SGVec3<T> offset = normalize(rndVec3<T>());
00395 T t = 4*sg_random();
00396
00397
00398 SGVec3<T> base = center + t*offset;
00399
00400 SGVec3<T> start = base;
00401 SGVec3<T> end = base + 2*sg_random()*offset;
00402
00403 SGLineSegment<T> lineSegment;
00404 lineSegment.set(start, end);
00405 if (intersects(sphere, lineSegment)) {
00406 if (radius < t) {
00407 std::cout << "Failed sphere line intersection test #" << i
00408 << ": false positive!\nt = " << t << "\n"
00409 << sphere << "\n" << lineSegment << std::endl;
00410 ++failedCount;
00411 }
00412 } else {
00413 if (t <= radius) {
00414 std::cout << "Failed sphere line intersection test #" << i
00415 << ": false negative!\nt = " << t << "\n"
00416 << sphere << "\n" << lineSegment << std::endl;
00417 ++failedCount;
00418 }
00419 }
00420
00421 SGRay<T> ray;
00422 ray.set(start, end - start);
00423 if (intersects(sphere, ray)) {
00424 if (radius < t) {
00425 std::cout << "Failed sphere line intersection test #" << i
00426 << ": false positive!\nt = " << t << "\n"
00427 << sphere << "\n" << ray << std::endl;
00428 ++failedCount;
00429 }
00430 } else {
00431 if (t <= radius) {
00432 std::cout << "Failed sphere line intersection test #" << i
00433 << ": false negative!\nt = " << t << "\n"
00434 << sphere << "\n" << ray << std::endl;
00435 ++failedCount;
00436 }
00437 }
00438 }
00439
00440 if (nTests < 100*failedCount) {
00441 std::cout << "Failed sphere line intersection tests: " << failedCount
00442 << " tests out of " << nTests
00443 << " went wrong. Abort!" << std::endl;
00444 return false;
00445 }
00446
00447 return true;
00448 }
00449
00450 template<typename T>
00451 bool
00452 BoxLineIntersectionTest(void)
00453 {
00454
00455
00456 unsigned nTests = 100000;
00457 unsigned failedCount = 0;
00458 for (unsigned i = 0; i < nTests; ++i) {
00459 SGBox<T> box;
00460 box.expandBy(rndVec3<T>());
00461 box.expandBy(rndVec3<T>());
00462
00463 SGVec3<T> center = box.getCenter();
00464
00465
00466 SGVec3<T> base = rndVec3<T>();
00467 SGVec3<T> dir = base - center;
00468
00469 SGLineSegment<T> lineSegment;
00470 lineSegment.set(base, base + dir);
00471 if (intersects(box, lineSegment)) {
00472 if (!intersects(box, base)) {
00473 std::cout << "Failed box line intersection test #" << i
00474 << ": false positive!\n"
00475 << box << "\n" << lineSegment << std::endl;
00476 ++failedCount;
00477 }
00478 } else {
00479 if (intersects(box, base)) {
00480 std::cout << "Failed box line intersection test #" << i
00481 << ": false negative!\n"
00482 << box << "\n" << lineSegment << std::endl;
00483 ++failedCount;
00484 }
00485 }
00486
00487 SGRay<T> ray;
00488 ray.set(base, dir);
00489 if (intersects(box, ray)) {
00490 if (!intersects(box, base)) {
00491 std::cout << "Failed box line intersection test #" << i
00492 << ": false positive!\n"
00493 << box << "\n" << ray << std::endl;
00494 ++failedCount;
00495 }
00496 } else {
00497 if (intersects(box, base)) {
00498 std::cout << "Failed box line intersection test #" << i
00499 << ": false negative!\n"
00500 << box << "\n" << ray << std::endl;
00501 ++failedCount;
00502 }
00503 }
00504 }
00505
00506 if (nTests < 100*failedCount) {
00507 std::cout << "Failed box line intersection tests: " << failedCount
00508 << " tests out of " << nTests
00509 << " went wrong. Abort!" << std::endl;
00510 return false;
00511 }
00512
00513 return true;
00514 }
00515
00516 int
00517 main(void)
00518 {
00519 std::cout << "Testing Geometry intersection routines.\n"
00520 << "Some of these tests can fail due to roundoff problems...\n"
00521 << "Dont worry if only a few of them fail..." << std::endl;
00522
00523 sg_srandom(17);
00524
00525 if (!TriangleClosestPointIntersectionTest<float>())
00526 return EXIT_FAILURE;
00527 if (!TriangleClosestPointIntersectionTest<double>())
00528 return EXIT_FAILURE;
00529
00530 if (!TriangleLineIntersectionTest<float>())
00531 return EXIT_FAILURE;
00532 if (!TriangleLineIntersectionTest<double>())
00533 return EXIT_FAILURE;
00534
00535 if (!SphereLineIntersectionTest<float>())
00536 return EXIT_FAILURE;
00537 if (!SphereLineIntersectionTest<double>())
00538 return EXIT_FAILURE;
00539
00540 if (!BoxLineIntersectionTest<float>())
00541 return EXIT_FAILURE;
00542 if (!BoxLineIntersectionTest<double>())
00543 return EXIT_FAILURE;
00544
00545 std::cout << "Successfully passed all tests!" << std::endl;
00546 return EXIT_SUCCESS;
00547 }