using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;

namespace CSGBuilder {
    [Serializable()]
    class Ellipsoid : Solid {
        public static int counter = 1;

        // A három  sugár
        private double xradius, yradius, zradius;
        // Vízszintes és függőleges felosztás
        private int hdiv, vdiv;

        #region Properties
        public double XRadius {
            get { return xradius; }
            set { xradius = value; }
        }

        public double YRadius {
            get { return yradius; }
            set { yradius = value; }
        }

        public double ZRadius {
            get { return zradius; }
            set { zradius = value; }
        }

        public int Vdiv {
            get { return vdiv; }
            set { vdiv = value; }
        }

        public int Hdiv {
            get { return hdiv; }
            set { hdiv = value; }
        }
        #endregion

        public Ellipsoid(double rx, double ry, double rz, int hdiv, int vdiv, Point3D ct) {
            this.xradius = rx;
            this.yradius = ry;
            this.zradius = rz;
            this.hdiv = hdiv;
            this.vdiv = vdiv;
            // Középpont
            if (ct == null) this.center = new Point3D(0.0, 0.0, 0.0); else this.center = ct;
            // Tengelyek
            this.e1 = new Point3D(xradius, 0.0, 0.0);
            this.e2 = new Point3D(0.0, yradius, 0.0);
            this.e3 = new Point3D(0.0, 0.0, zradius);
            // Befoglaló téglatest
            this.UpperCorner = new Point3D(xradius, yradius, zradius);
            this.LowerCorner = new Point3D(-xradius, -yradius, -zradius);
            MeshTesselation();
        }

        public override void GetObjectData(SerializationInfo info, StreamingContext context) {
            base.GetObjectData(info, context);
            info.AddValue("XRadius", xradius);
            info.AddValue("YRadius", yradius);
            info.AddValue("ZRadius", zradius);
            info.AddValue("HDiv", hdiv);
            info.AddValue("VDiv", vdiv);
        }

        public Ellipsoid(SerializationInfo info, StreamingContext context) : base(info, context) {
            xradius = info.GetDouble("XRadius");
            yradius = info.GetDouble("YRadius");
            zradius = info.GetDouble("ZRadius");
            hdiv = info.GetInt32("HDiv");
            vdiv = info.GetInt32("VDiv");            
        }

        public override string SolidType() {
            return "Ellipsoid";
        }

        public override void MeshTesselation() {
            mesh = new BRep();
            // Vízszintes lépésköz
            double hstep = 360.0 / (double)hdiv;
            // Függőleges lépésköz
            double vstep = 180.0 / (double)vdiv;

            // Csúcsok
            #region Vertices
            for (int i = 0; i < hdiv; i += 1)
                for (int j = 0; j < vdiv - 1; j += 1)
                    mesh.Vertices.Add(new Point3D(
                        xradius * Math.Cos((double)i * hstep * Math.PI / 180.0) * Math.Cos((double)(j * vstep + vstep + 90) * Math.PI / 180.0),
                        yradius * Math.Sin((double)i * hstep * Math.PI / 180.0) * Math.Cos((double)(j * vstep + vstep + 90) * Math.PI / 180.0),
                        zradius * Math.Sin((double)(j * vstep + vstep + 90) * Math.PI / 180.0)));
            mesh.Vertices.Add(new Point3D(0.0, 0.0, -zradius));
            mesh.Vertices.Add(new Point3D(0.0, 0.0, zradius));
            #endregion

            // Élek
            #region Edges
            for (int i = 0; i < hdiv; i++)
                for (int j = 0; j < vdiv - 2; j++)
                    mesh.Edges.Add(new Edge(i * (vdiv - 1) + j, i * (vdiv - 1) + j + 1));
            for (int i = 0; i < hdiv - 1; i++)
                for (int j = 0; j < vdiv - 1; j++)
                    mesh.Edges.Add(new Edge(i * (vdiv - 1) + j, i * (vdiv - 1) + j + vdiv - 1));
            for (int j = 0; j < vdiv - 1; j++)
                mesh.Edges.Add(new Edge((hdiv - 1) * (vdiv - 1) + j, j));
            for (int j = 0; j < hdiv; j++)
                mesh.Edges.Add(new Edge(j * (vdiv - 1), mesh.Vertices.Count - 1));
            for (int j = 0; j < hdiv; j++)
                mesh.Edges.Add(new Edge(j * (vdiv - 1) + vdiv - 2, mesh.Vertices.Count - 2));
            #endregion

            // Lapok
            #region Faces
            for (int i = 0; i < hdiv - 1; i++)
                for (int j = 0; j < vdiv - 2; j++) {
                    mesh.Faces.Add(new Face(i * (vdiv - 1) + j, i * (vdiv - 1) + j + 1, i * (vdiv - 1) + j + vdiv));
                    mesh.Faces.Add(new Face(i * (vdiv - 1) + j, i * (vdiv - 1) + j + vdiv, i * (vdiv - 1) + j + vdiv - 1));
                }
            for (int j = 0; j < vdiv - 2; j++) {
                mesh.Faces.Add(new Face((hdiv - 1) * (vdiv - 1) + j, (hdiv - 1) * (vdiv - 1) + j + 1, j + 1));
                mesh.Faces.Add(new Face((hdiv - 1) * (vdiv - 1) + j, j + 1, j));
            }
            for (int j = 0; j < hdiv - 1; j++)
                mesh.Faces.Add(new Face(j * (vdiv - 1), (j + 1) * (vdiv - 1), mesh.Vertices.Count - 1));
            mesh.Faces.Add(new Face((hdiv - 1) * (vdiv - 1), 0, mesh.Vertices.Count - 1));
            for (int j = 0; j < hdiv - 1; j++)
                mesh.Faces.Add(new Face(j * (vdiv - 1) + vdiv - 2, mesh.Vertices.Count - 2, (j + 1) * (vdiv - 1) + vdiv - 2));
            mesh.Faces.Add(new Face((hdiv - 1) * (vdiv - 1) + vdiv - 2, mesh.Vertices.Count - 2, (vdiv - 2)));
            #endregion
        }

        public override void ChangeParams() {
            NewEllipsoid ns = new NewEllipsoid();
            ns.Text = "Modify Ellipsoid";
            ns.tbRadX.Text = this.XRadius.ToString();
            ns.tbRadY.Text = this.YRadius.ToString();
            ns.tbRadZ.Text = this.ZRadius.ToString();
            ns.tbHdiv.Text = this.Hdiv.ToString();
            ns.tbVdiv.Text = this.Vdiv.ToString();
            if (this.center.X != 0.0 || this.center.Y != 0.0 || this.center.Z != 0.0) {
                ns.cbCenter.Checked = false;
                ns.tbCX.Text = this.center.X.ToString();
                ns.tbCY.Text = this.center.Y.ToString();
                ns.tbCZ.Text = this.center.Z.ToString();
            } else ns.cbCenter.Checked = true;
            if (ns.ShowDialog() == System.Windows.Forms.DialogResult.Cancel) return;
            this.xradius = ns.radx;
            this.yradius = ns.rady;
            this.zradius = ns.radz;
            this.hdiv = ns.hdiv;
            this.vdiv = ns.vdiv;
            if (ns.cbCenter.Checked)
                this.center = new Point3D(0.0, 0.0, 0.0);
            else
                this.center = new Point3D(ns.cx, ns.cy, ns.cz);
            this.e1 = new Point3D(xradius, 0.0, 0.0);
            this.e2 = new Point3D(0.0, yradius, 0.0);
            this.e3 = new Point3D(0.0, 0.0, zradius);
            // Befoglaló téglatest
            this.UpperCorner = new Point3D(xradius, yradius, zradius);
            this.LowerCorner = new Point3D(-xradius, -yradius, -zradius);
            base.ChangeParams();
        }
    }
}
