package ProGAL.geom3d; import java.awt.Color; import ProGAL.geom3d.volumes.LSS; import ProGAL.geom3d.volumes.Tetrahedron; import ProGAL.math.Constants; import ProGAL.math.Matrix; /** * A triangle in (x,y,z)-space represented by the three corner-points. */ public class Triangle implements Simplex{ protected Point p1, p2, p3; protected Shape[] LSSs = new Shape[3]; protected Shape face; /** Construct a triangle using the three specified points as corners */ public Triangle(Point p1, Point p2, Point p3) { this.p1 = p1; this.p2 = p2; this.p3 = p3; } public Triangle(Point[] p) { this.p1 = p[0]; this.p2 = p[1]; this.p3 = p[2]; } /** Get the first corner */ public Point getP1(){ return p1; } /** Get the second corner */ public Point getP2(){ return p2; } /** Get the third corner */ public Point getP3(){ return p3; } /** Get the specified corner of this triangle */ public Point getCorner(int c){ return getPoint(c); } /** Get the specified corner-point of this triangle */ public Point getPoint(int c){ switch(c){ case 0: return p1; case 1: return p2; case 2: return p3; } throw new Error("Badly specified point number ("+c+"). Should be between 0 and 2"); } /** Return the 'dimension' of this object. Required by the interface Simplex. */ public int getDimension() { return 2; } public boolean orient(Point p){ Matrix m = new Matrix(4,4); for(int r=0;r<3;r++){ for(int c=0;c<3;c++){ m.set(r, c, getCorner(r).getCoord(c)); } m.set(r, 3, 1); } for(int c=0;c<3;c++) m.set(3, c, p.getCoord(c)); m.set(3,3,1); double det = m.determinant(); if (Math.abs(det)<Constants.EPSILON) return true; return det<0; } /** Return the center of the triangle. Here average of the corners is used.*/ public Point getCenter() { return new Point( (p1.x()+p2.x()+p3.x())/3, (p1.y()+p2.y()+p3.y())/3, (p1.z()+p2.z()+p3.z())/3 ); } /** Return the area of one side of the triangle. */ public double getArea(){ return 0.5*p1.vectorTo(p2).crossThis(p1.vectorTo(p3)).length(); } /** Return a vector that is normal to this triangle. */ public Vector getNormal() { return p1.vectorTo(p2).crossThis(p1.vectorTo(p3)).normalizeThis(); } /** * Return the circumradius of the triangle. If one side has zero length this method returns * the length of the two remaining sides. */ public double circumradius(){ double a = p1.distance(p2); double b = p1.distance(p3); double c = p2.distance(p3); double s = (a+b+c)/2;//Semiperemiter return a*b*c/(4*Math.sqrt(s*(a+b-s)*(a+c-s)*(b+c-s))); } /** Return the circumcenter of the triangle. * TODO: Test * TODO: Make more efficient (transform to origo with n as z and use 2D formula) */ public Point circumcenter() { Vector n = getNormal(); Point m1 = Point.getMidpoint(p1, p2); Point m2 = Point.getMidpoint(p1, p3); Line l1 = new Line(m1, p1.vectorTo(p2).crossThis(n)); Line l2 = new Line(m2, p1.vectorTo(p3).crossThis(n)); return l1.getIntersection(l2); } public double inradius(){ double a = p1.distance(p2); double b = p1.distance(p3); double c = p2.distance(p3); double s = (a+b+c)/2;//Semiperemiter return Math.sqrt( ((s-a)*(s-b)*(s-c))/s ); } public Point incenter(){ double a = p1.distance(p2); double b = p1.distance(p3); double c = p2.distance(p3); double P = a+b+c; Vector C = p3.toVector().multiplyThis(a); C.addThis(p2.toVector().multiplyThis(b)); C.addThis(p1.toVector().multiplyThis(c)); C.divideThis(P); return C.toPoint(); } public Point getIntersection(Point p, Point q) { Vector dir = new Vector(p, q); //Daisy /* Plane plane = new Plane(p1, p2, p3); Line line = new Line(p, q); Point intersectionPoint = plane.getIntersection(line);*/ //Rasmus Vector u = new Vector(p1, p2); Vector v = new Vector(p1, p3); Vector n = u.cross(v); if (n.isZeroVector()) { System.out.println("Normal is zero"); return null; } // triangle is degenerated Vector w0 = new Vector(p1, p); double a = -n.dot(w0); double b = n.dot(dir); if (Math.abs(b) < Constants.EPSILON) { if (a == 0) { System.out.println("a is zero"); return null; } // ray is in the triangle plane else { System.out.println("a is not zero"); return null; } // ray is not intersecting the plane } double r = a/b; if (r < 0.0) { /*System.out.println("r is less than zero");*/ return null; } // ray goes away from the triangle plane, no intersection // for a segment, also test if r > 1.0. if so, no intersection Point intersection = new Point(p.x() + r*dir.x(), p.y() + r*dir.y(), p.z() + r*dir.z()); if (contains(intersection)) return intersection; else { return null; } } //Daisy public boolean containsPoint(Point p) { return (p1.equals(p) || p2.equals(p) || p3.equals(p)); } public boolean contains(Point p) { //Daisy /* double[] r1 = {p1.getCoord(0), p2.getCoord(0), p3.getCoord(0)}; double[] r2 = {p1.getCoord(1), p2.getCoord(1), p3.getCoord(1)}; double[] r3 = {1, 1, 1}; double[][] rows = {r1, r2, r3}; Matrix orientation = new Matrix(rows); if (orientation.determinant()<0) { System.out.println("Wooh!"); System.out.println("Triangle = "+this.toString()); System.out.println("Point = "+p.toString()); double[] r1_12 = {p1.getCoord(0), p2.getCoord(0), p.getCoord(0)}; double[] r2_12 = {p1.getCoord(1), p2.getCoord(1), p.getCoord(1)}; double[] r3_12 = {1, 1, 1}; double[][] rows12 = {r1_12, r2_12, r3_12}; Matrix orientation12 = new Matrix(rows12); if (orientation12.determinant()<0) { System.out.println("Wooh!"); double[] r1_23 = {p2.getCoord(0), p3.getCoord(0), p.getCoord(0)}; double[] r2_23 = {p2.getCoord(1), p3.getCoord(1), p.getCoord(1)}; double[] r3_23 = {1, 1, 1}; double[][] rows23 = {r1_23, r2_23, r3_23}; Matrix orientation23 = new Matrix(rows23); if (orientation23.determinant()<0) { System.out.println("Wooh!"); double[] r1_31 = {p3.getCoord(0), p1.getCoord(0), p.getCoord(0)}; double[] r2_31 = {p3.getCoord(1), p1.getCoord(1), p.getCoord(1)}; double[] r3_31 = {1, 1, 1}; double[][] rows31 = {r1_31, r2_31, r3_31}; Matrix orientation31 = new Matrix(rows31); if (orientation31.determinant()<0) { System.out.println("Wooh!"); return true; } } } } return false;*/ /* List<Double> xs = new ArrayList<Double>(); xs.add(p1.get(0)); xs.add(p2.get(0)); xs.add(p3.get(0)); List<Double> ys = new ArrayList<Double>(); ys.add(p1.get(1)); ys.add(p2.get(1)); ys.add(p3.get(1)); List<Double> zs = new ArrayList<Double>(); zs.add(p1.get(2)); zs.add(p2.get(2)); zs.add(p3.get(2)); double xMax = Collections.max(xs); double xMin = Collections.min(xs); double yMax = Collections.max(ys); double yMin = Collections.min(ys); double zMax = Collections.max(zs); double zMin = Collections.min(zs); if (xMax > p.get(0) && xMin < p.get(0) && yMax > p.get(1) && yMin < p.get(1) && zMax > p.get(2) && zMin < p.get(2)) return true; else return false;*/ /*double alpha = ((p2.getCoord(1) - p3.getCoord(1))*(p.getCoord(0) - p3.getCoord(0)) + (p3.getCoord(0) - p2.getCoord(0))*(p.getCoord(1) - p3.getCoord(1))) / ((p2.getCoord(1) - p3.getCoord(1))*(p1.getCoord(0) - p3.getCoord(0)) + (p3.getCoord(0) - p2.getCoord(0))*(p1.getCoord(1) - p3.getCoord(1))); System.out.println("Alpha = "+alpha); if (alpha>-Constants.EPSILON) { double beta = ((p3.getCoord(1) - p1.getCoord(1))*(p.getCoord(0) - p3.getCoord(0)) + (p1.getCoord(0) - p3.getCoord(0))*(p.getCoord(1) - p3.getCoord(1))) / ((p2.getCoord(1) - p3.getCoord(1))*(p1.getCoord(0) - p3.getCoord(0)) + (p3.getCoord(0) - p2.getCoord(0))*(p1.getCoord(1) - p3.getCoord(1))); System.out.println("Beta = "+beta); if (beta>-Constants.EPSILON) { double gamma = 1.0 - alpha - beta; if (gamma>-Constants.EPSILON) return true; System.out.println("Gamma = "+gamma); } } return false;*/ //Rasmus Vector u = new Vector(p1, p2); Vector v = new Vector(p1, p3); double uu = u.dot(u); double uv = u.dot(v); double vv = v.dot(v); Vector w = new Vector(p1, p); double wu = w.dot(u); double wv = w.dot(v); double D = uv*uv -uu*vv; double s = (uv*wv -vv*wu)/D; if ((s < 0.0) || (s > 1.0)) return false; double t = (uv*wu -uu*wv)/D; if ((t < 0.0) || (s + t > 1.0)) return false; return true; } /** Returns a string-representation of this triangle formatted with two decimals precision. */ public String toString(){ return toString(2); } /** Returns a string-representation of this triangle formatted with <code>dec</code> decimals precision. */ public String toString(int dec) { return String.format("Triangle[p1=%s,p2=%s,p3=%s]",p1.toString(dec), p2.toString(dec), p3.toString(dec)); } /** Writes this triangle to <code>System.out</code> with 2 decimals precision. */ public void toConsole() { toConsole(2); } /** Writes this triangle to <code>System.out</code> with <code>dec</code> decimals precision. */ public void toConsole(int dec) { System.out.println(toString(dec)); } private boolean isBig(Point p) { return ((Math.abs(p.x()) > 1000) || (Math.abs(p.y()) > 1000) || (Math.abs(p.z()) > 1000)); } public Triangle clone(){ return new Triangle(p1.clone(), p2.clone(), p3.clone()); } }