oxiproj-core 0.1.2

Foundation types for OxiProj: coordinates, errors, ellipsoids, datums, and units.
Documentation
//! Named ellipsoid definitions ported from PROJ `src/ellps.cpp`.

/// One row of the PROJ ellipsoid table. Ported from src/ellps.cpp.
#[derive(Debug, Clone, Copy, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct EllpsDef {
    /// Short ellipsoid identifier, e.g. `"WGS84"`, `"GRS80"`.
    pub id: &'static str,
    /// Semi-major axis parameter, formatted as `"a=<value>"`.
    pub major: &'static str,
    /// Shape parameter, formatted as either `"rf=<value>"` (inverse
    /// flattening) or `"b=<value>"` (semi-minor axis).
    pub shape: &'static str,
    /// Free-text description of the ellipsoid.
    pub name: &'static str,
}

/// The PROJ named-ellipsoid table. Ported verbatim from src/ellps.cpp.
pub static ELLPS_TABLE: &[EllpsDef] = &[
    EllpsDef {
        id: "MERIT",
        major: "a=6378137.0",
        shape: "rf=298.257",
        name: "MERIT 1983",
    },
    EllpsDef {
        id: "SGS85",
        major: "a=6378136.0",
        shape: "rf=298.257",
        name: "Soviet Geodetic System 85",
    },
    EllpsDef {
        id: "GRS80",
        major: "a=6378137.0",
        shape: "rf=298.257222101",
        name: "GRS 1980(IUGG, 1980)",
    },
    EllpsDef {
        id: "IAU76",
        major: "a=6378140.0",
        shape: "rf=298.257",
        name: "IAU 1976",
    },
    EllpsDef {
        id: "airy",
        major: "a=6377563.396",
        shape: "rf=299.3249646",
        name: "Airy 1830",
    },
    EllpsDef {
        id: "APL4.9",
        major: "a=6378137.0",
        shape: "rf=298.25",
        name: "Appl. Physics. 1965",
    },
    EllpsDef {
        id: "NWL9D",
        major: "a=6378145.0",
        shape: "rf=298.25",
        name: "Naval Weapons Lab., 1965",
    },
    EllpsDef {
        id: "mod_airy",
        major: "a=6377340.189",
        shape: "b=6356034.446",
        name: "Modified Airy",
    },
    EllpsDef {
        id: "andrae",
        major: "a=6377104.43",
        shape: "rf=300.0",
        name: "Andrae 1876 (Den., Iclnd.)",
    },
    EllpsDef {
        id: "danish",
        major: "a=6377019.2563",
        shape: "rf=300.0",
        name: "Andrae 1876 (Denmark, Iceland)",
    },
    EllpsDef {
        id: "aust_SA",
        major: "a=6378160.0",
        shape: "rf=298.25",
        name: "Australian Natl & S. Amer. 1969",
    },
    EllpsDef {
        id: "GRS67",
        major: "a=6378160.0",
        shape: "rf=298.2471674270",
        name: "GRS 67(IUGG 1967)",
    },
    EllpsDef {
        id: "GSK2011",
        major: "a=6378136.5",
        shape: "rf=298.2564151",
        name: "GSK-2011",
    },
    EllpsDef {
        id: "bessel",
        major: "a=6377397.155",
        shape: "rf=299.1528128",
        name: "Bessel 1841",
    },
    EllpsDef {
        id: "bess_nam",
        major: "a=6377483.865",
        shape: "rf=299.1528128",
        name: "Bessel 1841 (Namibia)",
    },
    EllpsDef {
        id: "clrk66",
        major: "a=6378206.4",
        shape: "b=6356583.8",
        name: "Clarke 1866",
    },
    EllpsDef {
        id: "clrk80",
        major: "a=6378249.145",
        shape: "rf=293.4663",
        name: "Clarke 1880 mod.",
    },
    EllpsDef {
        id: "clrk80ign",
        major: "a=6378249.2",
        shape: "rf=293.4660212936269",
        name: "Clarke 1880 (IGN).",
    },
    EllpsDef {
        id: "CPM",
        major: "a=6375738.7",
        shape: "rf=334.29",
        name: "Comm. des Poids et Mesures 1799",
    },
    EllpsDef {
        id: "delmbr",
        major: "a=6376428.",
        shape: "rf=311.5",
        name: "Delambre 1810 (Belgium)",
    },
    EllpsDef {
        id: "engelis",
        major: "a=6378136.05",
        shape: "rf=298.2566",
        name: "Engelis 1985",
    },
    EllpsDef {
        id: "evrst30",
        major: "a=6377276.345",
        shape: "rf=300.8017",
        name: "Everest 1830",
    },
    EllpsDef {
        id: "evrst48",
        major: "a=6377304.063",
        shape: "rf=300.8017",
        name: "Everest 1948",
    },
    EllpsDef {
        id: "evrst56",
        major: "a=6377301.243",
        shape: "rf=300.8017",
        name: "Everest 1956",
    },
    EllpsDef {
        id: "evrst69",
        major: "a=6377295.664",
        shape: "rf=300.8017",
        name: "Everest 1969",
    },
    EllpsDef {
        id: "evrstSS",
        major: "a=6377298.556",
        shape: "rf=300.8017",
        name: "Everest (Sabah & Sarawak)",
    },
    EllpsDef {
        id: "fschr60",
        major: "a=6378166.",
        shape: "rf=298.3",
        name: "Fischer (Mercury Datum) 1960",
    },
    EllpsDef {
        id: "fschr60m",
        major: "a=6378155.",
        shape: "rf=298.3",
        name: "Modified Fischer 1960",
    },
    EllpsDef {
        id: "fschr68",
        major: "a=6378150.",
        shape: "rf=298.3",
        name: "Fischer 1968",
    },
    EllpsDef {
        id: "helmert",
        major: "a=6378200.",
        shape: "rf=298.3",
        name: "Helmert 1906",
    },
    EllpsDef {
        id: "hough",
        major: "a=6378270.0",
        shape: "rf=297.",
        name: "Hough",
    },
    EllpsDef {
        id: "intl",
        major: "a=6378388.0",
        shape: "rf=297.",
        name: "International 1924 (Hayford 1909, 1910)",
    },
    EllpsDef {
        id: "krass",
        major: "a=6378245.0",
        shape: "rf=298.3",
        name: "Krassovsky, 1942",
    },
    EllpsDef {
        id: "kaula",
        major: "a=6378163.",
        shape: "rf=298.24",
        name: "Kaula 1961",
    },
    EllpsDef {
        id: "lerch",
        major: "a=6378139.",
        shape: "rf=298.257",
        name: "Lerch 1979",
    },
    EllpsDef {
        id: "mprts",
        major: "a=6397300.",
        shape: "rf=191.",
        name: "Maupertius 1738",
    },
    EllpsDef {
        id: "new_intl",
        major: "a=6378157.5",
        shape: "b=6356772.2",
        name: "New International 1967",
    },
    EllpsDef {
        id: "plessis",
        major: "a=6376523.",
        shape: "b=6355863.",
        name: "Plessis 1817 (France)",
    },
    EllpsDef {
        id: "PZ90",
        major: "a=6378136.0",
        shape: "rf=298.25784",
        name: "PZ-90",
    },
    EllpsDef {
        id: "SEasia",
        major: "a=6378155.0",
        shape: "b=6356773.3205",
        name: "Southeast Asia",
    },
    EllpsDef {
        id: "walbeck",
        major: "a=6376896.0",
        shape: "b=6355834.8467",
        name: "Walbeck",
    },
    EllpsDef {
        id: "WGS60",
        major: "a=6378165.0",
        shape: "rf=298.3",
        name: "WGS 60",
    },
    EllpsDef {
        id: "WGS66",
        major: "a=6378145.0",
        shape: "rf=298.25",
        name: "WGS 66",
    },
    EllpsDef {
        id: "WGS72",
        major: "a=6378135.0",
        shape: "rf=298.26",
        name: "WGS 72",
    },
    EllpsDef {
        id: "WGS84",
        major: "a=6378137.0",
        shape: "rf=298.257223563",
        name: "WGS 84",
    },
    EllpsDef {
        id: "sphere",
        major: "a=6370997.0",
        shape: "b=6370997.0",
        name: "Normal Sphere (r=6370997)",
    },
];

/// Look up a named ellipsoid by its exact `id`. Ported from src/ellps.cpp.
pub fn find_ellps(id: &str) -> Option<&'static EllpsDef> {
    ELLPS_TABLE.iter().find(|e| e.id == id)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn finds_wgs84() {
        let e = find_ellps("WGS84").expect("WGS84 must be present");
        assert_eq!(e.major, "a=6378137.0");
        assert_eq!(e.shape, "rf=298.257223563");
    }

    #[test]
    fn clrk66_uses_semi_minor_axis() {
        assert_eq!(find_ellps("clrk66").map(|e| e.shape), Some("b=6356583.8"));
    }

    #[test]
    fn finds_sphere() {
        assert!(find_ellps("sphere").is_some());
    }

    #[test]
    fn rejects_unknown_id() {
        assert!(find_ellps("nonexistent_xyz").is_none());
    }

    #[test]
    fn table_has_expected_minimum_length() {
        assert!(ELLPS_TABLE.len() >= 46);
    }

    #[test]
    fn every_entry_has_valid_major_and_shape_prefixes() {
        for e in ELLPS_TABLE {
            assert!(
                e.major.starts_with("a="),
                "entry {} has invalid major: {}",
                e.id,
                e.major
            );
            assert!(
                e.shape.starts_with("rf=") || e.shape.starts_with("b="),
                "entry {} has invalid shape: {}",
                e.id,
                e.shape
            );
        }
    }
}