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