00001 /* 00002 * The information in this file is 00003 * Copyright(c) 2007 Ball Aerospace & Technologies Corporation 00004 * and is subject to the terms and conditions of the 00005 * GNU Lesser General Public License Version 2.1 00006 * The license text is available from 00007 * http://www.gnu.org/licenses/lgpl.html 00008 */ 00009 00010 #ifndef DATA_ACCESSOR_IMPL_H 00011 #define DATA_ACCESSOR_IMPL_H 00012 00013 #include "AppConfig.h" 00014 #include "RasterElement.h" 00015 #include "RasterPager.h" 00016 #include "DataRequest.h" 00017 #include "TypesFile.h" 00018 #include "ObjectResource.h" 00019 #include <exception> 00020 #include <stdexcept> 00021 00022 class RasterPage; 00023 00024 typedef double (*convertToDouble)(const void*, int, ComplexComponent); 00025 typedef int64_t (*convertToInteger)(const void*, int, ComplexComponent); 00026 00027 /** 00028 * Provides a generic interface to the dataset. 00029 * 00030 * This class provides an efficient, generic interface to the raw dataset. To 00031 * provide efficient access to the raw data, range checking can not occur 00032 * within this class. It is up to the user of the DataAcessor to make 00033 * sure the bounds of the dataset are not exceeded. This class provides 00034 * row-major access to the data. All of the standard interleaves (BIP, 00035 * BIL, or BSQ) are row-major, so this class doesn't provide column-major access. 00036 * 00037 * @code 00038 * The following is the in the order for the dataset: 00039 * BIP: ( Maj, Mid, Min = Row, Col, Band ) 00040 * BIL: ( Maj, Mid, Min = Row, Band, Col (NOT IMPLEMENTED)) 00041 * BSQ: ( Maj, Mid, Min = Band, Row, Col ) 00042 * @endcode 00043 * 00044 * This class is not instantiated by a plug-in directly. The plug-in developer 00045 * can get access to this class through the RasterElement::getDataAccessor() 00046 * method. One example is to call getDataAccessor() with a DataRequest with 00047 * concurrentColumns == total columns, concurrentBands == 1, and 00048 * the default interleave. 00049 * 00050 * @code 00051 * for each row 00052 * for each column 00053 * value = *getColumn() 00054 * // Do something useful with the value. 00055 * nextColumn() 00056 * nextRow() 00057 * @endcode 00058 * 00059 * @see RasterElement::getDataAccessor() 00060 */ 00061 class DataAccessorImpl 00062 { 00063 public: 00064 /** 00065 * DataAcessorImpl constructor. 00066 * 00067 * This is the constructor for the data accessor. This constructor should 00068 * not be called directly from a plug-in. Use RasterElement::getDataAccessor() 00069 * to get a DataAccessor instance. 00070 * 00071 * @param pPage 00072 * A pointer to a page of the raw dataset. The size and ownership 00073 * of the data pointed to by mpPage is dependent on the interleave, 00074 * the concurrent elements and whether the data is loaded into memory 00075 * or not. 00076 * @param pRequest 00077 * The DataRequest for this accessor. DataAccessorImpl takes ownership 00078 * of the request. 00079 * @param concurrentRows 00080 * The number of rows provided by the RasterPager. 00081 * @param interLineBytes 00082 * The number of bytes following a row of data in the dataset. This includes bytes that come before the next line. 00083 * @param concurrentColumns 00084 * The number of columns provided by the RasterPager. 00085 * @param concurrentBands 00086 * The number of bands provided by the RasterPager. 00087 * @param elementSize 00088 * The size of the individual type referenced in the dataset 'matrix'. For 00089 * example, sizeof(long), sizeof(float), etc. 00090 * @param pRasterElement 00091 * This is a reference to the RasterElement class "owning" this DataAccessor. 00092 */ 00093 DataAccessorImpl(char *pPage, DataRequest *pRequest, size_t concurrentRows, 00094 size_t interLineBytes, size_t concurrentColumns, 00095 size_t concurrentBands, 00096 size_t elementSize, RasterElement* pRasterElement) : 00097 mbValid(true), 00098 mpPage(pPage), 00099 mpRasterElement(pRasterElement), 00100 mpRasterPage(NULL), 00101 mpRasterPager(NULL), 00102 mpRequest(pRequest), 00103 mConcurrentRows(concurrentRows), 00104 mConcurrentColumns(concurrentColumns), 00105 mConcurrentBands(concurrentBands), 00106 mCurrentRow(0), 00107 mCurrentColumn(0), 00108 mRowOffset(0), 00109 mColumnOffset(0), 00110 mRefCount(0), 00111 mConvertToDoubleFunc(NULL), 00112 mConvertToIntegerFunc(NULL) 00113 { 00114 if (pPage == NULL || mpRasterElement == NULL || mpRequest.get() == NULL) 00115 { 00116 throw std::logic_error("DataAccessorImpl constructor received NULL pointer"); 00117 } 00118 mAccessorRow = mpRequest->getStartRow().getActiveNumber(); 00119 mAccessorColumn = mpRequest->getStartColumn().getActiveNumber(); 00120 mAccessorBand = mpRequest->getStartBand().getActiveNumber(); 00121 updateDataSizes(elementSize, interLineBytes); 00122 } 00123 00124 /** 00125 * DataAcessorImpl destructor. 00126 */ 00127 ~DataAccessorImpl() 00128 { 00129 if ( (mpRasterPager) && (mpRasterPage) ) 00130 { 00131 mpRasterPager->releasePage(mpRasterPage); 00132 } 00133 } 00134 00135 /** 00136 * Gets a row of values. 00137 * 00138 * This method returns a pointer to the first element in an array that is 00139 * guaranteed to be at least (concurrent columns * number of bands) in size 00140 * for BIP data and (concurrent columns) in size for BSQ data. 00141 * 00142 * @return Pointer to the raw block of row data from the dataset. 00143 */ 00144 inline void *getRow() 00145 { 00146 return &mpPage[mRowOffset]; 00147 } 00148 00149 /** 00150 * Advances to the next row in the dataset. 00151 * 00152 * This method increments to the next row based on the interleave 00153 * BIP, BSQ, or BIL. 00154 * 00155 * @param resetColumn 00156 * Whether or not to reset the column to the beginning column of the accessor. 00157 */ 00158 inline void nextRow(bool resetColumn=true) 00159 { 00160 ++mCurrentRow; 00161 mRowOffset += mRowSize; 00162 if (resetColumn) 00163 { 00164 mCurrentColumn = mColumnOffset = 0; 00165 } 00166 updateIfNeeded(); 00167 } 00168 00169 /** 00170 * Advances to a succeeding row in the dataset. 00171 * 00172 * This method increments to a later row based on the interleave 00173 * BIP, BSQ, or BIL. 00174 * 00175 * @param count 00176 * The number of rows to advance 00177 * @param resetColumn 00178 * Whether or not to reset the column to the beginning column of the accessor. 00179 */ 00180 inline void nextRow(int count, bool resetColumn=true) 00181 { 00182 if (count==1) 00183 { 00184 nextRow(); 00185 } 00186 else 00187 { 00188 mCurrentRow+=count; 00189 mRowOffset += mRowSize*count; 00190 if (resetColumn) 00191 { 00192 mCurrentColumn=mColumnOffset=0; 00193 } 00194 updateIfNeeded(); 00195 } 00196 } 00197 00198 /** 00199 * Gets a column of values. 00200 * 00201 * This method returns a pointer to the first element in an array 00202 * that is guaranteed to be at least the number of bands in size 00203 * for BIP data and one in size for BSQ data. 00204 * 00205 * @return Pointer to the raw block of column data from the data set. 00206 */ 00207 inline void *getColumn() 00208 { 00209 return &mpPage[mRowOffset + mColumnOffset]; 00210 } 00211 00212 /** 00213 * Returns the data for the current column position as a double. 00214 * 00215 * @param iIndex 00216 * The number of elements past the current column position to access. 00217 * No bounds checking is performed on the provided index. 00218 * @param component 00219 * For complex data, this specifies the component of the complex 00220 * data that should be returned. If an invalid enum value is used 00221 * for complex data, a value of 0 will be returned. For non-complex data, this 00222 * value is ignored. 00223 * @return The value at the given iIndex past the current column, returned as a double. 00224 */ 00225 inline double getColumnAsDouble(int iIndex = 0, ComplexComponent component = COMPLEX_MAGNITUDE) const 00226 { 00227 return mConvertToDoubleFunc(&mpPage[mRowOffset + mColumnOffset], iIndex, component); 00228 } 00229 00230 /** 00231 * Returns the data for the current column position as an integer. 00232 * This method will truncate the value if the underlying data is stored in floating point. 00233 * 00234 * @param iIndex 00235 * The number of elements past the current column position to access. 00236 * No bounds checking is performed on the provided index. 00237 * @param component 00238 * For complex data, this specifies the component of the complex 00239 * data that should be returned. If an invalid enum value is used 00240 * for complex data, a value of 0 will be returned. For non-complex data, this 00241 * value is ignored. 00242 * @return The value at the given iIndex past the current column, returned as an integer. 00243 */ 00244 int64_t getColumnAsInteger(int iIndex = 0, ComplexComponent component = COMPLEX_MAGNITUDE) const 00245 { 00246 return mConvertToIntegerFunc(&mpPage[mRowOffset + mColumnOffset], iIndex, component); 00247 } 00248 00249 /** 00250 * Advances to the next column in the dataset. 00251 * 00252 * This method increments to the next column based on the interleave 00253 * BIP, BSQ, or BIL. 00254 */ 00255 inline void nextColumn() 00256 { 00257 ++mCurrentColumn; 00258 mColumnOffset += mColumnSize; 00259 } 00260 00261 /** 00262 * Advances to a succeeding column in the dataset. 00263 * 00264 * This method increments to a later column based on the interleave 00265 * BIP, BSQ, or BIL. 00266 * 00267 * @param count 00268 * The number of columns to advance. 00269 */ 00270 inline void nextColumn(int count) 00271 { 00272 if (count==1) 00273 { 00274 nextColumn(); 00275 } 00276 else 00277 { 00278 mCurrentColumn+=count; 00279 mColumnOffset += mColumnSize*count; 00280 } 00281 } 00282 00283 /** 00284 * Jumps to the specified pixel in the current band. 00285 * 00286 * This method updates the current offset to the given pixel at row, column 00287 * in the current band. 00288 * 00289 * @param row 00290 * The row to access in the current band. This must be non-negative 00291 * and less than the total number of rows. 00292 * @param column 00293 * The column to access in the current band. This must be 00294 * non-negative and less than the total number of columns. 00295 */ 00296 inline void toPixel(int row, int column) 00297 { 00298 mCurrentRow = row-mAccessorRow; 00299 mCurrentColumn = column-mAccessorColumn; 00300 mRowOffset = mCurrentRow * mRowSize; 00301 mColumnOffset = mCurrentColumn * mColumnSize; 00302 updateIfNeeded(); 00303 } 00304 00305 /** 00306 * Returns the RasterElement associated with this DataAccessor. 00307 * 00308 * @return Returns the RasterElement associated with this class. 00309 */ 00310 inline RasterElement *getAssociatedRasterElement() 00311 { 00312 return mpRasterElement; 00313 } 00314 00315 /** 00316 * Returns whether this is a valid data accessor. 00317 * 00318 * A valid data accessor means that calls to getRow() and getColumn() will point 00319 * to a valid location in memory. This method can be called between nextRow() 00320 * and getRow() or getColumn() calls. 00321 * 00322 * @return Returns whether this data accessor is valid, and subsequent calls to 00323 * getRow() or getColumn() are valid pointers in memory. 00324 * 00325 * @see DataAccessor::isValid() 00326 */ 00327 inline bool isValid() const 00328 { 00329 return mbValid; 00330 } 00331 00332 /** 00333 * Increases the number of users of this data accessor. 00334 * 00335 * This is simple reference counting mechanism to track the number 00336 * of users of the data accessor. 00337 * 00338 * @return Returns the current number of users of this data accessor. 00339 */ 00340 inline int incrementRefCount() 00341 { 00342 mRefCount++; 00343 return mRefCount; 00344 } 00345 00346 /** 00347 * Decreases the number of users of this data accessor. 00348 * 00349 * This is simple reference counting mechanism to track the number 00350 * of users of the data accessor. 00351 * 00352 * @return Returns the current number of users of this data accessor. 00353 */ 00354 inline int decrementRefCount() 00355 { 00356 mRefCount--; 00357 return mRefCount; 00358 } 00359 00360 /** 00361 * Access the size in bytes of a row of data. 00362 * 00363 * This includes the number of bytes of actual data in a row 00364 * and excludes preline and postline bytes. 00365 * 00366 * @note If using this information to access an entire row 00367 * of data with getRow(), you must ensure that the DataAccessor's 00368 * concurrent columns (and concurrent bands if the accessor is BIP) 00369 * is equal to the number of columns in the data set. 00370 * 00371 * @return The number of bytes in a row of data excluding preline and postline bytes. 00372 */ 00373 inline size_t getRowSize() const 00374 { 00375 return mRowSize - mInterlineBytes; 00376 } 00377 00378 /** 00379 * Access the number of columns available concurrently. 00380 * 00381 * @return The number of concurrent columns. 00382 * 00383 * @see getRow() 00384 */ 00385 inline size_t getConcurrentColumns() const 00386 { 00387 return mConcurrentColumns; 00388 } 00389 00390 private: 00391 friend class RasterElementImp; 00392 00393 /** 00394 * Jumps to the next column and row. 00395 * 00396 * This method enables the DataAccessor to update the view into the dataset 00397 * or read in the next block of data, if necessary. 00398 */ 00399 inline void updateIfNeeded() 00400 { 00401 if (mCurrentRow >= mConcurrentRows) 00402 { 00403 if (mpRasterElement == NULL) 00404 { 00405 throw std::logic_error("DataAccessor back-pointer to data cube has become corrupted"); 00406 } 00407 mpRasterElement->incrementDataAccessor(*this); 00408 mCurrentRow = 0; 00409 mRowOffset = 0; 00410 } 00411 } 00412 00413 /** 00414 * Calculate the column and row size depending on the interleave format 00415 * and number of concurrentColumns, concurrentRows and concurrentBands. 00416 * 00417 * @param elementSize 00418 * the number of bytes needed to represent a single pixel in memory. 00419 * 00420 * @param interLineBytes 00421 * the number of bytes between each line that do not contain 00422 * raw data. This includes bytes which come before the next line. 00423 */ 00424 void updateDataSizes(size_t elementSize, size_t interLineBytes) 00425 { 00426 mInterlineBytes = interLineBytes; 00427 switch(mpRequest->getInterleaveFormat()) 00428 { 00429 case BIP: 00430 mColumnSize = elementSize * mConcurrentBands; 00431 mRowSize = mColumnSize * mConcurrentColumns + interLineBytes; 00432 break; 00433 case BIL: 00434 mColumnSize = elementSize; 00435 mRowSize = mColumnSize * mConcurrentColumns * mConcurrentBands + interLineBytes; 00436 break; 00437 case BSQ: 00438 mColumnSize = elementSize; 00439 mRowSize = mColumnSize * mConcurrentColumns + interLineBytes; 00440 break; 00441 default: 00442 throw std::logic_error("DataAccessorImpl constructor received unknown interleave"); 00443 } 00444 } 00445 00446 bool mbValid; 00447 char *mpPage; 00448 RasterElement *mpRasterElement; 00449 RasterPage* mpRasterPage; 00450 RasterPager* mpRasterPager; 00451 FactoryResource<DataRequest> mpRequest; 00452 size_t mConcurrentRows; // Number of rows currently available in memory at once. 00453 size_t mConcurrentColumns; // Number of columns currently available in memory at once. 00454 size_t mConcurrentBands; // Number of bands currently available in memory at once. 00455 size_t mCurrentRow; // Current processing row 00456 size_t mCurrentColumn; // Current processing column 00457 size_t mRowSize; // Size of a full row 00458 size_t mColumnSize; // Size of a full column 00459 size_t mRowOffset; // Row offset into the cube 00460 size_t mColumnOffset; // Column offset into the cube 00461 size_t mInterlineBytes; // Number of bytes of non-data between rows 00462 00463 size_t mAccessorColumn; 00464 size_t mAccessorRow; 00465 size_t mAccessorBand; 00466 00467 int mRefCount; 00468 convertToDouble mConvertToDoubleFunc; 00469 convertToInteger mConvertToIntegerFunc; 00470 }; 00471 00472 #endif