/* This file is part of MAUS: http://micewww.pp.rl.ac.uk/projects/maus
*
* MAUS is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MAUS is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MAUS. If not, see .
*/
#ifndef _SRC_LEGACY_INTERFACE_MESHING_THREEDGRID_HH_
#define _SRC_LEGACY_INTERFACE_MESHING_THREEDGRID_HH_
#include
#include
#include
#include "src/legacy/Interface/Meshing/Mesh.hh"
/** ThreeDGrid holds grid information for a rectangular grid used in e.g.
* interpolation
*
* ThreeDGrid holds the necessary information for regular and irregular grid
* data for interpolation routines.
*
* Constructor is provided to generate a regular grid given grid spacing etc
* and an irregular grid given lists of x, y, z data for the grid points.
* Nearest either calculates nearest grid point a priori for regular grids or
* uses std::lower_bound to calculate nearest grid point (list bisection or
* somesuch). Controlled by _constantSpacing flag. The regular spacing lookup
* is quicker, so prefer constant spacing.
*
* ThreeDGrid holds a list of pointers to VectorMaps that use the grid for
* interpolation and functions to Add and Remove VectorMaps. If the Remove
* function removes the last VectorMap, then the ThreeDGrid is deleted. It's a
* sort of smart pointer.
*/
class ThreeDGrid : public Mesh {
public:
class Iterator;
/** Deep copy the grid */
Mesh * Clone() {return new ThreeDGrid(*this);}
/** Not implemented (returns NULL) */
Mesh * Dual () {return NULL;}
/** Default constructor */
ThreeDGrid();
/** Make a regular rectangular ThreeDGrid
*
* Set up a ThreeDGrid with regular grid spacing (same distance between
* every point)
* \param dX step size in x; should be positive
* \param dY step size in y; should be positive
* \param dZ step size in z; should be positive
* \param minX x position of grid lower edge
* \param minY y position of grid lower edge
* \param minZ z position of grid lower edge
* \param numberOfXCoords number of x coordinates on grid; should be > 1
* \param numberOfYCoords number of y coordinates on grid; should be > 1
* \param numberOfZCoords number of z coordinates on grid; should be > 1
*/
ThreeDGrid(double dX, double dY, double dZ,
double minX, double minY, double minZ,
int numberOfXCoords, int numberOfYCoords, int numberOfZCoords);
/** Make a irregular rectangular ThreeDGrid
*
* Set up a ThreeDGrid with irregular grid spacing
* \param xSize number of points in x
* \param x x points array
* \param ySize number of points in y
* \param y y points array
* \param zSize number of points in Z
* \param z z point array
* ThreeDGrid deep copies the data pointed to by x, y, z (i.e. it does not
* take ownership of these arrays).
*/
ThreeDGrid(int xSize, const double *x,
int ySize, const double *y,
int zSize, const double *z);
/** Make a irregular rectangular ThreeDGrid
*
* Set up a ThreeDGrid with irregular grid spacing
* \param x x points array
* \param y y points array
* \param z z point array
*/
ThreeDGrid(std::vector x,
std::vector y,
std::vector z);
/** Destructor */
~ThreeDGrid();
/** Get ith coordinate in x
*
* Round bracket indexing starts at 1 goes to nCoords
*/
inline double& x(const int& i) {return _x[i-1];}
/** Get ith coordinate in y
*
* Round bracket indexing starts at 1 goes to nCoords
*/
inline double& y(const int& j) {return _y[j-1];}
/** Get ith coordinate in z
*
* Round bracket indexing starts at 1 goes to nCoords
*/
inline double& z(const int& k) {return _z[k-1];}
/** Get ith coordinate in x
*
* Round bracket indexing starts at 1 goes to nCoords
*/
inline const double& x(const int& i) const {return _x[i-1];}
/** Get ith coordinate in y
*
* Round bracket indexing starts at 1 goes to nCoords
*/
inline const double& y(const int& j) const {return _y[j-1];}
/** Get ith coordinate in z
*
* Round bracket indexing starts at 1 goes to nCoords
*/
inline const double& z(const int& j) const {return _z[j-1];}
/** Get size of x data */
inline int xSize() const {return static_cast(_x.size());}
/** Get size of y data */
inline int ySize() const {return static_cast(_y.size());}
/** Get size of z data */
inline int zSize() const {return static_cast(_z.size());}
/** Get vector containing x grid data */
std::vector xVector() {return std::vector(_x);}
/** Get vector containing y grid data */
std::vector yVector() {return std::vector(_y);}
/** Get vector containing z grid data */
std::vector zVector() {return std::vector(_z);}
/** Allocate a new array containing x grid data */
inline double* newXArray();
/** Allocate a new array containing y grid data */
inline double* newYArray();
/** Allocate a new array containing z grid data */
inline double* newZArray();
/** Find the index of the nearest point less than x
*
* Note that in the case of a regular grid there is no bound checking; in
* the case of an irregular grid we always return an element in the grid
*/
inline void xLowerBound(const double& x, int& xIndex) const;
/** Find the index of the nearest point less than y
*
* Note that in the case of a regular grid there is no bound checking; in
* the case of an irregular grid we always return an element in the grid
*/
inline void yLowerBound(const double& y, int& yIndex) const;
/** Find the index of the nearest point less than z
*
* Note that in the case of a regular grid there is no bound checking; in
* the case of an irregular grid we always return an element in the grid
*/
inline void zLowerBound(const double& z, int& zIndex) const;
/** Find the indices of the nearest point on the grid less than x, y, z
*
* Note that in the case of a regular grid there is no bound checking; in
* the case of an irregular grid we always return an element in the grid
*/
inline void LowerBound(const double& x, int& xIndex,
const double& y, int& yIndex,
const double& z, int& zIndex) const;
/** Find the iterator of the nearest point on the grid less than x, y, z
*
* Note that in the case of a regular grid there is no bound checking; in
* the case of an irregular grid we always return an element in the grid
*/
inline void LowerBound(const double& x, const double& y, const double& z,
Mesh::Iterator& it) const;
/** Return the smallest value of x in the grid */
inline double MinX() const;
/** Return the largest value of x in the grid */
inline double MaxX() const;
/** Return the smallest value of y in the grid */
inline double MinY() const;
/** Return the largest value of y in the grid */
inline double MaxY() const;
/** Return the smallest value of z in the grid */
inline double MinZ() const;
/** Return the largest value of z in the grid */
inline double MaxZ() const;
/** Reset x grid points - note may need to set SetConstantSpacing() */
inline void SetX(int nXCoords, double * x);
/** Reset y grid points - note may need to set SetConstantSpacing() */
inline void SetY(int nYCoords, double * y);
/** Reset z grid points - note may need to set SetConstantSpacing() */
inline void SetZ(int nZCoords, double * z);
/** Add *map to the _maps list if it has not already been added */
void Add(VectorMap* map);
/** Remove *map from the _maps list if it has not already been removed. If
* there are no more maps in the list, delete this*/
void Remove(VectorMap* map);
/** Return an iterator pointing at the first element in the ThreeDGrid */
Mesh::Iterator Begin() const;
/** Return an iterator pointing at the last+1 element in the ThreeDGrid */
Mesh::Iterator End() const;
/** Fill position with the position of it
*
* \param it iterator pointing at a grid position
* \param position array of length >= 3 that will be filled with the
* position of it
*/
virtual void Position(const Mesh::Iterator& it, double * position) const;
/** Returns 3, the dimension of the space of the grid */
inline int PositionDimension() const;
/** Converts from iterator to integer value
*
* 0 corresponds to the mesh beginning. integers index (right most index)
* indexes z, middle index is y, most significant (left most index) indexes
* x.
*/
inline int ToInteger(const Mesh::Iterator& lhs) const;
/** Set to true to use constant spacing
*
* If constant spacing is true, assume regular grid with spacing given by
* separation of first two elements in each dimension
*/
inline void SetConstantSpacing(bool spacing);
/** Autodetect constant spacing with float tolerance of 1e-9
*/
void SetConstantSpacing();
/** Return true if using constant spacing */
inline bool GetConstantSpacing() const;
/** Return the point in the mesh nearest to position */
Mesh::Iterator Nearest(const double* position) const;
protected:
// Change position
virtual Mesh::Iterator& AddEquals(Mesh::Iterator& lhs, int difference) const;
virtual Mesh::Iterator& SubEquals(Mesh::Iterator& lhs, int difference) const;
virtual Mesh::Iterator& AddEquals
(Mesh::Iterator& lhs, const Mesh::Iterator& rhs) const;
virtual Mesh::Iterator& SubEquals
(Mesh::Iterator& lhs, const Mesh::Iterator& rhs) const;
virtual Mesh::Iterator& AddOne(Mesh::Iterator& lhs) const;
virtual Mesh::Iterator& SubOne(Mesh::Iterator& lhs) const;
// Check relative position
virtual bool IsGreater
(const Mesh::Iterator& lhs, const Mesh::Iterator& rhs) const;
private:
std::vector _x;
std::vector _y;
std::vector _z;
int _xSize;
int _ySize;
int _zSize;
std::vector _maps;
bool _constantSpacing;
friend Mesh::Iterator operator++(Mesh::Iterator& lhs, int);
friend Mesh::Iterator operator--(Mesh::Iterator& lhs, int);
friend Mesh::Iterator& operator++(Mesh::Iterator& lhs);
friend Mesh::Iterator& operator--(Mesh::Iterator& lhs);
friend Mesh::Iterator operator-
(const Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
friend Mesh::Iterator operator+
(const Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
friend Mesh::Iterator& operator-=
(Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
friend Mesh::Iterator& operator+=
(Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
friend bool operator==(const Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
friend bool operator!=(const Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
friend bool operator>=(const Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
friend bool operator<=(const Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
friend bool operator< (const Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
friend bool operator> (const Mesh::Iterator& lhs, const Mesh::Iterator& rhs);
};
double* ThreeDGrid::newXArray() {
double *x = new double[_x.size()];
for (unsigned int i = 0; i < _x.size(); i++)
x[i] = _x[i];
return x;
}
double* ThreeDGrid::newYArray() {
double *y = new double[_y.size()];
for (unsigned int i = 0; i < _y.size(); i++)
y[i] = _y[i];
return y;
}
double* ThreeDGrid::newZArray() {
double *z = new double[_z.size()];
for (unsigned int i = 0; i < _z.size(); i++)
z[i] = _z[i];
return z;
}
void ThreeDGrid::xLowerBound(const double& x, int& xIndex) const {
if (_constantSpacing)
xIndex = static_cast(floor((x - _x[0])/(_x[1]-_x[0]) ));
else
xIndex = std::lower_bound(_x.begin(), _x.end(), x)-_x.begin()-1;
}
void ThreeDGrid::yLowerBound(const double& y, int& yIndex) const {
if (_constantSpacing)
yIndex = static_cast(floor((y - _y[0])/(_y[1]-_y[0])));
else
yIndex = std::lower_bound(_y.begin(), _y.end(), y)-_y.begin()-1;
}
void ThreeDGrid::zLowerBound(const double& z, int& zIndex) const {
if (_constantSpacing)
zIndex = static_cast(floor((z - _z[0])/(_z[1]-_z[0])));
else
zIndex = std::lower_bound(_z.begin(), _z.end(), z)-_z.begin()-1;
}
void ThreeDGrid::LowerBound(const double& x, int& xIndex,
const double& y, int& yIndex,
const double& z, int& zIndex) const {
xLowerBound(x, xIndex);
yLowerBound(y, yIndex);
zLowerBound(z, zIndex);
}
void ThreeDGrid::LowerBound(const double& x,
const double& y,
const double& z,
Mesh::Iterator& it) const {
xLowerBound(x, it[0]);
yLowerBound(y, it[1]);
zLowerBound(z, it[2]);
it[0]++;
it[1]++;
it[2]++;
}
double ThreeDGrid::MinX() const {
return _x[0];
}
double ThreeDGrid::MaxX() const {
return _x[_xSize-1];
}
double ThreeDGrid::MinY() const {
return _y[0];
}
double ThreeDGrid::MaxY() const {
return _y[_ySize-1];
}
double ThreeDGrid::MinZ() const {
return _z[0];
}
double ThreeDGrid::MaxZ() const {
return _z[_zSize-1];
}
void ThreeDGrid::SetX(int nXCoords, double * x) {
_x = std::vector(x, x+nXCoords);
}
void ThreeDGrid::SetY(int nYCoords, double * y) {
_y = std::vector(y, y+nYCoords);
}
void ThreeDGrid::SetZ(int nZCoords, double * z) {
_z = std::vector(z, z+nZCoords);
}
int ThreeDGrid::PositionDimension() const {
return 3;
}
int ThreeDGrid::ToInteger(const Mesh::Iterator& lhs) const {
return (lhs.State()[0]-1)*_zSize*_ySize+
(lhs.State()[1]-1)*_zSize+
(lhs.State()[2]-1);
}
void ThreeDGrid::SetConstantSpacing(bool spacing) {
_constantSpacing = spacing;
}
bool ThreeDGrid::GetConstantSpacing() const {
return _constantSpacing;
}
#endif