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   7449 use 5.004;
  1         34  
36 1     1   5 use strict;
  1         2  
  1         36  
37 1     1   5 use List::Util 'first';
  1         2  
  1         100  
38 1     1   6 use List::Util 'min'; # 'max'
  1         2  
  1         44  
39             *max = \&Math::PlanePath::_max;
40              
41 1     1   536 use Math::PlanePath;
  1         2  
  1         39  
42             *_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
43              
44             use Math::PlanePath::Base::Generic
45 1         40 'is_infinite',
46             'round_nearest',
47 1     1   5 'xy_is_even';
  1         2  
48             use Math::PlanePath::Base::Digits
49 1         51 'digit_split_lowtohigh',
50             'digit_join_lowtohigh',
51 1     1   361 'round_up_pow';
  1         2  
52              
53 1     1   5 use vars '$VERSION', '@ISA';
  1         2  
  1         58  
54             $VERSION = 128;
55             @ISA = ('Math::PlanePath');
56              
57 1     1   405 use Math::PlanePath::TerdragonMidpoint;
  1         3  
  1         27  
58              
59             # uncomment this to run the ### lines
60             # use Smart::Comments;
61              
62              
63 1     1   6 use constant n_start => 0;
  1         2  
  1         70  
64 1         168 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   6 use constant dx_maximum => 2;
  1         1  
  1         50  
95 1     1   6 use constant dy_minimum => -1;
  1         2  
  1         35  
96 1     1   4 use constant dy_maximum => 1;
  1         2  
  1         120  
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   12 use constant absdx_minimum => 1;
  1         2  
  1         46  
112 1     1   5 use constant dsumxy_minimum => -2; # diagonals
  1         2  
  1         51  
113 1     1   5 use constant dsumxy_maximum => 2;
  1         2  
  1         36  
114 1     1   4 use constant ddiffxy_minimum => -2;
  1         1  
  1         41  
115 1     1   6 use constant ddiffxy_maximum => 2;
  1         1  
  1         75  
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   12 use constant turn_any_straight => 0; # never straight
  1         2  
  1         1923  
128              
129              
130             #------------------------------------------------------------------------------
131              
132             sub new {
133 24     24 1 3476 my $self = shift->SUPER::new(@_);
134 24   100     135 $self->{'arms'} = max(1, min(6, $self->{'arms'} || 1));
135 24         58 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 44720 my ($self, $n) = @_;
144             ### TerdragonCurve n_to_xy(): $n
145              
146 441 50       843 if ($n < 0) { return; }
  0         0  
147 441 50       813 if (is_infinite($n)) { return ($n, $n); }
  0         0  
148              
149 441         690 my $zero = ($n * 0); # inherit bignum 0
150              
151 441         500 my $i = 0;
152 441         503 my $j = 0;
153 441         478 my $k = 0;
154 441         485 my $si = $zero;
155 441         494 my $sj = $zero;
156 441         471 my $sk = $zero;
157              
158             # initial rotation from arm number
159             {
160 441         483 my $int = int($n);
  441         567  
161 441         556 my $frac = $n - $int; # inherit possible BigFloat
162 441         470 $n = $int; # BigFloat int() gives BigInt, use that
163              
164 441         856 my $rot = _divrem_mutate ($n, $self->{'arms'});
165              
166 441         583 my $s = $zero + 1; # inherit bignum 1
167 441 100       727 if ($rot >= 3) {
168 26         35 $s = -$s; # rotate 180
169 26         31 $frac = -$frac;
170 26         32 $rot -= 3;
171             }
172 441 100       649 if ($rot == 0) { $i = $frac; $si = $s; } # rotate 0
  258 100       277  
  258         619  
173 128         145 elsif ($rot == 1) { $j = $frac; $sj = $s; } # rotate +60
  128         164  
174 55         63 else { $k = $frac; $sk = $s; } # rotate +120
  55         73  
175             }
176              
177 441         782 foreach my $digit (digit_split_lowtohigh($n,3)) {
178             ### at: "$i,$j,$k side $si,$sj,$sk"
179             ### $digit
180              
181 3164 100       4625 if ($digit == 1) {
    100          
182 1157         1694 ($i,$j,$k) = ($si-$j, $sj-$k, $sk+$i); # rotate +120 and add
183             } elsif ($digit == 2) {
184 971         1044 $i -= $sk; # add rotated +60
185 971         1021 $j += $si;
186 971         1050 $k += $sj;
187             }
188              
189             # add rotated +60
190 3164         4533 ($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         1119 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 584 return scalar((shift->xy_to_n_list(@_))[0]);
214             }
215             sub xy_to_n_list {
216 55     55 1 465 my ($self, $x,$y) = @_;
217             ### TerdragonCurve xy_to_n_list(): "$x, $y"
218              
219 55         107 $x = round_nearest($x);
220 55         96 $y = round_nearest($y);
221             {
222             # nothing at an odd point, and trap overflows in $x+$y dividing out b
223 55         62 my $sum = abs($x) + abs($y);
  55         76  
224 55 50       89 if (is_infinite($sum)) { return $sum; } # infinity
  0         0  
225 55 50       122 if ($sum % 2) { return; }
  0         0  
226             }
227              
228 55 100 100     122 if ($x==0 && $y==0) {
229 12         37 return 0 .. $self->{'arms'}-1;
230             }
231              
232 43         91 my $arms_count = $self->arms_count;
233 43         60 my $zero = ($x * 0 * $y); # inherit bignum 0
234              
235 43         47 my @n_list;
236 43         68 foreach my $d (0,1,2) {
237 129         186 my ($ndigits,$arm) = _xy_d_to_ndigits_and_arm($x,$y,$d);
238 129 100       216 next if $arm >= $arms_count;
239 107         134 my $odd = ($arm & 1);
240 107 100       143 if ($odd) {
241 26         37 @$ndigits = (map {2-$_} @$ndigits);
  104         144  
242             ### flip to: $ndigits
243             }
244 107         199 push @n_list,
245             (digit_join_lowtohigh($ndigits, 3, $zero) + $odd) * $arms_count + $arm;
246             }
247              
248             ### @n_list
249 43         120 return sort {$a<=>$b} @n_list;
  83         166  
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 129     129   183 my ($x,$y, $d) = @_;
260 129         149 my @ndigits;
261             my $arm;
262 129         132 for (;;) {
263             ### at: "$x,$y d=$d"
264 1075 100 100     1020 if ($x==0 && $y==0) { $arm = 2*$d; last; }
  82         98  
  82         98  
265 993 100 100     885 if ($d==0 && $x==-2 && $y==0) { $arm = 3; last; }
  6   100     7  
  6         8  
266 987 100 100     913 if ($d==2 && $x==1 && $y==1) { $arm = 1; last; }
  23   100     28  
  23         27  
267 964 100 100     941 if ($d==1 && $x==1 && $y==-1) { $arm = 5; last; }
  18   100     26  
  18         22  
268              
269 946         547 my $digit = $x_to_digit[$x%3];
270 946         549 push @ndigits, $digit;
271              
272 946 100       649 if ($digit == 1) { $d = ($d-1) % 3; }
  212         243  
273 946         541 $x -= $digit_to_x[$d]->[$digit];
274 946         528 $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 946         3071 ($x,$y) = (($x+$y)/2, # divide b = w6+1
284             ($y-$x/3)/2);
285             }
286             ### $arm
287             ### @ndigits
288 129         214 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 2182 my ($self, $x1,$y1, $x2,$y2) = @_;
323             ### TerdragonCurve rect_to_n_range(): "$x1,$y1 $x2,$y2"
324 31         83 my $xmax = int(max(abs($x1),abs($x2)));
325 31         55 my $ymax = int(max(abs($y1),abs($y2)));
326             return (0,
327             ($xmax*$xmax + 3*$ymax*$ymax + 1)
328             * 2
329 31         82 * $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 13600 my ($self, $n) = @_;
339             ### n_to_dxdy(): $n
340              
341 1000 50       1389 if ($n < 0) {
342 0         0 return; # first direction at N=0
343             }
344 1000 50       1434 if (is_infinite($n)) {
345 0         0 return ($n,$n);
346             }
347              
348 1000         1410 my $int = int($n); # integer part
349 1000         1065 $n -= $int; # fraction part
350              
351             # initial direction from arm
352 1000         1588 my $dir6 = _divrem_mutate ($int, $self->{'arms'});
353              
354 1000         1555 my @ndigits = digit_split_lowtohigh($int,3);
355 1000         1305 $dir6 += 2 * scalar(grep {$_==1} @ndigits); # count 1s for total turn
  5278         7287  
356 1000         1204 $dir6 %= 6;
357 1000         1176 my $dx = $dir6_to_dx[$dir6];
358 1000         1597 my $dy = $dir6_to_dy[$dir6];
359              
360 1000 50       1427 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         1850 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 4449 my ($self, $level) = @_;
380 6         18 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__