File Coverage

blib/lib/Math/Intersection/Circle/Line.pm
Criterion Covered Total %
statement 261 262 99.6
branch 95 146 65.0
condition 118 186 63.4
subroutine 76 76 100.0
pod 31 35 88.5
total 581 705 82.4


line stmt bran cond sub pod time code
1             =pod
2              
3             =encoding utf8
4              
5             =head1 Name
6              
7             Math::Intersection::Circle::Line - Find the points at which circles and lines
8             intersect to test geometric intuition.
9              
10             =head1 Synopsis
11              
12             use Math::Intersection::Circle::Line q(:all);
13             use Test::More q(no_plan);
14             use utf8;
15              
16             # Euler Line, see: L
17              
18             if (1)
19             {my @t = (0, 0, 4, 0, 0, 3); # Corners of the triangle
20             &areaOfPolygon(sub {ok !$_[0]}, # Polygon formed by these points has zero area and so is a line or a point
21             &circumCircle (sub {@_[0,1]}, @t), # green
22             &ninePointCircle(sub {@_[0,1]}, @t), # red
23             &orthoCentre (sub {@_[0,1]}, @t), # blue
24             ¢roid (sub {@_[0,1]}, @t)); # orange
25             }
26              
27             # An isosceles tringle with an apex height of 3/4 of the radius of its
28             # circumcircle divides Euler's line into 6 equal pieces
29              
30             if (1)
31             {my $r = 400; # Arbitrary but convenient radius
32             intersectionCircleLine # Find coordinates of equiangles of isoceles triangle
33             {my ($x, $y, $𝕩, $𝕪) = @_; # Coordinates of equiangles
34             my ($𝘅, $𝘆) = (0, $r); # Coordinates of apex
35             my ($nx, $ny, $nr) = ninePointCircle {@_} $x, $y, $𝘅, $𝘆, $𝕩, $𝕪; # Coordinates of centre and radius of nine point circle
36             my ($cx, $cy) = centroid {@_} $x, $y, $𝘅, $𝘆, $𝕩, $𝕪; # Coordinates of centroid
37             my ($ox, $oy) = orthoCentre {@_} $x, $y, $𝘅, $𝘆, $𝕩, $𝕪; # Coordinates of orthocentre
38             ok near(100, $y); # Circumcentre to base of triangle
39             ok near(200, $cy); # Circumcentre to lower circumference of nine point circle
40             ok near(300, $y+$nr); # Circumcentre to centre of nine point circle
41             ok near(400, $𝘆); # Circumcentre to apex of isosceles triangle
42             ok near(500, $y+2*$nr); # Circumcentre to upper circumference of nine point circle
43             ok near(600, $oy); # Circumcentre to orthocentre
44             } 0, 0, $r, 0, $r/4, 1, $r/4; # Chord at 1/4 radius
45             }
46              
47             # A line segment across a circle is never longer than the diameter
48              
49             if (1) # Random circle and random line
50             {my ($x, $y, $r, $𝘅, $𝘆, $𝕩, $𝕪) = map {rand()} 1..7;
51             intersectionCircleLine # Find intersection of a circle and a line
52             {return ok 1 unless @_ == 4; # Ignore line unless it crosses circle
53             ok &vectorLength(@_) <= 2*$r; # Length if line segment is less than or equal to that of a diameter
54             } $x, $y, $r, $𝘅, $𝘆, $𝕩, $𝕪; # Circle and line to be intersected
55             }
56              
57             # The length of a side of a hexagon is the radius of a circle inscribed through
58             # its vertices
59              
60             if (1)
61             {my ($x, $y, $r) = map {rand()} 1..3; # Random circle
62             my @p = intersectionCircles {@_} $x, $y, $r, $x+$r, $y, $r; # First step of one radius
63             my @𝗽 = intersectionCircles {@_} $x, $y, $r, $p[0], $p[1], $r; # Second step of one radius
64             my @q = !&near($x+$r, $y, @𝗽[0,1]) ? @𝗽[0,1] : @𝗽[2,3]; # Away from start point
65             my @𝗾 = intersectionCircles {@_} $x, $y, $r, $q[0], $q[1], $r; # Third step of one radius
66             ok &near2(@𝗾[0,1], $x-$r, $y) or # Brings us to a point
67             &near2(@𝗾[2,3], $x-$r, $y); # opposite to the start point
68             }
69              
70             # Circle through three points chosen at random has the same centre regardless of
71             # the pairing of the points
72              
73             sub circleThrough3
74             {my ($x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Three points
75             &intersectionLines
76             (sub # Intersection of bisectors is the centre of the circle
77             {my @r =(&vectorLength(@_, $x, $y), # Radii from centre of circle to each point
78             &vectorLength(@_, $𝘅, $𝘆),
79             &vectorLength(@_, $𝕩, $𝕪));
80             ok &near(@r[0,1]); # Check radii are equal
81             ok &near(@r[1,2]);
82             @_ # Return centre
83             }, rotate90AroundMidPoint($x, $y, $𝘅, $𝘆), # Bisectors between pairs of points
84             rotate90AroundMidPoint($𝕩, $𝕪, $𝘅, $𝘆));
85             }
86              
87             if (1)
88             {my (@points) = map {rand()} 1..6; # Three points chosen at random
89             ok &near2(circleThrough3(@points), circleThrough3(@points[2..5, 0..1])); # Circle has same centre regardless
90             ok &near2(circleThrough3(@points), circleThrough3(@points[4..5, 0..3])); # of the pairing of the points
91             }
92              
93             =cut
94             package Math::Intersection::Circle::Line;
95             #-------------------------------------------------------------------------------
96             # Locate the points at which lines and circles cross in two dimensions
97             # Philip R Brenan at gmail dot com, Appa Apps Ltd, 2016, http://www.appaapps.com
98             #-------------------------------------------------------------------------------
99              
100 1     1   897 use v5.18;
  1         4  
101 1     1   5 use warnings FATAL => qw(all);
  1         1  
  1         45  
102 1     1   5 use strict;
  1         4  
  1         21  
103 1     1   855 use utf8;
  1         10  
  1         5  
104 1     1   27 use Carp;
  1         1  
  1         40058  
105              
106             #-------------------------------------------------------------------------------
107             # Our definition of nearness
108             #-------------------------------------------------------------------------------
109              
110             our $near = 1e-6; # Define nearness
111              
112 14059   100 14059 1 69454 sub near($;$) {return abs(($_[1]//0) - $_[0]) < $near} # Values this close are considered identical
113              
114             sub near2($$;$$) # Check that we are near enough
115 172     172 1 51477 {my ($a, $b, $A, $B) = @_;
116 172 100 100     516 near($A//0, $a) &&
      100        
117             near($B//0, $b)
118             }
119              
120             sub near3($$$;$$$) # Check that we are near enough
121 6     6 1 24 {my ($a, $b, $c, $A, $B, $C) = @_;
122 6 50 100     20 near($A//0, $a) &&
      100        
      100        
      33        
123             near($B//0, $b) &&
124             near($C//0, $c)
125             }
126              
127             sub near4($$$$;$$$$) # Check that we are near enough
128 21     21 1 92 {my ($a, $b, $c, $d, $A, $B, $C, $D) = @_;
129 21 50 100     63 near($A//0, $a) &&
      100        
      100        
      33        
      100        
      33        
130             near($B//0, $b) &&
131             near($C//0, $c) &&
132             near($D//0, $d)
133             }
134              
135             #-------------------------------------------------------------------------------
136             # Trigonometric functions
137             #-------------------------------------------------------------------------------
138              
139 134     134 0 36672 sub 𝝿 {4*atan2(1,1)} # Pi
140 6     6 1 8 sub acos($) {my ($a) = @_; atan2(sqrt(1 - $a**2), $a)} # acos
  6         21  
141              
142             #-------------------------------------------------------------------------------
143             # Length of a vector
144             #-------------------------------------------------------------------------------
145              
146             sub vectorSquaredLength($$;$$) # Length of a vector or distance between two vectors squared - useful for finding out which is longest without having to take a square root
147 5715     5715 0 8330 {my ($x, $y, $𝘅, $𝘆) = @_;
148 5715   100     25733 my $r = ($x-($𝘅//0))**2+($y-($𝘆//0))**2;
      100        
149 5715         11489 $r
150             }
151              
152 5330     5330 1 9472 sub vectorLength($$;$$) {sqrt(&vectorSquaredLength(@_))} # Length of a vector or distance between two vectors
153              
154             #-------------------------------------------------------------------------------
155             # Lengths of the sides of a polygon
156             #-------------------------------------------------------------------------------
157              
158             sub lengthsOfTheSidesOfAPolygon($$@)
159 5     5 1 12 {my ($x, $y, @vertices) = @_;
160 5 50       15 @_% 2 == 0 or confess "Odd number of coordinates!";
161 5 50       11 @_> 4 or confess "Must have at least two vertices!";
162 5         7 my @l;
163 5         7 my ($𝘅, $𝘆);
164 5         12 for(;scalar(@vertices);)
165 11         29 {($𝘅, $𝘆, @vertices) = @vertices;
166 11         21 push @l, vectorLength($x, $y, $𝘅, $𝘆);
167 11         33 ($x, $y) = ($𝘅, $𝘆)
168             }
169 5         14 push @l, vectorLength($_[-2]-$_[0], $_[-1]-$_[1]);
170             @l
171 5         17 }
172              
173             #-------------------------------------------------------------------------------
174             # Check whether three points are close to collinear by the Schwartz inequality
175             #-------------------------------------------------------------------------------
176              
177             sub threeCollinearPoints($$$$$$) # Three points to be tested
178 794     794 1 1288 {my ($x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;
179 794 50       1723 @_ == 6 or confess "Wrong number of parameters";
180 794 100 66     1424 return 1 if near($x, $𝘅) && near($y, $𝘆) or near($x, $𝕩) && near($y, $𝕪); # When two points are close the points are effectively collinear - although we should really check that all three points are not close sa this would identify either a number representation problem or a bad definition of nearness for this application
      100        
      33        
181 793         1604 my $d = vectorLength($𝘅, $𝘆, $𝕩, $𝕪);
182 793         1471 my $𝗱 = vectorLength($x, $y, $𝕩, $𝕪); # Lengths of sides opposite corners
183 793         1400 my $𝕕 = vectorLength($x, $y, $𝘅, $𝘆);
184 793 50 66     1568 return 1 if near($d, $𝗱) && near($𝕕); # Two sides equal and the other small makes the lines effectively collinear
185 793 50 66     1519 return 1 if near($d, $𝕕) && near($𝗱);
186 793 100 100     1639 return 1 if near($𝗱, $𝕕) && near($d);
187 792 100 100     1850 near($d, $𝗱+$𝕕) or near($𝗱, $𝕕+$d) or near($𝕕, $d+$𝗱) # One side is almost as long as the other two combined
188             }
189              
190             #-------------------------------------------------------------------------------
191             # Average of two vectors = coordinates of the mid point on the line between them
192             #-------------------------------------------------------------------------------
193              
194             sub midPoint($$$$)
195 219     219 1 315 {my ($x, $y, $𝘅, $𝘆) = @_;
196 219 50       472 @_ == 4 or confess "Wrong number of parameters";
197 219         576 (($x+$𝘅) / 2, ($y+$𝘆) / 2)
198             }
199              
200             #-------------------------------------------------------------------------------
201             # Rotations
202             #-------------------------------------------------------------------------------
203              
204 104     104 1 137 sub rotate90CW ($$) {my ($x, $y) = @_; (+$y, -$x)} # Clockwise
  104         228  
205 2     2 1 3 sub rotate90CCW($$) {my ($x, $y) = @_; (-$y, +$x)} # Counter clockwise
  2         11  
206              
207             sub rotate90AroundMidPoint($$$$)
208 102     102 1 158 {my ($x, $y, $𝘅, $𝘆) = @_;
209 102 50       224 @_ == 4 or confess "Wrong number of parameters";
210 102         251 my ($𝕩, $𝕪) = map {$_/2} rotate90CW($𝘅 - $x, $𝘆 - $y);
  204         402  
211 102         271 my ($X, $Y) = &midPoint(@_);
212 102         344 ($X - $𝕩, $Y - $𝕪, $X + $𝕩, $Y + $𝕪)
213             }
214              
215             #-------------------------------------------------------------------------------
216             # 𝗜ntersection of a circle A, with a circle B.
217             #
218             # 𝗞nown: coordinates of the centre and radius of each circle x, y, r, 𝘅, 𝘆, 𝗿
219             #
220             # 𝗙ind: the coordinates of the points at which the circles intersect.
221             #
222             # 𝗠ethod: Two different circles either do not intersect, or if they do, they
223             # intersect at one or two points. If they intersect at two points, the
224             # intersections are mirror images of each other in the line that connects the
225             # centres of the two circles.
226             #
227             # Let 𝗟 be the line joining the two centres with length 𝗹 = a + 𝗮 where a is the
228             # distance from (x, y) along 𝗟 to the point closest to the intersections. Then:
229             #
230             # r*r-a*a == 𝗿*𝗿-𝗮*𝗮
231             # r*r-𝗿*𝗿 == a*a-𝗮*𝗮
232             # == a*a-𝗮*𝗮 = (a+𝗮)(a-𝗮) == 𝗹*(a-𝗮) == 𝗹*(a - (𝗹 - a)) = 2*a*𝗹 - 𝗹*𝗹
233             #
234             # a == (r*r-𝗿*𝗿 + 𝗹*𝗹)/ (2*𝗹)
235             #
236             # The distance 𝗮 at right angles to 𝗟 to an intersection is sqrt(r*r-a*a)
237             #
238             # The unit vector 𝕕 == (𝕩, 𝕪) along line 𝗟 from (x,y) to (𝘅, 𝘆) is the unit in
239             # direction: (𝘅-x, 𝘆-y)
240             #
241             # The unit vectors d, 𝗱 at right angles to 𝗟 are (-𝕪, 𝕩) and (𝕪, -𝕩)
242             #-------------------------------------------------------------------------------
243              
244             sub intersectionCircles(&$$$$$$)
245 695     695 1 1561 {my ($sub, # Sub routine to process intersection
246             $x, $y, $r, # First circle centre, radius
247             $𝘅, $𝘆, $𝗿) = @_; # Second circle centre, radius
248 695 50       1482 @_ == 7 or confess "Wrong number of parameters";
249 695 100 100     1256 return &$sub("Duplicate circles!") if # Complain if the two circles are in fact the same circle within the definition of nearness
      100        
250             near($x, $𝘅) and near($y, $𝘆) and near($r, $𝗿);
251              
252 694         1406 my ($𝕏, $𝕐) = ($𝘅 - $x, $𝘆 - $y); # Vector between centres
253 694         1132 my $𝗹 = vectorLength($𝕏, $𝕐); # Distance between centres
254 694 100 100     3395 return &$sub("No intersection!") if $𝗹 > $r + $𝗿 or $𝗹 < abs($r - $𝗿); # The circles are too far apart or too close to intersect
255              
256 691         1220 my ($𝕩, $𝕪) = ($𝕏 / $𝗹, $𝕐 / $𝗹); # Unit vector between centres
257 691         1382 my $a = ($r*$r - $𝗿*$𝗿 + $𝗹*$𝗹)/ (2*$𝗹); # Length of the common side
258              
259 691 100 100     1444 return &$sub($x+$𝕩*$a, $y+$𝕪*$a) if near($𝗹, $r + $𝗿) or # The circles touch at one point if within the definition of nearness
260             near($𝗹, abs($r - $𝗿));
261              
262 685         1458 my $𝗮 = sqrt($r*$r-$a*$a);
263 685         2631 &$sub($x+$𝕩*$a-$𝕪*$𝗮, $y+$𝕪*$a+$𝕩*$𝗮, # The circles touch at two points
264             $x+$𝕩*$a+$𝕪*$𝗮, $y+$𝕪*$a-$𝕩*$𝗮);
265             }
266              
267             #-------------------------------------------------------------------------------
268             # 𝗔rea of intersection of two circles.
269             #
270             # 𝗞nown: two circles specified by ($x, $y, $r) and ($𝘅, $𝘆, $𝗿)
271             #
272             # 𝗙ind: the area of intersection expressed as a fraction of the area
273             # of the smaller circle
274             #
275             # 𝗠ethod: the area of a triangle is (base * height) / 2, the area of a slice is
276             # 𝝰𝗿𝗿/2 where 𝝰 is the angle of a slice.
277             #-------------------------------------------------------------------------------
278              
279             sub intersectionCirclesArea(&$$$$$$)
280 10     10 1 2518 {my ($sub, # Sub routine to process area
281             $x, $y, $r, # First circle centre, radius
282             $𝘅, $𝘆, $𝗿) = @_; # Second circle centre, radius
283 10 50       30 @_ == 7 or confess "Wrong number of parameters";
284 10 50       14 near($r) and confess "Radius of first circle is too small!";
285 10 50       21 near($𝗿) and confess "Radius of second circle is too small!";
286 10         25 my $l = vectorLength($𝘅 - $x, $𝘆 - $y); # Distance between centres
287 10 100       29 return &$sub(0) if $l >= $r + $𝗿; # The circles are too far apart to overlap
288 9 100       20 my $𝕣 = $r < $𝗿 ? $r : $𝗿; # Radius of smaller circle
289 9 100       27 return &$sub(1) if $l <= abs($r - $𝗿); # The larger circle overlaps the smaller circle completely
290              
291             intersectionCircles
292 6     6   10 {my ($X, $Y, $𝗫, $𝗬) = @_;
293 6         93 my $h = vectorLength($X - $𝗫, $Y - $𝗬) / 2; # Height of triangles
294 6         14 my $R = sqrt($r**2 - $h**2); # Base of triangle in first circle
295 6         11 my $𝗥 = sqrt($𝗿**2 - $h**2); # Base of triangle in second circle
296 6         38 &$sub(($r**2*atan2($h, $R) + $𝗿**2*atan2($h, $𝗥) - $h*($R+$𝗥))/(𝝿()*$𝕣**2)) # Fraction of smaller circle overlapped
297 6         32 } $x, $y, $r, $𝘅, $𝘆, $𝗿;
298             }
299              
300             #-------------------------------------------------------------------------------
301             # 𝗣osition on a line closest to a specified point
302             #
303             # 𝗞nown: two points on the line 𝗟 such that: 𝗹 = (𝘅, 𝘆), 𝕝 = (𝕩, 𝕪) and the
304             # specified point 𝗽 = (x, y).
305             #
306             # 𝗙ind 𝗰 the point on 𝗟 closest to 𝗽.
307             #
308             # 𝗠ethod: a circle with centre 𝗹 through 𝗽 will intersect a circle with centre 𝕝
309             # through 𝗽 at 𝗾. 𝗰 is then the average of 𝗽 and 𝗾.
310             #-------------------------------------------------------------------------------
311              
312             sub intersectionLinePoint(&$$$$$$)
313 796     796 1 1640 {my ($sub, # Sub routine to process intersection
314             $𝘅, $𝘆, $𝕩, $𝕪, # Two points on line 𝗹
315             $x, $y) = @_; # The point 𝗽
316 796 50       1831 @_ == 7 or confess "Wrong number of parameters";
317 796 50 66     1353 near($𝘅, $𝕩) and near($𝘆, $𝕪) and confess "Points on line are too close!"; # Line not well defined
318              
319 796 100 100     1719 return &$sub($x, $y) if near($x, $𝘅) && near($y, $𝘆) or # Point in question is near an end of the line segment
      100        
      66        
320             near($x, $𝕩) && near($y, $𝕪);
321              
322 785 100       1742 return &$sub($x, $y) if threeCollinearPoints($𝘅, $𝘆, $𝕩, $𝕪, $x, $y); # Collinear
323             # Points known not to be collinear
324 666         1937 my $𝗿 = vectorLength($𝘅 - $x, $𝘆 - $y); # Radius of first circle
325 666         1660 my $𝕣 = vectorLength($𝕩 - $x, $𝕪 - $y); # Radius of second circle
326             intersectionCircles
327 666 50   666   1532 {return &$sub(@_) if @_ == 2; # Point is on line
328 666         1134 my ($x, $y, $𝘅, $𝘆) = @_;
329 666         2024 &$sub(($x+$𝘅) / 2, ($y+$𝘆) / 2) # Average intersection of intersection points
330 666         3412 } $𝘅, $𝘆, $𝗿, $𝕩, $𝕪, $𝕣;
331             }
332              
333             sub unsignedDistanceFromLineToPoint(&$$$$$$) # Unsigned distance from point to line
334 287     287 0 545 {my ($sub, $𝘅, $𝘆, $𝕩, $𝕪, $x, $y) = @_; # Parameters are the same as for intersectionLinePoint()
335 287 50       609 @_ == 7 or confess "Wrong number of parameters";
336 287     287   1041 intersectionLinePoint {&$sub(&vectorLength($x, $y, @_))} $𝘅,$𝘆, $𝕩,$𝕪, $x,$y; # Distance from point to nearest point on line
  287         552  
337             }
338              
339             #-------------------------------------------------------------------------------
340             # 𝗜ntersection of two lines
341             #
342             # 𝗞nown: two lines l specified by two points 𝗹 = (𝘅, 𝘆), 𝕝 = (𝕩, 𝕪) and
343             # L specified by two points 𝗟 = (𝗫, 𝗬), 𝕃 = (𝕏, 𝕐)
344             # 𝗙ind 𝗰 the point where the two lines intersect else $sub is called empty
345             #
346             # 𝗠ethod: Let the closest point to point 𝗟 on line l be 𝗮 and the closest point
347             # to point 𝗮 on line L be 𝗯. L𝗮𝗯 is similar to L𝗮𝗰.
348             #-------------------------------------------------------------------------------
349              
350             sub intersectionLines(&$$$$$$$$)
351 196     196 1 4803 {my ($sub, # Sub routine to process intersection
352             $𝘅, $𝘆, $𝕩, $𝕪, # Two points on line l
353             $𝗫, $𝗬, $𝕏, $𝕐) = @_; # Two points on line L
354 196 50       463 @_ == 9 or confess "Wrong number of parameters";
355 196 50 66     385 near($𝘅, $𝕩) and near($𝘆, $𝕪) and confess "Points on first line are too close!";
356 196 50 66     410 near($𝗫, $𝕏) and near($𝗬, $𝕐) and confess "Points on second line are too close!";
357 196 100       31168 return &$sub("Parallel lines!") if # Lines are parallel if they have the same gradient
358             near(atan2($𝘆-$𝕪, $𝘅-$𝕩), atan2($𝗬-$𝕐, $𝗫-$𝕏));
359              
360             intersectionLinePoint # Find 𝗮
361 193     193   304 {my ($𝗮x, $𝗮y) = @_;
362              
363             intersectionLinePoint # Find 𝗯
364 193         344 {my ($𝗯x, $𝗯y) = @_;
365 193         468 my $La = vectorSquaredLength($𝗫 - $𝗮x, $𝗬 - $𝗮y); # Squared distance from 𝗟 to 𝗮
366 193 100       407 return &$sub($𝗫, $𝗬) if near($La); # End point of second line is on first line but the lines are not parallel
367 192         510 my $Lb = vectorSquaredLength($𝗫 - $𝗯x, $𝗬 - $𝗯y); # Squared distance from 𝗟 to 𝗯
368 192 50       395 near($Lb) and confess "Parallel lines!"; # Although this should not happen as we have already checked that the lines are not parallel
369 192         370 my $s = $La / $Lb; # Scale factor for 𝗟𝗯
370 192         767 &$sub($𝗫 + $s * ($𝗯x - $𝗫), $𝗬 + $s * ($𝗯y - $𝗬)) # Point of intersection
371 193         997 } $𝗫,$𝗬, $𝕏,$𝕐, $𝗮x,$𝗮y; # Find 𝗯 on second line
372 193         963 } $𝘅,$𝘆, $𝕩,$𝕪, $𝗫,$𝗬; # Find 𝗮 on first line
373             }
374              
375             #-------------------------------------------------------------------------------
376             # 𝗜ntersection of a circle with a line
377             #
378             # 𝗞nown: a circle specified by its centre (x, y), and radius (r)
379             # and a line that passes through points: ($𝘅, $𝘆) and ($𝕩, $𝕪).
380             #
381             # 𝗙ind: the two points at which the line crosses the circle or the single point
382             # at which the line touches the circle or report that there are no points in
383             # common.
384             #
385             # 𝗠ethod: If the line crosses the circle we can draw an isosceles triangle from
386             # the centre of the circle to the points of intersection, with the line forming
387             # the base of said triangle. The centre of the base is the closest point on the
388             # line to the centre of the circle. The line is at right angles to the line from
389             # the centre of the circle to the centre of the base.
390             #-------------------------------------------------------------------------------
391              
392             sub intersectionCircleLine(&$$$$$$$)
393 66     66 1 4535 {my ($sub, # Sub routine to process intersection
394             $x, $y, $r, # Circle centre, radius
395             $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Line goes through these two points
396 66 50       148 @_ == 8 or confess "Wrong number of parameters";
397 66 100 100     110 near($𝘅, $𝕩) and near($𝘆, $𝕪) and confess "Points on line are too close!";
398 65 100       130 if (near($r)) # Zero radius circle
399 1 50       4 {return &$sub($x, $y) if threeCollinearPoints($x, $y, $𝘅, $𝘆, $𝕩, $𝕪); # Line passes through the centre of the circle
400 0         0 confess "Radius is too small!";
401             }
402              
403             intersectionLinePoint
404 64     64   98 {my ($X, $Y) = @_; # Midpoint on line
405 64 100 100     131 if (near($x, $X) and near($y, $Y)) # Line passes through centre of circle
406 11         18 {my ($𝗫, $𝗬) = ($𝕩 - $𝘅, $𝕪 - $𝘆); # Vector along line
407 11         27 my $D = vectorLength($𝗫, $𝗬); # Length of vector along line
408 11         24 my $s = $r/$D; # Length from midpoint along line to circumference relative to length from centre to midpoint
409 11         87 return &$sub($x + $s * $𝗫, $y + $s * $𝗬, $x - $s * $𝗫, $y - $s * $𝗬); # Intersection points
410             }
411 53         118 my ($𝗫, $𝗬) = ($X - $x, $Y - $y); # Centre to midpoint
412 53         87 my $𝗗 = vectorLength($𝗫, $𝗬); # Distance to midpoint
413 53 100       139 return &$sub("No intersection!") if $𝗗 > $r; # Midpoint outside circle
414 51 100       88 return &$sub($X, $Y) if near($𝗗, $r); # Tangent
415 48         107 my $𝔻 = sqrt($r*$r - $𝗗*$𝗗); # Length from midpoint along line to circumference
416 48         70 my $s = $𝔻/$𝗗; # Length from midpoint along line to circumference relative to length from centre to midpoint
417 48         181 &$sub($X - $s * $𝗬, $Y + $s * $𝗫, $X + $s * $𝗬, $Y - $s * $𝗫) # Intersection points
418 64         344 } $𝘅, $𝘆, $𝕩, $𝕪, $x, $y; # Find point on line closest to centre of circle
419             }
420              
421             #-------------------------------------------------------------------------------
422             # 𝗔rea of intersection of a circle with a line
423             #
424             # 𝗞nown: a circle specified by its centre (x, y), and radius (r)
425             # and a line that passes through points: ($𝘅, $𝘆) and ($𝕩, $𝕪).
426             # 𝗙ind: the area of the smallest lune as a fraction of the area of the circle
427             # 𝗠ethod:
428             #-------------------------------------------------------------------------------
429              
430             sub intersectionCircleLineArea(&$$$$$$$)
431 49     49 1 19090 {my ($sub, # Sub routine to process area
432             $x, $y, $r, # Circle centre, radius
433             $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Line goes through these two points
434 49 50       128 @_ == 8 or confess "Wrong number of parameters";
435 49 50 33     98 near($𝘅, $𝕩) and near($𝘆, $𝕪) and confess "Points on line are too close!";
436 49 50       96 near($r) and confess "Radius is too small!";
437              
438             intersectionCircleLine
439 49 100   49   116 {return &$sub(0) if @_ < 4;
440 46         68 my ($X, $Y, $𝗫, $𝗬) = @_; # Intersection points
441 46         101 my $h = vectorLength($X - $𝗫, $Y - $𝗬) / 2; # Height of triangle
442 46         112 my $w = sqrt($r**2 - $h**2); # Base of triangle
443 46         159 &$sub(($r**2*atan2($h, $w) - $h*$w)/(𝝿()*$r**2)) # Area of smallest lune as a fraction of circle
444 49         244 } $x, $y, $r, $𝘅, $𝘆, $𝕩, $𝕪;
445             }
446              
447             #-------------------------------------------------------------------------------
448             # 𝗖ircumCentre: intersection of the sides of a triangle when rotated 𝝿/2 at
449             # their mid points - centre of the circumCircle
450             # 𝗞nown: coordinates of each corner of the triangle
451             #-------------------------------------------------------------------------------
452              
453             sub circumCentre(&$$$$$$)
454 46     46 1 84 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Subroutine to process results, coordinates of corners
455 46 50       152 @_ == 7 or confess "Wrong number of parameters";
456 46 50 66     80 (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";
      66        
      33        
457              
458 46     46   98 &intersectionLines(sub{&$sub(@_)},
459 46         179 rotate90AroundMidPoint($x, $y, $𝘅, $𝘆),
460             rotate90AroundMidPoint($𝘅, $𝘆, $𝕩, $𝕪));
461             }
462              
463             #-------------------------------------------------------------------------------
464             # 𝗖ircle through three points: https://en.wikipedia.org/wiki/Circumscribed_circle
465             # 𝗞nown: coordinates of each point
466             # 𝗙ind: coordinates of the centre and radius of the circle through these three
467             # points
468             #-------------------------------------------------------------------------------
469              
470             sub circumCircle(&$$$$$$)
471 46     46 1 10904 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Subroutine to process results, coordinates of corners
472 46 50       114 @_ == 7 or confess "Wrong number of parameters";
473 46 50 66     101 (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Points are too close!";
      66        
      33        
474              
475             circumCentre
476 46     46   71 {my ($X, $Y) = @_; # Centre
477 46         80 my @r = (vectorLength($x, $y, $X, $Y), # Radii
478             vectorLength($𝘅, $𝘆, $X, $Y),
479             vectorLength($𝕩, $𝕪, $X, $Y));
480 46 50 33     115 &near(@r[0,1]) && &near(@r[1,2]) or confess "Bad radius computed!";
481 46         145 &$sub($X, $Y, $r[0]) # Result
482 46         259 } $x, $y, $𝘅, $𝘆, $𝕩, $𝕪; # Centre lies at the intersection of
483             }
484              
485             #-------------------------------------------------------------------------------
486             # 𝗖entre of a circle inscribed inside a triangle so that the inscribed circle
487             # touches each side just once.
488             #
489             # 𝗞nown: coordinates of each corner of the triangle
490             # 𝗙ind: centre coordinates and radius of inscribed circle
491             # 𝗠ethod: find the intersection of the lines bisecting two angles
492             #-------------------------------------------------------------------------------
493              
494             sub circleInscribedInTriangle(&$$$$$$)
495 1     1 1 451 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Subroutine to process results, coordinates of corners
496 1 50       6 @_ == 7 or confess "Wrong number of parameters";
497 1 50 33     4 (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";
      33        
      33        
498 1         3 my $𝗱 = vectorLength($x, $y, $𝕩, $𝕪); # Lengths of sides opposite corners
499 1         3 my $𝕕 = vectorLength($x, $y, $𝘅, $𝘆);
500 1         2 my $d = vectorLength($𝘅, $𝘆, $𝕩, $𝕪);
501              
502             intersectionLines
503 1     1   9 {my ($X, $Y) = @_; # Intersection point
504 1         7 my @r = ((unsignedDistanceFromLineToPoint {@_} $x, $y, $𝘅, $𝘆, $X, $Y),
505 1         8 (unsignedDistanceFromLineToPoint {@_} $𝘅, $𝘆, $𝕩, $𝕪, $X, $Y),
506 1         19 (unsignedDistanceFromLineToPoint {@_} $𝕩, $𝕪, $x, $y, $X, $Y));
  1         5  
507 1 50 33     16 &near(@r[0,1]) && &near(@r[1,2]) or confess "Bad radius computed!";
508 1         5 return &$sub($X, $Y, $r[0]); # Coordinates of the centre of the inscribed circle, plus three estimates of its radius
509             }
510 1         14 $x, $y, $x + ($𝘅-$x)/$𝕕 + ($𝕩-$x)/$𝗱, $y + ($𝘆-$y)/$𝕕 + ($𝕪-$y)/$𝗱, # Intersection of an angle bisector
511             $𝘅, $𝘆, $𝘅 + ($𝕩-$𝘅)/$d + ($x-$𝘅)/$𝕕, $𝘆 + ($𝕪-$𝘆)/$d + ($y-$𝘆)/$𝕕; # Intersection of an angle bisector
512             }
513              
514             #-------------------------------------------------------------------------------
515             # 𝗖entre of a circle inscribed through the midpoints of each side of a triangle
516             # == Nine point circle: https://en.wikipedia.org/wiki/Nine-point_circle
517             # 𝗞nown: coordinates of each corner of the triangle
518             # 𝗙ind: centre coordinates and radius of circle through midpoints
519             # 𝗠ethod: use circumCircle on the midpoints
520             #-------------------------------------------------------------------------------
521              
522             sub ninePointCircle(&$$$$$$)
523 24     24 1 1632 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Subroutine to process results, coordinates of corners
524 24 50       60 @_ == 7 or confess "Wrong number of parameters";
525 24 50 33     46 (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";
      66        
      33        
526              
527 24     24   76 &circumCircle(sub{&$sub(@_)}, # Circle through mid points
528 24         95 midPoint($x, $y, $𝘅, $𝘆),
529             midPoint($𝘅, $𝘆, $𝕩, $𝕪),
530             midPoint($𝕩, $𝕪, $x, $y));
531             }
532              
533             #-------------------------------------------------------------------------------
534             # Bisect the first angle of a triangle
535             #-------------------------------------------------------------------------------
536              
537             sub bisectAnAngle(&$$$$$$)
538 114     114 0 209 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Subroutine to process results, coordinates of corners
539 114 50       258 @_ == 7 or confess "Wrong number of parameters";
540 114 50 33     207 (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";
      66        
      33        
541 114         256 my $𝕕 = vectorLength($x, $y, $𝕩, $𝕪); # Lengths to opposite corners
542 114         220 my $𝗱 = vectorLength($x, $y, $𝘅, $𝘆);
543 114         465 &$sub($x, $y, $x + ($𝘅-$x)/$𝕕 + ($𝕩-$x)/$𝗱, $y + ($𝘆-$y)/$𝕕 + ($𝕪-$y)/$𝗱) # Vector from vertex pointing along bisector
544             }
545              
546             #-------------------------------------------------------------------------------
547             # 𝗙ind the centres and radii of the excircles of a triangle
548             # https://en.wikipedia.org/wiki/Incircle_and_excircles_of_a_triangle
549             # 𝗞nown: coordinates of each corner of the triangle
550             # 𝗠ethod: intersection of appropriate angles of the triangles
551             #-------------------------------------------------------------------------------
552              
553             sub exCircles(&$$$$$$)
554 19     19 1 278 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Subroutine to process results, coordinates of corners
555 19 50       53 @_ == 7 or confess "Wrong number of parameters";
556 19 50 33     79 (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";
      33        
      33        
557              
558 19     19   126 my @c = &intersectionLines(sub{@_}, # Centres
559 19     19   118 (bisectAnAngle {@_} $x, $y, $𝘅, $𝘆, $𝕩, $𝕪),
560 19     19   103 (bisectAnAngle {@_} $𝘅, $𝘆, $𝕩, $𝕪, 2*$𝘅 - $x, 2*$𝘆 - $y));
  19         59  
561              
562 19     19   116 my @𝗰 = &intersectionLines(sub{@_},
563 19     19   109 (bisectAnAngle {@_} $𝘅, $𝘆, $𝕩, $𝕪, $x, $y),
564 19     19   383 (bisectAnAngle {@_} $𝕩, $𝕪, $x, $y, 2*$𝕩 - $𝘅, 2*$𝕪 - $𝘆));
  19         60  
565              
566 19     19   106 my @𝕔 = &intersectionLines(sub{@_},
567 19     19   106 (bisectAnAngle {@_} $𝕩, $𝕪, $x, $y, $𝘅, $𝘆),
568 19     19   341 (bisectAnAngle {@_} $x, $y, $𝘅, $𝘆, 2*$x - $𝕩, 2*$y - $𝕪));
  19         65  
569              
570 19     19   105 my @r = (&unsignedDistanceFromLineToPoint(sub {@_}, $x, $y, $𝘅, $𝘆, @c),
571 19     19   109 &unsignedDistanceFromLineToPoint(sub {@_}, $𝘅, $𝘆, $𝕩, $𝕪, @c),
572 19     19   357 &unsignedDistanceFromLineToPoint(sub {@_}, $𝕩, $𝕪, $x, $y, @c));
  19         76  
573              
574 19     19   101 my @𝗿 = (&unsignedDistanceFromLineToPoint(sub {@_}, $x, $y, $𝘅, $𝘆, @𝗰),
575 19     19   103 &unsignedDistanceFromLineToPoint(sub {@_}, $𝘅, $𝘆, $𝕩, $𝕪, @𝗰),
576 19     19   343 &unsignedDistanceFromLineToPoint(sub {@_}, $𝕩, $𝕪, $x, $y, @𝗰));
  19         73  
577              
578 19     19   111 my @𝕣 = (&unsignedDistanceFromLineToPoint(sub {@_}, $x, $y, $𝘅, $𝘆, @𝕔),
579 19     19   108 &unsignedDistanceFromLineToPoint(sub {@_}, $𝘅, $𝘆, $𝕩, $𝕪, @𝕔),
580 19     19   297 &unsignedDistanceFromLineToPoint(sub {@_}, $𝕩, $𝕪, $x, $y, @𝕔));
  19         78  
581 19         401 ([@c, @r], [@𝗰, @𝗿], [@𝕔, @𝕣]) # For each circle, the centre followed by the radii estimates
582             }
583              
584             #-------------------------------------------------------------------------------
585             # 𝗖entroid: intersection of lines between corners and mid points of opposite sides
586             # 𝗙ind: coordinates of centroid
587             # 𝗞nown: coordinates of each corner of the triangle
588             #-------------------------------------------------------------------------------
589              
590             sub centroid(&$$$$$$)
591 22     22 1 669 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Subroutine to process results, coordinates of corners
592 22 50       50 @_ == 7 or confess "Wrong number of parameters";
593 22 50 33     39 (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";
      33        
      33        
594              
595 22     22   55 &intersectionLines(sub{&$sub(@_)},
596 22         93 $x, $y, midPoint($𝘅, $𝘆, $𝕩, $𝕪),
597             $𝘅, $𝘆, midPoint($𝕩, $𝕪, $x, $y));
598             }
599              
600             #-------------------------------------------------------------------------------
601             # 𝗢rthocentre: intersection of altitudes
602             # 𝗙ind: coordinates of orthocentre
603             # 𝗞nown: coordinates of each corner of the triangle
604             #-------------------------------------------------------------------------------
605              
606             sub orthoCentre(&$$$$$$)
607 22     22 1 674 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Subroutine to process results, coordinates of corners
608 22 50       73 @_ == 7 or confess "Wrong number of parameters";
609 22 50 33     41 (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";
      33        
      33        
610              
611 22     22   65 &intersectionLines(sub{&$sub(@_)},
612 22     22   124 $x, $y, (intersectionLinePoint {@_} $𝘅, $𝘆, $𝕩, $𝕪, $x, $y),
613 22     22   113 $𝘅, $𝘆, (intersectionLinePoint {@_} $𝕩, $𝕪, $x, $y, $𝘅, $𝘆));
  22         81  
614             }
615              
616             #-------------------------------------------------------------------------------
617             # 𝗔rea of a triangle
618             # 𝗞nown: coordinates of each corner of the triangle
619             # 𝗙ind: area
620             # 𝗠ethod: height of one corner from line through other two corners
621             #-------------------------------------------------------------------------------
622              
623             sub areaOfTriangle(&$$$$$$)
624 125     125 1 15073 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Subroutine to process results, coordinates of corners
625 125 50       337 @_ == 7 or confess "Wrong number of parameters";
626 125 100 100     236 return &$sub(0) if near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪); # A pair of corners are close, so the area of the triangle must be zero
      66        
      66        
627 113     113   485 my ($d) = unsignedDistanceFromLineToPoint(sub {@_}, $𝘅, $𝘆, $𝕩, $𝕪, $x, $y); # Distance for first corner from opposite line
  113         315  
628 113         559 &$sub($d * vectorLength($𝘅, $𝘆, $𝕩, $𝕪)/2) # Area = half base * height
629             }
630              
631             #-------------------------------------------------------------------------------
632             # 𝗔rea of a polygon
633             # 𝗞nown: coordinates of each corner=vertex of the polygon
634             # 𝗙ind: area
635             # 𝗠ethod: divide the polygon into triangles which all share the first vertex
636             #-------------------------------------------------------------------------------
637              
638             sub areaOfPolygon(&@)
639 33     33 1 1738 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪, @vertices) = @_; # Subroutine to process results, coordinates of vertices
640 33     33   133 my ($area) = areaOfTriangle {@_} $x, $y, $𝘅, $𝘆, $𝕩, $𝕪; # Area of first triangle
  33         79  
641 33         128 for(;scalar @vertices;) # Each subsequent triangle
642 26         38 {($𝘅, $𝘆) = ($𝕩, $𝕪); # Move up one vertex at a time
643 26         53 ($𝕩, $𝕪) = splice @vertices, 0, 2; # Remove one vertex
644 26     26   96 my ($a) = areaOfTriangle {@_} $x, $y, $𝘅, $𝘆, $𝕩, $𝕪; # Area of latest triangle
  26         54  
645 26         107 $area += $a; # Sum areas
646             }
647 33         82 &$sub($area) # Area of polygon
648             }
649              
650             #-------------------------------------------------------------------------------
651             # 𝗦mallest positive angle made at the intersection of two lines, expressed in degrees
652             # 𝗞nown: coordinates of start and end of each line segment
653             # 𝗙ind: smallest angle between the two lines or zero if they do not intersect
654             # 𝗠ethod: use dot product
655             #-------------------------------------------------------------------------------
656              
657             sub smallestPositiveAngleBetweenTwoLines($$$$$$$$)
658 6     6 1 404 {my ($x, $y, $𝘅, $𝘆, $X, $Y, $𝗫, $𝗬) = @_; # Start and end coordinates of two line segments
659 6         14 my ($𝕩, $𝕪) = ($𝘅 - $x, $𝘆 - $y); # Vector along first line segment
660 6         11 my ($𝕏, $𝕐) = ($𝗫 - $X, $𝗬 - $Y); # Vector along second line segment
661 6         29 my $r = acos(($𝕩*$𝕏 + $𝕪*$𝕐) / sqrt(($𝕩*$𝕩+$𝕪*$𝕪) * ($𝕏*$𝕏 + $𝕐*$𝕐))); # Result in radians
662 6         16 my $𝗿 = abs(180 * $r / 𝝿()); # Result in positive degrees
663 6 100       37 $𝗿 > 90 ? 180 - $𝗿 : $𝗿 # Smallest angle between two lines
664             }
665              
666             #-------------------------------------------------------------------------------
667             # 𝗜s a triangle equilateral?
668             # 𝗞nown: coordinates of each corner=vertex of the triangle
669             # 𝗠ethod: compare lengths of sides
670             #-------------------------------------------------------------------------------
671              
672             sub isEquilateralTriangle(@)
673 1     1 1 2 {my ($x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Coordinates of vertices
674 1 50       4 @_ == 6 or confess "Wrong number of parameters";
675 1         4 my ($d, $𝗱, $𝕕) = &lengthsOfTheSidesOfAPolygon(@_); # Lengths of sides
676 1 50       4 near($d, $𝗱) && near($𝗱, $𝕕) # Equal sided?
677             }
678              
679             #-------------------------------------------------------------------------------
680             # 𝗜s a triangle isosceles
681             # 𝗞nown: coordinates of each corner=vertex of the triangle
682             # 𝗠ethod: compare lengths of sides
683             #-------------------------------------------------------------------------------
684              
685             sub isIsoscelesTriangle(@)
686 2     2 1 5 {my ($x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Coordinates of vertices
687 2 50       7 @_ == 6 or confess "Wrong number of parameters";
688 2         6 my ($d, $𝗱, $𝕕) = &lengthsOfTheSidesOfAPolygon(@_); # Lengths of sides
689 2 50 66     6 near($d, $𝗱) || near($𝗱, $𝕕) || near($d, $𝕕) # Two sides with equal lengths
690             }
691              
692             #-------------------------------------------------------------------------------
693             # 𝗜s a right angled triangle
694             # 𝗞nown: coordinates of each corner=vertex of the triangle
695             # 𝗠ethod: pythagoras on sides
696             #-------------------------------------------------------------------------------
697              
698             sub isRightAngledTriangle(@)
699 1     1 1 3 {my ($x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_; # Coordinates of vertices
700 1 50       4 @_ == 6 or confess "Wrong number of parameters";
701 1         4 my ($d, $𝗱, $𝕕) = &lengthsOfTheSidesOfAPolygon(@_); # Lengths of sides
702 1 50 33     5 near($d**2,$𝗱**2+$𝕕**2)||near($𝗱**2,$d**2+$𝕕**2) || near($𝕕**2,$d**2+$𝗱**2) # Pythagoras
703             }
704              
705             #-------------------------------------------------------------------------------
706             # 𝗘xport details
707             #-------------------------------------------------------------------------------
708              
709             require 5;
710             require Exporter;
711              
712 1     1   18 use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
  1         2  
  1         525  
713              
714             @ISA = qw(Exporter);
715              
716             @EXPORT = qw(exCircles intersectionCircles intersectionCirclesArea
717             intersectionCircleLine intersectionCircleLineArea intersectionLines
718             intersectionLinePoint circumCircle circumCentre circleInscribedInTriangle
719             ninePointCircle areaOfTriangle areaOfPolygon orthoCentre centroid
720             isEquilateralTriangle isIsoscelesTriangle isRightAngledTriangle);
721              
722             @EXPORT_OK = qw(midPoint near near2 near3 near4 rotate90CW rotate90CCW
723             rotate90AroundMidPoint vectorLength 𝝿 lengthsOfTheSidesOfAPolygon
724             threeCollinearPoints smallestPositiveAngleBetweenTwoLines);
725              
726             $EXPORT_TAGS{all} = [@EXPORT, @EXPORT_OK];
727              
728             =head1 Description
729              
730             Find the points at which circles and lines intersect to test geometric
731             intuition.
732              
733             Fast, fun and easy to use these functions are written in 100% Pure Perl.
734              
735             =head2 areaOfTriangle 𝘀𝘂𝗯 triangle
736              
737             Calls 𝘀𝘂𝗯($a) where $a is the area of the specified triangle:
738              
739             A triangle is specified by supplying a list of six numbers:
740              
741             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
742              
743             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
744             triangle.
745              
746             =head2 areaOfPolygon 𝘀𝘂𝗯 points...
747              
748             Calls 𝘀𝘂𝗯($a) where $a is the area of the polygon with vertices specified by
749             the points.
750              
751             A point is specified by supplying a list of two numbers:
752              
753             (𝘅, 𝘆)
754              
755             =head2 centroid 𝘀𝘂𝗯 triangle
756              
757             Calls 𝘀𝘂𝗯($x,$y) where $x,$y are the coordinates of the centroid of the
758             specified triangle:
759              
760             See: L
761              
762             A triangle is specified by supplying a list of six numbers:
763              
764             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
765              
766             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
767             triangle.
768              
769             =head2 circumCentre 𝘀𝘂𝗯 triangle
770              
771             Calls 𝘀𝘂𝗯($x,$y,$r) where $x,$y are the coordinates of the centre of the
772             circle drawn through the corners of the specified triangle and $r is its
773             radius:
774              
775             See: L
776              
777             A triangle is specified by supplying a list of six numbers:
778              
779             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
780              
781             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
782             triangle.
783              
784             =head2 circumCircle 𝘀𝘂𝗯 triangle
785              
786             Calls 𝘀𝘂𝗯($x,$y,$r) where $x,$y are the coordinates of the circumcentre of
787             the specified triangle and $r is its radius:
788              
789             See: L
790              
791             A triangle is specified by supplying a list of six numbers:
792              
793             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
794              
795             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
796             triangle.
797              
798             =head2 exCircles 𝘀𝘂𝗯 triangle
799              
800             Calls 𝘀𝘂𝗯([$x,$y,$r]...) where $x,$y are the coordinates of the centre of each
801             ex-circle and $r its radius for the specified triangle:
802              
803             See: L
804              
805             A triangle is specified by supplying a list of six numbers:
806              
807             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
808              
809             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
810             triangle.
811              
812             =head2 circleInscribedInTriangle 𝘀𝘂𝗯 triangle
813              
814             Calls 𝘀𝘂𝗯($x,$y,$r) where $x,$y are the coordinates of the centre of
815             a circle which touches each side of the triangle just once and $r is its radius:
816              
817             See: L
818              
819             A triangle is specified by supplying a list of six numbers:
820              
821             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
822              
823             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
824             triangle.
825              
826             =head2 intersectionCircles 𝘀𝘂𝗯 circle1, circle2
827              
828             Find the points at which two circles intersect. Complains if the two circles
829             are identical.
830              
831             𝘀𝘂𝗯 specifies a subroutine to be called with the coordinates of the
832             intersection points if there are any or an empty parameter list if there are
833             no points of intersection.
834              
835             A circle is specified by supplying a list of three numbers:
836              
837             (𝘅, 𝘆, 𝗿)
838              
839             where (𝘅, 𝘆) are the coordinates of the centre of the circle and (𝗿) is its
840             radius.
841              
842             Returns whatever is returned by 𝘀𝘂𝗯.
843              
844             =head2 intersectionCirclesArea 𝘀𝘂𝗯 circle1, circle2
845              
846             Find the area of overlap of two circles expressed as a fraction of the area of
847             the smallest circle. The fractional area is expressed as a number between 0
848             and 1.
849              
850             𝘀𝘂𝗯 specifies a subroutine to be called with the fractional area.
851              
852             A circle is specified by supplying a list of three numbers:
853              
854             (𝘅, 𝘆, 𝗿)
855              
856             where (𝘅, 𝘆) are the coordinates of the centre of the circle and (𝗿) is its
857             radius.
858              
859             Returns whatever is returned by 𝘀𝘂𝗯.
860              
861             =head2 intersectionCircleLine 𝘀𝘂𝗯 circle, line
862              
863             Find the points at which a circle and a line intersect.
864              
865             𝘀𝘂𝗯 specifies a subroutine to be called with the coordinates of the
866             intersection points if there are any or an empty parameter list if there are
867             no points of intersection.
868              
869             A circle is specified by supplying a list of three numbers:
870              
871             (𝘅, 𝘆, 𝗿)
872              
873             where (𝘅, 𝘆) are the coordinates of the centre of the circle and (𝗿) is its
874             radius.
875              
876             A line is specified by supplying a list of four numbers:
877              
878             (x, y, 𝘅, 𝘆)
879              
880             where (x, y) and (𝘅, 𝘆) are the coordinates of two points on the line.
881              
882             Returns whatever is returned by 𝘀𝘂𝗯.
883              
884             =head2 intersectionCircleLineArea 𝘀𝘂𝗯 circle, line
885              
886             Find the fractional area of a circle occupied by a lune produced by an
887             intersecting line. The fractional area is expressed as a number
888             between 0 and 1.
889              
890             𝘀𝘂𝗯 specifies a subroutine to be called with the fractional area.
891              
892             A circle is specified by supplying a list of three numbers:
893              
894             (𝘅, 𝘆, 𝗿)
895              
896             where (𝘅, 𝘆) are the coordinates of the centre of the circle and (𝗿) is its
897             radius.
898              
899             A line is specified by supplying a list of four numbers:
900              
901             (x, y, 𝘅, 𝘆)
902              
903             where (x, y) and (𝘅, 𝘆) are the coordinates of two points on the line.
904              
905             Returns whatever is returned by 𝘀𝘂𝗯.
906              
907             =head2 intersectionLines 𝘀𝘂𝗯 line1, line2
908              
909             Finds the point at which two lines intersect.
910              
911             𝘀𝘂𝗯 specifies a subroutine to be called with the coordinates of the
912             intersection point or an empty parameter list if the two lines do not
913             intersect.
914              
915             Complains if the two lines are collinear.
916              
917             A line is specified by supplying a list of four numbers:
918              
919             (x, y, 𝘅, 𝘆)
920              
921             where (x, y) and (𝘅, 𝘆) are the coordinates of two points on the line.
922              
923             Returns whatever is returned by 𝘀𝘂𝗯.
924              
925             =head2 intersectionLinePoint 𝘀𝘂𝗯 line, point
926              
927             Find the point on a line closest to a specified point.
928              
929             𝘀𝘂𝗯 specifies a subroutine to be called with the coordinates of the
930             intersection points if there are any.
931              
932             A line is specified by supplying a list of four numbers:
933              
934             (x, y, 𝘅, 𝘆)
935              
936             where (x, y) and (𝘅, 𝘆) are the coordinates of two points on the line.
937              
938             A point is specified by supplying a list of two numbers:
939              
940             (𝘅, 𝘆)
941              
942             where (𝘅, 𝘆) are the coordinates of the point.
943              
944             Returns whatever is returned by 𝘀𝘂𝗯.
945              
946             =head2 isEquilateralTriangle triangle
947              
948             Return true if the specified triangle is close to being equilateral within the
949             definition of nearness.
950              
951             A triangle is specified by supplying a list of six numbers:
952              
953             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
954              
955             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
956             triangle.
957              
958             =head2 isIsoscelesTriangle triangle
959              
960             Return true if the specified triangle is close to being isosceles within the
961             definition of nearness.
962              
963             A triangle is specified by supplying a list of six numbers:
964              
965             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
966              
967             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
968             triangle.
969              
970             =head2 isRightAngledTriangle triangle
971              
972             Return true if the specified triangle is close to being right angled within
973             the definition of nearness.
974              
975             A triangle is specified by supplying a list of six numbers:
976              
977             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
978              
979             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
980             triangle.
981              
982             =head2 ninePointCircle 𝘀𝘂𝗯 triangle
983              
984             Calls 𝘀𝘂𝗯($x,$y,$r) where $x,$y are the coordinates of the centre of the
985             circle drawn through the midpoints of each side of the specified triangle and
986             $r is its radius which gives the nine point circle:
987              
988             See: L
989              
990             A triangle is specified by supplying a list of six numbers:
991              
992             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
993              
994             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
995             triangle.
996              
997             =head2 orthoCentre 𝘀𝘂𝗯 triangle
998              
999             Calls 𝘀𝘂𝗯($x,$y) where $x,$y are the coordinates of the orthocentre of the
1000             specified triangle:
1001              
1002             See: L
1003              
1004             A triangle is specified by supplying a list of six numbers:
1005              
1006             (x, y, 𝘅, 𝘆, 𝕩, 𝕪)
1007              
1008             where (x, y), (𝘅, 𝘆) and (𝕩, 𝕪) are the coordinates of the vertices of the
1009             triangle.
1010              
1011             =head2 $Math::Intersection::Circle::Line::near
1012              
1013             As a finite computer cannot represent an infinite plane of points it is
1014             necessary to make the plane discrete by merging points closer than the
1015             distance contained in this variable, which is set by default to 1e-6.
1016              
1017             =head1 Exports
1018              
1019             The following functions are exported by default:
1020              
1021             =over
1022              
1023             =item C
1024              
1025             =item C
1026              
1027             =item C
1028              
1029             =item C
1030              
1031             =item C
1032              
1033             =item C
1034              
1035             =item C
1036              
1037             =item C
1038              
1039             =item C
1040              
1041             =item C
1042              
1043             =item C
1044              
1045             =item C
1046              
1047             =item C
1048              
1049             =item C
1050              
1051             =item C
1052              
1053             =item C
1054              
1055             =item C
1056              
1057             =item C
1058              
1059             =item C
1060              
1061             =back
1062              
1063             Optionally some useful helper functions can also be exported either by
1064             specifying the tag :𝗮𝗹𝗹 or by naming the required functions individually:
1065              
1066             =over
1067              
1068             =item C
1069              
1070             =item C
1071              
1072             =item C
1073              
1074             =item C
1075              
1076             =item C
1077              
1078             =item C
1079              
1080             =item C
1081              
1082             =item C
1083              
1084             =item C
1085              
1086             =item C
1087              
1088             =item C
1089              
1090             =item C
1091              
1092             =item C
1093              
1094             =item C
1095              
1096             =item C<𝝿()>
1097              
1098             =back
1099              
1100             =head1 Changes
1101              
1102             1.003 Sun 30 Aug 2015 - Started Geometry app
1103             1.005 Sun 20 Dec 2015 - Still going!
1104             1.006 Sat 02 Jan 2016 - Euler's line divided into 6 equal pieces
1105             1.007 Sat 02 Jan 2016 - [rt.cpan.org #110849] Test suite fails with uselongdouble
1106             1.008 Sun 03 Jan 2016 - [rt.cpan.org #110849] Removed dump
1107              
1108             =cut
1109              
1110             $VERSION = '1.008';
1111              
1112             =pod
1113              
1114             =head1 Installation
1115              
1116             Standard Module::Build process for building and installing modules:
1117              
1118             perl Build.PL
1119             ./Build
1120             ./Build test
1121             ./Build install
1122              
1123             Or, if you're on a platform (like DOS or Windows) that doesn't require
1124             the "./" notation, you can do this:
1125              
1126             perl Build.PL
1127             Build
1128             Build test
1129             Build install
1130              
1131             =head1 Author
1132              
1133             Philip R Brenan at gmail dot com
1134              
1135             http://www.appaapps.com
1136              
1137             =head1 Copyright
1138              
1139             Copyright (c) 2016 Philip R Brenan.
1140              
1141             This module is free software. It may be used, redistributed and/or
1142             modified under the same terms as Perl itself.
1143              
1144             =cut