QGIS API Documentation  2.17.0-Master (973e4b0)
qgspoint.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgspoint.cpp - description
3  -------------------
4  begin : Sat Jun 22 2002
5  copyright : (C) 2002 by Gary E.Sherman
6  email : sherman at mrcc.com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 
19 #include "qgspoint.h"
20 #include "qgis.h"
21 #include <cmath>
22 #include <QTextStream>
23 #include <QObject> // for tr()
24 
25 #include "qgsexception.h"
26 
27 //
28 // QgsVector
29 //
30 
32  : mX( 0.0 )
33  , mY( 0.0 )
34 {
35 }
36 
37 QgsVector::QgsVector( double x, double y )
38  : mX( x )
39  , mY( y )
40 {
41 }
42 
44 {
45  return QgsVector( -mX, -mY );
46 }
47 
48 QgsVector QgsVector::operator*( double scalar ) const
49 {
50  return QgsVector( mX * scalar, mY * scalar );
51 }
52 
53 QgsVector QgsVector::operator/( double scalar ) const
54 {
55  return *this * ( 1.0 / scalar );
56 }
57 
59 {
60  return mX * v.mX + mY * v.mY;
61 }
62 
63 double QgsVector::length() const
64 {
65  return sqrt( mX * mX + mY * mY );
66 }
67 
68 double QgsVector::x() const
69 {
70  return mX;
71 }
72 
73 double QgsVector::y() const
74 {
75  return mY;
76 }
77 
79 {
80  return QgsVector( -mY, mX );
81 }
82 
83 double QgsVector::angle() const
84 {
85  double ang = atan2( mY, mX );
86  return ang < 0.0 ? ang + 2.0 * M_PI : ang;
87 }
88 
89 double QgsVector::angle( QgsVector v ) const
90 {
91  return v.angle() - angle();
92 }
93 
94 QgsVector QgsVector::rotateBy( double rot ) const
95 {
96  double ang = atan2( mY, mX ) + rot;
97  double len = length();
98  return QgsVector( len * cos( ang ), len * sin( ang ) );
99 }
100 
102 {
103  return normalized();
104 }
105 
107 {
108  double len = length();
109 
110  if ( len == 0.0 )
111  {
112  throw QgsException( "normalized vector of null vector undefined" );
113  }
114 
115  return *this / len;
116 }
117 
118 
119 //
120 // QgsPoint
121 //
122 
124 {
125  m_x = p.x();
126  m_y = p.y();
127 }
128 
130 {
131  return QPointF( m_x, m_y );
132 }
133 
135 {
136  QString rep;
137  QTextStream ot( &rep );
138  ot.setRealNumberPrecision( 12 );
139  ot << m_x << ", " << m_y;
140  return rep;
141 }
142 
143 QString QgsPoint::toString( int thePrecision ) const
144 {
145  QString x = qIsFinite( m_x ) ? QString::number( m_x, 'f', thePrecision ) : QObject::tr( "infinite" );
146  QString y = qIsFinite( m_y ) ? QString::number( m_y, 'f', thePrecision ) : QObject::tr( "infinite" );
147  return QString( "%1,%2" ).arg( x, y );
148 }
149 
150 QString QgsPoint::toDegreesMinutesSeconds( int thePrecision, const bool useSuffix, const bool padded ) const
151 {
152  //first, limit longitude to -360 to 360 degree range
153  double myWrappedX = fmod( m_x, 360.0 );
154  //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
155  if ( myWrappedX > 180.0 )
156  {
157  myWrappedX = myWrappedX - 360.0;
158  }
159  else if ( myWrappedX < -180.0 )
160  {
161  myWrappedX = myWrappedX + 360.0;
162  }
163 
164  //first, limit latitude to -180 to 180 degree range
165  double myWrappedY = fmod( m_y, 180.0 );
166  //next, wrap around latitudes > 90 or < -90 degrees, so that eg "110S" -> "70N"
167  if ( myWrappedY > 90.0 )
168  {
169  myWrappedY = myWrappedY - 180.0;
170  }
171  else if ( myWrappedY < -90.0 )
172  {
173  myWrappedY = myWrappedY + 180.0;
174  }
175 
176  int myDegreesX = int( qAbs( myWrappedX ) );
177  double myFloatMinutesX = double(( qAbs( myWrappedX ) - myDegreesX ) * 60 );
178  int myIntMinutesX = int( myFloatMinutesX );
179  double mySecondsX = double( myFloatMinutesX - myIntMinutesX ) * 60;
180 
181  int myDegreesY = int( qAbs( myWrappedY ) );
182  double myFloatMinutesY = double(( qAbs( myWrappedY ) - myDegreesY ) * 60 );
183  int myIntMinutesY = int( myFloatMinutesY );
184  double mySecondsY = double( myFloatMinutesY - myIntMinutesY ) * 60;
185 
186  //make sure rounding to specified precision doesn't create seconds >= 60
187  if ( qRound( mySecondsX * pow( 10.0, thePrecision ) ) >= 60 * pow( 10.0, thePrecision ) )
188  {
189  mySecondsX = qMax( mySecondsX - 60, 0.0 );
190  myIntMinutesX++;
191  if ( myIntMinutesX >= 60 )
192  {
193  myIntMinutesX -= 60;
194  myDegreesX++;
195  }
196  }
197  if ( qRound( mySecondsY * pow( 10.0, thePrecision ) ) >= 60 * pow( 10.0, thePrecision ) )
198  {
199  mySecondsY = qMax( mySecondsY - 60, 0.0 );
200  myIntMinutesY++;
201  if ( myIntMinutesY >= 60 )
202  {
203  myIntMinutesY -= 60;
204  myDegreesY++;
205  }
206  }
207 
208  QString myXHemisphere;
209  QString myYHemisphere;
210  QString myXSign;
211  QString myYSign;
212  if ( useSuffix )
213  {
214  myXHemisphere = myWrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
215  myYHemisphere = myWrappedY < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
216  }
217  else
218  {
219  if ( myWrappedX < 0 )
220  {
221  myXSign = QObject::tr( "-" );
222  }
223  if ( myWrappedY < 0 )
224  {
225  myYSign = QObject::tr( "-" );
226  }
227  }
228  //check if coordinate is all zeros for the specified precision, and if so,
229  //remove the sign and hemisphere strings
230  if ( myDegreesX == 0 && myIntMinutesX == 0 && qRound( mySecondsX * pow( 10.0, thePrecision ) ) == 0 )
231  {
232  myXSign = QString();
233  myXHemisphere = QString();
234  }
235  if ( myDegreesY == 0 && myIntMinutesY == 0 && qRound( mySecondsY * pow( 10.0, thePrecision ) ) == 0 )
236  {
237  myYSign = QString();
238  myYHemisphere = QString();
239  }
240  //also remove directional prefix from 180 degree longitudes
241  if ( myDegreesX == 180 && myIntMinutesX == 0 && qRound( mySecondsX * pow( 10.0, thePrecision ) ) == 0 )
242  {
243  myXHemisphere = QString();
244  }
245  //pad minutes with leading digits if required
246  QString myMinutesX = padded ? QString( "%1" ).arg( myIntMinutesX, 2, 10, QChar( '0' ) ) : QString::number( myIntMinutesX );
247  QString myMinutesY = padded ? QString( "%1" ).arg( myIntMinutesY, 2, 10, QChar( '0' ) ) : QString::number( myIntMinutesY );
248  //pad seconds with leading digits if required
249  int digits = 2 + ( thePrecision == 0 ? 0 : 1 + thePrecision ); //1 for decimal place if required
250  QString myStrSecondsX = padded ? QString( "%1" ).arg( mySecondsX, digits, 'f', thePrecision, QChar( '0' ) ) : QString::number( mySecondsX, 'f', thePrecision );
251  QString myStrSecondsY = padded ? QString( "%1" ).arg( mySecondsY, digits, 'f', thePrecision, QChar( '0' ) ) : QString::number( mySecondsY, 'f', thePrecision );
252 
253  QString rep = myXSign + QString::number( myDegreesX ) + QChar( 176 ) +
254  myMinutesX + QChar( 0x2032 ) +
255  myStrSecondsX + QChar( 0x2033 ) +
256  myXHemisphere + ',' +
257  myYSign + QString::number( myDegreesY ) + QChar( 176 ) +
258  myMinutesY + QChar( 0x2032 ) +
259  myStrSecondsY + QChar( 0x2033 ) +
260  myYHemisphere;
261  return rep;
262 }
263 
264 QString QgsPoint::toDegreesMinutes( int thePrecision, const bool useSuffix, const bool padded ) const
265 {
266  //first, limit longitude to -360 to 360 degree range
267  double myWrappedX = fmod( m_x, 360.0 );
268  //next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
269  if ( myWrappedX > 180.0 )
270  {
271  myWrappedX = myWrappedX - 360.0;
272  }
273  else if ( myWrappedX < -180.0 )
274  {
275  myWrappedX = myWrappedX + 360.0;
276  }
277 
278  int myDegreesX = int( qAbs( myWrappedX ) );
279  double myFloatMinutesX = double(( qAbs( myWrappedX ) - myDegreesX ) * 60 );
280 
281  int myDegreesY = int( qAbs( m_y ) );
282  double myFloatMinutesY = double(( qAbs( m_y ) - myDegreesY ) * 60 );
283 
284  //make sure rounding to specified precision doesn't create minutes >= 60
285  if ( qRound( myFloatMinutesX * pow( 10.0, thePrecision ) ) >= 60 * pow( 10.0, thePrecision ) )
286  {
287  myFloatMinutesX = qMax( myFloatMinutesX - 60, 0.0 );
288  myDegreesX++;
289  }
290  if ( qRound( myFloatMinutesY * pow( 10.0, thePrecision ) ) >= 60 * pow( 10.0, thePrecision ) )
291  {
292  myFloatMinutesY = qMax( myFloatMinutesY - 60, 0.0 );
293  myDegreesY++;
294  }
295 
296  QString myXHemisphere;
297  QString myYHemisphere;
298  QString myXSign;
299  QString myYSign;
300  if ( useSuffix )
301  {
302  myXHemisphere = myWrappedX < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
303  myYHemisphere = m_y < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
304  }
305  else
306  {
307  if ( myWrappedX < 0 )
308  {
309  myXSign = QObject::tr( "-" );
310  }
311  if ( m_y < 0 )
312  {
313  myYSign = QObject::tr( "-" );
314  }
315  }
316  //check if coordinate is all zeros for the specified precision, and if so,
317  //remove the sign and hemisphere strings
318  if ( myDegreesX == 0 && qRound( myFloatMinutesX * pow( 10.0, thePrecision ) ) == 0 )
319  {
320  myXSign = QString();
321  myXHemisphere = QString();
322  }
323  if ( myDegreesY == 0 && qRound( myFloatMinutesY * pow( 10.0, thePrecision ) ) == 0 )
324  {
325  myYSign = QString();
326  myYHemisphere = QString();
327  }
328  //also remove directional prefix from 180 degree longitudes
329  if ( myDegreesX == 180 && qRound( myFloatMinutesX * pow( 10.0, thePrecision ) ) == 0 )
330  {
331  myXHemisphere = QString();
332  }
333 
334  //pad minutes with leading digits if required
335  int digits = 2 + ( thePrecision == 0 ? 0 : 1 + thePrecision ); //1 for decimal place if required
336  QString myStrMinutesX = padded ? QString( "%1" ).arg( myFloatMinutesX, digits, 'f', thePrecision, QChar( '0' ) ) : QString::number( myFloatMinutesX, 'f', thePrecision );
337  QString myStrMinutesY = padded ? QString( "%1" ).arg( myFloatMinutesY, digits, 'f', thePrecision, QChar( '0' ) ) : QString::number( myFloatMinutesY, 'f', thePrecision );
338 
339  QString rep = myXSign + QString::number( myDegreesX ) + QChar( 176 ) +
340  myStrMinutesX + QChar( 0x2032 ) +
341  myXHemisphere + ',' +
342  myYSign + QString::number( myDegreesY ) + QChar( 176 ) +
343  myStrMinutesY + QChar( 0x2032 ) +
344  myYHemisphere;
345  return rep;
346 }
347 
349 {
350  return QString( "POINT(%1 %2)" ).arg( qgsDoubleToString( m_x ), qgsDoubleToString( m_y ) );
351 }
352 
353 double QgsPoint::sqrDist( double x, double y ) const
354 {
355  return ( m_x - x ) * ( m_x - x ) + ( m_y - y ) * ( m_y - y );
356 }
357 
358 double QgsPoint::sqrDist( const QgsPoint& other ) const
359 {
360  return sqrDist( other.x(), other.y() );
361 }
362 
363 double QgsPoint::distance( double x, double y ) const
364 {
365  return sqrt( sqrDist( x, y ) );
366 }
367 
368 double QgsPoint::distance( const QgsPoint& other ) const
369 {
370  return sqrt( sqrDist( other ) );
371 }
372 
373 double QgsPoint::azimuth( const QgsPoint& other ) const
374 {
375  double dx = other.x() - m_x;
376  double dy = other.y() - m_y;
377  return ( atan2( dx, dy ) * 180.0 / M_PI );
378 }
379 
380 QgsPoint QgsPoint::project( double distance, double bearing ) const
381 {
382  double rads = bearing * M_PI / 180.0;
383  double dx = distance * sin( rads );
384  double dy = distance * cos( rads );
385  return QgsPoint( m_x + dx, m_y + dy );
386 }
387 
388 bool QgsPoint::compare( const QgsPoint &other, double epsilon ) const
389 {
390  return ( qgsDoubleNear( m_x, other.x(), epsilon ) && qgsDoubleNear( m_y, other.y(), epsilon ) );
391 }
392 
393 // operators
394 bool QgsPoint::operator==( const QgsPoint & other )
395 {
396  if ( qgsDoubleNear( m_x, other.x() ) && qgsDoubleNear( m_y, other.y() ) )
397  return true;
398  else
399  return false;
400 }
401 
402 bool QgsPoint::operator!=( const QgsPoint & other ) const
403 {
404  if ( qgsDoubleNear( m_x, other.x() ) && qgsDoubleNear( m_y, other.y() ) )
405  return false;
406  else
407  return true;
408 }
409 
411 {
412  if ( &other != this )
413  {
414  m_x = other.x();
415  m_y = other.y();
416  }
417 
418  return *this;
419 }
420 
421 void QgsPoint::multiply( double scalar )
422 {
423  m_x *= scalar;
424  m_y *= scalar;
425 }
426 
427 int QgsPoint::onSegment( const QgsPoint& a, const QgsPoint& b ) const
428 {
429  //algorithm from 'graphics GEMS', A. Paeth: 'A Fast 2D Point-on-line test'
430  if (
431  qAbs(( b.y() - a.y() ) *( m_x - a.x() ) - ( m_y - a.y() ) *( b.x() - a.x() ) )
432  >= qMax( qAbs( b.x() - a.x() ), qAbs( b.y() - a.y() ) )
433  )
434  {
435  return 0;
436  }
437  if (( b.x() < a.x() && a.x() < m_x ) || ( b.y() < a.y() && a.y() < m_y ) )
438  {
439  return 1;
440  }
441  if (( m_x < a.x() && a.x() < b.x() ) || ( m_y < a.y() && a.y() < b.y() ) )
442  {
443  return 1;
444  }
445  if (( a.x() < b.x() && b.x() < m_x ) || ( a.y() < b.y() && b.y() < m_y ) )
446  {
447  return 3;
448  }
449  if (( m_x < b.x() && b.x() < a.x() ) || ( m_y < b.y() && b.y() < a.y() ) )
450  {
451  return 3;
452  }
453 
454  return 2;
455 }
456 
457 double QgsPoint::sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint, double epsilon ) const
458 {
459  double nx, ny; //normal vector
460 
461  nx = y2 - y1;
462  ny = -( x2 - x1 );
463 
464  double t;
465  t = ( m_x * ny - m_y * nx - x1 * ny + y1 * nx ) / (( x2 - x1 ) * ny - ( y2 - y1 ) * nx );
466 
467  if ( t < 0.0 )
468  {
469  minDistPoint.setX( x1 );
470  minDistPoint.setY( y1 );
471  }
472  else if ( t > 1.0 )
473  {
474  minDistPoint.setX( x2 );
475  minDistPoint.setY( y2 );
476  }
477  else
478  {
479  minDistPoint.setX( x1 + t *( x2 - x1 ) );
480  minDistPoint.setY( y1 + t *( y2 - y1 ) );
481  }
482 
483  double dist = sqrDist( minDistPoint );
484  //prevent rounding errors if the point is directly on the segment
485  if ( qgsDoubleNear( dist, 0.0, epsilon ) )
486  {
487  minDistPoint.setX( m_x );
488  minDistPoint.setY( m_y );
489  return 0.0;
490  }
491  return dist;
492 }
QgsVector()
Default constructor for QgsVector.
Definition: qgspoint.cpp:31
QgsVector rotateBy(double rot) const
Rotates the vector by a specified angle.
Definition: qgspoint.cpp:94
int onSegment(const QgsPoint &a, const QgsPoint &b) const
Test if this point is on the segment defined by points a, b.
Definition: qgspoint.cpp:427
void setRealNumberPrecision(int precision)
void multiply(double scalar)
Multiply x and y by the given value.
Definition: qgspoint.cpp:421
QgsPoint project(double distance, double bearing) const
Returns a new point which correponds to this point projected by a specified distance in a specified b...
Definition: qgspoint.cpp:380
QgsPoint & operator=(const QgsPoint &other)
Assignment.
Definition: qgspoint.cpp:410
double y() const
Returns the vector&#39;s y-component.
Definition: qgspoint.cpp:73
double sqrDist(double x, double y) const
Returns the squared distance between this point a specified x, y coordinate.
Definition: qgspoint.cpp:353
QString tr(const char *sourceText, const char *disambiguation, int n)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Compare two doubles (but allow some difference)
Definition: qgis.h:353
double x() const
Get the x value of the point.
Definition: qgspoint.h:185
bool operator!=(const QgsPoint &other) const
Inequality operator.
Definition: qgspoint.cpp:402
QgsPoint()
Default constructor.
Definition: qgspoint.h:121
QString number(int n, int base)
double angle() const
Returns the angle of the vector in radians.
Definition: qgspoint.cpp:83
double azimuth(const QgsPoint &other) const
Calculates azimuth between this point and other one (clockwise in degree, starting from north) ...
Definition: qgspoint.cpp:373
QString qgsDoubleToString(double a, int precision=17)
Returns a string representation of a double.
Definition: qgis.h:341
QgsVector perpVector() const
Returns the perpendicular vector to this vector (rotated 90 degrees counter-clockwise) ...
Definition: qgspoint.cpp:78
double sqrDistToSegment(double x1, double y1, double x2, double y2, QgsPoint &minDistPoint, double epsilon=DEFAULT_SEGMENT_EPSILON) const
Returns the minimum distance between this point and a segment.
Definition: qgspoint.cpp:457
#define M_PI
bool operator==(const QgsPoint &other)
equality operator
Definition: qgspoint.cpp:394
QString toString() const
String representation of the point (x,y)
Definition: qgspoint.cpp:134
QgsVector operator-() const
Swaps the sign of the x and y components of the vector.
Definition: qgspoint.cpp:43
QgsVector normalized() const
Returns the vector&#39;s normalized (or "unit") vector (ie same angle but length of 1.0).
Definition: qgspoint.cpp:106
A class to represent a point.
Definition: qgspoint.h:117
A class to represent a vector.
Definition: qgspoint.h:32
void setX(double x)
Sets the x value of the point.
Definition: qgspoint.h:162
double length() const
Returns the length of the vector.
Definition: qgspoint.cpp:63
double distance(double x, double y) const
Returns the distance between this point and a specified x, y coordinate.
Definition: qgspoint.cpp:363
void setY(double y)
Sets the y value of the point.
Definition: qgspoint.h:170
Q_DECL_DEPRECATED QgsVector normal() const
Returns the vector&#39;s normalized (or "unit") vector (ie same angle but length of 1.0).
Definition: qgspoint.cpp:101
QString toDegreesMinutes(int thePrecision, const bool useSuffix=true, const bool padded=false) const
Return a string representation as degrees minutes.
Definition: qgspoint.cpp:264
QgsVector operator*(double scalar) const
Returns a vector where the components have been multiplied by a scalar value.
Definition: qgspoint.cpp:48
double y() const
Get the y value of the point.
Definition: qgspoint.h:193
QString toDegreesMinutesSeconds(int thePrecision, const bool useSuffix=true, const bool padded=false) const
Return a string representation as degrees minutes seconds.
Definition: qgspoint.cpp:150
double x() const
Returns the vector&#39;s x-component.
Definition: qgspoint.cpp:68
QgsVector operator/(double scalar) const
Returns a vector where the components have been divided by a scalar value.
Definition: qgspoint.cpp:53
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
Defines a qgis exception class.
Definition: qgsexception.h:25
QString wellKnownText() const
Return the well known text representation for the point.
Definition: qgspoint.cpp:348
bool compare(const QgsPoint &other, double epsilon=4 *DBL_EPSILON) const
Compares this point with another point with a fuzzy tolerance.
Definition: qgspoint.cpp:388
QPointF toQPointF() const
Converts a point to a QPointF.
Definition: qgspoint.cpp:129