public void AddChart(ChartStyle2D cs, DataSeriesSurface ds)
        {
            switch (ChartType)
            {
            case ChartTypeEnum.XYColor:
                cs.AddChartStyle2D(this);
                if (cs.IsColorBar && IsColormap)
                {
                    cs.AddColorBar2D(cs, ds, this, ds.ZDataMin(), ds.ZDataMax());
                }
                AddXYColor(cs, ds);
                break;

            case ChartTypeEnum.Contour:
                cs.AddChartStyle2D(this);
                if (cs.IsColorBar && IsColormap)
                {
                    cs.AddColorBar2D(cs, ds, this, ds.ZDataMin(), ds.ZDataMax());
                }
                AddContour(cs, ds);
                break;

            case ChartTypeEnum.FillContour:
                cs.AddChartStyle2D(this);
                if (cs.IsColorBar && IsColormap)
                {
                    cs.AddColorBar2D(cs, ds, this, ds.ZDataMin(), ds.ZDataMax());
                }
                AddXYColor(cs, ds);
                AddContour(cs, ds);
                break;

            case ChartTypeEnum.MeshContour3D:
                cs.AddChartStyle();
                AddContour3D(cs, ds);
                AddMesh(cs, ds);
                break;

            case ChartTypeEnum.SurfaceContour3D:
                cs.AddChartStyle();
                AddContour3D(cs, ds);
                AddSurface(cs, ds);
                break;

            case ChartTypeEnum.SurfaceFillContour3D:
                cs.AddChartStyle();
                AddXYColor3D(cs, ds);
                AddContour3D(cs, ds);
                AddSurface(cs, ds);
                break;
            }
        }
        private void AddXYColor(ChartStyle2D cs2d, DataSeriesSurface ds)
        {
            Point3D[,] pts = ds.PointArray;
            double zmin = ds.ZDataMin();
            double zmax = ds.ZDataMax();

            // Draw surface on the XY plane:
            if (!IsInterp)
            {
                for (int i = 0; i < pts.GetLength(0) - 1; i++)
                {
                    for (int j = 0; j < pts.GetLength(1) - 1; j++)
                    {
                        plg                 = new Polygon();
                        plg.Stroke          = ds.LineColor;
                        plg.StrokeThickness = ds.LineThickness;
                        plg.Fill            = GetBrush(pts[i, j].Z, zmin, zmax);
                        if (IsLineColorMatch)
                        {
                            plg.Stroke = GetBrush(pts[i, j].Z, zmin, zmax);
                        }
                        plg.Points.Add(cs2d.NormalizePoint(new Point(pts[i, j].X, pts[i, j].Y)));
                        plg.Points.Add(cs2d.NormalizePoint(new Point(pts[i, j + 1].X, pts[i, j + 1].Y)));
                        plg.Points.Add(cs2d.NormalizePoint(new Point(pts[i + 1, j + 1].X, pts[i + 1, j + 1].Y)));
                        plg.Points.Add(cs2d.NormalizePoint(new Point(pts[i + 1, j].X, pts[i + 1, j].Y)));
                        cs2d.Chart2dCanvas.Children.Add(plg);
                    }
                }
            }
            else if (IsInterp)
            {
                for (int i = 0; i < pts.GetLength(0) - 1; i++)
                {
                    for (int j = 0; j < pts.GetLength(1) - 1; j++)
                    {
                        Point3D[] points = new Point3D[4];
                        points[0] = pts[i, j];
                        points[1] = pts[i, j + 1];
                        points[2] = pts[i + 1, j + 1];
                        points[3] = pts[i + 1, j];

                        Interp2D(cs2d, points, zmin, zmax);
                        plg        = new Polygon();
                        plg.Stroke = ds.LineColor;
                        if (IsLineColorMatch)
                        {
                            plg.Stroke = GetBrush(pts[i, j].Z, zmin, zmax);
                        }
                        plg.StrokeThickness = ds.LineThickness;
                        plg.Fill            = Brushes.Transparent;
                        plg.Points.Add(cs2d.NormalizePoint(new Point(pts[i, j].X, pts[i, j].Y)));
                        plg.Points.Add(cs2d.NormalizePoint(new Point(pts[i, j + 1].X, pts[i, j + 1].Y)));
                        plg.Points.Add(cs2d.NormalizePoint(new Point(pts[i + 1, j + 1].X, pts[i + 1, j + 1].Y)));
                        plg.Points.Add(cs2d.NormalizePoint(new Point(pts[i + 1, j].X, pts[i + 1, j].Y)));
                        cs2d.Chart2dCanvas.Children.Add(plg);
                    }
                }
            }
        }
        private void AddXYColor3D(ChartStyle cs, DataSeriesSurface ds)
        {
            Point3D[,] pts  = ds.PointArray;
            Point3D[,] pts1 = new Point3D[pts.GetLength(0), pts.GetLength(1)];
            Matrix3D m   = Utility.AzimuthElevation(cs.Elevation, cs.Azimuth);
            Polygon  plg = new Polygon();

            // Find the minumum and maximum z values:
            double zmin = ds.ZDataMin();
            double zmax = ds.ZDataMax();

            // Perform transformation on points:
            for (int i = 0; i < pts.GetLength(0); i++)
            {
                for (int j = 0; j < pts.GetLength(1); j++)
                {
                    // Make a deep copy the points array:
                    pts1[i, j] = new Point3D(pts[i, j].X, pts[i, j].Y, cs.Zmin);
                    pts1[i, j] = cs.Normalize3D(m, pts1[i, j]);
                }
            }

            // Draw surface on the XY plane:
            for (int i = 0; i < pts.GetLength(0) - 1; i++)
            {
                for (int j = 0; j < pts.GetLength(1) - 1; j++)
                {
                    plg = new Polygon();
                    plg.Points.Add(new Point(pts1[i, j].X, pts1[i, j].Y));
                    plg.Points.Add(new Point(pts1[i, j + 1].X, pts1[i, j + 1].Y));
                    plg.Points.Add(new Point(pts1[i + 1, j + 1].X, pts1[i + 1, j + 1].Y));
                    plg.Points.Add(new Point(pts1[i + 1, j].X, pts1[i + 1, j].Y));
                    plg.StrokeThickness = ds.LineThickness;
                    plg.Fill            = GetBrush(pts[i, j].Z, zmin, zmax);
                    plg.Stroke          = GetBrush(pts[i, j].Z, zmin, zmax);
                    cs.ChartCanvas.Children.Add(plg);
                }
            }
        }
        public void AddSurface(ChartStyle cs, DataSeriesSurface ds)
        {
            Matrix3D m   = Utility.AzimuthElevation(cs.Elevation, cs.Azimuth);
            Polygon  plg = new Polygon();

            Point3D[,] pts  = ds.PointArray;
            Point3D[,] pts1 = new Point3D[pts.GetLength(0), pts.GetLength(1)];
            //double[,] zValues = new double[pts.GetLength(0), pts.GetLength(1)];
            double zmin = ds.ZDataMin();
            double zmax = ds.ZDataMax();

            for (int i = 0; i < pts.GetLength(0); i++)
            {
                for (int j = 0; j < pts.GetLength(1); j++)
                {
                    //zValues[i, j] = pts[i, j].Z;
                    pts1[i, j] = pts[i, j];
                    pts[i, j]  = cs.Normalize3D(m, pts[i, j]);
                }
            }

            // Draw surface chart:
            if (!IsInterp)
            {
                for (int i = 0; i < pts.GetLength(0) - 1; i++)
                {
                    int ii = i;
                    if (cs.Elevation >= 0)
                    {
                        ii = i;
                        if (cs.Azimuth >= -180 && cs.Azimuth < 0)
                        {
                            ii = pts.GetLength(0) - 2 - i;
                        }
                    }
                    else
                    {
                        ii = pts.GetLength(0) - 2 - i;
                        if (cs.Azimuth >= -180 && cs.Azimuth < 0)
                        {
                            ii = i;
                        }
                    }
                    for (int j = 0; j < pts.GetLength(1) - 1; j++)
                    {
                        int jj = j;
                        if (cs.Elevation < 0)
                        {
                            jj = pts.GetLength(1) - 2 - j;
                        }
                        plg = new Polygon();
                        plg.Points.Add(new Point(pts[ii, jj].X, pts[ii, jj].Y));
                        plg.Points.Add(new Point(pts[ii, jj + 1].X, pts[ii, jj + 1].Y));
                        plg.Points.Add(new Point(pts[ii + 1, jj + 1].X, pts[ii + 1, jj + 1].Y));
                        plg.Points.Add(new Point(pts[ii + 1, jj].X, pts[ii + 1, jj].Y));

                        plg.StrokeThickness = ds.LineThickness;
                        plg.Stroke          = ds.LineColor;
                        plg.Fill            = GetBrush(pts1[ii, jj].Z, zmin, zmax);
                        cs.ChartCanvas.Children.Add(plg);
                    }
                }
                if (cs.IsColorBar && IsColormap)
                {
                    AddColorBar(cs, ds, zmin, zmax);
                }
            }
            else if (IsInterp)
            {
                for (int i = 0; i < pts.GetLength(0) - 1; i++)
                {
                    int ii = i;
                    if (cs.Elevation >= 0)
                    {
                        ii = i;
                        if (cs.Azimuth >= -180 && cs.Azimuth < 0)
                        {
                            ii = pts.GetLength(0) - 2 - i;
                        }
                    }
                    else
                    {
                        ii = pts.GetLength(0) - 2 - i;
                        if (cs.Azimuth >= -180 && cs.Azimuth < 0)
                        {
                            ii = i;
                        }
                    }
                    for (int j = 0; j < pts.GetLength(1) - 1; j++)
                    {
                        int jj = j;
                        if (cs.Elevation < 0)
                        {
                            jj = pts.GetLength(1) - 2 - j;
                        }

                        Point3D[] points = new Point3D[4];
                        points[0] = pts1[ii, j];
                        points[1] = pts1[ii, j + 1];
                        points[2] = pts1[ii + 1, j + 1];
                        points[3] = pts1[ii + 1, j];
                        Interp(cs, m, points, zmin, zmax);
                        plg        = new Polygon();
                        plg.Stroke = ds.LineColor;
                        plg.Points.Add(new Point(pts[ii, j].X, pts[ii, j].Y));
                        plg.Points.Add(new Point(pts[ii, j + 1].X, pts[ii, j + 1].Y));
                        plg.Points.Add(new Point(pts[ii + 1, j + 1].X, pts[ii + 1, j + 1].Y));
                        plg.Points.Add(new Point(pts[ii + 1, j].X, pts[ii + 1, j].Y));
                        cs.ChartCanvas.Children.Add(plg);
                    }
                }
            }
            if (cs.IsColorBar && IsColormap)
            {
                AddColorBar(cs, ds, zmin, zmax);
            }
        }
        private void AddWaterfall(ChartStyle cs, DataSeriesSurface ds)
        {
            Matrix3D m   = Utility.AzimuthElevation(cs.Elevation, cs.Azimuth);
            Polygon  plg = new Polygon();

            Point3D[,] pts = ds.PointArray;
            Point3D[] pt3     = new Point3D[pts.GetLength(0) + 2];
            double[]  zValues = new double[pts.Length];
            Point[]   pta     = new Point[pts.GetLength(0) + 2];
            double    zmin    = ds.ZDataMin();
            double    zmax    = ds.ZDataMax();

            for (int j = 0; j < pts.GetLength(1); j++)
            {
                int jj = j;
                if (cs.Elevation >= 0)
                {
                    if (cs.Azimuth >= -90 && cs.Azimuth < 90)
                    {
                        jj = pts.GetLength(1) - 1 - j;
                    }
                }
                else if (cs.Elevation < 0)
                {
                    jj = pts.GetLength(1) - 1 - j;
                    if (cs.Azimuth >= -90 && cs.Azimuth < 90)
                    {
                        jj = j;
                    }
                }
                for (int i = 0; i < pts.GetLength(0); i++)
                {
                    pt3[i + 1] = pts[i, jj];

                    if (i == 0)
                    {
                        pt3[0] = new Point3D(pt3[i + 1].X, pt3[i + 1].Y, cs.Zmin);
                    }
                    if (i == pts.GetLength(0) - 1)
                    {
                        pt3[pts.GetLength(0) + 1] = new Point3D(pt3[i + 1].X, pt3[i + 1].Y, cs.Zmin);
                    }
                }
                plg = new Polygon();
                for (int i = 0; i < pt3.Length; i++)
                {
                    zValues[i] = pt3[i].Z;
                    pt3[i]     = cs.Normalize3D(m, pt3[i]);
                    pta[i]     = new Point(pt3[i].X, pt3[i].Y);
                    plg.Points.Add(new Point(pt3[i].X, pt3[i].Y));
                }
                plg.Stroke          = Brushes.Transparent;
                plg.StrokeThickness = ds.LineThickness;
                plg.Fill            = Brushes.White;
                cs.ChartCanvas.Children.Add(plg);

                for (int i = 1; i < pt3.Length; i++)
                {
                    Line line = new Line();
                    line.Stroke          = Brushes.Black;
                    line.StrokeThickness = ds.LineThickness;
                    if (IsColormap)
                    {
                        if (i < pt3.Length - 1)
                        {
                            line.Stroke = GetBrush(zValues[i], zmin, zmax);
                        }
                        else
                        {
                            line.Stroke = GetBrush(zValues[i - 1], zmin, zmax);
                        }
                    }
                    line.X1 = pta[i - 1].X;
                    line.Y1 = pta[i - 1].Y;
                    line.X2 = pta[i].X;
                    line.Y2 = pta[i].Y;
                    cs.ChartCanvas.Children.Add(line);
                }
            }

            if (cs.IsColorBar && IsColormap)
            {
                AddColorBar(cs, ds, zmin, zmax);
            }
        }
        private void AddMeshZ(ChartStyle cs, DataSeriesSurface ds)
        {
            Matrix3D m   = Utility.AzimuthElevation(cs.Elevation, cs.Azimuth);
            Polygon  plg = new Polygon();

            Point3D[,] pts    = ds.PointArray;
            Point3D[,] pts1   = new Point3D[pts.GetLength(0), pts.GetLength(1)];
            double[,] zValues = new double[pts.GetLength(0), pts.GetLength(1)];
            double zmin = ds.ZDataMin();
            double zmax = ds.ZDataMax();

            for (int i = 0; i < pts.GetLength(0); i++)
            {
                for (int j = 0; j < pts.GetLength(1); j++)
                {
                    zValues[i, j] = pts[i, j].Z;
                    pts1[i, j]    = new Point3D(pts[i, j].X, pts[i, j].Y, pts[i, j].Z);
                    pts[i, j]     = cs.Normalize3D(m, pts[i, j]);
                }
            }

            // Draw mesh using the z-order method:
            for (int i = 0; i < pts.GetLength(0) - 1; i++)
            {
                int ii = i;
                if (cs.Elevation >= 0)
                {
                    ii = i;
                    if (cs.Azimuth >= -180 && cs.Azimuth < 0)
                    {
                        ii = pts.GetLength(0) - 2 - i;
                    }
                }
                else
                {
                    ii = pts.GetLength(0) - 2 - i;
                    if (cs.Azimuth >= -180 && cs.Azimuth < 0)
                    {
                        ii = i;
                    }
                }
                for (int j = 0; j < pts.GetLength(1) - 1; j++)
                {
                    int jj = j;
                    if (cs.Elevation < 0)
                    {
                        jj = pts.GetLength(1) - 2 - j;
                    }
                    plg = new Polygon();
                    plg.Points.Add(new Point(pts[ii, jj].X, pts[ii, jj].Y));
                    plg.Points.Add(new Point(pts[ii, jj + 1].X, pts[ii, jj + 1].Y));
                    plg.Points.Add(new Point(pts[ii + 1, jj + 1].X, pts[ii + 1, jj + 1].Y));
                    plg.Points.Add(new Point(pts[ii + 1, jj].X, pts[ii + 1, jj].Y));

                    plg.Stroke          = Brushes.Black;
                    plg.StrokeThickness = ds.LineThickness;
                    plg.Fill            = Brushes.White;
                    if (!IsHiddenLine)
                    {
                        plg.Fill = Brushes.Transparent;
                    }
                    if (IsColormap)
                    {
                        plg.Stroke = GetBrush(zValues[ii, jj], zmin, zmax);
                    }
                    cs.ChartCanvas.Children.Add(plg);
                }
            }

            //Draw curtain lines:
            Point3D[] pta = new Point3D[4];
            for (int i = 0; i < pts1.GetLength(0); i++)
            {
                int jj = pts1.GetLength(0) - 1;
                if (cs.Elevation >= 0)
                {
                    if (cs.Azimuth >= -90 && cs.Azimuth <= 90)
                    {
                        jj = 0;
                    }
                }
                else if (cs.Elevation < 0)
                {
                    jj = 0;
                    if (cs.Azimuth >= -90 && cs.Azimuth <= 90)
                    {
                        jj = pts1.GetLength(0) - 1;
                    }
                }

                if (i < pts1.GetLength(0) - 1)
                {
                    pta[0] = new Point3D(pts1[i, jj].X, pts1[i, jj].Y, pts1[i, jj].Z);
                    pta[1] = new Point3D(pts1[i + 1, jj].X, pts1[i + 1, jj].Y, pts1[i + 1, jj].Z);
                    pta[2] = new Point3D(pts1[i + 1, jj].X, pts1[i + 1, jj].Y, cs.Zmin);
                    pta[3] = new Point3D(pts1[i, jj].X, pts1[i, jj].Y, cs.Zmin);
                    for (int k = 0; k < 4; k++)
                    {
                        pta[k] = cs.Normalize3D(m, pta[k]);
                    }
                    plg                 = new Polygon();
                    plg.Stroke          = Brushes.Black;
                    plg.StrokeThickness = ds.LineThickness;
                    plg.Fill            = Brushes.White;
                    plg.Points.Add(new Point(pta[0].X, pta[0].Y));
                    plg.Points.Add(new Point(pta[1].X, pta[1].Y));
                    plg.Points.Add(new Point(pta[2].X, pta[2].Y));
                    plg.Points.Add(new Point(pta[3].X, pta[3].Y));
                    if (!IsHiddenLine)
                    {
                        plg.Fill = Brushes.Transparent;
                    }
                    if (IsColormap)
                    {
                        plg.Stroke = GetBrush(pts1[i, jj].Z, zmin, zmax);
                    }
                    cs.ChartCanvas.Children.Add(plg);
                }
            }

            for (int j = 0; j < pts1.GetLength(1); j++)
            {
                int ii = 0;
                if (cs.Elevation >= 0)
                {
                    if (cs.Azimuth >= 0 && cs.Azimuth <= 180)
                    {
                        ii = pts1.GetLength(1) - 1;
                    }
                }
                else if (cs.Elevation < 0)
                {
                    if (cs.Azimuth >= -180 && cs.Azimuth <= 0)
                    {
                        ii = pts1.GetLength(1) - 1;
                    }
                }
                if (j < pts1.GetLength(1) - 1)
                {
                    pta[0] = new Point3D(pts1[ii, j].X, pts1[ii, j].Y, pts1[ii, j].Z);
                    pta[1] = new Point3D(pts1[ii, j + 1].X, pts1[ii, j + 1].Y, pts1[ii, j + 1].Z);
                    pta[2] = new Point3D(pts1[ii, j + 1].X, pts1[ii, j + 1].Y, cs.Zmin);
                    pta[3] = new Point3D(pts1[ii, j].X, pts1[ii, j].Y, cs.Zmin);
                    for (int k = 0; k < 4; k++)
                    {
                        pta[k] = cs.Normalize3D(m, pta[k]);
                    }
                    plg                 = new Polygon();
                    plg.Stroke          = Brushes.Black;
                    plg.StrokeThickness = ds.LineThickness;
                    plg.Fill            = Brushes.White;
                    plg.Points.Add(new Point(pta[0].X, pta[0].Y));
                    plg.Points.Add(new Point(pta[1].X, pta[1].Y));
                    plg.Points.Add(new Point(pta[2].X, pta[2].Y));
                    plg.Points.Add(new Point(pta[3].X, pta[3].Y));
                    if (!IsHiddenLine)
                    {
                        plg.Fill = Brushes.Transparent;
                    }
                    if (IsColormap)
                    {
                        plg.Stroke = GetBrush(pts1[ii, j].Z, zmin, zmax);
                    }
                    cs.ChartCanvas.Children.Add(plg);
                }
            }

            if (cs.IsColorBar && IsColormap)
            {
                AddColorBar(cs, ds, zmin, zmax);
            }
        }
        public void AddMesh(ChartStyle cs, DataSeriesSurface ds)
        {
            Matrix3D m   = Utility.AzimuthElevation(cs.Elevation, cs.Azimuth);
            Polygon  plg = new Polygon();

            Point3D[,] pts    = ds.PointArray;
            double[,] zValues = new double[pts.GetLength(0), pts.GetLength(1)];
            double zmin = ds.ZDataMin();
            double zmax = ds.ZDataMax();

            for (int i = 0; i < pts.GetLength(0); i++)
            {
                for (int j = 0; j < pts.GetLength(1); j++)
                {
                    zValues[i, j] = pts[i, j].Z;
                    pts[i, j]     = cs.Normalize3D(m, pts[i, j]);
                }
            }

            // Draw mesh chart:
            for (int i = 0; i < pts.GetLength(0) - 1; i++)
            {
                int ii = i;
                if (cs.Elevation >= 0)
                {
                    ii = i;
                    if (cs.Azimuth >= -180 && cs.Azimuth < 0)
                    {
                        ii = pts.GetLength(0) - 2 - i;
                    }
                }
                else
                {
                    ii = pts.GetLength(0) - 2 - i;
                    if (cs.Azimuth >= -180 && cs.Azimuth < 0)
                    {
                        ii = i;
                    }
                }
                for (int j = 0; j < pts.GetLength(1) - 1; j++)
                {
                    int jj = j;
                    if (cs.Elevation < 0)
                    {
                        jj = pts.GetLength(1) - 2 - j;
                    }
                    plg = new Polygon();
                    plg.Points.Add(new Point(pts[ii, jj].X, pts[ii, jj].Y));
                    plg.Points.Add(new Point(pts[ii, jj + 1].X, pts[ii, jj + 1].Y));
                    plg.Points.Add(new Point(pts[ii + 1, jj + 1].X, pts[ii + 1, jj + 1].Y));
                    plg.Points.Add(new Point(pts[ii + 1, jj].X, pts[ii + 1, jj].Y));

                    plg.Stroke          = Brushes.Black;
                    plg.StrokeThickness = ds.LineThickness;
                    plg.Fill            = Brushes.White;
                    if (!IsHiddenLine)
                    {
                        plg.Fill = Brushes.Transparent;
                    }
                    if (IsColormap)
                    {
                        plg.Stroke = GetBrush(zValues[ii, jj], zmin, zmax);
                    }
                    cs.ChartCanvas.Children.Add(plg);
                }
            }
            if (cs.IsColorBar && IsColormap)
            {
                AddColorBar(cs, ds, zmin, zmax);
            }
        }
        private void AddContour3D(ChartStyle cs, DataSeriesSurface ds)
        {
            Point3D[] pta = new Point3D[2];
            Point3D[,] pts = ds.PointArray;
            Matrix3D        m     = Utility.AzimuthElevation(cs.Elevation, cs.Azimuth);
            SolidColorBrush brush = Brushes.Black;

            // Find the minumum and maximum z values:
            double zmin = ds.ZDataMin();
            double zmax = ds.ZDataMax();

            double[] zlevels = new Double[NumberContours];
            for (int i = 0; i < NumberContours; i++)
            {
                zlevels[i] = zmin + i * (zmax - zmin) / (NumberContours - 1);
            }

            int    i0, i1, i2, j0, j1, j2;
            double zratio = 1;

            // Draw contour on the XY plane:
            for (int i = 0; i < pts.GetLength(0) - 1; i++)
            {
                for (int j = 0; j < pts.GetLength(1) - 1; j++)
                {
                    if (IsColormap && ChartType != ChartTypeEnum.FillContour)
                    {
                        brush = GetBrush(pts[i, j].Z, zmin, zmax);
                    }
                    for (int k = 0; k < numberContours; k++)
                    {
                        // Left triangle:
                        i0 = i;
                        j0 = j;
                        i1 = i;
                        j1 = j + 1;
                        i2 = i + 1;
                        j2 = j + 1;
                        if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k] <
                             pts[i1, j1].Z || zlevels[k] < pts[i0, j0].Z &&
                             zlevels[k] >= pts[i1, j1].Z) &&
                            (zlevels[k] >= pts[i1, j1].Z && zlevels[k]
                             < pts[i2, j2].Z || zlevels[k] < pts[i1, j1].Z &&
                             zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i1, j1].Z - pts[i0, j0].Z);
                            pta[0] = new Point3D(pts[i0, j0].X, (1 - zratio) * pts[i0, j0].Y + zratio * pts[i1, j1].Y, cs.Zmin);
                            zratio = (zlevels[k] - pts[i1, j1].Z) / (pts[i2, j2].Z - pts[i1, j1].Z);
                            pta[1] = new Point3D((1 - zratio) * pts[i1, j1].X + zratio * pts[i2, j2].X, pts[i1, j1].Y, cs.Zmin);
                            pta[0] = cs.Normalize3D(m, pta[0]);
                            pta[1] = cs.Normalize3D(m, pta[1]);
                            DrawLine3D(cs, ds, brush, new Point(pta[0].X, pta[0].Y), new Point(pta[1].X, pta[1].Y));
                        }
                        else if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k]
                                  < pts[i2, j2].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i2, j2].Z) &&
                                 (zlevels[k] >= pts[i1, j1].Z && zlevels[k]
                                  < pts[i2, j2].Z || zlevels[k] < pts[i1, j1].Z &&
                                  zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) / (pts[i2, j2].Z - pts[i0, j0].Z);
                            pta[0] = new Point3D((1 - zratio) * pts[i0, j0].X + zratio * pts[i2, j2].X, (1 - zratio) * pts[i0, j0].Y +
                                                 zratio * pts[i2, j2].Y, cs.Zmin);
                            zratio = (zlevels[k] - pts[i1, j1].Z) / (pts[i2, j2].Z - pts[i1, j1].Z);
                            pta[1] = new Point3D((1 - zratio) * pts[i1, j1].X + zratio * pts[i2, j2].X, pts[i1, j1].Y, cs.Zmin);
                            pta[0] = cs.Normalize3D(m, pta[0]);
                            pta[1] = cs.Normalize3D(m, pta[1]);
                            DrawLine3D(cs, ds, brush, new Point(pta[0].X, pta[0].Y), new Point(pta[1].X, pta[1].Y));
                        }
                        else if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k]
                                  < pts[i1, j1].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i1, j1].Z) &&
                                 (zlevels[k] >= pts[i0, j0].Z && zlevels[k]
                                  < pts[i2, j2].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i1, j1].Z - pts[i0, j0].Z);
                            pta[0] = new Point3D(pts[i0, j0].X, (1 - zratio) * pts[i0, j0].Y + zratio * pts[i1, j1].Y, cs.Zmin);
                            zratio = (zlevels[k] - pts[i0, j0].Z) / (pts[i2, j2].Z - pts[i0, j0].Z);
                            pta[1] = new Point3D(pts[i0, j0].X * (1 - zratio) + pts[i2, j2].X * zratio,
                                                 pts[i0, j0].Y * (1 - zratio) + pts[i2, j2].Y * zratio, cs.Zmin);
                            pta[0] = cs.Normalize3D(m, pta[0]);
                            pta[1] = cs.Normalize3D(m, pta[1]);
                            DrawLine3D(cs, ds, brush, new Point(pta[0].X, pta[0].Y), new Point(pta[1].X, pta[1].Y));
                        }

                        // right triangle:
                        i0 = i;
                        j0 = j;
                        i1 = i + 1;
                        j1 = j;
                        i2 = i + 1;
                        j2 = j + 1;
                        if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k] <
                             pts[i1, j1].Z || zlevels[k] < pts[i0, j0].Z &&
                             zlevels[k] >= pts[i1, j1].Z) &&
                            (zlevels[k] >= pts[i1, j1].Z && zlevels[k]
                             < pts[i2, j2].Z || zlevels[k] < pts[i1, j1].Z &&
                             zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i1, j1].Z - pts[i0, j0].Z);
                            pta[0] = new Point3D(pts[i0, j0].X * (1 - zratio) + pts[i1, j1].X * zratio, pts[i0, j0].Y, cs.Zmin);
                            zratio = (zlevels[k] - pts[i1, j1].Z) / (pts[i2, j2].Z - pts[i1, j1].Z);
                            pta[1] = new Point3D(pts[i1, j1].X, pts[i1, j1].Y * (1 - zratio) + pts[i2, j2].Y * zratio, cs.Zmin);
                            pta[0] = cs.Normalize3D(m, pta[0]);
                            pta[1] = cs.Normalize3D(m, pta[1]);
                            DrawLine3D(cs, ds, brush, new Point(pta[0].X, pta[0].Y), new Point(pta[1].X, pta[1].Y));
                        }
                        else if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k]
                                  < pts[i2, j2].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i2, j2].Z) &&
                                 (zlevels[k] >= pts[i1, j1].Z && zlevels[k] <
                                  pts[i2, j2].Z || zlevels[k] < pts[i1, j1].Z &&
                                  zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i2, j2].Z - pts[i0, j0].Z);
                            pta[0] = new Point3D(pts[i0, j0].X * (1 - zratio) + pts[i2, j2].X * zratio,
                                                 pts[i0, j0].Y * (1 - zratio) + pts[i2, j2].Y * zratio, cs.Zmin);
                            zratio = (zlevels[k] - pts[i1, j1].Z) / (pts[i2, j2].Z - pts[i1, j1].Z);
                            pta[1] = new Point3D(pts[i1, j1].X, pts[i1, j1].Y * (1 - zratio) + pts[i2, j2].Y * zratio, cs.Zmin);
                            pta[0] = cs.Normalize3D(m, pta[0]);
                            pta[1] = cs.Normalize3D(m, pta[1]);
                            DrawLine3D(cs, ds, brush, new Point(pta[0].X, pta[0].Y), new Point(pta[1].X, pta[1].Y));
                        }
                        else if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k]
                                  < pts[i1, j1].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i1, j1].Z) &&
                                 (zlevels[k] >= pts[i0, j0].Z && zlevels[k] <
                                  pts[i2, j2].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) / (pts[i1, j1].Z - pts[i0, j0].Z);
                            pta[0] = new Point3D(pts[i0, j0].X * (1 - zratio) + pts[i1, j1].X * zratio, pts[i0, j0].Y, cs.Zmin);
                            zratio = (zlevels[k] - pts[i0, j0].Z) / (pts[i2, j2].Z - pts[i0, j0].Z);
                            pta[1] = new Point3D(pts[i0, j0].X * (1 - zratio) + pts[i2, j2].X * zratio,
                                                 pts[i0, j0].Y * (1 - zratio) + pts[i2, j2].Y * zratio, cs.Zmin);
                            pta[0] = cs.Normalize3D(m, pta[0]);
                            pta[1] = cs.Normalize3D(m, pta[1]);
                            DrawLine3D(cs, ds, brush, new Point(pta[0].X, pta[0].Y), new Point(pta[1].X, pta[1].Y));
                        }
                    }
                }
            }
        }
        private void AddContour(ChartStyle2D cs2d, DataSeriesSurface ds)
        {
            Point[]         pta   = new Point[2];
            SolidColorBrush brush = Brushes.Black;
            Line            line  = new Line();

            Point3D[,] pts = ds.PointArray;
            double zmin = ds.ZDataMin();
            double zmax = ds.ZDataMax();

            double[] zlevels = new double[NumberContours];

            for (int i = 0; i < NumberContours; i++)
            {
                zlevels[i] = zmin + i * (zmax - zmin) / (NumberContours - 1);
            }

            int    i0, i1, i2, j0, j1, j2;
            double zratio = 1;

            // Draw contour on the XY plane:
            for (int i = 0; i < pts.GetLength(0) - 1; i++)
            {
                for (int j = 0; j < pts.GetLength(1) - 1; j++)
                {
                    if (IsColormap && ChartType != ChartTypeEnum.FillContour)
                    {
                        brush = GetBrush(pts[i, j].Z, zmin, zmax);
                    }
                    for (int k = 0; k < NumberContours; k++)
                    {
                        // Left triangle:
                        i0 = i;
                        j0 = j;
                        i1 = i;
                        j1 = j + 1;
                        i2 = i + 1;
                        j2 = j + 1;
                        if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k] < pts[i1, j1].Z ||
                             zlevels[k] < pts[i0, j0].Z && zlevels[k] >= pts[i1, j1].Z) &&
                            (zlevels[k] >= pts[i1, j1].Z && zlevels[k] <
                             pts[i2, j2].Z || zlevels[k] < pts[i1, j1].Z && zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i1, j1].Z - pts[i0, j0].Z);
                            pta[0] = cs2d.NormalizePoint(new Point(pts[i0, j0].X, (1 - zratio) * pts[i0, j0].Y + zratio * pts[i1, j1].Y));
                            zratio = (zlevels[k] - pts[i1, j1].Z) / (pts[i2, j2].Z - pts[i1, j1].Z);
                            pta[1] = cs2d.NormalizePoint(new Point((1 - zratio) * pts[i1, j1].X + zratio * pts[i2, j2].X, pts[i1, j1].Y));
                            DrawLine(cs2d, ds, brush, pta[0], pta[1]);
                        }
                        else if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k]
                                  < pts[i2, j2].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i2, j2].Z) &&
                                 (zlevels[k] >= pts[i1, j1].Z && zlevels[k] <
                                  pts[i2, j2].Z || zlevels[k] < pts[i1, j1].Z &&
                                  zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i2, j2].Z - pts[i0, j0].Z);
                            pta[0] = cs2d.NormalizePoint(new Point((1 - zratio) * pts[i0, j0].X + zratio * pts[i2, j2].X,
                                                                   (1 - zratio) * pts[i0, j0].Y + zratio * pts[i2, j2].Y));
                            zratio = (zlevels[k] - pts[i1, j1].Z) / (pts[i2, j2].Z - pts[i1, j1].Z);
                            pta[1] = cs2d.NormalizePoint(new Point((1 - zratio) * pts[i1, j1].X + zratio * pts[i2, j2].X, pts[i1, j1].Y));
                            DrawLine(cs2d, ds, brush, pta[0], pta[1]);
                        }
                        else if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k]
                                  < pts[i1, j1].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i1, j1].Z) &&
                                 (zlevels[k] >= pts[i0, j0].Z && zlevels[k] <
                                  pts[i2, j2].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i1, j1].Z - pts[i0, j0].Z);
                            pta[0] = cs2d.NormalizePoint(new Point(pts[i0, j0].X, (1 - zratio) * pts[i0, j0].Y + zratio * pts[i1, j1].Y));
                            zratio = (zlevels[k] - pts[i0, j0].Z) / (pts[i2, j2].Z - pts[i0, j0].Z);
                            pta[1] = cs2d.NormalizePoint(new Point(pts[i0, j0].X * (1 - zratio) + pts[i2, j2].X * zratio,
                                                                   pts[i0, j0].Y * (1 - zratio) + pts[i2, j2].Y * zratio));
                            DrawLine(cs2d, ds, brush, pta[0], pta[1]);
                        }

                        // right triangle:
                        i0 = i;
                        j0 = j;
                        i1 = i + 1;
                        j1 = j;
                        i2 = i + 1;
                        j2 = j + 1;
                        if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k] <
                             pts[i1, j1].Z || zlevels[k] < pts[i0, j0].Z &&
                             zlevels[k] >= pts[i1, j1].Z) &&
                            (zlevels[k] >= pts[i1, j1].Z && zlevels[k]
                             < pts[i2, j2].Z || zlevels[k] < pts[i1, j1].Z &&
                             zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i1, j1].Z - pts[i0, j0].Z);
                            pta[0] = cs2d.NormalizePoint(new Point(pts[i0, j0].X * (1 - zratio) + pts[i1, j1].X * zratio, pts[i0, j0].Y));
                            zratio = (zlevels[k] - pts[i1, j1].Z) / (pts[i2, j2].Z - pts[i1, j1].Z);
                            pta[1] = cs2d.NormalizePoint(new Point(pts[i1, j1].X, pts[i1, j1].Y * (1 - zratio) + pts[i2, j2].Y * zratio));
                            DrawLine(cs2d, ds, brush, pta[0], pta[1]);
                        }
                        else if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k]
                                  < pts[i2, j2].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i2, j2].Z) &&
                                 (zlevels[k] >= pts[i1, j1].Z && zlevels[k] <
                                  pts[i2, j2].Z || zlevels[k] < pts[i1, j1].Z &&
                                  zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i2, j2].Z - pts[i0, j0].Z);
                            pta[0] = cs2d.NormalizePoint(new Point(pts[i0, j0].X * (1 - zratio) +
                                                                   pts[i2, j2].X * zratio, pts[i0, j0].Y * (1 - zratio) + pts[i2, j2].Y * zratio));
                            zratio = (zlevels[k] - pts[i1, j1].Z) / (pts[i2, j2].Z - pts[i1, j1].Z);
                            pta[1] = cs2d.NormalizePoint(new Point(pts[i1, j1].X, pts[i1, j1].Y * (1 - zratio) + pts[i2, j2].Y * zratio));
                            DrawLine(cs2d, ds, brush, pta[0], pta[1]);
                        }
                        else if ((zlevels[k] >= pts[i0, j0].Z && zlevels[k]
                                  < pts[i1, j1].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i1, j1].Z) &&
                                 (zlevels[k] >= pts[i0, j0].Z && zlevels[k] <
                                  pts[i2, j2].Z || zlevels[k] < pts[i0, j0].Z &&
                                  zlevels[k] >= pts[i2, j2].Z))
                        {
                            zratio = (zlevels[k] - pts[i0, j0].Z) /
                                     (pts[i1, j1].Z - pts[i0, j0].Z);
                            pta[0] = cs2d.NormalizePoint(new Point(pts[i0, j0].X * (1 - zratio) + pts[i1, j1].X * zratio, pts[i0, j0].Y));
                            zratio = (zlevels[k] - pts[i0, j0].Z) / (pts[i2, j2].Z - pts[i0, j0].Z);
                            pta[1] = cs2d.NormalizePoint(new Point(pts[i0, j0].X * (1 - zratio) + pts[i2, j2].X * zratio,
                                                                   pts[i0, j0].Y * (1 - zratio) + pts[i2, j2].Y * zratio));
                            DrawLine(cs2d, ds, brush, pta[0], pta[1]);
                        }
                    }
                }
            }
        }