1.10.7. Get plane

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:

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

DataInfoPlanequery

Figure 1.88. DataInfoPlanequery


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);
  }