Compensating for the Reversal of the Y-Axis

Even though MM_LOENGLISH mapping has changed the direction of the y-axis for drawing, most of the current Scribble code doesn’t require any modifications. This is because the DPtoLP function performs the conversion for you. (DPtoLP is called by the mouse event handler functions: OnLButtonDown, OnMouseMove, and OnLButtonUp.)

When a point is received with a mouse message, its coordinates are converted by the DPtoLP function before being stored in a CStroke object. This means its y-coordinates are converted from a positive number of pixels to a negative number of inches (1 pixel = .01 inch). Those coordinates are then passed to the LineTo drawing function, and then it’s up to the device driver for the screen to determine how many pixels are equivalent to the value that was passed in inches. You never have to directly examine the value of the coordinates.

However, there are some places where the reversal of the y-axis does have an impact. The mapping mode used by GDI is a characteristic of a device context. Functions that don’t use a device context are unaffected by the mapping mode. The member functions of the CRect class don’t use the mapping mode; consequently, you must make some adjustments wherever Scribble uses CRect functions.

To compensate for the reversal of the y-axis

  1. From ClassView, jump to the FinishStroke member function definition of class CStroke.

  2. Modify the code, as shown below, by reversing the min and max functions for the top and bottom of the bounding rectangle, and adding a cast to the y-axis m_nPenWidth parameter. These modifications take into account the negative sign of the y-coordinates.

    Note that the lines of code shown already exist ? you are just modifying them slightly, as described.

    void CStroke::FinishStroke()
    {
    // ...
    
    m_rectBounding.top        = max(m_rectBounding.top, pt.y);
    m_rectBounding.bottom    = min(m_rectBounding.bottom, pt.y);
    }
    
    // ...
    m_rectBounding.InflateRect
    (CSize(m_nPenWidth,-(int)m_nPenWidth));
    return;
    }
    

    You must also make a correction when using the invalid rectangle. Recall that the OnDraw member function checks whether the invalid rectangle intersects the bounding rectangle for each stroke. The IntersectRect member function of CRect assumes that the bottom of a rectangle must have a larger y-coordinate than that of the top; it cannot find the intersection of two rectangles whose bottoms have smaller y-coordinates than their tops.

  3. Use ClassView to jump to the OnDraw member function definition of CScribbleView, and add the following lines of code after the line pDC->GetClipBox(&rectClip):
    pDC->LPtoDP(&rectClip);
    rectClip.InflateRect(1, 1); // avoid rounding to nothing
    
  4. Add the following lines of code after the line rectStroke = pStroke->GetBoundingRect():
    pDC->LPtoDP(&rectStroke);
    rectStroke.InflateRect(1, 1);
    

    Both the invalidated rectangle and the bounding rectangle are converted to device coordinates (changing the signs of the coordinates to positive) before being tested for intersection. They are also inflated by one pixel in case they were rounded to nothing during the conversion.