📄 fractalset.cs
字号:
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using System.Threading;
namespace Fractals
{
public class FractalSet : IDisposable
{
protected int _MaxIter = 512;
protected int _MaxColors;
protected int _MaxMagSquared = 4;
protected int[] _Color =
{
Color.Black.ToArgb(),
Color.Chocolate.ToArgb(),
Color.Beige.ToArgb(),
Color.Cyan.ToArgb(),
Color.DarkCyan.ToArgb(),
Color.Aqua.ToArgb(),
Color.Blue.ToArgb(),
Color.DarkBlue.ToArgb(),
Color.Red.ToArgb(),
Color.DarkRed.ToArgb(),
Color.Green.ToArgb(),
Color.DarkGreen.ToArgb(),
Color.Violet.ToArgb(),
Color.DarkViolet.ToArgb(),
Color.Yellow.ToArgb(),
Color.White.ToArgb()
};
private Rectangle _ZoomRect;
private Point _LastPoint;
private bool _MouseDown;
public delegate void UpdateReadoutsDelegate( double realCenter, double imgCenter, double scale );
public UpdateReadoutsDelegate ReadoutsDelegate;
protected bool _WorkStopped = false;
protected object _Lock = new object();
protected ManualResetEvent _ResetEvent = new ManualResetEvent(false);
protected delegate void UpdateImageDelegate(Bitmap ColBmp, int Col);
protected Thread _Thread;
protected Bitmap _bmp ;
protected PictureBox _PictureBox;
protected int _width = 0;
protected int _height = 0;
protected double _realCenter = 0.0;
protected double _imgCenter = 0.0;
protected double _realMin = -2.0;
protected double _imgMin = -2.0;
protected double _deltaReal;
protected double _deltaImg;
public FractalSet()
{
_MaxColors = _Color.Length;
}
protected void Draw()
{
int band = 5;
Bitmap bm = new Bitmap( band, _PictureBox.Height );
UpdateImageDelegate UpdateDelegate = new UpdateImageDelegate( UpdateImage );
int Col = 0;
object[] args = new object[] {bm, Col};
for( int i = 0 ; i < _width && WorkStopped == false ; i+=band )
{
for( int k = 0 ; k < band && WorkStopped == false ; k++ )
{
double RealC = _realMin + _deltaReal * (i + k);
for( int j = 0 ; j < _height && WorkStopped == false ; j++ )
{
double ImaginaryC = _imgMin + _deltaImg * j;
bm.SetPixel( k, j, GetColorVal( RealC, ImaginaryC ) );
}
}
//Copy a column to the large bitmap
args[1] = i;
IAsyncResult ares = _PictureBox.BeginInvoke( UpdateDelegate, args );
if( WorkStopped == false )
{
WaitHandle[] arr = new WaitHandle[2];
arr[0] = _ResetEvent;
arr[1] = ares.AsyncWaitHandle;
WaitHandle.WaitAny( arr );
}
}
}
protected virtual Color GetColorVal( double r, double i )
{
return( Color.Black );
}
public void Start( PictureBox pb )
{
DisableMouseHandlers();
_PictureBox = pb;
_PictureBox.MouseDown += new MouseEventHandler(_PictureBox_MouseDown);
_PictureBox.MouseMove += new MouseEventHandler(_PictureBox_MouseMove);
_PictureBox.MouseUp += new MouseEventHandler(_PictureBox_MouseUp);
Start();
}
public void DisableMouseHandlers()
{
if( _PictureBox != null )
{
_PictureBox.MouseDown -= new MouseEventHandler(_PictureBox_MouseDown);
_PictureBox.MouseMove -= new MouseEventHandler(_PictureBox_MouseMove);
_PictureBox.MouseUp -= new MouseEventHandler(_PictureBox_MouseUp);
}
}
private void Start()
{
if( (_Thread != null) && (_Thread.IsAlive) )
{
Kill();
}
CreateGraphicsObjects();
ThreadStart ts = new ThreadStart( Draw );
_Thread = new Thread( ts );
//_Thread.Priority = ThreadPriority.BelowNormal; //Option
_Thread.IsBackground = true;
WorkStopped = false;
_Thread.Start();
}
private void CreateGraphicsObjects()
{
if( _bmp == null )
{
_bmp = new Bitmap( _PictureBox.Width, _PictureBox.Height );
_PictureBox.BackgroundImage = _bmp;
}
else
{
if( (_bmp.Width != _PictureBox.Width) || (_bmp.Height != _PictureBox.Height) )
{
_bmp.Dispose();
_bmp = new Bitmap( _PictureBox.Width, _PictureBox.Height );
_PictureBox.BackgroundImage = _bmp;
}
}
_width = _bmp.Width;
_height = _bmp.Height;
_realMin = _realCenter - _deltaReal * _width / 2;
_imgMin = _imgCenter - _deltaImg * _height / 2;
if( ReadoutsDelegate != null )
{
ReadoutsDelegate( _realCenter, _imgCenter, _deltaReal );
}
//Make a bitmap to draw user selection on
Bitmap bmp = new Bitmap( _PictureBox.Width, _PictureBox.Height );
if( _PictureBox.Image != null )
{
_PictureBox.Image.Dispose();
}
_PictureBox.Image = bmp;
}
protected void UpdateImage( Bitmap ColBmp, int Col )
{
Graphics g = null;
try
{
g = Graphics.FromImage( _PictureBox.BackgroundImage );
g.DrawImage( ColBmp, Col, 0, ColBmp.Width, _height );
_PictureBox.Refresh();
Application.DoEvents();
}
finally
{
if( g != null )
{
g.Dispose();
}
}
}
public void Kill()
{
if( _Thread == null )
{
return;
}
if( _Thread.IsAlive == false )
{
return;
}
WorkStopped = true;
_ResetEvent.Set();
//Wait for thread to die
_Thread.Join();
WorkStopped = false;
_ResetEvent.Reset();
}
protected bool WorkStopped
{
get
{
bool b;
lock(_Lock)
{
b = _WorkStopped;
}
return b;
}
set
{
lock(_Lock)
{
_WorkStopped = value;
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//Called by Dispose()
if (_Thread != null)
{
Kill();
}
}
}
private void DrawSelection( Rectangle ZoomRect )
{
if( _PictureBox.Image == null )
{
return;
}
Graphics g = Graphics.FromImage( _PictureBox.Image );
ClearSelection( g );
Pen pen = new Pen( Color.LightBlue, 2 );
pen.DashPattern = new Single[] {1, 1, 2, 1};
g.DrawRectangle( pen, ZoomRect );
_ZoomRect = ZoomRect;
_PictureBox.Refresh();
}
private void ClearSelection( Graphics g )
{
g.Clear( Color.Transparent );
}
private void ClearSelection()
{
Graphics g = Graphics.FromImage( _PictureBox.Image );
g.Clear( Color.Transparent );
}
private void _PictureBox_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e ) //Handles _PictureBox.MouseDown
{
_MouseDown = true;
_LastPoint = new Point( e.X, e.Y );
}
private void _PictureBox_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
{
if( _MouseDown )
{
int X1, Y1, X2, Y2;
X1 = Math.Min( e.X, _LastPoint.X );
X2 = Math.Max( e.X, _LastPoint.X ) - X1;
Y1 = Math.Min( e.Y, _LastPoint.Y );
Y2 = Math.Max( e.Y, _LastPoint.Y ) - Y1;
Rectangle NewSelRect = new Rectangle( X1, Y1, X2, Y2 );
DrawSelection( NewSelRect );
}
}
private void _PictureBox_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
{
_MouseDown = false;
int X1, Y1, X2, Y2;
if( (e.X == _LastPoint.X) && (e.Y == _LastPoint.Y) )
{
double xCenter = _width / 2;
double yCenter = _height / 2;
double deltaReal = (e.X - xCenter) * _deltaReal;
double deltaImg = (e.Y - yCenter) * _deltaImg;
_realCenter += deltaReal;
_imgCenter += deltaImg;
Start();
}
else
{
//User may have selected from right to left
X1 = Math.Min( e.X, _LastPoint.X );
X2 = Math.Max( e.X, _LastPoint.X );
Y1 = Math.Min( e.Y, _LastPoint.Y );
Y2 = Math.Max( e.Y, _LastPoint.Y );
//If tiny selection, assume accidental mouseup
if( Math.Abs(X1 - X2) < 3 || Math.Abs(Y1 - Y2) < 3 )
{
ClearSelection();
}
else
{
Zoom( X1, Y1, X2, Y2 );
}
}
}
public void ZoomIn()
{
_deltaReal /= 2;
_deltaImg /= 2;
_realMin = _realCenter - (_width / 2) * _deltaReal;
_imgMin = _imgCenter - (_height / 2) * _deltaImg;
Start();
}
public void ZoomOut()
{
_deltaReal *= 2;
_deltaImg *= 2;
_realMin = _realCenter - (_width / 2) * _deltaReal;
_imgMin = _imgCenter - (_height / 2) * _deltaImg;
Start();
}
private void Zoom( int X1, int Y1, int X2, int Y2 )
{
double realMin = _realCenter - (_width / 2) * _deltaReal;
double realMax = _realCenter + (_width / 2) * _deltaReal;
double imgMin = _imgCenter - (_height / 2) * _deltaImg;
double imgMax = _imgCenter + (_height / 2) * _deltaImg;
double Old_realMin = realMin;
double Old_imgMin = imgMin;
double Old_realMax = realMax;
double Old_imgMax = imgMax;
realMin += (double)X1 * _deltaReal;
realMax = Old_realMin + (double)X2 * _deltaReal;
imgMin += (double)Y1 * _deltaImg;
imgMax = Old_imgMin + (double)Y2 * _deltaImg;
if( (realMin == realMax) || (imgMin == imgMax ) )
{
ClearSelection();
return;
}
_realCenter = (realMin + realMax) / 2;
_imgCenter = (imgMin + imgMax) / 2;
_deltaReal = (realMax - realMin) / _width;
_deltaImg = (imgMax - imgMin) / _height;
if( _deltaReal > _deltaImg )
{
_deltaImg = _deltaReal;
}
else
{
_deltaReal = _deltaImg;
}
Start();
}
public void SaveBitmap( string fn, ImageFormat format )
{
if( _bmp != null )
{
_bmp.Save( fn, format );
}
}
public Bitmap Image
{
get { return( _bmp ); }
}
public int Iterations
{
get { return( _MaxIter ); }
set { _MaxIter = value; }
}
public int[] ColorMap
{
get { return( _Color ); }
set { _Color = value; }
}
public double Scale
{
get { return( _deltaReal ); }
set { _deltaReal = value; _deltaImg = value; }
}
public double RealCenter
{
get { return( _realCenter ); }
set { _realCenter = value; }
}
public double ImgCenter
{
get { return( _imgCenter ); }
set { _imgCenter = value; }
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -