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 
1584  {
1585  dc.DrawLine( orgx - 4, p, endPx, p );
1586  }
1587  else
1588  {
1590  {
1591  // dc.DrawLine( orgX-4, p, orgx+4, p);
1592  dc.DrawLine( orgx - 4, p, endPx, p );
1593  }
1594  else
1595  {
1596  dc.DrawLine( orgx - 4, p, endPx, p );
1597  // dc.DrawLine( orgx-4/*-w.GetScrX()*/, p, w.GetScrX(), p);
1598  }
1599  }
1600 
1601  m_pen.SetStyle( wxPENSTYLE_SOLID );
1602  dc.SetPen( m_pen );
1603  }
1604 
1605  // Print ticks labels
1606  }
1607  }
1608 
1609  // printf("Y-ticks: %d\n", tickCount());
1610  for( n = 0; n < labelCount(); n++ )
1611  {
1612  // printf("Tick %d\n", n);
1613 
1614  double tp = getLabelPos( n );
1615 
1616  double py = TransformToPlot( tp ); // ( log10 ( tp ) - xlogmin) / (xlogmax - xlogmin);
1617  const int p = (int) ( ( w.GetPosY() - py ) * w.GetScaleY() );
1618 
1619  if( !m_tickLabels[n].visible )
1620  continue;
1621 
1622  if( (p >= minYpx) && (p <= maxYpx) )
1623  {
1624  s = getLabel( n );
1625  dc.GetTextExtent( s, &tx, &ty );
1626 
1628  dc.DrawText( s, orgx + 4, p - ty / 2 );
1629  else
1630  dc.DrawText( s, orgx - 4 - tx, p - ty / 2 ); // ( s, orgx+4, p-ty/2);
1631  }
1632  }
1633 
1634  // Draw axis name
1635  // Draw axis name
1636 
1637  dc.GetTextExtent( m_name, &tx, &ty );
1638 
1639  switch( m_nameFlags )
1640  {
1641  case mpALIGN_BORDER_LEFT:
1642  dc.DrawText( m_name, labelW + 8, 4 );
1643  break;
1644 
1645  case mpALIGN_LEFT:
1646  {
1647  // if ((!m_drawOutsideMargins) && (w.GetMarginLeft() > (ty + labelW + 8))) {
1648  // dc.DrawRotatedText( m_name, orgx - 6 - labelW - ty, (maxYpx + minYpx) / 2 + tx / 2, 90);
1649  // } else {
1650  dc.DrawText( m_name, orgx + 4, minYpx - ty - 4 );
1651  // }
1652  }
1653  break;
1654 
1655  case mpALIGN_CENTER:
1656  dc.DrawText( m_name, orgx + 4, 4 );
1657  break;
1658 
1659  case mpALIGN_RIGHT:
1660  {
1661  // dc.DrawRotatedText( m_name, orgx + 6, (maxYpx + minYpx) / 2 + tx / 2, 90);
1662 
1663  /*if ((!m_drawOutsideMargins) && (w.GetMarginRight() > (ty + labelW + 8))) {
1664  * dc.DrawRotatedText( m_name, orgx + 6 + labelW, (maxYpx - minYpx + tx)>>1, 90);
1665  * } else {*/
1666  dc.DrawText( m_name, orgx - tx - 4, minYpx - ty - 4 );
1667  // }
1668  }
1669  break;
1670 
1671  case mpALIGN_BORDER_RIGHT:
1672  dc.DrawText( m_name, orgx - 6 - tx - labelW, 4 );
1673  break;
1674 
1675  default:
1676  break;
1677  }
1678  }
1679 }
1680 
1681 
1682 // -----------------------------------------------------------------------------
1683 // mpWindow
1684 // -----------------------------------------------------------------------------
1685 
1686 IMPLEMENT_DYNAMIC_CLASS( mpWindow, wxWindow )
1687 
1688 BEGIN_EVENT_TABLE( mpWindow, wxWindow )
1689 EVT_PAINT( mpWindow::OnPaint )
1690 EVT_SIZE( mpWindow::OnSize )
1691 EVT_SCROLLWIN_THUMBTRACK( mpWindow::OnScrollThumbTrack )
1692 EVT_SCROLLWIN_PAGEUP( mpWindow::OnScrollPageUp )
1693 EVT_SCROLLWIN_PAGEDOWN( mpWindow::OnScrollPageDown )
1694 EVT_SCROLLWIN_LINEUP( mpWindow::OnScrollLineUp )
1695 EVT_SCROLLWIN_LINEDOWN( mpWindow::OnScrollLineDown )
1696 EVT_SCROLLWIN_TOP( mpWindow::OnScrollTop )
1697 EVT_SCROLLWIN_BOTTOM( mpWindow::OnScrollBottom )
1698 
1699 EVT_MIDDLE_DOWN( mpWindow::OnMouseMiddleDown ) // JLB
1700 EVT_RIGHT_UP( mpWindow::OnShowPopupMenu )
1701 EVT_MOUSEWHEEL( mpWindow::OnMouseWheel ) // JLB
1702 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
1703 EVT_MAGNIFY( mpWindow::OnMagnify )
1704 #endif
1705 EVT_MOTION( mpWindow::OnMouseMove ) // JLB
1706 EVT_LEFT_DOWN( mpWindow::OnMouseLeftDown )
1707 EVT_LEFT_UP( mpWindow::OnMouseLeftRelease )
1708 
1709 EVT_MENU( mpID_CENTER, mpWindow::OnCenter )
1710 EVT_MENU( mpID_FIT, mpWindow::OnFit )
1711 EVT_MENU( mpID_ZOOM_IN, mpWindow::OnZoomIn )
1714 END_EVENT_TABLE()
1715 
1716 mpWindow::mpWindow( wxWindow* parent,
1717  wxWindowID id,
1718  const wxPoint& pos,
1719  const wxSize& size,
1720  long flag )
1721  : wxWindow( parent, id, pos, size, flag, wxT( "mathplot" ) )
1722 {
1723  m_zooming = false;
1724  m_scaleX = m_scaleY = 1.0;
1725  m_posX = m_posY = 0;
1726  m_desiredXmin = m_desiredYmin = 0;
1727  m_desiredXmax = m_desiredYmax = 1;
1728  m_scrX = m_scrY = 64; // Fixed from m_scrX = m_scrX = 64;
1729  m_minX = m_minY = 0;
1730  m_maxX = m_maxY = 0;
1731  m_last_lx = m_last_ly = 0;
1732  m_buff_bmp = NULL;
1733  m_enableDoubleBuffer = false;
1734  m_enableMouseNavigation = true;
1735  m_enableLimitedView = false;
1736  m_movingInfoLayer = NULL;
1737  // Set margins to 0
1738  m_marginTop = 0; m_marginRight = 0; m_marginBottom = 0; m_marginLeft = 0;
1739 
1740 
1741  m_lockaspect = false;
1742 
1743  m_popmenu.Append( mpID_CENTER, _( "Center" ), _( "Center plot view to this position" ) );
1744  m_popmenu.Append( mpID_FIT, _( "Fit on Screen" ), _( "Set plot view to show all items" ) );
1745  m_popmenu.Append( mpID_ZOOM_IN, _( "Zoom In" ), _( "Zoom in plot view." ) );
1746  m_popmenu.Append( mpID_ZOOM_OUT, _( "Zoom Out" ), _( "Zoom out plot view." ) );
1747  // m_popmenu.AppendCheckItem( mpID_LOCKASPECT, _("Lock aspect"), _("Lock horizontal and vertical zoom aspect."));
1748  // m_popmenu.Append( mpID_HELP_MOUSE, _("Show mouse commands..."), _("Show help about the mouse commands."));
1749 
1750  m_layers.clear();
1751  SetBackgroundColour( *wxWHITE );
1752  m_bgColour = *wxWHITE;
1753  m_fgColour = *wxBLACK;
1754 
1755  m_enableScrollBars = false;
1756  SetSizeHints( 128, 128 );
1757 
1758  // J.L.Blanco: Eliminates the "flick" with the double buffer.
1759  SetBackgroundStyle( wxBG_STYLE_CUSTOM );
1760 
1761  UpdateAll();
1762 }
1763 
1764 
1766 {
1767  // Free all the layers:
1768  DelAllLayers( true, false );
1769 
1770  if( m_buff_bmp )
1771  {
1772  delete m_buff_bmp;
1773  m_buff_bmp = NULL;
1774  }
1775 }
1776 
1777 
1778 // Mouse handler, for detecting when the user drag with the right button or just "clicks" for the menu
1779 // JLB
1780 void mpWindow::OnMouseMiddleDown( wxMouseEvent& event )
1781 {
1782  m_mouseMClick.x = event.GetX();
1783  m_mouseMClick.y = event.GetY();
1784 }
1785 
1786 #if wxCHECK_VERSION( 3, 1, 0 ) || defined( USE_OSX_MAGNIFY_EVENT )
1787 void mpWindow::OnMagnify( wxMouseEvent& event )
1788 {
1790  {
1791  event.Skip();
1792  return;
1793  }
1794 
1795  float zoom = event.GetMagnification() + 1.0f;
1796  wxPoint pos( event.GetX(), event.GetY() );
1797  if( zoom > 1.0f )
1798  ZoomIn( pos, zoom );
1799  else if( zoom < 1.0f )
1800  ZoomOut( pos, 1.0f / zoom );
1801 }
1802 #endif
1803 
1804 // Process mouse wheel events
1805 // JLB
1806 void mpWindow::OnMouseWheel( wxMouseEvent& event )
1807 {
1809  {
1810  event.Skip();
1811  return;
1812  }
1813 
1814  int change = event.GetWheelRotation();
1815  const int axis = event.GetWheelAxis();
1816  double changeUnitsX = change / m_scaleX;
1817  double changeUnitsY = change / m_scaleY;
1818 
1819  if( ( !m_enableMouseWheelPan && ( event.ControlDown() || event.ShiftDown() ) )
1820  || ( m_enableMouseWheelPan && !event.ControlDown() ) )
1821  {
1822  // Scrolling
1823  if( m_enableMouseWheelPan )
1824  {
1825  if( axis == wxMOUSE_WHEEL_HORIZONTAL || event.ShiftDown() )
1826  SetXView( m_posX + changeUnitsX, m_desiredXmax + changeUnitsX,
1827  m_desiredXmin + changeUnitsX );
1828  else
1829  SetYView( m_posY + changeUnitsY, m_desiredYmax + changeUnitsY,
1830  m_desiredYmin + changeUnitsY );
1831  }
1832  else
1833  {
1834  if( event.ControlDown() )
1835  SetXView( m_posX + changeUnitsX, m_desiredXmax + changeUnitsX,
1836  m_desiredXmin + changeUnitsX );
1837  else
1838  SetYView( m_posY + changeUnitsY, m_desiredYmax + changeUnitsY,
1839  m_desiredYmin + changeUnitsY );
1840  }
1841 
1842  UpdateAll();
1843  }
1844  else
1845  {
1846  // zoom in/out
1847  wxPoint clickPt( event.GetX(), event.GetY() );
1848 
1849  if( event.GetWheelRotation() > 0 )
1850  ZoomIn( clickPt );
1851  else
1852  ZoomOut( clickPt );
1853 
1854  return;
1855  }
1856 }
1857 
1858 
1859 // If the user "drags" with the right buttom pressed, do "pan"
1860 // JLB
1861 void mpWindow::OnMouseMove( wxMouseEvent& event )
1862 {
1864  {
1865  event.Skip();
1866  return;
1867  }
1868 
1869  if( event.m_middleDown )
1870  {
1871  // The change:
1872  int Ax = m_mouseMClick.x - event.GetX();
1873  int Ay = m_mouseMClick.y - event.GetY();
1874 
1875  // For the next event, use relative to this coordinates.
1876  m_mouseMClick.x = event.GetX();
1877  m_mouseMClick.y = event.GetY();
1878 
1879  double Ax_units = Ax / m_scaleX;
1880  double Ay_units = -Ay / m_scaleY;
1881 
1882  bool updateRequired = false;
1883  updateRequired |= SetXView( m_posX + Ax_units,
1884  m_desiredXmax + Ax_units,
1885  m_desiredXmin + Ax_units );
1886  updateRequired |= SetYView( m_posY + Ay_units,
1887  m_desiredYmax + Ay_units,
1888  m_desiredYmin + Ay_units );
1889 
1890  if( updateRequired )
1891  UpdateAll();
1892 
1893 #ifdef MATHPLOT_DO_LOGGING
1894  wxLogMessage( "[mpWindow::OnMouseMove] Ax:%i Ay:%i m_posX:%f m_posY:%f",
1895  Ax,
1896  Ay,
1897  m_posX,
1898  m_posY );
1899 #endif
1900  }
1901  else
1902  {
1903  if( event.m_leftDown )
1904  {
1905  if( m_movingInfoLayer == NULL )
1906  {
1907  wxClientDC dc( this );
1908  wxPen pen( m_fgColour, 1, wxPENSTYLE_DOT );
1909  dc.SetPen( pen );
1910  dc.SetBrush( *wxTRANSPARENT_BRUSH );
1911  dc.DrawRectangle( m_mouseLClick.x, m_mouseLClick.y,
1912  event.GetX() - m_mouseLClick.x, event.GetY() - m_mouseLClick.y );
1913  m_zooming = true;
1916  m_zoomRect.width = event.GetX() - m_mouseLClick.x;
1917  m_zoomRect.height = event.GetY() - m_mouseLClick.y;
1918  }
1919  else
1920  {
1921  wxPoint moveVector( event.GetX() - m_mouseLClick.x,
1922  event.GetY() - m_mouseLClick.y );
1923  m_movingInfoLayer->Move( moveVector );
1924  m_zooming = false;
1925  }
1926 
1927  UpdateAll();
1928  }
1929  else
1930  {
1931 #if 0
1932  wxLayerList::iterator li;
1933 
1934  for( li = m_layers.begin(); li != m_layers.end(); li++ )
1935  {
1936  if( (*li)->IsInfo() && (*li)->IsVisible() )
1937  {
1938  mpInfoLayer* tmpLyr = (mpInfoLayer*) (*li);
1939  tmpLyr->UpdateInfo( *this, event );
1940  // UpdateAll();
1941  RefreshRect( tmpLyr->GetRectangle() );
1942  }
1943  }
1944 
1945 #endif
1946  /* if (m_coordTooltip) {
1947  * wxString toolTipContent;
1948  * toolTipContent.Printf( "X = %f\nY = %f", p2x(event.GetX()), p2y(event.GetY()));
1949  * wxTipWindow** ptr = NULL;
1950  * wxRect rectBounds(event.GetX(), event.GetY(), 5, 5);
1951  * wxTipWindow* tip = new wxTipWindow(this, toolTipContent, 100, ptr, &rectBounds);
1952  *
1953  * } */
1954  }
1955  }
1956 
1957  event.Skip();
1958 }
1959 
1960 
1961 void mpWindow::OnMouseLeftDown( wxMouseEvent& event )
1962 {
1963  m_mouseLClick.x = event.GetX();
1964  m_mouseLClick.y = event.GetY();
1965  m_zooming = true;
1966 #ifdef MATHPLOT_DO_LOGGING
1967  wxLogMessage( "mpWindow::OnMouseLeftDown() X = %d , Y = %d", event.GetX(), event.GetY() ); /*m_mouseLClick.x, m_mouseLClick.y);*/
1968 #endif
1969  wxPoint pointClicked = event.GetPosition();
1970  m_movingInfoLayer = IsInsideInfoLayer( pointClicked );
1971 
1972  if( m_movingInfoLayer != NULL )
1973  {
1974 #ifdef MATHPLOT_DO_LOGGING
1975  wxLogMessage( "mpWindow::OnMouseLeftDown() started moving layer %lx",
1976  (long int) m_movingInfoLayer ); /*m_mouseLClick.x, m_mouseLClick.y);*/
1977 #endif
1978  }
1979 
1980  event.Skip();
1981 }
1982 
1983 
1984 void mpWindow::OnMouseLeftRelease( wxMouseEvent& event )
1985 {
1986  wxPoint release( event.GetX(), event.GetY() );
1988 
1989  m_zooming = false;
1990 
1991  if( m_movingInfoLayer != NULL )
1992  {
1995  }
1996  else
1997  {
1998  if( release != press )
1999  {
2000  ZoomRect( press, release );
2001  } /*else {
2002  * if (m_coordTooltip) {
2003  * wxString toolTipContent;
2004  * toolTipContent.Printf( "X = %f\nY = %f", p2x(event.GetX()), p2y(event.GetY()));
2005  * SetToolTip(toolTipContent);
2006  * }
2007  * } */
2008  }
2009 
2010  event.Skip();
2011 }
2012 
2013 
2015 {
2016  if( UpdateBBox() )
2017  Fit( m_minX, m_maxX, m_minY, m_maxY );
2018 }
2019 
2020 
2021 // JL
2022 void mpWindow::Fit( double xMin, double xMax, double yMin, double yMax,
2023  wxCoord* printSizeX, wxCoord* printSizeY )
2024 {
2025  // Save desired borders:
2026  m_desiredXmin = xMin; m_desiredXmax = xMax;
2027  m_desiredYmin = yMin; m_desiredYmax = yMax;
2028 
2029  // Give a small margin to plot area
2030  double xExtra = fabs( xMax - xMin ) * 0.00;
2031  double yExtra = fabs( yMax - yMin ) * 0.03;
2032 
2033  xMin -= xExtra;
2034  xMax += xExtra;
2035  yMin -= yExtra;
2036  yMax += yExtra;
2037 
2038  if( printSizeX!=NULL && printSizeY!=NULL )
2039  {
2040  // Printer:
2041  m_scrX = *printSizeX;
2042  m_scrY = *printSizeY;
2043  }
2044  else
2045  {
2046  // Normal case (screen):
2047  GetClientSize( &m_scrX, &m_scrY );
2048  }
2049 
2050  double Ax, Ay;
2051 
2052  Ax = xMax - xMin;
2053  Ay = yMax - yMin;
2054 
2055  m_scaleX = (Ax!=0) ? (m_scrX - m_marginLeft - m_marginRight) / Ax : 1; // m_scaleX = (Ax!=0) ? m_scrX/Ax : 1;
2056  m_scaleY = (Ay!=0) ? (m_scrY - m_marginTop - m_marginBottom) / Ay : 1; // m_scaleY = (Ay!=0) ? m_scrY/Ay : 1;
2057 
2058  if( m_lockaspect )
2059  {
2060 #ifdef MATHPLOT_DO_LOGGING
2061  wxLogMessage( "mpWindow::Fit()(lock) m_scaleX=%f,m_scaleY=%f", m_scaleX, m_scaleY );
2062 #endif
2063  // Keep the lowest "scale" to fit the whole range required by that axis (to actually "fit"!):
2064  double s = m_scaleX < m_scaleY ? m_scaleX : m_scaleY;
2065  m_scaleX = s;
2066  m_scaleY = s;
2067  }
2068 
2069  // Adjusts corner coordinates: This should be simply:
2070  // m_posX = m_minX;
2071  // m_posY = m_maxY;
2072  // But account for centering if we have lock aspect:
2073  m_posX = (xMin + xMax) / 2 - ( (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft ) /
2074  m_scaleX; // m_posX = (xMin+xMax)/2 - (m_scrX/2)/m_scaleX;
2075  // 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;
2076  m_posY = (yMin + yMax) / 2 + ( (m_scrY - m_marginTop - m_marginBottom) / 2 + m_marginTop ) /
2077  m_scaleY; // m_posY = (yMin+yMax)/2 + (m_scrY/2)/m_scaleY;
2078 
2079 #ifdef MATHPLOT_DO_LOGGING
2080  wxLogMessage(
2081  "mpWindow::Fit() m_desiredXmin=%f m_desiredXmax=%f m_desiredYmin=%f m_desiredYmax=%f",
2082  xMin,
2083  xMax,
2084  yMin,
2085  yMax );
2086  wxLogMessage(
2087  "mpWindow::Fit() m_scaleX = %f , m_scrX = %d,m_scrY=%d, Ax=%f, Ay=%f, m_posX=%f, m_posY=%f",
2088  m_scaleX,
2089  m_scrX,
2090  m_scrY,
2091  Ax,
2092  Ay,
2093  m_posX,
2094  m_posY );
2095 #endif
2096 
2097  // It is VERY IMPORTANT to DO NOT call Refresh if we are drawing to the printer!!
2098  // Otherwise, the DC dimensions will be those of the window instead of the printer device
2099  if( printSizeX==NULL || printSizeY==NULL )
2100  UpdateAll();
2101 }
2102 
2103 
2104 // Patch ngpaton
2105 void mpWindow::DoZoomInXCalc( const int staticXpixel )
2106 {
2107  // Preserve the position of the clicked point:
2108  double staticX = p2x( staticXpixel );
2109 
2110  // Zoom in:
2112  // Adjust the new m_posx
2113  m_posX = staticX - (staticXpixel / m_scaleX);
2114  // Adjust desired
2117 #ifdef MATHPLOT_DO_LOGGING
2118  wxLogMessage(
2119  "mpWindow::DoZoomInXCalc() prior X coord: (%f), new X coord: (%f) SHOULD BE EQUAL!!",
2120  staticX, p2x( staticXpixel ) );
2121 #endif
2122 }
2123 
2124 
2125 void mpWindow::DoZoomInYCalc( const int staticYpixel )
2126 {
2127  // Preserve the position of the clicked point:
2128  double staticY = p2y( staticYpixel );
2129 
2130  // Zoom in:
2132  // Adjust the new m_posy:
2133  m_posY = staticY + (staticYpixel / m_scaleY);
2134  // Adjust desired
2137 #ifdef MATHPLOT_DO_LOGGING
2138  wxLogMessage(
2139  "mpWindow::DoZoomInYCalc() prior Y coord: (%f), new Y coord: (%f) SHOULD BE EQUAL!!",
2140  staticY, p2y( staticYpixel ) );
2141 #endif
2142 }
2143 
2144 
2145 void mpWindow::DoZoomOutXCalc( const int staticXpixel )
2146 {
2147  // Preserve the position of the clicked point:
2148  double staticX = p2x( staticXpixel );
2149 
2150  // Zoom out:
2152  // Adjust the new m_posx/y:
2153  m_posX = staticX - (staticXpixel / m_scaleX);
2154  // Adjust desired
2157 #ifdef MATHPLOT_DO_LOGGING
2158  wxLogMessage(
2159  "mpWindow::DoZoomOutXCalc() prior X coord: (%f), new X coord: (%f) SHOULD BE EQUAL!!",
2160  staticX, p2x( staticXpixel ) );
2161 #endif
2162 }
2163 
2164 
2165 void mpWindow::DoZoomOutYCalc( const int staticYpixel )
2166 {
2167  // Preserve the position of the clicked point:
2168  double staticY = p2y( staticYpixel );
2169 
2170  // Zoom out:
2172  // Adjust the new m_posx/y:
2173  m_posY = staticY + (staticYpixel / m_scaleY);
2174  // Adjust desired
2177 #ifdef MATHPLOT_DO_LOGGING
2178  wxLogMessage(
2179  "mpWindow::DoZoomOutYCalc() prior Y coord: (%f), new Y coord: (%f) SHOULD BE EQUAL!!",
2180  staticY, p2y( staticYpixel ) );
2181 #endif
2182 }
2183 
2184 
2186 {
2187  if( !m_enableLimitedView )
2188  return;
2189 
2190  // m_min and m_max are plot limits for curves
2191  // xMin, xMax, yMin, yMax are the full limits (plot limit + margin)
2192  const double xMin = m_minX - m_marginLeft / m_scaleX;
2193  const double xMax = m_maxX + m_marginRight / m_scaleX;
2194  const double yMin = m_minY - m_marginTop / m_scaleY;
2195  const double yMax = m_maxY + m_marginBottom / m_scaleY;
2196 
2197  if( m_desiredXmin < xMin )
2198  {
2199  double diff = xMin - m_desiredXmin;
2200  m_posX += diff;
2201  m_desiredXmax += diff;
2202  m_desiredXmin = xMin;
2203  }
2204 
2205  if( m_desiredXmax > xMax )
2206  {
2207  double diff = m_desiredXmax - xMax;
2208  m_posX -= diff;
2209  m_desiredXmin -= diff;
2210  m_desiredXmax = xMax;
2211  }
2212 
2213  if( m_desiredYmin < yMin )
2214  {
2215  double diff = yMin - m_desiredYmin;
2216  m_posY += diff;
2217  m_desiredYmax += diff;
2218  m_desiredYmin = yMin;
2219  }
2220 
2221  if( m_desiredYmax > yMax )
2222  {
2223  double diff = m_desiredYmax - yMax;
2224  m_posY -= diff;
2225  m_desiredYmin -= diff;
2226  m_desiredYmax = yMax;
2227  }
2228 }
2229 
2230 
2231 bool mpWindow::SetXView( double pos, double desiredMax, double desiredMin )
2232 {
2233  // if(!CheckXLimits(desiredMax, desiredMin))
2234  // return false;
2235 
2236  m_posX = pos;
2237  m_desiredXmax = desiredMax;
2238  m_desiredXmin = desiredMin;
2240 
2241  return true;
2242 }
2243 
2244 
2245 bool mpWindow::SetYView( double pos, double desiredMax, double desiredMin )
2246 {
2247  // if(!CheckYLimits(desiredMax, desiredMin))
2248  // return false;
2249 
2250  m_posY = pos;
2251  m_desiredYmax = desiredMax;
2252  m_desiredYmin = desiredMin;
2254 
2255  return true;
2256 }
2257 
2258 
2259 void mpWindow::ZoomIn( const wxPoint& centerPoint )
2260 {
2261  ZoomIn( centerPoint, zoomIncrementalFactor );
2262 }
2263 
2264 
2265 void mpWindow::ZoomIn( const wxPoint& centerPoint, double zoomFactor )
2266 {
2267  wxPoint c( centerPoint );
2268 
2269  if( c == wxDefaultPosition )
2270  {
2271  GetClientSize( &m_scrX, &m_scrY );
2272  c.x = (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft; // c.x = m_scrX/2;
2273  c.y = (m_scrY - m_marginTop - m_marginBottom) / 2 - m_marginTop; // c.y = m_scrY/2;
2274  }
2275  else
2276  {
2277  c.x = std::max( c.x, m_marginLeft );
2278  c.x = std::min( c.x, m_scrX - m_marginRight );
2279  c.y = std::max( c.y, m_marginTop );
2280  c.y = std::min( c.y, m_scrY - m_marginBottom );
2281  }
2282 
2283  // Preserve the position of the clicked point:
2284  double prior_layer_x = p2x( c.x );
2285  double prior_layer_y = p2y( c.y );
2286 
2287  // Zoom in:
2288  const double MAX_SCALE = 1e6;
2289  double newScaleX = m_scaleX * zoomFactor;
2290  double newScaleY = m_scaleY * zoomFactor;
2291 
2292  // Baaaaad things happen when you zoom in too much..
2293  if( newScaleX <= MAX_SCALE && newScaleY <= MAX_SCALE )
2294  {
2295  m_scaleX = newScaleX;
2296  m_scaleY = newScaleY;
2297  }
2298  else
2299  {
2300  return;
2301  }
2302 
2303  // Adjust the new m_posx/y:
2304  m_posX = prior_layer_x - c.x / m_scaleX;
2305  m_posY = prior_layer_y + c.y / m_scaleY;
2306 
2308  m_desiredXmax = m_posX + (m_scrX - m_marginLeft - m_marginRight) / m_scaleX; // m_desiredXmax = m_posX + m_scrX / m_scaleX;
2310  m_desiredYmin = m_posY - (m_scrY - m_marginTop - m_marginBottom) / m_scaleY; // m_desiredYmin = m_posY - m_scrY / m_scaleY;
2312 
2313 #ifdef MATHPLOT_DO_LOGGING
2314  wxLogMessage( "mpWindow::ZoomIn() prior coords: (%f,%f), new coords: (%f,%f) SHOULD BE EQUAL!!",
2315  prior_layer_x, prior_layer_y, p2x( c.x ), p2y( c.y ) );
2316 #endif
2317 
2318  UpdateAll();
2319 }
2320 
2321 
2322 void mpWindow::ZoomOut( const wxPoint& centerPoint )
2323 {
2324  ZoomOut( centerPoint, zoomIncrementalFactor );
2325 }
2326 
2327 
2328 void mpWindow::ZoomOut( const wxPoint& centerPoint, double zoomFactor )
2329 {
2330  wxPoint c( centerPoint );
2331 
2332  if( c == wxDefaultPosition )
2333  {
2334  GetClientSize( &m_scrX, &m_scrY );
2335  c.x = (m_scrX - m_marginLeft - m_marginRight) / 2 + m_marginLeft; // c.x = m_scrX/2;
2336  c.y = (m_scrY - m_marginTop - m_marginBottom) / 2 - m_marginTop; // c.y = m_scrY/2;
2337  }
2338 
2339  // Preserve the position of the clicked point:
2340  double prior_layer_x = p2x( c.x );
2341  double prior_layer_y = p2y( c.y );
2342 
2343  // Zoom out:
2344  m_scaleX = m_scaleX / zoomFactor;
2345  m_scaleY = m_scaleY / zoomFactor;
2346 
2347  // Adjust the new m_posx/y:
2348  m_posX = prior_layer_x - c.x / m_scaleX;
2349  m_posY = prior_layer_y + c.y / m_scaleY;
2350 
2352  m_desiredXmax = m_posX + (m_scrX - m_marginLeft - m_marginRight) / m_scaleX; // m_desiredXmax = m_posX + m_scrX / m_scaleX;
2354  m_desiredYmin = m_posY - (m_scrY - m_marginTop - m_marginBottom) / m_scaleY; // m_desiredYmin = m_posY - m_scrY / m_scaleY;
2355 
2356  // printf("desired xmin %.1f ymin %.1f xmax %.1f ymax %.1f l %d\n", m_desiredXmin, m_desiredYmin, m_desiredXmax, m_desiredYmax, !!m_enableLimitedView);
2357  // printf("current xmin %.1f ymin %.1f xmax %.1f ymax %.1f\n", m_minX, m_minY, m_maxX, m_maxY);
2358 
2361  {
2362  // printf("call fit()\n");
2363  Fit();
2364  }
2365 
2366 #ifdef MATHPLOT_DO_LOGGING
2367  wxLogMessage(
2368  "mpWindow::ZoomOut() prior coords: (%f,%f), new coords: (%f,%f) SHOULD BE EQUAL!!",
2369  prior_layer_x, prior_layer_y, p2x( c.x ), p2y( c.y ) );
2370 #endif
2371  UpdateAll();
2372 }
2373 
2374 
2376 {
2378  UpdateAll();
2379 }
2380 
2381 
2383 {
2385  UpdateAll();
2386 }
2387 
2388 
2390 {
2392  UpdateAll();
2393 }
2394 
2395 
2397 {
2399  UpdateAll();
2400 }
2401 
2402 
2404 {
2405  // Compute the 2 corners in graph coordinates:
2406  double p0x = p2x( p0.x );
2407  double p0y = p2y( p0.y );
2408  double p1x = p2x( p1.x );
2409  double p1y = p2y( p1.y );
2410 
2411  // Order them:
2412  double zoom_x_min = p0x<p1x ? p0x : p1x;
2413  double zoom_x_max = p0x>p1x ? p0x : p1x;
2414  double zoom_y_min = p0y<p1y ? p0y : p1y;
2415  double zoom_y_max = p0y>p1y ? p0y : p1y;
2416 
2417 #ifdef MATHPLOT_DO_LOGGING
2418  wxLogMessage( "Zoom: (%f,%f)-(%f,%f)", zoom_x_min, zoom_y_min, zoom_x_max, zoom_y_max );
2419 #endif
2420 
2421  Fit( zoom_x_min, zoom_x_max, zoom_y_min, zoom_y_max );
2423 }
2424 
2425 
2426 void mpWindow::LockAspect( bool enable )
2427 {
2428  m_lockaspect = enable;
2429  m_popmenu.Check( mpID_LOCKASPECT, enable );
2430 
2431  // Try to fit again with the new config:
2433 }
2434 
2435 
2436 void mpWindow::OnShowPopupMenu( wxMouseEvent& event )
2437 {
2438  m_clickedX = event.GetX();
2439  m_clickedY = event.GetY();
2440  PopupMenu( &m_popmenu, event.GetX(), event.GetY() );
2441 }
2442 
2443 
2444 void mpWindow::OnLockAspect( wxCommandEvent& WXUNUSED( event ) )
2445 {
2447 }
2448 
2449 
2450 void mpWindow::OnFit( wxCommandEvent& WXUNUSED( event ) )
2451 {
2452  Fit();
2453 }
2454 
2455 
2456 void mpWindow::OnCenter( wxCommandEvent& WXUNUSED( event ) )
2457 {
2458  GetClientSize( &m_scrX, &m_scrY );
2459  int centerX = (m_scrX - m_marginLeft - m_marginRight) / 2; // + m_marginLeft; // c.x = m_scrX/2;
2460  int centerY = (m_scrY - m_marginTop - m_marginBottom) / 2; // - m_marginTop; // c.y = m_scrY/2;
2461  SetPos( p2x( m_clickedX - centerX ), p2y( m_clickedY - centerY ) );
2462  // 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);
2463 }
2464 
2465 
2466 void mpWindow::OnZoomIn( wxCommandEvent& WXUNUSED( event ) )
2467 {
2469 }
2470 
2471 
2472 void mpWindow::OnZoomOut( wxCommandEvent& WXUNUSED( event ) )
2473 {
2474  ZoomOut();
2475 }
2476 
2477 
2478 void mpWindow::OnSize( wxSizeEvent& WXUNUSED( event ) )
2479 {
2480  // Try to fit again with the new window size:
2482 #ifdef MATHPLOT_DO_LOGGING
2483  wxLogMessage( "mpWindow::OnSize() m_scrX = %d, m_scrY = %d", m_scrX, m_scrY );
2484 #endif // MATHPLOT_DO_LOGGING
2485 }
2486 
2487 
2488 bool mpWindow::AddLayer( mpLayer* layer, bool refreshDisplay )
2489 {
2490  if( layer != NULL )
2491  {
2492  m_layers.push_back( layer );
2493 
2494  if( refreshDisplay )
2495  UpdateAll();
2496 
2497  return true;
2498  }
2499 
2500  ;
2501  return false;
2502 }
2503 
2504 
2506  bool alsoDeleteObject,
2507  bool refreshDisplay )
2508 {
2509  wxLayerList::iterator layIt;
2510 
2511  for( layIt = m_layers.begin(); layIt != m_layers.end(); layIt++ )
2512  {
2513  if( *layIt == layer )
2514  {
2515  // Also delete the object?
2516  if( alsoDeleteObject )
2517  delete *layIt;
2518 
2519  m_layers.erase( layIt ); // this deleted the reference only
2520 
2521  if( refreshDisplay )
2522  UpdateAll();
2523 
2524  return true;
2525  }
2526  }
2527 
2528  return false;
2529 }
2530 
2531 
2532 void mpWindow::DelAllLayers( bool alsoDeleteObject, bool refreshDisplay )
2533 {
2534  while( m_layers.size()>0 )
2535  {
2536  // Also delete the object?
2537  if( alsoDeleteObject )
2538  delete m_layers[0];
2539 
2540  m_layers.erase( m_layers.begin() ); // this deleted the reference only
2541  }
2542 
2543  if( refreshDisplay )
2544  UpdateAll();
2545 }
2546 
2547 
2548 void mpWindow::OnPaint( wxPaintEvent& WXUNUSED( event ) )
2549 {
2550  wxPaintDC dc( this );
2551 
2552  dc.GetSize( &m_scrX, &m_scrY ); // This is the size of the visible area only!
2553 
2554 #ifdef MATHPLOT_DO_LOGGING
2555  wxLogMessage( "[mpWindow::OnPaint] vis.area: x %i y%i", m_scrX, m_scrY );
2556 #endif
2557 
2558  // Selects direct or buffered draw:
2559  wxDC* trgDc;
2560 
2561  // J.L.Blanco @ Aug 2007: Added double buffer support
2562  if( m_enableDoubleBuffer )
2563  {
2564  if( m_last_lx!=m_scrX || m_last_ly!=m_scrY )
2565  {
2566  if( m_buff_bmp )
2567  delete m_buff_bmp;
2568 
2569  m_buff_bmp = new wxBitmap( m_scrX, m_scrY );
2570  m_buff_dc.SelectObject( *m_buff_bmp );
2571  m_last_lx = m_scrX;
2572  m_last_ly = m_scrY;
2573  }
2574 
2575  trgDc = &m_buff_dc;
2576  }
2577  else
2578  {
2579  trgDc = &dc;
2580  }
2581 
2582  // Draw background:
2583  // trgDc->SetDeviceOrigin(0,0);
2584  trgDc->SetPen( *wxTRANSPARENT_PEN );
2585  wxBrush brush( GetBackgroundColour() );
2586  trgDc->SetBrush( brush );
2587  trgDc->SetTextForeground( m_fgColour );
2588  trgDc->DrawRectangle( 0, 0, m_scrX, m_scrY );
2589 
2590  // Draw all the layers:
2591  // trgDc->SetDeviceOrigin( m_scrX>>1, m_scrY>>1); // Origin at the center
2592  wxLayerList::iterator li;
2593 
2594  for( li = m_layers.begin(); li != m_layers.end(); li++ )
2595  {
2596  (*li)->Plot( *trgDc, *this );
2597  }
2598 
2599  ;
2600 
2601  if( m_zooming )
2602  {
2603  wxPen pen( m_fgColour, 1, wxPENSTYLE_DOT );
2604  trgDc->SetPen( pen );
2605  trgDc->SetBrush( *wxTRANSPARENT_BRUSH );
2606  trgDc->DrawRectangle( m_zoomRect );
2607  }
2608 
2609  // If doublebuffer, draw now to the window:
2610  if( m_enableDoubleBuffer )
2611  {
2612  // trgDc->SetDeviceOrigin(0,0);
2613  // dc.SetDeviceOrigin(0,0); // Origin at the center
2614  dc.Blit( 0, 0, m_scrX, m_scrY, trgDc, 0, 0 );
2615  }
2616 
2617  /* if (m_coordTooltip) {
2618  * wxString toolTipContent;
2619  * wxPoint mousePoint = wxGetMousePosition();
2620  * toolTipContent.Printf( "X = %f\nY = %f", p2x(mousePoint.x), p2y(mousePoint.y));
2621  * SetToolTip(toolTipContent);
2622  * }*/
2623  // If scrollbars are enabled, refresh them
2624  if( m_enableScrollBars )
2625  {
2626  /* m_scroll.x = (int) floor((m_posX - m_minX)*m_scaleX);
2627  * m_scroll.y = (int) floor((m_maxY - m_posY )*m_scaleY);
2628  * Scroll(m_scroll.x, m_scroll.y);*/
2629  // Scroll(x2p(m_posX), y2p(m_posY));
2630  // SetVirtualSize((int) ((m_maxX - m_minX)*m_scaleX), (int) ((m_maxY - m_minY)*m_scaleY));
2631  // int centerX = (m_scrX - m_marginLeft - m_marginRight)/2; // + m_marginLeft; // c.x = m_scrX/2;
2632  // int centerY = (m_scrY - m_marginTop - m_marginBottom)/2; // - m_marginTop; // c.y = m_scrY/2;
2633  /*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);
2634  }
2635 }
2636 
2637 
2638 // void mpWindow::OnScroll2(wxScrollWinEvent &event)
2639 // {
2640 // #ifdef MATHPLOT_DO_LOGGING
2641 // wxLogMessage( "[mpWindow::OnScroll2] Init: m_posX=%f m_posY=%f, sc_pos = %d",m_posX,m_posY, event.GetPosition());
2642 // #endif
2644 // if (!m_enableScrollBars) {
2645 // event.Skip();
2646 // return;
2647 // }
2651 //
2654 // int pixelStep = 1;
2655 // if (event.GetOrientation() == wxHORIZONTAL) {
2658 // m_posX -= (m_scroll.x - event.GetPosition())/m_scaleX;
2659 // m_scroll.x = event.GetPosition();
2660 // }
2661 // Fit(m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax);
2677 // #ifdef MATHPLOT_DO_LOGGING
2678 // int px, py;
2679 // GetViewStart( &px, &py);
2680 // wxLogMessage( "[mpWindow::OnScroll2] End: m_posX = %f, m_posY = %f, px = %f, py = %f",m_posX, m_posY, px, py);
2681 // #endif
2682 //
2683 // UpdateAll();
2685 // }
2686 
2687 void mpWindow::SetMPScrollbars( bool status )
2688 {
2689  // Temporary behaviour: always disable scrollbars
2690  m_enableScrollBars = status; // false;
2691 
2692  if( status == false )
2693  {
2694  SetScrollbar( wxHORIZONTAL, 0, 0, 0 );
2695  SetScrollbar( wxVERTICAL, 0, 0, 0 );
2696  }
2697 
2698  // else the scroll bars will be updated in UpdateAll();
2699  UpdateAll();
2700 
2701  // EnableScrolling(false, false);
2702  // m_enableScrollBars = status;
2703  // EnableScrolling(status, status);
2704  /* m_scroll.x = (int) floor((m_posX - m_minX)*m_scaleX);
2705  * m_scroll.y = (int) floor((m_posY - m_minY)*m_scaleY);*/
2706  // int scrollWidth = (int) floor((m_maxX - m_minX)*m_scaleX) - m_scrX;
2707  // int scrollHeight = (int) floor((m_minY - m_maxY)*m_scaleY) - m_scrY;
2708 
2710  // m_scroll.y = (int) floor((m_maxY - m_posY /*- m_minY*/)*m_scaleY);
2711  // int scrollWidth = (int) floor(((m_maxX - m_minX) - (m_desiredXmax - m_desiredXmin))*m_scaleX);
2712  // int scrollHeight = (int) floor(((m_maxY - m_minY) - (m_desiredYmax - m_desiredYmin))*m_scaleY);
2713  // #ifdef MATHPLOT_DO_LOGGING
2714  // wxLogMessage( "mpWindow::SetMPScrollbars() scrollWidth = %d, scrollHeight = %d", scrollWidth, scrollHeight);
2715  // #endif
2716  // if(status) {
2717  // SetScrollbars(1,
2718  // 1,
2719  // scrollWidth,
2720  // scrollHeight,
2721  // m_scroll.x,
2722  // m_scroll.y);
2724  // }
2725  // Refresh(false);*/
2726 }
2727 
2729 {
2730  m_minX = 0.0;
2731  m_maxX = 1.0;
2732  m_minY = 0.0;
2733  m_maxY = 1.0;
2734 
2735  return true;
2736 
2737 #if 0
2738  bool first = true;
2739 
2740  for( wxLayerList::iterator li = m_layers.begin(); li != m_layers.end(); li++ )
2741  {
2742  mpLayer* f = *li;
2743 
2744  if( f->HasBBox() )
2745  {
2746  if( first )
2747  {
2748  first = false;
2749  m_minX = f->GetMinX(); m_maxX = f->GetMaxX();
2750  m_minY = f->GetMinY(); m_maxY = f->GetMaxY();
2751  }
2752  else
2753  {
2754  if( f->GetMinX()<m_minX )
2755  m_minX = f->GetMinX();
2756 
2757  if( f->GetMaxX()>m_maxX )
2758  m_maxX = f->GetMaxX();
2759 
2760  if( f->GetMinY()<m_minY )
2761  m_minY = f->GetMinY();
2762 
2763  if( f->GetMaxY()>m_maxY )
2764  m_maxY = f->GetMaxY();
2765  }
2766  }
2767 
2768  // node = node->GetNext();
2769  }
2770 
2771 #ifdef MATHPLOT_DO_LOGGING
2772  wxLogDebug( wxT(
2773  "[mpWindow::UpdateBBox] Bounding box: Xmin = %f, Xmax = %f, Ymin = %f, YMax = %f" ), m_minX, m_maxX, m_minY,
2774  m_maxY );
2775 #endif // MATHPLOT_DO_LOGGING
2776 
2777  return first == false;
2778 #endif
2779 }
2780 
2781 
2782 // void mpWindow::UpdateAll()
2783 // {
2784 // GetClientSize( &m_scrX,&m_scrY);
2785 /* if (m_enableScrollBars) {
2786  * // The "virtual size" of the scrolled window:
2787  * const int sx = (int)((m_maxX - m_minX) * GetScaleX());
2788  * const int sy = (int)((m_maxY - m_minY) * GetScaleY());
2789  * SetVirtualSize(sx, sy);
2790  * SetScrollRate(1, 1);*/
2791 // const int px = (int)((GetPosX() - m_minX) * GetScaleX());// - m_scrX); //(cx>>1));
2792 
2793 // J.L.Blanco, Aug 2007: Formula fixed:
2794 // const int py = (int)((m_maxY - GetPosY()) * GetScaleY());// - m_scrY); //(cy>>1));
2795 // int px, py;
2796 // GetViewStart(&px0, &py0);
2797 // px = (int)((m_posX - m_minX)*m_scaleX);
2798 // py = (int)((m_maxY - m_posY)*m_scaleY);
2799 
2800 // SetScrollbars( 1, 1, sx - m_scrX, sy - m_scrY, px, py, true);
2801 // }
2802 
2803 // Working code
2804 // UpdateBBox();
2805 // Refresh( false );
2806 // end working code
2807 
2808 // Old version
2809 /* bool box = UpdateBBox();
2810  * if (box)
2811  * {
2812  * int cx, cy;
2813  * GetClientSize( &cx, &cy);
2814  *
2815  * // The "virtual size" of the scrolled window:
2816  * const int sx = (int)((m_maxX - m_minX) * GetScaleX());
2817  * const int sy = (int)((m_maxY - m_minY) * GetScaleY());
2818  *
2819  * const int px = (int)((GetPosX() - m_minX) * GetScaleX() - (cx>>1));
2820  *
2821  * // J.L.Blanco, Aug 2007: Formula fixed:
2822  * const int py = (int)((m_maxY - GetPosY()) * GetScaleY() - (cy>>1));
2823  *
2824  * SetScrollbars( 1, 1, sx, sy, px, py, true);
2825  *
2826  * #ifdef MATHPLOT_DO_LOGGING
2827  * wxLogMessage( "[mpWindow::UpdateAll] Size:%ix%i ScrollBars:%i,%i",sx,sy,px,py);
2828  * #endif
2829  * }
2830  *
2831  * FitInside();
2832  * Refresh( false );
2833  */
2834 // }
2835 
2837 {
2838  if( UpdateBBox() )
2839  {
2840  if( m_enableScrollBars )
2841  {
2842  int cx, cy;
2843  GetClientSize( &cx, &cy );
2844  // Do x scroll bar
2845  {
2846  // Convert margin sizes from pixels to coordinates
2847  double leftMargin = m_marginLeft / m_scaleX;
2848  // Calculate the range in coords that we want to scroll over
2849  double maxX = (m_desiredXmax > m_maxX) ? m_desiredXmax : m_maxX;
2850  double minX = (m_desiredXmin < m_minX) ? m_desiredXmin : m_minX;
2851 
2852  if( (m_posX + leftMargin) < minX )
2853  minX = m_posX + leftMargin;
2854 
2855  // Calculate scroll bar size and thumb position
2856  int sizeX = (int) ( (maxX - minX) * m_scaleX );
2857  int thumbX = (int) ( ( (m_posX + leftMargin) - minX ) * m_scaleX );
2858  SetScrollbar( wxHORIZONTAL, thumbX, cx - (m_marginRight + m_marginLeft), sizeX );
2859  }
2860  // Do y scroll bar
2861  {
2862  // Convert margin sizes from pixels to coordinates
2863  double topMargin = m_marginTop / m_scaleY;
2864  // Calculate the range in coords that we want to scroll over
2865  double maxY = (m_desiredYmax > m_maxY) ? m_desiredYmax : m_maxY;
2866 
2867  if( (m_posY - topMargin) > maxY )
2868  maxY = m_posY - topMargin;
2869 
2870  double minY = (m_desiredYmin < m_minY) ? m_desiredYmin : m_minY;
2871  // Calculate scroll bar size and thumb position
2872  int sizeY = (int) ( (maxY - minY) * m_scaleY );
2873  int thumbY = (int) ( ( maxY - (m_posY - topMargin) ) * m_scaleY );
2874  SetScrollbar( wxVERTICAL, thumbY, cy - (m_marginTop + m_marginBottom), sizeY );
2875  }
2876  }
2877  }
2878 
2879  Refresh( false );
2880 }
2881 
2882 
2883 void mpWindow::DoScrollCalc( const int position, const int orientation )
2884 {
2885  if( orientation == wxVERTICAL )
2886  {
2887  // Y axis
2888  // Get top margin in coord units
2889  double topMargin = m_marginTop / m_scaleY;
2890  // Calculate maximum Y coord to be shown in the graph
2891  double maxY = m_desiredYmax > m_maxY ? m_desiredYmax : m_maxY;
2892  // Set new position
2893  SetPosY( ( maxY - (position / m_scaleY) ) + topMargin );
2894  }
2895  else
2896  {
2897  // X Axis
2898  // Get left margin in coord units
2899  double leftMargin = m_marginLeft / m_scaleX;
2900  // Calculate minimum X coord to be shown in the graph
2901  double minX = (m_desiredXmin < m_minX) ? m_desiredXmin : m_minX;
2902  // Set new position
2903  SetPosX( ( minX + (position / m_scaleX) ) - leftMargin );
2904  }
2905 }
2906 
2907 
2908 void mpWindow::OnScrollThumbTrack( wxScrollWinEvent& event )
2909 {
2910  DoScrollCalc( event.GetPosition(), event.GetOrientation() );
2911 }
2912 
2913 
2914 void mpWindow::OnScrollPageUp( wxScrollWinEvent& event )
2915 {
2916  int scrollOrientation = event.GetOrientation();
2917  // Get position before page up
2918  int position = GetScrollPos( scrollOrientation );
2919  // Get thumb size
2920  int thumbSize = GetScrollThumb( scrollOrientation );
2921 
2922  // Need to adjust position by a page
2923  position -= thumbSize;
2924 
2925  if( position < 0 )
2926  position = 0;
2927 
2928  DoScrollCalc( position, scrollOrientation );
2929 }
2930 
2931 
2932 void mpWindow::OnScrollPageDown( wxScrollWinEvent& event )
2933 {
2934  int scrollOrientation = event.GetOrientation();
2935  // Get position before page up
2936  int position = GetScrollPos( scrollOrientation );
2937  // Get thumb size
2938  int thumbSize = GetScrollThumb( scrollOrientation );
2939  // Get scroll range
2940  int scrollRange = GetScrollRange( scrollOrientation );
2941 
2942  // Need to adjust position by a page
2943  position += thumbSize;
2944 
2945  if( position > (scrollRange - thumbSize) )
2946  position = scrollRange - thumbSize;
2947 
2948  DoScrollCalc( position, scrollOrientation );
2949 }
2950 
2951 
2952 void mpWindow::OnScrollLineUp( wxScrollWinEvent& event )
2953 {
2954  int scrollOrientation = event.GetOrientation();
2955  // Get position before page up
2956  int position = GetScrollPos( scrollOrientation );
2957 
2958  // Need to adjust position by a line
2959  position -= mpSCROLL_NUM_PIXELS_PER_LINE;
2960 
2961  if( position < 0 )
2962  position = 0;
2963 
2964  DoScrollCalc( position, scrollOrientation );
2965 }
2966 
2967 
2968 void mpWindow::OnScrollLineDown( wxScrollWinEvent& event )
2969 {
2970  int scrollOrientation = event.GetOrientation();
2971  // Get position before page up
2972  int position = GetScrollPos( scrollOrientation );
2973  // Get thumb size
2974  int thumbSize = GetScrollThumb( scrollOrientation );
2975  // Get scroll range
2976  int scrollRange = GetScrollRange( scrollOrientation );
2977 
2978  // Need to adjust position by a page
2979  position += mpSCROLL_NUM_PIXELS_PER_LINE;
2980 
2981  if( position > (scrollRange - thumbSize) )
2982  position = scrollRange - thumbSize;
2983 
2984  DoScrollCalc( position, scrollOrientation );
2985 }
2986 
2987 
2988 void mpWindow::OnScrollTop( wxScrollWinEvent& event )
2989 {
2990  DoScrollCalc( 0, event.GetOrientation() );
2991 }
2992 
2993 
2994 void mpWindow::OnScrollBottom( wxScrollWinEvent& event )
2995 {
2996  int scrollOrientation = event.GetOrientation();
2997  // Get thumb size
2998  int thumbSize = GetScrollThumb( scrollOrientation );
2999  // Get scroll range
3000  int scrollRange = GetScrollRange( scrollOrientation );
3001 
3002  DoScrollCalc( scrollRange - thumbSize, scrollOrientation );
3003 }
3004 
3005 
3006 // End patch ngpaton
3007 
3008 void mpWindow::SetScaleX( double scaleX )
3009 {
3010  if( scaleX!=0 )
3011  m_scaleX = scaleX;
3012 
3013  UpdateAll();
3014 }
3015 
3016 
3017 // New methods implemented by Davide Rondini
3018 
3020 {
3021  // wxNode *node = m_layers.GetFirst();
3022  unsigned int layerNo = 0;
3023 
3024  for( wxLayerList::iterator li = m_layers.begin(); li != m_layers.end(); li++ ) // while(node)
3025  {
3026  if( (*li)->HasBBox() )
3027  layerNo++;
3028 
3029  // node = node->GetNext();
3030  }
3031 
3032  ;
3033  return layerNo;
3034 }
3035 
3036 
3037 mpLayer* mpWindow::GetLayer( int position )
3038 {
3039  if( ( position >= (int) m_layers.size() ) || position < 0 )
3040  return NULL;
3041 
3042  return m_layers[position];
3043 }
3044 
3045 
3047 {
3048  for( wxLayerList::iterator it = m_layers.begin(); it!=m_layers.end(); it++ )
3049  if( !(*it)->GetName().Cmp( name ) )
3050  return *it;
3051 
3052 
3053  return NULL; // Not found
3054 }
3055 
3056 
3057 void mpWindow::GetBoundingBox( double* bbox )
3058 {
3059  bbox[0] = m_minX;
3060  bbox[1] = m_maxX;
3061  bbox[2] = m_minY;
3062  bbox[3] = m_maxY;
3063 }
3064 
3065 
3066 bool mpWindow::SaveScreenshot( const wxString& filename, wxBitmapType type,
3067  wxSize imageSize, bool fit )
3068 {
3069  int sizeX, sizeY;
3070  int bk_scrX, bk_scrY;
3071 
3072  if( imageSize == wxDefaultSize )
3073  {
3074  sizeX = m_scrX;
3075  sizeY = m_scrY;
3076  }
3077  else
3078  {
3079  sizeX = imageSize.x;
3080  sizeY = imageSize.y;
3081  bk_scrX = m_scrX;
3082  bk_scrY = m_scrY;
3083  SetScr( sizeX, sizeY );
3084  }
3085 
3086  wxBitmap screenBuffer( sizeX, sizeY );
3087  wxMemoryDC screenDC;
3088  screenDC.SelectObject( screenBuffer );
3089  screenDC.SetPen( *wxWHITE_PEN );
3090  screenDC.SetTextForeground( m_fgColour );
3091  wxBrush brush( GetBackgroundColour() );
3092  screenDC.SetBrush( brush );
3093  screenDC.DrawRectangle( 0, 0, sizeX, sizeY );
3094 
3095  if( fit )
3096  {
3097  Fit( m_minX, m_maxX, m_minY, m_maxY, &sizeX, &sizeY );
3098  }
3099  else
3100  {
3102  }
3103 
3104  // Draw all the layers:
3105  wxLayerList::iterator li;
3106 
3107  for( li = m_layers.begin(); li != m_layers.end(); li++ )
3108  (*li)->Plot( screenDC, *this );
3109 
3110  if( imageSize != wxDefaultSize )
3111  {
3112  // Restore dimensions
3113  SetScr( bk_scrX, bk_scrY );
3114  Fit( m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax, &bk_scrX, &bk_scrY );
3115  UpdateAll();
3116  }
3117 
3118  // Once drawing is complete, actually save screen shot
3119  wxImage screenImage = screenBuffer.ConvertToImage();
3120  return screenImage.SaveFile( filename, type );
3121 }
3122 
3123 
3124 void mpWindow::SetMargins( int top, int right, int bottom, int left )
3125 {
3126  m_marginTop = top;
3127  m_marginRight = right;
3128  m_marginBottom = bottom;
3129  m_marginLeft = left;
3130 }
3131 
3132 
3134 {
3135  wxLayerList::iterator li;
3136 
3137  for( li = m_layers.begin(); li != m_layers.end(); li++ )
3138  {
3139 #ifdef MATHPLOT_DO_LOGGING
3140  wxLogMessage( "mpWindow::IsInsideInfoLayer() examinining layer = %p", (*li) );
3141 #endif // MATHPLOT_DO_LOGGING
3142 
3143  if( (*li)->IsInfo() )
3144  {
3145  mpInfoLayer* tmpLyr = (mpInfoLayer*) (*li);
3146 #ifdef MATHPLOT_DO_LOGGING
3147  wxLogMessage( "mpWindow::IsInsideInfoLayer() layer = %p", (*li) );
3148 #endif // MATHPLOT_DO_LOGGING
3149 
3150  if( tmpLyr->Inside( point ) )
3151  {
3152  return tmpLyr;
3153  }
3154  }
3155  }
3156 
3157  return NULL;
3158 }
3159 
3160 
3161 void mpWindow::SetLayerVisible( const wxString& name, bool viewable )
3162 {
3163  mpLayer* lx = GetLayerByName( name );
3164 
3165  if( lx )
3166  {
3167  lx->SetVisible( viewable );
3168  UpdateAll();
3169  }
3170 }
3171 
3172 
3173 bool mpWindow::IsLayerVisible( const wxString& name )
3174 {
3175  mpLayer* lx = GetLayerByName( name );
3176 
3177  return (lx) ? lx->IsVisible() : false;
3178 }
3179 
3180 
3181 void mpWindow::SetLayerVisible( const unsigned int position, bool viewable )
3182 {
3183  mpLayer* lx = GetLayer( position );
3184 
3185  if( lx )
3186  {
3187  lx->SetVisible( viewable );
3188  UpdateAll();
3189  }
3190 }
3191 
3192 
3193 bool mpWindow::IsLayerVisible( const unsigned int position )
3194 {
3195  mpLayer* lx = GetLayer( position );
3196 
3197  return (lx) ? lx->IsVisible() : false;
3198 }
3199 
3200 
3201 void mpWindow::SetColourTheme( const wxColour& bgColour,
3202  const wxColour& drawColour,
3203  const wxColour& axesColour )
3204 {
3205  SetBackgroundColour( bgColour );
3206  SetForegroundColour( drawColour );
3207  m_bgColour = bgColour;
3208  m_fgColour = drawColour;
3209  m_axColour = axesColour;
3210  // cycle between layers to set colours and properties to them
3211  wxLayerList::iterator li;
3212 
3213  for( li = m_layers.begin(); li != m_layers.end(); li++ )
3214  {
3215  if( (*li)->GetLayerType() == mpLAYER_AXIS )
3216  {
3217  wxPen axisPen = (*li)->GetPen(); // Get the old pen to modify only colour, not style or width
3218  axisPen.SetColour( axesColour );
3219  (*li)->SetPen( axisPen );
3220  }
3221 
3222  if( (*li)->GetLayerType() == mpLAYER_INFO )
3223  {
3224  wxPen infoPen = (*li)->GetPen(); // Get the old pen to modify only colour, not style or width
3225  infoPen.SetColour( drawColour );
3226  (*li)->SetPen( infoPen );
3227  }
3228  }
3229 }
3230 
3231 
3232 // void mpWindow::EnableCoordTooltip(bool value)
3233 // {
3234 // m_coordTooltip = value;
3236 // }
3237 
3238 /*
3239  * double mpWindow::p2x(wxCoord pixelCoordX, bool drawOutside )
3240  * {
3241  * if (drawOutside) {
3242  * return m_posX + pixelCoordX/m_scaleX;
3243  * }
3244  * // Draw inside margins
3245  * double marginScaleX = ((double)(m_scrX - m_marginLeft - m_marginRight))/m_scrX;
3246  * return m_marginLeft + (m_posX + pixelCoordX/m_scaleX)/marginScaleX;
3247  * }
3248  *
3249  * double mpWindow::p2y(wxCoord pixelCoordY, bool drawOutside )
3250  * {
3251  * if (drawOutside) {
3252  * return m_posY - pixelCoordY/m_scaleY;
3253  * }
3254  * // Draw inside margins
3255  * double marginScaleY = ((double)(m_scrY - m_marginTop - m_marginBottom))/m_scrY;
3256  * return m_marginTop + (m_posY - pixelCoordY/m_scaleY)/marginScaleY;
3257  * }
3258  *
3259  * wxCoord mpWindow::x2p(double x, bool drawOutside)
3260  * {
3261  * if (drawOutside) {
3262  * return (wxCoord) ((x-m_posX) * m_scaleX);
3263  * }
3264  * // Draw inside margins
3265  * double marginScaleX = ((double)(m_scrX - m_marginLeft - m_marginRight))/m_scrX;
3266  * #ifdef MATHPLOT_DO_LOGGING
3267  * wxLogMessage(wxT("x2p ScrX = %d, marginRight = %d, marginLeft = %d, marginScaleX = %f"), m_scrX, m_marginRight, m_marginLeft, marginScaleX);
3268  * #endif // MATHPLOT_DO_LOGGING
3269  * return (wxCoord) (int)(((x-m_posX) * m_scaleX)*marginScaleX) - m_marginLeft;
3270  * }
3271  *
3272  * wxCoord mpWindow::y2p(double y, bool drawOutside)
3273  * {
3274  * if (drawOutside) {
3275  * return (wxCoord) ( (m_posY-y) * m_scaleY);
3276  * }
3277  * // Draw inside margins
3278  * double marginScaleY = ((double)(m_scrY - m_marginTop - m_marginBottom))/m_scrY;
3279  * #ifdef MATHPLOT_DO_LOGGING
3280  * wxLogMessage(wxT("y2p ScrY = %d, marginTop = %d, marginBottom = %d, marginScaleY = %f"), m_scrY, m_marginTop, m_marginBottom, marginScaleY);
3281  * #endif // MATHPLOT_DO_LOGGING
3282  * return (wxCoord) ((int)((m_posY-y) * m_scaleY)*marginScaleY) - m_marginTop;
3283  * }
3284  */
3285 
3286 
3287 // -----------------------------------------------------------------------------
3288 // mpFXYVector implementation - by Jose Luis Blanco (AGO-2007)
3289 // -----------------------------------------------------------------------------
3290 
3291 IMPLEMENT_DYNAMIC_CLASS( mpFXYVector, mpFXY )
3292 
3293 // Constructor
3294 mpFXYVector::mpFXYVector( const wxString& name, int flags ) : mpFXY( name, flags )
3295 {
3296  m_index = 0;
3297  // printf("FXYVector::FXYVector!\n");
3298  m_minX = -1;
3299  m_maxX = 1;
3300  m_minY = -1;
3301  m_maxY = 1;
3302  m_type = mpLAYER_PLOT;
3303 }
3304 
3305 
3306 double mpScaleX::TransformToPlot( double x )
3307 {
3308  return (x + m_offset) * m_scale;
3309 }
3310 
3311 
3312 double mpScaleX::TransformFromPlot( double xplot )
3313 {
3314  return xplot / m_scale - m_offset;
3315 }
3316 
3317 
3318 double mpScaleY::TransformToPlot( double x )
3319 {
3320  return (x + m_offset) * m_scale;
3321 }
3322 
3323 
3324 double mpScaleY::TransformFromPlot( double xplot )
3325 {
3326  return xplot / m_scale - m_offset;
3327 }
3328 
3329 
3331 {
3332  double xlogmin = log10( m_minV );
3333  double xlogmax = log10( m_maxV );
3334 
3335  return ( log10( x ) - xlogmin) / (xlogmax - xlogmin);
3336 }
3337 
3338 
3339 double mpScaleXLog::TransformFromPlot( double xplot )
3340 {
3341  double xlogmin = log10( m_minV );
3342  double xlogmax = log10( m_maxV );
3343 
3344  return pow( 10.0, xplot * (xlogmax - xlogmin) + xlogmin );
3345 }
3346 
3347 
3348 #if 0
3349 mpFSemiLogXVector::mpFSemiLogXVector( wxString name, int flags ) :
3350  mpFXYVector( name, flags )
3351 {
3352 }
3353 
3354 
3355 IMPLEMENT_DYNAMIC_CLASS( mpFSemiLogXVector, mpFXYVector )
3356 #endif
3357 
3359 {
3360  m_index = 0;
3361 }
3362 
3364 {
3365  return m_xs.size();
3366 }
3367 
3368 
3369 bool mpFXYVector::GetNextXY( double& x, double& y )
3370 {
3371  if( m_index >= m_xs.size() )
3372  {
3373  return false;
3374  }
3375  else
3376  {
3377  x = m_xs[m_index];
3378  y = m_ys[m_index++];
3379  return m_index <= m_xs.size();
3380  }
3381 }
3382 
3383 
3385 {
3386  m_xs.clear();
3387  m_ys.clear();
3388 }
3389 
3390 
3391 void mpFXYVector::SetData( const std::vector<double>& xs, const std::vector<double>& ys )
3392 {
3393  // Check if the data vectora are of the same size
3394  if( xs.size() != ys.size() )
3395  {
3396  wxLogError( "wxMathPlot error: X and Y vector are not of the same length!" );
3397  return;
3398  }
3399 
3400  // Copy the data:
3401  m_xs = xs;
3402  m_ys = ys;
3403 
3404  // printf("FXYVector::setData %d %d\n", xs.size(), ys.size());
3405 
3406  // Update internal variables for the bounding box.
3407  if( xs.size()>0 )
3408  {
3409  m_minX = xs[0];
3410  m_maxX = xs[0];
3411  m_minY = ys[0];
3412  m_maxY = ys[0];
3413 
3414  std::vector<double>::const_iterator it;
3415 
3416  for( it = xs.begin(); it!=xs.end(); it++ )
3417  {
3418  if( *it<m_minX )
3419  m_minX = *it;
3420 
3421  if( *it>m_maxX )
3422  m_maxX = *it;
3423  }
3424 
3425  for( it = ys.begin(); it!=ys.end(); it++ )
3426  {
3427  if( *it<m_minY )
3428  m_minY = *it;
3429 
3430  if( *it>m_maxY )
3431  m_maxY = *it;
3432  }
3433 
3434  // printf("minX %.10f maxX %.10f\n ", m_minX, m_maxX );
3435  // printf("minY %.10f maxY %.10f\n ", m_minY, m_maxY );
3436  }
3437  else
3438  {
3439  m_minX = -1;
3440  m_maxX = 1;
3441  m_minY = -1;
3442  m_maxY = 1;
3443  }
3444 }
3445 
3446 
3447 // -----------------------------------------------------------------------------
3448 // mpText - provided by Val Greene
3449 // -----------------------------------------------------------------------------
3450 
3451 IMPLEMENT_DYNAMIC_CLASS( mpText, mpLayer )
3452 
3453 
3454 
3458 mpText::mpText( const wxString& name, int offsetx, int offsety )
3459 {
3460  SetName( name );
3461 
3462  if( offsetx >= 0 && offsetx <= 100 )
3463  m_offsetx = offsetx;
3464  else
3465  m_offsetx = 5;
3466 
3467  if( offsety >= 0 && offsety <= 100 )
3468  m_offsety = offsety;
3469  else
3470  m_offsety = 50;
3471 
3472  m_type = mpLAYER_INFO;
3473 }
3474 
3475 
3480 void mpText::Plot( wxDC& dc, mpWindow& w )
3481 {
3482  if( m_visible )
3483  {
3484  dc.SetPen( m_pen );
3485  dc.SetFont( m_font );
3486 
3487  wxCoord tw = 0, th = 0;
3488  dc.GetTextExtent( GetName(), &tw, &th );
3489 
3490  // int left = -dc.LogicalToDeviceX(0);
3491  // int width = dc.LogicalToDeviceX(0) - left;
3492  // int bottom = dc.LogicalToDeviceY(0);
3493  // int height = bottom - -dc.LogicalToDeviceY(0);
3494 
3495  /* dc.DrawText( GetName(),
3496  * (int)((((float)width/100.0) * m_offsety) + left - (tw/2)),
3497  * (int)((((float)height/100.0) * m_offsetx) - bottom) );*/
3498  int px = m_offsetx * ( w.GetScrX() - w.GetMarginLeft() - w.GetMarginRight() ) / 100;
3499  int py = m_offsety * ( w.GetScrY() - w.GetMarginTop() - w.GetMarginBottom() ) / 100;
3500  dc.DrawText( GetName(), px, py );
3501  }
3502 }
3503 
3504 
3505 // -----------------------------------------------------------------------------
3506 // mpPrintout - provided by Davide Rondini
3507 // -----------------------------------------------------------------------------
3508 
3509 mpPrintout::mpPrintout( mpWindow* drawWindow, const wxChar* title ) : wxPrintout( title )
3510 {
3511  drawn = false;
3512  plotWindow = drawWindow;
3513 }
3514 
3515 
3516 bool mpPrintout::OnPrintPage( int page )
3517 {
3518  wxDC* trgDc = GetDC();
3519 
3520  if( (trgDc) && (page == 1) )
3521  {
3522  wxCoord m_prnX, m_prnY;
3523  int marginX = 50;
3524  int marginY = 50;
3525  trgDc->GetSize( &m_prnX, &m_prnY );
3526 
3527  m_prnX -= (2 * marginX);
3528  m_prnY -= (2 * marginY);
3529  trgDc->SetDeviceOrigin( marginX, marginY );
3530 
3531 #ifdef MATHPLOT_DO_LOGGING
3532  wxLogMessage( wxT( "Print Size: %d x %d\n" ), m_prnX, m_prnY );
3533  wxLogMessage( wxT( "Screen Size: %d x %d\n" ), plotWindow->GetScrX(),
3534  plotWindow->GetScrY() );
3535 #endif
3536 
3537  // Set the scale according to the page:
3538  plotWindow->Fit(
3543  &m_prnX,
3544  &m_prnY );
3545 
3546  // Get the colours of the plotWindow to restore them ath the end
3547  wxColour oldBgColour = plotWindow->GetBackgroundColour();
3548  wxColour oldFgColour = plotWindow->GetForegroundColour();
3549  wxColour oldAxColour = plotWindow->GetAxesColour();
3550 
3551  // Draw background, ensuring to use white background for printing.
3552  trgDc->SetPen( *wxTRANSPARENT_PEN );
3553  // wxBrush brush( plotWindow->GetBackgroundColour() );
3554  wxBrush brush = *wxWHITE_BRUSH;
3555  trgDc->SetBrush( brush );
3556  trgDc->DrawRectangle( 0, 0, m_prnX, m_prnY );
3557 
3558  // Draw all the layers:
3559  // trgDc->SetDeviceOrigin( m_prnX>>1, m_prnY>>1); // Origin at the center
3560  mpLayer* layer;
3561 
3562  for( unsigned int li = 0; li < plotWindow->CountAllLayers(); li++ )
3563  {
3564  layer = plotWindow->GetLayer( li );
3565  layer->Plot( *trgDc, *plotWindow );
3566  }
3567 
3568  ;
3569  // Restore device origin
3570  // trgDc->SetDeviceOrigin(0, 0);
3571  // Restore colours
3572  plotWindow->SetColourTheme( oldBgColour, oldFgColour, oldAxColour );
3573  // Restore drawing
3577  plotWindow->UpdateAll();
3578  }
3579 
3580  return true;
3581 }
3582 
3583 
3584 bool mpPrintout::HasPage( int page )
3585 {
3586  return page == 1;
3587 }
3588 
3589 
3590 // -----------------------------------------------------------------------------
3591 // mpMovableObject - provided by Jose Luis Blanco
3592 // -----------------------------------------------------------------------------
3593 void mpMovableObject::TranslatePoint( double x, double y, double& out_x, double& out_y )
3594 {
3595  double ccos = cos( m_reference_phi ); // Avoid computing cos/sin twice.
3596  double csin = sin( m_reference_phi );
3597 
3598  out_x = m_reference_x + ccos * x - csin * y;
3599  out_y = m_reference_y + csin * x + ccos * y;
3600 }
3601 
3602 
3603 // This method updates the buffers m_trans_shape_xs/ys, and the precomputed bounding box.
3605 {
3606  // Just in case...
3607  if( m_shape_xs.size()!=m_shape_ys.size() )
3608  {
3609  wxLogError( wxT(
3610  "[mpMovableObject::ShapeUpdated] Error, m_shape_xs and m_shape_ys have different lengths!" ) );
3611  }
3612  else
3613  {
3614  double ccos = cos( m_reference_phi ); // Avoid computing cos/sin twice.
3615  double csin = sin( m_reference_phi );
3616 
3617  m_trans_shape_xs.resize( m_shape_xs.size() );
3618  m_trans_shape_ys.resize( m_shape_xs.size() );
3619 
3620  std::vector<double>::iterator itXi, itXo;
3621  std::vector<double>::iterator itYi, itYo;
3622 
3623  m_bbox_min_x = 1e300;
3624  m_bbox_max_x = -1e300;
3625  m_bbox_min_y = 1e300;
3626  m_bbox_max_y = -1e300;
3627 
3628  for( itXo = m_trans_shape_xs.begin(),
3629  itYo = m_trans_shape_ys.begin(), itXi = m_shape_xs.begin(), itYi = m_shape_ys.begin();
3630  itXo!=m_trans_shape_xs.end(); itXo++, itYo++, itXi++, itYi++ )
3631  {
3632  *itXo = m_reference_x + ccos * (*itXi) - csin * (*itYi);
3633  *itYo = m_reference_y + csin * (*itXi) + ccos * (*itYi);
3634 
3635  // Keep BBox:
3636  if( *itXo < m_bbox_min_x )
3637  m_bbox_min_x = *itXo;
3638 
3639  if( *itXo > m_bbox_max_x )
3640  m_bbox_max_x = *itXo;
3641 
3642  if( *itYo < m_bbox_min_y )
3643  m_bbox_min_y = *itYo;
3644 
3645  if( *itYo > m_bbox_max_y )
3646  m_bbox_max_y = *itYo;
3647  }
3648  }
3649 }
3650 
3651 
3652 void mpMovableObject::Plot( wxDC& dc, mpWindow& w )
3653 {
3654  if( m_visible )
3655  {
3656  dc.SetPen( m_pen );
3657 
3658 
3659  std::vector<double>::iterator itX = m_trans_shape_xs.begin();
3660  std::vector<double>::iterator itY = m_trans_shape_ys.begin();
3661 
3662  if( !m_continuous )
3663  {
3664  // for some reason DrawPoint does not use the current pen,
3665  // so we use DrawLine for fat pens
3666  if( m_pen.GetWidth() <= 1 )
3667  {
3668  while( itX!=m_trans_shape_xs.end() )
3669  {
3670  dc.DrawPoint( w.x2p( *(itX++) ), w.y2p( *(itY++) ) );
3671  }
3672  }
3673  else
3674  {
3675  while( itX!=m_trans_shape_xs.end() )
3676  {
3677  wxCoord cx = w.x2p( *(itX++) );
3678  wxCoord cy = w.y2p( *(itY++) );
3679  dc.DrawLine( cx, cy, cx, cy );
3680  }
3681  }
3682  }
3683  else
3684  {
3685  wxCoord cx0 = 0, cy0 = 0;
3686  bool first = true;
3687 
3688  while( itX!=m_trans_shape_xs.end() )
3689  {
3690  wxCoord cx = w.x2p( *(itX++) );
3691  wxCoord cy = w.y2p( *(itY++) );
3692 
3693  if( first )
3694  {
3695  first = false;
3696  cx0 = cx; cy0 = cy;
3697  }
3698 
3699  dc.DrawLine( cx0, cy0, cx, cy );
3700  cx0 = cx; cy0 = cy;
3701  }
3702  }
3703 
3704  if( !m_name.IsEmpty() && m_showName )
3705  {
3706  dc.SetFont( m_font );
3707 
3708  wxCoord tx, ty;
3709  dc.GetTextExtent( m_name, &tx, &ty );
3710 
3711  if( HasBBox() )
3712  {
3713  wxCoord sx = (wxCoord) ( ( m_bbox_max_x - w.GetPosX() ) * w.GetScaleX() );
3714  wxCoord sy = (wxCoord) ( (w.GetPosY() - m_bbox_max_y ) * w.GetScaleY() );
3715 
3716  tx = sx - tx - 8;
3717  ty = sy - 8 - ty;
3718  }
3719  else
3720  {
3721  const int sx = w.GetScrX() >> 1;
3722  const int sy = w.GetScrY() >> 1;
3723 
3724  if( (m_flags & mpALIGNMASK) == mpALIGN_NE )
3725  {
3726  tx = sx - tx - 8;
3727  ty = -sy + 8;
3728  }
3729  else if( (m_flags & mpALIGNMASK) == mpALIGN_NW )
3730  {
3731  tx = -sx + 8;
3732  ty = -sy + 8;
3733  }
3734  else if( (m_flags & mpALIGNMASK) == mpALIGN_SW )
3735  {
3736  tx = -sx + 8;
3737  ty = sy - 8 - ty;
3738  }
3739  else
3740  {
3741  tx = sx - tx - 8;
3742  ty = sy - 8 - ty;
3743  }
3744  }
3745 
3746  dc.DrawText( m_name, tx, ty );
3747  }
3748  }
3749 }
3750 
3751 
3752 // -----------------------------------------------------------------------------
3753 // mpCovarianceEllipse - provided by Jose Luis Blanco
3754 // -----------------------------------------------------------------------------
3755 
3756 // Called to update the m_shape_xs, m_shape_ys vectors, whenever a parameter changes.
3758 {
3759  m_shape_xs.clear();
3760  m_shape_ys.clear();
3761 
3762  // Preliminar checks:
3763  if( m_quantiles<0 )
3764  {
3765  wxLogError( wxT( "[mpCovarianceEllipse] Error: quantiles must be non-negative" ) ); return;
3766  }
3767 
3768  if( m_cov_00<0 )
3769  {
3770  wxLogError( wxT( "[mpCovarianceEllipse] Error: cov(0,0) must be non-negative" ) ); return;
3771  }
3772 
3773  if( m_cov_11<0 )
3774  {
3775  wxLogError( wxT( "[mpCovarianceEllipse] Error: cov(1,1) must be non-negative" ) ); return;
3776  }
3777 
3778  m_shape_xs.resize( m_segments, 0 );
3779  m_shape_ys.resize( m_segments, 0 );
3780 
3781  // Compute the two eigenvalues of the covariance:
3782  // -------------------------------------------------
3783  double b = -m_cov_00 - m_cov_11;
3784  double c = m_cov_00 * m_cov_11 - m_cov_01 * m_cov_01;
3785 
3786  double D = b * b - 4 * c;
3787 
3788  if( D<0 )
3789  {
3790  wxLogError( wxT( "[mpCovarianceEllipse] Error: cov is not positive definite" ) ); return;
3791  }
3792 
3793  double eigenVal0 = 0.5 * ( -b + sqrt( D ) );
3794  double eigenVal1 = 0.5 * ( -b - sqrt( D ) );
3795 
3796  // Compute the two corresponding eigenvectors:
3797  // -------------------------------------------------
3798  double eigenVec0_x, eigenVec0_y;
3799  double eigenVec1_x, eigenVec1_y;
3800 
3801  if( fabs( eigenVal0 - m_cov_00 )>1e-6 )
3802  {
3803  double k1x = m_cov_01 / ( eigenVal0 - m_cov_00 );
3804  eigenVec0_y = 1;
3805  eigenVec0_x = eigenVec0_y * k1x;
3806  }
3807  else
3808  {
3809  double k1y = m_cov_01 / ( eigenVal0 - m_cov_11 );
3810  eigenVec0_x = 1;
3811  eigenVec0_y = eigenVec0_x * k1y;
3812  }
3813 
3814  if( fabs( eigenVal1 - m_cov_00 )>1e-6 )
3815  {
3816  double k2x = m_cov_01 / ( eigenVal1 - m_cov_00 );
3817  eigenVec1_y = 1;
3818  eigenVec1_x = eigenVec1_y * k2x;
3819  }
3820  else
3821  {
3822  double k2y = m_cov_01 / ( eigenVal1 - m_cov_11 );
3823  eigenVec1_x = 1;
3824  eigenVec1_y = eigenVec1_x * k2y;
3825  }
3826 
3827  // Normalize the eigenvectors:
3828  double len = sqrt( eigenVec0_x * eigenVec0_x + eigenVec0_y * eigenVec0_y );
3829  eigenVec0_x /= len; // It *CANNOT* be zero
3830  eigenVec0_y /= len;
3831 
3832  len = sqrt( eigenVec1_x * eigenVec1_x + eigenVec1_y * eigenVec1_y );
3833  eigenVec1_x /= len; // It *CANNOT* be zero
3834  eigenVec1_y /= len;
3835 
3836 
3837  // Take the sqrt of the eigenvalues (required for the ellipse scale):
3838  eigenVal0 = sqrt( eigenVal0 );
3839  eigenVal1 = sqrt( eigenVal1 );
3840 
3841  // Compute the 2x2 matrix M = diag(eigVal) * (~eigVec) (each eigen vector is a row):
3842  double M_00 = eigenVec0_x * eigenVal0;
3843  double M_01 = eigenVec0_y * eigenVal0;
3844 
3845  double M_10 = eigenVec1_x * eigenVal1;
3846  double M_11 = eigenVec1_y * eigenVal1;
3847 
3848  // The points of the 2D ellipse:
3849  double ang;
3850  double Aang = 6.283185308 / (m_segments - 1);
3851  int i;
3852 
3853  for( i = 0, ang = 0; i<m_segments; i++, ang += Aang )
3854  {
3855  double ccos = cos( ang );
3856  double csin = sin( ang );
3857 
3858  m_shape_xs[i] = m_quantiles * (ccos * M_00 + csin * M_10 );
3859  m_shape_ys[i] = m_quantiles * (ccos * M_01 + csin * M_11 );
3860  } // end for points on ellipse
3861 
3862  ShapeUpdated();
3863 }
3864 
3865 
3866 // -----------------------------------------------------------------------------
3867 // mpPolygon - provided by Jose Luis Blanco
3868 // -----------------------------------------------------------------------------
3869 void mpPolygon::setPoints( const std::vector<double>& points_xs,
3870  const std::vector<double>& points_ys,
3871  bool closedShape )
3872 {
3873  if( points_xs.size()!=points_ys.size() )
3874  {
3875  wxLogError( wxT(
3876  "[mpPolygon] Error: points_xs and points_ys must have the same number of elements" ) );
3877  }
3878  else
3879  {
3880  m_shape_xs = points_xs;
3881  m_shape_ys = points_ys;
3882 
3883  if( closedShape && points_xs.size() )
3884  {
3885  m_shape_xs.push_back( points_xs[0] );
3886  m_shape_ys.push_back( points_ys[0] );
3887  }
3888 
3889  ShapeUpdated();
3890  }
3891 }
3892 
3893 
3894 // -----------------------------------------------------------------------------
3895 // mpBitmapLayer - provided by Jose Luis Blanco
3896 // -----------------------------------------------------------------------------
3897 void mpBitmapLayer::GetBitmapCopy( wxImage& outBmp ) const
3898 {
3899  if( m_validImg )
3900  outBmp = m_bitmap;
3901 }
3902 
3903 
3904 void mpBitmapLayer::SetBitmap( const wxImage& inBmp, double x, double y, double lx, double ly )
3905 {
3906  if( !inBmp.Ok() )
3907  {
3908  wxLogError( wxT( "[mpBitmapLayer] Assigned bitmap is not Ok()!" ) );
3909  }
3910  else
3911  {
3912  m_bitmap = inBmp; // .GetSubBitmap( wxRect(0, 0, inBmp.GetWidth(), inBmp.GetHeight()));
3913  m_min_x = x;
3914  m_min_y = y;
3915  m_max_x = x + lx;
3916  m_max_y = y + ly;
3917  m_validImg = true;
3918  }
3919 }
3920 
3921 
3922 void mpBitmapLayer::Plot( wxDC& dc, mpWindow& w )
3923 {
3924  if( m_visible && m_validImg )
3925  {
3926  /* 1st: We compute (x0,y0)-(x1,y1), the pixel coordinates of the real outer limits
3927  * of the image rectangle within the (screen) mpWindow. Note that these coordinates
3928  * might fall well far away from the real view limits when the user zoom in.
3929  *
3930  * 2nd: We compute (dx0,dy0)-(dx1,dy1), the pixel coordinates the rectangle that will
3931  * be actually drawn into the mpWindow, i.e. the clipped real rectangle that
3932  * avoids the non-visible parts. (offset_x,offset_y) are the pixel coordinates
3933  * that correspond to the window point (dx0,dy0) within the image "m_bitmap", and
3934  * (b_width,b_height) is the size of the bitmap patch that will be drawn.
3935  *
3936  * (x0,y0) ................. (x1,y0)
3937  * . .
3938  * . .
3939  * (x0,y1) ................ (x1,y1)
3940  * (In pixels!!)
3941  */
3942 
3943  // 1st step -------------------------------
3944  wxCoord x0 = w.x2p( m_min_x );
3945  wxCoord y0 = w.y2p( m_max_y );
3946  wxCoord x1 = w.x2p( m_max_x );
3947  wxCoord y1 = w.y2p( m_min_y );
3948 
3949  // 2nd step -------------------------------
3950  // Precompute the size of the actual bitmap pixel on the screen (e.g. will be >1 if zoomed in)
3951  double screenPixelX = ( x1 - x0 ) / (double) m_bitmap.GetWidth();
3952  double screenPixelY = ( y1 - y0 ) / (double) m_bitmap.GetHeight();
3953 
3954  // The minimum number of pixels that the streched image will overpass the actual mpWindow borders:
3955  wxCoord borderMarginX = (wxCoord) (screenPixelX + 1); // ceil
3956  wxCoord borderMarginY = (wxCoord) (screenPixelY + 1); // ceil
3957 
3958  // The actual drawn rectangle (dx0,dy0)-(dx1,dy1) is (x0,y0)-(x1,y1) clipped:
3959  wxCoord dx0 = x0, dx1 = x1, dy0 = y0, dy1 = y1;
3960 
3961  if( dx0<0 )
3962  dx0 = -borderMarginX;
3963 
3964  if( dy0<0 )
3965  dy0 = -borderMarginY;
3966 
3967  if( dx1>w.GetScrX() )
3968  dx1 = w.GetScrX() + borderMarginX;
3969 
3970  if( dy1>w.GetScrY() )
3971  dy1 = w.GetScrY() + borderMarginY;
3972 
3973  // For convenience, compute the width/height of the rectangle to be actually drawn:
3974  wxCoord d_width = dx1 - dx0 + 1;
3975  wxCoord d_height = dy1 - dy0 + 1;
3976 
3977  // Compute the pixel offsets in the internally stored bitmap:
3978  wxCoord offset_x = (wxCoord) ( (dx0 - x0) / screenPixelX );
3979  wxCoord offset_y = (wxCoord) ( (dy0 - y0) / screenPixelY );
3980 
3981  // and the size in pixel of the area to be actually drawn from the internally stored bitmap:
3982  wxCoord b_width = (wxCoord) ( (dx1 - dx0 + 1) / screenPixelX );
3983  wxCoord b_height = (wxCoord) ( (dy1 - dy0 + 1) / screenPixelY );
3984 
3985 #ifdef MATHPLOT_DO_LOGGING
3986  wxLogMessage( "[mpBitmapLayer::Plot] screenPixel: x=%f y=%f d_width=%ix%i",
3987  screenPixelX,
3988  screenPixelY,
3989  d_width,
3990  d_height );
3991  wxLogMessage( "[mpBitmapLayer::Plot] offset: x=%i y=%i bmpWidth=%ix%i",
3992  offset_x,
3993  offset_y,
3994  b_width,
3995  b_height );
3996 #endif
3997 
3998  // Is there any visible region?
3999  if( d_width>0 && d_height>0 )
4000  {
4001  // Build the scaled bitmap from the image, only if it has changed:
4002  if( m_scaledBitmap.GetWidth()!=d_width
4003  || m_scaledBitmap.GetHeight()!=d_height
4004  || m_scaledBitmap_offset_x != offset_x
4005  || m_scaledBitmap_offset_y != offset_y )
4006  {
4007  wxRect r( wxRect( offset_x, offset_y, b_width, b_height ) );
4008 
4009  // Just for the case....
4010  if( r.x<0 )
4011  r.x = 0;
4012 
4013  if( r.y<0 )
4014  r.y = 0;
4015 
4016  if( r.width>m_bitmap.GetWidth() )
4017  r.width = m_bitmap.GetWidth();
4018 
4019  if( r.height>m_bitmap.GetHeight() )
4020  r.height = m_bitmap.GetHeight();
4021 
4022  m_scaledBitmap = wxBitmap(
4023  wxBitmap( m_bitmap ).GetSubBitmap( r ).ConvertToImage()
4024  .Scale( d_width, d_height ) );
4025  m_scaledBitmap_offset_x = offset_x;
4026  m_scaledBitmap_offset_y = offset_y;
4027  }
4028 
4029  // Draw it:
4030  dc.DrawBitmap( m_scaledBitmap, dx0, dy0, true );
4031  }
4032  }
4033 
4034  // Draw the name label
4035  if( !m_name.IsEmpty() && m_showName )
4036  {
4037  dc.SetFont( m_font );
4038 
4039  wxCoord tx, ty;
4040  dc.GetTextExtent( m_name, &tx, &ty );
4041 
4042  if( HasBBox() )
4043  {
4044  wxCoord sx = (wxCoord) ( ( m_max_x - w.GetPosX() ) * w.GetScaleX() );
4045  wxCoord sy = (wxCoord) ( (w.GetPosY() - m_max_y ) * w.GetScaleY() );
4046 
4047  tx = sx - tx - 8;
4048  ty = sy - 8 - ty;
4049  }
4050  else
4051  {
4052  const int sx = w.GetScrX() >> 1;
4053  const int sy = w.GetScrY() >> 1;
4054 
4055  if( (m_flags & mpALIGNMASK) == mpALIGN_NE )
4056  {
4057  tx = sx - tx - 8;
4058  ty = -sy + 8;
4059  }
4060  else if( (m_flags & mpALIGNMASK) == mpALIGN_NW )
4061  {
4062  tx = -sx + 8;
4063  ty = -sy + 8;
4064  }
4065  else if( (m_flags & mpALIGNMASK) == mpALIGN_SW )
4066  {
4067  tx = -sx + 8;
4068  ty = sy - 8 - ty;
4069  }
4070  else
4071  {
4072  tx = sx - tx - 8;
4073  ty = sy - 8 - ty;
4074  }
4075  }
4076 
4077  dc.DrawText( m_name, tx, ty );
4078  }
4079 }
4080 
4081 
4082 void mpFXY::SetScale( mpScaleBase* scaleX, mpScaleBase* scaleY )
4083 {
4084  m_scaleX = scaleX;
4085  m_scaleY = scaleY;
4086 
4087  // printf("SetScales : %p %p\n", scaleX, scaleY);
4088  UpdateScales();
4089 }
4090 
4091 
4093 {
4094  if( m_scaleX )
4096 
4097  if( m_scaleY )
4099 }
4100 
4101 
4102 double mpFXY::s2x( double plotCoordX ) const
4103 {
4104  return m_scaleX->TransformFromPlot( plotCoordX );
4105 }
4106 
4107 
4108 double mpFXY::s2y( double plotCoordY ) const
4109 {
4110  return m_scaleY->TransformFromPlot( plotCoordY );
4111 }
4112 
4113 
4114 double mpFXY::x2s( double x ) const
4115 {
4116  return m_scaleX->TransformToPlot( x );
4117 }
4118 
4119 
4120 double mpFXY::y2s( double y ) const
4121 {
4122  return m_scaleY->TransformToPlot( y );
4123 }
int m_winX
Definition: mathplot.h:397
double m_maxV
Definition: mathplot.h:835
int m_offsetx
Definition: mathplot.h:1682
mpInfoLegend()
Default constructor.
Definition: mathplot.cpp:292
virtual double TransformToPlot(double x) override
Layer plot handler.
Definition: mathplot.cpp:3306
void ZoomOut(const wxPoint &centerPoint=wxDefaultPosition)
Zoom out current view and refresh display.
Definition: mathplot.cpp:2322
wxCoord maxDrawY
Definition: mathplot.h:630
double s2x(double plotCoordX) const
Definition: mathplot.cpp:4102
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:2908
#define mpALIGN_LEFT
Aligns label to the left.
Definition: mathplot.h:480
mpLayerType GetLayerType()
Get layer type: a Layer can be of different types: plot lines, axis, info boxes, etc,...
Definition: mathplot.h:293
double m_max_y
Definition: mathplot.h:2011
virtual void recalculateTicks(wxDC &dc, mpWindow &w)
Definition: mathplot.h:797
wxMemoryDC m_buff_dc
Definition: mathplot.h:1524
int m_marginRight
Definition: mathplot.h:1521
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:1708
bool m_continuous
Definition: mathplot.h:317
bool m_enableScrollBars
Definition: mathplot.h:1532
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:506
void OnLockAspect(wxCommandEvent &event)
Definition: mathplot.cpp:2444
mpWindow * plotWindow
Definition: mathplot.h:1709
wxBitmap m_scaledBitmap
Definition: mathplot.h:2004
void GetDataRange(double &minV, double &maxV)
Definition: mathplot.h:731
mpLayer * GetLayer(int position)
Definition: mathplot.cpp:3037
double m_maxX
Definition: mathplot.h:1596
bool m_zooming
Definition: mathplot.h:1535
wxString m_content
Definition: mathplot.h:430
virtual double TransformToPlot(double x) override
Definition: mathplot.cpp:3318
const wxString & GetName() const
Get layer name.
Definition: mathplot.h:237
double GetPosY(void) const
Definition: mathplot.h:1125
int m_marginLeft
Definition: mathplot.h:1521
int m_clickedX
Definition: mathplot.h:1513
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:3757
virtual bool SetYView(double pos, double desiredMax, double desiredMin)
Applies new Y view coordinates depending on the settings.
Definition: mathplot.cpp:2245
void Rewind() override
Rewind value enumeration with mpFXY::GetNextXY.
Definition: mathplot.cpp:3358
double GetScaleX(void) const
Definition: mathplot.h:1104
double p2x(wxCoord pixelCoordX)
Converts mpWindow (screen) pixel coordinates into graph (floating point) coordinates,...
Definition: mathplot.h:1187
void updateTickLabels(wxDC &dc, mpWindow &w)
Definition: mathplot.cpp:953
double m_desiredXmax
Definition: mathplot.h:1519
bool m_ticks
Definition: mathplot.h:834
virtual void Plot(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:541
double m_offset
Definition: mathplot.h:830
std::vector< double > m_trans_shape_ys
Definition: mathplot.h:1804
void OnScrollLineDown(wxScrollWinEvent &event)
Definition: mathplot.cpp:2968
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:2505
virtual void SetScale(mpScaleBase *scaleX, mpScaleBase *scaleY)
Definition: mathplot.cpp:4082
bool OnPrintPage(int page) override
Definition: mathplot.cpp:3516
Abstract base class providing plot and labeling functionality for functions F:X->Y.
Definition: mathplot.h:522
void OnZoomOut(wxCommandEvent &event)
Definition: mathplot.cpp:2472
double m_scaleY
Definition: mathplot.h:1508
#define Y_BORDER_SEPARATION
Definition: mathplot.h:94
bool m_enableMouseNavigation
Definition: mathplot.h:1527
double GetScaleY(void) const
Definition: mathplot.h:1111
int m_maxLabelHeight
Definition: mathplot.h:837
int GetMarginBottom()
Definition: mathplot.h:1370
int m_segments
The number of line segments that build up the ellipse.
Definition: mathplot.h:1899
int m_flags
Definition: mathplot.h:832
double m_min_y
Definition: mathplot.h:2011
void OnMouseMiddleDown(wxMouseEvent &event)
Definition: mathplot.cpp:1780
void GetBitmapCopy(wxImage &outBmp) const
Returns a copy of the current bitmap assigned to the layer.
Definition: mathplot.cpp:3897
virtual double TransformToPlot(double x) override
Definition: mathplot.cpp:3330
std::vector< TickLabel > m_tickLabels
Definition: mathplot.h:828
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:649
double m_posX
Definition: mathplot.h:1509
const wxColour & GetAxesColour()
Get axes draw colour.
Definition: mathplot.h:1421
double m_maxY
Definition: mathplot.h:1596
bool m_enableMouseWheelPan
Definition: mathplot.h:1528
bool IsLayerVisible(const wxString &name)
Check whether a layer with given name is visible.
Definition: mathplot.cpp:3173
double y2s(double y) const
Definition: mathplot.cpp:4120
int m_maxLabelWidth
Definition: mathplot.h:838
wxColour m_axColour
Definition: mathplot.h:1501
static int countDecimalDigits(double x, int maxDigits)
wxPoint m_mouseMClick
Definition: mathplot.h:1530
double m_reference_x
The coordinates of the object (orientation "phi" is in radians).
Definition: mathplot.h:1789
double m_minY
Definition: mathplot.h:1505
int m_flags
Definition: mathplot.h:576
#define mpALIGN_RIGHT
Aligns label to the right.
Definition: mathplot.h:476
void SetLayerVisible(const wxString &name, bool viewable)
Sets the visibility of a layer by its name.
Definition: mathplot.cpp:3161
double p2y(wxCoord pixelCoordY)
Converts mpWindow (screen) pixel coordinates into graph (floating point) coordinates,...
Definition: mathplot.h:1192
void OnScrollLineUp(wxScrollWinEvent &event)
Definition: mathplot.cpp:2952
A class providing graphs functionality for a 2D plot (either continuous or a set of points),...
Definition: mathplot.h:1564
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:1588
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:3133
void DoZoomInXCalc(const int staticXpixel)
Definition: mathplot.cpp:2105
bool AddLayer(mpLayer *layer, bool refreshDisplay=true)
Add a plot layer to the canvas.
Definition: mathplot.cpp:2488
void OnSize(wxSizeEvent &event)
Definition: mathplot.cpp:2478
bool GetNextXY(double &x, double &y) override
Get locus value for next N.
Definition: mathplot.cpp:3369
void ZoomInY()
Zoom in current view along Y and refresh display.
Definition: mathplot.cpp:2389
void ZoomOutX()
Zoom out current view along X and refresh display.
Definition: mathplot.cpp:2382
void ZoomOutY()
Zoom out current view along Y and refresh display.
Definition: mathplot.cpp:2396
std::vector< double > m_ys
Definition: mathplot.h:1588
size_t m_index
The internal counter for the "GetNextXY" interface.
Definition: mathplot.h:1592
int tickCount() const
Definition: mathplot.h:799
void ZoomInX()
Zoom in current view along X and refresh display.
Definition: mathplot.cpp:2375
double GetPosX(void) const
Definition: mathplot.h:1118
double m_scaleX
Definition: mathplot.h:1507
wxLayerList m_layers
Definition: mathplot.h:1495
void OnZoomIn(wxCommandEvent &event)
Definition: mathplot.cpp:2466
~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:588
bool m_visible
Definition: mathplot.h:321
void ExtendDataRange(double minV, double maxV)
Definition: mathplot.h:737
#define X_BORDER_SEPARATION
Definition: mathplot.h:93
mpScaleBase * m_scaleY
Definition: mathplot.h:632
void UpdateAll()
Refresh display.
Definition: mathplot.cpp:2836
void DoZoomInYCalc(const int staticYpixel)
Definition: mathplot.cpp:2125
void OnPaint(wxPaintEvent &event)
Definition: mathplot.cpp:2548
wxCoord m_scaledBitmap_offset_x
Definition: mathplot.h:2005
double GetDesiredXmax()
Returns the right-border layer coordinate that the user wants the mpWindow to show (it may be not exa...
Definition: mathplot.h:1307
wxPoint m_mouseLClick
Definition: mathplot.h:1531
#define mpALIGN_BORDER_TOP
Aligns X axis to top border.
Definition: mathplot.h:488
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:1809
wxCoord y2p(double y)
Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates,...
Definition: mathplot.h:1202
virtual bool HasBBox() override
Check whether this layer has a bounding box.
Definition: mathplot.h:1759
virtual double GetMaxX()
Get inclusive right border of bounding box.
Definition: mathplot.h:179
void SetPosX(double posX)
Set current view's X position and refresh display.
Definition: mathplot.h:1164
#define mpALIGN_BORDER_LEFT
Aligns Y axis to left border.
Definition: mathplot.h:500
void UpdateScales()
Definition: mathplot.cpp:4092
int m_winY
Definition: mathplot.h:397
double m_minY
Definition: mathplot.h:1596
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:1169
Plot layer implementing a x-scale ruler.
Definition: mathplot.h:692
double m_max_x
Definition: mathplot.h:2011
virtual double TransformFromPlot(double xplot) override
Definition: mathplot.cpp:3339
virtual void recalculateTicks(wxDC &dc, mpWindow &w) override
Definition: mathplot.cpp:833
double m_bbox_min_x
The precomputed bounding box:
Definition: mathplot.h:1809
#define NULL
double m_desiredYmax
Definition: mathplot.h:1519
void SetVisible(bool show)
Sets layer visibility.
Definition: mathplot.h:301
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:2914
virtual void Plot(wxDC &dc, mpWindow &w) override
Plot given view of layer to the given device context.
Definition: mathplot.cpp:3922
double m_absVisibleMaxV
Definition: mathplot.h:831
int GetMarginTop()
Definition: mathplot.h:1366
void ZoomIn(const wxPoint &centerPoint=wxDefaultPosition)
Zoom into current view and refresh display.
Definition: mathplot.cpp:2259
bool IsVisible()
Checks whether the layer is visible or not.
Definition: mathplot.h:297
void OnScrollBottom(wxScrollWinEvent &event)
Definition: mathplot.cpp:2994
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:3008
wxBrush m_brush
Definition: mathplot.h:396
Base class to create small rectangular info boxes mpInfoLayer is the base class to create a small rec...
Definition: mathplot.h:334
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:2403
wxRect m_zoomRect
Definition: mathplot.h:1536
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:1133
void OnMouseLeftRelease(wxMouseEvent &event)
Definition: mathplot.cpp:1984
bool m_lockaspect
Definition: mathplot.h:1497
void OnMouseMove(wxMouseEvent &event)
Definition: mathplot.cpp:1861
Plot layer implementing a y-scale ruler.
Definition: mathplot.h:940
void ShapeUpdated()
Must be called by the descendent class after updating the shape (m_shape_xs/ys), or when the transfor...
Definition: mathplot.cpp:3604
wxCoord minDrawY
Definition: mathplot.h:630
virtual double GetMaxY()
Get inclusive top border of bounding box.
Definition: mathplot.h:189
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:3124
void GetBoundingBox(double *bbox)
Returns the bounding box coordinates.
Definition: mathplot.cpp:3057
double m_reference_y
Definition: mathplot.h:1789
virtual void recalculateTicks(wxDC &dc, mpWindow &w) override
Definition: mathplot.cpp:1095
int m_flags
Definition: mathplot.h:999
void AdjustLimitedView()
Definition: mathplot.cpp:2185
virtual double getLabelPos(int n)
Definition: mathplot.h:817
double m_desiredXmin
These are updated in Fit() only, and may be different from the real borders (layer coordinates) only ...
Definition: mathplot.h:1519
#define mpALIGN_TOP
Aligns label to the top.
Definition: mathplot.h:482
virtual ~mpInfoLayer()
Destructor.
Definition: mathplot.cpp:125
void SetColourTheme(const wxColour &bgColour, const wxColour &drawColour, const wxColour &axesColour)
Set Color theme.
Definition: mathplot.cpp:3201
EVT_MIDDLE_DOWN(mpWindow::OnMouseMiddleDown) EVT_MOUSEWHEEL(mpWindow
Definition: mathplot.cpp:1699
bool CheckYLimits(double &desiredMax, double &desiredMin) const
Definition: mathplot.h:1470
bool m_ticks
Definition: mathplot.h:1000
void DelAllLayers(bool alsoDeleteObject, bool refreshDisplay=true)
Remove all layers from the plot.
Definition: mathplot.cpp:2532
bool m_rangeSet
Definition: mathplot.h:836
mpInfoLayer * m_movingInfoLayer
Definition: mathplot.h:1534
mpInfoLayer()
Default constructor.
Definition: mathplot.cpp:103
wxFont m_font
Definition: mathplot.h:309
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:504
int m_flags
Definition: mathplot.h:627
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
#define MAX_SCALE
wxColour m_fgColour
Definition: mathplot.h:1500
double m_minV
Definition: mathplot.h:835
int m_last_ly
Definition: mathplot.h:1523
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:2456
mpLayer * GetLayerByName(const wxString &name)
Definition: mathplot.cpp:3046
unsigned int CountAllLayers()
Counts the number of plot layers, whether or not they have a bounding box.
Definition: mathplot.h:1288
bool HasPage(int page) override
Definition: mathplot.cpp:3584
void LockAspect(bool enable=TRUE)
Enable or disable X/Y scale aspect locking for the view.
Definition: mathplot.cpp:2426
wxRect m_dim
Definition: mathplot.h:391
#define mpALIGNMASK
Definition: mathplot.h:474
void recalculateTicks(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:1205
virtual double TransformFromPlot(double xplot) override
Definition: mathplot.cpp:3312
bool m_drawOutsideMargins
Definition: mathplot.h:319
virtual bool HasBBox() override
Check whether this layer has a bounding box.
Definition: mathplot.h:1973
int GetMarginRight()
Definition: mathplot.h:1368
size_t GetCount() override
Definition: mathplot.cpp:3363
wxPoint m_reference
Definition: mathplot.h:395
int GetMarginLeft()
Definition: mathplot.h:1372
bool m_validImg
Definition: mathplot.h:2007
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:3593
virtual const wxString getLabel(int n)
Definition: mathplot.h:822
double m_posY
Definition: mathplot.h:1510
#define mpALIGN_BORDER_BOTTOM
Aligns X axis to bottom border.
Definition: mathplot.h:486
void Fit() override
Set view to fit global bounding box of all plot layers and refresh display.
Definition: mathplot.cpp:2014
int m_marginTop
Definition: mathplot.h:1521
double x2s(double x) const
Definition: mathplot.cpp:4114
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:391
virtual double GetMinX()
Get inclusive left border of bounding box.
Definition: mathplot.h:174
virtual bool GetNextXY(double &x, double &y)=0
Get locus value for next N.
void SetMPScrollbars(bool status)
Enable/disable scrollbars.
Definition: mathplot.cpp:2687
double m_scale
Definition: mathplot.h:830
virtual double GetMinY()
Get inclusive bottom border of bounding box.
Definition: mathplot.h:184
#define D(x)
Definition: ptree.cpp:41
wxImage m_bitmap
The internal copy of the Bitmap:
Definition: mathplot.h:2003
int m_flags
Definition: mathplot.h:544
void OnFit(wxCommandEvent &event)
Definition: mathplot.cpp:2450
virtual void UpdateReference()
Updates the rectangle reference point.
Definition: mathplot.cpp:148
bool m_showName
Definition: mathplot.h:318
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:773
double m_minX
Definition: mathplot.h:1503
void OnShowPopupMenu(wxMouseEvent &event)
Definition: mathplot.cpp:2436
wxCoord minDrawX
Definition: mathplot.h:630
double m_desiredYmin
Definition: mathplot.h:1519
wxCoord x2p(double x)
Converts graph (floating point) coordinates into mpWindow (screen) pixel coordinates,...
Definition: mathplot.h:1197
virtual void formatLabels()
Definition: mathplot.h:810
const char * name
Definition: DXF_plotter.cpp:60
void Clear()
Clears all the data, leaving the layer empty.
Definition: mathplot.cpp:3384
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:1313
virtual void Plot(wxDC &dc, mpWindow &w) override
Plot given view of layer to the given device context.
Definition: mathplot.cpp:3652
wxCoord m_scaledBitmap_offset_y
Definition: mathplot.h:2005
#define _(s)
Definition: 3d_actions.cpp:31
wxPen m_pen
Definition: mathplot.h:314
void SetScr(int scrX, int scrY)
Set current view's dimensions in device context units.
Definition: mathplot.h:1182
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:3904
#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:1175
void DoScrollCalc(const int position, const int orientation)
Definition: mathplot.cpp:2883
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:3509
~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:1799
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:1804
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:3391
virtual bool HasBBox()
Check whether this layer has a bounding box.
Definition: mathplot.h:160
int m_clickedY
Definition: mathplot.h:1514
Plot layer implementing a text string.
Definition: mathplot.h:1666
virtual bool SetXView(double pos, double desiredMax, double desiredMin)
Applies new X view coordinates depending on the settings.
Definition: mathplot.cpp:2231
void OnMouseLeftDown(wxMouseEvent &event)
Definition: mathplot.cpp:1961
int m_flags
Definition: mathplot.h:671
void DoZoomOutXCalc(const int staticXpixel)
Definition: mathplot.cpp:2145
Canvas for plotting mpLayer implementations.
Definition: mathplot.h:1045
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:1301
mpScaleBase * m_scaleX
Definition: mathplot.h:632
double m_minX
Loaded at SetData.
Definition: mathplot.h:1596
mpLayerType m_type
Definition: mathplot.h:320
int m_marginBottom
Definition: mathplot.h:1521
#define mpALIGN_BOTTOM
Aligns label to the bottom.
Definition: mathplot.h:484
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:2728
int m_last_lx
Definition: mathplot.h:1523
#define mpALIGN_CENTER
Aligns label to the center.
Definition: mathplot.h:478
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:3869
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:3019
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:316
int m_scrY
Definition: mathplot.h:1512
void OnScrollPageDown(wxScrollWinEvent &event)
Definition: mathplot.cpp:2932
bool m_enableLimitedView
Definition: mathplot.h:1529
double m_reference_phi
Definition: mathplot.h:1789
wxMenu m_popmenu
Definition: mathplot.h:1496
wxCoord maxDrawX
Definition: mathplot.h:630
void OnScrollTop(wxScrollWinEvent &event)
Definition: mathplot.cpp:2988
double m_maxX
Definition: mathplot.h:1504
bool CheckXLimits(double &desiredMax, double &desiredMin) const
Definition: mathplot.h:1463
virtual double TransformFromPlot(double xplot) override
Definition: mathplot.cpp:3324
wxColour m_bgColour
Definition: mathplot.h:1499
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:3066
double m_bbox_max_x
Definition: mathplot.h:1809
double s2y(double plotCoordY) const
Definition: mathplot.cpp:4108
void DoZoomOutYCalc(const int staticYpixel)
Definition: mathplot.cpp:2165
int m_nameFlags
Definition: mathplot.h:833
virtual int labelCount() const
Definition: mathplot.h:804
bool m_enableDoubleBuffer
Definition: mathplot.h:1526
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:1894
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:1346
mpScaleY * m_masterScale
Definition: mathplot.h:995
std::vector< double > m_tickValues
Definition: mathplot.h:827
const wxPen & GetPen() const
Get pen set for this layer.
Definition: mathplot.h:247
virtual void Plot(wxDC &dc, mpWindow &w) override
Layer plot handler.
Definition: mathplot.cpp:464
int m_scrX
Definition: mathplot.h:1511
#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:1525
#define mpALIGN_SE
Aligns label to south-east.
Definition: mathplot.h:510
Abstract base class providing plot and labeling functionality for functions F:Y->X.
Definition: mathplot.h:554
double GetDesiredYmax()
Returns the top layer-border coordinate that the user wants the mpWindow to show (it may be not exact...
Definition: mathplot.h:1319
virtual double getTickPos(int n)
Definition: mathplot.h:812
std::vector< double > m_shape_xs
This contains the object points, in local coordinates (to be transformed by the current transformatio...
Definition: mathplot.h:1799
#define mpLEGEND_LINEWIDTH
Definition: mathplot.cpp:54
void OnMouseWheel(wxMouseEvent &event)
Definition: mathplot.cpp:1806
double m_maxY
Definition: mathplot.h:1506
virtual double TransformFromPlot(double xplot)
Definition: mathplot.h:774
#define mpALIGN_BORDER_RIGHT
Aligns Y axis to right border.
Definition: mathplot.h:502
int m_offsety
Definition: mathplot.h:1683
int GetScrY(void) const
Get current view's Y dimension in device context units.
Definition: mathplot.h:1142
double m_min_x
The shape of the bitmap:
Definition: mathplot.h:2011
double m_bbox_min_y
Definition: mathplot.h:1809
virtual void Plot(wxDC &dc, mpWindow &w) override
Text Layer plot handler.
Definition: mathplot.cpp:3480
#define mpALIGN_SW
Aligns label to south-west.
Definition: mathplot.h:508