Gdiplus: Überschneidung transparenter Elemente
-
Ich verwende die GDI+, um transparente Linien und Flächen auszugeben. Dabei ergibt sich folgendes Problem:
Eine Pfeilspitze soll mit einer bestimmten Farbe und Deckkraft gezeichnet werden. Sie besteht aus einem umgebenden Polygon (Dreieck) mit bestimmter Linienbreite und der darin ausgefüllten Fläche. Diese Kombination ist notwendig, damit die Ecken mit der Linienbreite abgerundet sind (LineCapRound und LineJoinRound sind gesetzt). Beides kann z.B. mit DrawPolygon() und FillPolygon() realisiert werden. Leider entsteht dabei eine Überschneidung zwischen den inneren Linienhälften mit der scharfkantigen Dreiecksfläche. Durch die Transparenz erscheint dieser Überlappungsbereich dann auf weißem Hintergrund mit dunklerer Farbe. GDI+ sieht hier halt 2 verschiedene Elemente.
Wie kann ich es erreichen, dass diese zwei Grafikelemente (Linie und Fläche) als vereinigt angesehen werden, so dass sie im Überlappungbereich ihre gemeinsame Transparenz beibehalten.
Mit allen möglichen Liniengebilden kann man dies z.B. mithilfe des GraphicsPath-Objektes erreichen. Leider können hier nur strichartige Gebilde wie Linien, Polygone, Rechtecke, Pies, Ellipsen usw. zusammengefasst werden, aber keine flächenhaften Gebilde.Führt man allein für die dreieckige Umrandungslinie DrawPath() und FillPath() hintereinander aus, um auch ohne ein Flächenelement eine Füllung zu erhalten, entstehen wieder die dunkleren Überschneidungsbereiche.
Ich glaube, da hat die GDI+ ihre Grenzen. Oder hat jemand eine Idee?
-
Naja du kannst ne Region verwenden um beliebige Formen mit And/Or/Xor zu verknüpfen.
Dummerweise funktioniert dann Antialiasing nicht mehr, da Regions keine Sub-Pixel Genauigkeit haben.Die einfachste Variante wird wohl sein eine temporäre Bitmap zu verwenden um die beiden Formen zu kombinieren. In die Bitmap kannst du dann mit 100% Deckkraft zeichnen, und danach zeichnest du die Bitmap auf's Fenster (bzw. wo auch immer du hin zeichnen willst) mit der Deckkraft die du brauchst.
Sonst würde mir nur einfallen einen passenden GraphicsPath selbst "zu Fuss" zusammenzubauen. Also direkt die Outline inklusive abgerundeten Ecken aus Linien und Arcs zusammenzubauen.
Stelle ich mir aber halbwegs lästig vor - auch wenn es keine Rocket-Science ist sitzt man da sicher ne Zeit lang dran, und es ist ne halbwegs öde Arbeit.
-
Hallo hustbaer,
es handelt sich um Darstellungen in einem CAD-System. Diese sind bereits in einem sehr komplexen Regions-Management eingeschachtelt, um effizientes Scrolling und Updating mit Multithreading zu erhalten. Das ist aber kein Problem.
Die temporäre Bitmap wäre eine sehr aufwändige aber theoretische Möglichkeit. Allerdings lässt die Effizienz bei tausenden von Pfeilen nach. Das gilt auch für das Zusammenbasteln der gewünschten Endform. Hinzu kommt, dass eine Pfeilspitze durchs Zoomen gigantisch groß werden kann, sodass nur ein kleiner Teil sichtbar bleibt. Das temporäre Bitmap-Management müsste dann noch mit dem Clipping des Zeichnungs- bzw. Update-Ausschnitts abgestimmt werden.
Ich dachte, dass ich vielleicht noch Möglichkeiten in der GDI+ übersehe, weil ich mit ihr noch nicht viel gemacht habe.
Danke!
-
Ich habe jetzt doch noch folgende Lösung gefunden:
Gdiplus::SolidBrush *brush; Gdiplus::Pen *pen; Gdiplus::Point *pointlist; Gdiplus::GraphicsPath *path; Gdiplus::Region *region; pointlist=new Gdiplus::Point[3]; //Initialisierung der 3 Punkte pen=new Gdiplus::Pen(color, width); brush=new Gdiplus::SolidBrush(color); path=new Gdiplus::GraphicsPath(Gdiplus::FillModeAlternate); path->AddPolygon(pointlist, 3); region=new Gdiplus::Region(path); path->Widen(pen); region->Union(path); Gdiplus::Graphics->FillRegion(brush, region); delete path; delete region; delete pen; delete brush; delete[] pointlist;
1. Aus dem Pfad der dreieckigen Pfeilspitze wird eine Region erstellt.
2. Der Pfad kann mit Widen() auf die äußere Kontur gebracht werden, die er durch das Zeichnen mit einem Stift bekommen würde.
3. Diese wird dann mit der ersten Region vereinigt.So entsteht eine Region, die sowohl die Fläche der dicken Pfeilspitzenumrandung als auch die innere Fläche enthält. Die transparente Pfeilspitze kann dann mit FillRegion() als Ganzes ausgegeben werden (ohne innere Überlappungsbereiche).
-
Ja, das ist das was ich mit meinem ersten Satz gemeint hatte.
-
Ah ja, habe ich mir jetzt schon gedacht. Bei Region denke ich erst immer noch ans Clipping in Gerätekontexten. Dass die als Objekt in der GDI+ jetzt vielfältigere Verwendungsmöglichkeiten bietet, daran muss ich mich noch gewöhnen. Das Widen() ist hier ja auch interessant.
Also nochmals vielen Dank!
-
Och die konnte man eigentlich immer schon recht flexibel einsetzen...
http://msdn.microsoft.com/en-us/library/077zk1zy.aspx
GDI+ sowie die MFC machen was Regions angeht nicht mehr, als die Funktionalität der GDI in einer C++ Wrapperklasse einzuwickeln.