1package Math::Calc::Units::Convert::Distance; 2use base 'Math::Calc::Units::Convert::Metric'; 3use strict; 4 5my %total_unit_map; 6 7my %ranges = ( default => [ 1, 999 ] ); 8 9my %distance_units = ( inch => [ 2.54, 'centimeter' ], 10 foot => [ 12, 'inch' ], 11 yard => [ 3, 'foot' ], 12 mile => [ 5280, 'foot' ], 13); 14 15my %distance_pref = ( meter => 1.1, 16 inch => 0.7, 17 foot => 0.9, 18 yard => 0, 19 mile => 1.0, 20); 21 22my %aliases = ( 'feet' => 'foot', 23 ); 24 25# Perform all math in terms of meters 26sub canonical_unit { return 'meter'; } 27 28# Metric.pm uses this to construct unit names 29sub abbreviated_canonical_unit { return 'm'; } 30 31# Preference for this class's canonical unit to be the "major" unit 32# used. The major unit is the one that determines the range of values 33# to use for computing the overall preference. For example, if you 34# have 240000 meters/day, you would want to pick "240km/hour", which 35# is based on the number "240" being a decent one to use for meters. 36# If you had instead chosen 'hour' as the major unit, then you 37# wouldn't like using 240 because 240 hours should really be described 38# as 10 days. 39# 40# Note that the above example is not realistic, because the only units 41# that are eligible for being chosen as the major unit are the ones in 42# the numerator. So major_pref() is really only used for something 43# like "square meter seconds", where you want to choose between 44# "meter" and "second". 45sub major_pref { return 1; } 46 47sub major_variants { 48 my ($self) = @_; 49 return $self->variants('meter'); 50} 51 52sub get_ranges { 53 return \%ranges; 54} 55 56# Return the relative preference of different units. Meters are 57# preferred over miles, miles over feet. 58sub get_prefs { 59 return \%distance_pref; 60} 61 62sub singular { 63 my ($self, $unit) = @_; 64 $unit = $self->SUPER::singular($unit); 65 return $aliases{$unit} || $unit; 66} 67 68sub unit_map { 69 my ($self) = @_; 70 if (keys %total_unit_map == 0) { 71 %total_unit_map = (%{$self->SUPER::unit_map()}, %distance_units); 72 } 73 return \%total_unit_map; 74} 75 76# simple_convert : unitName x unitName -> multiplier 77# 78sub simple_convert { 79 my ($self, $from, $to) = @_; 80 81 # 'm', 'meter', or 'meters' 82 return 1 if $from =~ /^m(eter(s?))?$/i; 83 84 if (my $easy = $self->SUPER::simple_convert($from, $to)) { 85 return $easy; 86 } 87 88 # km == kilometer 89 if ($from =~ /^(.)m(eter(s?))?$/i) { 90 if (my ($prefix) = $self->expand($1)) { 91 return $self->simple_convert($prefix . "meter", $to); 92 } 93 } 94 95 return; # Failed 96} 97 98# Override Metric::variants because only meters should be given metric 99# prefixes, not inches, feet, etc. 100sub variants { 101 my ($self, $base) = @_; 102 my $canon = $self->canonical_unit(); 103 return ($base, 104 keys %{ $self->unit_map() }, 105 map { "$_$canon" } $self->get_prefixes()); 106} 107 1081; 109