/*-
 * Copyright (c) 1999,2000 Qube Software, Ltd.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of the source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Any redistribution solely in binary form must conspicuously
 *    reproduce the following disclaimer in documentation provided with the
 *    binary redistribution.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'', WITHOUT ANY WARRANTIES, EXPRESS
 * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  LICENSOR SHALL
 * NOT BE LIABLE FOR ANY LOSS OR DAMAGES RESULTING FROM THE USE OF THIS
 * SOFTWARE, EITHER ALONE OR IN COMBINATION WITH ANY OTHER SOFTWARE.
 * 
 * 	$Id: plane4.h,v 1.12 2000/06/21 10:03:45 peterj Exp $
 */

#ifndef __plane4_h__
#define __plane4_h__

MATHS_BEGIN

struct EXPORT_QMATHS Plane4f
{
    Vec3f	n;
    float	d;

    // Constructors
				Plane4f() {}
				Plane4f(const Vec3f& a,
                                        const Vec3f& b,
                                        const Vec3f& point)
                                {
                                    build(a, b, point);
                                }
				Plane4f(const Vec3f& norm, float dist)
				{
				    n = norm;
				    d = dist;
				}

    Plane4f& build(const Vec3f& a, const Vec3f& b,
                   const Vec3f& point);

    const Vec3f&		normal() const { return n; }
    float			distance() const { return d; }
    
    // Return 1 for outside, -1 for inside, 0 for on.
    int test(const Vec3f& v, float e = Epsilon) const {
	return compare(distance(v), 0.0f, e);
    }

    // Return distance to plane, positive for outside, negative inside.
    float distance(const Vec3f& v) const {
	return dot(n, v) + d;
    }

    bool operator < (const Plane4f& a) const {
	if (n.x - a.n.x < -Epsilon) return true;
	if (n.y - a.n.y < -Epsilon) return true;
	if (n.z - a.n.z < -Epsilon) return true;
	if (d - a.d < -Epsilon) return true;
	return false;
    }
    
    bool operator == (const Plane4f& a) const {
	if (equals(dot(n, a.n), 1.0f, Epsilon) &&
	    equals(d, a.d, Epsilon)) {
	    return true;
	} else {
	    return false;
	}
    }

    bool coPlanar (const Plane4f& a, float e = Epsilon) const {
	return  ((equals(dot(n, a.n), 1.0f, e) && equals(d, a.d, e))
		 || (equals(dot(n, a.n), -1.0f, e) && equals(d, -a.d, e)));
    }
    
    bool intersect(const Vec3f& origin, const Vec3f& dir,
		   Vec3f& v, const Matrix4f& m)
    {
	Vec3f trOrig = origin.inverseTransform(m);
	Vec3f trDir = dir.inverseRotate(m);
	
	if (dot(trDir, n) == 0) return false;
	    
	float lambda = - (d + dot(trOrig, n)) / dot(trDir, n);

	v = trOrig + (lambda * trDir);

	return true;
    }
};

MATHS_END

#endif

// Local Variables:
// mode: c++
// End:
