16.12.2021, 9:00 - 11:00: Due to updates GitLab may be unavailable for some minutes between 09:00 and 11:00.

Commit 6a38ca99 authored by Christian Schulte zu Berge's avatar Christian Schulte zu Berge
Browse files

Merge branch 'development' into 'master'

Development

See merge request !111
parents 3a127e47 75aa45ba
......@@ -235,14 +235,8 @@ namespace campvis {
_mainWindow->deinit();
QuadRenderer::deinit();
// deinit OpenGL and cgt
cgt::deinitGL();
}
// MainWindow dtor needs a valid CampVisApplication, so we need to call it here instead of during destruction.
delete _mainWindow;
// now delete everything in the right order:
for (std::vector<PipelineRecord>::iterator it = _pipelines.begin(); it != _pipelines.end(); ++it) {
delete it->_painter;
......@@ -252,6 +246,12 @@ namespace campvis {
delete *it;
}
{
// Deinit everything OpenGL using the local context.
cgt::GLContextScopedLock lock(_localContext);
cgt::deinitGL();
}
GLJobProc.stop();
OpenGLJobProcessor::deinit();
SimpleJobProcessor::deinit();
......
......@@ -24,6 +24,8 @@
#include "datacontainerfileloaderwidget.h"
#include <QScrollBar>
namespace campvis {
const std::string DataContainerFileLoaderWidget::loggerCat_ = "CAMPVis.application.DataContainerFileLoaderWidget";
......@@ -36,21 +38,20 @@ namespace campvis {
, _fileName("fileName", "Image URL", "")
, _propCollectionWidget(0)
{
this->_parent = parentDataInspector;
this->_dataContainer = this->_parent->getDataContainer();
this->_imgReader = new GenericImageReader();
this->_imgReader->setVisibibility(".mhd", true);
_parent = parentDataInspector;
_dataContainer = _parent->getDataContainer();
_imgReader = new GenericImageReader();
setupGUI();
}
DataContainerFileLoaderWidget::~DataContainerFileLoaderWidget() {
if (this->_dataContainer != 0) {
this->_dataContainer->s_dataAdded.disconnect(this);
if (_dataContainer != 0) {
_dataContainer->s_dataAdded.disconnect(this);
}
}
void DataContainerFileLoaderWidget::setDataContainer(DataContainer* dataContainer) {
this->_dataContainer = dataContainer;
_dataContainer = dataContainer;
}
QSize DataContainerFileLoaderWidget::sizeHint() const {
......@@ -61,33 +62,39 @@ namespace campvis {
void DataContainerFileLoaderWidget::setupGUI() {
setWindowTitle(tr("Browse File"));
this->_layout = new QGridLayout();
this->_layout->setSpacing(2);
_layout = new QGridLayout();
_layout->setSpacing(2);
setLayout(_layout);
this->_pipelinePropertiesScrollArea = new QScrollArea(this);
this->_pipelinePropertiesScrollArea->setWidgetResizable(true);
this->_pipelinePropertiesScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
this->_pipelinePropertiesScrollArea->setFrameStyle(QScrollArea::NoFrame);
_pipelinePropertiesScrollArea = new QScrollArea(this);
_pipelinePropertiesScrollArea->setWidgetResizable(true);
_pipelinePropertiesScrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
_pipelinePropertiesScrollArea->setFrameStyle(QScrollArea::NoFrame);
this->installEventFilter(this);
this->_propCollectionWidget = new PropertyCollectionWidget(this->_pipelinePropertiesScrollArea);
this->_layout->addWidget(this->_propCollectionWidget, 0, 0, 1, 2);
this->_propCollectionWidget->updatePropCollection(this->_imgReader, this->_dataContainer);
_propCollectionWidget = new PropertyCollectionWidget(_pipelinePropertiesScrollArea);
_propCollectionWidget->installEventFilter(this);
_pipelinePropertiesScrollArea->setWidget(_propCollectionWidget);
_propCollectionWidget->updatePropCollection(_imgReader, _dataContainer);
_layout->addWidget(_pipelinePropertiesScrollArea, 0, 0, 1, 2);
this->_btnLoadFile = new QPushButton(tr("Load"), this);
this->_layout->addWidget(this->_btnLoadFile, 1, 0, 1, 1);
this->_btnCancel = new QPushButton(tr("Cancel"), this);
this->_layout->addWidget(this->_btnCancel, 1, 1, 1, 1);
_btnLoadFile = new QPushButton(tr("Load"), this);
_layout->addWidget(_btnLoadFile, 1, 0, 1, 1);
_btnCancel = new QPushButton(tr("Cancel"), this);
_layout->addWidget(_btnCancel, 1, 1, 1, 1);
qRegisterMetaType<QtDataHandle>("QtDataHandle");
connect(
this->_btnCancel, SIGNAL(clicked()),
this, SLOT(onBtnCancelClicked()));
connect(
this->_btnLoadFile, SIGNAL(clicked()),
this, SLOT(onBtnLoadFileClicked()));
connect(_btnCancel, SIGNAL(clicked()), this, SLOT(onBtnCancelClicked()));
connect( _btnLoadFile, SIGNAL(clicked()), this, SLOT(onBtnLoadFileClicked()));
}
bool DataContainerFileLoaderWidget::eventFilter(QObject* watched, QEvent* event) {
if (watched == _propCollectionWidget && event->type() == QEvent::Resize) {
_pipelinePropertiesScrollArea->setMinimumWidth(_propCollectionWidget->minimumSizeHint().width() +
_pipelinePropertiesScrollArea->verticalScrollBar()->width());
}
return false;
}
void DataContainerFileLoaderWidget::init() {
......@@ -95,19 +102,19 @@ namespace campvis {
void DataContainerFileLoaderWidget::deinit() {
delete _imgReader;
this->_imgReader = nullptr;
_imgReader = nullptr;
}
void DataContainerFileLoaderWidget::onBtnCancelClicked() {
delete _imgReader;
this->_imgReader = nullptr;
this->close();
_imgReader = nullptr;
close();
}
void DataContainerFileLoaderWidget::onBtnLoadFileClicked() {
this->_imgReader->process(*_dataContainer);
this->_parent->setDataContainer(_dataContainer);
this->close();
_imgReader->process(*_dataContainer);
_parent->setDataContainer(_dataContainer);
close();
}
}
......@@ -94,6 +94,14 @@ namespace campvis {
*/
void setupGUI();
/**
* Listens to resize events on _pipelinePropertiesWidget and resizes _pipelinePropertiesScrollArea accordingly
* \param watched the object that caused the event
* \param event the event to be filtered
*/
bool eventFilter(QObject* watched, QEvent* event);
protected:
DataContainer* _dataContainer; ///< The DataContainer this widget is inspecting
......
......@@ -199,8 +199,8 @@ namespace campvis {
// compute transformation matrices
float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y);
float sliceRatio = (static_cast<float>(id->getSize().x) * id->getMappingInformation().getVoxelSize().x)
/ (static_cast<float>(id->getSize().y) * id->getMappingInformation().getVoxelSize().y);
float sliceRatio = (static_cast<float>(id->getSize().x) * std::abs(id->getMappingInformation().getVoxelSize().x))
/ (static_cast<float>(id->getSize().y) * std::abs(id->getMappingInformation().getVoxelSize().y));
float ratioRatio = sliceRatio / renderTargetRatio;
cgt::mat4 viewMatrix = (ratioRatio > 1) ? cgt::mat4::createScale(cgt::vec3(1.f, 1.f / ratioRatio, 1.f)) : cgt::mat4::createScale(cgt::vec3(ratioRatio, 1.f, 1.f));
......@@ -245,7 +245,7 @@ namespace campvis {
}
_paintShader->setIgnoreUniformLocationError(false);
_quad->render(GL_POLYGON);
_quad->render(GL_TRIANGLE_FAN);
LGL_ERROR;
}
......@@ -291,8 +291,8 @@ namespace campvis {
// compute transformation matrices
float renderTargetRatio = static_cast<float>(_quadSize.x) / static_cast<float>(_quadSize.y);
float sliceRatio = (static_cast<float>(id->getSize().x) * id->getMappingInformation().getVoxelSize().x)
/ (static_cast<float>(id->getSize().y) * id->getMappingInformation().getVoxelSize().y);
float sliceRatio = (static_cast<float>(id->getSize().x) * std::abs(id->getMappingInformation().getVoxelSize().x))
/ (static_cast<float>(id->getSize().y) * std::abs(id->getMappingInformation().getVoxelSize().y));
float ratioRatio = sliceRatio / renderTargetRatio;
lookupTexelFloat /= (ratioRatio > 1) ? cgt::vec2(1.f, 1.f / ratioRatio) : cgt::vec2(ratioRatio, 1.f);
......
......@@ -322,7 +322,7 @@ namespace campvis {
std::string pipeScript = "pipeline = pipelines[\"" + _selectedPipeline->getName()+"\"]\n\n";
for (size_t i = 0; i < _selectedPipeline->getProcessors().size(); i++) {
pipeScript += "proc = pipeline:getProcessor(" + StringUtils::toString(i) + ")\n";
AbstractProcessor* proc = _selectedPipeline->getProcessor(i);
AbstractProcessor* proc = _selectedPipeline->getProcessor(int(i));
_pcLua->updatePropCollection(proc, &_selectedPipeline->getDataContainer());
std::string res = _pcLua->getLuaScript(std::string(""), std::string("proc:"));
......
......@@ -28,6 +28,7 @@
#include <QComboBox>
#include <QLineEdit>
#include <QSortFilterProxyModel>
namespace campvis {
DataNamePropertyWidget::DataNamePropertyWidget(DataNameProperty* property, DataContainer* dc, QWidget* parent /*= 0*/)
......@@ -39,6 +40,11 @@ namespace campvis {
_combobox = new QComboBox(this);
_combobox->setEditable(true);
QSortFilterProxyModel* proxy = new QSortFilterProxyModel(_combobox);
proxy->setSourceModel(_combobox->model());
_combobox->model()->setParent(proxy); // combo's current model must be reparented, otherwise QComboBox::setModel() will delete it
_combobox->setModel(proxy);
if (dc != 0) {
std::vector< std::pair<std::string, DataHandle> > tmp = dc->getDataHandlesCopy();
QStringList sl;
......@@ -48,6 +54,7 @@ namespace campvis {
dc->s_dataAdded.connect(this, &DataNamePropertyWidget::onDataAdded);
connect(this, SIGNAL(s_dataAddedQt(const QString&, QtDataHandle)), this, SLOT(onDataAddedQt(const QString&, QtDataHandle)));
_combobox->model()->sort(Qt::AscendingOrder);
setCurrentComboBoxText(QString::fromStdString(property->getValue()));
}
......@@ -106,6 +113,7 @@ namespace campvis {
void DataNamePropertyWidget::onDataAddedQt(const QString& key, QtDataHandle dh) {
if (_combobox->findText(key) == -1) {
_combobox->addItem(key);
_combobox->model()->sort(Qt::AscendingOrder);
}
}
......
......@@ -71,7 +71,7 @@ namespace campvis {
_layout->setSpacing(8);
_layout->setMargin(0);
setLayout(_layout);
connect(this, SIGNAL(s_widgetVisibilityChanged(QWidget*, bool)), this, SLOT(onWidgetVisibilityChanged(QWidget*, bool)));
connect(this, SIGNAL(s_propertyVisibilityChanged(const AbstractProperty*)), this, SLOT(onWidgetVisibilityChanged(const AbstractProperty*)), Qt::QueuedConnection);
connect(this, SIGNAL(propertyAdded(AbstractProperty*)), this, SLOT(addProperty(AbstractProperty*)));
connect(this, SIGNAL(propertyRemoved(AbstractProperty*, QWidget*)), this, SLOT(removeProperty(AbstractProperty*, QWidget*)));
}
......@@ -91,14 +91,18 @@ namespace campvis {
}
void PropertyCollectionWidget::onPropertyVisibilityChanged(const AbstractProperty* prop) {
// This method is not always called on the main thread, so it is not safe to check anything here.
// The event is instead forwarded using the QT sigslot mechanism through a queued connection to the
// main thread.
emit s_propertyVisibilityChanged(prop);
}
void PropertyCollectionWidget::onWidgetVisibilityChanged(const AbstractProperty* prop) {
// const_cast does not harm anything.
std::map<AbstractProperty*, QWidget*>::iterator item = _widgetMap.find(const_cast<AbstractProperty*>(prop));
if (item != _widgetMap.end())
emit s_widgetVisibilityChanged(item->second, item->first->isVisible());
}
void PropertyCollectionWidget::onWidgetVisibilityChanged(QWidget* widget, bool visibility) {
widget->setVisible(visibility);
item->second->setVisible(item->first->isVisible());
}
void PropertyCollectionWidget::onPropCollectionPropAdded(AbstractProperty* prop) {
......
......@@ -72,7 +72,7 @@ namespace campvis {
/**
* Gets called when the property has changed, so that widget can update its state.
*/
virtual void onWidgetVisibilityChanged(QWidget* widget, bool visibility);
virtual void onWidgetVisibilityChanged(const AbstractProperty* prop);
/**
* Creates the property widget for \a prop, connects all neccesary signals, etc.
......@@ -87,7 +87,7 @@ namespace campvis {
void removeProperty(AbstractProperty* prop, QWidget* widget);
signals:
void s_widgetVisibilityChanged(QWidget* widget, bool visibility);
void s_propertyVisibilityChanged(const AbstractProperty* prop);
void propertyAdded(AbstractProperty* prop);
void propertyRemoved(AbstractProperty* prop, QWidget* widget);
......
......@@ -90,6 +90,13 @@ namespace campvis {
*/
virtual size_t getDimensionality() const = 0;
/**
* Returns the intensity domain where this TF has it's non-transparent parts.
* I.e. the minimum and the maximum intensity being opaque.
* \return The intensity domain where this TF has it's non-transparent parts.
*/
virtual cgt::vec2 getVisibilityDomain() const = 0;
/**
* Binds the transfer function OpenGL texture to the given texture and sets up uniforms.
* \note Calling thread must have a valid OpenGL context.
......
......@@ -59,6 +59,13 @@ namespace campvis {
* Destructor, make sure to delete the OpenGL texture beforehand by calling deinit() with a valid OpenGL context!
*/
virtual ~GenericGeometryTransferFunction();
/**
* Returns the intensity domain where this TF has it's non-transparent parts.
* I.e. the minimum and the maximum intensity being opaque.
* \return cgt::vec2(0.f, 1.f)
*/
virtual cgt::vec2 getVisibilityDomain() const;
/**
* Initializes the Shader, hence, this methods has to be called from a thread with a valid OpenGL context!
......@@ -128,6 +135,20 @@ namespace campvis {
campvis::GenericGeometryTransferFunction<T>::~GenericGeometryTransferFunction() {
}
template<class T>
cgt::vec2 campvis::GenericGeometryTransferFunction<T>::getVisibilityDomain() const {
if (_geometries.empty())
return cgt::vec2(-1.f, -1.f);
else {
cgt::vec2 minmax(1.f, 0.f);
for (size_t i = 0; i < _geometries.size(); ++i) {
minmax.x = std::min(minmax.x, _geometries[i]->getIntensityDomain().x);
minmax.y = std::max(minmax.y, _geometries[i]->getIntensityDomain().y);
}
return minmax;
}
}
template<class T>
void campvis::GenericGeometryTransferFunction<T>::initShader() {
_shader = ShdrMgr.load("core/glsl/passthrough.vert", "core/glsl/passthrough.frag", "");
......
......@@ -103,5 +103,9 @@ namespace campvis {
return _rightColor;
}
cgt::vec2 SimpleTransferFunction::getVisibilityDomain() const {
return cgt::vec2(0.f, 1.f);
}
}
\ No newline at end of file
......@@ -58,6 +58,13 @@ namespace campvis {
*/
virtual size_t getDimensionality() const;
/**
* Returns the intensity domain where this TF has it's non-transparent parts.
* I.e. the minimum and the maximum intensity being opaque.
* \return cgt::vec2(0.f, 1.f)
*/
virtual cgt::vec2 getVisibilityDomain() const;
const cgt::col4& getLeftColor() const;
void setLeftColor(const cgt::col4& color);
const cgt::col4& getRightColor() const;
......
......@@ -157,4 +157,8 @@ namespace campvis {
_keyPoints.insert(lb, kp);
}
cgt::vec2 TFGeometry1D::getIntensityDomain() const {
return cgt::vec2(_keyPoints.front()._position, _keyPoints.back()._position);
}
}
\ No newline at end of file
......@@ -110,6 +110,11 @@ namespace campvis {
*/
void addKeyPoint(float position, const cgt::col4& color);
/**
* Returns the intensity domain of this TFGeometry1D.
*/
cgt::vec2 getIntensityDomain() const;
/**
* Creates a simple quad geometry for the given interval.
* A quad geometry consists of two KeyPoints.
......
......@@ -129,6 +129,10 @@ namespace campvis {
std::sort(_keyPoints.begin(), _keyPoints.end(), KeyPointSorter(_center._position));
}
cgt::vec2 TFGeometry2D::getIntensityDomain() const {
return cgt::vec2(_keyPoints.front()._position.x, _keyPoints.back()._position.x);
}
}
\ No newline at end of file
......@@ -75,6 +75,11 @@ namespace campvis {
* \return
*/
std::vector<KeyPoint>& getKeyPoints();
/**
* Returns the intensity domain of this TFGeometry1D.
*/
cgt::vec2 getIntensityDomain() const;
/**
* Renders this transfer function geometry to the current active OpenGL context.
......
......@@ -84,7 +84,7 @@ namespace campvis {
* Renders this GeometryData.
* Must be called from a valid OpenGL context.
*/
virtual void render(GLenum mode = GL_POLYGON) const = 0;
virtual void render(GLenum mode = GL_TRIANGLE_FAN) const = 0;
/**
* Returns the geometry extent in world coordinates.
......
......@@ -95,7 +95,7 @@ namespace campvis {
* Renders this GeometryDataCollection.
* Must be called from a valid OpenGL context.
*/
virtual void render(GLenum mode = GL_POLYGON) const;
virtual void render(GLenum mode = GL_TRIANGLE_FAN) const;
/**
* Returns the geometry extent in world coordinates.
......
......@@ -160,7 +160,7 @@ namespace campvis {
return toReturn;
}
MultiIndexedGeometry* GeometryDataFactory::createSphere(uint16_t numStacks /*= 6*/, uint16_t numSlices /*= 12*/) {
MultiIndexedGeometry* GeometryDataFactory::createSphere(uint16_t numStacks /*= 6*/, uint16_t numSlices /*= 12*/, const cgt::vec3& exponents /*= cgt::vec3(1.f)*/) {
cgtAssert(numStacks > 1 && numSlices > 2, "Sphere must have minimum 2 stacks and 3 slices!");
std::vector<cgt::vec3> vertices;
std::vector<cgt::vec3> textureCoordinates;
......@@ -175,7 +175,17 @@ namespace campvis {
for (int j = 0; j < numSlices; ++j) {
float theta = static_cast<float>(j) * 2.f*cgt::PIf / static_cast<float>(numSlices);
vertices.push_back(cgt::vec3(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi)));
// apply exponents for supersphere
cgt::vec3 theVertex(cos(theta) * sin(phi), sin(theta) * sin(phi), cos(phi));
for (size_t e = 0; e < 3; ++e) {
if (theVertex[e] < 0)
theVertex[e] = -pow(-theVertex[e], exponents[e]);
else
theVertex[e] = pow(theVertex[e], exponents[e]);
}
vertices.push_back(theVertex);
textureCoordinates.push_back(cgt::vec3(theta / (2.f * cgt::PIf), phi / cgt::PIf, 0.f));
}
}
......
......@@ -68,22 +68,23 @@ namespace campvis {
/**
* Creates an MultiIndexedGeometry storing a unit sphere around the origin.
* \param numStacks Number of stacks in the sphere
* \param numSlices Number of slices in the sphere
* \param numStacks Number of stacks in the sphere
* \param numSlices Number of slices in the sphere
* \param exponents Exponent for each dimension to define a supersphere (defines the roundness)
* \return MultiIndexedGeometry storing a unit sphere around the origin.
*/
static MultiIndexedGeometry* createSphere(uint16_t numStacks = 6, uint16_t numSlices = 12);
static MultiIndexedGeometry* createSphere(uint16_t numStacks = 6, uint16_t numSlices = 12, const cgt::vec3& exponents = cgt::vec3(1.f));
/**
* Creates an MultiIndexedGeometry storing a unit length arrow in Z direction starting from the origin.
* \param numSlices Number of slices in the cylinder and cone
* \param tipLen Length of arrow tip (between 0 and 1)
* \param tipLen Length of arrow tip (between 0 and 1)
* \param cylRadius Radius of the cylinder (arrow shaft)
* \param tipRadius Radius of the bottom of the arrow tip
* \param tipRadius Radius of the bottom of the arrow tip
* \return MultiIndexedGeometry storing a unit arrow in Z direction starting from the origin.
*/
static MultiIndexedGeometry* createArrow(uint16_t numSlices = 12, float tipLen = 0.35, float cylRadius = 0.05, float tipRadius = 0.15);
static MultiIndexedGeometry* createArrow(uint16_t numSlices = 12, float tipLen = 0.35, float cylRadius = 0.05, float tipRadius = 0.15);
};
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment