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