Class SoLDMDataAccess


  • public class SoLDMDataAccess
    extends Inventor
    Volume data access methods. The Data Access API provides methods to conveniently extract data from a volume. This is useful, for example, to extract data for computation, for segmentation or for display using other primitives. The data is accessible whether the SoVolumeData is part of a scene graph or not. These methods are only valid in LDM mode (which is the default mode). The Data Access API automatically takes advantage of LDM multi-threaded data loading when multiple tiles (not already in cache) are needed to complete the request.

    The Data Access API automatically loads all data required to satisfy the request and can be invoked asynchronously to allow simultaneous loading and computation. The application can request data at any resolution level, e.g. full resolution (level 0) data, independent of the resolution level currently being used for rendering. For some requests, e.g. line and plane, the application can also specify a subvolume (region of interest) that limits the extent of the data request.

    SoLDMDataAccess provides the following data requests:

    • Subvolume: The set of voxels inside a specified subvolume.
    • Plane: The set of voxels intersecting an arbitrary plane.
    • Line: The set of voxels intersecting an arbitrary line.
    • Trace: A column of axis aligned voxels (e.g. a seismic trace).
    • Polyline: The set of voxels intersecting an arbitrary polyline.
    • Tile: Direct access to the tile containing a specified voxel. (This is the best way to query individual voxels. See the method for more information.)

    Each data request returns information struct specific to the request type. For example, SoLDMDataAccess.DataInfoBox is returned by the subvolume request. All these structs contain an errorFlag member containing the result of the request and a bufferSize member containing the amount of data (in bytes) returned. The application should always check these values. Note that even when errorFlag is CORRECT, bufferSize may be zero, meaning no data was returned. This happens, for example, if the specified plane is completely outside the volume.

    The application is responsible for allocating and freeing the memory to store the requested data. Calling the data request method with a null bufferObject will return the size of the memory needed, in bytes, in the bufferSize member of the information struct. Once the buffer is allocated, a second call will extract the data from the volume. Since Open Inventor 8.0 we recommend using the methods that return data into an SoBufferObject. Because this class abstracts access to data stored on different devices it is possible, for example, to conveniently fetch data into CPU memory or directly into GPU memory.

    Each data request can be either synchronous or asynchronous. Synchronous means that all the data will be loaded before the function returns. Asynchronous means that the function will return immediately and you will be notified when the data is actually available. This allows the application to continue to work while the data is being loaded, for example to overlap data loading and computation. Synchronous access is done using the getData methods.

    To do asynchronous access, you must create a new class derived from SoLDMDataAccess and implement your own version of the endRequest method. Begin a request by calling the appropriate requestData method. This method will return a requestId.

    • If the requestID is positive, this value will be passed to the endRequest method when the requested data is ready, and can then be used with the appropriate getRequestedData method to complete the transaction.
    • If the requestID is negative, the data is already in memory. In this case endRequest will not be called, and -requestID (a positive value) should be used with the getRequestedData method. The data inside the destBuffer will be aligned as in the original volume. The info structure contains additional information about the current request including error status, coordinates (for line and polyline requests), tile id (for tile requests), etc.

    Three different modes are available to control how data is requested from the volume reader when the necessary tiles are not already present in LDM cache memory:

    • CACHE: When data is requested, the data is copied from the LDM cache (tiles in memory) if possible. If any required tiles are not in the LDM cache, LDM will load those tiles into cache, then copy the data from the cache. This is the default behavior.
    • DIRECT: When data is requested, the data is copied from the LDM cache (tiles in memory) if possible. If any required tiles are not in the LDM cache, LDM will request the data directly from the volume reader without loading any tiles into the LDM cache memory. This could potentially be slower than the previous mode, but uses less I/O and less memory. It allows getting data without loading the whole tile into memory, for example when the requested data is a slice.
    • DIRECT_AND_PREFETCH: This mode is a mix of the previous modes. When data is requested, the data is copied from the LDM cache if possible. If any required tiles are not in the LDM cache, LDM will request the data directly from the volume reader to avoid reading complete tiles immediately, but will also schedule the relevant tiles to be loaded into the LDM cache memory asynchronously. This may improve performance overall if the application is likely to load additional data from these tiles.

    Note that DIRECT access requires that specific methods are implemented in the data set reader, for example readXSliceInTile (see SoLDMReader and SoVolumeReader). The default LDM reader implements these methods for the standard Open Inventor LDM file format. Custom LDM readers may need to be enhanced.

    EXAMPLE

    The following example shows how to extract a subvolume from a given volume.

     // Create a volume data object and attach to a data file
     SoVolumeData volData = new SoVolumeData();
     volData.fileName.setValue( "<path-to-filename>" );
     
     // Call with null to get size of data
     int      resolution = 0; // Full resolution data
     SbBox3i32 subvolume = new SbBox3i32(0,0,0, 63,63,63);
     SoLDMDataAccess access = volData.getLdmDataAccess();
     SoLDMDataAccess.DataInfoBox info;
     info = access.getData( resolution, subvolume, (SoBufferObject)null );
     
     if (info.errorFlag == SoLDMDataAccess.ErrorValues.CORRECT.getValue()) {
         // 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( resolution, subvolume, buffer );
     
         // Access the data
         IntBuffer ibuffer = buffer.asIntBuffer();
         int value = ibuffer.get(0);            
     }

    • Constructor Detail

      • SoLDMDataAccess

        public SoLDMDataAccess()
        Constructor. Application must call the setDataSet method before using any other methods of this object.
    • Method Detail

      • endRequest

        public void endRequest​(int requestId)
        This method is called each time a data request is finished, meaning that the data requested asynchronously is now available. This method should be overloaded in a derived class in order to handle loaded data.
      • getData

        public SoLDMDataAccess.DataInfoBox getData​(int resolution,
                                                   SbBox3i32 subVolume)
        Convenient method to get the required size of the application buffer: call getData(resolution, subvolume, null).
      • getData

        public SoLDMDataAccess.DataInfoBox getData​(int resolution,
                                                   SbBox3i32 subVolume,
                                                   SoBufferObject bufferObj)
        Given a subvolume in voxel coordinates, copies the associated data into an application buffer.

        The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...). Note: The data is copied.

        All information is returned in the object DataInfoBox. Call this method with buffer = null to get the required size of the application buffer (in the bufferSize member of DataInfoBox).

      • getData

        public SoLDMDataAccess.DataInfoPlane getData​(int resolution,
                                                     SbBox3i32 subVolume,
                                                     SbPlane plane)
        Convenient method to get the required size of the application buffer: call getData(resolution, subvolume, plane, null).
      • getData

        public SoLDMDataAccess.DataInfoPlane getData​(int resolution,
                                                     SbBox3i32 subVolume,
                                                     SbPlane plane,
                                                     SoBufferObject bufferObj)
        Given a subvolume in voxel coordinates and a plane, copies the data intersecting the plane and the subvolume into an application buffer

        The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...) Note: The data is copied.

        All information is returned in the object DataInfoPlane. Call this method with buffer = null to get the required size of the application buffer (in the bufferSize member of DataInfoPlane).

      • getData

        public SoLDMDataAccess.DataInfoLine getData​(int resolution,
                                                    SbBox3i32 subVolume,
                                                    SbLine line)
        Convenient method to get the required size of the application buffer: call getData(resolution, subvolume, line, null).
      • getData

        public SoLDMDataAccess.DataInfoLine getData​(int resolution,
                                                    SbBox3i32 subVolume,
                                                    SbLine line,
                                                    SoBufferObject bufferObj)
        Given a subvolume in voxel coordinates and a line, copies the data intersecting the line and the subvolume into an application buffer.

        The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...) Note: The data is copied.

        All information is returned in the object DataInfoLine. Call this method with buffer = null to get the required size of the application buffer (in the bufferSize member of DataInfoLine).

      • getData

        public SoLDMDataAccess.DataInfoTrace getData​(int resolution,
                                                     SbBox3i32 subVolume,
                                                     SbVec2i32 coord)
        Convenient method to get the required size of the application buffer: call getData(resolution, subvolume, coord, null).
      • getData

        public SoLDMDataAccess.DataInfoTrace getData​(int resolution,
                                                     SbBox3i32 subVolume,
                                                     SbVec2i32 coord,
                                                     SoBufferObject bufferObj)
        Data values in a single seismic trace (a row of voxels along the volume X axis) are copied into an application buffer.

        The trace is identified by a YZ voxel coordinate. The range of values returned is the intersection of the trace with the specified subvolume.
        The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...). Note: The data is copied.

        Returns a DataInfoTrace object containing errorFlag, bufferSize (number of bytes) and bufferDimension (number of values).
        Call this method with buffer = null to get the required size of the application buffer (in the bufferSize member of DataInfoTrace).

      • getData

        public SoLDMDataAccess.DataInfo getData​(int resolution,
                                                SbVec3i32 dataPosition)
        Returns a reference to the block of data which contains the voxel at dataPosition. The pointer will be valid until #releaseData is called or the associated volumeData is destroyed. The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...).
        See Also:
        Note: The data is not copied.
      • getRequestedDataBox

        public SoLDMDataAccess.DataInfoBox getRequestedDataBox​(int requestId)
        Returns the data associated with @B requestID@b into @B infoBox@b.
      • getRequestedDataLine

        public SoLDMDataAccess.DataInfoLine getRequestedDataLine​(int requestId)
        Returns the data associated with @B requestID@b into @B infoLine@b.
      • getRequestedDataPlane

        public SoLDMDataAccess.DataInfoPlane getRequestedDataPlane​(int requestId)
        Returns the data associated with @B requestID@b into @B infoPlane@b.
      • getRequestedDataTrace

        public SoLDMDataAccess.DataInfoTrace getRequestedDataTrace​(int requestId)
        Returns the data associated with @B requestID @b into @B infoTrace @b.
      • requestData

        public int requestData​(int resolution,
                               SbBox3i32 box,
                               SoBufferObject bufferObj)
        Given a subvolume in voxel coordinates, asynchronously copies the associated data into an application buffer.
        The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...). NOTE: The data is copied.

        Returns a request ID. If requestID is positive, this value will be passed to the endRequest method when the requested data is ready, and can then be used with the getRequestedData method to complete the transaction. If requestID is negative, the data is already in memory, so endRequest will not be called, and -requestID (a positive value) should be used with the getRequestedData method.

        Call this method with buffer = NULL to get the required size of the application buffer.

        Limitations :

        • it is not currently possible to query the value of a single voxel using this method. The smallest query possible is 8 voxels (a subvolume 2 x 2 x 2).
        • it is not possible to perform an asynchronous data request within GLRender action
      • isTileUniform

        public double isTileUniform​(int resolution,
                                    SbVec3i32 dataPosition)
        Returns true if the tile containing the data located at position dataPosition (IJK voxel coordinates) at the specified resolution is uniform (all voxels have the same value). Returns false if not or if accessing the tile failed (e.g. invalid coordinates). If true then uniformValue contains the uniform value of the tile, else it is undefined.

        Since:
        Open Inventor 9.1

      • releaseData

        public void releaseData​(SoLDMTileID tileID)
        Tells VolumeViz that this block of data (returned by getData above) is no longer in use by the application.
      • getDataSet

        public SoDataSet getDataSet()
        Returns the associated dataset.
      • setDataSet

        public void setDataSet​(SoDataSet v)
        Set dataset to fetch data from.
      • voxelToXYZ

        public SbBox3f voxelToXYZ​(SbBox3i32 boxIJK)
        Converts the specified box in voxel coordinates (I,J,K) to geometric coordinates (X,Y,Z). The geometric coordinates are expressed in "extent" space, where voxel coordinates are mapped to the box defined by the volume extent.

        Correctly converts coordinates that are outside the volume extent, but the resulting voxel coordinate is outside the volume dimensions.

        voxelToXYZ(const SbVec3i32&) const

        XYZToVoxel(const SbVec3f&) const

        XYZToVoxel(const SbBox3f&) const

        Since:
        Open Inventor 10.8

      • XYZToVoxel

        public SbBox3i32 XYZToVoxel​(SbBox3f boxXYZ)
        Converts the specified box in geometric coordinates (X,Y,Z) to voxel coordinates (I,J,K). The geometric coordinates are expressed in "extent" space, where voxel coordinates are mapped to the box defined by the volume extent.

        Correctly converts coordinates that are outside the volume extent, but the resulting voxel coordinate is outside the volume dimensions.

        voxelToXYZ(const SbVec3i32&) const

        voxelToXYZ(const SbBox3i32&) const

        XYZToVoxel(const SbVec3f&) const

        Since:
        Open Inventor 10.8

      • voxelToXYZ

        public SbVec3f voxelToXYZ​(SbVec3i32 dataPosition)
        Converts a voxel coordinate (I,J,K) to a geometry coordinate (X,Y,Z). The geometric coordinates are expressed in "extent" space, where voxel coordinates are mapped to the box defined by the volume extent.

        Correctly converts coordinates that are outside the volume extent, but the resulting voxel coordinate is outside the volume dimensions.

        voxelToXYZ(const SbBox3i32&) const

        XYZToVoxel(const SbVec3f&) const

        XYZToVoxel(const SbBox3f&) const

      • XYZToVoxel

        public SbVec3i32 XYZToVoxel​(SbVec3f dataPosition)
        Converts a geometry coordinate (X,Y,Z) to a voxel coordinate (I,J,K). The geometric coordinates are expressed in "extent" space, where voxel coordinates are mapped to the box defined by the volume extent.

        Correctly converts coordinates that are outside the volume extent, but the resulting voxel coordinate is outside the volume dimensions.

        voxelToXYZ(const SbVec3i32&) const

        voxelToXYZ(const SbBox3i32&) const

        XYZToVoxel(const SbBox3f&) const

      • setGetDataMode

        public boolean setGetDataMode​(SoLDMDataAccess.GetDataModes getDataMode)
        Set the GetDataMode.
        This controls how data is requested from the volume reader when the necessary tiles are not already present in LDM cache memory. Default is CACHE.
      • requestData

        public int requestData​(int resolution,
                               SbBox3i32 subVolume0,
                               SbVec2i32 coord,
                               SoBufferObject bufferObj)
        Data values in a single seismic trace (a row of voxels along the volume X axis) are asynchronously copied into an application buffer.
        The trace is identified by a YZ voxel coordinate. The range of values returned is the intersection of the trace with the specified subvolume (which may be the full dimensions of the volume). The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...). NOTE: The data is copied.

        Returns a request ID. If requestID is positive, this value will be passed to the endRequest method when the requested data is ready, and can then be used with the getRequestedData method to complete the transaction. If requestID is negative, the data is already in memory, so endRequest will not be called, and -requestID (a positive value) should be used with the getRequestedData method.

        Call this method with buffer = NULL to get the required size of the application buffer (in the bufferSize member of DataInfoTrace). Limitations :

        • it is not possible to perform an asynchronous data request within GLRender action
      • requestData

        public int requestData​(int resolution,
                               SbBox3i32 subVolume,
                               SbPlane plane,
                               SoBufferObject bufferObj)
        Given a subvolume in voxel coordinates and a plane, asynchronously copies the data intersecting the plane and the subvolume into an application buffer.
        The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...). NOTE: The data is copied.

        Returns a request ID. If requestID is positive, this value will be passed to the endRequest method when the requested data is ready, and can then be used with the getRequestedData method to complete the transaction. If requestID is negative, the data is already in memory, so endRequest will not be called, and -requestID (a positive value) should be used with the getRequestedData method.

        Call this method with buffer = NULL to get the required size of the application buffer (in the bufferSize member of DataInfoPlane). Limitations :

        • it is not possible to perform an asynchronous data request within GLRender action
      • requestData

        public int requestData​(int resolution,
                               SbBox3i32 subVolume0,
                               SbLine line,
                               SoBufferObject bufferObj)
        Given a subvolume in voxel coordinates and a line, asynchronously copies the data intersecting the line and the subvolume into an application buffer.
        The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...). NOTE: The data is copied.

        Returns a request ID. If requestID is positive, this value will be passed to the endRequest method when the requested data is ready, and can then be used with the getRequestedData method to complete the transaction. If requestID is negative, the data is already in memory, so endRequest will not be called, and -requestID (a positive value) should be used with the getRequestedData method.

        Call this method with buffer = NULL to get the required size of the application buffer (in the bufferSize member of DataInfoLine). Limitations :

        • it is not possible to perform an asynchronous data request within GLRender action
      • requestData

        public int requestData​(int resolution,
                               SbBox3i32 subVolume,
                               SbVec3i32[] polyline,
                               SoBufferObject bufferObj)
        Given a subvolume in voxel coordinates and a stack of line, asynchronously copies the data intersecting each line and the subvolume into an application buffer.
        The resolution is the power of 2 of the desired subsampling level (0:1/1, 1:1/2, 2:1/4, ...). NOTE: The data is copied.

        Returns a request ID. If requestID is positive, this value will be passed to the endRequest method when the requested data is ready, and can then be used with the getRequestedData method to complete the transaction. If requestID is negative, the data is already in memory, so endRequest will not be called, and -requestID (a positive value) should be used with the getRequestedData method.

        Call this method with buffer = NULL to get the required size of the application buffer (in the bufferSize member of DataInfoLine). Limitations :

        • it is not possible to perform an asynchronous data request within GLRender action