#ifndef __GEOWORLDPNGDEM_H__ #define __GEOWORLDPNGDEM_H__ #include #include #include #include #include "vmpdg.h" #include "gwtypedefs.h" namespace geoworld { class PNGDEM { private: template< typename T > class HeightMapAdapter : public mars::ScalarFieldView< T > { public: HeightMapAdapter (mars::ScalarFieldView< T > & src) : mars::ScalarFieldView< T >(src) {} HeightMapAdapter (const mars::ScalarFieldView< T > & src) : mars::ScalarFieldView< T >(src) {} void operator >> (PNGDEM & pngdem) const; }; template< typename E, typename T > class ElementalFieldAdapter : public ElementalFieldView< E, T > { public: ElementalFieldAdapter (ElementalFieldView< E, T > & src) : ElementalFieldView< E, T > (src) {} ElementalFieldAdapter (const ElementalFieldView< E, T > & src) : ElementalFieldView< E, T > (src) {} void operator >> (PNGDEM & pngdem) const; }; public: typedef std::vector< unsigned char > PNGBuffer; enum Format { Grayscale = 0, RGBMultiples = 1 }; PNGDEM(); inline void setFormat (const Format fmt) { _fmt = fmt; } inline void setDimensions(const unsigned short nWidth, const unsigned short nHeight) { _nWidth = nWidth; _nHeight = nHeight; _inbuff.resize(_nWidth * _nHeight * 4); } inline unsigned short getWidth () const { return _nWidth; } inline unsigned short getHeight () const { return _nHeight; } inline Format getFormat () const { return _fmt; } mars::ptr< GeoHeightMap > createHeightMap (const float fScale = 1.0f) const; void retrieveLine (GeoHeightMap::Precision * pnData, const unsigned short nY, const float fScale = 1.0f) const; inline PNGBuffer & buffer () { return _inbuff; } inline const PNGBuffer & buffer () const { return _inbuff; } void addCrosshairPoint (const unsigned short x, const unsigned short y, int idx = -1, const float fAlpha = 1.0f); void addCrosshairPoint (const unsigned short x, const unsigned short y, const float fRed, const float fGreen, const float fBlue, const float fAlpha = 1.0f); inline unsigned int nextCrosshair() { return ++_nCrossIdx; } template< typename T > void operator << ( const mars::ScalarFieldView< T > & view ) { setDimensions(view.width, view.height); HeightMapAdapter< T > (view) >> *this; } template< typename E, typename T > void operator << ( const ElementalFieldView< E, T > & view ) { setDimensions(view.width, view.height); ElementalFieldAdapter< E, T > (view) >> *this; } GeoHeightMap::Precision convertPixelComponentsToElevation( const unsigned char b, const unsigned char g, const unsigned char r ) const; unsigned char convertElevationToPixelComponent( const GeoHeightMap::Precision val, const unsigned bit ) const; void operator << (std::ifstream & input); std::ostream & operator >> (std::ostream & output); private: class CrosshairPoint { public: const unsigned short x, y; const float red, green, blue, alpha; inline CrosshairPoint (const unsigned short x, const unsigned short y, const float red, const float green, const float blue, const float alpha = 1.0f) : x(x), y(y), red(red), green(green), blue(blue), alpha(alpha) {} }; typedef std::list< CrosshairPoint > Crosshairs; Crosshairs _crosshairs; PNGBuffer _inbuff; Format _fmt; unsigned int _nCrossIdx; unsigned short _nWidth, _nHeight; mars::Range< GeoHeightMap::Precision > getRange (const GeoHeightMap::Precision * pnData, const unsigned short nWidth, const unsigned short nHeight) const; void flushCrosshairs(); }; template< typename T > void PNGDEM::HeightMapAdapter::operator >> ( PNGDEM & pngdem ) const { mars::RangeX< T > mmpDEMRange = mars::ScalarFieldView::range(); PNGDEM::PNGBuffer & buff = pngdem.buffer(); const double fRGBMultScaler = static_cast< double > (1 << 11); const unsigned short height = mars::ScalarFieldView::height, width = mars::ScalarFieldView::width; for (unsigned short j = 0; j < height; ++j) { const T * pnLine = mars::ScalarFieldView::line(j); for (unsigned short i = 0; i < width; ++i) { const unsigned int nIdxBase = j * width * 4 + i * 4; switch (pngdem.getFormat()) { case PNGDEM::Grayscale: buff[nIdxBase + 0] = buff[nIdxBase + 1] = buff[nIdxBase + 2] = static_cast ((static_cast (pnLine[i]) - static_cast (mmpDEMRange.minimum)) / static_cast (mmpDEMRange.delta) * 255.0); break; case PNGDEM::RGBMultiples: { const GeoHeightMap::Precision val = static_cast< GeoHeightMap::Precision > ( static_cast< double > (pnLine[i] - mmpDEMRange.minimum) / static_cast< double > (mmpDEMRange.delta) * fRGBMultScaler ); buff[nIdxBase + 0] = pngdem.convertElevationToPixelComponent(val, 0); buff[nIdxBase + 1] = pngdem.convertElevationToPixelComponent(val, 1); buff[nIdxBase + 2] = pngdem.convertElevationToPixelComponent(val, 2); } break; } buff[nIdxBase + 3] = 255; } } } template< typename E, typename T > void PNGDEM::ElementalFieldAdapter::operator >> ( PNGDEM & pngdem ) const { mars::Range< MPDGVecType< T > > mmpDEMRange = mars::ScalarFieldView::range(); const double fdrng = mmpDEMRange.maximum.altitude - mmpDEMRange.minimum.altitude; PNGDEM::PNGBuffer & buff = pngdem.buffer(); const unsigned short height = mars::ScalarFieldView::height, width = mars::ScalarFieldView::width; for (unsigned short j = 0; j < height; ++j) { const MPDGVecType< T > * pnLine = mars::ScalarFieldView::line(j); for (unsigned short i = 0; i < width; ++i) { const unsigned int nIdxBase = j * width * 4 + i * 4; const unsigned char nAlt = static_cast< unsigned char > ( static_cast< double > (pnLine[i].altitude - mmpDEMRange.minimum.altitude) / fdrng * 256.0f ); const unsigned short nMIndexCycle = (pnLine[i].mindex % 7) + 1; buff[nIdxBase + 0] = (nMIndexCycle & (1 << 0)) ? nAlt : 0; buff[nIdxBase + 1] = (nMIndexCycle & (1 << 1)) ? nAlt : 0; buff[nIdxBase + 2] = (nMIndexCycle & (1 << 2)) ? nAlt : 0; buff[nIdxBase + 3] = 255; } } } } #endif