sutherland_hodgman.sf 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/Sutherland-Hodgman_polygon_clipping
  4. #
  5. class Point(x, y) {
  6. method to_s {
  7. "(#{'%.2f' % x}, #{'%.2f' % y})"
  8. }
  9. }
  10. func sutherland_hodgman(subjectPolygon, clipPolygon) {
  11. var inside = { |cp1, cp2, p|
  12. ((cp2.x-cp1.x)*(p.y-cp1.y)) > ((cp2.y-cp1.y)*(p.x-cp1.x))
  13. }
  14. var intersection = { |cp1, cp2, s, e|
  15. var (dcx, dcy) = (cp1.x-cp2.x, cp1.y-cp2.y)
  16. var (dpx, dpy) = (s.x-e.x, s.y-e.y)
  17. var n1 = (cp1.x*cp2.y - cp1.y*cp2.x)
  18. var n2 = (s.x*e.y - s.y*e.x)
  19. var n3 = (1 / (dcx*dpy - dcy*dpx))
  20. Point((n1*dpx - n2*dcx) * n3, (n1*dpy - n2*dcy) * n3)
  21. }
  22. var outputList = subjectPolygon
  23. var cp1 = clipPolygon.last
  24. for cp2 in clipPolygon {
  25. var inputList = outputList
  26. outputList = []
  27. var s = inputList.last
  28. for e in inputList {
  29. if (inside(cp1, cp2, e)) {
  30. outputList << intersection(cp1, cp2, s, e) if !inside(cp1, cp2, s)
  31. outputList << e
  32. }
  33. elsif(inside(cp1, cp2, s)) {
  34. outputList << intersection(cp1, cp2, s, e)
  35. }
  36. s = e
  37. }
  38. cp1 = cp2
  39. }
  40. outputList
  41. }
  42. var subjectPolygon = [
  43. [50, 150], [200, 50], [350, 150], [350, 300],
  44. [250, 300], [200, 250], [150, 350], [100, 250],
  45. [100, 200]
  46. ].map{|pnt| Point(pnt...) }
  47. var clipPolygon = [
  48. [100, 100], [300, 100],
  49. [300, 300], [100, 300]
  50. ].map{|pnt| Point(pnt...) }
  51. sutherland_hodgman(subjectPolygon, clipPolygon).each { .say }