Jak kontrolować wypełnienie kształtu złożonego
Właściwość FillRule obiektu GeometryGroup lub PathGeometry, okreś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 FillRuleelementu : 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 regionie wypełnienia, rysując promienie od tego punktu do nieskończoności w dowolnym kierunku i zliczając liczbę segmentów ścieżek w danym kształcie, że przekreślić promienie. 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 na EvenOddwartość .
<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. Począwszy od liczby zera, dodaj jeden raz segment przecina promienie od lewej do prawej i odejmuje jeden za każdym razem segment ścieżki przecina promienie 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 Nonzero , wartość dla FillRule elementu daje następującą ilustrację w wyniku:
Jak widać, wszystkie pierścienie są wypełnione. Wynika to z faktu, że wszystkie segmenty działają w tym samym kierunku, a więc promienie pobrane z dowolnego punktu przekroczeń przekroczy jeden lub więcej segmentów, a suma przepraw 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. Począwszy od wartości zero, dla każdego segmentu, który przekreśli, wartość jednego jest dodawana, ponieważ segment przecina promienie od lewej do prawej.
Aby lepiej zademonstrować zachowanie Nonzero reguły, 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 za pomocą PathGeometry elementu , który tworzy cztery łuki koncentryczne, a następnie EllipseGeometry 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 wyjdą z punktu w regionie "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 części wypełnienia), podczas gdy suma, która nie jest równa zero, w tym wartość ujemna, jest częścią geometrii.
Uwaga
Dla celów FillRuleprogramu wszystkie 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 pod uwagę to, można oczekiwać promienia, który biegnie przez szczelinę, aby dać inny wynik, a następnie promieni działa w innym kierunku. Poniżej znajduje się powiększona ilustracja jednej z tych luk i "wyimaginowany segment" (segment, który jest rysowany do celów zastosowania FillRule) zamykający go.
Przykład
Zobacz też
.NET Desktop feedback