Task: Circles of given radius through two points


C++: #include <iostream>
#include <cmath>
#include <tuple>

struct point { double x, y; };

bool operator==(const point& lhs, const point& rhs)
{ return std::tie(lhs.x, lhs.y) == std::tie(rhs.x, rhs.y); }

enum result_category { NONE, ONE_COINCEDENT, ONE_DIAMETER, TWO, INFINITE };

using result_t = std::tuple<result_category, point, point>;

double distance(point l, point r)
{ return std::hypot(l.x - r.x, l.y - r.y); }

result_t find_circles(point p1, point p2, double r)
{
    point ans1 { 1/0., 1/0.}, ans2 { 1/0., 1/0.};
    if (p1 == p2) {
        if(r == 0.) return std::make_tuple(ONE_COINCEDENT, p1,   p2  );
        else        return std::make_tuple(INFINITE,       ans1, ans2);
    }
    point center { p1.x/2 + p2.x/2, p1.y/2 + p2.y/2};
    double half_distance = distance(center, p1);
    if(half_distance > r)      return std::make_tuple(NONE,         ans1,   ans2);
    if(half_distance - r == 0) return std::make_tuple(ONE_DIAMETER, center, ans2);
    double root = sqrt(pow(r, 2.l) - pow(half_distance, 2.l)) / distance(p1, p2);
    ans1.x = center.x + root * (p1.y - p2.y);
    ans1.y = center.y + root * (p2.x - p1.x);
    ans2.x = center.x - root * (p1.y - p2.y);
    ans2.y = center.y - root * (p2.x - p1.x);
    return std::make_tuple(TWO, ans1, ans2);
}

void print(result_t result, std::ostream& out = std::cout)
{
    point r1, r2; result_category res;
    std::tie(res, r1, r2) = result;
    switch(res) {
      case NONE:
        out << "There are no solutions, points are too far away\n"; break;
      case ONE_COINCEDENT: case ONE_DIAMETER:
        out << "Only one solution: " << r1.x << ' ' << r1.y << '\n'; break;
      case INFINITE:
        out << "Infinitely many circles can be drawn\n"; break;
      case TWO:
        out << "Two solutions: " << r1.x << ' ' << r1.y << " and " << r2.x << ' ' << r2.y << '\n'; break;
    }
}

int main()
{
    constexpr int size = 5;
    const point points[size*2] = {
        {0.1234, 0.9876}, {0.8765, 0.2345}, {0.0000, 2.0000}, {0.0000, 0.0000},
        {0.1234, 0.9876}, {0.1234, 0.9876}, {0.1234, 0.9876}, {0.8765, 0.2345},
        {0.1234, 0.9876}, {0.1234, 0.9876}
    };
    const double radius[size] = {2., 1., 2., .5, 0.};

    for(int i = 0; i < size; ++i)
        print(find_circles(points[i*2], points[i*2 + 1], radius[i]));
}









Fortran: 

program circles
implicit none
double precision :: P1(2), P2(2), R

P1 = (/0.1234d0, 0.9876d0/)
P2 = (/0.8765d0,0.2345d0/)
R = 2.0d0
call print_centers(P1,P2,R)

P1 = (/0.0d0, 2.0d0/)
P2 = (/0.0d0,0.0d0/)
R = 1.0d0
call print_centers(P1,P2,R)

P1 = (/0.1234d0, 0.9876d0/)
P2 = (/0.1234d0, 0.9876d0/)
R = 2.0d0
call print_centers(P1,P2,R)

P1 = (/0.1234d0, 0.9876d0/)
P2 = (/0.8765d0, 0.2345d0/)
R = 0.5d0
call print_centers(P1,P2,R)

P1 = (/0.1234d0, 0.9876d0/)
P2 = (/0.1234d0, 0.9876d0/)
R = 0.0d0
call print_centers(P1,P2,R)
end program circles

subroutine print_centers(P1,P2,R)
implicit none
double precision :: P1(2), P2(2), R, Center(2,2)
integer :: Res
call test_inputs(P1,P2,R,Res)
write(*,*)
write(*,'(A10,F7.4,A1,F7.4)') 'Point1  : ', P1(1), ' ', P1(2)
write(*,'(A10,F7.4,A1,F7.4)') 'Point2  : ', P2(1), ' ', P2(2)
write(*,'(A10,F7.4)') 'Radius  : ', R
if(Res.eq.1) then
  write(*,*) 'Same point because P1=P2 and r=0.'
elseif(Res.eq.2) then
  write(*,*) 'No circles can be drawn because r=0.'
elseif(Res.eq.3) then
  write(*,*) 'Infinite circles because P1=P2 for non-zero radius.'
elseif(Res.eq.4) then
  write(*,*) 'No circles with given r can be drawn because points are far apart.'
elseif(Res.eq.0) then
  call find_center(P1,P2,R,Center)
  if(Center(1,1).eq.Center(2,1) .and. Center(1,2).eq.Center(2,2)) then
    write(*,*) 'Points lie on the diameter. A single circle can be drawn.'
    write(*,'(A10,F7.4,A1,F7.4)') 'Center  : ', Center(1,1), ' ', Center(1,2)
  else
    write(*,*) 'Two distinct circles found.'
    write(*,'(A10,F7.4,A1,F7.4)') 'Center1 : ', Center(1,1), ' ', Center(1,2)
    write(*,'(A10,F7.4,A1,F7.4)') 'Center2 : ', Center(2,1), ' ', Center(2,2)
  end if
elseif(Res.lt.0) then
  write(*,*) 'Incorrect value for r.'
end if
write(*,*)
end subroutine print_centers

subroutine test_inputs(P1,P2,R,Res)
implicit none
double precision :: P1(2), P2(2), R, dist
integer :: Res
if(R.lt.0.0d0) then
  Res = -1
  return
elseif(R.eq.0.0d0 .and. P1(1).eq.P2(1) .and. P1(2).eq.P2(2)) then
  Res = 1
  return
elseif(R.eq.0.0d0) then
  Res = 2
  return
elseif(P1(1).eq.P2(1) .and. P1(2).eq.P2(2)) then
  Res = 3
  return
else
  dist = sqrt( (P1(1)-P2(1))**2 + (P1(2)-P2(2))**2 )
  if(dist.gt.2.0d0*R) then
    Res = 4
    return
  else
    Res = 0
    return
  end if
end if
end subroutine test_inputs

subroutine find_center(P1,P2,R,Center)
implicit none
double precision :: P1(2), P2(2), MP(2), Center(2,2), R, dm, dd
MP = (P1 + P2)/2.0d0
dm = sqrt((P1(1) - P2(1))**2 + (P1(2) - P2(2))**2)
dd = sqrt(R**2 - (dm/2.0d0)**2)
Center(1,1) = MP(1) - dd*(P2(2) - P1(2))/dm
Center(1,2) = MP(2) + dd*(P2(1) - P1(1))/dm

Center(2,1) = MP(1) + dd*(P2(2) - P1(2))/dm
Center(2,2) = MP(2) - dd*(P2(1) - P1(1))/dm
end subroutine find_center