I've done a much larger review and testing.
Comparing it to different vector implementations,
and looking at how it inter-operates with pygame and OpenGL APIs.
TLDR; these things need to be fixed:
- scalar construction is buggy.
- One naming improvement I'd like help with is .elementwise() ? I think
it's too long.
- float('NaN') and float('inf') behaviour is not tested.
- Construction from Color, and Rect needs to be defined.
There's other useful functionality that could be added later I think.
I'll finish off the narrative documentation and example program,
and then await feedback before the Experimental notice is lifted.
This process has already uncovered a bunch of things that
are missing, so I expect more to pop up.
IMHO, it's already one of the best vector2/vector3 implementations in
python.
And I like that people will be able to use their knowledge of this API with
GLSL (a bit).
*A) GLSL shadling language vectors*
https://en.wikibooks.org/wiki/GLSL_Programming/Vector_and_Matrix_Operations#Components
https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf
Here's what I've found missing/different.
1) Single scalar constructor should
Vector2(1) == Vector2(1, 1)
# currently it makes Vector2(1, 0)
2) Lower dimensional to higher dimension contructors should work:
Vector3(1, Vector2(2, 3)) == Vector3(1, 2, 3)
3) the GLSL documentation uses "component wise", whereas we use
elementwise()
Additionally, I think elementwise() is quite long, and should probably be
a property.
A shorter name here would be nice.
4) Missing functions:
abs
abs(Vector2(2,-1).elementwise()) works.
sign
floor
trunc
round
roundEven
ceil
fract
mod
modf
min
max
clamp
mix
step
smoothstep
faceForward are missing
... more
Section 8.3, Common Functions
https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.30.pdf
The functions operate component wise.
Vector2(1, 3).min(Vector2(4, -2)) == Vector2(1, -2)
We have min() and max() in python, but unfortunately they use some weird
magic, and not a dunder magic method.
"Classes that act like numbers"
http://www.diveintopython3.net/special-method-names.html#acts-like-number
__floor__
__ceil__
__trunc__
5) swizzling only there with xyzw
Seems like rgba, and stpq should be available.
{x, y, z, w} Useful when accessing vectors that represent points or normals
{r, g, b, a} Useful when accessing vectors that represent colors
{s, t, p, q} Useful when accessing vectors that represent texture
coordinates
Perhaps vec3.rgb would return a pygame.Color
*B) Compared to the CookBook 2d vector class...*
https://www.pygame.org/wiki/2DVectorClass
missing:
get_angle()
perpendicular
http://mathworld.wolfram.com/PerpendicularVector.html
perpendicular_normal
projection (not in here, but the inverse is the rejection)
https://en.wikipedia.org/wiki/Vector_projection
*C) Compred to box2d vec2*
https://github.com/pybox2d/pypybox2d/blob/master/pypybox2d/src/vec2module.c
missing:
contains() isn't there, but you can do:
2 in v2
clamp
min
max
*D) pyeuclid*
rotate_around(axis, theta)
https://github.com/ezag/pyeuclid/blob/master/euclid.py#L565
copy()
Rect, and Surface have this in pygame too
Vector2(Vector2(1,2)) work however.
*E) planar*
https://pythonhosted.org/planar/vectorref.html
almost_equals
https://pythonhosted.org/planar/vectorref.html#planar.Vec2.almost_equals
Should be called isclose like python3.5+ math.isclose
https://docs.python.org/3/library/math.html#math.isclose
scaled_to
https://pythonhosted.org/planar/vectorref.html#planar.Vec2.scaled_to
perpendicular
clamped
*Extras*
Additional functionality not done is the buffer stuff. Which is commented
out in math.c
I guess the purpose is to allow a Vector2/3 to act with it's storage coming
in
an array. This would be super useful if you allocated a big array and wanted
to act on one element easily. Again, I think this could come later without
harming
backwards compatibility.
There is partial support in the code for a Vector4.
There's nothing done for 2x2, 3x3 or 4x4 matrix.
Which are all quite useful in games (and in GLSL).
These can all come later without harming backwards compatibility.
*Existing pygame APIs.*
There are some differences between Vector3 and Rect and Color types.
Vectors allow some niceties which people might come to expect from Rect and
Color.
v2[:] = (3,4)
v2.xy = (3,4)
Vector3(0) -> Vector3(0, 0, 0)
Also, Rect has methods like copy() which are missing in Vector3.
Passing a color into pygame gives a very strange result.
>>> Vector2(pygame.Color(2,3,4, 111))
<Vector2(3.37522e+07, 0)>
I think Vector3(Color('red')) should work to give you Vector(1, 0, 0).
And Vector3(Color(255, 255, 255)) should give you Vector3(1, 1, 1).
Or maybe not. Maybe it should raise an error because Color is 4 elements.
Vector3().rgb = Color(255, 255, 255) makes a lot more sense to be
Vector3(1, 1, 1).
Should a rect be able to to be used to construct a Vector2?
Especially when people have been using rects for the position of things.
>>> Vector2(pygame.Rect(2,3,4,111))
ValueError: Vector2 must be initialized with 2 real numbers or a
sequence of 2 real numbers
It should use the x, and y parts of a rect. IMHO.
>>> Vector2(pygame.Rect(2,3,4,111))
Vector2(2, 3)
*OpenGL API interactions.*
Converting in another direction would be useful.
Where OpenGL has y at the bottom left.
Getting OpenGL compat coords would be nice.
Requires knowledge of screen height/axis dimensions.
*pymunk intergration.*
pymunk already has some pygame utils which do swapping of Y coordinates.
Would be good to consider that.
On Tue, Feb 27, 2018 at 11:43 AM, René Dudfield <[email protected]> wrote:
> I won't move pygame.math.Vector2/3 into pygame or pygame.locals namespace
> for now.
> That's potentially breaking things which already have their own Vector2/3.
> This type of API change will wait for pygame 2.
>
> Narrative documentation is missing, and I'm working on that now.
>