2using System.Collections.Generic;
 
    5using System.Threading.Tasks;
 
   18        private readonly SortedDictionary<float, LinkedList<PolyRec>> transparentPolygons = 
new SortedDictionary<float, LinkedList<PolyRec>>(
new BackToFront());
 
   19        private Guid 
id = Guid.NewGuid();
 
   20        private byte[] pixels;
 
   21        private float[] zBuffer;
 
   25        private Vector3[] normalBuf;
 
   26        private SKColor[] colorBuf;
 
   27        private SKColor backgroundColor;
 
   28        private Vector3 viewerPosition;
 
   29        private Matrix4x4 projectionTransformation;
 
   30        private Matrix4x4 modelTransformation;
 
   31        private Vector4 last = Vector4.Zero;
 
   34        private int overSampling;
 
   41        private float distance;
 
   70            this.Init(Width, Height, OverSampling, BackgroundColor);
 
   88            this.Init(Width, Height, OverSampling, BackgroundColor);
 
   91        private void Init(
int Width, 
int Height, 
int OverSampling, SKColor BackgroundColor)
 
   94                throw new ArgumentOutOfRangeException(
"Width must be a positive integer.", nameof(Width));
 
   97                throw new ArgumentOutOfRangeException(
"Height must be a positive integer.", nameof(Height));
 
   99            if (OverSampling <= 0)
 
  100                throw new ArgumentOutOfRangeException(
"Oversampling must be a positive integer.", nameof(OverSampling));
 
  103            this.height = Height;
 
  104            this.overSampling = OverSampling;
 
  105            this.w = Width * OverSampling;
 
  106            this.h = Height * OverSampling;
 
  107            this.wm1 = this.w - 1;
 
  108            this.hm1 = this.h - 1;
 
  109            this.cx = this.w / 2;
 
  110            this.cy = this.h / 2;
 
  111            this.backgroundColor = BackgroundColor;
 
  114            int c = this.w * this.h;
 
  116            this.pixels = 
new byte[c * 4];
 
  117            this.zBuffer = 
new float[c];
 
  118            this.xBuf = 
new float[this.w];
 
  119            this.yBuf = 
new float[this.w];
 
  120            this.zBuf = 
new float[this.w];
 
  121            this.normalBuf = 
new Vector3[this.w];
 
  122            this.colorBuf = 
new SKColor[this.w];
 
  127        private void ClearPixels()
 
  129            byte R = this.backgroundColor.Red;
 
  130            byte G = this.backgroundColor.Green;
 
  131            byte B = this.backgroundColor.Blue;
 
  132            byte A = this.backgroundColor.Alpha;
 
  133            int i, j, c = this.w * this.h;
 
  135            for (i = j = 0; i < c; i++)
 
  137                this.pixels[j++] = R;
 
  138                this.pixels[j++] = G;
 
  139                this.pixels[j++] = B;
 
  140                this.pixels[j++] = A;
 
  142                this.zBuffer[i] = 
float.MaxValue;
 
  151            this.pixels.Initialize();
 
  152            this.zBuffer.Initialize();
 
  153            this.xBuf.Initialize();
 
  154            this.yBuf.Initialize();
 
  155            this.zBuf.Initialize();
 
  156            this.normalBuf.Initialize();
 
  157            this.colorBuf.Initialize();
 
  165        private static uint ToUInt(SKColor Color)
 
  167            uint Result = Color.Alpha;
 
  169            Result |= Color.Blue;
 
  171            Result |= Color.Green;
 
  188            this.PaintTransparentPolygons();
 
  190            if (this.overSampling == 1)
 
  191                return new PixelInformationRaw(SKColorType.Rgba8888, 
this.pixels, 
this.width, 
this.height, 
this.width << 2);
 
  194                byte[] Pixels = 
new byte[this.width * this.height * 4];
 
  195                int x, y, dx, dy, p0, p, q = 0;
 
  196                int o2 = this.overSampling * this.overSampling;
 
  198                uint SumR, SumG, SumB, SumA;
 
  200                for (y = 0; y < this.height; y++)
 
  202                    for (x = 0; x < this.width; x++)
 
  204                        SumR = SumG = SumB = SumA = 0;
 
  205                        p0 = ((y * this.w) + x) * this.overSampling * 4;
 
  207                        for (dy = 0; dy < this.overSampling; dy++, p0 += this.w * 4)
 
  209                            for (dx = 0, p = p0; dx < this.overSampling; dx++)
 
  211                                SumR += this.pixels[p++];
 
  212                                SumG += this.pixels[p++];
 
  213                                SumB += this.pixels[p++];
 
  214                                SumA += this.pixels[p++];
 
  218                        Pixels[q++] = (byte)((SumR + h) / o2);
 
  219                        Pixels[q++] = (byte)((SumG + h) / o2);
 
  220                        Pixels[q++] = (byte)((SumB + h) / o2);
 
  221                        Pixels[q++] = (byte)((SumA + h) / o2);
 
  225                return new PixelInformationRaw(SKColorType.Rgba8888, Pixels, 
this.width, 
this.height, 
this.width << 2);
 
  231        #region Graph interface 
  263            get { 
return new Tuple<int, int>(this.width, this.height); }
 
  302            return this.
id.GetHashCode();
 
  316                SKColor Color = 
ToColor(Object);
 
  317                return new PhongIntensity(Color.Red, Color.Green, Color.Blue, Color.Alpha);
 
  323        #region Projection Transformations 
  331            this.viewerPosition = 
new Vector3(0, 0, 0);
 
  332            this.projectionTransformation = Matrix4x4.CreateTranslation(this.cx, this.cy, 0);
 
  333            this.projectionTransformation = Matrix4x4.CreateScale(-this.overSampling, this.overSampling, 1) * this.projectionTransformation;
 
  334            this.modelTransformation = Matrix4x4.Identity;
 
  342            get => this.projectionTransformation;
 
  343            set => this.projectionTransformation = value;
 
  352        public Matrix4x4 
Perspective(
float NearPlaneDistance, 
float FarPlaneDistance)
 
  354            if (NearPlaneDistance <= 0)
 
  355                throw new ArgumentOutOfRangeException(
"Invalid camera distance.", nameof(NearPlaneDistance));
 
  357            if (FarPlaneDistance <= NearPlaneDistance)
 
  358                throw new ArgumentOutOfRangeException(
"Invalid camera distance.", nameof(FarPlaneDistance));
 
  360            Matrix4x4 Prev = this.projectionTransformation;
 
  361            this.projectionTransformation = Matrix4x4.CreatePerspective(1, 1, NearPlaneDistance, FarPlaneDistance) * this.projectionTransformation;
 
  362            this.distance = NearPlaneDistance;
 
  363            this.viewerPosition = 
new Vector3(0, 0, -this.distance);
 
  380            Vector4 v = Vector4.Transform(Point, this.projectionTransformation);
 
  382            return new Vector3(v.X * d, v.Y * d, v.Z * d);
 
  392            return Vector3.Transform(Point, this.projectionTransformation);
 
  397        #region Model Transformations 
  404            get => this.modelTransformation;
 
  405            set => this.modelTransformation = value;
 
  415            return Vector4.Transform(Point, this.modelTransformation);
 
  425            return Vector3.Transform(Point, this.modelTransformation);
 
  435            Matrix4x4 Prev = this.modelTransformation;
 
  436            this.modelTransformation = Matrix4x4.CreateRotationX(Degrees * degToRad) * this.modelTransformation;
 
  440        private const float degToRad = (float)(Math.PI / 180);
 
  449        public Matrix4x4 
RotateX(
float Degrees, 
object CenterPoint)
 
  461        public Matrix4x4 
RotateX(
float Degrees, Vector3 CenterPoint)
 
  463            Matrix4x4 Prev = this.modelTransformation;
 
  464            this.modelTransformation = Matrix4x4.CreateRotationX(Degrees * degToRad, CenterPoint) * this.modelTransformation;
 
  475            Matrix4x4 Prev = this.modelTransformation;
 
  476            this.modelTransformation = Matrix4x4.CreateRotationY(Degrees * degToRad) * this.modelTransformation;
 
  487        public Matrix4x4 
RotateY(
float Degrees, 
object CenterPoint)
 
  499        public Matrix4x4 
RotateY(
float Degrees, Vector3 CenterPoint)
 
  501            Matrix4x4 Prev = this.modelTransformation;
 
  502            this.modelTransformation = Matrix4x4.CreateRotationY(Degrees * degToRad, CenterPoint) * this.modelTransformation;
 
  513            Matrix4x4 Prev = this.modelTransformation;
 
  514            this.modelTransformation = Matrix4x4.CreateRotationZ(Degrees * degToRad) * this.modelTransformation;
 
  525        public Matrix4x4 
RotateZ(
float Degrees, 
object CenterPoint)
 
  537        public Matrix4x4 
RotateZ(
float Degrees, Vector3 CenterPoint)
 
  539            Matrix4x4 Prev = this.modelTransformation;
 
  540            this.modelTransformation = Matrix4x4.CreateRotationZ(Degrees * degToRad, CenterPoint) * this.modelTransformation;
 
  551            Matrix4x4 Prev = this.modelTransformation;
 
  552            this.modelTransformation = Matrix4x4.CreateScale(
Scale) * this.modelTransformation;
 
  575            Matrix4x4 Prev = this.modelTransformation;
 
  576            this.modelTransformation = Matrix4x4.CreateScale(
Scale, CenterPoint) * this.modelTransformation;
 
  587        public Matrix4x4 
Scale(
float ScaleX, 
float ScaleY, 
float ScaleZ)
 
  589            Matrix4x4 Prev = this.modelTransformation;
 
  590            this.modelTransformation = Matrix4x4.CreateScale(ScaleX, ScaleY, ScaleZ) * this.modelTransformation;
 
  602        public Matrix4x4 
Scale(
float ScaleX, 
float ScaleY, 
float ScaleZ, 
object CenterPoint)
 
  604            return this.
Scale(ScaleX, ScaleY, ScaleZ, 
ToVector3(CenterPoint));
 
  615        public Matrix4x4 
Scale(
float ScaleX, 
float ScaleY, 
float ScaleZ, Vector3 CenterPoint)
 
  617            Matrix4x4 Prev = this.modelTransformation;
 
  618            this.modelTransformation = Matrix4x4.CreateScale(ScaleX, ScaleY, ScaleZ, CenterPoint) * this.modelTransformation;
 
  629            Matrix4x4 Prev = this.modelTransformation;
 
  630            this.modelTransformation = Matrix4x4.CreateTranslation(Delta) * this.modelTransformation;
 
  641        public Matrix4x4 
Translate(
float DeltaX, 
float DelayY, 
float DeltaZ)
 
  643            Matrix4x4 Prev = this.modelTransformation;
 
  644            this.modelTransformation = Matrix4x4.CreateTranslation(DeltaX, DelayY, DeltaZ) * this.modelTransformation;
 
  666        public Matrix4x4 
LookAt(
float PositionX, 
float PositionY, 
float PositionZ,
 
  667            float TargetX, 
float TargetY, 
float TargetZ, 
float UpX, 
float UpY, 
float UpZ)
 
  669            return this.
LookAt(
new Vector3(PositionX, PositionY, PositionZ),
 
  670                new Vector3(TargetX, TargetY, TargetZ), 
new Vector3(UpX, UpY, UpZ));
 
  683        public Matrix4x4 
LookAt(Vector3 Position, Vector3 Target, Vector3 Up)
 
  687            Vector3 V = Vector3.Normalize(Target - Position);           
 
  688            Vector3 U = Vector3.Normalize(Up - Vector3.Dot(V, Up) * V); 
 
  689            Vector3 R = Vector3.Cross(V, U);                            
 
  691            Matrix4x4 Prev = this.modelTransformation;
 
  692            Matrix4x4 M = 
new Matrix4x4(
 
  697            this.modelTransformation = M * this.modelTransformation;
 
  712        public void Plot(Vector4 Point, SKColor Color)
 
  714            this.
Plot(Point, ToUInt(Color));
 
  722        public void Plot(Vector4 Point, uint Color)
 
  727            Vector3 ScreenPoint = this.
Project(WorldPoint);
 
  728            if (ScreenPoint.Z >= 0)
 
  729                this.
Plot((
int)(ScreenPoint.X + 0.5f), (
int)(ScreenPoint.Y + 0.5f), WorldPoint.Z, Color);
 
  732        private void Plot(
int x, 
int y, 
float z, uint Color)
 
  734            if (x >= 0 && x < this.w && y >= 0 && y < this.h)
 
  736                int p = y * this.w + x;
 
  738                if (z >= 0 && z < this.zBuffer[p])
 
  744                    byte A = (byte)(Color >> 24);
 
  747                        this.pixels[p++] = (byte)Color;
 
  749                        this.pixels[p++] = (byte)Color;
 
  751                        this.pixels[p++] = (byte)Color;
 
  753                        this.pixels[p] = (byte)Color;
 
  757                        byte R = (byte)Color;
 
  758                        byte G = (byte)(Color >> 8);
 
  759                        byte B = (byte)(Color >> 16);
 
  760                        byte R2 = this.pixels[p++];
 
  761                        byte G2 = this.pixels[p++];
 
  762                        byte B2 = this.pixels[p++];
 
  763                        byte A2 = this.pixels[p];
 
  768                            R3 = (byte)(((R * A + R2 * (255 - A)) + 128) / 255);
 
  769                            G3 = (byte)(((G * A + G2 * (255 - A)) + 128) / 255);
 
  770                            B3 = (byte)(((B * A + B2 * (255 - A)) + 128) / 255);
 
  775                            R2 = (byte)((R2 * A2 + 128) / 255);
 
  776                            G2 = (byte)((G2 * A2 + 128) / 255);
 
  777                            B2 = (byte)((B2 * A2 + 128) / 255);
 
  779                            R3 = (byte)(((R * A + R2 * (255 - A)) + 128) / 255);
 
  780                            G3 = (byte)(((G * A + G2 * (255 - A)) + 128) / 255);
 
  781                            B3 = (byte)(((B * A + B2 * (255 - A)) + 128) / 255);
 
  782                            A3 = (byte)(255 - (((255 - A) * (255 - A2) + 128) / 255));
 
  785                        this.pixels[p--] = A3;
 
  786                        this.pixels[p--] = B3;
 
  787                        this.pixels[p--] = G3;
 
  798        private bool ClipLine(ref 
float x0, ref 
float y0, ref 
float z0,
 
  799            ref 
float x1, ref 
float y1, ref 
float z1)
 
  807            else if (x0 > this.wm1)
 
  812            else if (y0 > this.hm1)
 
  817            else if (x1 > this.wm1)
 
  822            else if (y1 > this.hm1)
 
  825            if (Mask0 == 0 && Mask1 == 0)
 
  828            if ((Mask0 & Mask1) != 0)
 
  833            if ((Mask0 & 1) != 0)
 
  835                Delta = x0 / (x1 - x0);    
 
  836                y0 -= (y1 - y0) * Delta;
 
  837                z0 -= (z1 - z0) * Delta;
 
  843                else if (y0 > this.hm1)
 
  846                if ((Mask0 & Mask1) != 0)
 
  850            if ((Mask1 & 1) != 0)
 
  852                Delta = x1 / (x0 - x1);    
 
  853                y1 -= (y0 - y1) * Delta;
 
  854                z1 -= (z0 - z1) * Delta;
 
  860                else if (y1 > this.hm1)
 
  863                if ((Mask0 & Mask1) != 0)
 
  869            if ((Mask0 & 4) != 0)
 
  871                Delta = y0 / (y1 - y0);    
 
  872                x0 -= (x1 - x0) * Delta;
 
  873                z0 -= (z1 - z0) * Delta;
 
  879                else if (x0 > this.wm1)
 
  882                if ((Mask0 & Mask1) != 0)
 
  886            if ((Mask1 & 4) != 0)
 
  888                Delta = y1 / (y0 - y1);    
 
  889                x1 -= (x0 - x1) * Delta;
 
  890                z1 -= (z0 - z1) * Delta;
 
  896                else if (x1 > this.wm1)
 
  899                if ((Mask0 & Mask1) != 0)
 
  905            if ((Mask0 & 2) != 0)
 
  907                Delta = (this.wm1 - x0) / (x1 - x0);    
 
  908                y0 += (y1 - y0) * Delta;
 
  909                z0 += (z1 - z0) * Delta;
 
  915                else if (y0 > this.hm1)
 
  918                if ((Mask0 & Mask1) != 0)
 
  922            if ((Mask1 & 2) != 0)
 
  924                Delta = (this.wm1 - x1) / (x0 - x1);    
 
  925                y1 += (y0 - y1) * Delta;
 
  926                z1 += (z0 - z1) * Delta;
 
  932                else if (y1 > this.hm1)
 
  935                if ((Mask0 & Mask1) != 0)
 
  941            if ((Mask0 & 8) != 0)
 
  943                Delta = (this.hm1 - y0) / (y1 - y0);    
 
  944                x0 += (x1 - x0) * Delta;
 
  945                z0 += (z1 - z0) * Delta;
 
  951                else if (x0 > this.wm1)
 
  954                if ((Mask0 & Mask1) != 0)
 
  958            if ((Mask1 & 8) != 0)
 
  960                Delta = (this.hm1 - y1) / (y0 - y1);    
 
  961                x1 += (x0 - x1) * Delta;
 
  962                z1 += (z0 - z1) * Delta;
 
  968                else if (x1 > this.wm1)
 
  971                if ((Mask0 & Mask1) != 0)
 
  975            return ((Mask0 | Mask1) == 0);
 
  979        private bool ClipLine(ref 
float x0, ref 
float y0,
 
  980            ref 
float rx0, ref 
float ry0, ref 
float rz0,
 
  981            ref 
float x1, ref 
float y1,
 
  982            ref 
float rx1, ref 
float ry1, ref 
float rz1)
 
  990            else if (x0 > this.wm1)
 
  995            else if (y0 > this.hm1)
 
 1000            else if (x1 > this.wm1)
 
 1005            else if (y1 > this.hm1)
 
 1008            if (Mask0 == 0 && Mask1 == 0)
 
 1011            if ((Mask0 & Mask1) != 0)
 
 1016            if ((Mask0 & 1) != 0)
 
 1018                Delta = x0 / (x1 - x0);    
 
 1019                y0 -= (y1 - y0) * Delta;
 
 1020                rx0 -= (rx1 - rx0) * Delta;
 
 1021                ry0 -= (ry1 - ry0) * Delta;
 
 1022                rz0 -= (rz1 - rz0) * Delta;
 
 1028                else if (y0 > this.hm1)
 
 1031                if ((Mask0 & Mask1) != 0)
 
 1035            if ((Mask1 & 1) != 0)
 
 1037                Delta = x1 / (x0 - x1);    
 
 1038                y1 -= (y0 - y1) * Delta;
 
 1039                rx1 -= (rx0 - rx1) * Delta;
 
 1040                ry1 -= (ry0 - ry1) * Delta;
 
 1041                rz1 -= (rz0 - rz1) * Delta;
 
 1047                else if (y1 > this.hm1)
 
 1050                if ((Mask0 & Mask1) != 0)
 
 1056            if ((Mask0 & 4) != 0)
 
 1058                Delta = y0 / (y1 - y0);    
 
 1059                x0 -= (x1 - x0) * Delta;
 
 1060                rx0 -= (rx1 - rx0) * Delta;
 
 1061                ry0 -= (ry1 - ry0) * Delta;
 
 1062                rz0 -= (rz1 - rz0) * Delta;
 
 1068                else if (x0 > this.wm1)
 
 1071                if ((Mask0 & Mask1) != 0)
 
 1075            if ((Mask1 & 4) != 0)
 
 1077                Delta = y1 / (y0 - y1);    
 
 1078                x1 -= (x0 - x1) * Delta;
 
 1079                rx1 -= (rx0 - rx1) * Delta;
 
 1080                ry1 -= (ry0 - ry1) * Delta;
 
 1081                rz1 -= (rz0 - rz1) * Delta;
 
 1087                else if (x1 > this.wm1)
 
 1090                if ((Mask0 & Mask1) != 0)
 
 1096            if ((Mask0 & 2) != 0)
 
 1098                Delta = (this.wm1 - x0) / (x1 - x0);    
 
 1099                y0 += (y1 - y0) * Delta;
 
 1100                rx0 += (rx1 - rx0) * Delta;
 
 1101                ry0 += (ry1 - ry0) * Delta;
 
 1102                rz0 += (rz1 - rz0) * Delta;
 
 1108                else if (y0 > this.hm1)
 
 1111                if ((Mask0 & Mask1) != 0)
 
 1115            if ((Mask1 & 2) != 0)
 
 1117                Delta = (this.wm1 - x1) / (x0 - x1);    
 
 1118                y1 += (y0 - y1) * Delta;
 
 1119                rx1 += (rx0 - rx1) * Delta;
 
 1120                ry1 += (ry0 - ry1) * Delta;
 
 1121                rz1 += (rz0 - rz1) * Delta;
 
 1127                else if (y1 > this.hm1)
 
 1130                if ((Mask0 & Mask1) != 0)
 
 1136            if ((Mask0 & 8) != 0)
 
 1138                Delta = (this.hm1 - y0) / (y1 - y0);    
 
 1139                x0 += (x1 - x0) * Delta;
 
 1140                rx0 += (rx1 - rx0) * Delta;
 
 1141                ry0 += (ry1 - ry0) * Delta;
 
 1142                rz0 += (rz1 - rz0) * Delta;
 
 1148                else if (x0 > this.wm1)
 
 1151                if ((Mask0 & Mask1) != 0)
 
 1155            if ((Mask1 & 8) != 0)
 
 1157                Delta = (this.hm1 - y1) / (y0 - y1);    
 
 1158                x1 += (x0 - x1) * Delta;
 
 1159                rx1 += (rx0 - rx1) * Delta;
 
 1160                ry1 += (ry0 - ry1) * Delta;
 
 1161                rz1 += (rz0 - rz1) * Delta;
 
 1167                else if (x1 > this.wm1)
 
 1170                if ((Mask0 & Mask1) != 0)
 
 1174            return ((Mask0 | Mask1) == 0);
 
 1183        public void Line(Vector4 P0, Vector4 P1, SKColor Color)
 
 1185            this.
Line(P0, P1, ToUInt(Color));
 
 1194        public void Line(Vector4 P0, Vector4 P1, uint Color)
 
 1200            Vector3 SP0 = this.
Project(WP0);
 
 1201            Vector3 SP1 = this.
Project(WP1);
 
 1216            if (this.ClipLine(ref x0, ref y0, ref z0, ref x1, ref y1, ref z1))
 
 1223                this.
Plot((
int)(x0 + 0.5f), (
int)(y0 + 0.5f), z0, Color);
 
 1225                if (Math.Abs(dy) >= Math.Abs(dx))
 
 1248                    dz = (z1 - z0) / dy;
 
 1251                    temp = 1 - (y0 - ((int)y0));
 
 1258                        this.
Plot((
int)(x0 + 0.5f), (
int)(y0 + 0.5f), z0, Color);
 
 1264                    temp = y1 - ((int)y1);
 
 1273                        this.
Plot((
int)(x0 + 0.5f), (
int)(y0 + 0.5f), z0, Color);
 
 1296                    dz = (z1 - z0) / dx;
 
 1299                    temp = 1 - (x0 - ((int)x0));
 
 1306                        this.
Plot((
int)(x0 + 0.5f), (
int)(y0 + 0.5f), z0, Color);
 
 1312                    temp = x1 - ((int)x1);
 
 1321                        this.
Plot((
int)(x0 + 0.5f), (
int)(y0 + 0.5f), z0, Color);
 
 1341        public void LineTo(Vector4 Point, SKColor Color)
 
 1343            this.
LineTo(Point, ToUInt(Color));
 
 1351        public void LineTo(Vector4 Point, uint Color)
 
 1353            this.
Line(this.last, Point, Color);
 
 1363            this.
PolyLine(Nodes, ToUInt(Color));
 
 1373            int i, c = Nodes.Length;
 
 1377            for (i = 1; i < c; i++)
 
 1378                this.
LineTo(Nodes[i], Color);
 
 1385        private void ScanLine(
 
 1386            float sx0, 
float sy0, 
float wx0, 
float wy0, 
float wz0, Vector3 N0,
 
 1387            float sx1, 
float wx1, 
float wy1, 
float wz1, Vector3 N1, 
I3DShader Shader)
 
 1413                ref sx0, ref sy0, ref wx0, ref wy0, ref wz0,
 
 1414                ref sx1, ref sy1, ref wx1, ref wy1, ref wz1))
 
 1423                    this.
Plot((
int)(sx0 + 0.5f), (
int)(sy0 + 0.5f), wz0,
 
 1424                        ToUInt(Shader.
GetColor(wx0, wy0, wz0, N0, 
this)));
 
 1428                    this.
Plot((
int)(sx1 + 0.5f), (
int)(sy1 + 0.5f), wz1,
 
 1429                        ToUInt(Shader.
GetColor(wx1, wy1, wz1, N1, 
this)));
 
 1434                int isx0 = (int)(sx0 + 0.5f);
 
 1435                int isx1 = (int)(sx1 + 0.5f);
 
 1436                float dsx = 1 / (sx1 - sx0);
 
 1437                float dwxdsx = (wx1 - wx0) * dsx;
 
 1438                float dwydsx = (wy1 - wy0) * dsx;
 
 1439                float dwzdsx = (wz1 - wz0) * dsx;
 
 1441                int p = (int)(sy0 + 0.5f) * this.w + isx0;
 
 1446                byte R2, G2, B2, A2;
 
 1447                byte R3, G3, B3, A3;
 
 1451                    Vector3 dNdsx = (N1 - N0) * dsx;
 
 1456                    this.normalBuf[i++] = N0;
 
 1468                        this.normalBuf[i++] = Vector3.Normalize(N0);
 
 1479                    this.normalBuf[i++] = N1;
 
 1488                        this.normalBuf[i++] = N0;
 
 1498                    this.normalBuf[i++] = N1;
 
 1502                Shader.
GetColors(this.xBuf, this.yBuf, this.zBuf, this.normalBuf, c, this.colorBuf, 
this);
 
 1504                for (i = 0; i < c; i++)
 
 1508                    if (wz0 > 0 && wz0 < this.zBuffer[p])
 
 1510                        this.zBuffer[p++] = wz0;
 
 1512                        cl = this.colorBuf[i];
 
 1514                        if ((A = cl.Alpha) == 255)
 
 1516                            this.pixels[p4++] = cl.Red;
 
 1517                            this.pixels[p4++] = cl.Green;
 
 1518                            this.pixels[p4++] = cl.Blue;
 
 1519                            this.pixels[p4++] = 255;
 
 1523                            R2 = this.pixels[p4++];
 
 1524                            G2 = this.pixels[p4++];
 
 1525                            B2 = this.pixels[p4++];
 
 1526                            A2 = this.pixels[p4];
 
 1530                                R3 = (byte)(((cl.Red * A + R2 * (255 - A)) + 128) / 255);
 
 1531                                G3 = (byte)(((cl.Green * A + G2 * (255 - A)) + 128) / 255);
 
 1532                                B3 = (byte)(((cl.Blue * A + B2 * (255 - A)) + 128) / 255);
 
 1537                                R2 = (byte)((R2 * A2 + 128) / 255);
 
 1538                                G2 = (byte)((G2 * A2 + 128) / 255);
 
 1539                                B2 = (byte)((B2 * A2 + 128) / 255);
 
 1541                                R3 = (byte)(((cl.Red * A + R2 * (255 - A)) + 128) / 255);
 
 1542                                G3 = (byte)(((cl.Green * A + G2 * (255 - A)) + 128) / 255);
 
 1543                                B3 = (byte)(((cl.Blue * A + B2 * (255 - A)) + 128) / 255);
 
 1544                                A3 = (byte)(255 - (((255 - A) * (255 - A2) + 128) / 255));
 
 1547                            this.pixels[p4--] = A3;
 
 1548                            this.pixels[p4--] = B3;
 
 1549                            this.pixels[p4--] = G3;
 
 1550                            this.pixels[p4] = R3;
 
 1574            if (P.W == 1 || P.W == 0)
 
 1575                return new Vector3(P.X, P.Y, P.Z);
 
 1578            return new Vector3(P.X * d, P.Y * d, P.Z * d);
 
 1588            if (Object is Vector3 Vector3)
 
 1590            else if (Object is Vector4 Vector4)
 
 1594                if (!(Object is 
double[] V))
 
 1596                    if (Object is Objects.VectorSpaces.DoubleVector V2)
 
 1606                        case 3: 
return new Vector3((
float)V[0], (
float)V[1], (
float)V[2]);
 
 1607                        case 4: 
return ToVector3(
new Vector4((
float)V[0], (
float)V[1], (
float)V[2], (
float)V[3]));
 
 1611                throw new NotSupportedException(
"Unable to convert argument to a Vector3 object instance.");
 
 1622            return new Vector4(P.X, P.Y, P.Z, 1);
 
 1632            return new Vector4(P.X, P.Y, P.Z, 0);
 
 1642        public static Vector3 
CalcNormal(Vector3 P0, Vector3 P1, Vector3 P2)
 
 1644            return Vector3.Normalize(Vector3.Cross(P1 - P0, P2 - P0));
 
 1654        public static Vector4 
CalcNormal(Vector4 P0, Vector4 P1, Vector4 P2)
 
 1659        private bool ClipTopBottom(
 
 1660            ref 
float x0, ref 
float y0,
 
 1661            ref 
float rx0, ref 
float ry0, ref 
float rz0,
 
 1662            ref 
float x1, ref 
float y1,
 
 1663            ref 
float rx1, ref 
float ry1, ref 
float rz1)
 
 1671            else if (y0 > this.hm1)
 
 1676            else if (y1 > this.hm1)
 
 1679            if (Mask0 == 0 && Mask1 == 0)
 
 1682            if ((Mask0 & Mask1) != 0)
 
 1687            if ((Mask0 & 4) != 0)
 
 1689                Delta = y0 / (y1 - y0);    
 
 1690                x0 -= (x1 - x0) * Delta;
 
 1691                rx0 -= (rx1 - rx0) * Delta;
 
 1692                ry0 -= (ry1 - ry0) * Delta;
 
 1693                rz0 -= (rz1 - rz0) * Delta;
 
 1699                else if (x0 > this.wm1)
 
 1702                if ((Mask0 & Mask1) != 0)
 
 1706            if ((Mask1 & 4) != 0)
 
 1708                Delta = y1 / (y0 - y1);    
 
 1709                x1 -= (x0 - x1) * Delta;
 
 1710                rx1 -= (rx0 - rx1) * Delta;
 
 1711                ry1 -= (ry0 - ry1) * Delta;
 
 1712                rz1 -= (rz0 - rz1) * Delta;
 
 1718                else if (x1 > this.wm1)
 
 1721                if ((Mask0 & Mask1) != 0)
 
 1727            if ((Mask0 & 8) != 0)
 
 1729                Delta = (this.hm1 - y0) / (y1 - y0);    
 
 1730                x0 += (x1 - x0) * Delta;
 
 1731                rx0 += (rx1 - rx0) * Delta;
 
 1732                ry0 += (ry1 - ry0) * Delta;
 
 1733                rz0 += (rz1 - rz0) * Delta;
 
 1739                else if (x0 > this.wm1)
 
 1742                if ((Mask0 & Mask1) != 0)
 
 1746            if ((Mask1 & 8) != 0)
 
 1748                Delta = (this.hm1 - y1) / (y0 - y1);    
 
 1749                x1 += (x0 - x1) * Delta;
 
 1750                rx1 += (rx0 - rx1) * Delta;
 
 1751                ry1 += (ry0 - ry1) * Delta;
 
 1752                rz1 += (rz0 - rz1) * Delta;
 
 1758                else if (x1 > this.wm1)
 
 1761                if ((Mask0 & Mask1) != 0)
 
 1765            return ((Mask0 | Mask1) == 0);
 
 1768        private bool ClipTopBottom(
 
 1769            ref 
float x0, ref 
float y0,
 
 1770            ref 
float rx0, ref 
float ry0, ref 
float rz0, ref Vector3 rN0,
 
 1771            ref 
float x1, ref 
float y1,
 
 1772            ref 
float rx1, ref 
float ry1, ref 
float rz1, ref Vector3 rN1)
 
 1780            else if (y0 > this.hm1)
 
 1785            else if (y1 > this.hm1)
 
 1788            if (Mask0 == 0 && Mask1 == 0)
 
 1791            if ((Mask0 & Mask1) != 0)
 
 1796            if ((Mask0 & 4) != 0)
 
 1798                Delta = y0 / (y1 - y0);    
 
 1799                x0 -= (x1 - x0) * Delta;
 
 1800                rx0 -= (rx1 - rx0) * Delta;
 
 1801                ry0 -= (ry1 - ry0) * Delta;
 
 1802                rz0 -= (rz1 - rz0) * Delta;
 
 1803                rN0 -= (rN1 - rN0) * Delta;
 
 1809                else if (x0 > this.wm1)
 
 1812                if ((Mask0 & Mask1) != 0)
 
 1816            if ((Mask1 & 4) != 0)
 
 1818                Delta = y1 / (y0 - y1);    
 
 1819                x1 -= (x0 - x1) * Delta;
 
 1820                rx1 -= (rx0 - rx1) * Delta;
 
 1821                ry1 -= (ry0 - ry1) * Delta;
 
 1822                rz1 -= (rz0 - rz1) * Delta;
 
 1823                rN1 -= (rN0 - rN1) * Delta;
 
 1829                else if (x1 > this.wm1)
 
 1832                if ((Mask0 & Mask1) != 0)
 
 1838            if ((Mask0 & 8) != 0)
 
 1840                Delta = (this.hm1 - y0) / (y1 - y0);    
 
 1841                x0 += (x1 - x0) * Delta;
 
 1842                rx0 += (rx1 - rx0) * Delta;
 
 1843                ry0 += (ry1 - ry0) * Delta;
 
 1844                rz0 += (rz1 - rz0) * Delta;
 
 1845                rN0 += (rN1 - rN0) * Delta;
 
 1851                else if (x0 > this.wm1)
 
 1854                if ((Mask0 & Mask1) != 0)
 
 1858            if ((Mask1 & 8) != 0)
 
 1860                Delta = (this.hm1 - y1) / (y0 - y1);    
 
 1861                x1 += (x0 - x1) * Delta;
 
 1862                rx1 += (rx0 - rx1) * Delta;
 
 1863                ry1 += (ry0 - ry1) * Delta;
 
 1864                rz1 += (rz0 - rz1) * Delta;
 
 1865                rN1 += (rN0 - rN1) * Delta;
 
 1871                else if (x1 > this.wm1)
 
 1874                if ((Mask0 & Mask1) != 0)
 
 1878            return ((Mask0 | Mask1) == 0);
 
 1892        public void Polygon(Vector4[] Nodes, SKColor Color, 
bool TwoSided)
 
 1909        public void Polygon(Vector4[] Nodes, Vector4[] Normals, SKColor Color, 
bool TwoSided)
 
 1911            this.
Polygons(
new Vector4[][] { Nodes }, 
new Vector4[][] { Normals }, 
new ConstantColor(Color), TwoSided);
 
 1927            this.
Polygons(
new Vector4[][] { Nodes }, 
null, Shader, TwoSided);
 
 1944            this.
Polygons(
new Vector4[][] { Nodes }, 
new Vector4[][] { Normals }, Shader, TwoSided);
 
 1958        public void Polygons(Vector4[][] Nodes, SKColor Color, 
bool TwoSided)
 
 1960            this.
Polygons(Nodes, 
null, Color, TwoSided);
 
 1975        public void Polygons(Vector4[][] Nodes, Vector4[][] Normals, SKColor Color, 
bool TwoSided)
 
 1993            this.
Polygons(Nodes, 
null, Shader, TwoSided);
 
 2010            this.
Polygons(Nodes, Normals, Shader, TwoSided ? Shader : 
null);
 
 2021            this.
Polygons(Nodes, 
null, FrontShader, BackShader);
 
 2041            Vector4[] v, n = 
null;
 
 2042            Vector3[] vw, vs, vn;
 
 2044            bool InterpolateNormals = !(Normals is 
null);
 
 2046            NrPolygons = Nodes.Length;
 
 2049            Vector3[][] World = 
new Vector3[NrPolygons][];
 
 2050            Vector3[][] Screen = 
new Vector3[NrPolygons][];
 
 2051            Vector3[][] Normals2 = InterpolateNormals ? 
new Vector3[NrPolygons][] : 
null;
 
 2053            for (j = l = 0; j < NrPolygons; j++)
 
 2061                vw = 
new Vector3[NrNodes];
 
 2062                vs = 
new Vector3[NrNodes];
 
 2064                if (InterpolateNormals)
 
 2067                    if (n.Length != NrNodes)
 
 2068                        throw new ArgumentException(
"Number of normals do not match number of vertices.", nameof(Normals));
 
 2070                    vn = 
new Vector3[NrNodes];
 
 2073                for (i = k = 0; i < NrNodes; i++)
 
 2078                    if (k > 0 && WP3 == vw[k - 1])
 
 2081                    if (InterpolateNormals)
 
 2085                    vs[k++] = SP = this.
Project(WP);
 
 2087                    Y = (int)(SP.Y + 0.5f);
 
 2100                if (k > 1 && vw[0] == vw[k - 1])
 
 2108                    Array.Resize(ref vw, k);
 
 2109                    Array.Resize(ref vs, k);
 
 2115                if (InterpolateNormals)
 
 2130            else if (MaxY >= this.h)
 
 2133            if ((FrontShader?.Opaque ?? 
true) && (BackShader?.
Opaque ?? 
true))
 
 2135                this.DrawPolygons(World, Screen, Normals2, MinY, MaxY, NrPolygons,
 
 2136                    FrontShader, BackShader, InterpolateNormals);
 
 2142                for (j = k = 0; j < NrPolygons; j++)
 
 2145                    NrNodes = vw.Length;
 
 2147                    for (i = 0; i < NrNodes; i++)
 
 2158                    if (!this.transparentPolygons.TryGetValue(AvgZ, out LinkedList<PolyRec> PerZ))
 
 2160                        PerZ = 
new LinkedList<PolyRec>();
 
 2161                        this.transparentPolygons[AvgZ] = PerZ;
 
 2164                    PerZ.AddLast(
new PolyRec()
 
 2171                        NrPolygons = NrPolygons,
 
 2172                        FrontShader = FrontShader,
 
 2173                        BackShader = BackShader,
 
 2174                        InterpolateNormals = InterpolateNormals,
 
 2180        private void PaintTransparentPolygons()
 
 2182            foreach (LinkedList<PolyRec> List 
in this.transparentPolygons.Values)
 
 2184                foreach (PolyRec Rec 
in List)
 
 2186                    this.DrawPolygons(Rec.World, Rec.Screen, Rec.Normals, Rec.MinY, Rec.MaxY,
 
 2187                        Rec.NrPolygons, Rec.FrontShader, Rec.BackShader, Rec.InterpolateNormals);
 
 2191            this.transparentPolygons.Clear();
 
 2194        private class PolyRec
 
 2196            public Vector3[][] World;
 
 2197            public Vector3[][] Screen;
 
 2198            public Vector3[][] Normals;
 
 2201            public int NrPolygons;
 
 2202            public I3DShader FrontShader;
 
 2203            public I3DShader BackShader;
 
 2204            public bool InterpolateNormals;
 
 2207        private class BackToFront : IComparer<float>
 
 2209            public int Compare(
float x, 
float y)
 
 2211                return Math.Sign(y - x);
 
 2215        private void DrawPolygons(Vector3[][] World, Vector3[][] Screen, Vector3[][] Normals,
 
 2216            int MinY, 
int MaxY, 
int NrPolygons, I3DShader FrontShader, I3DShader BackShader, 
bool InterpolateNormals)
 
 2218            int NrRecs = MaxY - MinY + 1;
 
 2219            ScanLineRecs[] Recs2;
 
 2223            Vector3[] vw, vs, vn = 
null;
 
 2226            if (FrontShader == BackShader)
 
 2228                ScanLineRecs Temp = 
new ScanLineRecs(NrRecs);
 
 2229                Recs2 = 
new ScanLineRecs[2] { Temp, Temp };
 
 2233                Recs2 = 
new ScanLineRecs[2]
 
 2235                    FrontShader is 
null ? null : 
new ScanLineRecs(NrRecs),
 
 2236                    BackShader is 
null ? null : 
new ScanLineRecs(NrRecs),
 
 2243            Vector3 CurrentWorld;
 
 2244            Vector3 LastNormal = Vector3.Zero;
 
 2245            Vector3 CurrentNormal = Vector3.Zero;
 
 2247            Vector3 CurrentScreen;
 
 2252            float wx0, wy0, wz0;
 
 2253            float wx1, wy1, wz1;
 
 2254            float invdsy, dsxdsy;
 
 2255            float dwxdsy, dwydsy, dwzdsy;
 
 2256            Vector3 dNdsy = Vector3.Zero;
 
 2261            for (j = 0; j < NrPolygons; j++)
 
 2265                NrNodes = vw.Length;
 
 2268                CurrentWorld = vw[NrNodes - 1];
 
 2269                LastScreen = vs[NrNodes - 2];
 
 2270                CurrentScreen = vs[NrNodes - 1];
 
 2274                if (Front = (Vector3.Dot(N, 
this.viewerPosition - vw[0]) >= 0))
 
 2282                if (InterpolateNormals)
 
 2285                    LastNormal = vn[NrNodes - 2];
 
 2286                    CurrentNormal = vn[NrNodes - 1];
 
 2290                sy1 = CurrentScreen.Y;
 
 2292                isy0 = (int)(sy0 + 0.5f);
 
 2293                isy1 = (int)(sy1 + 0.5f);
 
 2295                sx1 = wx1 = wy1 = wz1 = 
default;
 
 2297                int LastDir, LastNonZeroDir = 0;
 
 2298                int Dir = Math.Sign(isy1 - isy0);
 
 2300                float MinSx, WxMinSx, WyMinSx, WzMinSx;
 
 2301                float MaxSx, WxMaxSx, WyMaxSx, WzMaxSx;
 
 2302                Vector3 NMinSx, NMaxSx;
 
 2304                MinSx = MaxSx = CurrentScreen.X;
 
 2305                WxMinSx = WxMaxSx = CurrentWorld.X;
 
 2306                WyMinSx = WyMaxSx = CurrentWorld.Y;
 
 2307                WzMinSx = WzMaxSx = CurrentWorld.Z;
 
 2308                NMinSx = NMaxSx = CurrentNormal;
 
 2310                for (i = 0; i < NrNodes; i++)
 
 2312                    LastWorld = CurrentWorld;
 
 2313                    CurrentWorld = vw[i];
 
 2315                    LastScreen = CurrentScreen;
 
 2316                    CurrentScreen = vs[i];
 
 2318                    if (InterpolateNormals)
 
 2320                        LastNormal = CurrentNormal;
 
 2321                        CurrentNormal = vn[i];
 
 2327                    sx1 = CurrentScreen.X;
 
 2328                    sy1 = CurrentScreen.Y;
 
 2334                    wx1 = CurrentWorld.X;
 
 2335                    wy1 = CurrentWorld.Y;
 
 2336                    wz1 = CurrentWorld.Z;
 
 2338                    if (InterpolateNormals)
 
 2340                        if (!this.ClipTopBottom(
 
 2341                            ref sx0, ref sy0, ref wx0, ref wy0, ref wz0, ref LastNormal,
 
 2342                            ref sx1, ref sy1, ref wx1, ref wy1, ref wz1, ref CurrentNormal))
 
 2349                        if (!this.ClipTopBottom(
 
 2350                            ref sx0, ref sy0, ref wx0, ref wy0, ref wz0,
 
 2351                            ref sx1, ref sy1, ref wx1, ref wy1, ref wz1))
 
 2357                    isy0 = (int)(sy0 + 0.5f);
 
 2358                    isy1 = (int)(sy1 + 0.5f);
 
 2362                        LastNonZeroDir = Dir;
 
 2364                    Dir = Math.Sign(isy1 - isy0);
 
 2365                    SumAbsDir += Math.Abs(Dir);
 
 2372                            WxMaxSx = CurrentWorld.X;
 
 2373                            WyMaxSx = CurrentWorld.Y;
 
 2374                            WzMaxSx = CurrentWorld.Z;
 
 2375                            NMaxSx = CurrentNormal;
 
 2377                        else if (sx1 < MinSx)
 
 2380                            WxMinSx = CurrentWorld.X;
 
 2381                            WyMinSx = CurrentWorld.Y;
 
 2382                            WzMinSx = CurrentWorld.Z;
 
 2383                            NMinSx = CurrentNormal;
 
 2389                        invdsy = 1 / (sy1 - sy0);
 
 2390                        dsxdsy = (sx1 - sx0) * invdsy;
 
 2391                        dwxdsy = (wx1 - wx0) * invdsy;
 
 2392                        dwydsy = (wy1 - wy0) * invdsy;
 
 2393                        dwzdsy = (wz1 - wz0) * invdsy;
 
 2395                        if (InterpolateNormals)
 
 2396                            dNdsy = (CurrentNormal - LastNormal) * invdsy;
 
 2400                            if (LastDir == -1 || (LastDir == 0 && LastNonZeroDir == -1))
 
 2402                                this.AddNode(Recs, MinY, sx0, isy0, wx0, wy0, wz0,
 
 2403                                    InterpolateNormals ? Vector3.Normalize(LastNormal) : N, Front, Dir);
 
 2408                            sx0 += step * dsxdsy;
 
 2409                            wx0 += step * dwxdsy;
 
 2410                            wy0 += step * dwydsy;
 
 2411                            wz0 += step * dwzdsy;
 
 2413                            if (InterpolateNormals)
 
 2414                                LastNormal += step * dNdsy;
 
 2418                                this.AddNode(Recs, MinY, sx0, isy0, wx0, wy0, wz0,
 
 2419                                    InterpolateNormals ? Vector3.Normalize(LastNormal) : N, Front, Dir);
 
 2427                                if (InterpolateNormals)
 
 2428                                    LastNormal += dNdsy;
 
 2431                            this.AddNode(Recs, MinY, sx1, isy1, wx1, wy1, wz1,
 
 2432                                InterpolateNormals ? Vector3.Normalize(CurrentNormal) : N, Front, Dir);
 
 2436                            if (LastDir == 0 && LastNonZeroDir == 1)
 
 2438                                this.AddNode(Recs, MinY, sx0, isy0, wx0, wy0, wz0,
 
 2439                                    InterpolateNormals ? Vector3.Normalize(LastNormal) : N, Front, Dir);
 
 2442                            if (Dir == LastDir || LastDir == 0)
 
 2446                                sx0 -= step * dsxdsy;
 
 2447                                wx0 -= step * dwxdsy;
 
 2448                                wy0 -= step * dwydsy;
 
 2449                                wz0 -= step * dwzdsy;
 
 2451                                if (InterpolateNormals)
 
 2452                                    LastNormal -= step * dNdsy;
 
 2457                                Vector3 CurrentNormal2 = CurrentNormal;
 
 2459                                this.AddNode(Recs, MinY, sx1, isy1, wx1, wy1, wz1,
 
 2460                                    InterpolateNormals ? Vector3.Normalize(CurrentNormal2) : N, Front, Dir);
 
 2464                                sx1 += step * dsxdsy;
 
 2465                                wx1 += step * dwxdsy;
 
 2466                                wy1 += step * dwydsy;
 
 2467                                wz1 += step * dwzdsy;
 
 2469                                if (InterpolateNormals)
 
 2470                                    CurrentNormal2 += step * dNdsy;
 
 2474                                    this.AddNode(Recs, MinY, sx1, isy1, wx1, wy1, wz1,
 
 2475                                        InterpolateNormals ? Vector3.Normalize(CurrentNormal2) : N, Front, Dir);
 
 2483                                    if (InterpolateNormals)
 
 2484                                        CurrentNormal2 += dNdsy;
 
 2487                                this.AddNode(Recs, MinY, sx0, isy0, wx0, wy0, wz0,
 
 2488                                    InterpolateNormals ? Vector3.Normalize(LastNormal) : N, Front, Dir);
 
 2492                                this.AddNode(Recs, MinY, sx1, isy1, wx1, wy1, wz1,
 
 2493                                    InterpolateNormals ? Vector3.Normalize(CurrentNormal) : N, Front, Dir);
 
 2499                if (SumAbsDir == 0 && isy1 >= MinY && isy1 <= this.hm1)
 
 2501                    this.AddNode(Recs, MinY, MinSx, isy1, WxMinSx, WyMinSx, WzMinSx,
 
 2502                        InterpolateNormals ? Vector3.Normalize(NMinSx) : N, Front, 0);
 
 2504                    this.AddNode(Recs, MinY, MaxSx, isy1, WxMaxSx, WyMaxSx, WzMaxSx,
 
 2505                        InterpolateNormals ? Vector3.Normalize(NMaxSx) : N, Front, 0);
 
 2509            for (j = 0; j < 2; j++)
 
 2515                Shader = j == 0 ? FrontShader : BackShader;
 
 2517                for (i = 0; i < NrRecs; i++)
 
 2519                    Rec = Recs.Records[i];
 
 2525                    if (!(Rec.segments is 
null))
 
 2529                        sx0 = wx0 = wy0 = wz0 = 0;
 
 2532                        foreach (ScanLineSegment Rec2 
in Rec.segments)
 
 2545                                this.ScanLine(sx0, Y, wx0, wy0, wz0, N,
 
 2546                                    Rec2.sx, Rec2.wx, Rec2.wy, Rec2.wz, Rec2.n,
 
 2555                            this.
Plot((
int)(sx0 + 0.5f), Y, wz0,
 
 2556                                ToUInt(Shader.GetColor(wx0, wy0, wz0, N, 
this)));
 
 2561                        this.ScanLine(Rec.sx0, Y, Rec.wx0, Rec.wy0, Rec.wz0, Rec.n0,
 
 2562                            Rec.sx1, Rec.wx1, Rec.wy1, Rec.wz1, Rec.n1, Shader);
 
 2566                        this.
Plot((
int)(Rec.sx0 + 0.5f), Y, Rec.wz0,
 
 2567                            ToUInt(Shader.GetColor(Rec.wx0, Rec.wy0, Rec.wz0, Rec.n0, 
this)));
 
 2571                if (FrontShader == BackShader)
 
 2576        private void AddNode(ScanLineRecs Records, 
int MinY, 
float sx, 
int isy,
 
 2577            float wx, 
float wy, 
float wz, Vector3 N, 
bool Front, 
int Dir)
 
 2580            ScanLineRec Rec = Records.Records[i];
 
 2585            if (i == Records.Last && Dir == Records.LastDir)
 
 2587                switch (Records.Coordinate)
 
 2606                        Records.LastSegment.sx = sx;
 
 2607                        Records.LastSegment.wx = wx;
 
 2608                        Records.LastSegment.wy = wy;
 
 2609                        Records.LastSegment.wz = wz;
 
 2610                        Records.LastSegment.n = N;
 
 2617                Records.LastDir = Dir;
 
 2622                Records.Records[i] = 
new ScanLineRec()
 
 2631                Records.Coordinate = 0;
 
 2647                    Records.Coordinate = 0;
 
 2656                    Records.Coordinate = 1;
 
 2663                Records.Coordinate = 2;
 
 2665                if (Rec.segments is 
null)
 
 2667                    Rec.segments = 
new LinkedList<ScanLineSegment>();
 
 2669                    Rec.segments.AddLast(
new ScanLineSegment()
 
 2678                    Rec.segments.AddLast(
new ScanLineSegment()
 
 2688                LinkedListNode<ScanLineSegment> Loop = Rec.segments.First;
 
 2689                LinkedListNode<ScanLineSegment> Prev = 
null;
 
 2691                while (!(Loop is 
null) && Loop.Value.sx < sx)
 
 2697                Records.LastSegment = 
new ScanLineSegment()
 
 2707                    Rec.segments.AddLast(Records.LastSegment);
 
 2708                else if (Prev is 
null)
 
 2709                    Rec.segments.AddFirst(Records.LastSegment);
 
 2711                    Rec.segments.AddAfter(Prev, Records.LastSegment);
 
 2715        private class ScanLineRecs
 
 2717            public ScanLineRec[] Records;
 
 2718            public int Last = -1;
 
 2719            public int LastDir = 
int.MaxValue;
 
 2720            public int Coordinate = -1;
 
 2721            public ScanLineSegment LastSegment = 
null;
 
 2723            public ScanLineRecs(
int NrRecords)
 
 2725                this.Records = 
new ScanLineRec[NrRecords];
 
 2729        private class ScanLineRec
 
 2740            public LinkedList<ScanLineSegment> segments;
 
 2741            public Vector3 n0, n1;
 
 2745                StringBuilder sb = 
new StringBuilder();
 
 2747                if (this.segments is 
null)
 
 2749                    sb.Append(this.sx0.ToString());
 
 2754                        sb.Append(this.sx1.ToString());
 
 2761                    foreach (ScanLineSegment Segment 
in this.segments)
 
 2768                        sb.Append(Segment.sx.ToString());
 
 2771                    return sb.ToString();
 
 2774                return sb.ToString();
 
 2778        private class ScanLineSegment
 
 2799        public void Text(
string Text, Vector4 Start, 
string FontFamily, 
float TextSize, SKColor Color)
 
 2801            this.Text(Text, Start, FontFamily, SKFontStyleWeight.Normal, SKFontStyleWidth.Normal,
 
 2802                SKFontStyleSlant.Upright, TextSize, Color);
 
 2814        public void Text(
string Text, Vector4 Start, 
string FontFamily, SKFontStyleWeight Weight,
 
 2815            float TextSize, SKColor Color)
 
 2817            this.Text(Text, Start, FontFamily, Weight, SKFontStyleWidth.Normal,
 
 2818                SKFontStyleSlant.Upright, TextSize, Color);
 
 2831        public void Text(
string Text, Vector4 Start, 
string FontFamily, SKFontStyleWeight Weight,
 
 2832            SKFontStyleWidth Width, 
float TextSize, SKColor Color)
 
 2834            this.Text(Text, Start, FontFamily, Weight, Width, SKFontStyleSlant.Upright,
 
 2849        public void Text(
string Text, Vector4 Start, 
string FontFamily, SKFontStyleWeight Weight,
 
 2850            SKFontStyleWidth Width, SKFontStyleSlant Slant, 
float TextSize, SKColor Color)
 
 2852            SKPaint Paint = 
null;
 
 2854            SKPath.Iterator e = 
null;
 
 2855            SKPoint[] Points = 
new SKPoint[4];
 
 2860                Paint = 
new SKPaint()
 
 2862                    Typeface = SKTypeface.FromFamilyName(FontFamily, Weight, Width, Slant),
 
 2866                Path = Paint.GetTextPath(Text, 0, 0);
 
 2867                e = Path.CreateIterator(
false);
 
 2869                List<Vector4> P = 
new List<Vector4>();
 
 2870                List<Vector4[]> v = 
new List<Vector4[]>();
 
 2873                float x0, x1, x2, x3;
 
 2874                float y0, y1, y2, y3;
 
 2875                float dx, dy, t, w, d, t2, w2, t3, w3, weight;
 
 2878                while ((Verb = e.Next(Points)) != SKPathVerb.Done)
 
 2882                        case SKPathVerb.Close:
 
 2883                            if ((c = P.Count) > 1 && P[0] == P[c - 1])
 
 2890                        case SKPathVerb.Move:
 
 2896                                    this.
Polygons(v.ToArray(), Color, 
true);
 
 2905                                if ((c = P.Count) > 1 && P[0] == P[c - 1])
 
 2912                            P.Add(
new Vector4(Start.X + X, Start.Y - Points[0].Y, Start.Z, 1));
 
 2915                        case SKPathVerb.Line:
 
 2920                            P.Add(
new Vector4(Start.X + X, Start.Y - Points[1].Y, Start.Z, 1));
 
 2923                        case SKPathVerb.Quad:
 
 2942                            c = (int)Math.Ceiling(Math.Sqrt(dx * dx + dy * dy) / 5);
 
 2943                            for (i = 1; i <= c; i++)
 
 2951                                X = w2 * x0 + 2 * t * w * x1 + t2 * x2;
 
 2952                                Y = w2 * y0 + 2 * t * w * y1 + t2 * y2;
 
 2954                                P.Add(
new Vector4(Start.X + X, Start.Y - Y, Start.Z, 1));
 
 2958                        case SKPathVerb.Conic:
 
 2977                            weight = e.ConicWeight();
 
 2979                            c = (int)Math.Ceiling(Math.Sqrt(dx * dx + dy * dy) / 5);
 
 2980                            for (i = 1; i <= c; i++)
 
 2988                                d = 1.0f / (w2 + 2 * weight * t * w + t2);
 
 2989                                X = (w2 * x0 + 2 * weight * t * w * x1 + t2 * x2) * d;
 
 2990                                Y = (w2 * y0 + 2 * weight * t * w * y1 + t2 * y2) * d;
 
 2992                                P.Add(
new Vector4(Start.X + X, Start.Y - Y, Start.Z, 1));
 
 2996                        case SKPathVerb.Cubic:
 
 3020                            c = (int)Math.Ceiling(Math.Sqrt(dx * dx + dy * dy) / 5);
 
 3021                            for (i = 1; i <= c; i++)
 
 3032                                X = w3 * x0 + 3 * t * w2 * x1 + 3 * t2 * w * x2 + t3 * x3;
 
 3033                                Y = w3 * y0 + 3 * t * w2 * y1 + 3 * t2 * w * y2 + t3 * y3;
 
 3035                                P.Add(
new Vector4(Start.X + X, Start.Y - Y, Start.Z, 1));
 
 3045                    this.
Polygons(v.ToArray(), Color, 
true);
 
 3057        #region Text Dimensions 
 3068            return this.
TextDimensions(Text, FontFamily, SKFontStyleWeight.Normal, SKFontStyleWidth.Normal,
 
 3069                SKFontStyleSlant.Upright, TextSize);
 
 3080        public SKSize 
TextDimensions(
string Text, 
string FontFamily, SKFontStyleWeight Weight, 
float TextSize)
 
 3082            return this.
TextDimensions(Text, FontFamily, Weight, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright, TextSize);
 
 3094        public SKSize 
TextDimensions(
string Text, 
string FontFamily, SKFontStyleWeight Weight,
 
 3095            SKFontStyleWidth Width, 
float TextSize)
 
 3097            return this.
TextDimensions(Text, FontFamily, Weight, Width, SKFontStyleSlant.Upright, TextSize);
 
 3110        public SKSize 
TextDimensions(
string Text, 
string FontFamily, SKFontStyleWeight Weight,
 
 3111            SKFontStyleWidth Width, SKFontStyleSlant Slant, 
float TextSize)
 
 3113            SKPaint Paint = 
null;
 
 3115            SKPath.Iterator e = 
null;
 
 3116            SKPoint[] Points = 
new SKPoint[4];
 
 3121                Paint = 
new SKPaint()
 
 3123                    Typeface = SKTypeface.FromFamilyName(FontFamily, Weight, Width, Slant),
 
 3127                Path = Paint.GetTextPath(Text, 0, 0);
 
 3128                e = Path.CreateIterator(
false);
 
 3130                List<Vector4> P = 
new List<Vector4>();
 
 3131                List<Vector4[]> v = 
new List<Vector4[]>();
 
 3138                while ((Verb = e.Next(Points)) != SKPathVerb.Done)
 
 3142                        case SKPathVerb.Close:
 
 3145                        case SKPathVerb.Move:
 
 3160                        case SKPathVerb.Line:
 
 3175                        case SKPathVerb.Quad:
 
 3176                        case SKPathVerb.Conic:
 
 3191                        case SKPathVerb.Cubic:
 
 3208                return new SKSize(MaxX - MinX, MaxY - MinY);
 
 3229        public float TextWidth(
string Text, 
string FontFamily, 
float TextSize)
 
 3231            return this.
TextWidth(Text, FontFamily, SKFontStyleWeight.Normal, SKFontStyleWidth.Normal,
 
 3232                SKFontStyleSlant.Upright, TextSize);
 
 3243        public float TextWidth(
string Text, 
string FontFamily, SKFontStyleWeight Weight, 
float TextSize)
 
 3245            return this.
TextWidth(Text, FontFamily, Weight, SKFontStyleWidth.Normal, SKFontStyleSlant.Upright, TextSize);
 
 3257        public float TextWidth(
string Text, 
string FontFamily, SKFontStyleWeight Weight,
 
 3258            SKFontStyleWidth Width, 
float TextSize)
 
 3260            return this.
TextWidth(Text, FontFamily, Weight, Width, SKFontStyleSlant.Upright, TextSize);
 
 3273        public float TextWidth(
string Text, 
string FontFamily, SKFontStyleWeight Weight,
 
 3274            SKFontStyleWidth Width, SKFontStyleSlant Slant, 
float TextSize)
 
 3276            return this.
TextDimensions(Text, FontFamily, Weight, Width, Slant, TextSize).Width;
 
 3302            this.
Box(Corner1.X, Corner1.Y, Corner1.Z, Corner2.X, Corner2.Y, Corner2.Z, Shader);
 
 3315        public void Box(
float x1, 
float y1, 
float z1, 
float x2, 
float y2, 
float z2, 
I3DShader Shader)
 
 3317            Vector4 P0 = 
new Vector4(x1, y1, z1, 1);
 
 3318            Vector4 P1 = 
new Vector4(x1, y1, z2, 1);
 
 3319            Vector4 P2 = 
new Vector4(x2, y1, z2, 1);
 
 3320            Vector4 P3 = 
new Vector4(x2, y1, z1, 1);
 
 3321            Vector4 P4 = 
new Vector4(x1, y2, z1, 1);
 
 3322            Vector4 P5 = 
new Vector4(x1, y2, z2, 1);
 
 3323            Vector4 P6 = 
new Vector4(x2, y2, z2, 1);
 
 3324            Vector4 P7 = 
new Vector4(x2, y2, z1, 1);
 
 3326            bool TwoSided = !Shader.
Opaque;
 
 3328            this.
Polygon(
new Vector4[] { P0, P3, P2, P1 }, Shader, TwoSided);
 
 3329            this.
Polygon(
new Vector4[] { P7, P4, P5, P6 }, Shader, TwoSided);
 
 3330            this.
Polygon(
new Vector4[] { P5, P1, P2, P6 }, Shader, TwoSided);
 
 3331            this.
Polygon(
new Vector4[] { P4, P0, P1, P5 }, Shader, TwoSided);
 
 3332            this.
Polygon(
new Vector4[] { P6, P2, P3, P7 }, Shader, TwoSided);
 
 3333            this.
Polygon(
new Vector4[] { P0, P4, P7, P3 }, Shader, TwoSided);
 
 3349            this.
Ellipsoid(Center.X, Center.Y, Center.Z, Radius.X, Radius.Y, Radius.Z, Facets, Shader);
 
 3363        public void Ellipsoid(
float cx, 
float cy, 
float cz, 
float rx, 
float ry, 
float rz, 
int Facets, 
I3DShader Shader)
 
 3365            int N = (int)Math.Ceiling(Math.Sqrt(2 * Facets));
 
 3371            Vector4[,] Node = 
new Vector4[N, N2 + 1];
 
 3372            Vector4[,] Normal = 
new Vector4[N, N2 + 1];
 
 3373            Vector4 Center = 
new Vector4(cx, cy, cz, 1);
 
 3376            for (a = 0; a < N; a++)
 
 3378                double φ = a * Math.PI / N2;
 
 3380                for (b = 0; b <= N2; b++)
 
 3382                    double θ = b * Math.PI / N2;
 
 3383                    double sinθ = Math.Sin(θ);
 
 3385                    Normal[a, b] = Delta = 
new Vector4(
 
 3386                        (
float)(rx * sinθ * Math.Cos(φ)),
 
 3387                        (
float)(ry * Math.Cos(θ)),
 
 3388                        (
float)(rz * sinθ * Math.Sin(φ)),
 
 3391                    Node[a, b] = Delta + Center;
 
 3396            bool TwoSided = !Shader.
Opaque;
 
 3398            for (a = 0, pa = N - 1; a < N; pa = a++)
 
 3400                for (b = 1, pb = 0; b <= N2; pb = b++)
 
 3414                    }, Shader, TwoSided);
 
 3421        #region Exporting graph 
 3429            Dictionary<string, int> Shaders = 
new Dictionary<string, int>();
 
 3433            Output.WriteStartElement(
"Canvas3D");
 
 3434            Output.WriteAttributeString(
"id", this.
id.ToString());
 
 3435            Output.WriteAttributeString(
"width", this.width.ToString());
 
 3436            Output.WriteAttributeString(
"height", this.height.ToString());
 
 3437            Output.WriteAttributeString(
"overSampling", this.overSampling.ToString());
 
 3442            Output.WriteElementString(
"Projection", 
Expression.
ToString(
this.projectionTransformation));
 
 3444            Output.WriteElementString(
"Pixels", Convert.ToBase64String(
this.pixels));
 
 3447            foreach (KeyValuePair<
float, LinkedList<PolyRec>> P 
in this.transparentPolygons)
 
 3449                Output.WriteStartElement(
"Transparent");
 
 3452                foreach (PolyRec Rec 
in P.Value)
 
 3454                    Output.WriteStartElement(
"P");
 
 3455                    Output.WriteAttributeString(
"minY", Rec.MinY.ToString());
 
 3456                    Output.WriteAttributeString(
"maxY", Rec.MaxY.ToString());
 
 3457                    Output.WriteAttributeString(
"nrPolygons", Rec.NrPolygons.ToString());
 
 3458                    Output.WriteAttributeString(
"interpolateNormals", Rec.InterpolateNormals ? 
"true" : 
"false");
 
 3460                    if (!(Rec.FrontShader is 
null))
 
 3463                        if (!Shaders.TryGetValue(s, out 
int i))
 
 3469                        Output.WriteAttributeString(
"fs", i.ToString());
 
 3472                    if (!(Rec.BackShader is 
null))
 
 3475                        if (!Shaders.TryGetValue(s, out 
int i))
 
 3481                        Output.WriteAttributeString(
"bs", i.ToString());
 
 3488                    Output.WriteEndElement();
 
 3491                foreach (KeyValuePair<string, int> Shader 
in Shaders)
 
 3493                    Output.WriteStartElement(
"Shader");
 
 3494                    Output.WriteAttributeString(
"index", Shader.Value.ToString());
 
 3495                    Output.WriteValue(Shader.Key);
 
 3496                    Output.WriteEndElement();
 
 3499                Output.WriteEndElement();
 
 3502            Output.WriteEndElement();
 
 3514            foreach (XmlAttribute Attr 
in Xml.Attributes)
 
 3519                        this.id = Guid.Parse(Attr.Value);
 
 3523                        this.width = 
int.Parse(Attr.Value);
 
 3527                        this.height = 
int.Parse(Attr.Value);
 
 3530                    case "overSampling":
 
 3531                        this.overSampling = 
int.Parse(Attr.Value);
 
 3541                        this.backgroundColor = (SKColor)await Exp.EvaluateAsync(
Variables);
 
 3546                        this.viewerPosition = (Vector3)await Exp.EvaluateAsync(
Variables);
 
 3551            if (this.width <= 0)
 
 3552                throw new ArgumentOutOfRangeException(
"Width must be a positive integer.");
 
 3554            if (this.height <= 0)
 
 3555                throw new ArgumentOutOfRangeException(
"Height must be a positive integer.");
 
 3557            if (this.overSampling <= 0)
 
 3558                throw new ArgumentOutOfRangeException(
"Oversampling must be a positive integer.");
 
 3560            this.w = this.width * this.overSampling;
 
 3561            this.h = this.height * this.overSampling;
 
 3562            this.wm1 = this.w - 1;
 
 3563            this.hm1 = this.h - 1;
 
 3564            this.cx = this.w / 2;
 
 3565            this.cy = this.h / 2;
 
 3569            int i, c = this.w * this.h;
 
 3571            this.pixels = 
new byte[c * 4];
 
 3572            this.zBuffer = 
new float[c];
 
 3573            this.xBuf = 
new float[this.w];
 
 3574            this.yBuf = 
new float[this.w];
 
 3575            this.zBuf = 
new float[this.w];
 
 3576            this.normalBuf = 
new Vector3[this.w];
 
 3577            this.colorBuf = 
new SKColor[this.w];
 
 3579            Dictionary<int, I3DShader> Shaders = 
new Dictionary<int, I3DShader>();
 
 3581            foreach (XmlNode N 
in Xml.ChildNodes)
 
 3583                if (N is XmlElement E && E.LocalName == 
"Shader")
 
 3585                    int Index = 
int.Parse(E.GetAttribute(
"index"));
 
 3591            foreach (XmlNode N 
in Xml.ChildNodes)
 
 3593                if (N is XmlElement E)
 
 3595                    switch (E.LocalName)
 
 3599                            this.projectionTransformation = (Matrix4x4)await Exp.EvaluateAsync(
Variables);
 
 3604                            this.modelTransformation = (Matrix4x4)await Exp.EvaluateAsync(
Variables);
 
 3608                            this.pixels = Convert.FromBase64String(E.InnerText);
 
 3613                            double[] v = (
double[])await Exp.EvaluateAsync(
Variables);
 
 3616                            this.zBuffer = 
new float[c];
 
 3618                            for (i = 0; i < c; i++)
 
 3619                                this.zBuffer[i] = (
float)v[i];
 
 3625                            LinkedList<PolyRec> 
Polygons = 
new LinkedList<PolyRec>();
 
 3626                            this.transparentPolygons[z] = 
Polygons;
 
 3628                            foreach (XmlNode N2 
in E.ChildNodes)
 
 3630                                if (N2 is XmlElement E2 && E.LocalName == 
"P")
 
 3632                                    PolyRec P = 
new PolyRec();
 
 3634                                    foreach (XmlAttribute Attr2 
in E2.Attributes)
 
 3639                                                P.MinY = 
int.Parse(Attr2.Value);
 
 3643                                                P.MaxY = 
int.Parse(Attr2.Value);
 
 3647                                                P.NrPolygons = 
int.Parse(Attr2.Value);
 
 3650                                            case "interpolateNormals":
 
 3651                                                P.InterpolateNormals = Attr2.Value == 
"true";
 
 3655                                                P.FrontShader = Shaders[
int.Parse(Attr2.Value)];
 
 3659                                                P.BackShader = Shaders[
int.Parse(Attr2.Value)];
 
 3664                                    foreach (XmlNode N3 
in E2.ChildNodes)
 
 3666                                        if (N3 is XmlElement E3)
 
 3668                                            switch (E3.LocalName)
 
 3694        private static Vector3[][] ToVector3DoubleArray(
IMatrix M)
 
 3699            Vector3[][] Result = 
new Vector3[c][];
 
 3701            for (i = 0; i < c; i++)
 
 3703                Result[i] = 
new Vector3[d];
 
 3705                for (j = 0; j < d; j++)
 
Base class for all types of elements.
Class managing a script expression.
static bool TryParse(string s, out double Value)
Tries to parse a double-precision floating-point value.
static string ToString(double Value)
Converts a value to a string, that can be parsed as part of an expression.
void Plot(Vector4 Point, SKColor Color)
Plots a point on the 3D-canvas.
void Polygon(Vector4[] Nodes, SKColor Color, bool TwoSided)
Draws a closed polygon.
float TextWidth(string Text, string FontFamily, SKFontStyleWeight Weight, float TextSize)
Measures the width of text to be output.
Matrix4x4 RotateX(float Degrees, object CenterPoint)
Rotates the world around an axis parallel to the X-axis, going through the center point CenterPoint .
void PolyLine(Vector4[] Nodes, uint Color)
Draws lines between a set of nodes.
static Vector4 CalcNormal(Vector4 P0, Vector4 P1, Vector4 P2)
Calculates a normal to the plane that goes through P0, P1 and P2.
override PixelInformation CreatePixels(GraphSettings Settings, out object[] States)
Creates a bitmap of the graph.
void Polygons(Vector4[][] Nodes, I3DShader Shader, bool TwoSided)
Draws a set of closed polygons. Interior polygons can be used to undraw the corresponding sections.
Matrix4x4 Translate(Vector3 Delta)
Translates the world.
static Vector4 ToVector(Vector3 P)
Converts a Vector3 to a Vector4 vector.
void Polygon(Vector4[] Nodes, Vector4[] Normals, I3DShader Shader, bool TwoSided)
Draws a closed polygon.
void MoveTo(Vector4 Point)
Moves to a point.
Matrix4x4 Translate(float DeltaX, float DelayY, float DeltaZ)
Translates the world.
override int GetHashCode()
Calculates a hash code of the element.
Matrix4x4 Scale(float Scale)
Scales the world
Matrix4x4 RotateZ(float Degrees)
Rotates the world around the Z-axis.
void PolyLine(Vector4[] Nodes, SKColor Color)
Draws lines between a set of nodes.
void Polygons(Vector4[][] Nodes, Vector4[][] Normals, I3DShader Shader, bool TwoSided)
Draws a set of closed polygons. Interior polygons can be used to undraw the corresponding sections.
void Ellipsoid(float cx, float cy, float cz, float rx, float ry, float rz, int Facets, I3DShader Shader)
Draws an ellipsoid, with axes parallell to the x, y and z axis.
Matrix4x4 RotateY(float Degrees, object CenterPoint)
Rotates the world around an axis parallel to the Y-axis, going through the center point CenterPoint .
void Text(string Text, Vector4 Start, string FontFamily, SKFontStyleWeight Weight, SKFontStyleWidth Width, float TextSize, SKColor Color)
Draws text on the canvas.
SKSize TextDimensions(string Text, string FontFamily, SKFontStyleWeight Weight, float TextSize)
Measures the size of text to be output.
Matrix4x4 Scale(float Scale, object CenterPoint)
Scales the world
void Polygons(Vector4[][] Nodes, SKColor Color, bool TwoSided)
Draws a set of closed polygons. Interior polygons can be used to undraw the corresponding sections.
override ISemiGroupElement AddRight(ISemiGroupElement Element)
Tries to add an element to the current element, from the right.
void Polygon(Vector4[] Nodes, Vector4[] Normals, SKColor Color, bool TwoSided)
Draws a closed polygon.
static Vector3 CalcNormal(Vector3 P0, Vector3 P1, Vector3 P2)
Calculates a normal to the plane that goes through P0, P1 and P2.
Canvas3D(Variables Variables, int Width, int Height, int OverSampling, SKColor BackgroundColor)
3D drawing area.
override Tuple< int, int > RecommendedBitmapSize
The recommended bitmap size of the graph, if such is available, or null if not.
void Text(string Text, Vector4 Start, string FontFamily, SKFontStyleWeight Weight, SKFontStyleWidth Width, SKFontStyleSlant Slant, float TextSize, SKColor Color)
Draws text on the canvas.
Matrix4x4 Scale(float ScaleX, float ScaleY, float ScaleZ, Vector3 CenterPoint)
Scales the world
float TextWidth(string Text, string FontFamily, SKFontStyleWeight Weight, SKFontStyleWidth Width, SKFontStyleSlant Slant, float TextSize)
Measures the width of text to be output.
void Line(Vector4 P0, Vector4 P1, uint Color)
Draws a line between P0 and P1.
void Clear()
Clears the canvas.
Matrix4x4 RotateX(float Degrees, Vector3 CenterPoint)
Rotates the world around an axis parallel to the X-axis, going through the center point CenterPoint .
Vector3 ModelTransform(Vector3 Point)
Transforms a world coordinate to a display coordinate.
override bool TrySetDefaultColor(SKColor Color)
Tries to set the default color.
void Box(Vector4 Corner1, Vector4 Corner2, I3DShader Shader)
Draws a box, with sides parallell to the x, y and z axis.
override string GetBitmapClickScript(double X, double Y, object[] States)
Gets script corresponding to a point in a generated bitmap representation of the graph.
Matrix4x4 RotateZ(float Degrees, object CenterPoint)
Rotates the world around an axis parallel to the Z-axis, going through the center point CenterPoint .
Matrix4x4 RotateY(float Degrees)
Rotates the world around the Y-axis.
override bool Equals(object obj)
Compares the element to another.
static Vector4 ToPoint(Vector3 P)
Converts a Vector3 to a Vector4 point.
Matrix4x4 Perspective(float NearPlaneDistance, float FarPlaneDistance)
Applies a perspective projection.
void Text(string Text, Vector4 Start, string FontFamily, SKFontStyleWeight Weight, float TextSize, SKColor Color)
Draws text on the canvas.
SKSize TextDimensions(string Text, string FontFamily, float TextSize)
Measures the size of text to be output.
static PhongIntensity ToPhongIntensity(object Object)
Converts an object to a PhongIntensity object.
override ISemiGroupElement AddLeft(ISemiGroupElement Element)
Tries to add an element to the current element, from the left.
void Polygons(Vector4[][] Nodes, Vector4[][] Normals, SKColor Color, bool TwoSided)
Draws a set of closed polygons. Interior polygons can be used to undraw the corresponding sections.
void Box(float x1, float y1, float z1, float x2, float y2, float z2, I3DShader Shader)
Draws a box, with sides parallell to the x, y and z axis.
SKSize TextDimensions(string Text, string FontFamily, SKFontStyleWeight Weight, SKFontStyleWidth Width, SKFontStyleSlant Slant, float TextSize)
Measures the size of text to be output.
Canvas3D(GraphSettings Settings, int Width, int Height, int OverSampling, SKColor BackgroundColor)
3D drawing area.
float TextWidth(string Text, string FontFamily, SKFontStyleWeight Weight, SKFontStyleWidth Width, float TextSize)
Measures the width of text to be output.
Matrix4x4 ModelTransformation
Current model transformation matrix.
Vector4 ModelTransform(Vector4 Point)
Transforms a world coordinate to a display coordinate.
Canvas3D(Variables Variables)
3D drawing area.
override async Task ImportGraphAsync(XmlElement Xml)
Imports graph specifics from XML.
void LineTo(Vector4 Point, SKColor Color)
Draws a line to Point  from the last endpoint.
void Ellipsoid(Vector3 Center, Vector3 Radius, int Facets, I3DShader Shader)
Draws an ellipsoid, with axes parallell to the x, y and z axis.
Matrix4x4 ProjectionTransformation
Current projection transformation matrix.
void Polygons(Vector4[][] Nodes, Vector4[][] Normals, I3DShader FrontShader, I3DShader BackShader)
Draws a set of closed polygons. Interior polygons can be used to undraw the corresponding sections.
Matrix4x4 Scale(float ScaleX, float ScaleY, float ScaleZ, object CenterPoint)
Scales the world
Matrix4x4 Scale(float Scale, Vector3 CenterPoint)
Scales the world
void Polygon(Vector4[] Nodes, I3DShader Shader, bool TwoSided)
Draws a closed polygon.
static Vector3 ToVector3(object Object)
Converts a Vector4 to a Vector3.
override bool UsesDefaultColor
If graph uses default color
float TextWidth(string Text, string FontFamily, float TextSize)
Measures the width of text to be output.
SKSize TextDimensions(string Text, string FontFamily, SKFontStyleWeight Weight, SKFontStyleWidth Width, float TextSize)
Measures the size of text to be output.
Matrix4x4 RotateZ(float Degrees, Vector3 CenterPoint)
Rotates the world around an axis parallel to the Z-axis, going through the center point CenterPoint .
void Polygons(Vector4[][] Nodes, I3DShader FrontShader, I3DShader BackShader)
Draws a set of closed polygons. Interior polygons can be used to undraw the corresponding sections.
void LineTo(Vector4 Point, uint Color)
Draws a line to Point  from the last endpoint.
static Vector3 ToVector3(Vector4 P)
Converts a Vector4 to a Vector3.
void Plot(Vector4 Point, uint Color)
Plots a point on the 3D-canvas.
Matrix4x4 LookAt(Vector3 Position, Vector3 Target, Vector3 Up)
Places the observer at the point Position , looking at the point Target , with upwards pointing in th...
Matrix4x4 Scale(float ScaleX, float ScaleY, float ScaleZ)
Scales the world
Matrix4x4 LookAt(float PositionX, float PositionY, float PositionZ, float TargetX, float TargetY, float TargetZ, float UpX, float UpY, float UpZ)
Places the observer at the point (PositionX , PositionY , PositionZ ), looking at the point (TargetX ...
PixelInformation GetPixels()
Creates a bitmap from the pixels in the canvas.
Vector3 Project(Vector3 Point)
Transforms a world coordinate to a display coordinate.
void Line(Vector4 P0, Vector4 P1, SKColor Color)
Draws a line between P0 and P1.
void Box(Vector3 Corner1, Vector3 Corner2, I3DShader Shader)
Draws a box, with sides parallell to the x, y and z axis.
Matrix4x4 RotateX(float Degrees)
Rotates the world around the X-axis.
Vector3 ViewerPosition
Viewer position
Matrix4x4 RotateY(float Degrees, Vector3 CenterPoint)
Rotates the world around an axis parallel to the Y-axis, going through the center point CenterPoint .
Vector3 Project(Vector4 Point)
Transforms coordinates to screen coordinates.
void Text(string Text, Vector4 Start, string FontFamily, float TextSize, SKColor Color)
Draws text on the canvas.
override void ExportGraph(XmlWriter Output)
Exports graph specifics to XML.
void ResetTransforms()
Resets any transforms.
Shader returning a constant color.
Contains information about the intensity of a light component, as used in the Phong reflection model....
GraphSettings Settings
Graph settings available during creation.
static SKColor ToColor(object Object)
Converts an object to a color.
static async Task< IElement > ParseAsync(string s, Variables Variables)
Parses an element expression string.
object AssociatedObjectValue
Associated object value.
Basic interface for matrices.
int Columns
Number of columns.
IElement GetElement(int Column, int Row)
Gets an element of the matrix.
Basic interface for all types of semigroup elements.
Interface for 3D shaders.
bool Opaque
If shader is 100% opaque.
SKColor GetColor(float X, float Y, float Z, Vector3 Normal, Canvas3D Canvas)
Gets a color for a position.
void GetColors(float[] X, float[] Y, float[] Z, Vector3[] Normals, int N, SKColor[] Colors, Canvas3D Canvas)
Gets an array of colors.
delegate string ToString(IElement Element)
Delegate for callback methods that convert an element value to a string.