一個MVVM Mandelbrot
Xamarin.Forms - 以這種方式為像素着色。該程式還允許放大特定位置。這是Mandelbrot集的一個特征,無論你放大多遠,圖像仍然很有趣。不幸的是,基于doubleprecision浮點數的分辨率,縮放存在實際限制。
該程式使用MVVM原理進行架構,雖然在看到有些奇怪的使用者界面以及ViewModel如何處理該使用者界面後,您可能會質疑該決策的智慧。
MandelbrotXF的奇怪使用者界面源于決定避免任何特定于平台的代碼。在最初編寫此程式時,Xamarin.Forms不支援拖動和捏合等觸摸操作,這些操作可能有助于放大到特定位置。相反,程式的整個使用者界面使用兩個Slider元素,兩個Stepper元素,兩個Button元素,一個ProgessBar和使用BoxView實作的視覺效果來實作。
當您第一次運作該程式時,您将看到以下内容:

白色十字準線 - 沒有出現在空白的iOS和Windows 10移動螢幕的白色背景 - 在10秒的時間内淡出,這樣它們就不會模糊你很快就會欣賞的漂亮照片, 但你可以通過操縱滑塊或步進器來将它們帶回來。
但是你要做的第一件事就是按下Go按鈕。 該按鈕被取消按鈕替換,ProgressBar訓示進度。 當它完成後,你會看到一個彩色的Mandelbrot集:
兩個滑塊視圖允許您選擇一個新的中心,該中心在滑塊正下方顯示為複數。 第一個步進元素(标記為縮放)允許您選擇放大系數,也是2的幂。當您操縱這三個元素時,您将看到一個帶十字準線的方框
由六個薄BoxView元素構成。 該框标記下次按“執行”按鈕時将放大的區域:
這不是超越的容易障礙。 存在可變精度浮點數的實作,但由于它們不是由計算機的數學協處理器直接處理,涉及這些數字的計算必然比浮點數或雙精度類型慢得多,并且您可能不希望Mandelbrot計算慢一點。
MandelbrotXF程式同時具有ViewModel和底層模型。 模型執行實際數字運算并傳回BitmapInfo類型的對象,該對象訓示像素寬度和高度以及整數數組。 整數數組的大小是像素寬度和高度的乘積,數組的元素是疊代計數。 值-1表示Mandelbrot集的成員:
namespace MandelbrotXF
{
class BitmapInfo
{
public BitmapInfo(int pixelWidth, int pixelHeight, int[] iterationCounts)
{
PixelWidth = pixelWidth;
PixelHeight = pixelHeight;
IterationCounts = iterationCounts;
}
public int PixelWidth { private set; get; }
public int PixelHeight { private set; get; }
public int[] IterationCounts { private set; get; }
}
}
MandelbrotModel類包含單個異步方法。 除了IProgress對象之外,所有參數都是值類型,是以在計算進行過程中不存在任何參數更改的危險:
namespace MandelbrotXF
{
class MandelbrotModel
{
public Task<BitmapInfo> CalculateAsync(Complex Center,
double width, double height,
int pixelWidth, int pixelHeight,
int iterations,
IProgress<double> progress,
CancellationToken cancelToken)
{
return Task.Run(() =>
{
int[] iterationCounts = new int[pixelWidth * pixelHeight];
int index = 0;
for (int row = 0; row < pixelHeight; row++)
{
progress.Report((double)row / pixelHeight);
cancelToken.ThrowIfCancellationRequested();
double y = Center.Imaginary - height / 2 + row * height / pixelHeight;
for (int col = 0; col < pixelWidth; col++)
{
double x = Center.Real - width / 2 + col * width / pixelWidth;
Complex c = new Complex(x, y);
if ((c - new Complex(-1, 0)).MagnitudeSquared < 1.0 / 16)
{
iterationCounts[index++] = -1;
}
// http://www.reenigne.org/blog/algorithm-for-mandelbrot-cardioid/
else if (c.MagnitudeSquared * (8 * c.MagnitudeSquared - 3) <
3.0 / 32 - c.Real)
{
iterationCounts[index++] = -1;
}
else
{
Complex z = 0;
int iteration = 0;
do
{
z = z * z + c;
iteration++;
}
while (iteration < iterations && z.MagnitudeSquared < 4);
if (iteration == iterations)
{
iterationCounts[index++] = -1;
}
else
{
iterationCounts[index++] = iteration;
}
}
}
}
return new BitmapInfo(pixelWidth, pixelHeight, iterationCounts);
}, cancelToken);
}
}
}
此CalculateAsync方法僅從ViewModel調用。 ViewModel還旨在為XAML檔案提供資料綁定源,并幫助代碼隐藏檔案執行XAML資料綁定無法處理的那些作業。 (繪制十字準線和放大框是該代碼隐藏檔案的工作。)