update dev300-m58
[ooovba.git] / extensions / source / scanner / grid.cxx
blob5f1816d29fee47f38609746c6f075c0e28abd588
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: grid.cxx,v $
10 * $Revision: 1.12 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_extensions.hxx"
33 #include <grid.hrc>
34 #include <cstdio>
35 #include <math.h> // for M_LN10 and M_E
37 #define _USE_MATH_DEFINES
38 #include <cmath>
39 #undef _USE_MATH_DEFINES
41 #include <grid.hxx>
43 // for ::std::sort
44 #include <algorithm>
46 ResId SaneResId( sal_uInt32 );
48 /***********************************************************************
50 * GridWindow
52 ***********************************************************************/
54 // ---------------------------------------------------------------------
56 GridWindow::GridWindow(double* pXValues, double* pYValues, int nValues, Window* pParent, BOOL bCutValues )
57 : ModalDialog( pParent, SaneResId( GRID_DIALOG ) ),
58 m_aGridArea( 50, 15, 100, 100 ),
59 m_pXValues( pXValues ),
60 m_pOrigYValues( pYValues ),
61 m_nValues( nValues ),
62 m_pNewYValues( NULL ),
63 m_bCutValues( bCutValues ),
64 m_aHandles(),
65 m_nDragIndex( 0xffffffff ),
66 m_aMarkerBitmap( Bitmap( SaneResId( GRID_DIALOG_HANDLE_BMP ) ), Color( 255, 255, 255 ) ),
67 m_aOKButton( this, SaneResId( GRID_DIALOG_OK_BTN ) ),
68 m_aCancelButton( this, SaneResId( GRID_DIALOG_CANCEL_BTN ) ),
69 m_aResetTypeBox( this, SaneResId( GRID_DIALOG_TYPE_BOX ) ),
70 m_aResetButton( this, SaneResId( GRID_DIALOG_RESET_BTN ) )
72 USHORT nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_LINEAR_ASCENDING ) ) );
73 m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_LINEAR_ASCENDING );
75 nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_LINEAR_DESCENDING ) ) );
76 m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_LINEAR_DESCENDING );
78 nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_RESET ) ) );
79 m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_RESET );
81 nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_EXPONENTIAL ) ) );
82 m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_EXPONENTIAL );
84 m_aResetTypeBox.SelectEntryPos( 0 );
86 m_aResetButton.SetClickHdl( LINK( this, GridWindow, ClickButtonHdl ) );
88 SetMapMode( MapMode( MAP_PIXEL ) );
89 Size aSize = GetOutputSizePixel();
90 Size aBtnSize = m_aOKButton.GetOutputSizePixel();
91 m_aGridArea.setWidth( aSize.Width() - aBtnSize.Width() - 80 );
92 m_aGridArea.setHeight( aSize.Height() - 40 );
94 if( m_pOrigYValues && m_nValues )
96 m_pNewYValues = new double[ m_nValues ];
97 memcpy( m_pNewYValues, m_pOrigYValues, sizeof( double ) * m_nValues );
100 setBoundings( 0, 0, 1023, 1023 );
101 computeExtremes();
103 // create left and right marker as first and last entry
104 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
105 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
106 m_aHandles.push_back(impHandle(transform(findMinX(), findMinY()), m_BmOffX, m_BmOffY));
107 m_aHandles.push_back(impHandle(transform(findMaxX(), findMaxY()), m_BmOffX, m_BmOffY));
109 FreeResource();
112 // ---------------------------------------------------------------------
114 GridWindow::~GridWindow()
116 if( m_pNewYValues )
117 delete [] m_pNewYValues;
120 // ---------------------------------------------------------------------
122 double GridWindow::findMinX()
124 if( ! m_pXValues )
125 return 0.0;
126 double fMin = m_pXValues[0];
127 for( int i = 1; i < m_nValues; i++ )
128 if( m_pXValues[ i ] < fMin )
129 fMin = m_pXValues[ i ];
130 return fMin;
133 // ---------------------------------------------------------------------
135 double GridWindow::findMinY()
137 if( ! m_pNewYValues )
138 return 0.0;
139 double fMin = m_pNewYValues[0];
140 for( int i = 1; i < m_nValues; i++ )
141 if( m_pNewYValues[ i ] < fMin )
142 fMin = m_pNewYValues[ i ];
143 return fMin;
146 // ---------------------------------------------------------------------
148 double GridWindow::findMaxX()
150 if( ! m_pXValues )
151 return 0.0;
152 double fMax = m_pXValues[0];
153 for( int i = 1; i < m_nValues; i++ )
154 if( m_pXValues[ i ] > fMax )
155 fMax = m_pXValues[ i ];
156 return fMax;
159 // ---------------------------------------------------------------------
161 double GridWindow::findMaxY()
163 if( ! m_pNewYValues )
164 return 0.0;
165 double fMax = m_pNewYValues[0];
166 for( int i = 1; i < m_nValues; i++ )
167 if( m_pNewYValues[ i ] > fMax )
168 fMax = m_pNewYValues[ i ];
169 return fMax;
172 // ---------------------------------------------------------------------
174 void GridWindow::computeExtremes()
176 if( m_nValues && m_pXValues && m_pOrigYValues )
178 m_fMaxX = m_fMinX = m_pXValues[0];
179 m_fMaxY = m_fMinY = m_pOrigYValues[0];
180 for( int i = 1; i < m_nValues; i++ )
182 if( m_pXValues[ i ] > m_fMaxX )
183 m_fMaxX = m_pXValues[ i ];
184 else if( m_pXValues[ i ] < m_fMinX )
185 m_fMinX = m_pXValues[ i ];
186 if( m_pOrigYValues[ i ] > m_fMaxY )
187 m_fMaxY = m_pOrigYValues[ i ];
188 else if( m_pOrigYValues[ i ] < m_fMinY )
189 m_fMinY = m_pOrigYValues[ i ];
191 setBoundings( m_fMinX, m_fMinY, m_fMaxX, m_fMaxY );
195 // ---------------------------------------------------------------------
197 Point GridWindow::transform( double x, double y )
199 Point aRet;
201 aRet.X() = (long)( ( x - m_fMinX ) *
202 (double)m_aGridArea.GetWidth() / ( m_fMaxX - m_fMinX )
203 + m_aGridArea.Left() );
204 aRet.Y() = (long)(
205 m_aGridArea.Bottom() -
206 ( y - m_fMinY ) *
207 (double)m_aGridArea.GetHeight() / ( m_fMaxY - m_fMinY ) );
208 return aRet;
211 // ---------------------------------------------------------------------
213 void GridWindow::transform( const Point& rOriginal, double& x, double& y )
215 x = ( rOriginal.X() - m_aGridArea.Left() ) * (m_fMaxX - m_fMinX) / (double)m_aGridArea.GetWidth() + m_fMinX;
216 y = ( m_aGridArea.Bottom() - rOriginal.Y() ) * (m_fMaxY - m_fMinY) / (double)m_aGridArea.GetHeight() + m_fMinY;
219 // ---------------------------------------------------------------------
221 void GridWindow::drawLine( double x1, double y1, double x2, double y2 )
223 DrawLine( transform( x1, y1 ), transform( x2, y2 ) );
226 // ---------------------------------------------------------------------
228 void GridWindow::computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut )
230 // get a nice chunk size like 10, 100, 25 or such
231 fChunkOut = ( fMax - fMin ) / 6.0;
232 int logchunk = (int)std::log10( fChunkOut );
233 int nChunk = (int)( fChunkOut / std::exp( (double)(logchunk-1) * M_LN10 ) );
234 if( nChunk >= 75 )
235 nChunk = 100;
236 else if( nChunk >= 35 )
237 nChunk = 50;
238 else if ( nChunk > 20 )
239 nChunk = 25;
240 else if ( nChunk >= 13 )
241 nChunk = 20;
242 else if( nChunk > 5 )
243 nChunk = 10;
244 else
245 nChunk = 5;
246 fChunkOut = (double) nChunk * exp( (double)(logchunk-1) * M_LN10 );
247 // compute whole chunks fitting into fMin
248 nChunk = (int)( fMin / fChunkOut );
249 fMinChunkOut = (double)nChunk * fChunkOut;
250 while( fMinChunkOut < fMin )
251 fMinChunkOut += fChunkOut;
254 // ---------------------------------------------------------------------
256 void GridWindow::computeNew()
258 if(2L == m_aHandles.size())
260 // special case: only left and right markers
261 double xleft, yleft;
262 double xright, yright;
263 transform(m_aHandles[0L].maPos, xleft, yleft);
264 transform(m_aHandles[1L].maPos, xright, yright );
265 double factor = (yright-yleft)/(xright-xleft);
266 for( int i = 0; i < m_nValues; i++ )
268 m_pNewYValues[ i ] = yleft + ( m_pXValues[ i ] - xleft )*factor;
271 else
273 // sort markers
274 std::sort(m_aHandles.begin(), m_aHandles.end());
275 const int nSorted = m_aHandles.size();
276 int i;
278 // get node arrays
279 double* nodex = new double[ nSorted ];
280 double* nodey = new double[ nSorted ];
282 for( i = 0L; i < nSorted; i++ )
283 transform( m_aHandles[i].maPos, nodex[ i ], nodey[ i ] );
285 for( i = 0; i < m_nValues; i++ )
287 double x = m_pXValues[ i ];
288 m_pNewYValues[ i ] = interpolate( x, nodex, nodey, nSorted );
289 if( m_bCutValues )
291 if( m_pNewYValues[ i ] > m_fMaxY )
292 m_pNewYValues[ i ] = m_fMaxY;
293 else if( m_pNewYValues[ i ] < m_fMinY )
294 m_pNewYValues[ i ] = m_fMinY;
298 delete [] nodex;
299 delete [] nodey;
303 // ---------------------------------------------------------------------
305 double GridWindow::interpolate(
306 double x,
307 double* pNodeX,
308 double* pNodeY,
309 int nNodes )
311 // compute Lagrange interpolation
312 double ret = 0;
313 for( int i = 0; i < nNodes; i++ )
315 double sum = pNodeY[ i ];
316 for( int n = 0; n < nNodes; n++ )
318 if( n != i )
320 sum *= x - pNodeX[ n ];
321 sum /= pNodeX[ i ] - pNodeX[ n ];
324 ret += sum;
326 return ret;
329 // ---------------------------------------------------------------------
331 void GridWindow::setBoundings( double fMinX, double fMinY, double fMaxX, double fMaxY )
333 m_fMinX = fMinX;
334 m_fMinY = fMinY;
335 m_fMaxX = fMaxX;
336 m_fMaxY = fMaxY;
338 computeChunk( m_fMinX, m_fMaxX, m_fChunkX, m_fMinChunkX );
339 computeChunk( m_fMinY, m_fMaxY, m_fChunkY, m_fMinChunkY );
342 // ---------------------------------------------------------------------
344 void GridWindow::drawGrid()
346 char pBuf[256];
347 SetLineColor( Color( COL_BLACK ) );
348 // draw vertical lines
349 for( double fX = m_fMinChunkX; fX < m_fMaxX; fX += m_fChunkX )
351 drawLine( fX, m_fMinY, fX, m_fMaxY );
352 // draw tickmarks
353 Point aPt = transform( fX, m_fMinY );
354 std::sprintf( pBuf, "%g", fX );
355 String aMark( pBuf, gsl_getSystemTextEncoding() );
356 Size aTextSize( GetTextWidth( aMark ), GetTextHeight() );
357 aPt.X() -= aTextSize.Width()/2;
358 aPt.Y() += aTextSize.Height()/2;
359 DrawText( aPt, aMark );
361 // draw horizontal lines
362 for( double fY = m_fMinChunkY; fY < m_fMaxY; fY += m_fChunkY )
364 drawLine( m_fMinX, fY, m_fMaxX, fY );
365 // draw tickmarks
366 Point aPt = transform( m_fMinX, fY );
367 std::sprintf( pBuf, "%g", fY );
368 String aMark( pBuf, gsl_getSystemTextEncoding() );
369 Size aTextSize( GetTextWidth( aMark ), GetTextHeight() );
370 aPt.X() -= aTextSize.Width() + 2;
371 aPt.Y() -= aTextSize.Height()/2;
372 DrawText( aPt, aMark );
375 // draw boundings
376 drawLine( m_fMinX, m_fMinY, m_fMaxX, m_fMinY );
377 drawLine( m_fMinX, m_fMaxY, m_fMaxX, m_fMaxY );
378 drawLine( m_fMinX, m_fMinY, m_fMinX, m_fMaxY );
379 drawLine( m_fMaxX, m_fMinY, m_fMaxX, m_fMaxY );
382 // ---------------------------------------------------------------------
384 void GridWindow::drawOriginal()
386 if( m_nValues && m_pXValues && m_pOrigYValues )
388 SetLineColor( Color( COL_RED ) );
389 for( int i = 0; i < m_nValues-1; i++ )
391 drawLine( m_pXValues[ i ], m_pOrigYValues[ i ],
392 m_pXValues[ i+1 ], m_pOrigYValues[ i+1 ] );
397 // ---------------------------------------------------------------------
399 void GridWindow::drawNew()
401 if( m_nValues && m_pXValues && m_pNewYValues )
403 SetClipRegion( m_aGridArea );
404 SetLineColor( Color( COL_YELLOW ) );
405 for( int i = 0; i < m_nValues-1; i++ )
407 drawLine( m_pXValues[ i ], m_pNewYValues[ i ],
408 m_pXValues[ i+1 ], m_pNewYValues[ i+1 ] );
410 SetClipRegion();
414 // ---------------------------------------------------------------------
416 void GridWindow::drawHandles()
418 for(sal_uInt32 i(0L); i < m_aHandles.size(); i++)
420 m_aHandles[i].draw(*this, m_aMarkerBitmap);
424 // ---------------------------------------------------------------------
426 void GridWindow::Paint( const Rectangle& rRect )
428 ModalDialog::Paint( rRect );
429 drawGrid();
430 drawOriginal();
431 drawNew();
432 drawHandles();
435 // ---------------------------------------------------------------------
437 void GridWindow::MouseMove( const MouseEvent& rEvt )
439 if( rEvt.GetButtons() == MOUSE_LEFT && m_nDragIndex != 0xffffffff )
441 Point aPoint( rEvt.GetPosPixel() );
443 if( m_nDragIndex == 0L || m_nDragIndex == m_aHandles.size() - 1L)
445 aPoint.X() = m_aHandles[m_nDragIndex].maPos.X();
447 else
449 if(aPoint.X() < m_aGridArea.Left())
450 aPoint.X() = m_aGridArea.Left();
451 else if(aPoint.X() > m_aGridArea.Right())
452 aPoint.X() = m_aGridArea.Right();
455 if( aPoint.Y() < m_aGridArea.Top() )
456 aPoint.Y() = m_aGridArea.Top();
457 else if( aPoint.Y() > m_aGridArea.Bottom() )
458 aPoint.Y() = m_aGridArea.Bottom();
460 if( aPoint != m_aHandles[m_nDragIndex].maPos )
462 m_aHandles[m_nDragIndex].maPos = aPoint;
463 Invalidate( m_aGridArea );
467 ModalDialog::MouseMove( rEvt );
470 // ---------------------------------------------------------------------
472 void GridWindow::MouseButtonUp( const MouseEvent& rEvt )
474 if( rEvt.GetButtons() == MOUSE_LEFT )
476 if( m_nDragIndex != 0xffffffff )
478 m_nDragIndex = 0xffffffff;
479 computeNew();
480 Invalidate( m_aGridArea );
481 Paint( m_aGridArea );
485 ModalDialog::MouseButtonUp( rEvt );
488 // ---------------------------------------------------------------------
490 void GridWindow::MouseButtonDown( const MouseEvent& rEvt )
492 Point aPoint( rEvt.GetPosPixel() );
493 sal_uInt32 nMarkerIndex = 0xffffffff;
495 for(sal_uInt32 a(0L); nMarkerIndex == 0xffffffff && a < m_aHandles.size(); a++)
497 if(m_aHandles[a].isHit(*this, aPoint))
499 nMarkerIndex = a;
503 if( rEvt.GetButtons() == MOUSE_LEFT )
505 // user wants to drag a button
506 if( nMarkerIndex != 0xffffffff )
508 m_nDragIndex = nMarkerIndex;
511 else if( rEvt.GetButtons() == MOUSE_RIGHT )
513 // user wants to add/delete a button
514 if( nMarkerIndex != 0xffffffff )
516 if( nMarkerIndex != 0L && nMarkerIndex != m_aHandles.size() - 1L)
518 // delete marker under mouse
519 if( m_nDragIndex == nMarkerIndex )
520 m_nDragIndex = 0xffffffff;
522 m_aHandles.erase(m_aHandles.begin() + nMarkerIndex);
525 else
527 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
528 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
529 m_aHandles.push_back(impHandle(aPoint, m_BmOffX, m_BmOffY));
532 computeNew();
533 Invalidate( m_aGridArea );
534 Paint( m_aGridArea );
537 ModalDialog::MouseButtonDown( rEvt );
540 // ---------------------------------------------------------------------
542 IMPL_LINK( GridWindow, ClickButtonHdl, Button*, pButton )
544 if( pButton == &m_aResetButton )
546 int nType = (int)(sal_IntPtr)m_aResetTypeBox.GetEntryData( m_aResetTypeBox.GetSelectEntryPos() );
547 switch( nType )
549 case RESET_TYPE_LINEAR_ASCENDING:
551 for( int i = 0; i < m_nValues; i++ )
553 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
556 break;
557 case RESET_TYPE_LINEAR_DESCENDING:
559 for( int i = 0; i < m_nValues; i++ )
561 m_pNewYValues[ i ] = m_fMaxY - (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
564 break;
565 case RESET_TYPE_RESET:
567 if( m_pOrigYValues && m_pNewYValues && m_nValues )
568 memcpy( m_pNewYValues, m_pOrigYValues, m_nValues*sizeof(double) );
570 break;
571 case RESET_TYPE_EXPONENTIAL:
573 for( int i = 0; i < m_nValues; i++ )
575 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)*(std::exp((m_pXValues[i]-m_fMinX)/(m_fMaxX-m_fMinX))-1.0)/(M_E-1.0);
578 break;
580 default:
581 break;
584 for(sal_uInt32 i(0L); i < m_aHandles.size(); i++)
586 // find nearest xvalue
587 double x, y;
588 transform( m_aHandles[i].maPos, x, y );
589 int nIndex = 0;
590 double delta = std::fabs( x-m_pXValues[0] );
591 for( int n = 1; n < m_nValues; n++ )
593 if( delta > std::fabs( x - m_pXValues[ n ] ) )
595 delta = std::fabs( x - m_pXValues[ n ] );
596 nIndex = n;
599 if( 0 == i )
600 m_aHandles[i].maPos = transform( m_fMinX, m_pNewYValues[ nIndex ] );
601 else if( m_aHandles.size() - 1L == i )
602 m_aHandles[i].maPos = transform( m_fMaxX, m_pNewYValues[ nIndex ] );
603 else
604 m_aHandles[i].maPos = transform( m_pXValues[ nIndex ], m_pNewYValues[ nIndex ] );
607 Invalidate( m_aGridArea );
608 Paint(Rectangle());
610 return 0;