1package Geo::Coordinates::Converter::Format::Dms; 2use strict; 3use warnings; 4use parent 'Geo::Coordinates::Converter::Format'; 5 6use POSIX; 7 8our $DIGITS = 3; 9 10sub name { 'dms' } 11 12sub detect { 13 my($self, $point) = @_; 14 15 return unless defined $point->lat && $point->lat =~ /^[\-\+NS]?[0-9]{1,2}\.[0-9][0-9]?\.[0-9][0-9]?(?:\.[0-9]+)$/i; 16 return unless defined $point->lng && $point->lng =~ /^[\-\+EW]?[0-9]{1,3}\.[0-9][0-9]?\.[0-9][0-9]?(?:\.[0-9]+)$/i; 17 18 return $self->name; 19} 20 21sub to { 22 my($self, $point) = @_; 23 24 for my $meth (qw/ lat lng /) { 25 my($ws, $deg, $min, $sec) = $point->$meth =~ /^(\-?)([0-9]+)\.([0-9]+)\.([0-9]+(?:\.[0-9]+)?)$/i; 26 my $ret = $deg + ($min / 60) + ($sec / 3600); 27 $ret = $ws =~ /\-/i ? -1 * $ret : $ret; 28 $point->$meth($ret); 29 } 30 31 $point; 32} 33 34sub from { 35 my($self, $point) = @_; 36 37 for my $meth (qw/ lat lng /) { 38 my($ws, $degree) = $point->$meth =~ /^(\-?)(.+)$/; 39 40 my $deg = floor($degree); 41 my $min = floor(($degree - $deg) * 60 % 60); 42 my $sec = ($degree - $deg) * 3600 - $min * 60; 43 $point->$meth(sprintf "%s%s.%s.%s", $ws || '', $deg, $min, $sec); 44 } 45 46 $point; 47} 48 49sub round { 50 my($self, $val) = @_; 51 sprintf "%s%s.%02d.%06.${DIGITS}f", ($val =~ /^(\-?)([^\.]+)\.([^\.]+)\.(.+)$/); 52} 53 541; 55