mojxml_parser/
constants.rs

1use crate::error::{Error, Result};
2use proj4rs::proj::Proj;
3use std::collections::HashMap;
4use std::sync::OnceLock;
5
6static PROJ_STRS: &[(&str, &str); 20] = &[
7    ("WGS84", "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"),
8    (
9        "公共座標1系", // 2443
10        "+proj=tmerc +lat_0=33 +lon_0=129.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
11    ),
12    (
13        "公共座標2系", // 2444
14        "+proj=tmerc +lat_0=33 +lon_0=131 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
15    ),
16    (
17        "公共座標3系", // 2445
18        "+proj=tmerc +lat_0=36 +lon_0=132.166666666667 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
19    ),
20    (
21        "公共座標4系", // 2446
22        "+proj=tmerc +lat_0=33 +lon_0=133.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
23    ),
24    (
25        "公共座標5系", // 2447
26        "+proj=tmerc +lat_0=36 +lon_0=134.333333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
27    ),
28    (
29        "公共座標6系", // 2448
30        "+proj=tmerc +lat_0=36 +lon_0=136 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
31    ),
32    (
33        "公共座標7系", // 2449
34        "+proj=tmerc +lat_0=36 +lon_0=137.166666666667 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
35    ),
36    (
37        "公共座標8系", // 2450
38        "+proj=tmerc +lat_0=36 +lon_0=138.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
39    ),
40    (
41        "公共座標9系", // 2451
42        "+proj=tmerc +lat_0=36 +lon_0=139.833333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
43    ),
44    (
45        "公共座標10系", // 2452
46        "+proj=tmerc +lat_0=40 +lon_0=140.833333333333 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
47    ),
48    (
49        "公共座標11系", // 2453
50        "+proj=tmerc +lat_0=44 +lon_0=140.25 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
51    ),
52    (
53        "公共座標12系", // 2454
54        "+proj=tmerc +lat_0=44 +lon_0=142.25 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
55    ),
56    (
57        "公共座標13系", // 2455
58        "+proj=tmerc +lat_0=44 +lon_0=144.25 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
59    ),
60    (
61        "公共座標14系", // 2456
62        "+proj=tmerc +lat_0=26 +lon_0=142 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
63    ),
64    (
65        "公共座標15系", // 2457
66        "+proj=tmerc +lat_0=26 +lon_0=127.5 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
67    ),
68    (
69        "公共座標16系", // 2458
70        "+proj=tmerc +lat_0=26 +lon_0=124 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
71    ),
72    (
73        "公共座標17系", // 2459
74        "+proj=tmerc +lat_0=26 +lon_0=131 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
75    ),
76    (
77        "公共座標18系", // 2460
78        "+proj=tmerc +lat_0=20 +lon_0=136 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
79    ),
80    (
81        "公共座標19系", // 2461
82        "+proj=tmerc +lat_0=26 +lon_0=154 +k=0.9999 +x_0=0 +y_0=0 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs +type=crs",
83    ),
84];
85
86static PROJ_CACHE: OnceLock<HashMap<&'static str, OnceLock<Proj>>> = OnceLock::new();
87
88pub fn get_proj(name: &str) -> Result<Option<&'static Proj>> {
89    if name == "任意座標系" {
90        return Ok(None);
91    }
92    let definition = PROJ_STRS
93        .iter()
94        .find(|(n, _)| *n == name)
95        .map(|(_, s)| *s)
96        .ok_or_else(|| Error::UnsupportedCrs(name.to_string()))?;
97
98    let cache = PROJ_CACHE.get_or_init(|| {
99        let mut map = HashMap::with_capacity(PROJ_STRS.len());
100        for (name, _) in PROJ_STRS.iter() {
101            map.insert(*name, OnceLock::new());
102        }
103        map
104    });
105
106    let cell = cache
107        .get(name)
108        .ok_or_else(|| Error::UnsupportedCrs(name.to_string()))?;
109    let proj = cell.get_or_init(|| {
110        Proj::from_proj_string(definition)
111            .unwrap_or_else(|err| panic!("invalid PROJ definition for {name}: {err:?}"))
112    });
113    Ok(Some(proj))
114}
115
116pub fn get_xml_namespace(prefix: Option<&str>) -> Option<&'static str> {
117    match prefix {
118        None => Some("http://www.moj.go.jp/MINJI/tizuxml"),
119        Some("zmn") => Some("http://www.moj.go.jp/MINJI/tizuzumen"),
120        Some("xsi") => Some("http://www.w3.org/2001/XMLSchema-instance"),
121        _ => None,
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use super::get_proj;
128    use std::ptr;
129
130    #[test]
131    fn proj_cache_test() {
132        let wgs84 = get_proj("WGS84")
133            .expect("WGS84 lookup should succeed")
134            .expect("WGS84 should not map to None");
135        let wgs84_cached = get_proj("WGS84")
136            .expect("WGS84 cached lookup should succeed")
137            .expect("WGS84 cached lookup should not map to None");
138        assert!(
139            ptr::eq(wgs84, wgs84_cached),
140            "WGS84 should return the same cached Proj instance"
141        );
142
143        let public_zone_1 = get_proj("公共座標1系")
144            .expect("公共座標1系 lookup should succeed")
145            .expect("公共座標1系 should not map to None");
146        let public_zone_1_cached = get_proj("公共座標1系")
147            .expect("公共座標1系 cached lookup should succeed")
148            .expect("公共座標1系 cached lookup should not map to None");
149        assert!(
150            ptr::eq(public_zone_1, public_zone_1_cached),
151            "公共座標1系 should return the same cached Proj instance"
152        );
153
154        assert!(
155            !ptr::eq(wgs84, public_zone_1),
156            "Distinct CRS names should resolve to distinct Proj instances"
157        );
158    }
159}