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