Commit d53f6664 authored by Vladimir Ur's avatar Vladimir Ur
Browse files

New draft for length.h

parent a5a435f1
Loading
Loading
Loading
Loading
+168 −643
Original line number Diff line number Diff line
@@ -3,661 +3,186 @@
 * @file length.h
 */

#ifndef UNITS_H_INCLUDED
#define UNITS_H_INCLUDED 1
/* sorry it is not styles correctly, i'll work on it further */

#include <math.h>
#include <wx/gdicmn.h>
/**********************************************/
/*! I'm a physical length                     */
/**********************************************/
#ifndef LENGTH_H_INCLUDED
#define LENGTH_H_INCLUDED 1

class LENGTH
{
typedef int DEF_LENGTH_VALUE;

private:
    enum
    {
        METER = 1000000000, /* The ONLY constant connecting length to the real world */
template <typename T = DEF_LENGTH_VALUE, int P = 1> class LENGTH;

template <typename T> class LENGTH_UNITS;

template <typename T, int P> struct LENGTH_TRAITS {
	typedef LENGTH<T, P> flat;
};
    int m_Units;

    /*!
     * The only constructor allowing direct input of numeric value
     * in internal units. As this is not allowed in public, it's private.
     * Length objects elsewhere are created indirectly
     * @param units Length in internal units.
     */
    LENGTH( int units )
    {
        m_Units = units;
    }
template <typename T> struct LENGTH_TRAITS<T, 0> {
	typedef T flat;
};

public:
    /*!
     * Equality comparison of physical lengths.
     * @param y length to compare
     * @return lengths are equal
     */
    bool operator == ( const LENGTH y ) const
    {
        return m_Units == y.m_Units;
    }
template<typename T, int P> class LENGTH {
	friend class LENGTH_UNITS<T>;
	friend class LENGTH_TRAITS<T, P>;
	template <typename Y, int R> friend class LENGTH;
protected:

    /*!
     * Non-equality comparison of physical lengths.
     * @param y length to compare
     * @return lengts are different
     */
    bool operator != ( const LENGTH y ) const
    {
        return m_Units != y.m_Units;
	T m_U;
	LENGTH(T units) : m_U(units) {
	}

    /*!
     * Order comparison of physical lengths.
     * @param y length to compare
     * @return one less than another
     */
    bool operator < ( const LENGTH y ) const
    {
        return m_Units < y.m_Units;
	static T RawValue(const LENGTH<T, P> &x) {
		return x.m_U;
	}

    /*!
     * Order comparison of physical lengths.
     * @param y length to compare
     * @return one greater than another
     */
    bool operator > ( const LENGTH y ) const
    {
        return m_Units > y.m_Units;
	static T RawValue(const T& x) {
		return x;
	}

    /*!
     * Order comparison of physical lengths.
     * @param y length to compare
     * @return one less or equal than another
     */
    bool operator <= ( const LENGTH y ) const
    {
        return m_Units <= y.m_Units;
public:
	typedef LENGTH<T, P> flat;
	typedef T value_type;
	enum {
		dimension = P
	};
	LENGTH(const LENGTH <T, P> &orig) : m_U(orig.m_U) {
	}

    /*!
     * Order comparison of physical lengths.
     * @param y length to compare
     * @return one greater or equal than another
     */
    bool operator >= ( const LENGTH y ) const
    {
        return m_Units >= y.m_Units;
	LENGTH( void ) : m_U() {
	}
	
    /*!
     * Sum of two physical lengths. Only another length can be added.
     * @param y length to add
     * @return result of addition
     */
    const LENGTH operator + ( const LENGTH y ) const
    {
        return LENGTH( m_Units + y.m_Units );
	static LENGTH<T, P> zero (void) {
		return T(0);
	}

    /*!
     * Add a length inplace
     * @param y length to add
     * @return result of addition
     */
    LENGTH & operator += ( const LENGTH y )
    {
        m_Units += y.m_Units;
	LENGTH<T, P> & operator = (const LENGTH<T, P> & y) {
		this->m_U = y.m_U;
		return *this;
	}

    /*!
     * Differece of two physical lengths. Only another length can be subtracted.
     * @param y length to subtract
     * @return result of subtraction
     */
    const LENGTH operator - ( const LENGTH y ) const
    {
        return LENGTH( m_Units - y.m_Units );
	template<typename Y>
	operator LENGTH<Y, P> (void) {
		return this->m_U;
	}

    /*!
     * Subtract a length inplace
     * @param y length to add
     * @return result of addition
     */
    LENGTH & operator -= ( const LENGTH y )
    {
        m_Units -= y.m_Units;
        return *this;
	/*************************/
	/* comparisons and tests */
	/*************************/
	bool operator ==(const LENGTH <T, P> y) const {
		return m_U == y.m_U;
	}

    /*!
     * Negation of length.
     * @return length negated
     */
    const LENGTH operator - ( void ) const {
        return LENGTH( - m_Units );
	bool operator !=(const LENGTH <T, P> y) const {
		return m_U != y.m_U;
	}

    /*!
     * Scale length to rational number, given numerator and denominator.
     * This is done without overflow or precision loss unlike dealing
     * with * / and floating point.
     * @param mul numerator, length is multiplied by this value
     * @param div denominator. length is divided by this value
     * @return scaled length
     */
    const LENGTH byRatio ( int mul, int div ) const
    {
        return LENGTH( ( int )( ( long long ) m_Units * mul / div ) );
	bool operator <(const LENGTH <T, P> y) const {
		return m_U < y.m_U;
	}

    /*!
     * Scale length to rational number inplace.
     * @param mul numerator, length is multiplied by this value
     * @param div denominator. length is divided by this value
     * @return scaled length
     */
    LENGTH & setByRatio ( int mul, int div )
    {
        m_Units = ( int )( ( long long ) m_Units * mul / div );
	return *this;
	bool operator >=(const LENGTH <T, P> y) const {
		return m_U >= y.m_U;
	}

    /*!
     * Multiplies length by integer number.
     * @param y factor
     * @return scaled length
     */
    const LENGTH operator * ( int y ) const
    {
        return LENGTH( m_Units * y );
	bool operator >(const LENGTH <T, P> y) const {
		return m_U > y.m_U;
	}

    /*!
     * Multiply a length inplace
     * @param y factor
     * @return scaled length
     */
    LENGTH & operator *= ( int y )
    {
        m_Units *= y;
        return *this;
	bool operator <=(const LENGTH <T, P> y) const {
		return m_U <= y.m_U;
	}

    /*!
     * Multiplies length by floating point.
     * @param y factor
     * @return scaled length
     */
    const LENGTH operator * ( double y ) const
    {
        return LENGTH( ( int )( m_Units * y ) );
	bool operator !( void ) const {
		return !m_U;
	}

    /*!
     * Multiply a length inplace
     * @param y factor
     * @return scaled length
     */
    LENGTH & operator *= ( double y )
    {
        m_Units *= y;
        return *this;
	/*************************/
	/* basic arithmetic      */
	/*************************/
	LENGTH<T, P> operator - (void) const {
		return LENGTH<T, P>(-this->m_U);
	}

    /*!
     * Multiplies integer by length ( like abowe with args swapped ).
     * @param x factor
     * @param y length
     * @return scaled length
     */
    const LENGTH friend operator * ( int x, const LENGTH y )
    {
        return y * x;
	LENGTH<T, P> operator - (const LENGTH<T, P> y) const {
		return m_U - y.m_U;
	}

    /*!
     * Multiplies floating point by length ( like abowe with args swapped ).
     * @param x factor
     * @param y length
     * @return scaled length
     */
    const LENGTH friend operator * ( double x, const LENGTH y )
    {
        return y * x;
	LENGTH<T, P> operator + (const LENGTH<T, P> y) const {
		return m_U + y.m_U;
	}

    /*!
     * Divides length by integer number.
     * @param y divider
     * @return scaled length
     */
    const LENGTH operator / ( int y ) const
    {
        return LENGTH( m_Units / y );
	template <int R>
	typename LENGTH_TRAITS<T, P + R>::flat operator * (const LENGTH<T, R> &y) const {
		return m_U * y.m_U;
	}

    /*!
     * Divide a length inplace
     * @param y divider
     * @return scaled length
     */
    LENGTH & operator /= ( int y )
    {
        m_Units /= y;
        return *this;
	LENGTH<T, P> operator * (const T &y) const {
		return m_U * y;
	}

    /*!
     * Divides length by floating point.
     * @param y divider
     * @return scaled length
     */
    const LENGTH operator / ( double y ) const
    {
        return LENGTH( ( long long )( m_Units / y ) );
	LENGTH<T, P> friend operator * (const T &y, const LENGTH<T, P> &x) {
		return x.m_U * y;
	}
	
    /*!
     * Divide a length inplace
     * @param y divider
     * @return scaled length
     */
    LENGTH & operator /= ( double y )
    {
        m_Units /= y;
        return *this;
	template <int R>
	typename LENGTH_TRAITS<T, P - R>::flat operator / (const LENGTH<T, R> &y) const {
		return m_U / y.m_U;
	}

    /*!
     * Gets ratio of two lengths.
     * It is usable to get number of length units in length by
     * division of length by length unit ( See length units below ).
     * @param y base length
     * @return scaled length
     */
    double operator / ( const LENGTH y ) const
    {
        return ( double ) m_Units / y.m_Units;
	LENGTH<T, P> operator / (const T &y) const {
		return m_U / y;
	}

    /*!
     * Gets integer ( unlike operator / ) ratio of two lengths.
     * It is usable to get number of length units in length by
     * division of length by length unit ( See length units below ).
     * @param y base length
     * @return scaled length
     */
    int idiv( const LENGTH y ) const
    {
        return ( int )( m_Units / y.m_Units );
	LENGTH<T, -P> friend operator / (const T &y, const LENGTH<T, P> &x) {
		return y / x.m_U;
	}

    /*!
     * Zero.
     * @return Zero length
     */
    static const LENGTH zero( void )
    {
        return LENGTH( 0 );
	friend LENGTH<T, P> sqrt(LENGTH<T, P*2> y) {
		return sqrt(y.m_U);
	}

    /*!
     * The metre unit.
     * @return One metre length
     */
    static const LENGTH metre( void )
    {
        return LENGTH( METER );
	friend LENGTH<T, P> cbrt(LENGTH<T, P*3> y) {
		return cbrt(y.m_U);
	}

    /*!
     * The millimetre unit.
     * @return One millimetre length
     */
    static const LENGTH millimetre( void )
    {
        return LENGTH( METER/1000 );
	/*************************/
	/* assignment arithmetic */
	/*************************/
	LENGTH<T, P>& operator -= (const LENGTH<T, P> y) {
		return m_U -= y.m_U;
	}

    /*!
     * The inch unit.
     * @return One inch length
     */
    static const LENGTH inch( void )
    {
        return LENGTH( METER/10000*254 ); // ensure it's done without precision loss
	LENGTH<T, P>& operator += (const LENGTH<T, P> y) {
		return m_U += y.m_U;
	}

    /*!
     * The mil unit.
     * @return One mil length
     */
    static const LENGTH mil( void )
    {
        return inch()/1000;
	LENGTH<T, P>& operator *= (const T y) {
		return m_U *= y;
	}

    /*!
     * Hypotenuse of a triangle with two given katheti.
     * @param y another kathetus
     * @return hypothenuse
     */
    const LENGTH hypotenuse( LENGTH y ) const
    {
        return LENGTH ( ( int ) sqrt (
                ( ( double ) m_Units * m_Units
                + ( double ) y.m_Units * y.m_Units ) ) );
	LENGTH<T, P>& operator /= (const T y) {
		return m_U /= y;
	}
	/*************************/
	/* more arithmetic       */
	/*************************/
};

    /*!
     * Another kathetus of a triangle with given hypothenuse and kathetus.
     * @param y kathetus
     * @return another kathetus
     */
    const LENGTH kathetus( LENGTH y ) const
template <typename T = DEF_LENGTH_VALUE> class LENGTH_UNITS {
protected:
    enum
    {
        return LENGTH ( ( int ) sqrt ( 
               ( ( double ) m_Units * m_Units
               - ( double ) y.m_Units * y.m_Units ) ) );
    }
        METRE = 1000000000, /* The ONLY constant connecting length to the real world */
        
        INCH = METRE / 10000 * 254
    };

/**********************************************/
/*! I'm a point/vector in a physical 2D plane */
/**********************************************/

class LENGTH_XY {
private:
    LENGTH m_X, m_Y;

	public:
    /*!
     * One given x and y coords of type LENGTH
     * @param x coordinate
     * @param y coordinate
     */
    LENGTH_XY( const LENGTH x, const LENGTH y ) : m_X( x ), m_Y( y )
    {
	static LENGTH<T, 1> metre( void ) {
		return T(METRE);
	}

    /*! 
     * A point ( or vector ) given x and y multiplies of specified unit.
     * Given just for a convenience, you can use ( x*unit, y*unit ) instead.
     * @param x coordinate factor
     * @param y coordinate factor
     * @param unit the unit
     */
    LENGTH_XY( int x, int y, const LENGTH unit ) : m_X( unit * x ), m_Y( unit * y )
    {
	static LENGTH<T, 1> decimetre( void ) {
		return T(METRE / 10);
	}

    /*! 
     * A point ( or vector ) given wxPoint and unit
     * @param x wxPoint
     * @param unit the unit
     */
    LENGTH_XY( wxPoint x, const LENGTH unit ) : m_X( unit * x.x ), m_Y( unit * x.y )
    {
	static LENGTH<T, 1> centimetre( void ) {
		return T(METRE / 100);
	}

    /*! 
     * A point ( or vector ) given wxRealPoint and unit
     * @param x wxRealPoint
     * @param unit the unit
     */
    LENGTH_XY( wxRealPoint x, const LENGTH unit ) : m_X( unit * x.x ), m_Y( unit * x.y )
    {
	static LENGTH<T, 1> millimetre( void ) {
		return T(METRE / 1000);
	}

    /*!
     * x coordinate
     * @return x coordinate
     */
    const LENGTH x( void ) const
    {
        return m_X;
	static LENGTH<T, 1> micrometre( void ) {
		return T(METRE / 1000000);
	}

    /*!
     * y coordinate
     * @return y coordinate
     */
    const LENGTH y( void ) const 
    {
        return m_Y;
	static LENGTH<T, 1> foot( void ) { /* do not think this will ever need */
		return T(INCH * 12);
	}
    
    /*!
     * Absoulte value / length
     * @return absolute value 
     */
    const LENGTH abs( void ) const
    {
        return m_X.hypotenuse(m_Y);
	static LENGTH<T, 1> inch( void ) {
		return T(INCH);
	}

    /*!
     * Equality comparison of vectors.
     * @param y vectors to compare
     * @return vectors are equal
     */
    bool operator == ( const LENGTH_XY y ) const
    {
        return m_X == y.m_X && m_Y == y.m_Y;
    }

    /*!
     * Non-equality comparison of vectors.
     * @param y vectors to compare
     * @return vectors are different
     */
    bool operator != ( const LENGTH_XY y ) const
    {
        return m_X != y.m_X || m_Y != y.m_Y;
    }

    /*!
     * Sum of two vectors ( or a point translated by vector )
     * @param y vector to add
     * @return result of addition
     */
    const LENGTH_XY operator + ( const LENGTH_XY y ) const
    {
        return LENGTH_XY( m_X + y.m_X, m_Y + y.m_Y );
    }

    /*!
     * Translate a vector inplace
     * @param y vector to add
     * @return result of addition
     */
    LENGTH_XY & operator += ( const LENGTH_XY y )
    {
        m_X += y.m_X;
        m_Y += y.m_Y;
        return *this;
    }

    /*!
     * Difference of two vectors ( or a point translated by vector in reverse direction ).
     * @param y vector to subtract
     * @return result of subtraction
     */
    const LENGTH_XY operator - ( const LENGTH_XY y ) const
    {
        return LENGTH_XY( m_X - y.m_X, m_Y - y.m_Y );
    }

    /*!
     * Translate a vector inplace in opposite direction
     * @param y vector to subtract
     * @return result of subtraction
     */
    LENGTH_XY & operator -= ( const LENGTH_XY y )
    {
        m_X -= y.m_X;
        m_Y -= y.m_Y;
        return *this;
    }

    /*!
     * Vector with reverse direction.
     * @return reverse direction vector
     */
    const LENGTH_XY operator - ( void ) const
    {
        return LENGTH_XY( - m_X, - m_Y );
    }

    /*!
     * Scale vector to rational number, given numerator and denominator.
     * This is done without overflow or precision loss unlike dealing
     * with * / and floating point.
     * @param mul numerator ( length is multiplied by this value )
     * @param div denominator ( length is divided by this value )
     * @return scaled vector
     */
    const LENGTH_XY byRatio ( int mul, int div )
    {
        return LENGTH_XY( m_X.byRatio( mul, div ), m_Y.byRatio( mul, div ) );
    }

    /*!
     * Scale vector to rational number, inplace (like operator *=).
     * @param mul numerator ( length is multiplied by this value )
     * @param div denominator ( length is divided by this value )
     * @return scaled vector
     */
    LENGTH_XY & setByRatio ( int mul, int div )
    {
        m_X.setByRatio( mul, div );
        m_Y.setByRatio( mul, div );
        return *this;
    }

    /*!
     * Multiplies vector length by integer number.
     * @param y factor
     * @return scaled vector
     */
    const LENGTH_XY operator * ( int y ) const
    {
        return LENGTH_XY( m_X * y, m_Y * y );
    }

    /*!
     * Multiply a vector inplace
     * @param y factor
     * @return scaled vector
     */
    LENGTH_XY & operator *= ( int y )
    {
        m_X *= y;
        m_Y *= y;
        return *this;
    }

    /*!
     * Multiplies vector length by floating point number.
     * @param y factor
     * @return scaled length
     */
    const LENGTH_XY operator * ( double y ) const
    {
        return LENGTH_XY( m_X * y, m_Y * y );
    }

    /*!
     * Multiply a vector inplace
     * @param y factor
     * @return scaled vector
     */
    LENGTH_XY & operator *= ( double y )
    {
        m_X *= y;
        m_Y *= y;
        return *this;
    }

    /*!
     * Divides vector length by integer number.
     * @param y divider
     * @return scaled vector
     */
    const LENGTH_XY operator / ( int y ) const
    {
        return LENGTH_XY( m_X / y, m_Y / y );
    }

    /*!
     * Divide a vector inplace
     * @param y divider
     * @return scaled vector
     */
    LENGTH_XY & operator /= ( int y )
    {
        m_X /= y;
        m_Y /= y;
        return *this;
    }

    /*!
     * Divides vector length by floating point number.
     * @param y divider
     * @return scaled vector
     */
    const LENGTH_XY operator / ( double y ) const
    {
        return LENGTH_XY( m_X / y, m_Y / y );
    }

    /*!
     * Divide a vector inplace
     * @param y divider
     * @return scaled vector
     */
    LENGTH_XY & operator /= ( double y )
    {
        m_X /= y;
        m_Y /= y;
        return *this;
	static LENGTH<T, 1> mil( void ) {
		return T(INCH / 1000);
	}
};

    /*!
     * Outputs wxPoint in specified scale.
     * @param y scale
     * @return wxPoint
     */
    const wxPoint toWxPoint ( LENGTH y ) const
    {
        return wxPoint( m_X.idiv( y ), m_Y.idiv( y ) );
    }
/* shortcut */
template <typename T, int D> class LENGTH_UNITS<LENGTH<T, D> >: public LENGTH_UNITS<T> {
};

    /*!
     * Outputs wxRealPoint in specified scale.
     * @param y scale
     * @return wxPoint
     */
    const wxRealPoint toWxRealPoint ( LENGTH y ) const
    {
        return wxRealPoint( m_X / y, m_Y / y );
    }
/* TODO: argument promotion (but is this need? explicit casts would be enough) */

    /*!
     * Rotates vector 90 degrees ( X axis towards Y )
     * @return rotated
     */
    const LENGTH_XY rot90 ( void ) const
    {
        return LENGTH_XY( m_Y, -m_X );
    }
};
#endif