summaryrefslogtreecommitdiffstats
path: root/Project/wxMathPlot/mathplot.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Project/wxMathPlot/mathplot.cpp')
-rw-r--r--Project/wxMathPlot/mathplot.cpp3074
1 files changed, 3074 insertions, 0 deletions
diff --git a/Project/wxMathPlot/mathplot.cpp b/Project/wxMathPlot/mathplot.cpp
new file mode 100644
index 0000000..8543ca7
--- /dev/null
+++ b/Project/wxMathPlot/mathplot.cpp
@@ -0,0 +1,3074 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name: mathplot.cpp
+// Purpose: Framework for plotting in wxWindows
+// Original Author: David Schalig
+// Maintainer: Davide Rondini
+// Contributors: Jose Luis Blanco, Val Greene
+// Created: 21/07/2003
+// Last edit: 09/09/2007
+// Copyright: (c) David Schalig, Davide Rondini
+// Licence: wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+// #pragma implementation "plot.h"
+#pragma implementation "mathplot.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include <wx/window.h>
+//#include <wx/wxprec.h>
+
+// Comment out for release operation:
+// (Added by J.L.Blanco, Aug 2007)
+// #define MATHPLOT_DO_LOGGING
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/object.h"
+#include "wx/font.h"
+#include "wx/colour.h"
+#include "wx/settings.h"
+#include "wx/sizer.h"
+//#include "wx/log.h"
+#include "wx/intl.h"
+#include "wx/dcclient.h"
+#include "wx/cursor.h"
+#endif
+
+#include "mathplot.h"
+#include <wx/bmpbuttn.h>
+#include <wx/module.h>
+#include <wx/msgdlg.h>
+#include <wx/image.h>
+#include <wx/tipwin.h>
+
+#include <cmath>
+#include <cstdio> // used only for debug
+#include <ctime> // used for representation of x axes involving date
+
+// #include "pixel.xpm"
+
+// Memory leak debugging
+#ifdef _DEBUG
+#define new DEBUG_NEW
+#endif
+
+// Legend margins
+#define mpLEGEND_MARGIN 5
+#define mpLEGEND_LINEWIDTH 40
+
+// Minimum axis label separation
+#define mpMIN_X_AXIS_LABEL_SEPARATION 64
+#define mpMIN_Y_AXIS_LABEL_SEPARATION 32
+
+// Number of pixels to scroll when scrolling by a line
+#define mpSCROLL_NUM_PIXELS_PER_LINE 10
+
+// See doxygen comments.
+double mpWindow::zoomIncrementalFactor = 1.5;
+
+//-----------------------------------------------------------------------------
+// mpLayer
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_ABSTRACT_CLASS(mpLayer, wxObject)
+
+mpLayer::mpLayer() : m_type(mpLAYER_UNDEF)
+{
+ SetPen((wxPen&) *wxBLACK_PEN);
+ SetFont((wxFont&) *wxNORMAL_FONT);
+ m_continuous = FALSE; // Default
+ m_showName = TRUE; // Default
+ m_drawOutsideMargins = TRUE;
+ m_visible = true;
+}
+
+wxBitmap mpLayer::GetColourSquare(int side)
+{
+ wxBitmap square(side, side, -1);
+ wxColour filler = m_pen.GetColour();
+ wxBrush brush(filler, wxSOLID);
+ wxMemoryDC dc;
+ dc.SelectObject(square);
+ dc.SetBackground(brush);
+ dc.Clear();
+ dc.SelectObject(wxNullBitmap);
+ return square;
+}
+
+//-----------------------------------------------------------------------------
+// mpInfoLayer
+//-----------------------------------------------------------------------------
+IMPLEMENT_DYNAMIC_CLASS(mpInfoLayer, mpLayer)
+
+mpInfoLayer::mpInfoLayer()
+{
+ m_dim = wxRect(0,0,1,1);
+ m_brush = *wxTRANSPARENT_BRUSH;
+ m_reference.x = 0; m_reference.y = 0;
+ m_winX = 1; //parent->GetScrX();
+ m_winY = 1; //parent->GetScrY();
+ m_type = mpLAYER_INFO;
+}
+
+mpInfoLayer::mpInfoLayer(wxRect rect, const wxBrush* brush) : m_dim(rect)
+{
+ m_brush = *brush;
+ m_reference.x = rect.x;
+ m_reference.y = rect.y;
+ m_winX = 1; //parent->GetScrX();
+ m_winY = 1; //parent->GetScrY();
+ m_type = mpLAYER_INFO;
+}
+
+mpInfoLayer::~mpInfoLayer()
+{
+
+}
+
+void mpInfoLayer::UpdateInfo(mpWindow& w, wxEvent& event)
+{
+
+}
+
+bool mpInfoLayer::Inside(wxPoint& point)
+{
+ return m_dim.Contains(point);
+}
+
+void mpInfoLayer::Move(wxPoint delta)
+{
+ m_dim.SetX(m_reference.x + delta.x);
+ m_dim.SetY(m_reference.y + delta.y);
+}
+
+void mpInfoLayer::UpdateReference()
+{
+ m_reference.x = m_dim.x;
+ m_reference.y = m_dim.y;
+}
+
+
+void mpInfoLayer::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ // Adjust relative position inside the window
+ int scrx = w.GetScrX();
+ int scry = w.GetScrY();
+ // Avoid dividing by 0
+ if(scrx == 0) scrx=1;
+ if(scry == 0) scry=1;
+
+ if ((m_winX != scrx) || (m_winY != scry)) {
+#ifdef MATHPLOT_DO_LOGGING
+ // wxLogMessage(_("mpInfoLayer::Plot() screen size has changed from %d x %d to %d x %d"), m_winX, m_winY, scrx, scry);
+#endif
+ if (m_winX != 1) m_dim.x = (int) floor((double)(m_dim.x*scrx/m_winX));
+ if (m_winY != 1) {
+ m_dim.y = (int) floor((double)(m_dim.y*scry/m_winY));
+ UpdateReference();
+ }
+ // Finally update window size
+ m_winX = scrx;
+ m_winY = scry;
+ }
+ dc.SetPen(m_pen);
+// wxImage image0(wxT("pixel.png"), wxBITMAP_TYPE_PNG);
+// wxBitmap image1(image0);
+// wxBrush semiWhite(image1);
+ dc.SetBrush(m_brush);
+ dc.DrawRectangle(m_dim.x, m_dim.y, m_dim.width, m_dim.height);
+ }
+}
+
+wxPoint mpInfoLayer::GetPosition()
+{
+ return m_dim.GetPosition();
+}
+
+wxSize mpInfoLayer::GetSize()
+{
+ return m_dim.GetSize();
+}
+
+mpInfoCoords::mpInfoCoords() : mpInfoLayer()
+{
+
+}
+
+mpInfoCoords::mpInfoCoords(wxRect rect, const wxBrush* brush) : mpInfoLayer(rect, brush)
+{
+
+}
+
+mpInfoCoords::~mpInfoCoords()
+{
+
+}
+
+void mpInfoCoords::UpdateInfo(mpWindow& w, wxEvent& event)
+{
+ if (event.GetEventType() == wxEVT_MOTION) {
+ int mouseX = ((wxMouseEvent&)event).GetX();
+ int mouseY = ((wxMouseEvent&)event).GetY();
+/* It seems that Windows port of wxWidgets don't support multi-line test to be drawn in a wxDC.
+ wxGTK instead works perfectly with it.
+ Info on wxForum: http://wxforum.shadonet.com/viewtopic.php?t=3451&highlight=drawtext+eol */
+#ifdef _WINDOWS
+ m_content.Printf(wxT("x = %f y = %f"), w.p2x(mouseX), w.p2y(mouseY));
+#else
+ m_content.Printf(wxT("x = %f\ny = %f"), w.p2x(mouseX), w.p2y(mouseY));
+#endif
+ }
+}
+
+void mpInfoCoords::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ // Adjust relative position inside the window
+ int scrx = w.GetScrX();
+ int scry = w.GetScrY();
+ if ((m_winX != scrx) || (m_winY != scry)) {
+#ifdef MATHPLOT_DO_LOGGING
+ // wxLogMessage(_("mpInfoLayer::Plot() screen size has changed from %d x %d to %d x %d"), m_winX, m_winY, scrx, scry);
+#endif
+ if (m_winX != 1) m_dim.x = (int) floor((double)(m_dim.x*scrx/m_winX));
+ if (m_winY != 1) {
+ m_dim.y = (int) floor((double)(m_dim.y*scry/m_winY));
+ UpdateReference();
+ }
+ // Finally update window size
+ m_winX = scrx;
+ m_winY = scry;
+ }
+ dc.SetPen(m_pen);
+// wxImage image0(wxT("pixel.png"), wxBITMAP_TYPE_PNG);
+// wxBitmap image1(image0);
+// wxBrush semiWhite(image1);
+ dc.SetBrush(m_brush);
+ dc.SetFont(m_font);
+ int textX, textY;
+ dc.GetMultiLineTextExtent(m_content, &textX, &textY);
+ if (m_dim.width < textX + 10) m_dim.width = textX + 10;
+ if (m_dim.height < textY + 10) m_dim.height = textY + 10;
+ dc.DrawRectangle(m_dim.x, m_dim.y, m_dim.width, m_dim.height);
+ dc.DrawText(m_content, m_dim.x + 5, m_dim.y + 5);
+ }
+}
+
+mpInfoLegend::mpInfoLegend() : mpInfoLayer()
+{
+
+}
+
+mpInfoLegend::mpInfoLegend(wxRect rect, const wxBrush* brush) : mpInfoLayer(rect, brush)
+{
+
+}
+
+mpInfoLegend::~mpInfoLegend()
+{
+
+}
+
+void mpInfoLegend::UpdateInfo(mpWindow& w, wxEvent& event)
+{
+
+}
+
+void mpInfoLegend::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ // Adjust relative position inside the window
+ int scrx = w.GetScrX();
+ int scry = w.GetScrY();
+ if ((m_winX != scrx) || (m_winY != scry)) {
+#ifdef MATHPLOT_DO_LOGGING
+ // wxLogMessage(_("mpInfoLayer::Plot() screen size has changed from %d x %d to %d x %d"), m_winX, m_winY, scrx, scry);
+#endif
+ if (m_winX != 1) m_dim.x = (int) floor((double)(m_dim.x*scrx/m_winX));
+ if (m_winY != 1) {
+ m_dim.y = (int) floor((double)(m_dim.y*scry/m_winY));
+ UpdateReference();
+ }
+ // Finally update window size
+ m_winX = scrx;
+ m_winY = scry;
+ }
+// wxImage image0(wxT("pixel.png"), wxBITMAP_TYPE_PNG);
+// wxBitmap image1(image0);
+// wxBrush semiWhite(image1);
+ dc.SetBrush(m_brush);
+ dc.SetFont(m_font);
+ const int baseWidth = (mpLEGEND_MARGIN*2 + mpLEGEND_LINEWIDTH);
+ int textX = baseWidth, textY = mpLEGEND_MARGIN;
+ int plotCount = 0;
+ int posY = 0;
+ int tmpX = 0, tmpY = 0;
+ mpLayer* ly = NULL;
+ wxPen lpen;
+ wxString label;
+ for (unsigned int p = 0; p < w.CountAllLayers(); p++) {
+ ly = w.GetLayer(p);
+ if ((ly->GetLayerType() == mpLAYER_PLOT) && (ly->IsVisible())) {
+ label = ly->GetName();
+ dc.GetTextExtent(label, &tmpX, &tmpY);
+ textX = (textX > (tmpX + baseWidth)) ? textX : (tmpX + baseWidth + mpLEGEND_MARGIN);
+ textY += (tmpY);
+#ifdef MATHPLOT_DO_LOGGING
+ // wxLogMessage(_("mpInfoLegend::Plot() Adding layer %d: %s"), p, label.c_str());
+#endif
+ }
+ }
+ dc.SetPen(m_pen);
+ dc.SetBrush(m_brush);
+ m_dim.width = textX;
+ if (textY != mpLEGEND_MARGIN) { // Don't draw any thing if there are no visible layers
+ textY += mpLEGEND_MARGIN;
+ m_dim.height = textY;
+ dc.DrawRectangle(m_dim.x, m_dim.y, m_dim.width, m_dim.height);
+ for (unsigned int p2 = 0; p2 < w.CountAllLayers(); p2++) {
+ ly = w.GetLayer(p2);
+ if ((ly->GetLayerType() == mpLAYER_PLOT) && (ly->IsVisible())) {
+ label = ly->GetName();
+ lpen = ly->GetPen();
+ dc.GetTextExtent(label, &tmpX, &tmpY);
+ dc.SetPen(lpen);
+ //textX = (textX > (tmpX + baseWidth)) ? textX : (tmpX + baseWidth);
+ //textY += (tmpY + mpLEGEND_MARGIN);
+ posY = m_dim.y + mpLEGEND_MARGIN + plotCount*tmpY + (tmpY>>1);
+ dc.DrawLine(m_dim.x + mpLEGEND_MARGIN, // X start coord
+ posY, // Y start coord
+ m_dim.x + mpLEGEND_LINEWIDTH + mpLEGEND_MARGIN, // X end coord
+ posY);
+ //dc.DrawRectangle(m_dim.x + 5, m_dim.y + 5 + plotCount*tmpY, 5, 5);
+ dc.DrawText(label, m_dim.x + baseWidth, m_dim.y + mpLEGEND_MARGIN + plotCount*tmpY);
+ plotCount++;
+ }
+ }
+ }
+ }
+}
+
+
+
+//-----------------------------------------------------------------------------
+// mpLayer implementations - functions
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_ABSTRACT_CLASS(mpFX, mpLayer)
+
+mpFX::mpFX(wxString name, int flags)
+{
+ SetName(name);
+ m_flags = flags;
+ m_type = mpLAYER_PLOT;
+}
+
+void mpFX::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ dc.SetPen( m_pen);
+
+ wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
+ wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
+ wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
+ wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
+
+ wxCoord iy = 0;
+ if (m_pen.GetWidth() <= 1)
+ {
+ for (wxCoord i = startPx; i < endPx; ++i)
+ {
+ iy = w.y2p( GetY(w.p2x(i)));
+ // Draw the point only if you can draw outside margins or if the point is inside margins
+ if (m_drawOutsideMargins || ((iy >= minYpx) && (iy <= maxYpx)))
+ dc.DrawPoint(i, iy );// (wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY()));
+ }
+ }
+ else
+ {
+ for (wxCoord i = startPx; i < endPx; ++i)
+ {
+ iy = w.y2p( GetY(w.p2x(i)));
+ // Draw the point only if you can draw outside margins or if the point is inside margins
+ if (m_drawOutsideMargins || ((iy >= minYpx) && (iy <= maxYpx)))
+ dc.DrawLine( i, iy, i, iy);
+ // wxCoord c = w.y2p( GetY(w.p2x(i)) ); //(wxCoord) ((w.GetPosY() - GetY( (double)i / w.GetScaleX() + w.GetPosX()) ) * w.GetScaleY());
+
+ }
+ }
+
+ if (!m_name.IsEmpty() && m_showName)
+ {
+ dc.SetFont(m_font);
+
+ wxCoord tx, ty;
+ dc.GetTextExtent(m_name, &tx, &ty);
+
+ /*if ((m_flags & mpALIGNMASK) == mpALIGN_RIGHT)
+ tx = (w.GetScrX()>>1) - tx - 8;
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
+ tx = -tx/2;
+ else
+ tx = -(w.GetScrX()>>1) + 8;
+ */
+ if ((m_flags & mpALIGNMASK) == mpALIGN_RIGHT)
+ tx = (w.GetScrX() - tx) - w.GetMarginRight() - 8;
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
+ tx = ((w.GetScrX() - w.GetMarginRight() - w.GetMarginLeft() - tx) / 2) + w.GetMarginLeft();
+ else
+ tx = w.GetMarginLeft() + 8;
+ dc.DrawText( m_name, tx, w.y2p(GetY(w.p2x(tx))) ); // (wxCoord) ((w.GetPosY() - GetY( (double)tx / w.GetScaleX() + w.GetPosX())) * w.GetScaleY()) );
+ }
+ }
+}
+
+IMPLEMENT_ABSTRACT_CLASS(mpFY, mpLayer)
+
+mpFY::mpFY(wxString name, int flags)
+{
+ SetName(name);
+ m_flags = flags;
+ m_type = mpLAYER_PLOT;
+}
+
+void mpFY::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ dc.SetPen( m_pen);
+
+ wxCoord i, ix;
+
+ wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
+ wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
+ wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
+ wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
+
+ if (m_pen.GetWidth() <= 1)
+ {
+ for (i = minYpx; i < maxYpx; ++i)
+ {
+ ix = w.x2p(GetX(w.p2y(i)));
+ if (m_drawOutsideMargins || ((ix >= startPx) && (ix <= endPx)))
+ dc.DrawPoint(ix, i);
+ }
+ }
+ else
+ {
+ for (i=0;i< w.GetScrY(); ++i)
+ {
+ ix = w.x2p(GetX(w.p2y(i)));
+ if (m_drawOutsideMargins || ((ix >= startPx) && (ix <= endPx)))
+ dc.DrawLine(ix, i, ix, i);
+ // wxCoord c = w.x2p(GetX(w.p2y(i))); //(wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX());
+ // dc.DrawLine(c, i, c, i);
+ }
+ }
+
+ if (!m_name.IsEmpty() && m_showName)
+ {
+ dc.SetFont(m_font);
+
+ wxCoord tx, ty;
+ dc.GetTextExtent(m_name, &tx, &ty);
+
+ if ((m_flags & mpALIGNMASK) == mpALIGN_TOP)
+ ty = w.GetMarginTop() + 8;
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
+ ty = ((w.GetScrY() - w.GetMarginTop() - w.GetMarginBottom() - ty) / 2) + w.GetMarginTop();
+ else
+ ty = w.GetScrY() - 8 - ty - w.GetMarginBottom();
+
+ dc.DrawText( m_name, w.x2p(GetX(w.p2y(ty))), ty ); // (wxCoord) ((GetX( (double)i / w.GetScaleY() + w.GetPosY()) - w.GetPosX()) * w.GetScaleX()), -ty);
+ }
+ }
+}
+
+IMPLEMENT_ABSTRACT_CLASS(mpFXY, mpLayer)
+
+mpFXY::mpFXY(wxString name, int flags)
+{
+ SetName(name);
+ m_flags = flags;
+ m_type = mpLAYER_PLOT;
+}
+
+void mpFXY::UpdateViewBoundary(wxCoord xnew, wxCoord ynew)
+{
+ // Keep track of how many points have been drawn and the bouding box
+ maxDrawX = (xnew > maxDrawX) ? xnew : maxDrawX;
+ minDrawX = (xnew < minDrawX) ? xnew : minDrawX;
+ maxDrawY = (maxDrawY > ynew) ? maxDrawY : ynew;
+ minDrawY = (minDrawY < ynew) ? minDrawY : ynew;
+ //drawnPoints++;
+}
+
+void mpFXY::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ dc.SetPen( m_pen);
+
+ double x, y;
+ // Do this to reset the counters to evaluate bounding box for label positioning
+ Rewind(); GetNextXY(x, y);
+ maxDrawX = x; minDrawX = x; maxDrawY = y; minDrawY = y;
+ //drawnPoints = 0;
+ Rewind();
+
+ wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
+ wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
+ wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
+ wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
+
+ wxCoord ix = 0, iy = 0;
+
+ if (!m_continuous)
+ {
+ // for some reason DrawPoint does not use the current pen,
+ // so we use DrawLine for fat pens
+ if (m_pen.GetWidth() <= 1)
+ {
+ while (GetNextXY(x, y))
+ {
+ ix = w.x2p(x);
+ iy = w.y2p(y);
+ if (m_drawOutsideMargins || ((ix >= startPx) && (ix <= endPx) && (iy >= minYpx) && (iy <= maxYpx))) {
+ dc.DrawPoint(ix, iy);
+ UpdateViewBoundary(ix, iy);
+ };
+ }
+ }
+ else
+ {
+ while (GetNextXY(x, y))
+ {
+ ix = w.x2p(x);
+ iy = w.y2p(y);
+ if (m_drawOutsideMargins || ((ix >= startPx) && (ix <= endPx) && (iy >= minYpx) && (iy <= maxYpx))) {
+ dc.DrawLine(ix, iy, ix, iy);
+ UpdateViewBoundary(ix, iy);
+ }
+ // dc.DrawLine(cx, cy, cx, cy);
+ }
+ }
+ }
+ else
+ {
+ // Old code
+ wxCoord x0=0,c0=0;
+ bool first = TRUE;
+ std::vector<wxPoint> ptVector;
+ bool outUp, outDown;
+ outUp = outDown = true;
+ while (GetNextXY(x, y))
+ {
+ wxCoord x1 = w.x2p(x); // (wxCoord) ((x - w.GetPosX()) * w.GetScaleX());
+ wxCoord c1 = w.y2p(y); // (wxCoord) ((w.GetPosY() - y) * w.GetScaleY());
+ if (first)
+ {
+ first=FALSE;
+ x0=x1;c0=c1;
+ }
+ if((x1 >= startPx)&&(x0 <= endPx)) {
+ outDown = (c0 > maxYpx) && (c1 > maxYpx);
+ outUp = (c0 < minYpx) && (c1 < minYpx);
+ if (!outUp && !outDown) {
+ //Thales Lima Oliveira 22/06/2015
+ //Comentado para desaparecer a reta limite da curva (porque usar aquele limite??)
+ /*if (c1 != c0) {
+ if (c0 < minYpx) {
+ x0 = (int)(((float)(minYpx - c0))/((float)(c1 - c0))*(x1-x0)) + x0;
+ c0 = minYpx;
+ }
+ if (c0 > maxYpx) {
+ x0 = (int)(((float)(maxYpx - c0))/((float)(c1 - c0))*(x1-x0)) + x0;
+ //wxLogDebug(wxT("old x0 = %d, new x0 = %d"), x0, newX0);
+ //x0 = newX0;
+ c0 = maxYpx;
+ }
+ if (c1 < minYpx) {
+ x1 = (int)(((float)(minYpx - c0))/((float)(c1 - c0))*(x1-x0)) + x0;
+ c1 = minYpx;
+ }
+ if (c1 > maxYpx) {
+ x1 = (int)(((float)(maxYpx - c0))/((float)(c1 - c0))*(x1-x0)) + x0;
+ //wxLogDebug(wxT("old x0 = %d, old x1 = %d, new x1 = %d, c0 = %d, c1 = %d, maxYpx = %d"), x0, x1, newX1, c0, c1, maxYpx);
+ //x1 = newX1;
+ c1 = maxYpx;
+ }
+ }
+ if (x1 != x0) {
+ if (x0 < startPx) {
+ c0 = (int)(((float)(startPx - x0))/((float)(x1 -x0))*(c1 -c0)) + c0;
+ x0 = startPx;
+ }
+ if (x1 > endPx) {
+ c1 = (int)(((float)(endPx - x0))/((float)(x1 -x0))*(c1 -c0)) + c0;
+ x1 = endPx;
+ }
+ }*/
+
+ //dc.DrawLine(x0, c0, x1, c1);
+ //ptVector.push_back(wxPoint(x1, c1));
+ UpdateViewBoundary(x1, c1);
+ }
+ }
+ ptVector.push_back(wxPoint(x1, c1));
+ x0=x1; c0=c1;
+ }
+
+ //modificado a forma de desenhar (desenha agora de forma contínua, permitindo usar diferentes tipos de traços)
+ wxPoint drawPts[ptVector.size()];
+ for(int i = 0; i < (int)ptVector.size(); i++) {
+ drawPts[i] = ptVector[i];
+ }
+ dc.DrawLines(ptVector.size(), drawPts);
+
+ }
+
+ if (!m_name.IsEmpty() && m_showName)
+ {
+ dc.SetFont(m_font);
+
+ wxCoord tx, ty;
+ dc.GetTextExtent(m_name, &tx, &ty);
+
+ // xxx implement else ... if (!HasBBox())
+ {
+ // const int sx = w.GetScrX();
+ // const int sy = w.GetScrY();
+
+ if ((m_flags & mpALIGNMASK) == mpALIGN_NW)
+ {
+ tx = minDrawX + 8;
+ ty = maxDrawY + 8;
+ }
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_NE)
+ {
+ tx = maxDrawX - tx - 8;
+ ty = maxDrawY + 8;
+ }
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_SE)
+ {
+ tx = maxDrawX - tx - 8;
+ ty = minDrawY - ty - 8;
+ }
+ else
+ { // mpALIGN_SW
+ tx = minDrawX + 8;
+ ty = minDrawY - ty - 8;
+ }
+ }
+
+ dc.DrawText( m_name, tx, ty);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// mpProfile implementation
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_ABSTRACT_CLASS(mpProfile, mpLayer)
+
+mpProfile::mpProfile(wxString name, int flags)
+{
+ SetName(name);
+ m_flags = flags;
+ m_type = mpLAYER_PLOT;
+}
+
+void mpProfile::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ dc.SetPen( m_pen);
+
+ wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
+ wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
+ wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
+ wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
+
+ // Plot profile linking subsequent point of the profile, instead of mpFY, which plots simple points.
+ for (wxCoord i = startPx; i < endPx; ++i) {
+ wxCoord c0 = w.y2p( GetY(w.p2x(i)) ); // (wxCoord) ((w.GetYpos() - GetY( (double)i / w.GetXscl() + w.GetXpos()) ) * w.GetYscl());
+ wxCoord c1 = w.y2p( GetY(w.p2x(i+1)) );//(wxCoord) ((w.GetYpos() - GetY( (double)(i+1) / w.GetXscl() + (w.GetXpos() ) ) ) * w.GetYscl());
+ // c0 = (c0 <= maxYpx) ? ((c0 >= minYpx) ? c0 : minYpx) : maxYpx;
+ // c1 = (c1 <= maxYpx) ? ((c1 >= minYpx) ? c1 : minYpx) : maxYpx;
+ if (!m_drawOutsideMargins) {
+ c0 = (c0 <= maxYpx) ? ((c0 >= minYpx) ? c0 : minYpx) : maxYpx;
+ c1 = (c1 <= maxYpx) ? ((c1 >= minYpx) ? c1 : minYpx) : maxYpx;
+ }
+ dc.DrawLine(i, c0, i+1, c1);
+ };
+ if (!m_name.IsEmpty()) {
+ dc.SetFont(m_font);
+
+ wxCoord tx, ty;
+ dc.GetTextExtent(m_name, &tx, &ty);
+
+ if ((m_flags & mpALIGNMASK) == mpALIGN_RIGHT)
+ tx = (w.GetScrX() - tx) - w.GetMarginRight() - 8;
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_CENTER)
+ tx = ((w.GetScrX() - w.GetMarginRight() - w.GetMarginLeft() - tx) / 2) + w.GetMarginLeft();
+ else
+ tx = w.GetMarginLeft() + 8;
+
+ dc.DrawText( m_name, tx, w.y2p( GetY( w.p2x(tx) ) ) );//(wxCoord) ((w.GetPosY() - GetY( (double)tx / w.GetScaleX() + w.GetPosX())) * w.GetScaleY()) );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// mpLayer implementations - furniture (scales, ...)
+//-----------------------------------------------------------------------------
+
+#define mpLN10 2.3025850929940456840179914546844
+
+IMPLEMENT_DYNAMIC_CLASS(mpScaleX, mpLayer)
+
+mpScaleX::mpScaleX(wxString name, int flags, bool ticks, unsigned int type)
+{
+ SetName(name);
+ SetFont( (wxFont&) *wxSMALL_FONT);
+ SetPen( (wxPen&) *wxGREY_PEN);
+ m_flags = flags;
+ m_ticks = ticks;
+ m_labelType = type;
+ m_type = mpLAYER_AXIS;
+ m_labelFormat = wxT("");
+}
+
+void mpScaleX::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ dc.SetPen( m_pen);
+ dc.SetFont( m_font);
+ int orgy=0;
+
+ const int extend = w.GetScrX(); // /2;
+ if (m_flags == mpALIGN_CENTER)
+ orgy = w.y2p(0); //(int)(w.GetPosY() * w.GetScaleY());
+ if (m_flags == mpALIGN_TOP) {
+ if (m_drawOutsideMargins)
+ orgy = X_BORDER_SEPARATION;
+ else
+ orgy = w.GetMarginTop();
+ }
+ if (m_flags == mpALIGN_BOTTOM) {
+ if (m_drawOutsideMargins)
+ orgy = X_BORDER_SEPARATION;
+ else
+ orgy = w.GetScrY() - w.GetMarginBottom();
+ }
+ if (m_flags == mpALIGN_BORDER_BOTTOM )
+ orgy = w.GetScrY() - 1;//dc.LogicalToDeviceY(0) - 1;
+ if (m_flags == mpALIGN_BORDER_TOP )
+ orgy = 1;//-dc.LogicalToDeviceY(0);
+
+ //Thales Lima Oliveira - 23/06/2015
+ //Inserido retângulo para tapar a curva que fica fora do gráfico
+ dc.SetBrush( wxBrush(w.GetBackgroundColour()) );
+ dc.SetPen( *wxTRANSPARENT_PEN );
+ dc.DrawRectangle( 0, orgy, w.GetScrX(), orgy);
+ dc.DrawRectangle( 0, 0, w.GetScrX(), w.GetMarginTop());
+ dc.SetPen( m_pen);
+
+ dc.DrawLine( w.GetMarginLeft(), orgy, w.GetScrX() - w.GetMarginRight(), orgy);
+
+ // To cut the axis line when draw outside margin is false, use this code
+ /*if (m_drawOutsideMargins == true)
+ dc.DrawLine( 0, orgy, w.GetScrX(), orgy);
+ else
+ dc.DrawLine( w.GetMarginLeft(), orgy, w.GetScrX() - w.GetMarginRight(), orgy); */
+
+ const double dig = floor( log( 128.0 / w.GetScaleX() ) / mpLN10 );
+ const double step = exp( mpLN10 * dig);
+ const double end = w.GetPosX() + (double)extend / w.GetScaleX();
+
+ wxCoord tx, ty;
+ wxString s;
+ wxString fmt;
+ int tmp = (int)dig;
+ if (m_labelType == mpX_NORMAL) {
+ if (!m_labelFormat.IsEmpty()) {
+ fmt = m_labelFormat;
+ } else {
+ if (tmp>=1) {
+ fmt = wxT("%.f");
+ } else {
+ tmp=8-tmp;
+ fmt.Printf(wxT("%%.%df"), tmp >= -1 ? 2 : -tmp);
+ }
+ }
+ } else {
+ // Date and/or time axis representation
+ if (m_labelType == mpX_DATETIME) {
+ fmt = (wxT("%04.0f-%02.0f-%02.0fT%02.0f:%02.0f:%02.0f"));
+ } else if (m_labelType == mpX_DATE) {
+ fmt = (wxT("%04.0f-%02.0f-%02.0f"));
+ } else if ((m_labelType == mpX_TIME) && (end/60 < 2)) {
+ fmt = (wxT("%02.0f:%02.3f"));
+ } else {
+ fmt = (wxT("%02.0f:%02.0f:%02.0f"));
+ }
+ }
+
+ //double n = floor( (w.GetPosX() - (double)extend / w.GetScaleX()) / step ) * step ;
+ double n0 = floor( (w.GetPosX() /* - (double)(extend - w.GetMarginLeft() - w.GetMarginRight())/ w.GetScaleX() */) / step ) * step ;
+ double n = 0;
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(wxT("mpScaleX::Plot: dig: %f , step: %f, end: %f, n: %f"), dig, step, end, n0);
+#endif
+ wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft();
+ wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
+ wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
+ wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
+
+ tmp=-65535;
+ int labelH = 0; // Control labels heigth to decide where to put axis name (below labels or on top of axis)
+ int maxExtent = 0;
+ for (n = n0; n < end; n += step) {
+ const int p = (int)((n - w.GetPosX()) * w.GetScaleX());
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(wxT("mpScaleX::Plot: n: %f -> p = %d"), n, p);
+#endif
+ if ((p >= startPx) && (p <= endPx)) {
+ if (m_ticks) { // draw axis ticks
+ if (m_flags == mpALIGN_BORDER_BOTTOM)
+ dc.DrawLine( p, orgy, p, orgy-4);
+ else
+ dc.DrawLine( p, orgy, p, orgy+4);
+ } else { // draw grid dotted lines
+ m_pen.SetStyle(wxDOT);
+ dc.SetPen(m_pen);
+ if ((m_flags == mpALIGN_BOTTOM) && !m_drawOutsideMargins) {
+ dc.DrawLine( p, orgy+4, p, minYpx );
+ } else {
+ if ((m_flags == mpALIGN_TOP) && !m_drawOutsideMargins) {
+ dc.DrawLine( p, orgy-4, p, maxYpx );
+ } else {
+ dc.DrawLine( p, 0/*-w.GetScrY()*/, p, w.GetScrY() );
+ }
+ }
+ m_pen.SetStyle(wxSOLID);
+ dc.SetPen(m_pen);
+ }
+ // Write ticks labels in s string
+ if (m_labelType == mpX_NORMAL)
+ s.Printf(fmt, n);
+ else if (m_labelType == mpX_DATETIME) {
+ time_t when = (time_t)n;
+ struct tm tm = *localtime(&when);
+ s.Printf(fmt, (double)tm.tm_year+1900, (double)tm.tm_mon+1, (double)tm.tm_mday, (double)tm.tm_hour, (double)tm.tm_min, (double)tm.tm_sec);
+ } else if (m_labelType == mpX_DATE) {
+ time_t when = (time_t)n;
+ struct tm tm = *localtime(&when);
+ s.Printf(fmt, (double)tm.tm_year+1900, (double)tm.tm_mon+1, (double)tm.tm_mday);
+ } else if ((m_labelType == mpX_TIME) || (m_labelType == mpX_HOURS)) {
+ double modulus = fabs(n);
+ double sign = n/modulus;
+ double hh = floor(modulus/3600);
+ double mm = floor((modulus - hh*3600)/60);
+ double ss = modulus - hh*3600 - mm*60;
+ #ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(wxT("%02.0f Hours, %02.0f minutes, %02.0f seconds"), sign*hh, mm, ss);
+ #endif // MATHPLOT_DO_LOGGING
+ if (fmt.Len() == 20) // Format with hours has 11 chars
+ s.Printf(fmt, sign*hh, mm, floor(ss));
+ else
+ s.Printf(fmt, sign*mm, ss);
+ }
+ dc.GetTextExtent(s, &tx, &ty);
+ labelH = (labelH <= ty) ? ty : labelH;
+/* if ((p-tx/2-tmp) > 64) { // Problem about non-regular axis labels
+ if ((m_flags == mpALIGN_BORDER_BOTTOM) || (m_flags == mpALIGN_TOP)) {
+ dc.DrawText( s, p-tx/2, orgy-4-ty);
+ } else {
+ dc.DrawText( s, p-tx/2, orgy+4);
+ }
+ tmp=p+tx/2;
+ }
+ */
+ maxExtent = (tx > maxExtent) ? tx : maxExtent; // Keep in mind max label width
+ }
+ }
+ // Actually draw labels, taking care of not overlapping them, and distributing them regularly
+ double labelStep = ceil((maxExtent + mpMIN_X_AXIS_LABEL_SEPARATION)/(w.GetScaleX()*step))*step;
+ for (n = n0; n < end; n += labelStep) {
+ const int p = (int)((n - w.GetPosX()) * w.GetScaleX());
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(wxT("mpScaleX::Plot: n_label = %f -> p_label = %d"), n, p);
+#endif
+ if ((p >= startPx) && (p <= endPx)) {
+ // Write ticks labels in s string
+ if (m_labelType == mpX_NORMAL)
+ s.Printf(fmt, n);
+ else if (m_labelType == mpX_DATETIME) {
+ time_t when = (time_t)n;
+ struct tm tm = *localtime(&when);
+ s.Printf(fmt, (double)tm.tm_year+1900, (double)tm.tm_mon+1, (double)tm.tm_mday, (double)tm.tm_hour, (double)tm.tm_min, (double)tm.tm_sec);
+ } else if (m_labelType == mpX_DATE) {
+ time_t when = (time_t)n;
+ struct tm tm = *localtime(&when);
+ s.Printf(fmt, (double)tm.tm_year+1900, (double)tm.tm_mon+1, (double)tm.tm_mday);
+ } else if ((m_labelType == mpX_TIME) || (m_labelType == mpX_HOURS)) {
+ double modulus = fabs(n);
+ double sign = n/modulus;
+ double hh = floor(modulus/3600);
+ double mm = floor((modulus - hh*3600)/60);
+ double ss = modulus - hh*3600 - mm*60;
+ #ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(wxT("%02.0f Hours, %02.0f minutes, %02.0f seconds"), sign*hh, mm, ss);
+ #endif // MATHPLOT_DO_LOGGING
+ if (fmt.Len() == 20) // Format with hours has 11 chars
+ s.Printf(fmt, sign*hh, mm, floor(ss));
+ else
+ s.Printf(fmt, sign*mm, ss);
+ }
+ dc.GetTextExtent(s, &tx, &ty);
+ if ((m_flags == mpALIGN_BORDER_BOTTOM) || (m_flags == mpALIGN_TOP)) {
+ dc.DrawText( s, p-tx/2, orgy-4-ty);
+ } else {
+ dc.DrawText( s, p-tx/2, orgy+4);
+ }
+ }
+ }
+
+ // Draw axis name
+ dc.GetTextExtent(m_name, &tx, &ty);
+ switch (m_flags) {
+ case mpALIGN_BORDER_BOTTOM:
+ dc.DrawText( m_name, extend - tx - 4, orgy - 8 - ty - labelH);
+ break;
+ case mpALIGN_BOTTOM: {
+ if ((!m_drawOutsideMargins) && (w.GetMarginBottom() > (ty + labelH + 8))) {
+ dc.DrawText( m_name, (endPx - startPx - tx)>>1, orgy + 6 + labelH);
+ } else {
+ dc.DrawText( m_name, extend - tx - 4, orgy - 4 - ty);
+ }
+ } break;
+ case mpALIGN_CENTER:
+ dc.DrawText( m_name, extend - tx - 4, orgy - 4 - ty);
+ break;
+ case mpALIGN_TOP: {
+ if ((!m_drawOutsideMargins) && (w.GetMarginTop() > (ty + labelH + 8))) {
+ dc.DrawText( m_name, (endPx - startPx - tx)>>1, orgy - 6 - ty - labelH);
+ } else {
+ dc.DrawText( m_name, extend - tx - 4, orgy + 4);
+ }
+ } break;
+ case mpALIGN_BORDER_TOP:
+ dc.DrawText( m_name, extend - tx - 4, orgy + 6 + labelH);
+ break;
+ default:
+ break;
+ }
+ }
+/* if (m_flags != mpALIGN_TOP) {
+
+ if ((m_flags == mpALIGN_BORDER_BOTTOM) || (m_flags == mpALIGN_TOP)) {
+ dc.DrawText( m_name, extend - tx - 4, orgy - 4 - (ty*2));
+ } else {
+ dc.DrawText( m_name, extend - tx - 4, orgy - 4 - ty); //orgy + 4 + ty);
+ }
+ }; */
+}
+
+IMPLEMENT_DYNAMIC_CLASS(mpScaleY, mpLayer)
+
+mpScaleY::mpScaleY(wxString name, int flags, bool ticks)
+{
+ SetName(name);
+ SetFont( (wxFont&) *wxSMALL_FONT);
+ SetPen( (wxPen&) *wxGREY_PEN);
+ m_flags = flags;
+ m_ticks = ticks;
+ m_type = mpLAYER_AXIS;
+ m_labelFormat = wxT("");
+}
+
+void mpScaleY::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ dc.SetPen( m_pen);
+ dc.SetFont( m_font);
+
+ int orgx=0;
+ const int extend = w.GetScrY(); // /2;
+ if (m_flags == mpALIGN_CENTER)
+ orgx = w.x2p(0); //(int)(w.GetPosX() * w.GetScaleX());
+ if (m_flags == mpALIGN_LEFT) {
+ if (m_drawOutsideMargins)
+ orgx = Y_BORDER_SEPARATION;
+ else
+ orgx = w.GetMarginLeft();
+ }
+ if (m_flags == mpALIGN_RIGHT) {
+ if (m_drawOutsideMargins)
+ orgx = w.GetScrX() - Y_BORDER_SEPARATION;
+ else
+ orgx = w.GetScrX() - w.GetMarginRight();
+ }
+ if (m_flags == mpALIGN_BORDER_RIGHT )
+ orgx = w.GetScrX() - 1; //dc.LogicalToDeviceX(0) - 1;
+ if (m_flags == mpALIGN_BORDER_LEFT )
+ orgx = 1; //-dc.LogicalToDeviceX(0);
+
+ dc.SetBrush( wxBrush(w.GetBackgroundColour()) );
+ dc.SetPen( *wxTRANSPARENT_PEN );
+ dc.DrawRectangle( 0, 0, orgx, extend);
+ dc.DrawRectangle( w.GetScrX() - w.GetMarginRight(), 0, w.GetScrX() - w.GetMarginRight(), extend);
+ dc.SetPen( m_pen);
+
+ // Draw line
+ dc.DrawLine( orgx, w.GetMarginTop(), orgx, w.GetScrY() - w.GetMarginBottom());
+
+ // To cut the axis line when draw outside margin is false, use this code
+ /* if (m_drawOutsideMargins == true)
+ dc.DrawLine( orgx, 0, orgx, extend);
+ else
+ dc.DrawLine( orgx, w.GetMarginTop(), orgx, w.GetScrY() - w.GetMarginBottom()); */
+
+ const double dig = floor( log( 128.0 / w.GetScaleY() ) / mpLN10 );
+ const double step = exp( mpLN10 * dig);
+ const double end = w.GetPosY() + (double)extend / w.GetScaleY();
+
+ wxCoord tx, ty;
+ wxString s;
+ wxString fmt;
+ int tmp = (int)dig;
+ double maxScaleAbs = fabs(w.GetDesiredYmax());
+ double minScaleAbs = fabs(w.GetDesiredYmin());
+ double endscale = (maxScaleAbs > minScaleAbs) ? maxScaleAbs : minScaleAbs;
+ if (m_labelFormat.IsEmpty()) {
+ if ((endscale < 1e4) && (endscale > 1e-3))
+ fmt = wxT("%.2f");
+ else
+ fmt = wxT("%.1e");
+ } else {
+ fmt = m_labelFormat;
+ }
+ /* if (tmp>=1)
+ {*/
+ // fmt = wxT("%7.5g");
+ // }
+ // else
+ // {
+ // tmp=8-tmp;
+ // fmt.Printf(wxT("%%.%dg"), (tmp >= -1) ? 2 : -tmp);
+ // }
+
+ double n = floor( (w.GetPosY() - (double)(extend - w.GetMarginTop() - w.GetMarginBottom())/ w.GetScaleY()) / step ) * step ;
+
+ /* wxCoord startPx = m_drawOutsideMargins ? 0 : w.GetMarginLeft(); */
+ wxCoord endPx = m_drawOutsideMargins ? w.GetScrX() : w.GetScrX() - w.GetMarginRight();
+ wxCoord minYpx = m_drawOutsideMargins ? 0 : w.GetMarginTop();
+ wxCoord maxYpx = m_drawOutsideMargins ? w.GetScrY() : w.GetScrY() - w.GetMarginBottom();
+
+ tmp=65536;
+ int labelW = 0;
+ // Before staring cycle, calculate label height
+ int labelHeigth = 0;
+ s.Printf(fmt,n);
+ dc.GetTextExtent(s, &tx, &labelHeigth);
+ for (;n < end; n += step) {
+ const int p = (int)((w.GetPosY() - n) * w.GetScaleY());
+ if ((p >= minYpx) && (p <= maxYpx)) {
+ if (m_ticks) { // Draw axis ticks
+ if (m_flags == mpALIGN_BORDER_LEFT) {
+ dc.DrawLine( orgx, p, orgx+4, p);
+ } else {
+ dc.DrawLine( orgx-4, p, orgx, p); //( orgx, p, orgx+4, p);
+ }
+ } else {
+ m_pen.SetStyle(wxDOT);
+ dc.SetPen( m_pen);
+ if ((m_flags == mpALIGN_LEFT) && !m_drawOutsideMargins) {
+ dc.DrawLine( orgx-4, p, endPx, p);
+ } else {
+ if ((m_flags == mpALIGN_RIGHT) && !m_drawOutsideMargins) {
+ dc.DrawLine( minYpx, p, orgx+4, p);
+ } else {
+ dc.DrawLine( 0/*-w.GetScrX()*/, p, w.GetScrX(), p);
+ }
+ }
+ m_pen.SetStyle(wxSOLID);
+ dc.SetPen( m_pen);
+ }
+ // Print ticks labels
+ s.Printf(fmt, n);
+ dc.GetTextExtent(s, &tx, &ty);
+#ifdef MATHPLOT_DO_LOGGING
+ if (ty != labelHeigth) wxLogMessage(wxT("mpScaleY::Plot: ty(%f) and labelHeigth(%f) differ!"), ty, labelHeigth);
+#endif
+ labelW = (labelW <= tx) ? tx : labelW;
+ if ((tmp-p+labelHeigth/2) > mpMIN_Y_AXIS_LABEL_SEPARATION) {
+ if ((m_flags == mpALIGN_BORDER_LEFT) || (m_flags == mpALIGN_RIGHT))
+ dc.DrawText( s, orgx+4, p-ty/2);
+ else
+ dc.DrawText( s, orgx-4-tx, p-ty/2); //( s, orgx+4, p-ty/2);
+ tmp=p-labelHeigth/2;
+ }
+ }
+ }
+ // Draw axis name
+
+ dc.GetTextExtent(m_name, &tx, &ty);
+ switch (m_flags) {
+ case mpALIGN_BORDER_LEFT:
+ dc.DrawText( m_name, labelW + 8, 4);
+ break;
+ case mpALIGN_LEFT: {
+ if ((!m_drawOutsideMargins) && (w.GetMarginLeft() > (ty + labelW + 8))) {
+ dc.DrawRotatedText( m_name, orgx - 6 - labelW - ty, (maxYpx - minYpx + tx)>>1, 90);
+ } else {
+ dc.DrawText( m_name, orgx + 4, 4);
+ }
+ } break;
+ case mpALIGN_CENTER:
+ dc.DrawText( m_name, orgx + 4, 4);
+ break;
+ case mpALIGN_RIGHT: {
+ if ((!m_drawOutsideMargins) && (w.GetMarginRight() > (ty + labelW + 8))) {
+ dc.DrawRotatedText( m_name, orgx + 6 + labelW, (maxYpx - minYpx + tx)>>1, 90);
+ } else {
+ dc.DrawText( m_name, orgx - tx - 4, 4);
+ }
+ } break;
+ case mpALIGN_BORDER_RIGHT:
+ dc.DrawText( m_name, orgx - 6 - tx -labelW, 4);
+ break;
+ default:
+ break;
+ }
+ }
+
+/* if (m_flags != mpALIGN_RIGHT) {
+ dc.GetTextExtent(m_name, &tx, &ty);
+ if (m_flags == mpALIGN_BORDER_LEFT) {
+ dc.DrawText( m_name, orgx-tx-4, -extend + ty + 4);
+ } else {
+ if (m_flags == mpALIGN_BORDER_RIGHT )
+ dc.DrawText( m_name, orgx-(tx*2)-4, -extend + ty + 4);
+ else
+ dc.DrawText( m_name, orgx + 4, -extend + 4);
+ }
+ }; */
+}
+
+//-----------------------------------------------------------------------------
+// mpWindow
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(mpWindow, wxWindow)
+
+BEGIN_EVENT_TABLE(mpWindow, wxWindow)
+ EVT_PAINT ( mpWindow::OnPaint)
+ EVT_SIZE ( mpWindow::OnSize)
+ EVT_SCROLLWIN_THUMBTRACK(mpWindow::OnScrollThumbTrack)
+ EVT_SCROLLWIN_PAGEUP(mpWindow::OnScrollPageUp)
+ EVT_SCROLLWIN_PAGEDOWN(mpWindow::OnScrollPageDown)
+ EVT_SCROLLWIN_LINEUP(mpWindow::OnScrollLineUp)
+ EVT_SCROLLWIN_LINEDOWN(mpWindow::OnScrollLineDown)
+ EVT_SCROLLWIN_TOP(mpWindow::OnScrollTop)
+ EVT_SCROLLWIN_BOTTOM(mpWindow::OnScrollBottom)
+
+ EVT_MIDDLE_UP( mpWindow::OnShowPopupMenu)
+ EVT_RIGHT_DOWN( mpWindow::OnMouseRightDown) // JLB
+ EVT_RIGHT_UP ( mpWindow::OnShowPopupMenu)
+ EVT_MOUSEWHEEL( mpWindow::OnMouseWheel ) // JLB
+ EVT_MOTION( mpWindow::OnMouseMove ) // JLB
+ EVT_LEFT_DOWN( mpWindow::OnMouseLeftDown)
+ EVT_LEFT_UP( mpWindow::OnMouseLeftRelease)
+
+ EVT_MENU( mpID_CENTER, mpWindow::OnCenter)
+ EVT_MENU( mpID_FIT, mpWindow::OnFit)
+ EVT_MENU( mpID_ZOOM_IN, mpWindow::OnZoomIn)
+ EVT_MENU( mpID_ZOOM_OUT, mpWindow::OnZoomOut)
+ EVT_MENU( mpID_LOCKASPECT,mpWindow::OnLockAspect)
+ EVT_MENU( mpID_HELP_MOUSE,mpWindow::OnMouseHelp)
+END_EVENT_TABLE()
+
+mpWindow::mpWindow( wxWindow *parent, wxWindowID id, const wxPoint &pos, const wxSize &size, long flag )
+ : wxWindow( parent, id, pos, size, flag, wxT("mathplot") )
+{
+ selectionRect = wxRect(0,0,0,0);
+ srColour = *wxBLACK;
+
+ m_scaleX = m_scaleY = 1.0;
+ m_posX = m_posY = 0;
+ m_desiredXmin=m_desiredYmin=0;
+ m_desiredXmax=m_desiredYmax=1;
+ m_scrX = m_scrY = 64; // Fixed from m_scrX = m_scrX = 64;
+ m_minX = m_minY = 0;
+ m_maxX = m_maxY = 0;
+ m_last_lx= m_last_ly= 0;
+ m_buff_bmp = NULL;
+ m_enableDoubleBuffer = FALSE;
+ m_enableMouseNavigation = TRUE;
+ m_mouseMovedAfterRightClick = FALSE;
+ m_movingInfoLayer = NULL;
+ // Set margins to 0
+ m_marginTop = 0; m_marginRight = 0; m_marginBottom = 0; m_marginLeft = 0;
+
+
+ m_lockaspect = FALSE;
+
+ m_popmenu.Append( mpID_CENTER, _("Centralizar"), _("Centraliza a vizualização gráfico nesta posição"));
+ m_popmenu.Append( mpID_FIT, _("Encaixar"), _("Ajusta a vizualização para exibição de todos os itens"));
+ m_popmenu.Append( mpID_ZOOM_IN, _("Mais Zoom"), _("Mais Zoom na vizualização do gráfico."));
+ m_popmenu.Append( mpID_ZOOM_OUT, _("Menos Zoom"), _("Menos Zoom na vizualização do gráfico."));
+ m_popmenu.AppendCheckItem( mpID_LOCKASPECT, _("Bloquear proporções"), _("Bloquear as proporções do zoom horizontal e vertical."));
+ m_popmenu.Append( mpID_HELP_MOUSE, _("Mostrar comandos do mouse..."), _("Exibe a ajuda sobre os comandos do mouse."));
+
+ m_layers.clear();
+ SetBackgroundColour( *wxWHITE );
+ m_bgColour = *wxWHITE;
+ m_fgColour = *wxBLACK;
+
+ m_enableScrollBars = false;
+ SetSizeHints(128, 128);
+
+ // J.L.Blanco: Eliminates the "flick" with the double buffer.
+ SetBackgroundStyle( wxBG_STYLE_CUSTOM );
+
+ UpdateAll();
+}
+
+mpWindow::~mpWindow()
+{
+ // Free all the layers:
+ DelAllLayers( true, false );
+
+ if (m_buff_bmp)
+ {
+ delete m_buff_bmp;
+ m_buff_bmp = NULL;
+ }
+}
+
+// Mouse handler, for detecting when the user drag with the right button or just "clicks" for the menu
+// JLB
+void mpWindow::OnMouseRightDown(wxMouseEvent &event)
+{
+ m_mouseMovedAfterRightClick = FALSE;
+ m_mouseRClick_X = event.GetX();
+ m_mouseRClick_Y = event.GetY();
+ if (m_enableMouseNavigation)
+ {
+ SetCursor( *wxCROSS_CURSOR );
+ }
+}
+
+// Process mouse wheel events
+// JLB
+void mpWindow::OnMouseWheel( wxMouseEvent &event )
+{
+ if (!m_enableMouseNavigation)
+ {
+ event.Skip();
+ return;
+ }
+
+// GetClientSize( &m_scrX,&m_scrY);
+
+ if (event.m_controlDown)
+ {
+ wxPoint clickPt( event.GetX(),event.GetY() );
+ // CTRL key hold: Zoom in/out:
+ if (event.GetWheelRotation()>0)
+ ZoomIn( clickPt );
+ else ZoomOut( clickPt );
+ }
+ else
+ {
+ // Scroll vertically or horizontally (this is SHIFT is hold down).
+ int change = - event.GetWheelRotation(); // Opposite direction (More intuitive)!
+ double changeUnitsX = change / m_scaleX;
+ double changeUnitsY = change / m_scaleY;
+
+ if (event.m_shiftDown)
+ {
+ m_posX += changeUnitsX;
+ m_desiredXmax += changeUnitsX;
+ m_desiredXmin += changeUnitsX;
+ }
+ else
+ {
+ m_posY -= changeUnitsY;
+ m_desiredYmax -= changeUnitsY;
+ m_desiredYmax -= changeUnitsY;
+ }
+
+ UpdateAll();
+ }
+}
+
+// If the user "drags" with the right buttom pressed, do "pan"
+// JLB
+void mpWindow::OnMouseMove(wxMouseEvent &event)
+{
+ if (!m_enableMouseNavigation)
+ {
+ event.Skip();
+ return;
+ }
+
+ if (event.m_rightDown)
+ {
+ m_mouseMovedAfterRightClick = TRUE; // Hides the popup menu after releasing the button!
+
+ // The change:
+ int Ax= m_mouseRClick_X - event.GetX();
+ int Ay= m_mouseRClick_Y - event.GetY();
+
+ // For the next event, use relative to this coordinates.
+ m_mouseRClick_X = event.GetX();
+ m_mouseRClick_Y = event.GetY();
+
+ double Ax_units = Ax / m_scaleX;
+ double Ay_units = -Ay / m_scaleY;
+
+ m_posX += Ax_units;
+ m_posY += Ay_units;
+ m_desiredXmax += Ax_units;
+ m_desiredXmin += Ax_units;
+ m_desiredYmax += Ay_units;
+ m_desiredYmin += Ay_units;
+
+ UpdateAll();
+
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("[mpWindow::OnMouseMove] Ax:%i Ay:%i m_posX:%f m_posY:%f"),Ax,Ay,m_posX,m_posY);
+#endif
+ } else {
+ if (event.m_leftDown) {
+ if (m_movingInfoLayer == NULL) {
+ /*wxClientDC dc(this);
+ wxPen pen(*wxBLACK, 1, wxDOT);
+ dc.SetPen(pen);
+ dc.SetBrush(*wxTRANSPARENT_BRUSH);
+ dc.DrawRectangle(m_mouseLClick_X, m_mouseLClick_Y, event.GetX() - m_mouseLClick_X, event.GetY() - m_mouseLClick_Y);*/
+ selectionRect = wxRect(m_mouseLClick_X, m_mouseLClick_Y, event.GetX() - m_mouseLClick_X, event.GetY() - m_mouseLClick_Y);
+ } else {
+ wxPoint moveVector(event.GetX() - m_mouseLClick_X, event.GetY() - m_mouseLClick_Y);
+ m_movingInfoLayer->Move(moveVector);
+ }
+ UpdateAll();
+ } else {
+ wxLayerList::iterator li;
+ for (li = m_layers.begin(); li != m_layers.end(); li++) {
+ if ((*li)->IsInfo() && (*li)->IsVisible()) {
+ mpInfoLayer* tmpLyr = (mpInfoLayer*) (*li);
+ tmpLyr->UpdateInfo(*this, event);
+ // UpdateAll();
+ RefreshRect(tmpLyr->GetRectangle());
+ }
+ }
+ /* if (m_coordTooltip) {
+ wxString toolTipContent;
+ toolTipContent.Printf(_("X = %f\nY = %f"), p2x(event.GetX()), p2y(event.GetY()));
+ wxTipWindow** ptr = NULL;
+ wxRect rectBounds(event.GetX(), event.GetY(), 5, 5);
+ wxTipWindow* tip = new wxTipWindow(this, toolTipContent, 100, ptr, &rectBounds);
+
+ } */
+ }
+ }
+ event.Skip();
+}
+
+void mpWindow::OnMouseLeftDown (wxMouseEvent &event)
+{
+ m_mouseLClick_X = event.GetX();
+ m_mouseLClick_Y = event.GetY();
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::OnMouseLeftDown() X = %d , Y = %d"), event.GetX(), event.GetY());/*m_mouseLClick_X, m_mouseLClick_Y);*/
+#endif
+ wxPoint pointClicked = event.GetPosition();
+ m_movingInfoLayer = IsInsideInfoLayer(pointClicked);
+ if (m_movingInfoLayer != NULL) {
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::OnMouseLeftDown() started moving layer %lx"), (long int) m_movingInfoLayer);/*m_mouseLClick_X, m_mouseLClick_Y);*/
+#endif
+ }
+ /*/Modificação - Thales 22/06/2015
+ if(event.Dragging() && m_movingInfoLayer == NULL)
+ {
+ wxClientDC dc(this);
+ wxPen pen(*wxBLACK, 1, wxDOT);
+ dc.SetPen(pen);
+ dc.SetBrush(*wxTRANSPARENT_BRUSH);
+ dc.DrawRectangle(m_mouseLClick_X, m_mouseLClick_Y, event.GetX() - m_mouseLClick_X, event.GetY() - m_mouseLClick_Y);
+ }*/
+ event.Skip();
+}
+
+void mpWindow::OnMouseLeftRelease (wxMouseEvent &event)
+{
+ wxPoint release(event.GetX(), event.GetY());
+ wxPoint press(m_mouseLClick_X, m_mouseLClick_Y);
+ if (m_movingInfoLayer != NULL) {
+ m_movingInfoLayer->UpdateReference();
+ m_movingInfoLayer = NULL;
+ } else {
+ if (release != press) {
+ ZoomRect(press, release);
+ } /*else {
+ if (m_coordTooltip) {
+ wxString toolTipContent;
+ toolTipContent.Printf(_("X = %f\nY = %f"), p2x(event.GetX()), p2y(event.GetY()));
+ SetToolTip(toolTipContent);
+ }
+ } */
+ }
+ selectionRect = wxRect(0,0,0,0);
+ event.Skip();
+}
+
+void mpWindow::Fit()
+{
+ if (UpdateBBox())
+ Fit(m_minX ,m_maxX ,m_minY ,m_maxY );
+}
+
+
+// JL
+void mpWindow::Fit(double xMin, double xMax, double yMin, double yMax, wxCoord *printSizeX,wxCoord *printSizeY)
+{
+ // Save desired borders:
+ m_desiredXmin=xMin; m_desiredXmax=xMax;
+ m_desiredYmin=yMin; m_desiredYmax=yMax;
+
+ if (printSizeX!=NULL && printSizeY!=NULL)
+ {
+ // Printer:
+ m_scrX = *printSizeX;
+ m_scrY = *printSizeY;
+ }
+ else
+ {
+ // Normal case (screen):
+ GetClientSize( &m_scrX,&m_scrY);
+ }
+
+ double Ax,Ay;
+
+ Ax = xMax - xMin;
+ Ay = yMax - yMin;
+
+ m_scaleX = (Ax!=0) ? (m_scrX - m_marginLeft - m_marginRight)/Ax : 1; //m_scaleX = (Ax!=0) ? m_scrX/Ax : 1;
+ m_scaleY = (Ay!=0) ? (m_scrY - m_marginTop - m_marginBottom)/Ay : 1; //m_scaleY = (Ay!=0) ? m_scrY/Ay : 1;
+
+ if (m_lockaspect)
+ {
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::Fit()(lock) m_scaleX=%f,m_scaleY=%f"), m_scaleX,m_scaleY);
+#endif
+ // Keep the lowest "scale" to fit the whole range required by that axis (to actually "fit"!):
+ double s = m_scaleX < m_scaleY ? m_scaleX : m_scaleY;
+ m_scaleX = s;
+ m_scaleY = s;
+ }
+
+ // Adjusts corner coordinates: This should be simply:
+ // m_posX = m_minX;
+ // m_posY = m_maxY;
+ // But account for centering if we have lock aspect:
+ m_posX = (xMin+xMax)/2 - ((m_scrX - m_marginLeft - m_marginRight)/2 + m_marginLeft)/m_scaleX ; // m_posX = (xMin+xMax)/2 - (m_scrX/2)/m_scaleX;
+// 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;
+ 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;
+
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::Fit() m_desiredXmin=%f m_desiredXmax=%f m_desiredYmin=%f m_desiredYmax=%f"), xMin,xMax,yMin,yMax);
+ wxLogMessage(_("mpWindow::Fit() m_scaleX = %f , m_scrX = %d,m_scrY=%d, Ax=%f, Ay=%f, m_posX=%f, m_posY=%f"), m_scaleX, m_scrX,m_scrY, Ax,Ay,m_posX,m_posY);
+#endif
+
+ // It is VERY IMPORTANT to DO NOT call Refresh if we are drawing to the printer!!
+ // Otherwise, the DC dimensions will be those of the window instead of the printer device
+ if (printSizeX==NULL || printSizeY==NULL)
+ UpdateAll();
+}
+
+// Patch ngpaton
+void mpWindow::DoZoomInXCalc (const int staticXpixel)
+{
+ // Preserve the position of the clicked point:
+ double staticX = p2x( staticXpixel );
+ // Zoom in:
+ m_scaleX = m_scaleX * zoomIncrementalFactor;
+ // Adjust the new m_posx
+ m_posX = staticX - (staticXpixel / m_scaleX);
+ // Adjust desired
+ m_desiredXmin = m_posX;
+ m_desiredXmax = m_posX + (m_scrX - (m_marginLeft + m_marginRight)) / m_scaleX;
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::DoZoomInXCalc() prior X coord: (%f), new X coord: (%f) SHOULD BE EQUAL!!"), staticX, p2x(staticXpixel));
+#endif
+}
+
+void mpWindow::DoZoomInYCalc (const int staticYpixel)
+{
+ // Preserve the position of the clicked point:
+ double staticY = p2y( staticYpixel );
+ // Zoom in:
+ m_scaleY = m_scaleY * zoomIncrementalFactor;
+ // Adjust the new m_posy:
+ m_posY = staticY + (staticYpixel / m_scaleY);
+ // Adjust desired
+ m_desiredYmax = m_posY;
+ m_desiredYmin = m_posY - (m_scrY - (m_marginTop + m_marginBottom)) / m_scaleY;
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::DoZoomInYCalc() prior Y coord: (%f), new Y coord: (%f) SHOULD BE EQUAL!!"), staticY, p2y(staticYpixel));
+#endif
+}
+
+void mpWindow::DoZoomOutXCalc (const int staticXpixel)
+{
+ // Preserve the position of the clicked point:
+ double staticX = p2x( staticXpixel );
+ // Zoom out:
+ m_scaleX = m_scaleX / zoomIncrementalFactor;
+ // Adjust the new m_posx/y:
+ m_posX = staticX - (staticXpixel / m_scaleX);
+ // Adjust desired
+ m_desiredXmin = m_posX;
+ m_desiredXmax = m_posX + (m_scrX - (m_marginLeft + m_marginRight)) / m_scaleX;
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::DoZoomOutXCalc() prior X coord: (%f), new X coord: (%f) SHOULD BE EQUAL!!"), staticX, p2x(staticXpixel));
+#endif
+}
+
+void mpWindow::DoZoomOutYCalc (const int staticYpixel)
+{
+ // Preserve the position of the clicked point:
+ double staticY = p2y( staticYpixel );
+ // Zoom out:
+ m_scaleY = m_scaleY / zoomIncrementalFactor;
+ // Adjust the new m_posx/y:
+ m_posY = staticY + (staticYpixel / m_scaleY);
+ // Adjust desired
+ m_desiredYmax = m_posY;
+ m_desiredYmin = m_posY - (m_scrY - (m_marginTop + m_marginBottom)) / m_scaleY;
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::DoZoomOutYCalc() prior Y coord: (%f), new Y coord: (%f) SHOULD BE EQUAL!!"), staticY, p2y(staticYpixel));
+#endif
+}
+
+
+void mpWindow::ZoomIn(const wxPoint& centerPoint )
+{
+ wxPoint c(centerPoint);
+ if (c == wxDefaultPosition)
+ {
+ GetClientSize(&m_scrX, &m_scrY);
+ c.x = (m_scrX - m_marginLeft - m_marginRight)/2 + m_marginLeft; // c.x = m_scrX/2;
+ c.y = (m_scrY - m_marginTop - m_marginBottom)/2 - m_marginTop; // c.y = m_scrY/2;
+}
+
+ // Preserve the position of the clicked point:
+ double prior_layer_x = p2x( c.x );
+ double prior_layer_y = p2y( c.y );
+
+ // Zoom in:
+ m_scaleX = m_scaleX * zoomIncrementalFactor;
+ m_scaleY = m_scaleY * zoomIncrementalFactor;
+
+ // Adjust the new m_posx/y:
+ m_posX = prior_layer_x - c.x / m_scaleX;
+ m_posY = prior_layer_y + c.y / m_scaleY;
+
+ m_desiredXmin = m_posX;
+ m_desiredXmax = m_posX + (m_scrX - m_marginLeft - m_marginRight) / m_scaleX; // m_desiredXmax = m_posX + m_scrX / m_scaleX;
+ m_desiredYmax = m_posY;
+ m_desiredYmin = m_posY - (m_scrY - m_marginTop - m_marginBottom) / m_scaleY; // m_desiredYmin = m_posY - m_scrY / m_scaleY;
+
+
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::ZoomIn() prior coords: (%f,%f), new coords: (%f,%f) SHOULD BE EQUAL!!"), prior_layer_x,prior_layer_y, p2x(c.x),p2y(c.y));
+#endif
+
+ UpdateAll();
+}
+
+void mpWindow::ZoomOut(const wxPoint& centerPoint )
+{
+ wxPoint c(centerPoint);
+ if (c == wxDefaultPosition)
+ {
+ GetClientSize(&m_scrX, &m_scrY);
+ c.x = (m_scrX - m_marginLeft - m_marginRight)/2 + m_marginLeft; // c.x = m_scrX/2;
+ c.y = (m_scrY - m_marginTop - m_marginBottom)/2 - m_marginTop; // c.y = m_scrY/2;
+ }
+
+ // Preserve the position of the clicked point:
+ double prior_layer_x = p2x( c.x );
+ double prior_layer_y = p2y( c.y );
+
+ // Zoom out:
+ m_scaleX = m_scaleX / zoomIncrementalFactor;
+ m_scaleY = m_scaleY / zoomIncrementalFactor;
+
+ // Adjust the new m_posx/y:
+ m_posX = prior_layer_x - c.x / m_scaleX;
+ m_posY = prior_layer_y + c.y / m_scaleY;
+
+ m_desiredXmin = m_posX;
+ m_desiredXmax = m_posX + (m_scrX - m_marginLeft - m_marginRight) / m_scaleX; // m_desiredXmax = m_posX + m_scrX / m_scaleX;
+ m_desiredYmax = m_posY;
+ m_desiredYmin = m_posY - (m_scrY - m_marginTop - m_marginBottom) / m_scaleY; // m_desiredYmin = m_posY - m_scrY / m_scaleY;
+
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::ZoomOut() prior coords: (%f,%f), new coords: (%f,%f) SHOULD BE EQUAL!!"), prior_layer_x,prior_layer_y, p2x(c.x),p2y(c.y));
+#endif
+ UpdateAll();
+}
+
+void mpWindow::ZoomInX()
+{
+ m_scaleX = m_scaleX * zoomIncrementalFactor;
+ UpdateAll();
+}
+
+void mpWindow::ZoomOutX()
+{
+ m_scaleX = m_scaleX / zoomIncrementalFactor;
+ UpdateAll();
+}
+
+void mpWindow::ZoomInY()
+{
+ m_scaleY = m_scaleY * zoomIncrementalFactor;
+ UpdateAll();
+}
+
+void mpWindow::ZoomOutY()
+{
+ m_scaleY = m_scaleY / zoomIncrementalFactor;
+ UpdateAll();
+}
+
+void mpWindow::ZoomRect(wxPoint p0, wxPoint p1)
+{
+ // Compute the 2 corners in graph coordinates:
+ double p0x = p2x(p0.x);
+ double p0y = p2y(p0.y);
+ double p1x = p2x(p1.x);
+ double p1y = p2y(p1.y);
+
+ // Order them:
+ double zoom_x_min = p0x<p1x ? p0x:p1x;
+ double zoom_x_max = p0x>p1x ? p0x:p1x;
+ double zoom_y_min = p0y<p1y ? p0y:p1y;
+ double zoom_y_max = p0y>p1y ? p0y:p1y;
+
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("Zoom: (%f,%f)-(%f,%f)"),zoom_x_min,zoom_y_min,zoom_x_max,zoom_y_max);
+#endif
+
+ Fit(zoom_x_min,zoom_x_max,zoom_y_min,zoom_y_max);
+}
+
+void mpWindow::LockAspect(bool enable)
+{
+ m_lockaspect = enable;
+ m_popmenu.Check(mpID_LOCKASPECT, enable);
+
+ // Try to fit again with the new config:
+ Fit( m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax );
+}
+
+void mpWindow::OnShowPopupMenu(wxMouseEvent &event)
+{
+ // Only display menu if the user has not "dragged" the figure
+ if (m_enableMouseNavigation)
+ {
+ SetCursor( *wxSTANDARD_CURSOR );
+ }
+
+ if (!m_mouseMovedAfterRightClick) // JLB
+ {
+ m_clickedX = event.GetX();
+ m_clickedY = event.GetY();
+ PopupMenu( &m_popmenu, event.GetX(), event.GetY());
+ }
+}
+
+void mpWindow::OnLockAspect(wxCommandEvent& WXUNUSED(event))
+{
+ LockAspect( !m_lockaspect );
+}
+
+void mpWindow::OnMouseHelp(wxCommandEvent& WXUNUSED(event))
+{
+ wxMessageBox(_("Comandos suportados:\n \
+ - Botão esquerdo e arrastar: Zoom no retângulo\n \
+ - Botão direito e arrastar: Arrasta o gráfico\n \
+ - Wheel: Deslocamento vertical\n \
+ - Wheel + SHIFT: Deslocamento horizontal\n \
+ - Wheel + CTRL: Mais Zoom/Menos Zoom"),_("Ajuda"),wxOK,this);
+}
+
+void mpWindow::OnFit(wxCommandEvent& WXUNUSED(event))
+{
+ Fit();
+}
+
+void mpWindow::OnCenter(wxCommandEvent& WXUNUSED(event))
+{
+ GetClientSize(&m_scrX, &m_scrY);
+ int centerX = (m_scrX - m_marginLeft - m_marginRight)/2; // + m_marginLeft; // c.x = m_scrX/2;
+ int centerY = (m_scrY - m_marginTop - m_marginBottom)/2; // - m_marginTop; // c.y = m_scrY/2;
+ SetPos( p2x(m_clickedX - centerX), p2y(m_clickedY - centerY) );
+ //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);
+}
+
+void mpWindow::OnZoomIn(wxCommandEvent& WXUNUSED(event))
+{
+ ZoomIn( wxPoint(m_mouseRClick_X,m_mouseRClick_Y) );
+}
+
+void mpWindow::OnZoomOut(wxCommandEvent& WXUNUSED(event))
+{
+ ZoomOut();
+}
+
+void mpWindow::OnSize( wxSizeEvent& WXUNUSED(event) )
+{
+ // Try to fit again with the new window size:
+ Fit( m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax );
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::OnSize() m_scrX = %d, m_scrY = %d"), m_scrX, m_scrY);
+#endif // MATHPLOT_DO_LOGGING
+}
+
+bool mpWindow::AddLayer( mpLayer* layer, bool refreshDisplay )
+{
+ if (layer != NULL) {
+ m_layers.push_back( layer );
+ if (refreshDisplay) UpdateAll();
+ return true;
+ };
+ return false;
+}
+
+bool mpWindow::DelLayer(
+ mpLayer* layer,
+ bool alsoDeleteObject,
+ bool refreshDisplay )
+{
+ wxLayerList::iterator layIt;
+ for (layIt = m_layers.begin(); layIt != m_layers.end(); layIt++)
+ {
+ if (*layIt == layer)
+ {
+ // Also delete the object?
+ if (alsoDeleteObject)
+ delete *layIt;
+ m_layers.erase(layIt); // this deleted the reference only
+ if (refreshDisplay)
+ UpdateAll();
+ return true;
+ }
+ }
+ return false;
+}
+
+void mpWindow::DelAllLayers( bool alsoDeleteObject, bool refreshDisplay)
+{
+ while ( m_layers.size()>0 )
+ {
+ // Also delete the object?
+ if (alsoDeleteObject) delete m_layers[0];
+ m_layers.erase( m_layers.begin() ); // this deleted the reference only
+ }
+ if (refreshDisplay) UpdateAll();
+}
+
+// void mpWindow::DoPrepareDC(wxDC& dc)
+// {
+// dc.SetDeviceOrigin(x2p(m_minX), y2p(m_maxY));
+// }
+
+void mpWindow::OnPaint( wxPaintEvent& WXUNUSED(event) )
+{
+ wxPaintDC dc(this);
+ dc.GetSize(&m_scrX, &m_scrY); // This is the size of the visible area only!
+// DoPrepareDC(dc);
+
+#ifdef MATHPLOT_DO_LOGGING
+ {
+ int px, py;
+ GetViewStart( &px, &py );
+ wxLogMessage(_("[mpWindow::OnPaint] vis.area:%ix%i px=%i py=%i"),m_scrX,m_scrY,px,py);
+ }
+#endif
+
+ // Selects direct or buffered draw:
+ wxDC *trgDc;
+
+ // J.L.Blanco @ Aug 2007: Added double buffer support
+ if (m_enableDoubleBuffer)
+ {
+ if (m_last_lx!=m_scrX || m_last_ly!=m_scrY)
+ {
+ if (m_buff_bmp) delete m_buff_bmp;
+ m_buff_bmp = new wxBitmap(m_scrX,m_scrY);
+ m_buff_dc.SelectObject(*m_buff_bmp);
+ m_last_lx=m_scrX;
+ m_last_ly=m_scrY;
+ }
+ trgDc = &m_buff_dc;
+ }
+ else
+ {
+ trgDc = &dc;
+ }
+
+ // Draw background:
+ //trgDc->SetDeviceOrigin(0,0);
+ trgDc->SetPen( *wxTRANSPARENT_PEN );
+ wxBrush brush( GetBackgroundColour() );
+ trgDc->SetBrush( brush );
+ trgDc->SetTextForeground(m_fgColour);
+ trgDc->DrawRectangle(0,0,m_scrX,m_scrY);
+
+ // Draw all the layers:
+ //trgDc->SetDeviceOrigin( m_scrX>>1, m_scrY>>1); // Origin at the center
+ wxLayerList::iterator li;
+ for (li = m_layers.begin(); li != m_layers.end(); li++)
+ {
+ (*li)->Plot(*trgDc, *this);
+ };
+
+ // If doublebuffer, draw now to the window:
+ if (m_enableDoubleBuffer)
+ {
+ //trgDc->SetDeviceOrigin(0,0);
+ //dc.SetDeviceOrigin(0,0); // Origin at the center
+ dc.Blit(0,0,m_scrX,m_scrY,trgDc,0,0);
+ }
+
+/* if (m_coordTooltip) {
+ wxString toolTipContent;
+ wxPoint mousePoint = wxGetMousePosition();
+ toolTipContent.Printf(_("X = %f\nY = %f"), p2x(mousePoint.x), p2y(mousePoint.y));
+ SetToolTip(toolTipContent);
+ }*/
+ // If scrollbars are enabled, refresh them
+ if (m_enableScrollBars) {
+/* m_scrollX = (int) floor((m_posX - m_minX)*m_scaleX);
+ m_scrollY = (int) floor((m_maxY - m_posY )*m_scaleY);
+ Scroll(m_scrollX, m_scrollY);*/
+ // Scroll(x2p(m_posX), y2p(m_posY));
+// SetVirtualSize((int) ((m_maxX - m_minX)*m_scaleX), (int) ((m_maxY - m_minY)*m_scaleY));
+// int centerX = (m_scrX - m_marginLeft - m_marginRight)/2; // + m_marginLeft; // c.x = m_scrX/2;
+// int centerY = (m_scrY - m_marginTop - m_marginBottom)/2; // - m_marginTop; // c.y = m_scrY/2;
+ /*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);
+}
+ wxPen pen(srColour, 1, wxDOT);
+ dc.SetPen(pen);
+ dc.SetBrush(*wxTRANSPARENT_BRUSH);
+ dc.DrawRectangle(selectionRect);
+}
+
+// void mpWindow::OnScroll2(wxScrollWinEvent &event)
+// {
+// #ifdef MATHPLOT_DO_LOGGING
+// wxLogMessage(_("[mpWindow::OnScroll2] Init: m_posX=%f m_posY=%f, sc_pos = %d"),m_posX,m_posY, event.GetPosition());
+// #endif
+// // If scrollbars are not enabled, Skip operation
+// if (!m_enableScrollBars) {
+// event.Skip();
+// return;
+// }
+// // m_scrollX = (int) floor((m_posX - m_minX)*m_scaleX);
+// // m_scrollY = (int) floor((m_maxY - m_posY /*- m_minY*/)*m_scaleY);
+// // Scroll(m_scrollX, m_scrollY);
+//
+// // GetClientSize( &m_scrX, &m_scrY);
+// //Scroll(x2p(m_desiredXmin), y2p(m_desiredYmin));
+// int pixelStep = 1;
+// if (event.GetOrientation() == wxHORIZONTAL) {
+// //m_desiredXmin -= (m_scrollX - event.GetPosition())/m_scaleX;
+// //m_desiredXmax -= (m_scrollX - event.GetPosition())/m_scaleX;
+// m_posX -= (m_scrollX - event.GetPosition())/m_scaleX;
+// m_scrollX = event.GetPosition();
+// }
+// Fit(m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax);
+// // /* int pixelStep = 1;
+// // if (event.GetOrientation() == wxHORIZONTAL) {
+// // m_posX -= (px - event.GetPosition())/m_scaleX;//(pixelStep/m_scaleX);
+// // m_desiredXmax -= (px - event.GetPosition())/m_scaleX;//(pixelStep/m_scaleX);
+// // m_desiredXmin -= (px - event.GetPosition())/m_scaleX;//(pixelStep/m_scaleX);
+// // //SetPosX( (double)px / GetScaleX() + m_minX + (double)(width>>1)/GetScaleX());
+// // // m_posX = p2x(px); //m_minX + (double)(px /*+ (m_scrX)*/)/GetScaleX();
+// // } else {
+// // m_posY += (py - event.GetPosition())/m_scaleY;//(pixelStep/m_scaleY);
+// // m_desiredYmax += (py - event.GetPosition())/m_scaleY;//(pixelStep/m_scaleY);
+// // m_desiredYmax += (py - event.GetPosition())/m_scaleY;//(pixelStep/m_scaleY);
+// // //SetPosY( m_maxY - (double)py / GetScaleY() - (double)(height>>1)/GetScaleY());
+// // //m_posY = m_maxY - (double)py / GetScaleY() - (double)(height>>1)/GetScaleY();
+// // // m_posY = p2y(py);//m_maxY - (double)(py /*+ (m_scrY)*/)/GetScaleY();
+// // }*/
+// #ifdef MATHPLOT_DO_LOGGING
+// int px, py;
+// GetViewStart( &px, &py);
+// wxLogMessage(_("[mpWindow::OnScroll2] End: m_posX = %f, m_posY = %f, px = %f, py = %f"),m_posX, m_posY, px, py);
+// #endif
+//
+// UpdateAll();
+// // event.Skip();
+// }
+
+void mpWindow::SetMPScrollbars(bool status)
+{
+ // Temporary behaviour: always disable scrollbars
+ m_enableScrollBars = status; //false;
+ if (status == false)
+ {
+ SetScrollbar(wxHORIZONTAL, 0, 0, 0);
+ SetScrollbar(wxVERTICAL, 0, 0, 0);
+ }
+ // else the scroll bars will be updated in UpdateAll();
+ UpdateAll();
+
+// EnableScrolling(false, false);
+// m_enableScrollBars = status;
+// EnableScrolling(status, status);
+/* m_scrollX = (int) floor((m_posX - m_minX)*m_scaleX);
+ m_scrollY = (int) floor((m_posY - m_minY)*m_scaleY);*/
+// int scrollWidth = (int) floor((m_maxX - m_minX)*m_scaleX) - m_scrX;
+// int scrollHeight = (int) floor((m_minY - m_maxY)*m_scaleY) - m_scrY;
+
+// /* m_scrollX = (int) floor((m_posX - m_minX)*m_scaleX);
+// m_scrollY = (int) floor((m_maxY - m_posY /*- m_minY*/)*m_scaleY);
+// int scrollWidth = (int) floor(((m_maxX - m_minX) - (m_desiredXmax - m_desiredXmin))*m_scaleX);
+// int scrollHeight = (int) floor(((m_maxY - m_minY) - (m_desiredYmax - m_desiredYmin))*m_scaleY);
+// #ifdef MATHPLOT_DO_LOGGING
+// wxLogMessage(_("mpWindow::SetMPScrollbars() scrollWidth = %d, scrollHeight = %d"), scrollWidth, scrollHeight);
+// #endif
+// if(status) {
+// SetScrollbars(1,
+// 1,
+// scrollWidth,
+// scrollHeight,
+// m_scrollX,
+// m_scrollY);
+// // SetVirtualSize((int) (m_maxX - m_minX), (int) (m_maxY - m_minY));
+// }
+// Refresh(false);*/
+};
+
+bool mpWindow::UpdateBBox()
+{
+ bool first = TRUE;
+
+ for (wxLayerList::iterator li = m_layers.begin(); li != m_layers.end(); li++)
+ {
+ mpLayer* f = *li;
+
+ if (f->HasBBox())
+ {
+ if (first)
+ {
+ first = FALSE;
+ m_minX = f->GetMinX(); m_maxX=f->GetMaxX();
+ m_minY = f->GetMinY(); m_maxY=f->GetMaxY();
+ }
+ else
+ {
+ if (f->GetMinX()<m_minX) m_minX=f->GetMinX(); if (f->GetMaxX()>m_maxX) m_maxX=f->GetMaxX();
+ if (f->GetMinY()<m_minY) m_minY=f->GetMinY(); if (f->GetMaxY()>m_maxY) m_maxY=f->GetMaxY();
+ }
+ }
+ //node = node->GetNext();
+ }
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogDebug(wxT("[mpWindow::UpdateBBox] Bounding box: Xmin = %f, Xmax = %f, Ymin = %f, YMax = %f"), m_minX, m_maxX, m_minY, m_maxY);
+#endif // MATHPLOT_DO_LOGGING
+ return first == FALSE;
+}
+
+// void mpWindow::UpdateAll()
+// {
+ // GetClientSize( &m_scrX,&m_scrY);
+/* if (m_enableScrollBars) {
+ // The "virtual size" of the scrolled window:
+ const int sx = (int)((m_maxX - m_minX) * GetScaleX());
+ const int sy = (int)((m_maxY - m_minY) * GetScaleY());
+ SetVirtualSize(sx, sy);
+ SetScrollRate(1, 1);*/
+// const int px = (int)((GetPosX() - m_minX) * GetScaleX());// - m_scrX); //(cx>>1));
+
+ // J.L.Blanco, Aug 2007: Formula fixed:
+// const int py = (int)((m_maxY - GetPosY()) * GetScaleY());// - m_scrY); //(cy>>1));
+// int px, py;
+// GetViewStart(&px0, &py0);
+// px = (int)((m_posX - m_minX)*m_scaleX);
+// py = (int)((m_maxY - m_posY)*m_scaleY);
+
+// SetScrollbars( 1, 1, sx - m_scrX, sy - m_scrY, px, py, TRUE);
+// }
+
+// Working code
+// UpdateBBox();
+// Refresh( FALSE );
+// end working code
+
+// Old version
+/* bool box = UpdateBBox();
+ if (box)
+{
+ int cx, cy;
+ GetClientSize( &cx, &cy);
+
+ // The "virtual size" of the scrolled window:
+ const int sx = (int)((m_maxX - m_minX) * GetScaleX());
+ const int sy = (int)((m_maxY - m_minY) * GetScaleY());
+
+ const int px = (int)((GetPosX() - m_minX) * GetScaleX() - (cx>>1));
+
+ // J.L.Blanco, Aug 2007: Formula fixed:
+ const int py = (int)((m_maxY - GetPosY()) * GetScaleY() - (cy>>1));
+
+ SetScrollbars( 1, 1, sx, sy, px, py, TRUE);
+
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("[mpWindow::UpdateAll] Size:%ix%i ScrollBars:%i,%i"),sx,sy,px,py);
+#endif
+}
+
+ FitInside();
+ Refresh( FALSE );
+*/
+// }
+
+void mpWindow::UpdateAll()
+{
+ if (UpdateBBox())
+ {
+ if (m_enableScrollBars)
+ {
+ int cx, cy;
+ GetClientSize( &cx, &cy);
+ // Do x scroll bar
+ {
+ // Convert margin sizes from pixels to coordinates
+ double leftMargin = m_marginLeft / m_scaleX;
+ // Calculate the range in coords that we want to scroll over
+ double maxX = (m_desiredXmax > m_maxX) ? m_desiredXmax : m_maxX;
+ double minX = (m_desiredXmin < m_minX) ? m_desiredXmin : m_minX;
+ if ((m_posX + leftMargin) < minX)
+ minX = m_posX + leftMargin;
+ // Calculate scroll bar size and thumb position
+ int sizeX = (int) ((maxX - minX) * m_scaleX);
+ int thumbX = (int)(((m_posX + leftMargin) - minX) * m_scaleX);
+ SetScrollbar(wxHORIZONTAL, thumbX, cx - (m_marginRight + m_marginLeft), sizeX);
+ }
+ // Do y scroll bar
+ {
+ // Convert margin sizes from pixels to coordinates
+ double topMargin = m_marginTop / m_scaleY;
+ // Calculate the range in coords that we want to scroll over
+ double maxY = (m_desiredYmax > m_maxY) ? m_desiredYmax : m_maxY;
+ if ((m_posY - topMargin) > maxY)
+ maxY = m_posY - topMargin;
+ double minY = (m_desiredYmin < m_minY) ? m_desiredYmin : m_minY;
+ // Calculate scroll bar size and thumb position
+ int sizeY = (int)((maxY - minY) * m_scaleY);
+ int thumbY = (int)((maxY - (m_posY - topMargin)) * m_scaleY);
+ SetScrollbar(wxVERTICAL, thumbY, cy - (m_marginTop + m_marginBottom), sizeY);
+ }
+ }
+ }
+
+ Refresh( FALSE );
+}
+
+void mpWindow::DoScrollCalc (const int position, const int orientation)
+{
+ if (orientation == wxVERTICAL)
+ {
+ // Y axis
+ // Get top margin in coord units
+ double topMargin = m_marginTop / m_scaleY;
+ // Calculate maximum Y coord to be shown in the graph
+ double maxY = m_desiredYmax > m_maxY ? m_desiredYmax : m_maxY;
+ // Set new position
+ SetPosY((maxY - (position / m_scaleY)) + topMargin);
+ }
+ else
+ {
+ // X Axis
+ // Get left margin in coord units
+ double leftMargin = m_marginLeft / m_scaleX;
+ // Calculate minimum X coord to be shown in the graph
+ double minX = (m_desiredXmin < m_minX) ? m_desiredXmin : m_minX;
+ // Set new position
+ SetPosX((minX + (position / m_scaleX)) - leftMargin);
+ }
+}
+
+void mpWindow::OnScrollThumbTrack (wxScrollWinEvent &event)
+{
+ DoScrollCalc(event.GetPosition(), event.GetOrientation());
+}
+
+void mpWindow::OnScrollPageUp (wxScrollWinEvent &event)
+{
+ int scrollOrientation = event.GetOrientation();
+ // Get position before page up
+ int position = GetScrollPos(scrollOrientation);
+ // Get thumb size
+ int thumbSize = GetScrollThumb(scrollOrientation);
+ // Need to adjust position by a page
+ position -= thumbSize;
+ if (position < 0)
+ position = 0;
+
+ DoScrollCalc(position, scrollOrientation);
+}
+void mpWindow::OnScrollPageDown (wxScrollWinEvent &event)
+{
+ int scrollOrientation = event.GetOrientation();
+ // Get position before page up
+ int position = GetScrollPos(scrollOrientation);
+ // Get thumb size
+ int thumbSize = GetScrollThumb(scrollOrientation);
+ // Get scroll range
+ int scrollRange = GetScrollRange(scrollOrientation);
+ // Need to adjust position by a page
+ position += thumbSize;
+ if (position > (scrollRange - thumbSize))
+ position = scrollRange - thumbSize;
+
+ DoScrollCalc(position, scrollOrientation);
+}
+
+void mpWindow::OnScrollLineUp (wxScrollWinEvent &event)
+{
+ int scrollOrientation = event.GetOrientation();
+ // Get position before page up
+ int position = GetScrollPos(scrollOrientation);
+ // Need to adjust position by a line
+ position -= mpSCROLL_NUM_PIXELS_PER_LINE;
+ if (position < 0)
+ position = 0;
+
+ DoScrollCalc(position, scrollOrientation);
+}
+
+void mpWindow::OnScrollLineDown (wxScrollWinEvent &event)
+{
+ int scrollOrientation = event.GetOrientation();
+ // Get position before page up
+ int position = GetScrollPos(scrollOrientation);
+ // Get thumb size
+ int thumbSize = GetScrollThumb(scrollOrientation);
+ // Get scroll range
+ int scrollRange = GetScrollRange(scrollOrientation);
+ // Need to adjust position by a page
+ position += mpSCROLL_NUM_PIXELS_PER_LINE;
+ if (position > (scrollRange - thumbSize))
+ position = scrollRange - thumbSize;
+
+ DoScrollCalc(position, scrollOrientation);
+}
+
+void mpWindow::OnScrollTop(wxScrollWinEvent &event)
+{
+ DoScrollCalc(0, event.GetOrientation());
+}
+
+void mpWindow::OnScrollBottom(wxScrollWinEvent &event)
+{
+ int scrollOrientation = event.GetOrientation();
+ // Get thumb size
+ int thumbSize = GetScrollThumb(scrollOrientation);
+ // Get scroll range
+ int scrollRange = GetScrollRange(scrollOrientation);
+
+ DoScrollCalc(scrollRange - thumbSize, scrollOrientation);
+}
+// End patch ngpaton
+
+void mpWindow::SetScaleX(double scaleX)
+{
+ if (scaleX!=0) m_scaleX=scaleX;
+ UpdateAll();
+}
+
+// New methods implemented by Davide Rondini
+
+unsigned int mpWindow::CountLayers()
+{
+ //wxNode *node = m_layers.GetFirst();
+ unsigned int layerNo = 0;
+ for(wxLayerList::iterator li = m_layers.begin(); li != m_layers.end(); li++)//while(node)
+ {
+ if ((*li)->HasBBox()) layerNo++;
+ // node = node->GetNext();
+ };
+ return layerNo;
+}
+
+mpLayer* mpWindow::GetLayer(int position)
+{
+ if ((position >= (int) m_layers.size()) || position < 0) return NULL;
+ return m_layers[position];
+}
+
+mpLayer* mpWindow::GetLayerByName( const wxString &name)
+{
+ for (wxLayerList::iterator it=m_layers.begin();it!=m_layers.end();it++)
+ if (! (*it)->GetName().Cmp( name ) )
+ return *it;
+ return NULL; // Not found
+}
+
+void mpWindow::GetBoundingBox(double* bbox)
+{
+ bbox[0] = m_minX;
+ bbox[1] = m_maxX;
+ bbox[2] = m_minY;
+ bbox[3] = m_maxY;
+}
+
+bool mpWindow::SaveScreenshot(const wxString& filename, wxBitmapType type, wxSize imageSize, bool fit)
+{
+ int sizeX, sizeY;
+ int bk_scrX, bk_scrY;
+ if (imageSize == wxDefaultSize) {
+ sizeX = m_scrX;
+ sizeY = m_scrY;
+ } else {
+ sizeX = imageSize.x;
+ sizeY = imageSize.y;
+ bk_scrX = m_scrX;
+ bk_scrY = m_scrY;
+ SetScr(sizeX, sizeY);
+ }
+
+ wxBitmap screenBuffer(sizeX,sizeY);
+ wxMemoryDC screenDC;
+ screenDC.SelectObject(screenBuffer);
+ screenDC.SetPen( *wxTRANSPARENT_PEN );
+ wxBrush brush( GetBackgroundColour() );
+ screenDC.SetBrush( brush );
+ screenDC.DrawRectangle(0,0,sizeX,sizeY);
+
+ if (fit) {
+ Fit(m_minX, m_maxX, m_minY, m_maxY, &sizeX, &sizeY);
+ } else {
+ Fit(m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax, &sizeX, &sizeY);
+ }
+ // Draw all the layers:
+ wxLayerList::iterator li;
+ for (li = m_layers.begin(); li != m_layers.end(); li++)
+ (*li)->Plot(screenDC, *this);
+
+ if (imageSize != wxDefaultSize) {
+ // Restore dimensions
+ SetScr(bk_scrX, bk_scrY);
+ Fit(m_desiredXmin, m_desiredXmax, m_desiredYmin, m_desiredYmax, &bk_scrX, &bk_scrY);
+ UpdateAll();
+ }
+ // Once drawing is complete, actually save screen shot
+ wxImage screenImage = screenBuffer.ConvertToImage();
+ return screenImage.SaveFile(filename, type);
+}
+
+void mpWindow::SetMargins(int top, int right, int bottom, int left)
+{
+ m_marginTop = top;
+ m_marginRight = right;
+ m_marginBottom = bottom;
+ m_marginLeft = left;
+}
+
+mpInfoLayer* mpWindow::IsInsideInfoLayer(wxPoint& point)
+{
+ wxLayerList::iterator li;
+ for (li = m_layers.begin(); li != m_layers.end(); li++) {
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::IsInsideInfoLayer() examinining layer = %p"), (*li));
+#endif // MATHPLOT_DO_LOGGING
+ if ((*li)->IsInfo()) {
+ mpInfoLayer* tmpLyr = (mpInfoLayer*) (*li);
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("mpWindow::IsInsideInfoLayer() layer = %p"), (*li));
+#endif // MATHPLOT_DO_LOGGING
+ if (tmpLyr->Inside(point)) {
+ return tmpLyr;
+ }
+ }
+ }
+ return NULL;
+}
+
+void mpWindow::SetLayerVisible(const wxString &name, bool viewable)
+{
+ mpLayer* lx = GetLayerByName(name);
+ if ( lx ) {
+ lx->SetVisible(viewable);
+ UpdateAll();
+ }
+}
+
+bool mpWindow::IsLayerVisible(const wxString &name )
+{
+ mpLayer* lx = GetLayerByName(name);
+ return (lx) ? lx->IsVisible() : false;
+}
+
+void mpWindow::SetLayerVisible(const unsigned int position, bool viewable)
+{
+ mpLayer* lx = GetLayer(position);
+ if ( lx ) {
+ lx->SetVisible(viewable);
+ UpdateAll();
+ }
+}
+
+bool mpWindow::IsLayerVisible(const unsigned int position )
+{
+ mpLayer* lx = GetLayer(position);
+ return (lx) ? lx->IsVisible() : false;
+}
+
+void mpWindow::SetColourTheme(const wxColour& bgColour, const wxColour& drawColour, const wxColour& axesColour)
+{
+ SetBackgroundColour(bgColour);
+ SetForegroundColour(drawColour);
+ m_bgColour = bgColour;
+ m_fgColour = drawColour;
+ m_axColour = axesColour;
+ // cycle between layers to set colours and properties to them
+ wxLayerList::iterator li;
+ for (li = m_layers.begin(); li != m_layers.end(); li++) {
+ if ((*li)->GetLayerType() == mpLAYER_AXIS) {
+ wxPen axisPen = (*li)->GetPen(); // Get the old pen to modify only colour, not style or width
+ axisPen.SetColour(axesColour);
+ (*li)->SetPen(axisPen);
+ }
+ if ((*li)->GetLayerType() == mpLAYER_INFO) {
+ wxPen infoPen = (*li)->GetPen(); // Get the old pen to modify only colour, not style or width
+ infoPen.SetColour(drawColour);
+ (*li)->SetPen(infoPen);
+ }
+ }
+
+ srColour = drawColour;
+}
+
+// void mpWindow::EnableCoordTooltip(bool value)
+// {
+// m_coordTooltip = value;
+// // if (value) GetToolTip()->SetDelay(100);
+// }
+
+/*
+double mpWindow::p2x(wxCoord pixelCoordX, bool drawOutside )
+{
+ if (drawOutside) {
+ return m_posX + pixelCoordX/m_scaleX;
+ }
+ // Draw inside margins
+ double marginScaleX = ((double)(m_scrX - m_marginLeft - m_marginRight))/m_scrX;
+ return m_marginLeft + (m_posX + pixelCoordX/m_scaleX)/marginScaleX;
+}
+
+double mpWindow::p2y(wxCoord pixelCoordY, bool drawOutside )
+{
+ if (drawOutside) {
+ return m_posY - pixelCoordY/m_scaleY;
+ }
+ // Draw inside margins
+ double marginScaleY = ((double)(m_scrY - m_marginTop - m_marginBottom))/m_scrY;
+ return m_marginTop + (m_posY - pixelCoordY/m_scaleY)/marginScaleY;
+}
+
+wxCoord mpWindow::x2p(double x, bool drawOutside)
+{
+ if (drawOutside) {
+ return (wxCoord) ((x-m_posX) * m_scaleX);
+ }
+ // Draw inside margins
+ double marginScaleX = ((double)(m_scrX - m_marginLeft - m_marginRight))/m_scrX;
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(wxT("x2p ScrX = %d, marginRight = %d, marginLeft = %d, marginScaleX = %f"), m_scrX, m_marginRight, m_marginLeft, marginScaleX);
+#endif // MATHPLOT_DO_LOGGING
+ return (wxCoord) (int)(((x-m_posX) * m_scaleX)*marginScaleX) - m_marginLeft;
+}
+
+wxCoord mpWindow::y2p(double y, bool drawOutside)
+{
+ if (drawOutside) {
+ return (wxCoord) ( (m_posY-y) * m_scaleY);
+ }
+ // Draw inside margins
+ double marginScaleY = ((double)(m_scrY - m_marginTop - m_marginBottom))/m_scrY;
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(wxT("y2p ScrY = %d, marginTop = %d, marginBottom = %d, marginScaleY = %f"), m_scrY, m_marginTop, m_marginBottom, marginScaleY);
+#endif // MATHPLOT_DO_LOGGING
+ return (wxCoord) ((int)((m_posY-y) * m_scaleY)*marginScaleY) - m_marginTop;
+}
+*/
+
+
+//-----------------------------------------------------------------------------
+// mpFXYVector implementation - by Jose Luis Blanco (AGO-2007)
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(mpFXYVector, mpFXY)
+
+// Constructor
+mpFXYVector::mpFXYVector(wxString name, int flags ) : mpFXY(name,flags)
+{
+ m_index = 0;
+ m_minX = -1;
+ m_maxX = 1;
+ m_minY = -1;
+ m_maxY = 1;
+ m_type = mpLAYER_PLOT;
+}
+
+void mpFXYVector::Rewind()
+{
+ m_index = 0;
+}
+
+bool mpFXYVector::GetNextXY(double & x, double & y)
+{
+ if (m_index>=m_xs.size())
+ return FALSE;
+ else
+ {
+ x = m_xs[m_index];
+ y = m_ys[m_index++];
+ return m_index<=m_xs.size();
+ }
+}
+
+void mpFXYVector::Clear()
+{
+ m_xs.clear();
+ m_ys.clear();
+}
+
+void mpFXYVector::SetData( const std::vector<double> &xs,const std::vector<double> &ys)
+{
+ // Check if the data vectora are of the same size
+ if (xs.size() != ys.size()) {
+ //wxLogError(_("wxMathPlot error: X and Y vector are not of the same length!"));
+ return;
+ }
+ // Copy the data:
+ m_xs = xs;
+ m_ys = ys;
+
+
+ // Update internal variables for the bounding box.
+ if (xs.size()>0)
+ {
+ m_minX = xs[0];
+ m_maxX = xs[0];
+ m_minY = ys[0];
+ m_maxY = ys[0];
+
+ std::vector<double>::const_iterator it;
+
+ for (it=xs.begin();it!=xs.end();it++)
+ {
+ if (*it<m_minX) m_minX=*it;
+ if (*it>m_maxX) m_maxX=*it;
+ }
+ for (it=ys.begin();it!=ys.end();it++)
+ {
+ if (*it<m_minY) m_minY=*it;
+ if (*it>m_maxY) m_maxY=*it;
+ }
+ //Thales Lima - 03/07/2015 -> diminuindo offset de y e retirando de x
+ /*m_minX-=0.5f;
+ m_minY-=0.5f;
+ m_maxX+=0.5f;
+ m_maxY+=0.5f;*/
+ m_minY -= m_minY > 0.0 ? 0.005f*m_minY : -0.005f*m_minY;//0,5% de offset
+ m_maxY += m_maxY > 0.0 ? 0.005f*m_maxY : -0.005f*m_maxY;
+ }
+ else
+ {
+ m_minX = -1;
+ m_maxX = 1;
+ m_minY = -1;
+ m_maxY = 1;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// mpText - provided by Val Greene
+//-----------------------------------------------------------------------------
+
+IMPLEMENT_DYNAMIC_CLASS(mpText, mpLayer)
+
+
+/** @param name text to be displayed
+@param offsetx x position in percentage (0-100)
+@param offsetx y position in percentage (0-100)
+*/
+mpText::mpText( wxString name, int offsetx, int offsety )
+{
+ SetName(name);
+
+ if (offsetx >= 0 && offsetx <= 100)
+ m_offsetx = offsetx;
+ else
+ m_offsetx = 5;
+
+ if (offsety >= 0 && offsety <= 100)
+ m_offsety = offsety;
+ else
+ m_offsetx = 50;
+ m_type = mpLAYER_INFO;
+}
+
+/** mpText Layer plot handler.
+This implementation will plot the text adjusted to the visible area.
+*/
+
+void mpText::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ dc.SetPen(m_pen);
+ dc.SetFont(m_font);
+
+ wxCoord tw=0, th=0;
+ dc.GetTextExtent( GetName(), &tw, &th);
+
+ // int left = -dc.LogicalToDeviceX(0);
+ // int width = dc.LogicalToDeviceX(0) - left;
+ // int bottom = dc.LogicalToDeviceY(0);
+ // int height = bottom - -dc.LogicalToDeviceY(0);
+
+ /* dc.DrawText( GetName(),
+ (int)((((float)width/100.0) * m_offsety) + left - (tw/2)),
+ (int)((((float)height/100.0) * m_offsetx) - bottom) );*/
+ int px = m_offsetx*(w.GetScrX() - w.GetMarginLeft() - w.GetMarginRight())/100;
+ int py = m_offsety*(w.GetScrY() - w.GetMarginTop() - w.GetMarginBottom())/100;
+ dc.DrawText( GetName(), px, py);
+ }
+}
+
+//-----------------------------------------------------------------------------
+// mpPrintout - provided by Davide Rondini
+//-----------------------------------------------------------------------------
+
+mpPrintout::mpPrintout(mpWindow *drawWindow, const wxChar *title) : wxPrintout(title)
+{
+ drawn = false;
+ plotWindow = drawWindow;
+}
+
+bool mpPrintout::OnPrintPage(int page)
+{
+
+ wxDC *trgDc = GetDC();
+ if ((trgDc) && (page == 1)) {
+ wxCoord m_prnX, m_prnY;
+ int marginX = 50;
+ int marginY = 50;
+ trgDc->GetSize(&m_prnX, &m_prnY);
+
+ m_prnX -= (2*marginX);
+ m_prnY -= (2*marginY);
+ trgDc->SetDeviceOrigin(marginX, marginY);
+
+#ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(wxT("Print Size: %d x %d\n"), m_prnX, m_prnY);
+ wxLogMessage(wxT("Screen Size: %d x %d\n"), plotWindow->GetScrX(), plotWindow->GetScrY());
+#endif
+
+ // Set the scale according to the page:
+ plotWindow->Fit(
+ plotWindow->GetDesiredXmin(),
+ plotWindow->GetDesiredXmax(),
+ plotWindow->GetDesiredYmin(),
+ plotWindow->GetDesiredYmax(),
+ &m_prnX,
+ &m_prnY );
+
+ // Get the colours of the plotWindow to restore them ath the end
+ wxColour oldBgColour = plotWindow->GetBackgroundColour();
+ wxColour oldFgColour = plotWindow->GetForegroundColour();
+ wxColour oldAxColour = plotWindow->GetAxesColour();
+
+ // Draw background, ensuring to use white background for printing.
+ trgDc->SetPen( *wxTRANSPARENT_PEN );
+ // wxBrush brush( plotWindow->GetBackgroundColour() );
+ wxBrush brush = *wxWHITE_BRUSH;
+ trgDc->SetBrush( brush );
+ trgDc->DrawRectangle(0,0,m_prnX,m_prnY);
+
+ // Draw all the layers:
+ //trgDc->SetDeviceOrigin( m_prnX>>1, m_prnY>>1); // Origin at the center
+ mpLayer *layer;
+ for (unsigned int li = 0; li < plotWindow->CountAllLayers(); li++) {
+ layer = plotWindow->GetLayer(li);
+ layer->Plot(*trgDc, *plotWindow);
+ };
+ // Restore device origin
+ // trgDc->SetDeviceOrigin(0, 0);
+ // Restore colours
+ plotWindow->SetColourTheme(oldBgColour, oldFgColour, oldAxColour);
+ // Restore drawing
+ plotWindow->Fit(plotWindow->GetDesiredXmin(), plotWindow->GetDesiredXmax(), plotWindow->GetDesiredYmin(), plotWindow->GetDesiredYmax(), NULL, NULL);
+ plotWindow->UpdateAll();
+ }
+ return true;
+}
+
+bool mpPrintout::HasPage(int page)
+{
+ return (page == 1);
+}
+
+
+//-----------------------------------------------------------------------------
+// mpMovableObject - provided by Jose Luis Blanco
+//-----------------------------------------------------------------------------
+void mpMovableObject::TranslatePoint( double x,double y, double &out_x, double &out_y )
+{
+ double ccos = cos( m_reference_phi ); // Avoid computing cos/sin twice.
+ double csin = sin( m_reference_phi );
+
+ out_x = m_reference_x + ccos * x - csin * y;
+ out_y = m_reference_y + csin * x + ccos * y;
+}
+
+// This method updates the buffers m_trans_shape_xs/ys, and the precomputed bounding box.
+void mpMovableObject::ShapeUpdated()
+{
+ // Just in case...
+ if (m_shape_xs.size()!=m_shape_ys.size())
+ {
+ //::wxLogError(wxT("[mpMovableObject::ShapeUpdated] Error, m_shape_xs and m_shape_ys have different lengths!"));
+ }
+ else
+ {
+ double ccos = cos( m_reference_phi ); // Avoid computing cos/sin twice.
+ double csin = sin( m_reference_phi );
+
+ m_trans_shape_xs.resize(m_shape_xs.size());
+ m_trans_shape_ys.resize(m_shape_xs.size());
+
+ std::vector<double>::iterator itXi, itXo;
+ std::vector<double>::iterator itYi, itYo;
+
+ m_bbox_min_x=1e300;
+ m_bbox_max_x=-1e300;
+ m_bbox_min_y=1e300;
+ m_bbox_max_y=-1e300;
+
+ for (itXo=m_trans_shape_xs.begin(),itYo=m_trans_shape_ys.begin(),itXi=m_shape_xs.begin(),itYi=m_shape_ys.begin();
+ itXo!=m_trans_shape_xs.end(); itXo++,itYo++,itXi++,itYi++)
+ {
+ *itXo = m_reference_x + ccos * (*itXi) - csin * (*itYi);
+ *itYo = m_reference_y + csin * (*itXi) + ccos * (*itYi);
+
+ // Keep BBox:
+ if (*itXo < m_bbox_min_x) m_bbox_min_x = *itXo;
+ if (*itXo > m_bbox_max_x) m_bbox_max_x = *itXo;
+ if (*itYo < m_bbox_min_y) m_bbox_min_y = *itYo;
+ if (*itYo > m_bbox_max_y) m_bbox_max_y = *itYo;
+ }
+ }
+}
+
+void mpMovableObject::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible) {
+ dc.SetPen( m_pen);
+
+
+ std::vector<double>::iterator itX=m_trans_shape_xs.begin();
+ std::vector<double>::iterator itY=m_trans_shape_ys.begin();
+
+ if (!m_continuous)
+ {
+ // for some reason DrawPoint does not use the current pen,
+ // so we use DrawLine for fat pens
+ if (m_pen.GetWidth() <= 1)
+ {
+ while (itX!=m_trans_shape_xs.end())
+ {
+ dc.DrawPoint( w.x2p(*(itX++)), w.y2p( *(itY++) ) );
+ }
+ }
+ else
+ {
+ while (itX!=m_trans_shape_xs.end())
+ {
+ wxCoord cx = w.x2p(*(itX++));
+ wxCoord cy = w.y2p(*(itY++));
+ dc.DrawLine(cx, cy, cx, cy);
+ }
+ }
+ }
+ else
+ {
+ wxCoord cx0=0,cy0=0;
+ bool first = TRUE;
+ while (itX!=m_trans_shape_xs.end())
+ {
+ wxCoord cx = w.x2p(*(itX++));
+ wxCoord cy = w.y2p(*(itY++));
+ if (first)
+ {
+ first=FALSE;
+ cx0=cx;cy0=cy;
+ }
+ dc.DrawLine(cx0, cy0, cx, cy);
+ cx0=cx; cy0=cy;
+ }
+ }
+
+ if (!m_name.IsEmpty() && m_showName)
+ {
+ dc.SetFont(m_font);
+
+ wxCoord tx, ty;
+ dc.GetTextExtent(m_name, &tx, &ty);
+
+ if (HasBBox())
+ {
+ wxCoord sx = (wxCoord) (( m_bbox_max_x - w.GetPosX()) * w.GetScaleX());
+ wxCoord sy = (wxCoord) ((w.GetPosY() - m_bbox_max_y ) * w.GetScaleY());
+
+ tx = sx - tx - 8;
+ ty = sy - 8 - ty;
+ }
+ else
+ {
+ const int sx = w.GetScrX()>>1;
+ const int sy = w.GetScrY()>>1;
+
+ if ((m_flags & mpALIGNMASK) == mpALIGN_NE)
+ {
+ tx = sx - tx - 8;
+ ty = -sy + 8;
+ }
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_NW)
+ {
+ tx = -sx + 8;
+ ty = -sy + 8;
+ }
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_SW)
+ {
+ tx = -sx + 8;
+ ty = sy - 8 - ty;
+ }
+ else
+ {
+ tx = sx - tx - 8;
+ ty = sy - 8 - ty;
+ }
+ }
+
+ dc.DrawText( m_name, tx, ty);
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// mpCovarianceEllipse - provided by Jose Luis Blanco
+//-----------------------------------------------------------------------------
+
+// Called to update the m_shape_xs, m_shape_ys vectors, whenever a parameter changes.
+void mpCovarianceEllipse::RecalculateShape()
+{
+ m_shape_xs.clear();
+ m_shape_ys.clear();
+
+ // Preliminar checks:
+ if (m_quantiles<0) { /*::wxLogError(wxT("[mpCovarianceEllipse] Error: quantiles must be non-negative"));*/ return; }
+ if (m_cov_00<0) { /*::wxLogError(wxT("[mpCovarianceEllipse] Error: cov(0,0) must be non-negative"));*/ return; }
+ if (m_cov_11<0) { /*::wxLogError(wxT("[mpCovarianceEllipse] Error: cov(1,1) must be non-negative"));*/ return; }
+
+ m_shape_xs.resize( m_segments,0 );
+ m_shape_ys.resize( m_segments,0 );
+
+ // Compute the two eigenvalues of the covariance:
+ // -------------------------------------------------
+ double b = -m_cov_00 - m_cov_11;
+ double c = m_cov_00*m_cov_11 - m_cov_01*m_cov_01;
+
+ double D = b*b - 4*c;
+
+ if (D<0) { /*::wxLogError(wxT("[mpCovarianceEllipse] Error: cov is not positive definite"));*/ return; }
+
+ double eigenVal0 =0.5*( -b + sqrt(D) );
+ double eigenVal1 =0.5*( -b - sqrt(D) );
+
+ // Compute the two corresponding eigenvectors:
+ // -------------------------------------------------
+ double eigenVec0_x,eigenVec0_y;
+ double eigenVec1_x,eigenVec1_y;
+
+ if (fabs(eigenVal0 - m_cov_00)>1e-6)
+ {
+ double k1x = m_cov_01 / ( eigenVal0 - m_cov_00 );
+ eigenVec0_y = 1;
+ eigenVec0_x = eigenVec0_y * k1x;
+ }
+ else
+ {
+ double k1y = m_cov_01 / ( eigenVal0 - m_cov_11 );
+ eigenVec0_x = 1;
+ eigenVec0_y = eigenVec0_x * k1y;
+ }
+
+ if (fabs(eigenVal1 - m_cov_00)>1e-6)
+ {
+ double k2x = m_cov_01 / ( eigenVal1 - m_cov_00 );
+ eigenVec1_y = 1;
+ eigenVec1_x = eigenVec1_y * k2x;
+ }
+ else
+ {
+ double k2y = m_cov_01 / ( eigenVal1 - m_cov_11 );
+ eigenVec1_x = 1;
+ eigenVec1_y = eigenVec1_x * k2y;
+ }
+
+ // Normalize the eigenvectors:
+ double len = sqrt( eigenVec0_x*eigenVec0_x + eigenVec0_y*eigenVec0_y );
+ eigenVec0_x /= len; // It *CANNOT* be zero
+ eigenVec0_y /= len;
+
+ len = sqrt( eigenVec1_x*eigenVec1_x + eigenVec1_y*eigenVec1_y );
+ eigenVec1_x /= len; // It *CANNOT* be zero
+ eigenVec1_y /= len;
+
+
+ // Take the sqrt of the eigenvalues (required for the ellipse scale):
+ eigenVal0 = sqrt(eigenVal0);
+ eigenVal1 = sqrt(eigenVal1);
+
+ // Compute the 2x2 matrix M = diag(eigVal) * (~eigVec) (each eigen vector is a row):
+ double M_00 = eigenVec0_x * eigenVal0;
+ double M_01 = eigenVec0_y * eigenVal0;
+
+ double M_10 = eigenVec1_x * eigenVal1;
+ double M_11 = eigenVec1_y * eigenVal1;
+
+ // The points of the 2D ellipse:
+ double ang;
+ double Aang = 6.283185308/(m_segments-1);
+ int i;
+ for (i=0,ang=0;i<m_segments;i++,ang+= Aang )
+ {
+ double ccos = cos(ang);
+ double csin = sin(ang);
+
+ m_shape_xs[i] = m_quantiles * (ccos * M_00 + csin * M_10 );
+ m_shape_ys[i] = m_quantiles * (ccos * M_01 + csin * M_11 );
+ } // end for points on ellipse
+
+
+ ShapeUpdated();
+}
+
+//-----------------------------------------------------------------------------
+// mpPolygon - provided by Jose Luis Blanco
+//-----------------------------------------------------------------------------
+void mpPolygon::setPoints(
+ const std::vector<double>& points_xs,
+ const std::vector<double>& points_ys,
+ bool closedShape )
+{
+ if ( points_xs.size()!=points_ys.size() )
+ {
+ //::wxLogError(wxT("[mpPolygon] Error: points_xs and points_ys must have the same number of elements"));
+ }
+ else
+ {
+ m_shape_xs = points_xs;
+ m_shape_ys = points_ys;
+
+ if ( closedShape && points_xs.size())
+ {
+ m_shape_xs.push_back( points_xs[0] );
+ m_shape_ys.push_back( points_ys[0] );
+ }
+
+ ShapeUpdated();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// mpBitmapLayer - provided by Jose Luis Blanco
+//-----------------------------------------------------------------------------
+void mpBitmapLayer::GetBitmapCopy( wxImage &outBmp ) const
+{
+ if (m_validImg)
+ outBmp = m_bitmap;
+}
+
+void mpBitmapLayer::SetBitmap( const wxImage &inBmp, double x, double y, double lx, double ly )
+{
+ if (!inBmp.Ok())
+ {
+ //::wxLogError(wxT("[mpBitmapLayer] Assigned bitmap is not Ok()!"));
+ }
+ else
+ {
+ m_bitmap = inBmp; //.GetSubBitmap( wxRect(0, 0, inBmp.GetWidth(), inBmp.GetHeight()));
+ m_min_x = x;
+ m_min_y = y;
+ m_max_x = x+lx;
+ m_max_y = y+ly;
+ m_validImg = true;
+ }
+}
+
+
+void mpBitmapLayer::Plot(wxDC & dc, mpWindow & w)
+{
+ if (m_visible && m_validImg)
+ {
+ /* 1st: We compute (x0,y0)-(x1,y1), the pixel coordinates of the real outer limits
+ of the image rectangle within the (screen) mpWindow. Note that these coordinates
+ might fall well far away from the real view limits when the user zoom in.
+
+ 2nd: We compute (dx0,dy0)-(dx1,dy1), the pixel coordinates the rectangle that will
+ be actually drawn into the mpWindow, i.e. the clipped real rectangle that
+ avoids the non-visible parts. (offset_x,offset_y) are the pixel coordinates
+ that correspond to the window point (dx0,dy0) within the image "m_bitmap", and
+ (b_width,b_height) is the size of the bitmap patch that will be drawn.
+
+ (x0,y0) ................. (x1,y0)
+ . .
+ . .
+ (x0,y1) ................ (x1,y1)
+ (In pixels!!)
+ */
+
+ // 1st step -------------------------------
+ wxCoord x0 = w.x2p(m_min_x);
+ wxCoord y0 = w.y2p(m_max_y);
+ wxCoord x1 = w.x2p(m_max_x);
+ wxCoord y1 = w.y2p(m_min_y);
+
+ // 2nd step -------------------------------
+ // Precompute the size of the actual bitmap pixel on the screen (e.g. will be >1 if zoomed in)
+ double screenPixelX = ( x1-x0 ) / (double)m_bitmap.GetWidth();
+ double screenPixelY = ( y1-y0 ) / (double)m_bitmap.GetHeight();
+
+ // The minimum number of pixels that the streched image will overpass the actual mpWindow borders:
+ wxCoord borderMarginX = (wxCoord)(screenPixelX+1); // ceil
+ wxCoord borderMarginY = (wxCoord)(screenPixelY+1); // ceil
+
+ // The actual drawn rectangle (dx0,dy0)-(dx1,dy1) is (x0,y0)-(x1,y1) clipped:
+ wxCoord dx0=x0,dx1=x1,dy0=y0,dy1=y1;
+ if (dx0<0) dx0=-borderMarginX;
+ if (dy0<0) dy0=-borderMarginY;
+ if (dx1>w.GetScrX()) dx1=w.GetScrX()+borderMarginX;
+ if (dy1>w.GetScrY()) dy1=w.GetScrY()+borderMarginY;
+
+ // For convenience, compute the width/height of the rectangle to be actually drawn:
+ wxCoord d_width = dx1-dx0+1;
+ wxCoord d_height = dy1-dy0+1;
+
+ // Compute the pixel offsets in the internally stored bitmap:
+ wxCoord offset_x= (wxCoord) ( (dx0-x0)/screenPixelX );
+ wxCoord offset_y= (wxCoord) ( (dy0-y0)/screenPixelY );
+
+ // and the size in pixel of the area to be actually drawn from the internally stored bitmap:
+ wxCoord b_width = (wxCoord) ( (dx1-dx0+1)/screenPixelX );
+ wxCoord b_height = (wxCoord) ( (dy1-dy0+1)/screenPixelY );
+
+ #ifdef MATHPLOT_DO_LOGGING
+ wxLogMessage(_("[mpBitmapLayer::Plot] screenPixel: x=%f y=%f d_width=%ix%i"),screenPixelX,screenPixelY,d_width,d_height);
+ wxLogMessage(_("[mpBitmapLayer::Plot] offset: x=%i y=%i bmpWidth=%ix%i"),offset_x,offset_y,b_width,b_height);
+ #endif
+
+ // Is there any visible region?
+ if (d_width>0 && d_height>0)
+ {
+ // Build the scaled bitmap from the image, only if it has changed:
+ if (m_scaledBitmap.GetWidth()!=d_width ||
+ m_scaledBitmap.GetHeight()!=d_height ||
+ m_scaledBitmap_offset_x != offset_x ||
+ m_scaledBitmap_offset_y != offset_y )
+ {
+ wxRect r(wxRect(offset_x,offset_y,b_width,b_height));
+ // Just for the case....
+ if (r.x<0) r.x=0;
+ if (r.y<0) r.y=0;
+ if (r.width>m_bitmap.GetWidth()) r.width=m_bitmap.GetWidth();
+ if (r.height>m_bitmap.GetHeight()) r.height=m_bitmap.GetHeight();
+
+ m_scaledBitmap = wxBitmap(
+ wxBitmap(m_bitmap).GetSubBitmap( r ).ConvertToImage()
+ .Scale(d_width,d_height) );
+ m_scaledBitmap_offset_x = offset_x;
+ m_scaledBitmap_offset_y = offset_y;
+ }
+
+ // Draw it:
+ dc.DrawBitmap( m_scaledBitmap, dx0,dy0, true );
+ }
+ }
+
+ // Draw the name label
+ if (!m_name.IsEmpty() && m_showName)
+ {
+ dc.SetFont(m_font);
+
+ wxCoord tx, ty;
+ dc.GetTextExtent(m_name, &tx, &ty);
+
+ if (HasBBox())
+ {
+ wxCoord sx = (wxCoord) (( m_max_x - w.GetPosX()) * w.GetScaleX());
+ wxCoord sy = (wxCoord) ((w.GetPosY() - m_max_y ) * w.GetScaleY());
+
+ tx = sx - tx - 8;
+ ty = sy - 8 - ty;
+ }
+ else
+ {
+ const int sx = w.GetScrX()>>1;
+ const int sy = w.GetScrY()>>1;
+
+ if ((m_flags & mpALIGNMASK) == mpALIGN_NE)
+ {
+ tx = sx - tx - 8;
+ ty = -sy + 8;
+ }
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_NW)
+ {
+ tx = -sx + 8;
+ ty = -sy + 8;
+ }
+ else if ((m_flags & mpALIGNMASK) == mpALIGN_SW)
+ {
+ tx = -sx + 8;
+ ty = sy - 8 - ty;
+ }
+ else
+ {
+ tx = sx - tx - 8;
+ ty = sy - 8 - ty;
+ }
+ }
+
+ dc.DrawText( m_name, tx, ty);
+ }
+}