File Coverage

blib/lib/Math/PlanePath/DiagonalRationals.pm
Criterion Covered Total %
statement 83 101 82.1
branch 12 28 42.8
condition 6 17 35.2
subroutine 22 27 81.4
pod 9 9 100.0
total 132 182 72.5


line stmt bran cond sub pod time code
1             # Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018 Kevin Ryde
2              
3             # This file is part of Math-PlanePath.
4             #
5             # Math-PlanePath is free software; you can redistribute it and/or modify
6             # it under the terms of the GNU General Public License as published by the
7             # Free Software Foundation; either version 3, or (at your option) any later
8             # version.
9             #
10             # Math-PlanePath is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12             # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13             # for more details.
14             #
15             # You should have received a copy of the GNU General Public License along
16             # with Math-PlanePath. If not, see .
17              
18              
19             # Maybe:
20             # including_zero=>1 to have 0/1 for A038567
21              
22              
23             package Math::PlanePath::DiagonalRationals;
24 7     7   1384 use 5.004;
  7         24  
25 7     7   41 use strict;
  7         14  
  7         181  
26 7     7   38 use Carp 'croak';
  7         10  
  7         437  
27             #use List::Util 'max';
28             *max = \&Math::PlanePath::_max;
29              
30 7     7   70 use vars '$VERSION', '@ISA';
  7         17  
  7         433  
31             $VERSION = 127;
32 7     7   804 use Math::PlanePath;
  7         14  
  7         315  
33             @ISA = ('Math::PlanePath');
34             *_rect_for_first_quadrant = \&Math::PlanePath::_rect_for_first_quadrant;
35              
36             use Math::PlanePath::Base::Generic
37 7         343 'is_infinite',
38 7     7   40 'round_nearest';
  7         14  
39              
40 7     7   579 use Math::PlanePath::CoprimeColumns;
  7         16  
  7         362  
41             *_extend = \&Math::PlanePath::CoprimeColumns::_extend;
42             *_coprime = \&Math::PlanePath::CoprimeColumns::_coprime;
43 7     7   94 use vars '@_x_to_n';
  7         14  
  7         583  
44             *_x_to_n = \@Math::PlanePath::CoprimeColumns::_x_to_n;
45              
46             # uncomment this to run the ### lines
47             # use Smart::Comments;
48              
49              
50 7         427 use constant parameter_info_array =>
51             [ { name => 'direction',
52             share_key => 'direction_downup',
53             display => 'Direction',
54             type => 'enum',
55             default => 'down',
56             choices => ['down','up'],
57             choices_display => ['Down','Up'],
58             description => 'Number points downwards or upwards along the diagonals.',
59             },
60             Math::PlanePath::Base::Generic::parameter_info_nstart1(),
61 7     7   52 ];
  7         14  
62              
63 7     7   41 use constant default_n_start => 1;
  7         13  
  7         327  
64 7     7   57 use constant class_x_negative => 0;
  7         24  
  7         349  
65 7     7   44 use constant class_y_negative => 0;
  7         11  
  7         310  
66 7     7   38 use constant n_frac_discontinuity => .5;
  7         14  
  7         362  
67 7     7   46 use constant x_minimum => 1;
  7         12  
  7         344  
68 7     7   41 use constant y_minimum => 1;
  7         14  
  7         320  
69 7     7   39 use constant gcdxy_maximum => 1; # no common factor
  7         15  
  7         934  
70              
71             sub absdx_minimum {
72 0     0 1 0 my ($self) = @_;
73 0 0       0 return ($self->{'direction'} eq 'down' ? 0 : 1);
74             }
75             sub absdy_minimum {
76 0     0 1 0 my ($self) = @_;
77 0 0       0 return ($self->{'direction'} eq 'down' ? 1 : 0);
78             }
79 7     7   48 use constant dsumxy_minimum => 0;
  7         14  
  7         330  
80 7     7   38 use constant dsumxy_maximum => 1; # to next diagonal stripe
  7         22  
  7         4511  
81              
82             sub dir_minimum_dxdy {
83 0     0 1 0 my ($self) = @_;
84 0 0       0 return ($self->{'direction'} eq 'down'
85             ? (0,1) # North
86             : (1,0)); # East
87             }
88             sub dir_maximum_dxdy {
89 0     0 1 0 my ($self) = @_;
90 0 0       0 return ($self->{'direction'} eq 'down'
91             ? (1,-1) # South-East
92             : (2,-1)); # ESE at N=3 down to X axis
93             }
94              
95             #------------------------------------------------------------------------------
96              
97             sub new {
98 2     2 1 67 my $self = shift->SUPER::new (@_);
99              
100 2 100       13 if (! defined $self->{'n_start'}) {
101 1         12 $self->{'n_start'} = $self->default_n_start;
102             }
103 2   50     13 my $direction = ($self->{'direction'} ||= 'down');
104 2 50 33     9 if (! ($direction eq 'up' || $direction eq 'down')) {
105 0         0 croak "Unrecognised direction option: ", $direction;
106             }
107              
108 2         6 return $self;
109             }
110              
111             sub n_to_xy {
112 21     21 1 2391 my ($self, $n) = @_;
113             ### DiagonalRationals n_to_xy(): $n
114              
115 21 50       76 if (2*($n - $self->{'n_start'}) < -1) {
116             ### before n_start ...
117 0         0 return;
118             }
119 21 50       69 my ($x,$y) = $self->Math::PlanePath::CoprimeColumns::n_to_xy($n+1)
120             or return;
121             ### CoprimeColumns returned: "x=$x y=$y"
122              
123 21         36 $x -= $y;
124             ### shear to: "x=$x y=$y"
125              
126 21         42 return ($x,$y);
127             }
128              
129             # Note: shared by FactorRationals
130             sub xy_is_visited {
131 0     0 1 0 my ($self, $x, $y) = @_;
132 0         0 $x = round_nearest ($x);
133 0         0 $y = round_nearest ($y);
134 0 0 0     0 if ($x < 1
      0        
135             || $y < 1
136             || ! _coprime($x,$y)) {
137 0         0 return 0;
138             }
139 0         0 return 1;
140             }
141              
142             sub xy_to_n {
143 5646     5646 1 54765 my ($self, $x, $y) = @_;
144             ### DiagonalRationals xy_to_n(): "$x,$y"
145              
146 5646         11723 my $n = Math::PlanePath::CoprimeColumns::xy_to_n($self,$x+$y,$y);
147              
148             # not the N=0 at Xcol=1,Ycol=1 which is Xdiag=1,Ydiag=0
149 5646 100 100     15015 if (defined $n && $n > $self->{'n_start'}) {
150 2028         4675 return $n-1;
151             } else {
152 3618         6449 return undef;
153             }
154             }
155              
156             # not exact
157             sub rect_to_n_range {
158 23     23 1 4284 my ($self, $x1,$y1, $x2,$y2) = @_;
159             ### DiagonalRationals rect_to_n_range(): "$x1,$y1 $x2,$y2"
160              
161 23         56 $x1 = round_nearest($x1);
162 23         57 $y1 = round_nearest($y1);
163 23         45 $x2 = round_nearest($x2);
164 23         46 $y2 = round_nearest($y2);
165 23 100       49 ($x1,$x2) = ($x2,$x1) if $x1 > $x2;
166 23 50       50 ($y1,$y2) = ($y2,$y1) if $y1 > $y2;
167              
168 23 50 33     81 if ($x2 < 1 || $y2 < 1) {
169             ### outside quadrant ...
170 0         0 return (1, 0);
171             }
172              
173             ### rect: "$x1,$y1 $x2,$y2"
174              
175 23         38 my $d2 = $x2 + $y2 + 1;
176 23 50       48 if (is_infinite($d2)) {
177 0         0 return (1, $d2);
178             }
179 23         63 while ($#_x_to_n < $d2) {
180 192         405 _extend();
181             }
182 23         68 my $d1 = max (2, $x1 + $y1);
183             ### $d1
184             ### $d2
185              
186             return ($_x_to_n[$d1] - 1 + $self->{'n_start'},
187 23         76 $_x_to_n[$d2] + $self->{'n_start'});
188             }
189              
190             1;
191             __END__