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

Exceptions

 r==0.0 should be treated as never describing circles (except in the case where the points are coincident).
 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.
 If the points form a diameter then return two identical circles or return a single circle, according to which is the most natural mechanism for the implementation language.
 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



Related task

   Total circles area.


See also

   Finding the Center of a Circle from 2 Points and Radius from Math forum @ Drexel


 
LOCAL p1 As point, p2 As point, rr As Double
CLOSE DATABASES ALL
SET FIXED ON
SET DECIMALS TO 4
CLEAR
CREATE CURSOR circles (xc1 B(4), yc1 B(4), xc2 B(4), yc2 B(4), rad B(4))
INSERT INTO circles VALUES (0.1234, 0.9876, 0.8765, 0.2345, 2.0)
INSERT INTO circles VALUES (0.0000, 2.0000, 0.0000, 0.0000, 1.0)
INSERT INTO circles VALUES (0.1234, 0.9876, 0.1234, 0.9876, 2.0)
INSERT INTO circles VALUES (0.1234, 0.9876, 0.8765, 0.2345, 0.5)
INSERT INTO circles VALUES (0.1234, 0.9876, 0.1234, 0.9876, 0.0)
GO TOP
 
p1 = NEWOBJECT("point")
p2 = NEWOBJECT("point")
SCAN
    p1.SetPoints(xc1, yc1)
    p2.SetPoints(xc2, yc2)
    rr = rad
    GetCircles(p1, p2, rr)
    ?
ENDSCAN 	
 
SET DECIMALS TO 
SET FIXED OFF
 
PROCEDURE GetCircles(op1 As point, op2 As point, r As Double)
LOCAL ctr As point, half As point, lenhalf As Double, dist As Double, rot As point, c As String
ctr = NEWOBJECT("point")
half = NEWOBJECT("point")
ctr.SetPoints((op1.xc + op2.xc)/2, (op1.yc + op2.yc)/2)
half.SetPoints(op1.xc - ctr.xc, op1.yc - ctr.yc)
lenhalf = half.nLength
PrintPoints(op1, op2, r)
IF r < lenhalf
    ? "Cannot solve for these parameters."
    RETURN
ENDIF
IF lenhalf = 0
    ? "Points are coincident."
    RETURN
ENDIF
dist = SQRT(r^2 - lenhalf^2)/lenhalf
rot = NEWOBJECT("point")
rot.SetPoints(-dist*(op1.yc - ctr.yc) + ctr.xc, dist*(op1.xc - ctr.xc) + ctr.yc)
TEXT TO c TEXTMERGE NOSHOW PRETEXT 3
    Circle 1 (<<rot.xc>>, <<rot.yc>>)
ENDTEXT
? c
rot.SetPoints(-(rot.xc - ctr.xc) + ctr.xc, -((rot.yc - ctr.yc)) + ctr.yc)
TEXT TO c TEXTMERGE NOSHOW PRETEXT 3
    Circle 2 (<<rot.xc>>, <<rot.yc>>)
ENDTEXT
? c
ENDPROC
 
PROCEDURE PrintPoints(op1 As point, op2 As point, r As Double)
LOCAL lcTxt As String
TEXT TO lcTxt TEXTMERGE NOSHOW PRETEXT 3
    Points (<<op1.xc>>,<<op1.yc>>), (<<op2.xc>>,<<op2.yc>>) Radius <<r>>.
ENDTEXT
? lcTxt
ENDPROC	
 
DEFINE CLASS point As Custom
xc = 0
yc = 0
nLength = 0
 
PROCEDURE Init
DODEFAULT()
ENDPROC
 
PROCEDURE SetPoints(tnx As Double, tny As Double)
THIS.xc = tnx
THIS.yc = tny
THIS.nLength = THIS.GetLength()
ENDPROC
 
FUNCTION GetLength()
RETURN SQRT(THIS.xc*THIS.xc + THIS.yc*THIS.yc)
ENDFUNC
 
ENDDEFINE
 