Math-Intersection-Circle-Line

 view release on metacpan or  search on metacpan

lib/Math/Intersection/Circle/Line.pm  view on Meta::CPAN

#   a == (r*r-𝗿*𝗿 + 𝗹*𝗹)/ (2*𝗹)
#
# The distance 𝗮 at right angles to 𝗟 to an intersection is sqrt(r*r-a*a)
#
# The unit vector 𝕕 == (𝕩, 𝕪) along line 𝗟 from (x,y) to (𝘅, 𝘆) is the unit in
# direction: (𝘅-x, 𝘆-y)
#
# The unit vectors d, 𝗱 at right angles to 𝗟 are (-𝕪, 𝕩) and (𝕪, -𝕩)
#-------------------------------------------------------------------------------

sub intersectionCircles(&$$$$$$)
 {my ($sub,                                                                     # Sub routine to process intersection
      $x, $y, $r,                                                               # First circle centre, radius
      $𝘅, $𝘆, $𝗿) = @_;                                                         # Second circle centre, radius
  @_ == 7 or confess "Wrong number of parameters";
  return &$sub("Duplicate circles!") if                                         # Complain if the two circles are in fact the same circle within the definition of nearness
    near($x, $𝘅) and near($y, $𝘆) and near($r, $𝗿);

  my ($𝕏, $𝕐) = ($𝘅 - $x, $𝘆 - $y);                                             # Vector between centres
  my $𝗹 = vectorLength($𝕏, $𝕐);                                                 # Distance between centres
  return &$sub("No intersection!") if $𝗹 > $r + $𝗿 or $𝗹 < abs($r - $𝗿);        # The circles are too far apart or too close to intersect

lib/Math/Intersection/Circle/Line.pm  view on Meta::CPAN

#
# 𝗞nown: two circles specified by ($x, $y, $r) and ($𝘅, $𝘆, $𝗿)
#
# 𝗙ind: the area of intersection expressed as a fraction of the area
# of the smaller circle
#
# 𝗠ethod: the area of a triangle is (base * height) / 2, the area of a slice is
# 𝝰𝗿𝗿/2 where 𝝰 is the angle of a slice.
#-------------------------------------------------------------------------------

sub intersectionCirclesArea(&$$$$$$)
 {my ($sub,                                                                     # Sub routine to process area
      $x, $y, $r,                                                               # First circle centre, radius
      $𝘅, $𝘆, $𝗿) = @_;                                                         # Second circle centre, radius
  @_ == 7 or confess "Wrong number of parameters";
  near($r) and confess "Radius of first circle is too small!";
  near($𝗿) and confess "Radius of second circle is too small!";
  my $l = vectorLength($𝘅 - $x, $𝘆 - $y);                                       # Distance between centres
  return &$sub(0) if $l >= $r + $𝗿;                                             # The circles are too far apart to overlap
  my $𝕣 = $r < $𝗿 ? $r : $𝗿;                                                    # Radius of smaller circle
  return &$sub(1) if $l <= abs($r - $𝗿);                                        # The larger circle overlaps the smaller circle completely

lib/Math/Intersection/Circle/Line.pm  view on Meta::CPAN

#
# 𝗞nown: two points on the line 𝗟 such that: 𝗹 = (𝘅, 𝘆), 𝕝 = (𝕩, 𝕪) and the
# specified point 𝗽 = (x, y).
#
# 𝗙ind 𝗰 the point on 𝗟 closest to 𝗽.
#
# 𝗠ethod: a circle with centre 𝗹 through 𝗽 will intersect a circle with centre 𝕝
# through 𝗽 at 𝗾. 𝗰 is then the average of 𝗽 and 𝗾.
#-------------------------------------------------------------------------------

sub intersectionLinePoint(&$$$$$$)
 {my ($sub,                                                                     # Sub routine to process intersection
      $𝘅, $𝘆, $𝕩, $𝕪,                                                           # Two points on line 𝗹
      $x, $y) = @_;                                                             # The point 𝗽
  @_ == 7 or confess "Wrong number of parameters";
  near($𝘅, $𝕩) and near($𝘆, $𝕪) and confess "Points on line are too close!";    # Line not well defined

  return &$sub($x, $y) if near($x, $𝘅) && near($y, $𝘆) or                       # Point in question is near an end of the line segment
                          near($x, $𝕩) && near($y, $𝕪);

  return &$sub($x, $y) if threeCollinearPoints($𝘅, $𝘆, $𝕩, $𝕪, $x, $y);         # Collinear
                                                                                # Points known not to be collinear
  my $𝗿 = vectorLength($𝘅 - $x, $𝘆 - $y);                                       # Radius of first circle
  my $𝕣 = vectorLength($𝕩 - $x, $𝕪 - $y);                                       # Radius of second circle
  intersectionCircles
   {return &$sub(@_) if @_ == 2;                                                # Point is on line
    my ($x, $y, $𝘅, $𝘆) = @_;
    &$sub(($x+$𝘅) / 2, ($y+$𝘆) / 2)                                             # Average intersection of intersection points
   } $𝘅, $𝘆, $𝗿, $𝕩, $𝕪, $𝕣;
 }

sub unsignedDistanceFromLineToPoint(&$$$$$$)                                    # Unsigned distance from point to line
 {my ($sub, $𝘅, $𝘆, $𝕩, $𝕪, $x, $y) = @_;                                       # Parameters are the same as for intersectionLinePoint()
  @_ == 7 or confess "Wrong number of parameters";
  intersectionLinePoint {&$sub(&vectorLength($x, $y, @_))} $𝘅,$𝘆, $𝕩,$𝕪, $x,$y; # Distance from point to nearest point on line
 }

#-------------------------------------------------------------------------------
# 𝗜ntersection of two lines
#
# 𝗞nown: two lines l specified by two points 𝗹 = (𝘅, 𝘆),  𝕝 = (𝕩, 𝕪) and
#                  L specified by two points 𝗟 = (𝗫, 𝗬), 𝕃 = (𝕏, 𝕐)
# 𝗙ind 𝗰 the point where the two lines intersect else $sub is called empty
#
# 𝗠ethod: Let the closest point to point 𝗟 on line l be 𝗮 and the closest point
# to point 𝗮 on line L be 𝗯. L𝗮𝗯 is similar to L𝗮𝗰.
#-------------------------------------------------------------------------------

sub intersectionLines(&$$$$$$$$)
 {my ($sub,                                                                     # Sub routine to process intersection
      $𝘅, $𝘆, $𝕩, $𝕪,                                                           # Two points on line l
      $𝗫, $𝗬, $𝕏, $𝕐) = @_;                                                     # Two points on line L
  @_ == 9 or confess "Wrong number of parameters";
  near($𝘅, $𝕩) and near($𝘆, $𝕪) and confess "Points on first line are too close!";
  near($𝗫, $𝕏) and near($𝗬, $𝕐) and confess "Points on second line are too close!";
  return &$sub("Parallel lines!") if                                             # Lines are parallel if they have the same gradient
    near(atan2($𝘆-$𝕪, $𝘅-$𝕩), atan2($𝗬-$𝕐, $𝗫-$𝕏));

  intersectionLinePoint                                                         # Find 𝗮

lib/Math/Intersection/Circle/Line.pm  view on Meta::CPAN

# at which the line touches the circle or report that there are no points in
# common.
#
# 𝗠ethod: If the line crosses the circle we can draw an isosceles triangle from
# the centre of the circle to the points of intersection, with the line forming
# the base of said triangle.  The centre of the base is the closest point on the
# line to the centre of the circle. The line is at right angles to the line from
# the centre of the circle to the centre of the base.
#-------------------------------------------------------------------------------

sub intersectionCircleLine(&$$$$$$$)
 {my ($sub,                                                                     # Sub routine to process intersection
      $x, $y, $r,                                                               # Circle centre, radius
      $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                                     # Line goes through these two points
  @_ == 8 or confess "Wrong number of parameters";
  near($𝘅, $𝕩) and near($𝘆, $𝕪) and confess "Points on line are too close!";
  if (near($r))                                                                 # Zero radius circle
   {return &$sub($x, $y) if threeCollinearPoints($x, $y, $𝘅, $𝘆, $𝕩, $𝕪);       # Line passes through the centre of the circle
    confess "Radius is too small!";
   }

lib/Math/Intersection/Circle/Line.pm  view on Meta::CPAN


#-------------------------------------------------------------------------------
# 𝗔rea of intersection of a circle with a line
#
# 𝗞nown: a circle specified by its centre (x, y), and radius (r)
# and a line that passes through points: ($𝘅, $𝘆) and ($𝕩, $𝕪).
# 𝗙ind: the area of the smallest lune as a fraction of the area of the circle
# 𝗠ethod:
#-------------------------------------------------------------------------------

sub intersectionCircleLineArea(&$$$$$$$)
 {my ($sub,                                                                     # Sub routine to process area
      $x, $y, $r,                                                               # Circle centre, radius
      $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                                     # Line goes through these two points
  @_ == 8 or confess "Wrong number of parameters";
  near($𝘅, $𝕩) and near($𝘆, $𝕪) and confess "Points on line are too close!";
  near($r) and confess "Radius is too small!";

  intersectionCircleLine
   {return &$sub(0) if @_ < 4;
	  my ($X, $Y, $𝗫, $𝗬) = @_;                                                   # Intersection points

lib/Math/Intersection/Circle/Line.pm  view on Meta::CPAN

    &$sub(($r**2*atan2($h, $w) - $h*$w)/(𝝿()*$r**2))                            # Area of smallest lune as a fraction of circle
   } $x, $y, $r, $𝘅, $𝘆, $𝕩, $𝕪;
 }

#-------------------------------------------------------------------------------
# 𝗖ircumCentre: intersection of the sides of a triangle when rotated 𝝿/2 at
# their mid points - centre of the circumCircle
# 𝗞nown: coordinates of each corner of the triangle
#-------------------------------------------------------------------------------

sub circumCentre(&$$$$$$)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                       # Subroutine to process results, coordinates of corners
  @_ == 7 or confess "Wrong number of parameters";
  (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";

  &intersectionLines(sub{&$sub(@_)},
    rotate90AroundMidPoint($x, $y, $𝘅, $𝘆),
    rotate90AroundMidPoint($𝘅, $𝘆, $𝕩, $𝕪));
 }

#-------------------------------------------------------------------------------
# 𝗖ircle through three points: https://en.wikipedia.org/wiki/Circumscribed_circle
# 𝗞nown: coordinates of each point
# 𝗙ind: coordinates of the centre and radius of the circle through these three
# points
#-------------------------------------------------------------------------------

sub circumCircle(&$$$$$$)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                       # Subroutine to process results, coordinates of corners
  @_ == 7 or confess "Wrong number of parameters";
  (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Points are too close!";

  circumCentre
   {my ($X, $Y) = @_;                                                           # Centre
    my @r = (vectorLength($x, $y, $X, $Y),                                      # Radii
             vectorLength($𝘅, $𝘆, $X, $Y),
             vectorLength($𝕩, $𝕪, $X, $Y));
    &near(@r[0,1]) && &near(@r[1,2]) or confess "Bad radius computed!";

lib/Math/Intersection/Circle/Line.pm  view on Meta::CPAN


#-------------------------------------------------------------------------------
# 𝗖entre of a circle inscribed inside a triangle so that the inscribed circle
# touches each side just once.
#
# 𝗞nown: coordinates of each corner of the triangle
# 𝗙ind: centre coordinates and radius of inscribed circle
# 𝗠ethod: find the intersection of the lines bisecting two angles
#-------------------------------------------------------------------------------

sub circleInscribedInTriangle(&$$$$$$)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                       # Subroutine to process results, coordinates of corners
  @_ == 7 or confess "Wrong number of parameters";
  (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";
  my $𝗱 = vectorLength($x, $y, $𝕩, $𝕪);                                         # Lengths of sides opposite corners
  my $𝕕 = vectorLength($x, $y, $𝘅, $𝘆);
  my $d = vectorLength($𝘅, $𝘆, $𝕩, $𝕪);

  intersectionLines
     {my ($X, $Y) = @_;                                                         # Intersection point
      my @r = ((unsignedDistanceFromLineToPoint {@_} $x, $y, $𝘅, $𝘆, $X, $Y),

lib/Math/Intersection/Circle/Line.pm  view on Meta::CPAN

 }

#-------------------------------------------------------------------------------
# 𝗖entre of a circle inscribed through the midpoints of each side of a triangle
# == Nine point circle: https://en.wikipedia.org/wiki/Nine-point_circle
# 𝗞nown: coordinates of each corner of the triangle
# 𝗙ind: centre coordinates and radius of circle through midpoints
# 𝗠ethod: use circumCircle on the midpoints
#-------------------------------------------------------------------------------

sub ninePointCircle(&$$$$$$)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                       # Subroutine to process results, coordinates of corners
  @_ == 7 or confess "Wrong number of parameters";
  (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";

  &circumCircle(sub{&$sub(@_)},                                                 # Circle through mid points
    midPoint($x, $y, $𝘅, $𝘆),
    midPoint($𝘅, $𝘆, $𝕩, $𝕪),
    midPoint($𝕩, $𝕪, $x, $y));
 }

#-------------------------------------------------------------------------------
# Bisect the first angle of a triangle
#-------------------------------------------------------------------------------

sub bisectAnAngle(&$$$$$$)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                       # Subroutine to process results, coordinates of corners
  @_ == 7 or confess "Wrong number of parameters";
  (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";
  my $𝕕 = vectorLength($x, $y, $𝕩, $𝕪);                                         # Lengths to opposite corners
  my $𝗱 = vectorLength($x, $y, $𝘅, $𝘆);
  &$sub($x, $y, $x + ($𝘅-$x)/$𝕕 + ($𝕩-$x)/$𝗱, $y + ($𝘆-$y)/$𝕕 + ($𝕪-$y)/$𝗱)     # Vector from vertex pointing along bisector
 }

#-------------------------------------------------------------------------------
# 𝗙ind the centres and radii of the excircles of a triangle
# https://en.wikipedia.org/wiki/Incircle_and_excircles_of_a_triangle
# 𝗞nown: coordinates of each corner of the triangle
# 𝗠ethod: intersection of appropriate angles of the triangles
#-------------------------------------------------------------------------------

sub exCircles(&$$$$$$)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                       # Subroutine to process results, coordinates of corners
  @_ == 7 or confess "Wrong number of parameters";
  (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";

  my @c = &intersectionLines(sub{@_},                                           # Centres
   (bisectAnAngle {@_} $x, $y, $𝘅, $𝘆,   $𝕩,        $𝕪),
   (bisectAnAngle {@_} $𝘅, $𝘆, $𝕩, $𝕪, 2*$𝘅 - $x, 2*$𝘆 - $y));

  my @𝗰 = &intersectionLines(sub{@_},
   (bisectAnAngle {@_} $𝘅, $𝘆, $𝕩, $𝕪, $x, $y),

lib/Math/Intersection/Circle/Line.pm  view on Meta::CPAN

           &unsignedDistanceFromLineToPoint(sub {@_}, $𝕩, $𝕪, $x, $y, @𝕔));
  ([@c, @r], [@𝗰, @𝗿], [@𝕔, @𝕣])                                                # For each circle, the centre followed by the radii estimates
 }

#-------------------------------------------------------------------------------
# 𝗖entroid: intersection of lines between corners and mid points of opposite sides
# 𝗙ind: coordinates of centroid
# 𝗞nown: coordinates of each corner of the triangle
#-------------------------------------------------------------------------------

sub centroid(&$$$$$$)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                       # Subroutine to process results, coordinates of corners
  @_ == 7 or confess "Wrong number of parameters";
  (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";

  &intersectionLines(sub{&$sub(@_)},
    $x, $y, midPoint($𝘅, $𝘆, $𝕩, $𝕪),
    $𝘅, $𝘆, midPoint($𝕩, $𝕪, $x, $y));
 }

#-------------------------------------------------------------------------------
# 𝗢rthocentre: intersection of altitudes
# 𝗙ind: coordinates of orthocentre
# 𝗞nown: coordinates of each corner of the triangle
#-------------------------------------------------------------------------------

sub orthoCentre(&$$$$$$)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                       # Subroutine to process results, coordinates of corners
  @_ == 7 or confess "Wrong number of parameters";
  (near($x, $𝘅) && near($y, $𝘆) or near($𝘅, $𝕩) && near($𝘆, $𝕪)) and confess "Corners are too close!";

  &intersectionLines(sub{&$sub(@_)},
    $x, $y, (intersectionLinePoint {@_} $𝘅, $𝘆, $𝕩, $𝕪, $x, $y),
    $𝘅, $𝘆, (intersectionLinePoint {@_} $𝕩, $𝕪, $x, $y, $𝘅, $𝘆));
 }

#-------------------------------------------------------------------------------
# 𝗔rea of a triangle
# 𝗞nown: coordinates of each corner of the triangle
# 𝗙ind: area
# 𝗠ethod: height of one corner from line through other two corners
#-------------------------------------------------------------------------------

sub areaOfTriangle(&$$$$$$)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪) = @_;                                       # Subroutine to process results, coordinates of corners
  @_ == 7 or confess "Wrong number of parameters";
  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
  my ($d) = unsignedDistanceFromLineToPoint(sub {@_}, $𝘅, $𝘆, $𝕩, $𝕪, $x, $y);  # Distance for first corner from opposite line
  &$sub($d * vectorLength($𝘅, $𝘆, $𝕩, $𝕪)/2)                                    # Area = half base * height
 }

#-------------------------------------------------------------------------------
# 𝗔rea of a polygon
# 𝗞nown: coordinates of each corner=vertex of the polygon
# 𝗙ind: area
# 𝗠ethod: divide the polygon into triangles which all share the first vertex
#-------------------------------------------------------------------------------

sub areaOfPolygon(&@)
 {my ($sub, $x, $y, $𝘅, $𝘆, $𝕩, $𝕪, @vertices) = @_;                            # Subroutine to process results, coordinates of vertices
  my ($area) = areaOfTriangle {@_} $x, $y, $𝘅, $𝘆, $𝕩, $𝕪;                      # Area of first triangle
  for(;scalar @vertices;)                                                       # Each subsequent triangle
   {($𝘅, $𝘆) = ($𝕩, $𝕪);                                                        # Move up one vertex at a time
    ($𝕩, $𝕪) = splice @vertices, 0, 2;                                          # Remove one vertex
    my ($a) = areaOfTriangle {@_} $x, $y, $𝘅, $𝘆, $𝕩, $𝕪;                       # Area of latest triangle
    $area += $a;                                                                # Sum areas
   }
  &$sub($area)                                                                  # Area of polygon
 }



( run in 1.061 second using v1.01-cache-2.11-cpan-49f99fa48dc )