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