DMRITool  v0.1.1-139-g860d86b4
Diffusion MRI Tool
itkSamplingScheme3D.hxx
Go to the documentation of this file.
1 
19 #ifndef __itkSamplingScheme3D_hxx
20 #define __itkSamplingScheme3D_hxx
21 
22 
23 #include "itkSamplingScheme3D.h"
24 #include "utl.h"
25 
26 namespace itk
27 {
28 
29 template <class TPixelType>
32  m_RadiusVector(new STDVectorType()),
33  m_IndicesInShells(new Index2DVectorType()),
34  m_OrientationsCartesian(new MatrixType()),
35  m_OrientationsSpherical(new MatrixType())
36 {
37  m_Tau = ONE_OVER_4_PI_2; // 4*pi*pi*tau ==1
38  m_DeltaSmall = 0;
39  m_DeltaBig = m_Tau; // m_Tau = m_DeltaBig - m_DeltaSmall/3
40  m_RadiusThresholdSingleShell = 1e-4;
41 }
42 
43 template <class TPixelType>
44 void
47 {
48  if (m_RadiusVector != radiusVec)
49  {
50  m_RadiusVector = radiusVec;
51  if (m_RadiusVector->size()>0)
52  GroupRadiusValues();
53  this->Modified();
54  }
55 }
56 
57 template <class TPixelType>
60 ::GetRadiusVectorInShell(unsigned int shellIndex)
61 {
62  unsigned int num = GetNumberOfShells();
63  STDVectorPointer radiusVec(new STDVectorType());
64  if (shellIndex<num && m_RadiusVector->size()>num)
65  {
66  IndexVectorType vecTmp = (*m_IndicesInShells)[shellIndex];
67  for ( unsigned int i = 0; i < vecTmp.size(); i += 1 )
68  {
69  radiusVec->push_back( (*m_RadiusVector)[vecTmp[i] ] );
70  }
71  }
72  return radiusVec;
73 }
74 
75 template <class TPixelType>
78 ::GetOrientationsCartesian(const bool alwarysReCalculate)
79 {
80  if (alwarysReCalculate)
81  {
82  m_OrientationsCartesian = MatrixPointer(new MatrixType());
83  utl::PointsContainerToUtlMatrix<Superclass, double>(*this, *m_OrientationsCartesian);
84  return m_OrientationsCartesian;
85  }
86  else
87  {
88  if (m_OrientationsCartesian->Rows()==GetNumberOfSamples())
89  return m_OrientationsCartesian;
90  else if (m_OrientationsSpherical->Rows()==GetNumberOfSamples())
91  {
92  m_OrientationsCartesian = MatrixPointer(new MatrixType());
93  *m_OrientationsCartesian = utl::SphericalToCartesian(*m_OrientationsSpherical);
94  return m_OrientationsCartesian;
95  }
96  else if (this->GetNumberOfSamples()>0)
97  {
98  m_OrientationsCartesian = MatrixPointer(new MatrixType());
99  utl::PointsContainerToUtlMatrix<Superclass, double>(*this, *m_OrientationsCartesian);
100  return m_OrientationsCartesian;
101  }
102  else
103  utlGlobalException(true, "no orientations");
104  return MatrixPointer(new MatrixType());
105  }
106 }
107 
108 template <class TPixelType>
111 ::GetOrientationsSpherical(const bool alwarysReCalculate)
112 {
113  if (alwarysReCalculate)
114  {
115  m_OrientationsCartesian = MatrixPointer(new MatrixType());
116  m_OrientationsSpherical = MatrixPointer(new MatrixType());
117  utl::PointsContainerToUtlMatrix<Superclass, double>(*this, *m_OrientationsCartesian);
118  *m_OrientationsSpherical = utl::CartesianToSpherical(*m_OrientationsCartesian);
119  return m_OrientationsSpherical;
120  }
121  else
122  {
123  if (m_OrientationsSpherical->Rows()==GetNumberOfSamples())
124  return m_OrientationsSpherical;
125  else if (m_OrientationsCartesian->Rows()==GetNumberOfSamples())
126  {
127  m_OrientationsSpherical = MatrixPointer(new MatrixType());
128  *m_OrientationsSpherical = utl::CartesianToSpherical(*m_OrientationsCartesian);
129  return m_OrientationsSpherical;
130  }
131  else if (this->GetNumberOfSamples()>0)
132  {
133  m_OrientationsCartesian = MatrixPointer(new MatrixType());
134  m_OrientationsSpherical = MatrixPointer(new MatrixType());
135  utl::PointsContainerToUtlMatrix<Superclass, double>(*this, *m_OrientationsCartesian);
136  *m_OrientationsSpherical = utl::CartesianToSpherical(*m_OrientationsCartesian);
137  return m_OrientationsSpherical;
138  }
139  else
140  utlGlobalException(true, "no orientations");
141  return MatrixPointer(new MatrixType());
142  }
143 }
144 
145 template <class TPixelType>
146 void
149 {
150  m_OrientationsCartesian = mat;
151  utl::UtlMatrixToPointsContainer<double, Superclass>(*m_OrientationsCartesian, *this);
152  m_OrientationsSpherical=MatrixPointer(new MatrixType());
153  this->Modified();
154 }
155 
156 template <class TPixelType>
159 ::GetOrientationsSphericalInShell(const unsigned int shellIndex)
160 {
161  unsigned int num = GetNumberOfSamplesInShell(shellIndex);
162  utlGlobalException(num==0, "need to set m_IndicesInShells");
163  utlException(shellIndex>num, "wrong index");
164  MatrixPointer mat (new MatrixType(num, 3));
165  m_OrientationsSpherical = GetOrientationsSpherical();
166  *mat = m_OrientationsSpherical->GetRows((*m_IndicesInShells)[shellIndex]);
167  return mat;
168 }
169 
170 template <class TPixelType>
171 void
174 {
175  m_OrientationsSpherical = mat;
176  m_OrientationsCartesian = MatrixPointer(new MatrixType());
177  *m_OrientationsCartesian = utl::SphericalToCartesian(*m_OrientationsSpherical);
178  utl::UtlMatrixToPointsContainer<double, Superclass>(*m_OrientationsCartesian, *this);
179  this->Modified();
180 }
181 
182 template <class TPixelType>
185 ::GetOrientationsCartesianInShell(const unsigned int shellIndex) const
186 {
187  unsigned int num = GetNumberOfSamplesInShell(shellIndex);
188  utlGlobalException(num==0, "need to set m_IndicesInShells");
189  utlException(shellIndex>num, "wrong index");
190  MatrixPointer mat (new MatrixType(num, 3));
191  for ( unsigned int i = 0; i < num; i += 1 )
192  {
193  unsigned int ii = (*m_IndicesInShells)[shellIndex][i];
194  (*mat)(i,0) = (*this)[ii][0];
195  (*mat)(i,1) = (*this)[ii][1];
196  (*mat)(i,2) = (*this)[ii][2];
197  }
198  return mat;
199 }
200 
201 template <class TPixelType>
202 void
205 {
206  unsigned int num = GetNumberOfSamples();
207  double xi,yi,zi, norm2;
208  bool isPerformNormalization = false;
209  for ( unsigned int i = 0; i < num; i += 1 )
210  {
211  xi = (*this)[i][0];
212  yi = (*this)[i][1];
213  zi = (*this)[i][2];
214  norm2 = xi*xi + yi*yi + zi*zi;
215  if (norm2>0 && std::fabs(norm2-1)>1e-8 )
216  {
217  norm2 = std::sqrt(norm2);
218  (*this)[i][0] = xi / norm2;
219  (*this)[i][1] = yi / norm2;
220  (*this)[i][2] = yi / norm2;
221  isPerformNormalization = true;
222  }
223  }
224  if (isPerformNormalization)
225  {
226  m_OrientationsSpherical=MatrixPointer(new MatrixType());
227  m_OrientationsCartesian=MatrixPointer(new MatrixType());
228  }
229 }
230 
231 template <class TPixelType>
232 typename LightObject::Pointer
235 {
236  typename LightObject::Pointer loPtr = Superclass::InternalClone();
237 
238  typename Self::Pointer rval = dynamic_cast<Self *>(loPtr.GetPointer());
239  if(rval.IsNull())
240  {
241  itkExceptionMacro(<< "downcast to type " << this->GetNameOfClass()<< " failed.");
242  }
243 
244  for ( int i = 0; i < this->size(); i += 1 )
245  rval->push_back((*this)[i]);
246 
247  rval->m_DeltaSmall = m_DeltaSmall;
248  rval->m_DeltaBig = m_DeltaBig;
249  rval->m_Tau = m_Tau;
250  rval->m_RadiusThresholdSingleShell = m_RadiusThresholdSingleShell;
251 
252  // NOTE: shared_ptr is thread safe, if the data is read only, thus do not need to copy the data block.
253  // NOTE: when changing members in m_SamplingScheme3D, use new to generate another pointer for SmartPointer.
254  *rval->m_RadiusVector = *m_RadiusVector;
255  *rval->m_IndicesInShells = *m_IndicesInShells;
256  rval->m_OrientationsCartesian = m_OrientationsCartesian;
257  rval->m_OrientationsSpherical = m_OrientationsSpherical;
258  return loPtr;
259 }
260 
261 template <class TPixelType>
262 void
265 {
266  this->Superclass::Initialize();
267  m_RadiusVector=STDVectorPointer(new STDVectorType());
268  m_IndicesInShells=Index2DVectorPointer(new Index2DVectorType());
269  m_OrientationsSpherical=MatrixPointer(new MatrixType());
270  m_OrientationsCartesian=MatrixPointer(new MatrixType());
271  this->Modified();
272 }
273 
274 template <class TPixelType>
275 void
278 {
279  if (this->size()==0)
280  return;
281  utlGlobalException(m_IndicesInShells->size()==0, "need to set m_IndicesInShells first");
282  utlGlobalException(m_RadiusVector->size()>0 && m_RadiusVector->size()!=this->size(), "different size of radiusVector and gradients");
283 
284  Pointer selfClone = this->Clone();
285  this->Clear();
286  int ind=0;
287  for ( int i = 0; i < selfClone->GetNumberOfShells(); ++i )
288  {
289  IndexVectorType indices = (*selfClone->m_IndicesInShells)[i];
290  IndexVectorType indicesNew;
291  for ( int j = 0; j < indices.size(); ++j )
292  {
293  this->push_back((*selfClone)[indices[j]]);
294  if (selfClone->m_RadiusVector->size()>0)
295  this->m_RadiusVector->push_back((*selfClone->m_RadiusVector)[indices[j]]);
296  indicesNew.push_back(ind);
297  ind++;
298  }
299  this->m_IndicesInShells->push_back(indicesNew);
300  }
301 }
302 
303 template <class TPixelType>
304 std::vector<typename SamplingScheme3D<TPixelType>::STDVectorType>
307 {
308  utlGlobalException(m_RadiusVector->size()==0, "no radius values");
309  std::vector<STDVectorType> radiusVectors;
310  if (m_IndicesInShells->size()==0)
311  {
312  this->m_IndicesInShells = Index2DVectorPointer(new Index2DVectorType());
313  STDVectorType radiusMax, radiusMin;
314  for ( int i = 0; i < m_RadiusVector->size(); i += 1 )
315  {
316  double radius = (*m_RadiusVector)[i];
317  int j=0;
318  for ( j = 0; j < radiusVectors.size(); j += 1 )
319  {
320  if (radius>=radiusMin[j]-m_RadiusThresholdSingleShell && radius<=radiusMax[j]+m_RadiusThresholdSingleShell)
321  {
322  radiusVectors[j].push_back(radius);
323  (*m_IndicesInShells)[j].push_back(i);
324  if (radius<radiusMin[j])
325  radiusMin[j] = radius;
326  else if (radius>radiusMax[j])
327  radiusMax[j] = radius;
328  break;
329  }
330  }
331  if (j==radiusVectors.size())
332  {
333  STDVectorType radiusVecTemp;
334  radiusVecTemp.push_back(radius);
335  radiusVectors.push_back(radiusVecTemp);
336  IndexVectorType radiusIndexTemp;
337  radiusIndexTemp.push_back(i);
338  m_IndicesInShells->push_back(radiusIndexTemp);
339  radiusMin.push_back(radius);
340  radiusMax.push_back(radius);
341  }
342  }
343 
344  this->Modified();
345  for ( int j = 0; j < radiusVectors.size(); j += 1 )
346  {
347  itkAssertOrThrowMacro(radiusMax[j]-radiusMin[j]<100.0, "the range of radius values is larger than 100, which can not be in the same shell");
348  }
349  }
350  else
351  {
352  for ( int i = 0; i < m_IndicesInShells->size(); i += 1 )
353  {
354  STDVectorType radiusVecTemp;
355  IndexVectorType indexTemp = (*m_IndicesInShells)[i];
356  for ( int j = 0; j < indexTemp.size(); j += 1 )
357  {
358  radiusVecTemp.push_back((*m_RadiusVector)[ indexTemp[j] ]);
359  }
360  radiusVectors.push_back(radiusVecTemp);
361  }
362  }
363  return radiusVectors;
364 }
365 
366 template <class TPixelType>
367 void
370 {
371  utlGlobalException(m_RadiusVector->size()==0, "no radius values");
372  std::vector<STDVectorType> radiusVectors = GroupRadiusValues();
373 
374  for ( int j = 0; j < radiusVectors.size(); j += 1 )
375  {
376  double radiusMean=0;
377  for ( int k = 0; k < radiusVectors[j].size(); k += 1 )
378  radiusMean += radiusVectors[j][k];
379  radiusMean /= radiusVectors[j].size();
380  for ( int k = 0; k < radiusVectors[j].size(); k += 1 )
381  {
382  (*m_RadiusVector)[(*m_IndicesInShells)[j][k] ] = radiusMean;
383  }
384  }
385  this->Modified();
386 }
387 
388 template <class TPixelType>
389 void
391 ::ReadOrientationFile(const std::string& gradFile, const int NoSymmetricDuple,
392  const int flipx, const int flipy, const int flipz, const bool need_normalize)
393 {
394  Clear();
395  m_OrientationsCartesian = utl::ReadGrad<double>(gradFile, NoSymmetricDuple, CARTESIAN_TO_CARTESIAN, flipx, flipy, flipz, need_normalize);
396  utl::UtlMatrixToPointsContainer<double, Superclass>(*m_OrientationsCartesian, *this);
397  std::vector<int> indicesTmp;
398  m_IndicesInShells=Index2DVectorPointer(new Index2DVectorType());
399  for ( int j = 0; j < this->size(); j += 1 )
400  indicesTmp.push_back(j);
401  m_IndicesInShells->push_back(indicesTmp);
402  this->NormalizeDirections();
403  this->Modified();
404 }
405 
406 template <class TPixelType>
407 void
409 ::ReadOrientationFileList(const std::vector<std::string>& gradFileVec, const int NoSymmetricDuple,
410  const int flipx, const int flipy, const int flipz, const bool need_normalize)
411 {
412  utlGlobalException(gradFileVec.size()==0, "empty file list");
413  Clear();
414  MatrixPointer matrix(new MatrixType());
415 
416  std::vector<int> indicesTmp;
417  m_IndicesInShells=Index2DVectorPointer(new Index2DVectorType());
418  int ind=0;
419  for ( int i = 0; i < gradFileVec.size(); i += 1 )
420  {
421  matrix = utl::ReadGrad<double>(gradFileVec[i], NoSymmetricDuple, CARTESIAN_TO_CARTESIAN, flipx, flipy, flipz, need_normalize);
422  Pointer tmpThis = Self::New();
423  utl::UtlMatrixToPointsContainer<double, Superclass>(*matrix, *tmpThis);
424  indicesTmp.clear();
425  for ( int j = 0; j < tmpThis->size(); j += 1 )
426  {
427  this->push_back((*tmpThis)[j] );
428  indicesTmp.push_back( ind++ );
429  }
430  m_IndicesInShells->push_back(indicesTmp);
431  }
432 
433  this->NormalizeDirections();
434  this->Modified();
435 }
436 
437 template < class TPixelType >
438 void
440 ::GenerateFromRandomPoints ( const std::vector<int>& numberOfPoints )
441 {
442  Clear();
443  int ii=0;
444  PointType point;
445  for ( int i = 0; i < numberOfPoints.size(); i += 1 )
446  {
447  std::vector<int> indicesTmp;
448  for ( int j = 0; j < numberOfPoints[i]; j += 1 )
449  {
450  std::vector<double> pp = utl::RandomPointInSphere(true);
451  point[0]=pp[0]; point[1]=pp[1]; point[2]=pp[2];
452  this->push_back(point);
453  indicesTmp.push_back(ii++);
454  }
455  m_IndicesInShells->push_back(indicesTmp);
456  }
457 }
458 
459 
460 template <class TPixelType>
461 void
463 ::AppendOrientation(const double x, const double y, const double z, const int shell)
464 {
465  PointType point;
466  point[0]=x; point[1]=y; point[2]=z;
467  AppendOrientation(point, shell);
468 }
469 
470 template <class TPixelType>
471 void
473 ::AppendOrientation(const PointType& point, const int shell)
474 {
475  this->push_back(point);
476  m_OrientationsSpherical=MatrixPointer(new MatrixType());
477  m_OrientationsCartesian=MatrixPointer(new MatrixType());
478  utlException(shell<-1, "shell should be more than -1");
479  int num = GetNumberOfSamples();
480  if (shell>=0)
481  {
482  if (m_IndicesInShells->size()>shell)
483  (*m_IndicesInShells)[shell].push_back(num);
484  if (m_IndicesInShells->size()==shell)
485  {
486  IndexVectorType indexVec;
487  indexVec.push_back(num);
488  m_IndicesInShells->push_back(indexVec);
489  }
490  utlSAException(m_IndicesInShells->size()<shell)(m_IndicesInShells->size())(shell).msg("wrong shell index");
491  }
492  else
493  {
494  utlSAException(m_IndicesInShells->size()>1)(m_IndicesInShells->size()).msg("need to set shell index, because there are more than 1 shell");
495  if (m_IndicesInShells->size()==1)
496  (*m_IndicesInShells)[0].push_back(num);
497  }
498  this->Modified();
499 }
500 
501 template <class TPixelType>
502 void
504 ::AppendOrientationAndRadiusValue(const double x, const double y, const double z, const double radius, const int shell)
505 {
506  PointType point;
507  point[0]=x; point[1]=y; point[2]=z;
508  AppendOrientation(point, shell);
509  m_RadiusVector->push_back(radius);
510  this->Modified();
511 }
512 
513 template <class TPixelType>
516 ::CalculateInnerProductMatrix(const bool isAbsolute) const
517 {
518  unsigned int num = GetNumberOfSamples();
519  MatrixPointer result(new MatrixType(num, num));
520  double x,y,z, x1,y1,z1, dot;
521  for ( unsigned int i = 0; i < num; i += 1 )
522  {
523  result->operator()(i, i) = 1.0;
524  x = this->operator[](i)[0];
525  y = this->operator[](i)[1];
526  z = this->operator[](i)[2];
527  for ( int j = 0; j < i; j += 1 )
528  {
529  x1 = this->operator[](j)[0];
530  y1 = this->operator[](j)[1];
531  z1 = this->operator[](j)[2];
532  dot = x*x1 + y*y1 + z*z1;
533  if (dot<0 && isAbsolute)
534  result->operator()(i,j) = -dot;
535  else
536  result->operator()(i,j) = dot;
537  result->operator()(j,i) = result->operator()(i,j);
538  }
539  }
540  return result;
541 }
542 
543 template <class TPixelType>
546 ::CalculateElectrostaticEnergyMatrix(const double order ) const
547 {
548  double temp, xi, yi, zi, xj, yj, zj;
549  unsigned int num = GetNumberOfSamples();
550  MatrixPointer result(new MatrixType(num, num));
551  bool orderEqual2 = std::abs(order-2)<1e-8 ? true : false;
552  for(unsigned int i = 0; i < num; i++)
553  {
554  xi = (*this)[i][0];
555  yi = (*this)[i][1];
556  zi = (*this)[i][2];
557  result->operator()(i,i)= std::numeric_limits<double>::max();
558  for ( unsigned int j = 0; j< i; j += 1 )
559  {
560  xj = (*this)[j][0];
561  yj = (*this)[j][1];
562  zj = (*this)[j][2];
563  double dot = xi*xj + yi*yj + zi*zj;
564  double result1 = 2+2*dot;
565  double result2 = 2-2*dot;
566  utlWarning(result1<1e-8 || result2<1e-8, "identical directions, d1=("<<xi<<","<<yi<<","<<zi<<") , d2=("<<xj<<","<<yj<<","<<zj<<")");
567  temp = (!orderEqual2) ? (1.0/std::pow(result1, order*0.5) + 1.0/std::pow(result2, order*0.5)) : (1.0/result1 + 1.0/result2);
568  result->operator()(i,j) = temp;
569  result->operator()(j,i) = temp;
570  }
571  }
572  return result;
573 }
574 
575 template <class TPixelType>
576 double
578 ::CalculatePackingDensity( const bool isSymmetric) const
579 {
580  STDVectorType dist = CalculateMinDistance(isSymmetric);
581  double sum_area=0;
582  for ( int i = 0; i < dist.size(); ++i )
583  {
584  // https://en.wikipedia.org/wiki/Spherical_cap
585  // double area = 1.0/(4.0*M_PI) * (2.0*M_PI*(1-std::cos(dist[i]/2.0))) *2.0;
586  double area = 1-std::cos(dist[i]/2.0);
587  if (!isSymmetric)
588  area /= 2.0;
589  sum_area += area;
590  }
591  return sum_area;
592 }
593 
594 template <class TPixelType>
595 double
597 ::CalculatePackingDensityInShell(const unsigned int shellIndex, const bool isSymmetric) const
598 {
599  STDVectorType dist = CalculateMinDistanceInShell(shellIndex, isSymmetric);
600  double sum_area=0;
601  for ( int i = 0; i < dist.size(); ++i )
602  {
603  double area = 1-std::cos(dist[i]/2.0);
604  if (!isSymmetric)
605  area /= 2.0;
606  sum_area += area;
607  }
608  return sum_area;
609 }
610 
611 template <class TPixelType>
612 double
614 ::CalculateSphericalCodeEntropy( const bool isSymmetric) const
615 {
616  STDVectorType dist = CalculateMinDistance(isSymmetric);
617  STDVectorType pdf(dist.size()+1);
618  double sum_pdf=0.0;
619  for ( int i = 0; i < dist.size(); ++i )
620  {
621  // https://en.wikipedia.org/wiki/Spherical_cap
622  // double theta = dist[i]/2.0;
623  // pdf[i] = 1.0/(4.0*M_PI) * (2.0*M_PI*(1-std::cos(theta))) *2.0;
624  pdf[i] = 1-std::cos(dist[i]/2.0);
625  if (!isSymmetric)
626  pdf[i] /= 2.0;
627  sum_pdf += pdf[i];
628  }
629  pdf.back()= 1.0 - sum_pdf;
630  // utl::PrintVector(pdf, "pdf");
631  return utl::Entropy(pdf, pdf.size());
632 }
633 
634 template <class TPixelType>
635 double
637 ::CalculateSphericalCodeEntropyInShell(const unsigned int shellIndex, const bool isSymmetric) const
638 {
639  STDVectorType dist = CalculateMinDistanceInShell(shellIndex, isSymmetric);
640  STDVectorType pdf(dist.size()+1);
641  double sum_pdf=0.0;
642  for ( int i = 0; i < dist.size(); ++i )
643  {
644  pdf[i] = 1-std::cos(dist[i]/2.0);
645  if (!isSymmetric)
646  pdf[i] /= 2.0;
647  sum_pdf += pdf[i];
648  }
649  pdf.back()= 1.0 - sum_pdf;
650  return utl::Entropy(pdf, pdf.size());
651 }
652 
653 template <class TPixelType>
654 double
656 ::CalculateVoronoiEntropy(const MatrixType& grad, const MatrixType& gradTess, const bool isSymmetric)
657 {
658  unsigned int num = grad.Rows();
659  unsigned int N = gradTess.Rows();
660 
661  MatrixType dotMat = gradTess * grad.GetTranspose();
662  std::vector<int> indices(N,-1);
663  for ( int i = 0; i < N; ++i )
664  {
665  double dotMax=-2.0;
666  for ( int j = 0; j < num; ++j )
667  {
668  double dot = dotMat(i,j);
669  if (isSymmetric)
670  dot = std::fabs(dot);
671 
672  if (dotMax<dot)
673  {
674  dotMax = dot;
675  indices[i] = j;
676  }
677  }
678  }
679 
680  // utl::PrintVector(indices, "indices");
681  utl::Vector<double> distNum(num,0);
682  for ( int i = 0; i < N; ++i )
683  distNum[indices[i]] += 1;
684 
685  // utl::PrintUtlVector(distNum, "distNum");
686  distNum /= (double)N;
687  // utl::PrintUtlVector(distNum, "distNum");
688  return utl::Entropy(distNum, num);
689 }
690 
691 template <class TPixelType>
692 double
694 ::CalculateVoronoiEntropy(const int tess, const bool isSymmetric)
695 {
698  MatrixPointer grad = GetOrientationsCartesian();
699  return CalculateVoronoiEntropy(*grad, *gradT4, isSymmetric);
700 }
701 
702 template <class TPixelType>
703 double
705 ::CalculateVoronoiEntropyInShell(const unsigned int shellIndex, const int tess, const bool isSymmetric)
706 {
709  MatrixPointer grad = GetOrientationsCartesianInShell(shellIndex);
710  return CalculateVoronoiEntropy(*grad, *gradT4, isSymmetric);
711 }
712 
713 template <class TPixelType>
714 double
716 ::CalculateMaxDot(const unsigned int index, const bool isSymmetric) const
717 {
718  utlGlobalException(this->GetNumberOfSamples()<2, "No enough points!");
719  unsigned int num = GetNumberOfSamples();
720 
721  double dotMax=-3;
722 
723  double x = (*this)[index][0];
724  double y = (*this)[index][1];
725  double z = (*this)[index][2];
726 
727  for(unsigned int i = 0; i < num; i++)
728  {
729  if (i==index)
730  continue;
731 
732  double xi = (*this)[i][0];
733  double yi = (*this)[i][1];
734  double zi = (*this)[i][2];
735  double dot = x*xi + y*yi + z*zi;
736  if (isSymmetric && dot<0 )
737  dot = -dot;
738 
739  if (dot>dotMax)
740  dotMax = dot;
741  }
742  utlGlobalException(dotMax<-1.0-M_EPS || dotMax>1+M_EPS, "wrong dot, not in [-1,1]");
743  return dotMax;
744 }
745 
746 template <class TPixelType>
747 double
749 ::CalculateMaxDotInShell(const unsigned int sampleIndex, const unsigned int shellIndex, const bool isSymmetric) const
750 {
751  utlGlobalException(this->GetNumberOfSamples()<2, "No enough points!");
752  unsigned int num = GetNumberOfSamplesInShell(shellIndex);
753 
754  double dotMax=-3;
755 
756  double x = (*this)[sampleIndex][0];
757  double y = (*this)[sampleIndex][1];
758  double z = (*this)[sampleIndex][2];
759 
760  for(unsigned int i = 0; i < num; i++)
761  {
762  unsigned int ii = (*m_IndicesInShells)[shellIndex][i];
763  if (ii==sampleIndex)
764  continue;
765 
766  double xi = (*this)[ii][0];
767  double yi = (*this)[ii][1];
768  double zi = (*this)[ii][2];
769  double dot = x*xi + y*yi + z*zi;
770  if (isSymmetric && dot<0 )
771  dot = -dot;
772 
773  if (dot>dotMax)
774  dotMax = dot;
775  }
776  utlGlobalException(dotMax<-1.0-M_EPS || dotMax>1+M_EPS, "wrong dot, not in [-1,1]");
777  return dotMax;
778 }
779 
780 template <class TPixelType>
781 double
783 ::CalculateMinDistance(const unsigned int index, const bool isSymmetric) const
784 {
785  double dotMax = CalculateMaxDot(index, isSymmetric);
786  double angle=0;
787  if(dotMax >= -1.0 - M_EPS && dotMax <= -1.0 + M_EPS)
788  angle = M_PI;
789  else if(dotMax <= 1.0 + M_EPS && dotMax >= 1.0 - M_EPS)
790  angle = 0;
791  else
792  angle = std::acos(dotMax);
793  return angle;
794 }
795 
796 template <class TPixelType>
797 double
799 ::CalculateMinDistanceInShell(const unsigned int sampleIndex, const unsigned int shellIndex, const bool isSymmetric) const
800 {
801  double dotMax = CalculateMaxDotInShell(index, isSymmetric);
802  double angle=0;
803  if(dotMax >= -1.0 - M_EPS && dotMax <= -1.0 + M_EPS)
804  angle = M_PI;
805  else if(dotMax <= 1.0 + M_EPS && dotMax >= 1.0 - M_EPS)
806  angle = 0;
807  else
808  angle = std::acos(dotMax);
809  return angle;
810 }
811 
812 template <class TPixelType>
815 ::CalculateMinDistance(const bool isSymmetric) const
816 {
817  STDVectorType angleVec;
818  for(unsigned int i = 0; i < GetNumberOfSamples(); i++)
819  {
820  double angle = CalculateMinDistance(i, isSymmetric);
821  angleVec.push_back(angle);
822  }
823  return angleVec;
824 }
825 
826 template <class TPixelType>
829 ::CalculateMinDistanceInShell(const unsigned int shellIndex, const bool isSymmetric) const
830 {
831  STDVectorType angleVec;
832  unsigned int num = GetNumberOfSamplesInShell(shellIndex);
833  for(unsigned int i = 0; i < num; i++)
834  {
835  unsigned int ii = (*m_IndicesInShells)[shellIndex][i];
836  double angle = CalculateMinDistanceInShell(ii, shellIndex, isSymmetric);
837  angleVec.push_back(angle);
838  }
839  return angleVec;
840 }
841 
842 template <class TPixelType>
843 void
845 ::GetNumbers(int& numberUniqueSamples, int& numberAntipodalSamples, int& numberRepeatedSamples ) const
846 {
847  double xi, yi, zi, xj, yj, zj;
848  unsigned int num = GetNumberOfSamples();
849  numberUniqueSamples=0, numberAntipodalSamples=0, numberRepeatedSamples=0;
850  for(unsigned int i = 0; i < num; ++i)
851  {
852  xi = (*this)[i][0];
853  yi = (*this)[i][1];
854  zi = (*this)[i][2];
855  bool isUnique=true;
856  for ( unsigned int j = 0; j < i; ++j )
857  {
858  xj = (*this)[j][0];
859  yj = (*this)[j][1];
860  zj = (*this)[j][2];
861  double resultSame = (xi-xj)*(xi-xj) + (yi-yj)*(yi-yj) + (zi-zj)*(zi-zj);
862  double resultAntipodal = (xi+xj)*(xi+xj) + (yi+yj)*(yi+yj) + (zi+zj)*(zi+zj);
863  if (resultSame<1e-8 || resultAntipodal<1e-8)
864  isUnique=false;
865  if (resultSame<1e-8)
866  numberRepeatedSamples++;
867  if (resultAntipodal<1e-8)
868  numberAntipodalSamples++;
869  }
870  if (isUnique)
871  numberUniqueSamples++;
872  }
873 }
874 
875 template <class TPixelType>
876 double
878 ::CalculateElectrostaticEnergy(const double order, const bool isNormalize, const bool countHalf ) const
879 {
880  double result = 0;
881  double xi, yi, zi, xj, yj, zj;
882  int kk=0;
883  unsigned int num = GetNumberOfSamples();
884  for(unsigned int i = 0; i < num; i++)
885  {
886  xi = (*this)[i][0];
887  yi = (*this)[i][1];
888  zi = (*this)[i][2];
889  for ( unsigned int j = 0; (countHalf? (j < i) : (j< num) ); j += 1 )
890  {
891  if (i==j)
892  continue;
893  xj = (*this)[j][0];
894  yj = (*this)[j][1];
895  zj = (*this)[j][2];
896  double result1 = (xi-xj)*(xi-xj) + (yi-yj)*(yi-yj) + (zi-zj)*(zi-zj);
897  double result2 = (xi+xj)*(xi+xj) + (yi+yj)*(yi+yj) + (zi+zj)*(zi+zj);
898  utlWarning(result1<1e-8 || result2<1e-8, "identical directions, d1=("<<xi<<","<<yi<<","<<zi<<") , d2=("<<xj<<","<<yj<<","<<zj<<")");
899  double temp = (order!=2) ? (1.0/std::pow(result1, order*0.5) + 1.0/std::pow(result2, order*0.5)) : (1.0/result1 + 1.0/result2);
900  result += temp;
901  kk++;
902  }
903  }
904  if (isNormalize && kk>0)
905  result /= double(kk);
906  return result;
907 }
908 
909 template <class TPixelType>
910 double
912 ::CalculateElectrostaticEnergyInShell(const unsigned int shellIndex, const double order, const bool isNormalize, const bool countHalf ) const
913 {
914  double result = 0;
915  double xi, yi, zi, xj, yj, zj;
916  int kk=0;
917  unsigned int num = GetNumberOfSamplesInShell(shellIndex);
918  for(unsigned int i = 0; i < num; i++)
919  {
920  unsigned int ii = (*m_IndicesInShells)[shellIndex][i];
921  xi = (*this)[ii][0];
922  yi = (*this)[ii][1];
923  zi = (*this)[ii][2];
924  for ( unsigned int j = 0; (countHalf? (j < i) : (j< num) ); j += 1 )
925  {
926  if (i==j)
927  continue;
928  unsigned int jj = (*m_IndicesInShells)[shellIndex][j];
929  xj = (*this)[jj][0];
930  yj = (*this)[jj][1];
931  zj = (*this)[jj][2];
932  double result1 = (xi-xj)*(xi-xj) + (yi-yj)*(yi-yj) + (zi-zj)*(zi-zj);
933  double result2 = (xi+xj)*(xi+xj) + (yi+yj)*(yi+yj) + (zi+zj)*(zi+zj);
934  utlWarning(result1<1e-8 || result2<1e-8, "identical directions, d1=("<<xi<<","<<yi<<","<<zi<<") , d2=("<<xj<<","<<yj<<","<<zj<<")");
935  double temp = (order!=2) ? (1.0/std::pow(result1, order*0.5) + 1.0/std::pow(result2, order*0.5)) : (1.0/result1 + 1.0/result2);
936  result += temp;
937  kk++;
938  }
939  }
940  if (isNormalize && kk>0)
941  result /= double(kk);
942  return result;
943 }
944 
945 template <class TPixelType>
946 double
948 ::CalculateMinDistanceUpperBound(const unsigned int numberOfPoints, const bool isSphericalDistance)
949 {
950  double bound = numberOfPoints*M_PI/(6.0*(numberOfPoints-2.0));
951  bound = -2.0*std::sin(bound)/(std::cos(2*bound)-1);
952  bound = std::sqrt( 4 - bound*bound );
953  if (isSphericalDistance)
954  bound = std::acos((2.0-bound*bound)/2.0);
955  return bound;
956 }
957 
958 template <class TPixelType>
959 void
961 ::PrintSelf(std::ostream& os, Indent indent) const
962 {
963  Superclass::PrintSelf(os, indent);
964  PrintVar3(true, m_Tau, m_DeltaSmall, m_DeltaBig, os<<indent);
965  MatrixType mat;
966  utl::PointsContainerToUtlMatrix<Superclass, double>(*this, mat);
967  utl::PrintUtlMatrix(mat, "Orientations = ", " ", os<<indent);
968  if (m_OrientationsCartesian->Rows()!=0)
969  utl::PrintUtlMatrix(*m_OrientationsCartesian, "m_OrientationsCartesian", " ", os<<indent);
970  else if (m_OrientationsSpherical->Rows()!=0)
971  utl::PrintUtlMatrix(*m_OrientationsSpherical, "m_OrientationsSpherical", " ", os<<indent);
972 
973  utl::PrintVector(*m_RadiusVector, "m_RadiusVector", " ", os<<indent);
974  if (GetNumberOfShells()>0)
975  {
976  os << indent << GetNumberOfShells() << " shells" << std::endl << std::flush;
977  for ( int i = 0; i < GetNumberOfShells(); i += 1 )
978  {
979  os << indent << "shell " << i << " : ";
980  utl::PrintVector((*m_IndicesInShells)[i], "indexVector", " ", os<<indent );
981  }
982  }
983  os << indent << "m_RadiusThresholdSingleShell = " << m_RadiusThresholdSingleShell << std::endl << std::flush;
984 }
985 
986 }
987 
988 
989 #endif
990 
void AppendOrientationAndRadiusValue(const double x, const double y, const double z, const double radius, const int shell=-1)
NDArray<T,1> is a vector class which uses blas mkl.
Definition: utlVector.h:36
MatrixPointer GetOrientationsSphericalInShell(const unsigned int shellIndex)
void GetNumbers(int &numberUniqueSamples, int &numberAntipodalSamples, int &numberRepeatedSamples) const
double CalculateMaxDot(const unsigned int index, const bool isSymmetric=true) const
static MatrixPointer GetGrad(const int tessorder, const int NoSymmetricDuple=DIRECTION_NODUPLICATE, const int mode=CARTESIAN_TO_SPHERICAL, const int flipx=DIRECTION_NOFLIP, const int flipy=DIRECTION_NOFLIP, const int flipz=DIRECTION_NOFLIP, const bool need_normalize=true)
helper functions specifically used in dmritool
static double CalculateMinDistanceUpperBound(const unsigned int numberOfPoints, const bool isSphericalDistance=true)
double CalculateSphericalCodeEntropy(const bool isSymmetric=true) const
void PrintUtlMatrix(const NDArray< T, 2 > &mat, const std::string &str="", const char *separate=" ", std::ostream &os=std::cout)
void SetOrientationsCartesian(const MatrixPointer mat)
#define utlException(cond, expout)
Definition: utlCoreMacro.h:548
double CalculateElectrostaticEnergyInShell(const unsigned int shellIndex, const double order=2.0, const bool isNormalize=true, const bool countHalf=true) const
double CalculateElectrostaticEnergy(const double order=2.0, const bool isNormalize=true, const bool countHalf=true) const
MatrixPointer GetOrientationsCartesian(const bool alwarysReCalculate=false)
void SetRadiusVector(const STDVectorPointer radiusVec)
static double CalculateVoronoiEntropy(const MatrixType &grad, const MatrixType &gradTess, const bool isSymmetric=true)
const T & max(const T &a, const T &b)
Return the maximum between a and b.
Definition: utlCore.h:263
void PrintSelf(std::ostream &os, Indent indent) const ITK_OVERRIDE
NDArray< T, 2 > CartesianToSpherical(const NDArray< T, 2 > &in)
std::vector< IndexVectorType > Index2DVectorType
void ReadOrientationFileList(const std::vector< std::string > &gradFileVec, const int NoSymmetricDuple=DIRECTION_NODUPLICATE, const int flipx=DIRECTION_NOFLIP, const int flipy=DIRECTION_NOFLIP, const int flipz=DIRECTION_NOFLIP, const bool need_normalize=true)
std::vector< STDVectorType > GroupRadiusValues()
LightObject::Pointer InternalClone() const ITK_OVERRIDE
#define M_EPS
Definition: utlCoreMacro.h:54
virtual void CorrectRadiusValues()
double CalculatePackingDensityInShell(const unsigned int shellIndex, const bool isSymmetric=true) const
T abs(const T x)
template version of the fabs function
#define M_PI
Definition: utlCoreMacro.h:57
#define utlGlobalException(cond, expout)
Definition: utlCoreMacro.h:372
double Entropy(const VectorType &pdfVec, const int N)
Definition: utlMath.h:702
#define ONE_OVER_4_PI_2
Definition: utlCoreMacro.h:63
std::vector< double > STDVectorType
std::vector< double > RandomPointInSphere(const bool hemis)
Definition: utlCore.h:1489
std::vector< int > IndexVectorType
Point< TPixelType, 3 > PointType
double CalculateMaxDotInShell(const unsigned int sampleIndex, const unsigned int shellIndex, const bool isSymmetric=true) const
void ReadOrientationFile(const std::string &gradFile, const int NoSymmetricDuple=DIRECTION_NODUPLICATE, const int flipx=DIRECTION_NOFLIP, const int flipy=DIRECTION_NOFLIP, const int flipz=DIRECTION_NOFLIP, const bool need_normalize=true)
this class describes sampling in a 3D space (Q space or R space).
#define utlWarning(cond, expout)
Definition: utlCoreMacro.h:552
utl_shared_ptr< MatrixType > MatrixPointer
#define utlSAException(expr)
Definition: utlCoreMacro.h:543
SmartPointer< Self > Pointer
void SetOrientationsSpherical(const MatrixPointer mat)
static void Initialize(const int tessorder)
void PrintVector(const std::vector< T > &vec, const std::string &str="", const char *separate=" ", std::ostream &os=std::cout, bool showStats=true)
Definition: utlCore.h:1002
void GenerateFromRandomPoints(const std::vector< int > &numberOfPoints)
double CalculateSphericalCodeEntropyInShell(const unsigned int shellIndex, const bool isSymmetric=true) const
NDArray< T, 2 > SphericalToCartesian(const NDArray< T, 2 > &in)
utl_shared_ptr< STDVectorType > STDVectorPointer
#define PrintVar3(cond, var1, var2, var3, os)
Definition: utlCoreMacro.h:462
MatrixPointer CalculateElectrostaticEnergyMatrix(const double order=2.0) const
double CalculateMinDistanceInShell(const unsigned int sampleIndex, const unsigned int shellIndex, const bool isSymmetric=true) const
double CalculateVoronoiEntropyInShell(const unsigned int shellIndex, const int tess=7, const bool isSymmetric=true)
MatrixPointer GetOrientationsCartesianInShell(const unsigned int shellIndex) const
utl_shared_ptr< Index2DVectorType > Index2DVectorPointer
MatrixPointer CalculateInnerProductMatrix(const bool isAbsolute=true) const
MatrixPointer GetOrientationsSpherical(const bool alwarysReCalculate=false)
void AppendOrientation(const double x, const double y, const double z, const int shell=-1)
double CalculateMinDistance(const unsigned int index, const bool isSymmetric=true) const
double CalculatePackingDensity(const bool isSymmetric=true) const
STDVectorPointer GetRadiusVectorInShell(unsigned int shellIndex)