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, int orgy)
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         double sizedc = dc.GetSize().GetHeight()-orgy;
00332 
00333         dc.DrawLine( orgx, GetYTranslated(sizedc, -extend), orgx, GetYTranslated(sizedc, extend));
00334 
00335         const double dig  = floor( log( 128.0 / w.GetScaleY() ) / mpLN10 );
00336         const double step = exp( mpLN10 * dig);
00337         const double end  = w.GetPosY() + (double)extend / w.GetScaleY();
00338 
00339         wxCoord tx, ty;
00340         wxString s;
00341         wxString fmt;
00342         int tmp = (int)dig;
00343         if (tmp>=1)
00344         {
00345                 fmt = wxT("%.f");
00346         }
00347         else
00348         {
00349                 tmp=8-tmp;
00350                 fmt.Printf(wxT("%%.%df"), tmp >= -1 ? 2 : -tmp);
00351         }
00352 
00353         double n = floor( (w.GetPosY() - (double)extend / w.GetScaleY()) / step ) * step ;
00354 
00355         tmp=65536;
00356         for (;n < end; n += step)
00357         {
00358                 const int p = (int)((w.GetPosY() - n) * w.GetScaleY());
00359                 dc.DrawLine( orgx, GetYTranslated(sizedc, p), orgx+4, GetYTranslated(sizedc,p));
00360 
00361                 s.Printf(fmt, n);
00362                 dc.GetTextExtent(s, &tx, &ty);
00363                 if ((tmp-p+ty/2) > 32)
00364                 {
00365                         dc.DrawText( s, orgx+4, GetYTranslated(sizedc,p-ty/2));
00366                         tmp=p-ty/2;
00367                 }
00368         }
00369 
00370         dc.GetTextExtent(m_name, &tx, &ty);
00371         dc.DrawText( m_name, orgx-tx-4, GetYTranslated(sizedc,-extend + ty + 4));
00372 }
00373 
00374 
00375 
00376 
00377 
00378 IMPLEMENT_DYNAMIC_CLASS(mpWindow, wxScrolledWindow)
00379 
00380 BEGIN_EVENT_TABLE(mpWindow, wxScrolledWindow)
00381 EVT_PAINT    ( mpWindow::OnPaint)
00382 EVT_SIZE     ( mpWindow::OnSize)
00383 EVT_SCROLLWIN( mpWindow::OnScroll2)
00384 
00385 EVT_MIDDLE_UP( mpWindow::OnShowPopupMenu)
00386 EVT_RIGHT_UP ( mpWindow::OnShowPopupMenu)
00387 EVT_MENU( mpID_CENTER,    mpWindow::OnCenter)
00388 EVT_MENU( mpID_FIT,       mpWindow::OnFit)
00389 EVT_MENU( mpID_ZOOM_IN,   mpWindow::OnZoomIn)
00390 EVT_MENU( mpID_ZOOM_OUT,  mpWindow::OnZoomOut)
00391 
00392 
00393 EVT_MENU( mpID_LOCKASPECT,mpWindow::OnLockAspect)
00394 END_EVENT_TABLE()
00395 
00396 mpWindow::mpWindow( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, int flag )
00397 : wxScrolledWindow( parent, id, wxDefaultPosition, wxDefaultSize, flag, wxT("wxPlotter") )
00398 {
00399         m_scaleX = m_scaleY = 1.0;
00400         m_posX   = m_posY   = 0;
00401         m_scrX   = m_scrY   = 64;
00402         m_minX   = m_minY   = 0;
00403         m_maxX   = m_maxY   = 0;
00404         maxScrX = maxScrY   = 200;
00405         minScrX = minScrY   = 0;
00406         m_clickedX =  0;
00407         m_clickedY = 5000;
00408         m_lockaspect = FALSE;
00409         offsetX = offsetY = 0;
00410         offsetPixelX = offsetPixelY= 0;
00411         _bitmap_functions=NULL;
00412 
00413         real_guideLine_X = -1;
00414         real_guideLine_Y = -1;
00415         drawGuides = true;
00416         type=1;
00417 
00418         m_popmenu.Append( mpID_CENTER,     _("Center"),      _("Center plot view to this position"));
00419         m_popmenu.Append( mpID_FIT,        _("Fit"),         _("Set plot view to show all items"));
00420         m_popmenu.Append( mpID_ZOOM_IN,    _("Zoom in"),     _("Zoom in plot view."));
00421         m_popmenu.Append( mpID_ZOOM_OUT,   _("Zoom out"),    _("Zoom out plot view."));
00422         m_popmenu.AppendCheckItem( mpID_LOCKASPECT, _("Lock aspect"), _("Lock horizontal and vertical zoom aspect."));
00423 
00424         m_popmenu.AppendCheckItem( mpID_LINE_GUIDES, _("Turn off guide lines"), _("Enables/Disables the guide lines"));
00425 
00426         m_layers.DeleteContents(TRUE);
00427         SetBackgroundColour( *wxWHITE );
00428         EnableScrolling(FALSE, FALSE);
00429         SetSizeHints(128, 128);
00430         
00431         
00432 
00433         UpdateAll();
00434 }
00435 
00436 mpWindow::~mpWindow()
00437 {
00438 }
00439 
00440 void mpWindow::Fit()
00441 {
00442         if (UpdateBBox())
00443         {
00444                 int cx, cy;
00445                 GetClientSize( &cx, &cy);
00446                 
00447                 double d;
00448                 d = m_maxX - m_minX;
00449                 if (d!=0)
00450                 {
00451                         m_scaleX = cx/d;
00452                         m_posX = m_minX + d/2;
00453                 }
00454                 d = m_maxY - m_minY;
00455                 if (d!=0)
00456                 {
00457                         m_scaleY = cy/d;
00458                         m_posY = m_minY + d/2;
00459                 }
00460 
00461                 if (m_lockaspect)
00462                 {
00463                         double s = (m_scaleX + m_scaleY)/2;
00464                         m_scaleX = s;
00465                         m_scaleY = s;
00466                 }
00467 
00468                 UpdateAll();
00469         }
00470 }
00471 
00472 void mpWindow::ZoomIn()
00473 {
00474         m_scaleX = m_scaleX * 2;
00475         m_scaleY = m_scaleY * 2;
00476         UpdateAll();
00477 }
00478 
00479 void mpWindow::ZoomOut()
00480 {
00481         m_scaleX = m_scaleX / 2;
00482         m_scaleY = m_scaleY / 2;
00483         UpdateAll();
00484 }
00485 
00486 void mpWindow::LockAspect(bool enable)
00487 {
00488         m_lockaspect = enable;
00489 
00490         m_popmenu.Check(mpID_LOCKASPECT, enable);
00491 
00492         if (m_lockaspect)
00493         {
00494                 double s = (m_scaleX + m_scaleY)/2;
00495                 m_scaleX = s;
00496                 m_scaleY = s;
00497         }
00498 
00499         UpdateAll();
00500 }
00501 
00502 void mpWindow::OnShowPopupMenu(wxMouseEvent &event)
00503 {
00504         m_clickedX = event.GetX();
00505         m_clickedY = event.GetY();
00506         PopupMenu( &m_popmenu, event.GetX(), event.GetY());
00507 }
00508 
00509 void mpWindow::OnLockAspect(wxCommandEvent &event)
00510 {
00511         LockAspect( !m_popmenu.IsChecked(mpID_LOCKASPECT) );
00512 }
00513 
00514 void mpWindow::OnFit(wxCommandEvent &event)
00515 {
00516         Fit();
00517 }
00518 
00519 void mpWindow::OnCenter(wxCommandEvent &event)
00520 {
00521         int cx, cy;
00522         GetClientSize(&cx, &cy);
00523         SetPos( (double)(m_clickedX-cx/2) / m_scaleX + m_posX, (double)(cy/2-m_clickedY) / m_scaleY + m_posY);
00524 }
00525 
00526 void mpWindow::OnZoomIn(wxCommandEvent &event)
00527 {
00528         int cx, cy;
00529         GetClientSize(&cx, &cy);
00530         m_posX = (double)(m_clickedX-cx/2) / m_scaleX + m_posX;
00531         m_posY = (double)(cy/2-m_clickedY) / m_scaleY + m_posY;
00532         ZoomIn();
00533 }
00534 
00535 void mpWindow::OnZoomOut(wxCommandEvent &event)
00536 {
00537         ZoomOut();
00538 }
00539 
00540 void mpWindow::OnSize( wxSizeEvent &event )
00541 {
00542         UpdateAll();
00543 }
00544 
00545 bool mpWindow::AddLayer( mpLayer* layer)
00546 {
00547         bool ret = m_layers.Append( layer) != NULL;
00548         UpdateAll();
00549         return ret;
00550 }
00551 
00552 void mpWindow::DelLayer( mpLayer* layer)
00553 {
00554         m_layers.DeleteObject( layer);
00555         UpdateAll();
00556 }
00557 
00558 void mpWindow::Refresh(bool eraseBackground, const wxRect* rect)
00559 {
00560         wxScrolledWindow::Refresh(false);
00561 }
00562 
00563 
00564 void mpWindow::OnPaint( wxPaintEvent &event )
00565 {
00566         wxPaintDC dc(this);
00567         dc.GetSize(&m_scrX, &m_scrY);
00568 printf("EED mpWindow::OnPaint %d %d\n",m_scrX,m_scrY);
00569 
00570         
00571         
00572 
00573         wxMemoryDC temp_dc;
00574         
00575         
00576         _bitmap_functions=new wxBitmap(m_scrX,m_scrY);
00577         temp_dc.SelectObject(*_bitmap_functions);
00578 
00579         
00580         
00581         temp_dc.SetBrush(wxBrush( *wxWHITE_BRUSH  ) );
00582         temp_dc.SetPen(wxPen( *wxBLACK_PEN  ));
00583         temp_dc.DrawRectangle(0,0,m_scrX,m_scrY);
00584         
00585 
00586         wxNode *node = m_layers.GetFirst();
00587         while (node)
00588         {
00589                 ((mpLayer*)node->GetData())->Plot( temp_dc, *this);
00590                 node = node->GetNext();
00591         }
00592         
00593         
00594         
00595         
00596         
00597         
00598         
00599         
00600         temp_dc.SetDeviceOrigin(0,0);
00601         dc.Blit(0,0, m_scrX, m_scrY, &temp_dc,0,0);
00602         
00603         
00604         delete _bitmap_functions; 
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 
00652 
00653 
00654 void mpWindow::OnScroll2(wxScrollWinEvent &event)
00655 {
00656         int width, height;
00657         GetClientSize( &width, &height);
00658         int px, py;
00659         GetViewStart( &px, &py);
00660 
00661         if (event.GetOrientation() == wxHORIZONTAL)
00662         {
00663                 SetPosX( (double)px / GetScaleX() + m_minX + (double)(width>>1)/GetScaleX());
00664         }
00665         else
00666         {
00667                 SetPosY( m_maxY - (double)py / GetScaleY() - (double)(height>>1)/GetScaleY());
00668         }
00669         event.Skip();
00670 }
00671 
00672 bool mpWindow::UpdateBBox()
00673 {
00674         bool first = TRUE;
00675 
00676         wxNode *node = m_layers.GetFirst();
00677 
00678         while(node)
00679         {
00680                 mpLayer* f = (mpLayer*)node->GetData();
00681 
00682                 if (f->HasBBox())
00683                 {
00684                         if (first)
00685                         {
00686                                 first = FALSE;
00687                                 m_minX = f->GetMinX(); m_maxX=f->GetMaxX();
00688                                 m_minY = f->GetMinY(); m_maxY=f->GetMaxY();
00689                         }
00690                         else
00691                         {
00692                                 if (f->GetMinX()<m_minX) m_minX=f->GetMinX(); if (f->GetMaxX()>m_maxX) m_maxX=f->GetMaxX();
00693                                 if (f->GetMinY()<m_minY) m_minY=f->GetMinY(); if (f->GetMaxY()>m_maxY) m_maxY=f->GetMaxY();
00694                         }
00695                 }
00696                 node = node->GetNext();
00697         }
00698 
00699         return first == FALSE;
00700 }
00701 
00702 void mpWindow::UpdateAll()
00703 {
00704         if (UpdateBBox())
00705         {
00706                 int cx, cy;
00707                 GetClientSize( &cx, &cy);
00708 printf("EED mpWindow::UpdateAll %d %d\n",cx,cy);
00709 
00710                 
00711                 
00712                 
00713                 
00714                 
00715         }
00716 
00717         FitInside();
00718         Refresh( false );
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 
00745 
00746 
00747 bool mpWindow::drawGuideLines()
00748         {
00749                 return drawGuides;
00750         }       
00751