Поделиться через


Xamarin.Forms Фигуры: правила заливки

Несколько Xamarin.Forms классов фигур имеют FillRule свойства типа FillRule. Это операторы Polygon, Polyline, а также GeometryGroup.

Перечисление FillRule определяет EvenOdd и Nonzero элементы. Каждый элемент представляет собой другое правило для определения того, находится ли точка в области заливки фигуры.

Внимание

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

EvenOdd

EvenOdd Правило заливки рисует луч от точки до бесконечности в любом направлении и подсчитывает количество сегментов в фигуре, которую луч пересекает. Если это число нечетно, точка находится внутри. Если это число даже, точка находится вне.

В следующем примере XAML создается составная фигура FillRule и отрисовывается EvenOddпо умолчанию:

<Path Stroke="Black"
      Fill="#CCCCFF"
      Aspect="Uniform"
      HorizontalOptions="Start">
    <Path.Data>
        <!-- FillRule doesn't need to be set, because EvenOdd is the default. -->
        <GeometryGroup>
            <EllipseGeometry RadiusX="50"
                             RadiusY="50"
                             Center="75,75" />
            <EllipseGeometry RadiusX="70"
                             RadiusY="70"
                             Center="75,75" />
            <EllipseGeometry RadiusX="100"
                             RadiusY="100"
                             Center="75,75" />
            <EllipseGeometry RadiusX="120"
                             RadiusY="120"
                             Center="75,75" />
        </GeometryGroup>
    </Path.Data>
</Path>

В этом примере отображается составная фигура, состоящей из ряда концентрических кругов:

Составная фигура с правилом заливки EvenOdd

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

Аннотированная составная фигура с правилом заливки EvenOdd

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

Ненулевой

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

Следующий пример XAML создает и отрисовывает составную фигуру с заданным значением FillRule Nonzero:

<Path Stroke="Black"
      Fill="#CCCCFF"
      Aspect="Uniform"
      HorizontalOptions="Start">
    <Path.Data>
        <GeometryGroup FillRule="Nonzero">
            <EllipseGeometry RadiusX="50"
                             RadiusY="50"
                             Center="75,75" />
            <EllipseGeometry RadiusX="70"
                             RadiusY="70"
                             Center="75,75" />
            <EllipseGeometry RadiusX="100"
                             RadiusY="100"
                             Center="75,75" />
            <EllipseGeometry RadiusX="120"
                             RadiusY="120"
                             Center="75,75" />
        </GeometryGroup>
    </Path.Data>
</Path>

В этом примере отображается составная фигура, состоящей из ряда концентрических кругов:

На схеме показаны четыре концентрических круга, все заполнены.

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

На схеме показаны круги из предыдущей диаграммы с стрелками направления и лучом с аннотированной + 1 для каждого круга, пересекаемого.

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

Более сложная фигура с сегментами, работающими в разных направлениях, необходима, чтобы лучше продемонстрировать поведение Nonzero правила заливки. В следующем примере XAML создается аналогичная фигура предыдущего примера, за исключением того, что она создана с PathGeometry помощью EllipseGeometry:

<Path Stroke="Black"
      Fill="#CCCCFF">
     <Path.Data>
         <GeometryGroup FillRule="Nonzero">
             <PathGeometry>
                 <PathGeometry.Figures>
                     <!-- Inner ring -->
                     <PathFigure StartPoint="120,120">
                         <PathFigure.Segments>
                             <PathSegmentCollection>
                                 <ArcSegment Size="50,50"
                                             IsLargeArc="True"
                                             SweepDirection="CounterClockwise"
                                             Point="140,120" />
                             </PathSegmentCollection>
                         </PathFigure.Segments>
                     </PathFigure>

                     <!-- Second ring -->
                     <PathFigure StartPoint="120,100">
                         <PathFigure.Segments>
                             <PathSegmentCollection>
                                 <ArcSegment Size="70,70"
                                             IsLargeArc="True"
                                             SweepDirection="CounterClockwise"
                                             Point="140,100" />
                             </PathSegmentCollection>
                         </PathFigure.Segments>
                     </PathFigure>

                     <!-- Third ring  -->
                         <PathFigure StartPoint="120,70">
                         <PathFigure.Segments>
                             <PathSegmentCollection>
                                 <ArcSegment Size="100,100"
                                             IsLargeArc="True"
                                             SweepDirection="CounterClockwise"
                                             Point="140,70" />
                             </PathSegmentCollection>
                         </PathFigure.Segments>
                     </PathFigure>

                     <!-- Outer ring -->
                     <PathFigure StartPoint="120,300">
                         <PathFigure.Segments>
                             <ArcSegment Size="130,130"
                                         IsLargeArc="True"
                                         SweepDirection="Clockwise"
                                         Point="140,300" />
                         </PathFigure.Segments>
                     </PathFigure>
                 </PathGeometry.Figures>
             </PathGeometry>
         </GeometryGroup>
     </Path.Data>
 </Path>

В этом примере нарисуется ряд сегментов дуги, которые не закрываются:

На схеме показаны четыре концентрических круга с самыми исходящими и третьими из самых внешних заполнений.

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

На схеме показаны круги из предыдущей диаграммы с стрелками направления и двумя лучами, помеченными + 1 или – 1 для каждого круга, пересекающегося.

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

  • Произвольный луч, который перемещается по диагонали вправо, пересекает два сегмента, которые выполняются в разных направлениях. Таким образом, сегменты отменяют друг друга, давая значение нуля.
  • Произвольный луч, который перемещается по диагонали слева пересекает в общей сложности шесть сегментов. Однако пересечения отменяют друг друга, чтобы ноль является окончательной суммой.

Сумма нулевых результатов в кольце не заполняется.