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