/*
* 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
/**
* A subclass of WB_Triangle referencing points as array indices.
*/
public class WB_IndexedTriangle implements WB_Triangle {
/** index of first point. */
private int i1;
/** index of second point. */
private int i2;
/** index of third point. */
private final int i3;
/** The points. */
private final WB_Point3d[] points;
/** 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 indexed triangle.
*
* @param i1 index of first point
* @param i2 index of second point
* @param i3 index of third point
* @param points points as WB_Point[]
*/
public WB_IndexedTriangle(final int i1, final int i2, final int i3,
final WB_Point3d[] points) {
this.points = points;
this.i1 = i1;
this.i2 = i2;
this.i3 = i3;
update();
}
/**
* Reverse the triangle.
*/
public void reverse() {
final int t = i1;
i1 = i2;
i2 = t;
}
/*
* (non-Javadoc)
* @see wblut.geom.WB_Triangle#p1()
*/
public WB_Point3d p1() {
return points[i1];
}
/*
* (non-Javadoc)
* @see wblut.geom.WB_Triangle#p2()
*/
public WB_Point3d p2() {
return points[i2];
}
/*
* (non-Javadoc)
* @see wblut.geom.WB_Triangle#p3()
*/
public WB_Point3d p3() {
return points[i3];
}
/**
* I1.
*
* @return the int
*/
public int i1() {
return i1;
}
/*
* (non-Javadoc)
* @see wblut.geom.WB_Triangle#p2()
*/
/**
* I2.
*
* @return the int
*/
public int i2() {
return i2;
}
/*
* (non-Javadoc)
* @see wblut.geom.WB_Triangle#p3()
*/
/**
* I3.
*
* @return the int
*/
public int i3() {
return i3;
}
/**
* Update side lengths and corner angles.
*/
public void update() {
a = WB_Distance.distance(points[i2], points[i3]);
b = WB_Distance.distance(points[i1], points[i3]);
c = WB_Distance.distance(points[i1], points[i2]);
cosA = ((points[i2].x - points[i1].x) * (points[i3].x - points[i1].x)
+ (points[i2].y - points[i1].y) * (points[i3].y - points[i1].y) + (points[i2].z - points[i1].z)
* (points[i3].z - points[i1].z))
/ (b * c);
cosB = ((points[i1].x - points[i2].x) * (points[i3].x - points[i2].x)
+ (points[i1].y - points[i2].y) * (points[i3].y - points[i2].y) + (points[i1].z - points[i2].z)
* (points[i3].z - points[i2].z))
/ (a * c);
cosC = ((points[i2].x - points[i3].x) * (points[i1].x - points[i3].x)
+ (points[i2].y - points[i3].y) * (points[i1].y - points[i3].y) + (points[i2].z - points[i3].z)
* (points[i1].z - points[i3].z))
/ (a * b);
degenerate = WB_Epsilon.isZeroSq(WB_Distance.sqDistanceToLine(
points[i1], points[i2], points[i3]));
}
/**
* Get plane of triangle.
*
* @return WB_Plane
*/
public WB_Plane getPlane() {
final WB_Plane P = new WB_Plane(points[i1], points[i2], points[i3]);
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 = points[i2].subAndCopy(points[i3]);
final WB_Point3d eb = points[i1].subAndCopy(points[i3]);
ea.mult(b * y);
eb.mult(a * x);
ea.add(eb);
ea.div(abc);
ea.add(points[i3]);
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(points[i3].subToVector(points[i1]),
points[i2].subToVector(points[i1]));
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, points[i2].y,
points[i2].z, points[i3].y, points[i3].z);
nv = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.y, p.z, points[i3].y,
points[i3].z, points[i1].y, points[i1].z);
ood = 1.0 / m.x;
} else if (y >= x && y >= z) {
nu = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.x, p.z, points[i2].x,
points[i2].z, points[i3].x, points[i3].z);
nv = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.x, p.z, points[i3].x,
points[i3].z, points[i1].x, points[i1].z);
ood = -1.0 / m.y;
} else {
nu = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.x, p.y, points[i2].x,
points[i2].y, points[i3].x, points[i3].y);
nv = WB_ExplicitTriangle2D.twiceSignedTriArea2D(p.x, p.y, points[i3].x,
points[i3].y, points[i1].x, points[i1].y);
ood = -1.0 / m.z;
}
nu *= ood;
nv *= ood;
return new WB_Point3d(nu, nv, 1 - nu - nv);
}
}