Нашли ошибку или опечатку? Выделите текст и нажмите

Поменять цветовую

гамму сайта?

Поменять
Обновления сайта
и новые разделы

Рекомендовать в Google +1

PathGeometry

23

В PathGeometry содержится вся мощь геометрий. Этот объект может рисовать все, что и прочие объекты геометрии, плюс многое другое. Единственный связанный с ним недостаток — более длинный (и иногда сложный) синтаксис.

Каждый объект PathGeometry строится на основе одного или более объектов PathFigure (хранящихся в коллекции PathGeometry.Figures). Каждая фигура PathFigure представляет собой непрерывный набор связанных отрезков прямых и кривых линий, которые могут быть замкнуты или разомкнуты. Фигура замкнута, если конец последней линии фигуры соединяется с началом первой линии.

Класс PathFigure имеет четыре ключевых свойства, описанные ниже:

StartPoint

Точка начала первой линии фигуры

Segments

Коллекция объектов PathSegment, используемых для рисования фигуры

IsClosed

Если равно true, то WPF добавляет отрезок прямой, соединяющий начальную и конечную точки (если они не совпадают)

IsFilled

Если равно true, то область внутри фигуры заполняется кистью Path.Fill

Пока все выглядит достаточно просто. PathFigure — это фигура, которая рисуется непрерывной линией, состоящая из ряда сегментов. Однако трюк заключается в том, что есть несколько типов сегментов, и все они наследуются от класса PathSegment.

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

Классы сегментов
LineSegment Создает отрезок прямой линии между двумя точками
ArcSegment Создает эллиптическую дугу между двумя точками
BezierSegment Создает кривую Безье между двумя точками
QuadraticBezierSegment Создает упрощенную форму кривой Безье, имеющую одну опорную точку вместо двух и вычисляемую быстрее
PolyLineSegment Создает серию прямых линий. Вы можете получить тот же эффект, используя множество объектов LineSegment, но единственный объект PolyLineSegment более лаконичен
PolyBezierSegment Создает серию кривых Безье
PolyQuadraticBezierSegment Создает серию упрощенных квадратичных кривых Безье

Дуги

Дуги немного интереснее, чем прямые линии. Конечная точка идентифицируется свойством ArcSegment.Point — так же, как в случае с LineSegment. Однако PathFigure рисует кривую линию из начальной точки (или конечной точки предыдущего сегмента) в конечную точку дуги. Эта соединительная кривая линия на самом деле является частью эллипса.

Очевидно, что координат конечной точки не достаточно, чтобы нарисовать дугу, поскольку существует множество кривых (некоторые более пологие, некоторые более крутые), соединяющих две точки. Понадобится также указать размер воображаемого эллипса, частью которого является данная дуга. Это делается через свойство ArcSegment.Size, которое принимает радиусы X и Y эллипса. Чем больше размер воображаемого эллипса, тем более пологой будет кривая.

Для любых двух точек существует максимальный и минимальный практический размер эллипса. Максимум достигается тогда, когда эллипс настолько велик, что его сегмент, проходящий через заданные две точки, выглядит прямым. Увеличение размера сверх этого не дает никакого эффекта. Минимум достигается тогда, когда эллипс настолько мал, что эти две точки соединяются полным полукругом. Дальнейшее уменьшение размера не дает эффекта.

Ниже представлен пример:

<Path Stroke="LightBlue" StrokeThickness="6" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
      <Path.Data>
           <PathGeometry>
                   <PathFigure StartPoint="200,150">
                         <ArcSegment Point="480,20" Size="200,300"></ArcSegment>
                   </PathFigure>
           </PathGeometry>
      </Path.Data>
</Path>
Простая дуга

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

Чтобы понять суть проблемы, необходимо рассмотреть другие способы соединения двух точек дугой. Отметив две точки на эллипсе, станет ясно, что соединить их можно двумя способами — проходя по эллипсу по короткой или по длинной стороне.

Установка направления осуществляется с помощью свойства ArcSegment.IsLargeArc, которое может принимать значение true или false. Значением по умолчанию является false, означающее выбор кратчайшей из двух дуг.

Даже установив направление, остается одна неопределенность — где именно располагается эллипс. Например, предположим, что рисуется дуга, соединяющая точку слева с точкой справа по кратчайшей дуге. Кривая, соединяющая эти две точки, может протянуться вниз, затем вверх или же наоборот — вверх и вниз. Полученная в результате дуга зависит от порядка определения двух точек дуги и свойства ArcSegment.SweepDirection, которое может принимать значение Counterclockwise (против часовой стрелки, что принято по умолчанию) или Clockwise (по часовой стрелке):

Изменение направления обхода дуги

Кривые Безье

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

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

Кривая Безье

Даже не понимая всей математической подоплеки, достаточно легко "прочувствовать", как работает кривая Безье. По сути, всю "магию" обеспечивают две опорные точки. Они влияют на кривую двумя способами:

  • В начальной точке кривая Безье идет параллельно линии, соединяющей ее с первой опорной точкой. В конечной точке кривая идет параллельно линии, соединяющей ее с конечной точкой (между ними она является кривой).

  • Степень кривизны определяется расстоянием до двух опорных точек. Если одна из них находится дальше, она создает большее "напряжение" притяжения.

Для определения кривой Безье в коде разметки задаются три точки. Первые две (BezierSegment.Point1 и BezierSegment.Point2) — это опорные точки. Третья точка (BezierSegment.Point3) — конечная точка кривой. Как всегда, начальной точкой является начальная точка пути или конец предыдущего сегмента.

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

<Canvas>
    <Path Stroke="Blue" StrokeThickness="5" Canvas.Top="20">
      <Path.Data>        
        <PathGeometry>
          <PathGeometry.Figures>            
              <PathFigure StartPoint="10,10">
                <BezierSegment Point1="130,30" Point2="40,140" Point3="150,150"></BezierSegment>
              </PathFigure>            
          </PathGeometry.Figures>
        </PathGeometry>                  
      </Path.Data>
    </Path>
    <Path Stroke="Green" StrokeThickness="2" StrokeDashArray="5 2" Canvas.Top="20">
      <Path.Data>
        <GeometryGroup>
          <LineGeometry StartPoint="10,10" EndPoint="130,30"></LineGeometry>          
          <LineGeometry StartPoint="40,140" EndPoint="150,150"></LineGeometry>         
        </GeometryGroup>
      </Path.Data>
    </Path>
    <Path Fill="Red" Stroke="Red" StrokeThickness="8"  Canvas.Top="20">
      <Path.Data>
        <GeometryGroup>
          <EllipseGeometry Center="130,30"></EllipseGeometry>
          <EllipseGeometry Center="40,140"></EllipseGeometry>
        </GeometryGroup>
      </Path.Data>
    </Path>
</Canvas>

Попытка закодировать кривую Безье — верный способ потратить множество безуспешных часов на кодирование путем проб и ошибок. Гораздо проще нарисовать кривые (как и многие другие графические элементы) в специальной программе для рисования, оснащенной средствами экспорта в XAML, или в Microsoft Expression Blend.

Пройди тесты