Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide feature parity for Quaternion with Godot #981

Merged
merged 1 commit into from
Dec 22, 2024

Conversation

fpdotmonkey
Copy link
Contributor

More notable change is the renaming with deprecations for a couple methods. The new names are what Godot uses.

@GodotRust
Copy link

API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-981

@Bromeon Bromeon added feature Adds functionality to the library c: core Core components c: engine Godot classes (nodes, resources, ...) labels Dec 18, 2024
Copy link
Member

@Bromeon Bromeon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot!

Comment on lines 67 to 88
/// Constructs a Quaternion representing the shortest arc between `arc_from` and `arc_to`.
///
/// These can be imagined as two points intersecting a unit sphere's surface, with a radius of 1.0.
///
// This is an undocumented assumption of Godot's as well.
/// The inputs must be unit vectors.
///
/// For near-singular cases (`arc_from`≈`arc_to` or `arc_from`≈-`arc_to`) the current implementation is only accurate to about
/// 0.001, or better if `double-precision` is enabled.
///
/// *Godot equivalent: `Quaternion(arc_from: Vector3, arc_to: Vector3)`*
pub fn from_rotation_arc(arc_to: Vector3, arc_from: Vector3) -> Self {
<Self as GlamConv>::Glam::from_rotation_arc(arc_to.to_glam(), arc_from.to_glam()).to_front()
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find the to, from order confusing; it's also inconsistent with Godot's own constructor:

image

glam is still an implementation detail in our library, so we shouldn't take its conventions at face value.


Should we check preconditions such as "unit vectors" via debug_assert?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sorry I missed that order. Emulating Godot was my intention, just missed that bit.

Debug asserts could be good; I didn't add anything like that since Godot doesn't. Glam also has a feature for this kind of debug assert, so it might be possible to enable glam_assert for debug builds and gain these kinds of assertions for free (though then would the error messages be any good?)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd probably do our own asserts, then we're more in control -- and conditions for Godot are sometimes also different.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, done.

Comment on lines 142 to 154
pub fn get_euler(self, order: EulerOrder) -> Vector3 {
Basis::from_quat(self).to_euler(order)
}

#[deprecated = "Moved to `Quaternion::get_euler()`"]
pub fn to_euler(self, order: EulerOrder) -> Vector3 {
self.get_euler(order)
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to_euler was a deliberate choice, see #124 (review). As such I would keep it.

It could however benefit from a doc-alias.

Comment on lines 345 to 349
impl From<Basis> for Quaternion {
fn from(basis: Basis) -> Self {
basis.to_quat()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is necessary, given we already have Basis::to_quat.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this does give the user more control, this provides both Quaternion::from or basis.into() too. Depending on the user's coding style and what's easier for them to understand, any of the above may be better for them.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Multiple points here:

  • New features need to have a justification to exist, satisfying all code styles isn't a good one. If we followed that principle, we'd have a cluttered mess in no time 😉
  • Redundant features need an ever higher bar. Once there are multiple ways to achieve the same thing, the whole "which should I use" and "is there a difference" questions come up.
  • From has the problem that it cannot do type inference. You can write let a = basis.to_quat() but not let a = basis.into() (at least not without further info after this line).
  • When you use into(), your code is objectively harder to understand than a named method that shows what you convert into. The main benefit in my opinion is for generic programming, which isn't applicable here.
  • One argument is that From demonstrates equivalence between two types. This also doesn't apply here, because basis can store rotation + scale, while quaternion can only store rotation. This even goes against not one, but three official recommendations stating that From should be lossless, value-preserving and obvious.
  • godot-rust as part of its API design doesn't use From in many places. Traditionally we've had it for string types, and it helped keep arguments generic as impl Into<GString>. Now there's AsArg which takes over that role, but some conversions are still done via From. Maybe named methods would be better there too, who knows.

This discussion comes up every now and then, I should probably add it to the book 🙂

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • About the two first points, yeah, you're right. I like having multiple ways of achieving the same (&str to owned, to string, into String and String from), but the code clutter and confusion it generates is non negligible.
  • About type inference and understandability, when using into one can easily say into:: and it would make sense to say that as a sentence. to_quat is a specific function to know, it could be to_quaternion instead, it's not as intuitive imo. That said, if you are using Basis and Quaternions you know about them, so it makes sense one would found to_quat easily.
  • Does Into have the same recommendations as From? It would make sense, but it would also make sense the opposite since From → Into but not the opposite. I agree under those guidelines this is a bad use of From.
  • About the last part, I stand the same about named methods, imo they can be harder to find and use, rather than a To trait. But if the whole crate follows the convention to_name_struct that also fixes the above. I think it would be a nice addition to the book? A conversions between types section, maybe.

And yeah! It would be nice having it in the book. Thank you for illustrating me on this and sorry for having said something that dumb.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • when using into one can easily say into::

Actually not, the way it's defined doesn't allow you to use turbofish .into::<Quaternion>(). It's another common pitfall -- because the into() function isn't generic itself, only the Into<T> trait is 🙂

to_quat is a specific function to know, it could be to_quaternion instead, it's not as intuitive imo.

Fair point 🤔 it was added in #124 alongside Basis::from_quat for the other direction. In the context it's probably quite clear, there are also other abbreviations in conversions, such as from_cols, into_dyn etc. But I'm also OK with changing it.

Thank you for illustrating me on this and sorry for having said something that dumb.

It's not dumb at all! I appreciate any input as long as it's constructive, and the fact that this has been brought up a few time shows that it's a frequent question, too. So no worries at all 😊

  • I think it would be a nice addition to the book? A conversions between types section, maybe.

This particular instance is probably best kept in the API docs (as this is the place for looking up API of a concrete type). But what can make sense is to elaborate some general "conventions" or API designs that godot-rust uses. I'll make some notes about this.

Copy link
Contributor

@sylbeth sylbeth Dec 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's another common pitfall

Oh goddess Hylia I think I hate into now. I would then just advocate for a To trait with to() function, that makes the "to type" action a standard action in the repository, but I'm not against it not being a trait, I just think it could be easier to find the one function you need from a user standpoint.

But I'm also OK with changing it.

I'm not saying from_quat and to_quat are bad options though, I'm all on board of using abbreviations when it's clear. I just wish for times when there would be function aliases since what one people thinks obvious another would not. I'm not a library maintainer so I don't know much about these though.

So no worries at all 😊

I'm glad I don't annoy with my comments at the least.

But what can make sense is to elaborate some general "conventions" or API designs that godot-rust uses. I'll make some notes about this.

Yeah! This would be great, specially for contributors. I don't mind much so long as there's a convention I can follow safely and know users will understand.

@fpdotmonkey fpdotmonkey force-pushed the quaternion-compatibility branch 2 times, most recently from d569d2f to 3a5e921 Compare December 21, 2024 20:44
More notable change is the renaming with deprecations for a couple
methods.  The new names are what Godot uses.
@fpdotmonkey fpdotmonkey force-pushed the quaternion-compatibility branch from 3a5e921 to 3e1fbad Compare December 21, 2024 20:46
@Bromeon Bromeon added this pull request to the merge queue Dec 22, 2024
Merged via the queue into godot-rust:master with commit 24db37d Dec 22, 2024
15 checks passed
@Bromeon Bromeon mentioned this pull request Jan 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: core Core components c: engine Godot classes (nodes, resources, ...) feature Adds functionality to the library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants