mirror of https://github.com/tidwall/tile38.git
122 lines
2.0 KiB
Go
122 lines
2.0 KiB
Go
|
package poly
|
||
|
|
||
|
// This implementation of the raycast algorithm test if a point is
|
||
|
// to the left of a line, or on the segment line. Otherwise it is
|
||
|
// assumed that the point is outside of the segment line.
|
||
|
|
||
|
type rayres int
|
||
|
|
||
|
func (r rayres) String() string {
|
||
|
switch r {
|
||
|
default:
|
||
|
return "unknown"
|
||
|
case out:
|
||
|
return "out"
|
||
|
case left:
|
||
|
return "left"
|
||
|
case on:
|
||
|
return "on"
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const (
|
||
|
out = rayres(0) // outside of the segment.
|
||
|
left = rayres(1) // to the left of the segment
|
||
|
on = rayres(2) // on segment or vertex, special condition
|
||
|
)
|
||
|
|
||
|
func raycast(p, a, b Point) rayres {
|
||
|
if a.Y == b.Y {
|
||
|
// A and B share the same Y plane.
|
||
|
if a.X == b.X {
|
||
|
// AB is just a point.
|
||
|
if p.X == a.X && p.Y == a.Y {
|
||
|
return on
|
||
|
}
|
||
|
return out
|
||
|
}
|
||
|
// AB is a horizontal line.
|
||
|
if p.Y != a.Y {
|
||
|
// P is not on same Y plane as A and B.
|
||
|
return out
|
||
|
}
|
||
|
// P is on same Y plane as A and B
|
||
|
if a.X < b.X {
|
||
|
if p.X >= a.X && p.X <= b.X {
|
||
|
return on
|
||
|
}
|
||
|
if p.X < a.X {
|
||
|
return left
|
||
|
}
|
||
|
} else {
|
||
|
if p.X >= b.X && p.X <= a.X {
|
||
|
return on
|
||
|
}
|
||
|
if p.X < b.X {
|
||
|
return left
|
||
|
}
|
||
|
}
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
if a.X == b.X {
|
||
|
// AB is a vertical line.
|
||
|
if a.Y > b.Y {
|
||
|
// A is above B
|
||
|
if p.Y > a.Y || p.Y < b.Y {
|
||
|
return out
|
||
|
}
|
||
|
} else {
|
||
|
// B is above A
|
||
|
if p.Y > b.Y || p.Y < a.Y {
|
||
|
return out
|
||
|
}
|
||
|
}
|
||
|
if p.X == a.X {
|
||
|
return on
|
||
|
}
|
||
|
if p.X < a.X {
|
||
|
return left
|
||
|
}
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
// AB is an angled line
|
||
|
if a.Y > b.Y {
|
||
|
// swap A and B so that A is below B.
|
||
|
a.X, a.Y, b.X, b.Y = b.X, b.Y, a.X, a.Y
|
||
|
}
|
||
|
if p.Y < a.Y || p.Y > b.Y {
|
||
|
return out
|
||
|
}
|
||
|
if a.X < b.X {
|
||
|
if p.X < a.X {
|
||
|
return left
|
||
|
}
|
||
|
if p.X > b.X {
|
||
|
return out
|
||
|
}
|
||
|
} else {
|
||
|
if p.X < b.X {
|
||
|
return left
|
||
|
}
|
||
|
if p.X > a.X {
|
||
|
return out
|
||
|
}
|
||
|
}
|
||
|
if (p.X == a.X && p.Y == a.Y) || (p.X == b.X && p.Y == b.Y) {
|
||
|
// P is on a vertex.
|
||
|
return on
|
||
|
}
|
||
|
v1 := (p.Y - a.Y) / (p.X - a.X)
|
||
|
v2 := (b.Y - a.Y) / (b.X - a.X)
|
||
|
if v1-v2 == 0 {
|
||
|
// P is on a segment
|
||
|
return on
|
||
|
}
|
||
|
if v1 >= v2 {
|
||
|
return left
|
||
|
}
|
||
|
return out
|
||
|
}
|