#define TMM_VERSION
//#define PFX
//#define OUTER_LOOP
//#define INNER_LOOP
//#define USE_TEST_COORDINATES
// Options:
// TMM_VERSION
// PFX (with either OUTER_LOOP or INNER_LOOP but not both)
// neither - single threaded
// also see DualTask in Tasks.cs
// enable USE_TEST_COORDINATES for the coordinates I used in the performance tests.
/* *****************************************************************************
* Copyright (c) 2007, Yu-Jie Lin
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * The names of its contributors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
* *****************************************************************************/
/* Copyright (c) 2006-2007 Coskun Oba
* *****************************************************************************
*
* SCI - Scientific Software Platform
* Copyright (c) 2006-2007
* All rights reserved.
*
* Coskun Oba
* oba.coskun@hotmail.com
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY COSKUN OBA ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL COSKUN OBA BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* *****************************************************************************/
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Clifton.Concurrent;
using Sci.Math;
namespace ms
{
public partial class MainForm : Form
{
// Treat ComplexNumber as Point of double data type.
private Sci.Math.ComplexNumber P1;
private Sci.Math.ComplexNumber P2;
private Sci.Math.ComplexNumber oldP1;
private Sci.Math.ComplexNumber oldP2;
private Size oldSize;
private bool bmpLocked;
private int maxIteration;
private double escapeRadius;
private Color[] Colors = new Color[768];
private void InitView()
{
P1 = new Sci.Math.ComplexNumber(1, 1.5);
P2 = new Sci.Math.ComplexNumber(-2, -1.5);
oldP1 = new Sci.Math.ComplexNumber(1, 1.5);
oldP2 = new Sci.Math.ComplexNumber(-2, -1.5);
oldSize = new Size(300, 300);
numericUpDown1.Value = 15;
textBox1.Text = "2";
maxIteration = 15;
escapeRadius = 2;
}
public MainForm()
{
InitializeComponent();
}
private void UpdateLabels()
{
label1.Text = String.Format("({0:E},{1:E})", P1.Re, P1.Im);
label2.Text = String.Format("({0:E},{1:E})", P2.Re, P2.Im);
label3.Text = String.Format("{0:D} by {1:D} Pixels", p.Width, p.Height);
}
private void GenerateColors()
{
for (int i=0;i<768;i++)
{
int colorValueR=0;
int colorValueG=0;
int colorValueB=0;
if (i >= 512)
{
colorValueR = i - 512;
colorValueG = 255 - colorValueR;
}
else if (i >= 256)
{
colorValueG = i - 256;
colorValueB = 255 - colorValueG;
}
else
{
colorValueB = i;
}
Colors[i] = Color.FromArgb(colorValueR, colorValueG, colorValueB);
}
}
System.Drawing.Bitmap bmp;
private void button1_Click(object sender, EventArgs e)
{
bmp = new Bitmap(p.Width, p.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
bmpLocked = true;
System.Drawing.Imaging.BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0, p.Width, p.Height),
System.Drawing.Imaging.ImageLockMode.ReadWrite,
bmp.PixelFormat);
IntPtr bmpPtr = bmpData.Scan0;
int bytes = p.Width * p.Height * 4;
byte[] argb = new byte[bytes];
#if USE_TEST_COORDINATES
// setup:
maxIteration = 300;
P1 = new ComplexNumber(-0.669912107426552, 0.451398357629374);
P2 = new ComplexNumber(-0.672973630864052, 0.449948162316874);
#endif
double xStep = (P1.Re - P2.Re) / (p.Width - 1);
double yStep = (P1.Im - P2.Im) / (p.Height - 1);
double logEscapeRadius = Math.Log(escapeRadius);
Trace.WriteLine("!!ClearAll");
Trace.WriteLine("!tmm:P1 = " + P1.ToString() + " P2 = " + P2.ToString());
Trace.WriteLine("!tmm:Width = " + p.Width + " Height = " + p.Height);
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
#if TMM_VERSION
Trace.WriteLine("!tmm:Start TMM");
#else
#if PFX
Trace.WriteLine("!tmm:Start PFX");
#else
Trace.WriteLine("!tmm:Start single-threaded");
#endif
#endif
#if DEBUG
Trace.WriteLine("!tmm:Debug");
#else
Trace.WriteLine("!tmm:Release");
#endif
#if TMM_VERSION
progress.Maximum = p.Width * p.Height;
Tasks tasks = new Tasks(xStep, yStep, escapeRadius, logEscapeRadius, p.Width, p.Height, maxIteration, P1, P2, argb, Colors, progress);
tasks.Initialize();
tasks.SendX();
// Wait for the coord queue to flush.
TaskMessageManager.Default.Wait("CoordQueue", UpdateUI);
TaskMessageManager.Default.PostMessage("CoordQueue", StopMessage.Default);
// Wait next for the iteration queue to flush.
TaskMessageManager.Default.Wait("IterationQueue", UpdateUI);
TaskMessageManager.Default.PostMessage("IterationQueue", StopMessage.Default);
// Then wait for the bitmap queue to flush.
TaskMessageManager.Default.Wait("BitmapQueue", UpdateUI);
TaskMessageManager.Default.PostMessage("BitmapQueue", StopMessage.Default);
// Then wait for the bitmap queue to flush.
//TaskMessageManager.Default.Wait("UpdateQueue", UpdateUI);
//TaskMessageManager.Default.PostMessage("UpdateQueue", StopMessage.Default);
TaskMessageManager.Default.Wait(UpdateUI);
#else
// Sci.Math.ComplexNumber z = P2;
progress.Maximum = p.Width;
#if PFX
#if OUTER_LOOP
Parallel.For(0, p.Width, x =>
#endif
#if INNER_LOOP
for (int x = 0; x < p.Width; x++)
#endif
#else
for (int x = 0; x < p.Width; x++)
#endif
{
#if OUTER_LOOP
Sci.Math.ComplexNumber z = P2;
z.Im = P1.Im;
z.Re = P2.Re + (x * xStep);
#endif
#if INNER_LOOP
Parallel.For(0, p.Height, y =>
#else
for (int y = 0; y < p.Height; y++)
#endif
{
#if INNER_LOOP
ComplexNumber z=P2;
z.Re = P2.Re + (x * xStep);
#endif
z.Im = P1.Im - (yStep * y);
Sci.Math.ComplexNumber C = z;
int iteration = 0;
while (z.Modulus < escapeRadius && iteration < maxIteration)
{
z = z * z + C;
iteration++;
}
int colorIndex = 0;
int index = (y * p.Width + x) * 4;
if (iteration < maxIteration)
{
z = z * z + C; iteration++;
z = z * z + C; iteration++;
double mu = iteration - (Math.Log(Math.Log(z.Modulus))) / logEscapeRadius;
colorIndex = (int)(mu / maxIteration * 768);
if (colorIndex >= 768) colorIndex = 0;
if (colorIndex < 0) colorIndex = 0;
}
argb[index] = Colors[colorIndex].B;
argb[index + 1] = Colors[colorIndex].G;
argb[index + 2] = Colors[colorIndex].R;
argb[index + 3] = 255;
z = C;
}
#if INNER_LOOP
);
#endif
progress.Value = x;
}
#if PFX
#if OUTER_LOOP
);
#endif
#endif
#endif
long ms = stopwatch.ElapsedMilliseconds;
Trace.WriteLine("!tmm:Done. Time = "+ms+"ms");
System.Runtime.InteropServices.Marshal.Copy(argb, 0, bmpPtr, argb.Length);
bmp.UnlockBits(bmpData);
bmpLocked = false;
p.Invalidate();
progress.Value = 0;
oldP1 = P1;
oldP2 = P2;
oldSize = p.Size;
}
protected void UpdateUI()
{
// on 32 bit systems, this is atomic.
int val = Tasks.progressValue;
progress.Value = val;
Application.DoEvents();
Thread.Sleep(100);
}
private void p_MouseMove_1(object sender, MouseEventArgs e)
{
Control control = (Control)sender;
int x = e.X;
int y = (control.Height - 1) - e.Y;
Sci.Math.ComplexNumber P = P2 + new Sci.Math.ComplexNumber((double)x * (P1.Re - P2.Re) / (p.Width - 1),
(double)y * (P1.Im - P2.Im) / (p.Height - 1));
pos.Text = String.Format("({0:E},{1:E})", P.Re, P.Im);
}
private void p_SizeChanged(object sender, EventArgs e)
{
Control control = (Control)sender;
Sci.Math.ComplexNumber c = (oldP1 + oldP2) / 2;
Sci.Math.ComplexNumber diff = (oldP1 - oldP2) / 2;
diff = new Sci.Math.ComplexNumber(diff.Re * (double)control.Size.Width / oldSize.Width,
diff.Im * (double)control.Size.Height / oldSize.Height);
// New Region
P1 = c + diff;
P2 = c - diff;
p.Invalidate();
UpdateLabels();
}
private void p_MouseDoubleClick(object sender, MouseEventArgs e)
{
Control control = (Control)sender;
int x = e.X;
int y = (control.Height - 1) - e.Y;
Sci.Math.ComplexNumber P = P2 + new Sci.Math.ComplexNumber((double)x * (P1.Re - P2.Re) / (p.Width - 1),
(double)y * (P1.Im - P2.Im) / (p.Height - 1));
Sci.Math.ComplexNumber diff = new Sci.Math.ComplexNumber();
switch (e.Button)
{
case MouseButtons.Left:
// Zoom in
diff = (P1 - P2) / 2 / 2;
break;
case MouseButtons.Right:
// Zoom out
diff = (P1 - P2) / 2 * 2;
break;
}
// New Region
P1 = P + diff;
P2 = P - diff;
UpdateLabels();
button1_Click(null, null);
}
private void p_Paint(object sender, PaintEventArgs e)
{
if (!bmpLocked)
{
int x = (p.Width - oldSize.Width) / 2;
int y = (p.Height - oldSize.Height) / 2;
e.Graphics.DrawRectangle(new Pen(Color.White), 0, 0, p.Width, p.Height);
e.Graphics.DrawImage(bmp, x, y);
}
}
private void button2_Click(object sender, EventArgs e)
{
InitView();
WindowState = FormWindowState.Normal;
Size = MinimumSize;
UpdateLabels();
button1_Click(null, null);
}
private void numericUpDown1_ValueChanged(object sender, EventArgs e)
{
maxIteration = (int)((NumericUpDown)sender).Value;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
try
{
escapeRadius = int.Parse(((TextBox)sender).Text);
}
catch
{
// Do nothing
}
}
private void MainForm_Load(object sender, EventArgs e)
{
InitView();
bmp = new Bitmap(p.Width, p.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
GenerateColors();
UpdateLabels();
}
private void button4_Click(object sender, EventArgs e)
{
if (saveFileDialog1.ShowDialog()== DialogResult.OK)
bmp.Save(saveFileDialog1.FileName);
}
private void button3_Click(object sender, EventArgs e)
{
Clipboard.SetImage(bmp);
}
}
}