// 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