Gambaran umum geometri
Gambaran umum ini menjelaskan cara membuat dan menggunakan objekID2D1Geometryuntuk menentukan dan memanipulasi angka 2D. Ini berisi bagian berikut.
Apa itu geometri Direct2D?
Geometri Direct2D adalah ID2D1Geometry objek. Objek ini bisa menjadi 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 tidak dapat diubah dan merupakan sumber daya yang independen dari 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 yang independen dari perangkat dan bergantung pada perangkat, lihat Gambaran Umum Sumber Daya.
Bagian berikut menjelaskan berbagai jenis geometri.
Geometri sederhana
Geometri sederhana termasuk ID2D1RectangleGeometry, ID2D1RoundedRectangleGeometry, dan ID2D1EllipseGeometry objek, 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::Create<geometryType>Geometry. Metode ini membuat objek dari jenis yang ditentukan. Misalnya, untuk membuat persegi panjang, panggil ID2D1Factory::CreateRectangleGeometry, yang mengembalikan objekID2D1RectangleGeometry; untuk membuat persegi panjang bulat, panggil ID2D1Factory::CreateRoundedRectangleGeometry, yang mengembalikan objekID2D1RoundedRectangleGeometry, dan sebagainya.
Contoh kode berikut memanggil metodeCreateEllipseGeometry, 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 hitam ID2D1SolidColorBrush, 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 melukis interiornya, gunakan metodeFillGeometry.
Geometri jalur
Geometri jalur diwakili oleh antarmukaID2D1PathGeometry. Objek-objek ini dapat digunakan untuk menggambarkan gambar 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 ID2D1TransformedGeometry dan ID2D1GeometryGroup objek.
Kelompok geometri
Kelompok geometri adalah cara yang 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, dengan memberikan 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-tama mendeklarasikan array objek geometri. Objek ini adalah empat lingkaran konsentris yang memiliki radii berikut: 25, 50, 75, dan 100. Kemudian panggil CreateGeometryGroup pada objek ID2D1Factory, dengan memasukkan D2D1_FILL_MODE_ALTERNATE, sebuah array berisi objek geometri yang akan ditambahkan ke grup geometri, serta 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 mentransformasikan semua yang digambar oleh target render, atau Anda dapat menghubungkan transformasi secara langsung ke 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 garis ketika geometri sedang digambar.
Nota
Dimulai dengan Windows 8, transformasi dunia tidak akan mempengaruhi ketebalan stroke dengan D2D1_STROKE_TRANSFORM_TYPE_FIXEDatau 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 menggambarnya. Ilustrasi berikut menunjukkan hasil menggambar persegi panjang tanpa transformasi dan dengan transformasi. Perhatikan bahwa goresan lebih tebal setelah transformasi, meskipun ketebalan goresan 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 metodeCreateTransformedGeometry untuk menskalakan geometri dengan faktor 3, lalu menggambarnya. Ini menghasilkan output yang ditunjukkan dalam ilustrasi berikut. Perhatikan bahwa, meskipun persegi panjang lebih besar, garis tepinya tidak bertambah tebal.
// 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 objekID2D1Geometry sebagai masker geometris saat Anda memanggil metodePushLayer. Masker geometris menentukan area lapisan yang disusam ke dalam target render. Untuk informasi selengkapnya, lihat bagian Masker Geometrik dari Gambaran Umum Lapisan .
Operasi geometris
AntarmukaID2D1Geometry menyediakan beberapa operasi geometris yang dapat Anda gunakan untuk memanipulasi dan mengukur angka geometrik. Misalnya, Anda dapat menggunakannya untuk menghitung dan menentukan batas-batasnya, membandingkan untuk melihat bagaimana satu geometri secara spasial terkait dengan geometri lainnya (berguna untuk pengujian benturan), menghitung area dan panjang, dan banyak lagi. Tabel berikut ini menjelaskan operasi geometrik umum.
Operasi | Metode |
---|---|
Menggabungkan | GabungkanDenganGeometri |
Batas/ Batas yang Diperluas/Mengambil Batas, Pembaruan Wilayah Kotor | Widen, GetBounds, GetWidenedBounds |
Tekan Pengujian | FillContainsPoint, StrokeContainsPoint |
Stroke | StrokeMengandungTitik |
Perbandingan | BandingkanDenganGeometri |
Penyederhanaan (menghapus lengkungan dan kurva kuadrat Bezier) | Menyederhanakan |
Tessellation | Tessellate |
Garis Luar (hapus persimpangan) | Kerangka |
Menghitung luas atau panjang sebuah geometri | ComputeArea, ComputeLength, ComputePointAtLength |
Nota
Mulai Windows 8, Anda dapat menggunakan metodeComputePointAndSegmentAtLength padaID2D1PathGeometry1 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 (perpotongan), D2D1_COMBINE_MODE_XOR (xor), dan D2D1_COMBINE_MODE_EXCLUDE (pengecualian). 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 penggabungan union.
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 objekID2D1SimplifiedGeometrySink yang ditentukan. Contoh kode berikut memanggil Open pada objekID2D1PathGeometry. Jika Open berhasil, maka ia 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 menciptakan sekumpulan segitiga searah jarum jam yang mencakup geometri setelah diubah menggunakan matriks yang ditentukan dan diratakan sesuai 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 penyajian.
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, dengan 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 tersebut berisi titik yang ditentukan. Anda dapat menggunakan metode ini untuk melakukan uji tabrakan. Berikut ini adalah contoh kode yang 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 Simplify menghapus busur 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 diurai menjadi garis. Ini termasuk segmen penutupan implisit jika geometri ditutup. Contoh kode berikut menggunakan ComputeLength untuk menghitung panjang lingkaran yang ditentukan (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
);
Bandingkan Dengan Geometri
MetodeCompareWithGeometry menjelaskan persimpangan antara geometri yang memanggil metode ini dan geometri yang ditentukan. Nilai yang mungkin untuk persimpangan termasuk D2D1_GEOMETRY_RELATION_DISJOINT (terpisah), 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 bahwa geometri sepenuhnya terkandung oleh geometri yang ditentukan. "contains" berarti bahwa geometri sepenuhnya meliputi geometri yang ditentukan, dan "tumpang tindih" berarti dua geometri tumpang tindih tetapi tidak saling meliputi secara keseluruhan.
Contoh kode berikut menunjukkan cara membandingkan dua lingkaran yang memiliki radius sama-sama 50, tetapi digeser sejauh 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
);
}
}
Garis
Metode Outline menghitung garis batas dari geometri (versi geometri yang tidak saling berpotongan atau menyilang dengan figur lainnya) dan menulis hasilnya ke dalam ID2D1SimplifiedGeometrySink. Contoh kode berikut menggunakan Kerangka untuk membangun geometri yang setara tanpa persimpangan sendiri. 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.
}
MetodeGetWidenedBoundsmengambil 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 dari lingkaran tertentu (m_pCircleGeometry1) setelah lebarnya bertambah sesuai dengan 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
MetodeComputePointAtLength 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