-
-
Notifications
You must be signed in to change notification settings - Fork 158
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
new angle and angle_rad property in vector2 #3222
base: main
Are you sure you want to change the base?
new angle and angle_rad property in vector2 #3222
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs documentation, and there are a few issues I see offhand. But thanks for submitting! 🎉
src_c/math.c
Outdated
pgVector *vec = (pgVector *)self; | ||
|
||
if (vec->coords[0] == 0.0 && vec->coords[1] == 0.0) { | ||
return PyFloat_FromDouble(0.0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’d rather an exception get raised here. The zero vector is special and getting it’s angle makes no sense
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I thought it should be 0 because of the initial issue #3195, but I can change and raise an exception
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@oddbookworm
I strongly think the angle properties should be consistent with the existing behavior of .as_polar()
, .angle_to()
, .rotate()
and more importantly python math.atan2()
(which is based off the a C standard) and polar coordinates.
These functions don't raise errors and (for not nan
args) don't return nan
, and most actually do not document this special case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One reason I hate that behavior is because it can lead to very confusing behavior. Consider the case where you're just continuously scaling down a vector without changing it's direction. At some point, you'll go from a constant angle to 0, regardless of what the starting angle is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @aatle and @oddbookworm,
I saw on discord that there is many vision for what should be done for the zero vector. And I wanted to know if people agree on one of these in order to maybe change my code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @AntoineMamou, it has been settled that we will imitate python's math.atan2()
function behavior. (Returns certain value depending on sign of zeroes, for zero vector.)
See https://github.com/python/cpython/blob/ed81971e6b26c34445f06850192b34458b029337/Lib/test/test_math.py#L327 for the relevant test cases.
Here's the old CPython 3.7.2 implementation for special cases: https://github.com/python/cpython/blob/v3.7.2/Modules/mathmodule.c#L566-L600
Recent CPython relies on a library, with atan2
implemented here:
https://github.com/rust-lang/libm/blob/master/src/math/atan2.rs#L20-L31
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @aatle, so if we want to imitate math.atan2(), for the case where x=y=0, it should return 0, right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And I'm using atan2 to find the angle, so basically I can skip the if statement ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I'm missing something here
src_c/math.c
Outdated
static PyObject * | ||
vector_get_angle(pgVector *self, void *closure) | ||
{ | ||
pgVector *vec = (pgVector *)self; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this cast to the type it already is?
src_c/math.c
Outdated
|
||
double angle = atan2(vec->coords[1], vec->coords[0]) * 180.0 / M_PI; | ||
|
||
if (angle > 180.0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make constants instead of reusing the same hardcoded numbers
src_c/math.c
Outdated
} | ||
|
||
static PyObject * | ||
vector_get_angle_rad(pgVector *self, void *closure) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just reuse the function you already have instead of writing the same code twice. Since you already got the output in a form you like, just convert it from degrees to radians
src_c/math.c
Outdated
@@ -2585,6 +2631,8 @@ static PyMethodDef vector2_methods[] = { | |||
static PyGetSetDef vector2_getsets[] = { | |||
{"x", (getter)vector_getx, (setter)vector_setx, NULL, NULL}, | |||
{"y", (getter)vector_gety, (setter)vector_sety, NULL, NULL}, | |||
{"angle", (getter)vector_get_angle, NULL, NULL, NULL}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing the docs component of these structs, which should be generated in the docs header, which is generated from the documentation updates you need to make
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have to make a doc in the file math.rst, right ? I'm not understanding everything about the doc yet. But I'm working on it !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
I see that two checks were not successful but I don't understand why. Can someone help me ? |
buildconfig/stubs/pygame/math.pyi
Outdated
angle: float | ||
angle_rad: float |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
angle: float | |
angle_rad: float | |
@property | |
def angle(self) -> float: ... | |
@property | |
def angle_rad(self) -> float: ... |
These are properties and they are read-only.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@property
doesn't say that it's a read-only attribute, right ?
docs/reST/ref/math.rst
Outdated
| :sl:`Gives the angle of the vector in degrees, relative to the X-axis, normalized to the interval (-180, 180].` | ||
|
||
Read-only attribute representing the angle of the vector in degrees relative to the X-axis. This angle is normalized to | ||
the interval (-180, 180]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My mistake, the interval is actually inclusive of -180. So, [-180, 180]
docs/reST/ref/math.rst
Outdated
Read-only attribute representing the angle of the vector in degrees relative to the X-axis. This angle is normalized to | ||
the interval (-180, 180]. | ||
|
||
Usage: Accessing `angle` provides the current angle of the vector in degrees within the specified range. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reword "specified range". The word 'specified' implies that the user provides it.
src_c/math.c
Outdated
if (angle_deg > 180.0) { | ||
angle_deg -= 360.0; | ||
} | ||
else if (angle_deg <= -180.0) { | ||
angle_deg += 360.0; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems unnecessary. The radians is within [-pi, pi]
, so the degrees will be within [-180, 180]
.
src_c/math.c
Outdated
} | ||
|
||
static PyObject * | ||
vector_get_angle_rad(pgVector *self, void *closure) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest creating a helper function _pg_atan2
that takes doubles and returns double. That way, one doesn't have to convert back to double and then to pyobject when doing more operations on it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where I should make the documentations for _pg_atan2
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Thanks for implementing my feature request.
This PR follows this one : #3216
I make the changes needed and add two properties :
angle_rad
: Returns the vector’s angle in radians relative to the positive x-axis.angle
: Returns the angle in degrees, normalized to (180,180].