Skip to main content

powerio/geo/
mod.rs

1//! Typed coordinate metadata for the balanced model, and the standalone
2//! geographic document ([`GeoLayer`]) that carries coordinates as a file of
3//! their own.
4
5mod layer;
6mod pwd;
7
8pub use layer::{
9    ElementKey, GEO_LAYER_EXTENSION, GeoApplyReport, GeoApplyTarget, GeoFeature, GeoGeometry,
10    GeoLayer, GeoParsed, GeoTarget, apply_geo_features,
11};
12pub use pwd::{
13    PWD_MERCATOR_K, apply_substation_points, geo_layer_from_aux_substations, geo_layer_from_pwd,
14    pwd_mercator_to_lonlat,
15};
16
17use serde::{Deserialize, Serialize};
18
19/// A point attached to one model element.
20#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
21#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
22pub struct Location {
23    /// X coordinate. In geographic space this is longitude.
24    pub x: f64,
25    /// Y coordinate. In geographic space this is latitude.
26    pub y: f64,
27    /// Per point provenance when it differs from the network default.
28    #[serde(default, skip_serializing_if = "Option::is_none")]
29    pub kind: Option<CoordsKind>,
30}
31
32/// Coordinate provenance.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
34#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
35#[serde(rename_all = "snake_case")]
36#[non_exhaustive]
37pub enum CoordsKind {
38    Source,
39    Synthetic,
40    Manual,
41    Derived,
42}
43
44/// Network level coordinate metadata.
45#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
46#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
47pub struct GeoMeta {
48    /// Coordinate space shared by every location on the network.
49    #[serde(flatten)]
50    pub space: CoordinateSpace,
51    /// Default provenance for points without their own `kind`.
52    #[serde(default, skip_serializing_if = "Option::is_none")]
53    pub kind: Option<CoordsKind>,
54}
55
56/// Coordinate space for locations in a network.
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
59#[serde(tag = "space", rename_all = "snake_case")]
60#[non_exhaustive]
61pub enum CoordinateSpace {
62    /// x = longitude and y = latitude in decimal degrees. `None` means EPSG:4326.
63    Geographic {
64        #[serde(default, skip_serializing_if = "Option::is_none")]
65        crs: Option<String>,
66    },
67    /// Planar coordinates, with the CRS named when known.
68    Projected {
69        #[serde(default, skip_serializing_if = "Option::is_none")]
70        crs: Option<String>,
71    },
72    /// Drawing coordinates with no earth referent.
73    Diagram {
74        #[serde(default, skip_serializing_if = "Option::is_none")]
75        canvas: Option<Canvas>,
76    },
77    /// The source did not declare a coordinate space.
78    Unknown,
79}
80
81impl CoordinateSpace {
82    /// The serialized token naming the space family (`geographic`, `projected`,
83    /// `diagram`, `unknown`), as the `powerio_geo` member spells it.
84    #[must_use]
85    pub fn token(&self) -> &'static str {
86        match self {
87            CoordinateSpace::Geographic { .. } => "geographic",
88            CoordinateSpace::Projected { .. } => "projected",
89            CoordinateSpace::Diagram { .. } => "diagram",
90            _ => "unknown",
91        }
92    }
93}
94
95/// Diagram canvas metadata.
96#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
97#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
98pub struct Canvas {
99    #[serde(default, skip_serializing_if = "Option::is_none")]
100    pub width: Option<f64>,
101    #[serde(default, skip_serializing_if = "Option::is_none")]
102    pub height: Option<f64>,
103    #[serde(default, skip_serializing_if = "Option::is_none")]
104    pub units: Option<String>,
105}