Diskussion zum Artikel "MQL5-Handelswerkzeuge (Teil 17): Vektorbasierte abgerundete Rechtecke und Dreiecke"

 

Neuer Artikel MQL5-Handelswerkzeuge (Teil 17): Vektorbasierte abgerundete Rechtecke und Dreiecke :

In diesem Artikel befassen wir uns mit vektorbasierten Methoden zum Zeichnen abgerundeter Rechtecke und Dreiecke in MQL5 mithilfe von Canvas, wobei Supersampling für eine kantenglättete Darstellung zum Einsatz kommt. Wir setzen Scanline-Füllung, geometrische Vorberechnungen für Bögen und Tangenten sowie Rahmen ein, um glatte, anpassbare Formen zu erstellen. Dieser Ansatz schafft die Grundlage für moderne UI-Elemente in zukünftigen Trading-Tools und unterstützt die Eingabe von Größen, Radien, Rahmen und Deckkraftwerten.

Der vektorbasierte Ansatz zur Darstellung abgerundeter Rechtecke und Dreiecke nutzt mathematische Beschreibungen von Formen – Punkte, Linien und Kurven – anstelle von Pixelrastern und ermöglicht so skalierbare, auflösungsunabhängige Grafiken, die bei jeder Größe scharf bleiben. Im Gegensatz zu Raster-Methoden, die bei der Skalierung gezackte Kanten (Aliasing) erzeugen können, berechnen Vektortechniken präzise Begrenzungen und Füllungen mithilfe von Gleichungen für Bögen und Tangenten. Dadurch eignen sie sich ideal für UI-Elemente in MQL5, wo eine glatte Darstellung die Benutzerfreundlichkeit verbessert, ohne die Leistung zu beeinträchtigen. Abgerundete Ecken werden erzielt, indem scharfe Ecken durch Kreisbögen ersetzt werden, deren Radien die Krümmung bestimmen. Rahmen lassen sich über versetzte Pfade oder verbreiterte Kanten realisieren, und ein Supersampling verfeinert das Ergebnis zusätzlich, indem es zunächst mit höheren Auflösungen gerendert und anschließend heruntergerechnet wird, um Artefakte zu beseitigen.

Wir planen, hochauflösende Zeichenflächen (Canvas) mit Supersampling zu implementieren, Geometrien für Bögen und Tangenten in Dreiecken vorab zu berechnen, für beide Formen Scanline-Füllung zu verwenden, um präzise Innenbereiche zu gewährleisten, und anpassbare Rahmen mit vektorbasierten geraden Kanten und Eckbögen hinzuzufügen. Wir verarbeiten Benutzereingaben für Abmessungen, Radien, Deckkraftwerte und Farben, um flexible, kantenglättete Formen zu erstellen, die sich für moderne Handelsoberflächen eignen. Kurz gesagt: Hier ist eine visuelle Darstellung unserer Ziele.


Autor: Allan Munene Mutiiria

 
Vielen Dank für diesen Artikel! Er ist sehr hilfreich und ausführlich.
Ich versuche, meinem abgerundeten Rechteck einen Abschrägungseffekt (3D-Beleuchtung – weiß oben/links, schwarz unten/rechts) hinzuzufügen.
Ich habe den Abschrägungseffekt an geraden Kanten erfolgreich umgesetzt, habe aber Probleme, sie an den Ecken miteinander zu verbinden.
Siehe die roten Kreise im Bild unten, wo sich die Linien treffen.
Irgendwelche Vorschläge?


//+------------------------------------------------------------------+
//| EFFEKTE MIT ABGESCHRÄGTEN KANTEN
//+------------------------------------------------------------------+
void DrawBeveledEdges(int posX, int posY, int width, int height, int radius, int scaleFactor)
  {
   color lightColor = clrWhite;
   uint lightARGB = ColorToARGBWithOpacity(lightColor, 20);

   color darkColor = clrBlack;
   uint darkARGB = ColorToARGBWithOpacity(darkColor, 35);

   int bevelWidth = 3 * scaleFactor;

// ===== HELLER BEREICH (OBEN LINKS) =====

// Oberer horizontaler Teil
   for(int y = 0; y < bevelWidth; y++)
     {
      for(int x = radius; x < width - radius; x++)
        {
         rectangleHighResCanvas.PixelSet(posX + x, posY + y, lightARGB);
        }
     }

// Linker vertikaler Teil
   for(int x = 0; x < bevelWidth; x++)
     {
      for(int y = radius; y < height - radius; y++)
        {
         rectangleHighResCanvas.PixelSet(posX + x, posY + y, lightARGB);
        }
     }

// ARC oben links – NUR helle Farbe
   for(int dy = -radius; dy <= 0; dy++)
     {
      for(int dx = -radius; dx <= 0; dx++)
        {
         double dist = MathSqrt((double)(dx*dx + dy*dy));

         if(dist >= radius - bevelWidth && dist <= radius + 1)
           {
            int pixX = posX + radius + dx;
            int pixY = posY + radius + dy;

            if(pixX >= posX && pixY >= posY)
               rectangleHighResCanvas.PixelSet(pixX, pixY, lightARGB);
           }
        }
     }

// ARC oben rechts – NUR helle Farbe (obere rechte Ecke)
   for(int dy = -radius; dy <= 0; dy++)
     {
      for(int dx = 0; dx <= radius; dx++)
        {
         double dist = MathSqrt((double)(dx*dx + dy*dy));

         if(dist >= radius - bevelWidth && dist <= radius + 1)
           {
            int pixX = posX + width - radius + dx;
            int pixY = posY + radius + dy;

            if(pixX < posX + width && pixY >= posY)
               rectangleHighResCanvas.PixelSet(pixX, pixY, lightARGB);
           }
        }
     }

// ===== DUNKLE KANTE (UNTEN RECHTS) =====

// Unterer horizontaler Teil
   for(int y = height - bevelWidth; y < height; y++)
     {
      for(int x = radius; x < width - radius; x++)
        {
         rectangleHighResCanvas.PixelSet(posX + x, posY + y, darkARGB);
        }
     }

// Rechter vertikaler Teil
   for(int x = width - bevelWidth; x < width; x++)
     {
      for(int y = radius; y < height - radius; y++)
        {
         rectangleHighResCanvas.PixelSet(posX + x, posY + y, darkARGB);
        }
     }

// ARC unten rechts – NUR dunkle Farbe
   for(int dy = 0; dy <= radius; dy++)
     {
      for(int dx = 0; dx <= radius; dx++)
        {
         double dist = MathSqrt((double)(dx*dx + dy*dy));

         if(dist >= radius - bevelWidth && dist <= radius + 1)
           {
            int pixX = posX + width - radius + dx;
            int pixY = posY + height - radius + dy;

            if(pixX < posX + width && pixY < posY + height)
               rectangleHighResCanvas.PixelSet(pixX, pixY, darkARGB);
           }
        }
     }

// ARC unten links – NUR dunkle Farbe (untere linke Ecke)
   for(int dy = 0; dy <= radius; dy++)
     {
      for(int dx = -radius; dx <= 0; dx++)
        {
         double dist = MathSqrt((double)(dx*dx + dy*dy));

         if(dist >= radius - bevelWidth && dist <= radius + 1)
           {
            int pixX = posX + radius + dx;
            int pixY = posY + height - radius + dy;

            if(pixX >= posX && pixY < posY + height)
               rectangleHighResCanvas.PixelSet(pixX, pixY, darkARGB);
           }
        }
     }
  }
//+------------------------------------------------------------------+


P.S. - Themenvorschläge für zukünftige Artikel:
Schlagschatten- und Glüheffekte – wie man UI-Elementen Tiefe verleiht
Farbverläufe – 3D-Effekte durch Farbübergänge erzeugen
Anti-Aliasing-Techniken – Kanten glätten für ein professionelles Erscheinungsbild
Innenschatten – 3D-Abschrägungseffekte verstärken
Textur- und Rauschmuster – flachen Formen mehr Realismus verleihen