package geoimport ()//nolint:forbidigotypeRelativePointstruct { XPercentage float64 YPercentage float64}func (, float64) *RelativePoint {// 3 decimal points of precision is enough. Floating points on Bezier curves can reach the level of precision where different machines round differently.return &RelativePoint{XPercentage: TruncateDecimals(),YPercentage: TruncateDecimals(), }}typePointstruct { X float64`json:"x"` Y float64`json:"y"`}func (, float64) *Point {return &Point{X: , Y: }}func ( *Point) ( *Point) bool {if == nil {return == nil } elseif == nil {returnfalse }return (.X == .X) && (.Y == .Y)}func ( *Point) ( *Point) int { := Sign(.X - .X)if == 0 {returnSign(.Y - .Y) }return}func ( *Point) () *Point {return &Point{X: .X, Y: .Y}}typePoints []*Pointfunc ( Points) ( Points) bool {if == nil {return == nil } elseif == nil {returnfalse } := make(map[Point]struct{})for , := range { [*] = struct{}{} }for , := range {if , := [*]; ! {returnfalse } }returntrue}func ( Points) () *Point { := make([]float64, 0) := make([]float64, 0)for , := range { = append(, .X) = append(, .Y) }sort.Float64s()sort.Float64s() := len() / 2 := [] := []iflen()%2 == 0 { += [-1] /= 2 += [-1] /= 2 }return &Point{X: , Y: }}// GetOrientation gets orientation of pFrom to pTo// E.g. pFrom ---> pTo, here, pFrom is to the left of pTo, so Left would be returnedfunc ( *Point) ( *Point) Orientation {if .Y < .Y {if .X < .X {returnTopLeft }if .X > .X {returnTopRight }returnTop }if .Y > .Y {if .X < .X {returnBottomLeft }if .X > .X {returnBottomRight }returnBottom }if .X < .X {returnLeft }if .X > .X {returnRight }returnNONE}func ( *Point) () string {if == nil {return"" }returnfmt.Sprintf("(%v, %v)", .X, .Y)}func ( Points) () string { := make([]string, 0, len())for , := range { = append(, .ToString()) }returnstrings.Join(, ", ")}// https://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segmentfunc ( *Point) (, *Point) float64 { := .X - .X := .Y - .Y := .X - .X := .Y - .Y := ( * ) + ( * ) := ( * ) + ( * ) := -1.0if != 0 { = / }varfloat64varfloat64if < 0.0 { = .X = .Y } elseif > 1.0 { = .X = .Y } else { = .X + ( * ) = .Y + ( * ) } := .X - := .Y - returnmath.Sqrt(( * ) + ( * ))}// Moves the given point by Vectorfunc ( *Point) ( Vector) *Point {return .ToVector().Add().ToPoint()}// Creates a Vector of the size between start and endpoint, pointing to endpointfunc ( *Point) ( *Point) Vector {return .ToVector().Minus(.ToVector())}func ( *Point) () string {returnfmt.Sprintf("%d,%d", int(.X), int(.Y))}// returns true if point p is on orthogonal segment between points a and bfunc ( *Point) (, *Point) bool {if .X < .X {if .X < .X || .X < .X {returnfalse } } elseif .X < .X || .X < .X {returnfalse }if .Y < .Y {if .Y < .Y || .Y < .Y {returnfalse } } elseif .Y < .Y || .Y < .Y {returnfalse }returntrue}// Creates a Vector pointing to pointfunc ( *Point) () Vector {return []float64{.X, .Y}}// get the point of intersection between line segments u and v (or nil if they do not intersect)func (, , , *Point) *Point {// https://en.wikipedia.org/wiki/Intersection_(Euclidean_geometry) // // Example ('-' = 1, '|' = 1): // v0 // | //u0 -+--- u1 // | // | // v1 // // s = 0.2 (1/5 along u) // t = 0.25 (1/4 along v) // we compute s and t and if they are both in range [0,1], then // they intersect and we compute the point of intersection to return// when s = 0, x = u.Start.X; when s = 1, x = u.End.X // x = s * u1.X + (1 - s) * u0.X // = u0.X + s * (u1.X - u0.X)// x = u0.X + s * (u1.X - u0.X) // = v0.X + t * (v1.X - v0.X) // y = u0.Y + s * (u1.Y - u0.Y) // = v0.Y + t * (v1.Y - v0.Y)// s * (u1.X - u0.X) - t * (v1.X - v0.X) = v0.X - u0.X // s*udx - t*vdx = uvdx // s*udy - t*vdy = uvdy := .X - .X := .X - .X := .X - .X := .Y - .Y := .Y - .Y := .Y - .Y := (* - *)if == 0 {// lines are parallelreturnnil }// Cramer's rule := (* - *) / := (* - *) / // lines don't intersect within segmentsif < 0 || > 1 || < 0 || > 1 {// if s or t is outside [0, 1], the intersection of the lines are not on the segmentsreturnnil }// use s parameter to get point along u := new(Point) .X = .X + math.Round(*) .Y = .Y + math.Round(*)return}func ( *Point) () {if == nil {return } .X, .Y = .Y, .X}// point t% of the way between a and bfunc ( *Point) ( *Point, float64) *Point {returnNewPoint( .X*(1.0-)+.X*, .Y*(1.0-)+.Y*, )}func ( *Point) () { .X = float64(float32(.X)) .Y = float64(float32(.Y))}func ( *Point) () { .X = TruncateDecimals(.X) .Y = TruncateDecimals(.Y)}// RemovePoints returns a new Points slice without the points in toRemovefunc ( Points, []bool) Points { := len()for , := range {if { -- } } := make([]*Point, 0, )for := 0; < len(); ++ {if [] {continue } = append(, []) }return}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.