From 06e4e46e39946577094d5e4fdba7f5ed7662eaa3 Mon Sep 17 00:00:00 2001 From: Thales Lima Oliveira Date: Wed, 16 Oct 2019 22:35:28 -0300 Subject: External library deprected code fixed --- Project/wxMathPlot/mathplot.cpp | 5976 +++++++++++++++++++-------------------- 1 file changed, 2902 insertions(+), 3074 deletions(-) (limited to 'Project/wxMathPlot/mathplot.cpp') diff --git a/Project/wxMathPlot/mathplot.cpp b/Project/wxMathPlot/mathplot.cpp index 8543ca7..780e15e 100644 --- a/Project/wxMathPlot/mathplot.cpp +++ b/Project/wxMathPlot/mathplot.cpp @@ -1,3074 +1,2902 @@ -///////////////////////////////////////////////////////////////////////////// -// 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 -//#include - -// 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 -#include -#include -#include -#include - -#include -#include // used only for debug -#include // 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 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 = p0xp1x ? p0x:p1x; - double zoom_y_min = p0yp1y ? 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()GetMinX(); if (f->GetMaxX()>m_maxX) m_maxX=f->GetMaxX(); - if (f->GetMinY()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 &xs,const std::vector &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::const_iterator it; - - for (it=xs.begin();it!=xs.end();it++) - { - if (*itm_maxX) m_maxX=*it; - } - for (it=ys.begin();it!=ys.end();it++) - { - if (*itm_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::iterator itXi, itXo; - std::vector::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::iterator itX=m_trans_shape_xs.begin(); - std::vector::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& points_xs, - const std::vector& 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); - } -} +///////////////////////////////////////////////////////////////////////////// +// 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 +//#include + +// 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/colour.h" +#include "wx/font.h" +#include "wx/object.h" +#include "wx/settings.h" +#include "wx/sizer.h" +//#include "wx/log.h" +#include "wx/cursor.h" +#include "wx/dcclient.h" +#include "wx/intl.h" +#endif + +#include +#include +#include +#include +#include +#include "mathplot.h" + +#include +#include // used only for debug +#include // 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, wxBRUSHSTYLE_SOLID); + 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 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 + // Boundaries removal + /*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; + } + + // draw method modified + 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 + // Extended plot covering + 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(wxPENSTYLE_DOT); + 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(wxPENSTYLE_SOLID); + 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(wxPENSTYLE_DOT); + 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(wxPENSTYLE_SOLID); + 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, _("Center"), _("Center plot view to this position")); + m_popmenu.Append(mpID_FIT, _("Fit"), _("Set plot view to show all items")); + m_popmenu.Append(mpID_ZOOM_IN, _("Zoom in"), _("Zoom in plot view.")); + m_popmenu.Append(mpID_ZOOM_OUT, _("Zoom out"), _("Zoom out plot view.")); + m_popmenu.AppendCheckItem(mpID_LOCKASPECT, _("Lock aspect"), _("Lock horizontal and vertical zoom aspect.")); + m_popmenu.Append(mpID_HELP_MOUSE, _("Show mouse commands..."), _("Show help about the mouse commands.")); + + 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 + } + /*/Modification - 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(_("Supported Mouse commands:\n \ + - Left button down + Mark area: Rectangular zoom\n \ + - Right button down + Move: Pan (Move)\n \ + - Wheel: Vertical scroll\n \ + - Wheel + SHIFT: Horizontal scroll\n \ + - Wheel + CTRL: Zoom in/out"), + _("wxMathPlot help"), 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, wxPENSTYLE_DOT); + 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& xs, const std::vector& 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::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 + /*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::iterator itXi, itXo; + std::vector::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::iterator itX = m_trans_shape_xs.begin(); + std::vector::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& points_xs, const std::vector& 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); + } +} -- cgit