Direct2D: Geometries Overview
Опубликовано 26.05.2010 г. 00:06
Очередная статья, описывающая основы использования Direct2D, на этот раз посвящена использованию геометрических фигур. Первоисточником, как и прежде, является MSDN (Geometries Overview). Быть может в отличии от прежних статей данная будет более краткой и не такой подробной, но это вызвано тем, что мы уже немного знакомы с технологией и основными классами.
Что есть Direct2D geometry?
Ответ на данный вопрос прост, это объект представляющий геометрическую фигуру на плоскости, представленный классом ID2D1Geometry. При этом фигуры по сложности делятся на два вида: сложные и простые. К простым относятся элементарные фигуры:- прямоугольник (ID2D1RectangleGeometry )
- прямоугольник с закругленными углами (ID2D1RoundedRectangleGeometry)
- эллипс (ID2D1EllipseGeometry)
Простые фигуры
Как было сказано выше простые фигуры включают в себя прямоугольники, скругленные прямоугольники, и эллипсы. Думаю всем известно что окружность это частный случай эллипса (: Для создания простейших геометрических фигур предусмотрены соответствующие методы, по названиям самих фигур (а-ля Create[geometry_type]Geometry). Следующий код демонстрирует 4 варианта рисования эллипса:var e : ID2D1EllipseGeometry; factory : ID2D1Factory; ... with canvas do begin beginDraw(); //вариант №1. RenderTarget.GetFactory(factory); factory.CreateEllipseGeometry(D2D1Ellipse(point(150,150), 30, 30), e); rendertarget.DrawGeometry(e, brush.Handle); //вариант №2. DrawGeometry(e); //вариант №3. DrawEllipse(D2D1Ellipse(point(150,150),30,30)); //вариант №4. ellipse(200,100,250,250) EndDraw(); end;как не трудно заметить 1й способ, рисует заданную и предварительно созданную геометрию с помощью поверхности. Второй способ является имплементацией первого с помощью TDirect2dCanvas. Третий вариант рисует эллипс без использования геометрий, а используя структуру TD2D1Ellipse (которую кстати возвращает метод D2D1Ellipse), и четвертый метод рисует эллипс по четырем точкам. Поскольку речь идет о геометриях, то последние два метода рисования эллипса нам не интересны, хотя наверное они менее затратны с точки зрения использования ресурсов. Т.е скорее всего если вам потребуется просто нарисовать эллипс, то лучше обойтись без геометрий. Как обычно если нам требуется нарисовать контур фигуры то мы используем метод DrawGeometry(), а если залить внутренности то метод FillGeometry().
Сложные фигуры
Сложными фигурами будем называть сгруппированные или комбинированные фигуры, либо фигуру с какими либо трансформациями. Группы фигур представляются с помощью объекта ID2D1GeometryGroup, и создаются с помощью метода CreateGeometryGroup фабрики. Параметрами метода служат: вид заполнения, массив фигур, количество фигур в массиве. Посмотрим как это выглядит на примере. MSDN привел пример с тремя окружностями вложенными, но мы используем также и два других вида простых фигур.var gArray : array[0..3] of ID2D1Geometry; gg : ID2D1GeometryGroup; factory : ID2D1Factory; .... canvas.RenderTarget.GetFactory(factory); factory.CreateEllipseGeometry(D2D1Ellipse(point(150,150), 30, 30), ID2D1EllipseGeometry(gArray[0])); factory.CreateRectangleGeometry(Rect(100,100,200,200), ID2D1RectangleGeometry(gArray[1])); factory.CreateRoundedRectangleGeometry( D2D1RoundedRect(Rect(50,50,250,250),20,30), ID2D1RoundedRectangleGeometry(gArray[2])); .... //draw factory.CreateGeometryGroup(D2D1_FILL_MODE_WINDING, @gArray, 3, gg); FillGeometry(gg); .....Иллюстрация режимов заливки здесь. Отмечу что весьма интересно выглядит результат, когда фигуры не содержатся друг в друге, а пересекаются, что проиллюстрировано ниже:

Преобразования
Есть несколько путей чтобы изменить вид вашей фигуры. например вы можете использовать метод setTransform поверхности. Либо вы можете использовать метод CreateTransformedGeometry чтобы создать объект класса ID2D1TransformedGeometry. Понятное дело что вы должны использовать первый метод, когда хотите преобразовывать все что вы рисуете, и второй метод, когда хотите изменить только вашу фигуру. Не буду приводить исходный код потому как он весьма прост, и методами setTransform поверхности мы пользоваться уже умеем, параметрами же метода CreateTransformedGeometry являются те же матрицы преобразований что и для поверхности. При этом есть одно различие. Допустим мы имеем фигуру, например квадрат. Применим к поверхности трансформацию масштабирования (scale), и увеличим фигуру в два раза. После чего мы увидим что изменились не только координаты фигуры, но так же изменилась и толщина границы. Если же мы воспользуемся методом CreateTransformedGeometry то преобразование коснется лишь линейных размеров фигуры, толщина линий по-прежнему остается неизменной.Геометрические операции
Интерфейс ID2D1Geometry предоставляет набор различных геометрических операций для использования с фигурами. Самыми простыми о очевидными является метод комбинирования фигур CombineWithGeometry, который позволяет производить объединение, пересечение, исключение фигур. Для наглядности можно ознакомится с иллюстрацией.При использовании данного метода результат будет получен в объекте PathGeometry. Одним из параметров метода является матрица преобразований, при этом преобразование будет выполнено перед комбинированием. Не хочется подробно рассматривать все функции, просто перечислю часть из них.- расширять фигуру по границе [Widen()], на заданную ширину;
- определять содержит ли фигура заданную точку [FillContainsPoint()], что полезно для так называемого HitTest, либо же определять принадлежит точка границе фигуры [StrokeContainsPoint()].
- Точки в фигуре могут быть соединены не только прямыми но и дугами например, или кривыми Безье, метод Simplify() заменяет все такие кривые на прямые, для упрощения.
- Методы ComputeLength() и ComputeArea() соответственно вычисляют периметр и площадь фигуры.
- Функция CompareWithGeometry позволяет определить отношения между фигурами, например, содержит ли одна фигура другую и наоборот содержится, пересекаются фигуры или наоборот нет.
- Если ваша фигура имеет самопересечения то вы можете получить аналог без самопересечений используя метод Outline().
- Методы GetBounds и GetWidenedBounds позволяют получить описывающий фигуру прямоугольник, во втором случае прямоугольник будет описывать границы фигуры после различных преобразований, а в первом строится по исходным координатам.
- Осталось упомянуть два метода описанные в статье, ComputePointAtLength() сути которого я с первого прочтения не уловил,так что пояснить не могу. Второй - tesselate() в него вдаваться смысла пока нет ибо отдельная немного тематика, а подробностей для чего и как я не знаю.
Path geometries overview
Здесь содержится статья более подробно описывающая применение произвольных фигур. Итогом данной статьи является код реализующий следующую картинку:
Наверное самое важное что зритель отметит - применение кривых, для чего в произвольных фигурах используются не метод AddLines(), а метод AddBezier(). Автор этого блога перевел данное приложение на Delphi и разместил исходный код здесь, так что желающие могут ознакомится с профессиональной реализацией.
07.11.2012 в 17:11