gitea

Development moved to Codeberg

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24
  25. 25
  26. 26
  27. 27
  28. 28
  29. 29
  30. 30
  31. 31
  32. 32
  33. 33
  34. 34
  35. 35
  36. 36
  37. 37
  38. 38
  39. 39
  40. 40
  41. 41
  42. 42
  43. 43
  44. 44
  45. 45
  46. 46
  47. 47
  48. 48
  49. 49
  50. 50
  51. 51
  52. 52
  53. 53
  54. 54
  55. 55
  56. 56
  57. 57
  58. 58
  59. 59
  60. 60
  61. 61
  62. 62
  63. 63
  64. 64
  65. 65
  66. 66
  67. 67
  68. 68
// Copyright 2021 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

// Copied and modified from https://github.com/issue9/identicon/ (MIT License)

package identicon

var (
	// cos(0),cos(90),cos(180),cos(270)
	cos = []int{1, 0, -1, 0}

	// sin(0),sin(90),sin(180),sin(270)
	sin = []int{0, 1, 0, -1}
)

// rotate the points by center point (x,y)
// angle: [0,1,2,3] means [0,90,180,270] degree
func rotate(points []int, x, y, angle int) {
	// the angle is only used internally, and it has been guaranteed to be 0/1/2/3, so we do not check it again
	for i := 0; i < len(points); i += 2 {
		px, py := points[i]-x, points[i+1]-y
		points[i] = px*cos[angle] - py*sin[angle] + x
		points[i+1] = px*sin[angle] + py*cos[angle] + y
	}
}

// check whether the point is inside the polygon (defined by the points)
// the first and the last point must be the same
func pointInPolygon(x, y int, polygonPoints []int) bool {
	if len(polygonPoints) < 8 { // a valid polygon must have more than 2 points
		return false
	}

	// reference: nonzero winding rule, https://en.wikipedia.org/wiki/Nonzero-rule
	// split the plane into two by the check point horizontally:
	//   y>0,includes (x>0 && y==0)
	//   y<0,includes (x<0 && y==0)
	//
	// then scan every point in the polygon.
	//
	// if current point and previous point are in different planes (eg: curY>0 && prevY<0),
	// check the clock-direction from previous point to current point (use check point as origin).
	// if the direction is clockwise, then r++, otherwise then r--
	// finally, if 2==abs(r), then the check point is inside the polygon

	r := 0
	prevX, prevY := polygonPoints[0], polygonPoints[1]
	prev := (prevY > y) || ((prevX > x) && (prevY == y))
	for i := 2; i < len(polygonPoints); i += 2 {
		currX, currY := polygonPoints[i], polygonPoints[i+1]
		curr := (currY > y) || ((currX > x) && (currY == y))

		if curr == prev {
			prevX, prevY = currX, currY
			continue
		}

		if mul := (prevX-x)*(currY-y) - (currX-x)*(prevY-y); mul >= 0 {
			r++
		} else { // mul < 0
			r--
		}
		prevX, prevY = currX, currY
		prev = curr
	}

	return r == 2 || r == -2
}