Circles of given radius through two points: Difference between revisions

From Rosetta Code
Content added Content deleted
(Update to task description to add to special case exceptions to be handled.)
(→‎{{header|Python}}: Update to handle r==0.0 special case.)
Line 22: Line 22:


=={{header|Python}}==
=={{header|Python}}==
The function raises the ValueError exception for the special cases and usess try - except to catch these and extract the exception detail.

<lang python>from collections import namedtuple
<lang python>from collections import namedtuple
from math import sqrt
from math import sqrt
Line 30: Line 32:
def circles_from_p1p2r(p1, p2, r):
def circles_from_p1p2r(p1, p2, r):
'Following explanation at http://mathforum.org/library/drmath/view/53027.html'
'Following explanation at http://mathforum.org/library/drmath/view/53027.html'
if r == 0.0:
raise ValueError('radius of zero')
(x1, y1), (x2, y2) = p1, p2
(x1, y1), (x2, y2) = p1, p2
if p1 == p2:
if p1 == p2:
Line 56: Line 60:
for p1, p2, r in [(Pt(0.1234, 0.9876), Pt(0.8765, 0.2345), 2.0),
for p1, p2, r in [(Pt(0.1234, 0.9876), Pt(0.8765, 0.2345), 2.0),
(Pt(0.1234, 0.9876), Pt(0.1234, 0.9876), 2.0),
(Pt(0.1234, 0.9876), Pt(0.1234, 0.9876), 2.0),
(Pt(0.1234, 0.9876), Pt(0.8765, 0.2345), 0.5)]:
(Pt(0.1234, 0.9876), Pt(0.8765, 0.2345), 0.5),
(Pt(0.1234, 0.9876), Pt(0.1234, 0.9876), 0.0)]:
print('Through points:\n %r,\n %r\n and radius %f\nYou can construct the following circles:'
print('Through points:\n %r,\n %r\n and radius %f\nYou can construct the following circles:'
% (p1, p2, r))
% (p1, p2, r))
Line 93: Line 98:
and radius 0.500000
and radius 0.500000
You can construct the following circles:
You can construct the following circles:
ERROR: separation of points > diameter</pre>
ERROR: separation of points > diameter

Through points:
Pt(x=0.1234, y=0.9876),
Pt(x=0.1234, y=0.9876)
and radius 0.000000
You can construct the following circles:
ERROR: radius of zero</pre>

Revision as of 05:25, 17 April 2013

Circles of given radius through two points is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

Given two points on a plane and a radius, usually two circles of given radius can be drawn through the points.

Exceptions
  1. r==0.0 should be treated as never describing circles.
  2. If the points are coincident then an infinite number of circles with the point on their circumference can be drawn, unless r==0.0 as well which then collapses the circles to a point.
  3. If the points form a diameter then return two identical circles.
  4. If the points are too far apart then no circles can be drawn.
Task detail
  • Write a function/subroutine/method/... that takes two points and a radius and returns the two circles through those points, or some indication of special cases where two, possibly equal, circles cannot be returned.
  • Show here the output for the following inputs:
      p1                p2           r
0.1234, 0.9876    0.8765, 0.2345    2.0
0.0000, 2.0000    0.0000, 0.0000    1.0
0.1234, 0.9876    0.1234, 0.9876    2.0
0.1234, 0.9876    0.8765, 0.2345    0.5
0.1234, 0.9876    0.1234, 0.9876    0.0
Ref

Python

The function raises the ValueError exception for the special cases and usess try - except to catch these and extract the exception detail.

<lang python>from collections import namedtuple from math import sqrt

Pt = namedtuple('Pt', 'x, y') Circle = Cir = namedtuple('Circle', 'x, y, r')

def circles_from_p1p2r(p1, p2, r):

   'Following explanation at http://mathforum.org/library/drmath/view/53027.html'
   if r == 0.0:
       raise ValueError('radius of zero')
   (x1, y1), (x2, y2) = p1, p2
   if p1 == p2:
       raise ValueError('coincident points gives infinite number of Circles')
   # delta x, delta y between points
   dx, dy = x2 - x1, y2 - y1
   # dist between points
   q = sqrt(dx**2 + dy**2)
   if q > 2.0*r:
       raise ValueError('separation of points > diameter')
   # halfway point
   x3, y3 = (x1+x2)/2, (y1+y2)/2
   # distance along the mirror line
   d = sqrt(r**2-(q/2)**2)
   # One answer
   c1 = Cir(x = x3 - d*dy/q,
            y = y3 + d*dx/q,
            r = abs(r))
   # The other answer
   c2 = Cir(x = x3 + d*dy/q,
            y = y3 - d*dx/q,
            r = abs(r))
   return c1, c2

if __name__ == '__main__':

   for p1, p2, r in [(Pt(0.1234, 0.9876), Pt(0.8765, 0.2345), 2.0),
                     (Pt(0.1234, 0.9876), Pt(0.1234, 0.9876), 2.0),
                     (Pt(0.1234, 0.9876), Pt(0.8765, 0.2345), 0.5),
                     (Pt(0.1234, 0.9876), Pt(0.1234, 0.9876), 0.0)]:
       print('Through points:\n  %r,\n  %r\n  and radius %f\nYou can construct the following circles:'
             % (p1, p2, r))
       try:
           print('  %r\n  %r\n' % circles_from_p1p2r(p1, p2, r))
       except ValueError as v:
           print('  ERROR: %s\n' % (v.args[0],))</lang>
Output:
Through points:
  Pt(x=0.1234, y=0.9876),
  Pt(x=0.8765, y=0.2345)
  and radius 2.000000
You can construct the following circles:
  Circle(x=1.8631118016581893, y=1.974211801658189, r=2.0)
  Circle(x=-0.8632118016581896, y=-0.7521118016581892, r=2.0)

Through points:
  Pt(x=0.0, y=2.0),
  Pt(x=0.0, y=0.0)
  and radius 1.000000
You can construct the following circles:
  Circle(x=0.0, y=1.0, r=1.0)
  Circle(x=0.0, y=1.0, r=1.0)

Through points:
  Pt(x=0.1234, y=0.9876),
  Pt(x=0.1234, y=0.9876)
  and radius 2.000000
You can construct the following circles:
  ERROR: coincident points gives infinite number of Circles

Through points:
  Pt(x=0.1234, y=0.9876),
  Pt(x=0.8765, y=0.2345)
  and radius 0.500000
You can construct the following circles:
  ERROR: separation of points > diameter

Through points:
  Pt(x=0.1234, y=0.9876),
  Pt(x=0.1234, y=0.9876)
  and radius 0.000000
You can construct the following circles:
  ERROR: radius of zero