Skip to content

Instantly share code, notes, and snippets.

@jasonbeverage
Created June 2, 2016 19:40
Show Gist options
  • Save jasonbeverage/b4d021c1a7a06b0d9998bcf61546ba7b to your computer and use it in GitHub Desktop.
Save jasonbeverage/b4d021c1a7a06b0d9998bcf61546ba7b to your computer and use it in GitHub Desktop.
Test for zig zag encoding a heightfield.
/* -*-c++-*- */
/* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
* Copyright 2015 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#include <osgDB/ReadFile>
#include <osgEarth/HeightFieldUtils>
#include <osgEarth/ImageToHeightFieldConverter>
/*
int zigzag_encode(int i)
{
return (i << 1) ^ (i >> 31);
}
int zigzag_decode(int n)
{
return (n >> 1) ^ (-(n & 1));
}
*/
unsigned short zigzag_encode(short i)
{
return (i << 1) ^ (i >> 15);
}
short zigzag_decode(unsigned short n)
{
return (n >> 1) ^ (-(n & 1));
}
std::vector< short > writeDelta;
osg::HeightField* readQuantized(const std::string& filename)
{
std::ifstream in(filename, std::ios::binary);
unsigned int numCols, numRows;
in.read((char*)&numCols, sizeof(unsigned int));
in.read((char*)&numRows, sizeof(unsigned int));
float minHeight, maxHeight;
in.read((char*)&minHeight, sizeof(float));
in.read((char*)&maxHeight, sizeof(float));
OE_NOTICE << "Dimensions " << numCols << "x" << numRows << std::endl;
OE_NOTICE << "Min=" << minHeight << " Max=" << maxHeight << std::endl;
osg::ref_ptr< osg::HeightField > hf = new osg::HeightField;
hf->allocate(numCols, numRows);
short height = 0;
for (unsigned int i = 0; i < numCols * numRows; i++)
{
unsigned short h;
in.read((char*)&h, sizeof(unsigned short));
short delta = zigzag_decode(h);
if (delta != writeDelta[i])
{
OE_NOTICE << "Delta " << i << " doesn't match " << delta << " writeDelta=" << writeDelta[i] << std::endl;
}
height += delta;
//OE_NOTICE << "Height=" << height << std::endl;
hf->getFloatArray()->at(i) = minHeight + ((float)height / (float)32767) * (maxHeight - minHeight);
}
return hf.release();
}
void writeQuantized(osg::HeightField* heightfield, const std::string& filename)
{
std::ofstream out(filename, std::ios::binary);
float minHeight = FLT_MAX;
float maxHeight = -FLT_MIN;
for (unsigned int i = 0; i < heightfield->getFloatArray()->size(); i++)
{
float h = heightfield->getFloatArray()->at( i );
if (h < minHeight) minHeight = h;
if (h > maxHeight) maxHeight = h;
}
OE_NOTICE << "Computed min/max of " << minHeight << ", " << maxHeight << std::endl;
unsigned int numCols = heightfield->getNumColumns();
unsigned int numRows = heightfield->getNumRows();
out.write((char*)&numCols, sizeof(unsigned int));
out.write((char*)&numRows, sizeof(unsigned int));
out.write((char*)&minHeight, sizeof(float));
out.write((char*)&maxHeight, sizeof(float));
// Write out the heights as offset, zig_zag encoded heights
short height = 0;
for (unsigned int i = 0; i < heightfield->getFloatArray()->size(); i++)
{
float h = heightfield->getFloatArray()->at( i );
//OE_NOTICE << "height=" << h << std::endl;
short hQuant = ((h - minHeight) / (maxHeight - minHeight)) * 32767;
short delta = hQuant - height;
//OE_NOTICE << "Delta[" << i << "] =" << delta << std::endl;
writeDelta.push_back( delta );
unsigned short enc = zigzag_encode( delta );
out.write((char*)&enc, sizeof(unsigned short));
height = hQuant;
float testHeight = minHeight + ((float)height / (float)32767) * (maxHeight - minHeight);
//OE_NOTICE << "h=" << h << " testHeight=" << testHeight << std::endl;
}
out.close();
}
int
main(int argc, char** argv)
{
short value = 27644;
unsigned short enc = zigzag_encode(value);
short dec = zigzag_decode(enc);
OE_NOTICE << "enc= " << enc << " dec=" << dec << " value=" << value << std::endl;
osg::ref_ptr< osg::Image > image = osgDB::readImageFile("c:/temp/test.tif");
osgEarth::ImageToHeightFieldConverter converter;
osg::ref_ptr< osg::HeightField> heightfield = converter.convert( image.get() );
writeQuantized(heightfield, "c:/temp/quantized.hf");
osg::ref_ptr< osg::HeightField> read = readQuantized( "c:/temp/quantized.hf");
float maxDiff = -FLT_MAX;
for (unsigned int i = 0; i < heightfield->getFloatArray()->size(); i++)
{
float h0 = heightfield->getFloatArray()->at(i);
float h1 = read->getFloatArray()->at(i);
float diff = osg::absolute(h1-h0);
if (diff > maxDiff)
{
maxDiff = diff;
}
//OE_NOTICE << i << " h0=" << h0 << " h1=" << h1 << " Difference " << (h1-h0) << std::endl;
}
OE_NOTICE << "Max difference = " << maxDiff << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment