SMILX  1.01
milxQtPlot.cpp
1 /*=========================================================================
2  The Software is copyright (c) Commonwealth Scientific and Industrial Research Organisation (CSIRO)
3  ABN 41 687 119 230.
4  All rights reserved.
5 
6  Licensed under the CSIRO BSD 3-Clause License
7  You may not use this file except in compliance with the License.
8  You may obtain a copy of the License in the file LICENSE.md or at
9 
10  https://stash.csiro.au/projects/SMILI/repos/smili/browse/license.txt
11 
12  Unless required by applicable law or agreed to in writing, software
13  distributed under the License is distributed on an "AS IS" BASIS,
14  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  See the License for the specific language governing permissions and
16  limitations under the License.
17 =========================================================================*/
18 #include "milxQtPlot.h"
19 
20 #include <vtkContextView.h>
21 #include <vtkPlotPoints.h>
22 #include <vtkContextScene.h>
23 #include <vtkImageDataGeometryFilter.h>
24 #include <vtkXMLImageDataWriter.h>
25 #include <vtkImageData.h>
26 #include <vtkWarpScalar.h>
27 #include <vtkPolyDataNormals.h>
28 #include <vtkAxis.h>
29 #include <vtkTextProperty.h>
30 //Volume Rendering
31 #include <vtkColorTransferFunction.h>
32 #include <vtkPiecewiseFunction.h>
33 #include <vtkVolumeProperty.h>
34 
35 milxQtPlot::milxQtPlot(QWidget *theParent, bool contextSystem) : milxQtModel(theParent, contextSystem)
36 {
37  sourceLoaded = false;
38  sourceEightbit = false;
39  plotType2D = false;
40  plotType3D = false;
41  plotTypeSurface = false;
42  plotTypeVolume = false;
43  plotTypeGPU = false;
44  plotted = false;
45  xIndex = 0;
46  yIndex = 1;
47  zIndex = 2;
48  tickNumber = 100;
49  slideInterval = 1;
50 
51  table = vtkSmartPointer<vtkTable>::New();
52 
54  milxQtWindow::prefix = "Plot: ";
55 
58 
59  milxQtRenderWindow::humanAct->setChecked(false);
60  milxQtRenderWindow::humanAct->setEnabled(false);
61  humanGlyph->Off();
62 
63  createActions();
65 }
66 
68 {
69  //dtor
70 }
71 
72 void milxQtPlot::createMenu(QMenu *menu)
73 {
74  cout << "Creating Plot Menu 1" << endl;
75  if(!menu)
76  return;
77 
78  menu->clear();
80  menu->addMenu(milxQtModel::basicContextMenu());
81 
82  cout << "Creating Plot Menu 2" << endl;
83  if(plotTypeVolume)
84  {
85  foreach(QAction *currAct, actionsToAdd)
86  {
87  menu->addAction(currAct);
88  }
89  foreach(QMenu *currMenu, menusToAdd)
90  {
91  menu->addMenu(currMenu);
92  }
93  }
94  menu->addSeparator()->setText(tr("Plotting"));
95  menu->addAction(xAxisName);
96  if(plotType2D)
97  {
98  menu->addAction(titleName);
99  menu->addAction(pointsAct);
100  menu->addAction(logScaleAct);
101  menu->addAction(legendAct);
102  }
103  if(!plotType2D)
104  {
105  menu->addAction(milxQtModel::outlineAct);
106  menu->addAction(milxQtModel::cubeAxesAct);
107  menu->addAction(milxQtModel::scaleAct);
108  menu->addSeparator();
109  menu->addMenu(milxQtRenderWindow::viewMenu);
118  menu->addMenu(milxQtRenderWindow::colourMapMenu);
119  menu->addMenu(milxQtRenderWindow::contourMenu);
121  }
122  menu->addAction(milxQtRenderWindow::refreshAct);
123  if(!plotType2D)
124  menu->addAction(milxQtRenderWindow::resetAct);
125 }
126 
128 {
129  if(!sourceLoaded)
130  return;
131 
132  if(plotTypeVolume)
133  {
134  printInfo("Volume Plot mode set. Trying Volume plot.");
136  return;
137  }
138  if( plotTypeSurface && (table->GetNumberOfColumns() > 0 && !imageData) )
139  {
140  printInfo("Surface Plot mode set. Trying Table Surface plot.");
142  return;
143  }
144  if(plotType2D && table->GetNumberOfColumns() > 0)
145  {
146  printInfo("Scatter 2D Plot mode set. Trying Scatter xy plot.");
148  return;
149  }
150  if(plotType3D && table->GetNumberOfColumns() > 2)
151  {
152  printInfo("Scatter 3D Plot mode set. Trying Scatter xyz plot.");
154  return;
155  }
156  else if(plotType3D && table->GetNumberOfColumns() < 3)
157  {
158  printError("Insufficient number of columns for 3D scatter plot. Try adding more columns.");
159  return;
160  }
161 
163  if(imageData)
164  {
165  printInfo("Image data found. Trying Image Surface plot.");
167  return;
168  }
169 
170  if(table->GetNumberOfColumns() == 1) //bar chart
171  {
172  cerr << "One column is not supported yet." << endl;
173  }
174  else if(table->GetNumberOfColumns() == 2) //2D scatter
175  {
176  printInfo("Two columns found. Trying 2D scatter plot.");
177  plotType2D = true;
179  }
180  else if(table->GetNumberOfColumns() > 3 && table->GetNumberOfColumns() < 10) //3D scatter
181  {
182  printInfo("Less than 10 columns found. Trying 3D scatter plot.");
183  plotType3D = true;
185  }
186  else //surface plot
187  {
188  printInfo("More than 10 columns found. Trying Surface plot.");
189  plotTypeSurface = true;
191  }
192 }
193 
194 void milxQtPlot::scatterPlot(vtkSmartPointer<vtkTable> table, const int xColumn, const int yColumn)
195 {
196  printDebug("Plotting... ");
197  vtkSmartPointer<vtkContextView> view = vtkSmartPointer<vtkContextView>::New();
198 
199  templateChart = vtkSmartPointer<vtkChartXY>::New();
200 // templateChart->SetRenderEmpty(true);
201  templateChart->SetShowLegend(true);
202 
203  view->GetRenderer()->SetBackground(1.0, 1.0, 1.0);
204  view->GetRenderWindow()->SetSize(400, 300);
205  view->GetScene()->AddItem(templateChart);
206  //view->GetRenderWindow()->SetMultiSamples(0);
207 #if (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION < 8)
208  view->SetLabelRenderModeToQt();
209 #endif
210 
211  printInfo("Creating Scatter Plot ");
212  vtkPlot *templatePoints = templateChart->AddPlot(vtkChart::LINE);
213  printDebug("Source Table is " + QString::number(table->GetNumberOfRows()) + "x" + QString::number(table->GetNumberOfColumns()));
214  #if VTK_MAJOR_VERSION <=5
215  templatePoints->SetInput(table, xColumn, yColumn);
216  #else
217  templatePoints->SetInputData(table, xColumn, yColumn);
218  #endif // VTK_MAJOR_VERSION
219  templatePoints->SetColor(0, 0, 0, 255);
220  templatePoints->SetWidth(1.0);
221  vtkPlotPoints::SafeDownCast(templatePoints)->SetMarkerStyle(vtkPlotPoints::DIAMOND);
222  //vtkPlotPoints::SafeDownCast(templatePoints)->SetMarkerStyle(vtkPlotPoints::CROSS);
223  //vtkPlotPoints::SafeDownCast(templatePoints)->SetMarkerStyle(vtkPlotPoints::PLUS);
224  templatePoints->Update();
225 
226  view->SetInteractor(QVTKWidget::GetInteractor()); //order important, also do not move up
227  QVTKWidget::SetRenderWindow(view->GetRenderWindow());
228  milxQtRenderWindow::SetRenderer(view->GetRenderer());
229  milxQtRenderWindow::backgroundAct->setChecked(true);
231  view->ResetCamera();
232  view->Update();
233  refresh();
234  plotted = true;
235 
236  QString xAxisTitle(table->GetColumnName(xColumn));
237  QString yAxisTitle(table->GetColumnName(yColumn));
238  if(!xAxisTitle.isEmpty() && !yAxisTitle.isEmpty())
239  renameAxes(xAxisTitle, yAxisTitle);
240  renameTitle(this->name);
241  legend(legendAct->isChecked());
242 
243  emit resultAvailable( qobject_cast<milxQtRenderWindow *>(this) ); //only using render class
244 }
245 
246 void milxQtPlot::scatterPlot(vtkSmartPointer<vtkTable> table, const int xColumn, const int yColumn, const int zColumn)
247 {
248  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
249  for(int j = 0; j < table->GetNumberOfRows(); j ++)
250  {
251  vtkVariant x = table->GetValue(j, xColumn);
252  vtkVariant y = table->GetValue(j, yColumn);
253  vtkVariant z = table->GetValue(j, zColumn);
254  points->InsertNextPoint(x.ToDouble(), y.ToDouble(), z.ToDouble());
255  }
256 
257  setName("Plot");
258  SetPoints(points);
259 // double bounds[6];
260 // GetOutput()->GetBounds(bounds);
261 // double scaling = ( (bounds[1]-bounds[0]) + (bounds[3]-bounds[2]) + (bounds[5]-bounds[4]) )/150;
262 // if(points->GetNumberOfPoints() > 20000)
263  generateVertices(0,0,0);
264 // generateLabels();
265 // generateVerticesAs(milxQtModel::Cross);
266 // else
267 // generatePointModel(scaling);
268 // milxQtRenderWindow::backgroundAct->setChecked(true);
269 // background(true);
270  enableCubeAxes();
271  printInfo("To generate larger points for scatter plot. Use Generate->Point Model in context menu.");
272  plotted = true;
273 
274  QString xAxisTitle(table->GetColumnName(xColumn));
275  QString yAxisTitle(table->GetColumnName(yColumn));
276  QString zAxisTitle(table->GetColumnName(zColumn));
277  printInfo("Column Names: " + xAxisTitle + ", " + yAxisTitle + ", " + zAxisTitle);
278  if(!xAxisTitle.isEmpty() && !yAxisTitle.isEmpty() && !zAxisTitle.isEmpty())
279  renameAxes(xAxisTitle, yAxisTitle, zAxisTitle);
280 
281  emit resultAvailable(this);
282 }
283 
284 void milxQtPlot::surfacePlot(vtkSmartPointer<vtkImageData> img, const int zDirection)
285 {
286  if(!imageData)
287  imageData->DeepCopy(img);
288 
289  printDebug("Creating surface geometry");
290  vtkSmartPointer<vtkImageDataGeometryFilter> geometry = vtkSmartPointer<vtkImageDataGeometryFilter>::New();
291  #if VTK_MAJOR_VERSION <=5
292  geometry->SetInput(img);
293  #else
294  geometry->SetInputData(img);
295  #endif // VTK_MAJOR_VERSION
296  geometry->Update();
297 
298  double range[2], bounds[6];
299  img->GetScalarRange(range);
300  img->GetBounds(bounds);
301  const double scaling = 0.25*( 1.0 / ( 2.0*(range[1]-range[0]) / (bounds[1]+bounds[3]) ) );
302  printInfo("Min/Max for z-axis: " + QString::number(range[0]) + "/" + QString::number(range[1]));
303  printInfo("Scaling for z-axis: " + QString::number(scaling));
304 
305  printDebug("Warping based on scalars");
306  vtkSmartPointer<vtkWarpScalar> warpScalar = vtkSmartPointer<vtkWarpScalar>::New();
307  warpScalar->SetInputConnection(geometry->GetOutputPort());
308  if(zDirection == 0) //x
309  warpScalar->SetNormal(1, 0, 0);
310  else if(zDirection == 1) //y
311  warpScalar->SetNormal(0, 1, 0);
312  else //z default
313  warpScalar->SetNormal(0, 0, 1);
314  warpScalar->UseNormalOn();
315  warpScalar->SetScaleFactor(scaling);
316  warpScalar->Update();
317 
319  printDebug("Rescaling z-axis for Display");
320  double axesRange[6];
321  axesRange[0] = bounds[0];
322  axesRange[1] = bounds[1];
323  axesRange[2] = bounds[2];
324  axesRange[3] = bounds[3];
325  axesRange[4] = range[0];
326  axesRange[5] = range[1];
327 
328  vtkSmartPointer<vtkPolyDataNormals> normals = vtkSmartPointer<vtkPolyDataNormals>::New();
329  normals->SetInputConnection(warpScalar->GetOutputPort());
330  normals->Update();
331 
332  printDebug("Creating Surface Model for Display");
333  setName("Surface Plot");
334 // SetInputPointSet(warpScalar->GetOutput()); //doesnt require generate model call
335  SetInput(normals->GetOutput()); //doesnt require generate model call
336  generateModel();
337  enableCubeAxes(axesRange);
338 // enableCubeAxes();
339 
340  plotted = true;
341  legendAct->setDisabled(true);
342  emit resultAvailable(this);
343 }
344 
345 void milxQtPlot::surfacePlot(vtkSmartPointer<vtkTable> table)
346 {
347  int dim[3];
348  dim[0] = table->GetNumberOfRows();
349  dim[1] = table->GetNumberOfColumns();
350  dim[2] = 0;
351 
352  imageData = vtkSmartPointer<vtkImageData>::New();
353  imageData->SetDimensions(dim);
354  imageData->SetExtent(0, table->GetNumberOfRows()-1, 0, table->GetNumberOfColumns()-1, 0, 0);
355  #if VTK_MAJOR_VERSION <=5
356  imageData->SetNumberOfScalarComponents(1);
357  imageData->SetScalarTypeToDouble();
358  imageData->AllocateScalars();
359  #else
360  imageData->AllocateScalars(VTK_DOUBLE,1);
361  #endif
362 
364  for(int j = 0; j < table->GetNumberOfRows(); j ++)
365  for(int k = 0; k < table->GetNumberOfColumns(); k ++)
366  imageData->SetScalarComponentFromDouble(j, k, 0, 0, table->GetValue(j, k).ToDouble());
367 
369 }
370 
371 void milxQtPlot::volumePlot(vtkSmartPointer<vtkImageData> img, const bool eightbit, const bool quiet)
372 {
373  if(!sourceLoaded)
374  return;
375 
376  double range[2], bounds[6];
377  img->GetScalarRange(range);
378  img->GetBounds(bounds);
379 
380  //Create slicers and their dialogs
381  QDialog *slidersDlg = new QDialog(this);
382  QLabel *lowValueLbl = new QLabel(this);
383  lowSldr = new QSlider(this);
384  QLabel *highValueLbl = new QLabel(this);
385  highSldr = new QSlider(this);
386  QVBoxLayout *sliderLayout = new QVBoxLayout(this);
387  slideInterval = (range[1]-range[0])/tickNumber;
388 
389  lowValueLbl->setText("Lower Value");
390  lowSldr->setMinimum(0);
391  lowSldr->setMaximum(tickNumber);
392  lowSldr->setValue(0);
393  highValueLbl->setText("Upper Value");
394  highSldr->setMinimum(0);
395  highSldr->setMaximum(tickNumber);
396  highSldr->setValue(tickNumber);
397 
398  //Connect sliders
399  connect(lowSldr, SIGNAL(valueChanged(int)), this, SLOT(updateVolumePlot(int)));
400  connect(highSldr, SIGNAL(valueChanged(int)), this, SLOT(updateVolumePlot(int)));
401 
402  sliderLayout->addWidget(lowValueLbl);
403  sliderLayout->addWidget(lowSldr);
404  sliderLayout->addWidget(highValueLbl);
405  sliderLayout->addWidget(highSldr);
406  slidersDlg->setLayout(sliderLayout);
407  if(!quiet)
408  slidersDlg->show();
409 
410  //Construct rendering
411  emit working(-1);
412  generateRender();
413  milxQtRenderWindow::generateRender(); // make sure we have an OpenGL context.
414 
415  printDebug("Colour Function Setup");
416  vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
417  if(opacityTransferValues.empty())
418  {
419  compositeOpacity->AddPoint(range[0], 0.0);
420  compositeOpacity->AddPoint(range[1], 1.0);
421  }
422  else
423  {
424  for(size_t j = 0; j < opacityTransferValues.size(); j ++)
425  compositeOpacity->AddPoint(colourTransferValues[j], opacityTransferValues[j]);
426  }
427 
428  vtkSmartPointer<vtkColorTransferFunction> color = vtkSmartPointer<vtkColorTransferFunction>::New();
429  if(colourTransferValues.empty())
430  {
431  /*color->AddRGBPoint(range[0], 0.0,0.0,0.0);
432  color->AddRGBPoint(range[1]/3, 1.0,0.0,0.0);
433  color->AddRGBPoint(2*range[1]/3, 0.0,1.0,0.0);
434  color->AddRGBPoint(range[1], 0.0,0.0,1.0);*/
435  double incr = (range[1]-range[0])/100;
436  for(double j = range[0]; j <= range[1]; j += incr)
437  {
439  double colour[3];
440  lookupTable->GetColor(j, colour);
441  color->AddRGBPoint(j, colour[0], colour[1], colour[2]);
442  }
443  }
444  else
445  {
446  /*vtkSmartPointer<vtkLookupTable> transferLookupTable = vtkSmartPointer<vtkLookupTable>::New();
447 // transferLookupTable->SetTableRange(0.0, colourTransferValues.size());
448  transferLookupTable->SetTableRange(range[0], range[1]);
449  transferLookupTable->Build();*/
450 // float minVolumeValue = numeric_limits<float>::max();
451 // float maxVolumeValue = numeric_limits<float>::min();
452 
453  for(size_t j = 0; j < colourTransferValues.size(); j ++)
454  {
456  double colour[3];
457 // transferLookupTable->GetColor(j, colour); //!< Pull colour for data
458 // transferLookupTable->GetColor(colourTransferValues[j], colour); //!< Pull colour for data
459  lookupTable->GetColor(colourTransferValues[j], colour);
460 
461  color->AddRGBPoint(colourTransferValues[j], colour[0], colour[1], colour[2]);
462  }
463  }
464 
465  printDebug("Volume Property Setup");
466  vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
467  volumeProperty->SetScalarOpacity(compositeOpacity);
468  volumeProperty->SetColor(color);
469 // volumeProperty->SetScalarOpacityUnitDistance(0.001);
470  volumeProperty->ShadeOn();
471  volumeProperty->SetAmbient(0.6);
472  volumeProperty->SetDiffuse(0.4);
473  volumeProperty->SetSpecular(0.2);
474  if(eightbit)
475  volumeProperty->SetInterpolationTypeToNearest();
476  else
477  volumeProperty->SetInterpolationTypeToLinear();
478 
479  printDebug("Volume Setup");
480  volume = vtkSmartPointer<vtkVolume>::New();
481  volume->SetProperty(volumeProperty);
482 
483  printDebug("Smart Volume Rendering Setup");
484  vtkSmartPointer<vtkSmartVolumeMapper> volumeMapper = vtkSmartPointer<vtkSmartVolumeMapper>::New();
485  volumeMapper->SetBlendModeToComposite(); // composite first
486  #if VTK_MAJOR_VERSION <= 5
487  volumeMapper->SetInputConnection(img->GetProducerPort());
488  #else
489  volumeMapper->SetInputData(img);
490  #endif
491  if(eightbit)
492  volumeMapper->SetInterpolationModeToNearestNeighbor();
493  else
494  volumeMapper->SetInterpolationModeToLinear();
495  volumeMapper->SetRequestedRenderModeToDefault(); //choose best automatically
496  #if !defined(VTK_LEGACY_REMOVE) && (VTK_MAJOR_VERSION <= 5 || (VTK_MAJOR_VERSION == 6 && VTK_MINOR_VERSION <= 2))
497  volumeMapper->SetRequestedRenderModeToRayCastAndTexture();
498  #else // VTK_LEGACY_REMOVE
499  if(milxQtRenderWindow::GetRenderWindow()->IsDirect() && milxQtRenderWindow::GetRenderWindow()->SupportsOpenGL()) //if hardware accelleration present
500  {
501  printDebug("Requesting GPU Volume Rendering");
502  volumeMapper->SetRequestedRenderModeToGPU();
503  }
504  #endif
505 // volumeMapper->SetRequestedRenderModeToRayCast();
506  linkProgressEventOf(volumeMapper);
507 
508  volume->SetMapper(volumeMapper);
509  linkProgressEventOf(volume);
510  volume->Update();
511 
512  AddVolume(volume);
513  milxQtRenderWindow::renderer->ResetCamera();
514 // if(colourTransferValues.empty())
515  colourMapToJet();
516  refresh();
517  emit done(-1);
518 
519  enableCubeAxes(bounds, bounds);
520  plotted = true;
521  legendAct->setDisabled(true);
522  emit resultAvailable( qobject_cast<milxQtRenderWindow *>(this) );
523 }
524 
525 void milxQtPlot::renameAxes(QString xLabel, QString yLabel, QString zLabel)
526 {
527  if(!plotted)
528  return;
529 
530  if(xLabel.isEmpty() || yLabel.isEmpty())
531  {
532  bool ok1, ok2;
533  xLabel = QInputDialog::getText(this, tr("Please Provide the name of the x-axis"),
534  tr("x-Axis Name:"), QLineEdit::Normal, "x", &ok1);
535  yLabel = QInputDialog::getText(this, tr("Please Provide the name of the y-axis"),
536  tr("y-Axis Name:"), QLineEdit::Normal, "y", &ok2);
537 
538  if(!ok1 || !ok2)
539  return;
540  }
541 
542  if(zLabel.isEmpty() && (plotType3D || plotTypeSurface))
543  {
544  bool ok3;
545  zLabel = QInputDialog::getText(this, tr("Please Provide the name of the z-axis"),
546  tr("z-Axis Name:"), QLineEdit::Normal, "z", &ok3);
547 
548  if(!ok3)
549  return;
550  }
551 
552  if(plotType2D)
553  {
554  templateChart->GetPlot(0)->GetXAxis()->SetTitle(xLabel.toStdString().c_str());
555  templateChart->GetPlot(0)->GetYAxis()->SetTitle(yLabel.toStdString().c_str());
556  }
557  else if(plotType3D || plotTypeSurface)
558  {
559  cubeAxesActor->SetXTitle(xLabel.toStdString().c_str());
560  cubeAxesActor->SetYTitle(yLabel.toStdString().c_str());
561  cubeAxesActor->SetZTitle(zLabel.toStdString().c_str());
562  }
563 }
564 
565 void milxQtPlot::renameTitle(QString newTitle)
566 {
567  if(!plotted)
568  return;
569 
570  if(newTitle.isEmpty())
571  {
572  bool ok1;
573  newTitle = QInputDialog::getText(this, tr("Please Provide the name of the title"),
574  tr("Title Name:"), QLineEdit::Normal, "", &ok1);
575 
576  if(!ok1)
577  return;
578  }
579 
580  if(plotType2D)
581  templateChart->SetTitle(newTitle.toStdString().c_str());
582 // else
583 // {
584 // cubeAxesActor->SetXTitle(xLabel.toStdString().c_str());
585 // cubeAxesActor->SetYTitle(yLabel.toStdString().c_str());
586 // cubeAxesActor->SetZTitle(zLabel.toStdString().c_str());
587 // }
588 }
589 
590 void milxQtPlot::legend(const bool showIt)
591 {
592  if(!showIt)
593  legendAct->setChecked(false);
594  else
595  legendAct->setDisabled(false);
596 
597  if(!plotted)
598  return;
599 
600  if(plotType2D)
601  {
602  if(legendAct->isChecked())
603  templateChart->SetShowLegend(true);
604  else
605  templateChart->SetShowLegend(false);
606  }
607 }
608 
609 void milxQtPlot::points(const bool showIt)
610 {
611  if(!showIt)
612  pointsAct->setChecked(false);
613  else
614  pointsAct->setDisabled(false);
615 
616  if(!plotted)
617  return;
618 
619  if(plotType2D)
620  {
621  vtkPlot *plot = templateChart->GetPlot(0);
622  if(pointsAct->isChecked())
623  vtkPlotPoints::SafeDownCast(plot)->SetMarkerStyle(vtkPlotPoints::DIAMOND);
624  else
625  vtkPlotPoints::SafeDownCast(plot)->SetMarkerStyle(vtkPlotPoints::NONE);
626  }
627 }
628 
629 void milxQtPlot::logScale(const bool showIt)
630 {
631  if(!showIt)
632  logScaleAct->setChecked(false);
633  else
634  logScaleAct->setDisabled(false);
635 
636  if(!plotted)
637  return;
638 
639  if(plotType2D)
640  {
641  double range[2];
642  vtkPlot *plot = templateChart->GetPlot(0);
643  vtkDataArray *data = vtkDataArray::SafeDownCast(plot->GetInput()->GetColumn(1));
644  data->GetRange(range);
645 
646  vtkAxis *axis = plot->GetYAxis();
647  if(logScaleAct->isChecked())
648  {
649  axis->SetLogScale(true);
650  #if ( (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION >= 8) || (VTK_MAJOR_VERSION > 5) )
651  double scaleMin = log(range[0]);
652  double scaleMax = log(range[1]);
653  axis->SetRange(scaleMin, scaleMax);
654  #endif
655  }
656  else
657  {
658  axis->SetLogScale(false);
659  #if ( (VTK_MAJOR_VERSION == 5 && VTK_MINOR_VERSION >= 8) || (VTK_MAJOR_VERSION > 5) )
660  double scaleMin = range[0];
661  double scaleMax = range[1];
662  axis->SetRange(scaleMin, scaleMax);
663  #endif
664  }
665  //axis->RecalculateTickSpacing();
666  //axis->AutoScale();
667  axis->Update();
668  templateChart->Update();
669  }
670 }
671 
672 void milxQtPlot::enableScale(QString title)
673 {
674  if(!scale)
675  scale = vtkSmartPointer<vtkScalarBarActor>::New();
676  if(!scalarBar)
677  scalarBar = vtkSmartPointer<vtkScalarBarWidget>::New();
678 
680  QMessageBox msgBox;
681  msgBox.setText("An auto adjusted bar is about to be created");
682  msgBox.setInformativeText("Would you like to customise the bar?");
683  msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
684  msgBox.setDefaultButton(QMessageBox::No);
685  int ret = msgBox.exec();
686 
687  const float barWidth = 0.1, barHeight = 0.7;
688 
689  if(ret == QMessageBox::Yes)
690  {
691  bool ok1, ok2, ok3, ok4;
692 
693  double minRange = QInputDialog::getDouble(this, tr("Enter Table Range of new Lookup Table"),
694  tr("Minimum:"), 0, -2147483647, 2147483647, 5, &ok1);
695  double maxRange = QInputDialog::getDouble(this, tr("Enter Table Range of new Lookup Table"),
696  tr("Maximum:"), 1.0, -2147483647, 2147483647, 5, &ok2);
697  int noOfLabels = QInputDialog::getInt(this, tr("How many labels to show"),
698  tr("Labels:"), 3, 0, 99, 1, &ok3);
699  title = QInputDialog::getText(this, tr("Title of Bar"),
700  tr("Title:"), QLineEdit::Normal,
701  title, &ok4);
702 
703  if(!ok1 || !ok2 || !ok3 || !ok4)
704  return;
705 
706  scale->SetLookupTable(lookupTable);
707  scale->SetNumberOfLabels(noOfLabels);
708  if(plotTypeSurface)
709  {
710  modelMapper->SetLookupTable(lookupTable);
711  modelMapper->SetScalarRange( minRange, maxRange );
712  }
713  else if(plotTypeVolume)
714  {
715  slideInterval = (maxRange-minRange)/tickNumber;
716  vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity = volume->GetProperty()->GetScalarOpacity();
717  compositeOpacity->RemoveAllPoints();
718  compositeOpacity->AddPoint(minRange, 0.0);
719  compositeOpacity->AddPoint(maxRange, 0.2);
720 
721 // vtkSmartPointer<vtkColorTransferFunction> color = vtkSmartPointer<vtkColorTransferFunction>::New();
722 // color->DeepCopy(lookupTable.GetPointer());
723 
724 // volume->GetProperty()->SetColor(color);
725  volume->Update();
726  }
727  customScalarBar = true;
728  }
729  else
730  {
731  if(plotTypeSurface)
732  modelMapper->SetScalarRange( model.Result()->GetScalarRange() );
733  else if(plotTypeVolume)
734  {
735  double range[2];
736  imageData->GetScalarRange(range);
737 
738  slideInterval = (range[1]-range[0])/tickNumber;
739  vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity = volume->GetProperty()->GetScalarOpacity();
740  compositeOpacity->RemoveAllPoints();
741  compositeOpacity->AddPoint(range[0], 0.0);
742  compositeOpacity->AddPoint(range[1], 0.2);
743 
744 // vtkSmartPointer<vtkColorTransferFunction> color = vtkSmartPointer<vtkColorTransferFunction>::New();
745 // color->DeepCopy(lookupTable.GetPointer());
746 
747 // volume->GetProperty()->SetColor(color);
748  volume->Update();
749  }
750  scale->SetLookupTable(lookupTable);
751  scale->SetNumberOfLabels(3);
752  customScalarBar = false;
753  }
754  scale->SetTitle(title.toStdString().c_str());
755  scale->GetLabelTextProperty()->SetFontFamilyToArial();
756  scale->GetLabelTextProperty()->SetFontSize(8);
757  scale->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport();
758  scale->GetPositionCoordinate()->SetValue(.2,.05);
759  scale->SetWidth( barWidth );
760  scale->SetHeight( barHeight );
761  scale->SetPosition( 0.99 - barWidth, 0.1 );
762  scale->SetLabelFormat("%-#6.3f");
763  scale->GetTitleTextProperty()->SetFontFamilyToArial();
764  scale->GetTitleTextProperty()->SetFontSize(8);
765  scale->GetLabelTextProperty()->SetJustificationToCentered();
766 
767  if(milxQtRenderWindow::backgroundAct->isChecked())
768  {
769  scale->GetLabelTextProperty()->SetColor(0, 0, 0);
770  scale->GetTitleTextProperty()->SetColor(0, 0, 0);
771  }
772 
773  //Add scale to scale widget
774  scalarBar->SetInteractor(QVTKWidget::GetInteractor());
775  scalarBar->SetScalarBarActor(scale);
776  scalarBar->EnabledOn();
777 
778  scaleBefore = true;
779  scaleAct->setChecked(true);
780 }
781 
783 {
784  if(plotTypeSurface)
786  else if(plotTypeVolume)
787  {
788  if(scaleAct->isChecked())
789  enableScale("Voxels");
790  else
791  disableScale();
792 
793  Render();
794  }
795 }
796 
798 {
799  double range[2];
800  GetDataSet()->GetScalarRange(range); //This will propagate upwards to get the range for images or meshes
801 
802  if(plotTypeSurface)
804  else if(plotTypeVolume)
805  {
806  vtkSmartPointer<vtkColorTransferFunction> color = vtkSmartPointer<vtkColorTransferFunction>::New();
807  if(colourTransferValues.empty())
808  {
809  double incr = (range[1]-range[0])/100;
810  for(double j = range[0]; j <= range[1]; j += incr)
811  {
813  double colour[3];
814  lookupTable->GetColor(j, colour);
815  color->AddRGBPoint(j, colour[0], colour[1], colour[2]);
816  }
817  }
818  else
819  {
820  for(size_t j = 0; j < colourTransferValues.size(); j ++)
821  {
823  double colour[3];
824  lookupTable->GetColor(colourTransferValues[j], colour);
825  color->AddRGBPoint(colourTransferValues[j], colour[0], colour[1], colour[2]);
826  }
827  }
828 
829  volume->GetProperty()->SetColor(color);
830  volume->Update();
831 
832  if(scaleAct->isChecked())
833  enableScale("Voxels");
834  else
835  disableScale();
836 
837  Render();
838  }
839 }
840 
841 void milxQtPlot::updateCoords(vtkObject *obj)
842 {
844  {
846  return;
847  }
848 
850 // vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::SafeDownCast(obj);
851 
852  QString message = "Coordinates Unsupported at the moment.";
853  /*
858  if (dataPicker->Pick(iren->GetEventPosition()[0],
859  iren->GetEventPosition()[1],
860  0, // always zero.
861  renderer))
862  {
863  // Get the volume index within the entire volume now.
864  vtkIdType nVolIdx = dataPicker->GetPointId();
865 
866  if(nVolIdx >= 0) //-1 means no point picked
867  {
868  double *coords = currentMesh->GetPoint(nVolIdx);
869 
870  if(currentMesh->GetPointData()->GetScalars())
871  {
872  double *scalar = currentMesh->GetPointData()->GetScalars()->GetTuple(nVolIdx);
873 
874  if(currentMesh->GetPointData()->GetScalars()->GetNumberOfComponents() == 3)
875  message = "Point " + QString::number(nVolIdx) + ": (" + QString::number(coords[0]) + ", " + QString::number(coords[1]) + ", " + QString::number(coords[2]) + ") = "
876  + "[" + QString::number(scalar[0]) + ", " + QString::number(scalar[1]) + ", " + QString::number(scalar[2]) + "]";
877  else if(currentMesh->GetPointData()->GetScalars()->GetNumberOfComponents() == 2)
878  message = "Point " + QString::number(nVolIdx) + ": (" + QString::number(coords[0]) + ", " + QString::number(coords[1]) + ", " + QString::number(coords[2]) + ") = "
879  + "[" + QString::number(scalar[0]) + ", " + QString::number(scalar[1]) + "]";
880  else
881  message = "Point " + QString::number(nVolIdx) + ": (" + QString::number(coords[0]) + ", " + QString::number(coords[1]) + ", " + QString::number(coords[2]) + ") = "
882  + QString::number(scalar[0]);
883  }
884  else
885  {
886  message = "Point " + QString::number(nVolIdx) + ": (" + QString::number(coords[0]) + ", " + QString::number(coords[1]) + ", " + QString::number(coords[2]) + ")";
887  }
888  }
889  }*/
890 
892  updateBar->showMessage(message);
893 }
894 
896 {
897  const float value1 = lowSldr->minimum() + lowSldr->value()*slideInterval;
898  const float value2 = highSldr->minimum() + highSldr->value()*slideInterval;
899  printDebug("Slider Min Value: " + QString::number(value1));
900  printDebug("Slider Max Value: " + QString::number(value2));
901 
902  vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity = volume->GetProperty()->GetScalarOpacity();
903  compositeOpacity->RemoveAllPoints();
904  compositeOpacity->AddPoint(value1, 0.0);
905  compositeOpacity->AddPoint(value2, 0.2);
906 
907  volume->Update();
908  Render();
909 }
910 
912 {
913  //axes
914  xAxisName = new QAction(this);
915  xAxisName->setText(QApplication::translate("Plot", "Rename &Axes", 0, QApplication::UnicodeUTF8));
916  xAxisName->setShortcut(tr("Alt+x"));
917  titleName = new QAction(this);
918  titleName->setText(QApplication::translate("Plot", "Rename &Title", 0, QApplication::UnicodeUTF8));
919  titleName->setShortcut(tr("Alt+t"));
920  legendAct = new QAction(this);
921  legendAct->setText(QApplication::translate("Plot", "Legend", 0, QApplication::UnicodeUTF8));
922  legendAct->setShortcut(tr("Alt+l"));
923  legendAct->setCheckable(true);
924  legendAct->setChecked(true);
925  pointsAct = new QAction(this);
926  pointsAct->setText(QApplication::translate("Plot", "Show Points", 0, QApplication::UnicodeUTF8));
927  pointsAct->setShortcut(tr("Shift+Alt+l"));
928  pointsAct->setCheckable(true);
929  pointsAct->setChecked(true);
930  logScaleAct = new QAction(this);
931  logScaleAct->setText(QApplication::translate("Plot", "Log Scale", 0, QApplication::UnicodeUTF8));
932  logScaleAct->setShortcut(tr("Alt+s"));
933  logScaleAct->setCheckable(true);
934  logScaleAct->setChecked(false);
935  logScaleAct->setDisabled(true);
936 }
937 
939 {
940  //axes
941  connect(xAxisName, SIGNAL(triggered()), this, SLOT(renameAxes()));
942  connect(titleName, SIGNAL(triggered()), this, SLOT(renameTitle()));
943  connect(pointsAct, SIGNAL(triggered()), this, SLOT(points()));
944  connect(logScaleAct, SIGNAL(triggered()), this, SLOT(logScale()));
945  connect(legendAct, SIGNAL(triggered()), this, SLOT(legend()));
946 
947  connect(milxQtRenderWindow::refreshAct, SIGNAL(triggered()), this, SLOT(refresh()));
948 }
949 
950 void milxQtPlot::contextMenuEvent(QContextMenuEvent *currentEvent)
951 {
952  contextMenu = new QMenu(this);
953  contextMenu->setTitle(QApplication::translate("MainWindow", "Plotting", 0, QApplication::UnicodeUTF8));
954 
956 
957  contextMenu->exec(currentEvent->globalPos());
958 }
QAction * scaleAct
Action for the scale bar of the display.
void printError(QString msg)
Error message wrapper for console.
std::vector< float > opacityTransferValues
values for volume rendering opacity transfer function
Definition: milxQtPlot.h:315
void createConnections()
Create the connections for context menu etc.
Definition: milxQtPlot.cpp:938
QAction * outlineAct
show outline action
Definition: milxQtModel.h:1049
QAction * saveViewFileAct
Save camera view to file.
QMenu * viewMenu
Context Menu.
void setName(const QString filename)
Set the name of the data.
void renameTitle(QString newTitle="")
Rename the title of the plot.
Definition: milxQtPlot.cpp:565
vtkSmartPointer< vtkPolyDataMapper > modelMapper
Model mapper.
Definition: milxQtModel.h:986
vtkSmartPointer< vtkRenderer > renderer
Renderer for the data.
void surfacePlot(vtkSmartPointer< vtkImageData > img, const int zDirection=2)
Display a surface plot from image data given.
Definition: milxQtPlot.cpp:284
void generateVertices(float red=defaultColour, float green=defaultColour, float blue=defaultColour)
Generates the vertices for the dataset. Arguments provided are for the colours of the vertices...
vtkSmartPointer< vtkLookupTable > lookupTable
Lookup table for the shapes/images, base class is used to allow references to different look up table...
void logScale(const bool showIt=true)
Show/hide log scale (of the y-axis) for the line plot.
Definition: milxQtPlot.cpp:629
void enableCubeAxes(double *range=NULL, double *bounds=NULL)
Display cube (plot) axes of data.
QAction * viewZY
Change view to zy-plane (Coronal)
void AddVolume(vtkSmartPointer< vtkVolume > actor)
Add a VTK volume to this window.
QMenu * contextMenu
Context Menu.
Definition: milxQtWindow.h:250
bool plotTypeGPU
Use GPU whenever possible?
Definition: milxQtPlot.h:294
virtual void updateVolumePlot(int value)
Updates the volume rendering display. Used when slider values are changed.
Definition: milxQtPlot.cpp:895
vtkSmartPointer< vtkOrientationMarkerWidget > humanGlyph
Glyph for showing equivalent view on human.
void contextMenuEvent(QContextMenuEvent *event)
The context menu setup member.
Definition: milxQtPlot.cpp:950
QAction * titleName
Action for title name.
Definition: milxQtPlot.h:310
QAction * humanAct
Show human view orientation glyph?
void SetInput(vtkSmartPointer< vtkPolyData > mesh)
Assigns the mesh provided to the class, preparing for display. Call generateModel() and then show() t...
void scaleDisplay()
Toggles the scale bar display.
Definition: milxQtPlot.cpp:782
void setDeletableOnClose(bool delOnClose)
Set if the window deletable on close. Default is true.
Definition: milxQtWindow.h:178
bool plotType2D
2D plot type?
Definition: milxQtPlot.h:290
QList< QMenu * > menusToAdd
Context Menu&#39;s to add.
Definition: milxQtWindow.h:254
QAction * backgroundAct
Action for axes of the display.
virtual void updateLookupTable()
Sets the necessary LUTs to model view.
Definition: milxQtPlot.cpp:797
QString prefix
Prefix of the data.
Definition: milxQtWindow.h:242
virtual ~milxQtPlot()
Default destructor.
Definition: milxQtPlot.cpp:67
vtkSmartPointer< vtkPolyData > & Result()
Returns the current model, i.e. the result of the latest operation.
Definition: milxModel.h:202
void printDebug(QString msg)
Debug message wrapper for console.
void enableScale(QString title="")
Enable scale bar display with the title provided.
Definition: milxQtPlot.cpp:672
This class represents the MILX Qt Model/Mesh Display object using VTK.
Definition: milxQtModel.h:115
std::vector< float > colourTransferValues
values for volume rendering colour transfer function
Definition: milxQtPlot.h:316
virtual void scaleDisplay(const bool forceDisplay=false)
Toggles the scale bar display.
bool plotType3D
3D plot type?
Definition: milxQtPlot.h:291
virtual void updateCoords(vtkObject *obj)
Picks the coordinates and pixel value from the current mouse position in the window.
Definition: milxQtPlot.cpp:841
milxQtPlot(QWidget *theParent=0, bool contextSystem=true)
Default constructor.
Definition: milxQtPlot.cpp:35
void Render()
Force Render or Update of the display.
void renameAxes(QString xLabel="", QString yLabel="", QString zLabel="")
Rename the axes.
Definition: milxQtPlot.cpp:525
bool sourceEightbit
Table/data loaded is eightbit?
Definition: milxQtPlot.h:289
QMenu * basicContextMenu()
Return the basic context menu with the milxQtModel class ordering. This is for the benefit of derived...
vtkSmartPointer< vtkChartXY > templateChart
chart (used only for xy scatter plot)
Definition: milxQtPlot.h:303
QAction * cubeAxesAct
show cube axes action
Definition: milxQtModel.h:1050
QAction * refreshAct
Action for refreshing the display.
void resultAvailable(milxQtRenderWindow *)
Send signal that Resultant render window is available for showing.
void generatePlot()
Generate appropriate plot from the table of data provided by SetInput().
Definition: milxQtPlot.cpp:127
bool scaleBefore
scale displayed?
void enableActionBasedOnView()
Enables the view actions corresponding to current view set.
QAction * legendAct
Action for showing legend.
Definition: milxQtPlot.h:313
QMenu * contourMenu
Contour Menu.
vtkSmartPointer< vtkTable > table
data presented as a table
Definition: milxQtPlot.h:301
void generateModel(float red=defaultColour, float green=defaultColour, float blue=defaultColour)
Generates the model so that its ready for display. It requires that data has been set or assigned alr...
QAction * logScaleAct
Action for showing a log scale.
Definition: milxQtPlot.h:312
void SetRenderer(vtkRenderer *rnder)
Assigns a VTK Renderer object.
void SetPoints(vtkSmartPointer< vtkPoints > modelPoints)
Sets the points for the model to be generated. Must pass a vtkPoints objects, which is easy to use...
virtual void updateCoords(vtkObject *obj)
Picks the coordinates and pixel value from the current mouse position in the window.
virtual void updateLookupTable()
Sets the necessary LUTs to model view.
QAction * resetAct
Action for refreshing the display.
QMenu * colourMapMenu
Colour map menu.
void generateRender()
Generate the render so it is ready for display. Should be called before showing the window...
virtual void disableScale()
Disables the scale bar display.
void linkProgressEventOf(vtkObject *obj)
Link the progress of filters etc to keep the UI responsive.
bool plotted
plot done?
Definition: milxQtPlot.h:295
QAction * saveViewAct
Save camera view.
int xIndex
x axis index of table
Definition: milxQtPlot.h:296
int displaceAxis
warp axis for surface plots
Definition: milxQtPlot.h:299
QAction * viewXY
Change view to xy-plane (Axial)
int yIndex
y axis index of table
Definition: milxQtPlot.h:297
vtkSmartPointer< vtkImageData > imageData
data presented as a image
Definition: milxQtPlot.h:302
void createActions()
Create the actions for context menu etc.
Definition: milxQtPlot.cpp:911
QList< QAction * > actionsToAdd
Context actions to add.
Definition: milxQtWindow.h:251
bool sourceLoaded
Table/data loaded in class?
Definition: milxQtPlot.h:288
QAction * xAxisName
Action for x-axis name.
Definition: milxQtPlot.h:309
QAction * viewZX
Change view to zx-plane (Sagittal)
virtual void createMenu(QMenu *menu)
Create the menu for the data in this object. Used for context menu and file menus.
Definition: milxQtPlot.cpp:72
void points(const bool showIt=true)
Show/hide points for the line plot.
Definition: milxQtPlot.cpp:609
int zIndex
z axis index of table
Definition: milxQtPlot.h:298
void done(int value)
Send signal that computation is done. Value carries the progress,.
vtkSmartPointer< vtkScalarBarActor > scale
Scale for the display.
QAction * pointsAct
Action for showing line points.
Definition: milxQtPlot.h:311
milx::Model model
Actual model and its operations (from SMILI)
Definition: milxQtModel.h:979
bool plotTypeVolume
2D plot type?
Definition: milxQtPlot.h:293
bool plotTypeSurface
2D plot type?
Definition: milxQtPlot.h:292
void printInfo(QString msg)
Info message wrapper for console.
void volumePlot(vtkSmartPointer< vtkImageData > img, const bool eightbit, const bool quiet=false)
Display a volume plot from data in image given.
Definition: milxQtPlot.cpp:371
void scatterPlot(vtkSmartPointer< vtkTable > table, const int xColumn, const int yColumn)
Display a scatter x-y plot from data in table given at column indices x and y.
Definition: milxQtPlot.cpp:194
void working(int value)
Send signal that computation is in progress. Value carries the progress,.
vtkSmartPointer< vtkScalarBarWidget > scalarBar
Scalar Bar Widget for the display.
QMenu * windowPropertiesMenu
Context Menu.
void legend(const bool showIt=true)
Show/hide legend for plot.
Definition: milxQtPlot.cpp:590
vtkSmartPointer< vtkCubeAxesActor > cubeAxesActor
outline box
Definition: milxQtModel.h:992
QStatusBar * updateBar
Pointer to bar, not allocated or deleted. To be passed to only.
void refresh()
Refresh the display of the window.
Definition: milxQtPlot.h:188
void normals(const bool turnOn=false)
Shows the point normals of the model.
QAction * loadViewAct
Load camera view.
virtual vtkDataSet * GetDataSet()
Get the underlying data, return the vtkImageData object if volume plot else polydata, useful for getting scalar range etc.
Definition: milxQtPlot.h:158
virtual void colourMapToJet(double minRange=0.0, double maxRange=0.0)
Change the colour map to Jet.
QAction * loadViewFileAct
Load camera view to file.
QString name
Name of the data.
Definition: milxQtWindow.h:241