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