File Coverage

blib/lib/Math/Vector/Real/Polyline.pm
Criterion Covered Total %
statement 12 86 13.9
branch 0 24 0.0
condition 0 6 0.0
subroutine 4 12 33.3
pod 4 6 66.6
total 20 134 14.9


line stmt bran cond sub pod time code
1             package Math::Vector::Real::Polyline;
2              
3             our $VERSION = '0.01';
4              
5 1     1   74496 use strict;
  1         4  
  1         41  
6 1     1   8 use warnings;
  1         3  
  1         41  
7              
8 1     1   996 use Math::Vector::Real;
  1         17741  
  1         120  
9              
10             our $debug = 0;
11              
12             sub as_string;
13 1     1   13 use overload '""' => \&as_string;
  1         2  
  1         6  
14              
15             sub new {
16 0     0 1   my $class = shift;
17 0           my $self = [map V(@$_), @_];
18 0           bless $self, $class;
19             }
20              
21             sub dist2_to_point {
22 0     0 1   my $self = shift;
23 0           my $p = V(shift);
24 0 0         return unless @$self;
25 0           my $min_d2 = $self->[0]->dist2($p);
26              
27 0           for my $i (1..$#$self) {
28 0           my $d2 = $p->dist2_to_segment($self->[$i-1], $self->[$i]);
29 0 0         $min_d2 = $d2 if $d2 < $min_d2;
30             }
31              
32 0           $min_d2;
33             }
34              
35             sub dist2_to_segment {
36 0     0 1   my ($self, $a, $b) = @_;
37 0           my $min_d2 = $self->[0]->dist2($a);
38 0           for my $i (1..$#$self) {
39 0           my $d2 = Math::Vector::Real->dist2_between_segments($a, $b,
40             $self->[$i - 1], $self->[$i]);
41 0 0         $min_d2 = $d2 if $d2 < $min_d2;
42             }
43 0           $min_d2;
44             }
45              
46             sub _dist2_to_polyline_brute_force {
47 0     0     my ($self, $other, $min_d2) = @_;
48              
49 0           for my $i (1..$#$self) {
50 0           my $s0 = $self->[$i - 1];
51 0           my $s1 = $self->[$i];
52 0           for my $j (1..$#$other) {
53 0           my $d2 = Math::Vector::Real->dist2_between_segments($s0, $s1,
54             $other->[$j-1], $other->[$j]);
55 0 0         $min_d2 = $d2 if $d2 < $min_d2;
56             }
57             }
58 0           $min_d2;
59             }
60              
61             my $cutoff = 5;
62              
63             sub _dump_queue {
64 0     0     my $min_d2 = shift;
65 0           printf "Queue size: %d, min_d2: %f\n", scalar(@_), $min_d2;
66 0           for (@_) {
67 0           my $a = Math::Vector::Real::Polyline->new(@{$_->[0]});
  0            
68 0           my $b = Math::Vector::Real::Polyline->new(@{$_->[1]});
  0            
69 0           my $d2 = $_->[2];
70 0           print " a: $a b: $b d2: $d2\n";
71             }
72             }
73              
74             sub dist2_to_polyline {
75 0     0 1   my $self = shift;
76 0           my $other = shift;
77 0 0 0       return unless @$self and @$other;
78 0 0         return $other->dist2_to_point($self->[0]) if @$self == 1;
79 0 0         return $self->dist2_to_point($other->[0]) if @$other == 1;
80              
81 0           my $min_d2 = $self->[0]->dist2($other->[0]);
82 0           my @queue = [$self, $other, 0];
83              
84 0           while (@queue) {
85 0 0         $debug and _dump_queue($min_d2, @queue);
86 0           my ($a, $b, $bb_d2) = @{pop @queue};
  0            
87 0 0         last if $bb_d2 >= $min_d2;
88              
89 0 0 0       if (@$a <= $cutoff or @$b <= $cutoff) {
90 0           $min_d2 = _dist2_to_polyline_brute_force($a, $b, $min_d2);
91             }
92             else {
93 0           my $a_half = int(@$a / 2);
94 0           my $a0 = [@{$a}[0..$a_half]];
  0            
95 0           my $a1 = [@{$a}[$a_half..$#$a]];
  0            
96 0           my $b_half = int(@$b / 2);
97 0           my $b0 = [@{$b}[0..$b_half]];
  0            
98 0           my $b1 = [@{$b}[$b_half..$#$b]];
  0            
99 0           for my $pair ([$a0, $b0], [$a0, $b1], [$a1, $b0], [$a1, $b1]) {
100 0           my $bb_d2 = Math::Vector::Real->dist2_between_boxes(Math::Vector::Real->box(@{$pair->[0]}),
101 0           Math::Vector::Real->box(@{$pair->[1]}));
  0            
102 0 0         next if $bb_d2 > $min_d2;
103 0           $pair->[2] = $bb_d2;
104 0           my $i;
105              
106 0           for ($i = $#queue; $i >= 0; $i--) {
107 0           my $pivot = $queue[$i];
108 0 0         last if $bb_d2 <= $pivot->[2];
109 0           $queue[$i + 1] = $pivot
110             }
111 0           $queue[$i + 1] = $pair;
112             }
113             }
114             }
115 0           return $min_d2;
116             }
117              
118 0     0 0   sub dist_to_polyline { sqrt(&dist2_to_polyline) }
119              
120             sub as_string {
121 0     0 0   my $self = shift;
122 0           return '['.join('-', @$self).']';
123             }
124              
125             1;
126             __END__