Продолжение изучение геометрии, которая кратко была в 4 статье. Так как тема обширна, она будет разделена.

Рассмотрим геометрические структуры, использующиеся в статье:

  1. D2D1_POINT_2F - Структура для представления точки в двумерном пространстве.

    Поля структуры:

    1. тип FLOAT x - Координата X точки

    2. тип FLOAT y - Координата Y точки

  2. D2D1_RECT_F - Структура для представления прямоугольника.

    Поля структуры:

    1. тип FLOAT left - Координата X левой границы прямоугольника

    2. тип FLOAT top - Координата Y верхней границы прямоугольника

    3. тип FLOAT right - Координата X правой границы прямоугольника

    4. тип FLOAT bottom - Координата Y нижней границы прямоугольника

  3. D2D1_MATRIX_3X2_F - Структура для представления матрицы преобразования 3x2

    Поля структуры:

    1. FLOAT _11 - Элемент матрицы [1,1] (масштаб по X)

    2. FLOAT _12 - Элемент матрицы [1,2] (сдвиг по Y)

    3. FLOAT _21 - Элемент матрицы [2,1] (сдвиг по X)

    4. FLOAT _22 - Элемент матрицы [2,2] (масштаб по Y)

    5. FLOAT _31 - Элемент матрицы [3,1] (смещение по X)

    6. FLOAT _32 - Элемент матрицы [3,2] (смещение по Y)

  4. D2D1_ELLIPSE - Структура для представления эллипса

    Поля структуры:

    1. D2D1_POINT_2F point - Центр эллипса

    2. FLOAT radiusX - Радиус по оси X (горизонтальный радиус)

    3. FLOAT radiusY - Радиус по оси Y (вертикальный радиус)

  5. D2D1_ROUNDED_RECT - Структура для представления прямоугольника со скругленными углами

    Поля структуры:

    1. D2D1_RECT_F rect - Прямоугольник, определяющий границы фигуры

    2. FLOAT radiusX - Радиус скругления по оси X (горизонтальный радиус)

    3. FLOAT radiusY - Радиус скругления по оси Y (вертикальный радиус)

О родителе и дочерних классах:

  1. ID2D1Geometry - Интерфейс для всех геометрических фигур. Предоставляет общие методы(они их дальше) которые вызываются у дочерних структур.

    1. ID2D1RectangleGeometry - геометрия прямоугольника.

    2. ID2D1RoundedRectangleGeometry - геометрия прямоугольника со скругленными углами.

    3. ID2D1EllipseGeometry - геометрия эллипса/круга.

    4. ID2D1PathGeometry - сложная геометрия пути (состоит из последовательности сегментов).

      1. ID2D1PathGeometry1 - расширенная геометрия пути с дополнительными функциями анализа.

    5. ID2D1TransformedGeometry - рансформированная геометрия (применена матрица преобразования).

    6. ID2D1GeometryGroup - группа геометрий (объединяет несколько геометрий).

О общих методах:

Функции
  • Возвращаемый тип HRESULT название GetBounds:

  • Назначение:

    Описывает геометрию квадратом(внешним) или прямоугольником без учёта обводки

  • Аргументы:

    const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования(может быть nullptr).

    D2D1_RECT_F* bounds - результат функции.

  • Возвращаемый тип HRESULT название GetWidenedBounds:

  • Назначение:

    Описывает геометрию квадратом(внешним) или прямоугольником с учётом обводки

  • Аргументы:

    FLOAT strokeWidth - ширина строки(по умолчанию 1.0F).

    ID2D1StrokeStyle* strokeStyle - стиль строки(по умолчанию 0).

    const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования(может быть nullptr).

    FLOAT flatteningTolerance - допуск аппроксимации(есть вариант функции без него).

    D2D1_RECT_F* bounds - результат функции.

  • Возвращаемый тип HRESULT название FillContainsPoint:

  • Назначение:

    Проверяет находится ли точка внутри геометрии.

  • Аргументы:

  • D2D1_POINT_2F point - координата точки

  • const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования(может быть nullptr).

  • FLOAT flatteningTolerance - допуск аппроксимации(есть вариант функции без него).

  • BOOL* contains - результат функции.

  • Возвращаемый тип HRESULT название StrokeContainsPoint:

  • Назначение:

    Проверяет находится ли точка на обводке геометрии.

  • Аргументы:

  • D2D1_POINT_2F point - координата точки.

  • FLOAT strokeWidth - ширина строки.

  • ID2D1StrokeStyle* strokeStyle - стиль строки.

  • const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования(может быть nullptr).

  • FLOAT flatteningTolerance - допуск аппроксимации(есть вариант функции без него).

  • BOOL* contains - результат функции.

  • Возвращаемый тип HRESULT название ComputeArea

  • Назначение:

    Вычисляет площадь фигуры

  • Аргументы:

    const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования(может быть nullptr).

    FLOAT flatteningTolerance - допуск аппроксимации(есть вариант функции без него).

    FLOAT* area - результат функции.

  • Возвращаемый тип HRESULT название ComputeLength

  • Назначение:

  • Длина контура фигуры. То есть вот есть вершины фигуры, и проходим от одной к другой, от неё к следующей и так до конца, и вот путь это длина контура фигуры.

  • Аргументы:

  • const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования(может быть nullptr).

  • FLOAT flatteningTolerance - допуск аппроксимации(есть вариант функции без него).

  • FLOAT* length - результат функции.

  • возвращаемый тип HRESULT название ComputePointAtLength

  • Назначение:

    Находит точку на обводке и возвращает её, находит по принципу что мы указываем расстояние мин. значение которого 0 , а макс. значение которое возвращает функция ComputeLength , и функция берёт каждую вершину и строит вектор, и проходит от одного к другому, когда пройдённый путь является тем, что передали в функцию, например 50 , то возвращает точку на обводке и единичный вектор - направление.

  • Аргументы:

  • FLOAT length - длина пути, когда вернуть функцию.

  • const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования(может быть nullptr).

  • FLOAT flatteningTolerance - допуск аппроксимации(есть вариант функции без него).

  • D2D1_POINT_2F* point - вернёт результат функции - координату на обводке.

  • D2D1_POINT_2F* unitTangentVector - вернёт второй результат функции - единичный вектор - направление. (Может быть nullptr).

  • возвращаемый тип HRESULT название CompareWithGeometry

  • Назначение:

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

  • Аргументы:

  • ID2D1Geometry *inputGeometry - геометрия для сравнения

  • const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования(может быть nullptr).

  • FLOAT flatteningTolerance - допуск аппроксимации(есть вариант функции без него).

  • D2D1_GEOMETRY_RELATION *relation - енум перечисления и результат функции. Варианты:

    • D2D1_GEOMETRY_RELATION_DISJOINT - фигуры не пересекаются

    • D2D1_GEOMETRY_RELATION_IS_CONTAINED - фигура у которой вызвали функцию внутри той, которую передали функцию.

    • D2D1_GEOMETRY_RELATION_CONTAINS - фигура которую передали функцию внутри той у которой вызвали функцию

    • D2D1_GEOMETRY_RELATION_OVERLAP - фигуры пересекаются

    • D2D1_GEOMETRY_RELATION_UNKNOWN - ошибка вычисления

  • возвращаемый тип HRESULT название CombineWithGeometry

  • Назначение:

    Объединяет две фигуры по одному из четырёх правил, создавая единую фигуру-результат.

  • Аргументы:

  • ID2D1Geometry *inputGeometry - геометрия для объединения

  • enum D2D1_COMBINE_MODE - флаг объединения:

    D2D1_COMBINE_MODE_UNION 0x0 - Объединение ⬜ + ⬜ = ⬜ . Все точки, принадлежащие хотя бы одной из фигур.

    D2D1_COMBINE_MODE_INTERSECT 0x1 - Пересечение ◩ ∩ ◪ = ◨ . Только точки, принадлежащие обеим фигурам одновременно.

    D2D1_COMBINE_MODE_XOR 0x2 - Исключающее ИЛИ ◩ ⊕ ◪ = ◩◪ . Точки, принадлежащие только одной фигуре (но не обеим).

    D2D1_COMBINE_MODE_EXCLUDE 0x3 - Вычитание ◩ \ ◪ = ◩ . Точки первой фигуры за вычетом области второй фигуры.

  • D2D1_MATRIX_3X2_F *inputGeometryTransform - матрица преобразования (может быть nullptr).

  • FLOAT flatteningTolerance - допуск аппроксимации (есть вариант функции без него).

  • ID2D1SimplifiedGeometrySink *geometrySink - функция вернёт результат например в переданный ID2D1PathGeometry.

  • возвращаемый тип HRESULT название Simplify

  • Назначение:

    Упрощает геометрию: либо сохраняет только сегменты линий и кривых Безье 3-го порядка, удаляя дуги, либо преобразует все сегменты в линии.

  • Аргументы:

  • D2D1_GEOMETRY_SIMPLIFICATION_OPTION simplificationOption - флаг-опция:

    • D2D1_GEOMETRY_SIMPLIFICATION_OPTION_CUBICS_AND_LINES - результат может содержать кубические кривые Безье и отрезки прямых. Все остальные типы сегментов например дуги преобразуются в кубические кривые Безье.

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

  • D2D1_MATRIX_3X2_F &worldTransform - матрица преобразования (может быть nullptr).

  • FLOAT flatteningTolerance - допуск аппроксимации (есть вариант функции без него).

  • ID2D1SimplifiedGeometrySink *geometrySink - функция вернёт результат например в переданный ID2D1PathGeometry.

  • возвращаемый тип HRESULT название Outline

  • Назначение:

    Убирает внутренние пересечения , по сути оставляя только контур фигуры.

  • Аргументы:

  • const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования (может быть nullptr).

  • FLOAT flatteningTolerance - допуск аппроксимации (есть вариант функции без него).

  • ID2D1SimplifiedGeometrySink *geometrySink - функция вернёт результат

  • возвращаемый тип HRESULT название Widen

  • Назначение:

    Обводит фигуру обводкой, без учёта текущей, и возвращает как отдельную фигуру.

  • Аргументы:

  • const D2D1_MATRIX_3X2_F* worldTransform - матрица преобразования (может быть nullptr).

  • FLOAT flatteningTolerance - допуск аппроксимации (есть вариант функции без него).

  • ID2D1SimplifiedGeometrySink *geometrySink - функция вернёт результат

Теперь разберём структуры и создание разных форм(напоминаю что сложную геометрию разобрали в прошлой статье)(Пример создания будет ниже):

  1. Прямоугольник ID2D1RectangleGeometry , функция создания CreateRectangleGeometry вызывается через ID2D1Factory, первый аргумент это указатель на D2D1_RECT_F , второй указатель на ID2D1RectangleGeometry*.

  2. Скруглённый прямоугольник ID2D1RoundedRectangleGeometry, собственно всё тоже самое как и с ID2D1RectangleGeometry , только второй аргумент указатель на ID2D1RoundedRectangleGeometry и первый аргумент указатель на D2D1_ROUNDED_RECT

  3. Эллипс ID2D1EllipseGeometry , функция создания CreateEllipseGeometry вызывается через ID2D1Factory, первый аргумент это указатель на D2D1_ELLIPSE , второй аргумент указатель на ID2D1EllipseGeometry.

  4. ID2D1GeometryGroup - по сути контейнер геометрии, где по итогу вы с множеством геометрий, работаете как с одной, то есть за раз можете сразу всё и отрисовать и прочее. Но процесс создания чуть сложней: вызов функции CreateGeometryGroup из ID2D1Geometry , первый аргумент это флаг заливки:

    1. D2D1_FILL_MODE_ALTERNATE (чередование): Луч из точки пересекает контур. Внутренней считается область, где пересечений нечётное число.

    2. D2D1_FILL_MODE_WINDING (направление): Учитывает направление контура (по или против часовой стрелки).

  5. ID2D1TransformedGeometry - хранит матрицу которую повернули и\или изменили масштаб. Функция создания CreateTransformedGeometry вызов из ID2D1Factory

Собственно код-примеры для каждой функции, на основе кода из прошлой статьи.

На основе их и будут примеры.

Функция GetBounds, жертвой станет круг. Первый аргумент матрица преобразования, её нет поэтому nullptr, второе, это ссылка для возвращения результат функцией.
Собственно код который меняем:

Код

Меняем код в начале:


ID2D1RectangleGeometry* pReactangleOne = nullptr;
D2D1_RECT_F bounds;

ID2D1EllipseGeometry* pEllipseOne = nullptr;
D2D1_RECT_F reactangle = D2D1::RectF(10,10,60,60);
D2D1_ELLIPSE ellipse = D2D1::Ellipse({ 100,100 }, 20, 20);
ID2D1Factory* pFactory = nullptr;
ID2D1HwndRenderTarget* pRenderTarget = nullptr;
ID2D1SolidColorBrush* pBlackBrush = nullptr;
ID2D1SolidColorBrush* pRedBrush = nullptr;
ID2D1SolidColorBrush* pBlueBrush = nullptr;
ID2D1SolidColorBrush* pGreenBrush = nullptr;


template<class T>
void SafeRelease(T** ppT)
{
    if (*ppT)
    {
        (*ppT)->Release();
        *ppT = nullptr;
    }
}

// Создание устройство-независимых ресурсов
HRESULT CreateDeviceIndependentResources()
{
    HRESULT hr = S_OK;

    // Создаем фабрику Direct2D
    hr = D2D1CreateFactory(
        D2D1_FACTORY_TYPE_SINGLE_THREADED,
        &pFactory
    );

    pFactory->CreateRectangleGeometry(&reactangle, &pReactangleOne);
    pFactory->CreateEllipseGeometry(&ellipse, &pEllipseOne);
    pEllipseOne->GetBounds(nullptr, &bounds);
        
    return hr;
}

И метод onRender:

void OnRender(HWND hwnd)
{
    HRESULT hr = CreateDeviceResources(hwnd);

    if (SUCCEEDED(hr) && !(pRenderTarget->CheckWindowState() & D2D1_WINDOW_STATE_OCCLUDED))
    {
        pRenderTarget->BeginDraw();

        // Очищаем область белым цветом
        pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));






        pRenderTarget->DrawGeometry(pReactangleOne, pBlackBrush, 1.0F, 0);
        pRenderTarget->DrawGeometry(pEllipseOne, pRedBrush, 1.0F, 0);
        pRenderTarget->DrawRectangle(bounds, pBlackBrush, 1.0F, 0);
   
        hr = pRenderTarget->EndDraw();
    
       
        // Если устройство потеряно, пересоздаем ресурсы
        if (hr == D2DERR_RECREATE_TARGET)
        {
            DiscardDeviceResources();
        }
    }
}

Результат:


функция GetWidenedBounds , делает тоже самое что и GetBounds, но учитывает обводку. Первый аргумент принимает ширину строки, вторым стиль, третьим матрицу трансформации, а четвёртый может быть как допуск аппроксимации, либо же сразу ссылка на D2D1_RECT_F , в которую будет передан результат, собственно логика создания такая же как в GetBounds. А вот и результат:

Всё остальное работает по такому же принципу. В части 2 рассмотрим остальную часть геометрии, например структуру для хранения тесселяции. Собственно всем счастья и добра!

Комментарии (2)


  1. Arsenii14
    07.12.2025 16:17

    Есть вариант как работать с D2d1, используя mingw? Больно уж мне не нравится вариант от корпорации добра.


    1. Johnny_Depp Автор
      07.12.2025 16:17

      Можете открыть MSDN и глянуть к какой dll относится и слепить хоть на NASM(как я делал однажды) :D

      https://learn.microsoft.com/en-us/windows/win32/api/d2d1/nf-d2d1-d2d1createfactory - вот например, вниз мотните и там и dll и lib и заголовок, вполне можно подключить к проекту