1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Framework for mathematical graph plotting in wxWindows
4 // Author: David Schalig
7 // Copyright: (c) David Schalig
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "plot.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
24 #include "wx/object.h"
26 #include "wx/colour.h"
27 #include "wx/settings.h"
31 #include "wx/dcclient.h"
42 //#include "wx/bmpbuttn.h"
43 //#include "wx/module.h"
47 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
51 IMPLEMENT_ABSTRACT_CLASS(mpLayer, wxObject)
56 // SetPen( *wxBLACK_PEN);
57 // SetFont(*wxNORMAL_FONT);
59 wxFont ff( *wxNORMAL_FONT);
60 wxPen pp( *wxBLACK_PEN);
66 //-----------------------------------------------------------------------------
67 // mpLayer implementations - functions
68 //-----------------------------------------------------------------------------
70 IMPLEMENT_ABSTRACT_CLASS(mpFX, mpLayer)
72 mpFX::mpFX(wxString name, int flags)
78 void mpFX::Plot(wxDC & dc, mpWindow & w)
82 if (m_pen.GetWidth() <= 1)
84 for (wxCoord i = -(w.GetScrX()>>1); i < (w.GetScrX()>>1); ++i)
86 dc.DrawPoint(i, (wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY()));
91 for (wxCoord i = -(w.GetScrX()>>1); i < (w.GetScrX()>>1); ++i)
93 wxCoord c = (wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY());
94 dc.DrawLine( i, c, i, c);
98 if (!m_name.IsEmpty())
103 dc.GetTextExtent(m_name, &tx, &ty);
105 if ((m_flags & mpALIGNMASK) == mpALIGN_RIGHT)
106 tx = (w.GetScrX()>>1) - tx - 8;
107 else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
110 tx = -(w.GetScrX()>>1) + 8;
112 dc.DrawText( m_name, tx, (wxCoord) ((w.GetPosY() - GetY( (double)tx / w.GetScaleX() + w.GetPosX())) * w.GetScaleY()) );
116 IMPLEMENT_ABSTRACT_CLASS(mpFY, mpLayer)
118 mpFY::mpFY(wxString name, int flags)
124 void mpFY::Plot(wxDC & dc, mpWindow & w)
130 if (m_pen.GetWidth() <= 1)
132 for (i = -(w.GetScrY()>>1); i < (w.GetScrY()>>1); ++i)
134 dc.DrawPoint((wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX()), -i);
139 for (i = -(w.GetScrY()>>1); i < (w.GetScrY()>>1); ++i)
141 wxCoord c = (wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX());
142 dc.DrawLine(c, -i, c, -i);
146 if (!m_name.IsEmpty())
151 dc.GetTextExtent(m_name, &tx, &ty);
153 if ((m_flags & mpALIGNMASK) == mpALIGN_TOP)
154 ty = (w.GetScrY()>>1) - 8;
155 else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
158 ty = -(w.GetScrY()>>1) + 8;
160 dc.DrawText( m_name, (wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX()), -ty);
164 IMPLEMENT_ABSTRACT_CLASS(mpFXY, mpLayer)
166 mpFXY::mpFXY(wxString name, int flags)
172 void mpFXY::Plot(wxDC & dc, mpWindow & w)
179 // for some reason DrawPoint does not use the current pen,
180 // so we use DrawLine for fat pens
182 if (m_pen.GetWidth() <= 1)
184 while (GetNextXY(x, y))
186 dc.DrawPoint( (wxCoord) ((x - w.GetPosX()) * w.GetScaleX()) ,
187 (wxCoord) ((w.GetPosY() - y) * w.GetScaleY()) );
192 while (GetNextXY(x, y))
194 wxCoord cx = (wxCoord) ((x - w.GetPosX()) * w.GetScaleX());
195 wxCoord cy = (wxCoord) ((w.GetPosY() - y) * w.GetScaleY());
196 dc.DrawLine(cx, cy, cx, cy);
200 if (!m_name.IsEmpty())
205 dc.GetTextExtent(m_name, &tx, &ty);
207 // xxx implement else ... if (!HasBBox())
209 const int sx = w.GetScrX()>>1;
210 const int sy = w.GetScrY()>>1;
212 if ((m_flags & mpALIGNMASK) == mpALIGN_NE)
217 else if ((m_flags & mpALIGNMASK) == mpALIGN_NW)
222 else if ((m_flags & mpALIGNMASK) == mpALIGN_SW)
237 dc.DrawText( m_name, tx, ty);
241 //-----------------------------------------------------------------------------
242 // mpLayer implementations - furniture (scales, ...)
243 //-----------------------------------------------------------------------------
245 #define mpLN10 2.3025850929940456840179914546844
247 IMPLEMENT_CLASS(mpScaleX, mpLayer)
249 mpScaleX::mpScaleX(wxString name)
252 SetFont(*wxSMALL_FONT);
253 SetPen(*wxGREY_PEN);*/
255 wxFont ff( *wxSMALL_FONT);
256 wxPen pp( *wxGREY_PEN);
261 void mpScaleX::Plot(wxDC & dc, mpWindow & w)
266 const int orgy = (int)(w.GetPosY() * w.GetScaleY());
267 const int extend = w.GetScrX()/2;
269 dc.DrawLine( -extend, orgy, extend, orgy);
271 const double dig = floor( log( 128.0 / w.GetScaleX() ) / mpLN10 );
272 const double step = exp( mpLN10 * dig);
273 const double end = w.GetPosX() + (double)extend / w.GetScaleX();
286 fmt.Printf(wxT("%%.%df"), tmp >= -1 ? 2 : -tmp);
289 double n = floor( (w.GetPosX() - (double)extend / w.GetScaleX()) / step ) * step ;
292 for (;n < end; n += step)
294 const int p = (int)((n - w.GetPosX()) * w.GetScaleX());
295 dc.DrawLine( p, orgy, p, orgy+4);
298 dc.GetTextExtent(s, &tx, &ty);
299 if ((p-tx/2-tmp) > 64)
301 dc.DrawText( s, p-tx/2, orgy+4);
306 dc.GetTextExtent(m_name, &tx, &ty);
307 dc.DrawText( m_name, extend - tx - 4, orgy + 4 + ty);
310 IMPLEMENT_CLASS(mpScaleY, mpLayer)
312 mpScaleY::mpScaleY(wxString name)
315 SetFont(*wxSMALL_FONT);
316 SetPen(*wxGREY_PEN);*/
317 wxFont ff( *wxSMALL_FONT);
318 wxPen pp( *wxGREY_PEN);
323 void mpScaleY::Plot(wxDC & dc, mpWindow & w, int orgy)
328 const int orgx = -(int)(w.GetPosX() * w.GetScaleX());
329 const int extend = w.GetScrY()/2;
331 double sizedc = dc.GetSize().GetHeight()-orgy;
333 dc.DrawLine( orgx, GetYTranslated(sizedc, -extend), orgx, GetYTranslated(sizedc, extend));
335 const double dig = floor( log( 128.0 / w.GetScaleY() ) / mpLN10 );
336 const double step = exp( mpLN10 * dig);
337 const double end = w.GetPosY() + (double)extend / w.GetScaleY();
350 fmt.Printf(wxT("%%.%df"), tmp >= -1 ? 2 : -tmp);
353 double n = floor( (w.GetPosY() - (double)extend / w.GetScaleY()) / step ) * step ;
356 for (;n < end; n += step)
358 const int p = (int)((w.GetPosY() - n) * w.GetScaleY());
359 dc.DrawLine( orgx, GetYTranslated(sizedc, p), orgx+4, GetYTranslated(sizedc,p));
362 dc.GetTextExtent(s, &tx, &ty);
363 if ((tmp-p+ty/2) > 32)
365 dc.DrawText( s, orgx+4, GetYTranslated(sizedc,p-ty/2));
370 dc.GetTextExtent(m_name, &tx, &ty);
371 dc.DrawText( m_name, orgx-tx-4, GetYTranslated(sizedc,-extend + ty + 4));
374 //-----------------------------------------------------------------------------
376 //-----------------------------------------------------------------------------
378 IMPLEMENT_DYNAMIC_CLASS(mpWindow, wxScrolledWindow)
380 BEGIN_EVENT_TABLE(mpWindow, wxScrolledWindow)
381 EVT_PAINT ( mpWindow::OnPaint)
382 EVT_SIZE ( mpWindow::OnSize)
383 EVT_SCROLLWIN( mpWindow::OnScroll2)
385 EVT_MIDDLE_UP( mpWindow::OnShowPopupMenu)
386 EVT_RIGHT_UP ( mpWindow::OnShowPopupMenu)
387 EVT_MENU( mpID_CENTER, mpWindow::OnCenter)
388 EVT_MENU( mpID_FIT, mpWindow::OnFit)
389 EVT_MENU( mpID_ZOOM_IN, mpWindow::OnZoomIn)
390 EVT_MENU( mpID_ZOOM_OUT, mpWindow::OnZoomOut)
391 //EVT_MENU( mpID_LINE_GUIDES, mpWindow::OnGuideLines)
392 // New method that belongs to the mpWindow
393 EVT_MENU( mpID_LOCKASPECT,mpWindow::OnLockAspect)
396 mpWindow::mpWindow( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, int flag )
397 : wxScrolledWindow( parent, id, wxDefaultPosition, wxDefaultSize, flag, wxT("wxPlotter") )
399 m_scaleX = m_scaleY = 1.0;
401 m_scrX = m_scrY = 64;
404 maxScrX = maxScrY = 200;
405 minScrX = minScrY = 0;
408 m_lockaspect = FALSE;
409 offsetX = offsetY = 0;
410 offsetPixelX = offsetPixelY= 0;
411 _bitmap_functions=NULL;
413 real_guideLine_X = -1;
414 real_guideLine_Y = -1;
418 m_popmenu.Append( mpID_CENTER, _("Center"), _("Center plot view to this position"));
419 m_popmenu.Append( mpID_FIT, _("Fit"), _("Set plot view to show all items"));
420 m_popmenu.Append( mpID_ZOOM_IN, _("Zoom in"), _("Zoom in plot view."));
421 m_popmenu.Append( mpID_ZOOM_OUT, _("Zoom out"), _("Zoom out plot view."));
422 m_popmenu.AppendCheckItem( mpID_LOCKASPECT, _("Lock aspect"), _("Lock horizontal and vertical zoom aspect."));
424 m_popmenu.AppendCheckItem( mpID_LINE_GUIDES, _("Turn off guide lines"), _("Enables/Disables the guide lines"));
426 m_layers.DeleteContents(TRUE);
427 SetBackgroundColour( *wxWHITE );
428 EnableScrolling(FALSE, FALSE);
429 SetSizeHints(128, 128);
431 //_bitmap_functions= new wxBitmap(700,800);
436 mpWindow::~mpWindow()
445 GetClientSize( &cx, &cy);
452 m_posX = m_minX + d/2;
458 m_posY = m_minY + d/2;
463 double s = (m_scaleX + m_scaleY)/2;
472 void mpWindow::ZoomIn()
474 m_scaleX = m_scaleX * 2;
475 m_scaleY = m_scaleY * 2;
479 void mpWindow::ZoomOut()
481 m_scaleX = m_scaleX / 2;
482 m_scaleY = m_scaleY / 2;
486 void mpWindow::LockAspect(bool enable)
488 m_lockaspect = enable;
490 m_popmenu.Check(mpID_LOCKASPECT, enable);
494 double s = (m_scaleX + m_scaleY)/2;
502 void mpWindow::OnShowPopupMenu(wxMouseEvent &event)
504 m_clickedX = event.GetX();
505 m_clickedY = event.GetY();
506 PopupMenu( &m_popmenu, event.GetX(), event.GetY());
509 void mpWindow::OnLockAspect(wxCommandEvent &event)
511 LockAspect( !m_popmenu.IsChecked(mpID_LOCKASPECT) );
514 void mpWindow::OnFit(wxCommandEvent &event)
519 void mpWindow::OnCenter(wxCommandEvent &event)
522 GetClientSize(&cx, &cy);
523 SetPos( (double)(m_clickedX-cx/2) / m_scaleX + m_posX, (double)(cy/2-m_clickedY) / m_scaleY + m_posY);
526 void mpWindow::OnZoomIn(wxCommandEvent &event)
529 GetClientSize(&cx, &cy);
530 m_posX = (double)(m_clickedX-cx/2) / m_scaleX + m_posX;
531 m_posY = (double)(cy/2-m_clickedY) / m_scaleY + m_posY;
535 void mpWindow::OnZoomOut(wxCommandEvent &event)
540 void mpWindow::OnSize( wxSizeEvent &event )
545 bool mpWindow::AddLayer( mpLayer* layer)
547 bool ret = m_layers.Append( layer) != NULL;
552 void mpWindow::DelLayer( mpLayer* layer)
554 m_layers.DeleteObject( layer);
558 void mpWindow::Refresh(bool eraseBackground, const wxRect* rect)
560 wxScrolledWindow::Refresh(false);
564 void mpWindow::OnPaint( wxPaintEvent &event )
567 dc.GetSize(&m_scrX, &m_scrY);
568 printf("EED mpWindow::OnPaint %d %d\n",m_scrX,m_scrY);
574 //_bitmap_functions->SetWidth(m_scrX);
575 //_bitmap_functions->SetHeight(m_scrY);
576 _bitmap_functions=new wxBitmap(m_scrX,m_scrY);
577 temp_dc.SelectObject(*_bitmap_functions);
580 // wxColour colourParent = wxColour(255,0,0);
581 temp_dc.SetBrush(wxBrush( *wxWHITE_BRUSH ) );
582 temp_dc.SetPen(wxPen( *wxBLACK_PEN ));
583 temp_dc.DrawRectangle(0,0,m_scrX,m_scrY);
586 wxNode *node = m_layers.GetFirst();
589 ((mpLayer*)node->GetData())->Plot( temp_dc, *this);
590 node = node->GetNext();
593 //dc.SetDeviceOrigin(70,40);
594 //dc.SetAxisOrientation(false,true);
595 //temp_dc.SetAxisOrientation(true,false);
598 //dc.Blit(0,0, m_scrX, m_scrY, &temp_dc,-70,-m_scrY+40);
600 temp_dc.SetDeviceOrigin(0,0);
601 dc.Blit(0,0, m_scrX, m_scrY, &temp_dc,0,0);
604 delete _bitmap_functions;
606 //dc.SetAxisOrientation(false,true);
612 void mpWindow::OnPaint( wxPaintEvent &event )
618 dc.GetSize(&m_scrX, &m_scrY);
620 //const int orgy = m_scrY-40;
621 //dc.SetDeviceOrigin(70,orgy);
622 //dc.SetAxisOrientation(true,true);
624 // wxMemoryDC temp_dc;
626 // //_bitmap_functions=new wxBitmap(m_scrX,m_scrY);
628 // _bitmap_functions->SetWidth(100);//m_scrX);
629 // _bitmap_functions->SetHeight(200);//m_scrY);
631 // temp_dc.SelectObject(*_bitmap_functions);
634 // wxColour colourParent = wxColour(255,0,0);
635 // temp_dc.SetBrush(wxBrush( colourParent ,wxSOLID ));
636 // temp_dc.SetPen(wxPen( colourParent ,1,wxSOLID ));
637 // temp_dc.DrawRectangle(0,0,100,200);
638 // dc.Blit(0,0, 100, 200, &temp_dc,0,0);
639 // //dc.SetDeviceOrigin( m_scrX>>1, m_scrY>>1);
641 wxNode *node = m_layers.GetFirst();
644 ((mpLayer*)node->GetData())->Plot( dc, *this);
645 node = node->GetNext();
647 //temp_dc.SetAxisOrientation(true,false);
649 // dc.SetAxisOrientation(true,true);
650 //dc.Blit(70,(int)(-m_scrY+40),m_scrX-100,m_scrY-50,&temp_dc,0,0);
654 void mpWindow::OnScroll2(wxScrollWinEvent &event)
657 GetClientSize( &width, &height);
659 GetViewStart( &px, &py);
661 if (event.GetOrientation() == wxHORIZONTAL)
663 SetPosX( (double)px / GetScaleX() + m_minX + (double)(width>>1)/GetScaleX());
667 SetPosY( m_maxY - (double)py / GetScaleY() - (double)(height>>1)/GetScaleY());
672 bool mpWindow::UpdateBBox()
676 wxNode *node = m_layers.GetFirst();
680 mpLayer* f = (mpLayer*)node->GetData();
687 m_minX = f->GetMinX(); m_maxX=f->GetMaxX();
688 m_minY = f->GetMinY(); m_maxY=f->GetMaxY();
692 if (f->GetMinX()<m_minX) m_minX=f->GetMinX(); if (f->GetMaxX()>m_maxX) m_maxX=f->GetMaxX();
693 if (f->GetMinY()<m_minY) m_minY=f->GetMinY(); if (f->GetMaxY()>m_maxY) m_maxY=f->GetMaxY();
696 node = node->GetNext();
699 return first == FALSE;
702 void mpWindow::UpdateAll()
707 GetClientSize( &cx, &cy);
708 printf("EED mpWindow::UpdateAll %d %d\n",cx,cy);
710 //const int sx = (int)((m_maxX - m_minX) * GetScaleX()); // JPRx
711 //const int sy = (int)((m_maxY - m_minY) * GetScaleY()); // JPRx
712 //const int px = (int)((GetPosX() - m_minX) * GetScaleX() - (cx>>1)); // JPRx
713 //const int py = (int)((GetPosY() - m_minY) * GetScaleY() - (cy>>1)); // JPRx
714 //SetScrollbars( 1, 1, sx, sy, px, py);
722 * Guide lines menu handler method that reacts to the mpID_LINE_GUIDES cimmand event
723 * event The corresponding event to handle
726 void mpWindow :: OnGuideLines (wxCommandEvent &event)
728 wxString nextAction_text;
731 setLineGuidesCondition(false);
732 nextAction_text << "Turn on guide lines";
737 setLineGuidesCondition(true);
738 nextAction_text << "Turn off guide lines";
741 m_popmenu.SetLabel ( mpID_LINE_GUIDES, nextAction_text );
747 bool mpWindow::drawGuideLines()