ID2D1Geometry::GetWidenedBounds 메서드
지정한 스트로크 너비와 스타일에 의해 확장되고 지정된 행렬에 의해 변환된 후 기하 도형의 경계를 가져옵니다.
오버로드 목록
메서드 | 설명 |
---|---|
GetWidenedBounds(FLOAT,ID2D1StrokeStyle*,D2D1_MATRIX_3X2_F&D2D1_RECT_F*) | 지정한 스트로크 너비와 스타일에 의해 확장되고 지정된 행렬에 의해 변환된 후 기하 도형의 경계를 가져옵니다. |
GetWidenedBounds(FLOAT,ID2D1StrokeStyle*,D2D1_MATRIX_3X2_F*,D2D1_RECT_F*) | 지정한 스트로크 너비와 스타일에 의해 확장되고 지정된 행렬에 의해 변환된 후 기하 도형의 경계를 가져옵니다. |
GetWidenedBounds(FLOAT,ID2D1StrokeStyle*,D2D1_MATRIX_3X2_F&,FLOAT,D2D1_RECT_F*) | 지정한 스트로크 너비와 스타일에 의해 확장되고 지정된 행렬에 의해 변환된 후 기하 도형의 경계를 가져옵니다. |
GetWidenedBounds(FLOAT,ID2D1StrokeStyle*,D2D1_MATRIX_3X2_F*,FLOAT,D2D1_RECT_F*) | 지정한 스트로크 너비와 스타일에 의해 확장되고 지정된 행렬에 의해 변환된 후 기하 도형의 경계를 가져옵니다. |
예제
다음 코드에서는 GetWidenedBounds를 사용하여 지정된 스트로크 너비 및 스타일에 의해 확장되고 지정된 행렬에 의해 변형된 후 기하 도형의 범위를 검색하는 방법을 보여 줍니다.
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
¤tRTSize,
&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();
}
요구 사항
요구 사항 | 값 |
---|---|
라이브러리 |
|
DLL |
|