三点定圆的Racket实现

51 篇文章 16 订阅

一、数学解释

  如何通过三个点确定一个圆? 
  这是一个有趣的几何问题,同时也是计算机图形学要处理的问题。

  这里给出一个求解办法: 
  给出三个点:(spx,spy),(mpx,mpy),(epx,epy) 
  求解圆。 
  根据圆半径(r)、圆心(cpx,cpy)、圆上的一点(x,y)的关系:

  1. (x - cpx)^2 + (y - cpy)^2 = r^2

得出三个等式:

  1. 1):(spx - cpx)^2 + (spy - cpy)^2 = r^2
  2. 2):(mpx - cpx)^2 + (mpy - cpy)^2 = r^2
  3. 3):(epx - cpx)^2 + (epy - cpy)^2 = r^2

解开等式,得:

  1. 1):spx^2 + cpx^2 - 2 * spx * cpx + spy^2 + cpy^2 - 2 * spy * cpy = r^2
  2. 2):mpx^2 + cpx^2 - 2 * mpx * cpx + mpy^2 + cpy^2 - 2 * mpy * cpy = r^2
  3. 3):epx^2 + cpx^2 - 2 * epx * cpx + epy^2 + cpy^2 - 2 * epy * cpy = r^2

执行等式相减1)-2),1)-3),得到:

  1. 4):cpx * (spx - mpx) + cpy * (spy - mpy) =[(spx^2 - mpx^2) + (spy^2 - mpy^2)] / 2
  2. 5):cpx * (spx - epx) + cpy * (spy - epy) =[(spx^2 - epx^2) + (spy^2 - epy^2)] / 2

进行代数替代,设:

  1. smx = spx - mpx
  2. smy = spy - mpy
  3. sex = spx - epx
  4. sey = spy - epy
  5. smxy = [(spx^2 - mpx^2) + (spy^2 - mpy^2)] / 2
  6. sexy = [(spx^2 - epx^2) + (spy^2 - epy^2)] / 2

简化等式为:

  1. 4):smx * cpx + smy * cpy = smxy
  2. 5):sex * cpx + sey * cpy = sexy

则:

  1. 6):cpx = (smxy - smy * cpy) / smx

再计算得到cpy:

  1. cpy = (sexy * smx - sex * smxy) / (smx * sey - sex * smy)

则:

  1. cpx = (smxy * sey - smy * sexy) / (smx * sey - sex * smy)

注:也可以直接将取得的cpy代入式(6)中取得cpx值,计算更简单。 
最后计算r值:

  1. r = [(spx - cpx)^2 + (spy - cpy)^2]^(1/2)

二、程序实现:

根据以上推导,实现如下:

  1. ;3p-circle.rkt
  2. ;三点确定圆:
  3.  
  4. #lang racket
  5.  
  6. (provide
  7. (struct-out point)
  8. 3p-circle)
  9.  
  10. ;Racket实现:==================
  11. ;点结构:
  12. (struct point (x y))
  13. ;三点定圆:
  14. (define (3p-circle sp mp ep)
  15. (let* ([spx (point-x sp)]
  16. [spy (point-y sp)]
  17. [mpx (point-x mp)]
  18. [mpy (point-y mp)]
  19. [epx (point-x ep)]
  20. [epy (point-y ep)]
  21. [smx (- spx mpx)]
  22. [smy (- spy mpy)]
  23. [sex (- spx epx)]
  24. [sey (- spy epy)]
  25. [smxy (/
  26. (+
  27. (- (expt spx 2)
  28. (expt mpx 2))
  29. (- (expt spy 2)
  30. (expt mpy 2)))
  31. 2)]
  32. [sexy (/
  33. (+
  34. (- (expt spx 2)
  35. (expt epx 2))
  36. (- (expt spy 2)
  37. (expt epy 2)))
  38. 2)]
  39. [cpy (/
  40. (- (* sexy smx)
  41. (* smxy sex))
  42. (- (* smx sey)
  43. (* sex smy)))]
  44. [cpx (/
  45. (- smxy (* smy cpy))
  46. smx)]
  47. [r (sqrt
  48. (+
  49. (expt (- cpx epx) 2)
  50. (expt (- cpy epy) 2)))])
  51. (values (point cpx cpy) r)))

三、测试程序

  1. ;test.rkt
  2.  
  3. #lang racket/gui
  4.  
  5. (require racket/draw)
  6. (require "3p-circle.rkt")
  7.  
  8. ;测试:========================
  9. ;定义点:
  10. (define sp (point 498 116))
  11. (define mp (point 181 280))
  12. (define ep (point 290 458))
  13. ;定义视图:
  14. (define main-frame
  15. (new frame%
  16. [label "3点定圆测试"]
  17. [width 800]
  18. [height 600]
  19. [border 5]))
  20. (define canvas
  21. (new canvas%
  22. [parent main-frame]
  23. [paint-callback
  24. (lambda (canvas dc)
  25. (draw-circle/3p dc))]))
  26. ;显示视图:
  27. (send main-frame show #t)
  28.  
  29. ;绘圆:
  30. (define (draw-circle/3p dc)
  31. (let-values ([(cp r)
  32. (3p-circle sp mp ep)])
  33. (send dc set-background "black")
  34. (send dc clear)
  35. ;画圆:
  36. (send dc set-pen "white" 1 'solid);'
  37. (send dc set-brush "white" 'transparent);'
  38. (let* ([x (- (point-x cp) r)]
  39. [y (- (point-y cp) r)]
  40. [w (* r 2)])
  41. (send dc draw-ellipse x y w w))
  42. ;画标志点:
  43. (send dc set-pen "white" 0 'transparent);'
  44. (send dc set-brush "red" 'solid);'
  45. (draw-3ps dc)
  46. (send dc set-pen "red" 1 'solid );'
  47. (draw-center dc cp)))
  48.  
  49. ;画三个点:
  50. (define (draw-3ps dc)
  51. (draw-1p dc sp)
  52. (draw-1p dc mp)
  53. (draw-1p dc ep))
  54.  
  55. ;画单个点:
  56. (define (draw-1p dc p)
  57. (send dc draw-ellipse
  58. (point-x p)
  59. (point-y p)
  60. 6 6))
  61.  
  62. ;画圆心十字叉:
  63. (define (draw-center dc cp)
  64. (let ([x (point-x cp)]
  65. [y (point-y cp)])
  66. (send dc draw-line
  67. x (- y 6)
  68. x (+ y 6))
  69. (send dc draw-line
  70. (- x 6) y
  71. (+ x 6) y)))
  72. ;运行结果:
  73.  

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值