Skip to main content

from_path/
from_path.rs

1#![expect(
2    clippy::print_stdout,
3    reason = "the example intentionally displays the map data it reads"
4)]
5#![expect(
6    clippy::unwrap_used,
7    reason = "the example input is expected to contain nonempty objects and known symbols"
8)]
9#![expect(
10    clippy::expect_used,
11    reason = "the example input is expected to give the named symbol its documented type"
12)]
13
14use std::{cell::RefCell, rc::Weak};
15
16use geo_types::{Coord, LineString};
17#[cfg(feature = "geo_ref")]
18use omap::geo_referencing::GeoRef;
19#[cfg(feature = "geo_ref")]
20use omap::objects::MapObject;
21use omap::{
22    Code, Error, Omap,
23    colors::Color,
24    objects::{LineObject, TextGeometry, TextObject},
25    symbols::{TextSymbol, WeakLinePathSymbol},
26};
27
28fn main() -> Result<(), Error> {
29    let mut map = Omap::from_path("./example_data/from_path.omap")?;
30
31    #[cfg(feature = "geo_ref")]
32    {
33        // we want to move the map center to the average position of all objects
34        let old_transform = map.geo_referencing.get_transform();
35
36        let mut mean_pos = Coord::zero();
37        let mut num_coords = 0;
38        for obj in map.parts.iter().flat_map(|part| part.iter_all_objects()) {
39            match obj {
40                MapObject::Point(object) => {
41                    mean_pos = mean_pos + object.get_geometry().0;
42                    num_coords += 1;
43                }
44                MapObject::Line(object) => {
45                    let geometry = object.get_geometry(0.1)?;
46                    mean_pos =
47                        mean_pos + geometry.0.iter().copied().reduce(|sum, c| sum + c).unwrap();
48                    num_coords += geometry.0.len();
49                }
50                MapObject::Area(object) => {
51                    let geometry = object.get_geometry(0.1)?;
52                    mean_pos = mean_pos
53                        + geometry
54                            .exterior()
55                            .0
56                            .iter()
57                            .copied()
58                            .reduce(|sum, c| sum + c)
59                            .unwrap();
60                    num_coords += geometry.exterior().0.len();
61                }
62                MapObject::Text(object) => {
63                    match object.get_geometry() {
64                        TextGeometry::SingleAnchor(coord) => mean_pos = mean_pos + *coord,
65                        TextGeometry::WrapBox(wrap_box) => mean_pos = mean_pos + wrap_box.anchor,
66                    }
67                    num_coords += 1;
68                }
69            }
70        }
71        mean_pos = mean_pos / num_coords as f64;
72
73        // now transform that into projected coords
74        let mean_proj_pos = old_transform.to_projected(mean_pos);
75
76        // get the new georef info for that position
77        let new_gr = GeoRef::initialize(
78            mean_proj_pos,
79            map.geo_referencing.crs_type,
80            2_469.,
81            map.geo_referencing.scale_denominator,
82        )
83        .unwrap();
84
85        // assign the new info
86        map.geo_referencing = new_gr;
87
88        // get the new map transform
89        let new_transform = map.geo_referencing.get_transform();
90
91        // transfrom every object out of the old map space to projected coords
92        // and from projected coord to the new map space
93        // NB! If the new projection were different than the old,
94        // a transfrom between projections using a proj library like proj-core would be needed
95        // and this function would return Err
96        map.apply_affine_between(&old_transform, &new_transform)
97            .unwrap();
98    };
99
100    println!("Map colors in order:");
101    for color in map.colors.iter() {
102        match color {
103            Color::SpotColor(ref_cell) => {
104                let b = ref_cell.try_borrow().unwrap();
105                println!("{} with spot name {}", b.color_name, b.spotcolor_name);
106            }
107            Color::MixedColor(ref_cell) => {
108                println!("{}", ref_cell.try_borrow().unwrap().color_name);
109            }
110        }
111    }
112
113    let erosion_gully = map
114        .symbols
115        .get_symbol_by_code(Code::new(107, 0, 0))
116        .unwrap()
117        .downgrade();
118
119    let mut ls = LineObject::new(
120        WeakLinePathSymbol::try_from(erosion_gully).unwrap(),
121        // geometry coordinates are always in mm of paper
122        LineString::new(vec![Coord { x: -60., y: -50. }, Coord { x: 60., y: -50. }]),
123    );
124    ls.tags.insert("Some Key".to_owned(), "My value".to_owned());
125
126    map.parts.0[0].add_object(ls);
127
128    let weak_symbol = map
129        .symbols
130        .get_symbol_by_name("Contour value")
131        .unwrap()
132        .downgrade();
133
134    let ts = TextObject::new(
135        Weak::<RefCell<TextSymbol>>::try_from(weak_symbol)
136            .expect("The symbol type of Contour value is not Text"),
137        TextGeometry::SingleAnchor(Coord { x: 0., y: 0. }),
138        "This is the middle of the map".to_owned(),
139    );
140    map.parts.0[0].add_object(ts);
141
142    map.write_to_file("./from_path_out.omap")
143}