1 /*# ---------------------------------------------------------------------
3 # Copyright (c) CREATIS (Centre de Recherche en Acquisition et Traitement de l'Image
5 # Authors : Eduardo Davila, Frederic Cervenansky, Claire Mouton
6 # Previous Authors : Laurent Guigues, Jean-Pierre Roux
7 # CreaTools website : www.creatis.insa-lyon.fr/site/fr/creatools_accueil
9 # This software is governed by the CeCILL-B license under French law and
10 # abiding by the rules of distribution of free software. You can use,
11 # modify and/ or redistribute the software under the terms of the CeCILL-B
12 # license as circulated by CEA, CNRS and INRIA at the following URL
13 # http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
14 # or in the file LICENSE.txt.
16 # As a counterpart to the access to the source code and rights to copy,
17 # modify and redistribute granted by the license, users are provided only
18 # with a limited warranty and the software's author, the holder of the
19 # economic rights, and the successive licensors have only limited
22 # The fact that you are presently reading this means that you have had
23 # knowledge of the CeCILL-B license and that you accept its terms.
24 # ------------------------------------------------------------------------ */
26 /////////////////////////////////////////////////////////////////////////////
28 // Purpose: Framework for mathematical graph plotting in wxWindows
29 // Author: David Schalig
31 // Created: 21/07/2003
32 // Copyright: (c) David Schalig
33 // Licence: wxWindows licence
34 /////////////////////////////////////////////////////////////////////////////
38 #pragma implementation "plot.h"
41 // For compilers that support precompilation, includes "wx.h".
42 #include "wx/wxprec.h"
49 #include "wx/object.h"
51 #include "wx/colour.h"
52 #include "wx/settings.h"
56 #include "wx/dcclient.h"
67 //#include "wx/bmpbuttn.h"
68 //#include "wx/module.h"
72 //-----------------------------------------------------------------------------
74 //-----------------------------------------------------------------------------
76 IMPLEMENT_ABSTRACT_CLASS(mpLayer, wxObject)
81 // SetPen( *wxBLACK_PEN);
82 // SetFont(*wxNORMAL_FONT);
84 wxFont ff( *wxNORMAL_FONT);
85 wxPen pp( *wxBLACK_PEN);
91 //-----------------------------------------------------------------------------
92 // mpLayer implementations - functions
93 //-----------------------------------------------------------------------------
95 IMPLEMENT_ABSTRACT_CLASS(mpFX, mpLayer)
97 mpFX::mpFX(wxString name, int flags)
103 void mpFX::Plot(wxDC & dc, mpWindow & w)
107 if (m_pen.GetWidth() <= 1)
109 for (wxCoord i = -(w.GetScrX()>>1); i < (w.GetScrX()>>1); ++i)
111 dc.DrawPoint(i, (wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY()));
116 for (wxCoord i = -(w.GetScrX()>>1); i < (w.GetScrX()>>1); ++i)
118 wxCoord c = (wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY());
119 dc.DrawLine( i, c, i, c);
123 if (!m_name.IsEmpty())
128 dc.GetTextExtent(m_name, &tx, &ty);
130 if ((m_flags & mpALIGNMASK) == mpALIGN_RIGHT)
131 tx = (w.GetScrX()>>1) - tx - 8;
132 else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
135 tx = -(w.GetScrX()>>1) + 8;
137 dc.DrawText( m_name, tx, (wxCoord) ((w.GetPosY() - GetY( (double)tx / w.GetScaleX() + w.GetPosX())) * w.GetScaleY()) );
141 IMPLEMENT_ABSTRACT_CLASS(mpFY, mpLayer)
143 mpFY::mpFY(wxString name, int flags)
149 void mpFY::Plot(wxDC & dc, mpWindow & w)
155 if (m_pen.GetWidth() <= 1)
157 for (i = -(w.GetScrY()>>1); i < (w.GetScrY()>>1); ++i)
159 dc.DrawPoint((wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX()), -i);
164 for (i = -(w.GetScrY()>>1); i < (w.GetScrY()>>1); ++i)
166 wxCoord c = (wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX());
167 dc.DrawLine(c, -i, c, -i);
171 if (!m_name.IsEmpty())
176 dc.GetTextExtent(m_name, &tx, &ty);
178 if ((m_flags & mpALIGNMASK) == mpALIGN_TOP)
179 ty = (w.GetScrY()>>1) - 8;
180 else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
183 ty = -(w.GetScrY()>>1) + 8;
185 dc.DrawText( m_name, (wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX()), -ty);
189 IMPLEMENT_ABSTRACT_CLASS(mpFXY, mpLayer)
191 mpFXY::mpFXY(wxString name, int flags)
197 void mpFXY::Plot(wxDC & dc, mpWindow & w)
204 // for some reason DrawPoint does not use the current pen,
205 // so we use DrawLine for fat pens
207 if (m_pen.GetWidth() <= 1)
209 while (GetNextXY(x, y))
211 dc.DrawPoint( (wxCoord) ((x - w.GetPosX()) * w.GetScaleX()) ,
212 (wxCoord) ((w.GetPosY() - y) * w.GetScaleY()) );
217 while (GetNextXY(x, y))
219 wxCoord cx = (wxCoord) ((x - w.GetPosX()) * w.GetScaleX());
220 wxCoord cy = (wxCoord) ((w.GetPosY() - y) * w.GetScaleY());
221 dc.DrawLine(cx, cy, cx, cy);
225 if (!m_name.IsEmpty())
230 dc.GetTextExtent(m_name, &tx, &ty);
232 // xxx implement else ... if (!HasBBox())
234 const int sx = w.GetScrX()>>1;
235 const int sy = w.GetScrY()>>1;
237 if ((m_flags & mpALIGNMASK) == mpALIGN_NE)
242 else if ((m_flags & mpALIGNMASK) == mpALIGN_NW)
247 else if ((m_flags & mpALIGNMASK) == mpALIGN_SW)
262 dc.DrawText( m_name, tx, ty);
266 //-----------------------------------------------------------------------------
267 // mpLayer implementations - furniture (scales, ...)
268 //-----------------------------------------------------------------------------
270 #define mpLN10 2.3025850929940456840179914546844
272 IMPLEMENT_CLASS(mpScaleX, mpLayer)
274 mpScaleX::mpScaleX(wxString name)
277 SetFont(*wxSMALL_FONT);
278 SetPen(*wxGREY_PEN);*/
280 wxFont ff( *wxSMALL_FONT);
281 wxPen pp( *wxGREY_PEN);
286 void mpScaleX::Plot(wxDC & dc, mpWindow & w)
291 const int orgy = (int)(w.GetPosY() * w.GetScaleY());
292 const int extend = w.GetScrX()/2;
294 dc.DrawLine( -extend, orgy, extend, orgy);
296 const double dig = floor( log( 128.0 / w.GetScaleX() ) / mpLN10 );
297 const double step = exp( mpLN10 * dig);
298 const double end = w.GetPosX() + (double)extend / w.GetScaleX();
311 fmt.Printf(wxT("%%.%df"), tmp >= -1 ? 2 : -tmp);
314 double n = floor( (w.GetPosX() - (double)extend / w.GetScaleX()) / step ) * step ;
317 for (;n < end; n += step)
319 const int p = (int)((n - w.GetPosX()) * w.GetScaleX());
320 dc.DrawLine( p, orgy, p, orgy+4);
323 dc.GetTextExtent(s, &tx, &ty);
324 if ((p-tx/2-tmp) > 64)
326 dc.DrawText( s, p-tx/2, orgy+4);
331 dc.GetTextExtent(m_name, &tx, &ty);
332 dc.DrawText( m_name, extend - tx - 4, orgy + 4 + ty);
335 IMPLEMENT_CLASS(mpScaleY, mpLayer)
337 mpScaleY::mpScaleY(wxString name)
340 SetFont(*wxSMALL_FONT);
341 SetPen(*wxGREY_PEN);*/
342 wxFont ff( *wxSMALL_FONT);
343 wxPen pp( *wxGREY_PEN);
348 void mpScaleY::Plot(wxDC & dc, mpWindow & w, int orgy)
353 const int orgx = -(int)(w.GetPosX() * w.GetScaleX());
354 const int extend = w.GetScrY()/2;
356 double sizedc = dc.GetSize().GetHeight()-orgy;
358 dc.DrawLine( orgx, GetYTranslated(sizedc, -extend), orgx, GetYTranslated(sizedc, extend));
360 const double dig = floor( log( 128.0 / w.GetScaleY() ) / mpLN10 );
361 const double step = exp( mpLN10 * dig);
362 const double end = w.GetPosY() + (double)extend / w.GetScaleY();
375 fmt.Printf(wxT("%%.%df"), tmp >= -1 ? 2 : -tmp);
378 double n = floor( (w.GetPosY() - (double)extend / w.GetScaleY()) / step ) * step ;
381 for (;n < end; n += step)
383 const int p = (int)((w.GetPosY() - n) * w.GetScaleY());
384 dc.DrawLine( orgx, GetYTranslated(sizedc, p), orgx+4, GetYTranslated(sizedc,p));
387 dc.GetTextExtent(s, &tx, &ty);
388 if ((tmp-p+ty/2) > 32)
390 dc.DrawText( s, orgx+4, GetYTranslated(sizedc,p-ty/2));
395 dc.GetTextExtent(m_name, &tx, &ty);
396 dc.DrawText( m_name, orgx-tx-4, GetYTranslated(sizedc,-extend + ty + 4));
399 //-----------------------------------------------------------------------------
401 //-----------------------------------------------------------------------------
403 IMPLEMENT_DYNAMIC_CLASS(mpWindow, wxScrolledWindow)
405 BEGIN_EVENT_TABLE(mpWindow, wxScrolledWindow)
406 EVT_PAINT ( mpWindow::OnPaint)
407 EVT_SIZE ( mpWindow::OnSize)
408 EVT_SCROLLWIN( mpWindow::OnScroll2)
410 EVT_MIDDLE_UP( mpWindow::OnShowPopupMenu)
411 EVT_RIGHT_UP ( mpWindow::OnShowPopupMenu)
412 EVT_MENU( mpID_CENTER, mpWindow::OnCenter)
413 EVT_MENU( mpID_FIT, mpWindow::OnFit)
414 EVT_MENU( mpID_ZOOM_IN, mpWindow::OnZoomIn)
415 EVT_MENU( mpID_ZOOM_OUT, mpWindow::OnZoomOut)
416 //EVT_MENU( mpID_LINE_GUIDES, mpWindow::OnGuideLines)
417 // New method that belongs to the mpWindow
418 EVT_MENU( mpID_LOCKASPECT,mpWindow::OnLockAspect)
421 mpWindow::mpWindow( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, int flag )
422 : wxScrolledWindow( parent, id, wxDefaultPosition, wxDefaultSize, flag, wxT("wxPlotter") )
424 m_scaleX = m_scaleY = 1.0;
426 m_scrX = m_scrY = 64;
429 maxScrX = maxScrY = 200;
430 minScrX = minScrY = 0;
433 m_lockaspect = FALSE;
434 offsetX = offsetY = 0;
435 offsetPixelX = offsetPixelY= 0;
436 _bitmap_functions=NULL;
438 real_guideLine_X = -1;
439 real_guideLine_Y = -1;
443 m_popmenu.Append( mpID_CENTER, _("Center"), _("Center plot view to this position"));
444 m_popmenu.Append( mpID_FIT, _("Fit"), _("Set plot view to show all items"));
445 m_popmenu.Append( mpID_ZOOM_IN, _("Zoom in"), _("Zoom in plot view."));
446 m_popmenu.Append( mpID_ZOOM_OUT, _("Zoom out"), _("Zoom out plot view."));
447 m_popmenu.AppendCheckItem( mpID_LOCKASPECT, _("Lock aspect"), _("Lock horizontal and vertical zoom aspect."));
449 m_popmenu.AppendCheckItem( mpID_LINE_GUIDES, _("Turn off guide lines"), _("Enables/Disables the guide lines"));
451 m_layers.DeleteContents(TRUE);
452 SetBackgroundColour( *wxWHITE );
453 EnableScrolling(FALSE, FALSE);
454 SetSizeHints(128, 128);
456 //_bitmap_functions= new wxBitmap(700,800);
461 mpWindow::~mpWindow()
470 GetClientSize( &cx, &cy);
477 m_posX = m_minX + d/2;
483 m_posY = m_minY + d/2;
488 double s = (m_scaleX + m_scaleY)/2;
497 void mpWindow::ZoomIn()
499 m_scaleX = m_scaleX * 2;
500 m_scaleY = m_scaleY * 2;
504 void mpWindow::ZoomOut()
506 m_scaleX = m_scaleX / 2;
507 m_scaleY = m_scaleY / 2;
511 void mpWindow::LockAspect(bool enable)
513 m_lockaspect = enable;
515 m_popmenu.Check(mpID_LOCKASPECT, enable);
519 double s = (m_scaleX + m_scaleY)/2;
527 void mpWindow::OnShowPopupMenu(wxMouseEvent &event)
529 m_clickedX = event.GetX();
530 m_clickedY = event.GetY();
531 PopupMenu( &m_popmenu, event.GetX(), event.GetY());
534 void mpWindow::OnLockAspect(wxCommandEvent &event)
536 LockAspect( !m_popmenu.IsChecked(mpID_LOCKASPECT) );
539 void mpWindow::OnFit(wxCommandEvent &event)
544 void mpWindow::OnCenter(wxCommandEvent &event)
547 GetClientSize(&cx, &cy);
548 SetPos( (double)(m_clickedX-cx/2) / m_scaleX + m_posX, (double)(cy/2-m_clickedY) / m_scaleY + m_posY);
551 void mpWindow::OnZoomIn(wxCommandEvent &event)
554 GetClientSize(&cx, &cy);
555 m_posX = (double)(m_clickedX-cx/2) / m_scaleX + m_posX;
556 m_posY = (double)(cy/2-m_clickedY) / m_scaleY + m_posY;
560 void mpWindow::OnZoomOut(wxCommandEvent &event)
565 void mpWindow::OnSize( wxSizeEvent &event )
570 bool mpWindow::AddLayer( mpLayer* layer)
572 bool ret = m_layers.Append( layer) != NULL;
577 void mpWindow::DelLayer( mpLayer* layer)
579 m_layers.DeleteObject( layer);
583 void mpWindow::Refresh(bool eraseBackground, const wxRect* rect)
585 wxScrolledWindow::Refresh(false);
589 void mpWindow::OnPaint( wxPaintEvent &event )
592 dc.GetSize(&m_scrX, &m_scrY);
598 //_bitmap_functions->SetWidth(m_scrX);
599 //_bitmap_functions->SetHeight(m_scrY);
600 _bitmap_functions=new wxBitmap(m_scrX,m_scrY);
601 temp_dc.SelectObject(*_bitmap_functions);
604 // wxColour colourParent = wxColour(255,0,0);
605 temp_dc.SetBrush(wxBrush( *wxWHITE_BRUSH ) );
606 temp_dc.SetPen(wxPen( *wxBLACK_PEN ));
607 temp_dc.DrawRectangle(0,0,m_scrX,m_scrY);
610 wxNode *node = m_layers.GetFirst();
613 ((mpLayer*)node->GetData())->Plot( temp_dc, *this);
614 node = node->GetNext();
617 //dc.SetDeviceOrigin(70,40);
618 //dc.SetAxisOrientation(false,true);
619 //temp_dc.SetAxisOrientation(true,false);
622 //dc.Blit(0,0, m_scrX, m_scrY, &temp_dc,-70,-m_scrY+40);
624 temp_dc.SetDeviceOrigin(0,0);
625 dc.Blit(0,0, m_scrX, m_scrY, &temp_dc,0,0);
628 delete _bitmap_functions;
630 //dc.SetAxisOrientation(false,true);
636 void mpWindow::OnPaint( wxPaintEvent &event )
642 dc.GetSize(&m_scrX, &m_scrY);
644 //const int orgy = m_scrY-40;
645 //dc.SetDeviceOrigin(70,orgy);
646 //dc.SetAxisOrientation(true,true);
648 // wxMemoryDC temp_dc;
650 // //_bitmap_functions=new wxBitmap(m_scrX,m_scrY);
652 // _bitmap_functions->SetWidth(100);//m_scrX);
653 // _bitmap_functions->SetHeight(200);//m_scrY);
655 // temp_dc.SelectObject(*_bitmap_functions);
658 // wxColour colourParent = wxColour(255,0,0);
659 // temp_dc.SetBrush(wxBrush( colourParent ,wxSOLID ));
660 // temp_dc.SetPen(wxPen( colourParent ,1,wxSOLID ));
661 // temp_dc.DrawRectangle(0,0,100,200);
662 // dc.Blit(0,0, 100, 200, &temp_dc,0,0);
663 // //dc.SetDeviceOrigin( m_scrX>>1, m_scrY>>1);
665 wxNode *node = m_layers.GetFirst();
668 ((mpLayer*)node->GetData())->Plot( dc, *this);
669 node = node->GetNext();
671 //temp_dc.SetAxisOrientation(true,false);
673 // dc.SetAxisOrientation(true,true);
674 //dc.Blit(70,(int)(-m_scrY+40),m_scrX-100,m_scrY-50,&temp_dc,0,0);
678 void mpWindow::OnScroll2(wxScrollWinEvent &event)
681 GetClientSize( &width, &height);
683 GetViewStart( &px, &py);
685 if (event.GetOrientation() == wxHORIZONTAL)
687 SetPosX( (double)px / GetScaleX() + m_minX + (double)(width>>1)/GetScaleX());
691 SetPosY( m_maxY - (double)py / GetScaleY() - (double)(height>>1)/GetScaleY());
696 bool mpWindow::UpdateBBox()
700 wxNode *node = m_layers.GetFirst();
704 mpLayer* f = (mpLayer*)node->GetData();
711 m_minX = f->GetMinX(); m_maxX=f->GetMaxX();
712 m_minY = f->GetMinY(); m_maxY=f->GetMaxY();
716 if (f->GetMinX()<m_minX) m_minX=f->GetMinX(); if (f->GetMaxX()>m_maxX) m_maxX=f->GetMaxX();
717 if (f->GetMinY()<m_minY) m_minY=f->GetMinY(); if (f->GetMaxY()>m_maxY) m_maxY=f->GetMaxY();
720 node = node->GetNext();
723 return first == FALSE;
726 void mpWindow::UpdateAll()
731 GetClientSize( &cx, &cy);
732 const int sx = (int)((m_maxX - m_minX) * GetScaleX()); // JPRx
733 const int sy = (int)((m_maxY - m_minY) * GetScaleY()); // JPRx
734 const int px = (int)((GetPosX() - m_minX) * GetScaleX() - (cx>>1)); // JPRx
735 const int py = (int)((GetPosY() - m_minY) * GetScaleY() - (cy>>1)); // JPRx
736 SetScrollbars( 1, 1, sx, sy, px, py);
743 * Guide lines menu handler method that reacts to the mpID_LINE_GUIDES cimmand event
744 * event The corresponding event to handle
747 void mpWindow :: OnGuideLines (wxCommandEvent &event)
749 wxString nextAction_text;
752 setLineGuidesCondition(false);
753 nextAction_text << "Turn on guide lines";
758 setLineGuidesCondition(true);
759 nextAction_text << "Turn off guide lines";
762 m_popmenu.SetLabel ( mpID_LINE_GUIDES, nextAction_text );
768 bool mpWindow::drawGuideLines()