14
The user can enter GPS coordinates in two ways, Decimal Degrees or Degrees, Minutes, Seconds:
┌─────────────────────────────────┬─────────────────────┐
│ DMS (Degrees, Minutes, Seconds) │ DD (Decimal Degree) │
┌───────────┼─────────────────────────────────┼─────────────────────┤
│ Latitude │ N 40° 11′ 48.055″ │ 40.196682 │
├───────────┼─────────────────────────────────┼─────────────────────┤
│ Longitude │ W 8° 25′ 52.134″ │ -8.431149 │
└───────────┴─────────────────────────────────┴─────────────────────┘
These values have to be processed so that they remain in a single format for conversion between them, as well as for storage in the database.
The problem is in the DMS format, where the coordinates entered can vary from several digits, different references for the hemisphere to the characters that identify the separation between the values.
To facilitate the introduction of the coordinates, it is divided into two fields, Latitude and Longitude, and the introduction of spaces has been blocked, which gives us:
┌─────────────────────────────────┬─────────────────────┐
│ DMS (Degrees, Minutes, Seconds) │ DD (Decimal Degree) │
┌───────────┼─────────────────────────────────┼─────────────────────┤
│ Latitude │ N40°11′48.055″ │ 40.196682 │
├───────────┼─────────────────────────────────┼─────────────────────┤
│ Longitude │ W8°25′52.134″ │ -8.431149 │
└───────────┴─────────────────────────────────┴─────────────────────┘
In operation
I’m trying to extract the value in degrees, minutes and seconds for a matrix so that I can convert it to decimal format, but I’m finding the whole process a little too extensive and prone to failure:
Code
Assuming that the variable $entity_gps
contains N40°11'43.44" W8°25'1.31"
:
Note: The values, although entered separately, are stored in a database in a single field separated by a space.
$coordinatesArr = array(
"lat" => array(
"hem" => '',
"deg" => '',
"min" => '',
"sec" => ''
),
"lng" => array(
"hem" => '',
"deg" => '',
"min" => '',
"sec" => ''
)
);
if ($entity_gps!='') {
$gpsArr = explode(' ', $entity_geo->gps);
if (is_array($gpsArr)) {
$i = 0;
foreach ($gpsArr as $str) {
// Extract hemisphere
$hemisphere = mb_substr($str, 0, 1, 'UTF-8');
// Validate hemisphere
if (ctype_alpha($hemisphere)) {
/* Store hemisphere
*/
if ($i==0) {
$coordinatesArr["lat"]["hem"] = $hemisphere;
} else {
$coordinatesArr["lng"]["hem"] = $hemisphere;
}
// Extract degrees
$degree = mb_substr($str, 1, mb_strpos($str, '°')-1, 'UTF-8');
// Validate degrees
if (ctype_digit($degree)) {
/* Store degrees
*/
if ($i==0) {
$coordinatesArr["lat"]["deg"] = $degree;
} else {
$coordinatesArr["lng"]["deg"] = $degree;
}
// Extract minutes
$iniPos = mb_strpos($str, '°')+1;
$minutes = mb_substr($str, $iniPos, mb_strpos($str, "'")-$iniPos, 'UTF-8');
// Validate minutes
if (ctype_digit($minutes)) {
/* Store minutes
*/
if ($i==0) {
$coordinatesArr["lat"]["min"] = $minutes;
} else {
$coordinatesArr["lng"]["min"] = $minutes;
}
// Extract seconds
$iniPos = mb_strpos($str, "'")+1;
$seconds = mb_substr($str, $iniPos, mb_strpos($str, '"')-$iniPos, 'UTF-8');
// Validate seconds
if ($seconds!='') {
/* Store seconds
*/
if ($i==0) {
$coordinatesArr["lat"]["sec"] = $seconds;
} else {
$coordinatesArr["lng"]["sec"] = $seconds;
}
} else {
echo 'Erro ao identificar os segundos!';
}
} else {
echo 'Erro ao identificar os minutos!';
}
} else {
echo 'Erro ao identificar os graus!';
}
} else {
echo "Erro ao identificar o hemisfério!";
}
$i++;
}
}
}
Upshot:
Result when performing a var_dump()
to the matrix $coordinatesArr
, it contains the values as expected:
array(2) {
["lat"]=>
array(4) {
["hem"]=>
string(1) "N"
["deg"]=>
string(2) "40"
["min"]=>
string(2) "11"
["sec"]=>
string(5) "43.44"
}
["lng"]=>
array(4) {
["hem"]=>
string(1) "W"
["deg"]=>
string(1) "8"
["min"]=>
string(2) "25"
["sec"]=>
string(4) "1.31"
}
}
Problem
In addition to the code density, which can be passed to individual functions, there is a whole series of problems caused mainly by user-introduced separators.
Similarly, this check is to be reused when we are processing GPS coordinates in DMS format that are sourced from other sources.
- Instead of
°
another is present. - Instead of
'
is present´
or another. - Instead of
"
is present¨
or another.
Question
How can I simplify and improve the result of this code in order to convert GPS coordinates into DMS format into a matrix?
@Zuul I complemented the answer with additional explanations and another example of regular expression.
– utluiz
Rs a long time ago, but this expression vc copied from PHP code if used in javascript for example will be understood as the character ''
([NSWE])(\\d{1,2})[^\\d](\\d{1,2})[^\\d]([\\d\\.]{1,10})[^\\d\\s]
for([NSWE])(\d{1,2})[^\d](\d{1,2})[^\d]([\d\.]{1,10})[^\d\s]
:)– Leandro Amorim
@Leandroamorim That’s right. Duplicate bars are necessary to give escape in the PHP String. If you are going to use it in some other way, you have to adapt it to the context, considering if you need escape and something changes in the engine of regular expressions. For example, not all implementations support character limiters such as
{1,10}
.– utluiz