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