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__ |