SMILX  1.01
milxModel.cxx
1 /*=========================================================================
2  Program: milxSMILI
3  Module: milxModel
4  Author: Shekhar Chandra
5  Language: C++
6  Created: 18 Apr 2011 12:03:00 EST
7 
8  The Software is copyright (c) Commonwealth Scientific and Industrial Research Organisation (CSIRO)
9  ABN 41 687 119 230.
10  All rights reserved.
11 
12  Licensed under the CSIRO BSD 3-Clause License
13  You may not use this file except in compliance with the License.
14  You may obtain a copy of the License in the file LICENSE.md or at
15 
16  https://stash.csiro.au/projects/SMILI/repos/smili/browse/license.txt
17 
18  Unless required by applicable law or agreed to in writing, software
19  distributed under the License is distributed on an "AS IS" BASIS,
20  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  See the License for the specific language governing permissions and
22  limitations under the License.
23 =========================================================================*/
24 #include "milxModel.h"
25 
26 //VTK
27 #include <vtkAppendPolyData.h>
28 #include <vtkLandmarkTransform.h>
29 #include <vtkProcrustesAlignmentFilter.h>
30 #include <vtkAppendPolyData.h>
31 #include <vtkGraphToPolyData.h>
32 #include <vtkDoubleArray.h>
33 #include <vtkTable.h>
34 #include <vtkTriangle.h>
35 //VTK - Filters
36 #include <vtkCleanPolyData.h>
37 #include <vtkTriangleFilter.h>
38 #include <vtkDecimatePro.h>
39 #include <vtkQuadricDecimation.h>
40 #include <vtkQuadricClustering.h>
41 #include <vtkSmoothPolyDataFilter.h>
42 #include <vtkWindowedSincPolyDataFilter.h>
43 #include <vtkTransformPolyDataFilter.h>
44 #include <vtkIterativeClosestPointTransform.h>
45 #include <vtkLandmarkTransform.h>
46 #include <vtkCurvatures.h>
47 #include <vtkGradientFilter.h>
48 #include <vtkAssignAttribute.h>
49 #include <vtkSelectPolyData.h>
50 #include <vtkPolyDataToImageStencil.h>
51 #include <vtkImageStencil.h>
52 #include <vtkRotationFilter.h>
53 #include <vtkReflectionFilter.h>
54 #include <vtkThreshold.h> //clip
55 #include <vtkGeometryFilter.h>
56 #include <vtkDelaunay3D.h>
57 #include <vtkDelaunay2D.h>
58 #include <vtkExtractEdges.h>
59 #include <vtkTubeFilter.h>
60 #include <vtkVertexGlyphFilter.h>
61 #include <vtkIdFilter.h>
62 #include <vtkGlyph3D.h>
63 #include <vtkPolyDataPointSampler.h>
64 #include <vtkTensorGlyph.h>
65 #include <vtkHedgeHog.h>
66 #include <vtkPolyDataNormals.h>
67 #include <vtkFeatureEdges.h>
68 #include <vtkStripper.h>
69 #include <vtkConnectivityFilter.h>
70 #include <vtkSimpleElevationFilter.h>
71 #include <vtkElevationFilter.h>
72 #include <vtkKMeansStatistics.h>
73 #include <vtkQuantizePolyDataPoints.h>
74 //VTK 5.10 +
75 /*#include <vtkPolyDataToReebGraphFilter.h>
76 #include <vtkReebGraphSimplificationFilter.h>
77 #include <vtkReebGraphSurfaceSkeletonFilter.h>*/
78 //VTK - Sources
79 #include <vtkGlyphSource2D.h>
80 #include <vtkSphereSource.h>
81 #include <vtkArrowSource.h>
82 //VTK Imaging
83 #include <vtkImageFlip.h>
84 #include <vtkImageMarchingCubes.h>
85 #if VTK_MAJOR_VERSION > 5
86  #include <vtkMultiBlockDataSet.h>
87  #include <vtkMultiBlockDataGroupFilter.h>
88 #endif
89 //VTK Extension
90 //#include "vtkAreaSimplificationMetric.h"
91 //SMILI
92 #include "milxMath.h"
93 
94 typedef vtkDoubleArray milxArrayType;
95 
96 namespace milx
97 {
98 
100 {
101  InternalInPlaceOperation = false;
102 }
103 
104 Model::Model(vtkSmartPointer<vtkPolyData> model)
105 {
106  InternalInPlaceOperation = false;
107  SetInput(model);
108 }
109 
110 //IO
111 void Model::AddInput(vtkSmartPointer<vtkPolyData> model)
112 {
113  vtkSmartPointer<vtkAppendPolyData> appendPolyData = vtkSmartPointer<vtkAppendPolyData>::New();
114 #if (VTK_MAJOR_VERSION > 5)
115  if(CurrentModel)
116  appendPolyData->AddInputData(CurrentModel);
117  appendPolyData->AddInputData(model);
118 #else
119  if(CurrentModel)
120  appendPolyData->AddInput(CurrentModel);
121  appendPolyData->AddInput(model);
122 #endif
123  if(VTKProgressUpdates->IsBeingObserved())
124  appendPolyData->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
125  appendPolyData->Update();
126 
127  UpdateModelState(appendPolyData);
128 }
129 
130 void Model::SetInput(vtkSmartPointer<vtkPolyData> model)
131 {
132  if(!CurrentModel)
133  CurrentModel = vtkSmartPointer<vtkPolyData>::New();
134 
135  if(!InternalInPlaceOperation && CurrentModel != model)
136  CurrentModel->DeepCopy(model);
137  else
138  CurrentModel = model;
139 
141 }
142 
143 void Model::SetTransform(vtkSmartPointer<vtkAbstractTransform> newTransform)
144 {
145  if(!IsCurrentModel())
146  return;
147 
148  if(!CurrentTransform)
149  {
150  CurrentTransform = vtkSmartPointer<vtkTransform>::New();
151  CurrentTransform->Identity();
152  }
153 
154  vtkSmartPointer<vtkTransform> linearTransform = vtkTransform::SafeDownCast(newTransform);
155  if(linearTransform)
156  {
157  //CurrentTransform->Concatenate(linearTransform->GetMatrix());
158  CurrentTransform->SetMatrix(linearTransform->GetMatrix());
159  }
160 
161  PrintDebug("Transforming Surface");
162  vtkSmartPointer<vtkTransformPolyDataFilter> transformedMesh = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
163  #if VTK_MAJOR_VERSION <= 5
164  transformedMesh->SetInput(CurrentModel);
165  #else
166  transformedMesh->SetInputData(CurrentModel);
167  #endif
168  transformedMesh->SetTransform(newTransform);
169  if(VTKProgressUpdates->IsBeingObserved())
170  transformedMesh->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
171  transformedMesh->Update();
172 
173  UpdateModelState(transformedMesh);
174 }
175 
176 void Model::SetGraph(vtkSmartPointer<vtkMutableUndirectedGraph> graph)
177 {
178  if(!CurrentModel)
179  CurrentModel = vtkSmartPointer<vtkPolyData>::New();
180 
181  vtkSmartPointer<vtkGraphToPolyData> graphPolyData = vtkSmartPointer<vtkGraphToPolyData>::New();
182  #if VTK_MAJOR_VERSION <= 5
183  graphPolyData->SetInput(graph);
184  #else
185  graphPolyData->SetInputData(graph);
186  #endif
187  if(VTKProgressUpdates->IsBeingObserved())
188  graphPolyData->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
189  graphPolyData->Update();
190 
191  UpdateModelState(graphPolyData);
192 }
193 
194 void Model::SetPoints(vtkSmartPointer<vtkPoints> modelPoints)
195 {
196  if(!CurrentModel)
197  CurrentModel = vtkSmartPointer<vtkPolyData>::New();
198 
199  CurrentModel->SetPoints(modelPoints);
200 }
201 
202 void Model::SetPolys(vtkSmartPointer<vtkCellArray> modelPolys)
203 {
204  if(!IsCurrentModel())
205  return;
206 
207  CurrentModel->SetPolys(modelPolys);
208 }
209 
210 void Model::SetVectors(vtkSmartPointer<vtkDataArray> modelVectors)
211 {
212  if(!IsCurrentModel())
213  return;
214 
215  CurrentModel->GetPointData()->SetVectors(modelVectors);
216 }
217 
218 void Model::SetScalars(vtkSmartPointer<vtkDataArray> modelScalars)
219 {
220  if(!IsCurrentModel())
221  return;
222 
223  CurrentModel->GetPointData()->SetScalars(modelScalars);
224 }
225 
227 {
228  FillScalars(0.0);
229 }
230 
231 void Model::FillScalars(const coordinateType value)
232 {
233  if(CurrentModel->GetPointData()->GetScalars())
234  CurrentModel->GetPointData()->GetScalars()->FillComponent(0, value);
235  else
236  {
237  vtkSmartPointer<milxArrayType> scalars = vtkSmartPointer<milxArrayType>::New();
238  scalars->SetName("Reset Scalars");
239  scalars->SetNumberOfTuples(CurrentModel->GetNumberOfPoints());
240  scalars->SetNumberOfComponents(1);
241  scalars->FillComponent(0, value);
242  CurrentModel->GetPointData()->SetScalars(scalars);
243  }
244 }
245 
246 void Model::ClearScalars(vtkSmartPointer<vtkPolyData> &mesh)
247 {
248  if(!mesh)
249  return;
250 
251 #if (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION < 8)
252  mesh->GetPointData()->SetActiveScalars(NULL);
253 #else
254  const int n = mesh->GetPointData()->GetNumberOfArrays();
256  for(int j = 0; j < n; j ++)
257  {
258  //Ignore vector arrays etc.
259  if(mesh->GetPointData()->GetArray(n-1-j)->GetNumberOfComponents() == 1)
260  mesh->GetPointData()->RemoveArray(n-1-j);
261  }
262 #endif
263 }
264 
266 {
267  vtkSmartPointer<vtkPolyData> mesh = vtkSmartPointer<vtkPolyData>::New();
268  mesh->DeepCopy(CurrentModel); //Deep copy is to allow undo
269 
270  ClearScalars(mesh);
271 
272  UpdateModelStateFromModel(mesh);
273 }
274 
276 {
277  vtkSmartPointer<vtkPolyData> mesh = vtkSmartPointer<vtkPolyData>::New();
278  mesh->DeepCopy(CurrentModel); //Deep copy is to allow undo
279 
280  ClearArrays(mesh);
281 
282  UpdateModelStateFromModel(mesh);
283 }
284 
285 //Filters
287 {
288  if(!IsCurrentModel())
289  return;
290 
291  PrintDebug("Cleaning");
292  vtkSmartPointer<vtkCleanPolyData> cleanFilter = vtkSmartPointer<vtkCleanPolyData>::New();
293  #if VTK_MAJOR_VERSION <= 5
294  cleanFilter->SetInput(CurrentModel);
295  #else
296  cleanFilter->SetInputData(CurrentModel);
297  #endif
298  if(VTKProgressUpdates->IsBeingObserved())
299  cleanFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
300  cleanFilter->Update();
301 
302  UpdateModelState(cleanFilter);
303 }
304 
306 {
307  if(!IsCurrentModel())
308  return;
309 
310  PrintDebug("Triangulating");
311  vtkSmartPointer<vtkTriangleFilter> triangulate = vtkSmartPointer<vtkTriangleFilter>::New();
312  #if VTK_MAJOR_VERSION <= 5
313  triangulate->SetInput(CurrentModel);
314  #else
315  triangulate->SetInputData(CurrentModel);
316  #endif
317  if(VTKProgressUpdates->IsBeingObserved())
318  triangulate->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
319  triangulate->Update();
320 
321  UpdateModelState(triangulate);
322 }
323 
324 void Model::MatchInformation(vtkSmartPointer<vtkPolyData> matchMesh, const bool rescale)
325 {
326  if(!IsCurrentModel())
327  return;
328 
329  PrintDebug("Matching Information");
330  coordinate modelCentroid = milx::Math<coordinateType>::Centroid(CurrentModel->GetPoints());
331  coordinate otherCentroid = milx::Math<coordinateType>::Centroid(matchMesh->GetPoints());
332 #ifndef VTK_ONLY
333  coordinate newCentroid = otherCentroid - modelCentroid;
334 #else
335  coordinateType newCentroid[3];
336  newCentroid[0] = otherCentroid[0] - modelCentroid[0];
337  newCentroid[1] = otherCentroid[1] - modelCentroid[1];
338  newCentroid[2] = otherCentroid[2] - modelCentroid[2];
339 #endif
340 
341  //Scale
342  double modelScale = milx::Math<coordinateType>::CentroidSize(CurrentModel->GetPoints(), modelCentroid, true);
343  double otherScale = milx::Math<coordinateType>::CentroidSize(matchMesh->GetPoints(), otherCentroid, true);
344  double scaling = otherScale/modelScale;
345 
346  vtkSmartPointer<vtkTransform> transformer = vtkSmartPointer<vtkTransform>::New();
347  transformer->Translate(newCentroid[0], newCentroid[1], newCentroid[2]);
348  if(rescale)
349  transformer->Scale(scaling, scaling, scaling);
350 
351  SetTransform(transformer);
352 
353 #if defined VTK_ONLY
354  delete modelCentroid;
355  delete otherCentroid;
356 #endif
357 }
358 
359 void Model::IterativeClosestPointsRegistration(vtkSmartPointer<vtkPolyData> fixedMesh, const bool similarity, const int maxPoints)
360 {
361  if(!IsCurrentModel())
362  return;
363 
364  PrintDebug("Iterative Closest Points");
365  vtkSmartPointer<vtkIterativeClosestPointTransform> icp = vtkSmartPointer<vtkIterativeClosestPointTransform>::New();
366  icp->SetSource(CurrentModel);
367  icp->SetTarget(fixedMesh);
368  icp->CheckMeanDistanceOn();
369  icp->StartByMatchingCentroidsOn();
370  icp->SetMaximumMeanDistance(0.001);
371  icp->SetMaximumNumberOfIterations(300);
372  icp->SetMaximumNumberOfLandmarks(maxPoints);
373  icp->GetLandmarkTransform()->SetModeToRigidBody();
374  if(VTKProgressUpdates->IsBeingObserved())
375  icp->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
376  if(similarity)
377  icp->GetLandmarkTransform()->SetModeToSimilarity();
378  icp->Update();
379 
380  vtkMatrix4x4* transformMatrix = icp->GetMatrix();
381  vtkSmartPointer<vtkTransform> transformer = vtkSmartPointer<vtkTransform>::New();
382  transformer->SetMatrix(transformMatrix);
383 
384  SetTransform(transformer);
385 }
386 
387 void Model::LandmarkBasedRegistration(vtkSmartPointer<vtkPolyData> fixedMesh, const bool similarity)
388 {
389  if(!IsCurrentModel())
390  return;
391 
392  if(CurrentModel->GetNumberOfPoints() != fixedMesh->GetNumberOfPoints())
393  {
394  PrintError("Landmark-based registration requires equal number of points. Ignoring Operation.");
395  return;
396  }
397 
398  PrintDebug("Landmark Transform");
399  vtkSmartPointer<vtkLandmarkTransform> landmarkTransform = vtkSmartPointer<vtkLandmarkTransform>::New();
400  landmarkTransform->SetModeToRigidBody();
401  if(similarity)
402  landmarkTransform->SetModeToSimilarity();
403  landmarkTransform->SetSourceLandmarks(CurrentModel->GetPoints());
404  landmarkTransform->SetTargetLandmarks(fixedMesh->GetPoints());
405  if(VTKProgressUpdates->IsBeingObserved())
406  landmarkTransform->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
407  landmarkTransform->Update();
408 
409  vtkMatrix4x4* transformMatrix = landmarkTransform->GetMatrix();
410  vtkSmartPointer<vtkTransform> transformer = vtkSmartPointer<vtkTransform>::New();
411  transformer->SetMatrix(transformMatrix);
412 
413  SetTransform(transformer);
414 }
415 
416 void Model::Decimate(const float reduceFactor)
417 {
418  Triangulate();
420  PrintDebug("PRO Decimation");
421  vtkSmartPointer<vtkDecimatePro> decimateFilter = vtkSmartPointer<vtkDecimatePro>::New(); //Deliberate, destroy after use
422  #if VTK_MAJOR_VERSION <= 5
423  decimateFilter->SetInput(CurrentModel);
424  #else
425  decimateFilter->SetInputData(CurrentModel);
426  #endif
427  decimateFilter->SetTargetReduction(reduceFactor); //10% reduction (if there was 100 triangles, now there will be 90)
428  if(VTKProgressUpdates->IsBeingObserved())
429  decimateFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
430  decimateFilter->Update();
431 
432  UpdateModelState(decimateFilter);
433 }
434 
435 void Model::QuadricDecimate(const float reduceFactor)
436 {
437  Triangulate();
439  PrintDebug("Quadric Decimation");
440  vtkSmartPointer<vtkQuadricDecimation> decimateFilter = vtkSmartPointer<vtkQuadricDecimation>::New(); //Deliberate, destroy after use
441  #if VTK_MAJOR_VERSION <= 5
442  decimateFilter->SetInput(CurrentModel);
443  #else
444  decimateFilter->SetInputData(CurrentModel);
445  #endif
446  decimateFilter->SetTargetReduction(reduceFactor);
447  if(VTKProgressUpdates->IsBeingObserved())
448  decimateFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
449  decimateFilter->Update();
450 
451  UpdateModelState(decimateFilter);
452 }
453 
455 {
456  Triangulate();
458  PrintDebug("Quadric Clustering Decimation");
459  vtkSmartPointer<vtkQuadricClustering> decimateFilter = vtkSmartPointer<vtkQuadricClustering>::New(); //Deliberate, destroy after use
460  #if VTK_MAJOR_VERSION <= 5
461  decimateFilter->SetInput(CurrentModel);
462  #else
463  decimateFilter->SetInputData(CurrentModel);
464  #endif
465  decimateFilter->AutoAdjustNumberOfDivisionsOn();
466  if(VTKProgressUpdates->IsBeingObserved())
467  decimateFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
468  decimateFilter->Update();
469 
470  UpdateModelState(decimateFilter);
471 }
472 
473 void Model::LaplacianSmoothing(const int iterations)
474 {
475  if(!IsCurrentModel())
476  return;
477 
478  PrintDebug("Laplacian Smoothing");
479  vtkSmartPointer<vtkSmoothPolyDataFilter> smoothFilter = vtkSmartPointer<vtkSmoothPolyDataFilter>::New(); //Deliberate, destroy after use
480  #if VTK_MAJOR_VERSION <= 5
481  smoothFilter->SetInput(CurrentModel);
482  #else
483  smoothFilter->SetInputData(CurrentModel);
484  #endif
485  smoothFilter->SetNumberOfIterations(iterations);
486  if(VTKProgressUpdates->IsBeingObserved())
487  smoothFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
488  smoothFilter->Update();
489 
490  UpdateModelState(smoothFilter);
491 }
492 
493 void Model::WindowedSincSmoothing(const int iterations, const float passBand)
494 {
495  if(!IsCurrentModel())
496  return;
497 
498  PrintDebug("Windowed Sinc Smoothing");
499  vtkSmartPointer<vtkWindowedSincPolyDataFilter> smoothFilter = vtkSmartPointer<vtkWindowedSincPolyDataFilter>::New(); //Deliberate, destroy after use
500  #if VTK_MAJOR_VERSION <= 5
501  smoothFilter->SetInput(CurrentModel);
502  #else
503  smoothFilter->SetInputData(CurrentModel);
504  #endif
505  smoothFilter->SetNumberOfIterations(iterations);
506  smoothFilter->SetPassBand(passBand);
507  if(VTKProgressUpdates->IsBeingObserved())
508  smoothFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
509  smoothFilter->Update();
510 
511  UpdateModelState(smoothFilter);
512 }
513 
514 void Model::Curvature(const bool meanCurvature)
515 {
516  if(!IsCurrentModel())
517  return;
518 
519  vtkSmartPointer<vtkCurvatures> curvatureFilter = vtkSmartPointer<vtkCurvatures>::New(); //Deliberate, destroy after use
520  #if VTK_MAJOR_VERSION <= 5
521  curvatureFilter->SetInput(CurrentModel);
522  #else
523  curvatureFilter->SetInputData(CurrentModel);
524  #endif
525  curvatureFilter->SetCurvatureTypeToMean();
526  if(!meanCurvature)
527 // curvatureFilter->SetCurvatureTypeToGaussian();
528  curvatureFilter->SetCurvatureTypeToMaximum();
529 // curvatureFilter->SetCurvatureTypeToMinimum();
530  if(VTKProgressUpdates->IsBeingObserved())
531  curvatureFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
532  curvatureFilter->Update();
533 
534  UpdateModelState(curvatureFilter);
535 }
536 
538 {
539  if(!IsCurrentModel() || !CurrentModel->GetPointData()->GetScalars())
540  return;
541 
542  vtkSmartPointer<vtkGradientFilter> gradientFilter = vtkSmartPointer<vtkGradientFilter>::New(); //Deliberate, destroy after use
543  #if VTK_MAJOR_VERSION <= 5
544  gradientFilter->SetInput(CurrentModel);
545  #else
546  gradientFilter->SetInputData(CurrentModel);
547  #endif
548  if(VTKProgressUpdates->IsBeingObserved())
549  gradientFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
550 
551  vtkSmartPointer<vtkGeometryFilter> geometry = vtkSmartPointer<vtkGeometryFilter>::New();
552  geometry->SetInputConnection(gradientFilter->GetOutputPort());
553 
554  vtkSmartPointer<vtkAssignAttribute> vectors = vtkSmartPointer<vtkAssignAttribute>::New();
555  vectors->SetInputConnection(geometry->GetOutputPort());
556  vectors->Assign("Gradients", vtkDataSetAttributes::VECTORS, vtkAssignAttribute::POINT_DATA);
557  vectors->Update();
558 
559  UpdateModelStateFromModel(vectors->GetPolyDataOutput());
560 }
561 
562 void Model::DistanceMap(vtkSmartPointer<vtkPoints> loopPoints)
563 {
564  if(!IsCurrentModel())
565  return;
566 
567  vtkSmartPointer<vtkSelectPolyData> selection = vtkSmartPointer<vtkSelectPolyData>::New();
568  #if VTK_MAJOR_VERSION <= 5
569  selection->SetInput(CurrentModel);
570  #else
571  selection->SetInputData(CurrentModel);
572  #endif
573  selection->SetLoop(loopPoints);
574  selection->GenerateSelectionScalarsOn();
575  selection->SetSelectionModeToSmallestRegion(); //negative scalars inside
576 // selection->SetSelectionModeToClosestPointRegion();
577  if(VTKProgressUpdates->IsBeingObserved())
578  selection->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
579  selection->Update();
580 
581  UpdateModelState(selection);
582 }
583 
584 void Model::GaussianWeightScalars(float stddev, float clampValue)
585 {
586  if(!IsCurrentModel() || !GetScalars())
587  return;
588 
589  vtkSmartPointer<vtkPolyData> mesh = vtkSmartPointer<vtkPolyData>::New();
590  mesh->DeepCopy(CurrentModel);
591 
592  vtkSmartPointer<vtkDataArray> scalars = mesh->GetPointData()->GetScalars();
593 
594  const int n = mesh->GetNumberOfPoints();
595  const float stddevSquared = 0.5*stddev*stddev;
596  for(int j = 0; j < n; j ++)
597  {
598  double *value = scalars->GetTuple(j);
599  value[0] = exp(-value[0]*value[0]/stddevSquared);
600  if(value[0] < clampValue)
601  value[0] = clampValue;
602  scalars->SetTuple(j, value);
603  }
604 
605  UpdateModelStateFromModel(mesh);
606 }
607 
608 void Model::Rotate(const bool xAxis, const bool yAxis, const bool zAxis, const float angle, const coordinate centre)
609 {
610  if(!IsCurrentModel())
611  return;
612 
613  vtkSmartPointer<vtkRotationFilter> rotator = vtkSmartPointer<vtkRotationFilter>::New();
614  #if VTK_MAJOR_VERSION <= 5
615  rotator->SetInput(CurrentModel);
616  #else
617  rotator->SetInputData(CurrentModel);
618  #endif
619  if(VTKProgressUpdates->IsBeingObserved())
620  rotator->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
621  rotator->CopyInputOff();
622  if(xAxis)
623  rotator->SetAxisToX();
624  if(yAxis)
625  rotator->SetAxisToY();
626  if(zAxis)
627  rotator->SetAxisToZ();
628  rotator->SetAngle(angle);
629  rotator->SetCenter(centre[0], centre[1], centre[2]);
630  rotator->SetNumberOfCopies(1);
631  rotator->Update();
632 
634  vtkSmartPointer<vtkGeometryFilter> region = vtkSmartPointer<vtkGeometryFilter>::New();
635  region->SetInputConnection(rotator->GetOutputPort());
636  if(VTKProgressUpdates->IsBeingObserved())
637  region->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
638  region->Update();
639 
640  UpdateModelState(region);
641 }
642 
643 void Model::Flip(const bool xAxis, const bool yAxis, const bool zAxis)
644 {
645  if(!IsCurrentModel())
646  return;
647 
648  vtkSmartPointer<vtkReflectionFilter> flipper = vtkSmartPointer<vtkReflectionFilter>::New();
649  #if VTK_MAJOR_VERSION <= 5
650  flipper->SetInput(CurrentModel);
651  #else
652  flipper->SetInputData(CurrentModel);
653  #endif
654  if(VTKProgressUpdates->IsBeingObserved())
655  flipper->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
656  flipper->CopyInputOff();
657  if(xAxis)
658  flipper->SetPlaneToX();
659  if(yAxis)
660  flipper->SetPlaneToY();
661  if(zAxis)
662  flipper->SetPlaneToZ();
663  flipper->Update();
664 
666  vtkSmartPointer<vtkGeometryFilter> region = vtkSmartPointer<vtkGeometryFilter>::New();
667  region->SetInputConnection(flipper->GetOutputPort());
668  if(VTKProgressUpdates->IsBeingObserved())
669  region->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
670  region->Update();
671 
672  UpdateModelState(region);
673 }
674 
675 void Model::Clip(const coordinateType belowValue, const coordinateType aboveValue)
676 {
677  if(!IsCurrentModel())
678  return;
679 
680  vtkSmartPointer<vtkThreshold> thresh = vtkSmartPointer<vtkThreshold>::New();
681  #if VTK_MAJOR_VERSION <= 5
682  thresh->SetInput(CurrentModel);
683  #else
684  thresh->SetInputData(CurrentModel);
685  #endif
686  //~ thresh->ThresholdByLower(clusterID);
687  //~ thresh->ThresholdByUpper(value);
688  thresh->ThresholdBetween(belowValue, aboveValue);
689  if(VTKProgressUpdates->IsBeingObserved())
690  thresh->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
691 
693  vtkSmartPointer<vtkGeometryFilter> region = vtkSmartPointer<vtkGeometryFilter>::New();
694  region->SetInputConnection(thresh->GetOutputPort());
695  if(VTKProgressUpdates->IsBeingObserved())
696  region->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
697  region->Update();
698 
699  UpdateModelState(region);
700 }
701 
702 void Model::Threshold(const coordinateType belowVal, const coordinateType aboveVal, const coordinateType outsideVal)
703 {
704  if(!IsCurrentModel())
705  return;
706 
707  vtkSmartPointer<vtkPolyData> newMesh = vtkSmartPointer<vtkPolyData>::New();
708  newMesh->DeepCopy(CurrentModel);
709 
710  //Threshold
711  ThresholdScalars(newMesh, aboveVal, belowVal, outsideVal);
712 
713  UpdateModelStateFromModel(newMesh);
714 }
715 
716 void Model::Threshold(const coordinateType belowVal, const coordinateType aboveVal, const coordinateType insideVal, const coordinateType outsideVal)
717 {
718  if(!IsCurrentModel())
719  return;
720 
721  vtkSmartPointer<vtkPolyData> newMesh = vtkSmartPointer<vtkPolyData>::New();
722  newMesh->DeepCopy(CurrentModel);
723 
724  //Threshold
725  BinaryThresholdScalars(newMesh, aboveVal, belowVal, insideVal, outsideVal);
726 
727  UpdateModelStateFromModel(newMesh);
728 }
729 
730 void Model::Mask(vtkSmartPointer<vtkPolyData> maskMesh)
731 {
732  if(!IsCurrentModel())
733  return;
734 
735  vtkSmartPointer<vtkPolyData> newMesh = vtkSmartPointer<vtkPolyData>::New();
736  newMesh->DeepCopy(CurrentModel);
737 
738  //Threshold
739  MaskScalars(newMesh, maskMesh);
740 
741  UpdateModelStateFromModel(newMesh);
742 }
743 
744 void Model::IsoSurface(vtkSmartPointer<vtkImageData> img, double minValue)
745 {
746  vtkSmartPointer<vtkImageMarchingCubes> iso = vtkSmartPointer<vtkImageMarchingCubes>::New();
747  #if VTK_MAJOR_VERSION <= 5
748  iso->SetInput(img);
749  #else
750  iso->SetInputData(img);
751  #endif
752  iso->SetValue(0, minValue);
753  iso->ComputeNormalsOn();
754  iso->ComputeScalarsOff();
755  // iso->SetInputMemoryLimit(1000);
756  if(VTKProgressUpdates->IsBeingObserved())
757  iso->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
758  iso->Update();
759 
760  if(!IsCurrentModel())
761  SetInput(iso->GetOutput());
762  else
763  UpdateModelState(iso);
764 }
765 
766 vtkSmartPointer<vtkImageData> Model::Voxelise(const unsigned char insideValue, double *spacing, double *bounds, const size_t padVoxels)
767 {
768  if(!IsCurrentModel())
769  return NULL;
770 
771  vtkSmartPointer<vtkImageData> whiteImage = vtkSmartPointer<vtkImageData>::New();
772 
773  double totalBounds[6];
774  if(bounds == NULL)
775  {
776  bounds = &totalBounds[0];
777  CurrentModel->GetBounds(bounds);
778  }
779  whiteImage->SetSpacing(spacing);
780 
781  //Pad the bounds by a slice
782  bounds[0] -= padVoxels*spacing[0];
783  bounds[1] += padVoxels*spacing[0];
784  bounds[2] -= padVoxels*spacing[1];
785  bounds[3] += padVoxels*spacing[1];
786  bounds[4] -= padVoxels*spacing[2];
787  bounds[5] += padVoxels*spacing[2];
788 
789  // compute dimensions
790  int dim[3];
791  for (int i = 0; i < 3; i++)
792  {
793  dim[i] = static_cast<int>( ceil((bounds[i * 2 + 1] - bounds[i * 2]) / spacing[i]) );
794  }
795  PrintDebug("Dimensions of Voxelisation is " + NumberToString(dim[0]) + "x" + NumberToString(dim[1]) + "x" + NumberToString(dim[2]));
796  whiteImage->SetDimensions(dim);
797  whiteImage->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1);
798 
799  double origin[3];
800  // NOTE: I am not sure whether or not we had to add some offset!
801  origin[0] = bounds[0];// + spacing[0] / 2;
802  origin[1] = bounds[2];// + spacing[1] / 2;
803  origin[2] = bounds[4];// + spacing[2] / 2;
804  whiteImage->SetOrigin(origin);
805 #if VTK_MAJOR_VERSION <= 5
806  whiteImage->SetNumberOfScalarComponents(1);
807  whiteImage->SetScalarTypeToUnsignedChar();
808  whiteImage->AllocateScalars();
809 #else
810  whiteImage->AllocateScalars(VTK_UNSIGNED_CHAR,1);
811 #endif
812 
813  // fill the image with foreground voxels:
814  unsigned char inval = insideValue;
815  unsigned char outval = 0;
816  for (vtkIdType i = 0; i < whiteImage->GetNumberOfPoints(); ++i)
817  whiteImage->GetPointData()->GetScalars()->SetTuple1(i, inval);
818 
819  // polygonal data --> image stencil:
820  PrintDebug("Polygonal data --> Image stencil");
821  vtkSmartPointer<vtkPolyDataToImageStencil> pol2stenc = vtkSmartPointer<vtkPolyDataToImageStencil>::New();
822  #if VTK_MAJOR_VERSION <= 5
823  pol2stenc->SetInput(CurrentModel);
824  #else
825  pol2stenc->SetInputData(CurrentModel);
826  #endif
827  pol2stenc->SetOutputOrigin(origin);
828  pol2stenc->SetOutputSpacing(spacing);
829  pol2stenc->SetOutputWholeExtent(whiteImage->GetExtent());
830  if(VTKProgressUpdates->IsBeingObserved())
831  pol2stenc->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
832  pol2stenc->Update();
833 
834  // cut the corresponding white image and set the background:
835  PrintDebug("Image stencil --> Image");
836  vtkSmartPointer<vtkImageStencil> imgstenc = vtkSmartPointer<vtkImageStencil>::New();
837  #if VTK_MAJOR_VERSION <= 5
838  imgstenc->SetInput(whiteImage);
839  imgstenc->SetStencil(pol2stenc->GetOutput());
840  #else
841  imgstenc->SetInputData(whiteImage);
842  imgstenc->SetStencilConnection(pol2stenc->GetOutputPort());
843  #endif
844  imgstenc->ReverseStencilOff();
845  imgstenc->SetBackgroundValue(outval);
846  if(VTKProgressUpdates->IsBeingObserved())
847  imgstenc->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
848  imgstenc->Update();
849 
850  return imgstenc->GetOutput();
851 }
852 
854 {
855  if(!IsCurrentModel())
856  return;
857 
859  vtkSmartPointer<vtkDelaunay3D> delaunay = vtkSmartPointer<vtkDelaunay3D>::New();
860  #if VTK_MAJOR_VERSION <= 5
861  delaunay->SetInput(CurrentModel);
862  #else
863  delaunay->SetInputData(CurrentModel);
864  #endif
865  if(VTKProgressUpdates->IsBeingObserved())
866  delaunay->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
867  delaunay->Update();
869  vtkSmartPointer<vtkExtractEdges> extract = vtkSmartPointer<vtkExtractEdges>::New();
870  extract->SetInputConnection(delaunay->GetOutputPort());
871  if(VTKProgressUpdates->IsBeingObserved())
872  extract->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
874  vtkSmartPointer<vtkTubeFilter> tubes = vtkSmartPointer<vtkTubeFilter>::New();
875  tubes->SetInputConnection(extract->GetOutputPort());
876  tubes->SetRadius(0.02);
877  tubes->SetNumberOfSides(3);
878  if(VTKProgressUpdates->IsBeingObserved())
879  tubes->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
880  tubes->Update();
881 
882  UpdateModelState(tubes);
883 }
884 
886 {
887  if(!IsCurrentModel())
888  return;
889 
890  vtkSmartPointer<vtkCellArray> aCellArray = vtkSmartPointer<vtkCellArray>::New();
891  vtkSmartPointer<vtkPolyData> triangulatedModel = vtkSmartPointer<vtkPolyData>::New();
892  triangulatedModel->SetPoints(CurrentModel->GetPoints());
893  triangulatedModel->SetPolys(aCellArray);
894 
896  vtkSmartPointer<vtkDelaunay2D> delaunay = vtkSmartPointer<vtkDelaunay2D>::New();
897  #if VTK_MAJOR_VERSION <= 5
898  delaunay->SetInput(CurrentModel);
899  delaunay->SetSource(triangulatedModel);
900  #else
901  delaunay->SetInputData(CurrentModel);
902  delaunay->SetSourceData(triangulatedModel);
903  #endif
904  if(VTKProgressUpdates->IsBeingObserved())
905  delaunay->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
906  delaunay->Update();
907 
908  UpdateModelState(delaunay);
909 }
910 
912 {
913  if(!IsCurrentModel())
914  return;
915 
916  vtkSmartPointer<vtkDelaunay3D> delaunay = vtkSmartPointer<vtkDelaunay3D>::New();
917  #if VTK_MAJOR_VERSION <= 5
918  delaunay->SetInput(CurrentModel);
919  #else
920  delaunay->SetInputData(CurrentModel);
921  #endif
922  if(VTKProgressUpdates->IsBeingObserved())
923  delaunay->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
924  delaunay->Update();
925 
926  vtkSmartPointer<vtkGeometryFilter> region = vtkSmartPointer<vtkGeometryFilter>::New();
927  region->SetInputConnection(delaunay->GetOutputPort());
928  if(VTKProgressUpdates->IsBeingObserved())
929  region->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
930  region->Update();
931 
932  UpdateModelState(region);
933 }
934 
936 {
937  if(!IsCurrentModel())
938  return;
939 
940  vtkSmartPointer<vtkVertexGlyphFilter> vertices = vtkSmartPointer<vtkVertexGlyphFilter>::New();
941  #if VTK_MAJOR_VERSION <= 5
942  vertices->SetInput(CurrentModel);
943  #else
944  vertices->SetInputData(CurrentModel);
945  #endif
946  if(VTKProgressUpdates->IsBeingObserved())
947  vertices->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
948  vertices->Update();
949 
950  UpdateModelState(vertices);
951 }
952 
954 {
955  if(!IsCurrentModel())
956  return;
957 
958  vtkSmartPointer<vtkIdFilter> vertices = vtkSmartPointer<vtkIdFilter>::New();
959  #if VTK_MAJOR_VERSION <= 5
960  vertices->SetInput(CurrentModel);
961  #else
962  vertices->SetInputData(CurrentModel);
963  #endif
964  if(VTKProgressUpdates->IsBeingObserved())
965  vertices->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
966  vertices->SetIdsArrayName("Point IDs");
967  vertices->PointIdsOn();
968  vertices->Update();
969 
970  UpdateModelStateFromModel(vertices->GetPolyDataOutput());
971 }
972 
973 void Model::GenerateVerticesAs2DGlyphs(const GlyphType glyphType)
974 {
975  if(!IsCurrentModel())
976  return;
977 
978  vtkSmartPointer<vtkGlyphSource2D> circle = vtkSmartPointer<vtkGlyphSource2D>::New();
979  if(glyphType == Circle)
980  circle->SetGlyphTypeToCircle();
981  else if(glyphType == Triangle)
982  circle->SetGlyphTypeToTriangle();
983  else if(glyphType == Square)
984  circle->SetGlyphTypeToSquare();
985  else if(glyphType == Diamond)
986  circle->SetGlyphTypeToDiamond();
987  else
988  circle->SetGlyphTypeToThickCross();
989 // circle->SetScale(0.2);
990 // circle->FilledOff();
991 
992  // Glyph the gradient vector
993  vtkSmartPointer<vtkGlyph3D> glyph = vtkSmartPointer<vtkGlyph3D>::New();
994  glyph->SetSourceConnection(circle->GetOutputPort());
995  #if VTK_MAJOR_VERSION <= 5
996  glyph->SetInput(CurrentModel);
997  #else
998  glyph->SetInputData(CurrentModel);
999  #endif
1000  if(VTKProgressUpdates->IsBeingObserved())
1001  glyph->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1002  glyph->Update();
1003 
1004  UpdateModelState(glyph);
1005 }
1006 
1008 {
1009  if(!IsCurrentModel())
1010  return;
1011 
1012  vtkSmartPointer<vtkTubeFilter> tubes = vtkSmartPointer<vtkTubeFilter>::New();
1013  #if VTK_MAJOR_VERSION <= 5
1014  tubes->SetInput(CurrentModel);
1015  #else
1016  tubes->SetInputData(CurrentModel);
1017  #endif
1018  tubes->SetRadius(0.02);
1019  tubes->SetNumberOfSides(3);
1020  if(VTKProgressUpdates->IsBeingObserved())
1021  tubes->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1022  tubes->Update();
1023 
1024  UpdateModelState(tubes);
1025 }
1026 
1027 void Model::GeneratePointModel(const double newScale)
1028 {
1029  if(!IsCurrentModel())
1030  return;
1031 
1032  vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
1033 
1034  vtkSmartPointer<vtkGlyph3D> glyphs = vtkSmartPointer<vtkGlyph3D>::New();
1035  glyphs->SetSourceConnection(sphere->GetOutputPort());
1036  #if VTK_MAJOR_VERSION <= 5
1037  glyphs->SetInput(CurrentModel);
1038  #else
1039  glyphs->SetInputData(CurrentModel);
1040  #endif
1041  glyphs->SetScaleModeToDataScalingOff();
1042  glyphs->SetScaleFactor(newScale);
1043  if(VTKProgressUpdates->IsBeingObserved())
1044  glyphs->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1045  glyphs->Update();
1046 
1047  UpdateModelState(glyphs);
1048 }
1049 
1050 void Model::GenerateSampledPoints(const double distance)
1051 {
1052  if(!IsCurrentModel())
1053  return;
1054 
1055  vtkSmartPointer<vtkPolyDataPointSampler> pointSampler = vtkSmartPointer<vtkPolyDataPointSampler>::New();
1056  pointSampler->SetDistance(distance);
1057  #if VTK_MAJOR_VERSION <= 5
1058  pointSampler->SetInput(CurrentModel);
1059  #else
1060  pointSampler->SetInputData(CurrentModel);
1061  #endif
1062  pointSampler->GenerateVertexPointsOn();
1063  pointSampler->GenerateVerticesOn();
1064  if(VTKProgressUpdates->IsBeingObserved())
1065  pointSampler->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1066  pointSampler->Update();
1067 
1068  UpdateModelState(pointSampler);
1069 }
1070 
1071 void Model::GenerateVectorField(const double newScale, const bool useNormals)
1072 {
1073  if(!IsCurrentModel())
1074  return;
1075 
1076  vtkSmartPointer<vtkArrowSource> arrows = vtkSmartPointer<vtkArrowSource>::New();
1077  arrows->SetShaftResolution(3);
1078  arrows->SetTipResolution(3);
1079 
1080  vtkSmartPointer<vtkGlyph3D> glyphs = vtkSmartPointer<vtkGlyph3D>::New();
1081  if(useNormals)
1082  {
1083  glyphs->SetVectorModeToUseNormal();
1084  glyphs->SetScaleModeToScaleByScalar();
1085  }
1086  else
1087  {
1088  glyphs->SetVectorModeToUseVector();
1089  glyphs->SetScaleModeToScaleByVector();
1090  glyphs->SetColorModeToColorByScalar();
1091  }
1092  glyphs->SetSourceConnection(arrows->GetOutputPort());
1093  #if VTK_MAJOR_VERSION <= 5
1094  glyphs->SetInput(CurrentModel);
1095  #else
1096  glyphs->SetInputData(CurrentModel);
1097 
1098  #endif
1099  if(newScale != 0.0)
1100  glyphs->SetScaleFactor(newScale);
1101  if(VTKProgressUpdates->IsBeingObserved())
1102  glyphs->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1103  glyphs->Update();
1104 
1105  UpdateModelState(glyphs);
1106 }
1107 
1108 void Model::GenerateTensorField(const double newScale)
1109 {
1110  if(!IsCurrentModel())
1111  return;
1112 
1113  vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
1114  sphere->SetThetaResolution(4);
1115  sphere->SetPhiResolution(4);
1116 
1117  vtkSmartPointer<vtkTensorGlyph> ellipsoids = vtkSmartPointer<vtkTensorGlyph>::New();
1118  #if VTK_MAJOR_VERSION <= 5
1119  ellipsoids->SetInput(CurrentModel);
1120  ellipsoids->SetSource(sphere->GetOutput());
1121  #else
1122  ellipsoids->SetInputData(CurrentModel);
1123  ellipsoids->SetSourceData(sphere->GetOutput());
1124  #endif
1125  ellipsoids->ScalingOn();
1126  ellipsoids->ClampScalingOn();
1127  if(newScale != 0.0)
1128  ellipsoids->SetScaleFactor(newScale);
1129  ellipsoids->SetColorModeToScalars();
1130  if(VTKProgressUpdates->IsBeingObserved())
1131  ellipsoids->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1132  ellipsoids->Update();
1133 
1134  UpdateModelState(ellipsoids);
1135 }
1136 
1137 void Model::GenerateHedgehog(const double newScale)
1138 {
1139  if(!IsCurrentModel())
1140  return;
1141 
1142  vtkSmartPointer<vtkHedgeHog> hedgeHog = vtkSmartPointer<vtkHedgeHog>::New();
1143  hedgeHog->SetVectorModeToUseVector();
1144  #if VTK_MAJOR_VERSION <= 5
1145  hedgeHog->SetInput(CurrentModel);
1146  #else
1147  hedgeHog->SetInputData(CurrentModel);
1148  #endif
1149  if(newScale != 0.0)
1150  hedgeHog->SetScaleFactor(newScale);
1151  if(VTKProgressUpdates->IsBeingObserved())
1152  hedgeHog->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1153  hedgeHog->Update();
1154 
1155  UpdateModelState(hedgeHog);
1156 }
1157 
1158 void Model::GenerateNormals(const int pointNormals)
1159 {
1160  if(!IsCurrentModel())
1161  return;
1162 
1163  PrintDebug("Generating Normals");
1164  vtkSmartPointer<vtkPolyDataNormals> surfaceNormals = vtkSmartPointer<vtkPolyDataNormals>::New();
1165  surfaceNormals->ComputeCellNormalsOn();
1166  if(pointNormals == 0)
1167  {
1168  surfaceNormals->ComputePointNormalsOn();
1169  surfaceNormals->ComputeCellNormalsOff();
1170  }
1171  else if(pointNormals == 1)
1172  {
1173  surfaceNormals->ComputePointNormalsOff();
1174  surfaceNormals->ComputeCellNormalsOn();
1175  }
1176  else
1177  {
1178  surfaceNormals->ComputePointNormalsOn();
1179  surfaceNormals->ComputeCellNormalsOn();
1180  }
1181  surfaceNormals->SplittingOff();
1182  surfaceNormals->ConsistencyOn();
1183 // surfaceNormals->AutoOrientNormalsOn();
1184  #if VTK_MAJOR_VERSION <= 5
1185  surfaceNormals->SetInput(CurrentModel);
1186  #else
1187  surfaceNormals->SetInputData(CurrentModel);
1188  #endif
1189  surfaceNormals->SetFeatureAngle(37); //For shading
1190  if(VTKProgressUpdates->IsBeingObserved())
1191  surfaceNormals->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1192  surfaceNormals->Update();
1193 
1194  CurrentModel->GetPointData()->SetNormals( surfaceNormals->GetOutput()->GetPointData()->GetNormals() );
1195 }
1196 
1197 void Model::GenerateKMeansClustering(int numberOfClusters)
1198 {
1199  if(!IsCurrentModel())
1200  return;
1201 
1202  vtkSmartPointer<vtkTable> inputData = vtkSmartPointer<vtkTable>::New();
1203  for ( int c = 0; c < 3; ++c )
1204  {
1205  std::stringstream colName;
1206  colName << "coord " << c;
1207  vtkSmartPointer<vtkDoubleArray> doubleArray = vtkSmartPointer<vtkDoubleArray>::New();
1208  doubleArray->SetNumberOfComponents(1);
1209  doubleArray->SetName( colName.str().c_str() );
1210  doubleArray->SetNumberOfTuples(CurrentModel->GetNumberOfPoints());
1211 
1212  for ( int r = 0; r < CurrentModel->GetNumberOfPoints(); ++ r )
1213  {
1214  double p[3];
1215  CurrentModel->GetPoint(r, p);
1216 
1217  doubleArray->SetValue( r, p[c] );
1218  }
1219 
1220  inputData->AddColumn( doubleArray );
1221  }
1222 
1223  vtkSmartPointer<vtkKMeansStatistics> kMeansStatistics = vtkSmartPointer<vtkKMeansStatistics>::New();
1224  #if VTK_MAJOR_VERSION <= 5
1225  kMeansStatistics->SetInput( vtkStatisticsAlgorithm::INPUT_DATA, inputData );
1226  #else
1227  kMeansStatistics->SetInputData( vtkStatisticsAlgorithm::INPUT_DATA, inputData );
1228  #endif
1229  kMeansStatistics->SetColumnStatus( inputData->GetColumnName( 0 ) , 1 );
1230  kMeansStatistics->SetColumnStatus( inputData->GetColumnName( 1 ) , 1 );
1231  kMeansStatistics->SetColumnStatus( inputData->GetColumnName( 2 ) , 1 );
1232  //kMeansStatistics->SetColumnStatus( "Testing", 1 );
1233  kMeansStatistics->RequestSelectedColumns();
1234  kMeansStatistics->SetAssessOption( true );
1235  kMeansStatistics->SetDefaultNumberOfClusters( numberOfClusters );
1236  if(VTKProgressUpdates->IsBeingObserved())
1237  kMeansStatistics->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1238  kMeansStatistics->Update();
1239 
1240  //Form scalars and add to model
1241  const float scaling = 256.0/numberOfClusters;
1242  vtkSmartPointer<vtkFloatArray> clusterArray = vtkSmartPointer<vtkFloatArray>::New();
1243  clusterArray->SetNumberOfComponents(1);
1244  clusterArray->SetName( "Cluster ID" );
1245  for (unsigned int r = 0; r < kMeansStatistics->GetOutput()->GetNumberOfRows(); r++)
1246  {
1247  vtkVariant v = kMeansStatistics->GetOutput()->GetValue(r,kMeansStatistics->GetOutput()->GetNumberOfColumns() - 1);
1248 // std::cout << "Point " << r << " is in cluster " << scaling*(v.ToInt()+1) << std::endl;
1249  clusterArray->InsertNextValue(scaling*(v.ToInt()+1));
1250  }
1251  CurrentModel->GetPointData()->SetScalars(clusterArray);
1252 }
1253 
1254 void Model::GenerateQuantisedPoints(float quantiseFactor)
1255 {
1256  if(!IsCurrentModel())
1257  return;
1258 
1259  vtkSmartPointer<vtkQuantizePolyDataPoints> quantizeFilter = vtkSmartPointer<vtkQuantizePolyDataPoints>::New();
1260  #if VTK_MAJOR_VERSION <= 5
1261  quantizeFilter->SetInput(CurrentModel);
1262  #else
1263  quantizeFilter->SetInputData(CurrentModel);
1264  #endif
1265  quantizeFilter->SetQFactor(quantiseFactor);
1266  if(VTKProgressUpdates->IsBeingObserved())
1267  quantizeFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1268  quantizeFilter->Update();
1269 
1270  UpdateModelState(quantizeFilter);
1271 }
1272 
1274 {
1275  if(!IsCurrentModel())
1276  return;
1277 
1278  // Now extract feature edges, select the boundary
1279  vtkSmartPointer<vtkFeatureEdges> boundaryEdges = vtkSmartPointer<vtkFeatureEdges>::New();
1280  #if VTK_MAJOR_VERSION <= 5
1281  boundaryEdges->SetInput(CurrentModel);
1282  #else
1283  boundaryEdges->SetInputData(CurrentModel);
1284  #endif
1285  boundaryEdges->BoundaryEdgesOn();
1286  boundaryEdges->FeatureEdgesOff();
1287  boundaryEdges->NonManifoldEdgesOff();
1288  boundaryEdges->ManifoldEdgesOff();
1289  if(VTKProgressUpdates->IsBeingObserved())
1290  boundaryEdges->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1291 
1292  //Create triangles
1293  vtkSmartPointer<vtkStripper> boundaryStrips = vtkSmartPointer<vtkStripper>::New();
1294  boundaryStrips->SetInputConnection(boundaryEdges->GetOutputPort());
1295  if(VTKProgressUpdates->IsBeingObserved())
1296  boundaryStrips->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1297  boundaryStrips->Update();
1298 
1299  // Change the polylines into polygons
1300  vtkSmartPointer<vtkPolyData> boundaryPoly = vtkSmartPointer<vtkPolyData>::New();
1301  boundaryPoly->SetPoints(boundaryStrips->GetOutput()->GetPoints());
1302  boundaryPoly->SetPolys(boundaryStrips->GetOutput()->GetLines());
1303 
1304  AddInput(boundaryPoly);
1305 }
1306 
1308 {
1309  if(!IsCurrentModel())
1310  return;
1311 
1312  // Now extract feature edges, select the boundary
1313  vtkSmartPointer<vtkConnectivityFilter> connectivityFilter = vtkSmartPointer<vtkConnectivityFilter>::New();
1314  #if VTK_MAJOR_VERSION <= 5
1315  connectivityFilter->SetInput(CurrentModel);
1316  #else
1317  connectivityFilter->SetInputData(CurrentModel);
1318  #endif
1319  connectivityFilter->SetExtractionModeToAllRegions();
1320  connectivityFilter->ColorRegionsOn();
1321  if(VTKProgressUpdates->IsBeingObserved())
1322  connectivityFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1323 
1324  vtkSmartPointer<vtkGeometryFilter> region = vtkSmartPointer<vtkGeometryFilter>::New();
1325  region->SetInputConnection(connectivityFilter->GetOutputPort());
1326  if(VTKProgressUpdates->IsBeingObserved())
1327  region->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1328  region->Update();
1329 
1330  UpdateModelState(region);
1331 }
1332 
1333 void Model::GenerateElevation(double x, double y, double z)
1334 {
1335  if(!IsCurrentModel())
1336  return;
1337 
1338  // Now extract feature edges, select the boundary
1339  vtkSmartPointer<vtkSimpleElevationFilter> elevationFilter = vtkSmartPointer<vtkSimpleElevationFilter>::New();
1340  #if VTK_MAJOR_VERSION <= 5
1341  elevationFilter->SetInput(CurrentModel);
1342  #else
1343  elevationFilter->SetInputData(CurrentModel);
1344  #endif
1345  elevationFilter->SetVector(x, y, z);
1346  if(VTKProgressUpdates->IsBeingObserved())
1347  elevationFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1348  elevationFilter->Update();
1349 
1350  UpdateModelStateFromModel(elevationFilter->GetPolyDataOutput());
1351 }
1352 
1354 {
1355  if(!IsCurrentModel())
1356  return;
1357 
1358  double bounds[6];
1359  CurrentModel->GetBounds(bounds);
1360 
1361  // Now extract feature edges, select the boundary
1362  vtkSmartPointer<vtkElevationFilter> elevationFilter = vtkSmartPointer<vtkElevationFilter>::New();
1363  #if VTK_MAJOR_VERSION <= 5
1364  elevationFilter->SetInput(CurrentModel);
1365  #else
1366  elevationFilter->SetInputData(CurrentModel);
1367  #endif
1368  elevationFilter->SetLowPoint(bounds[0], bounds[2], bounds[4]);
1369  elevationFilter->SetHighPoint(bounds[0], bounds[2], bounds[5]);
1370  if(VTKProgressUpdates->IsBeingObserved())
1371  elevationFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1372  elevationFilter->Update();
1373 
1374  UpdateModelStateFromModel(elevationFilter->GetPolyDataOutput());
1375 }
1376 /*
1377 void Model::GenerateReebGraph()
1378 {
1379  if(!IsCurrentModel())
1380  return;
1381 
1382  // Now extract feature edges, select the boundary
1383  vtkSmartPointer<vtkPolyDataToReebGraphFilter> ReebGraphFilter = vtkSmartPointer<vtkPolyDataToReebGraphFilter>::New();
1384  #if VTK_MAJOR_VERSION <= 5
1385  ReebGraphFilter->SetInput(CurrentModel);
1386  #else
1387  ReebGraphFilter->SetInputData(CurrentModel);
1388  #endif
1389  if(VTKProgressUpdates->IsBeingObserved())
1390  ReebGraphFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1391  ReebGraphFilter->Update();
1392 
1393  // we don't define any custom simplification metric and use
1394  // the default one (persistence).
1395  vtkSmartPointer<vtkReebGraphSimplificationFilter> ReebSimplification = vtkSmartPointer<vtkReebGraphSimplificationFilter>::New();
1396 // vtkSmartPointer<vtkAreaSimplificationMetric> metric = vtkSmartPointer<vtkAreaSimplificationMetric>::New(); //vtk-ext
1397 // metric->SetLowerBound(0);
1398  // determining the maximum area
1399  //~ double globalArea = 0;
1400  //~ for(int i = 0; i < CurrentModel->GetNumberOfCells(); i ++)
1401  //~ {
1402  //~ vtkTriangle *t = vtkTriangle::SafeDownCast(CurrentModel->GetCell(i));
1403  //~ globalArea += t->ComputeArea();
1404  //~ }
1405  //~ metric->SetUpperBound(globalArea);
1406 // ReebSimplification->SetSimplificationMetric(metric);
1407  ReebSimplification->SetInputConnection(ReebGraphFilter->GetOutputPort()); //do not change, interface requires it
1408  ReebSimplification->SetSimplificationThreshold(0.01);
1409  ReebSimplification->Update();
1410 
1411  vtkSmartPointer<vtkReebGraphSurfaceSkeletonFilter> skeletonFilter = vtkSmartPointer<vtkReebGraphSurfaceSkeletonFilter>::New();
1412  #if VTK_MAJOR_VERSION <= 5
1413  skeletonFilter->SetInput(0, CurrentModel);
1414  #else
1415  skeletonFilter->SetInputData(0, CurrentModel);
1416  #endif
1417  skeletonFilter->SetInputConnection(1, ReebSimplification->GetOutputPort()); //do not change, interface requires it
1418  skeletonFilter->SetNumberOfSamples(5);
1419  if(VTKProgressUpdates->IsBeingObserved())
1420  skeletonFilter->AddObserver(vtkCommand::ProgressEvent, VTKProgressUpdates); //Keeps UI responsive
1421  skeletonFilter->Update();
1422  vtkTable *surfaceSkeleton = skeletonFilter->GetOutput();
1423 
1424  PrintInfo("Reeb Graph has " + NumberToString(surfaceSkeleton->GetNumberOfColumns()*surfaceSkeleton->GetNumberOfRows()) + "points");
1425  vtkSmartPointer<vtkPolyData> embeddedSkeleton = vtkSmartPointer<vtkPolyData>::New();
1426  embeddedSkeleton->Allocate();
1427 
1428  vtkSmartPointer<vtkPoints> skeletonSamples = vtkSmartPointer<vtkPoints>::New();
1429  skeletonSamples->SetNumberOfPoints(surfaceSkeleton->GetNumberOfColumns()*surfaceSkeleton->GetNumberOfRows());
1430 
1431  int sampleId = 0;
1432  for(int i = 0; i < surfaceSkeleton->GetNumberOfColumns(); i++)
1433  {
1434  vtkDoubleArray *arc = vtkDoubleArray::SafeDownCast(surfaceSkeleton->GetColumn(i));
1435 
1436  // now add the samples to the skeleton polyData
1437  int initialSampleId = sampleId;
1438  for(int j = 0; j < arc->GetNumberOfTuples(); j++)
1439  {
1440  double point[3];
1441  arc->GetTupleValue(j, point);
1442  skeletonSamples->SetPoint(sampleId, point);
1443  sampleId++;
1444  }
1445  for(int j = 1; j < arc->GetNumberOfTuples(); j++)
1446  {
1447  vtkIdType samplePair[2];
1448  samplePair[0] = j - 1 + initialSampleId;
1449  samplePair[1] = j + initialSampleId;
1450  embeddedSkeleton->InsertNextCell(VTK_LINE, 2, samplePair);
1451  }
1452  }
1453  embeddedSkeleton->SetPoints(skeletonSamples);
1454 
1455  UpdateModelStateFromModel(embeddedSkeleton);
1456 }*/
1457 
1458 //Atomic
1459 void Model::Append(vtkSmartPointer<vtkPolyData> model)
1460 {
1461  vtkSmartPointer<vtkAppendPolyData> appendPolyData = vtkSmartPointer<vtkAppendPolyData>::New();
1462  #if VTK_MAJOR_VERSION <= 5
1463  if(CurrentModel) //Add current model too
1464  appendPolyData->AddInput(CurrentModel);
1465  appendPolyData->AddInput(model);
1466  #else
1467  if(CurrentModel) //Add current model too
1468  appendPolyData->AddInputData(CurrentModel);
1469  appendPolyData->AddInputData(model);
1470  #endif
1471  appendPolyData->Update();
1472  PreviousModel = appendPolyData->GetInput();
1473  CurrentModel = appendPolyData->GetOutput();
1474 }
1475 
1476 void Model::Scale(vtkSmartPointer<vtkPolyData> model, const coordinateType scale, const bool useCentroid)
1477 {
1478  vtkSmartPointer<vtkPoints> points = model->GetPoints();
1479  const size_t numberOfPoints = model->GetNumberOfPoints();
1480 #ifndef VTK_ONLY
1481  coordinate centroid(0.0);
1482 #else
1483  coordinate centroid = new coordinateType[3];
1484 #endif
1485 
1486  if(useCentroid)
1487  centroid = milx::Math<double>::Centroid(points);
1488 
1489  for(size_t j = 0; j < numberOfPoints; j ++)
1490  {
1491 #ifndef VTK_ONLY
1492  coordinate point(points->GetPoint(j));
1493 
1494  if(useCentroid)
1495  point -= centroid;
1496 
1497  point *= scale;
1498 
1499  if(useCentroid)
1500  point += centroid;
1501 
1502  points->SetPoint(j, point.data_block());
1503 #else
1504  coordinateType point[3];
1505  points->GetPoint(j, point);
1506 
1507  if(useCentroid)
1508  {
1509  point[0] -= centroid[0];
1510  point[1] -= centroid[1];
1511  point[2] -= centroid[2];
1512  }
1513 
1514  point[0] *= scale;
1515  point[1] *= scale;
1516  point[2] *= scale;
1517 
1518  if(useCentroid)
1519  {
1520  point[0] += centroid[0];
1521  point[1] += centroid[1];
1522  point[2] += centroid[2];
1523  }
1524 
1525  points->SetPoint(j, point);
1526 #endif
1527  }
1528 }
1529 
1530 void Model::ScalarDifference(vtkSmartPointer<vtkPolyData> model1, vtkSmartPointer<vtkPolyData> model2, vtkSmartPointer<vtkPolyData> result)
1531 {
1532  const size_t numberOfPoints = model1->GetNumberOfPoints();
1533 
1534  for(size_t j = 0; j < numberOfPoints; j ++)
1535  {
1536  double scalar1 = model1->GetPointData()->GetScalars()->GetTuple1(j);
1537  double scalar2 = model2->GetPointData()->GetScalars()->GetTuple1(j);
1538  double resultant = result->GetPointData()->GetScalars()->GetTuple1(j);
1539 
1540  resultant += scalar1 - scalar2;
1541 
1542  result->GetPointData()->GetScalars()->SetTuple1(j, resultant);
1543  }
1544 }
1545 
1546 void Model::ThresholdScalars(vtkSmartPointer<vtkPolyData> model, const coordinateType aboveVal, const coordinateType belowVal, const coordinateType outsideVal)
1547 {
1548  BinaryThresholdScalars(model, aboveVal, belowVal, outsideVal, outsideVal);
1549 }
1550 
1551 void Model::BinaryThresholdScalars(vtkSmartPointer<vtkPolyData> model, const coordinateType aboveVal, const coordinateType belowVal, const coordinateType insideVal, const coordinateType outsideVal)
1552 {
1553  if(!model->GetPointData()->GetScalars())
1554  return;
1555 
1556  vtkSmartPointer<vtkDataArray> scalars = model->GetPointData()->GetScalars();
1557  for(vtkIdType j = 0; j < scalars->GetNumberOfTuples(); j ++)
1558  {
1559  coordinateType scalar = scalars->GetTuple1(j);
1560  coordinateType value = 0.0;
1561 
1562  if(insideVal == outsideVal || vtkMath::IsNan(insideVal))
1563  value = scalar;
1564  else
1565  value = insideVal;
1566 
1567  if(scalar < belowVal || scalar > aboveVal)
1568  scalars->SetTuple1(j, outsideVal);
1569  else
1570  scalars->SetTuple1(j, value);
1571  }
1572 }
1573 
1574 void Model::MaskScalars(vtkSmartPointer<vtkPolyData> model1, vtkSmartPointer<vtkPolyData> model2)
1575 {
1576  if(!model1->GetPointData()->GetScalars() || !model1->GetPointData()->GetScalars())
1577  return;
1578 
1579  vtkSmartPointer<vtkDataArray> scalars1 = model1->GetPointData()->GetScalars();
1580  vtkSmartPointer<vtkDataArray> scalars2 = model2->GetPointData()->GetScalars();
1581  for(vtkIdType j = 0; j < scalars1->GetNumberOfTuples(); j ++)
1582  {
1583  coordinateType scalar1 = scalars1->GetTuple1(j);
1584  coordinateType scalar2 = scalars2->GetTuple1(j);
1585  coordinateType value = 0.0;
1586 
1587  if(scalar2 >= 1)
1588  value = scalar1;
1589 
1590  scalars1->SetTuple1(j, value);
1591  }
1592 }
1593 
1594 vtkSmartPointer<vtkMatrix4x4> Model::ProcrustesAlign(vtkSmartPointer<vtkPolyData> source, vtkSmartPointer<vtkPolyData> target, bool rigid)
1595 {
1596  if(source->GetNumberOfPoints() != target->GetNumberOfPoints())
1597  return NULL;
1598 
1599  double outPoint[3];
1600  vtkSmartPointer<vtkLandmarkTransform> landmarkTransform = vtkSmartPointer<vtkLandmarkTransform>::New();
1601  landmarkTransform->SetSourceLandmarks(source->GetPoints());
1602  landmarkTransform->SetTargetLandmarks(target->GetPoints());
1603  landmarkTransform->SetModeToSimilarity();
1604  if(rigid)
1605  landmarkTransform->SetModeToRigidBody();
1606  landmarkTransform->Update();
1607  for(vtkIdType v = 0; v < source->GetNumberOfPoints(); v ++)
1608  {
1609  landmarkTransform->InternalTransformPoint(source->GetPoint(v), outPoint);
1610  source->GetPoints()->SetPoint(v, outPoint);
1611  }
1612 
1613  vtkSmartPointer<vtkMatrix4x4> currentTransformMatrix = vtkSmartPointer<vtkMatrix4x4>::New();
1614  currentTransformMatrix->DeepCopy(landmarkTransform->GetMatrix());
1615 
1616  return currentTransformMatrix;
1617 }
1618 
1619 //Batch
1620 void Model::ConcatenateCollection(vtkSmartPointer<vtkPolyDataCollection> collection)
1621 {
1622  const size_t n = collection->GetNumberOfItems();
1623 
1624  collection->InitTraversal();
1625  for(size_t j = 0; j < n; j ++)
1626  Append(collection->GetNextItem());
1627 }
1628 
1629 void Model::ScaleCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const coordinateType scale)
1630 {
1631  const size_t n = collection->GetNumberOfItems();
1632 
1633  collection->InitTraversal();
1634  for(size_t j = 0; j < n; j ++)
1635  Scale(collection->GetNextItem(), scale);
1636 }
1637 
1638 void Model::SmoothCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const size_t iterations)
1639 {
1640  const size_t n = collection->GetNumberOfItems();
1641  InternalInPlaceOperation = true;
1642 
1643  collection->InitTraversal();
1644  for(size_t j = 0; j < n; j ++)
1645  {
1646  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
1647  SetInput(mesh);
1648  WindowedSincSmoothing(iterations);
1649  mesh->DeepCopy(Result());
1650  }
1651 
1652  InternalInPlaceOperation = false;
1653 }
1654 
1655 void Model::LaplacianCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const size_t iterations)
1656 {
1657  const size_t n = collection->GetNumberOfItems();
1658  InternalInPlaceOperation = true;
1659 
1660  collection->InitTraversal();
1661  for(size_t j = 0; j < n; j ++)
1662  {
1663  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
1664  SetInput(mesh);
1665  LaplacianSmoothing(iterations);
1666  mesh->DeepCopy(Result());
1667  }
1668 
1669  InternalInPlaceOperation = false;
1670 }
1671 
1672 void Model::FlipCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const bool xAxis, const bool yAxis, const bool zAxis)
1673 {
1674  const size_t n = collection->GetNumberOfItems();
1675  InternalInPlaceOperation = true;
1676 
1677  collection->InitTraversal();
1678  for(size_t j = 0; j < n; j ++)
1679  {
1680  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
1681  SetInput(mesh);
1682  Flip(xAxis, yAxis, zAxis);
1683  mesh->DeepCopy(Result());
1684  }
1685 
1686  InternalInPlaceOperation = false;
1687 }
1688 
1689 void Model::DecimateCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const coordinateType factor)
1690 {
1691  const size_t n = collection->GetNumberOfItems();
1692  InternalInPlaceOperation = true;
1693 
1694  collection->InitTraversal();
1695  for(size_t j = 0; j < n; j ++)
1696  {
1697  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
1698  SetInput(mesh);
1699  QuadricDecimate(factor);
1700  mesh->DeepCopy(Result());
1701  }
1702 
1703  InternalInPlaceOperation = false;
1704 }
1705 
1706 void Model::SplitCollection(vtkSmartPointer<vtkPolyDataCollection> collection, vtkSmartPointer<vtkPolyDataCollection> components, std::vector< vtkSmartPointer<vtkPolyDataCollection> > &splitCollections)
1707 {
1708  const size_t n = collection->GetNumberOfItems();
1709  const size_t m = components->GetNumberOfItems();
1710 
1711  collection->InitTraversal();
1712  for(size_t j = 0; j < n; j ++)
1713  {
1714  vtkSmartPointer<vtkPolyDataCollection> splitCollection = vtkSmartPointer<vtkPolyDataCollection>::New();
1715  vtkSmartPointer<vtkPolyData> hybridSurface = collection->GetNextItem();
1716  vtkSmartPointer<vtkFloatArray> hybridScalars = vtkFloatArray::SafeDownCast(hybridSurface->GetPointData()->GetScalars());
1717  size_t accumulatedPoints = 0;
1718 
1719  components->InitTraversal();
1720  for(size_t k = 0; k < m; k ++)
1721  {
1722  vtkSmartPointer<vtkPolyData> splitResult = vtkSmartPointer<vtkPolyData>::New();
1723  vtkSmartPointer<vtkFloatArray> scalars = vtkSmartPointer<vtkFloatArray>::New();
1724  vtkSmartPointer<vtkPolyData> component = components->GetNextItem();
1725  const size_t numberOfPoints = component->GetNumberOfPoints();
1726 
1727  if(hybridScalars)
1728  {
1729  scalars->SetNumberOfComponents(hybridScalars->GetNumberOfComponents());
1730  scalars->SetNumberOfTuples(numberOfPoints);
1731  }
1732 
1733  //Split
1734  splitResult->DeepCopy(component); //Fast way to copy cell info etc.
1735  for(size_t l = 0; l < numberOfPoints; l ++) //We just change the geometric data
1736  {
1737  splitResult->GetPoints()->SetPoint(l, hybridSurface->GetPoint(l + accumulatedPoints));
1738  if(hybridScalars)
1739  scalars->SetTuple(l, hybridScalars->GetTuple(l + accumulatedPoints));
1740  }
1741 
1742  if(hybridScalars)
1743  splitResult->GetPointData()->SetScalars(scalars);
1744 
1745  splitCollection->AddItem(splitResult);
1746  accumulatedPoints += numberOfPoints;
1747  }
1748 
1749  splitCollections.push_back(splitCollection);
1750  }
1751 }
1752 
1753 void Model::ScalarDifferenceCollection(vtkSmartPointer<vtkPolyDataCollection> collection)
1754 {
1755  const size_t n = collection->GetNumberOfItems();
1756 
1757  collection->InitTraversal();
1758  vtkSmartPointer<vtkPolyData> surface1 = collection->GetNextItem();
1759 
1760  SetInput(surface1);
1761  ResetScalars();
1762 
1763  for(size_t j = 1; j < n; j ++)
1764  {
1765  vtkSmartPointer<vtkPolyData> surface2 = collection->GetNextItem();
1766 
1767  ScalarDifference(surface1, surface2, CurrentModel);
1768  }
1769 }
1770 
1771 void Model::ScalarThresholdCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const coordinateType aboveVal, const coordinateType belowVal)
1772 {
1773  const size_t n = collection->GetNumberOfItems();
1774 
1775  collection->InitTraversal();
1776  for(size_t j = 1; j < n; j ++)
1777  {
1778  vtkSmartPointer<vtkPolyData> surface = collection->GetNextItem();
1779 
1780  ThresholdScalars(surface, aboveVal, belowVal, 0.0);
1781  }
1782 }
1783 
1784 void Model::ClipCollection(vtkSmartPointer<vtkPolyDataCollection> collection, const coordinateType aboveVal, const coordinateType belowVal)
1785 {
1786  const size_t n = collection->GetNumberOfItems();
1787 
1788  collection->InitTraversal();
1789  for(size_t j = 0; j < n; j ++)
1790  {
1791  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
1792  SetInput(mesh);
1793  Clip(aboveVal, belowVal);
1794  mesh->DeepCopy(Result());
1795  }
1796 
1797  InternalInPlaceOperation = false;
1798 }
1799 
1800 void Model::ScalarDifferenceCollection(vtkSmartPointer<vtkPolyDataCollection> collection1, vtkSmartPointer<vtkPolyDataCollection> collection2, vtkSmartPointer<vtkPolyDataCollection> &results)
1801 {
1802  const size_t n = collection1->GetNumberOfItems();
1803 
1804  if(collection1->GetNumberOfItems() != collection2->GetNumberOfItems())
1805  {
1806  PrintError("Unequal collections. Stopping");
1807  return;
1808  }
1809 
1810  collection1->InitTraversal();
1811  collection2->InitTraversal();
1812  for(size_t j = 0; j < n; j ++)
1813  {
1814  vtkSmartPointer<vtkPolyData> surface1 = collection1->GetNextItem();
1815  vtkSmartPointer<vtkPolyData> surface2 = collection2->GetNextItem();
1816 
1817  vtkPolyData *result = vtkPolyData::New();
1818  result->DeepCopy(surface1);
1819  vtkSmartPointer<milxArrayType> scalars = vtkSmartPointer<milxArrayType>::New();
1820  scalars->SetNumberOfTuples(result->GetNumberOfPoints());
1821  scalars->SetNumberOfComponents(1);
1822  scalars->FillComponent(0, 0.0);
1823  result->GetPointData()->SetScalars(scalars);
1824 
1825  ScalarDifference(surface1, surface2, result);
1826 
1827  results->AddItem(result);
1828  }
1829 }
1830 
1831 void Model::ScalarStatisticsCollection(vtkSmartPointer<vtkPolyDataCollection> collection)
1832 {
1833  const size_t s = collection->GetNumberOfItems();
1834 
1835  collection->InitTraversal();
1836  vtkSmartPointer<vtkPolyData> firstSurface = collection->GetNextItem();
1837  const size_t n = firstSurface->GetNumberOfPoints();
1838 
1839  milxArrayType *minScalars = milxArrayType::New();
1840  minScalars->SetName("Minimum per Vertex");
1841  minScalars->SetNumberOfTuples(n);
1842  minScalars->SetNumberOfComponents(1);
1843  minScalars->FillComponent(0, minScalars->GetDataTypeMax());
1844  milxArrayType *maxScalars = milxArrayType::New();
1845  maxScalars->SetName("Maximum per Vertex");
1846  maxScalars->SetNumberOfTuples(n);
1847  maxScalars->SetNumberOfComponents(1);
1848  maxScalars->FillComponent(0, maxScalars->GetDataTypeMin());
1849  milxArrayType *meanScalars = milxArrayType::New();
1850  meanScalars->SetName("Mean per Vertex");
1851  meanScalars->SetNumberOfTuples(n);
1852  meanScalars->SetNumberOfComponents(1);
1853  meanScalars->FillComponent(0, 0.0);
1854  milxArrayType *varScalars = milxArrayType::New();
1855  varScalars->SetName("Variance per Vertex");
1856  varScalars->SetNumberOfTuples(n);
1857  varScalars->SetNumberOfComponents(1);
1858  varScalars->FillComponent(0, 0.0);
1859 
1860  size_t count = 0;
1861  collection->InitTraversal();
1862  for(size_t j = 0; j < s; j ++)
1863  {
1864  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
1865 
1866  if(!mesh->GetPointData()->GetScalars())
1867  continue; //ignore meshes with no scalars
1868 
1869  //safe casting requires double array
1870  vtkSmartPointer<vtkDataArray> scalars = mesh->GetPointData()->GetScalars();
1871 
1872  for(size_t k = 0; k < n; k ++)
1873  {
1874  if(scalars->GetTuple1(k) < minScalars->GetTuple1(k)) //min
1875  minScalars->SetTuple1(k, scalars->GetTuple1(k));
1876  if(scalars->GetTuple1(k) > maxScalars->GetTuple1(k)) //max
1877  maxScalars->SetTuple1(k, scalars->GetTuple1(k));
1878 
1879  meanScalars->SetTuple1( k, meanScalars->GetTuple1(k) + scalars->GetTuple1(k) ); //mean
1880  }
1881 
1882  count ++;
1883  }
1884  PrintDebug("Found "+NumberToString(count)+" Models with Scalars");
1885 
1886  for(size_t k = 0; k < n; k ++)
1887  meanScalars->SetTuple1( k, meanScalars->GetTuple1(k)/count ); //mean
1888 
1889  collection->InitTraversal();
1890  for(size_t j = 0; j < s; j ++)
1891  {
1892  vtkSmartPointer<vtkPolyData> mesh = collection->GetNextItem();
1893 
1894  if(!mesh->GetPointData()->GetScalars())
1895  continue; //ignore meshes with no scalars
1896 
1897  //safe casting requires double array
1898  vtkSmartPointer<vtkDataArray> scalars = mesh->GetPointData()->GetScalars();
1899 
1900  for(size_t k = 0; k < n; k ++)
1901  {
1902  const coordinateType diffValue = scalars->GetTuple1(k) - meanScalars->GetTuple1(k);
1903  varScalars->SetTuple1( k, varScalars->GetTuple1(k) + (diffValue*diffValue)/count ); //variance
1904  }
1905  }
1906 
1907  //Create resulting mesh
1908  SetInput(firstSurface);
1909  RemoveScalars();
1910  CurrentModel->GetPointData()->AddArray(meanScalars);
1911  CurrentModel->GetPointData()->AddArray(minScalars);
1912  CurrentModel->GetPointData()->AddArray(maxScalars);
1913  CurrentModel->GetPointData()->AddArray(varScalars);
1914  CurrentModel->GetPointData()->SetActiveScalars("Mean per Vertex");
1915 }
1916 
1917 void Model::ScalarRemoveCollection(vtkSmartPointer<vtkPolyDataCollection> collection)
1918 {
1919  const size_t n = collection->GetNumberOfItems();
1920 
1921  collection->InitTraversal();
1922  for(size_t j = 0; j < n; j ++)
1923  {
1924  vtkSmartPointer<vtkPolyData> surface = collection->GetNextItem();
1925 
1926  ClearScalars(surface);
1927  }
1928 }
1929 
1930 void Model::ScalarCopyCollection(vtkSmartPointer<vtkPolyDataCollection> collection)
1931 {
1932  const size_t n = collection->GetNumberOfItems();
1933 
1934  collection->InitTraversal();
1935  vtkSmartPointer<vtkPolyData> templateSurface = collection->GetNextItem();
1936  for(size_t j = 1; j < n; j ++)
1937  {
1938  vtkSmartPointer<vtkPolyData> surface = collection->GetNextItem();
1939 
1940  ClearScalars(surface);
1941 
1942  surface->GetPointData()->SetScalars(templateSurface->GetPointData()->GetScalars());
1943  }
1944 }
1945 
1946 double Model::MeanSquaredErrorCollection(vtkSmartPointer<vtkPolyDataCollection> collection)
1947 {
1948  const size_t n = collection->GetNumberOfItems();
1949  size_t count = 0;
1950  double error = 0.0;
1951 
1952  collection->InitTraversal();
1953  while(count < n)
1954  {
1955  vtkSmartPointer<vtkPolyData> surface1 = collection->GetNextItem();
1956  count ++;
1957 
1958  if(count >= n)
1959  break;
1960 
1961  vtkSmartPointer<vtkPolyData> surface2 = collection->GetNextItem();
1962  count ++;
1963 
1964  error += milx::Math<coordinateType>::MeanSquaredError(surface1->GetPoints(), surface2->GetPoints());
1965  }
1966 
1967  return error;
1968 }
1969 
1970 vtkSmartPointer<vtkPolyDataCollection> Model::ProcrustesAlignCollection(vtkSmartPointer<vtkPolyDataCollection> collection, bool rigid)
1971 {
1972  const int n = collection->GetNumberOfItems();
1973 
1974  collection->InitTraversal();
1975 
1976  //Alignment filter
1977  vtkSmartPointer<vtkProcrustesAlignmentFilter> procrustes = vtkSmartPointer<vtkProcrustesAlignmentFilter>::New();
1978  #if VTK_MAJOR_VERSION <=5
1979  procrustes->SetNumberOfInputs(n);
1980  #endif
1981  if(rigid)
1982  {
1983  procrustes->GetLandmarkTransform()->SetModeToRigidBody();
1984  procrustes->StartFromCentroidOn();
1985  }
1986  else
1987  procrustes->GetLandmarkTransform()->SetModeToSimilarity();
1988 
1989  //Current model used for mean
1990 
1991  //mean of scalars
1992  vtkSmartPointer<milxArrayType> meanScalars = vtkSmartPointer<milxArrayType>::New();
1993  meanScalars->SetNumberOfComponents(1);
1994 
1995 #if VTK_MAJOR_VERSION <=5
1996  for(int j = 0; j < n; j ++)
1997  procrustes->SetInput(j, collection->GetNextItem());
1998 #else
1999  vtkSmartPointer<vtkMultiBlockDataGroupFilter> group = vtkSmartPointer<vtkMultiBlockDataGroupFilter>::New();
2000  for(int j = 0; j < n; j ++)
2001  group->AddInputData(collection->GetNextItem());
2002  procrustes->SetInputConnection(group->GetOutputPort());
2003 #endif
2004 
2005  int numberOfPoints = 0;
2006  if(n > 0)
2007  {
2008  #if VTK_MAJOR_VERSION <=5
2009  numberOfPoints = procrustes->GetInput(0)->GetNumberOfPoints();
2010  #else
2011  numberOfPoints = vtkPointSet::SafeDownCast(procrustes->GetOutput()->GetBlock(0))->GetNumberOfPoints();
2012  #endif
2013  meanScalars->SetNumberOfTuples(numberOfPoints);
2014  meanScalars->FillComponent(0, 0.0);
2015  }
2016  procrustes->Update();
2017 
2018  vtkSmartPointer<vtkPolyDataCollection> alignedCollection = vtkSmartPointer<vtkPolyDataCollection>::New();
2019  collection->InitTraversal();
2020  for(int j = 0; j < n; j ++)
2021  {
2022  vtkPolyData *aligned = vtkPolyData::New();
2023  aligned->DeepCopy(collection->GetNextItem());
2024  #if VTK_MAJOR_VERSION <=5
2025  aligned->SetPoints(procrustes->GetOutput(j)->GetPoints());
2026  #else
2027  aligned->SetPoints( vtkPointSet::SafeDownCast(procrustes->GetOutput()->GetBlock(j))->GetPoints() );
2028  #endif
2029 
2030  if(aligned->GetPointData()->GetScalars())
2031  {
2032  for(int k = 0; k < numberOfPoints; k ++)
2033  {
2034  const double scalar = aligned->GetPointData()->GetScalars()->GetTuple1(k);
2035  double resultant = meanScalars->GetTuple1(k);
2036 
2037  resultant += scalar;
2038 
2039  meanScalars->SetTuple1(k, resultant);
2040  }
2041  }
2042 
2043  if(j == 0)
2044  SetInput(aligned);
2045 
2046  alignedCollection->AddItem(aligned);
2047  }
2048 
2049  //Finalise mean mesh
2050  for(int k = 0; k < numberOfPoints; k ++)
2051  {
2052  double resultant = meanScalars->GetTuple1(k);
2053 
2054  resultant /= n; //norm
2055 
2056  meanScalars->SetTuple1(k, resultant);
2057  }
2058  CurrentModel->SetPoints(procrustes->GetMeanPoints());
2059  CurrentModel->GetPointData()->SetScalars(meanScalars);
2060 
2061  return alignedCollection;
2062 }
2063 
2064 vtkSmartPointer<vtkPolyDataCollection> Model::IterativeClosestPointsAlignCollection(vtkSmartPointer<vtkPolyDataCollection> collection, bool rigid,
2065  vtkSmartPointer<vtkTransformCollection> tCollection)
2066 {
2067  const int n = collection->GetNumberOfItems();
2068  vtkSmartPointer<vtkPolyDataCollection> alignedCollection = vtkSmartPointer<vtkPolyDataCollection>::New();
2069 
2070  //Use the last item as the reference "fixed" surface
2071  vtkPolyData *last = static_cast<vtkPolyData *>(collection->GetItemAsObject(n-1));
2072 
2073  collection->InitTraversal();
2074  for(int j = 0; j < n-1; j ++)
2075  {
2076  vtkPolyData *aligned = collection->GetNextItem();
2077 
2078  SetInput(aligned);
2079  MatchInformation(last, !rigid);
2080  IterativeClosestPointsRegistration(last, !rigid);
2081 
2082  vtkSmartPointer<vtkPolyData> result = vtkSmartPointer<vtkPolyData>::New();
2083  result->DeepCopy(Result());
2084  alignedCollection->AddItem(result);
2085 
2086  if (tCollection.GetPointer() != 0) {
2087  vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
2088  transform->DeepCopy(this->CurrentTransform);
2089  tCollection->AddItem(transform);
2090  //tCollection->AddItem(vtkSmartPointer<vtkTransform>::NewInstance(this->CurrentTransform));
2091  }
2092  }
2093 
2094  return alignedCollection;
2095 }
2096 
2097 } //end milx namespace
void PrintDebug(const std::string msg)
Displays a generic msg to standard error with carriage return if in Debug mode.
Definition: milxGlobal.h:192
vtkSmartPointer< vtkPolyData > CurrentModel
Holds the current model in the pipeline.
Definition: milxModel.h:777
static Type Centroid(const vnl_vector< Type > &data)
Compute the centroid (or the mean) of a data vector.
Definition: milxMath.h:177
static Type MeanSquaredError(vtkPoints *sourcePoints, vtkPoints *targetPoints)
Compute the MSE of the given points sets.
Definition: milxMath.h:541
void ScalarStatisticsCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Computes the statistics (min, max, variance etc.) of the scalars over the collection assuming the mes...
Definition: milxModel.cxx:1831
void DelaunayTriangulation()
Compute the Delaunay 3D triangluation of the points in the mesh.
Definition: milxModel.cxx:911
void GenerateVertexScalars()
Generate vertex scalars for display from point data. This colours the mesh by point ids...
Definition: milxModel.cxx:953
static void ThresholdScalars(vtkSmartPointer< vtkPolyData > model, const coordinateType aboveVal, const coordinateType belowVal, const coordinateType outsideVal)
Thresholds scalar values of mesh in place.
Definition: milxModel.cxx:1546
void GenerateCappedBoundaries()
Generate capped boundaries for open meshes. This closes off open ends of a mesh.
Definition: milxModel.cxx:1273
void ConcatenateCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Concatenates all the models in the collection together into one model.
Definition: milxModel.cxx:1620
void GenerateHedgehog(const double newScale=0.0)
Generate a line field for vectors present (as an array) in the mesh at given scaling.
Definition: milxModel.cxx:1137
void RemoveScalars()
Removes all the scalars from the current model. Same as ClearScalars()
Definition: milxModel.cxx:265
void GenerateVertices()
Generate (only) vertices for display from point data. Good for when only points in mesh...
Definition: milxModel.cxx:935
void Flip(const bool xAxis, const bool yAxis, const bool zAxis)
Flip the mesh along the selected axes.
Definition: milxModel.cxx:643
void GenerateTensorField(const double newScale=0.0)
Generate tensor field for tensors present (as an array) in the mesh at given scaling.
Definition: milxModel.cxx:1108
void GenerateRegions()
Generate connected regions for the mesh labelled by scalar values.
Definition: milxModel.cxx:1307
bool InternalInPlaceOperation
Used by the collection members to assign via pointers rather than deep copys.
Definition: milxModel.h:781
void Mask(vtkSmartPointer< vtkPolyData > maskMesh)
Mask the scalars on the mesh based on values of maskMesh being >= 1.
Definition: milxModel.cxx:730
void ScaleCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const coordinateType scale)
Scales the coordinates of each point in all the models in the collection.
Definition: milxModel.cxx:1629
static void ScalarDifference(vtkSmartPointer< vtkPolyData > model1, vtkSmartPointer< vtkPolyData > model2, vtkSmartPointer< vtkPolyData > result)
Calculates differences within scalars of two meshes assuming the meshes have the same number of point...
Definition: milxModel.cxx:1530
vtkSmartPointer< vtkDataArray > GetScalars()
Returns the active scalars of the model.
Definition: milxModel.h:262
void SetPolys(vtkSmartPointer< vtkCellArray > modelPolys)
Assign polygons to the model via the array given.
Definition: milxModel.cxx:202
void PrintError(const std::string msg)
Displays a generic msg to standard error with carriage return.
Definition: milxGlobal.h:202
void SetGraph(vtkSmartPointer< vtkMutableUndirectedGraph > graph)
Converts a graph to polydata/mesh ready for display.
Definition: milxModel.cxx:176
void GenerateSampledPoints(const double distance)
Generate sampled points (only points) for the mesh at given spacing on triangles. ...
Definition: milxModel.cxx:1050
void DecimateCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const coordinateType factor)
Decimates all points in all the models in the collection using the Quadric algorithm algorithm...
Definition: milxModel.cxx:1689
void DelaunayGraph3D()
Compute the Delaunay 3D graph of the points in the mesh.
Definition: milxModel.cxx:853
void RemoveArrays()
Removes all the arrays from the current model. Same as ClearArrayss()
Definition: milxModel.cxx:275
void SplitCollection(vtkSmartPointer< vtkPolyDataCollection > collection, vtkSmartPointer< vtkPolyDataCollection > components, std::vector< vtkSmartPointer< vtkPolyDataCollection > > &splitCollections)
Splits each of the models in the collection into a collection of models.
Definition: milxModel.cxx:1706
void Delaunay2DTriangulation()
Compute the Delaunay 2D triangluation of the points in the mesh.
Definition: milxModel.cxx:885
vtkSmartPointer< vtkPolyData > & Result()
Returns the current model, i.e. the result of the latest operation.
Definition: milxModel.h:202
vtkSmartPointer< vtkPolyDataCollection > ProcrustesAlignCollection(vtkSmartPointer< vtkPolyDataCollection > collection, bool rigid=false)
Aligns the collection to the mean mesh (computed internally) of the collection assuming the meshes ha...
Definition: milxModel.cxx:1970
void FillScalars(const coordinateType value)
Sets all the scalars of the current model to value.
Definition: milxModel.cxx:231
static vtkSmartPointer< vtkMatrix4x4 > ProcrustesAlign(vtkSmartPointer< vtkPolyData > source, vtkSmartPointer< vtkPolyData > target, bool rigid=false)
Aligns the source mesh to target mesh assuming the meshes have the same number of points and correspo...
Definition: milxModel.cxx:1594
void SmoothCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const size_t iterations)
Smoothes all points in all the models in the collection using the Windowed Sinc algorithm.
Definition: milxModel.cxx:1638
void SetPoints(vtkSmartPointer< vtkPoints > modelPoints)
Assign points to the model.
Definition: milxModel.cxx:194
static void MaskScalars(vtkSmartPointer< vtkPolyData > model1, vtkSmartPointer< vtkPolyData > model2)
Masks the scalars in model1 with scalars in model2. Only values corresponding to >= 1 in model2 are k...
Definition: milxModel.cxx:1574
void Decimate(const float reduceFactor)
Decimate the mesh (in terms of points) using the Decimate PRO. Generally use QuadricDecimate() instea...
Definition: milxModel.cxx:416
void SetVectors(vtkSmartPointer< vtkDataArray > modelVectors)
Sets the vector field of the mesh (vectors per vertex of the surface)
Definition: milxModel.cxx:210
static void ClearScalars(vtkSmartPointer< vtkPolyData > &mesh)
Removes all the scalars from the current model.
Definition: milxModel.cxx:246
void Append(vtkSmartPointer< vtkPolyData > model)
Appends the model provided to the member into the current model.
Definition: milxModel.cxx:1459
vtkSmartPointer< vtkPolyData > PreviousModel
Holds the previous model in the pipeline.
Definition: milxModel.h:778
void GenerateVerticesAs2DGlyphs(const GlyphType glyphType)
Generate (only) vertices (as 2D glyphs like crosses etc.) for display from point data. Good for when only points in mesh.
Definition: milxModel.cxx:973
void Threshold(const coordinateType belowVal, const coordinateType aboveVal, const coordinateType outsideVal)
Threshold the scalars on the mesh based on a levels provided.
Definition: milxModel.cxx:702
void QuadricDecimate(const float reduceFactor)
Decimate the mesh (in terms of points) using the Quadric algorithm.
Definition: milxModel.cxx:435
void WindowedSincSmoothing(const int iterations, const float passBand=0.1)
Smooth the mesh (in terms of points) using the Taubin (1995) optimal filter.
Definition: milxModel.cxx:493
void Curvature(const bool meanCurvature=true)
Compute the curvature (using Laplace-Beltrami operator) of the mesh.
Definition: milxModel.cxx:514
void SetInput(vtkSmartPointer< vtkPolyData > model)
Assigns the input model to class.
Definition: milxModel.cxx:130
Model()
Standard constructor.
Definition: milxModel.cxx:99
void LaplacianSmoothing(const int iterations)
Smooth the mesh (in terms of points) using the Laplacian algorithm. It is unstable, use WindowedSincSmoothing() instead unless massive non-edge preserving smoothing is required.
Definition: milxModel.cxx:473
void ScalarThresholdCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const coordinateType aboveVal, const coordinateType belowVal)
Computes the Threshold of scalar values of meshes in place over the collection wrt the first mesh ass...
Definition: milxModel.cxx:1771
void SetTransform(vtkSmartPointer< vtkAbstractTransform > newTransform)
Transforms the model by given transform.
Definition: milxModel.cxx:143
void ResetScalars()
Resets the scalars to zero of the current model.
Definition: milxModel.cxx:226
vtkSmartPointer< vtkTransform > CurrentTransform
transform applied to model
Definition: milxModel.h:779
void LandmarkBasedRegistration(vtkSmartPointer< vtkPolyData > fixedMesh, const bool similarity=false)
Computes the landmark transform registration of the current mesh to the one provided. Requires point correspondence and same number of points.
Definition: milxModel.cxx:387
static void ClearArrays(vtkSmartPointer< vtkPolyData > &mesh)
Removes all the arrays from the current model.
Definition: milxModel.h:591
void Clean()
Removes duplicate points etc. from model.
Definition: milxModel.cxx:286
std::string NumberToString(double num, unsigned zeroPad=0)
Number to string converter.
Definition: milxGlobal.h:112
void Gradient()
Compute the gradient (using Laplace-Beltrami operator) of the scalars on the mesh.
Definition: milxModel.cxx:537
vtkSmartPointer< vtkImageData > Voxelise(const unsigned char insideValue, double *spacing, double *bounds=NULL, const size_t padVoxels=1)
Definition: milxModel.cxx:766
static Type CentroidSize(const vnl_matrix< Type > &data, const vnl_vector< Type > &centroid, bool norm=false)
Compute the centroid size or scale for a series of points.
Definition: milxMath.h:206
double MeanSquaredErrorCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Computes the MSE of all models in collection accummulatively.
Definition: milxModel.cxx:1946
void GenerateVectorField(const double newScale=0.0, const bool useNormals=false)
Generate vector field for vectors present (as an array) in the mesh at given scaling.
Definition: milxModel.cxx:1071
void DistanceMap(vtkSmartPointer< vtkPoints > loopPoints)
Compute the distance map of the mesh points given a loop (as points) assumed to be on the mesh surfac...
Definition: milxModel.cxx:562
void ScalarCopyCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Copies the scalars over the collection (from the first mesh) assuming the meshes have the same number...
Definition: milxModel.cxx:1930
vtkIdType GetNumberOfPoints()
Returns the total number of points of the model currently held.
Definition: milxModel.h:238
void LaplacianCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const size_t iterations)
Smoothes all points in all the models in the collection using the Laplacian algorithm.
Definition: milxModel.cxx:1655
void AddInput(vtkSmartPointer< vtkPolyData > model)
Assigns and coninually appends meshes provided to the class.
Definition: milxModel.cxx:111
void GenerateNormals(const int pointNormals=0)
Generate normal vectors for each point on the mesh. If pointNormals is (0,1,2), then normals are for ...
Definition: milxModel.cxx:1158
void GeneratePointModel(const double newScale)
Generate spheres of scaling for each point of the mesh.
Definition: milxModel.cxx:1027
void Clip(const coordinateType belowValue, const coordinateType aboveValue)
Clip the mesh based on a scalar threshold of the mesh scalars.
Definition: milxModel.cxx:675
void IterativeClosestPointsRegistration(vtkSmartPointer< vtkPolyData > fixedMesh, const bool similarity=false, const int maxPoints=1024)
Computes the ICP registration of the current mesh to the one provided.
Definition: milxModel.cxx:359
void GenerateKMeansClustering(int numberOfClusters)
Generate k-means clustering for the point positions in the mesh.
Definition: milxModel.cxx:1197
void GenerateTubes()
Generate tubes along edges of the mesh.
Definition: milxModel.cxx:1007
void ScalarRemoveCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Removes the scalars over the collection assuming the meshes have the same number of points...
Definition: milxModel.cxx:1917
void GenerateQuantisedPoints(float quantiseFactor)
Generate points of the mesh to have integral cordinates.
Definition: milxModel.cxx:1254
void SetScalars(vtkSmartPointer< vtkDataArray > modelScalars)
Sets the scalar field of the mesh (values per vertex of the surface)
Definition: milxModel.cxx:218
void Triangulate()
Ensures the polygons in the model are triangulated. Useful when some filters required triangulation b...
Definition: milxModel.cxx:305
static void Scale(vtkSmartPointer< vtkPolyData > model, const coordinateType scale, const bool useCentroid=true)
Scales the coordinates of each point in the model provided by scale.
Definition: milxModel.cxx:1476
void GaussianWeightScalars(float stddev, float clampValue)
Evaluate the Gaussian function with the given standard deviation for all values of the scalars on the...
Definition: milxModel.cxx:584
vtkSmartPointer< vtkPoints > GetPoints()
Returns the points of the model.
Definition: milxModel.h:256
void ClusterDecimate()
Decimate the mesh (in terms of points) using the Quadric Clustering algorithm.
Definition: milxModel.cxx:454
void IsoSurface(vtkSmartPointer< vtkImageData > img, double minValue)
Definition: milxModel.cxx:744
void GenerateElevation()
Generate scalar field for the mesh proportional to the elevation in the z-direction.
Definition: milxModel.cxx:1353
void FlipCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const bool xAxis, const bool yAxis, const bool zAxis)
Flips all points in all the models in the collection using the axis provided.
Definition: milxModel.cxx:1672
void MatchInformation(vtkSmartPointer< vtkPolyData > matchMesh, const bool rescale)
Matches the centroid and centroid scale of the model to the one given.
Definition: milxModel.cxx:324
void Rotate(const bool xAxis, const bool yAxis, const bool zAxis, const float angle, const coordinate centre)
Rotate the mesh along the selected axes from the centre by angle.
Definition: milxModel.cxx:608
vtkSmartPointer< vtkPolyData > InputModel
Holds the initial model in the pipeline.
Definition: milxModel.h:776
void ClipCollection(vtkSmartPointer< vtkPolyDataCollection > collection, const coordinateType aboveVal, const coordinateType belowVal)
Computes the Clipping of models via the Threshold of scalar values in place over the collection...
Definition: milxModel.cxx:1784
void ScalarDifferenceCollection(vtkSmartPointer< vtkPolyDataCollection > collection)
Computes the difference in scalars cummulatively over the collection wrt the first mesh assuming the ...
Definition: milxModel.cxx:1753
static void BinaryThresholdScalars(vtkSmartPointer< vtkPolyData > model, const coordinateType aboveVal, const coordinateType belowVal, const coordinateType insideVal=1.0, const coordinateType outsideVal=0.0)
Thresholds scalar values of mesh in place. Scalars outside the given range is set to outsideVal and s...
Definition: milxModel.cxx:1551
vtkSmartPointer< vtkPolyDataCollection > IterativeClosestPointsAlignCollection(vtkSmartPointer< vtkPolyDataCollection > collection, bool rigid=false, vtkSmartPointer< vtkTransformCollection > tCollection=0)
Aligns the collection to the mean mesh (computed internally) of the collection without needing corres...
Definition: milxModel.cxx:2064