diff --git a/CMakeLists.txt b/CMakeLists.txt index f005615..da8d4c2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -76,10 +76,13 @@ set(SOURCES src/Algo2DEntropy.cc src/Algo2DFourColors.cc src/Algo2DGrayscale.cc + src/Algo3DCubeFull.cc src/Algo3DCubeContiBnW.cc src/Algo3DCubeContiRainbow.cc src/Algo3DCubeContiFrebet.cc + src/Algo3DCubeEntropy.cc + src/Algo3DSphereFull.cc src/Algo3DSphereContiBnW.cc src/Algo3DSphereContiRainbow.cc diff --git a/src/Algo3DCubeEntropy.cc b/src/Algo3DCubeEntropy.cc new file mode 100644 index 0000000..658eecf --- /dev/null +++ b/src/Algo3DCubeEntropy.cc @@ -0,0 +1,70 @@ +#include +#include +#include + +#include + +// github.com/cortesi/scurve/blob/a59e8335c48a7cda7043fbd1b28bcae1abc9645d/binvis#L58 + +inline float +entropy (const u8* data, size_t len, size_t offset, size_t blocksize=32, size_t n_symbols=256) { + if (len < blocksize) + throw std::range_error("Data length must be larger than block size."); + + size_t start; + const auto half_block = blocksize / 2; + if (offset < half_block) + start = 0; + else if (offset > len - half_block) + start = len - half_block; + else + start = offset - half_block; + + std::vector hist(n_symbols, 0.0f); + for (size_t i = start; i < start + blocksize; ++i) + hist[ data[i] ]++; + + auto Blocksize = static_cast(blocksize); + auto base = static_cast(std::min(blocksize, n_symbols)); + auto base_log = 1 / std::log(base); + float entropy = 0; + for (float value : hist) { + if (value < 1.0f) + continue; + float p = value / Blocksize; + // If blocksize < 256, the number of possible byte values is restricted. + // In that case, we adjust the log base to make sure we get a value + // between 0 and 1. + entropy += p * std::log(p) * base_log; + } + return - entropy; +} + +inline float +curve (float v) { + float f = std::pow(4 * (v - std::pow(v, 2)), 4); + return std::max(f, 0.0f); +} + +bool +Algo3DCubeEntropy::apply(GLfloat* vertices, GLfloat* colors, VertIndices& selected, + size_t width, size_t height, size_t depth) { + make_vertices(vertices, width, height, depth); + + const size_t chunk_size = width * height * 2; + const u8* read = loader_->dataChunk(0, chunk_size); + size_t pos = 0; + for (size_t i = 0; i < chunk_size; ++i) { + auto e = entropy(read, chunk_size, i, 32, 256); + float r = (e > 0.5f) ? curve(e - 0.5f) : 0.0f; + if (r > 0.0f) + selected.push_back(pos / 4); + float b = std::pow(e, 2); + colors[pos++] = r; + colors[pos++] = 0.0f; + colors[pos++] = b; + colors[pos++] = 1.0f; + } + + return true; +} diff --git a/src/Algorithm.cc b/src/Algorithm.cc index bc315df..74db21a 100644 --- a/src/Algorithm.cc +++ b/src/Algorithm.cc @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -64,10 +65,13 @@ const std::map algorithms = { { "entropy", []() { return new Algo2DEntropy(); } }, { "4col", []() { return new Algo2DFourColors(); } }, { "gray", []() { return new Algo2DGrayscale(); } }, + { "cube", []() { return new Algo3DCubeFull(); } }, { "contibnw", []() { return new Algo3DCubeContiBnW(); } }, { "contirb", []() { return new Algo3DCubeContiRainbow(); } }, { "conti", []() { return new Algo3DCubeContiFrebet(); } }, + { "cube_entropy", []() { return new Algo3DCubeEntropy(); } }, + { "sphere", []() { return new Algo3DSphereFull(); } }, { "sphere_bnw", []() { return new Algo3DSphereContiBnW(); } }, { "sphere_rb", []() { return new Algo3DSphereContiRainbow(); } }, diff --git a/src/MmapLoader.cc b/src/MmapLoader.cc index af26a21..cea7d61 100644 --- a/src/MmapLoader.cc +++ b/src/MmapLoader.cc @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -44,6 +45,7 @@ MmapFileLoader::data() const u8* MmapFileLoader::dataChunk(size_t offset, size_t size) { + std::cout << size_ << " >= " << offset + size << std::endl; if (size_ < offset + size) throw std::out_of_range("Trying to read data out of bound"); return data() + offset; diff --git a/src/include/Algo3DCubeEntropy.hh b/src/include/Algo3DCubeEntropy.hh new file mode 100644 index 0000000..df4d950 --- /dev/null +++ b/src/include/Algo3DCubeEntropy.hh @@ -0,0 +1,13 @@ +#pragma once + +#include + +class Algo3DCubeEntropy : public Algo3DCube { +public: + Algo3DCubeEntropy() {} + virtual ~Algo3DCubeEntropy() {} + + virtual bool apply(GLfloat* vertices, GLfloat* colors, VertIndices& selected, + size_t width, size_t height, size_t depth); +}; +