From 27fbbb4886833a5d2e59c2c550657fa880b534bf Mon Sep 17 00:00:00 2001 From: charlotte Date: Sun, 20 Jul 2025 14:31:03 -0700 Subject: [PATCH 01/17] Make line segments mesehable. --- crates/bevy_math/src/primitives/dim2.rs | 9 ++++ crates/bevy_math/src/primitives/dim3.rs | 9 ++++ crates/bevy_mesh/src/primitives/dim2.rs | 42 ++++++++++++++++- crates/bevy_mesh/src/primitives/dim3/mod.rs | 1 + .../src/primitives/dim3/segment3d.rs | 45 +++++++++++++++++++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 crates/bevy_mesh/src/primitives/dim3/segment3d.rs diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index 9cb379706c18b..98f0ee5b9a41f 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -1245,6 +1245,15 @@ pub struct Segment2d { impl Primitive2d for Segment2d {} +impl Default for Segment2d { + /// Returns the default [`Segment2d`] with endpoints at `(0.0, 0.0)` and `(1.0, 0.0)`. + fn default() -> Self { + Self { + vertices: [Vec2::new(0.0, 0.0), Vec2::new(1.0, 0.0)], + } + } +} + impl Segment2d { /// Create a new `Segment2d` from its endpoints. #[inline(always)] diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 86aa6c5bdf068..a7208c37e5b9d 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -377,6 +377,15 @@ pub struct Segment3d { impl Primitive3d for Segment3d {} +impl Default for Segment3d { + /// Returns the default [`Segment3d`] with endpoints at `(0.0, 0.0, 0.0)` and `(1.0, 0.0, 0.0)`. + fn default() -> Self { + Self { + vertices: [Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 0.0)], + } + } +} + impl Segment3d { /// Create a new `Segment3d` from its endpoints. #[inline(always)] diff --git a/crates/bevy_mesh/src/primitives/dim2.rs b/crates/bevy_mesh/src/primitives/dim2.rs index e543f8a1951e3..172cb152074d8 100644 --- a/crates/bevy_mesh/src/primitives/dim2.rs +++ b/crates/bevy_mesh/src/primitives/dim2.rs @@ -8,7 +8,7 @@ use bevy_math::{ ops, primitives::{ Annulus, Capsule2d, Circle, CircularSector, CircularSegment, ConvexPolygon, Ellipse, - Rectangle, RegularPolygon, Rhombus, Triangle2d, Triangle3d, WindingOrder, + Rectangle, RegularPolygon, Rhombus, Segment2d, Triangle2d, Triangle3d, WindingOrder, }, FloatExt, Vec2, }; @@ -636,6 +636,46 @@ impl From for Mesh { } } +/// A builder used for creating a [`Mesh`] with a [`Segment2d`]. +pub struct Segment2dMeshBuilder { + /// The [`Segment2d`] shape. + pub segment: Segment2d, +} + +impl Segment2dMeshBuilder { + /// Creates a new [`Segment2dMeshBuilder`] from a given segment. + #[inline] + pub const fn new(line: Segment2d) -> Self { + Self { segment: line } + } +} + +impl MeshBuilder for Segment2dMeshBuilder { + fn build(&self) -> Mesh { + let positions = self.segment.vertices.map(|v| v.extend(0.0)).to_vec(); + let indices = Indices::U32(vec![0, 1]); + + Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default()) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + .with_inserted_indices(indices) + } +} + +impl Meshable for Segment2d { + type Output = Segment2dMeshBuilder; + + fn mesh(&self) -> Self::Output { + Segment2dMeshBuilder::new(*self) + } +} + +impl From for Mesh { + /// Converts this segment into a [`Mesh`] using a default [`Segment2dMeshBuilder`]. + fn from(segment: Segment2d) -> Self { + segment.mesh().build() + } +} + /// A builder for creating a [`Mesh`] with an [`Annulus`] shape. #[derive(Clone, Copy, Debug, Reflect)] #[reflect(Default, Debug, Clone)] diff --git a/crates/bevy_mesh/src/primitives/dim3/mod.rs b/crates/bevy_mesh/src/primitives/dim3/mod.rs index 2f8d724e673ab..3c2e16fb8f47f 100644 --- a/crates/bevy_mesh/src/primitives/dim3/mod.rs +++ b/crates/bevy_mesh/src/primitives/dim3/mod.rs @@ -8,6 +8,7 @@ mod sphere; mod tetrahedron; mod torus; pub(crate) mod triangle3d; +mod segment3d; pub use capsule::*; pub use cone::*; diff --git a/crates/bevy_mesh/src/primitives/dim3/segment3d.rs b/crates/bevy_mesh/src/primitives/dim3/segment3d.rs new file mode 100644 index 0000000000000..3c892b424277d --- /dev/null +++ b/crates/bevy_mesh/src/primitives/dim3/segment3d.rs @@ -0,0 +1,45 @@ +use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; +use bevy_asset::RenderAssetUsages; +use bevy_math::primitives::Segment3d; +use bevy_reflect::prelude::*; + +/// A builder used for creating a [`Mesh`] with a [`Segment3d`] shape. +#[derive(Clone, Copy, Debug, Default, Reflect)] +#[reflect(Default, Debug, Clone)] +pub struct Segment3dMeshBuilder { + segment: Segment3d, +} + +impl MeshBuilder for Segment3dMeshBuilder { + fn build(&self) -> Mesh { + let positions: Vec<_> = self.segment.vertices.into(); + let indices = Indices::U32(vec![0, 1]); + + Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default()) + .with_inserted_indices(indices) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + } +} + +impl Meshable for Segment3d { + type Output = Segment3dMeshBuilder; + + fn mesh(&self) -> Self::Output { + Segment3dMeshBuilder { segment: *self } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::Meshable; + use bevy_math::Vec3; + + #[test] + fn segment3d_mesh_builder() { + let segment = Segment3d::new(Vec3::ZERO, Vec3::X); + let mesh = segment.mesh().build(); + assert_eq!(mesh.attribute(Mesh::ATTRIBUTE_POSITION).unwrap().len(), 2); + assert_eq!(mesh.indices().unwrap().len(), 2); + } +} From 43917a4f6791e6b12ae54c4077333b6fb374d964 Mon Sep 17 00:00:00 2001 From: charlotte Date: Sun, 20 Jul 2025 14:35:12 -0700 Subject: [PATCH 02/17] Ci. --- crates/bevy_mesh/src/primitives/dim3/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_mesh/src/primitives/dim3/mod.rs b/crates/bevy_mesh/src/primitives/dim3/mod.rs index 3c2e16fb8f47f..a27d0a1bfb259 100644 --- a/crates/bevy_mesh/src/primitives/dim3/mod.rs +++ b/crates/bevy_mesh/src/primitives/dim3/mod.rs @@ -4,11 +4,11 @@ mod conical_frustum; mod cuboid; mod cylinder; mod plane; +mod segment3d; mod sphere; mod tetrahedron; mod torus; pub(crate) mod triangle3d; -mod segment3d; pub use capsule::*; pub use cone::*; From 746f47902828d57ed5850db3e19caeab3b9a9e16 Mon Sep 17 00:00:00 2001 From: charlotte Date: Tue, 22 Jul 2025 13:53:41 -0700 Subject: [PATCH 03/17] Make primitives non-const-generic. --- crates/bevy_math/src/primitives/serde.rs | 67 ------------------------ 1 file changed, 67 deletions(-) delete mode 100644 crates/bevy_math/src/primitives/serde.rs diff --git a/crates/bevy_math/src/primitives/serde.rs b/crates/bevy_math/src/primitives/serde.rs deleted file mode 100644 index a1b678132ee42..0000000000000 --- a/crates/bevy_math/src/primitives/serde.rs +++ /dev/null @@ -1,67 +0,0 @@ -//! This module defines serialization/deserialization for const generic arrays. -//! Unlike serde's default behavior, it supports arbitrarily large arrays. -//! The code is based on this github comment: -//! - -pub(crate) mod array { - use core::marker::PhantomData; - use serde::{ - de::{SeqAccess, Visitor}, - ser::SerializeTuple, - Deserialize, Deserializer, Serialize, Serializer, - }; - - pub fn serialize( - data: &[T; N], - ser: S, - ) -> Result { - let mut s = ser.serialize_tuple(N)?; - for item in data { - s.serialize_element(item)?; - } - s.end() - } - - struct GenericArrayVisitor(PhantomData); - - impl<'de, T, const N: usize> Visitor<'de> for GenericArrayVisitor - where - T: Deserialize<'de>, - { - type Value = [T; N]; - - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { - formatter.write_fmt(format_args!("an array of length {N}")) - } - - #[inline] - fn visit_seq(self, mut seq: A) -> Result - where - A: SeqAccess<'de>, - { - let mut data = [const { Option::::None }; N]; - - for element in data.iter_mut() { - match (seq.next_element())? { - Some(val) => *element = Some(val), - None => return Err(serde::de::Error::invalid_length(N, &self)), - } - } - - let data = data.map(|value| match value { - Some(value) => value, - None => unreachable!(), - }); - - Ok(data) - } - } - - pub fn deserialize<'de, D, T, const N: usize>(deserializer: D) -> Result<[T; N], D::Error> - where - D: Deserializer<'de>, - T: Deserialize<'de>, - { - deserializer.deserialize_tuple(N, GenericArrayVisitor::(PhantomData)) - } -} From b521097bffa8c695e11e69bd9d0b863e2fca29b6 Mon Sep 17 00:00:00 2001 From: charlotte Date: Tue, 22 Jul 2025 13:55:08 -0700 Subject: [PATCH 04/17] Make primitives non-const-generic, meshable. --- crates/bevy_gizmos/src/primitives/dim2.rs | 92 +--------- crates/bevy_gizmos/src/primitives/dim3.rs | 41 +---- .../src/bounding/bounded2d/primitive_impls.rs | 36 +--- .../src/bounding/bounded3d/extrusion.rs | 38 +--- .../src/bounding/bounded3d/primitive_impls.rs | 18 +- crates/bevy_math/src/primitives/dim2.rs | 173 +++++++----------- crates/bevy_math/src/primitives/dim3.rs | 73 +++----- crates/bevy_math/src/primitives/mod.rs | 2 - crates/bevy_mesh/src/primitives/dim2.rs | 77 ++++++-- crates/bevy_mesh/src/primitives/dim3/mod.rs | 1 + .../src/primitives/dim3/polyline3d.rs | 43 +++++ .../src/primitives/dim3/segment3d.rs | 6 + examples/2d/2d_shapes.rs | 9 + examples/3d/3d_shapes.rs | 6 + 14 files changed, 253 insertions(+), 362 deletions(-) create mode 100644 crates/bevy_mesh/src/primitives/dim3/polyline3d.rs diff --git a/crates/bevy_gizmos/src/primitives/dim2.rs b/crates/bevy_gizmos/src/primitives/dim2.rs index 9535c28fbd0ab..41b5e0a60a056 100644 --- a/crates/bevy_gizmos/src/primitives/dim2.rs +++ b/crates/bevy_gizmos/src/primitives/dim2.rs @@ -7,9 +7,9 @@ use super::helpers::*; use bevy_color::Color; use bevy_math::{ primitives::{ - Annulus, Arc2d, BoxedPolygon, BoxedPolyline2d, Capsule2d, Circle, CircularSector, - CircularSegment, Ellipse, Line2d, Plane2d, Polygon, Polyline2d, Primitive2d, Rectangle, - RegularPolygon, Rhombus, Segment2d, Triangle2d, + Annulus, Arc2d, Capsule2d, Circle, CircularSector, CircularSegment, Ellipse, Line2d, + Plane2d, Polygon, Polyline2d, Primitive2d, Rectangle, RegularPolygon, Rhombus, Segment2d, + Triangle2d, }, Dir2, Isometry2d, Rot2, Vec2, }; @@ -648,7 +648,7 @@ where // polyline 2d -impl GizmoPrimitive2d> for GizmoBuffer +impl GizmoPrimitive2d for GizmoBuffer where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -660,42 +660,7 @@ where fn primitive_2d( &mut self, - primitive: &Polyline2d, - isometry: impl Into, - color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { - return; - } - - let isometry = isometry.into(); - - self.linestrip_2d( - primitive - .vertices - .iter() - .copied() - .map(|vec2| isometry * vec2), - color, - ); - } -} - -// boxed polyline 2d - -impl GizmoPrimitive2d for GizmoBuffer -where - Config: GizmoConfigGroup, - Clear: 'static + Send + Sync, -{ - type Output<'a> - = () - where - Self: 'a; - - fn primitive_2d( - &mut self, - primitive: &BoxedPolyline2d, + primitive: &Polyline2d, isometry: impl Into, color: impl Into, ) -> Self::Output<'_> { @@ -784,7 +749,7 @@ where // polygon 2d -impl GizmoPrimitive2d> for GizmoBuffer +impl GizmoPrimitive2d for GizmoBuffer where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -796,7 +761,7 @@ where fn primitive_2d( &mut self, - primitive: &Polygon, + primitive: &Polygon, isometry: impl Into, color: impl Into, ) -> Self::Output<'_> { @@ -827,49 +792,6 @@ where } } -// boxed polygon 2d - -impl GizmoPrimitive2d for GizmoBuffer -where - Config: GizmoConfigGroup, - Clear: 'static + Send + Sync, -{ - type Output<'a> - = () - where - Self: 'a; - - fn primitive_2d( - &mut self, - primitive: &BoxedPolygon, - isometry: impl Into, - color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { - return; - } - - let isometry = isometry.into(); - - let closing_point = { - let first = primitive.vertices.first(); - (primitive.vertices.last() != first) - .then_some(first) - .flatten() - .cloned() - }; - self.linestrip_2d( - primitive - .vertices - .iter() - .copied() - .chain(closing_point) - .map(|vec2| isometry * vec2), - color, - ); - } -} - // regular polygon 2d impl GizmoPrimitive2d for GizmoBuffer diff --git a/crates/bevy_gizmos/src/primitives/dim3.rs b/crates/bevy_gizmos/src/primitives/dim3.rs index 898850ddea901..ca1172316b2c6 100644 --- a/crates/bevy_gizmos/src/primitives/dim3.rs +++ b/crates/bevy_gizmos/src/primitives/dim3.rs @@ -5,8 +5,8 @@ use super::helpers::*; use bevy_color::Color; use bevy_math::{ primitives::{ - BoxedPolyline3d, Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, Line3d, Plane3d, - Polyline3d, Primitive3d, Segment3d, Sphere, Tetrahedron, Torus, Triangle3d, + Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, Line3d, Plane3d, Polyline3d, + Primitive3d, Segment3d, Sphere, Tetrahedron, Torus, Triangle3d, }, Dir3, Isometry3d, Quat, UVec2, Vec2, Vec3, }; @@ -235,7 +235,7 @@ where // polyline 3d -impl GizmoPrimitive3d> for GizmoBuffer +impl GizmoPrimitive3d for GizmoBuffer where Config: GizmoConfigGroup, Clear: 'static + Send + Sync, @@ -247,34 +247,7 @@ where fn primitive_3d( &mut self, - primitive: &Polyline3d, - isometry: impl Into, - color: impl Into, - ) -> Self::Output<'_> { - if !self.enabled { - return; - } - - let isometry = isometry.into(); - self.linestrip(primitive.vertices.map(|vec3| isometry * vec3), color); - } -} - -// boxed polyline 3d - -impl GizmoPrimitive3d for GizmoBuffer -where - Config: GizmoConfigGroup, - Clear: 'static + Send + Sync, -{ - type Output<'a> - = () - where - Self: 'a; - - fn primitive_3d( - &mut self, - primitive: &BoxedPolyline3d, + primitive: &Polyline3d, isometry: impl Into, color: impl Into, ) -> Self::Output<'_> { @@ -284,11 +257,7 @@ where let isometry = isometry.into(); self.linestrip( - primitive - .vertices - .iter() - .copied() - .map(|vec3| isometry * vec3), + primitive.vertices.iter().map(|vec3| isometry * *vec3), color, ); } diff --git a/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs b/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs index f55f40ddc6c87..1c6858f63db46 100644 --- a/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs +++ b/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs @@ -5,15 +5,14 @@ use crate::{ ops, primitives::{ Annulus, Arc2d, Capsule2d, Circle, CircularSector, CircularSegment, ConvexPolygon, Ellipse, - Line2d, Plane2d, Polygon, Polyline2d, Rectangle, RegularPolygon, Rhombus, Segment2d, - Triangle2d, + Line2d, Plane2d, Rectangle, RegularPolygon, Rhombus, Segment2d, Triangle2d, }, Dir2, Isometry2d, Mat2, Rot2, Vec2, }; use core::f32::consts::{FRAC_PI_2, PI, TAU}; #[cfg(feature = "alloc")] -use crate::primitives::{BoxedPolygon, BoxedPolyline2d}; +use crate::primitives::{Polygon, Polyline2d}; use smallvec::SmallVec; @@ -279,18 +278,8 @@ impl Bounded2d for Segment2d { } } -impl Bounded2d for Polyline2d { - fn aabb_2d(&self, isometry: impl Into) -> Aabb2d { - Aabb2d::from_point_cloud(isometry, &self.vertices) - } - - fn bounding_circle(&self, isometry: impl Into) -> BoundingCircle { - BoundingCircle::from_point_cloud(isometry, &self.vertices) - } -} - #[cfg(feature = "alloc")] -impl Bounded2d for BoxedPolyline2d { +impl Bounded2d for Polyline2d { fn aabb_2d(&self, isometry: impl Into) -> Aabb2d { Aabb2d::from_point_cloud(isometry, &self.vertices) } @@ -366,7 +355,8 @@ impl Bounded2d for Rectangle { } } -impl Bounded2d for Polygon { +#[cfg(feature = "alloc")] +impl Bounded2d for Polygon { fn aabb_2d(&self, isometry: impl Into) -> Aabb2d { Aabb2d::from_point_cloud(isometry, &self.vertices) } @@ -376,24 +366,14 @@ impl Bounded2d for Polygon { } } -impl Bounded2d for ConvexPolygon { - fn aabb_2d(&self, isometry: impl Into) -> Aabb2d { - Aabb2d::from_point_cloud(isometry, self.vertices().as_slice()) - } - - fn bounding_circle(&self, isometry: impl Into) -> BoundingCircle { - BoundingCircle::from_point_cloud(isometry, self.vertices().as_slice()) - } -} - #[cfg(feature = "alloc")] -impl Bounded2d for BoxedPolygon { +impl Bounded2d for ConvexPolygon { fn aabb_2d(&self, isometry: impl Into) -> Aabb2d { - Aabb2d::from_point_cloud(isometry, &self.vertices) + Aabb2d::from_point_cloud(isometry, self.vertices()) } fn bounding_circle(&self, isometry: impl Into) -> BoundingCircle { - BoundingCircle::from_point_cloud(isometry, &self.vertices) + BoundingCircle::from_point_cloud(isometry, self.vertices()) } } diff --git a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs index 607d0f27464f3..9068ca50bc760 100644 --- a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs +++ b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs @@ -6,14 +6,14 @@ use crate::{ bounding::{BoundingCircle, BoundingVolume}, ops, primitives::{ - Capsule2d, Cuboid, Cylinder, Ellipse, Extrusion, Line2d, Polygon, Polyline2d, Primitive2d, - Rectangle, RegularPolygon, Segment2d, Triangle2d, + Capsule2d, Cuboid, Cylinder, Ellipse, Extrusion, Line2d, Primitive2d, Rectangle, + RegularPolygon, Segment2d, Triangle2d, }, Isometry2d, Isometry3d, Quat, Rot2, }; #[cfg(feature = "alloc")] -use crate::primitives::{BoxedPolygon, BoxedPolyline2d}; +use crate::primitives::{Polygon, Polyline2d}; use crate::{bounding::Bounded2d, primitives::Circle}; @@ -96,19 +96,8 @@ impl BoundedExtrusion for Segment2d { } } -impl BoundedExtrusion for Polyline2d { - fn extrusion_aabb_3d(&self, half_depth: f32, isometry: impl Into) -> Aabb3d { - let isometry = isometry.into(); - let aabb = - Aabb3d::from_point_cloud(isometry, self.vertices.map(|v| v.extend(0.)).into_iter()); - let depth = isometry.rotation * Vec3A::new(0., 0., half_depth); - - aabb.grow(depth.abs()) - } -} - #[cfg(feature = "alloc")] -impl BoundedExtrusion for BoxedPolyline2d { +impl BoundedExtrusion for Polyline2d { fn extrusion_aabb_3d(&self, half_depth: f32, isometry: impl Into) -> Aabb3d { let isometry = isometry.into(); let aabb = Aabb3d::from_point_cloud(isometry, self.vertices.iter().map(|v| v.extend(0.))); @@ -137,22 +126,13 @@ impl BoundedExtrusion for Rectangle { } } -impl BoundedExtrusion for Polygon { +impl BoundedExtrusion for Polygon { fn extrusion_aabb_3d(&self, half_depth: f32, isometry: impl Into) -> Aabb3d { let isometry = isometry.into(); - let aabb = - Aabb3d::from_point_cloud(isometry, self.vertices.map(|v| v.extend(0.)).into_iter()); - let depth = isometry.rotation * Vec3A::new(0., 0., half_depth); - - aabb.grow(depth.abs()) - } -} - -#[cfg(feature = "alloc")] -impl BoundedExtrusion for BoxedPolygon { - fn extrusion_aabb_3d(&self, half_depth: f32, isometry: impl Into) -> Aabb3d { - let isometry = isometry.into(); - let aabb = Aabb3d::from_point_cloud(isometry, self.vertices.iter().map(|v| v.extend(0.))); + let aabb = Aabb3d::from_point_cloud( + isometry, + self.vertices.iter().map(|v| v.extend(0.)).into_iter(), + ); let depth = isometry.rotation * Vec3A::new(0., 0., half_depth); aabb.grow(depth.abs()) diff --git a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs index ebfd0266e81d0..c03fc80218d63 100644 --- a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs +++ b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs @@ -4,14 +4,14 @@ use crate::{ bounding::{Bounded2d, BoundingCircle, BoundingVolume}, ops, primitives::{ - Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, InfinitePlane3d, Line3d, Polyline3d, - Segment3d, Sphere, Torus, Triangle2d, Triangle3d, + Capsule3d, Cone, ConicalFrustum, Cuboid, Cylinder, InfinitePlane3d, Line3d, Segment3d, + Sphere, Torus, Triangle2d, Triangle3d, }, Isometry2d, Isometry3d, Mat3, Vec2, Vec3, Vec3A, }; #[cfg(feature = "alloc")] -use crate::primitives::BoxedPolyline3d; +use crate::primitives::Polyline3d; use super::{Aabb3d, Bounded3d, BoundingSphere}; @@ -86,18 +86,8 @@ impl Bounded3d for Segment3d { } } -impl Bounded3d for Polyline3d { - fn aabb_3d(&self, isometry: impl Into) -> Aabb3d { - Aabb3d::from_point_cloud(isometry, self.vertices.iter().copied()) - } - - fn bounding_sphere(&self, isometry: impl Into) -> BoundingSphere { - BoundingSphere::from_point_cloud(isometry, &self.vertices) - } -} - #[cfg(feature = "alloc")] -impl Bounded3d for BoxedPolyline3d { +impl Bounded3d for Polyline3d { fn aabb_3d(&self, isometry: impl Into) -> Aabb3d { Aabb3d::from_point_cloud(isometry, self.vertices.iter().copied()) } diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index 98f0ee5b9a41f..fcc44d0ec7c38 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -17,7 +17,7 @@ use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; #[cfg(feature = "alloc")] -use alloc::{boxed::Box, vec::Vec}; +use alloc::vec::Vec; /// A circle primitive, representing the set of points some distance from the origin #[derive(Clone, Copy, Debug, PartialEq)] @@ -1246,10 +1246,9 @@ pub struct Segment2d { impl Primitive2d for Segment2d {} impl Default for Segment2d { - /// Returns the default [`Segment2d`] with endpoints at `(0.0, 0.0)` and `(1.0, 0.0)`. fn default() -> Self { Self { - vertices: [Vec2::new(0.0, 0.0), Vec2::new(1.0, 0.0)], + vertices: [Vec2::new(-0.5, 0.0), Vec2::new(0.5, 0.0)], } } } @@ -1508,6 +1507,7 @@ impl From<(Vec2, Vec2)> for Segment2d { /// A series of connected line segments in 2D space. /// /// For a version without generics: [`BoxedPolyline2d`] +#[cfg(feature = "alloc")] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -1519,63 +1519,52 @@ impl From<(Vec2, Vec2)> for Segment2d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] -pub struct Polyline2d { +pub struct Polyline2d { /// The vertices of the polyline - #[cfg_attr(feature = "serialize", serde(with = "super::serde::array"))] - pub vertices: [Vec2; N], + pub vertices: Vec, } -impl Primitive2d for Polyline2d {} +#[cfg(feature = "alloc")] +impl Primitive2d for Polyline2d {} -impl FromIterator for Polyline2d { +#[cfg(feature = "alloc")] +impl FromIterator for Polyline2d { fn from_iter>(iter: I) -> Self { - let mut vertices: [Vec2; N] = [Vec2::ZERO; N]; - - for (index, i) in iter.into_iter().take(N).enumerate() { - vertices[index] = i; + Self { + vertices: iter.into_iter().collect(), } - Self { vertices } } } -impl Polyline2d { - /// Create a new `Polyline2d` from its vertices - pub fn new(vertices: impl IntoIterator) -> Self { - Self::from_iter(vertices) - } -} - -/// A series of connected line segments in 2D space, allocated on the heap -/// in a `Box<[Vec2]>`. -/// -/// For a version without alloc: [`Polyline2d`] -#[cfg(feature = "alloc")] -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] -pub struct BoxedPolyline2d { - /// The vertices of the polyline - pub vertices: Box<[Vec2]>, -} - #[cfg(feature = "alloc")] -impl Primitive2d for BoxedPolyline2d {} - -#[cfg(feature = "alloc")] -impl FromIterator for BoxedPolyline2d { - fn from_iter>(iter: I) -> Self { - let vertices: Vec = iter.into_iter().collect(); +impl Default for Polyline2d { + fn default() -> Self { Self { - vertices: vertices.into_boxed_slice(), + vertices: Vec::from([Vec2::new(0.0, 0.0), Vec2::new(1.0, 0.0)]), } } } #[cfg(feature = "alloc")] -impl BoxedPolyline2d { - /// Create a new `BoxedPolyline2d` from its vertices +impl Polyline2d { + /// Create a new `Polyline2d` from its vertices pub fn new(vertices: impl IntoIterator) -> Self { Self::from_iter(vertices) } + + /// Create a new `Polyline2d` from two endpoints and a number of segments. + pub fn with_segment_count(start: Vec2, end: Vec2, segments: usize) -> Self { + if segments == 0 { + return Self::new(Vec::from([start, end])); + } + + let step = (end - start) / segments as f32; + let mut vertices = Vec::with_capacity(segments + 1); + for i in 0..=segments { + vertices.push(start + step * i as f32); + } + Self { vertices } + } } /// A triangle in 2D space @@ -1845,6 +1834,7 @@ impl Measured2d for Rectangle { /// A polygon with N vertices. /// /// For a version without generics: [`BoxedPolygon`] +#[cfg(feature = "alloc")] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -1856,26 +1846,25 @@ impl Measured2d for Rectangle { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] -pub struct Polygon { +pub struct Polygon { /// The vertices of the `Polygon` - #[cfg_attr(feature = "serialize", serde(with = "super::serde::array"))] - pub vertices: [Vec2; N], + pub vertices: Vec, } -impl Primitive2d for Polygon {} +#[cfg(feature = "alloc")] +impl Primitive2d for Polygon {} -impl FromIterator for Polygon { +#[cfg(feature = "alloc")] +impl FromIterator for Polygon { fn from_iter>(iter: I) -> Self { - let mut vertices: [Vec2; N] = [Vec2::ZERO; N]; - - for (index, i) in iter.into_iter().take(N).enumerate() { - vertices[index] = i; + Self { + vertices: iter.into_iter().collect(), } - Self { vertices } } } -impl Polygon { +#[cfg(feature = "alloc")] +impl Polygon { /// Create a new `Polygon` from its vertices pub fn new(vertices: impl IntoIterator) -> Self { Self::from_iter(vertices) @@ -1891,8 +1880,9 @@ impl Polygon { } } -impl From> for Polygon { - fn from(val: ConvexPolygon) -> Self { +#[cfg(feature = "alloc")] +impl From for Polygon { + fn from(val: ConvexPolygon) -> Self { Polygon { vertices: val.vertices, } @@ -1900,6 +1890,7 @@ impl From> for Polygon { } /// A convex polygon with `N` vertices. +#[cfg(feature = "alloc")] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -1911,15 +1902,16 @@ impl From> for Polygon { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] -pub struct ConvexPolygon { +pub struct ConvexPolygon { /// The vertices of the [`ConvexPolygon`]. - #[cfg_attr(feature = "serialize", serde(with = "super::serde::array"))] - vertices: [Vec2; N], + vertices: Vec, } -impl Primitive2d for ConvexPolygon {} +#[cfg(feature = "alloc")] +impl Primitive2d for ConvexPolygon {} /// An error that happens when creating a [`ConvexPolygon`]. +#[cfg(feature = "alloc")] #[derive(Error, Debug, Clone)] pub enum ConvexPolygonError { /// The created polygon is not convex. @@ -1927,7 +1919,8 @@ pub enum ConvexPolygonError { Concave, } -impl ConvexPolygon { +#[cfg(feature = "alloc")] +impl ConvexPolygon { fn triangle_winding_order( &self, a_index: usize, @@ -1945,11 +1938,12 @@ impl ConvexPolygon { /// # Errors /// /// Returns [`ConvexPolygonError::Concave`] if the `vertices` do not form a convex polygon. - pub fn new(vertices: [Vec2; N]) -> Result { + pub fn new(vertices: impl IntoIterator) -> Result { let polygon = Self::new_unchecked(vertices); - let ref_winding_order = polygon.triangle_winding_order(N - 1, 0, 1); - for i in 1..N { - let winding_order = polygon.triangle_winding_order(i - 1, i, (i + 1) % N); + let len = polygon.vertices.len(); + let ref_winding_order = polygon.triangle_winding_order(len - 1, 0, 1); + for i in 1..len { + let winding_order = polygon.triangle_winding_order(i - 1, i, (i + 1) % len); if winding_order != ref_winding_order { return Err(ConvexPolygonError::Concave); } @@ -1960,66 +1954,27 @@ impl ConvexPolygon { /// Create a [`ConvexPolygon`] from its `vertices`, without checks. /// Use this version only if you know that the `vertices` make up a convex polygon. #[inline(always)] - pub fn new_unchecked(vertices: [Vec2; N]) -> Self { - Self { vertices } + pub fn new_unchecked(vertices: impl IntoIterator) -> Self { + Self { + vertices: vertices.into_iter().collect(), + } } /// Get the vertices of this polygon #[inline(always)] - pub fn vertices(&self) -> &[Vec2; N] { + pub fn vertices(&self) -> &[Vec2] { &self.vertices } } -impl TryFrom> for ConvexPolygon { +impl TryFrom for ConvexPolygon { type Error = ConvexPolygonError; - fn try_from(val: Polygon) -> Result { + fn try_from(val: Polygon) -> Result { ConvexPolygon::new(val.vertices) } } -/// A polygon with a variable number of vertices, allocated on the heap -/// in a `Box<[Vec2]>`. -/// -/// For a version without alloc: [`Polygon`] -#[cfg(feature = "alloc")] -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] -pub struct BoxedPolygon { - /// The vertices of the `BoxedPolygon` - pub vertices: Box<[Vec2]>, -} - -#[cfg(feature = "alloc")] -impl Primitive2d for BoxedPolygon {} - -#[cfg(feature = "alloc")] -impl FromIterator for BoxedPolygon { - fn from_iter>(iter: I) -> Self { - let vertices: Vec = iter.into_iter().collect(); - Self { - vertices: vertices.into_boxed_slice(), - } - } -} - -#[cfg(feature = "alloc")] -impl BoxedPolygon { - /// Create a new `BoxedPolygon` from its vertices - pub fn new(vertices: impl IntoIterator) -> Self { - Self::from_iter(vertices) - } - - /// Tests if the polygon is simple. - /// - /// A polygon is simple if it is not self intersecting and not self tangent. - /// As such, no two edges of the polygon may cross each other and each vertex must not lie on another edge. - pub fn is_simple(&self) -> bool { - is_polygon_simple(&self.vertices) - } -} - /// A polygon centered on the origin where all vertices lie on a circle, equally far apart. #[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index a7208c37e5b9d..719467f88e274 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -13,7 +13,7 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; use glam::Quat; #[cfg(feature = "alloc")] -use alloc::{boxed::Box, vec::Vec}; +use alloc::vec::Vec; /// A sphere primitive, representing the set of all points some distance from the origin #[derive(Clone, Copy, Debug, PartialEq)] @@ -378,10 +378,9 @@ pub struct Segment3d { impl Primitive3d for Segment3d {} impl Default for Segment3d { - /// Returns the default [`Segment3d`] with endpoints at `(0.0, 0.0, 0.0)` and `(1.0, 0.0, 0.0)`. fn default() -> Self { Self { - vertices: [Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 0.0)], + vertices: [Vec3::new(-0.5, 0.0, 0.0), Vec3::new(0.5, 0.0, 0.0)], } } } @@ -576,6 +575,7 @@ impl From<(Vec3, Vec3)> for Segment3d { /// A series of connected line segments in 3D space. /// /// For a version without generics: [`BoxedPolyline3d`] +#[cfg(feature = "alloc")] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr( @@ -587,63 +587,50 @@ impl From<(Vec3, Vec3)> for Segment3d { all(feature = "serialize", feature = "bevy_reflect"), reflect(Serialize, Deserialize) )] -pub struct Polyline3d { +pub struct Polyline3d { /// The vertices of the polyline - #[cfg_attr(feature = "serialize", serde(with = "super::serde::array"))] - pub vertices: [Vec3; N], + pub vertices: Vec, } -impl Primitive3d for Polyline3d {} +#[cfg(feature = "alloc")] +impl Primitive3d for Polyline3d {} -impl FromIterator for Polyline3d { +#[cfg(feature = "alloc")] +impl FromIterator for Polyline3d { fn from_iter>(iter: I) -> Self { - let mut vertices: [Vec3; N] = [Vec3::ZERO; N]; - - for (index, i) in iter.into_iter().take(N).enumerate() { - vertices[index] = i; + Self { + vertices: iter.into_iter().collect(), } - Self { vertices } - } -} - -impl Polyline3d { - /// Create a new `Polyline3d` from its vertices - pub fn new(vertices: impl IntoIterator) -> Self { - Self::from_iter(vertices) } } -/// A series of connected line segments in 3D space, allocated on the heap -/// in a `Box<[Vec3]>`. -/// -/// For a version without alloc: [`Polyline3d`] -#[cfg(feature = "alloc")] -#[derive(Clone, Debug, PartialEq)] -#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] -pub struct BoxedPolyline3d { - /// The vertices of the polyline - pub vertices: Box<[Vec3]>, -} - -#[cfg(feature = "alloc")] -impl Primitive3d for BoxedPolyline3d {} - #[cfg(feature = "alloc")] -impl FromIterator for BoxedPolyline3d { - fn from_iter>(iter: I) -> Self { - let vertices: Vec = iter.into_iter().collect(); - Self { - vertices: vertices.into_boxed_slice(), - } +impl Default for Polyline3d { + fn default() -> Self { + Self::new([Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 0.0)]) } } #[cfg(feature = "alloc")] -impl BoxedPolyline3d { - /// Create a new `BoxedPolyline3d` from its vertices +impl Polyline3d { + /// Create a new `Polyline3d` from its vertices pub fn new(vertices: impl IntoIterator) -> Self { Self::from_iter(vertices) } + + /// Create a new `Polyline3d` from two endpoints and a number of segments. + pub fn with_segment_count(start: Vec3, end: Vec3, segments: usize) -> Self { + if segments == 0 { + return Self::new(Vec::from([start, end])); + } + + let step = (end - start) / segments as f32; + let mut vertices = Vec::with_capacity(segments + 1); + for i in 0..=segments { + vertices.push(start + step * i as f32); + } + Self { vertices } + } } /// A cuboid primitive, which is like a cube, except that the x, y, and z dimensions are not diff --git a/crates/bevy_math/src/primitives/mod.rs b/crates/bevy_math/src/primitives/mod.rs index b5c6644b13cc0..625a359dd711d 100644 --- a/crates/bevy_math/src/primitives/mod.rs +++ b/crates/bevy_math/src/primitives/mod.rs @@ -7,8 +7,6 @@ pub use dim2::*; mod dim3; pub use dim3::*; mod polygon; -#[cfg(feature = "serialize")] -mod serde; /// A marker trait for 2D primitives pub trait Primitive2d {} diff --git a/crates/bevy_mesh/src/primitives/dim2.rs b/crates/bevy_mesh/src/primitives/dim2.rs index 172cb152074d8..4648e3ea19b2b 100644 --- a/crates/bevy_mesh/src/primitives/dim2.rs +++ b/crates/bevy_mesh/src/primitives/dim2.rs @@ -4,6 +4,7 @@ use crate::{primitives::dim3::triangle3d, Indices, Mesh, PerimeterSegment}; use bevy_asset::RenderAssetUsages; use super::{Extrudable, MeshBuilder, Meshable}; +use bevy_math::prelude::Polyline2d; use bevy_math::{ ops, primitives::{ @@ -407,31 +408,32 @@ impl From for Mesh { /// /// You must verify that the `vertices` are not concave when constructing this type. You can /// guarantee this by creating a [`ConvexPolygon`] first, then calling [`ConvexPolygon::mesh()`]. -#[derive(Clone, Copy, Debug, Reflect)] +#[derive(Clone, Debug, Reflect)] #[reflect(Debug, Clone)] -pub struct ConvexPolygonMeshBuilder { - pub vertices: [Vec2; N], +pub struct ConvexPolygonMeshBuilder { + pub vertices: Vec, } -impl Meshable for ConvexPolygon { - type Output = ConvexPolygonMeshBuilder; +impl Meshable for ConvexPolygon { + type Output = ConvexPolygonMeshBuilder; fn mesh(&self) -> Self::Output { Self::Output { - vertices: *self.vertices(), + vertices: self.vertices().to_vec(), } } } -impl MeshBuilder for ConvexPolygonMeshBuilder { +impl MeshBuilder for ConvexPolygonMeshBuilder { fn build(&self) -> Mesh { - let mut indices = Vec::with_capacity((N - 2) * 3); - let mut positions = Vec::with_capacity(N); + let len = self.vertices.len(); + let mut indices = Vec::with_capacity((len - 2) * 3); + let mut positions = Vec::with_capacity(len); - for vertex in self.vertices { + for vertex in &self.vertices { positions.push([vertex.x, vertex.y, 0.0]); } - for i in 2..N as u32 { + for i in 2..len as u32 { indices.extend_from_slice(&[0, i - 1, i]); } Mesh::new( @@ -443,16 +445,16 @@ impl MeshBuilder for ConvexPolygonMeshBuilder { } } -impl Extrudable for ConvexPolygonMeshBuilder { +impl Extrudable for ConvexPolygonMeshBuilder { fn perimeter(&self) -> Vec { vec![PerimeterSegment::Flat { - indices: (0..N as u32).chain([0]).collect(), + indices: (0..self.vertices.len() as u32).chain([0]).collect(), }] } } -impl From> for Mesh { - fn from(polygon: ConvexPolygon) -> Self { +impl From for Mesh { + fn from(polygon: ConvexPolygon) -> Self { polygon.mesh().build() } } @@ -676,6 +678,50 @@ impl From for Mesh { } } +/// A builder used for creating a [`Mesh`] with a [`Polyline2d`] shape. +#[derive(Clone, Debug, Default, Reflect)] +#[reflect(Default, Debug, Clone)] +pub struct Polyline2dMeshBuilder { + polyline: Polyline2d, +} + +impl MeshBuilder for Polyline2dMeshBuilder { + fn build(&self) -> Mesh { + let positions: Vec<_> = self + .polyline + .vertices + .iter() + .map(|v| v.extend(0.0)) + .collect(); + + let indices = Indices::U32( + (0..self.polyline.vertices.len() as u32 - 1) + .flat_map(|i| [i, i + 1]) + .collect(), + ); + + Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default()) + .with_inserted_indices(indices) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + } +} + +impl Meshable for Polyline2d { + type Output = Polyline2dMeshBuilder; + + fn mesh(&self) -> Self::Output { + Polyline2dMeshBuilder { + polyline: self.clone(), + } + } +} + +impl From for Mesh { + fn from(polyline: Polyline2d) -> Self { + polyline.mesh().build() + } +} + /// A builder for creating a [`Mesh`] with an [`Annulus`] shape. #[derive(Clone, Copy, Debug, Reflect)] #[reflect(Default, Debug, Clone)] @@ -699,7 +745,6 @@ impl Default for AnnulusMeshBuilder { impl AnnulusMeshBuilder { /// Create an [`AnnulusMeshBuilder`] with the given inner radius, outer radius, and angular vertex count. - #[inline] pub fn new(inner_radius: f32, outer_radius: f32, resolution: u32) -> Self { Self { annulus: Annulus::new(inner_radius, outer_radius), diff --git a/crates/bevy_mesh/src/primitives/dim3/mod.rs b/crates/bevy_mesh/src/primitives/dim3/mod.rs index a27d0a1bfb259..21cd80b3a420f 100644 --- a/crates/bevy_mesh/src/primitives/dim3/mod.rs +++ b/crates/bevy_mesh/src/primitives/dim3/mod.rs @@ -4,6 +4,7 @@ mod conical_frustum; mod cuboid; mod cylinder; mod plane; +mod polyline3d; mod segment3d; mod sphere; mod tetrahedron; diff --git a/crates/bevy_mesh/src/primitives/dim3/polyline3d.rs b/crates/bevy_mesh/src/primitives/dim3/polyline3d.rs new file mode 100644 index 0000000000000..4d13112579f09 --- /dev/null +++ b/crates/bevy_mesh/src/primitives/dim3/polyline3d.rs @@ -0,0 +1,43 @@ +use crate::{Indices, Mesh, MeshBuilder, Meshable, PrimitiveTopology}; +use bevy_asset::RenderAssetUsages; +use bevy_math::primitives::Polyline3d; +use bevy_reflect::prelude::*; + +/// A builder used for creating a [`Mesh`] with a [`Polyline3d`] shape. +#[derive(Clone, Debug, Default, Reflect)] +#[reflect(Default, Debug, Clone)] +pub struct Polyline3dMeshBuilder { + polyline: Polyline3d, +} + +impl MeshBuilder for Polyline3dMeshBuilder { + fn build(&self) -> Mesh { + let positions: Vec<_> = self.polyline.vertices.clone(); + + let indices = Indices::U32( + (0..self.polyline.vertices.len() as u32 - 1) + .flat_map(|i| [i, i + 1]) + .collect(), + ); + + Mesh::new(PrimitiveTopology::LineList, RenderAssetUsages::default()) + .with_inserted_indices(indices) + .with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, positions) + } +} + +impl Meshable for Polyline3d { + type Output = Polyline3dMeshBuilder; + + fn mesh(&self) -> Self::Output { + Polyline3dMeshBuilder { + polyline: self.clone(), + } + } +} + +impl From for Mesh { + fn from(polyline: Polyline3d) -> Self { + polyline.mesh().build() + } +} diff --git a/crates/bevy_mesh/src/primitives/dim3/segment3d.rs b/crates/bevy_mesh/src/primitives/dim3/segment3d.rs index 3c892b424277d..d032285283afb 100644 --- a/crates/bevy_mesh/src/primitives/dim3/segment3d.rs +++ b/crates/bevy_mesh/src/primitives/dim3/segment3d.rs @@ -29,6 +29,12 @@ impl Meshable for Segment3d { } } +impl From for Mesh { + fn from(segment: Segment3d) -> Self { + segment.mesh().build() + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/examples/2d/2d_shapes.rs b/examples/2d/2d_shapes.rs index f69e138364190..03109baeee06e 100644 --- a/examples/2d/2d_shapes.rs +++ b/examples/2d/2d_shapes.rs @@ -54,6 +54,15 @@ fn setup( Vec2::new(-50.0, -50.0), Vec2::new(50.0, -50.0), )), + meshes.add(Segment2d::new( + Vec2::new(-50.0, 50.0), + Vec2::new(50.0, -50.0), + )), + meshes.add(Polyline2d::new(vec![ + Vec2::new(-50.0, 50.0), + Vec2::new(0.0, -50.0), + Vec2::new(50.0, 50.0), + ])), ]; let num_shapes = shapes.len(); diff --git a/examples/3d/3d_shapes.rs b/examples/3d/3d_shapes.rs index 3fab989a1bcf1..721a23caca9cc 100644 --- a/examples/3d/3d_shapes.rs +++ b/examples/3d/3d_shapes.rs @@ -74,6 +74,12 @@ fn setup( meshes.add(ConicalFrustum::default()), meshes.add(Sphere::default().mesh().ico(5).unwrap()), meshes.add(Sphere::default().mesh().uv(32, 18)), + meshes.add(Segment3d::default()), + meshes.add(Polyline3d::new(vec![ + Vec3::new(-0.5, 0.0, 0.0), + Vec3::new(0.5, 0.0, 0.0), + Vec3::new(0.0, 0.5, 0.0), + ])), ]; let extrusions = [ From 2be62f4ba83e876f4111ffc619de483cc825d6e0 Mon Sep 17 00:00:00 2001 From: charlotte Date: Tue, 22 Jul 2025 14:03:49 -0700 Subject: [PATCH 05/17] Ci. --- crates/bevy_mesh/src/primitives/dim2.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/bevy_mesh/src/primitives/dim2.rs b/crates/bevy_mesh/src/primitives/dim2.rs index 4648e3ea19b2b..268c263d87371 100644 --- a/crates/bevy_mesh/src/primitives/dim2.rs +++ b/crates/bevy_mesh/src/primitives/dim2.rs @@ -745,6 +745,7 @@ impl Default for AnnulusMeshBuilder { impl AnnulusMeshBuilder { /// Create an [`AnnulusMeshBuilder`] with the given inner radius, outer radius, and angular vertex count. + #[inline] pub fn new(inner_radius: f32, outer_radius: f32, resolution: u32) -> Self { Self { annulus: Annulus::new(inner_radius, outer_radius), From bae6e9bd7993c97a70f05cd2fabd6c58af9463c7 Mon Sep 17 00:00:00 2001 From: charlotte Date: Tue, 22 Jul 2025 14:09:58 -0700 Subject: [PATCH 06/17] Ci. --- crates/bevy_math/src/bounding/bounded3d/extrusion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs index 9068ca50bc760..417ca9e6696e2 100644 --- a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs +++ b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs @@ -131,7 +131,7 @@ impl BoundedExtrusion for Polygon { let isometry = isometry.into(); let aabb = Aabb3d::from_point_cloud( isometry, - self.vertices.iter().map(|v| v.extend(0.)).into_iter(), + self.vertices.iter().map(|v| v.extend(0.)), ); let depth = isometry.rotation * Vec3A::new(0., 0., half_depth); From cec5abfc03d820eba3f37e0dc12273913fe79283 Mon Sep 17 00:00:00 2001 From: charlotte Date: Tue, 22 Jul 2025 14:12:45 -0700 Subject: [PATCH 07/17] Ci. --- crates/bevy_math/src/bounding/bounded3d/extrusion.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs index 417ca9e6696e2..deb98a9a2ff74 100644 --- a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs +++ b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs @@ -129,10 +129,7 @@ impl BoundedExtrusion for Rectangle { impl BoundedExtrusion for Polygon { fn extrusion_aabb_3d(&self, half_depth: f32, isometry: impl Into) -> Aabb3d { let isometry = isometry.into(); - let aabb = Aabb3d::from_point_cloud( - isometry, - self.vertices.iter().map(|v| v.extend(0.)), - ); + let aabb = Aabb3d::from_point_cloud(isometry, self.vertices.iter().map(|v| v.extend(0.))); let depth = isometry.rotation * Vec3A::new(0., 0., half_depth); aabb.grow(depth.abs()) From 1fc73792d374d8181872eb6e7f2927ef360adb2f Mon Sep 17 00:00:00 2001 From: charlotte Date: Tue, 22 Jul 2025 14:31:03 -0700 Subject: [PATCH 08/17] Ci. --- .../src/bounding/bounded3d/primitive_impls.rs | 2 +- examples/math/render_primitives.rs | 67 ++++++++++--------- 2 files changed, 38 insertions(+), 31 deletions(-) diff --git a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs index c03fc80218d63..7cf118e4d97e8 100644 --- a/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs +++ b/crates/bevy_math/src/bounding/bounded3d/primitive_impls.rs @@ -461,7 +461,7 @@ mod tests { #[test] fn polyline() { - let polyline = Polyline3d::<4>::new([ + let polyline = Polyline3d::new([ Vec3::ONE, Vec3::new(-1.0, 1.0, 1.0), Vec3::NEG_ONE, diff --git a/examples/math/render_primitives.rs b/examples/math/render_primitives.rs index 26be0445baa90..1b7c7228c430b 100644 --- a/examples/math/render_primitives.rs +++ b/examples/math/render_primitives.rs @@ -197,33 +197,6 @@ const SEGMENT_3D: Segment3d = Segment3d { ], }; -const POLYLINE_2D: Polyline2d<4> = Polyline2d { - vertices: [ - Vec2::new(-BIG_2D, -SMALL_2D), - Vec2::new(-SMALL_2D, SMALL_2D), - Vec2::new(SMALL_2D, -SMALL_2D), - Vec2::new(BIG_2D, SMALL_2D), - ], -}; -const POLYLINE_3D: Polyline3d<4> = Polyline3d { - vertices: [ - Vec3::new(-BIG_3D, -SMALL_3D, -SMALL_3D), - Vec3::new(SMALL_3D, SMALL_3D, 0.0), - Vec3::new(-SMALL_3D, -SMALL_3D, 0.0), - Vec3::new(BIG_3D, SMALL_3D, SMALL_3D), - ], -}; - -const POLYGON_2D: Polygon<5> = Polygon { - vertices: [ - Vec2::new(-BIG_2D, -SMALL_2D), - Vec2::new(BIG_2D, -SMALL_2D), - Vec2::new(BIG_2D, SMALL_2D), - Vec2::new(0.0, 0.0), - Vec2::new(-BIG_2D, SMALL_2D), - ], -}; - const REGULAR_POLYGON: RegularPolygon = RegularPolygon { circumcircle: Circle { radius: BIG_2D }, sides: 5, @@ -452,8 +425,31 @@ fn draw_gizmos_2d(mut gizmos: Gizmos, state: Res>, time PrimitiveSelected::Segment => { drop(gizmos.primitive_2d(&SEGMENT_2D, isometry, color)); } - PrimitiveSelected::Polyline => gizmos.primitive_2d(&POLYLINE_2D, isometry, color), - PrimitiveSelected::Polygon => gizmos.primitive_2d(&POLYGON_2D, isometry, color), + PrimitiveSelected::Polyline => gizmos.primitive_2d( + &Polyline2d { + vertices: vec![ + Vec2::new(-BIG_2D, -SMALL_2D), + Vec2::new(-SMALL_2D, SMALL_2D), + Vec2::new(SMALL_2D, -SMALL_2D), + Vec2::new(BIG_2D, SMALL_2D), + ], + }, + isometry, + color, + ), + PrimitiveSelected::Polygon => gizmos.primitive_2d( + &Polygon { + vertices: vec![ + Vec2::new(-BIG_2D, -SMALL_2D), + Vec2::new(BIG_2D, -SMALL_2D), + Vec2::new(BIG_2D, SMALL_2D), + Vec2::new(0.0, 0.0), + Vec2::new(-BIG_2D, SMALL_2D), + ], + }, + isometry, + color, + ), PrimitiveSelected::RegularPolygon => { gizmos.primitive_2d(®ULAR_POLYGON, isometry, color); } @@ -667,7 +663,18 @@ fn draw_gizmos_3d(mut gizmos: Gizmos, state: Res>, time PrimitiveSelected::Plane => drop(gizmos.primitive_3d(&PLANE_3D, isometry, color)), PrimitiveSelected::Line => gizmos.primitive_3d(&LINE3D, isometry, color), PrimitiveSelected::Segment => gizmos.primitive_3d(&SEGMENT_3D, isometry, color), - PrimitiveSelected::Polyline => gizmos.primitive_3d(&POLYLINE_3D, isometry, color), + PrimitiveSelected::Polyline => gizmos.primitive_3d( + &Polyline3d { + vertices: vec![ + Vec3::new(-BIG_3D, -SMALL_3D, -SMALL_3D), + Vec3::new(SMALL_3D, SMALL_3D, 0.0), + Vec3::new(-SMALL_3D, -SMALL_3D, 0.0), + Vec3::new(BIG_3D, SMALL_3D, SMALL_3D), + ], + }, + isometry, + color, + ), PrimitiveSelected::Polygon => {} PrimitiveSelected::RegularPolygon => {} PrimitiveSelected::Capsule => drop( From 25a4fb4d690e8acedca9b7799027785f13033d2b Mon Sep 17 00:00:00 2001 From: charlotte Date: Tue, 22 Jul 2025 14:37:01 -0700 Subject: [PATCH 09/17] Ci. --- crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs | 4 ++-- crates/bevy_math/src/bounding/bounded3d/extrusion.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs b/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs index 1c6858f63db46..958617b7aa566 100644 --- a/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs +++ b/crates/bevy_math/src/bounding/bounded2d/primitive_impls.rs @@ -888,7 +888,7 @@ mod tests { #[test] fn polyline() { - let polyline = Polyline2d::<4>::new([ + let polyline = Polyline2d::new([ Vec2::ONE, Vec2::new(-1.0, 1.0), Vec2::NEG_ONE, @@ -961,7 +961,7 @@ mod tests { #[test] fn polygon() { - let polygon = Polygon::<4>::new([ + let polygon = Polygon::new([ Vec2::ONE, Vec2::new(-1.0, 1.0), Vec2::NEG_ONE, diff --git a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs index deb98a9a2ff74..540a9daa3c48f 100644 --- a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs +++ b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs @@ -390,7 +390,7 @@ mod tests { #[test] fn polygon() { - let polygon = Polygon::<4>::new([ + let polygon = Polygon::new([ Vec2::ONE, Vec2::new(-1.0, 1.0), Vec2::NEG_ONE, From 5e6c45d7387c8d85e85386730f7fe46662dc38d0 Mon Sep 17 00:00:00 2001 From: charlotte Date: Tue, 22 Jul 2025 19:37:26 -0700 Subject: [PATCH 10/17] Ci. --- crates/bevy_math/src/bounding/bounded3d/extrusion.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs index 540a9daa3c48f..8d849deaec433 100644 --- a/crates/bevy_math/src/bounding/bounded3d/extrusion.rs +++ b/crates/bevy_math/src/bounding/bounded3d/extrusion.rs @@ -344,7 +344,7 @@ mod tests { #[test] fn polyline() { - let polyline = Polyline2d::<4>::new([ + let polyline = Polyline2d::new([ Vec2::ONE, Vec2::new(-1.0, 1.0), Vec2::NEG_ONE, From 422de39231630fde2be0c049f8e8f7bb9ce3a1f8 Mon Sep 17 00:00:00 2001 From: charlotte Date: Wed, 23 Jul 2025 11:27:37 -0700 Subject: [PATCH 11/17] Ci. --- crates/bevy_math/src/primitives/dim2.rs | 4 ---- crates/bevy_math/src/primitives/dim3.rs | 2 -- crates/bevy_pbr/src/render/view_transformations.wgsl | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index dfaa19cca9acf..bf33812af03e9 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -1537,8 +1537,6 @@ impl From<(Vec2, Vec2)> for Segment2d { } /// A series of connected line segments in 2D space. -/// -/// For a version without generics: [`BoxedPolyline2d`] #[cfg(feature = "alloc")] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] @@ -1864,8 +1862,6 @@ impl Measured2d for Rectangle { } /// A polygon with N vertices. -/// -/// For a version without generics: [`BoxedPolygon`] #[cfg(feature = "alloc")] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 4b8643a729cde..d56edbbb606d8 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -605,8 +605,6 @@ impl From<(Vec3, Vec3)> for Segment3d { } /// A series of connected line segments in 3D space. -/// -/// For a version without generics: [`BoxedPolyline3d`] #[cfg(feature = "alloc")] #[derive(Clone, Debug, PartialEq)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/bevy_pbr/src/render/view_transformations.wgsl b/crates/bevy_pbr/src/render/view_transformations.wgsl index 80c26d7b69b2e..9bf229463300b 100644 --- a/crates/bevy_pbr/src/render/view_transformations.wgsl +++ b/crates/bevy_pbr/src/render/view_transformations.wgsl @@ -32,7 +32,7 @@ /// Convert a view space position to world space fn position_view_to_world(view_pos: vec3) -> vec3 { - let world_pos = view_bindings::view.world_from_view * vec4(view_pos, 1.0); + AMBIENT_DAYLIGHTlet world_pos = view_bindings::view.world_from_view * vec4(view_pos, 1.0); return world_pos.xyz; } From 9ec3b3715b08ea44fd497ad0403930f8314ecb69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Wed, 6 Aug 2025 21:06:11 -0700 Subject: [PATCH 12/17] Switch to subdivisions. --- crates/bevy_math/src/primitives/dim2.rs | 23 ++++++++++++++--------- crates/bevy_math/src/primitives/dim3.rs | 23 ++++++++++++++--------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index bf33812af03e9..32cf2a4762474 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -1582,17 +1582,22 @@ impl Polyline2d { Self::from_iter(vertices) } - /// Create a new `Polyline2d` from two endpoints and a number of segments. - pub fn with_segment_count(start: Vec2, end: Vec2, segments: usize) -> Self { - if segments == 0 { - return Self::new(Vec::from([start, end])); + /// Create a new `Polyline2d` from two endpoints with subdivision points. + /// `subdivisions = 0` creates a simple line with just start and end points. + /// `subdivisions = 1` adds one point in the middle, creating 2 segments, etc. + pub fn with_subdivisions(start: Vec2, end: Vec2, subdivisions: usize) -> Self { + let total_vertices = subdivisions + 2; + let mut vertices = Vec::with_capacity(total_vertices); + + if subdivisions == 0 { + vertices.extend([start, end]); + } else { + let step = (end - start) / (subdivisions + 1) as f32; + for i in 0..total_vertices { + vertices.push(start + step * i as f32); + } } - let step = (end - start) / segments as f32; - let mut vertices = Vec::with_capacity(segments + 1); - for i in 0..=segments { - vertices.push(start + step * i as f32); - } Self { vertices } } } diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index d56edbbb606d8..39ad0b6ea867a 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -648,17 +648,22 @@ impl Polyline3d { Self::from_iter(vertices) } - /// Create a new `Polyline3d` from two endpoints and a number of segments. - pub fn with_segment_count(start: Vec3, end: Vec3, segments: usize) -> Self { - if segments == 0 { - return Self::new(Vec::from([start, end])); + /// Create a new `Polyline3d` from two endpoints with subdivision points. + /// `subdivisions = 0` creates a simple line with just start and end points. + /// `subdivisions = 1` adds one point in the middle, creating 2 segments, etc. + pub fn with_subdivisions(start: Vec3, end: Vec3, subdivisions: usize) -> Self { + let total_vertices = subdivisions + 2; + let mut vertices = Vec::with_capacity(total_vertices); + + if subdivisions == 0 { + vertices.extend([start, end]); + } else { + let step = (end - start) / (subdivisions + 1) as f32; + for i in 0..total_vertices { + vertices.push(start + step * i as f32); + } } - let step = (end - start) / segments as f32; - let mut vertices = Vec::with_capacity(segments + 1); - for i in 0..=segments { - vertices.push(start + step * i as f32); - } Self { vertices } } } From 744be31496472d1c287d6d9caf3dda9bf117c68f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Wed, 6 Aug 2025 21:08:50 -0700 Subject: [PATCH 13/17] Simplify. --- crates/bevy_math/src/primitives/dim2.rs | 10 +++------- crates/bevy_math/src/primitives/dim3.rs | 10 +++------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index 32cf2a4762474..94ec3f007d90d 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -1589,13 +1589,9 @@ impl Polyline2d { let total_vertices = subdivisions + 2; let mut vertices = Vec::with_capacity(total_vertices); - if subdivisions == 0 { - vertices.extend([start, end]); - } else { - let step = (end - start) / (subdivisions + 1) as f32; - for i in 0..total_vertices { - vertices.push(start + step * i as f32); - } + let step = (end - start) / (subdivisions + 1) as f32; + for i in 0..total_vertices { + vertices.push(start + step * i as f32); } Self { vertices } diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index 39ad0b6ea867a..d0e6d3930fc25 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -655,13 +655,9 @@ impl Polyline3d { let total_vertices = subdivisions + 2; let mut vertices = Vec::with_capacity(total_vertices); - if subdivisions == 0 { - vertices.extend([start, end]); - } else { - let step = (end - start) / (subdivisions + 1) as f32; - for i in 0..total_vertices { - vertices.push(start + step * i as f32); - } + let step = (end - start) / (subdivisions + 1) as f32; + for i in 0..total_vertices { + vertices.push(start + step * i as f32); } Self { vertices } From 49dee2c03ce89df86da197292106ba1c9f88363d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Tue, 12 Aug 2025 15:20:04 -0700 Subject: [PATCH 14/17] Fix defaults. --- crates/bevy_math/src/primitives/dim2.rs | 2 +- crates/bevy_math/src/primitives/dim3.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_math/src/primitives/dim2.rs b/crates/bevy_math/src/primitives/dim2.rs index 94ec3f007d90d..f037fb638eeb9 100644 --- a/crates/bevy_math/src/primitives/dim2.rs +++ b/crates/bevy_math/src/primitives/dim2.rs @@ -1570,7 +1570,7 @@ impl FromIterator for Polyline2d { impl Default for Polyline2d { fn default() -> Self { Self { - vertices: Vec::from([Vec2::new(0.0, 0.0), Vec2::new(1.0, 0.0)]), + vertices: Vec::from([Vec2::new(-0.5, 0.0), Vec2::new(0.5, 0.0)]), } } } diff --git a/crates/bevy_math/src/primitives/dim3.rs b/crates/bevy_math/src/primitives/dim3.rs index d0e6d3930fc25..729ebd48e9442 100644 --- a/crates/bevy_math/src/primitives/dim3.rs +++ b/crates/bevy_math/src/primitives/dim3.rs @@ -637,7 +637,7 @@ impl FromIterator for Polyline3d { #[cfg(feature = "alloc")] impl Default for Polyline3d { fn default() -> Self { - Self::new([Vec3::new(0.0, 0.0, 0.0), Vec3::new(1.0, 0.0, 0.0)]) + Self::new([Vec3::new(-0.5, 0.0, 0.0), Vec3::new(0.5, 0.0, 0.0)]) } } From f2acb70ffe8929418e1284476bd993dc4b0068e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Tue, 12 Aug 2025 17:43:07 -0700 Subject: [PATCH 15/17] Add migration guidde. --- .../primitives_non_const_generic_meshable.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 release-content/migration-guides/primitives_non_const_generic_meshable.md diff --git a/release-content/migration-guides/primitives_non_const_generic_meshable.md b/release-content/migration-guides/primitives_non_const_generic_meshable.md new file mode 100644 index 0000000000000..f417317674303 --- /dev/null +++ b/release-content/migration-guides/primitives_non_const_generic_meshable.md @@ -0,0 +1,8 @@ +--- +title: Polylines and Polygons are no longer const-generic +pull_requests: [20250] +--- + +`Polyline2d`, `Polyline3d`, `Polygon`, and `ConvexPolygon` are no longer const-generic and now implement `Meshable` for +direct mesh generation. These types now use `Vec` instead of arrays internally and will therefore allocate and are no +longer `no_std` compatible. \ No newline at end of file From daba849c12af37c86061d859282fb6c562c0a975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?charlotte=20=F0=9F=8C=B8?= Date: Tue, 12 Aug 2025 17:48:39 -0700 Subject: [PATCH 16/17] Format police. --- .../migration-guides/primitives_non_const_generic_meshable.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release-content/migration-guides/primitives_non_const_generic_meshable.md b/release-content/migration-guides/primitives_non_const_generic_meshable.md index f417317674303..7357efacaae2a 100644 --- a/release-content/migration-guides/primitives_non_const_generic_meshable.md +++ b/release-content/migration-guides/primitives_non_const_generic_meshable.md @@ -1,8 +1,8 @@ --- title: Polylines and Polygons are no longer const-generic -pull_requests: [20250] +pull_requests: [ 20250 ] --- -`Polyline2d`, `Polyline3d`, `Polygon`, and `ConvexPolygon` are no longer const-generic and now implement `Meshable` for +`Polyline2d`, `Polyline3d`, `Polygon`, and `ConvexPolygon` are no longer const-generic and now implement `Meshable` for direct mesh generation. These types now use `Vec` instead of arrays internally and will therefore allocate and are no longer `no_std` compatible. \ No newline at end of file From 169efc751f03b5c7b63f93e20812620c62e4c26f Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Tue, 12 Aug 2025 20:59:22 -0400 Subject: [PATCH 17/17] Appease the whitespace police for Charlotte --- .../migration-guides/primitives_non_const_generic_meshable.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release-content/migration-guides/primitives_non_const_generic_meshable.md b/release-content/migration-guides/primitives_non_const_generic_meshable.md index 7357efacaae2a..378bf86f95c93 100644 --- a/release-content/migration-guides/primitives_non_const_generic_meshable.md +++ b/release-content/migration-guides/primitives_non_const_generic_meshable.md @@ -5,4 +5,4 @@ pull_requests: [ 20250 ] `Polyline2d`, `Polyline3d`, `Polygon`, and `ConvexPolygon` are no longer const-generic and now implement `Meshable` for direct mesh generation. These types now use `Vec` instead of arrays internally and will therefore allocate and are no -longer `no_std` compatible. \ No newline at end of file +longer `no_std` compatible.