Instrukcje: sterowanie wypełnieniem kształtu złożonego
Właściwość FillRuleGeometryGroup lub PathGeometryokreśla "regułę", której kształt złożony używa do określenia, czy dany punkt jest częścią geometrii. Istnieją dwie możliwe wartości dla FillRule: EvenOdd i Nonzero. W poniższych sekcjach opisano sposób używania tych dwóch reguł.
EvenOdd: Ta reguła określa, czy punkt znajduje się w obszarze wypełnienia, rysując promień od tego punktu do nieskończoności w dowolnym kierunku i zliczając liczbę segmentów ścieżki w danym kształcie, które promień przecina. Jeśli ta liczba jest nieparzysta, punkt znajduje się wewnątrz; jeśli nawet, punkt znajduje się poza.
Na przykład poniższy kod XAML tworzy złożony kształt składający się z serii pierścieni koncentrycznych (docelowych) z zestawem FillRule ustawionym na EvenOdd.
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<GeometryGroup FillRule="EvenOdd">
<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>
Poniższa ilustracja przedstawia kształt utworzony w poprzednim przykładzie.
Na poprzedniej ilustracji zwróć uwagę, że środek i trzeci pierścień nie są wypełnione. Wynika to z faktu, że promienie pobrane z dowolnego punktu w obrębie jednego z tych dwóch pierścieni przechodzi przez parzystą liczbę segmentów. Zobacz następującą ilustrację:
NonZero: Ta reguła określa, czy punkt znajduje się w regionie wypełnienia ścieżki, rysując promienie od tego punktu do nieskończoności w dowolnym kierunku, a następnie sprawdzając miejsca, w których segment kształtu przecina promienie. Zaczynając od liczby zero, dodaj jeden za każdym razem, gdy segment przecina promień od lewej do prawej, i odejmij jeden za każdym razem, gdy segment ścieżki przecina promień od prawej do lewej. Po zliczaniu przepraw, jeśli wynik wynosi zero, punkt znajduje się poza ścieżką. W przeciwnym razie znajduje się wewnątrz.
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<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>
Korzystając z poprzedniego przykładu, wartość Nonzero dla FillRule daje następującą ilustrację w wyniku:
Jak widać, wszystkie pierścienie są wypełnione. Wynika to z faktu, że wszystkie segmenty biegną w tym samym kierunku, a więc promień wyciągnięty z jakiegoś punktu przetnie jeden lub więcej segmentów, a suma przecięć nie będzie równa zero. Na przykład na poniższej ilustracji czerwone strzałki reprezentują kierunek, w którym segmenty są rysowane, a biała strzałka reprezentuje dowolny promień uruchomiony od punktu w najbardziej wewnętrznym pierścieniu. Zaczynając od wartości zero, dla każdego segmentu, który promień przecina, dodawana jest wartość jeden, ponieważ segment ów przekracza promień z lewej na prawą.
Aby lepiej zademonstrować zachowanie reguły Nonzero, wymagany jest bardziej złożony kształt z segmentami działającymi w różnych kierunkach. Poniższy kod XAML tworzy podobny kształt, jak w poprzednim przykładzie, z tą różnicą, że jest tworzony przy użyciu PathGeometry a następnie EllipseGeometry, który tworzy cztery łuki koncentryczne, a nie w pełni zamknięte okręgi koncentryczne.
<Path Stroke="Black" StrokeThickness="1" Fill="#CCCCFF">
<Path.Data>
<GeometryGroup FillRule="NonZero">
<PathGeometry>
<PathGeometry.Figures>
<!-- Inner Ring -->
<PathFigure StartPoint="10,120">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment Size="50,50" IsLargeArc="True" SweepDirection="CounterClockwise" Point="25,120" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<!-- Second Ring -->
<PathFigure StartPoint="10,100">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment Size="70,70" IsLargeArc="True" SweepDirection="CounterClockwise" Point="25,100" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<!-- Third Ring (Not part of path) -->
<PathFigure StartPoint="10,70">
<PathFigure.Segments>
<PathSegmentCollection>
<ArcSegment Size="100,100" IsLargeArc="True" SweepDirection="CounterClockwise" Point="25,70" />
</PathSegmentCollection>
</PathFigure.Segments>
</PathFigure>
<!-- Outer Ring -->
<PathFigure StartPoint="10,300">
<PathFigure.Segments>
<ArcSegment Size="130,130" IsLargeArc="True" SweepDirection="Clockwise" Point="25,300" />
</PathFigure.Segments>
</PathFigure>
</PathGeometry.Figures>
</PathGeometry>
</GeometryGroup>
</Path.Data>
</Path>
Poniższa ilustracja przedstawia kształt utworzony w poprzednim przykładzie.
Zwróć uwagę, że trzeci łuk z środka nie jest wypełniony. Na poniższej ilustracji pokazano, dlaczego tak jest. Na ilustracji czerwone strzałki reprezentują kierunek rysowania segmentów. Dwie białe strzałki reprezentują dwa dowolne promienie, które wychodzą z punktu w obszarze bez wypełnienia. Jak widać na ilustracji, suma wartości z danego promienia przechodzącego przez segmenty w ścieżce wynosi zero. Jak zdefiniowano powyżej, suma zera oznacza, że punkt nie jest częścią geometrii (nie jest częścią wypełnienia), podczas gdy suma, która jest różna od zera, w tym wartość ujemna, jest częścią geometrii.
Notatka
Do celów FillRulewszystkie kształty są uznawane za zamknięte. Jeśli w segmencie występuje luka, narysuj wyimaginowaną linię, aby ją zamknąć. W powyższym przykładzie istnieją małe luki w pierścieniach. Biorąc to pod uwagę, można oczekiwać, że promień biegnący przez szczelinę da inny wynik niż promień biegnący w innym kierunku. Poniżej znajduje się powiększona ilustracja jednej z tych luk oraz segmentu hipotetycznego (segment, który jest rysowany do celów zastosowania FillRule), który ją zamyka.
Przykład
Zobacz też
.NET Desktop feedback