// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 #pragma once namespace frantic { namespace volumetrics { namespace levelset { // Forward declaration of the rle_index_spec classes. class rle_index_spec; struct run_data; /** * This rle_run_iterator is designed to provide convenient iteration over all the runs for * one scanline in an rle_index_spec. * * Here's an example usage for one run: * *
* // Make i the begin iterator for the scanline being processed.
* rle_run_iterator i(ris, ris.y_to_b(y), ris.z_to_c(z));
* // Make ie the past-the-end iterator using the default constructor.
* rle_run_iterator ie;
* for( ; i != ie; ++i ) {
* // i.get_xmin() is the starting X coordinate
* // i.get_xsize() is the length of the run
* // i.get_data_index() is the data index or region code for the run
* }
* // At loop end, i.get_xmin() is the X coordinate at the very end of the processed scanline (assuming a non-empty
* scanline)
* // (NOTE that ie.get_xmin() is *NOT* that same X coordinate, note how it was created without knowledge of the
* scanline)
*
*
* Here's how you would typically use it to visit all runs in an rle_index_spec:
*
*
* const rle_index_spec& ris = ...;
* boundbox3 outerBounds = ris.outer_bounds();
* for( int z = outerBounds.zminimum(); z <= outerBounds.zmaximum(); ++z ) {
* for( int y = outerBounds.yminimum(); y <= outerBounds.ymaximum(); ++y ) {
* rle_run_iterator i(ris, ris.y_to_b(y), ris.z_to_c(z)), ie;
* for( ; i != ie; ++i ) {
* // i.get_xmin() is the starting X coordinate
* // i.get_xsize() is the length of the run
* // i.get_data_index() is the data index or region code for the run
* }
* // Here, i.get_xmin() is the X coordinate at the very end of the processed scanline (assuming a non-empty
* scanline)
* // (NOTE that ie.get_xmin() is *NOT* that same X coordinate, note how it was created without knowledge of the
* scanline)
* }
* }
*
*/
class rle_run_iterator {
const run_data *m_rd, *m_rdEnd;
int m_exteriorRegionCode;
boost::int32_t m_dataIndex;
boost::int32_t m_xStart, m_xSize;
public:
/**
* Constructs an iterator which will iterate over the runs in the scanline of the given BC coordinates.
*
* @param ris The rle_index_spec for run iteration.
* @param b The b coordinate for the scanline.
* @param c The c coordinate for the scanline.
*/
rle_run_iterator( const rle_index_spec& ris, int b, int c );
/**
* Constructs the 'past-the-end' iterator.
*/
rle_run_iterator();
/**
* Pre-increments the iterator.
*
* @todo Do both pre- and post-increment correctly
*/
rle_run_iterator& operator++();
/**
* For equality comparison, we don't check everything. But, the subset of what we
* check is enough to determine equality. Note that we're checking the things most likely
* to be different first, to be able to return false as quickly as possible in the common
* cases.
*/
bool operator==( const rle_run_iterator& iter ) const { return m_rd == iter.m_rd; }
bool operator!=( const rle_run_iterator& iter ) const { return !operator==( iter ); }
/**
* This gets the data index of the run, or the region code of the run if it
* is an undefined run.
*/
boost::int32_t get_data_index() const { return m_dataIndex; }
/**
* This returns the minimum X coordinate of the run.
*/
boost::int32_t get_xmin() const { return m_xStart; }
/**
* This returns the maximum X coordinate of the run.
*/
boost::int32_t get_xmax() const { return m_xStart + m_xSize - 1; }
/**
* This returns the size of the run in the X dimension.
*/
boost::int32_t get_xsize() const { return m_xSize; }
/**
* This gets the data index of the next run, or the region code of the run if it
* is an undefined run. It's more costly than retrieving the current index due
* to the extra indirection.
*/
boost::int32_t get_next_run_data_index() const {
if( m_rd == m_rdEnd )
return m_exteriorRegionCode;
const run_data* next_rd = m_rd + 1;
if( next_rd != m_rdEnd )
return next_rd->dataIndex;
else
return m_exteriorRegionCode;
}
};
} // namespace levelset
} // namespace volumetrics
} // namespace frantic