#include "stratum.h" #include "mindb.h" #include namespace geoworld { StratumView::~StratumView() { { GW_SCOPED_LOCK(atomic); assert(_nViewRefCount == 0); if (_nViewRefCount > 0) throw Ex("Still open views on GeoWorldPage instance"); } } const StratumView * StratumView::createView( const WorldUnit nLeft, const WorldUnit nTop, const WorldUnit nShallow, const WorldUnit nRight, const WorldUnit nBottom, const WorldUnit nDeep ) const { { GW_SCOPED_LOCK(atomic); ++_nViewRefCount; return new StratumView ( &_data, mars::BBox< WorldUnit > (nLeft, nTop, nRight, nBottom), nShallow, nDeep, 0, lod ); } } const StratumView * StratumView::createView( const WorldUnit nLeft, const WorldUnit nTop, const WorldUnit nRight, const WorldUnit nBottom ) const { { GW_SCOPED_LOCK(atomic); ++_nViewRefCount; return new StratumView ( this, mars::BBox< WorldUnit > (nLeft, nTop, nRight, nBottom) ); } } StratumView * StratumView::createView( const WorldUnit nLeft, const WorldUnit nTop, const WorldUnit nShallow, const WorldUnit nRight, const WorldUnit nBottom, const WorldUnit nDeep ) { { GW_SCOPED_LOCK(atomic); ++_nViewRefCount; return new StratumView ( &_data, mars::BBox< WorldUnit > (nLeft, nTop, nRight, nBottom), nShallow, nDeep, 0, lod ); } } StratumView * StratumView::createView( const WorldUnit nLeft, const WorldUnit nTop, const WorldUnit nRight, const WorldUnit nBottom ) { { GW_SCOPED_LOCK(atomic); ++_nViewRefCount; return new StratumView ( this, mars::BBox< WorldUnit > (nLeft, nTop, nRight, nBottom) ); } } void StratumView::fetchViewElements( std::set< GeoStratumField::Element > & st ) const { for (size_t j = 0; j < height; ++j) for (size_t i = 0; i < width; ++i) { GeoHeightMap::Precision zi = (*_data.baseview)(i, j); if (zi >= _z.minimum) { for (size_t c = 0; c < _data.fields.size(); ++c) { const GeoStratumField::View & view = *_data.fields[c]; const GeoStratumField::AltitudePrecision nAlt = view.altitude(i, j); if (zi >= _z.minimum && ((zi - nAlt) <= _z.maximum || c == _data.fields.size() - 1)) st.insert(view.getElement(i, j)); zi -= nAlt; } } else st.insert(_data.fields.front() ->getElement(i, j)); } } void StratumView::fetchViewIndices( std::set< unsigned short > & st ) const { for (size_t j = 0; j < height; ++j) for (size_t i = 0; i < width; ++i) { GeoHeightMap::Precision zi = (*_data.baseview)(i, j); size_t ii = 0; if (zi >= _z.minimum) { for (size_t c = 0; c < _data.fields.size(); ++c) { const GeoStratumField::View & view = *_data.fields[c]; const GeoStratumField::AltitudePrecision nAlt = view.altitude(i, j); if (zi >= _z.minimum && ((zi - nAlt) <= _z.maximum || c == _data.fields.size() - 1)) st.insert(view(i, j).mindex + ii); zi -= nAlt; ii += _counts[c]; } } else st.insert((*_data.fields.front())(i, j).mindex); } } unsigned short StratumView::getIndex (const WorldUnit x, const WorldUnit y, const WorldUnit z) const { assert(z >> lod >= _zBase && (z >> lod) < static_cast< WorldUnit > (_z.delta)); const signed int xlo = static_cast< signed int > (x >> lod), ylo = static_cast< signed int > (y >> lod), zalo = static_cast< signed int > (z >> lod) + _zBasedMin; // TODO: Check base GeoHeightMap::Precision zi = (*_data.baseview)(xlo, ylo); size_t ii = 0; if (zi >= _z.minimum) { for (size_t c = 0; c < _data.fields.size(); ++c) { const GeoStratumField::View & view = *_data.fields[c]; zi -= view.altitude(xlo, ylo); if (zi < zalo) return view(xlo, ylo).mindex + ii; ii += _counts[c]; } return (*_data.fields.back())(xlo, ylo).mindex + ii - _counts.back(); } else return (*_data.fields.front())(xlo, ylo).mindex; } const GeoStratumField::Element & StratumView::getElement( const WorldUnit x, const WorldUnit y, const WorldUnit z ) const { assert(z >> lod >= _zBase && (z >> lod) < static_cast< WorldUnit > (_z.delta)); const signed int xlo = static_cast< signed int > (x >> lod), ylo = static_cast< signed int > (y >> lod), zalo = static_cast< signed int > (z >> lod) + _zBasedMin; // TODO: Check base GeoHeightMap::Precision zi = (*_data.baseview)(xlo, ylo); if (zi >= _z.minimum) { for (size_t c = 0; c < _data.fields.size(); ++c) { const GeoStratumField::View & view = *_data.fields[c]; zi -= view.altitude(xlo, ylo); if (zi < zalo) return view.getElement(xlo, ylo); } return _data.fields.back() ->getElement(xlo, ylo); } else return _data.fields.front() ->getElement(xlo, ylo); } const GeoStratumField::Element & StratumView::getDominantElement( std::vector< unsigned short > & indices ) const { std::sort(indices.begin(), indices.end()); unsigned short countMax = 0, idx = indices[0], idxMax = indices[0], count = 0; for (size_t c = 0; c < indices.size(); ++c) { if (indices[c] != idx) { if (count > countMax) { idxMax = idx; countMax = count; } count = 1; idx = indices[c]; } else ++count; } return getElement(idxMax); } const GeoStratumField::Element & StratumView::getDominantElementVN3( const WorldUnit x, const WorldUnit y, const WorldUnit z ) const { std::vector< unsigned short > indices (6); indices[0] = getIndex(x - _one, y, z); indices[1] = getIndex(x, y - _one, z); indices[2] = getIndex(x, y, z - _one); indices[3] = getIndex(x + _one, y, z); indices[4] = getIndex(x, y + _one, z); indices[5] = getIndex(x, y, z + _one); return getDominantElement(indices); } const GeoStratumField::Element & StratumView::getDominantElementVN( const WorldUnit x, const WorldUnit y ) const { std::vector< unsigned short > indices (4); const signed int xlo = x >> lod, ylo = y >> lod; indices[0] = getIndex(x - _one, y, (static_cast< WorldUnit > ((*_data.baseview)(xlo - 1, ylo)) << lod) - _zBasedMin); indices[1] = getIndex(x, y - _one, (static_cast< WorldUnit > ((*_data.baseview)(xlo, ylo - 1)) << lod) - _zBasedMin); indices[3] = getIndex(x + _one, y, (static_cast< WorldUnit > ((*_data.baseview)(xlo + 1, ylo)) << lod) - _zBasedMin); indices[4] = getIndex(x, y + _one, (static_cast< WorldUnit > ((*_data.baseview)(xlo, ylo + 1)) << lod) - _zBasedMin); return getDominantElement(indices); } void StratumView::releaseView( const StratumView * pView ) const { { GW_SCOPED_LOCK(atomic); delete pView; --_nViewRefCount; } } void StratumView::updateIndexMap() { size_t nInc = 0; // DEPS: _idx0map - Implication made in fetchSurfaceViewIndices() _idx0map.clear(); for (size_t c = 0; c < _data.fields.size(); ++c) { const size_t nLen = _data.fields[c] ->elementCount(); _counts[c] = nLen; for (size_t i = 0; i < nLen; ++i) _idx0map.push_back(std::pair< size_t, size_t > (c, nInc)); nInc += nLen; } } StratumView::StratumView( StratumData * pParentData, const mars::BBox< WorldUnit > & bbox, const WorldUnit z0, const WorldUnit zN, const WorldUnit zBase, const unsigned short nLOD ) : _data( pParentData, static_cast< unsigned short > (bbox.left >> nLOD), static_cast< unsigned short > (bbox.top >> nLOD), static_cast< unsigned short > (bbox.right >> nLOD), static_cast< unsigned short > (bbox.bottom >> nLOD) ), layers(pParentData->fields.size()), _counts(pParentData->fields.size()), width (static_cast< unsigned short > (bbox.getWidth() >> nLOD)), height (static_cast< unsigned short > (bbox.getHeight() >> nLOD)), abswidth (bbox.getWidth()), absheight (bbox.getHeight()), absdepth(zN - z0), _zBase(static_cast< GeoHeightMap::Precision > (zBase >> nLOD)), _zBasedMin(static_cast< GeoHeightMap::Precision > ((z0 - zBase) >> nLOD)), depth(static_cast< unsigned short > ((zN - z0) >> nLOD)), lod(nLOD), _z(static_cast< GeoHeightMap::Precision > (z0 >> nLOD), static_cast< GeoHeightMap::Precision > (zN >> nLOD)), _nViewRefCount(0), _one(1 << nLOD) { assert(zBase >> nLOD > std::numeric_limits< signed short >::lowest()); assert((zN - z0) >> nLOD < 1 << 15); // Must fit into a WORD updateIndexMap(); } StratumView::StratumView(const size_t nLayers, const mars::BBox< WorldUnit > & bbox, const WorldUnit z0, const WorldUnit zN, const WorldUnit zBase, const unsigned short nLOD, const mars::GridType engt /*= mars::Normal*/ ) : _data( nLayers, static_cast< unsigned short > (bbox.getWidth() >> nLOD), static_cast< unsigned short > (bbox.getHeight() >> nLOD), engt ), layers(nLayers), _counts(nLayers), width (static_cast< unsigned short > (bbox.getWidth() >> nLOD)), height (static_cast< unsigned short > (bbox.getHeight() >> nLOD)), abswidth (bbox.getWidth()), absheight (bbox.getHeight()), absdepth(zN - z0), _zBase(static_cast< GeoHeightMap::Precision > (zBase >> nLOD)), _zBasedMin(static_cast< GeoHeightMap::Precision > ((z0 - zBase) >> nLOD)), depth(static_cast< unsigned short > ((zN - z0) >> nLOD)), lod(nLOD), _z(static_cast< GeoHeightMap::Precision > (z0 >> nLOD), static_cast< GeoHeightMap::Precision > (zN >> nLOD)), _nViewRefCount(0), _one(1 << nLOD) { assert(zBase >> nLOD > std::numeric_limits< signed short >::lowest()); assert((zN - z0) >> nLOD < 1 << 15); // Must fit into a WORD } StratumView::StratumView( const StratumView * const pParent, const mars::BBox< WorldUnit > & bbox ) : _data( &pParent->_data, static_cast< unsigned short > (bbox.left >> pParent->lod), static_cast< unsigned short > (bbox.top >> pParent->lod), static_cast< unsigned short > (bbox.right >> pParent->lod), static_cast< unsigned short > (bbox.bottom >> pParent->lod) ), layers(pParent->_data.fields.size()), _counts(pParent->_data.fields.size()), width (static_cast< unsigned short > (bbox.getWidth() >> pParent->lod)), height (static_cast< unsigned short > (bbox.getHeight() >> pParent->lod)), abswidth (bbox.getWidth()), absheight (bbox.getHeight()), absdepth(pParent->absdepth), depth(pParent->depth), lod(pParent->lod), _zBase(pParent->_zBase), _zBasedMin(pParent->_zBasedMin), _z(pParent->_z), _nViewRefCount(0), _one(pParent->_one) { updateIndexMap(); } void StratumView::applyDEM ( const GeoHeightMap::View & hmv, const unsigned short nDEMLOD ) { const unsigned short nDeltaLOD = lod - nDEMLOD; const size_t nInc = 1 << nDeltaLOD; assert(nDEMLOD <= lod); assert(hmv.width << nDEMLOD == width << lod && hmv.height << nDEMLOD == height << lod); if (nInc == 1) (*_data.baseview) << hmv; else { for (size_t j = 0, v = 0; j < absheight; j += nInc, ++v) for (size_t i = 0, u = 0; i < abswidth; i += nInc, ++u) _data.baseview->setn(u, v, hmv(i, j) >> nDeltaLOD); } } mars::Range< WorldUnit > StratumView::getRange() const { double f; WorldUnit nMin = std::numeric_limits< WorldUnit >::max(), nMax = std::numeric_limits< WorldUnit >::min(); for (size_t j = 0; j < height; ++j) for (size_t i = 0; i < width; ++i) { f = (getBase())(i, j); if (f > nMax) nMax = static_cast< WorldUnit > (f); for (StratumData::FieldList::const_iterator k = beginFields(); k != endFields(); ++k) f -= (**k)(i, j).altitude; if (f < nMin) nMin = static_cast< WorldUnit > (f); } return mars::Range< WorldUnit > ((nMin - _zBasedMin) << lod, (nMax - _zBasedMin) << lod); } std::ostream & Stratum::operator >> ( std::ostream & outs ) const { { std::vector< std::string > vsDefs; mars::ObjectStream outs2 (&outs); for (StratumData::FieldList::const_iterator i = beginFields(); i != endFields(); ++i) { for (GeoStratumField::ElementList::const_iterator j = (*i)->beginElements(); j != (*i)->endElements(); ++j) vsDefs.push_back(j->getName()); outs2 << vsDefs; vsDefs.clear(); } } static_cast< const GeoHeightMap & > (this->getBase()) >> outs; for (StratumData::FieldList::const_iterator i = beginFields(); i != endFields(); ++i) { *static_cast< const GeoStratumField * > (&**i) >> outs; } return outs; } std::istream & Stratum::operator << ( std::istream & ins ) { { std::vector< std::string > vsDefs; mars::ObjectStream ins2 (&ins); for (StratumData::FieldList::iterator i = beginFields(); i != endFields(); ++i) { ins2 >> vsDefs; (*i)->clearRegs(); for (std::vector< std::string >::const_iterator j = vsDefs.begin(); j != vsDefs.end(); ++j) (*i)->reg(*j); } } static_cast< GeoHeightMap & > (this->getBase()) << ins; size_t c = 0; for (StratumData::FieldList::iterator i = beginFields(); i != endFields(); ++i, ++c) { *static_cast< GeoStratumField * > (&**i) << ins; } return ins; } Stratum::Stratum( const size_t nLayers, const WorldUnit nWidth, const WorldUnit nHeight, const WorldUnit nDepth, const unsigned short nLOD, const mars::GridType engt /*= mars::Normal*/ ) : StratumView( nLayers, mars::BBox< WorldUnit > (0, 0, nWidth - 1, nHeight - 1), std::numeric_limits< signed short >::min() / 2, std::numeric_limits< signed short >::max() / 2, 0, nLOD, engt ), _nActualDepth(nDepth) { assert((nWidth >> nLOD) < (1 << 16) && (nHeight >> nLOD) < (1 << 16)); // Must be small enough to fit into an unsigned short } void StratumData::operator >> ( StratumData & dest ) const { assert(fields.size() == dest.fields.size()); *baseview >> *dest.baseview; for (size_t c = 0; c < fields.size(); ++c) *fields[c] >> *dest.fields[c]; } void StratumData::operator << ( const StratumData & src ) { assert(fields.size() == src.fields.size()); *baseview << *src.baseview; for (size_t c = 0; c < fields.size(); ++c) *fields[c] << *src.fields[c]; } StratumData::StratumData( StratumData * pParent, const unsigned short nLeft, const unsigned short nTop, const unsigned short nRight, const unsigned short nBottom ) : _pParent(pParent), fields(pParent->fields.size()) { assert(pParent != NULL); baseview = pParent->baseview->createView(nLeft, nTop, nRight, nBottom); for (size_t c = 0; c < fields.size(); ++c) fields[c] = pParent->fields[c] ->createView(nLeft, nTop, nRight, nBottom); } StratumData::StratumData( const size_t nLayers, const unsigned short nWidth, const unsigned short nHeight, const mars::GridType engt /*= mars::Normal*/ ) : _pParent(NULL), fields(nLayers), baseview (new GeoHeightMap(nWidth, nHeight, engt)) { for (size_t c = 0; c < fields.size(); ++c) fields[c] = new GeoStratumField(nWidth, nHeight, engt); } StratumData::~StratumData() { if (_pParent == NULL) { delete baseview; for (FieldList::iterator i = fields.begin(); i != fields.end(); ++i) delete *i; } else { _pParent->baseview->releaseView(baseview); for (size_t c = 0; c < fields.size(); ++c) _pParent->fields[c] ->releaseView(fields[c]); } } void StratumData::copySection( StratumData & dest, const signed int x, const signed int y ) const { assert(fields.size() == dest.fields.size()); *dest.baseview << GeoHeightMap::View::Offset (baseview, x, y); for (size_t c = 0; c < fields.size(); ++c) *dest.fields[c] << GeoStratumField::View::Offset(fields[c], x, y); } }