gov.nasa.worldwind.geom.Triangle Maven / Gradle / Ivy
The newest version!
/*
* Copyright (C) 2012 United States Government as represented by the Administrator of the
* National Aeronautics and Space Administration.
* All Rights Reserved.
*/
package gov.nasa.worldwind.geom;
import gov.nasa.worldwind.util.Logging;
import com.jogamp.opengl.GL;
import java.nio.*;
import java.util.*;
/**
* Provides operations on triangles.
*
* @author Eric Dalgliesh 30/11/2006
* @version $Id: Triangle.java 1171 2013-02-11 21:45:02Z dcollins $
*/
public class Triangle
{
private static final double EPSILON = 0.0000001; // used in intersects method
private final Vec4 a;
private final Vec4 b;
private final Vec4 c;
/**
* Construct a triangle from three counter-clockwise ordered vertices. The front face of the triangle is determined
* by the right-hand rule.
*
* @param a the first vertex.
* @param b the second vertex.
* @param c the third vertex.
*
* @throws IllegalArgumentException if any vertex is null.
*/
public Triangle(Vec4 a, Vec4 b, Vec4 c)
{
if (a == null || b == null || c == null)
{
String msg = Logging.getMessage("nullValue.PointIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
this.a = a;
this.b = b;
this.c = c;
}
/**
* Returns the first vertex.
*
* @return the first vertex.
*/
public Vec4 getA()
{
return this.a;
}
/**
* Returns the second vertex.
*
* @return the second vertex.
*/
public Vec4 getB()
{
return this.b;
}
/**
* Returns the third vertex.
*
* @return the third vertex.
*/
public Vec4 getC()
{
return this.c;
}
// private Plane getPlane()
// {
// Vector ab, ac;
// ab = new Vector(this.b.subtract(this.a)).normalize();
// ac = new Vector(this.c.subtract(this.a)).normalize();
//
// Vector n = new Vector(new Point(ab.x(), ab.y(), ab.z(), ab.w()).cross(new Point(ac.x(), ac.y(), ac.z(), ac.w())));
//
// return new gov.nasa.worldwind.geom.Plane(n);
// }
// private Point temporaryIntersectPlaneAndLine(Line line, Plane plane)
// {
// Vector n = line.getDirection();
// Point v0 = Point.fromOriginAndDirection(plane.getDistance(), plane.getNormal(), Point.ZERO);
// Point p0 = line.getPointAt(0);
// Point p1 = line.getPointAt(1);
//
// double r1 = n.dot(v0.subtract(p0))/n.dot(p1.subtract(p0));
// if(r1 >= 0)
// return line.getPointAt(r1);
// return null;
// }
//
// private Triangle divide(double d)
// {
// d = 1/d;
// return new Triangle(this.a.multiply(d), this.b.multiply(d), this.c.multiply(d));
// }
/**
* Indicates whether a specified point is on the triangle.
*
* @param p the point to test. If null, the method returns false.
*
* @return true if the point is on the triangle, otherwise false.
*/
public boolean contains(Vec4 p)
{
if (p == null)
return false;
// Compute vectors
Vec4 v0 = this.c.subtract3(this.a);
Vec4 v1 = this.b.subtract3(this.a);
Vec4 v2 = p.subtract3(this.a);
// Compute dot products
double dot00 = v0.dotSelf3();
double dot01 = v0.dot3(v1);
double dot02 = v0.dot3(v2);
double dot11 = v1.dotSelf3();
double dot12 = v1.dot3(v2);
// Compute barycentric coordinates
double det = (dot00 * dot11 - dot01 * dot01);
double detInv = 1 / det;
double u = (dot11 * dot02 - dot01 * dot12) * detInv;
double v = (dot00 * dot12 - dot01 * dot02) * detInv;
// Check if point is contained in triangle (including edges and vertices)
return (u >= 0d) && (v >= 0d) && (u + v <= 1d);
// Check if point is contained inside triangle (NOT including edges or vertices)
// return (u > 0d) && (v > 0d) && (u + v < 1d);
}
/**
* Determine the intersection of the triangle with a specified line.
*
* @param line the line to test.
*
* @return the point of intersection if the line intersects the triangle, otherwise null.
*
* @throws IllegalArgumentException if the line is null.
*/
public Vec4 intersect(Line line)
{
Intersection intersection = intersect(line, this.a, this.b, this.c);
return intersection != null ? intersection.getIntersectionPoint() : null;
}
/**
* Determines the intersection of a specified line with a specified triangle. The triangle is specified by three
* points ordered counterclockwise. The triangle's front face is determined by the right-hand rule.
*
* @param line the line to test.
* @param a the first vertex of the triangle.
* @param b the second vertex of the triangle.
* @param c the third vertex of the triangle.
*
* @return the point of intersection if the line intersects the triangle, otherwise null.
*
* @throws IllegalArgumentException if the line or any of the triangle vertices is null.
*/
public static Intersection intersect(Line line, Vec4 a, Vec4 b, Vec4 c)
{
return intersect(line, a.x, a.y, a.z, b.x, b.y, b.z, c.x, c.y, c.z);
}
/**
* Determines the intersection of a specified line with a triangle specified by individual coordinates.
*
* @param line the line to test.
* @param vax the X coordinate of the first vertex of the triangle.
* @param vay the Y coordinate of the first vertex of the triangle.
* @param vaz the Z coordinate of the first vertex of the triangle.
* @param vbx the X coordinate of the second vertex of the triangle.
* @param vby the Y coordinate of the second vertex of the triangle.
* @param vbz the Z coordinate of the second vertex of the triangle.
* @param vcx the X coordinate of the third vertex of the triangle.
* @param vcy the Y coordinate of the third vertex of the triangle.
* @param vcz the Z coordinate of the third vertex of the triangle.
*
* @return the point of intersection if the line intersects the triangle, otherwise null.
*/
public static Intersection intersect(Line line,
double vax, double vay, double vaz, double vbx, double vby, double vbz, double vcx, double vcy, double vcz)
{
if (line == null)
{
String msg = Logging.getMessage("nullValue.LineIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
// taken from Moller and Trumbore
// http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/
// Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf
Vec4 origin = line.getOrigin();
Vec4 dir = line.getDirection();
// find vectors for two edges sharing Point a: vb - va and vc - va
double edge1x = vbx - vax;
double edge1y = vby - vay;
double edge1z = vbz - vaz;
double edge2x = vcx - vax;
double edge2y = vcy - vay;
double edge2z = vcz - vaz;
// Start calculating determinant. Compute cross product of line direction and edge2.
double pvecx = (dir.y * edge2z) - (dir.z * edge2y);
double pvecy = (dir.z * edge2x) - (dir.x * edge2z);
double pvecz = (dir.x * edge2y) - (dir.y * edge2x);
// Get determinant.
double det = edge1x * pvecx + edge1y * pvecy + edge1z * pvecz; // edge1 dot pvec
if (det > -EPSILON && det < EPSILON) // If det is near zero, then ray lies on plane of triangle
return null;
double detInv = 1d / det;
// Distance from vertA to ray origin: origin - va
double tvecx = origin.x - vax;
double tvecy = origin.y - vay;
double tvecz = origin.z - vaz;
// Calculate u parameter and test bounds: 1/det * tvec dot pvec
double u = detInv * (tvecx * pvecx + tvecy * pvecy + tvecz * pvecz);
if (u < 0 || u > 1)
return null;
// Prepare to test v parameter: tvec cross edge1
double qvecx = (tvecy * edge1z) - (tvecz * edge1y);
double qvecy = (tvecz * edge1x) - (tvecx * edge1z);
double qvecz = (tvecx * edge1y) - (tvecy * edge1x);
// Calculate v parameter and test bounds: 1/det * dir dot qvec
double v = detInv * (dir.x * qvecx + dir.y * qvecy + dir.z * qvecz);
if (v < 0 || u + v > 1)
return null;
// Calculate the point of intersection on the line: t = 1/det * edge2 dot qvec;
double t = detInv * (edge2x * qvecx + edge2y * qvecy + edge2z * qvecz);
if (t < 0)
return null;
return new Intersection(line.getPointAt(t), t, false);
}
/**
* Compute the intersections of a line with a triangle strip.
*
* @param line the line to intersect.
* @param vertices the tri-strip vertices.
* @param indices the indices forming the tri-strip.
*
* @return the list of intersections with the line and the tri-strip, or null if there are no intersections.
*
* @throws IllegalArgumentException if the line, vertex buffer or index buffer is null.
*/
public static List intersectTriStrip(final Line line, FloatBuffer vertices, IntBuffer indices)
{
if (line == null)
{
String msg = Logging.getMessage("nullValue.LineIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (vertices == null || indices == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
List intersections = null;
for (int n = indices.position(); n < indices.limit() - 2; n++)
{
Intersection intersection;
int i = indices.get(n) * 3;
int j = indices.get(n + 1) * 3;
int k = indices.get(n + 2) * 3;
// The triangle intersect method detects front and back face intersections so there's no reason to
// order the vertices.
intersection = intersect(line,
vertices.get(i), vertices.get(i + 1), vertices.get(i + 2),
vertices.get(j), vertices.get(j + 1), vertices.get(j + 2),
vertices.get(k), vertices.get(k + 1), vertices.get(k + 2));
if (intersection != null)
{
if (intersections == null)
intersections = new ArrayList();
intersections.add(intersection);
}
}
return intersections;
}
/**
* Compute the intersections of a line with a triangle strip.
*
* @param line the line to intersect.
* @param vertices the tri-strip vertices.
* @param indices the indices forming the tri-strip.
*
* @return the list of intersections with the line and the triangle strip, or null if there are no intersections.
*
* @throws IllegalArgumentException if the line, vertex array or index buffer is null.
*/
public static List intersectTriStrip(final Line line, Vec4[] vertices, IntBuffer indices)
{
if (line == null)
{
String msg = Logging.getMessage("nullValue.LineIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (vertices == null)
{
String msg = Logging.getMessage("nullValue.ArrayIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (indices == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
List intersections = null;
for (int n = indices.position(); n < indices.limit() - 1; n++)
{
Intersection intersection;
int i = indices.get(n) * 3;
int j = indices.get(n + 1) * 3;
int k = indices.get(n + 2) * 3;
// The triangle intersect method detects front and back face intersections so there's no reason to
// order the vertices.
intersection = intersect(line, vertices[i], vertices[j], vertices[k]);
if (intersection != null)
{
if (intersections == null)
intersections = new ArrayList();
intersections.add(intersection);
}
}
return intersections;
}
/**
* Compute the intersections of a line with a triangle fan.
*
* @param line the line to intersect.
* @param vertices the tri-fan vertices.
* @param indices the indices forming the tri-fan.
*
* @return the list of intersections with the line and the triangle fan, or null if there are no intersections.
*
* @throws IllegalArgumentException if the line, vertex buffer or index buffer is null.
*/
public static List intersectTriFan(final Line line, FloatBuffer vertices, IntBuffer indices)
{
if (line == null)
{
String msg = Logging.getMessage("nullValue.LineIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (vertices == null || indices == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
List intersections = null;
// Get the index and then the values of the constant vertex.
int k = indices.get(); // note that this increments the index buffer position
float v0x = vertices.get(k * 3);
float v0y = vertices.get(k * 3 + 1);
float v0z = vertices.get(k * 3 + 2);
// Starting with the second position in the index buffer, get subsequent indices and vertices.
for (int n = indices.position(); n < indices.limit() - 1; n++)
{
Intersection intersection;
int i = indices.get(n) * 3;
int j = indices.get(n + 1) * 3;
// The triangle intersect method detects front and back face intersections so there's no reason to
// order the vertices.
intersection = intersect(line,
v0x, v0y, v0z,
vertices.get(i), vertices.get(i + 1), vertices.get(i + 2),
vertices.get(j), vertices.get(j + 1), vertices.get(j + 2));
if (intersection != null)
{
if (intersections == null)
intersections = new ArrayList();
intersections.add(intersection);
}
}
return intersections;
}
/**
* Compute the intersections of a line with a triangle fan.
*
* @param line the line to intersect.
* @param vertices the tri-fan vertices.
* @param indices the indices forming the tri-fan.
*
* @return the list of intersections with the line and the triangle fan, or null if there are no intersections.
*
* @throws IllegalArgumentException if the line, vertex array or index buffer is null.
*/
public static List intersectTriFan(final Line line, Vec4[] vertices, IntBuffer indices)
{
if (line == null)
{
String msg = Logging.getMessage("nullValue.LineIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (vertices == null)
{
String msg = Logging.getMessage("nullValue.ArrayIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (indices == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
List intersections = null;
Vec4 v0 = vertices[0];
for (int n = indices.position() + 1; n < indices.limit() - 1; n++)
{
Intersection intersection;
Vec4 v1 = vertices[indices.get(n)];
Vec4 v2 = vertices[indices.get(n + 1)];
// The triangle intersect method detects front and back face intersections so there's no reason to
// order the vertices.
intersection = intersect(line, v0, v1, v2);
if (intersection != null)
{
if (intersections == null)
intersections = new ArrayList();
intersections.add(intersection);
}
}
return intersections;
}
/**
* Compute the intersections of a line with a collection of triangles.
*
* @param line the line to intersect.
* @param vertices the triangles, arranged in a buffer as GL_TRIANGLES (9 floats per triangle).
*
* @return the list of intersections with the line and the triangles, or null if there are no intersections.
*
* @throws IllegalArgumentException if the line or vertex buffer is null.
*/
public static List intersectTriangles(final Line line, FloatBuffer vertices)
{
if (line == null)
{
String msg = Logging.getMessage("nullValue.LineIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (vertices == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
List intersections = null;
vertices.rewind();
while (vertices.limit() - vertices.position() >= 9)
{
Intersection intersection = intersect(line,
vertices.get(), vertices.get(), vertices.get(),
vertices.get(), vertices.get(), vertices.get(),
vertices.get(), vertices.get(), vertices.get());
if (intersection != null)
{
if (intersections == null)
intersections = new ArrayList();
intersections.add(intersection);
}
}
return intersections;
}
/**
* Compute the intersections of a line with a collection of triangles.
*
* @param line the line to intersect.
* @param vertices the triangles, arranged in a buffer as GL_TRIANGLES (9 floats per triangle).
* @param indices the indices forming the triangles.
*
* @return the list of intersections with the line and the triangle fan, or null if there are no intersections.
*
* @throws IllegalArgumentException if the line, vertex buffer or index buffer is null.
*/
public static List intersectTriangles(final Line line, FloatBuffer vertices, IntBuffer indices)
{
if (line == null)
{
String msg = Logging.getMessage("nullValue.LineIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (vertices == null || indices == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
List intersections = null;
for (int n = indices.position(); n < indices.limit(); n += 3)
{
Intersection intersection;
int i = indices.get(n) * 3;
int j = indices.get(n + 1) * 3;
int k = indices.get(n + 2) * 3;
intersection = intersect(line,
vertices.get(i), vertices.get(i + 1), vertices.get(i + 2),
vertices.get(j), vertices.get(j + 1), vertices.get(j + 2),
vertices.get(k), vertices.get(k + 1), vertices.get(k + 2));
if (intersection != null)
{
if (intersections == null)
intersections = new ArrayList();
intersections.add(intersection);
}
}
return intersections;
}
/**
* Compute the intersections of a line with a triangle collection.
*
* @param line the line to intersect.
* @param vertices the tri-fan vertices, in the order x, y, z, x, y, z, ...
* @param indices the indices forming the tri-fan.
* @param triangleType the type of triangle collection, either GL.GL_TRIANGLE_STRIP or GL.GL_TRIANGLE_FAN.
*
* @return the list of intersections with the line and the triangle fan, or null if there are no intersections.
*/
public static List intersectTriangleTypes(final Line line, FloatBuffer vertices, IntBuffer indices,
int triangleType)
{
if (triangleType == GL.GL_TRIANGLES)
return Triangle.intersectTriangles(line, vertices, indices);
else if (triangleType == GL.GL_TRIANGLE_STRIP)
return Triangle.intersectTriStrip(line, vertices, indices);
else if (triangleType == GL.GL_TRIANGLE_FAN)
return Triangle.intersectTriFan(line, vertices, indices);
return null;
}
/**
* Expands a buffer of indexed triangle vertices to a buffer of non-indexed triangle vertices.
*
* @param indices the triangle indices.
* @param inBuf the vertex buffer the indices refer to, in the order x, y, z, x, y, z, ...
* @param outBuf the buffer in which to place the expanded triangle vertices. The buffer must have a limit
* sufficient to hold the output vertices.
*
* @throws IllegalArgumentException if the index list or the input or output buffer is null, or if the output buffer
* size is insufficient.
*/
public static void expandTriangles(List indices, FloatBuffer inBuf, FloatBuffer outBuf)
{
if (indices == null)
{
String msg = Logging.getMessage("nullValue.ListIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (inBuf == null || outBuf == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
int nunTriangles = indices.size() / 3;
if (nunTriangles * 3 * 3 > outBuf.limit() - outBuf.position())
{
String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position());
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
for (int i = 0; i < indices.size(); i += 3)
{
int k = indices.get(i) * 3;
outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2));
k = indices.get(i + 1) * 3;
outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2));
k = indices.get(i + 2) * 3;
outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2));
}
}
/**
* Expands a buffer of indexed triangle fan vertices to a buffer of non-indexed general-triangle vertices.
*
* @param indices the triangle indices.
* @param inBuf the vertex buffer the indices refer to, in the order x, y, z, x, y, z, ...
* @param outBuf the buffer in which to place the expanded triangle vertices. The buffer must have a limit
* sufficient to hold the output vertices.
*
* @throws IllegalArgumentException if the index list or the input or output buffer is null, or if the output buffer
* size is insufficient.
*/
public static void expandTriangleFan(List indices, FloatBuffer inBuf, FloatBuffer outBuf)
{
if (indices == null)
{
String msg = Logging.getMessage("nullValue.ListIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (inBuf == null || outBuf == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
int nunTriangles = indices.size() - 2;
if (nunTriangles * 3 * 3 > outBuf.limit() - outBuf.position())
{
String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position());
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
int k = indices.get(0) * 3;
float v0x = inBuf.get(k);
float v0y = inBuf.get(k + 1);
float v0z = inBuf.get(k + 2);
for (int i = 1; i < indices.size() - 1; i++)
{
outBuf.put(v0x).put(v0y).put(v0z);
k = indices.get(i) * 3;
outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2));
k = indices.get(i + 1) * 3;
outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2));
}
}
/**
* Expands a buffer of indexed triangle strip vertices to a buffer of non-indexed general-triangle vertices.
*
* @param indices the triangle indices.
* @param inBuf the vertex buffer the indices refer to, in the order x, y, z, x, y, z, ...
* @param outBuf the buffer in which to place the expanded triangle vertices. The buffer must have a limit
* sufficient to hold the output vertices.
*
* @throws IllegalArgumentException if the index list or the input or output buffer is null, or if the output buffer
* size is insufficient.
*/
public static void expandTriangleStrip(List indices, FloatBuffer inBuf, FloatBuffer outBuf)
{
if (indices == null)
{
String msg = Logging.getMessage("nullValue.ListIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (inBuf == null || outBuf == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
int nunTriangles = indices.size() - 2;
if (nunTriangles * 3 * 3 > outBuf.limit() - outBuf.position())
{
String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position());
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
for (int i = 2; i < indices.size(); i++)
{
int k = indices.get(i - 2) * 3;
outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2));
k = indices.get(i % 2 == 0 ? i : i - 1) * 3;
outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2));
k = indices.get(i % 2 == 0 ? i - 1 : i) * 3;
outBuf.put(inBuf.get(k)).put(inBuf.get(k + 1)).put(inBuf.get(k + 2));
}
}
public static void expandTriangles(List indices, IntBuffer outBuf)
{
if (indices == null)
{
String msg = Logging.getMessage("nullValue.ListIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (outBuf == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
int numTriangles = indices.size() / 3;
if (numTriangles * 3 > outBuf.limit() - outBuf.position())
{
String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position());
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
for (int i = 0; i < indices.size(); i++)
{
outBuf.put(indices.get(i));
}
}
public static void expandTriangleFan(List indices, IntBuffer outBuf)
{
if (indices == null)
{
String msg = Logging.getMessage("nullValue.ListIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (outBuf == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
int nunTriangles = indices.size() - 2;
if (nunTriangles * 3 > outBuf.limit() - outBuf.position())
{
String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position());
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
int k0 = indices.get(0);
for (int i = 1; i < indices.size() - 1; i++)
{
outBuf.put(k0);
outBuf.put(indices.get(i));
outBuf.put(indices.get(i + 1));
}
}
public static void expandTriangleStrip(List indices, IntBuffer outBuf)
{
if (indices == null)
{
String msg = Logging.getMessage("nullValue.ListIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
if (outBuf == null)
{
String msg = Logging.getMessage("nullValue.BufferIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
int nunTriangles = indices.size() - 2;
if (nunTriangles * 3 > outBuf.limit() - outBuf.position())
{
String msg = Logging.getMessage("generic.BufferSize", outBuf.limit() - outBuf.position());
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
for (int i = 2; i < indices.size(); i++)
{
outBuf.put(indices.get(i - 2));
outBuf.put(indices.get(i % 2 == 0 ? i - 1 : i));
outBuf.put(indices.get(i % 2 == 0 ? i : i - 1));
}
}
/**
* Defines a line segment representing the intersection of a line with and in the plane of a triangle. Used only
* within {@link #intersectTriangles}.
*/
protected static class TriangleIntersection
{
public Vec4 p0; // the first point of the line
public Vec4 p1; // the second point of the line
public double s0; // the distance along the line to the first intersection with the triangle
public double s1; // the distance along the line to the second intersection with the triangle
}
/**
* Intersects two triangles and returns their intersection vertices.
*
* @param v the Cartesian coordinates of the first triangle.
* @param u the Cartesian coordinates of the second triangle.
* @param intersectionVertices a pre-allocated two-element array in which the intersection vertices, if any, are
* returned.
*
* @return -1 if there is no intersection, 1 if there is an intersection, or 0 if the triangles are co-planar.
*/
public static int intersectTriangles(Vec4[] v, Vec4[] u, Vec4[] intersectionVertices)
{
// Taken from http://jgt.akpeters.com/papers/Moller97/tritri.html#ISECTLINE
// Compute plane equation of first triangle: n1 * x + d1 = 0.
double e1x = v[1].x - v[0].x;
double e1y = v[1].y - v[0].y;
double e1z = v[1].z - v[0].z;
double e2x = v[2].x - v[0].x;
double e2y = v[2].y - v[0].y;
double e2z = v[2].z - v[0].z;
Vec4 n1 = new Vec4(e1y * e2z - e1z * e2y, e1z * e2x - e1x * e2z, e1x * e2y - e1y * e2x);
double d1 = -n1.dot3(v[0]);
// Evaluate second triangle with plane equation 1 to determine signed distances to the plane.
double du0 = n1.dot3(u[0]) + d1;
double du1 = n1.dot3(u[1]) + d1;
double du2 = n1.dot3(u[2]) + d1;
// Coplanarity robustness check.
if (Math.abs(du0) < EPSILON)
du0 = 0;
if (Math.abs(du1) < EPSILON)
du1 = 0;
if (Math.abs(du2) < EPSILON)
du2 = 0;
double du0du1 = du0 * du1;
double du0du2 = du0 * du2;
if (du0du1 > 0 && du0du2 > 0) // same sign on all of them + != 0 ==> no intersection
return -1;
// Compute plane equation of second triangle: n2 * x + d2 = 0
e1x = u[1].x - u[0].x;
e1y = u[1].y - u[0].y;
e1z = u[1].z - u[0].z;
e2x = u[2].x - u[0].x;
e2y = u[2].y - u[0].y;
e2z = u[2].z - u[0].z;
Vec4 n2 = new Vec4(e1y * e2z - e1z * e2y, e1z * e2x - e1x * e2z, e1x * e2y - e1y * e2x);
double d2 = -n2.dot3(u[0]);
// Evaluate first triangle with plane equation 2 to determine signed distances to the plane.
double dv0 = n2.dot3(v[0]) + d2;
double dv1 = n2.dot3(v[1]) + d2;
double dv2 = n2.dot3(v[2]) + d2;
// Coplanarity robustness check.
if (Math.abs(dv0) < EPSILON)
dv0 = 0;
if (Math.abs(dv1) < EPSILON)
dv1 = 0;
if (Math.abs(dv2) < EPSILON)
dv2 = 0;
double dv0dv1 = dv0 * dv1;
double dv0dv2 = dv0 * dv2;
if (dv0dv1 > 0 && dv0dv2 > 0) // same sign on all of them + != 0 ==> no intersection
return -1;
// Compute direction of intersection line.
Vec4 ld = n1.cross3(n2);
// Compute an index to the largest component of line direction.
double max = Math.abs(ld.x);
int index = 0;
double b = Math.abs(ld.y);
double c = Math.abs(ld.z);
if (b > max)
{
max = b;
index = 1;
}
if (c > max)
{
index = 2;
}
// This is the simplified projection onto the line of intersection.
double vp0 = v[0].x;
double vp1 = v[1].x;
double vp2 = v[2].x;
double up0 = u[0].x;
double up1 = u[1].x;
double up2 = u[2].x;
if (index == 1)
{
vp0 = v[0].y;
vp1 = v[1].y;
vp2 = v[2].y;
up0 = u[0].y;
up1 = u[1].y;
up2 = u[2].y;
}
else if (index == 2)
{
vp0 = v[0].z;
vp1 = v[1].z;
vp2 = v[2].z;
up0 = u[0].z;
up1 = u[1].z;
up2 = u[2].z;
}
// Compute interval for triangle 1.
TriangleIntersection isectA = compute_intervals_isectline(v, vp0, vp1, vp2, dv0, dv1, dv2, dv0dv1, dv0dv2);
if (isectA == null)
return coplanarTriangles(n1, v, u) ? 0 : -1;
int smallest1 = 0;
if (isectA.s0 > isectA.s1)
{
double cc = isectA.s0;
isectA.s0 = isectA.s1;
isectA.s1 = cc;
smallest1 = 1;
}
// Compute interval for triangle 2.
TriangleIntersection isectB = compute_intervals_isectline(u, up0, up1, up2, du0, du1, du2, du0du1, du0du2);
int smallest2 = 0;
if (isectB.s0 > isectB.s1)
{
double cc = isectB.s0;
isectB.s0 = isectB.s1;
isectB.s1 = cc;
smallest2 = 1;
}
if (isectA.s1 < isectB.s0 || isectB.s1 < isectA.s0)
return -1;
// At this point we know that the triangles intersect: there's an intersection line, the triangles are not
// coplanar, and they overlap.
if (isectB.s0 < isectA.s0)
{
if (smallest1 == 0)
intersectionVertices[0] = isectA.p0;
else
intersectionVertices[0] = isectA.p1;
if (isectB.s1 < isectA.s1)
{
if (smallest2 == 0)
intersectionVertices[1] = isectB.p1;
else
intersectionVertices[1] = isectB.p0;
}
else
{
if (smallest1 == 0)
intersectionVertices[1] = isectA.p1;
else
intersectionVertices[1] = isectA.p0;
}
}
else
{
if (smallest2 == 0)
intersectionVertices[0] = isectB.p0;
else
intersectionVertices[0] = isectB.p1;
if (isectB.s1 > isectA.s1)
{
if (smallest1 == 0)
intersectionVertices[1] = isectA.p1;
else
intersectionVertices[1] = isectA.p0;
}
else
{
if (smallest2 == 0)
intersectionVertices[1] = isectB.p1;
else
intersectionVertices[1] = isectB.p0;
}
}
return 1;
}
protected static TriangleIntersection compute_intervals_isectline(Vec4[] v, double vv0, double vv1, double vv2,
double d0, double d1, double d2,
double d0d1, double d0d2)
{
if (d0d1 > 0) // D0, D1 are on the same side, D2 on the other or on the plane
return intersect(v[2], v[0], v[1], vv2, vv0, vv1, d2, d0, d1);
else if (d0d2 > 0)
return intersect(v[1], v[0], v[2], vv1, vv0, vv2, d1, d0, d2);
else if (d1 * d2 > 0 || d0 != 0)
return intersect(v[0], v[1], v[2], vv0, vv1, vv2, d0, d1, d2);
else if (d1 != 0)
return intersect(v[1], v[0], v[2], vv1, vv0, vv2, d1, d0, d2);
else if (d2 != 0)
return intersect(v[2], v[0], v[1], vv2, vv0, vv1, d2, d0, d1);
else
return null; // triangles are coplanar
}
protected static TriangleIntersection intersect(Vec4 v0, Vec4 v1, Vec4 v2, double vv0, double vv1, double vv2,
double d0, double d1, double d2)
{
TriangleIntersection intersection = new TriangleIntersection();
double tmp = d0 / (d0 - d1);
intersection.s0 = vv0 + (vv1 - vv0) * tmp;
Vec4 diff = v1.subtract3(v0);
diff = diff.multiply3(tmp);
intersection.p0 = diff.add3(v0);
tmp = d0 / (d0 - d2);
intersection.s1 = vv0 + (vv2 - vv0) * tmp;
diff = v2.subtract3(v0);
diff = diff.multiply3(tmp);
intersection.p1 = diff.add3(v0);
return intersection;
}
protected static boolean coplanarTriangles(Vec4 n, Vec4[] v, Vec4[] u)
{
// First project onto an axis-aligned plane that maximizes the are of the triangles.
int i0;
int i1;
double[] a = new double[] {Math.abs(n.x), Math.abs(n.y), Math.abs(n.z)};
if (a[0] > a[1]) // X > Y
{
if (a[0] > a[2])
{ // X is greatest
i0 = 1;
i1 = 2;
}
else
{ // Z is greatest
i0 = 0;
i1 = 1;
}
}
else // X < Y
{
if (a[2] > a[1])
{ // Z is greatest
i0 = 0;
i1 = 1;
}
else
{ // Y is greatest
i0 = 0;
i1 = 2;
}
}
// Test all edges of triangle 1 against the edges of triangle 2.
double[] v0 = new double[] {v[0].x, v[0].y, v[0].z};
double[] v1 = new double[] {v[1].x, v[1].y, v[1].z};
double[] v2 = new double[] {v[2].x, v[2].y, v[2].z};
double[] u0 = new double[] {u[0].x, u[0].y, u[0].z};
double[] u1 = new double[] {u[1].x, u[1].y, u[1].z};
double[] u2 = new double[] {u[2].x, u[2].y, u[2].z};
boolean tf = triangleEdgeTest(v0, v1, u0, u1, u2, i0, i1);
if (tf)
return true;
tf = triangleEdgeTest(v1, v2, u0, u1, u2, i0, i1);
if (tf)
return true;
tf = triangleEdgeTest(v2, v0, u0, u1, u2, i0, i1);
if (tf)
return true;
// Finally, test whether one triangle is contained in the other one.
tf = pointInTri(v0, u0, u1, u2, i0, i1);
if (tf)
return true;
return pointInTri(u0, v0, v1, v2, i0, i1);
}
protected static boolean triangleEdgeTest(double[] v0, double[] v1, double[] u0, double[] u1, double[] u2, int i0,
int i1)
{
double ax = v1[i0] - v0[i0];
double ay = v1[i1] - v0[i1];
// Test edge u0:u1 against v0:v1
boolean tf = edgeEdgeTest(v0, u0, u1, i0, i1, ax, ay);
if (tf)
return true;
// Test edge u1:u2 against v0:v1
tf = edgeEdgeTest(v0, u1, u2, i0, i1, ax, ay);
if (tf)
return true;
// Test edge u2:u0 against v0:v1
return edgeEdgeTest(v0, u2, u0, i0, i1, ax, ay);
}
protected static boolean edgeEdgeTest(double[] v0, double[] u0, double[] u1, int i0, int i1, double ax, double ay)
{
double bx = u0[i0] - u1[i0];
double by = u0[i1] - u1[i1];
double cx = v0[i0] - u0[i0];
double cy = v0[i1] - u0[i1];
double f = ay * bx - ax * by;
double d = by * cx - bx * cy;
if ((f > 0 && d >= 0 && d <= f) || (f < 0 && d <= 0 && d >= f))
{
double e = ax * cy - ay * cx;
if (f > 0)
{
if (e >= 0 && e <= f)
return true;
}
else
{
if (e <= 0 && e >= f)
return true;
}
}
return false;
}
protected static boolean pointInTri(double[] v0, double[] u0, double[] u1, double[] u2, int i0, int i1)
{
double a = u1[i1] - u0[i1];
double b = -(u1[i0] - u0[i0]);
double c = -a * u0[i0] - b * u0[i1];
double d0 = a * v0[i0] + b * v0[i1] + c;
a = u2[i1] - u1[i1];
b = -(u2[i0] - u1[i0]);
c = -a * u1[i0] - b * u1[i1];
double d1 = a * v0[i0] + b * v0[i1] + c;
a = u0[i1] - u2[i1];
b = -(u0[i0] - u2[i0]);
c = -a * u2[i0] - b * u2[i1];
double d2 = a * v0[i0] + b * v0[i1] + c;
return d0 * d1 > 0 && d0 * d2 > 0;
}
public String toString()
{
return "Triangle (" + a + ", " + b + ", " + c + ")";
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy