Add QgsBox3D tests and fix the implementation

This commit is contained in:
Martin Dobias 2024-10-28 11:50:25 +01:00 committed by Nyall Dawson
parent 4f183696b0
commit ae13cfea17
5 changed files with 119 additions and 30 deletions

View File

@ -36,7 +36,7 @@ extent of a geometry or collection of geometries.
public:
QgsBox3D( SIP_PYOBJECT x /TypeHint="Optional[Union[QgsPoint, QgsRectangle, float]]"/ = Py_None, SIP_PYOBJECT y /TypeHint="Optional[QgsPoint, float]"/ = Py_None, SIP_PYOBJECT z /TypeHint="Optional[Union[bool, float]]"/ = Py_None, SIP_PYOBJECT x2 /TypeHint="Optional[Union[bool, float]]"/ = Py_None, SIP_PYOBJECT y2 /TypeHint="Optional[float]"/ = Py_None, SIP_PYOBJECT z2 /TypeHint="Optional[float]"/ = Py_None, SIP_PYOBJECT n /TypeHint="Optional[bool]"/ = Py_None ) [( double x = 0.0, double y = 0.0, double z = 0.0, double x2 = 0.0, double y2 = 0.0, double z2 = 0.0, bool n = true )];
QgsBox3D( SIP_PYOBJECT x /TypeHint="Optional[Union[QgsPoint, QgsVector3D, QgsRectangle, float]]"/ = Py_None, SIP_PYOBJECT y /TypeHint="Optional[QgsPoint, QgsVector3D, float]"/ = Py_None, SIP_PYOBJECT z /TypeHint="Optional[Union[bool, float]]"/ = Py_None, SIP_PYOBJECT x2 /TypeHint="Optional[Union[bool, float]]"/ = Py_None, SIP_PYOBJECT y2 /TypeHint="Optional[float]"/ = Py_None, SIP_PYOBJECT z2 /TypeHint="Optional[float]"/ = Py_None, SIP_PYOBJECT n /TypeHint="Optional[bool]"/ = Py_None ) [( double x = 0.0, double y = 0.0, double z = 0.0, double x2 = 0.0, double y2 = 0.0, double z2 = 0.0, bool n = true )];
%Docstring
Constructor for QgsBox3D which accepts the ranges of x/y/z coordinates. If ``normalize`` is ``False`` then
the normalization step will not be applied automatically.
@ -85,6 +85,30 @@ the normalization step will not be applied automatically.
}
}
}
else if ( sipCanConvertToType( a0, sipType_QgsVector3D, SIP_NOT_NONE ) && sipCanConvertToType( a1, sipType_QgsVector3D, SIP_NOT_NONE ) && a3 == Py_None && a4 == Py_None && a5 == Py_None && a6 == Py_None )
{
int state;
sipIsErr = 0;
QgsVector3D *corner1 = reinterpret_cast<QgsVector3D *>( sipConvertToType( a0, sipType_QgsVector3D, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
if ( sipIsErr )
{
sipReleaseType( corner1, sipType_QgsVector3D, state );
}
else
{
QgsVector3D *corner2 = reinterpret_cast<QgsVector3D *>( sipConvertToType( a1, sipType_QgsVector3D, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
if ( sipIsErr )
{
sipReleaseType( corner2, sipType_QgsVector3D, state );
}
else
{
bool n = a2 == Py_None ? true : PyObject_IsTrue( a2 );
sipCpp = new QgsBox3D( *corner1, *corner2, n );
}
}
}
else if (
( a0 == Py_None || PyFloat_AsDouble( a0 ) != -1.0 || !PyErr_Occurred() ) &&
( a1 == Py_None || PyFloat_AsDouble( a1 ) != -1.0 || !PyErr_Occurred() ) &&
@ -110,15 +134,6 @@ the normalization step will not be applied automatically.
}
%End
QgsBox3D( const QgsVector3D &corner1, const QgsVector3D &corner2, bool normalize = true );
%Docstring
Constructs a QgsBox3D from two 3D vectors representing opposite corners of the box.
The box is normalized after construction. If ``normalize`` is ``False`` then
the normalization step will not be applied automatically.
.. versionadded:: 3.42
%End
void set( double xMin, double yMin, double zMin, double xMax, double yMax, double zMax, bool normalize = true );
%Docstring
Sets the box from a set of (x,y,z) minimum and maximum coordinates.

View File

@ -36,7 +36,7 @@ extent of a geometry or collection of geometries.
public:
QgsBox3D( SIP_PYOBJECT x /TypeHint="Optional[Union[QgsPoint, QgsRectangle, float]]"/ = Py_None, SIP_PYOBJECT y /TypeHint="Optional[QgsPoint, float]"/ = Py_None, SIP_PYOBJECT z /TypeHint="Optional[Union[bool, float]]"/ = Py_None, SIP_PYOBJECT x2 /TypeHint="Optional[Union[bool, float]]"/ = Py_None, SIP_PYOBJECT y2 /TypeHint="Optional[float]"/ = Py_None, SIP_PYOBJECT z2 /TypeHint="Optional[float]"/ = Py_None, SIP_PYOBJECT n /TypeHint="Optional[bool]"/ = Py_None ) [( double x = 0.0, double y = 0.0, double z = 0.0, double x2 = 0.0, double y2 = 0.0, double z2 = 0.0, bool n = true )];
QgsBox3D( SIP_PYOBJECT x /TypeHint="Optional[Union[QgsPoint, QgsVector3D, QgsRectangle, float]]"/ = Py_None, SIP_PYOBJECT y /TypeHint="Optional[QgsPoint, QgsVector3D, float]"/ = Py_None, SIP_PYOBJECT z /TypeHint="Optional[Union[bool, float]]"/ = Py_None, SIP_PYOBJECT x2 /TypeHint="Optional[Union[bool, float]]"/ = Py_None, SIP_PYOBJECT y2 /TypeHint="Optional[float]"/ = Py_None, SIP_PYOBJECT z2 /TypeHint="Optional[float]"/ = Py_None, SIP_PYOBJECT n /TypeHint="Optional[bool]"/ = Py_None ) [( double x = 0.0, double y = 0.0, double z = 0.0, double x2 = 0.0, double y2 = 0.0, double z2 = 0.0, bool n = true )];
%Docstring
Constructor for QgsBox3D which accepts the ranges of x/y/z coordinates. If ``normalize`` is ``False`` then
the normalization step will not be applied automatically.
@ -85,6 +85,30 @@ the normalization step will not be applied automatically.
}
}
}
else if ( sipCanConvertToType( a0, sipType_QgsVector3D, SIP_NOT_NONE ) && sipCanConvertToType( a1, sipType_QgsVector3D, SIP_NOT_NONE ) && a3 == Py_None && a4 == Py_None && a5 == Py_None && a6 == Py_None )
{
int state;
sipIsErr = 0;
QgsVector3D *corner1 = reinterpret_cast<QgsVector3D *>( sipConvertToType( a0, sipType_QgsVector3D, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
if ( sipIsErr )
{
sipReleaseType( corner1, sipType_QgsVector3D, state );
}
else
{
QgsVector3D *corner2 = reinterpret_cast<QgsVector3D *>( sipConvertToType( a1, sipType_QgsVector3D, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
if ( sipIsErr )
{
sipReleaseType( corner2, sipType_QgsVector3D, state );
}
else
{
bool n = a2 == Py_None ? true : PyObject_IsTrue( a2 );
sipCpp = new QgsBox3D( *corner1, *corner2, n );
}
}
}
else if (
( a0 == Py_None || PyFloat_AsDouble( a0 ) != -1.0 || !PyErr_Occurred() ) &&
( a1 == Py_None || PyFloat_AsDouble( a1 ) != -1.0 || !PyErr_Occurred() ) &&
@ -110,15 +134,6 @@ the normalization step will not be applied automatically.
}
%End
QgsBox3D( const QgsVector3D &corner1, const QgsVector3D &corner2, bool normalize = true );
%Docstring
Constructs a QgsBox3D from two 3D vectors representing opposite corners of the box.
The box is normalized after construction. If ``normalize`` is ``False`` then
the normalization step will not be applied automatically.
.. versionadded:: 3.42
%End
void set( double xMin, double yMin, double zMin, double xMax, double yMax, double zMax, bool normalize = true );
%Docstring
Sets the box from a set of (x,y,z) minimum and maximum coordinates.

View File

@ -54,7 +54,7 @@ QgsBox3D::QgsBox3D( const QgsRectangle &rect, double zMin, double zMax, bool nor
}
QgsBox3D::QgsBox3D( const QgsVector3D &corner1, const QgsVector3D &corner2, bool normalize )
: mBounds2d( corner1.x(), corner1.y(), corner2.x(), corner2.y() )
: mBounds2d( corner1.x(), corner1.y(), corner2.x(), corner2.y(), false )
, mZmin( corner1.z() )
, mZmax( corner2.z() )
{

View File

@ -61,6 +61,14 @@ class CORE_EXPORT QgsBox3D
*/
QgsBox3D( const QgsPoint &p1, const QgsPoint &p2, bool normalize = true );
/**
* Constructs a QgsBox3D from two 3D vectors representing opposite corners of the box.
* The box is normalized after construction. If \a normalize is FALSE then
* the normalization step will not be applied automatically.
* \since QGIS 3.42
*/
QgsBox3D( const QgsVector3D &corner1, const QgsVector3D &corner2, bool normalize = true );
/**
* Constructs a QgsBox3D from a rectangle.
* If \a normalize is FALSE then the normalization step will not be applied automatically.
@ -70,7 +78,7 @@ class CORE_EXPORT QgsBox3D
bool normalize = true );
#else
QgsBox3D( SIP_PYOBJECT x SIP_TYPEHINT( Optional[Union[QgsPoint, QgsRectangle, float]] ) = Py_None, SIP_PYOBJECT y SIP_TYPEHINT( Optional[QgsPoint, float] ) = Py_None, SIP_PYOBJECT z SIP_TYPEHINT( Optional[Union[bool, float]] ) = Py_None, SIP_PYOBJECT x2 SIP_TYPEHINT( Optional[Union[bool, float]] ) = Py_None, SIP_PYOBJECT y2 SIP_TYPEHINT( Optional[float] ) = Py_None, SIP_PYOBJECT z2 SIP_TYPEHINT( Optional[float] ) = Py_None, SIP_PYOBJECT n SIP_TYPEHINT( Optional[bool] ) = Py_None ) [( double x = 0.0, double y = 0.0, double z = 0.0, double x2 = 0.0, double y2 = 0.0, double z2 = 0.0, bool n = true )];
QgsBox3D( SIP_PYOBJECT x SIP_TYPEHINT( Optional[Union[QgsPoint, QgsVector3D, QgsRectangle, float]] ) = Py_None, SIP_PYOBJECT y SIP_TYPEHINT( Optional[QgsPoint, QgsVector3D, float] ) = Py_None, SIP_PYOBJECT z SIP_TYPEHINT( Optional[Union[bool, float]] ) = Py_None, SIP_PYOBJECT x2 SIP_TYPEHINT( Optional[Union[bool, float]] ) = Py_None, SIP_PYOBJECT y2 SIP_TYPEHINT( Optional[float] ) = Py_None, SIP_PYOBJECT z2 SIP_TYPEHINT( Optional[float] ) = Py_None, SIP_PYOBJECT n SIP_TYPEHINT( Optional[bool] ) = Py_None ) [( double x = 0.0, double y = 0.0, double z = 0.0, double x2 = 0.0, double y2 = 0.0, double z2 = 0.0, bool n = true )];
% MethodCode
if ( sipCanConvertToType( a0, sipType_QgsRectangle, SIP_NOT_NONE ) && a4 == Py_None && a5 == Py_None && a6 == Py_None )
{
@ -115,6 +123,30 @@ class CORE_EXPORT QgsBox3D
}
}
}
else if ( sipCanConvertToType( a0, sipType_QgsVector3D, SIP_NOT_NONE ) && sipCanConvertToType( a1, sipType_QgsVector3D, SIP_NOT_NONE ) && a3 == Py_None && a4 == Py_None && a5 == Py_None && a6 == Py_None )
{
int state;
sipIsErr = 0;
QgsVector3D *corner1 = reinterpret_cast<QgsVector3D *>( sipConvertToType( a0, sipType_QgsVector3D, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
if ( sipIsErr )
{
sipReleaseType( corner1, sipType_QgsVector3D, state );
}
else
{
QgsVector3D *corner2 = reinterpret_cast<QgsVector3D *>( sipConvertToType( a1, sipType_QgsVector3D, 0, SIP_NOT_NONE, &state, &sipIsErr ) );
if ( sipIsErr )
{
sipReleaseType( corner2, sipType_QgsVector3D, state );
}
else
{
bool n = a2 == Py_None ? true : PyObject_IsTrue( a2 );
sipCpp = new QgsBox3D( *corner1, *corner2, n );
}
}
}
else if (
( a0 == Py_None || PyFloat_AsDouble( a0 ) != -1.0 || !PyErr_Occurred() ) &&
( a1 == Py_None || PyFloat_AsDouble( a1 ) != -1.0 || !PyErr_Occurred() ) &&
@ -141,14 +173,6 @@ class CORE_EXPORT QgsBox3D
% End
#endif
/**
* Constructs a QgsBox3D from two 3D vectors representing opposite corners of the box.
* The box is normalized after construction. If \a normalize is FALSE then
* the normalization step will not be applied automatically.
* \since QGIS 3.42
*/
QgsBox3D( const QgsVector3D &corner1, const QgsVector3D &corner2, bool normalize = true );
/**
* Sets the box from a set of (x,y,z) minimum and maximum coordinates.
*

View File

@ -95,6 +95,31 @@ class TestQgsBox3d(unittest.TestCase):
self.assertEqual(box.yMaximum(), 13.0)
self.assertEqual(box.zMaximum(), 5.0)
# constructor using two corners
box = QgsBox3d(QgsVector3D(3, 4, 5), QgsVector3D(8, 9, 10))
self.assertEqual(box.xMinimum(), 3.0)
self.assertEqual(box.yMinimum(), 4.0)
self.assertEqual(box.zMinimum(), 5.0)
self.assertEqual(box.xMaximum(), 8.0)
self.assertEqual(box.yMaximum(), 9.0)
self.assertEqual(box.zMaximum(), 10.0)
box = QgsBox3d(QgsVector3D(3, 4, 5), QgsVector3D(1, 2, 6))
self.assertEqual(box.xMinimum(), 1.0)
self.assertEqual(box.yMinimum(), 2.0)
self.assertEqual(box.zMinimum(), 5.0)
self.assertEqual(box.xMaximum(), 3.0)
self.assertEqual(box.yMaximum(), 4.0)
self.assertEqual(box.zMaximum(), 6.0)
box = QgsBox3d(QgsVector3D(3, 4, 5), QgsVector3D(1, 2, 6), False)
self.assertEqual(box.xMinimum(), 3.0)
self.assertEqual(box.yMinimum(), 4.0)
self.assertEqual(box.zMinimum(), 5.0)
self.assertEqual(box.xMaximum(), 1.0)
self.assertEqual(box.yMaximum(), 2.0)
self.assertEqual(box.zMaximum(), 6.0)
def test_repr(self):
box = QgsBox3d(5.0, 6.0, 7.0, 10.0, 11.0, 12.0)
self.assertEqual(str(box), '<QgsBox3D(5, 6, 7, 10, 11, 12)>')
@ -391,6 +416,16 @@ class TestQgsBox3d(unittest.TestCase):
self.assertEqual(box3.yMinimum(), -7.0)
self.assertEqual(box3.zMinimum(), -3.0)
def testGrow(self):
box = QgsBox3d(5.0, 6.0, 7.0, 11.0, 13.0, 15.0)
box.grow(2.0)
self.assertEqual(box.xMinimum(), 3.0)
self.assertEqual(box.yMinimum(), 4.0)
self.assertEqual(box.zMinimum(), 5.0)
self.assertEqual(box.xMaximum(), 13.0)
self.assertEqual(box.yMaximum(), 15.0)
self.assertEqual(box.zMaximum(), 17.0)
def testIsNull(self):
box1 = QgsBox3d()
self.assertTrue(box1.isNull())