private void voronoiButton_Click(object sender, EventArgs e)
        {
            if (sampler == null)
            {
                MessageBox.Show("You must load a original picture", "Original picture missing", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            if (timesCheckBox.Checked && MessageBox.Show("Are you sure, that interval 0-100% is right? Solving Voronoi diagram on this interval can be very slowly (tens of minutes, hours, ...).", "Is interval 0-100% right?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
            {
                return;
            }

            voronoiButton.Enabled = false;

            AutoSample(e);

            BenTools.Data.HashSet <BenTools.Mathematics.Vector> data = sampler.GetSampledData();

            if (data == null && !resample.Checked)
            {
                MessageBox.Show("You must sample original picture", "Original picture isn't sampled.", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                return;
            }

            voronoi = new Voronoi(data);

            Thread t = new Thread(ComputeVoronoiMap);

            t.Start();

            while (t.ThreadState == ThreadState.Running)
            {
                Application.DoEvents();
                Thread.Sleep(200);
                voronoiProgress.Value = voronoi.GetProgressOfComputing();
            }

            voronoiButton.Enabled = true;
        }
        /// <summary>
        /// Get the position with the largest view cone on a specific target and with respect to an input radius
        /// </summary>
        public static void GetOptimalPosition(float[] target, float radius)
        {
            List <float[]> neighbor_coords         = new List <float[]>();
            ArrayList      neighbor_theta_phi      = new ArrayList();
            ArrayList      neighbor_correspondance = new ArrayList();
            float          min_theta = 1000.0f;
            float          max_theta = 0.0f;
            float          min_phi   = 1000.0f;
            float          max_phi   = 0.0f;

            // Get all the atoms inside the sphere centered on the target and of the input radius, translate them into polar coordinates
            for (int i = 0; i < MoleculeModel.atomsLocationlist.Count; i++)
            {
                double dist = Distance3f(MoleculeModel.atomsLocationlist[i], target);
                if (dist < radius)
                {
                    neighbor_coords.Add(MoleculeModel.atomsLocationlist[i]);
                    float[] atom = new float[3];
                    atom[0] = MoleculeModel.atomsLocationlist[i][0] - target[0];
                    atom[1] = MoleculeModel.atomsLocationlist[i][1] - target[1];
                    atom[2] = MoleculeModel.atomsLocationlist[i][2] - target[2];
                    float  theta     = (float)Math.Acos(atom[2] / dist);
                    float  phi       = (float)Math.Atan2(atom[1], atom[0]);
                    Vector theta_phi = new Vector(2);
                    theta_phi[0] = theta;
                    theta_phi[1] = phi;
                    neighbor_theta_phi.Add(theta_phi);
                    neighbor_correspondance.Add(i);
//							Debug.Log (theta_phi);
                    theta_phi    = new Vector(2);
                    theta_phi[0] = theta + (float)Math.PI / 2;
                    theta_phi[1] = phi + (float)Math.PI;
                    neighbor_theta_phi.Add(theta_phi);
//							Debug.Log (theta_phi);
                    theta_phi    = new Vector(2);
                    theta_phi[0] = theta + (float)Math.PI / 2;
                    theta_phi[1] = phi;
                    neighbor_theta_phi.Add(theta_phi);
//							Debug.Log (theta_phi);
                    theta_phi    = new Vector(2);
                    theta_phi[0] = theta;
                    theta_phi[1] = phi + (float)Math.PI;
                    neighbor_theta_phi.Add(theta_phi);
//							Debug.Log (theta_phi);
                    if (theta + (float)Math.PI / 2 > max_theta)
                    {
                        max_theta = theta + (float)Math.PI / 2;
                    }
                    if (theta < min_theta)
                    {
                        min_theta = theta;
                    }
                    if (phi + (float)Math.PI > max_phi)
                    {
                        max_phi = phi + (float)Math.PI;
                    }
                    if (phi < min_phi)
                    {
                        min_phi = phi;
                    }
                }
            }

//					Debug.Log (neighbor_theta_phi.GetEnumerator().Current[0]+" "+neighbor_theta_phi.GetEnumerator().Current[1]);
//					Debug.Log (neighbor_theta_phi[1][0]+" "+neighbor_theta_phi[1][1]);
//					Debug.Log (neighbor_theta_phi[2][0]+" "+neighbor_theta_phi[2][1]);
//					Debug.Log (neighbor_theta_phi[3][0]+" "+neighbor_theta_phi[3][1]);

            StreamWriter sw = new StreamWriter(@"/Users/trellet/Dev/UnityMol_svn/trunk/Assets/neighbors.txt");


            foreach (Vector neighbor in neighbor_theta_phi)
            {
                sw.WriteLine("" + neighbor[0] + " " + neighbor[1]);
            }
            sw.Close();

//					int length = neighbor_theta_phi.Count;
//					for(int i=0; i<length; i++)
//					{
//						Vector theta_phi = new Vector(2);
//						theta_phi[0] = neighbor_theta_phi[i][0]+ (float) Math.PI;
//						theta_phi[1] = neighbor_theta_phi[i][1]+2*(float) Math.PI;
//						neighbor_theta_phi.Add (theta_phi);
//						theta_phi[0] = neighbor_theta_phi[i][0]+(float) Math.PI;
//						theta_phi[1] = neighbor_theta_phi[i][1];
//						neighbor_theta_phi.Add (theta_phi);
//						theta_phi[0] = neighbor_theta_phi[i][0];
//						theta_phi[1] = neighbor_theta_phi[i][1]+2*(float) Math.PI;
//						neighbor_theta_phi.Add (theta_phi);
//					}
            Debug.Log("Nb of neighbors: " + neighbor_theta_phi.Count);
            Debug.Log("Min/max theta/phi: " + min_theta + " " + max_theta + " " + min_phi + " " + max_phi);

            // Compute the Voronoi graph from the neighbors polar coordinates
            VoronoiGraph result = Fortune.ComputeVoronoiGraph(neighbor_theta_phi);

            MoleculeModel.atomsLocationlist.OrderBy(x => x[0]);
            Debug.Log(result.Vertizes.Count);

            StreamWriter sw2 = new StreamWriter(@"/Users/trellet/Dev/UnityMol_svn/trunk/Assets/vertices.txt");

            BenTools.Data.HashSet temp = new BenTools.Data.HashSet();

            foreach (Vector vert in result.Vertizes)
            {
                if (vert[0] > min_theta && vert[0] < max_theta && vert[1] < max_phi && vert[1] > min_phi)
                {
                    sw2.WriteLine("" + vert[0] + " " + vert[1]);
                    temp.Add(vert);
                }
            }
            sw2.Close();

            result.Vertizes = temp;



            //double min_dist = 1000.0;
            double max_dist = 0.0;

            float[] best_pos = new float[2];
            //float[] best_point = new float[2];
            //float[] vertex = new float[2];
            //float[] point = new float[2];
            //					Vector vert = new Vector();
            //int c = 0;
            double distance = 0.0;
            Dictionary <double, float[]> vertices = new Dictionary <double, float[]>();


            // Find the largest distance between each vertex and the closest point to each of them
            //// 1st METHOD (faster, use the edges that contain point information)
            foreach (VoronoiEdge edge in result.Edges)
            {
                //min_dist = 1000.0;

                if (edge.VVertexA[0] > min_theta && edge.VVertexA[0] < max_theta && edge.VVertexA[1] < max_phi && edge.VVertexA[1] > min_phi)
                {
                    distance = Distance2f(edge.VVertexA, edge.LeftData);
                    float[] t = new float[2];
                    t[0] = (float)edge.VVertexA[0];
                    t[1] = (float)edge.VVertexA[1];
                    vertices[distance] = t;
                    if (distance > max_dist)
                    {
                        max_dist    = distance;
                        best_pos[0] = (float)edge.VVertexA[0];
                        best_pos[1] = (float)edge.VVertexA[1];
                    }
                }
                if (edge.VVertexB[0] > min_theta && edge.VVertexB[0] < max_theta && edge.VVertexB[1] < max_phi && edge.VVertexB[1] > min_phi)
                {
                    distance = Distance2f(edge.VVertexB, edge.LeftData);
                    float[] t = new float[2];
                    t[0] = (float)edge.VVertexA[0];
                    t[1] = (float)edge.VVertexA[1];
                    vertices[distance] = t;
                    if (distance > max_dist)
                    {
                        max_dist    = distance;
                        best_pos[0] = (float)edge.VVertexB[0];
                        best_pos[1] = (float)edge.VVertexB[1];
                    }
                }
            }

            var list = vertices.Keys.ToList();

            list.Sort();
            float[] cartesian = new float[3];
            for (int i = list.Count - 1; i > list.Count - 8; i--)
            {
                //Debug.Log(list[i]+": "+vertices[list[i]][0]+" "+vertices[list[i]][1]);
                cartesian[0] = (radius * (float)Math.Sin(vertices[list[i]][0]) * (float)Math.Cos(vertices[list[i]][1])) + target[0];
                cartesian[1] = (radius * (float)Math.Sin(vertices[list[i]][0]) * (float)Math.Sin(vertices[list[i]][1])) + target[1];
                cartesian[2] = (radius * (float)Math.Cos(vertices[list[i]][0])) + target[2];
                Debug.Log(list[i] + ": " + cartesian[0] + " " + cartesian[1] + " " + cartesian[2]);
            }

            ////// 2nd METHOD (slower, all vertices vs all points)
//					foreach (Vector vert in result.Vertizes)
//					{
//						min_dist = 1000.0;
//
//						foreach (Vector neighbor in neighbor_theta_phi)
//						{
////							vertices[0] = (float) vert[0];
////							vertices[1] = (float) vert[1];
//
//							double dist = Distance2f(vert, neighbor);
//
//							if (dist < min_dist)
//							{
//								min_dist = dist;
//								point[0] = (float) neighbor[0];
//								point[1] = (float) neighbor[1];
//							}
//						}
//						if (min_dist > max_dist)
//						{
//							max_dist = min_dist;
//							best_pos[0] = (float) vert[0];
//							best_pos[1] = (float) vert[1];
//							best_point[0] = point[0];
//							best_point[1] = point[1];
//						}
//
//					}
            Debug.Log("Maximum distance: " + max_dist);
            Debug.Log("Theta and phi: " + best_pos[0] + " " + best_pos[1]);
            float[] best_pos_cart = new float[3];
            //float[] best_pos_cart2 = new float[3];
            //float[] best_pos_cart3 = new float[3];
            //float[] best_pos_cart4 = new float[3];

            // Convert polar coordinates of the best position to cartesian ones + shift to molecule system coordinates
            best_pos_cart[0] = (radius * (float)Math.Sin(best_pos[0]) * (float)Math.Cos(best_pos[1])) + target[0];
            best_pos_cart[1] = (radius * (float)Math.Sin(best_pos[0]) * (float)Math.Sin(best_pos[1])) + target[1];
            best_pos_cart[2] = (radius * (float)Math.Cos(best_pos[0])) + target[2];
            Debug.Log("Best position: " + best_pos_cart[0] + " " + best_pos_cart[1] + " " + best_pos_cart[2]);
//					best_pos_cart2[0] = (radius * (float) Math.Sin(best_pos[0]-Math.PI) * (float) Math.Cos(best_pos[1])) + target[0];
//					best_pos_cart2[1] = (radius * (float) Math.Sin(best_pos[0]-Math.PI) * (float) Math.Sin(best_pos[1])) + target[1];
//					best_pos_cart2[2] = (radius * (float) Math.Cos(best_pos[0]-Math.PI)) + target[2];
//					best_pos_cart3[0] = (radius * (float) Math.Sin(best_pos[0]-Math.PI) * (float) Math.Cos(best_pos[1]-2*Math.PI)) + target[0];
//					best_pos_cart3[1] = (radius * (float) Math.Sin(best_pos[0]-Math.PI) * (float) Math.Sin(best_pos[1]-2*Math.PI)) + target[1];
//					best_pos_cart3[2] = (radius * (float) Math.Cos(best_pos[0]-Math.PI)) + target[2];
//					best_pos_cart4[0] = (radius * (float) Math.Sin(best_pos[0]) * (float) Math.Cos(best_pos[1]-2*Math.PI)) + target[0];
//					best_pos_cart4[1] = (radius * (float) Math.Sin(best_pos[0]) * (float) Math.Sin(best_pos[1]-2*Math.PI)) + target[1];
//					best_pos_cart4[2] = (radius * (float) Math.Cos(best_pos[0])) + target[2];
//					Debug.Log("Best position2: "+best_pos_cart2[0]+" "+best_pos_cart2[1]+" "+best_pos_cart2[2]);
//					Debug.Log("Best position3: "+best_pos_cart3[0]+" "+best_pos_cart3[1]+" "+best_pos_cart3[2]);
//					Debug.Log("Best position4: "+best_pos_cart4[0]+" "+best_pos_cart4[1]+" "+best_pos_cart4[2]);

            // Place the camera at the new best position and make it face the target
            UIData.optim_view            = true;
            maxCamera.optim_target       = new Vector3(target[0], target[1], target[2]);
            maxCamera.optim_cam_position = new Vector3(best_pos_cart[0], best_pos_cart[1], best_pos_cart[2]);
            GameObject camera = GameObject.Find("LoadBox");

            UIData.optim_view_start_point = camera.transform.position;
            UIData.start_time             = Time.time;
            //camera.transform.position = new Vector3(best_pos_cart[0], best_pos_cart[1], best_pos_cart[2]);
//					Wait();
//					camera.transform.position = new Vector3(best_pos_cart2[0], best_pos_cart2[1], best_pos_cart2[2]);
//					Wait();
//					camera.transform.position = new Vector3(best_pos_cart3[0], best_pos_cart3[1], best_pos_cart3[2]);
//					Wait();
//					camera.transform.position = new Vector3(best_pos_cart4[0], best_pos_cart4[1], best_pos_cart4[2]);
            //maxCamera.ghost_target = GameObject.Find("Target");

//					camera.transform.LookAt(ghost_target.transform);
            //result.Vertizes
        }