irrlicht/include/triangle3d.h

235 lines
7.5 KiB
C++

// Copyright (C) 2002-2007 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#ifndef __IRR_TRIANGLE_3D_H_INCLUDED__
#define __IRR_TRIANGLE_3D_H_INCLUDED__
#include "vector3d.h"
#include "line3d.h"
#include "plane3d.h"
#include "aabbox3d.h"
namespace irr
{
namespace core
{
//! 3d triangle template class for doing collision detection and other things.
template <class T>
class triangle3d
{
public:
//! Constructor for an all 0 triangle
triangle3d() {}
//! Constructor for triangle with given three vertices
triangle3d(vector3d<T> v1, vector3d<T> v2, vector3d<T> v3) : pointA(v1), pointB(v2), pointC(v3) {}
//! Equality operator
bool operator==(const triangle3d<T>& other) const
{
return other.pointA==pointA && other.pointB==pointB && other.pointC==pointC;
}
//! Inequality operator
bool operator!=(const triangle3d<T>& other) const
{
return !(*this==other);
}
//! Determines if the triangle is totally inside a bounding box.
//! \param box: Box to check.
//! \return Returns true if the triangle is within the box,
//! and false otherwise.
bool isTotalInsideBox(const aabbox3d<T>& box) const
{
return (box.isPointInside(pointA) &&
box.isPointInside(pointB) &&
box.isPointInside(pointC));
}
//! Get the closest point on a triangle to a point on the same plane.
//! \param p: Point which must be on the same plane as the triangle.
//! \return The closest point of the triangle
core::vector3d<T> closestPointOnTriangle(const core::vector3d<T>& p) const
{
const core::vector3d<T> rab = line3d<T>(pointA, pointB).getClosestPoint(p);
const core::vector3d<T> rbc = line3d<T>(pointB, pointC).getClosestPoint(p);
const core::vector3d<T> rca = line3d<T>(pointC, pointA).getClosestPoint(p);
const T d1 = rab.getDistanceFrom(p);
const T d2 = rbc.getDistanceFrom(p);
const T d3 = rca.getDistanceFrom(p);
if (d1 < d2)
return d1 < d3 ? rab : rca;
return d2 < d3 ? rbc : rca;
}
//! Check if a point is inside the triangle
//! \param p: Point to test. Assumes that this point is already on the plane
//! of the triangle.
//! \return Returns true if the point is inside the triangle, otherwise false.
bool isPointInside(const vector3d<T>& p) const
{
return (isOnSameSide(p, pointA, pointB, pointC) &&
isOnSameSide(p, pointB, pointA, pointC) &&
isOnSameSide(p, pointC, pointA, pointB));
}
//! Check if a point is inside the triangle. This method is an implementation
//! of the example used in a paper by Kasper Fauerby original written
//! by Keidy from Mr-Gamemaker.
//! \param p: Point to test. Assumes that this point is already on the plane
//! of the triangle.
//! \return Returns true if the point is inside the triangle, otherwise false.
bool isPointInsideFast(const vector3d<T>& p) const
{
vector3d<T> f = pointB - pointA;
vector3d<T> g = pointC - pointA;
f32 a = f.dotProduct(f);
f32 b = f.dotProduct(g);
f32 c = g.dotProduct(g);
f32 ac_bb = (a*c)-(b*b);
vector3d<T> vp = p - pointA;
f32 d = vp.dotProduct(f);
f32 e = vp.dotProduct(g);
f32 x = (d*c)-(e*b);
f32 y = (e*a)-(d*b);
f32 z = x+y-ac_bb;
return (( ((u32&)z)& ~(((u32&)x)|((u32&)y))) & 0x80000000)!=0;
}
//! Get an intersection with a 3d line.
//! \param line: Line to intersect with.
//! \param outIntersection: Place to store the intersection point, if there is one.
//! \return Returns true if there was an intersection, false if not.
bool getIntersectionWithLimitedLine(const line3d<T>& line,
vector3d<T>& outIntersection) const
{
return getIntersectionWithLine(line.start,
line.getVector(), outIntersection) &&
outIntersection.isBetweenPoints(line.start, line.end);
}
//! Returns an intersection with a 3d line.
//! Please note that also points are returned as intersection which
//! are on the line, but not between the start and end point of the line.
//! If you want the returned point be between start and end
//! use getIntersectionWithLimitedLine().
//! \param linePoint: Point of the line to intersect with.
//! \param lineVect: Vector of the line to intersect with.
//! \param outIntersection: Place to store the intersection point, if there is one.
//! \return Returns true if there was an intersection, false if there was not.
bool getIntersectionWithLine(const vector3d<T>& linePoint,
const vector3d<T>& lineVect, vector3d<T>& outIntersection) const
{
if (getIntersectionOfPlaneWithLine(linePoint, lineVect, outIntersection))
return isPointInside(outIntersection);
return false;
}
//! Calculates the intersection between a 3d line and
//! the plane the triangle is on.
//! \param lineVect: Vector of the line to intersect with.
//! \param linePoint: Point of the line to intersect with.
//! \param outIntersection: Place to store the intersection point, if there is one.
//! \return Returns true if there was an intersection, false if there was not.
bool getIntersectionOfPlaneWithLine(const vector3d<T>& linePoint,
const vector3d<T>& lineVect, vector3d<T>& outIntersection) const
{
const vector3d<T> normal = getNormal().normalize();
T t2;
if ( core::iszero ( t2 = normal.dotProduct(lineVect) ) )
return false;
T d = pointA.dotProduct(normal);
T t = -(normal.dotProduct(linePoint) - d) / t2;
outIntersection = linePoint + (lineVect * t);
return true;
}
//! Returns the normal of the triangle.
//! Please note: The normal is not normalized.
vector3d<T> getNormal() const
{
return (pointB - pointA).crossProduct(pointC - pointA);
}
//! Test if the triangle would be front or backfacing from any
//! point. Thus, this method assumes a camera position from
//! which the triangle is definitely visible when looking into
//! the given direction.
//! Do not use this method with points as it will give wrong results!
//! \param lookDirection: Look direction.
//! \return Returns true if the plane is front facing and
//! false if it is backfacing.
bool isFrontFacing(const vector3d<T>& lookDirection) const
{
const vector3d<T> n = getNormal().normalize();
const f32 d = (f32)n.dotProduct(lookDirection);
return F32_LOWER_EQUAL_0(d);
}
//! Returns the plane of this triangle.
plane3d<T> getPlane() const
{
return plane3d<T>(pointA, pointB, pointC);
}
//! Returns the area of the triangle
T getArea() const
{
return (pointB - pointA).crossProduct(pointC - pointA).getLength() * 0.5;
}
//! sets the triangle's points
void set(const core::vector3d<T>& a, const core::vector3d<T>& b, const core::vector3d<T>& c)
{
pointA = a;
pointB = b;
pointC = c;
}
//! the three points of the triangle
vector3d<T> pointA;
vector3d<T> pointB;
vector3d<T> pointC;
private:
bool isOnSameSide(const vector3d<T>& p1, const vector3d<T>& p2,
const vector3d<T>& a, const vector3d<T>& b) const
{
vector3d<T> bminusa = b - a;
vector3d<T> cp1 = bminusa.crossProduct(p1 - a);
vector3d<T> cp2 = bminusa.crossProduct(p2 - a);
return (cp1.dotProduct(cp2) >= 0.0f);
}
};
//! Typedef for a f32 3d triangle.
typedef triangle3d<f32> triangle3df;
//! Typedef for an integer 3d triangle.
typedef triangle3d<s32> triangle3di;
} // end namespace core
} // end namespace irr
#endif