2016-07-13 18 views
2

Ich arbeite an diesem Iso-Raster-Spiel (genauer: dimetrische Projektion, indexiert in typischen Diamant-Layout) und wollte Kreisbürsten implementieren, um Fliesen auf meiner Karte nur zu malen wie in jeder Bildbearbeitungssoftware. Ich begann mit dem Midpoint Circle Algorithm, aber bemerkt sofort, dass das Ergebnis nicht so aussieht, was ich will für kleine Pinselgrößen zwischen 1 und 7.Bessere Algorithmus als Midpoint Circle für Kachel Map Brushes auf Iso-Gitter

enter image description here

würde ich viel lieber etwas wie dieses:

enter image description here

ignorieren, dass die ersten Kreise nicht gefüllt sind, das ist natürlich einfach. Gibt es geeignete Algorithmen zur Formerzeugung auf Iso-Gittern? Ich möchte wahrscheinlich nicht einmal Kreisformen, sondern abwechselnde Quad- und Kreuz-ähnliche/x-Formen. Hier

ist der Code für die erste Bild Probe aus der Wikipedia:

static List<IntVector2> GetBrushCircleCoords(int x0, int y0, int radius) 
{ 
    List<IntVector2> coords = new List<IntVector2>(); 
    int x = radius; 
    int y = 0; 
    int err = 0; 

    while (x >= y) 
    { 
     coords.Add(new IntVector2(x0 + x, y0 + y)); 
     coords.Add(new IntVector2(x0 + y, y0 + x)); 
     coords.Add(new IntVector2(x0 - y, y0 + x)); 
     coords.Add(new IntVector2(x0 - x, y0 + y)); 
     coords.Add(new IntVector2(x0 - x, y0 - y)); 
     coords.Add(new IntVector2(x0 - y, y0 - x)); 
     coords.Add(new IntVector2(x0 + y, y0 - x)); 
     coords.Add(new IntVector2(x0 + x, y0 - y)); 

     y += 1; 
     err += 1 + 2 * y; 
     if (2 * (err - x) + 1 > 0) 
     { 
      x -= 1; 
      err += 1 - 2 * x; 
     } 
    } 
    return coords; 
} 
+1

nicht sicher, wie man Verbessere den Code für kleine Kreise. Aber wie du schon erwähnst, magst du eigentlich (sowieso) keine Kreise haben, ich dachte mir das hier [Beitrag über 'virtuelle Pixel'] (http://stackoverflow.com/questions/22881312/c-sharp-drawing-text-using-custom -pixels/22881391 # 22881391) könnte von Interesse sein. Es wird erläutert, wie Sie mit normaler Zeichnung (GDI + oder was auch immer) eine Vorlage erstellen können, aus der Sie dann die Pinselpixel auswählen. Auf diese Weise können Sie alle grafischen Grundelemente, einschließlich sogar Schriftarten verwenden. – TaW

+0

** ** ** ** ** ** zu meiner Antwort hinzugefügt. – Spektre

Antwort

4

Sie nicht dem Layout Ihres isometrischen Raster angegeben haben. Ich nehme Diamant an, da es dort leichter zu implementieren ist. Bei Integer-Arithmetik ist es jedoch sehr schwierig, die Halbzellenauflösung des Radius zu implementieren. Für die Full Cell Resolution Radius Disc Füllung verwenden Sie einfach 2 verschachtelte for s mit Innenkreistest. Das Ergebnis sieht wie folgt aus:

raw

einfach den Baum und Fliesen Liste Overlay meiner isometrischen Editor ignorieren. Hier ist die C++ Quellcode für diese:

void isometric::brush_circle(int x0,int y0,int z0,int r) 
    { 
    r--; if (r<0) return; 
    int tp=16; // filling tile 
    int x,y,rx,ry,rxx,ryy,rr=(r+1)*(r+1)-(r>>1); 

    if ((z0>=0)&&(z0<gzs)) 
    for (rx=-r,x=x0+rx,rxx=rx*rx;rx<=r;rx++,x++,rxx=rx*rx) 
    for (ry=-r,y=y0+ry,ryy=ry*ry;ry<=r;ry++,y++,ryy=ry*ry) 
     if (rxx+ryy<rr) 
     if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) 
     map[z0][y][x]=tp; 

    _redraw=true; 
    } 

Es verwendet Disc/Kreisgleichung:

(x-x0)^2+(y-y0)^2<=r^2 

Mit etwas ganze Zahl abrunden zwicken, um besser aussehende Ergebnisse.Der Code wird auf diesem isometrischen Motor von mir basiert:

Nach den Kanten Anwendung Glättung des Ergebnis ist wie folgt:

smooth

Wenn Sie das umsetzen wollen Halbzelle Radius Auflösung haben Sie mehr Optionen zum Beispiel:

  1. Verwendung oder fester Punkt schwimmend arithmetics
  2. Verwendung diameter als Operanden Aufruf statt radius so aktualisieren Sie einfach die Gleichung entsprechend (mit Rundungs ​​Vermeidung)

Ich gehe für # 2 so verwenden:

Das nächste, was ich habe, ist dies (mit Sonderfall für d=2):

void isometric::brush_circle(int x0,int y0,int z0,int d) 
    { 
    if ((z0<0)||(z0>=gzs)) return; 
    int tp=16; // filling tile 
    int x,y,rx,ry,rxx,ryy,r=(d>>1)+1,rr=((d*d)-(d>>1))>>2; 
    if (d==2) 
     { 
     x=x0; y=y0; if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp; 
     x++;  if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp; 
     y++;  if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp; 
     x--;  if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp; 
     } 
    else 
    for (rx=-r,x=x0+rx,rxx=rx*rx;rx<=r;rx++,x++,rxx=rx*rx) 
     for (ry=-r,y=y0+ry,ryy=ry*ry;ry<=r;ry++,y++,ryy=ry*ry) 
     if (rxx+ryy<=rr) 
     if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) 
     map[z0][y][x]=tp; 
    _redraw=true; 
    } 

raw smooth

Es sieht aus wie es mindestens ein Sonderfall und oder zwicken die rr Konstante ein bisschen das Hinzufügen von benötigen.

[Edit1] Nach dem Mittagessen und einige mehr gelehrt ...

Aus integer Sicht viel besser Gleichung lautet:

4*((x-x0)^2 + (y-y0)^2) <= (d^2) 

final

void isometric::brush_circle(int x0,int y0,int z0,int d) 
    { 
    if ((z0<0)||(z0>=gzs)) return; 
    int tp=16; // filling tile 
    int x,y,rx,ry,rxx,ryy,r=(d>>1)+1,dd=(d*d)+d; 
    if (d==2) 
     { 
     x=x0; y=y0; if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp; 
     x++;  if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp; 
     y++;  if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp; 
     x--;  if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) map[z0][y][x]=tp; 
     } 
    else 
    for (rx=-r,x=x0+rx,rxx=rx*rx;rx<=r;rx++,x++,rxx=rx*rx) 
     for (ry=-r,y=y0+ry,ryy=ry*ry;ry<=r;ry++,y++,ryy=ry*ry) 
     if ((rxx+ryy)<<2<dd) 
     if ((x>=0)&&(x<gxs)&&(y>=0)&&(y<gys)) 
     map[z0][y][x]=tp; 
    _redraw=true; 
    } 
+0

Dies ist sehr hilfreich. Ich brauche etwas Zeit, um es zu verdauen, aber der erste Beispielcode funktioniert schon viel besser als mein Versuch. – Xarbrough

+0

@Xarbrough freuen uns, Ihnen behilflich zu sein – Spektre