KiCad PCB EDA Suite
mathplot.cpp
Go to the documentation of this file.
1 // Name: mathplot.cpp
3 // Purpose: Framework for plotting in wxWindows
4 // Original Author: David Schalig
5 // Maintainer: Davide Rondini
6 // Contributors: Jose Luis Blanco, Val Greene, Maciej Suminski, Tomasz Wlostowski
7 // Created: 21/07/2003
8 // Last edit: 25/08/2016
9 // Copyright: (c) David Schalig, Davide Rondini
10 // Licence: wxWindows licence
12 
13 #include <wx/window.h>
14 
15 // Comment out for release operation:
16 // (Added by J.L.Blanco, Aug 2007)
17 //#define MATHPLOT_DO_LOGGING
18 
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22 
23 #ifndef WX_PRECOMP
24 #include "wx/object.h"
25 #include "wx/font.h"
26 #include "wx/colour.h"
27 #include "wx/settings.h"
28 #include "wx/sizer.h"
29 #include "wx/log.h"
30 #include "wx/intl.h"
31 #include "wx/dcclient.h"
32 #include "wx/cursor.h"
33 #endif
34 
35 #include <widgets/mathplot.h>
36 #include <wx/bmpbuttn.h>
37 #include <wx/module.h>
38 #include <wx/msgdlg.h>
39 #include <wx/image.h>
40 #include <wx/tipwin.h>
41 
42 #include <cmath>
43 #include <cstdio> // used only for debug
44 #include <ctime> // used for representation of x axes involving date
45 #include <set>
46 
47 // Memory leak debugging
48 #ifdef _DEBUG
49 #define new DEBUG_NEW
50 #endif
51 
52 // Legend margins
53 #define mpLEGEND_MARGIN 5
54 #define mpLEGEND_LINEWIDTH 10
55 
56 // Minimum axis label separation
57 #define mpMIN_X_AXIS_LABEL_SEPARATION 64
58 #define mpMIN_Y_AXIS_LABEL_SEPARATION 32
59 
60 // Number of pixels to scroll when scrolling by a line
61 #define mpSCROLL_NUM_PIXELS_PER_LINE 10
62 
63 // See doxygen comments.
65 
66 // -----------------------------------------------------------------------------
67 // mpLayer
68 // -----------------------------------------------------------------------------
69 
70 IMPLEMENT_ABSTRACT_CLASS( mpLayer, wxObject )
71 
73 {
74  SetPen( (wxPen&) *wxBLACK_PEN );
75  SetFont( (wxFont&) *wxNORMAL_FONT );
76  m_continuous = false; // Default
77  m_showName = true; // Default
78  m_drawOutsideMargins = false;
79  m_visible = true;
80 }
81 
82 
83 wxBitmap mpLayer::GetColourSquare( int side )
84 {
85  wxBitmap square( side, side, -1 );
86  wxColour filler = m_pen.GetColour();
87  wxBrush brush( filler, wxBRUSHSTYLE_SOLID );
88  wxMemoryDC dc;
89 
90  dc.SelectObject( square );
91  dc.SetBackground( brush );
92  dc.Clear();
93  dc.SelectObject( wxNullBitmap );
94  return square;
95 }
96 
97 
98 // -----------------------------------------------------------------------------
99 // mpInfoLayer
100 // -----------------------------------------------------------------------------
101 IMPLEMENT_DYNAMIC_CLASS( mpInfoLayer, mpLayer )
102 
104 {
105  m_dim = wxRect( 0, 0, 1, 1 );
106  m_brush = *wxTRANSPARENT_BRUSH;
107  m_reference.x = 0; m_reference.y = 0;
108  m_winX = 1; // parent->GetScrX();
109  m_winY = 1; // parent->GetScrY();
110  m_type = mpLAYER_INFO;
111 }
112 
113 
114 mpInfoLayer::mpInfoLayer( wxRect rect, const wxBrush* brush ) : m_dim( rect )
115 {
116  m_brush = *brush;
117  m_reference.x = rect.x;
118  m_reference.y = rect.y;
119  m_winX = 1; // parent->GetScrX();
120  m_winY = 1; // parent->GetScrY();
122 }
123 
124 
126 {
127 }
128 
129 
130 void mpInfoLayer::UpdateInfo( mpWindow& w, wxEvent& event )
131 {
132 }
133 
134 
136 {
137  return m_dim.Contains( point );
138 }
139 
140 
142 {
143  m_dim.SetX( m_reference.x + delta.x );
144  m_dim.SetY( m_reference.y + delta.y );
145 }
146 
147 
149 {
150  m_reference.x = m_dim.x;
151  m_reference.y = m_dim.y;
152 }
153 
154 
155 void mpInfoLayer::Plot( wxDC& dc, mpWindow& w )
156 {
157  if( m_visible )
158  {
159  // Adjust relative position inside the window
160  int scrx = w.GetScrX();
161  int scry = w.GetScrY();
162 
163  // Avoid dividing by 0
164  if( scrx == 0 )
165  scrx = 1;
166 
167  if( scry == 0 )
168  scry = 1;
169 
170  if( (m_winX != scrx) || (m_winY != scry) )
171  {
172 #ifdef MATHPLOT_DO_LOGGING
173  // wxLogMessage( "mpInfoLayer::Plot() screen size has changed from %d x %d to %d x %d", m_winX, m_winY, scrx, scry);
174 #endif
175 
176  if( m_winX > 1 )
177  m_dim.x = (int) floor( (double) (m_dim.x * scrx / m_winX) );
178 
179  if( m_winY > 1 )
180  {
181  m_dim.y = (int) floor( (double) (m_dim.y * scry / m_winY) );
182  UpdateReference();
183  }
184 
185  // Finally update window size
186  m_winX = scrx;
187  m_winY = scry;
188  }
189 
190  dc.SetPen( m_pen );
191  // wxImage image0(wxT("pixel.png"), wxBITMAP_TYPE_PNG);
192  // wxBitmap image1(image0);
193  // wxBrush semiWhite(image1);
194  dc.SetBrush( m_brush );
195  dc.DrawRectangle( m_dim.x, m_dim.y, m_dim.width, m_dim.height );
196  }
197 }
198 
199 
201 {
202  return m_dim.GetPosition();
203 }
204 
205 
207 {
208  return m_dim.GetSize();
209 }
210 
211 
213 {
214 }
215 
216 
217 mpInfoCoords::mpInfoCoords( wxRect rect, const wxBrush* brush ) : mpInfoLayer( rect, brush )
218 {
219 }
220 
221 
223 {
224 }
225 
226 
227 void mpInfoCoords::UpdateInfo( mpWindow& w, wxEvent& event )
228 {
229  if( event.GetEventType() == wxEVT_MOTION )
230  {
231  /* It seems that Windows port of wxWidgets don't support multi-line test to be drawn in a wxDC.
232  * wxGTK instead works perfectly with it.
233  * Info on wxForum: http://wxforum.shadonet.com/viewtopic.php?t=3451&highlight=drawtext+eol */
234 #ifdef _WINDOWS
235  // FIXME m_content.Printf(wxT("x = %f y = %f"), XScale().P2x(w, mouseX), YScale().P2x(w, mouseY));
236 #else
237  // FIXME m_content.Printf(wxT("x = %f\ny = %f"), XScale().P2x(w, mouseX), YScale().P2x(w, mouseY));
238 #endif
239  }
240 }
241 
242 
243 void mpInfoCoords::Plot( wxDC& dc, mpWindow& w )
244 {
245  if( m_visible )
246  {
247  // Adjust relative position inside the window
248  int scrx = w.GetScrX();
249  int scry = w.GetScrY();
250 
251  if( (m_winX != scrx) || (m_winY != scry) )
252  {
253 #ifdef MATHPLOT_DO_LOGGING
254  // wxLogMessage( "mpInfoLayer::Plot() screen size has changed from %d x %d to %d x %d", m_winX, m_winY, scrx, scry);
255 #endif
256 
257  if( m_winX > 1 )
258  m_dim.x = (int) floor( (double) (m_dim.x * scrx / m_winX) );
259 
260  if( m_winY > 1 )
261  {
262  m_dim.y = (int) floor( (double) (m_dim.y * scry / m_winY) );
263  UpdateReference();
264  }
265 
266  // Finally update window size
267  m_winX = scrx;
268  m_winY = scry;
269  }
270 
271  dc.SetPen( m_pen );
272  // wxImage image0(wxT("pixel.png"), wxBITMAP_TYPE_PNG);
273  // wxBitmap image1(image0);
274  // wxBrush semiWhite(image1);
275  dc.SetBrush( m_brush );
276  dc.SetFont( m_font );
277  int textX, textY;
278  dc.GetTextExtent( m_content, &textX, &textY );
279 
280  if( m_dim.width < textX + 10 )
281  m_dim.width = textX + 10;
282 
283  if( m_dim.height < textY + 10 )
284  m_dim.height = textY + 10;
285 
286  dc.DrawRectangle( m_dim.x, m_dim.y, m_dim.width, m_dim.height );
287  dc.DrawText( m_content, m_dim.x + 5, m_dim.y + 5 );
288  }
289 }
290 
291 
293 {
294 }
295 
296 
297 mpInfoLegend::mpInfoLegend( wxRect rect, const wxBrush* brush ) : mpInfoLayer( rect, brush )
298 {
299 }
300 
301 
303 {
304 }
305 
306 
307 void mpInfoLegend::UpdateInfo( mpWindow& w, wxEvent& event )
308 {
309 }
310 
311 
312 void mpInfoLegend::Plot( wxDC& dc, mpWindow& w )
313 {
314  if( m_visible )
315  {
316  // Adjust relative position inside the window
317  int scrx = w.GetScrX();
318  int scry = w.GetScrY();
319 
320  if( (m_winX != scrx) || (m_winY != scry) )
321  {
322 #ifdef MATHPLOT_DO_LOGGING
323  // wxLogMessage( "mpInfoLayer::Plot() screen size has changed from %d x %d to %d x %d", m_winX, m_winY, scrx, scry);
324 #endif
325 
326  if( m_winX > 1 )
327  m_dim.x = (int) floor( (double) (m_dim.x * scrx / m_winX) );
328 
329  if( m_winY > 1 )
330  {
331  m_dim.y = (int) floor( (double) (m_dim.y * scry / m_winY) );
332  UpdateReference();
333  }
334 
335  // Finally update window size
336  m_winX = scrx;
337  m_winY = scry;
338  }
339 
340  // wxImage image0(wxT("pixel.png"), wxBITMAP_TYPE_PNG);
341  // wxBitmap image1(image0);
342  // wxBrush semiWhite(image1);
343  dc.SetBrush( m_brush );
344  dc.SetFont( m_font );
345  const int baseWidth = (mpLEGEND_MARGIN * 2 + mpLEGEND_LINEWIDTH);
346  int textX = baseWidth, textY = mpLEGEND_MARGIN;
347  int plotCount = 0;
348  int posY = 0;
349  int tmpX = 0, tmpY = 0;
350  mpLayer* ly = NULL;
351  wxPen lpen;
352  wxString label;
353 
354  for( unsigned int p = 0; p < w.CountAllLayers(); p++ )
355  {
356  ly = w.GetLayer( p );
357 
358  if( (ly->GetLayerType() == mpLAYER_PLOT) && ( ly->IsVisible() ) )
359  {
360  label = ly->GetName();
361  dc.GetTextExtent( label, &tmpX, &tmpY );
362  textX =
363  ( textX > (tmpX + baseWidth) ) ? textX : (tmpX + baseWidth + mpLEGEND_MARGIN);
364  textY += (tmpY);
365 #ifdef MATHPLOT_DO_LOGGING
366  // wxLogMessage( "mpInfoLegend::Plot() Adding layer %d: %s", p, label.c_str());
367 #endif
368  }
369  }
370 
371  dc.SetPen( m_pen );
372  dc.SetBrush( m_brush );
373  m_dim.width = textX;
374 
375  if( textY != mpLEGEND_MARGIN ) // Don't draw any thing if there are no visible layers
376  {
377  textY += mpLEGEND_MARGIN;
378  m_dim.height = textY;
379  dc.DrawRectangle( m_dim.x, m_dim.y, m_dim.width, m_dim.height );
380 
381  for( unsigned int p2 = 0; p2 < w.CountAllLayers(); p2++ )
382  {
383  ly = w.GetLayer( p2 );
384 
385  if( (ly->GetLayerType() == mpLAYER_PLOT) && ( ly->IsVisible() ) )
386  {
387  label = ly->GetName();
388  lpen = ly->GetPen();
389  dc.GetTextExtent( label, &tmpX, &tmpY );
390  dc.SetPen( lpen );
391  // textX = (textX > (tmpX + baseWidth)) ? textX : (tmpX + baseWidth);
392  // textY += (tmpY + mpLEGEND_MARGIN);
393  posY = m_dim.y + mpLEGEND_MARGIN + plotCount * tmpY + (tmpY >> 1);
394  dc.DrawLine( m_dim.x + mpLEGEND_MARGIN, // X start coord
395  posY, // Y start coord
396  m_dim.x + mpLEGEND_LINEWIDTH + mpLEGEND_MARGIN, // X end coord
397  posY );
398  // dc.DrawRectangle(m_dim.x + 5, m_dim.y + 5 + plotCount*tmpY, 5, 5);
399  dc.DrawText( label,
400  m_dim.x + baseWidth,
401  m_dim.y + mpLEGEND_MARGIN + plotCount * tmpY );
402  plotCount++;
403  }
404  }
405  }
406  }
407 }
408 
409 
410 #if 0
411 double mpScaleXLog::X2p( mpWindow& w, double x )
412 {
413  return ( x - w.GetPosX() ) * w.GetScaleX();
414 }
415 
416 
417 double mpScaleXLog::P2x( mpWindow& w, double x )
418 {
419  return w.GetPosX() + x / w.GetScaleX();
420 }
421 
422 
423 double mpScaleX::X2p( mpWindow& w, double x )
424 {
425  return ( x - w.GetPosX() ) * w.GetScaleX();
426 }
427 
428 
429 double mpScaleX::P2x( mpWindow& w, double x )
430 {
431  return w.GetPosX() + x / w.GetScaleX();
432 }
433 
434 
435 double mpScaleY::X2p( mpWindow& w, double x )
436 {
437  return ( w.GetPosY() - x ) * w.GetScaleY();
438 }
439 
440 
441 double mpScaleY::P2x( mpWindow& w, double x )
442 {
443  return w.GetPosY() - x / w.GetScaleY();
444 }
445 
446 
447 #endif
448 
449 
450 // -----------------------------------------------------------------------------
451 // mpLayer implementations - functions
452 // -----------------------------------------------------------------------------
453 
454 IMPLEMENT_ABSTRACT_CLASS( mpFX, mpLayer )
455 
456 mpFX::mpFX( const wxString& name, int flags )
457 {
458  SetName( name );
459  m_flags = flags;
460  m_type = mpLAYER_PLOT;
461 }
462 
463 
464 void mpFX::Plot( wxDC& dc, mpWindow& w )
465 {
466  if( m_visible )
467  {
468  dc.SetPen( m_pen );
469 
470  wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
471  wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
472  wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
473  wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
474 
475  wxCoord iy = 0;
476 
477  if( m_pen.GetWidth() <= 1 )
478  {
479  for( wxCoord i = startPx; i < endPx; ++i )
480  {
481  iy = w.y2p( GetY( w.p2x( i ) ) );
482 
483  // Draw the point only if you can draw outside margins or if the point is inside margins
484  if( m_drawOutsideMargins || ( (iy >= minYpx) && (iy <= maxYpx) ) )
485  dc.DrawPoint( i, iy ); // (wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY()));
486  }
487  }
488  else
489  {
490  for( wxCoord i = startPx; i < endPx; ++i )
491  {
492  iy = w.y2p( GetY( w.p2x( i ) ) );
493 
494  // Draw the point only if you can draw outside margins or if the point is inside margins
495  if( m_drawOutsideMargins || ( (iy >= minYpx) && (iy <= maxYpx) ) )
496  dc.DrawLine( i, iy, i, iy );
497 
498  // wxCoord c = YScale().X2p( GetY(XScale().P2x(i)) );
499  //(wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY());
500  }
501  }
502 
503  if( !m_name.IsEmpty() && m_showName )
504  {
505  dc.SetFont( m_font );
506 
507  wxCoord tx, ty;
508  dc.GetTextExtent( m_name, &tx, &ty );
509 
510  /*if ((m_flags & mpALIGNMASK) == mpALIGN_RIGHT)
511  * tx = (w.GetScrX()>>1) - tx - 8;
512  * else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
513  * tx = -tx/2;
514  * else
515  * tx = -(w.GetScrX()>>1) + 8;
516  */
517  if( (m_flags & mpALIGNMASK) == mpALIGN_RIGHT )
518  tx = (w.GetScrX() - tx) - w.GetMarginRight() - 8;
519  else if( (m_flags & mpALIGNMASK) == mpALIGN_CENTER )
520  tx = ( (w.GetScrX() - w.GetMarginRight() - w.GetMarginLeft() - tx) / 2 ) +
521  w.GetMarginLeft();
522  else
523  tx = w.GetMarginLeft() + 8;
524 
525  dc.DrawText( m_name, tx, w.y2p( GetY( w.p2x( tx ) ) ) );
526  }
527  }
528 }
529 
530 
531 IMPLEMENT_ABSTRACT_CLASS( mpFY, mpLayer )
532 
533 mpFY::mpFY( const wxString& name, int flags )
534 {
535  SetName( name );
536  m_flags = flags;
537  m_type = mpLAYER_PLOT;
538 }
539 
540 
541 void mpFY::Plot( wxDC& dc, mpWindow& w )
542 {
543  if( m_visible )
544  {
545  dc.SetPen( m_pen );
546 
547  wxCoord i, ix;
548 
549  wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
550  wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
551  wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
552  wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
553 
554  if( m_pen.GetWidth() <= 1 )
555  {
556  for( i = minYpx; i < maxYpx; ++i )
557  {
558  ix = w.x2p( GetX( w.p2y( i ) ) );
559 
560  if( m_drawOutsideMargins || ( (ix >= startPx) && (ix <= endPx) ) )
561  dc.DrawPoint( ix, i );
562  }
563  }
564  else
565  {
566  for( i = 0; i< w.GetScrY(); ++i )
567  {
568  ix = w.x2p( GetX( w.p2y( i ) ) );
569 
570  if( m_drawOutsideMargins || ( (ix >= startPx) && (ix <= endPx) ) )
571  dc.DrawLine( ix, i, ix, i );
572 
573  // wxCoord c = XScale().X2p(GetX(YScale().P2x(i)));
574  //(wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX());
575  // dc.DrawLine(c, i, c, i);
576  }
577  }
578 
579  if( !m_name.IsEmpty() && m_showName )
580  {
581  dc.SetFont( m_font );
582 
583  wxCoord tx, ty;
584  dc.GetTextExtent( m_name, &tx, &ty );
585 
586  if( (m_flags & mpALIGNMASK) == mpALIGN_TOP )
587  ty = w.GetMarginTop() + 8;
588  else if( (m_flags & mpALIGNMASK) == mpALIGN_CENTER )
589  ty = ( (w.GetScrY() - w.GetMarginTop() - w.GetMarginBottom() - ty) / 2 ) +
590  w.GetMarginTop();
591  else
592  ty = w.GetScrY() - 8 - ty - w.GetMarginBottom();
593 
594  dc.DrawText( m_name, w.x2p( GetX( w.p2y( ty ) ) ), ty ); // (wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX()), -ty);
595  }
596  }
597 }
598 
599 
600 IMPLEMENT_ABSTRACT_CLASS( mpFXY, mpLayer )
601 
602 mpFXY::mpFXY( const wxString& name, int flags )
603 {
604  SetName( name );
605  m_flags = flags;
606  m_type = mpLAYER_PLOT;
607  m_scaleX = NULL;
608  m_scaleY = NULL;
609 
610  // Avoid not initialized members:
611  maxDrawX = minDrawX = maxDrawY = minDrawY = 0;
612 }
613 
614 
615 void mpFXY::UpdateViewBoundary( wxCoord xnew, wxCoord ynew )
616 {
617  // Keep track of how many points have been drawn and the bounding box
618  maxDrawX = (xnew > maxDrawX) ? xnew : maxDrawX;
619  minDrawX = (xnew < minDrawX) ? xnew : minDrawX;
620  maxDrawY = (maxDrawY > ynew) ? maxDrawY : ynew;
621  minDrawY = (minDrawY < ynew) ? minDrawY : ynew;
622  // drawnPoints++;
623 }
624 
625 
626 void mpFXY::Plot( wxDC& dc, mpWindow& w )
627 {
628  if( m_visible )
629  {
630  dc.SetPen( m_pen );
631 
632  double x, y;
633  // Do this to reset the counters to evaluate bounding box for label positioning
634  Rewind(); GetNextXY( x, y );
635  maxDrawX = x; minDrawX = x; maxDrawY = y; minDrawY = y;
636  // drawnPoints = 0;
637  Rewind();
638 
639  wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
640  wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
641  wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
642  wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
643 
644  dc.SetClippingRegion( startPx, minYpx, endPx - startPx + 1, maxYpx - minYpx + 1 );
645 
646  if( !m_continuous )
647  {
648  bool first = true;
649  wxCoord ix;
650  std::set<wxCoord> ys;
651 
652  while( GetNextXY( x, y ) )
653  {
654  double px = m_scaleX->TransformToPlot( x );
655  double py = m_scaleY->TransformToPlot( y );
656  wxCoord newX = w.x2p( px );
657 
658  if( first )
659  {
660  ix = newX;
661  first = false;
662  }
663 
664  if( newX == ix ) // continue until a new X coordinate is reached
665  {
666  // collect all unique points
667  ys.insert( w.y2p( py ) );
668  continue;
669  }
670 
671  for( auto& iy: ys )
672  {
674  || ( (ix >= startPx) && (ix <= endPx) && (iy >= minYpx)
675  && (iy <= maxYpx) ) )
676  {
677  // for some reason DrawPoint does not use the current pen,
678  // so we use DrawLine for fat pens
679  if( m_pen.GetWidth() <= 1 )
680  {
681  dc.DrawPoint( ix, iy );
682  }
683  else
684  {
685  dc.DrawLine( ix, iy, ix, iy );
686  }
687 
688  UpdateViewBoundary( ix, iy );
689  }
690  }
691 
692  ys.clear();
693  ix = newX;
694  ys.insert( w.y2p( py ) );
695  }
696  }
697  else
698  {
699  wxPoint* points = new wxPoint[GetCount()];
700  int count = 0;
701 
702  while( GetNextXY( x, y ) )
703  {
704  double px = m_scaleX->TransformToPlot( x );
705  double py = m_scaleY->TransformToPlot( y );
706 
707  wxCoord x1 = w.x2p( px );
708  wxCoord y1 = w.y2p( py );
709 
710  points[count++] = wxPoint( x1, y1 );
711  }
712 
713  if( count > 0 )
714  dc.DrawLines( count, points );
715 
716  delete[] points;
717  }
718 
719  if( !m_name.IsEmpty() && m_showName )
720  {
721  dc.SetFont( m_font );
722 
723  wxCoord tx, ty;
724  dc.GetTextExtent( m_name, &tx, &ty );
725 
726  // xxx implement else ... if (!HasBBox())
727  {
728  // const int sx = w.GetScrX();
729  // const int sy = w.GetScrY();
730 
731  if( (m_flags & mpALIGNMASK) == mpALIGN_NW )
732  {
733  tx = minDrawX + 8;
734  ty = maxDrawY + 8;
735  }
736  else if( (m_flags & mpALIGNMASK) == mpALIGN_NE )
737  {
738  tx = maxDrawX - tx - 8;
739  ty = maxDrawY + 8;
740  }
741  else if( (m_flags & mpALIGNMASK) == mpALIGN_SE )
742  {
743  tx = maxDrawX - tx - 8;
744  ty = minDrawY - ty - 8;
745  }
746  else
747  {
748  // mpALIGN_SW
749  tx = minDrawX + 8;
750  ty = minDrawY - ty - 8;
751  }
752  }
753 
754  dc.DrawText( m_name, tx, ty );
755  }
756  }
757 
758  dc.DestroyClippingRegion();
759 }
760 
761 
762 // -----------------------------------------------------------------------------
763 // mpProfile implementation
764 // -----------------------------------------------------------------------------
765 
766 IMPLEMENT_ABSTRACT_CLASS( mpProfile, mpLayer )
767 
768 mpProfile::mpProfile( const wxString& name, int flags )
769 {
770  SetName( name );
771  m_flags = flags;
772  m_type = mpLAYER_PLOT;
773 }
774 
775 
776 void mpProfile::Plot( wxDC& dc, mpWindow& w )
777 {
778  if( m_visible )
779  {
780  dc.SetPen( m_pen );
781 
782  wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
783  wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
784  wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
785  wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
786 
787  // Plot profile linking subsequent point of the profile, instead of mpFY, which plots simple points.
788  for( wxCoord i = startPx; i < endPx; ++i )
789  {
790  wxCoord c0 = w.y2p( GetY( w.p2x( i ) ) ); // (wxCoord) ((w.GetYpos() - GetY( (double)i / w.GetXscl() + w.GetXpos()) ) * w.GetYscl());
791  wxCoord c1 = w.y2p( GetY( w.p2x( i + 1 ) ) ); // (wxCoord) ((w.GetYpos() - GetY( (double)(i+1) / w.GetXscl() + (w.GetXpos() ) ) ) * w.GetYscl());
792 
793  // c0 = (c0 <= maxYpx) ? ((c0 >= minYpx) ? c0 : minYpx) : maxYpx;
794  // c1 = (c1 <= maxYpx) ? ((c1 >= minYpx) ? c1 : minYpx) : maxYpx;
795  if( !m_drawOutsideMargins )
796  {
797  c0 = (c0 <= maxYpx) ? ( (c0 >= minYpx) ? c0 : minYpx ) : maxYpx;
798  c1 = (c1 <= maxYpx) ? ( (c1 >= minYpx) ? c1 : minYpx ) : maxYpx;
799  }
800 
801  dc.DrawLine( i, c0, i + 1, c1 );
802  }
803 
804  ;
805 
806  if( !m_name.IsEmpty() )
807  {
808  dc.SetFont( m_font );
809 
810  wxCoord tx, ty;
811  dc.GetTextExtent( m_name, &tx, &ty );
812 
813  if( (m_flags & mpALIGNMASK) == mpALIGN_RIGHT )
814  tx = (w.GetScrX() - tx) - w.GetMarginRight() - 8;
815  else if( (m_flags & mpALIGNMASK) == mpALIGN_CENTER )
816  tx = ( (w.GetScrX() - w.GetMarginRight() - w.GetMarginLeft() - tx) / 2 ) +
817  w.GetMarginLeft();
818  else
819  tx = w.GetMarginLeft() + 8;
820 
821  dc.DrawText( m_name, tx, w.y2p( GetY( w.p2x( tx ) ) ) ); // (wxCoord) ((w.GetPosY() - GetY( (double)tx / w.GetScaleX() + w.GetPosX())) * w.GetScaleY()) );
822  }
823  }
824 }
825 
826 
827 // -----------------------------------------------------------------------------
828 // mpLayer implementations - furniture (scales, ...)
829 // -----------------------------------------------------------------------------
830 
831 #define mpLN10 2.3025850929940456840179914546844
832 
834 {
835  double minV, maxV, minVvis, maxVvis;
836 
837  GetDataRange( minV, maxV );
838  getVisibleDataRange( w, minVvis, maxVvis );
839 
840  m_absVisibleMaxV = std::max( std::abs( minVvis ), std::abs( maxVvis ) );
841 
842  // printf("minV %.10f maxV %.10f %.10f %.10f\n", minV, maxV, minVvis, maxVvis);
843 
844  m_tickValues.clear();
845  m_tickLabels.clear();
846 
847  double minErr = 1000000000000.0;
848  double bestStep = 1.0;
849 
850  for( int i = 10; i <= 20; i += 2 )
851  {
852  double curr_step = fabs( maxVvis - minVvis ) / (double) i;
853  double base = pow( 10, floor( log10( curr_step ) ) );
854 
855  // printf("base %.3f\n", base);
856 
857  double stepInt = floor( curr_step / base ) * base;
858  double err = fabs( curr_step - stepInt );
859 
860  if( err < minErr )
861  {
862  minErr = err;
863  bestStep = stepInt;
864  }
865 
866  // printf("curr_step %d %.3f %.3f best %.3f\n",i, curr_step, stepInt, bestStep);
867  }
868 
869 
870  double v = floor( minVvis / bestStep ) * bestStep;
871 
872  double zeroOffset = 100000000.0;
873  // printf("maxVVis %.3f\n", maxVvis);
874 
875  while( v < maxVvis )
876  {
877  m_tickValues.push_back( v );
878 
879  if( fabs( v ) < zeroOffset )
880  zeroOffset = fabs( v );
881 
882  // printf("tick %.3f\n", v);
883  v += bestStep;
884  }
885 
886  if( zeroOffset <= bestStep )
887  {
888  for( double& t : m_tickValues )
889  t -= zeroOffset;
890  }
891 
892  for( double t : m_tickValues )
893  {
894  m_tickLabels.emplace_back( t );
895  }
896 
897  updateTickLabels( dc, w );
898 }
899 
900 
902 {
903  m_rangeSet = false;
905 
906  // initialize these members mainly to avoid not initialized values
907  m_offset = 0.0;
908  m_scale = 1.0;
909  m_absVisibleMaxV = 0.0;
910  m_flags = 0; // Flag for axis alignment
911  m_ticks = true; // Flag to toggle between ticks or grid
912  m_minV = 0.0;
913  m_maxV = 0.0;
914  m_maxLabelHeight = 1;
915  m_maxLabelWidth = 1;
916 }
917 
918 #if 0
919 int mpScaleBase::getLabelDecimalDigits( int maxDigits )
920 {
921  int m = 0;
922 
923  for( auto l : m_tickLabels )
924  {
925  int k = countDecimalDigits( l.pos );
926  m = std::max( k, m );
927  }
928 
929  return std::min( m, maxDigits );
930 }
931 
932 
933 #endif
934 
936 {
937  // printf("test: %d %d %d\n", countDecimalDigits(1.0), countDecimalDigits(1.1), countDecimalDigits(1.22231));
938  m_maxLabelHeight = 0;
939  m_maxLabelWidth = 0;
940 
941  for( int n = 0; n < labelCount(); n++ )
942  {
943  int tx, ty;
944  const wxString s = getLabel( n );
945 
946  dc.GetTextExtent( s, &tx, &ty );
947  m_maxLabelHeight = std::max( ty, m_maxLabelHeight );
948  m_maxLabelWidth = std::max( tx, m_maxLabelWidth );
949  }
950 }
951 
952 
954 {
955  formatLabels();
956  computeLabelExtents( dc, w );
957 
958  // int gap = IsHorizontal() ? m_maxLabelWidth + 10 : m_maxLabelHeight + 5;
959 
960  // if ( m_tickLabels.size() <= 2)
961  // return;
962 
963  /*
964  * fixme!
965  *
966  * for ( auto &l : m_tickLabels )
967  * {
968  * double p = TransformToPlot ( l.pos );
969  *
970  * if ( !IsHorizontal() )
971  * l.pixelPos = (int)(( w.GetPosY() - p ) * w.GetScaleY());
972  * else
973  * l.pixelPos = (int)(( p - w.GetPosX()) * w.GetScaleX());
974  * }
975  *
976  *
977  * for (int i = 1; i < m_tickLabels.size() - 1; i++)
978  * {
979  * int dist_prev;
980  *
981  * for(int j = i-1; j >= 1; j--)
982  * {
983  * if( m_tickLabels[j].visible)
984  * {
985  * dist_prev = abs( m_tickLabels[j].pixelPos - m_tickLabels[i].pixelPos );
986  * break;
987  * }
988  * }
989  *
990  * if (dist_prev < gap)
991  * m_tickLabels[i].visible = false;
992  * }
993  */
994 }
995 
996 
997 #if 0
998 int mpScaleX::tickCount() const
999 {
1000  return m_tickValues.size();
1001 }
1002 
1003 
1004 int mpScaleX::labelCount() const
1005 {
1006  return 0; // return m_labeledTicks.size();
1007 }
1008 
1009 
1010 const wxString mpScaleX::getLabel( int n )
1011 {
1012  return wxT( "L" );
1013 }
1014 
1015 
1016 double mpScaleX::getTickPos( int n )
1017 {
1018  return m_tickValues[n];
1019 }
1020 
1021 
1022 double mpScaleX::getLabelPos( int n )
1023 {
1024  return 0; // return m_labeledTicks[n];
1025 }
1026 
1027 
1028 #endif
1029 void mpScaleY::getVisibleDataRange( mpWindow& w, double& minV, double& maxV )
1030 {
1031  wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
1032  wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
1033 
1034  double pymin = w.p2y( minYpx );
1035  double pymax = w.p2y( maxYpx );
1036 
1037  // printf("PYmin %.3f PYmax %.3f\n", pymin, pymax);
1038 
1039  minV = TransformFromPlot( pymax );
1040  maxV = TransformFromPlot( pymin );
1041 }
1042 
1043 
1045 {
1046  if( m_masterScale->m_tickValues.size() == 0 )
1047  return;
1048 
1049  m_tickValues.clear();
1050  m_tickLabels.clear();
1051 
1052  // printf("NTicks %d\n", m_masterScale->m_tickValues.size());
1055 
1056  m_scale = 1.0 / ( m_maxV - m_minV );
1057  m_offset = -m_minV;
1058 
1059  double y_slave0 = p0 / m_scale;
1060  double y_slave1 = p1 / m_scale;
1061 
1062  double dy_slave = (y_slave1 - y_slave0);
1063  double exponent = floor( log10( dy_slave ) );
1064  double base = dy_slave / pow( 10.0, exponent );
1065 
1066  double dy_scaled = ceil( 2.0 * base ) / 2.0 * pow( 10.0, exponent );
1067 
1068  double minvv, maxvv;
1069 
1070  getVisibleDataRange( w, minvv, maxvv );
1071 
1072  minvv = floor( minvv / dy_scaled ) * dy_scaled;
1073 
1074  m_scale = 1.0 / ( m_maxV - m_minV );
1075  m_scale *= dy_slave / dy_scaled;
1076 
1077  m_offset = p0 / m_scale - minvv;
1078 
1079  m_tickValues.clear();
1080 
1081  double m;
1082 
1083  m_absVisibleMaxV = 0;
1084 
1085  for( unsigned int i = 0; i < m_masterScale->m_tickValues.size(); i++ )
1086  {
1088  m_tickValues.push_back( m );
1089  m_tickLabels.emplace_back( m );
1090  m_absVisibleMaxV = std::max( m_absVisibleMaxV, fabs( m ) );
1091  }
1092 }
1093 
1094 
1096 {
1097  // printf("this %p master %p\n", this, m_masterScale);
1098 
1099  if( m_masterScale )
1100  {
1101  computeSlaveTicks( w );
1102  updateTickLabels( dc, w );
1103 
1104  return;
1105  }
1106 
1107  double minV, maxV, minVvis, maxVvis;
1108  GetDataRange( minV, maxV );
1109  getVisibleDataRange( w, minVvis, maxVvis );
1110  // printf("vdr %.10f %.10f\n", minVvis, maxVvis);
1111 
1112  m_absVisibleMaxV = std::max( std::abs( minVvis ), std::abs( maxVvis ) );
1113 
1114 
1115  m_tickValues.clear();
1116  m_tickLabels.clear();
1117 
1118 
1119  double minErr = 1000000000000.0;
1120  double bestStep = 1.0;
1121 
1122  for( int i = 10; i <= 20; i += 2 )
1123  {
1124  double curr_step = fabs( maxVvis - minVvis ) / (double) i;
1125  double base = pow( 10, floor( log10( curr_step ) ) );
1126 
1127  // printf("base %.3f\n", base);
1128 
1129  double stepInt = floor( curr_step / base ) * base;
1130  double err = fabs( curr_step - stepInt );
1131 
1132  if( err< minErr )
1133  {
1134  minErr = err;
1135  bestStep = stepInt;
1136  }
1137 
1138  // printf("curr_step %d %.3f %.3f best %.3f\n",i, curr_step, stepInt, bestStep);
1139  }
1140 
1141 
1142  double v = floor( minVvis / bestStep ) * bestStep;
1143 
1144  double zeroOffset = 100000000.0;
1145  // printf("v %.3f maxVVis %.3f\n", v, maxVvis);
1146 
1147  const int iterLimit = 1000;
1148  int i = 0;
1149 
1150  while( v < maxVvis && i < iterLimit )
1151  {
1152  m_tickValues.push_back( v );
1153 
1154  if( fabs( v ) < zeroOffset )
1155  zeroOffset = fabs( v );
1156 
1157  // printf("tick %.3f %d\n", v, m_tickValues.size());
1158  v += bestStep;
1159  i++;
1160  }
1161 
1162 
1163  // something weird happened...
1164  if( i == iterLimit )
1165  {
1166  m_tickValues.clear();
1167  }
1168 
1169  if( zeroOffset <= bestStep )
1170  {
1171  for( double& t : m_tickValues )
1172  t -= zeroOffset;
1173  }
1174 
1175  for( double t : m_tickValues )
1176  m_tickLabels.emplace_back( t );
1177 
1178 
1179  // n0 = floor(minVvis / bestStep) * bestStep;
1180  // end = n0 +
1181 
1182  // n0 = floor( (w.GetPosX() ) / step ) * step ;
1183  // printf("zeroOffset:%.3f tickjs : %d\n", zeroOffset, m_tickValues.size());
1184  updateTickLabels( dc, w );
1185 
1186  // labelStep = ceil(((double) m_maxLabelWidth + mpMIN_X_AXIS_LABEL_SEPARATION)/(w.GetScaleX()*step))*step;
1187 }
1188 
1189 
1190 void mpScaleXBase::getVisibleDataRange( mpWindow& w, double& minV, double& maxV )
1191 {
1192  wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
1193  wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
1194 
1195  // printf("getVisibleDataRange\n");
1196 
1197  double pxmin = w.p2x( startPx );
1198  double pxmax = w.p2x( endPx );
1199 
1200  minV = TransformFromPlot( pxmin );
1201  maxV = TransformFromPlot( pxmax );
1202 }
1203 
1204 
1206 {
1207  double minV, maxV, minVvis, maxVvis;
1208 
1209  GetDataRange( minV, maxV );
1210  getVisibleDataRange( w, minVvis, maxVvis );
1211 
1212  // double decades = log( maxV / minV ) / log(10);
1213  double minDecade = pow( 10, floor( log10( minV ) ) );
1214  double maxDecade = pow( 10, ceil( log10( maxV ) ) );
1215  // printf("test: %d %d %d\n", countDecimalDigits(1.0), countDecimalDigits(1.1), countDecimalDigits(1.22231));
1216 
1217 
1218  double visibleDecades = log( maxVvis / minVvis ) / log( 10 );
1219 
1220  double d;
1221 
1222  m_tickValues.clear();
1223  m_tickLabels.clear();
1224 
1225  if( minDecade == 0.0 )
1226  return;
1227 
1228 
1229  for( d = minDecade; d<=maxDecade; d *= 10.0 )
1230  {
1231  // printf("d %.1f\n",d );
1232  m_tickLabels.emplace_back( d );
1233 
1234  for( double dd = d; dd < d * 10; dd += d )
1235  {
1236  if( visibleDecades < 2 )
1237  m_tickLabels.emplace_back( dd );
1238 
1239  m_tickValues.push_back( dd );
1240  }
1241  }
1242 
1243  updateTickLabels( dc, w );
1244 }
1245 
1246 
1247 IMPLEMENT_ABSTRACT_CLASS( mpScaleXBase, mpLayer )
1248 IMPLEMENT_DYNAMIC_CLASS( mpScaleX, mpScaleXBase )
1249 IMPLEMENT_DYNAMIC_CLASS( mpScaleXLog, mpScaleXBase )
1250 
1251 mpScaleXBase::mpScaleXBase( const wxString& name, int flags, bool ticks, unsigned int type )
1252 {
1253  SetName( name );
1254  SetFont( (wxFont&) *wxSMALL_FONT );
1255  SetPen( (wxPen&) *wxGREY_PEN );
1256  m_flags = flags;
1257  m_ticks = ticks;
1258  // m_labelType = type;
1259  m_type = mpLAYER_AXIS;
1260 }
1261 
1262 
1263 mpScaleX::mpScaleX( const wxString& name, int flags, bool ticks, unsigned int type ) :
1264  mpScaleXBase( name, flags, ticks, type )
1265 {
1266 }
1267 
1268 
1269 mpScaleXLog::mpScaleXLog( const wxString& name, int flags, bool ticks, unsigned int type ) :
1270  mpScaleXBase( name, flags, ticks, type )
1271 {
1272 }
1273 
1274 
1275 void mpScaleXBase::Plot( wxDC& dc, mpWindow& w )
1276 {
1277  int tx, ty;
1278 
1279  m_offset = -m_minV;
1280  m_scale = 1.0 / ( m_maxV - m_minV );
1281 
1282  recalculateTicks( dc, w );
1283 
1284  if( m_visible )
1285  {
1286  dc.SetPen( m_pen );
1287  dc.SetFont( m_font );
1288  int orgy = 0;
1289 
1290  const int extend = w.GetScrX();
1291 
1292  if( m_flags == mpALIGN_CENTER )
1293  orgy = w.y2p( 0 ); // (int)(w.GetPosY() * w.GetScaleY());
1294 
1295  if( m_flags == mpALIGN_TOP )
1296  {
1297  if( m_drawOutsideMargins )
1298  orgy = X_BORDER_SEPARATION;
1299  else
1300  orgy = w.GetMarginTop();
1301  }
1302 
1303  if( m_flags == mpALIGN_BOTTOM )
1304  {
1305  if( m_drawOutsideMargins )
1306  orgy = X_BORDER_SEPARATION;
1307  else
1308  orgy = w.GetScrY() - w.GetMarginBottom();
1309  }
1310 
1312  orgy = w.GetScrY() - 1; // dc.LogicalToDeviceY(0) - 1;
1313 
1314  if( m_flags == mpALIGN_BORDER_TOP )
1315  orgy = 1; // -dc.LogicalToDeviceY(0);
1316 
1317  // dc.DrawLine( 0, orgy, w.GetScrX(), orgy);
1318 
1319  wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
1320  wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
1321  wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
1322  wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
1323 
1324  // printf("StartPx %d endPx %d ordy %d maxy %d\n", startPx, endPx, orgy, maxYpx);
1325 
1326  // int tmp=-65535;
1327  int labelH = m_maxLabelHeight; // Control labels heigth to decide where to put axis name (below labels or on top of axis)
1328 
1329  // int maxExtent = tc.MaxLabelWidth();
1330  // printf("Ticks : %d\n",labelCount());
1331  for( int n = 0; n < tickCount(); n++ )
1332  {
1333  double tp = getTickPos( n );
1334 
1335  // double xlogmin = log10 ( m_minV );
1336  // double xlogmax = log10 ( m_maxV );
1337 
1338  double px = TransformToPlot( tp ); // ( log10 ( tp ) - xlogmin) / (xlogmax - xlogmin);
1339 
1340  const int p = (int) ( ( px - w.GetPosX() ) * w.GetScaleX() );
1341 
1342 #ifdef MATHPLOT_DO_LOGGING
1343  wxLogMessage( wxT( "mpScaleX::Plot: n: %f -> p = %d" ), n, p );
1344 #endif
1345 
1346  if( (p >= startPx) && (p <= endPx) )
1347  {
1348  if( m_ticks ) // draw axis ticks
1349  {
1351  dc.DrawLine( p, orgy, p, orgy - 4 );
1352  else
1353  dc.DrawLine( p, orgy, p, orgy + 4 );
1354  }
1355  else // draw grid dotted lines
1356  {
1357  m_pen.SetStyle( wxPENSTYLE_DOT );
1358  dc.SetPen( m_pen );
1359 
1361  {
1362  // printf("d1");
1363  m_pen.SetStyle( wxPENSTYLE_DOT );
1364  dc.SetPen( m_pen );
1365  dc.DrawLine( p, orgy + 4, p, minYpx );
1366  m_pen.SetStyle( wxPENSTYLE_SOLID );
1367  dc.SetPen( m_pen );
1368  dc.DrawLine( p, orgy + 4, p, orgy - 4 );
1369  }
1370  else
1371  {
1373  {
1374  // printf("d2");
1375  dc.DrawLine( p, orgy - 4, p, maxYpx );
1376  }
1377  else
1378  {
1379  // printf("d3");
1380  dc.DrawLine( p, minYpx, p, maxYpx ); // 0/*-w.GetScrY()*/, p, w.GetScrY() );
1381  }
1382  }
1383 
1384  m_pen.SetStyle( wxPENSTYLE_SOLID );
1385  dc.SetPen( m_pen );
1386  }
1387  }
1388  }
1389 
1390  m_pen.SetStyle( wxPENSTYLE_SOLID );
1391  dc.SetPen( m_pen );
1392  dc.DrawLine( startPx, minYpx, endPx, minYpx );
1393  dc.DrawLine( startPx, maxYpx, endPx, maxYpx );
1394 
1395  // printf("Labels : %d\n",labelCount());
1396  // Actually draw labels, taking care of not overlapping them, and distributing them regularly
1397  for( int n = 0; n < labelCount(); n++ )
1398  {
1399  double tp = getLabelPos( n );
1400 
1401  if( !m_tickLabels[n].visible )
1402  continue;
1403 
1404  // double xlogmin = log10 ( m_minV );
1405  // double xlogmax = log10 ( m_maxV );
1406 
1407  double px = TransformToPlot( tp ); // ( log10 ( tp ) - xlogmin) / (xlogmax - xlogmin);
1408 
1409  const int p = (int) ( ( px - w.GetPosX() ) * w.GetScaleX() );
1410 
1411  // printf("p %d %.1f\n", p, px);
1412 #ifdef MATHPLOT_DO_LOGGING
1413  wxLogMessage( wxT( "mpScaleX::Plot: n_label = %f -> p_label = %d" ), n, p );
1414 #endif
1415 
1416  if( (p >= startPx) && (p <= endPx) )
1417  {
1418  // Write ticks labels in s string
1419  wxString s = m_tickLabels[n].label;
1420 
1421  dc.GetTextExtent( s, &tx, &ty );
1422 
1424  {
1425  dc.DrawText( s, p - tx / 2, orgy - 4 - ty );
1426  }
1427  else
1428  {
1429  dc.DrawText( s, p - tx / 2, orgy + 4 );
1430  }
1431  }
1432  }
1433 
1434  // Draw axis name
1435  dc.GetTextExtent( m_name, &tx, &ty );
1436 
1437  switch( m_nameFlags )
1438  {
1439  case mpALIGN_BORDER_BOTTOM:
1440  dc.DrawText( m_name, extend - tx - 4, orgy - 8 - ty - labelH );
1441  break;
1442 
1443  case mpALIGN_BOTTOM:
1444  {
1445  dc.DrawText( m_name, (endPx + startPx) / 2 - tx / 2, orgy + 6 + labelH );
1446  }
1447  break;
1448 
1449  case mpALIGN_CENTER:
1450  dc.DrawText( m_name, extend - tx - 4, orgy - 4 - ty );
1451  break;
1452 
1453  case mpALIGN_TOP:
1454  {
1455  if( (!m_drawOutsideMargins) && ( w.GetMarginTop() > (ty + labelH + 8) ) )
1456  {
1457  dc.DrawText( m_name, (endPx - startPx - tx) >> 1, orgy - 6 - ty - labelH );
1458  }
1459  else
1460  {
1461  dc.DrawText( m_name, extend - tx - 4, orgy + 4 );
1462  }
1463  }
1464  break;
1465 
1466  case mpALIGN_BORDER_TOP:
1467  dc.DrawText( m_name, extend - tx - 4, orgy + 6 + labelH );
1468  break;
1469 
1470  default:
1471  break;
1472  }
1473  }
1474 }
1475 
1476 
1477 IMPLEMENT_DYNAMIC_CLASS( mpScaleY, mpLayer )
1478 
1479 mpScaleY::mpScaleY( const wxString& name, int flags, bool ticks )
1480 {
1481  SetName( name );
1482  SetFont( (wxFont&) *wxSMALL_FONT );
1483  SetPen( (wxPen&) *wxGREY_PEN );
1484  m_flags = flags;
1485  m_ticks = ticks;
1486  m_type = mpLAYER_AXIS;
1487  m_masterScale = NULL;
1488  m_nameFlags = mpALIGN_BORDER_LEFT;
1489 }
1490 
1491 
1492 void mpScaleY::Plot( wxDC& dc, mpWindow& w )
1493 {
1494  m_offset = -m_minV;
1495  m_scale = 1.0 / ( m_maxV - m_minV );
1496 
1497  // printf("Plot Y-scale\n");
1498  recalculateTicks( dc, w );
1499 
1500  if( m_visible )
1501  {
1502  dc.SetPen( m_pen );
1503  dc.SetFont( m_font );
1504 
1505  int orgx = 0;
1506 
1507  // const int extend = w.GetScrY(); // /2;
1508  if( m_flags == mpALIGN_CENTER )
1509  orgx = w.x2p( 0 ); // (int)(w.GetPosX() * w.GetScaleX());
1510 
1511  if( m_flags == mpALIGN_LEFT )
1512  {
1513  if( m_drawOutsideMargins )
1514  orgx = Y_BORDER_SEPARATION;
1515  else
1516  orgx = w.GetMarginLeft();
1517  }
1518 
1519  if( m_flags == mpALIGN_RIGHT )
1520  {
1521  if( m_drawOutsideMargins )
1522  orgx = w.GetScrX() - Y_BORDER_SEPARATION;
1523  else
1524  orgx = w.GetScrX() - w.GetMarginRight();
1525  }
1526 
1527  if( m_flags == mpALIGN_BORDER_RIGHT )
1528  orgx = w.GetScrX() - 1; // dc.LogicalToDeviceX(0) - 1;
1529 
1530  if( m_flags == mpALIGN_BORDER_LEFT )
1531  orgx = 1; // -dc.LogicalToDeviceX(0);
1532 
1533  wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
1534  wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
1535  wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
1536  // Draw line
1537  dc.DrawLine( orgx, minYpx, orgx, maxYpx );
1538 
1539 
1540  wxCoord tx, ty;
1541  wxString s;
1542  wxString fmt;
1543  int n = 0;
1544 
1545 
1546  int labelW = 0;
1547  // Before staring cycle, calculate label height
1548  int labelHeigth = 0;
1549  s.Printf( fmt, n );
1550  dc.GetTextExtent( s, &tx, &labelHeigth );
1551 
1552  // printf("Y-ticks: %d\n", tickCount());
1553  for( n = 0; n < tickCount(); n++ )
1554  {
1555  // printf("Tick %d\n", n);
1556 
1557  double tp = getTickPos( n );
1558 
1559  double py = TransformToPlot( tp ); // ( log10 ( tp ) - xlogmin) / (xlogmax - xlogmin);
1560  const int p = (int) ( ( w.GetPosY() - py ) * w.GetScaleY() );
1561 
1562 
1563  if( (p >= minYpx) && (p <= maxYpx) )
1564  {
1565  if( m_ticks ) // Draw axis ticks
1566  {
1567  if( m_flags == mpALIGN_BORDER_LEFT )
1568  {
1569  dc.DrawLine( orgx, p, orgx + 4, p );
1570  }
1571  else
1572  {
1573  dc.DrawLine( orgx - 4, p, orgx, p ); // ( orgx, p, orgx+4, p);
1574  }
1575  }
1576  else
1577  {
1578  dc.DrawLine( orgx - 4, p, orgx + 4, p );
1579 
1580  m_pen.SetStyle( wxPENSTYLE_DOT );
1581  dc.SetPen( m_pen );
1582 
1583  dc.DrawLine( orgx - 4, p, endPx, p );
1584 
1585  m_pen.SetStyle( wxPENSTYLE_SOLID );
1586  dc.SetPen( m_pen );
1587  }
1588 
1589  // Print ticks labels
1590  }
1591  }
1592 
1593  // printf("Y-ticks: %d\n", tickCount());
1594  for( n = 0; n < labelCount(); n++ )
1595  {
1596  // printf("Tick %d\n", n);
1597 
1598  double tp = getLabelPos( n );
1599 
1600  double py = TransformToPlot( tp ); // ( log10 ( tp ) - xlogmin) / (xlogmax - xlogmin);
1601  const int p = (int) ( ( w.GetPosY() - py ) * w.GetScaleY() );
1602 
1603  if( !m_tickLabels[n].visible )
1604  continue;
1605 
1606  if( (p >= minYpx) && (p <= maxYpx) )
1607  {
1608  s = getLabel( n );
1609  dc.GetTextExtent( s, &tx, &ty );
1610 
1612  dc.DrawText( s, orgx + 4, p - ty / 2 );
1613  else
1614  dc.DrawText( s, orgx - 4 - tx, p - ty / 2 ); // ( s, orgx+4, p-ty/2);
1615  }
1616  }
1617 
1618  // Draw axis name
1619  // Draw axis name
1620 
1621  dc.GetTextExtent( m_name, &tx, &ty );
1622 
1623  switch( m_nameFlags )
1624  {
1625  case mpALIGN_BORDER_LEFT:
1626  dc.DrawText( m_name, labelW + 8, 4 );
1627  break;
1628 
1629  case mpALIGN_LEFT:
1630  {
1631  // if ((!m_drawOutsideMargins) && (w.GetMarginLeft() > (ty + labelW + 8))) {
1632  // dc.DrawRotatedText( m_name, orgx - 6 - labelW - ty, (maxYpx + minYpx) / 2 + tx / 2, 90);
1633  // } else {
1634  dc.DrawText( m_name, orgx + 4, minYpx - ty - 4 );
1635  // }
1636  }
1637  break;
1638 
1639  case mpALIGN_CENTER:
1640  dc.DrawText( m_name, orgx + 4, 4 );
1641  break;
1642 
1643  case mpALIGN_RIGHT:
1644  {
1645  // dc.DrawRotatedText( m_name, orgx + 6, (maxYpx + minYpx) / 2 + tx / 2, 90);
1646 
1647  /*if ((!m_drawOutsideMargins) && (w.GetMarginRight() > (ty + labelW + 8))) {
1648  * dc.DrawRotatedText( m_name, orgx + 6 + labelW, (maxYpx - minYpx + tx)>>1, 90);
1649  * } else {*/
1650  dc.DrawText( m_name, orgx - tx - 4, minYpx - ty - 4 );
1651  // }
1652  }
1653  break;
1654 
1655  case mpALIGN_BORDER_RIGHT:
1656  dc.DrawText( m_name, orgx - 6 - tx - labelW, 4 );
1657  break;
1658 
1659  default:
1660  break;
1661  }
1662  }
1663 }
1664 
1665 
1666 // -----------------------------------------------------------------------------
1667 // mpWindow
1668 // -----------------------------------------------------------------------------
1669 
1670 IMPLEMENT_DYNAMIC_CLASS( mpWindow, wxWindow )
1671 
1672 BEGIN_EVENT_TABLE( mpWindow, wxWindow )
1673 EVT_PAINT( mpWindow::OnPaint )
1674 EVT_SIZE( mpWindow::OnSize )
1675 EVT_SCROLLWIN_THUMBTRACK( mpWindow::OnScrollThumbTrack )
1676 EVT_SCROLLWIN_PAGEUP( mpWindow::OnScrollPageUp )
1677 EVT_SCROLLWIN_PAGEDOWN( mpWindow::OnScrollPageDown )
1678 EVT_SCROLLWIN_LINEUP( mpWindow::OnScrollLineUp )
1679 EVT_SCROLLWIN_LINEDOWN( mpWindow::OnScrollLineDown )
1680 EVT_SCROLLWIN_TOP( mpWindow::OnScrollTop )
1681 EVT_SCROLLWIN_BOTTOM( mpWindow::OnScrollBottom )
1682 
1683 EVT_MIDDLE_DOWN( mpWindow::OnMouseMiddleDown ) // JLB
1684 EVT_RIGHT_UP( mpWindow::OnShowPopupMenu )
1685 EVT_MOUSEWHEEL( mpWindow::OnMouseWheel ) // JLB
1686 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
1687 EVT_MAGNIFY( mpWindow::OnMagnify )
1688 #endif
1689 EVT_MOTION( mpWindow::OnMouseMove ) // JLB
1690 EVT_LEFT_DOWN( mpWindow::OnMouseLeftDown )
1691 EVT_LEFT_UP( mpWindow::OnMouseLeftRelease )
1692 
1693 EVT_MENU( mpID_CENTER, mpWindow::OnCenter )
1694 EVT_MENU( mpID_FIT, mpWindow::OnFit )
1695 EVT_MENU( mpID_ZOOM_IN, mpWindow::OnZoomIn )
1698 END_EVENT_TABLE()
1699 
1700 mpWindow::mpWindow( wxWindow* parent,
1701  wxWindowID id,
1702  const wxPoint& pos,
1703  const wxSize& size,
1704  long flag )
1705  : wxWindow( parent, id, pos, size, flag, wxT( "mathplot" ) )
1706 {
1707  m_zooming = false;
1708  m_scaleX = m_scaleY = 1.0;
1709  m_posX = m_posY = 0;
1710  m_desiredXmin = m_desiredYmin = 0;
1711  m_desiredXmax = m_desiredYmax = 1;
1712  m_scrX = m_scrY = 64; // Fixed from m_scrX = m_scrX = 64;
1713  m_minX = m_minY = 0;
1714  m_maxX = m_maxY = 0;
1715  m_last_lx = m_last_ly = 0;
1716  m_buff_bmp = NULL;
1717  m_enableDoubleBuffer = false;
1718  m_enableMouseNavigation = true;
1719  m_enableLimitedView = false;
1720  m_movingInfoLayer = NULL;
1721  // Set margins to 0
1722  m_marginTop = 0; m_marginRight = 0; m_marginBottom = 0; m_marginLeft = 0;
1723 
1724 
1725  m_lockaspect = false;
1726 
1727  m_popmenu.Append( mpID_CENTER, _( "Center" ), _( "Center plot view to this position" ) );
1728  m_popmenu.Append( mpID_FIT, _( "Fit on Screen" ), _( "Set plot view to show all items" ) );
1729  m_popmenu.Append( mpID_ZOOM_IN, _( "Zoom In" ), _( "Zoom in plot view." ) );
1730  m_popmenu.Append( mpID_ZOOM_OUT, _( "Zoom Out" ), _( "Zoom out plot view." ) );
1731  // m_popmenu.AppendCheckItem( mpID_LOCKASPECT, _("Lock aspect"), _("Lock horizontal and vertical zoom aspect."));
1732  // m_popmenu.Append( mpID_HELP_MOUSE, _("Show mouse commands..."), _("Show help about the mouse commands."));
1733 
1734  m_layers.clear();
1735  SetBackgroundColour( *wxWHITE );
1736  m_bgColour = *wxWHITE;
1737  m_fgColour = *wxBLACK;
1738 
1739  m_enableScrollBars = false;
1740  SetSizeHints( 128, 128 );
1741 
1742  // J.L.Blanco: Eliminates the "flick" with the double buffer.
1743  SetBackgroundStyle( wxBG_STYLE_CUSTOM );
1744 
1745  UpdateAll();
1746 }
1747 
1748 
1750 {
1751  // Free all the layers:
1752  DelAllLayers( true, false );
1753 
1754  if( m_buff_bmp )
1755  {
1756  delete m_buff_bmp;
1757  m_buff_bmp = NULL;
1758  }
1759 }
1760 
1761 
1762 // Mouse handler, for detecting when the user drag with the right button or just "clicks" for the menu
1763 // JLB
1764 void mpWindow::OnMouseMiddleDown( wxMouseEvent& event )
1765 {
1766  m_mouseMClick.x = event.GetX();
1767  m_mouseMClick.y = event.GetY();
1768 }
1769 
1770 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
1771 void mpWindow::OnMagnify( wxMouseEvent& event )
1772 {
1774  {
1775  event.Skip();
1776  return;
1777  }
1778 
1779  float zoom = event.GetMagnification() + 1.0f;
1780  wxPoint pos( event.GetX(), event.GetY() );
1781  if( zoom > 1.0f )
1782  ZoomIn( pos, zoom );
1783  else if( zoom < 1.0f )
1784  ZoomOut( pos, 1.0f / zoom );
1785 }
1786 #endif
1787 
1788 // Process mouse wheel events
1789 // JLB
1790 void mpWindow::OnMouseWheel( wxMouseEvent& event )
1791 {
1793  {
1794  event.Skip();
1795  return;
1796  }
1797 
1798  int change = event.GetWheelRotation();
1799  const int axis = event.GetWheelAxis();
1800  double changeUnitsX = change / m_scaleX;
1801  double changeUnitsY = change / m_scaleY;
1802 
1803  if( ( !m_enableMouseWheelPan && ( event.ControlDown() || event.ShiftDown() ) )
1804  || ( m_enableMouseWheelPan && !event.ControlDown() ) )
1805  {
1806  // Scrolling
1807  if( m_enableMouseWheelPan )
1808  {
1809  if( axis == wxMOUSE_WHEEL_HORIZONTAL || event.ShiftDown() )
1810  SetXView( m_posX + changeUnitsX, m_desiredXmax + changeUnitsX,
1811  m_desiredXmin + changeUnitsX );
1812  else
1813  SetYView( m_posY + changeUnitsY, m_desiredYmax + changeUnitsY,
1814  m_desiredYmin + changeUnitsY );
1815  }
1816  else
1817  {
1818  if( event.ControlDown() )
1819  SetXView( m_posX + changeUnitsX, m_desiredXmax + changeUnitsX,
1820  m_desiredXmin + changeUnitsX );
1821  else
1822  SetYView( m_posY + changeUnitsY, m_desiredYmax + changeUnitsY,
1823  m_desiredYmin + changeUnitsY );
1824  }
1825 
1826  UpdateAll();
1827  }
1828  else
1829  {
1830  // zoom in/out
1831  wxPoint clickPt( event.GetX(), event.GetY() );
1832 
1833  if( event.GetWheelRotation() > 0 )
1834  ZoomIn( clickPt );
1835  else
1836  ZoomOut( clickPt );
1837 
1838  return;
1839  }
1840 }
1841 
1842 
1843 // If the user "drags" with the right buttom pressed, do "pan"
1844 // JLB
1845 void mpWindow::OnMouseMove( wxMouseEvent& event )
1846 {
1848  {
1849  event.Skip();
1850  return;
1851  }
1852 
1853  if( event.m_middleDown )
1854  {
1855  // The change:
1856  int Ax = m_mouseMClick.x - event.GetX();
1857  int Ay = m_mouseMClick.y - event.GetY();
1858 
1859  // For the next event, use relative to this coordinates.
1860  m_mouseMClick.x = event.GetX();
1861  m_mouseMClick.y = event.GetY();
1862 
1863  double Ax_units = Ax / m_scaleX;
1864  double Ay_units = -Ay / m_scaleY;
1865 
1866  bool updateRequired = false;
1867  updateRequired |= SetXView( m_posX + Ax_units,
1868  m_desiredXmax + Ax_units,
1869  m_desiredXmin + Ax_units );
1870  updateRequired |= SetYView( m_posY + Ay_units,
1871  m_desiredYmax + Ay_units,
1872  m_desiredYmin + Ay_units );
1873 
1874  if( updateRequired )
1875  UpdateAll();
1876 
1877 #ifdef MATHPLOT_DO_LOGGING
1878  wxLogMessage( "[mpWindow::OnMouseMove] Ax:%i Ay:%i m_posX:%f m_posY:%f",
1879  Ax,
1880  Ay,
1881  m_posX,
1882  m_posY );
1883 #endif
1884  }
1885  else
1886  {
1887  if( event.m_leftDown )
1888  {
1889  if( m_movingInfoLayer == NULL )
1890  {
1891  wxClientDC dc( this );
1892  wxPen pen( m_fgColour, 1, wxPENSTYLE_DOT );
1893  dc.SetPen( pen );
1894  dc.SetBrush( *wxTRANSPARENT_BRUSH );
1895  dc.DrawRectangle( m_mouseLClick.x, m_mouseLClick.y,
1896  event.GetX() - m_mouseLClick.x, event.GetY() - m_mouseLClick.y );
1897  m_zooming = true;
1900  m_zoomRect.width = event.GetX() - m_mouseLClick.x;
1901  m_zoomRect.height = event.GetY() - m_mouseLClick.y;
1902  }
1903  else
1904  {
1905  wxPoint moveVector( event.GetX() - m_mouseLClick.x,
1906  event.GetY() - m_mouseLClick.y );
1907  m_movingInfoLayer->Move( moveVector );
1908  m_zooming = false;
1909  }
1910 
1911  UpdateAll();
1912  }
1913  else
1914  {
1915 #if 0
1916  wxLayerList::iterator li;
1917 
1918  for( li = m_layers.begin(); li != m_layers.end(); li++ )
1919  {
1920  if( (*li)->IsInfo() && (*li)->IsVisible() )
1921  {
1922  mpInfoLayer* tmpLyr = (mpInfoLayer*) (*li);
1923  tmpLyr->UpdateInfo( *this, event );
1924  // UpdateAll();
1925  RefreshRect( tmpLyr->GetRectangle() );
1926  }
1927  }
1928 
1929 #endif
1930  /* if (m_coordTooltip) {
1931  * wxString toolTipContent;
1932  * toolTipContent.Printf( "X = %f\nY = %f", p2x(event.GetX()), p2y(event.GetY()));
1933  * wxTipWindow** ptr = NULL;
1934  * wxRect rectBounds(event.GetX(), event.GetY(), 5, 5);
1935  * wxTipWindow* tip = new wxTipWindow(this, toolTipContent, 100, ptr, &rectBounds);
1936  *
1937  * } */
1938  }
1939  }
1940 
1941  event.Skip();
1942 }
1943 
1944 
1945 void mpWindow::OnMouseLeftDown( wxMouseEvent& event )
1946 {
1947  m_mouseLClick.x = event.GetX();
1948  m_mouseLClick.y = event.GetY();
1949  m_zooming = true;
1950 #ifdef MATHPLOT_DO_LOGGING
1951  wxLogMessage( "mpWindow::OnMouseLeftDown() X = %d , Y = %d", event.GetX(), event.GetY() ); /*m_mouseLClick.x, m_mouseLClick.y);*/
1952 #endif
1953  wxPoint pointClicked = event.GetPosition();
1954  m_movingInfoLayer = IsInsideInfoLayer( pointClicked );
1955 
1956  if( m_movingInfoLayer != NULL )
1957  {
1958 #ifdef MATHPLOT_DO_LOGGING
1959  wxLogMessage( "mpWindow::OnMouseLeftDown() started moving layer %lx",
1960  (long int) m_movingInfoLayer ); /*m_mouseLClick.x, m_mouseLClick.y);*/
1961 #endif
1962  }
1963 
1964  event.Skip();
1965 }
1966 
1967 
1968 void mpWindow::OnMouseLeftRelease( wxMouseEvent& event )
1969 {
1970  wxPoint release( event.GetX(), event.GetY() );
1972 
1973  m_zooming = false;
1974 
1975  if( m_movingInfoLayer != NULL )
1976  {
1979  }
1980  else
1981  {
1982  if( release != press )
1983  {
1984  ZoomRect( press, release );
1985  } /*else {
1986  * if (m_coordTooltip) {
1987  * wxString toolTipContent;
1988  * toolTipContent.Printf( "X = %f\nY = %f", p2x(event.GetX()), p2y(event.GetY()));
1989  * SetToolTip(toolTipContent);
1990  * }
1991  * } */
1992  }
1993 
1994  event.Skip();
1995 }
1996 
1997 
1999 {
2000  if( UpdateBBox() )
2001  Fit( m_minX, m_maxX, m_minY, m_maxY );
2002 }
2003 
2004 
2005 // JL
2006 void mpWindow::Fit( double xMin, double xMax, double yMin, double yMax,
2007  wxCoord* printSizeX, wxCoord* printSizeY )
2008 {
2009  // Save desired borders:
2010  m_desiredXmin = xMin; m_desiredXmax = xMax;
2011  m_desiredYmin = yMin; m_desiredYmax = yMax;
2012 
2013  // Give a small margin to plot area
2014  double xExtra = fabs( xMax - xMin ) * 0.00;
2015  double yExtra = fabs( yMax - yMin ) * 0.03;
2016 
2017  xMin -= xExtra;
2018  xMax += xExtra;
2019  yMin -= yExtra;
2020  yMax += yExtra;
2021 
2022  if( printSizeX!=NULL && printSizeY!=NULL )
2023  {
2024  // Printer:
2025  m_scrX = *printSizeX;
2026  m_scrY = *printSizeY;
2027  }
2028  else
2029  {
2030  // Normal case (screen):
2031  GetClientSize( &m_scrX, &m_scrY );
2032  }
2033 
2034  double Ax, Ay;
2035 
2036  Ax = xMax - xMin;
2037  Ay = yMax - yMin;
2038 
2039  m_scaleX = (Ax!=0) ? (m_scrX - m_marginLeft - m_marginRight) / Ax : 1; // m_scaleX = (Ax!=0) ? m_scrX/Ax : 1;
2040  m_scaleY = (Ay!=0) ? (m_scrY - m_marginTop - m_marginBottom) / Ay : 1; // m_scaleY = (Ay!=0) ? m_scrY/Ay : 1;
2041 
2042  if( m_lockaspect )
2043  {
2044 #ifdef MATHPLOT_DO_LOGGING
2045  wxLogMessage( "mpWindow::Fit()(lock) m_scaleX=%f,m_scaleY=%f", m_scaleX, m_scaleY );
2046 #endif
2047  // Keep the lowest "scale" to fit the whole range required by that axis (to actually "fit"!):
2048  double s = m_scaleX < m_scaleY ? m_scaleX : m_scaleY;
2049  m_scaleX = s;
2050  m_scaleY = s;
2051  }
2052 
2053  // Adjusts corner coordinates: This should be simply:
2054  // m_posX = m_minX;
2055  // m_posY = m_maxY;
2056  // But account for centering if we have lock aspect:
2057  m_posX = (xMin + xMax) / 2 - ( (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft ) /
2058  m_scaleX; // m_posX = (xMin+xMax)/2 - (m_scrX/2)/m_scaleX;
2059  // m_posY = (yMin+yMax)/2 + ((m_scrY - m_marginTop - m_marginBottom)/2 - m_marginTop)/m_scaleY; // m_posY = (yMin+yMax)/2 + (m_scrY/2)/m_scaleY;
2060  m_posY = (yMin + yMax) / 2 + ( (m_scrY - m_marginTop - m_marginBottom) / 2 + m_marginTop ) /
2061  m_scaleY; // m_posY = (yMin+yMax)/2 + (m_scrY/2)/m_scaleY;
2062 
2063 #ifdef MATHPLOT_DO_LOGGING
2064  wxLogMessage(
2065  "mpWindow::Fit() m_desiredXmin=%f m_desiredXmax=%f m_desiredYmin=%f m_desiredYmax=%f",
2066  xMin,
2067  xMax,
2068  yMin,
2069  yMax );
2070  wxLogMessage(
2071  "mpWindow::Fit() m_scaleX = %f , m_scrX = %d,m_scrY=%d, Ax=%f, Ay=%f, m_posX=%f, m_posY=%f",
2072  m_scaleX,
2073  m_scrX,
2074  m_scrY,
2075  Ax,
2076  Ay,
2077  m_posX,
2078  m_posY );
2079 #endif
2080 
2081  // It is VERY IMPORTANT to DO NOT call Refresh if we are drawing to the printer!!
2082  // Otherwise, the DC dimensions will be those of the window instead of the printer device
2083  if( printSizeX==NULL || printSizeY==NULL )
2084  UpdateAll();
2085 }
2086 
2087 
2088 // Patch ngpaton
2089 void mpWindow::DoZoomInXCalc( const int staticXpixel )
2090 {
2091  // Preserve the position of the clicked point:
2092  double staticX = p2x( staticXpixel );
2093 
2094  // Zoom in:
2096  // Adjust the new m_posx
2097  m_posX = staticX - (staticXpixel / m_scaleX);
2098  // Adjust desired
2101 #ifdef MATHPLOT_DO_LOGGING
2102  wxLogMessage(
2103  "mpWindow::DoZoomInXCalc() prior X coord: (%f), new X coord: (%f) SHOULD BE EQUAL!!",
2104  staticX, p2x( staticXpixel ) );
2105 #endif
2106 }
2107 
2108 
2109 void mpWindow::DoZoomInYCalc( const int staticYpixel )
2110 {
2111  // Preserve the position of the clicked point:
2112  double staticY = p2y( staticYpixel );
2113 
2114  // Zoom in:
2116  // Adjust the new m_posy:
2117  m_posY = staticY + (staticYpixel / m_scaleY);
2118  // Adjust desired
2121 #ifdef MATHPLOT_DO_LOGGING
2122  wxLogMessage(
2123  "mpWindow::DoZoomInYCalc() prior Y coord: (%f), new Y coord: (%f) SHOULD BE EQUAL!!",
2124  staticY, p2y( staticYpixel ) );
2125 #endif
2126 }
2127 
2128 
2129 void mpWindow::DoZoomOutXCalc( const int staticXpixel )
2130 {
2131  // Preserve the position of the clicked point:
2132  double staticX = p2x( staticXpixel );
2133 
2134  // Zoom out:
2136  // Adjust the new m_posx/y:
2137  m_posX = staticX - (staticXpixel / m_scaleX);
2138  // Adjust desired
2141 #ifdef MATHPLOT_DO_LOGGING
2142  wxLogMessage(
2143  "mpWindow::DoZoomOutXCalc() prior X coord: (%f), new X coord: (%f) SHOULD BE EQUAL!!",
2144  staticX, p2x( staticXpixel ) );
2145 #endif
2146 }
2147 
2148 
2149 void mpWindow::DoZoomOutYCalc( const int staticYpixel )
2150 {
2151  // Preserve the position of the clicked point:
2152  double staticY = p2y( staticYpixel );
2153 
2154  // Zoom out:
2156  // Adjust the new m_posx/y:
2157  m_posY = staticY + (staticYpixel / m_scaleY);
2158  // Adjust desired
2161 #ifdef MATHPLOT_DO_LOGGING
2162  wxLogMessage(
2163  "mpWindow::DoZoomOutYCalc() prior Y coord: (%f), new Y coord: (%f) SHOULD BE EQUAL!!",
2164  staticY, p2y( staticYpixel ) );
2165 #endif
2166 }
2167 
2168 
2170 {
2171  if( !m_enableLimitedView )
2172  return;
2173 
2174  // m_min and m_max are plot limits for curves
2175  // xMin, xMax, yMin, yMax are the full limits (plot limit + margin)
2176  const double xMin = m_minX - m_marginLeft / m_scaleX;
2177  const double xMax = m_maxX + m_marginRight / m_scaleX;
2178  const double yMin = m_minY - m_marginTop / m_scaleY;
2179  const double yMax = m_maxY + m_marginBottom / m_scaleY;
2180 
2181  if( m_desiredXmin < xMin )
2182  {
2183  double diff = xMin - m_desiredXmin;
2184  m_posX += diff;
2185  m_desiredXmax += diff;
2186  m_desiredXmin = xMin;
2187  }
2188 
2189  if( m_desiredXmax > xMax )
2190  {
2191  double diff = m_desiredXmax - xMax;
2192  m_posX -= diff;
2193  m_desiredXmin -= diff;
2194  m_desiredXmax = xMax;
2195  }
2196 
2197  if( m_desiredYmin < yMin )
2198  {
2199  double diff = yMin - m_desiredYmin;
2200  m_posY += diff;
2201  m_desiredYmax += diff;
2202  m_desiredYmin = yMin;
2203  }
2204 
2205  if( m_desiredYmax > yMax )
2206  {
2207  double diff = m_desiredYmax - yMax;
2208  m_posY -= diff;
2209  m_desiredYmin -= diff;
2210  m_desiredYmax = yMax;
2211  }
2212 }
2213 
2214 
2215 bool mpWindow::SetXView( double pos, double desiredMax, double desiredMin )
2216 {
2217  // if(!CheckXLimits(desiredMax, desiredMin))
2218  // return false;
2219 
2220  m_posX = pos;
2221  m_desiredXmax = desiredMax;
2222  m_desiredXmin = desiredMin;
2224 
2225  return true;
2226 }
2227 
2228 
2229 bool mpWindow::SetYView( double pos, double desiredMax, double desiredMin )
2230 {
2231  // if(!CheckYLimits(desiredMax, desiredMin))
2232  // return false;
2233 
2234  m_posY = pos;
2235  m_desiredYmax = desiredMax;
2236  m_desiredYmin = desiredMin;
2238 
2239  return true;
2240 }
2241 
2242 
2243 void mpWindow::ZoomIn( const wxPoint& centerPoint )
2244 {
2245  ZoomIn( centerPoint, zoomIncrementalFactor );
2246 }
2247 
2248 
2249 void mpWindow::ZoomIn( const wxPoint& centerPoint, double zoomFactor )
2250 {
2251  wxPoint c( centerPoint );
2252 
2253  if( c == wxDefaultPosition )
2254  {
2255  GetClientSize( &m_scrX, &m_scrY );
2256  c.x = (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft; // c.x = m_scrX/2;
2257  c.y = (m_scrY - m_marginTop - m_marginBottom) / 2 - m_marginTop; // c.y = m_scrY/2;
2258  }
2259  else
2260  {
2261  c.x = std::max( c.x, m_marginLeft );
2262  c.x = std::min( c.x, m_scrX - m_marginRight );
2263  c.y = std::max( c.y, m_marginTop );
2264  c.y = std::min( c.y, m_scrY - m_marginBottom );
2265  }
2266 
2267  // Preserve the position of the clicked point:
2268  double prior_layer_x = p2x( c.x );
2269  double prior_layer_y = p2y( c.y );
2270 
2271  // Zoom in:
2272  const double MAX_SCALE = 1e6;
2273  double newScaleX = m_scaleX * zoomFactor;
2274  double newScaleY = m_scaleY * zoomFactor;
2275 
2276  // Baaaaad things happen when you zoom in too much..
2277  if( newScaleX <= MAX_SCALE && newScaleY <= MAX_SCALE )
2278  {
2279  m_scaleX = newScaleX;
2280  m_scaleY = newScaleY;
2281  }
2282  else
2283  {
2284  return;
2285  }
2286 
2287  // Adjust the new m_posx/y:
2288  m_posX = prior_layer_x - c.x / m_scaleX;
2289  m_posY = prior_layer_y + c.y / m_scaleY;
2290 
2292  m_desiredXmax = m_posX + (m_scrX - m_marginLeft - m_marginRight) / m_scaleX; // m_desiredXmax = m_posX + m_scrX / m_scaleX;
2294  m_desiredYmin = m_posY - (m_scrY - m_marginTop - m_marginBottom) / m_scaleY; // m_desiredYmin = m_posY - m_scrY / m_scaleY;
2296 
2297 #ifdef MATHPLOT_DO_LOGGING
2298  wxLogMessage( "mpWindow::ZoomIn() prior coords: (%f,%f), new coords: (%f,%f) SHOULD BE EQUAL!!",
2299  prior_layer_x, prior_layer_y, p2x( c.x ), p2y( c.y ) );
2300 #endif
2301 
2302  UpdateAll();
2303 }
2304 
2305 
2306 void mpWindow::ZoomOut( const wxPoint& centerPoint )
2307 {
2308  ZoomOut( centerPoint, zoomIncrementalFactor );
2309 }
2310 
2311 
2312 void mpWindow::ZoomOut( const wxPoint& centerPoint, double zoomFactor )
2313 {
2314  wxPoint c( centerPoint );
2315 
2316  if( c == wxDefaultPosition )
2317  {
2318  GetClientSize( &m_scrX, &m_scrY );
2319  c.x = (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft; // c.x = m_scrX/2;
2320  c.y = (m_scrY - m_marginTop - m_marginBottom) / 2 - m_marginTop; // c.y = m_scrY/2;
2321  }
2322 
2323  // Preserve the position of the clicked point:
2324  double prior_layer_x = p2x( c.x );
2325  double prior_layer_y = p2y( c.y );
2326 
2327  // Zoom out:
2328  m_scaleX = m_scaleX / zoomFactor;
2329  m_scaleY = m_scaleY / zoomFactor;
2330 
2331  // Adjust the new m_posx/y:
2332  m_posX = prior_layer_x - c.x / m_scaleX;
2333  m_posY = prior_layer_y + c.y / m_scaleY;
2334 
2336  m_desiredXmax = m_posX + (m_scrX - m_marginLeft - m_marginRight) / m_scaleX; // m_desiredXmax = m_posX + m_scrX / m_scaleX;
2338  m_desiredYmin = m_posY - (m_scrY - m_marginTop - m_marginBottom) / m_scaleY; // m_desiredYmin = m_posY - m_scrY / m_scaleY;
2339 
2340  // printf("desired xmin %.1f ymin %.1f xmax %.1f ymax %.1f l %d\n", m_desiredXmin, m_desiredYmin, m_desiredXmax, m_desiredYmax, !!m_enableLimitedView);
2341  // printf("current xmin %.1f ymin %.1f xmax %.1f ymax %.1f\n", m_minX, m_minY, m_maxX, m_maxY);
2342 
2345  {
2346  // printf("call fit()\n");
2347  Fit();
2348  }
2349 
2350 #ifdef MATHPLOT_DO_LOGGING
2351  wxLogMessage(
2352  "mpWindow::ZoomOut() prior coords: (%f,%f), new coords: (%f,%f) SHOULD BE EQUAL!!",
2353  prior_layer_x, prior_layer_y, p2x( c.x ), p2y( c.y ) );
2354 #endif
2355  UpdateAll();
2356 }
2357 
2358 
2360 {
2362  UpdateAll();
2363 }
2364 
2365 
2367 {
2369  UpdateAll();
2370 }
2371 
2372 
2374 {
2376  UpdateAll();
2377 }
2378 
2379 
2381 {
2383  UpdateAll();
2384 }
2385 
2386 
2388 {
2389  // Compute the 2 corners in graph coordinates:
2390  double p0x = p2x( p0.x );
2391  double p0y = p2y( p0.y );
2392  double p1x = p2x( p1.x );
2393  double p1y = p2y( p1.y );
2394 
2395  // Order them:
2396  double zoom_x_min = p0x<p1x ? p0x : p1x;
2397  double zoom_x_max = p0x>p1x ? p0x : p1x;
2398  double zoom_y_min = p0y<p1y ? p0y : p1y;
2399  double zoom_y_max = p0y>p1y ? p0y : p1y;
2400 
2401 #ifdef MATHPLOT_DO_LOGGING
2402  wxLogMessage( "Zoom: (%f,%f)-(%f,%f)", zoom_x_min, zoom_y_min, zoom_x_max, zoom_y_max );
2403 #endif
2404 
2405  Fit( zoom_x_min, zoom_x_max, zoom_y_min, zoom_y_max );
2407 }
2408 
2409 
2410 void mpWindow::LockAspect( bool enable )
2411 {
2412  m_lockaspect = enable;
2413  m_popmenu.Check( mpID_LOCKASPECT, enable );
2414 
2415  // Try to fit again with the new config:
2417 }
2418 
2419 
2420 void mpWindow::OnShowPopupMenu( wxMouseEvent& event )
2421 {
2422  m_clickedX = event.GetX();
2423  m_clickedY = event.GetY();
2424  PopupMenu( &m_popmenu, event.GetX(), event.GetY() );
2425 }
2426 
2427 
2428 void mpWindow::OnLockAspect( wxCommandEvent& WXUNUSED( event ) )
2429 {
2431 }
2432 
2433 
2434 void mpWindow::OnFit( wxCommandEvent& WXUNUSED( event ) )
2435 {
2436  Fit();
2437 }
2438 
2439 
2440 void mpWindow::OnCenter( wxCommandEvent& WXUNUSED( event ) )
2441 {
2442  GetClientSize( &m_scrX, &m_scrY );
2443  int centerX = (m_scrX - m_marginLeft - m_marginRight) / 2; // + m_marginLeft; // c.x = m_scrX/2;
2444  int centerY = (m_scrY - m_marginTop - m_marginBottom) / 2; // - m_marginTop; // c.y = m_scrY/2;
2445  SetPos( p2x( m_clickedX - centerX ), p2y( m_clickedY - centerY ) );
2446  // SetPos( p2x(m_clickedX-m_scrX/2), p2y(m_clickedY-m_scrY/2) ); //SetPos( (double)(m_clickedX-m_scrX/2) / m_scaleX + m_posX, (double)(m_scrY/2-m_clickedY) / m_scaleY + m_posY);
2447 }
2448 
2449 
2450 void mpWindow::OnZoomIn( wxCommandEvent& WXUNUSED( event ) )
2451 {
2453 }
2454 
2455 
2456 void mpWindow::OnZoomOut( wxCommandEvent& WXUNUSED( event ) )
2457 {
2458  ZoomOut();
2459 }
2460 
2461 
2462 void mpWindow::OnSize( wxSizeEvent& WXUNUSED( event ) )
2463 {
2464  // Try to fit again with the new window size:
2466 #ifdef MATHPLOT_DO_LOGGING
2467  wxLogMessage( "mpWindow::OnSize() m_scrX = %d, m_scrY = %d", m_scrX, m_scrY );
2468 #endif // MATHPLOT_DO_LOGGING
2469 }
2470 
2471 
2472 bool mpWindow::AddLayer( mpLayer* layer, bool refreshDisplay )
2473 {
2474  if( layer != NULL )
2475  {
2476  m_layers.push_back( layer );
2477 
2478  if( refreshDisplay )
2479  UpdateAll();
2480 
2481  return true;
2482  }
2483 
2484  ;
2485  return false;
2486 }
2487 
2488 
2490  bool alsoDeleteObject,
2491  bool refreshDisplay )
2492 {
2493  wxLayerList::iterator layIt;
2494 
2495  for( layIt = m_layers.begin(); layIt != m_layers.end(); layIt++ )
2496  {
2497  if( *layIt == layer )
2498  {
2499  // Also delete the object?
2500  if( alsoDeleteObject )
2501  delete *layIt;
2502 
2503  m_layers.erase( layIt ); // this deleted the reference only
2504 
2505  if( refreshDisplay )
2506  UpdateAll();
2507 
2508  return true;
2509  }
2510  }
2511 
2512  return false;
2513 }
2514 
2515 
2516 void mpWindow::DelAllLayers( bool alsoDeleteObject, bool refreshDisplay )
2517 {
2518  while( m_layers.size()>0 )
2519  {
2520  // Also delete the object?
2521  if( alsoDeleteObject )
2522  delete m_layers[0];
2523 
2524  m_layers.erase( m_layers.begin() ); // this deleted the reference only
2525  }
2526 
2527  if( refreshDisplay )
2528  UpdateAll();
2529 }
2530 
2531 
2532 void mpWindow::OnPaint( wxPaintEvent& WXUNUSED( event ) )
2533 {
2534  wxPaintDC dc( this );
2535 
2536  dc.GetSize( &m_scrX, &m_scrY ); // This is the size of the visible area only!
2537 
2538 #ifdef MATHPLOT_DO_LOGGING
2539  wxLogMessage( "[mpWindow::OnPaint] vis.area: x %i y%i", m_scrX, m_scrY );
2540 #endif
2541 
2542  // Selects direct or buffered draw:
2543  wxDC* trgDc;
2544 
2545  // J.L.Blanco @ Aug 2007: Added double buffer support
2546  if( m_enableDoubleBuffer )
2547  {
2548  if( m_last_lx!=m_scrX || m_last_ly!=m_scrY )
2549  {
2550  if( m_buff_bmp )
2551  delete m_buff_bmp;
2552 
2553  m_buff_bmp = new wxBitmap( m_scrX, m_scrY );
2554  m_buff_dc.SelectObject( *m_buff_bmp );
2555  m_last_lx = m_scrX;
2556  m_last_ly = m_scrY;
2557  }
2558 
2559  trgDc = &m_buff_dc;
2560  }
2561  else
2562  {
2563  trgDc = &dc;
2564  }
2565 
2566  // Draw background:
2567  // trgDc->SetDeviceOrigin(0,0);
2568  trgDc->SetPen( *wxTRANSPARENT_PEN );
2569  wxBrush brush( GetBackgroundColour() );
2570  trgDc->SetBrush( brush );
2571  trgDc->SetTextForeground( m_fgColour );
2572  trgDc->DrawRectangle( 0, 0, m_scrX, m_scrY );
2573 
2574  // Draw all the layers:
2575  // trgDc->SetDeviceOrigin( m_scrX>>1, m_scrY>>1); // Origin at the center
2576  wxLayerList::iterator li;
2577 
2578  for( li = m_layers.begin(); li != m_layers.end(); li++ )
2579  {
2580  (*li)->Plot( *trgDc, *this );
2581  }
2582 
2583  ;
2584 
2585  if( m_zooming )
2586  {
2587  wxPen pen( m_fgColour, 1, wxPENSTYLE_DOT );
2588  trgDc->SetPen( pen );
2589  trgDc->SetBrush( *wxTRANSPARENT_BRUSH );
2590  trgDc->DrawRectangle( m_zoomRect );
2591  }
2592 
2593  // If doublebuffer, draw now to the window:
2594  if( m_enableDoubleBuffer )
2595  {
2596  // trgDc->SetDeviceOrigin(0,0);
2597  // dc.SetDeviceOrigin(0,0); // Origin at the center
2598  dc.Blit( 0, 0, m_scrX, m_scrY, trgDc, 0, 0 );
2599  }
2600 
2601  /* if (m_coordTooltip) {
2602  * wxString toolTipContent;
2603  * wxPoint mousePoint = wxGetMousePosition();
2604  * toolTipContent.Printf( "X = %f\nY = %f", p2x(mousePoint.x), p2y(mousePoint.y));
2605  * SetToolTip(toolTipContent);
2606  * }*/
2607  // If scrollbars are enabled, refresh them
2608  if( m_enableScrollBars )
2609  {
2610  /* m_scroll.x = (int) floor((m_posX - m_minX)*m_scaleX);
2611  * m_scroll.y = (int) floor((m_maxY - m_posY )*m_scaleY);
2612  * Scroll(m_scroll.x, m_scroll.y);*/
2613  // Scroll(x2p(m_posX), y2p(m_posY));
2614  // SetVirtualSize((int) ((m_maxX - m_minX)*m_scaleX), (int) ((m_maxY - m_minY)*m_scaleY));
2615  // int centerX = (m_scrX - m_marginLeft - m_marginRight)/2; // + m_marginLeft; // c.x = m_scrX/2;
2616  // int centerY = (m_scrY - m_marginTop - m_marginBottom)/2; // - m_marginTop; // c.y = m_scrY/2;
2617  /*SetScrollbars(1, 1, (int) ((m_maxX - m_minX)*m_scaleX), (int) ((m_maxY - m_minY)*m_scaleY));*/ // , x2p(m_posX + centerX/m_scaleX), y2p(m_posY - centerY/m_scaleY), true);
2618  }
2619 }
2620 
2621 
2622 // void mpWindow::OnScroll2(wxScrollWinEvent &event)
2623 // {
2624 // #ifdef MATHPLOT_DO_LOGGING
2625 // wxLogMessage( "[mpWindow::OnScroll2] Init: m_posX=%f m_posY=%f, sc_pos = %d",m_posX,m_posY, event.GetPosition());
2626 // #endif
2628 // if (!m_enableScrollBars) {
2629 // event.Skip();
2630 // return;
2631 // }
2635 //
2638 // int pixelStep = 1;
2639 // if (event.GetOrientation() == wxHORIZONTAL) {
2642 // m_posX -= (m_scroll.x - event.GetPosition())/m_scaleX;
2643 // m_scroll.x = event.GetPosition();
2644 // }
2645 // Fit(m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax);
2661 // #ifdef MATHPLOT_DO_LOGGING
2662 // int px, py;
2663 // GetViewStart( &px, &py);
2664 // wxLogMessage( "[mpWindow::OnScroll2] End: m_posX = %f, m_posY = %f, px = %f, py = %f",m_posX, m_posY, px, py);
2665 // #endif
2666 //
2667 // UpdateAll();
2669 // }
2670 
2671 void mpWindow::SetMPScrollbars( bool status )
2672 {
2673  // Temporary behaviour: always disable scrollbars
2674  m_enableScrollBars = status; // false;
2675 
2676  if( status == false )
2677  {
2678  SetScrollbar( wxHORIZONTAL, 0, 0, 0 );
2679  SetScrollbar( wxVERTICAL, 0, 0, 0 );
2680  }
2681 
2682  // else the scroll bars will be updated in UpdateAll();
2683  UpdateAll();
2684 
2685  // EnableScrolling(false, false);
2686  // m_enableScrollBars = status;
2687  // EnableScrolling(status, status);
2688  /* m_scroll.x = (int) floor((m_posX - m_minX)*m_scaleX);
2689  * m_scroll.y = (int) floor((m_posY - m_minY)*m_scaleY);*/
2690  // int scrollWidth = (int) floor((m_maxX - m_minX)*m_scaleX) - m_scrX;
2691  // int scrollHeight = (int) floor((m_minY - m_maxY)*m_scaleY) - m_scrY;
2692 
2694  // m_scroll.y = (int) floor((m_maxY - m_posY /*- m_minY*/)*m_scaleY);
2695  // int scrollWidth = (int) floor(((m_maxX - m_minX) - (m_desiredXmax - m_desiredXmin))*m_scaleX);
2696  // int scrollHeight = (int) floor(((m_maxY - m_minY) - (m_desiredYmax - m_desiredYmin))*m_scaleY);
2697  // #ifdef MATHPLOT_DO_LOGGING
2698  // wxLogMessage( "mpWindow::SetMPScrollbars() scrollWidth = %d, scrollHeight = %d", scrollWidth, scrollHeight);
2699  // #endif
2700  // if(status) {
2701  // SetScrollbars(1,
2702  // 1,
2703  // scrollWidth,
2704  // scrollHeight,
2705  // m_scroll.x,
2706  // m_scroll.y);
2708  // }
2709  // Refresh(false);*/
2710 }
2711 
2713 {
2714  m_minX = 0.0;
2715  m_maxX = 1.0;
2716  m_minY = 0.0;
2717  m_maxY = 1.0;
2718 
2719  return true;
2720 
2721 #if 0
2722  bool first = true;
2723 
2724  for( wxLayerList::iterator li = m_layers.begin(); li != m_layers.end(); li++ )
2725  {
2726  mpLayer* f = *li;
2727 
2728  if( f->HasBBox() )
2729  {
2730  if( first )
2731  {
2732  first = false;
2733  m_minX = f->GetMinX(); m_maxX = f->GetMaxX();
2734  m_minY = f->GetMinY(); m_maxY = f->GetMaxY();
2735  }
2736  else
2737  {
2738  if( f->GetMinX()<m_minX )
2739  m_minX = f->GetMinX();
2740 
2741  if( f->GetMaxX()>m_maxX )
2742  m_maxX = f->GetMaxX();
2743 
2744  if( f->GetMinY()<m_minY )
2745  m_minY = f->GetMinY();
2746 
2747  if( f->GetMaxY()>m_maxY )
2748  m_maxY = f->GetMaxY();
2749  }
2750  }
2751 
2752  // node = node->GetNext();
2753  }
2754 
2755 #ifdef MATHPLOT_DO_LOGGING
2756  wxLogDebug( wxT(
2757  "[mpWindow::UpdateBBox] Bounding box: Xmin = %f, Xmax = %f, Ymin = %f, YMax = %f" ), m_minX, m_maxX, m_minY,
2758  m_maxY );
2759 #endif // MATHPLOT_DO_LOGGING
2760 
2761  return first == false;
2762 #endif
2763 }
2764 
2765 
2766 // void mpWindow::UpdateAll()
2767 // {
2768 // GetClientSize( &m_scrX,&m_scrY);
2769 /* if (m_enableScrollBars) {
2770  * // The "virtual size" of the scrolled window:
2771  * const int sx = (int)((m_maxX - m_minX) * GetScaleX());
2772  * const int sy = (int)((m_maxY - m_minY) * GetScaleY());
2773  * SetVirtualSize(sx, sy);
2774  * SetScrollRate(1, 1);*/
2775 // const int px = (int)((GetPosX() - m_minX) * GetScaleX());// - m_scrX); //(cx>>1));
2776 
2777 // J.L.Blanco, Aug 2007: Formula fixed:
2778 // const int py = (int)((m_maxY - GetPosY()) * GetScaleY());// - m_scrY); //(cy>>1));
2779 // int px, py;
2780 // GetViewStart(&px0, &py0);
2781 // px = (int)((m_posX - m_minX)*m_scaleX);
2782 // py = (int)((m_maxY - m_posY)*m_scaleY);
2783 
2784 // SetScrollbars( 1, 1, sx - m_scrX, sy - m_scrY, px, py, true);
2785 // }
2786 
2787 // Working code
2788 // UpdateBBox();
2789 // Refresh( false );
2790 // end working code
2791 
2792 // Old version
2793 /* bool box = UpdateBBox();
2794  * if (box)
2795  * {
2796  * int cx, cy;
2797  * GetClientSize( &cx, &cy);
2798  *
2799  * // The "virtual size" of the scrolled window:
2800  * const int sx = (int)((m_maxX - m_minX) * GetScaleX());
2801  * const int sy = (int)((m_maxY - m_minY) * GetScaleY());
2802  *
2803  * const int px = (int)((GetPosX() - m_minX) * GetScaleX() - (cx>>1));
2804  *
2805  * // J.L.Blanco, Aug 2007: Formula fixed:
2806  * const int py = (int)((m_maxY - GetPosY()) * GetScaleY() - (cy>>1));
2807  *
2808  * SetScrollbars( 1, 1, sx, sy, px, py, true);
2809  *
2810  * #ifdef MATHPLOT_DO_LOGGING
2811  * wxLogMessage( "[mpWindow::UpdateAll] Size:%ix%i ScrollBars:%i,%i",sx,sy,px,py);
2812  * #endif
2813  * }
2814  *
2815  * FitInside();
2816  * Refresh( false );
2817  */
2818 // }
2819 
2821 {
2822  if( UpdateBBox() )
2823  {
2824  if( m_enableScrollBars )
2825  {
2826  int cx, cy;
2827  GetClientSize( &cx, &cy );
2828  // Do x scroll bar
2829  {
2830  // Convert margin sizes from pixels to coordinates
2831  double leftMargin = m_marginLeft / m_scaleX;
2832  // Calculate the range in coords that we want to scroll over
2833  double maxX = (m_desiredXmax > m_maxX) ? m_desiredXmax : m_maxX;
2834  double minX = (m_desiredXmin < m_minX) ? m_desiredXmin : m_minX;
2835 
2836  if( (m_posX + leftMargin) < minX )
2837  minX = m_posX + leftMargin;
2838 
2839  // Calculate scroll bar size and thumb position
2840  int sizeX = (int) ( (maxX - minX) * m_scaleX );
2841  int thumbX = (int) ( ( (m_posX + leftMargin) - minX ) * m_scaleX );
2842  SetScrollbar( wxHORIZONTAL, thumbX, cx - (m_marginRight + m_marginLeft), sizeX );
2843  }
2844  // Do y scroll bar
2845  {
2846  // Convert margin sizes from pixels to coordinates
2847  double topMargin = m_marginTop / m_scaleY;
2848  // Calculate the range in coords that we want to scroll over
2849  double maxY = (m_desiredYmax > m_maxY) ? m_desiredYmax : m_maxY;
2850 
2851  if( (m_posY - topMargin) > maxY )
2852  maxY = m_posY - topMargin;
2853 
2854  double minY = (m_desiredYmin < m_minY) ? m_desiredYmin : m_minY;
2855  // Calculate scroll bar size and thumb position
2856  int sizeY = (int) ( (maxY - minY) * m_scaleY );
2857  int thumbY = (int) ( ( maxY - (m_posY - topMargin) ) * m_scaleY );
2858  SetScrollbar( wxVERTICAL, thumbY, cy - (m_marginTop + m_marginBottom), sizeY );
2859  }
2860  }
2861  }
2862 
2863  Refresh( false );
2864 }
2865 
2866 
2867 void mpWindow::DoScrollCalc( const int position, const int orientation )
2868 {
2869  if( orientation == wxVERTICAL )
2870  {
2871  // Y axis
2872  // Get top margin in coord units
2873  double topMargin = m_marginTop / m_scaleY;
2874  // Calculate maximum Y coord to be shown in the graph
2875  double maxY = m_desiredYmax > m_maxY ? m_desiredYmax : m_maxY;
2876  // Set new position
2877  SetPosY( ( maxY - (position / m_scaleY) ) + topMargin );
2878  }
2879  else
2880  {
2881  // X Axis
2882  // Get left margin in coord units
2883  double leftMargin = m_marginLeft / m_scaleX;
2884  // Calculate minimum X coord to be shown in the graph
2885  double minX = (m_desiredXmin < m_minX) ? m_desiredXmin : m_minX;
2886  // Set new position
2887  SetPosX( ( minX + (position / m_scaleX) ) - leftMargin );
2888  }
2889 }
2890 
2891 
2892 void mpWindow::OnScrollThumbTrack( wxScrollWinEvent& event )
2893 {
2894  DoScrollCalc( event.GetPosition(), event.GetOrientation() );
2895 }
2896 
2897 
2898 void mpWindow::OnScrollPageUp( wxScrollWinEvent& event )
2899 {
2900  int scrollOrientation = event.GetOrientation();
2901  // Get position before page up
2902  int position = GetScrollPos( scrollOrientation );
2903  // Get thumb size
2904  int thumbSize = GetScrollThumb( scrollOrientation );
2905 
2906  // Need to adjust position by a page
2907  position -= thumbSize;
2908 
2909  if( position < 0 )
2910  position = 0;
2911 
2912  DoScrollCalc( position, scrollOrientation );
2913 }
2914 
2915 
2916 void mpWindow::OnScrollPageDown( wxScrollWinEvent& event )
2917 {
2918  int scrollOrientation = event.GetOrientation();
2919  // Get position before page up
2920  int position = GetScrollPos( scrollOrientation );
2921  // Get thumb size
2922  int thumbSize = GetScrollThumb( scrollOrientation );
2923  // Get scroll range
2924  int scrollRange = GetScrollRange( scrollOrientation );
2925 
2926  // Need to adjust position by a page
2927  position += thumbSize;
2928 
2929  if( position > (scrollRange - thumbSize) )
2930  position = scrollRange - thumbSize;
2931 
2932  DoScrollCalc( position, scrollOrientation );
2933 }
2934 
2935 
2936 void mpWindow::OnScrollLineUp( wxScrollWinEvent& event )
2937 {
2938  int scrollOrientation = event.GetOrientation();
2939  // Get position before page up
2940  int position = GetScrollPos( scrollOrientation );
2941 
2942  // Need to adjust position by a line
2943  position -= mpSCROLL_NUM_PIXELS_PER_LINE;
2944 
2945  if( position < 0 )
2946  position = 0;
2947 
2948  DoScrollCalc( position, scrollOrientation );
2949 }
2950 
2951 
2952 void mpWindow::OnScrollLineDown( wxScrollWinEvent& event )
2953 {
2954  int scrollOrientation = event.GetOrientation();
2955  // Get position before page up
2956  int position = GetScrollPos( scrollOrientation );
2957  // Get thumb size
2958  int thumbSize = GetScrollThumb( scrollOrientation );
2959  // Get scroll range
2960  int scrollRange = GetScrollRange( scrollOrientation );
2961 
2962  // Need to adjust position by a page
2963  position += mpSCROLL_NUM_PIXELS_PER_LINE;
2964 
2965  if( position > (scrollRange - thumbSize) )
2966  position = scrollRange - thumbSize;
2967 
2968  DoScrollCalc( position, scrollOrientation );
2969 }
2970 
2971 
2972 void mpWindow::OnScrollTop( wxScrollWinEvent& event )
2973 {
2974  DoScrollCalc( 0, event.GetOrientation() );
2975 }
2976 
2977 
2978 void mpWindow::OnScrollBottom( wxScrollWinEvent& event )
2979 {
2980  int scrollOrientation = event.GetOrientation();
2981  // Get thumb size
2982  int thumbSize = GetScrollThumb( scrollOrientation );
2983  // Get scroll range
2984  int scrollRange = GetScrollRange( scrollOrientation );
2985 
2986  DoScrollCalc( scrollRange - thumbSize, scrollOrientation );
2987 }
2988 
2989 
2990 // End patch ngpaton
2991 
2992 void mpWindow::SetScaleX( double scaleX )
2993 {
2994  if( scaleX!=0 )
2995  m_scaleX = scaleX;
2996 
2997  UpdateAll();
2998 }
2999 
3000 
3001 // New methods implemented by Davide Rondini
3002 
3004 {
3005  // wxNode *node = m_layers.GetFirst();
3006  unsigned int layerNo = 0;
3007 
3008  for( wxLayerList::iterator li = m_layers.begin(); li != m_layers.end(); li++ ) // while(node)
3009  {
3010  if( (*li)->HasBBox() )
3011  layerNo++;
3012 
3013  // node = node->GetNext();
3014  }
3015 
3016  ;
3017  return layerNo;
3018 }
3019 
3020 
3021 mpLayer* mpWindow::GetLayer( int position )
3022 {
3023  if( ( position >= (int) m_layers.size() ) || position < 0 )
3024  return NULL;
3025 
3026  return m_layers[position];
3027 }
3028 
3029 
3031 {
3032  for( wxLayerList::iterator it = m_layers.begin(); it!=m_layers.end(); it++ )
3033  if( !(*it)->GetName().Cmp( name ) )
3034  return *it;
3035 
3036 
3037  return NULL; // Not found
3038 }
3039 
3040 
3041 void mpWindow::GetBoundingBox( double* bbox )
3042 {
3043  bbox[0] = m_minX;
3044  bbox[1] = m_maxX;
3045  bbox[2] = m_minY;
3046  bbox[3] = m_maxY;
3047 }
3048 
3049 
3050 bool mpWindow::SaveScreenshot( const wxString& filename, wxBitmapType type,
3051  wxSize imageSize, bool fit )
3052 {
3053  int sizeX, sizeY;
3054  int bk_scrX, bk_scrY;
3055 
3056  if( imageSize == wxDefaultSize )
3057  {
3058  sizeX = m_scrX;
3059  sizeY = m_scrY;
3060  }
3061  else
3062  {
3063  sizeX = imageSize.x;
3064  sizeY = imageSize.y;
3065  bk_scrX = m_scrX;
3066  bk_scrY = m_scrY;
3067  SetScr( sizeX, sizeY );
3068  }
3069 
3070  wxBitmap screenBuffer( sizeX, sizeY );
3071  wxMemoryDC screenDC;
3072  screenDC.SelectObject( screenBuffer );
3073  screenDC.SetPen( *wxWHITE_PEN );
3074  screenDC.SetTextForeground( m_fgColour );
3075  wxBrush brush( GetBackgroundColour() );
3076  screenDC.SetBrush( brush );
3077  screenDC.DrawRectangle( 0, 0, sizeX, sizeY );
3078 
3079  if( fit )
3080  {
3081  Fit( m_minX, m_maxX, m_minY, m_maxY, &sizeX, &sizeY );
3082  }
3083  else
3084  {
3086  }
3087 
3088  // Draw all the layers:
3089  wxLayerList::iterator li;
3090 
3091  for( li = m_layers.begin(); li != m_layers.end(); li++ )
3092  (*li)->Plot( screenDC, *this );
3093 
3094  if( imageSize != wxDefaultSize )
3095  {
3096  // Restore dimensions
3097  SetScr( bk_scrX, bk_scrY );
3098  Fit( m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax, &bk_scrX, &bk_scrY );
3099  UpdateAll();
3100  }
3101 
3102  // Once drawing is complete, actually save screen shot
3103  wxImage screenImage = screenBuffer.ConvertToImage();
3104  return screenImage.SaveFile( filename, type );
3105 }
3106 
3107 
3108 void mpWindow::SetMargins( int top, int right, int bottom, int left )
3109 {
3110  m_marginTop = top;
3111  m_marginRight = right;
3112  m_marginBottom = bottom;
3113  m_marginLeft = left;
3114 }
3115 
3116 
3118 {
3119  wxLayerList::iterator li;
3120 
3121  for( li = m_layers.begin(); li != m_layers.end(); li++ )
3122  {
3123 #ifdef MATHPLOT_DO_LOGGING
3124  wxLogMessage( "mpWindow::IsInsideInfoLayer() examinining layer = %p", (*li) );
3125 #endif // MATHPLOT_DO_LOGGING
3126 
3127  if( (*li)->IsInfo() )
3128  {
3129  mpInfoLayer* tmpLyr = (mpInfoLayer*) (*li);
3130 #ifdef MATHPLOT_DO_LOGGING
3131  wxLogMessage( "mpWindow::IsInsideInfoLayer() layer = %p", (*li) );
3132 #endif // MATHPLOT_DO_LOGGING
3133 
3134  if( tmpLyr->Inside( point ) )
3135  {
3136  return tmpLyr;
3137  }
3138  }
3139  }
3140 
3141  return NULL;
3142 }
3143 
3144 
3145 void mpWindow::SetLayerVisible( const wxString& name, bool viewable )
3146 {
3147  mpLayer* lx = GetLayerByName( name );
3148 
3149  if( lx )
3150  {
3151  lx->SetVisible( viewable );
3152  UpdateAll();
3153  }
3154 }
3155 
3156 
3157 bool mpWindow::IsLayerVisible( const wxString& name )
3158 {
3159  mpLayer* lx = GetLayerByName( name );
3160 
3161  return (lx) ? lx->IsVisible() : false;
3162 }
3163 
3164 
3165 void mpWindow::SetLayerVisible( const unsigned int position, bool viewable )
3166 {
3167  mpLayer* lx = GetLayer( position );
3168 
3169  if( lx )
3170  {
3171  lx->SetVisible( viewable );
3172  UpdateAll();
3173  }
3174 }
3175 
3176 
3177 bool mpWindow::IsLayerVisible( const unsigned int position )
3178 {
3179  mpLayer* lx = GetLayer( position );
3180 
3181  return (lx) ? lx->IsVisible() : false;
3182 }
3183 
3184 
3185 void mpWindow::SetColourTheme( const wxColour& bgColour,
3186  const wxColour& drawColour,
3187  const wxColour& axesColour )
3188 {
3189  SetBackgroundColour( bgColour );
3190  SetForegroundColour( drawColour );
3191  m_bgColour = bgColour;
3192  m_fgColour = drawColour;
3193  m_axColour = axesColour;
3194  // cycle between layers to set colours and properties to them
3195  wxLayerList::iterator li;
3196 
3197  for( li = m_layers.begin(); li != m_layers.end(); li++ )
3198  {
3199  if( (*li)->GetLayerType() == mpLAYER_AXIS )
3200  {
3201  wxPen axisPen = (*li)->GetPen(); // Get the old pen to modify only colour, not style or width
3202  axisPen.SetColour( axesColour );
3203  (*li)->SetPen( axisPen );
3204  }
3205 
3206  if( (*li)->GetLayerType() == mpLAYER_INFO )
3207  {
3208  wxPen infoPen = (*li)->GetPen(); // Get the old pen to modify only colour, not style or width
3209  infoPen.SetColour( drawColour );
3210  (*li)->SetPen( infoPen );
3211  }
3212  }
3213 }
3214 
3215 
3216 // void mpWindow::EnableCoordTooltip(bool value)
3217 // {
3218 // m_coordTooltip = value;
3220 // }
3221 
3222 /*
3223  * double mpWindow::p2x(wxCoord pixelCoordX, bool drawOutside )
3224  * {
3225  * if (drawOutside) {
3226  * return m_posX + pixelCoordX/m_scaleX;
3227  * }
3228  * // Draw inside margins
3229  * double marginScaleX = ((double)(m_scrX - m_marginLeft - m_marginRight))/m_scrX;
3230  * return m_marginLeft + (m_posX + pixelCoordX/m_scaleX)/marginScaleX;
3231  * }
3232  *
3233  * double mpWindow::p2y(wxCoord pixelCoordY, bool drawOutside )
3234  * {
3235  * if (drawOutside) {
3236  * return m_posY - pixelCoordY/m_scaleY;
3237  * }
3238  * // Draw inside margins
3239  * double marginScaleY = ((double)(m_scrY - m_marginTop - m_marginBottom))/m_scrY;
3240  * return m_marginTop + (m_posY - pixelCoordY/m_scaleY)/marginScaleY;
3241  * }
3242  *
3243  * wxCoord mpWindow::x2p(double x, bool drawOutside)
3244  * {
3245  * if (drawOutside) {
3246  * return (wxCoord) ((x-m_posX) * m_scaleX);
3247  * }
3248  * // Draw inside margins
3249  * double marginScaleX = ((double)(m_scrX - m_marginLeft - m_marginRight))/m_scrX;
3250  * #ifdef MATHPLOT_DO_LOGGING
3251  * wxLogMessage(wxT("x2p ScrX = %d, marginRight = %d, marginLeft = %d, marginScaleX = %f"), m_scrX, m_marginRight, m_marginLeft, marginScaleX);
3252  * #endif // MATHPLOT_DO_LOGGING
3253  * return (wxCoord) (int)(((x-m_posX) * m_scaleX)*marginScaleX) - m_marginLeft;
3254  * }
3255  *
3256  * wxCoord mpWindow::y2p(double y, bool drawOutside)
3257  * {
3258  * if (drawOutside) {
3259  * return (wxCoord) ( (m_posY-y) * m_scaleY);
3260  * }
3261  * // Draw inside margins
3262  * double marginScaleY = ((double)(m_scrY - m_marginTop - m_marginBottom))/m_scrY;
3263  * #ifdef MATHPLOT_DO_LOGGING
3264  * wxLogMessage(wxT("y2p ScrY = %d, marginTop = %d, marginBottom = %d, marginScaleY = %f"), m_scrY, m_marginTop, m_marginBottom, marginScaleY);
3265  * #endif // MATHPLOT_DO_LOGGING
3266  * return (wxCoord) ((int)((m_posY-y) * m_scaleY)*marginScaleY) - m_marginTop;
3267  * }
3268  */
3269 
3270 
3271 // -----------------------------------------------------------------------------
3272 // mpFXYVector implementation - by Jose Luis Blanco (AGO-2007)
3273 // -----------------------------------------------------------------------------
3274 
3275 IMPLEMENT_DYNAMIC_CLASS( mpFXYVector, mpFXY )
3276 
3277 // Constructor
3278 mpFXYVector::mpFXYVector( const wxString& name, int flags ) : mpFXY( name, flags )
3279 {
3280  m_index = 0;
3281  // printf("FXYVector::FXYVector!\n");
3282  m_minX = -1;
3283  m_maxX = 1;
3284  m_minY = -1;
3285  m_maxY = 1;
3286  m_type = mpLAYER_PLOT;
3287 }
3288 
3289 
3290 double mpScaleX::TransformToPlot( double x )
3291 {
3292  return (x + m_offset) * m_scale;
3293 }
3294 
3295 
3296 double mpScaleX::TransformFromPlot( double xplot )
3297 {
3298  return xplot / m_scale - m_offset;
3299 }
3300 
3301 
3302 double mpScaleY::TransformToPlot( double x )
3303 {
3304  return (x + m_offset) * m_scale;
3305 }
3306 
3307 
3308 double mpScaleY::TransformFromPlot( double xplot )
3309 {
3310  return xplot / m_scale - m_offset;
3311 }
3312 
3313 
3315 {
3316  double xlogmin = log10( m_minV );
3317  double xlogmax = log10( m_maxV );
3318 
3319  return ( log10( x ) - xlogmin) / (xlogmax - xlogmin);
3320 }
3321 
3322 
3323 double mpScaleXLog::TransformFromPlot( double xplot )
3324 {
3325  double xlogmin = log10( m_minV );
3326  double xlogmax = log10( m_maxV );
3327 
3328  return pow( 10.0, xplot * (xlogmax - xlogmin) + xlogmin );
3329 }
3330 
3331 
3332 #if 0
3333 mpFSemiLogXVector::mpFSemiLogXVector( wxString name, int flags ) :
3334  mpFXYVector( name, flags )
3335 {
3336 }
3337 
3338 
3339 IMPLEMENT_DYNAMIC_CLASS( mpFSemiLogXVector, mpFXYVector )
3340 #endif
3341 
3343 {
3344  m_index = 0;
3345 }
3346 
3348 {
3349  return m_xs.size();
3350 }
3351 
3352 
3353 bool mpFXYVector::GetNextXY( double& x, double& y )
3354 {
3355  if( m_index >= m_xs.size() )
3356  {
3357  return false;
3358  }
3359  else
3360  {
3361  x = m_xs[m_index];
3362  y = m_ys[m_index++];
3363  return m_index <= m_xs.size();
3364  }
3365 }
3366 
3367 
3369 {
3370  m_xs.clear();
3371  m_ys.clear();
3372 }
3373 
3374 
3375 void mpFXYVector::SetData( const std::vector<double>& xs, const std::vector<double>& ys )
3376 {
3377  // Check if the data vectora are of the same size
3378  if( xs.size() != ys.size() )
3379  {
3380  wxLogError( "wxMathPlot error: X and Y vector are not of the same length!" );
3381  return;
3382  }
3383 
3384  // Copy the data:
3385  m_xs = xs;
3386  m_ys = ys;
3387 
3388  // printf("FXYVector::setData %d %d\n", xs.size(), ys.size());
3389 
3390  // Update internal variables for the bounding box.
3391  if( xs.size()>0 )
3392  {
3393  m_minX = xs[0];
3394  m_maxX = xs[0];
3395  m_minY = ys[0];
3396  m_maxY = ys[0];
3397 
3398  std::vector<double>::const_iterator it;
3399 
3400  for( it = xs.begin(); it!=xs.end(); it++ )
3401  {
3402  if( *it<m_minX )
3403  m_minX = *it;
3404 
3405  if( *it>m_maxX )
3406  m_maxX = *it;
3407  }
3408 
3409  for( it = ys.begin(); it!=ys.end(); it++ )
3410  {
3411  if( *it<m_minY )
3412  m_minY = *it;
3413 
3414  if( *it>m_maxY )
3415  m_maxY = *it;
3416  }
3417 
3418  // printf("minX %.10f maxX %.10f\n ", m_minX, m_maxX );
3419  // printf("minY %.10f maxY %.10f\n ", m_minY, m_maxY );
3420  }
3421  else
3422  {
3423  m_minX = -1;
3424  m_maxX = 1;
3425  m_minY = -1;
3426  m_maxY = 1;
3427  }
3428 }
3429 
3430 
3431 // -----------------------------------------------------------------------------
3432 // mpText - provided by Val Greene
3433 // -----------------------------------------------------------------------------
3434 
3435 IMPLEMENT_DYNAMIC_CLASS( mpText, mpLayer )
3436 
3437 
3438 
3442 mpText::mpText( const wxString& name, int offsetx, int offsety )
3443 {
3444  SetName( name );
3445 
3446  if( offsetx >= 0 && offsetx <= 100 )
3447  m_offsetx = offsetx;
3448  else
3449  m_offsetx = 5;
3450 
3451  if( offsety >= 0 && offsety <= 100 )
3452  m_offsety = offsety;
3453  else
3454  m_offsety = 50;
3455 
3456  m_type = mpLAYER_INFO;
3457 }
3458 
3459 
3464 void mpText::Plot( wxDC& dc, mpWindow& w )
3465 {
3466  if( m_visible )
3467  {
3468  dc.SetPen( m_pen );
3469  dc.SetFont( m_font );
3470 
3471  wxCoord tw = 0, th = 0;
3472  dc.GetTextExtent( GetName(), &tw, &th );
3473 
3474  // int left = -dc.LogicalToDeviceX(0);
3475  // int width = dc.LogicalToDeviceX(0) - left;
3476  // int bottom = dc.LogicalToDeviceY(0);
3477  // int height = bottom - -dc.LogicalToDeviceY(0);
3478 
3479  /* dc.DrawText( GetName(),
3480  * (int)((((float)width/100.0) * m_offsety) + left - (tw/2)),
3481  * (int)((((float)height/100.0) * m_offsetx) - bottom) );*/
3482  int px = m_offsetx * ( w.GetScrX() - w.GetMarginLeft() - w.GetMarginRight() ) / 100;
3483  int py = m_offsety * ( w.GetScrY() - w.GetMarginTop() - w.GetMarginBottom() ) / 100;
3484  dc.DrawText( GetName(), px, py );
3485  }
3486 }
3487 
3488 
3489 // -----------------------------------------------------------------------------
3490 // mpPrintout - provided by Davide Rondini
3491 // -----------------------------------------------------------------------------
3492 
3493 mpPrintout::mpPrintout( mpWindow* drawWindow, const wxChar* title ) : wxPrintout( title )
3494 {
3495  drawn = false;
3496  plotWindow = drawWindow;
3497 }
3498 
3499 
3500 bool mpPrintout::OnPrintPage( int page )
3501 {
3502  wxDC* trgDc = GetDC();
3503 
3504  if( (trgDc) && (page == 1) )
3505  {
3506  wxCoord m_prnX, m_prnY;
3507  int marginX = 50;
3508  int marginY = 50;
3509  trgDc->GetSize( &m_prnX, &m_prnY );
3510 
3511  m_prnX -= (2 * marginX);
3512  m_prnY -= (2 * marginY);
3513  trgDc->SetDeviceOrigin( marginX, marginY );
3514 
3515 #ifdef MATHPLOT_DO_LOGGING
3516  wxLogMessage( wxT( "Print Size: %d x %d\n" ), m_prnX, m_prnY );
3517  wxLogMessage( wxT( "Screen Size: %d x %d\n" ), plotWindow->GetScrX(),
3518  plotWindow->GetScrY() );
3519 #endif
3520 
3521  // Set the scale according to the page:
3522  plotWindow->Fit(
3527  &m_prnX,
3528  &m_prnY );
3529 
3530  // Get the colours of the plotWindow to restore them ath the end
3531  wxColour oldBgColour = plotWindow->GetBackgroundColour();
3532  wxColour oldFgColour = plotWindow->GetForegroundColour();
3533  wxColour oldAxColour = plotWindow->GetAxesColour();
3534 
3535  // Draw background, ensuring to use white background for printing.
3536  trgDc->SetPen( *wxTRANSPARENT_PEN );
3537  // wxBrush brush( plotWindow->GetBackgroundColour() );
3538  wxBrush brush = *wxWHITE_BRUSH;
3539  trgDc->SetBrush( brush );
3540  trgDc->DrawRectangle( 0, 0, m_prnX, m_prnY );
3541 
3542  // Draw all the layers:
3543  // trgDc->SetDeviceOrigin( m_prnX>>1, m_prnY>>1); // Origin at the center
3544  mpLayer* layer;
3545 
3546  for( unsigned int li = 0; li < plotWindow->CountAllLayers(); li++ )
3547  {
3548  layer = plotWindow->GetLayer( li );
3549  layer->Plot( *trgDc, *plotWindow );
3550  }
3551 
3552  ;
3553  // Restore device origin
3554  // trgDc->SetDeviceOrigin(0, 0);
3555  // Restore colours
3556  plotWindow->SetColourTheme( oldBgColour, oldFgColour, oldAxColour );
3557  // Restore drawing
3561  plotWindow->UpdateAll();
3562  }
3563 
3564  return true;
3565 }
3566 
3567 
3568 bool mpPrintout::HasPage( int page )
3569 {
3570  return page == 1;
3571 }
3572 
3573 
3574 // -----------------------------------------------------------------------------
3575 // mpMovableObject - provided by Jose Luis Blanco
3576 // -----------------------------------------------------------------------------
3577 void mpMovableObject::TranslatePoint( double x, double y, double& out_x, double& out_y )
3578 {
3579  double ccos = cos( m_reference_phi ); // Avoid computing cos/sin twice.
3580  double csin = sin( m_reference_phi );
3581 
3582  out_x = m_reference_x + ccos * x - csin * y;
3583  out_y = m_reference_y + csin * x + ccos * y;
3584 }
3585 
3586 
3587 // This method updates the buffers m_trans_shape_xs/ys, and the precomputed bounding box.
3589 {
3590  // Just in case...
3591  if( m_shape_xs.size()!=m_shape_ys.size() )
3592  {
3593  wxLogError( wxT(
3594  "[mpMovableObject::ShapeUpdated] Error, m_shape_xs and m_shape_ys have different lengths!" ) );
3595  }
3596  else
3597  {
3598  double ccos = cos( m_reference_phi ); // Avoid computing cos/sin twice.
3599  double csin = sin( m_reference_phi );
3600 
3601  m_trans_shape_xs.resize( m_shape_xs.size() );
3602  m_trans_shape_ys.resize( m_shape_xs.size() );
3603 
3604  std::vector<double>::iterator itXi, itXo;
3605  std::vector<double>::iterator itYi, itYo;
3606 
3607  m_bbox_min_x = 1e300;
3608  m_bbox_max_x = -1e300;
3609  m_bbox_min_y = 1e300;
3610  m_bbox_max_y = -1e300;
3611 
3612  for( itXo = m_trans_shape_xs.begin(),
3613  itYo = m_trans_shape_ys.begin(), itXi = m_shape_xs.begin(), itYi = m_shape_ys.begin();
3614  itXo!=m_trans_shape_xs.end(); itXo++, itYo++, itXi++, itYi++ )
3615  {
3616  *itXo = m_reference_x + ccos * (*itXi) - csin * (*itYi);
3617  *itYo = m_reference_y + csin * (*itXi) + ccos * (*itYi);
3618 
3619  // Keep BBox:
3620  if( *itXo < m_bbox_min_x )
3621  m_bbox_min_x = *itXo;
3622 
3623  if( *itXo > m_bbox_max_x )
3624  m_bbox_max_x = *itXo;
3625 
3626  if( *itYo < m_bbox_min_y )
3627  m_bbox_min_y = *itYo;
3628 
3629  if( *itYo > m_bbox_max_y )
3630  m_bbox_max_y = *itYo;
3631  }
3632  }
3633 }
3634 
3635 
3636 void mpMovableObject::Plot( wxDC& dc, mpWindow& w )
3637 {
3638  if( m_visible )
3639  {
3640  dc.SetPen( m_pen );
3641 
3642 
3643  std::vector<double>::iterator itX = m_trans_shape_xs.begin();
3644  std::vector<double>::iterator itY = m_trans_shape_ys.begin();
3645 
3646  if( !m_continuous )
3647  {
3648  // for some reason DrawPoint does not use the current pen,
3649  // so we use DrawLine for fat pens
3650  if( m_pen.GetWidth() <= 1 )
3651  {
3652  while( itX!=m_trans_shape_xs.end() )
3653  {
3654  dc.DrawPoint( w.x2p( *(itX++) ), w.y2p( *(itY++) ) );
3655  }
3656  }
3657  else
3658  {
3659  while( itX!=m_trans_shape_xs.end() )
3660  {
3661  wxCoord cx = w.x2p( *(itX++) );
3662  wxCoord cy = w.y2p( *(itY++) );
3663  dc.DrawLine( cx, cy, cx, cy );
3664  }
3665  }
3666  }
3667  else
3668  {
3669  wxCoord cx0 = 0, cy0 = 0;
3670  bool first = true;
3671 
3672  while( itX!=m_trans_shape_xs.end() )
3673  {
3674  wxCoord cx = w.x2p( *(itX++) );
3675  wxCoord cy = w.y2p( *(itY++) );
3676 
3677  if( first )
3678  {
3679  first = false;
3680  cx0 = cx; cy0 = cy;
3681  }
3682 
3683  dc.DrawLine( cx0, cy0, cx, cy );
3684  cx0 = cx; cy0 = cy;
3685  }
3686  }
3687 
3688  if( !m_name.IsEmpty() && m_showName )
3689  {
3690  dc.SetFont( m_font );
3691 
3692  wxCoord tx, ty;
3693  dc.GetTextExtent( m_name, &tx, &ty );
3694 
3695  if( HasBBox() )
3696  {
3697  wxCoord sx = (wxCoord) ( ( m_bbox_max_x - w.GetPosX() ) * w.GetScaleX() );
3698  wxCoord sy = (wxCoord) ( (w.GetPosY() - m_bbox_max_y ) * w.GetScaleY() );
3699 
3700  tx = sx - tx - 8;
3701  ty = sy - 8 - ty;
3702  }
3703  else
3704  {
3705  const int sx = w.GetScrX() >> 1;
3706  const int sy = w.GetScrY() >> 1;
3707 
3708  if( (m_flags & mpALIGNMASK) == mpALIGN_NE )
3709  {
3710  tx = sx - tx - 8;
3711  ty = -sy + 8;
3712  }
3713  else if( (m_flags & mpALIGNMASK) == mpALIGN_NW )
3714  {
3715  tx = -sx + 8;
3716  ty = -sy + 8;
3717  }
3718  else if( (m_flags & mpALIGNMASK) == mpALIGN_SW )
3719  {
3720  tx = -sx + 8;
3721  ty = sy - 8 - ty;
3722  }
3723  else
3724  {
3725  tx = sx - tx - 8;
3726  ty = sy - 8 - ty;
3727  }
3728  }
3729 
3730  dc.DrawText( m_name, tx, ty );
3731  }
3732  }
3733 }
3734 
3735 
3736 // -----------------------------------------------------------------------------
3737 // mpCovarianceEllipse - provided by Jose Luis Blanco
3738 // -----------------------------------------------------------------------------
3739 
3740 // Called to update the m_shape_xs, m_shape_ys vectors, whenever a parameter changes.
3742 {
3743  m_shape_xs.clear();
3744  m_shape_ys.clear();
3745 
3746  // Preliminar checks:
3747  if( m_quantiles<0 )
3748  {
3749  wxLogError( wxT( "[mpCovarianceEllipse] Error: quantiles must be non-negative" ) ); return;
3750  }
3751 
3752  if( m_cov_00<0 )
3753  {
3754  wxLogError( wxT( "[mpCovarianceEllipse] Error: cov(0,0) must be non-negative" ) ); return;
3755  }
3756 
3757  if( m_cov_11<0 )
3758  {
3759  wxLogError( wxT( "[mpCovarianceEllipse] Error: cov(1,1) must be non-negative" ) ); return;
3760  }
3761 
3762  m_shape_xs.resize( m_segments, 0 );
3763  m_shape_ys.resize( m_segments, 0 );
3764 
3765  // Compute the two eigenvalues of the covariance:
3766  // -------------------------------------------------
3767  double b = -m_cov_00 - m_cov_11;
3768  double c = m_cov_00 * m_cov_11 - m_cov_01 * m_cov_01;
3769 
3770  double D = b * b - 4 * c;
3771 
3772  if( D<0 )
3773  {
3774  wxLogError( wxT( "[mpCovarianceEllipse] Error: cov is not positive definite" ) ); return;
3775  }
3776 
3777  double eigenVal0 = 0.5 * ( -b + sqrt( D ) );
3778  double eigenVal1 = 0.5 * ( -b - sqrt( D ) );
3779 
3780  // Compute the two corresponding eigenvectors:
3781  // -------------------------------------------------
3782  double eigenVec0_x, eigenVec0_y;
3783  double eigenVec1_x, eigenVec1_y;
3784 
3785  if( fabs( eigenVal0 - m_cov_00 )>1e-6 )
3786  {
3787  double k1x = m_cov_01 / ( eigenVal0 - m_cov_00 );
3788  eigenVec0_y = 1;
3789  eigenVec0_x = eigenVec0_y * k1x;
3790  }
3791  else
3792  {
3793  double k1y = m_cov_01 / ( eigenVal0 - m_cov_11 );
3794  eigenVec0_x = 1;
3795  eigenVec0_y = eigenVec0_x * k1y;
3796  }
3797 
3798  if( fabs( eigenVal1 - m_cov_00 )>1e-6 )
3799  {
3800  double k2x = m_cov_01 / ( eigenVal1 - m_cov_00 );
3801  eigenVec1_y = 1;
3802  eigenVec1_x = eigenVec1_y * k2x;
3803  }
3804  else
3805  {
3806  double k2y = m_cov_01 / ( eigenVal1 - m_cov_11 );
3807  eigenVec1_x = 1;
3808  eigenVec1_y = eigenVec1_x * k2y;
3809  }
3810 
3811  // Normalize the eigenvectors:
3812  double len = sqrt( eigenVec0_x * eigenVec0_x + eigenVec0_y * eigenVec0_y );
3813  eigenVec0_x /= len; // It *CANNOT* be zero
3814  eigenVec0_y /= len;
3815 
3816  len = sqrt( eigenVec1_x * eigenVec1_x + eigenVec1_y * eigenVec1_y );
3817  eigenVec1_x /= len; // It *CANNOT* be zero
3818  eigenVec1_y /= len;
3819 
3820 
3821  // Take the sqrt of the eigenvalues (required for the ellipse scale):
3822  eigenVal0 = sqrt( eigenVal0 );
3823  eigenVal1 = sqrt( eigenVal1 );
3824 
3825  // Compute the 2x2 matrix M = diag(eigVal) * (~eigVec) (each eigen vector is a row):
3826  double M_00 = eigenVec0_x * eigenVal0;
3827  double M_01 = eigenVec0_y * eigenVal0;
3828 
3829  double M_10 = eigenVec1_x * eigenVal1;
3830  double M_11 = eigenVec1_y * eigenVal1;
3831 
3832  // The points of the 2D ellipse:
3833  double ang;
3834  double Aang = 6.283185308 / (m_segments - 1);
3835  int i;
3836 
3837  for( i = 0, ang = 0; i<m_segments; i++, ang += Aang )
3838  {
3839  double ccos = cos( ang );
3840  double csin = sin( ang );
3841 
3842  m_shape_xs[i] = m_quantiles * (ccos * M_00 + csin * M_10 );
3843  m_shape_ys[i] = m_quantiles * (ccos * M_01 + csin * M_11 );
3844  } // end for points on ellipse
3845 
3846  ShapeUpdated();
3847 }
3848 
3849 
3850 // -----------------------------------------------------------------------------
3851 // mpPolygon - provided by Jose Luis Blanco
3852 // -----------------------------------------------------------------------------
3853 void mpPolygon::setPoints( const std::vector<double>& points_xs,
3854  const std::vector<double>& points_ys,
3855  bool closedShape )
3856 {
3857  if( points_xs.size()!=points_ys.size() )
3858  {
3859  wxLogError( wxT(
3860  "[mpPolygon] Error: points_xs and points_ys must have the same number of elements" ) );
3861  }
3862  else
3863  {
3864  m_shape_xs = points_xs;
3865  m_shape_ys = points_ys;
3866 
3867  if( closedShape && points_xs.size() )
3868  {
3869  m_shape_xs.push_back( points_xs[0] );
3870  m_shape_ys.push_back( points_ys[0] );
3871  }
3872 
3873  ShapeUpdated();
3874  }
3875 }
3876 
3877 
3878 // -----------------------------------------------------------------------------
3879 // mpBitmapLayer - provided by Jose Luis Blanco
3880 // -----------------------------------------------------------------------------
3881 void mpBitmapLayer::GetBitmapCopy( wxImage& outBmp ) const
3882 {
3883  if( m_validImg )
3884  outBmp = m_bitmap;
3885 }
3886 
3887 
3888 void mpBitmapLayer::SetBitmap( const wxImage& inBmp, double x, double y, double lx, double ly )
3889 {
3890  if( !inBmp.Ok() )
3891  {
3892  wxLogError( wxT( "[mpBitmapLayer] Assigned bitmap is not Ok()!" ) );
3893  }
3894  else
3895  {
3896  m_bitmap = inBmp; // .GetSubBitmap( wxRect(0, 0, inBmp.GetWidth(), inBmp.GetHeight()));
3897  m_min_x = x;
3898  m_min_y = y;
3899  m_max_x = x + lx;
3900  m_max_y = y + ly;
3901  m_validImg = true;
3902  }
3903 }
3904 
3905 
3906 void mpBitmapLayer::Plot( wxDC& dc, mpWindow& w )
3907 {
3908  if( m_visible && m_validImg )
3909  {
3910  /* 1st: We compute (x0,y0)-(x1,y1), the pixel coordinates of the real outer limits
3911  * of the image rectangle within the (screen) mpWindow. Note that these coordinates
3912  * might fall well far away from the real view limits when the user zoom in.
3913  *
3914  * 2nd: We compute (dx0,dy0)-(dx1,dy1), the pixel coordinates the rectangle that will
3915  * be actually drawn into the mpWindow, i.e. the clipped real rectangle that
3916  * avoids the non-visible parts. (offset_x,offset_y) are the pixel coordinates
3917  * that correspond to the window point (dx0,dy0) within the image "m_bitmap", and
3918  * (b_width,b_height) is the size of the bitmap patch that will be drawn.
3919  *
3920  * (x0,y0) ................. (x1,y0)
3921  * . .
3922  * . .
3923  * (x0,y1) ................ (x1,y1)
3924  * (In pixels!!)
3925  */
3926 
3927  // 1st step -------------------------------
3928  wxCoord x0 = w.x2p( m_min_x );
3929  wxCoord y0 = w.y2p( m_max_y );
3930  wxCoord x1 = w.x2p( m_max_x );
3931  wxCoord y1 = w.y2p( m_min_y );
3932 
3933  // 2nd step -------------------------------
3934  // Precompute the size of the actual bitmap pixel on the screen (e.g. will be >1 if zoomed in)
3935  double screenPixelX = ( x1 - x0 ) / (double) m_bitmap.GetWidth();
3936  double screenPixelY = ( y1 - y0 ) / (double) m_bitmap.GetHeight();
3937 
3938  // The minimum number of pixels that the streched image will overpass the actual mpWindow borders:
3939  wxCoord borderMarginX = (wxCoord) (screenPixelX + 1); // ceil
3940  wxCoord borderMarginY = (wxCoord) (screenPixelY + 1); // ceil
3941 
3942  // The actual drawn rectangle (dx0,dy0)-(dx1,dy1) is (x0,y0)-(x1,y1) clipped:
3943  wxCoord dx0 = x0, dx1 = x1, dy0 = y0, dy1 = y1;
3944 
3945  if( dx0<0 )
3946  dx0 = -borderMarginX;
3947 
3948  if( dy0<0 )
3949  dy0 = -borderMarginY;
3950 
3951  if( dx1>w.GetScrX() )
3952  dx1 = w.GetScrX() + borderMarginX;
3953 
3954  if( dy1>w.GetScrY() )
3955  dy1 = w.GetScrY() + borderMarginY;
3956 
3957  // For convenience, compute the width/height of the rectangle to be actually drawn:
3958  wxCoord d_width = dx1 - dx0 + 1;
3959  wxCoord d_height = dy1 - dy0 + 1;
3960 
3961  // Compute the pixel offsets in the internally stored bitmap:
3962  wxCoord offset_x = (wxCoord) ( (dx0 - x0) / screenPixelX );
3963  wxCoord offset_y = (wxCoord) ( (dy0 - y0) / screenPixelY );
3964 
3965  // and the size in pixel of the area to be actually drawn from the internally stored bitmap:
3966  wxCoord b_width = (wxCoord) ( (dx1 - dx0 + 1) / screenPixelX );
3967  wxCoord b_height = (wxCoord) ( (dy1 - dy0 + 1) / screenPixelY );
3968 
3969 #ifdef MATHPLOT_DO_LOGGING
3970  wxLogMessage( "[mpBitmapLayer::Plot] screenPixel: x=%f y=%f d_width=%ix%i",
3971  screenPixelX,
3972  screenPixelY,
3973  d_width,
3974  d_height );
3975  wxLogMessage( "[mpBitmapLayer::Plot] offset: x=%i y=%i bmpWidth=%ix%i",
3976  offset_x,
3977  offset_y,
3978  b_width,
3979  b_height );
3980 #endif
3981 
3982  // Is there any visible region?
3983  if( d_width>0 && d_height>0 )
3984  {
3985  // Build the scaled bitmap from the image, only if it has changed:
3986  if( m_scaledBitmap.GetWidth()!=d_width
3987  || m_scaledBitmap.GetHeight()!=d_height
3988  || m_scaledBitmap_offset_x != offset_x
3989  || m_scaledBitmap_offset_y != offset_y )
3990  {
3991  wxRect r( wxRect( offset_x, offset_y, b_width, b_height ) );
3992 
3993  // Just for the case....
3994  if( r.x<0 )
3995  r.x = 0;
3996 
3997  if( r.y<0 )
3998  r.y = 0;
3999 
4000  if( r.width>m_bitmap.GetWidth() )
4001  r.width = m_bitmap.GetWidth();
4002 
4003  if( r.height>m_bitmap.GetHeight() )
4004  r.height = m_bitmap.GetHeight();
4005 
4006  m_scaledBitmap = wxBitmap(
4007  wxBitmap( m_bitmap ).GetSubBitmap( r ).ConvertToImage()
4008  .Scale( d_width, d_height ) );
4009  m_scaledBitmap_offset_x = offset_x;
4010  m_scaledBitmap_offset_y = offset_y;
4011  }
4012 
4013  // Draw it:
4014  dc.DrawBitmap( m_scaledBitmap, dx0, dy0, true );
4015  }
4016  }
4017 
4018  // Draw the name label
4019  if( !m_name.IsEmpty() && m_showName )
4020  {
4021  dc.SetFont( m_font );
4022 
4023  wxCoord tx, ty;
4024  dc.GetTextExtent( m_name, &tx, &ty );
4025 
4026  if( HasBBox() )
4027  {
4028  wxCoord sx = (wxCoord) ( ( m_max_x - w.GetPosX() ) * w.GetScaleX() );
4029  wxCoord sy = (wxCoord) ( (w.GetPosY() - m_max_y ) * w.GetScaleY() );
4030 
4031  tx = sx - tx - 8;
4032  ty = sy - 8 - ty;
4033  }
4034  else
4035  {
4036  const int sx = w.GetScrX() >> 1;
4037  const int sy = w.GetScrY() >> 1;
4038 
4039  if( (m_flags & mpALIGNMASK) == mpALIGN_NE )
4040  {
4041  tx = sx - tx - 8;
4042  ty = -sy + 8;
4043  }
4044  else if( (m_flags & mpALIGNMASK) == mpALIGN_NW )
4045  {
4046  tx = -sx + 8;
4047  ty = -sy + 8;
4048  }
4049  else if( (m_flags & mpALIGNMASK) == mpALIGN_SW )
4050  {
4051  tx = -sx + 8;
4052  ty = sy - 8 - ty;
4053  }
4054  else
4055  {
4056  tx = sx - tx - 8;
4057  ty = sy - 8 - ty;
4058  }
4059  }
4060 
4061  dc.DrawText( m_name, tx, ty );
4062  }
4063 }
4064 
4065 
4066 void mpFXY::SetScale( mpScaleBase* scaleX, mpScaleBase* scaleY )
4067 {
4068  m_scaleX = scaleX;
4069  m_scaleY = scaleY;
4070 
4071  // printf("SetScales : %p %p\n", scaleX, scaleY);
4072  UpdateScales();
4073 }
4074 
4075 
4077 {
4078  if( m_scaleX )
4080 
4081  if( m_scaleY )
4083 }
4084 
4085 
4086 double mpFXY::s2x( double plotCoordX ) const
4087 {
4088  return m_scaleX->TransformFromPlot( plotCoordX );
4089 }
4090 
4091 
4092 double mpFXY::s2y( double plotCoordY ) const
4093 {
4094  return m_scaleY->TransformFromPlot( plotCoordY );
4095 }
4096 
4097 
4098 double mpFXY::x2s( double x ) const
4099 {
4100  return m_scaleX->TransformToPlot( x );
4101 }
4102 
4103 
4104 double mpFXY::y2s( double y ) const
4105 {
4106  return m_scaleY->TransformToPlot( y );
4107 }
int m_winX
Definition: mathplot.h:399
double m_maxV
Definition: mathplot.h:837
int m_offsetx
Definition: mathplot.h:1684
mpInfoLegend()
Default constructor.
Definition: mathplot.cpp:292
virtual double TransformToPlot(double x) override
Layer plot handler.
Definition: mathplot.cpp:3290
void ZoomOut(const wxPoint &centerPoint=wxDefaultPosition)
Zoom out current view and refresh display.
Definition: mathplot.cpp:2306
wxCoord maxDrawY
Definition: mathplot.h:632
double s2x(double plotCoordX) const
Definition: mathplot.cpp:4086
virtual void UpdateInfo(mpWindow &w, wxEvent &event) override
Updates the content of the info box.
Definition: mathplot.cpp:307
void OnScrollThumbTrack(wxScrollWinEvent &event)
Definition: mathplot.cpp:2892
#define mpALIGN_LEFT
Aligns label to the left.
Definition: mathplot.h:482
mpLayerType GetLayerType()
Get layer type: a Layer can be of different types: plot lines, axis, info boxes, etc,...
Definition: mathplot.h:295
double m_max_y
Definition: mathplot.h:2013
#define MAX_SCALE
Definition: panel_prev_3d.h:48
virtual void recalculateTicks(wxDC &dc, mpWindow &w)
Definition: mathplot.h:799
wxMemoryDC m_buff_dc
Definition: mathplot.h:1526
int m_marginRight
Definition: mathplot.h:1523
virtual double GetX(double y)=0
Get function value for argument.
virtual void getVisibleDataRange(mpWindow &w, double &minV, double &maxV) override
Definition: mathplot.cpp:1190
void OnMagnify(wxMouseEvent &event)
virtual void Plot(wxDC &dc, mpWindow &w) override
Plot method.
Definition: mathplot.cpp:243
bool drawn
Definition: mathplot.h:1710
bool m_continuous
Definition: mathplot.h:319
bool m_enableScrollBars
Definition: mathplot.h:1534
virtual double GetY(double x)=0
Get function value for argument.
virtual bool Inside(wxPoint &point)
Checks whether a point is inside the info box rectangle.
Definition: mathplot.cpp:135
#define mpALIGN_NW
Aligns label to north-west.
Definition: mathplot.h:508
void OnLockAspect(wxCommandEvent &event)
Definition: mathplot.cpp:2428
mpWindow * plotWindow
Definition: mathplot.h:1711
wxBitmap m_scaledBitmap
Definition: mathplot.h:2006
void GetDataRange(double &minV, double &maxV)
Definition: mathplot.h:733
mpLayer * GetLayer(int position)
Definition: mathplot.cpp:3021
double m_maxX
Definition: mathplot.h:1598
bool m_zooming
Definition: mathplot.h:1537
wxString m_content
Definition: mathplot.h:432
virtual double TransformToPlot(double x) override
Definition: mathplot.cpp:3302
const wxString & GetName() const
Get layer name.
Definition: mathplot.h:239
double GetPosY(void) const
Definition: mathplot.h:1127
int m_marginLeft
Definition: mathplot.h:1523
int m_clickedX
Definition: mathplot.h:1515
mpInfoCoords()
Default constructor.
Definition: mathplot.cpp:212
void RecalculateShape()
Called to update the m_shape_xs, m_shape_ys vectors, whenever a parameter changes.
Definition: mathplot.cpp:3741
virtual bool SetYView(double pos, double desiredMax, double desiredMin)
Applies new Y view coordinates depending on the settings.
Definition: mathplot.cpp:2229
void Rewind() override
Rewind value enumeration with mpFXY::GetNextXY.
Definition: mathplot.cpp:3342
double GetScaleX(void) const
Definition: mathplot.h:1106
double p2x(wxCoord pixelCoordX)
Converts mpWindow (screen) pixel coordinates into graph (floating point) coordinates,...
Definition: mathplot.h:1189
void updateTickLabels(wxDC &dc, mpWindow &w)
Definition: mathplot.cpp:953
double m_desiredXmax
Definition: mathplot.h:1521
bool m_ticks
Definition: mathplot.h:836
virtual void Plot(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:541
double m_offset
Definition: mathplot.h:832
std::vector< double > m_trans_shape_ys
Definition: mathplot.h:1806
void OnScrollLineDown(wxScrollWinEvent &event)
Definition: mathplot.cpp:2952
void computeSlaveTicks(mpWindow &w)
Definition: mathplot.cpp:1044
bool DelLayer(mpLayer *layer, bool alsoDeleteObject=false, bool refreshDisplay=true)
Remove a plot layer from the canvas.
Definition: mathplot.cpp:2489
virtual void SetScale(mpScaleBase *scaleX, mpScaleBase *scaleY)
Definition: mathplot.cpp:4066
bool OnPrintPage(int page) override
Definition: mathplot.cpp:3500
Abstract base class providing plot and labeling functionality for functions F:X->Y.
Definition: mathplot.h:524
void OnZoomOut(wxCommandEvent &event)
Definition: mathplot.cpp:2456
double m_scaleY
Definition: mathplot.h:1510
#define Y_BORDER_SEPARATION
Definition: mathplot.h:96
bool m_enableMouseNavigation
Definition: mathplot.h:1529
double GetScaleY(void) const
Definition: mathplot.h:1113
int m_maxLabelHeight
Definition: mathplot.h:839
int GetMarginBottom()
Definition: mathplot.h:1372
int m_segments
The number of line segments that build up the ellipse.
Definition: mathplot.h:1901
int m_flags
Definition: mathplot.h:834
double m_min_y
Definition: mathplot.h:2013
void OnMouseMiddleDown(wxMouseEvent &event)
Definition: mathplot.cpp:1764
void GetBitmapCopy(wxImage &outBmp) const
Returns a copy of the current bitmap assigned to the layer.
Definition: mathplot.cpp:3881
virtual double TransformToPlot(double x) override
Definition: mathplot.cpp:3314
std::vector< TickLabel > m_tickLabels
Definition: mathplot.h:830
double square(double x)
virtual void Plot(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:1275
Abstract base class providing plot and labeling functionality for functions F:Y->X.
Definition: mathplot.h:651
double m_posX
Definition: mathplot.h:1511
const wxColour & GetAxesColour()
Get axes draw colour.
Definition: mathplot.h:1423
double m_maxY
Definition: mathplot.h:1598
bool m_enableMouseWheelPan
Definition: mathplot.h:1530
bool IsLayerVisible(const wxString &name)
Check whether a layer with given name is visible.
Definition: mathplot.cpp:3157
double y2s(double y) const
Definition: mathplot.cpp:4104
int m_maxLabelWidth
Definition: mathplot.h:840
wxColour m_axColour
Definition: mathplot.h:1503
static int countDecimalDigits(double x, int maxDigits)
wxPoint m_mouseMClick
Definition: mathplot.h:1532
double m_reference_x
The coordinates of the object (orientation "phi" is in radians).
Definition: mathplot.h:1791
double m_minY
Definition: mathplot.h:1507
int m_flags
Definition: mathplot.h:578
#define mpALIGN_RIGHT
Aligns label to the right.
Definition: mathplot.h:478
void SetLayerVisible(const wxString &name, bool viewable)
Sets the visibility of a layer by its name.
Definition: mathplot.cpp:3145
double p2y(wxCoord pixelCoordY)
Converts mpWindow (screen) pixel coordinates into graph (floating point) coordinates,...
Definition: mathplot.h:1194
void OnScrollLineUp(wxScrollWinEvent &event)
Definition: mathplot.cpp:2936
A class providing graphs functionality for a 2D plot (either continuous or a set of points),...
Definition: mathplot.h:1566
virtual void Plot(wxDC &dc, mpWindow &w) override
Plot method.
Definition: mathplot.cpp:155
std::vector< double > m_xs
The internal copy of the set of data to draw.
Definition: mathplot.h:1590
virtual size_t GetCount()=0
mpInfoLayer * IsInsideInfoLayer(wxPoint &point)
Check if a given point is inside the area of a mpInfoLayer and eventually returns its pointer.
Definition: mathplot.cpp:3117
void DoZoomInXCalc(const int staticXpixel)
Definition: mathplot.cpp:2089
bool AddLayer(mpLayer *layer, bool refreshDisplay=true)
Add a plot layer to the canvas.
Definition: mathplot.cpp:2472
void OnSize(wxSizeEvent &event)
Definition: mathplot.cpp:2462
bool GetNextXY(double &x, double &y) override
Get locus value for next N.
Definition: mathplot.cpp:3353
void ZoomInY()
Zoom in current view along Y and refresh display.
Definition: mathplot.cpp:2373
void ZoomOutX()
Zoom out current view along X and refresh display.
Definition: mathplot.cpp:2366
void ZoomOutY()
Zoom out current view along Y and refresh display.
Definition: mathplot.cpp:2380
std::vector< double > m_ys
Definition: mathplot.h:1590
size_t m_index
The internal counter for the "GetNextXY" interface.
Definition: mathplot.h:1594
int tickCount() const
Definition: mathplot.h:801
void ZoomInX()
Zoom in current view along X and refresh display.
Definition: mathplot.cpp:2359
double GetPosX(void) const
Definition: mathplot.h:1120
double m_scaleX
Definition: mathplot.h:1509
wxLayerList m_layers
Definition: mathplot.h:1497
void OnZoomIn(wxCommandEvent &event)
Definition: mathplot.cpp:2450
~mpInfoCoords()
Default destructor.
Definition: mathplot.cpp:222
virtual void Plot(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:626
Abstract base class providing plot and labeling functionality for a locus plot F:N->X,...
Definition: mathplot.h:590
bool m_visible
Definition: mathplot.h:323
void ExtendDataRange(double minV, double maxV)
Definition: mathplot.h:739
#define X_BORDER_SEPARATION
Definition: mathplot.h:95
mpScaleBase * m_scaleY
Definition: mathplot.h:634
void UpdateAll()
Refresh display.
Definition: mathplot.cpp:2820
void DoZoomInYCalc(const int staticYpixel)
Definition: mathplot.cpp:2109
void OnPaint(wxPaintEvent &event)
Definition: mathplot.cpp:2532
wxCoord m_scaledBitmap_offset_x
Definition: mathplot.h:2007
double GetDesiredXmax()
Returns the right-border layer coordinate that the user wants the mpWindow to show (it may be not exa...
Definition: mathplot.h:1309
wxPoint m_mouseLClick
Definition: mathplot.h:1533
#define mpALIGN_BORDER_TOP
Aligns X axis to top border.
Definition: mathplot.h:490
virtual void Move(wxPoint delta)
Moves the layer rectangle of given pixel deltas.
Definition: mathplot.cpp:141
double m_bbox_max_y
Definition: mathplot.h:1811
wxCoord y2p(double y)
Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates,...
Definition: mathplot.h:1204
virtual bool HasBBox() override
Check whether this layer has a bounding box.
Definition: mathplot.h:1761
virtual double GetMaxX()
Get inclusive right border of bounding box.
Definition: mathplot.h:181
void SetPosX(double posX)
Set current view's X position and refresh display.
Definition: mathplot.h:1166
#define mpALIGN_BORDER_LEFT
Aligns Y axis to left border.
Definition: mathplot.h:502
void UpdateScales()
Definition: mathplot.cpp:4076
int m_winY
Definition: mathplot.h:399
double m_minY
Definition: mathplot.h:1598
void computeLabelExtents(wxDC &dc, mpWindow &w)
Definition: mathplot.cpp:935
void SetPosY(double posY)
Set current view's Y position and refresh display.
Definition: mathplot.h:1171
Plot layer implementing a x-scale ruler.
Definition: mathplot.h:694
double m_max_x
Definition: mathplot.h:2013
virtual double TransformFromPlot(double xplot) override
Definition: mathplot.cpp:3323
virtual void recalculateTicks(wxDC &dc, mpWindow &w) override
Definition: mathplot.cpp:833
double m_bbox_min_x
The precomputed bounding box:
Definition: mathplot.h:1811
#define NULL
double m_desiredYmax
Definition: mathplot.h:1521
void SetVisible(bool show)
Sets layer visibility.
Definition: mathplot.h:303
void Refresh()
Update the board display after modifying it by a python script (note: it is automatically called by a...
void OnScrollPageUp(wxScrollWinEvent &event)
Definition: mathplot.cpp:2898
virtual void Plot(wxDC &dc, mpWindow &w) override
Plot given view of layer to the given device context.
Definition: mathplot.cpp:3906
double m_absVisibleMaxV
Definition: mathplot.h:833
int GetMarginTop()
Definition: mathplot.h:1368
void ZoomIn(const wxPoint &centerPoint=wxDefaultPosition)
Zoom into current view and refresh display.
Definition: mathplot.cpp:2243
bool IsVisible()
Checks whether the layer is visible or not.
Definition: mathplot.h:299
void OnScrollBottom(wxScrollWinEvent &event)
Definition: mathplot.cpp:2978
virtual void UpdateInfo(mpWindow &w, wxEvent &event)
Updates the content of the info box.
Definition: mathplot.cpp:130
void SetScaleX(double scaleX)
Set current view's X scale and refresh display.
Definition: mathplot.cpp:2992
wxBrush m_brush
Definition: mathplot.h:398
Base class to create small rectangular info boxes mpInfoLayer is the base class to create a small rec...
Definition: mathplot.h:336
void ZoomRect(wxPoint p0, wxPoint p1)
Zoom view fitting given coordinates to the window (p0 and p1 do not need to be in any specific order)
Definition: mathplot.cpp:2387
wxRect m_zoomRect
Definition: mathplot.h:1538
virtual double GetY(double x)=0
Get function value for argument.
int GetScrX(void) const
Get current view's X dimension in device context units.
Definition: mathplot.h:1135
void OnMouseLeftRelease(wxMouseEvent &event)
Definition: mathplot.cpp:1968
bool m_lockaspect
Definition: mathplot.h:1499
void OnMouseMove(wxMouseEvent &event)
Definition: mathplot.cpp:1845
Plot layer implementing a y-scale ruler.
Definition: mathplot.h:942
void ShapeUpdated()
Must be called by the descendent class after updating the shape (m_shape_xs/ys), or when the transfor...
Definition: mathplot.cpp:3588
wxCoord minDrawY
Definition: mathplot.h:632
virtual double GetMaxY()
Get inclusive top border of bounding box.
Definition: mathplot.h:191
void SetMargins(int top, int right, int bottom, int left)
Set window margins, creating a blank area where some kinds of layers cannot draw.
Definition: mathplot.cpp:3108
void GetBoundingBox(double *bbox)
Returns the bounding box coordinates.
Definition: mathplot.cpp:3041
double m_reference_y
Definition: mathplot.h:1791
virtual void recalculateTicks(wxDC &dc, mpWindow &w) override
Definition: mathplot.cpp:1095
int m_flags
Definition: mathplot.h:1001
void AdjustLimitedView()
Definition: mathplot.cpp:2169
virtual double getLabelPos(int n)
Definition: mathplot.h:819
double m_desiredXmin
These are updated in Fit() only, and may be different from the real borders (layer coordinates) only ...
Definition: mathplot.h:1521
#define mpALIGN_TOP
Aligns label to the top.
Definition: mathplot.h:484
virtual ~mpInfoLayer()
Destructor.
Definition: mathplot.cpp:125
void SetColourTheme(const wxColour &bgColour, const wxColour &drawColour, const wxColour &axesColour)
Set Color theme.
Definition: mathplot.cpp:3185
EVT_MIDDLE_DOWN(mpWindow::OnMouseMiddleDown) EVT_MOUSEWHEEL(mpWindow
Definition: mathplot.cpp:1683
bool CheckYLimits(double &desiredMax, double &desiredMin) const
Definition: mathplot.h:1472
bool m_ticks
Definition: mathplot.h:1002
void DelAllLayers(bool alsoDeleteObject, bool refreshDisplay=true)
Remove all layers from the plot.
Definition: mathplot.cpp:2516
bool m_rangeSet
Definition: mathplot.h:838
mpInfoLayer * m_movingInfoLayer
Definition: mathplot.h:1536
mpInfoLayer()
Default constructor.
Definition: mathplot.cpp:103
wxFont m_font
Definition: mathplot.h:311
virtual void Plot(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:776
#define mpALIGN_NE
Aligns label to north-east.
Definition: mathplot.h:506
int m_flags
Definition: mathplot.h:629
virtual void Plot(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:1492
virtual void UpdateInfo(mpWindow &w, wxEvent &event) override
Updates the content of the info box.
Definition: mathplot.cpp:227
wxColour m_fgColour
Definition: mathplot.h:1502
double m_minV
Definition: mathplot.h:837
int m_last_ly
Definition: mathplot.h:1525
wxBitmap GetColourSquare(int side=16)
Get a small square bitmap filled with the colour of the pen used in the layer.
Definition: mathplot.cpp:83
void OnCenter(wxCommandEvent &event)
Definition: mathplot.cpp:2440
mpLayer * GetLayerByName(const wxString &name)
Definition: mathplot.cpp:3030
unsigned int CountAllLayers()
Counts the number of plot layers, whether or not they have a bounding box.
Definition: mathplot.h:1290
bool HasPage(int page) override
Definition: mathplot.cpp:3568
void LockAspect(bool enable=TRUE)
Enable or disable X/Y scale aspect locking for the view.
Definition: mathplot.cpp:2410
wxRect m_dim
Definition: mathplot.h:393
#define mpALIGNMASK
Definition: mathplot.h:476
void recalculateTicks(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:1205
virtual double TransformFromPlot(double xplot) override
Definition: mathplot.cpp:3296
bool m_drawOutsideMargins
Definition: mathplot.h:321
virtual bool HasBBox() override
Check whether this layer has a bounding box.
Definition: mathplot.h:1975
int GetMarginRight()
Definition: mathplot.h:1370
size_t GetCount() override
Definition: mathplot.cpp:3347
wxPoint m_reference
Definition: mathplot.h:397
int GetMarginLeft()
Definition: mathplot.h:1374
bool m_validImg
Definition: mathplot.h:2009
void TranslatePoint(double x, double y, double &out_x, double &out_y)
A method for 2D translation and rotation, using the current transformation stored in m_reference_x,...
Definition: mathplot.cpp:3577
virtual const wxString getLabel(int n)
Definition: mathplot.h:824
double m_posY
Definition: mathplot.h:1512
#define mpALIGN_BORDER_BOTTOM
Aligns X axis to bottom border.
Definition: mathplot.h:488
void Fit() override
Set view to fit global bounding box of all plot layers and refresh display.
Definition: mathplot.cpp:1998
int m_marginTop
Definition: mathplot.h:1523
double x2s(double x) const
Definition: mathplot.cpp:4098
void UpdateViewBoundary(wxCoord xnew, wxCoord ynew)
Update label positioning data.
Definition: mathplot.cpp:615
const wxRect & GetRectangle()
Returns the current rectangle coordinates.
Definition: mathplot.h:393
virtual double GetMinX()
Get inclusive left border of bounding box.
Definition: mathplot.h:176
virtual bool GetNextXY(double &x, double &y)=0
Get locus value for next N.
void SetMPScrollbars(bool status)
Enable/disable scrollbars.
Definition: mathplot.cpp:2671
double m_scale
Definition: mathplot.h:832
virtual double GetMinY()
Get inclusive bottom border of bounding box.
Definition: mathplot.h:186
#define D(x)
Definition: ptree.cpp:41
wxImage m_bitmap
The internal copy of the Bitmap:
Definition: mathplot.h:2005
int m_flags
Definition: mathplot.h:546
void OnFit(wxCommandEvent &event)
Definition: mathplot.cpp:2434
virtual void UpdateReference()
Updates the rectangle reference point.
Definition: mathplot.cpp:148
bool m_showName
Definition: mathplot.h:320
mpScaleXLog(const wxString &name=wxT("log(X)"), int flags=mpALIGN_CENTER, bool ticks=true, unsigned int type=mpX_NORMAL)
Full constructor.
Definition: mathplot.cpp:1269
virtual double TransformToPlot(double x)
Definition: mathplot.h:775
double m_minX
Definition: mathplot.h:1505
void OnShowPopupMenu(wxMouseEvent &event)
Definition: mathplot.cpp:2420
wxCoord minDrawX
Definition: mathplot.h:632
double m_desiredYmin
Definition: mathplot.h:1521
wxCoord x2p(double x)
Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates,...
Definition: mathplot.h:1199
virtual void formatLabels()
Definition: mathplot.h:812
const char * name
Definition: DXF_plotter.cpp:60
void Clear()
Clears all the data, leaving the layer empty.
Definition: mathplot.cpp:3368
virtual void getVisibleDataRange(mpWindow &w, double &minV, double &maxV) override
Definition: mathplot.cpp:1029
double GetDesiredYmin()
Returns the bottom-border layer coordinate that the user wants the mpWindow to show (it may be not ex...
Definition: mathplot.h:1315
virtual void Plot(wxDC &dc, mpWindow &w) override
Plot given view of layer to the given device context.
Definition: mathplot.cpp:3636
wxCoord m_scaledBitmap_offset_y
Definition: mathplot.h:2007
#define _(s)
Definition: 3d_actions.cpp:33
wxPen m_pen
Definition: mathplot.h:316
void SetScr(int scrX, int scrY)
Set current view's dimensions in device context units.
Definition: mathplot.h:1184
void SetBitmap(const wxImage &inBmp, double x, double y, double lx, double ly)
Change the bitmap associated with the layer (to update the screen, refresh the mpWindow).
Definition: mathplot.cpp:3888
#define mpSCROLL_NUM_PIXELS_PER_LINE
Definition: mathplot.cpp:61
void SetPos(double posX, double posY)
Set current view's X and Y position and refresh display.
Definition: mathplot.h:1177
void DoScrollCalc(const int position, const int orientation)
Definition: mathplot.cpp:2867
virtual void Plot(wxDC &dc, mpWindow &w) override
Plot method.
Definition: mathplot.cpp:312
mpPrintout(mpWindow *drawWindow, const wxChar *title=_T("wxMathPlot print output"))
Definition: mathplot.cpp:3493
~mpInfoLegend()
Default destructor.
Definition: mathplot.cpp:302
virtual void Plot(wxDC &dc, mpWindow &w)=0
Plot given view of layer to the given device context.
std::vector< double > m_shape_ys
Definition: mathplot.h:1801
std::vector< double > m_trans_shape_xs
The buffer for the translated & rotated points (to avoid recomputing them with each mpWindow refresh)...
Definition: mathplot.h:1806
virtual void SetData(const std::vector< double > &xs, const std::vector< double > &ys)
Changes the internal data: the set of points to draw.
Definition: mathplot.cpp:3375
virtual bool HasBBox()
Check whether this layer has a bounding box.
Definition: mathplot.h:162
int m_clickedY
Definition: mathplot.h:1516
Plot layer implementing a text string.
Definition: mathplot.h:1668
virtual bool SetXView(double pos, double desiredMax, double desiredMin)
Applies new X view coordinates depending on the settings.
Definition: mathplot.cpp:2215
void OnMouseLeftDown(wxMouseEvent &event)
Definition: mathplot.cpp:1945
int m_flags
Definition: mathplot.h:673
void DoZoomOutXCalc(const int staticXpixel)
Definition: mathplot.cpp:2129
Canvas for plotting mpLayer implementations.
Definition: mathplot.h:1047
virtual void Rewind()=0
Rewind value enumeration with mpFXY::GetNextXY.
double GetDesiredXmin()
Returns the left-border layer coordinate that the user wants the mpWindow to show (it may be not exac...
Definition: mathplot.h:1303
mpScaleBase * m_scaleX
Definition: mathplot.h:634
double m_minX
Loaded at SetData.
Definition: mathplot.h:1598
mpLayerType m_type
Definition: mathplot.h:322
int m_marginBottom
Definition: mathplot.h:1523
#define mpALIGN_BOTTOM
Aligns label to the bottom.
Definition: mathplot.h:486
mpScaleX(const wxString &name=wxT("X"), int flags=mpALIGN_CENTER, bool ticks=true, unsigned int type=mpX_NORMAL)
Full constructor.
Definition: mathplot.cpp:1263
virtual bool UpdateBBox()
Recalculate global layer bounding box, and save it in m_minX,...
Definition: mathplot.cpp:2712
int m_last_lx
Definition: mathplot.h:1525
#define mpALIGN_CENTER
Aligns label to the center.
Definition: mathplot.h:480
void setPoints(const std::vector< double > &points_xs, const std::vector< double > &points_ys, bool closedShape=true)
Set the points in the polygon.
Definition: mathplot.cpp:3853
unsigned int CountLayers()
Counts the number of plot layers, excluding axes or text: this is to count only the layers which have...
Definition: mathplot.cpp:3003
wxPoint GetPosition()
Returns the position of the upper left corner of the box (in pixels)
Definition: mathplot.cpp:200
wxString m_name
Definition: mathplot.h:318
int m_scrY
Definition: mathplot.h:1514
void OnScrollPageDown(wxScrollWinEvent &event)
Definition: mathplot.cpp:2916
bool m_enableLimitedView
Definition: mathplot.h:1531
double m_reference_phi
Definition: mathplot.h:1791
wxMenu m_popmenu
Definition: mathplot.h:1498
wxCoord maxDrawX
Definition: mathplot.h:632
void OnScrollTop(wxScrollWinEvent &event)
Definition: mathplot.cpp:2972
double m_maxX
Definition: mathplot.h:1506
bool CheckXLimits(double &desiredMax, double &desiredMin) const
Definition: mathplot.h:1465
virtual double TransformFromPlot(double xplot) override
Definition: mathplot.cpp:3308
wxColour m_bgColour
Definition: mathplot.h:1501
bool SaveScreenshot(const wxString &filename, wxBitmapType type=wxBITMAP_TYPE_BMP, wxSize imageSize=wxDefaultSize, bool fit=false)
Draw the window on a wxBitmap, then save it to a file.
Definition: mathplot.cpp:3050
double m_bbox_max_x
Definition: mathplot.h:1811
double s2y(double plotCoordY) const
Definition: mathplot.cpp:4092
void DoZoomOutYCalc(const int staticYpixel)
Definition: mathplot.cpp:2149
int m_nameFlags
Definition: mathplot.h:835
virtual int labelCount() const
Definition: mathplot.h:806
bool m_enableDoubleBuffer
Definition: mathplot.h:1528
double m_cov_00
The elements of the matrix (only 3 since cov(0,1)=cov(1,0) in any positive definite matrix).
Definition: mathplot.h:1896
static double zoomIncrementalFactor
This value sets the zoom steps whenever the user clicks "Zoom in/out" or performs zoom with the mouse...
Definition: mathplot.h:1348
mpScaleY * m_masterScale
Definition: mathplot.h:997
std::vector< double > m_tickValues
Definition: mathplot.h:829
const wxPen & GetPen() const
Get pen set for this layer.
Definition: mathplot.h:249
virtual void Plot(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:464
int m_scrX
Definition: mathplot.h:1513
#define mpLEGEND_MARGIN
Definition: mathplot.cpp:53
wxSize GetSize()
Returns the size of the box (in pixels)
Definition: mathplot.cpp:206
wxBitmap * m_buff_bmp
Definition: mathplot.h:1527
#define mpALIGN_SE
Aligns label to south-east.
Definition: mathplot.h:512
Abstract base class providing plot and labeling functionality for functions F:Y->X.
Definition: mathplot.h:556
double GetDesiredYmax()
Returns the top layer-border coordinate that the user wants the mpWindow to show (it may be not exact...
Definition: mathplot.h:1321
virtual double getTickPos(int n)
Definition: mathplot.h:814
std::vector< double > m_shape_xs
This contains the object points, in local coordinates (to be transformed by the current transformatio...
Definition: mathplot.h:1801
#define mpLEGEND_LINEWIDTH
Definition: mathplot.cpp:54
void OnMouseWheel(wxMouseEvent &event)
Definition: mathplot.cpp:1790
double m_maxY
Definition: mathplot.h:1508
virtual double TransformFromPlot(double xplot)
Definition: mathplot.h:776
#define mpALIGN_BORDER_RIGHT
Aligns Y axis to right border.
Definition: mathplot.h:504
int m_offsety
Definition: mathplot.h:1685
int GetScrY(void) const
Get current view's Y dimension in device context units.
Definition: mathplot.h:1144
double m_min_x
The shape of the bitmap:
Definition: mathplot.h:2013
double m_bbox_min_y
Definition: mathplot.h:1811
virtual void Plot(wxDC &dc, mpWindow &w) override
Text Layer plot handler.
Definition: mathplot.cpp:3464
#define mpALIGN_SW
Aligns label to south-west.
Definition: mathplot.h:510