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