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