Skip to content

Commit b439fe3

Browse files
PeterQFRPeter Milani
and
Peter Milani
authored
Added an option to force zones on conversionfrom WGS84 to utm. This will allow for smoother transitions across zonal boundaries (#43)
Co-authored-by: Peter Milani <[email protected]>
1 parent ccd1ace commit b439fe3

File tree

3 files changed

+58
-20
lines changed

3 files changed

+58
-20
lines changed

geodesy/include/geodesy/utm.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ class UTMPoint
100100
zone(that.zone),
101101
band(that.band)
102102
{}
103-
104103
UTMPoint(const geographic_msgs::msg::GeoPoint &pt);
105104

106105
/** Create a flattened 2-D grid point. */
@@ -124,7 +123,7 @@ class UTMPoint
124123

125124
// data members
126125
double easting; ///< easting within grid zone [meters]
127-
double northing; ///< northing within grid zone [meters]
126+
double northing; ///< northing within grid zone [meters]
128127
double altitude; ///< altitude above ellipsoid [meters] or NaN
129128
uint8_t zone; ///< UTM longitude zone number
130129
char band; ///< MGRS latitude band letter
@@ -147,7 +146,7 @@ class UTMPose
147146
position(that.position),
148147
orientation(that.orientation)
149148
{}
150-
149+
151150
/** Create from a WGS 84 geodetic pose. */
152151
UTMPose(const geographic_msgs::msg::GeoPose &pose):
153152
position(pose.position),
@@ -175,8 +174,10 @@ class UTMPose
175174
}; // class UTMPose
176175

177176
// conversion function prototypes
178-
void fromMsg(const geographic_msgs::msg::GeoPoint &from, UTMPoint &to);
179-
void fromMsg(const geographic_msgs::msg::GeoPose &from, UTMPose &to);
177+
void fromMsg(const geographic_msgs::msg::GeoPoint &from, UTMPoint &to,
178+
const bool& force_zone=false, const char& band='A', const uint8_t& zone=0 );
179+
void fromMsg(const geographic_msgs::msg::GeoPose &from, UTMPose &to,
180+
const bool& force_zone=false, const char& band='A', const uint8_t& zone=0 );
180181
geographic_msgs::msg::GeoPoint toMsg(const UTMPoint &from);
181182
geographic_msgs::msg::GeoPose toMsg(const UTMPose &from);
182183

geodesy/src/conv/utm_conversions.cpp

+26-15
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
#include <geodesy/utm.h>
4040

4141
/** @file
42-
42+
4343
@brief Universal Transverse Mercator transforms.
4444
4545
Functions to convert WGS 84 (ellipsoidal) latitude and longitude
@@ -145,7 +145,7 @@ geographic_msgs::msg::GeoPoint toMsg(const UTMPoint &from)
145145
mu = M/(a*(1-eccSquared/4-3*eccSquared*eccSquared/64
146146
-5*eccSquared*eccSquared*eccSquared/256));
147147

148-
phi1Rad = mu + ((3*e1/2-27*e1*e1*e1/32)*sin(2*mu)
148+
phi1Rad = mu + ((3*e1/2-27*e1*e1*e1/32)*sin(2*mu)
149149
+ (21*e1*e1/16-55*e1*e1*e1*e1/32)*sin(4*mu)
150150
+ (151*e1*e1*e1/96)*sin(6*mu));
151151

@@ -183,7 +183,8 @@ geographic_msgs::msg::GeoPoint toMsg(const UTMPoint &from)
183183
* @param from WGS 84 point message.
184184
* @param to UTM point.
185185
*/
186-
void fromMsg(const geographic_msgs::msg::GeoPoint &from, UTMPoint &to)
186+
void fromMsg(const geographic_msgs::msg::GeoPoint &from, UTMPoint &to,
187+
const bool& force_zone, const char& band, const uint8_t& zone)
187188
{
188189
double Lat = from.latitude;
189190
double Long = from.longitude;
@@ -195,7 +196,7 @@ void fromMsg(const geographic_msgs::msg::GeoPoint &from, UTMPoint &to)
195196
double LongOrigin;
196197
double eccPrimeSquared;
197198
double N, T, C, A, M;
198-
199+
199200
// Make sure the longitude is between -180.00 .. 179.9
200201
// (JOQ: this is broken for Long < -180, do a real normalize)
201202
double LongTemp = (Long+180)-int((Long+180)/360)*360-180;
@@ -204,25 +205,34 @@ void fromMsg(const geographic_msgs::msg::GeoPoint &from, UTMPoint &to)
204205
double LongOriginRad;
205206

206207
to.altitude = from.altitude;
207-
to.zone = int((LongTemp + 180)/6) + 1;
208-
208+
if (!force_zone)
209+
to.zone = int((LongTemp + 180)/6) + 1;
210+
else
211+
to.zone = zone;
212+
209213
if( Lat >= 56.0 && Lat < 64.0 && LongTemp >= 3.0 && LongTemp < 12.0 )
210214
to.zone = 32;
211215

212216
// Special zones for Svalbard
213-
if( Lat >= 72.0 && Lat < 84.0 )
217+
if( Lat >= 72.0 && Lat < 84.0 )
214218
{
215219
if( LongTemp >= 0.0 && LongTemp < 9.0 ) to.zone = 31;
216220
else if( LongTemp >= 9.0 && LongTemp < 21.0 ) to.zone = 33;
217221
else if( LongTemp >= 21.0 && LongTemp < 33.0 ) to.zone = 35;
218222
else if( LongTemp >= 33.0 && LongTemp < 42.0 ) to.zone = 37;
219223
}
220224
// +3 puts origin in middle of zone
221-
LongOrigin = (to.zone - 1)*6 - 180 + 3;
225+
LongOrigin = (to.zone - 1)*6 - 180 + 3;
222226
LongOriginRad = angles::from_degrees(LongOrigin);
223227

224228
// compute the UTM band from the latitude
225-
to.band = UTMBand(Lat, LongTemp);
229+
if (!force_zone)
230+
to.band = UTMBand(Lat, LongTemp);
231+
else
232+
to.band = band;
233+
234+
235+
226236
#if 0
227237
if (to.band == ' ')
228238
throw std::range_error;
@@ -236,13 +246,13 @@ void fromMsg(const geographic_msgs::msg::GeoPoint &from, UTMPoint &to)
236246
A = cos(LatRad)*(LongRad-LongOriginRad);
237247

238248
M = a*((1 - eccSquared/4 - 3*eccSquared*eccSquared/64
239-
- 5*eccSquared*eccSquared*eccSquared/256) * LatRad
249+
- 5*eccSquared*eccSquared*eccSquared/256) * LatRad
240250
- (3*eccSquared/8 + 3*eccSquared*eccSquared/32
241251
+ 45*eccSquared*eccSquared*eccSquared/1024)*sin(2*LatRad)
242252
+ (15*eccSquared*eccSquared/256
243-
+ 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad)
253+
+ 45*eccSquared*eccSquared*eccSquared/1024)*sin(4*LatRad)
244254
- (35*eccSquared*eccSquared*eccSquared/3072)*sin(6*LatRad));
245-
255+
246256
to.easting = (double)
247257
(k0*N*(A+(1-T+C)*A*A*A/6
248258
+ (5-18*T+T*T+72*C-58*eccPrimeSquared)*A*A*A*A*A/120)
@@ -277,7 +287,7 @@ bool isValid(const UTMPoint &pt)
277287

278288
return true;
279289
}
280-
290+
281291
/** Create UTM point from WGS 84 geodetic point. */
282292
UTMPoint::UTMPoint(const geographic_msgs::msg::GeoPoint &pt)
283293
{
@@ -291,9 +301,10 @@ UTMPoint::UTMPoint(const geographic_msgs::msg::GeoPoint &pt)
291301
*
292302
* @todo define the orientation transformation properly
293303
*/
294-
void fromMsg(const geographic_msgs::msg::GeoPose &from, UTMPose &to)
304+
void fromMsg(const geographic_msgs::msg::GeoPose &from, UTMPose &to,
305+
const bool& force_zone, const char& band, const uint8_t& zone)
295306
{
296-
fromMsg(from.position, to.position);
307+
fromMsg(from.position, to.position, force_zone, band, zone);
297308
to.orientation = from.orientation;
298309
}
299310

geodesy/tests/test_utm.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,32 @@ TEST(OStream, pose)
413413
EXPECT_EQ(out.str(), expected);
414414
}
415415

416+
TEST(ForceUTMZone, point)
417+
{
418+
419+
geographic_msgs::msg::GeoPoint zone2, zone3;
420+
zone2.latitude=24.02;
421+
zone2 = geodesy::toMsg(24.02, 5.999);
422+
zone3 = geodesy::toMsg(24.02, 6.001);
423+
geodesy::UTMPoint pt2, pt3, pt4;
424+
geodesy::fromMsg(zone2, pt2);
425+
geodesy::fromMsg(zone3, pt3);
426+
427+
EXPECT_FALSE(geodesy::sameGridZone(pt2, pt3) );
428+
429+
double diffx = pt2.easting - pt3.easting;
430+
double diffy = pt2.northing - pt3.northing;
431+
double distance = std::sqrt(diffx*diffx + diffy*diffy);
432+
433+
//Now force the pt3 into pt2's grid zone
434+
geodesy::fromMsg(zone3, pt4, true, pt2.band, pt2.zone);
435+
diffx = pt2.easting - pt4.easting;
436+
diffy = pt2.northing - pt4.northing;
437+
double distance2 = std::sqrt(diffx*diffx + diffy*diffy);
438+
ROS_INFO("Prev Distance %f, Actual Distance %f", distance, distance2);
439+
EXPECT_LT(distance2, distance);
440+
}
441+
416442
// Run all the tests that were declared with TEST()
417443
int main(int argc, char **argv)
418444
{

0 commit comments

Comments
 (0)