Polygon Füller [Erledigt, Code im Anhang]
Übersicht

![]() |
darthBetreff: Polygon Füller [Erledigt, Code im Anhang] |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo,
ich brauche gerade eine Methode um Polygone (konkave und konvexe) zu füllen. Ich dachte mir ich schreibe einen Scanline-Algorithmus, das Prinzip ist so: Code: [AUSKLAPPEN] für jede Bildzeile:
suche Schnittpunkte mit den Polygonkanten sortiere Schnittpunkte nach X Wert (aufsteigend, kleinster zuerst) füllen=false für jede Bildzeile: Schnittpunkt erreicht? füllen=!füllen (switch) füllen? zeichne Punkt Funktioniert soweit prächtig, gibt allerdings Probleme, wenn nicht das ganze Polygon im Bildschirm ist, aber da kann man das Polygon "clippen" (mir fällt kein schönes Wort auf deutsch dazu ein) - das ist ein anderes Thema. Mein Problem liegt hier (Erklärungsbild): Bei jedem Eckpunkt des Polygons habe ich immer zwei Schnittpunkte (einer von jeder Gerade). Das Problem hierbei ist, dass bei Punkt 0 und 1 brauche ich beide dieser Schnittpunkte (da das fill bei 0 von false zu false und bei 1 von true zu true wechseln muss, also einmal hin und einmal her). Bei 5 allerdings brauche ich nur einen, da dort das fill von false zu true wechseln muss. Die Punkte 2, 3, 4 sind trivial, da nachher nichtsmehr kommt und der Algorithmus sowieso mit füllen aufhört. Ich brauche jetzt eine Möglichkeit zu entscheiden, wann ich einen und wann ich zwei Schnittpunkte brauche. :/ Eine kleine Anmerkung: Die Durchgehensreihenfolge der Linien ist folgendermassen: Code: [AUSKLAPPEN] j=count
for i=0 to count line i,j j=i next Das bedeutet, der zweite Schnittpunkt für 1 wird bei i=2 (der erste bei i=1) gefunden und für 5 bei i=5 (der erste bei i=0). Es bringt also nichts, zu sehen ob der mittlere Punkt höhenmässig unter (bzw über) den beiden anderen liegt (weil der mittlere Punkt in beiden Fällen verschieden ist), das habe ich schon versucht. Was ebenfalls nichts bringt ist, bei jedem doppelten Punkt fill einfach auf true zu setzen, das funktioniert zwar für 1 und 5, schlägt aber bei 0 fehl. Was auch fehl schlägt ist, die Grenze der Linien für die Schnittpunkte zu "verkleinern", sprich, für: Code: [AUSKLAPPEN] Start + k * Vektor = Ziel
statt (k>=0 and k<=1) einfach (k>=0 and k<1) zu fordern funktioniert nicht. Viel mehr Ideen sind mir bisher nicht eingefallen, ich hoffe jemand anderes hat eine Idee und kann mir weiterhelfen. Ich freue mich auf überlegte Vorschläge (wildes Raten bringt nichts, das habe ich schon selber probiert ![]() MfG, Darth |
||
Diese Signatur ist leer. |
- Zuletzt bearbeitet von darth am Mo, Jan 04, 2010 15:07, insgesamt einmal bearbeitet
![]() |
HolzchopfMeisterpacker |
![]() Antworten mit Zitat ![]() |
---|---|---|
Zitat: Es bringt also nichts, zu sehen ob der mittlere Punkt höhenmässig unter (bzw über) den beiden anderen liegt (weil der mittlere Punkt in beiden Fällen verschieden ist), das habe ich schon versucht. Das verstehe ich jetzt nicht, zugegebenermassen ![]() Das sollte doch klappen? |
||
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BY ♫ BinaryBorn - Yogurt ♫ (31.10.2018) Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm |
![]() |
darth |
![]() Antworten mit Zitat ![]() |
---|---|---|
Scheint wohl missverständlich formuliert zu sein.
Das Problem ist zu eruieren, welcher der mittlere Punkt ist. Man betrachte das Bild im ersten Post, die Scanlinie sei auf der Höhe von Punkt 1. Es gibt folgende Schnittpunkt Resultate (nach Reihenfolge der Entdeckung): Code: [AUSKLAPPEN] 0-5
1-0 2-1 3-2 Die Punkte 1-0 und 2-1 sind die gleichen, man hat also einen Punkt in der Liste (1-0) und findet einen zweiten, der auf derselben Position ist (2-1), das geschieht also, bei i=2. Der mittlere Punkt ist hier also 1, links ist 0 und rechts ist 2. Das bedeutet: Mitte = i-1 Sei nun die Scalinie auf Höhe von Punkt 5. Dann gibt es folgende Schnittpunkte (nach Reihenfolge der Entdeckung): Code: [AUSKLAPPEN] 0-5
3-2 5-4 Hier sind die Punkte 0-5 und 5-4 die selben. Man hat den Punkt (0-5) in der Liste und findet nun (5-4) der an der selben Position ist, das ist bei i=5 der Fall. Der mittlere Punkt ist hier 5, links ist 4, rechts ist 0. Das bedeutet: Mitte = i Es zeigt sich also, dass der mittlere Punkt nicht immer nach dem selben Schema ermittelt werden kann, und das ist das Problem. Ich speichere in den Schnittpunkten nicht, woher sie kommen, also kann ich nicht ermitteln, welcher Punkt in der Mitte liegt, und kann von daher den Ansatz mit der Höhe nicht weiterverfolgen. Ich könnte natürlich dazu übergehen, die beiden Linienpunkte im Schnittpunkt zu speichern (und wenn alle Stricke reissen, werd ich das wohl tun müssen) - aber ich hoffe auf eine elegantere Lösung. MfG, Darth |
||
Diese Signatur ist leer. |
![]() |
hecticSieger des IS Talentwettbewerb 2006 |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ich hab überhaupt nicht ganz verstanden was du genau willst. Vielleicht würde ein Bild das zeigt wie es sein soll besser zur Verständlichkeit führen, als die ganzen Linien und Beschriftungen.
Aber eventuell ist eine Linienkollision das was du suchst. In so einem Fall nach Line Intersect suchen. |
||
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D |
Kruemelator |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Ich weis nich genau was du erreichen willst. Möchtest du aus den Punkten des konkaven Polygons einen konvexen Polygon erstellen welcher den konkaven umschließt?
Edit: Ich glaube ich habe es jetzt verstanden! ![]() Es geht um soetwas wie Rect oder Oval. Du könntest auch dein Polygon in mehrere Dreiecke unterteilen, das dürfte dann einfach gehen. |
||
![]() |
Midimaster |
![]() Antworten mit Zitat ![]() |
---|---|---|
ich hab das schon mal für ein ausmalspiel gebraucht. sieh mal unter floodfill in der blitzbasic.com nach.
Diese Routine läuft perfekt: 'Fill Routines ' Written By Paul Snart (Snarty) - Converted to BMax by klepto2 in Oct 2005 Link: http://www.blitzbasic.com/code...?code=1509 |
||
![]() |
Silver_Knee |
![]() Antworten mit Zitat ![]() |
---|---|---|
wenn beide Linien eines Eckpunktes über ihm liegen fällt ein Schnittpunktpaar weg, liegen beide unter ihm kommt eins hinzu und liegt eins darüber und eins darunter gibts nix neues.
Bei waagerechten Linien kommt auch keins dazu. |
||
![]() |
Eingeproggt |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hmm... Ich glaub ihr unterschätzt darth alle ein wenig - ist ja nicht so dass er es nicht hinkriegen würde Dreiecke zu zeichnen... Er hat da seine eigene Füllmethode wie im ersten Post beschrieben und dort steht er vor dem Problem was er machen soll wenn sein Füllalgo genau auf einen Eckpunkt trifft - wo ja 2 Linien aufeinander treffen.
Da würde seine Methode 2 mal "anschlagen" - den fillmode von False auf true und sofort wieder auf false ändern obwohl er im Falle des Punkt 5 in seiner Skizze ja dann innerhalb des polygons wäre und eigentlich füllen müsste. So hab ichs verstanden - ne Lösung hab ich dafür leider nicht, Sorry Darth ![]() |
||
Gewinner des BCC 18, 33 und 65 sowie MiniBCC 9 |
![]() |
Silver_Knee |
![]() Antworten mit Zitat ![]() |
---|---|---|
achso zeichne doch einfach durch wenn du genau auf nen punkt triffst... dh du gehst alle punkte durch und wenn du einen punkt in der aktuellen zeile erwischt musst du einfach alle lienien die von diesem unkt ausgehen ignorieren (die enden ja eh dort), dann passiert auch nix mit an aus usw | ||
![]() |
Goodjee |
![]() Antworten mit Zitat ![]() |
---|---|---|
könnte es helfen, die scanlines um 0.5 pixel nach oben/unten zu verschieben, wenn die punkte alle genau auf einem pixel liegen?
dann wird kein punkt mehr getroffen sondern nurnoch linien |
||
"Ideen sind keine Coladosen, man kann sie nicht recyclen"-Dr. House
http://deeebian.redio.de/ http://goodjee.redio.de/ |
![]() |
darth |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo,
danke für die vielen Vorschläge. Hier meine Antworten ![]() @Hectic: Siehst du die kleine schwarze Linie im weissen Bereich? Die müsste weg. Ich habe dort zwei Schnittpunkte, darum wird von nicht füllen zu nicht füllen gewechselt. Wäre da nur einer (und dazu bräuchte ich ein Auswahlkriterium, wann nehm ich einen, wann nehm ich zwei), würde es funktionieren. Den Lineintersect habe ich bereits implementiert, der ist nicht das Problem, das Problem ist eher: WELCHE Schnittpunkte akzeptiere ich für meine Liste? @Kruemelator: Ich habe eine Routine um das ganze in Dreiecke zu zerlegen. Ich habe sogar eine Routine, um das Ding in konvexe Polygone zu unterteilen, bei denen würde der Algorithmus übrigens wunderbar funktionieren. Das Problem ist, dass ich das nicht unbedingt möchte.. Ich suche einen Algorithmus, der für beliebige Polygone funktioniert, ohne irgendwelche Zerteilungen (Geschwindigkeitsfrage). @Midimaster: Danke für die Empfehlung. Einen Floodfill habe ich bereits ausprobiert. Das Problem dabei ist die Geschwindigkeit. Floodfill ist enorm aufwändig und eigentlich ein ziemlich schlechter Algorithmus. Der Linesearch Ansatz ist ziemlich viel schneller, deshalb möchte ich diesen verwenden. @Silver_Knee: Ich verstehe nicht ganz was du meinst, tut mir leid. Wie können Linien über einem Punkt sein? Meinst du, dass die Endpunkte der Linien die in diesem Schnittpunkt münden über dem Punkt sein müssten (oder untendran?) Falls ja, dann muss ich leider sagen, dass das so nicht funktioniert (jedenfalls nicht in der jetzigen Implementation), Grund dazu ist die fehlende Speicherung der Linienkomponenten im Schnittpunkt, siehe meinen 2. Post als Antwort auf Holzchopf. @Eingeproggt: Ja, du hast das Prinzip verstanden ![]() @Silver_Knee: Wenn ich bei Eckpunkten einfach weiterzeichne, dann zeichne ich auch bei der Ecke 0 weiter, und ich habe eine Linie die durch die Leere führt, das funktioniert leider auch nicht. @Goodjee: Ich rechne wenn ich mit Pixeln arbeite eigentlich generell mit Integern, da hat es keine Auswirkung (ausser einem ++) den Punkt um 0.5 zu verschieben. Selbst wenn es funktionieren würde, wüsste ich nicht, wo ich jetzt zeichnen soll.. zwischen Pixeln kann man keine Pixel setzen. Wie die Dinge stehen habe ich immernoch keine Ahnung wie ich meine Füllroutine korrigieren soll ![]() Ich hoffe immernoch auf eine Lösung, MfG, Darth |
||
Diese Signatur ist leer. |
![]() |
Midimaster |
![]() Antworten mit Zitat ![]() |
---|---|---|
du schreibst "einen floodfill..." Diesen? Wir verwenden ihn in unseren kommerziellen Produkten, er hatte uns echt überzeugt.
Ich kann dir jetzt aber nicht mehr über die Performance sagen, is schon zu lang her. Hier kannst du ihn beim Arbeiten zuschauen: http://www.midimaster.de/downl...smalen.exe |
||
![]() |
hecticSieger des IS Talentwettbewerb 2006 |
![]() Antworten mit Zitat ![]() |
---|---|---|
Nur eine Idee.
Eventuell könnte man eine jede Polygonposition mit ~+0.1 berechnen. Wenn die Eckpunkte dann mit der Füllinie schneiden, käme es zu solchen ''Fehlberechnungen'' nicht mehr. Hängt aber auch davon ab, wie das ganze berechnet wird. Edit1: Ok, Goodjee hat das gleiche Beispiel gebracht. Aber trotz Integer kann man Floatwerte zur Berechnung einbeziehen. Und soweit mir bekannt ist, kommen auch Divisionen in einer LinesIntersecs-Funktion vor, von daher hast su schon zwagsweise eine Float-Berechnung. |
||
Download der Draw3D2 V.1.1 für schnelle Echtzeiteffekte über Blitz3D |
- Zuletzt bearbeitet von hectic am Mo, Jan 04, 2010 0:22, insgesamt einmal bearbeitet
![]() |
darth |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo Midimaster,
ich habe einen Floodfill programmiert. Wie ich sehe ist die von dir gepostete Methode nicht rekursiv wie meine, das macht sie schon einmal schneller (und besser) als meine Version. Das Problem ist, dass Floodfill generell den Befehl Readpixel benötigt, der nicht der schnellste ist. Zum Füllen muss ich schon Writepixel verwenden (bzw WPFast), was mir auch schon nicht gefällt - aber unumgänglich ist (weil es keine andere Alternative gibt Pixel zu setzen :> ), aber zusätzlich zu dem noch überall Readpixel (oder RPFast) zu benutzen macht das ganze System nicht schneller. Zusätzlich kann ich bei meiner Routine leere Stücke überspringen. Floodfill hat das Problem nicht, da fängt man irgendwo in der Mitte an, aber man muss trotzdem sukzessiv durchsuchen, wo man setzen soll. Mit meinem Scanline Ansatz kann ich BERECHNEN wo ich setzen muss und dann muss ich die nur noch durchgehen. Floodfill kann zwar gut genug für die Benutzung implementiert werden, es bleibt aber ein eher langsamer, schlechter Ansatz den man nicht unbedingt verwenden sollte, wenn man die Geschwindigkeit optimieren möchte. MfG, Darth [EDIT:] Hallo nochmal, ich schulde dem lieben Goodjee eine Entschuldigung. Entschuldigung! Wenn ich den Y-Wert für meine Schnittberechnung nicht direkt aus dem Y-Wert des Punktes wähle, sondern PY=Polygon\Punkt[i]\Y-0.1 dann tritt das Problem nicht auf. Danke auch an Noobody der mich darauf aufmerksam gemacht hat dass ich doch nicht durchgehend mit Integern arbeite und es so funktioniert. Somit wäre das Problem gelöst, Thema beendet, Darth glücklich. MfG, Darth |
||
Diese Signatur ist leer. |
![]() |
Silver_Knee |
![]() Antworten mit Zitat ![]() |
---|---|---|
also zumindest writepiel kannste umgehen
du zeichnest ja nur lienien. Also kannst du Rect x,y,xend-x,1 nutzen, das dürfte schneller sein... Ich glaub wenn das unausgefüllt (bei einem Pixel eh egal) isses glaub noch schneller.. Vor allem bei langen Linien. |
||
![]() |
darth |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo Silver_Knee,
im Lockbuffer Modus ist Line wesentlich schneller als Rect soweit ich weiss. Aber die Pixel durch Linien zu ersetzen wäre eine gute Idee, mal sehn ob das schneller kommt als die einzelnen Punkte. MfG, Darth [Edit:] Begründet darauf: BlitzBasic: [AUSKLAPPEN] Graphics 800,600,0,2 Habe ich das Ding auf Line umgestellt, läuft jetzt nochmal schneller \o/ |
||
- Zuletzt bearbeitet von darth am Mo, Jan 04, 2010 15:00, insgesamt einmal bearbeitet
Kruemelator |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
Wenn der vorherige und der folgende Punkt jeweils beide über oder unter dem zu prüfenden Punkt liegen, dann dann bleibt es so wie es ist.
Gruß Kruemelator |
||
![]() |
darth |
![]() Antworten mit Zitat ![]() |
---|---|---|
Hallo Kruemelator,
Deine Antwort funktioniert in der Theorie, ist aber praktisch nicht umsetzbar, weil ich in den Punkten nicht speicher woher sie kommen. Das Problem lässt sich aber lösen, wenn ich die Punkte um 0.1 verschiebe, dann liegen sie nicht direkt auf der Scanlinie und ich hab das Problem mit dem doppelten Schnittpunkt gar nicht. --- Um weitere Unklarheiten zu vermeiden, stelle ich mal kurzerhand den fertigen Code hier rein (und werde wahrscheinlich den Threadtitel editieren): BlitzBasic: [AUSKLAPPEN] Type Vector Der Code ist zur freien Verwendung freigegeben. Sollte euer Computer im Laufe der Benutzung explodieren weise ich jede Schuld von mir. Gebrauch auf eigene Gefahr! MfG, Darth |
||
Diese Signatur ist leer. |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group