| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Math::Geometry::IntersectionArea; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '0.01'; |
|
4
|
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
20520
|
use strict; |
|
|
1
|
|
|
|
|
1
|
|
|
|
1
|
|
|
|
|
39
|
|
|
6
|
1
|
|
|
1
|
|
6
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
28
|
|
|
7
|
1
|
|
|
1
|
|
6
|
use Carp; |
|
|
1
|
|
|
|
|
6
|
|
|
|
1
|
|
|
|
|
300
|
|
|
8
|
1
|
|
|
1
|
|
35
|
use 5.010; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
97
|
|
|
9
|
1
|
|
|
1
|
|
1138
|
use Math::Vector::Real; |
|
|
1
|
|
|
|
|
34193
|
|
|
|
1
|
|
|
|
|
711
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
require Exporter; |
|
12
|
|
|
|
|
|
|
our @ISA = qw(Exporter); |
|
13
|
|
|
|
|
|
|
our @EXPORT_OK = qw(intersection_area_circle_rectangle |
|
14
|
|
|
|
|
|
|
intersection_area_circle_polygon); |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
sub _ia2_circle_segment { # ia2 = intersection area * 2 |
|
17
|
0
|
|
|
0
|
|
|
my ($r2, $a, $b) = @_; |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
# finds the oriented area of the intersection of the circle of |
|
20
|
|
|
|
|
|
|
# radius sqrt(r2) centered on the origin O and the |
|
21
|
|
|
|
|
|
|
# triangle(O,a,b). |
|
22
|
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# Cases: |
|
24
|
|
|
|
|
|
|
# |
|
25
|
|
|
|
|
|
|
# 0: /-----\ |
|
26
|
|
|
|
|
|
|
# / \ |
|
27
|
|
|
|
|
|
|
# | x---x | |
|
28
|
|
|
|
|
|
|
# |
|
29
|
|
|
|
|
|
|
# |
|
30
|
|
|
|
|
|
|
# 1: /-----\ |
|
31
|
|
|
|
|
|
|
# / \ x---x |
|
32
|
|
|
|
|
|
|
# | | |
|
33
|
|
|
|
|
|
|
# |
|
34
|
|
|
|
|
|
|
# |
|
35
|
|
|
|
|
|
|
# 2: /-----\ |
|
36
|
|
|
|
|
|
|
# x---x / \ |
|
37
|
|
|
|
|
|
|
# | | |
|
38
|
|
|
|
|
|
|
# |
|
39
|
|
|
|
|
|
|
# |
|
40
|
|
|
|
|
|
|
# 3: x---x |
|
41
|
|
|
|
|
|
|
# |
|
42
|
|
|
|
|
|
|
# /-----\ |
|
43
|
|
|
|
|
|
|
# |
|
44
|
|
|
|
|
|
|
# |
|
45
|
|
|
|
|
|
|
# 4: /-----\ |
|
46
|
|
|
|
|
|
|
# / \ |
|
47
|
|
|
|
|
|
|
# x-|-------|-x |
|
48
|
|
|
|
|
|
|
# |
|
49
|
|
|
|
|
|
|
# |
|
50
|
|
|
|
|
|
|
# 5: /-----\ |
|
51
|
|
|
|
|
|
|
# / \ |
|
52
|
|
|
|
|
|
|
# x-|---x | |
|
53
|
|
|
|
|
|
|
# |
|
54
|
|
|
|
|
|
|
# |
|
55
|
|
|
|
|
|
|
# 6: /-----\ |
|
56
|
|
|
|
|
|
|
# / \ |
|
57
|
|
|
|
|
|
|
# | x---|-x |
|
58
|
|
|
|
|
|
|
# |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
# The two points where the segment intersects the circle are found |
|
61
|
|
|
|
|
|
|
# solving the following cuadratic equation: |
|
62
|
|
|
|
|
|
|
# |
|
63
|
|
|
|
|
|
|
# norm(a + alfa * ab) = d |
|
64
|
|
|
|
|
|
|
# |
|
65
|
|
|
|
|
|
|
# |
|
66
|
|
|
|
|
|
|
# The coeficientes c2, c1, c0 are deduced from the formula |
|
67
|
|
|
|
|
|
|
# above such that: |
|
68
|
|
|
|
|
|
|
# |
|
69
|
|
|
|
|
|
|
# c2 * alfa**2 + 2 * c1 * alfa + c0 = 0 |
|
70
|
|
|
|
|
|
|
# |
|
71
|
|
|
|
|
|
|
# And then the clasical formula for quadratic equation solved is |
|
72
|
|
|
|
|
|
|
# used: |
|
73
|
|
|
|
|
|
|
# |
|
74
|
|
|
|
|
|
|
# alfa0 = 1/c2 + (-$c1 + sqrt($c1*$c1 - 4 * $c0 * $c2)) |
|
75
|
|
|
|
|
|
|
# alfa1 = 1/c2 + (-$c1 - sqrt($c1*$c1 - 4 * $c0 * $c2)) |
|
76
|
|
|
|
|
|
|
|
|
77
|
0
|
|
|
|
|
|
my $ab = $b - $a; |
|
78
|
0
|
0
|
|
|
|
|
my $c2 = $ab->norm2 or return 0; # a and b are the same point |
|
79
|
0
|
|
|
|
|
|
my $c1 = $a * $ab; |
|
80
|
0
|
|
|
|
|
|
my $c0 = $a->norm2 - $r2; |
|
81
|
0
|
|
|
|
|
|
my $discriminant = $c1 * $c1 - $c0 * $c2; |
|
82
|
0
|
0
|
|
|
|
|
if ($discriminant > 0) { # otherwise case 3 |
|
83
|
0
|
|
|
|
|
|
my $inv_c2 = 1/$c2; |
|
84
|
0
|
|
|
|
|
|
my $sqrt_discriminant = sqrt($discriminant); |
|
85
|
0
|
|
|
|
|
|
my $alfa0 = $inv_c2 * (-$c1 - $sqrt_discriminant); |
|
86
|
0
|
|
|
|
|
|
my $alfa1 = $inv_c2 * (-$c1 + $sqrt_discriminant); |
|
87
|
0
|
0
|
0
|
|
|
|
if ($alfa0 < 1 and $alfa1 > 0) { # otherwise cases 1 and 2 |
|
88
|
|
|
|
|
|
|
# cases 0, 4, 5 and 6 |
|
89
|
0
|
|
|
|
|
|
my $beta = 0; |
|
90
|
0
|
|
|
|
|
|
my ($p0, $p1); |
|
91
|
0
|
0
|
|
|
|
|
if ($alfa0 > 0) { |
|
92
|
0
|
|
|
|
|
|
$p0 = $a + $alfa0 * $ab; |
|
93
|
0
|
|
|
|
|
|
$beta += atan2($a, $p0); |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
else { |
|
96
|
0
|
|
|
|
|
|
$p0 = $a; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
0
|
0
|
|
|
|
|
if ($alfa1 <= 1) { |
|
99
|
0
|
|
|
|
|
|
$p1 = $a + $alfa1 * $ab; |
|
100
|
0
|
|
|
|
|
|
$beta += atan2($p1, $b); |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
else { |
|
103
|
0
|
|
|
|
|
|
$p1 = $b; |
|
104
|
|
|
|
|
|
|
} |
|
105
|
0
|
|
|
|
|
|
return $p0->[0] * $p1->[1] - $p0->[1] * $p1->[0] + $beta * $r2; |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
} |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
# else the sector is fully contained inside the triangle (cases 1, 2 and 3) |
|
110
|
0
|
|
|
|
|
|
return atan2($a, $b) * $r2 |
|
111
|
|
|
|
|
|
|
} |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
sub intersection_area_circle_rectangle { |
|
114
|
0
|
0
|
|
0
|
0
|
|
@_ == 4 or croak 'Usage: intersection_area_circle_rectangle($o, $r, $v0, $v1)'; |
|
115
|
0
|
|
|
|
|
|
my $O = V(@{shift()}); # accept plain array refs as vectors |
|
|
0
|
|
|
|
|
|
|
|
116
|
0
|
|
|
|
|
|
my $r = shift; |
|
117
|
0
|
|
|
|
|
|
my ($a, $c) = Math::Vector::Real->box($_[0] - $O, $_[1] - $O); |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# fast check: |
|
120
|
0
|
0
|
0
|
|
|
|
return 0 if ($a->[0] >= $r or $c->[0] <= -$r or |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
121
|
|
|
|
|
|
|
$a->[1] >= $r or $c->[1] <= -$r); |
|
122
|
|
|
|
|
|
|
|
|
123
|
0
|
|
|
|
|
|
my $b = V($a->[0], $c->[1]); |
|
124
|
0
|
|
|
|
|
|
my $d = V($c->[0], $a->[1]); |
|
125
|
0
|
|
|
|
|
|
my $r2 = $r * $r; |
|
126
|
0
|
|
|
|
|
|
abs(0.5 * (_ia2_circle_segment($r2, $a, $b) + |
|
127
|
|
|
|
|
|
|
_ia2_circle_segment($r2, $b, $c) + |
|
128
|
|
|
|
|
|
|
_ia2_circle_segment($r2, $c, $d) + |
|
129
|
|
|
|
|
|
|
_ia2_circle_segment($r2, $d, $a))); |
|
130
|
|
|
|
|
|
|
} |
|
131
|
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
sub intersection_area_circle_polygon { |
|
133
|
0
|
0
|
|
0
|
1
|
|
@_ > 4 or return 0; |
|
134
|
0
|
|
|
|
|
|
my $O = V(@{shift()}); # accept plain array refs as vectors |
|
|
0
|
|
|
|
|
|
|
|
135
|
0
|
|
|
|
|
|
my $r = shift; |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# fast check: |
|
138
|
0
|
|
|
|
|
|
my ($v0, $v1) = Math::Vector::Real->box(@_); |
|
139
|
0
|
|
|
|
|
|
$v0 -= $O; |
|
140
|
0
|
|
|
|
|
|
$v1 -= $O; |
|
141
|
0
|
0
|
0
|
|
|
|
return 0 if ($v0->[0] >= $r or $v1->[0] <= -$r or |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
142
|
|
|
|
|
|
|
$v0->[1] >= $r or $v1->[1] <= -$r); |
|
143
|
|
|
|
|
|
|
|
|
144
|
0
|
|
|
|
|
|
my $A = 0; |
|
145
|
0
|
|
|
|
|
|
my $r2 = $r * $r; |
|
146
|
0
|
|
|
|
|
|
my $last = $_[-1] - $O; |
|
147
|
0
|
|
|
|
|
|
for (@_) { |
|
148
|
0
|
|
|
|
|
|
my $p = $_ - $O; |
|
149
|
0
|
|
|
|
|
|
$A += _ia2_circle_segment($r2, $last, $p); |
|
150
|
0
|
|
|
|
|
|
$last = $p; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
0
|
|
|
|
|
|
return abs(0.5 * $A); |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
1; |
|
156
|
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
__END__ |