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