240 lines
6.7 KiB
Text
240 lines
6.7 KiB
Text
/**
|
|
* PANDA 3D SOFTWARE
|
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
*
|
|
* All use of this software is subject to the terms of the revised BSD
|
|
* license. You should have received a copy of this license along
|
|
* with this source code in a file named "LICENSE."
|
|
*
|
|
* @file plane_src.I
|
|
* @author mike
|
|
* @date 1997-01-09
|
|
*/
|
|
|
|
/**
|
|
* Creates a default plane. This plane happens to intersect the origin,
|
|
* perpendicular to the Z axis. It's not clear how useful a default plane is.
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPlane)::
|
|
FLOATNAME(LPlane)() {
|
|
_v(0) = 0.0f;
|
|
_v(1) = 0.0f;
|
|
_v(2) = 1.0f;
|
|
_v(3) = 0.0f;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPlane)::
|
|
FLOATNAME(LPlane)(const FLOATNAME(LVecBase4) ©) :
|
|
FLOATNAME(LVecBase4)(copy)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Constructs a plane given three counter-clockwise points, as seen from the
|
|
* front of the plane (that is, viewed from the end of the normal vector,
|
|
* looking down).
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPlane)::
|
|
FLOATNAME(LPlane)(const FLOATNAME(LPoint3) &a, const FLOATNAME(LPoint3) &b,
|
|
const FLOATNAME(LPoint3) &c) {
|
|
FLOATNAME(LVector3) u = b - a;
|
|
FLOATNAME(LVector3) v = c - a;
|
|
FLOATNAME(LVector3) p = ::normalize(cross(u, v));
|
|
|
|
_v(0) = p[0];
|
|
_v(1) = p[1];
|
|
_v(2) = p[2];
|
|
_v(3) = -::dot(p, a);
|
|
}
|
|
|
|
/**
|
|
* Constructs a plane given a surface normal vector and a point within the
|
|
* plane.
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPlane)::
|
|
FLOATNAME(LPlane)(const FLOATNAME(LVector3) &normal,
|
|
const FLOATNAME(LPoint3) &point) {
|
|
FLOATNAME(LVector3) p = ::normalize(normal);
|
|
|
|
_v(0) = p[0];
|
|
_v(1) = p[1];
|
|
_v(2) = p[2];
|
|
_v(3) = -::dot(p, point);
|
|
}
|
|
|
|
/**
|
|
* Constructs a plane given the four terms of the plane equation.
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPlane)::
|
|
FLOATNAME(LPlane)(FLOATTYPE a, FLOATTYPE b, FLOATTYPE c, FLOATTYPE d) :
|
|
FLOATNAME(LVecBase4)(a, b, c, d)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Transforms the plane by the indicated matrix.
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPlane) FLOATNAME(LPlane)::
|
|
operator * (const FLOATNAME(LMatrix3) &mat) const {
|
|
FLOATNAME(LVector3) new_normal = mat.xform(get_normal());
|
|
return FLOATNAME(LPlane)(new_normal, get_point());
|
|
}
|
|
|
|
/**
|
|
* Transforms the plane by the indicated matrix.
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPlane) FLOATNAME(LPlane)::
|
|
operator * (const FLOATNAME(LMatrix4) &mat) const {
|
|
FLOATNAME(LVector3) new_normal = mat.xform_vec_general(get_normal());
|
|
FLOATNAME(LPoint3) new_point = get_point() * mat;
|
|
return FLOATNAME(LPlane)(new_normal, new_point);
|
|
}
|
|
|
|
/**
|
|
* Transforms the plane by the indicated matrix.
|
|
*/
|
|
INLINE_MATHUTIL void FLOATNAME(LPlane)::
|
|
operator *= (const FLOATNAME(LMatrix4) &mat) {
|
|
(*this) = (*this) * mat;
|
|
}
|
|
|
|
/**
|
|
* Transforms the plane by the indicated matrix.
|
|
*/
|
|
INLINE_MATHUTIL void FLOATNAME(LPlane)::
|
|
xform(const FLOATNAME(LMatrix4) &mat) {
|
|
(*this) = (*this) * mat;
|
|
}
|
|
|
|
/**
|
|
* Returns the same plane facing the opposite direction.
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPlane) FLOATNAME(LPlane)::
|
|
operator - () const {
|
|
return FLOATNAME(LPlane)(-_v(0), -_v(1), -_v(2), -_v(3));
|
|
}
|
|
|
|
/**
|
|
* Returns the surface normal of the plane.
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LVector3) FLOATNAME(LPlane)::
|
|
get_normal() const {
|
|
return FLOATNAME(LVector3)(_v(0), _v(1), _v(2));
|
|
}
|
|
|
|
/**
|
|
* Returns the straight-line shortest distance from the point to the plane.
|
|
* The returned value is positive if the point is in front of the plane (on
|
|
* the side with the normal), or negative in the point is behind the plane (on
|
|
* the opposite side from the normal). It's zero if the point is exactly in
|
|
* the plane.
|
|
*/
|
|
INLINE_MATHUTIL FLOATTYPE FLOATNAME(LPlane)::
|
|
dist_to_plane(const FLOATNAME(LPoint3) &point) const {
|
|
return (_v(0) * point[0] + _v(1) * point[1] + _v(2) * point[2] + _v(3));
|
|
}
|
|
|
|
/**
|
|
* Normalizes the plane in place. Returns true if the plane was normalized,
|
|
* false if the plane had a zero-length normal vector.
|
|
*/
|
|
INLINE_MATHUTIL bool FLOATNAME(LPlane)::
|
|
normalize() {
|
|
FLOATTYPE l2 = get_normal().length_squared();
|
|
if (l2 == (FLOATTYPE)0.0f) {
|
|
return false;
|
|
|
|
} else if (!IS_THRESHOLD_EQUAL(l2, 1.0f, NEARLY_ZERO(FLOATTYPE) * NEARLY_ZERO(FLOATTYPE))) {
|
|
(*this) /= csqrt(l2);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Normalizes the plane and returns the normalized plane as a copy. If the
|
|
* plane's normal was a zero-length vector, the same plane is returned.
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPlane) FLOATNAME(LPlane)::
|
|
normalized() const {
|
|
FLOATTYPE l2 = get_normal().length_squared();
|
|
if (l2 != (FLOATTYPE)0.0f) {
|
|
return (*this) / csqrt(l2);
|
|
} else {
|
|
return (*this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the point within the plane nearest to the indicated point in space.
|
|
*/
|
|
INLINE_MATHUTIL FLOATNAME(LPoint3) FLOATNAME(LPlane)::
|
|
project(const FLOATNAME(LPoint3) &point) const {
|
|
return point - get_normal() * dist_to_plane(point);
|
|
}
|
|
|
|
/**
|
|
* Convenience method that flips the plane in-place. This is done by simply
|
|
* flipping the normal vector.
|
|
*/
|
|
INLINE_MATHUTIL void FLOATNAME(LPlane)::
|
|
flip() {
|
|
_v(0) = -_v(0);
|
|
_v(1) = -_v(1);
|
|
_v(2) = -_v(2);
|
|
_v(3) = -_v(3);
|
|
}
|
|
|
|
/**
|
|
* Returns true if the plane intersects the infinite line passing through
|
|
* points p1 and p2, false if the line is parallel. The points p1 and p2 are
|
|
* used only to define the Euclidean line; they have no other bearing on the
|
|
* intersection test. If true, sets intersection_point to the point of
|
|
* intersection.
|
|
*/
|
|
INLINE_MATHUTIL bool FLOATNAME(LPlane)::
|
|
intersects_line(FLOATNAME(LPoint3) &intersection_point,
|
|
const FLOATNAME(LPoint3) &p1,
|
|
const FLOATNAME(LPoint3) &p2) const {
|
|
FLOATTYPE t;
|
|
if (!intersects_line(t, p1, p2 - p1)) {
|
|
return false;
|
|
}
|
|
intersection_point = p1 + t * (p2 - p1);
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* This flavor of intersects_line() returns a bit more information about the
|
|
* nature of the intersecting point. The line is defined via the parametric
|
|
* equation from + t * delta for all real values of t.
|
|
*
|
|
* If there is no intersection with the plane, the function returns false and
|
|
* leaves t undefined. If there is an intersection with the plane, the
|
|
* function returns true and sets t to the parametric value that defines the
|
|
* point of intersection. That is, t == 0.0f implies that the intersection
|
|
* occurred exactly at point from, and t == 1.0f implies at point from +
|
|
* delta, with other values of t accordingly.
|
|
*/
|
|
INLINE_MATHUTIL bool FLOATNAME(LPlane)::
|
|
intersects_line(FLOATTYPE &t,
|
|
const FLOATNAME(LPoint3) &from,
|
|
const FLOATNAME(LVector3) &delta) const {
|
|
FLOATTYPE denom = ::dot(get_normal(), delta);
|
|
if (IS_NEARLY_ZERO(denom)) {
|
|
t = 0.0f;
|
|
return false;
|
|
}
|
|
|
|
t = -(dist_to_plane(from) / denom);
|
|
return true;
|
|
}
|
|
|
|
INLINE_MATHUTIL std::ostream &
|
|
operator << (std::ostream &out, const FLOATNAME(LPlane) &p) {
|
|
p.output(out);
|
|
return out;
|
|
}
|