00001
00022 #include "DGVVolumePlotVTK.h"
00023
00024 #include "vtkProperty2D.h"
00025 #include "vtkTextProperty.h"
00026 #include "vtkXMLImageDataWriter.h"
00027 #include "vtkStructuredPointsWriter.h"
00028
00029 DGVVolumePlotVTK::DGVVolumePlotVTK(QWidget *parent) : QVTKWidget(parent)
00030 {
00031 loaded = false;
00032 externalData = false;
00033 unsignedCharMode = false;
00034 mapper = false;
00035 generated = false;
00036 axisGenerated = false;
00037 closestTriad = false;
00038 antiAliasing = false;
00039 imageDataSource = false;
00040 }
00041
00042 DGVVolumePlotVTK::~DGVVolumePlotVTK()
00043 {
00044 if(loaded)
00045 {
00046 if(!externalData)
00047 plotData->Delete();
00048 if(generated)
00049 {
00050 opacityTransferFunction->Delete();
00051 colorTransferFunction->Delete();
00052 volumeProperty->Delete();
00053 if(mapper)
00054 {
00055 if(!unsignedCharMode)
00056 volumeMapper_Fixed->Delete();
00057 else
00058 {
00059 volumeMapper->Delete();
00060 compositeFunction->Delete();
00061 }
00062 }
00063 volume->Delete();
00064 renderer->Delete();
00065 renderWin->Delete();
00066 if(axisGenerated)
00067 axes->Delete();
00068 }
00069 }
00070 }
00071
00072 void DGVVolumePlotVTK::setName(QString filename)
00073 {
00074 name = filename;
00075 setWindowTitle(strippedNamePrefix());
00076 }
00077
00078 void DGVVolumePlotVTK::setData(Array<imageType,3> &data)
00079 {
00080 plotArray.resizeAndPreserve(data.shape());
00081 plotArray = data;
00082
00083 plotData = Blitz.arrayToVTKImageData(data);
00084 plotData->Update();
00085
00086 loaded = true;
00087 imageDataSource = false;
00088 cerr << "VPlot Min: " << Blitz.getMin() << ", Data Max: " << Blitz.getMax() << ". Mean: " << Blitz.getMean() << endl;
00089 }
00090
00091 void DGVVolumePlotVTK::setData(Array<complex<imageType>,3> &data)
00092 {
00093 plotArray.resizeAndPreserve(data.shape());
00094 plotArray = abs(data);
00095
00096 plotData = Blitz.arrayToVTKImageData(data);
00097 plotData->Update();
00098
00099 loaded = true;
00100 imageDataSource = false;
00101 cerr << "VPlot Min: " << Blitz.getMin() << ", Data Max: " << Blitz.getMax() << ". Mean: " << Blitz.getMean() << endl;
00102 }
00103
00104 void DGVVolumePlotVTK::setData(vtkImageData *data)
00105 {
00106 int bounds[6];
00107
00108 data->GetExtent(bounds);
00109
00110 if(bounds[1] > 0 && bounds[3] > 0 && bounds[5] > 0)
00111 {
00112 plotData = data;
00113 plotData->SetExtent(bounds);
00114 externalData = true;
00115 plotData->Update();
00116 Blitz.vtkImageDataToArray(plotData,plotArray);
00117 imageDataSource = true;
00118 loaded = true;
00119 }
00120 }
00121
00122 void DGVVolumePlotVTK::SetInputConnection(vtkAlgorithmOutput *connection)
00123 {
00124 inputConnection = connection;
00125 if(!unsignedCharMode)
00126 {
00127 volumeMapper_Fixed = vtkFixedPointVolumeRayCastMapper::New();
00128 volumeMapper_Fixed->SetInputConnection(connection);
00129 }
00130 else
00131 {
00132 compositeFunction = vtkVolumeRayCastCompositeFunction::New();
00133 volumeMapper = vtkVolumeRayCastMapper::New();
00134 volumeMapper->SetVolumeRayCastFunction(compositeFunction);
00135 volumeMapper->SetInputConnection(connection);
00136 }
00137 mapper = true;
00138 }
00139
00140 void DGVVolumePlotVTK::generatePlot()
00141 {
00142 if(loaded)
00143 {
00144 int bounds[6];
00145
00146 if(imageDataSource)
00147 Blitz.vtkImageDataToArray(plotData,plotArray);
00148
00149 plotData->GetExtent(bounds);
00150
00151 opacityTransferFunction = vtkPiecewiseFunction::New();
00152 opacityTransferFunction->AddPoint(Blitz.getMin(), 0.0);
00153 opacityTransferFunction->AddPoint(Blitz.getMax(), 0.2);
00154
00155 colorTransferFunction = vtkColorTransferFunction::New();
00156 colorTransferFunction->AddRGBPoint(Blitz.getMin(), 0.0, 0.0, 0.0);
00157 colorTransferFunction->AddRGBPoint(Blitz.getMax()/4, 1.0, 0.0, 0.0);
00158 colorTransferFunction->AddRGBPoint(Blitz.getMax()/2, 0.0, 0.0, 1.0);
00159 colorTransferFunction->AddRGBPoint(3*Blitz.getMax()/4, 0.0, 1.0, 0.0);
00160 colorTransferFunction->AddRGBPoint(Blitz.getMax(), 0.0, 0.2, 0.0);
00161
00162 volumeProperty = vtkVolumeProperty::New();
00163 volumeProperty->SetColor(colorTransferFunction);
00164 volumeProperty->SetScalarOpacity(opacityTransferFunction);
00165 volumeProperty->ShadeOn();
00166
00167
00168 volume = vtkVolume::New();
00169 if(!unsignedCharMode)
00170 {
00171 if(!mapper)
00172 {
00173 volumeMapper_Fixed = vtkFixedPointVolumeRayCastMapper::New();
00174 volumeMapper_Fixed->SetInput(plotData);
00175 mapper = true;
00176 }
00177 volume->SetMapper(volumeMapper_Fixed);
00178 }
00179 else
00180 {
00181 if(!mapper)
00182 {
00183 compositeFunction = vtkVolumeRayCastCompositeFunction::New();
00184 volumeMapper = vtkVolumeRayCastMapper::New();
00185 volumeMapper->SetVolumeRayCastFunction(compositeFunction);
00186 volumeMapper->SetInput(plotData);
00187 mapper = true;
00188 }
00189 volume->SetMapper(volumeMapper);
00190 }
00191 volume->SetProperty(volumeProperty);
00192
00193 renderer = vtkRenderer::New();
00194 renderer->AddVolume(volume);
00195 renderer->ResetCamera();
00196 renderer->SetBackground(0.1, 0.2, 0.4);
00197 renderer->ResetCameraClippingRange();
00198
00199 renderWin = vtkRenderWindow::New();
00200 renderWin->AddRenderer(renderer);
00201
00202 setupEvents();
00203
00204 QVTKWidget::SetRenderWindow(renderWin);
00205 if(bounds[1] > minWindowSize || bounds[3] > minWindowSize)
00206 {
00207 renderWin->SetSize(bounds[1],bounds[3]);
00208 QVTKWidget::resize(bounds[1],bounds[3]);
00209 }
00210 else
00211 {
00212 renderWin->SetSize(minWindowSize,minWindowSize);
00213 QVTKWidget::resize(minWindowSize,minWindowSize);
00214 }
00215 generated = true;
00216 }
00217 }
00218
00219 void DGVVolumePlotVTK::generateAxes()
00220 {
00221 if(loaded && generated)
00222 {
00223 double ranges[6];
00224 int bounds[6];
00225 axes = vtkCubeAxesActor2D::New();
00226
00228 axes->SetInput(plotData);
00229 axes->SetCamera(renderer->GetActiveCamera());
00230 axes->SetLabelFormat("%6.4g");
00231 if(!closestTriad)
00232 axes->SetFlyModeToOuterEdges();
00233 else
00234 axes->SetFlyModeToClosestTriad();
00235 axes->SetFontFactor(0.8);
00236
00238 plotData->GetExtent(bounds);
00239 axes->UseRangesOn();
00240 ranges[0] = 1.0;
00241 ranges[1] = static_cast<double>(bounds[1]+1);
00242 ranges[2] = 1.0;
00243 ranges[3] = static_cast<double>(bounds[3]+1);
00244 ranges[4] = 1.0;
00245 ranges[5] = static_cast<double>(bounds[5]+1);
00246 axes->SetRanges(ranges);
00247
00248 renderer->AddViewProp(axes);
00249 renderer->ResetCamera();
00250 renderer->SetBackground(0.1, 0.2, 0.4);
00251 renderer->ResetCameraClippingRange();
00252 renderWin->AddRenderer(renderer);
00253 QVTKWidget::SetRenderWindow(renderWin);
00254
00255 axisGenerated = true;
00256 }
00257 }
00258
00259 void DGVVolumePlotVTK::setXLabel(QString text)
00260 {
00261 if(axisGenerated)
00262 {
00263 axes->SetXLabel(text.toStdString().c_str());
00264 }
00265 }
00266
00267 void DGVVolumePlotVTK::setYLabel(QString text)
00268 {
00269 if(axisGenerated)
00270 {
00271 axes->SetYLabel(text.toStdString().c_str());
00272 }
00273 }
00274
00275 void DGVVolumePlotVTK::setZLabel(QString text)
00276 {
00277 if(axisGenerated)
00278 {
00279 axes->SetZLabel(text.toStdString().c_str());
00280 }
00281 }
00282
00283 void DGVVolumePlotVTK::setBackground(double r, double g, double b)
00284 {
00285 if(loaded && generated)
00286 {
00287 renderer->SetBackground(r, g, b);
00288 renderWin->Render();
00289 }
00290 }
00291
00292 void DGVVolumePlotVTK::setAxesAsClosestTriad()
00293 {
00294 if(axisGenerated)
00295 {
00296 axes->SetFlyModeToClosestTriad();
00297 }
00298 }
00299
00300 void DGVVolumePlotVTK::setAxesAsOuterEdges()
00301 {
00302 if(axisGenerated)
00303 {
00304 axes->SetFlyModeToOuterEdges();
00305 }
00306 }
00307
00308 bool DGVVolumePlotVTK::saveVTI(const QString filename)
00309 {
00310 if(loaded && generated)
00311 {
00312 vtkXMLImageDataWriter* writer = vtkXMLImageDataWriter::New();
00313
00314 writer->SetInput(plotData);
00315 writer->SetFileName(filename.toStdString().c_str());
00316 writer->SetDataModeToBinary();
00317 writer->Write();
00318 writer->Delete();
00319
00320 return true;
00321 }
00322 else
00323 return false;
00324 }
00325
00326 bool DGVVolumePlotVTK::saveVTK(const QString filename)
00327 {
00328 if(loaded && generated)
00329 {
00330 vtkStructuredPointsWriter* writer = vtkStructuredPointsWriter::New();
00331
00332 writer->SetInput(plotData);
00333 writer->SetFileName(filename.toStdString().c_str());
00334 writer->Write();
00335 writer->Delete();
00336
00337 return true;
00338 }
00339 else
00340 return false;
00341 }
00342
00343 QString DGVVolumePlotVTK::strippedName()
00344 {
00345 return QFileInfo(name).fileName();
00346 }
00347
00348 QString DGVVolumePlotVTK::strippedNamePrefix()
00349 {
00350 return "VPlot: " + QFileInfo(name).fileName();
00351 }
00352
00353 void DGVVolumePlotVTK::scanVolume()
00354 {
00355 if(loaded && generated)
00356 {
00357 bool ok;
00358 DGVSurfacePlotVTK *splot = new DGVSurfacePlotVTK(parentWidget());
00359
00360 double interval = QInputDialog::getDouble(this, tr("Scan Interval Time"), tr("Interval (ms):"), 250, -100000, 100000, 1, &ok);
00361
00362 if(ok)
00363 {
00364 splot->setName("Surface Animation");
00365 splot->autoScaleSurface(true);
00366 splot->animateFromSlices(&plotArray,interval);
00367 splot->show();
00368
00369 emit surfacePlotAvailable(splot);
00370 }
00371 }
00372 }
00373
00374 void DGVVolumePlotVTK::xLabel()
00375 {
00376 bool ok;
00377 QString text = QInputDialog::getText(this, tr("x-axis Label"),
00378 tr("New Label:"), QLineEdit::Normal,
00379 "x", &ok);
00380 if(ok)
00381 setXLabel(text);
00382 }
00383
00384 void DGVVolumePlotVTK::yLabel()
00385 {
00386 bool ok;
00387 QString text = QInputDialog::getText(this, tr("y-axis Label"),
00388 tr("New Label:"), QLineEdit::Normal,
00389 "y", &ok);
00390 if(ok)
00391 setYLabel(text);
00392 }
00393
00394 void DGVVolumePlotVTK::zLabel()
00395 {
00396 bool ok;
00397 QString text = QInputDialog::getText(this, tr("z-axis Label"),
00398 tr("New Label:"), QLineEdit::Normal,
00399 "z", &ok);
00400 if(ok)
00401 setZLabel(text);
00402 }
00403
00404 void DGVVolumePlotVTK::opacity()
00405 {
00406 if(generated)
00407 {
00408 bool ok1, ok2;
00409
00410 if(imageDataSource)
00411 Blitz.vtkImageDataToArray(plotData,plotArray);
00412
00413 double min = QInputDialog::getDouble(this, tr("Opacity"), tr("Opacity Min: "), Blitz.getMin(), Blitz.getMin(), Blitz.getMax(), 2, &ok1);
00414 double max = QInputDialog::getDouble(this, tr("Opacity"), tr("Opacity Max: "), Blitz.getMax(), Blitz.getMin(), Blitz.getMax(), 2, &ok2);
00415
00416 if(ok1 && ok2)
00417 {
00418 opacityTransferFunction->Initialize();
00419 opacityTransferFunction->AddPoint(min, 0.0);
00420 opacityTransferFunction->AddPoint(max, 0.2);
00421 volume->Update();
00422 renderWin->Render();
00423 }
00424 }
00425 }
00426
00427 void DGVVolumePlotVTK::background()
00428 {
00429 double colours[3];
00430 bool ok1, ok2, ok3;
00431
00432 if(generated)
00433 {
00434 if(imageDataSource)
00435 Blitz.vtkImageDataToArray(plotData,plotArray);
00436
00437 renderer->GetBackground(colours);
00438 double red = QInputDialog::getDouble(this, tr("New Background Colour"), tr("Red Component: "), colours[0], 0, 255, 2, &ok1);
00439 double green = QInputDialog::getDouble(this, tr("New Background Colour"), tr("Green Component: "), colours[1], 0, 255, 2, &ok2);
00440 double blue = QInputDialog::getDouble(this, tr("New Background Colour"), tr("Blue Component: "), colours[2], 0, 255, 2, &ok3);
00441
00442 if(ok1 && ok2 && ok3)
00443 setBackground(red,green,blue);
00444 }
00445 }
00446
00447 void DGVVolumePlotVTK::axesProperties()
00448 {
00449 bool ok1, ok2, ok3, ok4;
00450
00451 if(axisGenerated)
00452 {
00453 double colours[3], factor = 1.0;
00454 vtkProperty2D *properties = axes->GetProperty();
00455 vtkTextProperty *txtProperties = axes->GetAxisTitleTextProperty();
00456
00457 properties->GetColor(colours);
00458 factor = axes->GetFontFactor();
00459 double red = QInputDialog::getDouble(this, tr("New Axis Colour"), tr("Red Component (0.0-1.0): "), colours[0], 0, 1, 2, &ok1);
00460 double green = QInputDialog::getDouble(this, tr("New Axis Colour"), tr("Green Component (0.0-1.0): "), colours[1], 0, 1, 2, &ok2);
00461 double blue = QInputDialog::getDouble(this, tr("New Axis Colour"), tr("Blue Component (0.0-1.0): "), colours[2], 0, 1, 2, &ok3);
00462 factor = QInputDialog::getDouble(this, tr("New Axis Font Factor"), tr("Font Factor: "), factor, 0, 100, 3, &ok4);
00463
00464 if(ok1 && ok2 && ok3 && ok4)
00465 {
00466 properties->SetColor(red,green,blue);
00467 txtProperties->ShadowOff();
00468 txtProperties->SetColor(red,green,blue);
00469 axes->SetFontFactor(factor);
00470 axes->SetProperty(properties);
00471 axes->SetAxisTitleTextProperty(txtProperties);
00472 axes->SetAxisLabelTextProperty(txtProperties);
00473 renderWin->Render();
00474 }
00475 }
00476 }
00477
00478 void DGVVolumePlotVTK::toggleAxesAsClosestTriad()
00479 {
00480 if(axisGenerated)
00481 {
00482 closestTriad = triadAct->isChecked();
00483 if(closestTriad)
00484 setAxesAsClosestTriad();
00485 else
00486 setAxesAsOuterEdges();
00487 }
00488 }
00489
00490 void DGVVolumePlotVTK::toggleAntiAliasing()
00491 {
00492 if(generated)
00493 {
00494 antiAliasing = antiAliasingAct->isChecked();
00495 if(antiAliasing)
00496 {
00497 renderWin->SetAAFrames(maxAASamples);
00498 renderWin->Render();
00499 }
00500 else
00501 {
00502 renderWin->SetAAFrames(0);
00503 renderWin->Render();
00504 }
00505 }
00506 }
00507
00508 void DGVVolumePlotVTK::save()
00509 {
00510 if(loaded && generated)
00511 {
00512 QFileDialog *fileSaver = new QFileDialog(this);
00513 QSettings settings("Shakes", "DGV");
00514
00515 QString path = settings.value("recentPath").toString();
00516 QString filename = fileSaver->getSaveFileName(this,
00517 tr("Select File Name to Save"),
00518 path,
00519 tr("VTK Files (*.vti *.vtk)"));
00520
00521 if(!filename.isEmpty())
00522 {
00523 QFileInfo fi(filename);
00524 QString extension = fi.suffix().toLower();
00525
00526 if(extension == "vtk")
00527 saveVTK(filename);
00528 else
00529 saveVTI(filename);
00530 }
00531 }
00532 }
00533
00534 void DGVVolumePlotVTK::renameData()
00535 {
00536 bool ok;
00537
00538 QString newName = QInputDialog::getText(this, tr("Rename Data"), tr("New Name: "), QLineEdit::Normal, name, &ok);
00539
00540 if(ok)
00541 setName(newName);
00542 }
00543
00544 void DGVVolumePlotVTK::setupEvents()
00545 {
00547 QVTKWidget::GetRenderWindow()->GetInteractor()->RemoveObservers(vtkCommand::RightButtonPressEvent);
00548 QVTKWidget::GetRenderWindow()->GetInteractor()->RemoveObservers(vtkCommand::RightButtonReleaseEvent);
00549 }
00550
00551 void DGVVolumePlotVTK::contextMenuEvent(QContextMenuEvent *event)
00552 {
00553 contextMenu = new QMenu(this);
00554
00556 surfaceAct = contextMenu->addAction(tr("&Scan Volume with Surfaces"));
00557 surfaceAct->setShortcut(tr("Ctrl+s"));
00558 connect(surfaceAct, SIGNAL(triggered()), this, SLOT(scanVolume()));
00559 contextMenu->addSeparator()->setText("Axes");
00561 xLabelAct = contextMenu->addAction(tr("Set &x Label"));
00562 xLabelAct->setShortcut(tr("Ctrl+x"));
00563 connect(xLabelAct, SIGNAL(triggered()), this, SLOT(xLabel()));
00564 yLabelAct = contextMenu->addAction(tr("Set &y Label"));
00565 yLabelAct->setShortcut(tr("Ctrl+y"));
00566 connect(yLabelAct, SIGNAL(triggered()), this, SLOT(yLabel()));
00567 zLabelAct = contextMenu->addAction(tr("Set &z Label"));
00568 zLabelAct->setShortcut(tr("Ctrl+z"));
00569 connect(zLabelAct, SIGNAL(triggered()), this, SLOT(zLabel()));
00570 opacityAct = contextMenu->addAction(tr("Set &Opacity Level"));
00571 opacityAct->setShortcut(tr("Ctrl+o"));
00572 connect(opacityAct, SIGNAL(triggered()), this, SLOT(opacity()));
00573 backgroundAct = contextMenu->addAction(tr("Set &Background Colour"));
00574 backgroundAct->setShortcut(tr("Ctrl+b"));
00575 connect(backgroundAct, SIGNAL(triggered()), this, SLOT(background()));
00576 axesAct = contextMenu->addAction(tr("Set &Axes Colour/Font"));
00577 axesAct->setShortcut(tr("Ctrl+a"));
00578 connect(axesAct, SIGNAL(triggered()), this, SLOT(axesProperties()));
00580 triadAct = contextMenu->addAction(tr("Axes as Closest Triad"));
00581 triadAct->setCheckable(true);
00582 triadAct->setChecked(closestTriad);
00583 connect(triadAct, SIGNAL(triggered()), this, SLOT(toggleAxesAsClosestTriad()));
00584 antiAliasingAct = contextMenu->addAction(tr("Anti-Aliasing"));
00585 antiAliasingAct->setCheckable(true);
00586 antiAliasingAct->setChecked(antiAliasing);
00587 connect(antiAliasingAct, SIGNAL(triggered()), this, SLOT(toggleAntiAliasing()));
00588 contextMenu->addSeparator();
00591 saveAct = contextMenu->addAction(tr("Save Volume Data..."));
00592 saveAct->setShortcut(tr("Ctrl+s"));
00593 connect(saveAct, SIGNAL(triggered()), this, SLOT(save()));
00594 renameAct = contextMenu->addAction(tr("Rename"));
00595 renameAct->setShortcut(tr("Ctrl+r"));
00596 connect(renameAct, SIGNAL(triggered()), this, SLOT(renameData()));
00598 closeAct = contextMenu->addAction(tr("Close"));
00599 closeAct->setShortcut(tr("Ctrl+q"));
00600 connect(closeAct, SIGNAL(triggered()), this, SLOT(close()));
00601
00602 contextMenu->exec(event->globalPos());
00603 }