diff options
Diffstat (limited to 'modules/avatar/identicon/polygon.go')
-rw-r--r-- | modules/avatar/identicon/polygon.go | 69 |
1 files changed, 69 insertions, 0 deletions
diff --git a/modules/avatar/identicon/polygon.go b/modules/avatar/identicon/polygon.go new file mode 100644 index 0000000000..02890737da --- /dev/null +++ b/modules/avatar/identicon/polygon.go @@ -0,0 +1,69 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +// 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 int, 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 +} |