private static void RecDrawOctree(Octree tree, IOctreeNode iOctreeNode, Vector3 LowerLocalCorner, int current_recursion)
        {
            if (iOctreeNode == null)
            {
                return;
            }


            double boxWidth = Math.Pow(2, -current_recursion);

            if (iOctreeNode is OctreeEndNode)
            {
                OctreeEndNode       oen = ((OctreeEndNode)iOctreeNode);
                SurfaceTangentPoint stp = new SurfaceTangentPoint();
                stp.SurfaceNormal = oen.SurfaceNormal;
                stp.Location      = tree.OctreeToWorld(LowerLocalCorner);
                RenderPoint(stp);
            }
            if (iOctreeNode is OctreeParent)
            {
                double       b      = boxWidth / 2;
                OctreeParent parent = (OctreeParent)iOctreeNode;

                RecDrawOctree(tree, parent.xyz, LowerLocalCorner + new Vector3(0, 0, 0), current_recursion + 1);
                RecDrawOctree(tree, parent.xyZ, LowerLocalCorner + new Vector3(0, 0, b), current_recursion + 1);
                RecDrawOctree(tree, parent.xYz, LowerLocalCorner + new Vector3(0, b, 0), current_recursion + 1);
                RecDrawOctree(tree, parent.xYZ, LowerLocalCorner + new Vector3(0, b, b), current_recursion + 1);

                RecDrawOctree(tree, parent.Xyz, LowerLocalCorner + new Vector3(b, 0, 0), current_recursion + 1);
                RecDrawOctree(tree, parent.XyZ, LowerLocalCorner + new Vector3(b, 0, b), current_recursion + 1);
                RecDrawOctree(tree, parent.XYz, LowerLocalCorner + new Vector3(b, b, 0), current_recursion + 1);
                RecDrawOctree(tree, parent.XYZ, LowerLocalCorner + new Vector3(b, b, b), current_recursion + 1);
            }
        }
        private static void RenderPoint(SurfaceTangentPoint point)
        {
            Vector3 v = transform(point.Location, false);

            if (v.Z > 0.001)
            {
                double x = v.X / v.Z;
                double y = v.Y / v.Z;
                if (-1 < x && x < 1 && -1 < y && y < 1)
                {
                    int _x = (int)((x + 1) * width / 2);
                    int _y = (int)((y + 1) * height / 2);
                    if (buffer[_x, _y].depth < 0.001 || (buffer[_x, _y].depth > 0.001 && buffer[_x, _y].depth > v.Z))
                    {
                        buffer[_x, _y].depth = v.Z;
                        double dot = -Vector3.Dot(transform(point.SurfaceNormal, true), light);
                        int    col = (int)(dot * 255);
                        if (col < 0)
                        {
                            col = 0;
                        }
                        buffer[_x, _y].color = Color.FromArgb(col, col, col);
                    }
                }
            }
        }
        public static List <SurfaceTangentPoint> Donut()
        {
            List <SurfaceTangentPoint> list = new List <SurfaceTangentPoint>();

            for (double a = 0; a < 1; a += .0005)
            {
                Vector3 v1 = new Vector3(3 * Math.Cos(a * Math.PI * 2), 3 * Math.Sin(a * Math.PI * 2), 0);
                for (double b = 0; b < 1; b += .0005)
                {
                    Vector3 v2 = new Vector3(Math.Cos(b * Math.PI * 2) * Math.Cos(a * Math.PI * 2), Math.Cos(b * Math.PI * 2) * Math.Sin(a * Math.PI * 2), Math.Sin(b * Math.PI * 2));
                    v2 = v2.Normalized();
                    SurfaceTangentPoint p = new SurfaceTangentPoint();
                    p.Location      = v1 + v2;
                    p.SurfaceNormal = v2;
                    list.Add(p);
                }
            }
            return(list);
        }