You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

polygon.go 2.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. // Copyright 2021 The Gitea Authors. All rights reserved.
  2. // Use of this source code is governed by a MIT-style
  3. // license that can be found in the LICENSE file.
  4. // Copied and modified from https://github.com/issue9/identicon/ (MIT License)
  5. package identicon
  6. var (
  7. // cos(0),cos(90),cos(180),cos(270)
  8. cos = []int{1, 0, -1, 0}
  9. // sin(0),sin(90),sin(180),sin(270)
  10. sin = []int{0, 1, 0, -1}
  11. )
  12. // rotate the points by center point (x,y)
  13. // angle: [0,1,2,3] means [0,90,180,270] degree
  14. func rotate(points []int, x, y int, angle int) {
  15. // the angle is only used internally, and it has been guaranteed to be 0/1/2/3, so we do not check it again
  16. for i := 0; i < len(points); i += 2 {
  17. px, py := points[i]-x, points[i+1]-y
  18. points[i] = px*cos[angle] - py*sin[angle] + x
  19. points[i+1] = px*sin[angle] + py*cos[angle] + y
  20. }
  21. }
  22. // check whether the point is inside the polygon (defined by the points)
  23. // the first and the last point must be the same
  24. func pointInPolygon(x, y int, polygonPoints []int) bool {
  25. if len(polygonPoints) < 8 { // a valid polygon must have more than 2 points
  26. return false
  27. }
  28. // reference: nonzero winding rule, https://en.wikipedia.org/wiki/Nonzero-rule
  29. // split the plane into two by the check point horizontally:
  30. // y>0,includes (x>0 && y==0)
  31. // y<0,includes (x<0 && y==0)
  32. //
  33. // then scan every point in the polygon.
  34. //
  35. // if current point and previous point are in different planes (eg: curY>0 && prevY<0),
  36. // check the clock-direction from previous point to current point (use check point as origin).
  37. // if the direction is clockwise, then r++, otherwise then r--
  38. // finally, if 2==abs(r), then the check point is inside the polygon
  39. r := 0
  40. prevX, prevY := polygonPoints[0], polygonPoints[1]
  41. prev := (prevY > y) || ((prevX > x) && (prevY == y))
  42. for i := 2; i < len(polygonPoints); i += 2 {
  43. currX, currY := polygonPoints[i], polygonPoints[i+1]
  44. curr := (currY > y) || ((currX > x) && (currY == y))
  45. if curr == prev {
  46. prevX, prevY = currX, currY
  47. continue
  48. }
  49. if mul := (prevX-x)*(currY-y) - (currX-x)*(prevY-y); mul >= 0 {
  50. r++
  51. } else { // mul < 0
  52. r--
  53. }
  54. prevX, prevY = currX, currY
  55. prev = curr
  56. }
  57. return r == 2 || r == -2
  58. }