triangle3d.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Copyright (C) 2008-2012 Colin MacDonald
  2. // No rights reserved: this software is in the public domain.
  3. #include "testUtils.h"
  4. #include <irrlicht.h>
  5. using namespace irr;
  6. using namespace core;
  7. template<class T>
  8. static bool testGetIntersectionWithLine(core::triangle3d<T>& triangle, const core::line3d<T>& ray)
  9. {
  10. bool allExpected=true;
  11. const vector3d<T> linevect = ray.getVector().normalize();
  12. vector3d<T> intersection;
  13. // When we just raise Y parallel to the ray then either all should fail or all succeed (the latter in our case).
  14. for (u32 i=0; i<100; ++i)
  15. {
  16. if (!triangle.getIntersectionOfPlaneWithLine(ray.start, linevect, intersection))
  17. {
  18. allExpected=false;
  19. logTestString("triangle3d plane test %d failed\n", i);
  20. }
  21. //logTestString("intersection: %f %f %f\n", intersection.X, intersection.Y, intersection.Z);
  22. if (!triangle.isPointInsideFast(intersection))
  23. {
  24. allExpected=false;
  25. logTestString("triangle3d fast point test %d failed\n", i);
  26. }
  27. if (!triangle.isPointInside(intersection))
  28. {
  29. allExpected=false;
  30. logTestString("triangle3d point test %d failed\n", i);
  31. }
  32. if (!triangle.getIntersectionWithLine(ray.start, linevect, intersection))
  33. {
  34. allExpected=false;
  35. logTestString("triangle3d tri test %d failed\n", i);
  36. }
  37. triangle.pointB.Y += 1;
  38. }
  39. return allExpected;
  40. }
  41. // modifying the same triangle in diverse ways get some more test-cases automatically
  42. template<class T>
  43. static bool stageModifications(int stage, triangle3d<T>& triangle)
  44. {
  45. switch ( stage )
  46. {
  47. case 0:
  48. return true;
  49. case 1:
  50. swap(triangle.pointB, triangle.pointC);
  51. return true;
  52. case 2:
  53. swap(triangle.pointA, triangle.pointC);
  54. return true;
  55. case 3:
  56. triangle.pointA.Z += 1000;
  57. triangle.pointB.Z += 1000;
  58. triangle.pointC.Z += 1000;
  59. return true;
  60. case 4:
  61. swap(triangle.pointA.Y, triangle.pointA.Z);
  62. swap(triangle.pointB.Y, triangle.pointB.Z);
  63. swap(triangle.pointC.Y, triangle.pointC.Z);
  64. return true;
  65. }
  66. return false;
  67. }
  68. template<class T>
  69. static void stageModifications(int stage, vector3d<T>& point)
  70. {
  71. switch ( stage )
  72. {
  73. case 3:
  74. point.Z += 1000;
  75. break;
  76. case 4:
  77. swap(point.Y, point.Z);
  78. break;
  79. }
  80. }
  81. template<class T>
  82. static bool isPointInside(triangle3d<T> triangleOrig, bool testIsInside, bool testIsInsideFast)
  83. {
  84. bool allExpected=true;
  85. array< vector3d<T> > pointsInside;
  86. pointsInside.push_back( vector3d<T>(0,0,0) );
  87. pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB + triangleOrig.pointC) / 3 );
  88. pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 + vector3d<T>(0,1,0) );
  89. pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 + vector3d<T>(1,0,0) );
  90. pointsInside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 - vector3d<T>(1,0,0) );
  91. for (u32 stage=0; ; ++stage)
  92. {
  93. triangle3d<T> triangle = triangleOrig;
  94. if ( !stageModifications(stage, triangle) )
  95. break;
  96. for ( u32 i=0; i < pointsInside.size(); ++i )
  97. {
  98. vector3d<T> point = pointsInside[i];
  99. stageModifications(stage, point);
  100. if ( testIsInside )
  101. {
  102. allExpected &= triangle.isPointInside( point );
  103. if ( !allExpected )
  104. {
  105. logTestString("triangle3d::isPointInside pointsInside test failed in stage %d point %d\n", stage, i);
  106. return false;
  107. }
  108. }
  109. if ( testIsInsideFast )
  110. {
  111. allExpected &= triangle.isPointInsideFast( point );
  112. if ( !allExpected )
  113. {
  114. logTestString("triangle3d::isPointInsideFast pointsInside test failed in stage %d point %d\n", stage, i);
  115. return false;
  116. }
  117. }
  118. }
  119. }
  120. array< vector3d<T> > pointsOutside;
  121. pointsOutside.push_back( triangleOrig.pointA - vector3d<T>(1,0,0) );
  122. pointsOutside.push_back( triangleOrig.pointA - vector3d<T>(0,1,0) );
  123. pointsOutside.push_back( triangleOrig.pointB + vector3d<T>(1,0,0) );
  124. pointsOutside.push_back( triangleOrig.pointB - vector3d<T>(0,1,0) );
  125. pointsOutside.push_back( triangleOrig.pointC - vector3d<T>(1,0,0) );
  126. pointsOutside.push_back( triangleOrig.pointC + vector3d<T>(1,0,0) );
  127. pointsOutside.push_back( triangleOrig.pointC + vector3d<T>(0,1,0) );
  128. pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 - vector3d<T>(0,1,0) );
  129. pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 - vector3d<T>(1,0,0) );
  130. pointsOutside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 + vector3d<T>(1,0,0) );
  131. for (u32 stage=0; ; ++stage)
  132. {
  133. triangle3d<T> triangle = triangleOrig;
  134. if ( !stageModifications(stage, triangle) )
  135. break;
  136. for ( u32 i=0; i < pointsOutside.size(); ++i )
  137. {
  138. vector3d<T> point = pointsOutside[i];
  139. stageModifications(stage, point);
  140. if ( testIsInside )
  141. {
  142. allExpected &= !triangle.isPointInside( point );
  143. if ( !allExpected )
  144. {
  145. logTestString("triangle3d::isPointInside pointsOutside test failed in stage %d point %d\n", stage, i);
  146. return false;
  147. }
  148. }
  149. if ( testIsInsideFast )
  150. {
  151. allExpected &= !triangle.isPointInsideFast( point );
  152. if ( !allExpected )
  153. {
  154. logTestString("triangle3d::isPointInsideFast pointsOutside test failed in stage %d point %d\n", stage, i);
  155. return false;
  156. }
  157. }
  158. }
  159. }
  160. array< vector3d<T> > pointsBorder;
  161. pointsBorder.push_back( triangleOrig.pointA );
  162. pointsBorder.push_back( triangleOrig.pointB );
  163. pointsBorder.push_back( triangleOrig.pointC );
  164. pointsBorder.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 );
  165. pointsBorder.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 );
  166. pointsBorder.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 );
  167. for (u32 stage=0; ; ++stage)
  168. {
  169. triangle3d<T> triangle = triangleOrig;
  170. if ( !stageModifications(stage, triangle) )
  171. break;
  172. for ( u32 i=0; i < pointsBorder.size(); ++i )
  173. {
  174. vector3d<T> point = pointsBorder[i];
  175. stageModifications(stage, point);
  176. if ( testIsInside )
  177. {
  178. allExpected &= triangle.isPointInside( point );
  179. if ( !allExpected )
  180. {
  181. logTestString("triangle3d::isPointInside pointsBorder test failed in stage %d point %d\n", stage, i);
  182. return false;
  183. }
  184. }
  185. if ( testIsInsideFast )
  186. {
  187. allExpected &= triangle.isPointInsideFast( point );
  188. if ( !allExpected )
  189. {
  190. logTestString("triangle3d::isPointInsideFast pointsBorder test failed in stage %d point %d\n", stage, i);
  191. return false;
  192. }
  193. }
  194. }
  195. }
  196. return allExpected;
  197. }
  198. // Test the functionality of triangle3d<T>
  199. bool testTriangle3d(void)
  200. {
  201. bool allExpected = true;
  202. logTestString("Test getIntersectionWithLine with f32\n");
  203. {
  204. triangle3df triangle(
  205. vector3df(11300.f, 129.411758f, 200.f),
  206. vector3df(11200.f, 94.117645f, 300.f),
  207. vector3df(11300.f, 129.411758f, 300.f));
  208. line3df ray;
  209. ray.start = vector3df(11250.f, 329.f, 250.f);
  210. ray.end = vector3df(11250.f, -1000.f, 250.f);
  211. allExpected &= testGetIntersectionWithLine(triangle, ray);
  212. }
  213. logTestString("Test getIntersectionWithLine with f64\n");
  214. {
  215. triangle3d<f64> triangle(
  216. vector3d<f64>(11300., 129.411758, 200.),
  217. vector3d<f64>(11200., 94.117645, 300.),
  218. vector3d<f64>(11300., 129.411758, 300.));
  219. line3d<f64> ray;
  220. ray.start = vector3d<f64>(11250., 329., 250.);
  221. ray.end = vector3d<f64>(11250., -1000., 250.);
  222. allExpected &= testGetIntersectionWithLine(triangle, ray);
  223. }
  224. bool testEigen = triangle3di(vector3di(250, 0, 0), vector3di(0, 0, 500), vector3di(500, 0, 500)).isPointInside(vector3di(300,0,300));
  225. if ( !testEigen ) // test from Eigen from here: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=44372&p=254331#p254331
  226. logTestString("Test isPointInside fails with integers\n");
  227. allExpected &= testEigen;
  228. logTestString("Test isPointInside with f32\n");
  229. {
  230. triangle3d<f32> t(vector3d<f32>(-1000,-1000,0), vector3d<f32>(1000,-1000,0), vector3d<f32>(0,1000,0));
  231. allExpected &= isPointInside(t, true, true);
  232. }
  233. logTestString("Test isPointInside with f64\n");
  234. {
  235. triangle3d<f64> t(vector3d<f64>(-1000,-1000,0), vector3d<f64>(1000,-1000,0), vector3d<f64>(0,1000,0));
  236. allExpected &= isPointInside(t, true, true);
  237. }
  238. logTestString("Test isPointInside with s32\n");
  239. {
  240. triangle3d<s32> t(vector3d<s32>(-1000,-1000,0), vector3d<s32>(1000,-1000,0), vector3d<s32>(0,1000,0));
  241. allExpected &= isPointInside(t, false, true);
  242. }
  243. if(allExpected)
  244. logTestString("\nAll tests passed\n");
  245. else
  246. logTestString("\nFAIL!\n");
  247. return allExpected;
  248. }