2017-06-21 7 views
-1

Ich versuche einen Weg zu finden, mein Mandelbrot auf Klick zu vergrößern. Ich habe es so, wenn ich es ein wenig zoome reinziehe aber es bewegt das Mandelbrot nicht entsprechend.Zoom auf Mandelbrot

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows.Forms; 
using System.Numerics; 

namespace Project_V2 
{ 
    public partial class FractalGen : Form 
    { 
     public double zoom = 2.4; 
     public FractalGen() 
     { 
      InitializeComponent(); 
     } 

     private void pictureBox1_Click(object sender, EventArgs e) 
     { 
      zoom -= 0.3; 
      Mandelbrot(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
     } 

     private void Form1_Load(object sender, EventArgs e) 
     { 
      Mandelbrot(); 
     } 

     private void timer1_Tick(object sender, EventArgs e) 
     { 

     } 

     private void Mandelbrot() 
     { 
      Bitmap bm = new Bitmap(pictureBox1.Width, pictureBox1.Height); 
      DateTime StartT = DateTime.Now; 
      for (int x = 0; x < pictureBox1.Width; x++) 
      { 
       for (int y = 0; y < pictureBox1.Height; y++) 
       { 
        double a = (double)(x - (pictureBox1.Width/1.25))/(double)(pictureBox1.Width/zoom); 
        double b = (double)(y - (pictureBox1.Height/2))/(double)(pictureBox1.Height/zoom); 
        Complex C = new Complex(a, b); 
        Complex Z = new Complex(0, 0); 
        int u = 0; 
        do 
        { 
         u++; 
         Z = Z * Z; 
         Z = Z + C; 
         double Mag = Complex.Abs(Z); 
         if (Mag > 2.0) break; 
        } while (u < 255); 
        Color rgbInside = Color.FromArgb(0, 0, 0); 
        Color rgbOutside = Color.FromArgb(u >= 127 ? 255 : 2 * u, u >= 127 ? (u - 127) : 0, 0); 
        bm.SetPixel(x, y, u < 255 ? rgbOutside : rgbInside); 
       } 
      } 
      pictureBox1.Image = bm; 
      DateTime EndT = DateTime.Now; 
      string Time = Convert.ToString((EndT - StartT).TotalSeconds); 
      textBox1.Text = "Time Taken: " + Time + " Seconds"; 
     } 

     private void button1_Click_1(object sender, EventArgs e) 
     { 
      zoom = 2.4; 
      Mandelbrot(); 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
      saveFileDialog1.ShowDialog(); 
     } 

     private void saveFileDialog1_FileOk(object sender, CancelEventArgs e) 
     { 
      string name = saveFileDialog1.FileName; 
      pictureBox1.Image.Save(saveFileDialog1.FileName, System.Drawing.Imaging.ImageFormat.Png); 
     } 
    } 
} 

Der aktuelle Code teilt die picturebox Breite und Höhe um einen Wert, aber ich will es haben, so dass es auf zoomt, wo ich auf. Wie könnte ich die Picturebox in Bezug auf wo ich klicken skalieren?

+1

Sie müssen sich mit dem mouseposition abzurufen und zu arbeiten. Diese Antwort hat die Lösung, sogar bereit für eine Bildbox https://stackoverflow.com/questions/7055211/how-to-get-the-position-of-a-click –

+0

Vergiss die Bilderbox und konzentriere dich auf die Daten! - Oh, das habe ich dir schon einmal gesagt und du hast es ignoriert. Nun, viel Glück dann .. – TaW

+0

@TaW: _ "Ich habe dir das vorher gesagt" _ - in welchem ​​Kontext? Gibt es eine gelöschte Frage, wo Sie diese Informationen zur Verfügung gestellt haben? Es würde helfen zu wissen, welche Ratschläge dem OP bereits gegeben wurden, um besser zu verstehen, was sie vielleicht bereits gehört haben und was sie vielleicht nur schwer verstehen können. –

Antwort

2

Es wäre hilfreich zu verstehen, welche Anleitung Ihnen bereits angeboten wurde. Ich folge aus this comment, dass es wahrscheinlich eine bestehende Frage gibt, die Sie gestellt und dann gelöscht haben, in der dieses Problem besprochen wurde. Ohne zu wissen, welche Hilfe bereits angeboten wurde und was genau Sie nicht verstehen konnten, ist es schwer zu wissen, wie Sie am besten eine neue Antwort präsentieren können.

Das heißt, gibt es zwei grundlegende Probleme, die Sie das Verhalten Sie suchen lösen müssen zu erreichen:

  1. identifizieren, wo die Maus geklickt wird. Derzeit verwenden Sie das Ereignis Click, das nur Ihrem Code berichtet, auf den das Steuerelement geklickt wurde, und nicht , auf dem geklickt wurde.
  2. Korrigieren Sie den Rendering-Code, um Änderungen an den Grenzen dessen, was gezeichnet werden soll, anzupassen. Derzeit immer Sie den Bereich der Pixel in der Bitmap auf den Bereich in der komplexen Ebene Karte zentriert auf (-0,72, 0), nur Anpassung, wie weit von diesem Zentrum gemacht wird (dh die zoom Variable.

zu adressieren # 1, müssen Sie stattdessen das Ereignis MouseClick abonnieren Dieses übergibt ein Objekt MouseEventArgs an Ihr Handler, das über eine Location -Eigenschaft verfügt, die den Punkt im Clientbereich des Steuerelements angibt, auf den tatsächlich geklickt wurde (dh die angegebenen Koordinaten sind relativ zu einem Ursprung an der oberen linken Seite des Steuerelements)

Um Nummer 2 zu adressieren, müssen Sie Ihrer Klasse einige Variablen hinzufügen, um die relative Position Ihrer Position zu verfolgen möchte zeichnen. Es gibt viele Möglichkeiten, dies zu tun, aber bei Ihrer derzeitigen Konvention, den aktuellen Zoomfaktor als Breite und Höhe des gerenderten Bereichs darzustellen, scheint es sinnvoll zu sein, das Zentrum des gerenderten Raums zu verfolgen, z Position, auf die die Maus geklickt wurde, in Bezug auf die Position in der komplexen Ebene, die gezeichnet wurde.

Ich habe einen starken Einwand gegen Programme, die die Benutzeroberfläche sperren, während sie lang laufende Aufgaben erledigen. Bei der Überarbeitung Ihres Codebeispiels habe ich es so geändert, dass das Bild in einem Arbeitsthread gerendert wird. Außerdem würde ich den Renderfortschritt melden, indem ich eine Statusmeldung für eine Label, die ich dem Formular hinzugefügt habe, übermittele. (Dies beinhaltete Ihre Mandelbrot() Methode eine async Methode & hellip zu machen;. Ich ging weiter und verwenden await beim Aufruf Compiler-Warnungen zu unterdrücken, aber natürlich in diesem Zusammenhang die await s sind nicht unbedingt erforderlich)

Eine Sache habe ich nicht war es, weitere Optimierungen zum Code hinzuzufügen. Diese neigen dazu, die Änderungen zu verschleiern, die direkt auf Ihre Frage bezogen sind. Es gibt eine Reihe von Dingen, die Sie mit Ihrem Code tun können, um die Leistung zu verbessern, indem Sie überflüssige Berechnungen entfernen oder mathematische Beziehungen verwenden, um Berechnungen kostengünstiger durchzuführen als die wörtliche Übersetzung des Mandelbrot-Algorithmus.

Es gibt viele im Internet darüber, wie man Mandelbrot-Bilder rendert, so dass man sich umsehen kann, um diese Art von Ratschlägen zu finden, sobald man die Grundidee zum Laufen gebracht hat. Außerdem ist die Leistung für jetzt mit nur 255 Iterationen pro Pixel und der relativ kleinen Bitmap keine ernsthafte Überlegung. Hier

ist die Version des Codes ich kam mit:

public partial class Form1 : Form 
{ 
    double zoom = 2.4; 
    double centerX = -0.72, centerY = 0; 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private async void pictureBox1_MouseClick(object sender, MouseEventArgs e) 
    { 
     double minX = centerX - zoom/2, minY = centerY - zoom/2; 
     centerX = minX + (double)e.Location.X/pictureBox1.Width * zoom; 
     centerY = minY + (double)e.Location.Y/pictureBox1.Height * zoom; 
     zoom -= 0.3; 
     await Mandelbrot(); 
    } 

    private async void Form1_Load(object sender, EventArgs e) 
    { 
     await Mandelbrot(); 
    } 

    private async Task Mandelbrot() 
    { 
     IProgress<double> progress = new Progress<double>(x => label1.Text = $"{x * 100:0}% done"); 

     DateTime StartT = DateTime.UtcNow; 
     pictureBox1.Image = await Task.Run(() => _GenerateBitmap(progress)); 
     DateTime EndT = DateTime.UtcNow; 
     string Time = Convert.ToString((EndT - StartT).TotalSeconds); 
     textBox1.Text = "Time Taken: " + Time + " Seconds"; 
    } 

    private Bitmap _GenerateBitmap(IProgress<double> progress) 
    { 
     Bitmap bm = new Bitmap(pictureBox1.Width, pictureBox1.Height); 
     double minX = centerX - zoom/2, minY = centerY - zoom/2; 

     for (int x = 0; x < pictureBox1.Width; x++) 
     { 
      for (int y = 0; y < pictureBox1.Height; y++) 
      { 
       double a = minX + (double)x/pictureBox1.Width * zoom; 
       double b = minY + (double)y/pictureBox1.Height * zoom; 
       Complex C = new Complex(a, b); 
       Complex Z = new Complex(0, 0); 
       int u = 0; 
       do 
       { 
        u++; 
        Z = Z * Z; 
        Z = Z + C; 
        double Mag = Complex.Abs(Z); 
        if (Mag > 2.0) break; 
       } while (u < 255); 
       Color rgbInside = Color.FromArgb(0, 0, 0); 
       Color rgbOutside = Color.FromArgb(u >= 127 ? 255 : 2 * u, u >= 127 ? (u - 127) : 0, 0); 
       bm.SetPixel(x, y, u < 255 ? rgbOutside : rgbInside); 
      } 

      progress.Report((double)x/pictureBox1.Width); 
     } 

     return bm; 
    } 

    private async void button1_Click_1(object sender, EventArgs e) 
    { 
     zoom = 2.4; 
     await Mandelbrot(); 
    } 
} 
+0

Könnten Sie bitte erklären, was diese Codezeile macht? IProgress progress = new Fortschritt (x => label1.Text = $ ("{x * 100: 0}% done"); –

+0

Das erzeugt eine Instanz von 'Progress ', eine generische Klasse, die 'double' verwendet Der Fall, der bei der Erstellung im UI-Thread den an diesen UI-Thread übergebenen Handler automatisch ausführt Der Handler ist in diesem Fall der Lambda-Ausdruck, der den Statuswert "x" empfängt und ihn so formatiert, dass er auf dem Bildschirm angezeigt wird Die formatierte Zeichenkette zu 'label1.Text'. Durch die Übergabe der ganzen' Progress ' Instanz (eingegeben als 'IProgress ', die Fortschrittsberichtsschnittstelle, die 'Progress ' implementiert) zu der Methode, die funktioniert, kann sie den Fortschritt melden wie es geht. –