Click here to Skip to main content
15,887,434 members
Articles / Desktop Programming / Windows Forms

Visualizing Complex Functions

Rate me:
Please Sign up or sign in to vote.
4.95/5 (77 votes)
23 May 2010Ms-PL14 min read 109.9K   4.1K   127  
A program to produce beautiful and informative images of complex functions.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Text;
using System.Windows.Forms;

using Meta.Numerics;
using Meta.Numerics.Functions;

namespace ComplexExplorer {

    public partial class ComplexExplorerForm : Form {

        public ComplexExplorerForm () {
            InitializeComponent();
        }

        // create an image based on the current complex function

        public void DrawImage () {

            // get the function to evaluate
            Function<Complex,Complex> f = functions[functionList.SelectedIndex].Function;

            Bitmap image = new Bitmap(imageBox.Width, imageBox.Height);

            // iterate over all image pixels
            for (int x = 0; x < imageBox.Width; x++) {
                double re = re_min + x * (re_max - re_min) / imageBox.Width;
                for (int y = 0; y < imageBox.Height; y++) {
                    double im = im_max - y * (im_max - im_min) / imageBox.Height;

                    // form a complex number based on the pixel value
                    Complex z = new Complex(re, im);

                    // compute the value of the current complex function for that complex number
                    Complex fz = f(z);

                    // don't try to plot non-numeric values (e.g. at poles)
                    if (Double.IsInfinity(fz.Re) || Double.IsNaN(fz.Re) || Double.IsInfinity(fz.Im) || Double.IsNaN(fz.Im)) continue;

                    // convert the complex function value to a HSV color triplet
                    ColorTriplet hsv = ColorMap.ComplexToHsv(fz);

                    // convert the HSV color triplet to an RBG color triplet
                    ColorTriplet rgb = ColorMap.HsvToRgb(hsv);
                    int r = (int) Math.Truncate(255.0 * rgb.X);
                    int g = (int) Math.Truncate(255.0 * rgb.Y);
                    int b = (int) Math.Truncate(255.0 * rgb.Z);
                    Color color = Color.FromArgb(r, g, b);

                    // plot the point
                    image.SetPixel(x, y, color);

                }
            }

            // put the image in the image box control
            imageBox.Image = image;

        }

        // bounds in the complex plane

        private double re_min = -3.0;
        private double re_max = +3.0;
        private double im_min = -3.0;
        private double im_max = +3.0;

        // the list of complex functions available

        private List<ComplexFunction> functions = new List<ComplexFunction>();

        // when a new function is selected, re-draw image

        private void functionList_SelectedIndexChanged (object sender, EventArgs e) {

            valueText.Text = String.Empty;
            DrawImage();

        }

        // when the image is clicked on, display the function value

        private void imageBox_MouseClick (object sender, MouseEventArgs e) {
            if (functionList.SelectedIndex < 0) return;
            double re = re_min + e.X * (re_max - re_min) / imageBox.Width;
            double im = im_max - e.Y * (im_max - im_min) / imageBox.Height;
            Complex z = new Complex(re, im);
            Complex fz = functions[functionList.SelectedIndex].Function(z);
            valueText.Text = String.Format(CultureInfo.CurrentCulture, "f({0}) = {1}", FormatComplex(z), FormatComplex(fz));
        }

        // formatting a complex number

        private static string FormatComplex (Complex z) {
            StringBuilder text = new StringBuilder();
            double re = z.Re;
            double im = z.Im;
            if ((re != 0.0) || (im == 0.0)) {
                text.AppendFormat(CultureInfo.CurrentCulture, "{0:g4}", re);
            }
            if (im != 0.0) {
                if (im < 0.0) {
                    text.Append(CultureInfo.CurrentCulture.NumberFormat.NegativeSign);
                    im = -im;
                } else {
                    if (re != 0.0) text.Append(CultureInfo.CurrentCulture.NumberFormat.PositiveSign);
                }
                text.AppendFormat(CultureInfo.CurrentCulture, "{0:g4}", im);
                text.Append("i");
            }
            return (text.ToString());
        }

        // save file

        private void saveButton_Click (object sender, EventArgs e) {

            SaveFileDialog dialog = new SaveFileDialog();
            dialog.Filter = "Portable Network Graphics (*.png)|*.png";
            dialog.RestoreDirectory = true;
            if (dialog.ShowDialog() == DialogResult.OK) {

                using (Stream writer = dialog.OpenFile()) {
                    if (writer == null) return;
                    imageBox.Image.Save(writer, System.Drawing.Imaging.ImageFormat.Png);
                }

            }

        }

        // setup behavior

        private void ComplexExplorerForm_Load (object sender, EventArgs e) {

            // load functions

            functions.AddRange(new ComplexFunction[] {
                new ComplexFunction() {
                    Label = "z",
                    Function = delegate(Complex z) { return (z); }
                },
                new ComplexFunction() {
                    Label = "z^2 - 1",
                    Function = delegate(Complex z) { return ((z-1.0) * (z+ 1.0)); }
                },
                new ComplexFunction() {
                    Label = "z^3 + 1",
                    Function = delegate(Complex z) { return (z*z*z + 1.0); }
                },
                new ComplexFunction() {
                    Label = "1/z",
                    Function = delegate(Complex z) { return(1.0/z); }
                },
                // Claudio Rocchini's example function from http://en.wikipedia.org/wiki/File:Color_complex_plot.jpg
                new ComplexFunction() {
                    Label = "(z^2-1)(z-2-i)^2/(z^2+2+2i)",
                    Function = delegate(Complex z) { 
                        Complex zs = z - 2.0 - ComplexMath.I;
                        return((z*z-1.0)*zs*zs/(z*z+2.0+2.0*ComplexMath.I));
                    }
                },
                new ComplexFunction() {
                    Label = "sqrt(z)",
                    Function = ComplexMath.Sqrt
                },
                new ComplexFunction() {
                    Label = "exp(z)",
                    Function = ComplexMath.Exp
                },                new ComplexFunction() {
                    Label = "ln(z)",
                    Function = ComplexMath.Log
                },
                new ComplexFunction() {
                    Label = "Gamma(z)",
                    Function = AdvancedComplexMath.Gamma
                },
                new ComplexFunction() {
                    Label = "Psi(z)",
                    Function = AdvancedComplexMath.Psi
                },
                new ComplexFunction() {
                    Label = "Faddeeva(z)",
                    Function = AdvancedComplexMath.Faddeeva
                }
            });

            // bind functions to function list

            foreach (ComplexFunction function in functions) {
                functionList.Items.Add(function.Label);
            }

            // select first function

            functionList.SelectedIndex = 0;

        }

        // call up web site when footer is clicked

        private void footerLabel_LinkClicked (object sender, LinkLabelLinkClickedEventArgs e) {
            Process.Start("http://www.meta-numerics.net");
        }

    }

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
United States United States
I am a .NET developer who works daily on enterprise-scale applications using C#, SQL, XML, ASP.NET, and myriad other technologies. My academic background is in physics and economics.

I am the original architect of Sandcastle managed reference documentation engine and of the Meta.Numerics library for scientific computation.

Comments and Discussions