using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing.Drawing2D;
using System.Runtime.Serialization;

namespace CSGBuilder {
    [Serializable()]
    public partial class SolidForm : Form, ISerializable {
        public Solid solid;  // Az alaptest
        public Solid solid2;  // Az alaptestre alkalmazott transzformációk eredménye

        private List<Transformation> transf = new List<Transformation>();  // Transzformációk

        private int displayMode = 3;  // 0: Points, 1: Wireframe, 2: Color Fill, 3: Flat Shaded, 4: Gouraud Shaded

        // Színek
        public Color lineColor;
        public Color faceColor;

        // Billentyűesemények
        private string key = "";

        // Ideiglenes változók az eltoláshoz és forgatáshoz
        private double angle = 0.0, dist = 0.0;
        private double gDX = 0.0, gDY = 0.0;
        private Matrix tempMatrix;
        private Matrix defaultTranslation = new Matrix(4, 4);
        private Point3D origo = new Point3D(0.0, 0.0, 0.0);

        private Matrix tr = new Matrix(4, 4);
        private Matrix proj = new Matrix(3, 3);
        private Matrix m = new Matrix(4, 4);

        // 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;

        #region Szerializációs metódusok

        public void GetObjectData(SerializationInfo info, StreamingContext context) {
            info.AddValue("SolidType", solid.SolidType());
            info.AddValue("Solid", solid);
            info.AddValue("TransformationCount", transf.Count);
            for (int i = 0; i < transf.Count; i++) {
                info.AddValue("TR" + i + "Type", transf[i].Type());
                info.AddValue("TR" + i + "Value", transf[i]);
            }
            info.AddValue("LineColor", lineColor);
            info.AddValue("FaceColor", faceColor);
        }

        public SolidForm(SerializationInfo info, StreamingContext ctxt) {
            InitializeComponent();
            cbDisplayMode.SelectedIndex = displayMode;
            string stype = (string)info.GetValue("SolidType", typeof(string));
            switch (stype) {
                case "Cuboid": solid = (Cuboid)info.GetValue("Solid", typeof(Cuboid)); this.Text = "Cuboid " + Cuboid.counter++; break;
                case "Ellipsoid": solid = (Ellipsoid)info.GetValue("Solid", typeof(Ellipsoid)); this.Text = "Ellipsoid " + Ellipsoid.counter++; break;
                case "Torus": solid = (Torus)info.GetValue("Solid", typeof(Torus)); this.Text = "Torus " + Torus.counter++; break;
                case "Cylinder": solid = (Cylinder)info.GetValue("Solid", typeof(Cylinder)); this.Text = "Cylinder " + Cylinder.counter++; break;
                case "Cone": solid = (Cone)info.GetValue("Solid", typeof(Cone)); this.Text = "Cone " + Cone.counter++; break;
                default: solid = (Solid)info.GetValue("Solid", typeof(Solid)); this.Text = "Solid " + Solid.pcounter++; break;
            }
            defaultTranslation.LoadIdentity();
            if (solid.Center.X != 0.0 || solid.Center.Y != 0.0 || solid.Center.Z != 0.0) {
                defaultTranslation[0, 3] = solid.Center.X;
                defaultTranslation[1, 3] = solid.Center.Y;
                defaultTranslation[2, 3] = solid.Center.Z;
            }
            tempMatrix = new Matrix(4, 4);
            tempMatrix.LoadIdentity();
            int n = info.GetInt32("TransformationCount");
            transf = new List<Transformation>();
            for (int i = 0; i < n; i++) {
                switch (info.GetString("TR" + i + "Type")) {
                    case "Rotation": transf.Add((Rotation)info.GetValue("TR" + i + "Value", typeof(Rotation))); break;
                    case "Translation": transf.Add((Translation)info.GetValue("TR" + i + "Value", typeof(Translation))); break;
                    case "Scale": transf.Add((Scale)info.GetValue("TR" + i + "Value", typeof(Scale))); break;
                }
            }
            foreach (Transformation t in transf)
                lbTransf.Items.Add(t.ToString());
            lineColor = (Color)info.GetValue("LineColor", typeof(Color));
            faceColor = (Color)info.GetValue("FaceColor", typeof(Color));
            if (this.Text.Contains("Solid"))
                btChangeParams.Enabled = false;
            foreach (Face f in solid.Mesh.Faces) {
                solid.Mesh.Vertices[f[0]].Color = f.Color;
                solid.Mesh.Vertices[f[1]].Color = f.Color;
                solid.Mesh.Vertices[f[2]].Color = f.Color;
            }
            pbDisplay.BackColor = btBackColor.BackColor;
        }

        #endregion

        public Solid Solid {
            get { return solid; }
            set { solid = value; }
        }

        public SolidForm(String title, Solid solid) {
            InitializeComponent();
            cbDisplayMode.SelectedIndex = displayMode;
            this.Text = title;
            this.solid = solid;
            defaultTranslation.LoadIdentity();
            if (solid.Center.X != 0.0 || solid.Center.Y != 0.0 || solid.Center.Z != 0.0) {
                defaultTranslation[0, 3] = solid.Center.X;
                defaultTranslation[1, 3] = solid.Center.Y;
                defaultTranslation[2, 3] = solid.Center.Z;
            }
            tempMatrix = new Matrix(4, 4);
            tempMatrix.LoadIdentity();
            lineColor = btLineColor.BackColor;
            faceColor = btFillColor.BackColor;
            if (!this.Text.Contains("Solid")) {
                foreach (Face f in solid.Mesh.Faces) {
                    f.Color = faceColor;
                    solid.Mesh.Vertices[f[0]].Color = faceColor;
                    solid.Mesh.Vertices[f[1]].Color = faceColor;
                    solid.Mesh.Vertices[f[2]].Color = faceColor;
                }
                foreach (Edge e in solid.Mesh.Edges)
                    e.Color = lineColor;
            } else btChangeParams.Enabled = false;
            pbDisplay.BackColor = btBackColor.BackColor;
        }

        public Solid getModifiedSolid() {
            Solid s = new Solid();
            s.Mesh = new BRep();

            Matrix m = new Matrix(4, 4);
            m.LoadIdentity();

            m = defaultTranslation * m;
            // A végső transzformációs mátrix az összes mátrix szorzata
            for (int i = 0; i < transf.Count; i++)
                m = transf[i].TrMatrix * m;

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

            s.Center = solid.Center;
            s.E1 = (m * solid.E1).ToPoint3Dh();
            s.E2 = (m * solid.E2).ToPoint3Dh();
            s.E3 = (m * solid.E3).ToPoint3Dh();
            foreach (Face f in solid.Mesh.Faces)
                s.Mesh.Faces.Add(f.Clone());
            foreach (Edge e in solid.Mesh.Edges)
                s.Mesh.Edges.Add(e.Clone());

            // A befoglaló téglalap meghatározása
            double minx, miny, minz; minx = miny = minz = double.MaxValue;
            double maxx, maxy, maxz; maxx = maxy = maxz = double.MinValue;
            foreach (Point3D p in s.Mesh.Vertices) {
                if (p.X < minx) minx = p.X;
                if (p.Y < miny) miny = p.Y;
                if (p.Z < minz) minz = p.Z;
                if (p.X > maxx) maxx = p.X;
                if (p.Y > maxy) maxy = p.Y;
                if (p.Z > maxz) maxz = p.Z;
            }
            s.LowerCorner = new Point3D(minx, miny, minz);
            s.UpperCorner = new Point3D(maxx, maxy, maxz);
            return s;
        }

        #region displayMode beállítása
        private void cbDisplayMode_SelectedIndexChanged(object sender, EventArgs e) {
            displayMode = cbDisplayMode.SelectedIndex;
            pbDisplay.Refresh();
        }

        private void rbColor_CheckedChanged(object sender, EventArgs e) {
            displayMode = 1;
            pbDisplay.Refresh();
        }

        private void rbFlat_CheckedChanged(object sender, EventArgs e) {
            displayMode = 2;
            pbDisplay.Refresh();
        }

        private void rbGouraud_CheckedChanged(object sender, EventArgs e) {
            displayMode = 3;
            pbDisplay.Refresh();
        }

        private void rbWire_CheckedChanged(object sender, EventArgs e) {
            displayMode = 0;
            pbDisplay.Refresh();
        }

        private void rbPoints_CheckedChanged(object sender, EventArgs e) {
            displayMode = 4;
            pbDisplay.Refresh();
        }
        #endregion

        private void pbDisplay_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            
            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
            proj.LoadIdentity();
            proj[0, 0] = cpd / mu;
            proj[1, 1] = cpd / mu;            

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

            m.LoadIdentity();
            m = defaultTranslation * m;
            // A végső transzformációs mátrix az összes mátrix szorzata
            for (int i = 0; i < transf.Count; i++)
                m = transf[i].TrMatrix * m;

            m = tr * tempMatrix * m;

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

            solid2.Center = (m * origo).ToPoint3Dh();
            solid2.E1 = (m * solid.E1).ToPoint3Dh();
            solid2.E2 = (m * solid.E2).ToPoint3Dh();
            solid2.E3 = (m * solid.E3).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();
            cam = (tr * cam).ToPoint3Dh();

            // 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 (displayMode == 3) {
                solid2.Mesh.CalcLights(cam);
            }
            if (displayMode == 4) {
                solid2.Mesh.CalcVectors(cam);
            }

            // kirajzolás
            pbDisplay.drawindex = displayMode;
            pbDisplay.mesh = solid2.Mesh;
            //pbDisplay.cam = cam;
            pbDisplay.dx = gDX;
            pbDisplay.dy = gDY;

            pbDisplay.gAxes = pbDisplay.lAxes = pbDisplay.dAxes = false;

            #region Koordinátarendszer kirajzolása
            #region Lokális koordinátarendszer leképezése
            Point3D ple1 = ((m * solid.E1) as Matrix).ToPoint3Dh();
            Point imglE1 = (proj * ple1).ToPoint2D();
            imglE1.X = (int)(imglE1.X + pbDisplay.Width / 2 + gDX);
            imglE1.Y = (int)(imglE1.Y + pbDisplay.Height / 2 + gDY);

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

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

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

            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 + pbDisplay.Width / 2 + gDX), (int)(pe1.Y + pbDisplay.Height / 2 + gDY));
            Point imgE2 = new Point((int)(pe2.X + pbDisplay.Width / 2 + gDX), (int)(pe2.Y + pbDisplay.Height / 2 + gDY));
            Point imgE3 = new Point((int)(pe3.X + pbDisplay.Width / 2 + gDX), (int)(pe3.Y + pbDisplay.Height / 2 + gDY));

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

            pbDisplay.lAxes = cbShowLCS.Checked;
            pbDisplay.lCenter = cimg;
            pbDisplay.lXAxis = imglE1;
            pbDisplay.lYAxis = imglE2;
            pbDisplay.lZAxis = imglE3;

            pbDisplay.labelSize = cpd / 300.0;

            #endregion

        }

        // Kattintáskor tárolja az egér pozícióját
        private void pbDisplay_MouseDown(object sender, MouseEventArgs e) {
            mx = e.X;
            my = e.Y;
        }

        private Matrix getRotationMatrix(Point3D sp, Point3D ep, double angle) {
            double delta = angle * Math.PI / 180;

            double h = Math.Sqrt((ep.X - sp.X) * (ep.X - sp.X) +
                (ep.Y - sp.Y) * (ep.Y - sp.Y) + (ep.Z - sp.Z) * (ep.Z - sp.Z));
            double cx = (ep.X - sp.X) / h;
            double cy = (ep.Y - sp.Y) / h;
            double cz = (ep.Z - sp.Z) / h;
            double d = Math.Sqrt(cz * cz + cy * cy);

            double cx2 = cx * cx;
            double cy2 = cy * cy;
            double cz2 = cz * cz;
            double d2 = d * d;

            Matrix t = new Matrix(4, 4);
            t.LoadIdentity();
            t[0, 3] = -sp.X;
            t[1, 3] = -sp.Y;
            t[2, 3] = -sp.Z;

            Matrix rx = new Matrix(4, 4);
            rx.LoadIdentity();
            if (d != 0) {
                rx[1, 1] = cz / d;
                rx[1, 2] = -cy / d;
                rx[2, 1] = cy / d;
                rx[2, 2] = cz / d;
            }

            Matrix ry = new Matrix(4, 4);
            ry.LoadIdentity();
            ry[0, 0] = d;
            ry[0, 2] = -cx;
            ry[2, 0] = cx;
            ry[2, 2] = d;

            Matrix rz = new Matrix(4, 4);
            rz.LoadIdentity();
            rz[0, 0] = Math.Cos(delta);
            rz[0, 1] = -Math.Sin(delta);
            rz[1, 0] = Math.Sin(delta);
            rz[1, 1] = Math.Cos(delta);

            return t.Trans() * rx.Trans() * ry.Trans() * rz * ry * rx * t;
        }

        private void pbDisplay_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;
                    pbDisplay.Refresh();
                    return;
                }

                if (key == "RX") {
                    angle = (angle + e.X - mx) % 360;
                    mx = e.X; my = e.Y;
                    tempMatrix = getRotationMatrix(new Point3D(0, 0, 0), new Point3D(1, 0, 0), angle);
                } else if (key == "RY") {
                    angle = (angle + e.X - mx) % 360;
                    mx = e.X; my = e.Y;
                    tempMatrix = getRotationMatrix(origo, solid.E2, angle);
                } else if (key == "RZ") {
                    angle = (angle + e.X - mx) % 360;
                    mx = e.X; my = e.Y;
                    tempMatrix = getRotationMatrix(origo, solid.E3, angle);
                } else

                if (key == "TX") {
                    dist += (e.X - mx);
                    mx = e.X; my = e.Y;
                    tempMatrix.LoadIdentity();
                    tempMatrix[0, 3] = dist;
                } else if (key == "TY") {
                    dist += (e.X - mx);
                    mx = e.X; my = e.Y;
                    tempMatrix.LoadIdentity();
                    tempMatrix[1, 3] = dist;
                } else if (key == "TZ") {
                    dist += (e.X - mx);
                    mx = e.X; my = e.Y;
                    tempMatrix.LoadIdentity();
                    tempMatrix[2, 3] = dist;
                } else

                if (key == "SX") {
                    dist = (e.X - mx) / 100.0 + 1.0;
                    if (dist < 0.000001) dist = 0.000001;
                    tempMatrix.LoadIdentity();
                    tempMatrix[0, 0] = dist;
                } else if (key == "SY") {
                    dist = (e.X - mx) / 100.0 + 1.0;
                    if (dist < 0.000001) dist = 0.000001;
                    tempMatrix.LoadIdentity();
                    tempMatrix[1, 1] = dist;
                } else if (key == "SZ") {
                    dist = (e.X - mx) / 100.0 + 1.0;
                    if (dist < 0.000001) dist = 0.000001;
                    tempMatrix.LoadIdentity();
                    tempMatrix[2, 2] = dist;
                } else {
                    alpha = (alpha + e.X - mx) % 360;
                    beta = (beta + e.Y - my) % 360;
                    mx = e.X; my = e.Y;
                }
                pbDisplay.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;
                pbDisplay.Refresh();
            }
        }

        // Mutassa a globális koordinátarendszert
        private void cbShowCS_CheckedChanged(object sender, EventArgs e) {
            pbDisplay.Refresh();
        }

        // Mutassa a lokális koordinátarendszert       
        private void cbShowLCS_CheckedChanged(object sender, EventArgs e) {
            pbDisplay.Refresh();
        }

        // Transzformáció-választó menü
        private void btAddTr_Click(object sender, EventArgs e) {
            cmAddTr.Show(btAddTr, btAddTr.Width, 0);
        }

        #region Színek választása
        private void btBackColor_Click(object sender, EventArgs e) {
            cdColors.Color = btBackColor.BackColor;
            if (cdColors.ShowDialog() == DialogResult.OK) {
                btBackColor.BackColor = cdColors.Color;
                pbDisplay.BackColor = cdColors.Color;
                pbDisplay.Refresh();
            }
        }

        private void btLineColor_Click(object sender, EventArgs e) {
            cdColors.Color = btLineColor.BackColor;
            if (cdColors.ShowDialog() == DialogResult.OK) {
                btLineColor.BackColor = cdColors.Color;
                lineColor = cdColors.Color;
                foreach (Edge ed in solid.Mesh.Edges)
                    ed.Color = lineColor;
                pbDisplay.Refresh();
            }
        }

        private void btFillColor_Click(object sender, EventArgs e) {
            cdColors.Color = btFillColor.BackColor;
            if (cdColors.ShowDialog() == DialogResult.OK) {
                btFillColor.BackColor = cdColors.Color;
                faceColor = cdColors.Color;
                foreach (Face f in solid.Mesh.Faces) {
                    f.Color = faceColor;
                    solid.Mesh.Vertices[f[0]].Color = faceColor;
                    solid.Mesh.Vertices[f[1]].Color = faceColor;
                    solid.Mesh.Vertices[f[2]].Color = faceColor;
                }
                pbDisplay.Refresh();
            }
        }
        #endregion

        #region Transzformációk módosítása/törlése

        private void btRemoveTr_Click(object sender, EventArgs e) {
            int i = lbTransf.SelectedIndex;
            if (i != -1) {
                lbTransf.Items.RemoveAt(i);
                transf.RemoveAt(i);
                ((MainForm)this.ParentForm).SetSaved(false);
                pbDisplay.Refresh();
            }
        }

        private void btClearTr_Click(object sender, EventArgs e) {
            if (MessageBox.Show("Are you sure you want to delete all the transformations?", "Question",
                MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.Yes) {
                lbTransf.Items.Clear();
                transf.Clear();
                ((MainForm)this.ParentForm).SetSaved(false);
                pbDisplay.Refresh();
            }
        }

        private void btModifyTr_Click(object sender, EventArgs e) {
            int i = lbTransf.SelectedIndex;
            if (i != -1) {
                if (transf[i] is Translation) {
                    TranslateForm tf = new TranslateForm();
                    Translation tr = transf[i] as Translation;
                    tf.tbDX.Text = tr.Dx.ToString("F3");
                    tf.tbDY.Text = tr.Dy.ToString("F3");
                    tf.tbDZ.Text = tr.Dz.ToString("F3");
                    if (tf.ShowDialog() == DialogResult.OK) {
                        Translation t = new Translation(Double.Parse(tf.tbDX.Text), Double.Parse(tf.tbDY.Text), Double.Parse(tf.tbDZ.Text));
                        transf[i] = t;
                        lbTransf.Items[i] = t.ToString();
                        ((MainForm)this.ParentForm).SetSaved(false);
                        pbDisplay.Refresh();
                    }
                }
                if (transf[i] is Rotation) {
                    RotateForm rf = new RotateForm();
                    Rotation r = transf[i] as Rotation;
                    if (r.Sp == origo && r.Ep == solid.E1) rf.cbAxis.SelectedIndex = 0;
                    else if (r.Sp == origo && r.Ep == solid.E2) rf.cbAxis.SelectedIndex = 1;
                    else if (r.Sp == origo && r.Ep == solid.E3) rf.cbAxis.SelectedIndex = 2;
                    else {
                        rf.cbAxis.SelectedIndex = 3;
                        rf.tbUX1.Text = r.Sp.X.ToString("F3");
                        rf.tbUY1.Text = r.Sp.Y.ToString("F3");
                        rf.tbUZ1.Text = r.Sp.Z.ToString("F3");
                        rf.tbUX2.Text = r.Ep.X.ToString("F3");
                        rf.tbUY2.Text = r.Ep.Y.ToString("F3");
                        rf.tbUZ2.Text = r.Ep.Z.ToString("F3");
                    }
                    rf.tbAngle.Text = r.Angle.ToString("F3");
                    if (rf.ShowDialog() == DialogResult.OK) {
                        Point3D sp = null, ep = null;
                        switch (rf.cbAxis.SelectedIndex) {
                            case 0: sp = origo; ep = solid.E1; break;
                            case 1: sp = origo; ep = solid.E2; break;
                            case 2: sp = origo; ep = solid.E3; break;
                            case 3:
                                sp = new Point3D(Double.Parse(rf.tbUX1.Text), Double.Parse(rf.tbUY1.Text), Double.Parse(rf.tbUZ1.Text));
                                ep = new Point3D(Double.Parse(rf.tbUX2.Text), Double.Parse(rf.tbUY2.Text), Double.Parse(rf.tbUZ2.Text));
                                break;
                        }
                        Rotation rot = new Rotation(sp, ep, Double.Parse(rf.tbAngle.Text));
                        transf[i] = rot;
                        lbTransf.Items[i] = rot.ToString();
                        ((MainForm)this.ParentForm).SetSaved(false);
                        pbDisplay.Refresh();
                    }
                }
                if (transf[i] is Scale) {
                    ScaleForm tf = new ScaleForm();
                    Scale tr = transf[i] as Scale;
                    tf.tbLX.Text = tr.Lx.ToString("F3");
                    tf.tbLY.Text = tr.Ly.ToString("F3");
                    tf.tbLZ.Text = tr.Lz.ToString("F3");
                    if (tf.ShowDialog() == DialogResult.OK) {
                        Scale t = new Scale(Double.Parse(tf.tbLX.Text), Double.Parse(tf.tbLY.Text), Double.Parse(tf.tbLZ.Text));
                        transf[i] = t;
                        lbTransf.Items[i] = t.ToString();
                        ((MainForm)this.ParentForm).SetSaved(false);
                        pbDisplay.Refresh();
                    }
                }
            }
        }

        #endregion

        #region Transzformációk megadása
        private void miTranslate_Click(object sender, EventArgs e) {
            TranslateForm tf = new TranslateForm();
            if (tf.ShowDialog() == DialogResult.OK) {
                Translation t = new Translation(Double.Parse(tf.tbDX.Text), Double.Parse(tf.tbDY.Text), Double.Parse(tf.tbDZ.Text));
                transf.Add(t);
                lbTransf.Items.Add(t.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
                pbDisplay.Refresh();
            }
        }

        private void miRotate_Click(object sender, EventArgs e) {
            RotateForm rf = new RotateForm();
            if (rf.ShowDialog() == DialogResult.OK) {
                Point3D sp = null, ep = null;
                switch (rf.cbAxis.SelectedIndex) {
                    case 0: sp = origo; ep = solid.E1; break;
                    case 1: sp = origo; ep = solid.E2; break;
                    case 2: sp = origo; ep = solid.E3; break;
                    case 3:
                        sp = new Point3D(Double.Parse(rf.tbUX1.Text), Double.Parse(rf.tbUY1.Text), Double.Parse(rf.tbUZ1.Text));
                        ep = new Point3D(Double.Parse(rf.tbUX2.Text), Double.Parse(rf.tbUY2.Text), Double.Parse(rf.tbUZ2.Text));
                        break;
                }
                Rotation r = new Rotation(sp, ep, Double.Parse(rf.tbAngle.Text));
                transf.Add(r);
                lbTransf.Items.Add(r.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
                pbDisplay.Refresh();
            }
        }

        private void miScale_Click(object sender, EventArgs e) {
            ScaleForm sf = new ScaleForm();
            if (sf.ShowDialog() == DialogResult.OK) {
                Scale s = new Scale(Double.Parse(sf.tbLX.Text), Double.Parse(sf.tbLY.Text), Double.Parse(sf.tbLZ.Text));
                transf.Add(s);
                lbTransf.Items.Add(s.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
                pbDisplay.Refresh();
            }
        }
        #endregion

        #region Infók kiírása a státuszsorba

        private void pbDisplay_MouseEnter(object sender, EventArgs e) {
            lInfo.Text = "Left Mouse Button: Rotate Camera  |  Right Mouse Button: Zoom";
        }

        private void pbDisplay_MouseLeave(object sender, EventArgs e) {
            if (solid2 != null)
                lInfo.Text =
                    "Points: " + solid2.Mesh.Vertices.Count + "  | Edges: " + solid2.Mesh.Edges.Count + "  | Faces: " + solid2.Mesh.Faces.Count +
                    "  | Visible Faces: " + solid2.Mesh.VisibleFaces.Count;
        }

        private void cbShowCS_MouseHover(object sender, EventArgs e) {
            lInfo.Text = "X Axis: Red | Y Axis: Green | Z Axis: Blue | Local Coord. System: Yellow";
        }

        private void btBackColor_MouseHover(object sender, EventArgs e) {
            lInfo.Text = "Change the background color";
        }

        private void btLineColor_MouseHover(object sender, EventArgs e) {
            lInfo.Text = "Change the color of lines";
        }

        private void btFillColor_MouseHover(object sender, EventArgs e) {
            lInfo.Text = "Change the poligon filling color";
        }

        #endregion

        private void SolidForm_KeyDown(object sender, KeyEventArgs e) {
            if (e.KeyCode == Keys.Delete) {
                if (lbTransf.SelectedIndex != -1) {
                    transf.RemoveAt(lbTransf.SelectedIndex);
                    lbTransf.Items.RemoveAt(lbTransf.SelectedIndex);
                    ((MainForm)this.ParentForm).SetSaved(false);
                }
                e.Handled = true;
                pbDisplay.Refresh();
                return;
            }
            if (e.KeyCode == Keys.D1 && e.Modifiers == Keys.Control) {
                displayMode = 0; cbDisplayMode.SelectedIndex = 0; pbDisplay.Refresh();
            }
            if (e.KeyCode == Keys.D2 && e.Modifiers == Keys.Control) {
                displayMode = 1; cbDisplayMode.SelectedIndex = 1; pbDisplay.Refresh();
            }
            if (e.KeyCode == Keys.D3 && e.Modifiers == Keys.Control) {
                displayMode = 2; cbDisplayMode.SelectedIndex = 2; pbDisplay.Refresh();
            }
            if (e.KeyCode == Keys.D4 && e.Modifiers == Keys.Control) {
                displayMode = 3; cbDisplayMode.SelectedIndex = 3; pbDisplay.Refresh();
            }
            if (e.KeyCode == Keys.D5 && e.Modifiers == Keys.Control) {
                displayMode = 4; cbDisplayMode.SelectedIndex = 4; pbDisplay.Refresh();
            }
            if (ModifierKeys == Keys.None) {
                if (key.Length == 2) return;
                if (key.Length == 0 && (e.KeyCode == Keys.T || e.KeyCode == Keys.R || e.KeyCode == Keys.S))
                    key += e.KeyCode.ToString();
                if (key.Length == 1 && (e.KeyCode == Keys.X || e.KeyCode == Keys.Y || e.KeyCode == Keys.Z))
                    key += e.KeyCode.ToString();
                string text = "";
                if (key.Length > 0)
                    switch (key[0]) {
                        case 'T': text = "Translate: (Press X, Y or Z)"; break;
                        case 'R': text = "Rotate: (Press X, Y or Z)"; break;
                        case 'S': text = "Scale: (Press X, Y or Z)"; break;
                    }
                if (key.Length > 1)
                    switch (key[1]) {
                        case 'X': text = text.Substring(0, text.IndexOf('(') - 1) + " X axis   Drag the mouse left or right!"; break;
                        case 'Y': text = text.Substring(0, text.IndexOf('(') - 1) + " Y axis   Drag the mouse left or right!"; break;
                        case 'Z': text = text.Substring(0, text.IndexOf('(') - 1) + " Z axis   Drag the mouse left or right!"; break;
                    }
                lInfo.Text = text;
                sbStatus.Refresh();
                pbDisplay.Refresh();
            }
        }

        private void SolidForm_KeyUp(object sender, KeyEventArgs e) {
            tempMatrix.LoadIdentity();
            lInfo.Text = "";
            if (key == "RX" && angle != 0.0) {
                Rotation r = new Rotation(origo, solid.E1, angle);
                transf.Add(r);
                lbTransf.Items.Add(r.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
            } else if (key == "RY" && angle != 0.0) {
                Rotation r = new Rotation(origo, solid.E2, angle);
                transf.Add(r);
                lbTransf.Items.Add(r.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
            } else if (key == "RZ" && angle != 0.0) {
                Rotation r = new Rotation(origo, solid.E3, angle);
                transf.Add(r);
                lbTransf.Items.Add(r.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
            } else if (key == "TX" && dist != 0.0) {
                Translation t = new Translation(dist, 0.0, 0.0);
                transf.Add(t);
                lbTransf.Items.Add(t.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
            } else if (key == "TY" && dist != 0.0) {
                Translation t = new Translation(0.0, dist, 0.0);
                transf.Add(t);
                lbTransf.Items.Add(t.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
            } else if (key == "TZ" && dist != 0.0) {
                Translation t = new Translation(0.0, 0.0, dist);
                transf.Add(t);
                lbTransf.Items.Add(t.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
            } else if (key == "SX" && dist > 0.0) {
                Scale s = new Scale(dist, 1.0, 1.0);
                transf.Add(s);
                lbTransf.Items.Add(s.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
            } else if (key == "SY" && dist > 0.0) {
                Scale s = new Scale(1.0, dist, 1.0);
                transf.Add(s);
                lbTransf.Items.Add(s.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
            } else if (key == "SZ" && dist > 0.0) {
                Scale s = new Scale(1.0, 1.0, dist);
                transf.Add(s);
                lbTransf.Items.Add(s.ToString());
                ((MainForm)this.ParentForm).SetSaved(false);
            }
            key = "";
            angle = 0.0;
            dist = 0.0;
        }

        private void btChangeParams_Click(object sender, EventArgs e) {
            solid.ChangeParams();
            if (solid.Center.X != 0.0 || solid.Center.Y != 0.0 || solid.Center.Z != 0.0) {
                defaultTranslation[0, 3] = solid.Center.X;
                defaultTranslation[1, 3] = solid.Center.Y;
                defaultTranslation[2, 3] = solid.Center.Z;
            } else defaultTranslation.LoadIdentity();
            pbDisplay.Refresh();
        }

        private void SolidForm_FormClosing(object sender, FormClosingEventArgs e) {
            if (e.CloseReason != CloseReason.UserClosing) return;
            if (MessageBox.Show("Are you sure you want to delete this solid: " + this.Text + " ?", "Deleting solid",
                MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
                e.Cancel = true;
            ((MainForm)this.ParentForm).SetSaved(false);
        }


    }
}