1.10.6. Get polyline

This request returns all the voxels intersected by a polyline (set of line segments), optionally bounded by a subvolume. In addition to the resolution and bufferObj parameters, this request takes an SbBox3i32 SbBox3i32 specifying the bounds of the subvolume in voxel (IJK) coordinates, an integer specifying the number of vertices, and an array of SbVec3i32 SbVec3i32 specifying the vertices in the polyline. The vertices are in IJK (voxel) coordinates.

The returned info struct, DataInfoPolyLine , is more complex than the previous data request. Unlike the other data requests, the struct is passed as a parameter to the method and the struct must be created using its constructor, passing the number of vertices in the polyline.

The request returns a DataInfoPolyLine struct containing:

  • errorFlag – Set to CORRECT if the request succeeded.

  • bufferSize – Returns the required buffer size (int) in bytes.

  • numSegment – Returns the number of segments in the polyline (int) that are (at least partially) inside the specified subvolume.

  • segmentBufferDim – Returns an array of numSegment integers containing the number of values for each segment. A value of zero means the segment was completely outside the specified subvolume.

  • segmentBufferSize – Returns an array of numSegment integers containing the number of bytes in the buffer used for each segment.

  • segmentCoord- Returns an array of arrays containing two SbVec3i32 SbVec3i32 values (begin and end) for each segment.

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

DataInfoPolyLine query

Figure 1.87. DataInfoPolyLine query



The setup for this query is slightly different than the others. Notice that the DataInfoPolyLine struct must be created using the constructor and given the number of points in the polyline; that the DataInfoPolyLine struct is passed as a parameter (not returned by the method); and finally that the 'L' is capitalized in this name (unlike the usual spelling of polyline).

The following example shows how to extract a polyline from a volume. As usual the example code does not show error checking. In production code the application should check the errorFlag parameter in the returned DataInfoPolyline DataInfoPolyline DataInfoPolyline struct.

// Get subvolume bounds equal to volume dimensions
const SbVec3i32& volDim = pVolData->data.getSize();
const SbBox3i32 subVol( 0,0,0, volDim[0]-1,volDim[1]-1,volDim[2]-1 );

// Polyline starting at voxel 0,63,0 and ending at voxel 127,63,0
// (Same row of voxels as getLine example, but in five segments)
const int numPts = 5;
SbVec3i32 polyline[numPts];
polyline[0].setValue(  0,63,0);
polyline[1].setValue( 31,63,0);
polyline[2].setValue( 63,63,0);
polyline[3].setValue( 95,63,0);
polyline[4].setValue(127,63,0);

// Call with null to get size of data
// Note: Casting “NULL” is required in C++ (else method signature is ambiguous)
int res = 0;
SoLDMDataAccess& access = pVolData->getLdmDataAccess();
SoLDMDataAccess::DataInfoPolyLine info(numPts); // Note constructor required
access.getData( info, res, subVol, numPts, polyline, (SoBufferObject*)NULL );

// 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
access.getData( info, res, subVol, numPts, polyline, pBuffer );

// Access the data then unmap the buffer
unsigned int* p = (unsigned int*)pBuffer->map(SoBufferObject::READ_ONLY);
 . . .
pBuffer->unmap();
// Get subvolume bounds equal to volume dimensions
SbVec3i32 volDim = VolData.data.GetSize();
SbBox3i32 subVol = new SbBox3i32(0, 0, 0, volDim[0] - 1, volDim[1] - 1, volDim[2] - 1);

// Polyline starting at voxel 0,63,0 and ending at voxel 127,63,0
// (Same row of voxels as getLine example, but in five segments)
int numPts = 5;
SbVec3i32[] polyline = new SbVec3i32[numPts];
polyline[0].SetValue(  0, 0, 0);
polyline[1].SetValue( 31, 0, 0);
polyline[2].SetValue( 63, 0, 0);
polyline[3].SetValue( 95, 0, 0);
polyline[4].SetValue(127, 0, 0);

// Call with null to get size of data
// Note constructor required for info struct in this case.
int res = 0;
SoLDMDataAccess access = VolData.GetLdmDataAccess();
SoLDMDataAccess.DataInfoPolyLine info = new SoLDMDataAccess.DataInfoPolyLine(numPts);
access.GetData(info, res, subVol, polyline);

// 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
access.GetData(info, res, subVol, polyline, 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();

The total number of data values returned is DataInfoPolyline DataInfoPolyline DataInfoPolyline .bufferSize divided by the size of the data type (in bytes). But interpreting the information returned in the segmentBufferDim and segmentBufferSize members is a little more complicated. We can consider that each segment of the polyline has two coordinates, although the first coordinate of each segment (after the first one) is the same as the last coordinate of the preceding segment. So each pair of consecutive segments shares one coordinate. VolumeViz only returns the value for the shared coordinate once. So each pair of consecutive segments also shares one data value. But... VolumeViz counts the number of values in each segment as if the shared coordinates were separate. Therefore if you sum the values in the segmentBufferDim array the result is the total number of data values plus the number of segments. Each value in segmentBufferSize is the corresponding value in segmentBufferDim times the size of the data type (in bytes). So likewise the sum of all the values in segmentBufferDim is larger than the actual number of bytes in the buffer (bufferSize).

In the example above, all the segments of the polyline lie on a line (a single row of voxels), so we can easily predict what should be returned by the query. As expected the query returns 128 values and (assuming unsigned integers are 4 bytes long) bufferSize is 512 bytes. The segmentBufferDim and segmentBufferSize members each contain numSegment (4) values. The segmentBufferDim member contains the values: 32, 33, 33, 33. The sum of these values is 132 (number of values plus number of segments). If we consider the returned buffer to be an array, then the value corresponding to polyline[0] (the first coordinate = 0,63,0) is in buffer[0], the value corresponding to polyline[1] (the second coordinate = 31,63,0) is in buffer[31] and so on.