microcad_core/geo2d/
primitives.rs

1// Copyright © 2025 The µcad authors <info@ucad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4//! 2D primitives
5
6use geo::AffineOps;
7
8use crate::{geo2d::*, *};
9
10/// Line string.
11pub type LineString = geo::LineString<Scalar>;
12/// Multiple line strings.
13pub type MultiLineString = geo::MultiLineString<Scalar>;
14/// Polygon.
15pub type Polygon = geo::Polygon<Scalar>;
16/// Multiple polygons.
17pub type MultiPolygon = geo::MultiPolygon<Scalar>;
18/// Rectangle.
19pub type Rect = geo::Rect<Scalar>;
20/// Point.
21pub type Point = geo::Point<Scalar>;
22
23impl RenderToMultiPolygon for LineString {}
24
25impl Transformed2D for LineString {
26    fn transformed_2d(&self, _: &RenderResolution, mat: &Mat3) -> Self {
27        self.affine_transform(&mat3_to_affine_transform(mat))
28    }
29}
30
31impl RenderToMultiPolygon for MultiLineString {}
32
33impl Transformed2D for MultiLineString {
34    fn transformed_2d(&self, _: &RenderResolution, mat: &Mat3) -> Self {
35        self.affine_transform(&mat3_to_affine_transform(mat))
36    }
37}
38
39impl RenderToMultiPolygon for Polygon {
40    fn render_to_polygon(&self, _: &RenderResolution) -> Option<Polygon> {
41        Some(self.clone())
42    }
43}
44
45impl Transformed2D for Polygon {
46    fn transformed_2d(&self, _: &RenderResolution, mat: &Mat3) -> Self {
47        self.affine_transform(&mat3_to_affine_transform(mat))
48    }
49}
50
51impl RenderToMultiPolygon for MultiPolygon {
52    fn render_to_existing_multi_polygon(
53        &self,
54        _resolution: &RenderResolution,
55        polygons: &mut MultiPolygon,
56    ) {
57        polygons.0.append(&mut self.0.clone());
58    }
59}
60
61impl Transformed2D for MultiPolygon {
62    fn transformed_2d(&self, _: &RenderResolution, mat: &Mat3) -> Self {
63        self.affine_transform(&mat3_to_affine_transform(mat))
64    }
65}
66
67impl FetchPoints2D for Rect {
68    fn fetch_points_2d(&self) -> Vec<Vec2> {
69        let min = self.min();
70        let max = self.max();
71        vec![
72            Vec2::new(min.x, min.y),
73            Vec2::new(min.x, max.y),
74            Vec2::new(max.x, min.y),
75            Vec2::new(max.x, max.y),
76        ]
77    }
78}
79
80impl RenderToMultiPolygon for Rect {
81    fn render_to_polygon(&self, _: &RenderResolution) -> Option<Polygon> {
82        Some(self.to_polygon())
83    }
84}
85
86impl Transformed2D for Rect {
87    fn transformed_2d(&self, _: &RenderResolution, mat: &Mat3) -> Self {
88        self.affine_transform(&mat3_to_affine_transform(mat))
89    }
90}
91
92impl Transformed2D<Polygon> for Rect {
93    fn transformed_2d(&self, render_resolution: &RenderResolution, mat: &Mat3) -> Polygon {
94        self.render_to_polygon(render_resolution)
95            .expect("Polygon")
96            .transformed_2d(render_resolution, mat)
97    }
98}
99
100/// Convert a line string to a vector of [`Scalar`].
101pub fn line_string_to_vec(line_string: &LineString) -> Vec<Scalar> {
102    line_string
103        .points()
104        .flat_map(|point| vec![point.x(), point.y()])
105        .collect()
106}
107
108/// Convert a polygon to a vector of [`Scalar`].
109///
110/// Exterior polygon has CW winding order, interior polygon have CCW winding order.
111pub fn polygon_to_vec(polygon: &Polygon) -> Vec<Scalar> {
112    let mut vec = line_string_to_vec(polygon.exterior());
113    polygon.interiors().iter().for_each(|interior| {
114        vec.append(&mut line_string_to_vec(interior));
115    });
116    vec
117}
118
119/// Convert a multi polygon into a vector of coordinates.
120pub fn multi_polygon_to_vec(multi_polygon: &MultiPolygon) -> Vec<Vec<Scalar>> {
121    multi_polygon.0.iter().map(polygon_to_vec).collect()
122}