00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "precompiled_extensions.hxx"
00038 #include <grid.hrc>
00039 #include <cstdio>
00040
00041 #define _USE_MATH_DEFINES
00042 #include <cmath>
00043 #undef _USE_MATH_DEFINES
00044
00045 #include <grid.hxx>
00046
00047
00048 #include <algorithm>
00049
00050 ResId SaneResId( sal_uInt32 );
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 GridWindow::GridWindow(double* pXValues, double* pYValues, int nValues, Window* pParent, BOOL bCutValues )
00061 : ModalDialog( pParent, SaneResId( GRID_DIALOG ) ),
00062 m_aGridArea( 50, 15, 100, 100 ),
00063 m_pXValues( pXValues ),
00064 m_pOrigYValues( pYValues ),
00065 m_nValues( nValues ),
00066 m_pNewYValues( NULL ),
00067 m_bCutValues( bCutValues ),
00068 m_aHandles(),
00069 m_nDragIndex( 0xffffffff ),
00070 m_aMarkerBitmap( Bitmap( SaneResId( GRID_DIALOG_HANDLE_BMP ) ), Color( 255, 255, 255 ) ),
00071 m_aOKButton( this, SaneResId( GRID_DIALOG_OK_BTN ) ),
00072 m_aCancelButton( this, SaneResId( GRID_DIALOG_CANCEL_BTN ) ),
00073 m_aResetTypeBox( this, SaneResId( GRID_DIALOG_TYPE_BOX ) ),
00074 m_aResetButton( this, SaneResId( GRID_DIALOG_RESET_BTN ) )
00075 {
00076 USHORT nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_LINEAR_ASCENDING ) ) );
00077 m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_LINEAR_ASCENDING );
00078
00079 nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_LINEAR_DESCENDING ) ) );
00080 m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_LINEAR_DESCENDING );
00081
00082 nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_RESET ) ) );
00083 m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_RESET );
00084
00085 nPos = m_aResetTypeBox.InsertEntry( String( SaneResId( RESET_TYPE_EXPONENTIAL ) ) );
00086 m_aResetTypeBox.SetEntryData( nPos, (void *)RESET_TYPE_EXPONENTIAL );
00087
00088 m_aResetTypeBox.SelectEntryPos( 0 );
00089
00090 m_aResetButton.SetClickHdl( LINK( this, GridWindow, ClickButtonHdl ) );
00091
00092 SetMapMode( MapMode( MAP_PIXEL ) );
00093 Size aSize = GetOutputSizePixel();
00094 Size aBtnSize = m_aOKButton.GetOutputSizePixel();
00095 m_aGridArea.setWidth( aSize.Width() - aBtnSize.Width() - 80 );
00096 m_aGridArea.setHeight( aSize.Height() - 40 );
00097
00098 if( m_pOrigYValues && m_nValues )
00099 {
00100 m_pNewYValues = new double[ m_nValues ];
00101 memcpy( m_pNewYValues, m_pOrigYValues, sizeof( double ) * m_nValues );
00102 }
00103
00104 setBoundings( 0, 0, 1023, 1023 );
00105 computeExtremes();
00106
00107
00108 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
00109 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
00110 m_aHandles.push_back(impHandle(transform(findMinX(), findMinY()), m_BmOffX, m_BmOffY));
00111 m_aHandles.push_back(impHandle(transform(findMaxX(), findMaxY()), m_BmOffX, m_BmOffY));
00112
00113 FreeResource();
00114 }
00115
00116
00117
00118 GridWindow::~GridWindow()
00119 {
00120 if( m_pNewYValues )
00121 delete [] m_pNewYValues;
00122 }
00123
00124
00125
00126 double GridWindow::findMinX()
00127 {
00128 if( ! m_pXValues )
00129 return 0.0;
00130 double fMin = m_pXValues[0];
00131 for( int i = 1; i < m_nValues; i++ )
00132 if( m_pXValues[ i ] < fMin )
00133 fMin = m_pXValues[ i ];
00134 return fMin;
00135 }
00136
00137
00138
00139 double GridWindow::findMinY()
00140 {
00141 if( ! m_pNewYValues )
00142 return 0.0;
00143 double fMin = m_pNewYValues[0];
00144 for( int i = 1; i < m_nValues; i++ )
00145 if( m_pNewYValues[ i ] < fMin )
00146 fMin = m_pNewYValues[ i ];
00147 return fMin;
00148 }
00149
00150
00151
00152 double GridWindow::findMaxX()
00153 {
00154 if( ! m_pXValues )
00155 return 0.0;
00156 double fMax = m_pXValues[0];
00157 for( int i = 1; i < m_nValues; i++ )
00158 if( m_pXValues[ i ] > fMax )
00159 fMax = m_pXValues[ i ];
00160 return fMax;
00161 }
00162
00163
00164
00165 double GridWindow::findMaxY()
00166 {
00167 if( ! m_pNewYValues )
00168 return 0.0;
00169 double fMax = m_pNewYValues[0];
00170 for( int i = 1; i < m_nValues; i++ )
00171 if( m_pNewYValues[ i ] > fMax )
00172 fMax = m_pNewYValues[ i ];
00173 return fMax;
00174 }
00175
00176
00177
00178 void GridWindow::computeExtremes()
00179 {
00180 if( m_nValues && m_pXValues && m_pOrigYValues )
00181 {
00182 m_fMaxX = m_fMinX = m_pXValues[0];
00183 m_fMaxY = m_fMinY = m_pOrigYValues[0];
00184 for( int i = 1; i < m_nValues; i++ )
00185 {
00186 if( m_pXValues[ i ] > m_fMaxX )
00187 m_fMaxX = m_pXValues[ i ];
00188 else if( m_pXValues[ i ] < m_fMinX )
00189 m_fMinX = m_pXValues[ i ];
00190 if( m_pOrigYValues[ i ] > m_fMaxY )
00191 m_fMaxY = m_pOrigYValues[ i ];
00192 else if( m_pOrigYValues[ i ] < m_fMinY )
00193 m_fMinY = m_pOrigYValues[ i ];
00194 }
00195 setBoundings( m_fMinX, m_fMinY, m_fMaxX, m_fMaxY );
00196 }
00197 }
00198
00199
00200
00201 Point GridWindow::transform( double x, double y )
00202 {
00203 Point aRet;
00204
00205 aRet.X() = (long)( ( x - m_fMinX ) *
00206 (double)m_aGridArea.GetWidth() / ( m_fMaxX - m_fMinX )
00207 + m_aGridArea.Left() );
00208 aRet.Y() = (long)(
00209 m_aGridArea.Bottom() -
00210 ( y - m_fMinY ) *
00211 (double)m_aGridArea.GetHeight() / ( m_fMaxY - m_fMinY ) );
00212 return aRet;
00213 }
00214
00215
00216
00217 void GridWindow::transform( const Point& rOriginal, double& x, double& y )
00218 {
00219 x = ( rOriginal.X() - m_aGridArea.Left() ) * (m_fMaxX - m_fMinX) / (double)m_aGridArea.GetWidth() + m_fMinX;
00220 y = ( m_aGridArea.Bottom() - rOriginal.Y() ) * (m_fMaxY - m_fMinY) / (double)m_aGridArea.GetHeight() + m_fMinY;
00221 }
00222
00223
00224
00225 void GridWindow::drawPoint( double x, double y )
00226 {
00227 DrawPixel( transform( x, y ) );
00228 }
00229
00230
00231
00232 void GridWindow::drawLine( double x1, double y1, double x2, double y2 )
00233 {
00234 DrawLine( transform( x1, y1 ), transform( x2, y2 ) );
00235 }
00236
00237
00238
00239 void GridWindow::computeChunk( double fMin, double fMax, double& fChunkOut, double& fMinChunkOut )
00240 {
00241
00242 fChunkOut = ( fMax - fMin ) / 6.0;
00243 int logchunk = (int)log10( fChunkOut );
00244 int nChunk = (int)( fChunkOut / exp( (double)(logchunk-1) * M_LN10 ) );
00245 if( nChunk >= 75 )
00246 nChunk = 100;
00247 else if( nChunk >= 35 )
00248 nChunk = 50;
00249 else if ( nChunk > 20 )
00250 nChunk = 25;
00251 else if ( nChunk >= 13 )
00252 nChunk = 20;
00253 else if( nChunk > 5 )
00254 nChunk = 10;
00255 else
00256 nChunk = 5;
00257 fChunkOut = (double) nChunk * exp( (double)(logchunk-1) * M_LN10 );
00258
00259 nChunk = (int)( fMin / fChunkOut );
00260 fMinChunkOut = (double)nChunk * fChunkOut;
00261 while( fMinChunkOut < fMin )
00262 fMinChunkOut += fChunkOut;
00263 }
00264
00265
00266
00267 void GridWindow::computeNew()
00268 {
00269 if(2L == m_aHandles.size())
00270 {
00271
00272 double xleft, yleft;
00273 double xright, yright;
00274 transform(m_aHandles[0L].maPos, xleft, yleft);
00275 transform(m_aHandles[1L].maPos, xright, yright );
00276 double factor = (yright-yleft)/(xright-xleft);
00277 for( int i = 0; i < m_nValues; i++ )
00278 {
00279 m_pNewYValues[ i ] = yleft + ( m_pXValues[ i ] - xleft )*factor;
00280 }
00281 }
00282 else
00283 {
00284
00285 std::sort(m_aHandles.begin(), m_aHandles.end());
00286 const int nSorted = m_aHandles.size();
00287 int i;
00288
00289
00290 double* nodex = new double[ nSorted ];
00291 double* nodey = new double[ nSorted ];
00292
00293 for( i = 0L; i < nSorted; i++ )
00294 transform( m_aHandles[i].maPos, nodex[ i ], nodey[ i ] );
00295
00296 for( i = 0; i < m_nValues; i++ )
00297 {
00298 double x = m_pXValues[ i ];
00299 m_pNewYValues[ i ] = interpolate( x, nodex, nodey, nSorted );
00300 if( m_bCutValues )
00301 {
00302 if( m_pNewYValues[ i ] > m_fMaxY )
00303 m_pNewYValues[ i ] = m_fMaxY;
00304 else if( m_pNewYValues[ i ] < m_fMinY )
00305 m_pNewYValues[ i ] = m_fMinY;
00306 }
00307 }
00308
00309 delete [] nodex;
00310 delete [] nodey;
00311 }
00312 }
00313
00314
00315
00316 double GridWindow::interpolate(
00317 double x,
00318 double* pNodeX,
00319 double* pNodeY,
00320 int nNodes )
00321 {
00322
00323 double ret = 0;
00324 for( int i = 0; i < nNodes; i++ )
00325 {
00326 double sum = pNodeY[ i ];
00327 for( int n = 0; n < nNodes; n++ )
00328 {
00329 if( n != i )
00330 {
00331 sum *= x - pNodeX[ n ];
00332 sum /= pNodeX[ i ] - pNodeX[ n ];
00333 }
00334 }
00335 ret += sum;
00336 }
00337 return ret;
00338 }
00339
00340
00341
00342 void GridWindow::setBoundings( double fMinX, double fMinY, double fMaxX, double fMaxY )
00343 {
00344 m_fMinX = fMinX;
00345 m_fMinY = fMinY;
00346 m_fMaxX = fMaxX;
00347 m_fMaxY = fMaxY;
00348
00349 computeChunk( m_fMinX, m_fMaxX, m_fChunkX, m_fMinChunkX );
00350 computeChunk( m_fMinY, m_fMaxY, m_fChunkY, m_fMinChunkY );
00351 }
00352
00353
00354
00355 void GridWindow::drawGrid()
00356 {
00357 char pBuf[256];
00358 SetLineColor( Color( COL_BLACK ) );
00359
00360 for( double fX = m_fMinChunkX; fX < m_fMaxX; fX += m_fChunkX )
00361 {
00362 drawLine( fX, m_fMinY, fX, m_fMaxY );
00363
00364 Point aPt = transform( fX, m_fMinY );
00365 sprintf( pBuf, "%g", fX );
00366 String aMark( pBuf, gsl_getSystemTextEncoding() );
00367 Size aTextSize( GetTextWidth( aMark ), GetTextHeight() );
00368 aPt.X() -= aTextSize.Width()/2;
00369 aPt.Y() += aTextSize.Height()/2;
00370 DrawText( aPt, aMark );
00371 }
00372
00373 for( double fY = m_fMinChunkY; fY < m_fMaxY; fY += m_fChunkY )
00374 {
00375 drawLine( m_fMinX, fY, m_fMaxX, fY );
00376
00377 Point aPt = transform( m_fMinX, fY );
00378 sprintf( pBuf, "%g", fY );
00379 String aMark( pBuf, gsl_getSystemTextEncoding() );
00380 Size aTextSize( GetTextWidth( aMark ), GetTextHeight() );
00381 aPt.X() -= aTextSize.Width() + 2;
00382 aPt.Y() -= aTextSize.Height()/2;
00383 DrawText( aPt, aMark );
00384 }
00385
00386
00387 drawLine( m_fMinX, m_fMinY, m_fMaxX, m_fMinY );
00388 drawLine( m_fMinX, m_fMaxY, m_fMaxX, m_fMaxY );
00389 drawLine( m_fMinX, m_fMinY, m_fMinX, m_fMaxY );
00390 drawLine( m_fMaxX, m_fMinY, m_fMaxX, m_fMaxY );
00391 }
00392
00393
00394
00395 void GridWindow::drawOriginal()
00396 {
00397 if( m_nValues && m_pXValues && m_pOrigYValues )
00398 {
00399 SetLineColor( Color( COL_RED ) );
00400 for( int i = 0; i < m_nValues-1; i++ )
00401 {
00402 drawLine( m_pXValues[ i ], m_pOrigYValues[ i ],
00403 m_pXValues[ i+1 ], m_pOrigYValues[ i+1 ] );
00404 }
00405 }
00406 }
00407
00408
00409
00410 void GridWindow::drawNew()
00411 {
00412 if( m_nValues && m_pXValues && m_pNewYValues )
00413 {
00414 SetClipRegion( m_aGridArea );
00415 SetLineColor( Color( COL_YELLOW ) );
00416 for( int i = 0; i < m_nValues-1; i++ )
00417 {
00418 drawLine( m_pXValues[ i ], m_pNewYValues[ i ],
00419 m_pXValues[ i+1 ], m_pNewYValues[ i+1 ] );
00420 }
00421 SetClipRegion();
00422 }
00423 }
00424
00425
00426
00427 void GridWindow::drawHandles()
00428 {
00429 for(sal_uInt32 i(0L); i < m_aHandles.size(); i++)
00430 {
00431 m_aHandles[i].draw(*this, m_aMarkerBitmap);
00432 }
00433 }
00434
00435
00436
00437 void GridWindow::Paint( const Rectangle& rRect )
00438 {
00439 ModalDialog::Paint( rRect );
00440 drawGrid();
00441 drawOriginal();
00442 drawNew();
00443 drawHandles();
00444 }
00445
00446
00447
00448 void GridWindow::MouseMove( const MouseEvent& rEvt )
00449 {
00450 if( rEvt.GetButtons() == MOUSE_LEFT && m_nDragIndex != 0xffffffff )
00451 {
00452 Point aPoint( rEvt.GetPosPixel() );
00453
00454 if( m_nDragIndex == 0L || m_nDragIndex == m_aHandles.size() - 1L)
00455 {
00456 aPoint.X() = m_aHandles[m_nDragIndex].maPos.X();
00457 }
00458 else
00459 {
00460 if(aPoint.X() < m_aGridArea.Left())
00461 aPoint.X() = m_aGridArea.Left();
00462 else if(aPoint.X() > m_aGridArea.Right())
00463 aPoint.X() = m_aGridArea.Right();
00464 }
00465
00466 if( aPoint.Y() < m_aGridArea.Top() )
00467 aPoint.Y() = m_aGridArea.Top();
00468 else if( aPoint.Y() > m_aGridArea.Bottom() )
00469 aPoint.Y() = m_aGridArea.Bottom();
00470
00471 if( aPoint != m_aHandles[m_nDragIndex].maPos )
00472 {
00473 m_aHandles[m_nDragIndex].maPos = aPoint;
00474 Invalidate( m_aGridArea );
00475 }
00476 }
00477
00478 ModalDialog::MouseMove( rEvt );
00479 }
00480
00481
00482
00483 void GridWindow::MouseButtonUp( const MouseEvent& rEvt )
00484 {
00485 if( rEvt.GetButtons() == MOUSE_LEFT )
00486 {
00487 if( m_nDragIndex != 0xffffffff )
00488 {
00489 m_nDragIndex = 0xffffffff;
00490 computeNew();
00491 Invalidate( m_aGridArea );
00492 Paint( m_aGridArea );
00493 }
00494 }
00495
00496 ModalDialog::MouseButtonUp( rEvt );
00497 }
00498
00499
00500
00501 void GridWindow::MouseButtonDown( const MouseEvent& rEvt )
00502 {
00503 Point aPoint( rEvt.GetPosPixel() );
00504 sal_uInt32 nMarkerIndex = 0xffffffff;
00505
00506 for(sal_uInt32 a(0L); nMarkerIndex == 0xffffffff && a < m_aHandles.size(); a++)
00507 {
00508 if(m_aHandles[a].isHit(*this, aPoint))
00509 {
00510 nMarkerIndex = a;
00511 }
00512 }
00513
00514 if( rEvt.GetButtons() == MOUSE_LEFT )
00515 {
00516
00517 if( nMarkerIndex != 0xffffffff )
00518 {
00519 m_nDragIndex = nMarkerIndex;
00520 }
00521 }
00522 else if( rEvt.GetButtons() == MOUSE_RIGHT )
00523 {
00524
00525 if( nMarkerIndex != 0xffffffff )
00526 {
00527 if( nMarkerIndex != 0L && nMarkerIndex != m_aHandles.size() - 1L)
00528 {
00529
00530 if( m_nDragIndex == nMarkerIndex )
00531 m_nDragIndex = 0xffffffff;
00532
00533 m_aHandles.erase(m_aHandles.begin() + nMarkerIndex);
00534 }
00535 }
00536 else
00537 {
00538 m_BmOffX = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Width() >> 1);
00539 m_BmOffY = sal_uInt16(m_aMarkerBitmap.GetSizePixel().Height() >> 1);
00540 m_aHandles.push_back(impHandle(aPoint, m_BmOffX, m_BmOffY));
00541 }
00542
00543 computeNew();
00544 Invalidate( m_aGridArea );
00545 Paint( m_aGridArea );
00546 }
00547
00548 ModalDialog::MouseButtonDown( rEvt );
00549 }
00550
00551
00552
00553 IMPL_LINK( GridWindow, ClickButtonHdl, Button*, pButton )
00554 {
00555 if( pButton == &m_aResetButton )
00556 {
00557 int nType = (int)(sal_IntPtr)m_aResetTypeBox.GetEntryData( m_aResetTypeBox.GetSelectEntryPos() );
00558 switch( nType )
00559 {
00560 case RESET_TYPE_LINEAR_ASCENDING:
00561 {
00562 for( int i = 0; i < m_nValues; i++ )
00563 {
00564 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
00565 }
00566 }
00567 break;
00568 case RESET_TYPE_LINEAR_DESCENDING:
00569 {
00570 for( int i = 0; i < m_nValues; i++ )
00571 {
00572 m_pNewYValues[ i ] = m_fMaxY - (m_fMaxY-m_fMinY)/(m_fMaxX-m_fMinX)*(m_pXValues[i]-m_fMinX);
00573 }
00574 }
00575 break;
00576 case RESET_TYPE_RESET:
00577 {
00578 if( m_pOrigYValues && m_pNewYValues && m_nValues )
00579 memcpy( m_pNewYValues, m_pOrigYValues, m_nValues*sizeof(double) );
00580 }
00581 break;
00582 case RESET_TYPE_EXPONENTIAL:
00583 {
00584 for( int i = 0; i < m_nValues; i++ )
00585 {
00586 m_pNewYValues[ i ] = m_fMinY + (m_fMaxY-m_fMinY)*(exp((m_pXValues[i]-m_fMinX)/(m_fMaxX-m_fMinX))-1.0)/(M_E-1.0);
00587 }
00588 }
00589 break;
00590
00591 default:
00592 break;
00593 }
00594
00595 for(sal_uInt32 i(0L); i < m_aHandles.size(); i++)
00596 {
00597
00598 double x, y;
00599 transform( m_aHandles[i].maPos, x, y );
00600 int nIndex = 0;
00601 double delta = fabs( x-m_pXValues[0] );
00602 for( int n = 1; n < m_nValues; n++ )
00603 {
00604 if( delta > fabs( x - m_pXValues[ n ] ) )
00605 {
00606 delta = fabs( x - m_pXValues[ n ] );
00607 nIndex = n;
00608 }
00609 }
00610 if( 0 == i )
00611 m_aHandles[i].maPos = transform( m_fMinX, m_pNewYValues[ nIndex ] );
00612 else if( m_aHandles.size() - 1L == i )
00613 m_aHandles[i].maPos = transform( m_fMaxX, m_pNewYValues[ nIndex ] );
00614 else
00615 m_aHandles[i].maPos = transform( m_pXValues[ nIndex ], m_pNewYValues[ nIndex ] );
00616 }
00617
00618 Invalidate( m_aGridArea );
00619 Paint(Rectangle());
00620 }
00621 return 0;
00622 }