00001
00002
00003
00004
00005
00006
00007
00008 package edu.tum.cs.vis.model.util;
00009
00010 import java.util.HashSet;
00011 import java.util.Set;
00012 import java.util.concurrent.locks.Lock;
00013
00014 import javax.vecmath.Point2f;
00015 import javax.vecmath.Point3f;
00016 import javax.vecmath.Tuple3f;
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 Triangle(Tuple3f p1, Tuple3f p2, Tuple3f p3) {
00087 this(new Vertex(p1), new Vertex(p2), new Vertex(p3));
00088 }
00089
00106 public Triangle(Tuple3f p1, Vector3f normP1, Tuple3f p2, Vector3f normP2, Tuple3f p3,
00107 Vector3f normP3) {
00108 super(3);
00109 position[0] = new Vertex(p1, normP1);
00110 position[1] = new Vertex(p2, normP2);
00111 position[2] = new Vertex(p3, normP3);
00112 }
00113
00124 public Triangle(Vertex p1, Vertex p2, Vertex p3) {
00125 super(3);
00126 position[0] = p1;
00127 position[1] = p2;
00128 position[2] = p3;
00129 }
00130
00146 public boolean addNeighbor(Triangle neighbor, Lock lock) {
00147 boolean add = false;
00148
00149 if (neighbors.size() >= 3)
00150
00151 return false;
00152
00153 add = isDirectNeighbor(neighbor);
00154
00155 if (add) {
00156 if (lock != null)
00157 lock.lock();
00158
00159 synchronized (neighbors) {
00160 neighbors.add(neighbor);
00161 }
00162 synchronized (neighbor.neighbors) {
00163 neighbor.neighbors.add(this);
00164 }
00165 if (lock != null)
00166 lock.unlock();
00167 }
00168 return add;
00169 }
00170
00178 public void removeNeighbor(Triangle n) {
00179 if (neighbors != null) {
00180 synchronized (neighbors) {
00181 neighbors.remove(n);
00182 }
00183 }
00184 if (n.neighbors != null) {
00185 synchronized (n.neighbors) {
00186 n.neighbors.remove(this);
00187 }
00188 }
00189 }
00190
00200 public void draw(PGraphics g, DrawSettings drawSettings) {
00201 applyColor(g, drawSettings);
00202
00203 if (drawSettings != null && drawSettings.drawType == DrawType.POINTS) {
00204
00205 for (int i = 0; i < position.length; i++) {
00206 if (position[i].overrideColor != null) {
00207 g.stroke(position[i].overrideColor.getRed(),
00208 position[i].overrideColor.getGreen(),
00209 position[i].overrideColor.getBlue());
00210 g.noFill();
00211 } else if (drawSettings.getOverrideColor() == null && position[i].color != null) {
00212 g.stroke(position[i].color.getRed(), position[i].color.getGreen(),
00213 position[i].color.getBlue());
00214 g.noFill();
00215 }
00216 g.point(position[i].x, position[i].y, position[i].z);
00217 }
00218 } else {
00219 g.beginShape(PConstants.TRIANGLES);
00220 if (appearance == null || appearance.getImageReference() == null
00221 || drawSettings.getOverrideColor() != null
00222 || position[0].overrideColor != null ) {
00223
00224
00225 for (int i = 0; i < position.length; i++) {
00226
00227 if (drawSettings != null && drawSettings.drawType == DrawType.LINES) {
00228 if (position[i].overrideColor != null) {
00229 g.stroke(position[i].overrideColor.getRed(),
00230 position[i].overrideColor.getGreen(),
00231 position[i].overrideColor.getBlue());
00232 g.noFill();
00233 } else if (drawSettings.getOverrideColor() == null
00234 && position[i].color != null) {
00235 g.stroke(position[i].color.getRed(), position[i].color.getGreen(),
00236 position[i].color.getBlue());
00237 g.noFill();
00238 }
00239 } else {
00240 if (position[i].overrideColor != null) {
00241 g.fill(position[i].overrideColor.getRed(),
00242 position[i].overrideColor.getGreen(),
00243 position[i].overrideColor.getBlue());
00244 } else if ((drawSettings == null || drawSettings.getOverrideColor() == null)
00245 && position[i].color != null) {
00246 g.fill(position[i].color.getRed(), position[i].color.getGreen(),
00247 position[i].color.getBlue());
00248 }
00249 }
00250
00251 if (position[i].getNormalVector() != null)
00252 g.normal(position[i].getNormalVector().x, position[i].getNormalVector().y,
00253 position[i].getNormalVector().z);
00254 g.vertex(position[i].x, position[i].y, position[i].z);
00255 }
00256
00257 } else {
00258
00259 g.texture(appearance.getImageReference());
00260
00261 for (int i = 0; i < position.length; i++) {
00262
00263 g.vertex(position[i].x, position[i].y, position[i].z, texPosition[i].x,
00264 texPosition[i].y);
00265
00266 }
00267
00268 }
00269 g.endShape();
00270 }
00271 }
00272
00278 public float getArea() {
00279 if (position.length == 3) {
00280
00281 Point3f v = (Point3f) position[1].clone();
00282 v.sub(position[0]);
00283 Point3f w = (Point3f) position[2].clone();
00284 w.sub(position[0]);
00285
00286 Vector3f v1 = new Vector3f(v);
00287 Vector3f w1 = new Vector3f(w);
00288
00289 Vector3f cross = new Vector3f();
00290 cross.cross(v1, w1);
00291 return cross.length() / 2f;
00292 }
00293
00294 logger.error("getArea not implemented for " + position.length + "-Triangle");
00295 return 0;
00296 }
00297
00303 public Point3f getCentroid() {
00304 return centroid;
00305 }
00306
00312 public Vector3f getCornerarea() {
00313 return cornerarea;
00314 }
00315
00321 public Set<Triangle> getNeighbors() {
00322 return neighbors;
00323 }
00324
00333 public double getDihedralAngle(Triangle t) {
00334 double dot = this.getNormalVector().dot(t.getNormalVector());
00335 dot = Math.max(-1, dot);
00336 dot = Math.min(1, dot);
00337 return Math.acos(dot);
00338 }
00339
00345 public Vector3f getNormalVector() {
00346 return normalVector;
00347 }
00348
00354 public Point2f[] getTexPosition() {
00355 return texPosition;
00356 }
00357
00368 public boolean intersectsRay(Point3f rayStart, Point3f rayEnd) {
00369 return intersectsRay(rayStart, rayEnd, null);
00370 }
00371
00377 public boolean calculateNormalVector() {
00378
00379 Vector3f avgVertexNorm = new Vector3f();
00380 for (int i = 0; i < 3; i++) {
00381 if (position[i].getNormalVector() == null) {
00382 avgVertexNorm = null;
00383 break;
00384 }
00385 avgVertexNorm.add(position[i].getNormalVector());
00386 }
00387 if (avgVertexNorm != null) {
00388 avgVertexNorm.scale(1f / 3f);
00389 }
00390
00391 Vector3f a = new Vector3f(position[0]);
00392 a.sub(position[1]);
00393 Vector3f b = new Vector3f(position[1]);
00394 b.sub(position[2]);
00395
00396
00397
00398
00399
00400 Vector3f norm = new Vector3f();
00401 norm.cross(a, b);
00402 if (norm.lengthSquared() == 0) {
00403 return false;
00404 }
00405 norm.normalize();
00406
00407 if (avgVertexNorm != null && avgVertexNorm.dot(norm) < 0)
00408 norm.scale(-1f);
00409
00410 this.normalVector = norm;
00411 return true;
00412 }
00413
00431 public boolean intersectsRay(Point3f p1, Point3f p2, Point3f intersectionPoint) {
00432
00433 if (position.length != 3) {
00434 System.out.println("intersectRay not implemented for not triangles!!");
00435 return false;
00436 }
00437
00438 Vector3d u, v, n;
00439 Vector3d dir, w0, w;
00440 double r, a, b;
00441
00442
00443 u = new Vector3d(position[1]);
00444 u.sub(new Vector3d(position[0]));
00445 v = new Vector3d(position[2]);
00446 v.sub(new Vector3d(position[0]));
00447
00448 n = new Vector3d();
00449 n.cross(u, v);
00450 if (n.equals(new Vector3d(0, 0, 0)))
00451 return false;
00452
00453 dir = new Vector3d(p2);
00454 dir.sub(new Vector3d(p1));
00455
00456 w0 = new Vector3d(p1);
00457 w0.sub(new Vector3d(position[0]));
00458
00459 a = -n.dot(w0);
00460 b = n.dot(dir);
00461
00462 if (Math.abs(b) < 0.00000001) {
00463 if (a == 0)
00464 return false;
00465
00466 return false;
00467 }
00468
00469
00470 r = a / b;
00471
00472
00473
00474
00475
00476 Point3f intersect = intersectionPoint;
00477
00478 if (intersect == null)
00479 intersect = new Point3f();
00480
00481 intersect.set(dir);
00482 intersect.scale((float) r);
00483 intersect.add(p1);
00484
00485
00486 double uu, uv, vv, wu, wv, D;
00487 uu = new Vector3d(u).dot(u);
00488 uv = new Vector3d(u).dot(v);
00489 vv = new Vector3d(v).dot(v);
00490 w = new Vector3d(intersect);
00491 w.sub(new Vector3d(position[0]));
00492 wu = new Vector3d(w).dot(u);
00493 wv = new Vector3d(w).dot(v);
00494 D = uv * uv - uu * vv;
00495
00496
00497 double s, t;
00498 s = (uv * wv - vv * wu) / D;
00499 if (s < 0.0 || s > 1.0)
00500 return false;
00501 t = (uv * wu - uu * wv) / D;
00502 if (t < 0.0 || (s + t) > 1.0)
00503 return false;
00504
00505 return true;
00506 }
00507
00516 public boolean isDirectNeighbor(Triangle tr) {
00517
00518 int eqCnt = 0;
00519 boolean isNeighbor = false;
00520
00521 for (int i = 0; i < 3; i++) {
00522 if (i == 2 && eqCnt == 0)
00523 break;
00524 Point3f p1 = position[i];
00525 for (Point3f p2 : tr.position) {
00526 if (p1.x == p2.x && p1.y == p2.y && p1.z == p2.z) {
00527 eqCnt++;
00528 if (eqCnt == 2) {
00529 isNeighbor = true;
00530 } else if (eqCnt == 3) {
00531
00532 return false;
00533 }
00534 break;
00535 }
00536
00537 }
00538 }
00539 return isNeighbor;
00540 }
00541
00550 public boolean isAdjacentNeighbor(Triangle tr) {
00551
00552 int eqCnt = 0;
00553 boolean isNeighbor = false;
00554
00555 for (int i = 0; i < 3; i++) {
00556 if (i == 2 && eqCnt == 0)
00557 break;
00558 Point3f p1 = position[i];
00559 for (Point3f p2 : tr.position) {
00560 if (p1 == p2) {
00561 eqCnt++;
00562 if (eqCnt == 2) {
00563 isNeighbor = true;
00564 }
00565 if (eqCnt == 3) {
00566
00567 isNeighbor = false;
00568 }
00569 break;
00570 }
00571
00572 }
00573 }
00574 return isNeighbor;
00575 }
00576
00581 public void setCornerarea(Vector3f cornerarea) {
00582 this.cornerarea = cornerarea;
00583 }
00584
00591 public void setNeighbors(Set<Triangle> neighbors) {
00592 this.neighbors = neighbors;
00593 }
00594
00601 public void setNormalVector(Vector3f normalVector) {
00602 this.normalVector = normalVector;
00603 }
00604
00611 public void setTexPosition(Point2f[] texPosition) {
00612 this.texPosition = texPosition;
00613 }
00614
00615 @Override
00616 public void updateCentroid() {
00617 centroid = new Point3f(0, 0, 0);
00618
00619 for (int i = 0; i < position.length; i++) {
00620 centroid.add(position[i]);
00621 }
00622 centroid.scale(1f / position.length);
00623 }
00624
00625 }