1 /***************************************************************************
2 * This file is part of Tecorrec. *
3 * Copyright 2008 James Hogan <james@albanarts.com> *
5 * Tecorrec is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation, either version 2 of the License, or *
8 * (at your option) any later version. *
10 * Tecorrec is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with Tecorrec. If not, write to the Free Software Foundation, *
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
18 ***************************************************************************/
21 * @file tcIlluminantDirection.cpp
22 * @brief Illuminant direction based calculation.
25 #include "tcIlluminantDirection.h"
26 #include "tcChannelConfigWidget.h"
27 #include "tcChannel.h"
30 #include <QVBoxLayout>
31 #include <QPushButton>
34 * Constructors + destructor
37 /// Primary constructor.
38 tcIlluminantDirection::tcIlluminantDirection(const QList
<tcChannel
*>& chromaticities
,
39 int outputs
, const QString
& name
, const QString
& description
)
40 : tcChannelGroup(outputs
, name
, description
)
41 , m_chromaticities(chromaticities
)
42 , m_illuminantDirection(chromaticities
.size(), 1.0f
)
43 , m_illuminantDirectionSamples(0)
46 m_illuminantDirection
.normalize();
50 tcIlluminantDirection::~tcIlluminantDirection()
52 delete m_configWidget
;
59 /// Get the number of chromaticity channels.
60 int tcIlluminantDirection::numChromaticities() const
62 return m_chromaticities
.size();
65 /// Get the list of chromaticitiy channels.
66 const QList
<tcChannel
*>& tcIlluminantDirection::chromaticities() const
68 return m_chromaticities
;
71 /// Get the illuminant direction.
72 const maths::VarVector
<float>& tcIlluminantDirection::illuminantDirection() const
74 return m_illuminantDirection
;
78 * Main image interface
81 tcChannelConfigWidget
* tcIlluminantDirection::configWidget()
83 if (0 == m_configWidget
)
85 m_configWidget
= new tcChannelConfigWidget();
86 m_configWidget
->setWindowTitle(tr("%1 Configuration").arg(name()));
88 QVBoxLayout
* layout
= new QVBoxLayout(m_configWidget
);
90 // Create a button which triggers an illuminant direction reset.
91 QPushButton
* btnReset
= new QPushButton(tr("Reset illuminant direction"), m_configWidget
);
92 layout
->addWidget(btnReset
);
93 connect(btnReset
, SIGNAL(clicked(bool)), this, SLOT(resetIlluminantDirection()));
95 // Create a button which triggers texture point request.
96 QPushButton
* btnNewShadowNonShadow
= new QPushButton(tr("Choose Shadow/Non-Shadow transition"), m_configWidget
);
97 layout
->addWidget(btnNewShadowNonShadow
);
98 connect(btnNewShadowNonShadow
, SIGNAL(clicked(bool)), this, SLOT(startShadowNonShadow()));
100 return m_configWidget
;
107 /// Reset the illuminant direction vector.
108 void tcIlluminantDirection::resetIlluminantDirection()
110 for (int i
= 0; i
< m_illuminantDirection
.length(); ++i
)
112 m_illuminantDirection
[i
] = 1.0f
;
114 m_illuminantDirectionSamples
= 0;
116 m_configWidget
->requestRedraw();
119 /// Start choosing a shadow / non shadow pair.
120 void tcIlluminantDirection::startShadowNonShadow()
122 Q_ASSERT(0 != m_configWidget
);
123 m_configWidget
->requestTexturePoint(this, SLOT(selectShadowPoint(const maths::Vector
<2,float>&)));
126 /// New shadow point.
127 void tcIlluminantDirection::selectShadowPoint(const maths::Vector
<2,float>& point
)
129 Q_ASSERT(0 != m_configWidget
);
130 m_shadowPoint
= point
;
131 m_configWidget
->requestTexturePoint(this, SLOT(selectNonShadowPoint(const maths::Vector
<2,float>&)));
134 /// New non-shadow point.
135 void tcIlluminantDirection::selectNonShadowPoint(const maths::Vector
<2,float>& point
)
137 Q_ASSERT(0 != m_configWidget
);
138 // Find the direction between the log chromaticities of the two points
139 for (int i
= 0; i
< m_chromaticities
.size(); ++i
)
141 tcChannel
* channel
= m_chromaticities
[i
];
142 Reference
<tcAbstractPixelData
> pixelData
= channel
->portion();
145 float delta
= pixelData
->sampleFloat(point
[0], 1.0f
- point
[1])
146 - pixelData
->sampleFloat(m_shadowPoint
[0], 1.0f
- m_shadowPoint
[1]);
147 m_illuminantDirection
[i
] *= m_illuminantDirectionSamples
;
148 m_illuminantDirection
[i
] += delta
;
149 m_illuminantDirection
[i
] /= m_illuminantDirectionSamples
+1;
152 m_illuminantDirection
.normalize();
153 ++m_illuminantDirectionSamples
;
155 m_configWidget
->requestRedraw();
159 * Interface for derived class to implement
162 void tcIlluminantDirection::roundPortion(double* x1
, double* y1
, double* x2
, double* y2
)
164 if (!m_chromaticities
.empty())
166 m_chromaticities
[0]->roundPortion(x1
,y1
,x2
,y2
);
170 void tcIlluminantDirection::loadPortions(double x1
, double y1
, double x2
, double y2
, bool changed
)
172 QList
< Reference
< tcPixelData
<float> > > chromaticityData
;
175 foreach (tcChannel
* channel
, m_chromaticities
)
177 /// @todo Make this neater
182 Reference
< tcPixelData
<float> > pixelData
= dynamicCast
< tcPixelData
<GLfloat
>* >(channel
->portion(&x1a
,&y1a
,&x2a
,&y2a
));
183 chromaticityData
+= pixelData
;
184 Q_ASSERT(0 != pixelData
);
185 // Ensure each channel is the same resolution
188 width
= pixelData
->width();
192 Q_ASSERT(width
== pixelData
->width());
196 height
= pixelData
->height();
200 Q_ASSERT(height
== pixelData
->height());
203 loadPortions(chromaticityData
, width
, height
);