|
| 1 | +package ellipsoid |
| 2 | + |
| 3 | +// FIXME add Vincenty algorithm https://github.com/twpayne/ol3/blob/189ba34955029280ba348a65540e5e36539477f9/src/ol/ellipsoid/ellipsoid.js#L56 |
| 4 | +// FIXME compare with https://github.com/StefanSchroeder/Golang-Ellipsoid |
| 5 | + |
| 6 | +import ( |
| 7 | + "math" |
| 8 | + |
| 9 | + "github.com/twpayne/go-kml/v3" |
| 10 | +) |
| 11 | + |
| 12 | +// An Ellipsoid is an ellipsoid. |
| 13 | +type Ellipsoid struct { |
| 14 | + A float64 |
| 15 | + Flattening float64 |
| 16 | +} |
| 17 | + |
| 18 | +// WGS84 is the WGS84 ellipsoid. |
| 19 | +var WGS84 = Ellipsoid{ |
| 20 | + A: 6378137, |
| 21 | + Flattening: 1.0 / 298.257223563, |
| 22 | +} |
| 23 | + |
| 24 | +// Distance returns the distance between c1 and c2. |
| 25 | +func (e Ellipsoid) Distance(c1, c2 kml.Coordinate) float64 { |
| 26 | + // See "Annex C Ellipsoid distance between two points" in the "FAI Sporting |
| 27 | + // Code: Section 7F – XC Scoring". |
| 28 | + // |
| 29 | + // https://fai.org/sites/default/files/civl/documents/sporting_code_s7_f_-_xc_scoring_2025_v1.0.pdf |
| 30 | + lat1r := math.Pi * c1.Lat / 180 |
| 31 | + lon1r := math.Pi * c1.Lon / 180 |
| 32 | + lat2r := math.Pi * c2.Lat / 180 |
| 33 | + lon2r := math.Pi * c2.Lon / 180 |
| 34 | + if lon1r == lon2r && lat1r == lat2r { |
| 35 | + return 0 |
| 36 | + } |
| 37 | + theta1 := math.Atan(e.oneMinusF() * math.Tan(lat1r)) |
| 38 | + theta2 := math.Atan(e.oneMinusF() * math.Tan(lat2r)) |
| 39 | + thetaM := (theta1 + theta2) / 2.0 |
| 40 | + dThetaM := (theta2 - theta1) / 2.0 |
| 41 | + dLambda := lon2r - lon1r |
| 42 | + dLambdaM := dLambda / 2.0 |
| 43 | + sinThetaM := math.Sin(thetaM) |
| 44 | + cosThetaM := math.Cos(thetaM) |
| 45 | + sinDThetaM := math.Sin(dThetaM) |
| 46 | + cosDThetaM := math.Cos(dThetaM) |
| 47 | + sin2ThetaM := sinThetaM * sinThetaM |
| 48 | + cos2ThetaM := cosThetaM * cosThetaM |
| 49 | + sin2DThetaM := sinDThetaM * sinDThetaM |
| 50 | + cos2DThetaM := cosDThetaM * cosDThetaM |
| 51 | + sinDLambdaM := math.Sin(dLambdaM) |
| 52 | + sin2DLambdaM := sinDLambdaM * sinDLambdaM |
| 53 | + H := cos2ThetaM - sin2DThetaM |
| 54 | + L := sin2DThetaM + H*sin2DLambdaM |
| 55 | + cosD := 1.0 - 2.0*L |
| 56 | + d := math.Acos(cosD) |
| 57 | + sinD := math.Sin(d) |
| 58 | + oneMinusL := 1.0 - L |
| 59 | + if sinD == 0.0 || L == 0.0 || oneMinusL == 0.0 { |
| 60 | + return 0 |
| 61 | + } |
| 62 | + U := 2.0 * sin2ThetaM * cos2DThetaM / oneMinusL |
| 63 | + V := 2.0 * sin2DThetaM * cos2ThetaM / L |
| 64 | + X := U + V |
| 65 | + Y := U - V |
| 66 | + T := d / sinD |
| 67 | + D := 4.0 * T * T |
| 68 | + E := 2.0 * cosD |
| 69 | + A := D * E |
| 70 | + B := 2.0 * D |
| 71 | + C := T - (A-E)/2.0 |
| 72 | + n1 := X * (A + C*X) |
| 73 | + n2 := Y * (B + E*Y) |
| 74 | + n3 := D * X * Y |
| 75 | + delta1d := e.Flattening * (T*X - Y) / 4.0 |
| 76 | + delta2d := e.flatSq64() * (n1 - n2 + n3) |
| 77 | + return e.A * sinD * (T - delta1d + delta2d) |
| 78 | +} |
| 79 | + |
| 80 | +func (e Ellipsoid) flatSq64() float64 { |
| 81 | + return e.Flattening * e.Flattening / 64 |
| 82 | +} |
| 83 | + |
| 84 | +func (e Ellipsoid) oneMinusF() float64 { |
| 85 | + return 1 - e.Flattening |
| 86 | +} |
0 commit comments