Commit Graph

75 Commits

Author SHA1 Message Date
Gino Valente
9b32e09551
bevy_reflect: Add clone registrations project-wide (#18307)
# Objective

Now that #13432 has been merged, it's important we update our reflected
types to properly opt into this feature. If we do not, then this could
cause issues for users downstream who want to make use of
reflection-based cloning.

## Solution

This PR is broken into 4 commits:

1. Add `#[reflect(Clone)]` on all types marked `#[reflect(opaque)]` that
are also `Clone`. This is mandatory as these types would otherwise cause
the cloning operation to fail for any type that contains it at any
depth.
2. Update the reflection example to suggest adding `#[reflect(Clone)]`
on opaque types.
3. Add `#[reflect(clone)]` attributes on all fields marked
`#[reflect(ignore)]` that are also `Clone`. This prevents the ignored
field from causing the cloning operation to fail.
   
Note that some of the types that contain these fields are also `Clone`,
and thus can be marked `#[reflect(Clone)]`. This makes the
`#[reflect(clone)]` attribute redundant. However, I think it's safer to
keep it marked in the case that the `Clone` impl/derive is ever removed.
I'm open to removing them, though, if people disagree.
4. Finally, I added `#[reflect(Clone)]` on all types that are also
`Clone`. While not strictly necessary, it enables us to reduce the
generated output since we can just call `Clone::clone` directly instead
of calling `PartialReflect::reflect_clone` on each variant/field. It
also means we benefit from any optimizations or customizations made in
the `Clone` impl, including directly dereferencing `Copy` values and
increasing reference counters.

Along with that change I also took the liberty of adding any missing
registrations that I saw could be applied to the type as well, such as
`Default`, `PartialEq`, and `Hash`. There were hundreds of these to
edit, though, so it's possible I missed quite a few.

That last commit is **_massive_**. There were nearly 700 types to
update. So it's recommended to review the first three before moving onto
that last one.

Additionally, I can break the last commit off into its own PR or into
smaller PRs, but I figured this would be the easiest way of doing it
(and in a timely manner since I unfortunately don't have as much time as
I used to for code contributions).

## Testing

You can test locally with a `cargo check`:

```
cargo check --workspace --all-features
```
2025-03-17 18:32:35 +00:00
Joona Aalto
9f6d628c48
Improve Segment2d/Segment3d API and docs (#18206)
# Objective

#17404 reworked the `Segment2d` and `Segment3d` types to be defined by
two endpoints rather than a direction and half-length. However, the API
is still very minimal and limited, and documentation is inconsistent and
outdated.

## Solution

Add the following helper methods for `Segment2d` and `Segment3d`:

- `from_scaled_direction`
- `from_ray_and_length`
- `length_squared`
- `direction`
- `try_direction`
- `scaled_direction`
- `transformed`
- `reversed`

`Segment2d` has a few 2D-specific methods:

- `left_normal`
- `try_left_normal`
- `scaled_left_normal`
- `right_normal`
- `try_right_normal`
- `scaled_right_normal`

There are now also `From` implementations for converting `[Vec2; 2]` and
`(Vec2, Vec2)` to a `Segment2d`, and similarly for 3D.

I have also updated documentation to be more accurate and consistent,
and simplified a few methods.

---

## Prior Art

Parry's
[`Segment`](https://docs.rs/parry2d/latest/parry2d/shape/struct.Segment.html)
type has a lot of similar methods, though my implementation is a bit
more comprehensive. A lot of these methods can be useful for various
geometry algorithms.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Greeble <166992735+greeble-dev@users.noreply.github.com>
2025-03-09 20:21:31 +00:00
Sigma-dev
7c8da1c05d
Reworked Segment types into their cartesian forms (#17404)
# Objective

Segment2d and Segment3d are currently hard to work with because unlike
many other primary shapes, they are bound to the origin.
The objective of this PR is to allow these segments to exist anywhere in
cartesian space, making them much more useful in a variety of contexts.

## Solution

Reworking the existing segment type's internal fields and methods to
allow them to exist anywhere in cartesian space.
I have done both reworks for 2d and 3d segments but I was unsure if I
should just have it all here or not so feel free to tell me how I should
proceed, for now I have only pushed Segment2d changes.

As I am not a very seasoned contributor, this first implementation is
very likely sloppy and will need some additional work from my end, I am
open to all criticisms and willing to work to get this to bevy's
standards.

## Testing

I am not very familiar with the standards of testing. Of course my
changes had to pass the thorough existing tests for primitive shapes.
I also checked the gizmo 2d shapes intersection example and everything
looked fine.

I did add a few utility methods to the types that have no tests yet. I
am willing to implement some if it is deemed necessary

## Migration Guide

The segment type constructors changed so if someone previously created a
Segment2d with a direction and length they would now need to use the
`from_direction` constructor

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2025-01-19 03:54:45 +00:00
Rob Parrett
651b22f31f
Update typos (#17126)
# Objective

Use the latest version of `typos` and fix the typos that it now detects

# Additional Info

By the way, `typos` has a "low priority typo suggestions issue" where we
can throw typos we find that `typos` doesn't catch.

(This link may go stale) https://github.com/crate-ci/typos/issues/1200
2025-01-03 17:44:26 +00:00
Zachary Harrold
5f42c9ab6d
Fix no_std CI Warnings and WASM Compatibility (#17049)
# Objective

- Resolve several warnings encountered when compiling for `no_std`
around `dead_code`
- Fix compatibility with `wasm32-unknown-unknown` when using `no_std`
(identified by Sachymetsu on
[Discord](https://discord.com/channels/691052431525675048/692572690833473578/1323365426901549097))

## Solution

- Removed some unused imports
- Added `allow(dead_code)` for certain private items when compiling on
`no_std`
- Fixed `bevy_app` and `bevy_tasks` compatibility with WASM when
compiling without `std` by appropriately importing `Box` and feature
gating panic unwinding

## Testing

- CI
2024-12-30 23:01:27 +00:00
Vic
b78efd339d
Simplify sort/max_by calls (#17048)
# Objective

Some sort calls and `Ord` impls are unnecessarily complex.

## Solution

Rewrite the "match on cmp, if equal do another cmp" as either a
comparison on tuples, or `Ordering::then_with`, depending on whether the
compare keys need construction.

`sort_by` -> `sort_by_key` when symmetrical. Do the same for
`min_by`/`max_by`.

Note that `total_cmp` can only work with `sort_by`, and not on tuples.

When sorting collected query results that contain
`Entity`/`MainEntity`/`RenderEntity` in their `QueryData`, with that
`Entity` in the sort key:
stable -> unstable sort (all queried entities are unique)

If key construction is not simple, switch to `sort_by_cached_key` when
possible.

Sorts that are only performed to discover the maximal element are
replaced by `max_by_key`.

Dedicated comparison functions and structs are removed where simple.

Derive `PartialOrd`/`Ord` when useful.

Misc. closure style inconsistencies.

## Testing
- Existing tests.
2024-12-30 22:59:36 +00:00
Patrick Walton
bb090e6176
Feature gate is_polygon_simple behind the alloc feature. (#16739)
CI was failing because `bevy_math` no longer compiled with `libcore`.
This was due to PR #15981. This commit fixes the issue by moving the
applicable functionality behind `#[cfg(feature = "alloc")]`.
2024-12-10 07:45:02 +00:00
Lynn
fcaa271693
Polygon simplicity (#15981)
# Objective

- This PR adds the ability to determine whether a `Polygon<N>` or
`BoxedPolygon` is simple (aka. not self-intersecting) by calling
`my_polygon.is_simple()`.
- This may be useful information for users to determine whether their
polygons are 'valid' and will be useful when adding meshing for
polygons.
  - As such this is a step towards fixing #15255

## Solution

- Implemented the Shamos-Hoey algorithm in its own module `polygon`.

## Testing

- Tests are included, and can be verified visually.

---

## Performance

- The Shamos-Hoey algorithm runs in O(n * log n)
- In reality, the results look more linear to me.
- Determining simplicity for a simple polygon (the worst case) with less
than 100 vertices takes less than 0.2ms.


![image](https://github.com/user-attachments/assets/23c62234-abdc-4710-a3b4-feaad5929133)
2024-12-10 02:02:12 +00:00
homersimpsons
a6b5f80715
⬆️ Upgrade typos and its configuration (#16712)
# Objective

Fixes #16610, related to #16702

## Solution

Upgrade typos and its configuration

## Testing

- Did you test these changes? If so, how? No
- Are there any parts that need more testing? No
- How can other people (reviewers) test your changes? Is there anything
specific they need to know? No
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test? Not applicable
2024-12-08 17:25:10 +00:00
Zachary Harrold
a6adced9ed
Deny derive_more error feature and replace it with thiserror (#16684)
# Objective

- Remove `derive_more`'s error derivation and replace it with
`thiserror`

## Solution

- Added `derive_more`'s `error` feature to `deny.toml` to prevent it
sneaking back in.
- Reverted to `thiserror` error derivation

## Notes

Merge conflicts were too numerous to revert the individual changes, so
this reversion was done manually. Please scrutinise carefully during
review.
2024-12-06 17:03:55 +00:00
Zachary Harrold
a8b9c945c7
Add no_std Support to bevy_math (#15810)
# Objective

- Contributes to #15460

## Solution

- Added two new features, `std` (default) and `alloc`, gating `std` and
`alloc` behind them respectively.
- Added missing `f32` functions to `std_ops` as required. These `f32`
methods have been added to the `clippy.toml` deny list to aid in
`no_std` development.

## Testing

- CI
- `cargo clippy -p bevy_math --no-default-features --features libm
--target "x86_64-unknown-none"`
- `cargo test -p bevy_math --no-default-features --features libm`
- `cargo test -p bevy_math --no-default-features --features "libm,
alloc"`
- `cargo test -p bevy_math --no-default-features --features "libm,
alloc, std"`
- `cargo test -p bevy_math --no-default-features --features "std"`

## Notes

The following items require the `alloc` feature to be enabled:

- `CubicBSpline`
- `CubicBezier`
- `CubicCardinalSpline`
- `CubicCurve`
- `CubicGenerator`
- `CubicHermite`
- `CubicNurbs`
- `CyclicCubicGenerator`
- `RationalCurve`
- `RationalGenerator`
- `BoxedPolygon`
- `BoxedPolyline2d`
- `BoxedPolyline3d`
- `SampleCurve`
- `SampleAutoCurve`
- `UnevenSampleCurve`
- `UnevenSampleAutoCurve`
- `EvenCore`
- `UnevenCore`
- `ChunkedUnevenCore`

This requirement could be relaxed in certain cases, but I had erred on
the side of gating rather than modifying. Since `no_std` is a new set of
platforms we are adding support to, and the `alloc` feature is enabled
by default, this is not a breaking change.

---------

Co-authored-by: Benjamin Brienen <benjamin.brienen@outlook.com>
Co-authored-by: Matty <2975848+mweatherley@users.noreply.github.com>
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
2024-12-03 17:14:51 +00:00
Lynn
52b8b55c2d
Implement Measured2d for Arc2d-based primitives. (#16213)
# Objective

- `CircularSegment` and `CircularSector` are well defined 2D shapes with
both an area and a perimeter.

# Solution

- This PR implements `perimeter` for both and moves the existsing `area`
functions into the `Measured2d` implementations.

## Testing

- The `arc_tests` have been extended to also check for perimeters.
2024-11-03 16:12:31 +00:00
Lynn
b4e04f9d9f
Remove write access to ConvexPolygon.vertices (#15965)
# Objective

- Fixes #15963

## Solution

- Implement `TryFrom<Polygon<N> for ConvexPolygon<N>`
- Implement `From<ConvexPolygon<N>> for Polygon<N>`
- Remove `pub` from `vertices`
- Add `ConvexPolygon::vertices()` to get read only access to the
vertices of a convex polygon.
2024-10-16 22:21:01 +00:00
Zachary Harrold
9366b95006
Remove thiserror from bevy_math (#15769)
# Objective

- Contributes to #15460

## Solution

- Removed `thiserror` from `bevy_math`
2024-10-09 14:23:23 +00:00
Joona Aalto
21b78b5990
Implement From translation and rotation for isometries (#15733)
# Objective

Several of our APIs (namely gizmos and bounding) use isometries on
current Bevy main. This is nicer than separate properties in a lot of
cases, but users have still expressed usability concerns.

One problem is that in a lot of cases, you only care about e.g.
translation, so you end up with this:

```rust
gizmos.cross_2d(
    Isometry2d::from_translation(Vec2::new(-160.0, 120.0)),
    12.0,
    FUCHSIA,
);
```

The isometry adds quite a lot of length and verbosity, and isn't really
that relevant since only the translation is important here.

It would be nice if you could use the translation directly, and only
supply an isometry if both translation and rotation are needed. This
would make the following possible:

```rust
gizmos.cross_2d(Vec2::new(-160.0, 120.0), 12.0, FUCHSIA);
```

removing a lot of verbosity.

## Solution

Implement `From<Vec2>` and `From<Rot2>` for `Isometry2d`, and
`From<Vec3>`, `From<Vec3A>`, and `From<Quat>` for `Isometry3d`. These
are lossless conversions that fit the semantics of `From`.

This makes the proposed API possible! The methods must now simply take
an `impl Into<IsometryNd>`, and this works:

```rust
gizmos.cross_2d(Vec2::new(-160.0, 120.0), 12.0, FUCHSIA);
```
2024-10-08 16:09:28 +00:00
Tomi Fontanilles
3d8e56f766
introduction of ConvexPolygon and ConvexPolygonMeshBuilder (#15544)
# Objective

- As discussed on
[Discord](https://discord.com/channels/691052431525675048/1203087353850364004/1285300659746246849),
implement a `ConvexPolygon` 2D math primitive and associated mesh
builder.
- The original goal was to have a mesh builder for the simplest (i.e.
convex) polygons.

## Solution

- The `ConvexPolygon` is created from its vertices.
- The convexity of the polygon is checked when created via `new()` by
verifying that the winding order of all the triangles formed with
adjacent vertices is the same.
- The `ConvexPolygonMeshBuilder` uses an anchor vertex and goes through
every adjacent pair of vertices in the polygon to form triangles that
fill up the polygon.

## Testing

- Tested locally with my own simple `ConvexPolygonMeshBuilder` usage.
2024-10-08 15:02:38 +00:00
TheBigCheese
01dce4742f
Add to_inner_rectangle, area and perimeter methods to Capsule2d (#15388)
# Objective

Unlike `Capsule3d` which has the `.to_cylinder` method, `Capsule2d`
doesn't have an equivalent `.to_inner_rectangle` method and as shown by
#15191 this is surprisingly easy to get wrong

## Solution

Implemented a `Capsule2d::to_inner_rectangle` method as it is
implemented in the fixed `Capsule2d` shape sampling, and as I was adding
tests I noticed `Capsule2d` didn't implement `Measure2d` so I did this
as well.

## Changelog
### Added
- `Capsule2d::to_inner_rectangle`, `Capsule2d::area` and
`Capsule2d::perimeter`

---------

Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
Co-authored-by: James Liu <contact@jamessliu.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
2024-09-30 18:44:49 +00:00
Zachary Harrold
d70595b667
Add core and alloc over std Lints (#15281)
# Objective

- Fixes #6370
- Closes #6581

## Solution

- Added the following lints to the workspace:
  - `std_instead_of_core`
  - `std_instead_of_alloc`
  - `alloc_instead_of_core`
- Used `cargo +nightly fmt` with [item level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Item%5C%3A)
to split all `use` statements into single items.
- Used `cargo clippy --workspace --all-targets --all-features --fix
--allow-dirty` to _attempt_ to resolve the new linting issues, and
intervened where the lint was unable to resolve the issue automatically
(usually due to needing an `extern crate alloc;` statement in a crate
root).
- Manually removed certain uses of `std` where negative feature gating
prevented `--all-features` from finding the offending uses.
- Used `cargo +nightly fmt` with [crate level use
formatting](https://rust-lang.github.io/rustfmt/?version=v1.6.0&search=#Crate%5C%3A)
to re-merge all `use` statements matching Bevy's previous styling.
- Manually fixed cases where the `fmt` tool could not re-merge `use`
statements due to conditional compilation attributes.

## Testing

- Ran CI locally

## Migration Guide

The MSRV is now 1.81. Please update to this version or higher.

## Notes

- This is a _massive_ change to try and push through, which is why I've
outlined the semi-automatic steps I used to create this PR, in case this
fails and someone else tries again in the future.
- Making this change has no impact on user code, but does mean Bevy
contributors will be warned to use `core` and `alloc` instead of `std`
where possible.
- This lint is a critical first step towards investigating `no_std`
options for Bevy.

---------

Co-authored-by: François Mockers <francois.mockers@vleue.com>
2024-09-27 00:59:59 +00:00
EdJoPaTo
938d810766
Apply unused_qualifications lint (#14828)
# Objective

Fixes #14782

## Solution

Enable the lint and fix all upcoming hints (`--fix`). Also tried to
figure out the false-positive (see review comment). Maybe split this PR
up into multiple parts where only the last one enables the lint, so some
can already be merged resulting in less many files touched / less
potential for merge conflicts?

Currently, there are some cases where it might be easier to read the
code with the qualifier, so perhaps remove the import of it and adapt
its cases? In the current stage it's just a plain adoption of the
suggestions in order to have a base to discuss.

## Testing

`cargo clippy` and `cargo run -p ci` are happy.
2024-08-21 12:29:33 +00:00
Robert Walter
d2fa55db6b
New utility methods on InfinitePlane3d (#14651)
# Objective

Some algorithms don't really work well or are not efficient in 3D space.
When we know we have points on an `InfinitePlane3d` it would be helpful
to have some utility methods to reversibly transform points on the plane
to 2D space to apply some algorithms there.

## Solution

This PR adds a few of methods to project 3D points on a plane to 2D
points and inject them back. Additionally there are some other small
common helper methods.

## Testing

- added some tests that cover the new methods

---------

Co-authored-by: Matty <weatherleymatthew@gmail.com>
2024-08-19 21:36:18 +00:00
Matty
61a1530c56
Make bevy_math's libm feature use libm for all f32methods with unspecified precision (#14693)
# Objective

Closes #14474

Previously, the `libm` feature of bevy_math would just pass the same
feature flag down to glam. However, bevy_math itself had many uses of
floating-point arithmetic with unspecified precision. For example,
`f32::sin_cos` and `f32::powi` have unspecified precision, which means
that the exact details of their output are not guaranteed to be stable
across different systems and/or versions of Rust. This means that users
of bevy_math could observe slightly different behavior on different
systems if these methods were used.

The goal of this PR is to make it so that the `libm` feature flag
actually guarantees some degree of determinacy within bevy_math itself
by switching to the libm versions of these functions when the `libm`
feature is enabled.

## Solution

bevy_math now has an internal module `bevy_math::ops`, which re-exports
either the standard versions of the operations or the libm versions
depending on whether the `libm` feature is enabled. For example,
`ops::sin` compiles to `f32::sin` without the `libm` feature and to
`libm::sinf` with it.

This approach has a small shortfall, which is that `f32::powi` (integer
powers of floating point numbers) does not have an equivalent in `libm`.
On the other hand, this method is only used for squaring and cubing
numbers in bevy_math. Accordingly, this deficit is covered by the
introduction of a trait `ops::FloatPow`:
```rust
pub(crate) trait FloatPow {
    fn squared(self) -> Self;
    fn cubed(self) -> Self;
}
```

Next, each current usage of the unspecified-precision methods has been
replaced by its equivalent in `ops`, so that when `libm` is enabled, the
libm version is used instead. The exception, of course, is that
`.powi(2)`/`.powi(3)` have been replaced with `.squared()`/`.cubed()`.

Finally, the usage of the plain `f32` methods with unspecified precision
is now linted out of bevy_math (and hence disallowed in CI). For
example, using `f32::sin` within bevy_math produces a warning that tells
the user to use the `ops::sin` version instead.

## Testing

Ran existing tests. It would be nice to check some benchmarks on NURBS
things once #14677 merges. I'm happy to wait until then if the rest of
this PR is fine.

---

## Discussion

In the future, it might make sense to actually expose `bevy_math::ops`
as public if any downstream Bevy crates want to provide similar
determinacy guarantees. For now, it's all just `pub(crate)`.

This PR also only covers `f32`. If we find ourselves using `f64`
internally in parts of bevy_math for better robustness, we could extend
the module and lints to cover the `f64` versions easily enough.

I don't know how feasible it is, but it would also be nice if we could
standardize the bevy_math tests with the `libm` feature in CI, since
their success is currently platform-dependent (e.g. 8 of them fail on my
machine when run locally).

---------

Co-authored-by: IQuick 143 <IQuick143cz@gmail.com>
2024-08-12 16:13:36 +00:00
Steve Frampton
0e13b1ca5e
Added new method to Cone 3D primitive (#14325)
Reference to #14299.

# Objective
- Ensuring consistent practice of instantiating 3D primitive shapes in
Bevy.

## Solution

- Add `new` method, containing `radius` and `height` arguments, to Cone
3D primitive shape.

## Testing

- Instantiated cone using same values (radius is `2.` and height is
`5.`), using the current method and the added `new` method.
- Basic setup of Bevy Default Plugins and `3DCameraBundle`.


---

## Showcase

<details>
  <summary>Click to view showcase</summary>

```rust
use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .run();
}

fn setup(
    mut commands: Commands,
    mut meshes: ResMut<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    let new_cone = meshes.add(Cone::new(2., 5.));
    commands.spawn(PbrBundle {
        mesh: new_cone,
        ..default()
    });

    let old_cone = meshes.add(Cone {
        radius: 2.,
        height: 5.,
    });
    commands.spawn(PbrBundle {
        mesh: old_cone,
        material: materials.add(Color::WHITE),
        transform: Transform::from_xyz(10., 0., 0.),
        ..default()
    });

    commands.spawn(Camera3dBundle {
        transform: Transform::from_xyz(20., 20., 20.).looking_at(Vec3::ZERO, Dir3::Y),
        ..default()
    });
}
```

</details>


![image](https://github.com/user-attachments/assets/267f8124-8734-4c20-8840-fcf35375a778)


- Pink Cone is created using the `new` method.
- Black Cone is created using the existing method.

## Migration Guide
- Addition of `new` method to the 3D primitive Cone struct.
2024-07-16 12:59:26 +00:00
Octorine
dcb191bb18
Updated descriptions for some geometric primitives to include more detail (#13937)
This is an attempt to address issue #13725, which was about the
geometric primitives in the bevy_math crate lacking some detail in the
docs.

# Objective

Fixes #13725

## Solution

Added details to the docstrings. Mostly this consisted of specifying
that the primitives are centered on the origin, or describing how
they're defined (e.g., a circle is the set of all points some distance
from the origin).

## Testing

No testing, since the only changes were to docs.
2024-06-20 12:16:27 +00:00
NiseVoid
524dce7505
Use a well defined type for sides in RegularPolygon (#13837)
# Objective

- Primitives should not use poorly defined types like `usize`,
especially since they are serializable

## Solution

- Use `u32` instead of `usize`
- The generic array types do not need to be changed because this size is
not actually stored or serialized anywhere

---

## Migration Guide

- `RegularPolygon` now uses `u32` instead of `usize` for the number of
sides
2024-06-19 15:43:40 +00:00
Lynn
4e72bf4751
Clarify cone position (#13568)
# Objective

- Fixes #10616

## Solution

- Added docs describing the center as being the midpoint between the tip
and the center of its base.
2024-05-29 20:19:58 +00:00
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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