11package VWF::Utils ;
22
33# VWF is licensed under GPL2.0 for personal use only
4- # njh@bandsman.co.uk
4+ # njh@nigelhorne.com
55
66=head1 NAME
77
@@ -90,58 +90,6 @@ sub create_memory_cache {
9090 return _create_cache(' memory_cache' , $args );
9191}
9292
93- =head2 distance
94-
95- Calculate the great circle distance between two points on Earth using the Haversine formula.
96- More accurate than the original implementation, especially for short distances.
97-
98- Parameters:
99- - lat1, lon1: Latitude and longitude of first point (decimal degrees)
100- - lat2, lon2: Latitude and longitude of second point (decimal degrees)
101- - unit: 'K' for kilometers, 'N' for nautical miles, 'M' or undef for statute miles
102-
103- Returns: Distance in specified units
104-
105- Throws: Error on invalid input parameters
106-
107- =cut
108-
109- sub distance ($lat1 , $lon1 , $lat2 , $lon2 , $unit = ' M' ) {
110- # Input validation
111- for my $coord_ref ([\$lat1 , ' lat1' ], [\$lon1 , ' lon1' ], [\$lat2 , ' lat2' ], [\$lon2 , ' lon2' ]) {
112- my ($coord , $name ) = @$coord_ref ;
113- croak " $name must be defined" unless defined $$coord ;
114- croak " $name must be numeric" unless looks_like_number($$coord );
115- }
116-
117- # Range validation
118- croak " Latitude must be between -90 and 90 degrees"
119- if abs($lat1 ) > 90 || abs($lat2 ) > 90;
120- croak " Longitude must be between -180 and 180 degrees"
121- if abs($lon1 ) > 180 || abs($lon2 ) > 180;
122-
123- # Handle identical points
124- return 0 if $lat1 == $lat2 && $lon1 == $lon2 ;
125-
126- # Validate unit
127- $unit = uc ($unit || ' M' );
128- croak " Unknown unit '$unit '. Use 'K', 'N', or 'M'"
129- unless $unit =~ / ^[KNM]$ / ;
130-
131- # Use optimized calculation with appropriate radius
132- my $radius = $unit eq ' K' ? EARTH_RADIUS_KM :
133- $unit eq ' N' ? EARTH_RADIUS_NM :
134- EARTH_RADIUS_MILES;
135-
136- # Haversine formula
137- my $dlat = deg2rad($lat2 - $lat1 );
138- my $dlon = deg2rad($lon2 - $lon1 );
139- my $a = sin ($dlat /2)**2 + cos (deg2rad($lat1 )) * cos (deg2rad($lat2 )) * sin ($dlon /2)**2;
140- my $c = 2 * asin(sqrt ($a ));
141-
142- return $radius * $c ;
143- }
144-
14593# Private helper functions
14694
14795sub _create_cache ($cache_type , $args ) {
@@ -383,13 +331,65 @@ sub _parse_server_config($config, $logger) {
383331 return @servers ;
384332}
385333
334+ =head2 distance
335+
336+ Calculate the great circle distance between two points on Earth using the Haversine formula.
337+ More accurate than the original implementation, especially for short distances.
338+
339+ Parameters:
340+ - lat1, lon1: Latitude and longitude of first point (decimal degrees)
341+ - lat2, lon2: Latitude and longitude of second point (decimal degrees)
342+ - unit: 'K' for kilometers, 'N' for nautical miles, 'M' or undef for statute miles
343+
344+ Returns: Distance in specified units
345+
346+ Throws: Error on invalid input parameters
347+
348+ =cut
349+
350+ sub distance ($lat1 , $lon1 , $lat2 , $lon2 , $unit = ' M' ) {
351+ # Input validation
352+ for my $coord_ref ([\$lat1 , ' lat1' ], [\$lon1 , ' lon1' ], [\$lat2 , ' lat2' ], [\$lon2 , ' lon2' ]) {
353+ my ($coord , $name ) = @$coord_ref ;
354+ croak " $name must be defined" unless defined $$coord ;
355+ croak " $name must be numeric" unless looks_like_number($$coord );
356+ }
357+
358+ # Range validation
359+ croak " Latitude must be between -90 and 90 degrees"
360+ if abs($lat1 ) > 90 || abs($lat2 ) > 90;
361+ croak " Longitude must be between -180 and 180 degrees"
362+ if abs($lon1 ) > 180 || abs($lon2 ) > 180;
363+
364+ # Handle identical points
365+ return 0 if $lat1 == $lat2 && $lon1 == $lon2 ;
366+
367+ # Validate unit
368+ $unit = uc ($unit || ' M' );
369+ croak " Unknown unit '$unit '. Use 'K', 'N', or 'M'"
370+ unless $unit =~ / ^[KNM]$ / ;
371+
372+ # Use optimized calculation with appropriate radius
373+ my $radius = $unit eq ' K' ? EARTH_RADIUS_KM :
374+ $unit eq ' N' ? EARTH_RADIUS_NM :
375+ EARTH_RADIUS_MILES;
376+
377+ # Haversine formula
378+ my $dlat = deg2rad($lat2 - $lat1 );
379+ my $dlon = deg2rad($lon2 - $lon1 );
380+ my $a = sin ($dlat /2)**2 + cos (deg2rad($lat1 )) * cos (deg2rad($lat2 )) * sin ($dlon /2)**2;
381+ my $c = 2 * asin(sqrt ($a ));
382+
383+ return $radius * $c ;
384+ }
385+
3863861;
387387
388388__END__
389389
390390=head1 AUTHOR
391391
392- Nigel Horne, C<< <njh at bandsman.co.uk > >>
392+ Nigel Horne, C<< <njh at nigelhorne.com > >>
393393
394394=head1 BUGS
395395
@@ -410,4 +410,4 @@ Commercial users must apply in writing for a licence.
410410
411411L<CHI> , L<Math::Trig> , L<DBI>
412412
413- =cut
413+ =cut
0 commit comments