linmath: Backport support for floor division to 1.10

Backport of 89447378440e9b9472a7290facbd8949f41a64ae

(Also fixes return type of `__pow__` to always be derived class)
This commit is contained in:
rdb 2021-06-01 10:44:39 +02:00
parent 4e0e945279
commit 2386e80448
12 changed files with 321 additions and 24 deletions

View File

@ -200,11 +200,78 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
/**
*
*/
INLINE_LINMATH FLOATNAME(LVecBase2) Extension<FLOATNAME(LVecBase2)>::
__pow__(FLOATTYPE exponent) const {
return FLOATNAME(LVecBase2)(
cpow(_this->_v(0), exponent),
cpow(_this->_v(1), exponent));
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase2)>::
__floordiv__(PyObject *self, FLOATTYPE scalar) const {
if (scalar == (FLOATTYPE)0) {
return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
}
#ifndef CPPPARSER
extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
#endif
PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
if (py_vec != nullptr) {
FLOATNAME(LVecBase2) *vec = (FLOATNAME(LVecBase2) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase2));
nassertr(vec != nullptr, nullptr);
#ifdef FLOATTYPE_IS_INT
if (scalar > 0) {
vec->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
vec->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
} else {
vec->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
vec->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
}
#else
vec->_v(0) = std::floor(_this->_v(0) / scalar);
vec->_v(1) = std::floor(_this->_v(1) / scalar);
#endif
}
return py_vec;
}
/**
*
*/
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase2)>::
__ifloordiv__(PyObject *self, FLOATTYPE scalar) {
if (scalar == (FLOATTYPE)0) {
return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
}
#ifdef FLOATTYPE_IS_INT
if (scalar > 0) {
_this->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
_this->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
} else {
_this->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
_this->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
}
#else
_this->_v(0) = std::floor(_this->_v(0) / scalar);
_this->_v(1) = std::floor(_this->_v(1) / scalar);
#endif
Py_INCREF(self);
return self;
}
/**
*
*/
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase2)>::
__pow__(PyObject *self, FLOATTYPE exponent) const {
#ifndef CPPPARSER
extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase2);
#endif
PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
if (py_vec != nullptr) {
FLOATNAME(LVecBase2) *vec = (FLOATNAME(LVecBase2) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase2));
nassertr(vec != nullptr, nullptr);
vec->_v(0) = cpow(_this->_v(0), exponent);
vec->_v(1) = cpow(_this->_v(1), exponent);
}
return py_vec;
}
/**

View File

@ -23,7 +23,10 @@ public:
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH std::string __repr__() const;
INLINE_LINMATH FLOATNAME(LVecBase2) __pow__(FLOATTYPE exponent) const;
INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const;
INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar);
INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const;
INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent);
INLINE_LINMATH PyObject *__round__(PyObject *self) const;

View File

@ -133,7 +133,10 @@ PUBLISHED:
INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase2) &other);
EXTENSION(INLINE_LINMATH FLOATNAME(LVecBase2) __pow__(FLOATTYPE exponent) const);
EXTENSION(INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const);
EXTENSION(INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar));
EXTENSION(INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const);
EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent));
EXTENSION(INLINE_LINMATH PyObject *__round__(PyObject *self));

View File

@ -201,12 +201,85 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
/**
*
*/
INLINE_LINMATH FLOATNAME(LVecBase3) Extension<FLOATNAME(LVecBase3)>::
__pow__(FLOATTYPE exponent) const {
return FLOATNAME(LVecBase3)(
cpow(_this->_v(0), exponent),
cpow(_this->_v(1), exponent),
cpow(_this->_v(2), exponent));
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase3)>::
__floordiv__(PyObject *self, FLOATTYPE scalar) const {
if (scalar == (FLOATTYPE)0) {
return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
}
#ifndef CPPPARSER
extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase3);
#endif
PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
if (py_vec != nullptr) {
FLOATNAME(LVecBase3) *vec = (FLOATNAME(LVecBase3) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase3));
nassertr(vec != nullptr, nullptr);
#ifdef FLOATTYPE_IS_INT
if (scalar > 0) {
vec->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
vec->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
vec->_v(2) = (_this->_v(2) >= 0) ? _this->_v(2) / scalar : -1 - (-1 - _this->_v(2)) / scalar;
} else {
vec->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
vec->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
vec->_v(2) = (_this->_v(2) <= 0) ? _this->_v(2) / scalar : -1 + (1 - _this->_v(2)) / -scalar;
}
#else
vec->_v(0) = std::floor(_this->_v(0) / scalar);
vec->_v(1) = std::floor(_this->_v(1) / scalar);
vec->_v(2) = std::floor(_this->_v(2) / scalar);
#endif
}
return py_vec;
}
/**
*
*/
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase3)>::
__ifloordiv__(PyObject *self, FLOATTYPE scalar) {
if (scalar == (FLOATTYPE)0) {
return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
}
#ifdef FLOATTYPE_IS_INT
if (scalar > 0) {
_this->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
_this->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
_this->_v(2) = (_this->_v(2) >= 0) ? _this->_v(2) / scalar : -1 - (-1 - _this->_v(2)) / scalar;
} else {
_this->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
_this->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
_this->_v(2) = (_this->_v(2) <= 0) ? _this->_v(2) / scalar : -1 + (1 - _this->_v(2)) / -scalar;
}
#else
_this->_v(0) = std::floor(_this->_v(0) / scalar);
_this->_v(1) = std::floor(_this->_v(1) / scalar);
_this->_v(2) = std::floor(_this->_v(2) / scalar);
#endif
Py_INCREF(self);
return self;
}
/**
*
*/
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase3)>::
__pow__(PyObject *self, FLOATTYPE exponent) const {
#ifndef CPPPARSER
extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase3);
#endif
PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
if (py_vec != nullptr) {
FLOATNAME(LVecBase3) *vec = (FLOATNAME(LVecBase3) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase3));
nassertr(vec != nullptr, nullptr);
vec->_v(0) = cpow(_this->_v(0), exponent);
vec->_v(1) = cpow(_this->_v(1), exponent);
vec->_v(2) = cpow(_this->_v(2), exponent);
}
return py_vec;
}
/**

View File

@ -23,7 +23,10 @@ public:
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH std::string __repr__() const;
INLINE_LINMATH FLOATNAME(LVecBase3) __pow__(FLOATTYPE exponent) const;
INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const;
INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar);
INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const;
INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent);
INLINE_LINMATH PyObject *__round__(PyObject *self) const;

View File

@ -152,7 +152,10 @@ PUBLISHED:
INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase3) &other);
EXTENSION(INLINE_LINMATH FLOATNAME(LVecBase3) __pow__(FLOATTYPE exponent) const);
EXTENSION(INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const);
EXTENSION(INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar));
EXTENSION(INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const);
EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent));
EXTENSION(INLINE_LINMATH PyObject *__round__(PyObject *self));

View File

@ -207,13 +207,92 @@ __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign) {
/**
*
*/
INLINE_LINMATH FLOATNAME(LVecBase4) Extension<FLOATNAME(LVecBase4)>::
__pow__(FLOATTYPE exponent) const {
return FLOATNAME(LVecBase4)(
cpow(_this->_v(0), exponent),
cpow(_this->_v(1), exponent),
cpow(_this->_v(2), exponent),
cpow(_this->_v(3), exponent));
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase4)>::
__floordiv__(PyObject *self, FLOATTYPE scalar) const {
if (scalar == (FLOATTYPE)0) {
return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
}
#ifndef CPPPARSER
extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
#endif
PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
if (py_vec != nullptr) {
FLOATNAME(LVecBase4) *vec = (FLOATNAME(LVecBase4) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase4));
nassertr(vec != nullptr, nullptr);
#ifdef FLOATTYPE_IS_INT
if (scalar > 0) {
vec->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
vec->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
vec->_v(2) = (_this->_v(2) >= 0) ? _this->_v(2) / scalar : -1 - (-1 - _this->_v(2)) / scalar;
vec->_v(3) = (_this->_v(3) >= 0) ? _this->_v(3) / scalar : -1 - (-1 - _this->_v(3)) / scalar;
} else {
vec->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
vec->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
vec->_v(2) = (_this->_v(2) <= 0) ? _this->_v(2) / scalar : -1 + (1 - _this->_v(2)) / -scalar;
vec->_v(3) = (_this->_v(3) <= 0) ? _this->_v(3) / scalar : -1 + (1 - _this->_v(3)) / -scalar;
}
#else
vec->_v(0) = std::floor(_this->_v(0) / scalar);
vec->_v(1) = std::floor(_this->_v(1) / scalar);
vec->_v(2) = std::floor(_this->_v(2) / scalar);
vec->_v(3) = std::floor(_this->_v(3) / scalar);
#endif
}
return py_vec;
}
/**
*
*/
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase4)>::
__ifloordiv__(PyObject *self, FLOATTYPE scalar) {
if (scalar == (FLOATTYPE)0) {
return PyErr_Format(PyExc_ZeroDivisionError, "floor division by zero");
}
#ifdef FLOATTYPE_IS_INT
if (scalar > 0) {
_this->_v(0) = (_this->_v(0) >= 0) ? _this->_v(0) / scalar : -1 - (-1 - _this->_v(0)) / scalar;
_this->_v(1) = (_this->_v(1) >= 0) ? _this->_v(1) / scalar : -1 - (-1 - _this->_v(1)) / scalar;
_this->_v(2) = (_this->_v(2) >= 0) ? _this->_v(2) / scalar : -1 - (-1 - _this->_v(2)) / scalar;
_this->_v(3) = (_this->_v(3) >= 0) ? _this->_v(3) / scalar : -1 - (-1 - _this->_v(3)) / scalar;
} else {
_this->_v(0) = (_this->_v(0) <= 0) ? _this->_v(0) / scalar : -1 + (1 - _this->_v(0)) / -scalar;
_this->_v(1) = (_this->_v(1) <= 0) ? _this->_v(1) / scalar : -1 + (1 - _this->_v(1)) / -scalar;
_this->_v(2) = (_this->_v(2) <= 0) ? _this->_v(2) / scalar : -1 + (1 - _this->_v(2)) / -scalar;
_this->_v(3) = (_this->_v(3) <= 0) ? _this->_v(3) / scalar : -1 + (1 - _this->_v(3)) / -scalar;
}
#else
_this->_v(0) = std::floor(_this->_v(0) / scalar);
_this->_v(1) = std::floor(_this->_v(1) / scalar);
_this->_v(2) = std::floor(_this->_v(2) / scalar);
_this->_v(3) = std::floor(_this->_v(3) / scalar);
#endif
Py_INCREF(self);
return self;
}
/**
*
*/
INLINE_LINMATH PyObject *Extension<FLOATNAME(LVecBase4)>::
__pow__(PyObject *self, FLOATTYPE exponent) const {
#ifndef CPPPARSER
extern struct Dtool_PyTypedObject FLOATNAME(Dtool_LVecBase4);
#endif
PyObject *py_vec = PyObject_CallNoArgs((PyObject *)DtoolInstance_TYPE(self));
if (py_vec != nullptr) {
FLOATNAME(LVecBase4) *vec = (FLOATNAME(LVecBase4) *)DtoolInstance_UPCAST(py_vec, FLOATNAME(Dtool_LVecBase4));
nassertr(vec != nullptr, nullptr);
vec->_v(0) = cpow(_this->_v(0), exponent);
vec->_v(1) = cpow(_this->_v(1), exponent);
vec->_v(2) = cpow(_this->_v(2), exponent);
vec->_v(3) = cpow(_this->_v(3), exponent);
}
return py_vec;
}
/**

View File

@ -23,7 +23,10 @@ public:
INLINE_LINMATH int __setattr__(PyObject *self, const std::string &attr_name, PyObject *assign);
INLINE_LINMATH std::string __repr__() const;
INLINE_LINMATH FLOATNAME(LVecBase4) __pow__(FLOATTYPE exponent) const;
INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const;
INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar);
INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const;
INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent);
INLINE_LINMATH PyObject *__round__(PyObject *self) const;

View File

@ -160,7 +160,10 @@ PUBLISHED:
INLINE_LINMATH void componentwise_mult(const FLOATNAME(LVecBase4) &other);
EXTENSION(INLINE_LINMATH FLOATNAME(LVecBase4) __pow__(FLOATTYPE exponent) const);
EXTENSION(INLINE_LINMATH PyObject *__floordiv__(PyObject *self, FLOATTYPE scalar) const);
EXTENSION(INLINE_LINMATH PyObject *__ifloordiv__(PyObject *self, FLOATTYPE scalar));
EXTENSION(INLINE_LINMATH PyObject *__pow__(PyObject *self, FLOATTYPE exponent) const);
EXTENSION(INLINE_LINMATH PyObject *__ipow__(PyObject *self, FLOATTYPE exponent));
EXTENSION(INLINE_LINMATH PyObject *__round__(PyObject *self));

View File

@ -2,6 +2,7 @@ from math import floor, ceil
import sys
from panda3d.core import Vec2, Vec3, Vec4, Vec2F, Vec2D
from panda3d import core
import pytest
@ -121,3 +122,22 @@ def test_vec2_ceil():
rounded_vector = ceil(original_vector)
assert rounded_vector.x == 3
assert rounded_vector.y == -2
@pytest.mark.parametrize("type", (core.LVecBase2f, core.LVecBase2d, core.LVecBase2i))
def test_vec2_floordiv(type):
with pytest.raises(ZeroDivisionError):
type(1, 2) // 0
for i in range(-100, 100):
for j in range(1, 100):
assert (type(i) // j).x == i // j
assert (type(i) // -j).x == i // -j
v = type(i)
v //= j
assert v.x == i // j
v = type(i)
v //= -j
assert v.x == i // -j

View File

@ -2,6 +2,7 @@ from math import floor, ceil
import sys
from panda3d.core import Vec2, Vec3, Vec3F, Vec3D
from panda3d import core
import pytest
@ -106,3 +107,22 @@ def test_vec3_ceil():
assert rounded_vector.x == 3
assert rounded_vector.y == -2
assert rounded_vector.z == 4
@pytest.mark.parametrize("type", (core.LVecBase3f, core.LVecBase3d, core.LVecBase3i))
def test_vec3_floordiv(type):
with pytest.raises(ZeroDivisionError):
type(1, 2, 3) // 0
for i in range(-100, 100):
for j in range(1, 100):
assert (type(i) // j).x == i // j
assert (type(i) // -j).x == i // -j
v = type(i)
v //= j
assert v.x == i // j
v = type(i)
v //= -j
assert v.x == i // -j

View File

@ -2,6 +2,7 @@ from math import floor, ceil
import sys
from panda3d.core import Vec2, Vec3, Vec4, Vec4F, Vec4D
from panda3d import core
import pytest
@ -122,3 +123,22 @@ def test_vec4_ceil():
assert rounded_vector.y == -2
assert rounded_vector.z == 4
assert rounded_vector.w == 1
@pytest.mark.parametrize("type", (core.LVecBase4f, core.LVecBase4d, core.LVecBase4i))
def test_vec4_floordiv(type):
with pytest.raises(ZeroDivisionError):
type(1, 2, 3, 4) // 0
for i in range(-100, 100):
for j in range(1, 100):
assert (type(i) // j).x == i // j
assert (type(i) // -j).x == i // -j
v = type(i)
v //= j
assert v.x == i // j
v = type(i)
v //= -j
assert v.x == i // -j