File Coverage

blib/lib/Path/Hilbert.pm
Criterion Covered Total %
statement 86 89 96.6
branch 5 6 83.3
condition n/a
subroutine 18 19 94.7
pod 3 3 100.0
total 112 117 95.7


line stmt bran cond sub pod time code
1             package Path::Hilbert;
2              
3 2     2   663 use strict;
  2         2  
  2         59  
4 2     2   6 use warnings;
  2         2  
  2         43  
5 2     2   40 use 5.012;
  2         7  
  2         47  
6 2     2   1069 use utf8;
  2         16  
  2         7  
7              
8 2     2   68 use Exporter qw( import );
  2         3  
  2         253  
9              
10             our @EXPORT = qw( xy2d d2xy );
11              
12             our $VERSION = '1.204';
13              
14             # optional constructor if you want OO-style
15             sub new {
16 0     0 1 0 my $class = shift;
17 0         0 my ($n) = @_;
18 0         0 return bless { n => $n } => $class;
19             }
20              
21             # convert (x,y) to d
22             sub xy2d {
23 1360     1360 1 3466 my ($side, $x, $y) = @_;
24 1360         1493 my $n = _valid_n($side);
25 1360         1392 my ($X, $Y) = map { int($_ + 0.5) } ($x, $y);
  2720         3445  
26 1360         1142 my $D;
27             {
28 2     2   942 use integer;
  2         16  
  2         7  
  1360         1067  
29 1360         1169 my $d = 0;
30 1360         1311 my ($x, $y) = map { int($_) } ($X, $Y);
  2720         2650  
31 1360         2450 for (my $s = $n / 2; $s > 0; $s /= 2) {
32 19720         16953 my $rx = ($x & $s) > 0;
33 19720         13942 my $ry = ($y & $s) > 0;
34 19720         16881 $d += $s * $s * ((3 * $rx) ^ $ry);
35 19720         21775 ($x, $y) = _rot($s, $x, $y, $rx, $ry);
36             }
37 2     2   195 no integer;
  2         2  
  2         8  
38 1360         1526 $D = $d;
39             }
40 1360         1617 return $D * _side_scale($side);
41             }
42              
43             # convert d to (x,y)
44             sub d2xy {
45 4080     4080 1 3189881 my ($side, $d) = @_;
46 4080         8903 my $n = _valid_n($side);
47 4080         6031 my $T = int($d + 0.5);
48 4080         4346 my ($X, $Y);
49             {
50 2     2   208 use integer;
  2         2  
  2         5  
  4080         3498  
51 4080         5372 my ($x, $y) = (0, 0);
52 4080         4601 my $t = int($T);
53 4080         10295 for (my $s = 1; $s < $n; $s *= 2) {
54 59160         49152 my $rx = 1 & ($t / 2);
55 59160         49237 my $ry = 1 & ($t ^ $rx);
56 59160         69060 ($x, $y) = _rot($s, $x, $y, $rx, $ry);
57 59160         51006 $x += $s * $rx;
58 59160         41795 $y += $s * $ry;
59 59160         94346 $t /= 4;
60             }
61 2     2   171 no integer;
  2         4  
  2         6  
62 4080         5424 ($X, $Y) = ($x, $y);
63             }
64 4080         4157 return map { _side_scale($side) * $_ } ($X, $Y);
  8160         10909  
65             }
66              
67             # rotate/flip a quadrant appropriately
68             sub _rot {
69 2     2   137 use integer;
  2         3  
  2         4  
70 78880     78880   70778 my ($n, $x, $y, $rx, $ry) = map { int($_) } @_;
  394400         346824  
71 78880 100       113061 if (!$ry) {
72 72268 100       95457 if ($rx) {
73 2448         2452 $x = $n - 1 - $x;
74 2448         2570 $y = $n - 1 - $y;
75             }
76 72268         65147 ($x, $y) = ($y, $x);
77             }
78 78880         106484 return ($x, $y);
79             }
80              
81             sub _valid_n {
82 14960     14960   19633 my $n = _extract_side(shift(@_));
83 2     2   204 no integer;
  2         3  
  2         5  
84 14960         29107 my $rv = 2 ** int((log($n) / log(2)) + 0.5);
85 2     2   79 use integer;
  2         2  
  2         5  
86 14960         17326 return int($rv);
87             }
88              
89             sub _extract_side {
90 24480     24480   20079 my ($n) = @_;
91 24480 50       34798 $n = $n->{ n } if ref($n);
92 24480         24287 return $n;
93             }
94              
95             sub _side_scale {
96 9520     9520   13056 my $side = _extract_side(shift(@_));
97 9520         11511 my $n = _valid_n($side);
98 9520         22055 return $side / $n;
99             }
100              
101             1;
102              
103             __END__