Files

78 lines
2.1 KiB
Go

package area
import (
"fmt"
"math"
)
const epsilon = 1e-9
func ValidateGeometry(kind, direction string, points []Point) error {
for _, point := range points {
if point.X < 0 || point.X > 1 || point.Y < 0 || point.Y > 1 {
return fmt.Errorf("坐标必须位于画面范围内")
}
}
switch kind {
case KindPolygon:
if len(points) < 3 {
return fmt.Errorf("多边形至少需要 3 个点")
}
if math.Abs(polygonArea(points)) < epsilon {
return fmt.Errorf("多边形不能退化为直线")
}
if selfIntersects(points, true) {
return fmt.Errorf("多边形不能自交")
}
case KindLine:
if len(points) != 2 {
return fmt.Errorf("警戒线必须恰好包含 2 个点")
}
if distance(points[0], points[1]) < epsilon {
return fmt.Errorf("警戒线两点不能重合")
}
if direction != DirectionAToB && direction != DirectionBToA && direction != DirectionBoth {
return fmt.Errorf("警戒线方向不正确")
}
default:
return fmt.Errorf("区域类型不正确")
}
return nil
}
func polygonArea(points []Point) float64 {
sum := 0.0
for i := range points {
next := (i + 1) % len(points)
sum += points[i].X*points[next].Y - points[next].X*points[i].Y
}
return sum / 2
}
func distance(a, b Point) float64 { dx, dy := a.X-b.X, a.Y-b.Y; return dx*dx + dy*dy }
func selfIntersects(points []Point, closed bool) bool {
segments := len(points) - 1
if closed {
segments = len(points)
}
for i := 0; i < segments; i++ {
a1, a2 := points[i], points[(i+1)%len(points)]
if distance(a1, a2) < epsilon {
return true
}
for j := i + 1; j < segments; j++ {
if j == i+1 || closed && i == 0 && j == segments-1 {
continue
}
b1, b2 := points[j], points[(j+1)%len(points)]
if segmentsIntersect(a1, a2, b1, b2) {
return true
}
}
}
return false
}
func segmentsIntersect(a, b, c, d Point) bool {
o1, o2, o3, o4 := orientation(a, b, c), orientation(a, b, d), orientation(c, d, a), orientation(c, d, b)
return o1*o2 < 0 && o3*o4 < 0
}
func orientation(a, b, c Point) float64 { return (b.X-a.X)*(c.Y-a.Y) - (b.Y-a.Y)*(c.X-a.X) }