#pragma once //#include "DataStructures.h" #include "Image3D.h" #include "../../geo/Point3.h" #include "../../geo/BBox3.h" template struct Grid3D { static_assert(std::is_floating_point::value, "Grid3D only supports float values"); public: const _BBox3 bb; const size_t numBinsX, numBinsY, numBinsZ; const T binSizeX, binSizeY, binSizeZ; private: Image3D data; bool empty; public: Grid3D(_BBox3 bb, size_t numBinsAll) : Grid3D(bb, numBinsAll, numBinsAll, numBinsAll) {} Grid3D(_BBox3 bb, size_t numBinsX, size_t numBinsY, size_t numBinsZ) : bb(bb), numBinsX(numBinsX), numBinsY(numBinsY), numBinsZ(numBinsZ), binSizeX((bb.getSize().x + 1) / numBinsX), binSizeY((bb.getSize().y + 1) / numBinsY), binSizeZ((bb.getSize().z + 1) / numBinsZ), data(numBinsX, numBinsY, numBinsZ), empty(false) { } Image3D& image() { return data; } const Image3D& image() const { return data; } T& operator() (size_t x, size_t y, size_t z) { return data(x, y, z); } const T& operator() (size_t x, size_t y, size_t z) const { return data(x, y, z); } void clear() { data.clear(); } void fill(const std::vector<_Point3>& samples) { assertMsg(!samples.empty(), "Samples must be non-empty"); if (!empty) data.clear(); const T weight = T(1.0) / samples.size(); for (const auto& pt : samples) { add(pt.x, pt.y, pt.z, weight); } empty = false; } void fill(const std::vector<_Point3>& samples, const std::vector& weights) { assertMsg(!samples.empty(), "Samples must be non-empty"); assertMsg(weights.size() == samples.size(), "Weights must have the same size as samples"); if (!empty) data.clear(); for (size_t i = 0; i < samples.size(); i++) { add(samples[i].x, samples[i].y, samples[i].z, weights[i]); } empty = false; } _Point3 add(_Point3 pt, T w) { return add(pt.x, pt.y, pt.z, w); } _Point3 add(T x, T y, T z, T w) { if (assertCond(bb.contains(_Point3(x, y, z)))) { std::stringstream ss; ss << "Point " << "(" << x << "; " << y << "; " << z << ")" << " is out of bounds: " << "(X: " << bb.getMin().x << " - " << bb.getMax().x << ";" << " Y: " << bb.getMin().y << " - " << bb.getMax().y << ";" << " Z: " << bb.getMin().z << " - " << bb.getMax().z << ")"; assertThrow(ss.str()); } return add_simple_bin(x, y, z, w); } T fetch(T x, T y, T z) const { size_t bin_x = (size_t)((x - bb.getMin().x) / binSizeX); size_t bin_y = (size_t)((y - bb.getMin().y) / binSizeY); size_t bin_z = (size_t)((z - bb.getMin().z) / binSizeZ); return data(bin_x, bin_y, bin_z); } T maximum(_Point3& pt) const { _Point3 gridPt; T maxValue = image().maximum(gridPt); pt = asInputSpace(gridPt); return maxValue; } // // Takes a point in input space and converts it to grid space coordinates //_Point3 asGridSpace(T x, T y, T z) const // { // size_t bin_x = (size_t)((x - bb.MinX) / binSizeX); // size_t bin_y = (size_t)((y - bb.MinY) / binSizeY); // size_t bin_z = (size_t)((z - bb.MinZ) / binSizeZ); // if (bin_x == data.width) bin_x--; // if (bin_y == data.height) bin_y--; // if (bin_z == data.depth) bin_z--; // return Point3D(bin_x, bin_y, bin_z); // } // // Takes a Size2D in input space and converts it to grid space coordiantes //_Point3 asGridSpace(Size3D sz) const // { // return _Point3(sz.sX / binSizeX, sz.sY / binSizeY, sz.sZ / binSizeZ); // } // // Takes a Range2D in input space and converts it to grid space coordinates // Range3D asGridSpace(Range3D range) const // { // Point3D startPt = asGridSpace(range.X.Start, range.Y.Start, range.Z.Start); // size_t lengthX = range.X.Length / binSizeX; // size_t lengthY = range.Y.Length / binSizeY; // size_t lengthZ = range.Z.Length / binSizeZ; // return Range3D(startPt.X, lengthX, startPt.Y, lengthY, startPt.Z, lengthZ); // } // Takes a point in grid space and converts it to input space coordinates _Point3 asInputSpace(_Point3 pt) const { return asInputSpace(pt.x, pt.y, pt.z); } // Takes a point in grid space and converts it to input space coordinates _Point3 asInputSpace(size_t x, size_t y, size_t z) const { return _Point3(x * binSizeX + bb.getMin().x + T(0.5)*binSizeX, y * binSizeY + bb.getMin().y + T(0.5)*binSizeY, z * binSizeZ + bb.getMin().z + T(0.5)*binSizeZ); } private: _Point3 add_simple_bin(T x, T y, T z, T w) { Assert::isTrue(w > 0, "Weight needs to be postive."); size_t bin_x = (size_t)((x - bb.getMin().x) / binSizeX); size_t bin_y = (size_t)((y - bb.getMin().y) / binSizeY); size_t bin_z = (size_t)((z - bb.getMin().z) / binSizeZ); //if (bin_x == data.width) bin_x--; //if (bin_y == data.height) bin_y--; //if (bin_z == data.depth) bin_z--; data(bin_x, bin_y, bin_z) += w; return _Point3(bin_x, bin_y, bin_z); } }; template struct Grid3D; template struct Grid3D;