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   613 use strict;
  2         2  
  2         66  
4 2     2   11 use warnings;
  2         2  
  2         53  
5 2     2   43 use 5.012;
  2         7  
  2         136  
6 2     2   1098 use utf8;
  2         16  
  2         7  
7              
8 2     2   67 use Exporter qw( import );
  2         3  
  2         250  
9              
10             our @EXPORT = qw( xy2d d2xy );
11              
12             our $VERSION = '1.203';
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 3376 my ($side, $x, $y) = @_;
24 1360         1475 my $n = _valid_n($side);
25 1360         1561 my ($X, $Y) = map { int($_ + 0.5) } ($x, $y);
  2720         3241  
26 1360         1171 my $D;
27             {
28 2     2   918 use integer;
  2         16  
  2         7  
  1360         1024  
29 1360         1146 my $d = 0;
30 1360         1311 my ($x, $y) = map { int($_) } ($X, $Y);
  2720         2633  
31 1360         2439 for (my $s = $n / 2; $s > 0; $s /= 2) {
32 19720         17414 my $rx = ($x & $s) > 0;
33 19720         14325 my $ry = ($y & $s) > 0;
34 19720         17758 $d += $s * $s * ((3 * $rx) ^ $ry);
35 19720         22067 ($x, $y) = _rot($s, $x, $y, $rx, $ry);
36             }
37 2     2   194 no integer;
  2         3  
  2         6  
38 1360         1540 $D = $d;
39             }
40 1360         1792 return $D * _side_scale($side);
41             }
42              
43             # convert d to (x,y)
44             sub d2xy {
45 4080     4080 1 2989479 my ($side, $d) = @_;
46 4080         8657 my $n = _valid_n($side);
47 4080         6603 my $T = int($d + 0.5);
48 4080         3758 my ($X, $Y);
49             {
50 2     2   256 use integer;
  2         2  
  2         7  
  4080         3996  
51 4080         5771 my ($x, $y) = (0, 0);
52 4080         4224 my $t = int($T);
53 4080         9892 for (my $s = 1; $s < $n; $s *= 2) {
54 59160         51722 my $rx = 1 & ($t / 2);
55 59160         47203 my $ry = 1 & ($t ^ $rx);
56 59160         71091 ($x, $y) = _rot($s, $x, $y, $rx, $ry);
57 59160         50774 $x += $s * $rx;
58 59160         40750 $y += $s * $ry;
59 59160         92501 $t /= 4;
60             }
61 2     2   230 no integer;
  2         6  
  2         8  
62 4080         5908 ($X, $Y) = ($x, $y);
63             }
64 4080         4051 return map { _side_scale($side) * $_ } ($X, $Y);
  8160         11115  
65             }
66              
67             # rotate/flip a quadrant appropriately
68             sub _rot {
69 2     2   141 use integer;
  2         3  
  2         5  
70 78880     78880   72438 my ($n, $x, $y, $rx, $ry) = map { int($_) } @_;
  394400         349441  
71 78880 100       117253 if (!$ry) {
72 72268 100       95563 if ($rx) {
73 2448         2906 $x = $n - 1 - $x;
74 2448         2659 $y = $n - 1 - $y;
75             }
76 72268         68499 ($x, $y) = ($y, $x);
77             }
78 78880         110365 return ($x, $y);
79             }
80              
81             sub _valid_n {
82 14960     14960   19789 my $n = _extract_side(shift(@_));
83 2     2   236 no integer;
  2         2  
  2         5  
84 14960         28668 my $rv = 2 ** int((log($n) / log(2)) + 0.5);
85 2     2   81 use integer;
  2         2  
  2         5  
86 14960         16846 return int($rv);
87             }
88              
89             sub _extract_side {
90 24480     24480   20932 my ($n) = @_;
91 24480 50       35503 $n = $n->{ n } if ref($n);
92 24480         25479 return $n;
93             }
94              
95             sub _side_scale {
96 9520     9520   12032 my $side = _extract_side(shift(@_));
97 9520         11832 my $n = _valid_n($side);
98 9520         22623 return $side / $n;
99             }
100              
101             1;
102              
103             __END__