// Magic Software, Inc.
// http://www.magic-software.com
// http://www.wild-magic.com
// Copyright (c) 2004.  All Rights Reserved
//
// The Wild Magic Library (WML) source code is supplied under the terms of
// the license agreement http://www.magic-software.com/License/WildMagic.pdf
// and may not be copied or disclosed except in accordance with the terms of
// that agreement.

#ifndef WMLPLANE3_H
#define WMLPLANE3_H

#include "WmlVector3.h"
#include "WmlPoint4.h"

namespace Wml
{

template <class Real>
class WML_ITEM Plane3
{
public:
    // The plane is represented as Dot(N,X) = c where N is the plane normal
    // vector, not necessarily unit length, c is the plane constant, and X is
    // any point on the plane.

    // N and c are uninitialized
    Plane3 ();

    // N and c are specified
    Plane3 (const Vector3<Real>& rkNormal, Real fConstant);

    // N is specified, c = Dot(N,P) where P is the input point
    Plane3 (const Vector3<Real>& rkNormal, const Vector3<Real>& rkPoint);

    // N = Cross(P1-P0,P2-P0), c = Dot(N,P0) where P0, P1, P2 are input points
    Plane3 (const Vector3<Real>& rkPoint0, const Vector3<Real>& rkPoint1,
        const Vector3<Real>& rkPoint2);

    // copy constructor
    Plane3 (const Plane3& rkPlane);

		// Marco
    // N = Cross(P1-P0,P2-P0), c = Dot(N,P0) where P0, P1, P2 are input points
    void CalcPlaneUnnormalized (const Vector3<Real>& rkPoint0, const Vector3<Real>& rkPoint1,
        const Vector3<Real>& rkPoint2);

    // member access
    void SetNormal (const Vector3<Real>& rkNormal);
    Vector3<Real> GetNormal () const;
    void SetConstant (Real fConstant);
    Real GetConstant () const;
    void Set (const Vector3<Real>& rkNormal, Real fConstant);
    void Get (Vector3<Real>& rkNormal, Real& rfConstant) const;

    // access plane P as P[0] = N.x, P[1] = N.y, P[2] = N.z, P[3] = c
    operator const Real* () const;
    operator Real* ();
    Real operator[] (int i) const;
    Real& operator[] (int i);

    // Access plane as homogeneous vector (N.x,N.y,N.z,-c) for use in
    // multiplication by 4-by-4 homogeneous matrix.
    operator Point4<Real> ();

    // assignment
    Plane3& operator= (const Plane3& rkPlane);

    // The "positive side" of the plane is the half space to which the plane
    // normal points.  The "negative side" is the other half space.  The flag
    // "no side" indicates the plane itself.
    enum Side
    {
        NO_SIDE,
        POSITIVE_SIDE,
        NEGATIVE_SIDE
    };

    Side WhichSide (const Vector3<Real>& rkPoint) const;

    // This is a pseudodistance.  The sign of the return value is positive if
    // the point is on the positive side of the plane, negative if the point
    // is on the negative side, and zero if the point is on the plane.  The
    // absolute value of the return value is the true distance only when the
    // plane normal is a unit length vector.
    Real DistanceTo (const Vector3<Real>& rkPoint) const;

    // If the plane is Dot(N,X) = c, arrange for the normal vector to be
    // unit length.  The new equation is Dot(N/|N|,X) = c/|N|.
    void Normalize ();

protected:
    // Normal N = (nx,ny,nz), constant c, plane is Dot(N,X) = c.  The tuple
    // stores tuple[0] = nx, tuple[1] = ny, tuple[2] = nz, tuple[3] = c.
    Real m_afTuple[4];
};

typedef Plane3<float> Plane3f;
typedef Plane3<double> Plane3d;

}

#endif
