/* ************************************************************************** description -------------------- copyright : (C) 2000-2001 by Andreas Zehender email : zehender@kde.org ************************************************************************** ************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * **************************************************************************/ #include "pmvector.h" #include "pmmath.h" #include "pmmatrix.h" #include "pmdebug.h" #include #include #include double PMVector::s_dummy = 0; double& PMVector::operator[] ( int index ) { if( ( index >= 0 ) && ( index < ( signed ) m_size ) ) return m_coord[index]; kdError( PMArea ) << "Bad index in PMVector operator []\n"; return s_dummy; } const double& PMVector::operator[] ( int index ) const { if( ( index >= 0 ) && ( index < ( signed ) m_size ) ) return m_coord[index]; kdError( PMArea ) << "Bad index in PMVector operator []\n"; return s_dummy; } void PMVector::allocateMemory( unsigned int size ) { m_size = size; if( m_size == 0 ) m_coord = 0; else m_coord = ( double* ) malloc( sizeof( double ) * m_size ); } PMVector::PMVector( const PMVector& v ) { unsigned int i; allocateMemory( v.m_size ); for( i = 0; i < m_size; i++ ) m_coord[i] = v.m_coord[i]; } PMVector::PMVector( ) { unsigned int i; allocateMemory( 3 ); for( i = 0; i < 3; i++ ) m_coord[i] = 0.0; } PMVector::PMVector( unsigned int s ) { unsigned int i; allocateMemory( s ); for( i = 0; i < s; i++ ) m_coord[i] = 0.0; } PMVector::PMVector( const double x, const double y ) { allocateMemory( 2 ); m_coord[0] = x; m_coord[1] = y; } PMVector::PMVector( const double x, const double y, const double z ) { allocateMemory( 3 ); m_coord[0] = x; m_coord[1] = y; m_coord[2] = z; } PMVector::PMVector( const double x, const double y, const double z, const double t ) { allocateMemory( 4 ); m_coord[0] = x; m_coord[1] = y; m_coord[2] = z; m_coord[3] = t; } PMVector::~PMVector( ) { if( m_coord ) free( m_coord ); } void PMVector::resize( unsigned int s ) { unsigned int i; if( s != m_size ) { m_coord = ( double* ) realloc( m_coord, sizeof( double ) * s ); for( i = m_size; i < s; i++ ) m_coord[i] = 0.0; if( m_coord ) m_size = s; else m_size = 0; // possibly out of memory } } void PMVector::transform( const PMMatrix& m ) { (*this) = m * (*this); } PMVector& PMVector::operator= ( const PMVector& p ) { unsigned int i; resize( p.m_size ); for( i = 0; i < m_size; i++ ) m_coord[i] = p[i]; return *this; } PMVector& PMVector::operator= ( const double d ) { unsigned int i; for( i = 0; i < m_size; i++ ) m_coord[i] = d; return *this; } PMVector& PMVector::operator*= ( const PMVector& p ) { unsigned int i; if( m_size != p.m_size ) resize( p.m_size ); for( i = 0; i < m_size; i++ ) m_coord[i] *= p[i]; return *this; } PMVector& PMVector::operator/= ( const PMVector& p ) { unsigned int i; if( m_size > p.m_size ) { kdError( PMArea ) << "Vector p is too small in PMVector& PMVector::operator/= ( const PMVector& p )\n"; } else { for( i = 0; i < m_size; i++ ) { if( approxZero( p[i] ) ) kdError( PMArea ) << "Division by zero in PMVector::operator/= " << "\n"; else m_coord[i] *= p[i]; } } return *this; } PMVector& PMVector::operator*= ( double d ) { unsigned int i; for( i = 0; i < m_size; i++ ) m_coord[i] *= d; return *this; } PMVector& PMVector::operator/= ( double d ) { if( approxZero( d ) ) { kdError( PMArea ) << "Division by zero in PMVector::operator/= " << "\n"; } else { unsigned int i; for( i = 0; i < m_size; i++ ) m_coord[i] /= d; } return *this; } PMVector& PMVector::operator+= ( double d ) { unsigned int i; for( i = 0; i < m_size; i++ ) m_coord[i] += d; return *this; } PMVector& PMVector::operator-= ( double d ) { unsigned int i; for( i = 0; i < m_size; i++ ) m_coord[i] -= d; return *this; } PMVector& PMVector::operator+= ( const PMVector& p ) { unsigned int i; if( m_size < p.m_size ) resize( p.m_size ); for( i = 0; i < p.m_size; i++ ) m_coord[i] += p[i]; return *this; } PMVector& PMVector::operator-= ( const PMVector& p ) { unsigned int i; if( m_size < p.m_size ) resize( p.m_size ); for( i = 0; i < m_size; i++ ) m_coord[i] -= p[i]; return *this; } PMVector operator- ( const PMVector& p ) { PMVector result( p.m_size ); unsigned int i; for( i = 0; i < p.m_size; i++ ) result[i] = -p[i]; return result; } PMVector operator+ ( const PMVector& p1, const PMVector& p2 ) { PMVector result( p1 ); result += p2; return result; } PMVector operator- ( const PMVector& p1, const PMVector& p2 ) { PMVector result( p1 ); result -= p2; return result; } PMVector operator* ( const PMVector& p, const double d ) { PMVector result( p.m_size ); unsigned int i; for( i = 0; i < p.m_size; i++ ) result[i] = p[i] * d; return result; } PMVector operator/ ( const PMVector& p, const double d ) { PMVector result( p.m_size ); unsigned int i; if( approxZero( d ) ) kdError( PMArea ) << "Division by zero in PMVector::operator/ ( PMVector& p, double d ) " << "\n"; else for( i = 0; i < p.m_size; i++ ) result[i] = p[i] / d; return result; } PMVector operator+ ( const PMVector& p, const double d ) { PMVector result( p.m_size ); unsigned int i; for( i = 0; i < p.m_size; i++ ) result[i] = p[i] + d; return result; } PMVector operator- ( const PMVector& p, const double d ) { PMVector result( p.m_size ); unsigned int i; for( i = 0; i < p.m_size; i++ ) result[i] = p[i] - d; return result; } PMVector operator* ( const double d, const PMVector& p ) { PMVector result( p.m_size ); unsigned int i; for( i = 0; i < p.m_size; i++ ) result[i] = p[i] * d; return result; } PMVector operator* ( const PMMatrix& m, const PMVector& p ) { PMVector result( 3 ); int c, i; // for homogenous coordinates double u; if( p.m_size != 3 ) kdError( PMArea ) << "Vector has not size 3 in PMVector operator* ( const PMVector& p, const PMMatrix& m ) \n"; else { for( c=0; c<3; c++ ) { result[c] = 0.0; for( i=0; i<4; i++ ) result[c] += m[i][c] * ( i<3 ? p[i] : 1.0 ); } u = 0.0; for( i=0; i<4; i++ ) u += m[i][3] * ( i<3 ? p[i] : 1.0 ); if( !approxZero( u ) ) for( i=0; i<3; i++ ) result[i] /= u; } return result; } PMVector operator* ( const PMVector& p1, const PMVector& p2 ) { PMVector result( p1 ); result *= p2; return result; } PMVector operator/ ( const PMVector& p1, const PMVector& p2 ) { PMVector result( p1 ); result /= p2; return result; } bool PMVector::operator== ( const PMVector& p ) const { unsigned int i; if( m_size != p.m_size ) return false; if( m_size == 0 ) return true; for( i = 0; i < m_size; i++ ) if( p.m_coord[i] != m_coord[i] ) return false; return true; } bool PMVector::approxEqual( const PMVector& p, double epsilon ) const { unsigned int i; if( m_size != p.m_size ) return false; if( m_size == 0 ) return true; for( i = 0; i < m_size; i++ ) if( ! approx( p.m_coord[i], m_coord[i], epsilon ) ) return false; return true; } bool PMVector::operator!= ( const PMVector& p ) const { return !( *this == p ); } PMVector PMVector::cross( const PMVector& v1, const PMVector& v2 ) { PMVector result; if( ( v1.size( ) == 3 ) && ( v2.size( ) == 3 ) ) { result[0] = v1[1]*v2[2] - v1[2]*v2[1]; result[1] = v1[2]*v2[0] - v1[0]*v2[2]; result[2] = v1[0]*v2[1] - v1[1]*v2[0]; } else kdError( PMArea ) << "Wrong sizes in PMVector::cross( )\n"; return result; } double PMVector::dot( const PMVector& v1, const PMVector& v2 ) { double result = 0.0; unsigned int i; if( v1.size( ) == v2.size( ) ) { for( i = 0; i < v1.size( ); i++ ) result += v1[i] * v2[i]; } else kdError( PMArea ) << "Wrong sizes in PMVector::dot( )\n"; return result; } double PMVector::angle( const PMVector& v1, const PMVector& v2 ) { PMVector cr; double s, c, n; double a = 0; int i; if( ( v1.size( ) == 3 ) && ( v2.size( ) == 3 ) ) { n = v1.abs( ) * v2.abs( ); if( approxZero( n ) ) a = 0; else { cr = cross( v1, v2 ); s = cr.abs( ) / n; c = 0; for( i = 0; i < 3; i++ ) c += v1[i] * v2[i]; c = c / n; a = pmatan( s, c ); } } else kdError( PMArea ) << "Wrong sizes in PMVector::angle( )\n"; return a; } double PMVector::abs( ) const { unsigned int i; double a = 0.0; for( i = 0; i < m_size; i++ ) a += m_coord[i] * m_coord[i]; return sqrt( a ); } PMVector PMVector::orthogonal( ) const { PMVector result; double l, rl; l = abs( ); if( approxZero( l ) ) { kdError( PMArea ) << "Can't calculate an orthogonal vector from a null vector\n"; return PMVector( 1, 0, 0 ); } result = cross( (*this) / l, PMVector( 0, 0, 1 ) ); rl = result.abs( ); if( rl < 0.001 ) { result = cross( (*this) / l, PMVector( 1, 0, 0 ) ); rl = result.abs( ); } return result / rl; } TQString PMVector::serialize( ) const { TQString result; TQTextStream str( &result, IO_WriteOnly ); unsigned int i; if( m_size > 0 ) { str << '<'; for( i = 0; i < m_size; i++ ) { if( i > 0 ) str << ", "; str << m_coord[i]; } str << '>'; } else kdError( PMArea ) << "Can't serialize a vector with size 0\n"; return result; } TQString PMVector::serializeXML( ) const { TQString result; TQTextStream str( &result, IO_WriteOnly ); unsigned int i; if( m_size > 0 ) { for( i = 0; i < m_size; i++ ) { if( i > 0 ) str << ' '; str << m_coord[i]; } } else kdError( PMArea ) << "Can't serialize a vector with size 0\n"; return result; } bool PMVector::loadXML( const TQString& str ) { int i; int size = str.contains( ' ' ) + 1; TQString tmp( str ); TQTextStream s( &tmp, IO_ReadOnly ); TQString val; bool ok; resize( size ); for( i = 0; i < size; i++ ) { s >> val; m_coord[i] = val.toDouble( &ok ); if( !ok ) return false; } return true; }