PageRenderTime 93ms CodeModel.GetById 44ms app.highlight 43ms RepoModel.GetById 2ms app.codeStats 0ms

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