/// <summary> /// </summary> /// <param name="controls"></param> /// <param name="numColors"></param> /// <param name="extrapolationType"></param> /// <returns></returns> /// <exception cref="ArgumentNullException"><paramref name="source" /> or <paramref name="selector" /> is null.</exception> /// <exception cref="ArgumentException"><paramref name="red" />, <paramref name="green" />, or <paramref name="blue" /> is less than 0 or greater than 255.</exception> /// <exception cref="OverflowException">The number of elements in <paramref name="source" /> is larger than <see cref="F:System.Int32.MaxValue" />.</exception> /// <exception cref="InvalidOperationException"><paramref name="source" /> contains no elements.</exception> /// <exception cref="Exception">A delegate callback throws an exception.</exception> /// <exception cref="ArgumentOutOfRangeException"><paramref name="count" /> is less than 0.-or-<paramref name="start" /> + <paramref name="count" /> -1 is larger than <see cref="F:System.Int32.MaxValue" />.</exception> public static RgbValue[] GenerateColorPalette(Tuple <double, Color>[] controls, int numColors, MathUtilities.ExtrapolationType extrapolationType = MathUtilities.ExtrapolationType.None) { var palette = new RgbValue[numColors]; var controlCount = controls.Length; var oneOverNumColors = 1.0 / numColors; double[] red = new double[controlCount], green = new double[controlCount], blue = new double[controlCount], xs = new double[controlCount]; for (var i = 0; i < controlCount; ++i) { red[i] = controls[i].Item2.R; green[i] = controls[i].Item2.G; blue[i] = controls[i].Item2.B; xs[i] = controls[i].Item1; } var channelSplines = new[] { MathUtilities.CreateInterpolant(xs, red, extrapolationType), MathUtilities.CreateInterpolant(xs, green, extrapolationType), MathUtilities.CreateInterpolant(xs, blue, extrapolationType) }; for (var i = 0; i < numColors; ++i) { var arg = i * oneOverNumColors; palette[i] = new RgbValue(); palette[i].red = MathUtilities.Clamp((int)channelSplines[0](arg), 0, 255); palette[i].green = MathUtilities.Clamp((int)channelSplines[1](arg), 0, 255); palette[i].blue = MathUtilities.Clamp((int)channelSplines[2](arg), 0, 255); } return(palette); }
public static RgbValue[] LoadPalette(string path) { List <RgbValue> pallete = new List <RgbValue>(); using (StreamReader palleteData = new StreamReader(path)) { while (!palleteData.EndOfStream) { try { string palleteString = palleteData.ReadLine(); if (string.IsNullOrWhiteSpace(palleteString)) { continue; } string[] palleteTokens = palleteString.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int r = int.Parse(palleteTokens[0]); int g = int.Parse(palleteTokens[1]); int b = int.Parse(palleteTokens[2]); RgbValue color = new RgbValue(r, g, b); pallete.Add(color); } catch (FormatException) { } } return(pallete.ToArray()); } }
public static RgbValue LerpColors(RgbValue a, RgbValue b, double alpha) { // Initialize final color RgbValue c = new RgbValue(); // Linear interpolate red, green, and blue values. c.red = (int)Lerp(a.red, b.red, alpha); c.green = (int)Lerp(a.green, b.green, alpha); c.blue = (int)Lerp(a.blue, b.blue, alpha); return(c); }
public static double FindPaletteColorLocation(RgbValue[] palette, RgbValue color) { var locationOfPaletteColorClosestToBlack = 0.0; var distanceOfPaletteColorClosestToBlack = EuclideanDistance(palette[0], color); for (var i = 1; i < palette.Length; ++i) { var distanceOfCurrentColorFromBlack = EuclideanDistance(palette[i], color); if (Math.Abs(distanceOfCurrentColorFromBlack) < MathUtilities.Tolerance) { break; } if (distanceOfCurrentColorFromBlack < distanceOfPaletteColorClosestToBlack) { locationOfPaletteColorClosestToBlack = i; distanceOfPaletteColorClosestToBlack = distanceOfCurrentColorFromBlack; } } return(locationOfPaletteColorClosestToBlack / palette.Length); }
private static double EuclideanDistance(RgbValue a, RgbValue b) { double dR = a.red - b.red, dG = a.green - b.green, dB = a.blue - b.blue; return(Math.Sqrt(dR * dR + dG * dG + dB * dB)); }
/// <summary> /// The following code was decompiled by JetBrains dotTrace. /// I have subsequently made a couple of micro optimizations, /// but it otherwise is equivalent to the DrawMandelbrot code /// above. /// </summary> /// <param name="startX"></param> /// <param name="startY"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="realStart"></param> /// <param name="imaginaryStart"></param> /// <param name="maxIterations"></param> /// <param name="realScale"></param> /// <param name="imaginaryScale"></param> /// <param name="scan"></param> /// <param name="palette"></param> /// <param name="gradient"></param> /// <param name="image"></param> /// <param name="colors"></param> /// <param name="bailoutSquared"></param> /// <param name="halfOverLogBailout"></param> /// <param name="logBase"></param> /// <param name="logMinIterations"></param> /// <param name="root"></param> /// <param name="rootMinIterations"></param> /// <param name="indexScale"></param> /// <param name="indexWeight"></param> /// <param name="useSqrt"></param> /// <param name="maxIterationColor"></param> private static void DrawMandelbrotDC( int startX, int startY, int width, int height, double realStart, double imaginaryStart, int maxIterations, double realScale, double imaginaryScale, int scan, RgbValue[] palette, Gradient gradient, byte[] image, int colors, double bailoutSquared, double halfOverLogBailout, double logBase, double logMinIterations, double root, double rootMinIterations, double indexScale, double indexWeight, bool useSqrt, Color maxIterationColor) { for (int index1 = 0; index1 < height; ++index1) { for (int index2 = 0; index2 < width; ++index2) { double num1 = 0.0; double num2 = 0.0; double num3 = 0.0; double num4 = 0.0; double d = 0.0; double num5 = (double)index2 * realScale + realStart; double num6 = (double)index1 * imaginaryScale + imaginaryStart; int num7; double num1num1 = 0.0; double num3num3 = 0.0; for (num7 = 0; d < bailoutSquared && num7 < maxIterations; ++num7) { double num8 = num1num1 - num3num3 + num5; double num9 = 2.0 * num1 * num3 + num6; double num10 = num8 - num1; double num11 = num9 - num3; if (num10 * num10 < 1E-20 && num11 * num11 < 1E-20) { num7 = maxIterations; break; } double num12 = num8 - num2; double num13 = num9 - num4; if (num12 * num12 < 1E-20 && num13 * num13 < 1E-20) { num7 = maxIterations; break; } num2 = num1; num4 = num3; num1 = num8; num3 = num9; num1num1 = num1 * num1; num3num3 = num3 * num3; d = num1num1 + num3num3; // save num1*num1, num3*num3, used above } double num14 = Math.Log(Math.Log(d) * halfOverLogBailout) * Mandelbrot.OneOverLog2; double num15 = indexScale * ((double)(num7 + 1) - indexWeight * num14); if (useSqrt) { num15 = Math.Sqrt(num15) - rootMinIterations; } else if (gradient.RootIndex) { num15 = Math.Pow(num15, root) - rootMinIterations; } if (gradient.LogIndex) { num15 = Math.Log(num15, logBase) - logMinIterations; } double index3 = MathUtilities.NormalizeIndex(num15, colors); int index4 = MathUtilities.PreparePaletteIndex(index3, colors, gradient); byte num16; byte num17; byte num18; if (num7 >= maxIterations) { num16 = maxIterationColor.R; num17 = maxIterationColor.G; num18 = maxIterationColor.B; } else { RgbValue rgbValue = RgbValue.LerpColors(palette[index4], palette[(index4 + 1) % colors], index3 - (double)(long)index3); num16 = (byte)rgbValue.red; num17 = (byte)rgbValue.green; num18 = (byte)rgbValue.blue; } int index5 = 3 * ((startY + index1) * scan + (startX + index2)); image[index5] = num18; image[index5 + 1] = num17; image[index5 + 2] = num16; } } }
/// <summary> /// </summary> /// <param name="startX"></param> /// <param name="startY"></param> /// <param name="width"></param> /// <param name="height"></param> /// <param name="realStart"></param> /// <param name="imaginaryStart"></param> /// <param name="maxIterations"></param> /// <param name="realScale"></param> /// <param name="imaginaryScale"></param> /// <param name="scan"></param> /// <param name="palette"></param> /// <param name="gradient"></param> /// <param name="image"></param> /// <param name="colors"></param> /// <param name="bailoutSquared"></param> /// <param name="halfOverLogBailout"></param> /// <param name="logBase"></param> /// <param name="logMinIterations"></param> /// <param name="root"></param> /// <param name="rootMinIterations"></param> /// <param name="indexScale"></param> /// <param name="indexWeight"></param> /// <param name="useSqrt"></param> /// <param name="maxIterationColor"></param> private static void DrawMandelbrot( int startX, int startY, int width, int height, double realStart, double imaginaryStart, int maxIterations, double realScale, double imaginaryScale, int scan, RgbValue[] palette, Gradient gradient, byte[] image, int colors, double bailoutSquared, double halfOverLogBailout, double logBase, double logMinIterations, double root, double rootMinIterations, double indexScale, double indexWeight, bool useSqrt, Color maxIterationColor) { for (var py = 0; py < height; ++py) { for (var px = 0; px < width; ++px) { double x = 0.0, xp = 0.0; // x; double y = 0.0, yp = 0.0; // y; var modulusSquared = 0.0; // x * x + y * y; var x0 = px * realScale + realStart; var y0 = py * imaginaryScale + imaginaryStart; var iterations = 0; while (modulusSquared < bailoutSquared && iterations < maxIterations) { var xtemp = x * x - y * y + x0; var ytemp = 2 * x * y + y0; double dx = xtemp - x, dy = ytemp - y, dxp = xtemp - xp, dyp = ytemp - yp; if ((dx * dx < Epsilon && dy * dy < Epsilon) || (dxp * dxp < Epsilon && dyp * dyp < Epsilon)) { iterations = maxIterations; break; } xp = x; yp = y; x = xtemp; y = ytemp; modulusSquared = x * x + y * y; ++iterations; } var smoothed = Math.Log(Math.Log(modulusSquared) * halfOverLogBailout) * OneOverLog2; var index = indexScale * (iterations + 1 - indexWeight * smoothed); if (useSqrt) { index = Math.Sqrt(index) - rootMinIterations; } else if (gradient.RootIndex) { index = Math.Pow(index, root) - rootMinIterations; } if (gradient.LogIndex) { index = Math.Log(index, logBase) - logMinIterations; } index = MathUtilities.NormalizeIndex(index, colors); var actualIndex = MathUtilities.PreparePaletteIndex(index, colors, gradient); byte red, green, blue; if (iterations >= maxIterations) { red = maxIterationColor.R; green = maxIterationColor.G; blue = maxIterationColor.B; } else { var outval = RgbValue.LerpColors( palette[actualIndex], palette[(actualIndex + 1) % colors], index - (long)index); //Palette.Lerp( // palette[actualIndex], // palette[(actualIndex + 1) % colors], // index - (long)index, // out red, out green, out blue); red = (byte)outval.red; green = (byte)outval.green; blue = (byte)outval.blue; } var offset = BitDepthFor24BppRgb * ((startY + py) * scan + (startX + px)); image[offset] = blue; image[offset + 1] = green; image[offset + 2] = red; } } }