236 lines
7.6 KiB
C++
236 lines
7.6 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
|
|
{
|
|
const vector3d<T> f = pointB - pointA;
|
|
const vector3d<T> g = pointC - pointA;
|
|
|
|
const f32 a = f.dotProduct(f);
|
|
const f32 b = f.dotProduct(g);
|
|
const f32 c = g.dotProduct(g);
|
|
|
|
const vector3d<T> vp = p - pointA;
|
|
const f32 d = vp.dotProduct(f);
|
|
const f32 e = vp.dotProduct(g);
|
|
|
|
f32 x = (d*c)-(e*b);
|
|
f32 y = (e*a)-(d*b);
|
|
const f32 ac_bb = (a*c)-(b*b);
|
|
f32 z = x+y-ac_bb;
|
|
|
|
return (( (IR(z)) & ~((IR(x))|(IR(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
|
|
|