/* * Copyright (c) 2010, Frederik Vanhoutte This library is free software; you can * redistribute it and/or modify it under the terms of the GNU Lesser General * Public License as published by the Free Software Foundation; either version * 2.1 of the License, or (at your option) any later version. * http://creativecommons.org/licenses/LGPL/2.1/ This library is distributed in * the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See * the GNU Lesser General Public License for more details. You should have * received a copy of the GNU Lesser General Public License along with this * library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, * Fifth Floor, Boston, MA 02110-1301 USA */ package wblut.geom; import wblut.WB_Epsilon; import wblut.math.WB_Fast; // TODO: Auto-generated Javadoc /** * 3D Triangle. */ public class WB_ExplicitTriangle implements WB_Triangle { /** First point. */ public WB_Point3d p1; /** Second point. */ public WB_Point3d p2; /** Third point. */ public WB_Point3d p3; /** Length of side a. */ protected double a; /** Length of side b. */ protected double b; /** Length of side c. */ protected double c; /** Cosine of angle A. */ protected double cosA; /** Cosine of angle B. */ protected double cosB; /** Cosine of angle C. */ protected double cosC; /** Is triangle degenerate?. */ protected boolean degenerate; /** * Instantiates a new WB_Triangle. No copies are made. * * @param p1 first point * @param p2 second point * @param p3 third point */ public WB_ExplicitTriangle(final WB_Point3d p1, final WB_Point3d p2, final WB_Point3d p3) { this.p1 = p1; this.p2 = p2; this.p3 = p3; update(); } /** * Instantiates a new WB_Triangle. * * @param p1 first point * @param p2 second point * @param p3 third point * @param copy copy points? */ public WB_ExplicitTriangle(final WB_Point3d p1, final WB_Point3d p2, final WB_Point3d p3, final boolean copy) { if (!copy) { this.p1 = p1; this.p2 = p2; this.p3 = p3; } else { this.p1 = p1.get(); this.p2 = p2.get(); this.p3 = p3.get(); } update(); } /** * Update side lengths and corner angles. */ public void update() { a = WB_Distance.distance(p2, p3); b = WB_Distance.distance(p1, p3); c = WB_Distance.distance(p1, p2); cosA = ((p2.x - p1.x) * (p3.x - p1.x) + (p2.y - p1.y) * (p3.y - p1.y) + (p2.z - p1.z) * (p3.z - p1.z)) / (b * c); cosB = ((p1.x - p2.x) * (p3.x - p2.x) + (p1.y - p2.y) * (p3.y - p2.y) + (p1.z - p2.z) * (p3.z - p2.z)) / (a * c); cosC = ((p2.x - p3.x) * (p1.x - p3.x) + (p2.y - p3.y) * (p1.y - p3.y) + (p2.z - p3.z) * (p1.z - p3.z)) / (a * b); degenerate = WB_Epsilon.isZeroSq(WB_Distance.sqDistanceToLine(p1, p2, p3)); } /** * Get plane of triangle. * * @return WB_Plane */ public WB_Plane getPlane() { final WB_Plane P = new WB_Plane(p1, p2, p3); if (P.getNormal().mag2() < WB_Epsilon.SQEPSILON) { return null; } return P; } /** * Get incenter. * * @return incenter */ public WB_Point3d getCenter() { return getPointFromTrilinear(1, 1, 1); } /** * Get centroid. * * @return centroid */ public WB_Point3d getCentroid() { return getPointFromTrilinear(b * c, c * a, a * b); } /** * Get circumcenter. * * @return circumcenter */ public WB_Point3d getCircumcenter() { return getPointFromTrilinear(cosA, cosB, cosC); } /** * Get orthocenter. * * @return orthocenter */ public WB_Point3d getOrthocenter() { final double a2 = a * a; final double b2 = b * b; final double c2 = c * c; return getPointFromBarycentric((a2 + b2 - c2) * (a2 - b2 + c2), (a2 + b2 - c2) * (-a2 + b2 + c2), (a2 - b2 + c2) * (-a2 + b2 + c2)); } /** * Get point from trilinear coordinates. * * @param x the x * @param y the y * @param z the z * @return point */ public WB_Point3d getPointFromTrilinear(final double x, final double y, final double z) { if (!degenerate) { final double abc = a * x + b * y + c * z; final WB_Point3d ea = p2.subAndCopy(p3); final WB_Point3d eb = p1.subAndCopy(p3); ea.mult(b * y); eb.mult(a * x); ea.add(eb); ea.div(abc); ea.add(p3); return ea; } return null; } /** * Get point from barycentric coordinates. * * @param x the x * @param y the y * @param z the z * @return point */ public WB_Point3d getPointFromBarycentric(final double x, final double y, final double z) { if (!degenerate) { return getPointFromTrilinear(x / a, y / b, z / c); } return null; } /** * Barycentric. * * @param p the p * @return the w b_ point */ public WB_Point3d getBarycentric(final WB_Point3d p) { final WB_Vector3d m = WB_Vector3d.cross(p3.subToVector(p1), p2.subToVector(p1)); double nu, nv, ood; final double x = WB_Fast.abs(m.x); final double y = WB_Fast.abs(m.y); final double z = WB_Fast.abs(m.z); if (x >= y && x >= z) { nu = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.y, p.z, p2.y, p2.z, p3.y, p3.z); nv = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.y, p.z, p3.y, p3.z, p1.y, p1.z); ood = 1.0 / m.x; } else if (y >= x && y >= z) { nu = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.x, p.z, p2.x, p2.z, p3.x, p3.z); nv = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.x, p.z, p3.x, p3.z, p1.x, p1.z); ood = -1.0 / m.y; } else { nu = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.x, p.y, p2.x, p2.y, p3.x, p3.y); nv = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.x, p.y, p3.x, p3.y, p1.x, p1.y); ood = -1.0 / m.z; } nu *= ood; nv *= ood; return new WB_Point3d(nu, nv, 1 - nu - nv); } /* * (non-Javadoc) * @see wblut.geom.WB_Triangle#p1() */ public WB_Point3d p1() { return p1; } /* * (non-Javadoc) * @see wblut.geom.WB_Triangle#p2() */ public WB_Point3d p2() { return p2; } /* * (non-Javadoc) * @see wblut.geom.WB_Triangle#p3() */ public WB_Point3d p3() { return p3; } /** * Gets the area. * * @return the area */ public double getArea() { final WB_Plane P = getPlane(); if (P == null) { return 0.0; } final WB_Normal3d n = getPlane().getNormal(); final double x = WB_Fast.abs(n.x); final double y = WB_Fast.abs(n.y); final double z = WB_Fast.abs(n.z); double area = 0; int coord = 3; if (x >= y && x >= z) { coord = 1; } else if (y >= x && y >= z) { coord = 2; } switch (coord) { case 1: area = (p1.y * (p2.z - p3.z)) + (p2.y * (p3.z - p1.z)) + (p3.y * (p1.z - p2.z)); break; case 2: area = (p1.x * (p2.z - p3.z)) + (p2.x * (p3.z - p1.z)) + (p3.x * (p1.z - p2.z)); break; case 3: area = (p1.x * (p2.y - p3.y)) + (p2.x * (p3.y - p1.y)) + (p3.x * (p1.y - p2.y)); break; } switch (coord) { case 1: area *= (0.5 / x); break; case 2: area *= (0.5 / y); break; case 3: area *= (0.5 / z); } return WB_Fast.abs(area); } }