static void Main(string[] args)
        {
            //Parse the argument array in arbitrary order and give an interface to retrieve them
            Arguments a = new Arguments(args);
            //Read the input file specified in the arguments
            //PostscriptReader rdr = new PostscriptReader(a.InputFile);
            SMFReader rdr = new SMFReader(a.FirstModel);
            List<Polygon3D> prims = rdr.ReadFile();
            Matrix4<double> cameraTranslation = new Matrix4<double>
                (
                1, 0, 0, -a.VRP_X,
                0, 1, 0, -a.VRP_Y,
                0, 0, 1, -a.VRP_Z,
                0, 0, 0, 1
                );
            //Cross product
            double VRR_X = a.VUP_Y * a.VPN_Z - a.VUP_Z * a.VPN_Y;
            double VRR_Y = a.VUP_Z * a.VPN_X - a.VUP_X * a.VPN_Z;
            double VRR_Z = a.VUP_X * a.VPN_Y - a.VUP_Y * a.VPN_X;
            double normalizer = System.Math.Sqrt(System.Math.Pow(VRR_X, 2) + System.Math.Pow(VRR_Y, 2) + System.Math.Pow(VRR_Z, 2));
            VRR_X = VRR_X / normalizer;
            VRR_Y = VRR_Y / normalizer;
            VRR_Z = VRR_Z / normalizer;
            double normalizerVUP = System.Math.Sqrt(System.Math.Pow(a.VUP_X, 2) + System.Math.Pow(a.VUP_Y, 2) + System.Math.Pow(a.VUP_Z, 2));
            double VUP_X = a.VUP_X / normalizerVUP;
            double VUP_Y = a.VUP_Y / normalizerVUP;
            double VUP_Z = a.VUP_Z / normalizerVUP;
            double normalizerVPN = System.Math.Sqrt(System.Math.Pow(a.VPN_X, 2) + System.Math.Pow(a.VPN_Y, 2) + System.Math.Pow(a.VPN_Z, 2));
            double VPN_X = a.VPN_X / normalizerVPN;
            double VPN_Y = a.VPN_Y / normalizerVPN;
            double VPN_Z = a.VPN_Z / normalizerVPN;
            Matrix4<double> cameraRotation = new Matrix4<double>
                (
                VRR_X, VRR_Y, VRR_Z, 0,
                VUP_X, VUP_Y, VUP_Z, 0,
                VPN_X, VPN_Y, VPN_Z, 0,
                0, 0, 0, 1
                );

            Matrix4<double> projection;
            if (a.IsParallelProjection)
            {
                projection = Matrix4<double>.GetParallelProjectionMatrix(a.VRC_UMIN, a.VRC_UMAX, a.VRC_VMIN, a.VRC_VMAX, a.PRP_X, a.PRP_Y, a.PRP_Z, 0.6, -0.6);
                //projection *= Matrix4<double>.GetPerspectiveProjectionMatrix(a.VRC_UMIN, a.VRC_UMAX, a.VRC_VMIN, a.VRC_VMAX, a.PRP_X, a.PRP_Y, a.PRP_Z, -0.6);
            }
            else
            {
                projection = Matrix4<double>.GetPerspectiveProjectionMatrix(a.VRC_UMIN, a.VRC_UMAX, a.VRC_VMIN, a.VRC_VMAX, a.PRP_X, a.PRP_Y, a.PRP_Z, -0.6);
                //projection *= Matrix4<double>.GetParallelProjectionMatrix(a.VRC_UMIN, a.VRC_UMAX, a.VRC_VMIN, a.VRC_VMAX, a.PRP_X, a.PRP_Y, a.PRP_Z, 0.6, -0.6);
            }
            foreach (var p in prims)
            {
                //Transfrom into canonical orthogonal view volume to perform clipping?? Tried it and didn't get correct results. But this doesn't work either so something else must be wrong...
                p.ProjectAndView(cameraTranslation);
                p.ProjectAndView(cameraRotation);
                p.ProjectAndView(projection);
            }
            List<Polygon3D> acceptedPolys = new List<Polygon3D>();
            //Clip polygons -- this doesn't work
            foreach (var p in prims)
            {
                bool accept = false;
                foreach (var v in p)
                {
                    if (v.X > 1 || v.X < -1)
                    {
                        accept = false;
                    }
                    else if (v.Y > 1 || v.Y < -1)
                    {
                        accept = false;
                    }
                    else
                    {
                        accept = true;
                    }
                }

                if (accept)
                    acceptedPolys.Add(p);
            }
            //This is the part that I think is wrong but i'm not sure how to correct it. The scaling seems to be fine for parallel but not for perspective and the translation
            //is definitely wrong but i'm not sure what it should be. I have these as separate statements instead of matrix multiplication to make it easier to debug
            foreach (var p in acceptedPolys)
            {
                if (a.IsParallelProjection)
                {
                    foreach (var v in p)
                    {
                        v.X += 1;
                        v.Y += 1;
                        v.X *= (a.XUpper - a.XLower)/2;
                        v.Y *= (a.YUpper - a.YLower)/2;
                        v.X += a.VRC_UMIN;
                        v.Y += a.VRC_VMIN;
                    }
                }
                else
                {
                    //p.ProjectAndView(projection);
                    foreach (var v in p)
                    {
                        //Perspective division
                        v.X /= -v.Z;
                        v.Y /= -v.Z;
                        v.X += 1;
                        v.Y += 1;
                        v.X *= (a.VP_XUpper - a.VP_XLower) / 2;
                        v.Y *= (a.VP_YUpper - a.VP_YLower) / 2;
                        v.X += a.VRC_UMIN;
                        v.Y += a.VRC_VMIN;

                    }
                }

            }
            PixelBuffer pb = new PixelBuffer(a.XLower, a.XUpper, a.YLower, a.YUpper, a.VP_XLower, a.VP_XUpper, a.VP_YLower, a.VP_YUpper, a.BackPlaneVRC, a.FrontPlaneVRC);
            foreach (var p in acceptedPolys)
            {
                p.MapToViewPort(PixelBuffer.GetVPMatrix(a.XLower, a.XUpper, a.YLower, a.YUpper, a.VP_XLower, a.VP_XUpper, a.VP_YLower, a.VP_YUpper));
                pb.FillPolygon(p);
            }
            ////Draw lines

            pb.DrawPolygon3D(acceptedPolys);
            Console.Write(pb.WriteToXPM());
        }
        static void Main(string[] args)
        {
            //Parse the argument array in arbitrary order and give an interface to retrieve them
            Arguments a = new Arguments(args);
            //Read the input file specified in the arguments
            //PostscriptReader rdr = new PostscriptReader(a.InputFile);
            SMFReader        rdr               = new SMFReader(a.FirstModel);
            List <Polygon3D> prims             = rdr.ReadFile();
            Matrix4 <double> cameraTranslation = new Matrix4 <double>
                                                 (
                1, 0, 0, -a.VRP_X,
                0, 1, 0, -a.VRP_Y,
                0, 0, 1, -a.VRP_Z,
                0, 0, 0, 1
                                                 );
            //Cross product
            double VRR_X      = a.VUP_Y * a.VPN_Z - a.VUP_Z * a.VPN_Y;
            double VRR_Y      = a.VUP_Z * a.VPN_X - a.VUP_X * a.VPN_Z;
            double VRR_Z      = a.VUP_X * a.VPN_Y - a.VUP_Y * a.VPN_X;
            double normalizer = System.Math.Sqrt(System.Math.Pow(VRR_X, 2) + System.Math.Pow(VRR_Y, 2) + System.Math.Pow(VRR_Z, 2));

            VRR_X = VRR_X / normalizer;
            VRR_Y = VRR_Y / normalizer;
            VRR_Z = VRR_Z / normalizer;
            double           normalizerVUP  = System.Math.Sqrt(System.Math.Pow(a.VUP_X, 2) + System.Math.Pow(a.VUP_Y, 2) + System.Math.Pow(a.VUP_Z, 2));
            double           VUP_X          = a.VUP_X / normalizerVUP;
            double           VUP_Y          = a.VUP_Y / normalizerVUP;
            double           VUP_Z          = a.VUP_Z / normalizerVUP;
            double           normalizerVPN  = System.Math.Sqrt(System.Math.Pow(a.VPN_X, 2) + System.Math.Pow(a.VPN_Y, 2) + System.Math.Pow(a.VPN_Z, 2));
            double           VPN_X          = a.VPN_X / normalizerVPN;
            double           VPN_Y          = a.VPN_Y / normalizerVPN;
            double           VPN_Z          = a.VPN_Z / normalizerVPN;
            Matrix4 <double> cameraRotation = new Matrix4 <double>
                                              (
                VRR_X, VRR_Y, VRR_Z, 0,
                VUP_X, VUP_Y, VUP_Z, 0,
                VPN_X, VPN_Y, VPN_Z, 0,
                0, 0, 0, 1
                                              );

            Matrix4 <double> projection;

            if (a.IsParallelProjection)
            {
                projection = Matrix4 <double> .GetParallelProjectionMatrix(a.VRC_UMIN, a.VRC_UMAX, a.VRC_VMIN, a.VRC_VMAX, a.PRP_X, a.PRP_Y, a.PRP_Z, 0.6, -0.6);

                //projection *= Matrix4<double>.GetPerspectiveProjectionMatrix(a.VRC_UMIN, a.VRC_UMAX, a.VRC_VMIN, a.VRC_VMAX, a.PRP_X, a.PRP_Y, a.PRP_Z, -0.6);
            }
            else
            {
                projection = Matrix4 <double> .GetPerspectiveProjectionMatrix(a.VRC_UMIN, a.VRC_UMAX, a.VRC_VMIN, a.VRC_VMAX, a.PRP_X, a.PRP_Y, a.PRP_Z, -0.6);

                //projection *= Matrix4<double>.GetParallelProjectionMatrix(a.VRC_UMIN, a.VRC_UMAX, a.VRC_VMIN, a.VRC_VMAX, a.PRP_X, a.PRP_Y, a.PRP_Z, 0.6, -0.6);
            }
            foreach (var p in prims)
            {
                //Transfrom into canonical orthogonal view volume to perform clipping?? Tried it and didn't get correct results. But this doesn't work either so something else must be wrong...
                p.ProjectAndView(cameraTranslation);
                p.ProjectAndView(cameraRotation);
                p.ProjectAndView(projection);
            }
            List <Polygon3D> acceptedPolys = new List <Polygon3D>();

            //Clip polygons -- this doesn't work
            foreach (var p in prims)
            {
                bool accept = false;
                foreach (var v in p)
                {
                    if (v.X > 1 || v.X < -1)
                    {
                        accept = false;
                    }
                    else if (v.Y > 1 || v.Y < -1)
                    {
                        accept = false;
                    }
                    else
                    {
                        accept = true;
                    }
                }

                if (accept)
                {
                    acceptedPolys.Add(p);
                }
            }
            //This is the part that I think is wrong but i'm not sure how to correct it. The scaling seems to be fine for parallel but not for perspective and the translation
            //is definitely wrong but i'm not sure what it should be. I have these as separate statements instead of matrix multiplication to make it easier to debug
            foreach (var p in acceptedPolys)
            {
                if (a.IsParallelProjection)
                {
                    foreach (var v in p)
                    {
                        v.X += 1;
                        v.Y += 1;
                        v.X *= (a.XUpper - a.XLower) / 2;
                        v.Y *= (a.YUpper - a.YLower) / 2;
                        v.X += a.VRC_UMIN;
                        v.Y += a.VRC_VMIN;
                    }
                }
                else
                {
                    //p.ProjectAndView(projection);
                    foreach (var v in p)
                    {
                        //Perspective division
                        v.X /= -v.Z;
                        v.Y /= -v.Z;
                        v.X += 1;
                        v.Y += 1;
                        v.X *= (a.VP_XUpper - a.VP_XLower) / 2;
                        v.Y *= (a.VP_YUpper - a.VP_YLower) / 2;
                        v.X += a.VRC_UMIN;
                        v.Y += a.VRC_VMIN;
                    }
                }
            }
            PixelBuffer pb = new PixelBuffer(a.XLower, a.XUpper, a.YLower, a.YUpper, a.VP_XLower, a.VP_XUpper, a.VP_YLower, a.VP_YUpper, a.BackPlaneVRC, a.FrontPlaneVRC);

            foreach (var p in acceptedPolys)
            {
                p.MapToViewPort(PixelBuffer.GetVPMatrix(a.XLower, a.XUpper, a.YLower, a.YUpper, a.VP_XLower, a.VP_XUpper, a.VP_YLower, a.VP_YUpper));
                pb.FillPolygon(p);
            }
            ////Draw lines

            pb.DrawPolygon3D(acceptedPolys);
            Console.Write(pb.WriteToXPM());
        }