1.10.3. Get subvolume

One of the most commonly used requests is also one of the simplest: requesting the voxels inside a “box” or subvolume. In addition to the usual resolution and bufferObj parameters, this request takes an SbBox3i32( C++ | Java ) object specifying the bounds of the subvolume in voxel (IJK) coordinates. The bounds of the subvolume are always specified in full resolution voxel coordinates. If the requested resolution level is greater than zero, the bufferDimension returned will be smaller than the requested bounds by the corresponding reduction factor.

Get subvolume is the “work horse” of many computation algorithms. It can return any part of the volume, independent of tile boundaries. Remember that VolumeViz is making a copy of the data and that, when possible, it will be more efficient to request subvolumes on tile boundaries. If the algorithm can work with a single tile it will be more efficient to use the get tile data request, because it does not make a copy of the data.

Currently VolumeViz does not allow the min and max values for any axis of the subvolume to be the same value. For example, a subvolume with min = 0,0,0 and max = 0,0,0 is not valid. As a result it is not possible to use this request to get the a single voxel, a single row of voxels or a single slice of voxels. It is possible to get the value of a single voxel by specifying a 2x2x2 subvolume where min is the desired voxel. In this case the desired voxel will be the first value in the buffer. If the algorithm requires a large number of single voxel values it will be more efficient to use the get tile data request. For a single row of voxels along the volume X axis you can use the get tile data request. A single row of voxels can also be requested using the get line data request. A single slice of voxels can be requested using the get plane data request.

This request returns a DataInfoBox struct (defined in class SoLDMDataAccess( C++ | Java | .NET )) containing:

The data type is not returned in this struct, but can be queried from the volume data node as shown in a previous section.

DataInfoBox query

Figure 1.99. DataInfoBox query


The following example shows how to extract a subvolume from a volume. In this example the application is requesting a 64 by 64 by 64 block of full resolution data (resolution = 0) and the volume contains unsigned integer data. The example code does not show error checking. In production code the application should check the errorFlag parameter in the returned struct.


C++
SbBox3i32 box(0,0,0,63,63,63);

// Call with null to get size of data
int res = 0;
SoLDMDataAccess& access = pVolData->getLdmDataAccess();
SoLDMDataAccess::DataInfoBox info;
info = access.getData( res, box );

// Create a buffer and set size large enough for returned data
SoRef<SoCpuBufferObject> pBuffer = new SoCpuBufferObject;
pBuffer->setSize( info.bufferSize );

// Call to get the actual data
info = access.getData( res, box, pBuffer.ptr() );

// Access the data then unmap the buffer
unsigned int* pData = (unsigned int*)pBuffer->map(SoBufferObject::READ_ONLY);
unsigned int value = pData[0];
 . . .
pBuffer->unmap();

.NET
SbBox3i32 box = new SbBox3i32(0,0,0, 63,63,63);

// Call with null to get size of data
int res = 0;
SoLDMDataAccess access = VolData.GetLdmDataAccess();
SoLDMDataAccess.DataInfoBox info;
info = access.GetData(res, box);

// Create a buffer and set size large enough for returned data
SoCpuBufferObject buffer = new SoCpuBufferObject();
buffer.SetSize((ulong)info.BufferSize);

// Call to get the actual data
info = access.GetData(res, box, buffer);

// Access the data then unmap the buffer
SbNativeArray<uint> data = (SbNativeArray<uint>)buffer.Map(SoBufferObject.AccessModes.READ_ONLY);
uint value = data[0];
. . .
buffer.unmap();

Java
SbBox3i32 box = new SbBox3i32(0,0,0, 63,63,63);

// Call with null to get size of data
int res = 0;
SoLDMDataAccess access = volData.getLdmDataAccess();
SoLDMDataAccess.DataInfoBox info;
info = access.getData(res, box, null);

// Create a buffer and set size large enough for returned data
ByteBuffer buffer = ByteBuffer.allocateDirect( info.bufferSize );
buffer.order(ByteOrder.nativeOrder());

// Call to get the actual data
info = access.getData(res, box, buffer);
  
// Access the data
IntBuffer ibuffer = buffer.asIntBuffer();
int value = ibuffer.get(0);
. . .