Skip to main content

microcad_export/wkt/
mod.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! Export 2D models to Well-Known Text (WKT).
5
6use std::fmt::Write;
7
8use geo::line_string;
9use microcad_core::{Geometries2D, Geometry2D, Transformed2D, mat4_to_mat3};
10use microcad_lang::{
11    Id,
12    builtin::{ExportError, Exporter, FileIoInterface},
13    model::{Model, OutputType},
14    value::Value,
15};
16use wkt::ToWkt;
17
18/// WKT Exporter.
19pub struct WktExporter;
20
21trait WriteWkt {
22    fn write_wkt(&self, writer: &mut impl Write) -> std::fmt::Result;
23}
24
25impl WriteWkt for Geometries2D {
26    fn write_wkt(&self, writer: &mut impl Write) -> std::fmt::Result {
27        writeln!(writer, "GEOMETRYCOLLECTION(")?;
28        self.iter().try_for_each(|geo| geo.write_wkt(writer))?;
29        writeln!(writer, ")")
30    }
31}
32
33impl WriteWkt for Geometry2D {
34    fn write_wkt(&self, writer: &mut impl Write) -> std::fmt::Result {
35        match &self {
36            Geometry2D::LineString(line_string) => {
37                writeln!(writer, "{}", line_string.wkt_string())
38            }
39            Geometry2D::MultiLineString(multi_line_string) => {
40                writeln!(writer, "{}", multi_line_string.wkt_string())
41            }
42            Geometry2D::Polygon(polygon) => {
43                writeln!(writer, "{}", polygon.wkt_string())
44            }
45            Geometry2D::MultiPolygon(multi_polygon) => {
46                writeln!(writer, "{}", multi_polygon.wkt_string())
47            }
48            Geometry2D::Rect(rect) => {
49                writeln!(writer, "{}", rect.wkt_string())
50            }
51            Geometry2D::Line(line) => {
52                writeln!(
53                    writer,
54                    "{}",
55                    line_string![line.0.into(), line.1.into()].wkt_string()
56                )
57            }
58            Geometry2D::Collection(collection) => collection.write_wkt(writer),
59        }
60    }
61}
62
63impl WriteWkt for Model {
64    fn write_wkt(&self, writer: &mut impl Write) -> std::fmt::Result {
65        let self_ = self.borrow();
66        let output = self_.output();
67        match &output.geometry {
68            Some(microcad_lang::render::GeometryOutput::Geometry2D(geometry)) => {
69                let mat = output.world_matrix.expect("Some matrix");
70                (*geometry.transformed_2d(&mat4_to_mat3(&mat))).write_wkt(writer)
71            }
72            None => self_
73                .children()
74                .try_for_each(|model| model.write_wkt(writer)),
75            _ => Ok(()),
76        }
77    }
78}
79
80impl Exporter for WktExporter {
81    fn export(&self, model: &Model, filename: &std::path::Path) -> Result<Value, ExportError> {
82        use std::io::Write;
83
84        let mut f = std::fs::File::create(filename)?;
85        let mut buffer = String::new();
86        model.write_wkt(&mut buffer)?;
87        f.write_all(buffer.as_bytes())?;
88        Ok(Value::None)
89    }
90
91    fn output_type(&self) -> OutputType {
92        OutputType::Geometry2D
93    }
94}
95
96impl FileIoInterface for WktExporter {
97    fn id(&self) -> Id {
98        Id::new("wkt")
99    }
100}