From 014bd2ae54b6224dc01b18c313353231f4b539f6 Mon Sep 17 00:00:00 2001 From: Artur Wieczorek Date: Sun, 13 Sep 2020 23:47:26 +0200 Subject: [PATCH] Implement platform-specific coordinate conversion functions Generic wxDC::DeviceToLogical{X|Y}() and wxDC::LogicalToDevice{X|Y}() functions don't take into account transformations applied with wxDC::SetTransformMatrix() so conversion results are invalid if wxDC is transformed with both e.g. wxDC::SetUserScale() and wxDC::SetTransformMatrix(). We need to implement functions in wxDCImpl and its platform-specific derivates to do this conversion with taking into account all applied transformations. See #18916. --- include/wx/dc.h | 4 ++++ include/wx/dcgraph.h | 5 +++++ include/wx/msw/dc.h | 3 +++ src/common/dcbase.cpp | 10 ++++++++++ src/common/dcgraph.cpp | 19 +++++++++++++++++++ src/msw/dc.cpp | 18 ++++++++++++++++++ 6 files changed, 59 insertions(+) diff --git a/include/wx/dc.h b/include/wx/dc.h index a9e901ae22..492d4e5405 100644 --- a/include/wx/dc.h +++ b/include/wx/dc.h @@ -323,6 +323,10 @@ public: // flushing the content of this dc immediately eg onto screen virtual void Flush() { } + // coordinates conversions and transforms + virtual wxPoint DeviceToLogical(wxCoord x, wxCoord y) const; + virtual wxPoint LogicalToDevice(wxCoord x, wxCoord y) const; + // bounding box virtual void CalcBoundingBox(wxCoord x, wxCoord y) diff --git a/include/wx/dcgraph.h b/include/wx/dcgraph.h index fd413d0835..4622a3534a 100644 --- a/include/wx/dcgraph.h +++ b/include/wx/dcgraph.h @@ -121,6 +121,10 @@ public: virtual void ResetTransformMatrix() wxOVERRIDE; #endif // wxUSE_DC_TRANSFORM_MATRIX + // coordinates conversions and transforms + virtual wxPoint DeviceToLogical(wxCoord x, wxCoord y) const wxOVERRIDE; + virtual wxPoint LogicalToDevice(wxCoord x, wxCoord y) const wxOVERRIDE; + // the true implementations virtual bool DoFloodFill(wxCoord x, wxCoord y, const wxColour& col, wxFloodFillStyle style = wxFLOOD_SURFACE) wxOVERRIDE; @@ -225,6 +229,7 @@ protected: bool m_logicalFunctionSupported; wxGraphicsMatrix m_matrixOriginal; wxGraphicsMatrix m_matrixCurrent; + wxGraphicsMatrix m_matrixCurrentInv; #if wxUSE_DC_TRANSFORM_MATRIX wxAffineMatrix2D m_matrixExtTransform; #endif // wxUSE_DC_TRANSFORM_MATRIX diff --git a/include/wx/msw/dc.h b/include/wx/msw/dc.h index a27b70dab3..faaab34283 100644 --- a/include/wx/msw/dc.h +++ b/include/wx/msw/dc.h @@ -86,6 +86,9 @@ public: virtual void SetDeviceOrigin(wxCoord x, wxCoord y) wxOVERRIDE; virtual void SetAxisOrientation(bool xLeftRight, bool yBottomUp) wxOVERRIDE; + virtual wxPoint DeviceToLogical(wxCoord x, wxCoord y) const wxOVERRIDE; + virtual wxPoint LogicalToDevice(wxCoord x, wxCoord y) const wxOVERRIDE; + #if wxUSE_DC_TRANSFORM_MATRIX virtual bool CanUseTransformMatrix() const wxOVERRIDE; virtual bool SetTransformMatrix(const wxAffineMatrix2D& matrix) wxOVERRIDE; diff --git a/src/common/dcbase.cpp b/src/common/dcbase.cpp index beededefe7..59f61bce0a 100644 --- a/src/common/dcbase.cpp +++ b/src/common/dcbase.cpp @@ -502,6 +502,16 @@ wxCoord wxDCImpl::LogicalToDeviceYRel(wxCoord y) const return wxRound((double)(y) * m_scaleY); } +wxPoint wxDCImpl::DeviceToLogical(wxCoord x, wxCoord y) const +{ + return wxPoint(DeviceToLogicalX(x), DeviceToLogicalY(y)); +} + +wxPoint wxDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const +{ + return wxPoint(LogicalToDeviceX(x), LogicalToDeviceY(y)); +} + void wxDCImpl::ComputeScaleAndOrigin() { m_scaleX = m_logicalScaleX * m_userScaleX; diff --git a/src/common/dcgraph.cpp b/src/common/dcgraph.cpp index 1ab8f4c494..a731de53bc 100644 --- a/src/common/dcgraph.cpp +++ b/src/common/dcgraph.cpp @@ -487,6 +487,8 @@ void wxGCDCImpl::ComputeScaleAndOrigin() m_matrixCurrent.Concat(mtxExt); #endif // wxUSE_DC_TRANSFORM_MATRIX m_graphicContext->ConcatTransform( m_matrixCurrent ); + m_matrixCurrentInv = m_matrixCurrent; + m_matrixCurrentInv.Invert(); m_isClipBoxValid = false; } } @@ -594,6 +596,23 @@ void wxGCDCImpl::ResetTransformMatrix() #endif // wxUSE_DC_TRANSFORM_MATRIX +// coordinates conversions and transforms +wxPoint wxGCDCImpl::DeviceToLogical(wxCoord x, wxCoord y) const +{ + wxDouble px = x; + wxDouble py = y; + m_matrixCurrentInv.TransformPoint(&px, &py); + return wxPoint(wxRound(px), wxRound(py)); +} + +wxPoint wxGCDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const +{ + wxDouble px = x; + wxDouble py = y; + m_matrixCurrent.TransformPoint(&px, &py); + return wxPoint(wxRound(px), wxRound(py)); +} + bool wxGCDCImpl::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), const wxColour& WXUNUSED(col), wxFloodFillStyle WXUNUSED(style)) diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index 39ac13ec3d..6ebc77b68e 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -2100,6 +2100,24 @@ void wxMSWDCImpl::SetDeviceOrigin(wxCoord x, wxCoord y) m_isClipBoxValid = false; } +wxPoint wxMSWDCImpl::DeviceToLogical(wxCoord x, wxCoord y) const +{ + POINT p[1]; + p[0].x = x; + p[0].y = y; + ::DPtoLP(GetHdc(), p, WXSIZEOF(p)); + return wxPoint(p[0].x, p[0].y); +} + +wxPoint wxMSWDCImpl::LogicalToDevice(wxCoord x, wxCoord y) const +{ + POINT p[1]; + p[0].x = x; + p[0].y = y; + ::LPtoDP(GetHdc(), p, WXSIZEOF(p)); + return wxPoint(p[0].x, p[0].y); +} + // ---------------------------------------------------------------------------- // Transform matrix // ----------------------------------------------------------------------------