#include "PNGDEM.h" #include #include #include namespace geoworld { PNGDEM::PNGDEM() : _fmt(RGBMultiples), _nCrossIdx(0) {} mars::Range< GeoHeightMap::Precision > PNGDEM::getRange( const GeoHeightMap::Precision * pnData, const unsigned short nWidth, const unsigned short nHeight ) const { size_t nLen = nWidth * nHeight; GeoHeightMap::Precision nMin = std::numeric_limits< GeoHeightMap::Precision > ::max(), nMax = std::numeric_limits< GeoHeightMap::Precision > ::lowest(); while (nLen--) { if (pnData[nLen] > nMax) nMax = pnData[nLen]; if (pnData[nLen] < nMin) nMin = pnData[nLen]; } return mars::Range< GeoHeightMap::Precision > (nMin, nMax); } GeoHeightMap::Precision PNGDEM::convertPixelComponentsToElevation( const unsigned char b, const unsigned char g, const unsigned char r ) const { return static_cast< GeoHeightMap::Precision > ( static_cast< unsigned long > (b) * (1 << 2) + static_cast< unsigned long > (g) * (1 << 1) + static_cast< unsigned long > (r) * (1 << 0) ); } unsigned char PNGDEM::convertElevationToPixelComponent( const GeoHeightMap::Precision val, const unsigned bit ) const { const unsigned nMask = 1 << bit, nMult = val / 256; return ((256 - 1) - (val % 256)) * ((nMult & nMask) >> bit) + (val % 256) * (((nMult + 1) & nMask) >> bit); } void PNGDEM::addCrosshairPoint( const unsigned short x, const unsigned short y, int idx /*= -1*/, const float fAlpha /*= 1.0f*/ ) { if (idx < 0) idx = _nCrossIdx++; const float r = (idx % 3) / 2.0f, g = ((idx + 1) % 3) / 2.0f, b = ((idx + 2) % 3) / 2.0f; assert(fAlpha <= 1.0f && fAlpha >= 0.0f); addCrosshairPoint(x, y, r, g, b, fAlpha); } void PNGDEM::addCrosshairPoint( const unsigned short x, const unsigned short y, const float fRed, const float fGreen, const float fBlue, const float fAlpha /*= 1.0f*/ ) { _crosshairs.push_back(CrosshairPoint(x, y, fRed, fGreen, fBlue, fAlpha)); } void PNGDEM::operator << ( std::ifstream & input ) { std::streamsize nSize = 0; if (input.seekg(0, std::ios::end).good()) nSize = input.tellg(); if (input.seekg(0, std::ios::beg).good()) nSize -= input.tellg(); assert(nSize <= std::numeric_limits< unsigned int >::max()); std::vector rgbaData (nSize); if (nSize > 0) input.read(reinterpret_cast< char * > (&rgbaData[0]), nSize); unsigned int width, height; lodepng::decode(_inbuff, width, height, rgbaData); _nWidth = width; _nHeight = height; } std::ostream & PNGDEM::operator >> ( std::ostream & output ) { std::vector raw; flushCrosshairs(); lodepng::encode(raw, _inbuff, _nWidth, _nHeight); output.write(reinterpret_cast< char * > (&raw[0]), raw.size()); return output; } mars::ptr< GeoHeightMap > PNGDEM::createHeightMap(const float fScale /*= 1.0f*/) const { mars::ptr< GeoHeightMap > phm = new GeoHeightMap(_nWidth, _nHeight); GeoHeightMap & hm = *phm; unsigned int c = 0; for (std::vector< unsigned char >::const_iterator i = _inbuff.begin(); i != _inbuff.end(); ++i) { const unsigned int nX = c % _nWidth, nY = c / _nWidth; switch (_fmt) { case Grayscale: hm(nX, nY) = static_cast< GeoHeightMap::Precision > (static_cast< float > (*i++ + *i++ + *i++) / 3.0f * fScale); break; case RGBMultiples: hm(nX, nY) = static_cast< GeoHeightMap::Precision > (static_cast< float > (convertPixelComponentsToElevation(*i++, *i++, *i++)) * fScale); break; } ++c; } return phm; } void PNGDEM::retrieveLine( GeoHeightMap::Precision * pnData, const unsigned short nY, const float fScale /*= 1.0f*/ ) const { const unsigned int nLen = (nY + 1) * _nWidth; for (unsigned int c = nY * _nWidth, i = 0; c < nLen; ++c, ++i) { switch (_fmt) { case Grayscale: pnData[i] = static_cast< GeoHeightMap::Precision > (static_cast< float > (_inbuff[c++] + _inbuff[c++] + _inbuff[c++]) / 3.0f * fScale); break; case RGBMultiples: pnData[i] = static_cast< GeoHeightMap::Precision > (static_cast< float > (convertPixelComponentsToElevation(_inbuff[c++], _inbuff[c++], _inbuff[c++])) * fScale); break; } } } void PNGDEM::flushCrosshairs() { for (Crosshairs::const_iterator i = _crosshairs.begin(); i != _crosshairs.end(); ++i) { if (i->x > 0 && i->y > 0 && i->x - 1 < _nWidth && i->y - 1 < _nHeight) { const unsigned char cRed = static_cast< unsigned char > (i->red * 255.0f), cGreen = static_cast< unsigned char > (i->green * 255.0f), cBlue = static_cast< unsigned char > (i->blue * 255.0f), cAlpha = static_cast< unsigned char > (i->alpha * 255.0f); _inbuff[i->y * _nWidth * 4 + i->x * 4 + 0] = cRed; _inbuff[i->y * _nWidth * 4 + i->x * 4 + 1] = cGreen; _inbuff[i->y * _nWidth * 4 + i->x * 4 + 2] = cBlue; _inbuff[i->y * _nWidth * 4 + i->x * 4 + 3] = cAlpha; if (i->y > 0) { _inbuff[(i->y - 1) * _nWidth * 4 + i->x * 4 + 0] = cRed; _inbuff[(i->y - 1) * _nWidth * 4 + i->x * 4 + 1] = cGreen; _inbuff[(i->y - 1) * _nWidth * 4 + i->x * 4 + 2] = cBlue; _inbuff[(i->y - 1) * _nWidth * 4 + i->x * 4 + 3] = cAlpha; } if (i->y < _nHeight - 1) { _inbuff[(i->y + 1) * _nWidth * 4 + i->x * 4 + 0] = cRed; _inbuff[(i->y + 1) * _nWidth * 4 + i->x * 4 + 1] = cGreen; _inbuff[(i->y + 1) * _nWidth * 4 + i->x * 4 + 2] = cBlue; _inbuff[(i->y + 1) * _nWidth * 4 + i->x * 4 + 3] = cAlpha; } if (i->x > 0) { _inbuff[i->y * _nWidth * 4 + (i->x - 1) * 4 + 0] = cRed; _inbuff[i->y * _nWidth * 4 + (i->x - 1) * 4 + 1] = cGreen; _inbuff[i->y * _nWidth * 4 + (i->x - 1) * 4 + 2] = cBlue; _inbuff[i->y * _nWidth * 4 + (i->x - 1) * 4 + 3] = cAlpha; } if (i->x < _nWidth - 1) { _inbuff[i->y * _nWidth * 4 + (i->x + 1) * 4 + 0] = cRed; _inbuff[i->y * _nWidth * 4 + (i->x + 1) * 4 + 1] = cGreen; _inbuff[i->y * _nWidth * 4 + (i->x + 1) * 4 + 2] = cBlue; _inbuff[i->y * _nWidth * 4 + (i->x + 1) * 4 + 3] = cAlpha; } } } } }