Información general sobre geometrías de ruta de acceso

En este tema se describe cómo usar geometrías de ruta de acceso de Direct2D para crear dibujos complejos. Contiene las siguientes secciones:

Requisitos previos

En esta introducción se supone que está familiarizado con la creación de aplicaciones básicas de Direct2D, como se describe en Creación de una aplicación direct2D sencilla. También se supone que está familiarizado con las características básicas de las geometrías de Direct2D, como se describe en Información general sobre geometrías.

Geometrías de ruta de acceso en Direct2D

Las geometrías de ruta de acceso se representan mediante la interfaz ID2D1PathGeometry . Para crear una instancia de una geometría de ruta de acceso, llame al método ID2D1Factory::CreatePathGeometry . Estos objetos se pueden usar para describir figuras geométricas complejas compuestas de segmentos como arcos, curvas y líneas. Para rellenar una geometría de trazado con figuras y segmentos, llame al método Open para recuperar un ID2D1GeometrySink y use los métodos del receptor de geometría para agregar figuras y segmentos a la geometría de la ruta de acceso.

Usar un ID2D1GeometrySink para rellenar una geometría de ruta de acceso

ID2D1GeometrySink describe un trazado geométrico que puede contener líneas, arcos, curvas bezier cúbicas y curvas bezier cuadráticas.

Un receptor de geometría consta de una o varias figuras. Cada figura se compone de una o varias líneas, curvas o segmentos de arco. Para crear una ilustración, llame al método BeginFigure , pase el punto inicial de la figura y, a continuación, use sus métodos Add (como AddLine y AddBezier) para agregar segmentos. Cuando haya terminado de agregar segmentos, llame al método EndFigure . Puede repetir esta secuencia para crear figuras adicionales. Cuando haya terminado de crear ilustraciones, llame al método Close .

Ejemplo: Crear un dibujo complejo

En la ilustración siguiente se muestra un dibujo complejo con líneas, arcos y curvas Bezier. En el ejemplo de código siguiente se muestra cómo crear el dibujo mediante cuatro objetos geometry de trazado, uno para la montaña izquierda, otro para la montaña derecha, otro para el río y otro para el sol con brotes.

ilustración de un río, montañas y el sol, mediante geometrías de trazado

Crear una geometría de trazado para la montaña izquierda

En primer lugar, el ejemplo crea una geometría de trazado para la montaña izquierda, como se muestra en la ilustración siguiente.

Muestra un dibujo complejo de un polígono que muestra una montaña.

Para crear la montaña izquierda, el ejemplo llama al método ID2D1Factory::CreatePathGeometry para crear un id2D1PathGeometry.

hr = m_pD2DFactory->CreatePathGeometry(&m_pLeftMountainGeometry);

A continuación, en el ejemplo se usa el método Open para obtener un receptor de geometría de un ID2D1PathGeometry y almacenarlo en la variable pSink .

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

A continuación, el ejemplo llama a BeginFigure, pasando D2D1_FIGURE_BEGIN_FILLED que indica que esta figura se rellena, luego llama a AddLines, pasando una matriz de puntos de D2D1_POINT_2F , (267, 177), (236, 192), (212, 160), (156, 255) y (346, 255).

El código siguiente muestra cómo hacerlo.

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);

Crear una geometría de trazado para la montaña derecha

A continuación, el ejemplo crea otra geometría de trazado para la montaña derecha con puntos (481, 146), (449, 181), (433, 159), (401, 214), (381, 199), (323, 263) y (575, 263). En la ilustración siguiente se muestra cómo se muestra la montaña derecha.

ilustración de un polígono que muestra una montaña

El código siguiente muestra cómo hacerlo.

        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);
       }

Crear una geometría de trazado para el sol

A continuación, en el ejemplo se rellena otra geometría de trazado para el sol, como se muestra en la ilustración siguiente.

ilustración de una curva de arco y bezier que muestran el sol

Para ello, la geometría de la ruta de acceso crea un receptor y agrega una figura para el arco y una figura para cada brote al receptor. Al repetir la secuencia de BeginFigure, sus métodos Add (como AddBezier) y EndFigure, se agregan varias figuras al receptor.

El código siguiente muestra cómo hacerlo.

        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);
       }

Crear una geometría de trazado para el río

A continuación, en el ejemplo se crea otra ruta de geometría para el río que contiene curvas Bezier. En la ilustración siguiente se muestra cómo se muestra el río.

ilustración de curvas bezier que muestran un río

El código siguiente muestra cómo hacerlo.

        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);
            }

Representar las geometrías de la ruta de acceso en la pantalla

En el código siguiente se muestra cómo representar las geometrías de ruta de acceso rellenadas en la pantalla. Primero dibuja y pinta la geometría del sol, junto a la geometría de montaña izquierda, luego la geometría del río, y finalmente la geometría de la montaña derecha.

 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();

En el ejemplo completo se muestra la ilustración siguiente.

ilustración de un río, montañas y el sol, mediante geometrías de trazado

Creación de aplicación Direct2D simpl

Información general sobre las geometrías