//---------------------------------------------------------------------------------------------
 // Facultad de Informatica. Universidad Politecnica de Madrid
 // Trabajo de Fin de Carrera. Diciembre de 2000
 // Autor: Juan Carlos Ferreras Ferreras
 // Tutor: Manuel Abellanas Oar
 // Voronoi.java : Simulacion del Algoritmo de Fortune para el Calculo de D. Voronoi en Internet
 // Tambien calcula T. Delaunay y Cierre Convexo
 //---------------------------------------------------------------------------------------------
 
 import java.applet.*;
 import java.awt.*;
 import java.awt.event.*;
 import java.lang.*;
 
 public class voronoi extends Applet {
  int DIM_APPLET_X;     //Ancho en Pixels del Applet según el TAG html
  int DIM_APPLET_Y;     //Alto en Pixels del Applet según el TAG html
  int BALDOSA_X=20;     //Coordenada x de la posicion del canvas en la pantalla
  int BALDOSA_Y=40;     //Coordenada Y de la posicion del canvas en la pantalla
  int TAMANO_BALDOSA_X; //Tamaño en pixels de la baldosa gráfica 
  int TAMANO_BALDOSA_Y; //Tamaño en pixels de la baldosa gráfica 
  int MAX_VERTICES=2000;//Maximo numero de vertices
  int MAX_LADOS=12000;   //Maximo numero de lados
  int MAX_CARAS=4000;   //Maximo numero de caras
  Color COLOR_FONDO_BALDOSA = Color.white; //Color de fondo de la baldosa
  Color COLOR_LINEAS = Color.blue.darker().darker(); //Color de lineas
  Color COLOR_PUNTOS = Color.red; //Color de los puntos
  Color COLOR_PLAYA = new Color((float)0.5783256,
                            (float)0.77211806,
                            (float)0.99363103); //Color de la playa
  matriz_puntos m_puntos; //Array que comprueba si el punto ya esta insertado
  lista_vertices V;       //Lista de vertices
  lista_lados L;          //Lista de lados
  lista_caras C;          //Lista de caras
  inserta_punto accion_pulsar_punto; //Evento de pulsar el canvas
  hacer_drag_sweep drag_sweep;       //Evento para hacer drag en sweep
  hacer_click_sweep click_sweep;     //Evento para hacer click en sweep
  Image fondo;                       //Se guarda el fondo del applet
  Image baldosa_buffer=null;         //Imagen de la baldosa
  Image baldosa_color;               //Imagen de la baldosa color aleatorio
  Image cierre_convexo;              //Imagen del cierre convexo
  Image i_voronoi;                   //Imagen de Voronoi
  Image i_voronoi_color;             //Imagen de Voronoi Color
  Image sweep;                       //Imagen del Sweep 
  Image sweep_color;                 //Imagen del Sweep
  Image cir_dela;                    //Imagen para circunferencia y Delone
  Graphics contexto_baldosa_buffer;  //contexto gráfico de baldosa_buffer
  Graphics contexto_baldosa_color;   //contexto gráfico de baldosa color aleatorio
  Graphics contexto_cierre_convexo;  //contexto gráfico del cierre convexo
  Graphics contexto_i_voronoi;       //contexto voronoi
  Graphics contexto_i_voronoi_color; //contexto voronoi color
  Graphics contexto_sweep;           //contexto sweep
  Graphics contexto_sweep_color;     //contexto sweep color
  Graphics contexto_cir_dela;        // conteto para circunferenca y delanuay
  micanvas baldosa;                  //Canvas que contiene la baldosa inicial
  Button boton_insertar_puntos;      //Comienzo de inserción de puntos
  Choice seleccion;          //Choice para Voronoi, Triangulación, cierre convexo
  Choice velocidad;          //Choice para la velocidad de la simulacion automatica
  CheckboxGroup grupo_check; //Para agrupar los tres check 
  Checkbox check_b_n;        //Checkbox b/n    
  Checkbox check_color;      //Checkbox para color
  Checkbox check_circulos;   //Checkbox para circ
  Checkbox check_voro;       //Checkbox para voro
  Button    boton_nuevo;        //Boton nuevo
  Button    boton_simula;       //Boton Simulacion Sweep Line
  Button    boton_cambiar_color;//Boton para cambiar botones
  Button    boton_manual;       //Boton manual sweep
  Button    boton_automatico;   //Boton automatico sweep
  Button boton_volver;       //Boton volver
  Button boton_comenzar;     //Boton para comenzar la simulacion automatica
  Label titulo;              //String de sweep line
  boolean pinta_delaunay = true;      //Por defecto Delaunay
  boolean pinta_cierre_convexo=false; //Por defecto Cierre Convexo
  boolean pinta_voronoi=false;        //Por defecto Voronoi
  boolean pinta_b_n=true;      //Por defecto b/n
  boolean pinta_color=false;   //Por defecto color a false
  boolean pinta_sweep=false;   //Por defecto sweep line a false 
  boolean pinta_sweep_automatico=false; //Por defecto sweep line a false 
  boolean mostrar_voro_dela=false;      //Por defecto voro_dela a false
  boolean mostrar_circulos_dela=false;  //Por defecto cir_dela a false
  int posicion_x_linea=0;    //Posicion de la linea de barrido
  int incremento=1;          //Incremento de la linea de barrido
  Polygon l_polig[];         //Para guardar los voronoi de todos los puntos
  Polygon lista_voronoi_camb_color[]; // Lista de los poligonos de Voronoi
 
  class micanvas extends Canvas {
   public void update(Graphics g) {
    paint(g);
   }
   public void paint (Graphics g) {
    if (baldosa_buffer != null) {
     if (pinta_delaunay &&
         pinta_b_n &&
         !(mostrar_voro_dela || mostrar_circulos_dela)) {
      g.drawImage(baldosa_buffer, 0, 0, null);
     }
     if (pinta_delaunay && pinta_b_n && (mostrar_voro_dela || mostrar_circulos_dela)) {
      Polygon p;
      Polygon l_p[];
      double centro_x[];
      double centro_y[];
      int n_p=0;
      l_p=new Polygon[C.num_caras];
      centro_x=new double[C.num_caras];
      centro_y=new double[C.num_caras];
      for (int i=1; i<C.num_caras;i++) {
       p = new Polygon();
       p.addPoint(C.l_caras[i].lado_interno.origen.punto.x,
                  C.l_caras[i].lado_interno.origen.punto.y);
       p.addPoint(C.l_caras[i].lado_interno.next.origen.punto.x,
                  C.l_caras[i].lado_interno.next.origen.punto.y);
       p.addPoint(C.l_caras[i].lado_interno.prev.origen.punto.x,
                  C.l_caras[i].lado_interno.prev.origen.punto.y);
       if (!(((p.xpoints[0]==V.l_vertices[0].punto.x) &&
           (p.ypoints[0]==V.l_vertices[0].punto.y)) ||
           ((p.xpoints[0]==V.l_vertices[1].punto.x) &&
           (p.ypoints[0]==V.l_vertices[1].punto.y)) ||
           ((p.xpoints[0]==V.l_vertices[2].punto.x) &&
           (p.ypoints[0]==V.l_vertices[2].punto.y)) ||
           ((p.xpoints[1]==V.l_vertices[0].punto.x) &&
           (p.ypoints[1]==V.l_vertices[0].punto.y)) ||
           ((p.xpoints[1]==V.l_vertices[1].punto.x) &&
           (p.ypoints[1]==V.l_vertices[1].punto.y)) ||
           ((p.xpoints[1]==V.l_vertices[2].punto.x) &&
           (p.ypoints[1]==V.l_vertices[2].punto.y)) ||
           ((p.xpoints[2]==V.l_vertices[0].punto.x) &&
           (p.ypoints[2]==V.l_vertices[0].punto.y)) ||
           ((p.xpoints[2]==V.l_vertices[1].punto.x) &&
           (p.ypoints[2]==V.l_vertices[1].punto.y)) ||
           ((p.xpoints[2]==V.l_vertices[2].punto.x) &&
           (p.ypoints[2]==V.l_vertices[2].punto.y)))) {
        l_p[n_p]=p;
        centro_x[n_p]=C.l_caras[0].circun_x(C.l_caras[i]);
        centro_y[n_p]=C.l_caras[0].circun_y(C.l_caras[i]);
        n_p++;
       }//del if
      }//del for
      if (mostrar_circulos_dela && (!mostrar_voro_dela)) {
       contexto_cir_dela.setColor(COLOR_FONDO_BALDOSA);
       contexto_cir_dela.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
       contexto_cir_dela.setColor(Color.green.brighter().brighter());
       int distancia=0;
       for (int n=0; n<n_p; n++) {
        distancia=(int)V.l_vertices[0].distancia(centro_x[n],
                                                 centro_y[n],
                                 l_p[n].xpoints[0],
                                 l_p[n].ypoints[0]);
        contexto_cir_dela.drawOval((int)centro_x[n]-distancia,
                                   (int)centro_y[n]-distancia,
                                (int)2 * distancia,
                                (int)2 * distancia);
       } //del for
       contexto_cir_dela.setColor(Color.red);
       for (int j=0; j<n_p; j++) contexto_cir_dela.drawPolygon(l_p[j]);
       if (V.num_vertices==5) contexto_cir_dela.drawLine(V.l_vertices[3].punto.x,
                                                   V.l_vertices[3].punto.y,
                                                  V.l_vertices[4].punto.x,
                                                 V.l_vertices[4].punto.y);
      }
      if (mostrar_voro_dela && (!mostrar_circulos_dela)) {
       contexto_cir_dela.drawImage(i_voronoi, 0, 0, null);
       contexto_cir_dela.setColor(Color.red);
       for (int j=0; j<n_p; j++) contexto_cir_dela.drawPolygon(l_p[j]);
       if (V.num_vertices==5) contexto_cir_dela.drawLine(V.l_vertices[3].punto.x,
                                                         V.l_vertices[3].punto.y,
                                                         V.l_vertices[4].punto.x,
                                                         V.l_vertices[4].punto.y);
      } //de mostrar_voro_dela
      if (mostrar_circulos_dela && mostrar_voro_dela) {
       contexto_cir_dela.drawImage(i_voronoi, 0, 0, null);
       contexto_cir_dela.setColor(Color.green.brighter().brighter());
       int distancia=0;
       for (int n=0; n<n_p; n++) {
        distancia=(int)V.l_vertices[0].distancia(centro_x[n],
                                                 centro_y[n],
                                              l_p[n].xpoints[0],
                                              l_p[n].ypoints[0]);
        contexto_cir_dela.drawOval((int)centro_x[n]-distancia,
                                      (int)centro_y[n]-distancia,
                                      (int)2 * distancia,
                                      (int)2 * distancia);
       } //del for
       contexto_cir_dela.setColor(Color.red);
       for (int j=0; j<n_p; j++) contexto_cir_dela.drawPolygon(l_p[j]);
       if (V.num_vertices==5) contexto_cir_dela.drawLine(V.l_vertices[3].punto.x,
                                                         V.l_vertices[3].punto.y,
                                                         V.l_vertices[4].punto.x,
                                                         V.l_vertices[4].punto.y);
      } //de mostrar_circulos_dela
      contexto_cir_dela.setColor(COLOR_PUNTOS);
      for (int l=0; l<V.num_vertices; l++) {
       contexto_cir_dela.fillOval( V.l_vertices[l].punto.x-2,
                                   V.l_vertices[l].punto.y-2,
                                   5,
                                   5);
      }
      g.drawImage(cir_dela, 0, 0, null);
     }
     if (pinta_delaunay && pinta_color) {
      g.drawImage(baldosa_color, 0, 0, null);
     }
     if (pinta_cierre_convexo) {
      g.drawImage(cierre_convexo, 0, 0, null);
     }
     if (pinta_voronoi && pinta_b_n) {
      g.drawImage(i_voronoi, 0, 0, null);
     }
     if (pinta_voronoi && pinta_color) {
      g.drawImage(i_voronoi_color, 0, 0, null);
     }
     if (pinta_sweep) {
       Polygon parabola;
       parabola =new Polygon();
       int max_valor=-1;
       int valor; //valor
       int valor_aux=20000;
       valor=valor_aux;
       for (int k=-1; k<TAMANO_BALDOSA_Y+1; k++) {
        for (int t=3; t<V.num_vertices; t++) {
            if (V.l_vertices[t].punto.x > posicion_x_linea) {
          valor_aux = (int)((0.5*(k*k-2.0*V.l_vertices[t].punto.y*k+V.l_vertices[t].punto.y * V.l_vertices[t].punto.y +V.l_vertices[t].punto.x * V.l_vertices[t].punto.x-posicion_x_linea*posicion_x_linea))/(V.l_vertices[t].punto.x-posicion_x_linea));
          if (valor_aux<valor) valor=valor_aux;
         } //del if
        } //del for
        if (valor < posicion_x_linea) {
            valor = posicion_x_linea;
            parabola.addPoint(valor,k-1);
            parabola.addPoint(valor,k+1);
        } else { 
         parabola.addPoint(valor,k);
        }
        if (valor > max_valor) max_valor=valor;                
        valor=20000;
        valor_aux=20000;
       } //del for
       parabola.addPoint(TAMANO_BALDOSA_X+2,TAMANO_BALDOSA_Y+2);                          
       parabola.addPoint(-2,TAMANO_BALDOSA_Y+2); 
       parabola.addPoint(-2,-2);
       parabola.addPoint(TAMANO_BALDOSA_X+2,-2);
       if (pinta_color) {
        contexto_sweep.drawImage(i_voronoi_color, 0, 0, null);
       } else { 
        contexto_sweep.drawImage(i_voronoi, 0, 0, null);
       }
       contexto_sweep.setColor(COLOR_PLAYA);
       contexto_sweep.fillRect(0,0,posicion_x_linea,TAMANO_BALDOSA_Y);
       contexto_sweep.fillPolygon(parabola);
       contexto_sweep.setColor(COLOR_LINEAS);
       contexto_sweep.drawPolygon(parabola);
       for (int i=0; i<TAMANO_BALDOSA_Y; i++) {
        if ((posicion_x_linea>=0) && (posicion_x_linea < TAMANO_BALDOSA_X))
         if (m_puntos.esta(posicion_x_linea,i))
             contexto_sweep.drawLine(posicion_x_linea,i,parabola.xpoints[i],i); 
       }
       // Y los puntos
       contexto_sweep.setColor(COLOR_PUNTOS);
       for (int l=0; l<V.num_vertices; l++) {
        contexto_sweep.fillOval( V.l_vertices[l].punto.x-2,
                                 V.l_vertices[l].punto.y-2,
                                 5,
                                 5);
       }
       contexto_sweep.setColor(Color.white); 
       contexto_sweep.fillRect(posicion_x_linea-1,-1,
                               2,TAMANO_BALDOSA_Y+1);
       contexto_sweep.setColor(Color.black);
       contexto_sweep.drawLine(posicion_x_linea, -1,
                                  posicion_x_linea, TAMANO_BALDOSA_Y+1);
       g.drawImage(sweep, 0, 0, null);
       if (pinta_sweep_automatico && (max_valor > -1)) {
        posicion_x_linea= posicion_x_linea - incremento;
        baldosa.repaint();
       } 
       if ((pinta_sweep_automatico) && (max_valor <= -1))
        boton_comenzar.setEnabled(true);
     } 
    } //del if
   } //de paint
  } // de micanvas
   
  //Mantiene una matriz booleana con los puntos que se han pulsado  
  public class matriz_puntos {
   public int num_puntos;
   public boolean array_puntos [][]; //Array que comprueba si el punto ya está.
   // Constructores
   public matriz_puntos (int x, int y) { //lo crea nuevo
    array_puntos=new boolean[x][y]; //array del tamaño del canvas
    num_puntos=0;
    for (int i=0; i<x; i++) {
     for (int j=0; j<y; j++) {
      array_puntos[i][j] = false;
     }
    }          
   } 
   //Metodos
   public boolean esta (int x, int y) {
    return (array_puntos[x][y] == true); // Porque no estan a false
   }
   public void inserta (int x, int y) {
    array_puntos[x][y]=true;
    num_puntos++;
   }
   public void inicializa (int x, int y) { // Inicializa la matriz de boolean
    num_puntos=0;
    for (int i=0; i<x; i++) {
     for (int j=0; j<y; j++) {
      array_puntos[i][j] = false;
     }
    }          
   } 
  } // De la clase matriz_puntos
    
  public class vertice {
   public Point punto;
   public lado lado_incidente;
   public Color color_vertice;
   //Constructores
   public vertice (Point p, lado l) {
    punto = new Point(p);
    lado_incidente=l;
    color_vertice = new Color((float)Math.random(),
                              (float)Math.random(),
                              (float)Math.random());
   }
   public vertice (int x, int y, lado l) {
    punto = new Point(x, y);
    lado_incidente=l;
    color_vertice = new Color((float)Math.random(),
                              (float)Math.random(),
                              (float)Math.random());
   }
   public vertice () {
    punto = null;
    lado_incidente = null;
    color_vertice = new Color((float)Math.random(),
                              (float)Math.random(),
                              (float)Math.random());
   }
   // Metodos
   public double distancia_2 (int x1, int y1, int x2, int y2) {
   // Devuelve la distancia al cuadrado de dos puntos
    return Math.pow((double)x1 - (double)x2, 2) +
                    Math.pow((double)y1 - (double)y2, 2);
   } 
   public double distancia_2 (double x1, double y1, double x2, double y2) {
   // Devuelve la distancia al cuadrado de dos puntos
    return Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2);
   } 
   public double distancia (int x1, int y1, int x2, int y2) {
   // Devuelve la distancia de dos puntos
    return Math.sqrt (distancia_2(x1, y1, x2, y2));
   }
   public double distancia (double x1, double y1, double x2, double y2) {
   // Devuelve la distancia de dos puntos
    return Math.sqrt (distancia_2(x1, y1, x2, y2));
   }
  } // de vertice
    
  public class lista_vertices {
   public vertice l_vertices[];
   public int num_vertices;
   // Constructor
   public lista_vertices(int i) {
    l_vertices = new vertice[i];
    num_vertices = 0;
   }
   // Métodos
   public void inserta (vertice v, lado l) {
    l_vertices[num_vertices] = v;
    num_vertices++;
   } 
   public void inserta (Point p, lado l) {
    l_vertices[num_vertices] = new vertice(p, l);
    num_vertices++;
   } 
   public void inserta (int x, int y, lado l) {
    l_vertices[num_vertices] = new vertice(x, y, l);
    num_vertices++;
   } 
   public Point ultimo () {
    return l_vertices[num_vertices-1].punto;
   } 
   public Point punto (int index) {
    return l_vertices[index].punto;
   }
   public void inicializa() {
   // Inicializa
    num_vertices = 0;
   }
  }
     
  public class lado {   //Del triángulo
   public vertice origen;
   public lado twin;
   public lado next;
   public lado prev;
   public cara cara_incidente;
   // Constructor
   public lado(vertice or, lado tw, lado nx, lado pr, cara c_i) {
    origen=or;
    twin=tw;
    next=nx;
    prev=pr;
    cara_incidente=c_i;
   }
   // Metodos
   public boolean ilegal (vertice v, lado l) {        
    vertice p0;
    vertice p1; // vertices del triangulo externo
    vertice p2;
    vertice v0;
    vertice v1; // vertices de los 2 triangulos
    vertice v2;
    vertice v3;
    p0 = new vertice();
    p1 = new vertice();
    p2 = new vertice();
    v0 = new vertice();
    v1 = new vertice();
    v2 = new vertice();
    v3 = new vertice();
    p0 = V.l_vertices[0]; 
    p1 = V.l_vertices[1]; 
    p2 = V.l_vertices[2];
    v0 = v;
    v1 = l.origen;
    v2 = l.twin.prev.origen;
    v3 = l.twin.origen;
    // Empezamos con los casos
    // i y j son negativos
    if (((v1==p0) ||
         (v1==p1) ||
         (v1==p2)) &&
        ((v3==p0) ||
         (v3==p1) ||
         (v3==p2)) ) {
     return false;
    } // son todos positivos
    if ((v0!=p0) && (v0!=p1) && (v0!=p2) &&
        (v1!=p0) && (v1!=p1) && (v1!=p2) &&
        (v2!=p0) && (v2!=p1) && (v2!=p2) &&
        (v3!=p0) && (v3!=p1) && (v3!=p2) ) {
     double c_x;
     double c_y;
     c_x = l.cara_incidente.circun_x(l.cara_incidente); 
     c_y = l.cara_incidente.circun_y(l.cara_incidente); 
     if (v0.distancia_2 (c_x, c_y, (double)v0.punto.x, (double)v0.punto.y) >
         v0.distancia_2 (c_x, c_y, (double)v2.punto.x, (double)v2.punto.y)) 
      return true;
     else return false;        
    }  
    // Solo 1 negativo
    int cuantos = 0;
    int cuales [];
    cuales = new int[4];
    for (int i=0; i<4; i++) cuales[i]= -1;
    if (v0==p0){
     cuales[0] = 0;
     cuantos++;
    }
    if (v0==p1){
     cuales[0] = 1;
     cuantos++;
    }
    if (v0==p2){
     cuales[0] = 2;
     cuantos++;
    }       
    if (v1==p0){
     cuales[1] = 0;
     cuantos++;
    }
    if (v1==p1){
     cuales[1] = 1;
     cuantos++;
    }
    if (v1==p2){
     cuales[1] = 2;
     cuantos++;
    }
    if (v2==p0){
     cuales[2] = 0;
     cuantos++;
    }
    if (v2==p1){
     cuales[2] = 1;
     cuantos++;
    }
    if (v2==p2){
     cuales[2] = 2;
     cuantos++;
    }
    if (v3==p0){
     cuales[3] = 0;
     cuantos++;
    }
    if (v3==p1){
     cuales[3] = 1;
     cuantos++;
    }
    if (v3==p2){
     cuales[3] = 2;
     cuantos++;
    }
    // 1 Negativo             
    if (cuantos == 1) {
     if ((cuales[1]!= -1)||
      (cuales[3]!= -1)) {
      if ((l.cara_incidente.left_no_colineal(v0.punto, v1.punto, v2.punto)) &&
       (l.cara_incidente.left_no_colineal(v2.punto, v3.punto, v0.punto))) {
       return true;
      }       
     } else { 
      return false;
     }      
    }
    // 2 Negativos    
    if (cuantos == 2) {
     if ((cuales[0] + cuales[2]) >
      (cuales[1] + cuales[3])) {
      return false;
     } else {
      if ((l.cara_incidente.left_no_colineal(v0.punto, v1.punto, v2.punto)) &&
       (l.cara_incidente.left_no_colineal(v2.punto, v3.punto, v0.punto))) {                            
       return true;
      }    
     }
    }
    // Fin de solo 1 negativo     
    return false;  
   } //de ilegal
          
   public void legaliza_lado(vertice v, lado l) {
    lado aux1;
    lado aux2;
    lado aux3;
    lado aux4;
    lado aux5;
    lado aux6;
    cara caraaux1;
    cara caraaux2;
    if (ilegal(v,l)) {
     aux1 = new lado(null, null, null, null, null);
     aux2 = new lado(null, null, null, null, null);
     aux3 = new lado(null, null, null, null, null);
     aux4 = new lado(null, null, null, null, null);
     aux5 = new lado(null, null, null, null, null);
     aux6 = new lado(null, null, null, null, null);
     caraaux1 = new cara(null);
     caraaux2 = new cara(null);
     aux1 = l;
     aux2 = l.next;
     aux3 = l.prev;
     aux4 = l.twin;
     aux5 = l.twin.next;
     aux6 = l.twin.prev;
     caraaux1 = aux1.cara_incidente;
     caraaux2 = aux4.cara_incidente;
     //los origenes
     aux1.origen = aux3.origen;
     aux4.origen = aux6.origen;
     //Los twin
     // No es necesario
     // Los next
     aux1.next = aux6;
     aux2.next = aux1;
     aux3.next = aux5;
     aux4.next = aux3;
     aux5.next = aux4;
     aux6.next = aux2;
     // Los prev
     aux1.prev = aux2;
     aux2.prev = aux6;
     aux3.prev = aux4;
     aux4.prev = aux5;
     aux5.prev = aux3;
     aux6.prev = aux1;
     // Las cara_incidente
     aux1.cara_incidente = caraaux1;
     aux2.cara_incidente = caraaux1;
     aux3.cara_incidente = caraaux2;
     aux4.cara_incidente = caraaux2;
     aux5.cara_incidente = caraaux2;
     aux6.cara_incidente = caraaux1;
     //Lados internos de las caras
     caraaux1.lado_interno = aux1; 
     caraaux2.lado_interno = aux4;
     //Los vertices
     aux2.origen.lado_incidente = aux2; 
     aux3.origen.lado_incidente = aux3; 
     aux5.origen.lado_incidente = aux5; 
     aux6.origen.lado_incidente = aux6; 
     // Y legalizo los nuevos lados
     legaliza_lado(v, aux5);
     legaliza_lado(v, aux6);
    } // del if
   } // del metodo legaliza_lado     
  }
    
  public class lista_lados {
   public lado l_lados[];
   public int num_lados;
   public lista_lados(int i) {
    l_lados = new lado[i];
    num_lados = 0;
   }
   public void inicializa() {
    // Inicializa
    num_lados = 0;
   }
  }
 
  public class cara {
   public lado lado_interno;
   public Color color_cara;
   //Constructor
   public cara (lado l) {
    lado_interno = l;
    color_cara = new Color((float)Math.random(),
                           (float)Math.random(),
                           (float)Math.random());
   }
   //Metodos
   public int area2 (Point p1, Point p2, Point p3) {
    //2 veces el area
    return (p1.x * p2.y - p1.y * p2.x + 
            p1.y * p3.x - p1.x * p3.y + 
            p2.x * p3.y - p3.x * p2.y);  
   }
   public boolean colineal (Point p1, Point p2, Point p3) {
    // true si son colineales
    return (area2(p1, p2, p3)==0);
   }
   public boolean left_no_colineal (Point p1, Point p2, Point p3) {
    // true si son colineales
    return (area2(p1, p2, p3)<0);
   }
   public boolean left (Point p1, Point p2, Point p3) {
    // true si p3 a la izqda. de p1---p2
    return (area2(p1, p2, p3)<=0);
   }
   public boolean en_triangulo(cara c, Point p) {
    if (
        left(c.lado_interno.origen.punto, c.lado_interno.next.origen.punto, p) &&
        left(c.lado_interno.prev.origen.punto, c.lado_interno.origen.punto, p) &&
        left(c.lado_interno.next.origen.punto, c.lado_interno.prev.origen.punto, p)
       ) return true;
    else return false;
   }
   public boolean interior_estricto_al_triangulo (cara c, Point p) {
    if (
        left_no_colineal(c.lado_interno.origen.punto, c.lado_interno.next.origen.punto, p) &&
        left_no_colineal(c.lado_interno.prev.origen.punto, c.lado_interno.origen.punto, p) &&
        left_no_colineal(c.lado_interno.next.origen.punto, c.lado_interno.prev.origen.punto, p)
        ) return true;
    else return false;
   }
   public lado lado_interseccion (cara c, Point p) {
    if (colineal(c.lado_interno.origen.punto, c.lado_interno.next.origen.punto, p))
     return c.lado_interno;
    else if (colineal(c.lado_interno.prev.origen.punto, c.lado_interno.origen.punto, p))
     return (c.lado_interno.prev);
    else if (colineal(c.lado_interno.next.origen.punto, c.lado_interno.prev.origen.punto, p))
     return (c.lado_interno.next);
    else return null; // Nunca se da el caso      
   }
   public cara encuentra_triangulo (Point p) {
    int i;
    for (i=1; i<C.num_caras; i++) { //nos saltamos la cara 0 pq es la del triangulo externo
     if (en_triangulo (C.l_caras[i], p)) break; 
    }          
    return C.l_caras[i];
   } // del metodo
   public double circun_x (cara c) {
    double x1;    
    double y1;    
    double x2;    
    double y2;    
    double x3;    
    double y3;    
    x1= (double)c.lado_interno.origen.punto.x;
    y1= (double)c.lado_interno.origen.punto.y;
    x2= (double)c.lado_interno.next.origen.punto.x;
    y2= (double)c.lado_interno.next.origen.punto.y;
    x3= (double)c.lado_interno.prev.origen.punto.x;
    y3= (double)c.lado_interno.prev.origen.punto.y;
    return (y3*x2*x2-y1*x2*x2+y2*y2*y3+y1*x3*x3+y3*y3*y1+
            y2*x1*x1-y1*y2*y2-x1*x1*y3-x3*x3*y2-y2*y3*y3+
            y1*y1*y2-y3*y1*y1)/
           ((double)2.0*(x1*y2-x1*y3-x3*y2-x2*y1+y1*x3+y3*x2));
   }
   public float circun_x_float (cara c) {
    float x1;    
    float y1;    
    float x2;    
    float y2;    
    float x3;    
    float y3;    
    x1= (float)c.lado_interno.origen.punto.x;
    y1= (float)c.lado_interno.origen.punto.y;
    x2= (float)c.lado_interno.next.origen.punto.x;
    y2= (float)c.lado_interno.next.origen.punto.y;
    x3= (float)c.lado_interno.prev.origen.punto.x;
    y3= (float)c.lado_interno.prev.origen.punto.y;
    return (y3*x2*x2-y1*x2*x2+y2*y2*y3+y1*x3*x3+y3*y3*y1+
            y2*x1*x1-y1*y2*y2-x1*x1*y3-x3*x3*y2-y2*y3*y3+
            y1*y1*y2-y3*y1*y1)/
           ((float)2.0*(x1*y2-x1*y3-x3*y2-x2*y1+y1*x3+y3*x2));
   }
   public double circun_y (cara c) {
    double x1;    
    double y1;    
    double x2;    
    double y2;    
    double x3;    
    double y3;    
    x1= (double)c.lado_interno.origen.punto.x;
    y1= (double)c.lado_interno.origen.punto.y;
    x2= (double)c.lado_interno.next.origen.punto.x;
    y2= (double)c.lado_interno.next.origen.punto.y;
    x3= (double)c.lado_interno.prev.origen.punto.x;
    y3= (double)c.lado_interno.prev.origen.punto.y;
    return (-x2*x2*x1-y2*y2*x1+x1*x3*x3+x1*y3*y3+x3*x2*x2+
             x3*y2*y2+x2*x1*x1-x1*x1*x3+x2*y1*y1-y1*y1*x3-
             x3*x3*x2-y3*y3*x2)/
            ((double)-2.0*(x1*y2-x1*y3-x3*y2-x2*y1+y1*x3+y3*x2));
   }
   public float circun_y_float (cara c) {
    float x1;    
    float y1;    
    float x2;    
    float y2;    
    float x3;    
    float y3;    
    x1= (float)c.lado_interno.origen.punto.x;
    y1= (float)c.lado_interno.origen.punto.y;
    x2= (float)c.lado_interno.next.origen.punto.x;
    y2= (float)c.lado_interno.next.origen.punto.y;
    x3= (float)c.lado_interno.prev.origen.punto.x;
    y3= (float)c.lado_interno.prev.origen.punto.y;
    return (-x2*x2*x1-y2*y2*x1+x1*x3*x3+x1*y3*y3+x3*x2*x2+
             x3*y2*y2+x2*x1*x1-x1*x1*x3+x2*y1*y1-y1*y1*x3-
             x3*x3*x2-y3*y3*x2)/
            ((float)-2.0*(x1*y2-x1*y3-x3*y2-x2*y1+y1*x3+y3*x2));
   }    
  } //de la clase
    
  public class lista_caras {
   public cara l_caras[];
   public int num_caras;
   //Constructores
   public lista_caras(int i) {
    l_caras=new cara[i];
    num_caras=0;
   }
   public void inserta (cara c) {
    num_caras++;
   }
   public void inicializa() {
    // Inicializa
    num_caras = 0;
   }
  }
    
  public void inserta_triangulo_externo () {
   V.inserta(TAMANO_BALDOSA_X/2, -2  * TAMANO_BALDOSA_Y, null);
   V.inserta(-TAMANO_BALDOSA_X,  2*  TAMANO_BALDOSA_Y, null);
   V.inserta( 2 * TAMANO_BALDOSA_X, 2  * TAMANO_BALDOSA_Y, null);
   //Estrutura total del triangulo inicial
   L.num_lados=L.num_lados + 6;
   L.l_lados[0] = new lado(V.l_vertices[1], null, null, null, null);
   L.l_lados[1] = new lado(V.l_vertices[0], null, null, null, null);
   L.l_lados[2] = new lado(V.l_vertices[2], null, null, null, null);
   L.l_lados[3] = new lado(V.l_vertices[0], null, null, null, null);
   L.l_lados[4] = new lado(V.l_vertices[1], null, null, null, null);
   L.l_lados[5] = new lado(V.l_vertices[2], null, null, null, null);
   //
   C.num_caras = C.num_caras + 2;
   C.l_caras[0] = new cara (L.l_lados[0]); // Externo
   C.l_caras[1] = new cara (L.l_lados[3]); // Interno
   //
   L.l_lados[0].twin = L.l_lados[3];
   L.l_lados[1].twin = L.l_lados[5];
   L.l_lados[2].twin = L.l_lados[4];
   L.l_lados[3].twin = L.l_lados[0];
   L.l_lados[4].twin = L.l_lados[2]; 
   L.l_lados[5].twin = L.l_lados[1]; 
   //
   L.l_lados[0].next = L.l_lados[1]; 
   L.l_lados[1].next = L.l_lados[2]; 
   L.l_lados[2].next = L.l_lados[0]; 
   L.l_lados[3].next = L.l_lados[4]; 
   L.l_lados[4].next = L.l_lados[5]; 
   L.l_lados[5].next = L.l_lados[3]; 
   //
   L.l_lados[0].prev = L.l_lados[2]; 
   L.l_lados[1].prev = L.l_lados[0]; 
   L.l_lados[2].prev = L.l_lados[1]; 
   L.l_lados[3].prev = L.l_lados[5]; 
   L.l_lados[4].prev = L.l_lados[3]; 
   L.l_lados[5].prev = L.l_lados[4]; 
   //
   L.l_lados[0].cara_incidente = C.l_caras[0];
   L.l_lados[1].cara_incidente = C.l_caras[0];
   L.l_lados[2].cara_incidente = C.l_caras[0];
   L.l_lados[3].cara_incidente = C.l_caras[1];
   L.l_lados[4].cara_incidente = C.l_caras[1];
   L.l_lados[5].cara_incidente = C.l_caras[1];
   //
   V.l_vertices[0].lado_incidente = L.l_lados[3];
   V.l_vertices[1].lado_incidente = L.l_lados[4];
   V.l_vertices[2].lado_incidente = L.l_lados[5];
  } // Fin inserta_triangulo_externo
    
  public Polygon transforma_poligono (Polygon pol) {
   Polygon paux;
   int MAX_CORD = 29000; //10000;
   double new_x, new_y;
   paux = new Polygon();
   for (int i=0; i<pol.npoints; i++) {
    if ((Math.abs(pol.xpoints[i]) <= MAX_CORD) &&
        (Math.abs(pol.ypoints[i]) <= MAX_CORD)) { //Es dibujable
     paux.addPoint (pol.xpoints[i], pol.ypoints[i]);
     if ((Math.abs(pol.xpoints[(i + 1 + pol.npoints) % pol.npoints]) > MAX_CORD) ||
        (Math.abs(pol.ypoints[(i + 1 + pol.npoints) % pol.npoints]) > MAX_CORD)) { //No es dibujable el sig.
       new_x = pol.xpoints[i] + 2000 *
               (pol.xpoints[(i + 1 + pol.npoints) % pol.npoints] - pol.xpoints[i]) /
               V.l_vertices[0].distancia(pol.xpoints[(i + 1 + pol.npoints) % pol.npoints],
               pol.ypoints[(i + 1 + pol.npoints) % pol.npoints],
               pol.xpoints[i],
               pol.ypoints[i]);
       new_y = pol.ypoints[i] + 2000 * 
               (pol.ypoints[(i + 1 + pol.npoints) % pol.npoints] - pol.ypoints[i]) / 
               V.l_vertices[0].distancia(pol.xpoints[(i + 1 + pol.npoints) % pol.npoints],
               pol.ypoints[(i + 1 + pol.npoints) % pol.npoints],
               pol.xpoints[i],
               pol.ypoints[i]);
       paux.addPoint ((int)Math.round(new_x ),(int)Math.round(new_y));
      } //fin del if interno
     } // Fin de punto i dentro
     //Ahora le punto i esta fuera de la zona dibujable
     if ((Math.abs(pol.xpoints[i]) > MAX_CORD) ||
        (Math.abs(pol.ypoints[i]) > MAX_CORD)) {
      new_x = V.l_vertices[V.num_vertices-1].punto.x + 2000 *
             (pol.xpoints[i] - V.l_vertices[V.num_vertices-1].punto.x) /
              V.l_vertices[0].distancia(V.l_vertices[V.num_vertices-1].punto.x,
            V.l_vertices[V.num_vertices-1].punto.y,
            pol.xpoints[i],
            pol.ypoints[i]);
      new_y = V.l_vertices[V.num_vertices-1].punto.y + 2000 *
             (pol.ypoints[i] - V.l_vertices[V.num_vertices-1].punto.y) /
              V.l_vertices[0].distancia(V.l_vertices[V.num_vertices-1].punto.x,
            V.l_vertices[V.num_vertices-1].punto.y,
            pol.xpoints[i],
            pol.ypoints[i]);
      paux.addPoint ((int)Math.round(new_x ),(int)Math.round(new_y));
      //Añado tb el punto intermedio entre los 2
      if ((Math.abs(pol.xpoints[(i + 1 + pol.npoints) % pol.npoints]) > MAX_CORD) ||
          (Math.abs(pol.ypoints[(i + 1 + pol.npoints) % pol.npoints]) > MAX_CORD)) {
       new_x = V.l_vertices[V.num_vertices-1].punto.x + 2000 *
              ((pol.xpoints[i]+pol.xpoints[(i + 1 + pol.npoints) % pol.npoints])/2 - V.l_vertices[V.num_vertices-1].punto.x /
             V.l_vertices[0].distancia((pol.xpoints[i]+pol.xpoints[(i + 1 + pol.npoints) % pol.npoints])/2,
            (pol.ypoints[i]+pol.ypoints[(i + 1 + pol.npoints) % pol.npoints])/2,
             V.l_vertices[V.num_vertices-1].punto.x,
             V.l_vertices[V.num_vertices-1].punto.y));
       new_y = V.l_vertices[V.num_vertices-1].punto.y + 2000 *
            ((pol.ypoints[i]+pol.ypoints[(i + 1 + pol.npoints) % pol.npoints])/2 - V.l_vertices[V.num_vertices-1].punto.y /
             V.l_vertices[0].distancia((pol.xpoints[i]+pol.xpoints[(i + 1 + pol.npoints) % pol.npoints])/2,
            (pol.ypoints[i]+pol.ypoints[(i + 1 + pol.npoints) % pol.npoints])/2,
             V.l_vertices[V.num_vertices-1].punto.x,
             V.l_vertices[V.num_vertices-1].punto.y));
       paux.addPoint ((int)Math.round(new_x ),(int)Math.round(new_y));
      }    
      // Si el siguiente esta dentro
      if ((Math.abs(pol.xpoints[(i + 1 + pol.npoints) % pol.npoints]) <= MAX_CORD) &&
          (Math.abs(pol.ypoints[(i + 1 + pol.npoints) % pol.npoints]) <= MAX_CORD)) {
       new_x = pol.xpoints[(i + 1 + pol.npoints) % pol.npoints] + 2000 *
               (pol.xpoints[i] - pol.xpoints[(i + 1 + pol.npoints) % pol.npoints]) /
                V.l_vertices[0].distancia(pol.xpoints[(i + 1 + pol.npoints) % pol.npoints],
                pol.ypoints[(i + 1 + pol.npoints) % pol.npoints],
                pol.xpoints[i],
                pol.ypoints[i]);
       new_y = pol.ypoints[(i + 1 + pol.npoints) % pol.npoints] + 2000 *
               (pol.ypoints[i] - pol.ypoints[(i + 1 + pol.npoints) % pol.npoints]) /
                V.l_vertices[0].distancia(pol.xpoints[(i + 1 + pol.npoints) % pol.npoints],
                pol.ypoints[(i + 1 + pol.npoints) % pol.npoints],
                pol.xpoints[i],
                pol.ypoints[i]);
                paux.addPoint ((int)Math.round(new_x ),(int)Math.round(new_y));
      } // Fin del sihuiente dentro
      // Y si el sihuiente esta fuera de la zona dibujable pero corta la parte del applet
      if ((Math.abs(pol.xpoints[(i + 1 + pol.npoints) % pol.npoints]) > MAX_CORD) ||
         (Math.abs(pol.ypoints[(i + 1 + pol.npoints) % pol.npoints]) > MAX_CORD)) {
       System.out.println("Ha ocurrido..... ¡OJO!");
      } // el siguiente fuera pero cortando la zona visible             
    } // Fin de i fuera de la zona dibujable
   } //del for
   return paux;
  } // de transforma_poligono
          
  public void dibuja_voronoi_vertice(vertice v) {
   lado lado_aux1;
   lado lado_aux2;
   Polygon p_v;
   boolean es_interno=true;
   boolean circuncentro_fuera=false;
   float cx, cy;
   Point vector_director;
   double dist;
   double punto_medio_x;
   double punto_medio_y;
   double posible_circun_x;
   double posible_circun_y;
   boolean dibujable = true;
   p_v = new Polygon();
   lado_aux1 = new lado(null, null, null, null, null);
   lado_aux2 = new lado(null, null, null, null, null);
   lado_aux1 = v.lado_incidente;
   cx= (C.l_caras[0].circun_x_float(lado_aux1.cara_incidente));                              
   cy= (C.l_caras[0].circun_y_float(lado_aux1.cara_incidente));
   p_v.addPoint( (int)Math.round(cx), (int)Math.round(cy));
   lado_aux2 = lado_aux1.prev.twin;
   while ( lado_aux2 != lado_aux1 ) {
    cx= (C.l_caras[0].circun_x_float(lado_aux2.cara_incidente));                              
    cy= (C.l_caras[0].circun_y_float(lado_aux2.cara_incidente));
    p_v.addPoint( (int)Math.round(cx), (int)Math.round(cy));
    lado_aux2 = lado_aux2.prev.twin;
   }
   for (int g=0; g<p_v.npoints; g++) {
    if ((p_v.xpoints[g]>30000) ||
        (p_v.xpoints[g]<-30000) ||
        (p_v.ypoints[g]>30000) ||
        (p_v.ypoints[g]<-30000))  {
     dibujable =false;
     break;
    }
   }                     
   if (dibujable) {
    lista_voronoi_camb_color[V.num_vertices-1]= p_v;
    contexto_i_voronoi.setColor(COLOR_FONDO_BALDOSA);
    contexto_i_voronoi.fillPolygon(p_v);
    contexto_i_voronoi.setColor(COLOR_LINEAS);
    contexto_i_voronoi.drawPolygon(p_v);
    contexto_i_voronoi_color.setColor(v.color_vertice);
    contexto_i_voronoi_color.fillPolygon(p_v);
    //El de color con lineas
    contexto_i_voronoi_color.setColor(COLOR_LINEAS);
    contexto_i_voronoi_color.drawPolygon(p_v);
   } else { //No lo puedo dibujar pq se sale de la zona dibujable
    Polygon p_v_new;
    p_v_new = new Polygon();
    p_v_new = transforma_poligono (p_v);
    lista_voronoi_camb_color[V.num_vertices-1]= p_v_new;
    contexto_i_voronoi.setColor(COLOR_FONDO_BALDOSA);
    contexto_i_voronoi.fillPolygon(p_v_new);
    contexto_i_voronoi.setColor(COLOR_LINEAS);
    contexto_i_voronoi.drawPolygon(p_v_new);
    contexto_i_voronoi_color.setColor(v.color_vertice);
    contexto_i_voronoi_color.fillPolygon(p_v_new);
    //El de color con lineas
    contexto_i_voronoi_color.setColor(COLOR_LINEAS);
    contexto_i_voronoi_color.drawPolygon(p_v_new);
   } //del else
   contexto_i_voronoi.setColor(Color.red);
   contexto_i_voronoi_color.setColor(Color.red);
   for (int j=0; j<V.num_vertices; j++) {
    contexto_i_voronoi.fillOval( V.l_vertices[j].punto.x-2,
                                 V.l_vertices[j].punto.y-2,
                                 5,
                                 5);
    contexto_i_voronoi_color.fillOval( V.l_vertices[j].punto.x-2,
                                       V.l_vertices[j].punto.y-2,
                                       5,
                                       5); 
   } //del for
  } 
  
  public void dibuja_voronoi() {
   dibuja_voronoi_vertice(V.l_vertices[V.num_vertices-1]);
   for (int m=1; m<C.num_caras; m++){
    if (C.l_caras[0].colineal(C.l_caras[m].lado_interno.origen.punto,
                              C.l_caras[m].lado_interno.next.origen.punto,
                              C.l_caras[m].lado_interno.prev.origen.punto)) {
     break;
    }
   }  
   for (int b=3; b<V.num_vertices; b++) {
    if ( C.l_caras[0].colineal(V.l_vertices[b].lado_incidente.origen.punto,
                               V.l_vertices[b].lado_incidente.next.origen.punto,
                               V.l_vertices[b].lado_incidente.prev.origen.punto)) {
     break;
    }
   }          
   contexto_i_voronoi.setColor(Color.red);
   contexto_i_voronoi_color.setColor(Color.red);
   for (int j=0; j<V.num_vertices; j++) {
    contexto_i_voronoi.fillOval( V.l_vertices[j].punto.x-2,
                                 V.l_vertices[j].punto.y-2,
                                 5,
                                 5);
    contexto_i_voronoi_color.fillOval( V.l_vertices[j].punto.x-2,
                                       V.l_vertices[j].punto.y-2,
                                       5,
                                       5); 
   }
  }     
  public void dibuja_cierre_convexo (){
   // Dibuja el cierre convexo, solo cuando se pide, no siempre
   Polygon c_c;
   vertice first;
   lado aux1;
   c_c = new Polygon();
   contexto_cierre_convexo.setColor(COLOR_FONDO_BALDOSA); //FONDO_BALDOSA);
   contexto_cierre_convexo.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   aux1 = L.l_lados[0].twin.prev;
   first= L.l_lados[0].twin.prev.origen;
   c_c.addPoint(aux1.origen.punto.x, aux1.origen.punto.y);
   do {
    if ((aux1.twin.prev.origen == V.l_vertices[0]) ||
        (aux1.twin.prev.origen == V.l_vertices[1]) ||
        (aux1.twin.prev.origen == V.l_vertices[2])) {
     aux1 = aux1.twin.next;
    } else {
     aux1 = aux1.twin.prev;
    }
    c_c.addPoint(aux1.origen.punto.x, aux1.origen.punto.y);
   } while (aux1.origen != first);   
   if (!pinta_color) {
    contexto_cierre_convexo.setColor(COLOR_LINEAS);
    contexto_cierre_convexo.drawPolygon(c_c);
   } else {
    contexto_cierre_convexo.setColor(C.l_caras[0].color_cara);
    contexto_cierre_convexo.fillPolygon(c_c);
    // Y la linea de fuera
    contexto_cierre_convexo.setColor(COLOR_LINEAS);
    contexto_cierre_convexo.drawPolygon(c_c);
   }   
   if (m_puntos.num_puntos==2) {
    if (!pinta_color) {
     contexto_cierre_convexo.setColor(COLOR_LINEAS);
     contexto_cierre_convexo.drawLine(V.l_vertices[V.num_vertices-1].punto.x,
                                      V.l_vertices[V.num_vertices-1].punto.y,
                                      V.l_vertices[V.num_vertices-2].punto.x,
                                      V.l_vertices[V.num_vertices-2].punto.y);         
    } else {                                    
     contexto_cierre_convexo.setColor(C.l_caras[0].color_cara);
     contexto_cierre_convexo.drawLine(V.l_vertices[V.num_vertices-1].punto.x,
                                      V.l_vertices[V.num_vertices-1].punto.y,
                                      V.l_vertices[V.num_vertices-2].punto.x,
                                      V.l_vertices[V.num_vertices-2].punto.y);         
    }
   }                                    
   contexto_cierre_convexo.setColor(COLOR_PUNTOS);
   for (int l=0; l<V.num_vertices; l++) {
    contexto_cierre_convexo.fillOval( V.l_vertices[l].punto.x-2,
                                      V.l_vertices[l].punto.y-2,
                                      5,
                                      5);
   }
   baldosa.repaint();
  }
 
  public void repintar_triangulacion_color () {
   contexto_baldosa_color.setColor(COLOR_FONDO_BALDOSA);
   contexto_baldosa_color.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   Polygon pol;
   // si solo son dos puntos a color dibujo una linea    
   if (m_puntos.num_puntos == 2) {
    contexto_baldosa_color.setColor(C.l_caras[1].color_cara);
    contexto_baldosa_color.drawLine(V.l_vertices[3].punto.x,
                                    V.l_vertices[3].punto.y, 
                                  V.l_vertices[4].punto.x, 
                                  V.l_vertices[4].punto.y);
   }                                       
   for (int j=0; j<C.num_caras; j++) {
    if ((C.l_caras[j].lado_interno.origen!=V.l_vertices[0]) &&
        (C.l_caras[j].lado_interno.origen!=V.l_vertices[1]) &&
        (C.l_caras[j].lado_interno.origen!=V.l_vertices[2]) &&
        (C.l_caras[j].lado_interno.next.origen!=V.l_vertices[0]) &&
        (C.l_caras[j].lado_interno.next.origen!=V.l_vertices[1]) &&
        (C.l_caras[j].lado_interno.next.origen!=V.l_vertices[2]) &&
        (C.l_caras[j].lado_interno.prev.origen!=V.l_vertices[0]) &&
        (C.l_caras[j].lado_interno.prev.origen!=V.l_vertices[1]) &&
        (C.l_caras[j].lado_interno.prev.origen!=V.l_vertices[2])) {
     pol = new Polygon();
     pol.addPoint(C.l_caras[j].lado_interno.origen.punto.x,
                  C.l_caras[j].lado_interno.origen.punto.y);
     pol.addPoint(C.l_caras[j].lado_interno.next.origen.punto.x,
                  C.l_caras[j].lado_interno.next.origen.punto.y);
     pol.addPoint(C.l_caras[j].lado_interno.prev.origen.punto.x,
                  C.l_caras[j].lado_interno.prev.origen.punto.y);
     contexto_baldosa_color.setColor(C.l_caras[j].color_cara);
     contexto_baldosa_color.fillPolygon(pol);
     // Para la triangulacion en color
     contexto_baldosa_color.setColor(COLOR_LINEAS);
     contexto_baldosa_color.drawPolygon(pol);
    }    // del if 
   }  // del for      
   contexto_baldosa_color.setColor(COLOR_PUNTOS);
   for (int l=0; l<V.num_vertices; l++) {
    contexto_baldosa_color.fillOval( V.l_vertices[l].punto.x-2,
                                     V.l_vertices[l].punto.y-2,
                                     5,
                                     5);
   }
  }
 
  class  pulsar_boton_nuevo implements ActionListener {
   public void actionPerformed (ActionEvent e) {
    remove(titulo);
    remove(boton_automatico);
    remove(boton_manual);
    contexto_baldosa_buffer.setColor(COLOR_FONDO_BALDOSA);
    contexto_baldosa_buffer.fillRect(0, 0,
                                     TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
    contexto_baldosa_color.setColor(COLOR_FONDO_BALDOSA);
    contexto_baldosa_color.fillRect(0, 0,
                                    TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y); 
    contexto_i_voronoi.setColor(COLOR_FONDO_BALDOSA);
    contexto_i_voronoi.fillRect(0, 0,
                                TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y); 
    contexto_i_voronoi_color.setColor(COLOR_FONDO_BALDOSA);
    contexto_i_voronoi_color.fillRect(0, 0,
                                      TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);                                                                                                                  
    m_puntos.inicializa(TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);                                   
    V.inicializa();                                   
    L.inicializa();
    C.inicializa();
    inserta_triangulo_externo();
    if (pinta_cierre_convexo) dibuja_cierre_convexo();
     baldosa.repaint();
   }  
  }              
 
  class  pulsar_boton_insertar_puntos implements ActionListener {
   // Cuando se pulsa dicho botón para empezar a introducir puntos
   public void actionPerformed (ActionEvent e) {
    baldosa.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
    add(boton_nuevo); // estan por debajo
    add(seleccion);   // estan por debajo
    remove(boton_insertar_puntos);
    add(check_b_n);
    add(check_color);
    add(check_circulos);
    add(check_voro);
    inserta_triangulo_externo();
    baldosa.addMouseListener (accion_pulsar_punto); //estaba parado en el init
    contexto_baldosa_buffer.setColor(COLOR_FONDO_BALDOSA);
    contexto_baldosa_buffer.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
    baldosa.repaint();
   }    
  } // Fin de evento de pulsación de ratón en le botón
    
  class pulsar_boton_cambiar_color implements ActionListener {
   public void actionPerformed (ActionEvent e) {
    COLOR_PLAYA = new Color((float)Math.random(),
                            (float)Math.random(),
                            (float)Math.random()); 
    for (int i=0; i<C.num_caras; i++) {
     C.l_caras[i].color_cara = new Color((float)Math.random(),
                                         (float)Math.random(),
                                         (float)Math.random());
    }
    for (int j=0; j<V.num_vertices; j++) {
     V.l_vertices[j].color_vertice = new Color((float)Math.random(),
                                               (float)Math.random(),
                                               (float)Math.random());
    } 
    if (pinta_delaunay) repintar_triangulacion_color();
    if (pinta_cierre_convexo) dibuja_cierre_convexo();
    if (pinta_voronoi||pinta_sweep) { // Para que repinte todo el voronoi color
     for (int p=3; p < V.num_vertices; p++ ) {
      contexto_i_voronoi_color.setColor(V.l_vertices[p].color_vertice);
      contexto_i_voronoi_color.fillPolygon(lista_voronoi_camb_color[p]);
      //El de color con lineas
      contexto_i_voronoi_color.setColor(COLOR_LINEAS);
      contexto_i_voronoi_color.drawPolygon(lista_voronoi_camb_color[p]);
     }
     contexto_i_voronoi_color.setColor(COLOR_PUNTOS);
     for (int l=0; l<V.num_vertices; l++) {
      contexto_i_voronoi_color.fillOval( V.l_vertices[l].punto.x-2,
                                         V.l_vertices[l].punto.y-2,
                                         5,
                                         5);
     }
    }    
    baldosa.repaint();
   }
  }      
 
  class pulsar_boton_manual implements ActionListener {
   public void actionPerformed (ActionEvent e) {
    baldosa.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    posicion_x_linea=TAMANO_BALDOSA_X /2;
    seleccion.setEnabled(false); // deja disbale el menu
    pinta_sweep=true;
    pinta_voronoi=false;
    pinta_sweep_automatico=false;
    boton_manual.setEnabled(false);
    boton_nuevo.setEnabled(false);
    boton_automatico.setEnabled(false);
    //Esto crea todos los poligonos en l_polig
    l_polig = new Polygon[V.num_vertices];
    Polygon voro;
    voro = new Polygon();
    lado lado_aux1;
    lado lado_aux2;
    float cx;
    float cy;
    for (int j=3; j<V.num_vertices; j++) {
     voro = new Polygon();
     lado_aux1 = new lado(null, null, null, null, null);
     lado_aux2 = new lado(null, null, null, null, null);
     lado_aux1 = V.l_vertices[j].lado_incidente;
     cx= (C.l_caras[0].circun_x_float(lado_aux1.cara_incidente));                              
     cy= (C.l_caras[0].circun_y_float(lado_aux1.cara_incidente));
     voro.addPoint( (int)Math.round(cx), (int)Math.round(cy));
     lado_aux2 = lado_aux1.prev.twin;
     while ( lado_aux2 != lado_aux1 ) {
      cx= (C.l_caras[0].circun_x_float(lado_aux2.cara_incidente));                              
      cy= (C.l_caras[0].circun_y_float(lado_aux2.cara_incidente));
      voro.addPoint( (int)Math.round(cx), (int)Math.round(cy));
      lado_aux2 = lado_aux2.prev.twin;
     }
     l_polig[j]=new Polygon(); 
     l_polig[j]=voro;
    } // Fin de todos los voronois
    baldosa.removeMouseListener(accion_pulsar_punto);
    baldosa.addMouseMotionListener( drag_sweep = new hacer_drag_sweep());
    baldosa.addMouseListener( click_sweep = new hacer_click_sweep());
    add(boton_volver);
    pinta_sweep=true;  //solo para la primera vez
    baldosa.repaint(); //solo util la primera vez que se pulsa
   }
  }
  
  class pulsar_boton_automatico implements ActionListener {
   public void actionPerformed (ActionEvent e) {
    baldosa.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    baldosa.removeMouseListener(accion_pulsar_punto);
    boton_automatico.setEnabled(false);
    boton_nuevo.setEnabled(false);
    boton_manual.setEnabled(false);
    seleccion.setEnabled(false);
    add(boton_comenzar);
    add(velocidad);
    add(boton_volver);
   }
  }
    
  class pulsar_boton_comenzar implements ActionListener {
   //Es el del comienzo de la simulacion automatica
   public void actionPerformed (ActionEvent e) {
    boton_comenzar.setEnabled(false);
    pinta_sweep=true;
    pinta_sweep_automatico=true;
    pinta_voronoi=false;
    boton_automatico.setEnabled(false);
    boton_manual.setEnabled(false);
    seleccion.setEnabled(false);
    boton_nuevo.setEnabled(false);
    baldosa.removeMouseListener(accion_pulsar_punto);
    posicion_x_linea=TAMANO_BALDOSA_X;
    baldosa.repaint();
   }
  }
     
  class pulsar_boton_volver implements ActionListener {
   public void actionPerformed (ActionEvent e) {
    boton_comenzar.setEnabled(true);
    posicion_x_linea=TAMANO_BALDOSA_X /2;
    seleccion.setEnabled(true); // deja disbale el menu
    pinta_sweep=false;
    pinta_voronoi=true;
    boton_manual.setEnabled(true);
    boton_automatico.setEnabled(true);
    boton_nuevo.setEnabled(true);
    remove(boton_volver);
    remove(velocidad);
    remove(boton_comenzar);
    baldosa.removeMouseMotionListener(drag_sweep);
    baldosa.removeMouseListener(click_sweep);
    baldosa.addMouseListener( accion_pulsar_punto);
    baldosa.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
    baldosa.repaint();
   }
  }       
     
  class pulsar_velocidad implements ItemListener {
   public void itemStateChanged (ItemEvent e) {
    if (e.getItem().equals(" Muy Lento")) {
     incremento=1;
    }
    if (e.getItem().equals(" Lento")) {
     incremento=2;
    }
    if (e.getItem().equals(" Medio")) {
     incremento=3;
    }
    if (e.getItem().equals(" Rápido")) {
     incremento=4;
    }
    if (e.getItem().equals(" Muy Rápido")) {
     incremento=5;
    } 
   }
  }
     
  class pulsar_seleccion implements ItemListener {
   // Evento de pulsacion del Choice
   public void itemStateChanged (ItemEvent e) {
    if (e.getItem().equals(" Cierre Convexo")) {
     remove(titulo);
     remove(boton_automatico);
     remove(boton_manual);
     if (check_voro.isShowing()){
      remove(check_voro);
      remove(check_circulos);
     }
     if (pinta_sweep) {
      baldosa.addMouseListener(accion_pulsar_punto);
      baldosa.removeMouseMotionListener(drag_sweep);
      baldosa.removeMouseListener(click_sweep);
      if (pinta_color) add(boton_cambiar_color);
     }
     pinta_cierre_convexo=true;
     pinta_delaunay=false;
     pinta_voronoi=false;
     pinta_sweep=false;
     dibuja_cierre_convexo();
    }
    if (e.getItem().equals(" Triangulación de Delaunay")) {
     remove(titulo);
     remove(boton_automatico);
     remove(boton_manual);
     if (!check_voro.isShowing() && !pinta_color){
      add(check_voro);
      add(check_circulos);
     }
     if (pinta_sweep) {
      baldosa.addMouseListener(accion_pulsar_punto);
      baldosa.removeMouseMotionListener(drag_sweep);
      baldosa.removeMouseListener(click_sweep);
      if (pinta_color) add(boton_cambiar_color);
     }
     pinta_delaunay=true;
     pinta_voronoi=false;
     pinta_cierre_convexo=false;
     pinta_sweep=false;
    }
    if (e.getItem().equals(" Diagrama de Voronoi")) {
     if (check_voro.isShowing()){
      remove(check_voro);
      remove(check_circulos);
     }
     if ((!pinta_voronoi)&&(V.num_vertices>3)) {
      if (!titulo.isShowing()) add(titulo);
      if (!boton_automatico.isShowing()) add(boton_automatico);
      if (!boton_manual.isShowing()) add(boton_manual);
     }
     if (pinta_sweep) {
      baldosa.addMouseListener(accion_pulsar_punto);
      baldosa.removeMouseMotionListener(drag_sweep);
      baldosa.removeMouseListener(click_sweep);
      if (pinta_color) add(boton_cambiar_color);
     }
     pinta_voronoi=true;
     pinta_delaunay=false;
     pinta_cierre_convexo=false;
     pinta_sweep=false;
    }
    baldosa.repaint();
   }
  }
  
  class pulsar_check_circulos implements ItemListener {
   public void itemStateChanged (ItemEvent e) {
    if (e.getStateChange() == ItemEvent.SELECTED)
     mostrar_circulos_dela=true;
    if (e.getStateChange() == ItemEvent.DESELECTED)
     mostrar_circulos_dela=false;
    baldosa.repaint();
   }
  }
 
  class pulsar_check_voro implements ItemListener {
   public void itemStateChanged (ItemEvent e) {
    if (e.getStateChange() == ItemEvent.SELECTED)
     mostrar_voro_dela=true;
    if (e.getStateChange() == ItemEvent.DESELECTED)
     mostrar_voro_dela=false;
     baldosa.repaint();
   }
  }
 
  class pulsar_check_b_n implements ItemListener {
   // Evento de pulsacion del Check B-N
   public void itemStateChanged (ItemEvent e) {
    if (pinta_delaunay && !check_voro.isShowing()){
     add(check_voro);
     add(check_circulos);
    }
    pinta_b_n = true;
    pinta_color = false;
    remove(boton_cambiar_color);
    if (pinta_cierre_convexo) dibuja_cierre_convexo();
    baldosa.repaint();
   }
  }
    
  class pulsar_checkcolor implements ItemListener {
   // Evento de pulsacion del Check Color
   public void itemStateChanged (ItemEvent e) {
    if (pinta_delaunay && check_voro.isShowing()){
     remove(check_voro);
     remove(check_circulos);
    }
    pinta_b_n = false;
    pinta_color = true;
    add(boton_cambiar_color);
    if (pinta_cierre_convexo) dibuja_cierre_convexo();
    baldosa.repaint();
   }
  }   
    
  class hacer_click_sweep extends MouseAdapter {
   // Click  en el canvas para colocar la linea de barrido
   public void mousePressed (MouseEvent e) {
    baldosa.setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
    posicion_x_linea=e.getPoint().x;
    baldosa.repaint();
   }
   public void mouseReleased (MouseEvent e) {
    baldosa.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
   }
  }
     
  class hacer_drag_sweep extends MouseMotionAdapter {
   // Click  en el canvas para colocar la linea de barrido
   public void mouseDragged (MouseEvent e) { //Esto esta en prueba para mover la linea de barrido
    baldosa.setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
    posicion_x_linea=e.getPoint().x;
    baldosa.repaint();
   }
   public void mouseMoved (MouseEvent e) { //Esto esta en prueba para mover la linea de barrido
    if ((e.getPoint().x<=posicion_x_linea+3) &&
        (e.getPoint().x>=posicion_x_linea-3)) {
     baldosa.setCursor(new Cursor(Cursor.W_RESIZE_CURSOR));
    } else {
     baldosa.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
    }
   }
  }
 
  class inserta_punto extends MouseAdapter {
   /* Click realizado sobre el Canvas de la baldosa inicial */
   //Variables
   Point punto;
   cara triangulo;
   lado lado_i;
   lado aux1;
   lado aux2;
   lado aux3;
   lado aux4;
   lado aux5;
   lado aux6;
   lado aux7;
   lado aux8;
   lado aux9;
   lado aux10;
   lado aux11;
   lado aux12;
   lado lado1;
   lado lado2;
   lado lado3;
   cara caraaux1;
   cara caraaux2;
   cara caraaux3;
   cara triangulo_twin;
             
   public void mousePressed (MouseEvent e) {
    //Al loro con esto, paro la escucha de la insercion de puntos
    baldosa.setCursor(new Cursor(Cursor.CROSSHAIR_CURSOR));
    baldosa.removeMouseListener (accion_pulsar_punto);
    punto=e.getPoint();
    if (m_puntos.esta(punto.x, punto.y) ||
       (V.num_vertices == MAX_VERTICES)) {
    } else { // No estaba
     m_puntos.inserta (punto.x, punto.y); // Lo mete en la matriz booleana
     V.inserta(punto, null); // Insertamos el punto en la la lista de vertices
     triangulo= new cara(null);
     triangulo = triangulo.encuentra_triangulo(V.l_vertices[V.num_vertices-1].punto);
     if (triangulo.interior_estricto_al_triangulo(triangulo,
         V.l_vertices[V.num_vertices-1].punto)) { //Estamos dentro del triangulo
      L.l_lados[L.num_lados] = new lado(null, null, null, null, null);
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado(null, null, null, null, null);
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado(null, null, null, null, null);
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado(null, null, null, null, null);
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado(null, null, null, null, null);
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado(null, null, null, null, null);
      L.num_lados++;
      aux1 = new lado(null, null, null, null, null);
      aux2 = new lado(null, null, null, null, null);
      aux3 = new lado(null, null, null, null, null);                              
      aux4 = new lado(null, null, null, null, null);
      aux5 = new lado(null, null, null, null, null);
      aux6 = new lado(null, null, null, null, null);
      lado1 = new lado(null, null, null, null, null);
      lado2 = new lado(null, null, null, null, null);
      lado3 = new lado(null, null, null, null, null);
      lado1 = triangulo.lado_interno;
      lado2 = triangulo.lado_interno.next;
      lado3 = triangulo.lado_interno.prev;
      caraaux2 = new cara(null);
      caraaux3 = new cara(null);
      aux6 = L.l_lados[L.num_lados-1];
      aux5 = L.l_lados[L.num_lados-2];
      aux4 = L.l_lados[L.num_lados-3];
      aux3 = L.l_lados[L.num_lados-4];
      aux2 = L.l_lados[L.num_lados-5];
      aux1 = L.l_lados[L.num_lados-6];
      //Los origenes
      aux1.origen = lado2.origen;
      aux2.origen = V.l_vertices[V.num_vertices-1];
      aux3.origen = lado1.origen;
      aux4.origen = V.l_vertices[V.num_vertices-1];
      aux5.origen = lado3.origen;
      aux6.origen = V.l_vertices[V.num_vertices-1];
      //los twin
      aux1.twin = aux6;
      aux2.twin = aux3;
      aux3.twin = aux2;
      aux4.twin = aux5;
      aux5.twin = aux4;
      aux6.twin = aux1;
      //los next
      aux1.next = aux2;
      aux2.next = lado1;
      aux3.next = aux4;
      aux4.next = lado3;
      aux5.next = aux6;
      aux6.next = lado2;
      //los prev
      aux1.prev = lado1;
      aux2.prev = aux1;
      aux3.prev = lado3;
      aux4.prev = aux3;
      aux5.prev = lado2;
      aux6.prev = aux5;
      //Ok el punto insertado
      V.l_vertices[V.num_vertices-1].lado_incidente = aux2; //por ejemplo
      // Ahora empiezo con las caras
      C.l_caras[C.num_caras] = new cara (null);
      caraaux2 = C.l_caras[C.num_caras];
      caraaux2.lado_interno = lado2;
      C.num_caras++;
      C.l_caras[C.num_caras] = new cara (null);
      caraaux3 = C.l_caras[C.num_caras];
      caraaux3.lado_interno = lado3;
      C.num_caras++;
      //Vamos con las cara_incidente de los nuevos lados
      aux1.cara_incidente = triangulo;
      aux2.cara_incidente = triangulo;
      aux3.cara_incidente = caraaux3;
      aux4.cara_incidente = caraaux3;
      aux5.cara_incidente = caraaux2;
      aux6.cara_incidente = caraaux2;
      lado1.cara_incidente = triangulo;
      lado2.cara_incidente = caraaux2;
      lado3.cara_incidente = caraaux3;
      // lados
      lado1.next = aux1;
      lado2.next = aux5;
      lado3.next = aux3;
      lado1.prev = aux2;
      lado2.prev = aux6;
      lado3.prev = aux4;                  
      //
      lado1.origen.lado_incidente = lado1;
      lado2.origen.lado_incidente = lado2;
      lado3.origen.lado_incidente = lado3;
      aux6.origen.lado_incidente = aux6;
      // Y legalizo los lados
      L.l_lados[L.num_lados-1].legaliza_lado(V.l_vertices[V.num_vertices-1],
                                             lado1);
      L.l_lados[L.num_lados-1].legaliza_lado(V.l_vertices[V.num_vertices-1],
                                             lado2);
      L.l_lados[L.num_lados-1].legaliza_lado(V.l_vertices[V.num_vertices-1],
                                             lado3);
     } else {   // El punto esta justamente sobre el lado (=0)
      //vemaos cual es el lado
      lado_i = new lado(null, null, null, null, null);
      lado_i = triangulo.lado_interseccion(triangulo,V.l_vertices[V.num_vertices-1].punto);
      aux1 = new lado(null, null, null, null, null);
      aux2 = new lado(null, null, null, null, null);
      aux3 = new lado(null, null, null, null, null);
      aux4 = new lado(null, null, null, null, null);
      aux5 = new lado(null, null, null, null, null);
      aux6 = new lado(null, null, null, null, null);
      aux7 = new lado(null, null, null, null, null);
      aux8 = new lado(null, null, null, null, null);
      aux9 = new lado(null, null, null, null, null);
      aux10 = new lado(null, null, null, null, null);
      aux11 = new lado(null, null, null, null, null);
      aux12 = new lado(null, null, null, null, null);
      triangulo_twin = new cara(null);
      caraaux1 = new cara (null);
      caraaux2 = new cara (null);
      aux1 = lado_i;
      aux2 = lado_i.next;
      aux3 = lado_i.prev;
      aux4 = lado_i.twin;
      aux5 = lado_i.twin.next;
      aux6 = lado_i.twin.prev;
      triangulo_twin = aux4.cara_incidente;
      //Empezamos con los nuevos lados
      L.l_lados[L.num_lados] = new lado (aux3.origen, null, null, null, null);
      aux7 = L.l_lados[L.num_lados];
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado (V.l_vertices[V.num_vertices-1], null, null, null, null);
      aux8 = L.l_lados[L.num_lados];
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado (aux5.origen, null, null, null, null);
      aux9 = L.l_lados[L.num_lados];
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado (V.l_vertices[V.num_vertices-1], null, null, null, null);
      aux10 = L.l_lados[L.num_lados];
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado (aux6.origen, null, null, null, null);
      aux11 = L.l_lados[L.num_lados];
      L.num_lados++;
      L.l_lados[L.num_lados] = new lado (V.l_vertices[V.num_vertices-1], null, null, null, null);
      aux12 = L.l_lados[L.num_lados];
      L.num_lados++;
      //El origen de aux1 ok
      aux1.origen = V.l_vertices[V.num_vertices-1];
      // Los twin
      aux7.twin = aux8;
      aux8.twin = aux7;
      aux9.twin = aux10;
      aux10.twin = aux9;
      aux11.twin = aux12;
      aux12.twin = aux11;
      //Los next
      aux1.next = aux2;
      aux2.next = aux7;
      aux3.next = aux9;
      aux4.next = aux12;
      aux5.next =    aux11;            
      aux6.next = aux4;
      aux7.next = aux1;
      aux8.next = aux3;
      aux9.next = aux8;
      aux10.next = aux5;
      aux11.next = aux10;
      aux12.next = aux6;
      //Los prev
      aux1.prev = aux7;
      aux2.prev = aux1;
      aux3.prev = aux8;
      aux4.prev = aux6;
      aux5.prev =    aux10;            
      aux6.prev = aux12;
      aux7.prev = aux2;
      aux8.prev = aux9;
      aux9.prev = aux3;
      aux10.prev = aux11;
      aux11.prev = aux5;
      aux12.prev = aux4;
      // 2 nuevas caras
      C.l_caras[C.num_caras] = new cara (null);
      caraaux1 = C.l_caras[C.num_caras];
      C.num_caras++;
      C.l_caras[C.num_caras] = new cara (null);
      caraaux2 = C.l_caras[C.num_caras];
      C.num_caras++;
      caraaux1.lado_interno = aux9;
      caraaux2.lado_interno = aux10;
      triangulo.lado_interno = aux1;
      triangulo_twin.lado_interno = aux4;
      // Las caras incidentes
      aux1.cara_incidente = triangulo;
      aux2.cara_incidente = triangulo;
      aux3.cara_incidente = caraaux1;
      aux4.cara_incidente = triangulo_twin;
      aux5.cara_incidente =    caraaux2;            
      aux6.cara_incidente = triangulo_twin;
      aux7.cara_incidente = triangulo;
      aux8.cara_incidente = caraaux1;
      aux9.cara_incidente = caraaux1;
      aux10.cara_incidente = caraaux2;
      aux11.cara_incidente = caraaux2;
      aux12.cara_incidente = triangulo_twin;
      //Los lado_incidente de los puntos
      aux2.origen.lado_incidente = aux2;
      aux3.origen.lado_incidente = aux3;
      aux5.origen.lado_incidente = aux5;
      aux6.origen.lado_incidente = aux6;
      V.l_vertices[V.num_vertices-1].lado_incidente = aux1;
      // Legalizacion de lados
      //
      L.l_lados[L.num_lados-1].legaliza_lado(V.l_vertices[V.num_vertices-1], aux2);
      L.l_lados[L.num_lados-1].legaliza_lado(V.l_vertices[V.num_vertices-1], aux3);
      L.l_lados[L.num_lados-1].legaliza_lado(V.l_vertices[V.num_vertices-1], aux5);
      L.l_lados[L.num_lados-1].legaliza_lado(V.l_vertices[V.num_vertices-1], aux6);
      // Fin 
     }  
     //Vamos a intentar dibujar de manera eficiente
     Polygon P;
     Polygon tri;
     Color colores[];
     colores=new Color[MAX_CARAS];
     P = new Polygon();
     lado l_i;
     lado l_ax;
     l_i=new lado(null,null,null,null,null);
     l_i=V.l_vertices[V.num_vertices-1].lado_incidente;
     P.addPoint(l_i.next.origen.punto.x,
                l_i.next.origen.punto.y);
     colores[0]=l_i.cara_incidente.color_cara;
     l_ax=l_i.next.next.twin;
     while (l_ax != l_i) {
      P.addPoint(l_ax.next.origen.punto.x,
                 l_ax.next.origen.punto.y);
      colores[P.npoints-1]=l_ax.cara_incidente.color_cara;
      l_ax=l_ax.next.next.twin;
     }
     for (int c=0; c<P.npoints; c++){
      if ((P.xpoints[c]!=V.l_vertices[0].punto.x) &&
          (P.ypoints[c]!=V.l_vertices[0].punto.y) &&
          (P.xpoints[c]!=V.l_vertices[1].punto.x) &&
          (P.ypoints[c]!=V.l_vertices[1].punto.y) &&
          (P.xpoints[c]!=V.l_vertices[2].punto.x) &&
          (P.ypoints[c]!=V.l_vertices[2].punto.y) &&
          (P.xpoints[(c+1)%P.npoints]!=V.l_vertices[0].punto.x) &&
          (P.ypoints[(c+1)%P.npoints]!=V.l_vertices[0].punto.y) &&
          (P.xpoints[(c+1)%P.npoints]!=V.l_vertices[1].punto.x) &&
          (P.ypoints[(c+1)%P.npoints]!=V.l_vertices[1].punto.y) &&
          (P.xpoints[(c+1)%P.npoints]!=V.l_vertices[2].punto.x) &&
          (P.ypoints[(c+1)%P.npoints]!=V.l_vertices[2].punto.y))  {
       tri= new Polygon();
       tri.addPoint(P.xpoints[c], P.ypoints[c]);
       tri.addPoint(P.xpoints[(c+1)%P.npoints], P.ypoints[(c+1)%P.npoints]);
       tri.addPoint(V.l_vertices[V.num_vertices-1].punto.x,
                    V.l_vertices[V.num_vertices-1].punto.y);
       contexto_baldosa_buffer.setColor(COLOR_FONDO_BALDOSA);
       contexto_baldosa_buffer.fillPolygon(tri);
       contexto_baldosa_color.setColor(colores[c]);
       contexto_baldosa_color.fillPolygon(tri);
       contexto_baldosa_buffer.setColor(COLOR_LINEAS);
       contexto_baldosa_color.setColor(COLOR_LINEAS);
       contexto_baldosa_buffer.drawPolygon(tri);
       contexto_baldosa_color.drawPolygon(tri);
      }
     }
     if (m_puntos.num_puntos==2) {
      contexto_baldosa_buffer.setColor(COLOR_LINEAS);
      contexto_baldosa_buffer.drawLine(V.l_vertices[V.num_vertices-1].punto.x,
                                       V.l_vertices[V.num_vertices-1].punto.y,
                                       V.l_vertices[V.num_vertices-2].punto.x,
                                       V.l_vertices[V.num_vertices-2].punto.y);
      contexto_baldosa_color.setColor(C.l_caras[C.num_caras-1].color_cara);
      contexto_baldosa_color.drawLine(V.l_vertices[V.num_vertices-1].punto.x,
                                      V.l_vertices[V.num_vertices-1].punto.y,
                                      V.l_vertices[V.num_vertices-2].punto.x,
                                      V.l_vertices[V.num_vertices-2].punto.y);     
     }
     contexto_baldosa_buffer.setColor(COLOR_PUNTOS);
     contexto_baldosa_color.setColor(COLOR_PUNTOS);
     for (int h=0; h<P.npoints; h++) {
      contexto_baldosa_color.fillOval( P.xpoints[h]-2,
                                       P.ypoints[h]-2,
                                       5,
                                       5);
      contexto_baldosa_buffer.fillOval( P.xpoints[h]-2,
                                        P.ypoints[h]-2,
                                        5,
                                        5);
     }
     contexto_baldosa_color.fillOval( V.l_vertices[V.num_vertices-1].punto.x-2,
                                      V.l_vertices[V.num_vertices-1].punto.y-2,
                                      5,
                                      5);
     contexto_baldosa_buffer.fillOval( V.l_vertices[V.num_vertices-1].punto.x-2,
                                       V.l_vertices[V.num_vertices-1].punto.y-2,
                                       5,
                                       5);
     // Ahora si es necesario llamo a dibuja_cierre_convexo
     if (pinta_cierre_convexo) dibuja_cierre_convexo();
    } //del else (el punto no existia)
    dibuja_voronoi_vertice(V.l_vertices[V.num_vertices-1]);
    baldosa.repaint();
    baldosa.addMouseListener (accion_pulsar_punto);
    if ((pinta_voronoi)&&(V.num_vertices>3)) {
     if (!titulo.isShowing()) add(titulo);
     if (!boton_automatico.isShowing()) add(boton_automatico);
     if (!boton_manual.isShowing()) add(boton_manual);
    }
   } //Del metodo Mousepressed
  }  // De la clase inserta_punto
 
  public Image dibuja_fondo(Image img) {
   // Dibuja una imagen con forma de ventana Windows
   Graphics g;
   int ancho, alto;
   g = img.getGraphics();
   ancho = img.getWidth(null); // Tamaño en pixels ancho imagen
   alto = img.getHeight(null); // Tamaño en pixels alto imagen
   g.setColor(Color.lightGray);
   g.fillRect(0, 0, ancho, alto); // Cubre todo de gris claro
   g.setColor(Color.white.darker()); //Para el rectángulo de abajo gris claro
   g.fillRect(4, BALDOSA_Y + TAMANO_BALDOSA_Y + 11, ancho, alto); //Lo dibuja
   g.setColor(Color.black); //Sombra negra
   g.drawRect(ancho-1,0,ancho-1,alto-1); //rectangulo negro
   g.drawLine(0,alto-1,ancho-1,alto-1); // abajo
   g.setColor(Color.gray); //Vamos al gris
   g.drawLine(1,alto-2,ancho -2,alto-2); //abajo
   g.drawLine(ancho-2,1,ancho-2,alto-2); //derecha
   g.setColor(Color.white); //ahora banco
   g.drawLine(1,1,ancho-3,1); // arriba
   g.drawLine(1,1,1,alto-3);  // izqda.
   g.setColor(Color.blue.darker().darker()); //Azul Oscuro para el titulo
   g.fillRect(4,4,ancho-8,18);
   g.setColor(Color.gray); //Gris otra vez para linea de separacion
   g.drawLine(4,23,ancho-5,23); // Linea de separaci¢n
   g.setColor(Color.white); //idem
   g.drawLine(4,24,ancho-5,24); //idem   
   g.setColor(Color.white); //Gris otra vez para linea de separacion abajo
   g.drawLine(4,BALDOSA_Y + TAMANO_BALDOSA_Y + 9,
              ancho-5,BALDOSA_Y + TAMANO_BALDOSA_Y + 9); // Linea de separaci¢n
   g.setColor(Color.gray); //idem
   g.drawLine(4,BALDOSA_Y + TAMANO_BALDOSA_Y + 10,
              ancho-5,BALDOSA_Y + TAMANO_BALDOSA_Y + 10); //idem
   g.setColor(Color.red); //Para el nombre de la ventana
   g.setFont(new Font("Sanserif",Font.BOLD,17)); //Tipo de letra
   g.drawString("V",10,19);
   g.setColor(Color.green); //Para el nombre de la ventana
   g.setFont(new Font("Sanserif",Font.BOLD,15)); //Tipo de letra
   g.drawString("V",13,19);
   g.setColor(Color.yellow); //Para el nombre de la ventana
   g.setFont(new Font("Sanserif",Font.BOLD,12)); //Tipo de letra
   g.drawString("V",18,19);
   g.setColor(Color.white.brighter()); //Para el nombre de la ventana
   g.setFont(new Font("Sanserif",Font.BOLD,12)); //Tipo de letra
   g.drawString("Delaunay/Voronoi/Simulación Sweep Line", 37,17); // Título
   g.setColor(Color.green);
   g.setFont(new Font("Sanserif",Font.PLAIN,11));
   g.drawString("Versión 9.3.7",DIM_APPLET_X-120, 17);
   // Para poner icono a la derecha arriba
   g.setColor(Color.green);
   g.setFont(new Font("Sanserif",Font.BOLD,17));
   g.drawString("o",DIM_APPLET_X-17 ,17);    
   g.setColor(Color.red);
   g.drawString("V",DIM_APPLET_X-21 ,19);
   g.drawString("V",DIM_APPLET_X-22 ,19);
   g.setColor(Color.yellow);
   g.setFont(new Font("Sanserif",Font.BOLD,16));
   g.drawString("o",DIM_APPLET_X-25 ,20);    
   // Ahora pongo el reborde 3D al Panel de dibujo alrededor de la baldosa
   g.setColor(Color.gray); 
   g.drawLine(BALDOSA_X - 1,
              BALDOSA_Y - 1,
              BALDOSA_X + TAMANO_BALDOSA_X,
              BALDOSA_Y - 1);
   g.drawLine(BALDOSA_X - 1,
              BALDOSA_Y - 1,
              BALDOSA_X - 1,
              BALDOSA_Y + TAMANO_BALDOSA_Y);
   g.setColor(Color.white); 
   g.drawLine(BALDOSA_X - 1,
              BALDOSA_Y + TAMANO_BALDOSA_Y + 1,
              BALDOSA_X + TAMANO_BALDOSA_X + 1,
              BALDOSA_Y + TAMANO_BALDOSA_Y + 1);
   g.drawLine(BALDOSA_X + TAMANO_BALDOSA_X +1,
              BALDOSA_Y - 1,
              BALDOSA_X + TAMANO_BALDOSA_X + 1,
              BALDOSA_Y + TAMANO_BALDOSA_Y+ 1);
   g.drawLine(BALDOSA_X - 4,
              BALDOSA_Y - 4,
              BALDOSA_X + TAMANO_BALDOSA_X + 3,
              BALDOSA_Y - 4);
   g.drawLine(BALDOSA_X - 4,
              BALDOSA_Y - 4,
              BALDOSA_X - 4,
              BALDOSA_Y + TAMANO_BALDOSA_Y + 3);
   g.setColor(Color.gray); 
   g.drawLine(BALDOSA_X - 4,
              BALDOSA_Y + TAMANO_BALDOSA_Y + 4,
              BALDOSA_X + TAMANO_BALDOSA_X + 4,
              BALDOSA_Y + TAMANO_BALDOSA_Y + 4);
   g.drawLine(BALDOSA_X + TAMANO_BALDOSA_X + 4,
              BALDOSA_Y - 4,
              BALDOSA_X + TAMANO_BALDOSA_X + 4,
              BALDOSA_Y + TAMANO_BALDOSA_Y + 4);
   g.setColor(Color.black); 
   g.drawLine(BALDOSA_X + TAMANO_BALDOSA_X + 5,
              BALDOSA_Y - 5,
              BALDOSA_X + TAMANO_BALDOSA_X + 5,
              BALDOSA_Y + TAMANO_BALDOSA_Y + 5);
   g.drawLine(BALDOSA_X - 5,
              BALDOSA_Y + TAMANO_BALDOSA_Y + 5,
              BALDOSA_X + TAMANO_BALDOSA_X + 5,
              BALDOSA_Y + TAMANO_BALDOSA_Y + 5);
   return img;
  }
 
  public void init() {        
   V = new lista_vertices(MAX_VERTICES); // Lista de vertices
   L = new lista_lados(MAX_LADOS);    // Lista de lados
   C = new lista_caras(MAX_CARAS);    // Lista de caras 
        
   lista_voronoi_camb_color = new Polygon[MAX_VERTICES]; //Lista de voronois
                                                         //repintar color
   this.setLayout(null); //Coloco manualmente los componentes
   DIM_APPLET_X = this.getSize().width;
   DIM_APPLET_Y = this.getSize().height;
   // Tamaño de la baldosa en el init en relación al tamaño del applet
   // Aquí se cambian las relaciones de tamaño de la baldosa de dibujo
   TAMANO_BALDOSA_X = DIM_APPLET_X - 2 * BALDOSA_X; //Tamaño en pixels de la baldosa gráfica (Image)(Coord X)
   TAMANO_BALDOSA_Y = DIM_APPLET_Y - BALDOSA_Y - 70; //Tamaño en pixels de la baldosa gr fica (Image)(Coord Y)
   // Creo la matriz booleana que indica si el punto está o no insertado
   m_puntos= new matriz_puntos(TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   // Creo la imagen del tamaño del applet para dibujar el fondo
   fondo=this.createImage(DIM_APPLET_X, DIM_APPLET_Y);
   fondo=dibuja_fondo(fondo); //Dibujamos el fondo
   // Creo el doble buffer de la baldosa inicial
   baldosa_buffer=this.createImage( TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_baldosa_buffer=baldosa_buffer.getGraphics();
   contexto_baldosa_buffer.setColor(COLOR_FONDO_BALDOSA);
   contexto_baldosa_buffer.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_baldosa_buffer.setColor(Color.black);
   // Baldosa color 
   baldosa_color=this.createImage( TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_baldosa_color=baldosa_color.getGraphics();
   contexto_baldosa_color.setColor(COLOR_FONDO_BALDOSA);
   contexto_baldosa_color.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_baldosa_color.setColor(Color.black);
   // Baldosa cierre convexo
   cierre_convexo=this.createImage( TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_cierre_convexo=cierre_convexo.getGraphics();
   contexto_cierre_convexo.setColor(COLOR_FONDO_BALDOSA); //FONDO_BALDOSA);
   contexto_cierre_convexo.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_cierre_convexo.setColor(Color.black);
   // Baldosa voronoi
   i_voronoi=this.createImage( TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_i_voronoi=i_voronoi.getGraphics();
   contexto_i_voronoi.setColor(COLOR_FONDO_BALDOSA); //FONDO_BALDOSA);
   contexto_i_voronoi.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_i_voronoi.setColor(Color.black);
   // Baldosa voronoi color
   i_voronoi_color=this.createImage( TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_i_voronoi_color=i_voronoi_color.getGraphics();
   contexto_i_voronoi_color.setColor(COLOR_FONDO_BALDOSA); //FONDO_BALDOSA);
   contexto_i_voronoi_color.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_i_voronoi_color.setColor(Color.black);
   // Baldosa para dibujar la evolucion de la linea de barrido
   sweep=this.createImage( TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_sweep=sweep.getGraphics();
   // Baldosa para dibujar circunferencia y Voronoi en delaunay
   cir_dela=this.createImage( TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   contexto_cir_dela = cir_dela.getGraphics(); 
   // Creo la imagen del tamaño del applet para dibujar el fondo
   baldosa = new micanvas();
   baldosa.setBounds( BALDOSA_X, BALDOSA_Y,
                      TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   //No escucha eventos el canvas hasta que pulse el botón                   
   //baldosa.addMouseListener(accion_pulsar_punto = new inserta_punto());
   add(baldosa);      //Añado el Canvas baldosa 
   // Añado el botón para empezar a insertar puntos  
   String s;
   s="¡¡ Pulsar aquí para iniciar la Aplicación !!";
   boton_insertar_puntos = new Button(s);
   FontMetrics fm;
   Font f;
   f=new Font("Sanserif",Font.BOLD,15);
   fm=boton_insertar_puntos.getFontMetrics(f);
   int tam=0;
   tam=fm.stringWidth(s);
   boton_insertar_puntos.setFont(f);
   boton_insertar_puntos.setForeground(Color.black);
   boton_insertar_puntos.setBounds((DIM_APPLET_X-tam)/2-30,
                                    BALDOSA_Y + TAMANO_BALDOSA_Y + 15,
                                    tam+60,
                                    DIM_APPLET_Y -
                                   (BALDOSA_Y + TAMANO_BALDOSA_Y + 15) - 10 );
   boton_insertar_puntos.addActionListener(new pulsar_boton_insertar_puntos());
   boton_insertar_puntos.setBackground(Color.lightGray);
   add(boton_insertar_puntos);
   // Esto va en pruebas para la caratula inicial
   contexto_baldosa_buffer.setColor(Color.black);
   contexto_baldosa_buffer.fillRect(0,0,TAMANO_BALDOSA_X, TAMANO_BALDOSA_Y);
   f=new Font("Sanserif",Font.BOLD,30);
   fm=this.getFontMetrics(f);
   s="FACULTAD DE INFORMATICA - U.P.M.";
   tam=fm.stringWidth(s);
   contexto_baldosa_buffer.setFont(f);
   contexto_baldosa_buffer.setColor(Color.blue);
   contexto_baldosa_buffer.drawString(s,
                                      (TAMANO_BALDOSA_X-tam)/2,
                                       TAMANO_BALDOSA_Y/5);
   f=new Font("Sanserif",Font.ITALIC,25);
   fm=this.getFontMetrics(f);
   s="VISUALIZACION INTERACTIVA DEL ALGORITMO";
   tam=fm.stringWidth(s);
   contexto_baldosa_buffer.setFont(f);
   contexto_baldosa_buffer.setColor(Color.white);
   contexto_baldosa_buffer.drawString(s,
                                      (TAMANO_BALDOSA_X-tam)/2,
                                      TAMANO_BALDOSA_Y*2/5);
   contexto_baldosa_buffer.drawLine((TAMANO_BALDOSA_X-tam)/2,
                                     TAMANO_BALDOSA_Y*2/5+1,
                                     TAMANO_BALDOSA_X-(TAMANO_BALDOSA_X-tam)/2,
                                     TAMANO_BALDOSA_Y*2/5+1);
   contexto_baldosa_buffer.drawLine((TAMANO_BALDOSA_X-tam)/2,
                                     TAMANO_BALDOSA_Y*2/5+2,
                                     TAMANO_BALDOSA_X-(TAMANO_BALDOSA_X-tam)/2,
                                     TAMANO_BALDOSA_Y*2/5+2);
   s="DE FORTUNE EN INTERNET";
   tam=fm.stringWidth(s);
   contexto_baldosa_buffer.drawString(s,
                                      (TAMANO_BALDOSA_X-tam)/2,
                                       TAMANO_BALDOSA_Y*2/5 + fm.getHeight()); 
   contexto_baldosa_buffer.drawLine((TAMANO_BALDOSA_X-tam)/2,
                                     TAMANO_BALDOSA_Y*2/5 + fm.getHeight()+1,
                                     TAMANO_BALDOSA_X-(TAMANO_BALDOSA_X-tam)/2,
                                     TAMANO_BALDOSA_Y*2/5 + fm.getHeight()+1);
   contexto_baldosa_buffer.drawLine((TAMANO_BALDOSA_X-tam)/2,
                                     TAMANO_BALDOSA_Y*2/5 + fm.getHeight()+2,
                                     TAMANO_BALDOSA_X-(TAMANO_BALDOSA_X-tam)/2,
                                     TAMANO_BALDOSA_Y*2/5 + fm.getHeight()+2);
   s="TUTOR: Manuel Abellanas Oar";
   f=new Font("Sanserif",Font.PLAIN,18);
   fm=this.getFontMetrics(f);
   tam=fm.stringWidth(s);
   contexto_baldosa_buffer.setFont(f);
   contexto_baldosa_buffer.setColor(Color.gray);
   contexto_baldosa_buffer.drawString(s,
                                      (TAMANO_BALDOSA_X-tam)/2,
                                       TAMANO_BALDOSA_Y*8/10); 
   s="AUTOR: Juan Carlos Ferreras Ferreras";
   tam=fm.stringWidth(s);
   contexto_baldosa_buffer.drawString(s,
                                      (TAMANO_BALDOSA_X-tam)/2,
                                       TAMANO_BALDOSA_Y*8/10+fm.getHeight());
   s="Diciembre de 2000";
   f=new Font("Sanserif",Font.ITALIC,16);
   fm=this.getFontMetrics(f);
   tam=fm.stringWidth(s);
   contexto_baldosa_buffer.setFont(f);
   contexto_baldosa_buffer.drawString(s,
                                      (TAMANO_BALDOSA_X-tam)/2,
                                       TAMANO_BALDOSA_Y*8/10+5*fm.getHeight()/2); 
   //Añado el evento al canvas y lo paro después
   baldosa.addMouseListener(accion_pulsar_punto = new inserta_punto());
   baldosa.removeMouseListener (accion_pulsar_punto);
   // Al loro
   seleccion = new Choice();
   seleccion.add(" Triangulación de Delaunay");
   seleccion.add(" Diagrama de Voronoi");
   seleccion.add(" Cierre Convexo");
   seleccion.setBounds(BALDOSA_X,
                       BALDOSA_Y + TAMANO_BALDOSA_Y + 20,
                       (TAMANO_BALDOSA_X + 11)/3 ,
                       19);
   seleccion.addItemListener(new pulsar_seleccion());
   velocidad = new Choice();
   velocidad.add(" Muy Lento");
   velocidad.add(" Lento");
   velocidad.add(" Medio");
   velocidad.add(" Rápido");
   velocidad.add(" Muy Rápido");
   velocidad.setBounds(5*(TAMANO_BALDOSA_X + 11)/12+2*(TAMANO_BALDOSA_X + 11)/12+7,
                       DIM_APPLET_Y - 22,         
                       2*(TAMANO_BALDOSA_X + 11)/12+3,
                       19);
   velocidad.addItemListener(new pulsar_velocidad());
   // Check para triangulacion circilos y voronoi En pruebas
   check_circulos = new Checkbox("Mostrar Círculos");
   check_voro = new Checkbox("Mostrar Voronoi");
   check_voro.setBounds(5*(TAMANO_BALDOSA_X + 11)/12 ,
                        DIM_APPLET_Y - 52,
                        2*(TAMANO_BALDOSA_X + 11)/12+13,
                        19);
   check_voro.setBackground(Color.white.darker());
   check_voro.addItemListener(new pulsar_check_voro());
   check_circulos.setBounds(5*(TAMANO_BALDOSA_X + 11)/12 ,
                            DIM_APPLET_Y - 32,
                            2*(TAMANO_BALDOSA_X + 11)/12+13,
                            19);
   check_circulos.setBackground(Color.white.darker());
   check_circulos.addItemListener(new pulsar_check_circulos());
   //grupo de checks
   grupo_check = new CheckboxGroup();
   check_b_n = new Checkbox( "B/N", grupo_check, true);
   check_b_n.setBackground(Color.white.darker());
   check_b_n.setBounds(BALDOSA_X ,
                       DIM_APPLET_Y - 22,
                       (TAMANO_BALDOSA_X + 11)/12-5,
                       19);
   check_b_n.addItemListener(new pulsar_check_b_n());
   check_color = new Checkbox( "Color", grupo_check, false);
   check_color.setBackground(Color.white.darker());
   check_color.setBounds((TAMANO_BALDOSA_X + 11)/12+15,
                         DIM_APPLET_Y - 22,
                         52,    
                         19);
   check_color.addItemListener(new pulsar_checkcolor());                     
   //boton para cambiar el color
   boton_cambiar_color = new Button( "Cambiar colores");
   boton_cambiar_color.setBackground(Color.lightGray);
   boton_cambiar_color.setBounds(BALDOSA_X +(TAMANO_BALDOSA_X + 11)/6,
                                 DIM_APPLET_Y - 22,
                                 2*(TAMANO_BALDOSA_X + 11)/12+3,
                                 19);
   boton_cambiar_color.addActionListener(new pulsar_boton_cambiar_color());  
   //Boton manual sweep
   boton_manual = new Button("Manual");
   boton_manual.setBounds(5*(TAMANO_BALDOSA_X + 11)/12,
                          DIM_APPLET_Y - 42,
                          2*(TAMANO_BALDOSA_X + 11)/12+3,
                          19);
   boton_manual.setForeground(Color.blue.darker().darker());
   boton_manual.addActionListener(new pulsar_boton_manual());
   //Boton volver
   boton_volver = new Button("Volver");
   boton_volver.setBounds(5*(TAMANO_BALDOSA_X + 11)/12+2*(TAMANO_BALDOSA_X + 11)/12+7,
                          DIM_APPLET_Y - 42,
                          2*(TAMANO_BALDOSA_X + 11)/12+3,
                          19);
   boton_volver.setFont(new Font("Sanserif",Font.BOLD,14));
   boton_volver.setForeground(Color.red);
   boton_volver.addActionListener(new pulsar_boton_volver());
   boton_comenzar = new Button("Start");
   boton_comenzar.setBounds((5*(TAMANO_BALDOSA_X + 11)/12+2*(TAMANO_BALDOSA_X + 11)/12+7)+(2*(TAMANO_BALDOSA_X + 11)/12+3)+3,
                             DIM_APPLET_Y - 42,
                            (2*(TAMANO_BALDOSA_X + 11)/12+3)/2+3,
                             40);
   boton_comenzar.setFont(new Font("Sanserif",Font.BOLD,15));
   boton_comenzar.setForeground(Color.blue.darker().darker());
   boton_comenzar.addActionListener(new pulsar_boton_comenzar());
   //Boton automatico sweep
   boton_automatico = new Button("Automático");
   boton_automatico.setBounds(5*(TAMANO_BALDOSA_X + 11)/12,
                              DIM_APPLET_Y - 22,
                              2*(TAMANO_BALDOSA_X + 11)/12+3,
                              19);
   boton_automatico.setForeground(Color.blue.darker().darker());
   boton_automatico.addActionListener(new pulsar_boton_automatico());
   // Esto es para cargar las clases de drag y sweep y no ralenticen la carga
   drag_sweep = new hacer_drag_sweep();
   click_sweep = new hacer_click_sweep();
   // El titulo del Sweep
   titulo =new Label("SIMULACION SWEEP LINE",Label.CENTER);
   titulo.setBounds(5*(TAMANO_BALDOSA_X + 11)/12-17,
                    DIM_APPLET_Y - 58,
                    2*(TAMANO_BALDOSA_X + 11)/12+35,
                    16);
   titulo.setFont(new Font("Sanserif",Font.BOLD,11));
   titulo.setBackground(Color.white.darker());
   titulo.setForeground(Color.blue.darker().darker());
   boton_nuevo = new Button("Nuevo");
   boton_nuevo.setBounds(BALDOSA_X + 5 * (TAMANO_BALDOSA_X + 11)/6,
                         BALDOSA_Y + TAMANO_BALDOSA_Y + 15,
                         (TAMANO_BALDOSA_X + 11) / 6 - 4,
                         DIM_APPLET_Y -
                         (BALDOSA_Y + TAMANO_BALDOSA_Y + 15) - 10 );
   boton_nuevo.addActionListener(new pulsar_boton_nuevo());
   boton_nuevo.setBackground(Color.lightGray);
  } //del init()
                             
  public void update(Graphics g) {
   paint(g);
  }
 
  public void paint(Graphics g) {
   g.drawImage(fondo,0,0,null,null);
  } 
 } //De Voronoi