QGIS API Documentation  2.0.1-Dufour
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 
31 QgsVector::QgsVector() : m_x( 0.0 ), m_y( 0.0 )
32 {
33 }
34 
35 QgsVector::QgsVector( double x, double y ) : m_x( x ), m_y( y )
36 {
37 }
38 
40 {
41  return QgsVector( -m_x, -m_y );
42 }
43 
44 QgsVector QgsVector::operator*( double scalar ) const
45 {
46  return QgsVector( m_x * scalar, m_y * scalar );
47 }
48 
49 QgsVector QgsVector::operator/( double scalar ) const
50 {
51  return *this * ( 1.0 / scalar );
52 }
53 
55 {
56  return m_x * v.m_x + m_y * v.m_y;
57 }
58 
59 double QgsVector::length() const
60 {
61  return sqrt( m_x * m_x + m_y * m_y );
62 }
63 
64 double QgsVector::x() const
65 {
66  return m_x;
67 }
68 
69 double QgsVector::y() const
70 {
71  return m_y;
72 }
73 
74 // perpendicular vector (rotated 90� counter-clockwise)
76 {
77  return QgsVector( -m_y, m_x );
78 }
79 
80 double QgsVector::angle( void ) const
81 {
82  double ang = atan2( m_y, m_x );
83  return ang < 0.0 ? ang + 2.0 * M_PI : ang;
84 }
85 
86 double QgsVector::angle( QgsVector v ) const
87 {
88  return v.angle() - angle();
89 }
90 
91 QgsVector QgsVector::rotateBy( double rot ) const
92 {
93  double ang = atan2( m_y, m_x ) + rot;
94  double len = length();
95  return QgsVector( len * cos( ang ), len * sin( ang ) );
96 }
97 
99 {
100  double len = length();
101 
102  if ( len == 0.0 )
103  {
104  throw QgsException( "normal vector of null vector undefined" );
105  }
106 
107  return *this / len;
108 }
109 
110 
111 //
112 // QgsPoint
113 //
114 
116 {
117  m_x = p.x();
118  m_y = p.y();
119 }
120 
121 QString QgsPoint::toString() const
122 {
123  QString rep;
124  QTextStream ot( &rep );
125  ot.setRealNumberPrecision( 12 );
126  ot << m_x << ", " << m_y;
127  return rep;
128 }
129 
130 QString QgsPoint::toString( int thePrecision ) const
131 {
132  QString x = qIsFinite( m_x ) ? QString::number( m_x, 'f', thePrecision ) : QObject::tr( "infinite" );
133  QString y = qIsFinite( m_y ) ? QString::number( m_y, 'f', thePrecision ) : QObject::tr( "infinite" );
134  return QString( "%1,%2" ).arg( x ).arg( y );
135 }
136 
137 QString QgsPoint::toDegreesMinutesSeconds( int thePrecision ) const
138 {
139  int myDegreesX = int( qAbs( m_x ) );
140  float myFloatMinutesX = float(( qAbs( m_x ) - myDegreesX ) * 60 );
141  int myIntMinutesX = int( myFloatMinutesX );
142  float mySecondsX = float( myFloatMinutesX - myIntMinutesX ) * 60;
143 
144  int myDegreesY = int( qAbs( m_y ) );
145  float myFloatMinutesY = float(( qAbs( m_y ) - myDegreesY ) * 60 );
146  int myIntMinutesY = int( myFloatMinutesY );
147  float mySecondsY = float( myFloatMinutesY - myIntMinutesY ) * 60;
148 
149  QString myXHemisphere = m_x < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
150  QString myYHemisphere = m_y < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
151  QString rep = QString::number( myDegreesX ) + QChar( 176 ) +
152  QString::number( myIntMinutesX ) + QString( "'" ) +
153  QString::number( mySecondsX, 'f', thePrecision ) + QString( "\"" ) +
154  myXHemisphere + QString( "," ) +
155  QString::number( myDegreesY ) + QChar( 176 ) +
156  QString::number( myIntMinutesY ) + QString( "'" ) +
157  QString::number( mySecondsY, 'f', thePrecision ) + QString( "\"" ) +
158  myYHemisphere;
159  return rep;
160 }
161 
162 QString QgsPoint::toDegreesMinutes( int thePrecision ) const
163 {
164  int myDegreesX = int( qAbs( m_x ) );
165  float myFloatMinutesX = float(( qAbs( m_x ) - myDegreesX ) * 60 );
166 
167  int myDegreesY = int( qAbs( m_y ) );
168  float myFloatMinutesY = float(( qAbs( m_y ) - myDegreesY ) * 60 );
169 
170  QString myXHemisphere = m_x < 0 ? QObject::tr( "W" ) : QObject::tr( "E" );
171  QString myYHemisphere = m_y < 0 ? QObject::tr( "S" ) : QObject::tr( "N" );
172  QString rep = QString::number( myDegreesX ) + QChar( 176 ) +
173  QString::number( myFloatMinutesX, 'f', thePrecision ) + QString( "'" ) +
174  myXHemisphere + QString( "," ) +
175  QString::number( myDegreesY ) + QChar( 176 ) +
176  QString::number( myFloatMinutesY, 'f', thePrecision ) + QString( "'" ) +
177  myYHemisphere;
178  return rep;
179 }
180 
181 QString QgsPoint::wellKnownText() const
182 {
183  return QString( "POINT(%1 %2)" ).arg( qgsDoubleToString( m_x ) ).arg( qgsDoubleToString( m_y ) );
184 }
185 
186 double QgsPoint::sqrDist( double x, double y ) const
187 {
188  return ( m_x - x ) * ( m_x - x ) + ( m_y - y ) * ( m_y - y );
189 }
190 
191 double QgsPoint::sqrDist( const QgsPoint& other ) const
192 {
193  return sqrDist( other.x(), other.y() );
194 }
195 
196 double QgsPoint::azimuth( const QgsPoint& other )
197 {
198  double dx = other.x() - m_x;
199  double dy = other.y() - m_y;
200  return ( atan2( dx, dy ) * 180.0 / M_PI );
201 }
202 
203 // operators
204 bool QgsPoint::operator==( const QgsPoint & other )
205 {
206  if (( m_x == other.x() ) && ( m_y == other.y() ) )
207  return true;
208  else
209  return false;
210 }
211 
212 bool QgsPoint::operator!=( const QgsPoint & other ) const
213 {
214  if (( m_x == other.x() ) && ( m_y == other.y() ) )
215  return false;
216  else
217  return true;
218 }
219 
221 {
222  if ( &other != this )
223  {
224  m_x = other.x();
225  m_y = other.y();
226  }
227 
228  return *this;
229 }
230 
231 void QgsPoint::multiply( const double& scalar )
232 {
233  m_x *= scalar;
234  m_y *= scalar;
235 }
236 
237 int QgsPoint::onSegment( const QgsPoint& a, const QgsPoint& b ) const
238 {
239  //algorithm from 'graphics GEMS', A. Paeth: 'A Fast 2D Point-on-line test'
240  if (
241  qAbs(( b.y() - a.y() ) *( m_x - a.x() ) - ( m_y - a.y() ) *( b.x() - a.x() ) )
242  >= qMax( qAbs( b.x() - a.x() ), qAbs( b.y() - a.y() ) )
243  )
244  {
245  return 0;
246  }
247  if (( b.x() < a.x() && a.x() < m_x ) || ( b.y() < a.y() && a.y() < m_y ) )
248  {
249  return 1;
250  }
251  if (( m_x < a.x() && a.x() < b.x() ) || ( m_y < a.y() && a.y() < b.y() ) )
252  {
253  return 1;
254  }
255  if (( a.x() < b.x() && b.x() < m_x ) || ( a.y() < b.y() && b.y() < m_y ) )
256  {
257  return 3;
258  }
259  if (( m_x < b.x() && b.x() < a.x() ) || ( m_y < b.y() && b.y() < a.y() ) )
260  {
261  return 3;
262  }
263 
264  return 2;
265 }
266 
267 double QgsPoint::sqrDistToSegment( double x1, double y1, double x2, double y2, QgsPoint& minDistPoint, double epsilon ) const
268 {
269  double nx, ny; //normal vector
270 
271  nx = y2 - y1;
272  ny = -( x2 - x1 );
273 
274  double t;
275  t = ( m_x * ny - m_y * nx - x1 * ny + y1 * nx ) / (( x2 - x1 ) * ny - ( y2 - y1 ) * nx );
276 
277  if ( t < 0.0 )
278  {
279  minDistPoint.setX( x1 );
280  minDistPoint.setY( y1 );
281  }
282  else if ( t > 1.0 )
283  {
284  minDistPoint.setX( x2 );
285  minDistPoint.setY( y2 );
286  }
287  else
288  {
289  minDistPoint.setX( x1 + t *( x2 - x1 ) );
290  minDistPoint.setY( y1 + t *( y2 - y1 ) );
291  }
292 
293  double dist = sqrDist( minDistPoint );
294  //prevent rounding errors if the point is directly on the segment
295  if ( qgsDoubleNear( dist, 0.0, epsilon ) )
296  {
297  minDistPoint.setX( m_x );
298  minDistPoint.setY( m_y );
299  return 0.0;
300  }
301  return dist;
302 }