File Coverage

blib/lib/Math/PlanePath/CincoCurve.pm
Criterion Covered Total %
statement 51 110 46.3
branch 4 26 15.3
condition 0 10 0.0
subroutine 12 15 80.0
pod 3 3 100.0
total 70 164 42.6


line stmt bran cond sub pod time code
1             # Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020 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             # http://www.cisl.ucar.edu/css/papers/sfc3.pdf
20             # Hilbert + Peano-meander
21             #
22             # http://oceans11.lanl.gov/svn/POP/trunk/pop/source/distribution.F90
23             #
24              
25             package Math::PlanePath::CincoCurve;
26 1     1   9190 use 5.004;
  1         10  
27 1     1   5 use strict;
  1         2  
  1         66  
28             #use List::Util 'min', 'max';
29             *min = \&Math::PlanePath::_min;
30             *max = \&Math::PlanePath::_max;
31              
32 1     1   7 use vars '$VERSION', '@ISA';
  1         2  
  1         70  
33             $VERSION = 129;
34 1     1   694 use Math::PlanePath;
  1         2  
  1         30  
35 1     1   425 use Math::PlanePath::Base::NSEW;
  1         2  
  1         41  
36             @ISA = ('Math::PlanePath::Base::NSEW',
37             'Math::PlanePath');
38              
39             use Math::PlanePath::Base::Generic
40 1         107 'is_infinite',
41 1     1   6 'round_nearest';
  1         1  
42             use Math::PlanePath::Base::Digits
43 1         68 'round_down_pow',
44             'digit_split_lowtohigh',
45 1     1   490 'digit_join_lowtohigh';
  1         3  
46              
47              
48 1     1   7 use constant n_start => 0;
  1         2  
  1         48  
49 1     1   5 use constant class_x_negative => 0;
  1         2  
  1         39  
50 1     1   5 use constant class_y_negative => 0;
  1         2  
  1         1753  
51             *xy_is_visited = \&Math::PlanePath::Base::Generic::xy_is_visited_quad1;
52              
53              
54             #------------------------------------------------------------------------------
55             # tables generated by tools/dekking-curve-table.pl
56             #
57             my @next_state = ( 0, 0,50,50,50, # 0
58             75,25,25,50,50,
59             0, 0,75,50, 0,
60             0, 0,25,75,75,
61             0,25,75,75, 0,
62             25,25,75,75,75, # 25
63             50, 0, 0,75,75,
64             25,25,50,75,25,
65             25,25, 0,50,50,
66             25, 0,50,50,25,
67             50,50, 0, 0, 0, # 50
68             25,75,75, 0, 0,
69             50,50,25, 0,50,
70             50,50,75,25,25,
71             50,75,25,25,50,
72             75,75,25,25,25, # 75
73             0,50,50,25,25,
74             75,75, 0,25,75,
75             75,75,50, 0, 0,
76             75,50, 0, 0,75);
77             my @digit_to_x = (0,1,2,2,2, 1,1,0,0,0, 0,1,1,2,2, 3,4,4,3,3, 4,4,3,3,4,
78             4,3,2,2,2, 3,3,4,4,4, 4,3,3,2,2, 1,0,0,1,1, 0,0,1,1,0,
79             0,0,0,1,2, 2,1,1,2,3, 4,4,3,3,4, 4,4,3,3,2, 2,1,1,0,0,
80             4,4,4,3,2, 2,3,3,2,1, 0,0,1,1,0, 0,0,1,1,2, 2,3,3,4,4);
81             my @digit_to_y = (0,0,0,1,2, 2,1,1,2,3, 4,4,3,3,4, 4,4,3,3,2, 2,1,1,0,0,
82             4,4,4,3,2, 2,3,3,2,1, 0,0,1,1,0, 0,0,1,1,2, 2,3,3,4,4,
83             0,1,2,2,2, 1,1,0,0,0, 0,1,1,2,2, 3,4,4,3,3, 4,4,3,3,4,
84             4,3,2,2,2, 3,3,4,4,4, 4,3,3,2,2, 1,0,0,1,1, 0,0,1,1,0);
85             my @yx_to_digit = ( 0, 1, 2,23,24, # 0
86             7, 6, 3,22,21,
87             8, 5, 4,19,20,
88             9,12,13,18,17,
89             10,11,14,15,16,
90             16,15,14,11,10, # 25
91             17,18,13,12, 9,
92             20,19, 4, 5, 8,
93             21,22, 3, 6, 7,
94             24,23, 2, 1, 0,
95             0, 7, 8, 9,10, # 50
96             1, 6, 5,12,11,
97             2, 3, 4,13,14,
98             23,22,19,18,15,
99             24,21,20,17,16,
100             16,17,20,21,24, # 75
101             15,18,19,22,23,
102             14,13, 4, 3, 2,
103             11,12, 5, 6, 1,
104             10, 9, 8, 7, 0);
105             my @min_digit = ( 0, 0, 0, 0, 0, # 0
106             7, 7, 7, 7, 8,
107             8, 8, 9, 9,10,
108             0, 0, 0, 0, 0,
109             6, 5, 5, 5, 5,
110             5, 5, 9, 9,10, # 25
111             0, 0, 0, 0, 0,
112             3, 3, 3, 3, 4,
113             4, 4, 9, 9,10,
114             0, 0, 0, 0, 0,
115             3, 3, 3, 3, 4, # 50
116             4, 4, 9, 9,10,
117             0, 0, 0, 0, 0,
118             3, 3, 3, 3, 4,
119             4, 4, 9, 9,10,
120             1, 1, 1, 1, 1, # 75
121             6, 5, 5, 5, 5,
122             5, 5,12,11,11,
123             1, 1, 1, 1, 1,
124             3, 3, 3, 3, 4,
125             4, 4,12,11,11, # 100
126             1, 1, 1, 1, 1,
127             3, 3, 3, 3, 4,
128             4, 4,12,11,11,
129             1, 1, 1, 1, 1,
130             3, 3, 3, 3, 4, # 125
131             4, 4,12,11,11,
132             2, 2, 2, 2, 2,
133             3, 3, 3, 3, 4,
134             4, 4,13,13,14,
135             2, 2, 2, 2, 2, # 150
136             3, 3, 3, 3, 4,
137             4, 4,13,13,14,
138             2, 2, 2, 2, 2,
139             3, 3, 3, 3, 4,
140             4, 4,13,13,14, # 175
141             23,22,19,18,15,
142             22,19,18,15,19,
143             18,15,18,15,15,
144             23,21,19,17,15,
145             21,19,17,15,19, # 200
146             17,15,17,15,15,
147             24,21,20,17,16,
148             21,20,17,16,20,
149             17,16,17,16,16,
150             16,16,16,16,16, # 225
151             17,17,17,17,20,
152             20,20,21,21,24,
153             15,15,15,15,15,
154             17,17,17,17,19,
155             19,19,21,21,23, # 250
156             14,13, 4, 3, 2,
157             13, 4, 3, 2, 4,
158             3, 2, 3, 2, 2,
159             11,11, 4, 3, 1,
160             12, 4, 3, 1, 4, # 275
161             3, 1, 3, 1, 1,
162             10, 9, 4, 3, 0,
163             9, 4, 3, 0, 4,
164             3, 0, 3, 0, 0,
165             15,15,15,15,15, # 300
166             18,18,18,18,19,
167             19,19,22,22,23,
168             14,13, 4, 3, 2,
169             13, 4, 3, 2, 4,
170             3, 2, 3, 2, 2, # 325
171             11,11, 4, 3, 1,
172             12, 4, 3, 1, 4,
173             3, 1, 3, 1, 1,
174             10, 9, 4, 3, 0,
175             9, 4, 3, 0, 4, # 350
176             3, 0, 3, 0, 0,
177             14,13, 4, 3, 2,
178             13, 4, 3, 2, 4,
179             3, 2, 3, 2, 2,
180             11,11, 4, 3, 1, # 375
181             12, 4, 3, 1, 4,
182             3, 1, 3, 1, 1,
183             10, 9, 4, 3, 0,
184             9, 4, 3, 0, 4,
185             3, 0, 3, 0, 0, # 400
186             11,11, 5, 5, 1,
187             12, 5, 5, 1, 5,
188             5, 1, 6, 1, 1,
189             10, 9, 5, 5, 0,
190             9, 5, 5, 0, 5, # 425
191             5, 0, 6, 0, 0,
192             10, 9, 8, 7, 0,
193             9, 8, 7, 0, 8,
194             7, 0, 7, 0, 0,
195             0, 0, 0, 0, 0, # 450
196             1, 1, 1, 1, 2,
197             2, 2,23,23,24,
198             0, 0, 0, 0, 0,
199             1, 1, 1, 1, 2,
200             2, 2,22,21,21, # 475
201             0, 0, 0, 0, 0,
202             1, 1, 1, 1, 2,
203             2, 2,19,19,20,
204             0, 0, 0, 0, 0,
205             1, 1, 1, 1, 2, # 500
206             2, 2,18,17,17,
207             0, 0, 0, 0, 0,
208             1, 1, 1, 1, 2,
209             2, 2,15,15,16,
210             7, 6, 3, 3, 3, # 525
211             6, 3, 3, 3, 3,
212             3, 3,22,21,21,
213             7, 5, 3, 3, 3,
214             5, 3, 3, 3, 3,
215             3, 3,19,19,20, # 550
216             7, 5, 3, 3, 3,
217             5, 3, 3, 3, 3,
218             3, 3,18,17,17,
219             7, 5, 3, 3, 3,
220             5, 3, 3, 3, 3, # 575
221             3, 3,15,15,16,
222             8, 5, 4, 4, 4,
223             5, 4, 4, 4, 4,
224             4, 4,19,19,20,
225             8, 5, 4, 4, 4, # 600
226             5, 4, 4, 4, 4,
227             4, 4,18,17,17,
228             8, 5, 4, 4, 4,
229             5, 4, 4, 4, 4,
230             4, 4,15,15,16, # 625
231             9, 9, 9, 9, 9,
232             12,12,12,12,13,
233             13,13,18,17,17,
234             9, 9, 9, 9, 9,
235             11,11,11,11,13, # 650
236             13,13,15,15,16,
237             10,10,10,10,10,
238             11,11,11,11,14,
239             14,14,15,15,16,
240             16,15,14,11,10, # 675
241             15,14,11,10,14,
242             11,10,11,10,10,
243             16,15,13,11, 9,
244             15,13,11, 9,13,
245             11, 9,11, 9, 9, # 700
246             16,15, 4, 4, 4,
247             15, 4, 4, 4, 4,
248             4, 4, 5, 5, 8,
249             16,15, 3, 3, 3,
250             15, 3, 3, 3, 3, # 725
251             3, 3, 5, 5, 7,
252             16,15, 2, 1, 0,
253             15, 2, 1, 0, 2,
254             1, 0, 1, 0, 0,
255             17,17,13,12, 9, # 750
256             18,13,12, 9,13,
257             12, 9,12, 9, 9,
258             17,17, 4, 4, 4,
259             18, 4, 4, 4, 4,
260             4, 4, 5, 5, 8, # 775
261             17,17, 3, 3, 3,
262             18, 3, 3, 3, 3,
263             3, 3, 5, 5, 7,
264             17,17, 2, 1, 0,
265             18, 2, 1, 0, 2, # 800
266             1, 0, 1, 0, 0,
267             20,19, 4, 4, 4,
268             19, 4, 4, 4, 4,
269             4, 4, 5, 5, 8,
270             20,19, 3, 3, 3, # 825
271             19, 3, 3, 3, 3,
272             3, 3, 5, 5, 7,
273             20,19, 2, 1, 0,
274             19, 2, 1, 0, 2,
275             1, 0, 1, 0, 0, # 850
276             21,21, 3, 3, 3,
277             22, 3, 3, 3, 3,
278             3, 3, 6, 6, 7,
279             21,21, 2, 1, 0,
280             22, 2, 1, 0, 2, # 875
281             1, 0, 1, 0, 0,
282             24,23, 2, 1, 0,
283             23, 2, 1, 0, 2,
284             1, 0, 1, 0, 0);
285             my @max_digit = ( 0, 7, 8, 9,10, # 0
286             7, 8, 9,10, 8,
287             9,10, 9,10,10,
288             1, 7, 8,12,12,
289             7, 8,12,12, 8,
290             12,12,12,12,11, # 25
291             2, 7, 8,13,14,
292             7, 8,13,14, 8,
293             13,14,13,14,14,
294             23,23,23,23,23,
295             22,22,22,22,19, # 50
296             19,19,18,18,15,
297             24,24,24,24,24,
298             22,22,22,22,20,
299             20,20,18,18,16,
300             1, 6, 6,12,12, # 75
301             6, 6,12,12, 5,
302             12,12,12,12,11,
303             2, 6, 6,13,14,
304             6, 6,13,14, 5,
305             13,14,13,14,14, # 100
306             23,23,23,23,23,
307             22,22,22,22,19,
308             19,19,18,18,15,
309             24,24,24,24,24,
310             22,22,22,22,20, # 125
311             20,20,18,18,16,
312             2, 3, 4,13,14,
313             3, 4,13,14, 4,
314             13,14,13,14,14,
315             23,23,23,23,23, # 150
316             22,22,22,22,19,
317             19,19,18,18,15,
318             24,24,24,24,24,
319             22,22,22,22,20,
320             20,20,18,18,16, # 175
321             23,23,23,23,23,
322             22,22,22,22,19,
323             19,19,18,18,15,
324             24,24,24,24,24,
325             22,22,22,22,20, # 200
326             20,20,18,18,16,
327             24,24,24,24,24,
328             21,21,21,21,20,
329             20,20,17,17,16,
330             16,17,20,21,24, # 225
331             17,20,21,24,20,
332             21,24,21,24,24,
333             16,18,20,22,24,
334             18,20,22,24,20,
335             22,24,22,24,24, # 250
336             16,18,20,22,24,
337             18,20,22,24,20,
338             22,24,22,24,24,
339             16,18,20,22,24,
340             18,20,22,24,20, # 275
341             22,24,22,24,24,
342             16,18,20,22,24,
343             18,20,22,24,20,
344             22,24,22,24,24,
345             15,18,19,22,23, # 300
346             18,19,22,23,19,
347             22,23,22,23,23,
348             15,18,19,22,23,
349             18,19,22,23,19,
350             22,23,22,23,23, # 325
351             15,18,19,22,23,
352             18,19,22,23,19,
353             22,23,22,23,23,
354             15,18,19,22,23,
355             18,19,22,23,19, # 350
356             22,23,22,23,23,
357             14,14,14,14,14,
358             13,13,13,13, 4,
359             4, 4, 3, 3, 2,
360             14,14,14,14,14, # 375
361             13,13,13,13, 5,
362             6, 6, 6, 6, 2,
363             14,14,14,14,14,
364             13,13,13,13, 8,
365             8, 8, 7, 7, 2, # 400
366             11,12,12,12,12,
367             12,12,12,12, 5,
368             6, 6, 6, 6, 1,
369             11,12,12,12,12,
370             12,12,12,12, 8, # 425
371             8, 8, 7, 7, 1,
372             10,10,10,10,10,
373             9, 9, 9, 9, 8,
374             8, 8, 7, 7, 0,
375             0, 1, 2,23,24, # 450
376             1, 2,23,24, 2,
377             23,24,23,24,24,
378             7, 7, 7,23,24,
379             6, 6,23,24, 3,
380             23,24,23,24,24, # 475
381             8, 8, 8,23,24,
382             6, 6,23,24, 4,
383             23,24,23,24,24,
384             9,12,13,23,24,
385             12,13,23,24,13, # 500
386             23,24,23,24,24,
387             10,12,14,23,24,
388             12,14,23,24,14,
389             23,24,23,24,24,
390             7, 7, 7,22,22, # 525
391             6, 6,22,22, 3,
392             22,22,22,22,21,
393             8, 8, 8,22,22,
394             6, 6,22,22, 4,
395             22,22,22,22,21, # 550
396             9,12,13,22,22,
397             12,13,22,22,13,
398             22,22,22,22,21,
399             10,12,14,22,22,
400             12,14,22,22,14, # 575
401             22,22,22,22,21,
402             8, 8, 8,19,20,
403             5, 5,19,20, 4,
404             19,20,19,20,20,
405             9,12,13,19,20, # 600
406             12,13,19,20,13,
407             19,20,19,20,20,
408             10,12,14,19,20,
409             12,14,19,20,14,
410             19,20,19,20,20, # 625
411             9,12,13,18,18,
412             12,13,18,18,13,
413             18,18,18,18,17,
414             10,12,14,18,18,
415             12,14,18,18,14, # 650
416             18,18,18,18,17,
417             10,11,14,15,16,
418             11,14,15,16,14,
419             15,16,15,16,16,
420             16,16,16,16,16, # 675
421             15,15,15,15,14,
422             14,14,11,11,10,
423             17,18,18,18,18,
424             18,18,18,18,14,
425             14,14,12,12,10, # 700
426             20,20,20,20,20,
427             19,19,19,19,14,
428             14,14,12,12,10,
429             21,22,22,22,22,
430             22,22,22,22,14, # 725
431             14,14,12,12,10,
432             24,24,24,24,24,
433             23,23,23,23,14,
434             14,14,12,12,10,
435             17,18,18,18,18, # 750
436             18,18,18,18,13,
437             13,13,12,12, 9,
438             20,20,20,20,20,
439             19,19,19,19,13,
440             13,13,12,12, 9, # 775
441             21,22,22,22,22,
442             22,22,22,22,13,
443             13,13,12,12, 9,
444             24,24,24,24,24,
445             23,23,23,23,13, # 800
446             13,13,12,12, 9,
447             20,20,20,20,20,
448             19,19,19,19, 4,
449             5, 8, 5, 8, 8,
450             21,22,22,22,22, # 825
451             22,22,22,22, 4,
452             6, 8, 6, 8, 8,
453             24,24,24,24,24,
454             23,23,23,23, 4,
455             6, 8, 6, 8, 8, # 850
456             21,22,22,22,22,
457             22,22,22,22, 3,
458             6, 7, 6, 7, 7,
459             24,24,24,24,24,
460             23,23,23,23, 3, # 875
461             6, 7, 6, 7, 7,
462             24,24,24,24,24,
463             23,23,23,23, 2,
464             2, 2, 1, 1, 0);
465             # state length 100 in each of 4 tables = 400
466             # min/max 2 of 900 each = 1800
467              
468             sub n_to_xy {
469 31363     31363 1 203433 my ($self, $n) = @_;
470             ### CincoCurve n_to_xy(): $n
471              
472 31363 50       55975 if ($n < 0) { return; }
  0         0  
473 31363 50       56988 if (is_infinite($n)) { return ($n,$n); }
  0         0  
474              
475 31363         56325 my $int = int($n);
476 31363         43111 $n -= $int; # fraction part
477              
478 31363         59373 my @digits = digit_split_lowtohigh($int,25);
479 31363         55749 my $len = ($int*0 + 5) ** scalar(@digits); # inherit bignum
480              
481             ### digits: join(', ',@digits)." count ".scalar(@digits)
482             ### $len
483              
484 31363         45098 my $state = my $dir = 0;
485 31363         40667 my $x = 0;
486 31363         39137 my $y = 0;
487              
488 31363         60477 while (defined (my $digit = pop @digits)) {
489 92740         125298 $len /= 5;
490 92740         113868 $state += $digit;
491 92740 100       150176 if ($digit != 24) {
492 88984         116409 $dir = $state;
493             }
494              
495             ### $len
496             ### $state
497             ### digit_to_x: $digit_to_x[$state]
498             ### digit_to_y: $digit_to_y[$state]
499             ### next_state: $next_state[$state]
500              
501 92740         128645 $x += $len * $digit_to_x[$state];
502 92740         121246 $y += $len * $digit_to_y[$state];
503 92740         174497 $state = $next_state[$state];
504             }
505              
506             ### final integer: "$x,$y"
507             ### assert: ($dir % 25) != 24
508              
509             # with $n fractional part
510 31363         99216 return ($n * ($digit_to_x[$dir+1] - $digit_to_x[$dir]) + $x,
511             $n * ($digit_to_y[$dir+1] - $digit_to_y[$dir]) + $y);
512             }
513              
514             sub xy_to_n {
515 0     0 1   my ($self, $x, $y) = @_;
516             ### CincoCurve xy_to_n(): "$x, $y"
517              
518 0           $x = round_nearest ($x);
519 0           $y = round_nearest ($y);
520 0 0 0       if ($x < 0 || $y < 0) {
521 0           return undef;
522             }
523 0 0         if (is_infinite($x)) {
524 0           return $x;
525             }
526 0 0         if (is_infinite($y)) {
527 0           return $y;
528             }
529              
530 0           my @xdigits = digit_split_lowtohigh ($x, 5);
531 0           my @ydigits = digit_split_lowtohigh ($y, 5);
532 0           my $state = 0;
533 0           my @ndigits;
534              
535 0           foreach my $i (reverse 0 .. max($#xdigits,$#ydigits)) { # high to low
536 0   0       my $ndigit = $yx_to_digit[$state
      0        
537             + 5*($ydigits[$i]||0)
538             + ($xdigits[$i]||0)];
539 0           $ndigits[$i] = $ndigit;
540 0           $state = $next_state[$state+$ndigit];
541             }
542              
543 0           return digit_join_lowtohigh (\@ndigits, 25,
544             $x * 0 * $y); # bignum zero
545             }
546              
547             # exact
548             sub rect_to_n_range {
549 0     0 1   my ($self, $x1,$y1, $x2,$y2) = @_;
550             ### BetaOmega rect_to_n_range(): "$x1,$y1, $x2,$y2"
551              
552 0           $x1 = round_nearest ($x1);
553 0           $x2 = round_nearest ($x2);
554 0           $y1 = round_nearest ($y1);
555 0           $y2 = round_nearest ($y2);
556 0 0         ($x1,$x2) = ($x2,$x1) if $x1 > $x2;
557 0 0         ($y1,$y2) = ($y2,$y1) if $y1 > $y2;
558              
559 0 0 0       if ($x2 < 0 || $y2 < 0) {
560 0           return (1, 0);
561             }
562 0 0         if ($x1 < 0) { $x1 *= 0; } # "*=" to preserve bigint x1 or y1
  0            
563 0 0         if ($y1 < 0) { $y1 *= 0; }
  0            
564              
565 0 0         my ($len, $level) = round_down_pow (($x2 > $y2 ? $x2 : $y2),
566             5);
567 0 0         if (is_infinite($len)) {
568 0           return (0, $len);
569             }
570              
571             # At this point an over-estimate would be: return (0, 25*$len*$len-1);
572              
573              
574 0           my $n_min = my $n_max
575             = my $y_min = my $y_max
576             = my $x_min = my $x_max
577             = my $min_state = my $max_state
578             = 0;
579             ### $x_min
580             ### $y_min
581              
582 0           while ($level >= 0) {
583             ### $level
584             ### $len
585             {
586 0           my $digit = $min_digit[9*$min_state
587             + _rect_key($x1, $x2, $x_min, $len) * 15
588             + _rect_key($y1, $y2, $y_min, $len)];
589              
590             ### $min_state
591             ### $x_min
592             ### $y_min
593             ### $digit
594              
595 0           $n_min = 25*$n_min + $digit;
596 0           $min_state += $digit;
597 0           $x_min += $len * $digit_to_x[$min_state];
598 0           $y_min += $len * $digit_to_y[$min_state];
599 0           $min_state = $next_state[$min_state];
600             }
601             {
602 0           my $digit = $max_digit[9*$max_state
  0            
  0            
603             + _rect_key($x1, $x2, $x_max, $len) * 15
604             + _rect_key($y1, $y2, $y_max, $len)];
605              
606 0           $n_max = 25*$n_max + $digit;
607 0           $max_state += $digit;
608 0           $x_max += $len * $digit_to_x[$max_state];
609 0           $y_max += $len * $digit_to_y[$max_state];
610 0           $max_state = $next_state[$max_state];
611             }
612              
613 0           $len = int($len/5);
614 0           $level--;
615             }
616              
617 0           return ($n_min, $n_max);
618             }
619              
620             sub _rect_key {
621 0     0     my ($z1, $z2, $zbase, $len) = @_;
622 0           $z1 = max (0, min (4, int (($z1 - $zbase)/$len)));
623 0           $z2 = max (0, min (4, int (($z2 - $zbase)/$len)));
624             ### assert: $z1 <= $z2
625 0           return (9-$z1)*$z1/2 + $z2;
626             }
627              
628             #------------------------------------------------------------------------------
629             # levels
630              
631 1     1   504 use Math::PlanePath::DekkingCentres;
  1         3  
  1         153  
632             *level_to_n_range = \&Math::PlanePath::DekkingCentres::level_to_n_range;
633             *n_to_level = \&Math::PlanePath::DekkingCentres::n_to_level;
634              
635              
636             #------------------------------------------------------------------------------
637             1;
638             __END__