Starting from 2021-07-01, all LRZ GitLab users will be required to explicitly accept the GitLab Terms of Service. Please see the detailed information at https://doku.lrz.de/display/PUBLIC/GitLab and make sure that your projects conform to the requirements.

Commit bf230b50 authored by schultezub's avatar schultezub
Browse files

more work on GeometryTransferFunctionEditor

git-svn-id: https://camplinux.in.tum.de/svn/campvis/trunk@315 bb408c1c-ae56-11e1-83d9-df6b3e0c105e
parent aee478c6
......@@ -44,19 +44,24 @@
#include <QGridLayout>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
namespace TUMVis {
GeometryTransferFunctionEditor::GeometryTransferFunctionEditor(GeometryTransferFunction* tf, QWidget* parent /*= 0*/)
: AbstractTransferFunctionEditor(tf, parent)
, _selectedGeometry(0)
, _layout(0)
, _canvas(0)
, _lblIntensityLeft(0)
, _lblIntensityRight(0)
, _btnAddGeometry(0)
{
setupGUI();
tf->s_geometryCollectionChanged.connect(this, &GeometryTransferFunctionEditor::onGeometryCollectionChanged);
updateManipulators();
setEventTypes(tgt::Event::MOUSEPRESSEVENT);
}
GeometryTransferFunctionEditor::~GeometryTransferFunctionEditor() {
......@@ -80,6 +85,8 @@ namespace TUMVis {
// TODO: get rid of intermediate mode?
glPushAttrib(GL_ALL_ATTRIB_BITS);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glViewport(0, 0, _canvas->width(), _canvas->height());
glMatrixMode(GL_PROJECTION);
......@@ -106,8 +113,6 @@ namespace TUMVis {
float yl = static_cast<float>(ih->getNumElements(0)) / maxFilling;
float yr = 0.f;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_QUADS);
glColor4f(1.f, .75f, 0.f, .5f);
for (size_t i = 1; i < numBuckets; ++i) {
......@@ -123,7 +128,6 @@ namespace TUMVis {
yl = yr;
}
glEnd();
glDisable(GL_BLEND);
}
}
glPopMatrix();
......@@ -147,6 +151,30 @@ namespace TUMVis {
invalidate();
}
void GeometryTransferFunctionEditor::mousePressEvent(tgt::MouseEvent* e) {
if (_selectedGeometry != 0 && e->modifiers() & tgt::Event::CTRL) {
TFGeometry* g = _selectedGeometry->getGeometry();
std::vector<TFGeometry::KeyPoint>& kpts = g->getKeyPoints();
TFGeometry::KeyPoint kp(static_cast<float>(e->x()) / static_cast<float>(_canvas->width()), tgt::col4(255));
std::vector<TFGeometry::KeyPoint>::const_iterator lb = std::lower_bound(kpts.begin(), kpts.end(), kp);
if (lb != kpts.end()) {
kp._color = lb->_color;
}
else {
kp._color = kpts.back()._color;
}
float alpha = tgt::clamp(static_cast<float>(_canvas->height() - e->y()) / static_cast<float>(_canvas->height()), 0.f, 1.f);
kp._color.a = static_cast<uint8_t>(alpha * 255.f);
kpts.insert(lb, kp);
updateManipulators();
g->s_changed();
}
else {
_selectedGeometry = 0;
e->ignore();
}
}
void GeometryTransferFunctionEditor::invalidate() {
GLJobProc.enqueueJob(_canvas, new CallMemberFuncJob<GeometryTransferFunctionEditor>(this, &GeometryTransferFunctionEditor::paint), OpenGLJobProcessor::PaintJob);
}
......@@ -177,14 +205,28 @@ namespace TUMVis {
_lblIntensityRight = new QLabel(QString::number(gtf->getIntensityDomain().y), this);
_layout->addWidget(_lblIntensityRight, 4, 3, 1, 1, Qt::AlignRight);
QVBoxLayout* buttonLayout = new QVBoxLayout(); // TODO: check whether buttonLayout will be deleted by Qt's GC!
_layout->addLayout(buttonLayout, 1, 4, 1, 3, Qt::AlignTop);
_btnAddGeometry = new QPushButton(tr("Add Geometry"), this);
buttonLayout->addWidget(_btnAddGeometry);
connect(_btnAddGeometry, SIGNAL(clicked()), this, SLOT(onBtnAddGeometryClicked()));
_btnRemoveGeometry = new QPushButton(tr("Remove Geometry"), this);
buttonLayout->addWidget(_btnRemoveGeometry);
connect(_btnRemoveGeometry, SIGNAL(clicked()), this, SLOT(onBtnRemoveGeometryClicked()));
_layout->setColumnStretch(2, 1);
_layout->setRowStretch(2, 1);
}
void GeometryTransferFunctionEditor::updateManipulators() {
// clear and delete former stuff
_selectedGeometry = 0;
_canvas->getEventHandler()->clear();
for (std::vector<AbstractTFGeometryManipulator*>::iterator it = _manipulators.begin(); it != _manipulators.end(); ++it) {
if (WholeTFGeometryManipulator* tester = dynamic_cast<WholeTFGeometryManipulator*>(*it)) {
tester->s_selected.disconnect(this);
}
delete *it;
}
_manipulators.clear();
......@@ -193,21 +235,51 @@ namespace TUMVis {
const std::vector<TFGeometry*>& geometries = gtf->getGeometries();
for (std::vector<TFGeometry*>::const_iterator git = geometries.begin(); git != geometries.end(); ++git) {
// Add manipulator for the whole geometry and register it as event handler:
_manipulators.push_back(new WholeTFGeometryManipulator(_canvas->getSize(), gtf, *git));
_canvas->getEventHandler()->addListenerToBack(_manipulators.back());
WholeTFGeometryManipulator* wtf = new WholeTFGeometryManipulator(_canvas->getSize(), gtf, *git);
_manipulators.push_back(wtf);
_canvas->getEventHandler()->addListenerToFront(wtf);
wtf->s_selected.connect(this, &GeometryTransferFunctionEditor::onWholeTFGeometryManipulatorSelected);
// Add a manipulator for each KeyPoint and register it as event handler:
for (std::vector<TFGeometry::KeyPoint>::iterator kpit = (*git)->getKeyPoints().begin(); kpit != (*git)->getKeyPoints().end(); ++kpit) {
_manipulators.push_back(new KeyPointManipulator(_canvas->getSize(), gtf, *git, kpit));
_canvas->getEventHandler()->addListenerToBack(_manipulators.back());
_canvas->getEventHandler()->addListenerToFront(_manipulators.back());
}
}
_canvas->getEventHandler()->addListenerToFront(this);
}
void GeometryTransferFunctionEditor::onGeometryCollectionChanged() {
updateManipulators();
}
void GeometryTransferFunctionEditor::onWholeTFGeometryManipulatorSelected(WholeTFGeometryManipulator* wtf /* :) */) {
_selectedGeometry = wtf;
}
void GeometryTransferFunctionEditor::onBtnAddGeometryClicked() {
GeometryTransferFunction* gtf = static_cast<GeometryTransferFunction*>(_transferFunction);
gtf->addGeometry(TFGeometry::createQuad(tgt::vec2(.4f, .6f), tgt::col4(196), tgt::col4(196)));
}
void GeometryTransferFunctionEditor::onBtnRemoveGeometryClicked() {
if (_selectedGeometry != 0) {
GeometryTransferFunction* gtf = static_cast<GeometryTransferFunction*>(_transferFunction);
// to get the signal-slots disconnected in the correct order and avoid double deletion,
// this is getting a little messy and cumbersome:
TFGeometry* geometryToRemove = _selectedGeometry->getGeometry();
for (std::vector<AbstractTFGeometryManipulator*>::iterator it = _manipulators.begin(); it != _manipulators.end(); ++it) {
if (*it == _selectedGeometry) {
_manipulators.erase(it);
break;
}
}
delete _selectedGeometry;
_selectedGeometry = 0;
gtf->removeGeometry(geometryToRemove);
}
}
}
\ No newline at end of file
......@@ -36,6 +36,7 @@
class QGridLayout;
class QLabel;
class QPushButton;
namespace tgt {
class QtThreadedCanvas;
......@@ -46,11 +47,12 @@ namespace TUMVis {
class ColorPickerWidget;
class GeometryTransferFunction;
class AbstractTFGeometryManipulator;
class WholeTFGeometryManipulator;
/**
* Editor widget for a GeometryTransferFunction.
*/
class GeometryTransferFunctionEditor : public AbstractTransferFunctionEditor, public tgt::Painter {
class GeometryTransferFunctionEditor : public AbstractTransferFunctionEditor, public tgt::EventListener, public tgt::Painter {
Q_OBJECT;
public:
......@@ -75,13 +77,32 @@ namespace TUMVis {
/// \see tgt::Painter::sizeChanged
virtual void sizeChanged(const tgt::ivec2&);
/// \see tgt::EventListener::mousePressEvent
virtual void mousePressEvent(tgt::MouseEvent* e);
/**
* Slot to be called when the geometry vector of the transfer function has changed.
*/
void onGeometryCollectionChanged();
protected:
/**
* Slot tp be called when a WholeTFGeometryManipulator was selected.
* \param the selected WholeTFGeometryManipulator
*/
void onWholeTFGeometryManipulatorSelected(WholeTFGeometryManipulator* wtf /* :) */);
protected slots:
/**
* Slot to be called when _btnAddGeometry was clicked.
*/
void onBtnAddGeometryClicked();
/**
* Slot to be called when _btnRemoveGeometry was clicked.
*/
void onBtnRemoveGeometryClicked();
protected:
/**
* Gets called when the property has changed, so that widget can update its state.
*/
......@@ -104,12 +125,15 @@ namespace TUMVis {
void setupGUI();
std::vector<AbstractTFGeometryManipulator*> _manipulators;
WholeTFGeometryManipulator* _selectedGeometry;
QGridLayout* _layout;
tgt::QtThreadedCanvas* _canvas;
QLabel* _lblIntensityLeft;
QLabel* _lblIntensityRight;
QPushButton* _btnAddGeometry;
QPushButton* _btnRemoveGeometry;
};
}
......
......@@ -38,6 +38,7 @@
#include "core/tools/algorithmicgeometry.h"
#include <QColorDialog>
#include <algorithm>
namespace TUMVis {
......@@ -110,6 +111,7 @@ namespace TUMVis {
_keyPoint->_position = tfCoords.x;
_keyPoint->_color.a = static_cast<uint8_t>(tfCoords.y * 255.f);
std::sort(_geometry->getKeyPoints().begin(), _geometry->getKeyPoints().end());
_geometry->s_changed();
}
// ignore here, because other listeners probably need this signal as well
......@@ -133,14 +135,14 @@ namespace TUMVis {
}
}
const int KeyPointManipulator::MANIPULATOR_SIZE = 6;
const int KeyPointManipulator::MANIPULATOR_SIZE = 5;
// ================================================================================================
WholeTFGeometryManipulator::WholeTFGeometryManipulator(const tgt::ivec2& viewportSize, GeometryTransferFunction* tf, TFGeometry* geometry)
: AbstractTFGeometryManipulator(viewportSize, tf)
, _geometry(geometry)
, _mousePressed(false)
{
tgtAssert(geometry != 0, "Geometry must not be 0.");
_geometry->s_changed.connect(this, &WholeTFGeometryManipulator::onGeometryChanged);
......@@ -155,11 +157,16 @@ namespace TUMVis {
}
TFGeometry* WholeTFGeometryManipulator::getGeometry() const {
return _geometry;
}
void WholeTFGeometryManipulator::mousePressEvent(tgt::MouseEvent* e) {
_pressedPosition = viewportToTF(tgt::ivec2(e->coord().x, _viewportSize.y - e->coord().y));
if (insideGeometry(_pressedPosition)) {
_mousePressed = true;
_valuesWhenPressed = _geometry->getKeyPoints();
s_selected(this);
e->accept();
}
else {
......
......@@ -146,6 +146,12 @@ namespace TUMVis {
*/
virtual ~WholeTFGeometryManipulator();
/**
* Returns the Parent geometry of the KeyPoint to manipulate.
* \return _geometry
*/
TFGeometry* getGeometry() const;
/// \see AbstractTFGeometryManipulator::render
void render();
......@@ -163,6 +169,9 @@ namespace TUMVis {
*/
void onGeometryChanged();
/// Signal to be emitted when the mouse was pressed and has hit this manipulator
sigslot::signal1<WholeTFGeometryManipulator*> s_selected;
protected:
/**
* Checks whether \a position is within the geometry.
......@@ -176,8 +185,8 @@ namespace TUMVis {
*/
void updateHelperPoints();
TFGeometry* _geometry; ///< Parent geometry of the KeyPoint to manipulate
std::vector<tgt::vec2> _helperPoints;
TFGeometry* _geometry; ///< Parent geometry of the KeyPoint to manipulate
std::vector<tgt::vec2> _helperPoints; ///< vector chaching the 2D coordinates of the TF key points
// event handling stuff:
bool _mousePressed; ///< Flag whether the mouse button is currently pressed
......
......@@ -89,6 +89,23 @@ namespace TUMVis {
s_changed();
}
void GeometryTransferFunction::removeGeometry(TFGeometry* geometry) {
{
tbb::mutex::scoped_lock lock(_localMutex);
for (std::vector<TFGeometry*>::iterator it = _geometries.begin(); it != _geometries.end(); ++it) {
if (*it == geometry) {
_geometries.erase(it);
break;
}
}
}
geometry->s_changed.disconnect(this);
delete geometry;
_dirtyTexture = true;
s_geometryCollectionChanged();
s_changed();
}
void GeometryTransferFunction::onGeometryChanged() {
_dirtyTexture = true;
s_changed();
......
......@@ -73,6 +73,13 @@ namespace TUMVis {
*/
void addGeometry(TFGeometry* geometry);
/**
* Removes the given TF geometry from this transfer function.
* \note After the call \a geometry will no longer be valid as GeometryTransferFunction deletes the given TFGeometry.
* \param geometry TF geometry to remove, GeometryTransferFunction will delete it
*/
void removeGeometry(TFGeometry* geometry);
/**
* Slot to be called by TFGeometry's s_changed signal.
*/
......
......@@ -102,24 +102,23 @@ namespace TUMVis {
void TFGeometry::render() const {
// TODO: get rid of intermediade mode?
glBegin(GL_POLYGON);
if (_keyPoints.front()._color.w > 0) {
glColor3ubv(_keyPoints.front()._color.elem);
glVertex2f(_keyPoints.front()._position, 0.f);
}
for (std::vector<KeyPoint>::const_iterator it = _keyPoints.begin(); it != _keyPoints.end(); ++it) {
glColor3ubv(it->_color.elem);
float y = static_cast<float>(it->_color.a) / 255.f;
glVertex2f(it->_position, y);
}
if (_keyPoints.size() < 2)
return;
if (_keyPoints.back()._color.w > 0) {
glColor3ubv(_keyPoints.back()._color.elem);
glVertex2f(_keyPoints.back()._position, 0.f);
glBegin(GL_QUADS);
std::vector<KeyPoint>::const_iterator a = _keyPoints.begin();
std::vector<KeyPoint>::const_iterator b = _keyPoints.begin()+1;
for (/* already inited */; b != _keyPoints.end(); ++a, ++b) {
glColor4ubv(a->_color.elem);
float y = static_cast<float>(a->_color.a) / 255.f;
glVertex2f(a->_position, 0.f);
glVertex2f(a->_position, y);
glColor4ubv(b->_color.elem);
y = static_cast<float>(b->_color.a) / 255.f;
glVertex2f(b->_position, y);
glVertex2f(b->_position, 0.f);
}
glEnd();
}
......
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