Export (0) Print
Expand All

ID2D1Geometry::GetBounds methods

Retrieves the bounds of the geometry.

Overload list

MethodDescription
GetBounds(D2D1_MATRIX_3X2_F&,D2D_RECT_F*)

Retrieves the bounds of the geometry.

GetBounds(D2D1_MATRIX_3X2_F*,D2D1_RECT_F*)

Retrieves the bounds of the geometry.

Examples

The following code shows how to use GetBounds to retrieve the bounds of the geometry.


HRESULT hr = S_OK;

D2D1_RECT_F bounds;
D2D1_RECT_F inflatedPixelBounds;
D2D1_SIZE_U inflatedIntegerPixelSize;
D2D1_SIZE_U currentRTSize;
D2D1_MATRIX_3X2_F translateMatrix;
float dpiX, dpiY;
float scaleX = 1.0f;
float scaleY = 1.0f;

ID2D1BitmapRenderTarget *pCompatRT = NULL;
SafeReplace(&pCompatRT, *ppBitmapRT);

ID2D1SolidColorBrush *pBrush = NULL;

hr = pBaseRT->CreateSolidColorBrush(
    D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f),
    &pBrush
    );
if (SUCCEEDED(hr))
{
    pBaseRT->GetDpi(&dpiX, &dpiY);
    if (fill)
    {
        hr = pIGeometry->GetBounds(
            pWorldTransform,
            &bounds
            );
    }
    else
    {
        hr = pIGeometry->GetWidenedBounds(
            strokeWidth,
            pStrokeStyle,
            pWorldTransform,
            &bounds
            );
    }

    if (SUCCEEDED(hr))
    {
        //
        // A rect where left > right is defined to be empty.
        //
        // The slightly baroque expression used below is an idiom that also
        // correctly handles NaNs (i.e., if any of the coordinates of the bounds is
        // a NaN, we want to treat the bounds as empty)
        //
        if (
            !(bounds.left <= bounds.right) ||
            !(bounds.top <= bounds.bottom)
           )
        {
            // Bounds are empty or ill-defined.

            // Make up a fake bounds
            inflatedPixelBounds.top = 0.0f;
            inflatedPixelBounds.left = 0.0f;
            inflatedPixelBounds.bottom = 1.0f;
            inflatedPixelBounds.right = 1.0f;
        }
        else
        {
            //
            // We inflate the pixel bounds by 1 in each direction to ensure we have
            // a border of completely transparent pixels around the geometry.  This
            // ensures that when the realization is stretched the alpha ramp still
            // smoothly falls off to 0 rather than being clipped by the rect.
            //
            inflatedPixelBounds.top = floorf(bounds.top*dpiY/96)-1.0f;
            inflatedPixelBounds.left = floorf(bounds.left*dpiX/96)-1.0f;
            inflatedPixelBounds.bottom = ceilf(bounds.bottom*dpiY/96)+1.0f;
            inflatedPixelBounds.right = ceilf(bounds.right*dpiX/96)+1.0f;
        }


        //
        // Compute the width and height of the underlying bitmap we will need.
        // Note: We round up the width and height to be a multiple of
        // sc_bitmapChunkSize. We do this primarily to ensure that we aren't
        // constantly reallocating bitmaps in the case where a realization is being
        // zoomed in on slowly and updated frequently.
        //

        inflatedIntegerPixelSize = D2D1::SizeU(
            static_cast<UINT>(inflatedPixelBounds.right - inflatedPixelBounds.left),
            static_cast<UINT>(inflatedPixelBounds.bottom - inflatedPixelBounds.top)
            );

        // Round up
        inflatedIntegerPixelSize.width =
            (inflatedIntegerPixelSize.width + sc_bitmapChunkSize - 1)/sc_bitmapChunkSize * sc_bitmapChunkSize;

        // Round up
        inflatedIntegerPixelSize.height =
            (inflatedIntegerPixelSize.height + sc_bitmapChunkSize - 1)/sc_bitmapChunkSize * sc_bitmapChunkSize;

        //
        // Compute the bounds we will pass to FillOpacityMask (which are in Device
        // Independent Pixels).
        //
        // Note: The DIP bounds do *not* use the rounded coordinates, since this
        // would cause us to render superfluous, fully-transparent pixels, which
        // would hurt fill rate.
        //
        D2D1_RECT_F inflatedDipBounds = D2D1::RectF(
            inflatedPixelBounds.left * 96/dpiX,
            inflatedPixelBounds.top * 96/dpiY,
            inflatedPixelBounds.right * 96/dpiX,
            inflatedPixelBounds.bottom * 96/dpiY
            );

        if (pCompatRT)
        {
            currentRTSize = pCompatRT->GetPixelSize();
        }
        else
        {
            // This will force the creation of a new target
            currentRTSize = D2D1::SizeU(0,0);
        }

        //
        // We need to ensure that our desired render target size isn't larger than
        // the max allowable bitmap size. If it is, we need to scale the bitmap
        // down by the appropriate amount.
        //

        if (inflatedIntegerPixelSize.width > maxRealizationDimension)
        {
            scaleX = maxRealizationDimension/static_cast<float>(inflatedIntegerPixelSize.width);
            inflatedIntegerPixelSize.width = maxRealizationDimension;
        }

        if (inflatedIntegerPixelSize.height > maxRealizationDimension)
        {
            scaleY = maxRealizationDimension/static_cast<float>(inflatedIntegerPixelSize.height);
            inflatedIntegerPixelSize.height = maxRealizationDimension;
        }


        //
        // If the necessary pixel dimensions are less than half the existing
        // bitmap's dimensions (in either direction), force the bitmap to be
        // reallocated to save memory.
        //
        // Note: The fact that we use > rather than >= is important for a subtle
        // reason: We'd like to have the property that repeated small changes in
        // geometry size do not cause repeated reallocations of memory. >= does not
        // ensure this property in the case where the geometry size is close to
        // sc_bitmapChunkSize, but > does.
        //
        // Example:
        //
        // Assume sc_bitmapChunkSize is 64 and the initial geometry width is 63
        // pixels. This will get rounded up to 64, and we will allocate a bitmap
        // with width 64. Now, say, we zoom in slightly, so the new geometry width
        // becomes 65 pixels. This will get rounded up to 128 pixels, and a new
        // bitmap will be allocated. Now, say the geometry drops back down to 63
        // pixels. This will get rounded up to 64. If we used >=, this would cause
        // another reallocation.  Since we use >, on the other hand, the 128 pixel
        // bitmap will be reused.
        //

        if (currentRTSize.width > 2*inflatedIntegerPixelSize.width ||
            currentRTSize.height > 2*inflatedIntegerPixelSize.height
           )
        {
            SafeRelease(&pCompatRT);
            currentRTSize.width = currentRTSize.height = 0;
        }

        if (inflatedIntegerPixelSize.width > currentRTSize.width ||
            inflatedIntegerPixelSize.height > currentRTSize.height
           )
        {
            SafeRelease(&pCompatRT);
        }

        if (!pCompatRT)
        {
            //
            // Make sure our new rendertarget is strictly larger than before.
            //
            currentRTSize.width =
                max(inflatedIntegerPixelSize.width, currentRTSize.width);

            currentRTSize.height =
                max(inflatedIntegerPixelSize.height, currentRTSize.height);

            D2D1_PIXEL_FORMAT alphaOnlyFormat =
                D2D1::PixelFormat(
                    DXGI_FORMAT_A8_UNORM,
                    D2D1_ALPHA_MODE_PREMULTIPLIED
                    );

            hr = pBaseRT->CreateCompatibleRenderTarget(
                NULL, // desiredSize
                &currentRTSize,
                &alphaOnlyFormat,
                D2D1_COMPATIBLE_RENDER_TARGET_OPTIONS_NONE,
                &pCompatRT
                );
        }

        if (SUCCEEDED(hr))
        {
            //
            // Translate the geometry so it is flush against the left and top
            // sides of the render target.
            //

            translateMatrix =
                D2D1::Matrix3x2F::Translation(
                    -inflatedDipBounds.left,
                    -inflatedDipBounds.top
                    ) *
                D2D1::Matrix3x2F::Scale(
                    scaleX,
                    scaleY
                    );

            if (pWorldTransform)
            {
                pCompatRT->SetTransform(
                    *pWorldTransform * translateMatrix
                    );
            }
            else
            {
                pCompatRT->SetTransform(
                    translateMatrix
                    );
            }

            //
            // Render the geometry.
            //

            pCompatRT->BeginDraw();

            pCompatRT->Clear(
                D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f)
                );

            if (fill)
            {
                pCompatRT->FillGeometry(
                    pIGeometry,
                    pBrush
                    );
            }
            else
            {
                pCompatRT->DrawGeometry(
                    pIGeometry,
                    pBrush,
                    strokeWidth,
                    pStrokeStyle
                    );
            }

            hr = pCompatRT->EndDraw();
            if (SUCCEEDED(hr))
            {
                //
                // Report back the source and dest bounds (to be used as input parameters
                // to FillOpacityMask.
                //
                *pMaskDestBounds = inflatedDipBounds;

                *pMaskSourceBounds = D2D1::Rect<float>(
                    0.0f,
                    0.0f,
                    static_cast<float>(inflatedDipBounds.right - inflatedDipBounds.left)*scaleX,
                    static_cast<float>(inflatedDipBounds.bottom - inflatedDipBounds.top)*scaleY
                    );

                if (*ppBitmapRT != pCompatRT)
                {
                    SafeReplace(ppBitmapRT, pCompatRT);
                }
            }
        }
    }
    pBrush->Release();
}


For the complete example, see the Geometry Realization Sample.

Requirements

Library

D2d1.lib

DLL

D2d1.dll

See also

ID2D1Geometry

 

 

Community Additions

ADD
Show:
© 2014 Microsoft