Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
W tym omówieniu opisano sposób tworzenia i używania obiektów ID2D1Geometry do definiowania i manipulowania rysunkami 2D. Zawiera on następujące sekcje.
Co to jest geometria Direct2D?
Geometria Direct2D jest obiektem ID2D1Geometry . Ten obiekt może być prostą geometrią (ID2D1RectangleGeometry, ID2D1RoundedRectangleGeometry lub ID2D1EllipseGeometry), geometrią ścieżki (ID2D1PathGeometry) lub geometrią złożoną (ID2D1GeometryGroup i ID2D1TransformedGeometry).
Geometrie Direct2D umożliwiają opisywanie dwuwymiarowych liczb i oferowanie wielu zastosowań, takich jak definiowanie regionów testów trafień, regionów klipów, a nawet ścieżek animacji.
Geometrie Direct2D są niezmienne i niezależne od urządzenia zasoby utworzone przez ID2D1Factory. Ogólnie rzecz biorąc, należy utworzyć geometrie raz i zachować je na okres życia aplikacji lub do momentu ich zmiany. Aby uzyskać więcej informacji na temat zasobów niezależnych od urządzenia i zależnych od urządzenia, zobacz Omówienie zasobów.
W poniższych sekcjach opisano różne rodzaje geometrii.
Proste geometrie
Proste geometrie obejmują obiekty ID2D1RectangleGeometry, ID2D1RoundedRectangleGeometry i ID2D1EllipseGeometry i mogą służyć do tworzenia podstawowych figur geometrycznych, takich jak prostokąty, zaokrąglone prostokąty, okręgi i elipsy.
Aby utworzyć prostą geometrię, użyj jednej z metod ID2D1Factory::Create<geometryType>Geometry . Te metody tworzą obiekt określonego typu. Aby na przykład utworzyć prostokąt, wywołaj metodę ID2D1Factory::CreateRectangleGeometry, która zwraca obiekt ID2D1RectangleGeometry ; aby utworzyć zaokrąglony prostokąt, wywołaj metodę ID2D1Factory::CreateRoundedRectangleGeometry, która zwraca obiekt ID2D1RoundedRectangleGeometry itd.
Poniższy przykład kodu wywołuje metodę CreateEllipseGeometry, przekazując strukturę elipsy ze środkiem ustawionym na (100, 100), promieniem w osi x równym 100 i promieniem w osi y równym 50. Następnie wywołuje metodę DrawGeometry, przekazując zwróconą geometrię elipsy, wskaźnik do czarnego ID2D1SolidColorBrush i szerokość pociągnięcia wynoszącą 5. Poniższa ilustracja przedstawia dane wyjściowe z przykładu kodu.
ID2D1EllipseGeometry *m_pEllipseGeometry;
if (SUCCEEDED(hr))
{
hr = m_pD2DFactory->CreateEllipseGeometry(
D2D1::Ellipse(D2D1::Point2F(100.f, 60.f), 100.f, 50.f),
&m_pEllipseGeometry
);
}
m_pRenderTarget->DrawGeometry(m_pEllipseGeometry, m_pBlackBrush, 5);
Aby narysować kontur dowolnej geometrii, użyj metody DrawGeometry . Aby malować swoje wnętrze, użyj metody FillGeometry .
Geometrie ścieżek
Geometrie ścieżek są reprezentowane przez interfejsID2D1PathGeometry. Te obiekty mogą służyć do opisywania złożonych figur geometrycznych składających się z segmentów, takich jak łuki, krzywe i linie. Na poniższej ilustracji przedstawiono rysunek utworzony przy użyciu geometrii ścieżki.
Aby uzyskać więcej informacji i przykładów, zobacz Przegląd geometrii ścieżek.
Geometrie złożone
Geometria złożona to geometria pogrupowana lub połączona z innym obiektem geometrycznym lub przekształceniem. Geometrie złożone obejmują obiekty ID2D1TransformedGeometry i ID2D1GeometryGroup .
Grupy geometrii
Grupy geometryczne są wygodnym sposobem grupowania kilku geometrii w tym samym czasie, więc wszystkie figury kilku odrębnych geometrii są łączone w jeden. Aby utworzyć obiekt ID2D1GeometryGroup , wywołaj metodę CreateGeometryGroup w obiekcie ID2D1Factory , przekazując metodę fillMode z możliwymi wartościami D2D1_FILL_MODE_ALTERNATE (alternatywnych) i D2D1_FILL_MODE_WINDING, tablicą obiektów geometrycznych, które mają zostać dodane do grupy geometrii, oraz liczbę elementów w tej tablicy.
Poniższy przykład kodu najpierw deklaruje tablicę obiektów geometrycznych. Te obiekty są czterema okręgami koncentrycznymi, które mają następujące promienie: 25, 50, 75 i 100. Następnie wywołaj metodę CreateGeometryGroup w obiekcie ID2D1Factory , przekazując D2D1_FILL_MODE_ALTERNATE, tablicę obiektów geometrycznych, które mają zostać dodane do grupy geometrii oraz liczbę elementów w tej tablicy.
ID2D1Geometry *ppGeometries[] =
{
m_pEllipseGeometry1,
m_pEllipseGeometry2,
m_pEllipseGeometry3,
m_pEllipseGeometry4
};
hr = m_pD2DFactory->CreateGeometryGroup(
D2D1_FILL_MODE_ALTERNATE,
ppGeometries,
ARRAYSIZE(ppGeometries),
&m_pGeoGroup_AlternateFill
);
if (SUCCEEDED(hr))
{
hr = m_pD2DFactory->CreateGeometryGroup(
D2D1_FILL_MODE_WINDING,
ppGeometries,
ARRAYSIZE(ppGeometries),
&m_pGeoGroup_WindingFill
);
}
Poniższa ilustracja przedstawia wyniki renderowania dwóch geometrii grup z przykładu.
Przekształcone geometrie
Istnieje wiele sposobów przekształcania geometrii. Możesz użyć metody SetTransform elementu docelowego renderowania, aby przekształcić wszystko, co rysuje obiekt docelowy renderowania, lub można skojarzyć przekształcenie bezpośrednio z geometrią przy użyciu metody CreateTransformedGeometry w celu utworzenia elementu ID2D1TransformedGeometry.
Metoda, której należy użyć, zależy od żądanego efektu. Gdy używasz celu renderowania do przekształcania, a następnie renderowania geometrii, transformacja wpływa na całą geometrię, w tym szerokość każdego zastosowanego pociągnięcia. Z drugiej strony, jeśli używasz id2D1TransformedGeometry, przekształcenie wpływa tylko na współrzędne, które opisują kształt. Przekształcenie nie wpłynie na grubość linii, gdy geometria zostanie narysowana.
Uwaga / Notatka
Począwszy od systemu Windows 8, transformacja przestrzeni nie wpłynie na grubość pociągnięć z D2D1_STROKE_TRANSFORM_TYPE_FIXED albo D2D1_STROKE_TRANSFORM_TYPE_HAIRLINE. Tych typów transformacji należy użyć do osiągnięcia niezależnych pociągnięć
Poniższy przykład tworzy ID2D1RectangleGeometry, a następnie rysuje go, nie dokonując jego przekształceń. Spowoduje to wygenerowanie danych wyjściowych przedstawionych na poniższej ilustracji.
hr = m_pD2DFactory->CreateRectangleGeometry(
D2D1::RectF(150.f, 150.f, 200.f, 200.f),
&m_pRectangleGeometry
);
// Draw the untransformed rectangle geometry.
m_pRenderTarget->DrawGeometry(m_pRectangleGeometry, m_pBlackBrush, 1);
W następnym przykładzie użyto celu renderowania do skalowania geometrii przez współczynnik 3, a następnie ją rysuje. Poniższa ilustracja przedstawia wynik rysowania prostokąta bez przekształcenia oraz z przekształceniem. Zwróć uwagę, że pociągnięcie jest grubsze po przekształceniu, mimo że grubość pociągnięcia wynosi 1.
// Transform the render target, then draw the rectangle geometry again.
m_pRenderTarget->SetTransform(
D2D1::Matrix3x2F::Scale(
D2D1::SizeF(3.f, 3.f),
D2D1::Point2F(175.f, 175.f))
);
m_pRenderTarget->DrawGeometry(m_pRectangleGeometry, m_pBlackBrush, 1);
W następnym przykładzie użyto metody CreateTransformedGeometry do skalowania geometrii przez współczynnik 3, a następnie rysuje ją. Spowoduje to wygenerowanie danych wyjściowych przedstawionych na poniższej ilustracji. Zwróć uwagę, że chociaż prostokąt jest większy, jego pociągnięcie nie zostało zwiększone.
// Create a geometry that is a scaled version
// of m_pRectangleGeometry.
// The new geometry is scaled by a factory of 3
// from the center of the geometry, (35, 35).
hr = m_pD2DFactory->CreateTransformedGeometry(
m_pRectangleGeometry,
D2D1::Matrix3x2F::Scale(
D2D1::SizeF(3.f, 3.f),
D2D1::Point2F(175.f, 175.f)),
&m_pTransformedGeometry
);
// Replace the previous render target transform.
m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
// Draw the transformed geometry.
m_pRenderTarget->DrawGeometry(m_pTransformedGeometry, m_pBlackBrush, 1);
Geometrie jako maski
Podczas wywoływania metody PushLayer można użyć obiektu ID2D1Geometry jako maski geometrycznej. Maska geometryczna określa obszar warstwy komponowanej do celu renderowania. Aby uzyskać więcej informacji, zobacz sekcję Przegląd warstw dotyczącą Geometricznych masek.
Operacje geometryczne
Interfejs ID2D1Geometry udostępnia kilka operacji geometrycznych, których można użyć do manipulowania i mierzenia figur geometrycznych. Można na przykład użyć ich do obliczenia i zwrócenia ich granic, aby sprawdzić, jak jedna geometria jest przestrzennie powiązana z inną (przydatną do testowania trafień), obliczyć obszary i długości i nie tylko. W poniższej tabeli opisano typowe operacje geometryczne.
Operacja | Metoda |
---|---|
Łączyć | CombineWithGeometry |
Ograniczenia/ Rozszerzone granice/Pobieranie granic, Aktualizacja zanieczyszczonego regionu | Widen, GetBounds, GetWidenedBounds |
Testowanie trafień | FillContainsPoint, StrokeContainsPoint |
Udar | StrokeContainsPoint |
Porównanie | CompareWithGeometry |
Uproszczenie (usuwa łuki i krzywe Beziera kwadratowego) | Uprościć |
Tesselacja | Tessellate |
Konspekt (usuń przecięcie) | Zarys |
Obliczanie obszaru lub długości geometrii | ComputeArea, ComputeLength, ComputePointAtLength |
Uwaga / Notatka
Począwszy od systemu Windows 8, można użyć metody ComputePointAndSegmentAtLength w id2D1PathGeometry1 , aby obliczyć obszar lub długość geometrii.
Łączenie geometrii
Aby połączyć jedną geometrię z inną, wywołaj metodę ID2D1Geometry::CombineWithGeometry . Po połączeniu geometrii należy określić jeden z czterech sposobów wykonywania operacji łączenia: D2D1_COMBINE_MODE_UNION (unii), D2D1_COMBINE_MODE_INTERSECT (przecięcie), D2D1_COMBINE_MODE_XOR (xor) i D2D1_COMBINE_MODE_EXCLUDE (wykluczanie). Poniższy przykład kodu przedstawia dwa okręgi, połączone przy użyciu trybu sumy. Pierwszy okrąg ma środek w punkcie (75, 75) i o promieniu 50, a drugi okrąg ma środek w punkcie (125, 75) i o promieniu 50.
HRESULT hr = S_OK;
ID2D1GeometrySink *pGeometrySink = NULL;
// Create the first ellipse geometry to merge.
const D2D1_ELLIPSE circle1 = D2D1::Ellipse(
D2D1::Point2F(75.0f, 75.0f),
50.0f,
50.0f
);
hr = m_pD2DFactory->CreateEllipseGeometry(
circle1,
&m_pCircleGeometry1
);
if (SUCCEEDED(hr))
{
// Create the second ellipse geometry to merge.
const D2D1_ELLIPSE circle2 = D2D1::Ellipse(
D2D1::Point2F(125.0f, 75.0f),
50.0f,
50.0f
);
hr = m_pD2DFactory->CreateEllipseGeometry(circle2, &m_pCircleGeometry2);
}
if (SUCCEEDED(hr))
{
//
// Use D2D1_COMBINE_MODE_UNION to combine the geometries.
//
hr = m_pD2DFactory->CreatePathGeometry(&m_pPathGeometryUnion);
if (SUCCEEDED(hr))
{
hr = m_pPathGeometryUnion->Open(&pGeometrySink);
if (SUCCEEDED(hr))
{
hr = m_pCircleGeometry1->CombineWithGeometry(
m_pCircleGeometry2,
D2D1_COMBINE_MODE_UNION,
NULL,
NULL,
pGeometrySink
);
}
if (SUCCEEDED(hr))
{
hr = pGeometrySink->Close();
}
SafeRelease(&pGeometrySink);
}
}
Poniższa ilustracja przedstawia dwa okręgi połączone metodą łączenia suma.
Aby uzyskać ilustracje dotyczące wszystkich trybów łączenia, zobacz wyliczenie D2D1_COMBINE_MODE.
Rozszerzyć
Metoda Widen generuje nową geometrię, której wypełnienie jest równoważne naciśnięciu istniejącej geometrii, a następnie zapisuje wynik do określonego obiektu ID2D1SimplifiedGeometrySink . Poniższy przykład kodu wywołuje metodę Open w obiekcie ID2D1PathGeometry . Jeśli Open zakończy się sukcesem, wywołuje metodę Widen na obiekcie geometrycznym.
ID2D1GeometrySink *pGeometrySink = NULL;
hr = pPathGeometry->Open(&pGeometrySink);
if (SUCCEEDED(hr))
{
hr = pGeometry->Widen(
strokeWidth,
pIStrokeStyle,
pWorldTransform,
pGeometrySink
);
Tessellate
Metoda Tessellate tworzy zestaw trójkątów ran zgodnie z ruchem wskazówek zegara, które pokrywają geometrię po jej przekształceniu przy użyciu określonej macierzy i spłaszczone przy użyciu określonej tolerancji. W poniższym przykładzie kodu użyto narzędzia Tessellate do utworzenia listy trójkątów reprezentujących element pPathGeometry. Trójkąty są przechowywane w id2D1Mesh, pMesh, a następnie przenoszone do składowej klasy , m_pStrokeMesh, do późniejszego użycia podczas renderowania.
ID2D1Mesh *pMesh = NULL;
hr = m_pRT->CreateMesh(&pMesh);
if (SUCCEEDED(hr))
{
ID2D1TessellationSink *pSink = NULL;
hr = pMesh->Open(&pSink);
if (SUCCEEDED(hr))
{
hr = pPathGeometry->Tessellate(
NULL, // world transform (already handled in Widen)
pSink
);
if (SUCCEEDED(hr))
{
hr = pSink->Close();
if (SUCCEEDED(hr))
{
SafeReplace(&m_pStrokeMesh, pMesh);
}
}
pSink->Release();
}
pMesh->Release();
}
FillContainsPoint i StrokeContainsPoint
Metoda FillContainsPoint wskazuje, czy obszar wypełniony geometrią zawiera określony punkt. Za pomocą tej metody można wykonywać sprawdzanie trafień. Poniższy przykład kodu wywołuje FillContainsPoint na obiekcie ID2D1EllipseGeometry, przekazując punkt (0,0) i macierz tożsamościową.
BOOL containsPoint1;
hr = m_pCircleGeometry1->FillContainsPoint(
D2D1::Point2F(0,0),
D2D1::Matrix3x2F::Identity(),
&containsPoint1
);
if (SUCCEEDED(hr))
{
// Process containsPoint.
}
Metoda StrokeContainsPoint określa, czy obrys geometrii zawiera określony punkt. Za pomocą tej metody można przeprowadzić testowanie kolizji. W poniższym przykładzie kodu użyto elementu StrokeContainsPoint.
BOOL containsPoint;
hr = m_pCircleGeometry1->StrokeContainsPoint(
D2D1::Point2F(0,0),
10, // stroke width
NULL, // stroke style
NULL, // world transform
&containsPoint
);
if (SUCCEEDED(hr))
{
// Process containsPoint.
}
Uprościć
Metoda Upraszczanie usuwa łuki i krzywe Beziera z określonej geometrii. W związku z tym wynikowa geometria zawiera tylko linie i, opcjonalnie, krzywe Beziera sześciennego. W poniższym przykładzie kodu użyto metody Upraszczanie , aby przekształcić geometrię za pomocą krzywych Beziera w geometrię zawierającą tylko segmenty linii.
HRESULT D2DFlatten(
ID2D1Geometry *pGeometry,
float flatteningTolerance,
ID2D1Geometry **ppGeometry
)
{
HRESULT hr;
ID2D1Factory *pFactory = NULL;
pGeometry->GetFactory(&pFactory);
ID2D1PathGeometry *pPathGeometry = NULL;
hr = pFactory->CreatePathGeometry(&pPathGeometry);
if (SUCCEEDED(hr))
{
ID2D1GeometrySink *pSink = NULL;
hr = pPathGeometry->Open(&pSink);
if (SUCCEEDED(hr))
{
hr = pGeometry->Simplify(
D2D1_GEOMETRY_SIMPLIFICATION_OPTION_LINES,
NULL, // world transform
flatteningTolerance,
pSink
);
if (SUCCEEDED(hr))
{
hr = pSink->Close();
if (SUCCEEDED(hr))
{
*ppGeometry = pPathGeometry;
(*ppGeometry)->AddRef();
}
}
pSink->Release();
}
pPathGeometry->Release();
}
pFactory->Release();
return hr;
}
ComputeLength i ComputeArea
Metoda ComputeLength oblicza długość określonej geometrii, jeśli każdy segment został wyrejestrowany do linii. Obejmuje to niejawny segment zamykający, jeśli geometria jest zamknięta. Poniższy przykład kodu używa metody ComputeLength do obliczenia długości określonego okręgu (m_pCircleGeometry1).
float length;
// Compute the area of circle1
hr = m_pCircleGeometry1->ComputeLength(
D2D1::IdentityMatrix(),
&length
);
if (SUCCEEDED(hr))
{
// Process the length of the geometry.
}
Metoda ComputeArea oblicza obszar określonej geometrii. Poniższy przykład kodu używa obszaru ComputeArea do obliczenia obszaru określonego okręgu (m_pCircleGeometry1).
float area;
// Compute the area of circle1
hr = m_pCircleGeometry1->ComputeArea(
D2D1::IdentityMatrix(),
&area
);
CompareWithGeometry
Metoda CompareWithGeometry opisuje przecięcie między geometrią, która wywołuje tę metodę i określoną geometrię. Możliwe wartości skrzyżowania obejmują D2D1_GEOMETRY_RELATION_DISJOINT (rozłączne), D2D1_GEOMETRY_RELATION_IS_CONTAINED (jest zawarte), D2D1_GEOMETRY_RELATION_CONTAINS (zawiera) i D2D1_GEOMETRY_RELATION_OVERLAP (nakładające się). "rozłączne" oznacza, że dwa wypełnienia geometryczne w ogóle nie przecinają się. "jest zawarty" oznacza, że geometria jest całkowicie zawarta w określonej geometrii. "contains" oznacza, że geometria całkowicie zawiera określoną geometrię, a "overlap" oznacza, że dwie geometrie nakładają się, ale żadna z nich nie zawiera całkowicie drugiej.
Poniższy przykład kodu pokazuje, jak porównać dwa okręgi, które mają ten sam promień 50, ale są przesunięte o 50.
HRESULT hr = S_OK;
ID2D1GeometrySink *pGeometrySink = NULL;
// Create the first ellipse geometry to merge.
const D2D1_ELLIPSE circle1 = D2D1::Ellipse(
D2D1::Point2F(75.0f, 75.0f),
50.0f,
50.0f
);
hr = m_pD2DFactory->CreateEllipseGeometry(
circle1,
&m_pCircleGeometry1
);
if (SUCCEEDED(hr))
{
// Create the second ellipse geometry to merge.
const D2D1_ELLIPSE circle2 = D2D1::Ellipse(
D2D1::Point2F(125.0f, 75.0f),
50.0f,
50.0f
);
hr = m_pD2DFactory->CreateEllipseGeometry(circle2, &m_pCircleGeometry2);
}
D2D1_GEOMETRY_RELATION result = D2D1_GEOMETRY_RELATION_UNKNOWN;
// Compare circle1 with circle2
hr = m_pCircleGeometry1->CompareWithGeometry(
m_pCircleGeometry2,
D2D1::IdentityMatrix(),
0.1f,
&result
);
if (SUCCEEDED(hr))
{
static const WCHAR szGeometryRelation[] = L"Two circles overlap.";
m_pRenderTarget->SetTransform(D2D1::IdentityMatrix());
if (result == D2D1_GEOMETRY_RELATION_OVERLAP)
{
m_pRenderTarget->DrawText(
szGeometryRelation,
ARRAYSIZE(szGeometryRelation) - 1,
m_pTextFormat,
D2D1::RectF(25.0f, 160.0f, 200.0f, 300.0f),
m_pTextBrush
);
}
}
Zarys
Metoda Konspektu oblicza konspekt geometrii (wersja geometrii, w której żaden rysunek nie przecina się ani żaden inny rysunek) i zapisuje wynik w id2D1SimplifiedGeometrySink. W poniższym przykładzie kodu użyto konspektu w celu skonstruowania równoważnej geometrii bez żadnych samocięcia. Używa domyślnej tolerancji spłaszczania.
HRESULT D2DOutline(
ID2D1Geometry *pGeometry,
ID2D1Geometry **ppGeometry
)
{
HRESULT hr;
ID2D1Factory *pFactory = NULL;
pGeometry->GetFactory(&pFactory);
ID2D1PathGeometry *pPathGeometry = NULL;
hr = pFactory->CreatePathGeometry(&pPathGeometry);
if (SUCCEEDED(hr))
{
ID2D1GeometrySink *pSink = NULL;
hr = pPathGeometry->Open(&pSink);
if (SUCCEEDED(hr))
{
hr = pGeometry->Outline(NULL, pSink);
if (SUCCEEDED(hr))
{
hr = pSink->Close();
if (SUCCEEDED(hr))
{
*ppGeometry = pPathGeometry;
(*ppGeometry)->AddRef();
}
}
pSink->Release();
}
pPathGeometry->Release();
}
pFactory->Release();
return hr;
}
GetBounds i GetWidenedBounds
Metoda GetBounds pobiera granice geometrii. Poniższy przykład kodu używa funkcji GetBounds do pobierania granic określonego okręgu (m_pCircleGeometry1).
D2D1_RECT_F bounds;
hr = m_pCircleGeometry1->GetBounds(
D2D1::IdentityMatrix(),
&bounds
);
if (SUCCEEDED(hr))
{
// Retrieve the bounds.
}
Metoda GetWidenedBounds pobiera granice geometrii po jej poszerzone przez określoną szerokość i styl pociągnięcia oraz przekształcone przez określoną macierz. Poniższy przykład kodu używa metody GetWidenedBounds do pobierania granic określonego okręgu (m_pCircleGeometry1) po jego poszerzonej o określoną szerokość pociągnięcia.
float dashes[] = {1.f, 1.f, 2.f, 3.f, 5.f};
m_pD2DFactory->CreateStrokeStyle(
D2D1::StrokeStyleProperties(
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_FLAT,
D2D1_CAP_STYLE_ROUND,
D2D1_LINE_JOIN_ROUND, // lineJoin
10.f, //miterLimit
D2D1_DASH_STYLE_CUSTOM,
0.f //dashOffset
),
dashes,
ARRAYSIZE(dashes)-1,
&m_pStrokeStyle
);
D2D1_RECT_F bounds1;
hr = m_pCircleGeometry1->GetWidenedBounds(
5.0,
m_pStrokeStyle,
D2D1::IdentityMatrix(),
&bounds1
);
if (SUCCEEDED(hr))
{
// Retrieve the widened bounds.
}
ObliczPunktNaDługości
Metoda ComputePointAtLength oblicza punkt i wektor tangens na określonej odległości wzdłuż geometrii. W poniższym przykładzie kodu użyto metody ComputePointAtLength.
D2D1_POINT_2F point;
D2D1_POINT_2F tangent;
hr = m_pCircleGeometry1->ComputePointAtLength(
10,
NULL,
&point,
&tangent);
Tematy pokrewne