19 #ifndef ATOMPROBE_VOXELS_H 20 #define ATOMPROBE_VOXELS_H 39 #define XOR(a,b) ((!(a)) ^ (!(b))) 113 std::vector<T> voxels;
120 size_t shape3(
size_t x,
size_t y,
size_t z)
const;
152 size_t y,
size_t z)
const;
154 inline T
getData(
size_t x,
size_t y,
size_t z)
const;
156 inline T
getData(
size_t i)
const {
return voxels[i];}
158 void setEntry(
size_t n,
const T &val) { voxels[n] = val;};
162 void setData(
size_t x,
size_t y,
size_t z,
const T &val);
164 void setData(
size_t n,
const T &val);
175 void getSlice(
size_t normal,
size_t offset, T *p)
const;
177 void getSize(
size_t &x,
size_t &y,
size_t &z)
const;
205 size_t y,
size_t z,
unsigned int edge)
const;
214 size_t y,
size_t z,
unsigned int edge)
const;
224 void getEdgeCell(
size_t edgeUniqId,
size_t &x,
size_t &y,
size_t &z,
size_t &axis )
const;
234 T
getSum(
const T &initialVal=T(0.0))
const;
237 size_t count(
const T &minIntensity)
const;
240 void fill(
const T &val);
245 void getAxisBounds(
size_t axis,
float &minV,
float &maxV)
const;
256 size_t init(
size_t nX,
size_t nY,
size_t nZ,
const BoundCube &bound);
258 size_t init(
size_t nX,
size_t nY,
size_t nZ);
265 size_t loadFile(
const char *cpFilename,
size_t nX,
266 size_t nY,
size_t nZ,
bool silent=
false);
271 size_t writeFile(
const char *cpFilename)
const;
277 void threshold(
const T &thresh,
bool keepUpper,
const T & newVal);
292 void thresholdForPosition(std::vector<AtomProbe::Point3D> &p,
const T &thresh,
bool lowerEq=
false)
const;
308 const T &offThresh)
const;
323 void minMax(T &min, T &max)
const;
334 int countPoints(
const std::vector<AtomProbe::Point3D> &points,
bool noWrap=
true,
bool doErase=
true);
344 int countIons(
const std::vector<AtomProbe::IonHit> &ions,
bool noWrap=
true,
bool doErase=
true);
361 size_t size()
const {
return voxels.size();}
367 template<
class T,
class U>
375 template<
class T,
class U>
382 size_t nMax=src.
size();
383 for(
size_t ui=0; ui<nMax; ui++)
405 return x + y*binCount[0] + z*binCount[0]*binCount[1];
411 newVox.binCount[0]=binCount[0];
412 newVox.binCount[1]=binCount[1];
413 newVox.binCount[2]=binCount[2];
415 newVox.voxels=voxels;
416 newVox.minBound=minBound;
417 newVox.maxBound=maxBound;
427 for(
size_t ui=0;ui<3;ui++)
428 pos[ui] = (
size_t)round(point[ui]*(
float)binCount[ui]);
430 voxels[shape3(pos[0],pos[1],pos[2])] = val;
436 size_t z,
const T &val)
440 ASSERT( x < binCount[0] && y < binCount[1] && z < binCount[2]);
441 voxels[shape3(x,y,z)]=val;
459 offsetFrac=point-minBound;
460 for(
size_t ui=0;ui<3;ui++)
462 offsetFrac[ui]/=(maxBound[ui]-minBound[ui]);
463 pos[ui] = (size_t)round(offsetFrac[ui]*(
float)binCount[ui]);
466 return voxels[shape3(pos[0],pos[1],pos[2])];
474 return AtomProbe::Point3D((
float)x/(
float)binCount[0]*(maxBound[0]-minBound[0]) + minBound[0],
475 (
float)y/(
float)binCount[1]*(maxBound[1]-minBound[1]) + minBound[1],
476 (
float)z/(
float)binCount[2]*(maxBound[2]-minBound[2]) + minBound[2]);
483 (
float)1.0/(
float)binCount[1]*(maxBound[1]-minBound[1]),
484 (
float)1.0/(
float)binCount[2]*(maxBound[2]-minBound[2]));
591 size_t result = 12*(z + y*(binCount[2]+1) + x*(binCount[2]+1)*(binCount[1]+1)) +
743 size_t cellIdx = 12*(z + y*(binCount[2]+1) + x*(binCount[2]+1)*(binCount[1]+1)) ;
756 axis=(edgeUniqId%12)/4;
758 size_t tmp = edgeUniqId/12;
759 x = tmp/((binCount[2]+1)*(binCount[1]+1));
760 tmp-=x*((binCount[2]+1)*(binCount[1]+1));
762 y=tmp/(binCount[2]+1);
763 tmp-=y*(binCount[2]+1);
768 ASSERT(x< binCount[0]+1 && y<binCount[1]+1 && z<binCount[2]+1);
792 b=cellCentre + AtomProbe::Point3D(0,delta[1],0);
797 b=cellCentre + AtomProbe::Point3D(0,0,delta[2]);
807 bc.
expand(sqrtf(std::numeric_limits<float>::epsilon()));
842 minBound=newMinBound;
843 maxBound=newMaxBound;
847 voxels.resize(binCount[0]*binCount[1]*binCount[2]);
849 catch(std::exception &e)
860 return resize(oth.binCount[0],oth.binCount[1],oth.binCount[2],oth.minBound,oth.maxBound);
872 if(v.
resize(newX,newY,newZ))
879 minBound=newMinBound;
880 maxBound=newMaxBound;
885 itStop[0]=std::min(newX,binCount[0]);
886 itStop[1]=std::min(newY,binCount[1]);
887 itStop[2]=std::min(newZ,binCount[2]);
890 itMax[0]=std::max(newX,binCount[0]);
891 itMax[1]=std::max(newY,binCount[1]);
892 itMax[2]=std::max(newZ,binCount[2]);
897 #pragma omp parallel for 898 for(
size_t ui=0;ui<itMax[0];ui++)
901 for(
size_t uj=0;uj<itMax[1];uj++)
903 for(
size_t uk=0;uk<itMax[2];uk++)
905 if(itStop[0]< binCount[0] &&
906 itStop[1]<binCount[1] && itStop[2] < binCount[2])
918 #pragma omp parallel for 919 for(
size_t ui=0;ui<newX;ui++)
922 for(
size_t uj=0;uj<newY;uj++)
924 for(
size_t uk=0;uk<newZ;uk++)
965 for(
auto ui=0;ui<3;ui++)
967 ASSERT(pMin[ui] <=pMax[ui]);
991 voxels.resize(nX*nY*nZ);
1009 const unsigned int ITEM_BUFFER_SIZE=65536;
1011 std::ifstream CFile(cpFilename,std::ios::binary);
1016 CFile.seekg(0,std::ios::end);
1019 size_t fileSize = CFile.tellg();
1020 if(fileSize !=nX*nY*nZ*
sizeof(T))
1025 CFile.seekg(0,std::ios::beg);
1027 unsigned int curBufferSize=ITEM_BUFFER_SIZE*
sizeof(T);
1028 unsigned char *buffer =
new unsigned char[curBufferSize];
1032 while(fileSize < curBufferSize)
1033 curBufferSize = curBufferSize >> 1;
1039 std::cerr << std::endl <<
"|";
1040 for(
unsigned int ui=0; ui<100; ui++)
1042 std::cerr <<
"| 100%" << std::endl <<
"|";
1045 unsigned int lastFrac=0;
1052 while((
size_t)CFile.tellg() <= fileSize-curBufferSize)
1055 if(!silent && ((
unsigned int)(((
float)CFile.tellg()*100.0f)/(
float)fileSize) > lastFrac))
1059 lastFrac=(
unsigned int)(((
float)CFile.tellg()*100.0f)/(
float)fileSize) ;
1063 CFile.read((
char *)buffer,curBufferSize);
1069 for(
size_t position=0; position<curBufferSize; position+=(
sizeof(T)))
1070 voxels[ui++] = (*((T *)(buffer+position)));
1074 curBufferSize = curBufferSize >> 1 ;
1076 }
while(curBufferSize>
sizeof(T));
1086 std::cerr <<
"| done" << std::endl;
1098 std::ofstream file(filename, std::ios::binary);
1104 for(
size_t ui=0; ui<voxels.size(); ui++)
1108 file.write((
char *)&v,
sizeof(T));
1120 T tmp(initialValue);
1121 size_t n=voxels.size();
1122 #pragma omp parallel for reduction(+:tmp) 1123 for(
size_t ui=0;ui<n;ui++)
1134 float prefactor=1.0;
1135 for(
size_t ui=0;ui<3;ui++)
1137 prefactor*=(maxBound[ui]-
1139 (
float)binCount[ui];
1145 double accumulation(0.0);
1147 #pragma omp parallel for reduction(+:accumulation) 1148 for(
size_t ui=0;ui<voxels.size(); ui++)
1149 accumulation+=voxels[ui];
1151 return prefactor*accumulation;
1159 bins=binCount[0]*binCount[1]*binCount[2];
1162 #pragma omp parallel for reduction(+:sum) 1163 for(
size_t ui=0;ui<bins; ui++)
1165 if(voxels[ui]>=minIntensity)
1175 std::swap(binCount[0],other.binCount[0]);
1176 std::swap(binCount[1],other.binCount[1]);
1177 std::swap(binCount[2],other.binCount[2]);
1179 voxels.swap(other.voxels);
1181 std::swap(maxBound,other.maxBound);
1182 std::swap(minBound,other.minBound);
1188 ASSERT(x < binCount[0] && y < binCount[1] && z < binCount[2]);
1189 return voxels[shape3(x,y,z)];
1199 #pragma omp parallel for 1200 for(
size_t ui=0;ui<binCount[0]; ui++)
1202 for(
size_t uj=0;uj<binCount[1]; uj++)
1204 for(
size_t uk=0;uk<binCount[2]; uk++)
1206 if(
getData(ui,uj,uk) < thresh)
1208 #pragma omp critical 1218 #pragma omp parallel for 1219 for(
size_t ui=0;ui<binCount[0]; ui++)
1221 for(
size_t uj=0;uj<binCount[1]; uj++)
1223 for(
size_t uk=0;uk<binCount[2]; uk++)
1225 if(
getData(ui,uj,uk) > thresh)
1227 #pragma omp critical 1243 #pragma omp parallel for 1244 for(
size_t ui=0;ui<(size_t)binCount[0]; ui++)
1246 for(
size_t uj=0;uj<binCount[1]; uj++)
1248 for(
size_t uk=0;uk<binCount[2]; uk++)
1250 if(
getData(ui,uj,uk) < thresh)
1258 #pragma omp parallel for 1259 for(
size_t ui=0;ui<(size_t)binCount[0]; ui++)
1261 for(
size_t uj=0;uj<binCount[1]; uj++)
1263 for(
size_t uk=0;uk<binCount[2]; uk++)
1265 if(
getData(ui,uj,uk) > thresh)
1276 result.
resize(binCount[0],binCount[1],binCount[2],
1279 #pragma omp parallel for 1280 for(
size_t ui=0;ui<(size_t)binCount[0]; ui++)
1282 for(
size_t uj=0;uj<binCount[1]; uj++)
1284 for(
size_t uk=0;uk<binCount[2]; uk++)
1287 res=(
getData(ui,uj,uk) > thresh);
1305 for(
auto i=0;i<3;i++)
1307 ASSERT(v[i] == binCount[i]);
1313 for(
auto i=0; i<voxels.size(); i++)
1321 for(
auto i=0; i<voxels.size(); i++)
1331 const T &onThresh,
const T &offThresh)
const 1334 result.
resize(binCount[0],binCount[1],
1335 binCount[2],minBound,maxBound);
1336 #pragma omp parallel for 1337 for(
size_t ui=0;ui<(size_t)binCount[0]; ui++)
1339 for(
size_t uj=0;uj<binCount[1]; uj++)
1341 for(
size_t uk=0;uk<binCount[2]; uk++)
1343 if(
getData(ui,uj,uk) < thresh)
1344 result.
setData(ui,uj,uk,offThresh);
1347 result.
setData(ui,uj,uk,onThresh);
1360 return *std::min_element(voxels.begin(),voxels.end());
1367 return *std::max_element(voxels.begin(),voxels.end());
1377 min=*std::min_element(voxels.begin(),voxels.end());
1378 max=*std::max_element(voxels.begin(),voxels.end());
1391 for(
size_t ui=0; ui<points.size(); ui++)
1397 if(x < binCount[0] && y < binCount[1] && z< binCount[2])
1429 for(
size_t ui=0; ui<points.size(); ui++)
1432 getIndex(x,y,z,points[ui].getPosRef());
1435 if(x < binCount[0] && y < binCount[1] && z< binCount[2])
1450 for(
size_t ui=0; ui<points.size(); ui++)
1453 getIndex(x,y,z,points[ui].getPosRef());
1456 if(x < binCount[0] && y < binCount[1] && z< binCount[2])
1473 double volume = 1.0;
1474 for (
int i = 0; i < 3; i++)
1475 volume *= size[i] / binCount[i];
1478 #pragma omp parallel for 1479 for(
size_t ui=0; ui<voxels.size(); ui++)
1480 voxels[ui] /= volume;
1488 double volume = 1.0;
1489 for (
int i = 0; i < 3; i++)
1490 volume *= size[i] / binCount[i];
1500 ASSERT(p[0] >=minBound[0] && p[1] >=minBound[1] && p[2] >=minBound[2] &&
1501 p[0] <=maxBound[0] && p[1] <=maxBound[1] && p[2] <=maxBound[2]);
1502 x=(size_t)((p[0]-minBound[0])/(maxBound[0]-minBound[0])*(
float)binCount[0]);
1503 y=(size_t)((p[1]-minBound[1])/(maxBound[1]-minBound[1])*(
float)binCount[1]);
1504 z=(size_t)((p[2]-minBound[2])/(maxBound[2]-minBound[2])*(
float)binCount[2]);
1506 if(x == binCount[0])
1508 if(y == binCount[1])
1510 if(z == binCount[2])
1523 if(x==binCount[0] &&
1524 fabs(p[0] -maxBound[0]) < sqrtf(std::numeric_limits<float>::epsilon()))
1526 if(y==binCount[1] &&
1527 fabs(p[1] -maxBound[1]) < sqrtf(std::numeric_limits<float>::epsilon()))
1529 if(z==binCount[2] &&
1530 fabs(p[2] -maxBound[2]) < sqrtf(std::numeric_limits<float>::epsilon()))
1538 std::fill(voxels.begin(),voxels.end(),v);
1549 size_t dimA,dimB,nA;
1583 for(
size_t ui=0;ui<binCount[dimA];ui++)
1585 for(
size_t uj=0;uj<binCount[dimB];uj++)
1586 p[uj*nA + ui] =
getData(offset,ui,uj);
1592 for(
size_t ui=0;ui<binCount[dimA];ui++)
1594 for(
size_t uj=0;uj<binCount[dimB];uj++)
1595 p[uj*nA + ui] =
getData(ui,offset,uj);
1601 for(
size_t ui=0;ui<binCount[dimA];ui++)
1603 for(
size_t uj=0;uj<binCount[dimB];uj++)
1604 p[uj*nA + ui] =
getData(ui,uj,offset);
1615 T *p,
size_t interpMode)
const 1617 ASSERT(offset <=1.0f && offset >=0.0f);
1625 slicePos=roundf(offset*binCount[normal]);
1626 slicePos=std::min(slicePos,binCount[normal]-1);
1634 size_t sliceUpper,sliceLower;
1635 if(binCount[0] == 1)
1636 sliceUpper=sliceLower=0;
1639 sliceUpper=ceilf(offset*binCount[normal]);
1641 if(sliceUpper >=binCount[normal])
1642 sliceUpper=binCount[normal]-1;
1643 else if(sliceUpper==0)
1646 sliceLower=sliceUpper-1;
1651 size_t numEntries=binCount[(normal+1)%3]*binCount[(normal+2)%3];
1653 pLower =
new T[numEntries];
1655 getSlice(normal,sliceLower,pLower);
1660 float delta=modff(offset*binCount[normal],&integ);
1661 for(
size_t ui=0;ui<numEntries;ui++)
1662 p[ui] = delta*(p[ui]-pLower[ui]) + pLower[ui];
1687 getIndex(index[0],index[1],index[2],p);
1694 fraction =fraction/pitch;
1699 for(
unsigned int ui=0;ui<3;ui++)
1701 if(index[ui] == (binCount[ui]-1))
1714 float xf = 1-fraction[0];
1718 xHigh = index[0] + iPlus[0];
1719 c[0][0] =
getData(xLow,index[1],index[2])*xf +
getData(xHigh,index[1],index[2])*fraction[0] ;
1720 c[0][1] =
getData(xLow,index[1],index[2]+iPlus[2])*xf +
getData(xHigh,index[1],index[2]+iPlus[2])*fraction[0] ;
1721 c[1][0] =
getData(xLow,index[1]+iPlus[1],index[2])*xf +
getData(xHigh,index[1]+iPlus[1],index[2])*fraction[0] ;
1722 c[1][1] =
getData(xLow,index[1]+iPlus[1],index[2]+iPlus[2])*xf +
getData(xHigh,index[1]+iPlus[1],index[2]+iPlus[2])*fraction[0] ;
1726 c0 = c[0][0]*(1-fraction[1]) + c[1][0]*fraction[1];
1727 c1 = c[0][1]*(1-fraction[1]) + c[1][1]*fraction[1];
1729 v= c0*(1-fraction[2])+c1*fraction[2];
1738 ASSERT(v.voxels.size() == voxels.size());
1743 for(
size_t ui=0;ui<voxels.size();ui++)
1746 voxels[ui]/=v.voxels[ui];
1761 for(
size_t ui=0;ui<voxels.size();ui++)
1775 for(
size_t ui=0;ui<3;ui++)
1778 if(v.binCount[ui] != binCount[ui])
1782 return v.voxels == voxels;
1786 bool runVoxelTests();
T min() const
Find minimum in dataset.
static size_t sizeofType()
Return the sizeof value for the T type.
void operator/=(const Voxels< T > &v)
Element wise division.
void binarise(Voxels< T > &result, const T &thresh, const T &onThresh, const T &offThresh) const
Binarise the data into a result vector.
bool containsPt(const Point3D &pt) const
Check to see if the point is contained in, or part of the walls of the cube.
size_t count(const T &minIntensity) const
count the number of cells with at least this intensity
void applyMask(const Voxels< bool > &mask, const T &newVal, bool invert=false)
Apply a mask to this dataset, where the mask is true (if not inverting), replace with specified val (...
T getSum(const T &initialVal=T(0.0)) const
Get the total value of the data field.
void castVoxels(const Voxels< T > &src, Voxels< U > &dest)
Convert one type of voxel into another by assignment operator.
AtomProbe::Point3D getMaxBounds() const
size_t resize(size_t newX, size_t newY, size_t newZ, const AtomProbe::Point3D &newMinBound=AtomProbe::Point3D(0.0f, 0.0f, 0.0f), const AtomProbe::Point3D &newMaxBound=AtomProbe::Point3D(1.0f, 1.0f, 1.0f))
Resize the data field.
size_t deprecatedGetEdgeUniqueIndex(size_t x, size_t y, size_t z, unsigned int edge) const
DEPRECATED FUNCTION : Get a unique integer that corresponds to the edge index for the voxel; where ed...
void getEdgeEndApproxVals(size_t edgeUniqId, T &a, T &b) const
Return the values that are associated with the edge ends, as returned by getEdgeEnds.
size_t resizeKeepData(size_t newX, size_t newY, size_t newZ, unsigned int direction=CLIP_LOWER_SOUTH_WEST, const AtomProbe::Point3D &newMinBound=AtomProbe::Point3D(0.0f, 0.0f, 0.0f), const AtomProbe::Point3D &newMaxBound=AtomProbe::Point3D(1.0f, 1.0f, 1.0f), const T &fill=T(0), bool doFill=false)
Resize the data field, maintaining data as best as possible.
int countIons(const std::vector< AtomProbe::IonHit > &ions, bool noWrap=true, bool doErase=true)
Generate a dataset that consists of the counts of points in a given voxel.
void getBounds(AtomProbe::Point3D &pMin, AtomProbe::Point3D &pMax) const
Get the bounding size.
float getBinVolume() const
void thresholdToBoolMask(const T &thresh, bool keepUpper, Voxels< bool > &result) const
Generate a boolean voxel field stating whether the data is above or below the threshold specified...
void swap(Voxels< T > &v)
Swap object contents with other voxel object.
AtomProbe::Point3D getMinBounds() const
Get the bounding box vertex (min/max)
T trapezIntegral() const
Integrate the datataset via the trapezoidal method.
void sumVoxels(const Voxels< T > &src, U &counter)
Use one counting type to sum counts in a voxel of given type.
void getBounds(BoundCube &bc) const
void getBounds(Point3D &low, Point3D &high) const
Get the bounds of the cube as two points, the lower left (minimum bound) and upper right corner (max ...
Template class that stores 3D voxel data.
void calculateDensity()
Convert voxel intensity into voxel density.
T getData(size_t i) const
Retrieve value of the nth voxel.
size_t init(size_t nX, size_t nY, size_t nZ, const BoundCube &bound)
Initialise the voxel storage.
void fill(const T &val)
Fill all voxels with a given value.
T getPointData(const AtomProbe::Point3D &pt) const
Retrieve the value of a datapoint, this is rounded to the nearest voxel.
void threshold(const T &thresh, bool keepUpper, const T &newVal)
Threshold the voxels, keeping either the lower or upper values above this threshold.
T getData(size_t x, size_t y, size_t z) const
Retrieve the value of a specific voxel.
A 3D point data class storage.
void minMax(T &min, T &max) const
Find both min and max in dataset in the same loop.
AtomProbe::Point3D getPoint(size_t x, size_t y, size_t z) const
Get the position associated with an XYZ voxel.
void getEdgeEnds(size_t edgeIndex, AtomProbe::Point3D &a, AtomProbe::Point3D &b) const
Convert the edge index (as generated by getEdgeUniqueIndex) into a cenre position.
void setEntry(size_t n, const T &val)
size_t loadFile(const char *cpFilename, size_t nX, size_t nY, size_t nZ, bool silent=false)
Load the voxels from file.
void setBounds(const AtomProbe::Point3D &pMin, const AtomProbe::Point3D &pMax)
Set the bounding size.
void setPoint(const AtomProbe::Point3D &pt, const T &val)
Set the value of a point in the dataset.
void getInterpSlice(size_t normal, float offset, T *p, size_t interpMode=VOX_INTERP_NONE) const
void getIndex(size_t &x, size_t &y, size_t &z, const AtomProbe::Point3D &p) const
Retrieve the XYZ voxel location associated with a given position.
Helper class to define a bounding cube.
void copy(Voxels< T > &newCopy) const
Clone data into another object.
size_t getCellUniqueEdgeIndex(size_t x, size_t y, size_t z, unsigned int edge) const
Get a unique integer that corresponds to an edge index for the voxel; where edges are shared between ...
AtomProbe::Point3D getPitch() const
! Get the spacing for a unit cell
void setData(size_t x, size_t y, size_t z, const T &val)
Retrieve a reference to the data ata given position.
T max() const
Find maximum in dataset.
bool operator==(const Voxels< T > &v) const
void getSlice(size_t normal, size_t offset, T *p) const
int countPoints(const std::vector< AtomProbe::Point3D > &points, bool noWrap=true, bool doErase=true)
Generate a dataset that consists of the counts of points in a given voxel.
void getSize(size_t &x, size_t &y, size_t &z) const
Get the size of the data field.
void getEdgeCell(size_t edgeUniqId, size_t &x, size_t &y, size_t &z, size_t &axis) const
Convert edge index (only as generted by getCellUniqueEdgeIndex) into a cell & axis value...
void clear()
Empty the data.
void getInterpolatedData(const AtomProbe::Point3D &pt, T &v) const
size_t writeFile(const char *cpFilename) const
Write the voxel objects in column major written out to file.
void getIndexWithUpper(size_t &x, size_t &y, size_t &z, const AtomProbe::Point3D &p) const
Retrieve the XYZ voxel location associated with a given position,.
void thresholdForPosition(std::vector< AtomProbe::Point3D > &p, const T &thresh, bool lowerEq=false) const
Find the positions of the voxels that are above or below a given value.
void setBounds(float xMin, float yMin, float zMin, float xMax, float yMax, float zMax)
Set the bounds by passing in minima and maxima of each dimension.
void expand(const BoundCube &b)
Expand (as needed) volume such that the argument bounding cube is enclosed by this one...
void getAxisBounds(size_t axis, float &minV, float &maxV) const