Created
June 2, 2016 19:40
-
-
Save jasonbeverage/b4d021c1a7a06b0d9998bcf61546ba7b to your computer and use it in GitHub Desktop.
Test for zig zag encoding a heightfield.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -*-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