00001
00002
00003
00004
00005
00006
00007
00008
00010
00011
00012
00013
00014
00015
00016
00017 #include "wx/wxprec.h"
00018 #ifdef __BORLANDC__
00019 #pragma hdrstop
00020 #endif
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "mathplot.h"
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 IMPLEMENT_ABSTRACT_CLASS(mpLayer, wxObject)
00052
00053 mpLayer::mpLayer()
00054 {
00055
00056
00057
00058
00059 wxFont ff( *wxNORMAL_FONT);
00060 wxPen pp( *wxBLACK_PEN);
00061 SetPen( pp );
00062 SetFont( ff );
00063
00064 }
00065
00066
00067
00068
00069
00070 IMPLEMENT_ABSTRACT_CLASS(mpFX, mpLayer)
00071
00072 mpFX::mpFX(wxString name, int flags)
00073 {
00074 SetName(name);
00075 m_flags = flags;
00076 }
00077
00078 void mpFX::Plot(wxDC & dc, mpWindow & w)
00079 {
00080 dc.SetPen( m_pen);
00081
00082 if (m_pen.GetWidth() <= 1)
00083 {
00084 for (wxCoord i = -(w.GetScrX()>>1); i < (w.GetScrX()>>1); ++i)
00085 {
00086 dc.DrawPoint(i, (wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY()));
00087 }
00088 }
00089 else
00090 {
00091 for (wxCoord i = -(w.GetScrX()>>1); i < (w.GetScrX()>>1); ++i)
00092 {
00093 wxCoord c = (wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY());
00094 dc.DrawLine( i, c, i, c);
00095 }
00096 }
00097
00098 if (!m_name.IsEmpty())
00099 {
00100 dc.SetFont(m_font);
00101
00102 wxCoord tx, ty;
00103 dc.GetTextExtent(m_name, &tx, &ty);
00104
00105 if ((m_flags & mpALIGNMASK) == mpALIGN_RIGHT)
00106 tx = (w.GetScrX()>>1) - tx - 8;
00107 else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
00108 tx = -tx/2;
00109 else
00110 tx = -(w.GetScrX()>>1) + 8;
00111
00112 dc.DrawText( m_name, tx, (wxCoord) ((w.GetPosY() - GetY( (double)tx / w.GetScaleX() + w.GetPosX())) * w.GetScaleY()) );
00113 }
00114 }
00115
00116 IMPLEMENT_ABSTRACT_CLASS(mpFY, mpLayer)
00117
00118 mpFY::mpFY(wxString name, int flags)
00119 {
00120 SetName(name);
00121 m_flags = flags;
00122 }
00123
00124 void mpFY::Plot(wxDC & dc, mpWindow & w)
00125 {
00126 dc.SetPen( m_pen);
00127
00128 wxCoord i;
00129
00130 if (m_pen.GetWidth() <= 1)
00131 {
00132 for (i = -(w.GetScrY()>>1); i < (w.GetScrY()>>1); ++i)
00133 {
00134 dc.DrawPoint((wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX()), -i);
00135 }
00136 }
00137 else
00138 {
00139 for (i = -(w.GetScrY()>>1); i < (w.GetScrY()>>1); ++i)
00140 {
00141 wxCoord c = (wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX());
00142 dc.DrawLine(c, -i, c, -i);
00143 }
00144 }
00145
00146 if (!m_name.IsEmpty())
00147 {
00148 dc.SetFont(m_font);
00149
00150 wxCoord tx, ty;
00151 dc.GetTextExtent(m_name, &tx, &ty);
00152
00153 if ((m_flags & mpALIGNMASK) == mpALIGN_TOP)
00154 ty = (w.GetScrY()>>1) - 8;
00155 else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
00156 ty = 16 - ty/2;
00157 else
00158 ty = -(w.GetScrY()>>1) + 8;
00159
00160 dc.DrawText( m_name, (wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX()), -ty);
00161 }
00162 }
00163
00164 IMPLEMENT_ABSTRACT_CLASS(mpFXY, mpLayer)
00165
00166 mpFXY::mpFXY(wxString name, int flags)
00167 {
00168 SetName(name);
00169 m_flags = flags;
00170 }
00171
00172 void mpFXY::Plot(wxDC & dc, mpWindow & w)
00173 {
00174 dc.SetPen( m_pen);
00175
00176 double x, y;
00177 Rewind();
00178
00179
00180
00181
00182 if (m_pen.GetWidth() <= 1)
00183 {
00184 while (GetNextXY(x, y))
00185 {
00186 dc.DrawPoint( (wxCoord) ((x - w.GetPosX()) * w.GetScaleX()) ,
00187 (wxCoord) ((w.GetPosY() - y) * w.GetScaleY()) );
00188 }
00189 }
00190 else
00191 {
00192 while (GetNextXY(x, y))
00193 {
00194 wxCoord cx = (wxCoord) ((x - w.GetPosX()) * w.GetScaleX());
00195 wxCoord cy = (wxCoord) ((w.GetPosY() - y) * w.GetScaleY());
00196 dc.DrawLine(cx, cy, cx, cy);
00197 }
00198 }
00199
00200 if (!m_name.IsEmpty())
00201 {
00202 dc.SetFont(m_font);
00203
00204 wxCoord tx, ty;
00205 dc.GetTextExtent(m_name, &tx, &ty);
00206
00207
00208 {
00209 const int sx = w.GetScrX()>>1;
00210 const int sy = w.GetScrY()>>1;
00211
00212 if ((m_flags & mpALIGNMASK) == mpALIGN_NE)
00213 {
00214 tx = sx - tx - 8;
00215 ty = -sy + 8;
00216 }
00217 else if ((m_flags & mpALIGNMASK) == mpALIGN_NW)
00218 {
00219 tx = -sx + 8;
00220 ty = -sy + 8;
00221 }
00222 else if ((m_flags & mpALIGNMASK) == mpALIGN_SW)
00223 {
00224 tx = -sx + 8;
00225 ty = sy - 8 - ty;
00226 }
00227 else
00228 {
00229 tx = sx - tx - 8;
00230 ty = sy - 8 - ty;
00231 }
00232 }
00233
00234
00235
00236
00237 dc.DrawText( m_name, tx, ty);
00238 }
00239 }
00240
00241
00242
00243
00244
00245 #define mpLN10 2.3025850929940456840179914546844
00246
00247 IMPLEMENT_CLASS(mpScaleX, mpLayer)
00248
00249 mpScaleX::mpScaleX(wxString name)
00250 {
00251 SetName(name);
00252
00253
00254
00255 wxFont ff( *wxSMALL_FONT);
00256 wxPen pp( *wxGREY_PEN);
00257 SetPen( pp );
00258 SetFont( ff );
00259 }
00260
00261 void mpScaleX::Plot(wxDC & dc, mpWindow & w)
00262 {
00263 dc.SetPen( m_pen);
00264 dc.SetFont( m_font);
00265
00266 const int orgy = (int)(w.GetPosY() * w.GetScaleY());
00267 const int extend = w.GetScrX()/2;
00268
00269 dc.DrawLine( -extend, orgy, extend, orgy);
00270
00271 const double dig = floor( log( 128.0 / w.GetScaleX() ) / mpLN10 );
00272 const double step = exp( mpLN10 * dig);
00273 const double end = w.GetPosX() + (double)extend / w.GetScaleX();
00274
00275 wxCoord tx, ty;
00276 wxString s;
00277 wxString fmt;
00278 int tmp = (int)dig;
00279 if (tmp>=1)
00280 {
00281 fmt = wxT("%.f");
00282 }
00283 else
00284 {
00285 tmp=8-tmp;
00286 fmt.Printf(wxT("%%.%df"), tmp >= -1 ? 2 : -tmp);
00287 }
00288
00289 double n = floor( (w.GetPosX() - (double)extend / w.GetScaleX()) / step ) * step ;
00290
00291 tmp=-65535;
00292 for (;n < end; n += step)
00293 {
00294 const int p = (int)((n - w.GetPosX()) * w.GetScaleX());
00295 dc.DrawLine( p, orgy, p, orgy+4);
00296
00297 s.Printf(fmt, n);
00298 dc.GetTextExtent(s, &tx, &ty);
00299 if ((p-tx/2-tmp) > 64)
00300 {
00301 dc.DrawText( s, p-tx/2, orgy+4);
00302 tmp=p+tx/2;
00303 }
00304 }
00305
00306 dc.GetTextExtent(m_name, &tx, &ty);
00307 dc.DrawText( m_name, extend - tx - 4, orgy + 4 + ty);
00308 }
00309
00310 IMPLEMENT_CLASS(mpScaleY, mpLayer)
00311
00312 mpScaleY::mpScaleY(wxString name)
00313 {
00314 SetName(name);
00315
00316
00317 wxFont ff( *wxSMALL_FONT);
00318 wxPen pp( *wxGREY_PEN);
00319 SetPen( pp );
00320 SetFont( ff );
00321 }
00322
00323 void mpScaleY::Plot(wxDC & dc, mpWindow & w)
00324 {
00325 dc.SetPen( m_pen);
00326 dc.SetFont( m_font);
00327
00328 const int orgx = -(int)(w.GetPosX() * w.GetScaleX());
00329 const int extend = w.GetScrY()/2;
00330
00331 dc.DrawLine( orgx, -extend, orgx, extend);
00332
00333 const double dig = floor( log( 128.0 / w.GetScaleY() ) / mpLN10 );
00334 const double step = exp( mpLN10 * dig);
00335 const double end = w.GetPosY() + (double)extend / w.GetScaleY();
00336
00337 wxCoord tx, ty;
00338 wxString s;
00339 wxString fmt;
00340 int tmp = (int)dig;
00341 if (tmp>=1)
00342 {
00343 fmt = wxT("%.f");
00344 }
00345 else
00346 {
00347 tmp=8-tmp;
00348 fmt.Printf(wxT("%%.%df"), tmp >= -1 ? 2 : -tmp);
00349 }
00350
00351 double n = floor( (w.GetPosY() - (double)extend / w.GetScaleY()) / step ) * step ;
00352
00353 tmp=65536;
00354 for (;n < end; n += step)
00355 {
00356 const int p = (int)((w.GetPosY() - n) * w.GetScaleY());
00357 dc.DrawLine( orgx, p, orgx+4, p);
00358
00359 s.Printf(fmt, n);
00360 dc.GetTextExtent(s, &tx, &ty);
00361 if ((tmp-p+ty/2) > 32)
00362 {
00363 dc.DrawText( s, orgx+4, p-ty/2);
00364 tmp=p-ty/2;
00365 }
00366 }
00367
00368 dc.GetTextExtent(m_name, &tx, &ty);
00369 dc.DrawText( m_name, orgx-tx-4, -extend + ty + 4);
00370 }
00371
00372
00373
00374
00375
00376 IMPLEMENT_DYNAMIC_CLASS(mpWindow, wxScrolledWindow)
00377
00378 BEGIN_EVENT_TABLE(mpWindow, wxScrolledWindow)
00379 EVT_PAINT ( mpWindow::OnPaint)
00380 EVT_SIZE ( mpWindow::OnSize)
00381 EVT_SCROLLWIN( mpWindow::OnScroll2)
00382
00383 EVT_MIDDLE_UP( mpWindow::OnShowPopupMenu)
00384 EVT_RIGHT_UP ( mpWindow::OnShowPopupMenu)
00385 EVT_MENU( mpID_CENTER, mpWindow::OnCenter)
00386 EVT_MENU( mpID_FIT, mpWindow::OnFit)
00387 EVT_MENU( mpID_ZOOM_IN, mpWindow::OnZoomIn)
00388 EVT_MENU( mpID_ZOOM_OUT, mpWindow::OnZoomOut)
00389
00390
00391 EVT_MENU( mpID_LOCKASPECT,mpWindow::OnLockAspect)
00392 END_EVENT_TABLE()
00393
00394 mpWindow::mpWindow( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, int flag )
00395 : wxScrolledWindow( parent, id, pos, size, flag, wxT("wxPlotter") )
00396 {
00397 m_scaleX = m_scaleY = 1.0;
00398 m_posX = m_posY = 0;
00399 m_scrX = m_scrY = 64;
00400 m_minX = m_minY = 0;
00401 m_maxX = m_maxY = 0;
00402 maxScrX = maxScrY = 200;
00403 minScrX = minScrY = 0;
00404 m_clickedX = 0;
00405 m_clickedY = 5000;
00406 m_lockaspect = FALSE;
00407 offsetX = offsetY = 0;
00408 offsetPixelX = offsetPixelY= 0;
00409
00410 real_guideLine_X = -1;
00411 real_guideLine_Y = -1;
00412 drawGuides = true;
00413 type=1;
00414
00415 m_popmenu.Append( mpID_CENTER, _("Center"), _("Center plot view to this position"));
00416 m_popmenu.Append( mpID_FIT, _("Fit"), _("Set plot view to show all items"));
00417 m_popmenu.Append( mpID_ZOOM_IN, _("Zoom in"), _("Zoom in plot view."));
00418 m_popmenu.Append( mpID_ZOOM_OUT, _("Zoom out"), _("Zoom out plot view."));
00419 m_popmenu.AppendCheckItem( mpID_LOCKASPECT, _("Lock aspect"), _("Lock horizontal and vertical zoom aspect."));
00420
00421 m_popmenu.AppendCheckItem( mpID_LINE_GUIDES, _("Turn off guide lines"), _("Enables/Disables the guide lines"));
00422
00423 m_layers.DeleteContents(TRUE);
00424 SetBackgroundColour( *wxWHITE );
00425 EnableScrolling(FALSE, FALSE);
00426 SetSizeHints(128, 128);
00427
00428
00429
00430 UpdateAll();
00431 }
00432
00433 mpWindow::~mpWindow()
00434 {
00435 }
00436
00437 void mpWindow::Fit()
00438 {
00439 if (UpdateBBox())
00440 {
00441 int cx, cy;
00442 GetClientSize( &cx, &cy);
00443
00444 double d;
00445 d = m_maxX - m_minX;
00446 if (d!=0)
00447 {
00448 m_scaleX = cx/d;
00449 m_posX = m_minX + d/2;
00450 }
00451 d = m_maxY - m_minY;
00452 if (d!=0)
00453 {
00454 m_scaleY = cy/d;
00455 m_posY = m_minY + d/2;
00456 }
00457
00458 if (m_lockaspect)
00459 {
00460 double s = (m_scaleX + m_scaleY)/2;
00461 m_scaleX = s;
00462 m_scaleY = s;
00463 }
00464
00465 UpdateAll();
00466 }
00467 }
00468
00469 void mpWindow::ZoomIn()
00470 {
00471 m_scaleX = m_scaleX * 2;
00472 m_scaleY = m_scaleY * 2;
00473 UpdateAll();
00474 }
00475
00476 void mpWindow::ZoomOut()
00477 {
00478 m_scaleX = m_scaleX / 2;
00479 m_scaleY = m_scaleY / 2;
00480 UpdateAll();
00481 }
00482
00483 void mpWindow::LockAspect(bool enable)
00484 {
00485 m_lockaspect = enable;
00486
00487 m_popmenu.Check(mpID_LOCKASPECT, enable);
00488
00489 if (m_lockaspect)
00490 {
00491 double s = (m_scaleX + m_scaleY)/2;
00492 m_scaleX = s;
00493 m_scaleY = s;
00494 }
00495
00496 UpdateAll();
00497 }
00498
00499 void mpWindow::OnShowPopupMenu(wxMouseEvent &event)
00500 {
00501 m_clickedX = event.GetX();
00502 m_clickedY = event.GetY();
00503 PopupMenu( &m_popmenu, event.GetX(), event.GetY());
00504 }
00505
00506 void mpWindow::OnLockAspect(wxCommandEvent &event)
00507 {
00508 LockAspect( !m_popmenu.IsChecked(mpID_LOCKASPECT) );
00509 }
00510
00511 void mpWindow::OnFit(wxCommandEvent &event)
00512 {
00513 Fit();
00514 }
00515
00516 void mpWindow::OnCenter(wxCommandEvent &event)
00517 {
00518 int cx, cy;
00519 GetClientSize(&cx, &cy);
00520 SetPos( (double)(m_clickedX-cx/2) / m_scaleX + m_posX, (double)(cy/2-m_clickedY) / m_scaleY + m_posY);
00521 }
00522
00523 void mpWindow::OnZoomIn(wxCommandEvent &event)
00524 {
00525 int cx, cy;
00526 GetClientSize(&cx, &cy);
00527 m_posX = (double)(m_clickedX-cx/2) / m_scaleX + m_posX;
00528 m_posY = (double)(cy/2-m_clickedY) / m_scaleY + m_posY;
00529 ZoomIn();
00530 }
00531
00532 void mpWindow::OnZoomOut(wxCommandEvent &event)
00533 {
00534 ZoomOut();
00535 }
00536
00537 void mpWindow::OnSize( wxSizeEvent &event )
00538 {
00539 UpdateAll();
00540 }
00541
00542 bool mpWindow::AddLayer( mpLayer* layer)
00543 {
00544 bool ret = m_layers.Append( layer) != NULL;
00545 UpdateAll();
00546 return ret;
00547 }
00548
00549 void mpWindow::DelLayer( mpLayer* layer)
00550 {
00551 m_layers.DeleteObject( layer);
00552 UpdateAll();
00553 }
00554
00555 void mpWindow::Refresh(bool eraseBackground, const wxRect* rect)
00556 {
00557 wxScrolledWindow::Refresh(false);
00558 }
00559
00560
00561 void mpWindow::OnPaint( wxPaintEvent &event )
00562 {
00563 wxPaintDC dc(this);
00564 dc.GetSize(&m_scrX, &m_scrY);
00565 printf("EED mpWindow::OnPaint %d %d\n",m_scrX,m_scrY);
00566
00567
00568
00569
00570 wxMemoryDC temp_dc;
00571
00572
00573 _bitmap_functions=new wxBitmap(m_scrX,m_scrY);
00574 temp_dc.SelectObject(*_bitmap_functions);
00575
00576
00577
00578 temp_dc.SetBrush(wxBrush( *wxWHITE_BRUSH ) );
00579 temp_dc.SetPen(wxPen( *wxBLACK_PEN ));
00580 temp_dc.DrawRectangle(0,0,m_scrX,m_scrY);
00581
00582
00583 wxNode *node = m_layers.GetFirst();
00584 while (node)
00585 {
00586 ((mpLayer*)node->GetData())->Plot( temp_dc, *this);
00587 node = node->GetNext();
00588 }
00589
00590
00591
00592 temp_dc.SetAxisOrientation(true,false);
00593
00594
00595
00596
00597 temp_dc.SetDeviceOrigin(0,0);
00598 dc.Blit(0,0, m_scrX, m_scrY, &temp_dc,0,0);
00599
00600
00601 delete _bitmap_functions;
00602
00603
00604
00605
00606 }
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651 void mpWindow::OnScroll2(wxScrollWinEvent &event)
00652 {
00653 int width, height;
00654 GetClientSize( &width, &height);
00655 int px, py;
00656 GetViewStart( &px, &py);
00657
00658 if (event.GetOrientation() == wxHORIZONTAL)
00659 {
00660 SetPosX( (double)px / GetScaleX() + m_minX + (double)(width>>1)/GetScaleX());
00661 }
00662 else
00663 {
00664 SetPosY( m_maxY - (double)py / GetScaleY() - (double)(height>>1)/GetScaleY());
00665 }
00666 event.Skip();
00667 }
00668
00669 bool mpWindow::UpdateBBox()
00670 {
00671 bool first = TRUE;
00672
00673 wxNode *node = m_layers.GetFirst();
00674
00675 while(node)
00676 {
00677 mpLayer* f = (mpLayer*)node->GetData();
00678
00679 if (f->HasBBox())
00680 {
00681 if (first)
00682 {
00683 first = FALSE;
00684 m_minX = f->GetMinX(); m_maxX=f->GetMaxX();
00685 m_minY = f->GetMinY(); m_maxY=f->GetMaxY();
00686 }
00687 else
00688 {
00689 if (f->GetMinX()<m_minX) m_minX=f->GetMinX(); if (f->GetMaxX()>m_maxX) m_maxX=f->GetMaxX();
00690 if (f->GetMinY()<m_minY) m_minY=f->GetMinY(); if (f->GetMaxY()>m_maxY) m_maxY=f->GetMaxY();
00691 }
00692 }
00693 node = node->GetNext();
00694 }
00695
00696 return first == FALSE;
00697 }
00698
00699 void mpWindow::UpdateAll()
00700 {
00701 if (UpdateBBox())
00702 {
00703 int cx, cy;
00704 GetClientSize( &cx, &cy);
00705 printf("EED mpWindow::UpdateAll %d %d\n",cx,cy);
00706
00707
00708
00709
00710
00711
00712 }
00713
00714 FitInside();
00715 Refresh( false );
00716 }
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744 bool mpWindow::drawGuideLines()
00745 {
00746 return drawGuides;
00747 }
00748