File Coverage

blib/lib/Math/Intersection/Circle/Line.pm
Criterion Covered Total %
statement 15 17 88.2
branch n/a
condition n/a
subroutine 6 6 100.0
pod n/a
total 21 23 91.3


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