ExtFloodFill with custom scaling

William Kandler 1 Reputation point
2021-07-10T19:17:38.12+00:00

I'm filling irregular shapes with solid colors and my desired coord system is centered origin. I can make this work by setting scaleheight/width to max dimension of picturebox and computing offset=maxdimension/2. But this means every point must be specified as x+offest/y+offset; rather messy.

I can set up for 0/0 centered in pic via

dest.ScaleMode = vbInches 'here's the key; picture's scale mode is inches

dest.ScaleWidth = MaxDimension
dest.ScaleLeft = -dest.ScaleWidth / 2

dest.ScaleHeight = MaxDimension
dest.ScaleTop = -dest.ScaleHeight / 2

But extfloodfill cannot locate the proper fill point(fills from wrong point).

Windows API - Win32
Windows API - Win32
A core set of Windows application programming interfaces (APIs) for desktop and server applications. Previously known as Win32 API.
2,416 questions
{count} votes

8 answers

Sort by: Most helpful
  1. William Kandler 6 Reputation points
    2021-07-23T19:49:11.947+00:00

    I have located and fixed my problem. The scalex and scaley functions do not function properly when changing coordinate systems. They only handle simple scaling., Thus, when floodfill and scale(-2.5,-2.5)-(2.5,2.5) come together and you use

    Sub ScaleToPixels(Pic As PictureBox, inp As ObjPt, outv As ObjPt)
    With inp
    outv.x = Pic.ScaleX(.x, Pic.ScaleMode, vbPixels)
    outv.y = Pic.ScaleY(-.y, Pic.ScaleMode, vbPixels)
    End With
    End Sub

    to give floodfill its starting point in pixels, it gives you the scale(-2.5,-2.5)-(2.5,2.5) coordinate system you specified instead of scale(0,0)-(maxx,maxy) that floodfill requires. So you have to something like this.

    Sub ScaleToPixels(Pic As PictureBox, inp As ObjPt, outv As ObjPt)
    With inp
    outv.x = 238 + Pic.ScaleX(.x, Pic.ScaleMode, vbPixels)
    outv.y = 238 - Pic.ScaleY(-.y, Pic.ScaleMode, vbPixels)
    End With
    End Sub

    238 is the mid-point pixel for my case.

    1 person found this answer helpful.
    0 comments No comments

  2. Xiaopo Yang - MSFT 11,336 Reputation points Microsoft Vendor
    2021-07-13T01:40:00.57+00:00

    It's prefer to use WinAPI to set the origin at the center.
    Such As:

    void SetIsotropic(HDC hdc, int cxClient,int xyClient)
    {
     SetMapMode(hdc,MM_ISOTROPIC);
     SetWindowExtEx(hdc,1000,1000,NULL);
     SetViewportExtEx(hdc, cxClient / 2,-xyClient / 2,NULL);
     SetViewportOrgEx(hdc, cxClient / 2, xyClient / 2, NULL);
    }
    

    The previous code Need more care to use.
    And Then perhaps ExtFloodFill will have normal behavior.

    0 comments No comments

  3. William Kandler 1 Reputation point
    2021-07-13T23:42:40.12+00:00

    my test is a 3000x3000 twips picturebox. Here is what I've tried for a working space of +-2.5 with the origin at 0,0 in the center of the box:

    SetMapMode Pic2.hdc, MM_ISOTROPIC
    SetWindowExtEx Pic2.hdc, 3000, 3000, 3000
    SetViewportExtEx Pic2.hdc, 2.5, -2.5, 2.5
    SetViewportOrgEx Pic2.hdc, -2.5, -2.5, PointOf(0, 0)

    Pic.ScaleX(X/Y, Pic.ScaleMode, vbPixels) is then used to get the starting point for floodfill.

    For -2.5/-2.5 it ought to give 0/0 and for 2.5/2.5 it ought to give 200/200, but actually results in -97/-97 and 97/97.

    0 comments No comments

  4. Xiaopo Yang - MSFT 11,336 Reputation points Microsoft Vendor
    2021-07-14T07:02:16.173+00:00

    After Testing, I found There is no problem on ExtFloodFill. As far as the following code concerned, The ExtFloodFill interpreted coordinate correctly.

    LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)  
    {  
        switch (message)  
        {  
        case WM_PAINT:  
            {  
                PAINTSTRUCT ps;  
                HDC hdc = BeginPaint(hWnd, &ps);  
                // TODO: Add any drawing code that uses hdc here...  
     RECT rc{};  
      
     GetClientRect(hWnd, &rc);  
     SetMapMode(hdc, MM_ANISOTROPIC);  
     SetWindowExtEx(hdc, 100, 100, NULL);  
     SetViewportExtEx(hdc, rc.right / 2, -rc.bottom / 2, NULL);  
     SetViewportOrgEx(hdc, rc.right / 2, rc.bottom / 2, NULL);  
      
     POINT aptTriangle[] = { 0,50, 100,0,  0,-99, -25,0, 0,50 };  
     Polyline(hdc, aptTriangle, ARRAYSIZE(aptTriangle));  
      
     HBRUSH hBrush = CreateHatchBrush(HS_DIAGCROSS, RGB(0, 0, 255));  
     // ' Select it for use in Form1, noting the previous brush.  
     HGDIOBJ hOldBrush = SelectObject(hdc, hBrush);  
     BOOL retval = FALSE;  
     // ' Flood fill the area outside the ellipse (use a green boundary)  
     retval = ExtFloodFill(hdc, 10, 10, Color::Black, FLOODFILLBORDER);//Picture 1  
     //retval = ExtFloodFill(hdc, 0, 51, Color::Black, FLOODFILLBORDER);//Picture 2  
      
     // ' Select the previously selected pen and brush.  
     SelectObject(hdc, hOldBrush);  
     // ' Delete the pen and brush to free up resources.  
     retval = DeleteObject(hBrush);  
                EndPaint(hWnd, &ps);  
            }  
            break;  
        case WM_DESTROY:  
            PostQuitMessage(0);  
            break;  
        default:  
            return DefWindowProc(hWnd, message, wParam, lParam);  
        }  
        return 0;  
    }  
    

    114474-image.png
    114475-image.png

    0 comments No comments

  5. William Kandler 1 Reputation point
    2021-07-14T18:47:29.167+00:00

    I write my question in vb; you answer in incomplete C.

    You specify:
    SetWindowExtEx(hdc, 100, 100, NULL);
    SetViewportExtEx(hdc, rc.right / 2, -rc.bottom / 2, NULL);
    SetViewportOrgEx(hdc, rc.right / 2, rc.bottom / 2, NULL);

    my obj is a 3000x3000 twits picturebox and my user coord. system is -2.5/-2.5 -> 2.5/2.5; so I should say?:

    SetWindowExtEx hdc, 3000, 3000, NULL
    SetViewportExtEx hdc, 2.5, -2.5, NULL
    SetViewportOrgEx hdc, 2.5, 2.5, NULL

    You then dispay using:
    POINT aptTriangle[] = { 0,50, 100,0, 0,-99, -25,0, 0,50 };
    Polyline(hdc, aptTriangle, ARRAYSIZE(aptTriangle));

    I can't draw my circle using inches at 0/0 with a radius of 2.5 with this code. that (as I originally stated) requires:

    dest.ScaleMode = vbInches

    dest.ScaleWidth = MaxDimension
    dest.ScaleLeft = -dest.ScaleWidth / 2

    dest.ScaleHeight = MaxDimension
    dest.ScaleTop = -dest.ScaleHeight / 2

    Then you fill via:

    retval = ExtFloodFill(hdc, 10, 10, Color::Black, FLOODFILLBORDER)

    My equivalent for center fill is:

    rtn = ExtFloodFill(dest.hDC, 0,0, 0, FLOODFILLBORDER)

    This fills, but not from the CENTER