diff --git a/Libs/Visualization/VTK/Widgets/ctkVTKChartView.cpp b/Libs/Visualization/VTK/Widgets/ctkVTKChartView.cpp index 0038ec0ed8..ce999525ec 100644 --- a/Libs/Visualization/VTK/Widgets/ctkVTKChartView.cpp +++ b/Libs/Visualization/VTK/Widgets/ctkVTKChartView.cpp @@ -28,6 +28,7 @@ // VTK includes #include +#include #include #include #include @@ -35,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -53,12 +55,13 @@ class ctkVTKChartViewPrivate ctkVTKChartViewPrivate(ctkVTKChartView& object); void init(); void chartBounds(double* bounds)const; + void setChartType(int chartType); #ifdef CTK_USE_QVTKOPENGLWIDGET vtkSmartPointer RenderWindow; #endif vtkSmartPointer ContextView; - vtkSmartPointer Chart; + vtkSmartPointer Chart; double UserBounds[8]; mutable double OldBounds[8]; }; @@ -74,7 +77,29 @@ ctkVTKChartViewPrivate::ctkVTKChartViewPrivate(ctkVTKChartView& object) #ifdef CTK_USE_QVTKOPENGLWIDGET this->RenderWindow = vtkSmartPointer::New(); #endif - this->Chart = vtkSmartPointer::New(); + this->setChartType(ctkVTKChartView::ChartTypes::XYChart); +} + +// ---------------------------------------------------------------------------- +void ctkVTKChartViewPrivate::setChartType(int chartType) +{ + if (this->ContextView->GetScene()->GetNumberOfItems() > 0) + { + this->ContextView->GetScene()->RemoveItem(this->Chart); + } + switch (chartType) + { + case ctkVTKChartView::ChartTypes::XYChart: + this->Chart = vtkSmartPointer::New(); + break; + case ctkVTKChartView::ChartTypes::ParallelCoordinatesChart: + this->Chart = vtkSmartPointer::New(); + break; + case ctkVTKChartView::ChartTypes::UnknownChart: + default: + qWarning() << "ctkVTKChartViewPrivate::setChartType - Unknown chart type: " << chartType; + return; + } this->ContextView->GetScene()->AddItem(this->Chart); this->UserBounds[0] = this->UserBounds[2] = this->UserBounds[4] = this->UserBounds[6] = 0.; this->UserBounds[1] = this->UserBounds[3] = this->UserBounds[5] = this->UserBounds[7] = -1.; @@ -82,6 +107,32 @@ ctkVTKChartViewPrivate::ctkVTKChartViewPrivate(ctkVTKChartView& object) this->OldBounds[1] = this->OldBounds[3] = this->OldBounds[5] = this->OldBounds[7] = -1.; } +// ---------------------------------------------------------------------------- +int ctkVTKChartView::chartType()const +{ + Q_D(const ctkVTKChartView); + if (d->Chart->IsA("vtkChartXY")) + { + return ctkVTKChartView::ChartTypes::XYChart; + } + else if (d->Chart->IsA("vtkChartParallelCoordinates")) + { + return ctkVTKChartView::ChartTypes::ParallelCoordinatesChart; + } + else + { + return ctkVTKChartView::ChartTypes::UnknownChart; + } +} + +// ---------------------------------------------------------------------------- +void ctkVTKChartView::setChartType(int type) +{ + Q_D(ctkVTKChartView); + d->setChartType(type); + emit chartTypeChanged(type); +} + // ---------------------------------------------------------------------------- void ctkVTKChartViewPrivate::init() { @@ -118,9 +169,9 @@ void ctkVTKChartViewPrivate::init() this->Chart->SetActionToButton(vtkChart::PAN, vtkContextMouseEvent::MIDDLE_BUTTON); this->Chart->SetActionToButton(vtkChart::SELECT, vtkContextMouseEvent::RIGHT_BUTTON); - q->qvtkConnect(q->chart()->GetAxis(vtkAxis::BOTTOM),vtkCommand::ModifiedEvent, + q->qvtkConnect(q->abstractChart()->GetAxis(vtkAxis::BOTTOM),vtkCommand::ModifiedEvent, q, SIGNAL(extentChanged())); - q->qvtkConnect(q->chart()->GetAxis(vtkAxis::LEFT),vtkCommand::ModifiedEvent, + q->qvtkConnect(q->abstractChart()->GetAxis(vtkAxis::LEFT),vtkCommand::ModifiedEvent, q, SIGNAL(extentChanged())); } @@ -135,53 +186,68 @@ void ctkVTKChartViewPrivate::chartBounds(double* bounds)const Q_Q(const ctkVTKChartView); bounds[0] = bounds[2] = bounds[4] = bounds[6] = VTK_DOUBLE_MAX; bounds[1] = bounds[3] = bounds[5] = bounds[7] = VTK_DOUBLE_MIN; - vtkChartXY* chart = q->chart(); + vtkChart* chart = q->abstractChart(); + vtkChartXY* chartXY = vtkChartXY::SafeDownCast(chart); const vtkIdType plotCount = chart->GetNumberOfPlots(); for (vtkIdType i = 0; i < plotCount; ++i) { vtkPlot* plot = chart->GetPlot(i); - int corner = chart->GetPlotCorner(plot); - double plotBounds[4]; - plot->GetBounds(plotBounds); - switch (corner) + if (chartXY) { - // bottom left - case 0: + int corner = chartXY->GetPlotCorner(plot); + double plotBounds[4]; + plot->GetBounds(plotBounds); + switch (corner) + { + // bottom left + case 0: + // x + bounds[2] = bounds[2] > plotBounds[0] ? plotBounds[0] : bounds[2]; + bounds[3] = bounds[3] < plotBounds[1] ? plotBounds[1] : bounds[3]; + // y + bounds[0] = bounds[0] > plotBounds[2] ? plotBounds[2] : bounds[0]; + bounds[1] = bounds[1] < plotBounds[3] ? plotBounds[3] : bounds[1]; + break; + // bottom right + case 1: + // x + bounds[2] = bounds[2] > plotBounds[0] ? plotBounds[0] : bounds[2]; + bounds[3] = bounds[3] < plotBounds[1] ? plotBounds[1] : bounds[3]; + // y + bounds[4] = bounds[4] > plotBounds[2] ? plotBounds[2] : bounds[4]; + bounds[5] = bounds[5] < plotBounds[3] ? plotBounds[3] : bounds[5]; + break; + // top right + case 2: + // x + bounds[6] = bounds[6] > plotBounds[0] ? plotBounds[0] : bounds[6]; + bounds[7] = bounds[7] < plotBounds[1] ? plotBounds[1] : bounds[7]; + // y + bounds[4] = bounds[4] > plotBounds[2] ? plotBounds[2] : bounds[4]; + bounds[5] = bounds[5] < plotBounds[3] ? plotBounds[3] : bounds[5]; + break; + // top left + case 3: + // x + bounds[6] = bounds[6] > plotBounds[0] ? plotBounds[0] : bounds[6]; + bounds[7] = bounds[7] < plotBounds[1] ? plotBounds[1] : bounds[7]; + // y + bounds[0] = bounds[0] > plotBounds[2] ? plotBounds[2] : bounds[1]; + bounds[1] = bounds[0] < plotBounds[3] ? plotBounds[3] : bounds[1]; + break; + } + } + else + { + double plotBounds[4]; + plot->GetBounds(plotBounds); // x bounds[2] = bounds[2] > plotBounds[0] ? plotBounds[0] : bounds[2]; bounds[3] = bounds[3] < plotBounds[1] ? plotBounds[1] : bounds[3]; // y bounds[0] = bounds[0] > plotBounds[2] ? plotBounds[2] : bounds[0]; bounds[1] = bounds[1] < plotBounds[3] ? plotBounds[3] : bounds[1]; - break; - // bottom right - case 1: - // x - bounds[2] = bounds[2] > plotBounds[0] ? plotBounds[0] : bounds[2]; - bounds[3] = bounds[3] < plotBounds[1] ? plotBounds[1] : bounds[3]; - // y - bounds[4] = bounds[4] > plotBounds[2] ? plotBounds[2] : bounds[4]; - bounds[5] = bounds[5] < plotBounds[3] ? plotBounds[3] : bounds[5]; - break; - // top right - case 2: - // x - bounds[6] = bounds[6] > plotBounds[0] ? plotBounds[0] : bounds[6]; - bounds[7] = bounds[7] < plotBounds[1] ? plotBounds[1] : bounds[7]; - // y - bounds[4] = bounds[4] > plotBounds[2] ? plotBounds[2] : bounds[4]; - bounds[5] = bounds[5] < plotBounds[3] ? plotBounds[3] : bounds[5]; - break; - // top left - case 3: - // x - bounds[6] = bounds[6] > plotBounds[0] ? plotBounds[0] : bounds[6]; - bounds[7] = bounds[7] < plotBounds[1] ? plotBounds[1] : bounds[7]; - // y - bounds[0] = bounds[0] > plotBounds[2] ? plotBounds[2] : bounds[1]; - bounds[1] = bounds[0] < plotBounds[3] ? plotBounds[3] : bounds[1]; - break; } } } @@ -230,12 +296,32 @@ QString ctkVTKChartView::title()const } // ---------------------------------------------------------------------------- -vtkChartXY* ctkVTKChartView::chart()const +vtkChart* ctkVTKChartView::abstractChart()const { Q_D(const ctkVTKChartView); return d->Chart; } +// ---------------------------------------------------------------------------- +vtkChartParallelCoordinates* ctkVTKChartView::parallelCoordinatesChart()const +{ + Q_D(const ctkVTKChartView); + return vtkChartParallelCoordinates::SafeDownCast(d->Chart); +} + +// ---------------------------------------------------------------------------- +vtkChartXY* ctkVTKChartView::xyChart()const +{ + Q_D(const ctkVTKChartView); + return vtkChartXY::SafeDownCast(d->Chart); +} + +// ---------------------------------------------------------------------------- +vtkChartXY* ctkVTKChartView::chart()const +{ + return this->xyChart(); +} + // ---------------------------------------------------------------------------- vtkContextScene* ctkVTKChartView::scene()const { @@ -321,7 +407,7 @@ void ctkVTKChartView::chartExtent(double* extent)const } extent[0] = extent[2] = extent[4] = extent[6] = VTK_DOUBLE_MAX; extent[1] = extent[3] = extent[5] = extent[7] = VTK_DOUBLE_MIN; - vtkChartXY* chart = this->chart(); + vtkChart* chart = this->abstractChart(); vtkAxis* axis = chart->GetAxis(vtkAxis::BOTTOM); extent[0] = qMin(axis->GetMinimum(), extent[0]); extent[1] = qMax(axis->GetMaximum(), extent[1]); @@ -344,7 +430,7 @@ void ctkVTKChartView::setChartUserExtent(double* userExtent) qCritical() << Q_FUNC_INFO << ": Invalid user extent"; return; } - vtkChartXY* chart = this->chart(); + vtkChart* chart = this->abstractChart(); vtkAxis* axis = chart->GetAxis(vtkAxis::BOTTOM); axis->SetRange(userExtent[0], userExtent[1]); axis = chart->GetAxis(vtkAxis::LEFT); @@ -395,7 +481,7 @@ void ctkVTKChartView::chartUserBounds(double* bounds)const // ---------------------------------------------------------------------------- void ctkVTKChartView::setAxesToChartBounds() { - vtkChartXY* chart = this->chart(); + vtkChart* chart = this->abstractChart(); double bounds[8]; this->chartBounds(bounds); for (int i = 0; i < chart->GetNumberOfAxes(); ++i) @@ -410,7 +496,7 @@ void ctkVTKChartView::setAxesToChartBounds() // ---------------------------------------------------------------------------- void ctkVTKChartView::boundAxesToChartBounds() { - vtkChartXY* chart = this->chart(); + vtkChart* chart = this->abstractChart(); double bounds[8]; this->chartBounds(bounds); for (int i = 0; i < chart->GetNumberOfAxes(); ++i) diff --git a/Libs/Visualization/VTK/Widgets/ctkVTKChartView.h b/Libs/Visualization/VTK/Widgets/ctkVTKChartView.h index 87c74baed5..0d251ec8e0 100644 --- a/Libs/Visualization/VTK/Widgets/ctkVTKChartView.h +++ b/Libs/Visualization/VTK/Widgets/ctkVTKChartView.h @@ -28,6 +28,8 @@ class ctkVTKChartViewPrivate; // VTK includes +class vtkChart; +class vtkChartParallelCoordinates; class vtkChartXY; class vtkContextScene; class vtkPlot; @@ -38,7 +40,7 @@ class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKChartView : public ctkVTKOpenGL Q_OBJECT QVTK_OBJECT Q_PROPERTY(QString title READ title WRITE setTitle) - + Q_PROPERTY(int chartType READ chartType WRITE setChartType) public: typedef ctkVTKOpenGLNativeWidget Superclass; ctkVTKChartView(QWidget* parent = 0); @@ -58,9 +60,27 @@ class CTK_VISUALIZATION_VTK_WIDGETS_EXPORT ctkVTKChartView : public ctkVTKOpenGL /// Utility function that returns the view chart. It can be used for customizing /// the chart display options (axes, legend...) + Q_INVOKABLE vtkChart* abstractChart()const; + Q_INVOKABLE vtkChartParallelCoordinates* parallelCoordinatesChart()const; + Q_INVOKABLE vtkChartXY* xyChart()const; Q_INVOKABLE vtkChartXY* chart()const; Q_INVOKABLE vtkContextScene* scene()const; + /// Enumerated values for charType + enum ChartTypes + { + UnknownChart = 0, + XYChart = 1, + ParallelCoordinatesChart = 2, + NumberOfChartTypes + }; + Q_ENUM(ChartTypes) + + /// Set/Get the type of the chart, XYChart is the default + /// The string names as the same as the ChartTypes enum + Q_INVOKABLE int chartType() const; + Q_INVOKABLE void setChartType(int type); + /// Title that appears inside the view QString title()const; void setTitle(const QString& title); @@ -100,6 +120,8 @@ public Q_SLOTS: /// Fired anytime an axis is modified. void extentChanged(); + void chartTypeChanged(int chartType); + protected: QScopedPointer d_ptr;