$search
00001 /******************************************************************************* 00002 * Copyright (c) 2012 Stefan Profanter. All rights reserved. This program and the accompanying 00003 * materials are made available under the terms of the GNU Public License v3.0 which accompanies 00004 * this distribution, and is available at http://www.gnu.org/licenses/gpl.html 00005 * 00006 * Contributors: Stefan Profanter - initial API and implementation, Year: 2012 00007 ******************************************************************************/ 00008 package edu.tum.cs.vis.model.util; 00009 00010 import java.awt.Color; 00011 import java.util.HashSet; 00012 import java.util.Set; 00013 import java.util.concurrent.locks.Lock; 00014 00015 import javax.vecmath.Point2f; 00016 import javax.vecmath.Point3f; 00017 import javax.vecmath.Vector3d; 00018 import javax.vecmath.Vector3f; 00019 00020 import org.apache.log4j.Logger; 00021 00022 import processing.core.PConstants; 00023 import processing.core.PGraphics; 00024 00031 public class Triangle extends DrawObject { 00032 00036 private static final long serialVersionUID = -5164768039180386782L; 00037 00041 private static Logger logger = Logger.getLogger(Triangle.class); 00042 00046 protected Point2f texPosition[]; 00047 00051 protected Vector3f normalVector = null; 00052 00056 protected Vector3f cornerarea = null; 00057 00061 protected Point3f centroid; 00062 00066 protected Set<Triangle> neighbors = new HashSet<Triangle>(3); 00067 00072 public Triangle() { 00073 super(3); 00074 } 00075 00086 public boolean addNeighbor(Triangle neighbor, Lock lock) { 00087 boolean add = false; 00088 00089 if (neighbors.size() >= 3) // for better performance skip if triangle has already all 00090 // neighbors set 00091 return false; 00092 00093 add = isDirectNeighbor(neighbor); 00094 00095 if (add) { 00096 if (lock != null) 00097 lock.lock(); 00098 // to make sure neighbors is not cached 00099 synchronized (neighbors) { 00100 neighbors.add(neighbor); 00101 } 00102 synchronized (neighbor.neighbors) { 00103 neighbor.neighbors.add(this); 00104 } 00105 if (lock != null) 00106 lock.unlock(); 00107 } 00108 return add; 00109 } 00110 00118 public void removeNeighbor(Triangle n) { 00119 if (neighbors != null) { 00120 synchronized (neighbors) { 00121 neighbors.remove(n); 00122 } 00123 } 00124 if (n.neighbors != null) { 00125 synchronized (n.neighbors) { 00126 n.neighbors.remove(this); 00127 } 00128 } 00129 } 00130 00139 public void draw(PGraphics g, Color overrideColor) { 00140 applyColor(g, overrideColor); 00141 g.beginShape(PConstants.TRIANGLES); 00142 if (appearance == null || appearance.getImageReference() == null || overrideColor != null 00143 || position[0].getNormalVector() != null) { 00144 // no texture only color 00145 00146 for (int i = 0; i < position.length; i++) { 00147 00148 if (position[i].overrideColor != null) { 00149 g.fill(position[i].overrideColor.getRed(), 00150 position[i].overrideColor.getGreen(), 00151 position[i].overrideColor.getBlue()); 00152 } else if (overrideColor == null && position[i].color != null) { 00153 g.fill(position[i].color.getRed(), position[i].color.getGreen(), 00154 position[i].color.getBlue()); 00155 } 00156 00157 if (position[i].getNormalVector() != null) 00158 g.normal(position[i].getNormalVector().x, position[i].getNormalVector().y, 00159 position[i].getNormalVector().z); 00160 g.vertex(position[i].x, position[i].y, position[i].z); 00161 } 00162 00163 } else { 00164 // has texture 00165 g.texture(appearance.getImageReference()); 00166 00167 for (int i = 0; i < position.length; i++) { 00168 00169 g.vertex(position[i].x, position[i].y, position[i].z, texPosition[i].x, 00170 texPosition[i].y); 00171 00172 } 00173 00174 } 00175 g.endShape(); 00176 } 00177 00183 public float getArea() { 00184 if (position.length == 3) { 00185 00186 Point3f v = (Point3f) position[1].clone(); 00187 v.sub(position[0]); 00188 Point3f w = (Point3f) position[2].clone(); 00189 w.sub(position[0]); 00190 00191 Vector3f v1 = new Vector3f(v); 00192 Vector3f w1 = new Vector3f(w); 00193 00194 Vector3f cross = new Vector3f(); 00195 cross.cross(v1, w1); 00196 return cross.length() / 2f; 00197 } 00198 00199 logger.error("getArea not implemented for " + position.length + "-Triangle"); 00200 return 0; 00201 } 00202 00208 public Point3f getCentroid() { 00209 return centroid; 00210 } 00211 00217 public Vector3f getCornerarea() { 00218 return cornerarea; 00219 } 00220 00226 public Set<Triangle> getNeighbors() { 00227 return neighbors; 00228 } 00229 00238 public double getDihedralAngle(Triangle t) { 00239 double dot = this.getNormalVector().dot(t.getNormalVector()); 00240 dot = Math.max(-1, dot); 00241 dot = Math.min(1, dot); 00242 return Math.acos(dot); 00243 } 00244 00250 public Vector3f getNormalVector() { 00251 return normalVector; 00252 } 00253 00259 public Point2f[] getTexPosition() { 00260 return texPosition; 00261 } 00262 00273 public boolean intersectsRay(Point3f rayStart, Point3f rayEnd) { 00274 return intersectsRay(rayStart, rayEnd, null); 00275 } 00276 00282 public boolean calculateNormalVector() { 00283 // Calculate normal vector for triangle 00284 Vector3f avgVertexNorm = new Vector3f(); 00285 for (int i = 0; i < 3; i++) { 00286 if (position[i].getNormalVector() == null) { 00287 avgVertexNorm = null; 00288 break; 00289 } 00290 avgVertexNorm.add(position[i].getNormalVector()); 00291 } 00292 if (avgVertexNorm != null) { 00293 avgVertexNorm.scale(1f / 3f); 00294 } 00295 00296 Vector3f a = new Vector3f(position[0]); 00297 a.sub(position[1]); 00298 Vector3f b = new Vector3f(position[1]); 00299 b.sub(position[2]); 00300 00301 /*Vector3f a = new Vector3f(position[1]); 00302 a.sub(position[0]); 00303 Vector3f b = new Vector3f(position[2]); 00304 b.sub(position[0]);*/ 00305 Vector3f norm = new Vector3f(); 00306 norm.cross(a, b); 00307 if (norm.lengthSquared() == 0) { 00308 return false; 00309 } 00310 norm.normalize(); 00311 00312 if (avgVertexNorm != null && avgVertexNorm.dot(norm) < 0) 00313 norm.scale(-1f); 00314 00315 this.normalVector = norm; 00316 return true; 00317 } 00318 00336 public boolean intersectsRay(Point3f p1, Point3f p2, Point3f intersectionPoint) { 00337 00338 if (position.length != 3) { 00339 System.out.println("intersectRay not implemented for not triangles!!"); 00340 return false; 00341 } 00342 00343 Vector3d u, v, n; // triangle vectors 00344 Vector3d dir, w0, w; // ray vectors 00345 double r, a, b; // params to calc ray-plane intersect 00346 00347 // get triangle edge vectors and plane normal 00348 u = new Vector3d(position[1]); 00349 u.sub(new Vector3d(position[0])); 00350 v = new Vector3d(position[2]); 00351 v.sub(new Vector3d(position[0])); 00352 00353 n = new Vector3d(); 00354 n.cross(u, v); // Normal vector 00355 if (n.equals(new Vector3d(0, 0, 0))) // triangle is degenerate 00356 return false; // do not deal with this case 00357 00358 dir = new Vector3d(p2);// ray direction vector 00359 dir.sub(new Vector3d(p1)); 00360 00361 w0 = new Vector3d(p1); 00362 w0.sub(new Vector3d(position[0])); 00363 00364 a = -n.dot(w0); 00365 b = n.dot(dir); 00366 // SMALL_NUM 0.00000001 // anything that avoids division overflow 00367 if (Math.abs(b) < 0.00000001) { // ray is parallel to triangle plane 00368 if (a == 0) // ray lies in triangle plane 00369 return false; 00370 00371 return false; // ray disjoint from plane 00372 } 00373 00374 // get intersect point of ray with triangle plane 00375 r = a / b; 00376 00377 // if (r < 0.0) // ray goes away from triangle 00378 // return false; // => no intersect 00379 // for a segment, also test if (r > 1.0) => no intersect 00380 00381 Point3f intersect = intersectionPoint; 00382 00383 if (intersect == null) 00384 intersect = new Point3f(); 00385 00386 intersect.set(dir); // intersect point of ray and plane 00387 intersect.scale((float) r); 00388 intersect.add(p1); 00389 00390 // is I inside T? 00391 double uu, uv, vv, wu, wv, D; 00392 uu = new Vector3d(u).dot(u); 00393 uv = new Vector3d(u).dot(v); 00394 vv = new Vector3d(v).dot(v); 00395 w = new Vector3d(intersect); 00396 w.sub(new Vector3d(position[0])); 00397 wu = new Vector3d(w).dot(u); 00398 wv = new Vector3d(w).dot(v); 00399 D = uv * uv - uu * vv; 00400 00401 // get and test parametric coords 00402 double s, t; 00403 s = (uv * wv - vv * wu) / D; 00404 if (s < 0.0 || s > 1.0) // I is outside T 00405 return false; 00406 t = (uv * wu - uu * wv) / D; 00407 if (t < 0.0 || (s + t) > 1.0) // I is outside T 00408 return false; 00409 00410 return true; // I is in T 00411 } 00412 00421 public boolean isDirectNeighbor(Triangle tr) { 00422 00423 int eqCnt = 0; 00424 boolean isNeighbor = false; 00425 00426 for (int i = 0; i < 3; i++) { 00427 if (i == 2 && eqCnt == 0) 00428 break; // if 2 of 3 points aren't equal, it is no neighbor 00429 Point3f p1 = position[i]; 00430 for (Point3f p2 : tr.position) { 00431 if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) { 00432 // if (p1 == p2) { 00433 eqCnt++; 00434 if (eqCnt == 2) { 00435 isNeighbor = true; 00436 } else if (eqCnt == 3) { 00437 // if triangle has same position but is backface 00438 return false; 00439 } 00440 break; 00441 } 00442 00443 } 00444 } 00445 return isNeighbor; 00446 } 00447 00456 public boolean isAdjacentNeighbor(Triangle tr) { 00457 00458 int eqCnt = 0; 00459 boolean isNeighbor = false; 00460 00461 for (int i = 0; i < 3; i++) { 00462 if (i == 2 && eqCnt == 0) 00463 break; // if 2 of 3 points aren't equal, it is no neighbor 00464 Point3f p1 = position[i]; 00465 for (Point3f p2 : tr.position) { 00466 if (p1 == p2) { 00467 eqCnt++; 00468 if (eqCnt == 2) { 00469 isNeighbor = true; 00470 } 00471 if (eqCnt == 3) { 00472 // if triangle has same position but is backface 00473 isNeighbor = false; 00474 } 00475 break; 00476 } 00477 00478 } 00479 } 00480 return isNeighbor; 00481 } 00482 00487 public void setCornerarea(Vector3f cornerarea) { 00488 this.cornerarea = cornerarea; 00489 } 00490 00497 public void setNeighbors(Set<Triangle> neighbors) { 00498 this.neighbors = neighbors; 00499 } 00500 00507 public void setNormalVector(Vector3f normalVector) { 00508 this.normalVector = normalVector; 00509 } 00510 00517 public void setTexPosition(Point2f[] texPosition) { 00518 this.texPosition = texPosition; 00519 } 00520 00521 @Override 00522 public void updateCentroid() { 00523 centroid = new Point3f(0, 0, 0); 00524 00525 for (int i = 0; i < position.length; i++) { 00526 centroid.add(position[i]); 00527 } 00528 centroid.scale(1f / position.length); 00529 } 00530 00531 }