This request returns all the voxels intersected by a plane, 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 IJK (voxel) coordinates and an SbPlane SbPlane specifying the plane. Although an SbPlane SbPlane is defined using floating point values, the plane is specified in IJK (voxel) coordinates. The plane can be defined using three points, a normal vector plus a point on the plane, or a normal vector plus the distance from the origin (this is the internal definition of the plane in all cases). For example a plane constructed using a normal vector and distance, like this: SbPlane SbPlane (SbVec3f SbVec3f (0,0,1),0), will return the first Z slice of the volume. Of course the plane can have any orientation and position.
This request can be used to get the voxel values associated with a VolumeViz slice primitive. This may be useful for computation or to display the slice “unfolded” in a separate window. For an SoOrthoSlice SoOrthoSlice SoOrthoSlice , set the normal vector to the slice axis and the distance to the slice number. For an SoVolumeSkin SoVolumeSkin SoVolumeSkin , treat each face similar to SoOrthoSlice SoOrthoSlice SoOrthoSlice . For an SoObliqueSlice SoObliqueSlice SoObliqueSlice , convert the slice’s plane from XYZ coordinates to IJK coordinates (described below). For an SoFenceSlice SoFenceSlice SoFenceSlice , treat each segment of the fence similar to an SoObliqueSlice SoObliqueSlice SoObliqueSlice .
The request returns a DataInfoPlane struct containing:
errorFlag – Set to CORRECT if the request succeeded.
bufferSize – Returns the required total buffer size in bytes.
bufferDimension – Returns the 2D dimensions of the buffer in voxels.
numPolygonPoints – Returns the number of points in the polygon formed by intersecting the plane with the subvolume. If the plane is parallel to at least one axis of the volume there will be four points, but in the general case there will be six points.
polygonCoord – Returns the four or six points in the polygon shown in the diagram below.
quadCoord – Returns the four points in the quadrangle shown in the diagram below.
uAxis – Returns an index (0 = X, 1 = Y, 2 = Z) indicating the first dimension of the returned buffer.
vAxis – Returns an index (0 = X, 1 = Y, 2 = Z) indicating the second dimension of the returned buffer.
The data type is not included in this struct, but can be queried from the volume data node as shown in a previous section.
The following example shows how to extract a plane 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 DataInfoBox DataInfoBox DataInfoBox 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 ); // This plane corresponds to the second Z slice of the volume SbVec3f pos(0,0,1); SbVec3f normal(0,0,1); SbPlane plane( normal, pos ); // 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::DataInfoPlane info; info = access.getData( res, subVol, plane, (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 info = access.getData( res, subVol, plane, pBuffer ); // Access the data then unmap the buffer unsigned int* pData = (unsigned int*)pBuffer->map(SoBufferObject::READ_ONLY); unsigned int value = pData[0]; . . . 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 ); // This plane corresponds to the second Z slice of the volume SbVec3f pos = new SbVec3f(0,0,1); SbVec3f normal = new SbVec3f(0,0,1); SbPlane plane = new SbPlane( normal, pos ); // Call with null to get size of data int res = 0; SoLDMDataAccess access = VolData.GetLdmDataAccess(); SoLDMDataAccess.DataInfoPlane info; info = access.GetData( res, subVol, plane ); // 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, subVol, plane, 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();
// Get subvolume bounds equal to volume dimensions SbVec3i32 volDim = volData.data.getSize(); SbBox3i32 subVol = new SbBox3i32( 0,0,0, volDim.getX()-1,volDim.getY()-1,volDim.getZ()-1 ); // This plane corresponds to the second Z slice of the volume SbVec3f pos = new SbVec3f(0,0,1); SbVec3f normal = new SbVec3f(0,0,1); SbPlane plane = new SbPlane( normal, pos ); // Call with null to get size of data int res = 0; SoLDMDataAccess access = volData.getLdmDataAccess(); SoLDMDataAccess.DataInfoPlane info; info = access.getData(res, subVol, plane, 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, subVol, plane, buffer); // Access the data IntBuffer ibuffer = buffer.asIntBuffer(); int value = ibuffer.get(0); . . .
Now suppose we want to extract the data on the plane defined by an SoObliqueSlice SoObliqueSlice SoObliqueSlice node. The code will be the same as the example above. We just need to convert the plane definition from XYZ coordinates to IJK (voxel) coordinates. The following example code shows how to do that. Note that SoLDMDataAccess SoLDMDataAccess SoLDMDataAccess provides a utility method XYZToVoxel(), but it may be useful to see how the conversion is done (and also that method returns an SbVec3i32 SbVec3i32 , but SbVec3f SbVec3f is more convenient here).
/////////////////////////////////////////////////////////////////////// // Convert point in XYZ coordinates to IJK (voxel) coordinates. // Scale and translate (remember that IJK space min is always 0,0,0). SbVec3f pointToIJK( SoVolumeData* pVolData, SbVec3f Pxyz ) { SbVec3i32 dim = pVolData->data.getSize(); float xmin,ymin,zmin,xmax,ymax,zmax; pVolData->extent.getValue().getBounds( xmin,ymin,zmin, xmax,ymax,zmax ); SbVec3f Pijk( (Pxyz[0] - xmin) * (dim[0] / (xmax-xmin)), (Pxyz[1] - ymin) * (dim[1] / (ymax-ymin)), (Pxyz[2] - zmin) * (dim[2] / (zmax-zmin)) ); return Pijk; } /////////////////////////////////////////////////////////////////////// // Convert plane in XYZ coordinates to IJK (voxel) coordinates. // Normal vector will be the same. Just computation position of plane. SbPlane planeToIJK( SoVolumeData* pVolData, SbPlane plane ) { SbVec3f Nxyz = plane.getNormal(); float Dxyz = plane.getDistanceFromOrigin(); // Pt on plane in xyz space SbVec3f Pxyz = Nxyz * Dxyz; // Pt on plane in IJK space SbVec3f Pijk = pointToIJK( pVolData, Pxyz ); // Return plane in IJK space return SbPlane(Nxyz,Pijk); }
///////////////////////////////////////////////////////////////////////
// Convert point in XYZ coordinates to IJK (voxel) coordinates.
// Scale and translate (remember that IJK space min is always 0,0,0).
public SbVec3f pointToIJK(SoVolumeData VolData, SbVec3f Pxyz)
{
SbVec3i32 dim = VolData.data.GetSize();
SbVec3f min = VolData.extent.Value.Min;
SbVec3f max = VolData.extent.Value.Max;
SbVec3f Pijk = new SbVec3f(
(Pxyz.X - min.X) * (dim.X / (max.X - min.X)),
(Pxyz.Y - min.Y) * (dim.Y / (max.Y - min.Y)),
(Pxyz.Z - min.Z) * (dim.Z / (max.Z - min.Z)) );
return Pijk;
}
///////////////////////////////////////////////////////////////////////
// Convert plane in XYZ coordinates to IJK (voxel) coordinates.
// Normal vector will be the same. Just compute position of plane.
public SbPlane planeToIJK(SoVolumeData pVolData, SbPlane plane)
{
SbVec3f Nxyz = plane.Normal;
float Dxyz = plane.DistanceFromOrigin;
// Pt on plane in xyz space
SbVec3f Pxyz = Nxyz * Dxyz;
// Pt on plane in IJK space
SbVec3f Pijk = pointToIJK(pVolData, Pxyz);
// Return plane in IJK space
return new SbPlane(Nxyz, Pijk);
}
///////////////////////////////////////////////////////////////////////
// Convert point in XYZ coordinates to IJK (voxel) coordinates.
// Scale and translate (remember that IJK space min is always 0,0,0).
public static SbVec3f pointToIJK(SoVolumeData VolData, SbVec3f Pxyz)
{
SbVec3i32 dim = VolData.data.getSize();
SbVec3f min = VolData.extent.getValue().getMin();
SbVec3f max = VolData.extent.getValue().getMax();
SbVec3f Pijk = new SbVec3f(
(Pxyz.getX() - min.getX()) * (dim.getX() / (max.getX() - min.getX())),
(Pxyz.getY() - min.getY()) * (dim.getY() / (max.getY() - min.getY())),
(Pxyz.getZ() - min.getZ()) * (dim.getZ() / (max.getZ() - min.getZ())) );
return Pijk;
}
///////////////////////////////////////////////////////////////////////
// Convert plane in XYZ coordinates to IJK (voxel) coordinates.
// Normal vector will be the same. Just compute position of plane.
public static SbPlane planeToIJK(SoVolumeData VolData, SbPlane plane)
{
SbVec3f Nxyz = plane.getNormal();
float Dxyz = plane.getDistanceFromOrigin();
// Pt on plane in xyz space
SbVec3f Pxyz = new SbVec3f(Nxyz);
Pxyz.multiply(Dxyz);
// Pt on plane in IJK space
SbVec3f Pijk = pointToIJK(VolData, Pxyz);
// Return plane in IJK space
return new SbPlane(Nxyz, Pijk);
}