/**
 * This file describes most of the computational geomtry for calculation.
 * Classes described here are:
 *		IGPoint2D, IGRPoint2D, and IGRect2D
 *
 *   IBM Open Class Library
 *   (C) Copyright International Business Machines Corporation,  1997
 *   Licensed Material - Program-Property of IBM - All Rights Reserved.
 *
 */

// Revision: 30 1.20.1.6 source/albert/graph2d/igbase2d.hpp, 2d, ioc.v400, 980918 

#ifndef _IGBASE2D_
#define _IGBASE2D_

#include <ibase.hpp>
#include <igrtypes.hpp>
#include <iprimtyp.hpp>

#if __IBMCPP__ >= 400
#pragma namemangling(compat)
#endif

class IDataStream;
class IPoint;
class IRectangle;

#pragma pack(push,4)
#pragma enum(4)

/**
 * IGPoint2D class represents a point or a vector on a 2-D plane.
 * IGPoint2D class represents a point or a vector on a 2-D plane.
 * The point is defined by an x-coordinate and a y-coordinate. It provides the basic means
 * for communicating between transforms and the rest of the 2-D world.
 * IGPoint2D's components are deliberately public. Note the handy arithmetic operators; these
 * perform vector arithmetic on the points.
 */

class IGPoint2D {
    public :
        IDataStream& operator>>= (IDataStream&) const;
        IDataStream& operator<<= (IDataStream&);
        void writeToStream(IDataStream& toWhere) const;
        void readFromStream(IDataStream& toWhere);
    public:

		/** x- and y- coordinates */
        #ifndef ARCHOK

        //The following public fields were approved by
        //                             Design Guidelines.
        // Yes, the data members are public, and this is deliberate.
        //  - The overhead of invoking a subroutine to access the coordinates
        //    is prohibative (On RISC machines, this could halve performance
        //    of anything using TGPoints).
        //  - Using in-line routines to avoid the above overhead
        //    exposes (and "freezes") the implementation anyway
        //  - The syntax of subroutine calls for accessing coordinates in
        //    mathematical
        //    expressions is awkward.
        //
        // Code police take note: this is approved by The Architect.
        /** x- coordinates */
        GCoordinate fX;
        /**  y- coordinates */
        GCoordinate fY;
        #endif

		/**
		 * Returns the origin point (0.0, 0.0).
		 */
        static const IGPoint2D& origin();

		/**
		 * Returns the infinity point (kInfinity, kInfinity).
		 */
        static const IGPoint2D& infinite();

    private:
        static const IGPoint2D* gOrigin;
        static const IGPoint2D* gInfinite;

    public:

		/**
		 * Constructor with default fX=0.0 and fY=0.0
		 */	
        IGPoint2D();

		/**
		 * Constructor takes new coordinates.
		 */	
        IGPoint2D (
            GCoordinate x,
            GCoordinate y );

		/**
		 * Constructor uses the coordinates in an IPoint.
		 */	
        IGPoint2D ( const IPoint& point );

		/**
		 * Copy constructor.
		 */	
        IGPoint2D ( const IGPoint2D& );

        ~IGPoint2D();

		/**
		 * Operator returns the reflection of the point across the origin with coordinates (-fX,-fY).
		 */	
        IGPoint2D operator- () const;

		/**
		 * Operator converts an IGPoint2D to an IPoint.
		 */
        operator IPoint() const;

		/**
		 * Operator adds the vector specified by the argument to the IGPoint2D.
		 */
        IGPoint2D& operator+= ( const IGPoint2D& Src );

		/**
		 * Operator subtracts the vector specified by the argument from the IGPoint2D.
		 */
        IGPoint2D& operator-= ( const IGPoint2D& Src );

		/**
		 * Operator multiplies the IGPoint2D by the vector argument.
		 */
        IGPoint2D& operator*= ( const IGPoint2D& Src );

		/**
		 * Operator multiplies the IGPoint2D by the scalar argument.
		 */
        IGPoint2D& operator*= ( const GCoordinate Src );

		/**
		 * Operator divides the IGPoint2D by the vector argument.
		 */
        IGPoint2D& operator/= ( const IGPoint2D& Src );

		/**
		 * Operator divides the IGPoint2D by the scalar argument.
		 */
        IGPoint2D& operator/= ( const GCoordinate Src );

		/**
		 * Assignment operator.
		 */
        IGPoint2D& operator= (const IGPoint2D& Src );

		/**
		 * Tests whether the point's coordinates equal those of the argument.
		 */
        bool operator== ( const IGPoint2D& Src ) const;

		/**
		 * Tests whether the point's coordinates differ from those of the argument.
		 */
        bool operator!= ( const IGPoint2D& Src ) const;

		/**
		 * Operator returns the x- or y-coordinate, depending on the index.
		 */
        GCoordinate& operator[]( unsigned long index );

		/**
		 * Operator returns the x- or y-coordinate of a const IGPoint2D.
		 */
        const GCoordinate& operator[]( unsigned long index ) const;

		/**
		 * Computes the dot product of the point and the vector argument.
		 */
        GCoordinate dotProduct( const IGPoint2D& vector ) const;

		/**
		 * Computes the cross product of the point and the vector argument.
		 */
        GCoordinate crossProduct( const IGPoint2D& vector ) const;

		/**
		 * Linearly interpolates between two points (or extrapolates beyond them).
		 */
        IGPoint2D interpolate( const IGPoint2D& dest, GParametric u ) const;

		/**
		 * Returns the distance of the point from the origin.
		 */
        GCoordinate vectorLength() const;

		/**
		 * Moves the point onto the unit circle, preserving its vector angle. The new vector length is 1.0.
		 */
        GCoordinate normalize();

		/**
		 * Computes the angle (in degrees) between the vector and the positive x-axis.
		 */
        GDegrees vectorAngle() const;

		/**
		 * Sets the distance of the point from the origin, without changing the vector angle.
		 */
        void setVectorLength( GCoordinate length );

		/**
		 * Sets the vector angle without changing the vector length.
		 */
        void setVectorAngle( GDegrees angle );

		/**
		 * Sets the point's position using polar coordinates (vector angle and vector length).
		 */
        void setPolarCoordinates( GDegrees angle, GCoordinate length = 1.0 );
};


/**
 * Addition operator.
 */
IGPoint2D operator+(const IGPoint2D& a, const IGPoint2D& b);

/**
 * Subtraction operator.
 */
IGPoint2D operator-(const IGPoint2D& a, const IGPoint2D& b);

/**
 * Vector multiplication operator.
 */
IGPoint2D operator*(const IGPoint2D& a, const IGPoint2D& b);

/**
 * Scalar multiplication operator.
 */
IGPoint2D operator*(const GCoordinate num, const IGPoint2D& pt);

/**
 * Scalar multiplication operator.
 */
IGPoint2D operator*(const IGPoint2D& pt, const GCoordinate num);

/**
 * Vector division operator.
 */
IGPoint2D operator/(const IGPoint2D& a, const IGPoint2D& b);

/**
 * Scalar division operator.
 */
IGPoint2D operator/(const IGPoint2D& pt, const GCoordinate num);


/**
 * The IGRPoint2D class represents a homogeneous (rational) point or vector on the 2-D coordinate plane.
 * The IGRPoint2D class represents a homogeneous (rational) point or vector on the 2-D coordinate plane.
 * IGRPoint2Ds are basic two-dimensional points with rational(homogeneous) coordinates.
 * These are used primarily by IGCurve2D(to provide an exact representation of conic curves with
 * splines) and for matrix operations requiring a homogeneous coordinate.
 * An IGPoint2D may be converted directly to a IGRPoint2D via the constructor, a "w" value of 1.0 is
 * assumed.  However, the conversion in the other direction must be done explicitly with either a
 * "divW" or "dropW" operation.  Note arithmetic operations are deliberatly -not- provided
 * for IGRPoint2Ds, because their correct interpretation would be too application specific.
 *
 */

class IGRPoint2D {

    public :
        IDataStream&    operator>>=(IDataStream&) const;
        IDataStream&    operator<<=(IDataStream&);
        void writeToStream(IDataStream& toWhere) const;
        void readFromStream(IDataStream& toWhere);
    public:
		
		/** x-, y-, and w-coordinates */
        #ifndef ARCHOK
        // Data members are deliberately public - see comment by IGPoint2D
        /** x-,coordinates */
        GCoordinate fX;
        /** y-,coordinates */
        GCoordinate fY;
        /** w-,coordinates */
        GCoordinate fW;
        #endif

		/**
		 * Constructor with default fX=0.0 and fY=0.0 and fW=0.0
		 */	
        IGRPoint2D ();

		/**
		 * Constructor takes new coordinates with fW=1.0 as default.
		 */	
        IGRPoint2D (
            GCoordinate x,
            GCoordinate y,
            GCoordinate w = 1.0);

		/**
		 * Copy constructor.
		 */	
        IGRPoint2D ( const IGRPoint2D& );

		/**
		 * Creates an IGRPoint2D whose x- and y-coordinates equal those of the IGPoint argument, and whose w=1.0.
		 */	
        IGRPoint2D ( const IGPoint2D& p );

        ~IGRPoint2D ();

		/**
		 * Assignment operator.
		 */	
        IGRPoint2D& operator= (const IGRPoint2D& Src );

		/**
		 * Tests whether the point's coordinates equal those of the argument.
		 */	
        bool operator== ( const IGRPoint2D& Src ) const;

		/**
		 * Tests whether the point's coordinates differ from those of the argument.
		 */	
        bool operator!= ( const IGRPoint2D& Src ) const;

		/**
		 * Divides the coordinates by w to create an IGPoint2D.
		 */	
        IGPoint2D divW() const;

		/**
		 * Creates an IGPoint2D by ignoring the w-coordinate.
		 */	
        IGPoint2D dropW() const;

		/**
		 * Returns the x-, y-, or w-coordinate, depending on the index.
		 */	
        GCoordinate& operator[]( unsigned long index );

		/**
		 * Returns the x-, y-, or w-coordinate of a const IGRPoint2D.
		 */	
        const GCoordinate& operator[]( unsigned long index ) const;
};


class IGLine2D;

/**
 * IGRect2D are axis-aligned rectangles: each side of the rectangle is parallel to the x- or y-axis.
 * IGRect2D are axis-aligned rectangles: each side of the rectangle is parallel to the x- or y-axis.
 * The rectangle is defined by the coordinate points for the top-left corner and the bottom-right
 * corner. The top-left corner consists of the minimum x- and y-coordinates. The bottom-right corner
 * consists of the maximum x- and y-coordinates.
 * An IGRect2D is area enclosing geometry that may be filled and/or framed. It is defined over a
 * half open interval, so a point is considered to be contained in the rect if it falls within
 * left <= x < right and top <= y < bottom.
 *
 */

class IGRect2D {
    public :
        IDataStream&    operator>>=(IDataStream&) const;
        IDataStream&    operator<<=(IDataStream&);
        void writeToStream(IDataStream& toWhere) const;
        void readFromStream(IDataStream& toWhere);
    public:
		/**
		 * Constructor with default fLeft=0.0 and fRight=0.0 and fTop=0.0 and fBottom=0.0
		 */	
        IGRect2D();

		/**
		 * Points are not sorted so p0 > p1, call orderPoints if you need this done.
		 */	
        IGRect2D(
            const IGPoint2D& p0,
            const IGPoint2D& p1 );

		/**
		 */	
        IGRect2D(
            GCoordinate left,
            GCoordinate top,
            GCoordinate right,
            GCoordinate bottom );

		/**
		 */	
        IGRect2D ( const IRectangle& rect );

		/**
		 */	
        IGRect2D( const IGRect2D& );

        ~IGRect2D();

		/**
		 * Returns the top-left point of the rectangle.
		 */
        IGPoint2D     topLeft() const;

		/**
		 * Returns the bottom-right  point of the rectangle.
		 */
        IGPoint2D     bottomRight() const;

		/**
		 * Returns the top-right point of the rectangle.
		 */
        IGPoint2D     topRight() const;

		/**
		 * Returns the bottom-left point of the rectangle.
		 */
        IGPoint2D     bottomLeft() const;

		/**
		 * Retrieves the top side of the rectangle.
		 */
        IGLine2D      topLine() const;

		/**
		 * Retrieves the bottom side of the rectangle.
		 */
        IGLine2D      bottomLine() const;

		/**
		 * Retrieves the left side of the rectangle.
		 */
        IGLine2D      leftLine() const;

		/**
		 * Retrieves the right side of the rectangle.
		 */
        IGLine2D      rightLine() const;

		/**
		 * Bilinearly creates the point within (or outside) the rectangle that corresponds to (u,v).
		 */
        IGPoint2D     interpolate( GParametric u, GParametric v ) const;

		/**
		 * Informs the caller whether the rectangle encloses no space.
		 */
        bool        isEmpty() const;

		/**
		 * Retrieves the height and width of the rectangle.
		 */
        IGPoint2D     size() const;

		/**
		 * Retrieves the midpoint of the rectangle.
	 	 */
        IGPoint2D     center() const;

		/**
		 * Retrieves the rectangle's height.
		 */
        GCoordinate height() const;

		/**
		 * Retrieves the width of the rectangle.
		 */
        GCoordinate width() const;

		/**
		 * Determines whether two rectangles have the same height and width.
		 */
        bool        equalSize( const IGRect2D& g) const;

		/**
		 * Moves a point to within the rectangle by forcing it to the nearest edge.
		 * Moves a point to within the rectangle by forcing it to the nearest edge.
		 * If the point is outside the rectangle, its values are modified to lie on the nearest
		 * border of the rectangle. If only one of the point's coordinates is outside the range
		 * of the rectangle's corresponding coordinate, the point is moved perpendicularly to the
		 * nearest border. If both its coordinates are outside the rectangle's range, it is moved
		 * to the nearest corner. If two side the rectangle are not in the normal order (for
		 * example, if fLeft >fRight), the point is always considered to be outside the rectangle,
		 * and it is moved to midway between these two sides.
		 *
		 */
        void        pin( IGPoint2D& Point ) const;

        /**
         * Takes the size and position of a rectangle r relative to this rectangle (in other words, *this)
         * Takes the size and position of a rectangle r relative to this rectangle (in other words, *this)
         * and maps it to the same proportional size and position relative to the destination
         * rectangle dr.
         */
		void        mapRect(
                        IGRect2D& r,
                        const IGRect2D& dr ) const;

        /**
         * Makes the rectangle infinitesimal and places it at the specified point.
         */
        void        setToPoint( const IGPoint2D& );

        /**
         * Sets the top-left corner of the rectangle to the specified point.
         */
        void        setTopLeft( const IGPoint2D& point);

        /**
         * Sets the bottom-right corner of the rectangle to the specified point.
         */
        void        setBottomRight( const IGPoint2D& point);

        /**
         * Sets the top-right corner of the rectangle to the specified point.
         */
        void        setTopRight( const IGPoint2D& pt );

        /**
         * Sets the bottom-left corner of the rectangle to the specified point.
         */
        void        setBottomLeft( const IGPoint2D& pt );

        /**
         * Moves the rectangle so that it is centered on the specified point.
         */
        void        setCenter( const IGPoint2D& center );

        /**
         * Sets the rectangle's height and width, without changing its center point.
         */
        void        setSize( const IGPoint2D& size );

        /**
         * Moves the rectangle's top-left and bottom-right corners to the specified points.
         */
        void        set(const IGPoint2D& a, const IGPoint2D& b);

        /**
         * Expands the rectangle until it just encompasses the specified rectangle.
         * Expands the rectangle until it just encompasses the specified rectangle.
         * If the specified rectangle is empty or already lies within this rectangle, nothing
         * changes. The rectangle is only stretched in the required direction(s), so it does not
         * necessarily retain its original shape or center.
         */
        void        extendTo( const IGRect2D& g );

        /**
         * Expands the rectangle until it just encompasses the specified point.
         * Expands the rectangle until it just encompasses the specified point.
         * If the specified point already lies within this rectangle, nothing changes.
         * The rectangle is only stretched in the required direction(s), so it does not
         * necessarily retain its original shape or center.
         */
        void        extendTo( const IGPoint2D& pt );

        /**
         * Finds the intersection of this rectangle with the specified rectangle g.
         * Finds the intersection of this rectangle with the specified rectangle g.
         * It modifies *this by replacing its coordinates with those of the rectangular
         * intersection.
         */
        void        intersectWith( const IGRect2D& g );

        /**
         * Moves the rectangle by the specified vector dg.
         */
        void        offset( const IGPoint2D& dg );

        /**
         * Moves opposite sides of the rectangle inwards towards its center or outwards from its center.
         */
        void        inset( const IGPoint2D& inset );

        /**
         * Swaps the rectangle's coordinates if necessary, so that the top-left corner is not below or to the right of the bottom-right corner.
         */
        void        orderPoints();

        /**
         * Specifies whether the rectangle intersects the specified rectangle.		
         */
        bool        intersects( const IGRect2D& g) const;

        /**
         * Specifies whether the rectangle encloses the specified point.
         * Specifies whether the rectangle encloses the specified point.
         * A point that lies on the top or left side is considered to be contained in the
         * rectangle, but a point on the right or bottom side isn't. 		
         */
        bool        contains( const IGPoint2D& p ) const;

        /**
         * Specifies whether the rectangle encloses the specified rectangle.
         * Specifies whether the rectangle encloses the specified rectangle.
         * Any or all sides of the enclosed rectangle can lie on the corresponding sides of
         * the outer rectangle.
         */
        bool        contains( const IGRect2D& g) const;

        /**
         * Assignment operator.
         */
        IGRect2D& operator=( const IGRect2D& Src );

        /**
         * Tests whether the rectangle's coordinates equal those of the argument.
         */
        bool operator==( const IGRect2D& Src ) const;

        /**
         * Tests whether the rectangle's coordinates differ from those of the argument.
         */
        bool operator!=( const IGRect2D& Src ) const;

        /**
         * Operator to convert from IGRect2D to IRectangle.
         */
       	operator IRectangle() const;

		/** Data members are deliberately public */
        GCoordinate fLeft;
        GCoordinate fTop;
        GCoordinate fRight;
        GCoordinate fBottom;

        /**
         * Returns a rectangle whose coordinates are (0.0, 0.0, 0.0, 0.0).
         */
        static const IGRect2D& zeroRect();

        /**
         * Returns a rectangle whose coordinates are (-1e10, -1e10, 1e10, 1e10).
         */
        static const IGRect2D& infiniteRect();

    private:
        static const IGRect2D* gZeroRect;
        static const IGRect2D* gInfiniteRect;

};

#pragma enum(pop)
#pragma pack(pop)

#if __IBMCPP__ >= 400
#pragma namemangling()
#endif

#include <igbase2d.inl>

#endif // _IGBASE2D_
