Rand Stats



Actions Status


Geo::Coordinates::UTM - Perl extension for Latitude Longitude conversions.


use Geo::Coordinates; use Geo::Coordinates::UTM;

my ($zone,$easting,$northing)= |latlon-to-utm($ellipsoid,$latitude,$longitude);

my $utmpoint = latlon-to-utm($ellipsoid, $latitude, $longitude);

my $point = Point.new(x => 141.5, y => -23.78);

$utmpoint = latlon-to-utm($ellipsoid, $point); # returns PointUTM

my $polygon = Polygon.new(...);

my $polygon-utm = latlon-to-utm($ellipsoid, $polygon); # returns PolygonUTM

$point = utm-to-latlon($ellipsoid, $zone, $easting, $northing); # returns PointLatLon

$point = utm-to-latlon($ellipsoid, $zone, $easting, $northing).Point; # coerce to Point

my ($latitude,$longitude)= |utm-to-latlon($ellipsoid,$zone,$easting,$northing);

my ($latitude,$longitude)= |utm-to-latlon($ellipsoid, $utmpoint);

my ($zone,$easting,$northing)= |mgrs-to-utm($mgrs);

my ($latitude,$longitude)= |mgrs-to-latlon($ellipsoid,$mgrs);

my ($mgrs)= |utm-to-mgrs($zone,$easting,$northing);

my ($mgrs)= |latlon-to-mgrs($ellipsoid,$latitude,$longitude);


This module will translate latitude longitude coordinates to Universal Transverse Mercator(UTM) coordinates and vice versa.

Mercator Projection

The Mercator projection was first invented to help mariners. They needed to be able to draw a straight line on a map and follow that bearing to arrive at a destination. In order to do this, Mercator invented a projection which preserved angle, by projecting the earth's surface onto a cylinder, sharing the same axis as the earth itself. This caused all Latitude and Longitude lines to be straight and to intersect at a 90° angle, but the downside was that the scale of the map increased as you moved away from the equator so that the lines of longitude were parallel.

Because the scale varies, areas near the poles appear much larger on the map than a similar sized object near the equator. The Mercator Projection is useless near the poles since the scale becomes infinite.

Transverse Mercator Projection

A Transverse Mercator projection takes the cylinder and turns it on its side. Now the cylinder's axis passes through the equator, and it can be rotated to line up with the area of interest. Many countries use Transverse Mercator for their grid systems. The disadvantage is that now neither the lines of latitude or longitude (apart from the central meridian) are straight.

Universal Transverse Mercator

The Universal Transverse Mercator(UTM) system sets up a universal world wide system for mapping. The Transverse Mercator projection is used, with the cylinder in 60 positions. This creates 60 zones around the world. Positions are measured using Eastings and Northings, measured in meters, instead of Latitude and Longitude. Eastings start at 500,000 on the centre line of each zone. In the Northern Hemisphere, Northings are zero at the equator and increase northward. In the Southern Hemisphere, Northings start at 10 million at the equator, and decrease southward. You must know which hemisphere and zone you are in to interpret your location globally. Distortion of scale, distance and area increase away from the central meridian.

UTM projection is used to define horizontal positions world-wide by dividing the surface of the Earth into 6° zones, each mapped by the Transverse Mercator projection with a central meridian in the center of the zone. UTM zone numbers designate 6° longitudinal strips extending from 80° South latitude to 84° North latitude. UTM zone characters designate 8° zones extending north and south from the equator. Eastings are measured from the central meridian (with a 500 km false easting to insure positive coordinates). Northings are measured from the equator (with a 10,000 km false northing for positions south of the equator).

UTM is applied separately to the Northern and Southern Hemisphere, thus within a single UTM zone, a single X / Y pair of values will occur in both the Northern and Southern Hemisphere. To eliminate this confusion, and to speed location of points, a UTM zone is sometimes subdivided into 20 zones of Latitude. These grids can be further subdivided into 100,000 meter grid squares with double-letter designations. This subdivision by Latitude and further division into grid squares is generally referred to as the Military Grid Reference System (MGRS). The unit of measurement of UTM is always meters and the zones are numbered from 1 to 60 eastward, beginning at the 180th meridian. The scale distortion in a north-south direction parallel to the central meridian (CM) is constant However, the scale distortion increases either direction away from the CM. To equalize the distortion of the map across the UTM zone, a scale factor of 0.9996 is applied to all distance measurements within the zone. The distortion at the zone boundary, 3°s away from the CM is approximately 1%.


Ellipsoids are imported from Geo::Ellipsoids.


latlon-to-utm is the main routine for converting latitude and longitude to UTΜcoordinates. It has various incantations depending on the form of the input, but the UTM coordinates are always expressed as a PointUTM object, or a collection of PointUTM objects (LineStringUTM or PolygonUTM).

A PointUTM has three accessor methods: zone, easting, and northing. In addition, and mainly for backwards compatibility with older versions of this module, a method List is provided so that the return value of the latlon-to-utm method can be used as a list of zone, easting and northing.

latlon-to-utm can be called with explicit values for latitude and longitude:

my $utm = latlon-to-utm($ellipsoid, $latitude, $longitude);

with the position expressed as a Geo::Geometry point type (Point, PointZ, PointM, or PointZM):

my $position = Point.new($longitude, %latitude_;
my $utm = latlon-to-utm($ellipsoid, $position);

with multiple positions expressed as a Geo::Geometry line type (LineString, LineStringZ, LineStringM, or LineStringZM):

my $line = LineString.new(...);
my $utm = latlon-to-utm($ellipsoid, $line);

or with multiple positions expressed as a Geo::Geometry polygon type (Polygon, PolygonZ, PolygonM, or PolygonZM):

my $polygon = Polygon.new(...);
my $utm = latlon-to-utm($ellipsoid, $polygon);

In the latter two cases, each point within the line or polygon will be converted to a PointUTM object, and the returned value will be a LineStringUTM or PolygonUTM object as appropriate.

A LineStringUTM object provides a single accessor method points which returns an array of PointUTM objects. A PolygonUTM object provides a single accessor method rings which returns an array of LinearRingUTM objects representing the polygon's external boundary and any internal holes. A LinearRingUTM object provides a single accessor method points which returns an array of PointUTM objects.

Latitude values in the southern hemisphere should be supplied as negative values (e.g. 30° South will be -30). Similarly Longitude values West of the meridian should also be supplied as negative values. Both latitude and longitude should not be entered as deg,min,sec but as their decimal equivalent, e.g. 30°12'22.432" sec should be entered as 30.2062311

Previous versions of this module allowed the ellipsoid to be expressed as an index into the array of ellipsoids. This usage was marked as deprecated, and is now removed.

For latitude 57°49'59.000" North longitude 02°47'20.226" West

using Clarke 1866 (Ellipsoid 5)

($zone,$east,$north)= |latlon-to-utm('clarke 1866',57.803055556,-2.788951667)


$zone  = "30V"
$east  = 512543.777159849
$north = 6406592.20049111

On occasions, it is necessary to map a pair of (latitude, longitude) coordinates to a predefined zone. This is done by providing a value for the optional named parameter zone as follows:

($zone, $east, $north)= |latlon-to-utm('international', :zone($zone-number),
                                     $latitude, $longitude)

For instance, Spain territory goes over zones 29, 30 and 31 but sometimes it is convenient to use the projection corresponding to zone 30 for all the country.

Santiago de Compostela is at 42°52'57.06" North, 8°32'28.70" West

($zone, $east, $north)= |latlon-to-utm('international',  42.882517, -8.541306)


$zone = "29T"
$east = 537460.331
$north = 4747955.991

but forcing the conversion to zone 30:

($zone, $east, $north)= |latlon-to-utm('international', :zone(30),
                                     42.882517, -8.541306)


$zone = "30T"
$east = 47404.442
$north = 4762771.704

This is also necessary when the eastern boundary of a map lies along a zone boundary. If the zone is not forced for values on that boundary then the returned values will not be useful.


Reversing the above example,

($latitude,$longitude)= |utm-to-latlon(5,'30V',512543.777159849,6406592.20049111)


$latitude  = 57.8030555601332
$longitude = -2.7889516669741

which equates to

latitude  57°49'59.000" North
longitude 02°47'20.226" West

To allow compatibility with previous versions of this module, utm-to-latlon returns an object of type PointLatLon which contains only the two attributes x (the longitude) and y (the latitude). If used as in the above example, the List method will be called which will return a list of the latitude and longitude. There is also a Point method to allow coercion to a more standard type.


latlon-to-mgrs is called in the same way as latlon-to-utm, but instead of a PointUTM object, the returned value will be a string contain the MGRS representation of the location.

For latitude 57°49'59.000" North longitude 02°47'20.226" West

using WGS84 (Ellipsoid 23)

$mgrs = latlon-to-mgrs('WGS-84', 57.8030590197684, -2.788956799)


$mgrs  = 30VWK1254306804

Currently only the version explicitly specifying longitude and latitude is implemented; Other versions will follow.

Note that previous versions of this module returned a list containing a single value. This is no longer the case and might cause problems in some circumstances.


Reversing the above example,



$latitude  = 57.8030590197684
$longitude = -2.788956799645

Like utm-to-latlon, the returned object is PointLatLon.


Similarly it is possible to convert MGRS directly to UTM



    $zone = 30V
    $easting = 512543
    $northing = 6406804


and the inverse converting from UTM to MGRS is done as follows


returns $mgrs = 30VWK1254306804


Kevin Pye, kjpye@cpan.org

Graham Crookham, grahamc@cpan.org


Thanks go to the following:

Felipe Mendonca Pimenta for helping out with the Southern hemisphere testing.

Michael Slater for discovering the Escape \Q bug.

Mark Overmeer for the ellipsoid-info routines and code review.

Lok Yan for the >72deg. N bug.

Salvador Fandino for the forced zone UTM and additional tests

Matthias Lendholt for modifications to MGRS calculations

Peder Stray for the short MGRS patch


Copyright (c) 2000,2002,2004,2007,2010,2013 by Graham Crookham. All rights reserved.

copyright (c) 2018, 2022 by Kevin Pye.

This package is free software; you can redistribute it and/or modify it under the same terms as Raku itself.