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 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   9047 use 5.004;
  1         11  
36 1     1   5 use strict;
  1         3  
  1         43  
37 1     1   6 use List::Util 'first';
  1         2  
  1         131  
38 1     1   7 use List::Util 'min'; # 'max'
  1         2  
  1         55  
39             *max = \&Math::PlanePath::_max;
40              
41 1     1   700 use Math::PlanePath;
  1         3  
  1         47  
42             *_divrem_mutate = \&Math::PlanePath::_divrem_mutate;
43              
44             use Math::PlanePath::Base::Generic
45 1         49 'is_infinite',
46             'round_nearest',
47 1     1   6 'xy_is_even';
  1         2  
48             use Math::PlanePath::Base::Digits
49 1         62 'digit_split_lowtohigh',
50             'digit_join_lowtohigh',
51 1     1   445 'round_up_pow';
  1         2  
52              
53 1     1   6 use vars '$VERSION', '@ISA';
  1         2  
  1         70  
54             $VERSION = 127;
55             @ISA = ('Math::PlanePath');
56              
57 1     1   506 use Math::PlanePath::TerdragonMidpoint;
  1         3  
  1         33  
58              
59             # uncomment this to run the ### lines
60             # use Smart::Comments;
61              
62              
63 1     1   7 use constant n_start => 0;
  1         1  
  1         82  
64 1         205 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   7 } ];
  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         2  
  1         49  
95 1     1   6 use constant dy_minimum => -1;
  1         2  
  1         60  
96 1     1   6 use constant dy_maximum => 1;
  1         2  
  1         144  
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   7 use constant absdx_minimum => 1;
  1         2  
  1         56  
112 1     1   12 use constant dsumxy_minimum => -2; # diagonals
  1         3  
  1         45  
113 1     1   6 use constant dsumxy_maximum => 2;
  1         1  
  1         57  
114 1     1   6 use constant ddiffxy_minimum => -2;
  1         2  
  1         41  
115 1     1   5 use constant ddiffxy_maximum => 2;
  1         2  
  1         98  
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   7 use constant turn_any_straight => 0; # never straight
  1         1  
  1         2287  
128              
129              
130             #------------------------------------------------------------------------------
131              
132             sub new {
133 24     24 1 4289 my $self = shift->SUPER::new(@_);
134 24   100     145 $self->{'arms'} = max(1, min(6, $self->{'arms'} || 1));
135 24         48 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 37248 my ($self, $n) = @_;
144             ### TerdragonCurve n_to_xy(): $n
145              
146 441 50       1061 if ($n < 0) { return; }
  0         0  
147 441 50       1051 if (is_infinite($n)) { return ($n, $n); }
  0         0  
148              
149 441         816 my $zero = ($n * 0); # inherit bignum 0
150              
151 441         609 my $i = 0;
152 441         603 my $j = 0;
153 441         543 my $k = 0;
154 441         613 my $si = $zero;
155 441         590 my $sj = $zero;
156 441         606 my $sk = $zero;
157              
158             # initial rotation from arm number
159             {
160 441         571 my $int = int($n);
  441         675  
161 441         650 my $frac = $n - $int; # inherit possible BigFloat
162 441         583 $n = $int; # BigFloat int() gives BigInt, use that
163              
164 441         1096 my $rot = _divrem_mutate ($n, $self->{'arms'});
165              
166 441         692 my $s = $zero + 1; # inherit bignum 1
167 441 100       803 if ($rot >= 3) {
168 41         61 $s = -$s; # rotate 180
169 41         61 $frac = -$frac;
170 41         55 $rot -= 3;
171             }
172 441 100       815 if ($rot == 0) { $i = $frac; $si = $s; } # rotate 0
  272 100       404  
  272         453  
173 105         152 elsif ($rot == 1) { $j = $frac; $sj = $s; } # rotate +60
  105         151  
174 64         90 else { $k = $frac; $sk = $s; } # rotate +120
  64         111  
175             }
176              
177 441         1002 foreach my $digit (digit_split_lowtohigh($n,3)) {
178             ### at: "$i,$j,$k side $si,$sj,$sk"
179             ### $digit
180              
181 2596 100       4745 if ($digit == 1) {
    100          
182 1007         1862 ($i,$j,$k) = ($si-$j, $sj-$k, $sk+$i); # rotate +120 and add
183             } elsif ($digit == 2) {
184 808         1078 $i -= $sk; # add rotated +60
185 808         1033 $j += $si;
186 808         1054 $k += $sj;
187             }
188              
189             # add rotated +60
190 2596         4583 ($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         1281 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 734 return scalar((shift->xy_to_n_list(@_))[0]);
214             }
215             sub xy_to_n_list {
216 55     55 1 728 my ($self, $x,$y) = @_;
217             ### TerdragonCurve xy_to_n_list(): "$x, $y"
218              
219 55         135 $x = round_nearest($x);
220 55         113 $y = round_nearest($y);
221             {
222             # nothing at an odd point, and trap overflows in $x+$y dividing out b
223 55         92 my $sum = abs($x) + abs($y);
  55         90  
224 55 50       106 if (is_infinite($sum)) { return $sum; } # infinity
  0         0  
225 55 50       144 if ($sum % 2) { return; }
  0         0  
226             }
227              
228 55 100 100     143 if ($x==0 && $y==0) {
229 12         48 return 0 .. $self->{'arms'}-1;
230             }
231              
232 43         112 my $arms_count = $self->arms_count;
233 43         75 my $zero = ($x * 0 * $y); # inherit bignum 0
234              
235 43         59 my @n_list;
236 43         76 foreach my $d (0,1,2) {
237 129         268 my ($ndigits,$arm) = _xy_d_to_ndigits_and_arm($x,$y,$d);
238 129 100       268 next if $arm >= $arms_count;
239 105         167 my $odd = ($arm & 1);
240 105 100       171 if ($odd) {
241 17         36 @$ndigits = (map {2-$_} @$ndigits);
  22         46  
242             ### flip to: $ndigits
243             }
244 105         220 push @n_list,
245             (digit_join_lowtohigh($ndigits, 3, $zero) + $odd) * $arms_count + $arm;
246             }
247              
248             ### @n_list
249 43         219 return sort {$a<=>$b} @n_list;
  80         192  
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   207 my ($x,$y, $d) = @_;
260 129         184 my @ndigits;
261             my $arm;
262 129         166 for (;;) {
263             ### at: "$x,$y d=$d"
264 939 100 100     1120 if ($x==0 && $y==0) { $arm = 2*$d; last; }
  89         124  
  89         134  
265 850 100 100     967 if ($d==0 && $x==-2 && $y==0) { $arm = 3; last; }
  4   100     7  
  4         7  
266 846 100 100     967 if ($d==2 && $x==1 && $y==1) { $arm = 1; last; }
  16   100     22  
  16         26  
267 830 100 100     1066 if ($d==1 && $x==1 && $y==-1) { $arm = 5; last; }
  20   100     26  
  20         33  
268              
269 810         612 my $digit = $x_to_digit[$x%3];
270 810         588 push @ndigits, $digit;
271              
272 810 100       705 if ($digit == 1) { $d = ($d-1) % 3; }
  192         268  
273 810         582 $x -= $digit_to_x[$d]->[$digit];
274 810         575 $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 810         3252 ($x,$y) = (($x+$y)/2, # divide b = w6+1
284             ($y-$x/3)/2);
285             }
286             ### $arm
287             ### @ndigits
288 129         265 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 2738 my ($self, $x1,$y1, $x2,$y2) = @_;
323             ### TerdragonCurve rect_to_n_range(): "$x1,$y1 $x2,$y2"
324 31         100 my $xmax = int(max(abs($x1),abs($x2)));
325 31         71 my $ymax = int(max(abs($y1),abs($y2)));
326             return (0,
327             ($xmax*$xmax + 3*$ymax*$ymax + 1)
328             * 2
329 31         105 * $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 16306 my ($self, $n) = @_;
339             ### n_to_dxdy(): $n
340              
341 1000 50       1790 if ($n < 0) {
342 0         0 return; # first direction at N=0
343             }
344 1000 50       1822 if (is_infinite($n)) {
345 0         0 return ($n,$n);
346             }
347              
348 1000         1704 my $int = int($n); # integer part
349 1000         1312 $n -= $int; # fraction part
350              
351             # initial direction from arm
352 1000         1958 my $dir6 = _divrem_mutate ($int, $self->{'arms'});
353              
354 1000         1909 my @ndigits = digit_split_lowtohigh($int,3);
355 1000         1645 $dir6 += 2 * scalar(grep {$_==1} @ndigits); # count 1s for total turn
  5278         9013  
356 1000         1474 $dir6 %= 6;
357 1000         1425 my $dx = $dir6_to_dx[$dir6];
358 1000         1301 my $dy = $dir6_to_dy[$dir6];
359              
360 1000 50       1688 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         2201 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 403 my ($self, $level) = @_;
380 6         22 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__