5using System.Threading.Tasks;
30 : base(new
ScriptNode[] { xc, yc, dr, N, FlameFunctions, Preview, Parallel, DimX, DimY, SuperSampling,
31 Gamma, LightFactor, Seed },
45 : base(new
ScriptNode[] { xc, yc, dr, N, FlameFunctions, Preview, Parallel, DimX, DimY, SuperSampling,
60 : base(new
ScriptNode[] { xc, yc, dr, N, FlameFunctions, Preview, Parallel, DimX, DimY, SuperSampling,
75 : base(new
ScriptNode[] { xc, yc, dr, N, FlameFunctions, Preview, Parallel, DimX, DimY, SuperSampling },
89 : base(new
ScriptNode[] { xc, yc, dr, N, FlameFunctions, Preview, Parallel, DimX, DimY },
102 : base(new
ScriptNode[] { xc, yc, dr, N, FlameFunctions, Preview, Parallel, DimX },
105 ArgumentType.Scalar },
115 : base(new
ScriptNode[] { xc, yc, dr, N, FlameFunctions, Preview, Parallel },
127 : base(new
ScriptNode[] { xc, yc, dr, N, FlameFunctions, Preview },
139 : base(new
ScriptNode[] { xc, yc, dr, N, FlameFunctions },
155 "xc",
"yc",
"dr",
"N",
"FlameFunctions",
"Preview",
"Parallel",
156 "DimX",
"DimY",
"SuperSampling",
"Gamma",
"LightFactor",
"Seed"
201 object Obj =
Arguments[i].AssociatedObjectValue;
202 string FunctionsExpression = this.Arguments[i++].SubExpression;
204 if (!(Obj is Array FlameArray))
205 throw new ScriptRuntimeException(
"The fifth parameter to FlameFractalHsl must be an array, containing flame definitions.",
this);
214 foreach (
object FlameItem
in FlameArray)
219 FlameFunctions.Add(CurrentFunction);
221 else if (FlameItem is SKColor || FlameItem is
string)
223 if (CurrentFunction is
null)
225 M =
new DoubleMatrix(
new double[,] { { 1, 0 }, { 0, 1 } });
227 FlameFunctions.Add(CurrentFunction);
231 cl.ToHsl(out
float H, out
float S, out
float L);
233 CurrentFunction.SetColorHsl(H, S, L);
234 CurrentFunction =
null;
238 if (CurrentFunction is
null)
240 M =
new DoubleMatrix(
new double[,] { { 1, 0 }, { 0, 1 } });
242 FlameFunctions.Add(CurrentFunction);
245 CurrentFunction.Add(FlameVariation);
249 if (CurrentFunction is
null)
251 M =
new DoubleMatrix(
new double[,] { { 1, 0 }, { 0, 1 } });
253 FlameFunctions.Add(CurrentFunction);
256 CurrentFunction.Add(LambdaExpression);
264 if (CurrentFunction is
null)
266 M =
new DoubleMatrix(
new double[,] { { 1, 0 }, { 0, 1 } });
268 FlameFunctions.Add(CurrentFunction);
271 CurrentFunction.SetWeight(Weight);
280 if (i < c &&
Arguments[i].AssociatedObjectValue is
bool Preview)
285 if (i < c &&
Arguments[i].AssociatedObjectValue is
bool Parallel)
329 throw new ScriptRuntimeException(
"Parameter mismatch in call to FlameFractalHsl(xc,yc,dr,N,FlameFunctions[,Preview[,Parallel[,dimx[,dimy[,SuperSampling[,Gamma[,LightFactor[,Seed]]]]]]]]).",
333 if (dimx <= 0 || dimx > 5000 || dimy <= 0 || dimy > 5000)
347 return await
CalcFlame(xc, yc, dr, N, Functions, dimx, dimy, Seed, SuperSampling, Gamma, LightFactor, Preview, Parallel,
Variables,
this,
348 this.FractalZoomScript,
new object[] { dimx, dimy, N, FunctionsExpression, Seed, SuperSampling, Gamma, LightFactor, Preview, Parallel });
351 private readonly
static Random gen =
new Random();
353 private string FractalZoomScript(
double r,
double i,
double Size,
object State)
355 object[] Parameters = (
object[])State;
356 int DimX = (int)Parameters[0];
357 int DimY = (int)Parameters[1];
358 long N = (long)Parameters[2];
359 string FunctionsExpression = (string)Parameters[3];
360 int Seed = (int)Parameters[4];
361 int SuperSampling = (int)Parameters[5];
362 double Gamma = (double)Parameters[6];
363 double LightFactor = (double)Parameters[7];
364 bool Preview = (bool)Parameters[8];
365 bool Parallel = (bool)Parameters[9];
367 StringBuilder sb =
new StringBuilder();
369 sb.Append(
"FlameFractalHsl(");
376 sb.Append(N.ToString());
378 sb.Append(FunctionsExpression);
384 sb.Append(DimX.ToString());
386 sb.Append(DimY.ToString());
388 sb.Append(SuperSampling.ToString());
394 sb.Append(Seed.ToString());
397 return sb.ToString();
403 public static async Task<FractalGraph>
CalcFlame(
double xCenter,
double yCenter,
double rDelta,
long N,
404 FlameFunction[] Functions,
int Width,
int Height,
int Seed,
int SuperSampling,
double Gamma,
406 FractalZoomScript FractalZoomScript,
object State)
408 double TotWeight = 0;
410 int i, c = Functions.Length;
411 Random Gen =
new Random(Seed);
416 if (SuperSampling < 1)
422 Array.Sort(Functions, (f1, f2) =>
424 double d = f2.Weight - f1.
Weight;
433 double[] SumWeights =
new double[c];
436 for (i = 0; i < c; i++)
445 SumWeights[i] = TotWeight;
451 for (i = 0; i < c; i++)
452 SumWeights[i] /= TotWeight;
454 double AspectRatio = ((double)Width) / Height;
455 double xMin, xMax, yMin, yMax;
457 xMin = xCenter - rDelta / 2;
458 xMax = xMin + rDelta;
459 yMin = yCenter - rDelta / (2 * AspectRatio);
460 yMax = yMin + rDelta / AspectRatio;
462 int NrGames = Parallel ? Environment.ProcessorCount : 1;
466 FlameState P =
new FlameState(Gen, xMin, xMax, yMin, yMax, Width, Height, SuperSampling, N, ColorMode.Hsl, Node);
470 await RunChaosGame(v, Functions, SumWeights, P, Preview, Gamma, LightFactor, Node);
472 return new FractalGraph(
Variables, P.RenderBitmapHsl(Gamma, LightFactor,
false, SKColors.Black), xMin, yMin, xMax, yMax, rDelta,
477 FlameState[] P =
new FlameState[NrGames];
478 WaitHandle[] Done =
new WaitHandle[NrGames];
479 Thread[] T =
new Thread[NrGames];
483 for (i = 0; i < NrGames; i++)
485 Done[i] =
new ManualResetEvent(
false);
486 P[i] =
new FlameState(Gen, xMin, xMax, yMin, yMax, Width, Height, SuperSampling,
487 i < NrGames - 1 ? N / NrGames : N - (N / NrGames) * (NrGames - 1),
488 ColorMode.Hsl, Node);
493 T[i] =
new Thread(
new ParameterizedThreadStart(ChaosGameThread))
495 Name =
"FlameFractal thread #" + (i + 1).
ToString(),
496 Priority = ThreadPriority.BelowNormal
499 T[i].Start(
new object[] { Done[i], i, v, Functions, SumWeights, P[i],
500 Node, i == 0 && Preview, Gamma, LightFactor });
503 WaitHandle.WaitAll(Done);
505 for (i = 1; i < NrGames; i++)
508 return new FractalGraph(
Variables, P[0].RenderBitmapHsl(Gamma, LightFactor,
false, SKColors.Black), xMin, yMin, xMax, yMax, rDelta,
511 catch (ThreadAbortException)
513 for (i = 0; i < NrGames; i++)
520 if (Done[i] is
null || !Done[i].WaitOne(0))
533 for (i = 0; i < NrGames; i++)
548 private static void ChaosGameThread(
object P)
550 object[] Parameters = (
object[])P;
551 ManualResetEvent Done = (ManualResetEvent)Parameters[0];
555 double[] SumWeights = (
double[])Parameters[4];
556 FlameState P2 = (FlameState)Parameters[5];
558 bool Preview = (bool)Parameters[7];
559 double Gamma = (double)Parameters[8];
560 double LightFactor = (double)Parameters[9];
564 RunChaosGame(v, Functions, SumWeights, P2, Preview, Gamma, LightFactor, Node).Wait();
566 catch (ThreadAbortException)
580 private static async Task RunChaosGame(
Variables v, FlameFunction[] Functions,
581 double[] SumWeights, FlameState P,
bool Preview,
double Gamma,
double LightFactor,
584 Random Gen =
new Random();
588 int c = Functions.Length;
590 for (i = 0; i < 20; i++)
592 Weight = Gen.NextDouble();
594 while (j < c - 1 && SumWeights[j] <= Weight)
598 if (!f.Operate(P, v))
607 DateTime
Start = DateTime.Now;
608 DateTime NextPreview =
Start.AddSeconds(1);
609 DateTime PrevPreview =
Start;
613 int NextPreviewDeciSeconds = 10;
614 int NrIterationsPerPreview = 4096;
615 int Pos = NrIterationsPerPreview;
617 long PrevNrIterations = 0;
618 long NrIterationsSinceLast;
620 double IterationsPerSeconds;
626 Pos = NrIterationsPerPreview;
628 if (Temp > NextPreview)
630 NextPreview = Temp.AddSeconds(NextPreviewDeciSeconds * 0.1);
631 if (NextPreviewDeciSeconds < 50)
632 NextPreviewDeciSeconds++;
638 Temp2 = DateTime.Now;
640 double d = (Temp2 - Temp).TotalSeconds;
641 double d2 = (Temp - PrevPreview).TotalSeconds;
645 NrIterationsPerPreview <<= 1;
646 if (NrIterationsPerPreview < 0)
647 NrIterationsPerPreview =
int.MaxValue;
651 NrIterations = P.N0 - P.N;
652 NrIterationsSinceLast = NrIterations - PrevNrIterations;
653 IterationsPerSeconds = NrIterationsSinceLast / (Temp - PrevPreview).TotalSeconds;
654 PercentDone = (100 * (1.0 - ((double)P.N) / P.N0));
655 TimeLeft =
new TimeSpan((
long)((Temp -
Start).Ticks * 100 / PercentDone));
656 await v.
Status(Node.
Expression, P.N.
ToString() +
" iterations left, " + NrIterations.ToString() +
" iterations done, " + IterationsPerSeconds.ToString(
"F0") +
" iterations/s, " + PercentDone.ToString(
"F1") +
"% done, Time Left: " + TimeLeft.ToString() +
".");
657 PrevNrIterations = NrIterations;
662 Weight = Gen.NextDouble();
664 while (j < c - 1 && SumWeights[j] <= Weight)
668 if (!f.Operate(P, v))
671 while (P.IncHistogram());
679 Weight = Gen.NextDouble();
681 while (j < c - 1 && SumWeights[j] <= Weight)
685 if (!f.Operate(P, v))
688 while (P.IncHistogram());
A chunked list is a linked list of chunks of objects of type T .
Script runtime exception.
Class managing a script expression.
static double ToDouble(object Object)
Converts an object to a double value.
static string ToString(double Value)
Converts a value to a string, that can be parsed as part of an expression.
Exception thrown if an image with invalid size is requested.
Defines a clickable fractal graph in the complex plane.
Calculates a flame fractal in HSL space. Intensity is mapped along the L-axis. Gamma correction is do...
static async Task< 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)
TODO
FlameFractalHsl(ScriptNode xc, ScriptNode yc, ScriptNode dr, ScriptNode N, ScriptNode FlameFunctions, ScriptNode Preview, ScriptNode Parallel, ScriptNode DimX, ScriptNode DimY, int Start, int Length, Expression Expression)
TODO
FlameFractalHsl(ScriptNode xc, ScriptNode yc, ScriptNode dr, ScriptNode N, ScriptNode FlameFunctions, ScriptNode Preview, ScriptNode Parallel, ScriptNode DimX, ScriptNode DimY, ScriptNode SuperSampling, ScriptNode Gamma, ScriptNode LightFactor, ScriptNode Seed, int Start, int Length, Expression Expression)
TODO
FlameFractalHsl(ScriptNode xc, ScriptNode yc, ScriptNode dr, ScriptNode N, ScriptNode FlameFunctions, ScriptNode Preview, ScriptNode Parallel, ScriptNode DimX, ScriptNode DimY, ScriptNode SuperSampling, int Start, int Length, Expression Expression)
TODO
FlameFractalHsl(ScriptNode xc, ScriptNode yc, ScriptNode dr, ScriptNode N, ScriptNode FlameFunctions, ScriptNode Preview, int Start, int Length, Expression Expression)
TODO
FlameFractalHsl(ScriptNode xc, ScriptNode yc, ScriptNode dr, ScriptNode N, ScriptNode FlameFunctions, ScriptNode Preview, ScriptNode Parallel, ScriptNode DimX, int Start, int Length, Expression Expression)
TODO
FlameFractalHsl(ScriptNode xc, ScriptNode yc, ScriptNode dr, ScriptNode N, ScriptNode FlameFunctions, ScriptNode Preview, ScriptNode Parallel, ScriptNode DimX, ScriptNode DimY, ScriptNode SuperSampling, ScriptNode Gamma, int Start, int Length, Expression Expression)
TODO
FlameFractalHsl(ScriptNode xc, ScriptNode yc, ScriptNode dr, ScriptNode N, ScriptNode FlameFunctions, ScriptNode Preview, ScriptNode Parallel, ScriptNode DimX, ScriptNode DimY, ScriptNode SuperSampling, ScriptNode Gamma, ScriptNode LightFactor, int Start, int Length, Expression Expression)
TODO
override IElement Evaluate(IElement[] Arguments, Variables Variables)
TODO
FlameFractalHsl(ScriptNode xc, ScriptNode yc, ScriptNode dr, ScriptNode N, ScriptNode FlameFunctions, int Start, int Length, Expression Expression)
TODO
FlameFractalHsl(ScriptNode xc, ScriptNode yc, ScriptNode dr, ScriptNode N, ScriptNode FlameFunctions, ScriptNode Preview, ScriptNode Parallel, int Start, int Length, Expression Expression)
TODO
override bool IsAsynchronous
If the node (or its decendants) include asynchronous evaluation. Asynchronous nodes should be evaluat...
override string[] DefaultArgumentNames
TODO
override async Task< IElement > EvaluateAsync(IElement[] Arguments, Variables Variables)
TODO
override string FunctionName
TODO
Calculates a flame fractal in RGBA space. Intensity is calculated along the A-axis....
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)
TODO
Handles bitmap-based graphs.
static SKColor ToColor(object Object)
Converts an object to a color.
Base class for multivariate funcions.
ScriptNode[] Arguments
Function arguments.
Base class for all nodes in a parsed script tree.
int Length
Length of expression covered by node.
override string ToString()
Expression Expression
Expression of which the node is a part.
int Start
Start position in script expression.
TextWriter ConsoleOut
Console out interface. Can be used by functions and script to output data to the console.
async Task Status(Expression Expression, string Result)
Reports current status of execution.
bool HandlesPreview
If previews are desired.
bool HandlesStatus
If status messages are desired.
void CopyTo(Variables Variables)
Copies available variables to another variable collection.
async Task Preview(Expression Expression, IElement Result)
Reports a preview of the final result.
Basic interface for all types of elements.
Base interface for lambda expressions.
delegate string FractalZoomScript(double r, double i, double Size, object State)
Generates new script when zoomed.
ArgumentType
Type of parameter used in a function definition or a lambda definition.