Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
Graph2D.cs
1using System;
2using System.Collections;
3using System.Collections.Generic;
4using System.Globalization;
5using System.Text;
6using System.Threading.Tasks;
7using System.Xml;
8using SkiaSharp;
19
20namespace Waher.Script.Graphs
21{
25 public class Graph2D : Graph
26 {
27 private LinkedList<IVector> x = new LinkedList<IVector>();
28 private LinkedList<IVector> y = new LinkedList<IVector>();
29 private readonly LinkedList<object[]> parameters = new LinkedList<object[]>();
30 private readonly LinkedList<IPainter2D> painters = new LinkedList<IPainter2D>();
31 private IElement minX, maxX;
32 private IElement minY, maxY;
33 private Type axisTypeX;
34 private Type axisTypeY;
35 private string title = string.Empty;
36 private string labelX = string.Empty;
37 private string labelY = string.Empty;
38 private bool showXAxis = true;
39 private bool showYAxis = true;
40 private bool showGrid = true;
41 private bool elementwise = false;
42 //private readonly bool showZeroX = false;
43 //private readonly bool showZeroY = false;
44
50 : this(Variables, null, null)
51 {
52 }
53
60 public Graph2D(Variables Variables, int? DefaultWidth, int? DefaultHeight)
61 : base(Variables, DefaultWidth, DefaultHeight)
62 {
63 }
64
70 : base(Settings)
71 {
72 }
73
85 public Graph2D(Variables Variables, IVector X, IVector Y, IPainter2D Painter, bool ShowZeroX, bool ShowZeroY,
86 ScriptNode Node, params object[] Parameters)
87 : base(Variables)
88 {
89 if (X is Interval XI)
90 X = new DoubleVector(XI.GetArray());
91
92 if (Y is Interval YI)
93 Y = new DoubleVector(YI.GetArray());
94
95 int i, c = X.Dimension;
96 bool HasNull = false;
97 IElement ex, ey;
98 IElement Zero;
99
100 if (c != Y.Dimension)
101 throw new ScriptException("X and Y series must be equally large.");
102
103 for (i = 0; i < c; i++)
104 {
105 ex = X.GetElement(i);
106 ey = Y.GetElement(i);
107
108 if (ex.AssociatedObjectValue is null || ey.AssociatedObjectValue is null)
109 {
110 HasNull = true;
111 break;
112 }
113 }
114
115 //this.showZeroX = ShowZeroX;
116 //this.showZeroY = ShowZeroY;
117
118 this.minX = Min.CalcMin(X, Node);
119 this.maxX = Max.CalcMax(X, Node);
120
121 if (ShowZeroX && c > 0 && this.minX.AssociatedSet is IAbelianGroup AG)
122 {
123 Zero = AG.AdditiveIdentity;
124
125 this.minX = Min.CalcMin(new ObjectVector(this.minX, Zero), null);
126 this.maxX = Max.CalcMax(new ObjectVector(this.maxX, Zero), null);
127 }
128
129 this.minY = Min.CalcMin(Y, Node);
130 this.maxY = Max.CalcMax(Y, Node);
131
132 if (ShowZeroY && c > 0 && this.minY.AssociatedSet is IAbelianGroup AG2)
133 {
134 Zero = AG2.AdditiveIdentity;
135
136 this.minY = Min.CalcMin(new ObjectVector(this.minY, Zero), null);
137 this.maxY = Max.CalcMax(new ObjectVector(this.maxY, Zero), null);
138 }
139
140 if (HasNull)
141 {
142 LinkedList<IElement> X2 = new LinkedList<IElement>();
143 LinkedList<IElement> Y2 = new LinkedList<IElement>();
144
145 this.axisTypeX = null;
146 this.axisTypeY = null;
147
148 for (i = 0; i < c; i++)
149 {
150 ex = X.GetElement(i);
151 ey = Y.GetElement(i);
152
153 if (ex.AssociatedObjectValue is null || ey.AssociatedObjectValue is null)
154 {
155 if (!(X2.First is null))
156 {
157 this.AddSegment(X, Y, X2, Y2, Node, Painter, Parameters);
158 X2 = new LinkedList<IElement>();
159 Y2 = new LinkedList<IElement>();
160 }
161 }
162 else
163 {
164 X2.AddLast(ex);
165 Y2.AddLast(ey);
166 }
167 }
168
169 if (!(X2.First is null))
170 this.AddSegment(X, Y, X2, Y2, Node, Painter, Parameters);
171 }
172 else
173 {
174 this.axisTypeX = X.GetType();
175 this.axisTypeY = Y.GetType();
176
177 if (c > 0)
178 {
179 this.x.AddLast(X);
180 this.y.AddLast(Y);
181 this.painters.AddLast(Painter);
182 this.parameters.AddLast(Parameters);
183 }
184 }
185 }
186
187 private void AddSegment(IVector X, IVector Y, ICollection<IElement> X2, ICollection<IElement> Y2,
188 ScriptNode Node, IPainter2D Painter, params object[] Parameters)
189 {
190 IVector X2V = (IVector)X.Encapsulate(X2, Node);
191 IVector Y2V = (IVector)Y.Encapsulate(Y2, Node);
192
193 if (this.axisTypeX is null)
194 {
195 this.axisTypeX = X2V.GetType();
196 this.axisTypeY = Y2V.GetType();
197 }
198 else if (X2V.GetType() != this.axisTypeX || Y2V.GetType() != this.axisTypeY)
199 throw new ScriptException("Incompatible types of series.");
200
201 this.x.AddLast(X2V);
202 this.y.AddLast(Y2V);
203 this.painters.AddLast(Painter);
204 this.parameters.AddLast(Parameters);
205 }
206
210 public LinkedList<IVector> X => this.x;
211
215 public LinkedList<IVector> Y => this.y;
216
220 public LinkedList<object[]> Parameters => this.parameters;
221
225 public IElement MinX => this.minX;
226
230 public IElement MaxX => this.maxX;
231
235 public IElement MinY => this.minY;
236
240 public IElement MaxY => this.maxY;
241
245 public bool Elementwise => this.elementwise;
246
250 public string Title
251 {
252 get => this.title;
253 set => this.title = value;
254 }
255
259 public string LabelX
260 {
261 get => this.labelX;
262 set => this.labelX = value;
263 }
264
268 public string LabelY
269 {
270 get => this.labelY;
271 set => this.labelY = value;
272 }
273
277 public bool ShowXAxis
278 {
279 get => this.showXAxis;
280 set => this.showXAxis = value;
281 }
282
286 public bool ShowYAxis
287 {
288 get => this.showYAxis;
289 set => this.showYAxis = value;
290 }
291
295 public bool ShowGrid
296 {
297 get => this.showGrid;
298 set => this.showGrid = value;
299 }
300
307 {
308 return Element.AddRight(this);
309 }
310
317 {
318 return this.AddRight(Element, false);
319 }
320
327 {
328 return Element.AddRightElementWise(this);
329 }
330
337 {
338 return this.AddRight(Element, true) as ISemiGroupElementWise;
339 }
340
348 {
349 if (this.x.First is null)
350 return Element;
351
352 if (!(Element is Graph2D G))
353 return null;
354
355 if (G.x.First is null)
356 return this;
357
358 Graph2D Result = new Graph2D(this.Settings)
359 {
360 minX = this.minX,
361 maxX = this.maxX,
362 minY = this.minY,
363 maxY = this.maxY,
364 axisTypeX = this.axisTypeX,
365 axisTypeY = this.axisTypeY,
366 title = this.title,
367 labelX = this.labelX,
368 labelY = this.labelY,
369 SameScale = this.SameScale
370 };
371
372 foreach (IVector v in this.x)
373 Result.x.AddLast(v);
374
375 foreach (IVector v in this.y)
376 Result.y.AddLast(v);
377
378 foreach (IPainter2D Painter in this.painters)
379 Result.painters.AddLast(Painter);
380
381 foreach (object[] P in this.parameters)
382 Result.parameters.AddLast(P);
383
384 if (G.axisTypeX != this.axisTypeX || G.axisTypeY != this.axisTypeY)
385 throw new ScriptException("Incompatible types of series.");
386
387 if (ElementWise)
388 {
389 GetLabels(ref Result.minX, ref Result.maxX, this.x, 2, out LabelType XLabelType);
390 GetLabels(ref Result.minY, ref Result.maxY, this.y, 2, out LabelType YLabelType);
391
392 if (XLabelType == LabelType.String && (YLabelType == LabelType.Double || YLabelType == LabelType.PhysicalQuantity))
393 ElementwiseAccumulatedAddition(ref Result.x, ref Result.y, G.x, G.y, ref Result.minX, ref Result.maxX, ref Result.minY, ref Result.maxY, G.minX, G.maxX);
394 else if (YLabelType == LabelType.String && (XLabelType == LabelType.Double || XLabelType == LabelType.PhysicalQuantity))
395 ElementwiseAccumulatedAddition(ref Result.y, ref Result.x, G.y, G.x, ref Result.minY, ref Result.maxY, ref Result.minX, ref Result.maxX, G.minY, G.maxY);
396 else
397 ElementWise = false;
398 }
399
400 if (!ElementWise)
401 {
402 foreach (IVector v in G.x)
403 Result.x.AddLast(v);
404
405 foreach (IVector v in G.y)
406 Result.y.AddLast(v);
407
408 Result.minX = Min.CalcMin((IVector)VectorDefinition.Encapsulate(new IElement[] { Result.minX, G.minX }, false, null), null);
409 Result.maxX = Max.CalcMax((IVector)VectorDefinition.Encapsulate(new IElement[] { Result.maxX, G.maxX }, false, null), null);
410 Result.minY = Min.CalcMin((IVector)VectorDefinition.Encapsulate(new IElement[] { Result.minY, G.minY }, false, null), null);
411 Result.maxY = Max.CalcMax((IVector)VectorDefinition.Encapsulate(new IElement[] { Result.maxY, G.maxY }, false, null), null);
412 }
413
414 foreach (IPainter2D Painter in G.painters)
415 Result.painters.AddLast(Painter);
416
417 foreach (object[] P in G.parameters)
418 Result.parameters.AddLast(P);
419
420 Result.showXAxis |= G.showXAxis;
421 Result.showYAxis |= G.showYAxis;
422 Result.elementwise = ElementWise;
423
424 return Result;
425 }
426
427 private static void ElementwiseAccumulatedAddition(ref LinkedList<IVector> DestFixed, ref LinkedList<IVector> DestValues,
428 LinkedList<IVector> AddFixed, LinkedList<IVector> AddValues, ref IElement MinFixed, ref IElement MaxFixed,
429 ref IElement MinValues, ref IElement MaxValues, IElement AddMinFixed, IElement AddMaxFixed)
430 {
431 Dictionary<string, IElement> Values = new Dictionary<string, IElement>();
432 IEnumerator<IVector> vX = DestFixed.GetEnumerator();
433 IEnumerator<IVector> vY = DestValues.GetEnumerator();
434 IEnumerator<IElement> eX;
435 IEnumerator<IElement> eY;
436 IVector X;
437 IVector Y;
438 LinkedList<IElement> Y2;
439
440 while (vX.MoveNext() && vY.MoveNext())
441 {
442 X = vX.Current;
443 Y = vY.Current;
444
445 eX = X.ChildElements.GetEnumerator();
446 eY = Y.ChildElements.GetEnumerator();
447
448 while (eX.MoveNext() && eY.MoveNext())
449 Values[eX.Current.AssociatedObjectValue?.ToString() ?? string.Empty] = eY.Current;
450 }
451
452 vX = AddFixed.GetEnumerator();
453 vY = AddValues.GetEnumerator();
454
455 while (vX.MoveNext() && vY.MoveNext())
456 {
457 X = vX.Current;
458 Y = vY.Current;
459 Y2 = new LinkedList<IElement>();
460
461 eX = X.ChildElements.GetEnumerator();
462 eY = Y.ChildElements.GetEnumerator();
463
464 while (eX.MoveNext() && eY.MoveNext())
465 {
466 if (Values.TryGetValue(eX.Current.AssociatedObjectValue?.ToString() ?? string.Empty, out IElement Value))
467 Y2.AddLast(Operators.Arithmetics.Add.EvaluateAddition(Value, eY.Current, null));
468 else
469 Y2.AddLast(eY.Current);
470 }
471
472 DestFixed.AddLast(X);
473 DestValues.AddLast(Y = (IVector)Y.Encapsulate(Y2, null));
474
475 MinValues = Min.CalcMin((IVector)VectorDefinition.Encapsulate(new IElement[] { MinValues, Min.CalcMin(Y, null) }, false, null), null);
476 MaxValues = Max.CalcMax((IVector)VectorDefinition.Encapsulate(new IElement[] { MaxValues, Max.CalcMax(Y, null) }, false, null), null);
477 }
478
479 MinFixed = Min.CalcMin((IVector)VectorDefinition.Encapsulate(new IElement[] { MinFixed, AddMinFixed }, false, null), null);
480 MaxFixed = Max.CalcMax((IVector)VectorDefinition.Encapsulate(new IElement[] { MaxFixed, AddMaxFixed }, false, null), null);
481
482 IVector Labels = GetLabels(ref MinFixed, ref MaxFixed, DestFixed, 2, out LabelType LabelType);
483 string[] Strings = LabelStrings(Labels, LabelType);
484 LinkedList<IVector> NormalizedX = new LinkedList<IVector>();
485 LinkedList<IVector> NormalizedY = new LinkedList<IVector>();
486 Dictionary<string, IElement> Sorted = new Dictionary<string, IElement>();
487 IElement Zero = (MinValues.AssociatedSet as Group)?.AdditiveIdentity ?? DoubleNumber.ZeroElement;
488
489 vX = DestFixed.GetEnumerator();
490 vY = DestValues.GetEnumerator();
491
492 while (vX.MoveNext() && vY.MoveNext())
493 {
494 X = vX.Current;
495 Y = vY.Current;
496 Y2 = new LinkedList<IElement>();
497
498 eX = X.ChildElements.GetEnumerator();
499 eY = Y.ChildElements.GetEnumerator();
500
501 while (eX.MoveNext() && eY.MoveNext())
502 Sorted[eX.Current.AssociatedObjectValue?.ToString() ?? string.Empty] = eY.Current;
503
504 foreach (string s in Strings)
505 {
506 if (Sorted.TryGetValue(s, out IElement E))
507 Y2.AddLast(E);
508 else
509 Y2.AddLast(Zero);
510 }
511
512 NormalizedX.AddLast(Labels);
513 NormalizedY.AddLast((IVector)Y.Encapsulate(Y2, null));
514 }
515
516 DestFixed = NormalizedX;
517 DestValues = NormalizedY;
518 }
519
521 public override bool Equals(object obj)
522 {
523 if (!(obj is Graph2D G))
524 return false;
525
526 return (
527 this.minX.Equals(G.minX) &&
528 this.maxX.Equals(G.maxX) &&
529 this.minY.Equals(G.minY) &&
530 this.maxY.Equals(G.maxY) &&
531 this.axisTypeX.Equals(G.axisTypeX) &&
532 this.axisTypeY.Equals(G.axisTypeY) &&
533 this.title.Equals(G.title) &&
534 this.labelX.Equals(G.labelX) &&
535 this.labelY.Equals(G.labelY) &&
536 this.showXAxis.Equals(G.showXAxis) &&
537 this.showYAxis.Equals(G.showYAxis) &&
538 this.showGrid.Equals(G.showGrid) &&
539 this.Equals(this.x.GetEnumerator(), G.x.GetEnumerator()) &&
540 this.Equals(this.y.GetEnumerator(), G.y.GetEnumerator()) &&
541 this.Equals(this.parameters.GetEnumerator(), G.parameters.GetEnumerator()) &&
542 this.Equals(this.painters.GetEnumerator(), G.painters.GetEnumerator()));
543 }
544
545 private bool Equals(IEnumerator e1, IEnumerator e2)
546 {
547 bool b1 = e1.MoveNext();
548 bool b2 = e2.MoveNext();
549
550 while (b1 && b2)
551 {
552 if (!e1.Current.Equals(e2.Current))
553 return false;
554
555 b1 = e1.MoveNext();
556 b2 = e2.MoveNext();
557 }
558
559 return !(b1 || b2);
560 }
561
563 public override int GetHashCode()
564 {
565 int Result = this.minX.GetHashCode();
566 Result ^= Result << 5 ^ this.maxX.GetHashCode();
567 Result ^= Result << 5 ^ this.minY.GetHashCode();
568 Result ^= Result << 5 ^ this.maxY.GetHashCode();
569 Result ^= Result << 5 ^ this.axisTypeX.GetHashCode();
570 Result ^= Result << 5 ^ this.axisTypeY.GetHashCode();
571 Result ^= Result << 5 ^ this.title.GetHashCode();
572 Result ^= Result << 5 ^ this.labelX.GetHashCode();
573 Result ^= Result << 5 ^ this.labelY.GetHashCode();
574 Result ^= Result << 5 ^ this.showXAxis.GetHashCode();
575 Result ^= Result << 5 ^ this.showYAxis.GetHashCode();
576 Result ^= Result << 5 ^ this.showGrid.GetHashCode();
577
578 foreach (IElement E in this.x)
579 Result ^= Result << 5 ^ E.GetHashCode();
580
581 foreach (IElement E in this.y)
582 Result ^= Result << 5 ^ E.GetHashCode();
583
584 foreach (object Obj in this.parameters)
585 Result ^= Result << 5 ^ Obj.GetHashCode();
586
587 foreach (IPainter2D Painter in this.painters)
588 Result ^= Result << 5 ^ Painter.GetHashCode();
589
590 return Result;
591 }
592
600 public override PixelInformation CreatePixels(GraphSettings Settings, out object[] States)
601 {
602 using (SKSurface Surface = SKSurface.Create(new SKImageInfo(Settings.Width, Settings.Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul)))
603 {
604 SKCanvas Canvas = Surface.Canvas;
605
606 States = new object[0];
607
608 Canvas.Clear(Settings.BackgroundColor);
609
610 int x1, y1, x2, y2, x3, y3, w, h;
611
612 x1 = Settings.MarginLeft;
613 x2 = Settings.Width - Settings.MarginRight;
614 y1 = Settings.MarginTop;
615 y2 = Settings.Height - Settings.MarginBottom;
616
617 if (!string.IsNullOrEmpty(this.labelY))
618 x1 += (int)(Settings.LabelFontSize * 2 + 0.5);
619
620 if (!string.IsNullOrEmpty(this.labelX))
621 y2 -= (int)(Settings.LabelFontSize * 2 + 0.5);
622
623 if (!string.IsNullOrEmpty(this.title))
624 y1 += (int)(Settings.LabelFontSize * 2 + 0.5);
625
626 IVector YLabels = GetLabels(ref this.minY, ref this.maxY, this.y, Settings.ApproxNrLabelsY, out LabelType YLabelType);
627 string[] YLabelStrings = LabelStrings(YLabels, YLabelType);
628 SKPaint Font = new SKPaint()
629 {
630 FilterQuality = SKFilterQuality.High,
631 HintingLevel = SKPaintHinting.Full,
632 SubpixelText = true,
633 IsAntialias = true,
634 Style = SKPaintStyle.Fill,
635 Color = Settings.AxisColor,
636 Typeface = SKTypeface.FromFamilyName(Settings.FontName, SKFontStyle.Normal),
637 TextSize = (float)Settings.LabelFontSize
638 };
639 SKRect Bounds = new SKRect();
640 float Size;
641 double MaxSize = 0;
642
643 if (this.showYAxis)
644 {
645 foreach (IElement Label in YLabels.ChildElements)
646 {
647 Font.MeasureText(LabelString(Label, YLabelType), ref Bounds);
648 Size = Bounds.Width;
649 if (Size > MaxSize)
650 MaxSize = Size;
651 }
652 }
653
654 x3 = (int)Math.Ceiling(x1 + MaxSize) + Settings.MarginLabel;
655
656 IVector XLabels = GetLabels(ref this.minX, ref this.maxX, this.x, Settings.ApproxNrLabelsX, out LabelType XLabelType);
657 string[] XLabelStrings = LabelStrings(XLabels, XLabelType);
658 MaxSize = 0;
659
660 if (this.showXAxis)
661 {
662 foreach (IElement Label in XLabels.ChildElements)
663 {
664 Font.MeasureText(LabelString(Label, XLabelType), ref Bounds);
665 Size = Bounds.Height;
666 if (Size > MaxSize)
667 MaxSize = Size;
668 }
669 }
670
671 y3 = (int)Math.Floor(y2 - MaxSize) - Settings.MarginLabel;
672 w = x2 - x3;
673 h = y3 - y1;
674
675 SKPaint AxisBrush = new SKPaint()
676 {
677 FilterQuality = SKFilterQuality.High,
678 IsAntialias = true,
679 Style = SKPaintStyle.Fill,
680 Color = Settings.AxisColor
681 };
682 SKPaint GridBrush = new SKPaint()
683 {
684 FilterQuality = SKFilterQuality.High,
685 IsAntialias = true,
686 Style = SKPaintStyle.Fill,
687 Color = Settings.GridColor
688 };
689 SKPaint AxisPen = new SKPaint()
690 {
691 FilterQuality = SKFilterQuality.High,
692 IsAntialias = true,
693 Style = SKPaintStyle.Stroke,
694 Color = Settings.AxisColor,
695 StrokeWidth = Settings.AxisWidth
696 };
697 SKPaint GridPen = new SKPaint()
698 {
699 FilterQuality = SKFilterQuality.High,
700 IsAntialias = true,
701 Style = SKPaintStyle.Stroke,
702 Color = Settings.GridColor,
703 StrokeWidth = Settings.GridWidth
704 };
705
706 if (this.SameScale &&
707 this.minX.AssociatedObjectValue is double MinX &&
708 this.maxX.AssociatedObjectValue is double MaxX &&
709 this.minY.AssociatedObjectValue is double MinY &&
710 this.maxY.AssociatedObjectValue is double MaxY)
711 {
712 double DX = MaxX - MinX;
713 double DY = MaxY - MinY;
714 double SX = w / (DX == 0 ? 1 : DX);
715 double SY = h / (DY == 0 ? 1 : DY);
716
717 if (SX < SY)
718 {
719 int h2 = (int)(h * SX / SY + 0.5);
720 y3 -= (h - h2) / 2;
721 h = h2;
722 }
723 else if (SY < SX)
724 {
725 int w2 = (int)(w * SY / SX + 0.5);
726 x3 += (w - w2) / 2;
727 w = w2;
728 }
729 }
730
731 double OrigoX;
732 double OrigoY;
733
734 if (this.minX.AssociatedSet is IAbelianGroup AgX)
735 OrigoX = Scale(new ObjectVector(AgX.AdditiveIdentity), this.minX, this.maxX, x3, w, null)[0];
736 else
737 OrigoX = 0;
738
739 if (this.minY.AssociatedSet is IAbelianGroup AgY)
740 OrigoY = Scale(new ObjectVector(AgY.AdditiveIdentity), this.minY, this.maxY, y3, -h, null)[0];
741 else
742 OrigoY = 0;
743
744 DrawingArea DrawingArea = new DrawingArea(this.minX, this.maxX, this.minY, this.maxY, x3, y3, w, -h, (float)OrigoX, (float)OrigoY, this.elementwise);
745 double[] LabelYY = DrawingArea.ScaleY(YLabels);
746 Dictionary<string, double> YLabelPositions = YLabelType == LabelType.String ? new Dictionary<string, double>() : null;
747 int i = 0;
748 float f;
749 double d;
750 string s;
751
752 foreach (IElement Label in YLabels.ChildElements)
753 {
754 s = YLabelStrings[i];
755 Font.MeasureText(s, ref Bounds);
756 d = LabelYY[i++];
757 f = (float)d;
758
759 if (!(YLabelPositions is null))
760 YLabelPositions[s] = d;
761
762 if (this.showGrid)
763 {
764 if (Label.AssociatedObjectValue is double Lbl && Lbl == 0)
765 Canvas.DrawLine(x3, f, x2, f, AxisPen);
766 else
767 Canvas.DrawLine(x3, f, x2, f, GridPen);
768 }
769
770 if (this.showYAxis)
771 {
772 f += Bounds.Height * 0.5f;
773 Canvas.DrawText(s, x3 - Bounds.Width - Settings.MarginLabel, f, Font);
774 }
775 }
776
777 double[] LabelXX = DrawingArea.ScaleX(XLabels);
778 Dictionary<string, double> XLabelPositions = XLabelType == LabelType.String ? new Dictionary<string, double>() : null;
779 i = 0;
780
781 foreach (IElement Label in XLabels.ChildElements)
782 {
783 s = XLabelStrings[i];
784 Font.MeasureText(s, ref Bounds);
785 d = LabelXX[i++];
786 f = (float)d;
787
788 if (!(XLabelPositions is null))
789 XLabelPositions[s] = d;
790
791 if (this.showGrid)
792 {
793 if (Label.AssociatedObjectValue is double DLbl && DLbl == 0)
794 Canvas.DrawLine(f, y1, f, y3, AxisPen);
795 else
796 Canvas.DrawLine(f, y1, f, y3, GridPen);
797 }
798
799 if (this.showXAxis)
800 {
801 Size = Bounds.Width;
802 f -= Size * 0.5f;
803 if (f < x3)
804 f = x3;
805 else if (f + Size > x3 + w)
806 f = x3 + w - Size;
807
808 Canvas.DrawText(s, f, y3 + Settings.MarginLabel + (float)Settings.LabelFontSize, Font);
809 }
810 }
811
812 DrawingArea.XLabelPositions = XLabelPositions;
813 DrawingArea.YLabelPositions = YLabelPositions;
814
815 Font.Dispose();
816 Font = null;
817
818 Font = new SKPaint()
819 {
820 FilterQuality = SKFilterQuality.High,
821 HintingLevel = SKPaintHinting.Full,
822 SubpixelText = true,
823 IsAntialias = true,
824 Style = SKPaintStyle.Fill,
825 Color = Settings.AxisColor,
826 Typeface = SKTypeface.FromFamilyName(Settings.FontName, SKFontStyle.Bold),
827 TextSize = (float)(Settings.LabelFontSize * 1.5)
828 };
829
830 if (!string.IsNullOrEmpty(this.title))
831 {
832 Font.MeasureText(this.title, ref Bounds);
833 Size = Bounds.Width;
834
835 f = x3 + (x2 - x3 - Size) * 0.5f;
836
837 if (f < x3)
838 f = x3;
839 else if (f + Size > x3 + w)
840 f = x3 + w - Size;
841
842 Canvas.DrawText(this.title, f, (float)(Settings.MarginTop + 0.1 * Settings.LabelFontSize - Bounds.Top), Font);
843 }
844
845 if (!string.IsNullOrEmpty(this.labelX))
846 {
847 Font.MeasureText(this.labelX, ref Bounds);
848 Size = Bounds.Width;
849
850 f = x3 + (x2 - x3 - Size) * 0.5f;
851
852 if (f < x3)
853 f = x3;
854 else if (f + Size > x3 + w)
855 f = x3 + w - Size;
856
857 Canvas.DrawText(this.labelX, f, (float)(Settings.Height - Settings.MarginBottom - 0.1 * Settings.LabelFontSize - Bounds.Height - Bounds.Top), Font);
858 }
859
860 if (!string.IsNullOrEmpty(this.labelY))
861 {
862 Font.MeasureText(this.labelY, ref Bounds);
863 Size = Bounds.Width;
864
865 f = y3 - (y3 - y1 - Size) * 0.5f;
866
867 if (f - Size < y1)
868 f = y1 + Size;
869 else if (f > y3 + h)
870 f = y3 + h;
871
872 Canvas.Translate((float)(Settings.MarginLeft + 0.1 * Settings.LabelFontSize - Bounds.Top), f);
873 Canvas.RotateDegrees(-90);
874 Canvas.DrawText(this.labelY, 0, 0, Font);
875 Canvas.ResetMatrix();
876 }
877
878 IEnumerator<IVector> ex = this.x.GetEnumerator();
879 IEnumerator<IVector> ey = this.y.GetEnumerator();
880 IEnumerator<object[]> eParameters = this.parameters.GetEnumerator();
881 IEnumerator<IPainter2D> ePainters = this.painters.GetEnumerator();
882 SKPoint[] Points;
883 SKPoint[] PrevPoints = null;
884 object[] PrevParameters = null;
885 IPainter2D PrevPainter = null;
886
887 while (ex.MoveNext() && ey.MoveNext() && eParameters.MoveNext() && ePainters.MoveNext())
888 {
889 Points = DrawingArea.Scale(ex.Current, ey.Current);
890
891 if (!(PrevPainter is null) && ePainters.Current.GetType() == PrevPainter.GetType())
892 ePainters.Current.DrawGraph(Canvas, Points, eParameters.Current, PrevPoints, PrevParameters, DrawingArea);
893 else
894 ePainters.Current.DrawGraph(Canvas, Points, eParameters.Current, null, null, DrawingArea);
895
896 PrevPoints = Points;
897 PrevParameters = eParameters.Current;
898 PrevPainter = ePainters.Current;
899 }
900
901 using (SKImage Result = Surface.Snapshot())
902 {
903 Font?.Dispose();
904
905 AxisBrush.Dispose();
906 GridBrush.Dispose();
907 GridPen.Dispose();
908 AxisPen.Dispose();
909
910 States = new object[] { DrawingArea };
911
912 return PixelInformation.FromImage(Result);
913 }
914 }
915 }
916
924 public override string GetBitmapClickScript(double X, double Y, object[] States)
925 {
927
930
931 return "[" + X2.ToString() + "," + Y2.ToString() + "]";
932 }
933
938 public override void ExportGraph(XmlWriter Output)
939 {
940 Output.WriteStartElement("Graph2D");
941 Output.WriteAttributeString("title", this.title);
942 Output.WriteAttributeString("labelX", this.labelX);
943 Output.WriteAttributeString("labelY", this.labelY);
944 Output.WriteAttributeString("axisTypeX", this.axisTypeX?.FullName);
945 Output.WriteAttributeString("axisTypeY", this.axisTypeY?.FullName);
946 Output.WriteAttributeString("minX", ReducedXmlString(this.minX));
947 Output.WriteAttributeString("maxX", ReducedXmlString(this.maxX));
948 Output.WriteAttributeString("minY", ReducedXmlString(this.minY));
949 Output.WriteAttributeString("maxY", ReducedXmlString(this.maxY));
950 Output.WriteAttributeString("showXAxis", this.showXAxis ? "true" : "false");
951 Output.WriteAttributeString("showYAxis", this.showYAxis ? "true" : "false");
952 Output.WriteAttributeString("showGrid", this.showGrid ? "true" : "false");
953
954 Dictionary<string, string> Series = new Dictionary<string, string>();
955 string Label;
956 string s;
957 int i = 1;
958
959 foreach (IVector v in this.x)
960 {
961 s = ReducedXmlString(v);
962 if (Series.TryGetValue(s, out Label))
963 Output.WriteElementString("X", Label);
964 else
965 {
966 Label = "X" + (i++).ToString();
967 Series[s] = Label;
968 Output.WriteElementString("X", Label + ":=" + s);
969 }
970 }
971
972 i = 1;
973
974 foreach (IVector v in this.y)
975 {
976 s = ReducedXmlString(v);
977 if (Series.TryGetValue(s, out Label))
978 Output.WriteElementString("Y", Label);
979 else
980 {
981 Label = "Y" + (i++).ToString();
982 Series[s] = Label;
983 Output.WriteElementString("Y", Label + ":=" + s);
984 }
985 }
986
987 i = 1;
988
989 foreach (object[] v in this.parameters)
990 {
991 s = Expression.ToString(new ObjectVector(v));
992 if (Series.TryGetValue(s, out Label))
993 Output.WriteElementString("Parameters", Label);
994 else
995 {
996 Label = "P" + (i++).ToString();
997 Series[s] = Label;
998 Output.WriteElementString("Parameters", Label + ":=" + s);
999 }
1000 }
1001
1002 foreach (IPainter2D Painter in this.painters)
1003 Output.WriteElementString("Painter", Painter.GetType().FullName);
1004
1005 Output.WriteEndElement();
1006 }
1007
1014 public static string ReducedXmlString(double Value)
1015 {
1016 return ((float)Value).ToString().Replace(NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, ".");
1017 }
1018
1025 public static string ReducedXmlString(DoubleVector Value)
1026 {
1027 StringBuilder sb = null;
1028
1029 foreach (double d in Value.Values)
1030 {
1031 if (sb is null)
1032 sb = new StringBuilder("[");
1033 else
1034 sb.Append(',');
1035
1036 sb.Append(((float)d).ToString().Replace(NumberFormatInfo.CurrentInfo.NumberDecimalSeparator, "."));
1037 }
1038
1039 if (sb is null)
1040 return "[]";
1041 else
1042 {
1043 sb.Append(']');
1044 return sb.ToString();
1045 }
1046 }
1047
1054 public static string ReducedXmlString(DateTimeVector Value)
1055 {
1056 StringBuilder sb = null;
1057
1058 foreach (DateTime d in Value.Values)
1059 {
1060 if (sb is null)
1061 sb = new StringBuilder("DateTime([");
1062 else
1063 sb.Append(',');
1064
1065 int Year = d.Year;
1066 int Month = d.Month;
1067 int Day = d.Day;
1068 int Hour = d.Hour;
1069 int Minute = d.Minute;
1070 int Second = d.Second;
1071 int MSecond = d.Millisecond;
1072 int Mask = 0;
1073
1074 if (Month != 0)
1075 Mask |= 1;
1076
1077 if (Day != 0)
1078 Mask |= 2;
1079
1080 if (Hour != 0)
1081 Mask |= 4;
1082
1083 if (Minute != 0)
1084 Mask |= 8;
1085
1086 if (Second != 0)
1087 Mask |= 16;
1088
1089 if (MSecond != 0)
1090 Mask |= 32;
1091
1092 sb.Append('"');
1093 sb.Append(Year.ToString());
1094
1095 if (Mask > 0)
1096 {
1097 Mask >>= 1;
1098 sb.Append('-');
1099 sb.Append(Month.ToString());
1100
1101 if (Mask > 0)
1102 {
1103 Mask >>= 1;
1104 sb.Append('-');
1105 sb.Append(Day.ToString());
1106
1107 if (Mask > 0)
1108 {
1109 Mask >>= 1;
1110 sb.Append('T');
1111 sb.Append(Hour.ToString());
1112
1113 if (Mask > 0)
1114 {
1115 Mask >>= 1;
1116 sb.Append(':');
1117 sb.Append(Minute.ToString());
1118
1119 if (Mask > 0)
1120 {
1121 Mask >>= 1;
1122 sb.Append(':');
1123 sb.Append(Second.ToString());
1124
1125 if (Mask > 0)
1126 {
1127 Mask >>= 1;
1128 sb.Append('.');
1129 sb.Append(MSecond.ToString());
1130 }
1131 }
1132 }
1133 }
1134 }
1135 }
1136
1137 if (d.Kind == DateTimeKind.Utc)
1138 sb.Append('z');
1139
1140 sb.Append('"');
1141 }
1142
1143 if (sb is null)
1144 return "[]";
1145 else
1146 {
1147 sb.Append("])");
1148 return sb.ToString();
1149 }
1150 }
1151
1158 public static string ReducedXmlStringTimeSpans(ObjectVector Value)
1159 {
1160 StringBuilder sb = null;
1161
1162 foreach (IElement E in Value.Values)
1163 {
1164 if (!(E.AssociatedObjectValue is TimeSpan TS))
1165 continue;
1166
1167 if (sb is null)
1168 sb = new StringBuilder("TimeSpan([");
1169 else
1170 sb.Append(',');
1171
1172 int Days = TS.Days;
1173 int Hours = TS.Hours;
1174 int Minutes = TS.Minutes;
1175 int Seconds = TS.Seconds;
1176 int MSeconds = TS.Milliseconds;
1177 int Mask = 0;
1178
1179 if (Hours != 0)
1180 Mask |= 1;
1181
1182 if (Minutes != 0)
1183 Mask |= 2;
1184
1185 if (Seconds != 0)
1186 Mask |= 4;
1187
1188 if (MSeconds != 0)
1189 Mask |= 5;
1190
1191 sb.Append('"');
1192
1193 if (Days != 0 || Mask == 0)
1194 sb.Append(Days.ToString());
1195
1196 if (Mask > 0)
1197 {
1198 Mask >>= 1;
1199
1200 if (Days != 0)
1201 sb.Append('.');
1202
1203 sb.Append(Hours.ToString());
1204
1205 if (Mask > 0)
1206 {
1207 Mask >>= 1;
1208 sb.Append(':');
1209 sb.Append(Minutes.ToString());
1210
1211 if (Mask > 0)
1212 {
1213 Mask >>= 1;
1214 sb.Append(':');
1215 sb.Append(Seconds.ToString());
1216
1217 if (Mask > 0)
1218 {
1219 Mask >>= 1;
1220 sb.Append('.');
1221 sb.Append(MSeconds.ToString());
1222 }
1223 }
1224 }
1225 }
1226
1227 sb.Append('"');
1228 }
1229
1230 if (sb is null)
1231 return "[]";
1232 else
1233 {
1234 sb.Append("])");
1235 return sb.ToString();
1236 }
1237 }
1238
1245 public static string ReducedXmlString(IElement Value)
1246 {
1247 if (Value.AssociatedObjectValue is double N)
1248 return ReducedXmlString(N);
1249 else if (Value is DoubleVector v)
1250 return ReducedXmlString(v);
1251 else if (Value is DateTimeVector DT)
1252 return ReducedXmlString(DT);
1253 else if (Value is ObjectVector ov && IsTimeSpanVector(ov))
1254 return ReducedXmlStringTimeSpans(ov);
1255 else
1256 return Expression.ToString(Value);
1257 }
1258
1259 private static bool IsTimeSpanVector(ObjectVector v)
1260 {
1261 foreach (IElement E in v.VectorElements)
1262 {
1263 if (!(E.AssociatedObjectValue is TimeSpan))
1264 return false;
1265 }
1266
1267 return true;
1268 }
1269
1274 public override async Task ImportGraphAsync(XmlElement Xml)
1275 {
1277
1278 foreach (XmlAttribute Attr in Xml.Attributes)
1279 {
1280 switch (Attr.Name)
1281 {
1282 case "title":
1283 this.title = Attr.Value;
1284 break;
1285
1286 case "labelX":
1287 this.labelX = Attr.Value;
1288 break;
1289
1290 case "labelY":
1291 this.labelY = Attr.Value;
1292 break;
1293
1294 case "axisTypeX":
1295 this.axisTypeX = Types.GetType(Attr.Value);
1296 break;
1297
1298 case "axisTypeY":
1299 this.axisTypeY = Types.GetType(Attr.Value);
1300 break;
1301
1302 case "minX":
1303 this.minX = await ParseAsync(Attr.Value, Variables);
1304 break;
1305
1306 case "maxX":
1307 this.maxX = await ParseAsync(Attr.Value, Variables);
1308 break;
1309
1310 case "minY":
1311 this.minY = await ParseAsync(Attr.Value, Variables);
1312 break;
1313
1314 case "maxY":
1315 this.maxY = await ParseAsync(Attr.Value, Variables);
1316 break;
1317
1318 case "showXAxis":
1319 this.showXAxis = Attr.Value == "true";
1320 break;
1321
1322 case "showYAxis":
1323 this.showYAxis = Attr.Value == "true";
1324 break;
1325
1326 case "showGrid":
1327 this.showGrid = Attr.Value == "true";
1328 break;
1329 }
1330 }
1331
1332 foreach (XmlNode N in Xml.ChildNodes)
1333 {
1334 if (N is XmlElement E)
1335 {
1336 switch (E.LocalName)
1337 {
1338 case "X":
1339 this.x.AddLast((IVector)await ParseAsync(E.InnerText, Variables));
1340 break;
1341
1342 case "Y":
1343 this.y.AddLast((IVector)await ParseAsync(E.InnerText, Variables));
1344 break;
1345
1346 case "Parameters":
1347 IVector v = (IVector)await ParseAsync(E.InnerText, Variables);
1348 this.parameters.AddLast(this.ToObjectArray(v));
1349 break;
1350
1351 case "Painter":
1352 this.painters.AddLast((IPainter2D)Activator.CreateInstance(Types.GetType(E.InnerText)));
1353 break;
1354 }
1355 }
1356 }
1357 }
1358
1362 public override bool UsesDefaultColor
1363 {
1364 get
1365 {
1366 IEnumerator<object[]> eParameters = this.parameters.GetEnumerator();
1367 IEnumerator<IPainter2D> ePainter = this.painters.GetEnumerator();
1368
1369 while (eParameters.MoveNext() && ePainter.MoveNext())
1370 {
1371 if (!ePainter.Current.UsesDefaultColor(eParameters.Current))
1372 return false;
1373 }
1374
1375 return true;
1376 }
1377 }
1378
1384 public override bool TrySetDefaultColor(SKColor Color)
1385 {
1386 if (!this.UsesDefaultColor)
1387 return false;
1388
1389 IEnumerator<object[]> eParameters = this.parameters.GetEnumerator();
1390 IEnumerator<IPainter2D> ePainter = this.painters.GetEnumerator();
1391 bool Result = true;
1392
1393 while (eParameters.MoveNext() && ePainter.MoveNext())
1394 {
1395 if (!ePainter.Current.TrySetDefaultColor(Color, eParameters.Current))
1396 Result = false;
1397 }
1398
1399 return Result;
1400 }
1401
1402 }
1403}
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:14
static Type GetType(string FullName)
Gets a type, given its full name.
Definition: Types.cs:41
Base class for all types of elements.
Definition: Element.cs:13
Element()
Base class for all types of elements.
Definition: Element.cs:17
virtual ICollection< IElement > VectorElements
An enumeration of vector elements.
Base class for all types of groups.
Definition: Group.cs:10
Base class for script exceptions.
Class managing a script expression.
Definition: Expression.cs:39
static string ToString(double Value)
Converts a value to a string, that can be parsed as part of an expression.
Definition: Expression.cs:4496
static double CalcMax(double[] Values, ScriptNode Node)
Returns the largest value.
Definition: Max.cs:54
static double CalcMin(double[] Values, ScriptNode Node)
Returns the smallest value.
Definition: Min.cs:54
Contains information about the current drawing area.
Definition: DrawingArea.cs:12
IElement DescaleY(double Value)
Descales a scaled value along the Y-axis.
Definition: DrawingArea.cs:174
SKPoint[] Scale(IVector VectorX, IVector VectorY)
Scales two vectors of equal size to points in a rectangular area.
Definition: DrawingArea.cs:135
IElement DescaleX(double Value)
Descales a scaled value along the X-axis.
Definition: DrawingArea.cs:165
double[] ScaleX(IVector Vector)
Scales a vector to fit a given area.
Definition: DrawingArea.cs:146
double[] ScaleY(IVector Vector)
Scales a vector to fit a given area.
Definition: DrawingArea.cs:155
Handles two-dimensional graphs.
Definition: Graph2D.cs:26
override ISemiGroupElementWise AddRightElementWise(ISemiGroupElementWise Element)
Tries to add an element to the current element, from the right, element-wise.
Definition: Graph2D.cs:336
IElement MinX
Smallest X-value.
Definition: Graph2D.cs:225
static string ReducedXmlString(double Value)
Generates an XML value string of an element, possible with reduced resolution, to avoid unnecessary d...
Definition: Graph2D.cs:1014
ISemiGroupElement AddRight(ISemiGroupElement Element, bool ElementWise)
Tries to add an element to the current element, from the right.
Definition: Graph2D.cs:347
string Title
Title for graph.
Definition: Graph2D.cs:251
bool ShowXAxis
If the X-axis is to be displayed.
Definition: Graph2D.cs:278
override void ExportGraph(XmlWriter Output)
Exports graph specifics to XML.
Definition: Graph2D.cs:938
bool ShowYAxis
If the Y-axis is to be displayed.
Definition: Graph2D.cs:287
override ISemiGroupElement AddLeft(ISemiGroupElement Element)
Tries to add an element to the current element, from the left.
Definition: Graph2D.cs:306
static string ReducedXmlStringTimeSpans(ObjectVector Value)
Generates an XML value string of an element, possible with reduced resolution, to avoid unnecessary d...
Definition: Graph2D.cs:1158
IElement MinY
Smallest Y-value.
Definition: Graph2D.cs:235
override bool Equals(object obj)
Compares the element to another. If elements are equal.
Definition: Graph2D.cs:521
override bool UsesDefaultColor
If graph uses default color
Definition: Graph2D.cs:1363
IElement MaxX
Largest X-value.
Definition: Graph2D.cs:230
override ISemiGroupElementWise AddLeftElementWise(ISemiGroupElementWise Element)
Tries to add an element to the current element, from the left, element-wise.
Definition: Graph2D.cs:326
static string ReducedXmlString(DateTimeVector Value)
Generates an XML value string of an element, possible with reduced resolution, to avoid unnecessary d...
Definition: Graph2D.cs:1054
static string ReducedXmlString(DoubleVector Value)
Generates an XML value string of an element, possible with reduced resolution, to avoid unnecessary d...
Definition: Graph2D.cs:1025
override PixelInformation CreatePixels(GraphSettings Settings, out object[] States)
Creates a bitmap of the graph.
Definition: Graph2D.cs:600
override string GetBitmapClickScript(double X, double Y, object[] States)
Gets script corresponding to a point in a generated bitmap representation of the graph.
Definition: Graph2D.cs:924
LinkedList< object[]> Parameters
Parameters.
Definition: Graph2D.cs:220
string LabelY
Label for y-axis.
Definition: Graph2D.cs:269
override bool TrySetDefaultColor(SKColor Color)
Tries to set the default color.
Definition: Graph2D.cs:1384
Graph2D(Variables Variables, IVector X, IVector Y, IPainter2D Painter, bool ShowZeroX, bool ShowZeroY, ScriptNode Node, params object[] Parameters)
Base class for two-dimensional graphs.
Definition: Graph2D.cs:85
LinkedList< IVector > Y
Y-axis series.
Definition: Graph2D.cs:215
IElement MaxY
Largest Y-value.
Definition: Graph2D.cs:240
override int GetHashCode()
Calculates a hash code of the element. Hash code.
Definition: Graph2D.cs:563
LinkedList< IVector > X
X-axis series.
Definition: Graph2D.cs:210
override ISemiGroupElement AddRight(ISemiGroupElement Element)
Tries to add an element to the current element, from the right.
Definition: Graph2D.cs:316
Graph2D(Variables Variables, int? DefaultWidth, int? DefaultHeight)
Base class for two-dimensional graphs.
Definition: Graph2D.cs:60
Graph2D(GraphSettings Settings)
Base class for two-dimensional graphs.
Definition: Graph2D.cs:69
Graph2D(Variables Variables)
Base class for two-dimensional graphs.
Definition: Graph2D.cs:49
override async Task ImportGraphAsync(XmlElement Xml)
Imports graph specifics from XML.
Definition: Graph2D.cs:1274
static string ReducedXmlString(IElement Value)
Generates an XML value string of an element, possible with reduced resolution, to avoid unnecessary d...
Definition: Graph2D.cs:1245
bool Elementwise
If graph was generated using element-wise addition operations.
Definition: Graph2D.cs:245
bool ShowGrid
If the grid is to be displayed.
Definition: Graph2D.cs:296
string LabelX
Label for x-axis.
Definition: Graph2D.cs:260
Base class for graphs.
Definition: Graph.cs:79
bool SameScale
If the same scale should be used for all axes.
Definition: Graph.cs:170
object[] ToObjectArray(IVector v)
Gets an array of objects corresponding to the elements of a vector.
Definition: Graph.cs:1607
static string[] LabelStrings(IVector Labels, LabelType LabelType)
Converts a vector of labels to a string array.
Definition: Graph.cs:1458
static IVector GetLabels(ref IElement Min, ref IElement Max, IEnumerable< IVector > Series, int ApproxNrLabels, out LabelType LabelType)
Gets label values for a series vector.
Definition: Graph.cs:927
static SKPoint[] Scale(IVector VectorX, IVector VectorY, IElement MinX, IElement MaxX, IElement MinY, IElement MaxY, double OffsetX, double OffsetY, double Width, double Height, Dictionary< string, double > XLabelPositions, Dictionary< string, double > YLabelPositions)
Scales two vectors of equal size to points in a rectangular area.
Definition: Graph.cs:496
GraphSettings Settings
Graph settings available during creation.
Definition: Graph.cs:188
static string LabelString(IElement Label, LabelType LabelType)
Converts a label to a string.
Definition: Graph.cs:1418
static async Task< IElement > ParseAsync(string s, Variables Variables)
Parses an element expression string.
Definition: Graph.cs:1585
SKColor BackgroundColor
Background color.
int ApproxNrLabelsY
Approximate number of labels along the Y-axis.
int ApproxNrLabelsX
Approximate number of labels along the X-axis.
double LabelFontSize
Label font size
int Width
Width of graph, in pixels. (Default=640 pixels.)
int Height
Height of graph, in pixels. (Default=480 pixels.)
Contains pixel information
static PixelInformation FromImage(SKImage Image)
Gets the pixel information from an SKImage.
Base class for all nodes in a parsed script tree.
Definition: ScriptNode.cs:69
static readonly DoubleNumber ZeroElement
0
Definition: DoubleNumber.cs:16
Represents an interval.
Definition: Interval.cs:15
static IElement Encapsulate(Array Elements, bool CanEncapsulateAsMatrix, ScriptNode Node)
Encapsulates the elements of a vector.
Collection of variables.
Definition: Variables.cs:25
Basic interface for all types of elements.
Definition: IElement.cs:20
object AssociatedObjectValue
Associated object value.
Definition: IElement.cs:33
ICollection< IElement > ChildElements
An enumeration of child elements. If the element is a scalar, this property will return null.
Definition: IElement.cs:49
Basic interface for all types of semigroup elements.
Basic interface for all types of element-wise semigroup elements.
Basic interface for vectors.
Definition: IVector.cs:9
Basic interface for all types of abelian groups.
Interface for 2D graph drawing functions.
Definition: IPainter2D.cs:10
LabelType
Type of labels
Definition: Graph.cs:23