Commit graph

252 commits

Author SHA1 Message Date
Olle Lukowski
d7fc20c484
Implemented Reflect for (almost) all bevy_math types (#13537)
# Objective

Fixes #13535.

## Solution

I implemented `Reflect` for close to all math types now, except for some
types that it would cause issues (like some boxed types).

## Testing

- Everything seems to still build, will await CI though.
---

## Changelog

- Made close to all math types implement `Reflect`.
2024-05-27 18:18:10 +00:00
Olle Lukowski
8c7f73ab81
Move bevy_math Reflect impls (#13520)
# Objective

Fixes #13456 

## Solution

Moved `bevy_math`'s `Reflect` impls from `bevy_reflect` to `bevy_math`.


### Quick note
I accidentally used the same commit message while resolving a merge
conflict (first time I had to resolve a conflict). Sorry about that.
2024-05-27 14:15:22 +00:00
Salvador Carvalhinho
7d843e0c08
Implement Rhombus 2D primitive. (#13501)
# Objective

- Create a new 2D primitive, Rhombus, also knows as "Diamond Shape"
- Simplify the creation and handling of isometric projections
- Extend Bevy's arsenal of 2D primitives

## Testing

- New unit tests created in bevy_math/ primitives and bev_math/ bounding
- Tested translations, rotations, wireframe, bounding sphere, aabb and
creation parameters

---------

Co-authored-by: Luís Figueiredo <luispcfigueiredo@tecnico.ulisboa.pt>
2024-05-26 15:27:57 +00:00
Joona Aalto
383314ef62
Add meshing for ConicalFrustum (#11819)
# Objective

The `ConicalFrustum` primitive should support meshing.

## Solution

Implement meshing for the `ConicalFrustum` primitive. The implementation
is nearly identical to `Cylinder` meshing, but supports two radii.

The default conical frustum is equivalent to a cone with a height of 1
and a radius of 0.5, truncated at half-height.


![kuva](https://github.com/bevyengine/bevy/assets/57632562/b4cab136-ff55-4056-b818-1218e4f38845)
2024-05-25 21:56:09 +00:00
Ben Harper
ec01c2dc45
New circular primitives: Arc2d, CircularSector, CircularSegment (#13482)
# Objective

Adopted #11748

## Solution

I've rebased on main to fix the merge conflicts. ~~Not quite ready to
merge yet~~

* Clippy is happy and the tests are passing, but...
* ~~The new shapes in `examples/2d/2d_shapes.rs` don't look right at
all~~ Never mind, looks like radians and degrees just got mixed up at
some point?
* I have updated one doc comment based on a review in the original PR.

---------

Co-authored-by: Alexis "spectria" Horizon <spectria.limina@gmail.com>
Co-authored-by: Alexis "spectria" Horizon <118812919+spectria-limina@users.noreply.github.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Ben Harper <ben@tukom.org>
2024-05-23 16:12:46 +00:00
Vitaliy Sapronenko
da1e6e63ff
Mention of Vec normalization for Dir::new (#13483)
# Objective

- Fixes #13429 .

## Solution

- Improved docs for methods `new`, `new_and_length` of `Dir2`, `Dir3`,
`Dir3A`.
2024-05-23 15:20:21 +00:00
Ben Harper
bd5148e0f5
Add triangle_math tests and fix Triangle3d::bounding_sphere bug (#13467)
# Objective

Adopted #12659.

Resolved the merge conflicts on #12659;

* I merged the `triangle_tests` added by this PR and by #13020.
* I moved the [commented out
code](https://github.com/bevyengine/bevy/pull/12659#discussion_r1536640427)
from the original PR into a separate test with `#[should_panic]`.

---------

Co-authored-by: Vitor Falcao <vitorfhc@protonmail.com>
Co-authored-by: Ben Harper <ben@tukom.org>
2024-05-23 15:03:00 +00:00
Olle Lukowski
1ec5cdf3f2
Optimize the values for EMPTY rect. (#13470)
I am unsure if this needs changing, so let me know if I need to change
anything else.

# Objective

Fixes #13461.

## Solution

I applied the changes as suggested in the issue, and updated the doc
comments accordingly

## Testing

I don't think this needs too much testing, but there are no `cargo test`
failures.
2024-05-22 13:34:23 +00:00
Matty
5dbd827728
Annulus sampling (#13471)
# Objective

Add random sampling for the `Annulus` primitive. This is part of ongoing
work to bring the various `bevy_math` primitives to feature parity.

## Solution

`Annulus` implements `ShapeSample`. Boundary sampling is implemented in
the obvious way, and interior sampling works exactly as in the
implementation for `Circle`, using the fact that the square of the
radius should be taken uniformly from between r^2 and R^2, where r and R
are the inner and outer radii respectively.

## Testing

I generated a bunch of random points and rendered them. Here's 1000
points on the interior of the default annulus:
<img width="1440" alt="Screenshot 2024-05-22 at 8 01 34 AM"
src="https://github.com/bevyengine/bevy/assets/2975848/19c31bb0-edba-477f-b247-2b12d854afae">

This looks kind of weird around the edges, but I verified that they're
all actually inside the annulus, so I assume it has to do with the fact
that the rendered circles have some radius.
2024-05-22 13:13:04 +00:00
Matty
d2ef88f5e8
Add Distribution access methods for ShapeSample trait (#13315)
Stolen from #12835. 

# Objective

Sometimes you want to sample a whole bunch of points from a shape
instead of just one. You can write your own loop to do this, but it's
really more idiomatic to use a `rand`
[`Distribution`](https://docs.rs/rand/latest/rand/distributions/trait.Distribution.html)
with the `sample_iter` method. Distributions also support other useful
things like mapping, and they are suitable as generic items for
consumption by other APIs.

## Solution

`ShapeSample` has been given two new automatic trait methods,
`interior_dist` and `boundary_dist`. They both have similar signatures
(recall that `Output` is the output type for `ShapeSample`):
```rust
fn interior_dist(self) -> impl Distribution<Self::Output>
where Self: Sized { //... }
```

These have default implementations which are powered by wrapper structs
`InteriorOf` and `BoundaryOf` that actually implement `Distribution` —
the implementations effectively just call `ShapeSample::sample_interior`
and `ShapeSample::sample_boundary` on the contained type.

The upshot is that this allows iteration as follows:
```rust
// Get an iterator over boundary points of a rectangle:
let rectangle = Rectangle::new(1.0, 2.0);
let boundary_iter = rectangle.boundary_dist().sample_iter(rng);
// Collect a bunch of boundary points at once:
let boundary_pts: Vec<Vec2> = boundary_iter.take(1000).collect();
```

Alternatively, you can use `InteriorOf`/`BoundaryOf` explicitly to
similar effect:
```rust
let boundary_pts: Vec<Vec2> = BoundaryOf(rectangle).sample_iter(rng).take(1000).collect();
```

---

## Changelog

- Added `InteriorOf` and `BoundaryOf` distribution wrapper structs in
`bevy_math::sampling::shape_sampling`.
- Added `interior_dist` and `boundary_dist` automatic trait methods to
`ShapeSample`.
- Made `shape_sampling` module public with explanatory documentation.

---

## Discussion

### Design choices

The main point of interest here is just the choice of `impl
Distribution` instead of explicitly using `InteriorOf`/`BoundaryOf`
return types for `interior_dist` and `boundary_dist`. The reason for
this choice is that it allows future optimizations for repeated sampling
— for example, instead of just wrapping the base type,
`interior_dist`/`boundary_dist` could construct auxiliary data that is
held over between sampling operations.
2024-05-22 12:38:08 +00:00
Vitaliy Sapronenko
151e198d94
Add slerp function for Dir2, Dir3, Dir3A (#13451)
# Objective

- Fixes #13407 .

## Solution

- Used Quat and Rotation2d.

## Testing

- Added tests based on 0°, 30°, 45°, 60° and 90° angles
2024-05-21 21:13:32 +00:00
Martín Maita
f9da5eecf2
Rename Rect inset() method to inflate() (#13452)
# Objective

- Fixes #13092.

## Solution

- Renamed the `inset()` method in `Rect`, `IRect` and `URect` to
`inflate()`.
- Added `EMPTY` constants to all `Rect` variants, represented by corners
with the maximum numerical values for each kind.

---

## Migration Guide

- Replace `Rect::inset()`, `IRect::inset()` and `URect::inset()` calls
with `inflate()`.
2024-05-21 20:53:55 +00:00
Matty
b7ec19bb2d
Tetrahedron sampling (#13430)
# Objective

Add interior and boundary sampling for the `Tetrahedron` primitive. This
is part of ongoing work to bring the primitives to parity with each
other in terms of their capabilities.

## Solution

`Tetrahedron` implements the `ShapeSample` trait. To support this, there
is a new public method `Tetrahedron::faces` which gets the faces of a
tetrahedron as `Triangle3d`s. There are more sophisticated ideas for
getting the faces we might want to consider in the future (e.g.
adjusting according to the orientation), but this method gives the most
mathematically straightforward answer, giving the faces the orientation
induced by the tetrahedron itself.
2024-05-21 18:40:03 +00:00
Ben Harper
be03ba1b68
Add reflect impls for bevy_math curve structs (#13348)
# Objective

Fixes #13189

## Solution

To add the reflect impls I needed to make all the struct fields pub. I
don't think there's any harm for these types, but just a note for
review.

---------

Co-authored-by: Ben Harper <ben@tukom.org>
2024-05-16 17:59:56 +00:00
IcyLeave6109
f61c55fd90
Allow shapes to be constructed with zero values (#13365)
# Objective

Fixes #13332.

## Solution

The assertion `circumradius >= 0.0` to allow zero.

Are there any other shapes that need to be allowed to be constructed
with zero?

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-05-16 02:22:50 +00:00
Brezak
cbda71c2b3
Determine msrv for every standalone bevy_* crate. (#13211)
# Objective

As was pointed out in #13183, `bevy_mikktspace` is missing it's msrv
from it `Cargo.toml`. This promted me to check the msrv of every
`bevy_*` crate. Closes #13183.

## Solution

- Call `cargo check` with different rust versions on every bevy crate
until it doesn't complain.
- Write down the rust version `cargo check` started working.

## Testing

- Install `cargo-msrv`.
- Run `cargo msrv verify`.
- Rejoice.

---

## Changelog

Every published bevy crate now specifies a MSRV. If your rust toolchain
isn't at least version `1.77.0` You'll likely not be able to compile
most of bevy.

## Migration Guide

If your rust toolchain is bellow version`1.77.0, update.
2024-05-13 18:26:41 +00:00
Joona Aalto
ac1f135e20
Add meshing for Cone (#11820)
# Objective

The `Cone` primitive should support meshing.

## Solution

Implement meshing for the `Cone` primitive. The default cone has a
height of 1 and a base radius of 0.5, and is centered at the origin.

An issue with cone meshes is that the tip does not really have a normal
that works, even with duplicated vertices. This PR uses only a single
vertex for the tip, with a normal of zero; this results in an "invalid"
normal that gets ignored by the fragment shader. This seems to be the
only approach we have for perfectly smooth cones. For discussion on the
topic, see #10298 and #5891.

Another thing to note is that the cone uses polar coordinates for the
UVs:

<img
src="https://github.com/bevyengine/bevy/assets/57632562/e101ded9-110a-4ac4-a98d-f1e4d740a24a"
alt="cone" width="400" />

This way, textures are applied as if looking at the cone from above:

<img
src="https://github.com/bevyengine/bevy/assets/57632562/8dea00f1-a283-4bc4-9676-91e8d4adb07a"
alt="texture" width="200" />

<img
src="https://github.com/bevyengine/bevy/assets/57632562/d9d1b5e6-a8ba-4690-b599-904dd85777a1"
alt="cone" width="200" />
2024-05-13 18:00:59 +00:00
Ben Harper
6f641e9f9b
Add copy, clone, and debug derives to cubic spline structs (#13293)
# Objective

Fixes #13190

---------

Co-authored-by: Ben Harper <ben@tukom.org>
2024-05-12 20:48:08 +00:00
Matty
4da11fda77
Add AXES iterators for Dir types (#13305)
# Objective

Sometimes it's nice to iterate over all the coordinate axes using
something like `Vec3::AXES`. This was not available for the
corresponding `Dir` types and now it is.

## Solution

We already have things like `Dir2::X`, `Dir3::Z` and so on, so I just
threw them in an array like the vector types do it. I also slightly
refactored the sphere gizmo code to use `Dir3::AXES` and operate on
directions instead of using `Dir3::new_unchecked`.

## Testing

I looked at the sphere in the `3d_gizmos` example and it seems to work,
so I assume I didn't break anything.
2024-05-09 23:30:44 +00:00
Lynn
03f4cc5dde
Extrusion (#13270)
# Objective

- Adds a basic `Extrusion<T: Primitive2d>` shape, suggestion of #10572 

## Solution

- Adds `Measured2d` and `Measured3d` traits for getting the
perimeter/area or area/volume of shapes. This allows implementing
`.volume()` and `.area()` for all extrusions `Extrusion<T: Primitive2d +
Measured2d>` within `bevy_math`
- All existing perimeter, area and volume implementations for primitves
have been moved into implementations of `Measured2d` and `Measured3d`
- Shapes should be extruded along the Z-axis since an extrusion of depth
`0.` should be equivalent in everything but name to the base shape

## Caviats

- I am not sure about the naming. `Extrusion<T>` could also be
`Prism<T>` and the `MeasuredNd` could also be something like
`MeasuredPrimitiveNd`. If you have any other suggestions, please fell
free to share them :)

## Future work

This PR adds a basic `Extrusion` shape and does not implement a lot of
things you might want it to. Some of the future possibilities include:
- [ ] bounding for extrusions
- [ ] making extrusions work with gizmos
- [ ] meshing

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-05-07 14:41:55 +00:00
moonlightaria
1126b5a3d6
replace std::f32::EPSILON with f32::EPSILON (#13267)
# Objective
fixes clippy warning related to using a std::f32::EPSILON which is
planned to be depreciated for f32::EPSILON
2024-05-07 05:23:53 +00:00
Lynn
4f9f987099
Ellipse functions (#13025)
# Objective

- Add some useful methods to `Ellipse`

## Solution

- Added `Ellipse::perimeter()` and `::focal_length()`

---------

Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-05-06 21:31:51 +00:00
BD103
e357b63448
Add README.md to all crates (#13184)
# Objective

- `README.md` is a common file that usually gives an overview of the
folder it is in.
- When on <https://crates.io>, `README.md` is rendered as the main
description.
- Many crates in this repository are lacking `README.md` files, which
makes it more difficult to understand their purpose.

<img width="1552" alt="image"
src="https://github.com/bevyengine/bevy/assets/59022059/78ebf91d-b0c4-4b18-9874-365d6310640f">

- There are also a few inconsistencies with `README.md` files that this
PR and its follow-ups intend to fix.

## Solution

- Create a `README.md` file for all crates that do not have one.
- This file only contains the title of the crate (underscores removed,
proper capitalization, acronyms expanded) and the <https://shields.io>
badges.
- Remove the `readme` field in `Cargo.toml` for `bevy` and
`bevy_reflect`.
- This field is redundant because [Cargo automatically detects
`README.md`
files](https://doc.rust-lang.org/cargo/reference/manifest.html#the-readme-field).
The field is only there if you name it something else, like `INFO.md`.
- Fix capitalization of `bevy_utils`'s `README.md`.
- It was originally `Readme.md`, which is inconsistent with the rest of
the project.
- I created two commits renaming it to `README.md`, because Git appears
to be case-insensitive.
- Expand acronyms in title of `bevy_ptr` and `bevy_utils`.
- In the commit where I created all the new `README.md` files, I
preferred using expanded acronyms in the titles. (E.g. "Bevy Developer
Tools" instead of "Bevy Dev Tools".)
- This commit changes the title of existing `README.md` files to follow
the same scheme.
- I do not feel strongly about this change, please comment if you
disagree and I can revert it.
- Add <https://shields.io> badges to `bevy_time` and `bevy_transform`,
which are the only crates currently lacking them.

---

## Changelog

- Added `README.md` files to all crates missing it.
2024-05-02 18:56:00 +00:00
Martín Maita
32cd0c5dc1
Update glam version requirement from 0.25 to 0.27 (#12757)
# Objective

- Update glam version requirement to latest version.

## Solution

- Updated `glam` version requirement from 0.25 to 0.27.
- Updated `encase` and `encase_derive_impl` version requirement from 0.7
to 0.8.
- Updated `hexasphere` version requirement from 10.0 to 12.0.
- Breaking changes from glam changelog:
- [0.26.0] Minimum Supported Rust Version bumped to 1.68.2 for impl
From<bool> for {f32,f64} support.
- [0.27.0] Changed implementation of vector fract method to match the
Rust implementation instead of the GLSL implementation, that is self -
self.trunc() instead of self - self.floor().

---

## Migration Guide

- When using `glam` exports, keep in mind that `vector` `fract()` method
now matches Rust implementation (that is `self - self.trunc()` instead
of `self - self.floor()`). If you want to use the GLSL implementation
you should now use `fract_gl()`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-05-02 18:42:34 +00:00
NiseVoid
414abb4959
Use Vec3A for 3D bounding volumes and raycasts (#13087)
# Objective

- People have reported bounding volumes being slower than their existing
solution because it doesn't use SIMD aligned types.

## Solution

- Use `Vec3A` internally for bounding volumes, accepting `Into<Vec3A>`
wherever possible
- Change some code to make it more likely SIMD operations are used.

---

## Changelog

- Use `Vec3A` for 3D bounding volumes and raycasts

## Migration Guide

- 3D bounding volumes now use `Vec3A` types internally, return values
from methods on them now return `Vec3A` instead of `Vec3`
2024-04-25 18:56:58 +00:00
nullicorn
f496d2a3c3
Additional doc aliases for WindingOrder in bevy_math (#13065)
# Objective

Adds a few extra `#[doc(alias)]` entries to the
`bevy_math::primitives::WindingOrder` enum and its variants to improve
searchability.

## Solution

- Add "Orientation" for `WindingOrder` itself
- Add "AntiClockwise" for `CounterClockwise` variant
- Add "Collinear" for `Invalid` variant

These alternate terms seem to be quite common, especially in the
contexts of rendering and collision-detection.

Signed-off-by: Nullicorn <git@nullicorn.me>
2024-04-22 21:50:27 +00:00
targrub
8316166622
Fix uses of "it's" vs "its". (#13033)
Grammar changes only.
2024-04-19 18:17:31 +00:00
Lynn
cd80b10d43
Math primitives cleanup (#13020)
# Objective

- General clenup of the primitives in `bevy_math`
- Add `eccentricity()` to `Ellipse`

## Solution

- Moved `Bounded3d` implementation for `Triangle3d` to the `bounded`
module
- Added `eccentricity()` to `Ellipse`
- `Ellipse::semi_major()` and `::semi_minor()` now accept `&self`
instead of `self`
- `Triangle3d::is_degenerate()` actually uses `f32::EPSILON` as
documented
- Added tests for `Triangle3d`-maths

---------

Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
Co-authored-by: Miles Silberling-Cook <nth.tensor@gmail.com>
2024-04-18 23:45:51 +00:00
andristarr
2b3e3341d6
separating finite and infinite 3d planes (#12426)
# Objective

Fixes #12388

## Solution

- Removing the plane3d and adding rect3d primitive mesh
2024-04-18 14:13:22 +00:00
Matty
3a7923ea92
Random sampling of directions and quaternions (#12857)
# Objective

Augment Bevy's random sampling capabilities by providing good tools for
producing random directions and rotations.

## Solution

The `rand` crate has a natural tool for providing `Distribution`s whose
output is a type that doesn't require any additional data to sample
values — namely,
[`Standard`](https://docs.rs/rand/latest/rand/distributions/struct.Standard.html).

Here, our existing `ShapeSample` implementations have been put to good
use in providing these, resulting in patterns like the following:
```rust
// Using thread-local rng
let random_direction1: Dir3 = random();

// Using an explicit rng
let random_direction2: Dir3 = rng.gen();

// Using an explicit rng coupled explicitly with Standard
let random_directions: Vec<Dir3> = rng.sample_iter(Standard).take(5).collect();
```

Furthermore, we have introduced a trait `FromRng` which provides sugar
for `rng.gen()` that is more namespace-friendly (in this author's
opinion):
```rust
let random_direction = Dir3::from_rng(rng);
```

The types this has been implemented for are `Dir2`, `Dir3`, `Dir3A`, and
`Quat`. Notably, `Quat` uses `glam`'s implementation rather than an
in-house one, and as a result, `bevy_math`'s "rand" feature now enables
that of `glam`.

---

## Changelog

- Created `standard` submodule in `sampling` to hold implementations and
other items related to the `Standard` distribution.
- "rand" feature of `bevy_math` now enables that of `glam`.

---

## Discussion

From a quick glance at `Quat`'s distribution implementation in `glam`, I
am a bit suspicious, since it is simple and doesn't match any algorithm
that I came across in my research. I will do a little more digging as a
follow-up to this and see if it's actually uniform (maybe even using
those tools I wrote — what a thrill).

As an aside, I'd also like to say that I think
[`Distribution`](https://docs.rs/rand/latest/rand/distributions/trait.Distribution.html)
is really, really good. It integrates with distributions provided
externally (e.g. in `rand` itself and its extensions) along with doing a
good job of isolating the source of randomness, so that output can be
reliably reproduced if need be. Finally, `Distribution::sample_iter` is
quite good for ergonomically acquiring lots of random values. At one
point I found myself writing traits to describe random sampling and
essentially reinvented this one. I just think it's good, and I think
it's worth centralizing around to a significant extent.
2024-04-04 23:13:00 +00:00
Antony
344e28d095
Change Tetrahedron default origin to (0, 0, 0) (#12867)
# Objective

- Fixes #12837.

## Solution

- Update `Tetrahedron` default vertices to `[0.5, 0.5, 0.5]`, `[-0.5,
0.5, -0.5]`, `[-0.5, -0.5, 0.5]` and `[0.5, -0.5, -0.5]` respectively.
- Update `tetrahedron_math` tests to account for change in default
vertices.
2024-04-03 23:00:54 +00:00
mamekoro
8092e2c86d
Implement basic traits for AspectRatio (#12840)
# Objective
`AspectRatio` is a newtype of `f32`, so it can implement basic traits;
`Copy`, `Clone`, `Debug`, `PartialEq` and `PartialOrd`.

## Solution
Derive basic traits for `AspectRatio`.
2024-04-01 23:02:07 +00:00
Jakub Marcowski
20ee56e719
Add Tetrahedron primitive to bevy_math::primitives (#12688)
# Objective

- #10572

There is no 3D primitive available for the common shape of a tetrahedron
(3-simplex).

## Solution

This PR introduces a new type to the existing math primitives:

- `Tetrahedron`: a polyhedron composed of four triangular faces, six
straight edges, and four vertices

---

## Changelog

### Added

- `Tetrahedron` primitive to the `bevy_math` crate
- `Tetrahedron` tests (`area`, `volume` methods)
- `impl_reflect!` declaration for `Tetrahedron` in the `bevy_reflect`
crate
2024-04-01 21:53:12 +00:00
BD103
84363f2fab
Remove redundant imports (#12817)
# Objective

- There are several redundant imports in the tests and examples that are
not caught by CI because additional flags need to be passed.

## Solution

- Run `cargo check --workspace --tests` and `cargo check --workspace
--examples`, then fix all warnings.
- Add `test-check` to CI, which will be run in the check-compiles job.
This should catch future warnings for tests. Examples are already
checked, but I'm not yet sure why they weren't caught.

## Discussion

- Should the `--tests` and `--examples` flags be added to CI, so this is
caught in the future?
- If so, #12818 will need to be merged first. It was also a warning
raised by checking the examples, but I chose to split off into a
separate PR.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-04-01 19:59:08 +00:00
Verte
97f0555cb0
Remove VectorSpace impl on Quat (#12796)
- Fixes #[12762](https://github.com/bevyengine/bevy/issues/12762).

## Migration Guide

- `Quat` no longer implements `VectorSpace` as unit quaternions don't
actually form proper vector spaces. If you're absolutely certain that
what you're doing is correct, convert the `Quat` into a `Vec4` and
perform the operations before converting back.
2024-03-30 17:18:52 +00:00
Matty
bcdb20d4f3
Fix Triangle2d/Triangle3d interior sampling to correctly follow triangle (#12766)
# Objective

When I wrote #12747 I neglected to translate random samples from
triangles back to the point where they originated, so they would be
sampled near the origin instead of at the actual triangle location.

## Solution

Translate by the first vertex location so that the samples follow the
actual triangle.
2024-03-29 13:10:23 +00:00
Matty
f924b4d9ef
Move Point out of cubic splines module and expand it (#12747)
# Objective

Previously, the `Point` trait, which abstracts all of the operations of
a real vector space, was sitting in the submodule of `bevy_math` for
cubic splines. However, the trait has broader applications than merely
cubic splines, and we should use it when possible to avoid code
duplication when performing vector operations.

## Solution

`Point` has been moved into a new submodule in `bevy_math` named
`common_traits`. Furthermore, it has been renamed to `VectorSpace`,
which is more descriptive, and an additional trait `NormedVectorSpace`
has been introduced to expand the API to cover situations involving
geometry in addition to algebra. Additionally, `VectorSpace` itself now
requires a `ZERO` constant and `Neg`. It also supports a `lerp` function
as an automatic trait method.

Here is what that looks like:
```rust
/// A type that supports the mathematical operations of a real vector space, irrespective of dimension.
/// In particular, this means that the implementing type supports:
/// - Scalar multiplication and division on the right by elements of `f32`
/// - Negation
/// - Addition and subtraction
/// - Zero
///
/// Within the limitations of floating point arithmetic, all the following are required to hold:
/// - (Associativity of addition) For all `u, v, w: Self`, `(u + v) + w == u + (v + w)`.
/// - (Commutativity of addition) For all `u, v: Self`, `u + v == v + u`.
/// - (Additive identity) For all `v: Self`, `v + Self::ZERO == v`.
/// - (Additive inverse) For all `v: Self`, `v - v == v + (-v) == Self::ZERO`.
/// - (Compatibility of multiplication) For all `a, b: f32`, `v: Self`, `v * (a * b) == (v * a) * b`.
/// - (Multiplicative identity) For all `v: Self`, `v * 1.0 == v`.
/// - (Distributivity for vector addition) For all `a: f32`, `u, v: Self`, `(u + v) * a == u * a + v * a`.
/// - (Distributivity for scalar addition) For all `a, b: f32`, `v: Self`, `v * (a + b) == v * a + v * b`.
///
/// Note that, because implementing types use floating point arithmetic, they are not required to actually
/// implement `PartialEq` or `Eq`.
pub trait VectorSpace:
    Mul<f32, Output = Self>
    + Div<f32, Output = Self>
    + Add<Self, Output = Self>
    + Sub<Self, Output = Self>
    + Neg
    + Default
    + Debug
    + Clone
    + Copy
{
    /// The zero vector, which is the identity of addition for the vector space type.
    const ZERO: Self;

    /// Perform vector space linear interpolation between this element and another, based
    /// on the parameter `t`. When `t` is `0`, `self` is recovered. When `t` is `1`, `rhs`
    /// is recovered.
    ///
    /// Note that the value of `t` is not clamped by this function, so interpolating outside
    /// of the interval `[0,1]` is allowed.
    #[inline]
    fn lerp(&self, rhs: Self, t: f32) -> Self {
        *self * (1. - t) + rhs * t
    }
}
```
```rust
/// A type that supports the operations of a normed vector space; i.e. a norm operation in addition
/// to those of [`VectorSpace`]. Specifically, the implementor must guarantee that the following
/// relationships hold, within the limitations of floating point arithmetic:
/// - (Nonnegativity) For all `v: Self`, `v.norm() >= 0.0`.
/// - (Positive definiteness) For all `v: Self`, `v.norm() == 0.0` implies `v == Self::ZERO`.
/// - (Absolute homogeneity) For all `c: f32`, `v: Self`, `(v * c).norm() == v.norm() * c.abs()`.
/// - (Triangle inequality) For all `v, w: Self`, `(v + w).norm() <= v.norm() + w.norm()`.
///
/// Note that, because implementing types use floating point arithmetic, they are not required to actually
/// implement `PartialEq` or `Eq`.
pub trait NormedVectorSpace: VectorSpace {
    /// The size of this element. The return value should always be nonnegative.
    fn norm(self) -> f32;

    /// The squared norm of this element. Computing this is often faster than computing
    /// [`NormedVectorSpace::norm`].
    #[inline]
    fn norm_squared(self) -> f32 {
        self.norm() * self.norm()
    }

    /// The distance between this element and another, as determined by the norm.
    #[inline]
    fn distance(self, rhs: Self) -> f32 {
        (rhs - self).norm()
    }

    /// The squared distance between this element and another, as determined by the norm. Note that
    /// this is often faster to compute in practice than [`NormedVectorSpace::distance`].
    #[inline]
    fn distance_squared(self, rhs: Self) -> f32 {
        (rhs - self).norm_squared()
    }
}
```

Furthermore, this PR also demonstrates the use of the
`NormedVectorSpace` combined API to implement `ShapeSample` for
`Triangle2d` and `Triangle3d` simultaneously. Such deduplication is one
of the drivers for developing these APIs.

---

## Changelog

- `Point` from `cubic_splines` becomes `VectorSpace`, exported as
`bevy::math::VectorSpace`.
- `VectorSpace` requires `Neg` and `VectorSpace::ZERO` in addition to
its existing prerequisites.
- Introduced public traits `bevy::math::NormedVectorSpace` for generic
geometry tasks involving vectors.
- Implemented `ShapeSample` for `Triangle2d` and `Triangle3d`.

## Migration Guide

Since `Point` no longer exists, any projects using it must switch to
`bevy::math::VectorSpace`. Additionally, third-party implementations of
this trait now require the `Neg` trait; the constant `VectorSpace::ZERO`
must be provided as well.

---

## Discussion

### Design considerations

Originally, the `NormedVectorSpace::norm` method was part of a separate
trait `Normed`. However, I think that was probably too broad and, more
importantly, the semantics of having it in `NormedVectorSpace` are much
clearer.

As it currently stands, the API exposed here is pretty minimal, and
there is definitely a lot more that we could do, but there are more
questions to answer along the way. As a silly example, we could
implement `NormedVectorSpace::length` as an alias for
`NormedVectorSpace::norm`, but this overlaps with methods in all of the
glam types, so we would want to make sure that the implementations are
effectively identical (for what it's worth, I think they are already).

### Future directions

One example of something that could belong in the `NormedVectorSpace`
API is normalization. Actually, such a thing previously existed on this
branch before I decided to shelve it because of concerns with namespace
collision. It looked like this:
```rust
/// This element, but normalized to norm 1 if possible. Returns an error when the reciprocal of
/// the element's norm is not finite.
#[inline]
#[must_use]
fn normalize(&self) -> Result<Self, NonNormalizableError> {
    let reciprocal = 1.0 / self.norm();
    if reciprocal.is_finite() {
        Ok(*self * reciprocal)
    } else {
        Err(NonNormalizableError { reciprocal })
    }
}

/// An error indicating that an element of a [`NormedVectorSpace`] was non-normalizable due to having 
/// non-finite norm-reciprocal.
#[derive(Debug, Error)]
#[error("Element with norm reciprocal {reciprocal} cannot be normalized")]
pub struct NonNormalizableError {
    reciprocal: f32
}
```

With this kind of thing in hand, it might be worth considering
eventually making the passage from vectors to directions fully generic
by employing a wrapper type. (Of course, for our concrete types, we
would leave the existing names in place as aliases.) That is, something
like:
```rust
pub struct NormOne<T>
where T: NormedVectorSpace { //... }
```

Utterly separately, the reason that I implemented `ShapeSample` for
`Triangle2d`/`Triangle3d` was to prototype uniform sampling of abstract
meshes, so that's also a future direction.

---------

Co-authored-by: Zachary Harrold <zac@harrold.com.au>
2024-03-28 13:40:26 +00:00
mamekoro
6840f95d62
Implement From<Vec2> for AspectRatio (#12754)
# Objective
Since it is common to store a pair of width and height as `Vec2`, it
would be useful to have an easy way to instantiate `AspectRatio` from
`Vec2`.

## Solution
Add `impl From<Vec2> for AspectRatio`.

---

## Changelog
- Added `impl From<Vec2> for AspectRatio`
2024-03-27 22:32:31 +00:00
Vitaliy Sapronenko
c38e2d037d
Math tests fix (#12748)
# Objective

Fixes `cargo test -p bevy_math` as in #12729.

## Solution

As described in
[message](https://github.com/bevyengine/bevy/issues/12729#issuecomment-2022197944)
Added workaround `bevy_math = { path = ".", version = "0.14.0-dev",
features = ["approx"] }` to `bevy_math`'s `dev-dependencies`

---------

Co-authored-by: BD103 <59022059+BD103@users.noreply.github.com>
2024-03-27 20:48:20 +00:00
Jacques Schutte
4508077297
Move FloatOrd into bevy_math (#12732)
# Objective

- Fixes #12712

## Solution

- Move the `float_ord.rs` file to `bevy_math`
- Change any `bevy_utils::FloatOrd` statements to `bevy_math::FloatOrd`

---

## Changelog

- Moved `FloatOrd` from `bevy_utils` to `bevy_math`

## Migration Guide

- References to `bevy_utils::FloatOrd` should be changed to
`bevy_math::FloatOrd`
2024-03-27 18:30:11 +00:00
James Liu
56bcbb0975
Forbid unsafe in most crates in the engine (#12684)
# Objective
Resolves #3824. `unsafe` code should be the exception, not the norm in
Rust. It's obviously needed for various use cases as it's interfacing
with platforms and essentially running the borrow checker at runtime in
the ECS, but the touted benefits of Bevy is that we are able to heavily
leverage Rust's safety, and we should be holding ourselves accountable
to that by minimizing our unsafe footprint.

## Solution
Deny `unsafe_code` workspace wide. Add explicit exceptions for the
following crates, and forbid it in almost all of the others.

* bevy_ecs - Obvious given how much unsafe is needed to achieve
performant results
* bevy_ptr - Works with raw pointers, even more low level than bevy_ecs.
 * bevy_render - due to needing to integrate with wgpu
 * bevy_window - due to needing to integrate with raw_window_handle
* bevy_utils - Several unsafe utilities used by bevy_ecs. Ideally moved
into bevy_ecs instead of made publicly usable.
 * bevy_reflect - Required for the unsafe type casting it's doing.
 * bevy_transform - for the parallel transform propagation
 * bevy_gizmos  - For the SystemParam impls it has.
* bevy_assets - To support reflection. Might not be required, not 100%
sure yet.
* bevy_mikktspace - due to being a conversion from a C library. Pending
safe rewrite.
* bevy_dynamic_plugin - Inherently unsafe due to the dynamic loading
nature.

Several uses of unsafe were rewritten, as they did not need to be using
them:

* bevy_text - a case of `Option::unchecked` could be rewritten as a
normal for loop and match instead of an iterator.
* bevy_color - the Pod/Zeroable implementations were replaceable with
bytemuck's derive macros.
2024-03-27 03:30:08 +00:00
Jakub Marcowski
31d91466b4
Add Annulus primitive to bevy_math::primitives (#12706)
# Objective

- #10572

There is no 2D primitive available for the common shape of an annulus
(ring).

## Solution

This PR introduces a new type to the existing math primitives:

- `Annulus`: the region between two concentric circles

---

## Changelog

### Added

- `Annulus` primitive to the `bevy_math` crate
- `Annulus` tests (`diameter`, `thickness`, `area`, `perimeter` and
`closest_point` methods)

---------

Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-03-25 23:13:14 +00:00
James Liu
f096ad4155
Set the logo and favicon for all of Bevy's published crates (#12696)
# Objective
Currently the built docs only shows the logo and favicon for the top
level `bevy` crate. This makes views like
https://docs.rs/bevy_ecs/latest/bevy_ecs/ look potentially unrelated to
the project at first glance.

## Solution
Reproduce the docs attributes for every crate that Bevy publishes.

Ideally this would be done with some workspace level Cargo.toml control,
but AFAICT, such support does not exist.
2024-03-25 18:52:50 +00:00
Ame
72c51cdab9
Make feature(doc_auto_cfg) work (#12642)
# Objective

- In #12366 `![cfg_attr(docsrs, feature(doc_auto_cfg))] `was added. But
to apply it it needs `--cfg=docsrs` in rustdoc-args.


## Solution

- Apply `--cfg=docsrs` to all crates and CI.

I also added `[package.metadata.docs.rs]` to all crates to avoid adding
code behind a feature and forget adding the metadata.

Before:

![Screenshot 2024-03-22 at 00 51
57](https://github.com/bevyengine/bevy/assets/104745335/6a9dfdaa-8710-4784-852b-5f9b74e3522c)

After:
![Screenshot 2024-03-22 at 00 51
32](https://github.com/bevyengine/bevy/assets/104745335/c5bd6d8e-8ddb-45b3-b844-5ecf9f88961c)
2024-03-23 02:22:52 +00:00
Vitor Falcao
c9ec95d782
Add Triangle3d primitive to bevy_math::primitives (#12508)
# Context

[GitHub Discussion
Link](https://github.com/bevyengine/bevy/discussions/12506)

# Objective

- **Clarity:** More explicit representation of a common geometric
primitive.
- **Convenience:** Provide methods tailored to 3D triangles (area,
perimeters, etc.).

## Solution

- Adding the `Triangle3d` primitive into the `bevy_math` crate.

---

## Changelog

### Added

- `Triangle3d` primitive to the `bevy_math` crate

### Changed

- `Triangle2d::reverse`: the first and last vertices are swapped instead
of the second and third.

---------

Co-authored-by: Miles Silberling-Cook <NthTensor@users.noreply.github.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-03-22 17:24:51 +00:00
Matty
93c17d105a
Make cardinal splines include endpoints (#12574)
# Objective

- Fixes #12570 

## Solution

Previously, cardinal splines constructed by `CubicCardinalSpline` would
leave out their endpoints when constructing the cubic curve segments
connecting their points. (See the linked issue for details.)

Now, cardinal splines include the endpoints. For instance, the provided
usage example
```rust
let points = [
    vec2(-1.0, -20.0),
    vec2(3.0, 2.0),
    vec2(5.0, 3.0),
    vec2(9.0, 8.0),
];
let cardinal = CubicCardinalSpline::new(0.3, points).to_curve();
let positions: Vec<_> = cardinal.iter_positions(100).collect();
```
will actually produce a spline that connects all four of these points
instead of just the middle two "interior" points.

Internally, this is achieved by duplicating the endpoints of the vector
of control points before performing the construction of the associated
`CubicCurve`. This amounts to specifying that the tangents at the
endpoints `P_0` and `P_n` (say) should be parallel to `P_1 - P_0` and
`P_n - P_{n-1}`.

---

## Migration Guide

Any users relying on the old behavior of `CubicCardinalSpline` will have
to truncate any parametrizations they used in order to access a curve
identical to the one they had previously. This would be done by chopping
off a unit-distance segment from each end of the parametrizing interval.
For instance, if a user's existing code looks as follows
```rust
fn interpolate(t: f32) -> Vec2 {
    let points = [
        vec2(-1.0, -20.0),
        vec2(3.0, 2.0),
        vec2(5.0, 3.0),
        vec2(9.0, 8.0),
    ];
    let my_curve = CubicCardinalSpline::new(0.3, points).to_curve();
    my_curve.position(t)
}
```

then in order to obtain similar behavior, `t` will need to be shifted up
by 1, since the output of `CubicCardinalSpline::to_curve` has introduced
a new segment in the interval [0,1], displacing the old segment from
[0,1] to [1,2]:

```rust
fn interpolate(t: f32) -> Vec2 {
    let points = [
        vec2(-1.0, -20.0),
        vec2(3.0, 2.0),
        vec2(5.0, 3.0),
        vec2(9.0, 8.0),
    ];
    let my_curve = CubicCardinalSpline::new(0.3, points).to_curve();
    my_curve.position(t+1)
}
```

(Note that this does not provide identical output for values of `t`
outside of the interval [0,1].)

On the other hand, any user who was specifying additional endpoint
tangents simply to get the curve to pass through the right points (i.e.
not requiring exactly the same output) can simply omit the endpoints
that were being supplied only for control purposes.

---

## Discussion

### Design considerations

This is one of the two approaches outlined in #12570 — in this PR, we
are basically declaring that the docs are right and the implementation
was flawed.

One semi-interesting question is how the endpoint tangents actually
ought to be defined when we include them, and another option considered
was mirroring the control points adjacent to the endpoints instead of
duplicating them, which would have had the advantage that the expected
length of the corresponding difference should be more similar to that of
the other difference-tangents, provided that the points are equally
spaced.

In this PR, the duplication method (which produces smaller tangents) was
chosen for a couple reasons:
- It seems to be more standard
- It is exceptionally simple to implement
- I was a little concerned that the aforementioned alternative would
result in some over-extrapolation

### An annoyance

If you look at the code, you'll see I was unable to find a satisfactory
way of doing this without allocating a new vector. This doesn't seem
like a big problem given the context, but it does bother me. In
particular, if there is some easy parallel to `slice::windows` for
iterators that doesn't pull in an external dependency, I would love to
know about it.
2024-03-21 18:58:51 +00:00
Brezak
ed44eb3913
Add a from Dir2 impl for Vec2 (#12594)
# Objective

Allow converting from `Dir2` to `Vec2` in generic code. Fixes #12529.

## Solution

Added a `From<Dir2>` impl for `Vec2`.
2024-03-20 14:21:50 +00:00
Multirious
70da903cec
Add methods to return the inner value for direction types (#12516)
# Objective

Currently in order to retrieve the inner values from direction types is
that you need to use the `Deref` trait or `From`/`Into`. `Deref` that is
currently implemented is an anti-pattern that I believe should be less
relied upon.
This pull-request add getters for retrieving the inner values for
direction types.

Advantages of getters:
- Let rust-analyzer to list out available methods for users to
understand better to on how to get the inner value. (This happens to me.
I really don't know how to get the value until I look through the source
code.)
- They are simple.
- Generally won't be ambiguous in most context. Traits such as
`From`/`Into` will require fully qualified syntax from time to time.
- Unsurprising result.

Disadvantages of getters:
- More verbose

Advantages of deref polymorphism:
- You reduce boilerplate for getting the value and call inner methods
by:
  ```rust
  let dir = Dir3::new(Vec3::UP).unwrap();
  // getting value
  let value = *dir;
  // instead of using getters
  let value = dir.vec3();

  // calling methods for the inner vector
  dir.xy();
  // instead of using getters
  dir.vec3().xy();
  ```

Disadvantages of deref polymorphism:
- When under more level of indirection, it will requires more
dereferencing which will get ugly in some part:
  ```rust
  // getting value
  let value = **dir;
  // instead of using getters
  let value = dir.vec3();

  // calling methods for the inner vector
  dir.xy();
  // instead of using getters
  dir.vec3().xy();
  ```

[More detail
here](https://rust-unofficial.github.io/patterns/anti_patterns/deref.html).


Edit: Update information for From/Into trait.
Edit: Advantages and disadvantages.

## Solution

Add `vec2` method for Dir2.
Add `vec3` method for Dir3.
Add `vec3a` method for Dir3A.
2024-03-18 17:49:58 +00:00
TheBigCheese
948ea3137a
Uniform point sampling methods for some primitive shapes. (#12484)
# Objective
Give easy methods for uniform point sampling in a variety of primitive
shapes (particularly useful for circles and spheres) because in a lot of
cases its quite easy to get wrong (non-uniform).

## Solution
Added the `ShapeSample` trait to `bevy_math` and implemented it for
`Circle`, `Sphere`, `Rectangle`, `Cuboid`, `Cylinder`, `Capsule2d` and
`Capsule3d`. There are a few other shapes it would be reasonable to
implement for like `Triangle`, `Ellipse` and `Torus` but I'm not
immediately sure how these would be implemented (other than rejection
which could be the best method, and could be more performant than some
of the solutions in this pr I'm not sure). This exposes the
`sample_volume` and `sample_surface` methods to get both a random point
from its interior or its surface. EDIT: Renamed `sample_volume` to
`sample_interior` and `sample_surface` to `sample_boundary`

This brings in `rand` as a default optional dependency (without default
features), and the methods take `&mut impl Rng` which allows them to use
any random source implementing `RngCore`.

---

## Changelog
### Added
Added the methods `sample_interior` and `sample_boundary` to a variety
of primitive shapes providing easy uniform point sampling.
2024-03-17 14:48:16 +00:00
Antony
686d354d28
Add scale_around_center method to BoundingVolume trait (#12142)
# Objective

Add a `scale_around_center` method to the `BoundingVolume` trait, as per
#12130.

## Solution

Added `scale_around_center` to the `BoundingVolume` trait, implemented
in `Aabb2d`, `Aabb3d`, `BoundingCircle`, and `BoundingSphere` (with
tests).
2024-03-11 21:48:25 +00:00
Joona Aalto
f89af0567b
Add Rotation2d (#11658)
# Objective

Rotating vectors is a very common task. It is required for a variety of
things both within Bevy itself and in many third party plugins, for
example all over physics and collision detection, and for things like
Bevy's bounding volumes and several gizmo implementations.

For 3D, we can do this using a `Quat`, but for 2D, we do not have a
clear and efficient option. `Mat2` can be used for rotating vectors if
created using `Mat2::from_angle`, but this is not obvious to many users,
it doesn't have many rotation helpers, and the type does not give any
guarantees that it represents a valid rotation.

We should have a proper type for 2D rotations. In addition to allowing
for potential optimization, it would allow us to have a consistent and
explicitly documented representation used throughout the engine, i.e.
counterclockwise and in radians.

## Representation

The mathematical formula for rotating a 2D vector is the following:

```
new_x = x * cos - y * sin
new_y = x * sin + y * cos
```

Here, `sin` and `cos` are the sine and cosine of the rotation angle.
Computing these every time when a vector needs to be rotated can be
expensive, so the rotation shouldn't be just an `f32` angle. Instead, it
is often more efficient to represent the rotation using the sine and
cosine of the angle instead of storing the angle itself. This can be
freely passed around and reused without unnecessary computations.

The two options are either a 2x2 rotation matrix or a unit complex
number where the cosine is the real part and the sine is the imaginary
part. These are equivalent for the most part, but the unit complex
representation is a bit more memory efficient (two `f32`s instead of
four), so I chose that. This is like Nalgebra's
[`UnitComplex`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.UnitComplex.html)
type, which can be used for the
[`Rotation2`](https://docs.rs/nalgebra/latest/nalgebra/geometry/type.Rotation2.html)
type.

## Implementation

Add a `Rotation2d` type represented as a unit complex number:

```rust
/// A counterclockwise 2D rotation in radians.
///
/// The rotation angle is wrapped to be within the `]-pi, pi]` range.
pub struct Rotation2d {
    /// The cosine of the rotation angle in radians.
    ///
    /// This is the real part of the unit complex number representing the rotation.
    pub cos: f32,
    /// The sine of the rotation angle in radians.
    ///
    /// This is the imaginary part of the unit complex number representing the rotation.
    pub sin: f32,
}
```

Using it is similar to using `Quat`, but in 2D:

```rust
let rotation = Rotation2d::radians(PI / 2.0);

// Rotate vector (also works on Direction2d!)
assert_eq!(rotation * Vec2::X, Vec2::Y);

// Get angle as degrees
assert_eq!(rotation.as_degrees(), 90.0);

// Getting sin and cos is free
let (sin, cos) = rotation.sin_cos();

// "Subtract" rotations
let rotation2 = Rotation2d::FRAC_PI_4; // there are constants!
let diff = rotation * rotation2.inverse();
assert_eq!(diff.as_radians(), PI / 4.0);

// This is equivalent to the above
assert_eq!(rotation2.angle_between(rotation), PI / 4.0);

// Lerp
let rotation1 = Rotation2d::IDENTITY;
let rotation2 = Rotation2d::FRAC_PI_2;
let result = rotation1.lerp(rotation2, 0.5);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_4);

// Slerp
let rotation1 = Rotation2d::FRAC_PI_4);
let rotation2 = Rotation2d::degrees(-180.0); // we can use degrees too!
let result = rotation1.slerp(rotation2, 1.0 / 3.0);
assert_eq!(result.as_radians(), std::f32::consts::FRAC_PI_2);
```

There's also a `From<f32>` implementation for `Rotation2d`, which means
that methods can still accept radians as floats if the argument uses
`impl Into<Rotation2d>`. This means that adding `Rotation2d` shouldn't
even be a breaking change.

---

## Changelog

- Added `Rotation2d`
- Bounding volume methods now take an `impl Into<Rotation2d>`
- Gizmo methods with rotation now take an `impl Into<Rotation2d>`

## Future use cases

- Collision detection (a type like this is quite essential considering
how common vector rotations are)
- `Transform` helpers (e.g. return a 2D rotation about the Z axis from a
`Transform`)
- The rotation used for `Transform2d` (#8268)
- More gizmos, maybe meshes... everything in 2D that uses rotation

---------

Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
Co-authored-by: Robert Walter <robwalter96@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-03-11 19:11:57 +00:00
Al M
52e3f2007b
Add "all-features = true" to docs.rs metadata for most crates (#12366)
# Objective

Fix missing `TextBundle` (and many others) which are present in the main
crate as default features but optional in the sub-crate. See:

- https://docs.rs/bevy/0.13.0/bevy/ui/node_bundles/index.html
- https://docs.rs/bevy_ui/0.13.0/bevy_ui/node_bundles/index.html

~~There are probably other instances in other crates that I could track
down, but maybe "all-features = true" should be used by default in all
sub-crates? Not sure.~~ (There were many.) I only noticed this because
rust-analyzer's "open docs" features takes me to the sub-crate, not the
main one.

## Solution

Add "all-features = true" to docs.rs metadata for crates that use
features.

## Changelog

### Changed

- Unified features documented on docs.rs between main crate and
sub-crates
2024-03-08 20:03:09 +00:00
Joona Aalto
4bed1b2200
Add note about rotations for Aabb3d (#12315)
# Objective

Fixes #12310.

#11681 added transformations for bounding volumes, but I accidentally
only added a note in the docs about repeated rotations for `Aabb2d` and
not `Aabb3d`.

## Solution

Copy the docs over to `Aabb3d`.
2024-03-05 17:22:53 +00:00
Joona Aalto
921ba54acf
Support transforming bounding volumes (#11681)
# Objective

Make it straightforward to translate and rotate bounding volumes.

## Solution

Add `translate_by`/`translated_by`, `rotate_by`/`rotated_by`,
`transform_by`/`transformed_by` methods to the `BoundingVolume` trait.
This follows the naming used for mesh transformations (see #11454 and
#11675).

---

## Changelog

- Added `translate_by`/`translated_by`, `rotate_by`/`rotated_by`,
`transform_by`/`transformed_by` methods to the `BoundingVolume` trait
and implemented them for the bounding volumes
- Renamed `Position` associated type to `Translation`

---------

Co-authored-by: Mateusz Wachowiak <mateusz_wachowiak@outlook.com>
2024-03-05 00:48:45 +00:00
Joona Aalto
983da7677a
Improve error messages for denormalized directions (#12278)
# Objective

`Dir3` and `Dir3A` can be rotated using `Quat`s. However, if enough
floating point error accumulates or (more commonly) the rotation itself
is degenerate (like not normalized), the resulting direction can also
become denormalized.

Currently, with debug assertions enabled, it panics in these cases with
the message `rotated.is_normalized()`. This error message is unclear,
doesn't give information about *how* it is denormalized (like is the
length too large, NaN, or something else), and is overall not very
helpful. Panicking for small-ish error might also be a bit too strict,
and has lead to unwanted crashes in crates like `bevy_xpbd` (although it
has also helped in finding actual bugs).

The error message should be clearer and give more context, and it
shouldn't cause unwanted crashes.

## Solution

Change the `debug_assert!` to a warning for small error with a (squared
length) threshold of 2e-4 and a panic for clear error with a threshold
of 2e-2. The warnings mention the direction type and the length of the
denormalized vector.

Here's what the error and warning look like:

```
Error: `Dir3` is denormalized after rotation. The length is 1.014242.
```

```
Warning: `Dir3A` is denormalized after rotation. The length is 1.0001414.
```

I gave the same treatment to `new_unchecked`:

```
Error: The vector given to `Dir3::new_unchecked` is not normalized. The length is 1.014242.
```

```
Warning: The vector given to `Dir3A::new_unchecked` is not normalized. The length is 1.0001414.
```

---

## Discussion

### Threshold values

The thresholds are somewhat arbitrary. 2e-4 is what Glam uses for the
squared length in `is_normalized` (after I corrected it in
bitshifter/glam-rs#480), and 2e-2 is just what I thought could be a
clear sign of something being critically wrong. I can definitely tune
them if there are better thresholds though.

### Logging

`bevy_math` doesn't have `bevy_log`, so we can't use `warn!` or
`error!`. This is why I made it use just `eprintln!` and `panic!` for
now. Let me know if there's a better way of logging errors in
`bevy_math`.
2024-03-04 00:01:32 +00:00
Joona Aalto
6032978eba
Implement Mul between f32 and direction types (#12276)
# Objective

Bevy's `Dir3` and `Dir3A` only implement `Mul<f32>` and not vice versa,
and `Dir2` can not be multiplied by `f32` at all. They all should
implement multiplication both ways, just like Glam's vector types.

## Solution

Implement `Mul<Dir2>`, `Mul<Dir3>`, and `Mul<Dir3A>` for `f32`, and
`Mul<f32>` for `Dir2`.
2024-03-03 17:44:16 +00:00
Joona Aalto
f418de8eb6
Rename Direction2d/3d to Dir2/3 (#12189)
# Objective

Split up from #12017, rename Bevy's direction types.

Currently, Bevy has the `Direction2d`, `Direction3d`, and `Direction3dA`
types, which provide a type-level guarantee that their contained vectors
remain normalized. They can be very useful for a lot of APIs for safety,
explicitness, and in some cases performance, as they can sometimes avoid
unnecessary normalizations.

However, many consider them to be inconvenient to use, and opt for
standard vector types like `Vec3` because of this. One reason is that
the direction type names are a bit long and can be annoying to write (of
course you can use autocomplete, but just typing `Vec3` is still nicer),
and in some intances, the extra characters can make formatting worse.
The naming is also inconsistent with Glam's shorter type names, and
results in names like `Direction3dA`, which (in my opinion) are
difficult to read and even a bit ugly.

This PR proposes renaming the types to `Dir2`, `Dir3`, and `Dir3A`.
These names are nice and easy to write, consistent with Glam, and work
well for variants like the SIMD aligned `Dir3A`. As a bonus, it can also
result in nicer formatting in a lot of cases, which can be seen from the
diff of this PR.

Some examples of what it looks like: (copied from #12017)

```rust
// Before
let ray_cast = RayCast2d::new(Vec2::ZERO, Direction2d::X, 5.0);

// After
let ray_cast = RayCast2d::new(Vec2::ZERO, Dir2::X, 5.0);
```

```rust
// Before (an example using Bevy XPBD)
let hit = spatial_query.cast_ray(
    Vec3::ZERO,
    Direction3d::X,
    f32::MAX,
    true,
    SpatialQueryFilter::default(),
);

// After
let hit = spatial_query.cast_ray(
    Vec3::ZERO,
    Dir3::X,
    f32::MAX,
    true,
    SpatialQueryFilter::default(),
);
```

```rust
// Before
self.circle(
    Vec3::new(0.0, -2.0, 0.0),
    Direction3d::Y,
    5.0,
    Color::TURQUOISE,
);

// After (formatting is collapsed in this case)
self.circle(Vec3::new(0.0, -2.0, 0.0), Dir3::Y, 5.0, Color::TURQUOISE);
```

## Solution

Rename `Direction2d`, `Direction3d`, and `Direction3dA` to `Dir2`,
`Dir3`, and `Dir3A`.

---

## Migration Guide

The `Direction2d` and `Direction3d` types have been renamed to `Dir2`
and `Dir3`.

## Additional Context

This has been brought up on the Discord a few times, and we had a small
[poll](https://discord.com/channels/691052431525675048/1203087353850364004/1212465038711984158)
on this. `Dir2`/`Dir3`/`Dir3A` was quite unanimously chosen as the best
option, but of course it was a very small poll and inconclusive, so
other opinions are certainly welcome too.

---------

Co-authored-by: IceSentry <c.giguere42@gmail.com>
2024-02-28 22:48:43 +00:00
JohnTheCoolingFan
a543536a34
Cubic splines overhaul (#10701)
# Objective

Improve the `bevy::math::cubic_splines` module by making it more
flexible and adding new curve types.
Closes #10220 

## Solution

Added new spline types and improved existing

---

## Changelog

### Added

- `CubicNurbs` rational cubic curve generator, allows setting the knot
vector and weights associated with every point
- `LinearSpline` curve generator, allows generating a linearly
interpolated curve segment
- Ability to push additional cubic segments to `CubicCurve`
- `IntoIterator` and `Extend` implementations for `CubicCurve`

### Changed

- `Point` trait has been implemented for more types: `Quat` and `Vec4`.
- `CubicCurve::coefficients` was moved to `CubicSegment::coefficients`
because the function returns `CubicSegment`, so it seems logical to be
associated with `CubicSegment` instead. The method is still not public.

### Fixed

- `CubicBSpline::new` was referencing Cardinal spline instead of
B-Spline

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
Co-authored-by: Miles Silberling-Cook <nth.tensor@gmail.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-02-28 17:18:42 +00:00
Joona Aalto
9bd6cc0a5e
Add Direction3dA and move direction types out of primitives (#12018)
# Objective

Split up from #12017, add an aligned version of `Direction3d` for SIMD,
and move direction types out of `primitives`.

## Solution

Add `Direction3dA` and move direction types into a new `direction`
module.

---

## Migration Guide

The `Direction2d`, `Direction3d`, and `InvalidDirectionError` types have
been moved out of `bevy::math::primitives`.

Before:

```rust
use bevy::math::primitives::Direction3d;
```

After:

```rust
use bevy::math::Direction3d;
```

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-02-26 13:57:49 +00:00
github-actions[bot]
e7c3359c4b
Bump Version after Release (#12020)
Fixes #12016.

Bump version after release
This PR has been auto-generated

Co-authored-by: Bevy Auto Releaser <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: François <mockersf@gmail.com>
2024-02-21 20:58:59 +00:00
Aztro
eef7dbefe8
Add single-f32 constructors for a few (very few) primitives (#11934)
# Objective

- I hated having to do `Cuboid::new(1.0, 1.0, 1.0)` or
`Cuboid::from_size(Vec3::splat(1.0))` when there should be a much easier
way to do this.

## Solution

- Implemented a `from_length()` method that only takes in a single
float, and constructs a primitive of equal size in all directions.
- Ex:
  ```rs
  // These:
  Cuboid::new(1.0, 1.0, 1.0);
  Cuboid::from_size(Vec3::splat(1.0));
  // Are equivalent to this:
  Cuboid::from_length(1.0);
  ```
 - For the rest of the changed primitives:
    ```rs
    Rectangle::from_length(1.0);
    Plane3d::default().mesh().from_length(1.0);
    ```
2024-02-18 07:43:45 +00:00
Carter Anderson
abb8c353f4
Release 0.13.0 (#11920)
Bump Bevy crates to 0.13.0 in preparation for release.

(Note that we accidentally skipped the `0.13.0-dev` step this cycle)
2024-02-17 09:24:25 +00:00
Joona Aalto
cf15e6bba3
Implement Meshable for some 3D primitives (#11688)
# Objective

Split up from #11007, fixing most of the remaining work for #10569.

Implement `Meshable` for `Cuboid`, `Sphere`, `Cylinder`, `Capsule`,
`Torus`, and `Plane3d`. This covers all shapes that Bevy has mesh
structs for in `bevy_render::mesh::shapes`.

`Cone` and `ConicalFrustum` are new shapes, so I can add them in a
follow-up, or I could just add them here directly if that's preferrable.

## Solution

Implement `Meshable` for `Cuboid`, `Sphere`, `Cylinder`, `Capsule`,
`Torus`, and `Plane3d`.

The logic is mostly just a copy of the the existing `bevy_render`
shapes, but `Plane3d` has a configurable surface normal that affects the
orientation. Some property names have also been changed to be more
consistent.

The default values differ from the old shapes to make them a bit more
logical:

- Spheres now have a radius of 0.5 instead of 1.0. The default capsule
is equivalent to the default cylinder with the sphere's halves glued on.
- The inner and outer radius of the torus are now 0.5 and 1.0 instead of
0.5 and 1.5 (i.e. the new minor and major radii are 0.25 and 0.75). It's
double the width of the default cuboid, half of its height, and the
default sphere matches the size of the hole.
- `Cuboid` is 1x1x1 by default unlike the dreaded `Box` which is 2x1x1.

Before, with "old" shapes:


![old](https://github.com/bevyengine/bevy/assets/57632562/733f3dda-258c-4491-8152-9829e056a1a3)

Now, with primitive meshing:


![new](https://github.com/bevyengine/bevy/assets/57632562/5a1af14f-bb98-401d-82cf-de8072fea4ec)

I only changed the `3d_shapes` example to use primitives for now. I can
change them all in this PR or a follow-up though, whichever way is
preferrable.

### Sphere API

Spheres have had separate `Icosphere` and `UVSphere` structs, but with
primitives we only have one `Sphere`.

We need to handle this with builders:

```rust
// Existing structs
let ico = Mesh::try_from(Icophere::default()).unwrap();
let uv = Mesh::from(UVSphere::default());

// Primitives
let ico = Sphere::default().mesh().ico(5).unwrap();
let uv = Sphere::default().mesh().uv(32, 18);
```

We could add methods on `Sphere` directly to skip calling `.mesh()`.

I also added a `SphereKind` enum that can be used with the `kind`
method:

```rust
let ico = Sphere::default()
    .mesh()
    .kind(SphereKind::Ico { subdivisions: 8 })
    .build();
```

The default mesh for a `Sphere` is an icosphere with 5 subdivisions
(like the default `Icosphere`).

---

## Changelog

- Implement `Meshable` and `Default` for `Cuboid`, `Sphere`, `Cylinder`,
`Capsule`, `Torus`, and `Plane3d`
- Use primitives in `3d_shapes` example

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-02-06 21:44:13 +00:00
Tristan Guichaoua
694c06f3d0
Inverse missing_docs logic (#11676)
# Objective

Currently the `missing_docs` lint is allowed-by-default and enabled at
crate level when their documentations is complete (see #3492).
This PR proposes to inverse this logic by making `missing_docs`
warn-by-default and mark crates with imcomplete docs allowed.

## Solution

Makes `missing_docs` warn at workspace level and allowed at crate level
when the docs is imcomplete.
2024-02-03 21:40:55 +00:00
Joona Aalto
9bad607df9
Implement meshing for Capsule2d (#11639)
# Objective

The `Capsule2d` primitive was added in #11585. It should support meshing
like the other 2D primitives.

## Solution

Implement meshing for `Capsule2d`.

It doesn't currently support "rings" like Bevy's `Capsule` shape (not
`Capsule3d`), but it does support resolution to control the number of
vertices used for one hemicircle. The total vertex count is two times
the resolution; if we allowed setting the full vertex count, odd numbers
would lead to uneven vertex counts for the top and bottom hemicircles
and produce potentially unwanted results.

The capsule looks like this (with UV visualization and wireframe) using
resolutions of 16, 8, and 3:

![Resolution
16](https://github.com/bevyengine/bevy/assets/57632562/feae22de-bdc5-438a-861f-848284b67a52)
![Resolution
8](https://github.com/bevyengine/bevy/assets/57632562/e95aab8e-793f-45ac-8a74-8be39f7626dd)
![Resolution of
3](https://github.com/bevyengine/bevy/assets/57632562/bcf01d23-1d8b-4cdb-966a-c9022a07c287)

The `2d_shapes` example now includes the capsule, so we also get one
more color of the rainbow 🌈

![New 2D shapes
example](https://github.com/bevyengine/bevy/assets/57632562/1c45b5f5-d26a-4e8c-8e8a-e106ab14d46e)
2024-02-03 18:03:43 +00:00
Robert Walter
041731b7e0
Drawing Primitives with Gizmos (#11072)
The PR is in a reviewable state now in the sense that the basic
implementations are there. There are still some ToDos that I'm aware of:

- [x] docs for all the new structs and traits
- [x] implement `Default` and derive other useful traits for the new
structs
- [x] Take a look at the notes again (Do this after a first round of
reviews)
- [x] Take care of the repetition in the circle drawing functions

---

# Objective

- TLDR: This PR enables us to quickly draw all the newly added
primitives from `bevy_math` in immediate mode with gizmos
- Addresses #10571

## Solution

- This implements the first design idea I had that covered everything
that was mentioned in the Issue
https://github.com/bevyengine/bevy/issues/10571#issuecomment-1863646197

--- 

## Caveats

- I added the `Primitive(2/3)d` impls for `Direction(2/3)d` to make them
work with the current solution. We could impose less strict requirements
for the gizmoable objects and remove the impls afterwards if the
community doesn't like the current approach.

---

## Changelog

- implement capabilities to draw ellipses on the gizmo in general (this
was required to have some code which is able to draw the ellipse
primitive)
- refactored circle drawing code to use the more general ellipse drawing
code to keep code duplication low
- implement `Primitive2d` for `Direction2d` and impl `Primitive3d` for
`Direction3d`
- implement trait to draw primitives with specialized details with
gizmos
  - `GizmoPrimitive2d` for all the 2D primitives
  - `GizmoPrimitive3d` for all the 3D primitives
- (question while writing this: Does it actually matter if we split this
in 2D and 3D? I guess it could be useful in the future if we do
something based on the main rendering mode even though atm it's kinda
useless)

---

---------

Co-authored-by: nothendev <borodinov.ilya@gmail.com>
2024-02-02 21:13:03 +00:00
Rose Hudson
d6f1649646
return Direction3d from Transform::up and friends (#11604)
# Objective
Drawing a `Gizmos::circle` whose normal is derived from a Transform's
local axes now requires converting a Vec3 to a Direction3d and
unwrapping the result, and I think we shold move the conversion into
Bevy.

## Solution
We can make
`Transform::{left,right,up,down,forward,back,local_x,local_y,local_z}`
return a Direction3d, because they know that their results will be of
finite non-zero length (roughly 1.0).

---

## Changelog
`Transform::up()` and similar functions now return `Direction3d` instead
of `Vec3`.

## Migration Guide
Callers of `Transform::up()` and similar functions may have to
dereference the returned `Direction3d` to get to the inner `Vec3`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-02-02 15:05:35 +00:00
NiseVoid
0ffc8d8a6f
Rename RayTest to RayCast (#11635)
# Objective

- `RayTest` vs `AabbCast` and `CircleCast` is inconsistent

## Solution

- Renaming the other two would only make the name more confusing, so we
rename `RayTest2d/3d` to `RayCast2d/3d`
2024-02-02 15:01:04 +00:00
Joona Aalto
6f2eec8f78
Support rotating Direction3d by Quat (#11649)
# Objective

It's often necessary to rotate directions, but it currently has to be
done like this:

```rust
Direction3d::new_unchecked(quat * *direction)
```

It'd be nice if you could rotate `Direction3d` directly:

```rust
quat * direction
```

## Solution

Implement `Mul<Direction3d>` for `Quat` ~~and the other way around.~~
(Glam doesn't impl `Mul<Quat>` or `MulAssign<Quat>` for `Vec3`)

The quaternion must be a unit quaternion to keep the direction
normalized, so there is a `debug_assert!` to be sure. Almost all `Quat`
constructors produce unit quaternions, so there should only be issues if
doing something like `quat + quat` instead of `quat * quat`, using
`Quat::from_xyzw` directly, or when you have significant enough drift
caused by e.g. physics simulation that doesn't normalize rotation. In
general, these would probably cause unexpected results anyway.

I also moved tests around slightly to make `dim2` and `dim3` more
consistent (`dim3` had *two* separate `test` modules for some reason).

In the future, we'll probably want a `Rotation2d` type that would
support the same for `Direction2d`. I considered implementing
`Mul<Mat2>` for `Direction2d`, but that would probably be more
questionable since `Mat2` isn't as clearly associated with rotations as
`Quat` is.
2024-02-01 20:08:24 +00:00
Joona Aalto
d30fdda2c3
Implement approx traits for direction types (#11650)
# Objective

`approx` has traits like
[`AbsDiffEq`](https://docs.rs/approx/latest/approx/trait.AbsDiffEq.html),
[`RelativeEq`](https://docs.rs/approx/latest/approx/trait.RelativeEq.html),
and [`UlpsEq`](https://docs.rs/approx/latest/approx/trait.UlpsEq.html).
Glam implements them for its math types when the `approx` feature is
enabled. Bevy's `Direction2d` and `Direction3d` should implement these
too.

## Solution

Implement the traits. See [how Glam implements them for its own math
types](https://github.com/bitshifter/glam-rs/blob/main/src/features/impl_approx.rs).
For the epsilon values, I use the same as `Vec2`/`Vec3` (just
`f32::EPSILON`).
2024-02-01 19:22:28 +00:00
NiseVoid
e3126a494f
Add Clone to intersection test types (#11640)
# Objective

- Add Clone to RayTest/AabbCast2d/AabbCast3d/CircleCast/SphereCast
2024-02-01 00:54:30 +00:00
NiseVoid
1b98de68fe
Add volume cast intersection tests (#11586)
# Objective

- Add a basic form of shapecasting for bounding volumes

## Solution

- Implement AabbCast2d, AabbCast3d, BoundingCircleCast, and
BoundingSphereCast
- These are really just raycasts, but they modify the volumes the ray is
casting against
- The tests are slightly simpler, since they just use the raycast code
for the heavy lifting
2024-01-31 20:14:15 +00:00
Joona Aalto
a9f061e909
Add Capsule2d primitive (#11585)
# Objective

Currently, the `Capsule` primitive is technically dimension-agnostic in
that it implements both `Primitive2d` and `Primitive3d`. This seems good
on paper, but it can often be useful to have separate 2D and 3D versions
of primitives.

For example, one might want a two-dimensional capsule mesh. We can't
really implement both 2D and 3D meshing for the same type using the
upcoming `Meshable` trait (see #11431). We also currently don't
implement `Bounded2d` for `Capsule`, see
https://github.com/bevyengine/bevy/pull/11336#issuecomment-1890797788.

Having 2D and 3D separate at a type level is more explicit, and also
more consistent with the existing primitives, as there are no other
types that implement both `Primitive2d` and `Primitive3d` at the same
time.

## Solution

Rename `Capsule` to `Capsule3d` and add `Capsule2d`. `Capsule2d`
implements `Bounded2d`.

For now, I went for `Capsule2d` for the sake of consistency and clarity.
Mathematically the more accurate term would be `Stadium` or `Pill` (see
[Wikipedia](https://en.wikipedia.org/wiki/Stadium_(geometry))), but
those might be less obvious to game devs. For reference, Godot has
[`CapsuleShape2D`](https://docs.godotengine.org/en/stable/classes/class_capsuleshape2d.html).
I can rename it if others think the geometrically correct name is better
though.

---

## Changelog

- Renamed `Capsule` to `Capsule3d`
- Added `Capsule2d` with `Bounded2d` implemented

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-29 17:52:04 +00:00
Joona Aalto
2bf481c03b
Add Meshable trait and implement meshing for 2D primitives (#11431)
# Objective

The first part of #10569, split up from #11007.

The goal is to implement meshing support for Bevy's new geometric
primitives, starting with 2D primitives. 3D meshing will be added in a
follow-up, and we can consider removing the old mesh shapes completely.

## Solution

Add a `Meshable` trait that primitives need to implement to support
meshing, as suggested by the
[RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/12-primitive-shapes.md#meshing).

```rust
/// A trait for shapes that can be turned into a [`Mesh`].
pub trait Meshable {
    /// The output of [`Self::mesh`]. This can either be a [`Mesh`]
    /// or a builder used for creating a [`Mesh`].
    type Output;

    /// Creates a [`Mesh`] for a shape.
    fn mesh(&self) -> Self::Output;
}
```

This PR implements it for the following primitives:

- `Circle`
- `Ellipse`
- `Rectangle`
- `RegularPolygon`
- `Triangle2d`

The `mesh` method typically returns a builder-like struct such as
`CircleMeshBuilder`. This is needed to support shape-specific
configuration for things like mesh resolution or UV configuration:

```rust
meshes.add(Circle { radius: 0.5 }.mesh().resolution(64));
```

Note that if no configuration is needed, you can even skip calling
`mesh` because `From<MyPrimitive>` is implemented for `Mesh`:

```rust
meshes.add(Circle { radius: 0.5 });
```

I also updated the `2d_shapes` example to use primitives, and tweaked
the colors to have better contrast against the dark background.

Before:

![Old 2D
shapes](https://github.com/bevyengine/bevy/assets/57632562/f1d8c2d5-55be-495f-8ed4-5890154b81ca)

After:

![New 2D
shapes](https://github.com/bevyengine/bevy/assets/57632562/f166c013-34b8-4752-800a-5517b284d978)

Here you can see the UVs and different facing directions: (taken from
#11007, so excuse the 3D primitives at the bottom left)

![UVs and facing
directions](https://github.com/bevyengine/bevy/assets/57632562/eaf0be4e-187d-4b6d-8fb8-c996ba295a8a)

---

## Changelog

- Added `bevy_render::mesh::primitives` module
- Added `Meshable` trait and implemented it for:
  - `Circle`
  - `Ellipse`
  - `Rectangle`
  - `RegularPolygon`
  - `Triangle2d`
- Implemented `Default` and `Copy` for several 2D primitives
- Updated `2d_shapes` example to use primitives
- Tweaked colors in `2d_shapes` example to have better contrast against
the (new-ish) dark background

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-29 16:47:47 +00:00
Joona Aalto
92567490a9
Add more constructors and math helpers for primitive shapes (#10632)
# Objective

Working towards finishing a part of #10572, this PR adds a ton of math
helpers and useful constructors for primitive shapes. I also tried
fixing some naming inconsistencies.

## Solution

- Add mathematical helpers like `area`, `volume`, `perimeter`,
`RegularPolygon::inradius` and so on, trying to cover all core
mathematical properties of each shape
- Add some constructors like `Rectangle::from_corners`,
`Cuboid::from_corners` and `Plane3d::from_points`

I also derived `PartialEq` for the shapes where it's trivial. Primitives
like `Line2d` and `Segment2d` are not trivial because you could argue
that they would be equal if they had an opposite direction.

All mathematical methods have tests with reference values computed by
hand or with external tools.

## Todo

- [x] Add tests to verify that the values from mathematical helpers are
correct

---------

Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-01-29 16:04:51 +00:00
NiseVoid
8851532890
Add RayTest2d and RayTest3d (#11310)
# Objective

Implement a raycast intersection test for bounding volumes

## Solution

- Implement RayTest2d and RayTest3d types

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-01-28 20:12:08 +00:00
NiseVoid
755917fe4b
Derive PartialEq, Serialize, Deserialize and Reflect on primitives (#11514)
# Objective

- Implement common traits on primitives

## Solution

- Derive PartialEq on types that were missing it.
- Derive Copy on small types that were missing it.
- Derive Serialize/Deserialize if the feature on bevy_math is enabled.
- Add a lot of cursed stuff to the bevy_reflect `impls` module.
2024-01-28 14:55:30 +00:00
Joona Aalto
dd4d07dc9c
Add new constructors for Circle and Sphere (#11526)
# Objective

Make APIs more consistent and ergonomic by adding a `new` constructor
for `Circle` and `Sphere`.

This could be seen as a redundant "trivial constructor", but in
practise, it seems valuable to me. I have lots of cases where formatting
becomes ugly because of the lack of a constructor, like this:

```rust
Circle {
    radius: self.radius(),
}
.contains_local_point(centered_pt)
```

With `new`, it'd be formatted much nicer:

```rust
Circle::new(self.radius()).contains_local_point(centered_pt)
```

Of course, this is just one example, but my circle/sphere definitions
very frequently span three or more lines when they could fit on one.

Adding `new` also increases consistency. `Ellipse` has `new` already,
and so does the mesh version of `Circle`.

## Solution

Add a `new` constructor for `Circle` and `Sphere`.
2024-01-26 16:00:59 +00:00
Joona Aalto
6a3b059db9
Implement bounding volume intersections (#11439)
# Objective

#10946 added bounding volume types and an `IntersectsVolume` trait, but
didn't actually implement intersections between bounding volumes.

This PR implements AABB-AABB, circle-circle / sphere-sphere, and
AABB-circle / AABB-sphere intersections.

## Solution

Implement `IntersectsVolume` for bounding volume pairs. I also added
`closest_point` methods to return the closest point on the surface /
inside of bounding volumes. This is used for AABB-circle / AABB-sphere
intersections.

---------

Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-01-22 17:55:59 +00:00
Doonv
0387331c12
Direction: Rename from_normalized to new_unchecked (#11425)
# Objective

`Direction2d::from_normalized` & `Direction3d::from_normalized` don't
emphasize that importance of the vector being normalized enough.

## Solution

Rename `from_normalized` to `new_unchecked` and add more documentation.

---

`Direction2d` and `Direction3d` were added somewhat recently in
https://github.com/bevyengine/bevy/pull/10466 (after 0.12), so I don't
think documenting the changelog and migration guide is necessary (Since
there is no major previous version to migrate from).

But here it is anyway in case it's needed:

## Changelog

- Renamed `Direction2d::from_normalized` and
`Direction3d::from_normalized` to `new_unchecked`.

## Migration Guide

- Renamed `Direction2d::from_normalized` and
`Direction3d::from_normalized` to `new_unchecked`.

---------

Co-authored-by: Tristan Guichaoua <33934311+tguichaoua@users.noreply.github.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-01-20 21:52:09 +00:00
Joona Aalto
c6f45831e9
Add geometric primitives to bevy_math::prelude (#11432)
# Objective

Currently, the `primitives` module is inside of the prelude for
`bevy_math`, but the actual primitives are not. This requires either
importing the shapes everywhere that uses them, or adding the
`primitives::` prefix:

```rust
let rectangle = meshes.add(primitives::Rectangle::new(5.0, 2.5));
```

(Note: meshing isn't actually implemented yet, but it's in #11431)

The primitives are meant to be used for a variety of tasks across
several crates, like for meshing, bounding volumes, gizmos, colliders,
and so on, so I think having them in the prelude is justified. It would
make several common tasks a lot more ergonomic.

```rust
let rectangle = meshes.add(Rectangle::new(5.0, 2.5));
```

## Solution

Add `primitives::*` to `bevy_math::prelude`.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-20 20:15:38 +00:00
Joona Aalto
c31f3aa128
Add Aabb2d::new and Aabb3d::new constructors (#11433)
# Objective

Currently, the only way to create an AABB is to specify its `min` and
`max` coordinates. However, it's often more useful to use the center and
half-size instead.

## Solution

Add `new` constructors for `Aabb2d` and `Aabb3d`.

This:

```rust
let aabb = Aabb3d {
    min: center - half_size,
    max: center + half_size,
}
```

becomes this:

```rust
let aabb = Aabb3d::new(center, half_size);
```

I also made the usage of "half-extents" vs. "half-size" a bit more
consistent.
2024-01-20 20:12:20 +00:00
Joona Aalto
b592a72916
Change Ellipse representation and improve helpers (#11435)
# Objective

Currently, the `Ellipse` primitive is represented by a `half_width` and
`half_height`. To improve consistency (similarly to #11434), it might
make more sense to use a `Vec2` `half_size` instead.

Alternatively, to make the elliptical nature clearer, the properties
could also be called `radius_x` and `radius_y`.

Secondly, `Ellipse::new` currently takes a *full* width and height
instead of two radii. I would expect it to take the half-width and
half-height because ellipses and circles are almost always defined using
radii. I wouldn't expect `Circle::new` to take a diameter (if we had
that method).

## Solution

Change `Ellipse` to store a `half_size` and `new` to take the half-width
and half-height.

I also added a `from_size` method similar to `Rectangle::from_size`, and
added the `semi_minor` and `semi_major` helpers to get the
semi-minor/major radius.
2024-01-20 18:04:53 +00:00
Joona Aalto
6337fb33ff
Improve Rectangle and Cuboid consistency (#11434)
# Objective

The `Rectangle` and `Cuboid` primitives currently use different
representations:

```rust
pub struct Rectangle {
    /// The half width of the rectangle
    pub half_width: f32,
    /// The half height of the rectangle
    pub half_height: f32,
}

pub struct Cuboid {
    /// Half of the width, height and depth of the cuboid
    pub half_extents: Vec3,
}
```

The property names and helpers are also inconsistent. `Cuboid` has
`half_extents`, but it also has a method called `from_size`. Most
existing code also uses "size" instead of "extents".

## Solution

Represent both `Rectangle` and `Cuboid` with `half_size` properties.
2024-01-20 18:03:47 +00:00
Joona Aalto
c62ad4b2c4
Implement bounding volumes for primitive shapes (#11336)
# Objective

Closes #10570.

#10946 added bounding volume types and traits, but didn't use them for
anything yet. This PR implements `Bounded2d` and `Bounded3d` for Bevy's
primitive shapes.

## Solution

Implement `Bounded2d` and `Bounded3d` for primitive shapes. This allows
computing AABBs and bounding circles/spheres for them.

For most shapes, there are several ways of implementing bounding
volumes. I took inspiration from [Parry's bounding
volumes](https://github.com/dimforge/parry/tree/master/src/bounding_volume),
[Inigo Quilez](http://iquilezles.org/articles/diskbbox/), and figured
out the rest myself using geometry. I tried to comment all slightly
non-trivial or unclear math to make it understandable.

Parry uses support mapping (finding the farthest point in some direction
for convex shapes) for some AABBs like cones, cylinders, and line
segments. This involves several quat operations and normalizations, so I
opted for the simpler and more efficient geometric approaches shown in
[Quilez's article](http://iquilezles.org/articles/diskbbox/).

Below you can see some of the bounding volumes working in 2D and 3D.
Note that I can't conveniently add these examples yet because they use
primitive shape meshing, which is still WIP.


https://github.com/bevyengine/bevy/assets/57632562/4465cbc6-285b-4c71-b62d-a2b3ee16f8b4


https://github.com/bevyengine/bevy/assets/57632562/94b4ac84-a092-46d7-b438-ce2e971496a4

---

## Changelog

- Implemented `Bounded2d`/`Bounded3d` for primitive shapes
- Added `from_point_cloud` method for bounding volumes (used by many
bounding implementations)
- Added `point_cloud_2d/3d_center` and `rotate_vec2` utility functions
- Added `RegularPolygon::vertices` method (used in regular polygon AABB
construction)
- Added `Triangle::circumcenter` method (used in triangle bounding
circle construction)
- Added bounding circle/sphere creation from AABBs and vice versa

## Extra

Do we want to implement `Bounded2d` for some "3D-ish" shapes too? For
example, capsules are sort of dimension-agnostic and useful for 2D, so I
think that would be good to implement. But a cylinder in 2D is just a
rectangle, and a cone is a triangle, so they wouldn't make as much sense
to me. A conical frustum would be an isosceles trapezoid, which could be
useful, but I'm not sure if computing the 2D AABB of a 3D frustum makes
semantic sense.
2024-01-18 15:55:36 +00:00
BD103
6f6269e195
Remove Default impl for CubicCurve (#11335)
# Objective

- Implementing `Default` for
[`CubicCurve`](https://docs.rs/bevy/latest/bevy/math/cubic_splines/struct.CubicCurve.html)
does not make sense because it cannot be mutated after creation.
- Closes #11209.
- Alternative to #11211.

## Solution

- Remove `Default` from `CubicCurve`'s derive statement.

Based off of @mockersf comment
(https://github.com/bevyengine/bevy/pull/11211#issuecomment-1880088036):

> CubicCurve can't be updated once created... I would prefer to remove
the Default impl as it doesn't make sense

---

## Changelog

- Removed the `Default` implementation for `CubicCurve`.

## Migration Guide

- Remove `CubicCurve` from any structs that implement `Default`.
- Wrap `CubicCurve` in a new type and provide your own default.

```rust
#[derive(Deref)]
struct MyCubicCurve<P: Point>(pub CubicCurve<P>);

impl Default for MyCubicCurve<Vec2> {
    fn default() -> Self {
        let points = [[
            vec2(-1.0, -20.0),
            vec2(3.0, 2.0),
            vec2(5.0, 3.0),
            vec2(9.0, 8.0),
        ]];

        Self(CubicBezier::new(points).to_curve())
    }
}
```
2024-01-14 04:40:37 +00:00
NiseVoid
c4e479a2d4
Implement bounding volume types (#10946)
# Objective

Implement bounding volume trait and the 4 types from
https://github.com/bevyengine/bevy/issues/10570. I will add intersection
tests in a future PR.

## Solution

Implement mostly everything as written in the issue, except:
- Intersection is no longer a method on the bounding volumes, but a
separate trait.
- I implemented a `visible_area` since it's the most common usecase to
care about the surface that could collide with cast rays.
  - Maybe we want both?

---

## Changelog

- Added bounding volume types to bevy_math

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-01-10 23:18:51 +00:00
irate
ec14e946b8
Update glam, encase and hexasphere (#11082)
Update to `glam` 0.25, `encase` 0.7 and `hexasphere` to 10.0

## Changelog
Added the `FloatExt` trait to the `bevy_math` prelude which adds `lerp`,
`inverse_lerp` and `remap` methods to the `f32` and `f64` types.
2024-01-08 22:58:45 +00:00
Joona Aalto
bcbb7bb9dd
Add new_and_length method to Direction2d and Direction3d (#11172)
# Objective

When creating a normalized direction from a vector, it can be useful to
get both the direction *and* the original length of the vector.

This came up when I was recreating some Parry APIs using bevy_math, and
doing it manually is quite painful. Nalgebra calls this method
[`Unit::try_new_and_get`](https://docs.rs/nalgebra/latest/nalgebra/base/struct.Unit.html#method.try_new_and_get).

## Solution

Add a `new_and_length` method to `Direction2d` and `Direction3d`.

Usage:

```rust
if let Ok((direction, length)) = Direction2d::new_and_length(Vec2::X * 10.0) {
    assert_eq!(direction, Vec2::X);
    assert_eq!(length, 10.0);
}
```

I'm open to different names, couldn't come up with a perfectly clear one
that isn't too long. My reasoning with the current name is that it's
like using `new` and calling `length` on the original vector.
2024-01-08 22:36:56 +00:00
Joona Aalto
0349809420
Add libm feature to bevy_math (#11238)
# Objective

Different platforms use their own implementations of several
mathematical functions (especially transcendental functions like sin,
cos, tan, atan, and so on) to provide hardware-level optimization using
intrinsics. This is good for performance, but bad when you expect
consistent outputs across machines.

[`libm`](https://github.com/rust-lang/libm) is a widely used crate that
provides mathematical functions that don't use intrinsics like `std`
functions. This allows bit-for-bit deterministic math across hardware,
which is crucial for things like cross-platform deterministic physics
simulation.

Glam has the `libm` feature for using [`libm` for the
math](d2871a151b/src/f32/math.rs (L35))
in its own types. This would be nice to expose as a feature in
`bevy_math`.

## Solution

Add `libm` feature to `bevy_math`. We could name it something like
`enhanced-determinism`, but this wouldn't be accurate for the rest of
Bevy, so I think just `libm` is more fitting and explicit.
2024-01-06 22:01:57 +00:00
Joona Aalto
536a7bd810
Add approx feature to bevy_math (#11176)
# Objective

`bevy_math` re-exports Glam, but doesn't have a feature for enabling
`approx` for it. Many projects (including some of Bevy's own crates)
need `approx`, and it'd be nice if you didn't have to manually add Glam
to specify the feature for it.

## Solution

Add an `approx` feature to `bevy_math`.
2024-01-02 18:10:44 +00:00
Joona Aalto
2c5439b25e
Add constants for Direction2d and Direction3d (#11180)
# Objective

I often need a direction along one of the cartesian XYZ axes, and it
currently requires e.g. `Direction2d::from_normalized(Vec2::X)`, which
isn't ideal.

## Solution

Add direction constants that are the same as the ones on Glam types. I
also copied the doc comment format "A unit vector pointing along the ...
axis", but I can change it if there's a better wording for directions.
2024-01-02 17:00:23 +00:00
Joona Aalto
6086d4193e
Implement Neg for Direction2d and Direction3d (#11179)
# Objective

I frequently encounter cases where I need to get the opposite direction.
This currently requires something like
`Direction2d::from_normalized(-*direction)`, which is very inconvenient.

## Solution

Implement `Neg` for `Direction2d` and `Direction3d`.
2024-01-02 16:46:03 +00:00
Doonv
189ceaf0d3
Replace or document ignored doctests (#11040)
# Objective

There are a lot of doctests that are `ignore`d for no documented reason.
And that should be fixed.

## Solution

I searched the bevy repo with the regex ` ```[a-z,]*ignore ` in order to
find all `ignore`d doctests. For each one of the `ignore`d doctests, I
did the following steps:
1. Attempt to remove the `ignored` attribute while still passing the
test. I did this by adding hidden dummy structs and imports.
2. If step 1 doesn't work, attempt to replace the `ignored` attribute
with the `no_run` attribute while still passing the test.
3. If step 2 doesn't work, keep the `ignored` attribute but add
documentation for why the `ignored` attribute was added.

---------

Co-authored-by: François <mockersf@gmail.com>
2024-01-01 16:50:56 +00:00
Olle Lukowski
6b9cd57956
Introduce AspectRatio struct (#10368)
# Objective

- Fix an inconsistency in the calculation of aspect ratio's. 
- Fixes #10288 

## Solution

- Created an intermediate `AspectRatio` struct, as suggested in the
issue. This is currently just used in any places where aspect ratio
calculations happen, to prevent doing it wrong. In my and @mamekoro 's
opinion, it would be better if this was used instead of a normal `f32`
in various places, but I didn't want to make too many changes to begin
with.

## Migration Guide
- Anywhere where you are currently expecting a f32 when getting aspect
ratios, you will now receive a `AspectRatio` struct. this still holds
the same value.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2023-12-17 02:01:26 +00:00
Tygyh
645625b789
Replace deprecated elements (#10999)
# Objective

- Replace deprecated elements.

## Solution

- Remove 'std::' from constants.
2023-12-16 23:24:49 +00:00
Joona Aalto
029dd06f7d
Add Direction2d::from_xy and Direction3d::from_xyz (#10882)
# Objective

Make direction construction a bit more ergonomic.

## Solution

Add `Direction2d::from_xy` and `Direction3d::from_xyz`, similar to
`Transform::from_xyz`:

```rust
let dir2 = Direction2d::from_xy(0.5, 0.5).unwrap();
let dir3 = Direction3d::from_xyz(0.5, 0.5, 0.5).unwrap();
```

This can be a bit cleaner than using `new`:

```rust
let dir2 = Direction2d::new(Vec2::new(0.5, 0.5)).unwrap();
let dir3 = Direction3d::new(Vec3::new(0.5, 0.5, 0.5)).unwrap();
```
2023-12-14 14:56:07 +00:00
Joona Aalto
d9aac887b5
Split Ray into Ray2d and Ray3d and simplify plane construction (#10856)
# Objective

A better alternative version of #10843.

Currently, Bevy has a single `Ray` struct for 3D. To allow better
interoperability with Bevy's primitive shapes (#10572) and some third
party crates (that handle e.g. spatial queries), it would be very useful
to have separate versions for 2D and 3D respectively.

## Solution

Separate `Ray` into `Ray2d` and `Ray3d`. These new structs also take
advantage of the new primitives by using `Direction2d`/`Direction3d` for
the direction:

```rust
pub struct Ray2d {
    pub origin: Vec2,
    pub direction: Direction2d,
}

pub struct Ray3d {
    pub origin: Vec3,
    pub direction: Direction3d,
}
```

and by using `Plane2d`/`Plane3d` in `intersect_plane`:

```rust
impl Ray2d {
    // ...
    pub fn intersect_plane(&self, plane_origin: Vec2, plane: Plane2d) -> Option<f32> {
        // ...
    }
}
```

---

## Changelog

### Added

- `Ray2d` and `Ray3d`
- `Ray2d::new` and `Ray3d::new` constructors
- `Plane2d::new` and `Plane3d::new` constructors

### Removed

- Removed `Ray` in favor of `Ray3d`

### Changed

- `direction` is now a `Direction2d`/`Direction3d` instead of a vector,
which provides guaranteed normalization
- `intersect_plane` now takes a `Plane2d`/`Plane3d` instead of just a
vector for the plane normal
- `Direction2d` and `Direction3d` now derive `Serialize` and
`Deserialize` to preserve ray (de)serialization

## Migration Guide

`Ray` has been renamed to `Ray3d`.

### Ray creation

Before:

```rust
Ray {
    origin: Vec3::ZERO,
    direction: Vec3::new(0.5, 0.6, 0.2).normalize(),
}
```

After:

```rust
// Option 1:
Ray3d {
    origin: Vec3::ZERO,
    direction: Direction3d::new(Vec3::new(0.5, 0.6, 0.2)).unwrap(),
}

// Option 2:
Ray3d::new(Vec3::ZERO, Vec3::new(0.5, 0.6, 0.2))
```

### Plane intersections

Before:

```rust
let result = ray.intersect_plane(Vec2::X, Vec2::Y);
```

After:

```rust
let result = ray.intersect_plane(Vec2::X, Plane2d::new(Vec2::Y));
```
2023-12-06 14:09:04 +00:00
Joona Aalto
f683b802f1
Impl TryFrom vector for directions and add InvalidDirectionError (#10884)
# Objective

Implement `TryFrom<Vec2>`/`TryFrom<Vec3>` for direction primitives as
considered in #10857.

## Solution

Implement `TryFrom` for the direction primitives.

These are all equivalent:

```rust
let dir2d = Direction2d::try_from(Vec2::new(0.5, 0.5)).unwrap();
let dir2d = Vec2::new(0.5, 0.5).try_into().unwrap(); // (assumes that the type is inferred)
let dir2d = Direction2d::new(Vec2::new(0.5, 0.5)).unwrap();
```

For error cases, an `Err(InvalidDirectionError)` is returned. It
contains the type of failure:

```rust
/// An error indicating that a direction is invalid.
#[derive(Debug, PartialEq)]
pub enum InvalidDirectionError {
    /// The length of the direction vector is zero or very close to zero.
    Zero,
    /// The length of the direction vector is `std::f32::INFINITY`.
    Infinite,
    /// The length of the direction vector is `NaN`.
    NaN,
}
```
2023-12-06 00:05:37 +00:00
irate
83ee6de1da
Remove From implementations from the direction types (#10857)
This removes the `From<Vec2/3>` implementations for the direction types.
It doesn't seem right to have when it only works if the vector is
nonzero and finite and produces NaN otherwise.

Added `Direction2d/3d::new` which uses `Vec2/3::try_normalize` to
guarantee it returns either a valid direction or `None`.

This should make it impossible to create an invalid direction, which I
think was the intention with these types.
2023-12-05 02:44:27 +00:00