/* 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 .
*/
#include "src/legacy/Interface/Meshing/ThreeDGrid.hh"
#include "Utils/Exception.hh"
ThreeDGrid::ThreeDGrid()
: _x(2, 0), _y(2, 0), _z(2, 0), _xSize(0), _ySize(0), _zSize(0), _maps(0),
_constantSpacing(false) {
SetConstantSpacing();
_x[1] = _y[1] = _z[1] = 1.;
}
ThreeDGrid::ThreeDGrid(int xSize, const double *x,
int ySize, const double *y,
int zSize, const double *z)
: _x(x, x+xSize), _y(y, y+ySize), _z(z, z+zSize),
_xSize(xSize), _ySize(ySize), _zSize(zSize),
_maps(), _constantSpacing(false) {
SetConstantSpacing();
if (_xSize < 2 || _ySize < 2 || _zSize < 2)
throw(MAUS::Exception(MAUS::Exception::recoverable,
"3D Grid must be at least 2x2x2 grid",
"ThreeDGrid::ThreeDGrid(...)")
);
}
ThreeDGrid::ThreeDGrid(std::vector x,
std::vector y,
std::vector z)
: _x(x), _y(y), _z(z),
_xSize(x.size()), _ySize(y.size()), _zSize(z.size()),
_maps(), _constantSpacing(false) {
SetConstantSpacing();
if (_xSize < 2 || _ySize < 2 || _zSize < 2)
throw(MAUS::Exception(MAUS::Exception::recoverable,
"3D Grid must be at least 2x2x2 grid",
"ThreeDGrid::ThreeDGrid(...)")
);
}
ThreeDGrid::ThreeDGrid(double dX, double dY, double dZ,
double minX, double minY, double minZ,
int numberOfXCoords, int numberOfYCoords,
int numberOfZCoords)
: _x(numberOfXCoords), _y(numberOfYCoords), _z(numberOfZCoords),
_xSize(numberOfXCoords), _ySize(numberOfYCoords), _zSize(numberOfZCoords),
_maps(), _constantSpacing(true) {
for (int i = 0; i < numberOfXCoords; i++)
_x[i] = minX+i*dX;
for (int j = 0; j < numberOfYCoords; j++)
_y[j] = minY+j*dY;
for (int k = 0; k < numberOfZCoords; k++)
_z[k] = minZ+k*dZ;
SetConstantSpacing();
}
ThreeDGrid::~ThreeDGrid() {
}
// state starts at 1,1,1
Mesh::Iterator ThreeDGrid::Begin() const {
return Mesh::Iterator(std::vector(3, 1), this);
}
Mesh::Iterator ThreeDGrid::End() const {
std::vector end(3, 1);
end[0] = _xSize+1;
return Mesh::Iterator(end, this);
}
void ThreeDGrid::Position(const Mesh::Iterator& it, double * position) const {
position[0] = x(it._state[0]);
position[1] = y(it._state[1]);
position[2] = z(it._state[2]);
}
Mesh::Iterator& ThreeDGrid::AddEquals
(Mesh::Iterator& lhs, int difference) const {
if (difference < 0)
return SubEquals(lhs, -difference);
lhs._state[0] += difference/(_ySize*_zSize);
difference = difference%(_ySize*_zSize);
lhs._state[1] += difference/(_zSize);
lhs._state[2] += difference%(_zSize);
if (lhs._state[1] > _ySize) {
lhs._state[0]++;
lhs._state[1] -= _ySize;
}
if (lhs._state[2] > _zSize) {
lhs._state[1]++;
lhs._state[2] -= _zSize;
}
return lhs;
}
Mesh::Iterator& ThreeDGrid::SubEquals
(Mesh::Iterator& lhs, int difference) const {
if (difference < 0)
return AddEquals(lhs, -difference);
lhs._state[0] -= difference/(_ySize*_zSize);
difference = difference%(_ySize*_zSize);
lhs._state[1] -= difference/(_zSize);
lhs._state[2] -= difference%(_zSize);
while (lhs._state[2] < 1) {
lhs._state[1]--;
lhs._state[2] += _zSize;
}
while (lhs._state[1] < 1) {
lhs._state[0]--;
lhs._state[1] += _ySize;
}
return lhs;
}
Mesh::Iterator& ThreeDGrid::AddEquals
(Mesh::Iterator& lhs, const Mesh::Iterator& rhs) const {
return AddEquals(lhs, rhs.ToInteger());
}
Mesh::Iterator& ThreeDGrid::SubEquals
(Mesh::Iterator& lhs, const Mesh::Iterator& rhs) const {
return SubEquals(lhs, rhs.ToInteger());
}
Mesh::Iterator& ThreeDGrid::AddOne(Mesh::Iterator& lhs) const {
if (lhs._state[1] == _ySize && lhs._state[2] == _zSize) {
++lhs._state[0];
lhs._state[1] = lhs._state[2] = 1;
} else if (lhs._state[2] == _zSize) {
++lhs._state[1];
lhs._state[2] = 1;
} else {
++lhs._state[2];
}
return lhs;
}
Mesh::Iterator& ThreeDGrid::SubOne(Mesh::Iterator& lhs) const {
if (lhs._state[1] == 1 && lhs._state[2] == 1) {
--lhs._state[0];
lhs._state[1] = _ySize;
lhs._state[2] = _zSize;
} else if (lhs._state[2] == 1) {
--lhs._state[1];
lhs._state[2] = _zSize;
} else {
--lhs._state[2];
}
return lhs;
}
// Check relative position
bool ThreeDGrid::IsGreater
(const Mesh::Iterator& lhs, const Mesh::Iterator& rhs) const {
if (lhs._state[0] > rhs._state[0])
return true;
else if (lhs._state[0] == rhs._state[0] && lhs._state[1] > rhs._state[1])
return true;
else if (lhs._state[0] == rhs._state[0] &&
lhs._state[1] == rhs._state[1] &&
lhs._state[2] > rhs._state[2])
return true;
return false;
}
// remove *map if it exists; delete this if there are no more VectorMaps
void ThreeDGrid::Remove(VectorMap* map) {
std::vector::iterator it =
std::find(_maps.begin(), _maps.end(), map);
if (it < _maps.end()) {
_maps.erase(it);
}
if (_maps.begin() == _maps.end()) {
delete this;
}
}
// add *map if it has not already been added
void ThreeDGrid::Add(VectorMap* map) {
std::vector::iterator it =
std::find(_maps.begin(), _maps.end(), map);
if (it == _maps.end()) {
_maps.push_back(map);
}
}
void ThreeDGrid::SetConstantSpacing() {
_constantSpacing = true;
for (unsigned int i = 0; i < _x.size()-1; i++)
if (fabs(1-(_x[i+1]-_x[i])/(_x[1]-_x[0])) > 1e-9) {
_constantSpacing = false;
return;
}
for (unsigned int i = 0; i < _y.size()-1; i++)
if (fabs(1-(_y[i+1]-_y[i])/(_y[1]-_y[0])) > 1e-9) {
_constantSpacing = false;
return;
}
for (unsigned int i = 0; i < _z.size()-1; i++)
if (fabs(1-(_z[i+1]-_z[i])/(_z[1]-_z[0])) > 1e-9) {
_constantSpacing = false;
return;
}
}
Mesh::Iterator ThreeDGrid::Nearest(const double* position) const {
std::vector index(3);
LowerBound(position[0], index[0],
position[1], index[1],
position[2], index[2]);
if (index[0] < _xSize-1 && index[0] >= 0)
index[0] += (2*(position[0] - _x[index[0]]) >
_x[index[0]+1]-_x[index[0]] ? 2 : 1);
else
index[0]++;
if (index[1] < _ySize-1 && index[1] >= 0)
index[1] += (2*(position[1] - _y[index[1]]) >
_y[index[1]+1]-_y[index[1]] ? 2 : 1);
else
index[1]++;
if (index[2] < _zSize-1 && index[2] >= 0)
index[2] += (2*(position[2] - _z[index[2]]) >
_z[index[2]+1]-_z[index[2]] ? 2 : 1);
else
index[2]++;
if (index[0] < 1)
index[0] = 1;
if (index[1] < 1)
index[1] = 1;
if (index[2] < 1)
index[2] = 1;
if (index[0] > _xSize)
index[0] = _xSize;
if (index[1] > _ySize)
index[1] = _ySize;
if (index[2] > _zSize)
index[2] = _zSize;
return Mesh::Iterator(index, this);
}