• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine / 13696412051

06 Mar 2025 10:20AM UTC coverage: 90.082% (+0.006%) from 90.076%
13696412051

Pull #1026

github

web-flow
Merge 3299874a0 into c96026921
Pull Request #1026: Ubuntu 24 LTS

2310 of 2429 new or added lines in 103 files covered. (95.1%)

6 existing lines in 4 files now uncovered.

126335 of 140244 relevant lines covered (90.08%)

57394.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.01
/datatypes/src/spatial_reference.rs
1
use crate::{
2
    error,
3
    operations::reproject::{CoordinateProjection, CoordinateProjector, Reproject},
4
    primitives::AxisAlignedRectangle,
5
    util::Result,
6
};
7
use gdal::spatial_ref::SpatialRef;
8

9
use postgres_types::private::BytesMut;
10

11
use postgres_types::{FromSql, IsNull, ToSql, Type};
12
use proj::Proj;
13
use serde::de::Visitor;
14
use serde::{Deserialize, Deserializer, Serialize, Serializer};
15

16
use snafu::Error;
17
use snafu::ResultExt;
18
use std::str::FromStr;
19
use std::{convert::TryFrom, fmt::Formatter};
20

21
/// A spatial reference authority that is part of a spatial reference definition
22
#[derive(
23
    Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize, ToSql, FromSql,
×
24
)]
25
#[serde(rename_all = "SCREAMING-KEBAB-CASE")]
26
pub enum SpatialReferenceAuthority {
27
    Epsg,
28
    SrOrg,
29
    Iau2000,
30
    Esri,
31
}
32

33
impl std::fmt::Display for SpatialReferenceAuthority {
34
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1,226✔
35
        write!(
1,226✔
36
            f,
1,226✔
37
            "{}",
1,226✔
38
            match self {
1,226✔
39
                SpatialReferenceAuthority::Epsg => "EPSG",
1,215✔
40
                SpatialReferenceAuthority::SrOrg => "SR-ORG",
3✔
41
                SpatialReferenceAuthority::Iau2000 => "IAU2000",
4✔
42
                SpatialReferenceAuthority::Esri => "ESRI",
4✔
43
            }
44
        )
45
    }
1,226✔
46
}
47

48
/// A spatial reference consists of an authority and a code
49
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, ToSql, FromSql)]
×
50
pub struct SpatialReference {
51
    authority: SpatialReferenceAuthority,
52
    code: u32,
53
}
54

55
impl SpatialReference {
56
    pub fn new(authority: SpatialReferenceAuthority, code: u32) -> Self {
1,698✔
57
        Self { authority, code }
1,698✔
58
    }
1,698✔
59

60
    pub fn authority(&self) -> &SpatialReferenceAuthority {
52✔
61
        &self.authority
52✔
62
    }
52✔
63

64
    pub fn code(self) -> u32 {
52✔
65
        self.code
52✔
66
    }
52✔
67

68
    /// the WGS 84 spatial reference system
69
    pub fn epsg_4326() -> Self {
661✔
70
        Self::new(SpatialReferenceAuthority::Epsg, 4326)
661✔
71
    }
661✔
72

73
    pub fn proj_string(self) -> Result<String> {
546✔
74
        match self.authority {
2✔
75
            SpatialReferenceAuthority::Epsg | SpatialReferenceAuthority::Iau2000 | SpatialReferenceAuthority::Esri => {
76
                Ok(format!("{}:{}", self.authority, self.code))
544✔
77
            }
78
            // poor-mans integration of Meteosat Second Generation 
79
            SpatialReferenceAuthority::SrOrg if self.code == 81 => Ok("+proj=geos +lon_0=0 +h=35785831 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs".to_owned()),
2✔
80
            SpatialReferenceAuthority::SrOrg => {
81
                Err(error::Error::ProjStringUnresolvable { spatial_ref: self })
1✔
82
                //TODO: we might need to look them up somehow! Best solution would be a registry where we can store user definexd srs strings.
83
            }
84
        }
85
    }
546✔
86

87
    /// Return the area of use in EPSG:4326 projection
88
    pub fn area_of_use<A: AxisAlignedRectangle>(self) -> Result<A> {
72✔
89
        let proj_string = self.proj_string()?;
72✔
90

91
        let proj = Proj::new(&proj_string).map_err(|_| error::Error::InvalidProjDefinition {
72✔
UNCOV
92
            proj_definition: proj_string.clone(),
×
93
        })?;
72✔
94
        let area = proj
72✔
95
            .area_of_use()
72✔
96
            .context(error::ProjInternal)?
72✔
97
            .0
98
            .ok_or(error::Error::NoAreaOfUseDefined { proj_string })?;
72✔
99
        A::from_min_max(
72✔
100
            (area.west, area.south).into(),
72✔
101
            (area.east, area.north).into(),
72✔
102
        )
72✔
103
    }
72✔
104

105
    /// Return the area of use in current projection
106
    pub fn area_of_use_projected<A: AxisAlignedRectangle>(self) -> Result<A> {
28✔
107
        if self == Self::epsg_4326() {
28✔
108
            return self.area_of_use();
24✔
109
        }
4✔
110
        let p = CoordinateProjector::from_known_srs(Self::epsg_4326(), self)?;
4✔
111
        self.area_of_use::<A>()?.reproject(&p)
4✔
112
    }
28✔
113

114
    /// Return the srs-string "authority:code"
115
    #[allow(clippy::trivially_copy_pass_by_ref)]
116
    pub fn srs_string(&self) -> String {
1✔
117
        format!("{}:{}", self.authority, self.code)
1✔
118
    }
1✔
119

120
    /// Compute the bounding box of this spatial reference that is also valid in the `other` spatial reference. Might be None.
121
    #[allow(clippy::trivially_copy_pass_by_ref)]
122
    pub fn area_of_use_intersection<T>(&self, other: &SpatialReference) -> Result<Option<T>>
6✔
123
    where
6✔
124
        T: AxisAlignedRectangle,
6✔
125
    {
6✔
126
        // generate a projector which transforms wgs84 into the projection we want to produce.
127
        let valid_bounds_proj =
6✔
128
            CoordinateProjector::from_known_srs(SpatialReference::epsg_4326(), *self)?;
6✔
129

130
        // transform the bounds of the input srs (coordinates are in wgs84) into the output projection.
131
        // TODO check if  there is a better / smarter way to check if the coordinates are valid.
132
        let area_out = self.area_of_use::<T>()?;
6✔
133
        let area_other = other.area_of_use::<T>()?;
6✔
134

135
        area_out
6✔
136
            .intersection(&area_other)
6✔
137
            .map(|x| x.reproject(&valid_bounds_proj))
6✔
138
            .transpose()
6✔
139
    }
6✔
140
}
141

142
impl std::fmt::Display for SpatialReference {
143
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
673✔
144
        write!(f, "{}:{}", self.authority, self.code)
673✔
145
    }
673✔
146
}
147

148
impl Serialize for SpatialReference {
149
    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
20✔
150
    where
20✔
151
        S: Serializer,
20✔
152
    {
20✔
153
        serializer.serialize_str(&self.to_string())
20✔
154
    }
20✔
155
}
156

157
/// Helper struct for deserializing a `SpatialReferencce`
158
struct SpatialReferenceDeserializeVisitor;
159

160
impl Visitor<'_> for SpatialReferenceDeserializeVisitor {
161
    type Value = SpatialReference;
162

163
    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
×
164
        formatter.write_str("a spatial reference in the form authority:code")
×
165
    }
×
166

167
    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
26✔
168
    where
26✔
169
        E: serde::de::Error,
26✔
170
    {
26✔
171
        v.parse().map_err(serde::de::Error::custom)
26✔
172
    }
26✔
173
}
174

175
impl<'de> Deserialize<'de> for SpatialReference {
176
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
26✔
177
    where
26✔
178
        D: Deserializer<'de>,
26✔
179
    {
26✔
180
        deserializer.deserialize_str(SpatialReferenceDeserializeVisitor)
26✔
181
    }
26✔
182
}
183

184
impl FromStr for SpatialReferenceAuthority {
185
    type Err = error::Error;
186

187
    fn from_str(s: &str) -> Result<Self, Self::Err> {
965✔
188
        Ok(match s {
965✔
189
            "EPSG" => SpatialReferenceAuthority::Epsg,
965✔
190
            "SR-ORG" => SpatialReferenceAuthority::SrOrg,
201✔
191
            "IAU2000" => SpatialReferenceAuthority::Iau2000,
200✔
192
            "ESRI" => SpatialReferenceAuthority::Esri,
199✔
193
            _ => {
194
                return Err(error::Error::InvalidSpatialReferenceString {
2✔
195
                    spatial_reference_string: s.into(),
2✔
196
                });
2✔
197
            }
198
        })
199
    }
965✔
200
}
201

202
impl FromStr for SpatialReference {
203
    type Err = error::Error;
204

205
    fn from_str(s: &str) -> Result<Self, Self::Err> {
154✔
206
        let mut split = s.split(':');
154✔
207

154✔
208
        match (split.next(), split.next(), split.next()) {
154✔
209
            (Some(authority), Some(code), None) => Ok(Self::new(
154✔
210
                authority.parse()?,
154✔
211
                code.parse::<u32>().context(error::ParseU32)?,
152✔
212
            )),
213
            _ => Err(error::Error::InvalidSpatialReferenceString {
×
214
                spatial_reference_string: s.into(),
×
215
            }),
×
216
        }
217
    }
154✔
218
}
219

220
impl TryFrom<SpatialRef> for SpatialReference {
221
    type Error = error::Error;
222

223
    fn try_from(value: SpatialRef) -> Result<Self, Self::Error> {
931✔
224
        Ok(SpatialReference::new(
931✔
225
            SpatialReferenceAuthority::from_str(&value.auth_name()?)?,
931✔
226
            value.auth_code()? as u32,
811✔
227
        ))
228
    }
931✔
229
}
230

231
impl TryFrom<SpatialReference> for SpatialRef {
232
    type Error = error::Error;
233

234
    fn try_from(value: SpatialReference) -> Result<Self, Self::Error> {
48✔
235
        if value.authority == SpatialReferenceAuthority::Epsg {
48✔
236
            return SpatialRef::from_epsg(value.code).context(error::Gdal);
48✔
237
        }
×
238

×
239
        // TODO: support other projections reliably
×
240

×
241
        SpatialRef::from_proj4(&value.proj_string()?).context(error::Gdal)
×
242
    }
48✔
243
}
244

245
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
246
pub enum SpatialReferenceOption {
247
    SpatialReference(SpatialReference),
248
    Unreferenced,
249
}
250

251
impl SpatialReferenceOption {
252
    pub fn is_spatial_ref(self) -> bool {
4✔
253
        match self {
4✔
254
            SpatialReferenceOption::SpatialReference(_) => true,
2✔
255
            SpatialReferenceOption::Unreferenced => false,
2✔
256
        }
257
    }
4✔
258

259
    pub fn is_unreferenced(self) -> bool {
2✔
260
        !self.is_spatial_ref()
2✔
261
    }
2✔
262
}
263

264
impl ToSql for SpatialReferenceOption {
265
    fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>>
442✔
266
    where
442✔
267
        Self: Sized,
442✔
268
    {
442✔
269
        match self {
442✔
270
            SpatialReferenceOption::SpatialReference(sref) => sref.to_sql(ty, out),
337✔
271
            SpatialReferenceOption::Unreferenced => Ok(IsNull::Yes),
105✔
272
        }
273
    }
442✔
274

275
    fn accepts(ty: &Type) -> bool
247✔
276
    where
247✔
277
        Self: Sized,
247✔
278
    {
247✔
279
        <SpatialReference as ToSql>::accepts(ty)
247✔
280
    }
247✔
281

282
    fn to_sql_checked(
×
283
        &self,
×
284
        ty: &Type,
×
285
        out: &mut BytesMut,
×
286
    ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
×
287
        match self {
×
288
            SpatialReferenceOption::SpatialReference(sref) => sref.to_sql_checked(ty, out),
×
289
            SpatialReferenceOption::Unreferenced => Ok(IsNull::Yes),
×
290
        }
291
    }
×
292
}
293

294
impl<'a> FromSql<'a> for SpatialReferenceOption {
295
    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
58✔
296
        Ok(SpatialReferenceOption::SpatialReference(
58✔
297
            SpatialReference::from_sql(ty, raw)?,
58✔
298
        ))
299
    }
58✔
300

301
    fn from_sql_null(_: &Type) -> Result<Self, Box<dyn Error + Sync + Send>> {
53✔
302
        Ok(SpatialReferenceOption::Unreferenced)
53✔
303
    }
53✔
304

305
    fn accepts(ty: &Type) -> bool {
1,431✔
306
        <SpatialReference as FromSql>::accepts(ty)
1,431✔
307
    }
1,431✔
308
}
309

310
impl std::fmt::Display for SpatialReferenceOption {
311
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
661✔
312
        match self {
661✔
313
            SpatialReferenceOption::SpatialReference(p) => write!(f, "{p}"),
649✔
314
            SpatialReferenceOption::Unreferenced => Ok(()),
12✔
315
        }
316
    }
661✔
317
}
318

319
impl From<SpatialReference> for SpatialReferenceOption {
320
    fn from(spatial_reference: SpatialReference) -> Self {
802✔
321
        Self::SpatialReference(spatial_reference)
802✔
322
    }
802✔
323
}
324

325
impl From<Option<SpatialReference>> for SpatialReferenceOption {
326
    fn from(option: Option<SpatialReference>) -> Self {
5✔
327
        match option {
5✔
328
            Some(p) => SpatialReferenceOption::SpatialReference(p),
4✔
329
            None => SpatialReferenceOption::Unreferenced,
1✔
330
        }
331
    }
5✔
332
}
333

334
impl Serialize for SpatialReferenceOption {
335
    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
651✔
336
    where
651✔
337
        S: Serializer,
651✔
338
    {
651✔
339
        serializer.serialize_str(&self.to_string())
651✔
340
    }
651✔
341
}
342

343
impl From<SpatialReferenceOption> for Option<SpatialReference> {
344
    fn from(s_ref: SpatialReferenceOption) -> Self {
27✔
345
        match s_ref {
27✔
346
            SpatialReferenceOption::SpatialReference(s) => Some(s),
26✔
347
            SpatialReferenceOption::Unreferenced => None,
1✔
348
        }
349
    }
27✔
350
}
351

352
/// Helper struct for deserializing a `SpatialReferenceOption`
353
struct SpatialReferenceOptionDeserializeVisitor;
354

355
impl Visitor<'_> for SpatialReferenceOptionDeserializeVisitor {
356
    type Value = SpatialReferenceOption;
357

358
    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
×
359
        formatter.write_str("a spatial reference in the form authority:code")
×
360
    }
×
361

362
    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
51✔
363
    where
51✔
364
        E: serde::de::Error,
51✔
365
    {
51✔
366
        if v.is_empty() {
51✔
367
            return Ok(SpatialReferenceOption::Unreferenced);
7✔
368
        }
44✔
369

370
        let spatial_reference: SpatialReference = v.parse().map_err(serde::de::Error::custom)?;
44✔
371

372
        Ok(spatial_reference.into())
43✔
373
    }
51✔
374
}
375

376
impl<'de> Deserialize<'de> for SpatialReferenceOption {
377
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
51✔
378
    where
51✔
379
        D: Deserializer<'de>,
51✔
380
    {
51✔
381
        deserializer.deserialize_str(SpatialReferenceOptionDeserializeVisitor)
51✔
382
    }
51✔
383
}
384

385
#[cfg(test)]
386
mod tests {
387
    use super::*;
388
    use std::convert::TryInto;
389

390
    #[test]
391
    fn display() {
1✔
392
        assert_eq!(SpatialReferenceAuthority::Epsg.to_string(), "EPSG");
1✔
393
        assert_eq!(SpatialReferenceAuthority::SrOrg.to_string(), "SR-ORG");
1✔
394
        assert_eq!(SpatialReferenceAuthority::Iau2000.to_string(), "IAU2000");
1✔
395
        assert_eq!(SpatialReferenceAuthority::Esri.to_string(), "ESRI");
1✔
396

397
        assert_eq!(
1✔
398
            SpatialReference::new(SpatialReferenceAuthority::Epsg, 4326).to_string(),
1✔
399
            "EPSG:4326"
1✔
400
        );
1✔
401
        assert_eq!(
1✔
402
            SpatialReference::new(SpatialReferenceAuthority::SrOrg, 1).to_string(),
1✔
403
            "SR-ORG:1"
1✔
404
        );
1✔
405
        assert_eq!(
1✔
406
            SpatialReference::new(SpatialReferenceAuthority::Iau2000, 4711).to_string(),
1✔
407
            "IAU2000:4711"
1✔
408
        );
1✔
409
        assert_eq!(
1✔
410
            SpatialReference::new(SpatialReferenceAuthority::Esri, 42).to_string(),
1✔
411
            "ESRI:42"
1✔
412
        );
1✔
413
    }
1✔
414

415
    #[test]
416
    fn serialize_json() {
1✔
417
        assert_eq!(
1✔
418
            serde_json::to_string(&SpatialReference::new(
1✔
419
                SpatialReferenceAuthority::Epsg,
1✔
420
                4326
1✔
421
            ))
1✔
422
            .unwrap(),
1✔
423
            "\"EPSG:4326\""
1✔
424
        );
1✔
425
        assert_eq!(
1✔
426
            serde_json::to_string(&SpatialReference::new(SpatialReferenceAuthority::SrOrg, 1))
1✔
427
                .unwrap(),
1✔
428
            "\"SR-ORG:1\""
1✔
429
        );
1✔
430
        assert_eq!(
1✔
431
            serde_json::to_string(&SpatialReference::new(
1✔
432
                SpatialReferenceAuthority::Iau2000,
1✔
433
                4711
1✔
434
            ))
1✔
435
            .unwrap(),
1✔
436
            "\"IAU2000:4711\""
1✔
437
        );
1✔
438
        assert_eq!(
1✔
439
            serde_json::to_string(&SpatialReference::new(SpatialReferenceAuthority::Esri, 42))
1✔
440
                .unwrap(),
1✔
441
            "\"ESRI:42\""
1✔
442
        );
1✔
443
    }
1✔
444

445
    #[test]
446
    fn deserialize_json() {
1✔
447
        assert_eq!(
1✔
448
            SpatialReference::new(SpatialReferenceAuthority::Epsg, 4326),
1✔
449
            serde_json::from_str("\"EPSG:4326\"").unwrap()
1✔
450
        );
1✔
451
        assert_eq!(
1✔
452
            SpatialReference::new(SpatialReferenceAuthority::SrOrg, 1),
1✔
453
            serde_json::from_str("\"SR-ORG:1\"").unwrap()
1✔
454
        );
1✔
455
        assert_eq!(
1✔
456
            SpatialReference::new(SpatialReferenceAuthority::Iau2000, 4711),
1✔
457
            serde_json::from_str("\"IAU2000:4711\"").unwrap()
1✔
458
        );
1✔
459
        assert_eq!(
1✔
460
            SpatialReference::new(SpatialReferenceAuthority::Esri, 42),
1✔
461
            serde_json::from_str("\"ESRI:42\"").unwrap()
1✔
462
        );
1✔
463

464
        assert!(serde_json::from_str::<SpatialReference>("\"foo:bar\"").is_err());
1✔
465
    }
1✔
466

467
    #[test]
468
    fn spatial_reference_option_serde() {
1✔
469
        assert_eq!(
1✔
470
            serde_json::to_string(&SpatialReferenceOption::SpatialReference(
1✔
471
                SpatialReference::new(SpatialReferenceAuthority::Epsg, 4326)
1✔
472
            ))
1✔
473
            .unwrap(),
1✔
474
            "\"EPSG:4326\""
1✔
475
        );
1✔
476

477
        assert_eq!(
1✔
478
            serde_json::to_string(&SpatialReferenceOption::Unreferenced).unwrap(),
1✔
479
            "\"\""
1✔
480
        );
1✔
481

482
        assert_eq!(
1✔
483
            SpatialReferenceOption::SpatialReference(SpatialReference::new(
1✔
484
                SpatialReferenceAuthority::Epsg,
1✔
485
                4326
1✔
486
            )),
1✔
487
            serde_json::from_str("\"EPSG:4326\"").unwrap()
1✔
488
        );
1✔
489

490
        assert_eq!(
1✔
491
            SpatialReferenceOption::Unreferenced,
1✔
492
            serde_json::from_str("\"\"").unwrap()
1✔
493
        );
1✔
494

495
        assert!(serde_json::from_str::<SpatialReferenceOption>("\"foo:bar\"").is_err());
1✔
496
    }
1✔
497

498
    #[test]
499
    fn is_spatial_ref() {
1✔
500
        let s_ref = SpatialReferenceOption::from(SpatialReference::epsg_4326());
1✔
501
        assert!(s_ref.is_spatial_ref());
1✔
502
        assert!(!s_ref.is_unreferenced());
1✔
503
    }
1✔
504

505
    #[test]
506
    fn is_unreferenced() {
1✔
507
        let s_ref = SpatialReferenceOption::Unreferenced;
1✔
508
        assert!(s_ref.is_unreferenced());
1✔
509
        assert!(!s_ref.is_spatial_ref());
1✔
510
    }
1✔
511

512
    #[test]
513
    fn from_option_some() {
1✔
514
        let s_ref: SpatialReferenceOption = Some(SpatialReference::epsg_4326()).into();
1✔
515
        assert_eq!(
1✔
516
            s_ref,
1✔
517
            SpatialReferenceOption::SpatialReference(SpatialReference::epsg_4326())
1✔
518
        );
1✔
519
    }
1✔
520

521
    #[test]
522
    fn from_option_none() {
1✔
523
        let s_ref: SpatialReferenceOption = None.into();
1✔
524
        assert_eq!(s_ref, SpatialReferenceOption::Unreferenced);
1✔
525
    }
1✔
526

527
    #[test]
528
    fn into_option_some() {
1✔
529
        let s_ref: Option<SpatialReference> =
1✔
530
            SpatialReferenceOption::SpatialReference(SpatialReference::epsg_4326()).into();
1✔
531
        assert_eq!(s_ref, Some(SpatialReference::epsg_4326()));
1✔
532
    }
1✔
533

534
    #[test]
535
    fn into_option_none() {
1✔
536
        let s_ref: Option<SpatialReference> = SpatialReferenceOption::Unreferenced.into();
1✔
537
        assert_eq!(s_ref, None);
1✔
538
    }
1✔
539

540
    #[test]
541
    fn proj_string() {
1✔
542
        assert_eq!(
1✔
543
            SpatialReference::new(SpatialReferenceAuthority::Epsg, 4326)
1✔
544
                .proj_string()
1✔
545
                .unwrap(),
1✔
546
            "EPSG:4326"
1✔
547
        );
1✔
548
        assert_eq!(
1✔
549
            SpatialReference::new(SpatialReferenceAuthority::SrOrg, 81)
1✔
550
                .proj_string()
1✔
551
                .unwrap(),
1✔
552
            "+proj=geos +lon_0=0 +h=35785831 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs +type=crs"
1✔
553
        );
1✔
554
        assert_eq!(
1✔
555
            SpatialReference::new(SpatialReferenceAuthority::Iau2000, 4711)
1✔
556
                .proj_string()
1✔
557
                .unwrap(),
1✔
558
            "IAU2000:4711"
1✔
559
        );
1✔
560
        assert_eq!(
1✔
561
            SpatialReference::new(SpatialReferenceAuthority::Esri, 42)
1✔
562
                .proj_string()
1✔
563
                .unwrap(),
1✔
564
            "ESRI:42"
1✔
565
        );
1✔
566
        assert!(
1✔
567
            SpatialReference::new(SpatialReferenceAuthority::SrOrg, 1)
1✔
568
                .proj_string()
1✔
569
                .is_err()
1✔
570
        );
1✔
571
    }
1✔
572

573
    #[test]
574
    fn spatial_reference_to_gdal_spatial_ref_epsg() {
1✔
575
        let spatial_reference = SpatialReference::epsg_4326();
1✔
576
        let gdal_sref: SpatialRef = spatial_reference.try_into().unwrap();
1✔
577

1✔
578
        assert_eq!(gdal_sref.auth_name().unwrap(), "EPSG");
1✔
579
        assert_eq!(gdal_sref.auth_code().unwrap(), 4326);
1✔
580
    }
1✔
581
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc