Quantum GIS API Documentation
1.7.4
|
00001 /*************************************************************************** 00002 qgspoint.cpp - description 00003 ------------------- 00004 begin : Sat Jun 22 2002 00005 copyright : (C) 2002 by Gary E.Sherman 00006 email : sherman at mrcc.com 00007 ***************************************************************************/ 00008 00009 /*************************************************************************** 00010 * * 00011 * This program is free software; you can redistribute it and/or modify * 00012 * it under the terms of the GNU General Public License as published by * 00013 * the Free Software Foundation; either version 2 of the License, or * 00014 * (at your option) any later version. * 00015 * * 00016 ***************************************************************************/ 00017 /* $Id$ */ 00018 00019 00020 #include "qgspoint.h" 00021 #include "qgis.h" 00022 #include <cmath> 00023 #include <QTextStream> 00024 #include <QObject> // for tr() 00025 00026 #include "qgsexception.h" 00027 00028 // 00029 // QgsVector 00030 // 00031 00032 QgsVector::QgsVector() : m_x( 0.0 ), m_y( 0.0 ) 00033 { 00034 } 00035 00036 QgsVector::QgsVector( double x, double y ) : m_x( x ), m_y( y ) 00037 { 00038 } 00039 00040 QgsVector QgsVector::operator-( void ) const 00041 { 00042 return QgsVector( -m_x, -m_y ); 00043 } 00044 00045 QgsVector QgsVector::operator*( double scalar ) const 00046 { 00047 return QgsVector( m_x * scalar, m_y * scalar ); 00048 } 00049 00050 QgsVector QgsVector::operator/( double scalar ) const 00051 { 00052 return *this * ( 1.0 / scalar ); 00053 } 00054 00055 double QgsVector::operator*( QgsVector v ) const 00056 { 00057 return m_x * v.m_x + m_y * v.m_y; 00058 } 00059 00060 double QgsVector::length() const 00061 { 00062 return sqrt( m_x * m_x + m_y * m_y ); 00063 } 00064 00065 double QgsVector::x() const 00066 { 00067 return m_x; 00068 } 00069 00070 double QgsVector::y() const 00071 { 00072 return m_y; 00073 } 00074 00075 // perpendicular vector (rotated 90� counter-clockwise) 00076 QgsVector QgsVector::perpVector() const 00077 { 00078 return QgsVector( -m_y, m_x ); 00079 } 00080 00081 double QgsVector::angle( void ) const 00082 { 00083 double ang = atan2( m_y, m_x ); 00084 return ang < 0.0 ? ang + 2.0 * M_PI : ang; 00085 } 00086 00087 double QgsVector::angle( QgsVector v ) const 00088 { 00089 return v.angle() - angle(); 00090 } 00091 00092 QgsVector QgsVector::rotateBy( double rot ) const 00093 { 00094 double ang = atan2( m_y, m_x ) + rot; 00095 double len = length(); 00096 return QgsVector( len * cos( ang ), len * sin( ang ) ); 00097 } 00098 00099 QgsVector QgsVector::normal() const 00100 { 00101 double len = length(); 00102 00103 if ( len == 0.0 ) 00104 { 00105 throw QgsException( "normal vector of null vector undefined" ); 00106 } 00107 00108 return *this / len; 00109 } 00110 00111 00112 // 00113 // QgsPoint 00114 // 00115 00116 QgsPoint::QgsPoint( const QgsPoint& p ) 00117 { 00118 m_x = p.x(); 00119 m_y = p.y(); 00120 } 00121 00122 QString QgsPoint::toString() const 00123 { 00124 QString rep; 00125 QTextStream ot( &rep ); 00126 ot.setRealNumberPrecision( 12 ); 00127 ot << m_x << ", " << m_y; 00128 return rep; 00129 } 00130 00131 QString QgsPoint::toString( int thePrecision ) const 00132 { 00133 QString rep = QString::number( m_x, 'f', thePrecision ) + QString( "," ) + 00134 QString::number( m_y, 'f', thePrecision ); 00135 return rep; 00136 } 00137 00138 QString QgsPoint::toDegreesMinutesSeconds( int thePrecision ) const 00139 { 00140 int myDegreesX = int( qAbs( m_x ) ); 00141 float myFloatMinutesX = float(( qAbs( m_x ) - myDegreesX ) * 60 ); 00142 int myIntMinutesX = int( myFloatMinutesX ); 00143 float mySecondsX = float( myFloatMinutesX - myIntMinutesX ) * 60; 00144 00145 int myDegreesY = int( qAbs( m_y ) ); 00146 float myFloatMinutesY = float(( qAbs( m_y ) - myDegreesY ) * 60 ); 00147 int myIntMinutesY = int( myFloatMinutesY ); 00148 float mySecondsY = float( myFloatMinutesY - myIntMinutesY ) * 60; 00149 00150 QString myXHemisphere = m_x < 0 ? QObject::tr( "W" ) : QObject::tr( "E" ); 00151 QString myYHemisphere = m_y < 0 ? QObject::tr( "S" ) : QObject::tr( "N" ); 00152 QString rep = QString::number( myDegreesX ) + QChar( 176 ) + 00153 QString::number( myIntMinutesX ) + QString( "'" ) + 00154 QString::number( mySecondsX, 'f', thePrecision ) + QString( "\"" ) + 00155 myXHemisphere + QString( "," ) + 00156 QString::number( myDegreesY ) + QChar( 176 ) + 00157 QString::number( myIntMinutesY ) + QString( "'" ) + 00158 QString::number( mySecondsY, 'f', thePrecision ) + QString( "\"" ) + 00159 myYHemisphere; 00160 return rep; 00161 } 00162 00163 00164 QString QgsPoint::wellKnownText() const 00165 { 00166 return QString( "POINT(%1 %2)" ).arg( QString::number( m_x, 'f', 18 ) ).arg( QString::number( m_y, 'f', 18 ) ); 00167 } 00168 00169 double QgsPoint::sqrDist( double x, double y ) const 00170 { 00171 return ( m_x - x ) * ( m_x - x ) + ( m_y - y ) * ( m_y - y ); 00172 } 00173 00174 double QgsPoint::sqrDist( const QgsPoint& other ) const 00175 { 00176 return sqrDist( other.x(), other.y() ); 00177 } 00178 00179 double QgsPoint::azimuth( const QgsPoint& other ) 00180 { 00181 double dx = other.x() - m_x; 00182 double dy = other.y() - m_y; 00183 return ( atan2( dx, dy ) * 180.0 / M_PI ); 00184 } 00185 00186 // operators 00187 bool QgsPoint::operator==( const QgsPoint & other ) 00188 { 00189 if (( m_x == other.x() ) && ( m_y == other.y() ) ) 00190 return true; 00191 else 00192 return false; 00193 } 00194 00195 bool QgsPoint::operator!=( const QgsPoint & other ) const 00196 { 00197 if (( m_x == other.x() ) && ( m_y == other.y() ) ) 00198 return false; 00199 else 00200 return true; 00201 } 00202 00203 QgsPoint & QgsPoint::operator=( const QgsPoint & other ) 00204 { 00205 if ( &other != this ) 00206 { 00207 m_x = other.x(); 00208 m_y = other.y(); 00209 } 00210 00211 return *this; 00212 } 00213 00214 void QgsPoint::multiply( const double& scalar ) 00215 { 00216 m_x *= scalar; 00217 m_y *= scalar; 00218 } 00219 00220 int QgsPoint::onSegment( const QgsPoint& a, const QgsPoint& b ) const 00221 { 00222 //algorithm from 'graphics GEMS', A. Paeth: 'A Fast 2D Point-on-line test' 00223 if ( 00224 qAbs(( b.y() - a.y() ) *( m_x - a.x() ) - ( m_y - a.y() ) *( b.x() - a.x() ) ) 00225 >= qMax( qAbs( b.x() - a.x() ), qAbs( b.y() - a.y() ) ) 00226 ) 00227 { 00228 return 0; 00229 } 00230 if (( b.x() < a.x() && a.x() < m_x ) || ( b.y() < a.y() && a.y() < m_y ) ) 00231 { 00232 return 1; 00233 } 00234 if (( m_x < a.x() && a.x() < b.x() ) || ( m_y < a.y() && a.y() < b.y() ) ) 00235 { 00236 return 1; 00237 } 00238 if (( a.x() < b.x() && b.x() < m_x ) || ( a.y() < b.y() && b.y() < m_y ) ) 00239 { 00240 return 3; 00241 } 00242 if (( m_x < b.x() && b.x() < a.x() ) || ( m_y < b.y() && b.y() < a.y() ) ) 00243 { 00244 return 3; 00245 } 00246 00247 return 2; 00248 } 00249 00250 double QgsPoint::sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint ) const 00251 { 00252 double nx, ny; //normal vector 00253 00254 nx = y2 - y1; 00255 ny = -( x2 - x1 ); 00256 00257 double t; 00258 t = ( m_x * ny - m_y * nx - x1 * ny + y1 * nx ) / (( x2 - x1 ) * ny - ( y2 - y1 ) * nx ); 00259 00260 if ( t < 0.0 ) 00261 { 00262 minDistPoint.setX( x1 ); 00263 minDistPoint.setY( y1 ); 00264 } 00265 else if ( t > 1.0 ) 00266 { 00267 minDistPoint.setX( x2 ); 00268 minDistPoint.setY( y2 ); 00269 } 00270 else 00271 { 00272 minDistPoint.setX( x1 + t *( x2 - x1 ) ); 00273 minDistPoint.setY( y1 + t *( y2 - y1 ) ); 00274 } 00275 00276 double dist = sqrDist( minDistPoint ); 00277 //prevent rounding errors if the point is directly on the segment 00278 if ( doubleNear( dist, 0.0, 0.00000001 ) ) 00279 { 00280 minDistPoint.setX( m_x ); 00281 minDistPoint.setY( m_y ); 00282 return 0.0; 00283 } 00284 return dist; 00285 }