diff --git a/Gui/Base/CMakeLists.txt b/Gui/Base/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..af1ca87ef2a211bc84a4dbd836a4a4750ae9ff8a --- /dev/null +++ b/Gui/Base/CMakeLists.txt @@ -0,0 +1,57 @@ +# Source files +set( SOURCES + OGSError.cpp + QNonScalableGraphicsTextItem.cpp + RecentFiles.cpp + TreeItem.cpp + TreeModel.cpp + ColorPickerPushButton.cpp + TreeModelIterator.cpp + # modeltest.cpp # Not needed + CheckboxDelegate.cpp + QValueTooltipSlider.cpp +) + +# Moc headers +set( MOC_HEADERS + RecentFiles.h + TreeModel.h + ColorPickerPushButton.h + # modeltest.h # Not needed + CheckboxDelegate.h + QValueTooltipSlider.h +) + +# Header files +set( HEADERS + OGSError.h + QNonScalableGraphicsTextItem.h + TreeItem.h + TreeModelIterator.h + StrictDoubleValidator.h +) + +# UI files +set ( UIS +) + +# Put moc files in a project folder +source_group("UI Files" REGULAR_EXPRESSION "\\w*\\.ui") +source_group("Moc Files" REGULAR_EXPRESSION "moc_.*") + +# Run Qts user interface compiler uic on .ui files +qt4_wrap_ui( UI_HEADERS ${UIS} ) + +# Run Qts meta object compiler moc on header files +qt4_wrap_cpp( MOC_SOURCES ${MOC_HEADERS} ) + +# Create the library +add_library( QtBase STATIC + ${SOURCES} + ${HEADERS} + ${MOC_HEADERS} + ${MOC_SOURCES} + ${UIS} +) + +target_link_libraries( QtBase ${QT_LIBRARIES} ) diff --git a/Gui/Base/CheckboxDelegate.cpp b/Gui/Base/CheckboxDelegate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0224f1006fc00905bd9623ab37cb76cd70706a5 --- /dev/null +++ b/Gui/Base/CheckboxDelegate.cpp @@ -0,0 +1,94 @@ +/** + * \file CheckboxDelegate.cpp + * 19/08/2010 LB Initial implementation + * + * Implementation of CheckboxDelegate class + */ + +// ** INCLUDES ** +#include "CheckboxDelegate.h" +#include <QApplication> +#include <QCheckBox> +#include <QEvent> +#include <QMouseEvent> +#include <QPainter> +#include <QStyleOptionButton> + +#include <iostream> + +CheckboxDelegate::CheckboxDelegate(QObject* parent) + : QItemDelegate(parent) +{ +} + +void CheckboxDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const +{ + if(index.isValid()) + { + bool checked = index.model()->data(index, Qt::DisplayRole).toBool(); + + QStyleOptionButton styleOptionButton; + styleOptionButton.state |= QStyle::State_Enabled; + if (checked) + styleOptionButton.state |= QStyle::State_On; + else + styleOptionButton.state |= QStyle::State_Off; + + styleOptionButton.rect = this->checkboxRect(option); + + QApplication::style()->drawControl(QStyle::CE_CheckBox, + &styleOptionButton, painter); + } + else + QItemDelegate::paint(painter, option, index); +} + +bool CheckboxDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, + const QStyleOptionViewItem &option, const QModelIndex &index) +{ + Q_UNUSED(option); + + if ((event->type() == QEvent::MouseButtonRelease) || + (event->type() == QEvent::MouseButtonDblClick)) + { + QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event); + if (mouse_event->button() != Qt::LeftButton || + !checkboxRect(option).contains(mouse_event->pos())) + return false; + if (event->type() == QEvent::MouseButtonDblClick) + return true; + } + else if (event->type() == QEvent::KeyPress) + { + if (static_cast<QKeyEvent*>(event)->key() != Qt::Key_Space && + static_cast<QKeyEvent*>(event)->key() != Qt::Key_Select) + return false; + } + else + return false; + + bool checked = index.model()->data(index, Qt::DisplayRole).toBool(); + return model->setData(index, !checked, Qt::EditRole); +} + +QSize CheckboxDelegate::sizeHint(const QStyleOptionViewItem & option, + const QModelIndex & index) const +{ + Q_UNUSED(index); + + QRect rect = checkboxRect(option); + return QSize(rect.width(), rect.height()); +} + +QRect CheckboxDelegate::checkboxRect(const QStyleOptionViewItem& viewItemStyleOptions) const +{ + QStyleOptionButton styleOptionButton; + QRect rect = QApplication::style()->subElementRect( + QStyle::SE_CheckBoxIndicator, &styleOptionButton); + QPoint point(viewItemStyleOptions.rect.x() + + viewItemStyleOptions.rect.width() / 2 - rect.width() / 2, + viewItemStyleOptions.rect.y() + viewItemStyleOptions.rect.height() / 2 - + rect.height() / 2); + return QRect(point, rect.size()); +} diff --git a/Gui/Base/CheckboxDelegate.h b/Gui/Base/CheckboxDelegate.h new file mode 100644 index 0000000000000000000000000000000000000000..67a4fbef36495060b16741a516d9627a86d4d7ba --- /dev/null +++ b/Gui/Base/CheckboxDelegate.h @@ -0,0 +1,42 @@ +/** + * \file CheckboxDelegate.h + * 19/08/2010 LB Initial implementation + */ + +#ifndef CHECKBOXDELEGATE_H +#define CHECKBOXDELEGATE_H + +#include <QItemDelegate> + +class QWidget; +class QRect; + +/** + * \brief CheckboxDelegate modifies a model view to display boolean values as checkboxes. + * + * Important: the column on which this delegate is set (QAbstractItemView::setItemDelegateForColumn()) + * must not have the flags Qt::ItemIsEditable or Qt::ItemIsUserCheckable set in the model. + **/ +class CheckboxDelegate : public QItemDelegate +{ + Q_OBJECT + +public: + /// \brief Constructor + CheckboxDelegate (QObject* parent = 0); + + /// \brief Paints a checkbox. This overrides the default painting of a combo box. + void paint(QPainter* painter, const QStyleOptionViewItem& option, + const QModelIndex& index) const; + + /// \brief Handles the click events and sets the model data. + bool editorEvent(QEvent* event, QAbstractItemModel* model, + const QStyleOptionViewItem &option, const QModelIndex &index); + + QSize sizeHint (const QStyleOptionViewItem & option, const QModelIndex & index) const; + +private: + QRect checkboxRect(const QStyleOptionViewItem& viewItemStyleOptions) const; +}; + +#endif // CHECKBOXDELEGATE_H diff --git a/Gui/Base/ColorPickerPushButton.cpp b/Gui/Base/ColorPickerPushButton.cpp new file mode 100644 index 0000000000000000000000000000000000000000..802d4beea81bacf4b40587c7b9d2c17e078f21f2 --- /dev/null +++ b/Gui/Base/ColorPickerPushButton.cpp @@ -0,0 +1,77 @@ +/** + * \file ColorPickerPushButton.cpp + * 17/5/2010 LB Initial implementation + * + * Implementation of ColorPickerPushButton + */ + +// ** INCLUDES ** +#include "ColorPickerPushButton.h" + +#include <QColorDialog> + +ColorPickerPushButton::ColorPickerPushButton( QWidget* parent /*= 0*/ ) + : QPushButton(parent) +{ + setAutoFillBackground(true); + _color = QColor("white"); +} + +void ColorPickerPushButton::mouseReleaseEvent(QMouseEvent* e) +{ + Q_UNUSED(e); + QColor newColor = QColorDialog::getColor(_color, NULL, "Choose a color"); + if (!newColor.isValid()) + return; + + setColor(newColor); + + emit colorPicked(_color); +} + +QString ColorPickerPushButton::colorToCss( QColor color ) +{ + QString colorStr = "rgb"; + colorStr.append(colorToString(color)); + + return colorStr; +} + +QString ColorPickerPushButton::colorToString( QColor color ) +{ + QString colorStr = "("; + colorStr.append(QString::number(color.red())); + colorStr.append(", "); + colorStr.append(QString::number(color.green())); + colorStr.append(", "); + colorStr.append(QString::number(color.blue())); + colorStr.append(")"); + + return colorStr; +} + +void ColorPickerPushButton::setColor( QColor color ) +{ + _color = color; + + // Compute text color + QColor hsv = _color.toHsv(); + QString textColorStr; + if (hsv.valueF() < 0.5f) + textColorStr = "color: rgb(255, 255, 255);"; + else + textColorStr = "color: rgb(0, 0, 0);"; + + QString stylesheetStr = "background-color: "; + stylesheetStr.append(colorToCss(_color)); + stylesheetStr.append(";"); + stylesheetStr.append(textColorStr); + this->setStyleSheet(stylesheetStr); + + this->setText(colorToString(_color)); +} + +void ColorPickerPushButton::setColor( double* color ) +{ + return setColor(QColor::fromRgbF(color[0], color[1], color[2])); +} diff --git a/Gui/Base/ColorPickerPushButton.h b/Gui/Base/ColorPickerPushButton.h new file mode 100644 index 0000000000000000000000000000000000000000..5703d44e023bd82e66682923d49af1449b9c501f --- /dev/null +++ b/Gui/Base/ColorPickerPushButton.h @@ -0,0 +1,47 @@ +/** + * \file ColorPickerPushButton.h + * 17/5/2010 LB Initial implementation + * + */ + +#ifndef COLORPICKERPUSHBUTTON_H +#define COLORPICKERPUSHBUTTON_H + +// ** INCLUDES ** +#include <QPushButton> + +class QColor; +class QMouseEvent; + +/** + * ColorPickerPushButton calls a QColorDialog on clicking and then sends a + * colorPicked(QColor) signal. It also saves the last color and sets its + * background color accordingly. + */ +class ColorPickerPushButton : public QPushButton +{ + Q_OBJECT + +public: + ColorPickerPushButton(QWidget* parent = 0); + +public slots: + /// Calls the QColorDialog + void mouseReleaseEvent(QMouseEvent* e); + + /// Sets the color. + void setColor(QColor color); + void setColor(double* color); + +private: + QString colorToCss(QColor color); + QString colorToString(QColor color); + + QColor _color; + +signals: + /// Is emitted when a color was picked from the dialog. + void colorPicked(QColor); +}; + +#endif // COLORPICKERPUSHBUTTON_H diff --git a/Gui/Base/OGSError.cpp b/Gui/Base/OGSError.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5620ee672100e18e3f859cd428633e28e8391ce6 --- /dev/null +++ b/Gui/Base/OGSError.cpp @@ -0,0 +1,37 @@ +/** + * \file OGSError.cpp + * KR Initial implementation + */ +#include "OGSError.h" + +#include <QMessageBox> +#include <QString> + +OGSError::OGSError() +{} + +OGSError::~OGSError() +{} + +/** + * Displays an error in a QMessageBox + * \param e The error message. + */ +void OGSError::box(const QString &e) +{ + box(e, "OpenGeoSys"); +} + +/** + * Displays an error in a QMessageBox + * \param e The error message. + * \param t The title of the message box + * \sa QMessageBox + */ +void OGSError::box(const QString &e, const QString &t) +{ + QMessageBox msgBox; + msgBox.setWindowTitle(t); + msgBox.setText(e); + msgBox.exec(); +} diff --git a/Gui/Base/OGSError.h b/Gui/Base/OGSError.h new file mode 100644 index 0000000000000000000000000000000000000000..99de59763fb81e5faa9efd776894c23b2385b166 --- /dev/null +++ b/Gui/Base/OGSError.h @@ -0,0 +1,25 @@ +/** + * \file OGSError.h + * KR Initial implementation + */ + +#ifndef OGSERROR_H +#define OGSERROR_H + +class QString; + +/** + * \brief Manages error messages via message boxes + */ +class OGSError +{ +public: + static void box(const QString &e); + static void box(const QString &e, const QString &t); + +protected: + OGSError(); + ~OGSError(); +}; + +#endif //OGSERROR_H diff --git a/Gui/Base/QNonScalableGraphicsTextItem.cpp b/Gui/Base/QNonScalableGraphicsTextItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0901e7cdcd75d499f1894a8dbb4878f8744f35f1 --- /dev/null +++ b/Gui/Base/QNonScalableGraphicsTextItem.cpp @@ -0,0 +1,50 @@ +/** + * \file QNonScalableGraphicsTextItem.cpp + * KR Initial implementation + */ + +#include "QNonScalableGraphicsTextItem.h" +#include <QPainter> + +/// Constructor using a QGraphicsTextItem. +QNonScalableGraphicsTextItem::QNonScalableGraphicsTextItem(QGraphicsItem* parent) : + QGraphicsTextItem(parent) +{ + setAcceptDrops(true); + setAcceptHoverEvents(true); + setFlag(QGraphicsItem::ItemIgnoresTransformations, true); +} + +/// Constructor using a QString. +QNonScalableGraphicsTextItem::QNonScalableGraphicsTextItem(const QString & text, + QGraphicsItem* parent) : + QGraphicsTextItem(parent) +{ + if (!text.isEmpty()) + setPlainText(text); + setAcceptDrops(true); + setAcceptHoverEvents(true); + setFlag(QGraphicsItem::ItemIgnoresTransformations, true); +} + +QNonScalableGraphicsTextItem::~QNonScalableGraphicsTextItem() +{ +} + +/// Paints the text item. +void QNonScalableGraphicsTextItem::paint(QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) +{ + //painter->drawRect(boundingRect()); + QRectF rect = boundingRect(); + painter->translate(-rect.width() / 2, -rect.height() / 2); + QGraphicsTextItem::paint(painter, option, widget); +} + +/// Returns the bounding rectangle of the text item. +QRectF QNonScalableGraphicsTextItem::boundingRect() const +{ + QRectF rect = QGraphicsTextItem::boundingRect(); + return rect; //QRectF(rect.x()-rect.width()/2, rect.y()-rect.height()/2,rect.width(), rect.height()); +} diff --git a/Gui/Base/QNonScalableGraphicsTextItem.h b/Gui/Base/QNonScalableGraphicsTextItem.h new file mode 100644 index 0000000000000000000000000000000000000000..1b3dc2679519ce6beb8b7f99a29f4187dbd758b5 --- /dev/null +++ b/Gui/Base/QNonScalableGraphicsTextItem.h @@ -0,0 +1,27 @@ +/** + * \file QNonScalableGraphicsTextItem.h + * KR Initial implementation + */ + +#ifndef QNONSCALABLETEXTITEM_H +#define QNONSCALABLETEXTITEM_H + +#include <QGraphicsTextItem> + +/** + * \brief A QGraphicsTextItem that will ignore all geometric transformations. + * + * A QGraphicsTextItem that will ignore all geometric transformations to the underlying QGraphicsView/QGraphicsScene (in particular, it will not be scaled). + */ +class QNonScalableGraphicsTextItem : public QGraphicsTextItem +{ +public: + QNonScalableGraphicsTextItem(QGraphicsItem* parent = 0); + QNonScalableGraphicsTextItem(const QString &text, QGraphicsItem* parent = 0); + ~QNonScalableGraphicsTextItem(); + + void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget); + virtual QRectF boundingRect() const; +}; + +#endif //QNONSCALABLETEXTITEM_H diff --git a/Gui/Base/QValueTooltipSlider.cpp b/Gui/Base/QValueTooltipSlider.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f66584a0573f7ffcf935b86eb3876e0f249781ec --- /dev/null +++ b/Gui/Base/QValueTooltipSlider.cpp @@ -0,0 +1,26 @@ +/** + * \file QValueTooltipSlider.cpp + * 23/03/2011 LB Initial implementation + * + * Implementation of QValueSlider class + */ + +// ** INCLUDES ** +#include "QValueTooltipSlider.h" + +#include <QCursor> +#include <QString> +#include <QToolTip> + +#include <iostream> + +QValueTooltipSlider::QValueTooltipSlider(QWidget* parent) + : QSlider(parent) +{ + connect(this, SIGNAL(sliderMoved(int)), this, SLOT(setTooltipValue(int))); +} + +void QValueTooltipSlider::setTooltipValue(int value) +{ + QToolTip::showText(QCursor::pos(), QString::number(value)); +} diff --git a/Gui/Base/QValueTooltipSlider.h b/Gui/Base/QValueTooltipSlider.h new file mode 100644 index 0000000000000000000000000000000000000000..3facee9475cba66a54efd7339e35fd8b88b052e0 --- /dev/null +++ b/Gui/Base/QValueTooltipSlider.h @@ -0,0 +1,24 @@ +/** + * \file QValueTooltipSlider.h + * 23/03/2011 LB Initial implementation + */ + +#ifndef QVALUETOOLTIPSLIDER_H +#define QVALUETOOLTIPSLIDER_H + +#include <QSlider> + +class QValueTooltipSlider : public QSlider +{ + Q_OBJECT + +public: + QValueTooltipSlider(QWidget* parent = 0); + +public slots: + void setTooltipValue(int value); + +protected: +}; + +#endif // QVALUETOOLTIPSLIDER_H diff --git a/Gui/Base/RecentFiles.cpp b/Gui/Base/RecentFiles.cpp new file mode 100644 index 0000000000000000000000000000000000000000..520b8ad230d49bca3ea92c2d56aff9b777aac70a --- /dev/null +++ b/Gui/Base/RecentFiles.cpp @@ -0,0 +1,75 @@ +/** + * \file RecentFiles.cpp + * 5/11/2009 LB Initial implementation + * + * Implementation of RecentFiles + */ + +// ** INCLUDES ** +#include "RecentFiles.h" + +#include <QFileInfo> +#include <QSettings> + +RecentFiles::RecentFiles( QObject* parent, const char* slot, + QString settingsName, QString programName ) + : QObject(parent), _settingsName(settingsName), _programName(programName) +{ + _filesMenu = new QMenu(tr("Recent files")); + for (int i = 0; i < _maxFiles; i++) + { + _fileActions[i] = new QAction(this); + _fileActions[i]->setVisible(false); + connect(_fileActions[i], SIGNAL(triggered()), parent, slot); + _filesMenu->addAction(_fileActions[i]); + } + updateRecentFileActions(); +} + +RecentFiles::~RecentFiles() +{ + delete _filesMenu; +} + +QMenu* RecentFiles::menu() +{ + return _filesMenu; +} +void RecentFiles::setCurrentFile( const QString& filename ) +{ + _currentFile = filename; + + QSettings settings("UFZ", _programName); + QStringList files = settings.value(_settingsName).toStringList(); + files.removeAll(filename); + files.prepend(filename); + while (files.size() > _maxFiles) + files.removeLast(); + + settings.setValue("recentFileList", files); + + updateRecentFileActions(); +} +void RecentFiles::updateRecentFileActions() +{ + QSettings settings("UFZ", _programName); + QStringList files = settings.value(_settingsName).toStringList(); + + int numFiles = qMin(files.size(), (int)_maxFiles); + + for (int i = 0; i < numFiles; ++i) + { + QString text = tr("&%1 %2").arg(i + 1).arg(strippedName(files[i])); + _fileActions[i]->setText(text); + _fileActions[i]->setData(files[i]); + _fileActions[i]->setVisible(true); + } + + for (int i = numFiles; i < _maxFiles; ++i) + _fileActions[i]->setVisible(false); +} + +QString RecentFiles::strippedName( const QString& fullFileName ) +{ + return QFileInfo(fullFileName).fileName(); +} diff --git a/Gui/Base/RecentFiles.h b/Gui/Base/RecentFiles.h new file mode 100644 index 0000000000000000000000000000000000000000..01281edbaa9d344baaa0d7fdfa66fa63f0771326 --- /dev/null +++ b/Gui/Base/RecentFiles.h @@ -0,0 +1,72 @@ +/** + * \file RecentFiles.h + * 5/11/2009 LB Initial implementation + * + */ + +#ifndef RECENTFILES_H +#define RECENTFILES_H + +// ** INCLUDES ** +#include <QAction> +#include <QMenu> +#include <QObject> + +class QString; + +/** + * The RecentFiles class provides functionality to store informations about + * recently used files (e.g. loaded or saved files). + * Example Usage: + * \code RecentFiles* recentFiles = new RecentFiles(this, SLOT(openRecentFile()), "recentFileList", "OpenGeoSys-5"); + * connect(this, SIGNAL(fileUsed(QString)), recentFiles, SLOT(setCurrentFile(QString))); + * menu_File->addMenu( recentFiles->menu() ); \endcode + * with: + * \code void MainWindow::openRecentFile() + * { + * QAction* action = qobject_cast<QAction*>(sender()); + * if (action) + * loadFile(action->data().toString()); + * } \endcode + */ +class RecentFiles : public QObject +{ + Q_OBJECT + +public: + /** + * Constructor. Example Usage: + * \code RecentFiles recentFiles = new RecentFiles(this, SLOT(mySlot(QString)), "recentFileList"); \endcode + * \param parent The parent object. Normally the QMainWindow instance + * \param slot A slot on parent which is called when a recent file is clicked. + * Use this with Qts SLOT() macro! + * \param settingsName The setting key + * \param programName The name of the program. QSettings of one program + * should be stored with the same keys: QSettings("UFZ", programName) + */ + RecentFiles(QObject* parent, const char* slot, QString settingsName, QString programName); + ~RecentFiles(); + + /// Returns the created menu. Add this menu to your QMainWindow menu. + QMenu* menu(); + +public slots: + /// Should be called from the application when a file was used. + void setCurrentFile(const QString& filename); + +private: + /// Updates the recent files list and writes it to the settings. + void updateRecentFileActions(); + + /// Returns the filename from a full file path. + QString strippedName(const QString& fullFileName); + + QMenu* _filesMenu; + QString _currentFile; + QString _settingsName; + QString _programName; + enum { _maxFiles = 5 }; + QAction* _fileActions[_maxFiles]; +}; + +#endif // RECENTFILES_H diff --git a/Gui/Base/StrictDoubleValidator.h b/Gui/Base/StrictDoubleValidator.h new file mode 100644 index 0000000000000000000000000000000000000000..1b845ff813c34fd44499df759b59657be5c4b24d --- /dev/null +++ b/Gui/Base/StrictDoubleValidator.h @@ -0,0 +1,33 @@ +/* + * StrictDoubleValidator.h + * + * Created on: Jan 24, 2011 + * Author: TF + */ + +#ifndef STRICTDOUBLEVALIDATOR_H_ +#define STRICTDOUBLEVALIDATOR_H_ + +// source code adapted from: +// http://developer.qt.nokia.com/faq/answer/i_can_still_insert_numbers_outside_the_range_specified_with_a_qdoublevalida + +#include <QDoubleValidator> + +class StrictDoubleValidator : public QDoubleValidator +{ +public: + StrictDoubleValidator ( double min, double max, size_t decimals, QObject* parent = 0) : + QDoubleValidator( min, max, decimals, parent) + {} + + QValidator::State validate(QString & input, int &pos) const + { + if (input.isEmpty() || input == ".") return Intermediate; + + if (QDoubleValidator::validate(input, pos) != Acceptable) + return Invalid; + return Acceptable; + } +}; + +#endif /* STRICTDOUBLEVALIDATOR_H_ */ diff --git a/Gui/Base/StrictIntValidator.h b/Gui/Base/StrictIntValidator.h new file mode 100644 index 0000000000000000000000000000000000000000..ad7533b1aded04ffe7b19bbf656c358d2dbe75cf --- /dev/null +++ b/Gui/Base/StrictIntValidator.h @@ -0,0 +1,33 @@ +/* + * StrictIntValidator.h + * + * Created on: Jan 24, 2011 + * Author: TF + */ + +#ifndef STRICTINTVALIDATOR_H_ +#define STRICTINTVALIDATOR_H_ + +// source code adapted from: +// http://developer.qt.nokia.com/faq/answer/i_can_still_insert_numbers_outside_the_range_specified_with_a_qdoublevalida + +#include <QIntValidator> + +class StrictIntValidator : public QIntValidator +{ +public: + StrictIntValidator ( int min, int max, QObject* parent = 0) : + QIntValidator( min, max, parent) + {} + + QValidator::State validate(QString & input, int &pos) const + { + if (input.isEmpty()) return Intermediate; + + if (QIntValidator::validate(input, pos) != Acceptable) + return Invalid; + return Acceptable; + } +}; + +#endif /* STRICTINTVALIDATOR_H_ */ diff --git a/Gui/Base/TreeItem.cpp b/Gui/Base/TreeItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0182de58ae57ef89dbf071675b5c7d7904b8a6d4 --- /dev/null +++ b/Gui/Base/TreeItem.cpp @@ -0,0 +1,115 @@ +/** + * \file TreeItem.cpp + * KR Initial implementation + */ + +#include "TreeItem.h" + +/** + * The constructor is only used to record the item's parent + * and the data associated with each column. + */ +TreeItem::TreeItem(const QList<QVariant> &data, TreeItem* parent) +: _itemData(data), _parentItem(parent) +{ +} + +/** + * A pointer to each of the child items belonging to this item + * will be stored in the _childItems private member variable. When + * the class's destructor is called, it must delete each of these + * to ensure that their memory is reused. + */ +TreeItem::~TreeItem() +{ + qDeleteAll(_childItems); +} + +/** + * Add a child to the tree item + */ +void TreeItem::appendChild(TreeItem* item) +{ + _childItems.append(item); +} + +/** + * Returns the child that corresponds to the specified row number + * in the item's list of child items + * Returns NULL if that child does not exist. + */ +TreeItem* TreeItem::child(int row) const +{ + if (_childItems.count() > row) + return _childItems.value(row); + else + return NULL; +} + +/** + * Returns the number of _childItems + */ +int TreeItem::childCount() const +{ + return _childItems.count(); +} + +/** + * Returns the item's location within its parent's list of items. + */ +int TreeItem::row() const +{ + if (_parentItem) + return _parentItem->_childItems.indexOf(const_cast<TreeItem*>(this)); + + return 0; +} + +/** + * Returns the number of columns of data in the item. + */ +int TreeItem::columnCount() const +{ + return _itemData.count(); +} + +/** + * Returns the data from all the columns. + */ +QVariant TreeItem::data(int column) const +{ + return _itemData.value(column); +} + +/** + * Sets the data at a given column. + */ +bool TreeItem::setData( int column, const QVariant &value ) +{ + if (column < 0 || column >= _itemData.size()) + return false; + + _itemData[column] = value; + return true; +} +/** + * Returns the parent object of the tree item. + */ +TreeItem* TreeItem::parentItem() const +{ + return _parentItem; +} + +/** + * Removes a number of children of the TreeItem starting from the given position. + */ +bool TreeItem::removeChildren(int position, int count) +{ + if (position < 0 || position + count > _childItems.size()) + return false; + + for (int row = 0; row < count; ++row) + delete _childItems.takeAt(position); + + return true; +} diff --git a/Gui/Base/TreeItem.h b/Gui/Base/TreeItem.h new file mode 100644 index 0000000000000000000000000000000000000000..4fd9d18e72bc4273d3bd588769fc1e8fbceac775 --- /dev/null +++ b/Gui/Base/TreeItem.h @@ -0,0 +1,41 @@ +/** + * \file TreeItem.h + * KR Initial implementation + */ + +#ifndef QTREEITEM_H +#define QTREEITEM_H + +#include <QList> +#include <QVariant> + +/** + * \brief Objects nodes for the TreeModel. + * + * The TreeItem class provides simple items that contain several pieces of data, + * and which can provide information about their parent and child items + * \sa TreeModel + */ +class TreeItem +{ +public: + TreeItem(const QList<QVariant> &data, TreeItem* parent); + virtual ~TreeItem(); + + void appendChild(TreeItem* child); + TreeItem* child(int row) const; + virtual int childCount() const; + virtual int columnCount() const; + virtual QVariant data(int column) const; + virtual bool setData(int column, const QVariant &value); + int row() const; + TreeItem* parentItem() const; + bool removeChildren(int position, int count); + +private: + QList<TreeItem*> _childItems; + QList<QVariant> _itemData; + TreeItem* _parentItem; +}; + +#endif //QTREEITEM_H diff --git a/Gui/Base/TreeModel.cpp b/Gui/Base/TreeModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f25f944c3e70051df5161241e083483d3b078cc --- /dev/null +++ b/Gui/Base/TreeModel.cpp @@ -0,0 +1,249 @@ +/** + * \file TreeModel.cpp + * KR Initial implementation + */ + +#include "TreeModel.h" + +#include "TreeItem.h" + +#include <QModelIndex> +#include <QStringList> +#include <QVariant> + +/** + * A model for the QTreeView implementing the tree as a double-linked list. + */ +TreeModel::TreeModel( QObject* parent ) + : QAbstractItemModel(parent) +{ + //_modelType = TREE_MODEL; + QList<QVariant> rootData; + rootData << "1" << "2" << "3"; + _rootItem = new TreeItem(rootData, NULL); + //setupModelData(data, _rootItem); +} + +TreeModel::~TreeModel() +{ + delete _rootItem; +} + +/** + * Returns the index of a TreeItem given its parent and position. + * It is first checked if the model index is valid. If it is not, it is assumed that a + * top-level item is being referred to; otherwise, the data pointer from the model + * index is obtained with its internalPointer() function and is used to reference a + * TreeItem object + * \param row Row of the tree object + * \param column Column of the tree object + * \param parent Index of the parent object + */ +QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + TreeItem* parentItem; + + if (!parent.isValid()) + parentItem = _rootItem; + else + parentItem = static_cast<TreeItem*>(parent.internalPointer()); + + TreeItem* childItem = parentItem->child(row); + if (childItem) + return createIndex(row, column, childItem); + else + return QModelIndex(); +} + +/** + * Returns the model index of a TreeItem based on its index. + */ +QModelIndex TreeModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + TreeItem* childItem = static_cast<TreeItem*>(index.internalPointer()); + TreeItem* parentItem = childItem->parentItem(); + + if (parentItem == _rootItem) + return QModelIndex(); + + return createIndex(parentItem->row(), 0, parentItem); +} + +/** + * Returns the number of child items for the TreeItem that corresponds to a given + * model index, or the number of top-level items if an invalid index is specified. + */ +int TreeModel::rowCount(const QModelIndex &parent) const +{ + TreeItem* parentItem; + if (parent.column() > 0) + return 0; + + if (!parent.isValid()) + parentItem = _rootItem; + else + parentItem = static_cast<TreeItem*>(parent.internalPointer()); + + return parentItem->childCount(); +} + +/** + * Determines how many columns are present for a given model index. + */ +int TreeModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return static_cast<TreeItem*>(parent.internalPointer())->columnCount(); + else + return _rootItem->columnCount(); +} + +void TreeModel::updateData() +{ +} +/** + * Since each item manages its own columns, the column number is used to retrieve + * the data with the TreeItem::data() function + */ +QVariant TreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::EditRole || role == Qt::DisplayRole) + { + TreeItem* item = static_cast<TreeItem*>(index.internalPointer()); + + return item->data(index.column()); + } + + return QVariant(); +} + +bool TreeModel::setData( const QModelIndex &index, const QVariant &value, int role /* = Qt::EditRole */ ) +{ + if (!index.isValid()) + return false; + + if (role == Qt::EditRole) + { + TreeItem* item = static_cast<TreeItem*>(index.internalPointer()); + item->setData(index.column(), value); + return true; + } + return false; +} +Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; +} + +/** + * Returns the Item characterized by the given index. + */ +TreeItem* TreeModel::getItem(const QModelIndex &index) const +{ + if (index.isValid()) + { + TreeItem* item = static_cast<TreeItem*>(index.internalPointer()); + if (item) + return item; + } + return _rootItem; +} + +QVariant TreeModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole) + return _rootItem->data(section); + + return QVariant(); +} + +/** + * Removes item from the model. + */ +bool TreeModel::removeRows(int position, int count, const QModelIndex & parent) +{ + TreeItem* parentItem = getItem(parent); + bool success = true; + + beginRemoveRows(parent, position, position + count - 1); + success = parentItem->removeChildren(position, count); + endRemoveRows(); + + return success; +} + +/** + * Test method for creating a tree model + */ +void TreeModel::setupModelData(const QStringList &lines, TreeItem* parent) +{ + QList<TreeItem*> parents; + QList<int> indentations; + parents << parent; + indentations << 0; + + int number = 0; + + while (number < lines.count()) + { + int position = 0; + while (position < lines[number].length()) + { + if (lines[number].mid(position, 1) != " ") + break; + position++; + } + + QString lineData = lines[number].mid(position).trimmed(); + + if (!lineData.isEmpty()) + { + // Read the column data from the rest of the line. + QStringList columnStrings = lineData.split("\t", QString::SkipEmptyParts); + QList<QVariant> columnData; + for (int column = 0; column < columnStrings.count(); ++column) + columnData << columnStrings[column]; + + if (position > indentations.last()) + { + // The last child of the current parent is now the new parent + // unless the current parent has no children. + + if (parents.last()->childCount() > 0) + { + parents << parents.last()->child(parents.last()->childCount( + ) - 1); + indentations << position; + } + } + else + while (position < indentations.last() && parents.count() > 0) + { + parents.pop_back(); + indentations.pop_back(); + } + + // Append a new item to the current parent's list of children. + parents.last()->appendChild(new TreeItem(columnData, parents.last())); + } + + number++; + } +} + +TreeItem* TreeModel::rootItem() const +{ + return _rootItem; +} diff --git a/Gui/Base/TreeModel.h b/Gui/Base/TreeModel.h new file mode 100644 index 0000000000000000000000000000000000000000..32d36ee8d233f6730d9c5e97b9b5cc4af1ac75c5 --- /dev/null +++ b/Gui/Base/TreeModel.h @@ -0,0 +1,53 @@ +/** + * \file TreeModel.cpp + * KR Initial implementation + */ + +#ifndef QTREEMODEL_H +#define QTREEMODEL_H + +#include <QAbstractItemModel> + +class QVariant; +class QModelIndex; +class TreeItem; + +/** + * \brief A hierarchical model for a tree implemented as a double-linked list + * + * A hierarchical model for the pre-defined QTreeView included in QT. The tree as implemented + * as a double-linked list. + */ +class TreeModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + TreeModel(QObject* parent = 0); + virtual ~TreeModel(); + + QVariant data(const QModelIndex &index, int role) const; + bool setData(const QModelIndex &index, const QVariant &value, int role /* = Qt::EditRole */); + Qt::ItemFlags flags(const QModelIndex &index) const; + TreeItem* getItem(const QModelIndex &index) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = + Qt::DisplayRole) const; + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + QModelIndex parent(const QModelIndex &index) const; + bool removeRows(int row, int count, const QModelIndex & parent); + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + + TreeItem* rootItem() const; + +public slots: + void updateData(); + +protected: + TreeItem* _rootItem; + +private: + void setupModelData(const QStringList &lines, TreeItem* parent); +}; + +#endif //QTREEMODEL_H diff --git a/Gui/Base/TreeModelIterator.cpp b/Gui/Base/TreeModelIterator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9e36bb3616e8ca48afa748661fd33d67ed669c26 --- /dev/null +++ b/Gui/Base/TreeModelIterator.cpp @@ -0,0 +1,71 @@ +/** + * \file TreeModelIterator.cpp + * 23/6/2010 LB Initial implementation + * + * Implementation of TreeModelIterator + */ + +// ** INCLUDES ** +#include "TreeModelIterator.h" + +#include "TreeItem.h" +#include "TreeModel.h" + +TreeModelIterator::TreeModelIterator( TreeModel* model ) + : _current(NULL), _model(model) +{ + if (_model->rootItem()->childCount() > 0) + { + _current = _model->rootItem(); + next(_current); + //_parentIndex.push(0); + //_currentIndex = 0; + } +} + +TreeItem* TreeModelIterator::operator*() const +{ + return _current; +} + +TreeModelIterator& TreeModelIterator::operator++() +{ + if (_current) + _current = next(_current); + + return *this; +} + +TreeItem* TreeModelIterator::next( const TreeItem* current ) +{ + if (!current) + return NULL; + + TreeItem* next = NULL; + if (current->childCount()) + { + // walk the child + _parentIndex.push(_currentIndex); + _currentIndex = 0; + next = current->child(0); + } + else + { + // walk the sibling + TreeItem* parent = current->parentItem(); + next = parent ? parent->child(_currentIndex + 1) + : _model->rootItem()->child(_currentIndex + 1); + while (!next && parent) + { + // if we had no sibling walk up the parent + // and try the sibling of that + parent = parent->parentItem(); + _currentIndex = _parentIndex.pop(); + next = parent ? parent->child(_currentIndex + 1) + : _model->rootItem()->child(_currentIndex + 1); + } + if (next) + ++(_currentIndex); + } + return next; +} diff --git a/Gui/Base/TreeModelIterator.h b/Gui/Base/TreeModelIterator.h new file mode 100644 index 0000000000000000000000000000000000000000..b8d8a9cc80d48a2d19382c0c0d14435fb21cedbc --- /dev/null +++ b/Gui/Base/TreeModelIterator.h @@ -0,0 +1,57 @@ +/** + * \file TreeModelIterator.h + * 23/6/2010 LB Initial implementation + * + */ + +#ifndef TREEMODELITERATOR_H +#define TREEMODELITERATOR_H + +// ** INCLUDES ** +#include <QStack> + +class TreeModel; +class TreeItem; + +/** + * \brief TreeModelIterator provides a way to iterate over TreeItems in a TreeModel. + * Usage: \code + * TreeModelIterator it(model); + * while(*it) + * { + * QVariant var = (*it)->data(0); + * std::cout << var.toString().toStdString() << std::endl; + * ++it; + * } \endcode + */ +class TreeModelIterator +{ +public: + /// \brief Constructor. Provide a tree model to iterate over. + TreeModelIterator(TreeModel* model); + + /// \brief Dereferencing the iterator to retrieve the current TreeItem. + /// Returns NULL if the iterator is at the end. + TreeItem* operator* () const; + + /// \brief Advance the iterator to the next TreeItem. + TreeModelIterator& operator++ (); + +private: + /// \brief The current TreeItem. + TreeItem* _current; + + /// \brief The current child index. + int _currentIndex; + + /// \brief Stack to save the child indices of the parent TreeItems. + QStack<int> _parentIndex; + + /// \brief The model to iterate over. + TreeModel* _model; + + /// \brief The traversal implementation. + TreeItem* next(const TreeItem* current); +}; + +#endif // TREEMODELITERATOR_H diff --git a/Gui/Base/modeltest.cpp b/Gui/Base/modeltest.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a43db8aa557dd72412a5fe8be1cbcef2165c56d0 --- /dev/null +++ b/Gui/Base/modeltest.cpp @@ -0,0 +1,542 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Concurrent project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include <QtGui/QtGui> + +#include "modeltest.h" + +Q_DECLARE_METATYPE(QModelIndex) + +/*! + Connect to all of the models signals. Whenever anything happens recheck everything. + */ +ModelTest::ModelTest(QAbstractItemModel* _model, + QObject* parent) : QObject(parent), model(_model), fetchingMore(false) +{ + Q_ASSERT(model); + + connect(model, SIGNAL(columnsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(columnsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(columnsInserted(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(columnsRemoved(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(headerDataChanged(Qt::Orientation, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(layoutAboutToBeChanged ()), this, SLOT(runAllTests())); + connect(model, SIGNAL(layoutChanged ()), this, SLOT(runAllTests())); + connect(model, SIGNAL(modelReset ()), this, SLOT(runAllTests())); + connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(runAllTests())); + + // Special checks for inserting/removing + connect(model, SIGNAL(layoutAboutToBeChanged()), + this, SLOT(layoutAboutToBeChanged())); + connect(model, SIGNAL(layoutChanged()), + this, SLOT(layoutChanged())); + + connect(model, SIGNAL(rowsAboutToBeInserted(const QModelIndex &, int, int)), + this, SLOT(rowsAboutToBeInserted(const QModelIndex &, int, int))); + connect(model, SIGNAL(rowsAboutToBeRemoved(const QModelIndex &, int, int)), + this, SLOT(rowsAboutToBeRemoved(const QModelIndex &, int, int))); + connect(model, SIGNAL(rowsInserted(const QModelIndex &, int, int)), + this, SLOT(rowsInserted(const QModelIndex &, int, int))); + connect(model, SIGNAL(rowsRemoved(const QModelIndex &, int, int)), + this, SLOT(rowsRemoved(const QModelIndex &, int, int))); + + runAllTests(); +} + +void ModelTest::runAllTests() +{ + if (fetchingMore) + return; + nonDestructiveBasicTest(); + rowCount(); + columnCount(); + hasIndex(); + index(); + parent(); + data(); +} + +/*! + nonDestructiveBasicTest tries to call a number of the basic functions (not all) + to make sure the model doesn't outright segfault, testing the functions that makes sense. + */ +void ModelTest::nonDestructiveBasicTest() +{ + Q_ASSERT(model->buddy(QModelIndex()) == QModelIndex()); + model->canFetchMore(QModelIndex()); + Q_ASSERT(model->columnCount(QModelIndex()) >= 0); + Q_ASSERT(model->data(QModelIndex()) == QVariant()); + fetchingMore = true; + model->fetchMore(QModelIndex()); + fetchingMore = false; + Qt::ItemFlags flags = model->flags(QModelIndex()); + Q_ASSERT(flags == Qt::ItemIsDropEnabled || flags == 0); + model->hasChildren(QModelIndex()); + model->hasIndex(0, 0); + model->headerData(0, Qt::Horizontal); + model->index(0, 0); + Q_ASSERT(model->index(-1, -1) == QModelIndex()); + model->itemData(QModelIndex()); + QVariant cache; + model->match(QModelIndex(), -1, cache); + model->mimeTypes(); + Q_ASSERT(model->parent(QModelIndex()) == QModelIndex()); + Q_ASSERT(model->rowCount() >= 0); + QVariant variant; + model->setData(QModelIndex(), variant, -1); + model->setHeaderData(-1, Qt::Horizontal, QVariant()); + model->setHeaderData(0, Qt::Horizontal, QVariant()); + model->setHeaderData(999999, Qt::Horizontal, QVariant()); + QMap<int, QVariant> roles; + model->sibling(0, 0, QModelIndex()); + model->span(QModelIndex()); + model->supportedDropActions(); +} + +/*! + Tests model's implementation of QAbstractItemModel::rowCount() and hasChildren() + + Models that are dynamically populated are not as fully tested here. + */ +void ModelTest::rowCount() +{ + // check top row + QModelIndex topIndex = model->index(0, 0, QModelIndex()); + int rows = model->rowCount(topIndex); + Q_ASSERT(rows >= 0); + if (rows > 0) + Q_ASSERT(model->hasChildren(topIndex) == true); + + QModelIndex secondLevelIndex = model->index(0, 0, topIndex); + if (secondLevelIndex.isValid()) // not the top level + { // check a row count where parent is valid + rows = model->rowCount(secondLevelIndex); + Q_ASSERT(rows >= 0); + if (rows > 0) + Q_ASSERT(model->hasChildren(secondLevelIndex) == true); + } + + // The models rowCount() is tested more extensively in checkChildren(), + // but this catches the big mistakes +} + +/*! + Tests model's implementation of QAbstractItemModel::columnCount() and hasChildren() + */ +void ModelTest::columnCount() +{ + // check top row + QModelIndex topIndex = model->index(0, 0, QModelIndex()); + Q_ASSERT(model->columnCount(topIndex) >= 0); + + // check a column count where parent is valid + QModelIndex childIndex = model->index(0, 0, topIndex); + if (childIndex.isValid()) + Q_ASSERT(model->columnCount(childIndex) >= 0); + + // columnCount() is tested more extensively in checkChildren(), + // but this catches the big mistakes +} + +/*! + Tests model's implementation of QAbstractItemModel::hasIndex() + */ +void ModelTest::hasIndex() +{ + // Make sure that invalid values returns an invalid index + Q_ASSERT(model->hasIndex(-2, -2) == false); + Q_ASSERT(model->hasIndex(-2, 0) == false); + Q_ASSERT(model->hasIndex(0, -2) == false); + + int rows = model->rowCount(); + int columns = model->columnCount(); + + // check out of bounds + Q_ASSERT(model->hasIndex(rows, columns) == false); + Q_ASSERT(model->hasIndex(rows + 1, columns + 1) == false); + + if (rows > 0) + Q_ASSERT(model->hasIndex(0, 0) == true); + + // hasIndex() is tested more extensively in checkChildren(), + // but this catches the big mistakes +} + +/*! + Tests model's implementation of QAbstractItemModel::index() + */ +void ModelTest::index() +{ + // Make sure that invalid values returns an invalid index + Q_ASSERT(model->index(-2, -2) == QModelIndex()); + Q_ASSERT(model->index(-2, 0) == QModelIndex()); + Q_ASSERT(model->index(0, -2) == QModelIndex()); + + int rows = model->rowCount(); + int columns = model->columnCount(); + + if (rows == 0) + return; + + // Catch off by one errors + Q_ASSERT(model->index(rows, columns) == QModelIndex()); + Q_ASSERT(model->index(0, 0).isValid() == true); + + // Make sure that the same index is *always* returned + QModelIndex a = model->index(0, 0); + QModelIndex b = model->index(0, 0); + Q_ASSERT(a == b); + + // index() is tested more extensively in checkChildren(), + // but this catches the big mistakes +} + +/*! + Tests model's implementation of QAbstractItemModel::parent() + */ +void ModelTest::parent() +{ + // Make sure the model wont crash and will return an invalid QModelIndex + // when asked for the parent of an invalid index. + Q_ASSERT(model->parent(QModelIndex()) == QModelIndex()); + + if (model->rowCount() == 0) + return; + + // Column 0 | Column 1 | + // QModelIndex() | | + // \- topIndex | topIndex1 | + // \- childIndex | childIndex1 | + + // Common error test #1, make sure that a top level index has a parent + // that is a invalid QModelIndex. + QModelIndex topIndex = model->index(0, 0, QModelIndex()); + Q_ASSERT(model->parent(topIndex) == QModelIndex()); + + // Common error test #2, make sure that a second level index has a parent + // that is the first level index. + if (model->rowCount(topIndex) > 0) + { + QModelIndex childIndex = model->index(0, 0, topIndex); + Q_ASSERT(model->parent(childIndex) == topIndex); + } + + // Common error test #3, the second column should NOT have the same children + // as the first column in a row. + // Usually the second column shouldn't have children. + QModelIndex topIndex1 = model->index(0, 1, QModelIndex()); + if (model->rowCount(topIndex1) > 0) + { + QModelIndex childIndex = model->index(0, 0, topIndex); + QModelIndex childIndex1 = model->index(0, 0, topIndex1); + Q_ASSERT(childIndex != childIndex1); + } + + // Full test, walk n levels deep through the model making sure that all + // parent's children correctly specify their parent. + checkChildren(QModelIndex()); +} + +/*! + Called from the parent() test. + + A model that returns an index of parent X should also return X when asking + for the parent of the index. + + This recursive function does pretty extensive testing on the whole model in an + effort to catch edge cases. + + This function assumes that rowCount(), columnCount() and index() already work. + If they have a bug it will point it out, but the above tests should have already + found the basic bugs because it is easier to figure out the problem in + those tests then this one. + */ +void ModelTest::checkChildren(const QModelIndex &parent, int currentDepth) +{ + // First just try walking back up the tree. + QModelIndex p = parent; + while (p.isValid()) + p = p.parent(); + + // For models that are dynamically populated + if (model->canFetchMore(parent)) + { + fetchingMore = true; + model->fetchMore(parent); + fetchingMore = false; + } + + int rows = model->rowCount(parent); + int columns = model->columnCount(parent); + + if (rows > 0) + Q_ASSERT(model->hasChildren(parent)); + + // Some further testing against rows(), columns(), and hasChildren() + Q_ASSERT(rows >= 0); + Q_ASSERT(columns >= 0); + if (rows > 0) + Q_ASSERT(model->hasChildren(parent) == true); + + //qDebug() << "parent:" << model->data(parent).toString() << "rows:" << rows + // << "columns:" << columns << "parent column:" << parent.column(); + + Q_ASSERT(model->hasIndex(rows + 1, 0, parent) == false); + for (int r = 0; r < rows; ++r) + { + if (model->canFetchMore(parent)) + { + fetchingMore = true; + model->fetchMore(parent); + fetchingMore = false; + } + Q_ASSERT(model->hasIndex(r, columns + 1, parent) == false); + for (int c = 0; c < columns; ++c) + { + Q_ASSERT(model->hasIndex(r, c, parent) == true); + QModelIndex index = model->index(r, c, parent); + // rowCount() and columnCount() said that it existed... + Q_ASSERT(index.isValid() == true); + + // index() should always return the same index when called twice in a row + QModelIndex modifiedIndex = model->index(r, c, parent); + Q_ASSERT(index == modifiedIndex); + + // Make sure we get the same index if we request it twice in a row + QModelIndex a = model->index(r, c, parent); + QModelIndex b = model->index(r, c, parent); + Q_ASSERT(a == b); + + // Some basic checking on the index that is returned + Q_ASSERT(index.model() == model); + Q_ASSERT(index.row() == r); + Q_ASSERT(index.column() == c); + // While you can technically return a QVariant usually this is a sign + // of an bug in data() Disable if this really is ok in your model. + //Q_ASSERT(model->data(index, Qt::DisplayRole).isValid() == true); + + // If the next test fails here is some somewhat useful debug you play with. + /* + if (model->parent(index) != parent) { + qDebug() << r << c << currentDepth << model->data(index).toString() + << model->data(parent).toString(); + qDebug() << index << parent << model->parent(index); + // And a view that you can even use to show the model. + //QTreeView view; + //view.setModel(model); + //view.show(); + }*/ + + // Check that we can get back our real parent. + QModelIndex p = model->parent(index); + //qDebug() << "child:" << index; + //qDebug() << p; + //qDebug() << parent; + Q_ASSERT(model->parent(index) == parent); + + // recursively go down the children + if (model->hasChildren(index) && currentDepth < 10 ) + //qDebug() << r << c << "has children" << model->rowCount(index); + checkChildren(index, ++currentDepth); + /* else { if (currentDepth >= 10) qDebug() << "checked 10 deep"; };*/ + + // make sure that after testing the children that the index doesn't change. + QModelIndex newerIndex = model->index(r, c, parent); + Q_ASSERT(index == newerIndex); + } + } +} + +/*! + Tests model's implementation of QAbstractItemModel::data() + */ +void ModelTest::data() +{ + // Invalid index should return an invalid qvariant + Q_ASSERT(!model->data(QModelIndex()).isValid()); + + if (model->rowCount() == 0) + return; + + // A valid index should have a valid QVariant data + Q_ASSERT(model->index(0, 0).isValid()); + + // shouldn't be able to set data on an invalid index + Q_ASSERT(model->setData(QModelIndex(), QLatin1String("foo"), Qt::DisplayRole) == false); + + // General Purpose roles that should return a QString + QVariant variant = model->data(model->index(0, 0), Qt::ToolTipRole); + if (variant.isValid()) + Q_ASSERT(qVariantCanConvert<QString>(variant)); + variant = model->data(model->index(0, 0), Qt::StatusTipRole); + if (variant.isValid()) + Q_ASSERT(qVariantCanConvert<QString>(variant)); + variant = model->data(model->index(0, 0), Qt::WhatsThisRole); + if (variant.isValid()) + Q_ASSERT(qVariantCanConvert<QString>(variant)); + + // General Purpose roles that should return a QSize + variant = model->data(model->index(0, 0), Qt::SizeHintRole); + if (variant.isValid()) + Q_ASSERT(qVariantCanConvert<QSize>(variant)); + + // General Purpose roles that should return a QFont + QVariant fontVariant = model->data(model->index(0, 0), Qt::FontRole); + if (fontVariant.isValid()) + Q_ASSERT(qVariantCanConvert<QFont>(fontVariant)); + + // Check that the alignment is one we know about + QVariant textAlignmentVariant = model->data(model->index(0, 0), Qt::TextAlignmentRole); + if (textAlignmentVariant.isValid()) + { + int alignment = textAlignmentVariant.toInt(); + Q_ASSERT(alignment == Qt::AlignLeft || + alignment == Qt::AlignRight || + alignment == Qt::AlignHCenter || + alignment == Qt::AlignJustify || + alignment == Qt::AlignTop || + alignment == Qt::AlignBottom || + alignment == Qt::AlignVCenter || + alignment == Qt::AlignCenter || + alignment == Qt::AlignAbsolute || + alignment == Qt::AlignLeading || + alignment == Qt::AlignTrailing); + } + + // General Purpose roles that should return a QColor + QVariant colorVariant = model->data(model->index(0, 0), Qt::BackgroundColorRole); + if (colorVariant.isValid()) + Q_ASSERT(qVariantCanConvert<QColor>(colorVariant)); + + colorVariant = model->data(model->index(0, 0), Qt::TextColorRole); + if (colorVariant.isValid()) + Q_ASSERT(qVariantCanConvert<QColor>(colorVariant)); + + // Check that the "check state" is one we know about. + QVariant checkStateVariant = model->data(model->index(0, 0), Qt::CheckStateRole); + if (checkStateVariant.isValid()) + { + int state = checkStateVariant.toInt(); + Q_ASSERT(state == Qt::Unchecked || + state == Qt::PartiallyChecked || + state == Qt::Checked); + } +} + +/*! + Store what is about to be inserted to make sure it actually happens + + \sa rowsInserted() + */ +void ModelTest::rowsAboutToBeInserted(const QModelIndex &parent, int start, int end) +{ + Q_UNUSED(end); + Changing c; + c.parent = parent; + c.oldSize = model->rowCount(parent); + c.last = model->data(model->index(start - 1, 0, parent)); + c.next = model->data(model->index(start, 0, parent)); + insert.push(c); +} + +/*! + Confirm that what was said was going to happen actually did + + \sa rowsAboutToBeInserted() + */ +void ModelTest::rowsInserted(const QModelIndex & parent, int start, int end) +{ + Changing c = insert.pop(); + Q_ASSERT(c.parent == parent); + Q_ASSERT(c.oldSize + (end - start + 1) == model->rowCount(parent)); + Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent))); + /* + if (c.next != model->data(model->index(end + 1, 0, c.parent))) { + qDebug() << start << end; + for (int i=0; i < model->rowCount(); ++i) + qDebug() << model->index(i, 0).data().toString(); + qDebug() << c.next << model->data(model->index(end + 1, 0, c.parent)); + } + */ + Q_ASSERT(c.next == model->data(model->index(end + 1, 0, c.parent))); +} + +void ModelTest::layoutAboutToBeChanged() +{ + for (int i = 0; i < qBound(0, model->rowCount(), 100); ++i) + changing.append(QPersistentModelIndex(model->index(i, 0))); +} + +void ModelTest::layoutChanged() +{ + for (int i = 0; i < changing.count(); ++i) + { + QPersistentModelIndex p = changing[i]; + Q_ASSERT(p == model->index(p.row(), p.column(), p.parent())); + } + changing.clear(); +} + +/*! + Store what is about to be inserted to make sure it actually happens + + \sa rowsRemoved() + */ +void ModelTest::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +{ + Changing c; + c.parent = parent; + c.oldSize = model->rowCount(parent); + c.last = model->data(model->index(start - 1, 0, parent)); + c.next = model->data(model->index(end + 1, 0, parent)); + remove.push(c); +} + +/*! + Confirm that what was said was going to happen actually did + + \sa rowsAboutToBeRemoved() + */ +void ModelTest::rowsRemoved(const QModelIndex & parent, int start, int end) +{ + Changing c = remove.pop(); + Q_ASSERT(c.parent == parent); + Q_ASSERT(c.oldSize - (end - start + 1) == model->rowCount(parent)); + Q_ASSERT(c.last == model->data(model->index(start - 1, 0, c.parent))); + Q_ASSERT(c.next == model->data(model->index(start, 0, c.parent))); +} + diff --git a/Gui/Base/modeltest.h b/Gui/Base/modeltest.h new file mode 100644 index 0000000000000000000000000000000000000000..ca72795ff9a9917253e466bfd58fe60429979a04 --- /dev/null +++ b/Gui/Base/modeltest.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2007 Trolltech ASA. All rights reserved. +** +** This file is part of the Qt Concurrent project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.trolltech.com/products/qt/opensource.html +** +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://www.trolltech.com/products/qt/licensing.html or contact the +** sales department at sales@trolltech.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef MODELTEST_H +#define MODELTEST_H + +#include <QtCore/QAbstractItemModel> +#include <QtCore/QObject> +#include <QtCore/QStack> + +class ModelTest : public QObject +{ + Q_OBJECT + +public: + ModelTest(QAbstractItemModel* model, QObject* parent = 0); + +private Q_SLOTS: + void nonDestructiveBasicTest(); + void rowCount(); + void columnCount(); + void hasIndex(); + void index(); + void parent(); + void data(); + +protected Q_SLOTS: + void runAllTests(); + void layoutAboutToBeChanged(); + void layoutChanged(); + void rowsAboutToBeInserted(const QModelIndex &parent, int start, int end); + void rowsInserted(const QModelIndex & parent, int start, int end); + void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end); + void rowsRemoved(const QModelIndex & parent, int start, int end); + +private: + void checkChildren(const QModelIndex &parent, int currentDepth = 0); + + QAbstractItemModel* model; + + struct Changing + { + QModelIndex parent; + int oldSize; + QVariant last; + QVariant next; + }; + QStack<Changing> insert; + QStack<Changing> remove; + + bool fetchingMore; + + QList<QPersistentModelIndex> changing; +}; + +#endif diff --git a/Gui/CMakeLists.txt b/Gui/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..88fdb47082f914fb0058d180b9a41345a6fc8dc1 --- /dev/null +++ b/Gui/CMakeLists.txt @@ -0,0 +1,21 @@ +IF (NOT VTK_FOUND) + MESSAGE(FATAL_ERROR "Error: VTK was not found but is needed for the GUI. Aborting...") +ENDIF (NOT VTK_FOUND) +INCLUDE( ${VTK_USE_FILE} ) + +SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /ZI /Od /Ob0") + +# Add subprojects +ADD_SUBDIRECTORY( Base ) +ADD_SUBDIRECTORY( DataView/StratView ) +ADD_SUBDIRECTORY( DataView ) +ADD_SUBDIRECTORY( DataView/DiagramView ) +ADD_SUBDIRECTORY( VtkVis ) +ADD_SUBDIRECTORY( VtkAct ) +IF (OGS_USE_OPENSG) + ADD_SUBDIRECTORY( OpenSG ) +ENDIF (OGS_USE_OPENSG) +IF(VRPN_FOUND AND OGS_USE_VRPN) + ADD_SUBDIRECTORY( Vrpn ) +ENDIF() +ADD_SUBDIRECTORY( Gui ) diff --git a/Gui/DataExplorer.cmake b/Gui/DataExplorer.cmake new file mode 100644 index 0000000000000000000000000000000000000000..5ea553cc89a8dcb2d147c18bb1e64f2161f3c44a --- /dev/null +++ b/Gui/DataExplorer.cmake @@ -0,0 +1,212 @@ +# Source files +SET( SOURCES + mainwindow.cpp + ${CMAKE_SOURCE_DIR}/UTL/FileConverter/OGSFileConverter/OGSFileConverter.cpp + ${CMAKE_SOURCE_DIR}/UTL/FileConverter/OGSFileConverter/FileListDialog.cpp + ${CMAKE_SOURCE_DIR}/UTL/FileConverter/OGSFileConverter/ConversionTools.cpp +) + +# Moc Header files +SET( MOC_HEADERS + mainwindow.h + ${CMAKE_SOURCE_DIR}/UTL/FileConverter/OGSFileConverter/OGSFileConverter.h + ${CMAKE_SOURCE_DIR}/UTL/FileConverter/OGSFileConverter/FileListDialog.h + ${CMAKE_SOURCE_DIR}/UTL/FileConverter/OGSFileConverter/ConversionTools.h +) + +# Header files +SET( HEADERS + +) + +# UI files +SET( UIS + mainwindow.ui + ${CMAKE_SOURCE_DIR}/UTL/FileConverter/OGSFileConverter/OGSFileConverter.ui + ${CMAKE_SOURCE_DIR}/UTL/FileConverter/OGSFileConverter/FileList.ui +) + + +# Run Qts user interface compiler uic on .ui files +QT4_WRAP_UI( UI_HEADERS ${UIS} ) + +# Run Qts meta object compiler moc on header files +QT4_WRAP_CPP( MOC_SOURCES ${MOC_HEADERS} ) + +INCLUDE( ${VTK_USE_FILE} ) + +# Include the headers which are generated by uic and moc +# and include additional header +INCLUDE_DIRECTORIES( + ${CMAKE_BINARY_DIR}/Qt/Base + ${CMAKE_BINARY_DIR}/Qt/Gui + ${CMAKE_BINARY_DIR}/Qt/DataView + ${CMAKE_BINARY_DIR}/Qt/DataView/StratView + ${CMAKE_BINARY_DIR}/Qt/DataView/DiagramView + ${CMAKE_BINARY_DIR}/Qt/VtkVis + ${CMAKE_BINARY_DIR}/Qt/VtkAct + ${CMAKE_SOURCE_DIR}/Base + ${CMAKE_SOURCE_DIR}/MathLib + ${CMAKE_SOURCE_DIR}/GEO + ${CMAKE_SOURCE_DIR}/FileIO + ${CMAKE_SOURCE_DIR}/MSH + ${CMAKE_SOURCE_DIR}/MSHGEOTOOLS + ${CMAKE_SOURCE_DIR}/FEM + ${CMAKE_SOURCE_DIR}/Qt/Base + ${CMAKE_SOURCE_DIR}/Qt/DataView + ${CMAKE_SOURCE_DIR}/Qt/DataView/StratView + ${CMAKE_SOURCE_DIR}/Qt/DataView/DiagramView + ${CMAKE_SOURCE_DIR}/Qt/VtkVis + ${CMAKE_SOURCE_DIR}/Qt/VtkAct + ${CMAKE_SOURCE_DIR}/UTL/FileConverter/OGSFileConverter +) + +IF (Shapelib_FOUND) + INCLUDE_DIRECTORIES( ${Shapelib_INCLUDE_DIR} ) +ENDIF () # Shapelib_FOUND + +# Put moc files in a project folder +SOURCE_GROUP("UI Files" REGULAR_EXPRESSION "\\w*\\.ui") +SOURCE_GROUP("Moc Files" REGULAR_EXPRESSION "moc_.*") + +# Create the library +ADD_EXECUTABLE( ogs-gui + main.cpp + ${SOURCES} + ${HEADERS} + ${MOC_HEADERS} + ${MOC_SOURCES} + ${UIS} +) + +TARGET_LINK_LIBRARIES( ogs-gui + ${QT_LIBRARIES} + Base + GEO + FileIO + MSH + MSHGEOTOOLS + FEM + OGSProject + QtBase + QtDataView + StratView + VtkVis + VtkAct + vtkRendering + vtkWidgets + QVTK +) + +IF(VTK_NETCDF_FOUND) + TARGET_LINK_LIBRARIES( ogs-gui vtkNetCDF vtkNetCDF_cxx ) +ELSE() + TARGET_LINK_LIBRARIES( ogs-gui ${NETCDF_LIBRARIES} ) +ENDIF() + +IF (Shapelib_FOUND) + TARGET_LINK_LIBRARIES( ogs-gui ${Shapelib_LIBRARIES} ) +ENDIF () # Shapelib_FOUND + +IF (libgeotiff_FOUND) + TARGET_LINK_LIBRARIES( ogs-gui ${libgeotiff_LIBRARIES} ) +ENDIF () # libgeotiff_FOUND + +ADD_DEPENDENCIES ( ogs-gui VtkVis OGSProject ) + +IF(MSVC) + # Set linker flags + SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /NODEFAULTLIB:MSVCRT") +ENDIF(MSVC) + +IF(OGS_BUILD_INFO) + ADD_DEFINITIONS(-DOGS_BUILD_INFO) +ENDIF() # OGS_BUILD_INFO + +### OpenSG support ### +IF (OGS_USE_OPENSG) + USE_OPENSG(ogs-gui) + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Qt/OpenSG ) + TARGET_LINK_LIBRARIES( ogs-gui OgsOpenSG ) +ENDIF (OGS_USE_OPENSG) + +IF(OGS_USE_VRPN) + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Qt/Vrpn ${CMAKE_BINARY_DIR}/Qt/Vrpn ) + TARGET_LINK_LIBRARIES( ogs-gui ${VRPN_LIBRARIES} OgsVrpn ) +ENDIF() + +################### +### VRED plugin ### +################### + +IF (OGS_VRED_PLUGIN) + + ADD_DEFINITIONS( + -DBOOST_PYTHON_DYNAMIC_LIB + ) + + INCLUDE_DIRECTORIES( + #${VRED_DIR}/include/vred + ${VRED_DIR}/include/boost-1.34-vc8.0 + ${VRED_DIR}/include/python-2.52-vc8.0 + #${VRED_DIR}/include/zlib-1.23 + #${VRED_DIR}/include/OpenSG + #${VRED_DIR}/include/OpenSG/OpenSG + ) + LINK_DIRECTORIES( ${VRED_DIR}/bin/WIN32 ) + + ADD_LIBRARY( ogs-gui-vred SHARED + ${SOURCES} + ${HEADERS} + ${MOC_HEADERS} + ${MOC_SOURCES} + ${UIS} + pymainwindow.cpp + ) + TARGET_LINK_LIBRARIES( ogs-gui-vred + ${QT_LIBRARIES} + GEO + FileIO + MSH + FEM + OGSProject + QtBase + QtDataView + StratView + ${Shapelib_LIBRARIES} + ${libgeotiff_LIBRARIES} + VtkVis + VtkAct + #boost_python-vc80-mt-1_34_1 + ) + + ADD_DEPENDENCIES ( ogs-gui-vred VtkVis OGSProject ) +ENDIF (OGS_VRED_PLUGIN) + +#################### +### Installation ### +#################### + +IF (OGS_PACKAGING) + INSTALL (TARGETS ogs-gui RUNTIME DESTINATION bin COMPONENT ogs_gui) + + IF(MSVC) + SET(OGS_GUI_EXE ${OGS_EXECUTABLE}-gui.exe) + ELSE(MSVC) + SET(OGS_GUI_EXE ${OGS_EXECUTABLE}-gui) + ENDIF(MSVC) + + INCLUDE(GetPrerequisites) + if (EXISTS ${OGS_GUI_EXE}) + GET_PREREQUISITES(${OGS_GUI_EXE} OGS_GUI_DEPENDENCIES 1 1 "/usr/local/lib;/;${VTK_DIR};${OpenSG_LIBRARY_DIRS}" "") + MESSAGE (STATUS "ogs-gui depends on:") + FOREACH(DEPENDENCY ${OGS_GUI_DEPENDENCIES}) + IF(NOT ${DEPENDENCY} STREQUAL "not") # Some bug on Linux? + message("${DEPENDENCY}") + GP_RESOLVE_ITEM ("/" "${DEPENDENCY}" ${OGS_GUI_EXE} "/usr/local/lib;/;${VTK_DIR}" DEPENDENCY_PATH) + SET (DEPENDENCY_PATHS ${DEPENDENCY_PATHS} ${DEPENDENCY_PATH}) + ENDIF() + ENDFOREACH (DEPENDENCY IN ${OGS_GUI_DEPENDENCIES}) + INSTALL (FILES ${DEPENDENCY_PATHS} DESTINATION bin COMPONENT ogs_gui) + ENDIF (EXISTS ${OGS_GUI_EXE}) +ENDIF (OGS_PACKAGING) \ No newline at end of file diff --git a/Gui/DataView/BaseItem.h b/Gui/DataView/BaseItem.h new file mode 100644 index 0000000000000000000000000000000000000000..08c4722eb82975f9be44c611691426138644ddff --- /dev/null +++ b/Gui/DataView/BaseItem.h @@ -0,0 +1,57 @@ +/** + * \file BaseItem.h + * 20/01/2010 KR Initial implementation + * + */ +#ifndef BASEITEM_H +#define BASEITEM_H + +#include "Point.h" + +#include "VtkStationSource.h" +#include <QModelIndex> +#include <vtkPolyDataAlgorithm.h> + +/** + * \brief A BaseItem contains additional Information about a subtree in the StationTreeModel. + * + * It is used for list names in the StationTreeModel and it contains the + * vtkObject for visualisation of the whole list in 3D. + */ +class BaseItem +{ +public: + BaseItem(const QString &listName, const std::vector<GEOLIB::Point*>* stations = NULL ) + : _stations(stations), _vtkSource(VtkStationSource::New()) + { + // create the vtk-object for 3d-visualisation of this list + static_cast<VtkStationSource*>(_vtkSource)->setStations(stations); + static_cast<VtkStationSource*>(_vtkSource)->SetName(listName); + } + + ~BaseItem() + { + _vtkSource->Delete(); + } + + /// Returns the associated QModelIndex which belongs to a Qt model + QModelIndex modelIndex() const { return _modelIndex; } + + /// Sets the model index + void setModelIndex( QModelIndex index ) { _modelIndex = index; } + + const std::vector<GEOLIB::Point*>* getStations() { return _stations; } + + /// Returns the Vtk polydata source object + vtkPolyDataAlgorithm* vtkSource() const { return _vtkSource; } + +private: + QModelIndex _modelIndex; + const std::vector<GEOLIB::Point*>* _stations; + + /// The Vtk data source object. This is the starting point for a Vtk data + /// visualization pipeline. + vtkPolyDataAlgorithm* _vtkSource; +}; + +#endif //BASEITEM_H diff --git a/Gui/DataView/CMakeLists.txt b/Gui/DataView/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..edbd1f6634475afcdec3ee44fc92c733d5000ee3 --- /dev/null +++ b/Gui/DataView/CMakeLists.txt @@ -0,0 +1,195 @@ +# Source files +set( SOURCES + ColorTableModel.cpp + ColorTableView.cpp + CondFromRasterDialog.cpp + ConditionWriterDialog.cpp + DatabaseConnection.cpp + DataView.cpp + DBConnectionDialog.cpp + DirectConditionGenerator.cpp + ElementTreeModel.cpp + FEMConditionSetupDialog.cpp + GEOModels.cpp + GeoTabWidget.cpp + GeoTreeModel.cpp + GeoTreeView.cpp + GMSHPrefsDialog.cpp + LinearEditDialog.cpp + LineEditDialog.cpp + ListPropertiesDialog.cpp + ModellingTabWidget.cpp + ModelTreeItem.cpp + MshEditDialog.cpp + MshItem.cpp + MshLayerMapper.cpp + MshModel.cpp + MshQualitySelectionDialog.cpp + MshTabWidget.cpp + NetCdfConfigureDialog.cpp + NewProcessDialog.cpp + ProcessModel.cpp + ProcessView.cpp + QueryResultsDialog.cpp + SelectMeshDialog.cpp + SetNameDialog.cpp + StationTabWidget.cpp + StationTreeModel.cpp + StationTreeView.cpp +) + +# Moc Header files +set( MOC_HEADERS + ColorTableModel.h + ColorTableView.h + CondFromRasterDialog.h + ConditionWriterDialog.h + DatabaseConnection.h + DataView.h + DBConnectionDialog.h + ElementTreeModel.h + FEMConditionSetupDialog.h + GEOModels.h + GeoTabWidget.h + GeoTreeModel.h + GeoTreeView.h + GMSHPrefsDialog.h + LinearEditDialog.h + LineEditDialog.h + ListPropertiesDialog.h + ModellingTabWidget.h + MshEditDialog.h + MshModel.h + MshQualitySelectionDialog.h + MshTabWidget.h + NetCdfConfigureDialog.h + NewProcessDialog.h + ProcessModel.h + ProcessView.h + QueryResultsDialog.h + SelectMeshDialog.h + SetNameDialog.h + StationTabWidget.h + StationTreeModel.h + StationTreeView.h +) + +# Header files +set( HEADERS + BaseItem.h + CondItem.h + DirectConditionGenerator.h + CondObjectListItem.h + GeoObjectListItem.h + GeoTreeItem.h + ModelTreeItem.h + MshItem.h + MshLayerMapper.h + ProcessItem.h +) + +# UI files +set( UIS + CondFromRaster.ui + ConditionWriter.ui + DatabaseResultView.ui + DBConnection.ui + FEMConditionSetup.ui + GeoTabWidgetBase.ui + GMSHPrefs.ui + LinearEdit.ui + LineEdit.ui + ModellingTabWidgetBase.ui + MshEdit.ui + MshQualitySelection.ui + MshTabWidgetBase.ui + NetCdfConfigure.ui + NewProcess.ui + StationTabWidgetBase.ui +) + +IF (Shapelib_FOUND) + SET( SOURCES ${SOURCES} SHPImportDialog.cpp) + SET( MOC_HEADERS ${MOC_HEADERS} SHPImportDialog.h) + INCLUDE_DIRECTORIES( ${Shapelib_INCLUDE_DIR} ) +ENDIF () # Shapelib_FOUND + +# Put filter in a folder +SOURCE_GROUP("Dialog Header Files" REGULAR_EXPRESSION "[.]*Dialog.h") +SOURCE_GROUP("Dialog Source Files" REGULAR_EXPRESSION "[.]*Dialog.cpp") +SOURCE_GROUP("Data Model Header Files" REGULAR_EXPRESSION "[.]*Item.h|[.]*Model.h|[.]*View.h") +SOURCE_GROUP("Data Model Source Files" REGULAR_EXPRESSION "[.]*Item.cpp|[.]*Model.cpp|[.]*View.cpp") + +# Run Qts user interface compiler uic on .ui files +qt4_wrap_ui( UI_HEADERS ${UIS} ) + +# Run Qts meta object compiler moc on header files +qt4_wrap_cpp( MOC_SOURCES ${MOC_HEADERS} ) + + +# Include the headers which are generated by uic and moc +# and include additional header +include_directories( + ${CMAKE_BINARY_DIR}/Qt/Base + ${CMAKE_BINARY_DIR}/Qt/DataView + ${CMAKE_BINARY_DIR}/Qt/DataView/DiagramView + ${CMAKE_BINARY_DIR}/Qt/DataView/StratView + + ${CMAKE_SOURCE_DIR}/Base + ${CMAKE_SOURCE_DIR}/MathLib + ${CMAKE_SOURCE_DIR}/GEO + ${CMAKE_SOURCE_DIR}/MSH + ${CMAKE_SOURCE_DIR}/FEM + ${CMAKE_SOURCE_DIR}/FileIO + ${CMAKE_SOURCE_DIR}/Qt/Base + ${CMAKE_SOURCE_DIR}/Qt/DataView + ${CMAKE_SOURCE_DIR}/Qt/DataView/DiagramView + ${CMAKE_SOURCE_DIR}/Qt/DataView/StratView + ${CMAKE_SOURCE_DIR}/Qt/VtkVis +) + +IF(VRPN_FOUND) + INCLUDE_DIRECTORIES( ../Vrpn ${VRPN_INCLUDE_DIRS} ) +ENDIF() + +IF (OGS_USE_OPENSG) + INCLUDE_DIRECTORIES( ${OpenSG_INCLUDE_DIRS} ) +ENDIF (OGS_USE_OPENSG) + +IF (libgeotiff_FOUND) + INCLUDE_DIRECTORIES( ${libgeotiff_INCLUDE_DIR} ${libgeotiff_INCLUDE_DIR}/libxtiff ${VTK_DIR}/../Utilities/vtktiff ) +ENDIF () # libgeotiff_FOUND + +# Put moc files in a project folder +source_group("UI Files" REGULAR_EXPRESSION "\\w*\\.ui") +source_group("Moc Files" REGULAR_EXPRESSION "moc_.*") + + +# Create the library +add_library( QtDataView STATIC + ${SOURCES} + ${HEADERS} + ${MOC_HEADERS} + ${MOC_SOURCES} + #${UI_HEADERS} + ${UIS} +) + +# Link Qt library +target_link_libraries( QtDataView + ${QT_LIBRARIES} + FEM + FileIO + GEO + MSH + QtBase + DiagramView + StratView +) + +IF (Shapelib_FOUND) + TARGET_LINK_LIBRARIES( QtDataView ${Shapelib_LIBRARIES} ) +ENDIF () # Shapelib_FOUND +IF (libgeotiff_FOUND) + TARGET_LINK_LIBRARIES( QtDataView ${libgeotiff_LIBRARIES} ) +ENDIF () # libgeotiff_FOUND diff --git a/Gui/DataView/ColorTableModel.cpp b/Gui/DataView/ColorTableModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98d5a2c9f82be701a6e9fd19511895f09e4b5fce --- /dev/null +++ b/Gui/DataView/ColorTableModel.cpp @@ -0,0 +1,102 @@ +/** + * \file ColorTableModel.cpp + * 24/9/2009 LB Initial implementation + * 05/05/2010 KR 2d graphic functionality removed and various layout changes + * + * Implementation of PolylinesModel + */ + +#include "ColorTableModel.h" + +ColorTableModel::ColorTableModel( const std::map<std::string, GEOLIB::Color*> &colorLookupTable, + QObject* parent /*= 0*/ ) +{ + Q_UNUSED(parent) + + this->buildTable(colorLookupTable); +} + +ColorTableModel::~ColorTableModel() +{ +} + +int ColorTableModel::columnCount( const QModelIndex& parent /*= QModelIndex()*/ ) const +{ + Q_UNUSED(parent) + + return 2; +} + +QVariant ColorTableModel::headerData( int section, Qt::Orientation orientation, + int role /*= Qt::DisplayRole*/ ) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + { + switch (section) + { + case 0: return "Name"; + case 1: return "Colour"; + default: return QVariant(); + } + } + else + return QString("Row %1").arg(section); +} + +QVariant ColorTableModel::data( const QModelIndex& index, int role ) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= _listOfPairs.size() || index.row() < 0) + return QVariant(); + + if (role == Qt::DisplayRole) + { + QPair<QString, QColor> pair = _listOfPairs.at(index.row()); + + switch (index.column()) + { + case 0: + return pair.first; + case 1: + return pair.second; + default: + return QVariant(); + } + } + return QVariant(); +} + +bool ColorTableModel::buildTable(const std::map<std::string, GEOLIB::Color*> &colorLookupTable) +{ + int count = 0; + beginInsertRows(QModelIndex(), 0, colorLookupTable.size() - 1); + + for (std::map<std::string, GEOLIB::Color*>::const_iterator it = colorLookupTable.begin(); + it != colorLookupTable.end(); ++it) + { + QColor color((*(it->second))[0], (*(it->second))[1], (*(it->second))[2]); + QString name(QString::fromStdString(it->first)); + + /* Saudi Arabia strat names * + if (it->first.compare("1")==0) name="Buweib"; + if (it->first.compare("2")==0) name="Wasia"; + if (it->first.compare("3")==0) name="Aruma"; + if (it->first.compare("4")==0) name="Umm Er Radhuma"; + if (it->first.compare("5")==0) name="Rus"; + if (it->first.compare("6")==0) name="Dammam"; + if (it->first.compare("7")==0) name="Neogene"; + */ + + QPair<QString, QColor> pair(name, color); + _listOfPairs.insert(count++, pair); + } + + endInsertRows(); + return true; +} + diff --git a/Gui/DataView/ColorTableModel.h b/Gui/DataView/ColorTableModel.h new file mode 100644 index 0000000000000000000000000000000000000000..37debb210436ea4320cb3e4a736d320d70462d28 --- /dev/null +++ b/Gui/DataView/ColorTableModel.h @@ -0,0 +1,43 @@ +/** + * \file ColorTableModel.h + * 17/06/2010 KR Initial implementation + */ + +#ifndef COLORTABLEMODEL_H +#define COLORTABLEMODEL_H + +#include "Color.h" +#include <QAbstractTableModel> +#include <QColor> + +/** + * The PolylinesModel is a Qt model which represents Polylines. + */ +class ColorTableModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + ColorTableModel( const std::map<std::string, GEOLIB::Color*> &colorLookupTable, + QObject* parent = 0 ); + ~ColorTableModel(); + + int columnCount(const QModelIndex& parent = QModelIndex()) const; + + QVariant data( const QModelIndex& index, int role ) const; + + int rowCount(const QModelIndex& parent = QModelIndex()) const + { + Q_UNUSED (parent); + return _listOfPairs.size(); + } + + QVariant headerData( int section, Qt::Orientation orientation, + int role /*= Qt::DisplayRole*/ ) const; + +private: + bool buildTable( const std::map<std::string, GEOLIB::Color*> &colorLookupTable ); + + QList< QPair<QString, QColor> > _listOfPairs; +}; +#endif // COLORTABLEMODEL_H diff --git a/Gui/DataView/ColorTableView.cpp b/Gui/DataView/ColorTableView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..aadf9ecabcd9a5143f929d150c19fa3df8aa100e --- /dev/null +++ b/Gui/DataView/ColorTableView.cpp @@ -0,0 +1,45 @@ +/** + * \file ColorTableView.cpp + * 17/06/2010 KR Initial implementation + * + */ + +#include "ColorTableView.h" +#include <QHeaderView> +#include <QPainter> + +ColorTableView::ColorTableView( QWidget* parent /*= 0*/ ) : QTableView(parent) +{ + this->verticalHeader()->hide(); + this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + this->resizeColumnsToContents(); + this->resizeRowsToContents(); +} + +void ColorTableViewDelegate::paint(QPainter* painter, + const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QColor val; + if (index.column() == 1) + { + if (qVariantCanConvert<QColor>(index.data())) + { + val = qVariantValue<QColor>(index.data()); + QBrush brush(val); + painter->fillRect(option.rect, brush); + } + } + else + QItemDelegate::paint(painter, option, index); +} + +QSize ColorTableViewDelegate::sizeHint( const QStyleOptionViewItem &option, + const QModelIndex &index ) const +{ + QSize s = QItemDelegate::sizeHint(option, index); + if( s.isValid() ) + s.setHeight((int)(0.5 * s.height())); + return s; +} + diff --git a/Gui/DataView/ColorTableView.h b/Gui/DataView/ColorTableView.h new file mode 100644 index 0000000000000000000000000000000000000000..4ff1c48ddd4c1fece1631d57f239147c9d810ce1 --- /dev/null +++ b/Gui/DataView/ColorTableView.h @@ -0,0 +1,42 @@ +/** + * \file ColorTableView.h + * 17/06/2010 KR Initial implementation + */ +#ifndef COLORTABLEVIEW_H +#define COLORTABLEVIEW_H + +#include <QItemDelegate> +#include <QTableView> + +/** + * A QTableView to display colour lookup tables. + */ +class ColorTableView : public QTableView +{ + Q_OBJECT + +public: + /// Constructor + ColorTableView(QWidget* parent = 0); +}; + +/** + * A delegate class to manage properties of ColorTableView. + */ +class ColorTableViewDelegate : public QItemDelegate +{ + Q_OBJECT + +public: + /// Constructor + ColorTableViewDelegate(QWidget* parent = 0) : QItemDelegate(parent) {} + + /// Overwrites the paint-method to set user-defined properties instead of the default properties. + void paint(QPainter* painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const; + + QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const; +}; + +#endif // COLORTABLEVIEW_H + diff --git a/Gui/DataView/CondFromRaster.ui b/Gui/DataView/CondFromRaster.ui new file mode 100644 index 0000000000000000000000000000000000000000..44be4ff9166939d0cbe2ef50b03111ca2f471f0d --- /dev/null +++ b/Gui/DataView/CondFromRaster.ui @@ -0,0 +1,241 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>CondFromRaster</class> + <widget class="QDialog" name="CondFromRaster"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>340</width> + <height>230</height> + </rect> + </property> + <property name="windowTitle"> + <string>Create Boundary Conditions from Raster Files</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="meshLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Mesh</string> + </property> + </widget> + </item> + <item row="0" column="1" colspan="3"> + <widget class="QComboBox" name="meshBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="rasterLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Raster</string> + </property> + </widget> + </item> + <item row="4" column="1" colspan="2"> + <widget class="QLineEdit" name="rasterEdit"/> + </item> + <item row="4" column="3"> + <widget class="QPushButton" name="selectButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximumSize"> + <size> + <width>30</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + <item row="7" column="2" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="6" column="0" colspan="4"> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Calculation method</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0" colspan="3"> + <widget class="QRadioButton" name="directButton"> + <property name="minimumSize"> + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Use raster values directly</string> + </property> + </widget> + </item> + <item row="1" column="0" colspan="3"> + <widget class="QRadioButton" name="integrateButton"> + <property name="minimumSize"> + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Integrate over mesh elements</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="scalingLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>50</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>50</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Scaling</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="scalingEdit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>70</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>70</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>(Note: Normalization is 1 / Scaling)</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>CondFromRaster</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>CondFromRaster</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/CondFromRasterDialog.cpp b/Gui/DataView/CondFromRasterDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..babf1d87f4233514c9ab8a7269216eb50f0662cb --- /dev/null +++ b/Gui/DataView/CondFromRasterDialog.cpp @@ -0,0 +1,111 @@ +/** + * \file CondFromRasterDialog.cpp + * 2012/01/04 KR Initial implementation + */ + +#include "CondFromRasterDialog.h" + +#include <QFileDialog> +#include <QSettings> + +#include "DirectConditionGenerator.h" +#include "OGSError.h" +#include "StrictDoubleValidator.h" + +CondFromRasterDialog::CondFromRasterDialog(const std::map<std::string, MeshLib::CFEMesh*> &msh_map, QDialog* parent) + : QDialog(parent), _msh_map(msh_map) +{ + setupUi(this); + + this->scalingEdit->setEnabled(false); + _scale_validator = new StrictDoubleValidator(-1e+10, 1e+20, 5); + this->scalingEdit->setText("1.0"); + this->scalingEdit->setValidator (_scale_validator); + + for (std::map<std::string, MeshLib::CFEMesh*>::const_iterator it = _msh_map.begin(); + it != _msh_map.end(); ++it) + this->meshBox->addItem(QString::fromStdString(it->first)); + + this->directButton->setChecked(true); +} + +CondFromRasterDialog::~CondFromRasterDialog() +{ + delete _scale_validator; +} + +void CondFromRasterDialog::on_selectButton_pressed() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); +#ifdef libgeotiff_FOUND + QString geotiffExtension(" *.tif"); +#else + QString geotiffExtension(""); +#endif + QString fileName = QFileDialog::getOpenFileName(this, "Select raster file", + settings.value("lastOpenedConditionsFileDirectory").toString(), QString( + "Raster files (*.asc *.grd);;") .arg(geotiffExtension)); + + if (!fileName.isEmpty()) + { + this->rasterEdit->setText(fileName); + + QDir dir = QDir(fileName); + settings.setValue("lastOpenedConditionsFileDirectory", dir.absolutePath()); + } +} + + +void CondFromRasterDialog::accept() +{ + std::string mesh_name (this->meshBox->currentText().toStdString()); + std::string raster_name (this->rasterEdit->text().toStdString()); + double scaling_factor = strtod(this->scalingEdit->text().toStdString().c_str(), 0); + std::vector< std::pair<size_t,double> > direct_values; + + if (mesh_name.empty()) + { + OGSError::box("No mesh selected."); + return; + } + if (raster_name.empty()) + { + OGSError::box("No raster selected."); + return; + } + + const MeshLib::CFEMesh* mesh = (_msh_map.find(mesh_name))->second; + //std::string direct_node_name(raster_name + ".txt"); + + if (this->directButton->isChecked()) + { + DirectConditionGenerator dcg; + direct_values = dcg.directToSurfaceNodes(*mesh, raster_name); + //dcg.writeToFile(direct_node_name); + } + else + { + if (scaling_factor <= 0) + { + OGSError::box("No valid scaling factor given."); + return; + } + MeshLib::CFEMesh* new_mesh = const_cast<MeshLib::CFEMesh*>(mesh); + DirectConditionGenerator dcg; + direct_values = dcg.directWithSurfaceIntegration(*new_mesh, raster_name, scaling_factor); + //dcg.writeToFile(direct_node_name); + } + //emit directNodesWritten(direct_node_name); + emit transmitDisValues(direct_values); + this->done(QDialog::Accepted); +} + +void CondFromRasterDialog::reject() +{ + this->done(QDialog::Rejected); +} + +void CondFromRasterDialog::on_integrateButton_toggled(bool isSelected) +{ + this->scalingEdit->setEnabled(isSelected); +} \ No newline at end of file diff --git a/Gui/DataView/CondFromRasterDialog.h b/Gui/DataView/CondFromRasterDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..0537113915df691b4529de2cc545babd799a1020 --- /dev/null +++ b/Gui/DataView/CondFromRasterDialog.h @@ -0,0 +1,47 @@ +/** + * \file CondFromRasterDialog.h + * 2012/01/04 KR Initial implementation + */ + +#ifndef CONDFROMRASTERDIALOG_H +#define CONDFROMRASTERDIALOG_H + +#include "ui_CondFromRaster.h" +#include <QDialog> + +#include "ProjectData.h" +#include "GridAdapter.h" + +class StrictDoubleValidator; + +/** + * \brief A dialog window for creating DIRECT boundary conditions from raster files + */ +class CondFromRasterDialog : public QDialog, private Ui_CondFromRaster +{ + Q_OBJECT + +public: + CondFromRasterDialog(const std::map<std::string, MeshLib::CFEMesh*> &msh_map, QDialog* parent = 0); + ~CondFromRasterDialog(void); + +private: + const std::map<std::string, MeshLib::CFEMesh*> _msh_map; + StrictDoubleValidator* _scale_validator; + +private slots: + void on_integrateButton_toggled(bool isSelected); + void on_selectButton_pressed(); + + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void directNodesWritten(std::string); + void transmitDisValues(std::vector< std::pair<size_t,double> >); +}; + +#endif //CONDFROMRASTERDIALOG_H diff --git a/Gui/DataView/CondItem.h b/Gui/DataView/CondItem.h new file mode 100644 index 0000000000000000000000000000000000000000..d03d4a27dbd57d1d531666752116f3f31da8b992 --- /dev/null +++ b/Gui/DataView/CondItem.h @@ -0,0 +1,38 @@ +/** + * \file CondItem.h + * 20/10/2010 KR Initial implementation + */ + +#ifndef CONDITEM_H +#define CONDITEM_H + +#include "FEMCondition.h" +#include "TreeItem.h" +#include "VtkPointsSource.h" + +/** + * \brief A TreeItem containing a condition of a FEM (BC, IC or ST). + * \sa TreeItem + */ +class CondItem : public TreeItem +{ +public: + /// Constructor + CondItem(const QList<QVariant> &data, TreeItem* parent, const FEMCondition* cond) + : TreeItem(data, parent), _item(cond) + { + } + + ~CondItem() {} + + /// Returns the FEM Condition associated with the item. + const FEMCondition* getItem() { return _item; } + + /// Returns the geo-object on which the condition is placed. + const GEOLIB::GeoObject* getGeoObject() { return this->getGeoObject(); } + +private: + const FEMCondition* _item; +}; + +#endif //CONDITEM_H diff --git a/Gui/DataView/CondObjectListItem.h b/Gui/DataView/CondObjectListItem.h new file mode 100644 index 0000000000000000000000000000000000000000..4ab7b837428804e9353b3cc74ef1830017d5d846 --- /dev/null +++ b/Gui/DataView/CondObjectListItem.h @@ -0,0 +1,69 @@ +/** + * \file GeoObjectListItem.h + * 2011/04/05 KR Initial implementation + * + */ +#ifndef CONDOBJECTLISTITEM_H +#define CONDOBJECTLISTITEM_H + +#include "FEMCondition.h" +#include "TreeItem.h" +#include "VtkConditionSource.h" +#include <QModelIndex> +#include <vtkPolyDataAlgorithm.h> +#include <vtkThresholdPoints.h> + +/** + * \brief The CondObjectListItem is the TreeItem that contains the subtree for either initial conditions, + * boundary conditions source terms. This item also contains the vtk source-item for visualisation of this + * information and the indices of the associated geometry-objects. + * Upon creation the type of condition needs to be defined and the vector of points of the associated geometry + * is needed for created of the vtk-object. + * The actual FEM Condtions are added using the addCondition()-method. + * \sa TreeItem + */ +class CondObjectListItem : public TreeItem +{ +public: + /// Constructor for the TreeItem specifying FEM Conditions. + CondObjectListItem(const QList<QVariant> &data, + TreeItem* parent, + FEMCondition* cond, + const std::vector<GEOLIB::Point*>* points) + : TreeItem(data, parent), _vtkSource(VtkConditionSource::New()), _type(cond->getCondType()), + _cond_vec(new std::vector<FEMCondition*>) + { + _cond_vec->push_back(cond); + QString display_name = parent->data(0).toString().append(" - ").append( + QString::fromStdString(FEMCondition::condTypeToString(_type))); + static_cast<VtkConditionSource*>(_vtkSource)->setData( points, _cond_vec); + static_cast<VtkConditionSource*>(_vtkSource)->SetName( display_name ); + } + + ~CondObjectListItem() + { + _vtkSource->Delete(); + delete _cond_vec; + } + + /// Adds FEMCondtion for construction of VTK object. + void addCondition(FEMCondition* cond) + { + _cond_vec->push_back(cond); + _vtkSource->Modified(); + } + + /// Returns the type of geo-objects contained in the subtree of this item. + FEMCondition::CondType getType() const { return _type; }; + + /// Returns the Vtk polydata source object + vtkPolyDataAlgorithm* vtkSource() const { return _vtkSource; }; + +private: + /// The Vtk data source object. This is the starting point for a Vtk data visualization pipeline. + vtkPolyDataAlgorithm* _vtkSource; + FEMCondition::CondType _type; + std::vector<FEMCondition*>* _cond_vec; +}; + +#endif //CONDOBJECTLISTITEM_H diff --git a/Gui/DataView/ConditionWriter.ui b/Gui/DataView/ConditionWriter.ui new file mode 100644 index 0000000000000000000000000000000000000000..a7bd5995c644de73773b2ae1a59c3995c96f2706 --- /dev/null +++ b/Gui/DataView/ConditionWriter.ui @@ -0,0 +1,143 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ConditionWriter</class> + <widget class="QDialog" name="ConditionWriter"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>203</height> + </rect> + </property> + <property name="windowTitle"> + <string>Save FEM Conditions...</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <widget class="QLabel" name="geoLabel"> + <property name="text"> + <string>Geometry</string> + </property> + <property name="margin"> + <number>10</number> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="condTypeLabel"> + <property name="text"> + <string>Condition Type</string> + </property> + <property name="margin"> + <number>10</number> + </property> + </widget> + </item> + <item row="1" column="2" colspan="2"> + <widget class="QComboBox" name="geoBox"> + <item> + <property name="text"> + <string>All (XML files only)</string> + </property> + </item> + </widget> + </item> + <item row="2" column="2" colspan="2"> + <widget class="QComboBox" name="condTypeBox"> + <item> + <property name="text"> + <string>All (XML files only)</string> + </property> + </item> + <item> + <property name="text"> + <string>Boundary Conditions</string> + </property> + </item> + <item> + <property name="text"> + <string>Initial Conditions</string> + </property> + </item> + <item> + <property name="text"> + <string>Source Terms</string> + </property> + </item> + </widget> + </item> + <item row="4" column="2" colspan="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="fileNameLabel"> + <property name="text"> + <string>Filename</string> + </property> + <property name="margin"> + <number>10</number> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QLineEdit" name="fileNameEdit"/> + </item> + <item row="3" column="3"> + <widget class="QPushButton" name="fileNameButton"> + <property name="maximumSize"> + <size> + <width>30</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>...</string> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>ConditionWriter</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>ConditionWriter</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/ConditionWriterDialog.cpp b/Gui/DataView/ConditionWriterDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3480132224faba04295bbb20e0cc84133233c75c --- /dev/null +++ b/Gui/DataView/ConditionWriterDialog.cpp @@ -0,0 +1,95 @@ +/** + * \file ConditionWriterDialog.cpp + * 2012/01/11 KR Initial implementation + */ + +#include "ConditionWriterDialog.h" +#include "FEMCondition.h" +#include "OGSError.h" + +#include <QFileDialog> +#include <QFileInfo> +#include <QSettings> + +ConditionWriterDialog::ConditionWriterDialog(const GEOLIB::GEOObjects *geo_objects, QDialog* parent) + : QDialog(parent) +{ + setupUi(this); + + std::vector<std::string> geo_names; + geo_objects->getGeometryNames(geo_names); + + for (size_t i=0; i<geo_names.size(); i++) + this->geoBox->addItem(QString::fromStdString(geo_names[i])); + +} + +ConditionWriterDialog::~ConditionWriterDialog() +{ +} + +void ConditionWriterDialog::on_fileNameButton_pressed() +{ + QString filetypes(""); + int geo_idx = this->geoBox->currentIndex(); + int cnd_idx = this->condTypeBox->currentIndex(); + if ((geo_idx == 0) || (cnd_idx == 0)) filetypes = "OpenGeoSys FEM Condition file (*.cnd)"; + else if ((geo_idx != 0) && (cnd_idx == 1)) filetypes = "OpenGeoSys FEM Condition file (*.cnd);;GeoSys Boundary Condition (*.bc)"; + else if ((geo_idx != 0) && (cnd_idx == 2)) filetypes = "OpenGeoSys FEM Condition file (*.cnd);;GeoSys Initial Condition (*.ic)"; + else if ((geo_idx != 0) && (cnd_idx == 3)) filetypes = "OpenGeoSys FEM Condition file (*.cnd);;GeoSys Source Condition (*.st)"; + + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getSaveFileName(this, "Select path", + settings.value("lastOpenedConditionsFileDirectory").toString(), filetypes); + + if (!fileName.isEmpty()) + { + this->fileNameEdit->setText(fileName); + + QDir dir = QDir(fileName); + settings.setValue("lastOpenedConditionsFileDirectory", dir.absolutePath()); + } +} + + +void ConditionWriterDialog::accept() +{ + const QString file_name = this->fileNameEdit->text(); + QFileInfo fi(file_name); + + if ((fi.suffix().toLower().compare("cnd") != 0) && + ((this->geoBox->currentIndex()==0) || (this->condTypeBox->currentIndex()==0))) + { + OGSError::box("Multiple geometries or multiple types of conditions\ncan only be saved to *.cnd files.","Inconsistent selection of parameters"); + } + else + { + QString geo_name = this->geoBox->currentText(); + if (this->geoBox->currentIndex() == 0) geo_name = ""; + + FEMCondition::CondType cond_type(FEMCondition::UNSPECIFIED);; + switch (this->condTypeBox->currentIndex()) + { + case 0: + cond_type = FEMCondition::UNSPECIFIED; break; + case 1: + cond_type = FEMCondition::BOUNDARY_CONDITION; break; + case 2: + cond_type = FEMCondition::INITIAL_CONDITION; break; + case 3: + cond_type = FEMCondition::SOURCE_TERM; break; + default: + std::cout << "Error in ConditionWriterDialog..." << std::endl; + } + + emit saveFEMConditionsRequested(geo_name, cond_type, file_name); + + this->done(QDialog::Accepted); + } +} + +void ConditionWriterDialog::reject() +{ + this->done(QDialog::Rejected); +} + diff --git a/Gui/DataView/ConditionWriterDialog.h b/Gui/DataView/ConditionWriterDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..399ee350dcf7c7687eb71983ec5ac76b68305d29 --- /dev/null +++ b/Gui/DataView/ConditionWriterDialog.h @@ -0,0 +1,40 @@ +/** + * \file ConditionWriterDialog.h + * 2012/01/11 KR Initial implementation + */ + +#ifndef CONDITIONWRITERDIALOG_H +#define CONDITIONWRITERDIALOG_H + +#include "ui_ConditionWriter.h" +#include <QDialog> + +#include "GEOObjects.h" +#include "FEMCondition.h" + +/** + * \brief A dialog window for creating DIRECT boundary conditions from raster files + */ +class ConditionWriterDialog : public QDialog, private Ui_ConditionWriter +{ + Q_OBJECT + +public: + ConditionWriterDialog(const GEOLIB::GEOObjects* geoObjects, QDialog* parent = 0); + ~ConditionWriterDialog(void); + +private slots: + void on_fileNameButton_pressed(); + + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void saveFEMConditionsRequested(const QString&, const FEMCondition::CondType, const QString&); + +}; + +#endif //CONDITIONWRITERDIALOG_H diff --git a/Gui/DataView/DBConnection.ui b/Gui/DataView/DBConnection.ui new file mode 100644 index 0000000000000000000000000000000000000000..f097882e6d0c3348756b00e5a55be44eb3f10e49 --- /dev/null +++ b/Gui/DataView/DBConnection.ui @@ -0,0 +1,228 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>DBConnectionDialog</class> + <widget class="QDialog" name="DBConnectionDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>388</width> + <height>215</height> + </rect> + </property> + <property name="windowTitle"> + <string>Database Connection Settings</string> + </property> + <widget class="QDialogButtonBox" name="dbButtonBox"> + <property name="geometry"> + <rect> + <x>30</x> + <y>170</y> + <width>341</width> + <height>32</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set> + </property> + </widget> + <widget class="QComboBox" name="driverBox"> + <property name="geometry"> + <rect> + <x>170</x> + <y>20</y> + <width>201</width> + <height>22</height> + </rect> + </property> + <item> + <property name="text"> + <string>QDB2 (IBM DB2)</string> + </property> + </item> + <item> + <property name="text"> + <string>QIBASE (Borland Interbase)</string> + </property> + </item> + <item> + <property name="text"> + <string>QMYSQL (MySQL)</string> + </property> + </item> + <item> + <property name="text"> + <string>QOCI (Oracle Call Interface)</string> + </property> + </item> + <item> + <property name="text"> + <string>QODBC (ODBC / MS SQL Server)</string> + </property> + </item> + <item> + <property name="text"> + <string>QPSQL (PostgreSQL)</string> + </property> + </item> + <item> + <property name="text"> + <string>QSQLITE (SQLite v.3 or above)</string> + </property> + </item> + <item> + <property name="text"> + <string>QSQLITE2 (SQLite v.2)</string> + </property> + </item> + <item> + <property name="text"> + <string>QTDS (Sybase Adaptive Server)</string> + </property> + </item> + </widget> + <widget class="QLabel" name="driverLine"> + <property name="geometry"> + <rect> + <x>20</x> + <y>20</y> + <width>131</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Database Driver:</string> + </property> + </widget> + <widget class="QLabel" name="hostnameLabel"> + <property name="geometry"> + <rect> + <x>20</x> + <y>50</y> + <width>131</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Hostname:</string> + </property> + </widget> + <widget class="QLabel" name="dbnameLabel"> + <property name="geometry"> + <rect> + <x>20</x> + <y>80</y> + <width>131</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Database Name:</string> + </property> + </widget> + <widget class="QLabel" name="usernameLabel"> + <property name="geometry"> + <rect> + <x>20</x> + <y>110</y> + <width>131</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Username:</string> + </property> + </widget> + <widget class="QLabel" name="passwordLabel"> + <property name="geometry"> + <rect> + <x>20</x> + <y>140</y> + <width>131</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Password (optional):</string> + </property> + </widget> + <widget class="QLineEdit" name="hostnameLine"> + <property name="geometry"> + <rect> + <x>170</x> + <y>50</y> + <width>201</width> + <height>20</height> + </rect> + </property> + </widget> + <widget class="QLineEdit" name="dbnameLine"> + <property name="geometry"> + <rect> + <x>170</x> + <y>80</y> + <width>201</width> + <height>20</height> + </rect> + </property> + </widget> + <widget class="QLineEdit" name="usernameLine"> + <property name="geometry"> + <rect> + <x>170</x> + <y>110</y> + <width>201</width> + <height>20</height> + </rect> + </property> + </widget> + <widget class="QLineEdit" name="passwordLine"> + <property name="geometry"> + <rect> + <x>170</x> + <y>140</y> + <width>201</width> + <height>20</height> + </rect> + </property> + </widget> + </widget> + <resources/> + <connections> + <connection> + <sender>dbButtonBox</sender> + <signal>accepted()</signal> + <receiver>DBConnectionDialog</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>dbButtonBox</sender> + <signal>rejected()</signal> + <receiver>DBConnectionDialog</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/DBConnectionDialog.cpp b/Gui/DataView/DBConnectionDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b3b6349ef5333cf45db0e7c78950526e64ac6304 --- /dev/null +++ b/Gui/DataView/DBConnectionDialog.cpp @@ -0,0 +1,51 @@ +/** + * \file DBConnectionDialog.cpp + * KR Initial implementation + */ + +#include "DBConnectionDialog.h" +#include <QSettings> + +/// Constructor +DBConnectionDialog::DBConnectionDialog(QDialog* parent) : QDialog(parent) +{ + setupUi(this); + + int idx = 0; + QSettings settings("UFZ", "OpenGeoSys-5"); + + if (!settings.value("DBProtocol", "").toString().isEmpty()) + for (int i = 0; i < driverBox->count(); i++) + if (driverBox->itemText(i).startsWith(settings.value("DBProtocol", + "").toString())) + idx = i; + + driverBox->setCurrentIndex(idx); + hostnameLine->setText(settings.value("DBHost", "").toString()); + dbnameLine->setText(settings.value("DBName", "").toString()); + usernameLine->setText(settings.value("DBUser", "").toString()); + passwordLine->setText(settings.value("DBPass", "").toString()); +} + +DBConnectionDialog::~DBConnectionDialog() +{ +} + +/// Instructions if the OK-Button has been pressed. +void DBConnectionDialog::accept() +{ + QString protocol = (driverBox->currentText()).left((driverBox->currentText()).indexOf(" ")); + QString hostname = hostnameLine->text(); + QString dbname = dbnameLine->text(); + QString user = usernameLine->text(); + QString pass = passwordLine->text(); + + emit connectionRequested(protocol, hostname, dbname, user, pass); + this->done(QDialog::Accepted); +} + +/// Instructions if the Cancel-Button has been pressed. +void DBConnectionDialog::reject() +{ + this->done(QDialog::Rejected); +} diff --git a/Gui/DataView/DBConnectionDialog.h b/Gui/DataView/DBConnectionDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..65bf87d45430a47af725374fb7ce2ceabe2276d4 --- /dev/null +++ b/Gui/DataView/DBConnectionDialog.h @@ -0,0 +1,32 @@ +/** + * \file DBConnectionDialog.h + * KR Initial implementation + */ + +#ifndef DBCONNECTIONDIALOG_H +#define DBCONNECTIONDIALOG_H + +#include "ui_DBConnection.h" +#include <QSqlQueryModel> +#include <QDialog> + +/** + * \brief A dialog window for settung up a database connection + */ +class DBConnectionDialog : public QDialog, private Ui_DBConnectionDialog +{ + Q_OBJECT + +public: + DBConnectionDialog(QDialog* parent = 0); + ~DBConnectionDialog(void); + +private slots: + void accept(); + void reject(); + +signals: + void connectionRequested(QString, QString, QString, QString, QString); +}; + +#endif //DBCONNECTIONDIALOG_H diff --git a/Gui/DataView/DataView.cpp b/Gui/DataView/DataView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1802a5551b084bb91a9a4a3953b2edbf7133853 --- /dev/null +++ b/Gui/DataView/DataView.cpp @@ -0,0 +1,196 @@ +/** + * \file DataView.cpp + * 24/9/2009 LB Initial implementation + * + * Implementation of DataView + */ + +#include "DataView.h" +#include "GridAdapter.h" +#include "MshEditDialog.h" +#include "MshItem.h" +#include "MshModel.h" +#include "OGSError.h" +#include <QHeaderView> + +#include "VtkMeshSource.h" + +#include <QContextMenuEvent> +#include <QFileDialog> +#include <QMenu> +#include <QObject> +#include <QSettings> + +#include "MeshIO/OGSMeshIO.h" +#include "Writer.h" // necessary to avoid Linker Error in Windows + +DataView::DataView( QWidget* parent /*= 0*/ ) + : QTreeView(parent) +{ + //resizeColumnsToContents(); + //resizeRowsToContents(); +} + +void DataView::updateView() +{ + setAlternatingRowColors(true); + setColumnWidth(0,125); + size_t nColumns = (this->model() != NULL) ? this->model()->columnCount() : 0; + for (size_t i = 1; i < nColumns; i++) + resizeColumnToContents(i); +} + +void DataView::addMeshAction() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = + QFileDialog::getOpenFileName(this, "Select mesh file", settings.value( + "lastOpenedFileDirectory").toString(), + "OpenGeosys mesh files (*.msh);;All files (* *.*)"); + if (!fileName.isEmpty()) + { + std::string name = fileName.toStdString(); + FileIO::OGSMeshIO meshIO; + MeshLib::CFEMesh* msh = meshIO.loadMeshFromFile(name); + if (msh) + static_cast<MshModel*>(this->model())->addMesh(msh, name); + } +} + +void DataView::removeMesh() +{ + emit requestMeshRemoval(this->selectionModel()->currentIndex()); +} + +void DataView::removeAllMeshes() +{ + TreeItem* root = static_cast<MshModel*>(this->model())->getItem(QModelIndex()); + int nChildren = root->childCount() - 1; + for (int i = nChildren; i >= 0; i--) + emit requestMeshRemoval(this->model()->index(i, 0, QModelIndex())); +} + +void DataView::contextMenuEvent( QContextMenuEvent* event ) +{ + QModelIndex index = this->selectionModel()->currentIndex(); + MshItem* item = dynamic_cast<MshItem*>(static_cast<TreeItem*>(index.internalPointer())); + + if (item) + { + QMenu menu; + QAction* editMeshAction = menu.addAction("Edit mesh..."); + QAction* checkMeshAction = menu.addAction("Check mesh quality..."); + QAction* saveMeshAction = menu.addAction("Save mesh..."); + menu.addSeparator(); + QMenu direct_cond_menu("DIRECT Conditions"); + menu.addMenu(&direct_cond_menu); + QAction* addDirectAction = direct_cond_menu.addAction("Add..."); + QAction* loadDirectAction = direct_cond_menu.addAction("Load..."); + menu.addSeparator(); + QAction* removeMeshAction = menu.addAction("Remove mesh"); + connect(editMeshAction, SIGNAL(triggered()), this, SLOT(openMshEditDialog())); + connect(checkMeshAction, SIGNAL(triggered()), this, SLOT(checkMeshQuality())); + connect(saveMeshAction, SIGNAL(triggered()), this, SLOT(writeMeshToFile())); + connect(addDirectAction, SIGNAL(triggered()), this, SLOT(addDIRECTSourceTerms())); + connect(loadDirectAction, SIGNAL(triggered()), this, SLOT(loadDIRECTSourceTerms())); + connect(removeMeshAction, SIGNAL(triggered()), this, SLOT(removeMesh())); + menu.exec(event->globalPos()); + } +} + +void DataView::openMshEditDialog() +{ + MshModel* model = static_cast<MshModel*>(this->model()); + QModelIndex index = this->selectionModel()->currentIndex(); + const MeshLib::CFEMesh* mesh = + static_cast<MshModel*>(this->model())->getMesh(index)->getCFEMesh(); + + MshEditDialog meshEdit(mesh); + connect(&meshEdit, SIGNAL(mshEditFinished(MeshLib::CFEMesh*, std::string &)), + model, SLOT(addMesh(MeshLib::CFEMesh*, std::string &))); + meshEdit.exec(); +} + +int DataView::writeMeshToFile() const +{ + QModelIndex index = this->selectionModel()->currentIndex(); + const MeshLib::CFEMesh* mesh = + static_cast<MshModel*>(this->model())->getMesh(index)->getCFEMesh(); + + if (mesh) + { + QSettings settings("UFZ", "OpenGeoSys-5"); + QString mshName = QString::fromStdString( + static_cast<MshModel*>(this->model())->getMesh(index)->getName()); + QString fileName = QFileDialog::getSaveFileName(NULL, "Save mesh as", + settings.value("lastOpenedMeshFileDirectory").toString(), + "GeoSys mesh file (*.msh)"); + + if (!fileName.isEmpty()) + { + FileIO::OGSMeshIO meshIO; + meshIO.setMesh(mesh); + meshIO.writeToFile(fileName.toStdString().c_str()); + QDir dir = QDir(fileName); + settings.setValue("lastOpenedMeshFileDirectory", dir.absolutePath()); + return 1; + } + else + OGSError::box("No file name entered."); + } + return 0; +} + +void DataView::addDIRECTSourceTerms() +{ + QModelIndex index = this->selectionModel()->currentIndex(); + const GridAdapter* grid = static_cast<MshModel*>(this->model())->getMesh(index); + emit requestCondSetupDialog(grid->getName(), GEOLIB::INVALID, 0, false); +} + + +void DataView::loadDIRECTSourceTerms() +{ + QModelIndex index = this->selectionModel()->currentIndex(); + const GridAdapter* grid = static_cast<MshModel*>(this->model())->getMesh(index); + const std::vector<GEOLIB::Point*>* points = grid->getNodes(); + emit requestDIRECTSourceTerms(grid->getName(), points); +} + +void DataView::checkMeshQuality () +{ + QModelIndex index = this->selectionModel()->currentIndex(); + MshItem* item = static_cast<MshItem*>(static_cast<MshModel*>(this->model())->getItem(index)); + emit qualityCheckRequested(item->vtkSource()); +} + +/* + void DataView::selectionChanged( const QItemSelection &selected, const QItemSelection &deselected ) + { + emit itemSelectionChanged(selected, deselected); + return QTreeView::selectionChanged(selected, deselected); + } + + void DataView::selectionChangedFromOutside( const QItemSelection &selected, const QItemSelection &deselected ) + { + QItemSelectionModel* selModel = this->selectionModel(); + + Q_ASSERT(selModel); + + selModel->blockSignals(true); + selModel->select(deselected, QItemSelectionModel::Deselect); + selModel->select(selected, QItemSelectionModel::Select); + selModel->blockSignals(false); + + Model* model = static_cast<Model*>(this->model()); + //model->setSelectionFromOutside(selected, deselected); + + return QTreeView::selectionChanged(selected, deselected); + } + + void DataView::clearSelection() + { + selectionModel()->clearSelection(); + } + */ + diff --git a/Gui/DataView/DataView.h b/Gui/DataView/DataView.h new file mode 100644 index 0000000000000000000000000000000000000000..215320a91dc81d9c254802c8bfcade4a26d55ac3 --- /dev/null +++ b/Gui/DataView/DataView.h @@ -0,0 +1,93 @@ +/** + * \file DataView.h + * 24/9/2009 LB Initial implementation + */ +#ifndef DATAVIEW_H +#define DATAVIEW_H + +#include "Point.h" +#include "GeoType.h" +#include <QTreeView> + +class GridAdapter; +class MshModel; +class VtkMeshSource; + +namespace MeshLib +{ +class CFEMesh; +} +/* + namespace GEOLIB { + class Point; + } + */ +/** + * The DataView is table view which acts as a base class for displaying + * several OSG data formats. + */ +class DataView : public QTreeView +{ + Q_OBJECT + +public: + DataView(QWidget* parent = 0); + +public slots: + void updateView(); + +protected slots: + /// Is called when the selection of this view changes. Emits a the signal + /// itemSelectionChanged() + //void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + + /// Selects items without sending signals. + //void selectionChangedFromOutside(const QItemSelection &selected, + // const QItemSelection &deselected); + + /// Clears the selection + //void clearSelection(); + +private: + void contextMenuEvent( QContextMenuEvent* event ); + +private slots: + /// Open a dialog for editing meshes. + void openMshEditDialog(); + + /// Adds a new mesh. + void addMeshAction(); + + void addDIRECTSourceTerms(); + + void loadDIRECTSourceTerms(); + + /// Remove the currently selected mesh. + void removeMesh(); + + /// Remove all currently loaded meshes. + void removeAllMeshes(); + + /// Calls the FileDialog to save a mesh to a file. + int writeMeshToFile() const; + + /** + * checks the mesh quality + */ + void checkMeshQuality(); + +signals: + void qualityCheckRequested(VtkMeshSource*); + void requestCondSetupDialog(const std::string&, const GEOLIB::GEOTYPE, const size_t, bool on_points); + void requestMeshRemoval(const QModelIndex&); + void requestDIRECTSourceTerms(const std::string, const std::vector<GEOLIB::Point*>*); + void saveMeshAction(); + +/* + void itemSelectionChanged(const QItemSelection &selected, + const QItemSelection &deselected); + void itemSelectionChangedFromOutside(const QItemSelection &selected, + const QItemSelection &deselected); + */ +}; +#endif // DATAVIEW_H diff --git a/Gui/DataView/DatabaseConnection.cpp b/Gui/DataView/DatabaseConnection.cpp new file mode 100644 index 0000000000000000000000000000000000000000..73cd556317a8073283658c8f9d42795f4530b3fb --- /dev/null +++ b/Gui/DataView/DatabaseConnection.cpp @@ -0,0 +1,847 @@ +/** + * \file DatabaseConnection.cpp + * KR Initial implementation + */ + +#include "DatabaseConnection.h" +#include "DateTools.h" +#include "OGSError.h" +#include "QueryResultsDialog.h" +#include "StringTools.h" +#include <QSettings> +#include <QSqlError> +#include <QSqlQuery> +#include <QSqlQueryModel> +#include <QVariant> + +#include <fstream> +#include <iostream> + +/// The OGS5-Connection to a database +DatabaseConnection::DatabaseConnection(GEOLIB::GEOObjects* geoObjects, + QObject* parent) : QObject(parent), _geoObjects(geoObjects) +{ +} + +/// Deconstructor for the connection object +DatabaseConnection::~DatabaseConnection() +{ + _db.removeDatabase("QOCI"); +} + +/** + * Initialising and testing the default database-connection. + * \return 1 if the connection has been established, 0 (and an error message) otherwise. + */ +int DatabaseConnection::dbConnect() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString protocol = settings.value("DBProtocol", "").toString(); + QString hostname = settings.value("DBHost", "").toString(); + QString dbname = settings.value("DBName", "").toString(); + QString user = settings.value("DBUser", "").toString(); + QString pass = settings.value("DBPass", "").toString(); + + //default connection + if (protocol.isEmpty() || hostname.isEmpty() || dbname.isEmpty() || user.isEmpty() || + pass.isEmpty()) + { + protocol = "QOCI"; + hostname = "cora1-vip.leipzig.ufz.de"; + dbname = "ORACLE1"; + user = "GEOSYS"; + pass = "project09"; + } + + return dbConnect(protocol, hostname, dbname, user, pass); +} + +/** + * Initialising and testing a specific database-connection. + * \param protocol The database connection driver + * \param hostname The connection's host name + * \param dbname The connection's database name + * \param user The user name for connecting to the database + * \param pass The password for the specified user name + * \return 1 if the connection has been established, 0 (and an error message) otherwise. + */ +int DatabaseConnection::dbConnect(QString protocol, + QString hostname, + QString dbname, + QString user, + QString pass) +{ + QSqlDatabase::removeDatabase(_db.connectionName()); + + _db = QSqlDatabase::addDatabase(protocol); + _db.setHostName(hostname); + _db.setDatabaseName(dbname); + _db.setUserName(user); + _db.setPassword(pass); + + return test(false); +} + +/** + * Setting up a new database-connection as default connection. + * \param protocol The database connection driver + * \param hostname The connection's host name + * \param dbname The connection's database name + * \param user The user name for connecting to the database + * \param pass The password for the specified user name + * \return 1 if the connection has been established, 0 (and an error message) otherwise. + */ +int DatabaseConnection::setConnection(QString protocol, + QString hostname, + QString dbname, + QString user, + QString pass) +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + + settings.setValue("DBProtocol", protocol); + settings.setValue("DBHost", hostname); + settings.setValue("DBName", dbname); + settings.setValue("DBUser", user); + settings.setValue("DBPass", pass); + + dbConnect(protocol, hostname, dbname, user, pass); + disconnect(this, SLOT(setConnection(QString, QString, QString, QString, QString))); + return test(true); +} + +/** + * Tests the current database connection. + * \return 1 if the connection has been established, 0 (and an error message) otherwise. + */ +int DatabaseConnection::test(bool showBox) +{ + if (_db.open()) + { + if (showBox) + OGSError::box("Database connection established."); + else + std::cout << "Database connection established...\n"; + _db.close(); + return 1; + } + else + { + std::cout << "Database connection failed...\n"; + databaseError(); + OGSError::box("Could not connect to database."); + return 0; + } +} + +/// Outputting an error related to the database connection +void DatabaseConnection::databaseError() +{ + QSqlError error = _db.lastError(); + if (error.isValid()) + { + std::cout << (error.databaseText()).toStdString(); + std::cout << (error.driverText()).toStdString() << "\n\n"; + } +} + +/// Opening a dialog containing all the available station lists +void DatabaseConnection::getListSelection() +{ + if (_db.open()) + { + QSqlQueryModel* qModel = new QSqlQueryModel(); + qModel->setQuery( + "select l.listid, c.catname, l.listname from lists l, categories c where c.catid=l.catid order by c.catname"); + + QueryResultsDialog* dbView = new QueryResultsDialog(); + connect(dbView, SIGNAL(listSelected(int)), this, SLOT(loadStationList(int))); + + dbView->setView(qModel); + dbView->exec(); + + _db.close(); + } + else + databaseError(); +} + +/// Tests if the current database connection is valid. +bool DatabaseConnection::isConnected() +{ + return _db.isValid(); +} + +/** + * Loads a list of stations. + * \param listID The ID of the list that is requested + * \return 1 if there were no errors, 0 and an error message otherwise. + */ +int DatabaseConnection::loadStationList(int listID) +{ + if (_db.open()) + { + QSqlQuery query, stnQuery; + QString stationName; + std::vector<GEOLIB::Point*>* stations = new std::vector<GEOLIB::Point*>; + + query.exec( + "select stationtype from geosysstationtypes where listid=" + + QString::number(listID)); + + if (query.next()) + { + GEOLIB::Station::StationType type = + static_cast<GEOLIB::Station::StationType>(query.value(0).toInt()); + if (type == GEOLIB::Station::BOREHOLE) + query.exec( + "select c.catname, l.listname from lists l, categories c, boreholes b where c.catid=l.catid and l.listid=b.listid and l.listid=" + + QString::number(listID)); + else + query.exec( + "select c.catname, l.listname from lists l, categories c where c.catid=l.catid and l.listid=" + + QString::number(listID)); + + if (query.next()) + { + QString listName = (query.value(0)).toString() + " (" + + (query.value(1)).toString() + ")"; + + if (type == GEOLIB::Station::BOREHOLE) + stnQuery.exec( + "select s.stationid, s.name, s.x, s.y, s.z, b.bdepth, to_char(b.bdate, 'YYYY-MM-DD') from stations s, boreholes b where s.listid=b.listid and s.stationid=b.stationid and s.listid=" + + QString::number(listID) + " order by stationid"); + else + stnQuery.exec( + "select stationid, name, x, y, z from stations where listid=" + + QString::number(listID) + " order by stationid"); + + while (stnQuery.next()) + { + stationName = stnQuery.value(1).toString(); + if (stationName.isEmpty()) + stationName = "Station" + + stnQuery.value(0).toString(); + + GEOLIB::Station* newStation; + if (type == GEOLIB::Station::BOREHOLE) + newStation = GEOLIB::StationBorehole::createStation( + stationName.toStdString(), + stnQuery.value(2).toDouble(), + stnQuery.value(3).toDouble(), + stnQuery.value(4).toDouble(), + stnQuery.value(5).toDouble(), + stnQuery.value(6).toString().toStdString()); + else + newStation = GEOLIB::Station::createStation( + stationName.toStdString(), + stnQuery.value(2).toDouble(), + stnQuery.value(3).toDouble(), + stnQuery.value(4).toDouble()); + + stations->push_back(newStation); + } + + if (type == GEOLIB::Station::BOREHOLE) + //addStratigraphy(listID, _geoObjects->getStationVec(listName.toStdString())); + addStratigraphy(listID, stations); + + std::string temp_name (listName.toStdString()); + if (!stations->empty()) + _geoObjects->addStationVec(stations, temp_name); + + _db.close(); + //emit listLoaded(listName); + + return 1; + } + } + else + { + std::cout << + "DatabaseConnection::loadList() - No database entry found for the selected key." + << std::endl; + _db.close(); + } + } + else + databaseError(); + + return 0; +} + +/** + * Loads additional stratigraphy-data if the loaded station list consists of boreholes + * \param listID The ID of the list that is requested + * \param stations List of station objects for which stratigraphy data will be provided + * \return 1 if there were no errors, 0 and an error message otherwise. + */ +int DatabaseConnection::addStratigraphy(int listID, std::vector<GEOLIB::Point*>* stations) +{ + if (_db.open()) + { + QSqlQuery strat; + + size_t size = stations->size(); + for (size_t i = 0; i < size; i++) + { + int count = 1; + GEOLIB::StationBorehole* newStation = + static_cast<GEOLIB::StationBorehole*>((*stations)[i]); + strat.exec( + "select s.layerid, s.thickness, s.strat from stations t, stratigraphies s where s.listid=" + + QString::number( + listID) + + " and s.listid=t.listid and s.stationid=t.stationid and t.name='" + + QString::fromStdString(static_cast<GEOLIB::Station*>((*stations)[i]) + -> + getName()) + "' order by layerid"); + + while (strat.next()) + { + if (count == strat.value(0)) + newStation->addSoilLayer (strat.value(1).toDouble(), + (strat.value( + 2).toString()). + toStdString()); + //newStation->type = Station::BOREHOLE; + else + std::cout << + "DatabaseConnection::addStratigraphy - Station " << + static_cast<GEOLIB::Station*>((*stations)[i])->getName() << + ": Stratigraphy incomplete...\n"; + count++; + } + (*stations)[i] = newStation; + } + } + else + { + std::cout << "Database error" << std::endl; + return 0; + } + + return 1; +} + +/** + * Returns the list ID for the station at a given postition + * \param list The name of the list + * \param x The x-coordinate of a station within the list + * \param y The y-coordinate of a station within the list + * \return The list ID if there were no errors, -1 and an error message otherwise. + */ +int DatabaseConnection::getListID(const QString &list, const double &x, const double &y) +{ + if (_db.open()) + { + QSqlQuery query; + query.exec( + "select l.listid from lists l, categories c, stations s where l.catid = c.catid and l.listid = s.listid and s.x=" + + QString::number(x,'f') + " and s.y=" + QString::number(y, + 'f') + + " and c.catname='" + list.left(list.indexOf(" (")) + "'"); + + if (query.next()) + return query.value(0).toInt(); + + return -1; + } + + return -1; +} + +/** + * Returns the station ID for the station at a given postition + * \param listID The ID of the list the station belongs to + * \param x The x-coordinate of the station + * \param y The y-coordinate of the station + * \return The station ID if there were no errors, -1 and an error message otherwise. + */ +int DatabaseConnection::getStationID(const int &listID, const double &x, const double &y) +{ + if (_db.open()) + { + QSqlQuery query; + query.exec("select stationid from stations where listid=" + QString::number( + listID) + " and x=" + QString::number(x, + 'f') + " and y=" + + QString::number(y,'f')); + + QString oldq = query.lastQuery(); + if (query.next()) + return query.value(0).toInt(); + + return -1; + } + + return -1; +} + +/** + * Returns all properties associated with a given list + * Note: This function is currently not implemented correctly. Please leave it alone or contact me if you want to use it. + * \param listID The ID of the queried list + * \param propNames A vector in which the properties will be stored + * \return 1 if there were no errors, 0 and an error message otherwise. + */ +int DatabaseConnection::getListProperties(const int &listID, std::vector<QString> &propNames) +{ + Q_UNUSED (listID); + + if (_db.open()) + { + QSqlQuery query; + query.exec( + "select column_name,data_type from all_tab_cols where table_name =\'STATIONS\'"); + while (query.next()) + if ((query.value(0).toString()).compare("LISTID") != 0 && + (query.value(0).toString()).compare("STATIONID") != 0 && + (query.value(1).toString()).compare("VARCHAR2") != 0) + propNames.push_back(query.value(0).toString()); + + return 1; + } + return 0; +} + +/** + * The minimum and maximum date for time series data associated with a given station + * \param listID The ID of the list the station belongs to + * \param stationID The ID of the station + * \param startDate The value of the first date for that station found in the database + * \param endDate The value of the last date for that station found in the database + * \return 1 if there were no errors, 0 and an error message otherwise. + */ +int DatabaseConnection::getDateBounds(const int &listID, + const int &stationID, + QString &startDate, + QString &endDate) +{ + startDate = ""; + endDate = ""; + if (_db.open()) + { + QSqlQuery query; + query.exec( + "select to_char(min(mdate), 'DD.MM.YYYY'), to_char(max(mdate), 'DD.MM.YYYY') from mvalues where listid=" + + QString::number(listID) + " and stationID=" + QString::number(stationID)); + if (query.next()) + { + startDate = query.value(0).toString(); + endDate = query.value(1).toString(); + } + _db.close(); + return 1; + } + return 0; +} + +/** + * The minimum and maximum value for a given property associated with a given list + * \param listID The ID of the list + * \param prop The name of the property + * \param min The smallest value of that property found in the database + * \param max The largest value of that property found in the database + * \return 1 if there were no errors, 0 and an error message otherwise. + */ +int DatabaseConnection::getPropertyBounds(const int &listID, + const QString &prop, + double &min, + double &max) +{ + if (_db.open()) + { + QSqlQuery query; + query.exec( + "select min(" + prop + "), max(" + prop + + ") from stations where listid=" + + QString::number(listID)); + if (query.next()) + { + min = query.value(0).toDouble(); + max = query.value(1).toDouble(); + } + _db.close(); + return 1; + } + return 0; +} + +/** + * Load time series data for a given station from the database + * \param listID The ID of the list the station belongs to + * \param stationID The ID of the station + * \param startDate The start date for the requested time series data + * \param endDate The end date for the requested time series data + * \param values The data + * \return 1 if there were no errors, 0 and an error message otherwise. + */ +int DatabaseConnection::loadValues(const int &listID, + const int &stationID, + const QDateTime &startDate, + const QDateTime &endDate, + std::vector< std::pair<QDateTime, float> > &values) +{ + if (startDate < endDate && _db.open()) + { + QSqlQuery query; + + query.prepare( + "select to_char(mdate,'YYYY-MM-DD'),mvalue from mvalues where listid=:listID and stationid=:stationID " + "and mdate>=to_date(:startDate,'DD.MM.YYYY') and mdate<=to_date(:endDate,'DD.MM.YYYY') order by mdate"); + query.bindValue(":listID", listID); + query.bindValue(":stationID", stationID); + query.bindValue(":startDate", startDate.toString("dd.MM.yyyy")); + query.bindValue(":endDate", endDate.toString("dd.MM.yyyy")); + query.exec(); + + while (query.next()) + values.push_back( std::pair<QDateTime, float>(query.value(0).toDateTime(), + static_cast<float>(query. + value(1). + toDouble())) ); + + _db.close(); + return 1; + } + + _db.close(); + return 0; +} + +/********************************************* +* Inserting data into the database. * +* Be very careful what you do with any of * +* functions below. * +* You might corrupt the database otherwise. * +* --KR * +*********************************************/ + +/** + * Inserts a new station list into the database + * \param path the path to the file containing the data + * \param listName the name of the list given a certain category + * \param catName the category of stations (i.e. boreholes) + * \param type the OGS5 Stationtype + */ +int DatabaseConnection::addListToDB(std::string path, + std::string listName, + std::string catName, + GEOLIB::Station::StationType type) +{ + if (_db.open()) + { + int listID, catID(0); + bool status = true, commit = true; + + std::ifstream in( path.c_str() ); + + if (!in.is_open()) + { + std::cout << + "DatabaseConnection::addListToDB() - Could not open file..." << std::endl; + return 0; + } + + /* a name for the list in the first line of the file. this name is ignored here because + * the real list name is required as parameter to this method + */ + std::string line; + getline(in, line); + if ((line.substr(0,1)).compare("!") == 0) + line.substr( 1, line.length() - 1 ); + + QSqlQuery query; + query.exec("select max(listid) from lists"); + if (query.next()) + { + listID = query.value(0).toInt() + 1; + + query.exec( + "select catid from categories where catname='" + + QString::fromStdString(catName) + "'"); + + if (query.next()) + catID = query.value(0).toInt(); + else + { + query.exec("select max(catid) from categories"); + if (query.next()) + catID = query.value(0).toInt() + 1; + query.prepare("insert into categories values (" + + QString::number( + catID) + ", '" + QString::fromStdString( + catName) + "')"); + commitTransaction(query); + } + + _db.transaction(); + query.exec("insert into lists values(" + QString::number( + listID) + ", '" + QString::fromStdString( + listName) + "', " + + QString::number(catID) + ", 0)"); + if (type == GEOLIB::Station::BOREHOLE) + query.exec( + "insert into geosysstationtypes values (" + QString::number( + listID) + ", 2)"); + + int stationID = 1; + + /* read all stations */ + while ( getline(in, line) ) + { + if (type == GEOLIB::Station::BOREHOLE) + status = addBoreholeToDB(listID, stationID, line); + else + status = addStationToDB(listID, stationID, line); + + if (!status) + { + databaseError(); + commit = false; + } + stationID++; + } + + if (commit) + _db.commit(); + else + _db.rollback(); + + _db.close(); + in.close(); + + return commit; + } + else + std::cout << "Database error." << std::endl; + + _db.close(); + } + else + databaseError(); + + return 0; +} + +/** + * Inserts a new station into the database (this is to be called from addListToDB()) + * \param listID the ID of the list the station belongs to + * \param stationID the ID of the station + * \param line a line of text containing all the necessary information for the station (typically from a textfile) + */ +bool DatabaseConnection::addStationToDB(int listID, int stationID, std::string line) +{ + QSqlQuery query; + GEOLIB::Station* station = GEOLIB::Station::createStation(line); + query.prepare("insert into stations values(:listid, :stationid, :stationname, :x, :y, :z)"); + query.bindValue(":listid", listID); + query.bindValue(":stationid", stationID); + query.bindValue(":stationname", QString::fromStdString(station->getName())); + query.bindValue(":x", (*station)[0]); + query.bindValue(":y", (*station)[1]); + query.bindValue(":z", (*station)[2]); + return query.exec(); +} + +/** + * Inserts a new borehole into the database (this is to be called from addListToDB()) + * This is kind of an expansion of addStationToDB() which uses the same parameters + * \param listID the ID of the list the station belongs to + * \param stationID the ID of the station + * \param line a line of text containing all the necessary information for the station (typically from a textfile) + */ +bool DatabaseConnection::addBoreholeToDB(int listID, int stationID, std::string line) +{ + QSqlQuery query; + GEOLIB::StationBorehole* station = GEOLIB::StationBorehole::createStation(line); + + if (addStationToDB(listID, stationID, line)) + { + query.prepare( + "insert into boreholes values (:listid, :stationid, :bdepth, to_date(:bdate, 'DD.MM.YYYY'))"); + query.bindValue(":listid", listID); + query.bindValue(":stationid", stationID); + query.bindValue(":bdepth", station->getDepth()); + QString sDate = QString::fromStdString(date2string(station->getDate())); + query.bindValue(":bdate", sDate); + return query.exec(); + } + return false; +} + +/** + * Adds stratigraphic information for a given list of boreholes to the database + * This method assumes that the given list of boreholes exists + * \param path the path to the file containing the data + * \param listID the ID of the station list the stratigraphic data belongs to + */ +int DatabaseConnection::addStratigraphyToDB(std::string path, int listID) +{ + QSqlQuery query; + int stationID; + std::string line, stationName; + + if (_db.open()) + { + std::ifstream in( path.c_str() ); + + if (!in.is_open()) + { + std::cout << + "DatabaseConnection::addListToDB() - Could not open file..." << std::endl; + return 0; + } + + query.exec("select count(*) from lists where listid=" + QString::number(listID)); + if (query.next()) + { + if (query.value(0).toInt() == 1) + { + _db.transaction(); + + /* read all stations */ + while ( getline(in, line) ) + { + std::list<std::string> fields = splitString(line, '\t'); + + stationName = fields.front(); + fields.pop_front(); + query.exec( + "select stationid from stations where listid=" + + QString::number( + listID) + " and name='" + + QString::fromStdString( + stationName) + "'" ); + + if (query.next() && fields.size() >= 3) + { + stationID = query.value(0).toInt(); + + query.prepare( + "insert into stratigraphies values (:listid, :stationid, :layerid, :thickness, :strat, :petro)"); + query.bindValue(":listid", listID); + query.bindValue(":stationid", stationID); + query.bindValue(":layerid", + atoi(fields.front().c_str())); + fields.pop_front(); + query.bindValue(":thickness", + strtod(replaceString(",", ".", + fields.front()) + .c_str(),0)); + fields.pop_front(); + query.bindValue(":strat", + QString::fromStdString(fields.front())); + fields.pop_front(); + + if (!fields.empty()) + query.bindValue(":petro", + QString::fromStdString( + fields.front())); + else + query.bindValue(":petro", ""); + + query.exec(); + } + } + _db.commit(); + } + in.close(); + _db.close(); + + return 1; + } + else + std::cout << "Database error." << std::endl; + + _db.close(); + } + else + databaseError(); + + return 0; +} + +/** + * Adds time series information for a given station to the database + * This method assumes that the given list and station-id exists + * \param path the path to the file containing the data + * \param listID the ID of the list the stratigraphic data belongs to + * \param stationID the ID of the station the stratigraphic data belongs to + */ +int DatabaseConnection::addMeasuredValuesToDB(std::string path, int listID, int stationID) +{ + QSqlQuery query; + std::string line; + + if (_db.open()) + { + std::ifstream in( path.c_str() ); + + if (!in.is_open()) + { + std::cout << + "DatabaseConnection::addMeasuredValuesToDB() - Could not open file..." << + std::endl; + return 0; + } + + query.exec("select count(*) from stations where listid=" + QString::number( + listID) + " and stationid=" + QString::number(stationID)); + if (query.next()) + { + if (query.value(0).toInt() == 1) + { + _db.transaction(); + + while ( getline(in, line) ) + { + std::list<std::string> fields = splitString(line, '\t'); + + QString a = query.lastQuery(); + + query.prepare( + "insert into mvalues values (:listid, :stationid, to_date(:mdatetime,'DD.MM.YYYY'), :mvalue)"); + query.bindValue(":listid", listID); + query.bindValue(":stationid", stationID); + query.bindValue(":mdatetime", + QString::fromStdString(fields.front())); + fields.pop_front(); + query.bindValue(":mvalue", + strtod(replaceString(",", ".", + fields.front()).c_str(), + 0)); + fields.pop_front(); + query.exec(); + } + _db.commit(); + } + in.close(); + _db.close(); + + return 1; + } + else + std::cout << "Database error." << std::endl; + + _db.close(); + } + else + databaseError(); + + return 0; +} + +/** + * Executing a query as an encapsulated transaction + * \return True if everything is alright, false if there were errors. + */ +bool DatabaseConnection::commitTransaction(QSqlQuery query) +{ + _db.transaction(); + query.exec(); + bool r = _db.commit(); + return r; +} + diff --git a/Gui/DataView/DatabaseConnection.h b/Gui/DataView/DatabaseConnection.h new file mode 100644 index 0000000000000000000000000000000000000000..06728a899bbba255cdb6d699f1fa689b1b4d8a3d --- /dev/null +++ b/Gui/DataView/DatabaseConnection.h @@ -0,0 +1,80 @@ +/** + * \file DatabaseConnection.h + * KR Initial implementation + */ + +#ifndef DATABASECONNECTION_H +#define DATABASECONNECTION_H + +#include "GEOObjects.h" +#include "Station.h" +#include <QDateTime> +#include <QObject> +#include <QSqlDatabase> +#include <string> + +/** + * \brief Management of a database connection including the actual connection process, error handling and relevant queries. + */ +class DatabaseConnection : public QObject +{ + Q_OBJECT + +public: + DatabaseConnection(GEOLIB::GEOObjects* geoObjects, QObject* parent = 0); + ~DatabaseConnection(); + + int dbConnect(); + + int getDateBounds(const int &listID, + const int &stationID, + QString &startDate, + QString &endDate); + int getListID(const QString &list, const double &x, const double &y); + int getListProperties(const int &listID, std::vector<QString> &propNames); + int getPropertyBounds(const int &listID, const QString &prop, double &min, double &max); + int getStationID(const int &listID, const double &x, const double &y); + void getListSelection(); + bool isConnected(); + int loadValues(const int &listID, + const int &stationID, + const QDateTime &startDate, + const QDateTime &endDate, + std::vector< std::pair<QDateTime, float> > &values); + int test(bool showBox); + +public slots: + int dbConnect(QString protocol, + QString hostname, + QString dbname, + QString user, + QString pass); + int loadStationList(int listID); + int setConnection(QString protocol, + QString hostname, + QString dbname, + QString user, + QString pass); + +private: + void databaseError(); + int addStratigraphy(int listID, std::vector<GEOLIB::Point*>* stations); + bool commitTransaction(QSqlQuery query); + + //data-insert functions -- be careful! + int addListToDB(std::string path, + std::string listName, + std::string catName, + GEOLIB::Station::StationType type); + bool addStationToDB(int listID, int stationID, std::string line); + bool addBoreholeToDB(int listID, int stationID, std::string line); + int addStratigraphyToDB(std::string path, int listID); + int addMeasuredValuesToDB(std::string path, int listID, int stationID); + + QSqlDatabase _db; + GEOLIB::GEOObjects* _geoObjects; + +signals: + void listLoaded(QString listName); +}; +#endif //DATABASECONNECTION_H diff --git a/Gui/DataView/DatabaseResultView.ui b/Gui/DataView/DatabaseResultView.ui new file mode 100644 index 0000000000000000000000000000000000000000..81c25edeef525c24c972330e9ca16e568af7337d --- /dev/null +++ b/Gui/DataView/DatabaseResultView.ui @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>DatabaseResultsView</class> + <widget class="QDialog" name="DatabaseResultsView"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>290</height> + </rect> + </property> + <property name="windowTitle"> + <string>Existing Datasets</string> + </property> + <widget class="QTableView" name="queryView"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>381</width> + <height>231</height> + </rect> + </property> + </widget> + <widget class="QPushButton" name="openButton"> + <property name="geometry"> + <rect> + <x>70</x> + <y>250</y> + <width>121</width> + <height>31</height> + </rect> + </property> + <property name="text"> + <string>Open Dataset</string> + </property> + </widget> + <widget class="QPushButton" name="cancelButton"> + <property name="geometry"> + <rect> + <x>210</x> + <y>250</y> + <width>121</width> + <height>31</height> + </rect> + </property> + <property name="text"> + <string>Cancel</string> + </property> + </widget> + </widget> + <resources/> + <connections/> +</ui> diff --git a/Gui/DataView/DiagramView/CMakeLists.txt b/Gui/DataView/DiagramView/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a7f258c7ccc55968bfce55840349a64d89faf440 --- /dev/null +++ b/Gui/DataView/DiagramView/CMakeLists.txt @@ -0,0 +1,71 @@ +# Source files +set( SOURCES + DetailWindow.cpp + DiagramList.cpp + DiagramPrefsDialog.cpp + DiagramScene.cpp + DiagramView.cpp + QArrow.cpp + QGraphicsGrid.cpp +) + +# Moc Header files +set( MOC_HEADERS + DetailWindow.h + DiagramPrefsDialog.h + DiagramView.h +) + +# Header files +set( HEADERS + DiagramList.h + QArrow.h + QGraphicsGrid.h + DiagramScene.h +) + +# UI files +set( UIS + DetailWindow.ui + DiagramPrefs.ui +) + +# Run Qts user interface compiler uic on .ui files +qt4_wrap_ui( UI_HEADERS ${UIS} ) + +# Run Qts meta object compiler moc on header files +qt4_wrap_cpp( MOC_SOURCES ${MOC_HEADERS} ) + +# Include the headers which are generated by uic and moc +# and include additional header +include_directories( + ${CMAKE_SOURCE_DIR}/Qt/DataView/DiagramView + ${CMAKE_BINARY_DIR}/Qt/DataView/DiagramView + ${CMAKE_BINARY_DIR}/Qt/DataView + ${CMAKE_SOURCE_DIR}/Base + ${CMAKE_SOURCE_DIR}/GEO + ${CMAKE_SOURCE_DIR}/Qt/Base + ${CMAKE_SOURCE_DIR}/Qt/DataView + ${CMAKE_SOURCE_DIR}/MathLib +) + +# Put moc files in a project folder +source_group("Moc Files" REGULAR_EXPRESSION moc_*) + + + +# Create the library +#add_executable( DiagramView +add_library( DiagramView STATIC + ${SOURCES} + ${HEADERS} + ${MOC_HEADERS} + ${MOC_SOURCES} + ${UI_HEADERS} +) + +# Link Qt library +target_link_libraries( DiagramView + ${QT_LIBRARIES} + GEO +) diff --git a/Gui/DataView/DiagramView/DetailWindow.cpp b/Gui/DataView/DiagramView/DetailWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48b9a344a4882ae29c8c4df6fbdc117106f2c244 --- /dev/null +++ b/Gui/DataView/DiagramView/DetailWindow.cpp @@ -0,0 +1,148 @@ +/** + * \file DetailWindow.cpp + * KR Initial implementation + */ + +#include "Color.h" +#include "DetailWindow.h" +#include "DiagramPrefsDialog.h" + +#include <QFileDialog> +#include <QSettings> + +DetailWindow::DetailWindow(QWidget* parent) : QWidget(parent) +{ + setupUi(this); + stationView->setRenderHints( QPainter::Antialiasing ); + +/* + DiagramList* list = new DiagramList(); + DiagramList* list2 = new DiagramList(); + + + // ================================================== + // input files should be defined in WaterML + // inserting the details below into the list-objects + // kind of simulates the information that would be + // included in a WaterML-file and is needed for + // display + // ================================================== + + // make up list-object for the first test station + list->setName("Water Level Observation Station: Halberstadt 2002"); + list->setXLabel("Time"); + list->setYLabel("Water Level"); + list->setXUnit("day"); + list->setYUnit("metres"); + list->setColor(QColor(Qt::red)); + list->readList("c:\\project\\timeseries-a.stn"); + + // make up list-object for the second test station + list2->setName("Water Level Observation Station: Oschersleben 2002"); + list2->setXLabel("Time"); + list2->setYLabel("Water Level"); + list2->setXUnit("day"); + list2->setYUnit("metres"); + list2->setColor(QColor(Qt::green)); + list2->readList("c:\\project\\timeseries-b.stn"); + + // ================================================== + + + stationView->addGraph(list); + stationView->addGraph(list2); + + resizeWindow(); + */ +} + +DetailWindow::DetailWindow(QString filename, QWidget* parent) : QWidget(parent) +{ + setupUi(this); + stationView->setRenderHints( QPainter::Antialiasing ); + + std::vector<DiagramList*> lists; + DiagramList::readList(filename, lists); + + for (size_t i = 0; i < lists.size(); i++) + stationView->addGraph(lists[i]); + + resizeWindow(); +} + +DetailWindow::DetailWindow(DiagramList* list, QWidget* parent) : QWidget(parent) +{ + setupUi(this); + stationView->setRenderHints( QPainter::Antialiasing ); + stationView->addGraph(list); + resizeWindow(); +} + +DetailWindow::DetailWindow(std::vector<size_t> data, QWidget* parent) : QWidget(parent) +{ + setupUi(this); + size_t nEntries = data.size(); + std::vector< std::pair<float, float> > list_data(nEntries); + + for (size_t i=0; i<nEntries; i++) + list_data.push_back(std::pair<float, float>(static_cast<float>(i), static_cast<float>(data[i]))); + + DiagramList* list = new DiagramList(); + list->setList(list_data); + list->setXUnit("Value"); + list->setYUnit("Amount"); + list->setName("Histogram"); + stationView->setRenderHints( QPainter::Antialiasing ); + stationView->addGraph(list); + resizeWindow(); +} + +DetailWindow::~DetailWindow() +{ +} + +void DetailWindow::on_closeButton_clicked() +{ + this->close(); +} + +void DetailWindow::resizeWindow() +{ + int width = (stationView->getWidth() > 800) ? 800 : stationView->getWidth(); + int height = (stationView->getHeight() > 600) ? 600 : stationView->getHeight(); + resize(width, height); +} + +void DetailWindow::addList(DiagramList* list) +{ + GEOLIB::Color* c = GEOLIB::getRandomColor(); + QColor colour((*c)[0], (*c)[1], (*c)[2]); + delete c; + this->addList(list, colour); + resizeWindow(); +} + +void DetailWindow::addList(DiagramList* list, QColor c) +{ + list->setColor(c); + this->stationView->addGraph(list); +} + +void DetailWindow::on_addDataButton_clicked() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName( this, "Select data file to open", + settings.value( + "lastOpenedFileDirectory"). + toString(), + "Text files (*.txt);;All files (* *.*)"); + if (!fileName.isEmpty()) + { + QDir dir = QDir(fileName); + settings.setValue("lastOpenedFileDirectory", dir.absolutePath()); + DiagramPrefsDialog* prefs = new DiagramPrefsDialog(fileName, this); + prefs->setAttribute(Qt::WA_DeleteOnClose); + prefs->show(); + } +} + diff --git a/Gui/DataView/DiagramView/DetailWindow.h b/Gui/DataView/DiagramView/DetailWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..dc8af4c15ca380711e2dceae64346734f6d3f9a1 --- /dev/null +++ b/Gui/DataView/DiagramView/DetailWindow.h @@ -0,0 +1,59 @@ +/** + * \file DetailWindow.h + * KR Initial implementation + */ + +#ifndef DETAILWINDOW_H +#define DETAILWINDOW_H + +#include "ui_DetailWindow.h" +#include <QtGui/QWidget> + +/** + * \brief Creates a window containing a diagram. + */ +class DetailWindow : public QWidget, private Ui_DetailWindow +{ + Q_OBJECT + +public: + /// Creates an empty diagram window. + DetailWindow(QWidget* parent = 0); + /** + * Creates a window containing a diagram. + * \param filename ASCII file containing x and y values for the graph to be displayed. + * \param parent The parent QWidget. + */ + DetailWindow(QString filename, QWidget* parent = 0); + + /** + * Creates a window containing a diagram + * \param list A QDiagramList containing all the data points and necessary metainformation for a graph to be displayed + * \param parent The parent QWidget. + */ + DetailWindow(DiagramList* list, QWidget* parent = 0); + + DetailWindow(std::vector<size_t> data, QWidget* parent = 0); + + ~DetailWindow(void); + + /** + * Adds another plot to window. Axes are automatically resized, a random color is used. + */ + void addList(DiagramList* list); + + /** + * Adds another plot with a given colour to window. Axes are automatically resized. + */ + void addList(DiagramList* list, QColor c); + +private: + /// Automatically resize window based on the measurements of the included graphs. + void resizeWindow(); + +private slots: + void on_addDataButton_clicked(); + void on_closeButton_clicked(); +}; + +#endif //DETAILWINDOW_H diff --git a/Gui/DataView/DiagramView/DetailWindow.ui b/Gui/DataView/DiagramView/DetailWindow.ui new file mode 100644 index 0000000000000000000000000000000000000000..6ebcf53db90ffc2c37ec662c2c06eab5c6225e8a --- /dev/null +++ b/Gui/DataView/DiagramView/DetailWindow.ui @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>DetailWindow</class> + <widget class="QWidget" name="DetailWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>564</width> + <height>317</height> + </rect> + </property> + <property name="windowTitle"> + <string>Observation Station</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="DiagramView" name="stationView"> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + </widget> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QPushButton" name="addDataButton"> + <property name="text"> + <string>Add Data...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="closeButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="text"> + <string>Close</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>DiagramView</class> + <extends>QGraphicsView</extends> + <header location="global">DiagramView.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Gui/DataView/DiagramView/DiagramList.cpp b/Gui/DataView/DiagramView/DiagramList.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d74f4180208d4f0b3c2b9da97c68f09f287cb0e1 --- /dev/null +++ b/Gui/DataView/DiagramView/DiagramList.cpp @@ -0,0 +1,324 @@ +/** + * \file DiagramList.cpp + * KR Initial implementation + */ + +#include "DiagramList.h" +#include "DateTools.h" +#include "StringTools.h" +#include "SensorData.h" +#include <QFile> +#include <QTextStream> +#include <limits> + +DiagramList::DiagramList() : _maxX(0), _maxY(0), _minX(0), _minY(0), _xLabel(""), _yLabel(""), + _xUnit(""), _yUnit(""), _startDate() +{ +} + +DiagramList::~DiagramList() +{ +} + +float DiagramList::calcMinXValue() +{ + float min = std::numeric_limits<float>::max(); + size_t nCoords = _coords.size(); + for (size_t i = 0; i < nCoords; i++) + if (_coords[i].first < min) + min = _coords[i].first; + return min; +} + +float DiagramList::calcMaxXValue() +{ + float max = std::numeric_limits<float>::min(); + size_t nCoords = _coords.size(); + for (size_t i = 0; i < nCoords; i++) + if (_coords[i].first > max) + max = _coords[i].first; + return max; +} + +float DiagramList::calcMinYValue() +{ + float min = std::numeric_limits<float>::max(); + size_t nCoords = _coords.size(); + for (size_t i = 0; i < nCoords; i++) + if (_coords[i].second < min) + min = _coords[i].second; + return min; +} + +float DiagramList::calcMaxYValue() +{ + float max = std::numeric_limits<float>::min(); + size_t nCoords = _coords.size(); + for (size_t i = 0; i < nCoords; i++) + if (_coords[i].second > max) + max = _coords[i].second; + return max; +} + +bool DiagramList::getPath(QPainterPath &path, float scaleX, float scaleY) +{ + QPointF p; + if (getPoint(p,0)) + { + QPainterPath pp(QPointF(p.x() * scaleX, p.y() * scaleY)); + path = pp; + + size_t nCoords = _coords.size(); + for (size_t i = 1; i < nCoords; i++) + { + getPoint(p,i); + path.lineTo(QPointF(p.x() * scaleX, p.y() * scaleY)); + } + return true; + } + else + return false; +} + +bool DiagramList::getPoint(QPointF &p, size_t i) +{ + if (i < _coords.size()) + { + p.setX(_coords[i].first); + p.setY(_coords[i].second); + return true; + } + else + return false; +} + +/* + * Reads an external list into the coordinate arrays. + * This method uses files containing the following format: + * xValue <tab> yValue + * Both values may be int or double. + */ +/* + int DiagramList::readList(char* path) + { + int date; + double xVal, yVal; + QString line; + QStringList fields; + + QFile file(path); + QTextStream in( &file ); + + if (!file.open(QIODevice::ReadOnly)) + { + return 0; + } + + while (!in.atEnd()) { + line = in.readLine(); + fields = line.split('\t'); + if (fields.size() >= 2) { + xVal = fields.takeFirst().toDouble(); + yVal = fields.takeFirst().toDouble(); + xCoords.push_back(xVal); + yCoords.push_back(yVal); + } + else return 0; + } + + file.close(); + update(); + + return 1; + }*/ + +int DiagramList::readList(const QString &path, std::vector<DiagramList*> &lists) +{ + QFile file(path); + QTextStream in( &file ); + + if (!file.open(QIODevice::ReadOnly)) + { + qDebug("Could not open file..."); + return 0; + } + + QString line = in.readLine(); + QStringList fields = line.split('\t'); + int nLists(fields.size() - 1); + + if (fields.size() >= 2) + { + fields.takeFirst(); + for (int i = 0; i < nLists; i++) + { + DiagramList* l = new DiagramList; + l->setName(fields.takeFirst()); + //value = strtod(replaceString(",", ".", fields.takeFirst().toStdString()).c_str(),0); + //l->setStartDate(startDate); + //l->addNextPoint(0,value); + lists.push_back(l); + } + + bool first_loop(true); + int numberOfSecs(0); + double value(0); + QString stringDate(""); + QDateTime startDate, currentDate; + + while (!in.atEnd()) + { + line = in.readLine(); + fields = line.split('\t'); + if (fields.size() >= (nLists + 1)) + { + stringDate = fields.takeFirst(); + currentDate = getDateTime(stringDate); + if (first_loop) + { + startDate = currentDate; + for (int i = 0; i < nLists; i++) + lists[i]->setStartDate(startDate); + first_loop = false; + } + + numberOfSecs = startDate.secsTo(currentDate); + + for (int i = 0; i < nLists; i++) + { + value = strtod(replaceString(",", ".",fields.takeFirst().toStdString()).c_str(),0); + lists[i]->addNextPoint(numberOfSecs,value); + } + } + else + { + qDebug("Unexpected file format..."); + file.close(); + return 0; + } + } + } + else + { + qDebug("Unexpected file format..."); + file.close(); + return 0; + } + + file.close(); + + for (int i = 0; i < nLists; i++) + lists[i]->update(); + + return nLists; +} + +int DiagramList::readList(const SensorData* data, std::vector<DiagramList*> &lists) +{ + const std::vector<SensorDataType::type> time_series_names (data->getTimeSeriesNames()); + int nLists(time_series_names.size()); + + std::vector<size_t> time_steps; + if (data->getStepSize()>0) + { + const size_t start = data->getStartTime(); + const size_t end = data->getEndTime(); + const size_t stepsize = data->getStepSize(); + for (size_t i = start; i <= end; i+=stepsize) + time_steps.push_back(i); + } + else + time_steps = data->getTimeSteps(); + + bool is_date (false); + + if (!(int2date(time_steps[0])).empty()) + is_date = true; + + + size_t nValues (time_steps.size()); + + for (int i = 0; i < nLists; i++) + { + DiagramList* l = new DiagramList; + l->setName(QString::fromStdString(SensorData::convertSensorDataType2String(time_series_names[i]))); + l->setXLabel("Time"); + lists.push_back(l); + + const std::vector<float> *time_series = data->getTimeSeries(time_series_names[i]); + + if (is_date) + { + l->setXUnit("day"); + QDateTime startDate(getDateTime(QString::fromStdString(int2date(time_steps[0])))); + lists[i]->setStartDate(startDate); + int numberOfSecs(0); + for (size_t j = 0; j < nValues; j++) + { + numberOfSecs = startDate.secsTo(getDateTime(QString::fromStdString(int2date(time_steps[j])))); + lists[i]->addNextPoint(numberOfSecs, (*time_series)[j]); + } + } + else + { + l->setXUnit("time step"); + for (size_t j = 0; j < nValues; j++) + lists[i]->addNextPoint(time_steps[j], (*time_series)[j]); + } + + lists[i]->update(); + } + + return nLists; +} + +void DiagramList::setList(std::vector< std::pair<QDateTime, float> > coords) +{ + int numberOfDays; + + this->_startDate = coords[0].first; + _coords.push_back(std::pair<float, float>(0, coords[0].second)); + + size_t nCoords = coords.size(); + for (size_t i = 1; i < nCoords; i++) + { + numberOfDays = this->_startDate.daysTo(coords[i].first); + _coords.push_back(std::pair<float, float>(numberOfDays, coords[i].second)); + } + + update(); +} + +void DiagramList::setList(std::vector< std::pair<float, float> > coords) +{ + this->_startDate = QDateTime(); + size_t nCoords = coords.size(); + for (size_t i = 0; i < nCoords; i++) + _coords.push_back(coords[i]); + + update(); +} + +size_t DiagramList::size() +{ + if (!(_coords.empty())) + return _coords.size(); + else + return 0; +} + +void DiagramList::update() +{ + _minX = calcMinXValue(); + _maxX = calcMaxXValue(); + _minY = calcMinYValue(); + _maxY = calcMaxYValue(); +} + +QDateTime DiagramList::getDateTime(QString stringDate) +{ + if (stringDate.length() <= 10) + return QDateTime::fromString(stringDate, "dd.MM.yyyy"); + else + return QDateTime::fromString(stringDate, "dd.MM.yyyy.HH.mm.ss"); +} diff --git a/Gui/DataView/DiagramView/DiagramList.h b/Gui/DataView/DiagramView/DiagramList.h new file mode 100644 index 0000000000000000000000000000000000000000..143253e7a832afeedf9f2118f453f72608ba5b7e --- /dev/null +++ b/Gui/DataView/DiagramView/DiagramList.h @@ -0,0 +1,179 @@ +/** + * \file DiagramList.h + * KR Initial implementation + */ + +#ifndef DIAGRAMLIST_H +#define DIAGRAMLIST_H + +#include <QColor> +#include <QDateTime> +#include <QPainterPath> +#include <QPoint> +#include <vector> + +class SensorData; + +/** + * \brief A List of data points and all the necessary meta-information to draw a graph. + */ +class DiagramList +{ +public: + /// Constructur containing an empty list. + DiagramList(); + ~DiagramList(); + + /// Returns the colour of the graph. + QColor getColor() const { return _colour; } + + /// Returns the height of the bounding box of all data points within the list. + float height() const { return _maxY - _minY; } + + /// Returns the minimum x-value. + float minXValue() const { return _minX; } + + /// Returns the maximum x-value. + float maxXValue() const { return _maxX; } + + /// Returns the minimum y-value. + float minYValue() const { return _minY; } + + /// Returns the maximum y-value. + float maxYValue() const { return _maxY; } + + /// Returns the start date of this list + const QDateTime getStartDate() const { return _startDate; } + + /// Returns the name of the diagram. + QString getName() const { return _name; } + + /** + * Returns all the data points in form of a QPainterPath in scene coordinates. + * The order of the points is the same as in the vector of coordinates. + * \param path The path containing all data points. + * \param scaleX Scaling factor in x-direction. + * \param scaleY Scaling factor in y-direction. + * \return true if everything is alright. false if the size of the coordinate arrays don't match. + */ + bool getPath(QPainterPath &path, float scaleX, float scaleY); + + /** + * Returns the position of one point in the vector of coordinates. + * \param p The point-object that will be returned. + * \param i Number of the point to be returned. + * \return true if everything is alright. false if the point does not exist. + */ + bool getPoint(QPointF &p, size_t i); + + /// Returns the label associated with the x-axis + QString getXLabel() const { return _xLabel; } + + /// Returns the label associated with the y-axis + QString getYLabel() const { return _yLabel; } + + /// Returns the unit associated with the x-axis + QString getXUnit() const { return _xUnit; } + + /// Returns the unit associated with the y-axis + QString getYUnit() const { return _yUnit; } + + /** + * Reads information from a file. The reader assumes that values in the file are seperated + * by tabstops. Also, the first row should contain identifiers for the values and the first + * column should contain timestamps. Currently accepted timestamps are of the following + * formats: + * "dd.mm.yyyy" + * "dd.mm.yyyy.hh.mm.ss" (this is the timestamp format used for the UFZ database) + * For each column after the timestamps a new diagram list is created. + */ + static int readList(const QString &path, std::vector<DiagramList*> &list); + + static int readList(const SensorData* data, std::vector<DiagramList*> &list); + + /// Sets the colour of the graph. + void setColor(QColor c) { _colour = c; } + + /// Sets the name of the graph to be displayed in the caption. + void setName(QString name) { _name = name; } + + /// Adds a point at (x,y) to the list + void addNextPoint(float x, float y) { _coords.push_back(std::pair<float, float>(x, y)); } + + /// Sets the start date (i.e. the min-value of the x-axis). + void setStartDate(QDateTime date) { _startDate = date; } + + /// Specifies the meaning of the x Axis. + void setXLabel(QString label) { _xLabel = label; } + + /// Specifies the meaning of the y Axis. + void setYLabel(QString label) { _yLabel = label; } + + /** + * Sets the list of x/y-coordinates. + * \param coords List of coordinates. + */ + void setList(std::vector< std::pair<float, float> > coords); + + /** + * Sets the list of x/y-coordinates. + * Note: This function converts QDateTime values to float values of the number of + * days from the first date (which is set as day 0) + * \param coords List of coordinates. + */ + void setList(std::vector< std::pair<QDateTime, float> > coords); + + /// Specifies the unit of the x Axis. + void setXUnit(QString unit) { _xUnit = unit; } + + /// Specifies the unit of the y Axis. + void setYUnit(QString unit) { _yUnit = unit; } + + /// Returns the number of data points. + size_t size(); + + /// Returns the width of the bounding box of all data points within the list. + double width() const { return _maxX - _minX; } + +private: + /// Returns the minimum x-value of all the data points. + float calcMinXValue(); + + /// Returns the maximum x-value of all the data points. + float calcMaxXValue(); + + /// Returns the minimum y-value of all the data points. + float calcMinYValue(); + + /// Returns the maximum y-value of all the data points. + float calcMaxYValue(); + + static QDateTime getDateTime(QString s); + + /** + * Reads an ASCII file containing the coordinates in the following format: + * date (tab) value + * where 'date' is given as 'dd.mm.yyyy'. + * (Changes to that format are easily implemented using QTimeDate) + * \return Returns 1 if everything is alright. Returns 0 and displays an error message if there was an error. + */ + int readLine(std::ifstream inFile, QDateTime &cDate, float &cValue); + + /// Updates the bounds of the data points contained in the list. + void update(); + + float _maxX; + float _maxY; + float _minX; + float _minY; + std::vector< std::pair<float, float> > _coords; + QString _name; + QString _xLabel; + QString _yLabel; + QString _xUnit; + QString _yUnit; + QColor _colour; + QDateTime _startDate; +}; + +#endif //DIAGRAMLIST_H diff --git a/Gui/DataView/DiagramView/DiagramPrefs.ui b/Gui/DataView/DiagramView/DiagramPrefs.ui new file mode 100644 index 0000000000000000000000000000000000000000..19ca90608a4368f247d84c664c690bc2bdb182e0 --- /dev/null +++ b/Gui/DataView/DiagramView/DiagramPrefs.ui @@ -0,0 +1,152 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>DiagramPrefs</class> + <widget class="QDialog" name="DiagramPrefs"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>267</width> + <height>236</height> + </rect> + </property> + <property name="windowTitle"> + <string>Diagram Preferences</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QLabel" name="stationTypeLabel"> + <property name="text"> + <string>StationType</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="stationNameLabel"> + <property name="font"> + <font> + <family>MS Shell Dlg 2</family> + <pointsize>10</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>StationName</string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="viewDataLabel"> + <property name="text"> + <string>View Data</string> + </property> + </widget> + </item> + <item> + <layout class="QGridLayout" name="DateBoundsLayout"> + <property name="margin"> + <number>10</number> + </property> + <property name="spacing"> + <number>20</number> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="fromDateLabel"> + <property name="text"> + <string>From:</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="toDateLabel"> + <property name="text"> + <string>To:</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="toDateLine"/> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="fromDateLine"/> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="CheckBoxLayout"/> + </item> + <item> + <layout class="QHBoxLayout" name="ButtonLayout"> + <property name="topMargin"> + <number>10</number> + </property> + <property name="bottomMargin"> + <number>10</number> + </property> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="loadFileButton"> + <property name="text"> + <string>Load File</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <tabstops> + <tabstop>fromDateLine</tabstop> + <tabstop>toDateLine</tabstop> + <tabstop>buttonBox</tabstop> + <tabstop>loadFileButton</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>DiagramPrefs</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>DiagramPrefs</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/DiagramView/DiagramPrefsDialog.cpp b/Gui/DataView/DiagramView/DiagramPrefsDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13d47bf19d8b54679d258b847f4e0d043ead0eea --- /dev/null +++ b/Gui/DataView/DiagramView/DiagramPrefsDialog.cpp @@ -0,0 +1,206 @@ +/** + * \file DiagramPrefsDialog.cpp + * KR Initial implementation + */ + +#include "DatabaseConnection.h" +#include "DetailWindow.h" +#include "DiagramList.h" +#include "DiagramPrefsDialog.h" +#include "OGSError.h" +#include "Station.h" + +#include <QCheckBox> +#include <QFileDialog> +#include <QMessageBox> + +DiagramPrefsDialog::DiagramPrefsDialog(const GEOLIB::Station* stn, + const QString &listName, + DatabaseConnection* db, + QDialog* parent) + : QDialog(parent), _window(NULL) +{ + setAttribute(Qt::WA_DeleteOnClose); + + _listID = -1; + _stationID = -1; + setupUi(this); + stationNameLabel->setText(QString::fromStdString(stn->getName())); + stationTypeLabel->setText(listName); + + if (db) + { + _db = db; + _listID = _db->getListID(listName, (*stn)[0], (*stn)[1]); + _stationID = _db->getStationID(_listID, (*stn)[0], (*stn)[1]); + if (_listID > 0 && _stationID > 0) + { + QString startDate, endDate; + if (_db->getDateBounds(_listID, _stationID, startDate, endDate)) + { + fromDateLine->setText(startDate); + toDateLine->setText(endDate); + } + } + } +} + +DiagramPrefsDialog::DiagramPrefsDialog(GEOLIB::Station* stn, QDialog* parent) + : QDialog(parent), _window(NULL) +{ + setupUi(this); + stationNameLabel->setText(QString::fromStdString(stn->getName())); + stationTypeLabel->setText(""); + DiagramList::readList(stn->getSensorData(), _list); + + fromDateLine->setText(QString::number(stn->getSensorData()->getStartTime())); + toDateLine->setText(QString::number(stn->getSensorData()->getEndTime())); + this->createVisibilityCheckboxes(); +} + +DiagramPrefsDialog::DiagramPrefsDialog(const QString &filename, + DetailWindow* window, + QDialog* parent) + : QDialog(parent), _window(window) +{ + QFileInfo fi(filename); + setupUi(this); + stationNameLabel->setText(fi.baseName()); + stationTypeLabel->setText(""); + this->loadFile(filename); +} + +DiagramPrefsDialog::~DiagramPrefsDialog() +{ + this->destroy(); +} + +void DiagramPrefsDialog::accept() +{ + if ((fromDateLine->text().length() > 0) && (toDateLine->text().length() > 0) && + (!_list.empty())) + { + if (_list[0]->size() == 0) // data will be read from the database (if data has been loaded from file, size is already >0) + + if (_listID > 0 && _stationID > 0) + { + std::vector< std::pair<QDateTime, float> > values; + _db->loadValues(_listID, _stationID, + QDateTime::fromString( + fromDateLine->text(), + "dd.MM.yyyy"), + QDateTime::fromString(toDateLine->text(), + "dd.MM.yyyy"), values); + if (!loadList(values)) + OGSError::box("No data found."); + } + + // data has been loaded + if (_list[0]->size() > 0) + { + bool window_is_empty(false); + if (_window == NULL) + { + _window = new DetailWindow(); + _window->setAttribute(Qt::WA_DeleteOnClose); + window_is_empty = true; + } + + for (size_t i = 0; i < _list.size(); i++) + if (this->_visability[i]->isChecked()) + { + _window->addList(_list[i]); + window_is_empty = false; + } + + if (!window_is_empty) + { + _window->show(); + this->done(QDialog::Accepted); + } + else + { + delete _window; + _window = NULL; + OGSError::box("No dataset selected."); + } + } + else + { + OGSError::box("Invalid station data."); + this->done(QDialog::Rejected); + } + } + else + OGSError::box("No data found..."); +} + +void DiagramPrefsDialog::reject() +{ + this->done(QDialog::Rejected); +} + +void DiagramPrefsDialog::on_loadFileButton_clicked() +{ + QString fileName = QFileDialog::getOpenFileName(this, + "Select time series file to open", + "", + "Time series files (*.stn *.txt)"); + if (!fileName.isEmpty()) + loadFile(fileName); +} + +int DiagramPrefsDialog::loadFile(const QString &filename) +{ + if (DiagramList::readList(filename, _list)) + { + for (size_t i = 0; i < _list.size(); i++) + { + //_list[i]->setName(stationTypeLabel->text() + ": " + stationNameLabel->text()); + _list[i]->setXLabel("Time"); + //_list[i]->setYLabel("Water Level"); + _list[i]->setXUnit("day"); + //_list[i]->setYUnit("metres"); + _list[i]->setColor(QColor(Qt::red)); + } + fromDateLine->setText(_list[0]->getStartDate().toString("dd.MM.yyyy")); //QString::number(_list[0]->minXValue())); + QDateTime endDate = + _list[0]->getStartDate().addSecs(static_cast<int>(_list[0]->maxXValue())); + toDateLine->setText(endDate.toString("dd.MM.yyyy")); //QString::number(_list[0]->maxXValue())); + this->createVisibilityCheckboxes(); + return 1; + } + + OGSError::box("Error reading file."); + return 0; +} + +int DiagramPrefsDialog::loadList(const std::vector< std::pair<QDateTime, float> > &coords) +{ + if (!coords.empty()) + { + DiagramList* l = new DiagramList; + l->setName(stationTypeLabel->text() + ": " + stationNameLabel->text()); + l->setXLabel("Time"); + //l->setYLabel("Water Level"); + l->setXUnit("day"); + //l->setYUnit("metres"); + l->setColor(QColor(Qt::red)); + l->setList(coords); + _list.push_back(l); + return 1; + } + return 0; +} + +void DiagramPrefsDialog::createVisibilityCheckboxes() +{ + for (size_t i = 0; i < _list.size(); i++) + { + QCheckBox* box = new QCheckBox(_list[i]->getName()); + box->setChecked(true); + this->CheckBoxLayout->addWidget(box); + _visability.push_back(box); + } +} + diff --git a/Gui/DataView/DiagramView/DiagramPrefsDialog.h b/Gui/DataView/DiagramView/DiagramPrefsDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..ed683b1aa24c3eb3660499532ca40081633bcfff --- /dev/null +++ b/Gui/DataView/DiagramView/DiagramPrefsDialog.h @@ -0,0 +1,111 @@ +/** + * \file DiagramPrefsDialog.h + * KR Initial implementation + */ + +#ifndef DIAGRAMPREFSDIALOG_H +#define DIAGRAMPREFSDIALOG_H + +#include "ui_DiagramPrefs.h" +#include <QtGui/QMainWindow> + +class DatabaseConnection; +class DetailWindow; +class DiagramList; +class QCheckBox; + +namespace GEOLIB +{ +class Station; +} + +/** + * \brief A dialog that allows for setting preferences for a requested diagram. + * + * A dialog that allows for setting preferences for a requested diagram. Note: In the current version + * this dialog only works when requesting data from a database. Visualisation of data from an ASCII-file + * is still possible using the "Load File"-button but setting the preferences will not work (i.e. it is + * only possible to visualise all the data in the file with default preferences. + */ +class DiagramPrefsDialog : public QDialog, private Ui_DiagramPrefs +{ + Q_OBJECT + +public: + /** + * Opens a new dialog based on station and the list this station belongs to. If a database connection + * is available, the program will try to find data associated with the station, otherwise data can be + * loaded from a file. + * \param stn The station object associated the diagram. + * \param listName The station list the station belongs to. + * \param db The database connection were the diagram-related data can be found + * \param parent The parent QDialog. + */ + DiagramPrefsDialog(const GEOLIB::Station* stn, + const QString &listName, + DatabaseConnection* db, + QDialog* parent = 0); + + /** + * Opens a new dialog and automatically reads data from the associated station object. + * \param stn The station object associated the diagram. + * \param parent The parent QDialog. + */ + DiagramPrefsDialog(GEOLIB::Station* stn, QDialog* parent = 0); + + /** + * Opens a new dialog and automatically reads data from the specified file. The diagram is not associated + * with any geometric object. + * \param filename File containing data for the diagram(s) to be visualised. + * \param parent The parent QDialog. + */ + DiagramPrefsDialog(const QString &filename, + DetailWindow* window = NULL, + QDialog* parent = 0); + + ~DiagramPrefsDialog(void); + +private: + /** + * Creates checkboxes for every list of data values found. Per default all of these are checked, i.e. all + * diagrams will be visualised. Any checkbox the user unchecks will result in the associated data not being + * visualised. + */ + void createVisibilityCheckboxes(); + + /** + * Loading data from a file + * \param filename Name of the file containing the data + * return 1 if everything is okay, 0 and an error message if there were errors + */ + int loadFile(const QString &filename); + + /** + * Setting up the QDiagramList object were the time series data will be stored + * \param coords List of coordinates. + * return 1 if everything is okay, 0 and an error message if there were errors + */ + int loadList(const std::vector< std::pair<QDateTime, float> > &coords); + + std::vector<DiagramList*> _list; + std::vector<QCheckBox*> _visability; + DatabaseConnection* _db; + int _listID; + int _stationID; + DetailWindow* _window; + +private slots: + /// Instructions if the OK-Button has been pressed. + /// Note: Clicking the "Load from file"-button overrides the database input! + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + + /// Instructions if the "Load File"-Button has been pressed. + void on_loadFileButton_clicked(); + +signals: +}; + +#endif //DIAGRAMPREFSDIALOG_H diff --git a/Gui/DataView/DiagramView/DiagramScene.cpp b/Gui/DataView/DiagramView/DiagramScene.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b845561aac5e5d8027766678fad8f50f9ac460e --- /dev/null +++ b/Gui/DataView/DiagramView/DiagramScene.cpp @@ -0,0 +1,347 @@ +/** + * \file DiagramScene.cpp + * KR Initial implementation + */ + +#include "DiagramScene.h" +#include <limits> +#include <math.h> + +// default size of a new window +const float DEFAULTX = 500.0; +const float DEFAULTY = 300.0; + +/** + * Creates a new scene. Since no data points are given some default + * values are used for constructing all the necessary objects. + */ +DiagramScene::DiagramScene(QObject* parent) : QGraphicsScene(parent) +{ + _bounds.setRect(0,0,1,1); + initialize(); +} + +/** + * Creates a new scene. + * \param list includes all necessary information of the graph to display. + * \param parent The parent QObject. + */ +DiagramScene::DiagramScene(DiagramList* list, QObject* parent) : QGraphicsScene(parent) +{ + setDiagramBoundaries(list); + initialize(); +} + +DiagramScene::~DiagramScene() +{ + delete _grid; + delete _xAxis; + delete _yAxis; + delete _xLabel; + delete _yLabel; + delete _xUnit; + delete _yUnit; + for (int i = 0; i < _graphCaptions.size(); i++) + delete _graphCaptions[i]; + _graphCaptions.clear(); + for (int i = 0; i < _graphs.size(); i++) + delete _graphs[i]; + _graphs.clear(); + for (int i = 0; i < _xTicksText.size(); i++) + delete _xTicksText[i]; + _xTicksText.clear(); + for (int i = 0; i < _yTicksText.size(); i++) + delete _yTicksText[i]; + _yTicksText.clear(); + for (int i = 0; i < _lists.size(); i++) + delete _lists[i]; + _lists.clear(); +} + +/// Adds an arrow object to the diagram which might be used as a coordinate axis, etc. +QArrow* DiagramScene::addArrow(float length, float angle, QPen &pen) +{ + QArrow* arrow = new QArrow(length, angle, 8, 5, pen); + addItem(arrow); + return arrow; +} + +/// Adds a caption for a graph beneath the actual diagram. +void DiagramScene::addCaption(const QString &name, QPen &pen) +{ + QGraphicsItemGroup* caption = new QGraphicsItemGroup(NULL); + QGraphicsLineItem* l = addLine(0,0,100,0,pen); + QGraphicsTextItem* t = addText(name); + l->setPos(0,0); + t->setPos(110, -(t->boundingRect()).height() / 2); + caption->addToGroup(l); + caption->addToGroup(t); + caption->setFlag(QGraphicsItem::ItemIgnoresTransformations, true); + + _graphCaptions.push_back(caption); + addItem(_graphCaptions[_graphCaptions.size() - 1]); +} + +/// Adds a graph to the scene, including all data points and meta-information. +void DiagramScene::addGraph(DiagramList* list) +{ + setDiagramBoundaries(list); + adjustScaling(); + _xLabel->setPlainText(list->getXLabel()); + _yLabel->setPlainText(list->getYLabel()); + _xUnit->setPlainText(list->getXUnit()); + _yUnit->setPlainText(list->getYUnit()); + + clearGrid(); + constructGrid(); + + _lists.push_back(list); + for (int i = 0; i < _lists.size(); i++) + drawGraph(_lists[i]); + + update(); +} + +/// Adds a grid-object to the scene +QGraphicsGrid* DiagramScene::addGrid(const QRectF &rect, int xTicks, int yTicks, const QPen &pen) +{ + QGraphicsGrid* g = new QGraphicsGrid(rect, xTicks, yTicks, true, pen); + addItem(g); + return g; +} + +/// Adds a non-scalable text object to the scene +QNonScalableGraphicsTextItem* DiagramScene::addNonScalableText(const QString &text, + const QFont &font) +{ + QNonScalableGraphicsTextItem* item = new QNonScalableGraphicsTextItem(text); + item->setFont(font); + addItem(item); + return item; +} + +/// Resizes a given axis to "nice" dimensions and calculates an adequate number of ticks to be placed on it +void DiagramScene::adjustAxis(float &min, float &max, int &numberOfTicks) +{ + const int MinTicks = 4; + double grossStep = (max - min) / MinTicks; + double step = pow(10.0, floor(log10(grossStep))); + if (5 * step < grossStep) + step *= 5; + else if (2 * step < grossStep) + step *= 2; + numberOfTicks = int(ceil(max / step) - floor(min / step)); + if (numberOfTicks < MinTicks) + numberOfTicks = MinTicks; + min = floor(min / step) * step; + max = ceil(max / step) * step; +} + +///Calculates scaling factors to set coordinate system and graphs to default window size +void DiagramScene::adjustScaling() +{ + if ( (_unscaledBounds.width() > 0) && (_unscaledBounds.height() > 0)) + { + _scaleX = DEFAULTX / (_unscaledBounds.width()); + _scaleY = DEFAULTY / (_unscaledBounds.height()); + } +} + +/// Destroys the grid object (coordinate system) when a new graph is added. +void DiagramScene::clearGrid() +{ + if (!_lists.isEmpty()) + { + removeItem(_grid); + + for (int i = 0; i < _xTicksText.size(); ++i) + removeItem(_xTicksText[i]); + for (int j = 0; j < _yTicksText.size(); ++j) + removeItem(_yTicksText[j]); + for (int k = 0; k < _graphs.size(); k++) + removeItem(_graphs[k]); + for (int l = 0; l < _graphCaptions.size(); l++) + removeItem(_graphCaptions[l]); + + _xTicksText.clear(); + _yTicksText.clear(); + _graphs.clear(); + _graphCaptions.clear(); + } +} + +/// Adjusts the underlying grid based on the graphs that are displayed in the diagram +void DiagramScene::constructGrid() +{ + // be very careful with scaling parameters here! + int numXTicks, numYTicks; + float xMin = _unscaledBounds.left(); + float yMin = _unscaledBounds.top(); + float xMax = _unscaledBounds.right(); + float yMax = _unscaledBounds.bottom(); + + adjustAxis(xMin, xMax, numXTicks); + adjustAxis(yMin, yMax, numYTicks); + + // adjust boundaries of coordinate system according to scaling + _bounds.setRect( xMin * _scaleX, + yMin * _scaleY, + (xMax - xMin) * _scaleX, + (yMax - yMin) * _scaleY + ); + + QPen pen(Qt::black, 1, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin); + _grid = addGrid(_bounds, numXTicks, numYTicks, pen); + + if (_startDate == QDateTime()) + { + for (int i = 0; i <= numXTicks; ++i) + { + int x = static_cast<int>(_bounds.left() / _scaleX + + (i * (_bounds.width() / _scaleX) / numXTicks)); + _xTicksText.push_back(addNonScalableText(QString::number(x))); + _xTicksText.last()->setPos(x * _scaleX, _bounds.bottom() + 15); + } + } + else + { + for (int i = 0; i <= numXTicks; ++i) + { + int x = static_cast<int>(_bounds.left() / _scaleX + + (i * (_bounds.width() / _scaleX) / numXTicks)); + QDateTime currentDate = _startDate.addSecs(x); + _xTicksText.push_back(addNonScalableText(currentDate.toString("dd.MM.yyyy"))); + _xTicksText.last()->setPos(x * _scaleX, _bounds.bottom() + 15); + } + } + + for (int j = 0; j <= numYTicks; ++j) + { + float y = _bounds.bottom() / _scaleY - + (j * (_bounds.height() / _scaleY) / numYTicks); + float label = _bounds.top() / _scaleY + + (j * (_bounds.height() / _scaleY) / numYTicks); + _yTicksText.push_back(addNonScalableText(QString::number(label))); + _yTicksText.last()->setPos(_bounds.left() - MARGIN / 2, y * _scaleY); + } +} + +/// Plots the graph. +void DiagramScene::drawGraph(DiagramList* list) +{ + QPainterPath path; + + if (list->getPath(path, _scaleX, _scaleY)) + { + QPen pen(list->getColor(), 2, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin); + pen.setCosmetic(true); + _graphs.push_back(addPath(path, pen)); + addCaption(list->getName(), pen); + + int last = _graphs.size() - 1; + + /** + * For correct display the graph needs to be flipped vertically and then + * translated back to its original position + */ + int verticalShift = + static_cast<int>(2 * + (list->minYValue() * + _scaleY) + (_graphs[last]->boundingRect()).height()); + _graphs[last]->setTransform(QTransform(QMatrix(1,0,0,-1,0,verticalShift))); + } +} + +/// Returns the y-value at which the x-axis should cross the y-axis. +/// This value is zero if minYValue<0<maxYValue and minYValue otherwise. +int DiagramScene::getXAxisOffset() +{ + return (_bounds.top() <= 0 && _bounds.bottom() > 0) ? (int)(_bounds.bottom() + + _bounds.top()) : (int)_bounds. + bottom(); +} + +/// Returns the x-value at which the y-axis should cross the x-axis. +/// This value is zero if minXValue<0<maxXValue and minXValue otherwise. +int DiagramScene::getYAxisOffset() +{ + return (_bounds.left() <= 0 && _bounds.right() > 0) ? 0 : (int)_bounds.left(); +} + +/// Initialises the coordinate axes, adds labels and/or units to the axes, +/// calculates axes-lengths, offsets, etc. +void DiagramScene::initialize() +{ + QPen pen(Qt::black, 2, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin); + pen.setCosmetic(true); + + setXAxis(addArrow(_bounds.width(), 0, pen)); + setYAxis(addArrow(_bounds.height(), -90, pen)); + _xLabel = addNonScalableText(" "); + _yLabel = addNonScalableText(" "); + _yLabel->rotate(-90); + + _xUnit = addNonScalableText(" "); + _yUnit = addNonScalableText(" "); + + update(); +} + +/// Updates the (unscaled) boundaries of the visible coordinate system when a new +/// list is added (boundaries are rescaled in the constructGrid-method +void DiagramScene::setDiagramBoundaries(DiagramList* list) +{ + if (!_lists.isEmpty()) + { + if (list->minXValue() < _unscaledBounds.left()) + _unscaledBounds.setLeft(list->minXValue()); + if (list->minYValue() < _unscaledBounds.top()) + _unscaledBounds.setTop(list->minYValue()); + if (list->maxXValue() > _unscaledBounds.right()) + _unscaledBounds.setRight(list->maxXValue()); + if (list->maxYValue() > _unscaledBounds.bottom()) + _unscaledBounds.setBottom(list->maxYValue()); + if (_startDate > list->getStartDate()) + _startDate = list->getStartDate(); + } + else + { + _unscaledBounds.setRect(list->minXValue(), list->minYValue(), + list->maxXValue() - list->minXValue(), + list->maxYValue() - list->minYValue()); + _startDate = list->getStartDate(); + } +} + +/** + * Updates the scene at the start and everytime new data points + * are added. Specifically, objects on the scene are assigned + * their position in the new coordinate system and are resized + * if necessary. + */ +void DiagramScene::update() +{ + _xAxis->setPos(_bounds.left(),getXAxisOffset()); + _yAxis->setPos(getYAxisOffset(),_bounds.bottom()); + _xAxis->setLength(_bounds.width()); + _yAxis->setLength(_bounds.height()); + + _xLabel->setPos( _bounds.left() + _bounds.width() / 2, _bounds.bottom() + 1.5 * MARGIN ); + _yLabel->setPos( _bounds.left() - 1.5 * MARGIN, _bounds.top() + _bounds.height() / 2 ); + + _xUnit->setPos( _bounds.right(), _bounds.bottom() + 1.2 * MARGIN); + _yUnit->setPos( _bounds.left(), _bounds.top() - 0.5 * MARGIN); + + /* update graphs and their captions */ + QRectF rect; + for (int i = 0; i < _graphs.size(); i++) + { + rect = _graphs[i]->boundingRect(); + int offset = static_cast<int>(fabs(rect.bottom() - _bounds.bottom()) + - fabs(rect.top() - _bounds.top())); + _graphs[i]->setPos(0, offset); + + rect = itemsBoundingRect(); + _graphCaptions[i]->setPos(_bounds.left(),rect.bottom() + 10); + } +} diff --git a/Gui/DataView/DiagramView/DiagramScene.h b/Gui/DataView/DiagramView/DiagramScene.h new file mode 100644 index 0000000000000000000000000000000000000000..466c3134e480a51610841a160f046f6a808c662a --- /dev/null +++ b/Gui/DataView/DiagramView/DiagramScene.h @@ -0,0 +1,74 @@ +/** + * \file DiagramScene.h + * KR Initial implementation + */ + +#ifndef DIAGRAMSCENE_H +#define DIAGRAMSCENE_H + +#include "DiagramList.h" +#include "QArrow.h" +#include "QGraphicsGrid.h" +#include "QNonScalableGraphicsTextItem.h" +#include <QGraphicsScene> + +class QDateTime; + +/** + * \brief A scene graph for a 2D Diagram including coordinate axes with labels and ticks for one or more plotted graphs. + */ +class DiagramScene : public QGraphicsScene +{ +public: + DiagramScene(QObject* parent = 0); + DiagramScene(DiagramList* list, QObject* parent = 0); + ~DiagramScene(); + + QArrow* addArrow(float length, float angle, QPen &pen); + void addGraph(DiagramList* list); + QGraphicsGrid* addGrid(const QRectF &rect, int xTicks, int yTicks, const QPen &pen); + + static const int MARGIN = 30; /// The margin between the boundary of the scene and the bounding box of all items within the scene + +private: + void addCaption(const QString &name, QPen &pen); + QNonScalableGraphicsTextItem* addNonScalableText(const QString &text, + const QFont &font = QFont()); + void adjustAxis(float &min, float &max, int &numberOfTicks); + void adjustScaling(); + void clearGrid(); + void constructGrid(); + void drawGraph(DiagramList* list); + int getXAxisOffset(); + int getYAxisOffset(); + void initialize(); + void setDiagramBoundaries(DiagramList* list); + + /// Sets an arrow as x-axis + void setXAxis(QArrow* arrow) { _xAxis = arrow; } + + /// Sets an arrow as y-axis + void setYAxis(QArrow* arrow) { _yAxis = arrow; } + + void update(); + + QRectF _bounds; + QRectF _unscaledBounds; + QVector<DiagramList*> _lists; + QVector<QGraphicsItemGroup*> _graphCaptions; + QVector<QGraphicsPathItem*> _graphs; + QGraphicsGrid* _grid; + QDateTime _startDate; + float _scaleX; + float _scaleY; + QArrow* _xAxis; + QArrow* _yAxis; + QNonScalableGraphicsTextItem* _xLabel; + QNonScalableGraphicsTextItem* _yLabel; + QNonScalableGraphicsTextItem* _xUnit; + QNonScalableGraphicsTextItem* _yUnit; + QVector<QNonScalableGraphicsTextItem*> _xTicksText; + QVector<QNonScalableGraphicsTextItem*> _yTicksText; +}; + +#endif //DIAGRAMSCENE_H diff --git a/Gui/DataView/DiagramView/DiagramView.cpp b/Gui/DataView/DiagramView/DiagramView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..44e9dd5ce8cd771d9755ea807ffe4243adaa1fa9 --- /dev/null +++ b/Gui/DataView/DiagramView/DiagramView.cpp @@ -0,0 +1,111 @@ +/** + * \file DiagramView.cpp + * KR Initial implementation + */ + +#include "DiagramView.h" +#include <QGraphicsTextItem> +#include <math.h> + +DiagramView::DiagramView(QWidget* parent) : QGraphicsView(parent) +{ + _scene = new DiagramScene(); + setScene(_scene); + initialize(); +} + +DiagramView::DiagramView(DiagramList* list, QWidget* parent) : QGraphicsView(parent) +{ + _scene = new DiagramScene(list); + setScene(_scene); + initialize(); +} + +DiagramView::~DiagramView() +{ + delete _scene; +} + +void DiagramView::addGraph(DiagramList* list) +{ + _scene->addGraph(list); + update(); +} + +int DiagramView::getHeight() +{ + return static_cast<int>((_scene->itemsBoundingRect()).height()); +} + +int DiagramView::getWidth() +{ + return static_cast<int>((_scene->itemsBoundingRect()).width()); +} + +/** + * Initialises the view. + */ +void DiagramView::initialize() +{ + //QMatrix currentMatrix = matrix(); + //setMatrix(currentMatrix * scene->getTransformationMatrix()); + + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + update(); +} + +/* + * Keeps the aspect ration of the labels when the view is resized. + * It is only necessary to call this if + * Qt::AspectRatioMode == Qt::IgnoreAspectRatio. + * Also, this method is kind of annoying because you have to set the + * appropriate transform for every single QGraphicsTextItem seperately. + */ +/* + void DiagramView::keepItemAspectRatio() + { + double xFactor = transform().mapRect(QRectF(0, 0, 1, 1)).width(); + double yFactor = transform().mapRect(QRectF(0, 0, 1, 1)).height(); + QMatrix invertedScaling; + invertedScaling.scale(1.0 , xFactor / yFactor); + + scene->xLabel->setTransform(QTransform(invertedScaling)); + scene->yLabel->setTransform(QTransform(invertedScaling)); + scene->yLabel->rotate(-90); + } + */ + +QSize DiagramView::minimumSizeHint() const +{ + return QSize(3 * _scene->MARGIN,2 * _scene->MARGIN); +} + +QSize DiagramView::sizeHint() const +{ + return QSize(6 * _scene->MARGIN, 4 * _scene->MARGIN); +} + +void DiagramView::resizeEvent(QResizeEvent* event) +{ + Q_UNUSED (event) + update(); + //keepItemAspectRatio(); +} + +/** + * Updates the view automatically when a new list is added or when + * the window containing the view is resized or changes its state. + * Basically, the methods makes sure that everything keeps looking + * as it is supposed to. + */ +void DiagramView::update() +{ + //setResizeAnchor(QGraphicsView::AnchorViewCenter); + QRectF viewRect = _scene->itemsBoundingRect(); + _scene->setSceneRect(viewRect); + QRectF sceneInView(0 /*_scene->MARGIN*/,_scene->MARGIN / 2, + viewRect.width() /*+_scene->MARGIN*/,viewRect.height() + _scene->MARGIN); + fitInView(sceneInView, Qt::IgnoreAspectRatio); +} diff --git a/Gui/DataView/DiagramView/DiagramView.h b/Gui/DataView/DiagramView/DiagramView.h new file mode 100644 index 0000000000000000000000000000000000000000..98e8f236414b9ba7b804b63cc73d01e7cf904d4c --- /dev/null +++ b/Gui/DataView/DiagramView/DiagramView.h @@ -0,0 +1,55 @@ +/** + * \file DiagramView.h + * KR Initial implementation + */ + +#ifndef DIAGRAMVIEW_H +#define DIAGRAMVIEW_H + +#include "DiagramScene.h" +#include <QGraphicsView> +#include <QtGui/QWidget> + +/** + * \brief A view in which to display a DiagramScene. + * + * A view in which to display a DiagramScene. It supports resizing of the window and loading of data into the diagram. + */ +class DiagramView : public QGraphicsView +{ + Q_OBJECT +public: + /** + * Creates an empty view. + */ + DiagramView(QWidget* parent = 0); + /** + * Creates a view already containing a graph + * \param list Contains a list of data points and metainformation to be displayed by the scene. + * \param parent The parent QWidget. + */ + DiagramView(DiagramList* list, QWidget* parent = 0); + ~DiagramView(); + + /// Adds a new graph to the scene. + void addGraph(DiagramList* list); + /// Returns the height of the bounding rectangle of all objects within the scene. + int getHeight(); + /// Returns the width of the bounding rectangle of all objects within the scene. + int getWidth(); + +protected: + /// Resizes the scene. + void resizeEvent(QResizeEvent* event); + +private: + void initialize(); + void keepItemAspectRatio(); + QSize minimumSizeHint() const; + QSize sizeHint() const; + void update(); + + DiagramScene* _scene; +}; + +#endif //DIAGRAMVIEW_H diff --git a/Gui/DataView/DiagramView/QArrow.cpp b/Gui/DataView/DiagramView/QArrow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1db08f7596557b9fbbdb1c0d0e82a30a7cb19354 --- /dev/null +++ b/Gui/DataView/DiagramView/QArrow.cpp @@ -0,0 +1,121 @@ +/** + * \file QArrow.cpp + * KR Initial implementation + */ + +#include "QArrow.h" +#include <QPainter> +#include <math.h> + +/** + * Creates an arrow as a QGraphicItem. + * \param l Length of the arrow + * \param a Orientation of the arrow + * \param hl Length of the arrow head + * \param hw Width of the arrow head + * \param pen The pen for drawing the arrow + * \param parent The parent QGraphicsItem. + */ +QArrow::QArrow(float l, float a, float hl, float hw, QPen &pen, + QGraphicsItem* parent) : QGraphicsItem(parent) +{ + _arrowLength = l; + _arrowAngle = a; + _headLength = hl; + _headWidth = hw; + _arrowPen = pen; +} + +/** + * Creates an arrow as a QGraphicItem. Length and width of the arrow head are given by default values. + * \param l Length of the arrow + * \param a Orientation of the arrow + * \param pen The pen for drawing the arrow + * \param parent The parent QGraphicsItem. + */ +QArrow::QArrow(float l, float a, QPen &pen, QGraphicsItem* parent) : QGraphicsItem(parent) +{ + _arrowLength = l; + _arrowAngle = a; + _headLength = 8; // default headlength + _headWidth = 5; // default headwidth + _arrowPen = pen; +} + +QArrow::~QArrow() +{ +} + +double QArrow::calcCos(double angle) +{ + return cos (angle * PI / 180); +} + +double QArrow::calcSin(double angle) +{ + return sin (angle * PI / 180); +} + +/// The bounding box of the arrow +QRectF QArrow::boundingRect() const +{ + double deltaX = cos(_arrowAngle) * _arrowLength; + double deltaY = sin(_arrowAngle) * _arrowLength; + + return QRectF(0, 0, deltaX, deltaY); +} + +/// Returns the length of the arrow. +double QArrow::getLength() +{ + return _arrowLength; +} + +/// Returns the orientation of the arrow +double QArrow::getAngle() +{ + return _arrowAngle; +} + +/** + * Overloaded paint-method from QGraphicsItem. + * Basically it draws a line with an arrowhead consisting of two short lines at the end + */ +void QArrow::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + Q_UNUSED (option) + Q_UNUSED (widget) + + double ddeltaX = calcCos(_arrowAngle) * _arrowLength; + double ddeltaY = calcSin(_arrowAngle) * _arrowLength; + double theta = atan(ddeltaY / ddeltaX); + double theta2 = (ddeltaX < 0.0) ? (theta + PI) : theta; + int lengthdeltaX = -static_cast<int>(cos(theta2) * _headLength); + int lengthdeltaY = -static_cast<int>(sin(theta2) * _headLength); + int widthdeltaX = static_cast<int>(sin(theta2) * _headWidth); + int widthdeltaY = static_cast<int>(cos(theta2) * _headWidth); + int deltaX = static_cast<int>(ddeltaX); + int deltaY = static_cast<int>(ddeltaY); + painter->setPen(_arrowPen); + painter->drawLine(0, 0, deltaX, deltaY); + painter->drawLine(deltaX, + deltaY, + deltaX + lengthdeltaX + widthdeltaX, + deltaY + lengthdeltaY - widthdeltaY); + painter->drawLine(deltaX, + deltaY, + deltaX + lengthdeltaX - widthdeltaX, + deltaY + lengthdeltaY + widthdeltaY); +} + +/// Changes orientation of the arrow. +void QArrow::setAngle(double a) +{ + _arrowAngle = a; +} + +/// Changes the length of the arrow. +void QArrow::setLength(double l) +{ + _arrowLength = l; +} diff --git a/Gui/DataView/DiagramView/QArrow.h b/Gui/DataView/DiagramView/QArrow.h new file mode 100644 index 0000000000000000000000000000000000000000..145904b9b9c7fab58359b38c77ba96baa00d137b --- /dev/null +++ b/Gui/DataView/DiagramView/QArrow.h @@ -0,0 +1,42 @@ +/** + * \file QArrow.h + * KR Initial implementation + */ + +#ifndef QARROW_H +#define QARROW_H + +#include <QGraphicsItem> +#include <QPen> + +const double PI = 3.14159265; + +/** + * \brief An arrow as a QGraphicsObject + */ +class QArrow : public QGraphicsItem +{ +public: + QArrow(float l, float a, float hl, float hw, QPen &pen, QGraphicsItem* parent = 0); + QArrow(float l, float a, QPen &pen, QGraphicsItem* parent = 0); + ~QArrow(); + + double getLength(); + double getAngle(); + void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget); + QRectF boundingRect() const; + void setAngle(double a); + void setLength(double l); + +private: + double calcCos(double angle); + double calcSin(double angle); + + float _arrowLength; + float _arrowAngle; + float _headLength; + float _headWidth; + QPen _arrowPen; +}; + +#endif //QARROW_H diff --git a/Gui/DataView/DiagramView/QGraphicsGrid.cpp b/Gui/DataView/DiagramView/QGraphicsGrid.cpp new file mode 100644 index 0000000000000000000000000000000000000000..01a40db427ec5bc80702d11479f02dc364cc8f7c --- /dev/null +++ b/Gui/DataView/DiagramView/QGraphicsGrid.cpp @@ -0,0 +1,225 @@ +/** + * \file QGraphicsGrid.cpp + * KR Initial implementation + */ + +#include "QGraphicsGrid.h" +#include <QPainter> + +/** + * Creates a grid using a QRectF object and a default pen and no ticks. + * \param rect A rectangle specifying the size of the grid. + * \param xCells The number of grid cells in x-direction. + * \param yCells The number of grid cells in y-direction. + * \param parent The parent QGraphicsItem. + */ +QGraphicsGrid::QGraphicsGrid(QRectF rect, int xCells, int yCells, + QGraphicsItem* parent) : QGraphicsItem(parent) +{ + _numberOfXCells = xCells; + _numberOfYCells = yCells; + _bounds = rect; + _showTicks = false; + + initDefaultPens(); +} + +/** + * Creates a grid by specifying its bounding rectangle using a default pen and no ticks. + * \param x X-coordinate for the lower left corner of the bounding rectangle for the grid. + * \param y Y-coordinate for the lower left corner of the bounding rectangle for the grid. + * \param width Width of the bounding rectangle. + * \param height Height of the bounding rectangle. + * \param xCells The number of grid cells in x-direction. + * \param yCells The number of grid cells in y-direction. + * \param parent The parent QGraphicsItem. + */ +QGraphicsGrid::QGraphicsGrid(int x, + int y, + int width, + int height, + int xCells, + int yCells, + QGraphicsItem* parent) : QGraphicsItem(parent) +{ + _numberOfXCells = xCells; + _numberOfYCells = yCells; + _bounds = QRectF(x,y,width,height); + _showTicks = false; + + initDefaultPens(); +} + +/** + * Creates a grid using a QRectF object and a default pen and no ticks. + * \param rect A rectangle specifying the size of the grid. + * \param xCells The number of grid cells in x-direction. + * \param yCells The number of grid cells in y-direction. + * \param ticks Specifies if ticks are displayed for the grid. + * \param pen The pen for drawing the grid. + * \param parent The parent QGraphicsItem. + */ +QGraphicsGrid::QGraphicsGrid(QRectF rect, + int xCells, + int yCells, + bool ticks, + QPen pen, + QGraphicsItem* parent) : QGraphicsItem(parent) +{ + _numberOfXCells = xCells; + _numberOfYCells = yCells; + _bounds = rect; + _showTicks = ticks; + + _outside = pen; + _outside.setCosmetic(true); + + _inside = pen; + QColor iColour = pen.color(); + iColour.setAlpha(125); + _inside.setColor(iColour); + _inside.setStyle(Qt::DotLine); + _inside.setCosmetic(true); +} + +/** + * Creates a grid by specifying its bounding rectangle using a default pen and no ticks. + * \param x X-coordinate for the lower left corner of the bounding rectangle for the grid. + * \param y Y-coordinate for the lower left corner of the bounding rectangle for the grid. + * \param width Width of the bounding rectangle. + * \param height Height of the bounding rectangle. + * \param xCells The number of grid cells in x-direction. + * \param yCells The number of grid cells in y-direction. + * \param ticks Specifies if ticks are displayed for the grid. + * \param pen The pen for drawing the grid. + * \param parent The parent QGraphicsItem. + */ +QGraphicsGrid::QGraphicsGrid(int x, + int y, + int width, + int height, + int xCells, + int yCells, + bool ticks, + QPen pen, + QGraphicsItem* parent) : QGraphicsItem(parent) +{ + _numberOfXCells = xCells; + _numberOfYCells = yCells; + _bounds = QRectF(x,y,width,height); + _showTicks = ticks; + + _outside = pen; + _outside.setCosmetic(true); + + _inside = pen; + QColor iColour = pen.color(); + iColour.setAlpha(125); + _inside.setColor(iColour); + _inside.setStyle(Qt::DotLine); + _inside.setCosmetic(true); +} + +QGraphicsGrid::~QGraphicsGrid() +{ +} + +/// Returns the bounding rectangle of the grid. +QRectF QGraphicsGrid::boundingRect() const +{ + return _bounds; +} + +/// Defines the default pens. +void QGraphicsGrid::initDefaultPens() +{ + QPen in(Qt::gray, 1, Qt::DotLine, Qt::SquareCap, Qt::RoundJoin); + QPen out(Qt::black, 1, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin); + _inside = in; + _outside = out; + _inside.setCosmetic(true); + _outside.setCosmetic(true); +} + +/// Paints the grid. +void QGraphicsGrid::paint(QPainter* painter, + const QStyleOptionGraphicsItem* option, + QWidget* widget) +{ + Q_UNUSED (option) + Q_UNUSED (widget) + + if (!_bounds.isValid()) + return; + + /* draw outside rectangle */ + QBrush brush(Qt::NoBrush); + painter->setPen(_outside); + painter->drawRect(_bounds); + + /* draw horizontal lines */ + for (int i = 0; i <= _numberOfXCells; ++i) + { + int x = + static_cast<int>(_bounds.left() + + (i * (_bounds.width() - 1) / _numberOfXCells)); + + if (i > 0 && i < _numberOfXCells) + { + painter->setPen(_inside); + painter->drawLine(x, (int)_bounds.top(), x, (int)_bounds.bottom()); + } + + /* draw ticks on x-axis */ + if (_showTicks) + { + //double label = bounds.left() + (i * bounds.width() / numberOfXCells); + painter->setPen(_outside); + painter->drawLine(x, (int)_bounds.bottom(), x, (int)_bounds.bottom() + 5); + //painter->drawText(x - margin, bounds.bottom() + 5, 2*margin, 20, + // Qt::AlignHCenter | Qt::AlignTop, QString::number(label)); + } + } + + /* draw vertical lines */ + for (int j = 0; j <= _numberOfYCells; ++j) + { + int y = + static_cast<int>(_bounds.bottom() - + (j * (_bounds.height() - 1) / _numberOfYCells)); + + if (j > 0 && j < _numberOfYCells) + { + painter->setPen(_inside); + painter->drawLine((int)_bounds.left(), y, (int)_bounds.right(), y); + } + + /* draw ticks on y-axis */ + if (_showTicks) + { + //double label = bounds.top() + (j * bounds.height() / numberOfYCells); + painter->setPen(_outside); + painter->drawLine((int)_bounds.left() - 5, y, (int)_bounds.left(), y); + //painter->drawText(bounds.left() - margin, y - 10, margin - 5, 20, + // Qt::AlignRight | Qt::AlignVCenter, QString::number(label)); + } + } +} + +/// Sets the number of cells in x direction. +void QGraphicsGrid::setNumberOfXCells(int xCells) +{ + _numberOfXCells = xCells; +} + +/// Sets the number of cells in y direction. +void QGraphicsGrid::setNumberOfYCells(int yCells) +{ + _numberOfYCells = yCells; +} + +/// Sets the bounding rectangle of the grid. +void QGraphicsGrid::setRect(int x, int y, int width, int height) +{ + _bounds = QRectF(x,y,width,height); +} diff --git a/Gui/DataView/DiagramView/QGraphicsGrid.h b/Gui/DataView/DiagramView/QGraphicsGrid.h new file mode 100644 index 0000000000000000000000000000000000000000..6f0645dde9970f0bdd302a0cdf84b463ac761d10 --- /dev/null +++ b/Gui/DataView/DiagramView/QGraphicsGrid.h @@ -0,0 +1,63 @@ +/** + * \file QGraphicsGrid.h + * KR Initial implementation + */ + +#ifndef QGRAPHICSGRID_H +#define QGRAPHICSGRID_H + +#include <QGraphicsItem> +#include <QPen> + +/** + * \brief A 2D carthesian grid as a QGraphicsItem. + * + * A 2D carthesian grid as a QGraphicsItem. The size of the grid cells is constant but can be anisotroph. + */ +class QGraphicsGrid : public QGraphicsItem +{ +public: + QGraphicsGrid(QRectF rect, int xCells, int yCells, QGraphicsItem* parent = 0); + QGraphicsGrid(int x, + int y, + int width, + int height, + int xCells, + int yCells, + QGraphicsItem* parent = 0); + QGraphicsGrid(QRectF rect, + int xCells, + int yCells, + bool ticks, + QPen pen, + QGraphicsItem* parent = 0); + QGraphicsGrid(int x, + int y, + int width, + int height, + int xCells, + int yCells, + bool ticks, + QPen pen, + QGraphicsItem* parent = 0); + ~QGraphicsGrid(); + + QRectF boundingRect() const; + void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget); + void setNumberOfXCells(int xCells); + void setNumberOfYCells(int yCells); + void setRect(QRectF rect); + void setRect(int x, int y, int width, int height); + +private: + void initDefaultPens(); + + QPen _inside; + QPen _outside; + QRectF _bounds; + int _numberOfXCells; + int _numberOfYCells; + bool _showTicks; +}; + +#endif //QGRAPHICSGRID_H diff --git a/Gui/DataView/DirectConditionGenerator.cpp b/Gui/DataView/DirectConditionGenerator.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ff691b095995ddbf3a1928aaee1f74e68ef73b43 --- /dev/null +++ b/Gui/DataView/DirectConditionGenerator.cpp @@ -0,0 +1,168 @@ +/** + * \file DirectConditionGenerator.cpp + * 2012/01/04 KR Initial implementation + * + */ + +#include "DirectConditionGenerator.h" + +#include "VtkRaster.h" +#include "MshEditor.h" +#include "PointWithID.h" + +#include "fem_ele.h" + +const std::vector< std::pair<size_t,double> >& DirectConditionGenerator::directToSurfaceNodes(const MeshLib::CFEMesh &mesh, const std::string &filename) +{ + if (_direct_values.empty()) + { + double origin_x(0), origin_y(0), delta(0); + size_t imgwidth(0), imgheight(0); + + float* img = VtkRaster::loadDataFromASC(filename, origin_x, origin_y, imgwidth, imgheight, delta); + if (img == 0) + { + std::cout << "Error in DirectConditionGenerator::directWithSurfaceIntegration() - could not load vtk raster." << std::endl; + return _direct_values; + } + + const std::vector<GEOLIB::PointWithID*> surface_nodes ( MshEditor::getSurfaceNodes(mesh) ); + //std::vector<MeshLib::CNode*> nodes = mesh.nod_vector; + const size_t nNodes(surface_nodes.size()); + _direct_values.reserve(nNodes); + for (size_t i=0; i<nNodes; i++) + { + const double* coords (surface_nodes[i]->getData()); + + if (coords[0]>=origin_x && coords[0]<(origin_x+(delta*imgwidth)) && coords[1]>=origin_y && coords[1]<(origin_y+(delta*imgheight))) + { + int cell_x = static_cast<int>(floor((coords[0] - origin_x)/delta)); + int cell_y = static_cast<int>(floor((coords[1] - origin_y)/delta)); + + // if node outside of raster use raster boundary values + cell_x = (cell_x < 0) ? 0 : ((cell_x > static_cast<int>(imgwidth )) ? (imgwidth-1) : cell_x); + cell_y = (cell_y < 0) ? 0 : ((cell_y > static_cast<int>(imgheight)) ? (imgheight-1) : cell_y); + + size_t index = cell_y*imgwidth+cell_x; + if (fabs(img[index] + 9999) > std::numeric_limits<float>::min()) + _direct_values.push_back( std::pair<size_t, double>(surface_nodes[i]->getID(),img[index*2]) ); + } + } + + delete[] img; + + } + else + std::cout << "Error in DirectConditionGenerator::directToSurfaceNodes() - Data vector contains outdated values..." << std::endl; + + return _direct_values; +} + + +const std::vector< std::pair<size_t,double> >& DirectConditionGenerator::directWithSurfaceIntegration(MeshLib::CFEMesh &mesh, const std::string &filename, double scaling) +{ + double no_data_value (-9999); // TODO: get this from asc-reader! + + if (_direct_values.empty()) + { + mesh.MarkInterface_mHM_Hydro_3D(); // mark element faces on the surface + + double origin_x(0), origin_y(0), delta(0); + size_t imgwidth(0), imgheight(0); + double node_val[8] = {0,0,0,0,0,0,0,0}; // maximum possible number of nodes per face (just in case ...) + + FiniteElement::CElement* fem ( new FiniteElement::CElement(mesh.GetCoordinateFlag()) ); + + float* img = 0; + if (filename.substr(filename.length()-3,3).compare("asc") == 0) + img = VtkRaster::loadDataFromASC(filename, origin_x, origin_y, imgwidth, imgheight, delta); + else if (filename.substr(filename.length()-3,3).compare("grd") == 0) + img = VtkRaster::loadDataFromSurfer(filename, origin_x, origin_y, imgwidth, imgheight, delta); + + if (img == 0) + { + std::cout << "Error in DirectConditionGenerator::directWithSurfaceIntegration() - could not load vtk raster." << std::endl; + return _direct_values; + } + + const size_t nNodes(mesh.nod_vector.size()); + std::vector<double> val(nNodes, 0.0); + for(size_t i = 0; i < nNodes; i++) + mesh.nod_vector[i]->SetMark(false); + + // copied from CFEMesh::Precipitation2NeumannBC() by WW + size_t nFaces = mesh.face_vector.size(); + for(size_t i=0; i<nFaces; i++) + { + MeshLib::CElem* elem = mesh.face_vector[i]; + if (!elem->GetMark()) + continue; + + // if face is on the surface of the mesh + size_t nElemNodes = elem->GetNodesNumber(false); + for(size_t k=0; k<nElemNodes; k++) + node_val[k] = 0.0; + + // get values from the raster for all nodes of the face + for(size_t k=0; k<nElemNodes; k++) + { + double const* const pnt_k (elem->GetNode(k)->getData()); + int cell_x = static_cast<int>(floor((pnt_k[0] - origin_x) / delta)); + int cell_y = static_cast<int>(floor((pnt_k[1] - origin_y) / delta)); + + // if node outside of raster use raster boundary values + cell_x = (cell_x < 0) ? 0 : ((static_cast<size_t>(cell_x) > imgwidth) ? (imgwidth-1) : cell_x); + cell_y = (cell_y < 0) ? 0 : ((static_cast<size_t>(cell_y) > imgheight) ? (imgheight-1) : cell_y); + + node_val[k] = img[ 2 * (cell_y * imgwidth + cell_x) ]; + if (fabs(node_val[k] - no_data_value) < std::numeric_limits<double>::min()) + node_val[k] = 0.; + } + + // get area of the surface element face + elem->ComputeVolume(); + + // do the actual surface integration + fem->setOrder(mesh.getOrder() + 1); + fem->ConfigElement(elem); + fem->FaceIntegration(node_val); + + // add up the integrated values (nodes get values added for all faces they are part of) + for(size_t k=0; k<elem->GetNodesNumber(false); k++) + { + MeshLib::CNode* node = elem->GetNode(k); + node->SetMark(true); + val[node->GetIndex()] += node_val[k]; + } + } + + _direct_values.reserve(nNodes); + for(size_t k=0; k<nNodes; k++) + { + if (!mesh.nod_vector[k]->GetMark()) + continue; + // Assuming the unit of precipitation is mm/day + _direct_values.push_back( std::pair<size_t, double>(k, val[k] / scaling) ); + } + } + else + std::cout << "Error in DirectConditionGenerator::directWithSurfaceIntegration() - Data vector contains outdated values..." << std::endl; + + return _direct_values; +} + + +int DirectConditionGenerator::writeToFile(const std::string &name) const +{ + std::ofstream out( name.c_str(), std::ios::out ); + + if (out) + { + for (std::vector< std::pair<size_t,double> >::const_iterator it = _direct_values.begin(); it != _direct_values.end(); ++it) + out << it->first << "\t" << it->second << std::endl; + + out.close(); + } + return 0; +} + diff --git a/Gui/DataView/DirectConditionGenerator.h b/Gui/DataView/DirectConditionGenerator.h new file mode 100644 index 0000000000000000000000000000000000000000..e1839d73b324382360a189150723ab95cfbb8ff8 --- /dev/null +++ b/Gui/DataView/DirectConditionGenerator.h @@ -0,0 +1,30 @@ +/** + * \file DirectConditionGenerator.h + * 2012/01/04 KR Initial implementation + * + */ + +#ifndef DIRECTCONDITIONGENERATOR_H +#define DIRECTCONDITIONGENERATOR_H + +#include "msh_mesh.h" + +class DirectConditionGenerator +{ +public: + DirectConditionGenerator() {}; + ~DirectConditionGenerator() {}; + + const std::vector< std::pair<size_t,double> >& directToSurfaceNodes(const MeshLib::CFEMesh &mesh, const std::string &filename); + + const std::vector< std::pair<size_t,double> >& directWithSurfaceIntegration(MeshLib::CFEMesh &mesh, const std::string &filename, double scaling); + + int writeToFile(const std::string &name) const; + +private: + std::vector< std::pair<size_t,double> > _direct_values; + +}; + +#endif // DIRECTCONDITIONGENERATOR_H + diff --git a/Gui/DataView/ElementTreeModel.cpp b/Gui/DataView/ElementTreeModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b73f842ee06333131aa6749952c43dd570cdc14 --- /dev/null +++ b/Gui/DataView/ElementTreeModel.cpp @@ -0,0 +1,76 @@ +/** + * \file ElementTreeModel.cpp + * 2011/05/10 KR Initial implementation + */ + +#include "ElementTreeModel.h" +#include "OGSError.h" +#include "TreeItem.h" + +/** + * Constructor. + */ +ElementTreeModel::ElementTreeModel( QObject* parent ) + : TreeModel(parent) +{ + QList<QVariant> rootData; + delete _rootItem; + rootData << "Name" << "Type" << "" << ""; + _rootItem = new TreeItem(rootData, NULL); +} + +ElementTreeModel::~ElementTreeModel() +{ +} + +void ElementTreeModel::setElement(const GridAdapter* grid, const size_t elem_index) +{ + this->clearView(); + GridAdapter::Element* elem = (*(grid->getElements()))[elem_index]; + + QList<QVariant> elemData; + elemData << "Element " + QString::number(elem_index) << "" << "" << ""; + TreeItem* elemItem = new TreeItem(elemData, _rootItem); + _rootItem->appendChild(elemItem); + + QList<QVariant> typeData; + typeData << "Element Type: " << QString::fromStdString(MshElemType2String(elem->type)); + TreeItem* typeItem = new TreeItem(typeData, elemItem); + elemItem->appendChild(typeItem); + + QList<QVariant> materialData; + materialData << "MaterialID: " << QString::number(elem->material); + TreeItem* matItem = new TreeItem(materialData, elemItem); + elemItem->appendChild(matItem); + + QList<QVariant> volData; + volData << "Area/Volume: " << + QString::number(grid->getCFEMesh()->getElementVector()[elem_index]->calcVolume()); + TreeItem* volItem = new TreeItem(volData, elemItem); + elemItem->appendChild(volItem); + + QList<QVariant> nodeListData; + nodeListData << "Nodes" << "" << "" << ""; + TreeItem* nodeListItem = new TreeItem(nodeListData, elemItem); + elemItem->appendChild(nodeListItem); + + const std::vector<GEOLIB::Point*>* nodes_vec = grid->getNodes(); + for (size_t i = 0; i < elem->nodes.size(); i++) + { + const GEOLIB::Point* pnt = (*nodes_vec)[elem->nodes[i]]; + QList<QVariant> nodeData; + nodeData << "Node " + QString::number(elem->nodes[i]) << + QString::number((*pnt)[0]) << QString::number((*pnt)[1]) << + QString::number((*pnt)[2]); + TreeItem* nodeItem = new TreeItem(nodeData, nodeListItem); + nodeListItem->appendChild(nodeItem); + } + reset(); +} + +void ElementTreeModel::clearView() +{ + _rootItem->removeChildren(0, _rootItem->childCount()); + reset(); +} + diff --git a/Gui/DataView/ElementTreeModel.h b/Gui/DataView/ElementTreeModel.h new file mode 100644 index 0000000000000000000000000000000000000000..5c75e467fbdc7af2fd81f792f478140a66104386 --- /dev/null +++ b/Gui/DataView/ElementTreeModel.h @@ -0,0 +1,34 @@ +/** + * \file ElementTreeModel.h + * 2011/05/10 KR Initial implementation + */ + +#ifndef ELEMENTTREEMODEL_H +#define ELEMENTTREEMODEL_H + +#include "GridAdapter.h" +#include "TreeModel.h" + +/** + * \brief A model for the display of information concerning element information implemented as a TreeModel. + * \sa TreeModel, ElementTreeView, TreeItem + */ +class ElementTreeModel : public TreeModel +{ + Q_OBJECT + +public: + ElementTreeModel( QObject* parent = 0 ); + ~ElementTreeModel(); + +public slots: + /// Clears the tree. + void clearView(); + + /// Extracts information of the element with the given index from the given grid. + void setElement(const GridAdapter* grid, const size_t elem_index); + +private: +}; + +#endif //ELEMENTTREEMODEL_H diff --git a/Gui/DataView/FEMConditionSetup.ui b/Gui/DataView/FEMConditionSetup.ui new file mode 100644 index 0000000000000000000000000000000000000000..32c1e35e95008d8d90361c40bbf3d4c8eec0e917 --- /dev/null +++ b/Gui/DataView/FEMConditionSetup.ui @@ -0,0 +1,164 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>FEMConditionSetup</class> + <widget class="QDialog" name="FEMConditionSetup"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>280</width> + <height>272</height> + </rect> + </property> + <property name="windowTitle"> + <string>FEM Condition Setup</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <widget class="QLabel" name="processTypeLabel"> + <property name="text"> + <string>Process Type</string> + </property> + <property name="margin"> + <number>10</number> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="disTypeLabel"> + <property name="text"> + <string>Distribution Type</string> + </property> + <property name="margin"> + <number>10</number> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="valueLabel"> + <property name="text"> + <string>Value</string> + </property> + <property name="margin"> + <number>10</number> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="processTypeBox"/> + </item> + <item row="4" column="1"> + <widget class="QComboBox" name="disTypeBox"/> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="pvTypeLabel"> + <property name="text"> + <string>Primary Variable</string> + </property> + <property name="margin"> + <number>10</number> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="pvTypeBox"/> + </item> + <item row="5" column="1"> + <widget class="QLineEdit" name="firstValueEdit"/> + </item> + <item row="7" column="1"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="6" column="0"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="condTypeLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Condition Type</string> + </property> + <property name="margin"> + <number>10</number> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="condTypeBox"> + <item> + <property name="text"> + <string>Boundary Condition</string> + </property> + </item> + <item> + <property name="text"> + <string>Initial Condition</string> + </property> + </item> + <item> + <property name="text"> + <string>Source Term</string> + </property> + </item> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>FEMConditionSetup</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>FEMConditionSetup</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/FEMConditionSetupDialog.cpp b/Gui/DataView/FEMConditionSetupDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..463174cebe07c9e8173ecb6ec0f8b54f97fba525 --- /dev/null +++ b/Gui/DataView/FEMConditionSetupDialog.cpp @@ -0,0 +1,333 @@ +/** + * \file FEMConditionSetupDialog.cpp + * 2011/11/07 KR Initial implementation + */ + +#include "FEMConditionSetupDialog.h" +#include "OGSError.h" +#include "FEMEnums.h" +#include "ProjectData.h" +#include "StrictDoubleValidator.h" +#include "StringTools.h" +#include "LinearEditDialog.h" +#include "CondFromRasterDialog.h" + +#include "BoundaryCondition.h" +#include "InitialCondition.h" +#include "SourceTerm.h" + +FEMConditionSetupDialog::FEMConditionSetupDialog(const std::string &associated_geometry, + const GEOLIB::GEOTYPE type, + const std::string &geo_name, + const GEOLIB::GeoObject* const geo_object, + bool on_points, + QDialog* parent) +: QDialog(parent), _cond(associated_geometry, FEMCondition::UNSPECIFIED), _set_on_points(on_points), + _combobox(NULL), directButton(NULL), _mesh(NULL), _first_value_validator(NULL) +{ + _cond.setGeoType(type); + _cond.setGeoName(geo_name); + _cond.setGeoObj(geo_object); + + setupUi(this); + setupDialog(); +} + +FEMConditionSetupDialog::FEMConditionSetupDialog(const FEMCondition &cond, QDialog* parent) + : QDialog(parent), _cond(cond), _set_on_points(false), _combobox(NULL), directButton(NULL), + _mesh(NULL), _first_value_validator(NULL) +{ + setupUi(this); + setupDialog(); + setValuesFromCond(); +} + +FEMConditionSetupDialog::FEMConditionSetupDialog(const std::string &name, const MeshLib::CFEMesh* mesh, QDialog* parent) +: QDialog(parent), _cond(name, FEMCondition::UNSPECIFIED), _set_on_points(false), _combobox(NULL), directButton(NULL), + _mesh(mesh), _first_value_validator(NULL) +{ + _cond.setGeoType(GEOLIB::INVALID); + _cond.setGeoName(name); + _cond.setGeoObj(NULL); + + setupUi(this); + setupDialog(); +} + +FEMConditionSetupDialog::~FEMConditionSetupDialog() +{ + delete _combobox; + delete directButton; + delete _first_value_validator; +} + +void FEMConditionSetupDialog::setupDialog() +{ + if (_cond.getGeoType() != GEOLIB::INVALID) + { + this->disTypeBox->addItem("Constant (Dirichlet)"); + if (_cond.getGeoType() == GEOLIB::POLYLINE) + this->disTypeBox->addItem("Linear (Dirichlet)"); + + if (this->_set_on_points) + { + _combobox = new QComboBox; + _combobox->addItem("Elevation"); + static_cast<QGridLayout*>(this->layout())->addWidget(_combobox,5,1) ; + } + else + { + _first_value_validator = new StrictDoubleValidator(-1e+10, 1e+10, 5); + this->firstValueEdit->setText("0"); + this->firstValueEdit->setValidator (_first_value_validator); + } + } + else // direct on mesh + { + this->disTypeBox->addItem("Direct"); + //static_cast<QGridLayout*>(this->layout())->removeWidget(this->firstValueEdit); + directButton = new QPushButton("Calculate Values"); + static_cast<QGridLayout*>(this->layout())->addWidget(directButton,5,1); + connect(this->directButton, SIGNAL(pressed()), this, SLOT(directButton_pressed())); + } + + const std::list<std::string> process_names = FiniteElement::getAllProcessNames(); + for (std::list<std::string>::const_iterator it = process_names.begin(); it != process_names.end(); ++it) + this->processTypeBox->addItem(QString::fromStdString(*it)); + + const std::list<std::string> pv_names = FiniteElement::getAllPrimaryVariableNames(); + for (std::list<std::string>::const_iterator it = pv_names.begin(); it != pv_names.end(); ++it) + this->pvTypeBox->addItem(QString::fromStdString(*it)); +/* + const std::list<std::string> dis_names = FiniteElement::getAllDistributionNames(); + for (std::list<std::string>::const_iterator it = dis_names.begin(); it != dis_names.end(); ++it) + this->disTypeBox->addItem(QString::fromStdString(*it)); +*/ +} + +void FEMConditionSetupDialog::setValuesFromCond() +{ + QString pcs_type = QString::fromStdString(FiniteElement::convertProcessTypeToString(_cond.getProcessType())); + this->processTypeBox->setCurrentIndex(this->processTypeBox->findText(pcs_type)); + + QString pv_type = QString::fromStdString(FiniteElement::convertPrimaryVariableToString(_cond.getProcessPrimaryVariable())); + this->pvTypeBox->setCurrentIndex(this->pvTypeBox->findText(pv_type)); + + if (_cond.getCondType() == FEMCondition::INITIAL_CONDITION) + this->condTypeBox->setCurrentIndex(1); + else if (_cond.getCondType() == FEMCondition::SOURCE_TERM) + { + this->condTypeBox->setCurrentIndex(2); + on_condTypeBox_currentIndexChanged(2); + } + + if (_cond.getGeoType() != GEOLIB::INVALID) + { + if (_cond.getProcessDistributionType() == FiniteElement::CONSTANT || _cond.getProcessDistributionType() == FiniteElement::CONSTANT_NEUMANN) + { + this->disTypeBox->setCurrentIndex(0); + this->firstValueEdit->setText(QString::number(_cond.getDisValues()[0])); + } + else + { + this->disTypeBox->setCurrentIndex(1); + directButton = new QPushButton(QString::number(static_cast<int>(_cond.getDisValues().size())) + " values"); + } + } + else // direct on mesh + { + this->directButton->setText(QString::number(static_cast<int>(_cond.getDisValues().size())) + " values"); + } +} + + +void FEMConditionSetupDialog::accept() +{ + _cond.setProcessType(static_cast<FiniteElement::ProcessType>(this->processTypeBox->currentIndex() + 1)); + _cond.setProcessPrimaryVariable(static_cast<FiniteElement::PrimaryVariable>(this->pvTypeBox->currentIndex() + 1)); + + if (_cond.getGeoType() != GEOLIB::INVALID) + { + if (condTypeBox->currentIndex()>1) + { + if (this->disTypeBox->currentIndex()>0) + _cond.setProcessDistributionType(FiniteElement::LINEAR_NEUMANN); + else + { + _cond.setProcessDistributionType(FiniteElement::CONSTANT_NEUMANN); + _cond.setConstantDisValue(this->firstValueEdit->text().toDouble()); + } + } + else + { + if (this->disTypeBox->currentIndex()>0) + _cond.setProcessDistributionType(FiniteElement::LINEAR); + else + { + _cond.setProcessDistributionType(FiniteElement::CONSTANT); + _cond.setConstantDisValue(this->firstValueEdit->text().toDouble()); + } + } + } + else // direct on mesh + _cond.setProcessDistributionType(FiniteElement::DIRECT); + if (_cond.getDisValues().size()==0) + { + OGSError::box("No distribution values specified!"); + return; + } + + if (!_set_on_points) + { + std::vector<FEMCondition*> conditions; + conditions.push_back(this->typeCast(_cond)); + emit createFEMCondition(conditions); + } + else + this->copyCondOnPoints(); + + this->done(QDialog::Accepted); +} + +void FEMConditionSetupDialog::reject() +{ + this->done(QDialog::Rejected); +} + + +void FEMConditionSetupDialog::on_condTypeBox_currentIndexChanged(int index) +{ + //if (index==1) + // this->geoNameBox->addItem("Domain"); + // remove "Domain" if IC is unselected + if (_cond.getGeoType() != GEOLIB::INVALID) + { + if (index>1) // source terms selected + { + while (this->disTypeBox->count()>0) + this->disTypeBox->removeItem(0); + this->disTypeBox->addItem("Constant (Neumann)"); + if (_cond.getGeoType() == GEOLIB::POLYLINE) + this->disTypeBox->addItem("Linear (Neumann)"); + } + else + { + while (this->disTypeBox->count()>0) + this->disTypeBox->removeItem(0); + this->disTypeBox->addItem("Constant (Dirichlet)"); + if (_cond.getGeoType() == GEOLIB::POLYLINE) + this->disTypeBox->addItem("Linear (Dirichlet)"); + } + } +} + + +void FEMConditionSetupDialog::on_disTypeBox_currentIndexChanged(int index) +{ + if (index>0) // linear + { + static_cast<QGridLayout*>(this->layout())->removeWidget(this->firstValueEdit); + directButton = new QPushButton("Calculate Values"); + connect(this->directButton, SIGNAL(pressed()), this, SLOT(directButton_pressed())); + static_cast<QGridLayout*>(this->layout())->addWidget(directButton,5,1); + } + else // constant + { + static_cast<QGridLayout*>(this->layout())->removeWidget(this->directButton); + delete directButton; + directButton = NULL; + static_cast<QGridLayout*>(this->layout())->addWidget(this->firstValueEdit,5,1); + } + +} + +void FEMConditionSetupDialog::directButton_pressed() +{ + if (this->_mesh == NULL) + { + const GEOLIB::Polyline* line = dynamic_cast<const GEOLIB::Polyline*>(_cond.getGeoObj()); + const std::vector<size_t> nodes = _cond.getDisNodes(); + const std::vector<double> values = _cond.getDisValues(); + LinearEditDialog dlg(*line, nodes, values); + connect(&dlg, SIGNAL(transmitDisValues(std::vector< std::pair<size_t,double> >)), + this, SLOT(addDisValues(std::vector< std::pair<size_t,double> >))); + dlg.exec(); + } + else + { + std::map<std::string, MeshLib::CFEMesh*> msh_map; + msh_map.insert( std::pair<std::string, MeshLib::CFEMesh*>(this->_cond.getGeoName(), const_cast<MeshLib::CFEMesh*>(this->_mesh)) ); + CondFromRasterDialog dlg(msh_map); + //connect(&dlg, SIGNAL(directNodesWritten(std::string)), this, SLOT(direct_path_changed(std::string))); + connect(&dlg, SIGNAL(transmitDisValues(std::vector< std::pair<size_t,double> >)), + this, SLOT(addDisValues(std::vector< std::pair<size_t,double> >))); + dlg.exec(); + } +} + +void FEMConditionSetupDialog::addDisValues(std::vector< std::pair<size_t,double> > direct_values) +{ + _cond.setDisValues(direct_values); + this->directButton->setText(QString::number(direct_values.size()) + " values added"); + //this->directButton->setEnabled(false); +} + +FEMCondition* FEMConditionSetupDialog::typeCast(const FEMCondition &cond) +{ + FEMCondition* new_cond(NULL); + switch(this->condTypeBox->currentIndex()) + { + case 0: + new_cond = new BoundaryCondition(cond); + break; + case 1: + new_cond = new InitialCondition(cond); + break; + default: + new_cond = new SourceTerm(cond); + } + return new_cond; +} + +void FEMConditionSetupDialog::copyCondOnPoints() +{ + std::vector<FEMCondition*> conditions; + if (_cond.getGeoType() == GEOLIB::POLYLINE) + { + const GEOLIB::Polyline* ply = dynamic_cast<const GEOLIB::Polyline*>(_cond.getGeoObj()); + size_t nPoints = ply->getNumberOfPoints(); + for (size_t i=0; i<nPoints; i++) + { + FEMCondition* cond = new FEMCondition(_cond); + cond->setGeoObj(NULL); + cond->setGeoType(GEOLIB::POINT); + cond->setGeoName(_cond.getAssociatedGeometryName() + "_Point" + number2str(ply->getPointID(i))); + cond->clearDisValues(); + cond->setConstantDisValue((*ply->getPoint(i))[2]); + conditions.push_back(this->typeCast(*cond)); + } + emit createFEMCondition(conditions); + } + else if (_cond.getGeoType() == GEOLIB::SURFACE) + { + const GEOLIB::Surface* sfc = dynamic_cast<const GEOLIB::Surface*>(_cond.getGeoObj()); + size_t nTriangles = sfc->getNTriangles(); + for (size_t i=0; i<nTriangles; i++) + { + const GEOLIB::Triangle* tri = (*sfc)[i]; + for (size_t j=0; j<3; j++) + { + FEMCondition* cond = new FEMCondition(_cond); + cond->setGeoObj(NULL); + cond->setGeoType(GEOLIB::POINT); + cond->setGeoName(_cond.getAssociatedGeometryName() + "_Point" + number2str((*tri)[j])); + cond->clearDisValues(); + cond->setConstantDisValue((*tri->getPoint(j))[2]); + conditions.push_back(this->typeCast(*cond)); + } + } + emit createFEMCondition(conditions); + } + else + std::cout << "Error discerning GeoType ..." << std::endl; +} diff --git a/Gui/DataView/FEMConditionSetupDialog.h b/Gui/DataView/FEMConditionSetupDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..84453433e5bf1ad9c0f35485860439d45f77db5b --- /dev/null +++ b/Gui/DataView/FEMConditionSetupDialog.h @@ -0,0 +1,88 @@ +/** + * \file FEMConditionSetupDialog.h + * 2011/11/07 KR Initial implementation + */ + +#ifndef FEMCONDITIONSETUPDIALOG_H +#define FEMCONDITIONSETUPDIALOG_H + +#include "ui_FEMConditionSetup.h" +#include "FEMCondition.h" + +#include <QDialog> + +class QComboBox; +class QPushButton; +class StrictDoubleValidator; + +namespace GEOLIB { + class GeoObject; +} + +namespace MeshLib { + class CFEMesh; +} + +/** + * \brief A dialog window for adding FEM Conditions based + * on geometrica objects. + */ +class FEMConditionSetupDialog : public QDialog, private Ui_FEMConditionSetup +{ + Q_OBJECT + +public: + /// Constructor for creating a new FEM condition. + FEMConditionSetupDialog(const std::string &associated_geometry, + const GEOLIB::GEOTYPE type, + const std::string &geo_name, + const GEOLIB::GeoObject* const geo_object, + bool on_points = false, + QDialog* parent = 0); + + /// Constructor for editing an existing FEM condition. + FEMConditionSetupDialog(const FEMCondition &cond, QDialog* parent = 0); + + /// Constructor for creating DIRECT FEM conditions on MeshNodes. + FEMConditionSetupDialog(const std::string &name, const MeshLib::CFEMesh* mesh, QDialog* parent = 0); + + ~FEMConditionSetupDialog(void); + +private: + /// Sets layout of the dialog according to properties of the object + void setupDialog(); + /// Inserts existing values if an existing FEMCondition is being edited + void setValuesFromCond(); + + FEMCondition _cond; + bool _set_on_points; + QComboBox* _combobox; //needed for on_points & linear conds + QPushButton* directButton; // needed for direct conditions + const MeshLib::CFEMesh* _mesh; // needed for direct conditions + StrictDoubleValidator* _first_value_validator; + +private slots: + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + + void on_condTypeBox_currentIndexChanged(int index); + + void on_disTypeBox_currentIndexChanged(int index); + + void directButton_pressed(); + + void addDisValues(std::vector< std::pair<size_t,double> > direct_values); + + void copyCondOnPoints(); + + FEMCondition* typeCast(const FEMCondition &cond); + +signals: + void createFEMCondition(std::vector<FEMCondition*>); + +}; + +#endif //FEMCONDITIONSETUPDIALOG_H diff --git a/Gui/DataView/GEOModels.cpp b/Gui/DataView/GEOModels.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ae9314fe023173411e81dfb729b633e01387e8b3 --- /dev/null +++ b/Gui/DataView/GEOModels.cpp @@ -0,0 +1,251 @@ +/** + * \file GEOModels.cpp + * 9/2/2010 LB Initial implementation + * + * Implementation of GEOModels + */ + +// ** INCLUDES ** +#include "GEOModels.h" + +#include "GeoTreeModel.h" +#include "StationTreeModel.h" + +#include "StringTools.h" + +#include "OGSError.h" + +GEOModels::GEOModels( QObject* parent /*= 0*/ ) : + QObject (parent) +{ + _geoModel = new GeoTreeModel(); + _stationModel = new StationTreeModel(); +} + +GEOModels::~GEOModels() +{ + delete _stationModel; + delete _geoModel; +} + +void GEOModels::removeGeometry(std::string geo_name, GEOLIB::GEOTYPE type) +{ + if (type == GEOLIB::INVALID || type == GEOLIB::SURFACE) + this->removeSurfaceVec(geo_name); + if (type == GEOLIB::INVALID || type == GEOLIB::POLYLINE) + this->removePolylineVec(geo_name); + if (type == GEOLIB::INVALID || type == GEOLIB::POINT) + this->removePointVec(geo_name); +} + +void GEOModels::addPointVec( std::vector<GEOLIB::Point*>* points, + std::string &name, + std::map<std::string, size_t>* name_pnt_id_map, + double eps) +{ + GEOObjects::addPointVec(points, name, name_pnt_id_map, eps); + _geoModel->addPointList(QString::fromStdString(name), this->getPointVecObj(name)); + emit geoDataAdded(_geoModel, name, GEOLIB::POINT); +} + +bool GEOModels::appendPointVec(const std::vector<GEOLIB::Point*> &points, + const std::string &name, std::vector<size_t>* ids) +{ + bool ret (GEOLIB::GEOObjects::appendPointVec (points, name, ids)); + // TODO import new points into geo-treeview + return ret; +} + +bool GEOModels::removePointVec( const std::string &name ) +{ + if (!isPntVecUsed(name)) + { + emit geoDataRemoved(_geoModel, name, GEOLIB::POINT); + this->_geoModel->removeGeoList(name, GEOLIB::POINT); + return GEOObjects::removePointVec(name); + } + std::cout << + "GEOModels::removePointVec() - There are still Polylines or Surfaces depending on these points." + << std::endl; + return false; +} + +void GEOModels::addStationVec( std::vector<GEOLIB::Point*>* stations, + std::string &name) +{ + GEOObjects::addStationVec(stations, name); + + _stationModel->addStationList(QString::fromStdString(name), stations); + emit stationVectorAdded(_stationModel, name); +} + +void GEOModels::filterStationVec(const std::string &name, const std::vector<PropertyBounds> &bounds) +{ + emit stationVectorRemoved(_stationModel, name); + const std::vector<GEOLIB::Point*>* stations (GEOObjects::getStationVec(name)); + _stationModel->filterStations(name, stations, bounds); + emit stationVectorAdded(_stationModel, name); +} + +bool GEOModels::removeStationVec( const std::string &name ) +{ + emit stationVectorRemoved(_stationModel, name); + _stationModel->removeStationList(name); + return GEOObjects::removeStationVec(name); +} + +void GEOModels::addPolylineVec( std::vector<GEOLIB::Polyline*>* lines, + const std::string &name, + std::map<std::string,size_t>* ply_names ) +{ + GEOObjects::addPolylineVec(lines, name, ply_names); + if (lines->empty()) + return; + + _geoModel->addPolylineList(QString::fromStdString(name), this->getPolylineVecObj(name)); + emit geoDataAdded(_geoModel, name, GEOLIB::POLYLINE); +} + +bool GEOModels::appendPolylineVec(const std::vector<GEOLIB::Polyline*> &polylines, + const std::string &name) +{ + bool ret (GEOLIB::GEOObjects::appendPolylineVec (polylines, name)); + + this->_geoModel->appendPolylines(name, this->getPolylineVecObj(name)); + return ret; +} + +bool GEOModels::removePolylineVec( const std::string &name ) +{ + emit geoDataRemoved(_geoModel, name, GEOLIB::POLYLINE); + this->_geoModel->removeGeoList(name, GEOLIB::POLYLINE); + return GEOObjects::removePolylineVec (name); +} + +void GEOModels::addSurfaceVec( std::vector<GEOLIB::Surface*>* surfaces, + const std::string &name, + std::map<std::string,size_t>* sfc_names ) +{ + GEOObjects::addSurfaceVec(surfaces, name, sfc_names); + if (surfaces->empty()) + return; + + _geoModel->addSurfaceList(QString::fromStdString(name), this->getSurfaceVecObj(name)); + emit geoDataAdded(_geoModel, name, GEOLIB::SURFACE); +} + +bool GEOModels::appendSurfaceVec(const std::vector<GEOLIB::Surface*> &surfaces, + const std::string &name) +{ + bool ret (GEOLIB::GEOObjects::appendSurfaceVec (surfaces, name)); + + if (ret) + this->_geoModel->appendSurfaces(name, this->getSurfaceVecObj(name)); + else + { + std::vector<GEOLIB::Surface*>* sfc = new std::vector<GEOLIB::Surface*>; + for (size_t i = 0; i < surfaces.size(); i++) + sfc->push_back(surfaces[i]); + this->addSurfaceVec(sfc, name); + } + + return ret; +} + +bool GEOModels::removeSurfaceVec( const std::string &name ) +{ + emit geoDataRemoved(_geoModel, name, GEOLIB::SURFACE); + this->_geoModel->removeGeoList(name, GEOLIB::SURFACE); + return GEOObjects::removeSurfaceVec (name); +} + +void GEOModels::connectPolylineSegments(const std::string &geoName, + std::vector<size_t> indexlist, + double proximity, + std::string ply_name, + bool closePly, + bool triangulatePly) +{ + GEOLIB::PolylineVec* plyVec = this->getPolylineVecObj(geoName); + + if (plyVec) + { + const std::vector<GEOLIB::Polyline*>* polylines = plyVec->getVector(); + std::vector<GEOLIB::Polyline*> ply_list; + for (size_t i = 0; i < indexlist.size(); i++) + ply_list.push_back( (*polylines)[indexlist[i]] ); + + // connect polylines + GEOLIB::Polyline* new_line = GEOLIB::Polyline::constructPolylineFromSegments( + ply_list, + proximity); + + if (new_line) + { + // insert result in a new vector of polylines (because the GEOObjects::appendPolylines()-method requires a vector) + std::vector<GEOLIB::Polyline*> connected_ply; + + if (closePly) + { + new_line = GEOLIB::Polyline::closePolyline(*new_line); + + if (triangulatePly) + { + std::vector<GEOLIB::Surface*> new_sfc; + new_sfc.push_back(GEOLIB::Surface::createSurface(*new_line)); + this->appendSurfaceVec(new_sfc, geoName); + } + } + + connected_ply.push_back(new_line); + if (!ply_name.empty()) + plyVec->setNameOfElementByID(polylines->size(), ply_name); + this->appendPolylineVec(connected_ply, geoName); + } + else + OGSError::box("Error connecting polyines."); + } + else + OGSError::box("Corresponding geometry not found."); +} + + +void GEOModels::addNameForElement(const std::string &geometry_name, const GEOLIB::GEOTYPE object_type, size_t id, std::string new_name) +{ + if (object_type == GEOLIB::POINT) + this->getPointVecObj(geometry_name)->setNameForElement(id, new_name); + else if (object_type == GEOLIB::POLYLINE) + this->getPolylineVecObj(geometry_name)->setNameForElement(id, new_name); + else if (object_type == GEOLIB::SURFACE) + this->getSurfaceVecObj(geometry_name)->setNameForElement(id, new_name); + else + std::cout << "Error in GEOModels::addNameForElement() - Unknown GEOTYPE..." << std::endl; +} + +void GEOModels::addNameForObjectPoints(const std::string &geometry_name, const GEOLIB::GEOTYPE object_type, const std::string &geo_object_name, const std::string &new_name) +{ + const GEOLIB::GeoObject* obj = this->getGEOObject(geometry_name, object_type, geo_object_name); + GEOLIB::PointVec* pnt_vec = this->getPointVecObj(geometry_name); + if (object_type == GEOLIB::POLYLINE) + { + const GEOLIB::Polyline* ply = dynamic_cast<const GEOLIB::Polyline*>(obj); + size_t nPoints = ply->getNumberOfPoints(); + for (size_t i=0; i<nPoints; i++) + pnt_vec->setNameForElement(ply->getPointID(i), new_name + "_Point" + number2str(ply->getPointID(i))); + } + else if (object_type == GEOLIB::SURFACE) + { + const GEOLIB::Surface* sfc = dynamic_cast<const GEOLIB::Surface*>(obj); + size_t nTriangles = sfc->getNTriangles(); + for (size_t i=0; i<nTriangles; i++) + { + const GEOLIB::Triangle* tri = (*sfc)[i]; + pnt_vec->setNameForElement((*tri)[0], new_name + "_Point" + number2str((*tri)[0])); + pnt_vec->setNameForElement((*tri)[1], new_name + "_Point" + number2str((*tri)[1])); + pnt_vec->setNameForElement((*tri)[2], new_name + "_Point" + number2str((*tri)[2])); + } + } + else + std::cout << "Error in GEOModels::addNameForElement() - Unknown GEOTYPE..." << std::endl; +} + diff --git a/Gui/DataView/GEOModels.h b/Gui/DataView/GEOModels.h new file mode 100644 index 0000000000000000000000000000000000000000..b90689c32c9cd83fa4051c64a14964b9050acbd8 --- /dev/null +++ b/Gui/DataView/GEOModels.h @@ -0,0 +1,103 @@ +/** + * \file GEOModels.h + * 9/2/2010 LB Initial implementation + * + */ + +#ifndef GEOMODELS_H +#define GEOMODELS_H + +// ** INCLUDES ** +#include "GEOObjects.h" +#include "GeoType.h" +#include <QObject> + +class GeoTreeModel; +class Model; +class PntsModel; +class StationTreeModel; +class PolylinesModel; +class SurfaceModel; +class TreeModel; + +/** + * \brief GEOModels connects the data management class GEOObjects and the GUI. + * It inherits from GEOLIB::GEOObjects and additionally emits signals when + * data objects are modified. The GUI connects to these signals. Model instances + * are created for every data object. + */ +class GEOModels : public QObject, public GEOLIB::GEOObjects +{ + Q_OBJECT + +public: + GEOModels(QObject* parent = 0); + ~GEOModels(); + + GeoTreeModel* getGeoModel() { return _geoModel; } + StationTreeModel* getStationModel() { return _stationModel; } + +public slots: + /// Removes all parts (points, lines, surfaces) of the geometry with the given name. + virtual void removeGeometry(std::string geo_name, GEOLIB::GEOTYPE type); + + virtual void addPointVec(std::vector<GEOLIB::Point*>* points, + std::string &name, + std::map<std::string, size_t>* name_pnt_id_map = NULL, + double eps = sqrt(std::numeric_limits<double>::min())); + virtual bool appendPointVec(const std::vector<GEOLIB::Point*> &points, + const std::string &name, + std::vector<size_t>* ids = NULL); + virtual bool removePointVec(const std::string &name); + + virtual void addStationVec(std::vector<GEOLIB::Point*>* stations, + std::string &name); + void filterStationVec(const std::string &name, const std::vector<PropertyBounds> &bounds); + virtual bool removeStationVec(const std::string &name); + + virtual void addPolylineVec(std::vector<GEOLIB::Polyline*>* lines, + const std::string &name, + std::map<std::string,size_t>* ply_names = NULL); + virtual bool appendPolylineVec(const std::vector<GEOLIB::Polyline*> &polylines, + const std::string &name); + virtual bool removePolylineVec(const std::string &name); + + virtual void addSurfaceVec(std::vector<GEOLIB::Surface*>* surfaces, + const std::string &name, + std::map<std::string,size_t>* sfc_names = NULL); + + /// @brief + /// @param surfaces The surface vector. + virtual bool appendSurfaceVec(const std::vector<GEOLIB::Surface*> &surfaces, + const std::string &name); + virtual bool removeSurfaceVec(const std::string &name); + + /// Adds the name 'new_name' for the geo-object specified by the parameters + void addNameForElement(const std::string &geometry_name, const GEOLIB::GEOTYPE object_type, size_t id, std::string new_name); + + /// Adds a generic name to all points that are part of the specified geo-object + void addNameForObjectPoints(const std::string &geometry_name, const GEOLIB::GEOTYPE object_type, const std::string &geo_object_name, const std::string &new_name); + + /// Calls all necessary functions to connect polyline-segments and update all views and windows. + void connectPolylineSegments(const std::string &geoName, + std::vector<size_t> indexlist, + double proximity, + std::string ply_name, + bool closePly, + bool triangulatePly); + +protected: + GeoTreeModel* _geoModel; + StationTreeModel* _stationModel; + +private: + +signals: + void geoDataAdded(GeoTreeModel*, std::string, GEOLIB::GEOTYPE); + void geoDataRemoved(GeoTreeModel*, std::string, GEOLIB::GEOTYPE); + + void stationVectorAdded(StationTreeModel* model, std::string name); + void stationVectorRemoved(StationTreeModel* model, std::string name); +}; + +#endif // GEOMODELS_H diff --git a/Gui/DataView/GMSHPrefs.ui b/Gui/DataView/GMSHPrefs.ui new file mode 100644 index 0000000000000000000000000000000000000000..c9ce0c07e3fb30d51eadeb64f314be8aa5dee117 --- /dev/null +++ b/Gui/DataView/GMSHPrefs.ui @@ -0,0 +1,515 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>GMSHPrefs</class> + <widget class="QDialog" name="GMSHPrefs"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>524</width> + <height>399</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="GeoTab"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <attribute name="title"> + <string>Geometry</string> + </attribute> + <widget class="QPushButton" name="deselectGeoButton"> + <property name="geometry"> + <rect> + <x>230</x> + <y>190</y> + <width>41</width> + <height>23</height> + </rect> + </property> + <property name="text"> + <string><<</string> + </property> + </widget> + <widget class="QPushButton" name="selectGeoButton"> + <property name="geometry"> + <rect> + <x>230</x> + <y>160</y> + <width>41</width> + <height>23</height> + </rect> + </property> + <property name="text"> + <string>>></string> + </property> + </widget> + <widget class="QListView" name="allGeoView"> + <property name="geometry"> + <rect> + <x>10</x> + <y>70</y> + <width>211</width> + <height>221</height> + </rect> + </property> + </widget> + <widget class="QListView" name="selectedGeoView"> + <property name="geometry"> + <rect> + <x>280</x> + <y>70</y> + <width>211</width> + <height>221</height> + </rect> + </property> + </widget> + <widget class="QLabel" name="label"> + <property name="geometry"> + <rect> + <x>10</x> + <y>50</y> + <width>141</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>Available information:</string> + </property> + </widget> + <widget class="QLabel" name="label_2"> + <property name="geometry"> + <rect> + <x>280</x> + <y>50</y> + <width>151</width> + <height>21</height> + </rect> + </property> + <property name="text"> + <string>Employed information</string> + </property> + </widget> + <widget class="QLabel" name="label_7"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>481</width> + <height>31</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Selection of geometry incorporated into mesh</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </widget> + <widget class="QWidget" name="OptionsTab"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <attribute name="title"> + <string>Advanced</string> + </attribute> + <widget class="QLabel" name="label_8"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="geometry"> + <rect> + <x>8</x> + <y>10</y> + <width>481</width> + <height>31</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Advanced meshing options</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + <widget class="QRadioButton" name="radioAdaptive"> + <property name="geometry"> + <rect> + <x>10</x> + <y>50</y> + <width>399</width> + <height>17</height> + </rect> + </property> + <property name="text"> + <string>Adaptive meshing</string> + </property> + </widget> + <widget class="QGroupBox" name="groupBox"> + <property name="geometry"> + <rect> + <x>10</x> + <y>70</y> + <width>481</width> + <height>111</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Adaptive meshing options</string> + </property> + <widget class="QWidget" name="gridLayoutWidget_2"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>471</width> + <height>101</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <property name="leftMargin"> + <number>0</number> + </property> + <item row="1" column="0"> + <widget class="QLabel" name="label_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>250</width> + <height>0</height> + </size> + </property> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="text"> + <string>Max. number of points in Quadtree leaf</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_4"> + <property name="minimumSize"> + <size> + <width>250</width> + <height>0</height> + </size> + </property> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="text"> + <string>Mesh density scaling for points</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_5"> + <property name="minimumSize"> + <size> + <width>250</width> + <height>0</height> + </size> + </property> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="text"> + <string>Mesh density scaling for stations</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="param1"> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="param2"> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="2"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="3" column="2"> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="3" column="1"> + <widget class="QLineEdit" name="param3"> + <property name="text"> + <string/> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <widget class="QGroupBox" name="groupBox_2"> + <property name="geometry"> + <rect> + <x>10</x> + <y>210</y> + <width>481</width> + <height>61</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Homogeneous meshing options</string> + </property> + <widget class="QWidget" name="gridLayoutWidget_3"> + <property name="geometry"> + <rect> + <x>10</x> + <y>10</y> + <width>471</width> + <height>51</height> + </rect> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="2"> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_6"> + <property name="minimumSize"> + <size> + <width>250</width> + <height>0</height> + </size> + </property> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="text"> + <string>Element Size</string> + </property> + <property name="margin"> + <number>5</number> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="param4"/> + </item> + </layout> + </widget> + </widget> + <widget class="QRadioButton" name="radioHomogeneous"> + <property name="geometry"> + <rect> + <x>10</x> + <y>190</y> + <width>399</width> + <height>17</height> + </rect> + </property> + <property name="text"> + <string>Homogeneous meshing</string> + </property> + </widget> + <widget class="QCheckBox" name="geoFileDelete"> + <property name="geometry"> + <rect> + <x>10</x> + <y>290</y> + <width>421</width> + <height>17</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Delete GMSH geo-file after generating mesh</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>GMSHPrefs</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>221</x> + <y>361</y> + </hint> + <hint type="destinationlabel"> + <x>221</x> + <y>190</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>GMSHPrefs</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>221</x> + <y>361</y> + </hint> + <hint type="destinationlabel"> + <x>221</x> + <y>190</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/GMSHPrefsDialog.cpp b/Gui/DataView/GMSHPrefsDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9b4e5dde61fd80d5bf0539c56cc5879910a0832d --- /dev/null +++ b/Gui/DataView/GMSHPrefsDialog.cpp @@ -0,0 +1,185 @@ +/** + * \file GMSHPrefsDialog.cpp + * 2010/01/21 KR Initial implementation + */ + +// Base +#include "StringTools.h" + +// Qt/Base +#include "StrictDoubleValidator.h" +#include "StrictIntValidator.h" + +#include "GEOObjects.h" +#include "GMSHPrefsDialog.h" +#include <QStringList> +#include <QStringListModel> + +#include "OGSError.h" + +GMSHPrefsDialog::GMSHPrefsDialog(const GEOLIB::GEOObjects* geoObjects, QDialog* parent) + : QDialog(parent), _allGeo(new QStringListModel), _selGeo(new QStringListModel) +{ + setupUi(this); + + // default parameters + this->param1->setText("2"); + this->param2->setText("0.3"); + this->param3->setText("0.05"); + this->param4->setText("0"); + + // object will be deleted by Qt + StrictIntValidator* max_number_of_points_in_quadtree_leaf_validator (new StrictIntValidator ( + 1, + 1000, + this->param1)); + param1->setValidator (max_number_of_points_in_quadtree_leaf_validator); + // object will be deleted by Qt + StrictDoubleValidator* mesh_density_scaling_pnts_validator(new StrictDoubleValidator ( + 1e-10, + 1.0, + 5, + this + ->param2)); + param2->setValidator (mesh_density_scaling_pnts_validator); + // object will be deleted by Qt# + StrictDoubleValidator* mesh_density_scaling_stations_validator(new StrictDoubleValidator ( + 1e-10, + 1.0, + 5, + this->param3)); + param3->setValidator (mesh_density_scaling_stations_validator); + + std::vector<std::string> geoNames; + geoObjects->getGeometryNames(geoNames); + + // get station names + std::vector<std::string> geo_station_names; + geoObjects->getStationVectorNames(geo_station_names); + + for (size_t k(0); k < geo_station_names.size(); k++) + geoNames.push_back (geo_station_names[k]); + + size_t nGeoObjects(geoNames.size()); + + QStringList list; + for (size_t i = 0; i < nGeoObjects; i++) + list.append(QString::fromStdString(geoNames[i])); + + if (list.empty()) + { + this->selectGeoButton->setDisabled(true); + this->deselectGeoButton->setDisabled(true); + list.append("(No geometry available.)"); + } + _allGeo->setStringList(list); + this->allGeoView->setModel(_allGeo); + this->selectedGeoView->setModel(_selGeo); + this->radioAdaptive->toggle(); // default is adaptive meshing + this->on_radioAdaptive_toggled(true); +} + +GMSHPrefsDialog::~GMSHPrefsDialog() +{ + delete _allGeo; + delete _selGeo; +} + +void GMSHPrefsDialog::on_selectGeoButton_pressed() +{ + QModelIndexList selected = this->allGeoView->selectionModel()->selectedIndexes(); + QStringList list = _selGeo->stringList(); + + for (QModelIndexList::iterator it = selected.begin(); it != selected.end(); ++it) + { + list.append(it->data().toString()); + + _allGeo->removeRow(it->row()); + } + _selGeo->setStringList(list); +} + +void GMSHPrefsDialog::on_deselectGeoButton_pressed() +{ + QModelIndexList selected = this->selectedGeoView->selectionModel()->selectedIndexes(); + QStringList list = _allGeo->stringList(); + + for (QModelIndexList::iterator it = selected.begin(); it != selected.end(); ++it) + { + list.append(it->data().toString()); + + _selGeo->removeRow(it->row()); + } + _allGeo->setStringList(list); +} + +void GMSHPrefsDialog::on_radioAdaptive_toggled(bool isTrue) +{ + if (isTrue) // meshing set to adaptive + { + this->param1->setEnabled(true); + this->param2->setEnabled(true); + this->param3->setEnabled(true); + this->param4->setEnabled(false); + } + else // meshing set to homogeneous + { + this->param1->setEnabled(false); + this->param2->setEnabled(false); + this->param3->setEnabled(false); + this->param4->setEnabled(true); + } +} + +void GMSHPrefsDialog::accept() +{ + if (this->_selGeo->stringList().empty()) + { + OGSError::box("No geometry loaded. Geometric data\n is necessary for mesh generation."); + this->done(QDialog::Rejected); + } + + std::vector<std::string> selectedObjects = this->getSelectedObjects(_selGeo->stringList()); + size_t max_number_of_points_in_quadtree_leaf (10); + double mesh_density_scaling_pnts(0.5); + double mesh_density_scaling_stations (0.05); + double val4(-1); + + if (this->radioAdaptive->isChecked()) + { + max_number_of_points_in_quadtree_leaf = str2number<size_t> ( + param1->text().toStdString().c_str()); + if (max_number_of_points_in_quadtree_leaf == 0) + max_number_of_points_in_quadtree_leaf = 10; + mesh_density_scaling_pnts = fabs (strtod(param2->text().toStdString().c_str(), 0)); + if (mesh_density_scaling_pnts < sqrt(std::numeric_limits<double>::min())) + mesh_density_scaling_pnts = 0.5; + mesh_density_scaling_stations = strtod(param3->text().toStdString().c_str(), 0); + if (mesh_density_scaling_stations < sqrt(std::numeric_limits<double>::min())) + mesh_density_scaling_stations = 0.05; + } + else + val4 = strtod(param4->text().toStdString().c_str(), 0); + + bool delete_geo_file = this->geoFileDelete->isChecked(); + emit requestMeshing(selectedObjects, + max_number_of_points_in_quadtree_leaf, + mesh_density_scaling_pnts, + mesh_density_scaling_stations, + val4, + delete_geo_file); + this->done(QDialog::Accepted); +} + +void GMSHPrefsDialog::reject() +{ + this->done(QDialog::Rejected); +} + +std::vector<std::string> GMSHPrefsDialog::getSelectedObjects(QStringList list) +{ + std::vector<std::string> indexList; + for (QStringList::iterator it = list.begin(); it != list.end(); ++it) + indexList.push_back(it->toStdString()); + return indexList; +} diff --git a/Gui/DataView/GMSHPrefsDialog.h b/Gui/DataView/GMSHPrefsDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..98b9ce5c2aeaa1278386884e5bffbed3686f8432 --- /dev/null +++ b/Gui/DataView/GMSHPrefsDialog.h @@ -0,0 +1,51 @@ +/** + * \file GMSHPrefsDialog.h + * 2010/01/21 KR Initial implementation + */ + +#ifndef GMSHPREFSDIALOG_H +#define GMSHPREFSDIALOG_H + +#include "ui_GMSHPrefs.h" +#include <QDialog> + +class QStringListModel; + +namespace GEOLIB +{ +class GEOObjects; +} + +/** + * \brief A dialog window for setting preferences for GMSH + */ +class GMSHPrefsDialog : public QDialog, private Ui_GMSHPrefs +{ + Q_OBJECT + +public: + GMSHPrefsDialog(const GEOLIB::GEOObjects* geoObjects, QDialog* parent = 0); + ~GMSHPrefsDialog(void); + +private: + std::vector<std::string> getSelectedObjects(QStringList list); + + QStringListModel* _allGeo; + QStringListModel* _selGeo; + +private slots: + void on_selectGeoButton_pressed(); + void on_deselectGeoButton_pressed(); + void on_radioAdaptive_toggled(bool isTrue); + + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void requestMeshing(std::vector<std::string> &, size_t, double, double, double, bool); +}; + +#endif //GMSHPREFSDIALOG_H diff --git a/Gui/DataView/GeoObjectListItem.h b/Gui/DataView/GeoObjectListItem.h new file mode 100644 index 0000000000000000000000000000000000000000..19a848ff6ce77e77dba1cf4f2122be0b32d33930 --- /dev/null +++ b/Gui/DataView/GeoObjectListItem.h @@ -0,0 +1,83 @@ +/** + * \file GeoObjectListItem.h + * 2011/02/07 KR Initial implementation + * + */ +#ifndef GEOOBJECTLISTITEM_H +#define GEOOBJECTLISTITEM_H + +#include "TreeItem.h" + +#include "GeoType.h" + +#include "VtkPointsSource.h" +#include "VtkPolylinesSource.h" +#include "VtkSurfacesSource.h" +#include <QModelIndex> +#include <vtkPolyDataAlgorithm.h> + +/** + * Creates parent items for geometric object lists (i.e. points, polylines and surfaces) + * for the GeoTreeModel + * + * \sa GeoTreeModel, GeoTreeItem + */ +class GeoObjectListItem : public TreeItem +{ +public: + /// Constructor for the TreeItem specifying the "Points"-subtree of a geometry. + GeoObjectListItem(const QList<QVariant> &data, + TreeItem* parent, + const std::vector<GEOLIB::Point*>* geo_data = NULL, + GEOLIB::GEOTYPE type = GEOLIB::POINT) + : TreeItem(data, parent), _vtkSource(VtkPointsSource::New()), _type(type) + { + QString geo_name = parent->data(0).toString(); + static_cast<VtkPointsSource*>(_vtkSource)->setPoints(geo_data); + static_cast<VtkPointsSource*>(_vtkSource)->SetName(geo_name + " - Points"); + } + + /// Constructor for the TreeItem specifying the "Polylines"-subtree of a geometry. + GeoObjectListItem(const QList<QVariant> &data, + TreeItem* parent, + const std::vector<GEOLIB::Polyline*>* geo_data = NULL, + GEOLIB::GEOTYPE type = GEOLIB::POLYLINE) + : TreeItem(data, parent), _vtkSource(VtkPolylinesSource::New()), _type(type) + { + QString geo_name = parent->data(0).toString(); + static_cast<VtkPolylinesSource*>(_vtkSource)->setPolylines(geo_data); + static_cast<VtkPolylinesSource*>(_vtkSource)->SetName(geo_name + " - Polylines"); + } + + /// Constructor for the TreeItem specifying the "Surfaces"-subtree of a geometry. + GeoObjectListItem(const QList<QVariant> &data, + TreeItem* parent, + const std::vector<GEOLIB::Surface*>* geo_data = NULL, + GEOLIB::GEOTYPE type = GEOLIB::SURFACE) + : TreeItem(data, parent), _vtkSource(VtkSurfacesSource::New()), _type(type) + { + QString geo_name = parent->data(0).toString(); + static_cast<VtkSurfacesSource*>(_vtkSource)->setSurfaces(geo_data); + static_cast<VtkSurfacesSource*>(_vtkSource)->SetName(geo_name + " - Surfaces"); + } + + ~GeoObjectListItem() + { + _vtkSource->Delete(); + } + + /// Returns the type of geo-objects contained in the subtree of this item. + GEOLIB::GEOTYPE getType() { return _type; } + + /// Returns the Vtk polydata source object + vtkPolyDataAlgorithm* vtkSource() const { return _vtkSource; } + +private: + /// The Vtk data source object. This is the starting point for a Vtk data + /// visualization pipeline. + vtkPolyDataAlgorithm* _vtkSource; + + GEOLIB::GEOTYPE _type; +}; + +#endif //GEOOBJECTLISTITEM_H diff --git a/Gui/DataView/GeoTabWidget.cpp b/Gui/DataView/GeoTabWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13089a21e4741fd0b2311c6e1db09cbe7a455e25 --- /dev/null +++ b/Gui/DataView/GeoTabWidget.cpp @@ -0,0 +1,13 @@ +/** + * \file GeoTabWidget.cpp + * 2011/02/07 KR Initial implementation + */ + +// ** INCLUDES ** +#include "GeoTabWidget.h" + +GeoTabWidget::GeoTabWidget( QWidget* parent /*= 0*/ ) + : QWidget(parent) +{ + setupUi(this); +} diff --git a/Gui/DataView/GeoTabWidget.h b/Gui/DataView/GeoTabWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..d17a90c62e6d66e8045e063c984a410ff2770ed5 --- /dev/null +++ b/Gui/DataView/GeoTabWidget.h @@ -0,0 +1,26 @@ +/** + * \file GeoTabWidget.h + * 2011/02/07 KR Initial implementation + * + */ + +#ifndef GEOTABWIDGET_H +#define GEOTABWIDGET_H + +// ** INCLUDES ** +#include "ui_GeoTabWidgetBase.h" + +/** + * \brief Widget containing GeoTreeView-objects. + */ +class GeoTabWidget : public QWidget, public Ui_GeoTabWidgetBase +{ + Q_OBJECT + +public: + GeoTabWidget(QWidget* parent = 0); + +private: +}; + +#endif // GEOTABWIDGET_H diff --git a/Gui/DataView/GeoTabWidgetBase.ui b/Gui/DataView/GeoTabWidgetBase.ui new file mode 100644 index 0000000000000000000000000000000000000000..6dce56723bf7bd20c03ef8b6b9e300a44b40e023 --- /dev/null +++ b/Gui/DataView/GeoTabWidgetBase.ui @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>GeoTabWidgetBase</class> + <widget class="QWidget" name="GeoTabWidgetBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>250</width> + <height>500</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="margin"> + <number>2</number> + </property> + <item> + <widget class="GeoTreeView" name="treeView"/> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>GeoTreeView</class> + <extends>QTreeView</extends> + <header>GeoTreeView.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Gui/DataView/GeoTreeItem.h b/Gui/DataView/GeoTreeItem.h new file mode 100644 index 0000000000000000000000000000000000000000..b9e091d79af2ed99181484d31b8c9d9d6e6e75ce --- /dev/null +++ b/Gui/DataView/GeoTreeItem.h @@ -0,0 +1,39 @@ +/** + * \file GeoTreeItem.h + * 2010/12/08 KR Initial implementation + */ + +#ifndef GEOTREEITEM_H +#define GEOTREEITEM_H + +#include "TreeItem.h" + +#include "GeoObject.h" + +/** + * \brief A TreeItem containing an additional GeoObject + * + * \sa TreeItem + */ +class GeoTreeItem : public TreeItem +{ +public: + /** + * Constructor + * \param data The data associated with each column + * \param parent The parent item in the tree + * \param item The GeoObject (i.e. Point, Polyline or Surface) + */ + GeoTreeItem(const QList<QVariant> &data, + TreeItem* parent, + const GEOLIB::GeoObject* item = NULL) : TreeItem(data, parent), _item(item) {} + ~GeoTreeItem() {} + + /// Returns the geo-object associated with this item (i.e. a point, polyline or surface). + const GEOLIB::GeoObject* getGeoObject() const { return _item; } + +private: + const GEOLIB::GeoObject* _item; +}; + +#endif //GEOTREEITEM_H diff --git a/Gui/DataView/GeoTreeModel.cpp b/Gui/DataView/GeoTreeModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3f48f3c4094b16432a3a6c94741789446822e0e1 --- /dev/null +++ b/Gui/DataView/GeoTreeModel.cpp @@ -0,0 +1,332 @@ +/** + * \file GeoTreeModel.cpp + * 2011/02/07 KR Initial implementation + */ + +#include "GeoObjectListItem.h" +#include "GeoTreeItem.h" +#include "GeoTreeModel.h" +#include "OGSError.h" + +/** + * Constructor. + */ +GeoTreeModel::GeoTreeModel( QObject* parent ) + : TreeModel(parent) +{ + QList<QVariant> rootData; + delete _rootItem; + rootData << "Id" << "x" << "y" << "z" << "name "; + _rootItem = new GeoTreeItem(rootData, NULL, NULL); +} + +GeoTreeModel::~GeoTreeModel() +{ +} + +void GeoTreeModel::addPointList(QString geoName, const GEOLIB::PointVec* pointVec) +{ + const std::vector<GEOLIB::Point*>* points = pointVec->getVector(); + + QList<QVariant> geoData; + geoData << QVariant(geoName) << "" << "" << "" << ""; + GeoTreeItem* geo (new GeoTreeItem(geoData, _rootItem)); + _lists.push_back(geo); + _rootItem->appendChild(geo); + + QList<QVariant> pointData; + pointData << "Points" << "" << "" << "" << ""; + GeoObjectListItem* pointList = new GeoObjectListItem(pointData, geo, points, GEOLIB::POINT); + geo->appendChild(pointList); + + size_t nPoints = points->size(); + + for (size_t j = 0; j < nPoints; j++) + { + const GEOLIB::Point &pnt(*(*points)[j]); + std::string pnt_name(""); + pointVec->getNameOfElementByID(j, pnt_name); + QList<QVariant> pnt_data; + pnt_data << static_cast<unsigned>(j) + << QString::number(pnt[0], 'f') + << QString::number(pnt[1], 'f') + << QString::number(pnt[2], 'f') + << QString::fromStdString(pnt_name); + GeoTreeItem* point(new GeoTreeItem(pnt_data, pointList, static_cast<const GEOLIB::Point*>(&pnt))); + pointList->appendChild(point); + } + + std::cout << "Geometry \"" << geoName.toStdString() << "\" built." << std::endl; + std::cout << nPoints << " points added." << std::endl; + + reset(); +} + +void GeoTreeModel::addPolylineList(QString geoName, const GEOLIB::PolylineVec* polylineVec) +{ + int nLists = _rootItem->childCount(); + TreeItem* geo(NULL); + for (int i = 0; i < nLists; i++) + { + if (_rootItem->child(i)->data(0).toString().compare(geoName) == 0) + geo = _rootItem->child(i); + } + + if (geo == NULL) + { + std::cout << "GeoTreeModel::addPolylineList() - Error: No corresponding geometry found..." + << std::endl; + return; + } + + const std::vector<GEOLIB::Polyline*>* lines = polylineVec->getVector(); + + QList<QVariant> plyData; + plyData << "Polylines" << "" << "" << ""; + GeoObjectListItem* plyList = new GeoObjectListItem(plyData, geo, lines, GEOLIB::POLYLINE); + geo->appendChild(plyList); + this->addChildren(plyList, polylineVec, 0, lines->size()); + reset(); +} + +void GeoTreeModel::appendPolylines(const std::string &name, const GEOLIB::PolylineVec* polylineVec) +{ + for (size_t i = 0; i < _lists.size(); i++) + { + if ( name.compare( _lists[i]->data(0).toString().toStdString() ) == 0 ) + for (int j = 0; j < _lists[i]->childCount(); j++) + { + GeoObjectListItem* parent = + static_cast<GeoObjectListItem*>(_lists[i]->child(j)); + if (GEOLIB::POLYLINE == parent->getType()) + { + this->addChildren(parent, polylineVec, + parent->childCount(), + polylineVec->getVector()->size()); + reset(); + parent->vtkSource()->Modified(); + return; + } + } + } + OGSError::box("Error adding polyline to geometry."); +} + +void GeoTreeModel::addChildren(GeoObjectListItem* plyList, + const GEOLIB::PolylineVec* polyline_vec, + size_t start_index, + size_t end_index) +{ + const std::vector<GEOLIB::Polyline*> lines = *(polyline_vec->getVector()); + + for (size_t i = start_index; i < end_index; i++) + { + QList<QVariant> line_data; + std::string ply_name(""); + if (polyline_vec->getNameOfElementByID(i, ply_name)) + line_data << "Line " + QString::number(i) << QString::fromStdString(ply_name) << "" << ""; + else line_data << "Line " + QString::number(i) << "" << "" << ""; + + const GEOLIB::Polyline &line(*(lines[i])); + GeoTreeItem* lineItem(new GeoTreeItem(line_data, plyList, &line)); + plyList->appendChild(lineItem); + + int nPoints = static_cast<int>(lines[i]->getNumberOfPoints()); + for (int j = 0; j < nPoints; j++) + { + const GEOLIB::Point pnt(*(line[j])); + QList<QVariant> pnt_data; + pnt_data << static_cast<int>(line.getPointID(j)) + << QString::number(pnt[0], 'f') + << QString::number(pnt[1], 'f') + << QString::number(pnt[2], 'f'); + TreeItem* child(new TreeItem(pnt_data, lineItem)); + lineItem->appendChild(child); + } + } + std::cout << end_index - start_index << " polylines added." << std::endl; +} + +void GeoTreeModel::addSurfaceList(QString geoName, const GEOLIB::SurfaceVec* surfaceVec) +{ + int nLists = _rootItem->childCount(); + TreeItem* geo(NULL); + for (int i = 0; i < nLists; i++) + { + if (_rootItem->child(i)->data(0).toString().compare(geoName) == 0) + geo = _rootItem->child(i); + } + + if (geo == NULL) + { + std::cout << "GeoTreeModel::addSurfaceList() - Error: No corresponding geometry found..." + << std::endl; + return; + } + + const std::vector<GEOLIB::Surface*>* surfaces = surfaceVec->getVector(); + + QList<QVariant> sfcData; + sfcData << "Surfaces" << "" << "" << ""; + GeoObjectListItem* sfcList = new GeoObjectListItem(sfcData, geo, surfaces, GEOLIB::SURFACE); + geo->appendChild(sfcList); + this->addChildren(sfcList, surfaceVec, 0, surfaces->size()); + + reset(); +} + +void GeoTreeModel::appendSurfaces(const std::string &name, GEOLIB::SurfaceVec* surfaceVec) +{ + for (size_t i = 0; i < _lists.size(); i++) + { + if ( name.compare( _lists[i]->data(0).toString().toStdString() ) == 0 ) + { + int nChildren = _lists[i]->childCount(); + for (int j = 0; j < nChildren; j++) + { + GeoObjectListItem* parent = static_cast<GeoObjectListItem*>(_lists[i]->child(j)); + if (GEOLIB::SURFACE == parent->getType()) + { + this->addChildren(parent, surfaceVec, + parent->childCount(), + surfaceVec->getVector()->size()); + parent->vtkSource()->Modified(); + reset(); + return; + } + } + } + } + OGSError::box("Error adding surface to geometry."); +} + +void GeoTreeModel::addChildren(GeoObjectListItem* sfcList, + const GEOLIB::SurfaceVec* surface_vec, + size_t start_index, + size_t end_index) +{ + const std::vector<GEOLIB::Surface*>* surfaces = surface_vec->getVector(); + + const std::vector<GEOLIB::Point*> &nodesVec(*((*surfaces)[start_index]->getPointVec())); + for (size_t i = start_index; i < end_index; i++) + { + QList<QVariant> surface; + std::string sfc_name(""); + surface_vec->getNameOfElementByID(i, sfc_name); + surface << "Surface " + QString::number(i) << QString::fromStdString(sfc_name) << "" << ""; + + const GEOLIB::Surface &sfc(*(*surfaces)[i]); + GeoTreeItem* surfaceItem(new GeoTreeItem(surface, sfcList, &sfc)); + sfcList->appendChild(surfaceItem); + + int nElems = static_cast<int>((*surfaces)[i]->getNTriangles()); + for (int j = 0; j < nElems; j++) + { + QList<QVariant> elem; + const GEOLIB::Triangle &triangle(*sfc[j]); + elem << j << static_cast<int>(triangle[0]) + << static_cast<int>(triangle[1]) + << static_cast<int>(triangle[2]); + TreeItem* child(new TreeItem(elem, surfaceItem)); + surfaceItem->appendChild(child); + + for (int k = 0; k < 3; k++) + { + QList<QVariant> node; + const GEOLIB::Point &pnt(*(nodesVec[triangle[k]])); + node << static_cast<int>(triangle[k]) + << QString::number(pnt[0], 'f') + << QString::number(pnt[1], 'f') + << QString::number(pnt[2], 'f'); + TreeItem* nchild(new TreeItem(node, child)); + child->appendChild(nchild); + } + } + } + std::cout << end_index - start_index << " surfaces added." << std::endl; +} + +/** + * Removes the TreeItem with the given name including all its children + */ +void GeoTreeModel::removeGeoList(const std::string &name, GEOLIB::GEOTYPE type) +{ + for (size_t i = 0; i < _lists.size(); i++) + if ( name.compare( _lists[i]->data(0).toString().toStdString() ) == 0 ) + { + for (int j = 0; j < _lists[i]->childCount(); j++) + if (type == + static_cast<GeoObjectListItem*>(_lists[i]->child(j))->getType()) + { + QModelIndex index = createIndex(j, 0, _lists[i]->child(j)); + removeRows(0, _lists[i]->child(j)->childCount(), index); + removeRows(j, 1, parent(index)); + break; + } + if (_lists[i]->childCount() == 0) + { + _lists.erase(_lists.begin() + i); + removeRows(i, 1, QModelIndex()); + } + } +} + +vtkPolyDataAlgorithm* GeoTreeModel::vtkSource(const std::string &name, GEOLIB::GEOTYPE type) const +{ + size_t nLists = _lists.size(); + for (size_t i = 0; i < nLists; i++) + { + if ( name.compare( _lists[i]->data(0).toString().toStdString() ) == 0 ) + for (int j = 0; j < _lists[i]->childCount(); j++) + { + GeoObjectListItem* item = + dynamic_cast<GeoObjectListItem*>(_lists[i]->child(j)); + if (item->getType() == type) + return item->vtkSource(); + } + } + return NULL; +} + +void GeoTreeModel::setNameForItem(const std::string &name, GEOLIB::GEOTYPE type, size_t id, std::string item_name) +{ + int type_idx(0); + int col_idx(1); + + switch(type) + { + case GEOLIB::POINT: + type_idx = 0; + col_idx = 4; // for points the name is at a different position + break; + case GEOLIB::POLYLINE: + type_idx = 1; + break; + case GEOLIB::SURFACE: + type_idx = 2; + break; + case GEOLIB::VOLUME: + type_idx = 3; + break; + default: + type_idx = -1; + } + + for (size_t i=0; i<_lists.size(); i++) + { + if ( name.compare( _lists[i]->data(0).toString().toStdString() ) == 0 ) + { + TreeItem* object_list = _lists[i]->child(type_idx); +// for (int j=0; j<object_list->childCount(); j++) +// { + TreeItem* item = object_list->child(/*j*/id); +// if (static_cast<size_t>(item->data(0).toInt()) == id) +// { + item->setData(col_idx, QString::fromStdString(item_name)); +// break; +// } +// } + break; + } + } +} diff --git a/Gui/DataView/GeoTreeModel.h b/Gui/DataView/GeoTreeModel.h new file mode 100644 index 0000000000000000000000000000000000000000..8da296ec245973be37312331503b8975e40feabc --- /dev/null +++ b/Gui/DataView/GeoTreeModel.h @@ -0,0 +1,91 @@ +/** + * \file GeoTreeModel.h + * 2011/02/07 KR Initial implementation + */ + +#ifndef GEOTREEMODEL_H +#define GEOTREEMODEL_H + +#include <vector> + +#include "GeoType.h" +#include "PointVec.h" +#include "PolylineVec.h" +#include "SurfaceVec.h" +#include "TreeModel.h" +#include <vtkPolyDataAlgorithm.h> + +namespace GEOLIB +{ +class GeoObject; +} + +class QString; +class QModelIndex; +class GeoTreeItem; +class GeoObjectListItem; + +/** + * \brief A model for the GeoTreeView implementing a tree as a double-linked list. + * \sa TreeModel, GeoTreeView, TreeItem, GeoTreeItem + */ +class GeoTreeModel : public TreeModel +{ + Q_OBJECT + +public: + GeoTreeModel( QObject* parent = 0 ); + ~GeoTreeModel(); + + /** + * Inserts a new subtree under _rootItem for a geometry with the given name along with a subtree named "Points" for that new geometry. + * \param geoName Name of the new subtree. If no name is given a default name is assigned. + * \param pointVec The list of points to be added as children of that subtree (no geometry can be added with a set of points!) + */ + void addPointList(QString geoName, const GEOLIB::PointVec* pointVec); + /// Adds a subtree "Polylines" to an existing geometry with the given name. + void addPolylineList(QString geoName, const GEOLIB::PolylineVec* polylineVec); + /// Appends polylines to the "Polyline"-subtree + void appendPolylines(const std::string &name, const GEOLIB::PolylineVec* polylineVec); + /// Adds a subtree "Surfaces" to an existing geometry with the given name. + void addSurfaceList(QString geoName, const GEOLIB::SurfaceVec* surfaceVec); + /// Appends surfaces to the "Surface"-subtree + void appendSurfaces(const std::string &name, GEOLIB::SurfaceVec* surfaceVec); + /// Returns a list of all existing geometries. + const std::vector<GeoTreeItem*> &getLists() { return _lists; } + /** + * Removes a geometry (points, polylines & surfaces) or just a specified subtree indicated by type. + * Note that points cannot be deleted as long as other objects exist that depend on them. + */ + void removeGeoList(const std::string &name, GEOLIB::GEOTYPE type = GEOLIB::INVALID); + + void setNameForItem(const std::string &name, GEOLIB::GEOTYPE type, size_t id, std::string item_name); + + /* + * Returns the geo-object specified by the given index. + * \param index Index of the requested item + * \param listName Here, the method will put the name of the geometry this object belongs to. + * \return A geo-object (Point / Polyline / Surface) + */ + //const GEOLIB::GeoObject* objectFromIndex( const QModelIndex& index, QString &geoName ) const; + + /// Returns the vtk-object indicated by type of the geometry indicated by name. + vtkPolyDataAlgorithm* vtkSource(const std::string &name, GEOLIB::GEOTYPE type) const; + +private: + /// Adds children to the "Polylines" node + void addChildren(GeoObjectListItem* plyList, + const GEOLIB::PolylineVec* polyline_vec, + size_t start_index, + size_t end_index); + + /// Adds children to the "Surfaces" node + void addChildren(GeoObjectListItem* sfcList, + const GEOLIB::SurfaceVec* surface_vec, + size_t start_index, + size_t end_index); + + std::vector<GeoTreeItem*> _lists; +}; + +#endif //GEOTREEMODEL_H diff --git a/Gui/DataView/GeoTreeView.cpp b/Gui/DataView/GeoTreeView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1623bc19bdc12b16a35f5179114786c23857f890 --- /dev/null +++ b/Gui/DataView/GeoTreeView.cpp @@ -0,0 +1,199 @@ +/** + * \file GeoTreeView.cpp + * 2011/02/07 KR Initial implementation + */ + +#include <QFileDialog> +#include <QMenu> +#include <iostream> + +#include "GeoObjectListItem.h" +#include "GeoTreeItem.h" +#include "GeoTreeModel.h" +#include "GeoTreeView.h" +#include "OGSError.h" + +GeoTreeView::GeoTreeView(QWidget* parent) : QTreeView(parent) +{ +} + +void GeoTreeView::updateView() +{ + setAlternatingRowColors(true); + //resizeColumnToContents(0); + setColumnWidth(0,150); + setColumnWidth(1,50); + setColumnWidth(2,50); +} + +void GeoTreeView::on_Clicked(QModelIndex idx) +{ + qDebug("%d, %d",idx.parent().row(), idx.row()); +} + +void GeoTreeView::selectionChanged( const QItemSelection &selected, + const QItemSelection &deselected ) +{ + Q_UNUSED(deselected); + if (!selected.isEmpty()) + { + const QModelIndex idx = *(selected.indexes().begin()); + const TreeItem* tree_item = static_cast<TreeModel*>(this->model())->getItem(idx); + + const GeoObjectListItem* list_item = dynamic_cast<GeoObjectListItem*>(tree_item->parentItem()); + if (list_item) + emit geoItemSelected(list_item->vtkSource(), tree_item->row()); + else + emit removeGeoItemSelection(); + } + //emit itemSelectionChanged(selected, deselected); + //return QTreeView::selectionChanged(selected, deselected); +} + +void GeoTreeView::selectionChangedFromOutside( const QItemSelection &selected, + const QItemSelection &deselected ) +{ + QItemSelectionModel* selModel = this->selectionModel(); + + selModel->blockSignals(true); + selModel->select(deselected, QItemSelectionModel::Deselect); + selModel->select(selected, QItemSelectionModel::Select); + selModel->blockSignals(false); + + return QTreeView::selectionChanged(selected, deselected); +} + +void GeoTreeView::contextMenuEvent( QContextMenuEvent* event ) +{ + QModelIndex index = this->selectionModel()->currentIndex(); + TreeItem* item = static_cast<TreeItem*>(index.internalPointer()); + + GeoObjectListItem* list = dynamic_cast<GeoObjectListItem*>(item); + QMenu menu; + + // The current index is a list of points/polylines/surfaces + if (list != NULL) + { + QAction* connectPlyAction(NULL); + if (list->getType() == GEOLIB::POLYLINE) + { + connectPlyAction = menu.addAction("Connect Polylines..."); + connect(connectPlyAction, SIGNAL(triggered()), this, + SLOT(connectPolylines())); + } + menu.addSeparator(); + QAction* removeAction = menu.addAction("Remove " + item->data(0).toString()); + connect(removeAction, SIGNAL(triggered()), this, SLOT(removeList())); + } + else + { + if (!item) // Otherwise sometimes it crashes when (unmotivated ;-) ) clicking in a treeview + return; + + GeoObjectListItem* parent = dynamic_cast<GeoObjectListItem*>(item->parentItem()); + + // The current index refers to a geo-object + if (parent != NULL) + { + QMenu* cond_menu = new QMenu("Set FEM Condition"); + menu.addMenu(cond_menu); + QAction* addCondAction = cond_menu->addAction("On object..."); + QAction* addCondPointAction = cond_menu->addAction("On all points..."); + QAction* addNameAction = menu.addAction("Set name..."); + connect(addCondAction, SIGNAL(triggered()), this, SLOT(setObjectAsCondition())); + connect(addNameAction, SIGNAL(triggered()), this, SLOT(setNameForElement())); + + if (parent->getType() == GEOLIB::POINT) + addCondPointAction->setEnabled(false); + else + connect(addCondPointAction, SIGNAL(triggered()), this, SLOT(setObjectPointsAsCondition())); + + } + // The current index refers to the name of a geometry-object + else if (item->childCount() > 0) + { + if (item->child(0)->data(0).toString().compare("Points") == 0) // clumsy way to find out + { + QAction* saveAction = menu.addAction("Save geometry..."); + QAction* addCNDAction = menu.addAction("Load FEM Conditions..."); + //QAction* saveCondAction = menu.addAction("Save FEM conditions..."); + menu.addSeparator(); + QAction* removeAction = menu.addAction("Remove geometry"); + connect(saveAction, SIGNAL(triggered()), this, SLOT(writeToFile())); + connect(addCNDAction, SIGNAL(triggered()), this, SLOT(loadFEMConditions())); + //connect(saveCondAction, SIGNAL(triggered()), this, SLOT(saveFEMConditions())); + connect(removeAction, SIGNAL(triggered()), this, SLOT(removeList())); + } + } + } + + menu.exec(event->globalPos()); +} + +void GeoTreeView::connectPolylines() +{ + TreeItem* item = static_cast<GeoTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex())->parentItem(); + emit requestLineEditDialog(item->data(0).toString().toStdString()); +} + +void GeoTreeView::removeList() +{ + TreeItem* item = static_cast<GeoTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex()); + + GeoObjectListItem* list = dynamic_cast<GeoObjectListItem*>(item); + if (list) + emit listRemoved((item->parentItem()->data( + 0).toString()).toStdString(), list->getType()); + else + emit listRemoved((item->data(0).toString()).toStdString(), GEOLIB::INVALID); +} + +void GeoTreeView::setElementAsCondition(bool set_on_points) +{ + const TreeItem* item = static_cast<GeoTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex()); + const size_t id = item->row(); + const GEOLIB::GEOTYPE type = static_cast<GeoObjectListItem*>(item->parentItem())->getType(); + const std::string geometry_name = item->parentItem()->parentItem()->data(0).toString().toStdString(); + emit requestCondSetupDialog(geometry_name, type, id, set_on_points); +} + +void GeoTreeView::setNameForElement() +{ + const TreeItem* item = static_cast<GeoTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex()); + const size_t id = item->row(); + const GEOLIB::GEOTYPE type = static_cast<GeoObjectListItem*>(item->parentItem())->getType(); + const std::string geometry_name = item->parentItem()->parentItem()->data(0).toString().toStdString(); + emit requestNameChangeDialog(geometry_name, type, id); +} + +void GeoTreeView::writeToFile() const +{ + TreeItem* item = static_cast<GeoTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex()); + QString gliName = item->data(0).toString(); + QString fileName = QFileDialog::getSaveFileName(NULL, + "Save geometry as", gliName, "GeoSys geometry file (*.gml)"); + if (!fileName.isEmpty()) + emit saveToFileRequested(gliName, fileName); +} + +void GeoTreeView::loadFEMConditions() +{ + TreeItem* item = static_cast<GeoTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex()); + emit loadFEMCondFileRequested(item->data(0).toString().toStdString()); +} +/* +void GeoTreeView::saveFEMConditions() +{ + TreeItem* item = static_cast<GeoTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex()); + QString fileName = QFileDialog::getSaveFileName(NULL, + "Save FEM Conditions as", "", "OpenGeoSys FEM Condition file (*.cnd);; GeoSys Boundary Condition (*.bc);; GeoSys Initial Condition (*.ic);; GeoSys Source Condition (*.st)"); + emit saveFEMConditionsRequested(item->data(0).toString(), fileName); +} +*/ diff --git a/Gui/DataView/GeoTreeView.h b/Gui/DataView/GeoTreeView.h new file mode 100644 index 0000000000000000000000000000000000000000..376d2f9080b99b1a91bb569e3ad80867bd2290ed --- /dev/null +++ b/Gui/DataView/GeoTreeView.h @@ -0,0 +1,74 @@ +/** + * \file GeoTreeView.h + * 2011/02/07 KR Initial implementation + */ + +#ifndef GEOTREEVIEW_H +#define GEOTREEVIEW_H + +#include "GeoType.h" +#include <QContextMenuEvent> +#include <QTreeView> + +class vtkPolyDataAlgorithm; + +/** + * \brief A view for the GeoTreeModel + * \sa GeoTreeModel, GeoTreeItem + */ +class GeoTreeView : public QTreeView +{ + Q_OBJECT + +public: + /// Constructor + GeoTreeView(QWidget* parent = 0); + + /// Update the view to visualise changes made to the underlying data + void updateView(); + +protected slots: + /// Instructions if the selection of items in the view has changed. + void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + + /// Instructions if the selection of items in the view has changed by events outside the view (i.e. by actions made in the visualisation). + void selectionChangedFromOutside(const QItemSelection &selected, + const QItemSelection &deselected); + +private: + /// Actions to be taken after a right mouse click is performed in the station view. + void contextMenuEvent( QContextMenuEvent* e ); + /// Calls a FEMConditionSetupDialog. + void setElementAsCondition(bool set_on_points = false); + +private slots: + /// Allows to add FEM Conditions to a process + void loadFEMConditions(); + void on_Clicked(QModelIndex idx); + /// Calls a LineEditDialog. + void connectPolylines(); + /// Calls a SetNameDialog. + void setNameForElement(); + void setObjectAsCondition() { setElementAsCondition(false); }; + void setObjectPointsAsCondition() { setElementAsCondition(true); }; + /// Saves a geometry in a file. + void writeToFile() const; + /// Removes a whole geometry or parts of it. + void removeList(); + /// Saves FEM Conditions associated with the given geometry + //void saveFEMConditions(); + +signals: + void geoItemSelected(const vtkPolyDataAlgorithm*, int); + void removeGeoItemSelection(); + //void itemSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected); + void listRemoved(std::string name, GEOLIB::GEOTYPE); + void loadFEMCondFileRequested(std::string); + void saveToFileRequested(QString, QString) const; + void requestCondSetupDialog(const std::string&, const GEOLIB::GEOTYPE, const size_t, bool on_points); + void requestLineEditDialog(const std::string&); + void requestNameChangeDialog(const std::string&, const GEOLIB::GEOTYPE, const size_t); + //void saveFEMConditionsRequested(QString, QString); +}; + +#endif //GEOTREEVIEW_H diff --git a/Gui/DataView/LineEdit.ui b/Gui/DataView/LineEdit.ui new file mode 100644 index 0000000000000000000000000000000000000000..2968d8b8dcaeefb644293e45535a08faf454a9f0 --- /dev/null +++ b/Gui/DataView/LineEdit.ui @@ -0,0 +1,221 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>LineEdit</class> + <widget class="QDialog" name="LineEdit"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>372</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="geometry"> + <rect> + <x>40</x> + <y>330</y> + <width>341</width> + <height>32</height> + </rect> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + <widget class="QPushButton" name="selectPlyButton"> + <property name="geometry"> + <rect> + <x>180</x> + <y>80</y> + <width>41</width> + <height>23</height> + </rect> + </property> + <property name="text"> + <string>>></string> + </property> + </widget> + <widget class="QPushButton" name="deselectPlyButton"> + <property name="geometry"> + <rect> + <x>180</x> + <y>120</y> + <width>41</width> + <height>23</height> + </rect> + </property> + <property name="text"> + <string><<</string> + </property> + </widget> + <widget class="QCheckBox" name="closePlyCheckBox"> + <property name="geometry"> + <rect> + <x>20</x> + <y>290</y> + <width>141</width> + <height>17</height> + </rect> + </property> + <property name="text"> + <string>Close connected Polyline</string> + </property> + </widget> + <widget class="QCheckBox" name="createSfcCheckBox"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="geometry"> + <rect> + <x>20</x> + <y>310</y> + <width>161</width> + <height>17</height> + </rect> + </property> + <property name="text"> + <string>Create Surface from Polyline</string> + </property> + </widget> + <widget class="QLabel" name="label"> + <property name="geometry"> + <rect> + <x>20</x> + <y>10</y> + <width>111</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>All Polylines:</string> + </property> + </widget> + <widget class="QLabel" name="label_2"> + <property name="geometry"> + <rect> + <x>230</x> + <y>10</y> + <width>101</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Selected Polylines:</string> + </property> + </widget> + <widget class="QListView" name="allPlyView"> + <property name="geometry"> + <rect> + <x>20</x> + <y>30</y> + <width>151</width> + <height>191</height> + </rect> + </property> + </widget> + <widget class="QListView" name="selectedPlyView"> + <property name="geometry"> + <rect> + <x>230</x> + <y>30</y> + <width>151</width> + <height>191</height> + </rect> + </property> + </widget> + <widget class="QLabel" name="label_3"> + <property name="geometry"> + <rect> + <x>20</x> + <y>230</y> + <width>211</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Maximum Distance between end points</string> + </property> + </widget> + <widget class="QLineEdit" name="proximityEdit"> + <property name="geometry"> + <rect> + <x>230</x> + <y>230</y> + <width>151</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string>0.0</string> + </property> + </widget> + <widget class="QLineEdit" name="plyNameEdit"> + <property name="geometry"> + <rect> + <x>230</x> + <y>260</y> + <width>151</width> + <height>20</height> + </rect> + </property> + <property name="text"> + <string/> + </property> + </widget> + <widget class="QLabel" name="label_4"> + <property name="geometry"> + <rect> + <x>20</x> + <y>260</y> + <width>211</width> + <height>16</height> + </rect> + </property> + <property name="text"> + <string>Name of new polyline (optional)</string> + </property> + </widget> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>LineEdit</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>LineEdit</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/LineEditDialog.cpp b/Gui/DataView/LineEditDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a063e471a8821fd6a05762fb678dd93942d6d20b --- /dev/null +++ b/Gui/DataView/LineEditDialog.cpp @@ -0,0 +1,104 @@ +/** + * \file LineEditDialog.cpp + * 2010/12/09 KR Initial implementation + */ + +#include "LineEditDialog.h" +#include "OGSError.h" +#include <QStringList> +#include <QStringListModel> + +LineEditDialog::LineEditDialog(const GEOLIB::PolylineVec &ply_vec, QDialog* parent) + : QDialog(parent), _allPly(new QStringListModel), _selPly(new QStringListModel), + _geoName(ply_vec.getName()) +{ + setupUi(this); + + this->proximityEdit->setValidator(new QDoubleValidator(0, 100, 8, this)); + + size_t nPly(ply_vec.size()); + QStringList list; + for (size_t i = 0; i < nPly; i++) + { + std::string ply_name(""); + ply_vec.getNameOfElementByID(i, ply_name); + list.append("Line " + QString::number(i) + " " + QString::fromStdString(ply_name)); + } + _allPly->setStringList(list); + + this->allPlyView->setModel(_allPly); + this->selectedPlyView->setModel(_selPly); +} + +LineEditDialog::~LineEditDialog() +{ + delete _allPly; + delete _selPly; +} + +void LineEditDialog::on_selectPlyButton_pressed() +{ + QModelIndexList selected = this->allPlyView->selectionModel()->selectedIndexes(); + QStringList list = _selPly->stringList(); + + for (QModelIndexList::iterator it = selected.begin(); it != selected.end(); ++it) + { + list.append(it->data().toString()); + + _allPly->removeRow(it->row()); + } + _selPly->setStringList(list); +} + +void LineEditDialog::on_deselectPlyButton_pressed() +{ + QModelIndexList selected = this->selectedPlyView->selectionModel()->selectedIndexes(); + QStringList list = _allPly->stringList(); + + for (QModelIndexList::iterator it = selected.begin(); it != selected.end(); ++it) + { + list.append(it->data().toString()); + + _selPly->removeRow(it->row()); + } + _allPly->setStringList(list); +} + +void LineEditDialog::accept() +{ + std::vector<size_t> selectedIndeces = this->getSelectedIndeces(_selPly->stringList()); + + if (!selectedIndeces.empty()) + { + std::string prox_string = this->proximityEdit->text().toStdString(); + double prox = (prox_string.empty()) ? 0.0 : strtod( prox_string.c_str(), 0 ); + std::string ply_name = + (plyNameEdit->text().toStdString().empty()) ? "" : plyNameEdit->text(). + toStdString(); + emit connectPolylines(_geoName, + selectedIndeces, + prox, + ply_name, + this->closePlyCheckBox->isChecked(), + this->createSfcCheckBox->isChecked()); + this->done(QDialog::Accepted); + } + else + OGSError::box("No polylines selected", "Error"); +} + +void LineEditDialog::reject() +{ + this->done(QDialog::Rejected); +} + +std::vector<size_t> LineEditDialog::getSelectedIndeces(QStringList list) +{ + std::vector<size_t> indexList; + for (QStringList::iterator it = list.begin(); it != list.end(); ++it) + { + QString s = it->mid(5, it->indexOf(" ") - 5); + indexList.push_back(atoi(s.toStdString().c_str())); + } + return indexList; +} diff --git a/Gui/DataView/LineEditDialog.h b/Gui/DataView/LineEditDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..048be457e3467332e21b12b82b3b2a7de5c283ba --- /dev/null +++ b/Gui/DataView/LineEditDialog.h @@ -0,0 +1,59 @@ +/** + * \file LineEditDialog.h + * 2010/12/09 KR Initial implementation + */ + +#ifndef LINEEDITDIALOG_H +#define LINEEDITDIALOG_H + +#include "ui_LineEdit.h" +#include <QDialog> + +#include "PolylineVec.h" + +class QStringListModel; + +/** + * \brief A dialog window for manipulation of polylines. + * Currently included functionality is the concatenation of polylines + * as well as creating polygons or surfaces from polylines. + */ +class LineEditDialog : public QDialog, private Ui_LineEdit +{ + Q_OBJECT + +public: + LineEditDialog(const GEOLIB::PolylineVec &ply_vec, QDialog* parent = 0); + ~LineEditDialog(void); + +private: + std::vector<size_t> getSelectedIndeces(QStringList list); + + QStringListModel* _allPly; + QStringListModel* _selPly; + std::string _geoName; + +private slots: + /// Instructions when polylines are selected. + void on_selectPlyButton_pressed(); + + /// Instructions when polylines are deselected. + void on_deselectPlyButton_pressed(); + + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void connectPolylines(const std::string&, + std::vector<size_t>, + double, + std::string, + bool, + bool); + void triangulateSurface(const GEOLIB::Polyline); +}; + +#endif //LINEEDITDIALOG_H diff --git a/Gui/DataView/LinearEdit.ui b/Gui/DataView/LinearEdit.ui new file mode 100644 index 0000000000000000000000000000000000000000..7806f69b3799d5d2571d0e832c15039fb657c8bb --- /dev/null +++ b/Gui/DataView/LinearEdit.ui @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>LinearEdit</class> + <widget class="QDialog" name="LinearEdit"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>174</width> + <height>347</height> + </rect> + </property> + <property name="windowTitle"> + <string>Linear Edit</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QComboBox" name="comboBox"> + <item> + <property name="text"> + <string>Values</string> + </property> + </item> + <item> + <property name="text"> + <string>Elevation</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QTableWidget" name="tableWidget"> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <column> + <property name="text"> + <string>Value</string> + </property> + </column> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>LinearEdit</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>LinearEdit</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/LinearEditDialog.cpp b/Gui/DataView/LinearEditDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f23b82573f54f216f1f45be168496a4643164ba5 --- /dev/null +++ b/Gui/DataView/LinearEditDialog.cpp @@ -0,0 +1,68 @@ +/** + * \file LinearEditDialog.cpp + * 2012/04/17 KR Initial implementation + */ + +#include "LinearEditDialog.h" + +LinearEditDialog::LinearEditDialog(const GEOLIB::Polyline &line, const std::vector<size_t> &dis_nodes, const std::vector<double> &dis_values, QDialog* parent) + : QDialog(parent), _line(line) +{ + setupUi(this); + setupDialog(dis_nodes, dis_values); +} + +void LinearEditDialog::setupDialog(const std::vector<size_t> &dis_nodes, const std::vector<double> &dis_values) +{ + size_t nPoints(_line.getNumberOfPoints()); + this->tableWidget->setRowCount(nPoints); + QList<QString> indexlist; + + for (size_t i=0; i<nPoints; i++) + { + indexlist.push_back(QString::number(i)); + QTableWidgetItem *newItem = new QTableWidgetItem(""); + tableWidget->setItem(i, 0, newItem); + } + QStringList vHeaders(indexlist); + tableWidget->setVerticalHeaderLabels(vHeaders); + + size_t nValues (dis_values.size()); + for (size_t i=0; i<nValues; i++) + tableWidget->item(dis_nodes[i],0)->setText(QString::number(dis_values[i])); +} + +LinearEditDialog::~LinearEditDialog() +{ +} + +void LinearEditDialog::on_comboBox_currentIndexChanged(int index) +{ + if (index>0) //elevation + { + size_t nRows = tableWidget->rowCount(); + for (size_t i=0; i<nRows; i++) + tableWidget->item(i,0)->setText(QString::number(_line[i]->getData()[2])); + } +} + +void LinearEditDialog::accept() +{ + std::vector< std::pair<size_t,double> > linear_values; + + size_t nRows = tableWidget->rowCount(); + for (size_t i=0; i<nRows; i++) + { + QString row_text (tableWidget->item(i,0)->text()); + if (row_text.length()>0) + linear_values.push_back( std::pair<size_t, double>(i, row_text.toDouble()) ); + } + + emit transmitDisValues(linear_values); + this->done(QDialog::Accepted); +} + +void LinearEditDialog::reject() +{ + this->done(QDialog::Rejected); +} diff --git a/Gui/DataView/LinearEditDialog.h b/Gui/DataView/LinearEditDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..41fde93c1451361f9edc72a4e4950b592eb3cd60 --- /dev/null +++ b/Gui/DataView/LinearEditDialog.h @@ -0,0 +1,43 @@ +/** + * \file LinearEditDialog.h + * 2012/04/17 KR Initial implementation + */ + +#ifndef LINEAREDITDIALOG_H +#define LINEAREDITDIALOG_H + +#include "ui_LinearEdit.h" +#include <QDialog> + +#include "Polyline.h" + +/** + * \brief A dialog window for creating linear boundary conditions on polylines + */ +class LinearEditDialog : public QDialog, private Ui_LinearEdit +{ + Q_OBJECT + +public: + LinearEditDialog(const GEOLIB::Polyline &line, const std::vector<size_t> &dis_nodes, const std::vector<double> &dis_values, QDialog* parent = 0); + ~LinearEditDialog(void); + +private: + void setupDialog(const std::vector<size_t> &dis_nodes, const std::vector<double> &dis_values); + + const GEOLIB::Polyline _line; + +private slots: + void on_comboBox_currentIndexChanged(int index); + + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void transmitDisValues(std::vector< std::pair<size_t,double> >); +}; + +#endif //LINEAREDITDIALOG_H diff --git a/Gui/DataView/ListPropertiesDialog.cpp b/Gui/DataView/ListPropertiesDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8c34807388bb4284d219558e854f6d18309512c6 --- /dev/null +++ b/Gui/DataView/ListPropertiesDialog.cpp @@ -0,0 +1,152 @@ +/** + * \file ListPropertiesDialog.cpp + * KR Initial implementation + */ + +#include "DateTools.h" +#include "ListPropertiesDialog.h" +#include "PropertyBounds.h" +#include "StringTools.h" +#include <QDialogButtonBox> +#include <QGridLayout> +#include <QLabel> +#include <QLineEdit> + +/** + * Creates a new dialog. + */ +ListPropertiesDialog::ListPropertiesDialog(std::string listName, + GEOModels* geoModels, + QDialog* parent) : + QDialog(parent), _listName(listName), _geoModels(geoModels) +{ + setupDialog(); + show(); +} + +ListPropertiesDialog::~ListPropertiesDialog() +{ + for (size_t i = 0; i < _propLabel.size(); i++) + { + delete _propLabel[i]; + delete _minValue[i]; + delete _maxValue[i]; + } + + delete _buttonBox; +} + +/// Constructs a dialog window based on the properties retrieved from the station objects +void ListPropertiesDialog::setupDialog() +{ + int i = 0; + double minVal = 0, maxVal = 0; + + const std::vector<GEOLIB::Point*>* stations ( _geoModels->getStationVec(_listName)); + + std::map<std::string, + double> properties = static_cast<GEOLIB::Station*>((*stations)[0])->getProperties(); + QGridLayout* layout = new QGridLayout; + + setWindowTitle("List Properties"); + + for(std::map<std::string, double>::const_iterator it = properties.begin(); + it != properties.end(); ++it) + { + QLabel* _prop = new QLabel(this); + QLineEdit* _min = new QLineEdit(this); + QLineEdit* _max = new QLineEdit(this); + _prop->setText(QString::fromStdString(it->first)); + + if (getPropertyBounds(stations, it->first, minVal, maxVal)) + { + _min->setText(QString::number(minVal, 'f')); + if (_prop->text().compare("date") == 0) + _min->setText(QString::fromStdString(date2string(minVal))); + + _max->setText(QString::number(maxVal, 'f')); + if (_prop->text().compare("date") == 0) + _max->setText(QString::fromStdString(date2string(maxVal))); + } + + _propLabel.push_back(_prop); + _minValue.push_back(_min); + _maxValue.push_back(_max); + + layout->addWidget( _propLabel[i], i, 0 ); + layout->addWidget( _minValue[i], i, 1 ); + layout->addWidget( _maxValue[i], i, 2 ); + i++; + } + + _buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + + layout->addWidget(_buttonBox, i + 1, 1, 1, 2 ); + + setLayout(layout); +} + +int ListPropertiesDialog::getPropertyBounds(const std::vector<GEOLIB::Point*>* stations, + const std::string &prop, + double &minVal, + double &maxVal) +{ + if (!stations->empty()) + { + std::map<std::string, double> properties ( + static_cast<GEOLIB::Station*>((*stations)[0])->getProperties()); + minVal = properties[prop]; + maxVal = properties[prop]; + + size_t size = stations->size(); + for (size_t i = 1; i < size; i++) + { + properties = static_cast<GEOLIB::Station*>((*stations)[i])->getProperties(); + if (minVal > properties[prop]) + minVal = properties[prop]; + if (maxVal < properties[prop]) + maxVal = properties[prop]; + } + return 1; + } + return 0; +} + +/// Instructions if the OK-Button has been pressed. +void ListPropertiesDialog::accept() +{ + std::vector<PropertyBounds> bounds; + int noProp = _propLabel.size(); + double minVal, maxVal; + + for (int i = 0; i < noProp; i++) + { + if (_propLabel[i]->text().compare("date") == 0) + { + minVal = xmlDate2int(_minValue[i]->text().toStdString()); + maxVal = xmlDate2int(_maxValue[i]->text().toStdString()); + } + else + { + minVal = strtod(replaceString(",", ".", + _minValue[i]->text().toStdString()).c_str(),0); + maxVal = strtod(replaceString(",", ".", + _maxValue[i]->text().toStdString()).c_str(), + 0); + } + PropertyBounds b(_propLabel[i]->text().toStdString(), minVal, maxVal); + bounds.push_back(b); + } + + emit propertyBoundariesChanged(_listName, bounds); + + this->done(QDialog::Accepted); +} + +/// Instructions if the Cancel-Button has been pressed. +void ListPropertiesDialog::reject() +{ + this->done(QDialog::Rejected); +} diff --git a/Gui/DataView/ListPropertiesDialog.h b/Gui/DataView/ListPropertiesDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..540af179e553cb53c12c96d4f7013a7eae1c16bd --- /dev/null +++ b/Gui/DataView/ListPropertiesDialog.h @@ -0,0 +1,55 @@ +/** + * \file ListPropertiesDialog.h + * KR Initial implementation + */ + +#ifndef LISTPROPERTIESDIALOG_H +#define LISTPROPERTIESDIALOG_H + +#include "GEOModels.h" +#include "Station.h" +#include <QDialog> +#include <vector> + +class QLabel; +class QLineEdit; +class QDialogButtonBox; + +/** + * \brief A dialog for selecting a subset of a station list based on the properties of that list. + * + * A dialog for selecting a subset of a station list based on the properties of that list. + * Note: Currently, this dialog only works if the list is loaded from a database. + */ +class ListPropertiesDialog : public QDialog +{ + Q_OBJECT + +public: + ListPropertiesDialog(std::string listName, GEOModels* geoModels, QDialog* parent = 0); + ~ListPropertiesDialog(); + +private: + int getPropertyBounds(const std::vector<GEOLIB::Point*>* stations, + const std::string &prop, + double &minVal, + double &maxVal); + void setupDialog(); + + QDialogButtonBox* _buttonBox; /// The buttons used in this dialog. + std::vector<QLabel*> _propLabel; /// The names of the properties. + std::vector<QLineEdit*> _minValue; /// The minimum values of each property. + std::vector<QLineEdit*> _maxValue; /// The maximum values of each property. + + std::string _listName; + GEOModels* _geoModels; + +private slots: + void accept(); + void reject(); + +signals: + void propertyBoundariesChanged(std::string name, std::vector<PropertyBounds> bounds); +}; + +#endif //LISTPROPERTIESDIALOG_H diff --git a/Gui/DataView/ModelTreeItem.cpp b/Gui/DataView/ModelTreeItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..039d6705a86bfa442c981082aaebb2cbd9628432 --- /dev/null +++ b/Gui/DataView/ModelTreeItem.cpp @@ -0,0 +1,19 @@ +/** + * \file ModelTreeItem.cpp + * KR Initial implementation + */ + +#include "ModelTreeItem.h" + +ModelTreeItem::ModelTreeItem(const QList<QVariant> &data, TreeItem* parent, BaseItem* item) + : TreeItem(data, parent), _item(item) +{ +} + +BaseItem* ModelTreeItem::getItem() const +{ + if (_item != NULL) + return _item; + return NULL; +} + diff --git a/Gui/DataView/ModelTreeItem.h b/Gui/DataView/ModelTreeItem.h new file mode 100644 index 0000000000000000000000000000000000000000..9f149aefc6174a34934cb0ae8474dee819c9ff90 --- /dev/null +++ b/Gui/DataView/ModelTreeItem.h @@ -0,0 +1,47 @@ +/** + * \file ModelTreeItem.h + * KR Initial implementation + */ + +#ifndef QMODELTREEITEM_H +#define QMODELTREEITEM_H + +#include "BaseItem.h" +#include "Station.h" +#include "TreeItem.h" + +/** + * \brief A TreeItem containing some additional information used in the StationModel. + * + * \sa TreeItem + */ +class ModelTreeItem : public TreeItem +{ +public: + /** + * Constructor + * \param data The data associated with each column + * \param parent The parent item in the tree + * \param item The ModelItem-object + */ + ModelTreeItem(const QList<QVariant> &data, TreeItem* parent, BaseItem* item = NULL); + ~ModelTreeItem() { delete _item; } + + /// Returns the station object from which this item has been constructed + GEOLIB::Station* getStation() { return _stn; } + + /// Returns the BaseItem associated with this item + BaseItem* getItem() const; + + /// Associates a station object with this item + void setStation(GEOLIB::Station* stn) { _stn = stn; } + + /// Associates a BaseItem with this item + void setItem( BaseItem* item ) { _item = item; } + +private: + BaseItem* _item; + GEOLIB::Station* _stn; +}; + +#endif //QMODELTREEITEM_H diff --git a/Gui/DataView/ModellingTabWidget.cpp b/Gui/DataView/ModellingTabWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..85bc76df17803259afab49620828b86f2a330e60 --- /dev/null +++ b/Gui/DataView/ModellingTabWidget.cpp @@ -0,0 +1,26 @@ +/** + * \file ModellingTabWidget.cpp + * 2010/12/14 KR Initial implementation + * + * Implementation of StationTabWidget + */ + +// ** INCLUDES ** +#include "ProcessModel.h" +#include "ModellingTabWidget.h" + +ModellingTabWidget::ModellingTabWidget( QWidget* parent /*= 0*/ ) + : QWidget(parent) +{ + setupUi(this); +} + +void ModellingTabWidget::on_addProcessButton_pressed() +{ + emit requestNewProcess(); +} + +void ModellingTabWidget::on_deleteAllButton_pressed() +{ + static_cast<ProcessModel*>(this->treeView->model())->removeAllProcesses(); +} diff --git a/Gui/DataView/ModellingTabWidget.h b/Gui/DataView/ModellingTabWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..6a741be7b02671445f7f3ade5bb3b98c465ef14f --- /dev/null +++ b/Gui/DataView/ModellingTabWidget.h @@ -0,0 +1,31 @@ +/** + * \file ModellingTabWidget.h + * 2010/12/14 KR Initial implementation + * + */ + +#ifndef MODELLINGTABWIDGET_H +#define MODELLINGTABWIDGET_H + +// ** INCLUDES ** +#include "ui_ModellingTabWidgetBase.h" + +/** + * \brief Widget containing the ProcessView. + */ +class ModellingTabWidget : public QWidget, public Ui_ModellingTabWidgetBase +{ + Q_OBJECT + +public: + ModellingTabWidget(QWidget* parent = 0); + +private slots: + void on_addProcessButton_pressed(); + void on_deleteAllButton_pressed(); + +signals: + void requestNewProcess(); +}; + +#endif // MODELLINGTABWIDGET_H diff --git a/Gui/DataView/ModellingTabWidgetBase.ui b/Gui/DataView/ModellingTabWidgetBase.ui new file mode 100644 index 0000000000000000000000000000000000000000..d5ede9a4f068c67071fa36ad29cd9d0a27b778e0 --- /dev/null +++ b/Gui/DataView/ModellingTabWidgetBase.ui @@ -0,0 +1,52 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>ModellingTabWidgetBase</class> + <widget class="QWidget" name="ModellingTabWidgetBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>250</width> + <height>500</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="margin"> + <number>2</number> + </property> + <item> + <widget class="ProcessView" name="treeView"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="addProcessButton"> + <property name="text"> + <string>Add process...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="deleteAllButton"> + <property name="text"> + <string>Remove All</string> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>ProcessView</class> + <extends>QTreeView</extends> + <header>ProcessView.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Gui/DataView/MshEdit.ui b/Gui/DataView/MshEdit.ui new file mode 100644 index 0000000000000000000000000000000000000000..af36067029927f9fd365ff234b76dbe9d0ea27c9 --- /dev/null +++ b/Gui/DataView/MshEdit.ui @@ -0,0 +1,420 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MshEdit</class> + <widget class="QDialog" name="MshEdit"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>408</width> + <height>324</height> + </rect> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="tab3DExtrusion"> + <attribute name="title"> + <string>3D Extrusion</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QVBoxLayout" name="vLayout3DExtrusion"> + <property name="spacing"> + <number>16</number> + </property> + <item> + <widget class="QLabel" name="label_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>50</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Extrude Mesh-Elements to 3D</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Please specify the number of layers and their default thickness:</string> + </property> + <property name="margin"> + <number>0</number> + </property> + </widget> + </item> + <item> + <layout class="QGridLayout" name="gridLayout3DExtrusion"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>15</number> + </property> + <property name="horizontalSpacing"> + <number>16</number> + </property> + <property name="verticalSpacing"> + <number>26</number> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="labelNLayers"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Number of Layers</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="editNLayers"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="labelThickness"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Thickness</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="editThickness"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="2"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="2"> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="tabLayerMapping"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <attribute name="title"> + <string>Layer Mapping</string> + </attribute> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <property name="spacing"> + <number>0</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QScrollArea" name="scrollArea"> + <property name="frameShadow"> + <enum>QFrame::Sunken</enum> + </property> + <property name="lineWidth"> + <number>0</number> + </property> + <property name="widgetResizable"> + <bool>true</bool> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>382</width> + <height>249</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="spacing"> + <number>6</number> + </property> + <property name="margin"> + <number>9</number> + </property> + <item> + <layout class="QVBoxLayout" name="vLayoutLayerMapping"> + <property name="spacing"> + <number>16</number> + </property> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QLabel" name="label_5"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>50</height> + </size> + </property> + <property name="font"> + <font> + <pointsize>11</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Map mesh layers by raster</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Please specify which rasterfile should used for each mesh layer:</string> + </property> + </widget> + </item> + <item> + <layout class="QGridLayout" name="gridLayoutLayerMapping"> + <property name="margin"> + <number>0</number> + </property> + </layout> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>MshEdit</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>MshEdit</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/MshEditDialog.cpp b/Gui/DataView/MshEditDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1337841ef936ed3fb529fe920631e34f0f958004 --- /dev/null +++ b/Gui/DataView/MshEditDialog.cpp @@ -0,0 +1,157 @@ +/** + * \file MshEditDialog.cpp + * 2010/11/09 KR Initial implementation + */ + +#include "MshEditDialog.h" +#include "OGSError.h" +#include "StringTools.h" +#include "msh_mesh.h" + +#include <QCheckBox> +#include <QFileDialog> +#include <QPushButton> +#include <QSettings> + +MshEditDialog::MshEditDialog(const MeshLib::CFEMesh* mesh, QDialog* parent) + : QDialog(parent), _msh(mesh), _noDataDeleteBox(NULL) +{ + setupUi(this); + + this->gridLayoutLayerMapping->setMargin(5); + this->gridLayoutLayerMapping->setColumnMinimumWidth(2,10); + this->gridLayoutLayerMapping->setColumnStretch(0, 80); + this->gridLayoutLayerMapping->setColumnStretch(1, 200); + this->gridLayoutLayerMapping->setColumnStretch(2, 10); + + size_t nLayers = mesh->getNumberOfMeshLayers(); + + for (size_t i = 0; i <= nLayers+1; i++) + { + QString text(""); + if (i==0) text="Surface"; + else if (i>nLayers) text="Layer" + QString::number(nLayers) + "-Bottom"; + else text="Layer" + QString::number(i) + "-Top"; + QLabel* label = new QLabel(text); + QLineEdit* edit = new QLineEdit(); + QPushButton* button = new QPushButton("..."); + + _labels.push_back(label); + _edits.push_back(edit); + _buttons.push_back(button); + _fileButtonMap.insert(button, edit); + connect(button, SIGNAL(clicked()), this, SLOT(getFileName())); + + this->gridLayoutLayerMapping->addWidget(_labels[i], i, 0); + this->gridLayoutLayerMapping->addWidget(_edits[i], i, 1); + this->gridLayoutLayerMapping->addWidget(_buttons[i], i, 2); + + if (nLayers==0) break; // don't add bottom layer if mesh contains only surface + } + + _noDataDeleteBox = new QCheckBox("Remove mesh nodes at NoData values"); + _noDataDeleteBox->setChecked(false); + _noDataDeleteBox->setEnabled(false); + if (nLayers == 0) + { + _noDataDeleteBox->setEnabled(true); + this->gridLayoutLayerMapping->addWidget(_noDataDeleteBox, 2, 1); + } +} + +MshEditDialog::~MshEditDialog() +{ + delete _noDataDeleteBox; + + for (int i = 0; i < _labels.size(); i++) + { + delete _labels[i]; + delete _edits[i]; + delete _buttons[i]; + } +} + +void MshEditDialog::accept() +{ + int tabIndex = this->tabWidget->currentIndex(); + + if (tabIndex >= 0) + { + MeshLib::CFEMesh* new_mesh = NULL; + + switch (tabIndex) + { + case 0: + { + const int nLayers = atoi(this->editNLayers->text().toStdString().c_str()); + const double thickness = strtod(replaceString(",", ".", this->editThickness->text().toStdString()).c_str(), 0); + new_mesh = MshLayerMapper::CreateLayers(_msh, nLayers, thickness); + break; + } + case 1: + { + new_mesh = new MeshLib::CFEMesh(*_msh); + const size_t nLayers = _msh->getNumberOfMeshLayers(); + if (nLayers==0) + { + const std::string imgPath ( this->_edits[0]->text().toStdString() ); + if (!imgPath.empty()) + MshLayerMapper::LayerMapping(new_mesh, imgPath, nLayers, 0, _noDataDeleteBox->isChecked()); + } + else + { + for (size_t i = 1; i <= nLayers+1; i++) + { + const std::string imgPath ( this->_edits[i]->text().toStdString() ); + if (!imgPath.empty()) + { + int result = MshLayerMapper::LayerMapping(new_mesh, imgPath, nLayers, i-1, _noDataDeleteBox->isChecked()); + if (result==0) break; + } + } + } + if (nLayers>0 && this->_edits[0]->text().length()>0) + { + MeshLib::CFEMesh* final_mesh = MshLayerMapper::blendLayersWithSurface(new_mesh, nLayers, this->_edits[0]->text().toStdString()); + delete new_mesh; + new_mesh = final_mesh; + } + break; + } + default: + std::cout << + "Error in MshEditDialog::accept() - No instructions found for selected tab..." + << std::endl; + } + if (new_mesh) + { + std::string mshname("NewMesh"); + emit mshEditFinished(new_mesh, mshname); + } + else + OGSError::box("Error creating mesh"); + } + else + std::cout << "Error in MshEditDialog::accept() - No tab selected... " << std::endl; + this->done(QDialog::Accepted); +} + +void MshEditDialog::reject() +{ + this->done(QDialog::Rejected); +} + +void MshEditDialog::getFileName() +{ + QPushButton* button = dynamic_cast<QPushButton*>(this->sender()); + QSettings settings("UFZ", "OpenGeoSys-5"); + QString filename = QFileDialog::getOpenFileName(this, + "Select raster file to open", + settings.value( + "lastOpenedFileDirectory").toString( + ), + "ASCII raster files (*.asc);;All files (* *.*)"); + _fileButtonMap[button]->setText(filename); + QDir dir = QDir(filename); + settings.setValue("lastOpenedFileDirectory", dir.absolutePath()); +} diff --git a/Gui/DataView/MshEditDialog.h b/Gui/DataView/MshEditDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..214c04dabdfd767a0a912b4d124e090ce6bbbd05 --- /dev/null +++ b/Gui/DataView/MshEditDialog.h @@ -0,0 +1,54 @@ +/** + * \file MshEditDialog.h + * 2010/11/09 KR Initial implementation + */ + +#ifndef MSHEDITDIALOG_H +#define MSHEDITDIALOG_H + +#include "ui_MshEdit.h" +#include <QDialog> + +#include "MshLayerMapper.h" + +class QPushButton; +class QCheckBox; + +namespace MeshLib +{ +class CFEMesh; +} + +/** + * \brief A dialog window for editing meshes in various ways + */ +class MshEditDialog : public QDialog, private Ui_MshEdit +{ + Q_OBJECT + +public: + MshEditDialog(const MeshLib::CFEMesh* mesh, QDialog* parent = 0); + ~MshEditDialog(void); + +private: + const MeshLib::CFEMesh* _msh; + QVector<QLabel*> _labels; + QMap<QPushButton*, QLineEdit*> _fileButtonMap; + QVector<QLineEdit*> _edits; + QVector<QPushButton*> _buttons; + QCheckBox* _noDataDeleteBox; + +private slots: + void getFileName(); + + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void mshEditFinished(MeshLib::CFEMesh*, std::string&); +}; + +#endif //MSHEDITDIALOG_H diff --git a/Gui/DataView/MshItem.cpp b/Gui/DataView/MshItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d34b0b0ad0414993010f03baed7ed630b0744927 --- /dev/null +++ b/Gui/DataView/MshItem.cpp @@ -0,0 +1,26 @@ +/** + * \file MshItem.cpp + * 17/05/2010 KR Initial implementation + */ + +#include "GridAdapter.h" +#include "MshItem.h" +#include "VtkMeshSource.h" + +/** + * Constructor. + * \param data The data associated with each column + * \param parent The parent item in the tree + * \param grid The mesh associated with this item + */ +MshItem::MshItem(const QList<QVariant> &data, TreeItem* parent, GridAdapter* grid) + : TreeItem(data, parent) +{ + _meshSource = VtkMeshSource::New(); + _meshSource->SetGrid(grid); +} + +MshItem::~MshItem() +{ + _meshSource->Delete(); +} diff --git a/Gui/DataView/MshItem.h b/Gui/DataView/MshItem.h new file mode 100644 index 0000000000000000000000000000000000000000..548ee347b47e757ff8c530207970a64d409bd859 --- /dev/null +++ b/Gui/DataView/MshItem.h @@ -0,0 +1,35 @@ +/** + * \file MshItem.h + * 17/05/2010 KR Initial implementation + */ + +#ifndef MSHITEM_H +#define MSHITEM_H + +#include "TreeItem.h" +#include "VtkMeshSource.h" + +class GridAdapter; +class VtkMeshSource; + +/** + * \brief A TreeItem containing a mesh and the associated vtk object used in the Mesh Model. + * \sa TreeItem + */ +class MshItem : public TreeItem +{ +public: + /// Constructor, automatically generates VTK object of the given mesh. + MshItem(const QList<QVariant> &data, TreeItem* parent, GridAdapter* grid); + ~MshItem(); + + /// Returns the mesh as a GridAdapter. + const GridAdapter* getGrid() const { return this->_meshSource->GetGrid(); } + /// Returns the VTK object. + VtkMeshSource* vtkSource() const { return _meshSource; } + +private: + VtkMeshSource* _meshSource; +}; + +#endif //MSHITEM_H diff --git a/Gui/DataView/MshLayerMapper.cpp b/Gui/DataView/MshLayerMapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31cdd370a68e1b6d45e10110ae7c87226289dfdf --- /dev/null +++ b/Gui/DataView/MshLayerMapper.cpp @@ -0,0 +1,413 @@ +/** + * \file MshLayerMapper.cpp + * 01/11/2010 KR Initial implementation + */ + +#include "MshLayerMapper.h" +#include "VtkRaster.h" + +#include "MshEditor.h" +#include "GridAdapter.h" +#include "matrix_class.h" +#include "msh_mesh.h" + +#include <QImage> + +MeshLib::CFEMesh* MshLayerMapper::CreateLayers(const MeshLib::CFEMesh* mesh, + size_t nLayers, + double thickness) +{ + if (nLayers < 1 || thickness <= 0) + { + std::cout << + "Error in MshLayerMapper::CreateLayers() - Invalid parameter: nLayers > 0 and thickness > 0 are required." + << std::endl; + return NULL; + } +/* + if ((mesh->ele_vector[0]->GetElementType() != MshElemType::TRIANGLE) && (mesh->ele_vector[0]->GetElementType() != MshElemType::QUAD)) // check if mesh elements are triangles or quads + { + std::cout << "Error in MshLayerMapper::CreateLayers() - Method can only handle triangle- or quad-meshes... " << std::endl; + return NULL; + } + */ + MeshLib::CFEMesh* new_mesh ( new MeshLib::CFEMesh() ); + const size_t nNodes = mesh->nod_vector.size(); + const size_t nElems = mesh->ele_vector.size(); + + for (size_t layer_id = 0; layer_id <= nLayers; layer_id++) + { + // add nodes for new layer + size_t node_offset ( nNodes * layer_id ); + const double z_offset ( layer_id*thickness ); + for (size_t i = 0; i < nNodes; i++) + { + const double* coords = mesh->nod_vector[i]->getData(); + new_mesh->nod_vector.push_back( new MeshLib::CNode(node_offset + i, + coords[0], + coords[1], + coords[2]-z_offset) ); + } + + if (layer_id > 0) // starting with the 2nd layer prism (or hex) elements can be created + { + // create prism elements connecting the last layer with the current one + node_offset = (layer_id - 1) * nNodes; + for (size_t i = 0; i < nElems; i++) + { + const MeshLib::CElem* sfc_elem( mesh->ele_vector[i] ); + MeshLib::CElem* elem( new MeshLib::CElem() ); + size_t nElemNodes = sfc_elem->getNodeIndices().Size(); + if (sfc_elem->GetElementType() == MshElemType::TRIANGLE) + elem->setElementProperties(MshElemType::PRISM); // extrude triangles to prism + else if (sfc_elem->GetElementType() == MshElemType::QUAD) + elem->setElementProperties(MshElemType::HEXAHEDRON); // extrude quads to hexes + else if (sfc_elem->GetElementType() == MshElemType::LINE) + continue; // line elements are ignored and not duplicated + else + { + std::cout << "Error in MshLayerMapper::CreateLayers() - Method can only handle 2D mesh elements ..." << std::endl; + std::cout << "Element " << i << " is of type \"" << MshElemType2String(sfc_elem->GetElementType()) << "\"." << std::endl; + delete new_mesh; + return NULL; + } + elem->SetPatchIndex(nLayers - layer_id); + elem->SetNodesNumber(2 * nElemNodes); + elem->getNodeIndices().resize(2 * nElemNodes); + for (size_t j = 0; j < nElemNodes; j++) + { + long idx = sfc_elem->GetNodeIndex(j); + elem->SetNodeIndex(nElemNodes-j-1, node_offset + idx); + elem->SetNodeIndex(nElemNodes-j-1 + nElemNodes, node_offset + nNodes + idx); + } + new_mesh->ele_vector.push_back(elem); + } + } + } + + new_mesh->setNumberOfNodesFromNodesVectorSize (); + new_mesh->setNumberOfMeshLayers(nLayers); + + new_mesh->ConstructGrid(); + new_mesh->FillTransformMatrix(); + + return new_mesh; +} + +int MshLayerMapper::LayerMapping(MeshLib::CFEMesh* new_mesh, + const std::string &rasterfile, + const size_t nLayers, + const size_t layer_id, + bool removeNoDataValues) +{ + if (new_mesh == NULL) + { + std::cout << + "Error in MshLayerMapper::LayerMapping() - Passed Mesh is NULL..." << + std::endl; + return 0; + } + + if (new_mesh->getNumberOfMeshLayers() >= layer_id) + { + double x0(0), y0(0), delta(1); + size_t width(1), height(1); + float* elevation = VtkRaster::loadDataFromASC(rasterfile, x0, y0, width,height, delta); + + if (elevation == NULL) + { + delete [] elevation; + return 0; + } + + const std::pair<double, double> xDim(x0, x0 + width * delta); // extension in x-dimension + const std::pair<double, double> yDim(y0, y0 + height * delta); // extension in y-dimension + + if (!meshFitsImage(new_mesh, xDim, yDim)) + { + delete [] elevation; + return 0; + } + + const size_t nNodes = new_mesh->nod_vector.size(); + const size_t nNodesPerLayer = nNodes / (nLayers+1); + + const size_t firstNode = layer_id * nNodesPerLayer; + const size_t lastNode = firstNode + nNodesPerLayer; + + std::vector<size_t> noData_nodes; + const double half_delta = 0.5*delta; + for(size_t i = firstNode; i < lastNode; i++) + { + const double* coords = new_mesh->nod_vector[i]->getData(); + // position in raster + const double xPos ((coords[0] - xDim.first) / delta); + const double yPos ((coords[1] - yDim.first) / delta); + // raster cell index + const size_t xIdx (static_cast<size_t>(floor(xPos))); + const size_t yIdx (static_cast<size_t>(floor(yPos))); + + // deviation of mesh node from centre of raster cell ( in [-1:1) because it is normalised by delta/2 ) + const double xShift = (xPos-xIdx-half_delta)/half_delta; + const double yShift = (yPos-yIdx-half_delta)/half_delta; + + const int xShiftIdx = (xShift>=0) ? ceil(xShift) : floor(xShift); + const int yShiftIdx = (yShift>=0) ? ceil(yShift) : floor(yShift); + + // determining the neighbouring pixels that add weight to the interpolation + const size_t x_nb[4] = {0, xShiftIdx, xShiftIdx, 0}; + const size_t y_nb[4] = {0, 0, yShiftIdx, yShiftIdx}; + + double locZ[4]; + locZ[0] = elevation[2*(yIdx*width + xIdx)]; + if (fabs(locZ[0] + 9999) > std::numeric_limits<double>::min()) + { + for (size_t j=1; j<4; j++) + { + locZ[j] = elevation[2*((yIdx+y_nb[j])*width + (xIdx+x_nb[j]))]; + if (fabs(locZ[j] + 9999) < std::numeric_limits<double>::min()) + locZ[j]=locZ[0]; + } + + double ome[4]; + double xi = 1-fabs(xShift); + double eta = 1-fabs(xShift); + MPhi2D(ome, xi, eta); + + double z(0.0); + for(size_t j = 0; j < 4; j++) + z += ome[j] * locZ[j]; + new_mesh->nod_vector[i]->SetZ(z); + new_mesh->nod_vector[i]->SetMark(true); + } + else + { + new_mesh->nod_vector[i]->SetZ(0); + new_mesh->nod_vector[i]->SetMark(false); + noData_nodes.push_back(i); + } + } + + if ((nLayers == 0) && removeNoDataValues) + { + if (noData_nodes.size() < (new_mesh->nod_vector.size() - 2)) + { + std::cout << "Warning: Removing " << noData_nodes.size() << + " mesh nodes at NoData values ... " << std::endl; + MeshLib::CFEMesh* red_mesh = MshEditor::removeMeshNodes( + new_mesh, + noData_nodes); + if (!new_mesh->ele_vector.empty()) + { + delete new_mesh; + new_mesh = red_mesh; + } + else + { + delete red_mesh; + std::cout << "Too many NoData values..." << std::endl; + } + } + else + std::cout << "Too many NoData values..." << std::endl; + } + + delete [] elevation; + return 1; + } + else + std::cout << "Error in MshLayerMapper::LayerMapping() - Mesh has only " << + new_mesh->getNumberOfMeshLayers() << " Layers, cannot assign layer " << layer_id << + "..." << std::endl; + return 0; +} + +// KR, based on code by WW (Note: this method has not been tested yet and will probably fail miserably!) +bool MshLayerMapper::meshFitsImage(const MeshLib::CFEMesh* msh, + const std::pair<double, double> &xDim, + const std::pair<double, double> &yDim) +{ + double const* pnt (msh->nod_vector[0]->getData()); + double xMin(pnt[0]); + double yMin(pnt[1]); + double xMax(pnt[0]); + double yMax(pnt[1]); + + size_t nNodes = msh->nod_vector.size(); + for (size_t i = 1; i < nNodes; i++) + { + pnt = msh->nod_vector[i]->getData(); + if (xMin > pnt[0]) + xMin = pnt[0]; + else if (xMax < pnt[0]) + xMax = pnt[0]; + + if (yMin > pnt[1]) + yMin = pnt[1]; + else if (yMax < pnt[1]) + yMax = pnt[1]; + } + + if (xMin < xDim.first || xMax > xDim.second || yMin < yDim.first || yMax > yDim.second) + { + std::cout << "Warning: Mesh does not fit into given raster file." << std::endl; + return false; + } + return true; +} + +MeshLib::CFEMesh* MshLayerMapper::blendLayersWithSurface(MeshLib::CFEMesh* mesh, const size_t nLayers, const std::string &dem_raster) +{ + // construct surface mesh from DEM + MeshLib::CFEMesh* dem = MshEditor::getMeshSurface(*mesh); + MshLayerMapper::LayerMapping(dem, dem_raster, 0, 0); + + const size_t nNodes = mesh->nod_vector.size(); + const size_t nNodesPerLayer = nNodes / (nLayers+1); + std::vector<bool> is_surface_node(nNodes, false); + std::vector<bool> nodes_below_surface(nNodes, false); + + // check if bottom layer nodes are below DEM + const size_t bottom_firstNode = nLayers * nNodesPerLayer; + const size_t bottom_lastNode = bottom_firstNode + nNodesPerLayer; + for(size_t i = bottom_firstNode; i < bottom_lastNode; i++) + { + nodes_below_surface[i]=true; + const double* coords = mesh->nod_vector[i]->getData(); + const double* dem_coords = dem->nod_vector[i-bottom_firstNode]->getData(); + if (coords[2] >= dem_coords[2]) + { + std::cout << "Warning: Node " << i << " (in bottom-layer) is above surface node " << (i-bottom_firstNode) << ". (" << coords[2] << " > " << dem_coords[2] << ")" << std::endl; + is_surface_node[i] = true; + } + } + + // for all other layers: + // if node < dem-node: do nothing + // if node > dem-node: + // if first node above surface: map to dem and mark as surface node + // else remove node + for (int layer_id=nLayers-1; layer_id>=0; layer_id--) + { + const size_t firstNode = layer_id * nNodesPerLayer; + const size_t lastNode = firstNode + nNodesPerLayer; + + for(size_t i = firstNode; i < lastNode; i++) + { + if (is_surface_node[i+nNodesPerLayer]) + is_surface_node[i]=true; + else + { + nodes_below_surface[i]=true; + MeshLib::CNode* node (mesh->nod_vector[i]); + const double* coords = node->getData(); + const double* dem_coords = dem->nod_vector[i-firstNode]->getData(); + if (coords[2] > dem_coords[2]) + { + const double new_coords[3] = { dem_coords[0], dem_coords[1], dem_coords[2] }; + node->SetCoordinates(new_coords); + is_surface_node[i] = true; + } + } + } + } + + std::vector<GEOLIB::Point*> *nodes = new std::vector<GEOLIB::Point*>; + std::vector<int> node_index_map(nNodes, -1); + size_t node_count(0); + for (size_t j=0; j<nNodes; j++) + { + if (nodes_below_surface[j]) + { + nodes->push_back(new GEOLIB::Point(mesh->nod_vector[j]->getData())); + node_index_map[j]=node_count++; + } + } + + const size_t nElems = mesh->ele_vector.size(); + std::vector<GridAdapter::Element*> *elements = new std::vector<GridAdapter::Element*>; + for (size_t j=0; j<nElems; j++) + { + const MeshLib::CElem* elem = mesh->ele_vector[j]; + + size_t count(0); + for (size_t i=0; i<6; i++) // check top surface of prism + if (nodes_below_surface[elem->GetNodeIndex(i)]) count++; + + if (count==6) // copy prism elements if all six nodes are valid + { + GridAdapter::Element* prism = new GridAdapter::Element; + std::vector<size_t> elem_nodes; + for (size_t i=0; i<6; i++) + elem_nodes.push_back( node_index_map[elem->GetNodeIndex(i)] ); + prism->material = elem->GetPatchIndex(); + prism->type = MshElemType::PRISM; + prism->nodes = elem_nodes; + elements->push_back(prism); + } + else if (count==5) // change the current element to two tetrahedra if only five nodes are valid + { + GridAdapter::Element* tet1 = new GridAdapter::Element; + std::vector<size_t> elem_nodes; + if (nodes_below_surface[elem->GetNodeIndex(0)]) + elem_nodes.push_back( node_index_map[elem->GetNodeIndex(0)] ); + else + elem_nodes.push_back( node_index_map[elem->GetNodeIndex(1)] ); + for (size_t i=3; i<6; i++) + elem_nodes.push_back( node_index_map[elem->GetNodeIndex(i)] ); + tet1->material = elem->GetPatchIndex(); + tet1->type = MshElemType::TETRAHEDRON; + tet1->nodes = elem_nodes; + elements->push_back(tet1); + + GridAdapter::Element* tet2 = new GridAdapter::Element; + std::vector<size_t> elem_nodes2; + if (nodes_below_surface[elem->GetNodeIndex(0)]) + { + elem_nodes2.push_back( node_index_map[elem->GetNodeIndex(0)] ); + if (nodes_below_surface[elem->GetNodeIndex(1)]) + elem_nodes2.push_back( node_index_map[elem->GetNodeIndex(1)] ); + else + elem_nodes2.push_back( node_index_map[elem->GetNodeIndex(2)] ); + elem_nodes2.push_back( node_index_map[elem->GetNodeIndex(5)] ); + elem_nodes2.push_back( node_index_map[elem->GetNodeIndex(4)] ); + } + else + { + elem_nodes2.push_back( node_index_map[elem->GetNodeIndex(1)] ); + elem_nodes2.push_back( node_index_map[elem->GetNodeIndex(2)] ); + elem_nodes2.push_back( node_index_map[elem->GetNodeIndex(3)] ); + elem_nodes2.push_back( node_index_map[elem->GetNodeIndex(5)] ); + } + tet2->material = elem->GetPatchIndex(); + tet2->type = MshElemType::TETRAHEDRON; + tet2->nodes = elem_nodes2; + elements->push_back(tet2); + } + else if (count==4) // change the current element to a tetrahedron if only four nodes are valid + { + std::vector<size_t> elem_nodes; + for (size_t i=0; i<3; i++) + if (nodes_below_surface[elem->GetNodeIndex(i)]) + elem_nodes.push_back( node_index_map[elem->GetNodeIndex(i)] ); + + if (elem_nodes.size()==1) // make sure than only one node is from the upper layer and three from the lower + { + for (size_t i=3; i<6; i++) + elem_nodes.push_back( node_index_map[elem->GetNodeIndex(i)] ); + GridAdapter::Element* tet = new GridAdapter::Element; + tet->material = elem->GetPatchIndex(); + tet->type = MshElemType::TETRAHEDRON; + tet->nodes = elem_nodes; + elements->push_back(tet); + } + } + // else remove element, if less than four nodes are valid + } + GridAdapter grid; + grid.setNodeVector(nodes); + grid.setElements(elements); + MeshLib::CFEMesh* struct_mesh = new MeshLib::CFEMesh(*grid.getCFEMesh()); + return struct_mesh; +} + diff --git a/Gui/DataView/MshLayerMapper.h b/Gui/DataView/MshLayerMapper.h new file mode 100644 index 0000000000000000000000000000000000000000..daf3833971a427b881adc03d22191f9965e7d5a5 --- /dev/null +++ b/Gui/DataView/MshLayerMapper.h @@ -0,0 +1,55 @@ +/** + * \file MshLayerMapper.h + * 01/11/2010 KR Initial implementation + */ + +#ifndef MSHLAYERMAPPER_H +#define MSHLAYERMAPPER_H + +#include <string> + +class QImage; + +namespace MeshLib +{ +class CFEMesh; +} + +/** + * \brief Manipulating and adding layers to an existing mesh + */ +class MshLayerMapper +{ +public: + MshLayerMapper() {} + ~MshLayerMapper() {} + + /** + * Based on a triangle-or quad mesh this method creates a 3D mesh with with a given number of prism- or hex-layers + * \param mesh The triangle/quad mesh that is the basis for the new prism/hex mesh + * \param nLayers The number of layers of prism/hex elements that will be extruded from the triangle/quad elements of the original mesh + * \param thickness The thickness of each of these newly added layers + * \return A mesh with the requested number of layers of prism/hex elements + */ + static MeshLib::CFEMesh* CreateLayers(const MeshLib::CFEMesh* mesh, + size_t nLayers, + double thickness); + + /// Maps the z-values of nodes in the designated layer of the given mesh according to the given raster. + static int LayerMapping(MeshLib::CFEMesh* msh, + const std::string &rasterfile, + const size_t nLayers, + const size_t layer_id, + bool removeNoDataValues = false); + + /// Blends a mesh with the surface given by dem_raster. Nodes and elements above the surface are either removed or adapted to fit the surface. + static MeshLib::CFEMesh* blendLayersWithSurface(MeshLib::CFEMesh* mesh, const size_t nLayers, const std::string &dem_raster); + +private: + /// Checks if the given mesh is within the dimensions given by xDim and yDim. + static bool meshFitsImage(const MeshLib::CFEMesh* msh, + const std::pair<double, double> &xDim, + const std::pair<double, double> &yDim); +}; + +#endif //MSHLAYERMAPPER_H diff --git a/Gui/DataView/MshModel.cpp b/Gui/DataView/MshModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fed3acb09e80b37dd018e967e221351c8e06b67e --- /dev/null +++ b/Gui/DataView/MshModel.cpp @@ -0,0 +1,204 @@ +/** + * \file MshModel.cpp + * 19/10/2009 LB Initial implementation + * 12/05/2010 KR re-implementation + * + * Implementation of MshModel + */ + +// ** INCLUDES ** +#include "MshItem.h" +#include "MshModel.h" +#include "StringTools.h" +#include "TreeItem.h" +#include "VtkMeshSource.h" + +#include "msh_lib.h" + +#include <QFileInfo> +#include <QString> +#include <QTime> + +MshModel::MshModel(ProjectData &project, QObject* parent /*= 0*/ ) + : TreeModel(parent), _project(project) +{ + delete _rootItem; + QList<QVariant> rootData; + rootData << "Mesh Name" << "Type" << "Node IDs"; + _rootItem = new TreeItem(rootData, NULL); +} + +int MshModel::columnCount( const QModelIndex &parent /*= QModelIndex()*/ ) const +{ + Q_UNUSED(parent) + + return 3; +} + +void MshModel::addMesh(MeshLib::CFEMesh* mesh, std::string &name) +{ + _project.addMesh(mesh, name); + GridAdapter* grid = new GridAdapter(mesh); + grid->setName(name); + this->addMeshObject(grid); +} + +void MshModel::addMesh(GridAdapter* mesh) +{ + MeshLib::CFEMesh* ogsmesh( const_cast<MeshLib::CFEMesh*>(mesh->getCFEMesh()) ); + std::string msh_name = mesh->getName(); + _project.addMesh(ogsmesh, msh_name); + this->addMeshObject(mesh); +} + +void MshModel::addMeshObject(GridAdapter* mesh) +{ + std::string name(mesh->getName()); + std::cout << "name: " << name << std::endl; + QFileInfo fi(QString::fromStdString(name)); + name = fi.baseName().toStdString(); + mesh->setName(name); + QList<QVariant> meshData; + meshData << QString::fromStdString(name) << ""; + MshItem* newMesh = new MshItem(meshData, _rootItem, mesh); + if (newMesh->vtkSource()) + newMesh->vtkSource()->SetName(fi.fileName()); + _rootItem->appendChild(newMesh); + + // display elements + const std::vector<GridAdapter::Element*>* elems = mesh->getElements(); + const size_t nElems (elems->size()); + QString elem_type_string(""); + MshElemType::type elem_type(MshElemType::INVALID); + + for (size_t i = 0; i < nElems; i++) + { + const GridAdapter::Element* current_element = (*elems)[i]; + QList<QVariant> elemData; + + if (current_element->type != elem_type) + { + elem_type = current_element->type; + elem_type_string = QString::fromStdString(MshElemType2String(current_element->type)); + } + + QString nodestxt(""); + const size_t nNodes(current_element->nodes.size()); + for (size_t j = 0; j < nNodes; j++) + nodestxt.append(QString::number(current_element->nodes[j]) + ", "); + + elemData << "Element " + QString::number(i) << elem_type_string << nodestxt.left(nodestxt.length() - 2); + + TreeItem* elem = new TreeItem(elemData, newMesh); + newMesh->appendChild(elem); + } + + reset(); + + emit meshAdded(this, this->index(_rootItem->childCount() - 1, 0, QModelIndex())); +} + +const GridAdapter* MshModel::getMesh(const QModelIndex &idx) const +{ + if (idx.isValid()) + { + MshItem* item = dynamic_cast<MshItem*>(this->getItem(idx)); + if (item) + return item->getGrid(); + else + return NULL; + } + std::cout << "MshModel::getMesh() - Specified index does not exist." << std::endl; + return NULL; +} + +const GridAdapter* MshModel::getMesh(const std::string &name) const +{ + for (int i = 0; i < _rootItem->childCount(); i++) + { + MshItem* item = static_cast<MshItem*>(_rootItem->child(i)); + if (item->data(0).toString().toStdString().compare(name) == 0) + return item->getGrid(); + } + + std::cout << "MshModel::getMesh() - No entry found with name \"" << name << "\"." << + std::endl; + return NULL; +} + +bool MshModel::removeMesh(const QModelIndex &idx) +{ + if (idx.isValid()) + { + MshItem* item = dynamic_cast<MshItem*>(this->getItem(idx)); + if (item) + { + emit meshRemoved(this, idx); + _rootItem->removeChildren(item->row(),1); + reset(); + return true; + } + return false; + } + + return false; +} + +bool MshModel::removeMesh(const std::string &name) +{ + for (int i = 0; i < _rootItem->childCount(); i++) + { + TreeItem* item = _rootItem->child(i); + if (item->data(0).toString().toStdString().compare(name) == 0) + { + emit meshRemoved(this, this->index(i, 0, QModelIndex())); + _rootItem->removeChildren(i,1); + reset(); + return _project.removeMesh(name); + } + } + + std::cout << "MshModel::removeMesh() - No entry found with name \"" << name << "." << + std::endl; + return false; +} + +void MshModel::updateModel() +{ + const std::map<std::string, MeshLib::CFEMesh*> msh_vec = _project.getMeshObjects(); + for (std::map<std::string, MeshLib::CFEMesh*>::const_iterator it(msh_vec.begin()); + it != msh_vec.end(); ++it) + if (this->getMesh(it->first) == NULL) // if GridAdapter does not yet exist, create one. + { + std::string name = it->first; + addMeshObject(new GridAdapter(it->second)); + } +} + +VtkMeshSource* MshModel::vtkSource(const QModelIndex &idx) const +{ + if (idx.isValid()) + { + MshItem* item = static_cast<MshItem*>(this->getItem(idx)); + return item->vtkSource(); + } + + std::cout << "MshModel::removeMesh() - Specified index does not exist." << std::endl; + return NULL; +} + +VtkMeshSource* MshModel::vtkSource(const std::string &name) const +{ + for (int i = 0; i < _rootItem->childCount(); i++) + { + MshItem* item = static_cast<MshItem*>(_rootItem->child(i)); + if (item->data(0).toString().toStdString().compare(name) == 0) + return item->vtkSource(); + } + + std::cout << "MshModel::getMesh() - No entry found with name \"" << name << "\"." << + std::endl; + return NULL; +} + + diff --git a/Gui/DataView/MshModel.h b/Gui/DataView/MshModel.h new file mode 100644 index 0000000000000000000000000000000000000000..c64edaa90c49f83642af0be9ed97ed360d9e0d6f --- /dev/null +++ b/Gui/DataView/MshModel.h @@ -0,0 +1,64 @@ +/** + * \file MshModel.h + * 19/10/2009 LB Initial implementation + * 12/05/2010 KR re-implementation + * + */ + +#ifndef MSHMODEL_H +#define MSHMODEL_H + +// ** INCLUDES ** +#include "GridAdapter.h" +#include "ProjectData.h" +#include "TreeModel.h" + +class VtkMeshSource; + +/** + * The MshModel is a Qt model which represents Mesh objects. + */ +class MshModel : public TreeModel +{ + Q_OBJECT + +public: + MshModel(ProjectData &project, QObject* parent = 0); + + /// Returns the number of columns used for the data list + int columnCount(const QModelIndex& parent = QModelIndex()) const; + +public slots: + /// Adds a new mesh + void addMesh(GridAdapter* mesh); + /// Adds a new mesh + void addMesh(MeshLib::CFEMesh* mesh, std::string &name); // needs only to be a slot for MshLayerMapper. Otherwise normal function would be okay. + /// Returns the mesh with the given index. + const GridAdapter* getMesh(const QModelIndex &idx) const; + /// Returns the mesh with the given name. + const GridAdapter* getMesh(const std::string &name) const; + /// Removes the mesh with the given index. + bool removeMesh(const QModelIndex &idx); + /// Removes the mesh with the given name. + bool removeMesh(const std::string &name); + /// Updates the model based on the ProjectData-object + void updateModel(); + /// Returns the VTK source item for the mesh with the given index. + VtkMeshSource* vtkSource(const QModelIndex &idx) const; + /// Returns the VTK source item for the mesh with the given name. + VtkMeshSource* vtkSource(const std::string &name) const; + +private: + /// Adds the mesh to the GUI-Mesh-Model und -View + void addMeshObject(GridAdapter* mesh); + + /// Checks if the name of the mesh is already exists, if so it generates a unique name. + //bool isUniqueMeshName(std::string &name); + ProjectData& _project; + +signals: + void meshAdded(MshModel*, const QModelIndex&); + void meshRemoved(MshModel*, const QModelIndex&); +}; + +#endif // MSHMODEL_H diff --git a/Gui/DataView/MshQualitySelection.ui b/Gui/DataView/MshQualitySelection.ui new file mode 100644 index 0000000000000000000000000000000000000000..d082f66f6f32f99ae798acb28692800d047fe152 --- /dev/null +++ b/Gui/DataView/MshQualitySelection.ui @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MshQualitySelection</class> + <widget class="QDialog" name="MshQualitySelection"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>247</width> + <height>257</height> + </rect> + </property> + <property name="windowTitle"> + <string>Mesh Quality Selection</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Select Quality Measure</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QRadioButton" name="choiceEdges"> + <property name="text"> + <string>Aspect Ratio of Edge Length</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="choiceArea"> + <property name="text"> + <string>Area of 2D Elements</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="choiceVolume"> + <property name="text"> + <string>Volume of 3D Elements</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="choiceAngles"> + <property name="text"> + <string>Angles between Adjacent Edges</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>MshQualitySelection</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>MshQualitySelection</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/MshQualitySelectionDialog.cpp b/Gui/DataView/MshQualitySelectionDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3deac76eb0bb2fd17abec324364ce632cf09d206 --- /dev/null +++ b/Gui/DataView/MshQualitySelectionDialog.cpp @@ -0,0 +1,44 @@ +/** + * \file MshQualitySelectionDialog.cpp + * 2011/03/16 KR Initial implementation + */ + +#include "MshQualitySelectionDialog.h" +#include "VtkMeshSource.h" + +/// Constructor +MshQualitySelectionDialog::MshQualitySelectionDialog(VtkMeshSource* msh, QDialog* parent) + : QDialog(parent), _msh(msh) +{ + setupUi(this); + this->choiceEdges->toggle(); +} + +MshQualitySelectionDialog::~MshQualitySelectionDialog() +{ +} + +/// Instructions if the OK-Button has been pressed. +void MshQualitySelectionDialog::accept() +{ + MshQualityType::type t; + if (this->choiceEdges->isChecked()) + t = MshQualityType::EDGERATIO; + else if (this->choiceArea->isChecked()) + t = MshQualityType::AREA; + else if (this->choiceVolume->isChecked()) + t = MshQualityType::VOLUME; + else if (this->choiceAngles->isChecked()) + t = MshQualityType::EQUIANGLESKEW; + else + t = MshQualityType::INVALID; + + emit measureSelected(_msh, t); + this->done(QDialog::Accepted); +} + +/// Instructions if the Cancel-Button has been pressed. +void MshQualitySelectionDialog::reject() +{ + this->done(QDialog::Rejected); +} diff --git a/Gui/DataView/MshQualitySelectionDialog.h b/Gui/DataView/MshQualitySelectionDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..a74d3e2a4e3a6b24a55af3223b135d927f508423 --- /dev/null +++ b/Gui/DataView/MshQualitySelectionDialog.h @@ -0,0 +1,37 @@ +/** + * \file MshQualitySelectionDialog.h + * 2011/03/16 KR Initial implementation + */ + +#ifndef MSHQUALITYSELECTIONDIALOG_H +#define MSHQUALITYSELECTIONDIALOG_H + +#include "MSHEnums.h" +#include "ui_MshQualitySelection.h" +#include <QDialog> + +class VtkMeshSource; + +/** + * \brief A dialog window for settung up a database connection + */ +class MshQualitySelectionDialog : public QDialog, private Ui_MshQualitySelection +{ + Q_OBJECT + +public: + MshQualitySelectionDialog(VtkMeshSource* msh, QDialog* parent = 0); + ~MshQualitySelectionDialog(void); + +private: + VtkMeshSource* _msh; + +private slots: + void accept(); + void reject(); + +signals: + void measureSelected(VtkMeshSource*, MshQualityType::type); +}; + +#endif //MSHQUALITYSELECTIONDIALOG_H diff --git a/Gui/DataView/MshTabWidget.cpp b/Gui/DataView/MshTabWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fbe82e62f1c54af2b81f0e695c0df90890ee7498 --- /dev/null +++ b/Gui/DataView/MshTabWidget.cpp @@ -0,0 +1,19 @@ +/** + * \file MshTabWidget.cpp + * 3/11/2009 LB Initial implementation + * 18/05/2010 KR Re-Implementation + * + * Implementation of MshTabWidget + */ + +// ** INCLUDES ** +#include "MshTabWidget.h" + +MshTabWidget::MshTabWidget( QWidget* parent /*= 0*/ ) + : QWidget(parent) +{ + setupUi(this); + + connect(this->addMeshPushButton, SIGNAL(clicked()), this->treeView, SLOT(addMeshAction())); + connect(this->clearAllPushButton, SIGNAL(clicked()), this->treeView, SLOT(removeAllMeshes())); +} diff --git a/Gui/DataView/MshTabWidget.h b/Gui/DataView/MshTabWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..40722c3d21d390f208cbec50d50205d5943e94ff --- /dev/null +++ b/Gui/DataView/MshTabWidget.h @@ -0,0 +1,25 @@ +/** + * \file MshTabWidget.h + * 3/11/2009 LB Initial implementation + * 18/05/2010 KR Re-Implementation + * + */ + +#ifndef MSHTABWIDGET_H +#define MSHTABWIDGET_H + +// ** INCLUDES ** +#include "ui_MshTabWidgetBase.h" + +/** + * \brief Widget for data views of meshes. + */ +class MshTabWidget : public QWidget, public Ui_MshTabWidgetBase +{ + Q_OBJECT + +public: + MshTabWidget(QWidget* parent = 0); +}; + +#endif // MSHTABWIDGET_H diff --git a/Gui/DataView/MshTabWidgetBase.ui b/Gui/DataView/MshTabWidgetBase.ui new file mode 100644 index 0000000000000000000000000000000000000000..b83f93919abc653bc0e1d1bc25dfc6d1af5f9499 --- /dev/null +++ b/Gui/DataView/MshTabWidgetBase.ui @@ -0,0 +1,85 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MshTabWidgetBase</class> + <widget class="QWidget" name="MshTabWidgetBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>227</width> + <height>500</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="margin"> + <number>2</number> + </property> + <item> + <widget class="DataView" name="treeView"/> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QPushButton" name="addMeshPushButton"> + <property name="text"> + <string>Add mesh...</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="clearAllPushButton"> + <property name="text"> + <string>Remove All</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="topMargin"> + <number>10</number> + </property> + <item> + <widget class="QLabel" name="label"> + <property name="font"> + <font> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="text"> + <string>Element Properties: </string> + </property> + </widget> + </item> + <item> + <widget class="QLabel" name="label_2"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>(for picked elements)</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="DataView" name="elementView"/> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>DataView</class> + <extends>QTreeView</extends> + <header>DataView.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Gui/DataView/NetCdfConfigure.ui b/Gui/DataView/NetCdfConfigure.ui new file mode 100644 index 0000000000000000000000000000000000000000..18ed8e38a2c2432a7866174eb48ae6d19f9985e4 --- /dev/null +++ b/Gui/DataView/NetCdfConfigure.ui @@ -0,0 +1,801 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>NetCdfConfigure</class> + <widget class="QDialog" name="NetCdfConfigure"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>477</width> + <height>460</height> + </rect> + </property> + <property name="cursor"> + <cursorShape>SizeAllCursor</cursorShape> + </property> + <property name="windowTitle"> + <string>Dialog</string> + </property> + <layout class="QGridLayout" name="gridLayout_3"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Variable</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="comboBoxVariable"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item row="1" column="0" colspan="3"> + <widget class="QGroupBox" name="groupBoxDimensions"> + <property name="minimumSize"> + <size> + <width>450</width> + <height>100</height> + </size> + </property> + <property name="title"> + <string>Dimensions for the Axis</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="3"> + <widget class="QDoubleSpinBox" name="doubleSpinBoxDim1End"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>110</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>110</width> + <height>16777215</height> + </size> + </property> + <property name="wrapping"> + <bool>false</bool> + </property> + <property name="frame"> + <bool>true</bool> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="accelerated"> + <bool>false</bool> + </property> + <property name="maximum"> + <double>10000000.000000000000000</double> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QDoubleSpinBox" name="doubleSpinBoxDim1Start"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>110</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="maximum"> + <double>10000000.000000000000000</double> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QDoubleSpinBox" name="doubleSpinBoxDim2Start"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>110</width> + <height>0</height> + </size> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="maximum"> + <double>10000000.000000000000000</double> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QDoubleSpinBox" name="doubleSpinBoxDim2End"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="minimumSize"> + <size> + <width>110</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>110</width> + <height>16777215</height> + </size> + </property> + <property name="font"> + <font> + <italic>false</italic> + </font> + </property> + <property name="readOnly"> + <bool>true</bool> + </property> + <property name="maximum"> + <double>10000000.000000000000000</double> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Value Start</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Value End</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="comboBoxDim1"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QComboBox" name="comboBoxDim2"> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_4"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Lat</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_8"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Lon</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="8" column="2"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="8" column="0" colspan="2"> + <spacer name="horizontalSpacer_3"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer_4"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="0" colspan="3"> + <widget class="QGroupBox" name="groupBox"> + <property name="minimumSize"> + <size> + <width>450</width> + <height>0</height> + </size> + </property> + <property name="title"> + <string>Other Dimensions</string> + </property> + <layout class="QGridLayout" name="gridLayout_4"> + <item row="0" column="0"> + <widget class="QLabel" name="label_9"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Time</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_10"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Others</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QComboBox" name="comboBoxDim3"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>80</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="QComboBox" name="comboBoxDim4"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="minimumSize"> + <size> + <width>80</width> + <height>0</height> + </size> + </property> + </widget> + </item> + <item row="3" column="2"> + <widget class="QSpinBox" name="spinBoxDim4"> + <property name="minimumSize"> + <size> + <width>110</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>110</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QDateTimeEdit" name="dateTimeEditDim3"> + <property name="minimumSize"> + <size> + <width>110</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>110</width> + <height>16777215</height> + </size> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <property name="dateTime"> + <datetime> + <hour>0</hour> + <minute>0</minute> + <second>0</second> + <year>1900</year> + <month>1</month> + <day>1</day> + </datetime> + </property> + <property name="date"> + <date> + <year>1900</year> + <month>1</month> + <day>1</day> + </date> + </property> + <property name="maximumDateTime"> + <datetime> + <hour>23</hour> + <minute>59</minute> + <second>59</second> + <year>2200</year> + <month>12</month> + <day>31</day> + </datetime> + </property> + <property name="minimumDateTime"> + <datetime> + <hour>0</hour> + <minute>0</minute> + <second>0</second> + <year>1900</year> + <month>1</month> + <day>1</day> + </datetime> + </property> + <property name="displayFormat"> + <string>dd.MM.yyyy</string> + </property> + <property name="calendarPopup"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="3" column="3"> + <spacer name="horizontalSpacer_8"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="3"> + <spacer name="horizontalSpacer_5"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item row="3" column="0" colspan="3"> + <widget class="QGroupBox" name="groupBox_2"> + <property name="minimumSize"> + <size> + <width>450</width> + <height>0</height> + </size> + </property> + <property name="title"> + <string>Parameters</string> + </property> + <layout class="QGridLayout" name="gridLayout_5"> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Resolution</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <spacer name="horizontalSpacer_9"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="0" column="1"> + <widget class="QDoubleSpinBox" name="doubleSpinBoxResolution"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="decimals"> + <number>3</number> + </property> + <property name="minimum"> + <double>0.000000000000000</double> + </property> + <property name="maximum"> + <double>10000.000000000000000</double> + </property> + <property name="singleStep"> + <double>1.000000000000000</double> + </property> + <property name="value"> + <double>1.000000000000000</double> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_11"> + <property name="text"> + <string>m</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="7" column="0" colspan="3"> + <widget class="QGroupBox" name="groupBox_3"> + <property name="title"> + <string>Object</string> + </property> + <layout class="QGridLayout" name="gridLayout_6"> + <item row="0" column="0"> + <widget class="QLabel" name="label_12"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Name</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="lineEditName"> + <property name="minimumSize"> + <size> + <width>220</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>110</width> + <height>16777215</height> + </size> + </property> + </widget> + </item> + <item row="0" column="2"> + <spacer name="horizontalSpacer_6"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + <item row="4" column="0" colspan="3"> + <widget class="QGroupBox" name="groupBoxMesh"> + <property name="minimumSize"> + <size> + <width>450</width> + <height>50</height> + </size> + </property> + <property name="title"> + <string>Output</string> + </property> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="1" column="2"> + <widget class="QLabel" name="label_2"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Mesh Element Type</string> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QComboBox" name="comboBoxMeshElemType"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <item> + <property name="text"> + <string>Quad</string> + </property> + </item> + <item> + <property name="text"> + <string>Triangle</string> + </property> + </item> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="label_3"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>100</width> + <height>16777215</height> + </size> + </property> + <property name="text"> + <string>Use Intensity as</string> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QComboBox" name="comboBoxUseIntensity"> + <item> + <property name="text"> + <string>Material</string> + </property> + </item> + <item> + <property name="text"> + <string>Evelation</string> + </property> + </item> + </widget> + </item> + <item row="1" column="0"> + <widget class="QRadioButton" name="radioMesh"> + <property name="text"> + <string>Mesh</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QRadioButton" name="radioImage"> + <property name="text"> + <string>Raster</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>50</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="1"> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Expanding</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>50</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="4"> + <spacer name="horizontalSpacer_7"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="2" column="4"> + <spacer name="horizontalSpacer_10"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>NetCdfConfigure</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>NetCdfConfigure</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/NetCdfConfigureDialog.cpp b/Gui/DataView/NetCdfConfigureDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c68ee0912b31cb2ae5d1459f0b599f57a76ba47a --- /dev/null +++ b/Gui/DataView/NetCdfConfigureDialog.cpp @@ -0,0 +1,457 @@ +//file NetCDFConfigureDialog.cpp +//CH Initial implementation + +#include "NetCdfConfigureDialog.h" + +#include "VtkMeshConverter.h" +#include "GridAdapter.h" +#include "VtkGeoImageSource.h" +#include "VtkRaster.h" + +#include <QMessageBox> +#include <QSettings> + +#include <vtkImageImport.h> + +// Constructor +NetCdfConfigureDialog::NetCdfConfigureDialog(const std::string &fileName, QDialog* parent) + : QDialog(parent), _currentFile(new NcFile(fileName.c_str(), NcFile::ReadOnly)), + _currentInitialDateTime(QDateTime()), _currentMesh(NULL), _currentRaster(NULL), _currentPath(fileName) +{ + setupUi(this); + + setVariableSelect(); // set up variables of the file in the combobox + comboBoxVariable->setCurrentIndex(valueWithMaxDim()); //pre-select the variable with the biggest number of dimensions...valueWithMaxDim() + + _currentVar = _currentFile->get_var(comboBoxVariable->currentIndex()); + + setDimensionSelect(); + + lineEditName->setText(setName()); + + this->radioMesh->setChecked(true); + +} + +NetCdfConfigureDialog::~NetCdfConfigureDialog() +{ +} + +// Instructions if the OK-Button has been pressed. +void NetCdfConfigureDialog::accept() +{ + QMessageBox valueErrorBox; + if (_currentVar->num_dims() < 3){ + valueErrorBox.setText("Selected Variable has not enough dimensions."); + valueErrorBox.exec(); + }else if (doubleSpinBoxDim2Start->value() == doubleSpinBoxDim2Start->maximum()){ + valueErrorBox.setText("Lon has invalid extend."); + valueErrorBox.exec(); + }else if(doubleSpinBoxDim1Start->value() == doubleSpinBoxDim1Start->maximum()){ + valueErrorBox.setText("Lat has invalid extend."); + valueErrorBox.exec(); + }else{ + createDataObject(); + delete _currentFile; + this->done(QDialog::Accepted); + } +} + +// Instructions if the Cancel-Button has been pressed. +void NetCdfConfigureDialog::reject() +{ + delete _currentFile; + this->done(QDialog::Rejected); +} + +int NetCdfConfigureDialog::valueWithMaxDim() +{ + int idMaxDim = 0; + for (int i=0; i < _currentFile->num_dims(); i++) + { + if ((_currentFile->get_var(i)->num_dims()) > 0) idMaxDim = i + 1; + } + return idMaxDim; +} + +void NetCdfConfigureDialog::on_comboBoxVariable_currentIndexChanged(int id) +{ + _currentVar = _currentFile->get_var(id); + setDimensionSelect(); +} + +//set up x-axis/lat +void NetCdfConfigureDialog::on_comboBoxDim1_currentIndexChanged(int id) +{ + if (id == -1) id = 0; + double firstValue=0, lastValue=0; + size_t size = 0; + getDimEdges(id,size,firstValue,lastValue); + doubleSpinBoxDim1Start->setValue(firstValue); + doubleSpinBoxDim1End->setValue(lastValue); + doubleSpinBoxResolution->setValue(getResolution()); +} + +//set up y-axis/lon +void NetCdfConfigureDialog::on_comboBoxDim2_currentIndexChanged(int id) +{ + if (_currentVar->num_dims() > 1) + { + if (id == -1) id = 0; + double firstValue=0, lastValue=0; + size_t size = 0; + getDimEdges(id,size,firstValue,lastValue); + doubleSpinBoxDim2Start->setValue(firstValue); + doubleSpinBoxDim2End->setValue(lastValue); + } +} + +//set up time +void NetCdfConfigureDialog::on_comboBoxDim3_currentIndexChanged(int id) +{ + if (_currentVar->num_dims() > 2) + { + if (id == -1) id = 0; + double firstValue=0, lastValue=0; + size_t size = 0; + getDimEdges(id,size,firstValue,lastValue); + + QTime firstTime(0,0,0), lastTime(0,0,0); + int firstDaysToAdd = 0, lastDaysToAdd = 0; + + getDaysTime(firstValue,firstTime,firstDaysToAdd); + getDaysTime(lastValue,lastTime,lastDaysToAdd); + + QDate initialDate(1960,1,1); + QTime initialTime(0,0); + + QDateTime initialDateTime; + initialDateTime.setDate(initialDate); + initialDateTime.setTime(initialTime); + + QDateTime firstDateTime = initialDateTime.addDays(firstDaysToAdd); + firstDateTime.setTime(firstTime); + + QDateTime lastDateTime = initialDateTime.addDays(lastDaysToAdd); + lastDateTime.setTime(lastTime); + + dateTimeEditDim3->setDateTime(firstDateTime); + dateTimeEditDim3->setMinimumDateTime(firstDateTime); + dateTimeEditDim3->setMaximumDateTime(lastDateTime); + + _currentInitialDateTime = initialDateTime; + lineEditName->setText(setName()); + } +} + +//set up additional dimension +void NetCdfConfigureDialog::on_comboBoxDim4_currentIndexChanged(int id) +{ + if (_currentVar->num_dims() > 3) + { + if (id == -1) id = 0; + double firstValue=0, lastValue=0; + size_t size = 0; + getDimEdges(id,size,firstValue,lastValue); + // WARNING: Implicit conversion to int in spinBoxDim4->set*() + spinBoxDim4->setValue(firstValue); + spinBoxDim4->setMinimum(firstValue); + spinBoxDim4->setMaximum(lastValue); + } +} + +void NetCdfConfigureDialog::setVariableSelect() +{ + for (int i=0; i<(_currentFile->num_vars()); i++) + { + NcVar *focusedVar = _currentFile->get_var(i); + if (focusedVar->num_dims() > 0) comboBoxVariable->addItem(focusedVar->name()); + } +} + +void NetCdfConfigureDialog::setDimensionSelect() +{ + comboBoxDim1->clear(); + comboBoxDim2->clear(); + comboBoxDim3->clear(); + comboBoxDim4->clear(); + for (int i=0; i < _currentVar->num_dims(); i++) //write dimension-names into selection-boxes + { + comboBoxDim1->addItem(_currentVar->get_dim(i)->name()); + comboBoxDim2->addItem(_currentVar->get_dim(i)->name()); + comboBoxDim3->addItem(_currentVar->get_dim(i)->name()); + comboBoxDim4->addItem(_currentVar->get_dim(i)->name()); + } + if (_currentVar->num_dims() < 4) + { + comboBoxDim4->setEnabled(false);comboBoxDim4->clear(); + spinBoxDim4->setEnabled(false);spinBoxDim4->setValue(0); + }else{ //pre-set dimension selection, typical for 4-d-nc-files: + comboBoxDim4->setEnabled(true); + spinBoxDim4->setEnabled(true); + comboBoxDim1->setCurrentIndex(2);on_comboBoxDim1_currentIndexChanged(2); + comboBoxDim2->setCurrentIndex(3);on_comboBoxDim2_currentIndexChanged(3); + comboBoxDim3->setCurrentIndex(0);on_comboBoxDim3_currentIndexChanged(0); + comboBoxDim4->setCurrentIndex(1);on_comboBoxDim4_currentIndexChanged(1); + } + if (_currentVar->num_dims() == 3) //pre-set dimension selection, typical for 3-d-nc-files: + { + comboBoxDim1->setCurrentIndex(1);on_comboBoxDim1_currentIndexChanged(1); + comboBoxDim2->setCurrentIndex(2);on_comboBoxDim2_currentIndexChanged(2); + comboBoxDim3->setCurrentIndex(0);on_comboBoxDim3_currentIndexChanged(0); + } + if (_currentVar->num_dims() < 3) + { + comboBoxDim3->setEnabled(false);comboBoxDim3->clear(); + dateTimeEditDim3->setEnabled(false);dateTimeEditDim3->setDateTime(_currentInitialDateTime); + + }else{ + comboBoxDim3->setEnabled(true); + dateTimeEditDim3->setEnabled(true); + } + if (_currentVar->num_dims() < 2) + { + comboBoxDim2->setEnabled(false);comboBoxDim2->clear(); + doubleSpinBoxDim2Start->setValue(0); doubleSpinBoxDim2End->setValue(0); + }else{ + comboBoxDim2->setEnabled(true); + } + +} + +void NetCdfConfigureDialog::getDimEdges(int dimId, size_t &size, double &firstValue, double &lastValue) +{ + if ((_currentFile->get_var(_currentVar->get_dim(dimId)->name())) != NULL) + { + NcVar *tmpVarOfDim = _currentFile->get_var(_currentVar->get_dim(dimId)->name()); + if ((tmpVarOfDim->num_dims()) == 1) + { + int sizeOfDim = tmpVarOfDim->get_dim(0)->size(); + size = sizeOfDim; + double arrayOfDimStart[1] = {0}; +#ifdef VTK_NETCDF_FOUND + size_t edgeOfArray[1] = {1}; +#else + long edgeOfArray[1] = {1}; +#endif + long edgeOrigin[1] = {0}; + tmpVarOfDim->set_cur(edgeOrigin); + tmpVarOfDim->get(arrayOfDimStart,edgeOfArray); + firstValue = arrayOfDimStart[0]; + double arrayOfDimEnd[1] = {0}; + edgeOrigin[0] = sizeOfDim - 1; + tmpVarOfDim->set_cur(edgeOrigin); + tmpVarOfDim->get(arrayOfDimEnd,edgeOfArray); + lastValue = arrayOfDimEnd[0]; + } + }else{ + size = 0; + firstValue = 0; + lastValue = 0; + } +} + +void NetCdfConfigureDialog::getDaysTime(double minSince, QTime &time, int &days) +{ + long tmpMin = (long) minSince; + long minuits = tmpMin % 60; + long tmpHours = tmpMin / 60; + long hours = tmpHours % 24; + days = (int) (tmpHours / 24); + time.setHMS(hours,minuits,0); +} + +long NetCdfConfigureDialog::convertDateToMinutes(QDateTime initialDateTime, QDate selectedDate, QTime selectedTime) +{ + int tmpInitialToSelectedDate = (selectedDate.daysTo(initialDateTime.date())); + long selectedDays = - tmpInitialToSelectedDate * 24 * 60; + long selectedMinutes = (selectedTime.hour() * 60) + selectedTime.minute() + selectedDays; + return selectedMinutes; +} + +int NetCdfConfigureDialog::getTimeStep() +{ + NcVar* timeVar = _currentFile->get_var(comboBoxDim2->currentIndex()); + + const double datesToMinutes = convertDateToMinutes(_currentInitialDateTime,dateTimeEditDim3->date(),dateTimeEditDim3->time()); + + double timeArray[1] = {datesToMinutes}; + double currentTime = timeVar->get_index(timeArray); + if (currentTime < 0) currentTime=0; //if the value isn't found in the array, set it to 0 as default... + return currentTime; +} + +int NetCdfConfigureDialog::getDim4() +{ + NcVar* dim3Var = _currentFile->get_var(comboBoxDim4->currentIndex()); + double timeArray[1] = {static_cast<double>(spinBoxDim4->value())}; + double currentValueDim3 = dim3Var->get_index(timeArray); + if (currentValueDim3 < 0) currentValueDim3=0; //if the value isn't found in the array, set it to 0 as default... + return currentValueDim3; +} + +double NetCdfConfigureDialog::getResolution() +{ + if (comboBoxDim1->currentIndex() > -1) + { + NcVar *latVar = _currentFile->get_var(comboBoxDim1->currentIndex()); + double firstValue=0, lastValue=0; + size_t size=0; + getDimEdges(latVar->id(),size,firstValue,lastValue); + if (size < 2) + { + return 1; + } + else + { + double interval = fabs(lastValue-firstValue); + double resolution = (double)interval/(size-1); + return resolution; + } + } + else + { + return 0; + } +} + +void NetCdfConfigureDialog::createDataObject() +{ +#ifdef VTK_NETCDF_FOUND + size_t* length = new size_t[_currentVar->num_dims()]; +#else + long* length = new long[_currentVar->num_dims()]; +#endif + double originLon = 0, originLat = 0; + double lastLon = 0, lastLat = 0; + size_t sizeLon = 0, sizeLat = 0; + getDimEdges(comboBoxDim1->currentIndex(), sizeLat, originLat, lastLat); + getDimEdges(comboBoxDim2->currentIndex(), sizeLon, originLon, lastLon); + + for(int i=0; i < _currentVar->num_dims(); i++) length[i]=1; + + // set array edges: lat x lon + length[comboBoxDim1->currentIndex()]=sizeLat; + length[comboBoxDim2->currentIndex()]=sizeLon; + + // set up array + double* data_array = new double[sizeLat*sizeLon]; + for(size_t i=0; i < (sizeLat*sizeLon); i++) data_array[i]=0; + + //Time-Dimension: + if (_currentVar->num_dims() > 2) + { + long* newOrigin = new long[_currentVar->num_dims()]; + for (int i=0; i < _currentVar->num_dims(); i++) newOrigin[i]=0; + newOrigin[comboBoxDim3->currentIndex()] = getTimeStep(); //set origin to selected time + _currentVar->set_cur(newOrigin); + //Dimension 4: + if (_currentVar->num_dims() > 3) newOrigin[comboBoxDim4->currentIndex()] = getDim4(); //if there are is a 4th dimension + delete newOrigin; + } + + _currentVar->get(data_array,length); //create Array of Values + + for (size_t i=0; i < (sizeLat*sizeLon); i++) + { + //data_array[i] = data_array[i] - 273; // convert from kalvin to celsius + if (data_array[i] < -9999 ) data_array[i] = -9999; // all values < -10000, set to "no-value" + } + + double origin_x = (originLon < lastLon) ? originLon : lastLon; + double origin_y = (originLat < lastLat) ? originLat : lastLat; + double originNetCdf[3] = {origin_x, origin_y, 0}; + + double resolution = (doubleSpinBoxResolution->value()); + + if (originLat > lastLat) // reverse lines in vertical direction if the original file has its origin in the northwest corner + this->reverseNorthSouth(data_array, sizeLon, sizeLat); + + if (this->radioMesh->isChecked()) + { + MshElemType::type meshElemType = MshElemType::QUAD; + UseIntensityAs::type useIntensity = UseIntensityAs::MATERIAL; + if ((comboBoxMeshElemType->currentIndex()) == 1) + { + meshElemType = MshElemType::TRIANGLE; + }else{ + meshElemType = MshElemType::QUAD; + } + if ((comboBoxUseIntensity->currentIndex()) == 1) + { + useIntensity = UseIntensityAs::ELEVATION; + }else{ + useIntensity = UseIntensityAs::MATERIAL; + } + + _currentMesh = VtkMeshConverter::convertImgToMesh(data_array,originNetCdf,sizeLon,sizeLat,resolution,meshElemType,useIntensity); + } + else + { + vtkImageImport* image = VtkRaster::loadImageFromArray(data_array, originNetCdf[0], originNetCdf[1], sizeLon, sizeLat, resolution, -9999.0); + _currentRaster = VtkGeoImageSource::New(); + _currentRaster->setImage(image, QString::fromStdString(this->getName()), originNetCdf[0], originNetCdf[1], resolution); + } + + delete[] length; + delete[] data_array; +} + +QString NetCdfConfigureDialog::setName() +{ + std::string name; + name.append(_currentPath); + name.erase(0,name.find_last_of("/")+1); + name.erase(name.find_last_of(".")); + QString qstr = QString::fromStdString(name); + return qstr; +} + +std::string NetCdfConfigureDialog::getName() +{ + std::string name = (lineEditName->text()).toStdString(); + QString date = dateTimeEditDim3->date().toString(Qt::LocalDate); + name.append(" - ").append(date.toStdString()); + return name; +} + +void NetCdfConfigureDialog::reverseNorthSouth(double* data, size_t width, size_t height) +{ + double* cp_array = new double[width*height]; + + for (size_t i=0; i<height; i++) + { + for (size_t j=0; j<width; j++) + { + size_t old_index((width*height)-(width*(i+1))); + size_t new_index(width*i); + cp_array[new_index+j] = data[old_index+j]; + } + } + + size_t length(height*width); + for (size_t i=0; i<length; i++) + data[i] = cp_array[i]; + + delete[] cp_array; +} + +void NetCdfConfigureDialog::on_radioMesh_toggled(bool isTrue) +{ + if (isTrue) // output set to "mesh" + { + this->label_2->setEnabled(true); + this->label_3->setEnabled(true); + this->comboBoxMeshElemType->setEnabled(true); + this->comboBoxUseIntensity->setEnabled(true); + } + else // output set to "raster" + { + this->label_2->setEnabled(false); + this->label_3->setEnabled(false); + this->comboBoxMeshElemType->setEnabled(false); + this->comboBoxUseIntensity->setEnabled(false); + } +} + + diff --git a/Gui/DataView/NetCdfConfigureDialog.h b/Gui/DataView/NetCdfConfigureDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..c97f2433f09e71eec7f6bc56640a7b5af5e575cd --- /dev/null +++ b/Gui/DataView/NetCdfConfigureDialog.h @@ -0,0 +1,62 @@ +//file NetCDFConfigureDialog.cpp +//CH Initial implementation + +#ifndef NETCDFCONFIGUREDIALOG_H +#define NETCDFCONFIGUREDIALOG_H + +#ifdef VTK_NETCDF_FOUND +#include <vtknetcdf/netcdfcpp.h> +#else +#include <netcdfcpp.h> +#endif +#include <QDialog> +#include "ui_NetCdfConfigure.h" + +class GridAdapter; +class VtkGeoImageSource; + +class NetCdfConfigureDialog : public QDialog, private Ui_NetCdfConfigure +{ + Q_OBJECT + +public: + NetCdfConfigureDialog(const std::string &fileName, QDialog* parent = 0); + ~NetCdfConfigureDialog(void); + GridAdapter* getMesh() { return _currentMesh; }; + std::string getName(); + VtkGeoImageSource* getRaster() { return _currentRaster; }; + +private slots: + void accept(); + void reject(); + void on_comboBoxVariable_currentIndexChanged(int id); + void on_comboBoxDim1_currentIndexChanged(int id); + void on_comboBoxDim2_currentIndexChanged(int id); + void on_comboBoxDim3_currentIndexChanged(int id); + void on_comboBoxDim4_currentIndexChanged(int id); + void on_radioMesh_toggled(bool isTrue); + +private: + void setVariableSelect(); + void setDimensionSelect(); + void getDimEdges(int dimId,size_t &size, double &firstValue, double &lastValue); + void getDaysTime(double minSince, QTime &time, int &days); + long convertDateToMinutes(QDateTime initialDateTime,QDate selectedDate, QTime selectedTime); + void createDataObject(); + int valueWithMaxDim(); + int getTimeStep(); + int getDim4(); + double getResolution(); + QString setName(); + void reverseNorthSouth(double* data, size_t width, size_t height); + + NcFile *_currentFile; + NcVar *_currentVar; + QDateTime _currentInitialDateTime; + GridAdapter* _currentMesh; + VtkGeoImageSource* _currentRaster; + std::string _currentPath; +}; + +#endif //NETCDFCONFIGUREDIALOG_H + diff --git a/Gui/DataView/NewProcess.ui b/Gui/DataView/NewProcess.ui new file mode 100644 index 0000000000000000000000000000000000000000..25b20ce6ef69b1d0d28941e4bcebb766c5f17d9d --- /dev/null +++ b/Gui/DataView/NewProcess.ui @@ -0,0 +1,87 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>NewProcess</class> + <widget class="QDialog" name="NewProcess"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>350</width> + <height>160</height> + </rect> + </property> + <property name="windowTitle"> + <string>Create new process...</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="horizontalSpacing"> + <number>18</number> + </property> + <item row="2" column="3"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="1" column="2"> + <widget class="QLabel" name="pvLabel"> + <property name="text"> + <string>Select Primary Variable</string> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QComboBox" name="pvTypeBox"/> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="processLabel"> + <property name="text"> + <string>Select Process Type</string> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QComboBox" name="processTypeBox"/> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>NewProcess</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>NewProcess</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/DataView/NewProcessDialog.cpp b/Gui/DataView/NewProcessDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91c2a80c25e73c51d33c36dada175750da35ea77 --- /dev/null +++ b/Gui/DataView/NewProcessDialog.cpp @@ -0,0 +1,42 @@ +/** + * \file NewProcessDialog.cpp + * 2011/11/17 KR Initial implementation + */ + +#include "NewProcessDialog.h" +#include "FEMEnums.h" +#include "ProcessInfo.h" + + +NewProcessDialog::NewProcessDialog(QDialog* parent) +: QDialog(parent) +{ + setupUi(this); + setupDialog(); +} + +void NewProcessDialog::setupDialog() +{ + const std::list<std::string> process_names = FiniteElement::getAllProcessNames(); + for (std::list<std::string>::const_iterator it = process_names.begin(); it != process_names.end(); ++it) + this->processTypeBox->addItem(QString::fromStdString(*it)); + + const std::list<std::string> pv_names = FiniteElement::getAllPrimaryVariableNames(); + for (std::list<std::string>::const_iterator it = pv_names.begin(); it != pv_names.end(); ++it) + this->pvTypeBox->addItem(QString::fromStdString(*it)); +} + +void NewProcessDialog::accept() +{ + ProcessInfo* info = new ProcessInfo(); + info->setProcessType(static_cast<FiniteElement::ProcessType>(this->processTypeBox->currentIndex() + 1)); + info->setProcessPrimaryVariable(static_cast<FiniteElement::PrimaryVariable>(this->pvTypeBox->currentIndex() + 1)); + + emit addProcess(info); + this->done(QDialog::Accepted); +} + +void NewProcessDialog::reject() +{ + this->done(QDialog::Rejected); +} diff --git a/Gui/DataView/NewProcessDialog.h b/Gui/DataView/NewProcessDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..f189f1b2853ec8555c60cff0b846d75e89f69e4c --- /dev/null +++ b/Gui/DataView/NewProcessDialog.h @@ -0,0 +1,43 @@ +/** + * \file NewProcessDialog.h + * 2011/11/17 KR Initial implementation + */ + +#ifndef NEWPROCESSDIALOG_H +#define NEWPROCESSDIALOG_H + +#include <QDialog> + +#include "ui_NewProcess.h" + +class ProcessInfo; + +/** + * \brief A dialog window for adding a new process in GUI + */ +class NewProcessDialog : public QDialog, private Ui_NewProcess +{ + Q_OBJECT + +public: + /// Constructor for creating a new FEM condition. + NewProcessDialog(QDialog* parent = 0); + + ~NewProcessDialog(void) {}; + +private: + void setupDialog(); + +private slots: + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void addProcess(ProcessInfo*); + +}; + +#endif //NEWPROCESSDIALOG_H diff --git a/Gui/DataView/ProcessItem.h b/Gui/DataView/ProcessItem.h new file mode 100644 index 0000000000000000000000000000000000000000..cc71efb691789f356715853a10f90b5d9c63e8d5 --- /dev/null +++ b/Gui/DataView/ProcessItem.h @@ -0,0 +1,34 @@ +/** + * \file ProcessItem.h + * 2011/11/22 KR Initial implementation + */ + +#ifndef PROCESSITEM_H +#define PROCESSITEM_H + +#include "TreeItem.h" +#include "ProcessInfo.h" + +/** + * \brief A TreeItem representing process information. + * \sa TreeItem + */ +class ProcessItem : public TreeItem +{ +public: + /// Constructor + ProcessItem(const QList<QVariant> &data, TreeItem* parent, const ProcessInfo* pcs) + : TreeItem(data, parent), _item(pcs) + { + } + + ~ProcessItem() {} + + /// Returns the Process Information associated with the item. + const ProcessInfo* getItem() { return _item; } + +private: + const ProcessInfo* _item; +}; + +#endif //PROCESSITEM_H diff --git a/Gui/DataView/ProcessModel.cpp b/Gui/DataView/ProcessModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..806c6f7b179f19340c8d2fd69e362aac960468f8 --- /dev/null +++ b/Gui/DataView/ProcessModel.cpp @@ -0,0 +1,269 @@ +/** + * \file ProcessModel.cpp + * 18/10/2010 KR Initial implementation + */ + +// ** INCLUDES ** +#include "ProcessItem.h" +#include "CondObjectListItem.h" +#include "CondItem.h" +#include "ProcessItem.h" +#include "ProcessModel.h" +#include "FEMCondition.h" +#include "GEOObjects.h" +#include "GeoObject.h" +#include "GeoType.h" + +#include <QFileInfo> +#include <vtkPolyDataAlgorithm.h> + +ProcessModel::ProcessModel( ProjectData &project, QObject* parent /*= 0*/ ) + : TreeModel(parent), _project(project) +{ + QList<QVariant> rootData; + delete _rootItem; + rootData << "Name" << "Value" << "" << "" << ""; + _rootItem = new TreeItem(rootData, NULL); +} + +ProcessModel::~ProcessModel() +{ +} + +int ProcessModel::columnCount( const QModelIndex &parent /*= QModelIndex()*/ ) const +{ + Q_UNUSED(parent) + + return 2; +} + +void ProcessModel::addConditionItem(FEMCondition* c) +{ + ProcessItem* processParent = this->getProcessParent(c->getProcessType()); + if (processParent == NULL) + { + ProcessInfo* pcs = new ProcessInfo(c->getProcessType(), c->getProcessPrimaryVariable(), NULL); + processParent = this->addProcess(pcs); + } + + CondObjectListItem* condParent = this->getCondParent(processParent, c->getCondType()); + if (condParent == NULL) + condParent = this->createCondParent(processParent, c); + else + condParent->addCondition(c); + + QList<QVariant> condData; + condData << QString::fromStdString(c->getGeoName()) + << QString::fromStdString(c->getGeoTypeAsString()); + CondItem* condItem = new CondItem(condData, condParent, c); + condParent->appendChild(condItem); + // add information on primary variable + QList<QVariant> pvData; + pvData << QString::fromStdString(convertPrimaryVariableToString(c->getProcessPrimaryVariable())); + TreeItem* pvInfo = new TreeItem(pvData, condItem); + // add distribution information + QList<QVariant> disData; + disData << QString::fromStdString(convertDisTypeToString(c->getProcessDistributionType())); + std::vector<size_t> dis_nodes = c->getDisNodes(); + std::vector<double> dis_values = c->getDisValues(); + TreeItem* disInfo; + if (c->getProcessDistributionType() == FiniteElement::CONSTANT || + c->getProcessDistributionType() == FiniteElement::CONSTANT_NEUMANN) + { + disData << dis_values[0]; + disInfo = new TreeItem(disData, condItem); + } + else + { + size_t nVals = dis_values.size(); + disData << static_cast<int>(nVals); + disInfo = new TreeItem(disData, condItem); + for (size_t i = 0; i < nVals; i++) + { + QList<QVariant> linData; + linData << static_cast<int>(dis_nodes[i]) << dis_values[i]; + TreeItem* linInfo = new TreeItem(linData, disInfo); + disInfo->appendChild(linInfo); + } + } + + //condItem->appendChild(pcsInfo); + condItem->appendChild(pvInfo); + condItem->appendChild(disInfo); + + reset(); +} + +void ProcessModel::addCondition(FEMCondition* condition) +{ + bool is_domain = (condition->getGeoType() == GEOLIB::GEODOMAIN) ? true : false; + // HACK: direct source terms are not domain conditions but they also don't contain geo-object-names + if (condition->getProcessDistributionType() == FiniteElement::DIRECT) is_domain = true; + + const GEOLIB::GeoObject* object = condition->getGeoObj(); + if (object == NULL) + { + object = _project.getGEOObjects()->getGEOObject( + condition->getAssociatedGeometryName(), + condition->getGeoType(), + condition->getGeoName()); + condition->setGeoObj(object); + } + if (object || is_domain) + { + _project.addCondition(condition); + this->addConditionItem(condition); + } + else + std::cout << "Error in ProcessModel::addConditions() - Specified geometrical object \"" + << condition->getGeoName() << "\" not found in associated geometry..." + << std::endl; +} + +void ProcessModel::addConditions(std::vector<FEMCondition*> &conditions) +{ + for (size_t i = 0; i < conditions.size(); i++) + this->addCondition(conditions[i]); +} + +ProcessItem* ProcessModel::addProcess(ProcessInfo *pcs) +{ + if (this->getProcessParent(pcs->getProcessType()) == NULL) + { + this->_project.addProcess(pcs); + QList<QVariant> processData; + processData << QVariant(QString::fromStdString(FiniteElement::convertProcessTypeToString(pcs->getProcessType()))) << ""; + ProcessItem* process = new ProcessItem(processData, _rootItem, pcs); + _rootItem->appendChild(process); + reset(); + return process; + } + else + { + std::cout << "Warning in ProcessModel::addProcess() - " + << FiniteElement::convertProcessTypeToString(pcs->getProcessType()) + << " already exists." << std::endl; + return NULL; + } +} + +void ProcessModel::removeFEMConditions(const FiniteElement::ProcessType pcs_type, const std::string &geometry_name, const FEMCondition::CondType cond_type) +{ + _project.removeConditions(pcs_type, geometry_name, cond_type); + + while (_rootItem->childCount()>0) + { + ProcessItem* pcs = static_cast<ProcessItem*>(_rootItem->child(0)); + for (int j=0; j<pcs->childCount(); j++) + emit conditionsRemoved(this, pcs->getItem()->getProcessType(), (static_cast<CondObjectListItem*>(pcs->child(j)))->getType()); + + _rootItem->removeChildren(0, 1); + } + + const std::vector<FEMCondition*> conds = _project.getConditions(FiniteElement::INVALID_PROCESS, "", FEMCondition::UNSPECIFIED); + if (!conds.empty()) + { + size_t nConds (conds.size()); + for (size_t i=0; i<nConds; i++) + this->addConditionItem(conds[i]); + } + reset(); +} + +void ProcessModel::removeProcess(const FiniteElement::ProcessType type) +{ + this->removeFEMConditions(type, "", FEMCondition::UNSPECIFIED); + + const ProcessItem* processParent = this->getProcessParent(type); + if (processParent) + { + this->_project.removeProcess(type); + removeRows(processParent->row(), 1, QModelIndex()); + } + reset(); +} + +void ProcessModel::removeAllProcesses() +{ + int nProcesses = _rootItem->childCount(); + for (int i=0; i<nProcesses; i++) + { + ProcessItem* item = static_cast<ProcessItem*>(_rootItem->child(i)); + removeProcess(item->getItem()->getProcessType()); + } +} + +int ProcessModel::getGEOIndex(const std::string &geo_name, + GEOLIB::GEOTYPE type, + const std::string &obj_name) const +{ + bool exists(false); + size_t idx(0); + if (type == GEOLIB::POINT) + exists = this->_project.getGEOObjects()->getPointVecObj(geo_name)->getElementIDByName(obj_name, idx); + else if (type == GEOLIB::POLYLINE) + exists = this->_project.getGEOObjects()->getPolylineVecObj(geo_name)->getElementIDByName(obj_name,idx); + else if (type == GEOLIB::SURFACE) + exists = this->_project.getGEOObjects()->getSurfaceVecObj(geo_name)->getElementIDByName(obj_name,idx); + + if (exists) + return static_cast<int>(idx); + return -1; +} + +ProcessItem* ProcessModel::getProcessParent(const FiniteElement::ProcessType type) const +{ + int nLists = _rootItem->childCount(); + for (int i = 0; i < nLists; i++) + if (static_cast<ProcessItem*>(_rootItem->child(i))->getItem()->getProcessType() == type) + return static_cast<ProcessItem*>(_rootItem->child(i)); + + return NULL; +} + +CondObjectListItem* ProcessModel::getCondParent(TreeItem* parent, const FEMCondition::CondType type) +{ + int nLists = parent->childCount(); + for (int i = 0; i < nLists; i++) + if (dynamic_cast<CondObjectListItem*>(parent->child(i))->getType() == type) + return dynamic_cast<CondObjectListItem*>(parent->child(i)); + return NULL; +} + +CondObjectListItem* ProcessModel::createCondParent(ProcessItem* parent, FEMCondition* cond) +{ + QString condType(QString::fromStdString(FEMCondition::condTypeToString(cond->getCondType()))); + QList<QVariant> condData; + condData << condType << ""; + + const std::vector<GEOLIB::Point*>* pnts = _project.getGEOObjects()->getPointVec(cond->getAssociatedGeometryName()); + if (pnts) + { + CondObjectListItem* cond_list = new CondObjectListItem(condData, parent, cond, pnts); + parent->appendChild(cond_list); + emit conditionAdded(this, parent->getItem()->getProcessType(), cond->getCondType()); + return cond_list; + } + + return NULL; +} + +vtkPolyDataAlgorithm* ProcessModel::vtkSource(const FiniteElement::ProcessType pcs_type, const FEMCondition::CondType cond_type) +{ + ProcessItem* processParent = this->getProcessParent(pcs_type); + if (processParent) + { + CondObjectListItem* condParent = this->getCondParent(processParent, cond_type); + if (condParent) + return condParent->vtkSource(); + } + return NULL; +} + +void ProcessModel::replaceCondition(const QModelIndex &idx, FEMCondition* condition) +{ + // remove old condition + this->getItem(idx)->parentItem()->removeChildren(this->getItem(idx)->row(),1); + //add new condition + this->addCondition(condition); +} diff --git a/Gui/DataView/ProcessModel.h b/Gui/DataView/ProcessModel.h new file mode 100644 index 0000000000000000000000000000000000000000..ff445aaa2867f6be60f878cd5e64310fd527c553 --- /dev/null +++ b/Gui/DataView/ProcessModel.h @@ -0,0 +1,90 @@ +/** + * \file ProcessModel.h + * 18/10/2010 KR Initial implementation + */ + +#ifndef PROCESSMODEL_H +#define PROCESSMODEL_H + +// ** INCLUDES ** +#include "ProjectData.h" +#include "TreeModel.h" + +class FEMCondition; +class ProcessItem; +class CondObjectListItem; +class vtkPolyDataAlgorithm; + +namespace GEOLIB +{ +class GeoObject; +} + +/** + * \brief A model implementing a tree structure for process-relevant information such as + * process types, FEM-Conditions (BCs, ICs, STs), etc. as a double-linked list. + * \sa TreeModel, ProcessView, TreeItem, CondObjectListItem + */ +class ProcessModel : public TreeModel +{ + Q_OBJECT + +public: + ProcessModel(ProjectData &project, QObject* parent = 0); + ~ProcessModel(); + + int columnCount(const QModelIndex& parent = QModelIndex()) const; + /// Returns the vtk source object for the specified subtree of a process with the given name. + vtkPolyDataAlgorithm* vtkSource(const FiniteElement::ProcessType pcs_type, const FEMCondition::CondType cond_type); + +public slots: + /// Adds a vector of FEM Conditions to the model. Objects in the vector can consist of BCs, ICs or STs in any combination and sequence. + void addConditions(std::vector<FEMCondition*> &conditions); + + /// Adds a single FEM Conditions to the model + void addCondition(FEMCondition* condition); + + /// Adds a process to the model + ProcessItem* addProcess(ProcessInfo* pcs); + + /// Removes FEMConditions from the the model. Conditions can be specified by process type, geometry name or condition type or a combination of the three. + void removeFEMConditions(const FiniteElement::ProcessType pcs_type, const std::string &geometry_name, const FEMCondition::CondType cond_type); + + /// Removes a process from the model + void removeProcess(const FiniteElement::ProcessType type); + + /// Removes all processes from the model + void removeAllProcesses(); + + /// Remove the given TreeItem and replace it with another condition (this is used for editing FEMConditions) + void replaceCondition(const QModelIndex &idx, FEMCondition* condition); + +private: + /// Adds a new FEM condition to the condition tree model. + void addConditionItem(FEMCondition* condition); + + /// Removes the FEM condition with the given index. + //bool removeConditionItem(const QModelIndex &idx); + + /// Creates the TreeItem for one of the condition subtrees. + CondObjectListItem* createCondParent(ProcessItem* parent, FEMCondition* cond); + + /// Returns the subtree-item for a given type of condtion. + CondObjectListItem* getCondParent(TreeItem* parent, const FEMCondition::CondType type) ; + + /// Returns the subtree item for a process with the given name. If create_item is true, this item will be created if it doesn't exist yet. + ProcessItem* getProcessParent(const FiniteElement::ProcessType type) const; + + /// Returns the index of a geometric item of the given name and type for the associated geometry. + int getGEOIndex(const std::string &geo_name, + GEOLIB::GEOTYPE type, + const std::string &obj_name) const; + + ProjectData& _project; + +signals: + void conditionAdded(ProcessModel*, const FiniteElement::ProcessType, const FEMCondition::CondType); + void conditionsRemoved(ProcessModel*, const FiniteElement::ProcessType, const FEMCondition::CondType); +}; + +#endif // PROCESSMODEL_H diff --git a/Gui/DataView/ProcessView.cpp b/Gui/DataView/ProcessView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4e40d69fcd44396f158a868e1a37cc6b39b29d8 --- /dev/null +++ b/Gui/DataView/ProcessView.cpp @@ -0,0 +1,134 @@ +/** + * \file ProcessView.cpp + * 2010/12/13 KR Initial implementation + */ + +#include <QMenu> +#include <QFileDialog> + +#include "ProcessItem.h" +#include "CondObjectListItem.h" +#include "CondItem.h" +#include "ProcessModel.h" +#include "ProcessView.h" +#include "FEMConditionSetupDialog.h" +#include "SelectMeshDialog.h" + +ProcessView::ProcessView(QWidget* parent) : QTreeView(parent) +{ +} + +void ProcessView::updateView() +{ + setAlternatingRowColors(true); + resizeColumnToContents(0); + setColumnWidth(1,50); + setColumnWidth(2,50); +} + +void ProcessView::on_Clicked(QModelIndex idx) +{ + qDebug("%d, %d",idx.parent().row(), idx.row()); +} + +void ProcessView::selectionChanged( const QItemSelection &selected, + const QItemSelection &deselected ) +{ + emit itemSelectionChanged(selected, deselected); + return QTreeView::selectionChanged(selected, deselected); +} + +void ProcessView::contextMenuEvent( QContextMenuEvent* event ) +{ + Q_UNUSED(event); + + const QModelIndex idx(this->selectionModel()->currentIndex()); + QMenu menu; + + if (this->isProcessItem(idx)) + { + QAction* saveCondAction = menu.addAction("Save FEM Conditions..."); + QAction* removePCSAction = menu.addAction("Remove process"); + connect(saveCondAction, SIGNAL(triggered()), this, SLOT(saveConditions())); + connect(removePCSAction, SIGNAL(triggered()), this, SLOT(removeProcess())); + } + else if (this->isListItem(idx)) + { + QAction* removeCondAction = menu.addAction("Remove conditions"); + connect(removeCondAction, SIGNAL(triggered()), this, SLOT(removeCondition())); + } + else if (this->isConditionItem(idx)) + { + QAction* editCondAction = menu.addAction("Edit condition"); + connect(editCondAction, SIGNAL(triggered()), this, SLOT(editCondition())); + } + + menu.exec(event->globalPos()); +} + +void ProcessView::removeCondition() +{ + CondObjectListItem* item = dynamic_cast<CondObjectListItem*>(static_cast<ProcessModel*>(this->model())->getItem(this->selectionModel()->currentIndex())); + + if (item) + { + const FiniteElement::ProcessType pcs_type = static_cast<ProcessItem*>(item->parentItem())->getItem()->getProcessType(); + const FEMCondition::CondType cond_type = item->getType(); + emit conditionsRemoved(pcs_type, "", cond_type); + } +} + +void ProcessView::editCondition() +{ + CondItem* item = dynamic_cast<CondItem*>(static_cast<ProcessModel*>(this->model())->getItem(this->selectionModel()->currentIndex())); + + if (item) + { + FEMConditionSetupDialog dlg(*(item->getItem())); + connect(&dlg, SIGNAL(createFEMCondition(std::vector<FEMCondition*>)), this, SLOT(replaceCondition(std::vector<FEMCondition*>))); + dlg.exec(); + } +} + +void ProcessView::replaceCondition(std::vector<FEMCondition*> conditions) +{ + static_cast<ProcessModel*>(this->model())->replaceCondition(this->selectionModel()->currentIndex(), conditions[0]); + this->reset(); +} + +void ProcessView::saveConditions() +{ + emit saveConditionsRequested(); +} + +void ProcessView::removeProcess() +{ + ProcessItem* item = dynamic_cast<ProcessItem*>(static_cast<ProcessModel*>(this->model())->getItem(this->selectionModel()->currentIndex())); + + if (item) + { + const FiniteElement::ProcessType pcs_type = item->getItem()->getProcessType(); + emit processRemoved(pcs_type); + } +} + +bool ProcessView::isProcessItem(const QModelIndex &idx) const +{ + ProcessItem* pcs_item = dynamic_cast<ProcessItem*>(static_cast<ProcessModel*>(this->model())->getItem(idx)); + if (pcs_item) return true; + return false; +} + +bool ProcessView::isListItem(const QModelIndex &idx) const +{ + CondObjectListItem* cond_item = dynamic_cast<CondObjectListItem*>(static_cast<ProcessModel*>(this->model())->getItem(idx)); + if (cond_item) return true; + return false; +} + +bool ProcessView::isConditionItem(const QModelIndex &idx) const +{ + CondObjectListItem* cond_item = dynamic_cast<CondObjectListItem*>(static_cast<ProcessModel*>(this->model())->getItem(idx.parent())); + if (cond_item) return true; + return false; +} \ No newline at end of file diff --git a/Gui/DataView/ProcessView.h b/Gui/DataView/ProcessView.h new file mode 100644 index 0000000000000000000000000000000000000000..ba378765217a246912f7c10a460e944bb29b7524 --- /dev/null +++ b/Gui/DataView/ProcessView.h @@ -0,0 +1,59 @@ +/** + * \file ProcessView.h + * 2010/12/13 KR Initial implementation + */ + +#ifndef PROCESSVIEW_H +#define PROCESSVIEW_H + +#include <QContextMenuEvent> +#include <QTreeView> + +#include "FEMCondition.h" + +class ConditionModel; + +/** + * \brief A view for FEM-Conditions (Initial- & Boundary Conditions / Source Terms) with a number of additional + * information such as Process Type, Distribution, etc. + * \sa ConditionModel, CondItem + */ +class ProcessView : public QTreeView +{ + Q_OBJECT + +public: + /// Constructor + ProcessView(QWidget* parent = 0); + + /// Update the view to visualise changes made to the underlying data + void updateView(); + +protected slots: + /// Instructions if the selection of items in the view has changed. + void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + +private: + /// Actions to be taken after a right mouse click is performed in the station view. + void contextMenuEvent( QContextMenuEvent* e ); + bool isProcessItem(const QModelIndex &idx) const; + bool isListItem(const QModelIndex &idx) const; + bool isConditionItem(const QModelIndex &idx) const; + +private slots: + void on_Clicked(QModelIndex idx); + void editCondition(); + void removeCondition(); + void removeProcess(); + void replaceCondition(std::vector<FEMCondition*> conditions); + void saveConditions(); + +signals: + void conditionsRemoved(const FiniteElement::ProcessType, const std::string&, const FEMCondition::CondType); + void itemSelectionChanged(const QItemSelection & selected, const QItemSelection & deselected); + void processRemoved(const FiniteElement::ProcessType); + void saveConditionsRequested(); +}; + +#endif //PROCESSVIEW_H + diff --git a/Gui/DataView/QueryResultsDialog.cpp b/Gui/DataView/QueryResultsDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..585579a03547b0f2917d59feaff99453c2b5fd3e --- /dev/null +++ b/Gui/DataView/QueryResultsDialog.cpp @@ -0,0 +1,60 @@ +/** + * \file QueryResultsDialog.cpp + * KR Initial implementation + */ + +#include "OGSError.h" +#include "QueryResultsDialog.h" + +/** + * Constructor. + */ +QueryResultsDialog::QueryResultsDialog(QDialog* parent) : QDialog(parent) +{ + setupUi(this); +} + +QueryResultsDialog::~QueryResultsDialog() +{ +} + +void QueryResultsDialog::setView(QSqlQueryModel* model) +{ + queryView->setModel(model); + setViewProperties(); +} + +void QueryResultsDialog::setViewProperties() +{ + queryView->setColumnHidden(0, true); //hide ID column + queryView->setSelectionMode(QAbstractItemView::SingleSelection); + queryView->setSelectionBehavior(QAbstractItemView::SelectRows); + queryView->setEditTriggers(QAbstractItemView::NoEditTriggers); + queryView->resizeColumnsToContents(); + + QHeaderView* header = queryView->horizontalHeader(); + header->setStretchLastSection(true); +} + +void QueryResultsDialog::on_openButton_clicked() +{ + QItemSelectionModel* selection = queryView->selectionModel(); + + if (selection->hasSelection()) + { + queryView->selectColumn(0); + QModelIndexList indexes = selection->selectedIndexes(); + int listID = (queryView->model()->data(indexes.first())).toInt(); + + emit listSelected(listID); + + this->done(QDialog::Accepted); + } + else + OGSError::box("No data selected."); +} + +void QueryResultsDialog::on_cancelButton_clicked() +{ + this->done(QDialog::Rejected); +} diff --git a/Gui/DataView/QueryResultsDialog.h b/Gui/DataView/QueryResultsDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..2e374b32784d479e8d506f55a33e93c81264e0ff --- /dev/null +++ b/Gui/DataView/QueryResultsDialog.h @@ -0,0 +1,42 @@ +/** + * \file QueryResultsDialog.h + * KR Initial implementation + */ + +#ifndef QUERYRESULTSDIALOG_H +#define QUERYRESULTSDIALOG_H + +#include "ui_DatabaseResultView.h" +#include <QSqlQueryModel> +#include <QDialog> + +/** + * \brief A Dialog for displaying the results of a database query in a table. + */ +class QueryResultsDialog : public QDialog, private Ui_DatabaseResultsView +{ + Q_OBJECT + +public: + QueryResultsDialog(QDialog* parent = 0); + ~QueryResultsDialog(void); + + /// Sets up the view. + void setView(QSqlQueryModel* model); + +private: + /// Sets the properties of the view. + void setViewProperties(); + +private slots: + /// Instructions if the Cancel-button is clicked. + void on_cancelButton_clicked(); + + /// Instructions if the Open-button is clicked. + void on_openButton_clicked(); + +signals: + void listSelected(int listID); +}; + +#endif //QUERYRESULTSDIALOG_H diff --git a/Gui/DataView/SHPImportDialog.cpp b/Gui/DataView/SHPImportDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2a5ea954c0c293a2d0ab428fc94b91b41cddb243 --- /dev/null +++ b/Gui/DataView/SHPImportDialog.cpp @@ -0,0 +1,147 @@ +/** + * \file SHPImportDialog.cpp + * 25/01/2010 KR Initial implementation + */ + +#include "GEOModels.h" +#include "OGSError.h" +#include "SHPImportDialog.h" +#include "SHPInterface.h" + +#include <QDialogButtonBox> +#include <QFileInfo> +#include <QLabel> +#include <QLineEdit> +#include <QRadioButton> +#include <QVBoxLayout> + +SHPImportDialog::SHPImportDialog(std::string filename, GEOModels* geoModels, QDialog* parent) + : QDialog(parent), _buttonBox(NULL), _layout(NULL), _shpContentLabel(NULL), _nameLabel(NULL), + _listName(new QLineEdit()), _choice1(NULL), _choice2(NULL), _filename(filename), + _fileType(0), + _shpInterface(new SHPInterface(geoModels)) +{ + setupDialog(); + show(); +} + +SHPImportDialog::~SHPImportDialog() +{ + delete _shpInterface; + delete _buttonBox; + delete _listName; + delete _choice1; + delete _choice2; + delete _shpContentLabel; + delete _nameLabel; + delete _layout; +} + +void SHPImportDialog::setupDialog() +{ + _layout = new QGridLayout(this); + int shpType = 0, numberOfEntities = 0; + QString type = ""; + + setWindowTitle("Import SHP File"); + + if (_shpInterface->readSHPInfo(_filename, shpType, numberOfEntities)) + { + if ((shpType - 1) % 10 == 0) + type = "points"; + if ((shpType - 3) % 10 == 0) + type = "polylines"; + if ((shpType - 5) % 10 == 0) + type = "polygons"; + if ((shpType - 8) % 10 == 0) + type = "multipoints"; + if (shpType == 31) + type = "TIN elements"; + + _shpContentLabel = + new QLabel("The selected file contains " + QString::number( + numberOfEntities) + " " + type, this); + _nameLabel = new QLabel("List Name: ", this); + + QFileInfo fi(QString::fromStdString(_filename)); + _listName->setText(fi.baseName()); + + if ((shpType - 1) % 10 == 0 && shpType != 31) // Points + { + _choice1 = new QRadioButton("Read as GLI-Points"); + _choice2 = new QRadioButton("Read as Station Points"); + _choice1->toggle(); // default choice + _layout->addWidget( _shpContentLabel ); + _layout->addWidget( _choice1 ); + _layout->addWidget( _choice2 ); + _layout->addWidget( _nameLabel ); + _layout->addWidget( _listName ); + _fileType = 1; + } + else if ((shpType - 3) % 10 == 0 || (shpType - 5) % 10 == 0) // Polylines + { + _choice1 = new QRadioButton("Read as Polylines"); + _choice2 = new QRadioButton("Read as Polygons"); + if ((shpType - 3) % 10 == 0) + _choice2->setDisabled(true); // disable polygon-choice if file contains only polylines + _choice1->toggle(); // default choice + _layout->addWidget( _shpContentLabel ); + _layout->addWidget( _choice1 ); + _layout->addWidget( _choice2 ); + _layout->addWidget( _nameLabel ); + _layout->addWidget( _listName ); + _fileType = 2; + } + else + { + _nameLabel->setText("This element type is currently not supported."); + _layout->addWidget( _shpContentLabel ); + _layout->addWidget( _nameLabel ); + } + + _buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + _layout->addWidget( _buttonBox ); + + setLayout(_layout); + } + else + OGSError::box("Error reading shapefile!"); +} + +void SHPImportDialog::accept() +{ + QString list_name(_listName->text()); + if (list_name.compare("") == 0) + { + OGSError::box("Please insert a name for the data in this file."); + return; + } + else + { + if (_fileType == 1 && _choice1->isChecked()) + _shpInterface->readSHPFile(_filename, + SHPInterface::POINT, + list_name.toStdString()); + if (_fileType == 1 && _choice2->isChecked()) + _shpInterface->readSHPFile(_filename, + SHPInterface::STATION, + list_name.toStdString()); + if (_fileType == 2 && _choice1->isChecked()) + _shpInterface->readSHPFile(_filename, + SHPInterface::POLYLINE, + list_name.toStdString()); + if (_fileType == 2 && _choice2->isChecked()) + _shpInterface->readSHPFile(_filename, + SHPInterface::POLYGON, + list_name.toStdString()); + emit shpLoaded(list_name); + } + this->done(QDialog::Accepted); +} + +void SHPImportDialog::reject() +{ + this->done(QDialog::Rejected); +} diff --git a/Gui/DataView/SHPImportDialog.h b/Gui/DataView/SHPImportDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..59e834978cc167263911853391a29a2a6f51b02c --- /dev/null +++ b/Gui/DataView/SHPImportDialog.h @@ -0,0 +1,60 @@ +/** + * \file SHPImportDialog.h + * 25/01/2010 KR Initial implementation + */ + +#ifndef SHPIMPORTDIALOG_H +#define SHPIMPORTDIALOG_H + +#include <QDialog> + +class SHPInterface; +class GEOModels; + +class QDialogButtonBox; +class QFileInfo; +class QGridLayout; +class QLabel; +class QLineEdit; +class QRadioButton; +class QVBoxLayout; + +/** + * \brief Dialog for selecting which information should be loaded from a shape file. + */ +class SHPImportDialog : public QDialog +{ + Q_OBJECT + +public: + /// Constructor + SHPImportDialog(std::string filename, GEOModels* geoModels, QDialog* parent = 0); + ~SHPImportDialog(); + + QDialogButtonBox* _buttonBox; /// The buttons used in this dialog. + +private: + /// Constructs a dialog window based on the information found in the selected shape file + void setupDialog(); + + QGridLayout* _layout; + QLabel* _shpContentLabel; + QLabel* _nameLabel; + QLineEdit* _listName; + QRadioButton* _choice1, * _choice2; + std::string _filename; + short _fileType; + SHPInterface* _shpInterface; + +private slots: + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void shpLoaded(QString); +}; + +#endif //SHPIMPORTDIALOG_H diff --git a/Gui/DataView/SelectMeshDialog.cpp b/Gui/DataView/SelectMeshDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7d80b9820d6f1d2b5a03e8068feeab54d3304607 --- /dev/null +++ b/Gui/DataView/SelectMeshDialog.cpp @@ -0,0 +1,61 @@ +/** + * \file QComboBox.cpp + * 2012/04/20 KR Initial implementation + */ + +#include "SelectMeshDialog.h" +#include "GeoObject.h" + +#include <QDialogButtonBox> +#include <QLabel> +#include <QComboBox> +#include <QVBoxLayout> + +SelectMeshDialog::SelectMeshDialog(const GEOLIB::GeoObject* geo_object, const std::list<std::string> &msh_names, QDialog* parent) : + QDialog(parent), _geo_object(geo_object) +{ + setupDialog(msh_names); + show(); +} + +SelectMeshDialog::~SelectMeshDialog() +{ + delete _buttonBox; + delete _layout; + delete _msh_names; + delete _txt_label; +} + +void SelectMeshDialog::setupDialog(const std::list<std::string> &msh_names) +{ + _layout = new QVBoxLayout(this); + QString dialog_text("Select Mesh"); + _txt_label = new QLabel(this); + _txt_label->setText(dialog_text); + + + _msh_names = new QComboBox(); + for (std::list<std::string>::const_iterator it=msh_names.begin(); it != msh_names.end(); ++it) + _msh_names->addItem(QString::fromStdString(*it)); + + setWindowTitle("Select Mesh..."); + _layout->addWidget( _txt_label ); + _layout->addWidget( _msh_names ); + _buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + _layout->addWidget( _buttonBox ); + + setLayout(_layout); +} + +void SelectMeshDialog::accept() +{ + //emit requestNameChange(_parent_name, GEOLIB::convertGeoType(_object_type_name), _id, _new_name->text().toStdString()); + this->done(QDialog::Accepted); +} + +void SelectMeshDialog::reject() +{ + this->done(QDialog::Rejected); +} diff --git a/Gui/DataView/SelectMeshDialog.h b/Gui/DataView/SelectMeshDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..a64cf195e6d072529a1a3774cd8a21aa42e1dd10 --- /dev/null +++ b/Gui/DataView/SelectMeshDialog.h @@ -0,0 +1,57 @@ +/** + * \file SelectMeshDialog.h + * 2012/04/20 KR Initial implementation + */ + +#ifndef SELECTMESHDIALOG_H +#define SELECTMESHDIALOG_H + +#include <QDialog> + +namespace GEOLIB { + class GeoObject; +} + +class QDialogButtonBox; +class QLabel; +class QComboBox; +class QVBoxLayout; + +/** + * \brief Small dialog for setting a name for an object. + */ +class SelectMeshDialog : public QDialog +{ + Q_OBJECT + +public: + /// Constructor + SelectMeshDialog(const GEOLIB::GeoObject* geo_object, + const std::list<std::string> &msh_names, + QDialog* parent = 0); + ~SelectMeshDialog(); + + QDialogButtonBox* _buttonBox; /// The buttons used in this dialog. + +private: + /// Constructs a dialog window + void setupDialog(const std::list<std::string> &msh_names); + + QLabel* _txt_label; + QComboBox* _msh_names; + QVBoxLayout* _layout; + const GEOLIB::GeoObject* _geo_object; + + +private slots: + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + //void requestNameChange(const std::string&, const GEOLIB::GEOTYPE, size_t, std::string); +}; + +#endif //SELECTMESHDIALOG_H diff --git a/Gui/DataView/SetNameDialog.cpp b/Gui/DataView/SetNameDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2f0ffb19468f4f9c3afa3fb3f01fe957ee116c94 --- /dev/null +++ b/Gui/DataView/SetNameDialog.cpp @@ -0,0 +1,57 @@ +/** + * \file SetNameDialog.cpp + * 2011/10/26 KR Initial implementation + */ + +#include "SetNameDialog.h" + +#include <QDialogButtonBox> +#include <QDialogButtonBox> +#include <QLabel> +#include <QLineEdit> +#include <QVBoxLayout> + +SetNameDialog::SetNameDialog(const std::string &parent_name, const std::string &object_type_name, size_t id, const std::string &old_name = "", QDialog* parent) : + QDialog(parent), _parent_name(parent_name), _object_type_name(object_type_name), _id(id) +{ + setupDialog(old_name); + show(); +} + +SetNameDialog::~SetNameDialog() +{ + delete _buttonBox; + delete _layout; + delete _new_name; + delete _txt_label; +} + +void SetNameDialog::setupDialog(const std::string &old_name) +{ + _layout = new QVBoxLayout(this); + QString dialog_text("Please enter a name for " + QString::fromStdString(_object_type_name) + " #" + QString::number(_id)); + _txt_label = new QLabel(this); + _txt_label->setText(dialog_text); + _new_name = new QLineEdit(QString::fromStdString(old_name)); + + setWindowTitle("Set name..."); + _layout->addWidget( _txt_label ); + _layout->addWidget( _new_name ); + _buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + connect(_buttonBox, SIGNAL(accepted()), this, SLOT(accept())); + connect(_buttonBox, SIGNAL(rejected()), this, SLOT(reject())); + _layout->addWidget( _buttonBox ); + + setLayout(_layout); +} + +void SetNameDialog::accept() +{ + emit requestNameChange(_parent_name, GEOLIB::convertGeoType(_object_type_name), _id, _new_name->text().toStdString()); + this->done(QDialog::Accepted); +} + +void SetNameDialog::reject() +{ + this->done(QDialog::Rejected); +} diff --git a/Gui/DataView/SetNameDialog.h b/Gui/DataView/SetNameDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..9b95132d410c92958f867ed2f7409a6431578deb --- /dev/null +++ b/Gui/DataView/SetNameDialog.h @@ -0,0 +1,59 @@ +/** + * \file SetNameDialog.h + * 2011/10/26 KR Initial implementation + */ + +#ifndef SETNAMEDIALOG_H +#define SETNAMEDIALOG_H + +#include "GeoType.h" + +#include <QDialog> + +class QDialogButtonBox; +class QLabel; +class QLineEdit; +class QVBoxLayout; + +/** + * \brief Small dialog for setting a name for an object. + */ +class SetNameDialog : public QDialog +{ + Q_OBJECT + +public: + /// Constructor + SetNameDialog(const std::string &parent_name, + const std::string &object_type_name, + size_t id, + const std::string &old_name, + QDialog* parent = 0); + ~SetNameDialog(); + + QDialogButtonBox* _buttonBox; /// The buttons used in this dialog. + +private: + /// Constructs a dialog window + void setupDialog(const std::string &old_name); + + QLabel* _txt_label; + QLineEdit* _new_name; + QVBoxLayout* _layout; + + std::string _parent_name; + std::string _object_type_name; + size_t _id; + +private slots: + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void requestNameChange(const std::string&, const GEOLIB::GEOTYPE, size_t, std::string); +}; + +#endif //SETNAMEDIALOG_H diff --git a/Gui/DataView/StationTabWidget.cpp b/Gui/DataView/StationTabWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c309fed97c8b9ac72d4da44ff0da38fe0d80d0fc --- /dev/null +++ b/Gui/DataView/StationTabWidget.cpp @@ -0,0 +1,15 @@ +/** + * \file StationTabWidget.cpp + * 3/11/2009 LB Initial implementation + * + * Implementation of StationTabWidget + */ + +// ** INCLUDES ** +#include "StationTabWidget.h" + +StationTabWidget::StationTabWidget( QWidget* parent /*= 0*/ ) + : QWidget(parent) +{ + setupUi(this); +} diff --git a/Gui/DataView/StationTabWidget.h b/Gui/DataView/StationTabWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..ea7e9de9fba5886d22f3c3e4a5637d58293bdff9 --- /dev/null +++ b/Gui/DataView/StationTabWidget.h @@ -0,0 +1,26 @@ +/** + * \file StationTabWidget.h + * 3/11/2009 LB Initial implementation + * + */ + +#ifndef STATIONTABWIDGET_H +#define STATIONTABWIDGET_H + +// ** INCLUDES ** +#include "ui_StationTabWidgetBase.h" + +/** + * \brief Widget containing StationTreeView-objects. + */ +class StationTabWidget : public QWidget, public Ui_StationTabWidgetBase +{ + Q_OBJECT + +public: + StationTabWidget(QWidget* parent = 0); + +private: +}; + +#endif // STATIONTABWIDGET_H diff --git a/Gui/DataView/StationTabWidgetBase.ui b/Gui/DataView/StationTabWidgetBase.ui new file mode 100644 index 0000000000000000000000000000000000000000..d1badedab01a12f4430238d2899b82b53f60fe6a --- /dev/null +++ b/Gui/DataView/StationTabWidgetBase.ui @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>StationTabWidgetBase</class> + <widget class="QWidget" name="StationTabWidgetBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>250</width> + <height>500</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="margin"> + <number>2</number> + </property> + <item> + <widget class="StationTreeView" name="treeView"/> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>StationTreeView</class> + <extends>QTreeView</extends> + <header>StationTreeView.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Gui/DataView/StationTreeModel.cpp b/Gui/DataView/StationTreeModel.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9f206c5b6e0265c2e49643e3e3e5f2d243ea1201 --- /dev/null +++ b/Gui/DataView/StationTreeModel.cpp @@ -0,0 +1,241 @@ +/** + * \file StationTreeModel.cpp + * KR Initial implementation + */ + +#include "BaseItem.h" +#include "OGSError.h" +#include "Station.h" +#include "StationTreeModel.h" + +#include <QDebug> + +/** + * Constructor. + */ +StationTreeModel::StationTreeModel( QObject* parent ) + : TreeModel(parent) +{ + QList<QVariant> rootData; + delete _rootItem; + rootData << "Station Name" << "x" << "y" << "z"; + _rootItem = new ModelTreeItem(rootData, NULL, NULL); +} + +StationTreeModel::~StationTreeModel() +{ +} + +/** + * Returns the model index of an item in the tree. + * \param row The row where the item is located + * \param column The column where the item is located + * \param parent The parent of the item + * \return The model index of the item + */ +QModelIndex StationTreeModel::index( int row, int column, + const QModelIndex &parent /*= QModelIndex()*/ ) const +{ + if (!hasIndex(row, column, parent)) + return QModelIndex(); + + ModelTreeItem* parentItem; + + if (!parent.isValid()) + parentItem = (ModelTreeItem*)(_rootItem); + else + parentItem = static_cast<ModelTreeItem*>(parent.internalPointer()); + + ModelTreeItem* childItem = (ModelTreeItem*)(parentItem->child(row)); + if (childItem) + { + QModelIndex newIndex = createIndex(row, column, childItem); + // assign ModelIndex to BaseItem so it can communicate with the model + BaseItem* item = childItem->getItem(); + if ( item != NULL ) + item->setModelIndex(newIndex); + return newIndex; + } + else + return QModelIndex(); +} + +/* + * Returns the model item associated with a tree item. This is a re-implementation of + * QOgsModelBase::itemFromIndex to deal with TreeItems with an optionally attached BaseItem + * \param index Index of the requested item + * \return The BaseItem associated with the tree item + * + BaseItem* StationTreeModel::itemFromIndex( const QModelIndex& index ) const + { + if (index.isValid()) + { + ModelTreeItem* treeItem = static_cast<ModelTreeItem*>(index.internalPointer()); + BaseItem* baseItem = treeItem->getItem(); + return baseItem; + } + else + return NULL; + } + */ + +/** + * Returns the Station-Object of the ModelTreeItem with the given index and the name of the list this station belongs to. + * \param index Index of the requested item + * \param listName Here, the method will put the name of the list this station belongs to. + * \return The station object associated with the tree item + */ +GEOLIB::Station* StationTreeModel::stationFromIndex( const QModelIndex& index, + QString &listName ) const +{ + if (index.isValid()) + { + ModelTreeItem* treeItem = static_cast<ModelTreeItem*>(index.internalPointer()); + TreeItem* parentItem = treeItem->parentItem(); + listName = parentItem->data(0).toString(); + return treeItem->getStation(); + } + else + return NULL; +} + +vtkPolyDataAlgorithm* StationTreeModel::vtkSource(const std::string &name) const +{ + size_t nLists = _lists.size(); + for (size_t i = 0; i < nLists; i++) + if ( name.compare( _lists[i]->data(0).toString().toStdString() ) == 0 ) + return dynamic_cast<BaseItem*>(_lists[i]->getItem())->vtkSource(); + return NULL; +} + +/** + * Inserts a subtree under _rootItem. + * \param listName Name of the new subtree. If no name is given a default name is assigned. + * \param stations The list with stations to be added as children of that subtree + */ +void StationTreeModel::addStationList(QString listName, const std::vector<GEOLIB::Point*>* stations) +{ + QList<QVariant> grpName; + if (listName.compare("") == 0) // if no name is given a default name is assigned + { + listName = "List"; + listName.append(QString::number(rowCount() + 1)); + } + grpName.push_back(QVariant(listName)); + grpName.push_back(QVariant("")); + grpName.push_back(QVariant("")); + grpName.push_back(QVariant("")); + BaseItem* grpItem = new BaseItem(listName, stations); + ModelTreeItem* group = new ModelTreeItem(grpName, _rootItem, grpItem); + _lists.push_back(group); + _rootItem->appendChild(group); + int vectorSize = stations->size(); + + for (int i = 0; i < vectorSize; i++) + { + QList<QVariant> stn; + stn.push_back(QVariant(QString::fromStdString(static_cast<GEOLIB::Station*>((* + stations) + [i])-> + getName()))); + stn.push_back(QVariant(QString::number((*(*stations)[i])[0],'f'))); + stn.push_back(QVariant(QString::number((*(*stations)[i])[1],'f'))); + stn.push_back(QVariant(QString::number((*(*stations)[i])[2],'f'))); + + ModelTreeItem* child = new ModelTreeItem(stn, group); + child->setStation(static_cast<GEOLIB::Station*>((*stations)[i])); + group->appendChild(child); + } + + qDebug() << "List" << listName << "loaded, " << stations->size() << "items added."; + + reset(); +} + +/** + * Removes the TreeItem with the given Index including all its children + */ +void StationTreeModel::removeStationList(QModelIndex index) +{ + if (index.isValid()) // + { + ModelTreeItem* item = static_cast<ModelTreeItem*>(getItem(index)); + + // also delete the lists entry in the list directory of the model + for (size_t i = 0; i < _lists.size(); i++) + if (item == _lists[i]) + _lists.erase(_lists.begin() + i); + + removeRows(0, item->childCount(), index); + removeRows(item->row(), 1, parent(index)); + } +} + +/** + * Removes the TreeItem with the given name including all its children + */ +void StationTreeModel::removeStationList(const std::string &name) +{ + for (size_t i = 0; i < _lists.size(); i++) + if ( name.compare( _lists[i]->data(0).toString().toStdString() ) == 0 ) + removeStationList(createIndex(_lists[i]->row(), 0, _lists[i])); +} + +/* + * Traverses the (sub-)tree of the TreeItem with the given index and looks for an item in that subtree + * with the given name. Using this method is probably rather slow and not recommended. + * If this method is called with an empty QModelIndex, the TreeModel will assign the rootItem to that + * index. + * \param index The TreeItem whose subtree will be searched. + * \param name The name of the item that should be found + * \return The QModelIndex of the desired item (or an empty index if no such item exists). + * + QModelIndex StationTreeModel::getItemByName(const QModelIndex &idx, const std::string &name) const + { + QModelIndex didx; + TreeItem* item = getItem(idx); + + int nChildren = item->childCount(); + for (int i=0; i<nChildren; i++) + { + TreeItem* child = item->child(i); + QString test = child->data(0).toString(); + + if ( name.compare(child->data(0).toString().toStdString()) != 0 ) + didx = getItemByName( index(i, 0, idx), name ); + else didx = index(i, 0, idx); + if (didx.isValid()) + return didx; + + } + + return QModelIndex(); // this is no valid QModelIndex and signifies that no item by the given name could be found. + } + */ + +/** + * Filters the station list based on the property boundaries given in bounds. + * Technically, the complete station list is removed from the model and only those items are re-loaded that fit the description. + * If no station in the list fulfills the given description an error msg is given. + */ +void StationTreeModel::filterStations(const std::string &listName, + const std::vector<GEOLIB::Point*>* stations, + const std::vector<PropertyBounds> &bounds) +{ + std::vector<GEOLIB::Point*>* filteredStations = new std::vector<GEOLIB::Point*>; + + size_t vectorSize = stations->size(); + for (size_t i = 0; i < vectorSize; i++) + if (static_cast<GEOLIB::Station*>((*stations)[i])->inSelection(bounds)) + filteredStations->push_back((*stations)[i]); + + if (filteredStations->empty()) + OGSError::box("No object is within the given boundaries."); //The filtered list is empty. + else + { + removeStationList(listName); + this->addStationList(QString::fromStdString(listName), filteredStations); + std::cout << "Filter applied to List \"" << listName << "\", " << + filteredStations->size() << " items added."; + } +} diff --git a/Gui/DataView/StationTreeModel.h b/Gui/DataView/StationTreeModel.h new file mode 100644 index 0000000000000000000000000000000000000000..4d0c5fe82d6619f22c301b303bb2a19c072ea31a --- /dev/null +++ b/Gui/DataView/StationTreeModel.h @@ -0,0 +1,57 @@ +/** + * \file StationTreeModel.h + * KR Initial implementation + */ + +#ifndef QSTATIONTREEMODEL_H +#define QSTATIONTREEMODEL_H + +#include <vector> + +#include "ModelTreeItem.h" +#include "Point.h" +#include "TreeModel.h" +#include <vtkPolyDataAlgorithm.h> + +namespace GEOLIB +{ +class Station; +class StationBorehole; +} + +class QString; +class QModelIndex; +class PropertyBounds; + +/** + * \brief A model for the StationTreeView implementing a tree as a double-linked list. + * + * A model for the StationTreeView implementing a tree as a double-linked list. + * In addition to a simple TreeModel each item also contains a 2D / 3D GraphicsItem for visualization. + * \sa TreeModel, StationTreeView, TreeItem, ModelTreeItem + */ +class StationTreeModel : public TreeModel +{ + Q_OBJECT + +public: + StationTreeModel(QObject* parent = 0); + ~StationTreeModel(); + + void addStationList(QString listName, const std::vector<GEOLIB::Point*>* stations); + void filterStations(const std::string &name, + const std::vector<GEOLIB::Point*>* stations, + const std::vector<PropertyBounds> &bounds); + const std::vector<ModelTreeItem*> &getLists() { return _lists; } + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + //BaseItem* itemFromIndex( const QModelIndex& index ) const; + void removeStationList(QModelIndex index); + void removeStationList(const std::string &name); + GEOLIB::Station* stationFromIndex( const QModelIndex& index, QString &listName ) const; + vtkPolyDataAlgorithm* vtkSource(const std::string &name) const; + +private: + std::vector<ModelTreeItem*> _lists; +}; + +#endif //QSTATIONTREEMODEL_H diff --git a/Gui/DataView/StationTreeView.cpp b/Gui/DataView/StationTreeView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..376b76a67a742ac6f428ca7852b086cfe7756519 --- /dev/null +++ b/Gui/DataView/StationTreeView.cpp @@ -0,0 +1,240 @@ +/** + * \file StationTreeView.cpp + * KR Initial implementation + */ + +#include <QFileDialog> +#include <QMenu> +#include <iostream> + +#include "GMSInterface.h" +#include "Station.h" +#include "StationIO.h" + +#include "DiagramPrefsDialog.h" +#include "ModelTreeItem.h" +#include "OGSError.h" +#include "StationTreeModel.h" +#include "StationTreeView.h" +#include "StratWindow.h" + +StationTreeView::StationTreeView(QWidget* parent) : QTreeView(parent) +{ +// setContextMenuPolicy(Qt::CustomContextMenu); +// connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showContextMenu(const QPoint &))); +} + +void StationTreeView::updateView() +{ + setAlternatingRowColors(true); + resizeColumnToContents(0); + setColumnWidth(1,50); + setColumnWidth(2,50); +} + +void StationTreeView::on_Clicked(QModelIndex idx) +{ + qDebug("%d, %d",idx.parent().row(), idx.row()); +} + +void StationTreeView::selectionChanged( const QItemSelection &selected, + const QItemSelection &deselected ) +{ + emit itemSelectionChanged(selected, deselected); + return QTreeView::selectionChanged(selected, deselected); +} + +void StationTreeView::selectionChangedFromOutside( const QItemSelection &selected, + const QItemSelection &deselected ) +{ + QItemSelectionModel* selModel = this->selectionModel(); + + selModel->blockSignals(true); + selModel->select(deselected, QItemSelectionModel::Deselect); + selModel->select(selected, QItemSelectionModel::Select); + selModel->blockSignals(false); + + return QTreeView::selectionChanged(selected, deselected); +} + +void StationTreeView::contextMenuEvent( QContextMenuEvent* event ) +{ + QModelIndex index = this->selectionModel()->currentIndex(); + ModelTreeItem* item = static_cast<ModelTreeItem*>(index.internalPointer()); + + if (!item) // Otherwise sometimes it crashes when (unmotivated ;-) ) clicking in a treeview + return; + + // The current index refers to a parent item (e.g. a listname) + if (item->childCount() > 0) + { + QMenu menu; + QAction* propertyAction = menu.addAction("Display list properties..."); + QAction* exportAction = menu.addAction("Export to GMS..."); + QAction* saveAction = menu.addAction("Save to file..."); + menu.addSeparator(); + QAction* removeAction = menu.addAction("Remove station list"); + + connect(propertyAction, SIGNAL(triggered()), this, SLOT(showPropertiesDialog())); + connect(exportAction, SIGNAL(triggered()), this, SLOT(exportList())); + connect(saveAction, SIGNAL(triggered()), this, SLOT(saveList())); + connect(removeAction, SIGNAL(triggered()), this, SLOT(removeStationList())); + menu.exec(event->globalPos()); + } + // The current index refers to a station object + else + { + QString temp_name; + QMenu menu; + + if (static_cast<StationTreeModel*>(model())->stationFromIndex(index, + temp_name)->type() == + GEOLIB::Station::BOREHOLE) + { + QAction* stratAction = menu.addAction("Display Stratigraphy..."); + QAction* exportAction = menu.addAction("Export to GMS..."); + connect(stratAction, SIGNAL(triggered()), this, SLOT(displayStratigraphy())); + connect(exportAction, SIGNAL(triggered()), this, SLOT(exportStation())); + menu.exec(event->globalPos()); + } + else + { + menu.addAction("View Information..."); + QAction* showDiagramAction = menu.addAction("View Diagram..."); + connect(showDiagramAction, SIGNAL(triggered()), this, + SLOT(showDiagramPrefsDialog())); + menu.exec(event->globalPos()); + } + } +} + +void StationTreeView::displayStratigraphy() +{ + QModelIndex index = this->selectionModel()->currentIndex(); + + QString temp_name; + // get list name + static_cast<StationTreeModel*>(model())->stationFromIndex( + this->selectionModel()->currentIndex(), temp_name); + // get color table (horrible way to do it but there you go ...) + std::map<std::string, + GEOLIB::Color*> colorLookupTable = + static_cast<VtkStationSource*>(static_cast<StationTreeModel*>(model())->vtkSource( + temp_name. + toStdString())) + ->getColorLookupTable(); + StratWindow* stratView = + new StratWindow(static_cast<GEOLIB::StationBorehole*>(static_cast<StationTreeModel*>( + model()) + ->stationFromIndex(index, + temp_name)), + &colorLookupTable); + stratView->setAttribute(Qt::WA_DeleteOnClose); // this fixes the memory leak shown by cppcheck + stratView->show(); +} + +void StationTreeView::saveList() +{ + TreeItem* item = static_cast<StationTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex()); + QString listName = item->data(0).toString(); + QString fileName = QFileDialog::getSaveFileName(this, "Save station list", "","*.stn"); + if (!fileName.isEmpty()) + emit stationListSaved(listName, fileName); +} + +void StationTreeView::exportList() +{ + // only a test for the stratigraphy screenshot tool and writer!! + //QString Name = static_cast<StationTreeModel*>(model())->getItem(this->selectionModel()->currentIndex())->data(0).toString(); + //writeStratigraphiesAsImages(Name); + + TreeItem* item = static_cast<StationTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex()); + std::string listName = item->data(0).toString().toStdString(); + QString fileName = QFileDialog::getSaveFileName(this, + "Export Boreholes to GMS-Format", + "", + "*.txt"); + if (!fileName.isEmpty()) + emit stationListExportRequested(listName, fileName.toStdString()); +} + +void StationTreeView::exportStation() +{ + QModelIndex index = this->selectionModel()->currentIndex(); + QString fileName = QFileDialog::getSaveFileName(this, + "Export Borehole to GMS-Format", + "", + "*.txt"); + if (!fileName.isEmpty()) + { + QString temp_name; + std::vector<std::string> temp_soil_names; + temp_soil_names.push_back(""); // soil name vector needs to be initialised + GMSInterface::writeBoreholeToGMS(static_cast<GEOLIB::StationBorehole*>(static_cast< + StationTreeModel + *>( + model())->stationFromIndex(index, + temp_name)), + fileName.toStdString(), temp_soil_names); + } +} + +void StationTreeView::removeStationList() +{ + TreeItem* item = static_cast<StationTreeModel*>(model())->getItem( + this->selectionModel()->currentIndex()); + emit stationListRemoved((item->data(0).toString()).toStdString()); +} + +void StationTreeView::showPropertiesDialog() +{ + QModelIndex index = this->selectionModel()->currentIndex(); + QString name = (static_cast<ModelTreeItem*>(index.internalPointer())->data(0)).toString(); + emit propertiesDialogRequested(name.toStdString()); +} + +void StationTreeView::showDiagramPrefsDialog() +{ + QModelIndex index = this->selectionModel()->currentIndex(); + emit diagramRequested(index); +} + +void StationTreeView::writeStratigraphiesAsImages(QString listName) +{ + std::map<std::string, + GEOLIB::Color*> colorLookupTable = + static_cast<VtkStationSource*>(static_cast<StationTreeModel*>(model())->vtkSource( + listName. + toStdString())) + ->getColorLookupTable(); + std::vector<ModelTreeItem*> lists = static_cast<StationTreeModel*>(model())->getLists(); + size_t nLists = lists.size(); + for (size_t i = 0; i < nLists; i++) + if ( listName.toStdString().compare( lists[i]->data(0).toString().toStdString() ) + == 0 ) + { + const std::vector<GEOLIB::Point*>* stations = + dynamic_cast<BaseItem*>(lists[i]->getItem())->getStations(); + + for (size_t i = 0; i < stations->size(); i++) + { + StratWindow* stratView = + new StratWindow(static_cast<GEOLIB::StationBorehole*>((* + stations) + [i]), + &colorLookupTable); + stratView->setAttribute(Qt::WA_DeleteOnClose); // this fixes the memory leak shown by cppcheck + stratView->show(); + stratView->stationView->saveAsImage( + "c:/project/" + + QString::fromStdString(static_cast<GEOLIB::StationBorehole*>(( + * + stations) + [ + i])->getName()) + ".jpg"); + stratView->close(); + } + } +} diff --git a/Gui/DataView/StationTreeView.h b/Gui/DataView/StationTreeView.h new file mode 100644 index 0000000000000000000000000000000000000000..273c8a24c4758408f4b81f4d642a235ee8f6bd88 --- /dev/null +++ b/Gui/DataView/StationTreeView.h @@ -0,0 +1,68 @@ +/** + * \file StationTreeView.h + * KR Initial implementation + */ + +#ifndef QSTATIONTREEVIEW_H +#define QSTATIONTREEVIEW_H + +#include "PropertyBounds.h" +#include <QContextMenuEvent> +#include <QTreeView> + +#include "Station.h" + +/** + * \brief A view for the StationTreeModel with a number of properties adequate for this kind of data + * \sa StationTreeModel, ModelTreeItem + */ +class StationTreeView : public QTreeView +{ + Q_OBJECT + +public: + /// Constructor + StationTreeView(QWidget* parent = 0); + + /// Update the view to visualise changes made to the underlying data + void updateView(); + +public slots: + //void filterStations(std::vector<PropertyBounds> bounds); + +protected slots: + /// Instructions if the selection of items in the view has changed. + void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + + /// Instructions if the selection of items in the view has changed by events outside the view (i.e. by actions made in the visualisation). + void selectionChangedFromOutside(const QItemSelection &selected, + const QItemSelection &deselected); + +private: + /// Actions to be taken after a right mouse click is performed in the station view. + void contextMenuEvent( QContextMenuEvent* e ); + + /// Create image files from all stratigraphies in a borehole vector + void writeStratigraphiesAsImages(QString listName); + +private slots: + void on_Clicked(QModelIndex idx); + void displayStratigraphy(); + void exportList(); + void exportStation(); + void removeStationList(); + void saveList(); + void showPropertiesDialog(); + void showDiagramPrefsDialog(); + +signals: + void itemSelectionChanged(const QItemSelection & selected, + const QItemSelection & deselected); + void propertiesDialogRequested(std::string name); + void stationListExportRequested(std::string listName, std::string fileName); + void stationListRemoved(std::string name); + void stationListSaved(QString listName, QString fileName); + void diagramRequested(QModelIndex&); +}; + +#endif //QSTATIONTREEVIEW_H diff --git a/Gui/DataView/StratView/CMakeLists.txt b/Gui/DataView/StratView/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..52172483f51b50c7e2d84c576d98e802371e4cd3 --- /dev/null +++ b/Gui/DataView/StratView/CMakeLists.txt @@ -0,0 +1,63 @@ +# Source files +set( SOURCES + StratBar.cpp + StratScene.cpp + StratView.cpp + StratWindow.cpp +) + +# Moc Header files +set( MOC_HEADERS + StratView.h + StratWindow.h +) + +# Header files +set( HEADERS + StratBar.h + StratScene.h +) + +# UI files +set( UIS + StratWindow.ui +) + +# Run Qts user interface compiler uic on .ui files +qt4_wrap_ui( UI_HEADERS ${UIS} ) + +# Run Qts meta object compiler moc on header files +qt4_wrap_cpp( MOC_SOURCES ${MOC_HEADERS} ) + +# Include the headers which are generated by uic and moc +# and include additional header +include_directories( + ${CMAKE_SOURCE_DIR}/Qt/DataView/StratView + ${CMAKE_BINARY_DIR}/Qt/DataView/StratView + ${CMAKE_SOURCE_DIR}/Base + ${CMAKE_SOURCE_DIR}/GEO + ${CMAKE_SOURCE_DIR}/MathLib + ${CMAKE_SOURCE_DIR}/Qt/Base +) + +# Put moc files in a project folder +source_group("Moc Files" REGULAR_EXPRESSION moc_*) + + + +# Create the library +#add_executable( StratView +add_library( StratView STATIC + ${SOURCES} + ${HEADERS} + ${MOC_HEADERS} + ${MOC_SOURCES} + ${UI_HEADERS} +) + +# Link Qt library +target_link_libraries( StratView + ${QT_LIBRARIES} + Base + GEO +) diff --git a/Gui/DataView/StratView/StratBar.cpp b/Gui/DataView/StratView/StratBar.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a49cfca9cedb8c98503ce47d42b82ec3e6206920 --- /dev/null +++ b/Gui/DataView/StratView/StratBar.cpp @@ -0,0 +1,77 @@ +/** + * \file StratBar.cpp + * 2010/03/16 - KR Initial implementation + */ + +#include "StratBar.h" +#include <QPainter> + +StratBar::StratBar(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors, + QGraphicsItem* parent) : + QGraphicsItem(parent), _station(station) +{ + if (stratColors) + _stratColors = *stratColors; +} + +StratBar::~StratBar() +{ +// std::map<std::string, GEOLIB::Color*>::iterator it; +// for (it = _stratColors.begin(); it != _stratColors.end(); it++) { +// delete it->second; +// } +} + +QRectF StratBar::boundingRect() const +{ + return QRectF(0, 0, BARWIDTH + 10, totalLogHeight()); +} + +void StratBar::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget) +{ + Q_UNUSED (option) + Q_UNUSED (widget) + + double top = 0, height = 0; + + QPen pen(Qt::black, 1, Qt::SolidLine, Qt::SquareCap, Qt::RoundJoin); + pen.setCosmetic(true); + painter->setPen(pen); + //painter->drawRect(_bar); + + //pen.setWidth(1); + std::vector<GEOLIB::Point*> profile = _station->getProfile(); + std::vector<std::string> soilNames = _station->getSoilNames(); + size_t nLayers = profile.size(); + + painter->drawLine(0, 0, BARWIDTH + 5, 0); + + for (size_t i = 1; i < nLayers; i++) + { + top += height; + height = logHeight(((*(profile[i - 1]))[2] - (*(profile[i]))[2])); + QRectF layer(0, top, BARWIDTH, height); + const GEOLIB::Color* c (GEOLIB::getColor(soilNames[i], _stratColors)); + QBrush brush(QColor((int)(*c)[0], + (int)(*c)[1], + (int)(*c)[2], + 127), Qt::SolidPattern); + painter->setBrush(brush); + + painter->drawRect(layer); + painter->drawLine(0, (int)layer.bottom(), BARWIDTH + 5, (int)layer.bottom()); + //painter->drawText(BARWIDTH+10, layer.bottom(), QString::number((*(profile[i]))[2])); + } +} + +double StratBar::totalLogHeight() const +{ + double height = 0; + std::vector<GEOLIB::Point*> profile = _station->getProfile(); + + for (size_t i = 1; i < profile.size(); i++) + height += ( log((*(profile[i - 1]))[2] - (*(profile[i]))[2] + 1) * 100 ); + + return height; +} diff --git a/Gui/DataView/StratView/StratBar.h b/Gui/DataView/StratView/StratBar.h new file mode 100644 index 0000000000000000000000000000000000000000..2bff5e45659ff3d8495d2b098c20da347b4e8e5a --- /dev/null +++ b/Gui/DataView/StratView/StratBar.h @@ -0,0 +1,55 @@ +/** + * \file StratBar.h + * 2010/03/16 - KR Initial implementation + */ + +#ifndef STRATBAR_H +#define STRATBAR_H + +#include "Station.h" +#include <QGraphicsItem> +#include <cmath> + +/** + * \brief A 2D bar visualisation of a borehole stratigraphy. + * + * A 2D bar visualisation of a borehole stratigraphy as a QGraphicsItem. + */ +class StratBar : public QGraphicsItem +{ +public: + /** + * \brief Constructor + * \param station The borehole whose stratigraphy will be visualised. + * \param stratColors A color map. + * \param parent The parent QGraphicsItem. + */ + StratBar(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors = NULL, + QGraphicsItem* parent = 0); + ~StratBar(); + + /// Returns the bounding rectangle of the bar. + QRectF boundingRect() const; + + /// Paints the bar. + void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget); + +private: + /** + * \brief Calculates the height for a soil layer by "log(d+1)*100". + * \param h The original thickness of the soil layer. + */ + double logHeight(double h) const { return log(h + 1) * 100; } + + /// Calculates the total height of the bar by calculating and adding the log-height for all layers in the borehole + double totalLogHeight() const; + + /// The default width of the bar + static const int BARWIDTH = 50; + + GEOLIB::StationBorehole* _station; + std::map<std::string, GEOLIB::Color*> _stratColors; +}; + +#endif //STRATBAR_H diff --git a/Gui/DataView/StratView/StratScene.cpp b/Gui/DataView/StratView/StratScene.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c4bbe6477f73818eec7d8bd76555c951aeebab4f --- /dev/null +++ b/Gui/DataView/StratView/StratScene.cpp @@ -0,0 +1,114 @@ +/** + * \file StratScene.cpp + * 2010/03/16 - KR Initial implementation + */ + +#include <limits> +#include <math.h> + +#include <QGraphicsTextItem> + +#include "DateTools.h" +#include "QNonScalableGraphicsTextItem.h" +#include "StratBar.h" +#include "StratScene.h" + +StratScene::StratScene(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors, + QObject* parent) : QGraphicsScene(parent) +{ + QRectF textBounds; + int stratBarOffset = 250; + + QFont font( "Arial", 15, QFont::DemiBold, false); + + QNonScalableGraphicsTextItem* boreholeTag = addNonScalableText("Borehole", font); + QNonScalableGraphicsTextItem* boreholeName = addNonScalableText( + "\"" + QString::fromStdString(station->getName()) + "\"", + font); + textBounds = boreholeTag->boundingRect(); + boreholeTag->setPos((textBounds.width() / 2.0), 80); + textBounds = boreholeName->boundingRect(); + boreholeName->setPos((textBounds.width() / 2.0), 200); + + QNonScalableGraphicsTextItem* totalDepth = + addNonScalableText("Depth: " + QString::number(station->getDepth()) + " m"); + textBounds = totalDepth->boundingRect(); + totalDepth->setPos((textBounds.width() / 2.0), 350); +/* + QNonScalableGraphicsTextItem* dateText = addNonScalableText("Date: " + QString::fromStdString(date2string(station->getDate()))); + textBounds = dateText->boundingRect(); + dateText->setPos(this->MARGIN + (textBounds.width()/2.0), 350); + */ + QNonScalableGraphicsTextItem* dot = addNonScalableText(" "); + dot->setPos(0, 0); + + StratBar* stratBar = addStratBar(station, stratColors); + stratBar->setPos(stratBarOffset, MARGIN); + QRectF stratBarBounds = stratBar->boundingRect(); + + addDepthLabels(station->getProfile(), stratBarOffset + stratBarBounds.width()); + + if (station->getSoilNames().size() > 0) + addSoilNameLabels(station->getSoilNames(), station->getProfile(), stratBarOffset + + (stratBarBounds.width() / 2)); +} + +StratScene::~StratScene() +{ +} + +void StratScene::addDepthLabels(std::vector<GEOLIB::Point*> profile, double offset) +{ + QRectF textBounds; + double vertPos = MARGIN; + std::vector<QNonScalableGraphicsTextItem*> depthText; + depthText.push_back(addNonScalableText(QString::number((*(profile[0]))[2]))); + textBounds = depthText[0]->boundingRect(); + depthText[0]->setPos(offset + textBounds.width() / 2, vertPos); + + for (size_t i = 1; i < profile.size(); i++) + { + depthText.push_back(addNonScalableText(QString::number((*(profile[i]))[2]))); + vertPos += log((*(profile[i - 1]))[2] - (*(profile[i]))[2] + 1) * 100; + textBounds = depthText[i]->boundingRect(); + depthText[i]->setPos(offset + textBounds.width() / 2, vertPos); + } +} + +QNonScalableGraphicsTextItem* StratScene::addNonScalableText(const QString &text, const QFont &font) +{ + QNonScalableGraphicsTextItem* item = new QNonScalableGraphicsTextItem(text); + item->setFont(font); + addItem(item); + return item; +} + +void StratScene::addSoilNameLabels(std::vector<std::string> soilNames, + std::vector<GEOLIB::Point*> profile, + double offset) +{ + //QRectF textBounds; + double vertPos = MARGIN, halfHeight = 0; + std::vector<QNonScalableGraphicsTextItem*> soilText; + soilText.push_back(addNonScalableText(QString::fromStdString(soilNames[0]))); + //textBounds = soilText[0]->boundingRect(); + soilText[0]->setPos(offset /* - textBounds.width() */, vertPos); + + for (size_t i = 1; i < soilNames.size(); i++) + { + soilText.push_back(addNonScalableText(QString::fromStdString(soilNames[i]))); + halfHeight = log((*(profile[i - 1]))[2] - (*(profile[i]))[2] + 1) * 100 / 2; + //textBounds = soilText[i]->boundingRect(); + soilText[i]->setPos(offset /* - textBounds.width() */, vertPos + halfHeight); + vertPos += ( 2 * halfHeight ); + } +} + +StratBar* StratScene::addStratBar(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors) +{ + StratBar* b = new StratBar(station, stratColors); + addItem(b); + return b; +} diff --git a/Gui/DataView/StratView/StratScene.h b/Gui/DataView/StratView/StratScene.h new file mode 100644 index 0000000000000000000000000000000000000000..1dd2b192e2b340dcf0fc6fbed59dd3eb5276354b --- /dev/null +++ b/Gui/DataView/StratView/StratScene.h @@ -0,0 +1,48 @@ +/** + * \file StratScene.h + * 2010/03/16 - KR Initial implementation + */ + +#ifndef STRATSCENE_H +#define STRATSCENE_H + +#include "Station.h" +#include <QGraphicsScene> + +class StratBar; +class QNonScalableGraphicsTextItem; + +/** + * \brief The scene for the visualisation of the stratigraphy of a borehole. + */ +class StratScene : public QGraphicsScene +{ +public: + /// Constructor + StratScene(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors = NULL, + QObject* parent = 0); + ~StratScene(); + + /// The margin between the boundary of the scene and the bounding box of all items within the scene + static const int MARGIN = 50; + +private: + /// Adds text labels indicating the depth at the beginning and end of each soil layer + void addDepthLabels(std::vector<GEOLIB::Point*> profile, double offset); + + /// Add a non-scalable text item to the scene. + QNonScalableGraphicsTextItem* addNonScalableText(const QString &text, + const QFont &font = QFont()); + + /// Adds text labels indicating the name of each soil layer + void addSoilNameLabels(std::vector<std::string> soilNames, + std::vector<GEOLIB::Point*> profile, + double offset); + + /// Add a stratigraphy-bar to the scene. + StratBar* addStratBar(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors = NULL); +}; + +#endif //STRATSCENE_H diff --git a/Gui/DataView/StratView/StratView.cpp b/Gui/DataView/StratView/StratView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a3442d64196dbcd2f58af2067b82099d5c2ed728 --- /dev/null +++ b/Gui/DataView/StratView/StratView.cpp @@ -0,0 +1,58 @@ +/** + * \file StratView.cpp + * 2010/03/16 - KR Initial implementation + */ + +#include "Station.h" +#include "StratView.h" +#include <math.h> + +StratView::~StratView() +{ + delete _scene; +} + +void StratView::setStation(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors) +{ + _scene = new StratScene(station, stratColors); + setScene(_scene); + initialize(); +} + +void StratView::initialize() +{ + setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + update(); +} + +void StratView::resizeEvent(QResizeEvent* event) +{ + Q_UNUSED (event) + update(); +} + +void StratView::update() +{ + QRectF viewRect = _scene->itemsBoundingRect(); + _scene->setSceneRect(viewRect); + QRectF sceneInView(_scene->MARGIN,_scene->MARGIN, + viewRect.width() + 2 * _scene->MARGIN, + viewRect.height() + 2 * _scene->MARGIN); + fitInView(sceneInView, Qt::IgnoreAspectRatio); +} + +void StratView::saveAsImage(QString fileName) +{ + this->update(); + + QRectF viewRect = _scene->itemsBoundingRect(); + QImage img( + static_cast<int>(viewRect.width()) + 2 * _scene->MARGIN, 600, QImage::Format_ARGB32); + QPainter painter(&img); + + this->render(&painter); + img.save(fileName); +} diff --git a/Gui/DataView/StratView/StratView.h b/Gui/DataView/StratView/StratView.h new file mode 100644 index 0000000000000000000000000000000000000000..634a5da7f730fcd66bb9cbc1c0c5b2fd33e5b7db --- /dev/null +++ b/Gui/DataView/StratView/StratView.h @@ -0,0 +1,63 @@ +/** + * \file StratView.h + * 2010/03/16 - KR Initial implementation + */ + +#ifndef STRATVIEW_H +#define STRATVIEW_H + +#include "StratScene.h" +#include <QGraphicsView> +#include <QtGui/QWidget> + +namespace GEOLIB +{ +class StationBorehole; +} + +/** + * \brief A view in which to display the stratigraphy of a borehole. + */ +class StratView : public QGraphicsView +{ + Q_OBJECT +public: + /** + * Creates an empty view. + */ + StratView(QWidget* parent = 0) : _scene(NULL) {Q_UNUSED(parent); } + ~StratView(); + + /// Sets the Borehole whose data should be visualised. + void setStation(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors = NULL); + + /// Returns the height of the bounding rectangle of all objects within the scene. + int getHeight() { return static_cast<int>((_scene->itemsBoundingRect()).height()); } + + /// Returns the width of the bounding rectangle of all objects within the scene. + int getWidth() { return static_cast<int>((_scene->itemsBoundingRect()).width()); } + + void saveAsImage(QString fileName); + +protected: + /// Resizes the scene. + void resizeEvent(QResizeEvent* event); + +private: + /// Initialises the view. + void initialize(); + + /// The minimum size of the window. + QSize minimumSizeHint() const { return QSize(3 * _scene->MARGIN,2 * _scene->MARGIN); } + + /// The default size of the window. + QSize sizeHint() const { return QSize(6 * _scene->MARGIN, 4 * _scene->MARGIN); } + + /// Updates the view automatically when a Borehole is added or when the window containing the view changes its state. + void update(); + + StratScene* _scene; +}; + +#endif //STRATVIEW_H diff --git a/Gui/DataView/StratView/StratWindow.cpp b/Gui/DataView/StratView/StratWindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..51facd10aa212fd56f837dd7965c20b0a80f0551 --- /dev/null +++ b/Gui/DataView/StratView/StratWindow.cpp @@ -0,0 +1,29 @@ +/** + * \file StratWindow.cpp + * 2010/03/16 - KR Initial implementation + */ + +#include "Station.h" +#include "StratWindow.h" + +StratWindow::StratWindow(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors, + QWidget* parent) : QWidget(parent) +{ + setupUi(this); + stationView->setRenderHints( QPainter::Antialiasing ); + stationView->setStation(station, stratColors); + resizeWindow(); +} + +void StratWindow::on_closeButton_clicked() +{ + this->close(); +} + +void StratWindow::resizeWindow() +{ + int width = (stationView->getWidth() > 800) ? 800 : stationView->getWidth(); + int height = (stationView->getHeight() > 600) ? 600 : stationView->getHeight(); + resize(width, height); +} diff --git a/Gui/DataView/StratView/StratWindow.h b/Gui/DataView/StratView/StratWindow.h new file mode 100644 index 0000000000000000000000000000000000000000..e51c1ef48d502962b27a6fd3f229123bffe1646d --- /dev/null +++ b/Gui/DataView/StratView/StratWindow.h @@ -0,0 +1,44 @@ +/** + * \file StratWindow.h + * 2010/03/16 - KR Initial implementation + */ + +#ifndef STRATWINDOW_H +#define STRATWINDOW_H + +#include "ui_StratWindow.h" +#include <QWidget> + +namespace GEOLIB +{ +class StationBorehole; +} + +/** + * \brief Creates a window to visualise the stratigraphy of a borehole. + */ +class StratWindow : public QWidget, public Ui_StratWindow +{ + Q_OBJECT + +public: + /** + * Constructor + * \param station The borehole object to be visualised. + * \param stratColors A color map. + * \param parent The parent QWidget. + */ + StratWindow(GEOLIB::StationBorehole* station, + std::map<std::string, GEOLIB::Color*>* stratColors = NULL, + QWidget* parent = 0); + ~StratWindow(void) { this->destroy(); } + +private: + /// Automatically resize window based on the measurements of the borehole. + void resizeWindow(); + +private slots: + void on_closeButton_clicked(); +}; + +#endif //STRATWINDOW_H diff --git a/Gui/DataView/StratView/StratWindow.ui b/Gui/DataView/StratView/StratWindow.ui new file mode 100644 index 0000000000000000000000000000000000000000..f6719ed02d10b36614ffa183524a81f9ff880101 --- /dev/null +++ b/Gui/DataView/StratView/StratWindow.ui @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>StratWindow</class> + <widget class="QWidget" name="StratWindow"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>410</width> + <height>428</height> + </rect> + </property> + <property name="windowTitle"> + <string>Observation Station</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="StratView" name="stationView"> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="frameShape"> + <enum>QFrame::Box</enum> + </property> + <property name="frameShadow"> + <enum>QFrame::Plain</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="closeButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="layoutDirection"> + <enum>Qt::RightToLeft</enum> + </property> + <property name="text"> + <string>Close</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>StratView</class> + <extends>QGraphicsView</extends> + <header location="global">StratView.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Gui/DataView/ncvalues.h b/Gui/DataView/ncvalues.h new file mode 100644 index 0000000000000000000000000000000000000000..2daf28a0168fff9eaeb25c6a5d32ed94d025fe48 --- /dev/null +++ b/Gui/DataView/ncvalues.h @@ -0,0 +1,283 @@ +/********************************************************************* + * Copyright 1992, University Corporation for Atmospheric Research + * See netcdf/README file for copying and redistribution conditions. + * + * Purpose: interface for classes of typed arrays for netCDF + * + * $Header: /upc/share/CVS/netcdf-3/cxx/ncvalues.h,v 1.7 2006/07/26 21:12:06 russ Exp $ + *********************************************************************/ + +#ifndef Ncvalues_def +#define Ncvalues_def + +#include <iostream> +#include <sstream> +#include <limits.h> +#ifdef VTK_NETCDF_FOUND +#include <vtknetcdf/netcdf.h> +#else +#include <netcdf.h> +#endif + +// Documentation warned this might change and now it has, for +// consistency with C interface +typedef signed char ncbyte; + +#define NC_UNSPECIFIED ((nc_type)0) + +// C++ interface dates from before netcdf-3, still uses some netcdf-2 names +#ifdef NO_NETCDF_2 +#define NC_LONG NC_INT +#define FILL_LONG NC_FILL_INT +typedef int nclong; +#define NC_FATAL 1 +#define NC_VERBOSE 2 +#endif + +enum NcType +{ + ncNoType = NC_UNSPECIFIED, + ncByte = NC_BYTE, + ncChar = NC_CHAR, + ncShort = NC_SHORT, + ncInt = NC_INT, + ncLong = NC_LONG, // deprecated, someday want to use for 64-bit ints + ncFloat = NC_FLOAT, + ncDouble = NC_DOUBLE +}; + +#define ncBad_ncbyte ncBad_byte +static const ncbyte ncBad_byte = NC_FILL_BYTE; +static const char ncBad_char = NC_FILL_CHAR; +static const short ncBad_short = NC_FILL_SHORT; +static const nclong ncBad_nclong = FILL_LONG; // deprecated +static const int ncBad_int = NC_FILL_INT; +static const long ncBad_long = FILL_LONG; // deprecated +static const float ncBad_float = NC_FILL_FLOAT; +static const double ncBad_double = NC_FILL_DOUBLE; + +// macros to glue tokens together to form new names (used to be in generic.h) +#define name2(a,b) a ## b +#define declare(clas,t) name2(clas,declare)(t) +#define implement(clas,t) name2(clas,implement)(t) +// This is the same as the name2 macro, but we need to define our own +// version since rescanning something generated with the name2 macro +// won't necessarily cause name2 to be expanded again. +#define makename2(z, y) makename2_x(z, y) +#define makename2_x(z, y) z##y + +#define NcVal(TYPE) makename2(NcValues_,TYPE) + +#define NcValuesdeclare(TYPE) \ +class MSCPP_EXTRA NcVal(TYPE) : public NcValues \ +{ \ + public: \ + NcVal(TYPE)( void ); \ + NcVal(TYPE)(long Num); \ + NcVal(TYPE)(long Num, const TYPE* vals); \ + NcVal(TYPE)(const NcVal(TYPE)&); \ + virtual NcVal(TYPE)& operator=(const NcVal(TYPE)&); \ + virtual ~NcVal(TYPE)( void ); \ + virtual void* base( void ) const; \ + virtual int bytes_for_one( void ) const; \ + virtual ncbyte as_ncbyte( long n ) const; \ + virtual char as_char( long n ) const; \ + virtual short as_short( long n ) const; \ + virtual int as_int( long n ) const; \ + virtual int as_nclong( long n ) const; \ + virtual long as_long( long n ) const; \ + virtual float as_float( long n ) const; \ + virtual double as_double( long n ) const; \ + virtual char* as_string( long n ) const; \ + virtual int invalid( void ) const; \ + private: \ + TYPE* the_values; \ + std::ostream& print(std::ostream&) const; \ +}; + +#define NcTypeEnum(TYPE) makename2(_nc__,TYPE) +#define _nc__ncbyte ncByte +#define _nc__char ncChar +#define _nc__short ncShort +#define _nc__int ncInt +#define _nc__nclong ncLong +#define _nc__long ncLong +#define _nc__float ncFloat +#define _nc__double ncDouble +#define NcValuesimplement(TYPE) \ +NcVal(TYPE)::NcVal(TYPE)( void ) \ + : NcValues(NcTypeEnum(TYPE), 0), the_values(0) \ +{} \ + \ +NcVal(TYPE)::NcVal(TYPE)(long Num, const TYPE* vals) \ + : NcValues(NcTypeEnum(TYPE), Num) \ +{ \ + the_values = new TYPE[Num]; \ + for(int i = 0; i < Num; i++) \ + the_values[i] = vals[i]; \ +} \ + \ +NcVal(TYPE)::NcVal(TYPE)(long Num) \ + : NcValues(NcTypeEnum(TYPE), Num), the_values(new TYPE[Num]) \ +{} \ + \ +NcVal(TYPE)::NcVal(TYPE)(const NcVal(TYPE)& v) : \ + NcValues(v) \ +{ \ + delete[] the_values; \ + the_values = new TYPE[v.the_number]; \ + for(int i = 0; i < v.the_number; i++) \ + the_values[i] = v.the_values[i]; \ +} \ + \ +NcVal(TYPE)& NcVal(TYPE)::operator=(const NcVal(TYPE)& v) \ +{ \ + if ( &v != this) { \ + NcValues::operator=(v); \ + delete[] the_values; \ + the_values = new TYPE[v.the_number]; \ + for(int i = 0; i < v.the_number; i++) \ + the_values[i] = v.the_values[i]; \ + } \ + return *this; \ +} \ + \ +void* NcVal(TYPE)::base( void ) const \ +{ \ + return the_values; \ +} \ + \ +NcVal(TYPE)::~NcVal(TYPE)( void ) \ +{ \ + delete[] the_values; \ +} \ + \ +int NcVal(TYPE)::invalid( void ) const \ +{ \ + for(int i=0;i<the_number;i++) \ + if (the_values[i] == makename2(ncBad_,TYPE)) return 1; \ + return 0; \ +} \ + + +#define Ncbytes_for_one_implement(TYPE) \ +int NcVal(TYPE)::bytes_for_one( void ) const \ +{ \ + return sizeof(TYPE); \ +} + +#define as_ncbyte_implement(TYPE) \ +ncbyte NcVal(TYPE)::as_ncbyte( long n ) const \ +{ \ + if (the_values[n] < 0 || the_values[n] > UCHAR_MAX) \ + return ncBad_byte; \ + return (ncbyte) the_values[n]; \ +} + +#define as_char_implement(TYPE) \ +char NcVal(TYPE)::as_char( long n ) const \ +{ \ + if (the_values[n] < CHAR_MIN || the_values[n] > CHAR_MAX) \ + return ncBad_char; \ + return (char) the_values[n]; \ +} + +#define as_short_implement(TYPE) \ +short NcVal(TYPE)::as_short( long n ) const \ +{ \ + if (the_values[n] < SHRT_MIN || the_values[n] > SHRT_MAX) \ + return ncBad_short; \ + return (short) the_values[n]; \ +} + +#define NCINT_MIN INT_MIN +#define NCINT_MAX INT_MAX +#define as_int_implement(TYPE) \ +int NcVal(TYPE)::as_int( long n ) const \ +{ \ + if (the_values[n] < NCINT_MIN || the_values[n] > NCINT_MAX) \ + return ncBad_int; \ + return (int) the_values[n]; \ +} + +#define NCLONG_MIN INT_MIN +#define NCLONG_MAX INT_MAX +#define as_nclong_implement(TYPE) \ +nclong NcVal(TYPE)::as_nclong( long n ) const \ +{ \ + if (the_values[n] < NCLONG_MIN || the_values[n] > NCLONG_MAX) \ + return ncBad_nclong; \ + return (nclong) the_values[n]; \ +} + +#define as_long_implement(TYPE) \ +long NcVal(TYPE)::as_long( long n ) const \ +{ \ + if (the_values[n] < LONG_MIN || the_values[n] > LONG_MAX) \ + return ncBad_long; \ + return (long) the_values[n]; \ +} + +#define as_float_implement(TYPE) \ +inline float NcVal(TYPE)::as_float( long n ) const \ +{ \ + return (float) the_values[n]; \ +} + +#define as_double_implement(TYPE) \ +inline double NcVal(TYPE)::as_double( long n ) const \ +{ \ + return (double) the_values[n]; \ +} + +#define as_string_implement(TYPE) \ +char* NcVal(TYPE)::as_string( long n ) const \ +{ \ + char* s = new char[32]; \ + std::ostringstream ostr; \ + ostr << the_values[n]; \ + ostr.str().copy(s, std::string::npos); \ + s[ostr.str().length()] = 0; \ + return s; \ +} + +class MSCPP_EXTRA NcValues // ABC for value blocks +{ + public: + NcValues( void ); + NcValues(NcType, long); + virtual ~NcValues( void ); + virtual long num( void ); + virtual std::ostream& print(std::ostream&) const = 0; + virtual void* base( void ) const = 0; + virtual int bytes_for_one( void ) const = 0; + + // The following member functions provide conversions from the value + // type to a desired basic type. If the value is out of range, the + // default "fill-value" for the appropriate type is returned. + virtual ncbyte as_ncbyte( long n ) const = 0; // nth value as a byte + virtual char as_char( long n ) const = 0; // nth value as char + virtual short as_short( long n ) const = 0; // nth value as short + virtual int as_int( long n ) const = 0; // nth value as int + virtual int as_nclong( long n ) const = 0; // nth value as nclong + virtual long as_long( long n ) const = 0; // nth value as long + virtual float as_float( long n ) const = 0; // nth value as floating-point + virtual double as_double( long n ) const = 0; // nth value as double + virtual char* as_string( long n ) const = 0; // value as string + + protected: + NcType the_type; + long the_number; + friend std::ostream& operator<< (std::ostream&, const NcValues&); +}; + +declare(NcValues,ncbyte) +declare(NcValues,char) +declare(NcValues,short) +declare(NcValues,int) +declare(NcValues,nclong) +declare(NcValues,long) +declare(NcValues,float) +declare(NcValues,double) + +#endif \ No newline at end of file diff --git a/Gui/OpenSG/CMakeLists.txt b/Gui/OpenSG/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..76558c93482bec78e0a0b6cb89bed26b6bdddbb6 --- /dev/null +++ b/Gui/OpenSG/CMakeLists.txt @@ -0,0 +1,25 @@ +# 24/08/2010 LB Initial implementation +# CMake file for OgsOpenSG + +### Source files ### +SET( SOURCES + vtkOsgConverter.cpp +) + +### Header files ### +SET( HEADERS + vtkOsgConverter.h +) + +### Include directories ### +INCLUDE_DIRECTORIES( + ${CMAKE_SOURCE_DIR}/Qt/OpenSG +) + +### Create the library ### +ADD_LIBRARY( OgsOpenSG STATIC + ${SOURCES} + ${HEADERS} +) + +USE_OPENSG(OgsOpenSG) \ No newline at end of file diff --git a/Gui/OpenSG/vtkOsgConverter.cpp b/Gui/OpenSG/vtkOsgConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5078fda13aa6722aac54f97cc51a317dfda496db --- /dev/null +++ b/Gui/OpenSG/vtkOsgConverter.cpp @@ -0,0 +1,954 @@ +/** + * \file vtkOsgConverter.cpp + * 27/07/2011 LB Initial implementation + * + * Implementation of vtkOsgConverter class + */ + +// ** INCLUDES ** +#include "vtkOsgConverter.h" + +#include <vtkActor.h> +#include <vtkCellArray.h> +#include <vtkCellData.h> +#include <vtkCompositeDataGeometryFilter.h> +#include <vtkDataArray.h> +#include <vtkDataSet.h> +#include <vtkDataSetMapper.h> +#include <vtkGeometryFilter.h> +#include <vtkImageData.h> +#include <vtkMapper.h> +#include <vtkPointData.h> +#include <vtkPolyData.h> +#include <vtkPolyDataMapper.h> +#include <vtkProperty.h> +#include <vtkSmartPointer.h> +#include <vtkTexture.h> +#include <vtkUnsignedCharArray.h> +#include <vtkCellDataToPointData.h> +#include <vtkLookupTable.h> +#include <vtkDiscretizableColorTransferFunction.h> + +#include <OpenSG/OSGGeoFunctions.h> +#include <OpenSG/OSGGroup.h> +#include <OpenSG/OSGImage.h> +#include <OpenSG/OSGLineChunk.h> +#include <OpenSG/OSGMaterialChunk.h> +#include <OpenSG/OSGMatrix.h> +#include <OpenSG/OSGPointChunk.h> +#include <OpenSG/OSGPolygonChunk.h> +#include <OpenSG/OSGSimpleGeometry.h> +#include <OpenSG/OSGTwoSidedLightingChunk.h> +#include <OpenSG/OSGTextureChunk.h> +#include <OpenSG/OSGGL.h> + +OSG_USING_NAMESPACE + +vtkOsgConverter::vtkOsgConverter(vtkActor* actor) : + _actor(actor), + _verbose(true), + _osgRoot(NullFC), + _osgTransform(NullFC) +{ + TransformPtr tptr; + _osgRoot = makeCoredNode<osg::Transform>(&tptr); + _osgTransform = tptr; +} + +vtkOsgConverter::~vtkOsgConverter(void) +{ + _osgRoot = NullFC; +} + +bool vtkOsgConverter::WriteAnActor() +{ + vtkMapper* actorMapper = _actor->GetMapper(); + // see if the actor has a mapper. it could be an assembly + if (actorMapper == NULL) + return false; + // dont export when not visible + if (_actor->GetVisibility() == 0) + return false; + + vtkDataObject* inputDO = actorMapper->GetInputDataObject(0, 0); + if (inputDO == NULL) + return false; + + // Get PolyData. Convert if necessary becasue we only want polydata + vtkSmartPointer<vtkPolyData> pd; + if(inputDO->IsA("vtkCompositeDataSet")) + { + vtkCompositeDataGeometryFilter* gf = vtkCompositeDataGeometryFilter::New(); + gf->SetInput(inputDO); + gf->Update(); + pd = gf->GetOutput(); + gf->Delete(); + } + else if(inputDO->GetDataObjectType() != VTK_POLY_DATA) + { + vtkGeometryFilter* gf = vtkGeometryFilter::New(); + gf->SetInput(inputDO); + gf->Update(); + pd = gf->GetOutput(); + gf->Delete(); + } + else + pd = static_cast<vtkPolyData*>(inputDO); + + // Get the color range from actors lookup table + double range[2]; + vtkLookupTable* actorLut = static_cast<vtkLookupTable*>(actorMapper->GetLookupTable()); + actorLut->GetTableRange(range); + + // Copy mapper to a new one + vtkPolyDataMapper* pm = vtkPolyDataMapper::New(); + // Convert cell data to point data + // NOTE: Comment this out to export a mesh + if (actorMapper->GetScalarMode() == VTK_SCALAR_MODE_USE_CELL_DATA || + actorMapper->GetScalarMode() == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA) + { + vtkCellDataToPointData* cellDataToPointData = vtkCellDataToPointData::New(); + cellDataToPointData->PassCellDataOff(); + cellDataToPointData->SetInput(pd); + cellDataToPointData->Update(); + pd = cellDataToPointData->GetPolyDataOutput(); + cellDataToPointData->Delete(); + + pm->SetScalarMode(VTK_SCALAR_MODE_USE_POINT_DATA); + } + else + pm->SetScalarMode(actorMapper->GetScalarMode()); + + pm->SetInput(pd); + pm->SetScalarVisibility(actorMapper->GetScalarVisibility()); + + vtkLookupTable* lut = NULL; + // ParaView OpenSG Exporter + if (dynamic_cast<vtkDiscretizableColorTransferFunction*>(actorMapper->GetLookupTable())) + lut = actorLut; + // Clone the lut in OGS because otherwise the original lut gets destroyed + else + { + lut = vtkLookupTable::New(); + lut->DeepCopy(actorLut); + lut->Build(); + } + pm->SetLookupTable(lut); + pm->SetScalarRange(range); + pm->Update(); + + if(pm->GetScalarMode() == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA || + pm->GetScalarMode() == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA ) + { + if(actorMapper->GetArrayAccessMode() == VTK_GET_ARRAY_BY_ID ) + pm->ColorByArrayComponent(actorMapper->GetArrayId(), + actorMapper->GetArrayComponent()); + else + pm->ColorByArrayComponent(actorMapper->GetArrayName(), + actorMapper->GetArrayComponent()); + } + + + vtkPointData* pntData = pd->GetPointData(); + bool hasTexCoords = false; + vtkUnsignedCharArray* vtkColors = pm->MapScalars(1.0); + + // ARRAY SIZES + vtkIdType m_iNumPoints = pd->GetNumberOfPoints(); + if (m_iNumPoints == 0) + return false; + vtkIdType m_iNumGLPoints = pd->GetVerts()->GetNumberOfCells(); + vtkIdType m_iNumGLLineStrips = pd->GetLines()->GetNumberOfCells(); + vtkIdType m_iNumGLPolygons = pd->GetPolys()->GetNumberOfCells(); + vtkIdType m_iNumGLTriStrips = pd->GetStrips()->GetNumberOfCells(); + vtkIdType m_iNumGLPrimitives = m_iNumGLPoints + m_iNumGLLineStrips + m_iNumGLPolygons + + m_iNumGLTriStrips; + bool lit = !(m_iNumGLPolygons == 0 && m_iNumGLTriStrips == 0); + + if (_verbose) + { + std::cout << "Array sizes:" << std::endl; + std::cout << " number of vertices: " << m_iNumPoints << std::endl; + std::cout << " number of GL_POINTS: " << m_iNumGLPoints << std::endl; + std::cout << " number of GL_LINE_STRIPS: " << m_iNumGLLineStrips << std::endl; + std::cout << " number of GL_POLYGON's: " << m_iNumGLPolygons << std::endl; + std::cout << " number of GL_TRIANGLE_STRIPS: " << m_iNumGLTriStrips << std::endl; + std::cout << " number of primitives: " << m_iNumGLPrimitives << std::endl; + } + + // NORMALS + vtkDataArray* vtkNormals = NULL; + int m_iNormalType = NOT_GIVEN; + if (_actor->GetProperty()->GetInterpolation() == VTK_FLAT) + { + vtkNormals = pd->GetCellData()->GetNormals(); + if (vtkNormals != NULL) + m_iNormalType = PER_CELL; + } + else + { + vtkNormals = pntData->GetNormals(); + if (vtkNormals != NULL) + m_iNormalType = PER_VERTEX; + } + if (_verbose) + { + std::cout << "Normals:" << std::endl; + if (m_iNormalType != NOT_GIVEN) + { + std::cout << " number of normals: " << vtkNormals->GetNumberOfTuples() << + std::endl; + std::cout << " normals are given: "; + std::cout << + ((m_iNormalType == PER_VERTEX) ? "per vertex" : "per cell") << std::endl; + } + else + std::cout << " no normals are given" << std::endl; + } + + // COLORS + int m_iColorType = NOT_GIVEN; + if(pm->GetScalarVisibility()) + { + int iScalarMode = pm->GetScalarMode(); + if(vtkColors == NULL) + { + m_iColorType = NOT_GIVEN; + std::cout << "WARNING: MapScalars(1.0) did not return array!" << std::endl; + } + else if(iScalarMode == VTK_SCALAR_MODE_USE_CELL_DATA) + m_iColorType = PER_CELL; + else if(iScalarMode == VTK_SCALAR_MODE_USE_POINT_DATA) + m_iColorType = PER_VERTEX; + else if(iScalarMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA) + { + std::cout << + "WARNING TO BE REMOVED: Can not process colours with scalar mode using cell field data!" + << std::endl; + m_iColorType = PER_CELL; + } + else if(iScalarMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA) + { + std::cout << + "WARNING TO BE REMOVED: Can not process colours with scalar mode using point field data!" + << std::endl; + m_iColorType = PER_VERTEX; + } + else if(iScalarMode == VTK_SCALAR_MODE_DEFAULT) + { + //Bummer, we do not know what it is. may be we can make a guess + int numColors = vtkColors->GetNumberOfTuples(); + if (numColors == 0) + { + m_iColorType = NOT_GIVEN; + std::cout << "WARNING: No colors found!" << std::endl; + } + else if (numColors == m_iNumPoints) + m_iColorType = PER_VERTEX; + else if (numColors == m_iNumGLPrimitives) + m_iColorType = PER_CELL; + else + { + m_iColorType = NOT_GIVEN; + std::cout << + "WARNING: Number of colors do not match number of points / cells!" + << std::endl; + } + } + } + if (_verbose) + { + std::cout << "Colors:" << std::endl; + if (m_iColorType != NOT_GIVEN) + { + std::cout << " number of colors: " << vtkColors->GetNumberOfTuples() << + std::endl; + std::cout << " colors are given: " << + ((m_iColorType == PER_VERTEX) ? "per vertex" : "per cell") << std::endl; + } + else + std::cout << " no colors are given" << std::endl; + } + + // TEXCOORDS + vtkDataArray* vtkTexCoords = pntData->GetTCoords(); + if (_verbose) + { + std::cout << "Tex-coords:" << std::endl; + if (vtkTexCoords) + { + std::cout << " Number of tex-coords: " << + vtkTexCoords->GetNumberOfTuples() << std::endl; + hasTexCoords = true; + } + else + std::cout << " No tex-coords where given" << std::endl; + } + + // TRANSFORMATION + double scaling[3]; + double translation[3]; + // double rotation[3]; + + _actor->GetPosition(translation); + _actor->GetScale(scaling); + //_actor->GetRotation(rotation[0], rotation[1], rotation[2]); + + if (_verbose) + std::cout << "set scaling: " << scaling[0] << " " << scaling[1] << " " << + scaling[2] << std::endl; + + osg::Matrix m; + m.setIdentity(); + m.setTranslate(translation[0], translation[1], translation[2]); + m.setScale(scaling[0], scaling[1], scaling[2]); + // TODO QUATERNION m.setRotate(rotation[0], rotation[1], rotation[2]) + beginEditCP(_osgTransform); + _osgTransform->setMatrix(m); + endEditCP(_osgTransform); + + //pm->Update(); + + // Get the converted OpenSG node + NodePtr osgGeomNode = Node::create(); + GeometryPtr osgGeometry = Geometry::create(); + beginEditCP(osgGeomNode); + osgGeomNode->setCore(osgGeometry); + endEditCP(osgGeomNode); + + bool osgConversionSuccess = false; + + GeoPTypesPtr osgTypes = GeoPTypesUI8::create(); + GeoPLengthsPtr osgLengths = GeoPLengthsUI32::create(); + GeoIndicesUI32Ptr osgIndices = GeoIndicesUI32::create(); + GeoPositions3fPtr osgPoints = GeoPositions3f::create(); + GeoNormals3fPtr osgNormals = GeoNormals3f::create(); + GeoColors3fPtr osgColors = GeoColors3f::create(); + GeoTexCoords2dPtr osgTexCoords = GeoTexCoords2d::create(); + + //Rendering with OpenSG simple indexed geometry + if (((m_iNormalType == PER_VERTEX) || (m_iNormalType == NOT_GIVEN)) && + ((m_iColorType == PER_VERTEX) || (m_iColorType == NOT_GIVEN))) + { + if (_verbose) + std::cout << "Start ProcessGeometryNormalsAndColorsPerVertex()" << std::endl; + + //getting the vertices: + beginEditCP(osgPoints); + { + for (int i = 0; i < m_iNumPoints; i++) + { + double* aVertex = pd->GetPoint(i); + osgPoints->addValue(Vec3f(aVertex[0], aVertex[1], aVertex[2])); + } + } endEditCP(osgPoints); + + //possibly getting the normals + if (m_iNormalType == PER_VERTEX) + { + vtkIdType iNumNormals = vtkNormals->GetNumberOfTuples(); + beginEditCP(osgNormals); + { + double* aNormal; + for (int i = 0; i < iNumNormals; i++) + { + aNormal = vtkNormals->GetTuple(i); + osgNormals->addValue(Vec3f(aNormal[0], aNormal[1], aNormal[2])); + } + } endEditCP(osgNormals); + if (iNumNormals != m_iNumPoints) + { + std::cout << + "WARNING: CVtkActorToOpenSG::ProcessGeometryNormalsAndColorsPerVertex() number of normals" + << std::endl; + std::cout << "should equal the number of vertices (points)!" << std::endl << std::endl; + } + } + + //possibly getting the colors + if (m_iColorType == PER_VERTEX) + { + vtkIdType iNumColors = vtkColors->GetNumberOfTuples(); + beginEditCP(osgColors); + { + unsigned char aColor[4]; + for (int i = 0; i < iNumColors; i++) + { + vtkColors->GetTupleValue(i, aColor); + float r = ((float) aColor[0]) / 255.0f; + float g = ((float) aColor[1]) / 255.0f; + float b = ((float) aColor[2]) / 255.0f; + osgColors->addValue(Color3f(r, g, b)); + } + } endEditCP(osgColors); + if (iNumColors != m_iNumPoints) + { + std::cout << + "WARNING: CVtkActorToOpenSG::ProcessGeometryNormalsAndColorsPerVertex() number of colors" + << std::endl; + std::cout << "should equal the number of vertices (points)!" << std::endl << std::endl; + } + } + + //possibly getting the texture coordinates. These are alwary per vertex + if (vtkTexCoords != NULL) + { + int numTuples = vtkTexCoords->GetNumberOfTuples(); + for (int i = 0; i < numTuples; i++) + { + double texCoords[3]; + vtkTexCoords->GetTuple(i, texCoords); + osgTexCoords->addValue(Vec2f(texCoords[0], texCoords[1])); + } + } + + //getting the cells + beginEditCP(osgTypes); + beginEditCP(osgLengths); + beginEditCP(osgIndices); + { + vtkCellArray* pCells; + vtkIdType npts, * pts; + int prim; + + prim = 0; + pCells = pd->GetVerts(); + if (pCells->GetNumberOfCells() > 0) + for (pCells->InitTraversal(); pCells->GetNextCell(npts, pts); + prim++) + { + osgLengths->addValue(npts); + osgTypes->addValue(GL_POINTS); + for (int i = 0; i < npts; i++) + osgIndices->addValue(pts[i]); + } + + prim = 0; + pCells = pd->GetLines(); + if (pCells->GetNumberOfCells() > 0) + for (pCells->InitTraversal(); pCells->GetNextCell(npts, pts); + prim++) + { + osgLengths->addValue(npts); + osgTypes->addValue(GL_LINE_STRIP); + for (int i = 0; i < npts; i++) + osgIndices->addValue(pts[i]); + } + + prim = 0; + pCells = pd->GetPolys(); + if (pCells->GetNumberOfCells() > 0) + for (pCells->InitTraversal(); pCells->GetNextCell(npts, pts); + prim++) + { + osgLengths->addValue(npts); + osgTypes->addValue(GL_POLYGON); + for (int i = 0; i < npts; i++) + osgIndices->addValue(pts[i]); + } + + prim = 0; + pCells = pd->GetStrips(); + if (pCells->GetNumberOfCells() > 0) + for (pCells->InitTraversal(); pCells->GetNextCell(npts, pts); prim++) + { + osgLengths->addValue(npts); + osgTypes->addValue(GL_TRIANGLE_STRIP); + for (int i = 0; i < npts; i++) + osgIndices->addValue(pts[i]); + } + } endEditCP(osgIndices); + endEditCP(osgLengths); + endEditCP(osgTypes); + + ChunkMaterialPtr material = CreateMaterial(lit, hasTexCoords); + beginEditCP(osgGeometry); + { + osgGeometry->setPositions(osgPoints); + osgGeometry->setTypes(osgTypes); + osgGeometry->setLengths(osgLengths); + osgGeometry->setIndices(osgIndices); + osgGeometry->setMaterial(material); + + if (m_iNormalType == PER_VERTEX) + osgGeometry->setNormals(osgNormals); + if (m_iColorType == PER_VERTEX) + osgGeometry->setColors(osgColors); + if (osgTexCoords->getSize() > 0) + osgGeometry->setTexCoords(osgTexCoords); + } endEditCP(osgGeometry); + + osgConversionSuccess = true; + + if (_verbose) + std::cout << " End ProcessGeometryNormalsAndColorsPerVertex()" << + std::endl; + } + else + { + //Rendering with OpenSG non indexed geometry by copying a lot of attribute data + if (_verbose) + std::cout << + "Start ProcessGeometryNonIndexedCopyAttributes(int gl_primitive_type)" << + std::endl; + int gl_primitive_type = -1; + if(m_iNumGLPolygons > 0) + { + if(m_iNumGLPolygons != m_iNumGLPrimitives) + std::cout << "WARNING: vtkActor contains different kind of primitives" << std::endl; + gl_primitive_type = GL_POLYGON; + //osgConversionSuccess = this->ProcessGeometryNonIndexedCopyAttributes(GL_POLYGON, pd, osgGeometry); + } + else if(m_iNumGLLineStrips > 0) + { + if (m_iNumGLLineStrips != m_iNumGLPrimitives) + std::cout << "WARNING: vtkActor contains different kind of primitives" << std::endl; + gl_primitive_type = GL_LINE_STRIP; + //osgConversionSuccess = this->ProcessGeometryNonIndexedCopyAttributes(GL_LINE_STRIP, pd osgGeometry); + } + else if(m_iNumGLTriStrips > 0) + { + if (m_iNumGLTriStrips != m_iNumGLPrimitives) + std::cout << "WARNING: vtkActor contains different kind of primitives" << std::endl; + gl_primitive_type = GL_TRIANGLE_STRIP; + //osgConversionSuccess = this->ProcessGeometryNonIndexedCopyAttributes(GL_TRIANGLE_STRIP, pd osgGeometry); + } + else if (m_iNumGLPoints > 0) + { + if (m_iNumGLPoints != m_iNumGLPrimitives) + std::cout << "WARNING: vtkActor contains different kind of primitives" << std::endl; + gl_primitive_type = GL_POINTS; + //osgConversionSuccess = this->ProcessGeometryNonIndexedCopyAttributes(GL_POINTS, pd osgGeometry); + } + if(gl_primitive_type != -1) + { + vtkCellArray* pCells; + if (gl_primitive_type == GL_POINTS) + pCells = pd->GetVerts(); + else if (gl_primitive_type == GL_LINE_STRIP) + pCells = pd->GetLines(); + else if (gl_primitive_type == GL_POLYGON) + pCells = pd->GetPolys(); + else if (gl_primitive_type == GL_TRIANGLE_STRIP) + pCells = pd->GetStrips(); + else + { + std::cout << + "CVtkActorToOpenSG::ProcessGeometryNonIndexedCopyAttributes(int gl_primitive_type)" + << std::endl << " was called with non implemented gl_primitive_type!" << std::endl; + } + + beginEditCP(osgTypes); + beginEditCP(osgLengths); + beginEditCP(osgPoints); + beginEditCP(osgColors); + beginEditCP(osgNormals); + { + int prim = 0; + if (pCells->GetNumberOfCells() > 0) + { + vtkIdType npts, * pts; + for (pCells->InitTraversal(); pCells->GetNextCell(npts, pts); + prim++) + { + osgLengths->addValue(npts); + osgTypes->addValue(GL_POLYGON); + for (int i = 0; i < npts; i++) + { + double* aVertex; + double* aNormal; + unsigned char aColor[4]; + + aVertex = pd->GetPoint(pts[i]); + osgPoints->addValue(Vec3f(aVertex[0], aVertex[1], aVertex[2])); + + if (m_iNormalType == PER_VERTEX) + { + aNormal = + vtkNormals->GetTuple(pts[i]); + osgNormals->addValue(Vec3f(aNormal[0], aNormal[1], aNormal[2])); + } + else if (m_iNormalType == PER_CELL) + { + aNormal = vtkNormals->GetTuple(prim); + osgNormals->addValue(Vec3f(aNormal[0], aNormal[1], aNormal[2])); + } + + if (m_iColorType == PER_VERTEX) + { + vtkColors->GetTupleValue(pts[i], aColor); + float r = ((float) aColor[0]) / 255.0f; + float g = ((float) aColor[1]) / 255.0f; + float b = ((float) aColor[2]) / 255.0f; + osgColors->addValue(Color3f(r, g, b)); + } + else if (m_iColorType == PER_CELL) + { + vtkColors->GetTupleValue(prim, + aColor); + float r = ((float) aColor[0]) / 255.0f; + float g = ((float) aColor[1]) / 255.0f; + float b = ((float) aColor[2]) / 255.0f; + osgColors->addValue(Color3f(r, g, b)); + } + } + } + } + } endEditCP(osgTypes); + endEditCP(osgLengths); + endEditCP(osgPoints); + endEditCP(osgColors); + endEditCP(osgNormals); + + //possibly getting the texture coordinates. These are always per vertex + vtkPoints* points = pd->GetPoints(); + if ((vtkTexCoords != NULL) && (points != NULL)) + { + int numPoints = points->GetNumberOfPoints(); + int numTexCoords = vtkTexCoords->GetNumberOfTuples(); + if (numPoints == numTexCoords) + { + beginEditCP(osgTexCoords); + { + int numTuples = vtkTexCoords->GetNumberOfTuples(); + for (int i = 0; i < numTuples; i++) + { + double texCoords[3]; + vtkTexCoords->GetTuple(i, texCoords); + osgTexCoords->addValue(Vec2f(texCoords[0], texCoords[1])); + } + } endEditCP(osgTexCoords); + } + } + + ChunkMaterialPtr material = CreateMaterial(lit, hasTexCoords); + //GeometryPtr geo = Geometry::create(); + beginEditCP(osgGeometry); + { + osgGeometry->setPositions(osgPoints); + osgGeometry->setTypes(osgTypes); + osgGeometry->setLengths(osgLengths); + osgGeometry->setMaterial(material); + + if (m_iNormalType != NOT_GIVEN) + osgGeometry->setNormals(osgNormals); + if (m_iColorType != NOT_GIVEN) + osgGeometry->setColors(osgColors); + if (osgTexCoords->getSize() > 0) + osgGeometry->setTexCoords(osgTexCoords); + //geo->setMaterial(getDefaultMaterial()); + } endEditCP(osgGeometry); + + osgConversionSuccess = true; + } + if (_verbose) + std::cout << + " End ProcessGeometryNonIndexedCopyAttributes(int gl_primitive_type)" << + std::endl; + } + + if(!osgConversionSuccess) + { + std::cout << "OpenSG converter was not able to convert this actor." << std::endl; + return false; + } + + if(m_iNormalType == NOT_GIVEN) + { + //GeometryPtr newGeometryPtr = GeometryPtr::dcast(newNodePtr->getCore()); + if((osgGeometry != NullFC) && (m_iColorType == PER_VERTEX)) + { + std::cout << + "WARNING: Normals are missing in the vtk layer, calculating normals per vertex!" + << std::endl; + calcVertexNormals(osgGeometry); + } + else if ((osgGeometry != NullFC) && (m_iColorType == PER_CELL)) + { + std::cout << + "WARNING: Normals are missing in the vtk layer, calculating normals per face!" + << std::endl; + calcFaceNormals(osgGeometry); + } + else if (osgGeometry != NullFC) + { + std::cout << + "WARNING: Normals are missing in the vtk layer, calculating normals per vertex!" + << std::endl; + calcVertexNormals(osgGeometry); + } + } + + std::cout << "Conversion finished." << std::endl; + + // Add node to root + beginEditCP(_osgRoot); + _osgRoot->addChild(osgGeomNode); + endEditCP(_osgRoot); + + pm->Delete(); + + return true; +} + +void vtkOsgConverter::SetVerbose(bool value) +{ + _verbose = value; +} + +NodePtr vtkOsgConverter::GetOsgNode() +{ + return _osgRoot; +} + +TextureChunkPtr vtkOsgConverter::CreateTexture(vtkTexture* vtkTexture) +{ + if(_verbose) + std::cout << "Calling CreateTexture()" << std::endl; + + // if(! m_bTextureHasChanged) + // { + // if (_verbose) + // { + // std::cout << " ... nothing to do" << std::endl; + // std::cout << " End CreateTexture()" << std::endl; + // } + // //can we check if the actual image has been updated, even if the texture is the same? + // return; + // } + // else if(m_pvtkTexture == NULL) + // { + // if (_verbose) + // { + // std::cout << " ... texture is (still ?) NULL" << std::endl; + // std::cout << " EndCreateTexture()" << std::endl; + // } + // //the texture has changed but it is NULL now. We should remove the texture from the material + // return; + // } + // m_bTextureHasChanged = false; + + vtkImageData* imgData = vtkTexture->GetInput(); + int iImgDims[3]; + imgData->GetDimensions(iImgDims); + + vtkPointData* imgPointData = imgData->GetPointData(); + vtkCellData* imgCellData = imgData->GetCellData(); + + vtkDataArray* data = NULL; + + if (imgPointData != NULL) + if (NULL != imgPointData->GetScalars()) + { + data = imgPointData->GetScalars(); + if (_verbose) + std::cout << " Found texture data in point data" << std::endl; + } + + if (imgCellData != NULL) + if (NULL != imgCellData->GetScalars()) + { + data = imgCellData->GetScalars(); + if (_verbose) + std::cout << " Found texture data in cell data" << std::endl; + } + + if (data == NULL) + { + std::cout << " could not load texture data" << std::endl; + return NullFC; + } + + int iImgComps = data->GetNumberOfComponents(); + int iImgPixels = data->GetNumberOfTuples(); + if (iImgPixels != (iImgDims[0] * iImgDims[1] * iImgDims[2])) + { + std::cout << "Number of pixels in data array seems to be wrong!" << std::endl; + return NullFC; + } + + UInt8* newImageData = new UInt8[iImgDims[0] * iImgDims[1] * iImgDims[2] * iImgComps]; + vtkUnsignedCharArray* oldImageUChar = NULL; + oldImageUChar = dynamic_cast<vtkUnsignedCharArray*>(data); + int ucharCounter = 0; + if (oldImageUChar != NULL) + for (int i = 0; i < iImgPixels; i++) + { + unsigned char pixel[4]; + oldImageUChar->GetTupleValue(i, pixel); + for (int j = 0; j < iImgComps; j++) + newImageData[ucharCounter + j] = pixel[j]; + ucharCounter += iImgComps; + } + else + std::cout << "Pixel data come in unsupported vtk type" << std::endl; + + ImagePtr osgImage = Image::create(); + beginEditCP(osgImage); + { + osgImage->setWidth(iImgDims[0]); + osgImage->setHeight(iImgDims[1]); + osgImage->setDepth(iImgDims[2]); + osgImage->setDataType(Image::OSG_UINT8_IMAGEDATA); + if (iImgComps == 1) + osgImage->setPixelFormat(Image::OSG_L_PF); + else if (iImgComps == 2) + osgImage->setPixelFormat(Image::OSG_LA_PF); + else if (iImgComps == 3) + osgImage->setPixelFormat(Image::OSG_RGB_PF); + else if (iImgComps == 4) + osgImage->setPixelFormat(Image::OSG_RGBA_PF); + else + { + std::cout << "Unsupported image type!" << std::endl; + delete [] newImageData; + return NullFC; + } + osgImage->setData(newImageData); + } endEditCP(osgImage); + + TextureChunkPtr osgTextureChunk = TextureChunk::create(); + beginEditCP(osgTextureChunk); + { + osgTextureChunk->setImage(osgImage); + } endEditCP(osgTextureChunk); + + if (_verbose) + { + std::cout << " Loading image with " << iImgDims[0] << " x " << iImgDims[1] << + " x " << iImgDims[2] << " pixels." << std::endl; + std::cout << " Components: " << iImgComps << std::endl; + std::cout << "End CreateTexture()" << std::endl; + } + + return osgTextureChunk; +} + +ChunkMaterialPtr vtkOsgConverter::CreateMaterial(bool lit, bool hasTexCoords) +{ + if (_verbose) + std::cout << "Start CreateMaterial()" << std::endl; + + vtkProperty* prop = _actor->GetProperty(); + double* diffuseColor = prop->GetDiffuseColor(); + double* ambientColor = prop->GetAmbientColor(); + double* specularColor = prop->GetSpecularColor(); + double specularPower = prop->GetSpecularPower(); + + double diffuse = prop->GetDiffuse(); + double ambient = prop->GetAmbient(); + double specular = prop->GetSpecular(); + double opacity = prop->GetOpacity(); + + float pointSize = prop->GetPointSize(); + float lineWidth = prop->GetLineWidth(); + // int lineStipplePattern = prop->GetLineStipplePattern(); + + int representation = prop->GetRepresentation(); + + if (_verbose) + { + std::cout << " Colors:" << std::endl; + std::cout << " diffuse " << diffuse << " * " << diffuseColor[0] << " " << + diffuseColor[1] << " " << diffuseColor[2] << std::endl; + std::cout << " ambient " << ambient << " * " << ambientColor[0] << " " << + ambientColor[1] << " " << ambientColor[2] << std::endl; + std::cout << " specular " << specular << " * " << specularColor[0] << " " << + specularColor[1] << " " << specularColor[2] << std::endl; + } + + PolygonChunkPtr polygonChunk = PolygonChunk::create(); + beginEditCP(polygonChunk); + { + if (representation == VTK_SURFACE) + { + polygonChunk->setFrontMode(GL_FILL); + polygonChunk->setBackMode(GL_FILL); + } + else if (representation == VTK_WIREFRAME) + { + polygonChunk->setFrontMode(GL_LINE); + polygonChunk->setBackMode(GL_LINE); + } + else + { + polygonChunk->setFrontMode(GL_POINT); + polygonChunk->setBackMode(GL_POINT); + } + } endEditCP(polygonChunk); + + MaterialChunkPtr osgMaterialChunk = MaterialChunk::create(); + beginEditCP(osgMaterialChunk); + { + osgMaterialChunk->setDiffuse(Color4f(diffuseColor[0] * diffuse, diffuseColor[1] * + diffuse, diffuseColor[2] * diffuse, opacity)); + osgMaterialChunk->setSpecular(Color4f(specularColor[0] * specular, + specularColor[1] * specular, + specularColor[2] * specular, 1.0)); + osgMaterialChunk->setAmbient(Color4f(ambientColor[0] * ambient, ambientColor[1] * + ambient, ambientColor[2] * ambient, opacity)); + osgMaterialChunk->setShininess(specularPower); + + //if(opacity < 1.0) + //{ + // osgMaterialChunk->setColorMaterial(GL_AMBIENT); // HACK: Opacity does not work with GL_AMBIENT_AND_DIFFUSE + //osgMaterialChunk->setTransparency(1.0f - opacity); + //} + //else + osgMaterialChunk->setColorMaterial(GL_AMBIENT_AND_DIFFUSE); + + // On objects consisting only of points or lines, dont lit + if(!lit) + osgMaterialChunk->setLit(false); + } endEditCP(osgMaterialChunk); + + ChunkMaterialPtr osgChunkMaterial = ChunkMaterial::create(); + beginEditCP(osgChunkMaterial); + { + osgChunkMaterial->addChunk(osgMaterialChunk); + osgChunkMaterial->addChunk(TwoSidedLightingChunk::create()); + osgChunkMaterial->addChunk(polygonChunk); + + if(pointSize > 1.0f) + { + PointChunkPtr pointChunk = PointChunk::create(); + pointChunk->setSize(pointSize); + osgChunkMaterial->addChunk(pointChunk); + } + + if(lineWidth > 1.0f) + { + LineChunkPtr lineChunk = LineChunk::create(); + lineChunk->setWidth(lineWidth); + osgChunkMaterial->addChunk(lineChunk); + } + + // TEXTURE + if (hasTexCoords) + { + vtkTexture* vtkTexture = _actor->GetTexture(); + if (vtkTexture) + { + TextureChunkPtr osgTextureChunk = NullFC; + osgTextureChunk = CreateTexture(vtkTexture); + + if(osgTextureChunk != NullFC) + { + if (_verbose) + std::cout << " Add TextureChunk" << std::endl; + osgChunkMaterial->addChunk(osgTextureChunk); + } + + // Per default EnvMode is set to GL_REPLACE which does not lit the surface + beginEditCP(osgTextureChunk); + osgTextureChunk->setEnvMode(GL_MODULATE); + endEditCP(osgTextureChunk); + } + } + } endEditCP(osgChunkMaterial); + + if (_verbose) + std::cout << "End CreateMaterial()" << std::endl; + + return osgChunkMaterial; +} diff --git a/Gui/OpenSG/vtkOsgConverter.h b/Gui/OpenSG/vtkOsgConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..a5f06c0bcbd77eaae927cb8dca730f3f9cd48fbe --- /dev/null +++ b/Gui/OpenSG/vtkOsgConverter.h @@ -0,0 +1,58 @@ +/** + * \file vtkOsgConverter.h + * 27/07/2011 LB Initial implementation + * Derived from class vtkOsgActor from Bjoern Zehner + */ + +#ifndef VTKOSGCONVERTER_H +#define VTKOSGCONVERTER_H + +#include <OpenSG/OSGChunkMaterial.h> +#include <OpenSG/OSGNode.h> +#include <OpenSG/OSGRefPtr.h> +#include <OpenSG/OSGTextureChunk.h> +#include <OpenSG/OSGTransform.h> + +class vtkActor; +class vtkMapper; +class vtkTexture; + +/// @brief Converts a vtkActor to an OpenSG-Node. +/// Example usage: +/// +/// @code +/// vtkOsgConverter* osgConverter = new vtkOsgConverter(aVtkActor); +/// if(osgConverter->WriteAnActor()) +/// { +/// beginEditCP(rootNode); +/// rootNode->addChild(osgConverter->GetOsgNode()); +/// endEditCP(rootNode); +/// } +/// @endcode +class vtkOsgConverter +{ +public: + vtkOsgConverter(vtkActor* actor); + virtual ~vtkOsgConverter(); + + bool WriteAnActor(); + void SetVerbose(bool value); + OSG::NodePtr GetOsgNode(); + +protected: + +private: + vtkActor* _actor; + + enum {NOT_GIVEN, PER_VERTEX, PER_CELL}; + bool _verbose; + + //For the translation to OpenSG + OSG::RefPtr<OSG::NodePtr> _osgRoot; + OSG::RefPtr<OSG::TransformPtr> _osgTransform; + + OSG::TextureChunkPtr CreateTexture(vtkTexture* vtkTexture); + OSG::ChunkMaterialPtr CreateMaterial(bool lit, bool hasTexCoords); +}; + +#endif // VTKOSGCONVERTER_H \ No newline at end of file diff --git a/Gui/Vrpn/CMakeLists.txt b/Gui/Vrpn/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa5cdcf8abd2bacc7ecf57247d4219d80f48b5a8 --- /dev/null +++ b/Gui/Vrpn/CMakeLists.txt @@ -0,0 +1,62 @@ +# 24/08/2010 LB Initial implementation +# CMake file for OgsVrpn + +### Source files ### +SET( SOURCES + VrpnClient.cpp + SpaceNavigatorClient.cpp + QSpaceNavigatorClient.cpp + VrpnArtTrackingClient.cpp + QVrpnArtTrackingClient.cpp + TrackingSettingsWidget.cpp +) + +### Moc header files ### +SET( MOC_HEADERS + VrpnClient.h + QSpaceNavigatorClient.h + QVrpnArtTrackingClient.h + TrackingSettingsWidget.h +) + +### UI files ### +SET( UIS + TrackingSettingsWidgetBase.ui +) + +### Header files ### +SET( HEADERS + SpaceNavigatorClient.h + VrpnArtTrackingClient.h +) + +### Qt precompiler ### +QT4_WRAP_UI( UI_HEADERS ${UIS} ) +Qt4_WRAP_CPP( MOC_SOURCES ${MOC_HEADERS} ) + +### Include directories ### +INCLUDE_DIRECTORIES( + ${CMAKE_SOURCE_DIR}/Qt/Vrpn + ${CMAKE_BINARY_DIR}/Qt/Vrpn + ${VRPN_INCLUDE_DIRS} + ${CMAKE_SOURCE_DIR}/Qt/VtkVis + ${CMAKE_BINARY_DIR}/Qt/VtkVis +) + +# Put moc files in a project folder +SOURCE_GROUP("UI Files" REGULAR_EXPRESSION "\\w*\\.ui") +SOURCE_GROUP("Moc Files" REGULAR_EXPRESSION "moc_.*") + +### Create the library ### +ADD_LIBRARY( OgsVrpn STATIC + ${SOURCES} + ${HEADERS} + ${MOC_HEADERS} + ${MOC_SOURCES} + ${UIS} +) + +### Link other libraries ### +#TARGET_LINK_LIBRARIES( OgsVrpn +# ${QT_LIBRARIES} +#) diff --git a/Gui/Vrpn/QSpaceNavigatorClient.cpp b/Gui/Vrpn/QSpaceNavigatorClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b62ecbc994892e2458918da5dffdd9984ef26f81 --- /dev/null +++ b/Gui/Vrpn/QSpaceNavigatorClient.cpp @@ -0,0 +1,58 @@ +/** + * \file QSpaceNavigatorClient.cpp + * 31/08/2010 LB Initial implementation + * + * Implementation of QSpaceNavigatorClient class + */ + +// ** INCLUDES ** +#include "QSpaceNavigatorClient.h" + +QSpaceNavigatorClient* QSpaceNavigatorClient::_singleton = 0; + +QSpaceNavigatorClient::QSpaceNavigatorClient(QObject* parent /*= NULL*/) + : QObject(parent), SpaceNavigatorClient() +{ + //SpaceNavigatorClient::Instance(); + _time.start(); + _timer = new QTimer(this); + connect( _timer, SIGNAL(timeout()), this, SLOT(update()) ); +} + +QSpaceNavigatorClient::~QSpaceNavigatorClient() +{ +} + +QSpaceNavigatorClient* QSpaceNavigatorClient::Instance(QObject* parent /*= NULL*/) +{ + if(_singleton == 0) + _singleton = new QSpaceNavigatorClient(parent); + return _singleton; +} + +void QSpaceNavigatorClient::init(const char* deviceName, + int updateInterval /*= 100*/, SpaceNavigatorAxes axis /*= Y*/) +{ + SpaceNavigatorClient::init(deviceName, axis); + if (updateInterval > 0) + _timer->start(updateInterval); +} + +void QSpaceNavigatorClient::update() +{ + SpaceNavigatorClient::update(); + if (_unconsumedData) + { + _unconsumedData = false; + double x, y, z, rx, ry, rz; + getTranslation(x, y, z); + getRotation(rx, ry, rz); + //emit updated(x, y, z, rx, ry, rz); + emit translated(x, y, z); + } +} + +int QSpaceNavigatorClient::getFrameTime() +{ + return _time.restart(); +} \ No newline at end of file diff --git a/Gui/Vrpn/QSpaceNavigatorClient.h b/Gui/Vrpn/QSpaceNavigatorClient.h new file mode 100644 index 0000000000000000000000000000000000000000..20ede3f9c6f9216b72b9a8b161090f8600f7ab17 --- /dev/null +++ b/Gui/Vrpn/QSpaceNavigatorClient.h @@ -0,0 +1,70 @@ +/** + * \file QSpaceNavigatorClient.h + * 31/08/2010 LB Initial implementation + */ + +#ifndef QSPACENAVIGATORCLIENT_H +#define QSPACENAVIGATORCLIENT_H + +#include "SpaceNavigatorClient.h" +#include <QObject> +#include <QTime> +#include <QTimer> + +/// @brief Is a qt specific implementation of SpaceNavigatorClient. +class QSpaceNavigatorClient : public QObject, public SpaceNavigatorClient +{ + Q_OBJECT + +public: + /// @brief Returns the singleton of this class + static QSpaceNavigatorClient* Instance(QObject* parent = NULL); + + /// @brief Initializes the SpaceNavigator. + /// Connects with the server and registers the callback handlers. + /// It is possible to specify the z-axis as the up-axis. + /// Default the y-axis is the up-axis. + /// @param deviceName Example: "SpaceNav@viswork01.intern.ufz.de" + /// @param updateInterval The update interval in ms. If 0 then you have to + /// manually call update(). + /// @param axis The up axis. + void init(const char* deviceName, int updateInterval = 100, SpaceNavigatorAxes axis = Y); + +public slots: + /// @brief Calls the SpaceNavigatorClient::update() method and emits updated() + /// and translated() signals if there is new data. + /// Is called automatically if an updateInterval was given in init(). + void update(); + +protected: + /// @brief The constructor is protected because of the singleton + /// design pattern. + QSpaceNavigatorClient(QObject* parent = NULL); + + /// @brief Destructor. + virtual ~QSpaceNavigatorClient(); + + /// @brief Returns the elapsed time since the last function call in ms. + int getFrameTime(); + +private: + /// Used in getFrameTime() to compute the elapsed time since last call. + QTime _time; + + /// Calls update(), see init(). + QTimer* _timer; + + /// @brief This one points to the class itself. + /// You can use only one QSpaceNavigatorClient because it´s static. + /// This is needed for the callback methods which only + /// can access static members. + static QSpaceNavigatorClient* _singleton; + +signals: + void updated(double x, double y, double z, double rx, double ry, double rz); + + /// Is emitted when there is new translation data. + void translated(double x, double y, double z); +}; + +#endif // QSPACENAVIGATORCLIENT_H diff --git a/Gui/Vrpn/QVrpnArtTrackingClient.cpp b/Gui/Vrpn/QVrpnArtTrackingClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a6a3eb83c9006b5dc8f5cb96be81c6b04411af5c --- /dev/null +++ b/Gui/Vrpn/QVrpnArtTrackingClient.cpp @@ -0,0 +1,80 @@ +/** + * \file QVrpnArtTrackingClient.cpp + * 03/09/2010 LB Initial implementation + * + * Implementation of QVrpnArtTrackingClient class + */ + +// ** INCLUDES ** +#include "QVrpnArtTrackingClient.h" + +#include <iostream> + +#include <QSettings> +#include <QString> +#include <QStringList> + +QVrpnArtTrackingClient* QVrpnArtTrackingClient::_singleton = 0; + +QVrpnArtTrackingClient::QVrpnArtTrackingClient(QObject* parent /*= NULL*/) + : QObject(parent), VrpnArtTrackingClient() +{ + //SpaceNavigatorClient::Instance(); + _timer = new QTimer(this); + connect( _timer, SIGNAL(timeout()), this, SLOT(MainLoop()) ); +} + +QVrpnArtTrackingClient::~QVrpnArtTrackingClient() +{ + QStringList list = _deviceName.split("@"); + + QSettings settings("UFZ", "OpenGeoSys-5"); + settings.beginGroup("Tracking"); + settings.setValue("artDeviceName", list.at(0)); + settings.setValue("artDeviceNameAt", list.at(1)); + settings.setValue("artUpdateInterval", _updateInterval); + settings.endGroup(); + + delete _timer; +} + +QVrpnArtTrackingClient* QVrpnArtTrackingClient::Instance(QObject* parent /*= NULL*/) +{ + if(_singleton == 0) + _singleton = new QVrpnArtTrackingClient(parent); + return _singleton; +} + +void QVrpnArtTrackingClient::StartTracking(const char* deviceName, + int updateInterval /*= 100*/) +{ + _deviceName = QString(deviceName); + _updateInterval = updateInterval; + VrpnArtTrackingClient::StartTracking(deviceName); + std::cout << "Tracking started." << std::endl; + if (updateInterval > 0) + _timer->start(updateInterval); +} + +void QVrpnArtTrackingClient::MainLoop() +{ + VrpnArtTrackingClient::MainLoop(); + + double x, y, z; + VrpnArtTrackingClient::GetBodyTranslation(x, y, z); + //std::cout << "Body: " << x << " " << y << " " << z << std::endl; + //std::cout << "Body: " << m_dBodyTranslation[0] << " " << m_dBodyTranslation[1] << " " << m_dBodyTranslation[2] << std::endl; + emit positionUpdated(x, z, y); + + /* + if (_unconsumedData) + { + _unconsumedData = false; + double x, y, z, rx, ry, rz; + getTranslation(x, y, z); + getRotation(rx, ry, rz); + //emit updated(x, y, z, rx, ry, rz); + emit translated(x, y, z); + } + */ +} diff --git a/Gui/Vrpn/QVrpnArtTrackingClient.h b/Gui/Vrpn/QVrpnArtTrackingClient.h new file mode 100644 index 0000000000000000000000000000000000000000..eee1184da33d8acba1d3e4b9c95fabb4aaf79122 --- /dev/null +++ b/Gui/Vrpn/QVrpnArtTrackingClient.h @@ -0,0 +1,66 @@ +/** + * \file QVrpnArtTrackingClient.h + * 03/09/2010 LB Initial implementation + */ + +#ifndef QVRPNARTTRACKINGCLIENT_H +#define QVRPNARTTRACKINGCLIENT_H + +#include "VrpnArtTrackingClient.h" +#include <QObject> + +#include <QTimer> + +class QString; + +class QVrpnArtTrackingClient : public QObject, public VrpnArtTrackingClient +{ + Q_OBJECT + +public: + /// @brief Returns the singleton of this class + static QVrpnArtTrackingClient* Instance(QObject* parent = NULL); + + /// @brief Initializes and starts the tracking. + /// @param deviceName The name of the vrpn device @ vrpn server host name + /// e.g. DTrack@visserv3.intern.ufz.de + /// @param updateInterval The update interval in ms. If 0 then you have to + /// manually call MainLoop(). + void StartTracking(const char* deviceName, int updateInterval = 100); + + /// @brief Returns the device name. + QString deviceName() const { return _deviceName; } + + /// @ Returns the update interval. + int updateInterval() const { return _updateInterval; } + +public slots: + /// @brief Calls the vrpn mainloop functions. Must be called once per frame. + /// Is called automatically if an updateInterval was given in init(). + void MainLoop(); + +protected: + QVrpnArtTrackingClient(QObject* parent = NULL); + virtual ~QVrpnArtTrackingClient(); + +private: + /// Calls MainLoop(), see init(). + QTimer* _timer; + + /// The device name, e.g. DTrack@141.65.34.36 + QString _deviceName; + + /// The update interval + int _updateInterval; + + /// @brief This one points to the class itself. + /// You can use only one QVrpnArtTrackingClient because it´s static. + /// This is needed for the callback methods which only + /// can access static members. + static QVrpnArtTrackingClient* _singleton; + +signals: + void positionUpdated(double x, double y, double z); +}; + +#endif // QVRPNARTTRACKINGCLIENT_H diff --git a/Gui/Vrpn/SpaceNavigatorClient.cpp b/Gui/Vrpn/SpaceNavigatorClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e737d53c927ede4177a52b07f91a572a80dd4983 --- /dev/null +++ b/Gui/Vrpn/SpaceNavigatorClient.cpp @@ -0,0 +1,401 @@ +// SpaceNavigatorClient.cpp +// +// +// Author: Lars Bilke + +// ** INCLUDES ** +#include "SpaceNavigatorClient.h" +#include <iostream> + +SpaceNavigatorClient* SpaceNavigatorClient::_spacenavigator = 0; + +SpaceNavigatorClient::SpaceNavigatorClient() +{ + _button = NULL; + _analog = NULL; + _unconsumedData = false; + _frameRotationFactor = 0.0; + _frameTranslationFactor = 0.0; + _upAxis = Y; + + // set all fields to start values + _spacenavigator = this; + for(int i = 0; i < 8; i++) + buttons[0] = false; + _defaultButtonBehaviour = true; + x = y = z = rx = ry = rz = 0.0; + _translationFactor = _rotationFactor = 1.0; + + _dominating = false; + _invertAxes[0] = _invertAxes[2] = _invertAxes[3] = _invertAxes[5] = 1.0; + _invertAxes[1] = _invertAxes[4] = -1.0; + + _mode = TRANSROT; +} + +SpaceNavigatorClient::~SpaceNavigatorClient() +{ + // clean up + if(_button) + { + _button->unregister_change_handler( + NULL, + (vrpn_BUTTONCHANGEHANDLER) SpaceNavigatorClient + ::_handleButtons); + delete _button; + _button = NULL; + } + if(_analog) + { + _analog->unregister_change_handler( + NULL, + (vrpn_ANALOGCHANGEHANDLER) SpaceNavigatorClient + ::_handleAnalogs); + delete _analog; + _analog = NULL; + } +} + +void SpaceNavigatorClient::init( const char* deviceName, SpaceNavigatorAxes axis /*= Y*/ ) +{ + // Create new button_remote object that connects to the corresponding server object + // at the specified computer and register the callback function + if(_button) + { + _button->unregister_change_handler( + NULL, + (vrpn_BUTTONCHANGEHANDLER) SpaceNavigatorClient + ::_handleButtons); + delete _button; + } + _button = new vrpn_Button_Remote(deviceName); + _button->register_change_handler( + NULL, + (vrpn_BUTTONCHANGEHANDLER) SpaceNavigatorClient:: + _handleButtons); + + // Create new analog_remote object that connects to the corresponding server object + // at the specified computer and register the callback function + if(_analog) + { + _analog->unregister_change_handler( + NULL, + (vrpn_ANALOGCHANGEHANDLER) SpaceNavigatorClient + ::_handleAnalogs); + delete _analog; + } + _analog = new vrpn_Analog_Remote(deviceName); + _analog->register_change_handler( + NULL, + (vrpn_ANALOGCHANGEHANDLER) SpaceNavigatorClient:: + _handleAnalogs); + + // set up axis + if(axis == Z) + _upAxis = axis; + else + _upAxis = Y; +} + +void SpaceNavigatorClient::getTranslation(double& retx, double& rety, double& retz) const +{ + retx = x * _frameTranslationFactor; + rety = y * _frameTranslationFactor; + retz = z * _frameTranslationFactor; +} + +void SpaceNavigatorClient::getRotation(double& retx, double& rety, double& retz) const +{ + retx = rx * _frameTranslationFactor; + rety = ry * _frameTranslationFactor; + retz = rz * _frameTranslationFactor; +} + +void SpaceNavigatorClient::update() +{ + double frameTime = getFrameTime(); // in ms + _frameTranslationFactor = _translationFactor * (frameTime / 1000.0); + _frameRotationFactor = _rotationFactor * (frameTime / 800.0); + + // process messages from server + this->_button->mainloop(); + this->_analog->mainloop(); +} + +void SpaceNavigatorClient::setTranslationFactor(double factor) +{ + _translationFactor = factor; +} + +void SpaceNavigatorClient::setRotationFactor(double factor) +{ + _rotationFactor = factor; +} + +bool SpaceNavigatorClient::getZUpAxis() +{ + if (_upAxis == Z) + return true; + else + return false; +} + +void SpaceNavigatorClient::setZUpAxis( bool zUp ) +{ + if (zUp) + _upAxis = Z; + else + _upAxis = Y; +} +void SpaceNavigatorClient::setDomination(bool dominating) +{ + this->_dominating = dominating; + +#ifdef SPACENAVIGATOR_DEBUG_OUTPUT + std::cout << "SpaceNavigator: Axis domination mode: "; + if(dominating) + std::cout << "ON" << std::endl; + else + std::cout << "OFF" << std::endl; +#endif // SPACENAVIGATOR_DEBUG_OUTPUT +} + +void SpaceNavigatorClient::switchDomination() +{ + this->_dominating = !this->_dominating; + +#ifdef SPACENAVIGATOR_DEBUG_OUTPUT + std::cout << "SpaceNavigator: Axis domination mode: "; + if(_dominating) + std::cout << "ON" << std::endl; + else + std::cout << "OFF" << std::endl; +#endif // SPACENAVIGATOR_DEBUG_OUTPUT +} + +void SpaceNavigatorClient::setMode(SpaceNavigatorClient::SpaceNavigatorMode mode) +{ + this->_mode = mode; + +#ifdef SPACENAVIGATOR_DEBUG_OUTPUT + std::cout << "SpaceNavigator: Transformation mode: "; + if(mode == TRANSROT) + std::cout << "TRANSLATION and ROTATION" << std::endl; + else if(mode == TRANS) + std::cout << "TRANSLATION only" << std::endl; + else if(mode == ROT) + std::cout << "ROTATION only" << std::endl; +#endif // SPACENAVIGATOR_DEBUG_OUTPUT +} + +void SpaceNavigatorClient::switchMode() +{ + this->_mode = (SpaceNavigatorClient::SpaceNavigatorMode)((this->_mode + 1) % 3); + +#ifdef SPACENAVIGATOR_DEBUG_OUTPUT + std::cout << "SpaceNavigator: Transformation mode: "; + if(_mode == TRANSROT) + std::cout << "TRANSLATION and ROTATION" << std::endl; + else if(_mode == TRANS) + std::cout << "TRANSLATION only" << std::endl; + else if(_mode == ROT) + std::cout << "ROTATION only" << std::endl; +#endif // SPACENAVIGATOR_DEBUG_OUTPUT +} + +void SpaceNavigatorClient::setDefaultButtonBehaviour(bool enable) +{ + _defaultButtonBehaviour = enable; +} + +void SpaceNavigatorClient::invertAxis(SpaceNavigatorAxes axisToInvert) +{ + if(axisToInvert < 7 && axisToInvert > 0) + { + if(_invertAxes[axisToInvert - 1] == 1.0) + _invertAxes[axisToInvert - 1] = -1.0; + else + _invertAxes[axisToInvert - 1] = 1.0; + } +} + +void VRPN_CALLBACK SpaceNavigatorClient::_handleButtons(void*, vrpn_BUTTONCB buttonData) +{ + // read button data + _spacenavigator->buttons[buttonData.button] = buttonData.state ? true : false; + + if(_spacenavigator->_defaultButtonBehaviour) + { + if(_spacenavigator->buttons[0]) + _spacenavigator->switchMode(); + + if(_spacenavigator->buttons[1]) + _spacenavigator->switchDomination(); + } + + _spacenavigator->_unconsumedData = true; +} + +void VRPN_CALLBACK SpaceNavigatorClient::_handleAnalogs(void*, vrpn_ANALOGCB analogData) +{ + // read data from the analog axes + // range [0, 1] + // set some values to 0 due to mode + + // normal mode (translation and rotation) + if(_spacenavigator->_mode == TRANSROT) + { + if(_spacenavigator->_dominating) + { + double max = analogData.channel[0]; + int index = 0; + for(int i = 1; i < 6; i++) + if(abs(analogData.channel[i]) > abs(max)) + { + index = i; + max = analogData.channel[i]; + } + _spacenavigator->x = _spacenavigator->y = _spacenavigator->z = + _spacenavigator->rx = + _spacenavigator-> + ry = _spacenavigator->rz = 0; + switch(index) + { + case 0: _spacenavigator->x = max * _spacenavigator->_invertAxes[0]; + break; + case 2: _spacenavigator->y = max * _spacenavigator->_invertAxes[1]; + break; + case 1: _spacenavigator->z = max * _spacenavigator->_invertAxes[2]; + break; + case 3: _spacenavigator->rx = max * _spacenavigator->_invertAxes[3]; + break; + case 5: _spacenavigator->ry = max * _spacenavigator->_invertAxes[4]; + break; + case 4: _spacenavigator->rz = max * _spacenavigator->_invertAxes[5]; + break; + } + } + else + { + _spacenavigator->x = analogData.channel[0] * + _spacenavigator->_invertAxes[0]; + _spacenavigator->y = analogData.channel[2] * + _spacenavigator->_invertAxes[1]; + _spacenavigator->z = analogData.channel[1] * + _spacenavigator->_invertAxes[2]; + _spacenavigator->rx = analogData.channel[3] * + _spacenavigator->_invertAxes[3]; + _spacenavigator->ry = analogData.channel[5] * + _spacenavigator->_invertAxes[4]; + _spacenavigator->rz = analogData.channel[4] * + _spacenavigator->_invertAxes[5]; + } + } + + // translation only mode + else if(_spacenavigator->_mode == TRANS) + { + if(_spacenavigator->_dominating) + { + double max = analogData.channel[0]; + int index = 0; + for(int i = 1; i < 3; i++) + if(abs(analogData.channel[i]) > abs(max)) + { + index = i; + max = analogData.channel[i]; + } + _spacenavigator->x = _spacenavigator->y = _spacenavigator->z = + _spacenavigator->rx = + _spacenavigator-> + ry = _spacenavigator->rz = 0; + switch(index) + { + case 0: _spacenavigator->x = max * _spacenavigator->_invertAxes[0]; + break; + case 2: _spacenavigator->y = max * _spacenavigator->_invertAxes[1]; + break; + case 1: _spacenavigator->z = max * _spacenavigator->_invertAxes[2]; + break; + } + } + else + { + _spacenavigator->x = analogData.channel[0] * + _spacenavigator->_invertAxes[0]; + _spacenavigator->y = analogData.channel[2] * + _spacenavigator->_invertAxes[1]; + _spacenavigator->z = analogData.channel[1] * + _spacenavigator->_invertAxes[2]; + _spacenavigator->rx = _spacenavigator->ry = _spacenavigator->rz = 0; + } + } + + // rotation only mode + else if(_spacenavigator->_mode == ROT) + { + if(_spacenavigator->_dominating) + { + double max = analogData.channel[3]; + int index = 3; + for(int i = 4; i < 6; i++) + if(abs(analogData.channel[i]) > abs(max)) + { + index = i; + max = analogData.channel[i]; + } + _spacenavigator->x = _spacenavigator->y = _spacenavigator->z = + _spacenavigator->rx = + _spacenavigator-> + ry = _spacenavigator->rz = 0; + switch(index) + { + case 3: _spacenavigator->rx = max * _spacenavigator->_invertAxes[3]; + break; + case 5: _spacenavigator->ry = max * _spacenavigator->_invertAxes[4]; + break; + case 4: _spacenavigator->rz = max * _spacenavigator->_invertAxes[5]; + break; + } + } + else + { + _spacenavigator->rx = analogData.channel[3] * + _spacenavigator->_invertAxes[3]; + _spacenavigator->ry = analogData.channel[5] * + _spacenavigator->_invertAxes[4]; + _spacenavigator->rz = analogData.channel[4] * + _spacenavigator->_invertAxes[5]; + _spacenavigator->x = _spacenavigator->y = _spacenavigator->z = 0; + } + } + + // swap axes if the z-axis is the up axis + if(_spacenavigator->_upAxis == Z) + { + double temp = _spacenavigator->y; + _spacenavigator->y = _spacenavigator->z; + _spacenavigator->z = temp; + + temp = _spacenavigator->ry; + _spacenavigator->ry = _spacenavigator->rz; + _spacenavigator->rz = temp; + } + + _spacenavigator->_unconsumedData = true; + +#ifdef SPACENAVIGATOR_DEBUG_OUTPUT + std::cout << "Translation: { " << _spacenavigator->x << ", " << _spacenavigator->y << + ", " << _spacenavigator->z << " }" << std::endl; + std::cout << "Rotation: { " << _spacenavigator->rx << ", " << _spacenavigator->ry << + ", " << _spacenavigator->rz << " }" << std::endl; +#endif // SPACENAVIGATOR_DEBUG_OUTPUT +} + +SpaceNavigatorClient* SpaceNavigatorClient::Instance() +{ + if(_spacenavigator == 0) + _spacenavigator = new SpaceNavigatorClient(); + + return _spacenavigator; +} diff --git a/Gui/Vrpn/SpaceNavigatorClient.h b/Gui/Vrpn/SpaceNavigatorClient.h new file mode 100644 index 0000000000000000000000000000000000000000..f6f1115e97063b3651a96ec3d46842711c952810 --- /dev/null +++ b/Gui/Vrpn/SpaceNavigatorClient.h @@ -0,0 +1,180 @@ +// SpaceNavigatorClient.h +// +// +// Author: Lars Bilke + +#ifndef SPACENAVIGATORCLIENT_H +#define SPACENAVIGATORCLIENT_H + +// comment this out to suppress debug outputs on the console +//#define SPACENAVIGATOR_DEBUG_OUTPUT + +// ** INCLUDES ** +#include <vrpn_Analog.h> +#include <vrpn_Button.h> + +// ** SpaceNavigatorClient - CLASS ** +// This implements the singleton design pattern. +// ****************************** +class SpaceNavigatorClient +{ +public: + // ** ENUMS ** + + /// @brief Navigation modes: translation and rotation or translation + /// or rotation only. + enum SpaceNavigatorMode + { + TRANSROT = 0, + TRANS, + ROT + }; + + /// @brief SpaceNavigator axes. + enum SpaceNavigatorAxes + { + X = 1, + Y, + Z, + rX, + rY, + rZ + }; + + // ** Public member fields ** + + /// @brief State of the up to eight buttons. + bool buttons[8]; + + // ** Public member functions ** + + /// @brief Returns the singleton of the SpaceNavigator. + static SpaceNavigatorClient* Instance(); + + /// @brief Initializes the SpaceNavigator. + /// Connects with the server and registers the callback handlers. + /// @param deviceName Example: "SpaceNav@viswork01.intern.ufz.de" + /// @param axis The up axis. + /// It is possible to specify the z-axis as the up-axis. + /// Default the y-axis is the up-axis. + void init(const char* deviceName, SpaceNavigatorAxes axis = Y); + + /// @brief Returns the translation values. + void getTranslation(double& retx, double& rety, double& retz) const; + + /// @brief Returns the rotation values + void getRotation(double& retx, double& rety, double& retz) const; + + /// @brief Updates the translation and rotation values. + /// Must be called once per frame before getTranslation/Rotation. + void update(); + + /// @brief Sets the translation scaling factor. + void setTranslationFactor(double factor); + + /// @brief Sets the rotation scaling factor. + void setRotationFactor(double factor); + + /// @brief Returns true if Z is the up axis. + bool getZUpAxis(); + + /// @brief Sets if Z is the up axis. + void setZUpAxis(bool zUp); + + /// @brief Enables / disables the axis-domination mode. + /// Only the axis with the highest value is used. + void setDomination(bool dominating); + + /// @brief Switches axis-domination mode. + void switchDomination(); + + /// @brief Switch navigation mode. See SpaceNavigatorMode. + void setMode(SpaceNavigatorClient::SpaceNavigatorMode mode); + + /// @brief Switch through navigation modes. + void switchMode(); + + /// @brief Sets the default button behavior. + /// on: left button --> switch mode + /// right button --> switch domination + /// off: no button behavior + void setDefaultButtonBehaviour(bool enable); + + /// @brief Inverts the specified axis of type SpaceNavigatorAxes + void invertAxis(SpaceNavigatorAxes axisToInvert); + +protected: + // ** Protected member functions ** + + /// @brief The constructor is protected because of the singleton + /// design pattern. + SpaceNavigatorClient(); + + /// @brief Destructor + virtual ~SpaceNavigatorClient(); + + /// @brief Returns the elapsed time since the last function call in ms. + /// This must be implemented in a subclass. + virtual int getFrameTime() { return 1; } + + /// @brief Does all the event processing. + /// This function should be run one time per Frame + /// e.g. in the glut display function. + // void mainloop(); + + /// @brief Actual values of the rotation + double rx, ry, rz; + + /// @brief Actual values of the translation + double x, y, z; + + /// @brief This one points to the class itself. + /// You can use only one SpaceNavigatorClient because it´s static. + /// This is needed for the callback methods which only + /// can access static members. + static SpaceNavigatorClient* _spacenavigator; + + /// @brief Is set to true if a vrpn callback was called. + bool _unconsumedData; + +private: + // ** Private member fields ** + vrpn_Button_Remote* _button; + vrpn_Analog_Remote* _analog; + + // is domination mode active? + bool _dominating; + + // mode: 0 - translation and rotation + SpaceNavigatorMode _mode; + + // default button behavior? + bool _defaultButtonBehaviour; + + // which axis should be inverted? + double _invertAxes[6]; + + // ** Private member functions ** + + /// @brief Callbacks which are called whenever a button is pressed + /// or the SpaceNavigator is moved. + /// Callbacks as class members have to be static. + static void VRPN_CALLBACK _handleButtons(void*, vrpn_BUTTONCB buttonData); + static void VRPN_CALLBACK _handleAnalogs(void*, vrpn_ANALOGCB analogData); + + // which is the up-axis (y - normal, z - from the gis world) + SpaceNavigatorAxes _upAxis; + + // The translation factor. + double _translationFactor; + + // The rotation factor. + double _rotationFactor; + + // The translation factor for this frame. + double _frameTranslationFactor; + + // The rotation factor for this frame. + double _frameRotationFactor; +}; +#endif // SPACENAVIGATORCLIENT_H diff --git a/Gui/Vrpn/TrackingSettingsWidget.cpp b/Gui/Vrpn/TrackingSettingsWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ad3a078d8182cfc8d3390f2a3fc47c6cbdabb085 --- /dev/null +++ b/Gui/Vrpn/TrackingSettingsWidget.cpp @@ -0,0 +1,115 @@ +/** + * \file TrackingSettingsWidget.cpp + * 06/09/2010 LB Initial implementation + * + * Implementation of TrackingSettingsWidget class + */ + +// ** INCLUDES ** +#include "QSpaceNavigatorClient.h" +#include "QVrpnArtTrackingClient.h" +#include "TrackingSettingsWidget.h" +#include "VtkTrackedCamera.h" + +#include <QCompleter> +#include <QDoubleValidator> +#include <QLineEdit> +#include <QStringList> + +TrackingSettingsWidget::TrackingSettingsWidget(VtkTrackedCamera* cam, + QWidget* parent /*= 0*/, Qt::WindowFlags f /*= 0*/) + : QWidget(parent, f), _cam(cam) +{ + setupUi(this); + + QStringList deviceNameAtSuggestionList; + deviceNameAtSuggestionList << "141.65.34.36" << "visserv3.intern.ufz.de" << "localhost"; + QCompleter* deviceNameAtCompleter = new QCompleter(deviceNameAtSuggestionList, this); + deviceNameAtCompleter->setCaseSensitivity(Qt::CaseInsensitive); + deviceNameAtLineEdit->setCompleter(deviceNameAtCompleter); + + offsetXLineEdit->setValidator(new QDoubleValidator(offsetXLineEdit)); + offsetYLineEdit->setValidator(new QDoubleValidator(offsetYLineEdit)); + offsetZLineEdit->setValidator(new QDoubleValidator(offsetZLineEdit)); + realToVirtualScaleLineEdit->setValidator(new QDoubleValidator(realToVirtualScaleLineEdit)); + aspectRatioLineEdit->setValidator(new QDoubleValidator(aspectRatioLineEdit)); + screenHeightLineEdit->setValidator(new QDoubleValidator(0.1, 10.0, 2, screenHeightLineEdit)); + nearClipPlaneLineEdit->setValidator(new QDoubleValidator(nearClipPlaneLineEdit)); + farClipPlaneLineEdit->setValidator(new QDoubleValidator(farClipPlaneLineEdit)); + + QVrpnArtTrackingClient* art = QVrpnArtTrackingClient::Instance(); + QStringList list = art->deviceName().split("@"); + deviceNameLineEdit->setText(list.at(0)); + deviceNameAtLineEdit->setText(list.at(1)); + updateIntervalSpinBox->setValue(art->updateInterval()); + offsetXLineEdit->setText(QString::number(_cam->trackingOffsetX())); + offsetYLineEdit->setText(QString::number(_cam->trackingOffsetY())); + offsetZLineEdit->setText(QString::number(_cam->trackingOffsetZ())); + realToVirtualScaleLineEdit->setText(QString::number(_cam->realToVirtualScale())); + aspectRatioLineEdit->setText(QString::number(_cam->screenAspectRatio())); + screenHeightLineEdit->setText(QString::number(_cam->screenHeight())); +} + +TrackingSettingsWidget::~TrackingSettingsWidget() +{ +} + +void TrackingSettingsWidget::on_offsetXLineEdit_textChanged(QString text) +{ + double value = text.toDouble(); + _cam->setTrackingOffsetX(value); +} + +void TrackingSettingsWidget::on_offsetYLineEdit_textChanged(QString text) +{ + double value = text.toDouble(); + _cam->setTrackingOffsetY(value); +} +void TrackingSettingsWidget::on_offsetZLineEdit_textChanged(QString text) +{ + double value = text.toDouble(); + _cam->setTrackingOffsetZ(value); +} + +void TrackingSettingsWidget::on_realToVirtualScaleLineEdit_textChanged(QString text) +{ + double value = text.toDouble(); + _cam->setRealToVirtualScale(value); +} + +void TrackingSettingsWidget::on_aspectRatioLineEdit_textChanged(QString text) +{ + double value = text.toDouble(); + _cam->setScreenAspectRatio(value); +} + +void TrackingSettingsWidget::on_screenHeightLineEdit_textChanged(QString text) +{ + double value = text.toDouble(); + _cam->setScreenHeight(value); +} + +void TrackingSettingsWidget::on_applyPushButton_pressed() +{ + QVrpnArtTrackingClient* art = QVrpnArtTrackingClient::Instance(); + art->StopTracking(); + QString deviceName = deviceNameLineEdit->text() + "@" + deviceNameAtLineEdit->text(); + art->StartTracking(deviceName.toStdString().c_str(), updateIntervalSpinBox->value()); + applyPushButton->setEnabled(false); +} + +void TrackingSettingsWidget::on_nearClipPlaneLineEdit_textChanged( QString text ) +{ + double value = text.toDouble(); + double dnear,dfar; + _cam->GetClippingRange(dnear, dfar); + _cam->SetClippingRange(value, dfar); +} + +void TrackingSettingsWidget::on_farClipPlaneLineEdit_textChanged( QString text ) +{ + double value = text.toDouble(); + double dnear, dfar; + _cam->GetClippingRange(dnear, dfar); + _cam->SetClippingRange(dnear, value); +} diff --git a/Gui/Vrpn/TrackingSettingsWidget.h b/Gui/Vrpn/TrackingSettingsWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..eb29a90fa0ea300357679e95d5f4ff65812bbdbc --- /dev/null +++ b/Gui/Vrpn/TrackingSettingsWidget.h @@ -0,0 +1,40 @@ +/** + * \file TrackingSettingsWidget.h + * 06/09/2010 LB Initial implementation + */ + +#ifndef TRACKINGSETTINGSWIDGET_H +#define TRACKINGSETTINGSWIDGET_H + +#include "ui_TrackingSettingsWidgetBase.h" + +class VtkTrackedCamera; +class QSpaceNavigatorClient; +class QVrpnArtTrackingClient; + +// TODO Add QSettings stuff +class TrackingSettingsWidget : public QWidget, public Ui_TrackingSettingsWidgetBase +{ + Q_OBJECT + +public: + TrackingSettingsWidget(VtkTrackedCamera* cam, QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~TrackingSettingsWidget(); + +protected slots: + void on_deviceNameLineEdit_textChanged() { applyPushButton->setEnabled(true); } + void on_deviceNameAtLineEdit_textChanged() { applyPushButton->setEnabled(true); } + void on_applyPushButton_pressed(); + void on_offsetXLineEdit_textChanged(QString text); + void on_offsetYLineEdit_textChanged(QString text); + void on_offsetZLineEdit_textChanged(QString text); + void on_realToVirtualScaleLineEdit_textChanged(QString text); + void on_aspectRatioLineEdit_textChanged(QString text); + void on_screenHeightLineEdit_textChanged(QString text); + void on_nearClipPlaneLineEdit_textChanged(QString text); + void on_farClipPlaneLineEdit_textChanged(QString text); +private: + VtkTrackedCamera* _cam; +}; + +#endif // TRACKINGSETTINGSWIDGET_H diff --git a/Gui/Vrpn/TrackingSettingsWidgetBase.ui b/Gui/Vrpn/TrackingSettingsWidgetBase.ui new file mode 100644 index 0000000000000000000000000000000000000000..b0a241fd41edc57a390baf54e50f8197e0c2f364 --- /dev/null +++ b/Gui/Vrpn/TrackingSettingsWidgetBase.ui @@ -0,0 +1,271 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <author>Lars Bilke</author> + <class>TrackingSettingsWidgetBase</class> + <widget class="QWidget" name="TrackingSettingsWidgetBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>400</width> + <height>308</height> + </rect> + </property> + <property name="windowTitle"> + <string>Tracking Settings</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QTabWidget" name="tabWidget"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="artTrackTab"> + <attribute name="title"> + <string>ART Tracking</string> + </attribute> + <layout class="QGridLayout" name="gridLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Device Name:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="deviceNameLineEdit"> + <property name="text"> + <string>DTrack</string> + </property> + </widget> + </item> + <item row="0" column="2"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>@</string> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> + </property> + </widget> + </item> + <item row="0" column="3"> + <widget class="QLineEdit" name="deviceNameAtLineEdit"> + <property name="text"> + <string>141.65.34.36</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Update Interval:</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2"> + <widget class="QSpinBox" name="updateIntervalSpinBox"> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + <property name="maximum"> + <number>2000</number> + </property> + <property name="singleStep"> + <number>25</number> + </property> + <property name="value"> + <number>100</number> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>ms</string> + </property> + </widget> + </item> + <item row="8" column="3"> + <widget class="QPushButton" name="applyPushButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>Apply</string> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_5"> + <property name="text"> + <string>Tracking Offset:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLineEdit" name="offsetXLineEdit"> + <property name="text"> + <string>0.0</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLineEdit" name="offsetYLineEdit"> + <property name="text"> + <string>0.0</string> + </property> + </widget> + </item> + <item row="2" column="3"> + <widget class="QLineEdit" name="offsetZLineEdit"> + <property name="text"> + <string>0.0</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_6"> + <property name="text"> + <string>Scale Factor:</string> + </property> + </widget> + </item> + <item row="7" column="0"> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="3" column="1" colspan="2"> + <widget class="QLineEdit" name="realToVirtualScaleLineEdit"> + <property name="toolTip"> + <string>Real to virtual scaling factor</string> + </property> + <property name="text"> + <string>1.0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="3" column="3"> + <widget class="QPushButton" name="pushButton"> + <property name="toolTip"> + <string>Computes the real to virtual scaling factor based on scene boundaries</string> + </property> + <property name="text"> + <string>Compute</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Scr. Aspect Ratio:</string> + </property> + </widget> + </item> + <item row="5" column="0"> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Screen Height:</string> + </property> + </widget> + </item> + <item row="4" column="1" colspan="2"> + <widget class="QLineEdit" name="aspectRatioLineEdit"> + <property name="toolTip"> + <string>Screen width / screen height</string> + </property> + <property name="text"> + <string>1.6</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="5" column="1" colspan="2"> + <widget class="QLineEdit" name="screenHeightLineEdit"> + <property name="text"> + <string>0.4</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="5" column="3"> + <widget class="QLabel" name="label_9"> + <property name="text"> + <string>m</string> + </property> + </widget> + </item> + <item row="6" column="0"> + <widget class="QLabel" name="label_10"> + <property name="text"> + <string>Clipping Planes:</string> + </property> + </widget> + </item> + <item row="6" column="1"> + <widget class="QLineEdit" name="nearClipPlaneLineEdit"> + <property name="text"> + <string>0.1</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="6" column="2"> + <widget class="QLineEdit" name="farClipPlaneLineEdit"> + <property name="text"> + <string>1000.0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="spacenavTab"> + <attribute name="title"> + <string>Space Navigator</string> + </attribute> + </widget> + </widget> + </item> + </layout> + </widget> + <resources/> + <connections/> + <designerdata> + <property name="gridDeltaX"> + <number>10</number> + </property> + <property name="gridDeltaY"> + <number>10</number> + </property> + <property name="gridSnapX"> + <bool>true</bool> + </property> + <property name="gridSnapY"> + <bool>true</bool> + </property> + <property name="gridVisible"> + <bool>false</bool> + </property> + </designerdata> +</ui> diff --git a/Gui/Vrpn/VrpnArtTrackingClient.cpp b/Gui/Vrpn/VrpnArtTrackingClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0364d8d761ed00ef3293c34ec1a64051a799c4d1 --- /dev/null +++ b/Gui/Vrpn/VrpnArtTrackingClient.cpp @@ -0,0 +1,272 @@ +#include "VrpnArtTrackingClient.h" + +#include <assert.h> +#include <iostream> + +VrpnArtTrackingClient* VrpnArtTrackingClient::m_pInstance = NULL; + +VrpnArtTrackingClient::VrpnArtTrackingClient() +{ + int i; + for (i = 0; i < 3; i++) + { + m_dBodyTranslation[i] = 0.0; + m_dFlyTranslation[i] = 0.0; + } + for (i = 0; i < 4; i++) + { + m_dBodyQuaternion[i] = 0.0; + m_dFlyQuaternion[i] = 0.0; + } + + for (i = 0; i < 10; i++) + { + m_dAnalogData[i] = 0.0; + m_bButtonData[i] = false; + } + + m_pvrpnAnalog = NULL; + m_pvrpnTracker = NULL; + m_pvrpnButtons = NULL; + + m_bTrackingStarted = false; + + m_pInstance = this; +} + +VrpnArtTrackingClient* VrpnArtTrackingClient::Instance() +{ + if (m_pInstance == NULL) + { + m_pInstance = new VrpnArtTrackingClient(); + return m_pInstance; + } + else + return m_pInstance; +} + +VrpnArtTrackingClient::~VrpnArtTrackingClient() +{ + StopTracking(); +} + +void VrpnArtTrackingClient::StartTracking(const char* deviceName) +{ + m_pvrpnAnalog = new vrpn_Analog_Remote(deviceName); + m_pvrpnTracker = new vrpn_Tracker_Remote(deviceName); + m_pvrpnButtons = new vrpn_Button_Remote(deviceName); + + m_pvrpnTracker->register_change_handler( + NULL, + (vrpn_TRACKERCHANGEHANDLER) VrpnArtTrackingClient:: + CBHandleTracker); + m_pvrpnAnalog->register_change_handler( + NULL, + (vrpn_ANALOGCHANGEHANDLER) VrpnArtTrackingClient:: + CBHandleAnalogs); + m_pvrpnButtons->register_change_handler( + NULL, + (vrpn_BUTTONCHANGEHANDLER) VrpnArtTrackingClient:: + CBHandleButtons); + + m_bTrackingStarted = true; +} + +void VrpnArtTrackingClient::StopTracking() +{ + if (m_pvrpnAnalog) + { + m_pvrpnAnalog->unregister_change_handler( + NULL, + (vrpn_ANALOGCHANGEHANDLER) + VrpnArtTrackingClient::CBHandleAnalogs); + delete m_pvrpnAnalog; + } + if (m_pvrpnTracker) + { + m_pvrpnTracker->unregister_change_handler( + NULL, + (vrpn_TRACKERCHANGEHANDLER) + VrpnArtTrackingClient::CBHandleTracker); + delete m_pvrpnTracker; + } + if (m_pvrpnButtons) + { + m_pvrpnButtons->unregister_change_handler( + NULL, + (vrpn_BUTTONCHANGEHANDLER) + VrpnArtTrackingClient::CBHandleButtons); + delete m_pvrpnButtons; + } + + m_pvrpnAnalog = NULL; + m_pvrpnTracker = NULL; + m_pvrpnButtons = NULL; + + int i; + for (i = 0; i < 3; i++) + { + m_dBodyTranslation[i] = 0.0; + m_dFlyTranslation[i] = 0.0; + } + for (i = 0; i < 4; i++) + { + m_dBodyQuaternion[i] = 0.0; + m_dFlyQuaternion[i] = 0.0; + } + + for (i = 0; i < 10; i++) + { + m_dAnalogData[i] = 0.0; + m_bButtonData[i] = false; + } + + m_bTrackingStarted = false; +} + +void VrpnArtTrackingClient::MainLoop() +{ + if (m_bTrackingStarted) + { + //std::cout << "MainLoop" << std::endl; + m_pvrpnTracker->mainloop(); + m_pvrpnAnalog->mainloop(); + m_pvrpnButtons->mainloop(); + } + else + std::cout << + "WARNING: VrpnArtTrackingClient::MainLoop() has been called but tracking ist not been started!" + << std::endl; +} + +void VrpnArtTrackingClient::GetBodyTranslation(double &x, double &y, double &z) +{ + x = m_dBodyTranslation[0]; + y = m_dBodyTranslation[1]; + z = m_dBodyTranslation[2]; + + if (!m_bTrackingStarted) + std::cout << + "WARNING: VrpnArtTrackingClient::GetBodyTranslation() has been called but tracking has not been started!" + << std::endl; +} + +void VrpnArtTrackingClient::GetBodyQuaternion(double &v0, double &v1, double &v2, double &v3) +{ + v0 = m_dBodyQuaternion[0]; + v1 = m_dBodyQuaternion[1]; + v2 = m_dBodyQuaternion[2]; + v3 = m_dBodyQuaternion[3]; + + if (!m_bTrackingStarted) + std::cout << + "WARNING: VrpnArtTrackingClient::GetBodyQuaternion() has been called but tracking has not been started!" + << std::endl; +} + +void VrpnArtTrackingClient::GetFlyTranslation(double &x, double &y, double &z) +{ + x = m_dFlyTranslation[0]; + y = m_dFlyTranslation[1]; + z = m_dFlyTranslation[2]; + + if (!m_bTrackingStarted) + std::cout << + "WARNING: VrpnArtTrackingClient::GetFlyTranslation() has been called but tracking has not been started!" + << std::endl; +} + +void VrpnArtTrackingClient::GetFlyQuaternion(double &v0, double &v1, double &v2, double &v3) +{ + v0 = m_dFlyQuaternion[0]; + v1 = m_dFlyQuaternion[1]; + v2 = m_dFlyQuaternion[2]; + v3 = m_dFlyQuaternion[3]; + + if (!m_bTrackingStarted) + std::cout << + "WARNING: VrpnArtTrackingClient::GetFlyQuaternion() has been called but tracking has not been started!" + << std::endl; +} + +double VrpnArtTrackingClient::GetAnalogData(int index) +{ + if (index < 10) + return m_dAnalogData[index]; + else + return 0.0; + + if (!m_bTrackingStarted) + std::cout << + "WARNING: VrpnArtTrackingClient::GetAnalogData() has been called but tracking has not been started!" + << std::endl; +} + +bool VrpnArtTrackingClient::GetButtonData(int index) +{ + if (index < 10) + return m_bButtonData[index]; + else + return false; + + if (!m_bTrackingStarted) + std::cout << + "WARNING: VrpnArtTrackingClient::GetButtonData() has been called but tracking has not been started!" + << std::endl; +} + +void VRPN_CALLBACK VrpnArtTrackingClient::CBHandleTracker(void* userdata, const vrpn_TRACKERCB t) +{ + (void)userdata; + + VrpnArtTrackingClient* art = m_pInstance; + if (art != NULL) + { + if (t.sensor == 0) + { + //std::cout << "CBHandleTracker" << std::endl; + for (int i = 0; i < 3; i++) + art->m_dBodyTranslation[i] = t.pos[i]; + //std::cout << t.pos[i] << std::endl; + for (int i = 0; i < 4; i++) + art->m_dBodyQuaternion[i] = t.quat[i]; + //std::cout << t.quat[i] << std::endl; + } + else if (t.sensor == 1) + { + for (int i = 0; i < 3; i++) + art->m_dFlyTranslation[i] = t.pos[i]; + for (int i = 0; i < 4; i++) + art->m_dFlyQuaternion[i] = t.quat[i]; + } + } +} + +void VRPN_CALLBACK VrpnArtTrackingClient::CBHandleAnalogs(void*, vrpn_ANALOGCB analogData) +{ + //std::cout << "CBHandleAnalogs" << std::endl; + + VrpnArtTrackingClient* art = m_pInstance; + if (art != NULL) + { + int numChannels = analogData.num_channel; + if (numChannels > 10) + numChannels = 10; + for (int i = 0; i < numChannels; i++) + art->m_dAnalogData[i] = analogData.channel[i]; + } +} + +void VRPN_CALLBACK VrpnArtTrackingClient::CBHandleButtons(void* userdata, vrpn_BUTTONCB buttonData) +{ + //std::cout << "CBHandleButtons" << std::endl; + + (void)userdata; + VrpnArtTrackingClient* art = m_pInstance; + if (art != NULL) + { + int buttonIndex = buttonData.button; + if (buttonIndex < 10) + art->m_bButtonData[buttonIndex] = buttonData.state ? true : false; + } +} diff --git a/Gui/Vrpn/VrpnArtTrackingClient.h b/Gui/Vrpn/VrpnArtTrackingClient.h new file mode 100644 index 0000000000000000000000000000000000000000..9cfd40026cd2368b1fbbbb5b142c5db0468edebd --- /dev/null +++ b/Gui/Vrpn/VrpnArtTrackingClient.h @@ -0,0 +1,90 @@ +#ifndef VRPNARTTRACKINGCLIENT_H +#define VRPNARTTRACKINGCLIENT_H + +#include <vrpn_Analog.h> +#include <vrpn_Button.h> +#include <vrpn_Tracker.h> + +/// @brief Vrpn client fort ART-Tracking system +class VrpnArtTrackingClient +{ +public: + /// @brief Returns the singleton of this class + static VrpnArtTrackingClient* Instance(); + + /// @brief Initializes and starts the tracking. + /// @param deviceName The name of the vrpn device @ vrpn server host name + /// e.g. DTrack@visserv3.intern.ufz.de + void StartTracking(const char* deviceName); + + /// @brief Stops the tracking. + void StopTracking(); + + /// @brief Returns true if tracking is started + bool IsStarted() const {return m_bTrackingStarted; } + + /// @brief Calls the vrpn mainloop functions. Must be called once per frame. + void MainLoop(); + + /// @brief Returns the bodys (head) position. + void GetBodyTranslation(double &x, double &y, double &z); + + /// @brief Returns the bodys orientation as a quaternion. + void GetBodyQuaternion(double &v0, double &v1, double &v2, double &v3); + + /// @brief Returns the flysticks position. + void GetFlyTranslation(double &x, double &y, double &z); + + /// @brief Returns the flysticks orientation as a quaternion. + void GetFlyQuaternion(double &v0, double &v1, double &v2, double &v3); + + /// @brief Returns the analog value of an axis of the flysticks yellow little joystick. + /// @param index The axis. + double GetAnalogData(int index); + + /// @brief Returns if the button with the given index of the flystick is pressed. + bool GetButtonData(int index); + +protected: + + /// @brief The constructor is protected because of the singleton + /// design pattern. + VrpnArtTrackingClient(); + + /// @brief Destructor. + ~VrpnArtTrackingClient(); + + /// @brief This one points to the class itself. + /// You can use only one VrpnArtTrackingClient because it´s static. + /// This is needed for the callback methods which only + /// can access static members. + static VrpnArtTrackingClient* m_pInstance; + + // Is the tracker initialized ? + bool m_bTrackingStarted; + + // Tracking values + double m_dBodyQuaternion[4]; + double m_dBodyTranslation[3]; + + // Flystick + double m_dFlyQuaternion[4]; + double m_dFlyTranslation[3]; + + // Analogs + double m_dAnalogData[10]; + + // Buttons + bool m_bButtonData[10]; + + // VRPN related stuff + vrpn_Analog_Remote* m_pvrpnAnalog; + vrpn_Tracker_Remote* m_pvrpnTracker; + vrpn_Button_Remote* m_pvrpnButtons; + + static void VRPN_CALLBACK CBHandleTracker(void* userdata, const vrpn_TRACKERCB t); + static void VRPN_CALLBACK CBHandleAnalogs(void* userdata, vrpn_ANALOGCB analogData); + static void VRPN_CALLBACK CBHandleButtons(void* userdata, vrpn_BUTTONCB buttonData); +}; + +#endif // VRPNARTTRACKINGCLIENT_H diff --git a/Gui/Vrpn/VrpnClient.cpp b/Gui/Vrpn/VrpnClient.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8b9d9b5bb667824ea2cb0c823f154337fc53d78d --- /dev/null +++ b/Gui/Vrpn/VrpnClient.cpp @@ -0,0 +1,60 @@ +/** + * \file VrpnClient.cpp + * 30/08/2010 LB Initial implementation + * + * Implementation of VrpnClient class + */ + +// ** INCLUDES ** +#include "VrpnClient.h" + +#include <QTimer> +#include <vrpn_Analog.h> + +void VRPN_CALLBACK handle_analog( void* userData, const vrpn_ANALOGCB a ) +{ + int i; + const char* name = (const char*)userData; + + printf("Analog %s:\n %5.2f", name, a.channel[0]); + for (i = 1; i < a.num_channel; i++) + printf(", %5.2f", a.channel[i]); + printf(" (%d chans)\n", a.num_channel); + + // if (a.num_channel >= 3) + // emit positionChanged(a.channel[1], a.channel[2], a.channel[3]); + // if (a.num_channel >= 6) + // emit rotationChanged(a.channel[4], a.channel[5], a.channel[6]); +} + +VrpnClient::VrpnClient( QString deviceName, int updateInterval /*= 100*/, QObject* parent /*= NULL*/ ) + : QObject(parent) +{ + // Create vrpn analog device + _deviceName = deviceName; + _vrpnAnalog = new vrpn_Analog_Remote( deviceName.toStdString().c_str() ); + _vrpnAnalog->register_change_handler( 0, handle_analog ); + + int numChannels = _vrpnAnalog->getNumChannels(); + _analogData.fill(0.0, numChannels); + + // Call the vrpn mainloop every updateInterval ms + QTimer* vrpnTimer = new QTimer(this); + connect(vrpnTimer, SIGNAL(timeout()), this, SLOT(update())); + vrpnTimer->start(updateInterval); +} +VrpnClient::~VrpnClient() +{ + _vrpnAnalog->unregister_change_handler( 0, handle_analog ); + delete _vrpnAnalog; +} + +double VrpnClient::getAnalog(int channel) +{ + return _analogData[channel]; +} + +void VrpnClient::update() +{ + _vrpnAnalog->mainloop(); +} \ No newline at end of file diff --git a/Gui/Vrpn/VrpnClient.h b/Gui/Vrpn/VrpnClient.h new file mode 100644 index 0000000000000000000000000000000000000000..cdd673da83869208684146c73b0189bbf49ebe0c --- /dev/null +++ b/Gui/Vrpn/VrpnClient.h @@ -0,0 +1,39 @@ +/** + * \file VrpnClient.h + * 30/08/2010 LB Initial implementation + */ + +#ifndef VRPNCLIENT_H +#define VRPNCLIENT_H + +#include <QObject> +#include <QVector> +#include <vrpn_Analog.h> + +class QString; +class vrpn_Analog_Remote; + +class VrpnClient : public QObject +{ + Q_OBJECT + +public: + VrpnClient(QString deviceName, int updateInterval = 100, QObject* parent = NULL); + virtual ~VrpnClient(); + + double getAnalog(int channel); + +public slots: + void update(); + +protected: + QString _deviceName; + vrpn_Analog_Remote* _vrpnAnalog; + QVector<double> _analogData; + +signals: + void positionChanged(double x, double y, double z); + void rotationChanged(double x, double y, double z); +}; + +#endif // VRPNCLIENT_H diff --git a/Gui/VtkAct/CMakeLists.txt b/Gui/VtkAct/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a8606e0be7275e698bbeca85bfc4974d6d97e2c7 --- /dev/null +++ b/Gui/VtkAct/CMakeLists.txt @@ -0,0 +1,54 @@ +# Source files +set( SOURCES + VtkPickCallback.cpp + VtkCustomInteractorStyle.cpp +) + +# Moc headers +set( MOC_HEADERS + VtkPickCallback.h + VtkCustomInteractorStyle.h +) + +# Header files +set( HEADERS + +) + +# UI files +#set ( UIS +#) + +# Put moc files in a project folder +source_group("UI Files" REGULAR_EXPRESSION "\\w*\\.ui") +source_group("Moc Files" REGULAR_EXPRESSION "moc_.*") + +# Run Qts user interface compiler uic on .ui files +#qt4_wrap_ui( UI_HEADERS ${UIS} ) + +# Run Qts meta object compiler moc on header files +qt4_wrap_cpp( MOC_SOURCES ${MOC_HEADERS} ) + +include_directories( + ${CMAKE_SOURCE_DIR}/Qt/VtkAct + ${CMAKE_BINARY_DIR}/Qt/VtkAct + ${CMAKE_SOURCE_DIR}/Base + ${CMAKE_SOURCE_DIR}/FEM + ${CMAKE_SOURCE_DIR}/GEO + ${CMAKE_SOURCE_DIR}/FileIO + ${CMAKE_SOURCE_DIR}/FileIO/MeshIO + ${CMAKE_SOURCE_DIR}/MSH + ${CMAKE_SOURCE_DIR}/MathLib + ${CMAKE_SOURCE_DIR}/Qt/VtkVis +) + +# Create the library +add_library( VtkAct STATIC + ${SOURCES} + ${HEADERS} + ${MOC_HEADERS} + ${MOC_SOURCES} + ${UIS} +) + +target_link_libraries( VtkAct ${QT_LIBRARIES} ) diff --git a/Gui/VtkAct/VtkCustomInteractorStyle.cpp b/Gui/VtkAct/VtkCustomInteractorStyle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..34cfc3397fa139646355fe69b0db81f2dad6591a --- /dev/null +++ b/Gui/VtkAct/VtkCustomInteractorStyle.cpp @@ -0,0 +1,232 @@ +/** + * \file VtkCustomInteractorStyle.cpp + * 21/6/2010 LB Initial implementation + * + * Implementation of VtkInteractorStyle + */ + +// ** INCLUDES ** +#include "VtkCustomInteractorStyle.h" + +#include <vtkActor.h> +#include <vtkAlgorithmOutput.h> +#include <vtkCamera.h> +#include <vtkCellPicker.h> +#include <vtkDataSetMapper.h> +#include <vtkExtractSelection.h> +#include <vtkIdTypeArray.h> +#include <vtkObjectFactory.h> +#include <vtkProp.h> +#include <vtkProperty.h> +#include <vtkRenderWindow.h> +#include <vtkRenderWindowInteractor.h> +#include <vtkRendererCollection.h> +#include <vtkSelection.h> +#include <vtkSelectionNode.h> +#include <vtkSmartPointer.h> +#include <vtkUnstructuredGrid.h> + +#include <string> + +#include "VtkMeshSource.h" + +vtkStandardNewMacro(VtkCustomInteractorStyle); + +VtkCustomInteractorStyle::VtkCustomInteractorStyle() + : _highlightActor(true), _alternateMouseActions(false) +{ + selectedMapper = vtkDataSetMapper::New(); + selectedActor = vtkActor::New(); + selectedActor->SetMapper(selectedMapper); + selectedActor->GetProperty()->EdgeVisibilityOn(); + selectedActor->GetProperty()->SetEdgeColor(1,0,0); + selectedActor->GetProperty()->SetLineWidth(3); + Data = NULL; +} + +VtkCustomInteractorStyle::~VtkCustomInteractorStyle() +{ + selectedActor->Delete(); + selectedMapper->Delete(); +} + +void VtkCustomInteractorStyle::OnChar() +{ + switch (Interactor->GetKeyCode()) + { + case '3': + std::cout << "The 3 key was pressed." << std::endl; + break; + case 'a': + break; + default: + vtkInteractorStyleTrackballCamera::OnChar(); + } +} + +void VtkCustomInteractorStyle::OnKeyDown() +{ + switch (Interactor->GetKeyCode()) + { + case 32: // Space + _alternateMouseActions = true; + emit cursorChanged(Qt::CrossCursor); + break; + default: + vtkInteractorStyleTrackballCamera::OnKeyDown(); + } +} + +void VtkCustomInteractorStyle::OnKeyUp() +{ + switch (Interactor->GetKeyCode()) + { + case 32: // Space + _alternateMouseActions = false; + emit cursorChanged(Qt::ArrowCursor); + break; + default: + vtkInteractorStyleTrackballCamera::OnKeyUp(); + } +} + +void VtkCustomInteractorStyle::highlightActor( vtkProp3D* actor ) +{ + if (_highlightActor) + HighlightProp((vtkProp*)actor); +} + +void VtkCustomInteractorStyle::setHighlightActor(bool on) +{ + _highlightActor = on; + if (!on) + HighlightProp((vtkProp*)NULL); +} + +void VtkCustomInteractorStyle::pickableDataObject(vtkDataObject* object) +{ + Data = object; + if (!object) + { + this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()-> + RemoveActor(selectedActor); + selectedMapper->SetInputConnection(NULL); + } +} + +// From http://www.vtk.org/Wiki/VTK/Examples/Cxx/Picking/CellPicking +void VtkCustomInteractorStyle::OnLeftButtonDown() +{ + if (!Data) + return vtkInteractorStyleTrackballCamera::OnLeftButtonDown(); + + if (_alternateMouseActions) + { + // Get the location of the click (in window coordinates) + int* pos = this->GetInteractor()->GetEventPosition(); + + vtkSmartPointer<vtkCellPicker> picker = + vtkSmartPointer<vtkCellPicker>::New(); + picker->SetTolerance(0.0005); + + // Pick from this location. + picker->Pick(pos[0], pos[1], 0, this->GetDefaultRenderer()); + + double* worldPosition = picker->GetPickPosition(); + std::cout << "Cell id is: " << picker->GetCellId() << std::endl; + + if(picker->GetCellId() != -1) + { + std::cout << "Pick position is: " << worldPosition[0] << " " << + worldPosition[1] + << " " << worldPosition[2] << endl; + + vtkSmartPointer<vtkIdTypeArray> ids = + vtkSmartPointer<vtkIdTypeArray>::New(); + ids->SetNumberOfComponents(1); + ids->InsertNextValue(picker->GetCellId()); + + vtkSmartPointer<vtkSelectionNode> selectionNode = + vtkSmartPointer<vtkSelectionNode>::New(); + selectionNode->SetFieldType(vtkSelectionNode::CELL); + selectionNode->SetContentType(vtkSelectionNode::INDICES); + selectionNode->SetSelectionList(ids); + + vtkSmartPointer<vtkSelection> selection = + vtkSmartPointer<vtkSelection>::New(); + selection->AddNode(selectionNode); + + vtkSmartPointer<vtkExtractSelection> extractSelection = + vtkSmartPointer<vtkExtractSelection>::New(); + extractSelection->SetInput(0, this->Data); + extractSelection->SetInput(1, selection); + extractSelection->Update(); + + // In selection + vtkSmartPointer<vtkUnstructuredGrid> selected = + vtkSmartPointer<vtkUnstructuredGrid>::New(); + selected->ShallowCopy(extractSelection->GetOutput()); + + std::cout << "There are " << selected->GetNumberOfPoints() + << " points in the selection." << std::endl; + std::cout << "There are " << selected->GetNumberOfCells() + << " cells in the selection." << std::endl; + + // check if the underlying object is a mesh and if so, send a signal to the element model for display of information about the picked element. + vtkAlgorithm* data_set = + picker->GetActor()->GetMapper()->GetInputConnection(0, + 0)->GetProducer() + ->GetInputConnection(0,0)->GetProducer(); + VtkMeshSource* source = dynamic_cast<VtkMeshSource*>(data_set); + if (source) + emit elementPicked(source->GetGrid(), picker->GetCellId()); + + selectedMapper->SetInputConnection(selected->GetProducerPort()); + + this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()-> + AddActor(selectedActor); + } + else + this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()-> + RemoveActor(selectedActor); + emit requestViewUpdate(); + } + else + // Forward events + vtkInteractorStyleTrackballCamera::OnLeftButtonDown(); +} + +void VtkCustomInteractorStyle::OnRightButtonDown() +{ + if (!Data) + return vtkInteractorStyleTrackballCamera::OnRightButtonDown(); + + if (_alternateMouseActions) + { + // Get the location of the click (in window coordinates) + int* pos = this->GetInteractor()->GetEventPosition(); + + vtkSmartPointer<vtkCellPicker> picker = + vtkSmartPointer<vtkCellPicker>::New(); + picker->SetTolerance(0.0005); + + // Pick from this location. + picker->Pick(pos[0], pos[1], 0, this->GetDefaultRenderer()); + + double* worldPosition = picker->GetPickPosition(); + std::cout << "Cell id is: " << picker->GetCellId() << std::endl; + + if(picker->GetCellId() != -1) + { + vtkRenderer* renderer = + this->Interactor->GetRenderWindow()->GetRenderers()-> + GetFirstRenderer(); + vtkCamera* cam = renderer->GetActiveCamera(); + cam->SetFocalPoint(worldPosition); + emit requestViewUpdate(); + } + } + else + // Forward events + vtkInteractorStyleTrackballCamera::OnRightButtonDown(); +} diff --git a/Gui/VtkAct/VtkCustomInteractorStyle.h b/Gui/VtkAct/VtkCustomInteractorStyle.h new file mode 100644 index 0000000000000000000000000000000000000000..b4fa3d033d70e4010c363848d7dc7a696e5fea4a --- /dev/null +++ b/Gui/VtkAct/VtkCustomInteractorStyle.h @@ -0,0 +1,86 @@ +/** + * \file VtkCustomInteractorStyle.h + * 21/6/2010 LB Initial implementation + * + */ + +#ifndef VTKCUSTOMINTERACTORSTYLE_H +#define VTKCUSTOMINTERACTORSTYLE_H + +// ** INCLUDES ** +#include <QObject> + +#include <vtkInteractorStyleTrackballCamera.h> + +class vtkDataObject; +class vtkDataSetMapper; +class vtkActor; +class GridAdapter; + +/** + * VtkCustomInteractorStyle implements highlighting of an active actor and + * highlighting of picked cells inside a vtk object. + * Picking occurs when a vtk object was selected, the alternate mouse mode is + * active (hold spacebar) and the user left clicks. On right click the cameras + * focal point (center of rotation) is set to the picking position. + */ +class VtkCustomInteractorStyle : public QObject, public vtkInteractorStyleTrackballCamera +{ + Q_OBJECT + +public: + static VtkCustomInteractorStyle* New(); + vtkTypeMacro (VtkCustomInteractorStyle, vtkInteractorStyleTrackballCamera); + + /// @brief Handles key press events. + virtual void OnChar(); + + /// @brief Handles key down events. + virtual void OnKeyDown(); + + /// @brief Handles key up events. + virtual void OnKeyUp(); + + /// @brief Handles left mouse button events (picking). + virtual void OnLeftButtonDown(); + + /// @brief Handles middle mouse button events (rotation point picking). + virtual void OnRightButtonDown(); + +public slots: + void highlightActor(vtkProp3D* prop); + void setHighlightActor(bool on); + + /// @brief Sets the highlightable vtk object. + void pickableDataObject(vtkDataObject* object); + +protected: + VtkCustomInteractorStyle(); + virtual ~VtkCustomInteractorStyle(); + + /// @brief The vtk object to pick. + vtkDataObject* Data; + + /// @brief The mapper for highlighting the selected cell. + vtkDataSetMapper* selectedMapper; + + /// @brief The actor for highlighting the selected cell. + vtkActor* selectedActor; + +private: + bool _highlightActor; + bool _alternateMouseActions; + +signals: + /// @brief Emitted when something was picked. + void requestViewUpdate(); + + /// @brief Emitted when the cursor shape was changed due to alternate + /// mouse action mode. + void cursorChanged(Qt::CursorShape); + + /// @brief Emitted when a mesh element has been picked + void elementPicked(const GridAdapter*, const size_t); +}; + +#endif // VTKINTERACTORSTYLE_H diff --git a/Gui/VtkAct/VtkPickCallback.cpp b/Gui/VtkAct/VtkPickCallback.cpp new file mode 100644 index 0000000000000000000000000000000000000000..11873328cb58d11b3c6117004b454786e43723cd --- /dev/null +++ b/Gui/VtkAct/VtkPickCallback.cpp @@ -0,0 +1,43 @@ +/** + * \file VtkPickCallback.cpp + * 21/6/2010 LB Initial implementation + * + * Implementation of VtkPickCallback + */ + +// ** INCLUDES ** +#include "VtkPickCallback.h" + +#include <vtkActor.h> +#include <vtkCellPicker.h> + +VtkPickCallback* VtkPickCallback::New() +{ + return new VtkPickCallback(); +} + +void VtkPickCallback::Execute( vtkObject* caller, unsigned long vtkNotUsed( + eventId), void* vtkNotUsed(callData) ) +{ + vtkCellPicker* picker = static_cast<vtkCellPicker*>(caller); + if (picker->GetCellId() < 0) + { + // Nothing is picked + } + else + { + vtkActor* actor = picker->GetActor(); + if (actor) + emit actorPicked (actor); + + double* pos = picker->GetPickPosition(); + std::cout << "Picked cell id is: " << picker->GetCellId() << std::endl; + std::cout << "Picked position is: " << pos[0] << " " << pos[1] << " " << pos[2] << + std::endl; + } +} + +VtkPickCallback::VtkPickCallback() + : QObject() +{ +} diff --git a/Gui/VtkAct/VtkPickCallback.h b/Gui/VtkAct/VtkPickCallback.h new file mode 100644 index 0000000000000000000000000000000000000000..d71792df23dca94fe733b3ed4945bfea0a37d1da --- /dev/null +++ b/Gui/VtkAct/VtkPickCallback.h @@ -0,0 +1,37 @@ +/** + * \file VtkPickCallback.h + * 21/6/2010 LB Initial implementation + * + */ + +#ifndef VTKPICKCALLBACK_H +#define VTKPICKCALLBACK_H + +// ** INCLUDES ** +#include <QObject> +#include <vtkCommand.h> + +class vtkProp3D; + +/** + * VtkPickCallback is a vtkCommand that implements functionality when + * picking a vtk object through a vtkCellPicker. + */ +class VtkPickCallback : public QObject, public vtkCommand +{ + Q_OBJECT + +public: + static VtkPickCallback* New(); + + void Execute(vtkObject* caller, unsigned long eventId, void* callData); + +protected: + VtkPickCallback(); + +signals: + /// Is emitted when an vtkActor was picked. + void actorPicked (vtkProp3D* actor); +}; + +#endif // VTKPICKCALLBACK_H diff --git a/Gui/VtkVis/CMakeLists.txt b/Gui/VtkVis/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..822a84efcf5b860050f2a5498d1d4dd80eb22d5b --- /dev/null +++ b/Gui/VtkVis/CMakeLists.txt @@ -0,0 +1,170 @@ +# Source files +SET( SOURCES + MeshFromRasterDialog.cpp + QVtkDataSetMapper.cpp + VisPrefsDialog.cpp + VisualizationWidget.cpp + VtkAddFilterDialog.cpp + VtkAlgorithmPropertyCheckbox.cpp + VtkAlgorithmPropertyLineEdit.cpp + VtkAlgorithmPropertyVectorEdit.cpp + VtkBGImageSource.cpp + VtkColorByHeightFilter.cpp + VtkColorLookupTable.cpp + VtkCompositeFilter.cpp + VtkCompositeColorByHeightFilter.cpp + VtkCompositeColormapToImageFilter.cpp + VtkCompositeContourFilter.cpp + VtkCompositeGeoObjectFilter.cpp + VtkCompositeImageToCylindersFilter.cpp + VtkCompositeLineToTubeFilter.cpp + VtkCompositePointToGlyphFilter.cpp + VtkCompositeSelectionFilter.cpp + VtkCompositeTextureOnSurfaceFilter.cpp + VtkCompositeThresholdFilter.cpp + VtkConditionSource.cpp + VtkFilterFactory.cpp + VtkGeoImageSource.cpp + VtkImageDataToLinePolyDataFilter.cpp + VtkMeshConverter.cpp + VtkMeshSource.cpp + VtkPolylinesSource.cpp + VtkPointsSource.cpp + VtkRaster.cpp + VtkSelectionFilter.cpp + VtkStationSource.cpp + VtkSurfacesSource.cpp + VtkTextureOnSurfaceFilter.cpp + VtkTrackedCamera.cpp + VtkVisHelper.cpp + VtkVisImageItem.cpp + VtkVisPipeline.cpp + VtkVisPipelineItem.cpp + VtkVisPipelineView.cpp + VtkVisPointSetItem.cpp + VtkVisTabWidget.cpp + VtkAlgorithmProperties.cpp +) + +# Moc headers +SET( MOC_HEADERS + MeshFromRasterDialog.h + QVtkDataSetMapper.h + VisPrefsDialog.h + VisualizationWidget.h + VtkAddFilterDialog.h + VtkAlgorithmProperties.h + VtkAlgorithmPropertyLineEdit.h + VtkAlgorithmPropertyCheckbox.h + VtkAlgorithmPropertyVectorEdit.h + VtkTrackedCamera.h + VtkVisPipeline.h + VtkVisPipelineView.h + VtkVisTabWidget.h +) + +# Header files +SET( HEADERS + VtkBGImageSource.h + VtkColorByHeightFilter.h + VtkColorLookupTable.h + VtkCompositeFilter.h + VtkCompositeColorByHeightFilter.h + VtkCompositeColormapToImageFilter.h + VtkCompositeContourFilter.h + VtkCompositeGeoObjectFilter.h + VtkCompositeImageToCylindersFilter.h + VtkCompositeLineToTubeFilter.h + VtkCompositePointToGlyphFilter.h + VtkCompositeSelectionFilter.h + VtkCompositeTextureOnSurfaceFilter.h + VtkCompositeThresholdFilter.h + VtkConditionSource.h + VtkFilterFactory.h + VtkGeoImageSource.h + VtkImageDataToLinePolyDataFilter.h + VtkMeshConverter.h + VtkMeshSource.h + VtkPolylinesSource.h + VtkPointsSource.h + VtkRaster.h + VtkSelectionFilter.h + VtkStationSource.h + VtkSurfacesSource.h + VtkTextureOnSurfaceFilter.h + VtkVisHelper.h + VtkVisImageItem.h + VtkVisPipelineItem.h + VtkVisPointSetItem.h +) + +# UI files +SET ( UIS + MeshFromRaster.ui + VtkAddFilterDialogBase.ui + VtkVisTabWidgetBase.ui + VisualizationWidgetBase.ui + VisPrefs.ui +) + +# Put moc files in a project folder +SOURCE_GROUP("UI Files" REGULAR_EXPRESSION "\\w*\\.ui") +SOURCE_GROUP("Moc Files" REGULAR_EXPRESSION "moc_.*") + +# Put filter in a folder +SOURCE_GROUP("Filter Header Files" REGULAR_EXPRESSION "[.]*Filter.h") +SOURCE_GROUP("Filter Source Files" REGULAR_EXPRESSION "[.]*Filter.cpp") + +# Put vtk source files in a folder +SOURCE_GROUP("Source Header Files" REGULAR_EXPRESSION "[.]*Source.h") +SOURCE_GROUP("Source Source Files" REGULAR_EXPRESSION "[.]*Source.cpp") + +# Run Qts user interface compiler uic on .ui files +QT4_WRAP_UI( UI_HEADERS ${UIS} ) + +# Run Qts meta object compiler moc on header files +QT4_WRAP_CPP( MOC_SOURCES ${MOC_HEADERS} ) + +INCLUDE( ${VTK_USE_FILE} ) + +INCLUDE_DIRECTORIES( + ${CMAKE_SOURCE_DIR}/Qt/VtkVis + ${CMAKE_SOURCE_DIR}/Qt/VtkAct + ${CMAKE_BINARY_DIR}/Qt/VtkVis + ${CMAKE_SOURCE_DIR}/Base + ${CMAKE_SOURCE_DIR}/FEM + ${CMAKE_SOURCE_DIR}/GEO + ${CMAKE_SOURCE_DIR}/MathLib + ${CMAKE_SOURCE_DIR}/FileIO + ${CMAKE_SOURCE_DIR}/MSH + ${CMAKE_SOURCE_DIR}/Qt/Base + ${CMAKE_SOURCE_DIR}/Qt/DataView + ${CMAKE_BINARY_DIR}/Qt/DataView +) + +# Create the library +ADD_LIBRARY( VtkVis STATIC + ${SOURCES} + ${HEADERS} + ${MOC_HEADERS} + ${MOC_SOURCES} + ${UIS} +) + +IF (libgeotiff_FOUND) + INCLUDE_DIRECTORIES( ${libgeotiff_INCLUDE_DIR} ${libgeotiff_INCLUDE_DIR}/libxtiff ${VTK_DIR}/../Utilities/vtktiff ) + TARGET_LINK_LIBRARIES( VtkVis ${libgeotiff_LIBRARIES} ) +ENDIF () # libgeotiff_FOUND + +TARGET_LINK_LIBRARIES( VtkVis ${QT_LIBRARIES} ) + +ADD_DEPENDENCIES(VtkVis QtDataView) + +IF(OGS_USE_VRPN) + INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/Qt/Vrpn) +ENDIF() # OGS_USE_VRPN + +IF (OGS_USE_OPENSG) + USE_OPENSG(VtkVis) + INCLUDE_DIRECTORIES( ${CMAKE_SOURCE_DIR}/Qt/OpenSG ) +ENDIF (OGS_USE_OPENSG) diff --git a/Gui/VtkVis/MeshFromRaster.ui b/Gui/VtkVis/MeshFromRaster.ui new file mode 100644 index 0000000000000000000000000000000000000000..32c88e9b8e6d2c4bd5cd9e6021fe3e294f22edb3 --- /dev/null +++ b/Gui/VtkVis/MeshFromRaster.ui @@ -0,0 +1,156 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MeshFromRaster</class> + <widget class="QDialog" name="MeshFromRaster"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>350</width> + <height>220</height> + </rect> + </property> + <property name="windowTitle"> + <string>Create mesh from raster...</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <item row="2" column="1"> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QGroupBox" name="interpretationGroupBox"> + <property name="title"> + <string>Interpret intensities as</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QRadioButton" name="elevationButton"> + <property name="text"> + <string>Elevation</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="materialButton"> + <property name="text"> + <string>Materials</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="ignoreButton"> + <property name="text"> + <string>Ignore</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="0" column="1"> + <widget class="QGroupBox" name="elementTypeGroupBox"> + <property name="title"> + <string>Represent pixels as</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QRadioButton" name="triButton"> + <property name="text"> + <string>sets of two triangles</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="quadButton"> + <property name="text"> + <string>rectangles</string> + </property> + </widget> + </item> + <item> + <widget class="QRadioButton" name="hexButton"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="text"> + <string>hexahedra</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item row="2" column="0"> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="mshNameLabel"> + <property name="layoutDirection"> + <enum>Qt::LeftToRight</enum> + </property> + <property name="text"> + <string> Name of mesh:</string> + </property> + <property name="alignment"> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="mshNameEdit"/> + </item> + </layout> + </widget> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>MeshFromRaster</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>MeshFromRaster</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/VtkVis/MeshFromRasterDialog.cpp b/Gui/VtkVis/MeshFromRasterDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..597a83ca1fbe6e61df516662bab42bf164c95866 --- /dev/null +++ b/Gui/VtkVis/MeshFromRasterDialog.cpp @@ -0,0 +1,43 @@ +/** + * \file MeshFromRasterDialog.cpp + * 2011/11/17 KR Initial implementation + */ + +#include "MeshFromRasterDialog.h" +#include "OGSError.h" + +MeshFromRasterDialog::MeshFromRasterDialog(QDialog* parent) +: QDialog(parent) +{ + setupUi(this); + + this->elevationButton->setChecked(true); + this->triButton->setChecked(true); + this->mshNameEdit->setText("NewMesh"); +} + + +MeshFromRasterDialog::~MeshFromRasterDialog() +{ +} + + +void MeshFromRasterDialog::accept() +{ + UseIntensityAs::type i_type(UseIntensityAs::ELEVATION); + if (this->materialButton->isChecked()) i_type = UseIntensityAs::MATERIAL; + else if (this->ignoreButton->isChecked()) i_type = UseIntensityAs::NONE; + + MshElemType::type e_type(MshElemType::TRIANGLE); + if (this->quadButton->isChecked()) e_type = MshElemType::QUAD; + else if (this->hexButton->isChecked()) e_type = MshElemType::HEXAHEDRON; + + emit setMeshParameters(this->mshNameEdit->text(), e_type, i_type); + this->done(QDialog::Accepted); +} + +void MeshFromRasterDialog::reject() +{ + this->done(QDialog::Rejected); +} + diff --git a/Gui/VtkVis/MeshFromRasterDialog.h b/Gui/VtkVis/MeshFromRasterDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..944c4cd2dc480cac5a754c926b8441adda4937a7 --- /dev/null +++ b/Gui/VtkVis/MeshFromRasterDialog.h @@ -0,0 +1,40 @@ +/** + * \file MeshFromRasterDialog.h + * 2011/11/17 KR Initial implementation + */ + +#ifndef MSHFROMRASTERDIALOG_H +#define MSHFROMRASTERDIALOG_H + +#include "ui_MeshFromRaster.h" +#include "VtkMeshConverter.h" + +#include <QtGui/QDialog> + + +/** + * \brief A dialog for specifying the parameters to construct a mesh based on a raster + */ +class MeshFromRasterDialog : public QDialog, private Ui_MeshFromRaster +{ + Q_OBJECT + +public: + /// Constructor + MeshFromRasterDialog(QDialog* parent = 0); + + ~MeshFromRasterDialog(void); + +private slots: + /// Instructions if the OK-Button has been pressed. + void accept(); + + /// Instructions if the Cancel-Button has been pressed. + void reject(); + +signals: + void setMeshParameters(QString, MshElemType::type, UseIntensityAs::type); + +}; + +#endif //MSHFROMRASTERDIALOG_H diff --git a/Gui/VtkVis/OGSFilterInfo.h b/Gui/VtkVis/OGSFilterInfo.h new file mode 100644 index 0000000000000000000000000000000000000000..d4cfe368ee6340d736cf755eb4d18e76a9d543b7 --- /dev/null +++ b/Gui/VtkVis/OGSFilterInfo.h @@ -0,0 +1,37 @@ +/** + * \file OGSFilterInfo.h + * 29/09/2010 KR Initial implementation + * + */ + +#ifndef OGSFILTERINFO_H +#define OGSFILTERINFO_H + +#include "VtkOGSFilter.h" +#include <string> + +///Stores information about filters in VtkOGSFilter for access-routines from the GUI. +class OGSFilterInfo +{ +public: + enum VtkTargetObject + { + POLYDATA = 0, + UNSTRUCTUREDGRID = 1, + IMAGEDATA = 3 + }; + + OGSFilterInfo(std::string t, VtkOGSFilter::OGSVisFilter f, + VtkTargetObject v) : _text(t), _filter(f), _target(v) {} + ~OGSFilterInfo() {} + const std::string& text() const { return _text; } + const VtkOGSFilter::OGSVisFilter& filter() const { return _filter; } + const VtkTargetObject& target() const { return _target; } + +private: + std::string _text; + VtkOGSFilter::OGSVisFilter _filter; + VtkTargetObject _target; +}; + +#endif // OGSFILTERINFO_H diff --git a/Gui/VtkVis/QVtkDataSetMapper.cpp b/Gui/VtkVis/QVtkDataSetMapper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ec6d0b6396f0bd616ee5297e70b8095b8875cdd1 --- /dev/null +++ b/Gui/VtkVis/QVtkDataSetMapper.cpp @@ -0,0 +1,33 @@ +/** + * \file QVtkDataSetMapper.cpp + * 12/11/2010 LB Initial implementation + * + * Implementation of QVtkDataSetMapper class + */ + +// ** INCLUDES ** +#include "QVtkDataSetMapper.h" + +#include <vtkObjectFactory.h> + +vtkStandardNewMacro(QVtkDataSetMapper); + +QVtkDataSetMapper::QVtkDataSetMapper() + : QObject(NULL) +{ +} + +QVtkDataSetMapper::~QVtkDataSetMapper() +{ +} + +void QVtkDataSetMapper::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +void QVtkDataSetMapper::SetScalarVisibility( bool on ) +{ + vtkDataSetMapper::SetScalarVisibility((int)on); +} + diff --git a/Gui/VtkVis/QVtkDataSetMapper.h b/Gui/VtkVis/QVtkDataSetMapper.h new file mode 100644 index 0000000000000000000000000000000000000000..2138b3cecefd977b6a57bba21dbf4a4a98cb79b6 --- /dev/null +++ b/Gui/VtkVis/QVtkDataSetMapper.h @@ -0,0 +1,43 @@ +/** + * \file QVtkDataSetMapper.h + * 12/11/2010 LB Initial implementation + */ + +#ifndef QVTKDATASETMAPPER_H +#define QVTKDATASETMAPPER_H + +#include <QObject> +#include <vtkDataSetMapper.h> + +/// @brief Simply wraps vtkDataSetMapper as a Qt object to enable slot connections. +class QVtkDataSetMapper : public QObject, public vtkDataSetMapper +{ + Q_OBJECT + +public: + /// @brief Create new objects with New() because of VTKs reference counting. + static QVtkDataSetMapper* New(); + + vtkTypeMacro(QVtkDataSetMapper, vtkDataSetMapper); + + /// @brief Prints information about itself. + void PrintSelf(ostream& os, vtkIndent indent); + +public slots: + /// @brief Sets the scalar visibility on this mapper. + virtual void SetScalarVisibility(bool on); + virtual void SetScalarVisibility(int on) { SetScalarVisibility(static_cast<bool>(on)); } + +protected: + /// @brief Constructor. + QVtkDataSetMapper(); + + /// @brief Destructor. + virtual ~QVtkDataSetMapper(); + +private: + QVtkDataSetMapper(const QVtkDataSetMapper&); // Not implemented. + void operator=(const QVtkDataSetMapper&); // Not implemented +}; + +#endif // QVTKDATASETMAPPER_H diff --git a/Gui/VtkVis/VisPrefs.ui b/Gui/VtkVis/VisPrefs.ui new file mode 100644 index 0000000000000000000000000000000000000000..6641f0ffb83a09296e3eba089e147b998a386670 --- /dev/null +++ b/Gui/VtkVis/VisPrefs.ui @@ -0,0 +1,167 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>VisPrefsDialog</class> + <widget class="QDialog" name="VisPrefsDialog"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>188</width> + <height>402</height> + </rect> + </property> + <property name="windowTitle"> + <string>Visualisation Settings</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QGroupBox" name="LightBox"> + <property name="title"> + <string>Additional Illumination</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <widget class="QCheckBox" name="lightAboveBox"> + <property name="text"> + <string>Light from above</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="lightBelowBox"> + <property name="text"> + <string>Light from below</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="ColorBox"> + <property name="title"> + <string>Background Colour</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="ColorPickerPushButton" name="bgColorButton"> + <property name="text"> + <string>(255,255,255)</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="SuperelevationBox"> + <property name="title"> + <string>Superelevation</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QLineEdit" name="superelevationLineEdit"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Specify the superelevation factor. Click on the button to apply.</string> + </property> + <property name="text"> + <string>1</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="superelevationPushButton"> + <property name="text"> + <string>Apply</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="ViewUpdateBox"> + <property name="title"> + <string>View Update</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <widget class="QCheckBox" name="loadShowAllCheckBox"> + <property name="toolTip"> + <string>Resizes view to show the entire scene when loading new data.</string> + </property> + <property name="text"> + <string>Reset view on load</string> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Rendering</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QCheckBox" name="cullBackfacesCheckBox"> + <property name="toolTip"> + <string>If enabled, all objects (such as triangles, quads) which normals are not pointing towards the view are not rendered.</string> + </property> + <property name="text"> + <string>Cull backfaces</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QPushButton" name="closePushButton"> + <property name="text"> + <string>Close</string> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>ColorPickerPushButton</class> + <extends>QPushButton</extends> + <header>ColorPickerPushButton.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>closePushButton</sender> + <signal>clicked()</signal> + <receiver>VisPrefsDialog</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>93</x> + <y>275</y> + </hint> + <hint type="destinationlabel"> + <x>93</x> + <y>147</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/VtkVis/VisPrefsDialog.cpp b/Gui/VtkVis/VisPrefsDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc2fb388d06893d4ef39421e9f8cfe19ebf2bb4a --- /dev/null +++ b/Gui/VtkVis/VisPrefsDialog.cpp @@ -0,0 +1,81 @@ +/** + * \file VisPrefsDialog.cpp + * 14/06/2010 KR Initial implementation + */ + +#include "VisPrefsDialog.h" +#include <QDoubleValidator> +#include <QLineEdit> +#include <QSettings> +#include <QVariant> + +#include "VisualizationWidget.h" +#include "VtkVisPipeline.h" + +/// Constructor +VisPrefsDialog::VisPrefsDialog(VtkVisPipeline* pipeline, + VisualizationWidget* widget, + QDialog* parent) : + QDialog(parent), _vtkVisPipeline(pipeline), _visWidget(widget), + _above(0,0,2000000), _below(0,0,-2000000) +{ + setupUi(this); + if (_vtkVisPipeline->getLight(_above)) + lightAboveBox->toggle(); + if (_vtkVisPipeline->getLight(_below)) + lightBelowBox->toggle(); + + bgColorButton->setColor(_vtkVisPipeline->getBGColor()); + + QValidator* validator = new QDoubleValidator(0, 100000, 2, this); + superelevationLineEdit->setValidator(validator); + QSettings settings("UFZ, OpenGeoSys-5"); + superelevationLineEdit->setText(settings.value("globalSuperelevation", 1.0).toString()); + cullBackfacesCheckBox->setCheckState(Qt::CheckState(settings.value("globalCullBackfaces", 0).toInt())); +} + +void VisPrefsDialog::on_bgColorButton_colorPicked( QColor color ) +{ + QColor bgColor(color.red(), color.green(), color.blue()); + _vtkVisPipeline->setBGColor(bgColor); +} + +void VisPrefsDialog::on_lightAboveBox_clicked() +{ + if (lightAboveBox->isChecked()) + _vtkVisPipeline->addLight(_above); + else + _vtkVisPipeline->removeLight(_above); +} + +void VisPrefsDialog::on_lightBelowBox_clicked() +{ + if (lightBelowBox->isChecked()) + _vtkVisPipeline->addLight(_below); + else + _vtkVisPipeline->removeLight(_below); +} + +void VisPrefsDialog::on_superelevationPushButton_pressed() +{ + double factor = superelevationLineEdit->text().toDouble(); + _vtkVisPipeline->setGlobalSuperelevation(factor); + + QSettings settings("UFZ, OpenGeoSys-5"); + settings.setValue("globalSuperelevation", factor); +} + +void VisPrefsDialog::on_loadShowAllCheckBox_stateChanged(int state) +{ + _visWidget->setShowAllOnLoad((bool)state); + _vtkVisPipeline->resetCameraOnAddOrRemove((bool)state); +} + +void VisPrefsDialog::on_cullBackfacesCheckBox_stateChanged(int state) +{ + _vtkVisPipeline->setGlobalBackfaceCulling((bool)state); + + QSettings settings("UFZ, OpenGeoSys-5"); + settings.setValue("globalCullBackfaces", state); +} + diff --git a/Gui/VtkVis/VisPrefsDialog.h b/Gui/VtkVis/VisPrefsDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..dd9fced3a2dac238211e4673ebda740263e44b15 --- /dev/null +++ b/Gui/VtkVis/VisPrefsDialog.h @@ -0,0 +1,54 @@ +/** + * \file VisPrefsDialog.h + * 14/06/2010 KR Initial implementation + */ + +#ifndef VISPREFSDIALOG_H +#define VISPREFSDIALOG_H + +#include "Point.h" +#include "ui_VisPrefs.h" +#include <QDialog> + +class VtkVisPipeline; +class VisualizationWidget; + +/** + * \brief A dialog window for settung up a visualisation preferences + */ +class VisPrefsDialog : public QDialog, private Ui_VisPrefsDialog +{ + Q_OBJECT + +public: + VisPrefsDialog(VtkVisPipeline* pipeline, + VisualizationWidget* widget, + QDialog* parent = NULL); + +protected slots: + /// @brief Sets the background colour. + void on_bgColorButton_colorPicked(QColor color); + + /// @brief Adds a light above the scene. + void on_lightAboveBox_clicked(); + + /// @brief Adds a light below the scene. + void on_lightBelowBox_clicked(); + + /// @brief Sets the given superelevation on all vis pipeline source objects + void on_superelevationPushButton_pressed(); + + /// @brief + void on_loadShowAllCheckBox_stateChanged(int state); + + /// @brief Culls backfacing rendering primitives on all actors. + void on_cullBackfacesCheckBox_stateChanged(int state); + +private: + VtkVisPipeline* _vtkVisPipeline; + VisualizationWidget* _visWidget; + GEOLIB::Point _above; + GEOLIB::Point _below; +}; + +#endif //VISPREFSDIALOG_H diff --git a/Gui/VtkVis/VisualizationWidget.cpp b/Gui/VtkVis/VisualizationWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c258222682bbeaa42340abbd2f3302879f04590 --- /dev/null +++ b/Gui/VtkVis/VisualizationWidget.cpp @@ -0,0 +1,292 @@ +/** + * \file VisualizationWidget.cpp + * 3/11/2009 LB Initial implementation + * + * Implementation of VisualizationWidget + */ + +// ** INCLUDES ** +#include "Point.h" +#include "VisualizationWidget.h" +#include "VtkCustomInteractorStyle.h" +#include "VtkPickCallback.h" +#include "VtkTrackedCamera.h" + +#include <vtkCamera.h> +#include <vtkCellPicker.h> +#include <vtkRenderWindow.h> +#include <vtkRenderer.h> +#include <vtkSmartPointer.h> + +#include <vtkAxesActor.h> +#include <vtkCommand.h> +#include <vtkInteractorStyleRubberBandZoom.h> +#include <vtkInteractorStyleSwitch.h> +#include <vtkMath.h> +#include <vtkOrientationMarkerWidget.h> +#include <vtkPNGWriter.h> +#include <vtkSmartPointer.h> +#include <vtkWindowToImageFilter.h> + +#include <QCursor> +#include <QDir> +#include <QFileDialog> +#include <QInputDialog> +#include <QLineEdit> +#include <QSettings> +#include <QSettings> +#include <QString> + +#ifdef OGS_USE_VRPN +#include "QSpaceNavigatorClient.h" +#include "QVrpnArtTrackingClient.h" +#include "VtkTrackedCamera.h" +#include <QTimer> +#include <vtkEventQtSlotConnect.h> +#endif // OGS_USE_VRPN + +VisualizationWidget::VisualizationWidget( QWidget* parent /*= 0*/ ) + : QWidget(parent) +{ + this->setupUi(this); + + _interactorStyle = VtkCustomInteractorStyle::New(); + vtkWidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle(_interactorStyle); + + _vtkPickCallback = VtkPickCallback::New(); + vtkSmartPointer<vtkCellPicker> picker = vtkSmartPointer<vtkCellPicker>::New(); + picker->AddObserver(vtkCommand::EndPickEvent, _vtkPickCallback); + vtkWidget->GetRenderWindow()->GetInteractor()->SetPicker(picker); + + // BUG Render Window conflicts with VREDs render window +#ifndef OGS_VRED_PLUGIN + vtkRenderWindow* renderWindow = vtkWidget->GetRenderWindow(); + renderWindow->StereoCapableWindowOn(); + renderWindow->SetStereoTypeToCrystalEyes(); + _vtkRender = vtkRenderer::New(); + renderWindow->AddRenderer(_vtkRender); + _interactorStyle->SetDefaultRenderer(_vtkRender); +#endif // OGS_VRED_PLUGIN + + QSettings settings("UFZ", "OpenGeoSys-5"); + +#ifdef OGS_USE_VRPN + VtkTrackedCamera* cam = new VtkTrackedCamera(this); + _vtkRender->SetActiveCamera(cam); + connect( cam, SIGNAL(viewUpdated()), this, SLOT(updateView()) ); + + //QSpaceNavigatorClient* spacenav = QSpaceNavigatorClient::Instance(); + //spacenav->init("spacenav@localhost", 1000 / 15, SpaceNavigatorClient::Z); + //cam->setFocalPoint(0, 5.0, 0.5); + //cam->updateView(); + //spacenav->setTranslationFactor(2.0); + //connect( spacenav, SIGNAL(translated(double, double, double)), cam, SLOT(setTrackingData(double, double, double)) ); + //connect( spacenav, SIGNAL(translated(double, double, double)), cam, SLOT(translate(double, double, double)) ); + + QVrpnArtTrackingClient* art = QVrpnArtTrackingClient::Instance(this); + if (settings.contains("Tracking/artDeviceName")) + { + QString deviceName = settings.value("Tracking/artDeviceName").toString(); + QString deviceNameAt = settings.value("Tracking/artDeviceNameAt").toString(); + art->StartTracking(QString(deviceName + "@" + deviceNameAt).toStdString().c_str(), + settings.value("Tracking/artUpdateInterval").toInt()); + } + else + art->StartTracking("DTrack@141.65.34.36"); + connect( art, SIGNAL(positionUpdated(double, double, double)), + cam, SLOT(setTrackingData(double, double, double)) ); + + // Connect the vtk event to the qt slot + _qtConnect = vtkEventQtSlotConnect::New(); + _qtConnect->Connect(vtkWidget->GetRenderWindow()->GetInteractor(), + vtkCommand::EndInteractionEvent, + cam, + SLOT(updatedFromOutside())); + +#endif // OGS_USE_VRPN + + _vtkRender->SetBackground(0.0,0.0,0.0); + + // Restore settings + stereoToolButton->setChecked(settings.value("stereoEnabled").toBool()); + //if (settings.contains("stereoEyeAngle")) + // cam->SetEyeAngle(settings.value("stereoEyeAngle").toDouble()); + //else + // cam->SetEyeAngle(2.0); +/* + if (!stereoToolButton->isChecked()) + { + eyeAngleLabel->setEnabled(false); + eyeAngleSlider->setEnabled(false); + } + */ + //eyeAngleSlider->setValue((int)(_vtkRender->GetActiveCamera()->GetEyeAngle() * 10)); + + // Create an orientation marker using vtkAxesActor + vtkSmartPointer<vtkAxesActor> axesActor = vtkSmartPointer<vtkAxesActor>::New(); + vtkOrientationMarkerWidget* markerWidget = vtkOrientationMarkerWidget::New(); + markerWidget->SetOrientationMarker(axesActor); + //markerWidget->SetViewport(0.0, 0.0, 0.15, 0.3); // size + markerWidget->SetInteractor(vtkWidget->GetRenderWindow()->GetInteractor()); + markerWidget->EnabledOn(); + markerWidget->InteractiveOff(); + + _isShowAllOnLoad = true; + + // Set alternate cursor shapes + connect(_interactorStyle, SIGNAL(cursorChanged(Qt::CursorShape)), + this, SLOT(setCursorShape(Qt::CursorShape))); +} + +VisualizationWidget::~VisualizationWidget() +{ + // Write settings + QSettings settings("UFZ", "OpenGeoSys-5"); + settings.setValue("stereoEnabled", stereoToolButton->isChecked()); + settings.setValue("stereoEyeAngle", _vtkRender->GetActiveCamera()->GetEyeAngle()); + + _interactorStyle->deleteLater(); + _vtkPickCallback->deleteLater(); +#ifdef OGS_USE_VRPN + _qtConnect->Delete(); +#endif // OGS_USE_VRPN +} +VtkCustomInteractorStyle* VisualizationWidget::interactorStyle() const +{ + return _interactorStyle; +} +VtkPickCallback* VisualizationWidget::vtkPickCallback() const +{ + return _vtkPickCallback; +} +void VisualizationWidget::updateView() +{ + //QDialog box(0, Qt::WindowTitleHint); + //box.show(); + vtkWidget->GetRenderWindow()->Render(); +} + +void VisualizationWidget::showAll() +{ + _vtkRender->ResetCamera(); + vtkCamera* cam = _vtkRender->GetActiveCamera(); + double* fp = cam->GetFocalPoint(); + double* p = cam->GetPosition(); + double dist = sqrt(vtkMath::Distance2BetweenPoints(p, fp)); + cam->SetPosition(fp[0], fp[1], fp[2] + dist); + cam->SetViewUp(0.0, 1.0, 0.0); + this->updateView(); +} + +void VisualizationWidget::updateViewOnLoad() +{ + if (_isShowAllOnLoad) + this->showAll(); + else + updateView(); +} + +void VisualizationWidget::on_stereoToolButton_toggled( bool checked ) +{ + if (checked) + vtkWidget->GetRenderWindow()->StereoRenderOn(); + //eyeAngleLabel->setEnabled(true); + //eyeAngleSlider->setEnabled(true); + else + vtkWidget->GetRenderWindow()->StereoRenderOff(); + //eyeAngleLabel->setEnabled(false); + //eyeAngleSlider->setEnabled(false); + + this->updateView(); +} +/* + void VisualizationWidget::on_eyeAngleSlider_valueChanged( int value ) + { + Q_UNUSED(value); + //_vtkRender->GetActiveCamera()->SetEyeAngle(value / 10.0); + //updateView(); + } + */ +void VisualizationWidget::on_zoomToolButton_toggled( bool checked ) +{ + if (checked) + { + vtkSmartPointer<vtkInteractorStyleRubberBandZoom> interactorStyle = + vtkSmartPointer<vtkInteractorStyleRubberBandZoom>::New(); + vtkWidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle(interactorStyle); + QCursor cursor; + cursor.setShape(Qt::CrossCursor); + vtkWidget->setCursor(cursor); + } + else + { + vtkWidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle(_interactorStyle); + QCursor cursor; + cursor.setShape(Qt::ArrowCursor); + vtkWidget->setCursor(cursor); + } +} + +void VisualizationWidget::on_showAllPushButton_pressed() +{ + this->showAll(); +} + +void VisualizationWidget::on_highlightToolButton_toggled(bool checked) +{ + _interactorStyle->setHighlightActor(checked); +} + +void VisualizationWidget::on_orthogonalProjectionToolButton_toggled( bool checked ) +{ + _vtkRender->GetActiveCamera()->SetParallelProjection(checked); + this->updateView(); +} + +void VisualizationWidget::on_screenshotPushButton_pressed() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString filename = QFileDialog::getSaveFileName(this, tr("Save screenshot"), + settings.value( + "lastScreenshotDir").toString(), + "PNG file (*.png)"); + if (filename.count() > 4) + { + bool ok; + int magnification = QInputDialog::getInt(this, tr("Screenshot magnification"), + tr( + "Enter a magnification factor for the resulting image."), + 2, 1, 10, 1, &ok); + if (ok) + { + QDir dir(filename); + settings.setValue("lastScreenshotDir", dir.absolutePath()); + this->screenshot(filename, magnification); + } + } +} + +void VisualizationWidget::screenshot(QString filename, int magnification) +{ + vtkSmartPointer<vtkWindowToImageFilter> windowToImageFilter = + vtkSmartPointer<vtkWindowToImageFilter>::New(); + windowToImageFilter->SetInput(vtkWidget->GetRenderWindow()); + // Set the resolution of the output image + // magnification times the current resolution of vtk render window + windowToImageFilter->SetMagnification(magnification); + // Also record the alpha (transparency) channel + windowToImageFilter->SetInputBufferTypeToRGBA(); + windowToImageFilter->Update(); + + vtkSmartPointer<vtkPNGWriter> writer = vtkSmartPointer<vtkPNGWriter>::New(); + writer->SetFileName(filename.toStdString().c_str()); + writer->SetInput(windowToImageFilter->GetOutput()); + writer->Write(); + + this->updateView(); +} + +void VisualizationWidget::setCursorShape(Qt::CursorShape shape) +{ + this->setCursor(QCursor(shape)); +} diff --git a/Gui/VtkVis/VisualizationWidget.h b/Gui/VtkVis/VisualizationWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..3495cc9b33b85e58143bf445fdb1abc65a489e0b --- /dev/null +++ b/Gui/VtkVis/VisualizationWidget.h @@ -0,0 +1,96 @@ +/** + * \file VisualizationWidget.h + * 3/11/2009 LB Initial implementation + * + */ + +#ifndef VISUALIZATIONWIDGET_H +#define VISUALIZATIONWIDGET_H + +// ** INCLUDES ** +#include "ui_VisualizationWidgetBase.h" + +class vtkRenderer; +class VtkCustomInteractorStyle; +class VtkPickCallback; +#ifdef OGS_USE_VRPN +class vtkEventQtSlotConnect; +#endif // OGS_USE_VRPN + +/** + * \brief Widget containing the 3d VTK scene view. + */ +class VisualizationWidget : public QWidget, public Ui_VisualizationWidgetBase +{ + Q_OBJECT + +public: + + /// @brief Constructor. + VisualizationWidget(QWidget* parent = 0); + + /// @brief Destructor. + ~VisualizationWidget(); + + /// @brief Returns the VtkCustomInteractorStyle. + VtkCustomInteractorStyle* interactorStyle() const; + + /// @brief Returns the VtkPickCallback. + VtkPickCallback* vtkPickCallback() const; + + /// @brief See updateViewOnLoad(). + void setShowAllOnLoad(bool show) { _isShowAllOnLoad = show; } + +public slots: + /// @brief Updates the the 3d view. + void updateView(); + + /// @brief Shows the entire scene on the views. + void showAll(); + + /// @brief Updates the view only or additionally shows the entire scene. + void updateViewOnLoad(); + + /// @brief Saves a magnified image of the current render window to a file. + void screenshot(QString filename, int magnification); + + /// @brief Returns the vtk renderer + vtkRenderer* renderer() const { return _vtkRender; } + + /// @brief Sets the widgets cursor shape. + /// @see http://doc.qt.nokia.com/4.7/qt.html#CursorShape-enum + void setCursorShape(Qt::CursorShape shape); + +protected slots: + /// @brief Toggles stereo rendering on / off. + void on_stereoToolButton_toggled(bool checked); + + /// @brief Adjusts the eye angle (separation) for stereo viewing. + //void on_eyeAngleSlider_valueChanged(int value); + + /// @brief Toggles rectangular zooming mode. + void on_zoomToolButton_toggled(bool checked); + + /// @brief Resets the camera to view the entire scene. + void on_showAllPushButton_pressed(); + + /// @brief Toggles the display of bounding boxes around. + void on_highlightToolButton_toggled(bool checked); + + /// @brief Toggles the orthogonal projection. + void on_orthogonalProjectionToolButton_toggled(bool checked); + + /// @brief Saves a screenshot. + void on_screenshotPushButton_pressed(); + +private: + vtkRenderer* _vtkRender; + VtkCustomInteractorStyle* _interactorStyle; + VtkPickCallback* _vtkPickCallback; + bool _isShowAllOnLoad; +#ifdef OGS_USE_VRPN + vtkEventQtSlotConnect* _qtConnect; +#endif // OGS_USE_VRPN +}; + +#endif // VISUALIZATIONWIDGET_H diff --git a/Gui/VtkVis/VisualizationWidgetBase.ui b/Gui/VtkVis/VisualizationWidgetBase.ui new file mode 100644 index 0000000000000000000000000000000000000000..bc4108fa752d9aae0e116d447e8ad34f331caed0 --- /dev/null +++ b/Gui/VtkVis/VisualizationWidgetBase.ui @@ -0,0 +1,150 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>VisualizationWidgetBase</class> + <widget class="QWidget" name="VisualizationWidgetBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>665</width> + <height>412</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <property name="margin"> + <number>0</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QPushButton" name="showAllPushButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="toolTip"> + <string>Resets camera to view the entire scene from above.</string> + </property> + <property name="text"> + <string>Show All</string> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="zoomToolButton"> + <property name="toolTip"> + <string>When activated hold down the left mouse button and draw a rectangle to zoom to the rectangles area.</string> + </property> + <property name="text"> + <string>Zoom</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="highlightToolButton"> + <property name="toolTip"> + <string>When enabled a red bounding box is shown on selected items in the visualization pipeline.</string> + </property> + <property name="text"> + <string>Highlight</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="orthogonalProjectionToolButton"> + <property name="toolTip"> + <string>Switches between perspective and orthogonal projection.</string> + </property> + <property name="text"> + <string>Ortho</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QToolButton" name="stereoToolButton"> + <property name="toolTip"> + <string>Enables / disables stereo rendering.</string> + </property> + <property name="text"> + <string>Stereo</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="screenshotPushButton"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Fixed" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Screenshot</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QVTKWidget" name="vtkWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>QVTKWidget</class> + <extends>QWidget</extends> + <header>QVTKWidget.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Gui/VtkVis/VtkAddFilterDialog.cpp b/Gui/VtkVis/VtkAddFilterDialog.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6eddb7665822a0059faa8398fd03d565e37cb904 --- /dev/null +++ b/Gui/VtkVis/VtkAddFilterDialog.cpp @@ -0,0 +1,118 @@ +/** + * \file VtkAddFilterDialog.cpp + * 23/2/2010 LB Initial implementation + * + * Implementation of VtkAddFilterDialog + */ + +// ** INCLUDES ** +#include "VtkAddFilterDialog.h" +#include "VtkCompositeFilter.h" +#include "VtkFilterFactory.h" +#include "VtkVisImageItem.h" +#include "VtkVisPipeline.h" +#include "VtkVisPipelineItem.h" +#include "VtkVisPointSetItem.h" + +#include <vtkContourFilter.h> +#include <vtkOutlineFilter.h> +#include <vtkTransformFilter.h> + +#include <QModelIndex> + +VtkAddFilterDialog::VtkAddFilterDialog( VtkVisPipeline* pipeline, + QModelIndex parentIndex, + QDialog* parent /*= 0*/ ) + : QDialog(parent), _pipeline(pipeline), _parentIndex(parentIndex) +{ + setupUi(this); + filterListWidget->setSelectionMode(QAbstractItemView::SingleSelection); + + VtkVisPipelineItem* parentItem = + static_cast<VtkVisPipelineItem*>(_pipeline->getItem(parentIndex)); + vtkDataObject* parentDataObject = parentItem->algorithm()->GetOutputDataObject(0); + int parentDataObjectType = parentDataObject->GetDataObjectType(); + + QVector<VtkFilterInfo> filterList = VtkFilterFactory::GetFilterList(); + foreach(VtkFilterInfo filter, filterList) + { + // Check for suitable filters (see vtkDataSet inheritance diagram) + int inputType = filter.inputDataObjectType; + if ((inputType == parentDataObjectType) || + (inputType == VTK_POINT_SET && parentDataObjectType != VTK_IMAGE_DATA) || + (inputType == VTK_IMAGE_DATA && + (parentDataObjectType == VTK_STRUCTURED_POINTS || parentDataObjectType == + VTK_UNIFORM_GRID))) + + new QListWidgetItem(filter.readableName, filterListWidget); + } + + // On double clicking an item the dialog gets accepted + connect(filterListWidget,SIGNAL(itemDoubleClicked(QListWidgetItem*)), + this->buttonBox,SIGNAL(accepted())); +} + +void VtkAddFilterDialog::on_buttonBox_accepted() +{ + QVector<VtkFilterInfo> filterList = VtkFilterFactory::GetFilterList(); + QString filterName; + foreach(VtkFilterInfo filter, filterList) + { + if (filter.readableName.compare(filterListWidget->currentItem()->text()) == 0) + { + filterName = filter.name; + break; + } + } + VtkVisPipelineItem* parentItem = + static_cast<VtkVisPipelineItem*>(_pipeline->getItem(_parentIndex)); + QList<QVariant> itemData; + itemData << filterListWidget->currentItem()->text() << true; + + VtkCompositeFilter* filter; + if (dynamic_cast<VtkVisImageItem*>(parentItem)) + filter = VtkFilterFactory::CreateCompositeFilter(filterName, parentItem->algorithm()); + else + filter = VtkFilterFactory::CreateCompositeFilter(filterName, + parentItem->transformFilter()); + + VtkVisPipelineItem* item; + if (filter) + { + if (filter->GetOutputDataObjectType() == VTK_IMAGE_DATA) + item = new VtkVisImageItem(filter, parentItem, itemData); + else + item = new VtkVisPointSetItem(filter, parentItem, itemData); + } + else + { + vtkAlgorithm* algorithm = VtkFilterFactory::CreateSimpleFilter(filterName); + if (algorithm) + item = new VtkVisPointSetItem(algorithm, parentItem, itemData); + else + { + std::cout << "Error: VtkFilterFavctory cannot create " << + filterName.toStdString() << std::endl; + return; + } + } + _pipeline->addPipelineItem(item, _parentIndex); +} + +void VtkAddFilterDialog::on_filterListWidget_currentRowChanged( int currentRow ) +{ + foreach(VtkFilterInfo filter, VtkFilterFactory::GetFilterList()) + { + if (filter.readableName.compare(filterListWidget->item(currentRow)->text()) == 0) + { + QString desc = filter.description; + desc = desc + QString("\n\nThis filter outputs ") + + filter.OutputDataObjectTypeAsString() + + QString("\n\nFilter class name: ") + + filter.name; + + this->filterDescTextEdit->setText(desc); + continue; + } + } +} diff --git a/Gui/VtkVis/VtkAddFilterDialog.h b/Gui/VtkVis/VtkAddFilterDialog.h new file mode 100644 index 0000000000000000000000000000000000000000..3e8d9d73bf2eb39916654673942e21d80824382c --- /dev/null +++ b/Gui/VtkVis/VtkAddFilterDialog.h @@ -0,0 +1,40 @@ +/** + * \file VtkAddFilterDialog.h + * 23/2/2010 LB Initial implementation + * + */ + +#ifndef VTKADDFILTERDIALOG_H +#define VTKADDFILTERDIALOG_H + +// ** INCLUDES ** +#include "ui_VtkAddFilterDialogBase.h" + +class VtkVisPipeline; +class QModelIndex; +class QRadioButton; + +/** + * \brief Dialog for selecting a filter to be applied to a VtkPipelineItem. + * The dialog lets you select filters defined in VtkOGSFilter that have been registered as OGSFilterInfo - objects. + */ +class VtkAddFilterDialog : public QDialog, public Ui_VtkAddFilterDialogBase +{ + Q_OBJECT + +public: + /// Constructor + VtkAddFilterDialog(VtkVisPipeline* pipeline, QModelIndex parentIndex, QDialog* parent = 0); + +public slots: + void on_buttonBox_accepted(); + +protected slots: + void on_filterListWidget_currentRowChanged(int currentRow); + +private: + VtkVisPipeline* _pipeline; + QModelIndex _parentIndex; +}; + +#endif // VTKADDFILTERDIALOG_H diff --git a/Gui/VtkVis/VtkAddFilterDialogBase.ui b/Gui/VtkVis/VtkAddFilterDialogBase.ui new file mode 100644 index 0000000000000000000000000000000000000000..5bd68a1ebff255fc44b7d3e277f6e4cbb7031068 --- /dev/null +++ b/Gui/VtkVis/VtkAddFilterDialogBase.ui @@ -0,0 +1,142 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>VtkAddFilterDialogBase</class> + <widget class="QDialog" name="VtkAddFilterDialogBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>325</width> + <height>608</height> + </rect> + </property> + <property name="windowTitle"> + <string>Add visualization filter</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="parentGroupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Parent</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <item> + <layout class="QGridLayout" name="gridLayout_2"> + <item row="0" column="0"> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Type:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QLineEdit" name="parentTypeLineEdit"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Output:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QLineEdit" name="parentOutputLineEdit"/> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QGroupBox" name="filterGroupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="title"> + <string>Add filter</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QListWidget" name="filterListWidget"/> + </item> + <item> + <widget class="QTextEdit" name="filterDescTextEdit"/> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>filterListWidget</tabstop> + <tabstop>buttonBox</tabstop> + <tabstop>parentTypeLineEdit</tabstop> + <tabstop>parentOutputLineEdit</tabstop> + <tabstop>filterDescTextEdit</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>VtkAddFilterDialogBase</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>VtkAddFilterDialogBase</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui> diff --git a/Gui/VtkVis/VtkAlgorithmProperties.cpp b/Gui/VtkVis/VtkAlgorithmProperties.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7cc79c44e246e07c33777d50feefa4c5365e479e --- /dev/null +++ b/Gui/VtkVis/VtkAlgorithmProperties.cpp @@ -0,0 +1,99 @@ +/** + * \file VtkAlgorithmProperties.cpp + * 14/02/2012 LB Initial implementation + * + * Implementation of the VtkAlgorithmProperties class + */ + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" + +#include <vtkProperty.h> +#include <vtkTexture.h> + +#include "VtkColorLookupTable.h" +#include "XmlIO/XmlLutReader.h" + +VtkAlgorithmProperties::VtkAlgorithmProperties(QObject* parent /*= NULL*/) + : QObject(parent) +{ + _property = vtkProperty::New(); + _texture = NULL; + _scalarVisibility = true; + _algorithmUserProperties = new QMap<QString, QVariant>; + _algorithmUserVectorProperties = new QMap<QString, QList<QVariant> >; + _activeAttributeName = ""; + _removable = true; +} + +VtkAlgorithmProperties::~VtkAlgorithmProperties() +{ + _property->Delete(); + if (_texture != NULL) _texture->Delete(); + + for (std::map<QString, vtkLookupTable*>::iterator it = _lut.begin(); + it != _lut.end(); ++it) + it->second->Delete(); + delete _algorithmUserProperties; + delete _algorithmUserVectorProperties; +} + +vtkLookupTable* VtkAlgorithmProperties::GetLookupTable(const QString& array_name) +{ + std::map<QString, vtkLookupTable*>::iterator it = _lut.find(array_name); + if (it != _lut.end()) + return it->second; + else + return NULL; +} + +void VtkAlgorithmProperties::SetLookUpTable(const QString &array_name, vtkLookupTable* lut) +{ + lut->Build(); + + if (array_name.length() > 0) + { + std::map<QString, vtkLookupTable*>::iterator it = _lut.find(array_name); + if (it != _lut.end()) + { + it->second->Delete(); + _lut.erase(it); + } + _lut.insert( std::pair<QString, vtkLookupTable*>(array_name, lut) ); + _activeAttributeName = array_name; + } +} + +void VtkAlgorithmProperties::SetLookUpTable(const QString &array_name, const QString &filename) +{ + VtkColorLookupTable* colorLookupTable = XmlLutReader::readFromFile(filename); + SetLookUpTable(array_name, colorLookupTable); +} + +void VtkAlgorithmProperties::SetScalarVisibility(bool on) +{ + _scalarVisibility = on; + emit ScalarVisibilityChanged(on); +} + +QVariant VtkAlgorithmProperties::GetUserProperty(QString name) const +{ + if (this->_algorithmUserProperties->contains(name)) + return this->_algorithmUserProperties->value(name); + else + { + std::cout << "Not a valid property: " << name.toStdString() << std::endl; + return QVariant(); + } +} + +QList<QVariant> VtkAlgorithmProperties::GetUserVectorProperty(QString name) const +{ + if (this->_algorithmUserVectorProperties->contains(name)) + return this->_algorithmUserVectorProperties->value(name); + else + { + std::cout << "Not a valid property: " << name.toStdString() << std::endl; + return QList<QVariant>(); + } +} diff --git a/Gui/VtkVis/VtkAlgorithmProperties.h b/Gui/VtkVis/VtkAlgorithmProperties.h new file mode 100644 index 0000000000000000000000000000000000000000..56e6d3e0c374fdb50dbfb4c1574d2a20ab040fd6 --- /dev/null +++ b/Gui/VtkVis/VtkAlgorithmProperties.h @@ -0,0 +1,228 @@ +/** + * \file VtkAlgorithmProperties.h + * 24/03/2010 KR Initial implementation + * + */ + +#ifndef VTKALGORITHMPROPERTIES_H +#define VTKALGORITHMPROPERTIES_H + +// ** INCLUDES ** +#include <QList> +#include <QMap> +#include <QObject> +#include <QString> +#include <QVariant> + +class vtkProperty; +class vtkTexture; +class vtkLookupTable; + + +#define ogsUserPropertyMacro(name,type) \ + virtual void Set ## name (type _arg) \ + { \ + vtkDebugMacro( \ + << this->GetClassName() << " (" << this << "): setting " # name " to " << \ + _arg); \ + if (this->name != _arg) \ + { \ + this->name = _arg; \ + this->Modified(); \ + (*(this->_algorithmUserProperties))[QString(# name)] = QVariant(_arg); \ + } \ + } \ +\ + type name; +// End of ogsUserPropertyMacro + +#define ogsUserVec2PropertyMacro(name,type) \ + virtual void Set ## name (type _arg1, type _arg2) \ + { \ + vtkDebugMacro( \ + << this->GetClassName() << " (" << this << "): setting " << \ + # name " to (" << \ + _arg1 << "," << _arg2 << ")"); \ + if ((this->name[0] != _arg1) || (this->name[1] != _arg2)) \ + { \ + this->name[0] = _arg1; \ + this->name[1] = _arg2; \ + this->Modified(); \ + QList<QVariant> list; \ + list.push_back(QVariant(_arg1)); \ + list.push_back(QVariant(_arg2)); \ + (*(this->_algorithmUserVectorProperties))[QString(# name)] = list; \ + } \ + } \ +\ + virtual void Set ## name (type _arg[2]) \ + { \ + this->Set ## name (_arg[0], _arg[1]); \ + } \ +\ + type name[2]; +// End of ogsUserVec2PropertyMacro + +#define ogsUserVec3PropertyMacro(name,type) \ + virtual void Set ## name (type _arg1, type _arg2, type _arg3) \ + { \ + vtkDebugMacro( \ + << this->GetClassName() << " (" << this << "): setting " << \ + # name " to (" << \ + _arg1 << "," << _arg2 << "," << _arg3 << ")"); \ + if ((this->name[0] != _arg1) || (this->name[1] != _arg2) || (this->name[2] != _arg3)) \ + { \ + this->name[0] = _arg1; \ + this->name[1] = _arg2; \ + this->name[2] = _arg3; \ + this->Modified(); \ + QList<QVariant> list; \ + list.push_back(QVariant(_arg1)); \ + list.push_back(QVariant(_arg2)); \ + list.push_back(QVariant(_arg3)); \ + (*(this->_algorithmUserVectorProperties))[QString(# name)] = list; \ + } \ + } \ +\ + virtual void Set ## name (type _arg[3]) \ + { \ + this->Set ## name (_arg[0], _arg[1], _arg[2]); \ + } \ +\ + type name[3]; +// End of ogsUserVec3PropertyMacro + +#define ogsUserVec4PropertyMacro(name,type) \ + virtual void Set ## name (type _arg1, type _arg2, type _arg3, type _arg4) \ + { \ + vtkDebugMacro( \ + << this->GetClassName() << " (" << this << "): setting " << \ + # name " to (" << \ + _arg1 << "," << _arg2 << "," << _arg3 << "," << _arg4 << ")"); \ + if ((this->name[0] != _arg1) || (this->name[1] != _arg2) || \ + (this->name[2] != _arg3) || (this->name[3] != _arg4)) \ + { \ + this->name[0] = _arg1; \ + this->name[1] = _arg2; \ + this->name[2] = _arg3; \ + this->name[3] = _arg4; \ + this->Modified(); \ + QList<QVariant> list; \ + list.push_back(QVariant(_arg1)); \ + list.push_back(QVariant(_arg2)); \ + list.push_back(QVariant(_arg3)); \ + list.push_back(QVariant(_arg4)); \ + (*(this->_algorithmUserVectorProperties))[QString(# name)] = list; \ + } \ + } \ +\ + virtual void Set ## name (type _arg[4]) \ + { \ + this->Set ## name (_arg[0], _arg[1], _arg[2], _arg[3]); \ + } \ +\ + type name[4]; +// End of ogsUserVec4PropertyMacro + +/** + * \brief Contains properties for the visualization of objects as VtkVisPipelineItems + */ +class VtkAlgorithmProperties : public QObject +{ + Q_OBJECT + +public: + /// Constructor (sets default values) + VtkAlgorithmProperties(QObject* parent = NULL); + + virtual ~VtkAlgorithmProperties(); + + /// @brief Returns the vtk properties + vtkProperty* GetProperties() const { return _property; } + + /// @brief Returns a texture (if one has been assigned). + vtkTexture* GetTexture() { return _texture; } + + /// @brief Sets a texture for the VtkVisPipelineItem. + void SetTexture(vtkTexture* t) { _texture = t; } + + /// @brief Returns the colour lookup table (if one has been assigned). + vtkLookupTable* GetLookupTable(const QString& array_name); + + /// @brief Sets a colour lookup table for the given scalar array of the VtkVisPipelineItem. + void SetLookUpTable(const QString &array_name, vtkLookupTable* lut); + + /// Loads a predefined color lookup table from a file for the specified scalar array. + void SetLookUpTable(const QString &array_name, const QString &filename); + + /// @brief Returns the scalar visibility. + bool GetScalarVisibility() const { return _scalarVisibility; } + + /// @brief Sets the scalar visibility. + void SetScalarVisibility(bool on); + + /// @brief Returns the name. This is set to the file path if it is a source algorithm. + QString GetName() const { return _name; } + + /// @brief Sets the name. + void SetName(QString name) { _name = name; } + + /// @brief Is this algorithm removable from the pipeline (view). + bool IsRemovable() const { return _removable; } + + /// @brief Returns a map of user properties. + QMap<QString, QVariant>* GetAlgorithmUserProperties() const { + return _algorithmUserProperties; + } + + /// @brief Returns a map of vector user properties. + QMap<QString, QList<QVariant> >* GetAlgorithmUserVectorProperties() const { + return _algorithmUserVectorProperties; + } + + /// @brief Sets a user property. This should be implemented by subclasses. + virtual void SetUserProperty(QString name, QVariant value) { + (*_algorithmUserProperties)[name] = value; + } + + /// @brief Returns the value of a user property. + QVariant GetUserProperty(QString name) const; + + /// @brief Sets a vector user property. This should be implemented by subclasses. + virtual void SetUserVectorProperty(QString name, QList<QVariant> values) { + (*_algorithmUserVectorProperties)[name] = values; + } + + /// @brief Returns a list of values of a vector user property. + QList<QVariant> GetUserVectorProperty(QString name) const; + + /// @brief Set the active attribute + void SetActiveAttribute(QString name) { _activeAttributeName = name; } + + /// @brief Returns the desired active attribute. + QString GetActiveAttribute() const { return _activeAttributeName; } + + +protected: + + // Properties set on vtkActor + vtkProperty* _property; + vtkTexture* _texture; + + // Properties set on vtkMapper + bool _scalarVisibility; + std::map<QString, vtkLookupTable*> _lut; + + // Properties used in the GUI + QString _name; + QString _activeAttributeName; + bool _removable; + + QMap<QString, QVariant>* _algorithmUserProperties; + QMap<QString, QList<QVariant> >* _algorithmUserVectorProperties; + +signals: + void ScalarVisibilityChanged(bool on); +}; + +#endif // VTKALGORITHMPROPERTIES_H diff --git a/Gui/VtkVis/VtkAlgorithmPropertyCheckbox.cpp b/Gui/VtkVis/VtkAlgorithmPropertyCheckbox.cpp new file mode 100644 index 0000000000000000000000000000000000000000..98f9c7169de7ca666f366da0c1f89fb985a955d7 --- /dev/null +++ b/Gui/VtkVis/VtkAlgorithmPropertyCheckbox.cpp @@ -0,0 +1,31 @@ +/** + * \file VtkAlgorithmPropertyCheckbox.cpp + * 20/10/2010 LB Initial implementation + * + * Implementation of VtkAlgorithmPropertyCheckbox class + */ + +// ** INCLUDES ** +#include "VtkAlgorithmPropertyCheckbox.h" + +#include "VtkAlgorithmProperties.h" + +VtkAlgorithmPropertyCheckbox::VtkAlgorithmPropertyCheckbox(const bool value, + const QString& name, + VtkAlgorithmProperties* algProps, + QWidget* parent /*= 0*/ ) + : QCheckBox(parent), _name(name), _algProps(algProps) +{ + this->setChecked(value); + connect(this, SIGNAL(stateChanged(int)), this, SLOT(setNewValue(int))); +} + +VtkAlgorithmPropertyCheckbox::~VtkAlgorithmPropertyCheckbox() +{ +} + +void VtkAlgorithmPropertyCheckbox::setNewValue( int state ) +{ + bool boolState = (bool)state; + _algProps->SetUserProperty(_name, QVariant(boolState)); +} diff --git a/Gui/VtkVis/VtkAlgorithmPropertyCheckbox.h b/Gui/VtkVis/VtkAlgorithmPropertyCheckbox.h new file mode 100644 index 0000000000000000000000000000000000000000..d6da25deaa9b74852e540a68a103e62512fc792c --- /dev/null +++ b/Gui/VtkVis/VtkAlgorithmPropertyCheckbox.h @@ -0,0 +1,40 @@ +/** + * \file VtkAlgorithmPropertyCheckbox.h + * 20/10/2010 LB Initial implementation + */ + +#ifndef VTKALGORITHMPROPERTIESCHECKBOX_H +#define VTKALGORITHMPROPERTIESCHECKBOX_H + +#include <QCheckBox> + +class VtkAlgorithmProperties; + +/// @brief This checkbox sets a user property on the given VtkAlgorithmProperties +/// object automatically. +class VtkAlgorithmPropertyCheckbox : public QCheckBox +{ + Q_OBJECT + +public: + /// @brief Constructor. + /// @param value The initial check state. + /// @param name The name of the user property to set. + /// @param algProps The VtkAlgorithmProperties object. + /// @param parent The parent widget. + VtkAlgorithmPropertyCheckbox(const bool value, const QString& name, + VtkAlgorithmProperties* algProps, QWidget* parent = 0); + + /// @brief Destructor. + virtual ~VtkAlgorithmPropertyCheckbox(); + +private: + const QString _name; + VtkAlgorithmProperties* _algProps; + +private slots: + /// @brief This slots is automatically called when the checkbox state changed. + void setNewValue(int state); +}; + +#endif // VTKALGORITHMPROPERTIESCHECKBOX_H diff --git a/Gui/VtkVis/VtkAlgorithmPropertyLineEdit.cpp b/Gui/VtkVis/VtkAlgorithmPropertyLineEdit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3403ed9fb546708dff378eee36893595ff5509d5 --- /dev/null +++ b/Gui/VtkVis/VtkAlgorithmPropertyLineEdit.cpp @@ -0,0 +1,48 @@ +/** + * \file VtkAlgorithmPropertyLineEdit.cpp + * 18/10/2010 LB Initial implementation + * + * Implementation of VtkAlgorithmPropertyLineEdit class + */ + +// ** INCLUDES ** +#include "VtkAlgorithmPropertyLineEdit.h" + +#include "VtkAlgorithmProperties.h" + +#include <QDoubleValidator> +#include <QIntValidator> + +VtkAlgorithmPropertyLineEdit::VtkAlgorithmPropertyLineEdit(const QString& contents, + const QString& name, + QVariant::Type type, + VtkAlgorithmProperties* algProps, + QWidget* parent /*= 0*/) + : QLineEdit(contents, parent), _name(name), _algProps(algProps), _type(type) +{ + switch(_type) + { + case QVariant::Double: + this->setValidator(new QDoubleValidator(this)); + break; + + case QVariant::Int: + this->setValidator(new QIntValidator(this)); + + default: + break; + } + + connect(this, SIGNAL(editingFinished()), this, SLOT(setNewValue())); +} + +VtkAlgorithmPropertyLineEdit::~VtkAlgorithmPropertyLineEdit() +{ +} + +void VtkAlgorithmPropertyLineEdit::setNewValue() +{ + QVariant value(this->text()); + if (value.convert(_type)) + _algProps->SetUserProperty(_name, value); +} diff --git a/Gui/VtkVis/VtkAlgorithmPropertyLineEdit.h b/Gui/VtkVis/VtkAlgorithmPropertyLineEdit.h new file mode 100644 index 0000000000000000000000000000000000000000..5f277330a9a08319e68f9d9d43cbcc4db9dd463e --- /dev/null +++ b/Gui/VtkVis/VtkAlgorithmPropertyLineEdit.h @@ -0,0 +1,45 @@ +/** + * \file VtkAlgorithmPropertyLineEdit.h + * 18/10/2010 LB Initial implementation + */ + +#ifndef VTKALGORITHMPROPERTYLINEEDIT_H +#define VTKALGORITHMPROPERTYLINEEDIT_H + +#include <QLineEdit> +#include <QVariant> + +class VtkAlgorithmProperties; +class QString; + +/// @brief This QLineEdit sets a user property on the given VtkAlgorithmProperties +/// object automatically. +class VtkAlgorithmPropertyLineEdit : public QLineEdit +{ + Q_OBJECT + +public: + /// @brief Constructor. + /// @param contents The initial text. + /// @param name The name of the user property to set. + /// @param type The type of the property. + /// @param algProps The VtkAlgorithmProperties object. + /// @param parent The parent widget. + VtkAlgorithmPropertyLineEdit(const QString& contents, + const QString& name, + QVariant::Type type, + VtkAlgorithmProperties* algProps, + QWidget* parent = 0); + virtual ~VtkAlgorithmPropertyLineEdit(); + +private: + const QString _name; + VtkAlgorithmProperties* _algProps; + QVariant::Type _type; + +private slots: + /// @brief This slots is automatically called when the text changed. + void setNewValue(); +}; + +#endif // VTKALGORITHMPROPERTYLINEEDIT_H diff --git a/Gui/VtkVis/VtkAlgorithmPropertyVectorEdit.cpp b/Gui/VtkVis/VtkAlgorithmPropertyVectorEdit.cpp new file mode 100644 index 0000000000000000000000000000000000000000..951f61f8aa038262a195a07b41cb6c49396fcb32 --- /dev/null +++ b/Gui/VtkVis/VtkAlgorithmPropertyVectorEdit.cpp @@ -0,0 +1,72 @@ +/** + * \file VtkAlgorithmPropertyVectorEdit.cpp + * 22/10/2010 LB Initial implementation + * + * Implementation of VtkAlgorithmPropertyVectorEdit class + */ + +// ** INCLUDES ** +#include "VtkAlgorithmPropertyVectorEdit.h" + +#include "VtkAlgorithmProperties.h" + +#include <QDoubleValidator> +#include <QHBoxLayout> +#include <QIntValidator> +#include <QLineEdit> +#include <QSize> + +VtkAlgorithmPropertyVectorEdit::VtkAlgorithmPropertyVectorEdit( const QList<QString> contents, + const QString& name, + QVariant::Type type, + VtkAlgorithmProperties* algProps, + QWidget* parent /*= 0*/ ) + : QWidget(parent), _name(name), _algProps(algProps), _type(type) +{ + QHBoxLayout* layout = new QHBoxLayout; + layout->setSpacing(3); + layout->setContentsMargins(0, 0, 0, 0); + + foreach(QString content, contents) + { + QLineEdit* lineEdit = new QLineEdit(content, this); + layout->addWidget(lineEdit); + + switch(_type) + { + case QVariant::Double: + lineEdit->setValidator(new QDoubleValidator(this)); + break; + + case QVariant::Int: + lineEdit->setValidator(new QIntValidator(this)); + + default: + break; + } + + connect(lineEdit, SIGNAL(editingFinished()), this, SLOT(setNewValue())); + } + + this->setLayout(layout); + this->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); +} + +VtkAlgorithmPropertyVectorEdit::~VtkAlgorithmPropertyVectorEdit() +{ +} + +void VtkAlgorithmPropertyVectorEdit::setNewValue() +{ + QLayout* layout = this->layout(); + QList<QVariant> list; + for (int i = 0; i < layout->count(); ++i) + { + QLineEdit* lineEdit = static_cast<QLineEdit*>(layout->itemAt(i)->widget()); + list.push_back(QVariant(lineEdit->text())); + } + + _algProps->SetUserVectorProperty(_name, list); + + emit editingFinished(); +} diff --git a/Gui/VtkVis/VtkAlgorithmPropertyVectorEdit.h b/Gui/VtkVis/VtkAlgorithmPropertyVectorEdit.h new file mode 100644 index 0000000000000000000000000000000000000000..6a62c83be20b93c809390429d05802c83f461e1b --- /dev/null +++ b/Gui/VtkVis/VtkAlgorithmPropertyVectorEdit.h @@ -0,0 +1,49 @@ +/** + * \file VtkAlgorithmPropertyVectorEdit.h + * 22/10/2010 LB Initial implementation + */ + +#ifndef VTKALGORITHMPROPERTYVECTOREDIT_H +#define VTKALGORITHMPROPERTYVECTOREDIT_H + +#include <QList> +#include <QVariant> +#include <QWidget> + +class VtkAlgorithmProperties; + +/// @brief This edit widget consists of several QLineEdit to set a user vector +/// property on the given VtkAlgorithmProperties object automatically. +class VtkAlgorithmPropertyVectorEdit : public QWidget +{ + Q_OBJECT + +public: + /// @brief Constructor. + /// @param contents The initial values of the text edits. + /// @param name The name of the user property to set. + /// @param type The type of the property. + /// @param algProps The VtkAlgorithmProperties object. + /// @param parent The parent widget. + VtkAlgorithmPropertyVectorEdit(const QList<QString> contents, + const QString& name, + QVariant::Type type, + VtkAlgorithmProperties* algProps, + QWidget* parent = 0); + virtual ~VtkAlgorithmPropertyVectorEdit(); + +private: + const QString _name; + VtkAlgorithmProperties* _algProps; + QVariant::Type _type; + +private slots: + /// @brief This slots is automatically called when the checkbox state changed. + void setNewValue(); + +signals: + /// @brief Is emitted when text of one the line edits changed. + void editingFinished(); +}; + +#endif // VTKALGORITHMPROPERTYVECTOREDIT_H diff --git a/Gui/VtkVis/VtkBGImageSource.cpp b/Gui/VtkVis/VtkBGImageSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4755c9445ca2e28a57129a9c8f4a0344f4c03fb5 --- /dev/null +++ b/Gui/VtkVis/VtkBGImageSource.cpp @@ -0,0 +1,72 @@ +/** + * \file VtkBGImageSource.cpp + * 30/04/2010 KR Initial implementation + * + */ + +// ** INCLUDES ** +#include "VtkBGImageSource.h" +#include "VtkVisHelper.h" + +#include <vtkImageAlgorithm.h> +#include <vtkObjectFactory.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkPlaneSource.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkTexture.h> +#include <vtkImageData.h> +#include <vtkPointData.h> +#include <vtkImageShiftScale.h> + +vtkStandardNewMacro(VtkBGImageSource); +vtkCxxRevisionMacro(VtkBGImageSource, "$Revision$"); + +VtkBGImageSource::VtkBGImageSource() : _origin(0,0), _cellsize(1) +{ +} + +VtkBGImageSource::~VtkBGImageSource() +{ +} + +void VtkBGImageSource::SetRaster(vtkImageAlgorithm *img, double x0, double y0, double scalingFactor) +{ + double range[2]; + img->Update(); + img->GetOutput()->GetPointData()->GetScalars()->GetRange(range); + vtkSmartPointer<vtkImageShiftScale> scale = vtkSmartPointer<vtkImageShiftScale>::New(); + scale->SetInputConnection(img->GetOutputPort()); + scale->SetShift(-range[0]); + scale->SetScale(255.0/(range[1]-range[0])); + scale->SetOutputScalarTypeToUnsignedChar(); + scale->Update(); + + vtkImageData* imageData = scale->GetOutput(); + int dims[3]; + imageData->GetDimensions(dims); + vtkTexture* texture = vtkTexture::New(); + texture->InterpolateOff(); + texture->RepeatOff(); + // texture->EdgeClampOn(); // does not work + texture->SetInput(imageData); + this->SetTexture(texture); + + _origin = std::pair<float, float>(static_cast<float>(x0), static_cast<float>(y0)); + _cellsize = scalingFactor; + + + vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New(); + plane->SetOrigin( _origin.first, _origin.second, -1 ); + plane->SetPoint1( _origin.first + dims[0] * _cellsize, _origin.second, -1 ); + plane->SetPoint2( _origin.first,_origin.second + dims[1] * _cellsize, -1 ); + + this->SetInputConnection(0, plane->GetOutputPort(0)); + this->SetTexture(texture); +} + +void VtkBGImageSource::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); +} diff --git a/Gui/VtkVis/VtkBGImageSource.h b/Gui/VtkVis/VtkBGImageSource.h new file mode 100644 index 0000000000000000000000000000000000000000..336b55c07cce151d4a92ac11f42f76be0227e396 --- /dev/null +++ b/Gui/VtkVis/VtkBGImageSource.h @@ -0,0 +1,44 @@ +/** + * \file VtkBGImageSource.h + * 30/04/2010 KR Initial implementation + * + */ + +#ifndef VTKBGIMAGESOURCE_H +#define VTKBGIMAGESOURCE_H + +// ** INCLUDES ** +#include <vtkTextureMapToPlane.h> + +#include "VtkAlgorithmProperties.h" + +class vtkImageAlgorithm; + +/** + * \brief Uses an image source to create a plane in the 3D with the given + * image texture mapped on it. + */ +class VtkBGImageSource : public vtkTextureMapToPlane, public VtkAlgorithmProperties +{ +public: + /// Create new objects with New() because of VTKs object reference counting. + static VtkBGImageSource* New(); + + vtkTypeRevisionMacro(VtkBGImageSource, vtkTextureMapToPlane); + + /// Sets the raster/image to be used as a texture map + void SetRaster(vtkImageAlgorithm *img, double x0, double y0, double scalingFactor); + + virtual void SetUserProperty(QString name, QVariant value); + +protected: + VtkBGImageSource(); + ~VtkBGImageSource(); + +private: + + std::pair<double, double> _origin; + double _cellsize; +}; + +#endif // VTKBGIMAGESOURCE_H diff --git a/Gui/VtkVis/VtkColorByHeightFilter.cpp b/Gui/VtkVis/VtkColorByHeightFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8f48c6d0c37c1d8ee56b3874d50c8bc54069e506 --- /dev/null +++ b/Gui/VtkVis/VtkColorByHeightFilter.cpp @@ -0,0 +1,109 @@ +/** + * \file VtkColorByHeightFilter.cpp + * 21/04/2010 KR Initial implementation + * + */ + +// ** VTK INCLUDES ** +#include "VtkColorByHeightFilter.h" +#include "VtkColorLookupTable.h" + +#include <vtkCellData.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkLookupTable.h> +#include <vtkObjectFactory.h> +#include <vtkPointData.h> +#include <vtkPolyData.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkFloatArray.h> + +vtkStandardNewMacro(VtkColorByHeightFilter); +vtkCxxRevisionMacro(VtkColorByHeightFilter, "$Revision$"); + +VtkColorByHeightFilter::VtkColorByHeightFilter() +: ColorLookupTable(VtkColorLookupTable::New()), _tableRangeScaling(1.0) +{ +} + +VtkColorByHeightFilter::~VtkColorByHeightFilter() +{ +} + +void VtkColorByHeightFilter::PrintSelf( ostream& os, vtkIndent indent ) +{ + this->Superclass::PrintSelf(os,indent); + + double range[2]; + ColorLookupTable->GetTableRange(range); + os << indent << "== VtkColorByHeightFilter ==" << endl; + os << indent << "Range: " << range[0] << "-" << range[1] << endl; + os << indent << "Interpolation Type:" << ColorLookupTable->getInterpolationType() << endl; +} + +unsigned long VtkColorByHeightFilter::GetMTime() +{ + unsigned long t1, t2; + + t1 = this->Superclass::GetMTime(); + if (this->ColorLookupTable) + { + t2 = this->ColorLookupTable->GetMTime(); + if (t2 > t1) + t1 = t2; + } + return t1; +} +int VtkColorByHeightFilter::RequestData( vtkInformation*, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + vtkPolyData* input = vtkPolyData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkSmartPointer<vtkFloatArray> colors = vtkSmartPointer<vtkFloatArray>::New(); + colors->SetNumberOfComponents(1); + colors->SetName("Colors"); + + // Inserts height values as a new scalar array + size_t nPoints = input->GetNumberOfPoints(); + for (size_t i = 0; i < nPoints; i++) + { + double p[3]; + input->GetPoint(i,p); + colors->InsertNextValue(p[2]); + } + + vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + output->CopyStructure(input); + output->GetPointData()->PassData(input->GetPointData()); + output->GetCellData()->PassData(input->GetCellData()); + output->GetPointData()->AddArray(colors); + output->GetPointData()->SetActiveScalars("Colors"); + + return 1; +} + +void VtkColorByHeightFilter::SetTableRange(double min, double max) +{ + if (min < max) + { + this->_tableRange[0] = min; + this->_tableRange[1] = max; + this->ColorLookupTable->SetTableRange(min, max); + } + else + vtkstd::cout << + "VtkColorByHeightFilter::SetLimits(min, max) - Limits not changed because min value > max value." + << vtkstd::endl; +} + +void VtkColorByHeightFilter::SetTableRangeScaling( double scale ) +{ + this->_tableRangeScaling = scale; + this->ColorLookupTable->SetTableRange( + this->_tableRange[0] * scale, this->_tableRange[1] * scale); +} + diff --git a/Gui/VtkVis/VtkColorByHeightFilter.h b/Gui/VtkVis/VtkColorByHeightFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..f896939a16c0b8300d641ef7d2e564609e31f847 --- /dev/null +++ b/Gui/VtkVis/VtkColorByHeightFilter.h @@ -0,0 +1,77 @@ +/** + * \file VtkColorByHeightFilter.h + * 21/04/2010 KR Initial implementation + * + */ + +#ifndef VTKCOLORBYHEIGHTFILTER_H +#define VTKCOLORBYHEIGHTFILTER_H + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include <vtkPolyDataAlgorithm.h> + +class VtkColorLookupTable; + +/** + * \brief VTK filter object for colouring vtkPolyData objects based on z-coordinates. + * + * This filter class is basically a container for a ColorLookupTable. In fact, you can get the underlying + * ColorLookupTable using the method GetColorLookupTable(). Using this method allows the user to set a number + * of properties on that lookup table such as interpolation method, the range of values over which the lookup + * table is calculated and so on. + * If no range boundaries are explicitly set, the minimum and maximum height value will be calculated from + * the data and set as minimum and maximum value for the lookup table. + * ColorLookupTable must be deleted manually. + * \see VtkCompositeColorByHeightFilter::init() for example usage. + */ +class VtkColorByHeightFilter : public vtkPolyDataAlgorithm, public VtkAlgorithmProperties +{ +public: + /// @brief Create new objects with New() because of VTKs object reference counting. + static VtkColorByHeightFilter* New(); + + vtkTypeRevisionMacro(VtkColorByHeightFilter, vtkPolyDataAlgorithm); + + /// @brief Prints the mesh data to an output stream. + void PrintSelf(ostream& os, vtkIndent indent); + + /// @brief Returns the underlying colour look up table object. + vtkGetObjectMacro(ColorLookupTable,VtkColorLookupTable) + + /// @brief This filter gets updated when the color look-up table was modified. + virtual unsigned long GetMTime(); + + /// @brief Sets user properties. + void SetUserProperty(QString name, QVariant value) + { + Q_UNUSED(name); + Q_UNUSED(value); + } + + /// @brief Sets the boundaries for the color look-up table. + void SetTableRange(double min, double max); + + /// @brief Sets the scaling of the color look-up table boundaries. + /// This is used in VtkVisTabWidget when a parent filter is scaled. + void SetTableRangeScaling(double scale); + +protected: + VtkColorByHeightFilter(); + ~VtkColorByHeightFilter(); + + /// @brief The filter logic. + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + /// @brief Calculates the color lookup table based on set parameters. + VtkColorLookupTable* BuildColorTable(); + + VtkColorLookupTable* ColorLookupTable; + + double _tableRange[2]; + double _tableRangeScaling; +}; + +#endif // VTKCOLORBYHEIGHTFILTER_H diff --git a/Gui/VtkVis/VtkColorLookupTable.cpp b/Gui/VtkVis/VtkColorLookupTable.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9bb936b02877d152cf88d7257bbfaebb8f4d9282 --- /dev/null +++ b/Gui/VtkVis/VtkColorLookupTable.cpp @@ -0,0 +1,176 @@ +/** + * \file VtkColorLookupTable.cpp + * 23/04/2010 KR Initial implementation + * + */ + +#include "VtkColorLookupTable.h" + +#include <Color.h> +#include <cmath> +#include <vtkObjectFactory.h> + +vtkStandardNewMacro(VtkColorLookupTable); +vtkCxxRevisionMacro(VtkColorLookupTable, "$Revision$"); + +VtkColorLookupTable::VtkColorLookupTable() + : _type(VtkColorLookupTable::LINEAR) +{ +} + +VtkColorLookupTable::~VtkColorLookupTable() +{ + for (std::map<double, unsigned char*>::const_iterator it = _dict.begin(); it != _dict.end(); + ++it) + delete it->second; +} + +unsigned char VtkColorLookupTable::linInterpolation(unsigned char a, unsigned char b, + double p) const +{ + return static_cast<unsigned char>(a * (1 - p) + b * p); +} + +unsigned char VtkColorLookupTable::expInterpolation(unsigned char a, + unsigned char b, + double gamma, + double p) const +{ + assert (gamma > 0 && gamma < 4); + return static_cast<unsigned char>((b - a) * pow(p,gamma) + a); +} + +void VtkColorLookupTable::Build() +{ + double range[2]; + this->GetTableRange(range); + const double interval = range[1]-range[0]; + this->SetNumberOfTableValues(ceil(interval)+1); +// const vtkIdType nColours = this->GetNumberOfTableValues(); + if (!_dict.empty()) + { + // make sure that color map starts with the first color in the dictionary + unsigned char startcolor[4] = { 0, 0 , 0 , 0 }; + std::pair<size_t, unsigned char*> lastValue(0, startcolor); + size_t nextIndex(0); + + for (std::map<double, unsigned char*>::const_iterator it = _dict.begin(); it != _dict.end(); ++it) + { + double val = (it->first < range[0]) ? range[0] : ((it->first > range[1]) ? range[1] : it->first); + nextIndex = static_cast<size_t>( floor(val-range[0]) ); + + this->SetTableValue(nextIndex, it->second); + + if ( nextIndex - lastValue.first > 0 ) + for (size_t i = lastValue.first + 1; i < nextIndex; i++) + { + unsigned char int_rgba[4]; + double pos = (i - lastValue.first) / (static_cast<double>(nextIndex - lastValue.first)); + + if (_type == VtkColorLookupTable::LINEAR) + for (size_t j = 0; j < 4; j++) + int_rgba[j] = linInterpolation( (lastValue.second)[j], (it->second)[j], pos); + else if (_type == VtkColorLookupTable::EXPONENTIAL) + for (size_t j = 0; j < 4; j++) + int_rgba[j] = expInterpolation((lastValue.second)[j], (it->second)[j], 0.2, pos); + else // no interpolation + for (size_t j = 0; j < 4; j++) + int_rgba[j] = (lastValue.second)[j]; + + this->SetTableValue(i, int_rgba); + } + + lastValue.first = nextIndex; + lastValue.second = it->second; + } + } + else + vtkLookupTable::Build(); +} + +void VtkColorLookupTable::writeToFile(const std::string &filename) +{ + std::cout << "Writing color table to " << filename << "...."; + std::ofstream out( filename.c_str(), std::ios::out ); + + size_t nColors = this->GetNumberOfTableValues(); + for (size_t i = 0; i < nColors; i++) + { + unsigned char rgba[4]; + this->GetTableValue(i, rgba); + out << i << "\t" << rgba[0] << "\t" << rgba[1] << "\t" << rgba[2] << std::endl; + } + + std::cout << " done." << std::endl; + out.close(); +} + +void VtkColorLookupTable::SetTableValue(vtkIdType indx, unsigned char rgba[4]) +{ + // Check the index to make sure it is valid + if (indx < 0) + { + vtkErrorMacro("Can't set the table value for negative index " << indx); + return; + } + if (indx >= this->NumberOfColors) + { + vtkErrorMacro( + "Index " << indx << " is greater than the number of colors " << + this->NumberOfColors); + return; + } + + unsigned char* _rgba = this->Table->WritePointer(4 * indx,4); + for (size_t i = 0; i < 4; i++) + _rgba[i] = rgba[i]; + + this->InsertTime.Modified(); + this->Modified(); +} + +void VtkColorLookupTable::SetTableValue(vtkIdType indx, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char a) +{ + unsigned char rgba[4]; + rgba[0] = r; + rgba[1] = g; + rgba[2] = b; + rgba[3] = a; + this->SetTableValue(indx,rgba); +} + +void VtkColorLookupTable::GetTableValue(vtkIdType indx, unsigned char rgba[4]) +{ + unsigned char* _rgba; + _rgba = this->Table->GetPointer(indx * 4); + for (size_t i = 0; i < 4; i++) + rgba[i] = _rgba[i]; +} + +void VtkColorLookupTable::setColor(double pos, unsigned char rgba[4]) +{ + unsigned char* dict_rgba = new unsigned char[4]; + for (size_t i = 0; i < 4; i++) + dict_rgba[i] = rgba[i]; + _dict.insert( std::pair<double, unsigned char*>(pos, dict_rgba) ); +} + +void VtkColorLookupTable::getColor(vtkIdType indx, unsigned char rgba[4]) const +{ + indx = + ((indx < this->TableRange[0]) + ? static_cast<vtkIdType>(this->TableRange[0]) + : (indx >=this->TableRange[1] ? static_cast<vtkIdType>(this->TableRange[1]) - 1 : indx)); + indx = + static_cast<size_t>( floor( (indx - this->TableRange[0]) * + (this->NumberOfColors / (this->TableRange[1] - this->TableRange[0])) ) ); + + unsigned char* _rgba; + _rgba = this->Table->GetPointer(indx * 4); + for (size_t i = 0; i < 4; i++) + rgba[i] = _rgba[i]; +} diff --git a/Gui/VtkVis/VtkColorLookupTable.h b/Gui/VtkVis/VtkColorLookupTable.h new file mode 100644 index 0000000000000000000000000000000000000000..fd0d35c00a0c2365134604250f4af355f11b528d --- /dev/null +++ b/Gui/VtkVis/VtkColorLookupTable.h @@ -0,0 +1,112 @@ +/** + * \file VtkColorLookupTable.h + * 23/04/2010 KR Initial implementation + * + */ + +#ifndef VTKCOLORLOOKUPTABLE_H +#define VTKCOLORLOOKUPTABLE_H + +// ** INCLUDES ** +#include <cassert> +#include <map> +#include <vector> +#include <vtkLookupTable.h> + +/** + * \brief Calculates and stores a colour lookup table. + * + * Based on a start colour and an end colour, RGB-values are interpolated and stored in vector of GEOLIB::Color. If no + * colours are set, default values are used for start (blue) and end (red). The number of entries of the colour table can + * be set in the constructor, the default value is 256. If additional colours are inserted into the table using setColor() + * the interpolation will be calculated iteratively between set colour values. Interpolation can be linear (default) or + * exponential. Based on the set range of values, colour values can be retrieved using getColor(). + */ +class VtkColorLookupTable : public vtkLookupTable +{ +public: + /// Interpolation methods + enum LUTType { + NONE = 0, + LINEAR = 1, + EXPONENTIAL = 2, + SIGMOID = 3 // not yet implemented + }; + + static const int DEFAULTMINVALUE = -9999; + static const int DEFAULTMAXVALUE = 9999; + + /// \brief Create new objects with New() because of VTKs object reference counting. + static VtkColorLookupTable* New(); + + vtkTypeRevisionMacro(VtkColorLookupTable,vtkLookupTable); + + /// \brief Builds the colour table based on the previously set parameters. + /// This method should only be called after all options have been set. + void Build(); + + /* \brief Sets the given colour as a constant in the colour lookup table. + * The colour will subsequently be considered in the interpolation process when the lookup table is built. Note that pos is only a + * relative position, i.e. pos in (0,1). The actual position of that colour in the table is dependent on the number of entries set + * the SetRange() method. + */ + void setColor(double pos, unsigned char rgba[4]); + + /* \brief Returns the colour at the given index from the colour lookup table. + * The colour will be interpolated from the colour-dictionary entries before and after this index. + * Make sure that Build() has been called before using this method. + */ + void getColor(vtkIdType indx, unsigned char rgba[4]) const; + + /// Returns the type of interpolation used. + VtkColorLookupTable::LUTType getInterpolationType() const { return _type; } + + /// Sets the type of interpolation. + void setInterpolationType(VtkColorLookupTable::LUTType type) { _type = type; } + + /// Imports a color table from a file. + //void readFromFile(const std::string &filename); + + /// Exports a color table to a file. + void writeToFile(const std::string &filename); + + /** + * Directly load color into lookup table. Use unsigned char values for color + * component specification. Make sure that you've either used the + * Build() method or used SetNumberOfTableValues() prior to using this method. + * This is just a convenience method to use instead of vtkLookupTable::SetTableValue(). + */ + void SetTableValue(vtkIdType indx, unsigned char rgba[4]); + + /// Directly load color into lookup table. + /// This is just a convenience method to use instead of vtkLookupTable::SetTableValue(). + void SetTableValue(vtkIdType indx, + unsigned char r, + unsigned char g, + unsigned char b, + unsigned char a); + + /// Return a rgba color value for the given index into the lookup Table. + /// This is just a convenience method to use instead of vtkLookupTable::GetTableValue(). + void GetTableValue(vtkIdType indx, unsigned char rgba[4]); + +protected: + /// Constructor + VtkColorLookupTable(); + + /// Destructor + ~VtkColorLookupTable(); + +private: + /// Interpolates values linearly. + unsigned char linInterpolation(unsigned char a, unsigned char b, double p) const; + + /// Interpolates values exponentially. gamma should roughly be in [0,4), for gamma=1 interpolation is linear. + unsigned char expInterpolation(unsigned char a, unsigned char b, double gamma, + double p) const; + + std::map<double, unsigned char*> _dict; + LUTType _type; +}; + +#endif // VTKCOLORLOOKUPTABLE_H diff --git a/Gui/VtkVis/VtkCompositeColorByHeightFilter.cpp b/Gui/VtkVis/VtkCompositeColorByHeightFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6d35ffce9c7f88eebcf165948382228ee7f904f --- /dev/null +++ b/Gui/VtkVis/VtkCompositeColorByHeightFilter.cpp @@ -0,0 +1,65 @@ +/** + * \file VtkCompositeColorByHeightFilter.cpp + * 01/11/2010 KR Initial implementation + * + * Implementation of VtkCompositePointToGlyphFilter class + */ + +// ** INCLUDES ** +#include "VtkColorByHeightFilter.h" +#include "VtkColorLookupTable.h" +#include "VtkCompositeColorByHeightFilter.h" + +#include <vtkDataSetSurfaceFilter.h> +#include <vtkSmartPointer.h> +#include <vtkUnstructuredGrid.h> + +VtkCompositeColorByHeightFilter::VtkCompositeColorByHeightFilter( vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm) +{ + this->init(); +} + +void VtkCompositeColorByHeightFilter::init() +{ + this->_inputDataObjectType = VTK_DATA_SET; + this->_outputDataObjectType = VTK_POLY_DATA; + + vtkSmartPointer<vtkDataSetSurfaceFilter> surfaceFilter; + VtkColorByHeightFilter* heightFilter = VtkColorByHeightFilter::New(); + + if (dynamic_cast<vtkUnstructuredGrid*>(_inputAlgorithm->GetOutputDataObject(0))) + { + surfaceFilter = vtkSmartPointer<vtkDataSetSurfaceFilter>::New(); + surfaceFilter->SetInputConnection(_inputAlgorithm->GetOutputPort()); + heightFilter->SetInputConnection(surfaceFilter->GetOutputPort()); + } + else + heightFilter->SetInputConnection(_inputAlgorithm->GetOutputPort()); + + unsigned char a[4] = { 0, 0, 255, 255 }; // blue + unsigned char b[4] = { 0, 255, 0, 255 }; // green + unsigned char c[4] = { 255, 255, 0, 255 }; // yellow + unsigned char d[4] = { 255, 0, 0, 255 }; // red + VtkColorLookupTable* ColorLookupTable = heightFilter->GetColorLookupTable(); + ColorLookupTable->setInterpolationType(VtkColorLookupTable::LINEAR); + ColorLookupTable->setColor(-35, a); + ColorLookupTable->setColor(150, b); // green at about 150m + ColorLookupTable->setColor(450, c); // yellow at about 450m and changing to red from then on + ColorLookupTable->setColor(800, d); + ColorLookupTable->SetTableRange(-35, 800); + ColorLookupTable->Build(); + + // This passes ownership of the ColorLookupTable to VtkVisPointSetItem + heightFilter->SetLookUpTable("P-Colors", ColorLookupTable); + heightFilter->Update(); + + _outputAlgorithm = heightFilter; + _activeAttributeName = heightFilter->GetActiveAttribute(); +} + +void VtkCompositeColorByHeightFilter::SetUserProperty( QString name, QVariant value ) +{ + Q_UNUSED(name); + Q_UNUSED(value); +} diff --git a/Gui/VtkVis/VtkCompositeColorByHeightFilter.h b/Gui/VtkVis/VtkCompositeColorByHeightFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..c6d8cebe1f3ddfeb6e40f182fab526149241d3e1 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeColorByHeightFilter.h @@ -0,0 +1,27 @@ +/** + * \file VtkCompositeColorByHeightFilter.h + * 01/11/2010 KR Initial implementation + */ + +#ifndef VTKCOMPOSITECOLORBYHEIGHTFILTER_H +#define VTKCOMPOSITECOLORBYHEIGHTFILTER_H + +#include "VtkCompositeFilter.h" + +class vtkSphereSource; + +/// @brief This filter colors the input by the points z-value. +class VtkCompositeColorByHeightFilter : public VtkCompositeFilter +{ +public: + VtkCompositeColorByHeightFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositeColorByHeightFilter() {} + + virtual void init(); + + virtual void SetUserProperty(QString name, QVariant value); + +protected: +}; + +#endif // VTKCOMPOSITECOLORBYHEIGHTFILTER_H diff --git a/Gui/VtkVis/VtkCompositeColormapToImageFilter.cpp b/Gui/VtkVis/VtkCompositeColormapToImageFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6eace8d14c2755a314fd497867ead1ad3c0be4c9 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeColormapToImageFilter.cpp @@ -0,0 +1,106 @@ +/** + * \file VtkCompositeColormapToImageFilter.cpp + * 21/10/2010 LB Initial implementation + * + * Implementation of VtkCompositeColormapToImageFilter class + */ + +// ** INCLUDES ** +#include "VtkCompositeColormapToImageFilter.h" + +#include <vtkImageMapToColors.h> +#include <vtkImageData.h> +#include <vtkLookupTable.h> +#include <vtkPointData.h> +#include <vtkSmartPointer.h> + +#include <QSettings> +#include <QFileDialog> + +#include "VtkColorLookupTable.h" +#include "XmlIO/XmlLutReader.h" + +VtkCompositeColormapToImageFilter::VtkCompositeColormapToImageFilter( vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm) +{ + this->init(); +} + +VtkCompositeColormapToImageFilter::~VtkCompositeColormapToImageFilter() +{ +} + +void VtkCompositeColormapToImageFilter::init() +{ + this->_inputDataObjectType = VTK_IMAGE_DATA; + this->_outputDataObjectType = VTK_IMAGE_DATA; + + vtkSmartPointer<VtkColorLookupTable> colormap; + + QWidget* parent = 0; + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName(parent, + "Select color lookup table", + settings.value("lastOpenedLookupTableFileDirectory"). + toString(), + "Lookup table XML files (*.xml);;"); + double range[2]; + dynamic_cast<vtkImageAlgorithm*>(_inputAlgorithm)->GetOutput()->GetPointData()->GetScalars()->GetRange(range); + + if (!fileName.length()==0) + { + colormap = XmlLutReader::readFromFile(fileName); + settings.setValue("lastOpenedLookupTableFileDirectory", fileName); + } + else + { + colormap = vtkSmartPointer<VtkColorLookupTable>::New(); + colormap->SetTableRange(range[0], range[1]); + colormap->SetHueRange(0.0, 0.666); + } + colormap->SetNumberOfTableValues(256); + colormap->Build(); + + colormap->GetTableRange(range); + QList<QVariant> tableRangeList; + tableRangeList.push_back(range[0]); + tableRangeList.push_back(range[1]); + QList<QVariant> hueRangeList; + hueRangeList.push_back(0.0); + hueRangeList.push_back(0.666); + (*_algorithmUserVectorProperties)["TableRange"] = tableRangeList; + (*_algorithmUserVectorProperties)["HueRange"] = hueRangeList; + + vtkImageMapToColors* map = vtkImageMapToColors::New(); + map->SetInputConnection(0, _inputAlgorithm->GetOutputPort()); + map->SetLookupTable(colormap); + map->SetPassAlphaToOutput(1); + (*_algorithmUserProperties)["PassAlphaToOutput"] = true; + (*_algorithmUserProperties)["NumberOfColors"] = 256; + + _outputAlgorithm = map; +} + +void VtkCompositeColormapToImageFilter::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); + + vtkImageMapToColors* map = static_cast<vtkImageMapToColors*>(_outputAlgorithm); + if (name.compare("PassAlphaToOutput") == 0) + map->SetPassAlphaToOutput(value.toBool()); + else if (name.compare("NumberOfColors") == 0) + static_cast<vtkLookupTable*>(map->GetLookupTable())->SetNumberOfTableValues(value.toInt()); +} + +void VtkCompositeColormapToImageFilter::SetUserVectorProperty( QString name, QList<QVariant> values ) +{ + VtkAlgorithmProperties::SetUserVectorProperty(name, values); + + vtkImageMapToColors* map = static_cast<vtkImageMapToColors*>(_outputAlgorithm); + if (name.compare("TableRange") == 0) + static_cast<vtkLookupTable*>(map->GetLookupTable())->SetTableRange( + values[0].toInt(), values[1].toInt()); + else if (name.compare("HueRange") == 0) + static_cast<vtkLookupTable*>(map->GetLookupTable())->SetHueRange(values[0].toDouble(), + values[1].toDouble()); +} diff --git a/Gui/VtkVis/VtkCompositeColormapToImageFilter.h b/Gui/VtkVis/VtkCompositeColormapToImageFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..f9f0821d511801a3a21bce3a718b440ab8479979 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeColormapToImageFilter.h @@ -0,0 +1,27 @@ +/** + * \file VtkCompositeColormapToImageFilter.h + * 21/10/2010 LB Initial implementation + */ + +#ifndef VTKCOMPOSITECOLORMAPTOIMAGEFILTER_H +#define VTKCOMPOSITECOLORMAPTOIMAGEFILTER_H + +#include "VtkCompositeFilter.h" + +/// @brief Applies a user adjustable color map to an image. +class VtkCompositeColormapToImageFilter : public VtkCompositeFilter +{ +public: + VtkCompositeColormapToImageFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositeColormapToImageFilter(); + + virtual void init(); + + virtual void SetUserProperty(QString name, QVariant value); + + virtual void SetUserVectorProperty(QString name, QList<QVariant> values); + +private: +}; + +#endif // VTKCOMPOSITECOLORMAPTOIMAGEFILTER_H diff --git a/Gui/VtkVis/VtkCompositeContourFilter.cpp b/Gui/VtkVis/VtkCompositeContourFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2fd39008a30ed6d215e587de27519f4ca90772d1 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeContourFilter.cpp @@ -0,0 +1,91 @@ +/** + * \file VtkCompositeContourFilter.cpp + * 2011/08/05 KR Initial implementation + */ + +// ** INCLUDES ** +#include "VtkCompositeContourFilter.h" + +#include <vtkPointData.h> +#include <vtkContourFilter.h> +#include <vtkSmartPointer.h> +#include <vtkUnstructuredGrid.h> + +#include <limits> + +VtkCompositeContourFilter::VtkCompositeContourFilter( vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm) +{ + this->init(); +} + +VtkCompositeContourFilter::~VtkCompositeContourFilter() +{ +} + +void VtkCompositeContourFilter::init() +{ + // Set meta information about input and output data types + this->_inputDataObjectType = VTK_UNSTRUCTURED_GRID; //VTK_DATA_SET; + this->_outputDataObjectType = VTK_UNSTRUCTURED_GRID; + + // Because this is the only filter here we cannot use vtkSmartPointer + vtkContourFilter* contour = vtkContourFilter::New(); + contour->SetInputConnection(_inputAlgorithm->GetOutputPort()); + + // Getting the scalar range from the active point data scalar of the input algorithm + // This assumes that we do not want to contour on cell data. + double range[2]; + vtkDataSet* dataSet = vtkDataSet::SafeDownCast(_inputAlgorithm->GetOutputDataObject(0)); + if(dataSet) + { + vtkPointData* pointData = dataSet->GetPointData(); + if(pointData) + pointData->GetScalars()->GetRange(range); + } + else + { + // Setting the range to min / max values, this will result in a "bad table range" + // vtk warning. + range[0] = std::numeric_limits<double>::min(); + range[1] = std::numeric_limits<double>::max(); + } + + // Sets a filter vector property which will be user editable + contour->GenerateValues(10, range[0], range[1]); + + // Create a list for the ThresholdBetween (vector) property. + QList<QVariant> contourRangeList; + // Insert the values (same values as above) + contourRangeList.push_back(range[0]); + contourRangeList.push_back(range[1]); + // Put that list in the property map + (*_algorithmUserVectorProperties)["Range"] = contourRangeList; + + // Make a new entry in the property map for the "Number of Values" property + (*_algorithmUserProperties)["Number of Contours"] = 10; + + // The threshold filter is last one and so it is also the _outputAlgorithm + _outputAlgorithm = contour; +} + +void VtkCompositeContourFilter::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); + + // Use the same name as in init() + if (name.compare("Number of Contours") == 0) + static_cast<vtkContourFilter*>(_outputAlgorithm)->SetNumberOfContours(value.toInt()); +} + +void VtkCompositeContourFilter::SetUserVectorProperty( QString name, QList<QVariant> values ) +{ + VtkAlgorithmProperties::SetUserVectorProperty(name, values); + + // Use the same name as in init() + if (name.compare("Range") == 0) + static_cast<vtkContourFilter*>(_outputAlgorithm)->GenerateValues( + VtkAlgorithmProperties::GetUserProperty("Number of Contours").toInt(), + values[0].toDouble(), + values[1].toDouble()); +} diff --git a/Gui/VtkVis/VtkCompositeContourFilter.h b/Gui/VtkVis/VtkCompositeContourFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..9ec22dacaaf28176ec7712560f1e97b409233eb6 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeContourFilter.h @@ -0,0 +1,29 @@ +/** + * \file VtkCompositeContourFilter.h + * 2011/08/05 KR Initial implementation + */ + +#ifndef VTKCOMPOSITECONTOURFILTER_H +#define VTKCOMPOSITECONTOURFILTER_H + +#include "VtkCompositeFilter.h" + +/// @brief Visualisation of contour-lines/-planes within dense scalar fields. +/// In init() the threshold is first set to double min / max values. Set the +/// threshold later on via SetUserVectorProperty() to the actual data range. +class VtkCompositeContourFilter : public VtkCompositeFilter +{ +public: + VtkCompositeContourFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositeContourFilter(); + + virtual void init(); + + virtual void SetUserProperty(QString name, QVariant value); + + void SetUserVectorProperty( QString name, QList<QVariant> values ); + +private: +}; + +#endif // VTKCOMPOSITECONTOURFILTER_H diff --git a/Gui/VtkVis/VtkCompositeFilter.cpp b/Gui/VtkVis/VtkCompositeFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b650f8eede0fd2af6ef759d08cbc5fd6a8ecdf16 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeFilter.cpp @@ -0,0 +1,26 @@ +/** + * \file VtkCompositeFilter.cpp + * 19/10/2010 LB Initial implementation + * + * Implementation of VtkCompositeFilter class + */ + +// ** INCLUDES ** +#include "VtkCompositeFilter.h" + +#include <vtkAlgorithm.h> + +#include <QMapIterator> +#include <QString> +#include <QVector> + +VtkCompositeFilter::VtkCompositeFilter(vtkAlgorithm* inputAlgorithm) + : _inputDataObjectType(0), _outputDataObjectType(1), + _inputAlgorithm(inputAlgorithm) +{ +} + +VtkCompositeFilter::~VtkCompositeFilter() +{ + _outputAlgorithm->Delete(); +} diff --git a/Gui/VtkVis/VtkCompositeFilter.h b/Gui/VtkVis/VtkCompositeFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..a83e098b16757f8e4a6b39ac3187646defb48a82 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeFilter.h @@ -0,0 +1,70 @@ +/** + * \file VtkCompositeFilter.h + * 19/10/2010 LB Initial implementation + */ + +#ifndef VTKCOMPOSITEFILTER_H +#define VTKCOMPOSITEFILTER_H + +#include "VtkAlgorithmProperties.h" + +class vtkAlgorithm; + +/// @brief Is used to combine several filter in one VtkVisPipelineItem. You can +/// use vtk filter and custom filter. To subclass this you have to implement the +/// init() function. There you combine the filters. Make sure to set the members +/// _inputDataObjectType, _outputDataObjectType and _outputAlgorithm. Make also +/// sure to implement VtkAlgorithmProperties::SetUserProperty() and +/// VtkAlgorithmProperties::SetUserVectorProperty(). +/// +/// Allocate vtk objects inside init() with vtkSmartPointer except for the last +/// filter. This filter must also be set to _outputAlgorithm, e.g. +/// \code +/// MyVtkFilter* lastFilter = MyVtkFilter::New(); +/// ...(do something here) +/// _outputAlgorithm = lastFilter; +/// \endcode +/// +/// Create user properties with ogsUserPropertyMacro or ogsUserVecxPropertyMacro +/// and initialize these properties inside the constructor with +/// this->Set[Property Name](value) +/// See VtkCompositeThresholdFilter for an example. +class VtkCompositeFilter : public VtkAlgorithmProperties +{ +public: + /// @brief Constructor. + /// @param inputAlgorithm The algorithm to attach this filter to. + VtkCompositeFilter(vtkAlgorithm* inputAlgorithm); + + /// @brief Destructor. + virtual ~VtkCompositeFilter(); + + /// @return the type of the data input. + /// Can be compared with + /// - VTK_POLY_DATA + /// - VTK_STRUCTURED_POINTS + /// - VTK_STRUCTURED_GRID + /// - VTK_RECTILINEAR_GRID + /// - VTK_UNSTRUCTURED_GRID + /// - VTK_IMAGE_DATA + /// - VTK_DATA_SET + int GetInputDataObjectType() const { return _inputDataObjectType; } + + /// @return the type of the data output. + int GetOutputDataObjectType() const { return _outputDataObjectType; } + + /// @return the last algorithm in this composite filter. + vtkAlgorithm* GetOutputAlgorithm() const { return _outputAlgorithm; } + +protected: + /// See vtkSetGet.h for the defines + int _inputDataObjectType; + int _outputDataObjectType; + + vtkAlgorithm* _inputAlgorithm; + vtkAlgorithm* _outputAlgorithm; + + virtual void init() = 0; +}; + +#endif // VTKCOMPOSITEFILTER_H diff --git a/Gui/VtkVis/VtkCompositeGeoObjectFilter.cpp b/Gui/VtkVis/VtkCompositeGeoObjectFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d586cd6cd51f527efe48c7031ef687a8ab7a1660 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeGeoObjectFilter.cpp @@ -0,0 +1,97 @@ +/** + * \file VtkCompositeGeoObjectFilter.cpp + * 2011/12/02 KR Initial implementation + * + * Implementation of VtkCompositeGeoObjectFilter class + */ + +// ** INCLUDES ** +#include "VtkCompositeGeoObjectFilter.h" + +#include <vtkDataSetSurfaceFilter.h> +#include <vtkSmartPointer.h> +#include <vtkThreshold.h> +#include <vtkAlgorithmOutput.h> + +#include "VtkPolylinesSource.h" +#include "VtkSurfacesSource.h" +#include "VtkCompositePointToGlyphFilter.h" +#include "VtkCompositeLineToTubeFilter.h" + +#include <vtkPointData.h> + +VtkCompositeGeoObjectFilter::VtkCompositeGeoObjectFilter( vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm), _type(GEOLIB::POINT), _threshold(vtkThreshold::New()) +{ + if (inputAlgorithm->GetNumberOfInputPorts() && inputAlgorithm->GetNumberOfInputConnections(0)) + { + vtkAlgorithmOutput* ao = inputAlgorithm->GetInputConnection(0,0); + + if (ao) + { + vtkAlgorithm* parentAlg = ao->GetProducer(); + + if (dynamic_cast<VtkPolylinesSource*>(parentAlg) != NULL) + _type = GEOLIB::POLYLINE; + else if (dynamic_cast<VtkSurfacesSource*>(parentAlg) != NULL) + _type = GEOLIB::SURFACE; + } + + } + + this->init(); +} + +VtkCompositeGeoObjectFilter::~VtkCompositeGeoObjectFilter() +{ +} + +void VtkCompositeGeoObjectFilter::init() +{ + this->_inputDataObjectType = VTK_POLY_DATA; + this->_outputDataObjectType = VTK_POLY_DATA; + + _threshold->SetInputConnection(_inputAlgorithm->GetOutputPort()); + _threshold->SetSelectedComponent(0); + _threshold->ThresholdBetween(0,0); + + vtkDataSetSurfaceFilter* surface = vtkDataSetSurfaceFilter::New(); + surface->SetInputConnection(_threshold->GetOutputPort()); + + VtkCompositeFilter* composite; + if (_type == GEOLIB::POINT) + { + composite = new VtkCompositePointToGlyphFilter(surface); + composite->SetUserProperty("Radius", this->GetInitialRadius()); + _outputAlgorithm = composite->GetOutputAlgorithm(); + } + else if (_type == GEOLIB::POLYLINE) + { + composite = new VtkCompositeLineToTubeFilter(surface); + composite->SetUserProperty("Radius", this->GetInitialRadius()); + _outputAlgorithm = composite->GetOutputAlgorithm(); + + } + else + _outputAlgorithm = surface; + +} + +void VtkCompositeGeoObjectFilter::SetIndex(size_t idx) +{ + _threshold->ThresholdBetween(idx, idx); +} + +float VtkCompositeGeoObjectFilter::GetInitialRadius() const +{ + double bounding_box[6]; + static_cast<vtkPolyData*>(this->_inputAlgorithm->GetOutputDataObject(0))->GetBounds(bounding_box); + double x_diff = fabs(bounding_box[0]-bounding_box[1]); + double y_diff = fabs(bounding_box[2]-bounding_box[3]); + double z_diff = fabs(bounding_box[4]-bounding_box[5]); + + double max = (x_diff > y_diff) ? x_diff : y_diff; + max = (max > z_diff) ? max : z_diff; + + return max/200.0; +} diff --git a/Gui/VtkVis/VtkCompositeGeoObjectFilter.h b/Gui/VtkVis/VtkCompositeGeoObjectFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..0ab513e3f04022a14569f7c4016c278762b60858 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeGeoObjectFilter.h @@ -0,0 +1,39 @@ +/** + * \file VtkCompositeGeoObjectFilter.h + * 2011/12/02 KR Initial implementation + */ + +#ifndef VTKCOMPOSITEGEOOBJECTFILTER_H +#define VTKCOMPOSITEGEOOBJECTFILTER_H + +#include "VtkCompositeFilter.h" +#include "GeoType.h" + +class vtkThreshold; + +/// @brief Hightlights a single GeoObject +class VtkCompositeGeoObjectFilter : public VtkCompositeFilter +{ +public: + VtkCompositeGeoObjectFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositeGeoObjectFilter(); + + virtual void init(); + + /// @brief Sets user properties. + void SetUserProperty(QString name, QVariant value) + { + Q_UNUSED(name); + Q_UNUSED(value); + } + + void SetIndex(size_t idx); + +private: + float GetInitialRadius() const; + + GEOLIB::GEOTYPE _type; + vtkThreshold* _threshold; +}; + +#endif // VTKCOMPOSITEGEOOBJECTFILTER_H diff --git a/Gui/VtkVis/VtkCompositeImageToCylindersFilter.cpp b/Gui/VtkVis/VtkCompositeImageToCylindersFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f482ffbe622f3551a118751253cbdd5995c9a314 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeImageToCylindersFilter.cpp @@ -0,0 +1,122 @@ +/** + * \file VtkCompositeImageToCylindersFilter.cpp + * 19/10/2010 LB Initial implementation + * + * Implementation of VtkCompositeImageToCylindersFilter class + */ + +// ** INCLUDES ** +#include "VtkCompositeImageToCylindersFilter.h" + +#include "VtkImageDataToLinePolyDataFilter.h" + +#include <vtkLookupTable.h> +#include <vtkPointData.h> +#include <vtkSmartPointer.h> +#include <vtkTubeFilter.h> +#include <vtkUnsignedCharArray.h> + +#include <QMap> +#include <QString> +#include <QVariant> +#include <QVector> + +VtkCompositeImageToCylindersFilter::VtkCompositeImageToCylindersFilter( + vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm) +{ + this->init(); +} + +void VtkCompositeImageToCylindersFilter::init() +{ + this->_inputDataObjectType = VTK_IMAGE_DATA; + this->_outputDataObjectType = VTK_POLY_DATA; + + _lineFilter = VtkImageDataToLinePolyDataFilter::New(); + _lineFilter->SetInputConnection(_inputAlgorithm->GetOutputPort()); + _lineFilter->SetLengthScaleFactor(1); + (*_algorithmUserProperties)["LengthScaleFactor"] = 1.0; + _lineFilter->Update(); + + double range[2]; + // The data is always on points + vtkDataSet::SafeDownCast(_lineFilter->GetOutputDataObject(0))->GetPointData()->GetScalars()->GetRange(range); + + vtkLookupTable* colormap = vtkLookupTable::New(); + colormap->SetTableRange(range[0], range[1]); + colormap->SetHueRange(0.0, 0.666); + colormap->SetNumberOfTableValues(256); + colormap->ForceBuild(); + QList<QVariant> tableRangeList; + tableRangeList.push_back(range[0]); + tableRangeList.push_back(range[1]); + QList<QVariant> hueRangeList; + hueRangeList.push_back(0.0); + hueRangeList.push_back(0.666); + (*_algorithmUserVectorProperties)["TableRange"] = tableRangeList; + (*_algorithmUserVectorProperties)["HueRange"] = hueRangeList; + + this->SetLookUpTable("P-Colors", colormap); + + vtkTubeFilter* tubeFilter = vtkTubeFilter::New(); + tubeFilter->SetInputConnection(_lineFilter->GetOutputPort()); + tubeFilter->CappingOn(); + tubeFilter->SetNumberOfSides(6); + tubeFilter->SetRadius(_lineFilter->GetImageSpacing() * 0.25); + (*_algorithmUserProperties)["NumberOfColors"] = 256; + (*_algorithmUserProperties)["Capping"] = true; + (*_algorithmUserProperties)["NumberOfSides"] = 6; + (*_algorithmUserProperties)["RadiusFactor"] = 0.25; + + _outputAlgorithm = tubeFilter; +} + +void VtkCompositeImageToCylindersFilter::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); + + _lineFilter->SetUserProperty(name, value); + + // VtkImageDataToLinePolyDataFilter is equal to _firstAlgorithm + // vtkTubeFilter is equal _outputAlgorithm + if (name.compare("NumberOfColors") == 0) + { + vtkLookupTable* lut = this->GetLookupTable("P-Colors"); + if(lut) + lut->SetNumberOfTableValues(value.toInt()); + } + else if (name.compare("NumberOfSides") == 0) + static_cast<vtkTubeFilter*>(_outputAlgorithm)->SetNumberOfSides(value.toInt()); + else if (name.compare("Capping") == 0) + static_cast<vtkTubeFilter*>(_outputAlgorithm)->SetCapping(value.toBool()); + else if (name.compare("RadiusFactor") == 0) + static_cast<vtkTubeFilter*>(_outputAlgorithm)->SetRadius( + _lineFilter->GetImageSpacing() * value.toDouble()); +} + +void VtkCompositeImageToCylindersFilter::SetUserVectorProperty( QString name, + QList<QVariant> values ) +{ + VtkAlgorithmProperties::SetUserVectorProperty(name, values); + + _lineFilter->SetUserVectorProperty(name, values); + + if (name.compare("TableRange") == 0) + { + vtkLookupTable* lut = this->GetLookupTable("P-Colors"); + if(lut) + lut->SetTableRange(values[0].toDouble(), values[1].toDouble()); + } + else if (name.compare("HueRange") == 0) + { + vtkLookupTable* lut = this->GetLookupTable("P-Colors"); + if(lut) + lut->SetHueRange(values[0].toDouble(), values[1].toDouble()); + } +} + +VtkCompositeImageToCylindersFilter::~VtkCompositeImageToCylindersFilter() +{ + _lineFilter->Delete(); +} diff --git a/Gui/VtkVis/VtkCompositeImageToCylindersFilter.h b/Gui/VtkVis/VtkCompositeImageToCylindersFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..b696fee158dc22466f7c298334d86e5fde262ca5 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeImageToCylindersFilter.h @@ -0,0 +1,32 @@ +/** + * \file VtkCompositeImageToCylindersFilter.h + * 19/10/2010 LB Initial implementation + */ + +#ifndef VTKCOMPOSITEIMAGETOCYLINDERSFILTER_H +#define VTKCOMPOSITEIMAGETOCYLINDERSFILTER_H + +#include "VtkCompositeFilter.h" + +class VtkImageDataToLinePolyDataFilter; + +/// @brief Creates cylinders that stand on top of the image with the length +/// of the corresponding first sub-pixel value (the red value). Useful to +/// visualize precipitation maps as a 3d bar chart. +class VtkCompositeImageToCylindersFilter : public VtkCompositeFilter +{ +public: + VtkCompositeImageToCylindersFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositeImageToCylindersFilter(); + + virtual void init(); + + virtual void SetUserProperty(QString name, QVariant value); + + void SetUserVectorProperty( QString name, QList<QVariant> values ); + +private: + VtkImageDataToLinePolyDataFilter* _lineFilter; +}; + +#endif // VTKCOMPOSITEIMAGETOCYLINDERSFILTER_H diff --git a/Gui/VtkVis/VtkCompositeLineToTubeFilter.cpp b/Gui/VtkVis/VtkCompositeLineToTubeFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8eb9efa1d985f3257aeb2c0d47c1a75e27b5c0b0 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeLineToTubeFilter.cpp @@ -0,0 +1,80 @@ +/** + * \file VtkCompositeLineToTubeFilter.cpp + * 18/11/2010 KR Initial implementation + * + * Implementation of VtkCompositeLineToTubeFilter class + */ + +// ** INCLUDES ** +#include "VtkCompositeLineToTubeFilter.h" + +#include <vtkCleanPolyData.h> +#include <vtkSmartPointer.h> +#include <vtkTubeFilter.h> + +VtkCompositeLineToTubeFilter::VtkCompositeLineToTubeFilter( vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm) +{ + this->init(); +} + +VtkCompositeLineToTubeFilter::~VtkCompositeLineToTubeFilter() +{ +} + +void VtkCompositeLineToTubeFilter::init() +{ + this->_inputDataObjectType = VTK_DATA_SET; + this->_outputDataObjectType = VTK_POLY_DATA; + + // collapse coincident points + vtkSmartPointer<vtkCleanPolyData> mergePoints = vtkSmartPointer<vtkCleanPolyData>::New(); + mergePoints->SetInputConnection(0, _inputAlgorithm->GetOutputPort(0)); + mergePoints->SetTolerance(0.0); + mergePoints->ConvertLinesToPointsOn(); + + double default_radius(GetInitialRadius()); + int default_number_of_sides(8); + vtkTubeFilter* tubes = vtkTubeFilter::New(); + tubes->SetInputConnection(0, mergePoints->GetOutputPort(0)); + + //tubes->SetInputArrayToProcess(1,0,0,vtkDataObject::FIELD_ASSOCIATION_CELLS,"StationValue"); + //tubes->SetVaryRadiusToVaryRadiusByScalar(); // KR radius changes with scalar + + tubes->SetInputArrayToProcess(1,0,0,vtkDataObject::FIELD_ASSOCIATION_CELLS,"Stratigraphies"); + tubes->SetRadius(default_radius); + tubes->SetNumberOfSides(default_number_of_sides); + tubes->SetCapping(1); + + (*_algorithmUserProperties)["Radius"] = default_radius; + (*_algorithmUserProperties)["NumberOfSides"] = default_number_of_sides; + (*_algorithmUserProperties)["Capping"] = true; + + _outputAlgorithm = tubes; +} + +void VtkCompositeLineToTubeFilter::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); + + if (name.compare("Radius") == 0) + static_cast<vtkTubeFilter*>(_outputAlgorithm)->SetRadius(value.toDouble()); + else if (name.compare("NumberOfSides") == 0) + static_cast<vtkTubeFilter*>(_outputAlgorithm)->SetNumberOfSides(value.toInt()); + else if (name.compare("Capping") == 0) + static_cast<vtkTubeFilter*>(_outputAlgorithm)->SetCapping(value.toBool()); +} + +float VtkCompositeLineToTubeFilter::GetInitialRadius() const +{ + double bounding_box[6]; + static_cast<vtkPolyData*>(this->_inputAlgorithm->GetOutputDataObject(0))->GetBounds(bounding_box); + double x_diff = fabs(bounding_box[0]-bounding_box[1]); + double y_diff = fabs(bounding_box[2]-bounding_box[3]); + double z_diff = fabs(bounding_box[4]-bounding_box[5]); + + double max = (x_diff > y_diff) ? x_diff : y_diff; + max = (max > z_diff) ? max : z_diff; + + return max/200.0; +} diff --git a/Gui/VtkVis/VtkCompositeLineToTubeFilter.h b/Gui/VtkVis/VtkCompositeLineToTubeFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..10b6b6603e32f193be16fa205adcf5a62519647e --- /dev/null +++ b/Gui/VtkVis/VtkCompositeLineToTubeFilter.h @@ -0,0 +1,26 @@ +/** + * \file VtkCompositeLineToTubeFilter.h + * 18/11/2010 KR Initial implementation + */ + +#ifndef VTKCOMPOSITELINETOTUBEFILTER_H +#define VTKCOMPOSITELINETOTUBEFILTER_H + +#include "VtkCompositeFilter.h" + +/// @brief Converts lines to tube-objects. +class VtkCompositeLineToTubeFilter : public VtkCompositeFilter +{ +public: + VtkCompositeLineToTubeFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositeLineToTubeFilter(); + + virtual void init(); + + virtual void SetUserProperty(QString name, QVariant value); + +private: + float GetInitialRadius() const; +}; + +#endif // VTKCOMPOSITELINETOTUBEFILTER_H diff --git a/Gui/VtkVis/VtkCompositePointToGlyphFilter.cpp b/Gui/VtkVis/VtkCompositePointToGlyphFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a520ab5177fbb778870b6ca344cc570cf6a6aa8 --- /dev/null +++ b/Gui/VtkVis/VtkCompositePointToGlyphFilter.cpp @@ -0,0 +1,102 @@ +/** + * \file VtkCompositePointToGlyphFilter.cpp + * 21/10/2010 LB Initial implementation + * + * Implementation of VtkCompositePointToGlyphFilter class + */ + +// ** INCLUDES ** +#include "VtkCompositePointToGlyphFilter.h" + +#include <vtkDataSetAlgorithm.h> +#include <vtkGlyph3D.h> +#include <vtkPointData.h> +#include <vtkSphereSource.h> + +VtkCompositePointToGlyphFilter::VtkCompositePointToGlyphFilter( vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm) +{ + this->init(); +} + +VtkCompositePointToGlyphFilter::~VtkCompositePointToGlyphFilter() +{ + _glyphSource->Delete(); +} + +void VtkCompositePointToGlyphFilter::init() +{ + this->_inputDataObjectType = VTK_DATA_SET; + this->_outputDataObjectType = VTK_POLY_DATA; + + size_t nPoints = static_cast<vtkDataSetAlgorithm*>(_inputAlgorithm) + ->GetOutput()->GetPointData()->GetNumberOfTuples(); + int phi (10 - static_cast<size_t>(nPoints / 2000.0)); + int theta (phi); + if (phi < 4) + { + phi = 4; + theta = 4; // for theta 3 would be possible, too, but 4 looks much better + } + + double default_radius(GetInitialRadius()); + _glyphSource = vtkSphereSource::New(); + _glyphSource->SetRadius(default_radius); + _glyphSource->SetPhiResolution(phi); + _glyphSource->SetThetaResolution(theta); + (*_algorithmUserProperties)["Radius"] = default_radius; + + (*_algorithmUserProperties)["PhiResolution"] = phi; + (*_algorithmUserProperties)["ThetaResolution"] = theta; + + vtkGlyph3D* glyphFilter = vtkGlyph3D::New(); + glyphFilter->ScalingOn(); // KR important to scale glyphs with double precision (e.g. 0.1 of their size for small datasets) + //glyphFilter->SetScaleModeToScaleByScalar(); // KR can easily obscure view when scalar values have large differences (this is also the default scaling method) + glyphFilter->SetScaleModeToDataScalingOff(); // KR scaling is possible but scalar values are ignored + glyphFilter->SetScaleFactor(1.0); + glyphFilter->SetSource(_glyphSource->GetOutput()); + glyphFilter->SetInputConnection(_inputAlgorithm->GetOutputPort()); + //(*_algorithmUserProperties)["ScaleMode"] = 0; + //(*_algorithmUserProperties)["ScaleFactor"] = 1.0; + //(*_algorithmUserProperties)["ColorMode"] = glyphFilter->GetColorMode(); + //(*_algorithmUserProperties)["VectorMode"] = glyphFilter->GetVectorMode(); + //(*_algorithmUserProperties)["Orient"] = glyphFilter->GetOrient(); + + _outputAlgorithm = glyphFilter; +} + +void VtkCompositePointToGlyphFilter::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); + + if (name.compare("Radius") == 0) + _glyphSource->SetRadius(value.toDouble()); + else if (name.compare("PhiResolution") == 0) + _glyphSource->SetPhiResolution(value.toInt()); + else if (name.compare("ThetaResolution") == 0) + _glyphSource->SetThetaResolution(value.toInt()); + else if (name.compare("ScaleMode") == 0) + static_cast<vtkGlyph3D*>(_outputAlgorithm)->SetScaleMode(value.toInt()); + else if (name.compare("ScaleFactor") == 0) + static_cast<vtkGlyph3D*>(_outputAlgorithm)->SetScaleFactor(value.toDouble()); + else if (name.compare("ColorMode") == 0) + static_cast<vtkGlyph3D*>(_outputAlgorithm)->SetColorMode(value.toInt()); + else if (name.compare("VectorMode") == 0) + static_cast<vtkGlyph3D*>(_outputAlgorithm)->SetVectorMode(value.toInt()); + else if (name.compare("Orient") == 0) + static_cast<vtkGlyph3D*>(_outputAlgorithm)->SetOrient(value.toBool()); +} + +float VtkCompositePointToGlyphFilter::GetInitialRadius() const +{ + double bounding_box[6]; + static_cast<vtkPolyData*>(this->_inputAlgorithm->GetOutputDataObject(0))->GetBounds(bounding_box); + double x_diff = fabs(bounding_box[0]-bounding_box[1]); + double y_diff = fabs(bounding_box[2]-bounding_box[3]); + double z_diff = fabs(bounding_box[4]-bounding_box[5]); + + double max = (x_diff > y_diff) ? x_diff : y_diff; + max = (max > z_diff) ? max : z_diff; + + return max/100.0; +} diff --git a/Gui/VtkVis/VtkCompositePointToGlyphFilter.h b/Gui/VtkVis/VtkCompositePointToGlyphFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..dedd0a438550e48943f7dbed442a4ccfb1dc7438 --- /dev/null +++ b/Gui/VtkVis/VtkCompositePointToGlyphFilter.h @@ -0,0 +1,30 @@ +/** + * \file VtkCompositePointToGlyphFilter.h + * 21/10/2010 LB Initial implementation + */ + +#ifndef VTKCOMPOSITEPOINTTOGLYPHFILTER_H +#define VTKCOMPOSITEPOINTTOGLYPHFILTER_H + +#include "VtkCompositeFilter.h" + +class vtkSphereSource; + +/// @brief Converts point data to scalar-scaled spheres. +class VtkCompositePointToGlyphFilter : public VtkCompositeFilter +{ +public: + VtkCompositePointToGlyphFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositePointToGlyphFilter(); + + virtual void init(); + + virtual void SetUserProperty(QString name, QVariant value); + +private: + float GetInitialRadius() const; + + vtkSphereSource* _glyphSource; +}; + +#endif // VTKCOMPOSITEPOINTTOGLYPHFILTER_H diff --git a/Gui/VtkVis/VtkCompositeSelectionFilter.cpp b/Gui/VtkVis/VtkCompositeSelectionFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d902bc82628700f00f116a53b0d3ceb7fa7ebfd --- /dev/null +++ b/Gui/VtkVis/VtkCompositeSelectionFilter.cpp @@ -0,0 +1,76 @@ +/** + * \file VtkCompositeSelectionFilter.cpp + * 2011/02/10 KR Initial implementation + * + * Implementation of VtkCompositeSelectionFilter class + */ + +// ** INCLUDES ** +#include "VtkCompositeSelectionFilter.h" +#include "VtkSelectionFilter.h" +#include "VtkColorLookupTable.h" + +#include <vtkDataSetSurfaceFilter.h> +#include <vtkSmartPointer.h> +#include <vtkThreshold.h> +#include <vtkUnstructuredGrid.h> + +VtkCompositeSelectionFilter::VtkCompositeSelectionFilter( vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm) +{ + //this->init(); +} + +void VtkCompositeSelectionFilter::init() +{ + const char* filter_name("Selection"); + double thresholdLower(0.0), thresholdUpper(1.0); + this->_inputDataObjectType = VTK_UNSTRUCTURED_GRID; + this->_outputDataObjectType = VTK_UNSTRUCTURED_GRID; + + this->SetLookUpTable(QString(filter_name), this->GetLookupTable()); + + VtkSelectionFilter* selFilter = VtkSelectionFilter::New(); + selFilter->SetInputConnection(_inputAlgorithm->GetOutputPort()); + selFilter->SetSelectionArray(_selection, thresholdLower, thresholdUpper); + selFilter->Update(); + + vtkThreshold* threshold = vtkThreshold::New(); + threshold->SetInputConnection(selFilter->GetOutputPort()); + threshold->SetInputArrayToProcess(0,0,0,vtkDataObject::FIELD_ASSOCIATION_CELLS, filter_name); + threshold->SetSelectedComponent(0); + threshold->ThresholdBetween(thresholdLower, thresholdUpper); + threshold->Update(); + + QList<QVariant> thresholdRangeList; + thresholdRangeList.push_back(0.0); + thresholdRangeList.push_back(1.0); + (*_algorithmUserVectorProperties)["Threshold Between"] = thresholdRangeList; + + _outputAlgorithm = threshold; +} + +void VtkCompositeSelectionFilter::SetUserVectorProperty( QString name, QList<QVariant> values) +{ + VtkAlgorithmProperties::SetUserVectorProperty(name, values); + + if (name.compare("Threshold Between") == 0) + static_cast<vtkThreshold*>(_outputAlgorithm)->ThresholdBetween( + values[0].toDouble(), values[1].toDouble()); +} + +VtkColorLookupTable* VtkCompositeSelectionFilter::GetLookupTable() +{ + VtkColorLookupTable* lut = VtkColorLookupTable::New(); + lut->SetTableRange(0,1); + unsigned char a[4] = { 0, 0, 255, 255 }; // blue + unsigned char b[4] = { 0, 255, 0, 255 }; // green + unsigned char c[4] = { 255, 255, 0, 255 }; // yellow + unsigned char d[4] = { 255, 0, 0, 255 }; // red + lut->setColor(1.0, a); + lut->setColor(0.5, b); + lut->setColor(0.25, c); + lut->setColor(0.1, d); + lut->Build(); + return lut; +} diff --git a/Gui/VtkVis/VtkCompositeSelectionFilter.h b/Gui/VtkVis/VtkCompositeSelectionFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..ff76d6df863e0aa3f6ca29050766279f2e6c91f8 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeSelectionFilter.h @@ -0,0 +1,36 @@ +/** + * \file VtkCompositeSelectionFilter.h + * 2011/02/10 KR Initial implementation + */ + +#ifndef VTKCOMPOSITESELECTIONFILTER_H +#define VTKCOMPOSITESELECTIONFILTER_H + +#include "VtkCompositeFilter.h" + +#include <vector> + +class VtkColorLookupTable; + +/// @brief This filter colors the input by the points z-value. +class VtkCompositeSelectionFilter : public VtkCompositeFilter +{ +public: + VtkCompositeSelectionFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositeSelectionFilter() {} + + virtual void init(); + + void setSelectionArray(std::vector<double> selection) { _selection = selection; + init(); } + + virtual void SetUserVectorProperty(QString name, QList<QVariant> values); + +private: + /// Returns a colour lookup table optimised for quality measures + VtkColorLookupTable* GetLookupTable(); + + std::vector<double> _selection; +}; + +#endif // VTKCOMPOSITESELECTIONFILTER_H diff --git a/Gui/VtkVis/VtkCompositeTextureOnSurfaceFilter.cpp b/Gui/VtkVis/VtkCompositeTextureOnSurfaceFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..30b79d59b9484aef582e55f93d8f0d455a78923d --- /dev/null +++ b/Gui/VtkVis/VtkCompositeTextureOnSurfaceFilter.cpp @@ -0,0 +1,105 @@ +/** + * \file VtkCompositeTextureOnSurfaceFilter.cpp + * 18/11/2010 KR Initial implementation + * + * Implementation of VtkCompositeTextureOnSurfaceFilter class + */ + +// ** INCLUDES ** +#include "VtkCompositeTextureOnSurfaceFilter.h" +#include "VtkTextureOnSurfaceFilter.h" +#include <vtkDataSetSurfaceFilter.h> +#include <vtkSmartPointer.h> +#include <vtkUnstructuredGrid.h> +#include "VtkGeoImageSource.h" +#include "VtkRaster.h" +#include "NetCdfConfigureDialog.h" + +#include <QFileDialog> +#include <QFileInfo> +#include <QSettings> + +//#include "VtkCompositeColormapToImageFilter.h" + + +VtkCompositeTextureOnSurfaceFilter::VtkCompositeTextureOnSurfaceFilter( + vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm) +{ + this->init(); +} + +VtkCompositeTextureOnSurfaceFilter::~VtkCompositeTextureOnSurfaceFilter() +{ +} + +void VtkCompositeTextureOnSurfaceFilter::init() +{ + this->_inputDataObjectType = VTK_DATA_SET; + this->_outputDataObjectType = VTK_POLY_DATA; + + vtkSmartPointer<vtkDataSetSurfaceFilter> surfaceFilter; + VtkTextureOnSurfaceFilter* surface = VtkTextureOnSurfaceFilter::New(); + + if (dynamic_cast<vtkUnstructuredGrid*>(_inputAlgorithm->GetOutputDataObject(0))) + { + surfaceFilter = vtkSmartPointer<vtkDataSetSurfaceFilter>::New(); + surfaceFilter->SetInputConnection(_inputAlgorithm->GetOutputPort()); + surface->SetInputConnection(surfaceFilter->GetOutputPort()); + } + else + surface->SetInputConnection(_inputAlgorithm->GetOutputPort()); + + QWidget* parent = 0; + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName(parent, + "Select raster file to apply as texture", + settings.value("lastOpenedTextureFileDirectory"). + toString(), + "Raster files (*.asc *.grd *.bmp *.jpg *.png *.tif);;NetCDF files (*.nc);;"); + QFileInfo fi(fileName); + + if ((fi.suffix().toLower() == "asc") || (fi.suffix().toLower() == "tif") || + (fi.suffix().toLower() == "png") || (fi.suffix().toLower() == "grd") || + (fi.suffix().toLower() == "jpg") || (fi.suffix().toLower() == "bmp")) + { + double x0(0), y0(0), scalingFactor(1); + std::string name = fileName.toStdString(); + vtkImageAlgorithm* image = VtkRaster::loadImage(name, x0, y0, scalingFactor); + surface->SetRaster(image, x0, y0, scalingFactor); + surface->Update(); + + QDir dir = QDir(fileName); + settings.setValue("lastOpenedTextureFileDirectory", dir.absolutePath()); + } + else if (fi.suffix().toLower() == "nc") + { + NetCdfConfigureDialog dlg(fileName.toStdString().c_str()); + dlg.exec(); + if (dlg.getRaster() != NULL) + { + VtkGeoImageSource* image = dlg.getRaster(); + double origin[3]; + image->GetOutput()->GetOrigin(origin); + double spacing[3]; + image->GetOutput()->GetSpacing(spacing); +/* + VtkCompositeColormapToImageFilter* cm = new VtkCompositeColormapToImageFilter(image); + vtkImageAlgorithm* img = dynamic_cast<vtkImageAlgorithm*>(cm->GetOutputAlgorithm()); +*/ + surface->SetRaster(image, origin[0], origin[1], spacing[0]); + surface->Update(); + } + } + else + std::cout << + "VtkCompositeTextureOnSurfaceFilter.init() - Error reading texture file..." << + std::endl; + + _outputAlgorithm = surface; +} + +void VtkCompositeTextureOnSurfaceFilter::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); +} diff --git a/Gui/VtkVis/VtkCompositeTextureOnSurfaceFilter.h b/Gui/VtkVis/VtkCompositeTextureOnSurfaceFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..f269351f6b6b23f3ec068687dc8b5f472848c6a2 --- /dev/null +++ b/Gui/VtkVis/VtkCompositeTextureOnSurfaceFilter.h @@ -0,0 +1,27 @@ +/** + * \file VtkCompositeTextureOnSurfaceFilter.h + * 18/11/2010 KR Initial implementation + */ + +#ifndef VTKCOMPOSITETEXTUREONSURFACEFILTER_H +#define VTKCOMPOSITETEXTUREONSURFACEFILTER_H + +#include "VtkCompositeFilter.h" + +class vtkSphereSource; + +/// @brief Puts a texture on an object (and converts it into a vtkPolyData if necessary). +class VtkCompositeTextureOnSurfaceFilter : public VtkCompositeFilter +{ +public: + VtkCompositeTextureOnSurfaceFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositeTextureOnSurfaceFilter(); + + virtual void init(); + + virtual void SetUserProperty(QString name, QVariant value); + +private: +}; + +#endif // VTKCOMPOSITETEXTUREONSURFACEFILTER_H diff --git a/Gui/VtkVis/VtkCompositeThresholdFilter.cpp b/Gui/VtkVis/VtkCompositeThresholdFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..544b6289a170027571f6f2ae94d1df38c0e903ff --- /dev/null +++ b/Gui/VtkVis/VtkCompositeThresholdFilter.cpp @@ -0,0 +1,88 @@ +/** + * \file VtkCompositeThresholdFilter.cpp + * 25/10/2010 LB Initial implementation + * + * Implementation of VtkCompositeThresholdFilter class + */ + +// ** INCLUDES ** +#include "VtkCompositeThresholdFilter.h" + +#include <vtkCellData.h> +#include <vtkThreshold.h> +#include <vtkUnstructuredGrid.h> +#include <vtkIntArray.h> +#include <vtkSmartPointer.h> + +#include <limits> + +VtkCompositeThresholdFilter::VtkCompositeThresholdFilter( vtkAlgorithm* inputAlgorithm ) + : VtkCompositeFilter(inputAlgorithm) +{ + this->init(); +} + +VtkCompositeThresholdFilter::~VtkCompositeThresholdFilter() +{ +} + +void VtkCompositeThresholdFilter::init() +{ + // Set meta information about input and output data types + this->_inputDataObjectType = VTK_DATA_SET; + this->_outputDataObjectType = VTK_UNSTRUCTURED_GRID; + + // Because this is the only filter here we cannot use vtkSmartPointer + vtkThreshold* threshold = vtkThreshold::New(); + threshold->SetInputConnection(_inputAlgorithm->GetOutputPort()); + + // Sets a filter property which will be user editable + threshold->SetSelectedComponent(0); + + // Setting the threshold to min / max values to ensure that the whole data + // is first processed. This is needed for correct lookup table generation. + const double dMin = std::numeric_limits<double>::min(); + const double dMax = std::numeric_limits<double>::max(); + threshold->ThresholdBetween(dMin, dMax); + + // Create a list for the ThresholdBetween (vector) property. + QList<QVariant> thresholdRangeList; + // Insert the values (same values as above) + thresholdRangeList.push_back(dMin); + thresholdRangeList.push_back(dMax); + // Put that list in the property map + (*_algorithmUserVectorProperties)["Range"] = thresholdRangeList; + + // Make a new entry in the property map for the SelectedComponent property + (*_algorithmUserProperties)["Selected Component"] = 0; + + // Must all scalars match the criterium + threshold->SetAllScalars(1); + (*_algorithmUserProperties)["Evaluate all points"] = true; + + // The threshold filter is last one and so it is also the _outputAlgorithm + _outputAlgorithm = threshold; +} + +void VtkCompositeThresholdFilter::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); + + // Use the same name as in init() + if (name.compare("Selected Component") == 0) + // Set the property on the algorithm + static_cast<vtkThreshold*>(_outputAlgorithm)->SetSelectedComponent(value.toInt()); + else if (name.compare("Evaluate all points") == 0) + static_cast<vtkThreshold*>(_outputAlgorithm)->SetAllScalars(value.toBool()); +} + +void VtkCompositeThresholdFilter::SetUserVectorProperty( QString name, QList<QVariant> values ) +{ + VtkAlgorithmProperties::SetUserVectorProperty(name, values); + + // Use the same name as in init() + if (name.compare("Range") == 0) + // Set the vector property on the algorithm + static_cast<vtkThreshold*>(_outputAlgorithm)->ThresholdBetween( + values[0].toDouble(), values[1].toDouble()); +} diff --git a/Gui/VtkVis/VtkCompositeThresholdFilter.h b/Gui/VtkVis/VtkCompositeThresholdFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..acdfe7c460c45d26013bd0a378f1f6fee0bd832b --- /dev/null +++ b/Gui/VtkVis/VtkCompositeThresholdFilter.h @@ -0,0 +1,29 @@ +/** + * \file VtkCompositeThresholdFilter.h + * 25/10/2010 LB Initial implementation + */ + +#ifndef VTKCOMPOSITETHRESHOLDFILTER_H +#define VTKCOMPOSITETHRESHOLDFILTER_H + +#include "VtkCompositeFilter.h" + +/// @brief Visualises only parts of meshes that are above/below/within given thresholds. +/// In init() the threshold is first set to double min / max values. Set the +/// threshold later on via SetUserVectorProperty() to the actual data range. +class VtkCompositeThresholdFilter : public VtkCompositeFilter +{ +public: + VtkCompositeThresholdFilter(vtkAlgorithm* inputAlgorithm); + virtual ~VtkCompositeThresholdFilter(); + + virtual void init(); + + virtual void SetUserProperty(QString name, QVariant value); + + void SetUserVectorProperty( QString name, QList<QVariant> values ); + +private: +}; + +#endif // VTKCOMPOSITETHRESHOLDFILTER_H diff --git a/Gui/VtkVis/VtkConditionSource.cpp b/Gui/VtkVis/VtkConditionSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1d26f5f595d410cd0f5536f14401cc8f07c5ddc5 --- /dev/null +++ b/Gui/VtkVis/VtkConditionSource.cpp @@ -0,0 +1,324 @@ +/** + * \file VtkConditionSource.cpp + * 2011/03/02 KR Initial implementation + */ + +// ** INCLUDES ** +#include "AxisAlignedBoundingBox.h" +#include "FEMCondition.h" +#include "VtkConditionSource.h" + +#include <vtkCellArray.h> +#include <vtkDoubleArray.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkObjectFactory.h> +#include <vtkPointData.h> +#include <vtkPoints.h> +#include <vtkPolyData.h> +#include <vtkPolygon.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkProperty.h> + +#include <vtkLookupTable.h> + +vtkStandardNewMacro(VtkConditionSource); +vtkCxxRevisionMacro(VtkConditionSource, "$Revision$"); + +VtkConditionSource::VtkConditionSource() + : _points(NULL), _cond_vec(NULL) +{ + this->SetNumberOfInputPorts(0); + + const GEOLIB::Color* c = GEOLIB::getRandomColor(); + GetProperties()->SetColor((*c)[0] / 255.0,(*c)[1] / 255.0,(*c)[2] / 255.0); +} + +VtkConditionSource::~VtkConditionSource() +{ +} + +void VtkConditionSource::setData(const std::vector<GEOLIB::Point*>* points, + const std::vector<FEMCondition*>* conds) +{ + _removable = false; // From VtkAlgorithmProperties + _points = points; + _cond_vec = conds; +} + +void VtkConditionSource::PrintSelf( ostream& os, vtkIndent indent ) +{ + this->Superclass::PrintSelf(os,indent); + + if (_points->size() == 0) + return; + + os << indent << "== VtkConditionSource ==" << "\n"; +} + +int VtkConditionSource::RequestData( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + if (this->_points->empty() || this->_cond_vec->empty()) + return 0; + + vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New(); + vtkSmartPointer<vtkInformation> outInfo = outputVector->GetInformationObject(0); + vtkSmartPointer<vtkPolyData> output = + vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkSmartPointer<vtkIdTypeArray> distypes = vtkSmartPointer<vtkIdTypeArray>::New(); + distypes->SetNumberOfComponents(1); + distypes->SetName("DisTypes"); + + vtkSmartPointer<vtkDoubleArray> scalars = vtkSmartPointer<vtkDoubleArray>::New(); + scalars->SetNumberOfComponents(1); + scalars->SetName("Scalars"); + //std::map<size_t, size_t> idx_map; + + vtkSmartPointer<vtkCellArray> newVerts = vtkSmartPointer<vtkCellArray>::New(); + vtkSmartPointer<vtkCellArray> newLines = vtkSmartPointer<vtkCellArray>::New(); + vtkSmartPointer<vtkCellArray> newPolys = vtkSmartPointer<vtkCellArray>::New(); + + if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) + return 1; + /* + size_t n_pnts = _points->size(); + double value(-9999); + if (!_cond_vec->empty()) + { + const std::vector<double> dv = (*_cond_vec)[0]->getDisValue(); + value = dv[dv.size()-1]; // get an existing value for the distribution so scaling on point data will be correct during rendering process! + } + + for (size_t i = 0; i < n_pnts; i++) + { + double coords[3] = {(*(*_points)[i])[0], (*(*_points)[i])[1], (*(*_points)[i])[2]}; + newPoints->InsertNextPoint(coords); + distypes->InsertNextValue(0); + scalars->InsertNextValue(value); + } + */ + vtkIdType pnt_id = 0; + size_t nCond = _cond_vec->size(); + for (size_t n = 0; n < nCond; n++) + { + FiniteElement::DistributionType type = (*_cond_vec)[n]->getProcessDistributionType(); + const std::vector<size_t> dis_nodes = (*_cond_vec)[n]->getDisNodes(); + const std::vector<double> dis_values = (*_cond_vec)[n]->getDisValues(); + + vtkIdType dis_type_value(0); + std::map<FiniteElement::DistributionType, vtkIdType>::const_iterator it(_dis_type_map.find(type)); + if (it == _dis_type_map.end()) + { + dis_type_value = static_cast<vtkIdType>(_dis_type_map.size()); + _dis_type_map.insert(std::pair<FiniteElement::DistributionType, size_t>(type, dis_type_value)); + } + else dis_type_value = it->second; + + if ((*_cond_vec)[n]->getGeoType() == GEOLIB::POINT) + { + /* + size_t nPoints = _points->size(); + const GEOLIB::Point* pnt = + static_cast<const GEOLIB::Point*>((*_cond_vec)[n]->getGeoObj()); + int id(-1); + for (size_t i = 0; i < nPoints; i++) + if ((*_points)[i] == pnt) + { + id = static_cast<int>(i); //(this->getIndex(i, newPoints, scalars, idx_map)); + vtkIdType vtk_id = static_cast<vtkIdType>(id); + */ + const GEOLIB::Point* pnt = static_cast<const GEOLIB::Point*>((*_cond_vec)[n]->getGeoObj()); + newPoints->InsertNextPoint(pnt->getData()); + + newVerts->InsertNextCell(1, &pnt_id); + if (type == FiniteElement::CONSTANT || type == FiniteElement::CONSTANT_NEUMANN) + scalars->InsertNextValue(dis_values[0]); + else scalars->InsertNextValue(0); + distypes->InsertNextValue(dis_type_value); + pnt_id++; + /* + break; + } + if (id == -1) + std::cout << + "Error in VtkConditionSource::RequestData() - Point object not found ..." + << std::endl; + */ + } + else if ((*_cond_vec)[n]->getGeoType() == GEOLIB::POLYLINE) + { + const GEOLIB::Polyline* ply = static_cast<const GEOLIB::Polyline*>((*_cond_vec)[n]->getGeoObj()); + const int nPoints = ply->getNumberOfPoints(); + newLines->InsertNextCell(nPoints); + double value (0); + for (int i = 0; i < nPoints; i++) + { + size_t point_index = ply->getPointID(i); + + newPoints->InsertNextPoint((*_points)[point_index]->getData()); + newLines->InsertCellPoint(pnt_id); + distypes->InsertNextValue(dis_type_value); + + if (type == FiniteElement::CONSTANT || type == FiniteElement::CONSTANT_NEUMANN) + scalars->InsertNextValue(dis_values[0]); + else if (type == FiniteElement::LINEAR || type == FiniteElement::LINEAR_NEUMANN) + { + for (size_t j = 0; j < dis_values.size(); j ++) + { + if (static_cast<int>(dis_nodes[j]) == i) + value = dis_values[j]; + } + scalars->InsertNextValue(value); + } + else + scalars->InsertNextValue(0); + pnt_id++; + } + } + else if ((*_cond_vec)[n]->getGeoType() == GEOLIB::SURFACE) + { + std::vector<int> point_idx_map(_points->size(), -1); + + const GEOLIB::Surface* sfc = + static_cast<const GEOLIB::Surface*>((*_cond_vec)[n]->getGeoObj()); + + const size_t nTriangles = sfc->getNTriangles(); + + for (size_t i = 0; i < nTriangles; i++) + { + vtkPolygon* aPolygon = vtkPolygon::New(); + aPolygon->GetPointIds()->SetNumberOfIds(3); + + const GEOLIB::Triangle* triangle = (*sfc)[i]; + for (size_t j = 0; j < 3; j++) + { + size_t point_index ((*triangle)[j]); + + if (point_idx_map[point_index] == -1) + { + point_idx_map[point_index] = pnt_id; + newPoints->InsertNextPoint((*_points)[point_index]->getData()); + aPolygon->GetPointIds()->SetId(j, pnt_id); + distypes->InsertNextValue(dis_type_value); + + if (type == FiniteElement::CONSTANT || type == FiniteElement::CONSTANT_NEUMANN) + scalars->InsertNextValue(dis_values[0]); + else if (type == FiniteElement::LINEAR || type == FiniteElement::LINEAR_NEUMANN) + { + for (size_t k = 0; k < dis_values.size(); k++) + if (static_cast<size_t>(dis_nodes[j]) == point_index) + { + scalars->InsertNextValue(dis_values[j]); + break; + } + } + else scalars->InsertNextValue(0); + pnt_id++; + } + else + aPolygon->GetPointIds()->SetId(j, static_cast<vtkIdType>(point_idx_map[point_index])); + } + newPolys->InsertNextCell(aPolygon); + + aPolygon->Delete(); + } + } + // HACK: this is currently used when applying DIRECT conditions + else if ((*_cond_vec)[n]->getGeoType() == GEOLIB::INVALID) + { + size_t nValues = dis_values.size(); + for (size_t i=0; i<nValues; i++) + { + //vtkIdType pid = newPoints->InsertNextPoint((*_points)[dis_nodes[i]]->getData()); + vtkIdType pid = newPoints->InsertNextPoint((*_points)[i]->getData()); + newVerts->InsertNextCell(1, &pid); + scalars->InsertNextValue(dis_values[i]); + distypes->InsertNextValue(dis_type_value); + pnt_id++; + } + } + // draw a bounding box in case of of the conditions is "domain" + else if ((*_cond_vec)[n]->getGeoType() == GEOLIB::GEODOMAIN) + { + GEOLIB::AABB bounding_box (_points); + std::vector<GEOLIB::Point> box; + box.push_back(bounding_box.getMinPoint()); + box.push_back(bounding_box.getMaxPoint()); + + vtkIdType nPoints = newPoints->GetNumberOfPoints(); + //size_t pnt_idx = _points->size(); + + for (size_t i = 0; i < 8; i++) + { + double coords[3] = + {box[i % 2][0], box[(i >> 1) % 2][1], box[i >> 2][2]}; + newPoints->InsertNextPoint(coords); + distypes->InsertNextValue(dis_type_value); + scalars->InsertNextValue(0.0); + //idx_map.insert( std::pair<size_t,size_t>(pnt_idx+i, nPoints+i)); + } + + for (size_t i = 0; i < 4; i++) + { + vtkIdType a[2] = {nPoints + i, nPoints + i + 4}; + vtkIdType b[2] = {nPoints + (i * 2), nPoints + (i * 2 + 1)}; + vtkIdType c[2] = {nPoints + (static_cast<int>(i / 2) * 4 + (i % 2)), nPoints + (static_cast<int>(i / 2) * 4 + (i % 2) + 2)}; + newLines->InsertNextCell(2, &a[0]); + newLines->InsertNextCell(2, &b[0]); + newLines->InsertNextCell(2, &c[0]); + } + } + } + + output->SetPoints(newPoints); + output->GetPointData()->AddArray(distypes); + output->GetPointData()->AddArray(scalars); + output->GetPointData()->SetActiveScalars("Scalars"); + output->SetVerts(newVerts); + output->SetLines(newLines); + output->SetPolys(newPolys); + + return 1; +} + +int VtkConditionSource::RequestInformation( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + vtkInformation* outInfo = outputVector->GetInformationObject(0); + outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1); + + return 1; +} + +void VtkConditionSource::SetUserProperty( QString name, QVariant value ) +{ + Q_UNUSED(name); + Q_UNUSED(value); +} + +/* + size_t VtkConditionSource::getIndex(size_t idx, vtkSmartPointer<vtkPoints> newPoints, vtkSmartPointer<vtkDoubleArray> scalars, std::map<size_t, size_t> &idx_map) + { + std::map<size_t,size_t>::iterator mapped_index = idx_map.find(idx); + if (mapped_index != idx_map.end()) return mapped_index->second; + + double coords[3] = {(*(*_points)[idx])[0], (*(*_points)[idx])[1], (*(*_points)[idx])[2]}; + newPoints->InsertNextPoint(coords); + scalars->InsertNextValue(0.0); + size_t new_idx = idx_map.size(); + idx_map.insert( std::pair<size_t,size_t>(idx, new_idx) ); + std::cout << idx << ", " << new_idx << std::endl; + return new_idx; + } + */ diff --git a/Gui/VtkVis/VtkConditionSource.h b/Gui/VtkVis/VtkConditionSource.h new file mode 100644 index 0000000000000000000000000000000000000000..04c15eba7bdf496fe4778a61f78698c8dae88bfb --- /dev/null +++ b/Gui/VtkVis/VtkConditionSource.h @@ -0,0 +1,63 @@ +/** + * \file VtkConditionSource.h + * 2011/03/02 KR Initial implementation + * + */ + +#ifndef VTKCONDITIONSOURCE_H +#define VTKCONDITIONSOURCE_H + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include <vtkPolyDataAlgorithm.h> + +#include "GEOObjects.h" +//#include <vtkSmartPointer.h> + +class FEMCondition; +//class vtkPoints; +//class vtkDoubleArray; + +/** + * \brief VtkConditionSource is a VTK source object for the visualization + * of FEM conditions. As a vtkPolyDataAlgorithm it outputs polygonal data. + */ +class VtkConditionSource : public vtkPolyDataAlgorithm, public VtkAlgorithmProperties +{ +public: + /// Create new objects with New() because of VTKs object reference counting. + static VtkConditionSource* New(); + + vtkTypeRevisionMacro(VtkConditionSource,vtkPolyDataAlgorithm); + + /// Sets the FEMCondition that need to be visualised. The geometry points array is needed because polylines and surfaces are linked to this data. + void setData(const std::vector<GEOLIB::Point*>* points, + const std::vector<FEMCondition*>* conds); + + /// Prints its data on a stream. + void PrintSelf(ostream& os, vtkIndent indent); + + virtual void SetUserProperty(QString name, QVariant value); + +protected: + VtkConditionSource(); + ~VtkConditionSource(); + + /// Computes the polygonal data object. + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + int RequestInformation(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + +private: + //size_t getIndex(size_t idx, vtkSmartPointer<vtkPoints> newPoints, vtkSmartPointer<vtkDoubleArray> scalars, std::map<size_t, size_t> &idx_map); + + const std::vector<GEOLIB::Point*>* _points; + const std::vector<FEMCondition*>* _cond_vec; + std::map<FiniteElement::DistributionType, vtkIdType> _dis_type_map; +}; + +#endif // VTKCONDITIONSOURCE_H diff --git a/Gui/VtkVis/VtkFilterFactory.cpp b/Gui/VtkVis/VtkFilterFactory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e3d22317ad63d97445c027913df5226263d7b205 --- /dev/null +++ b/Gui/VtkVis/VtkFilterFactory.cpp @@ -0,0 +1,137 @@ +/** + * \file VtkFilterFactory.cpp + * 20/10/2010 LB Initial implementation + * + * Implementation of VtkFilterFactory class + */ + +// ** INCLUDES ** +#include "VtkFilterFactory.h" + +#include "VtkCompositeColorByHeightFilter.h" +#include "VtkCompositeColormapToImageFilter.h" +#include "VtkCompositeContourFilter.h" +#include "VtkCompositeGeoObjectFilter.h" +#include "VtkCompositeImageToCylindersFilter.h" +#include "VtkCompositeLineToTubeFilter.h" +#include "VtkCompositePointToGlyphFilter.h" +#include "VtkCompositeSelectionFilter.h" +#include "VtkCompositeTextureOnSurfaceFilter.h" +#include "VtkCompositeThresholdFilter.h" +#include "VtkImageDataToLinePolyDataFilter.h" + +#include <vtkDataSetSurfaceFilter.h> + +const QVector<VtkFilterInfo> VtkFilterFactory::GetFilterList() +{ + QVector<VtkFilterInfo> filterList; + + // Composite filters + filterList.push_back(VtkFilterInfo( + "VtkCompositeImageToCylindersFilter", + "Image to bar chart", + "This filter converts the red pixel values of the image into a bar graph.", + VTK_IMAGE_DATA, VTK_POLY_DATA)); + + filterList.push_back(VtkFilterInfo( + "VtkCompositePointToGlyphFilter", + "Points to spheres", + "This filter generates spheres on point data that can be scaled and colored by scalar data.", + VTK_POLY_DATA, VTK_POLY_DATA)); + + filterList.push_back(VtkFilterInfo( + "VtkCompositeLineToTubeFilter", + "Lines to tubes", + "This filter will convert lines to tubes that can be colored by scalar data.", + VTK_POLY_DATA, VTK_POLY_DATA)); + + filterList.push_back(VtkFilterInfo( + "VtkCompositeColormapToImageFilter", + "Apply lookup table to image", + "This filter will take an input image of any valid scalar type, and map the first component of the image through a lookup table.", + VTK_IMAGE_DATA, VTK_IMAGE_DATA)); + + filterList.push_back(VtkFilterInfo( + "VtkCompositeTextureOnSurfaceFilter", + "Apply texture to surface", + "This filter assigns an image or raster file as a texture for the given surface.", + VTK_POINT_SET, VTK_POLY_DATA)); + + filterList.push_back(VtkFilterInfo( + "VtkCompositeThresholdFilter", + "Extract cells by threshold", + "This filter extracts cells from any dataset type that satisfy a threshold criterion. A cell satisfies the criterion if the (first) scalar value of (every or any) point satisfies the criterion. For example this can be used to show only certain material groups in a mesh.", + VTK_POINT_SET, VTK_UNSTRUCTURED_GRID)); + + filterList.push_back(VtkFilterInfo( + "VtkCompositeColorByHeightFilter", + "Elevation-based colouring", + "This filter will generate scalar values based on the elevation of each point in the dataset.", + VTK_POINT_SET, VTK_POLY_DATA)); + + filterList.push_back(VtkFilterInfo( + "VtkCompositeContourFilter", + "Generate contours based on scalar fields", + "Visualisation of contour-lines/-planes within dense scalar fields.", + VTK_UNSTRUCTURED_GRID, VTK_UNSTRUCTURED_GRID)); + + // Simple filters + filterList.push_back(VtkFilterInfo( + "VtkImageDataToLinePolyDataFilter", + "Image to vertical lines", + "This filter converts the red pixel values of the image to lines with length of the value.", + VTK_IMAGE_DATA, VTK_POLY_DATA)); + + // Standard VTK filter without properties + filterList.push_back(VtkFilterInfo( + "vtkDataSetSurfaceFilter", + "Surface filter", + "Extracts outer (polygonal) surface.", + VTK_UNSTRUCTURED_GRID, VTK_POLY_DATA)); + +// filterList.push_back(VtkFilterInfo( +// "VtkCompositeSelectionFilter", +// "Mesh Quality Filter", +// "This filter calculates the quality of meshes and highlights deformed elements.", +// VTK_UNSTRUCTURED_GRID, VTK_UNSTRUCTURED_GRID)); + + return filterList; +} + +VtkCompositeFilter* VtkFilterFactory::CreateCompositeFilter( QString type, + vtkAlgorithm* inputAlgorithm ) +{ + if (type.compare(QString("VtkCompositeImageToCylindersFilter")) == 0) + return new VtkCompositeImageToCylindersFilter(inputAlgorithm); + else if (type.compare(QString("VtkCompositePointToGlyphFilter")) == 0) + return new VtkCompositePointToGlyphFilter(inputAlgorithm); + else if (type.compare(QString("VtkCompositeLineToTubeFilter")) == 0) + return new VtkCompositeLineToTubeFilter(inputAlgorithm); + else if (type.compare(QString("VtkCompositeColormapToImageFilter")) == 0) + return new VtkCompositeColormapToImageFilter(inputAlgorithm); + else if (type.compare(QString("VtkCompositeTextureOnSurfaceFilter")) == 0) + return new VtkCompositeTextureOnSurfaceFilter(inputAlgorithm); + else if (type.compare(QString("VtkCompositeThresholdFilter")) == 0) + return new VtkCompositeThresholdFilter(inputAlgorithm); + else if (type.compare(QString("VtkCompositeColorByHeightFilter")) == 0) + return new VtkCompositeColorByHeightFilter(inputAlgorithm); + else if (type.compare(QString("VtkCompositeSelectionFilter")) == 0) + return new VtkCompositeSelectionFilter(inputAlgorithm); + else if (type.compare(QString("VtkCompositeContourFilter")) == 0) + return new VtkCompositeContourFilter(inputAlgorithm); + else if (type.compare(QString("VtkCompositeGeoObjectFilter")) == 0) + return new VtkCompositeGeoObjectFilter(inputAlgorithm); + + else + return NULL; +} + +vtkAlgorithm* VtkFilterFactory::CreateSimpleFilter( QString type ) +{ + if (type.compare(QString("VtkImageDataToLinePolyDataFilter")) == 0) + return VtkImageDataToLinePolyDataFilter::New(); + if (type.compare(QString("vtkDataSetSurfaceFilter")) == 0) + return vtkDataSetSurfaceFilter::New(); + + return NULL; +} diff --git a/Gui/VtkVis/VtkFilterFactory.h b/Gui/VtkVis/VtkFilterFactory.h new file mode 100644 index 0000000000000000000000000000000000000000..1c5f093fca9ad8cbb51ed9de9b567cb4f67fbcfe --- /dev/null +++ b/Gui/VtkVis/VtkFilterFactory.h @@ -0,0 +1,88 @@ +/** + * \file VtkFilterFactory.h + * 20/10/2010 LB Initial implementation + */ + +#ifndef VTKFILTERFACTORY_H +#define VTKFILTERFACTORY_H + +#include <QString> +#include <QVector> +#include <vtkSetGet.h> + +class VtkCompositeFilter; +class vtkAlgorithm; +struct VtkFilterInfo; + +/// @brief Creates registered filter objects by name. +class VtkFilterFactory +{ +public: + //VtkFilterFactory(); + //virtual ~VtkFilterFactory(); + + /// @brief Returns all registered filters. + /// New VtkCompositeFilter or filter inherited from VtkAlgorithmProperties + /// must be registered here. + static const QVector<VtkFilterInfo> GetFilterList(); + + /// @brief Creates a composite filter by name. + static VtkCompositeFilter* CreateCompositeFilter(QString type, vtkAlgorithm* inputAlgorithm); + + /// @brief Creates a normal filter name. + static vtkAlgorithm* CreateSimpleFilter(QString type); +}; + +/// @brief Holds meta information about a filter +struct VtkFilterInfo +{ + /// @brief Constructor. + /// @param name The name of the filter (the class name) + /// @param readableName + /// @param description A short description of what the filter does + /// @param inputDataObjectType The input data type (see OutputDataObjectTypeAsString()) + /// @param outputDataObjectType The output data type (see OutputDataObjectTypeAsString()) + VtkFilterInfo(QString name, QString readableName, QString description, + int inputDataObjectType, int outputDataObjectType) + { + this->name = name; + this->readableName = readableName; + this->description = description; + this->inputDataObjectType = inputDataObjectType; + this->outputDataObjectType = outputDataObjectType; + } + + /// @brief Default constructor. + VtkFilterInfo() + { + this->name = QString(); + this->readableName = QString(); + this->description = QString(); + this->inputDataObjectType = -1; + this->outputDataObjectType = -1; + } + + /// @brief Returns the data type as a string. + QString OutputDataObjectTypeAsString() const + { + switch (outputDataObjectType) + { + case VTK_POLY_DATA: return QString("vtkPolyData"); + case VTK_STRUCTURED_POINTS: return QString("vtkStructuredPoints"); + case VTK_STRUCTURED_GRID: return QString("vtkStructuredGrid"); + case VTK_RECTILINEAR_GRID: return QString("vtkRectilinearGrid"); + case VTK_UNSTRUCTURED_GRID: return QString("vtkUnstructuredGrid"); + case VTK_IMAGE_DATA: return QString("vtkImageData"); + case VTK_DATA_SET: return QString("vtkDataSet"); + default: return QString("Data type not defined!"); + } + } + + QString name; + QString readableName; + QString description; + int inputDataObjectType; + int outputDataObjectType; +}; + +#endif // VTKFILTERFACTORY_H diff --git a/Gui/VtkVis/VtkGeoImageSource.cpp b/Gui/VtkVis/VtkGeoImageSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1ee5e8dd0d46c0b81e81871914f2fc328796a5ea --- /dev/null +++ b/Gui/VtkVis/VtkGeoImageSource.cpp @@ -0,0 +1,126 @@ +/** + * \file VtkGeoImageSource.cpp + * 28/09/2010 LB Initial implementation + * + * Implementation of VtkGeoImageSource class + */ + +// ** INCLUDES ** +#include "VtkGeoImageSource.h" + +//#include "OGSRaster.h" +#include "VtkRaster.h" + +#include <vtkFloatArray.h> +#include <vtkImageChangeInformation.h> +#include <vtkImageData.h> +#include <vtkImageImport.h> +#include <vtkImageShiftScale.h> +#include <vtkObjectFactory.h> +#include <vtkPointData.h> +#include <vtkIntArray.h> + +vtkStandardNewMacro(VtkGeoImageSource); + +// This function is copied from the vtkSimpleImageFilterExample.cpp +// +// The switch statement in Execute will call this method with +// the appropriate input type (IT). Note that this example assumes +// that the output data type is the same as the input data type. +// This is not always the case. +template <class IT> +void vtkSimpleImageFilterExampleExecute(vtkImageData* input, + vtkImageData* output, + IT* inPtr, IT* outPtr) +{ + int dims[3]; + input->GetDimensions(dims); + if (input->GetScalarType() != output->GetScalarType()) + { + vtkGenericWarningMacro(<< "Execute: input ScalarType, " << input->GetScalarType() + << ", must match out ScalarType " << output->GetScalarType()); + return; + } + // HACK LB Multiply by number of scalar components due to RGBA values ????? + int size = dims[0] * dims[1] * dims[2] * input->GetNumberOfScalarComponents(); + + for(int i = 0; i < size; i++) + outPtr[i] = inPtr[i]; +} + +VtkGeoImageSource::VtkGeoImageSource() +: _imageSource(NULL), _x0(0), _y0(0), _z0(0), _spacing(1) +{ +} + +VtkGeoImageSource::~VtkGeoImageSource() +{ + if(_imageSource) _imageSource->Delete(); +} + +void VtkGeoImageSource::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); +} + +void VtkGeoImageSource::readImage(const QString &filename) +{ + this->setImage(VtkRaster::loadImage(filename.toStdString(), _x0, _y0, _spacing), filename, _x0, _y0, _spacing); +} + +void VtkGeoImageSource::setImage(vtkImageAlgorithm* image, const QString &name, double x0, double y0, double spacing) +{ + this->_imageSource = image; + this->SetInputConnection(_imageSource->GetOutputPort()); + this->SetName(name); + _x0 = x0; _y0 = y0; _z0 = -10; _spacing = spacing; + + this->GetOutput()->SetOrigin(_x0, _y0, _z0); + this->GetOutput()->SetSpacing(_spacing, _spacing, _spacing); +} + +vtkImageData* VtkGeoImageSource::getImageData() +{ + return this->_imageSource->GetImageDataInput(0); +} + +void VtkGeoImageSource::getOrigin(double origin[3]) const +{ + origin[0] = this->_x0; + origin[1] = this->_y0; + origin[2] = this->_z0; +} + +double VtkGeoImageSource::getSpacing() const +{ + return this->_spacing; +} + +void VtkGeoImageSource::getRange(double range[2]) +{ + this->_imageSource->Update(); + _imageSource->GetOutput()->GetPointData()->GetArray(0)->GetRange(range); +} + +void VtkGeoImageSource::SimpleExecute(vtkImageData* input, vtkImageData* output) +{ + vtkDebugMacro(<< "Executing VtkGeoImageSource") + void* inPtr = input->GetScalarPointer(); + void* outPtr = output->GetScalarPointer(); + switch(output->GetScalarType()) + { + // This is simply a #define for a big case list. + // It handles all data types that VTK supports. + vtkTemplateMacro(vtkSimpleImageFilterExampleExecute( + input, output, (VTK_TT*)(inPtr), (VTK_TT*)(outPtr))); + default: + vtkGenericWarningMacro("Execute: Unknown input ScalarType"); + return; + } +} + +void VtkGeoImageSource::SetUserProperty( QString name, QVariant value ) +{ + Q_UNUSED(name); + Q_UNUSED(value); +} diff --git a/Gui/VtkVis/VtkGeoImageSource.h b/Gui/VtkVis/VtkGeoImageSource.h new file mode 100644 index 0000000000000000000000000000000000000000..3e12f7ab926d623b3bb5e8c21f8d4aaf5eb65c8d --- /dev/null +++ b/Gui/VtkVis/VtkGeoImageSource.h @@ -0,0 +1,70 @@ +/** + * \file VtkGeoImageSource.h + * 28/09/2010 LB Initial implementation + */ + +#ifndef VTKGEOIMAGESOURCE_H +#define VTKGEOIMAGESOURCE_H + +#include "VtkAlgorithmProperties.h" +#include <vtkSimpleImageToImageFilter.h> + +class QString; +class QPointF; +class QImage; +class vtkQImageToImageSource; +class vtkImageShiftScale; +class vtkImageData; + + +class VtkGeoImageSource : public vtkSimpleImageToImageFilter, public VtkAlgorithmProperties +{ +public: + /// @brief Create new objects with New() because of VTKs reference counting. + static VtkGeoImageSource* New(); + + vtkTypeMacro(VtkGeoImageSource, vtkSimpleImageToImageFilter); + + /// @brief Prints information about itself. + void PrintSelf(ostream& os, vtkIndent indent); + + /// @brief Returns the ImageData object. + vtkImageData* getImageData(); + + /// @brief Reads an image from file. + void readImage(const QString &filename); + + /// @brief Imports an existing image object. + void setImage(vtkImageAlgorithm* img, const QString &name, double x0, double y0, double spacing); + + /// @brief Returns the origin in world coordinates. + void getOrigin(double origin[3]) const; + + /// @brief Returns the scalar data range. + void getRange(double range[2]); + + /// @brief Returns the spacing betweeen two pixels. + double getSpacing() const; + + virtual void SetUserProperty(QString name, QVariant value); + +protected: + /// @brief Constructor. + VtkGeoImageSource(); + + /// @brief Destructor. + virtual ~VtkGeoImageSource(); + + /// @brief Filter execution. + virtual void SimpleExecute(vtkImageData* input, vtkImageData* output); + +private: + VtkGeoImageSource(const VtkGeoImageSource&); // Not implemented. + void operator=(const VtkGeoImageSource&); // Not implemented + + vtkImageAlgorithm* _imageSource; + + double _x0, _y0, _z0, _spacing; +}; + +#endif // VTKGEOIMAGESOURCE_H diff --git a/Gui/VtkVis/VtkImageDataToLinePolyDataFilter.cpp b/Gui/VtkVis/VtkImageDataToLinePolyDataFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a83e0bd5d2e4c174913da5b70227afcd9a8cc003 --- /dev/null +++ b/Gui/VtkVis/VtkImageDataToLinePolyDataFilter.cpp @@ -0,0 +1,154 @@ +/** + * \file VtkImageDataToLinePolyDataFilter.cpp + * 06/10/2010 LB Initial implementation + * + * Implementation of VtkImageDataToLinePolyDataFilter class + */ + +// ** INCLUDES ** +#include "VtkImageDataToLinePolyDataFilter.h" + +#include <vtkIdList.h> +#include <vtkImageData.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkLine.h> +#include <vtkObjectFactory.h> +#include <vtkPointData.h> +#include <vtkPolyData.h> +#include <vtkSmartPointer.h> + +vtkStandardNewMacro(VtkImageDataToLinePolyDataFilter); + +VtkImageDataToLinePolyDataFilter::VtkImageDataToLinePolyDataFilter() +{ + this->SetLengthScaleFactor(1.0); +} + +VtkImageDataToLinePolyDataFilter::~VtkImageDataToLinePolyDataFilter() +{ +} + +void VtkImageDataToLinePolyDataFilter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os, indent); + os << indent << "LengthScaleFactor: " << this->LengthScaleFactor << "\n"; +} + +int VtkImageDataToLinePolyDataFilter::FillInputPortInformation(int, vtkInformation* info) +{ + info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData"); + return 1; +} + +int VtkImageDataToLinePolyDataFilter::RequestData(vtkInformation*, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector) +{ + vtkDebugMacro(<< "Executing VtkImageDataToPolyDataFilter"); + + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkImageData* input = vtkImageData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + void* inScalarPtr = input->GetScalarPointer(); + int numScalarComponents = input->GetNumberOfScalarComponents(); + + double spacing[3]; + input->GetSpacing(spacing); + this->ImageSpacing = spacing[0]; + + int dimensions[3]; + input->GetDimensions(dimensions); + + // Skip execution if there are no points + vtkIdType numPts = input->GetNumberOfPoints(); + if (numPts < 1) + { + vtkDebugMacro("No data to extract lines!"); + return 1; + } + + // Allocate memory for olds and new cell point lists + vtkSmartPointer<vtkIdList> ptIds = vtkSmartPointer<vtkIdList>::New(); + ptIds->Allocate(VTK_CELL_SIZE); + vtkSmartPointer<vtkIdList> newPtIds = vtkSmartPointer<vtkIdList>::New(); + newPtIds->Allocate(VTK_CELL_SIZE); + + // Allocate the space needed for the output cells. + output->Allocate(numPts); + + // Allocate space for a new set of points + vtkSmartPointer<vtkPoints> newPts = vtkSmartPointer<vtkPoints>::New(); + newPts->Allocate(numPts * 2, numPts); + + // Allocate space for the data associated with the new set of points + vtkPointData* inPD = input->GetPointData(); + vtkPointData* outPD = output->GetPointData(); + outPD->CopyAllocate(inPD, numPts * 16, numPts); + + // Compute scaling factor that max height is 0.1 * longest image dimension + double range[2]; + inPD->GetArray(0)->GetRange(range); + float scalingFactor = (std::max(dimensions[0], dimensions[1]) * spacing[0] * 0.1) + / std::max(range[0], range[1]); + + double dir[3] = {0, 0, 1}; + + // Traverse all points creating another point with scalar distance in Z direction + for (vtkIdType ptId = 0; ptId < numPts; ++ptId) + { + // Skip translucent pixels + float opacity = ((float*)inScalarPtr)[ptId * numScalarComponents + 1]; + if (opacity < 0.00000001f) + continue; + + // Compute length of the new line (scalar * LengthScaleFactor) + float length = ((float*)inScalarPtr)[ptId * numScalarComponents] + * scalingFactor * this->LengthScaleFactor; + //float length = (((unsigned char*)inScalarPtr)[ptId * numScalarComponents]* this->LengthScaleFactor > 50000) ? 50000 : ((unsigned char*)inScalarPtr)[ptId * numScalarComponents]* this->LengthScaleFactor; + + // Skip this line if length is zero + if (length < 0.00000001f) + continue; + + // Get the old point location + double p[3]; + input->GetPoint(ptId, p); + + // Compute the new point location + double newPt[3]; + for(size_t i = 0; i < 3; ++i) + newPt[i] = p[i] + dir[i] * length; + + // Copy the old point + vtkIdType newOldId = newPts->InsertNextPoint(p); + newPtIds->InsertId(ptId * 2, ptId); + outPD->CopyData(inPD, ptId, newOldId); + + // Create the new point + vtkIdType newId = newPts->InsertNextPoint(newPt); + newPtIds->InsertId(ptId * 2 + 1, newId); + outPD->CopyData(inPD, ptId, newId); + + // Create the line + vtkSmartPointer<vtkLine> line = vtkSmartPointer<vtkLine>::New(); + line->GetPointIds()->SetId(0, newOldId); + line->GetPointIds()->SetId(1, newId); + output->InsertNextCell(line->GetCellType(), line->GetPointIds()); + } + + // Store the new set of points in the output + output->SetPoints(newPts); + output->GetPointData()->GetArray(0)->SetName("Colors"); + + // Avoid keeping extra memory around + output->Squeeze(); + + vtkDebugMacro(<< "Created: " + << newPts->GetNumberOfPoints() << " points, " + << output->GetNumberOfCells() << " lines"); + + return 1; +} diff --git a/Gui/VtkVis/VtkImageDataToLinePolyDataFilter.h b/Gui/VtkVis/VtkImageDataToLinePolyDataFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..cddf808d5c356302e7f5bb8b3aa5e0288f0ec97c --- /dev/null +++ b/Gui/VtkVis/VtkImageDataToLinePolyDataFilter.h @@ -0,0 +1,65 @@ +/** + * \file VtkImageDataToLinePolyDataFilter.h + * 06/10/2010 LB Initial implementation + */ + +#ifndef VTKIMAGEDATATOLINEPOLYDATAFILTER_H +#define VTKIMAGEDATATOLINEPOLYDATAFILTER_H + +#include "VtkAlgorithmProperties.h" +#include <vtkPolyDataAlgorithm.h> + +class vtkInformation; +class vtkInformationVector; + +/// @brief Creates lines that stand on top of the image with the length +/// of the corresponding first sub-pixel value (the grey or red value). +/// The maximum height is 0.1 * longest image dimension. +/// Used by VtkCompositeImageDataToCylindersFilter. +class VtkImageDataToLinePolyDataFilter : public vtkPolyDataAlgorithm, public VtkAlgorithmProperties +{ +public: + /// @brief Create new objects with New() because of VTKs reference counting. + static VtkImageDataToLinePolyDataFilter* New(); + + vtkTypeMacro(VtkImageDataToLinePolyDataFilter, vtkPolyDataAlgorithm); + + /// @brief Prints information about itself. + void PrintSelf(ostream& os, vtkIndent indent); + + /// @brief Sets the scaling of the length of the lines. + ogsUserPropertyMacro(LengthScaleFactor,double); + + /// @brief Sets a user property. + virtual void SetUserProperty(QString name, QVariant value) + { + if (name.compare("LengthScaleFactor") == 0) + SetLengthScaleFactor(value.toDouble()); + } + + /// @brief Returns the space between two pixels. + vtkGetMacro(ImageSpacing,double); + +protected: + /// @brief Constructor. + VtkImageDataToLinePolyDataFilter(); + + /// @brief Destructor. + virtual ~VtkImageDataToLinePolyDataFilter(); + + /// @brief Sets input port to vtkImageData. + virtual int FillInputPortInformation(int port, vtkInformation* info); + + /// @brief Converts the image data to lines + virtual int RequestData(vtkInformation* request, vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + /// @brief The spacing of the image + double ImageSpacing; + +private: + VtkImageDataToLinePolyDataFilter(const VtkImageDataToLinePolyDataFilter&); // Not implemented. + void operator=(const VtkImageDataToLinePolyDataFilter&); // Not implemented +}; + +#endif // VTKIMAGEDATATOLINEPOLYDATAFILTER_H diff --git a/Gui/VtkVis/VtkMeshConverter.cpp b/Gui/VtkVis/VtkMeshConverter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1bb4c75c46a57fdc8614b5c1563dc706d6d1a996 --- /dev/null +++ b/Gui/VtkVis/VtkMeshConverter.cpp @@ -0,0 +1,309 @@ +/** + * \file VtkMeshConverter.cpp + * 23/08/2011 KR Initial implementation + * + */ + +#include "VtkMeshConverter.h" + +#include "GridAdapter.h" + +// Conversion from Image to QuadMesh +#include <vtkImageData.h> +#include <vtkPointData.h> +#include <vtkSmartPointer.h> +#include <vtkUnsignedCharArray.h> + +// Conversion from vtkUnstructuredGrid +#include <vtkCell.h> +#include <vtkCellData.h> +#include <vtkUnstructuredGrid.h> +#include <vtkFloatArray.h> + + +GridAdapter* VtkMeshConverter::convertImgToMesh(vtkImageData* img, + const double origin[3], + const double scalingFactor, + MshElemType::type elem_type, + UseIntensityAs::type intensity_type) +{ + if ((elem_type != MshElemType::TRIANGLE) && (elem_type != MshElemType::QUAD)) + { + std::cout << "Error in VtkMeshConverter::convertImgToMesh() - Invalid Mesh Element Type..." << std::endl; + return NULL; + } + + vtkSmartPointer<vtkFloatArray> pixelData = vtkSmartPointer<vtkFloatArray>( + vtkFloatArray::SafeDownCast(img->GetPointData()->GetScalars())); + int* dims = img->GetDimensions(); + + const size_t imgHeight = dims[0]; + const size_t imgWidth = dims[1]; + const size_t incHeight = imgHeight+1; + const size_t incWidth = imgWidth+1; + double* pixVal (new double[incHeight * incWidth]); + bool* visNodes(new bool[incWidth * incHeight]); + int* node_idx_map(new int[incWidth * incHeight]); + + for (size_t j = 0; j < incHeight; j++) + { + pixVal[j]=0; + visNodes[j]=false; + node_idx_map[j]=-1; + } + for (size_t i = 0; i < imgWidth; i++) + { + for (size_t j = 0; j < imgHeight; j++) + { + const size_t img_idx = i * imgHeight + j; + const size_t index = (i+1) * incHeight + j; + int nTuple = pixelData->GetNumberOfComponents(); + double* colour; + if (nTuple == 2) //Grey+Alpha + { + colour = pixelData->GetTuple2(img_idx); + pixVal[index] = colour[0]; + + } + else if (nTuple == 4) //RGBA + { + colour = pixelData->GetTuple4(img_idx); + pixVal[index] = 0.3 * colour[0] + 0.6 * colour[1] + 0.1 * colour[2]; + } + else + { + std::cout << "Unsupported pixel composition!" << std::endl; + return NULL; + } + + visNodes[index] = (colour[nTuple-1] > 0); + node_idx_map[index]=-1; + } + pixVal[(i+2)*incHeight-1]=0; + visNodes[(i+2)*incHeight-1]=false; + node_idx_map[(i+2)*incHeight-1]=-1; + } + + GridAdapter* mesh = constructMesh(pixVal, node_idx_map, visNodes, origin, imgHeight, imgWidth, scalingFactor, elem_type, intensity_type); + + delete [] pixVal; + delete [] visNodes; + delete [] node_idx_map; + + return mesh; +} + +GridAdapter* VtkMeshConverter::convertImgToMesh(const double* img, + const double origin[3], + const size_t imgHeight, + const size_t imgWidth, + const double &scalingFactor, + MshElemType::type elem_type, + UseIntensityAs::type intensity_type) +{ + const size_t incHeight = imgHeight+1; + const size_t incWidth = imgWidth+1; + double* pixVal (new double[incHeight * incWidth]); + bool* visNodes(new bool[incWidth * incHeight]); + int* node_idx_map(new int[incWidth * incHeight]); + + double noDataValue = getExistingValue(img, imgWidth*imgHeight); + + for (size_t j = 0; j < imgHeight; j++) + { + pixVal[j]=0; + visNodes[j]=false; + node_idx_map[j]=-1; + } + for (size_t i = 0; i < imgWidth; i++) + { + for (size_t j = 0; j < imgHeight; j++) + { + const size_t img_idx = i * imgHeight + j; + const size_t index = (i+1) * incHeight + j; + if (img[img_idx] == -9999) + { + visNodes[index] = false; + pixVal[index] = noDataValue; + } + else + { + pixVal[index] = img[img_idx]; + visNodes[index] = true; + } + + node_idx_map[index]=-1; + } + pixVal[(i+2)*incHeight-1]=0; + visNodes[(i+2)*incHeight-1]=false; + node_idx_map[(i+2)*incHeight-1]=-1; + } + + GridAdapter* mesh = constructMesh(pixVal, node_idx_map, visNodes, origin, imgHeight, imgWidth, scalingFactor, elem_type, intensity_type); + + delete [] pixVal; + delete [] visNodes; + delete [] node_idx_map; + + return mesh; +} + +GridAdapter* VtkMeshConverter::constructMesh(const double* pixVal, + int* node_idx_map, + const bool* visNodes, + const double origin[3], + const size_t &imgHeight, + const size_t &imgWidth, + const double &scalingFactor, + MshElemType::type elem_type, + UseIntensityAs::type intensity_type) +{ + const size_t incHeight = imgHeight+1; + const size_t incWidth = imgWidth+1; + GridAdapter* grid = new GridAdapter(); + size_t node_idx_count(0); + const double x_offset(origin[0] - scalingFactor/2.0); + const double y_offset(origin[1] - scalingFactor/2.0); + + for (size_t i = 0; i < incWidth; i++) + for (size_t j = 0; j < incHeight; j++) + { + const size_t index = i * incHeight + j; + + bool set_node (false); + if (j==0 && i==imgWidth) set_node = visNodes[index]; + else if (j==0) set_node = (visNodes[index] || visNodes[index+incHeight]); + else if (i==imgWidth) set_node = (visNodes[index] || visNodes[index-1]); + else set_node = (visNodes[index] || visNodes[index-1] || visNodes[index+incHeight] || visNodes[index+incHeight-1]); + + if (set_node) + { + double zValue = (intensity_type == UseIntensityAs::ELEVATION) ? pixVal[index] : 0.0; + grid->addNode(new GEOLIB::Point(x_offset + (scalingFactor * j), + y_offset + (scalingFactor * i), + zValue)); + node_idx_map[index] = node_idx_count; + node_idx_count++; + } + } + + // set mesh elements + for (size_t i = 0; i < imgWidth; i++) + for (size_t j = 0; j < imgHeight; j++) + { + const int index = i * incHeight + j; + if ((node_idx_map[index]!=-1) && (node_idx_map[index+1]!=-1) && (node_idx_map[index+incHeight]!=-1) && (node_idx_map[index+incHeight+1]!=-1) && (visNodes[index+incHeight])) + { + const int mat = (intensity_type != UseIntensityAs::MATERIAL) ? 0 : static_cast<int>(pixVal[index+incHeight]); + if (elem_type == MshElemType::TRIANGLE) + { + grid->addElement(createElement(elem_type, mat, node_idx_map[index], node_idx_map[index + 1], + node_idx_map[index + incHeight])); // upper left triangle + grid->addElement(createElement(elem_type, mat, node_idx_map[index + 1], + node_idx_map[index + incHeight + 1], + node_idx_map[index + incHeight])); // lower right triangle + } + if (elem_type == MshElemType::QUAD) + { + grid->addElement(createElement(elem_type, mat, node_idx_map[index], node_idx_map[index + 1], + node_idx_map[index + incHeight + 1], + node_idx_map[index + incHeight])); + } + } + } + + return grid; +} + +GridAdapter::Element* VtkMeshConverter::createElement(MshElemType::type t, int mat, size_t node1, size_t node2, size_t node3, size_t node4) +{ + GridAdapter::Element* elem = new GridAdapter::Element(); + elem->material = mat; + elem->type = t; + std::vector<size_t> nodes; + nodes.push_back(node1); + nodes.push_back(node2); + nodes.push_back(node3); + if (t == MshElemType::QUAD) + nodes.push_back(node4); + elem->nodes = nodes; + return elem; +} + +GridAdapter* VtkMeshConverter::convertUnstructuredGrid(vtkUnstructuredGrid* grid) +{ + if (!grid) + return NULL; + + GridAdapter* mesh = new GridAdapter(); + + const size_t nNodes = grid->GetPoints()->GetNumberOfPoints(); + const size_t nElems = grid->GetNumberOfCells(); + + // set mesh nodes + double* coords = NULL; + for (size_t i = 0; i < nNodes; i++) + { + coords = grid->GetPoints()->GetPoint(i); + mesh->addNode(new GEOLIB::Point(coords[0], coords[1], coords[2])); + } + + // set mesh elements + vtkCell* cell(NULL); + vtkDataArray* scalars = grid->GetCellData()->GetScalars("MaterialIDs"); + for (size_t i = 0; i < nElems; i++) + { + GridAdapter::Element* elem = new GridAdapter::Element(); + + MshElemType::type elem_type = MshElemType::INVALID; + int cell_type = grid->GetCellType(i); + + switch (cell_type) + { + case VTK_TRIANGLE: elem_type = MshElemType::TRIANGLE; + break; + case VTK_QUAD: elem_type = MshElemType::QUAD; + break; + case VTK_TETRA: elem_type = MshElemType::TETRAHEDRON; + break; + case VTK_HEXAHEDRON: elem_type = MshElemType::HEXAHEDRON; + break; + case VTK_WEDGE: elem_type = MshElemType::PRISM; + break; + case VTK_PYRAMID: elem_type = MshElemType::PYRAMID; + break; + } + + if (elem_type != MshElemType::INVALID) + { + elem->type = elem_type; + if (scalars) + elem->material = static_cast<int>(scalars->GetComponent(i,0)); + } + else + { + std::cout << "Error in GridAdapter::convertUnstructuredGrid() - Unknown mesh element type \"" << cell_type << "\" ..." << std::endl; + return NULL; + } + + cell = grid->GetCell(i); + size_t nElemNodes = cell->GetNumberOfPoints(); + std::vector<size_t> nodes; + for (size_t j = 0; j < nElemNodes; j++) + nodes.push_back(cell->GetPointId(j)); + + elem->nodes = nodes; + mesh->addElement(elem); + } + return mesh; +} + +double VtkMeshConverter::getExistingValue(const double* img, size_t length) +{ + for (size_t i=0; i<length; i++) + { + if (img[i] != -9999) + return img[i]; + } + return -9999; +} diff --git a/Gui/VtkVis/VtkMeshConverter.h b/Gui/VtkVis/VtkMeshConverter.h new file mode 100644 index 0000000000000000000000000000000000000000..ee748168c85afd81d1ecb60fcadf4085c1c4dd37 --- /dev/null +++ b/Gui/VtkVis/VtkMeshConverter.h @@ -0,0 +1,80 @@ +/** + * \file VtkMeshConverter.h + * 23/08/2011 KR Initial implementation + * + */ + +#ifndef VTKMESHCONVERTER_H +#define VTKMESHCONVERTER_H + +//#include <utility> +//#include "MSHEnums.h" +#include "GridAdapter.h" + +class vtkImageData; // For conversion from Image to QuadMesh +class vtkUnstructuredGrid; // For conversion vom vtk to ogs mesh + +/// Selection of possible interpretations for intensities +struct UseIntensityAs +{ + enum type { + ELEVATION, + MATERIAL, + NONE + }; +}; + +/** + * \brief Adapter class to convert FEM Mesh to a representation more suited for visualisation purposes + */ +class VtkMeshConverter +{ +public: + /** + * Converts greyscale image to a mesh + * \param elem_type defines if elements of the new mesh should be triangles or quads (or hexes for 3D) + * \param intensity_type defines how image intensities are interpreted + */ + static GridAdapter* convertImgToMesh(vtkImageData* img, + const double origin[3], + const double scalingFactor, + MshElemType::type elem_type, + UseIntensityAs::type intensity_type); + + /** + * Converts double array with raster values to a mesh + * \param elem_type defines if elements of the new mesh should be triangles or quads (or hexes for 3D) + * \param intensity_type defines how image intensities are interpreted + */ + static GridAdapter* convertImgToMesh(const double* img, + const double origin[3], + const size_t imgHeight, + const size_t imgWidth, + const double &scalingFactor, + MshElemType::type elem_type, + UseIntensityAs::type intensity_type); + + /// Converts a vtkUnstructuredGrid object to a CFEMesh + static GridAdapter* convertUnstructuredGrid(vtkUnstructuredGrid* grid); + +private: + /// Does the actual mesh generation based on the data given to the public methods. + static GridAdapter* constructMesh(const double* pixVal, + int* node_idx_map, + const bool* visNodes, + const double origin[3], + const size_t &imgHeight, + const size_t &imgWidth, + const double &scalingFactor, + MshElemType::type elem_type, + UseIntensityAs::type intensity_type); + + /// Creates a mesh element based on the given data. + static GridAdapter::Element* createElement(MshElemType::type t, int mat, + size_t node1, size_t node2, + size_t node3, size_t node4 = 0); + + static double getExistingValue(const double* img, size_t length); +}; + +#endif // VTKMESHCONVERTER_H diff --git a/Gui/VtkVis/VtkMeshSource.cpp b/Gui/VtkVis/VtkMeshSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e1efddbc3ab2635e3e0d731694a6bf83b87d1bd5 --- /dev/null +++ b/Gui/VtkVis/VtkMeshSource.cpp @@ -0,0 +1,179 @@ +/** + * \file VtkMeshSource.cpp + * 19/03/2010 KR Initial implementation + * + */ + +#include "VtkColorLookupTable.h" +#include "VtkMeshSource.h" + +// ** VTK INCLUDES ** +#include "vtkObjectFactory.h" +#include <vtkCellData.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkIntArray.h> +#include <vtkPoints.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkUnstructuredGrid.h> +#include <vtkProperty.h> + +// OGS Cell Types +#include <vtkHexahedron.h> +#include <vtkLine.h> +#include <vtkQuad.h> +#include <vtkTetra.h> +#include <vtkTriangle.h> +#include <vtkWedge.h> // == Prism +#include <vtkPyramid.h> + +vtkStandardNewMacro(VtkMeshSource); +vtkCxxRevisionMacro(VtkMeshSource, "$Revision$"); + +VtkMeshSource::VtkMeshSource() : _matName("MaterialIDs") +{ + _removable = false; // From VtkAlgorithmProperties + this->SetNumberOfInputPorts(0); + + const GEOLIB::Color* c = GEOLIB::getRandomColor(); + vtkProperty* vtkProps = GetProperties(); + vtkProps->SetColor((*c)[0] / 255.0,(*c)[1] / 255.0,(*c)[2] / 255.0); + vtkProps->SetEdgeVisibility(1); +} + +VtkMeshSource::~VtkMeshSource() +{ + delete _grid; +} + +void VtkMeshSource::PrintSelf( ostream& os, vtkIndent indent ) +{ + this->Superclass::PrintSelf(os,indent); + + if (_grid == NULL) + return; + const std::vector<GEOLIB::Point*>* nodes = _grid->getNodes(); + const std::vector<GridAdapter::Element*>* elems = _grid->getElements(); + if (nodes->empty() || elems->empty() ) + return; + + os << indent << "== VtkMeshSource ==" << "\n"; + + int i = 0; + for (std::vector<GEOLIB::Point*>::const_iterator it = nodes->begin(); + it != nodes->end(); ++it) + { + os << indent << "Point " << i << " (" << (*it)[0] << ", " << (*it)[1] << ", " << + (*it)[2] << ")" << std::endl; + i++; + } + + i = 0; + for (std::vector<GridAdapter::Element*>::const_iterator it = elems->begin(); + it != elems->end(); ++it) + { + os << indent << "Element " << i << ": "; + for (size_t t = 0; t < (*it)->nodes.size(); t++) + os << (*it)->nodes[t] << " "; + os << std::endl; + i++; + } +} + +int VtkMeshSource::RequestData( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + if (_grid == NULL) + return 0; + const std::vector<GEOLIB::Point*>* nodes = _grid->getNodes(); + const std::vector<GridAdapter::Element*>* elems = _grid->getElements(); + + const size_t nPoints = nodes->size(); + const size_t nElems = elems->size(); + if (nPoints == 0 || nElems == 0) + return 0; + + vtkSmartPointer<vtkInformation> outInfo = outputVector->GetInformationObject(0); + vtkSmartPointer<vtkUnstructuredGrid> output = vtkUnstructuredGrid::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); + output->Allocate(nElems); + + if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) + return 1; + + // Insert grid points + vtkSmartPointer<vtkPoints> gridPoints = vtkSmartPointer<vtkPoints>::New(); + gridPoints->Allocate(nPoints); + // Generate mesh nodes + for (size_t i = 0; i < nPoints; i++) + gridPoints->InsertPoint(i, (*(*nodes)[i])[0], (*(*nodes)[i])[1], (*(*nodes)[i])[2]); + + // Generate attribute vector for material groups + vtkSmartPointer<vtkIntArray> materialIDs = vtkSmartPointer<vtkIntArray>::New(); + materialIDs->SetName(_matName); + materialIDs->SetNumberOfComponents(1); + materialIDs->SetNumberOfTuples(nElems); + + // Generate mesh elements + for (size_t i = 0; i < nElems; i++) + { + int type(0); + const GridAdapter::Element* elem = (*elems)[i]; + + switch (elem->type) + { + case MshElemType::LINE: + type = 3; + break; + case MshElemType::TRIANGLE: + type = 5; + break; + case MshElemType::QUAD: + type = 8; + break; + case MshElemType::HEXAHEDRON: + type = 12; + break; + case MshElemType::TETRAHEDRON: + type = 10; + break; + case MshElemType::PRISM: + type = 13; + break; + case MshElemType::PYRAMID: + type = 14; + break; + default: // if none of the above can be applied + std::cout << "Error in VtkMeshSource::RequestData() - Unknown element type " << MshElemType2String(elem->type) << "." << std::endl; + return 0; + } + + materialIDs->InsertValue(i,(elem->material)); + vtkIdList* point_ids = vtkIdList::New(); + + const size_t nElemNodes (elem->nodes.size()); + for (size_t j = 0; j < nElemNodes; j++) + point_ids->InsertNextId(elem->nodes[nElemNodes-1-j]); + + output->InsertNextCell(type, point_ids); + } + + output->SetPoints(gridPoints); + + output->GetCellData()->AddArray(materialIDs); + output->GetCellData()->SetActiveAttribute(_matName, vtkDataSetAttributes::SCALARS); + + return 1; +} + +void VtkMeshSource::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); + + (*_algorithmUserProperties)[name] = value; +} diff --git a/Gui/VtkVis/VtkMeshSource.h b/Gui/VtkVis/VtkMeshSource.h new file mode 100644 index 0000000000000000000000000000000000000000..c85e1ccc31a0a7fa4f9a1228194a4484207bf823 --- /dev/null +++ b/Gui/VtkVis/VtkMeshSource.h @@ -0,0 +1,65 @@ +/** + * \file VtkMeshSource.h + * 19/03/2010 KR Initial implementation + * + */ + +#ifndef VTKMESHSOURCE_H +#define VTKMESHSOURCE_H + +// ** INCLUDES ** +#include <map> + +#include "GridAdapter.h" +#include "VtkAlgorithmProperties.h" +#include <vtkUnstructuredGridAlgorithm.h> + +class VtkColorLookupTable; + +/** + * \brief VTK source object for the visualisation of unstructured grids + */ +class VtkMeshSource : public vtkUnstructuredGridAlgorithm, public VtkAlgorithmProperties +{ +public: + /// Create new objects with New() because of VTKs object reference counting. + static VtkMeshSource* New(); + + vtkTypeRevisionMacro(VtkMeshSource, vtkUnstructuredGridAlgorithm); + + const char* GetMaterialArrayName() const { return _matName; } + + /// Returns the base object of this grid + const GridAdapter* GetGrid() { return this->_grid; } + + /// Sets the grid object that should be visualized + void SetGrid(const GridAdapter* grid) { _grid = grid; } + + /// Prints the mesh data to an output stream. + void PrintSelf(ostream& os, vtkIndent indent); + + /** + * \brief Generates random colors based on the material scalar value. + * Each element of the mesh is assigned an RGB-value based on its material group. + * This method should only be called after setMesh()! + */ + //ogsUserPropertyMacro(ColorByMaterial,bool); + + virtual void SetUserProperty(QString name, QVariant value); + +protected: + VtkMeshSource(); + ~VtkMeshSource(); + + /// Computes the unstructured grid data object. + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + const GridAdapter* _grid; + +private: + const char* _matName; +}; + +#endif // VTKMESHSOURCE_H diff --git a/Gui/VtkVis/VtkPointsSource.cpp b/Gui/VtkVis/VtkPointsSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1850908209cb56d60e3f998407674890f81c6ef9 --- /dev/null +++ b/Gui/VtkVis/VtkPointsSource.cpp @@ -0,0 +1,127 @@ +/** + * \file VtkPointsSource.cpp + * 3/2/2010 LB Initial implementation + * + * Implementation of VtkPointsSource + */ + +// ** INCLUDES ** +#include "VtkPointsSource.h" + +#include <vtkCellArray.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkObjectFactory.h> +#include <vtkPointData.h> +#include <vtkPoints.h> +#include <vtkPolyData.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkCellData.h> +#include <vtkProperty.h> + +vtkStandardNewMacro(VtkPointsSource); +vtkCxxRevisionMacro(VtkPointsSource, "$Revision$"); + +VtkPointsSource::VtkPointsSource() + : _points(NULL) +{ + _removable = false; // From VtkAlgorithmProperties + this->SetNumberOfInputPorts(0); + + const GEOLIB::Color* c = GEOLIB::getRandomColor(); + GetProperties()->SetColor((*c)[0] / 255.0,(*c)[1] / 255.0,(*c)[2] / 255.0); +} + +void VtkPointsSource::PrintSelf( ostream& os, vtkIndent indent ) +{ + this->Superclass::PrintSelf(os,indent); + + if (_points->size() == 0) + return; + + os << indent << "== VtkPointsSource ==" << "\n"; + + int i = 0; + for (std::vector<GEOLIB::Point*>::const_iterator it = _points->begin(); + it != _points->end(); ++it) + { + const double* coords = (*it)->getData(); + os << indent << "Point " << i << " (" << coords[0] << ", " << coords[1] << ", " << + coords[2] << ")\n"; + i++; + } +} + +int VtkPointsSource::RequestData( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + if (!_points) + return 0; + int numPoints = _points->size(); + if (numPoints == 0) + { + std::cout << "ERROR in VtkPointsSource::RequestData : Size of point vector is 0" << + std::endl; + return 0; + } + + vtkSmartPointer<vtkInformation> outInfo = outputVector->GetInformationObject(0); + vtkSmartPointer<vtkPolyData> output = + vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New(); + vtkSmartPointer<vtkCellArray> newVerts = vtkSmartPointer<vtkCellArray>::New(); + newPoints->Allocate(numPoints); + newVerts->Allocate(numPoints); + + vtkSmartPointer<vtkIntArray> pointIDs = vtkSmartPointer<vtkIntArray>::New(); + pointIDs->SetNumberOfComponents(1); + pointIDs->SetName("PointIDs"); + + if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) + return 1; + + // Generate points and vertices + int i = 0; + for (std::vector<GEOLIB::Point*>::const_iterator it = _points->begin(); + it != _points->end(); ++it) + { + double coords[3] = {(*(*it))[0], (*(*it))[1], (*(*it))[2]}; + vtkIdType pid = newPoints->InsertNextPoint(coords); + newVerts->InsertNextCell(1, &pid); + + pointIDs->InsertNextValue(i); + i++; + } + + output->SetPoints(newPoints); + output->SetVerts(newVerts); + output->GetCellData()->AddArray(pointIDs); + output->GetCellData()->SetActiveAttribute("PointIDs", vtkDataSetAttributes::SCALARS); + + return 1; +} + +int VtkPointsSource::RequestInformation( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + vtkInformation* outInfo = outputVector->GetInformationObject(0); + outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1); + + return 1; +} + +void VtkPointsSource::SetUserProperty( QString name, QVariant value ) +{ + Q_UNUSED(name); + Q_UNUSED(value); +} diff --git a/Gui/VtkVis/VtkPointsSource.h b/Gui/VtkVis/VtkPointsSource.h new file mode 100644 index 0000000000000000000000000000000000000000..4ac56bacfe66d6bb497a0ee4706bac27a6b61aca --- /dev/null +++ b/Gui/VtkVis/VtkPointsSource.h @@ -0,0 +1,55 @@ +/** + * \file VtkPointsSource.h + * 3/2/2010 LB Initial implementation + * + */ + +#ifndef VTKPOINTSSOURCE_H +#define VTKPOINTSSOURCE_H + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include <vtkPolyDataAlgorithm.h> + +#include "GEOObjects.h" + +/** + * \brief VtkPointsSource is a VTK source object for the visualization + * of point data. As a vtkPolyDataAlgorithm it outputs polygonal data. + */ +class VtkPointsSource : public vtkPolyDataAlgorithm, public VtkAlgorithmProperties +{ +public: + /// Create new objects with New() because of VTKs object reference counting. + static VtkPointsSource* New(); + + vtkTypeRevisionMacro(VtkPointsSource,vtkPolyDataAlgorithm); + + /// Sets the points as a vector + void setPoints(const std::vector<GEOLIB::Point*>* points) { _points = points; } + + /// Prints its data on a stream. + void PrintSelf(ostream& os, vtkIndent indent); + + virtual void SetUserProperty(QString name, QVariant value); + +protected: + VtkPointsSource(); + ~VtkPointsSource() {} + + /// Computes the polygonal data object. + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + int RequestInformation(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + /// The points to visualize + const std::vector<GEOLIB::Point*>* _points; + +private: +}; + +#endif // VTKPOINTSSOURCE_H diff --git a/Gui/VtkVis/VtkPolylinesSource.cpp b/Gui/VtkVis/VtkPolylinesSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..cc3aa88873de51a6fc16a9f8718d7dcc17187239 --- /dev/null +++ b/Gui/VtkVis/VtkPolylinesSource.cpp @@ -0,0 +1,146 @@ +/** + * \file VtkPolylinesSource.cpp + * 2/2/2010 LB Initial implementation + * + * Implementation of VtkPolylinesSource + */ + +// ** INCLUDES ** +#include "VtkPolylinesSource.h" + +#include <vtkCellArray.h> +#include <vtkCellData.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkObjectFactory.h> +#include <vtkPointData.h> +#include <vtkPoints.h> +#include <vtkPolyData.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkProperty.h> + +vtkStandardNewMacro(VtkPolylinesSource); +vtkCxxRevisionMacro(VtkPolylinesSource, "$Revision$"); + +VtkPolylinesSource::VtkPolylinesSource() + : _polylines(NULL) +{ + _removable = false; // From VtkAlgorithmProperties + this->SetNumberOfInputPorts(0); + + const GEOLIB::Color* c = GEOLIB::getRandomColor(); + GetProperties()->SetColor((*c)[0] / 255.0,(*c)[1] / 255.0,(*c)[2] / 255.0); +} + +VtkPolylinesSource::~VtkPolylinesSource() +{ +} + +void VtkPolylinesSource::PrintSelf( ostream& os, vtkIndent indent ) +{ + this->Superclass::PrintSelf(os,indent); + + if (_polylines->size() == 0) + return; + + for (std::vector<GEOLIB::Polyline*>::const_iterator it = _polylines->begin(); + it != _polylines->end(); ++it) + { + os << indent << "== Polyline ==" << "\n"; + int numPoints = (*it)->getNumberOfPoints(); + for (int i = 0; i < numPoints; i++) + { + const GEOLIB::Point* point = (**it)[i]; + const double* coords = point->getData(); + os << indent << "Point " << i << " (" << coords[0] << ", " << coords[1] << + ", " << coords[2] << ")\n"; + } + } +} + +int VtkPolylinesSource::RequestData( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + if (!_polylines) + return 0; + if (_polylines->size() == 0) + { + std::cout << + "ERROR in VtkPolylineSource::RequestData : Size of polyline vector is 0" << + std::endl; + return 0; + } + + vtkSmartPointer<vtkInformation> outInfo = outputVector->GetInformationObject(0); + vtkSmartPointer<vtkPolyData> output = + vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New(); + vtkSmartPointer<vtkCellArray> newLines = vtkSmartPointer<vtkCellArray>::New(); + + //newPoints->Allocate(numPoints); + //newLines->Allocate(newLines->EstimateSize(numLines, 2)); + + if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) + return 1; + + vtkSmartPointer<vtkIntArray> plyIDs = vtkSmartPointer<vtkIntArray>::New(); + plyIDs->SetNumberOfComponents(1); + plyIDs->SetName("PolylineIDs"); + + int lastMaxIndex = 0; + //for (std::vector<GEOLIB::Polyline*>::const_iterator it = _polylines->begin(); + // it != _polylines->end(); ++it) + for (size_t j = 0; j < _polylines->size(); j++) + { + const int numPoints = (*_polylines)[j]->getNumberOfPoints(); + //const int numLines = numPoints - 1; + + // Generate points + for (int i = 0; i < numPoints; i++) + { + const GEOLIB::Point* point = (*(*_polylines)[j])[i]; + const double* coords = point->getData(); + newPoints->InsertNextPoint(coords); + } + + // Generate lines + newLines->InsertNextCell(numPoints); + plyIDs->InsertNextValue(j); + for (int i = 0; i < numPoints; i++) + newLines->InsertCellPoint(i + lastMaxIndex); + + lastMaxIndex += numPoints; + } + + output->SetPoints(newPoints); + output->SetLines(newLines); + output->GetCellData()->AddArray(plyIDs); + output->GetCellData()->SetActiveAttribute("PolylineIDs", vtkDataSetAttributes::SCALARS); + + return 1; +} + +int VtkPolylinesSource::RequestInformation( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + vtkInformation* outInfo = outputVector->GetInformationObject(0); + outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1); + + return 1; +} + +void VtkPolylinesSource::SetUserProperty( QString name, QVariant value ) +{ + Q_UNUSED(name); + Q_UNUSED(value); +} diff --git a/Gui/VtkVis/VtkPolylinesSource.h b/Gui/VtkVis/VtkPolylinesSource.h new file mode 100644 index 0000000000000000000000000000000000000000..888f0b1297c2a447a36c6a7f344b43333afb4804 --- /dev/null +++ b/Gui/VtkVis/VtkPolylinesSource.h @@ -0,0 +1,55 @@ +/** + * \file VtkPolylinesSource.h + * 2/2/2010 LB Initial implementation + * + */ + +#ifndef VTKPOLYLINESSOURCE_H +#define VTKPOLYLINESSOURCE_H + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include <vtkPolyDataAlgorithm.h> + +#include "GEOObjects.h" + +/** + * \brief VtkPolylinesSource is a VTK source object for the visualisation of + * polyline data. As a vtkPolyDataAlgorithm it outputs polygonal data. + */ +class VtkPolylinesSource : public vtkPolyDataAlgorithm, public VtkAlgorithmProperties +{ +public: + /// Create new objects with New() because of VTKs object reference counting. + static VtkPolylinesSource* New(); + + vtkTypeRevisionMacro(VtkPolylinesSource,vtkPolyDataAlgorithm); + + /// Sets the polyline vector. + void setPolylines(const std::vector<GEOLIB::Polyline*>* polylines) { _polylines = polylines; } + + /// Prints its data on a stream. + void PrintSelf(ostream& os, vtkIndent indent); + + virtual void SetUserProperty(QString name, QVariant value); + +protected: + VtkPolylinesSource(); + ~VtkPolylinesSource(); + + /// Computes the polygonal data object. + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + int RequestInformation(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + /// The polylines to visualize. + const std::vector<GEOLIB::Polyline*>* _polylines; + +private: +}; + +#endif // VTKPOLYLINESSOURCE_H diff --git a/Gui/VtkVis/VtkRaster.cpp b/Gui/VtkVis/VtkRaster.cpp new file mode 100644 index 0000000000000000000000000000000000000000..13f920a9ae888ae21a26b6ab5dedb4b667e03a2f --- /dev/null +++ b/Gui/VtkVis/VtkRaster.cpp @@ -0,0 +1,516 @@ +/** + * \file VtkRaster.cpp + * 2012/02/01 KR Initial implementation + */ + +#include "VtkRaster.h" + +#include <cmath> +#include <iomanip> +#include <iostream> +#include <sstream> + +#include <QFileInfo> + +#include "StringTools.h" + +#include <vtkFloatArray.h> +#include <vtkPointData.h> + +#include <vtkImageAlgorithm.h> +#include <vtkImageData.h> +#include <vtkImageImport.h> +#include <vtkImageReader2.h> +#include <vtkPNGReader.h> +#include <vtkJPEGReader.h> +#include <vtkBMPReader.h> + +#ifdef libgeotiff_FOUND +#include "geo_tiffp.h" +#include "xtiffio.h" +#endif + +vtkImageAlgorithm* VtkRaster::loadImage(const std::string &fileName, + double& x0, double& y0, double& delta) +{ + QFileInfo fileInfo(QString::fromStdString(fileName)); + + if (fileInfo.suffix().toLower() == "asc" || fileInfo.suffix().toLower() == "grd") + return loadImageFromASC(fileName, x0, y0, delta); +#ifdef libgeotiff_FOUND + else if ((fileInfo.suffix().toLower() == "tif") || (fileInfo.suffix().toLower() == "tiff")) + return loadImageFromTIFF(fileName, x0, y0, delta); +#endif + else + return loadImageFromFile(fileName); +} + +vtkImageImport* VtkRaster::loadImageFromASC(const std::string &fileName, + double& x0, double& y0, double& delta) +{ + size_t width(0), height(0); + float* data; + + if (fileName.substr(fileName.length()-3, 3).compare("asc") == 0) + data = loadDataFromASC(fileName, x0, y0, width, height, delta); + else + data = loadDataFromSurfer(fileName, x0, y0, width, height, delta); + + vtkImageImport* image = vtkImageImport::New(); + image->SetDataSpacing(delta, delta,delta); + image->SetDataOrigin(x0+(delta/2.0), y0+(delta/2.0), 0); // translate whole mesh by half a pixel in x and y + image->SetWholeExtent(0, width-1, 0, height-1, 0, 0); + image->SetDataExtent(0, width-1, 0, height-1, 0, 0); + image->SetDataExtentToWholeExtent(); + image->SetDataScalarTypeToFloat(); + image->SetNumberOfScalarComponents(2); + image->SetImportVoidPointer(data, 0); + image->Update(); + + return image; +} + +vtkImageImport* VtkRaster::loadImageFromArray(double* data_array, double &x0, double &y0, size_t &width, size_t &height, double &delta, double noData) +{ + const size_t length = height*width; + float* data = new float[length*2]; + float max_val=noData; + for (size_t j=0; j<length; j++) + { + data[j*2] = static_cast<float>(data_array[j]); + max_val = (data[j*2]>max_val) ? data[j*2] : max_val; + } + for (size_t j=0; j<length; j++) + { + if (data[j*2]==noData) + { + data[j*2] = max_val; + data[j*2+1] = 0; + } + else + { + //data[j*2] = max_val-data[j*2];//delete; + data[j*2+1] = max_val; + } + } + + vtkImageImport* image = vtkImageImport::New(); + image->SetDataSpacing(delta, delta, delta); + image->SetDataOrigin(x0+(delta/2.0), y0+(delta/2.0), 0); // translate whole mesh by half a pixel in x and y + image->SetWholeExtent(0, width-1, 0, height-1, 0, 0); + image->SetDataExtent(0, width-1, 0, height-1-1, 0, 0); + image->SetDataExtentToWholeExtent(); + image->SetDataScalarTypeToFloat(); + image->SetNumberOfScalarComponents(2); + image->SetImportVoidPointer(data, 0); + image->Update(); + + return image; +} + + +bool VtkRaster::readASCHeader(ascHeader &header, std::ifstream &in) +{ + std::string line, tag, value; + + in >> tag; + if (tag.compare("ncols") == 0) + { + in >> value; + header.ncols = atoi(value.c_str()); + } + else + return false; + in >> tag; + if (tag.compare("nrows") == 0) + { + in >> value; + header.nrows = atoi(value.c_str()); + } + else + return false; + in >> tag; + if (tag.compare("xllcorner") == 0) + { + in >> value; + header.x = strtod(replaceString(",", ".", value).c_str(),0); + } + else + return false; + in >> tag; + if (tag.compare("yllcorner") == 0) + { + in >> value; + header.y = strtod(replaceString(",", ".", value).c_str(),0); + } + else + return false; + in >> tag; + if (tag.compare("cellsize") == 0) + { + in >> value; + header.cellsize = strtod(replaceString(",", ".", value).c_str(),0); + } + else + return false; + in >> tag; + if (tag.compare("NODATA_value") == 0) + { + in >> value; + header.noData = value.c_str(); + } + else + return false; + + // correct raster position by half a pixel for correct visualisation + // argh! wrong! correction has to happen in visualisation object, otherwise the actual data is wrong + //header.x = header.x + (header.cellsize / 2); + //header.y = header.y + (header.cellsize / 2); + + return true; +} + +float* VtkRaster::loadDataFromASC(const std::string &fileName, + double &x0, + double &y0, + size_t &width, + size_t &height, + double &delta) +{ + std::ifstream in( fileName.c_str() ); + + if (!in.is_open()) + { + std::cout << "VtkRaster::loadImageFromASC() - Could not open file..." << std::endl; + return NULL; + } + + ascHeader header; + + if (readASCHeader(header, in)) + { + x0 = header.x; + y0 = header.y; + width = header.ncols; + height = header.nrows; + delta = header.cellsize; + + float* values = new float[header.ncols * header.nrows * 2]; + + int col_index(0); + int noData = atoi(header.noData.c_str()); + float max_val = noData; + std::string s(""); + // read the file into a double-array + for (int j = 0; j < header.nrows; j++) + { + col_index = (header.nrows - j - 1) * header.ncols; + for (int i = 0; i < header.ncols; i++) + { + in >> s; + size_t index = 2*(col_index+i); + values[index] = static_cast<float>(strtod(replaceString(",", ".", s).c_str(),0)); + if (values[index] > max_val) + max_val = values[index]; + } + } + + // shift noData values into normal pixel-range and set transparancy values for all pixels + size_t nPixels = header.ncols * header.nrows; + for (size_t j = 0; j < nPixels; j++) + { + if (values[j*2] == noData) + { + values[j*2] = max_val; + values[j*2+1] = 0; + } + else + values[j*2+1] = max_val; + } + + in.close(); + return values; + } + return NULL; +} + +bool VtkRaster::readSurferHeader(ascHeader &header, std::ifstream &in) +{ + std::string line, tag, value; + double min, max; + + in >> tag; + + if (tag.compare("DSAA") != 0) + { + std::cout << "Error in readSurferHeader() - No Surfer file..." << std::endl; + return false; + } + else + { + in >> header.ncols >> header.nrows; + in >> min >> max; + header.x = min; + header.cellsize = (max-min)/(double)header.ncols; + + in >> min >> max; + header.y = min; + + if (ceil((max-min)/(double)header.nrows) == ceil(header.cellsize)) + header.cellsize = ceil(header.cellsize); + else + { + std::cout << "Error in readSurferHeader() - Anisotropic cellsize detected..." << std::endl; + return 0; + } + in >> min >> max; // ignore min- and max-values + + header.noData = "1.70141E+038"; + } + + return true; +} + +float* VtkRaster::loadDataFromSurfer(const std::string &fileName, + double &x0, + double &y0, + size_t &width, + size_t &height, + double &delta) +{ + std::ifstream in( fileName.c_str() ); + + if (!in.is_open()) + { + std::cout << "VtkRaster::loadImageFromSurfer() - Could not open file..." << std::endl; + return NULL; + } + + ascHeader header; + + if (readSurferHeader(header, in)) + { + x0 = header.x; + y0 = header.y; + width = header.ncols; + height = header.nrows; + delta = header.cellsize; + + float* values = new float[header.ncols * header.nrows * 2]; + + int col_index(0); + int noData = -9999; + float max_val = noData; + std::string s(""); + // read the file into a double-array + for (int j = 0; j < header.nrows; j++) + { + col_index = j * header.ncols; + for (int i = 0; i < header.ncols; i++) + { + in >> s; + if (s.compare(header.noData) == 0) + s = "-9999"; + size_t index = 2*(col_index+i); + values[index] = static_cast<float>(strtod(replaceString(",", ".", s).c_str(),0)); + if (values[index] > max_val) + max_val = values[index]; + } + } + + // shift noData values into normal pixel-range and set transparancy values for all pixels + size_t nPixels = header.ncols * header.nrows; + for (size_t j = 0; j < nPixels; j++) + { + if (values[j*2] == noData) + { + values[j*2] = max_val; + values[j*2+1] = 0; + } + else + values[j*2+1] = max_val; + } + + in.close(); + return values; + } + return NULL; +} + +#ifdef libgeotiff_FOUND +vtkImageImport* VtkRaster::loadImageFromTIFF(const std::string &fileName, + double &x0, double &y0, + double &cellsize) +{ + TIFF* tiff = XTIFFOpen(fileName.c_str(), "r"); + + if (tiff) + { + GTIF* geoTiff = GTIFNew(tiff); + + if (geoTiff) + { + int imgWidth = 0, imgHeight = 0, nImages = 0, pntCount = 0; + double* pnts = 0; + + // get actual number of images in the tiff file + do { + nImages++; + } while (TIFFReadDirectory(tiff)); + if (nImages > 1) + std::cout << "VtkRaster::loadImageFromTIFF() - File contains " << + nImages << " images. This method is not tested for this case." << + std::endl; + + // get image size + TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &imgWidth); + TIFFGetField(tiff, TIFFTAG_IMAGELENGTH, &imgHeight); + + // get cellsize + // Note: GeoTiff allows anisotropic pixels. This is not supported here and equilateral pixels are assumed. + if (TIFFGetField(tiff, GTIFF_PIXELSCALE, &pntCount, &pnts)) + { + if (pnts[0] != pnts[1]) + std::cout << + "VtkRaster::loadImageFromTIFF() - Warning: Original raster data has anisotrop pixel size!" + << std::endl; + cellsize = pnts[0]; + } + + // get upper left point / origin + if (TIFFGetField(tiff, GTIFF_TIEPOINTS, &pntCount, &pnts)) + { + x0 = pnts[3]; + y0 = pnts[4] - (imgHeight * cellsize); // the origin should be the lower left corner of the img + } + + // read pixel values + uint32* pixVal = + (uint32*) _TIFFmalloc(imgWidth * imgHeight * sizeof (uint32)); + if ((imgWidth > 0) && (imgHeight > 0)) + if (!TIFFReadRGBAImage(tiff, imgWidth, imgHeight, pixVal, 0)) + { + std::cout << + "VtkRaster::loadImageFromTIFF() - Error reading GeoTIFF file." + << std::endl; + _TIFFfree(pixVal); + GTIFFree(geoTiff); + XTIFFClose(tiff); + return false; + } + + // check for colormap + uint16 photometric; + TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); + // read colormap + uint16* cmap_red = NULL, * cmap_green = NULL, * cmap_blue = NULL; + /*int colormap_used = */TIFFGetField(tiff, + TIFFTAG_COLORMAP, + &cmap_red, + &cmap_green, + &cmap_blue); + + float* data = new float[imgWidth * imgHeight * 4]; + int* pxl (new int[4]); + for (int j = 0; j < imgHeight; j++) + { + int lineindex = j * imgWidth; + for (int i = 0; i < imgWidth; i++) + { // scale intensities and set nodata values to white (i.e. the background colour) + size_t pxl_idx(lineindex+i); + size_t pos = 4 * (pxl_idx); + if (photometric==1) + { + int idx = TIFFGetR(pixVal[pxl_idx]); + data[pos] = cmap_red[idx] >> 8; + data[pos+1] = cmap_green[idx] >> 8; + data[pos+2] = cmap_blue[idx] >> 8; + data[pos+3] = 1; + } + else + { + data[pos] = TIFFGetR(pixVal[pxl_idx]); + data[pos+1] = TIFFGetG(pixVal[pxl_idx]); + data[pos+2] = TIFFGetB(pixVal[pxl_idx]); + data[pos+3] = TIFFGetA(pixVal[pxl_idx]); + } + } + } + delete [] pxl; + + // set transparency values according to maximum pixel value + if (photometric==1) + { + float max_val(0); + size_t nPixels = 4*imgWidth*imgHeight; + for (size_t j = 0; j < nPixels; j++) + if (data[j]>max_val) + max_val = data[j]; + + for (size_t j = 0; j < nPixels; j+=4) + data[j+3] = max_val; + } + + vtkImageImport* image = vtkImageImport::New(); + image->SetDataOrigin(x0, y0, 0); + image->SetDataSpacing(cellsize, cellsize, cellsize); + image->SetWholeExtent(0, imgWidth-1, 0, imgHeight-1, 0, 0); + image->SetDataExtent(0, imgWidth-1, 0, imgHeight-1, 0, 0); + image->SetDataExtentToWholeExtent(); + image->SetDataScalarTypeToFloat(); + image->SetNumberOfScalarComponents(4); + image->SetImportVoidPointer(data, 0); + image->Update(); + + _TIFFfree(pixVal); + GTIFFree(geoTiff); + XTIFFClose(tiff); + return image; + } + + XTIFFClose(tiff); + std::cout << + "VtkRaster::loadImageFromTIFF() - File not recognised as GeoTIFF-Image." << + std::endl; + return NULL; + } + + std::cout << "VtkRaster::loadImageFromTIFF() - File not recognised as TIFF-Image." << + std::endl; + return NULL; +} +#endif + +vtkImageReader2* VtkRaster::loadImageFromFile(const std::string &fileName) +{ + QString file_name (QString::fromStdString(fileName)); + QFileInfo fi(file_name); + vtkImageReader2* image(NULL); + + if (fi.suffix().toLower() == "png") + image = vtkPNGReader::New(); + else if ((fi.suffix().toLower() == "jpg") || (fi.suffix().toLower() == "jpeg")) + image = vtkJPEGReader::New(); + else if (fi.suffix().toLower() == "bmp") + image = vtkBMPReader::New(); + else + { + std::cout << "VtkRaster::readImageFromFile() - File format not support, please convert to BMP, JPG, PNG or TIFF..." << std::endl; + return NULL; + } + + image->SetFileName(fileName.c_str()); + image->GetOutput()->SetScalarTypeToFloat(); + image->Update(); + return image; +} + +void VtkRaster::uint32toRGBA(const unsigned int s, int* p) +{ + p[3] = s / (256 * 256 * 256); + int r = s % (256 * 256 * 256); + p[2] = r / (256 * 256); + r %= (256 * 256); + p[1] = r / 256; + p[0] = r % 256; +} diff --git a/Gui/VtkVis/VtkRaster.h b/Gui/VtkVis/VtkRaster.h new file mode 100644 index 0000000000000000000000000000000000000000..f74797b352c78f89a009d8240aeaa4232eef91a9 --- /dev/null +++ b/Gui/VtkVis/VtkRaster.h @@ -0,0 +1,145 @@ +/** + * \file VtkRaster.h + * 2012/02/01 KR Initial implementation + * + */ +#ifndef VTKRASTER_H +#define VTKRASTER_H + +#include <fstream> + +class vtkImageAlgorithm; +class vtkImageImport; +class vtkImageReader2; + +/** + * \brief Loading raster data such as images or ArcGIS-data into VTK image data structures. + * + * The VtkRaster class enables loading of raster data such as images or ArcGIS-data. Supported image formats are ..... + * Georeferenced data can be imported via the GeoTIFF- or asc-format. + */ +class VtkRaster +{ + /// Data structure for the asc-file header. + struct ascHeader + { + int ncols; + int nrows; + double x; + double y; + double cellsize; + std::string noData; + }; + +public: + /** + * \brief Loads an image- or raster-file into an vtkImageAlgorithm-Object. + * + * Public method for loading all data formats. Internally the method automatically differentiates between + * images and georeferenced files and then calls the appropriate method for reading the file. + * \param fileName Filename of the file that should be loaded. + * \param x0 X-coordinate of the upper left corner of the data set, the default value is 0. + * \param y0 Y-coordinate of the upper left corner of the data set, the default value is 0. + * \param delta The size of each pixel in the image which is needed for correctly displaying the data, the default value is 1. + * \return The ImageAlgorithm-object. + */ + static vtkImageAlgorithm* loadImage(const std::string &fileName, + double& x0, + double& y0, + double& delta); + + /** + * \brief Loads an ASC file into a double array. + * The array alternates between pixel values and their respective alpha-values, i.e. + * result = { pixel0-value; pixel0-alpha, pixel1-value; pixel1-alpha; ... } + * + * \param fileName Filename of the file that should be loaded. + * \param x0 The x-coordinate of the origin. + * \param y0 The y-coordinate of the origin. + * \param width The width of the image. + * \param height The height of the image + * \param delta The size of each pixel in the image which is needed for correctly displaying the data. + * \return A float-array of pixel values incl. opacity (noData values are transparent) + */ + static float* loadDataFromASC(const std::string &fileName, + double &x0, + double &y0, + size_t &width, + size_t &height, + double &delta); + + /** + * \brief Loads an ASC file into a double array. + * Works exactly like loadDataFromASC(). + */ + static float* loadDataFromSurfer(const std::string &fileName, + double &x0, + double &y0, + size_t &width, + size_t &height, + double &delta); + + /** + * \brief Returns a VtkImageAlgorithm from an array of pixel values and some image meta data. + */ + static vtkImageImport* loadImageFromArray(double* data_array, + double &x0, + double &y0, + size_t &width, + size_t &height, + double &delta, + double noData); + +private: + /** + * Loads ArcGIS asc-files to a vtkImageImport object. + * \param fileName Filename of the file that should be loaded. + * \param x0 The x-coordinate of the origin. + * \param y0 The y-coordinate of the origin. + * \param delta The size of each pixel in the image which is needed for correctly displaying the data. + * \return A vtkImageImport-object (derived from vtkImageAlgorithm). + */ + static vtkImageImport* loadImageFromASC(const std::string &fileName, + double& x0, double& y0, double& delta); + + /** + * Loads ArcGIS asc-files to a QPixmap object and automatically does a contrast stretching to adjust values to 8 bit greyscale images. + * \param fileName Filename of the file that should be loaded. + * \param raster The QPixmap into which the raster data will be written. + * \param origin The upper left corner of the data set + * \param delta The size of each pixel in the image which is needed for correctly displaying the data. + * \return A vtkImageImport-object (derived from vtkImageAlgorithm). + */ +#ifdef libgeotiff_FOUND + static vtkImageImport* loadImageFromTIFF(const std::string &fileName, + double& x0, double& y0, double& delta); +#endif + + /** + * Loads image files into a QPixmap object. Since images are not geo-referenced no origin point will be returned. + * \param fileName Filename of the file that should be loaded. + * \return vtkImageReader2-object containing the image data. + */ + static vtkImageReader2* loadImageFromFile(const std::string &fileName); + + /** + * Reads the header of an ArcGIS asc-file. + * \param header The ascHeader-object into which all the information will be written. + * \param in FileInputStream used for reading the data. + * \return True if the header could be read correctly, false otherwise. + */ + static bool readASCHeader(ascHeader &header, std::ifstream &in); + + /** + * Reads the header of a Surfer grd-file. + * \param header The ascHeader-object into which all the information will be written. + * \param in FileInputStream used for reading the data. + * \return True if the header could be read correctly, false otherwise. + */ + static bool readSurferHeader(ascHeader &header, std::ifstream &in); + + /// Converts an uint32-number into a quadruple representing RGBA-colours for a pixel. + static void uint32toRGBA(const unsigned int s, int* p); +}; + +#endif //VTKRASTER_H diff --git a/Gui/VtkVis/VtkSelectionFilter.cpp b/Gui/VtkVis/VtkSelectionFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..48ccb562d942ea5d66ce832c5e74b6b8ec98b0ae --- /dev/null +++ b/Gui/VtkVis/VtkSelectionFilter.cpp @@ -0,0 +1,84 @@ +/** + * \file VtkSelectionFilter.cpp + * 2011/02/09 KR Initial implementation + * + */ + +// ** VTK INCLUDES ** +#include "VtkSelectionFilter.h" + +#include <vtkCellData.h> +#include <vtkDoubleArray.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkObjectFactory.h> +#include <vtkPointData.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkUnstructuredGrid.h> + +vtkStandardNewMacro(VtkSelectionFilter); +vtkCxxRevisionMacro(VtkSelectionFilter, "$Revision: 6995 $"); + +VtkSelectionFilter::VtkSelectionFilter() + : _thresholdLower(0.0), _thresholdUpper(1.0) +{ +} + +VtkSelectionFilter::~VtkSelectionFilter() +{ +} + +void VtkSelectionFilter::PrintSelf( ostream& os, vtkIndent indent ) +{ + this->Superclass::PrintSelf(os,indent); + os << indent << "== VtkSelectionFilter ==" << endl; +} + +int VtkSelectionFilter::RequestData( vtkInformation*, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + if (this->_selection.empty()) + { + std::cout << "VtkSelectionFilter - Error: Selection array is empty..." << std::endl; + return 0; + } + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + vtkUnstructuredGrid* input = + vtkUnstructuredGrid::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkSmartPointer<vtkDoubleArray> colors = vtkSmartPointer<vtkDoubleArray>::New(); + colors->SetNumberOfComponents(1); + colors->SetName("Selection"); + + size_t nCells = input->GetNumberOfCells(); + size_t arrayLength = this->_selection.size(); + if (nCells > arrayLength) + std::cout << + "VtkSelectionFilter - Warning: Number of cells exceeds selection array length. Surplus cells won't be examined." + << std::endl; + + for (size_t i = 0; i < arrayLength; i++) + colors->InsertNextValue(_selection[i]); + + vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkUnstructuredGrid* output = + vtkUnstructuredGrid::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + output->CopyStructure(input); + output->GetPointData()->PassData(input->GetPointData()); + output->GetCellData()->PassData(input->GetCellData()); + output->GetCellData()->AddArray(colors); + output->GetCellData()->SetActiveScalars("Selection"); + + return 1; +} + +void VtkSelectionFilter::SetSelectionArray(std::vector<double> selection, + double thresholdLower, + double thresholdUpper) +{ + this->_selection = selection; + this->_thresholdLower = thresholdLower; + this->_thresholdUpper = thresholdUpper; +} diff --git a/Gui/VtkVis/VtkSelectionFilter.h b/Gui/VtkVis/VtkSelectionFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..c58e6f6ee650a508ded1ffc3769b205a97943e39 --- /dev/null +++ b/Gui/VtkVis/VtkSelectionFilter.h @@ -0,0 +1,55 @@ +/** + * \file VtkSelectionFilter.h + * 2010/02/09 KR Initial implementation + * + */ + +#ifndef VTKSELECTIONFILTER_H +#define VTKSELECTIONFILTER_H + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" + +#include <vtkUnstructuredGridAlgorithm.h> + +#include <vector> + +class VtkSelectionFilter : public vtkUnstructuredGridAlgorithm, public VtkAlgorithmProperties +{ +public: + /// @brief Create new objects with New() because of VTKs object reference counting. + static VtkSelectionFilter* New(); + + vtkTypeRevisionMacro(VtkSelectionFilter, vtkUnstructuredGridAlgorithm); + + /// @brief Prints the mesh data to an output stream. + void PrintSelf(ostream& os, vtkIndent indent); + + /// @brief Sets user properties. + void SetUserProperty(QString name, QVariant value) + { + Q_UNUSED(name); + Q_UNUSED(value); + } + + void SetSelectionArray(std::vector<double> selection, + double thresholdLower, + double thresholdUpper); + +protected: + VtkSelectionFilter(); + ~VtkSelectionFilter(); + + /// @brief The filter logic. + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + +private: + std::vector<double> _selection; + double _thresholdLower; + double _thresholdUpper; + double _ifSmaller; +}; + +#endif // VTKSELECTIONFILTER_H diff --git a/Gui/VtkVis/VtkStationSource.cpp b/Gui/VtkVis/VtkStationSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ccf6bea5a92fd2fee143514ec5e60230adaf83cd --- /dev/null +++ b/Gui/VtkVis/VtkStationSource.cpp @@ -0,0 +1,221 @@ +/** + * \file VtkStationSource.cpp + * 24/02/2010 KR Initial implementation + * + */ + +#include "Color.h" +#include "Station.h" + +// ** VTK INCLUDES ** +#include "VtkStationSource.h" + +#include "vtkObjectFactory.h" +#include <vtkDoubleArray.h> +#include <vtkCellArray.h> +#include <vtkCellData.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkLine.h> +#include <vtkPointData.h> +#include <vtkPoints.h> +#include <vtkPolyData.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkProperty.h> + +vtkStandardNewMacro(VtkStationSource); +vtkCxxRevisionMacro(VtkStationSource, "$Revision$"); + +VtkStationSource::VtkStationSource() + : _stations(NULL) +{ + _removable = false; // From VtkAlgorithmProperties + this->SetNumberOfInputPorts(0); + + const GEOLIB::Color* c = GEOLIB::getRandomColor(); + GetProperties()->SetColor((*c)[0] / 255.0,(*c)[1] / 255.0,(*c)[2] / 255.0); + delete c; +} + +VtkStationSource::~VtkStationSource() +{ + std::map<std::string, GEOLIB::Color*>::iterator it; + for (it = _colorLookupTable.begin(); it != _colorLookupTable.end(); ++it) + delete it->second; +} + +void VtkStationSource::PrintSelf( ostream& os, vtkIndent indent ) +{ + this->Superclass::PrintSelf(os,indent); + + if (_stations->size() == 0) + return; + + os << indent << "== VtkStationSource ==" << "\n"; + + int i = 0; + for (std::vector<GEOLIB::Point*>::const_iterator it = _stations->begin(); + it != _stations->end(); ++it) + { + const double* coords = (*it)->getData(); + os << indent << "Station " << i << " (" << coords[0] << ", " << coords[1] << + ", " << coords[2] << ")\n"; + i++; + } +} + +/// Create 3d Station objects +int VtkStationSource::RequestData( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + if (!_stations) + return 0; + size_t nStations = _stations->size(); + if (nStations == 0) + return 0; + + bool useStationValues(false); + double sValue=static_cast<GEOLIB::Station*>((*_stations)[0])->getStationValue(); + for (size_t i = 1; i < nStations; i++) + if (static_cast<GEOLIB::Station*>((*_stations)[i])->getStationValue() != sValue) + { + useStationValues = true; + break; + } + + bool isBorehole = + (static_cast<GEOLIB::Station*>((*_stations)[0])->type() == + GEOLIB::Station::BOREHOLE) ? true : false; + + vtkSmartPointer<vtkInformation> outInfo = outputVector->GetInformationObject(0); + vtkSmartPointer<vtkPolyData> output = + vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + vtkSmartPointer<vtkPoints> newStations = vtkSmartPointer<vtkPoints>::New(); + vtkSmartPointer<vtkCellArray> newVerts = vtkSmartPointer<vtkCellArray>::New(); + newVerts->Allocate(nStations); + + vtkSmartPointer<vtkCellArray> newLines; + + if (isBorehole) + newLines = vtkSmartPointer<vtkCellArray>::New(); + + if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) + return 1; + + vtkSmartPointer<vtkIntArray> station_ids = vtkSmartPointer<vtkIntArray>::New(); + station_ids->SetNumberOfComponents(1); + station_ids->SetName("SiteIDs"); + + vtkSmartPointer<vtkDoubleArray> station_values = vtkSmartPointer<vtkDoubleArray>::New(); + station_values->SetNumberOfComponents(1); + station_values->SetName("StationValue"); + + vtkSmartPointer<vtkIntArray> strat_ids = vtkSmartPointer<vtkIntArray>::New(); + strat_ids->SetNumberOfComponents(1); + strat_ids->SetName("Stratigraphies"); + + size_t lastMaxIndex(0); + size_t site_count(0); + + // Generate graphic objects + for (std::vector<GEOLIB::Point*>::const_iterator it = _stations->begin(); + it != _stations->end(); ++it) + { + double coords[3] = { (*(*it))[0], (*(*it))[1], (*(*it))[2] }; + vtkIdType sid = newStations->InsertNextPoint(coords); + station_ids->InsertNextValue(site_count); + if (useStationValues) + station_values->InsertNextValue(static_cast<GEOLIB::Station*>(*it)->getStationValue()); + + if (!isBorehole) + newVerts->InsertNextCell(1, &sid); + else + { + std::vector<GEOLIB::Point*> profile = + static_cast<GEOLIB::StationBorehole*>(*it)->getProfile(); + std::vector<std::string> soilNames = + static_cast<GEOLIB::StationBorehole*>(*it)->getSoilNames(); + const size_t nLayers = profile.size(); + + for (size_t i = 1; i < nLayers; i++) + { + double* pCoords = const_cast<double*>(profile[i]->getData()); + double loc[3] = { pCoords[0], pCoords[1], pCoords[2] }; + newStations->InsertNextPoint(loc); + station_ids->InsertNextValue(site_count); + + newLines->InsertNextCell(2); + newLines->InsertCellPoint(lastMaxIndex); // start of borehole-layer + newLines->InsertCellPoint(lastMaxIndex + 1); //end of boreholelayer + lastMaxIndex++; + strat_ids->InsertNextValue(this->GetIndexByName(soilNames[i])); + if (useStationValues) + station_values->InsertNextValue(static_cast<GEOLIB::Station*>(*it)->getStationValue()); + } + lastMaxIndex++; + } + site_count++; + } + + output->SetPoints(newStations); + + if (!isBorehole) + { + output->SetVerts(newVerts); + output->GetPointData()->AddArray(station_ids); + } + else + { + output->SetLines(newLines); + output->GetCellData()->AddArray(strat_ids); + output->GetCellData()->SetActiveAttribute("Stratigraphies", + vtkDataSetAttributes::SCALARS); + } + if (useStationValues) + output->GetPointData()->AddArray(station_values); + + return 1; +} + +int VtkStationSource::RequestInformation( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + vtkInformation* outInfo = outputVector->GetInformationObject(0); + outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1); + + return 1; +} + +void VtkStationSource::SetUserProperty( QString name, QVariant value ) +{ + Q_UNUSED(name); + Q_UNUSED(value); +} + +size_t VtkStationSource::GetIndexByName( std::string name ) +{ + vtkIdType max_key(0); + for (std::map<std::string, vtkIdType>::const_iterator it = _id_map.begin(); + it != _id_map.end(); ++it) + { + if (name.compare(it->first) == 0) + return it->second; + if (it->second > max_key) + max_key = it->second; + } + + vtkIdType new_index = (_id_map.empty()) ? 0 : (max_key+1); + std::cout << "Key \"" << name << "\" (Index " << new_index << ") not found in color lookup table..." << std::endl; + _id_map.insert(std::pair<std::string, vtkIdType>(name, new_index)); + return new_index; +} diff --git a/Gui/VtkVis/VtkStationSource.h b/Gui/VtkVis/VtkStationSource.h new file mode 100644 index 0000000000000000000000000000000000000000..41fa39f4f8886ba552613ab35284aec0f07c7094 --- /dev/null +++ b/Gui/VtkVis/VtkStationSource.h @@ -0,0 +1,71 @@ +/** + * \file VtkStationSource.h + * 24/02/2010 KR Initial implementation + * + */ + +#ifndef VTKSTATIONSOURCE_H +#define VTKSTATIONSOURCE_H + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include <vtkPolyDataAlgorithm.h> + +#include "GEOObjects.h" + +/** + * \brief VTK source object for the visualisation of station data (including boreholes) + */ +class VtkStationSource : public vtkPolyDataAlgorithm, public VtkAlgorithmProperties +{ +public: + /// Create new objects with New() because of VTKs object reference counting. + static VtkStationSource* New(); + + vtkTypeRevisionMacro(VtkStationSource,vtkPolyDataAlgorithm); + + /// Returns the colour lookup table generated for boreholes. + /// This method should only be called after the colour lookup table has actually been build (via RequestData() or setColorLookupTable()). + const std::map<std::string, + GEOLIB::Color*>& getColorLookupTable() const { return _colorLookupTable; } + + /// Sets a predefined color lookup table for the colouring of borehole stratigraphies + int setColorLookupTable(const std::string &filename) { return readColorLookupTable( + _colorLookupTable, + filename); } + + /// Sets the stations as a vector + void setStations(const std::vector<GEOLIB::Point*>* stations) { _stations = stations; } + + /// Prints its data on a stream. + void PrintSelf(ostream& os, vtkIndent indent); + + virtual void SetUserProperty(QString name, QVariant value); + +protected: + VtkStationSource(); + ~VtkStationSource(); + + /// Computes the polygonal data object. + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + int RequestInformation(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + /// The stations to visualize + const std::vector<GEOLIB::Point*>* _stations; + + /// The colour table for stratigraphic data. This table is either set using the setColorLookupTable() method or is generated + /// automatically with random colours while creating the VtkStationSource-object. + std::map<std::string, GEOLIB::Color*> _colorLookupTable; + +private: + size_t GetIndexByName( std::string name ); + + std::map<std::string, vtkIdType> _id_map; +}; + +#endif // VTKSTATIONSOURCE_H diff --git a/Gui/VtkVis/VtkSurfacesSource.cpp b/Gui/VtkVis/VtkSurfacesSource.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fc7c47b42b09551aebcce43e407770ea839af8f7 --- /dev/null +++ b/Gui/VtkVis/VtkSurfacesSource.cpp @@ -0,0 +1,134 @@ +/** + * \file VtkSurfacesSource.cpp + * 3/2/2010 LB Initial implementation + * 23/04/2010 KR Surface visualisation + * + * Implementation of VtkSurfacesSource + */ + +// ** INCLUDES ** +#include "Color.h" +#include "VtkSurfacesSource.h" +#include <limits> + +#include <vtkCellArray.h> +#include <vtkCellData.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkObjectFactory.h> +#include <vtkPolyData.h> +#include <vtkPolygon.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkProperty.h> + +vtkStandardNewMacro(VtkSurfacesSource); +vtkCxxRevisionMacro(VtkSurfacesSource, "$Revision$"); + +VtkSurfacesSource::VtkSurfacesSource() + : _surfaces(NULL) +{ + _removable = false; // From VtkAlgorithmProperties + this->SetNumberOfInputPorts(0); + //this->SetColorBySurface(true); + + const GEOLIB::Color* c = GEOLIB::getRandomColor(); + vtkProperty* vtkProps = GetProperties(); + vtkProps->SetColor((*c)[0] / 255.0,(*c)[1] / 255.0,(*c)[2] / 255.0); + vtkProps->SetEdgeVisibility(0); +} + +void VtkSurfacesSource::PrintSelf( ostream& os, vtkIndent indent ) +{ + this->Superclass::PrintSelf(os,indent); + + if (_surfaces->size() == 0) + return; + + os << indent << "== VtkSurfacesSource ==" << "\n"; +} + +int VtkSurfacesSource::RequestData( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + const int nSurfaces = _surfaces->size(); + if (nSurfaces == 0) + return 0; + + const std::vector<GEOLIB::Point*>* surfacePoints = (*_surfaces)[0]->getPointVec(); + size_t nPoints = surfacePoints->size(); + + vtkSmartPointer<vtkInformation> outInfo = outputVector->GetInformationObject(0); + vtkSmartPointer<vtkPolyData> output = + vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + if (outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER()) > 0) + return 1; + + vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New(); + newPoints->Allocate(nPoints); + + vtkSmartPointer<vtkCellArray> newPolygons = vtkSmartPointer<vtkCellArray>::New(); + //newPolygons->Allocate(nSurfaces); + + vtkSmartPointer<vtkIntArray> sfcIDs = vtkSmartPointer<vtkIntArray>::New(); + sfcIDs->SetNumberOfComponents(1); + sfcIDs->SetName("SurfaceIDs"); + + for (size_t i = 0; i < nPoints; i++) + { + double* coords = const_cast<double*>((*surfacePoints)[i]->getData()); + newPoints->InsertNextPoint(coords); + } + + vtkIdType count(0); + for (std::vector<GEOLIB::Surface*>::const_iterator it = _surfaces->begin(); + it != _surfaces->end(); ++it) + { + const size_t nTriangles = (*it)->getNTriangles(); + + for (size_t i = 0; i < nTriangles; i++) + { + vtkPolygon* aPolygon = vtkPolygon::New(); + aPolygon->GetPointIds()->SetNumberOfIds(3); + + const GEOLIB::Triangle* triangle = (**it)[i]; + for (size_t j = 0; j < 3; j++) + aPolygon->GetPointIds()->SetId(j, ((*triangle)[2 - j])); + newPolygons->InsertNextCell(aPolygon); + sfcIDs->InsertNextValue(count); + aPolygon->Delete(); + } + count++; + } + + output->SetPoints(newPoints); + output->SetPolys(newPolygons); + output->GetCellData()->AddArray(sfcIDs); + output->GetCellData()->SetActiveAttribute("SurfaceIDs", vtkDataSetAttributes::SCALARS); + + return 1; +} + +int VtkSurfacesSource::RequestInformation( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + (void)inputVector; + + vtkInformation* outInfo = outputVector->GetInformationObject(0); + outInfo->Set(vtkStreamingDemandDrivenPipeline::MAXIMUM_NUMBER_OF_PIECES(), -1); + + return 1; +} + +void VtkSurfacesSource::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); + (*_algorithmUserProperties)[name] = value; +} + diff --git a/Gui/VtkVis/VtkSurfacesSource.h b/Gui/VtkVis/VtkSurfacesSource.h new file mode 100644 index 0000000000000000000000000000000000000000..f9e57ad04cf2c91db95a33d509e5b6010e36cac1 --- /dev/null +++ b/Gui/VtkVis/VtkSurfacesSource.h @@ -0,0 +1,61 @@ +/** + * \file VtkSurfacesSource.h + * 3/2/2010 LB Initial implementation + * 23/04/2010 KR Surface visualisation + * + */ + +#ifndef VTKSURFACESSOURCE_H +#define VTKSURFACESSOURCE_H + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include <vtkPolyDataAlgorithm.h> + +#include "Surface.h" + +/** + * \brief VTK source object for the visualisation of surfaces. + * Technically, surfaces are displayed as triangulated polydata objects. + */ +class VtkSurfacesSource : public vtkPolyDataAlgorithm, public VtkAlgorithmProperties +{ +public: + /// Create new objects with New() because of VTKs object reference counting. + static VtkSurfacesSource* New(); + + vtkTypeRevisionMacro(VtkSurfacesSource,vtkPolyDataAlgorithm); + + /// Sets the surfaces vector + void setSurfaces(const std::vector<GEOLIB::Surface*>* surfaces) { _surfaces = surfaces; } + + /// Prints its data on a stream. + void PrintSelf(ostream& os, vtkIndent indent); + + /** + * \brief Generates random colors for each surface. + */ + //ogsUserPropertyMacro(ColorBySurface,bool); + + virtual void SetUserProperty(QString name, QVariant value); + +protected: + VtkSurfacesSource(); + ~VtkSurfacesSource() {} + + /// Computes the polygonal data object. + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + int RequestInformation(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + + /// The surfaces to visualize + const std::vector<GEOLIB::Surface*>* _surfaces; + +private: +}; + +#endif // VTKSURFACESSOURCE_H diff --git a/Gui/VtkVis/VtkTextureOnSurfaceFilter.cpp b/Gui/VtkVis/VtkTextureOnSurfaceFilter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e27219111483e6336778cfafb1d74d7518cc53a6 --- /dev/null +++ b/Gui/VtkVis/VtkTextureOnSurfaceFilter.cpp @@ -0,0 +1,150 @@ +/** + * \file VtkTextureOnSurfaceFilter.cpp + * 3/2/2010 LB Initial implementation + * 23/04/2010 KR Surface visualisation + * + * Implementation of VtkSurfacesSource + */ + +// ** INCLUDES ** +#include <vtkCellData.h> +#include <vtkFloatArray.h> +#include <vtkInformation.h> +#include <vtkInformationVector.h> +#include <vtkObjectFactory.h> +#include <vtkPointData.h> +#include <vtkSmartPointer.h> +#include <vtkStreamingDemandDrivenPipeline.h> +#include <vtkImageShiftScale.h> +#include <vtkImageAlgorithm.h> +#include <vtkProperty.h> +#include <vtkTexture.h> + +#include "MathTools.h" +#include "VtkTextureOnSurfaceFilter.h" +#include "VtkVisHelper.h" + +vtkStandardNewMacro(VtkTextureOnSurfaceFilter); +vtkCxxRevisionMacro(VtkTextureOnSurfaceFilter, "$Revision$"); + +VtkTextureOnSurfaceFilter::VtkTextureOnSurfaceFilter() : _origin(0,0), _scalingFactor(0) +{ +} + +VtkTextureOnSurfaceFilter::~VtkTextureOnSurfaceFilter() +{ +} + +void VtkTextureOnSurfaceFilter::PrintSelf( ostream& os, vtkIndent indent ) +{ + this->Superclass::PrintSelf(os,indent); +} + +int VtkTextureOnSurfaceFilter::RequestData( vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector ) +{ + (void)request; + + if (this->GetTexture() == NULL) + { + std::cout << + "Error in VtkTextureOnSurfaceFilter::RequestData() - No texture specified ..." << + std::endl; + return 0; + } + + vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); + vtkPolyData* input = vtkPolyData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); + + int dims[3]; + this->GetTexture()->GetInput()->GetDimensions(dims); + size_t imgWidth = dims[0]; + size_t imgHeight = dims[1]; + + std::pair<int, int> min((int)_origin.first, (int)_origin.second); + std::pair<int, int> max((int)(_origin.first + (imgWidth * _scalingFactor)), + (int)(_origin.second + (imgHeight * _scalingFactor))); + + //calculate texture coordinates + vtkPoints* points = input->GetPoints(); + vtkSmartPointer<vtkFloatArray> textureCoordinates = vtkSmartPointer<vtkFloatArray>::New(); + textureCoordinates->SetNumberOfComponents(2); + textureCoordinates->SetName("TextureCoordinates"); + size_t nPoints = points->GetNumberOfPoints(); +/* // adaptation for netcdf-curtain for TERENO Demo + double dist(0.0); + for (size_t i = 0; i < nPoints; i++) + { + double coords[3]; + if ((i==0) || (i==173)) + { + if (i==0) dist=0; + } + else + { + points->GetPoint(i-1, coords); + GEOLIB::Point* pnt = new GEOLIB::Point(coords); + points->GetPoint(i, coords); + GEOLIB::Point* pnt2 = new GEOLIB::Point(coords); + if (i<173) + dist += sqrt(MathLib::sqrDist(pnt, pnt2)); + else + dist -= sqrt(MathLib::sqrDist(pnt, pnt2)); + } + points->GetPoint(i, coords); + double x = MathLib::normalize(0, 8404, dist); + double z = MathLib::normalize(-79.5, 1.5, coords[2]); + float newcoords[2] = {x, z}; + textureCoordinates->InsertNextTuple(newcoords); + } +*/ + for (size_t i = 0; i < nPoints; i++) + { + double coords[3]; + points->GetPoint(i, coords); + float newcoords[2] = { MathLib::normalize(min.first, max.first, coords[0]), + MathLib::normalize(min.second,max.second, coords[1])}; + textureCoordinates->InsertNextTuple(newcoords); + } + + // put it all together + vtkInformation* outInfo = outputVector->GetInformationObject(0); + vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + output->CopyStructure(input); + output->GetPointData()->PassData(input->GetPointData()); + output->GetCellData()->PassData(input->GetCellData()); + output->GetPointData()->SetTCoords(textureCoordinates); + + return 1; +} + +void VtkTextureOnSurfaceFilter::SetRaster(vtkImageAlgorithm* img, + double x0, double y0, + double scalingFactor) +{ + double range[2]; + img->Update(); + img->GetOutput()->GetPointData()->GetScalars()->GetRange(range); + vtkSmartPointer<vtkImageShiftScale> scale = vtkSmartPointer<vtkImageShiftScale>::New(); + scale->SetInputConnection(img->GetOutputPort()); + scale->SetShift(-range[0]); + scale->SetScale(255.0/(range[1]-range[0])); + scale->SetOutputScalarTypeToUnsignedChar(); // Comment this out to get colored grayscale textures + scale->Update(); + + vtkTexture* texture = vtkTexture::New(); + texture->InterpolateOff(); + texture->RepeatOff(); + // texture->EdgeClampOn(); // does not work + texture->SetInput(scale->GetOutput()); + this->SetTexture(texture); + + _origin = std::pair<float, float>(static_cast<float>(x0), static_cast<float>(y0)); + _scalingFactor = scalingFactor; +} + +void VtkTextureOnSurfaceFilter::SetUserProperty( QString name, QVariant value ) +{ + VtkAlgorithmProperties::SetUserProperty(name, value); +} diff --git a/Gui/VtkVis/VtkTextureOnSurfaceFilter.h b/Gui/VtkVis/VtkTextureOnSurfaceFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..2db29b931b974aaccd71ce53736d1d3b236e6eab --- /dev/null +++ b/Gui/VtkVis/VtkTextureOnSurfaceFilter.h @@ -0,0 +1,61 @@ +/** + * \file VtkTextureOnSurfaceFilter.h + * 28/05/2010 KR initial implementation + * + */ + +#ifndef VTKOGSPOLYDATAALGORITHM_H +#define VTKOGSPOLYDATAALGORITHM_H + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include <vtkImageData.h> +#include <vtkPolyDataAlgorithm.h> + +class QImage; +class vtkImageAlgorithm; + +/** + * \brief Filter class for assigning a texture to a surface. + * + * Use SetRaster() to define the texture that should be mapped on the object. + * The input of this class is a vtkPolyData object. It is important to call SetTexture() before + * calling SetInputConnection(). Texture coordinates will then be calculated automatically and + * the texture will also be saved in the VtkAlgorithmProperties object from which this class is + * derived (i.e. the texture can be returned by VtkAlgorithmProperties::GetTexture()). + * + * For convenience this class also has a converter function ConvertImageToTexture() which uses + * a QImage as input. + */ +class VtkTextureOnSurfaceFilter : public vtkPolyDataAlgorithm, public VtkAlgorithmProperties +{ +public: + /// Create new objects with New() because of VTKs object reference counting. + static VtkTextureOnSurfaceFilter* New(); + + vtkTypeRevisionMacro(VtkTextureOnSurfaceFilter,vtkPolyDataAlgorithm); + + /// Prints the object data to an output stream. + void PrintSelf(ostream& os, vtkIndent indent); + + /// Sets the raster/image to be used as a texture map + void SetRaster(vtkImageAlgorithm* img, double x0, double y0, double scalingFactor); + + virtual void SetUserProperty(QString name, QVariant value); + +protected: + VtkTextureOnSurfaceFilter(); + ~VtkTextureOnSurfaceFilter(); + + /// Copies the input data and calculates texture coordinates (this requires that SetRaster() has + /// been called before this method is executed. + int RequestData(vtkInformation* request, + vtkInformationVector** inputVector, + vtkInformationVector* outputVector); + +private: + std::pair<float, float> _origin; + double _scalingFactor; +}; + +#endif // VTKOGSPOLYDATAALGORITHM_H diff --git a/Gui/VtkVis/VtkTrackedCamera.cpp b/Gui/VtkVis/VtkTrackedCamera.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d58cbf45fb6b771a4f2cdc990b1f2a37201006fd --- /dev/null +++ b/Gui/VtkVis/VtkTrackedCamera.cpp @@ -0,0 +1,142 @@ +/** + * \file VtkTrackedCamera.cpp + * 25/08/2010 LB Initial implementation + * + * Implementation of VtkTrackedCamera class + */ + +// ** INCLUDES ** +#include "VtkTrackedCamera.h" + +#include <vtkMath.h> +#include <vtkPerspectiveTransform.h> + +#include <QSettings> + +VtkTrackedCamera::VtkTrackedCamera(QObject* parent) + : QObject(parent), vtkOpenGLCamera() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + settings.beginGroup("Tracking"); + // Read from settings + if (settings.contains("artOffsetX")) + { + _trackedPositionOffset[0] = settings.value("artOffsetX").toDouble(); + _trackedPositionOffset[1] = settings.value("artOffsetY").toDouble(); + _trackedPositionOffset[2] = settings.value("artOffsetZ").toDouble(); + _realToVirtualScale = settings.value("artRealToVirtualScale").toDouble(); + _screenAspectRatio = settings.value("artAspectRatio").toDouble(); + _screenHeight = settings.value("artScreenHeight").toDouble(); + } + // Default values + else + { + _trackedPositionOffset[0] = 0; + _trackedPositionOffset[1] = 0; + _trackedPositionOffset[2] = 0; + _realToVirtualScale = 1.0; + _screenAspectRatio = 1.6; + _screenHeight = 0.4; + } + settings.endGroup(); + + // if z up + _trackedPosition[0] = 0; + _trackedPosition[1] = 2; + _trackedPosition[2] = 0; + _focalPoint[0] = 0; + _focalPoint[1] = 0; + _focalPoint[2] = 0; + SetPosition(0,0,0); + SetFocalPoint(0,1,0); + SetViewUp(0,0,1); +} + +VtkTrackedCamera::~VtkTrackedCamera() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + settings.beginGroup("Tracking"); + settings.setValue("artOffsetX", _trackedPositionOffset[0]); + settings.setValue("artOffsetY", _trackedPositionOffset[1]); + settings.setValue("artOffsetZ", _trackedPositionOffset[2]); + settings.setValue("artRealToVirtualScale", _realToVirtualScale); + settings.setValue("artAspectRatio", _screenAspectRatio); + settings.setValue("artScreenHeight", _screenHeight); + settings.endGroup(); +} + +void VtkTrackedCamera::setTrackingData(double x, double y, double z) +{ + _trackedPosition[0] = x + _trackedPositionOffset[0]; + _trackedPosition[1] = y + _trackedPositionOffset[1]; + _trackedPosition[2] = z + _trackedPositionOffset[2]; + updateView(); +} + +void VtkTrackedCamera::setFocalPoint(double x, double y, double z) +{ + _focalPoint[0] = x; + _focalPoint[1] = y; + _focalPoint[2] = z; + updateView(); +} + +void VtkTrackedCamera::setTrackingOffset(double x, double y, double z) +{ + setTrackingOffsetX(x); + setTrackingOffsetY(y); + setTrackingOffsetZ(z); +} + +void VtkTrackedCamera::translate(double x, double y, double z) +{ + setFocalPoint(_focalPoint[0] + x, _focalPoint[1] + y, _focalPoint[2] + z); + updateView(); +} + +void VtkTrackedCamera::rotate(double yaw, double elevation, double roll) +{ + Q_UNUSED(yaw); + Q_UNUSED(elevation); + Q_UNUSED(roll); +} + +void VtkTrackedCamera::updateView() +{ + double x = _trackedPosition[0] * _realToVirtualScale; + double y = _trackedPosition[1] * _realToVirtualScale; + double z = _trackedPosition[2] * _realToVirtualScale; + double angle = vtkMath::DegreesFromRadians( + 2 * atan(0.5 * _screenHeight * _realToVirtualScale / y)); + + //double newfocal[3] = {_x + x, _y, _z + z}; + //double newpos[3] = {_x + x, _y + y, _z + z}; + //double viewup[3] = {0, 0, 1}; + SetViewAngle(angle); + //SetPosition(newpos); + //SetFocalPoint(newfocal); + //SetViewUp(viewup); + //SetClippingRange(_zNear, _zFar); + SetViewShear(x / y, z / y, 1); // see http://www.vtk.org/pipermail/vtkusers/2005-March/078735.html + + emit viewUpdated(); +} + +void VtkTrackedCamera::updatedFromOutside() +{ + double pos[3], dir[3]; + GetPosition(pos); + GetDirectionOfProjection(dir); + + vtkMath::Normalize(dir); // Get the view direction + dir[0] = dir[0] * _trackedPosition[1]; // Multiplying the view direction + dir[1] = dir[1] * _trackedPosition[1]; // with the tracked distance to the + dir[2] = dir[2] * _trackedPosition[1]; // display results in the vector + _focalPoint[0] = dir[0] + pos[0]; // from the position to the new + _focalPoint[1] = dir[1] + pos[1]; // focal point. + _focalPoint[2] = dir[2] + pos[2]; + + updateView(); + + //std::cout << "Camera slot" << std::endl; +} diff --git a/Gui/VtkVis/VtkTrackedCamera.h b/Gui/VtkVis/VtkTrackedCamera.h new file mode 100644 index 0000000000000000000000000000000000000000..6a04167d08cc408613d8bd9ad8090e8250f34cbb --- /dev/null +++ b/Gui/VtkVis/VtkTrackedCamera.h @@ -0,0 +1,97 @@ +/** + * \file VtkTrackedCamera.h + * 25/08/2010 LB Initial implementation + */ + +#ifndef VTKTRACKEDCAMERA_H +#define VTKTRACKEDCAMERA_H + +#include <QObject> +#include <vtkOpenGLCamera.h> + +/// @brief This camera implements view shearing for using with a head tracking +/// system. +class VtkTrackedCamera : public QObject, public vtkOpenGLCamera +{ + Q_OBJECT + +public: + /// @brief Constructor. + VtkTrackedCamera(QObject* parent); + + /// @brief Destructor + virtual ~VtkTrackedCamera(); + + /// Sets the scaling from real meters to virtual meters. + void setRealToVirtualScale(double scale) { _realToVirtualScale = scale; } + double realToVirtualScale () const { return _realToVirtualScale; } + + double trackingOffsetX() const { return _trackedPositionOffset[0]; } + double trackingOffsetY() const { return _trackedPositionOffset[1]; } + double trackingOffsetZ() const { return _trackedPositionOffset[2]; } + + double screenAspectRatio() const { return _screenAspectRatio; } + double screenHeight() const { return _screenHeight; } + +public slots: + //void setTrackinData(double position[3], double dir[3]); + /// @brief Sets the tracked position. The coordinate origin must be the center + /// of the projection wall. See also setTrackingOffset(). + void setTrackingData(double x, double y, double z); + + /// Sets the focal point in world coordinates. This point corresponds to the + /// center of the projection wall. + void setFocalPoint(double x, double y, double z); + + /// @brief Sets an offset of the tracked position. This must be used to setup + /// the origin of the calibrated tracking space. + void setTrackingOffset(double x, double y, double z); + + void setTrackingOffsetX(double val) { _trackedPositionOffset[0] = val; } + void setTrackingOffsetY(double val) { _trackedPositionOffset[1] = val; } + void setTrackingOffsetZ(double val) { _trackedPositionOffset[2] = val; } + + /// Move the camera by the given vector. + void translate(double x, double y, double z); + + /// Rotate the camera by the given angles. + void rotate(double yaw, double elevation, double roll); + + /// Updates the view. + void updateView(); + + /// Must be called to update the view after the camera was modified from the + /// outside, e.g. from the vtkRenderWindowInteractor. + void updatedFromOutside(); + + /// @brief Sets the screen properties. + /// @param aspectRatio width / height + /// @param height The screen height in meter. + void setScreenProperties(double aspectRatio, double height) + { + _screenAspectRatio = aspectRatio; + _screenHeight = height; + } + + /// @brief Sets the screen aspect ratio (width / height). + void setScreenAspectRatio(double ratio) { _screenAspectRatio = ratio; + updateView(); } + + /// @brief Sets the screen height in meter. + void setScreenHeight(double height) { _screenHeight = height; + updateView(); } + +private: + double _focalPoint[3]; + double _trackedPosition[3]; + double _trackedPositionOffset[3]; + double _realToVirtualScale; + double _screenAspectRatio; + double _screenHeight; + +signals: + /// Is emitted from updateView(). + void viewUpdated(); +}; + +#endif // VTKTRACKEDCAMERA_H diff --git a/Gui/VtkVis/VtkVisHelper.cpp b/Gui/VtkVis/VtkVisHelper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..420b1b1f22949b2041ea21373703eb3abf77deb4 --- /dev/null +++ b/Gui/VtkVis/VtkVisHelper.cpp @@ -0,0 +1,58 @@ +/** + * \file VtkVisHelper.cpp + * 22/09/2010 LB Initial implementation + * + * Implementation of VtkVisHelper class + */ + +// ** INCLUDES ** +#include "VtkVisHelper.h" + +#include <vtkImageData.h> +#include <vtkPointData.h> +#include <vtkSmartPointer.h> +#include <vtkTexture.h> +#include <vtkUnsignedCharArray.h> + +#include <QImage> + +vtkImageData* VtkVisHelper::QImageToVtkImageData(QImage &img) +{ + size_t imgWidth = img.width(), imgHeight = img.height(); + vtkSmartPointer<vtkUnsignedCharArray> data = vtkSmartPointer<vtkUnsignedCharArray>::New(); + data->SetNumberOfComponents(3); + data->SetNumberOfTuples( imgWidth * imgHeight ); + + for (size_t j = 0; j < imgHeight; j++) + for (size_t i = 0; i < imgWidth; i++) + { + QRgb pix = img.pixel(i,j); + const float color[3] = { static_cast<float>(qRed(pix)), + static_cast<float>(qGreen(pix)), + static_cast<float>(qBlue(pix)) + }; + data->SetTuple(j * imgWidth + i, color); + } + + vtkImageData* imgData = vtkImageData::New(); + imgData->SetExtent(0, imgWidth - 1, 0, imgHeight - 1, 0, 0); + imgData->SetOrigin(0, 0, 0); + imgData->SetNumberOfScalarComponents(3); + imgData->GetPointData()->SetScalars(data); + + return imgData; +} + +vtkTexture* VtkVisHelper::QImageToVtkTexture(QImage &img) +{ + vtkSmartPointer<vtkImageData> imgData = QImageToVtkImageData(img); + + vtkTexture* texture = vtkTexture::New(); + texture->InterpolateOff(); + texture->RepeatOff(); + //texture->EdgeClampOff(); + //texture->SetBlendingMode(0); + texture->SetInput(imgData); + + return texture; +} diff --git a/Gui/VtkVis/VtkVisHelper.h b/Gui/VtkVis/VtkVisHelper.h new file mode 100644 index 0000000000000000000000000000000000000000..088bd54aa46a3f5d0861246bb3b1853ef5fd5c83 --- /dev/null +++ b/Gui/VtkVis/VtkVisHelper.h @@ -0,0 +1,23 @@ +/** + * \file VtkVisHelper.h + * 22/09/2010 LB Initial implementation + */ + +#ifndef VTKVISHELPER_H +#define VTKVISHELPER_H + +class QImage; +class vtkTexture; +class vtkImageData; + +class VtkVisHelper +{ +public: + /// @brief Converts a QImage to vtkImageData. + static vtkImageData* QImageToVtkImageData(QImage &img); + + /// @brief Converts a QImage-object into a vtkTexture-object + static vtkTexture* QImageToVtkTexture(QImage &img); +}; + +#endif // VTKVISHELPER_H diff --git a/Gui/VtkVis/VtkVisImageItem.cpp b/Gui/VtkVis/VtkVisImageItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b523a0116e915655d611987e4daacbca8859ae98 --- /dev/null +++ b/Gui/VtkVis/VtkVisImageItem.cpp @@ -0,0 +1,152 @@ +/** + * \file VtkVisImageItem.cpp + * 2011/09/29 KR Initial implementation + */ + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include "VtkVisImageItem.h" +#include "VtkGeoImageSource.h" + +#include <vtkActor.h> +#include <vtkDataSetMapper.h> +#include <vtkImageAlgorithm.h> +#include <vtkImageChangeInformation.h> +#include <vtkImageData.h> +#include <vtkPointData.h> +#include <vtkRenderer.h> +#include <vtkSmartPointer.h> +#include <vtkImageShiftScale.h> + +// export +#include <vtkImageActor.h> +#include <vtkXMLImageDataWriter.h> + +VtkVisImageItem::VtkVisImageItem( + vtkAlgorithm* algorithm, TreeItem* parentItem, + const QList<QVariant> data /*= QList<QVariant>()*/) + : VtkVisPipelineItem(algorithm, parentItem, data), _transformFilter(NULL) +{ +} + +VtkVisImageItem::VtkVisImageItem( + VtkCompositeFilter* compositeFilter, TreeItem* parentItem, + const QList<QVariant> data /*= QList<QVariant>()*/) + : VtkVisPipelineItem(compositeFilter, parentItem, data), _transformFilter(NULL) +{ +} + +VtkVisImageItem::~VtkVisImageItem() +{ + _transformFilter->Delete(); +} + +void VtkVisImageItem::Initialize(vtkRenderer* renderer) +{ + vtkImageAlgorithm* img = dynamic_cast<vtkImageAlgorithm*>(_algorithm); + img->Update(); + //VtkGeoImageSource* img = dynamic_cast<VtkGeoImageSource*>(_algorithm); + + double origin[3]; + double spacing[3]; + double range[2]; + img->GetOutput()->GetOrigin(origin); + img->GetOutput()->GetSpacing(spacing); + //img->getRange(range); + img->GetOutput()->GetPointData()->GetScalars()->GetRange(range); + vtkImageShiftScale* scale = vtkImageShiftScale::New(); + scale->SetOutputScalarTypeToUnsignedChar(); + scale->SetInputConnection(img->GetOutputPort()); + scale->SetShift(-range[0]); + scale->SetScale(255.0/(range[1]-range[0])); + + _transformFilter = vtkImageChangeInformation::New(); + _transformFilter->SetInputConnection(scale->GetOutputPort()); + //double origin[3]; + //img->getOrigin(origin); + //double spacing = img->getSpacing(); + //_transformFilter->SetOutputOrigin(origin2); + //_transformFilter->SetOutputSpacing(spacing2); + _transformFilter->Update(); + + _renderer = renderer; + + // Use a special vtkImageActor instead of vtkActor + vtkImageActor* imageActor = vtkImageActor::New(); + imageActor->SetInput(_transformFilter->GetOutput()); + _actor = imageActor; + _renderer->AddActor(_actor); + + // Set pre-set properties + VtkAlgorithmProperties* vtkProps = dynamic_cast<VtkAlgorithmProperties*>(_algorithm); + if (vtkProps) + setVtkProperties(vtkProps); + + VtkVisPipelineItem* parentItem = dynamic_cast<VtkVisPipelineItem*>(this->parentItem()); + while (parentItem) + { + VtkAlgorithmProperties* parentProps = + dynamic_cast<VtkAlgorithmProperties*>(parentItem->algorithm()); + if (parentProps) + { + VtkAlgorithmProperties* newProps = new VtkAlgorithmProperties(); + newProps->SetScalarVisibility(parentProps->GetScalarVisibility()); + newProps->SetTexture(parentProps->GetTexture()); + setVtkProperties(newProps); + vtkProps = newProps; + parentItem = NULL; + } + else + parentItem = dynamic_cast<VtkVisPipelineItem*>(parentItem->parentItem()); + } + + // Set active scalar to the desired one from VtkAlgorithmProperties + // or to match those of the parent. + if (vtkProps) + { + if (vtkProps->GetActiveAttribute().length() > 0) + this->SetActiveAttribute(vtkProps->GetActiveAttribute()); + else + { + VtkVisPipelineItem* visParentItem = + dynamic_cast<VtkVisPipelineItem*>(this->parentItem()); + if (visParentItem) + this->SetActiveAttribute(visParentItem->GetActiveAttribute()); + if (vtkProps->GetTexture() != NULL) + this->SetActiveAttribute("Solid Color"); + } + } +} + +void VtkVisImageItem::setVtkProperties(VtkAlgorithmProperties* vtkProps) +{ + // todo implementation + (void)vtkProps; +} + +int VtkVisImageItem::callVTKWriter(vtkAlgorithm* algorithm, const std::string &filename) const +{ + vtkImageAlgorithm* algID = dynamic_cast<vtkImageAlgorithm*>(algorithm); + if (algID) + { + vtkSmartPointer<vtkXMLImageDataWriter> iWriter = + vtkSmartPointer<vtkXMLImageDataWriter>::New(); + iWriter->SetInput(algID->GetOutputDataObject(0)); + std::string filenameWithExt = filename; + filenameWithExt.append(".vti"); + iWriter->SetFileName(filenameWithExt.c_str()); + return iWriter->Write(); + } + std::cout << "VtkVisPipelineItem::writeToFile() - Unknown data type..." << std::endl; + return 0; +} + +void VtkVisImageItem::setTranslation(double x, double y, double z) const +{ + _transformFilter->SetOriginTranslation(x,y,z); +} + +vtkAlgorithm* VtkVisImageItem::transformFilter() const +{ + return _transformFilter; +} diff --git a/Gui/VtkVis/VtkVisImageItem.h b/Gui/VtkVis/VtkVisImageItem.h new file mode 100644 index 0000000000000000000000000000000000000000..827d87a3d37e9d9f90c49c97b83d9d5778f52b05 --- /dev/null +++ b/Gui/VtkVis/VtkVisImageItem.h @@ -0,0 +1,63 @@ +/** + * \file VtkVisImageItem.h + * 2011/09/29 KR Initial implementation + * + */ + +#ifndef VTKVISIMAGEITEM_H +#define VTKVISIMAGEITEM_H + +// ** INCLUDES ** +#include "VtkVisPipelineItem.h" + +class vtkAlgorithm; +class vtkImageChangeInformation; +class vtkPointSet; +class vtkProp3D; +class vtkRenderer; + +class vtkOsgActor; + +class VtkAlgorithmProperties; +class VtkCompositeFilter; + +/** + * \brief An item in the VtkVisPipeline containing an image to be visualized. + * + * Any vtkImageAlgorithm object is represented by a VtkVisImageItem to be assigned a mapper, + * an actor and its visualization properties. + * \sa VtkVisPipelineItem + */ +class VtkVisImageItem : public VtkVisPipelineItem +{ +public: + /// @brief Constructor for a source/filter object. + VtkVisImageItem(vtkAlgorithm* algorithm, + TreeItem* parentItem, + const QList<QVariant> data = QList<QVariant>()); + + /// @brief Constructor for composite filter + VtkVisImageItem(VtkCompositeFilter* compositeFilter, TreeItem* parentItem, + const QList<QVariant> data = QList<QVariant>()); + + ~VtkVisImageItem(); + + /// @brief Initializes vtkMapper and vtkActor necessary for visualization of + /// the item and sets the item's properties. + void Initialize(vtkRenderer* renderer); + + void setTranslation(double x, double y, double z) const; + + vtkAlgorithm* transformFilter() const; + +protected: + /// Selects the appropriate VTK-Writer object and writes the object to a file with the given name. + virtual int callVTKWriter(vtkAlgorithm* algorithm, const std::string &filename) const; + void setVtkProperties(VtkAlgorithmProperties* vtkProps); + +private: + vtkImageChangeInformation* _transformFilter; +}; + +#endif // VTKVISIMAGEITEM_H + diff --git a/Gui/VtkVis/VtkVisPipeline.cpp b/Gui/VtkVis/VtkVisPipeline.cpp new file mode 100644 index 0000000000000000000000000000000000000000..06929b7903097d23ac42ed0ec3accf8f82b29743 --- /dev/null +++ b/Gui/VtkVis/VtkVisPipeline.cpp @@ -0,0 +1,587 @@ +/** + * \file VtkVisPipeline.cpp + * 17/2/2010 LB Initial implementation + * + * Implementation of VtkVisPipeline + */ + +// ** INCLUDES ** +#include "VtkVisPipeline.h" + +// MathLib +#include "InterpolationAlgorithms/LinearIntervalInterpolation.h" + +//#include "Model.h" +#include "ProcessModel.h" +#include "GeoTreeModel.h" +#include "MeshQualityEquiAngleSkew.h" +#include "MeshQualityArea.h" +#include "MeshQualityVolume.h" +#include "MeshQualityShortestLongestRatio.h" +#include "MshItem.h" +#include "MshModel.h" +#include "StationTreeModel.h" +#include "TreeModel.h" +#include "VtkAlgorithmProperties.h" +#include "VtkCompositeSelectionFilter.h" +#include "VtkCompositeGeoObjectFilter.h" +#include "VtkFilterFactory.h" +#include "VtkMeshSource.h" +#include "VtkTrackedCamera.h" +#include "VtkVisImageItem.h" +#include "VtkVisPipelineItem.h" +#include "VtkVisPointSetItem.h" + +#include <vtkAlgorithm.h> +#include <vtkCamera.h> +#include <vtkGenericDataObjectReader.h> +#include <vtkImageActor.h> +#include <vtkImageReader2.h> +#include <vtkLight.h> +#include <vtkPointSet.h> +#include <vtkProp3D.h> +#include <vtkRenderer.h> +#include <vtkSmartPointer.h> +#include <vtkTransformFilter.h> +#include <vtkXMLImageDataReader.h> +#include <vtkXMLPolyDataReader.h> +#include <vtkXMLRectilinearGridReader.h> +#include <vtkXMLStructuredGridReader.h> +#include <vtkXMLUnstructuredGridReader.h> + +#include <vtkCellData.h> +#include <vtkFieldData.h> +#include <vtkPointData.h> + +#include <QColor> +#include <QFileInfo> +#include <QSettings> +#include <QString> +#include <QTime> + +VtkVisPipeline::VtkVisPipeline( vtkRenderer* renderer, QObject* parent /*= 0*/ ) + : TreeModel(parent), _renderer(renderer), _highlighted_geo_index(QModelIndex()) +{ + QList<QVariant> rootData; + rootData << "Object name" << "Visible"; + delete _rootItem; + _rootItem = new TreeItem(rootData, NULL); + + QSettings settings("UFZ", "OpenGeoSys-5"); + QVariant backgroundColorVariant = settings.value("VtkBackgroundColor"); + if (backgroundColorVariant != QVariant()) + this->setBGColor(backgroundColorVariant.value<QColor>()); + + _resetCameraOnAddOrRemove = true; +} + +bool VtkVisPipeline::setData( const QModelIndex &index, const QVariant &value, + int role /* = Qt::EditRole */ ) +{ + emit vtkVisPipelineChanged(); + + return TreeModel::setData(index, value, role); +} + +void VtkVisPipeline::addLight(const GEOLIB::Point &pos) +{ + double lightPos[3]; + for (std::list<vtkLight*>::iterator it = _lights.begin(); it != _lights.end(); ++it) + { + (*it)->GetPosition(lightPos); + if (pos[0] == lightPos[0] && pos[1] == lightPos[1] && pos[2] == lightPos[2]) + return; + } + vtkLight* l = vtkLight::New(); + l->SetPosition(pos[0], pos[1], pos[2]); + _renderer->AddLight(l); + _lights.push_back(l); +} + +vtkLight* VtkVisPipeline::getLight(const GEOLIB::Point &pos) const +{ + double lightPos[3]; + for (std::list<vtkLight*>::const_iterator it = _lights.begin(); it != _lights.end(); ++it) + { + (*it)->GetPosition(lightPos); + if (pos[0] == lightPos[0] && pos[1] == lightPos[1] && pos[2] == lightPos[2]) + return *it; + } + return NULL; +} + +void VtkVisPipeline::removeLight(const GEOLIB::Point &pos) +{ + double lightPos[3]; + for (std::list<vtkLight*>::iterator it = _lights.begin(); it != _lights.end(); ++it) + { + (*it)->GetPosition(lightPos); + if (pos[0] == lightPos[0] && pos[1] == lightPos[1] && pos[2] == lightPos[2]) + { + _renderer->RemoveLight(*it); + (*it)->Delete(); + _lights.erase(it); + return; + } + } +} + +const QColor VtkVisPipeline::getBGColor() const +{ + double* color = _renderer->GetBackground(); + QColor c(static_cast<int>(color[0] * 255), + static_cast<int>(color[1] * 255), + static_cast<int>(color[2] * 255)); + return c; +} + +void VtkVisPipeline::setBGColor(const QColor &color) +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + settings.setValue("VtkBackgroundColor", color); + _renderer->SetBackground(color.redF(), color.greenF(), color.blueF()); +} + +QModelIndex VtkVisPipeline::getIndex( vtkProp3D* actor ) +{ + return _actorMap.value(actor, QModelIndex()); +} + +Qt::ItemFlags VtkVisPipeline::flags( const QModelIndex &index ) const +{ + Qt::ItemFlags defaultFlags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + + if (!index.isValid()) + return Qt::ItemIsEnabled; + + //if (index.column() == 1) + // defaultFlags |= Qt::ItemIsEditable; + + return defaultFlags; +} + +void VtkVisPipeline::loadFromFile(QString filename) +{ +#ifndef NDEBUG + QTime myTimer; + myTimer.start(); + std::cout << "VTK Read: " << filename.toStdString() << + std::endl << std::flush; +#endif + + if (filename.size() > 0) + { + vtkXMLDataReader* reader; + if (filename.endsWith("vti")) + reader = vtkXMLImageDataReader::New(); + else if (filename.endsWith("vtr")) + reader = vtkXMLRectilinearGridReader::New(); + else if (filename.endsWith("vts")) + reader = vtkXMLStructuredGridReader::New(); + else if (filename.endsWith("vtp")) + reader = vtkXMLPolyDataReader::New(); + else if (filename.endsWith("vtu")) + reader = vtkXMLUnstructuredGridReader::New(); + else if (filename.endsWith("vtk")) + { + vtkGenericDataObjectReader* oldStyleReader = + vtkGenericDataObjectReader::New(); + oldStyleReader->SetFileName(filename.toStdString().c_str()); + oldStyleReader->ReadAllFieldsOn(); + oldStyleReader->ReadAllScalarsOn(); + oldStyleReader->Update(); + vtkDataSet* dataSet = vtkDataSet::SafeDownCast(oldStyleReader->GetOutput()); + if (dataSet) + { + this->listArrays(dataSet); + addPipelineItem(oldStyleReader); + } + else + std::cout << "Error loading vtk file: not a valid vtkDataSet." << + std::endl; + + return; + } + else + return; + + reader->SetFileName(filename.toStdString().c_str()); + // TODO: insert ReadAllScalarsOn()-equivalent for xml-file-reader here, otherwise arrays are not available in GUI! + reader->Update(); + //std::cout << "#cell scalars: " << reader->GetNumberOfCellArrays() << std::endl; + //std::cout << "#point scalars: " << reader->GetNumberOfPointArrays() << std::endl; + + vtkDataSet* dataSet = reader->GetOutputAsDataSet(); + if (dataSet) + { + this->listArrays(dataSet); + addPipelineItem(reader); + } + else + std::cout << "Error loading vtk file: not a valid vtkDataSet." << std::endl; + + //reader->Delete(); + } + +#ifndef NDEBUG + std::cout << myTimer.elapsed() << " ms" << std::endl; +#endif +} + +void VtkVisPipeline::setGlobalSuperelevation(double factor) const +{ + // iterate over all source items + for (int i = 0; i < _rootItem->childCount(); ++i) + { + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(_rootItem->child(i)); + item->setScale(1.0, 1.0, factor); + + // recursively set on all child items + item->setScaleOnChildren(1.0, 1.0, 1.0); + } + + emit vtkVisPipelineChanged(); +} + +void VtkVisPipeline::setGlobalBackfaceCulling(bool enable) const +{ + // iterate over all source items + for (int i = 0; i < _rootItem->childCount(); ++i) + { + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(_rootItem->child(i)); + item->setBackfaceCulling(enable); + + // recursively set on all child items + item->setBackfaceCullingOnChildren(enable); + } + + emit vtkVisPipelineChanged(); +} + +void VtkVisPipeline::addPipelineItem(GeoTreeModel* model, + const std::string &name, + GEOLIB::GEOTYPE type) +{ + addPipelineItem(model->vtkSource(name, type)); +} + +void VtkVisPipeline::addPipelineItem(StationTreeModel* model, const std::string &name) +{ + addPipelineItem(model->vtkSource(name)); +} + +void VtkVisPipeline::addPipelineItem(ProcessModel* model, const FiniteElement::ProcessType pcs_type, const FEMCondition::CondType cond_type) +{ + addPipelineItem(model->vtkSource(pcs_type, cond_type)); +} + +void VtkVisPipeline::addPipelineItem(MshModel* model, const QModelIndex &idx) +{ + addPipelineItem(static_cast<MshItem*>(model->getItem(idx))->vtkSource()); +} + +QModelIndex VtkVisPipeline::addPipelineItem(VtkVisPipelineItem* item, const QModelIndex &parent) +{ + item->Initialize(_renderer); + TreeItem* parentItem = item->parentItem(); + parentItem->appendChild(item); + + if (!parent.isValid()) // Set global superelevation on source objects + { + QSettings settings("UFZ, OpenGeoSys-5"); + if (dynamic_cast<vtkImageAlgorithm*>(item->algorithm()) == NULL) // if not an image + item->setScale(1.0, 1.0, settings.value("globalSuperelevation", 1.0).toDouble()); + } + + int parentChildCount = parentItem->childCount(); + QModelIndex newIndex = index(parentChildCount - 1, 0, parent); + + if (_resetCameraOnAddOrRemove) + _renderer->ResetCamera(_renderer->ComputeVisiblePropBounds()); + _actorMap.insert(item->actor(), newIndex); + + // Do not interpolate images + if (dynamic_cast<vtkImageAlgorithm*>(item->algorithm())) + static_cast<vtkImageActor*>(item->actor())->InterpolateOff(); + + reset(); + emit vtkVisPipelineChanged(); + + return newIndex; +} + +QModelIndex VtkVisPipeline::addPipelineItem( vtkAlgorithm* source, + QModelIndex parent /* = QModelindex() */) +{ + TreeItem* parentItem = getItem(parent); + + QList<QVariant> itemData; + QString itemName; + if (!parent.isValid()) // if source object + { + vtkGenericDataObjectReader* reader = + dynamic_cast<vtkGenericDataObjectReader*>(source); + vtkImageReader2* imageReader = dynamic_cast<vtkImageReader2*>(source); + VtkAlgorithmProperties* props = dynamic_cast<VtkAlgorithmProperties*>(source); + if (reader) + { + QFileInfo fi(QString(reader->GetFileName())); + itemName = fi.fileName(); + } + else if (imageReader) + { + QFileInfo fi(QString(imageReader->GetFileName())); + itemName = fi.fileName(); + } + else if (props) + { + QFileInfo fi(props->GetName()); + itemName = fi.fileName(); + } + else + itemName = QString(source->GetClassName()); + } + else + itemName = QString(source->GetClassName()); + itemData << itemName << true; + + VtkVisPipelineItem* item(NULL); + vtkImageAlgorithm* alg = dynamic_cast<vtkImageAlgorithm*>(source); + if (alg) + item = new VtkVisImageItem(source, parentItem, itemData); + else + item = new VtkVisPointSetItem(source, parentItem, itemData); + return this->addPipelineItem(item, parent); +} + +void VtkVisPipeline::removeSourceItem(GeoTreeModel* model, + const std::string &name, + GEOLIB::GEOTYPE type) +{ + for (int i = 0; i < _rootItem->childCount(); i++) + { + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(getItem(index(i, 0))); + if (item->algorithm() == model->vtkSource(name, type)) + { + removePipelineItem(index(i, 0)); + return; + } + } +} + +void VtkVisPipeline::removeSourceItem(ProcessModel* model, const FiniteElement::ProcessType pcs_type, const FEMCondition::CondType cond_type) +{ + for (int i = 0; i < _rootItem->childCount(); i++) + { + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(getItem(index(i, 0))); + if (item->algorithm() == model->vtkSource(pcs_type, cond_type)) + { + removePipelineItem(index(i, 0)); + return; + } + } +} + +void VtkVisPipeline::removeSourceItem(StationTreeModel* model, const std::string &name) +{ + for (int i = 0; i < _rootItem->childCount(); i++) + { + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(getItem(index(i, 0))); + if (item->algorithm() == model->vtkSource(name)) + { + removePipelineItem(index(i, 0)); + return; + } + } +} + +void VtkVisPipeline::removeSourceItem(MshModel* model, const QModelIndex &idx) +{ + MshItem* sItem = static_cast<MshItem*>(model->getItem(idx)); + + for (int i = 0; i < _rootItem->childCount(); i++) + { + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(getItem(index(i, 0))); + if (item->algorithm() == sItem->vtkSource()) + { + removePipelineItem(index(i, 0)); + return; + } + } +} + +void VtkVisPipeline::removePipelineItem( QModelIndex index ) +{ + if (!index.isValid()) + return; + + QMap<vtkProp3D*, QModelIndex>::iterator it = _actorMap.begin(); + while (it != _actorMap.end()) + { + QModelIndex itIndex = it.value(); + if (itIndex == index) + { + _actorMap.erase(it); + break; + } + ++it; + } + + //TreeItem* item = getItem(index); + removeRows(index.row(), 1, index.parent()); + + if (_resetCameraOnAddOrRemove) + _renderer->ResetCamera(_renderer->ComputeVisiblePropBounds()); + emit vtkVisPipelineChanged(); +} + +void VtkVisPipeline::listArrays(vtkDataSet* dataSet) +{ + if (dataSet) + { + vtkPointData* pointData = dataSet->GetPointData(); + std::cout << " #point data arrays: " << pointData->GetNumberOfArrays() << + std::endl; + for (int i = 0; i < pointData->GetNumberOfArrays(); i++) + std::cout << " Name: " << pointData->GetArrayName(i) << std::endl; + + vtkCellData* cellData = dataSet->GetCellData(); + std::cout << " #cell data arrays: " << cellData->GetNumberOfArrays() << std::endl; + for (int i = 0; i < cellData->GetNumberOfArrays(); i++) + std::cout << " Name: " << cellData->GetArrayName(i) << std::endl; + } + else + std::cout << "Error loading vtk file: not a valid vtkDataSet." << std::endl; +} + +void VtkVisPipeline::checkMeshQuality(VtkMeshSource* source, MshQualityType::type t) +{ + if (source) + { + const MeshLib::CFEMesh* mesh = source->GetGrid()->getCFEMesh(); + MeshLib::MeshQualityChecker* checker (NULL); + if (t == MshQualityType::EDGERATIO) + checker = new MeshLib::MeshQualityShortestLongestRatio(mesh); + else if (t == MshQualityType::AREA) + checker = new MeshLib::MeshQualityArea(mesh); + else if (t == MshQualityType::VOLUME) + checker = new MeshLib::MeshQualityVolume(mesh); + else if (t == MshQualityType::EQUIANGLESKEW) + checker = new MeshLib::MeshQualityEquiAngleSkew(mesh); + else + { + std::cout << "Error in VtkVisPipeline::checkMeshQuality() - Unknown MshQualityType..." + << std::endl; + delete checker; + return; + } + checker->check (); + + std::vector<double> quality (checker->getMeshQuality()); + // transform area and volume criterion values to [0, 1] + if (t == MshQualityType::AREA || t == MshQualityType::VOLUME) { + try { + MathLib::LinearIntervalInterpolation<double> lin_intpol(checker->getMinValue(), checker->getMaxValue(), 0, 1); + const size_t n_quality(quality.size()); + for (size_t k(0); k<n_quality; k++) + quality[k] = lin_intpol(quality[k]); + } catch (std::runtime_error& exception) { + std::cout << "run time error: " << exception.what() << std::endl; + } + } + + int nSources = this->_rootItem->childCount(); + for (int i = 0; i < nSources; i++) + { + VtkVisPipelineItem* parentItem = + static_cast<VtkVisPipelineItem*>(_rootItem->child(i)); + if (parentItem->algorithm() == source) + { + QList<QVariant> itemData; + itemData << "MeshQuality: " + QString::fromStdString( + MshQualityType2String(t)) << true; + + VtkCompositeFilter* filter = + VtkFilterFactory::CreateCompositeFilter( + "VtkCompositeSelectionFilter", + parentItem->transformFilter()); + static_cast<VtkCompositeSelectionFilter*>(filter)-> + setSelectionArray(quality); + VtkVisPointSetItem* item = new VtkVisPointSetItem(filter, + parentItem, + itemData); + this->addPipelineItem(item, this->createIndex(i, 0, item)); + break; + } + } + + // *** construct and write histogram + // simple suggestion: number of classes with Sturges criterion + size_t nclasses (static_cast<size_t>(1 + 3.3 * log (static_cast<float>((mesh->getElementVector()).size())))); +// bool ok; +// size_t size (static_cast<size_t>(QInputDialog::getInt(NULL, "OGS-Histogram", "number of histogram classes/spins (min: 1, max: 10000)", static_cast<int>(nclasses), 1, 10000, 1, &ok))); +// if (ok) ... + + BASELIB::Histogram<double> histogram (checker->getHistogram(nclasses)); + std::ofstream out ("mesh_histogram.txt"); + if (out) { + out << "# histogram depicts mesh quality criterion " << MshQualityType2String(t) + << " for mesh " << source->GetGrid()->getName() << std::endl; + nclasses = histogram.getNrBins(); + std::vector<size_t> const& bin_cnts(histogram.getBinCounts()); + const double min (histogram.getMinimum()); + const double bin_width (histogram.getBinWidth()); + + for (size_t k(0); k < nclasses; k++) + out << min+k*bin_width << " " << bin_cnts[k] << std::endl; + out.close (); + } else { + std::cerr << "could not open file mesh_histgram.txt" << std::endl; + } + +// size_t size (100); +// std::vector<size_t> histogram (size,0); +// checker->getHistogram(histogram); +// std::ofstream out ("mesh_histogram.txt"); +// const size_t histogram_size (histogram.size()); +// for (size_t k(0); k < histogram_size; k++) +// out << k / static_cast<double>(histogram_size) << " " << histogram[k] << +// std::endl; +// out.close (); + + delete checker; + } +} + +void VtkVisPipeline::highlightGeoObject(const vtkPolyDataAlgorithm* source, int index) +{ + this->removeHighlightedGeoObject(); + int nSources = this->_rootItem->childCount(); + for (int i = 0; i < nSources; i++) + { + VtkVisPipelineItem* parentItem = static_cast<VtkVisPipelineItem*>(_rootItem->child(i)); + if (parentItem->algorithm() == source) + { + QList<QVariant> itemData; + itemData << "Selected GeoObject" << true; + + VtkCompositeFilter* filter = VtkFilterFactory::CreateCompositeFilter( + "VtkCompositeGeoObjectFilter", + parentItem->transformFilter()); + static_cast<VtkCompositeGeoObjectFilter*>(filter)->SetIndex(index); + VtkVisPointSetItem* item = new VtkVisPointSetItem(filter, parentItem, itemData); + QModelIndex parent_index = static_cast<TreeModel*>(this)->index(i, 0, QModelIndex()); + _highlighted_geo_index = this->addPipelineItem(item, parent_index); + break; + } + } +} + +void VtkVisPipeline::removeHighlightedGeoObject() +{ + if (_highlighted_geo_index != QModelIndex()) + { + this->removePipelineItem(_highlighted_geo_index); + _highlighted_geo_index = QModelIndex(); + } +} diff --git a/Gui/VtkVis/VtkVisPipeline.h b/Gui/VtkVis/VtkVisPipeline.h new file mode 100644 index 0000000000000000000000000000000000000000..1594232a9285e8922057f3afe7f4789c75497a3c --- /dev/null +++ b/Gui/VtkVis/VtkVisPipeline.h @@ -0,0 +1,132 @@ +/** + * \file VtkVisPipeline.h + * 17/2/2010 LB Initial implementation + * + */ + +#ifndef VTKVISPIPELINE_H +#define VTKVISPIPELINE_H + +// ** INCLUDES ** +#include "Color.h" +#include "Configure.h" +#include "FEMCondition.h" +#include "GeoType.h" +#include "MSHEnums.h" +#include "Point.h" +#include "TreeModel.h" + +#include <QMap> +#include <QVector> + +class vtkAlgorithm; +class vtkDataSet; +class vtkLight; +class vtkPointSet; +class vtkPolyDataAlgorithm; +class vtkRenderer; +class vtkProp3D; +class QModelIndex; +class QString; +class GeoTreeModel; +class ProcessModel; +class MshModel; +class StationTreeModel; +class TreeModel; +class VtkVisPipelineItem; +class VtkMeshSource; + +/** + * \brief VtkVisPipeline manages the VTK visualization. + * It is a TreeModel and provides functions for adding and removing OGS + * Model or vtkAlgorithm objects. + */ +class VtkVisPipeline : public TreeModel +{ + Q_OBJECT + +public: + VtkVisPipeline(vtkRenderer* renderer, QObject* parent = 0); + + /// \brief Emits vtkVisPipelineChanged() and calls base class method. + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + + /// \brief Adds a light to the scene at the given coordinates. + void addLight(const GEOLIB::Point &pos); + + /// \brief Returns a light (or NULL) for the given coordinates. + vtkLight* getLight(const GEOLIB::Point &pos) const; + + /// \brief Removes a light at the given coordinates (if possible). + void removeLight(const GEOLIB::Point &pos); + + /// \brief Returns the background-colour of the scene. + const QColor getBGColor() const; + + /// \brief Sets the background-colour of the scene. + void setBGColor(const QColor &color); + + /// \brief Returns the QModelIndex of VtkVisPipelineItem which actor + /// is the given one. + QModelIndex getIndex(vtkProp3D* actor); + + Qt::ItemFlags flags( const QModelIndex &index ) const; + + /// \brief Loads a vtk object from the given file and adds it to the pipeline. + void loadFromFile(QString filename); + + /// \brief Defaults to on. + void resetCameraOnAddOrRemove(bool reset) { _resetCameraOnAddOrRemove = reset; } + + /// \brief Sets a global superelevation factor on all source items and resets + /// the factor on other items to 1. + void setGlobalSuperelevation(double factor) const; + + /// \brief Enables / disables backface culling on all actors. + void setGlobalBackfaceCulling(bool enable) const; + +public slots: + /// \brief Adds the given Model to the pipeline. + void addPipelineItem(MshModel* model, const QModelIndex &idx); + void addPipelineItem(GeoTreeModel* model, const std::string &name, GEOLIB::GEOTYPE type); + void addPipelineItem(ProcessModel* model, const FiniteElement::ProcessType pcs_type, FEMCondition::CondType cond_type); + void addPipelineItem(StationTreeModel* model, const std::string &name); + QModelIndex addPipelineItem(VtkVisPipelineItem* item, const QModelIndex &parent); + + /// \brief Inserts the vtkAlgorithm as a child of the given QModelIndex to the pipeline. + QModelIndex addPipelineItem(vtkAlgorithm* source, QModelIndex parent = QModelIndex()); + + /// \brief Removes the given Model (and all attached vtkAlgorithms) from the pipeline. + void removeSourceItem(MshModel* model, const QModelIndex &idx); + void removeSourceItem(GeoTreeModel* model, const std::string &name, GEOLIB::GEOTYPE type); + void removeSourceItem(ProcessModel* model, const FiniteElement::ProcessType pcs_type, FEMCondition::CondType cond_type); + void removeSourceItem(StationTreeModel* model, const std::string &name); + + /// \brief Removes the vtkAlgorithm at the given QModelIndex (and all attached + /// vtkAlgorithms) from the pipeline. + void removePipelineItem(QModelIndex index); + + /// Checks the quality of a mesh and cal a filter to highlight deformed elements. + void checkMeshQuality(VtkMeshSource* mesh, MshQualityType::type t); + + void highlightGeoObject(const vtkPolyDataAlgorithm* source, int index); + void removeHighlightedGeoObject(); + +private: + void listArrays(vtkDataSet* dataSet); + + vtkRenderer* _renderer; + QVector<vtkAlgorithm*> _sources; + std::list<vtkLight*> _lights; + QMap<vtkProp3D*, QModelIndex> _actorMap; + bool _resetCameraOnAddOrRemove; + + QModelIndex _highlighted_geo_index; + + +signals: + /// \brief Is emitted when a pipeline item was added or removed. + void vtkVisPipelineChanged() const; +}; + +#endif // VTKVISPIPELINE_H diff --git a/Gui/VtkVis/VtkVisPipelineItem.cpp b/Gui/VtkVis/VtkVisPipelineItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fd79579b341071ff191704bdf941d59b96c94de3 --- /dev/null +++ b/Gui/VtkVis/VtkVisPipelineItem.cpp @@ -0,0 +1,200 @@ +/** + * \file VtkVisPipelineItem.cpp + * 17/2/2010 LB Initial implementation + * + * Implementation of VtkVisPipelineItem + */ + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include "VtkVisPipelineItem.h" +#include "VtkCompositeFilter.h" + +#include "QVtkDataSetMapper.h" +#include <vtkActor.h> +#include <vtkAlgorithm.h> +#include <vtkDataSetMapper.h> +#include <vtkPointSet.h> +#include <vtkProperty.h> +#include <vtkRenderer.h> +#include <vtkSmartPointer.h> +#include <vtkTextureMapToPlane.h> +#include <vtkGenericDataObjectWriter.h> +#include <vtkCellData.h> +#include <vtkPointData.h> +#include <vtkImageActor.h> + +#include <QMessageBox> + +#ifdef OGS_USE_OPENSG +#include "vtkOsgConverter.h" +#include <OpenSG/OSGSceneFileHandler.h> +#endif + +VtkVisPipelineItem::VtkVisPipelineItem( + vtkAlgorithm* algorithm, TreeItem* parentItem, + const QList<QVariant> data /*= QList<QVariant>()*/) + : TreeItem(data, parentItem), _actor(NULL), _algorithm(algorithm), + _renderer(NULL), _compositeFilter(NULL), _vtkProps(NULL) +{ + VtkVisPipelineItem* visParentItem = dynamic_cast<VtkVisPipelineItem*>(parentItem); + if (parentItem->parentItem()) + _algorithm->SetInputConnection(visParentItem->algorithm()->GetOutputPort()); +} + +VtkVisPipelineItem::VtkVisPipelineItem( + VtkCompositeFilter* compositeFilter, TreeItem* parentItem, + const QList<QVariant> data /*= QList<QVariant>()*/) + : TreeItem(data, parentItem), _actor(NULL), _renderer(NULL), _compositeFilter(compositeFilter), + _vtkProps(NULL) +{ + _algorithm = _compositeFilter->GetOutputAlgorithm(); +} + +VtkVisPipelineItem::~VtkVisPipelineItem() +{ + _renderer->RemoveActor(_actor); + _actor->Delete(); + delete _compositeFilter; +} + +VtkVisPipelineItem* VtkVisPipelineItem::child( int row ) const +{ + TreeItem* treeItem = TreeItem::child(row); + if (treeItem) + return dynamic_cast<VtkVisPipelineItem*>(treeItem); + else + return NULL; +} + +QVariant VtkVisPipelineItem::data( int column ) const +{ + if (column == 1) + return isVisible(); + else + return TreeItem::data(column); +} + +bool VtkVisPipelineItem::setData( int column, const QVariant &value ) +{ + if (column == 1) + { + setVisible(value.toBool()); + return true; + } + else + return TreeItem::setData(column, value); +} +bool VtkVisPipelineItem::isVisible() const +{ + return (bool)_actor->GetVisibility(); +} + +void VtkVisPipelineItem::setVisible( bool visible ) +{ + _actor->SetVisibility((int)visible); + _actor->Modified(); + _renderer->Render(); +} + +int VtkVisPipelineItem::writeToFile(const std::string &filename) const +{ + if (!filename.empty()) + { + if (filename.substr(filename.size() - 4).find("os") != std::string::npos) + { +#ifdef OGS_USE_OPENSG + if(!dynamic_cast<vtkImageActor*>(_actor)) + { + vtkOsgConverter osgConverter(static_cast<vtkActor*>(_actor)); + if(osgConverter.WriteAnActor()) + OSG::SceneFileHandler::the().write( + osgConverter.GetOsgNode(), filename.c_str()); + } + else + QMessageBox::warning(NULL, "Conversion to OpenSG not possible", + "It is not possible to convert an vtkImageData based object\nto OpenSG. If you want to convert raster data import it via \" File / Import / Raster Files as PolyData\"!"); +#else + QMessageBox::warning( + NULL, + "Functionality not implemented", + "Sorry but this program was not compiled with OpenSG support."); +#endif + return 0; + } + + return callVTKWriter(this->algorithm(), filename); + } + return 0; +} + +int VtkVisPipelineItem::callVTKWriter(vtkAlgorithm* algorithm, const std::string &filename) const +{ + // needs to be implemented in derived classes! + (void)algorithm; + (void)filename; + return 0; +} + +vtkProp3D* VtkVisPipelineItem::actor() const +{ + return _actor; +} + +void VtkVisPipelineItem::setScale(double x, double y, double z) const +{ + (void)x; + (void)y, (void)z; +} + +void VtkVisPipelineItem::setTranslation(double x, double y, double z) const +{ + (void)x; + (void)y, (void)z; +} + +void VtkVisPipelineItem::setScaleOnChildren(double x, double y, double z) const +{ + for (int i = 0; i < this->childCount(); ++i) + { + VtkVisPipelineItem* child = this->child(i); + child->setScale(x, y, z); + } +} + +void VtkVisPipelineItem::setBackfaceCulling(bool enable) const +{ + // Reimplemented in subclass + (void)enable; +} + +void VtkVisPipelineItem::setBackfaceCullingOnChildren(bool enable) const +{ + for (int i = 0; i < this->childCount(); ++i) + { + VtkVisPipelineItem* child = this->child(i); + child->setBackfaceCulling((int)enable); + child->setBackfaceCullingOnChildren((int)enable); + } +} + +QStringList VtkVisPipelineItem::getScalarArrayNames() const +{ + vtkDataSet* dataSet = vtkDataSet::SafeDownCast(this->algorithm()->GetOutputDataObject(0)); + QStringList dataSetAttributesList; + if (dataSet) + { + vtkPointData* pointData = dataSet->GetPointData(); + //std::cout << " #point data arrays: " << pointData->GetNumberOfArrays() << std::endl; + for (int i = 0; i < pointData->GetNumberOfArrays(); i++) + //std::cout << " Name: " << pointData->GetArrayName(i) << std::endl; + dataSetAttributesList.push_back(QString("P-") + pointData->GetArrayName(i)); + + vtkCellData* cellData = dataSet->GetCellData(); + //std::cout << " #cell data arrays: " << cellData->GetNumberOfArrays() << std::endl; + for (int i = 0; i < cellData->GetNumberOfArrays(); i++) + //std::cout << " Name: " << cellData->GetArrayName(i) << std::endl; + dataSetAttributesList.push_back(QString("C-") + cellData->GetArrayName(i)); + } + return dataSetAttributesList; +} \ No newline at end of file diff --git a/Gui/VtkVis/VtkVisPipelineItem.h b/Gui/VtkVis/VtkVisPipelineItem.h new file mode 100644 index 0000000000000000000000000000000000000000..dc35c1ff980226a123a07645d8da64cddec9a7ca --- /dev/null +++ b/Gui/VtkVis/VtkVisPipelineItem.h @@ -0,0 +1,146 @@ +/** + * \file VtkVisPipelineItem.h + * 17/2/2010 LB Initial implementation + * + */ + +#ifndef VTKVISPIPELINEITEM_H +#define VTKVISPIPELINEITEM_H + +// ** INCLUDES ** +#include "Configure.h" +#include "TreeItem.h" + +#include <QList> +#include <QMap> +//#include <QObject> +#include <QString> +#include <QVariant> + +class QStringList; +class vtkAlgorithm; +class vtkDataSetAttributes; +class vtkPointSet; +class vtkProp3D; +class vtkRenderer; +class vtkTransformFilter; +class QVtkDataSetMapper; + +class vtkOsgActor; + +class VtkAlgorithmProperties; +class VtkCompositeFilter; + +/** + * \brief An item in the VtkVisPipeline containing a graphic object to be visualized. + * + * Any VTK-object (source-items, filter-items, etc.) need to be put into a VtkPipelineItem + * to be assigned a mapper, an actor and its visualization properties (colour, etc.). + */ +class VtkVisPipelineItem : /*public QObject,*/ public TreeItem +{ +// Q_OBJECT + +public: + /// @brief Constructor for a source/filter object. + VtkVisPipelineItem(vtkAlgorithm* algorithm, + TreeItem* parentItem, + const QList<QVariant> data = QList<QVariant>()); + + /// @brief Constructor for composite filter + VtkVisPipelineItem(VtkCompositeFilter* compositeFilter, TreeItem* parentItem, + const QList<QVariant> data = QList<QVariant>()); + + ~VtkVisPipelineItem(); + + /// @brief Returns a VtkVisPipelineItem. + VtkVisPipelineItem* child(int row) const; + + /// @brief Initializes vtkMapper and vtkActor necessary for visualization of + /// the item and sets the item's properties. + virtual void Initialize(vtkRenderer* renderer) = 0; + + QVariant data(int column) const; + bool setData(int column, const QVariant &value); + + /// @brief Returns the algorithm object + vtkAlgorithm* algorithm() const { return _algorithm; } + + /// @brief Returns the actor as vtkProp3D + vtkProp3D* actor() const; + + // Dummy for implementation in derived classes + virtual const QString GetActiveAttribute() const { return QString(""); } + + // Dummy for implementation in derived classes + virtual void SetActiveAttribute(const QString& str) { (void)str; } + + /// @brief Returns the composite filter + VtkCompositeFilter* compositeFilter() const { return _compositeFilter; } + + /// @brief Returns if the VTK object is visible in the visualization. + bool isVisible() const; + + /// @brief Sets the visibility of the VTK object in the visualization. + void setVisible(bool visible); + + /// @brief Writes this algorithm's vtkDataSet (i.e. vtkPolyData or vtkUnstructuredGrid) + /// to a vtk-file. + int writeToFile(const std::string &filename) const; + + /** + * @brief Scales the data in visualisation-space. + * This function is empty and needs to be implemented by derived classes. + */ + virtual void setScale(double x, double y, double z) const; + + /// @brief Sets the geometry and date scaling recursively on all children of + /// this item. + void setScaleOnChildren(double x, double y, double z) const; + + /** + * @brief Translates the item in visualisation-space. + * This function is empty and needs to be implemented by derived classes. + */ + virtual void setTranslation(double x, double y, double z) const; + + /** + * Returns the transform filter for the object. + * This function needs to be implemented by derived classes. + */ + virtual vtkAlgorithm* transformFilter() const = 0; + + /// @brief Enables / disables backface culling. + virtual void setBackfaceCulling(bool enable) const; + + /// @brief Enables / disables backface culling on all children. + void setBackfaceCullingOnChildren(bool enable) const; + + /// @brief Returns a list of array names prefixed with P- or C- + /// for point and cell data. + QStringList getScalarArrayNames() const; + + /// @brief Returns the VtkAlgorithmProperties. + VtkAlgorithmProperties* getVtkProperties() const { return _vtkProps; }; + +protected: + vtkProp3D* _actor; + vtkAlgorithm* _algorithm; + vtkRenderer* _renderer; + VtkCompositeFilter* _compositeFilter; + + /// @brief The active VtkAlgorithmProperties. + /// From algorithm, compositeFilter, or copied from parent + VtkAlgorithmProperties* _vtkProps; + + /** + * Selects the appropriate VTK-Writer object and writes the object to a file with the given name. + * This function is empty and needs to be implemented by derived classes. + */ + virtual int callVTKWriter(vtkAlgorithm* algorithm, const std::string &filename) const; + +private: +}; + +#endif // VTKVISPIPELINEITEM_H + diff --git a/Gui/VtkVis/VtkVisPipelineView.cpp b/Gui/VtkVis/VtkVisPipelineView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..edbf601c73b26f790e0ca591f1c70d96ef6a1a29 --- /dev/null +++ b/Gui/VtkVis/VtkVisPipelineView.cpp @@ -0,0 +1,288 @@ +/** + * \file VtkVisPipelineView.cpp + * 18/2/2010 LB Initial implementation + * + * Implementation of VtkVisPipelineView + */ + +// ** INCLUDES ** +#include "VtkVisPipelineView.h" + +#include "CheckboxDelegate.h" +#include "VtkVisPipeline.h" +#include "VtkVisPipelineItem.h" +#include "VtkVisPointSetItem.h" + +#include <vtkDataSetMapper.h> +#include <vtkProp3D.h> + +#include <QAbstractItemModel> +#include <QContextMenuEvent> +#include <QFileDialog> +#include <QHeaderView> +#include <QMenu> +#include <QSettings> +#include <QMessageBox> + +//image to mesh conversion +#include "msh_mesh.h" +#include "GridAdapter.h" +#include "VtkGeoImageSource.h" +#include <vtkImageData.h> +#include "MeshFromRasterDialog.h" +#include <vtkDataObject.h> +#include <vtkSmartPointer.h> +#include <vtkGenericDataObjectReader.h> +#include <vtkTransformFilter.h> +#include <vtkUnstructuredGrid.h> +#include <vtkUnstructuredGridAlgorithm.h> +#include <vtkXMLUnstructuredGridReader.h> + + +VtkVisPipelineView::VtkVisPipelineView( QWidget* parent /*= 0*/ ) + : QTreeView(parent) +{ + this->setItemsExpandable(false); + //setEditTriggers(QAbstractItemView::AllEditTriggers); + CheckboxDelegate* checkboxDelegate = new CheckboxDelegate(this); + this->setItemDelegateForColumn(1, checkboxDelegate); + this->header()->setStretchLastSection(false); + this->header()->setResizeMode(QHeaderView::ResizeToContents); +} + +void VtkVisPipelineView::setModel(QAbstractItemModel* model) +{ + QTreeView::setModel(model); + + // Move Visisble checkbox to the left. + // This is done here because at constructor time there arent any sections. + this->header()->moveSection(1, 0); +} + +void VtkVisPipelineView::contextMenuEvent( QContextMenuEvent* event ) +{ + QModelIndex index = selectionModel()->currentIndex(); + if (index.isValid()) + { + // check object type + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(static_cast<VtkVisPipeline*>( + this->model())->getItem(this->selectionModel()->currentIndex())); + int objectType = item->algorithm()->GetOutputDataObject(0)->GetDataObjectType(); + VtkAlgorithmProperties* vtkProps = item->getVtkProperties(); + bool isSourceItem = + (this->selectionModel()->currentIndex().parent().isValid()) ? 0 : 1; + + QMenu menu; + QAction* addFilterAction = menu.addAction("Add filter..."); + + QAction* addLUTAction(NULL); + QAction* addMeshingAction(NULL); + if (objectType == VTK_IMAGE_DATA) + { + // this exception is needed as image object are only displayed in the vis-pipeline + isSourceItem = false; + addMeshingAction = menu.addAction("Convert Image to Mesh..."); + connect(addMeshingAction, SIGNAL(triggered()), this, + SLOT(showImageToMeshConversionDialog())); + } + else + { + addLUTAction = menu.addAction("Add color table..."); + connect(addLUTAction, SIGNAL(triggered()), this, SLOT(addColorTable())); + } + + QAction* addConvertToCFEMeshAction(NULL); + if (objectType == VTK_UNSTRUCTURED_GRID) + { + addConvertToCFEMeshAction = menu.addAction("Convert to Mesh..."); + connect(addConvertToCFEMeshAction, SIGNAL(triggered()), this, + SLOT(convertVTKToOGSMesh())); + } + menu.addSeparator(); + QAction* exportVtkAction = menu.addAction("Export as VTK"); + QAction* exportOsgAction = menu.addAction("Export as OpenSG"); + QAction* removeAction = NULL; + if (!isSourceItem || vtkProps->IsRemovable()) + { + removeAction = menu.addAction("Remove"); + connect(removeAction, SIGNAL(triggered()), this, + SLOT(removeSelectedPipelineItem())); + } + + connect(addFilterAction, SIGNAL(triggered()), this, SLOT(addPipelineFilterItem())); + connect(exportVtkAction, SIGNAL(triggered()), this, + SLOT(exportSelectedPipelineItemAsVtk())); + connect(exportOsgAction, SIGNAL(triggered()), this, + SLOT(exportSelectedPipelineItemAsOsg())); + + menu.exec(event->globalPos()); + } +} + +void VtkVisPipelineView::exportSelectedPipelineItemAsVtk() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QModelIndex idx = this->selectionModel()->currentIndex(); + QString filename = QFileDialog::getSaveFileName(this, "Export object to vtk-file", + settings.value("lastExportedFileDirectory").toString(), + "All files (* *.*)"); + if (!filename.isEmpty()) + { + static_cast<VtkVisPipelineItem*>(static_cast<VtkVisPipeline*>(this->model())-> + getItem(idx))->writeToFile(filename.toStdString()); + QDir dir = QDir(filename); + settings.setValue("lastExportedFileDirectory", dir.absolutePath()); + } +} + +void VtkVisPipelineView::exportSelectedPipelineItemAsOsg() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QModelIndex idx = this->selectionModel()->currentIndex(); + QString filename = QFileDialog::getSaveFileName(this, "Export object to OpenSG file", + settings.value("lastExportedFileDirectory"). + toString(), "OpenSG file (*.osb)"); + if (!filename.isEmpty()) + { + static_cast<VtkVisPipelineItem*>(static_cast<VtkVisPipeline*>(this->model())-> + getItem(idx))->writeToFile(filename.toStdString()); + QDir dir = QDir(filename); + settings.setValue("lastExportedFileDirectory", dir.absolutePath()); + } +} + +void VtkVisPipelineView::removeSelectedPipelineItem() +{ + emit requestRemovePipelineItem(selectionModel()->currentIndex()); +} + +void VtkVisPipelineView::addPipelineFilterItem() +{ + emit requestAddPipelineFilterItem(selectionModel()->currentIndex()); +} + +void VtkVisPipelineView::showImageToMeshConversionDialog() +{ + MeshFromRasterDialog* dlg = new MeshFromRasterDialog(); + connect(dlg, SIGNAL(setMeshParameters(QString, MshElemType::type, UseIntensityAs::type)), + this, SLOT(constructMeshFromImage(QString, MshElemType::type, UseIntensityAs::type))); + dlg->exec(); +} + +void VtkVisPipelineView::constructMeshFromImage(QString msh_name, MshElemType::type element_type, UseIntensityAs::type intensity_type) +{ + vtkSmartPointer<vtkAlgorithm> algorithm = + static_cast<VtkVisPipelineItem*>(static_cast<VtkVisPipeline*>(this->model())-> + getItem(this->selectionModel()->currentIndex()))->algorithm(); + + vtkSmartPointer<VtkGeoImageSource> imageSource = VtkGeoImageSource::SafeDownCast(algorithm); + double origin[3]; + imageSource->GetOutput()->GetOrigin(origin); + double spacing[3]; + imageSource->GetOutput()->GetSpacing(spacing); + + GridAdapter* mesh = VtkMeshConverter::convertImgToMesh(imageSource->GetOutput(), origin, spacing[0], element_type, intensity_type); + mesh->setName(msh_name.toStdString()); + emit meshAdded(mesh); +} + +void VtkVisPipelineView::convertVTKToOGSMesh() +{ + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(static_cast<VtkVisPipeline*>(this->model())->getItem( + this->selectionModel()->currentIndex())); + vtkSmartPointer<vtkAlgorithm> algorithm = item->algorithm(); + + + vtkUnstructuredGrid* grid(NULL); + vtkUnstructuredGridAlgorithm* ugAlg = vtkUnstructuredGridAlgorithm::SafeDownCast(algorithm); + if (ugAlg) + grid = ugAlg->GetOutput(); + else + { + // for old filetypes + vtkGenericDataObjectReader* dataReader = vtkGenericDataObjectReader::SafeDownCast(algorithm); + if (dataReader) + grid = vtkUnstructuredGrid::SafeDownCast(dataReader->GetOutput()); + else + { + // for new filetypes + vtkXMLUnstructuredGridReader* xmlReader = vtkXMLUnstructuredGridReader::SafeDownCast(algorithm); + grid = vtkUnstructuredGrid::SafeDownCast(xmlReader->GetOutput()); + } + } + GridAdapter* mesh = VtkMeshConverter::convertUnstructuredGrid(grid); + mesh->setName(item->data(0).toString().toStdString()); + emit meshAdded(mesh); +} + +void VtkVisPipelineView::selectionChanged( const QItemSelection &selected, + const QItemSelection &deselected ) +{ + QTreeView::selectionChanged(selected, deselected); + + QModelIndex index = this->selectionModel()->currentIndex(); + if (index.isValid()) + { + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(index.internalPointer()); + emit actorSelected(item->actor()); + emit itemSelected(item); + if (item->transformFilter()) + emit dataObjectSelected(vtkDataObject::SafeDownCast( + item->transformFilter()-> + GetOutputDataObject(0))); + } + else + { + emit actorSelected(NULL); + emit itemSelected(NULL); + emit dataObjectSelected(NULL); + } +} + +void VtkVisPipelineView::selectItem( vtkProp3D* actor ) +{ + QModelIndex index = ((VtkVisPipeline*)(this->model()))->getIndex(actor); + if (!index.isValid()) + return; + + blockSignals(true); + QItemSelectionModel* selectionModel = this->selectionModel(); + selectionModel->clearSelection(); + selectionModel->select(index, QItemSelectionModel::Select); + blockSignals(false); +} + +void VtkVisPipelineView::addColorTable() +{ + VtkVisPipelineItem* item ( + static_cast<VtkVisPipelineItem*>(static_cast<VtkVisPipeline*>(this->model())-> + getItem( + this->selectionModel()->currentIndex())) ); + const QString array_name = item->GetActiveAttribute(); + + QSettings settings("UFZ", "OpenGeoSys-5"); + QString filename = QFileDialog::getOpenFileName(this, "Select color table", + settings.value("lastOpenedLutFileDirectory"). toString(), + "Color table files (*.xml);;"); + QFileInfo fi(filename); + + if (fi.suffix().toLower() == "xml") + { + VtkVisPointSetItem* pointSetItem = dynamic_cast<VtkVisPointSetItem*>(item); + if (pointSetItem) + { + VtkAlgorithmProperties* props = pointSetItem->getVtkProperties(); + if (props) + { + props->SetLookUpTable(array_name, filename); + item->SetActiveAttribute(array_name); + emit requestViewUpdate(); + } + } + else + QMessageBox::warning(NULL, "Color lookup table could not be applied.", + "Color lookup tables can only be applied to VtkVisPointSetItem."); + QDir dir = QDir(filename); + settings.setValue("lastOpenedLutFileDirectory", dir.absolutePath()); + } +} diff --git a/Gui/VtkVis/VtkVisPipelineView.h b/Gui/VtkVis/VtkVisPipelineView.h new file mode 100644 index 0000000000000000000000000000000000000000..652f121398c394bf4b547d567f2f43fd9d281257 --- /dev/null +++ b/Gui/VtkVis/VtkVisPipelineView.h @@ -0,0 +1,84 @@ +/** + * \file VtkVisPipelineView.h + * 18/2/2010 LB Initial implementation + * + */ + +#ifndef VTKVISPIPELINEVIEW_H +#define VTKVISPIPELINEVIEW_H + +// ** INCLUDES ** +#include <QTreeView> +#include "VtkMeshConverter.h" + +class QItemSelection; +class QAbstractItemModel; +class VtkVisPipelineItem; +class vtkProp3D; +class vtkDataObject; + +namespace MeshLib +{ +class CFEMesh; +} + +/** + * \brief VtkVisPipelineView is a QTreeView and shows VtkVisPipelineItems and their relation to each other. + */ +class VtkVisPipelineView : public QTreeView +{ + Q_OBJECT + +public: + /// @brief Constructor. + VtkVisPipelineView(QWidget* parent = 0); + + /// @brief Overridden to set model specific header properties. + virtual void setModel(QAbstractItemModel* model); + +protected slots: + /// Emits itemSelected() signals when an items was selected. + void selectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + void selectItem(vtkProp3D* actor); + +private: + /// Creates a menu on right-clicking on an item. + void contextMenuEvent(QContextMenuEvent* event); + +private slots: + /// Adds a color lookup table to the current scalar array of the selected pipeline item. + void addColorTable(); + + /// Exports the currently selected item as a VTK file + void exportSelectedPipelineItemAsVtk(); + + /// Exports the currently selected item as an OpenSG file + void exportSelectedPipelineItemAsOsg(); + + /// Sends an requestRemovePipelineItem() signal to remove + /// the currently selected item. + void removeSelectedPipelineItem(); + + /// Sends a requestAddPipelineFilterItem() signal to add a filter. + void addPipelineFilterItem(); + + /// Calls the conversion method for creating an OGS Mesh from a vtkImageData object. + void constructMeshFromImage(QString msh_name, MshElemType::type element_type, UseIntensityAs::type intensity_type); + + /// Calls the dialog to + void showImageToMeshConversionDialog(); + + /// Calls the conversion method for making a vtk grid an ogs mesh. + void convertVTKToOGSMesh(); + +signals: + void requestViewUpdate(); + void requestRemovePipelineItem(QModelIndex); + void requestAddPipelineFilterItem(QModelIndex); + void itemSelected(VtkVisPipelineItem*); + void actorSelected(vtkProp3D*); + void dataObjectSelected(vtkDataObject*); + void meshAdded(GridAdapter*); +}; + +#endif // VTKVISPIPELINEVIEW_H diff --git a/Gui/VtkVis/VtkVisPointSetItem.cpp b/Gui/VtkVis/VtkVisPointSetItem.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d34dcacc3c53f47454e390b14557f798cb1a6ec --- /dev/null +++ b/Gui/VtkVis/VtkVisPointSetItem.cpp @@ -0,0 +1,397 @@ +/** + * \file VtkVisPointSetItem.cpp + * 2011/09/29 KR Initial implementation + */ + +// ** INCLUDES ** +#include "VtkAlgorithmProperties.h" +#include "VtkVisPointSetItem.h" +#include "VtkCompositeFilter.h" +#include "VtkCompositeContourFilter.h" +#include "VtkCompositeThresholdFilter.h" + +#include <limits> + +#include "QVtkDataSetMapper.h" +#include <vtkActor.h> +#include <vtkCellData.h> +#include <vtkDataSetMapper.h> +#include <vtkImageAlgorithm.h> +#include <vtkPointData.h> +#include <vtkRenderer.h> +#include <vtkSmartPointer.h> +#include <vtkTransform.h> +#include <vtkTransformFilter.h> +#include <vtkProperty.h> +#include <vtkLookupTable.h> + +#include <QObject> +#include <QRegExp> +#include <QSettings> +#include <QStringList> + +// export test +#include <vtkPolyDataAlgorithm.h> +#include <vtkTriangleFilter.h> +#include <vtkTubeFilter.h> +#include <vtkUnstructuredGridAlgorithm.h> +#include <vtkXMLPolyDataWriter.h> +#include <vtkXMLUnstructuredGridWriter.h> + +#include <vtkDataSetAttributes.h> + +VtkVisPointSetItem::VtkVisPointSetItem( + vtkAlgorithm* algorithm, TreeItem* parentItem, + const QList<QVariant> data /*= QList<QVariant>()*/) + : VtkVisPipelineItem(algorithm, parentItem, data), _mapper(NULL), + _transformFilter(NULL), _onPointData(true), _activeArrayName("") +{ + VtkVisPipelineItem* visParentItem = dynamic_cast<VtkVisPipelineItem*>(parentItem); + if (parentItem->parentItem()) + { + // special case if parent is image but child is not (e.g. Image2BarChartFilter) + if (dynamic_cast<vtkImageAlgorithm*>(visParentItem->algorithm())) + _algorithm->SetInputConnection(visParentItem->algorithm()->GetOutputPort()); + else + { + VtkVisPointSetItem* pointSetItem = + dynamic_cast<VtkVisPointSetItem*>(parentItem); + if (pointSetItem) + _algorithm->SetInputConnection( + pointSetItem->transformFilter()->GetOutputPort()); + } + } +} + +VtkVisPointSetItem::VtkVisPointSetItem( + VtkCompositeFilter* compositeFilter, TreeItem* parentItem, + const QList<QVariant> data /*= QList<QVariant>()*/) + : VtkVisPipelineItem(compositeFilter, parentItem, data), _mapper(NULL), + _transformFilter(NULL), _onPointData(true), _activeArrayName("") +{ +} + +VtkVisPointSetItem::~VtkVisPointSetItem() +{ + _transformFilter->Delete(); + _mapper->Delete(); +} +const QString VtkVisPointSetItem::GetActiveAttribute() const +{ + return _vtkProps->GetActiveAttribute(); +} + +void VtkVisPointSetItem::Initialize(vtkRenderer* renderer) +{ + _transformFilter = vtkTransformFilter::New(); + vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New(); + transform->Identity(); + _transformFilter->SetTransform(transform); + + _transformFilter->SetInputConnection(_algorithm->GetOutputPort()); + _transformFilter->Update(); + + _renderer = renderer; + _mapper = QVtkDataSetMapper::New(); + _mapper->InterpolateScalarsBeforeMappingOff(); + _mapper->SetColorModeToMapScalars(); + + _mapper->SetInputConnection(_transformFilter->GetOutputPort()); + _actor = vtkActor::New(); + static_cast<vtkActor*>(_actor)->SetMapper(_mapper); + _renderer->AddActor(_actor); + + // Determine the right pre-set properties + // Order is: _algorithm, _compositeFilter, create a new one with props copied from parent + VtkAlgorithmProperties* vtkProps = dynamic_cast<VtkAlgorithmProperties*>(_algorithm); + if (!vtkProps) + { + vtkProps = dynamic_cast<VtkAlgorithmProperties*>(_compositeFilter); + + // Copy properties from parent or create a new VtkAlgorithmProperties + if (!vtkProps) + { + VtkVisPipelineItem* parentItem = dynamic_cast<VtkVisPipelineItem*>(this->parentItem()); + while (parentItem) + { + VtkAlgorithmProperties* parentProps = NULL; + if(dynamic_cast<VtkVisPointSetItem*>(parentItem)) + parentProps = dynamic_cast<VtkVisPointSetItem*>(parentItem)->getVtkProperties(); + if (parentProps) + { + vtkProps = new VtkAlgorithmProperties(); // TODO memory leak? + vtkProps->SetScalarVisibility(parentProps->GetScalarVisibility()); + vtkProps->SetTexture(parentProps->GetTexture()); + vtkProps->SetActiveAttribute(parentProps->GetActiveAttribute()); + parentItem = NULL; + } + else + parentItem = dynamic_cast<VtkVisPipelineItem*>(parentItem->parentItem()); + } + + // Has no parents + if (!vtkProps) + vtkProps = new VtkAlgorithmProperties(); // TODO memory leak? + } + } + _vtkProps = vtkProps; + + if (vtkProps->GetActiveAttribute().length() == 0) + { + // Get first scalar and set it to active + QStringList arrayNames = this->getScalarArrayNames(); + if (arrayNames.length() > 0) + vtkProps->SetActiveAttribute(arrayNames[0]); + else + vtkProps->SetActiveAttribute("Solid Color"); + } + this->setVtkProperties(vtkProps); + this->SetActiveAttribute(vtkProps->GetActiveAttribute()); + + + // Set global backface culling + QSettings settings("UFZ, OpenGeoSys-5"); + bool backfaceCulling = settings.value("globalCullBackfaces", 0).toBool(); + this->setBackfaceCulling(backfaceCulling); + + // Set the correct threshold range + if ( dynamic_cast<VtkCompositeThresholdFilter*>(this->_compositeFilter) ) + { + double range[2]; + this->GetRangeForActiveAttribute(range); + QList<QVariant> thresholdRangeList; + thresholdRangeList.push_back(range[0]); + thresholdRangeList.push_back(range[1]); + dynamic_cast<VtkCompositeFilter*>(this->_compositeFilter) + ->SetUserVectorProperty("Range", thresholdRangeList); + } +} + +void VtkVisPointSetItem::SetScalarVisibility( bool on ) +{ + _mapper->SetScalarVisibility(on); +} + +void VtkVisPointSetItem::setVtkProperties(VtkAlgorithmProperties* vtkProps) +{ + QObject::connect(vtkProps, SIGNAL(ScalarVisibilityChanged(bool)), + _mapper, SLOT(SetScalarVisibility(bool))); + + vtkActor* actor = dynamic_cast<vtkActor*>(_actor); + if (actor) + { + if (vtkProps->GetTexture() != NULL) + { + vtkProps->SetScalarVisibility(false); + actor->GetProperty()->SetColor(1,1,1); // don't colorise textures + actor->SetTexture(vtkProps->GetTexture()); + } + else + { + vtkSmartPointer<vtkProperty> itemProperty = vtkProps->GetProperties(); + actor->SetProperty(itemProperty); + } + + if (!vtkProps->GetScalarVisibility()) + vtkProps->SetScalarVisibility(false); + } +} + +int VtkVisPointSetItem::callVTKWriter(vtkAlgorithm* algorithm, const std::string &filename) const +{ + vtkPolyDataAlgorithm* algPD = dynamic_cast<vtkPolyDataAlgorithm*>(algorithm); + vtkUnstructuredGridAlgorithm* algUG = dynamic_cast<vtkUnstructuredGridAlgorithm*>(algorithm); + if (algPD) + { +// vtkGenericDataObjectWriter* pdWriter = vtkGenericDataObjectWriter::New(); + vtkSmartPointer<vtkXMLPolyDataWriter> pdWriter = + vtkSmartPointer<vtkXMLPolyDataWriter>::New(); + pdWriter->SetInput(algPD->GetOutputDataObject(0)); + //pdWriter->SetDataModeToAscii(); + //pdWriter->SetCompressorTypeToNone(); + std::string filenameWithExt = filename; + filenameWithExt.append(".vtp"); + pdWriter->SetFileName(filenameWithExt.c_str()); + return pdWriter->Write(); + } + else if (algUG) + { + vtkSmartPointer<vtkXMLUnstructuredGridWriter> ugWriter = + vtkSmartPointer<vtkXMLUnstructuredGridWriter>::New(); + ugWriter->SetInput(algUG->GetOutputDataObject(0)); + //ugWriter->SetDataModeToAscii(); + //ugWriter->SetCompressorTypeToNone(); + std::string filenameWithExt = filename; + filenameWithExt.append(".vtu"); + ugWriter->SetFileName(filenameWithExt.c_str()); + return ugWriter->Write(); + } + std::cout << "VtkVisPipelineItem::writeToFile() - Unknown data type..." << std::endl; + return 0; +} + +void VtkVisPointSetItem::SetActiveAttribute( const QString& name ) +{ + // Get type by identifier + if (name.contains(QRegExp("^P-"))) + _onPointData = true; + else if (name.contains(QRegExp("^C-"))) + _onPointData = false; + else if (name.contains("Solid Color")) + { + _vtkProps->SetActiveAttribute("Solid Color"); + _mapper->ScalarVisibilityOff(); + return; + } + else + return; + + // Remove type identifier + _activeArrayName = QString(name).remove(0, 2).toStdString(); + const char* charName = _activeArrayName.c_str(); + + double range[2]; + vtkDataSet* dataSet = vtkDataSet::SafeDownCast(this->_algorithm->GetOutputDataObject(0)); + if (dataSet) + { + if (_onPointData) + { + vtkPointData* pointData = dataSet->GetPointData(); + if(pointData) + { + if(activeAttributeExists(pointData, _activeArrayName)) + { + _algorithm->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, charName); + _mapper->SetScalarModeToUsePointData(); + pointData->GetArray(_activeArrayName.c_str())->GetRange(range); + } + else + { + _activeArrayName = ""; + _vtkProps->SetActiveAttribute("Solid Color"); + _mapper->ScalarVisibilityOff(); + return; + } + } + } + else + { + vtkCellData* cellData = dataSet->GetCellData(); + if(cellData) + { + if(activeAttributeExists(cellData, _activeArrayName)) + { + _algorithm->SetInputArrayToProcess(0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, charName); + _mapper->SetScalarModeToUseCellData(); + cellData->GetArray(_activeArrayName.c_str())->GetRange(range); + } + else + { + _activeArrayName = ""; + _vtkProps->SetActiveAttribute("Solid Color"); + _mapper->ScalarVisibilityOff(); + return; + } + } + } + + //std::cout << "Range for " << name.toStdString() << " :" << range[0] << " " << range[1] << std::endl; + _vtkProps->SetActiveAttribute(name); + + QVtkDataSetMapper* mapper = dynamic_cast<QVtkDataSetMapper*>(_mapper); + if (mapper) + { + // Create a default color table when there is no lookup table for this attribute + vtkLookupTable* lut = _vtkProps->GetLookupTable(name); + if (lut == NULL) + { + //std::cout << "Creating new lookup table for: " << name.toStdString() << std::endl; + lut = vtkLookupTable::New(); // is not a memory leak, gets deleted in VtkAlgorithmProperties + lut->SetTableRange(range); + _vtkProps->SetLookUpTable(name, lut); + } + + _mapper->SetLookupTable(lut); + _mapper->UseLookupTableScalarRangeOn(); + //_mapper->SetScalarRange(range); // not necessary when UseLookupTableScalarRange is on + } + + _mapper->ScalarVisibilityOn(); + _mapper->Update(); + } +} + +bool VtkVisPointSetItem::activeAttributeExists(vtkDataSetAttributes* data, std::string& name) +{ + bool arrayFound = false; + for (int i = 0; i < data->GetNumberOfArrays() && !arrayFound; i++) + { + std::string arrayName = data->GetArrayName(i); + if(arrayName.compare(name) == 0) + arrayFound = true; + } + if(arrayFound) + { + data->SetActiveAttribute(name.c_str(), vtkDataSetAttributes::SCALARS); + return true; + } + else + return false; +} + +void VtkVisPointSetItem::setScale(double x, double y, double z) const +{ + if (this->transformFilter()) + { + vtkTransform* transform = + static_cast<vtkTransform*>(this->_transformFilter->GetTransform()); + double* trans = transform->GetPosition(); + transform->Identity(); + transform->Scale(x, y, z); + transform->Translate(trans[0] / x, trans[1] / y, trans[2] / z); + this->transformFilter()->Modified(); + } +} + +void VtkVisPointSetItem::setTranslation(double x, double y, double z) const +{ + if (this->transformFilter()) + { + vtkTransform* transform = + static_cast<vtkTransform*>(this->_transformFilter->GetTransform()); + double* scale = transform->GetScale(); + transform->Identity(); + transform->Scale(scale); + transform->Translate(x, y, z); + this->transformFilter()->Modified(); + } +} + +vtkAlgorithm* VtkVisPointSetItem::transformFilter() const +{ + return _transformFilter; +} + +void VtkVisPointSetItem::setBackfaceCulling(bool enable) const +{ + static_cast<vtkActor*>(this->_actor)->GetProperty()->SetBackfaceCulling((int)enable); +} + +void VtkVisPointSetItem::GetRangeForActiveAttribute(double range[2]) const +{ + vtkDataSet* dataSet = vtkDataSet::SafeDownCast(this->_algorithm->GetOutputDataObject(0)); + if (dataSet && _activeArrayName.length() > 0) + { + if (_onPointData) + { + vtkPointData* pointData = dataSet->GetPointData(); + if(pointData) + pointData->GetArray(_activeArrayName.c_str())->GetRange(range); + } + else + { + vtkCellData* cellData = dataSet->GetCellData(); + cellData->GetArray(_activeArrayName.c_str())->GetRange(range); + } + } +} diff --git a/Gui/VtkVis/VtkVisPointSetItem.h b/Gui/VtkVis/VtkVisPointSetItem.h new file mode 100644 index 0000000000000000000000000000000000000000..ad106761807d0dd6a0fcc005cc6553f152c719c1 --- /dev/null +++ b/Gui/VtkVis/VtkVisPointSetItem.h @@ -0,0 +1,94 @@ +/** + * \file VtkVisPointSetItem.h + * 2011/09/29 KR Initial implementation + * + */ + +#ifndef VTKVISPOINTSETITEM_H +#define VTKVISPOINTSETITEM_H + +// ** INCLUDES ** +#include "VtkVisPipelineItem.h" + +class vtkAlgorithm; +class vtkDataSetAttributes; +class vtkPointSet; +class vtkProp3D; +class vtkRenderer; +class vtkTransformFilter; +class QVtkDataSetMapper; + +class vtkOsgActor; + +class VtkAlgorithmProperties; +class VtkCompositeFilter; + +/** + * \brief An item in the VtkVisPipeline containing a point set object to be visualized. + * + * Any VTK point set object (i.e. vtkUnstructuredGrid- and vtkPolyDataAlgorithm-objects) + * are represented by a VtkVisPointSetItem to be assigned a mapper, an actor and its + * visualization properties (colour, scalar values, etc.). + * \sa VtkVisPipelineItem + */ +class VtkVisPointSetItem : public VtkVisPipelineItem +{ + +public: + /// @brief Constructor for a source/filter object. + VtkVisPointSetItem(vtkAlgorithm* algorithm, + TreeItem* parentItem, + const QList<QVariant> data = QList<QVariant>()); + + /// @brief Constructor for composite filter + VtkVisPointSetItem(VtkCompositeFilter* compositeFilter, TreeItem* parentItem, + const QList<QVariant> data = QList<QVariant>()); + + ~VtkVisPointSetItem(); + + /// @brief Gets the last selected attribute. + const QString GetActiveAttribute() const; + + /// @brief Get the scalar range for the active attribute + void GetRangeForActiveAttribute(double range[2]) const; + + /// @brief Initializes vtkMapper and vtkActor necessary for visualization of + /// the item and sets the item's properties. + void Initialize(vtkRenderer* renderer); + + vtkAlgorithm* transformFilter() const; + + /// @brief Sets the selected attribute array for the visualisation of the data set. + void SetActiveAttribute(const QString& name); + + /// @brief Scales the data in visualisation-space. + void setScale(double x, double y, double z) const; + + /// @brief Translates the item in visualisation-space. + void setTranslation(double x, double y, double z) const; + + /// @brief Enables / disables backface culling. + void setBackfaceCulling(bool enable) const; + +protected: + QVtkDataSetMapper* _mapper; + vtkTransformFilter* _transformFilter; + bool _onPointData; + std::string _activeArrayName; + + /// Selects the appropriate VTK-Writer object and writes the object to a file with the given name. + virtual int callVTKWriter(vtkAlgorithm* algorithm, const std::string &filename) const; + + void SetScalarVisibility(bool on); + + /// @brief Sets pre-set properties on vtkActor and on vtkMapper + void setVtkProperties(VtkAlgorithmProperties* vtkProps); + +private: + /// Checks if the selected attribute actually exists for the data set + bool activeAttributeExists(vtkDataSetAttributes* data, std::string& name); + +}; + +#endif // VTKVISPOINTSETITEM_H + diff --git a/Gui/VtkVis/VtkVisTabWidget.cpp b/Gui/VtkVis/VtkVisTabWidget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2901f6de52fb8e73360b0a387a804c18b937a005 --- /dev/null +++ b/Gui/VtkVis/VtkVisTabWidget.cpp @@ -0,0 +1,364 @@ +/** + * \file VtkVisTabWidget.cpp + * 18/2/2010 LB Initial implementation + * + * Implementation of VtkVisTabWidget + */ + +// ** INCLUDES ** +#include "VtkColorByHeightFilter.h" +#include "VtkCompositeColorByHeightFilter.h" +#include "VtkVisPipelineItem.h" +#include "VtkVisImageItem.h" +#include "VtkVisTabWidget.h" + +#include <vtkActor.h> +#include <vtkImageChangeInformation.h> +#include <vtkProperty.h> +#include <vtkTransform.h> +#include <vtkTransformFilter.h> + +#include "ColorTableModel.h" +#include "ColorTableView.h" + +#include "VtkAlgorithmProperties.h" +#include "VtkAlgorithmPropertyCheckbox.h" +#include "VtkAlgorithmPropertyLineEdit.h" +#include "VtkAlgorithmPropertyVectorEdit.h" +#include "VtkCompositeFilter.h" + +#include <vtkCellData.h> +#include <vtkPointData.h> + +VtkVisTabWidget::VtkVisTabWidget( QWidget* parent /*= 0*/ ) + : QWidget(parent) +{ + setupUi(this); + + this->scaleZ->setValidator(new QDoubleValidator(0, 100, 8, this)); + + this->transX->setValidator(new QDoubleValidator(this)); + this->transY->setValidator(new QDoubleValidator(this)); + this->transZ->setValidator(new QDoubleValidator(this)); + + connect(this->vtkVisPipelineView, SIGNAL(requestViewUpdate()), + this, SIGNAL(requestViewUpdate())); + + connect(this->vtkVisPipelineView, SIGNAL(itemSelected(VtkVisPipelineItem*)), + this, SLOT(setActiveItem(VtkVisPipelineItem*))); + + connect(this->activeScalarComboBox, SIGNAL(currentIndexChanged(const QString &)), + this, SLOT(SetActiveAttributeOnItem(const QString &))); +} + +void VtkVisTabWidget::setActiveItem( VtkVisPipelineItem* item ) +{ + if (item) + { + _item = item; + transformTabWidget->setEnabled(true); + + vtkTransformFilter* transform_filter = dynamic_cast<vtkTransformFilter*>(_item->transformFilter()); + if (transform_filter) // if data set + { + actorPropertiesGroupBox->setEnabled(true); + vtkProperty* vtkProps = static_cast<vtkActor*>(_item->actor())->GetProperty(); + diffuseColorPickerButton->setColor(vtkProps->GetDiffuseColor()); + visibleEdgesCheckBox->setChecked(vtkProps->GetEdgeVisibility()); + edgeColorPickerButton->setColor(vtkProps->GetEdgeColor()); + opacitySlider->setValue((int)(vtkProps->GetOpacity() * 100.0)); + + vtkTransform* transform = + static_cast<vtkTransform*>(transform_filter->GetTransform()); + if (transform) + { + double scale[3]; + transform->GetScale(scale); + double trans[3]; + transform->GetPosition(trans); + + //switch signals off for just filling in text-boxes after clicking on an item + this->scaleZ->blockSignals(true); + this->transX->blockSignals(true); + this->transY->blockSignals(true); + this->transZ->blockSignals(true); + this->scaleZ->setText(QString::number(scale[2])); + this->transX->setText(QString::number(trans[0] / scale[0])); + this->transY->setText(QString::number(trans[1] / scale[1])); + this->transZ->setText(QString::number(trans[2] / scale[2])); + this->scaleZ->blockSignals(false); + this->transX->blockSignals(false); + this->transY->blockSignals(false); + this->transZ->blockSignals(false); + //switch signals back on + } + this->buildScalarArrayComboBox(_item); + + // Set to last active attribute + QString activeAttribute = _item->GetActiveAttribute(); + if (activeAttribute.length() > 0) + for (int i = 0; i < this->activeScalarComboBox->count(); i++) + { + QString itemText = this->activeScalarComboBox->itemText(i); + if (itemText.compare(activeAttribute) == 0) + { + this->activeScalarComboBox->setCurrentIndex(i); + break; + } + } + } + else // if image + { + const VtkVisImageItem* img = static_cast<VtkVisImageItem*>(_item); + actorPropertiesGroupBox->setEnabled(false); + vtkImageChangeInformation* transform = static_cast<vtkImageChangeInformation*>(img->transformFilter()); + double trans[3]; + transform->GetOriginTranslation(trans); + this->transX->blockSignals(true); + this->transY->blockSignals(true); + this->transZ->blockSignals(true); + this->transX->setText(QString::number(trans[0])); + this->transY->setText(QString::number(trans[1])); + this->transZ->setText(QString::number(trans[2])); + this->transX->blockSignals(false); + this->transY->blockSignals(false); + this->transZ->blockSignals(false); + } + + this->buildProportiesDialog(item); + + // + ///* Integrating colour tables into property-window (test!) */ + //VtkStationSource* test = dynamic_cast<VtkStationSource*>(_item->algorithm()); + //if (test) + //{ + // std::map<std::string, GEOLIB::Color> colors = test->getColorLookupTable(); + // if (!colors.empty()) + // { + // ColorTableModel* ctm = new ColorTableModel(colors); + // ColorTableView* ctv = new ColorTableView(); + // ctv->setModel(ctm); + // ctv->setItemDelegate(new ColorTableViewDelegate); + // vbox->addWidget(ctv); + // ctv->resizeRowsToContents(); + // } + //} + + /**/ + + emit requestViewUpdate(); + } + else + { + actorPropertiesGroupBox->setEnabled(false); + transformTabWidget->setEnabled(false); + this->activeScalarComboBox->clear(); + } +} + +void VtkVisTabWidget::on_diffuseColorPickerButton_colorPicked( QColor color ) +{ + static_cast<vtkActor*>(_item->actor())->GetProperty()->SetDiffuseColor( + color.redF(), color.greenF(), color.blueF()); + + emit requestViewUpdate(); +} + +void VtkVisTabWidget::on_visibleEdgesCheckBox_stateChanged( int state ) +{ + if (state == Qt::Checked) + { + static_cast<vtkActor*>(_item->actor())->GetProperty()->SetEdgeVisibility(1); + edgeColorPickerButton->setEnabled(true); + } + else + { + static_cast<vtkActor*>(_item->actor())->GetProperty()->SetEdgeVisibility(0); + edgeColorPickerButton->setEnabled(false); + } + + emit requestViewUpdate(); +} + +void VtkVisTabWidget::on_edgeColorPickerButton_colorPicked( QColor color ) +{ + static_cast<vtkActor*>(_item->actor())->GetProperty()->SetEdgeColor( + color.redF(), color.greenF(), color.blueF()); + emit requestViewUpdate(); +} + +void VtkVisTabWidget::on_opacitySlider_sliderMoved( int value ) +{ + static_cast<vtkActor*>(_item->actor())->GetProperty()->SetOpacity(value / 100.0); + emit requestViewUpdate(); +} + +void VtkVisTabWidget::on_scaleZ_textChanged(const QString &text) +{ + bool ok = true; + double scale = text.toDouble(&ok); + + // If z scale becomes zero, the object becomes invisible + if (ok && scale != 0.0) + { + _item->setScale(1.0, 1.0, scale); + + for (int i = 0; i < _item->childCount(); i++) + { + VtkVisPipelineItem* childItem = _item->child(i); + if (childItem) + { + VtkCompositeColorByHeightFilter* colorFilter = + dynamic_cast<VtkCompositeColorByHeightFilter*> + (childItem->compositeFilter()); + if (colorFilter) + VtkColorByHeightFilter::SafeDownCast( + colorFilter->GetOutputAlgorithm())-> + SetTableRangeScaling(scale); + } + } + + emit requestViewUpdate(); + } +} + +void VtkVisTabWidget::translateItem() +{ + bool okX(true), okY(true), okZ(true); + double trans[3]; + + trans[0] = transX->text().toDouble(&okX); + trans[1] = transY->text().toDouble(&okY); + trans[2] = transZ->text().toDouble(&okZ); + + if (okX && okY && okZ) + { + _item->setTranslation(trans[0], trans[1], trans[2]); + emit requestViewUpdate(); + } +} + +void VtkVisTabWidget::buildProportiesDialog(VtkVisPipelineItem* item) +{ + QFormLayout* layout = static_cast<QFormLayout*>(this->scrollAreaWidgetContents->layout()); + while(layout->count()) + delete layout->takeAt(0)->widget(); + + QMap<QString, QVariant>* propMap = NULL; + QMap<QString, QList<QVariant> >* propVecMap = NULL; + VtkAlgorithmProperties* algProps = NULL; + + // Retrieve algorithm properties + if (item->compositeFilter()) + { + algProps = item->compositeFilter(); + propMap = item->compositeFilter()->GetAlgorithmUserProperties(); + propVecMap = item->compositeFilter()->GetAlgorithmUserVectorProperties(); + } + else + { + algProps = dynamic_cast<VtkAlgorithmProperties*>(item->algorithm()); + if (algProps) + { + propMap = algProps->GetAlgorithmUserProperties(); + propVecMap = algProps->GetAlgorithmUserVectorProperties(); + } + } + + // Select appropriate GUI element and set connect for each property + if (propMap && algProps) + { + QMapIterator<QString, QVariant> i(*propMap); + while (i.hasNext()) + { + i.next(); + QString key = i.key(); + QVariant value = i.value(); + + VtkAlgorithmPropertyLineEdit* lineEdit; + VtkAlgorithmPropertyCheckbox* checkbox; + switch (value.type()) + { + case QVariant::Double: + lineEdit = + new VtkAlgorithmPropertyLineEdit(QString::number( + value.toDouble()), + key, QVariant::Double, + algProps); + connect(lineEdit, SIGNAL(editingFinished()), this, + SIGNAL(requestViewUpdate())); + layout->addRow(key, lineEdit); + break; + + case QVariant::Int: + lineEdit = + new VtkAlgorithmPropertyLineEdit(QString::number( + value.toInt()), + key, QVariant::Int, + algProps); + connect(lineEdit, SIGNAL(editingFinished()), this, + SIGNAL(requestViewUpdate())); + layout->addRow(key, lineEdit); + break; + + case QVariant::Bool: + checkbox = new VtkAlgorithmPropertyCheckbox( + value.toBool(), key, algProps); + connect(checkbox, SIGNAL(stateChanged(int)), this, + SIGNAL(requestViewUpdate())); + layout->addRow(key, checkbox); + break; + + default: + break; + } + } + } + + if (propVecMap && algProps) + { + QMapIterator<QString, QList<QVariant> > i(*propVecMap); + while (i.hasNext()) + { + i.next(); + QString key = i.key(); + QList<QVariant> values = i.value(); + + VtkAlgorithmPropertyVectorEdit* vectorEdit; + if (values.size() > 0) + { + QList<QString> valuesAsString; + foreach (QVariant variant, values) + valuesAsString.push_back(variant.toString()); + + vectorEdit = new VtkAlgorithmPropertyVectorEdit(valuesAsString, + key, + values.front().type(), + algProps); + connect(vectorEdit, SIGNAL(editingFinished()), this, + SIGNAL(requestViewUpdate())); + layout->addRow(key, vectorEdit); + } + } + } +} + +void VtkVisTabWidget::buildScalarArrayComboBox(VtkVisPipelineItem* item) +{ + QStringList dataSetAttributesList = item->getScalarArrayNames(); + dataSetAttributesList.push_back("Solid Color"); // all scalars switched off + this->activeScalarComboBox->blockSignals(true); + this->activeScalarComboBox->clear(); + this->activeScalarComboBox->insertItems(0, dataSetAttributesList); + this->activeScalarComboBox->blockSignals(false); + QList<QString>::iterator it = dataSetAttributesList.begin(); + if (item->GetActiveAttribute().count() == 0) + item->SetActiveAttribute(*it); +} + +void VtkVisTabWidget::SetActiveAttributeOnItem( const QString &name ) +{ + _item->SetActiveAttribute(name); + emit requestViewUpdate(); +} + diff --git a/Gui/VtkVis/VtkVisTabWidget.h b/Gui/VtkVis/VtkVisTabWidget.h new file mode 100644 index 0000000000000000000000000000000000000000..fb4b1a147a2eac51eb75947ca61da639cb159675 --- /dev/null +++ b/Gui/VtkVis/VtkVisTabWidget.h @@ -0,0 +1,70 @@ +/** + * \file VtkVisTabWidget.h + * 18/2/2010 LB Initial implementation + * + */ + +#ifndef VTKVISTABWIDGET_H +#define VTKVISTABWIDGET_H + +// ** INCLUDES ** +#include "ui_VtkVisTabWidgetBase.h" + +class vtkAlgorithm; + +/** + * \brief Contains a QTreeView of the VtkVisPipeline and a properties + * panel for adjusting vtkAlgorithms rendering and filter settings. + */ +class VtkVisTabWidget : public QWidget, public Ui_VtkVisTabWidgetBase +{ + Q_OBJECT + +public: + /// Constructor + VtkVisTabWidget(QWidget* parent = 0); + +protected slots: + /// Updates the property panels to show informations on the given VtkVisPipelineItem. + void setActiveItem(VtkVisPipelineItem* item); + + void on_diffuseColorPickerButton_colorPicked(QColor color); + void on_visibleEdgesCheckBox_stateChanged(int state); + void on_edgeColorPickerButton_colorPicked(QColor color); + void on_opacitySlider_sliderMoved(int value); + void on_scaleZ_textChanged(const QString &text); + void on_transX_textChanged(const QString &text) + { + Q_UNUSED(text); + this->translateItem(); + } + void on_transY_textChanged(const QString &text) + { + Q_UNUSED(text); + this->translateItem(); + } + void on_transZ_textChanged(const QString &text) + { + Q_UNUSED(text); + this->translateItem(); + } + + void SetActiveAttributeOnItem(const QString &name); + +private: + /// Reads the algorithm properties of the given pipeline item and builds a dialog for adjusting these properties in the GUI. + void buildProportiesDialog(VtkVisPipelineItem* item); + + /// Reads the scalar arrays of the given vtk-object and constructs content for the scalar array selection box. + void buildScalarArrayComboBox(VtkVisPipelineItem* item); + + void translateItem(); + + VtkVisPipelineItem* _item; + +signals: + /// Is emitted when a property was changed. + void requestViewUpdate(); +}; + +#endif // VTKVISTABWIDGET_H diff --git a/Gui/VtkVis/VtkVisTabWidgetBase.ui b/Gui/VtkVis/VtkVisTabWidgetBase.ui new file mode 100644 index 0000000000000000000000000000000000000000..5bad5ace50b77877336788fc9cc91a94414b79fb --- /dev/null +++ b/Gui/VtkVis/VtkVisTabWidgetBase.ui @@ -0,0 +1,380 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>VtkVisTabWidgetBase</class> + <widget class="QWidget" name="VtkVisTabWidgetBase"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>259</width> + <height>677</height> + </rect> + </property> + <property name="windowTitle"> + <string>Form</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="margin"> + <number>3</number> + </property> + <item> + <widget class="QSplitter" name="splitter"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <widget class="VtkVisPipelineView" name="vtkVisPipelineView"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="autoExpandDelay"> + <number>1</number> + </property> + <property name="indentation"> + <number>5</number> + </property> + <property name="animated"> + <bool>true</bool> + </property> + </widget> + <widget class="QWidget" name="layoutWidget"> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QGroupBox" name="actorPropertiesGroupBox"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>180</height> + </size> + </property> + <property name="title"> + <string>Actor Properties</string> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="margin"> + <number>3</number> + </property> + <item row="0" column="1"> + <widget class="ColorPickerPushButton" name="diffuseColorPickerButton"> + <property name="text"> + <string>(255,255,255)</string> + </property> + </widget> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="text"> + <string>Diffuse Color</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QCheckBox" name="visibleEdgesCheckBox"> + <property name="text"> + <string>Visible Edges</string> + </property> + </widget> + </item> + <item row="3" column="1"> + <widget class="ColorPickerPushButton" name="edgeColorPickerButton"> + <property name="text"> + <string>(255, 255, 255)</string> + </property> + </widget> + </item> + <item row="4" column="0"> + <widget class="QLabel" name="label_2"> + <property name="text"> + <string>Opacity</string> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QValueTooltipSlider" name="opacitySlider"> + <property name="maximum"> + <number>100</number> + </property> + <property name="value"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QComboBox" name="activeScalarComboBox"/> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Active Scalar</string> + </property> + </widget> + </item> + </layout> + </widget> + </item> + <item> + <widget class="QTabWidget" name="transformTabWidget"> + <property name="enabled"> + <bool>false</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>60</height> + </size> + </property> + <property name="currentIndex"> + <number>1</number> + </property> + <widget class="QWidget" name="scalingTab"> + <attribute name="title"> + <string>Scaling</string> + </attribute> + <layout class="QHBoxLayout" name="horizontalLayout_4"> + <property name="spacing"> + <number>5</number> + </property> + <property name="margin"> + <number>5</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="spacing"> + <number>5</number> + </property> + <property name="sizeConstraint"> + <enum>QLayout::SetDefaultConstraint</enum> + </property> + <item> + <widget class="QLabel" name="label_3"> + <property name="text"> + <string>Scaling Factor</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="scaleZ"> + <property name="text"> + <string>1</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + <widget class="QWidget" name="translationTab"> + <attribute name="title"> + <string>Translation</string> + </attribute> + <layout class="QHBoxLayout" name="horizontalLayout_5"> + <property name="spacing"> + <number>5</number> + </property> + <property name="margin"> + <number>5</number> + </property> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <property name="spacing"> + <number>5</number> + </property> + <item> + <widget class="QLabel" name="transXLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>X</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="transX"> + <property name="text"> + <string>0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="transYLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Y</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="transY"> + <property name="text"> + <string>0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>40</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QLabel" name="transZLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Minimum" vsizetype="Minimum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Z</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="transZ"> + <property name="text"> + <string>0</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </widget> + </item> + <item> + <widget class="QGroupBox" name="filterPropertiesGroupBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>0</width> + <height>100</height> + </size> + </property> + <property name="title"> + <string>Filter Properties</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="margin"> + <number>0</number> + </property> + <item> + <widget class="QScrollArea" name="filterPropertiesScrollArea"> + <property name="horizontalScrollBarPolicy"> + <enum>Qt::ScrollBarAlwaysOff</enum> + </property> + <property name="widgetResizable"> + <bool>false</bool> + </property> + <widget class="QWidget" name="scrollAreaWidgetContents"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>263</width> + <height>219</height> + </rect> + </property> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::FieldsStayAtSizeHint</enum> + </property> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> + </widget> + <customwidgets> + <customwidget> + <class>ColorPickerPushButton</class> + <extends>QPushButton</extends> + <header>ColorPickerPushButton.h</header> + </customwidget> + <customwidget> + <class>VtkVisPipelineView</class> + <extends>QTreeView</extends> + <header>VtkVisPipelineView.h</header> + </customwidget> + <customwidget> + <class>QValueTooltipSlider</class> + <extends>QSlider</extends> + <header>QValueTooltipSlider.h</header> + </customwidget> + </customwidgets> + <resources/> + <connections/> +</ui> diff --git a/Gui/main.cpp b/Gui/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..37de4122690bd0a8d2a2c5b7266aa779f28d52b5 --- /dev/null +++ b/Gui/main.cpp @@ -0,0 +1,27 @@ +#include "Configure.h" +#include "mainwindow.h" +#include <QtGui/QApplication> +#ifdef OGS_USE_OPENSG +#include <OpenSG/OSGBaseFunctions.h> +#endif + +int main(int argc, char* argv[]) +{ +#ifdef OGS_USE_OPENSG + OSG::osgInit(argc, argv); +#endif + + QApplication a(argc, argv); + setlocale(LC_NUMERIC,"C"); + MainWindow* w = new MainWindow(); + w->setWindowTitle( w->windowTitle() + " - " + QString(OGS_VERSION) + " - FirstFloor"); + w->show(); + int returncode = a.exec(); + delete w; + +#ifdef OGS_USE_OPENSG + OSG::osgExit(); +#endif // OGS_USE_OPENSG + + return returncode; +} diff --git a/Gui/mainwindow.cpp b/Gui/mainwindow.cpp new file mode 100644 index 0000000000000000000000000000000000000000..61c277e1c4e0d0d9e44233699e3f67128d17e029 --- /dev/null +++ b/Gui/mainwindow.cpp @@ -0,0 +1,1680 @@ +/** + * \file mainwindow.h + * 4/11/2009 LB Initial implementation + * + */ +#include "Configure.h" +#include "mainwindow.h" + +// models +#include "ProcessModel.h" +#include "ElementTreeModel.h" +#include "GEOModels.h" +#include "GeoTreeModel.h" +#include "MshModel.h" +#include "StationTreeModel.h" + +//dialogs +#include "DBConnectionDialog.h" +#include "CondFromRasterDialog.h" +#include "ConditionWriterDialog.h" +#include "DiagramPrefsDialog.h" +#include "FEMConditionSetupDialog.h" +#include "OGSFileConverter.h" +#include "GMSHPrefsDialog.h" +#include "LineEditDialog.h" +#include "ListPropertiesDialog.h" +#include "MshQualitySelectionDialog.h" +#include "NetCdfConfigureDialog.h" +#include "NewProcessDialog.h" +#include "SetNameDialog.h" +#include "VisPrefsDialog.h" +#include "VtkAddFilterDialog.h" + +#ifdef Shapelib_FOUND +#include "SHPImportDialog.h" +#endif + +#include "DatabaseConnection.h" +#include "OGSError.h" +#include "VtkRaster.h" +#include "RecentFiles.h" +#include "TreeModelIterator.h" +#include "VtkBGImageSource.h" +#include "VtkGeoImageSource.h" +#include "VtkVisPipeline.h" +#include "VtkVisPipelineItem.h" + +// FEM Conditions +#include "BoundaryCondition.h" +#include "InitialCondition.h" +#include "SourceTerm.h" +#include "rf_bc_new.h" +#include "rf_ic_new.h" +#include "rf_st_new.h" +#include "FEMIO/BoundaryConditionIO.h" + +// FileIO includes +#include "FEFLOWInterface.h" +#include "GMSInterface.h" +#include "GeoIO/Gmsh2GeoIO.h" +#include "GocadInterface.h" +#include "MeshIO/GMSHInterface.h" +#include "MeshIO/TetGenInterface.h" +#include "NetCDFInterface.h" //YW 07.2010 +#include "OGSIOVer4.h" +#include "PetrelInterface.h" +#include "StationIO.h" +#include "XmlIO/XmlCndInterface.h" +#include "XmlIO/XmlGmlInterface.h" +#include "XmlIO/XmlGspInterface.h" +#include "XmlIO/XmlStnInterface.h" + +#include "StringTools.h" + +// MSH +#include "msh_mesh.h" +#include "MshEditor.h" //test + +// MSHGEOTOOLS +#include "ExtractMeshNodes.h" + +// Qt includes +#include <QDesktopWidget> +#include <QFileDialog> +#include <QMessageBox> +#include <QObject> +#include <QSettings> + +// VTK includes +#include <vtkOBJExporter.h> +#include <vtkRenderer.h> +#include <vtkVRMLExporter.h> + +#ifdef OGS_USE_OPENSG +#include "vtkOsgConverter.h" +#include <OpenSG/OSGCoredNodePtr.h> +#include <OpenSG/OSGGroup.h> +#include <OpenSG/OSGSceneFileHandler.h> +#endif + +#ifdef OGS_USE_VRPN +#include "TrackingSettingsWidget.h" +#include "VtkTrackedCamera.h" +#endif // OGS_USE_VRPN + +#ifdef OGS_BUILD_INFO +#include "BuildInfo.h" +#endif // OGS_BUILD_INFO + +//// test only +//#include "rf_mmp_new.h" +//#include "rf_msp_new.h" +//#include "rf_mfp_new.h" + +/// FEM. 11.03.2010. WW +#include "problem.h" +Problem* aproblem = NULL; + +using namespace FileIO; + +MainWindow::MainWindow(QWidget* parent /* = 0*/) + : QMainWindow(parent), _db (NULL), _project(), _import_files_menu(NULL) +{ + setupUi(this); + + // Setup various models + _geoModels = new GEOModels(); + _project.setGEOObjects(_geoModels); + _meshModels = new MshModel(_project); + _elementModel = new ElementTreeModel(); + _processModel = new ProcessModel(_project); + + geoTabWidget->treeView->setModel(_geoModels->getGeoModel()); + stationTabWidget->treeView->setModel(_geoModels->getStationModel()); + mshTabWidget->treeView->setModel(_meshModels); + mshTabWidget->elementView->setModel(_elementModel); + modellingTabWidget->treeView->setModel(_processModel); + + // vtk visualization pipeline + _vtkVisPipeline = new VtkVisPipeline(visualizationWidget->renderer()); + + // station model connects + connect(stationTabWidget->treeView, SIGNAL(stationListExportRequested(std::string, std::string)), + this, SLOT(exportBoreholesToGMS(std::string, std::string))); // export Stationlist to GMS + connect(stationTabWidget->treeView, SIGNAL(stationListRemoved(std::string)), _geoModels, + SLOT(removeStationVec(std::string))); // update model when stations are removed + connect(stationTabWidget->treeView, SIGNAL(stationListSaved(QString, QString)), this, + SLOT(writeStationListToFile(QString, QString))); // save Stationlist to File + connect(_geoModels, SIGNAL(stationVectorRemoved(StationTreeModel *, std::string)), + this, SLOT(updateDataViews())); // update data view when stations are removed + connect(stationTabWidget->treeView, SIGNAL(diagramRequested(QModelIndex &)), + this, SLOT(showDiagramPrefsDialog(QModelIndex &))); // connect treeview to diagramview + + // geo model connects + connect(geoTabWidget->treeView, SIGNAL(listRemoved(std::string, GEOLIB::GEOTYPE)), + _geoModels, SLOT(removeGeometry(std::string, GEOLIB::GEOTYPE))); + connect(geoTabWidget->treeView, SIGNAL(saveToFileRequested(QString, QString)), + this, SLOT(writeGeometryToFile(QString, QString))); // save geometry to file + connect(geoTabWidget->treeView, SIGNAL(requestLineEditDialog(const std::string &)), + this, SLOT(showLineEditDialog(const std::string &))); // open line edit dialog + connect(geoTabWidget->treeView, SIGNAL(requestNameChangeDialog(const std::string&, const GEOLIB::GEOTYPE, size_t)), + this, SLOT(showGeoNameDialog(const std::string&, const GEOLIB::GEOTYPE, size_t))); + connect(geoTabWidget->treeView, SIGNAL(requestCondSetupDialog(const std::string&, const GEOLIB::GEOTYPE, size_t, bool)), + this, SLOT(showCondSetupDialog(const std::string&, const GEOLIB::GEOTYPE, size_t, bool))); + connect(geoTabWidget->treeView, SIGNAL(loadFEMCondFileRequested(std::string)), + this, SLOT(loadFEMConditions(std::string))); // add FEM Conditions + //connect(geoTabWidget->treeView, SIGNAL(saveFEMConditionsRequested(QString, QString)), + // this, SLOT(writeFEMConditionsToFile(QString, QString))); + connect(_geoModels, SIGNAL(geoDataAdded(GeoTreeModel *, std::string, GEOLIB::GEOTYPE)), + this, SLOT(updateDataViews())); + connect(_geoModels, SIGNAL(geoDataRemoved(GeoTreeModel *, std::string, GEOLIB::GEOTYPE)), + this, SLOT(updateDataViews())); + connect(geoTabWidget->treeView, SIGNAL(geoItemSelected(const vtkPolyDataAlgorithm*, int)), + _vtkVisPipeline, SLOT(highlightGeoObject(const vtkPolyDataAlgorithm*, int))); + connect(geoTabWidget->treeView, SIGNAL(removeGeoItemSelection()), + _vtkVisPipeline, SLOT(removeHighlightedGeoObject())); + + + // Setup connections for mesh models to GUI + connect(mshTabWidget->treeView, SIGNAL(requestMeshRemoval(const QModelIndex &)), + _meshModels, SLOT(removeMesh(const QModelIndex &))); + connect(mshTabWidget->treeView, SIGNAL(requestMeshRemoval(const QModelIndex &)), + _elementModel, SLOT(clearView())); + connect(mshTabWidget->treeView, SIGNAL(qualityCheckRequested(VtkMeshSource*)), + this, SLOT(showMshQualitySelectionDialog(VtkMeshSource*))); + connect(mshTabWidget->treeView, SIGNAL(requestCondSetupDialog(const std::string&, const GEOLIB::GEOTYPE, size_t, bool)), + this, SLOT(showCondSetupDialog(const std::string&, const GEOLIB::GEOTYPE, size_t, bool))); + connect(mshTabWidget->treeView, SIGNAL(requestDIRECTSourceTerms(const std::string, const std::vector<GEOLIB::Point*>*)), + this, SLOT(loadDIRECTSourceTermsFromASCII(const std::string, const std::vector<GEOLIB::Point*>*))); + + // Setup connections for process model to GUI + connect(modellingTabWidget->treeView, SIGNAL(conditionsRemoved(const FiniteElement::ProcessType, const std::string&, const FEMCondition::CondType)), + _processModel, SLOT(removeFEMConditions(const FiniteElement::ProcessType, const std::string&, const FEMCondition::CondType))); + connect(modellingTabWidget->treeView, SIGNAL(processRemoved(const FiniteElement::ProcessType)), + _processModel, SLOT(removeProcess(const FiniteElement::ProcessType))); + connect(modellingTabWidget, SIGNAL(requestNewProcess()), + this, SLOT(showNewProcessDialog())); + connect(modellingTabWidget->treeView, SIGNAL(saveConditionsRequested()), + this, SLOT(showConditionWriterDialog())); + + // VisPipeline Connects + connect(_geoModels, SIGNAL(geoDataAdded(GeoTreeModel *, std::string, GEOLIB::GEOTYPE)), + _vtkVisPipeline, SLOT(addPipelineItem(GeoTreeModel *, std::string, GEOLIB::GEOTYPE))); + connect(_geoModels, SIGNAL(geoDataRemoved(GeoTreeModel *, std::string, GEOLIB::GEOTYPE)), + _vtkVisPipeline, SLOT(removeSourceItem(GeoTreeModel *, std::string, GEOLIB::GEOTYPE))); + + connect(_processModel, SIGNAL(conditionAdded(ProcessModel *, const FiniteElement::ProcessType, const FEMCondition::CondType)), + _vtkVisPipeline, SLOT(addPipelineItem(ProcessModel *, const FiniteElement::ProcessType, const FEMCondition::CondType))); + connect(_processModel, SIGNAL(conditionsRemoved(ProcessModel *, const FiniteElement::ProcessType, const FEMCondition::CondType)), + _vtkVisPipeline, SLOT(removeSourceItem(ProcessModel *, const FiniteElement::ProcessType, const FEMCondition::CondType))); + + connect(_geoModels, SIGNAL(stationVectorAdded(StationTreeModel *, std::string)), + _vtkVisPipeline, SLOT(addPipelineItem(StationTreeModel *, std::string))); + connect(_geoModels, SIGNAL(stationVectorRemoved(StationTreeModel *, std::string)), + _vtkVisPipeline, SLOT(removeSourceItem(StationTreeModel *, std::string))); + + connect(_meshModels, SIGNAL(meshAdded(MshModel *, QModelIndex)), + _vtkVisPipeline, SLOT(addPipelineItem(MshModel *,QModelIndex))); + connect(_meshModels, SIGNAL(meshRemoved(MshModel *, QModelIndex)), + _vtkVisPipeline, SLOT(removeSourceItem(MshModel *, QModelIndex))); + + connect(_vtkVisPipeline, SIGNAL(vtkVisPipelineChanged()), + visualizationWidget->vtkWidget, SLOT(update())); + connect(_vtkVisPipeline, SIGNAL(vtkVisPipelineChanged()), + vtkVisTabWidget->vtkVisPipelineView, SLOT(expandAll())); + + vtkVisTabWidget->vtkVisPipelineView->setModel(_vtkVisPipeline); + connect(vtkVisTabWidget->vtkVisPipelineView, + SIGNAL(requestRemovePipelineItem(QModelIndex)), _vtkVisPipeline, + SLOT(removePipelineItem(QModelIndex))); + connect(vtkVisTabWidget->vtkVisPipelineView, + SIGNAL(requestAddPipelineFilterItem(QModelIndex)), this, + SLOT(showAddPipelineFilterItemDialog(QModelIndex))); + connect(vtkVisTabWidget, SIGNAL(requestViewUpdate()), visualizationWidget, + SLOT(updateView())); + + connect(vtkVisTabWidget->vtkVisPipelineView, + SIGNAL(actorSelected(vtkProp3D*)), + (QObject*) (visualizationWidget->interactorStyle()), + SLOT(highlightActor(vtkProp3D*))); + connect((QObject*) (visualizationWidget->interactorStyle()), + SIGNAL(requestViewUpdate()), + visualizationWidget, SLOT(updateView())); + + // Propagates selected vtk object in the pipeline to the pick interactor + connect(vtkVisTabWidget->vtkVisPipelineView, + SIGNAL(dataObjectSelected(vtkDataObject*)), + (QObject*) (visualizationWidget->interactorStyle()), + SLOT(pickableDataObject(vtkDataObject*))); + connect((QObject*) (visualizationWidget->vtkPickCallback()), + SIGNAL(actorPicked(vtkProp3D*)), + vtkVisTabWidget->vtkVisPipelineView, SLOT(selectItem(vtkProp3D*))); + connect((QObject*) (visualizationWidget->interactorStyle()), + SIGNAL(elementPicked(const GridAdapter *, const size_t)), + this->_elementModel, SLOT(setElement(const GridAdapter *, const size_t))); + connect((QObject*) (visualizationWidget->interactorStyle()), + SIGNAL(elementPicked(const GridAdapter *, const size_t)), + mshTabWidget->elementView, SLOT(updateView())); + + connect(vtkVisTabWidget->vtkVisPipelineView, SIGNAL(meshAdded(GridAdapter*)), + _meshModels, SLOT(addMesh(GridAdapter*))); + + // Stack the data dock widgets together + tabifyDockWidget(geoDock, mshDock); + tabifyDockWidget(mshDock, modellingDock); + tabifyDockWidget(modellingDock, stationDock); + + // Restore window geometry + readSettings(); + + // Get info on screens geometry(ies) + _vtkWidget = visualizationWidget->vtkWidget; + QDesktopWidget* desktopWidget = QApplication::desktop(); +#if OGS_QT_VERSION < 46 + const unsigned int screenCount = desktopWidget->numScreens(); +#else + const unsigned int screenCount = desktopWidget->screenCount(); +#endif // OGS_QT_VERSION < 46 + for (size_t i = 0; i < screenCount; ++i) + _screenGeometries.push_back(desktopWidget->availableGeometry((int)i)); + + // Setup import files menu + _import_files_menu = createImportFilesMenu(); + menu_File->insertMenu(action_Exit, _import_files_menu); + + // Setup recent files menu + RecentFiles* recentFiles = new RecentFiles(this, SLOT(openRecentFile()), + "recentFileList", "OpenGeoSys-5"); + connect(this, SIGNAL(fileUsed(QString)), recentFiles, + SLOT(setCurrentFile(QString))); + menu_File->insertMenu(action_Exit, recentFiles->menu()); + + // Setup Windows menu + QAction* showGeoDockAction = geoDock->toggleViewAction(); + showGeoDockAction->setStatusTip(tr("Shows / hides the geometry view")); + connect(showGeoDockAction, SIGNAL(triggered(bool)), this, + SLOT(showGeoDockWidget(bool))); + menuWindows->addAction(showGeoDockAction); + + QAction* showStationDockAction = stationDock->toggleViewAction(); + showStationDockAction->setStatusTip(tr("Shows / hides the station view")); + connect(showStationDockAction, SIGNAL(triggered(bool)), this, + SLOT(showStationDockWidget(bool))); + menuWindows->addAction(showStationDockAction); + + QAction* showMshDockAction = mshDock->toggleViewAction(); + showMshDockAction->setStatusTip(tr("Shows / hides the mesh view")); + connect(showMshDockAction, SIGNAL(triggered(bool)), this, + SLOT(showMshDockWidget(bool))); + menuWindows->addAction(showMshDockAction); + + QAction* showModellingDockAction = modellingDock->toggleViewAction(); + showModellingDockAction->setStatusTip(tr("Shows / hides the Process view")); + connect(showModellingDockAction, SIGNAL(triggered(bool)), this, + SLOT(showMshDockWidget(bool))); + menuWindows->addAction(showMshDockAction); + + QAction* showVisDockAction = vtkVisDock->toggleViewAction(); + showVisDockAction->setStatusTip(tr("Shows / hides the VTK Pipeline view")); + connect(showVisDockAction, SIGNAL(triggered(bool)), this, + SLOT(showVisDockWidget(bool))); + menuWindows->addAction(showVisDockAction); + + // Presentation mode + QMenu* presentationMenu = new QMenu(); + presentationMenu->setTitle("Presentation on"); + connect(presentationMenu, SIGNAL(aboutToShow()), this, + SLOT(createPresentationMenu())); + menuWindows->insertMenu(showVisDockAction, presentationMenu); + + _fileFinder.addDirectory("."); + _fileFinder.addDirectory(std::string(SOURCEPATH).append("/FileIO")); + +#ifdef OGS_USE_VRPN + VtkTrackedCamera* cam = static_cast<VtkTrackedCamera*> + (visualizationWidget->renderer()->GetActiveCamera()); + _trackingSettingsWidget = new TrackingSettingsWidget(cam, visualizationWidget, Qt::Window); +#endif // OGS_USE_VRPN + + // connects for station model + connect(stationTabWidget->treeView, + SIGNAL(propertiesDialogRequested(std::string)), this, + SLOT(showPropertiesDialog(std::string))); + + _visPrefsDialog = new VisPrefsDialog(_vtkVisPipeline, visualizationWidget); + + // std::cout << "size of Point: " << sizeof (GEOLIB::Point) << std::endl; + // std::cout << "size of CGLPoint: " << sizeof (CGLPoint) << std::endl; + // + // std::cout << "size of Polyline: " << sizeof (GEOLIB::Polyline) << std::endl; + // std::cout << "size of CGLPolyline: " << sizeof (CGLPolyline) << std::endl; + // + // std::cout << "size of GEOLIB::Surface: " << sizeof (GEOLIB::Surface) << std::endl; + // std::cout << "size of Surface: " << sizeof (Surface) << std::endl; + // + // std::cout << "size of CCore: " << sizeof (MeshLib::CCore) << std::endl; + // std::cout << "size of CNode: " << sizeof (MeshLib::CNode) << std::endl; + // std::cout << "size of CElement: " << sizeof (MeshLib::CNode) << std::endl; + // std::cout << "size of CEdge: " << sizeof (MeshLib::CEdge) << std::endl; + // std::cout << "size of CFEMesh: " << sizeof (MeshLib::CFEMesh) << std::endl; + // std::cout << "size of Matrix: " << sizeof (Math_Group::Matrix) << std::endl; + // + // std::cout << "size of vec<size_t>: " << sizeof (Math_Group::vec<size_t>) << std::endl; + // std::cout << "size of std::vector: " << sizeof (std::vector<size_t>) << std::endl; + + // std::cout << "size of CSourceTerm: " << sizeof (CSourceTerm) << std::endl; + // std::cout << "size of CBoundaryCondition: " << sizeof (CBoundaryCondition) << std::endl; + + // std::cout << "size of CElement: " << sizeof (FiniteElement::CElement) << std::endl; +// std::cout << "size of CMediumProperties: " << sizeof(CMediumProperties) << std::endl; +// std::cout << "size of CSolidProperties: " << sizeof(SolidProp::CSolidProperties) << std::endl; +// std::cout << "size of CFluidProperties: " << sizeof(CFluidProperties) << std::endl; + // std::cout << "size of CRFProcess: " << sizeof (CRFProcess) << std::endl; + // std::cout << "size of CFEMesh: " << sizeof (MeshLib::CFEMesh) << std::endl; +} + +MainWindow::~MainWindow() +{ + delete _import_files_menu; + delete _db; + delete _vtkVisPipeline; + delete _meshModels; + delete _processModel; + //delete _visPrefsDialog; + //delete _geoModels; + +#ifdef OGS_USE_VRPN + delete _trackingSettingsWidget; +#endif // OGS_USE_VRPN +} + +void MainWindow::closeEvent(QCloseEvent* event) +{ + writeSettings(); + QWidget::closeEvent(event); +} + +void MainWindow::showGeoDockWidget(bool show) +{ + if (show) + geoDock->show(); + else + geoDock->hide(); +} + +void MainWindow::showStationDockWidget(bool show) +{ + if (show) + stationDock->show(); + else + stationDock->hide(); +} + +void MainWindow::showMshDockWidget(bool show) +{ + if (show) + mshDock->show(); + else + mshDock->hide(); +} + +void MainWindow::showConditionDockWidget(bool show) +{ + if (show) + modellingDock->show(); + else + modellingDock->hide(); +} + +void MainWindow::showVisDockWidget(bool show) +{ + if (show) + vtkVisDock->show(); + else + vtkVisDock->hide(); +} + +void MainWindow::open() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName( this, "Select data file to open",settings.value("lastOpenedOgsFileDirectory").toString(), + "Geosys files (*.gsp *.gli *.gml *.msh *.stn);;Project files (*.gsp);;GeoSys FEM Conditions (*.cnd *.bc *.ic *.st);;GLI files (*.gli);;MSH files (*.msh);;STN files (*.stn);;All files (* *.*)"); + if (!fileName.isEmpty()) + { + QDir dir = QDir(fileName); + settings.setValue("lastOpenedOgsFileDirectory", dir.absolutePath()); + loadFile(fileName); + } +} + +void MainWindow::openDatabase() +{ + if (_db == NULL) + { + _db = new DatabaseConnection(_geoModels); + _db->dbConnect(); + } + + if (_db != NULL && _db->isConnected()) + { + _db->getListSelection(); + updateDataViews(); + } +} + +void MainWindow::openDatabaseConnection() +{ + if (_db == NULL) + _db = new DatabaseConnection(_geoModels); + DBConnectionDialog* dbConn = new DBConnectionDialog(); + connect( + dbConn, + SIGNAL(connectionRequested(QString, QString, QString, QString, QString)), + _db, + SLOT(setConnection(QString, QString, QString, QString, QString))); + dbConn->show(); +} + +void MainWindow::openRecentFile() +{ + QAction* action = qobject_cast<QAction*> (sender()); + if (action) + loadFile(action->data().toString()); +} + +void MainWindow::save() +{ + QString dir_str = this->getLastUsedDir(); + + QString fileName = QFileDialog::getSaveFileName( + this, + "Save data as", + dir_str, + "GeoSys project (*.gsp);;GeoSys4 geometry files (*.gli);;GMSH geometry files (*.geo)"); + + if (!fileName.isEmpty()) + { + QFileInfo fi(fileName); + + if (fi.suffix().toLower() == "gsp") + { + std::string schemaName(_fileFinder.getPath("OpenGeoSysProject.xsd")); + XmlGspInterface xml(&_project, schemaName); + xml.writeToFile(fileName.toStdString()); + } + else if (fi.suffix().toLower() == "geo") + { + // it works like this (none of it is particularily fast or optimised or anything): + // 1. merge all geometries that are currently loaded, all of these will be integrated into the mesh + // 2. if "useStationsAsConstraints"-parameter is true, GMSH-Interface will also integrate all stations that are currently loaded + // if "useSteinerPoints"-parameter is true, additional points will be inserted in large areas without information + // 3. after the geo-file is created the merged geometry is deleted again as it is no longer needed + std::vector<std::string> names; + this->_project.getGEOObjects()->getGeometryNames(names); + std::string merge_name("MergedGeometry"); + _geoModels->mergeGeometries (names, merge_name); + names.clear(); + names.push_back(merge_name); + + double param1(0.5); // mesh density scaling on normal points + double param2(0.05); // mesh density scaling on station points + size_t param3(2); // points per leaf + GMSHInterface gmsh_io(*(this->_project.getGEOObjects()), true, FileIO::GMSH::AdaptiveMeshDensity, param1, param2, param3, names); + gmsh_io.writeToFile(fileName.toStdString()); + + this->_project.getGEOObjects()->removeSurfaceVec(merge_name); + this->_project.getGEOObjects()->removePolylineVec(merge_name); + this->_project.getGEOObjects()->removePointVec(merge_name); + } + else if (fi.suffix().toLower() == "gli") + // writeGLIFileV4 (fileName.toStdString(), gliName.toStdString(), *_geoModels); + writeAllDataToGLIFileV4(fileName.toStdString(), *_geoModels); + } +} + +void MainWindow::loadFile(const QString &fileName) +{ + QFile file(fileName); + if (!file.open(QFile::ReadOnly)) + { + QMessageBox::warning(this, tr("Application"), tr( + "Cannot read file %1:\n%2.").arg(fileName).arg( + file.errorString())); + return; + } + + QApplication::setOverrideCursor(Qt::WaitCursor); + QFileInfo fi(fileName); + std::string base = + fi.absoluteDir().absoluteFilePath(fi.completeBaseName()).toStdString(); + if (fi.suffix().toLower() == "gli") + { +#ifndef NDEBUG + QTime myTimer0; + myTimer0.start(); +#endif + std::string unique_name; + std::vector<std::string> errors; + if (! readGLIFileV4(fileName.toStdString(), _geoModels, unique_name, errors)) { + for (size_t k(0); k<errors.size(); k++) + OGSError::box(QString::fromStdString(errors[k])); + } +#ifndef NDEBUG + std::cout << myTimer0.elapsed() << " ms" << std::endl; +#endif + // + //#ifndef NDEBUG + // QTime myTimer; + // myTimer.start(); + // std::cout << "GEOLIB_Read_GeoLib ... " << std::flush; + //#endif + // GEOLIB_Read_GeoLib(base); //fileName.toStdString()); + // cout << "Nr. Points: " << gli_points_vector.size() << endl; + // cout << "Nr. Lines: " << polyline_vector.size() << endl; + // cout << "Nr. Surfaces: " << surface_vector.size() << endl; + //#ifndef NDEBUG + // std::cout << myTimer.elapsed() << " ms" << std::endl; + //#endif + // GEOCalcPointMinMaxCoordinates(); + } + else if (fi.suffix().toLower() == "gsp") + { + std::string schemaName(_fileFinder.getPath("OpenGeoSysProject.xsd")); + XmlGspInterface xml(&_project, schemaName); + xml.readFile(fileName); + std::cout << "Adding missing meshes to GUI..." << std::endl; + _meshModels->updateModel(); + } + else if (fi.suffix().toLower() == "gml") + { +#ifndef NDEBUG + QTime myTimer0; + myTimer0.start(); +#endif + std::string schemaName(_fileFinder.getPath("OpenGeoSysGLI.xsd")); + XmlGmlInterface xml(&_project, schemaName); + xml.readFile(fileName); +#ifndef NDEBUG + std::cout << myTimer0.elapsed() << " ms" << std::endl; +#endif + } + // OpenGeoSys observation station files (incl. boreholes) + else if (fi.suffix().toLower() == "stn") + { + std::string schemaName(_fileFinder.getPath("OpenGeoSysSTN.xsd")); + XmlStnInterface xml(&_project, schemaName); + xml.readFile(fileName); + } + // OpenGeoSys mesh files + else if (fi.suffix().toLower() == "msh") + { + QTime myTimer0; + myTimer0.start(); + + FileIO::OGSMeshIO meshIO; + std::string name = fileName.toStdString(); + MeshLib::CFEMesh* msh = meshIO.loadMeshFromFile(name); + if (msh) + { + std::cout << "Total mesh loading time: " << myTimer0.elapsed() << " ms" << std::endl; + std::string mesh_name = fi.baseName().toStdString(); + _meshModels->addMesh(msh, mesh_name); + } + else + OGSError::box("Failed to load a mesh file."); + } + else if ((fi.suffix().toLower() == "cnd") || + (fi.suffix().toLower() == "bc") || + (fi.suffix().toLower() == "ic") || + (fi.suffix().toLower() == "st")) + { + this->loadFEMConditionsFromFile(fileName); + } + + // GMS borehole files + else if (fi.suffix().toLower() == "txt") + { + std::vector<GEOLIB::Point*>* boreholes = + new std::vector<GEOLIB::Point*>(); + std::string name = fi.baseName().toStdString(); + + if (GMSInterface::readBoreholesFromGMS(boreholes, fileName.toStdString())) + _geoModels->addStationVec(boreholes, name); + else + OGSError::box("Error reading GMS file."); + } + // GMS mesh files + else if (fi.suffix().toLower() == "3dm") + { + std::string name = fileName.toStdString(); + MeshLib::CFEMesh* mesh = GMSInterface::readGMS3DMMesh(name); + if (mesh) + _meshModels->addMesh(mesh, name); + } + // goCAD files + else if (fi.suffix().toLower() == "ts") + { +#ifndef NDEBUG + QTime myTimer; + myTimer.start(); + std::cout << "GoCad Read ... " << std::flush; +#endif + FileIO::GocadInterface(fileName.toStdString(), _geoModels); +#ifndef NDEBUG + std::cout << myTimer.elapsed() << " ms" << std::endl; +#endif + } + + // NetCDF files + // CH 01.2012 + else if (fi.suffix().toLower() == "nc") + { +#ifndef NDEBUG + QTime myTimer; + myTimer.start(); + std::cout << "NetCDF Read ...\n" << std::flush; +#endif + std::string name = fileName.toStdString(); + GridAdapter* mesh; + + NetCdfConfigureDialog dlg(name); + dlg.exec(); + if (dlg.getMesh() != NULL) + { + mesh = dlg.getMesh(); + mesh->setName(dlg.getName()); + _meshModels->addMesh(mesh); + } + if (dlg.getRaster() != NULL) + { + _vtkVisPipeline->addPipelineItem(dlg.getRaster()); + } + +#ifndef NDEBUG + std::cout << myTimer.elapsed() << " ms" << std::endl; +#endif + } + updateDataViews(); + + emit fileUsed(fileName); +} + +void MainWindow::loadPetrelFiles(const QStringList &sfc_file_names, + const QStringList &well_path_file_names) +{ + QStringList::const_iterator it = sfc_file_names.begin(); + std::list<std::string> sfc_files; + while (it != sfc_file_names.end()) + { + sfc_files.push_back((*it).toStdString()); + ++it; + } + + it = well_path_file_names.begin(); + std::list<std::string> well_path_files; + while (it != well_path_file_names.end()) + { + well_path_files.push_back((*it).toStdString()); + ++it; + } + + std::string unique_str(*(sfc_files.begin())); + + PetrelInterface(sfc_files, well_path_files, unique_str, _geoModels); +} + +void MainWindow::updateDataViews() +{ + visualizationWidget->updateViewOnLoad(); + geoTabWidget->treeView->updateView(); + stationTabWidget->treeView->updateView(); + mshTabWidget->treeView->updateView(); + + QApplication::restoreOverrideCursor(); +} + +void MainWindow::readSettings() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + + restoreGeometry(settings.value("windowGeometry").toByteArray()); + restoreState(settings.value("windowState").toByteArray()); +} + +void MainWindow::writeSettings() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + + settings.setValue("windowGeometry", saveGeometry()); + settings.setValue("windowState", saveState()); +} + +void MainWindow::about() +{ + QString ogsVersion = QString(OGS_VERSION); + + QString about = tr("Built on %1\nOGS Version: %2\n\n").arg( + QDate::currentDate().toString(Qt::ISODate)).arg(ogsVersion); +#ifdef OGS_BUILD_INFO +#ifdef SVN_REVISION + about.append(QString("Svn commit: %1\n").arg(SVN_REVISION)); +#endif +#ifdef GIT_COMMIT_INFO + QString gitCommit = QString(GIT_COMMIT_INFO); + about.append(QString("Git commit: %1\n").arg(gitCommit.mid(7))); +#endif // GIT_COMMIT_INFO +#ifdef GIT_BRANCH_INFO + QString gitBranch = QString(GIT_BRANCH_INFO); + about.append(QString("Git branch: %1\n").arg(gitBranch.mid(2))); +#endif // GIT_BRANCH_INFO +#endif // OGS_BUILD_INFO + QMessageBox::about(this, "About OpenGeoSys-5", about); +} + +QMenu* MainWindow::createImportFilesMenu() +{ + QMenu* importFiles = new QMenu("&Import Files"); + QAction* feflowFiles = importFiles->addAction("&FEFLOW Files..."); + connect(feflowFiles, SIGNAL(triggered()), this, SLOT(importFeflow())); + QAction* gmsFiles = importFiles->addAction("G&MS Files..."); + connect(gmsFiles, SIGNAL(triggered()), this, SLOT(importGMS())); + QAction* gocadFiles = importFiles->addAction("&Gocad Files..."); + connect(gocadFiles, SIGNAL(triggered()), this, SLOT(importGoCad())); + QAction* netcdfFiles = importFiles->addAction("&NetCDF Files..."); + connect(netcdfFiles, SIGNAL(triggered()), this, SLOT(importNetcdf())); + QAction* petrelFiles = importFiles->addAction("&Petrel Files..."); + connect(petrelFiles, SIGNAL(triggered()), this, SLOT(importPetrel())); + QAction* rasterFiles = importFiles->addAction("&Raster Files..."); + connect(rasterFiles, SIGNAL(triggered()), this, SLOT(importRaster())); +#ifdef OGS_USE_OPENSG + QAction* rasterPolyFiles = importFiles->addAction("R&aster Files as PolyData..."); + connect(rasterPolyFiles, SIGNAL(triggered()), this, SLOT(importRasterAsPoly())); +#endif +#ifdef Shapelib_FOUND + QAction* shapeFiles = importFiles->addAction("&Shape Files..."); + connect(shapeFiles, SIGNAL(triggered()), this, SLOT(importShape())); +#endif + QAction* tetgenFiles = importFiles->addAction("&TetGen Files..."); + connect( tetgenFiles, SIGNAL(triggered()), this, SLOT(importTetGen()) ); + QAction* vtkFiles = importFiles->addAction("&VTK Files..."); + connect( vtkFiles, SIGNAL(triggered()), this, SLOT(importVtk()) ); + + return importFiles; +} + +void MainWindow::importGMS() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName(this, + "Select GMS file to import", settings.value( + "lastOpenedFileDirectory").toString(), + "GMS files (*.txt *.3dm)"); + if (!fileName.isEmpty()) + { + loadFile(fileName); + QDir dir = QDir(fileName); + settings.setValue("lastOpenedFileDirectory", dir.absolutePath()); + } +} + +void MainWindow::importGoCad() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName(this, + "Select data file to import", + settings.value( + "lastOpenedFileDirectory").toString(), + "Gocad files (*.ts);;Gocad lines (*.tline)"); + if (!fileName.isEmpty()) + { + loadFile(fileName); + QDir dir = QDir(fileName); + settings.setValue("lastOpenedFileDirectory", dir.absolutePath()); + } +} + +void MainWindow::importRaster() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); +#ifdef libgeotiff_FOUND + QString geotiffExtension(" *.tif"); +#else + QString geotiffExtension(""); +#endif + QString fileName = QFileDialog::getOpenFileName(this, "Select raster file to import", + settings.value("lastOpenedRasterFileDirectory").toString(), QString( + "Raster files (*.asc *.grd *.bmp *.jpg *.png%1);;") .arg(geotiffExtension)); + + if (!fileName.isEmpty()) + { + VtkGeoImageSource* geoImage = VtkGeoImageSource::New(); + geoImage->readImage(fileName); + _vtkVisPipeline->addPipelineItem(geoImage); + + QDir dir = QDir(fileName); + settings.setValue("lastOpenedRasterFileDirectory", dir.absolutePath()); + } +} + +void MainWindow::importRasterAsPoly() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); +#ifdef libgeotiff_FOUND + QString geotiffExtension(" *.tif"); +#else + QString geotiffExtension(""); +#endif + QString fileName = QFileDialog::getOpenFileName(this, "Select raster file to import", + settings.value("lastOpenedRasterFileDirectory").toString(), QString( + "Raster files (*.asc *.bmp *.jpg *.png%1);;") .arg( + geotiffExtension)); + + if (!fileName.isEmpty()) + { + QImage raster; + double origin[2]; + double cellSize; + vtkImageAlgorithm* imageAlgorithm = VtkRaster::loadImage( + fileName.toStdString(), origin[0], origin[1], cellSize); + VtkBGImageSource* bg = VtkBGImageSource::New(); + bg->SetRaster(imageAlgorithm, origin[0], origin[1], cellSize); + bg->SetName(fileName); + _vtkVisPipeline->addPipelineItem(bg); + + QDir dir = QDir(fileName); + settings.setValue("lastOpenedRasterFileDirectory", dir.absolutePath()); + } +} + +#ifdef Shapelib_FOUND +void MainWindow::importShape() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName(this, "Select shape file to import", + settings.value("lastOpenedShapeFileDirectory").toString(), + "ESRI Shape files (*.shp );;"); + QFileInfo fi(fileName); + + if (fi.suffix().toLower() == "shp" || fi.suffix().toLower() == "dbf") + { + SHPImportDialog dlg((fileName.toUtf8()).constData(), _geoModels); + dlg.exec(); + + QDir dir = QDir(fileName); + settings.setValue("lastOpenedShapeFileDirectory", dir.absolutePath()); + } +} +#endif + +void MainWindow::importPetrel() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QStringList sfc_file_names = QFileDialog::getOpenFileNames( + this, "Select surface data file(s) to import", "", "Petrel files (*)"); + QStringList well_path_file_names = QFileDialog::getOpenFileNames( + this, "Select well path data file(s) to import", "", "Petrel files (*)"); + if (sfc_file_names.size() != 0 || well_path_file_names.size() != 0) + { + loadPetrelFiles(sfc_file_names, well_path_file_names); + QDir dir = QDir(sfc_file_names.at(0)); + settings.setValue("lastOpenedFileDirectory", dir.absolutePath()); + } +} + +//YW 07.2010 +void MainWindow::importNetcdf() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName(this, + "Select NetCDF file to import", + settings.value( + "lastOpenedFileDirectory").toString(), + "NetCDF files (*.nc);;"); + if (!fileName.isEmpty()) + { + loadFile(fileName); + QDir dir = QDir(fileName); + settings.setValue("lastOpenedFileDirectory", dir.absolutePath()); + } +} + +void MainWindow::importTetGen() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString node_fname(QFileDialog::getOpenFileName(this, "Select TetGen node file", + settings.value("lastOpenedTetgenFileDirectory").toString(), + "TetGen node files (*.node);;")); + QString element_fname(QFileDialog::getOpenFileName(this, "Select TetGen element file", + settings.value("lastOpenedTetgenFileDirectory").toString(), + "TetGen element files (*.ele);;")); + + if (!node_fname.isEmpty() && !element_fname.isEmpty()) { + FileIO::TetGenInterface tetgen; + MeshLib::CFEMesh* msh (tetgen.readTetGenMesh(node_fname.toStdString(), element_fname.toStdString())); + if (msh) { + std::string name(node_fname.toStdString()); + _meshModels->addMesh(msh, name); + } else + OGSError::box("Failed to load a TetGen mesh."); + settings.setValue("lastOpenedTetgenFileDirectory", QDir(node_fname).absolutePath()); + } +} + +void MainWindow::importVtk() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QStringList fileNames = QFileDialog::getOpenFileNames(this, + "Select VTK file(s) to import", + settings.value("lastOpenedVtkFileDirectory"). + toString(), + "VTK files (*.vtk *.vti *.vtr *.vts *.vtp *.vtu);;"); + foreach(QString fileName, fileNames) { + if (!fileName.isEmpty()) + { + _vtkVisPipeline->loadFromFile(fileName); + QDir dir = QDir(fileName); + settings.setValue("lastOpenedVtkFileDirectory", dir.absolutePath()); + } + } +} + +void MainWindow::importFeflow() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName(this, + "Select FEFLOW file(s) to import", + settings.value( + "lastOpenedFileDirectory").toString(), + "FEFLOW files (*.fem);;"); + if (!fileName.isEmpty()) + { + FEFLOWInterface feflowIO(_geoModels); + MeshLib::CFEMesh* msh = feflowIO.readFEFLOWModelFile(fileName.toStdString()); + if (msh) + { + std::string str = fileName.toStdString(); + _meshModels->addMesh(msh, str); + QDir dir = QDir(fileName); + settings.setValue("lastOpenedFileDirectory", dir.absolutePath()); + //_geoModels->modified("Feflow"); + updateDataViews(); + } + else + OGSError::box("Failed to load a FEFLOW file."); + } + emit fileUsed(fileName); +} + +void MainWindow::showPropertiesDialog(std::string const& name) +{ + ListPropertiesDialog dlg(name, _geoModels); + connect( + &dlg, + SIGNAL(propertyBoundariesChanged(std::string, std::vector<PropertyBounds>)), + _geoModels, + SLOT(filterStationVec(std::string, std::vector<PropertyBounds>))); + dlg.exec(); +} + +void MainWindow::showAddPipelineFilterItemDialog(QModelIndex parentIndex) +{ + VtkAddFilterDialog dlg(_vtkVisPipeline, parentIndex); + dlg.exec(); +} + +void MainWindow::loadFEMConditions(std::string geoName) +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName( this, "Select data file to open", + settings.value("lastOpenedFileDirectory").toString(), + "Geosys FEM condition files (*.cnd *.bc *.ic *.st);;All files (* *.*)"); + QDir dir = QDir(fileName); + settings.setValue("lastOpenedFileDirectory", dir.absolutePath()); + + if (!fileName.isEmpty()) + this->loadFEMConditionsFromFile(fileName, geoName); +} + +void MainWindow::loadFEMConditionsFromFile(const QString &fileName, std::string geoName) +{ + std::vector<FEMCondition*> conditions; + QFileInfo fi(fileName); + if (fi.suffix().toLower() == "cnd") + { + std::string schemaName(_fileFinder.getPath("OpenGeoSysCond.xsd")); + XmlCndInterface xml(&_project, schemaName); + xml.readFile(conditions, fileName); + } + else + { + if (geoName.empty()) + { + // assume that geoName is identical to filename of the currently loaded file (but with *.gli-extension) + QFileInfo fi(fileName); + geoName = fi.fileName().toStdString(); + geoName = geoName.substr(0, geoName.find_last_of(".")).append(".gli"); + } + if (fi.suffix().toLower() == "bc") + { + QString name = fi.path() + "/"; + BCRead((name.append(fi.baseName())).toStdString(), *_geoModels, geoName); + for (std::list<CBoundaryCondition*>::iterator it = bc_list.begin(); + it != bc_list.end(); ++it) + { + BoundaryCondition* bc = new BoundaryCondition(*(*it), geoName); + conditions.push_back(bc); + } + } + else if (fi.suffix().toLower() == "ic") + { + QString name = fi.path() + "/"; + ICRead((name.append(fi.baseName())).toStdString(), *_geoModels, geoName); + for (std::vector<CInitialCondition*>::iterator it = ic_vector.begin(); + it != ic_vector.end(); ++it) + { + InitialCondition* ic = new InitialCondition(*(*it), geoName); + conditions.push_back(ic); + } + } + else if (fi.suffix().toLower() == "st") + { + QString name = fi.path() + "/"; + STRead((name.append(fi.baseName())).toStdString(), *_geoModels, geoName); + for (std::vector<CSourceTerm*>::iterator it = st_vector.begin(); + it != st_vector.end(); ++it) + { + SourceTerm* st = new SourceTerm(*(*it), geoName); + conditions.push_back(st); + } + } + } + this->addFEMConditions(conditions); +} + +void MainWindow::addFEMConditions(const std::vector<FEMCondition*> conditions) +{ + if (!conditions.empty()) + { + for (size_t i = 0; i < conditions.size(); i++) + { + bool condition_ok(true); + if (conditions[i]->getProcessDistributionType() == FiniteElement::DIRECT) + { + if (_meshModels->getMesh(conditions[i]->getAssociatedGeometryName()) != NULL) { + std::vector<GEOLIB::Point*> *points = GEOLIB::PointVec::deepcopy(_meshModels->getMesh(conditions[i]->getAssociatedGeometryName())->getNodes()); + GEOLIB::PointVec pnt_vec("MeshNodes", points); + std::vector<GEOLIB::Point*> *cond_points = pnt_vec.getSubset(conditions[i]->getDisNodes()); + std::string geo_name = conditions[i]->getGeoName(); + this->_geoModels->addPointVec(cond_points, geo_name); + conditions[i]->setGeoName(geo_name); // this might have been changed upon inserting it into geo_objects + } else { + OGSError::box("Please load an appropriate geometry first", "Error"); + condition_ok = false; + } + } + if (condition_ok) { + this->_processModel->addCondition(conditions[i]); + } + } + + for (std::list<CBoundaryCondition*>::iterator it = bc_list.begin(); + it != bc_list.end(); ++it) + delete *it; + bc_list.clear(); + for (size_t i = 0; i < ic_vector.size(); i++) + delete ic_vector[i]; + ic_vector.clear(); + for (size_t i = 0; i < st_vector.size(); i++) + delete st_vector[i]; + st_vector.clear(); + } +} + +// Legacy function (only required for ascii st-files): reads values for 'direct' source terms +void MainWindow::loadDIRECTSourceTermsFromASCII(const std::string mshname, const std::vector<GEOLIB::Point*>* points) +{ + std::string geo_name(mshname); + + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName( this, "Select data file to open", + settings.value("lastOpenedFileDirectory").toString(), + "Geosys FEM condition files (*.st);;All files (* *.*)"); + QFileInfo fi(fileName); + std::string file_path = fi.absoluteDir().absolutePath().toStdString() + "/"; + + if (!fileName.isEmpty()) + { + std::string st_file_name (file_path); + STRead(st_file_name.append(fi.baseName().toStdString()), *_geoModels, geo_name); + + for (std::vector<CSourceTerm*>::const_iterator it = st_vector.begin(); it != st_vector.end(); + ++it) + { + if ((*it)->getProcessDistributionType() == FiniteElement::DIRECT) + { + CSourceTerm ast = **it; + SourceTerm* st = new SourceTerm(ast, mshname); + std::vector< std::pair<size_t, double> > node_values; + SourceTerm::getDirectNodeValues(file_path + (*it)->fname, node_values); + st->setGeoName(mshname); + st->setDisValues(node_values); + + std::vector<GEOLIB::Point*> *points2 = GEOLIB::PointVec::deepcopy(points); + GEOLIB::PointVec pnt_vec("MeshNodes", points2); + std::vector<GEOLIB::Point*> *cond_points = pnt_vec.getSubset(st->getDisNodes()); + std::string geometry_name = st->getGeoName(); + this->_geoModels->addPointVec(cond_points, geometry_name); + this->_processModel->addCondition(st); + } + } + } +} + +void MainWindow::writeFEMConditionsToFile(const QString &geoName, const FEMCondition::CondType type, const QString &fileName) +{ + QFileInfo fi(fileName); + if (fi.suffix().compare("cnd") == 0 ) + { + std::string schemaName(_fileFinder.getPath("OpenGeoSysCond.xsd")); + XmlCndInterface xml(&_project, schemaName); + xml.setNameForExport(geoName.toStdString()); + xml.setConditionType(type); + xml.writeToFile(fileName.toStdString()); + } + else + { + const std::vector<FEMCondition*> conds = _project.getConditions(); + for (size_t i=0; i<conds.size(); i++) + { + if ((conds[i]->getCondType() == type) && + (QString::fromStdString(conds[i]->getAssociatedGeometryName()) == geoName)) + { + if (type == FEMCondition::BOUNDARY_CONDITION) + bc_list.push_back(new CBoundaryCondition(static_cast<BoundaryCondition*>(conds[i]))); + else if (type == FEMCondition::INITIAL_CONDITION) + ic_vector.push_back(new CInitialCondition(static_cast<InitialCondition*>(conds[i]))); + else if (type == FEMCondition::SOURCE_TERM) + st_vector.push_back(new CSourceTerm(static_cast<SourceTerm*>(conds[i]))); + } + } + if (type == FEMCondition::BOUNDARY_CONDITION) + BCWrite(fileName.toStdString()); + else if (type == FEMCondition::INITIAL_CONDITION) + ICWrite(fileName.toStdString()); + else if (type == FEMCondition::SOURCE_TERM) + STWrite(fileName.toStdString()); + } +} + +void MainWindow::writeGeometryToFile(QString gliName, QString fileName) +{ + std::string schemaName(_fileFinder.getPath("OpenGeoSysGLI.xsd")); + XmlGmlInterface xml(&_project, schemaName); + xml.setNameForExport(gliName.toStdString()); + xml.writeToFile(fileName.toStdString()); +} + +void MainWindow::writeStationListToFile(QString listName, QString fileName) +{ + std::string schemaName(_fileFinder.getPath("OpenGeoSysSTN.xsd")); + XmlStnInterface xml(&_project, schemaName); + xml.setNameForExport(listName.toStdString()); + xml.writeToFile(fileName.toStdString()); +} + +void MainWindow::exportBoreholesToGMS(std::string listName, + std::string fileName) +{ + const std::vector<GEOLIB::Point*>* stations(_geoModels->getStationVec(listName)); + GMSInterface::writeBoreholesToGMS(stations, fileName); +} + +void MainWindow::callGMSH(std::vector<std::string> & selectedGeometries, + size_t param1, double param2, double param3, double param4, + bool delete_geo_file) +{ + if (!selectedGeometries.empty()) + { + std::cout << "Start meshing..." << std::endl; + + QString fileName(""); + QString dir_str = this->getLastUsedDir(); + + if (!delete_geo_file) + fileName = QFileDialog::getSaveFileName(this, + "Save GMSH-file as", + dir_str, + "GMSH geometry files (*.geo)"); + else + fileName = "tmp_gmsh.geo"; + + if (!fileName.isEmpty()) + { + if (param4 == -1) { // adaptive meshing selected + GMSHInterface gmsh_io(*(static_cast<GEOLIB::GEOObjects*> (_geoModels)), true, + FileIO::GMSH::AdaptiveMeshDensity, param2, param3, param1, + selectedGeometries); + gmsh_io.setPrecision(20); + gmsh_io.writeToFile(fileName.toStdString()); + } else { // homogeneous meshing selected + GMSHInterface gmsh_io(*(static_cast<GEOLIB::GEOObjects*> (_geoModels)), true, + FileIO::GMSH::FixedMeshDensity, param4, param3, param1, + selectedGeometries); + gmsh_io.setPrecision(20); + gmsh_io.writeToFile(fileName.toStdString()); + } + + + if (system(NULL) != 0) // command processor available + { + std::string gmsh_command("gmsh -2 -algo meshadapt "); + std::string fname (fileName.toStdString()); + gmsh_command += fname; + size_t pos (fname.rfind (".")); + if (pos != std::string::npos) + fname = fname.substr (0, pos); + gmsh_command += " -o " + fname + ".msh"; + system(gmsh_command.c_str()); + this->loadFile(fileName.left(fileName.length() - 3).append("msh")); + } + else + OGSError::box( + "Error executing command gmsh - no command processor available", + "Error"); + + if (delete_geo_file) // delete file + { + std::string remove_command ("rm "); +#ifdef _WIN32 + remove_command = "del "; +#endif + remove_command += fileName.toStdString(); + std::cout << "remove command: " << remove_command << std::endl; + system(remove_command.c_str()); + } + } + } + else + std::cout << "No geometry information selected..." << std::endl; +} + +void MainWindow::showConditionWriterDialog() +{ + ConditionWriterDialog dlg(_geoModels); + connect(&dlg , SIGNAL(saveFEMConditionsRequested(const QString&, const FEMCondition::CondType, const QString&)), + this, SLOT(writeFEMConditionsToFile(const QString&, const FEMCondition::CondType, const QString&))); + dlg.exec(); +} + +void MainWindow::showDiagramPrefsDialog(QModelIndex &index) +{ + QString listName; + GEOLIB::Station* stn = _geoModels->getStationModel()->stationFromIndex( + index, listName); + + if ((stn->type() == GEOLIB::Station::STATION) && stn->getSensorData()) + { + DiagramPrefsDialog* prefs ( new DiagramPrefsDialog(stn) ); + //DiagramPrefsDialog* prefs = new DiagramPrefsDialog(stn, listName, _db); + prefs->setAttribute(Qt::WA_DeleteOnClose); + prefs->show(); + } + if (stn->type() == GEOLIB::Station::BOREHOLE) + OGSError::box("No time series data available for borehole."); +} + +void MainWindow::showDiagramPrefsDialog() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getOpenFileName( this, "Select data file to open", + settings.value( + "lastOpenedFileDirectory"). + toString(), + "Text files (*.txt);;All files (* *.*)"); + if (!fileName.isEmpty()) + { + QDir dir = QDir(fileName); + settings.setValue("lastOpenedFileDirectory", dir.absolutePath()); + DiagramPrefsDialog* prefs = new DiagramPrefsDialog(fileName); + prefs->setAttribute(Qt::WA_DeleteOnClose); + prefs->show(); + } +} + +void MainWindow::showFileConverterDialog() +{ + OGSFileConverter dlg; + dlg.exec(); +} + +void MainWindow::showGeoNameDialog(const std::string &geometry_name, const GEOLIB::GEOTYPE object_type, size_t id) +{ + std::string old_name = this->_geoModels->getElementNameByID(geometry_name, object_type, id); + SetNameDialog dlg(geometry_name, GEOLIB::convertGeoTypeToString(object_type), id, old_name); + connect(&dlg, SIGNAL(requestNameChange(const std::string&, const GEOLIB::GEOTYPE, size_t, std::string)), + this->_geoModels, SLOT(addNameForElement(const std::string&, const GEOLIB::GEOTYPE, size_t, std::string))); + dlg.exec(); + + static_cast<GeoTreeModel*>(this->geoTabWidget->treeView->model())->setNameForItem(geometry_name, object_type, + id, this->_geoModels->getElementNameByID(geometry_name, object_type, id)); +} + +void MainWindow::showCondSetupDialog(const std::string &geometry_name, const GEOLIB::GEOTYPE object_type, size_t id, bool on_points) +{ + std::string geo_name(""); + if (object_type != GEOLIB::INVALID) + geo_name = this->_geoModels->getElementNameByID(geometry_name, object_type, id); + else + geo_name = geometry_name; // in this case this is actually the mesh name + + if (geo_name.empty()) + { + this->showGeoNameDialog(geometry_name, object_type, id); + geo_name = this->_geoModels->getElementNameByID(geometry_name, object_type, id); + } + // Object should now have a name ... if not, cancel the setup process + if (geo_name.empty()) + OGSError::box("FEM Condition Setup canceled."); + else + { + if (on_points) + this->_geoModels->addNameForObjectPoints(geometry_name, object_type, geo_name, geometry_name); + + if (object_type != GEOLIB::INVALID) + { + FEMConditionSetupDialog dlg(geometry_name, object_type, geo_name, this->_geoModels->getGEOObject(geometry_name, object_type, geo_name), on_points); + connect(&dlg, SIGNAL(createFEMCondition(std::vector<FEMCondition*>)), this, SLOT(addFEMConditions(std::vector<FEMCondition*>))); + dlg.exec(); + } + else + { + const MeshLib::CFEMesh* mesh = _project.getMesh(geo_name); + FEMConditionSetupDialog dlg(geo_name, mesh); + connect(&dlg, SIGNAL(createFEMCondition(std::vector<FEMCondition*>)), this, SLOT(addFEMConditions(std::vector<FEMCondition*>))); + dlg.exec(); + } + } +} + +void MainWindow::showNewProcessDialog() +{ + NewProcessDialog dlg; + connect(&dlg , SIGNAL(addProcess(ProcessInfo*)), + _processModel, SLOT(addProcess(ProcessInfo*))); + dlg.exec(); +} + +void MainWindow::showLineEditDialog(const std::string &geoName) +{ + LineEditDialog lineEdit(*(_geoModels->getPolylineVecObj(geoName))); + connect(&lineEdit, SIGNAL(connectPolylines(const std::string &, std::vector<size_t>, double, std::string, bool, bool)), + _geoModels, SLOT(connectPolylineSegments(const std::string &, std::vector<size_t>, double, std::string, bool, bool))); + lineEdit.exec(); +} + +void MainWindow::showGMSHPrefsDialog() +{ + GMSHPrefsDialog dlg(_geoModels); + connect(&dlg, SIGNAL(requestMeshing(std::vector<std::string> &, size_t, double, double, double, bool)), + this, SLOT(callGMSH(std::vector<std::string> &, size_t, double, double, double, bool))); + dlg.exec(); +} + +void MainWindow::showMshQualitySelectionDialog(VtkMeshSource* mshSource) +{ + MshQualitySelectionDialog dlg(mshSource); + connect(&dlg, SIGNAL(measureSelected(VtkMeshSource *, MshQualityType::type)), + _vtkVisPipeline, SLOT(checkMeshQuality(VtkMeshSource *, MshQualityType::type))); + dlg.exec(); +} + +void MainWindow::showVisalizationPrefsDialog() +{ + _visPrefsDialog->show(); +} + +void MainWindow::FEMTestStart() +{ + std::string name ("Test"); + _meshModels->addMesh(MshEditor::getMeshSurface(*_project.getMesh("Ammer-Homogen100m-Final")), name); + +/* + const std::vector<GEOLIB::Polyline*> *lines = this->_geoModels->getPolylineVec("WESS Rivers"); + MeshLib::CFEMesh* mesh = const_cast<MeshLib::CFEMesh*>(_project.getMesh("Ammer-Homogen100m-Final")); + std::vector<size_t> nodes; + mesh->GetNODOnPLY((*lines)[0], nodes); + + std::vector<GEOLIB::Point*> *points = new std::vector<GEOLIB::Point*>(nodes.size()); + for (size_t i=0; i<nodes.size(); i++) + { + (*points)[i] = new GEOLIB::Point(mesh->nod_vector[nodes[i]]->getData()); + } + std::string testpoints_name("testpoints"); + _geoModels->addPointVec(points, testpoints_name); +*/ +} + + +void MainWindow::showTrackingSettingsDialog() +{ +#ifdef OGS_USE_VRPN + _trackingSettingsWidget->show(); +#else // OGS_USE_VRPN + QMessageBox::warning(this, "Functionality not implemented", + "Sorry but this progam was not compiled with VRPN support."); +#endif // OGS_USE_VRPN +} + +void MainWindow::ShowWindow() +{ + this->show(); +} + +void MainWindow::HideWindow() +{ + this->hide(); +} + +void MainWindow::on_actionExportVTK_triggered(bool checked /*= false*/) +{ + Q_UNUSED(checked) + QSettings settings("UFZ", "OpenGeoSys-5"); + int count = 0; + QString filename = QFileDialog::getSaveFileName(this, + "Export object to vtk-files", + settings.value( + "lastExportedFileDirectory"). + toString(), + "VTK files (*.vtp *.vtu)"); + if (!filename.isEmpty()) + { + QDir dir = QDir(filename); + settings.setValue("lastExportedFileDirectory", dir.absolutePath()); + + std::string basename = QFileInfo(filename).path().toStdString(); + basename.append("/" + QFileInfo(filename).baseName().toStdString()); + TreeModelIterator it(_vtkVisPipeline); + ++it; + while (*it) + { + count++; + static_cast<VtkVisPipelineItem*> (*it)->writeToFile(basename + + number2str(count)); + ++it; + } + } +} + +void MainWindow::on_actionExportVRML2_triggered(bool checked /*= false*/) +{ + Q_UNUSED(checked) + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getSaveFileName(this, + "Save scene to VRML file", settings.value( + "lastExportedFileDirectory"). + toString(), + "VRML files (*.wrl);;"); + if (!fileName.isEmpty()) + { + QDir dir = QDir(fileName); + settings.setValue("lastExportedFileDirectory", dir.absolutePath()); + + vtkVRMLExporter* exporter = vtkVRMLExporter::New(); + exporter->SetFileName(fileName.toStdString().c_str()); + exporter->SetRenderWindow( + visualizationWidget->vtkWidget->GetRenderWindow()); + exporter->Write(); + exporter->Delete(); + } +} + +void MainWindow::on_actionExportObj_triggered(bool checked /*= false*/) +{ + Q_UNUSED(checked) + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName = QFileDialog::getSaveFileName(this, + "Save scene to Wavefront OBJ files", + settings.value( + "lastExportedFileDirectory"). + toString(), + ";;"); + if (!fileName.isEmpty()) + { + QDir dir = QDir(fileName); + settings.setValue("lastExportedFileDirectory", dir.absolutePath()); + + vtkOBJExporter* exporter = vtkOBJExporter::New(); + exporter->SetFilePrefix(fileName.toStdString().c_str()); + exporter->SetRenderWindow( + visualizationWidget->vtkWidget->GetRenderWindow()); + exporter->Write(); + exporter->Delete(); + } +} + +void MainWindow::on_actionExportOpenSG_triggered(bool checked /*= false*/) +{ + Q_UNUSED(checked) +#ifdef OGS_USE_OPENSG + QSettings settings("UFZ", "OpenGeoSys-5"); + QString filename = QFileDialog::getSaveFileName( + this, "Export scene to OpenSG binary file", settings.value( + "lastExportedFileDirectory").toString(), "OpenSG files (*.osb);;"); + if (!filename.isEmpty()) + { + QDir dir = QDir(filename); + settings.setValue("lastExportedFileDirectory", dir.absolutePath()); + + TreeModelIterator it(_vtkVisPipeline); + ++it; + OSG::NodePtr root = OSG::makeCoredNode<OSG::Group>(); + while(*it) + { + VtkVisPipelineItem* item = static_cast<VtkVisPipelineItem*>(*it); + vtkOsgConverter converter(static_cast<vtkActor*>(item->actor())); + if(converter.WriteAnActor()) + { + beginEditCP(root); + root->addChild(converter.GetOsgNode()); + endEditCP(root); + } + ++it; + } + + OSG::SceneFileHandler::the().write(root, filename.toStdString().c_str()); + } +#else // ifdef OGS_USE_OPENSG + QMessageBox::warning(this, "Functionality not implemented", + "Sorry but this progam was not compiled with OpenSG support."); +#endif +} + +void MainWindow::createPresentationMenu() +{ + QMenu* menu = static_cast<QMenu*> (QObject::sender()); + menu->clear(); + if (!_vtkWidget->parent()) + { + QAction* action = new QAction("Quit presentation mode", menu); + connect(action, SIGNAL(triggered()), this, SLOT(quitPresentationMode())); + action->setShortcutContext(Qt::WidgetShortcut); + action->setShortcut(QKeySequence(Qt::Key_Escape)); + menu->addAction(action); + } + else + { + int count = 0; + const int currentScreen = QApplication::desktop()->screenNumber( + visualizationWidget); + foreach (QRect screenGeo, _screenGeometries) + { + Q_UNUSED(screenGeo); + QAction* action = new QAction( + QString("On screen %1").arg(count), menu); + connect(action, SIGNAL(triggered()), this, + SLOT(startPresentationMode())); + if (count == currentScreen) + action->setEnabled(false); + menu->addAction(action); + ++count; + } + } +} + +void MainWindow::startPresentationMode() +{ + // Save the QMainWindow state to restore when quitting presentation mode + _windowState = this->saveState(); + + // Get the screen number from the QAction which sent the signal + QString actionText = static_cast<QAction*> (QObject::sender())->text(); + int screen = actionText.split(" ").back().toInt(); + + // Move the widget to the screen and maximize it + // Real fullscreen hides the menu + _vtkWidget->setParent(NULL, Qt::Window); + _vtkWidget->move(QPoint(_screenGeometries[screen].x(), + _screenGeometries[screen].y())); + //_vtkWidget->showFullScreen(); + _vtkWidget->showMaximized(); + + // Create an action which quits the presentation mode when pressing + // ESCAPE when the the window has focus + QAction* action = new QAction("Quit presentation mode", this); + connect(action, SIGNAL(triggered()), this, SLOT(quitPresentationMode())); + action->setShortcutContext(Qt::WidgetShortcut); + action->setShortcut(QKeySequence(Qt::Key_Escape)); + _vtkWidget->addAction(action); + + // Hide the central widget to maximize the dock widgets + QMainWindow::centralWidget()->hide(); +} + +void MainWindow::quitPresentationMode() +{ + // Remove the quit action + QAction* action = _vtkWidget->actions().back(); + _vtkWidget->removeAction(action); + delete action; + + // Add the widget back to visualization widget + visualizationWidget->layout()->addWidget(_vtkWidget); + + QMainWindow::centralWidget()->show(); + + // Restore the previously saved QMainWindow state + this->restoreState(_windowState); +} + +QString MainWindow::getLastUsedDir() +{ + QSettings settings("UFZ", "OpenGeoSys-5"); + QString fileName(""); + QStringList files = settings.value("recentFileList").toStringList(); + if (files.size() != 0) + return QFileInfo(files[0]).absolutePath(); + else + return QDir::homePath(); +} + diff --git a/Gui/mainwindow.h b/Gui/mainwindow.h new file mode 100644 index 0000000000000000000000000000000000000000..6da7ce35f6734a935df5bbb90105757d7a19480f --- /dev/null +++ b/Gui/mainwindow.h @@ -0,0 +1,164 @@ +/** + * \file mainwindow.h + * 4/11/2009 LB Initial implementation + * + */ + +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "FileFinder.h" +#include "ProjectData.h" +#include "ui_mainwindow.h" + +class GEOModels; +class MshModel; +class ElementTreeModel; +class StationTreeModel; +class ProcessModel; +class VtkVisPipeline; +class DatabaseConnection; +class VisPrefsDialog; + +#ifdef OGS_USE_VRPN +class TrackingSettingsWidget; +#endif // OGS_USE_VRPN + +/** + * Main program window for the graphical user interface of OpenGeoSys. + */ +class MainWindow : public QMainWindow, public Ui_MainWindowClass +{ + Q_OBJECT + +public: + MainWindow(QWidget* parent = 0); + ~MainWindow(); + + void ShowWindow(); + void HideWindow(); + +protected: + void closeEvent( QCloseEvent* event ); + +protected slots: + void showGeoDockWidget( bool show ); + void showStationDockWidget( bool show ); + void showMshDockWidget( bool show ); + void showConditionDockWidget( bool show ); + void showVisDockWidget( bool show ); + + /// Function calls for opening files. + void open(); + /// Function calls for saving files. + void save(); + /// Function calls for generating GMSH files from the GUI + void callGMSH(std::vector<std::string> & selectedGeometries, + size_t param1, + double param2, + double param3, + double param4, + bool delete_geo_file); + /// Function calls for GMS export. + void exportBoreholesToGMS(std::string listName, std::string fileName); + /// Testing functionality for connection to FEM lib + void FEMTestStart(); + void importGMS(); + void importGoCad(); + void importRaster(); + void importRasterAsPoly(); +#ifdef Shapelib_FOUND + void importShape(); +#endif + void importPetrel(); + void importNetcdf(); //YW 07.2010 + void importVtk(); + void importFeflow(); + void importTetGen(); + void loadFEMConditions(std::string geoName); + void openDatabase(); + void openDatabaseConnection(); + void openRecentFile(); + void about(); + void showAddPipelineFilterItemDialog(QModelIndex parentIndex); + void showConditionWriterDialog(); + /// Call dialog for creating or modifying FEM conditions. + void showCondSetupDialog(const std::string &geometry_name, const GEOLIB::GEOTYPE object_type, size_t id, bool on_points = false); + /// Allows setting the name for a geometric object + void showGeoNameDialog(const std::string &geometry_name, const GEOLIB::GEOTYPE object_type, size_t id); + /// Calls the diagram prefs dialog from the Tools menu. + void showDiagramPrefsDialog(); + /// Calls the diagram prefs dialog from the station list (i.e. for a specific station). + void showDiagramPrefsDialog(QModelIndex &index); + void showFileConverterDialog(); + void showLineEditDialog(const std::string &geoName); + void showGMSHPrefsDialog(); + void showMshQualitySelectionDialog(VtkMeshSource* mshSource); + void showNewProcessDialog(); + void showPropertiesDialog(std::string const& name); + void showVisalizationPrefsDialog(); + void showTrackingSettingsDialog(); + void updateDataViews(); + void addFEMConditions(const std::vector<FEMCondition*> conditions); + void writeFEMConditionsToFile(const QString &geoName, const FEMCondition::CondType type, const QString &fileName); + void writeGeometryToFile(QString listName, QString fileName); + void writeStationListToFile(QString listName, QString fileName); + + void on_actionExportVTK_triggered(bool checked = false); + void on_actionExportVRML2_triggered(bool checked = false); + void on_actionExportObj_triggered(bool checked = false); + void on_actionExportOpenSG_triggered(bool checked = false); + + void createPresentationMenu(); + void startPresentationMode(); + void quitPresentationMode(); + + void loadDIRECTSourceTermsFromASCII(const std::string name, const std::vector<GEOLIB::Point*>* points); //TODO put this in a better place + +private: + QMenu* createImportFilesMenu(); + void loadFile(const QString &fileName); + void loadFEMConditionsFromFile(const QString &fileName, std::string geoName = ""); + void loadPetrelFiles(const QStringList &sfc_file_names, + const QStringList &well_path_file_names); + + void readSettings(); + void writeSettings(); + QString getLastUsedDir(); + + QString curFile; + + DatabaseConnection* _db; + FileFinder _fileFinder; + GEOModels* _geoModels; + MshModel* _meshModels; + ElementTreeModel* _elementModel; + ProcessModel* _processModel; + ProjectData _project; + VtkVisPipeline* _vtkVisPipeline; + QList<QRect> _screenGeometries; + QWidget* _vtkWidget; + QByteArray _windowState; + QMenu* _import_files_menu; + +#ifdef OGS_USE_VRPN + TrackingSettingsWidget* _trackingSettingsWidget; +#endif // OGS_USE_VRPN + VisPrefsDialog* _visPrefsDialog; + +signals: + void fileUsed( QString filename ); +}; + +class StartQt4 +{ +public: + StartQt4() + { + int i = 0; + QApplication* qapp = new QApplication(i, NULL); + qapp->exec(); + } +}; + +#endif // MAINWINDOW_H diff --git a/Gui/mainwindow.ui b/Gui/mainwindow.ui new file mode 100644 index 0000000000000000000000000000000000000000..375d7f501435f867067bd03b14811458390a8845 --- /dev/null +++ b/Gui/mainwindow.ui @@ -0,0 +1,651 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>MainWindowClass</class> + <widget class="QMainWindow" name="MainWindowClass"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>801</width> + <height>745</height> + </rect> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>500</width> + <height>200</height> + </size> + </property> + <property name="windowTitle"> + <string>OpenGeoSys Data Explorer</string> + </property> + <property name="dockOptions"> + <set>QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks</set> + </property> + <widget class="QWidget" name="centralWidget"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>200</width> + <height>100</height> + </size> + </property> + <property name="autoFillBackground"> + <bool>false</bool> + </property> + <layout class="QGridLayout" name="gridLayout"> + <property name="leftMargin"> + <number>6</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>6</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + <item row="0" column="0"> + <widget class="VisualizationWidget" name="visualizationWidget" native="true"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>250</width> + <height>100</height> + </size> + </property> + </widget> + </item> + </layout> + </widget> + <widget class="QMenuBar" name="menuBar"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>801</width> + <height>21</height> + </rect> + </property> + <widget class="QMenu" name="menu_File"> + <property name="title"> + <string>&File</string> + </property> + <widget class="QMenu" name="menuExport"> + <property name="toolTip"> + <string>Exports the entire scene to a 3d-format for visualization.</string> + </property> + <property name="title"> + <string>Export</string> + </property> + <addaction name="actionExportVRML2"/> + <addaction name="actionExportVTK"/> + <addaction name="actionExportObj"/> + <addaction name="actionExportOpenSG"/> + </widget> + <addaction name="action_Open"/> + <addaction name="action_Database"/> + <addaction name="actionSave_As"/> + <addaction name="separator"/> + <addaction name="menuExport"/> + <addaction name="separator"/> + <addaction name="separator"/> + <addaction name="action_Exit"/> + </widget> + <widget class="QMenu" name="menuWindows"> + <property name="title"> + <string>Windows</string> + </property> + </widget> + <widget class="QMenu" name="menuSettings"> + <property name="title"> + <string>Settings</string> + </property> + <addaction name="action_DatabaseConnection"/> + <addaction name="action_VisualisationSettings"/> + <addaction name="action_TrackingSettings"/> + </widget> + <widget class="QMenu" name="menuTools"> + <property name="title"> + <string>Tools</string> + </property> + <addaction name="actionMesh_Generation"/> + <addaction name="actionFile_Converter"/> + <addaction name="actionDiagram_Viewer"/> + <addaction name="actionFEM_Test"/> + </widget> + <widget class="QMenu" name="menuHelp"> + <property name="title"> + <string>Help</string> + </property> + <addaction name="actionAbout"/> + </widget> + <addaction name="menu_File"/> + <addaction name="menuTools"/> + <addaction name="menuWindows"/> + <addaction name="menuSettings"/> + <addaction name="menuHelp"/> + </widget> + <widget class="QToolBar" name="mainToolBar"> + <attribute name="toolBarArea"> + <enum>TopToolBarArea</enum> + </attribute> + <attribute name="toolBarBreak"> + <bool>false</bool> + </attribute> + </widget> + <widget class="QStatusBar" name="statusBar"/> + <widget class="QDockWidget" name="mshDock"> + <property name="windowTitle"> + <string>Meshes</string> + </property> + <attribute name="dockWidgetArea"> + <number>1</number> + </attribute> + <widget class="QWidget" name="dockWidgetContents_2"> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <property name="margin"> + <number>1</number> + </property> + <item> + <widget class="MshTabWidget" name="mshTabWidget" native="true"/> + </item> + </layout> + </widget> + </widget> + <widget class="QDockWidget" name="stationDock"> + <property name="windowTitle"> + <string>Stations</string> + </property> + <attribute name="dockWidgetArea"> + <number>1</number> + </attribute> + <widget class="QWidget" name="dockWidgetContents_3"> + <layout class="QVBoxLayout" name="verticalLayout_3"> + <property name="margin"> + <number>1</number> + </property> + <item> + <widget class="StationTabWidget" name="stationTabWidget" native="true"/> + </item> + </layout> + </widget> + </widget> + <widget class="QDockWidget" name="vtkVisDock"> + <property name="windowTitle"> + <string>Visualization Pipeline</string> + </property> + <attribute name="dockWidgetArea"> + <number>2</number> + </attribute> + <widget class="QWidget" name="dockWidgetContents_7"> + <layout class="QVBoxLayout" name="verticalLayout_6"> + <property name="margin"> + <number>1</number> + </property> + <item> + <widget class="VtkVisTabWidget" name="vtkVisTabWidget" native="true"/> + </item> + </layout> + </widget> + </widget> + <widget class="QDockWidget" name="modellingDock"> + <property name="windowTitle"> + <string>Modelling</string> + </property> + <attribute name="dockWidgetArea"> + <number>1</number> + </attribute> + <widget class="QWidget" name="dockWidgetContents"> + <layout class="QVBoxLayout" name="verticalLayout_7"> + <property name="margin"> + <number>1</number> + </property> + <item> + <widget class="ModellingTabWidget" name="modellingTabWidget" native="true"/> + </item> + </layout> + </widget> + </widget> + <widget class="QDockWidget" name="geoDock"> + <property name="windowTitle"> + <string>Geometry</string> + </property> + <attribute name="dockWidgetArea"> + <number>1</number> + </attribute> + <widget class="QWidget" name="dockWidgetContents_5"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="GeoTabWidget" name="geoTabWidget" native="true"> + <property name="enabled"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </widget> + </widget> + <action name="action_Open"> + <property name="text"> + <string>&Open...</string> + </property> + <property name="toolTip"> + <string>Loads a OGS-native file. E.g. gli, gsp, gml, msh, stn.</string> + </property> + </action> + <action name="action_Exit"> + <property name="text"> + <string>&Exit</string> + </property> + <property name="toolTip"> + <string>Exits the application.</string> + </property> + </action> + <action name="actionPoints_view"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="text"> + <string>Points view</string> + </property> + </action> + <action name="actionLines_view"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="text"> + <string>Lines view</string> + </property> + </action> + <action name="actionStations_view"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="text"> + <string>Stations view</string> + </property> + </action> + <action name="actionMeshes_view"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>true</bool> + </property> + <property name="text"> + <string>Meshes view</string> + </property> + </action> + <action name="action_Database"> + <property name="text"> + <string>Database...</string> + </property> + <property name="toolTip"> + <string>Connects to a database.</string> + </property> + </action> + <action name="action_DatabaseConnection"> + <property name="text"> + <string>Database Settings...</string> + </property> + <property name="toolTip"> + <string>Sets the database settings.</string> + </property> + </action> + <action name="actionImport"> + <property name="text"> + <string>Import ...</string> + </property> + </action> + <action name="actionSave_As"> + <property name="text"> + <string>&Save As...</string> + </property> + </action> + <action name="actionExportVRML2"> + <property name="text"> + <string>VRML2</string> + </property> + <property name="toolTip"> + <string>Export as VRML2</string> + </property> + </action> + <action name="actionExportObj"> + <property name="text"> + <string>Wavefront OBJ</string> + </property> + </action> + <action name="action_VisualisationSettings"> + <property name="text"> + <string>Visualisation Settings...</string> + </property> + <property name="toolTip"> + <string>Sets settings regarding the 3d view. E.g. Background color, illumantion.</string> + </property> + </action> + <action name="actionExportVTK"> + <property name="text"> + <string>VTK</string> + </property> + </action> + <action name="actionExportOpenSG"> + <property name="text"> + <string>OpenSG</string> + </property> + <property name="toolTip"> + <string>Export to OpenSG binary format</string> + </property> + </action> + <action name="action_TrackingSettings"> + <property name="text"> + <string>Tracking Settings...</string> + </property> + <property name="toolTip"> + <string>Sets settings for head-tracking.</string> + </property> + </action> + <action name="actionMesh_Generation"> + <property name="text"> + <string>Mesh Generation...</string> + </property> + <property name="toolTip"> + <string>Generates a mesh from a geometry.</string> + </property> + </action> + <action name="actionFEM_Test"> + <property name="text"> + <string>FEM Test</string> + </property> + </action> + <action name="actionDiagram_Viewer"> + <property name="text"> + <string>Diagram Viewer...</string> + </property> + </action> + <action name="actionAbout"> + <property name="text"> + <string>About</string> + </property> + </action> + <action name="actionFile_Converter"> + <property name="text"> + <string>File Converter...</string> + </property> + </action> + </widget> + <layoutdefault spacing="6" margin="11"/> + <customwidgets> + <customwidget> + <class>VisualizationWidget</class> + <extends>QWidget</extends> + <header>VisualizationWidget.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>StationTabWidget</class> + <extends>QWidget</extends> + <header>StationTabWidget.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>MshTabWidget</class> + <extends>QWidget</extends> + <header>MshTabWidget.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>VtkVisTabWidget</class> + <extends>QWidget</extends> + <header>VtkVisTabWidget.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>GeoTabWidget</class> + <extends>QWidget</extends> + <header>GeoTabWidget.h</header> + <container>1</container> + </customwidget> + <customwidget> + <class>ModellingTabWidget</class> + <extends>QWidget</extends> + <header location="global">ModellingTabWidget.h</header> + <container>1</container> + </customwidget> + </customwidgets> + <resources/> + <connections> + <connection> + <sender>action_Open</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>open()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>369</x> + <y>223</y> + </hint> + </hints> + </connection> + <connection> + <sender>action_Exit</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>close()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>369</x> + <y>223</y> + </hint> + </hints> + </connection> + <connection> + <sender>action_Database</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>openDatabase()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>399</x> + <y>299</y> + </hint> + </hints> + </connection> + <connection> + <sender>action_DatabaseConnection</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>openDatabaseConnection()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>399</x> + <y>299</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionSave_As</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>save()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>399</x> + <y>299</y> + </hint> + </hints> + </connection> + <connection> + <sender>action_VisualisationSettings</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>showVisalizationPrefsDialog()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>399</x> + <y>300</y> + </hint> + </hints> + </connection> + <connection> + <sender>action_TrackingSettings</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>showTrackingSettingsDialog()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>399</x> + <y>300</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionMesh_Generation</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>showGMSHPrefsDialog()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>407</x> + <y>403</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionFEM_Test</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>FEMTestStart()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>407</x> + <y>403</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionDiagram_Viewer</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>showDiagramPrefsDialog()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>400</x> + <y>372</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionAbout</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>about()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>400</x> + <y>372</y> + </hint> + </hints> + </connection> + <connection> + <sender>actionFile_Converter</sender> + <signal>triggered()</signal> + <receiver>MainWindowClass</receiver> + <slot>showFileConverterDialog()</slot> + <hints> + <hint type="sourcelabel"> + <x>-1</x> + <y>-1</y> + </hint> + <hint type="destinationlabel"> + <x>400</x> + <y>372</y> + </hint> + </hints> + </connection> + </connections> + <slots> + <slot>open()</slot> + <slot>openDatabase()</slot> + <slot>openDatabaseConnection()</slot> + <slot>import()</slot> + <slot>save()</slot> + <slot>showVisalizationPrefsDialog()</slot> + <slot>showTrackingSettingsDialog()</slot> + <slot>showGMSHPrefsDialog()</slot> + <slot>FEMTestStart()</slot> + <slot>showDiagramPrefsDialog()</slot> + <slot>about()</slot> + <slot>showFileConverterDialog()</slot> + </slots> +</ui>