Продолжение изучение геометрии, которая кратко была в 4 статье. Так как тема обширна, она будет разделена.
Рассмотрим геометрические структуры, использующиеся в статье:
-
D2D1_POINT_2F - Структура для представления точки в двумерном пространстве.
Поля структуры:
тип FLOAT x - Координата X точки
тип FLOAT y - Координата Y точки
-
D2D1_RECT_F - Структура для представления прямоугольника.
Поля структуры:
тип FLOAT left - Координата X левой границы прямоугольника
тип FLOAT top - Координата Y верхней границы прямоугольника
тип FLOAT right - Координата X правой границы прямоугольника
тип FLOAT bottom - Координата Y нижней границы прямоугольника
-
D2D1_MATRIX_3X2_F - Структура для представления матрицы преобразования 3x2
Поля структуры:
FLOAT _11 - Элемент матрицы [1,1] (масштаб по X)
FLOAT _12 - Элемент матрицы [1,2] (сдвиг по Y)
FLOAT _21 - Элемент матрицы [2,1] (сдвиг по X)
FLOAT _22 - Элемент матрицы [2,2] (масштаб по Y)
FLOAT _31 - Элемент матрицы [3,1] (смещение по X)
FLOAT _32 - Элемент матрицы [3,2] (смещение по Y)
-
D2D1_ELLIPSE - Структура для представления эллипса
Поля структуры:
D2D1_POINT_2F point - Центр эллипса
FLOAT radiusX - Радиус по оси X (горизонтальный радиус)
FLOAT radiusY - Радиус по оси Y (вертикальный радиус)
-
D2D1_ROUNDED_RECT - Структура для представления прямоугольника со скругленными углами
Поля структуры:
D2D1_RECT_F rect - Прямоугольник, определяющий границы фигуры
FLOAT radiusX - Радиус скругления по оси X (горизонтальный радиус)
FLOAT radiusY - Радиус скругления по оси Y (вертикальный радиус)
О родителе и дочерних классах:
-
ID2D1Geometry - Интерфейс для всех геометрических фигур. Предоставляет общие методы(они их дальше) которые вызываются у дочерних структур.
ID2D1RectangleGeometry - геометрия прямоугольника.
ID2D1RoundedRectangleGeometry - геометрия прямоугольника со скругленными углами.
ID2D1EllipseGeometry - геометрия эллипса/круга.
-
ID2D1PathGeometry - сложная геометрия пути (состоит из последовательности сегментов).
ID2D1PathGeometry1 - расширенная геометрия пути с дополнительными функциями анализа.
ID2D1TransformedGeometry - рансформированная геометрия (применена матрица преобразования).
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 - функция вернёт результат
Теперь разберём структуры и создание разных форм(напоминаю что сложную геометрию разобрали в прошлой статье)(Пример создания будет ниже):
Прямоугольник ID2D1RectangleGeometry , функция создания CreateRectangleGeometry вызывается через ID2D1Factory, первый аргумент это указатель на D2D1_RECT_F , второй указатель на ID2D1RectangleGeometry*.
Скруглённый прямоугольник ID2D1RoundedRectangleGeometry, собственно всё тоже самое как и с ID2D1RectangleGeometry , только второй аргумент указатель на ID2D1RoundedRectangleGeometry и первый аргумент указатель на D2D1_ROUNDED_RECT
Эллипс ID2D1EllipseGeometry , функция создания CreateEllipseGeometry вызывается через ID2D1Factory, первый аргумент это указатель на D2D1_ELLIPSE , второй аргумент указатель на ID2D1EllipseGeometry.
-
ID2D1GeometryGroup - по сути контейнер геометрии, где по итогу вы с множеством геометрий, работаете как с одной, то есть за раз можете сразу всё и отрисовать и прочее. Но процесс создания чуть сложней: вызов функции CreateGeometryGroup из ID2D1Geometry , первый аргумент это флаг заливки:
D2D1_FILL_MODE_ALTERNATE (чередование): Луч из точки пересекает контур. Внутренней считается область, где пересечений нечётное число.
D2D1_FILL_MODE_WINDING (направление): Учитывает направление контура (по или против часовой стрелки).
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 рассмотрим остальную часть геометрии, например структуру для хранения тесселяции. Собственно всем счастья и добра!
Arsenii14
Есть вариант как работать с D2d1, используя mingw? Больно уж мне не нравится вариант от корпорации добра.
Johnny_Depp Автор
Можете открыть MSDN и глянуть к какой dll относится и слепить хоть на NASM(как я делал однажды) :D
https://learn.microsoft.com/en-us/windows/win32/api/d2d1/nf-d2d1-d2d1createfactory - вот например, вниз мотните и там и dll и lib и заголовок, вполне можно подключить к проекту