feat: polish & windviz & deploy

This commit is contained in:
Anatoly Antonov 2026-05-30 06:29:39 +09:00
parent 81b8e763bd
commit 465ad00f7b
78 changed files with 20622 additions and 2154 deletions

View file

@ -0,0 +1,41 @@
package numerics
import "math"
// PointInPolygon reports whether (lat, lng) lies inside the closed polygon
// whose vertices are given as parallel latitude/longitude slices (degrees).
//
// The test is ray casting in plate-carrée space. Every longitude is
// normalised to within 180° of the first vertex before testing, so a polygon
// spanning the antimeridian is handled correctly as long as it spans no more
// than 180° in longitude. polyLat and polyLng must have equal length >= 3.
func PointInPolygon(lat, lng float64, polyLat, polyLng []float64) bool {
n := len(polyLat)
if n < 3 || len(polyLng) != n {
return false
}
ref := polyLng[0]
qx := NormalizeLng(lng, ref)
inside := false
for i, j := 0, n-1; i < n; j, i = i, i+1 {
yi, yj := polyLat[i], polyLat[j]
xi := NormalizeLng(polyLng[i], ref)
xj := NormalizeLng(polyLng[j], ref)
if (yi > lat) != (yj > lat) {
xIntersect := (xj-xi)*(lat-yi)/(yj-yi) + xi
if qx < xIntersect {
inside = !inside
}
}
}
return inside
}
// NormalizeLng rewrites v so that it lies within 180° of ref. For example,
// NormalizeLng(350, 10) returns -10. Used to make longitude comparisons
// continuous across the antimeridian.
func NormalizeLng(v, ref float64) float64 {
return ref + math.Mod(v-ref+540, 360) - 180
}