Attention une mise à jour du serveur va être effectuée le lundi 17 mai entre 13h et 13h30. Cette mise à jour va générer une interruption du service de quelques minutes.

Commit f8928eaf authored by CABEL Tristan's avatar CABEL Tristan

Merge branch 'release/1.2.0'

parents 65cadd18 e51a131b
# Change Log:
## 2.2.0 19-Sep-2018
- add methods for Plot 2D to add/remove fields
## 2.1.1 14-Sep-2018
- fix install rules (missing layer wide header)
......
......@@ -23,8 +23,8 @@ project(dtkVisualization)
## ###################################################################
set(${PROJECT_NAME}_VERSION_MAJOR 2)
set(${PROJECT_NAME}_VERSION_MINOR 1)
set(${PROJECT_NAME}_VERSION_PATCH 1)
set(${PROJECT_NAME}_VERSION_MINOR 2)
set(${PROJECT_NAME}_VERSION_PATCH 0)
set(${PROJECT_NAME}_VERSION
${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH})
......
......@@ -18,6 +18,10 @@
;; QtWidgets
;; ******************************************************************/
QFrame {
color: white;
}
QComboBox {
color: #bebfbf;
border: 1px solid #242728;
......@@ -44,20 +48,16 @@ QComboBox QAbstractItemView {
background-color: #242728;
}
QSplitter::handle
{
QSplitter::handle {
background: #171819;
}
QToolTip
{
QToolTip {
color: #bebfbf;
border: 1px solid #242728;
border-radius: 4px;
background-color: #242728;
padding: 5px;
font: 14px;
}
......@@ -77,20 +77,16 @@ QScrollArea > QWidget > QScrollBar {
;; dtkWidgetsViewLayoutItem
;; ******************************************************************/
dtkWidgetsLayoutItemProxy
{
dtkWidgetsLayoutItemProxy {
background: #2d2e2e;
}
QFrame#dtkWidgetsLayoutItemFooterFocused
{
QFrame#dtkWidgetsLayoutItemFooterFocused {
background: #4b4c4d;
border-top: 1px solid #2e3133;
}
QFrame#dtkWidgetsLayoutItemFooterUnfocused
{
QFrame#dtkWidgetsLayoutItemFooterUnfocused {
background: #2e3133;
}
......@@ -98,10 +94,9 @@ QFrame#dtkWidgetsLayoutItemFooterUnfocused
;; dtkVisualizationViewerSidePane
;; ******************************************************************/
dtkVisualizationViewerSidePane
{
dtkVisualizationViewerSidePane {
background: #171819;
}
/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; dtkVisualizationViewer.qss ends here */
;; dtkVisualizationViewer.qss ends here */
......@@ -37,7 +37,7 @@ int main(int argc, char **argv)
application.setApplicationName("dtkVisualizationViewer");
application.setOrganizationName("inria");
application.setOrganizationDomain("fr");
application.setApplicationVersion("2.1.0");
application.setApplicationVersion("2.2.0");
dtkVisualizationViewer *viewer = new dtkVisualizationViewer;
viewer->show();
......
......@@ -16,6 +16,7 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/examples)
add_subdirectory(dtkVisualizationOverlayPaneItem)
add_subdirectory(dtkVisualizationOverlayRope)
add_subdirectory(dtkVisualizationPlot2D)
######################################################################
### CMakeLists.txt ends here
......@@ -23,6 +23,7 @@ int main(int argc, char **argv)
application.setApplicationName("dtkVisualizationOverlayPaneItem");
application.setOrganizationName("inria");
application.setOrganizationDomain("fr");
application.setApplicationVersion("2.2.0");
QFormLayout *layout_1 = new QFormLayout;
layout_1->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
......
......@@ -22,6 +22,7 @@ int main(int argc, char **argv)
application.setApplicationName("dtkVisualizationOverlayRope");
application.setOrganizationName("inria");
application.setOrganizationDomain("fr");
application.setApplicationVersion("2.2.0");
dtkWidgetsOverlayRope *window = new dtkWidgetsOverlayRope;
window->setWindowTitle("dtkVisualizationOverlayRope");
......
## Version: $Id$
##
######################################################################
##
### Commentary:
##
######################################################################
##
### Change Log:
##
######################################################################
##
### Code:
project(dtkVisualizationPlot2D)
## #################################################################
## Sources
## #################################################################
set(${PROJECT_NAME}_SOURCES main.cpp)
## #################################################################
## Build rules
## #################################################################
add_executable(${PROJECT_NAME} MACOSX_BUNDLE ${${PROJECT_NAME}_SOURCES})
target_link_libraries(${PROJECT_NAME} Qt5::Core)
target_link_libraries(${PROJECT_NAME} Qt5::Gui)
target_link_libraries(${PROJECT_NAME} Qt5::Widgets)
target_link_libraries(${PROJECT_NAME} dtkVisualization)
#target_link_libraries(${PROJECT_NAME} dtkWidgets)
target_link_libraries(${PROJECT_NAME} dtkVisualizationWidgets)
target_link_libraries(${PROJECT_NAME} ${VTK_LIBRARIES})
## ###################################################################
## Bundle setup
## ###################################################################
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.plist.in ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.plist)
if(APPLE)
set_target_properties(${PROJECT_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_BINARY_DIR}/${PROJECT_NAME}.plist)
endif(APPLE)
######################################################################
### CMakeLists.txt ends here
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
<string>@PROJECT_NAME@</string>
<key>CFBundleGetInfoString</key>
<string></string>
<key>CFBundleIconFile</key>
<string>@PROJECT_NAME@</string>
<key>CFBundleIdentifier</key>
<string>fr.inria.@PROJECT_NAME@</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleLongVersionString</key>
<string>@dtkVisualization_VERSION@</string>
<key>CFBundleName</key>
<string>@PROJECT_NAME@</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>@dtkVisualization_VERSION@</string>
<key>CFBundleVersion</key>
<string>@dtkVisualization_VERSION@</string>
<key>CSResourcesFileMapped</key>
<true/>
<key>NSHumanReadableCopyright</key>
<string>Inria</string>
<key>NSPrincipalClass</key>
<string>NSApplication</string>
<key>NSHighResolutionCapable</key>
<true/>
</dict>
</plist>
// Version: $Id$
//
//
// Commentary:
//
//
// Change Log:
//
//
// Code:
#include <dtkVisualization/dtkVisualizationPlot2D>
#include <QtWidgets>
#include <vtkChartXY.h>
#include <vtkAbstractArray.h>
#include <vtkDoubleArray.h>
#include <QVTKOpenGLWidget.h>
#include <math.h>
#define MAX 5
int main(int argc, char **argv)
{
QSurfaceFormat::setDefaultFormat(QVTKOpenGLWidget::defaultFormat());
QApplication application(argc, argv);
application.setApplicationName("dtkVisualizationPlot2D");
application.setOrganizationName("inria");
application.setOrganizationDomain("fr");
application.setApplicationVersion("2.2.0");
// ///////////////////////////////////////////////////////////////////
// Field data
// ///////////////////////////////////////////////////////////////////
vtkSmartPointer<vtkDoubleArray> field_1 = vtkSmartPointer<vtkDoubleArray>::New();
field_1->SetName("Linear");
field_1->SetNumberOfComponents(1);
field_1->SetNumberOfTuples(MAX * 1e2);
vtkSmartPointer<vtkDoubleArray> field_2 = vtkSmartPointer<vtkDoubleArray>::New();
field_2->SetName("Fake EEG");
field_2->SetNumberOfComponents(1);
field_2->SetNumberOfTuples(MAX * 1e2);
vtkSmartPointer<vtkDoubleArray> field_3 = vtkSmartPointer<vtkDoubleArray>::New();
field_3->SetName("third_field");
field_3->SetNumberOfComponents(1);
field_3->SetNumberOfTuples(MAX * 1e2);
for(double i = 0; i < MAX; i += 1e-2) {
field_1->SetValue(i * 1e2, i);
field_2->SetValue(i * 1e2, cos(M_PI*6*i) + 2*sin(M_PI*2*i));
field_3->SetValue(i * 1e2, rand() % 10);
}
// ///////////////////////////////////////////////////////////////////
// Plot 2D example
// ///////////////////////////////////////////////////////////////////
dtkVisualizationPlot2D *plot = new dtkVisualizationPlot2D;
plot->setWindowTitle("dtkVisualizationPlot2D");
plot->addField(field_1);
plot->addField(field_2, true, vtkChart::LINE, vtkPlotPoints::NONE);
plot->addField(field_3);
plot->show();
plot->raise();
plot->render();
qDebug() << plot->fields();
plot->removeField("third_field");
qDebug() << plot->fields();
// ///////////////////////////////////////////////////////////////////
return application.exec();
}
//
// main.cpp ends here
......@@ -18,11 +18,25 @@
#include <dtkWidgets/dtkWidgetsHUDItem>
#include <dtkWidgets/dtkWidgetsOverlayPane>
#include <vtkAbstractArray.h>
#include <vtkAxis.h>
#include <vtkBrush.h>
#include <vtkCamera.h>
#include <vtkChartXY.h>
#include <vtkContextActor.h>
#include <vtkContextScene.h>
#include <vtkDelimitedTextWriter.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkPen.h>
#include <vtkPlot.h>
#include <vtkPlotPoints.h>
#include <vtkPNGWriter.h>
#include <vtkTable.h>
#include <vtkTextProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkSmartPointer.h>
#include <vtkWindowToImageFilter.h>
#include <QVTKOpenGLWidget.h>
......@@ -41,20 +55,47 @@ public:
public:
QSize sizeHint(void) const;
public:
void clear(void);
public:
vtkSmartPointer<vtkGenericOpenGLRenderWindow> window;
vtkSmartPointer<vtkRenderer> renderer;
vtkSmartPointer<vtkTable> fields_table;
vtkSmartPointer<vtkChartXY> chart = nullptr;
vtkSmartPointer<vtkContextScene> chart_scene = nullptr;
vtkSmartPointer<vtkContextActor> chart_actor = nullptr;
protected:
void mousePressEvent(QMouseEvent *event);
void resizeEvent(QResizeEvent *event);
public slots:
void exportAsCSV(const QString &);
void exportAsPNG(const QString &);
public:
void exportAsCSV(void);
void exportAsPNG(void);
public:
QColor random(void);
public:
dtkVisualizationPlot2D *q = Q_NULLPTR;
public:
dtkWidgetsHUD *hud;
dtkWidgetsOverlayPane *overlay;
public:
QComboBox *field_x;
QListWidget *field_y;
QStringListModel *fields_table_model;
QMap<QString, int> chart_type;
QMap<QString, QColor> fields_color;
QMap<QString, int> marker_style;
bool show_legend = true;
};
dtkVisualizationPlot2DPrivate::dtkVisualizationPlot2DPrivate(QWidget *parent) : QVTKOpenGLWidget(parent)
......@@ -72,13 +113,26 @@ dtkVisualizationPlot2DPrivate::dtkVisualizationPlot2DPrivate(QWidget *parent) :
this->setObjectName(QString("Plot2D - %1").arg(count++));
this->hud = new dtkWidgetsHUD(this);
this->overlay = new dtkWidgetsOverlayPane(this);
this->hud = new dtkWidgetsHUD(parent);
this->overlay = new dtkWidgetsOverlayPane(parent);
this->fields_table = vtkSmartPointer<vtkTable>::New();
this->fields_table_model = new QStringListModel;
this->field_x = new QComboBox(this);
this->field_x->setInsertPolicy(QComboBox::InsertAlphabetically);
this->field_x->setModel(this->fields_table_model);
this->field_y = new QListWidget(this);
this->field_y->setFixedHeight(300);
qsrand((uint)QTime::currentTime().msec());
}
dtkVisualizationPlot2DPrivate::~dtkVisualizationPlot2DPrivate(void)
{
delete this->fields_table_model;
}
QSize dtkVisualizationPlot2DPrivate::sizeHint(void) const
......@@ -86,6 +140,11 @@ QSize dtkVisualizationPlot2DPrivate::sizeHint(void) const
return QSize(800, 600);
}
void dtkVisualizationPlot2DPrivate::clear(void)
{
this->chart->ClearPlots();
}
void dtkVisualizationPlot2DPrivate::mousePressEvent(QMouseEvent *event)
{
q->emit focused();
......@@ -102,6 +161,53 @@ void dtkVisualizationPlot2DPrivate::resizeEvent(QResizeEvent *event)
this->overlay->setFixedHeight(event->size().height());
}
QColor dtkVisualizationPlot2DPrivate::random(void)
{
return QColor(QColor::colorNames().at(qrand() % QColor::colorNames().count()));
}
void dtkVisualizationPlot2DPrivate::exportAsCSV(void)
{
QString path = QDir::homePath();
QFileDialog *dialog = new QFileDialog(this, tr("Save as"), path, QString("csv file (*.csv)"));
dialog->setAcceptMode(QFileDialog::AcceptSave);
dialog->setFileMode(QFileDialog::AnyFile);
dialog->open(this, SLOT(exportAsCSV(const QString&)));
}
void dtkVisualizationPlot2DPrivate::exportAsCSV(const QString &filename)
{
vtkSmartPointer<vtkDelimitedTextWriter> text_writer = vtkSmartPointer<vtkDelimitedTextWriter>::New();
text_writer->SetInputData(fields_table);
text_writer->SetFileName(filename.toStdString().c_str());
text_writer->Write();
}
void dtkVisualizationPlot2DPrivate::exportAsPNG(void)
{
QString path = QDir::homePath();
QFileDialog *dialog = new QFileDialog(this, tr("Save as"), path, QString("PNG file (*.png)"));
dialog->setAcceptMode(QFileDialog::AcceptSave);
dialog->setFileMode(QFileDialog::AnyFile);
dialog->open(this, SLOT(exportAsPNG(const QString&)));
}
void dtkVisualizationPlot2DPrivate::exportAsPNG(const QString &filename)
{
vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter = vtkSmartPointer<vtkWindowToImageFilter>::New();
windowToImageFilter->SetInput(this->renderer->GetRenderWindow());
windowToImageFilter->SetInputBufferTypeToRGBA();
windowToImageFilter->ReadFrontBufferOff();
windowToImageFilter->Update();
vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New();
writer->SetFileName(filename.toStdString().c_str());
writer->SetInputConnection(windowToImageFilter->GetOutputPort());
writer->Write();
}
// ///////////////////////////////////////////////////////////////////
// dtkVisualizationPlot2D
// ///////////////////////////////////////////////////////////////////
......@@ -121,6 +227,43 @@ dtkVisualizationPlot2D::dtkVisualizationPlot2D(QWidget *parent) : dtkWidgetsWidg
connect(settings, SIGNAL(clicked()), d->overlay, SLOT(toggle()));
this->setAcceptDrops(true);
QFormLayout *fields_form = new QFormLayout;
fields_form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
fields_form->addRow(tr("X"), d->field_x);
fields_form->addRow(tr("Y"), d->field_y);
connect(d->field_x, &QComboBox::currentTextChanged, [=] () { this->render(); });
connect(d->field_y, &QListWidget::itemChanged, [=] () { this->render(); });
QPushButton *export_as_png = new QPushButton(this);
export_as_png->setText("PNG");
QPushButton *export_as_csv = new QPushButton(this);
export_as_csv->setText("CSV");
QFormLayout *export_form = new QFormLayout;
export_form->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow);
export_form->addRow("Export as", export_as_png);
export_form->addRow("Export as", export_as_csv);
connect(export_as_png, &QPushButton::clicked, [=] () { d->exportAsPNG(); });
connect(export_as_csv, &QPushButton::clicked, [=] () { d->exportAsCSV(); });
dtkWidgetsOverlayPaneItem *fields_item = new dtkWidgetsOverlayPaneItem;
fields_item->setTitle("Fields");
fields_item->addLayout(fields_form);
fields_item->toggle();
dtkWidgetsOverlayPaneItem *export_item = new dtkWidgetsOverlayPaneItem;
export_item->setTitle("Export");
export_item->addLayout(export_form);
d->overlay->addWidget(fields_item);
d->overlay->addWidget(export_item);
d->overlay->toggle();
d->hud->addInfo("Start by selecting x-axis and y-axis");
}
dtkVisualizationPlot2D::~dtkVisualizationPlot2D(void)
......@@ -133,11 +276,112 @@ QWidget *dtkVisualizationPlot2D::widget(void)
return d;
}
void dtkVisualizationPlot2D::update(void)
void dtkVisualizationPlot2D::render(void)
{
if(d->field_x->currentText().isEmpty())
return;
if(!d->chart)
d->chart = vtkSmartPointer<vtkChartXY>::New();
d->clear();
d->chart->GetAxis(vtkAxis::LEFT)->SetMargins(0, 0);
d->chart->GetAxis(vtkAxis::LEFT)->GetPen()->SetColor(255, 255, 255);
d->chart->GetAxis(vtkAxis::LEFT)->GetLabelProperties()->SetColor(1.0, 1.0, 1.0);
d->chart->GetAxis(vtkAxis::LEFT)->GetTitleProperties()->SetColor(1.0, 1.0, 1.0);
d->chart->GetAxis(vtkAxis::BOTTOM)->SetMargins(0, 0);
d->chart->GetAxis(vtkAxis::BOTTOM)->GetPen()->SetColor(255, 255, 255);
d->chart->GetAxis(vtkAxis::BOTTOM)->GetLabelProperties()->SetColor(1.0, 1.0, 1.0);
d->chart->GetAxis(vtkAxis::BOTTOM)->GetTitleProperties()->SetColor(1.0, 1.0, 1.0);
d->chart->SetShowLegend(d->show_legend);
if(!d->chart_scene) {
d->chart_scene = vtkSmartPointer<vtkContextScene>::New();
d->chart_scene->AddItem(d->chart);
d->chart_scene->SetRenderer(d->renderer);
}
if(!d->chart_actor) {
d->chart_actor = vtkSmartPointer<vtkContextActor>::New();
d->chart_actor->SetScene(d->chart_scene);
d->renderer->AddActor(d->chart_actor);
}
for(int row=0; row < d->field_y->count(); ++row) {
if(d->field_y->item(row)->checkState() == Qt::Checked) {
int chart_type = d->chart_type[d->field_y->item(row)->text()];
vtkPlot *points = d->chart->AddPlot(chart_type);
points->SetInputData(d->fields_table,
d->field_x->currentText().toStdString(),
d->field_y->item(row)->text().toStdString());
QColor color = d->fields_color[d->field_y->item(row)->text()];
points->SetColor(color.red(), color.green(), color.blue(), 255);
points->GetBrush()->SetColor(255, 64, 64);
points->SetWidth(1.0);
vtkPlotPoints::SafeDownCast(points)->SetMarkerStyle(d->marker_style[d->field_y->item(row)->text()]);
}
}
d->GetInteractor()->Render();
}
QStringList dtkVisualizationPlot2D::fields(void)
{
return d->fields_table_model->stringList();
}
void dtkVisualizationPlot2D::addField(vtkSmartPointer<vtkAbstractArray> field, bool checked, int chart_type, int marker_style)
{
Q_ASSERT_X(chart_type >= 0 && chart_type < 7, "setChartType", "0: Line , 1: Points , 2: Bar , 3: Stacked , 4: Bag , 5: functionalBag , 6: Area -> as in vtkPlot");
Q_ASSERT_X(marker_style >= 0 && marker_style < 6, "setMarkerStyle", "NONE , CROSS , PLUS , SQUARE , CIRCLE , DIAMOND ");
d->fields_table->AddColumn(field);
d->chart_type[field->GetName()] = chart_type;
d->fields_color[field->GetName()] = d->random();
d->marker_style[field->GetName()] = marker_style;
d->field_x->addItem(field->GetName());
QListWidgetItem *new_field_item = new QListWidgetItem(field->GetName(), d->field_y);
new_field_item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
new_field_item->setCheckState(Qt::Unchecked);
new_field_item->setCheckState(checked ? Qt::Checked : Qt::Unchecked);
d->field_x->model()->sort(0);
d->field_y->sortItems();
this->render();
}
void dtkVisualizationPlot2D::removeField(vtkSmartPointer<vtkAbstractArray> field)
{
this->removeField(field->GetName());
<