Visão geral das geometrias de caminho

Este tópico descreve como usar Direct2D geometrias de caminho para criar desenhos complexos. Ele contém as seguintes seções:

Pré-requisitos

Essa visão geral pressupõe que você esteja familiarizado com a criação de aplicativos básicos Direct2D, conforme descrito em Criar um aplicativo de Direct2D simples. Ele também pressupõe que você esteja familiarizado com os recursos básicos de geometrias Direct2D, conforme descrito na Visão geral de geometrias.

Geometrias de caminho em Direct2D

As geometrias de caminho são representadas pela interface ID2D1PathGeometry . Para instanciar uma geometria de caminho, chame o método ID2D1Factory::CreatePathGeometry . Esses objetos podem ser usados para descrever figuras geométricas complexas compostas por segmentos como arcos, curvas e linhas. Para preencher uma geometria de caminho com figuras e segmentos, chame o método Open para recuperar um ID2D1GeometrySink e use os métodos do coletor de geometria para adicionar figuras e segmentos à geometria do caminho.

Usando um ID2D1GeometrySink para popular uma geometria de caminho

ID2D1GeometrySink descreve um caminho geométrico que pode conter linhas, arcos, curvas de Bézier cúbicas e curvas quadráticas de Bézier.

Um coletor de geometria consiste em uma ou mais figuras. Cada figura é composta por um ou mais segmentos de linha, curva ou arco. Para criar uma figura, chame o método BeginFigure , passando o ponto de partida da figura e, em seguida, use seus métodos Add (como AddLine e AddBezier) para adicionar segmentos. Quando terminar de adicionar segmentos, chame o método EndFigure . Você pode repetir essa sequência para criar figuras adicionais. Quando terminar de criar números, chame o método Close .

Exemplo: Criar um desenho complexo

A ilustração a seguir mostra um desenho complexo com linhas, arcos e curvas de Bézier. O exemplo de código a seguir mostra como criar o desenho usando quatro objetos de geometria de caminho, um para a montanha esquerda, um para a montanha direita, um para o rio e outro para o sol com sinalizadores.

ilustração de um rio, montanhas e o sol, usando geometrias de caminho

Criar uma geometria de caminho para a montanha esquerda

O exemplo primeiro cria uma geometria de caminho para a montanha esquerda, conforme mostrado na ilustração a seguir.

Mostra um desenho complexo de um polígono que mostra uma montanha.

Para criar a montanha esquerda, o exemplo chama o método ID2D1Factory::CreatePathGeometry para criar um ID2D1PathGeometry.

hr = m_pD2DFactory->CreatePathGeometry(&m_pLeftMountainGeometry);

Em seguida, o exemplo usa o método Open para obter um coletor de geometria de um ID2D1PathGeometry e o armazena na variável pSink .

ID2D1GeometrySink *pSink = NULL;
hr = m_pLeftMountainGeometry->Open(&pSink);

Em seguida, o exemplo chama BeginFigure, passando D2D1_FIGURE_BEGIN_FILLED que indica que essa figura está preenchida e chama AddLines, passando uma matriz de D2D1_POINT_2F pontos (267, 177), (236, 192), (212, 160), (156, 255) e (346, 255).

O código a seguir mostra como fazer isso.

pSink->SetFillMode(D2D1_FILL_MODE_WINDING);

pSink->BeginFigure(
    D2D1::Point2F(346,255),
    D2D1_FIGURE_BEGIN_FILLED
    );
D2D1_POINT_2F points[5] = {
   D2D1::Point2F(267, 177),
   D2D1::Point2F(236, 192),
   D2D1::Point2F(212, 160),
   D2D1::Point2F(156, 255),
   D2D1::Point2F(346, 255), 
   };
pSink->AddLines(points, ARRAYSIZE(points));
pSink->EndFigure(D2D1_FIGURE_END_CLOSED);

Criar uma geometria de caminho para a montanha direita

Em seguida, o exemplo cria outra geometria de caminho para a montanha direita com pontos (481, 146), (449, 181), (433, 159), (401, 214), (381, 199), (323, 263) e (575, 263). A ilustração a seguir mostra como a montanha direita é exibida.

ilustração de um polígono que mostra uma montanha

O código a seguir mostra como fazer isso.

        hr = m_pD2DFactory->CreatePathGeometry(&m_pRightMountainGeometry);
        if(SUCCEEDED(hr))
        {
            ID2D1GeometrySink *pSink = NULL;

            hr = m_pRightMountainGeometry->Open(&pSink);
            if (SUCCEEDED(hr))
            {
                pSink->SetFillMode(D2D1_FILL_MODE_WINDING);

                pSink->BeginFigure(
                    D2D1::Point2F(575,263),
                    D2D1_FIGURE_BEGIN_FILLED
                    );
                D2D1_POINT_2F points[] = {
                   D2D1::Point2F(481, 146),
                   D2D1::Point2F(449, 181),
                   D2D1::Point2F(433, 159),
                   D2D1::Point2F(401, 214),
                   D2D1::Point2F(381, 199), 
                   D2D1::Point2F(323, 263), 
                   D2D1::Point2F(575, 263)
                   };
                pSink->AddLines(points, ARRAYSIZE(points));
                pSink->EndFigure(D2D1_FIGURE_END_CLOSED);
            }
            hr = pSink->Close();

            SafeRelease(&pSink);
       }

Criar uma geometria de caminho para o sol

Em seguida, o exemplo preenche outra geometria de caminho para o sol, conforme mostrado na ilustração a seguir.

ilustração de um arco e curvas de bézier que mostram o sol

Para fazer isso, a geometria do caminho cria um coletor e adiciona uma figura para o arco e uma figura para cada sinalizador ao coletor. Repetindo a sequência de BeginFigure, seus métodos Add (como AddBezier) e EndFigure, várias figuras são adicionadas ao coletor.

O código a seguir mostra como fazer isso.

        hr = m_pD2DFactory->CreatePathGeometry(&m_pSunGeometry);
        if(SUCCEEDED(hr))
        {
            ID2D1GeometrySink *pSink = NULL;

            hr = m_pSunGeometry->Open(&pSink);
            if (SUCCEEDED(hr))
            {
                pSink->SetFillMode(D2D1_FILL_MODE_WINDING);
            
                pSink->BeginFigure(
                    D2D1::Point2F(270, 255),
                    D2D1_FIGURE_BEGIN_FILLED
                    );
                pSink->AddArc(
                    D2D1::ArcSegment(
                        D2D1::Point2F(440, 255), // end point
                        D2D1::SizeF(85, 85),
                        0.0f, // rotation angle
                        D2D1_SWEEP_DIRECTION_CLOCKWISE,
                        D2D1_ARC_SIZE_SMALL
                        ));            
                pSink->EndFigure(D2D1_FIGURE_END_CLOSED);

                pSink->BeginFigure(
                    D2D1::Point2F(299, 182),
                    D2D1_FIGURE_BEGIN_HOLLOW
                    );
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(299, 182),
                       D2D1::Point2F(294, 176),
                       D2D1::Point2F(285, 178)
                       ));
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(276, 179),
                       D2D1::Point2F(272, 173),
                       D2D1::Point2F(272, 173)
                       ));
                pSink->EndFigure(D2D1_FIGURE_END_OPEN);

                pSink->BeginFigure(
                    D2D1::Point2F(354, 156),
                    D2D1_FIGURE_BEGIN_HOLLOW
                    );
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(354, 156),
                       D2D1::Point2F(358, 149),
                       D2D1::Point2F(354, 142)
                       ));
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(349, 134),
                       D2D1::Point2F(354, 127),
                       D2D1::Point2F(354, 127)
                       ));
                pSink->EndFigure(D2D1_FIGURE_END_OPEN);

                pSink->BeginFigure(
                    D2D1::Point2F(322,164),
                    D2D1_FIGURE_BEGIN_HOLLOW
                    );
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(322, 164),
                       D2D1::Point2F(322, 156),
                       D2D1::Point2F(314, 152)
                       ));
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(306, 149),
                       D2D1::Point2F(305, 141),
                       D2D1::Point2F(305, 141)
                       ));              
                pSink->EndFigure(D2D1_FIGURE_END_OPEN);

                pSink->BeginFigure(
                    D2D1::Point2F(385, 164),
                    D2D1_FIGURE_BEGIN_HOLLOW
                    );
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(385,164),
                       D2D1::Point2F(392,161),
                       D2D1::Point2F(394,152)
                       ));
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(395,144),
                       D2D1::Point2F(402,141),
                       D2D1::Point2F(402,142)
                       ));                
                pSink->EndFigure(D2D1_FIGURE_END_OPEN);

                pSink->BeginFigure(
                    D2D1::Point2F(408,182),
                    D2D1_FIGURE_BEGIN_HOLLOW
                    );
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(408,182),
                       D2D1::Point2F(416,184),
                       D2D1::Point2F(422,178)
                       ));
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(428,171),
                       D2D1::Point2F(435,173),
                       D2D1::Point2F(435,173)
                       ));
                pSink->EndFigure(D2D1_FIGURE_END_OPEN);
            }
            hr = pSink->Close();

            SafeRelease(&pSink);
       }

Criar uma geometria de caminho para o rio

Em seguida, o exemplo cria outro caminho de geometria para o rio que contém curvas de Bézier. A ilustração a seguir mostra como o rio é exibido.

ilustração de curvas de bézier que mostram um rio

O código a seguir mostra como fazer isso.

        hr = m_pD2DFactory->CreatePathGeometry(&m_pRiverGeometry);
    
        if(SUCCEEDED(hr))
        {
            ID2D1GeometrySink *pSink = NULL;

            hr = m_pRiverGeometry->Open(&pSink);
            if (SUCCEEDED(hr))
            {
                pSink->SetFillMode(D2D1_FILL_MODE_WINDING);
                pSink->BeginFigure(
                    D2D1::Point2F(183, 392),
                    D2D1_FIGURE_BEGIN_FILLED
                    );
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(238, 284),
                       D2D1::Point2F(472, 345),
                       D2D1::Point2F(356, 303)
                       ));
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(237, 261),
                       D2D1::Point2F(333, 256),
                       D2D1::Point2F(333, 256)
                       ));
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(335, 257),
                       D2D1::Point2F(241, 261),
                       D2D1::Point2F(411, 306)
                       ));
                pSink->AddBezier(
                   D2D1::BezierSegment(
                       D2D1::Point2F(574, 350),
                       D2D1::Point2F(288, 324),
                       D2D1::Point2F(296, 392)
                       ));
                pSink->EndFigure(D2D1_FIGURE_END_OPEN);
            }

Renderizar as Geometrias de Caminho na Tela

O código a seguir mostra como renderizar as geometrias de caminho populadas na exibição. Primeiro desenha e pinta a geometria do sol, ao lado da geometria da montanha esquerda, depois a geometria do rio, e finalmente a geometria da montanha direita.

 m_pRenderTarget->BeginDraw();

 m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());

 m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));

 D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize();
 m_pRenderTarget->FillRectangle(
     D2D1::RectF(0, 0, rtSize.width, rtSize.height),
     m_pGridPatternBitmapBrush
     );

 m_pRenderTarget->FillGeometry(m_pSunGeometry, m_pRadialGradientBrush);

 m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black, 1.f));
 m_pRenderTarget->DrawGeometry(m_pSunGeometry, m_pSceneBrush, 1.f);

 m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::OliveDrab, 1.f));
 m_pRenderTarget->FillGeometry(m_pLeftMountainGeometry, m_pSceneBrush);

 m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black, 1.f));
 m_pRenderTarget->DrawGeometry(m_pLeftMountainGeometry, m_pSceneBrush, 1.f);

 m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::LightSkyBlue, 1.f));
 m_pRenderTarget->FillGeometry(m_pRiverGeometry, m_pSceneBrush);

 m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black, 1.f));
 m_pRenderTarget->DrawGeometry(m_pRiverGeometry, m_pSceneBrush, 1.f);

 m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::YellowGreen, 1.f));
 m_pRenderTarget->FillGeometry(m_pRightMountainGeometry, m_pSceneBrush);

 m_pSceneBrush->SetColor(D2D1::ColorF(D2D1::ColorF::Black, 1.f));
 m_pRenderTarget->DrawGeometry(m_pRightMountainGeometry, m_pSceneBrush, 1.f);


 hr = m_pRenderTarget->EndDraw();

O exemplo completo gera a ilustração a seguir.

ilustração de um rio, montanhas e o sol, usando geometrias de caminho

Criar um aplicativo Direct2D simples

Visão geral de geometrias