Gambaran umum geometri
Gambaran umum ini menjelaskan cara membuat dan menggunakan objek ID2D1Geometry untuk menentukan dan memanipulasi gambar 2D. Ini berisi bagian berikut.
Apa itu geometri Direct2D?
Geometri Direct2D adalah objek ID2D1Geometry . Objek ini dapat berupa geometri sederhana (ID2D1RectangleGeometry, ID2D1RoundedRectangleGeometry, atau ID2D1EllipseGeometry), geometri jalur (ID2D1PathGeometry), atau geometri komposit (ID2D1GeometryGroup dan ID2D1TransformedGeometry).
Geometri Direct2D memungkinkan Anda menggambarkan gambar dua dimensi dan menawarkan banyak kegunaan, seperti menentukan wilayah uji hit, wilayah klip, dan bahkan jalur animasi.
Geometri Direct2D adalah sumber daya yang tidak dapat diubah dan independen perangkat yang dibuat oleh ID2D1Factory. Umumnya, Anda harus membuat geometri satu kali dan menyimpannya selama masa pakai aplikasi, atau sampai harus diubah. Untuk informasi selengkapnya tentang sumber daya independen perangkat dan bergantung pada perangkat, lihat Gambaran Umum Sumber Daya.
Bagian berikut menjelaskan berbagai jenis geometri.
Geometri sederhana
Geometri sederhana termasuk objek ID2D1RectangleGeometry, ID2D1RoundedRectangleGeometry, dan objek ID2D1EllipseGeometry , dan dapat digunakan untuk membuat angka geometrik dasar, seperti persegi panjang, persegi panjang bulat, lingkaran, dan elipsis.
Untuk membuat geometri sederhana, gunakan salah satu metode ID2D1Factory::CreategeometryTypeGeometry><. Metode ini membuat objek dari jenis yang ditentukan. Misalnya, untuk membuat persegi panjang, panggil ID2D1Factory::CreateRectangleGeometry, yang mengembalikan objek ID2D1RectangleGeometry ; untuk membuat persegi panjang bulat, panggil ID2D1Factory::CreateRoundedRectangleGeometry, yang mengembalikan objek ID2D1RoundedRectangleGeometry , dan sebagainya.
Contoh kode berikut memanggil metode CreateEllipseGeometry , meneruskan struktur elips dengan pusat diatur ke (100, 100), x-radius ke 100, dan y-radius ke 50. Kemudian, ia memanggil DrawGeometry, melewati geometri elips yang dikembalikan, pointer ke ID2D1SolidColorBrush hitam, dan lebar goresan 5. Ilustrasi berikut menunjukkan output dari contoh kode.
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);
Untuk menggambar kerangka geometri apa pun, gunakan metode DrawGeometry . Untuk mengecat interiornya, gunakan metode FillGeometry .
Geometri jalur
Geometri jalur diwakili oleh antarmuka ID2D1PathGeometry . Objek-objek ini dapat digunakan untuk menggambarkan angka geometris kompleks yang terdiri dari segmen seperti busur, kurva, dan garis. Ilustrasi berikut menunjukkan gambar yang dibuat dengan menggunakan geometri jalur.
Untuk informasi dan contoh selengkapnya, lihat Gambaran Umum Geometri Jalur.
Geometri komposit
Geometri komposit adalah geometri yang dikelompokkan atau dikombinasikan dengan objek geometri lain, atau dengan transformasi. Geometri komposit termasuk objek ID2D1TransformedGeometry dan ID2D1GeometryGroup .
Grup geometri
Kelompok geometri adalah cara mudah untuk mengelompokkan beberapa geometri pada saat yang sama sehingga semua angka dari beberapa geometri yang berbeda digabungkan menjadi satu. Untuk membuat objek ID2D1GeometryGroup , panggil metode CreateGeometryGroup pada objek ID2D1Factory , meneruskan fillMode dengan kemungkinan nilai D2D1_FILL_MODE_ALTERNATE (alternatif) dan D2D1_FILL_MODE_WINDING, array objek geometri untuk ditambahkan ke grup geometri, dan jumlah elemen dalam array ini.
Contoh kode berikut pertama kali mendeklarasikan array objek geometri. Objek-objek ini adalah empat lingkaran konsentris yang memiliki radii berikut: 25, 50, 75, dan 100. Kemudian panggil CreateGeometryGroup pada objek ID2D1Factory , meneruskan D2D1_FILL_MODE_ALTERNATE, array objek geometri untuk ditambahkan ke grup geometri, dan jumlah elemen dalam array ini.
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
);
}
Ilustrasi berikut menunjukkan hasil penyajian dua geometri grup dari contoh.
Geometri yang diubah
Ada beberapa cara untuk mengubah geometri. Anda dapat menggunakan metode SetTransform dari target render untuk mengubah semua yang digambar target render, atau Anda dapat mengaitkan transformasi langsung dengan geometri dengan menggunakan metode CreateTransformedGeometry untuk membuat ID2D1TransformedGeometry.
Metode yang harus Anda gunakan tergantung pada efek yang Anda inginkan. Ketika Anda menggunakan target render untuk mengubah dan kemudian merender geometri, transformasi memengaruhi segala sesuatu tentang geometri, termasuk lebar goresan apa pun yang telah Anda terapkan. Di sisi lain, ketika Anda menggunakan ID2D1TransformedGeometry, transformasi hanya memengaruhi koordinat yang menggambarkan bentuk. Transformasi tidak akan mempengaruhi ketebalan stroke ketika geometri digambar.
Catatan
Dimulai dengan Windows 8 transformasi dunia tidak akan mempengaruhi ketebalan stroke dengan D2D1_STROKE_TRANSFORM_TYPE_FIXED or D2D1_STROKE_TRANSFORM_TYPE_HAIRLINE. Anda harus menggunakan jenis transformasi ini untuk mencapai stroke independen transformasi
Contoh berikut membuat ID2D1RectangleGeometry, lalu menggambarnya tanpa mengubahnya. Ini menghasilkan output yang ditunjukkan dalam ilustrasi berikut.
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);
Contoh berikutnya menggunakan target render untuk menskalakan geometri dengan faktor 3, lalu menariknya. Ilustrasi berikut menunjukkan hasil menggambar persegi tanpa transformasi dan dengan transformasi. Perhatikan bahwa stroke lebih tebal setelah transformasi, meskipun ketebalan stroke adalah 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);
Contoh berikutnya menggunakan metode CreateTransformedGeometry untuk menskalakan geometri dengan faktor 3, lalu menggambarnya. Ini menghasilkan output yang ditunjukkan dalam ilustrasi berikut. Perhatikan bahwa, meskipun persegi panjang lebih besar, stroke-nya belum meningkat.
// 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);
Geometri sebagai masker
Anda dapat menggunakan objek ID2D1Geometry sebagai masker geometris saat Anda memanggil metode PushLayer . Masker geometris menentukan area lapisan yang disusung ke dalam target render. Untuk informasi selengkapnya, lihat bagian Masker Geometris dari Gambaran Umum Lapisan.
Operasi geometris
Antarmuka ID2D1Geometry menyediakan beberapa operasi geometris yang dapat Anda gunakan untuk memanipulasi dan mengukur angka geometris. Misalnya, Anda dapat menggunakannya untuk menghitung dan mengembalikan batasnya, membandingkan dengan melihat bagaimana satu geometri terkait spasial dengan yang lain (berguna untuk pengujian hit), menghitung area dan panjang, dan banyak lagi. Tabel berikut ini menjelaskan operasi geometris umum.
Operasi | Metode |
---|---|
Menggabungkan | CombineWithGeometry |
Bounds/ Widened Bounds/Retrieve Bounds, Dirty Region update | Widen, GetBounds, GetWidenedBounds |
Uji Temuan | FillContainsPoint, StrokeContainsPoint |
Stroke | StrokeContainsPoint |
Perbandingan | CompareWithGeometry |
Penyederhanaan (menghapus busur dan kurva Bezier kuadrat) | Menyederhanakan |
Tessellation | Tessellate |
Kerangka (hapus persimpangan) | Kerangka |
Menghitung area atau panjang geometri | ComputeArea, ComputeLength, ComputePointAtLength |
Catatan
Mulai dari Windows 8, Anda bisa menggunakan metode ComputePointAndSegmentAtLength pada ID2D1PathGeometry1 untuk menghitung area atau panjang geometri.
Menggabungkan geometri
Untuk menggabungkan satu geometri dengan geometri lainnya, panggil metode ID2D1Geometry::CombineWithGeometry . Saat menggabungkan geometri, Anda menentukan salah satu dari empat cara untuk melakukan operasi gabungan: D2D1_COMBINE_MODE_UNION (gabungan), D2D1_COMBINE_MODE_INTERSECT (bersinggungan), D2D1_COMBINE_MODE_XOR (xor), dan D2D1_COMBINE_MODE_EXCLUDE (kecualikan). Contoh kode berikut menunjukkan dua lingkaran yang digabungkan dengan menggunakan mode gabungan gabungan, di mana lingkaran pertama memiliki titik tengah (75, 75) dan radius 50, dan lingkaran kedua memiliki titik tengah (125, 75) dan radius 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);
}
}
Ilustrasi berikut menunjukkan dua lingkaran yang dikombinasikan dengan mode gabungan gabungan.
Untuk ilustrasi semua mode gabungan, lihat enumerasi D2D1_COMBINE_MODE.
Memperluas
Metode Widen menghasilkan geometri baru yang isinya setara dengan membelai geometri yang ada, lalu menulis hasilnya ke objek ID2D1SimplifiedGeometrySink yang ditentukan. Contoh kode berikut memanggil Buka pada objek ID2D1PathGeometry . Jika Buka berhasil, itu memanggil Widen pada objek geometri.
ID2D1GeometrySink *pGeometrySink = NULL;
hr = pPathGeometry->Open(&pGeometrySink);
if (SUCCEEDED(hr))
{
hr = pGeometry->Widen(
strokeWidth,
pIStrokeStyle,
pWorldTransform,
pGeometrySink
);
Tessellate
Metode Tessellate membuat satu set segitiga luka searah jarang yang menutupi geometri setelah diubah dengan menggunakan matriks yang ditentukan dan diratakan dengan menggunakan toleransi yang ditentukan. Contoh kode berikut menggunakan Tessellate untuk membuat daftar segitiga yang mewakili pPathGeometry. Segitiga disimpan dalam ID2D1Mesh, pMesh, lalu ditransfer ke anggota kelas, m_pStrokeMesh, untuk digunakan nanti saat merender.
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 dan StrokeContainsPoint
Metode FillContainsPoint menunjukkan apakah area yang diisi oleh geometri berisi titik yang ditentukan. Anda dapat menggunakan metode ini untuk melakukan pengujian hit. Contoh kode berikut memanggil FillContainsPoint pada objek ID2D1EllipseGeometry , melewati titik di (0,0) dan matriks Identitas .
BOOL containsPoint1;
hr = m_pCircleGeometry1->FillContainsPoint(
D2D1::Point2F(0,0),
D2D1::Matrix3x2F::Identity(),
&containsPoint1
);
if (SUCCEEDED(hr))
{
// Process containsPoint.
}
Metode StrokeContainsPoint menentukan apakah goresan geometri berisi titik yang ditentukan. Anda dapat menggunakan metode ini untuk melakukan pengujian hit. Contoh kode berikut menggunakan 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.
}
Menyederhanakan
Metode Sederhana menghapus lengkungan dan kurva Bezier kuadrat dari geometri tertentu. Jadi, geometri yang dihasilkan hanya berisi garis dan, secara opsional, kurva Bezier kubik. Contoh kode berikut menggunakan Sederhanakan untuk mengubah geometri dengan kurva Bezier menjadi geometri yang hanya berisi segmen garis.
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 dan ComputeArea
Metode ComputeLength menghitung panjang geometri yang ditentukan jika setiap segmen tidak terdaftar ke dalam garis. Ini termasuk segmen penutupan implisit jika geometri ditutup. Contoh kode berikut menggunakan ComputeLength untuk menghitung panjang lingkaran tertentu (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.
}
Metode ComputeArea menghitung area geometri yang ditentukan. Contoh kode berikut menggunakan ComputeArea untuk menghitung area lingkaran tertentu (m_pCircleGeometry1).
float area;
// Compute the area of circle1
hr = m_pCircleGeometry1->ComputeArea(
D2D1::IdentityMatrix(),
&area
);
CompareWithGeometry
Metode CompareWithGeometry menjelaskan persimpangan antara geometri yang memanggil metode ini dan geometri yang ditentukan. Nilai yang mungkin untuk persimpangan termasuk D2D1_GEOMETRY_RELATION_DISJOINT (terputus-putus), D2D1_GEOMETRY_RELATION_IS_CONTAINED (terkandung), D2D1_GEOMETRY_RELATION_CONTAINS (berisi), dan D2D1_GEOMETRY_RELATION_OVERLAP (tumpang tindih). "terputus-putus" berarti bahwa dua isian geometri tidak bersinggungan sama sekali. "terkandung" berarti geometri sepenuhnya terkandung oleh geometri yang ditentukan. "contains" berarti bahwa geometri benar-benar berisi geometri yang ditentukan, dan "tumpang tindih" berarti dua geometri tumpang tindih tetapi tidak sepenuhnya berisi yang lain.
Contoh kode berikut menunjukkan cara membandingkan dua lingkaran yang memiliki radius 50 yang sama tetapi diimbangi dengan 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
);
}
}
Kerangka
Metode Kerangka menghitung kerangka geometri (versi geometri di mana tidak ada gambar yang melintasi dirinya sendiri atau gambar lain) dan menulis hasilnya ke ID2D1SimplifiedGeometrySink. Contoh kode berikut menggunakan Kerangka untuk membangun geometri yang setara tanpa persimpangan diri. Ini menggunakan toleransi meratakan default.
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 dan GetWidenedBounds
Metode GetBounds mengambil batas geometri. Contoh kode berikut menggunakan GetBounds untuk mengambil batas lingkaran tertentu (m_pCircleGeometry1).
D2D1_RECT_F bounds;
hr = m_pCircleGeometry1->GetBounds(
D2D1::IdentityMatrix(),
&bounds
);
if (SUCCEEDED(hr))
{
// Retrieve the bounds.
}
Metode GetWidenedBounds mengambil batas geometri setelah dilebarkan oleh lebar dan gaya goresan yang ditentukan dan diubah oleh matriks yang ditentukan. Contoh kode berikut menggunakan GetWidenedBounds untuk mengambil batas lingkaran tertentu (m_pCircleGeometry1) setelah dilebarkan oleh lebar goresan yang ditentukan.
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.
}
ComputePointAtLength
Metode ComputePointAtLength menghitung vektor titik dan tangen pada jarak yang ditentukan di sepanjang geometri. Contoh kode berikut menggunakan ComputePointAtLength.
D2D1_POINT_2F point;
D2D1_POINT_2F tangent;
hr = m_pCircleGeometry1->ComputePointAtLength(
10,
NULL,
&point,
&tangent);
Topik terkait