Commit 654a2a0c authored by Quentin Khan's avatar Quentin Khan

Factorize FTreeCoordinate code using FPoint

FTreeCoordinate and FPoint have a lot of methods in common. FTreeCoordinate now
inherits from FPoint to avoid code duplication.
parent 0da9e429
......@@ -4,13 +4,13 @@
// This software is a computer program whose purpose is to compute the FMM.
//
// This software is governed by the CeCILL-C and LGPL licenses and
// abiding by the rules of distribution of free software.
//
// abiding by the rules of distribution of free software.
//
// This program 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 and CeCILL-C Licenses for more details.
// "http://www.cecill.info".
// "http://www.cecill.info".
// "http://www.gnu.org/licenses".
// ===================================================================================
#ifndef FTREECOORDINATE_HPP
......@@ -19,6 +19,7 @@
#include <string>
#include "../Utils/FGlobal.hpp"
#include "../Utils/FPoint.hpp"
#include "../Utils/FMath.hpp"
#include "../Components/FAbstractSerializable.hpp"
......@@ -33,130 +34,57 @@
* It is directly related to morton index, as interleaves
* bits from this coordinate make the morton index
*/
class FTreeCoordinate : public FAbstractSerializable {
class FTreeCoordinate : public FAbstractSerializable, public FPoint<int, 3> {
private:
int data[3]; //< all box-th position
using point_t = FPoint<int, 3>;
public:
public:
/** Default constructor (position = {0,0,0})*/
FTreeCoordinate() {
data[0] = data[1] = data[2] = 0;
}
FTreeCoordinate(): point_t() {}
/** Default constructor (position = {0,0,0})*/
/** Constructor from Morton index */
explicit FTreeCoordinate(const MortonIndex mindex, const int indexLevel) {
setPositionFromMorton(mindex, indexLevel);
}
/**
* Default constructor
* @param inX the x
* @param inY the y
* @param inZ the z
*/
explicit FTreeCoordinate(const int inX,const int inY,const int inZ) {
data[0] = inX;
data[1] = inY;
data[2] = inZ;
}
/** Constructor from args
* @param inX the x
* @param inY the y
* @param inZ the z
*/
explicit FTreeCoordinate(const int inX,const int inY,const int inZ)
: point_t(inX, inY, inZ)
{}
explicit FTreeCoordinate(const int inPosition[3]) {
data[0] = inPosition[0];
data[1] = inPosition[1];
data[2] = inPosition[2];
}
explicit FTreeCoordinate(const int inPosition[3])
: point_t(inPosition)
{}
/**
* Copy constructor
* @param other the source class to copy
*/
FTreeCoordinate(const FTreeCoordinate& other) {
data[0] = other.data[0];
data[1] = other.data[1];
data[2] = other.data[2];
}
FTreeCoordinate(const FTreeCoordinate& other)
: point_t(other)
{}
/**
* Copy constructor
* @param other the source class to copy
*/
FTreeCoordinate(const FTreeCoordinate& other, const int inOffset) {
data[0] = other.data[0] + inOffset;
data[1] = other.data[1] + inOffset;
data[2] = other.data[2] + inOffset;
}
/** Copy and increment constructor
* @param other the source class to copy
*/
FTreeCoordinate(const FTreeCoordinate& other, const int inOffset)
: point_t(other, inOffset)
{}
/**
* Copy constructor
* Copy assignment
* @param other the source class to copy
* @return this a reference to the current object
*/
FTreeCoordinate& operator=(const FTreeCoordinate& other){
data[0] = other.data[0];
data[1] = other.data[1];
data[2] = other.data[2];
point_t::operator=(other);
return *this;
}
/**
* Position setter
* @param inX the new x
* @param inY the new y
* @param inZ the new z
*/
void setPosition(const int inX,const int inY,const int inZ){
data[0] = inX;
data[1] = inY;
data[2] = inZ;
}
/**
* X Getter
* @return data[0]
*/
int getX() const{
return data[0];
}
/**
* Y Getter
* @return data[1]
*/
int getY() const{
return data[1];
}
/**
* Z Getter
* @return data[2]
*/
int getZ() const{
return data[2];
}
/**
* X Setter, simply change x position
* @param the new x
*/
void setX(const int inX){
data[0] = inX;
}
/**
* Y Setter, simply change y position
* @param the new y
*/
void setY(const int inY){
data[1] = inY;
}
/**
* Z Setter, simply change z position
* @param the new z
*/
void setZ(const int inZ){
data[2] = inZ;
}
/**
* To get the morton index of the current position
......@@ -168,9 +96,9 @@ public:
MortonIndex index = 0x0LL;
MortonIndex mask = 0x1LL;
// the ordre is xyz.xyz...
MortonIndex mx = data[0] << 2;
MortonIndex my = data[1] << 1;
MortonIndex mz = data[2];
MortonIndex mx = point_t::data()[0] << 2;
MortonIndex my = point_t::data()[1] << 1;
MortonIndex mz = point_t::data()[2];
for(int indexLevel = 0; indexLevel < inLevel ; ++indexLevel){
index |= (mz & mask);
......@@ -195,72 +123,42 @@ public:
void setPositionFromMorton(MortonIndex inIndex, const int inLevel){
MortonIndex mask = 0x1LL;
data[0] = 0;
data[1] = 0;
data[2] = 0;
point_t::data()[0] = 0;
point_t::data()[1] = 0;
point_t::data()[2] = 0;
for(int indexLevel = 0; indexLevel < inLevel ; ++indexLevel){
data[2] |= int(inIndex & mask);
point_t::data()[2] |= int(inIndex & mask);
inIndex >>= 1;
data[1] |= int(inIndex & mask);
point_t::data()[1] |= int(inIndex & mask);
inIndex >>= 1;
data[0] |= int(inIndex & mask);
point_t::data()[0] |= int(inIndex & mask);
mask <<= 1;
}
}
/** Test equal operator
* @param other the coordinate to compare
* @return true if other & current object have same position
*/
bool operator==(const FTreeCoordinate& other) const {
return data[0] == other.data[0] && data[1] == other.data[1] && data[2] == other.data[2];
}
/** Test equal operator
* @param other the coordinate to compare
* @return true if other & current object have same position
*/
bool equals(const int inX, const int inY, const int inZ) const {
return data[0] == inX && data[1] == inY && data[2] == inZ;
}
/** To test difference
*
*/
bool operator!=(const FTreeCoordinate& other) const{
return data[0] != other.data[0] || data[1] != other.data[1] || data[2] != other.data[2];
return point_t::data()[0] == inX
&& point_t::data()[1] == inY
&& point_t::data()[2] == inZ;
}
/**
* Operator stream FTreeCoordinate to std::ostream
* This can be used to simply write out a tree coordinate
* @param[in,out] output where to write the coordinate
* @param[in] inCoordinate the coordinate to write out
* @return the output for multiple << operators
*/
template <class StreamClass>
friend StreamClass& operator<<(StreamClass& output, const FTreeCoordinate& inCoordinate){
output << "(" << inCoordinate.getX() << ", " << inCoordinate.getY() << ", " << inCoordinate.getZ() <<")";
return output; // for multiple << operators.
}
/** Use base class save */
using point_t::save;
/** Use base class restore */
using point_t::restore;
/** Save current object */
template <class BufferWriterClass>
void save(BufferWriterClass& buffer) const {
buffer << data[0] << data[1] << data[2];
}
/** Retrieve current object */
template <class BufferReaderClass>
void restore(BufferReaderClass& buffer) {
buffer >> data[0] >> data[1] >> data[2];
}
/** To know the size when we save it */
FSize getSavedSize() const {
return FSize(sizeof(data[0]) + sizeof(data[1]) + sizeof(data[2]));
return FSize(3 * sizeof(point_t::data()[0]));
}
......@@ -281,43 +179,12 @@ public:
return str;
}
/* @brief Compute the index of the cells in neighborhood of a given cell
* @param OtreeHeight Height of the Octree
* @param indexes target array to store the MortonIndexes computed
* @param indexInArray store
*/
int getNeighborsIndexes(const int OctreeHeight, MortonIndex indexes[26], int indexInArray[26]) const{
int idxNeig = 0;
int limite = 1 << (OctreeHeight - 1);
// We test all cells around
for(int idxX = -1 ; idxX <= 1 ; ++idxX){
if(!FMath::Between(this->getX() + idxX,0, limite)) continue;
for(int idxY = -1 ; idxY <= 1 ; ++idxY){
if(!FMath::Between(this->getY() + idxY,0, limite)) continue;
for(int idxZ = -1 ; idxZ <= 1 ; ++idxZ){
if(!FMath::Between(this->getZ() + idxZ,0, limite)) continue;
// if we are not on the current cell
if( idxX || idxY || idxZ ){
const FTreeCoordinate other(this->getX() + idxX, this->getY() + idxY, this->getZ() + idxZ);
indexes[ idxNeig ] = other.getMortonIndex(OctreeHeight - 1);
indexInArray[ idxNeig ] = ((idxX+1)*3 + (idxY+1)) * 3 + (idxZ+1);
++idxNeig;
}
}
}
}
return idxNeig;
}
/* @brief Compute the indexes of the neighborhood of the calling cell
* @param OtreeHeight Height of the Octree
* @param indexes target array to store the MortonIndexes computed
*/
int getNeighborsIndexes(const int OctreeHeight, MortonIndex indexes[26]) const{
/** @brief Compute the index of the cells in neighborhood of a given cell
* @param OtreeHeight Height of the Octree
* @param indexes target array to store the MortonIndexes computed
* @param indexInArray store (must have the same length as indexes)
*/
int getNeighborsIndexes(const int OctreeHeight, MortonIndex indexes[26], int* indexInArray = nullptr) const {
int idxNeig = 0;
int limite = 1 << (OctreeHeight - 1);
// We test all cells around
......@@ -334,6 +201,8 @@ public:
if( idxX || idxY || idxZ ){
const FTreeCoordinate other(this->getX() + idxX, this->getY() + idxY, this->getZ() + idxZ);
indexes[ idxNeig ] = other.getMortonIndex(OctreeHeight - 1);
if(indexInArray)
indexInArray[ idxNeig ] = ((idxX+1)*3 + (idxY+1)) * 3 + (idxZ+1);
++idxNeig;
}
}
......@@ -342,8 +211,11 @@ public:
return idxNeig;
}
int getInteractionNeighbors(const int inLevel, MortonIndex inNeighbors[/*189+26+1*/216], int inNeighborsPosition[/*189+26+1*/216],
const int neighSeparation = 1) const{
/**
* @param inNeighborsPosition (must have the same length as inNeighbors)
*/
int getInteractionNeighbors(const int inLevel, MortonIndex inNeighbors[/*189+26+1*/216], int* inNeighborsPosition,
const int neighSeparation = 1) const {
// Then take each child of the parent's neighbors if not in directNeighbors
// Father coordinate
const FTreeCoordinate parentCell(this->getX()>>1,this->getY()>>1,this->getZ()>>1);
......@@ -376,7 +248,8 @@ public:
// Test if it is a direct neighbor
if(FMath::Abs(xdiff) > neighSeparation || FMath::Abs(ydiff) > neighSeparation || FMath::Abs(zdiff) > neighSeparation){
// add to neighbors
inNeighborsPosition[idxNeighbors] = ((( (xdiff+3) * 7) + (ydiff+3))) * 7 + zdiff + 3;
if(inNeighborsPosition)
inNeighborsPosition[idxNeighbors] = ((( (xdiff+3) * 7) + (ydiff+3))) * 7 + zdiff + 3;
inNeighbors[idxNeighbors++] = (mortonOther << 3) | idxCousin;
}
}
......@@ -389,47 +262,7 @@ public:
}
int getInteractionNeighbors(const int inLevel, MortonIndex inNeighbors[/*189+26+1*/216], const int neighSeparation = 1) const{
// Then take each child of the parent's neighbors if not in directNeighbors
// Father coordinate
const FTreeCoordinate parentCell(this->getX()>>1,this->getY()>>1,this->getZ()>>1);
// Limite at parent level number of box (split by 2 by level)
const int limite = FMath::pow2(inLevel-1);
int idxNeighbors = 0;
// We test all cells around
for(int idxX = -1 ; idxX <= 1 ; ++idxX){
if(!FMath::Between(parentCell.getX() + idxX,0,limite)) continue;
for(int idxY = -1 ; idxY <= 1 ; ++idxY){
if(!FMath::Between(parentCell.getY() + idxY,0,limite)) continue;
for(int idxZ = -1 ; idxZ <= 1 ; ++idxZ){
if(!FMath::Between(parentCell.getZ() + idxZ,0,limite)) continue;
// if we are not on the current cell
if(neighSeparation<1 || idxX || idxY || idxZ ){
const FTreeCoordinate otherParent(parentCell.getX() + idxX,parentCell.getY() + idxY,parentCell.getZ() + idxZ);
const MortonIndex mortonOther = otherParent.getMortonIndex(inLevel-1);
// For each child
for(int idxCousin = 0 ; idxCousin < 8 ; ++idxCousin){
const int xdiff = ((otherParent.getX()<<1) | ( (idxCousin>>2) & 1)) - this->getX();
const int ydiff = ((otherParent.getY()<<1) | ( (idxCousin>>1) & 1)) - this->getY();
const int zdiff = ((otherParent.getZ()<<1) | (idxCousin&1)) - this->getZ();
// Test if it is a direct neighbor
if(FMath::Abs(xdiff) > neighSeparation || FMath::Abs(ydiff) > neighSeparation || FMath::Abs(zdiff) > neighSeparation){
// add to neighbors
inNeighbors[idxNeighbors++] = (mortonOther << 3) | idxCousin;
}
}
}
}
}
}
return idxNeighbors;
return getInteractionNeighbors(inLevel, inNeighbors, nullptr, neighSeparation);
}
};
......@@ -437,5 +270,3 @@ public:
#endif //FTREECOORDINATE_HPP
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment