77 lines
1.6 KiB
Go
77 lines
1.6 KiB
Go
package main
|
|
|
|
import (
|
|
"math"
|
|
"fmt"
|
|
)
|
|
|
|
type xy struct {
|
|
x, y float64
|
|
}
|
|
|
|
type closedPoly struct {
|
|
name string
|
|
vert []xy
|
|
}
|
|
|
|
func inside(pt xy, pg closedPoly) bool {
|
|
if len(pg.vert) < 3 {
|
|
return false
|
|
}
|
|
in := rayIntersectsSegment(pt, pg.vert[len(pg.vert)-1], pg.vert[0])
|
|
for i := 1; i < len(pg.vert); i++ {
|
|
if rayIntersectsSegment(pt, pg.vert[i-1], pg.vert[i]) {
|
|
in = !in
|
|
}
|
|
}
|
|
return in
|
|
}
|
|
|
|
func rayIntersectsSegment(p, a, b xy) bool {
|
|
if a.y > b.y {
|
|
a, b = b, a
|
|
}
|
|
for p.y == a.y || p.y == b.y {
|
|
p.y = math.Nextafter(p.y, math.Inf(1))
|
|
}
|
|
if p.y < a.y || p.y > b.y {
|
|
return false
|
|
}
|
|
if a.x > b.x {
|
|
if p.x > a.x {
|
|
return false
|
|
}
|
|
if p.x < b.x {
|
|
return true
|
|
}
|
|
} else {
|
|
if p.x > b.x {
|
|
return false
|
|
}
|
|
if p.x < a.x {
|
|
return true
|
|
}
|
|
}
|
|
return (p.y-a.y)/(p.x-a.x) >= (b.y-a.y)/(b.x-a.x)
|
|
}
|
|
|
|
var tpg = []closedPoly{
|
|
{"square", []xy{{0, 0}, {10, 0}, {10, 10}, {0, 10}}},
|
|
{"square hole", []xy{{0, 0}, {10, 0}, {10, 10}, {0, 10}, {0, 0},
|
|
{2.5, 2.5}, {7.5, 2.5}, {7.5, 7.5}, {2.5, 7.5}, {2.5, 2.5}}},
|
|
{"strange", []xy{{0, 0}, {2.5, 2.5}, {0, 10}, {2.5, 7.5}, {7.5, 7.5},
|
|
{10, 10}, {10, 0}, {2.5, 2.5}}},
|
|
{"exagon", []xy{{3, 0}, {7, 0}, {10, 5}, {7, 10}, {3, 10}, {0, 5}}},
|
|
}
|
|
|
|
var tpt = []xy{{1, 2}, {2, 1}}
|
|
|
|
func main() {
|
|
for _, pg := range tpg {
|
|
fmt.Printf("%s:\n", pg.name)
|
|
for _, pt := range tpt {
|
|
fmt.Println(pt, inside(pt, pg))
|
|
}
|
|
}
|
|
}
|