tile38/geojson/poly/raycast.go

122 lines
2.0 KiB
Go
Raw Normal View History

2016-03-05 02:08:16 +03:00
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
}