@@ -134,46 +134,188 @@ QString QgsPoint::toString( int thePrecision ) const
134134 return QString ( " %1,%2" ).arg ( x ).arg ( y );
135135}
136136
137- QString QgsPoint::toDegreesMinutesSeconds ( int thePrecision ) const
137+ QString QgsPoint::toDegreesMinutesSeconds ( int thePrecision, const bool useSuffix, const bool padded ) const
138138{
139- int myDegreesX = int ( qAbs ( m_x ) );
140- float myFloatMinutesX = float (( qAbs ( m_x ) - myDegreesX ) * 60 );
139+ // first, limit longitude to -360 to 360 degree range
140+ double myWrappedX = fmod ( m_x, 360.0 );
141+ // next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
142+ if ( myWrappedX > 180.0 )
143+ {
144+ myWrappedX = myWrappedX - 360.0 ;
145+ }
146+ else if ( myWrappedX < -180.0 )
147+ {
148+ myWrappedX = myWrappedX + 360.0 ;
149+ }
150+
151+ int myDegreesX = int ( qAbs ( myWrappedX ) );
152+ double myFloatMinutesX = double (( qAbs ( myWrappedX ) - myDegreesX ) * 60 );
141153 int myIntMinutesX = int ( myFloatMinutesX );
142- float mySecondsX = float ( myFloatMinutesX - myIntMinutesX ) * 60 ;
154+ double mySecondsX = double ( myFloatMinutesX - myIntMinutesX ) * 60 ;
143155
144156 int myDegreesY = int ( qAbs ( m_y ) );
145- float myFloatMinutesY = float (( qAbs ( m_y ) - myDegreesY ) * 60 );
157+ double myFloatMinutesY = double (( qAbs ( m_y ) - myDegreesY ) * 60 );
146158 int myIntMinutesY = int ( myFloatMinutesY );
147- float mySecondsY = float ( myFloatMinutesY - myIntMinutesY ) * 60 ;
159+ double mySecondsY = double ( myFloatMinutesY - myIntMinutesY ) * 60 ;
148160
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 ( " \" " ) +
161+ // make sure rounding to specified precision doesn't create seconds >= 60
162+ if ( qRound ( mySecondsX * pow ( 10 , thePrecision ) ) >= 60 * pow ( 10 , thePrecision ) )
163+ {
164+ mySecondsX = qMax ( mySecondsX - 60 , 0.0 );
165+ myIntMinutesX++;
166+ if ( myIntMinutesX >= 60 )
167+ {
168+ myIntMinutesX -= 60 ;
169+ myDegreesX++;
170+ }
171+ }
172+ if ( qRound ( mySecondsY * pow ( 10 , thePrecision ) ) >= 60 * pow ( 10 , thePrecision ) )
173+ {
174+ mySecondsY = qMax ( mySecondsY - 60 , 0.0 );
175+ myIntMinutesY++;
176+ if ( myIntMinutesY >= 60 )
177+ {
178+ myIntMinutesY -= 60 ;
179+ myDegreesY++;
180+ }
181+ }
182+
183+ QString myXHemisphere;
184+ QString myYHemisphere;
185+ QString myXSign;
186+ QString myYSign;
187+ if ( useSuffix )
188+ {
189+ myXHemisphere = myWrappedX < 0 ? QObject::tr ( " W" ) : QObject::tr ( " E" );
190+ myYHemisphere = m_y < 0 ? QObject::tr ( " S" ) : QObject::tr ( " N" );
191+ }
192+ else
193+ {
194+ if ( myWrappedX < 0 )
195+ {
196+ myXSign = QObject::tr ( " -" );
197+ }
198+ if ( m_y < 0 )
199+ {
200+ myYSign = QObject::tr ( " -" );
201+ }
202+ }
203+ // check if coordinate is all zeros for the specified precision, and if so,
204+ // remove the sign and hemisphere strings
205+ if ( myDegreesX == 0 && myIntMinutesX == 0 && qRound ( mySecondsX * pow ( 10 , thePrecision ) ) == 0 )
206+ {
207+ myXSign = QString ();
208+ myXHemisphere = QString ();
209+ }
210+ if ( myDegreesY == 0 && myIntMinutesY == 0 && qRound ( mySecondsY * pow ( 10 , thePrecision ) ) == 0 )
211+ {
212+ myYSign = QString ();
213+ myYHemisphere = QString ();
214+ }
215+ // also remove directional prefix from 180 degree longitudes
216+ if ( myDegreesX == 180 && myIntMinutesX == 0 && qRound ( mySecondsX * pow ( 10 , thePrecision ) ) == 0 )
217+ {
218+ myXHemisphere = QString ();
219+ }
220+ // pad minutes with leading digits if required
221+ QString myMinutesX = padded ? QString ( " %1" ).arg ( myIntMinutesX, 2 , 10 , QChar ( ' 0' ) ) : QString::number ( myIntMinutesX );
222+ QString myMinutesY = padded ? QString ( " %1" ).arg ( myIntMinutesY, 2 , 10 , QChar ( ' 0' ) ) : QString::number ( myIntMinutesY );
223+ // pad seconds with leading digits if required
224+ int digits = 2 + ( thePrecision == 0 ? 0 : 1 + thePrecision ); // 1 for decimal place if required
225+ QString myStrSecondsX = padded ? QString ( " %1" ).arg ( mySecondsX, digits, ' f' , thePrecision, QChar ( ' 0' ) ) : QString::number ( mySecondsX, ' f' , thePrecision );
226+ QString myStrSecondsY = padded ? QString ( " %1" ).arg ( mySecondsY, digits, ' f' , thePrecision, QChar ( ' 0' ) ) : QString::number ( mySecondsY, ' f' , thePrecision );
227+
228+ QString rep = myXSign + QString::number ( myDegreesX ) + QChar ( 176 ) +
229+ myMinutesX + QString ( " '" ) +
230+ myStrSecondsX + QString ( " \" " ) +
154231 myXHemisphere + QString ( " ," ) +
155- QString::number ( myDegreesY ) + QChar ( 176 ) +
156- QString::number ( myIntMinutesY ) + QString ( " '" ) +
157- QString::number ( mySecondsY, ' f ' , thePrecision ) + QString ( " \" " ) +
232+ myYSign + QString::number ( myDegreesY ) + QChar ( 176 ) +
233+ myMinutesY + QString ( " '" ) +
234+ myStrSecondsY + QString ( " \" " ) +
158235 myYHemisphere;
159236 return rep;
160237}
161238
162- QString QgsPoint::toDegreesMinutes ( int thePrecision ) const
239+ QString QgsPoint::toDegreesMinutes ( int thePrecision, const bool useSuffix, const bool padded ) const
163240{
164- int myDegreesX = int ( qAbs ( m_x ) );
165- float myFloatMinutesX = float (( qAbs ( m_x ) - myDegreesX ) * 60 );
241+ // first, limit longitude to -360 to 360 degree range
242+ double myWrappedX = fmod ( m_x, 360.0 );
243+ // next, wrap around longitudes > 180 or < -180 degrees, so that eg "190E" -> "170W"
244+ if ( myWrappedX > 180.0 )
245+ {
246+ myWrappedX = myWrappedX - 360.0 ;
247+ }
248+ else if ( myWrappedX < -180.0 )
249+ {
250+ myWrappedX = myWrappedX + 360.0 ;
251+ }
252+
253+ int myDegreesX = int ( qAbs ( myWrappedX ) );
254+ double myFloatMinutesX = double (( qAbs ( myWrappedX ) - myDegreesX ) * 60 );
166255
167256 int myDegreesY = int ( qAbs ( m_y ) );
168- float myFloatMinutesY = float (( qAbs ( m_y ) - myDegreesY ) * 60 );
257+ double myFloatMinutesY = double (( qAbs ( m_y ) - myDegreesY ) * 60 );
258+
259+ // make sure rounding to specified precision doesn't create minutes >= 60
260+ if ( qRound ( myFloatMinutesX * pow ( 10 , thePrecision ) ) >= 60 * pow ( 10 , thePrecision ) )
261+ {
262+ myFloatMinutesX = qMax ( myFloatMinutesX - 60 , 0.0 );
263+ myDegreesX++;
264+ }
265+ if ( qRound ( myFloatMinutesY * pow ( 10 , thePrecision ) ) >= 60 * pow ( 10 , thePrecision ) )
266+ {
267+ myFloatMinutesY = qMax ( myFloatMinutesY - 60 , 0.0 );
268+ myDegreesY++;
269+ }
270+
271+ QString myXHemisphere;
272+ QString myYHemisphere;
273+ QString myXSign;
274+ QString myYSign;
275+ if ( useSuffix )
276+ {
277+ myXHemisphere = myWrappedX < 0 ? QObject::tr ( " W" ) : QObject::tr ( " E" );
278+ myYHemisphere = m_y < 0 ? QObject::tr ( " S" ) : QObject::tr ( " N" );
279+ }
280+ else
281+ {
282+ if ( myWrappedX < 0 )
283+ {
284+ myXSign = QObject::tr ( " -" );
285+ }
286+ if ( m_y < 0 )
287+ {
288+ myYSign = QObject::tr ( " -" );
289+ }
290+ }
291+ // check if coordinate is all zeros for the specified precision, and if so,
292+ // remove the sign and hemisphere strings
293+ if ( myDegreesX == 0 && qRound ( myFloatMinutesX * pow ( 10 , thePrecision ) ) == 0 )
294+ {
295+ myXSign = QString ();
296+ myXHemisphere = QString ();
297+ }
298+ if ( myDegreesY == 0 && qRound ( myFloatMinutesY * pow ( 10 , thePrecision ) ) == 0 )
299+ {
300+ myYSign = QString ();
301+ myYHemisphere = QString ();
302+ }
303+ // also remove directional prefix from 180 degree longitudes
304+ if ( myDegreesX == 180 && qRound ( myFloatMinutesX * pow ( 10 , thePrecision ) ) == 0 )
305+ {
306+ myXHemisphere = QString ();
307+ }
308+
309+ // pad minutes with leading digits if required
310+ int digits = 2 + ( thePrecision == 0 ? 0 : 1 + thePrecision ); // 1 for decimal place if required
311+ QString myStrMinutesX = padded ? QString ( " %1" ).arg ( myFloatMinutesX, digits, ' f' , thePrecision, QChar ( ' 0' ) ) : QString::number ( myFloatMinutesX, ' f' , thePrecision );
312+ QString myStrMinutesY = padded ? QString ( " %1" ).arg ( myFloatMinutesY, digits, ' f' , thePrecision, QChar ( ' 0' ) ) : QString::number ( myFloatMinutesY, ' f' , thePrecision );
169313
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 ( " '" ) +
314+ QString rep = myXSign + QString::number ( myDegreesX ) + QChar ( 176 ) +
315+ myStrMinutesX + QString ( " '" ) +
174316 myXHemisphere + QString ( " ," ) +
175- QString::number ( myDegreesY ) + QChar ( 176 ) +
176- QString::number ( myFloatMinutesY, ' f ' , thePrecision ) + QString ( " '" ) +
317+ myYSign + QString::number ( myDegreesY ) + QChar ( 176 ) +
318+ myStrMinutesY + QString ( " '" ) +
177319 myYHemisphere;
178320 return rep;
179321}
0 commit comments