Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

Visualizing Complex Functions

, 23 May 2010 Ms-PL
A program to produce beautiful and informative images of complex functions.
ComplexExplorer.zip
Complex Explorer
ComplexExplorer.exe
Meta.Numerics.dll
ComplexExplorerSource.zip
ComplexExplorer
ComplexExplorer
Icon.ico
Properties
Settings.settings
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)

Share

About the Author

dawright

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.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150301.1 | Last Updated 24 May 2010
Article Copyright 2010 by dawright
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid