/*----------------------------------------------------------------------------*
 | headerfile Point3D.h                                                       |
 |                                                                            |
 | version 1.00                                                               |
 |                                                                            |
 |                                                                            |
 | This file is part of the 3D Geometry Primer, found at:                     |
 | http://www.flipcode.com/geometry/                                          |        
 |                                                                            |
 | It contains an example implementation of a 3D point.                       |
 | You can find more info in the 3D Geometry Primer on www.flipcode.com.      |
 |                                                                            |
 |                                                                            |
 | Copyright (C) 2002  Bram de Greve                                          |
 |                                                                            |
 | This library is free software; you can redistribute it and/or              |
 | modify it under the terms of the GNU Lesser General Public                 |
 | License as published by the Free Software Foundation; either               |
 | version 2.1 of the License, or (at your option) any later version.         |
 |                                                                            |
 | This library is distributed in the hope that it will be useful,            |
 | but WITHOUT ANY WARRANTY; without even the implied warranty of             |
 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU          |
 | Lesser General Public License for more details.                            |
 |                                                                            |
 | You should have received a copy of the GNU Lesser General Public           |
 | License along with this library; if not, write to the Free Software        |
 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA  |
 |                                                                            |
 | You can contact me by e-mail on bdegreve@mail.be                           |
 *----------------------------------------------------------------------------*/

// --- GUARDIAN OF INCLUSION ---------------------------------------------------

#ifndef GUARDIAN_OF_INCLUSION_3DGEOMETRYPRIMER_POINT3D_H
#define GUARDIAN_OF_INCLUSION_3DGEOMETRYPRIMER_POINT3D_H



// --- INCLUDED FILES ----------------------------------------------------------

#include <iostream>

#include "Vector3D.h"



// --- STRUCT DEFINITION -------------------------------------------------------

struct Point3D
{
public:
    
    // --- PUBLIC MEMBER DATA ---

    union
    {
        struct
        {
            // component values (x, y, z)
            float x;
            float y;
            float z;
        };
        struct
        {
            // position vector
            Vector3D position;
        };
    };



    // --- PUBLIC STRUCTORS ---

    // default contructor
    Point3D():
        position(0.0f, 0.0f, 0.0f)
    {
    }

    // constructor taking three component values (x, y, z)
    Point3D(float a_x, float a_y, float a_z):
        position(a_x, a_y, a_z)
    {
    }

    // explicit constructor to convert position vectors to points
    explicit Point3D(const Vector3D a_v): position(a_v) {}


    // --- PUBLIC OPERATORS ---

    // add vector v to this point, and return *this
    Point3D& operator+=(const Vector3D& a_v)
    {
        position += a_v;
        return *this;
    }

    // subtract vector v from this point, and return *this
    Point3D& operator-=(const Vector3D& a_v)
    {
        position -= a_v;
        return *this;
    }

    // add point p to this point, and return *this (don't abuse this! :)
    Point3D& operator+=(const Point3D& a_p) 
    { 
        position += a_p.position;
        return *this;
    }

    // scale this point by scalar r, and return *this (don't abuse this! :)
    Point3D& operator*=(float a_r)
    {
        position *= a_r;
        return *this;
    }

    // scale this point by scalar 1/r and return *this (don't abuse this! :)
    Point3D& operator/=(float a_r)
    {
        position /= a_r;
        return *this;
    }

    
    // --- PUBLIC ACCESSORS ---

    // set the three component values (x, y, z) of this point
    void set(float a_x, float a_y, float a_z)
    {
        position.set(a_x, a_y, a_z);
    }

    // set this point to the origin (0, 0, 0)
    void setNull()
    {
        position.setNull();
    }


    // --- PUBLIC METHODS ---

    // return true if this is the origin (0, 0, 0)
    bool isNull() const
    {
        return position.isNull();
    }

    // return true if this is the origin (0, 0, 0) within a given tolerance
    bool isNull(float a_tolerance) const
    {
        return position.isNull(a_tolerance);
    }
};



// --- NON-MEMBER BOOLEAN OPERATORS --------------------------------------------

// return true if both points p and q are equal
inline bool operator==(const Point3D& a_p, const Point3D& a_q)
{
    return a_p.position == a_q.position;
}

// return true if both points are not equal
inline bool operator!=(const Point3D& a_p, const Point3D& a_q)
{
    return a_p.position != a_q.position;
}


// --- NON-MEMBER ARITHMETICAL OPERATORS ---------------------------------------

// add point a_q to point a_p and return point (don't abuse this!)
inline Point3D operator+(const Point3D& a_p, const Point3D& a_q)
{
    return Point3D(a_p.position + a_q.position);
}

// add vector a_v to point a_p and return point
inline Point3D operator+(const Point3D& a_p, const Vector3D& a_v)
{
    return Point3D(a_p.position + a_v);
}

// add vector a_v to point a_p and return point
inline Point3D operator+(const Vector3D& a_v, const Point3D& a_p)
{
    return Point3D(a_p.position + a_v);
}

// subtract point a_q from point a_p and return vector
inline Vector3D operator-(const Point3D& a_p, const Point3D& a_q)
{
    return a_p.position - a_q.position;
}

// subtract vector a_v from point a_p and return point
inline Point3D operator-(const Point3D& a_p, const Vector3D& a_v)
{
    return Point3D(a_p.position - a_v);
}


// return p scaled by scalar r
inline Point3D operator*(const Point3D& p, float r)
{
    return Point3D(p.position * r);
}

// return p scaled by scalar r
inline Point3D operator*(float r, const Point3D& p)
{
    return Point3D(p.position * r);
}

// return p scaled by scalar 1/r
inline Point3D operator/(const Point3D& p, float r)
{
    return Point3D(p.position / r);
}



// --- NON-MEMBER ARITHMETICAL FUNCTIONS ---------------------------------------

// return the distance between points p and q
inline float dist(const Point3D a_p, const Point3D& a_q)
{
    const Vector3D v = a_p - a_q;
    return v.getNorm();
}



// --- NON-MEMBER OUTPUT FUNCTIONS ---------------------------------------------

// write p to output stream
inline std::ostream& operator<<(std::ostream& a_stream, const Point3D& a_p)
{
    a_stream << a_p.position;
    return a_stream;
}



// --- GUARDIAN OF INCLUSION ---------------------------------------------------

#endif



// --- END OF FILE Point3D.h ---------------------------------------------------