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

geo-engine / geoengine / 3929938005

pending completion
3929938005

push

github

GitHub
Merge #713

84930 of 96741 relevant lines covered (87.79%)

79640.1 hits per line

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

93.7
/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
#[cfg(feature = "postgres")]
9
use postgres_types::private::BytesMut;
10
#[cfg(feature = "postgres")]
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
#[cfg(feature = "postgres")]
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(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Serialize, Deserialize)]
132✔
23
#[cfg_attr(feature = "postgres", derive(ToSql, FromSql))]
142✔
24
#[serde(rename_all = "SCREAMING-KEBAB-CASE")]
25
pub enum SpatialReferenceAuthority {
26
    Epsg,
27
    SrOrg,
28
    Iau2000,
29
    Esri,
30
}
31

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

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

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

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

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

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

73
    pub fn proj_string(self) -> Result<String> {
74
        match self.authority {
2✔
75
            SpatialReferenceAuthority::Epsg | SpatialReferenceAuthority::Iau2000 => {
76
                Ok(format!("{}:{}", self.authority, self.code))
465✔
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 | SpatialReferenceAuthority::Esri => {
81
                Err(error::Error::ProjStringUnresolvable { spatial_ref: self })
2✔
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
    }
468✔
86

87
    /// Return the area of use in EPSG:4326 projection
88
    pub fn area_of_use<A: AxisAlignedRectangle>(self) -> Result<A> {
62✔
89
        let proj_string = match self.proj_string() {
62✔
90
            Ok(s) => s,
62✔
91
            Err(e) => return Err(e),
×
92
        };
93

94
        let proj = Proj::new(&proj_string).ok_or(error::Error::InvalidProjDefinition {
62✔
95
            proj_definition: proj_string.clone(),
62✔
96
        })?;
62✔
97
        let area = proj
62✔
98
            .area_of_use()
62✔
99
            .context(error::ProjInternal)?
62✔
100
            .0
101
            .ok_or(error::Error::NoAreaOfUseDefined { proj_string })?;
62✔
102
        A::from_min_max(
62✔
103
            (area.west, area.south).into(),
62✔
104
            (area.east, area.north).into(),
62✔
105
        )
62✔
106
    }
62✔
107

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

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

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

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

138
        area_out
6✔
139
            .intersection(&area_other)
6✔
140
            .map(|x| x.reproject(&valid_bounds_proj))
6✔
141
            .transpose()
6✔
142
    }
6✔
143
}
144

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

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

160
/// Helper struct for deserializing a `SpatialReferencce`
161
struct SpatialReferenceDeserializeVisitor;
162

163
impl<'de> Visitor<'de> for SpatialReferenceDeserializeVisitor {
164
    type Value = SpatialReference;
165

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

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

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

187
impl FromStr for SpatialReferenceAuthority {
188
    type Err = error::Error;
189

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

205
impl FromStr for SpatialReference {
206
    type Err = error::Error;
207

208
    fn from_str(s: &str) -> Result<Self, Self::Err> {
83✔
209
        let mut split = s.split(':');
83✔
210

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

223
impl TryFrom<SpatialRef> for SpatialReference {
224
    type Error = error::Error;
225

226
    fn try_from(value: SpatialRef) -> Result<Self, Self::Error> {
58✔
227
        Ok(SpatialReference::new(
58✔
228
            SpatialReferenceAuthority::from_str(&value.auth_name()?)?,
58✔
229
            value.auth_code()? as u32,
58✔
230
        ))
231
    }
58✔
232
}
233

234
impl TryFrom<SpatialReference> for SpatialRef {
235
    type Error = error::Error;
236

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

×
242
        // TODO: support other projections reliably
×
243

×
244
        SpatialRef::from_proj4(&value.proj_string()?).context(error::Gdal)
×
245
    }
17✔
246
}
247

248
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
605✔
249
pub enum SpatialReferenceOption {
250
    SpatialReference(SpatialReference),
251
    Unreferenced,
252
}
253

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

262
    pub fn is_unreferenced(self) -> bool {
2✔
263
        !self.is_spatial_ref()
2✔
264
    }
2✔
265
}
266

267
#[cfg(feature = "postgres")]
268
impl ToSql for SpatialReferenceOption {
269
    fn to_sql(&self, ty: &Type, out: &mut BytesMut) -> Result<IsNull, Box<dyn Error + Sync + Send>>
28✔
270
    where
28✔
271
        Self: Sized,
28✔
272
    {
28✔
273
        match self {
28✔
274
            SpatialReferenceOption::SpatialReference(sref) => sref.to_sql(ty, out),
2✔
275
            SpatialReferenceOption::Unreferenced => Ok(IsNull::Yes),
26✔
276
        }
277
    }
28✔
278

279
    fn accepts(ty: &Type) -> bool
28✔
280
    where
28✔
281
        Self: Sized,
28✔
282
    {
28✔
283
        <SpatialReference as ToSql>::accepts(ty)
28✔
284
    }
28✔
285

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

298
#[cfg(feature = "postgres")]
299
impl<'a> FromSql<'a> for SpatialReferenceOption {
300
    fn from_sql(ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
2✔
301
        Ok(SpatialReferenceOption::SpatialReference(
2✔
302
            SpatialReference::from_sql(ty, raw)?,
2✔
303
        ))
304
    }
2✔
305

306
    fn from_sql_null(_: &Type) -> Result<Self, Box<dyn Error + Sync + Send>> {
8✔
307
        Ok(SpatialReferenceOption::Unreferenced)
8✔
308
    }
8✔
309

310
    fn accepts(ty: &Type) -> bool {
17✔
311
        <SpatialReference as FromSql>::accepts(ty)
17✔
312
    }
17✔
313
}
314

315
impl std::fmt::Display for SpatialReferenceOption {
316
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109✔
317
        match self {
109✔
318
            SpatialReferenceOption::SpatialReference(p) => write!(f, "{p}"),
91✔
319
            SpatialReferenceOption::Unreferenced => Ok(()),
18✔
320
        }
321
    }
109✔
322
}
323

324
impl From<SpatialReference> for SpatialReferenceOption {
325
    fn from(spatial_reference: SpatialReference) -> Self {
531✔
326
        Self::SpatialReference(spatial_reference)
531✔
327
    }
531✔
328
}
329

330
impl From<Option<SpatialReference>> for SpatialReferenceOption {
331
    fn from(option: Option<SpatialReference>) -> Self {
10✔
332
        match option {
10✔
333
            Some(p) => SpatialReferenceOption::SpatialReference(p),
9✔
334
            None => SpatialReferenceOption::Unreferenced,
1✔
335
        }
336
    }
10✔
337
}
338

339
impl Serialize for SpatialReferenceOption {
340
    fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>
109✔
341
    where
109✔
342
        S: Serializer,
109✔
343
    {
109✔
344
        serializer.serialize_str(&self.to_string())
109✔
345
    }
109✔
346
}
347

348
impl From<SpatialReferenceOption> for Option<SpatialReference> {
349
    fn from(s_ref: SpatialReferenceOption) -> Self {
23✔
350
        match s_ref {
23✔
351
            SpatialReferenceOption::SpatialReference(s) => Some(s),
22✔
352
            SpatialReferenceOption::Unreferenced => None,
1✔
353
        }
354
    }
23✔
355
}
356

357
/// Helper struct for deserializing a `SpatialReferenceOption`
358
struct SpatialReferenceOptionDeserializeVisitor;
359

360
impl<'de> Visitor<'de> for SpatialReferenceOptionDeserializeVisitor {
361
    type Value = SpatialReferenceOption;
362

363
    fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
×
364
        formatter.write_str("a spatial reference in the form authority:code")
×
365
    }
×
366

367
    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
33✔
368
    where
33✔
369
        E: serde::de::Error,
33✔
370
    {
33✔
371
        if v.is_empty() {
33✔
372
            return Ok(SpatialReferenceOption::Unreferenced);
10✔
373
        }
23✔
374

375
        let spatial_reference: SpatialReference = v.parse().map_err(serde::de::Error::custom)?;
23✔
376

377
        Ok(spatial_reference.into())
22✔
378
    }
33✔
379
}
380

381
impl<'de> Deserialize<'de> for SpatialReferenceOption {
382
    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
33✔
383
    where
33✔
384
        D: Deserializer<'de>,
33✔
385
    {
33✔
386
        deserializer.deserialize_str(SpatialReferenceOptionDeserializeVisitor)
33✔
387
    }
33✔
388
}
389

390
#[cfg(test)]
391
mod tests {
392
    use super::*;
393
    use std::convert::TryInto;
394

395
    #[test]
1✔
396
    fn display() {
1✔
397
        assert_eq!(SpatialReferenceAuthority::Epsg.to_string(), "EPSG");
1✔
398
        assert_eq!(SpatialReferenceAuthority::SrOrg.to_string(), "SR-ORG");
1✔
399
        assert_eq!(SpatialReferenceAuthority::Iau2000.to_string(), "IAU2000");
1✔
400
        assert_eq!(SpatialReferenceAuthority::Esri.to_string(), "ESRI");
1✔
401

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

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

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

469
        assert!(serde_json::from_str::<SpatialReference>("\"foo:bar\"").is_err());
1✔
470
    }
1✔
471

472
    #[test]
1✔
473
    fn spatial_reference_option_serde() {
1✔
474
        assert_eq!(
1✔
475
            serde_json::to_string(&SpatialReferenceOption::SpatialReference(
1✔
476
                SpatialReference::new(SpatialReferenceAuthority::Epsg, 4326)
1✔
477
            ))
1✔
478
            .unwrap(),
1✔
479
            "\"EPSG:4326\""
1✔
480
        );
1✔
481

482
        assert_eq!(
1✔
483
            serde_json::to_string(&SpatialReferenceOption::Unreferenced).unwrap(),
1✔
484
            "\"\""
1✔
485
        );
1✔
486

487
        assert_eq!(
1✔
488
            SpatialReferenceOption::SpatialReference(SpatialReference::new(
1✔
489
                SpatialReferenceAuthority::Epsg,
1✔
490
                4326
1✔
491
            )),
1✔
492
            serde_json::from_str("\"EPSG:4326\"").unwrap()
1✔
493
        );
1✔
494

495
        assert_eq!(
1✔
496
            SpatialReferenceOption::Unreferenced,
1✔
497
            serde_json::from_str("\"\"").unwrap()
1✔
498
        );
1✔
499

500
        assert!(serde_json::from_str::<SpatialReferenceOption>("\"foo:bar\"").is_err());
1✔
501
    }
1✔
502

503
    #[test]
1✔
504
    fn is_spatial_ref() {
1✔
505
        let s_ref = SpatialReferenceOption::from(SpatialReference::epsg_4326());
1✔
506
        assert!(s_ref.is_spatial_ref());
1✔
507
        assert!(!s_ref.is_unreferenced());
1✔
508
    }
1✔
509

510
    #[test]
1✔
511
    fn is_unreferenced() {
1✔
512
        let s_ref = SpatialReferenceOption::Unreferenced;
1✔
513
        assert!(s_ref.is_unreferenced());
1✔
514
        assert!(!s_ref.is_spatial_ref());
1✔
515
    }
1✔
516

517
    #[test]
1✔
518
    fn from_option_some() {
1✔
519
        let s_ref: SpatialReferenceOption = Some(SpatialReference::epsg_4326()).into();
1✔
520
        assert_eq!(
1✔
521
            s_ref,
1✔
522
            SpatialReferenceOption::SpatialReference(SpatialReference::epsg_4326())
1✔
523
        );
1✔
524
    }
1✔
525

526
    #[test]
1✔
527
    fn from_option_none() {
1✔
528
        let s_ref: SpatialReferenceOption = None.into();
1✔
529
        assert_eq!(s_ref, SpatialReferenceOption::Unreferenced);
1✔
530
    }
1✔
531

532
    #[test]
1✔
533
    fn into_option_some() {
1✔
534
        let s_ref: Option<SpatialReference> =
1✔
535
            SpatialReferenceOption::SpatialReference(SpatialReference::epsg_4326()).into();
1✔
536
        assert_eq!(s_ref, Some(SpatialReference::epsg_4326()));
1✔
537
    }
1✔
538

539
    #[test]
1✔
540
    fn into_option_none() {
1✔
541
        let s_ref: Option<SpatialReference> = SpatialReferenceOption::Unreferenced.into();
1✔
542
        assert_eq!(s_ref, None);
1✔
543
    }
1✔
544

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

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

1✔
576
        assert_eq!(gdal_sref.auth_name().unwrap(), "EPSG");
1✔
577
        assert_eq!(gdal_sref.auth_code().unwrap(), 4326);
1✔
578
    }
1✔
579
}
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