/src/org/mt4j/components/visibleComponents/shapes/mesh/Triangle.java

http://mt4j.googlecode.com/ · Java · 509 lines · 173 code · 77 blank · 259 comment · 27 complexity · 6e9bd72a62aeedac098796bd825284c3 MD5 · raw file

  1. /***********************************************************************
  2. * mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. ***********************************************************************/
  18. package org.mt4j.components.visibleComponents.shapes.mesh;
  19. import org.mt4j.util.math.ToolsMath;
  20. import org.mt4j.util.math.Ray;
  21. import org.mt4j.util.math.ToolsGeometry;
  22. import org.mt4j.util.math.Vector3D;
  23. import org.mt4j.util.math.Vertex;
  24. /**
  25. * A triangle class used in meshes.
  26. *
  27. * @author Christopher Ruff
  28. */
  29. public class Triangle {
  30. /** The v0. */
  31. public Vertex v0;
  32. /** The v1. */
  33. public Vertex v1;
  34. /** The v2. */
  35. public Vertex v2;
  36. //Pointers into the vertex array
  37. /** The P0. */
  38. public int P0;
  39. /** The P1. */
  40. public int P1;
  41. /** The P2. */
  42. public int P2;
  43. /** The normal. */
  44. private Vector3D normal;
  45. /** The normal unnormalized. */
  46. private Vector3D normalUnnormalized;
  47. /** The center. */
  48. private Vector3D center;
  49. /** The normal dirty. */
  50. private boolean normalDirty;
  51. /** The center dirty. */
  52. private boolean centerDirty;
  53. // private boolean useLocalObjectSpace;
  54. /**
  55. * The Constructor.
  56. *
  57. * @param v0 the v0
  58. * @param v1 the v1
  59. * @param v2 the v2
  60. * @param p0 the index p0
  61. * @param p1 the index p1
  62. * @param p2 the index p2
  63. */
  64. public Triangle(Vertex v0, Vertex v1, Vertex v2, int p0, int p1, int p2) {
  65. this.v0 = v0;
  66. this.v1 = v1;
  67. this.v2 = v2;
  68. this.P0 = p0;
  69. this.P1 = p1;
  70. this.P2 = p2;
  71. this.normalDirty = true;
  72. // this.normal = this.getNormalLocal();
  73. this.normal = null; //lazily initialize them to save memory
  74. this.centerDirty = true;
  75. // this.center = this.getCenterPointLocal();
  76. this.center = null;
  77. // this.useLocalObjectSpace = true;
  78. }
  79. /**
  80. * Sets the.
  81. *
  82. * @param v0 the v0
  83. * @param v1 the v1
  84. * @param v2 the v2
  85. */
  86. public void set(Vertex v0, Vertex v1, Vertex v2){
  87. this.v0 = v0;
  88. this.v1 = v1;
  89. this.v2 = v2;
  90. this.normalDirty = true;
  91. this.centerDirty = true;
  92. }
  93. /**
  94. * Gets the normal obj space.
  95. *
  96. * @return the normal obj space
  97. *
  98. * the normal vector of the plane of the triangle
  99. */
  100. public Vector3D getNormalLocal(){
  101. this.calcNormal();
  102. return this.normal;
  103. }
  104. /**
  105. * Calc normal.
  106. */
  107. private void calcNormal(){
  108. if (normalDirty || this.normal == null || this.normalUnnormalized == null){
  109. this.normal = ToolsGeometry.getNormal(v0, v1, v2, false);
  110. //Get unnormalized normal for triangle intersection tests (So degenerate tris get detected)
  111. this.normalUnnormalized = normal.getCopy();
  112. this.normal.normalizeLocal();
  113. normalDirty = false;
  114. }
  115. }
  116. /**
  117. * Gets the center point local.
  118. *
  119. * @return the center point local
  120. */
  121. public Vector3D getCenterPointLocal(){
  122. this.calcCenterLocal();
  123. return this.center;
  124. }
  125. /**
  126. * Calc center local.
  127. */
  128. private void calcCenterLocal(){
  129. if (centerDirty || center == null){
  130. center = this.v0.getCopy();
  131. center.addLocal(v1);
  132. center.addLocal(v2);
  133. center.scaleLocal(ToolsMath.ONE_THIRD);
  134. centerDirty = false;
  135. }
  136. }
  137. /**
  138. * Tests if the given ray intersects this triangle.
  139. * Returns the intersection point or null if there is none.
  140. *
  141. * @param r the r
  142. *
  143. * @return the ray triangle intersection
  144. *
  145. * intersection vector
  146. */
  147. public Vector3D getRayTriangleIntersection(Ray r){
  148. //Update unnormalized normal if neccessary
  149. this.calcNormal();
  150. return ToolsGeometry.getRayTriangleIntersection(r, v0, v1, v2, this.normalUnnormalized);
  151. }
  152. /**
  153. * Checks if point vector is inside the triangle created by the points a, b
  154. * and c. These points will create a plane and the point checked will have
  155. * to be on this plane in the region between a,b,c.
  156. *
  157. * Note: The triangle must be defined in clockwise order a,b,c
  158. *
  159. * @param p the p
  160. *
  161. * @return true, if point is in triangle.
  162. */
  163. public boolean containsPoint(Vector3D p) {
  164. Vector3D a = p.getSubtracted(v0);
  165. a.normalizeLocal();
  166. Vector3D b = p.getSubtracted(v1);
  167. b.normalizeLocal();
  168. Vector3D c = p.getSubtracted(v2);
  169. c.normalizeLocal();
  170. double total_angles = Math.acos(a.dot(b));
  171. total_angles += Math.acos(b.dot(c));
  172. total_angles += Math.acos(c.dot(a));
  173. return (ToolsMath.abs((float) total_angles - ToolsMath.TWO_PI) <= 0.005f);
  174. }
  175. /**
  176. * Finds and returns the closest point on any of the triangle edges to the
  177. * point given.
  178. *
  179. * @param p point to check
  180. *
  181. * @return closest point
  182. */
  183. public Vector3D getClosestVertexTo(Vector3D p) {
  184. Vector3D Rab = getClosestVecToVecOnSegment(p, v0, v1);
  185. Vector3D Rbc = getClosestVecToVecOnSegment(p, v1, v2);
  186. Vector3D Rca = getClosestVecToVecOnSegment(p, v2, v0);
  187. float dAB = p.getSubtracted(Rab).lengthSquared();
  188. float dBC = p.getSubtracted(Rbc).lengthSquared();
  189. float dCA = p.getSubtracted(Rca).lengthSquared();
  190. float min = dAB;
  191. Vector3D result = Rab;
  192. if (dBC < min) {
  193. min = dBC;
  194. result = Rbc;
  195. }
  196. if (dCA < min){
  197. result = Rca;
  198. }
  199. return result;
  200. }
  201. /**
  202. * Computes the the point on the surface of
  203. * triangle closest to the given vector.
  204. *
  205. * From Real-Time Collision Detection by Christer Ericson, published by
  206. * Morgan Kaufmann Publishers, Copyright 2005 Elsevier Inc
  207. *
  208. * @param p the p
  209. *
  210. * @return closest point on triangle (result may also be one of v0, v1 or v2)
  211. */
  212. public Vector3D getClosestPointOnSurface(Vector3D p) {
  213. Vector3D ab = v1.getSubtracted(v0);
  214. Vector3D ac = v2.getSubtracted(v0);
  215. Vector3D bc = v2.getSubtracted(v1);
  216. Vector3D pa = p.getSubtracted(v0);
  217. Vector3D pb = p.getSubtracted(v1);
  218. Vector3D pc = p.getSubtracted(v2);
  219. Vector3D ap = v0.getSubtracted(p);
  220. Vector3D bp = v1.getSubtracted(p);
  221. Vector3D cp = v2.getSubtracted(p);
  222. // Compute parametric position s for projection P' of P on AB,
  223. // P' = A + s*AB, s = snom/(snom+sdenom)
  224. float snom = pa.dot(ab);
  225. float sdenom = pb.dot(v0.getSubtracted(v1));
  226. // Compute parametric position t for projection P' of P on AC,
  227. // P' = A + t*AC, s = tnom/(tnom+tdenom)
  228. float tnom = pa.dot(ac);
  229. float tdenom = pc.dot(v0.getSubtracted(v2));
  230. if (snom <= 0.0f && tnom <= 0.0f)
  231. return v0; // Vertex region early out
  232. // Compute parametric position u for projection P' of P on BC,
  233. // P' = B + u*BC, u = unom/(unom+udenom)
  234. float unom = pb.dot(bc);
  235. float udenom = pc.dot(v1.getSubtracted(v2));
  236. if (sdenom <= 0.0f && unom <= 0.0f)
  237. return v1; // Vertex region early out
  238. if (tdenom <= 0.0f && udenom <= 0.0f)
  239. return v2; // Vertex region early out
  240. // P is outside (or on) AB if the triple scalar product [N PA PB] <= 0
  241. Vector3D n = ab.getCross(ac);
  242. float vc = n.dot(ap.crossLocal(bp));
  243. // If P outside AB and within feature region of AB,
  244. // return projection of P onto AB
  245. if (vc <= 0.0f && snom >= 0.0f && sdenom >= 0.0f) {
  246. // return a + snom / (snom + sdenom) * ab;
  247. return v0.getAdded(ab.scaleLocal(snom / (snom + sdenom)));
  248. }
  249. // P is outside (or on) BC if the triple scalar product [N PB PC] <= 0
  250. float va = n.dot(bp.crossLocal(cp));
  251. // If P outside BC and within feature region of BC,
  252. // return projection of P onto BC
  253. if (va <= 0.0f && unom >= 0.0f && udenom >= 0.0f) {
  254. // return b + unom / (unom + udenom) * bc;
  255. return v1.getAdded(bc.scaleLocal(unom / (unom + udenom)));
  256. }
  257. // P is outside (or on) CA if the triple scalar product [N PC PA] <= 0
  258. float vb = n.dot(cp.crossLocal(ap));
  259. // If P outside CA and within feature region of CA,
  260. // return projection of P onto CA
  261. if (vb <= 0.0f && tnom >= 0.0f && tdenom >= 0.0f) {
  262. // return a + tnom / (tnom + tdenom) * ac;
  263. return v0.getAdded(ac.scaleLocal(tnom / (tnom + tdenom)));
  264. }
  265. // P must project inside face region. Compute Q using barycentric
  266. // coordinates
  267. float u = va / (va + vb + vc);
  268. float v = vb / (va + vb + vc);
  269. float w = 1.0f - u - v; // = vc / (va + vb + vc)
  270. // return u * a + v * b + w * c;
  271. return v0.getScaled(u).addLocal(v1.getScaled(v)).addLocal(v2.getScaled(w));
  272. }
  273. /**
  274. * Checks if is clockwise in xy.
  275. *
  276. * @return true, if is clockwise in xy
  277. */
  278. public boolean isClockwiseInXY() {
  279. return Triangle.isClockwiseInXY(v0, v1, v2);
  280. }
  281. /**
  282. * Checks if is clockwise in xz.
  283. *
  284. * @return true, if is clockwise in xz
  285. */
  286. public boolean isClockwiseInXZ() {
  287. return Triangle.isClockwiseInXY(v0, v1, v2);
  288. }
  289. /**
  290. * Checks if is clockwise in yz.
  291. *
  292. * @return true, if is clockwise in yz
  293. */
  294. public boolean isClockwiseInYZ() {
  295. return Triangle.isClockwiseInXY(v0, v1, v2);
  296. }
  297. /**
  298. * Checks if is clockwise in xy.
  299. *
  300. * @param v0 the v0
  301. * @param v1 the v1
  302. * @param v2 the v2
  303. *
  304. * @return true, if is clockwise in xy
  305. */
  306. public static boolean isClockwiseInXY(Vector3D v0, Vector3D v1, Vector3D v2) {
  307. float determ = (v1.x - v0.x) * (v2.y - v0.y) - (v2.x - v0.x) * (v1.y - v0.y);
  308. return (determ < 0.0);
  309. }
  310. /**
  311. * Checks if is clockwise in xz.
  312. *
  313. * @param v0 the v0
  314. * @param v1 the v1
  315. * @param v2 the v2
  316. *
  317. * @return true, if is clockwise in xz
  318. */
  319. public static boolean isClockwiseInXZ(Vector3D v0, Vector3D v1, Vector3D v2) {
  320. float determ = (v1.x - v0.x) * (v2.z - v0.z) - (v2.x - v0.x) * (v1.z - v0.z);
  321. return (determ < 0.0);
  322. }
  323. /**
  324. * Checks if is clockwise in yz.
  325. *
  326. * @param v0 the v0
  327. * @param v1 the v1
  328. * @param v2 the v2
  329. *
  330. * @return true, if is clockwise in yz
  331. */
  332. public static boolean isClockwiseInYZ(Vector3D v0, Vector3D v1, Vector3D v2) {
  333. float determ = (v1.y - v0.y) * (v2.z - v0.z) - (v2.y - v0.y) * (v1.z - v0.z);
  334. return (determ < 0.0);
  335. }
  336. /**
  337. * Gets the closest vec to vec on segment.
  338. *
  339. * @param p the point to find the closest point on the segment for
  340. * @param segmentStart start point of line segment
  341. * @param segmentEnd end point of line segment
  342. *
  343. * @return closest point on the line segment a -> b
  344. */
  345. private Vector3D getClosestVecToVecOnSegment(Vector3D p, Vector3D segmentStart, Vector3D segmentEnd) {
  346. Vector3D c = p.getSubtracted(segmentStart);
  347. Vector3D v = segmentEnd.getSubtracted(segmentStart);
  348. float d = v.length();
  349. v.normalizeLocal();
  350. float t = v.dot(c);
  351. // Check to see if t is beyond the extents of the line segment
  352. if (t < 0.0f) {
  353. return segmentStart;
  354. }
  355. if (t > d) {
  356. return segmentEnd;
  357. }
  358. // Return the point between 'a' and 'b'
  359. // set length of V to t. V is normalized so this is easy
  360. v.scaleLocal(t);
  361. return segmentStart.getAdded(v);
  362. }
  363. /* code rewritten to do tests on the sign of the determinant */
  364. /* the division is before the test of the sign of the det */
  365. // int intersect_triangle2(
  366. // double orig[3],
  367. // double dir[3],
  368. // double vert0[3],
  369. // double vert1[3],
  370. // double vert2[3],
  371. // double *t,
  372. // double *u,
  373. // double *v
  374. // ){
  375. // double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
  376. // double det,inv_det;
  377. //
  378. // /* find vectors for two edges sharing vert0 */
  379. // SUB(edge1, vert1, vert0);
  380. // SUB(edge2, vert2, vert0);
  381. //
  382. // /* begin calculating determinant - also used to calculate U parameter */
  383. // CROSS(pvec, dir, edge2);
  384. //
  385. // /* if determinant is near zero, ray lies in plane of triangle */
  386. // det = DOT(edge1, pvec);
  387. //
  388. // /* calculate distance from vert0 to ray origin */
  389. // SUB(tvec, orig, vert0);
  390. // inv_det = 1.0 / det;
  391. //
  392. // if (det > EPSILON)
  393. // {
  394. // /* calculate U parameter and test bounds */
  395. // *u = DOT(tvec, pvec);
  396. // if (*u < 0.0 || *u > det)
  397. // return 0;
  398. //
  399. // /* prepare to test V parameter */
  400. // CROSS(qvec, tvec, edge1);
  401. //
  402. // /* calculate V parameter and test bounds */
  403. // *v = DOT(dir, qvec);
  404. // if (*v < 0.0 || *u + *v > det)
  405. // return 0;
  406. //
  407. // }
  408. // else if(det < -EPSILON)
  409. // {
  410. // /* calculate U parameter and test bounds */
  411. // *u = DOT(tvec, pvec);
  412. // if (*u > 0.0 || *u < det)
  413. // return 0;
  414. //
  415. // /* prepare to test V parameter */
  416. // CROSS(qvec, tvec, edge1);
  417. //
  418. // /* calculate V parameter and test bounds */
  419. // *v = DOT(dir, qvec) ;
  420. // if (*v > 0.0 || *u + *v < det)
  421. // return 0;
  422. // }
  423. // else return 0; /* ray is parallell to the plane of the triangle */
  424. //
  425. // /* calculate t, ray intersects triangle */
  426. // *t = DOT(edge2, qvec) * inv_det;
  427. // (*u) *= inv_det;
  428. // (*v) *= inv_det;
  429. //
  430. // return 1;
  431. // }
  432. }