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, 2019 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   1374 use 5.004;
  7         27  
25 7     7   41 use strict;
  7         13  
  7         178  
26 7     7   47 use Carp 'croak';
  7         15  
  7         423  
27             #use List::Util 'max';
28             *max = \&Math::PlanePath::_max;
29              
30 7     7   44 use vars '$VERSION', '@ISA';
  7         20  
  7         460  
31             $VERSION = 128;
32 7     7   779 use Math::PlanePath;
  7         23  
  7         357  
33             @ISA = ('Math::PlanePath');
34             *_rect_for_first_quadrant = \&Math::PlanePath::_rect_for_first_quadrant;
35              
36             use Math::PlanePath::Base::Generic
37 7         322 'is_infinite',
38 7     7   51 'round_nearest';
  7         13  
39              
40 7     7   563 use Math::PlanePath::CoprimeColumns;
  7         15  
  7         402  
41             *_extend = \&Math::PlanePath::CoprimeColumns::_extend;
42             *_coprime = \&Math::PlanePath::CoprimeColumns::_coprime;
43 7     7   55 use vars '@_x_to_n';
  7         13  
  7         663  
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         451 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   50 ];
  7         18  
62              
63 7     7   56 use constant default_n_start => 1;
  7         16  
  7         334  
64 7     7   43 use constant class_x_negative => 0;
  7         13  
  7         318  
65 7     7   42 use constant class_y_negative => 0;
  7         13  
  7         341  
66 7     7   45 use constant n_frac_discontinuity => .5;
  7         18  
  7         405  
67 7     7   41 use constant x_minimum => 1;
  7         13  
  7         356  
68 7     7   42 use constant y_minimum => 1;
  7         18  
  7         333  
69 7     7   44 use constant gcdxy_maximum => 1; # no common factor
  7         37  
  7         993  
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   57 use constant dsumxy_minimum => 0;
  7         21  
  7         380  
80 7     7   46 use constant dsumxy_maximum => 1; # to next diagonal stripe
  7         15  
  7         4686  
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 63 my $self = shift->SUPER::new (@_);
99              
100 2 100       13 if (! defined $self->{'n_start'}) {
101 1         10 $self->{'n_start'} = $self->default_n_start;
102             }
103 2   50     12 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         5 return $self;
109             }
110              
111             sub n_to_xy {
112 21     21 1 2322 my ($self, $n) = @_;
113             ### DiagonalRationals n_to_xy(): $n
114              
115 21 50       67 if (2*($n - $self->{'n_start'}) < -1) {
116             ### before n_start ...
117 0         0 return;
118             }
119 21 50       67 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         34 $x -= $y;
124             ### shear to: "x=$x y=$y"
125              
126 21         45 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 54803 my ($self, $x, $y) = @_;
144             ### DiagonalRationals xy_to_n(): "$x,$y"
145              
146 5646         11458 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     15241 if (defined $n && $n > $self->{'n_start'}) {
150 2028         4371 return $n-1;
151             } else {
152 3618         6375 return undef;
153             }
154             }
155              
156             # not exact
157             sub rect_to_n_range {
158 23     23 1 4113 my ($self, $x1,$y1, $x2,$y2) = @_;
159             ### DiagonalRationals rect_to_n_range(): "$x1,$y1 $x2,$y2"
160              
161 23         62 $x1 = round_nearest($x1);
162 23         48 $y1 = round_nearest($y1);
163 23         40 $x2 = round_nearest($x2);
164 23         44 $y2 = round_nearest($y2);
165 23 100       47 ($x1,$x2) = ($x2,$x1) if $x1 > $x2;
166 23 50       44 ($y1,$y2) = ($y2,$y1) if $y1 > $y2;
167              
168 23 50 33     79 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         42 my $d2 = $x2 + $y2 + 1;
176 23 50       50 if (is_infinite($d2)) {
177 0         0 return (1, $d2);
178             }
179 23         62 while ($#_x_to_n < $d2) {
180 192         389 _extend();
181             }
182 23         64 my $d1 = max (2, $x1 + $y1);
183             ### $d1
184             ### $d2
185              
186             return ($_x_to_n[$d1] - 1 + $self->{'n_start'},
187 23         77 $_x_to_n[$d2] + $self->{'n_start'});
188             }
189              
190             1;
191             __END__