private static void ChaosGameThread(object P) { object[] Parameters = (object[])P; ManualResetEvent Done = (ManualResetEvent)Parameters[0]; int GameNr = (int)Parameters[1]; Variables v = (Variables)Parameters[2]; FlameFunction[] Functions = (FlameFunction[])Parameters[3]; double[] SumWeights = (double[])Parameters[4]; FlameState P2 = (FlameState)Parameters[5]; ScriptNode Node = (ScriptNode)Parameters[6]; bool Preview = (bool)Parameters[7]; double Gamma = (double)Parameters[8]; double LightFactor = (double)Parameters[9]; try { RunChaosGame(v, Functions, SumWeights, P2, Preview, Gamma, LightFactor, Node, GameNr == 0); } catch (ThreadAbortException) { Thread.ResetAbort(); } catch (Exception) { // Ignore. } finally { Done.Set(); } }
internal void Add(FlameState State) { int f1, f2; long f; int i; for (i = 0; i < this.size; i++) { f2 = State.frequency[i]; if (f2 == 0) { continue; } f1 = this.frequency[i]; if (f1 == 0) { this.frequency[i] = f2; this.reds[i] = State.reds[i]; this.greens[i] = State.greens[i]; this.blues[i] = State.blues[i]; } else { f = f1; f += f2; if (f > int.MaxValue) { this.frequency[i] = int.MaxValue; } else { this.frequency[i] = (int)f; } this.reds[i] = (f1 * this.reds[i] + f2 * State.reds[i]) / f; this.greens[i] = (f1 * this.greens[i] + f2 * State.greens[i]) / f; this.blues[i] = (f1 * this.blues[i] + f2 * State.blues[i]) / f; } } }
internal bool Operate(FlameState point, Variables Variables) { double x = point.x; double y = point.y; double x2 = this.homogeneousTransform[0] * x + this.homogeneousTransform[1] * y + this.homogeneousTransform[2]; double y2 = this.homogeneousTransform[3] * x + this.homogeneousTransform[4] * y + this.homogeneousTransform[5]; if (this.hasProjection) { double p = this.homogeneousTransform[6] * x + this.homogeneousTransform[7] * y + this.homogeneousTransform[6]; if (p == 0) { return(false); } x2 /= p; y2 /= p; } if (this.hasVariations) { double x3 = 0; double y3 = 0; double w; int i; if (this.nrVariations > 0) { for (i = 0; i < this.nrVariations; i++) { x = x2; y = y2; this.variations[i].Operate(ref x, ref y); w = this.variationWeights[i]; x3 += w * x; y3 += w * y; } } if (this.nrVariations2 > 0) { for (i = 0; i < this.nrVariations2; i++) { w = this.variation2Weights[i]; if (this.variation2IsReal[i]) { this.xv.Value = x2; this.yv.Value = y2; IElement Result = this.variations2[i].Evaluate(this.doubleParameters, Variables); if (!(Result is IVector V) || V.Dimension != 2) { throw new ScriptRuntimeException("Real-valued lambda expressions must return a vector containing 2 real-valued numbers.", this.node); } x3 += w * Expression.ToDouble(V.GetElement(0).AssociatedObjectValue); y3 += w * Expression.ToDouble(V.GetElement(1).AssociatedObjectValue); } else { this.zv.Value = new Complex(x2, y2); Complex z = Expression.ToComplex(this.variations2[i].Evaluate(this.complexParameters, Variables).AssociatedObjectValue); if (z == null) { throw new ScriptRuntimeException("Expected imaginary value as a result.", this.node); } x3 += w * z.Real; y3 += w * z.Imaginary; } } } point.x = x3; point.y = y3; } else { point.x = x2; point.y = y2; } if (!this.isTransparent) { switch (point.ColorMode) { case ColorMode.Rgba: point.red = (point.red + this.red) * 0.5; point.green = (point.green + this.green) * 0.5; point.blue = (point.blue + this.blue) * 0.5; break; case ColorMode.Hsl: double d; if (this.red < point.red) // H { d = point.red - this.red; if (d < 0.5) { point.red -= d * 0.5; } else { d = 1 - d; point.red += d * 0.5; if (point.red > 1) { point.red -= 1; } } } else { d = this.red - point.red; if (d < 0.5) { point.red += d * 0.5; } else { d = 1 - d; point.red -= d * 0.5; if (point.red < 1) { point.red += 1; } } } point.green = (point.green + this.green) * 0.5; // S point.blue = (point.blue + this.blue) * 0.5; // L break; } } return(true); }
private static void RunChaosGame(Variables v, FlameFunction[] Functions, double[] SumWeights, FlameState P, bool Preview, double Gamma, double LightFactor, ScriptNode Node, bool ShowStatus) { Random Gen = new Random(); FlameFunction f; double Weight; int i, j; int c = Functions.Length; for (i = 0; i < 20; i++) { Weight = Gen.NextDouble(); j = 0; while (j < c - 1 && SumWeights[j] <= Weight) { j++; } f = Functions[j]; if (!f.Operate(P, v)) { P.N = 0; break; } } if (Preview || Node.Expression.HandlesStatus) { System.DateTime Start = System.DateTime.Now; System.DateTime NextPreview = Start.AddSeconds(1); System.DateTime PrevPreview = Start; System.DateTime Temp; System.DateTime Temp2; TimeSpan TimeLeft; int NextPreviewDeciSeconds = 10; int NrIterationsPerPreview = 4096; int Pos = NrIterationsPerPreview; long NrIterations; long PrevNrIterations = 0; long NrIterationsSinceLast; double PercentDone; double IterationsPerSeconds; do { if (Pos-- <= 0) { Pos = NrIterationsPerPreview; Temp = System.DateTime.Now; if (Temp > NextPreview) { NextPreview = Temp.AddSeconds(NextPreviewDeciSeconds * 0.1); if (NextPreviewDeciSeconds < 50) { NextPreviewDeciSeconds++; } if (Preview) { Node.Expression.Preview(new GraphBitmap(P.RenderBitmapHsl(Gamma, LightFactor, true, SKColors.Black))); Temp2 = System.DateTime.Now; double d = (Temp2 - Temp).TotalSeconds; double d2 = (Temp - PrevPreview).TotalSeconds; if (d / d2 > 0.1) { NrIterationsPerPreview <<= 1; if (NrIterationsPerPreview < 0) { NrIterationsPerPreview = int.MaxValue; } } } NrIterations = P.N0 - P.N; NrIterationsSinceLast = NrIterations - PrevNrIterations; IterationsPerSeconds = NrIterationsSinceLast / (Temp - PrevPreview).TotalSeconds; PercentDone = (100 * (1.0 - ((double)P.N) / P.N0)); TimeLeft = new TimeSpan((long)((Temp - Start).Ticks * 100 / PercentDone)); Node.Expression.Status(P.N.ToString() + " iterations left, " + NrIterations.ToString() + " iterations done, " + IterationsPerSeconds.ToString("F0") + " iterations/s, " + PercentDone.ToString("F1") + "% done, Time Left: " + TimeLeft.ToString() + "."); PrevNrIterations = NrIterations; PrevPreview = Temp; } } Weight = Gen.NextDouble(); j = 0; while (j < c - 1 && SumWeights[j] <= Weight) { j++; } f = Functions[j]; if (!f.Operate(P, v)) { break; } }while (P.IncHistogram()); Node.Expression.Status(string.Empty); } else { do { Weight = Gen.NextDouble(); j = 0; while (j < c - 1 && SumWeights[j] <= Weight) { j++; } f = Functions[j]; if (!f.Operate(P, v)) { break; } }while (P.IncHistogram()); } }
public static FractalGraph CalcFlame(double xCenter, double yCenter, double rDelta, long N, FlameFunction[] Functions, int Width, int Height, int Seed, int SuperSampling, double Gamma, double LightFactor, bool Preview, bool Parallel, Variables Variables, ScriptNode Node, FractalZoomScript FractalZoomScript, object State) { double TotWeight = 0; double Weight; int i, c = Functions.Length; Random Gen = new Random(Seed); if (c < 1) { throw new ScriptRuntimeException("At least one flame function needs to be provided.", Node); } if (SuperSampling < 1) { throw new ScriptRuntimeException("SuperSampling must be a postitive integer.", Node); } if (!Node.Expression.HandlesPreview) { Preview = false; } Array.Sort <FlameFunction>(Functions, (f1, f2) => { double d = f2.Weight - f1.Weight; if (d < 0) { return(-1); } else if (d > 0) { return(1); } else { return(0); } }); double[] SumWeights = new double[c]; FlameFunction f; for (i = 0; i < c; i++) { f = Functions[i]; Weight = f.Weight; if (Weight < 0) { throw new ScriptRuntimeException("Weights must be non-negative.", Node); } f.DefinitionDone(); TotWeight += Weight; SumWeights[i] = TotWeight; } if (TotWeight == 0) { throw new ScriptRuntimeException("The total weight of all functions must be postitive.", Node); } for (i = 0; i < c; i++) { SumWeights[i] /= TotWeight; } double AspectRatio = ((double)Width) / Height; double xMin, xMax, yMin, yMax; xMin = xCenter - rDelta / 2; xMax = xMin + rDelta; yMin = yCenter - rDelta / (2 * AspectRatio); yMax = yMin + rDelta / AspectRatio; int NrGames = Parallel ? System.Environment.ProcessorCount : 1; if (NrGames <= 1) { FlameState P = new FlameState(Gen, xMin, xMax, yMin, yMax, Width, Height, SuperSampling, N, ColorMode.Hsl, Node); Variables v = new Variables(); Variables.CopyTo(v); RunChaosGame(v, Functions, SumWeights, P, Preview, Gamma, LightFactor, Node, true); return(new FractalGraph(P.RenderBitmapHsl(Gamma, LightFactor, false, SKColors.Black), xMin, yMin, xMax, yMax, rDelta, false, Node, FractalZoomScript, State)); } else { FlameState[] P = new FlameState[NrGames]; WaitHandle[] Done = new WaitHandle[NrGames]; Thread[] T = new Thread[NrGames]; try { for (i = 0; i < NrGames; i++) { Done[i] = new ManualResetEvent(false); P[i] = new FlameState(Gen, xMin, xMax, yMin, yMax, Width, Height, SuperSampling, i < NrGames - 1 ? N / NrGames : N - (N / NrGames) * (NrGames - 1), ColorMode.Hsl, Node); Variables v = new Variables(); Variables.CopyTo(v); T[i] = new Thread(new ParameterizedThreadStart(ChaosGameThread)) { Name = "FlameFractal thread #" + (i + 1).ToString(), Priority = ThreadPriority.BelowNormal }; T[i].Start(new object[] { Done[i], i, v, Functions, SumWeights, P[i], Node, i == 0 ? Preview : false, Gamma, LightFactor }); } WaitHandle.WaitAll(Done); for (i = 1; i < NrGames; i++) { P[0].Add(P[i]); } return(new FractalGraph(P[0].RenderBitmapHsl(Gamma, LightFactor, false, SKColors.Black), xMin, yMin, xMax, yMax, rDelta, false, Node, FractalZoomScript, State)); } catch (ThreadAbortException) { for (i = 0; i < NrGames; i++) { try { if (T[i] == null) { continue; } if (Done[i] == null || !Done[i].WaitOne(0)) { T[i].Abort(); } } catch (Exception) { // Ignore } } return(null); } finally { for (i = 0; i < NrGames; i++) { try { if (Done[i] != null) { Done[i].Close(); } } catch (Exception) { // Ignore } } } } }
public static void EstimateSize(out double xCenter, out double yCenter, out double rDelta, FlameFunction[] Functions, int Width, int Height, int Seed, long N, Variables Variables, ScriptNode Node) { double TotWeight = 0; double Weight; int i, c = Functions.Length; Random Gen = new Random(Seed); if (c < 1) { throw new ScriptRuntimeException("At least one flame function needs to be provided.", Node); } double[] SumWeights = new double[c]; FlameFunction f; for (i = 0; i < c; i++) { f = Functions[i]; Weight = f.Weight; if (Weight < 0) { throw new ScriptRuntimeException("Weights must be non-negative.", Node); } f.DefinitionDone(); TotWeight += Weight; SumWeights[i] = TotWeight; } if (TotWeight == 0) { throw new ScriptRuntimeException("The total weight of all functions must be postitive.", Node); } for (i = 0; i < c; i++) { SumWeights[i] /= TotWeight; } double AspectRatio = ((double)Width) / Height; int j; double xMin, xMax, yMin, yMax; double d; FlameState P = new FlameState(Gen, -1, 1, -1, 1, Width, Height, 1, N, ColorMode.Rgba, Node); Variables v = new Variables(); Variables.CopyTo(v); for (i = 0; i < 20; i++) { Weight = Gen.NextDouble(); j = 0; while (j < c - 1 && SumWeights[j] <= Weight) { j++; } f = Functions[j]; if (!f.Operate(P, v)) { N = 0; break; } } xMin = xMax = P.x; yMin = yMax = P.y; while (N-- > 0) { Weight = Gen.NextDouble(); j = 0; while (j < c - 1 && SumWeights[j] <= Weight) { j++; } f = Functions[j]; if (!f.Operate(P, v)) { break; } d = P.x; if (d < xMin) { xMin = d; } else if (d > xMax) { xMax = d; } d = P.y; if (d < yMin) { yMin = d; } else if (d > yMax) { yMax = d; } } d = Graph.GetStepSize(xMin, xMax, 10); xMin = Math.Floor(xMin / d) * d; xMax = Math.Ceiling(xMax / d) * d; d = Graph.GetStepSize(yMin, yMax, 10); yMin = Math.Floor(yMin / d) * d; yMax = Math.Ceiling(yMax / d) * d; xCenter = (xMax + xMin) * 0.5; yCenter = (yMax + yMin) * 0.5; rDelta = xMax - xMin; d = (yMax - yMin) * AspectRatio; if (d > rDelta) { rDelta = d; } }