1use bevy::prelude::{info_span, Mesh};
2use build_mesh::BuildMesh;
3use geo_traits::*;
4use line_string::LineStringMeshBuilder;
5use polygon::PolygonMeshBuilder;
6use std::iter;
7
8pub use point::SpritePosition;
9pub use polygon::PolygonMesh;
10
11mod build_mesh;
12mod line_string;
13mod point;
14mod polygon;
15
16pub fn line_to_mesh(line: impl LineTrait) -> Result<Mesh, Error> {
17 let mut mesh_builder = LineStringMeshBuilder::new();
18 mesh_builder.add_coords(iter::once(line.start()).chain(iter::once(line.end())))?;
19 mesh_builder.try_into()
20}
21
22pub fn line_string_to_mesh(line_string: impl LineStringTrait) -> Result<Mesh, Error> {
23 let mut mesh_builder = LineStringMeshBuilder::new();
24 mesh_builder.add_coords(line_string.coords())?;
25 mesh_builder.try_into()
26}
27
28pub fn multi_line_string_to_mesh(
29 multi_line_string: impl MultiLineStringTrait,
30) -> Result<Vec<Mesh>, Error> {
31 let mut line_string_meshes = Vec::with_capacity(multi_line_string.num_line_strings());
32
33 for line_string in multi_line_string.line_strings() {
34 line_string_meshes.push(line_string_to_mesh(line_string)?);
35 }
36
37 Ok(line_string_meshes)
38}
39
40pub fn polygon_to_mesh<Scalar: geo_types::CoordFloat>(
41 polygon: impl PolygonTrait<T = Scalar>,
42) -> Result<PolygonMesh, Error> {
43 let mut mesh_builder = PolygonMeshBuilder::new();
44 mesh_builder.add_polygon(&polygon)?;
45 mesh_builder.try_into()
46}
47
48pub fn multi_polygon_to_mesh<Scalar: geo_types::CoordFloat>(
49 multi_polygon: impl MultiPolygonTrait<T = Scalar>,
50) -> Result<Vec<PolygonMesh>, Error> {
51 let polygons = multi_polygon.polygons();
52 let mut polygon_meshes = Vec::with_capacity(polygons.len());
53 for polygon in polygons {
54 polygon_meshes.push(polygon_to_mesh(polygon)?);
55 }
56
57 Ok(polygon_meshes)
58}
59
60pub fn rect_to_mesh<Scalar: geo_types::CoordFloat>(
61 rect: impl RectTrait<T = Scalar>,
62) -> Result<PolygonMesh, Error> {
63 let mut mesh_builder = PolygonMeshBuilder::default();
64 mesh_builder.add_polygon_from_exterior_coords(
65 [
66 (rect.min().x(), rect.min().y()),
67 (rect.min().x(), rect.max().y()),
68 (rect.max().x(), rect.max().y()),
69 (rect.max().x(), rect.min().y()),
70 (rect.min().x(), rect.min().y()),
71 ]
72 .into_iter(),
73 )?;
74 PolygonMesh::try_from(mesh_builder)
75}
76
77pub fn triangle_to_mesh<Scalar: geo_types::CoordFloat>(
78 triangle: impl TriangleTrait<T = Scalar>,
79) -> Result<PolygonMesh, Error> {
80 let mut mesh_builder = PolygonMeshBuilder::default();
81 mesh_builder.add_polygon_from_exterior_coords(
82 [
83 (triangle.first().x(), triangle.first().y()),
84 (triangle.second().x(), triangle.second().y()),
85 (triangle.third().x(), triangle.third().y()),
86 (triangle.first().x(), triangle.first().y()),
87 ]
88 .into_iter(),
89 )?;
90 PolygonMesh::try_from(mesh_builder)
91}
92
93pub fn geometry_to_mesh<Scalar: geo_types::CoordFloat>(
94 geometry: impl GeometryTrait<T = Scalar>,
95) -> Result<GeometryMesh, Error> {
96 let mut ctx = build_mesh::BuildBevyMeshesContext::default();
97
98 info_span!("Populating Bevy mesh builder")
99 .in_scope(|| build_mesh::populate_geometry_mesh_builders(&geometry, &mut ctx))?;
100
101 info_span!("Building Bevy meshes").in_scope(|| {
102 [
103 ctx.point_mesh_builder.build(),
104 ctx.line_string_mesh_builder.build(),
105 ctx.polygon_mesh_builder.build(),
106 ]
107 .into_iter()
108 .find(|prepared_mesh| prepared_mesh.is_ok())
109 .unwrap_or(Err(Error::CouldNotBuildMesh))
110 })
111}
112
113pub enum GeometryMesh {
114 Point(Vec<SpritePosition>),
115 LineString(Mesh),
116 Polygon(polygon::PolygonMesh),
117}
118
119#[derive(Debug)]
120pub enum Error {
121 CouldNotBuildMesh,
122 CouldNotConvertToF32,
123 EmptyGeometry,
124 BevyEarcutr(bevy_earcutr::Error),
125}