File Coverage

blib/lib/Math/PlanePath/TerdragonCurve.pm
Criterion Covered Total %
statement 163 288 56.6
branch 33 100 33.0
condition 26 44 59.0
subroutine 28 44 63.6
pod 13 13 100.0
total 263 489 53.7


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              
20             # points singles A052548 2^n + 2
21             # points doubles A000918 2^n - 2
22             # points triples A028243 3^(n-1) - 2*2^(n-1) + 1 cf A[k] = 2*3^(k-1) - 2*2^(k-1)
23              
24             # T(3*N) = (w+1)*T(N) dir(N)=w^(2*count1digits)
25             # T(3*N+1) = (w+1)*T(N) + 1*dir(N)
26             # T(3*N+2) = (w+1)*T(N) + w*dir(N)
27              
28             # T(0*3^k + N) = T(N)
29             # T(1*3^k + N) = 2^k + w^2*T(N) # rotate and offset
30             # T(2*3^k + N) = w*2^k + T(N) # offset only
31              
32              
33              
34             package Math::PlanePath::TerdragonCurve;
35 1     1   9677 use 5.004;
  1         9  
36 1     1   6 use strict;
  1         2  
  1         39  
37 1     1   7 use List::Util 'first';
  1         2  
  1         133  
38 1     1   8 use List::Util 'min'; # 'max'
  1         2  
  1         65  
39             *max = \&Math::PlanePath::_max;
40              
41 1     1   706 use Math::PlanePath;
  1         3  
  1         47  
42             *_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
43              
44             use Math::PlanePath::Base::Generic
45 1         50 'is_infinite',
46             'round_nearest',
47 1     1   7 'xy_is_even';
  1         2  
48             use Math::PlanePath::Base::Digits
49 1         64 'digit_split_lowtohigh',
50             'digit_join_lowtohigh',
51 1     1   481 'round_up_pow';
  1         2  
52              
53 1     1   8 use vars '$VERSION', '@ISA';
  1         2  
  1         73  
54             $VERSION = 129;
55             @ISA = ('Math::PlanePath');
56              
57 1     1   603 use Math::PlanePath::TerdragonMidpoint;
  1         3  
  1         32  
58              
59             # uncomment this to run the ### lines
60             # use Smart::Comments;
61              
62              
63 1     1   7 use constant n_start => 0;
  1         2  
  1         69  
64 1         215 use constant parameter_info_array =>
65             [ { name => 'arms',
66             share_key => 'arms_6',
67             display => 'Arms',
68             type => 'integer',
69             minimum => 1,
70             maximum => 6,
71             default => 1,
72             width => 1,
73             description => 'Arms',
74 1     1   6 } ];
  1         2  
75              
76             {
77             my @x_negative_at_n = (undef, 13, 5, 5, 6, 7, 8);
78             sub x_negative_at_n {
79 0     0 1 0 my ($self) = @_;
80 0         0 return $x_negative_at_n[$self->{'arms'}];
81             }
82             }
83             {
84             my @y_negative_at_n = (undef, 159, 75, 20, 11, 9, 10);
85             sub y_negative_at_n {
86 0     0 1 0 my ($self) = @_;
87 0         0 return $y_negative_at_n[$self->{'arms'}];
88             }
89             }
90             sub dx_minimum {
91 0     0 1 0 my ($self) = @_;
92 0 0       0 return ($self->{'arms'} == 1 ? -1 : -2);
93             }
94 1     1   8 use constant dx_maximum => 2;
  1         2  
  1         61  
95 1     1   7 use constant dy_minimum => -1;
  1         2  
  1         44  
96 1     1   6 use constant dy_maximum => 1;
  1         2  
  1         185  
97              
98             sub _UNDOCUMENTED__dxdy_list {
99 0     0   0 my ($self) = @_;
100 0 0       0 return ($self->{'arms'} == 1
101             ? Math::PlanePath::_UNDOCUMENTED__dxdy_list_three()
102             : Math::PlanePath::_UNDOCUMENTED__dxdy_list_six());
103             }
104             {
105             my @_UNDOCUMENTED__dxdy_list_at_n = (undef, 4, 9, 13, 7, 8, 5);
106             sub _UNDOCUMENTED__dxdy_list_at_n {
107 0     0   0 my ($self) = @_;
108 0         0 return $_UNDOCUMENTED__dxdy_list_at_n[$self->{'arms'}];
109             }
110             }
111 1     1   22 use constant absdx_minimum => 1;
  1         2  
  1         52  
112 1     1   37 use constant dsumxy_minimum => -2; # diagonals
  1         6  
  1         72  
113 1     1   7 use constant dsumxy_maximum => 2;
  1         1  
  1         45  
114 1     1   6 use constant ddiffxy_minimum => -2;
  1         2  
  1         53  
115 1     1   7 use constant ddiffxy_maximum => 2;
  1         1  
  1         101  
116              
117             # arms=1 curve goes at 0,120,240 degrees
118             # arms=2 second +60 to 60,180,300 degrees
119             # so when arms==1 dir maximum is 240 degrees
120             sub dir_maximum_dxdy {
121 0     0 1 0 my ($self) = @_;
122 0 0       0 return ($self->{'arms'} == 1
123             ? (-1,-1) # 0,2,4 only South-West
124             : ( 1,-1)); # rotated to 1,3,5 too South-East
125             }
126              
127 1     1   8 use constant turn_any_straight => 0; # never straight
  1         2  
  1         2433  
128              
129              
130             #------------------------------------------------------------------------------
131              
132             sub new {
133 24     24 1 4333 my $self = shift->SUPER::new(@_);
134 24   100     175 $self->{'arms'} = max(1, min(6, $self->{'arms'} || 1));
135 24         54 return $self;
136             }
137              
138             my @dir6_to_si = (1,0,0, -1,0,0);
139             my @dir6_to_sj = (0,1,0, 0,-1,0);
140             my @dir6_to_sk = (0,0,1, 0,0,-1);
141              
142             sub n_to_xy {
143 441     441 1 38225 my ($self, $n) = @_;
144             ### TerdragonCurve n_to_xy(): $n
145              
146 441 50       1086 if ($n < 0) { return; }
  0         0  
147 441 50       1027 if (is_infinite($n)) { return ($n, $n); }
  0         0  
148              
149 441         812 my $zero = ($n * 0); # inherit bignum 0
150              
151 441         618 my $i = 0;
152 441         554 my $j = 0;
153 441         559 my $k = 0;
154 441         590 my $si = $zero;
155 441         568 my $sj = $zero;
156 441         613 my $sk = $zero;
157              
158             # initial rotation from arm number
159             {
160 441         586 my $int = int($n);
  441         667  
161 441         669 my $frac = $n - $int; # inherit possible BigFloat
162 441         604 $n = $int; # BigFloat int() gives BigInt, use that
163              
164 441         1403 my $rot = _divrem_mutate ($n, $self->{'arms'});
165              
166 441         704 my $s = $zero + 1; # inherit bignum 1
167 441 100       792 if ($rot >= 3) {
168 36         55 $s = -$s; # rotate 180
169 36         56 $frac = -$frac;
170 36         46 $rot -= 3;
171             }
172 441 100       818 if ($rot == 0) { $i = $frac; $si = $s; } # rotate 0
  270 100       384  
  270         415  
173 116         147 elsif ($rot == 1) { $j = $frac; $sj = $s; } # rotate +60
  116         171  
174 55         75 else { $k = $frac; $sk = $s; } # rotate +120
  55         88  
175             }
176              
177 441         978 foreach my $digit (digit_split_lowtohigh($n,3)) {
178             ### at: "$i,$j,$k side $si,$sj,$sk"
179             ### $digit
180              
181 2363 100       4191 if ($digit == 1) {
    100          
182 979         1822 ($i,$j,$k) = ($si-$j, $sj-$k, $sk+$i); # rotate +120 and add
183             } elsif ($digit == 2) {
184 776         1037 $i -= $sk; # add rotated +60
185 776         1004 $j += $si;
186 776         1042 $k += $sj;
187             }
188              
189             # add rotated +60
190 2363         4213 ($si,$sj,$sk) = ($si - $sk,
191             $sj + $si,
192             $sk + $sj);
193             }
194              
195             ### final: "$i,$j,$k side $si,$sj,$sk"
196             ### is: (2*$i + $j - $k).",".($j+$k)
197              
198 441         1312 return (2*$i + $j - $k, $j+$k);
199             }
200              
201              
202             # all even points when arms==6
203             sub xy_is_visited {
204 0     0 1 0 my ($self, $x, $y) = @_;
205 0 0       0 if ($self->{'arms'} == 6) {
206 0         0 return xy_is_even($self,$x,$y);
207             } else {
208 0         0 return defined($self->xy_to_n($x,$y));
209             }
210             }
211              
212             sub xy_to_n {
213 26     26 1 750 return scalar((shift->xy_to_n_list(@_))[0]);
214             }
215             sub xy_to_n_list {
216 55     55 1 737 my ($self, $x,$y) = @_;
217             ### TerdragonCurve xy_to_n_list(): "$x, $y"
218              
219 55         140 $x = round_nearest($x);
220 55         119 $y = round_nearest($y);
221             {
222             # nothing at an odd point, and trap overflows in $x+$y dividing out b
223 55         85 my $sum = abs($x) + abs($y);
  55         86  
224 55 50       109 if (is_infinite($sum)) { return $sum; } # infinity
  0         0  
225 55 50       200 if ($sum % 2) { return; }
  0         0  
226             }
227              
228 55 100 100     147 if ($x==0 && $y==0) {
229 11         42 return 0 .. $self->{'arms'}-1;
230             }
231              
232 44         110 my $arms_count = $self->arms_count;
233 44         73 my $zero = ($x * 0 * $y); # inherit bignum 0
234              
235 44         67 my @n_list;
236 44         90 foreach my $d (0,1,2) {
237 132         259 my ($ndigits,$arm) = _xy_d_to_ndigits_and_arm($x,$y,$d);
238 132 100       282 next if $arm >= $arms_count;
239 111         165 my $odd = ($arm & 1);
240 111 100       192 if ($odd) {
241 33         57 @$ndigits = (map {2-$_} @$ndigits);
  163         271  
242             ### flip to: $ndigits
243             }
244 111         262 push @n_list,
245             (digit_join_lowtohigh($ndigits, 3, $zero) + $odd) * $arms_count + $arm;
246             }
247              
248             ### @n_list
249 44         158 return sort {$a<=>$b} @n_list;
  88         215  
250             }
251              
252             my @x_to_digit = (0, 2, 1); # digit = -X mod 3
253             my @digit_to_x = ([0,2,1], [0,-1,-2], [0,-1, 1]);
254             my @digit_to_y = ([0,0,1], [0, 1, 0], [0,-1,-1]);
255              
256             # $d = 0,1,2 for segment leaving $x,$y at direction $d*120 degrees.
257             # For odd arms the digits are 0<->2 reversals.
258             sub _xy_d_to_ndigits_and_arm {
259 132     132   217 my ($x,$y, $d) = @_;
260 132         193 my @ndigits;
261             my $arm;
262 132         167 for (;;) {
263             ### at: "$x,$y d=$d"
264 1222 100 100     1361 if ($x==0 && $y==0) { $arm = 2*$d; last; }
  79         115  
  79         114  
265 1143 100 100     1243 if ($d==0 && $x==-2 && $y==0) { $arm = 3; last; }
  7   100     12  
  7         12  
266 1136 100 100     1321 if ($d==2 && $x==1 && $y==1) { $arm = 1; last; }
  30   100     38  
  30         51  
267 1106 100 100     1217 if ($d==1 && $x==1 && $y==-1) { $arm = 5; last; }
  16   100     28  
  16         24  
268              
269 1090         837 my $digit = $x_to_digit[$x%3];
270 1090         852 push @ndigits, $digit;
271              
272 1090 100       950 if ($digit == 1) { $d = ($d-1) % 3; }
  211         292  
273 1090         822 $x -= $digit_to_x[$d]->[$digit];
274 1090         753 $y -= $digit_to_y[$d]->[$digit];
275              
276             ### $digit
277             ### new d: $d
278             ### subtract: "$digit_to_x[$d]->[$digit],$digit_to_y[$d]->[$digit] to $x,$y"
279              
280             # ### assert: ($x+$y) % 2 == 0
281             # ### assert: $x % 3 == 0
282             # ### assert: ($y-$x/3) % 2 == 0
283 1090         4311 ($x,$y) = (($x+$y)/2, # divide b = w6+1
284             ($y-$x/3)/2);
285             }
286             ### $arm
287             ### @ndigits
288 132         306 return (\@ndigits, $arm);
289             }
290             # x+y*w3
291             # (x-y)+y*w3
292             # x/2 + y*sqrt3i/2
293             # sqrt3i/2 = w3+1/2
294             # x/2 + y*(w3+1/2) == 1/2*(x+y) + y*w3
295             # a = x+y = (x+3*y)/2
296             # GP-Test my(x=0,y=0); (-x)%3 == 0
297             # GP-Test my(x=2,y=0); (-x)%3 == 1
298             # GP-Test my(x=1,y=1); (-x)%3 == 2
299              
300             # minimum -- no, not quite right
301             #
302             # *----------*
303             # \
304             # \ *
305             # * \
306             # \
307             # *----------*
308             #
309             # width = side/2
310             # minimum = side*sqrt(3)/2 - width
311             # = side*(sqrt(3)/2 - 1)
312             #
313             # minimum 4/9 * 2.9^level roughly
314             # h = 4/9 * 2.9^level
315             # 2.9^level = h*9/4
316             # level = log(h*9/4)/log(2.9)
317             # 3^level = 3^(log(h*9/4)/log(2.9))
318             # = h*9/4, but big bigger for log
319             #
320             # not exact
321             sub rect_to_n_range {
322 31     31 1 2829 my ($self, $x1,$y1, $x2,$y2) = @_;
323             ### TerdragonCurve rect_to_n_range(): "$x1,$y1 $x2,$y2"
324 31         103 my $xmax = int(max(abs($x1),abs($x2)));
325 31         76 my $ymax = int(max(abs($y1),abs($y2)));
326             return (0,
327             ($xmax*$xmax + 3*$ymax*$ymax + 1)
328             * 2
329 31         104 * $self->{'arms'});
330             }
331              
332             # direction
333             #
334             my @dir6_to_dx = (2, 1,-1,-2, -1, 1);
335             my @dir6_to_dy = (0, 1, 1, 0, -1,-1);
336             my @digit_to_nextturn = (2,-2);
337             sub n_to_dxdy {
338 1000     1000 1 16551 my ($self, $n) = @_;
339             ### n_to_dxdy(): $n
340              
341 1000 50       1755 if ($n < 0) {
342 0         0 return; # first direction at N=0
343             }
344 1000 50       1814 if (is_infinite($n)) {
345 0         0 return ($n,$n);
346             }
347              
348 1000         1662 my $int = int($n); # integer part
349 1000         1372 $n -= $int; # fraction part
350              
351             # initial direction from arm
352 1000         1997 my $dir6 = _divrem_mutate ($int, $self->{'arms'});
353              
354 1000         1999 my @ndigits = digit_split_lowtohigh($int,3);
355 1000         1707 $dir6 += 2 * scalar(grep {$_==1} @ndigits); # count 1s for total turn
  5278         9343  
356 1000         1497 $dir6 %= 6;
357 1000         1454 my $dx = $dir6_to_dx[$dir6];
358 1000         1300 my $dy = $dir6_to_dy[$dir6];
359              
360 1000 50       1699 if ($n) {
361             # fraction part
362              
363             # find lowest non-2 digit, or zero if all 2s or no digits at all
364 0     0   0 $dir6 += $digit_to_nextturn[ first {$_!=2} @ndigits, 0];
  0         0  
365 0         0 $dir6 %= 6;
366 0         0 $dx += $n*($dir6_to_dx[$dir6] - $dx);
367 0         0 $dy += $n*($dir6_to_dy[$dir6] - $dy);
368             }
369 1000         2300 return ($dx, $dy);
370             }
371              
372              
373             #-----------------------------------------------------------------------------
374             # eg. arms=5 0 .. 5*3^k step by 5s
375             # 1 .. 5*3^k+1 step by 5s
376             # 4 .. 5*3^k+4 step by 5s
377             #
378             sub level_to_n_range {
379 6     6 1 408 my ($self, $level) = @_;
380 6         24 return (0, (3**$level + 1) * $self->{'arms'} - 1);
381             }
382             sub n_to_level {
383 0     0 1   my ($self, $n) = @_;
384 0 0         if ($n < 0) { return undef; }
  0            
385 0 0         if (is_infinite($n)) { return $n; }
  0            
386 0           $n = round_nearest($n);
387 0           _divrem_mutate ($n, $self->{'arms'});
388 0           my ($pow, $exp) = round_up_pow ($n, 3);
389 0           return $exp;
390             }
391              
392             #-----------------------------------------------------------------------------
393             # right boundary N
394              
395             # mixed radix binary, ternary
396             # no 11, 12, 20
397             # 11 -> 21, including low digit
398             # run of 11111 becomes 22221
399             # low to high 1 or 0 <- 0 cannot 20 can 10 00
400             # 2 or 0 <- 1 cannot 11 can 21 01
401             # 2 or 0 <- 2 cannot 12 can 02 22
402             sub _UNDOCUMENTED__right_boundary_i_to_n {
403 0     0     my ($self, $i) = @_;
404 0           my @digits = _digit_split_mix23_lowtohigh($i);
405 0           for ($i = $#digits; $i >= 1; $i--) { # high to low
406 0 0 0       if ($digits[$i] == 1 && $digits[$i-1] != 0) {
407 0           $digits[$i] = 2;
408             }
409             }
410 0           return digit_join_lowtohigh(\@digits, 3, $i*0);
411              
412             # {
413             # for (my $i = 0; $i < $#digits; $i++) { # low to high
414             # if ($digits[$i+1] == 1 && ($digits[$i] == 1 || $digits[$i] == 2)) {
415             # $digits[$i+1] = 2;
416             # }
417             # }
418             # return digit_join_lowtohigh(\@digits,3);
419             # }
420             }
421              
422             # Return a list of digits, low to high, which is a mixed radix
423             # representation low digit ternary and the rest binary.
424             sub _digit_split_mix23_lowtohigh {
425 0     0     my ($n) = @_;
426 0 0         if ($n == 0) {
427 0           return ();
428             }
429 0           my $low = _divrem_mutate($n,3);
430 0           return ($low, digit_split_lowtohigh($n,2));
431             }
432              
433             {
434             # disallowed digit pairs $disallowed[high][low]
435             my @disallowed;
436             $disallowed[1][1] = 1;
437             $disallowed[1][2] = 1;
438             $disallowed[2][0] = 1;
439              
440             sub _UNDOCUMENTED__n_segment_is_right_boundary {
441 0     0     my ($self, $n) = @_;
442 0 0         if (is_infinite($n)) { return 0; }
  0            
443 0 0         unless ($n >= 0) { return 0; }
  0            
444 0           $n = int($n);
445              
446             # no boundary when arms=6, right boundary is only in arm 0
447             {
448 0           my $arms = $self->{'arms'};
  0            
449 0 0         if ($arms == 6) { return 0; }
  0            
450 0 0         if (_divrem_mutate($n,$arms)) { return 0; }
  0            
451             }
452              
453 0           my $prev = _divrem_mutate($n,3);
454 0           while ($n) {
455 0           my $digit = _divrem_mutate($n,3);
456 0 0         if ($disallowed[$digit][$prev]) {
457 0           return 0;
458             }
459 0           $prev = $digit;
460             }
461 0           return 1;
462             }
463             }
464              
465             #-----------------------------------------------------------------------------
466             # left boundary N
467              
468              
469             # mixed 0,1, 2, 10, 11, 12, 100, 101, 102, 110, 111, 112, 1000, 1001, 1002, 1010, 1011, 1012, 1100, 1101, 1102,
470             # vals 0,1,12,120,121,122,1200,1201,1212,1220,1221,1222,12000,12001,12012,12120,12121,12122,12200,12201,12212,
471             {
472             my @_UNDOCUMENTED__left_boundary_i_to_n = ([0,2], # 0
473             [0,2], # 1
474             [1,2]); # 2
475             sub _UNDOCUMENTED__left_boundary_i_to_n {
476 0     0     my ($self, $i, $level) = @_;
477             ### _UNDOCUMENTED__left_boundary_i_to_n(): $i
478             ### $level
479              
480 0 0 0       if (defined $level && $level < 0) {
481 0 0         if ($i <= 2) {
482 0           return $i;
483             }
484 0           $i += 2;
485             }
486              
487 0           my @digits = _digit_split_mix23_lowtohigh($i);
488             ### @digits
489              
490 0 0         if (defined $level) {
491 0 0         if ($level >= 0) {
492 0 0         if (@digits > $level) {
493             ### beyond given level ...
494 0           return undef;
495             }
496             # pad for $level, total $level many digits
497 0           push @digits, (0) x ($level - scalar(@digits));
498             } else {
499             ### union all levels ...
500 0           pop @digits;
501 0 0         if ($digits[-1]) {
502 0           push @digits, 0; # high 0,1 or 0,2 when i=3
503             } else {
504 0           $digits[-1] = 1; # high 1
505             }
506             }
507             } else {
508             ### infinite curve, an extra high 0 ...
509 0           push @digits, 0;
510             }
511             ### @digits
512              
513 0           my $prev = $digits[0];
514 0           foreach my $i (1 .. $#digits) {
515 0           $prev = $digits[$i] = $_UNDOCUMENTED__left_boundary_i_to_n[$prev][$digits[$i]];
516             }
517             ### ternary: @digits
518 0           return digit_join_lowtohigh(\@digits, 3, $i*0);
519             }
520             }
521              
522             {
523             # disallowed digit pairs $disallowed[high][low]
524             my @disallowed;
525             $disallowed[0][2] = 1;
526             $disallowed[1][0] = 1;
527             $disallowed[1][1] = 1;
528              
529             sub _UNDOCUMENTED__n_segment_is_left_boundary {
530 0     0     my ($self, $n, $level) = @_;
531             ### _UNDOCUMENTED__n_segment_is_left_boundary(): $n
532             ### $level
533              
534 0 0         if (is_infinite($n)) { return 0; }
  0            
535 0 0         unless ($n >= 0) { return 0; }
  0            
536 0           $n = int($n);
537              
538 0 0 0       if (defined $level && $level == 0) {
539             ### level 0 curve, N=0 is only segment: ($n == 0)
540 0           return ($n == 0);
541             }
542              
543             {
544 0           my $arms = $self->{'arms'};
  0            
545 0 0         if ($arms == 6) {
546 0           return 0;
547             }
548 0           my $arm = _divrem_mutate($n,$arms);
549 0 0         if ($arm != $arms-1) {
550 0           return 0;
551             }
552             }
553              
554 0           my $prev = _divrem_mutate($n,3);
555 0 0         if (defined $level) { $level -= 1; }
  0            
556              
557 0           for (;;) {
558 0 0 0       if (defined $level && $level == 0) {
559             ### end of level many digits, must be N < 3**$level
560 0           return ($n == 0);
561             }
562 0 0         last unless $n;
563              
564 0           my $digit = _divrem_mutate($n,3);
565 0 0         if ($disallowed[$digit][$prev]) {
566 0           return 0;
567             }
568 0 0         if (defined $level) { $level -= 1; }
  0            
569 0           $prev = $digit;
570             }
571              
572 0   0       return ((defined $level && $level < 0) # union all levels
573             || ($prev != 2)); # not high 2 otherwise
574             }
575              
576             sub _UNDOCUMENTED__n_segment_is_any_left_boundary {
577 0     0     my ($self, $n) = @_;
578 0           my $prev = _divrem_mutate($n,3);
579 0           while ($n) {
580 0           my $digit = _divrem_mutate($n,3);
581 0 0         if ($disallowed[$digit][$prev]) {
582 0           return 0;
583             }
584 0           $prev = $digit;
585             }
586 0           return 1;
587             }
588              
589             # sub left_boundary_n_pred {
590             # my ($n) = @_;
591             # my $n3 = '0' . Math::BaseCnv::cnv($n,10,3);
592             # return ($n3 =~ /02|10|11/ ? 0 : 1);
593             # }
594             }
595             sub _UNDOCUMENTED__n_segment_is_boundary {
596 0     0     my ($self, $n, $level) = @_;
597 0   0       return $self->_UNDOCUMENTED__n_segment_is_right_boundary($n)
598             || $self->_UNDOCUMENTED__n_segment_is_left_boundary($n,$level);
599             }
600              
601             1;
602             __END__