/** * @file length.h * @brief The physical length library. Made for nanometer scale. */ /* sorry if it is not styled correctly, i'll work on it further */ #ifndef LENGTH_H_INCLUDED #define LENGTH_H_INCLUDED 1 #include template < typename T = double, int P = 1 > class LENGTH; template class LENGTH_UNITS; /*! * The template that "inflate" LENGTH< T, 0 > class to T. Used with (*) and (/). */ template < typename T, int P > struct LENGTH_TRAITS { typedef LENGTH flat; }; template < typename T > struct LENGTH_TRAITS< T, 0 > { /* length dimension to power 0 is just a number, so LENGTH should be automatically converted to T */ typedef T flat; }; /*! * The template for value type conversions */ template < typename T > struct LENGTH_CASTS { /*! This function to convert length value to given type T. */ template< typename X > static T nearest( const X x ) { return T( x ); } }; template <> struct LENGTH_CASTS < int > { static int nearest( const double x ) { return floor( x + 0.5 ); } }; template <> struct LENGTH_CASTS < long > { static long nearest( const double x ) { return floor( x + 0.5 ); } }; /** Forward declaration for LIMITED_INT to use with casts. */ template < typename T > class LIMITED_INT; template < typename T > struct LENGTH_CASTS < LIMITED_INT< T > > { static LIMITED_INT< T > nearest( const double x ) { return LIMITED_INT< T > ( floor( x + 0.5 ) ); } }; /** * Length template class. * @param T actual type holding a value (be aware of precision and range!) * @param P power of length unit: 1 - length, 2 - area, 3 - volume, -1 - lin. density etc... * This class check length dimension in compile time. In runtime it behaves * exactly like contained type t (which should be numeric type, like int or double) * This class can be replaced with its contained type or simple stub. * Check rules: * - comparisons (< = etc.), addition, subtraction require values of same dimension * e. g. length with length, area with area etc. * - multiplication and division result have appropriate dimension (powers * added and subtracted respectively) * - sqrt and cbrt have appropriate dimensions (P/2 and P/3). * Limitations: * - functions which should not be applied to dimensioned values are not implemeted: * they include algebraic (exp, log...), trigo (sin, cos...), hyperbolic (sinh, cosh..) * - pow function is not implemented as it is require dimension check in runtime * you should use multiplication, division, sqrt and cbrt functions instead. * - sqrt and cbrt result type should be instantiated before they used * Be aware when using them in complex formulae, e. g. * LENGTH< double, 1 > len = cbrt(vol) - is ok, but * LENGTH< double, 3 > vol = sqrt(area*area*area*area)/length - will fail * if LENGTH<..., 4> is not instantiated * - non-integer power values do not supported * they should be implemented carefully using natural fractions, not floats, to be exact * but they are very rare so you should not worry about. * e. g. linear electric noise density should be in mV/sqrt(m) * - automatic numeric type casts are not performed. You even have to manually * cast LENGTH< short > to LENGTH< int > or LENGTH< float > * to LENGTH< double >. Anyway it is not such trouble as progremmer should be * very careful when mixing numeric types and avoid automatic casts. * */ 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: T u; /** * The 'direct' constructor which should not be accessed from outside */ LENGTH( T units ) : u( units ) { } public: typedef T value_type; enum { dimension = P }; template< typename U > LENGTH( const LENGTH< U, P > &orig ) : u( LENGTH_CASTS < T >::nearest( orig.u ) ) { } LENGTH( void ) : u() { } /** * Zero length of given type * @return A zero */ static LENGTH zero ( void ) { return T(0); } /** * Internal unit. Service function. Do not use this, please! * @return An internal unit */ static LENGTH quantum ( void ) { return T(1); } LENGTH & operator = ( const LENGTH & y ) { this->u = y.u; return *this; } /** @} */ /** * @defgroup length-comparisons Comparisons and tests * @{ */ bool operator ==( const LENGTH < T, P > y ) const { return u == y.u; } bool operator !=( const LENGTH < T, P > y ) const { return u != y.u; } bool operator <( const LENGTH < T, P > y ) const { return u < y.u; } bool operator >=( const LENGTH < T, P > y ) const { return u >= y.u; } bool operator >( const LENGTH < T, P > y ) const { return u > y.u; } bool operator <=( const LENGTH < T, P > y ) const { return u <= y.u; } bool operator !( void ) const { return !u; } /** @} */ /** * @defgroup length-arithmetic Basic arithmetic * @{ */ LENGTH< T, P > operator - ( void ) const { LENGTH< T, P > z; z.u = -u; return z; } LENGTH< T, P >& operator -= ( const LENGTH< T, P > y ) { u -= y.u; return *this; } friend LENGTH< T, P > operator - ( const LENGTH< T, P > x, const LENGTH< T, P > y ) { LENGTH< T, P > z = x; z -= y; return z; } LENGTH< T, P >& operator += ( const LENGTH< T, P > y ) { u += y.u; return *this; } friend LENGTH< T, P > operator + ( const LENGTH< T, P > x, const LENGTH< T, P > y ) { LENGTH< T, P > z = x; z += y; return z; } LENGTH< T, P >& operator *= ( const T y ) { u *= y; return *this; } LENGTH< T, P > operator * ( const T & y) const { LENGTH< T, P > z = *this; z *= y; return z; } template < int R > typename LENGTH_TRAITS< T, P + R >::flat operator * ( const LENGTH &y ) const { LENGTH< T, P + R > z; z.u = u * y.u; return z; } LENGTH< T, P > friend operator * ( const T &y, const LENGTH &x ) { return x.u * y; } LENGTH< T, P >& operator /= ( const T y ) { u /= y; return *this; } LENGTH< T, P > operator / ( const T &y ) const { return u / y; } template < int R > typename LENGTH_TRAITS< T, P - R >::flat operator / ( const LENGTH< T, R > &y ) const { return u / y.u; } LENGTH< T, -P > friend operator / ( const T &y, const LENGTH< T, P > &x ) { return y / x.u; } /** @} */ /** * @defgroup length-algebra Algebraic functions * @{ */ /** Absolute value. */ friend LENGTH< T, P > abs( LENGTH< T, P > y ) { return 0 < y.u? y : -y; } /** Maximum of two values. */ friend LENGTH< T, P > max( LENGTH< T, P > x, LENGTH< T, P > y ) { LENGTH< T, P > z; z.u = max( x.u, y.u ); return z; } /** Minimum of two values. */ friend LENGTH< T, P > min( LENGTH< T, P > x, LENGTH< T, P > y ) { LENGTH< T, P > z; z.u = min( x.u, y.u ); return z; } /** Square root. */ friend LENGTH< T, P > sqrt( LENGTH< T, P*2 > y ) { LENGTH< T, P > z; z.u = sqrt( y.u ); return z; } /** Cubic root. */ friend LENGTH< T, P > cbrt( LENGTH< T, P*3 > y ) { LENGTH< T, P > z; z.u = cbrt( y.u ); return z; } /** Hypothenuse of a triangle given katheti. */ friend LENGTH< T, P > hypot( LENGTH< T, P > x, LENGTH< T, P > y ) { LENGTH< T, P > z; z.u = hypot( x.u, y.u ); return z; } /** Direction of vector given cartesian coords. */ friend double atan2( LENGTH< T, P > x, LENGTH< T, P > y ) { return atan2( double ( x.u ), double( y.u ) ); } /** @} */ }; /*! * Units of length * * How to use them: * there are several functions, named LENGTH_UNITS< T >::METRE, which return * named unit (1 meter in example) which have type LENGTH< T, P >. * to get specific length you should use a multiplication: * 3*LENGTH_UNITS::metre() gives 3 metres * 0.01*LENGTH_UNITS::metre() gives 0.01 inch * to get numeric value of length in specific units you should use a division * length/LENGTH_UNITS::metre() gives number of metres in length * legnth/LENGTH_UNITS::foot() gives number of feet in length * * Really these units are used in NEWPCB and printing routines, as EESCHEMA * is going to use relative units. */ template < typename T > class LENGTH_UNITS { protected: enum { METRE = 1000000000, /*!< The ONLY constant connecting length to the real world */ INCH = METRE / 10000 * 254 }; public: /** One metre. */ static LENGTH< T, 1 > metre( void ) { return T( METRE ); } /** One decimetre, 0.1 m. */ static LENGTH< T, 1 > decimetre( void ) { return T( METRE / 10 ); } /** One centimetre, 0.01 m. */ static LENGTH< T, 1 > centimetre( void ) { return T( METRE / 100 ); } /** One millimetre, 0.001 m. */ static LENGTH< T, 1 > millimetre( void ) { return T( METRE / 1000 ); } /** One micrometre, 1E-6 m. */ static LENGTH< T, 1 > micrometre( void ) { return T( METRE / 1000000 ); } /** One foot, 304.8 mm, 12 inch. */ static LENGTH< T, 1 > foot( void ) { return T( INCH * 12 ); } /** One inch, 25.4 mm, 1/12 feet. */ static LENGTH< T, 1 > inch( void ) { return T( INCH ); } /** One mil (or thou), 0.001 inch . */ static LENGTH< T, 1 > mil( void ) { return T( INCH / 1000 ); } }; /** * Shortcut to get units of given length type */ template < typename T, int D > class LENGTH_UNITS< LENGTH< T, D > >: public LENGTH_UNITS< T > { }; #endif /* def LENGTH_H_INCLUDED */