2011-12-13 10 views
9

Próbuję dowiedzieć się, jak całkowicie wypełnić niestandardową geometrię. Wygląda na to, że powinno to być powszechne pytanie, ale tak naprawdę nie byłem w stanie znaleźć żadnych rozwiązań.Napełnianie niestandardowych geometrii

Mam następujący przykład geometria:

<Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2"> 
     <Path.Data> 
      <PathGeometry 
       Figures="M112,296C112,296 136,296 136,320 M112,344C112,344 136,344 136,320 M112,296L112,296 96,296 96,344 112,344"/> 
     </Path.Data> 
    </Path> 

która produkuje następujący wynik:

Undesired Fill Result

Jest to wynik chciałbym zobaczyć:

Desired Fill Result

Dowolny Pomysły? Wiem, że mógłbym stworzyć pojedynczy łuk, który rozwiązałby ten konkretny przypadek, ale w mojej aplikacji użytkownik może narysować dowolny rodzaj geometrii, aby wynik mógł składać się z dowolnej liczby "prymitywów" (PolyLineSegments, EllipseGeometries, ArcSegments itd.) aw przypadku, gdy wynikowa geometria zawiera pewien rodzaj zamkniętego obszaru, chciałbym dokładnie wypełnić ten obszar.

EDIT:

Oto przykład tego, co CombinedGeometry wygląda jakbym zapewnić wszystkie trzy sąsiednie geometrie pokrywają się i stworzyć unioned CombinedGeometry z następującego kodu:

 <Path Grid.Row="2" Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2"> 
     <Path.Data> 
      <CombinedGeometry GeometryCombineMode="Union"> 
       <CombinedGeometry.Geometry1> 
        <CombinedGeometry GeometryCombineMode="Union"> 
         <CombinedGeometry.Geometry1> 
          <PathGeometry 
           Figures="M111,293C111,296 136,293 136,325"/> 
         </CombinedGeometry.Geometry1> 
         <CombinedGeometry.Geometry2> 
          <PathGeometry 
           Figures="M111,346C111,344 136,344 136,320"/> 
         </CombinedGeometry.Geometry2> 
        </CombinedGeometry> 
       </CombinedGeometry.Geometry1> 
       <CombinedGeometry.Geometry2> 
        <PathGeometry 
         Figures="M125,296L115,296 96,296 96,344 120,344"/> 
       </CombinedGeometry.Geometry2> 
      </CombinedGeometry> 
     </Path.Data> 
    </Path> 

I tu jest rezultat:

Combined Geometry

byłem Hopi ng to połączenie tylko pociągnięć i automagicznie znaleźć prawidłowe wypełnienie nowego, ciągłego wielokąta ... bummer.

EDIT 2:

Hmm więc myślę, że mam wymyślić kilka możliwych rozwiązań, z których żaden nie jest tak proste, jak ja ufałem byliby. Pierwszą opcją byłoby połączenie wszystkich geometrii jak powyżej za pomocą struktury CombineGeometry, a następnie nazwałem "GetFlattenedPathGeometry" na wynikowej "CombineGeometry" w celu uzyskania PathGeometry. Następnie powtarzam każdy rysunek w PathGeometry i po prostu usuwam te, które są dziurami (które, jak sądzę, powinieneś być w stanie zrobić, pozbywając się wszystkich figur, które są całkowicie zawarte przez inne, lub dziury mogą być zgodne z konwencją posiadania albo w prawo lub współrzędne przeciwne do ruchu wskazówek zegara, nie wiem ..), jeśli wszystko pójdzie dobrze, powinieneś pozostawić pojedynczą, całkowicie wypełnioną geometrię.

Drugą opcją byłoby ponowne wywołanie "GetFlattenedPathGeometry" na dowolnej ścieżce wypadkowej, aby uzyskać wielokątne przybliżenie ścieżki (bez krzywej, łuku, elipsy, itp.), Aby uzyskać ścieżka zawierająca tylko punkty i linie). Następnie wystarczy połączyć wszystkie wypadkowe liczby/segmenty w jedną figurę, której segmenty są uporządkowane zgodnie z ruchem wskazówek zegara lub przeciwnie do ruchu wskazówek zegara.

Testowałem oba podejścia i wydaje się, że działają one z co najmniej prostym przykładem testowym opisanym powyżej, ale nie będą działać z bardziej złożonymi kształtami (samoprzecinającymi się, wklęsłymi itp.) .. wsparcie, którego wymagam. więc pozostaje pytanie, jak to zrobić?

EDIT 3:

Tutaj jest bardziej skomplikowana geometria, w których kolejkowanie/łączenie staje się coraz trudniejsze:

 <Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2"> 
     <Path.Data> 
      <PathGeometry 
      Figures="M104,160C104,160 72,160 72,136 
       M104,128C104,128 72,128 72,152 
       M152,232L152,232 152,216 120,216 120,160 128,160 
       M152,232L152,232 72,232 104,216 104,160 96,160 
       M104,128L104,128 168,128 
       M128,160L128,160 168,160 
       M165,160L168,160 200,128 
       M200,160L200,160 200,128 
       M200,160L200,160 168,128 152,128"/> 
     </Path.Data> 
    </Path> 

która produkuje:

enter image description here

Odpowiedz

5

Twój przykład geometrii jest kombinacją trzech sąsiednich kształtów, które się nie nakładają. Obrys jest rysowany na zewnętrznych krawędziach, ponieważ kształty nie są zamknięte, a wewnętrzne linie obrysu nie istnieją. Chociaż może się wydawać, że kształty są łączone, a obrys jest stosowany do geometrii jako całości, to nie jest to, co się dzieje.

Zamknięcie otworu staje się bardziej złożonym problemem programowego wykrywania otworu i zamykania go odpowiednim kształtem lub tworzenia nowego połączonego kształtu, który nie ma otworu (prawdopodobnie przez wykrywanie i śledzenie zewnętrznych punktów). Nie jestem świadomy żadnej funkcjonalności w WPF, która może ci pomóc w tym zadaniu. Istnieje klasa CombinedGeometry, która może wytworzyć połączenie dwóch zachodzących na siebie kształtów. Kształty w tym przykładzie nie pokrywają się.

Bez kontekstu trudno jest zalecić rozwiązanie. Jeśli jest to program do rysowania swobodnego, być może użytkownik musi po prostu narysować inny kształt w środku, aby zamknąć geometrię.

+0

Dziękuję za odpowiedź. Przez "zamknięcie otworu" masz na myśli otwór w wypełnieniu lub niewielki odstęp między sąsiadującymi geometriami? Jeśli masz na myśli lukę między geometriami, niedługo opublikuję edycję za pomocą prostego przykładu CombinedGeometry, który wydaje się mieć ten sam problem, gdy pociągnięcia sąsiednich geometrii nakładają się na siebie i są połączone z połączeniem. Dzięki jeszcze raz! – Craig

+0

Chętnie pomogę. Chodziło mi o duży obszar, który próbujesz wypełnić, a nie małą szczelinę między sąsiednimi geometriami. Jak pokazuje Twój edytowany eksperyment, połączenie wielu kształtów nie eliminuje dziury. Nie mogłem znaleźć żadnej funkcjonalności w ramach WPF, która identyfikowałaby i usuwała otwory zamknięte w styku lub zachodzące na siebie geometrie. Twoje podejście polegające na łączeniu geometrii i usuwaniu postaci, które są całkowicie zamknięte, brzmi jak świetny początek. – Scott

2

traktować go jako "Połącz punkty" problemu :)

Masz 5 punktów:

  • 96.296 - górny lewy punkt (róg)
  • 112296 - top - początek krzywej Beziera
  • 136.320 - prawej - koniec pierwszej krzywej Beziera, początek drugiego jednej
  • 112,344 - dolnej - koniec drugiego Beziera
  • 96,344 - dolny lewy punkt (róg)

A teraz połączymy ich.

<Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2"> 
    <Path.Data> 
     <PathGeometry Figures="M112,296 C112,296 136,296 136,320 C136,320 136,344 112,344 M112,344 96,344 96,296 112,296"/> 
    </Path.Data> 
</Path> 

Można również użyć < GeometryGroup FillRule = "niezerowe" ... > wypełnić swoją niestandardową ścieżkę od 1 poście. Domyślna wartość to FillRule = "EvenOdd", która produkuje wypełnienie takie jak twoje. *

Zobacz składnię znaczników ścieżki (http://msdn.microsoft.com/en-us/library/ms752293.aspx), aby uzyskać więcej informacji o ścieżce mini-języku.

  • Zmieniono < Ścieżka > do <GeometryGroup>

EDIT 1:

I kolejność ścieżka trochę:

<Path Fill="White" Stretch="Fill" Stroke="Black" StrokeThickness="2"> 
    <Path.Data> 
     <PathGeometry Figures="M72,152 C72,152 72,128 104,128 L168,128 200,160 200,128 168,160 120,160 120,216 152,216 152,232 72,232 104,216 104,160 C104,160 72,160 72,136"/> 
    </Path.Data> 
</Path> 

co daje nam:

New shape

Rysunek ścieżka jest jak przy użyciu pewnego rodzaju „narysować kształt” narzędzie w oprogramowaniu do edycji wektorów, gdzie masz do wyboru następujące punkty, a gdy nie masz następny - kształt jest automatycznie zamykany (ostatnia Punkt jest połączony z pierwszym, ale tylko w celu wypełnienia kształtu - widzimy, jak to się robi, kiedy patrzymy na "nos" nowego kształtu). W twoim przykładzie Masz 9 oddzielnych kształtów (każdy w osobnej linii, gdzie M określa początek nowej figury) i wszystkie są wypełnione w powyższy sposób.

Oczywiście można użyć GeometryGroup (z FillRule) lub CombinedGeometry (z CombinedGeometryMode) do łączenia kształtów.

+0

Dzięki za odpowiedź. Zamawianie figur w kolejności zgodnej z ruchem wskazówek zegara jest czymś, co starałem się znaleźć w prostych kształtach, ale to samo podejście nie zadziała w przypadku bardziej złożonych kształtów (przecinających się, wklęsłych itp.). Ponadto ścieżka nie ma właściwości "FillRule" (przynajmniej nie w .NET 3.5), ale próbowałem umieścić geometrię w GeometryGroup, której FillRule było niezerowe, ale otrzymałem te same wyniki. Wkrótce opublikuję bardziej złożoną geometrię i mam nadzieję, że możesz mi udowodnić, że się mylę :). – Craig

+0

Nice. W jaki więc sposób zaproponowałbym programową geometrię? Moje narzędzie pozwala użytkownikowi konstruować te kształty z dowolnej kombinacji geometrii, więc kończę z czymś, co napisałem powyżej, gdzie geometrie są uporządkowane w dowolny sposób, w jaki użytkownik dodał je do płótna. Będę musiał programowo zmienić kolejność tych geometrii, aby były poprawnie wypełnione. Próbowałem używać CombinedGeometry, ale te związki nie tylko udaru, ale również wypełnienia, więc kończysz z czymś podobnym do tego, z czym zaczynałeś. – Craig

+0

Podczas tworzenia geometrii można spróbować dodać kolejny kształt ("pierwotny") bez uruchamiania nowej figury (Mxxx, xxx) - w przypadku np. Krzywe Beziera pierwszy punkt kontrolny powinien być ustawiony automatycznie (współrzędne takie same jak ostatni punkt). Możesz spróbować czegoś takiego (x, y to niestandardowe współrzędne): PathGeometry geom = new PathGeometry(); PathFigure path = new PathFigure(); path.StartPoint = new Point (x, y); geom.Figures.Add (ścieżka); LineSegment line = new LineSegment(); line.Point = new Point (x, y); path.Segments.Add (linia); i tak dalej .... Powinieneś także przypisać geom do _xamlPathObject_.Data –

1

Znalazłem an interesting article o tworzeniu kształtów za pomocą wpf przy użyciu pliku svg utworzonego za pomocą narzędzia graficznego, takiego jak inkscape. To może dać ci pewien wgląd.

Powiązane problemy