From 7d47bd13af75b80cea8ef0d323aacdefae7eded7 Mon Sep 17 00:00:00 2001 From: James Hogan Date: Mon, 1 Dec 2008 02:44:59 +0000 Subject: [PATCH] Basic incomplete illuminant direction processing including shadow free chromaticities and illuminant discontinuity --- geo/CMakeLists.txt | 3 + geo/tcChannel.cpp | 6 + geo/tcChannel.h | 3 + geo/tcChannelConfigWidget.cpp | 16 + geo/tcChannelConfigWidget.h | 12 + geo/tcChannelGroup.cpp | 7 +- geo/tcChannelGroup.h | 3 +- geo/tcGeoImageData.cpp | 21 + geo/tcGeoImageData.h | 12 + geo/tcGlobe.cpp | 15 +- geo/tcGlobe.h | 4 + geo/tcIlluminantDirection.cpp | 177 ++++++++ ...reeChromaticities.h => tcIlluminantDirection.h} | 57 ++- geo/tcIlluminantDiscontinuity.cpp | 132 ++++++ ...lConfigWidget.h => tcIlluminantDiscontinuity.h} | 29 +- geo/tcLandsatData.cpp | 19 + geo/tcLandsatData.h | 4 +- geo/tcPixelData.h | 13 + geo/tcShadowFreeChromaticities.cpp | 80 +--- geo/tcShadowFreeChromaticities.h | 35 +- maths/VarVector.h | 471 +++++++++++++++++++++ tcMainWindow.cpp | 10 +- tcViewportWidget.cpp | 56 ++- tcViewportWidget.h | 26 ++ 24 files changed, 1079 insertions(+), 132 deletions(-) create mode 100644 geo/tcIlluminantDirection.cpp copy geo/{tcShadowFreeChromaticities.h => tcIlluminantDirection.h} (60%) create mode 100644 geo/tcIlluminantDiscontinuity.cpp copy geo/{tcChannelConfigWidget.h => tcIlluminantDiscontinuity.h} (71%) create mode 100644 maths/VarVector.h diff --git a/geo/CMakeLists.txt b/geo/CMakeLists.txt index 22ad3c3..62bd990 100644 --- a/geo/CMakeLists.txt +++ b/geo/CMakeLists.txt @@ -21,7 +21,9 @@ set(tecorrec_geo_SRCS tcChannelConfigWidget.cpp tcChannelFile.cpp tcChannelChromaticity.cpp + tcIlluminantDirection.cpp tcShadowFreeChromaticities.cpp + tcIlluminantDiscontinuity.cpp tcGeoImageData.cpp tcSensor.cpp tcSpectrum.cpp @@ -32,6 +34,7 @@ set(tecorrec_geo_SRCS set(tecorrec_geo_HEADERS tcChannelConfigWidget.h + tcIlluminantDirection.h ) qt4_wrap_cpp(tecorrec_geo_MOCS ${tecorrec_geo_HEADERS}) diff --git a/geo/tcChannel.cpp b/geo/tcChannel.cpp index 54acfda..4160754 100644 --- a/geo/tcChannel.cpp +++ b/geo/tcChannel.cpp @@ -84,6 +84,12 @@ GLuint tcChannel::thumbnailTexture() return 0; } +/// Get a reference to the pixel data of the current portion of the image. +Reference tcChannel::portion() const +{ + return m_portion; +} + /// Get a reference to the pixel data of a portion of the image. Reference tcChannel::portion(double* x1, double* y1, double* x2, double* y2) { diff --git a/geo/tcChannel.h b/geo/tcChannel.h index 7485e05..20c4553 100644 --- a/geo/tcChannel.h +++ b/geo/tcChannel.h @@ -74,6 +74,9 @@ class tcChannel /// Get GL texture ID of thumbnail of the channel. virtual GLuint thumbnailTexture(); + /// Get a reference to the pixel data of the current portion of the image. + Reference portion() const; + /// Get a reference to the pixel data of a portion of the image. Reference portion(double* x1, double* y1, double* x2, double* y2); diff --git a/geo/tcChannelConfigWidget.cpp b/geo/tcChannelConfigWidget.cpp index 2af329a..33f61b7 100644 --- a/geo/tcChannelConfigWidget.cpp +++ b/geo/tcChannelConfigWidget.cpp @@ -38,3 +38,19 @@ tcChannelConfigWidget::tcChannelConfigWidget() tcChannelConfigWidget::~tcChannelConfigWidget() { } + +/* + * Main interface + */ + +/// Request a texture point. +void tcChannelConfigWidget::requestTexturePoint(QObject* receiver, const char* member) +{ + emit texturePointRequested(receiver, member); +} + +/// Request redraw. +void tcChannelConfigWidget::requestRedraw() +{ + emit updated(); +} diff --git a/geo/tcChannelConfigWidget.h b/geo/tcChannelConfigWidget.h index 1b13428..dad0fdb 100644 --- a/geo/tcChannelConfigWidget.h +++ b/geo/tcChannelConfigWidget.h @@ -44,6 +44,16 @@ class tcChannelConfigWidget : public QWidget /// Destructor. virtual ~tcChannelConfigWidget(); + /* + * Main interface + */ + + /// Request a texture point. + void requestTexturePoint(QObject* receiver, const char* member); + + /// Request redraw. + void requestRedraw(); + signals: /* @@ -53,6 +63,8 @@ class tcChannelConfigWidget : public QWidget /// Emitted when settings have been changed and the viewport may need redrawing. void updated(); + /// Emitted to select a new texture point. + void texturePointRequested(QObject* receiver, const char* member); }; #endif diff --git a/geo/tcChannelGroup.cpp b/geo/tcChannelGroup.cpp index dd133d2..7cef9a7 100644 --- a/geo/tcChannelGroup.cpp +++ b/geo/tcChannelGroup.cpp @@ -157,7 +157,7 @@ tcChannelConfigWidget* tcChannelGroup::configWidget() Reference tcChannelGroup::portion(int channel, double x1, double y1, double x2, double y2) { // If the portion is out of date, remove it - if (0 == m_portions.size()) + if (0 != m_portions.size()) { if (m_portionPosition[0][0] != x1 || m_portionPosition[0][1] != y1 || @@ -208,6 +208,11 @@ void tcChannelGroup::loadPortions(double x1, double y1, double x2, double y2) /// Invalidate this channel. void tcChannelGroup::invalidate() { + m_portions.clear(); + foreach (tcChannel* channel, m_channels) + { + channel->invalidate(); + } } /// Revalidate the channel, indicating that the data has changed. diff --git a/geo/tcChannelGroup.h b/geo/tcChannelGroup.h index 90ded58..1081778 100644 --- a/geo/tcChannelGroup.h +++ b/geo/tcChannelGroup.h @@ -28,6 +28,7 @@ #include "CountedReference.h" #include "tcPixelData.h" +#include #include #include @@ -37,7 +38,7 @@ class tcChannelConfigWidget; /** A single abstract image channel. * This sort of acts as a data source for a set of related output channels. */ -class tcChannelGroup +class tcChannelGroup : public QObject { public: diff --git a/geo/tcGeoImageData.cpp b/geo/tcGeoImageData.cpp index b0f45be..590ca6b 100644 --- a/geo/tcGeoImageData.cpp +++ b/geo/tcGeoImageData.cpp @@ -39,6 +39,8 @@ tcGeoImageData::tcGeoImageData() , m_sensor(0) , m_sunDirection(0) { + m_effectiveRange[0].x = 0.0; m_effectiveRange[0].y = 1.0; + m_effectiveRange[1].x = 0.0; m_effectiveRange[1].y = 1.0; } /// Destructor. @@ -73,6 +75,18 @@ void tcGeoImageData::geoToLocal(const tcGeo& coord, LocalCoord* local) } } +/// Minimum local coordinates. +const tcGeoImageData::LocalCoord& tcGeoImageData::minLocal() const +{ + return m_effectiveRange[0]; +} + +/// Range of local coordinates. +const tcGeoImageData::LocalCoord& tcGeoImageData::rangeLocal() const +{ + return m_effectiveRange[1]; +} + /* * Protected mutators */ @@ -83,3 +97,10 @@ void tcGeoImageData::setTransformation(OGRCoordinateTransformation* transformati Q_ASSERT(0 == m_transformFromGeo); m_transformFromGeo = transformation; } + +/// Set the effective range of local coordinates. +void tcGeoImageData::setEffectiveRange(const LocalCoord& min, const LocalCoord& range) +{ + m_effectiveRange[0] = min; + m_effectiveRange[1] = range; +} diff --git a/geo/tcGeoImageData.h b/geo/tcGeoImageData.h index e861f42..8ab7b67 100644 --- a/geo/tcGeoImageData.h +++ b/geo/tcGeoImageData.h @@ -78,6 +78,12 @@ class tcGeoImageData : public tcGeoData /// Convert a geo to local coordinates. void geoToLocal(const tcGeo& coord, LocalCoord* local); + /// Minimum local coordinates. + const LocalCoord& minLocal() const; + + /// Range of local coordinates. + const LocalCoord& rangeLocal() const; + /* * Rendering */ @@ -104,6 +110,9 @@ class tcGeoImageData : public tcGeoData /// Set the coordinate transform. void setTransformation(OGRCoordinateTransformation* transformation); + /// Set the effective range of local coordinates. + void setEffectiveRange(const LocalCoord& min, const LocalCoord& range); + private: /* @@ -116,6 +125,9 @@ class tcGeoImageData : public tcGeoData /// Transformation from geo to local. OGRCoordinateTransformation* m_transformFromGeo; + /// Current effective range of local coordinates. + LocalCoord m_effectiveRange[2]; + /// Sensors which collected the data. tcSensor* m_sensor; diff --git a/geo/tcGlobe.cpp b/geo/tcGlobe.cpp index 01cf7fb..d45a0b0 100644 --- a/geo/tcGlobe.cpp +++ b/geo/tcGlobe.cpp @@ -51,8 +51,8 @@ tcGlobe::tcGlobe(double meanRadius) { m_colourMapping[i] = 2-i; } - //setImagery(new tcLandsatData("/home/james/cs/pro/data/LE71950281999206EDC01/")); - setImagery(new tcLandsatData("/home/james/cs/pro/data/LE71950282000081EDC00/")); + setImagery(new tcLandsatData("/home/james/cs/pro/data/LE71950281999206EDC01/")); + //setImagery(new tcLandsatData("/home/james/cs/pro/data/LE71950282000081EDC00/")); } /// Destructor. @@ -582,3 +582,14 @@ double tcGlobe::radiusAt(const tcGeo& coord) const { return m_meanRadius + altitudeAt(coord); } + +/// Get the texture coordinate of the effective texture at a geographical coordinate. +maths::Vector<2,double> tcGlobe::textureCoordOfGeo(const tcGeo& coord) const +{ + const tcGeoImageData::LocalCoord& min = m_imagery->minLocal(); + const tcGeoImageData::LocalCoord& range = m_imagery->rangeLocal(); + tcGeoImageData::LocalCoord localCoord; + m_imagery->geoToLocal(coord, &localCoord); + return maths::Vector<2,double>((localCoord.x-min.x) / range.x, + (localCoord.y-min.y) / range.y); +} diff --git a/geo/tcGlobe.h b/geo/tcGlobe.h index af78b09..442cae5 100644 --- a/geo/tcGlobe.h +++ b/geo/tcGlobe.h @@ -114,6 +114,10 @@ class tcGlobe /// Get the radius at a coordinate. double radiusAt(const tcGeo& coord) const; + /// Get the texture coordinate of the effective texture at a geographical coordinate. + maths::Vector<2,double> textureCoordOfGeo(const tcGeo& coord) const; + + private: /* diff --git a/geo/tcIlluminantDirection.cpp b/geo/tcIlluminantDirection.cpp new file mode 100644 index 0000000..14b0afc --- /dev/null +++ b/geo/tcIlluminantDirection.cpp @@ -0,0 +1,177 @@ +/*************************************************************************** + * This file is part of Tecorrec. * + * Copyright 2008 James Hogan * + * * + * Tecorrec is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Tecorrec is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Tecorrec. If not, write to the Free Software Foundation, * + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +/** + * @file tcIlluminantDirection.cpp + * @brief Illuminant direction based calculation. + */ + +#include "tcIlluminantDirection.h" +#include "tcChannelConfigWidget.h" +#include "tcChannel.h" + +#include +#include + +/* + * Constructors + destructor + */ + +/// Primary constructor. +tcIlluminantDirection::tcIlluminantDirection(const QList& chromaticities, + int outputs, const QString& name, const QString& description) +: tcChannelGroup(outputs, name, description) +, m_chromaticities(chromaticities) +, m_illuminantDirection(chromaticities.size(), 1.0f) +, m_illuminantDirectionSamples(0) +, m_configWidget(0) +{ + m_illuminantDirection.normalize(); +} + +/// Destructor. +tcIlluminantDirection::~tcIlluminantDirection() +{ + delete m_configWidget; +} + +/* + * Accessors + */ + +/// Get the number of chromaticity channels. +int tcIlluminantDirection::numChromaticities() const +{ + return m_chromaticities.size(); +} + +/// Get the illuminant direction. +const maths::VarVector& tcIlluminantDirection::illuminantDirection() const +{ + return m_illuminantDirection; +} + +/* + * Main image interface + */ + +tcChannelConfigWidget* tcIlluminantDirection::configWidget() +{ + if (0 == m_configWidget) + { + m_configWidget = new tcChannelConfigWidget(); + m_configWidget->setWindowTitle(QObject::tr("%1 Configuration").arg(name())); + + // Create a button which triggers texture point request. + QPushButton* btnNewShadowNonShadow = new QPushButton(tr("Choose Shadow/Non-Shadow transition"), m_configWidget); + connect(btnNewShadowNonShadow, SIGNAL(clicked(bool)), this, SLOT(startShadowNonShadow())); + } + return m_configWidget; +} + +/* + * Private slots + */ + +/// Start choosing a shadow / non shadow pair. +void tcIlluminantDirection::startShadowNonShadow() +{ + Q_ASSERT(0 != m_configWidget); + m_configWidget->requestTexturePoint(this, SLOT(selectShadowPoint(const maths::Vector<2,float>&))); +} + +/// New shadow point. +void tcIlluminantDirection::selectShadowPoint(const maths::Vector<2,float>& point) +{ + Q_ASSERT(0 != m_configWidget); + m_shadowPoint = point; + m_configWidget->requestTexturePoint(this, SLOT(selectNonShadowPoint(const maths::Vector<2,float>&))); +} + +/// New non-shadow point. +void tcIlluminantDirection::selectNonShadowPoint(const maths::Vector<2,float>& point) +{ + Q_ASSERT(0 != m_configWidget); + // Find the direction between the log chromaticities of the two points + for (int i = 0; i < m_chromaticities.size(); ++i) + { + tcChannel* channel = m_chromaticities[i]; + Reference pixelData = channel->portion(); + if (0 != pixelData) + { + float delta = pixelData->sampleFloat(point[0], 1.0f - point[1]) + - pixelData->sampleFloat(m_shadowPoint[0], 1.0f - m_shadowPoint[1]); + m_illuminantDirection[i] *= m_illuminantDirectionSamples; + m_illuminantDirection[i] += delta; + m_illuminantDirection[i] /= m_illuminantDirectionSamples+1; + } + } + //m_illuminantDirection.normalize(); + ++m_illuminantDirectionSamples; + invalidate(); + m_configWidget->requestRedraw(); +} + +/* + * Interface for derived class to implement + */ + +void tcIlluminantDirection::roundPortion(double* x1, double* y1, double* x2, double* y2) +{ + if (!m_chromaticities.empty()) + { + m_chromaticities[0]->roundPortion(x1,y1,x2,y2); + } +} + +void tcIlluminantDirection::loadPortions(double x1, double y1, double x2, double y2) +{ + QList< Reference< tcPixelData > > chromaticityData; + int width = 0; + int height = 0; + foreach (tcChannel* channel, m_chromaticities) + { + /// @todo Make this neater + double x1a = x1; + double y1a = y1; + double x2a = x2; + double y2a = y2; + Reference< tcPixelData > pixelData = dynamicCast< tcPixelData* >(channel->portion(&x1a,&y1a,&x2a,&y2a)); + chromaticityData += pixelData; + Q_ASSERT(0 != pixelData); + // Ensure each channel is the same resolution + if (0 == width) + { + width = pixelData->width(); + } + else + { + Q_ASSERT(width == pixelData->width()); + } + if (0 == height) + { + height = pixelData->height(); + } + else + { + Q_ASSERT(height == pixelData->height()); + } + } + loadPortions(chromaticityData, width, height); +} diff --git a/geo/tcShadowFreeChromaticities.h b/geo/tcIlluminantDirection.h similarity index 60% copy from geo/tcShadowFreeChromaticities.h copy to geo/tcIlluminantDirection.h index 7a8d44c..867fe84 100644 --- a/geo/tcShadowFreeChromaticities.h +++ b/geo/tcIlluminantDirection.h @@ -17,23 +17,27 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef _tcShadowFreeChromaticities_h_ -#define _tcShadowFreeChromaticities_h_ +#ifndef _tcIlluminantDirection_h_ +#define _tcIlluminantDirection_h_ /** - * @file tcShadowFreeChromaticities.h - * @brief Remove the shadows from a set of chromaticities. + * @file tcIlluminantDirection.h + * @brief Illuminant direction based calculation. */ #include "tcChannelGroup.h" +#include "tcPixelData.h" +#include #include class tcChannel; -/// Remove the shadows from a set of chromaticities. -class tcShadowFreeChromaticities : public tcChannelGroup +/// Illuminant direction based calculation. +class tcIlluminantDirection : public tcChannelGroup { + Q_OBJECT + public: /* @@ -41,10 +45,21 @@ class tcShadowFreeChromaticities : public tcChannelGroup */ /// Primary constructor. - tcShadowFreeChromaticities(const QList& chromaticities); + tcIlluminantDirection(const QList& chromaticities, + int outputs, const QString& name, const QString& description); /// Destructor. - virtual ~tcShadowFreeChromaticities(); + virtual ~tcIlluminantDirection(); + + /* + * Accessors + */ + + /// Get the number of chromaticity channels. + int numChromaticities() const; + + /// Get the illuminant direction. + const maths::VarVector& illuminantDirection() const; /* * Main image interface @@ -53,6 +68,21 @@ class tcShadowFreeChromaticities : public tcChannelGroup // Reimplemented virtual tcChannelConfigWidget* configWidget(); + private slots: + + /* + * Private slots + */ + + /// Start choosing a shadow / non shadow pair. + void startShadowNonShadow(); + + /// New shadow point. + void selectShadowPoint(const maths::Vector<2,float>& point); + + /// New non-shadow point. + void selectNonShadowPoint(const maths::Vector<2,float>& point); + protected: /* @@ -65,6 +95,9 @@ class tcShadowFreeChromaticities : public tcChannelGroup // Reimplemented virtual void loadPortions(double x1, double y1, double x2, double y2); + /// Load portions using nicely accessed chromaticity data. + virtual void loadPortions(const QList< Reference< tcPixelData > >& chromaticities, int width, int height) = 0; + private: /* @@ -75,10 +108,16 @@ class tcShadowFreeChromaticities : public tcChannelGroup QList m_chromaticities; /// Current log chromaticity illuminant direction. - QList m_illuminantDirection; + maths::VarVector m_illuminantDirection; + + /// Number of samples used to approximate illuminant direction. + int m_illuminantDirectionSamples; /// Configuration widget. tcChannelConfigWidget* m_configWidget; + + /// Current shadow point. + maths::Vector<2,float> m_shadowPoint; }; #endif diff --git a/geo/tcIlluminantDiscontinuity.cpp b/geo/tcIlluminantDiscontinuity.cpp new file mode 100644 index 0000000..3f07b10 --- /dev/null +++ b/geo/tcIlluminantDiscontinuity.cpp @@ -0,0 +1,132 @@ +/*************************************************************************** + * This file is part of Tecorrec. * + * Copyright 2008 James Hogan * + * * + * Tecorrec is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Tecorrec is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Tecorrec. If not, write to the Free Software Foundation, * + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +/** + * @file tcIlluminantDiscontinuity.cpp + * @brief Illuminant discontinuity in both dimentions. + */ + +#include "tcIlluminantDiscontinuity.h" +#include "tcChannel.h" + +#include + +#include + +/* + * Constructors + destructor + */ + +/// Primary constructor. +tcIlluminantDiscontinuity::tcIlluminantDiscontinuity(const QList& chromaticities) +: tcIlluminantDirection(chromaticities, 2, QObject::tr("Illuminant discontinuity measure"), QObject::tr("")) +{ + channels()[0]->setName(QObject::tr("idm.x")); + channels()[1]->setName(QObject::tr("idm.y")); + channels()[0]->setDescription(QObject::tr("Illuminant discontinuity measure in the x direction")); + channels()[1]->setDescription(QObject::tr("Illuminant discontinuity measure in the y direction")); +} + +/// Destructor. +tcIlluminantDiscontinuity::~tcIlluminantDiscontinuity() +{ +} + +/* + * Interface for derived class to implement + */ + +void tcIlluminantDiscontinuity::loadPortions(const QList< Reference< tcPixelData > >& chromaticities, int width, int height) +{ + Reference< tcPixelData > discontinuityData[2]; + for (int i = 0; i < 2; ++i) + { + discontinuityData[i] = new tcPixelData(width, height); + m_portions += discontinuityData[i]; + } + + // Go through the pixels + maths::VarVector lastLogChromaticity(numChromaticities()); + maths::VarVector logChromaticity(numChromaticities()); + maths::VarVector temp(numChromaticities()); + float lastDisc = 0.0f; + for (int i = 0; i < width; ++i) + { + for (int j = 0; j < height; ++j) + { + int index = j*width + i; + // Fill log chromaticity vector + for (int channel = 0; channel < numChromaticities(); ++channel) + { + logChromaticity[channel] = logf(chromaticities[channel]->buffer()[index]); + } + + temp = logChromaticity; + temp -= lastLogChromaticity; + + float discontinuity = lastDisc; + float sqr = temp.sqr(); + if (sqr > 0.0f) + { + float mag = sqrtf(sqr); + if (mag > 0.0f) + { + discontinuity = /*fabs*/(temp * illuminantDirection()) /*/ mag*/; + } + } + lastDisc = discontinuity*0.5f; + + lastLogChromaticity = logChromaticity; + + discontinuityData[0]->buffer()[index] = 0.5f + discontinuity; + } + } + lastDisc = 0.0f; + for (int j = 0; j < height; ++j) + { + for (int i = 0; i < width; ++i) + { + int index = j*width + i; + // Fill log chromaticity vector + for (int channel = 0; channel < numChromaticities(); ++channel) + { + logChromaticity[channel] = logf(chromaticities[channel]->buffer()[index]); + } + + temp = logChromaticity; + temp -= lastLogChromaticity; + + float discontinuity = lastDisc; + float sqr = temp.sqr(); + if (sqr > 0.0f) + { + float mag = sqrtf(sqr); + if (mag > 0.0f) + { + discontinuity = /*fabs*/(temp * illuminantDirection()) /*/ mag*/; + } + } + lastDisc = discontinuity*0.5f; + + lastLogChromaticity = logChromaticity; + + discontinuityData[1]->buffer()[index] = 0.5f + discontinuity; + } + } +} diff --git a/geo/tcChannelConfigWidget.h b/geo/tcIlluminantDiscontinuity.h similarity index 71% copy from geo/tcChannelConfigWidget.h copy to geo/tcIlluminantDiscontinuity.h index 1b13428..d6b3853 100644 --- a/geo/tcChannelConfigWidget.h +++ b/geo/tcIlluminantDiscontinuity.h @@ -17,21 +17,19 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ -#ifndef _tcChannelConfigWidget_h_ -#define _tcChannelConfigWidget_h_ +#ifndef _tcIlluminantDiscontinuity_h_ +#define _tcIlluminantDiscontinuity_h_ /** - * @file tcChannelConfigWidget.h - * @brief A channel configuration widget. + * @file tcIlluminantDiscontinuity.h + * @brief Illuminant discontinuity in both dimentions. */ -#include +#include "tcIlluminantDirection.h" -/// A channel configuration widget. -class tcChannelConfigWidget : public QWidget +/// Illuminant discontinuity in both dimentions. +class tcIlluminantDiscontinuity : public tcIlluminantDirection { - Q_OBJECT - public: /* @@ -39,20 +37,19 @@ class tcChannelConfigWidget : public QWidget */ /// Primary constructor. - tcChannelConfigWidget(); + tcIlluminantDiscontinuity(const QList& chromaticities); /// Destructor. - virtual ~tcChannelConfigWidget(); + virtual ~tcIlluminantDiscontinuity(); - signals: + protected: /* - * Signals + * Interface for derived class to implement */ - /// Emitted when settings have been changed and the viewport may need redrawing. - void updated(); - + // Reimplemented + virtual void loadPortions(const QList< Reference< tcPixelData > >& chromaticities, int width, int height); }; #endif diff --git a/geo/tcLandsatData.cpp b/geo/tcLandsatData.cpp index e560d0e..908d79a 100644 --- a/geo/tcLandsatData.cpp +++ b/geo/tcLandsatData.cpp @@ -28,6 +28,7 @@ #include "tcChannelFile.h" #include "tcChannelChromaticity.h" #include "tcShadowFreeChromaticities.h" +#include "tcIlluminantDiscontinuity.h" #include #include @@ -128,6 +129,8 @@ tcLandsatData::tcLandsatData(const QString& path) } tcShadowFreeChromaticities* sfc = new tcShadowFreeChromaticities(chromaticities); channelManager()->addChannels(sfc->channels()); + tcIlluminantDiscontinuity* idm = new tcIlluminantDiscontinuity(chromaticities); + channelManager()->addChannels(idm->channels()); // Only load one metafile break; @@ -187,6 +190,14 @@ void tcLandsatData::setupThumbnailRendering(int redChannel, int greenChannel, in // Full image m_effectiveMetaData[i] = m_metaData; } + + LocalCoord min; + min.x = m_metaData.mapLowerLeft[0]; + min.y = m_metaData.mapLowerLeft[1]; + LocalCoord range; + range.x = m_metaData.mapRange[0]; + range.y = m_metaData.mapRange[1]; + setEffectiveRange(min, range); } void tcLandsatData::setupDetailedRendering(int redChannel, int greenChannel, int blueChannel, @@ -256,6 +267,14 @@ void tcLandsatData::setupDetailedRendering(int redChannel, int greenChannel, int } } } + + LocalCoord min; + min.x = m_effectiveMetaData[0].mapLowerLeft[0]; + min.y = m_effectiveMetaData[0].mapLowerLeft[1]; + LocalCoord range; + range.x = m_effectiveMetaData[0].mapRange[0]; + range.y = m_effectiveMetaData[0].mapRange[1]; + setEffectiveRange(min, range); } void tcLandsatData::texCoord(const LocalCoord& coord) diff --git a/geo/tcLandsatData.h b/geo/tcLandsatData.h index 2c5b899..d88290e 100644 --- a/geo/tcLandsatData.h +++ b/geo/tcLandsatData.h @@ -78,9 +78,9 @@ class tcLandsatData : public tcGeoImageData struct MetaData { /// Lower left corner map coordinates. - maths::Vector<3, double> mapLowerLeft; + maths::Vector<2, double> mapLowerLeft; /// Upper right corner map coordinates. - maths::Vector<3, double> mapRange; + maths::Vector<2, double> mapRange; } m_metaData; /// Effective metadata when using texturing. diff --git a/geo/tcPixelData.h b/geo/tcPixelData.h index 859432f..ba94d0d 100644 --- a/geo/tcPixelData.h +++ b/geo/tcPixelData.h @@ -71,6 +71,9 @@ class tcAbstractPixelData : public ReferenceCounted /// Discard of any cached texture id for this image. void discardTexture(); + /// Sample a floating point value from the image. + virtual float sampleFloat(float x, float y) const = 0; + protected: /* @@ -133,6 +136,16 @@ class tcPixelData : public tcAbstractPixelData return m_data; } + // Reimplemented + virtual float sampleFloat(float x, float y) const + { + if (x < 0.0) x = 0.0; + if (x > 1.0) x = 1.0; + if (y < 0.0) y = 0.0; + if (y > 1.0) y = 1.0; + return (float)m_data[(int)(y*(height()-1))*width() + (int)(x*(width()-1))]; + } + protected: /* diff --git a/geo/tcShadowFreeChromaticities.cpp b/geo/tcShadowFreeChromaticities.cpp index c368261..0df7c4d 100644 --- a/geo/tcShadowFreeChromaticities.cpp +++ b/geo/tcShadowFreeChromaticities.cpp @@ -23,21 +23,19 @@ */ #include "tcShadowFreeChromaticities.h" -#include "tcChannelConfigWidget.h" #include "tcChannel.h" #include +#include + /* * Constructors + destructor */ /// Primary constructor. tcShadowFreeChromaticities::tcShadowFreeChromaticities(const QList& chromaticities) -: tcChannelGroup(chromaticities.size(), QObject::tr("Shadow free chromaticities"), QObject::tr("Re-chromatised illuminant invariant")) -, m_chromaticities(chromaticities) -, m_illuminantDirection() -, m_configWidget(0) +: tcIlluminantDirection(chromaticities, chromaticities.size(), QObject::tr("Shadow free chromaticities"), QObject::tr("Re-chromatised illuminant invariant")) { for (int i = 0; i < chromaticities.size(); ++i) { @@ -49,83 +47,45 @@ tcShadowFreeChromaticities::tcShadowFreeChromaticities(const QList& /// Destructor. tcShadowFreeChromaticities::~tcShadowFreeChromaticities() { - delete m_configWidget; -} - -/* - * Main image interface - */ - -tcChannelConfigWidget* tcShadowFreeChromaticities::configWidget() -{ - if (0 == m_configWidget) - { - m_configWidget = new tcChannelConfigWidget(); - m_configWidget->setWindowTitle(QObject::tr("%1 Configuration").arg(name())); - } - return m_configWidget; } /* * Interface for derived class to implement */ -void tcShadowFreeChromaticities::roundPortion(double* x1, double* y1, double* x2, double* y2) -{ - if (!m_chromaticities.empty()) - { - m_chromaticities[0]->roundPortion(x1,y1,x2,y2); - } -} - -void tcShadowFreeChromaticities::loadPortions(double x1, double y1, double x2, double y2) +void tcShadowFreeChromaticities::loadPortions(const QList< Reference< tcPixelData > >& chromaticities, int width, int height) { - QList< Reference< tcPixelData > > chromaticityData; QList< Reference< tcPixelData > > newChromaticityData; - int width = 0; - int height = 0; - foreach (tcChannel* channel, m_chromaticities) + for (int i = 0; i < numChromaticities(); ++i) { - /// @todo Make this neater - double x1a = x1; - double y1a = y1; - double x2a = x2; - double y2a = y2; - Reference< tcPixelData > pixelData = dynamicCast< tcPixelData* >(channel->portion(&x1a,&y1a,&x2a,&y2a)); - chromaticityData += pixelData; - Q_ASSERT(0 != pixelData); - // Ensure each channel is the same resolution - if (0 == width) - { - width = pixelData->width(); - } - else - { - Q_ASSERT(width == pixelData->width()); - } - if (0 == height) - { - height = pixelData->height(); - } - else - { - Q_ASSERT(height == pixelData->height()); - } Reference< tcPixelData > newPixelData = new tcPixelData(width, height); newChromaticityData += newPixelData; m_portions += newPixelData; } // Go through the pixels + maths::VarVector logChromaticity(numChromaticities()); + maths::VarVector temp(numChromaticities()); for (int i = 0; i < width*height; ++i) { + // Fill log chromaticity vector + for (int channel = 0; channel < numChromaticities(); ++channel) + { + logChromaticity[channel] = logf(chromaticities[channel]->buffer()[i]); + } + // Find the dot of the chromaticity values with the illuminant direction vector + float illuminant = logChromaticity * illuminantDirection(); + // Subtract this * illuminant direction vector from original value to cancel out + temp = illuminantDirection(); + temp *= illuminant; + logChromaticity -= temp; // Copy the data for now - for (int channel = 0; channel < m_chromaticities.size(); ++channel) + for (int channel = 0; channel < numChromaticities(); ++channel) { - newChromaticityData[channel]->buffer()[i] = chromaticityData[channel]->buffer()[i]; + newChromaticityData[channel]->buffer()[i] = expf(logChromaticity[channel]); } } } diff --git a/geo/tcShadowFreeChromaticities.h b/geo/tcShadowFreeChromaticities.h index 7a8d44c..06a3263 100644 --- a/geo/tcShadowFreeChromaticities.h +++ b/geo/tcShadowFreeChromaticities.h @@ -25,14 +25,10 @@ * @brief Remove the shadows from a set of chromaticities. */ -#include "tcChannelGroup.h" - -#include - -class tcChannel; +#include "tcIlluminantDirection.h" /// Remove the shadows from a set of chromaticities. -class tcShadowFreeChromaticities : public tcChannelGroup +class tcShadowFreeChromaticities : public tcIlluminantDirection { public: @@ -46,13 +42,6 @@ class tcShadowFreeChromaticities : public tcChannelGroup /// Destructor. virtual ~tcShadowFreeChromaticities(); - /* - * Main image interface - */ - - // Reimplemented - virtual tcChannelConfigWidget* configWidget(); - protected: /* @@ -60,25 +49,7 @@ class tcShadowFreeChromaticities : public tcChannelGroup */ // Reimplemented - virtual void roundPortion(double* x1, double* y1, double* x2, double* y2); - - // Reimplemented - virtual void loadPortions(double x1, double y1, double x2, double y2); - - private: - - /* - * Variables - */ - - /// Input chromaticities. - QList m_chromaticities; - - /// Current log chromaticity illuminant direction. - QList m_illuminantDirection; - - /// Configuration widget. - tcChannelConfigWidget* m_configWidget; + virtual void loadPortions(const QList< Reference< tcPixelData > >& chromaticities, int width, int height); }; #endif diff --git a/maths/VarVector.h b/maths/VarVector.h new file mode 100644 index 0000000..51d2266 --- /dev/null +++ b/maths/VarVector.h @@ -0,0 +1,471 @@ +/*************************************************************************** + * This file is part of Tecorrec. * + * Copyright 2008 James Hogan * + * * + * Tecorrec is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * Tecorrec is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with Tecorrec. If not, write to the Free Software Foundation, * + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * + ***************************************************************************/ + +/** + * @file VarVector.h + * @brief Resizable vector of values, designed for spacial coordinate vectors. + * @author James Hogan + * @note Copyright (C) 2008 + */ + +#ifndef _maths_VarVector_h +#define _maths_VarVector_h + +#include "TemplateMaths.h" +#include "Vector.h" + +#include + +#include +#include + +namespace maths +{ + + /// VarVector. + /** + * @param N int Number of components in the vector. + * @param T typename Type of the components of the vector. + */ + template + class VarVector + { + private: + int m_length; + T* v; + + public: + typedef T Scalar; + + /// Default constructor (zero length, use setLength before doing anything) + inline explicit VarVector() + : m_length(0) + , v(0) + { + } + + /// Default constructor (Does not initialise the values!) + inline explicit VarVector(int components) + : m_length(components) + , v(new T[components]) + { + } + + inline VarVector(int components, T value) + : m_length(components) + , v(new T[components]) + { + for (int i = 0; i < m_length; ++i) + { + v[i] = value; + } + } + inline VarVector(int components, const T * vec) + : m_length(components) + , v(new T[components]) + { + for (int i = 0; i < m_length; ++i) + { + v[i] = vec[i]; + } + } + + /// Copy constructor + inline VarVector(const VarVector & copy) + : m_length(copy.m_length) + , v(new T[m_length]) + { + for (int i = 0; i < m_length; ++i) + { + v[i] = copy[i]; + } + } + template inline explicit VarVector(const VarVector & copy) + : m_length(copy.m_length) + , v(new T[m_length]) + { + for (int i = 0; i < m_length; ++i) + { + v[i] = copy[i]; + } + } + template inline explicit VarVector(const Vector & copy) + : m_length(M) + , v(new T[M]) + { + for (int i = 0; i < M; ++i) + { + v[i] = copy[i]; + } + } + + /// Destructor + inline ~VarVector() + { + delete [] v; + } + + /// Get the length of the vector. + int length() const + { + return m_length; + } + + /// Resize of the vector (values are lost). + void setLength(int newLength) + { + if (newLength != m_length) + { + Q_ASSERT(newLength > 0); + delete [] v; + m_length = newLength; + v = new T [newLength]; + } + } + + /// Assignment operator. + VarVector& operator = (const VarVector& other) + { + setLength(other.m_length); + for (int i = 0; i < m_length; ++i) + { + v[i] = other.v[i]; + } + return *this; + } + + /// Assignment operator. + template + VarVector& operator = (const VarVector& other) + { + setLength(other.m_length); + for (int i = 0; i < m_length; ++i) + { + v[i] = other.v[i]; + } + return *this; + } + + /// Setter for specific component. + template + inline void setComponent(const T newValue) + { + v[X] = newValue; + } + + /// Getter for specific component. + template + inline T getComponent() const + { + return v[X]; + } + + inline T & operator [] (int index) + { + return v[index]; + } + inline const T & operator [] (int index) const + { + return v[index]; + } + + inline operator T * () + { + return v; + } + inline operator const T * () const + { + return v; + } + + inline VarVector operator - () const + { + VarVector ret(m_length); + for (int i = 0; i < m_length; ++i) + { + ret[i] = -v[i]; + } + return ret; + } + + template + inline VarVector & operator += (const VarVector & rhs) + { + Q_ASSERT(m_length == rhs.m_length); + for (int i = 0; i < m_length; ++i) + { + v[i] += rhs.v[i]; + } + return *this; + } + template + inline VarVector operator + (const VarVector & rhs) const + { + VarVector ret = *this; + return ret += rhs; + } + + inline VarVector & operator -= (const VarVector & rhs) + { + Q_ASSERT(m_length == rhs.m_length); + for (int i = 0; i < m_length; ++i) + { + v[i] -= rhs.v[i]; + } + return *this; + } + inline VarVector operator - (const VarVector & rhs) const + { + VarVector ret = *this; + return ret -= rhs; + } + + inline VarVector & operator *= (const T rhs) + { + for (int i = 0; i < m_length; ++i) + { + v[i] *= rhs; + } + return *this; + } + inline VarVector operator * (const T rhs) const + { + VarVector ret = *this; + return ret *= rhs; + } + inline friend VarVector operator * (const T lhs, const VarVector & rhs) + { + return rhs * lhs; + } + + /// Dot product + inline T operator * (const VarVector & rhs) const + { + Q_ASSERT(m_length == rhs.m_length); + T fDot = maths::zero(); + for (int i = 0; i < m_length; ++i) + { + fDot += v[i]*rhs.v[i]; + } + return fDot; + } + + /// Dot quotient + inline T operator / (const VarVector & rhs) const + { + // a = B/C = (B*C)/(C*C) + return operator * (rhs) / rhs.sqr(); + } + + inline VarVector & operator /= (const T rhs) + { + for (int i = 0; i < m_length; ++i) + { + v[i] /= rhs; + } + return *this; + } + inline VarVector operator / (const T rhs) const + { + VarVector ret = *this; + return ret /= rhs; + } + inline friend VarVector operator / (const T lhs, const VarVector & rhs) + { + return rhs * (lhs / rhs.sqr()); + } + + inline T sqr() const + { + return tsqr(); + } + template + inline U tsqr() const + { + U ret = maths::zero(); + for (int i = 0; i < m_length; ++i) + { + ret += maths::sqr(v[i]); + } + return ret; + } + + inline VarVector inv() const + { + return *this / sqr(); + } + + inline T mag() const + { + return tmag(); + } + template + inline U tmag() const + { + return maths::sqrt(tsqr()); + } + + + inline VarVector & normalize() + { + return operator /= (mag()); + } + inline VarVector normalized() const + { + return operator / (mag()); + } + inline VarVector & resize(T tLength) + { + return operator *= (tLength / mag()); + } + inline VarVector resized(T tLength) const + { + return operator * (tLength / mag()); + } + + + // predicates + + /// Equality + inline bool operator == (const VarVector & rhs) const + { + Q_ASSERT(m_length == rhs.m_length); + for (int i = 0; i < m_length; ++i) + { + if (v[i] != rhs.v[i]) + { + return false; + } + } + return true; + } + /// Nonequality + inline bool operator != (const VarVector & rhs) const + { + Q_ASSERT(m_length == rhs.m_length); + for (int i = 0; i < m_length; ++i) + { + if (v[i] != rhs.v[i]) + { + return true; + } + } + return false; + } + + /// Compare the magnitude of vectors. + inline bool operator < (const VarVector & rhs) const + { + return sqr() < rhs.sqr(); + } + /// Compare the magnitude of the vector with a scalar magnitude. + inline bool operator < (const T & rhs) const + { + return sqr() < rhs*rhs; + } + /// Compare the magnitude of the vector with a scalar magnitude. + inline friend bool operator < (const T & lhs, const VarVector & rhs) + { + return lhs*lhs < rhs.sqr(); + } + /// Compare the magnitude of vectors. + inline bool operator <= (const VarVector & rhs) const + { + return sqr() <= rhs.sqr(); + } + /// Compare the magnitude of the vector with a scalar magnitude. + inline bool operator <= (const T & rhs) const + { + return sqr() <= rhs*rhs; + } + /// Compare the magnitude of the vector with a scalar magnitude. + inline friend bool operator <= (const T & lhs, const VarVector & rhs) + { + return lhs*lhs <= rhs.sqr(); + } + /// Compare the magnitude of vectors. + inline bool operator > (const VarVector & rhs) const + { + return sqr() > rhs.sqr(); + } + /// Compare the magnitude of the vector with a scalar magnitude. + inline bool operator > (const T & rhs) const + { + return sqr() > rhs*rhs; + } + /// Compare the magnitude of the vector with a scalar magnitude. + inline friend bool operator > (const T & lhs, const VarVector & rhs) + { + return lhs*lhs > rhs.sqr(); + } + /// Compare the magnitude of vectors. + inline bool operator >= (const VarVector & rhs) const + { + return sqr() >= rhs.sqr(); + } + /// Compare the magnitude of the vector with a scalar magnitude. + inline bool operator >= (const T & rhs) const + { + return sqr() >= rhs*rhs; + } + /// Compare the magnitude of the vector with a scalar magnitude. + inline friend bool operator >= (const T & lhs, const VarVector & rhs) + { + return lhs*lhs >= rhs.sqr(); + } + + /// Find whether the vector zero. + inline bool zero() const + { + for (int i = 0; i < m_length; ++i) + { + if (v[i]) + { + return false; + } + } + return true; + } + + inline operator std::string() const; + }; // ::maths::VarVector + + /// Write a vector to an output stream. + template + inline std::ostream & operator << (std::ostream & out, const VarVector & v) + { + out << "(" << v[0]; + for (int i = 1; i < v.length(); ++i) + { + out << ", " << v[i]; + } + return out << ")"; + } + /// Convert to a string using the above stream operator + template + inline VarVector::operator std::string() const + { + std::stringstream ss; + ss << v; + return ss.str(); + } + +} // ::maths + +#endif // _maths_VarVector_h diff --git a/tcMainWindow.cpp b/tcMainWindow.cpp index 463d612..120d238 100644 --- a/tcMainWindow.cpp +++ b/tcMainWindow.cpp @@ -96,9 +96,11 @@ tcMainWindow::tcMainWindow() setStatusBar(statusBar); } + QDockWidget* dockElevation; { // Docker for elevation data settings QDockWidget* docker = new QDockWidget(tr("Elevation Data"), this); + dockElevation = docker; QWidget* dockerWidget = new QWidget(docker); QVBoxLayout* layout = new QVBoxLayout(dockerWidget); docker->setWidget(dockerWidget); @@ -144,7 +146,7 @@ tcMainWindow::tcMainWindow() QWidget* dockerWidget = new QWidget(docker); QVBoxLayout* layout = new QVBoxLayout(dockerWidget); docker->setWidget(dockerWidget); - addDockWidget(Qt::LeftDockWidgetArea, docker); + tabifyDockWidget(dockElevation, docker); // Grid of colours layout->addWidget(m_colourMap); @@ -169,7 +171,7 @@ tcMainWindow::tcMainWindow() QWidget* dockerWidget = new QWidget(docker); QVBoxLayout* layout = new QVBoxLayout(dockerWidget); docker->setWidget(dockerWidget); - addDockWidget(Qt::LeftDockWidgetArea, docker); + tabifyDockWidget(dockElevation, docker); // Spacer layout->addStretch(); @@ -193,6 +195,10 @@ void tcMainWindow::configureChannel(int channel) tcChannelConfigWidget* configWidget = manager->channel(channel)->configWidget(); if (0 != configWidget) { + connect(configWidget, SIGNAL(updated()), + m_viewport, SLOT(updateGL())); + connect(configWidget, SIGNAL(texturePointRequested(QObject*, const char*)), + m_viewport, SLOT(texturePointMode(QObject*, const char*))); configWidget->show(); } } diff --git a/tcViewportWidget.cpp b/tcViewportWidget.cpp index 2b1b940..93f269a 100644 --- a/tcViewportWidget.cpp +++ b/tcViewportWidget.cpp @@ -44,12 +44,15 @@ tcViewportWidget::tcViewportWidget(QWidget* parent) , m_polygonMode(GL_FILL) , m_observer(new tcObserver()) , m_globe(0) +, m_interactionMode(Navigation) , m_mouseInteracting(false) , m_mousePos() , m_mouseIntersecting(false) , m_mouseCoord() , m_mouseSlicing(false) , m_sliced(false) +, m_texturePointObject(0) +, m_texturePointMember(0) { setMouseTracking(true); setMinimumSize(400,300); @@ -178,6 +181,24 @@ tcGeo tcViewportWidget::geoAt(float x, float y, bool* ok) } /* + * Interaction control + */ + +/// Enable navigation mode. +void tcViewportWidget::navigationMode() +{ + m_interactionMode = Navigation; +} + +/// Enable texture point selection mode. +void tcViewportWidget::texturePointMode(QObject* receiver, const char* member) +{ + m_interactionMode = TexturePoint; + m_texturePointObject = receiver; + m_texturePointMember = member; +} + +/* * General rendering slots */ @@ -486,19 +507,40 @@ void tcViewportWidget::mouseMoveEvent(QMouseEvent* event) void tcViewportWidget::mousePressEvent(QMouseEvent* event) { - if (event->button() == Qt::LeftButton) + if (m_interactionMode == Navigation) { - m_mouseInteracting = true; - m_mousePos = event->posF(); + if (event->button() == Qt::LeftButton) + { + m_mouseInteracting = true; + m_mousePos = event->posF(); + } + else if (event->button() == Qt::RightButton) + { + bool ok; + m_mouseStartCoord = geoAt(event->posF().x(), event->posF().y(), &ok); + m_mouseIntersecting = false; + if (ok) + { + m_mouseSlicing = true; + } + } } - else if (event->button() == Qt::RightButton) + else if (m_interactionMode == TexturePoint) { bool ok; - m_mouseStartCoord = geoAt(event->posF().x(), event->posF().y(), &ok); - m_mouseIntersecting = false; + tcGeo geoCoord = geoAt(event->posF().x(), event->posF().y(), &ok); if (ok) { - m_mouseSlicing = true; + maths::Vector<2,float> texturePoint(m_globe->textureCoordOfGeo(geoCoord)); + // need to revert interaction mode first in case slot at other end requests another + m_interactionMode = Navigation; + QObject* currentObj = m_texturePointObject; + const char* currentMember = m_texturePointMember; + connect(this, SIGNAL(texturePointSelected(const maths::Vector<2,float>&)), + currentObj, currentMember); + emit texturePointSelected(texturePoint); + disconnect(this, SIGNAL(texturePointSelected(const maths::Vector<2,float>&)), + currentObj, currentMember); } } } diff --git a/tcViewportWidget.h b/tcViewportWidget.h index 7fdbf49..1c1f730 100644 --- a/tcViewportWidget.h +++ b/tcViewportWidget.h @@ -70,6 +70,16 @@ class tcViewportWidget : public QGLWidget public slots: /* + * Interaction control + */ + + /// Enable navigation mode. + void navigationMode(); + + /// Enable texture point selection mode. + void texturePointMode(QObject* receiver, const char* member); + + /* * General rendering slots */ @@ -127,6 +137,9 @@ class tcViewportWidget : public QGLWidget */ void mouseGeoTextChanged(const QString& geo); + /// Emitted when a texture point is selected. + void texturePointSelected(const maths::Vector<2,float>& coord); + protected: /* @@ -184,6 +197,13 @@ class tcViewportWidget : public QGLWidget * Interaction */ + /// Interaction mode. + enum + { + Navigation, + TexturePoint + } m_interactionMode; + /// Are we currently interacting? bool m_mouseInteracting; @@ -207,6 +227,12 @@ class tcViewportWidget : public QGLWidget /// Coordinates of slice. tcGeo m_slice[2]; + + /// Texture point object. + QObject* m_texturePointObject; + + /// Texture point slot/signal. + const char* m_texturePointMember; }; #endif -- 2.11.4.GIT