Общие сведения о геометриях путей

В этом разделе описывается, как использовать геометрию пути Direct2D для создания сложных чертежей. В него входят следующие разделы.

Предварительные требования

В этом обзоре предполагается, что вы знакомы с созданием базовых приложений Direct2D, как описано в разделе Создание простого приложения Direct2D. Также предполагается, что вы знакомы с основными функциями геометрий Direct2D, как описано в обзоре геометрических объектов.

Геометрические объекты пути в Direct2D

Геометрические объекты пути представлены интерфейсом ID2D1PathGeometry . Чтобы создать экземпляр геометрии пути, вызовите метод ID2D1Factory::CreatePathGeometry . Эти объекты можно использовать для описания сложных геометрических фигур, состоящих из сегментов, таких как дуги, кривые и линии. Чтобы заполнить геометрию пути фигурами и сегментами, вызовите метод Open , чтобы получить id2D1GeometrySink , и используйте методы приемника geometry для добавления фигур и сегментов в геометрию пути.

Использование ID2D1GeometrySink для заполнения геометрии пути

ID2D1GeometrySink описывает геометрический путь, который может содержать линии, дуги, кубические кривые Безье и квадратичные кривые Безье.

Приемник geometry состоит из одной или нескольких фигур. Каждая фигура состоит из одного или нескольких сегментов линии, кривой или дуги. Чтобы создать фигуру, вызовите метод BeginFigure , передав начальную точку рисунка, а затем используйте его методы Add (например , AddLine и AddBezier) для добавления сегментов. Завершив добавление сегментов, вызовите метод EndFigure . Эту последовательность можно повторить, чтобы создать дополнительные фигуры. Завершив создание рисунков, вызовите метод Close .

Пример. Создание сложного документа

На следующем рисунке показан сложный рисунок с линиями, дугами и кривыми Безье. В следующем примере кода показано, как создать рисунок с помощью четырех геометрических объектов пути: один для левой горы, один для правой горы, один для реки и один для солнца с вспышками.

изображение реки, гор и солнца с использованием геометрии пути

Создание геометрии пути для левой горы

В примере сначала создается геометрия пути для левой горы, как показано на следующем рисунке.

Показывает сложный рисунок многоугольника, показывающий гору.

Чтобы создать левую гору, в примере вызывается метод ID2D1Factory::CreatePathGeometry для создания ID2D1PathGeometry.

hr = m_pD2DFactory->CreatePathGeometry(&m_pLeftMountainGeometry);

Затем в примере используется метод Open для получения приемника geometry из ID2D1PathGeometry и сохраняется в переменной pSink .

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

Затем в примере вызывается BeginFigure, передавая D2D1_FIGURE_BEGIN_FILLED , указывающее, что эта цифра заполнена, а затем вызывает AddLines, передав массив D2D1_POINT_2F точек( 267, 177), (236, 192), (212, 160), (156, 255) и (346, 255).

В следующем примере кода показано, как это сделать:

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

Создание геометрии пути для правой горы

Затем в примере создается другая геометрия пути для правой горы с точками (481, 146), (449, 181), (433, 159), (401, 214), (381, 199), (323, 263) и (575, 263). На следующем рисунке показано, как отображается правая гора.

иллюстрация многоугольника, показывающая гору

В следующем примере кода показано, как это сделать:

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

Создание геометрии пути для Солнца

Затем в примере заполняется другая геометрия пути для солнца, как показано на следующем рисунке.

иллюстрация дуги и безье кривых, которые показывают солнце

Для этого геометрия пути создает приемник и добавляет фигуру для дуги и фигуру для каждой вспышки в приемник. Повторяя последовательность BeginFigure, ее методов Add (например , AddBezier) и EndFigure, в приемник добавляются несколько фигур.

В следующем примере кода показано, как это сделать:

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

Создание геометрии пути для реки

Затем в примере создается другой геометрический путь для реки, содержащей кривые Безье. На следующем рисунке показано, как отображается река.

иллюстрация кривых безье, показывающих реку

В следующем примере кода показано, как это сделать:

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

Отрисовка геометрических объектов пути на дисплее

В следующем коде показано, как отобразить заполненные геометрические объекты пути на экране. Сначала рисует и рисует геометрию солнца, затем левую геометрию горы, затем геометрию реки и, наконец, правую геометрию горы.

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

Полный пример выводит следующий рисунок.

изображение реки, гор и солнца с использованием геометрии пути

Создание простого приложения Direct2D

Обзор геометрий