fix(input): correct lon mapping
This commit is contained in:
parent
19557f3a62
commit
84d1664b29
20 changed files with 1197 additions and 137 deletions
|
|
@ -2,22 +2,72 @@ package api
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"predictor-refactored/internal/api/async"
|
||||
"predictor-refactored/internal/engine"
|
||||
"predictor-refactored/internal/numerics"
|
||||
apirest "predictor-refactored/pkg/rest"
|
||||
)
|
||||
|
||||
// normalizeLng folds a longitude into [0, 360) for internal use.
|
||||
func normalizeLng(lng float64) float64 {
|
||||
if lng < 0 {
|
||||
return lng + 360
|
||||
// longitudeLimit bounds what either API version accepts, in degrees.
|
||||
//
|
||||
// Symmetric on purpose. Upstream Tawhiri implements a half-open [0, 360) — one
|
||||
// fundamental domain, every meridian spelled exactly once (measured). We accept a
|
||||
// superset because the frontend holds longitudes in [-180, 180], so a western
|
||||
// launch arrives negative, and we tolerate one full turn either way. Symmetry is
|
||||
// the whole point: the previous bound, [-180, 360), had its two ends justified by
|
||||
// unrelated things — the lower end was the signed convention's edge, the upper end
|
||||
// was the domain on which the old single-fold normalizeLng happened to be correct.
|
||||
//
|
||||
// Beyond one turn a value is a typo rather than a notation. 5170 is arithmetically
|
||||
// a perfectly good way to write 50 E, and upstream refuses it too.
|
||||
const longitudeLimit = 360.0
|
||||
|
||||
// validateLat refuses latitudes outside [-90, 90].
|
||||
//
|
||||
// Shared by both API versions. Unlike longitude this is a real geometric bound:
|
||||
// the poles are the ends of the axis, so no notation makes 100 meaningful. v2
|
||||
// checked it and v1 did not.
|
||||
func validateLat(lat float64) error {
|
||||
if math.IsNaN(lat) || lat < -90 || lat > 90 {
|
||||
return apiError(http.StatusBadRequest, fmt.Sprintf("launch latitude must be in [-90, 90], got %g", lat))
|
||||
}
|
||||
return lng
|
||||
return nil
|
||||
}
|
||||
|
||||
// signedLng converts an internal [0, 360) longitude back to [-180, 180).
|
||||
// validateLng refuses longitudes outside [-longitudeLimit, longitudeLimit].
|
||||
//
|
||||
// Shared by both API versions. v1 used to apply no check at all while v2 enforced
|
||||
// [-180, 360), so the same launch could be accepted by one and refused by the
|
||||
// other — a difference in behaviour where only format may differ.
|
||||
func validateLng(lng float64) error {
|
||||
if math.IsNaN(lng) || lng < -longitudeLimit || lng > longitudeLimit {
|
||||
return apiError(http.StatusBadRequest,
|
||||
fmt.Sprintf("launch longitude must be in [-%g, %g], got %g", longitudeLimit, longitudeLimit, lng))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// normalizeLng folds a longitude into the [0, 360) the wind grid is indexed on.
|
||||
//
|
||||
// A true modulo, via the same helper the integrator applies on every step
|
||||
// (numerics.PyMod in toGeo), so the request path and the engine agree by
|
||||
// construction rather than by coincidence. It used to be a single
|
||||
// `if lng < 0 { lng += 360 }`, correct only on [-360, 360): -400 became -40,
|
||||
// reached the grid, and came back as "lng=-40 out of range" — a complaint about
|
||||
// wind data for what was an input problem.
|
||||
func normalizeLng(lng float64) float64 {
|
||||
return numerics.PyMod(lng, 360)
|
||||
}
|
||||
|
||||
// signedLng converts an internal [0, 360) longitude to [-180, 180).
|
||||
//
|
||||
// This is v2's published format. v1 publishes the internal [0, 360) unchanged,
|
||||
// because that is the convention upstream Tawhiri publishes and v1 exists to be a
|
||||
// drop-in for it.
|
||||
func signedLng(lng float64) float64 {
|
||||
if lng > 180 {
|
||||
return lng - 360
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue