context: namespace Steema.TeeChart.Drawing
  {
      using Steema.TeeChart;
      using System;
      using System.ComponentModel;
      using System.Drawing;
      using System.Drawing.Drawing2D;
      using System.Drawing.Text;
      using System.Runtime.InteropServices;
      using System.Windows.Forms;
  
      public abstract class Graphics3D : TeeBase
      {
          protected System.Drawing.Drawing2D.SmoothingMode aSmoothingMode;
          protected internal Aspect aspect;
          protected System.Drawing.Text.TextRenderingHint aTextRenderingHint;
          private ChartBrush bBrush;
          private System.Drawing.Rectangle bounds;
          private bool buffered;
          private double c1;
          private double c2c1;
          private double c2c3;
          private double c2s1;
          private double c2s3;
          private double c3;
          public static Color[] ColorPalette = new Color[] { 
              Color.Red, Color.Green, Color.Yellow, Color.Blue, Color.White, Color.Gray, Color.Fuchsia, Color.Teal, Color.Navy, Color.Maroon, Color.Lime, Color.Olive, Color.Purple, Color.Silver, Color.Aqua, Color.Black, 
              Color.GreenYellow, Color.SkyBlue, Color.Bisque, Color.Indigo
           };
          internal const int DarkColorQuantity = 0x40;
          internal const int DarkerColorQuantity = 0x80;
          internal bool Dirty;
          private ChartFont font;
          public Point[] FourPoints;
          protected internal Graphics g;
          private double IOrthoX;
          private double IOrthoY;
          private double IPerspec;
          private Point[] IPoints;
          private double IZoomFactor;
          private bool IZoomText;
          private SizeF layoutArea;
          internal bool metafiling;
          public bool Monochrome;
          private ChartPen pen;
          private Pie3D pie3D;
          public const double PiStep = 0.017453292519943295;
          private PointXYZ rotationCenter;
          private double s1;
          private double s2;
          private double s3;
          protected StringFormat stringFormat;
          private bool supports3DText;
          private double tempXX;
          private double tempXZ;
          private double tempYX;
          private double tempYZ;
          private int xCenter;
          private int xCenterOffset;
          private int yCenter;
          private int yCenterOffset;
          private int zCenter;
  
          public Graphics3D(Chart c) : base(c)
          {
              this.FourPoints = new Point[4];
              this.aSmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
              this.aTextRenderingHint = System.Drawing.Text.TextRenderingHint.SystemDefault;
              this.stringFormat = new StringFormat();
              this.pen = new ChartPen(Color.Black);
              this.bBrush = new ChartBrush(null);
              this.font = new ChartFont(null);
              this.buffered = true;
              this.rotationCenter = new PointXYZ();
              this.IPoints = new Point[4];
              this.Dirty = true;
              this.layoutArea = new SizeF(1000f, 1000f);
              this.pen.chart = c;
              this.bBrush.chart = c;
              this.font.chart = c;
              this.aspect = base.chart.aspect;
          }
  
          private Region AddRightRegion(System.Drawing.Rectangle rect, int minZ, int maxZ)
          {
              Point[] points = new Point[6];
              points[0] = this.Calc3DPoint(rect.X, rect.Bottom, minZ);
              points[1] = this.Calc3DPoint(rect.X, rect.Y, minZ);
              Point point = this.Calc3DPoint(rect.X, rect.Y, maxZ);
              Point point2 = this.Calc3DPoint(rect.Right, rect.Y, minZ);
              points[2] = (point2.Y < point.Y) ? point2 : point;
              points[3] = this.Calc3DPoint(rect.Right, rect.Y, maxZ);
              point = this.Calc3DPoint(rect.Right, rect.Bottom, maxZ);
              point2 = this.Calc3DPoint(rect.Right, rect.Y, minZ);
              points[4] = (point2.X > point.X) ? point2 : point;
              points[5] = this.Calc3DPoint(rect.Right, rect.Bottom, minZ);
              if (points[5].X < points[0].X)
              {
                  points[0].X = points[5].X;
                  if (point2.Y < points[0].Y)
                  {
                      points[0].Y = point2.Y;
                  }
              }
              GraphicsPath path = new GraphicsPath();
              path.AddPolygon(points);
              return new Region(path);
          }
  
          public static void ApplyBright(ref Color c, byte howMuch)
          {
              byte r = c.R;
              byte g = c.G;
              byte b = c.B;
              if ((r + howMuch) < 0x100)
              {
                  r = (byte) (r + howMuch);
              }
              else
              {
                  r = 0xff;
              }
              if ((g + howMuch) < 0x100)
              {
                  g = (byte) (g + howMuch);
              }
              else
              {
                  g = 0xff;
              }
              if ((b + howMuch) < 0x100)
              {
                  b = (byte) (b + howMuch);
              }
              else
              {
                  b = 0xff;
              }
              c = Color.FromArgb(c.A, r, g, b);
          }
  
          public static void ApplyDark(ref Color c, byte howMuch)
          {
              byte r = c.R;
              byte g = c.G;
              byte b = c.B;
              if (r > howMuch)
              {
                  r = (byte) (r - howMuch);
              }
              else
              {
                  r = 0;
              }
              if (g > howMuch)
              {
                  g = (byte) (g - howMuch);
              }
              else
              {
                  g = 0;
              }
              if (b > howMuch)
              {
                  b = (byte) (b - howMuch);
              }
              else
              {
                  b = 0;
              }
              c = Color.FromArgb(c.A, r, g, b);
          }
  
          public abstract void Arc(int x1, int y1, int x2, int y2, float startAngle, float sweepAngle);
          public abstract void Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
          public void Arrow(bool filled, Point fromPoint, Point toPoint, int headWidth, int headHeight, int z)
          {
              int num = toPoint.X - fromPoint.X;
              int num2 = fromPoint.Y - toPoint.Y;
              double num3 = Math.Sqrt((double) ((num * num) + (num2 * num2)));
              if (num3 > 0.0)
              {
                  ArrowPoint point = new ArrowPoint();
                  point.z = z;
                  point.g = this;
                  int num4 = headWidth;
                  int num5 = Math.Min(Utils.Round(num3), headHeight);
                  point.SinA = ((double) num2) / num3;
                  point.CosA = ((double) num) / num3;
                  double num6 = (toPoint.X * point.CosA) - (toPoint.Y * point.SinA);
                  double num7 = (toPoint.X * point.SinA) + (toPoint.Y * point.CosA);
                  point.x = num6 - num5;
                  point.y = num7 - (num4 * 0.5);
                  Point p = point.Calc();
                  point.y = num7 + (num4 * 0.5);
                  Point point3 = point.Calc();
                  if (filled)
                  {
                      double num8 = num4 * 0.25;
                      point.y = num7 - num8;
                      Point point4 = point.Calc();
                      point.y = num7 + num8;
                      Point point5 = point.Calc();
                      point.x = (fromPoint.X * point.CosA) - (fromPoint.Y * point.SinA);
                      point.y = num7 - num8;
                      Point point6 = point.Calc();
                      point.y = num7 + num8;
                      Point point7 = point.Calc();
                      Point[] pointArray = new Point[] { point7, point6, point4, p, this.Calc3DPoint(toPoint, z), point3, point5 };
                      this.Polygon(pointArray);
                  }
                  else
                  {
                      this.MoveTo(fromPoint, z);
                      this.LineTo(toPoint, z);
                      this.LineTo(point3, z);
                      this.MoveTo(toPoint, z);
                      this.LineTo(p, z);
                  }
              }
          }
  
          public Point Calc3DPoint(Point3D p)
          {
              return this.Calc3DPoint(p.X, p.Y, p.Z);
          }
  
          public Point Calc3DPoint(Point p, int z)
          {
              this.Calc3DPos(ref p, p.X, p.Y, z);
              return p;
          }
  
          public Point Calc3DPoint(int x, int y, int z)
          {
              this.Calc3DPos(ref x, ref y, z);
              return new Point(x, y);
          }
  
          public void Calc3DPos(ref Point p, Point source, int z)
          {
              this.Calc3DPos(ref p, source.X, source.Y, z);
          }
  
          public void Calc3DPos(ref int x, ref int y, int z)
          {
              if (this.aspect.orthogonal)
              {
                  x = ((int) (this.IZoomFactor * ((double) ((x - this.xCenter) + z)))) + this.xCenterOffset;
                  y = ((int) (this.IZoomFactor * (((double) (y - this.yCenter)) - (this.IOrthoY * z)))) + this.yCenterOffset;
              }
              else if (this.aspect.view3D)
              {
                  double iZoomFactor;
                  z -= this.zCenter;
                  x -= this.xCenter;
                  y -= this.yCenter;
                  if (this.IPerspec > 0.0)
                  {
                      iZoomFactor = this.IZoomFactor * (1.0 - ((((((double) x) * this.c2s1) - (((double) y) * this.s2)) + (z * this.c2c1)) * this.IPerspec));
                  }
                  else
                  {
                      iZoomFactor = this.IZoomFactor;
                  }
                  int num2 = x;
                  x = ((int) ((((((double) x) * this.tempXX) + (((double) y) * this.c2s3)) + (z * this.tempXZ)) * iZoomFactor)) + this.xCenterOffset;
                  y = ((int) ((((num2 * this.tempYX) + (((double) y) * this.c2c3)) + (z * this.tempYZ)) * iZoomFactor)) + this.yCenterOffset;
              }
          }
  
          public void Calc3DPos(ref Point p, int x, int y, int z)
          {
              this.Calc3DPos(ref x, ref y, z);
              p.X = x;
              p.Y = y;
          }
  
          private static LineOrientations CalcLineParameters(Point PointA, Point PointB, out double Slope, out double Intercept)
          {
              Point point = new Point(PointA.X - PointB.X, PointA.Y - PointB.Y);
              if ((point.X == 0) && (point.Y == 0))
              {
                  Slope = 0.0;
                  Intercept = 0.0;
                  return LineOrientations.Point;
              }
              if (Math.Abs(point.X) >= Math.Abs(point.Y))
              {
                  try
                  {
                      Slope = Convert.ToDouble(point.Y) / Convert.ToDouble(point.X);
                  }
                  catch
                  {
                      Slope = 0.0;
                  }
                  Intercept = PointA.Y - (PointA.X * Slope);
                  return LineOrientations.Horizontal;
              }
              try
              {
                  Slope = Convert.ToDouble(point.X) / Convert.ToDouble(point.Y);
              }
              catch
              {
                  Slope = 0.0;
              }
              Intercept = PointA.X - (PointA.Y * Slope);
              return LineOrientations.Vertical;
          }
  
          internal void CalcPerspective(System.Drawing.Rectangle r)
          {
              this.IPerspec = (this.aspect.Perspective > 0) ? ((((double) this.aspect.Perspective) / 150.0) / ((double) r.Width)) : 0.0;
          }
  
          public System.Drawing.Rectangle CalcRect3D(System.Drawing.Rectangle r, int z)
          {
              int x = r.X;
              int y = r.Y;
              this.Calc3DPos(ref x, ref y, z);
              int right = r.Right;
              int bottom = r.Bottom;
              this.Calc3DPos(ref right, ref bottom, z);
              r.X = x;
              r.Y = y;
              r.Width = right - r.X;
              r.Height = bottom - r.Y;
              return r;
          }
  
          internal void CalcTrigValues()
          {
              double elevation;
              double tilt;
              double rotation = 0.0;
              if (!this.aspect.orthogonal)
              {
                  rotation = this.aspect.rotation;
                  elevation = this.aspect.Elevation;
                  tilt = this.aspect.Tilt;
              }
              else
              {
                  rotation = 0.0;
                  elevation = 0.0;
                  tilt = 0.0;
              }
              this.s1 = Math.Sin(rotation * 0.017453292519943295);
              this.c1 = Math.Cos(rotation * 0.017453292519943295);
              this.s2 = Math.Sin(elevation * 0.017453292519943295);
              double num4 = Math.Cos(elevation * 0.017453292519943295);
              this.s3 = Math.Sin(tilt * 0.017453292519943295);
              this.c3 = Math.Cos(tilt * 0.017453292519943295);
              this.c2s3 = num4 * this.s3;
              this.c2c3 = Math.Max((double) 1E-05, (double) (num4 * this.c3));
              this.tempXX = Math.Max((double) 1E-05, (double) (((this.s1 * this.s2) * this.s3) + (this.c1 * this.c3)));
              this.tempYX = ((this.c3 * this.s1) * this.s2) - (this.c1 * this.s3);
              this.tempXZ = ((this.c1 * this.s2) * this.s3) - (this.c3 * this.s1);
              this.tempYZ = ((this.c1 * this.c3) * this.s2) + (this.s1 * this.s3);
              this.c2s1 = num4 * this.s1;
              this.c2c1 = this.c1 * num4;
          }
  
          public void Calculate2DPosition(ref int x, ref int y, int z)
          {
              if (this.IZoomFactor != 0.0)
              {
                  double num2 = 1.0 / this.IZoomFactor;
                  if (this.aspect.orthogonal)
                  {
                      x = ((int) Math.Round((double) ((((double) (x - this.xCenterOffset)) * num2) - (this.IOrthoX * z)))) + this.xCenter;
                      y = ((int) Math.Round((double) ((((double) (y - this.yCenterOffset)) * num2) + (this.IOrthoY * z)))) + this.yCenter;
                  }
                  else if ((this.aspect.view3D && (this.tempXX != 0.0)) && (this.c2c3 != 0.0))
                  {
                      int num = x;
                      z -= this.zCenter;
                      x = ((int) Math.Round((double) (((((num - this.xCenterOffset) * num2) - (z * this.tempXZ)) - (((double) (y - this.yCenter)) * this.c2s3)) / this.tempXX))) + this.xCenter;
                      y = ((int) Math.Round((double) ((((((double) (y - this.yCenterOffset)) * num2) - (z * this.tempYZ)) - ((num - this.xCenter) * this.tempYX)) / this.c2c3))) + this.yCenter;
                  }
              }
          }
  
          public virtual void Changed(object o)
          {
          }
  
          public virtual void ClipCube(System.Drawing.Rectangle rect, int minZ, int maxZ)
          {
              if (this.aspect.View3D)
              {
                  Aspect aspect = this.aspect;
                  if ((aspect.Elevation == 270) && ((aspect.Rotation == 270) || (aspect.Rotation == 360)))
                  {
                      Point point = this.Calc3DPoint(rect.X, rect.Y, minZ);
                      Point point2 = this.Calc3DPoint(rect.Right, rect.Y, maxZ);
                      this.ClipRectangle(point.X, point.Y, point2.X, point2.Y);
                  }
                  else if (aspect.Orthogonal)
                  {
                      if (aspect.OrthoAngle > 90)
                      {
                          this.ClipToLeft(rect, minZ, maxZ);
                      }
                      else
                      {
                          this.ClipToRight(rect, minZ, maxZ);
                      }
                  }
                  else if (aspect.Rotation >= 270)
                  {
                      this.ClipToRight(rect, minZ, maxZ);
                  }
              }
              else
              {
                  this.ClipRectangle(rect.X + 1, rect.Y + 1, rect.Right - 1, rect.Bottom - 1);
              }
          }
  
          public abstract void ClipEllipse(System.Drawing.Rectangle r);
          public abstract void ClipPolygon(params Point[] p);
          public abstract void ClipRectangle(System.Drawing.Rectangle r);
          public void ClipRectangle(int left, int top, int right, int bottom)
          {
              this.ClipRectangle(System.Drawing.Rectangle.FromLTRB(left, top, right, bottom));
          }
  
          private void ClipToLeft(System.Drawing.Rectangle rect, int minZ, int maxZ)
          {
              Point[] p = new Point[] { this.Calc3DPoint(rect.X, rect.Bottom, minZ), this.Calc3DPoint(rect.X, rect.Bottom, maxZ), this.Calc3DPoint(rect.X, rect.Y, maxZ), this.Calc3DPoint(rect.Right, rect.Y, maxZ), this.Calc3DPoint(rect.Right, rect.Y, minZ), this.Calc3DPoint(rect.Right, rect.Bottom, minZ) };
              this.ClipPolygon(p);
          }
  
          private void ClipToRight(System.Drawing.Rectangle rect, int minZ, int maxZ)
          {
              Point[] p = new Point[6];
              p[0] = this.Calc3DPoint(rect.X, rect.Bottom, minZ);
              p[1] = this.Calc3DPoint(rect.X, rect.Y, minZ);
              Point point = this.Calc3DPoint(rect.X, rect.Y, maxZ);
              Point point2 = this.Calc3DPoint(rect.Right, rect.Y, minZ);
              p[2] = (point2.Y < point.Y) ? point2 : point;
              p[3] = this.Calc3DPoint(rect.Right, rect.Y, maxZ);
              point = this.Calc3DPoint(rect.Right, rect.Bottom, maxZ);
              point2 = this.Calc3DPoint(rect.Right, rect.Y, minZ);
              p[4] = (point2.X > point.X) ? point2 : point;
              p[5] = this.Calc3DPoint(rect.Right, rect.Bottom, minZ);
              if (p[5].X < p[0].X)
              {
                  p[0].X = p[5].X;
                  if (point2.Y < p[0].Y)
                  {
                      p[0].Y = point2.Y;
                  }
              }
              this.ClipPolygon(p);
          }
  
          public void Cone(bool vertical, System.Drawing.Rectangle r, int z0, int z1, bool darkSides)
          {
              this.InternalCylinder(vertical, r, z0, z1, darkSides, 0);
          }
  
          public void Cone(bool vertical, System.Drawing.Rectangle r, int z0, int z1, bool darkSides, int conePercent)
          {
              this.InternalCylinder(vertical, r, z0, z1, darkSides, conePercent);
          }
  
          public void Cone(bool vertical, int left, int top, int right, int bottom, int z0, int z1, bool darkSides)
          {
              this.InternalCylinder(vertical, System.Drawing.Rectangle.FromLTRB(left, top, right, bottom), z0, z1, darkSides, 0);
          }
  
          protected System.Drawing.Rectangle CorrectRectangle(System.Drawing.Rectangle r)
          {
              if (r.Height < 0)
              {
                  r.Y = r.Bottom;
                  r.Height = -r.Height;
              }
              if (r.Width < 0)
              {
                  r.X = r.Right;
                  r.Width = -r.Width;
              }
              return r;
          }
  
          public static bool CrossingLines(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4, out double x, out double y)
          {
              double num = y2 - y1;
              double num2 = y4 - y3;
              double num3 = x2 - x1;
              double num4 = x4 - x3;
              double num5 = num / num3;
              double num6 = num2 / num4;
              double num7 = y1 - (num5 * x1);
              double num8 = y3 - (num6 * x3);
              double num9 = num6 - num5;
              if (Math.Abs(num9) > 1E-15)
              {
                  x = (num7 - num8) / num9;
              }
              else
              {
                  x = x2;
              }
              y = (num5 * x) + num7;
              double num10 = (x1 * y2) - (x2 * y1);
              double num11 = (x3 * y4) - (x4 * y3);
              return ((((((num * x3) - (num3 * y3)) - num10) > 0.0) ^ ((((num * x4) - (num3 * y4)) - num10) > 0.0)) && (((((num2 * x1) - (num4 * y1)) - num11) > 0.0) ^ ((((num2 * x2) - (num4 * y2)) - num11) > 0.0)));
          }
  
          public void Cube(System.Drawing.Rectangle r, int z0, int z1)
          {
              this.Cube(r.X, r.Y, r.Right, r.Bottom, z0, z1, true);
          }
  
          public void Cube(System.Drawing.Rectangle r, int z0, int z1, bool darkSides)
          {
              this.Cube(r.X, r.Y, r.Right, r.Bottom, z0, z1, darkSides);
          }
  
          public void Cube(int left, int top, int right, int bottom, int z0, int z1, bool darkSides)
          {
              Color c = this.Brush.Color;
              Point point = this.Calc3DPoint(left, top, z0);
              Point point2 = this.Calc3DPoint(right, top, z0);
              Point point3 = this.Calc3DPoint(right, bottom, z0);
              Point point4 = this.Calc3DPoint(right, top, z1);
              this.IPoints[0] = point;
              this.IPoints[1] = point2;
              this.IPoints[2] = point3;
              this.IPoints[3] = this.Calc3DPoint(left, bottom, z0);
              if (this.Culling() > 0.0)
              {
                  this.PolygonFour();
              }
              else
              {
                  this.Calc3DPos(ref this.IPoints[0], left, top, z1);
                  this.Calc3DPos(ref this.IPoints[1], right, top, z1);
  
gt:                 this.Calc3DPos(ref this.IPoints[2], right, bottom, z1);