using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace CSGBuilder {
    public partial class Preview : Form {
        private Solid solid;
        private Solid solid2;

        // Gömbi koordináták
        private double mu = 2000.0, alpha = 225.0, beta = 120.0, cpd = 1500.0;

        // Az egér koordinátái
        private int mx, my;

        // Eltolás
        private double gDX = 0.0, gDY = 0.0;

        public Preview(Solid solid) {
            InitializeComponent();
            cbDisplayMode.SelectedIndex = 3;
            this.solid = solid;
        }

        private void prevWindow_Paint(object sender, PaintEventArgs e) {
            if (solid == null) return;

            // A globális koordinátarendszer
            Point3D e1 = new Point3D(cpd / 15.0, 0.0, 0.0);
            Point3D e2 = new Point3D(0.0, cpd / 15.0, 0.0);
            Point3D e3 = new Point3D(0.0, 0.0, cpd / 15.0);

            // A szögek átszámolva radiánba
            double ralpha = alpha * Math.PI / 180.0;
            double rbeta = beta * Math.PI / 180.0;

            // Transzformációs mátrix a gömbi koordinátás megjelenítéshez
            Matrix tr = new Matrix(4, 4);
            tr.LoadIdentity();
            tr[0, 0] = -Math.Sin(ralpha);
            tr[0, 1] = Math.Cos(ralpha);
            tr[1, 0] = -Math.Cos(ralpha) * Math.Cos(rbeta);
            tr[1, 1] = -Math.Sin(ralpha) * Math.Cos(rbeta);
            tr[1, 2] = Math.Sin(rbeta);
            tr[2, 0] = -Math.Cos(ralpha) * Math.Sin(rbeta);
            tr[2, 1] = -Math.Sin(ralpha) * Math.Sin(rbeta);
            tr[2, 2] = -Math.Cos(rbeta);
            tr[2, 3] = mu;

            // a leképezés mátrixa
            Matrix proj = new Matrix(3, 3);
            proj.LoadIdentity();
            //proj[2, 3] = cpd;
            proj[0, 0] = cpd / mu;
            proj[1, 1] = cpd / mu;

            solid2 = new Solid();
            solid2.Mesh = new BRep();
            //solid2.Center = solid.Center;            

            // A transzformáció és a leképezés végrehajtása az összes pontra
            //foreach (Point3D p in solid.Mesh.Vertices) 
            //    solid2.Mesh.Vertices.Add((tr * p).ToPoint3Dh());
            foreach (Point3D p in solid.Mesh.Vertices) {
                Point3D p2 = new Point3D(
                    p.X * tr[0, 0] + p.Y * tr[0, 1] + p.Z * tr[0, 2] + tr[0, 3],
                    p.X * tr[1, 0] + p.Y * tr[1, 1] + p.Z * tr[1, 2] + tr[1, 3],
                    p.X * tr[2, 0] + p.Y * tr[2, 1] + p.Z * tr[2, 2] + tr[2, 3]);
                p2.Color = p.Color;
                solid2.Mesh.Vertices.Add(p2);
            }

            solid2.Center = (tr * solid.Center).ToPoint3Dh();
            solid2.Mesh.Faces = solid.Mesh.Faces;
            solid2.Mesh.Edges = solid.Mesh.Edges;

            solid2.Mesh.Projection(proj);

            // a kamera koordinátái
            double x = mu * Math.Sin(rbeta) * Math.Cos(ralpha);
            double y = mu * Math.Sin(rbeta) * Math.Sin(ralpha);
            double z = mu * Math.Cos(rbeta);
            Point3D cam = new Point3D(x, y, z);
            cam.Normal();

            // hátsó lapok eldobása
            solid2.Mesh.BFC(cam);

            // mélységi rendezés
            solid2.Mesh.DepthSort();

            // a fények számítása
            if (cbDisplayMode.SelectedIndex == 3) {
                solid2.Mesh.CalcLights(cam);
                //solid2.Mesh.SetLightWeights((double)btFaceColor.BackColor.R / 255.0, (double)btFaceColor.BackColor.G / 255.0, (double)btFaceColor.BackColor.B / 255.0);
            }
            if (cbDisplayMode.SelectedIndex == 4) {
                solid2.Mesh.CalcVectors(cam);
                //solid2.Mesh.SetLightWeights((double)btFaceColor.BackColor.R / 255.0, (double)btFaceColor.BackColor.G / 255.0, (double)btFaceColor.BackColor.B / 255.0);
            }

            // kirajzolás
            //prevWindow.lineColor = btLineColor.BackColor;
            //prevWindow.faceColor = btFaceColor.BackColor;
            prevWindow.drawindex = cbDisplayMode.SelectedIndex;
            prevWindow.mesh = solid2.Mesh;
            //prevWindow.cam = cam;
            prevWindow.dx = gDX;
            prevWindow.dy = gDY;

            prevWindow.gAxes = prevWindow.lAxes = prevWindow.dAxes = false;

            #region Koordinátarendszer kirajzolása
            Point3D ple1 = ((tr * solid.E1) as Matrix).ToPoint3Dh();
            Point imglE1 = (proj * ple1).ToPoint2D();
            imglE1.X = (int)(imglE1.X + prevWindow.Width / 2 + gDX);
            imglE1.Y = (int)(imglE1.Y + prevWindow.Height / 2 + gDY);

            Point3D ple2 = ((tr * solid.E2) as Matrix).ToPoint3Dh();
            Point imglE2 = (proj * ple2).ToPoint2D();
            imglE2.X = (int)(imglE2.X + prevWindow.Width / 2 + gDX);
            imglE2.Y = (int)(imglE2.Y + prevWindow.Height / 2 + gDY);

            Point3D ple3 = ((tr * solid.E3) as Matrix).ToPoint3Dh();
            Point imglE3 = (proj * ple3).ToPoint2D();
            imglE3.X = (int)(imglE3.X + prevWindow.Width / 2 + gDX);
            imglE3.Y = (int)(imglE3.Y + prevWindow.Height / 2 + gDY);

            Point cimg = (proj * solid2.Center).ToPoint2D();
            cimg.X = (int)(cimg.X + prevWindow.Width / 2 + gDX);
            cimg.Y = (int)(cimg.Y + prevWindow.Height / 2 + gDY);

            Point3D pe1 = ((tr * e1) as Matrix).ToPoint3Dh();
            Point3D pe2 = ((tr * e2) as Matrix).ToPoint3Dh();
            Point3D pe3 = ((tr * e3) as Matrix).ToPoint3Dh();
            Point imgE1 = new Point((int)(pe1.X + prevWindow.Width / 2 + gDX), (int)(pe1.Y + prevWindow.Height / 2 + gDY));
            Point imgE2 = new Point((int)(pe2.X + prevWindow.Width / 2 + gDX), (int)(pe2.Y + prevWindow.Height / 2 + gDY));
            Point imgE3 = new Point((int)(pe3.X + prevWindow.Width / 2 + gDX), (int)(pe3.Y + prevWindow.Height / 2 + gDY));

            prevWindow.gAxes = prevWindow.lAxes = cbCS.Checked;
            prevWindow.gCenter = new Point((int)(prevWindow.Width / 2 + gDX), (int)(prevWindow.Height / 2 + gDY));
            prevWindow.gXAxis = imgE1;
            prevWindow.gYAxis = imgE2;
            prevWindow.gZAxis = imgE3;

            prevWindow.lCenter = cimg;
            prevWindow.lXAxis = imglE1;
            prevWindow.lYAxis = imglE2;
            prevWindow.lZAxis = imglE3;

            prevWindow.labelSize = cpd / 300.0;

            #endregion


        }

        private void prevWindow_MouseDown(object sender, MouseEventArgs e) {
            mx = e.X;
            my = e.Y;
        }

        private void prevWindow_MouseMove(object sender, MouseEventArgs e) {
            if (e.Button == MouseButtons.Left) {
                if (ModifierKeys == Keys.Control) {
                    gDX += (e.X - mx);
                    gDY += (my - e.Y);
                    mx = e.X; my = e.Y;
                    prevWindow.Refresh();
                    return;
                }
                alpha = (alpha + e.X - mx) % 360;
                beta = (beta + e.Y - my) % 360;
                mx = e.X; my = e.Y;
                prevWindow.Refresh();
            } else if (e.Button == MouseButtons.Right) {
                cpd = cpd + (e.X - mx) * 10;
                if (cpd < 10.0) cpd = 10.0;
                mx = e.X; my = e.Y;
                prevWindow.Refresh();
            }
        }

        private void cbDisplayMode_SelectedIndexChanged(object sender, EventArgs e) {
            prevWindow.Refresh();
        }

        private void cbCS_CheckedChanged(object sender, EventArgs e) {
            prevWindow.Refresh();
        }

    }
}