tile38/vendor/github.com/tidwall/geojson/geometry/raycast.go

100 lines
2.1 KiB
Go
Raw Normal View History

2021-02-08 03:54:56 +03:00
package geometry
import "math"
// RaycastResult holds the results of the Raycast operation
type RaycastResult struct {
In bool // point on the left
On bool // point is directly on top of
}
// Raycast performs the raycast operation
func (seg Segment) Raycast(point Point) RaycastResult {
p, a, b := point, seg.A, seg.B
// make sure that the point is inside the segment bounds
if a.Y < b.Y && (p.Y < a.Y || p.Y > b.Y) {
return RaycastResult{false, false}
} else if a.Y > b.Y && (p.Y < b.Y || p.Y > a.Y) {
return RaycastResult{false, false}
}
// test if point is in on the segment
if a.Y == b.Y {
if a.X == b.X {
if p == a {
return RaycastResult{false, true}
}
return RaycastResult{false, false}
}
if p.Y == b.Y {
// horizontal segment
// check if the point in on the line
if a.X < b.X {
if p.X >= a.X && p.X <= b.X {
return RaycastResult{false, true}
}
} else {
if p.X >= b.X && p.X <= a.X {
return RaycastResult{false, true}
}
}
}
}
if a.X == b.X && p.X == b.X {
// vertical segment
// check if the point in on the line
if a.Y < b.Y {
if p.Y >= a.Y && p.Y <= b.Y {
return RaycastResult{false, true}
}
} else {
if p.Y >= b.Y && p.Y <= a.Y {
return RaycastResult{false, true}
}
}
}
if (p.X-a.X)/(b.X-a.X) == (p.Y-a.Y)/(b.Y-a.Y) {
return RaycastResult{false, true}
}
// do the actual raycast here.
for p.Y == a.Y || p.Y == b.Y {
p.Y = math.Nextafter(p.Y, math.Inf(1))
}
if a.Y < b.Y {
if p.Y < a.Y || p.Y > b.Y {
return RaycastResult{false, false}
}
} else {
if p.Y < b.Y || p.Y > a.Y {
return RaycastResult{false, false}
}
}
if a.X > b.X {
if p.X >= a.X {
return RaycastResult{false, false}
}
if p.X <= b.X {
return RaycastResult{true, false}
}
} else {
if p.X >= b.X {
return RaycastResult{false, false}
}
if p.X <= a.X {
return RaycastResult{true, false}
}
}
if a.Y < b.Y {
if (p.Y-a.Y)/(p.X-a.X) >= (b.Y-a.Y)/(b.X-a.X) {
return RaycastResult{true, false}
}
} else {
if (p.Y-b.Y)/(p.X-b.X) >= (a.Y-b.Y)/(a.X-b.X) {
return RaycastResult{true, false}
}
}
return RaycastResult{false, false}
}