Test change - can I push OK?
[kdeedu-porting.git] / kalzium / src / spectrumwidget.cpp
blob4cc19f6ff1d07d095df2bae0e6cbb3e2f8d219f6
1 /***************************************************************************
2 * Copyright (C) 2005, 2006 by Carsten Niehaus *
3 * cniehaus@kde.org *
4 *
5 * *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
20 ***************************************************************************/
21 #include "spectrumwidget.h"
22 #include "spectrum.h"
23 #include "kalziumutils.h"
25 #include <element.h>
27 #include <kdebug.h>
28 #include <klocale.h>
29 #include <math.h>
31 #include <QCursor>
32 #include <QKeyEvent>
33 #include <QSizePolicy>
34 #include <QPainter>
35 #include <QPixmap>
37 #include <qglobal.h>
38 #if defined(Q_OS_SOLARIS)
39 #include <ieeefp.h>
40 #endif
42 SpectrumWidget::SpectrumWidget( QWidget *parent )
43 : QWidget( parent )
45 startValue = 0;
46 endValue = 0;
48 m_LMBPointCurrent.setX( -1 );
49 m_LMBPointPress.setX( -1 );
51 m_realHeight = 200;
53 Gamma = 0.8;
54 IntensityMax = 255;
56 setType( EmissionSpectrum );
58 setMinimumSize( 400, 230 );
59 setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding );
60 setAttribute( Qt::WA_OpaquePaintEvent, true );
63 void SpectrumWidget::paintEvent( QPaintEvent * /*e*/ )
65 if ( !m_spectrum )
66 return;
68 m_pixmap = QPixmap( width(), height() );
69 m_pixmap.fill( this, width(), height() );
71 QPainter p;
72 p.begin( &m_pixmap );
73 p.fillRect( 0, 0, width(), m_realHeight, Qt::black );
75 paintBands( &p );
77 drawTickmarks( &p );
79 if ( m_LMBPointPress.x() != -1 && m_LMBPointCurrent.x() != -1 )
80 drawZoomLine( &p );
82 p.end();
84 QPainter p2(this);
85 p2.drawPixmap(0, 0, m_pixmap);
88 void SpectrumWidget::drawZoomLine( QPainter* p )
90 p->setPen( Qt::white );
91 p->drawLine( m_LMBPointPress.x(), m_LMBPointPress.y(), m_LMBPointCurrent.x(), m_LMBPointPress.y() );
92 p->drawLine( m_LMBPointCurrent.x(), m_LMBPointPress.y()+10, m_LMBPointCurrent.x(), m_LMBPointPress.y()-10 );
93 p->drawLine( m_LMBPointPress.x(), m_LMBPointPress.y()+10, m_LMBPointPress.x(), m_LMBPointPress.y()-10 );
96 void SpectrumWidget::paintBands( QPainter* p )
98 if ( m_type == AbsorptionSpectrum )
100 for ( double va = startValue; va <= endValue ; va += 0.1 )
102 int x = xPos( va );
103 p->setPen( linecolor( va ) );
104 p->drawLine( x,0,x, m_realHeight );
107 p->setPen( Qt::black );
110 int i = 0;
111 int x = 0;
112 int temp = 0;
114 foreach ( Spectrum::peak * peak , m_spectrum->peaklist() )
116 if ( peak->wavelength < startValue || peak->wavelength > endValue )
117 continue;
119 x = xPos( peak->wavelength );
121 temp = 0;
123 switch ( m_type )
125 case EmissionSpectrum:
126 p->setPen( linecolor( peak->wavelength ) );
127 p->drawLine( x,0,x, m_realHeight-1 );
129 p->setPen( Qt::black );
130 p->drawLine( x,m_realHeight,x, m_realHeight );
131 break;
133 case AbsorptionSpectrum:
134 p->setPen( Qt::black );
135 p->drawLine( x,0,x, m_realHeight-1 );
136 break;
139 i++;
143 QColor SpectrumWidget::linecolor( double spectrum )
145 int r,g,b;
146 wavelengthToRGB( spectrum, r,g,b );
148 QColor c( r,g,b );
149 return c;
153 void SpectrumWidget::wavelengthToRGB( double wavelength, int& r, int& g, int& b )
155 double blue = 0.0, green = 0.0, red = 0.0, factor = 0.0;
157 int wavelength_ = ( int ) floor( wavelength );
158 if ( wavelength_ < 380 || wavelength_ > 780 )
160 //make everything white
161 r = g = b = 255;
162 return;
164 else if ( wavelength_ > 380 && wavelength_ < 439 )
166 red = -( wavelength-440 ) / ( 440-380 );
167 green = 0.0;
168 blue = 1.0;
170 else if ( wavelength_ > 440 && wavelength_ < 489 )
172 red = 0.0;
173 green = ( wavelength-440 ) / ( 490-440 );
174 blue = 1.0;
176 else if ( wavelength_ > 490 && wavelength_ < 509 )
178 red = 0.0;
179 green = 1.0;
180 blue = -( wavelength-510 ) / ( 510-490 );
182 else if ( wavelength_ > 510 && wavelength_ < 579 )
184 red = ( wavelength-510 ) / ( 580-510 );
185 green = 1.0;
186 blue = 0.0;
188 else if ( wavelength_ > 580 && wavelength_ < 644 )
190 red = 1.0;
191 green = -( wavelength-645 ) / ( 645-580 );
192 blue = 0.0;
194 else if ( wavelength_ > 645 && wavelength_ < 780 )
196 red = 1.0;
197 green = 0.0;
198 blue = 0.0;
201 if ( wavelength_ > 380 && wavelength_ < 419 )
202 factor = 0.3 + 0.7*( wavelength - 380 ) / ( 420 - 380 );
203 else if ( wavelength_ > 420 && wavelength_ < 700 )
204 factor = 1.0;
205 else if ( wavelength_ > 701 && wavelength_ < 780 )
206 factor = 0.3 + 0.7*( 780 - wavelength ) / ( 780 - 700 );
207 else
208 factor = 0.0;
210 r = Adjust( red, factor );
211 g = Adjust( green, factor );
212 b = Adjust( blue, factor );
215 int SpectrumWidget::Adjust( double color, double factor )
217 if ( color == 0.0 )
218 return 0;
219 else
220 return qRound( IntensityMax * pow( color*factor, Gamma ));
223 void SpectrumWidget::drawTickmarks( QPainter* p )
225 //the size of the text on the tickmarks
226 const int space = 20;
228 //the distance between the tickmarks in pixel
229 const int d = 10;
231 //the total number of tickmarks to draw (small and long)
232 const int numberOfTickmarks = ( int )floor( width()/d );
234 double pos = 0.0;
236 for ( int i = 0; i < numberOfTickmarks; i++ )
238 if( i%5 == 0 )
239 {//long tickmarks plus text
240 p->drawLine( i*d, m_realHeight, i*d, m_realHeight+10 );
241 if ( i%10 == 0 &&
242 i*d > space &&
243 i*d < width()-space )
245 pos = ( double ) ( i*d )/width();
246 p->fillRect( i*d-space, m_realHeight+12, 2*space, 15, Qt::white );
247 p->drawText( i*d-space, m_realHeight+12, 2*space, 15, Qt::AlignCenter, QString::number( KalziumUtils::strippedValue( Wavelength( pos ) ) ) );
250 else {//small tickmarks
251 p->drawLine( i*d, m_realHeight, i*d, m_realHeight+5 );
256 void SpectrumWidget::keyPressEvent( QKeyEvent *e )
258 switch ( e->key() )
260 case Qt::Key_Plus:
261 slotZoomIn();
262 break;
263 case Qt::Key_Minus:
264 slotZoomOut();
265 break;
269 void SpectrumWidget::slotZoomOut()
271 kDebug() << "SpectrumWidget::slotZoomOut() "<< startValue << ":: "<< endValue;
273 double diff = endValue - startValue;
275 double offset = diff * 0.05;
277 endValue = endValue + offset;
278 startValue = startValue - offset;
280 //check for invalid values
281 if ( startValue < 0.0 )
282 startValue = 0.0;
284 if ( endValue > 800.0 )
285 endValue = 800.0;
287 setBorders( startValue, endValue );
290 void SpectrumWidget::setBorders( double left, double right )
292 kDebug() << "setBorders " << left << ".."<< right;
294 startValue = left;
295 endValue = right;
297 //round the startValue down and the endValue up
298 emit bordersChanged( int(startValue+0.5), int(endValue+0.5) );
300 update();
303 void SpectrumWidget::slotZoomIn()
305 kDebug() << "SpectrumWidget::slotZoomIn() "<< startValue << ":: "<< endValue;
307 double diff = endValue - startValue;
309 double offset = diff * 0.05;
311 endValue = endValue - offset;
312 startValue = startValue + offset;
314 setBorders( startValue, endValue );
317 void SpectrumWidget::mouseMoveEvent( QMouseEvent *e )
319 m_LMBPointCurrent = e->pos();
320 update();
323 void SpectrumWidget::mousePressEvent( QMouseEvent *e )
325 if ( e->button() == Qt::LeftButton )
326 m_LMBPointPress = e->pos();
327 if ( e->button() == Qt::RightButton )
328 slotZoomOut();
330 findPeakFromMouseposition( Wavelength( ( double )e->pos().x()/width() ) );
333 void SpectrumWidget::findPeakFromMouseposition( double wavelength )
335 kDebug() << "SpectrumWidget::findPeakFromMouseposition()";
336 Spectrum::peak *peak = NULL;
338 //find the difference in percent (1.0 is 100%, 0.1 is 10%)
339 double dif = 0.0;
341 bool foundWavelength = false;
343 //find the highest intensity
344 foreach( Spectrum::peak *currentPeak, m_spectrum->peaklist() )
346 double thisdif = currentPeak->wavelength / wavelength;
348 if ( thisdif < 0.9 || thisdif > 1.1 )
349 continue;
351 if ( thisdif > 1.0 ){//convert for example 1.3 to 0.7
352 thisdif = thisdif-1;
353 thisdif = 1-thisdif;
356 if ( thisdif > dif )
358 dif = thisdif;
359 peak = currentPeak;
360 foundWavelength = true;
364 if ( foundWavelength )
365 emit peakSelected(peak);
368 void SpectrumWidget::mouseReleaseEvent( QMouseEvent *e )
370 if ( e->button() == Qt::LeftButton )
372 int left = (int)Wavelength( ( double )m_LMBPointPress.x()/width() );
373 int right = (int)Wavelength( ( double )e->pos().x()/width() );
375 if ( left == right )
376 return;
378 if ( left > right )
379 setBorders( right, left );
380 else
381 setBorders( left, right );
384 m_LMBPointPress.setX( -1 );
385 m_LMBPointCurrent.setX( -1 );
388 void SpectrumWidget::restart()
390 //set the minimum and maximum peak to the min/max wavelenght
391 //plus/minus ten. This makes then always visible
392 setBorders(m_spectrum->minPeak()-10.0, m_spectrum->maxPeak()+10.0);
395 #include "spectrumwidget.moc"