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,428 questions
{count} votes

8 answers

Sort by: Most helpful
  1. William Kandler 1 Reputation point
    2021-07-16T00:05:00.797+00:00

    Some progress has been made! Using this to setup:

    Pic2.ScaleMode = vbInches
    SetMapMode Pic2.hDC, MM_ISOTROPIC
    SetWindowExtEx Pic2.hDC, 1, 1, Null
    SetViewportExtEx Pic2.hDC, GetDeviceCaps(Pic2.hDC, LOGPIXELSX), GetDeviceCaps(Pic2.hDC, LOGPIXELSY), Null

    1,1 is to get inches. your code suggested 64,64 to get 1/64; doesn't make sense. I tried .5,.5 and 2,2, no change. my object is (-2..5,-2.5)-(2.5,2.5)

    The object is drawn and extfloodfill works BUT is drawn at 4x size and the origin is at 0/0 (upperleft corner)

    I added 1 line:

    Pic2.ScaleMode = vbInches
    SetMapMode Pic2.hDC, MM_ISOTROPIC
    SetWindowExtEx Pic2.hDC, 1, 1, Null
    SetViewportExtEx Pic2.hDC, GetDeviceCaps(Pic2.hDC, LOGPIXELSX), GetDeviceCaps(Pic2.hDC, LOGPIXELSY), Null
    Pic2.Scale (-2.5, -2.5)-(2.5, 2.5)

    Object size and positioning now proper but fill stops working

    0 comments No comments

  2. Xiaopo Yang - MSFT 11,501 Reputation points Microsoft Vendor
    2021-07-16T01:49:00.38+00:00

    The object is not drawn at 4x size

    You need SetStretchBltMode and StretchBlt.

    the origin is not at 0/0.

    You need SetViewportOrgEx.
    Such as

    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, 1, 1, NULL);  
    			int pixel_x = GetDeviceCaps(hdc, LOGPIXELSX);  
    			int pixel_y = GetDeviceCaps(hdc, LOGPIXELSY);  
    			SetViewportExtEx(hdc, pixel_x, -pixel_y, NULL);  
    			SetViewportOrgEx(hdc, rc.right / 2, rc.bottom / 2, NULL);  
    			  
    			//POINT aptTriangle[] = { 0,50, 100,0,  0,-99, -25,0, 0,50 };  
    			POINT aptTriangle[] = { 0,1, 1,0,  0,-1, -1,0, 0,1 };  
    			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, 0, 2, Color::Black, FLOODFILLBORDER);//Picture 1  
      
    			//	' 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;  
    

    115186-image.png

    Note: ExtFloodFill has a int x and y. So ExtFloodFill(hdc, 0, 1.2, Color::Black, FLOODFILLBORDER); will not work.

    0 comments No comments

  3. William Kandler 1 Reputation point
    2021-07-16T17:23:44.987+00:00

    Yes, floodfill shows that problem, but it is working with fractional starting points.
    115409-untitled.png
    Below is almost all my code. The disputed part is right up front in the Form_Load proc. Which paints a ring on 2 3000x3000 twip pictureboxes. Pic1, the left, works for positioning(centered), origin location(center), and fills. Pic2 doesn’t work quite right. The ring displays at 2x the size (my earlier comment of 4x was wrong) , its origin is at the upperleft corner, and fill works. I tried both -100, -100 and 100, 100 for the Viewportorg statement. It seemed to have no effect.
    .

    Dim SideNum As Integer 'counts from 1 to sides as we go around ring

    Private Sub Form_Load()
    Me.Show

    Pic1.ScaleMode = vbInches
    size = 5
    Pic1.ScaleWidth = size
    Pic1.ScaleHeight = size
    DrawRing Pic1, PointOf(2.5, 2.5), 12, 2, 1.5
    fill Pic1, PointOf(2.5, 2.5), RGB(255, 255, 0)
    fill Pic1, PointOf(-2.3, -2.3), RGB(0, 0, 255)

    Pic2.ScaleMode = vbInches
    SetMapMode Pic2.hDC, MM_ISOTROPIC
    SetWindowExtEx Pic2.hDC, 1, 1, Null
    SetViewportExtEx Pic2.hDC, GetDeviceCaps(Pic2.hDC, LOGPIXELSX), -GetDeviceCaps(Pic2.hDC,LOGPIXELSY), Null
    SetViewportOrgEx hDC, -100, -100, Null
    DrawRing Pic2, PointOf(0, 0), 12, 2, 1.5
    fill Pic2, PointOf(0, 0), RGB(255, 255, 0)
    End Sub

    Private Sub DrawRing(dest As PictureBox, Origin As ObjPt, Sides As Integer, Radius As Single, Wall As Single)
    Dim SO1 As ObjPt 'gap adjusted segment outer previous
    Dim SO2 As ObjPt 'gap adjusted segment outer current
    Dim SI1 As ObjPt 'gap adjusted segment inner previous
    Dim SI2 As ObjPt 'gap adjusted segment inner current
    Dim Ctr As ObjPt
    Dim Angle As Single 'current Angle
    Dim InitialAngle As Single 'first angle in loop to display ring
    Dim Miter As Single
    InitialAngle = 0
    FinalAngle = 360
    SideNum = 0
    Miter = 180 / Max(Sides, 1) 'Get apparent Cutting Angle
    While Angle <= FinalAngle 'loop around the circle to create segments
    SideNum = SideNum + 1
    PolarToCartesian Origin, Radius, Angle - 2 * Miter, SO1 'get X,Y of prior outer corner
    PolarToCartesian Origin, Radius - Wall, Angle - 2 * Miter, SI1 'get X,Y of prior inner corner
    PolarToCartesian Origin, Radius, Angle, SO2 'get X,Y of current outer corner
    PolarToCartesian Origin, Radius - Wall, Angle, SI2 'get X,Y of current inner corner
    DrawLineObj dest, "lft", SI1, SO1, 0 'first inter-segment boundary
    DrawLineObj dest, "out", SO1, SO2, 0 'outer edge
    DrawLineObj dest, "inr", SI1, SI2, 0 'inner edge
    DrawLineObj dest, "rgt", SI2, SO2, 0 'final inter-segment boundary
    CtrPoint SI1, SO1, SI2, SO2, Ctr
    fill dest, Ctr, RGB(255 - 10 * SideNum, 0, 0)
    Angle = Angle + 2 * Miter 'advance to next segment in the circle/riing
    Wend
    End Sub

    Private Sub fill(dest As PictureBox, Ctr As ObjPt, Color As Long)
    Dim p As ObjPt
    Dim rtn As Long
    dest.FillStyle = cSolid
    dest.fillcolor = Color 'set fill style and color
    ScaleToPixelsObj dest, Ctr, p
    rtn = ExtFloodFill(dest.hDC, p.X, p.y, 0, FLOODFILLBORDER) 'do the fill
    End Sub

    Private Sub ScaleToPixelsObj(Pic As PictureBox, FromObj As ObjPt, ToObj As ObjPt)
    With FromObj
    ToObj.X = Pic.ScaleX(.X, Pic.ScaleMode, vbPixels)
    ToObj.y = Pic.ScaleY(.y, Pic.ScaleMode, vbPixels)
    End With
    End Sub

    Private Function PointOf(X As Single, y As Single) As ObjPt
    Dim ans As ObjPt
    ans.X = X
    ans.y = y
    PointOf = ans
    End Function