region2d.hh
来自「Motion JPEG编解码器源代码」· HH 代码 · 共 1,013 行 · 第 1/2 页
HH
1,013 行
#ifndef __REGION2D_H__#define __REGION2D_H__// This file (C) 2004 Steven Boswell. All rights reserved.// Released to the public under the GNU General Public License.// See the file COPYING for more information.// Region2D tracks a 2-dimensional region of arbitrary points.//// It's the base class for more specific implementations of regions,// which only have to be compatible in the interface sense -- they// don't have to support being called properly through a base-class// pointer, they only have to be interchangeable when used as template// parameters. Region2D contains the interface definition & all the// code that will work with any implementation of regions.#include "Status_t.h"#include <iostream>// The 2-dimensional region class. Parameterized by the numeric type// to use for point indices, and the numeric type to use to count the// contained number of points.// This was an attempt to create a generic base class for 2-dimensional// regions. It can't be done without making many methods virtual, which// would prevent them from being inlined, and thus would impact// performance. Many methods do have a non-region-specific// implementation, just not enough.// The commented-out method prototypes are methods to be implemented by// subclasses. Not all methods have to be implemented, depending on// whether it's appropriate for the subclass, but that may impact how// widely the subclass may be used.template <class INDEX, class SIZE>class Region2D{public: // An extent within the region, representing a continuous series of // points in a horizontal line. Used by iterator classes to return // successive parts of the region. class Extent { public: INDEX m_tnY, m_tnXStart, m_tnXEnd; // The y-index, and the start/end x-indices, of the extent. // Note that m_tnXEnd is technically one past the end. Extent() {} // Default constructor. Extent (INDEX a_tnY, INDEX a_tnXStart, INDEX a_tnXEnd) : m_tnY (a_tnY), m_tnXStart (a_tnXStart), m_tnXEnd (a_tnXEnd) {} // Initializing constructor. bool operator== (const Extent &a_rOther) const { return (m_tnY == a_rOther.m_tnY && m_tnXStart == a_rOther.m_tnXStart && m_tnXEnd == a_rOther.m_tnXEnd) ? true : false; } // Equality operator. bool operator!= (const Extent &a_rOther) const { return (m_tnY != a_rOther.m_tnY || m_tnXStart != a_rOther.m_tnXStart || m_tnXEnd != a_rOther.m_tnXEnd) ? true : false; } // Inequality operator. inline bool operator < (const Extent &a_rOther) const; // Less-than operator. }; Region2D(); // Default constructor. Must be followed by Init(). template <class REGION> Region2D (Status_t &a_reStatus, const REGION &a_rOther); // Copy constructor. //void Init (Status_t &a_reStatus); // Initializer. Must be called on default-constructed regions. template <class REGION> void Assign (Status_t &a_reStatus, const REGION &a_rOther); // Make the current region a copy of the other region. virtual ~Region2D(); // Destructor. //SIZE NumberOfPoints (void) const; // Return the total number of points contained by the region. //void Clear (void); // Clear the region, emptying it of all extents. //void Union (Status_t &a_reStatus, INDEX a_tnY, INDEX a_tnXStart, // INDEX a_tnXEnd); // Add the given horizontal extent to the region. Note that // a_tnXEnd is technically one past the end of the extent. template <class REGION, class REGION_TEMP> void UnionDebug (Status_t &a_reStatus, INDEX a_tnY, INDEX a_tnXStart, INDEX a_tnXEnd, REGION_TEMP &a_rTemp); // Add the given horizontal extent to the region. Note that // a_tnXEnd is technically one past the end of the extent. // Exhaustively (i.e. slowly) verifies the results, using a // much simpler algorithm. // Requires the use of a temporary region, usually of the // final subclass' type, in order to work. (Since that can't // be known at this level, a template parameter is included for // it.) template <class REGION> void Union (Status_t &a_reStatus, const REGION &a_rOther); // Make the current region represent the union between itself // and the other given region. template <class REGION, class REGION_O, class REGION_TEMP> void UnionDebug (Status_t &a_reStatus, REGION_O &a_rOther, REGION_TEMP &a_rTemp); // Make the current region represent the union between itself // and the other given region. // Exhaustively (i.e. slowly) verifies the results, using a // much simpler algorithm. // Requires the use of a temporary region, usually of the // final subclass' type, in order to work. (Since that can't // be known at this level, a template parameter is included for // it.) //void Merge (Status_t &a_reStatus, INDEX a_tnY, INDEX a_tnXStart, // INDEX a_tnXEnd); // Merge this extent into the current region. // The new extent can't intersect any of the region's existing // extents (including being horizontally contiguous). //void Merge (Region2D<INDEX,SIZE> &a_rOther); // Merge the other region into ourselves, emptying the other // region. Like Union(), but doesn't allocate any new memory. // Also, the other region can't intersect any of the region's // existing extents (including being horizontally contiguous), // and both regions must use the same allocator. //void Move (Region2D<INDEX,SIZE> &a_rOther); // Move the contents of the other region into the current // region. // The current region must be empty. template <class REGION> bool CanMove (const REGION &a_rOther) const { return false; } // Returns true if the other region's contents can be moved // into the current region. // (False by default; subclasses will have to implement // specialized methods that explain when this is true.) template <class REGION> void Move (REGION &a_rOther) { assert (false); } // Let clients know we can't move extents between regions of // different types by default. //void Intersection (Status_t &a_reStatus, // const Region2D<INDEX,SIZE> &a_rOther); // Make the current region represent the intersection between // itself and the other given region. //void Subtract (Status_t &a_reStatus, INDEX a_tnY, // INDEX a_tnXStart, INDEX a_tnXEnd); // Subtract the given horizontal extent from the region. Note // that a_tnXEnd is technically one past the end of the extent. template <class REGION_TEMP> void SubtractDebug (Status_t &a_reStatus, INDEX a_tnY, INDEX a_tnXStart, INDEX a_tnXEnd, REGION_TEMP &a_rTemp); // Subtract the given horizontal extent from the region. Note // that a_tnXEnd is technically one past the end of the extent. // Exhaustively (i.e. slowly) verifies the results, using a // much simpler algorithm. // Requires the use of a temporary region, usually of the // final subclass' type, in order to work. (Since that can't // be known at this level, a template parameter is included for // it.) template <class REGION> void Subtract (Status_t &a_reStatus, const REGION &a_rOther); // Subtract the other region from the current region, i.e. // remove from the current region any extents that exist in the // other region. template <class REGION, class REGION_O, class REGION_TEMP> void SubtractDebug (Status_t &a_reStatus, REGION_O &a_rOther, REGION_TEMP &a_rTemp); // Subtract the other region from the current region, i.e. // remove from the current region any extents that exist in the // other region. // Exhaustively (i.e. slowly) verifies the results, using a // much simpler algorithm. // Requires the use of a temporary region, usually of the // final subclass' type, in order to work. (Since that can't // be known at this level, a template parameter is included for // it.) //typedef ... ConstIterator; //ConstIterator Begin (void) const { return m_setExtents.Begin(); } //ConstIterator End (void) const { return m_setExtents.End(); } // Allow our client to iterate through the extents & get their // values. //bool DoesContainPoint (INDEX a_tnY, INDEX a_tnX); // Returns true if the region contains the given point. //bool DoesContainPoint (INDEX a_tnY, INDEX a_tnX, // ConstIterator &a_ritHere); // Returns true if the region contains the given point. // Backpatches the extent that contains the point, or the // extent before where it should be. // A structure that helps implement flood-fills. Clients should // create a derived (or structurally compatible) class that, at a // minimum, describes whether a new point should be added to the // region. (The definition of this class follows the definition of // Region2D<>.) template <class REGION> class FloodFillControl; template <class CONTROL> void FloodFill (Status_t &a_reStatus, CONTROL &a_rControl, bool a_bVerify); // Flood-fill the current region. All points bordering the // current region are tested for inclusion; if a_bVerify is // true, all existing region points are tested first. template <class REGION> void MakeBorder (Status_t &a_reStatus, const REGION &a_rOther); // Make the current region represent the border of the other // region, i.e. every pixel that's adjacent to a pixel that's // in the region, but isn't already in the region. void UnionSurroundingExtents (Status_t &a_reStatus, INDEX a_tnY, INDEX a_tnXStart, INDEX a_tnXEnd); // Add all extents surrounding the given extent. // Used by FloodFill() and MakeBorder().};template <class INDEX, class SIZE>std::ostream &operator<< (std::ostream &a_rOut, const Region2D<INDEX,SIZE> &a_rRegion);// The flood-fill-control class.template <class INDEX, class SIZE>template <class REGION>class Region2D<INDEX,SIZE>::FloodFillControl{public: // (Although these fields are public, they should be considered // opaque to the client.) REGION m_oToDo; // Extents that still need to be be tested. REGION m_oAlreadyDone; // Extents that have been tested. REGION m_oNextToDo; // Extents contiguous with those that have just been added // to the flood-filled area. typedef typename REGION::ConstIterator ConstIterator; typedef typename REGION::Extent Extent; // The iterator/extent type for running through the above // regions.public: FloodFillControl(); // Default constructor. Must be followed by a call to Init(). FloodFillControl (Status_t &a_reStatus); // Initializing constructor. void Init (Status_t &a_reStatus); // Initializer. Must be called on default-constructed objects. // (May not be valid to call on subclasses, depending on // whether more parameters are needed for its Init().) // Methods to be redefined by clients implementing specific // flood-fills. bool ShouldUseExtent (Extent &a_rExtent) { return true; } // Return true if the flood-fill should examine the given // extent. Clients should redefine this to define their own // criteria for when extents should be used, and to modify the // extent as needed (e.g. to clip the extent to a bounding box). bool IsPointInRegion (INDEX a_tnX, INDEX a_tnY) { return false; } // Returns true if the given point should be included in the // flood-fill. Clients must redefine this to explain their // flood-fill criteria.};#if 0// I'm not sure how to do this yet. If the template just takes "class// REGION", I think it'll try to match everything in the world, and// that wouldn't be good. But how to do this???// Also, iterators aren't actually defined at the Region2D<> level.// Print the region's contents.template <class INDEX, class SIZE>std::ostream &operator<< (std::ostream &a_rOut, const Region2D<INDEX,SIZE> &a_rRegion){ Region2D<INDEX,SIZE>::ConstIterator itHere; // Used to loop through the region. // Print the region header. a_rOut << "( "; // Print each extent. for (itHere = Begin(); itHere != End(); ++itHere) { // Print the extent. a_rOut << '[' << ((*itHere).m_tnY) << ',' << ((*itHere).m_tnXStart) << '-' << ((*itHere).m_tnXEnd) << "] "; } // Print the region trailer. a_rOut << ")" return a_rOut;}#endif// Default constructor. Must be followed by Init().template <class INDEX, class SIZE>Region2D<INDEX,SIZE>::Region2D(){ // Nothing to do.}// Copy constructor.template <class INDEX, class SIZE>template <class REGION>Region2D<INDEX,SIZE>::Region2D (Status_t &a_reStatus, const REGION &a_rOther){ // Make sure they didn't start us off with an error. assert (a_reStatus == g_kNoError); // Copy all the extents. for (typename REGION::ConstIterator itHere = a_rOther.Begin(); itHere != a_rOther.End(); ++itHere) { Merge (a_reStatus, (*itHere).m_tnY, (*itHere).m_tnXStart, (*itHere).m_tnXEnd); if (a_reStatus != g_kNoError) return; }}// Make the current region a copy of the other region.template <class INDEX, class SIZE>template <class REGION>voidRegion2D<INDEX,SIZE>::Assign (Status_t &a_reStatus, const REGION &a_rOther){ // Make sure they didn't start us off with an error. assert (a_reStatus == g_kNoError); // Assign the other region's extents to ourselves. Region2D<INDEX,SIZE>::Clear(); for (typename REGION::ConstIterator itHere = a_rOther.Begin(); itHere != a_rOther.End(); ++itHere) { Merge (a_reStatus, (*itHere).m_tnY, (*itHere).m_tnXStart, (*itHere).m_tnXEnd); if (a_reStatus != g_kNoError) return; }}// Destructor.template <class INDEX, class SIZE>Region2D<INDEX,SIZE>::~Region2D(){ // Nothing to do.}// Add the given horizontal extent to the region.template <class INDEX, class SIZE>template <class REGION, class REGION_TEMP>voidRegion2D<INDEX,SIZE>::UnionDebug (Status_t &a_reStatus, INDEX a_tnY, INDEX a_tnXStart, INDEX a_tnXEnd, REGION_TEMP &a_rTemp){ typename REGION::ConstIterator itHere; typename REGION_TEMP::ConstIterator itHereO; INDEX tnX; // Used to loop through points. // Make sure they didn't start us off with an error. assert (a_reStatus == g_kNoError); // Calculate the union. a_rTemp.Assign (a_reStatus, *this); if (a_reStatus != g_kNoError) return; a_rTemp.Union (a_reStatus, a_tnY, a_tnXStart, a_tnXEnd); if (a_reStatus != g_kNoError) return; // Loop through every point in the result, make sure it's in // one of the two input regions. for (itHereO = a_rTemp.Begin(); itHereO != a_rTemp.End(); ++itHereO) { const Extent &rHere = *itHereO; for (tnX = rHere.m_tnXStart; tnX < rHere.m_tnXEnd; ++tnX) { if (!((rHere.m_tnY == a_tnY && (tnX >= a_tnXStart && tnX < a_tnXEnd)) || this->DoesContainPoint (rHere.m_tnY, tnX))) goto error; } } // Loop through every point in the original region, make sure // it's in the result. for (itHere = this->Begin(); itHere != this->End(); ++itHere) { const Extent &rHere = *itHere; for (tnX = rHere.m_tnXStart; tnX < rHere.m_tnXEnd; ++tnX) { if (!a_rTemp.DoesContainPoint (rHere.m_tnY, tnX)) goto error; } } // Loop through every point in the added extent, make sure it's in // the result. for (tnX = a_tnXStart; tnX < a_tnXEnd; ++tnX) { if (!a_rTemp.DoesContainPoint (a_tnY, tnX)) goto error; } // The operation succeeded. Commit it. Assign (a_reStatus, a_rTemp); if (a_reStatus != g_kNoError) return; // All done. return;error: // Handle deviations. fprintf (stderr, "Region2D::Union() failed\n"); fprintf (stderr, "Input region:\n"); PrintRegion (*this); fprintf (stderr, "Input extent: [%d,%d-%d]\n", int (a_tnY), int (a_tnXStart), int (a_tnXEnd)); fprintf (stderr, "Result:\n"); PrintRegion (a_rTemp); assert (false);}// Make the current region represent the union between itself// and the other given region.template <class INDEX, class SIZE>template <class REGION>voidRegion2D<INDEX,SIZE>::Union (Status_t &a_reStatus, const REGION &a_rOther){ typename REGION::ConstIterator itHere; // Where we are in the other region's extents. // Make sure they didn't start us off with an error. assert (a_reStatus == g_kNoError); // Run through the extents in the other region, add them to the // current region. for (itHere = a_rOther.Begin(); itHere != a_rOther.End(); ++itHere) { // Add this extent to the current region. Union (a_reStatus, (*itHere).m_tnY, (*itHere).m_tnXStart, (*itHere).m_tnXEnd);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?