Skip to content

Commit f0a7da0

Browse files
committed
BoxVectorData : Add buffer protocol support
1 parent 8005501 commit f0a7da0

File tree

4 files changed

+75
-6
lines changed

4 files changed

+75
-6
lines changed

Changes

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
10.6.x.x (relative to 10.6.2.1)
22
========
33

4+
API
5+
---
46

7+
- IECorePython : Added `Buffer` object and associated `asReadOnlyBuffer()` and `asReadWriteBuffer()` methods for numeric-based `*VectorData` types. This adds support for Python's buffer protocol which allows direct access to the vector.
58

69
10.6.2.1 (relative to 10.6.2.0)
710
========

src/IECorePython/ImathBoxVectorBinding.cpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,22 @@ IECOREPYTHON_DEFINEVECTORDATASTRSPECIALISATION( Box3i )
4848
IECOREPYTHON_DEFINEVECTORDATASTRSPECIALISATION( Box3f )
4949
IECOREPYTHON_DEFINEVECTORDATASTRSPECIALISATION( Box3d )
5050

51+
#define BIND_BOX_VECTOR_TYPEDDATA(T, Tname) \
52+
{ \
53+
BASIC_VECTOR_BINDING(IECore::TypedData< std::vector< T > >, Tname) \
54+
.def("__cmp__", &ThisBinder::invalidOperator, "Raises an exception. This vector type does not support comparison operators.") \
55+
BIND_BUFFER_PROTOCOL_METHODS \
56+
; \
57+
}
58+
5159
void bindImathBoxVectorTypedData()
5260
{
53-
BIND_VECTOR_TYPEDDATA ( Box< V2i >, "Box2i")
54-
BIND_VECTOR_TYPEDDATA ( Box< V2f >, "Box2f")
55-
BIND_VECTOR_TYPEDDATA ( Box< V2d >, "Box2d")
56-
BIND_VECTOR_TYPEDDATA ( Box< V3i >, "Box3i")
57-
BIND_VECTOR_TYPEDDATA ( Box< V3f >, "Box3f")
58-
BIND_VECTOR_TYPEDDATA ( Box< V3d >, "Box3d")
61+
BIND_BOX_VECTOR_TYPEDDATA ( Box< V2i >, "Box2i")
62+
BIND_BOX_VECTOR_TYPEDDATA ( Box< V2f >, "Box2f")
63+
BIND_BOX_VECTOR_TYPEDDATA ( Box< V2d >, "Box2d")
64+
BIND_BOX_VECTOR_TYPEDDATA ( Box< V3i >, "Box3i")
65+
BIND_BOX_VECTOR_TYPEDDATA ( Box< V3f >, "Box3f")
66+
BIND_BOX_VECTOR_TYPEDDATA ( Box< V3d >, "Box3d")
5967
}
6068

6169
} // namespace IECorePython

src/IECorePython/VectorTypedDataBinding.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ constexpr std::pair<const char *, Py_ssize_t> typeInfo()
102102
{
103103
return { PythonType<typename T::BaseType>::value(), sizeof( T::BaseType ) };
104104
}
105+
else if constexpr( IECore::TypeTraits::IsBox<T>::value )
106+
{
107+
using ElementType = decltype( T::min );
108+
return { PythonType<typename ElementType::BaseType>::value(), sizeof( ElementType::BaseType ) };
109+
}
105110
else
106111
{
107112
return { PythonType<T>::value(), sizeof( T ) };
@@ -293,6 +298,19 @@ int Buffer::getBuffer( PyObject *object, Py_buffer *view, int flags )
293298
strides = new Py_ssize_t[2]{ ElementType::dimensions() * itemSize, itemSize };
294299
}
295300
}
301+
else if constexpr( IECore::TypeTraits::IsBox<ElementType>::value )
302+
{
303+
ndim = 3;
304+
using ElementType = decltype( ElementType::min );
305+
if( ( flags & PyBUF_ND ) == PyBUF_ND )
306+
{
307+
shape = new Py_ssize_t[3]{ (Py_ssize_t)bufferData->readable().size(), 2, ElementType::dimensions() };
308+
}
309+
if( ( flags & PyBUF_STRIDES ) == PyBUF_STRIDES )
310+
{
311+
strides = new Py_ssize_t[3]{ 2 * ElementType::dimensions() * itemSize, ElementType::dimensions() * itemSize, itemSize };
312+
}
313+
}
296314
else
297315
{
298316
shape = new Py_ssize_t{ (Py_ssize_t)bufferData->readable().size() };

test/IECore/VectorData.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,6 +1498,46 @@ def testTwoDimensionalBuffers( self ) :
14981498

14991499
self.__assertMemoryBufferProperties( m, b, elementFormat, 2, ( len( v ), dimensions ), ( dimensions * m.itemsize, m.itemsize ) )
15001500

1501+
def testBoxTypes( self ) :
1502+
1503+
for elementType, vectorType, elementFormat, componentType in [
1504+
( imath.Box2i, IECore.Box2iVectorData, "i", imath.V2i ),
1505+
( imath.Box2f, IECore.Box2fVectorData, "f", imath.V2f ),
1506+
( imath.Box2d, IECore.Box2dVectorData, "d", imath.V2d ),
1507+
( imath.Box3i, IECore.Box3iVectorData, "i", imath.V3i ),
1508+
( imath.Box3f, IECore.Box3fVectorData, "f", imath.V3f ),
1509+
( imath.Box3d, IECore.Box3dVectorData, "d", imath.V3d )
1510+
] :
1511+
with self.subTest( elementType = elementType, vectorType = vectorType ) :
1512+
v = vectorType(
1513+
[
1514+
elementType(
1515+
componentType( *list( range( i, i + componentType.dimensions() ) ) ),
1516+
componentType( *list( range( i + 10, i + 10 + componentType.dimensions() ) ) )
1517+
) for i in range( 0, 3 )
1518+
]
1519+
)
1520+
1521+
b = v.asReadOnlyBuffer()
1522+
m = memoryview( b )
1523+
1524+
self.assertIsNotNone( m )
1525+
for i in range( 0, len( v ) ) :
1526+
for j in range( 0, 2 ) :
1527+
for k in range( 0, componentType.dimensions() ) :
1528+
if j == 0 :
1529+
self.assertEqual( m.tolist()[i][j][k], v[i].min()[k] )
1530+
else :
1531+
self.assertEqual( m.tolist()[i][j][k], v[i].max()[k] )
1532+
1533+
self.__assertMemoryBufferProperties(
1534+
m,
1535+
b,
1536+
elementFormat,
1537+
3,
1538+
( len( v ), 2, componentType.dimensions() ),
1539+
( 2 * componentType.dimensions() * m.itemsize, componentType.dimensions() * m.itemsize, m.itemsize )
1540+
)
15011541

15021542
def testReadOnlyBuffer( self ) :
15031543

0 commit comments

Comments
 (0)