2D transformation giving me a headache



  • I have an image view widget that displays a pixmap. The view can be zoomed about either the centre of the pixmap or an arbitrary point (that was under the mouse pointer when the zoom starts).

    This is rendered onto a buffer pixmap which is then copied to the screen and some other stuff is displayed in the paint event after drawing the buffer.

    The code to draw the buffer pixmap looks like:

        //
        // Calculate the rectangle we're interested in that is centred on the point in the pixmap
        // that is under the mouse pointer (or the centre of the pixmap if the mouse isn't over
        // the image).  Need to adjust the origin position depending on the zoom factor
        //
        const qreal width = m_pixmap.width();
        const qreal height = m_pixmap.height();
        const qreal x = m_pointInPixmap.x();
        const qreal y = m_pointInPixmap.y();
        QRectF  sourceRect(
            x - (x / m_zoom),
            y - (y / m_zoom),
            width / m_zoom,
            height / m_zoom
        );
    
        //
        // Now take the intersection of the rectangle of interest and the pixmap's rectangle.
        //
        sourceRect &= m_pixmap.rect();
    
        painter.save();
        painter.translate(m_origin);
        painter.scale(m_zoom* m_scale, m_zoom* m_scale);
        painter.translate(-m_origin);
    
        //
        // Finally draw the clipped rectangle of interest at the origin location
        //
        painter.drawPixmap(m_origin, m_pixmap, sourceRect);
        painter.restore();
    
    

    There's also a widget that works in a similar way to QRubberBand that allows selection of part of the image (in image coordinates). I need to transform the selection rectangle so it displays at the correct location on the zoomed pixmap, but I've so far failed to work out the correct transformation when the image is zoomed in.

    The transformation when the image is NOT zoomed (m_zoom is 1.0) is simply:

        inline QRectF BitmapToScreen(const QRectF& rc) noexcept
        {
            return QRectF(
                QPointF(rc.left() * m_zoom * m_scale + m_origin.x(),
                    rc.top() * m_zoom * m_scale + m_origin.y()),
                QPointF(rc.right() * m_zoom * m_scale + m_origin.x(),
                    rc.bottom() * m_zoom * m_scale + m_origin.y())
                );
        };
    

    But that falls apart when the image is zoomed.

    Can anyone help with this please?

    David



  • I solved it thanks to a hint on another forum.

    I saved the rectangle which I called sourceRect in the above code as rectOfInterest.

    The following code for what was previously called BitmapToScreen now looks like this:

        inline QRectF imageToScreen(const QRectF& rc) noexcept
        {
            return QRectF(
                rc.topLeft() * m_zoom * m_scale + m_origin - rectOfInterest.topLeft() * m_zoom * m_scale,
                rc.size() * m_zoom * m_scale
                );
        };
    
    

    And what's more it works!



  • I solved it thanks to a hint on another forum.

    I saved the rectangle which I called sourceRect in the above code as rectOfInterest.

    The following code for what was previously called BitmapToScreen now looks like this:

        inline QRectF imageToScreen(const QRectF& rc) noexcept
        {
            return QRectF(
                rc.topLeft() * m_zoom * m_scale + m_origin - rectOfInterest.topLeft() * m_zoom * m_scale,
                rc.size() * m_zoom * m_scale
                );
        };
    
    

    And what's more it works!


Log in to reply