using System.Drawing;

using Spark3D.Algebra3D;

namespace Spark3D.Projector3D
{
    public class IsometricProjector : ProjectorCommon, IProjector3D
    {
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="FieldOfViewX">In degrees</param>
        /// <param name="FieldOfViewY">In degrees</param>
        public IsometricProjector()
        {
            FieldOfView = 0.3;
            Vector3D angles = new Vector3D(45.0, 45.0, 0.0);
            Vector3D radians = Vector3D.DegreesToRadians(angles);
            Vector3D Sins = Vector3D.Sin(radians);
            Vector3D Coss = Vector3D.Cos(radians);
            Matrix3D Rx = new Matrix3D(new double[,] {
            { 1.0, 0.0    , 0.0     }, 
            { 0.0, Coss[0], Sins[0] }, 
            { 0.0,-Sins[0], Coss[0] } 
            });
            Matrix3D Ry = new Matrix3D(new double[,] {
            { Coss[1], 0.0, Sins[1] }, 
            { 0.0    , 1.0, 0.0     }, 
            {-Sins[1], 0.0, Coss[1] } 
            });
            Matrix3D Rz = new Matrix3D(new double[,] {
            { Coss[2], Sins[2], 0.0 }, 
            {-Sins[2], Coss[2], 0.0 }, 
            { 0.0    , 0.0    , 1.0 } 
            });

            Rotation = Rx * Ry * Rz;
        }

        /// <summary>
        /// No need to move.
        /// </summary>
        /// <param name="v">polar coordinates=(r,theta,phi)</param>
        public override void MoveView(Vector3D angles)
        {
            //Noop angle are fixed for an isometric projection.              
        }
        /// <summary>
        /// Projects a Vector3D to a ProjectedPoint
        /// </summary>
        /// <param name="p3">The Vector3D to project</param>
        /// <returns>The projected point</returns>
        public override ProjectedPoint Project(Vector3D p3)
        {
            // Rotate in 3D space.
            Vector3D d = Rotation * p3 - CameraPosition;
            // Project down to 2D space.
            double b_x = d[0] * ScaleX;
            double b_y = d[1] * ScaleY;
            // If Viewer[3]=e_z is adjusted properly that sets the scale so that |b| > 1.
            return new ProjectedPoint(new Point((int)b_x, (int)b_y), d);
        }


    }
}
