delphsim.model.Resultado.java Source code

Java tutorial

Introduction

Here is the source code for delphsim.model.Resultado.java

Source

/** 
 * Copyright 2008 Vctor Enrique Tamames,
 * Universidad de Valladolid, Espaa.
 * 
 * This file is part of DelphSim.
 *
 * DelphSim is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or any later version.
 *
 * DelphSim is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * DelphSim. If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * DelphSim (Delphos Simulator), simulador de epidemias desarrollado como
 * Proyecto Fin de Carrera de Ingeniera Informtica para la Escuela Tcnica
 * Superior de Ingeniera Informtica de la Universidad de Valladolid.
 */
package delphsim.model;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Rectangle;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Vector;

import org.apache.batik.dom.GenericDOMImplementation;
import org.apache.batik.svggen.SVGGraphics2D;

import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.dom4j.tree.DefaultAttribute;
import org.dom4j.tree.DefaultElement;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.DefaultXYDataset;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;

/**
 * Los objetos de esta clase representan resultados que el usuario espera
 * obtener si se completa una simulacin satisfactoriamente.
 * @author Vctor E. Tamames Gmez
 */
public class Resultado implements Cloneable {

    /**
     * Nmero de puntos que se guardarn para dibujar la grfica. Es una
     * aproximacin, no tienen por qu guardarse exactamente el nmero que
     * se marca con este atributo.
     */
    public static int NUM_PUNTOS_GRAFICAS = 1000;

    /**
     * Resoluciones disponibles para que el usuario exporte las grficas en
     * formato de imagen. El primer valor indica el ancho, el segundo el alto
     * y el ltimo, entre corchetes, la proporcin.
     */
    public static Object[] RESOLUCIONES_DISPONIBLES = { "640, 480 [4:3]", "800, 600 [4:3]", "1024, 768 [4:3]",
            "1280, 960 [4:3]", "1600, 1200 [4:3]", "2048, 1536 [4:3]", "640, 360 [16:9]", "800, 450 [16:9]",
            "1024, 576 [16:9]", "1280, 720 [16:9]", "1600, 900 [16:9]", "2048, 1152 [16:9]" };

    /**
     * De las resoluciones disponibles, el ndice de la que aparece marcada
     * por defecto.
     */
    public static int RESOLUCION_POR_DEFECTO = 2;

    /**
     * El ttulo del resultado.
     */
    private String titulo;

    /**
     * La etiqueta del eje horizontal, de abcisas, o de las 'x'.
     */
    private String xLabel;

    /**
     * La etiqueta del eje vertical, de ordenadas, o de las 'y'.
     */
    private String yLabel;

    /**
     * Funciones que se calculan para este resultado. Hacen referencia a una
     * clase interna.
     */
    private Funcion[] funciones = new Funcion[0];

    /**
     * La grfica a generar cuando se complete la simulacin.
     */
    private JFreeChart grafica;

    /**
     * Los valores del tiempo para los puntos que se van a usar para generar
     * la grfica.
     */
    private Vector puntosTiempo = new Vector();

    /**
     * Archivo donde se almacenan los valores de la simulacin correspondientes 
     * al tiempo.
     */
    private File archivoTiempo;

    /**
     * Nmero de puntos total calculados en la simulacin.
     */
    private long numPuntosTotal;

    /**
     * Constructor de la clase.
     */
    public Resultado() {
    }

    /**
     * Mtodo que aade una nueva funcin a este resultado con la informacin
     * pasada en los parmetros.
     * @param n El nombre de la funcin (para la leyenda).
     * @param d La definicin de la funcin.
     * @param c El color de la lnea de la funcin.
     * @param g El grosor de la lnea de la funcin.
     */
    public void anadirFuncion(String n, String d, Color c, int g) {
        Funcion[] fs = new Funcion[this.funciones.length + 1];
        for (int i = 0; i < this.funciones.length; i++) {
            fs[i] = this.funciones[i];
        }
        fs[this.funciones.length] = new Funcion(n, d, c, g);
        this.funciones = fs;
    }

    /**
     * Aade un nuevo valor al vector de valores del tiempo.
     * @param pTiempo El nuevo valor a aadir.
     */
    public void anadirPuntoTiempo(double pTiempo) {
        this.puntosTiempo.add(pTiempo);
    }

    /**
     * Aade un nuevo valor al vector de valores de una funcin.
     * @param pFuncion El nuevo valor a aadir.
     * @param indice El ndice de la funcin a la que aadirle el valor.
     */
    public void anadirPuntoFuncion(double pFuncion, int indice) {
        this.funciones[indice].addPunto(pFuncion);
    }

    /**
     * Mtodo para cambiar el ttulo de este resultado.
     * @param t El nuevo ttulo para este resultado.
     */
    public void setTitulo(String t) {
        this.titulo = t;
    }

    /**
     * Mtodo para obtener el ttulo de este resultado.
     * @return El ttulo de este resultado.
     */
    public String getTitulo() {
        return this.titulo;
    }

    /**
     * Mtodo para cambiar la etiqueta del eje horizontal.
     * @param x La nueva etiqueta.
     */
    public void setXLabel(String x) {
        this.xLabel = x;
    }

    /**
     * Mtodo para obtener la etiqueta del eje horizontal.
     * @return La etiqueta.
     */
    public String getXLabel() {
        return this.xLabel;
    }

    /**
     * Mtodo para cambiar la etiqueta del eje vertical.
     * @param y La nueva etiqueta.
     */
    public void setYLabel(String y) {
        this.yLabel = y;
    }

    /**
     * Mtodo para obtener la etiqueta del eje vertical.
     * @return La etiqueta.
     */
    public String getYLabel() {
        return this.yLabel;
    }

    /**
     * Mtodo para cambiar el archivo que contiene los valores de la simulacin
     * referidos al tiempo.
     * @param f El nuevo fichero.
     */
    public void setFileTiempo(String f) {
        this.archivoTiempo = new File(f);
    }

    /**
     * Mtodo para obtener el archivo que contiene los valores de la simulacin
     * referidos al tiempo.
     * @return El fichero.
     */
    public File getFileTiempo() {
        return this.archivoTiempo;
    }

    /**
     * Mtodo para cambiar el nmero de puntos total generados por la simulacin.
     * @param t El nuevo nmero de puntos total.
     */
    public void setNumPuntosTotal(long t) {
        this.numPuntosTotal = t;
    }

    /**
     * Mtodo para cambiar el nmero de puntos total generados por la simulacin.
     * @return El nmero de puntos total.
     */
    public long getNumPuntosTotal() {
        return this.numPuntosTotal;
    }

    /**
     * Mtodo para obtener el nmero de funciones que tiene este resultado.
     * @return El nmero de funciones.
     */
    public int getNumFunciones() {
        return this.funciones.length;
    }

    /**
     * Mtodo para cambiar la informacin de una funcin en concreto.
     * @param funcion Un array que contiene el nombre de la funcin, la
     *                definicin, el color y el grosor, en ese orden.
     * @param indice El ndice de la funcin a cambiar.
     */
    public void setFuncion(Object[] funcion, int indice) {
        if (this.funciones[indice] != null) {
            this.funciones[indice].eliminar();
        }
        this.funciones[indice] = new Funcion((String) funcion[0], (String) funcion[1], (Color) funcion[2],
                (Integer) funcion[3]);
    }

    /**
     * Mtodo para obtener la informacin de una funcin en concreto.
     * @param indice El ndice de la funcin.
     * @return Un array que contiene el nombre de la funcin, la definicin,
     *         el color y el grosor, en ese orden.
     */
    public Object[] getFuncion(int indice) {
        Object[] o = new Object[4];
        o[0] = this.funciones[indice].getNombre();
        o[1] = this.funciones[indice].getDefinicion();
        o[2] = this.funciones[indice].getColor();
        o[3] = this.funciones[indice].getGrosor();
        return o;
    }

    /**
     * Mtodo para cambiar las funciones de este resultado.
     * @param fs Las nuevas funciones.
     */
    private void setFunciones(Funcion[] fs) {
        this.funciones = fs;
    }

    /**
     * Mtodo para cambiar el archivo que contiene los valores de una funcin.
     * @param f El nuevo fichero.
     * @param indice El ndice de la funcin.
     */
    public void setFileFuncion(String f, int indice) {
        this.funciones[indice].setFichero(f);
    }

    /**
     * Mtodo para obtener el archivo que contiene los valores de una funcin.
     * @param indice El ndice de la funcin.
     * @return El fichero.
     */
    public File getFileFuncion(int indice) {
        return this.funciones[indice].getFichero();
    }

    /**
     * Mtodo que elimina las funciones de este resultado una por una.
     */
    public void eliminarFunciones() {
        for (int i = 0; i < this.funciones.length; i++) {
            this.funciones[i].eliminar();
        }
        this.funciones = new Funcion[0];
    }

    /**
     * Mtodo para construir una grfica de tipo <CODE>JFreeChart</CODE> con
     * los valores de este resultado y sus funciones y obtener como resultado
     * el panel de tipo <CODE>ChartPanel</CODE> que la contiene.
     * @return Un panel <CODE>ChartPanel</CODE> con la nueva grfica.
     */
    public ChartPanel construirPanelResultado() {
        DefaultXYDataset data = new DefaultXYDataset();
        for (int i = 0; i < this.getNumFunciones(); i++) {
            String nombre = this.funciones[i].getNombre();
            double[][] puntos = new double[2][this.puntosTiempo.size()];
            for (int j = 0; j < this.puntosTiempo.size(); j++) {
                puntos[0][j] = Double.valueOf(this.puntosTiempo.get(j).toString());
                puntos[1][j] = this.funciones[i].getPunto(j);
            }
            data.addSeries(nombre, puntos);
        }
        JFreeChart chart = ChartFactory.createXYLineChart(this.getTitulo(), // ttulo laaargo
                this.getXLabel(), // xLabel
                this.getYLabel(), // yLabel
                data, // datos
                PlotOrientation.VERTICAL, true, // legenda
                true, // tooltips
                false // URLs
        );
        for (int i = 0; i < this.getNumFunciones(); i++) {
            chart.getXYPlot().getRenderer().setSeriesStroke(i, new BasicStroke(this.funciones[i].getGrosor()));
            chart.getXYPlot().getRenderer().setSeriesPaint(i, this.funciones[i].getColor());
        }
        ChartPanel panel = new ChartPanel(chart, // grfica
                true, // propiedades
                false, // guardar
                false, // imprimir
                true, // zoom
                true // tooltips
        );
        this.grafica = chart;
        return panel;
    }

    /**
     * Mtodo para exportar la grfica de este resultado a un formato de imagen.
     * Para ello emplea los mtodos estticos de la clase <CODE>Resultado</CODE>.
     * @param destino El fichero donde exportar la imagen.
     * @param resolucion El tamao de la imagen.
     * @param formato El formato de la imagen.
     * @throws java.io.IOException Si hay algn problema al guardar la imagen en disco.
     * @see delphsim.model.Resultado#exportarComoPNG(java.io.File, org.jfree.chart.JFreeChart, int, int) exportarComoPNG
     * @see delphsim.model.Resultado#exportarComoSVG(java.io.File, org.jfree.chart.JFreeChart, int, int) exportarComoSVG
     */
    public void exportarImagen(File destino, Object resolucion, String formato) throws IOException {
        // Primero transformamos la resolucin a anchura y altura
        int anchura = Integer.valueOf(resolucion.toString().split(", ")[0]); // NOI18N
        int altura = Integer.valueOf(resolucion.toString().split(", ")[1].split(" ")[0]); // NOI18N
        if (formato.equals("png")) {
            Resultado.exportarComoPNG(destino, this.grafica, anchura, altura);
        } else if (formato.equals("svg")) {
            Resultado.exportarComoSVG(destino, this.grafica, anchura, altura);
        } else {
            System.err.println("Error: formato de imagen desconocido.");
        }
    }

    /**
     * Mtodo para exportar los datos de este resultado a un formato de texto.
     * Para ello emplea los mtodos estticos de la clase <CODE>Resultado</CODE>.
     * @param destino El fichero donde exportar los datos.
     * @param numDatos El nmero de datos (puntos, filas) que se quieren exportar.
     * @param formato El formato de exportacin.
     * @throws java.io.IOException Si hay algn problema al crear el fichero.
     * @see delphsim.model.Resultado#exportarComoCSV(java.io.File, java.lang.String, java.io.File[], long, long) exportarComoCSV
     * @see delphsim.model.Resultado#exportarComoXML(java.io.File, java.lang.String[], java.lang.String[], java.io.File[], long, long) exportarComoXML
     */
    public void exportarDatos(File destino, int numDatos, String formato) throws IOException {
        // Primero recogemos los archivos de todas las funciones
        File[] temps = new File[this.getNumFunciones() + 1];
        temps[0] = this.archivoTiempo;
        for (int i = 0; i < this.getNumFunciones(); i++) {
            temps[i + 1] = this.getFileFuncion(i);
        }
        if (formato.equals("csv")) {
            // Construimos la cabecera con datos privados
            String cabecera = "\"Tiempo\"";
            for (int i = 0; i < this.getNumFunciones(); i++) {
                cabecera += ",\"" + this.funciones[i].getNombre() + " {" + this.funciones[i].getDefinicion()
                        + "}\"";
            }
            if (numDatos == 0 || numDatos >= this.numPuntosTotal) {
                Resultado.exportarComoCSV(destino, cabecera, temps, this.numPuntosTotal, this.numPuntosTotal);
            } else {
                Resultado.exportarComoCSV(destino, cabecera, temps, this.numPuntosTotal, numDatos);
            }
        } else if (formato.equals("xml")) {
            // Recogemos los datos privados en dos arrays para pasarlos
            String[] nombres = new String[this.getNumFunciones() + 1];
            String[] definiciones = new String[this.getNumFunciones() + 1];
            nombres[0] = null;
            definiciones[0] = null;
            for (int i = 0; i < this.getNumFunciones(); i++) {
                nombres[i + 1] = this.funciones[i].getNombre();
                definiciones[i + 1] = this.funciones[i].getDefinicion();
            }
            if (numDatos == 0 || numDatos >= this.numPuntosTotal) {
                Resultado.exportarComoXML(destino, nombres, definiciones, temps, this.numPuntosTotal,
                        this.numPuntosTotal);
            } else {
                Resultado.exportarComoXML(destino, nombres, definiciones, temps, this.numPuntosTotal, numDatos);
            }
        } else {
            System.err.println("Error: formato de texto desconocido.");
        }
    }

    /**
     * Mtodo esttico que exporta una grfica <CODE>JFreeChart</CODE> al
     * formato de imagen PNG.
     * @param destino El fichero de destino.
     * @param chart La grfica a exportar.
     * @param anchura Anchura de la imagen final.
     * @param altura Altura de la imagen final.
     * @throws java.io.IOException Si hubiera algn problema al crear el archivo en disco.
     */
    public static void exportarComoPNG(File destino, JFreeChart chart, int anchura, int altura) throws IOException {
        // Para PNG utilizamos las herramientas que ofrece JFreeChart
        ChartUtilities.saveChartAsPNG(destino, chart, anchura, altura);
    }

    /**
     * Mtodo esttico que exporta una grfica <CODE>JFreeChart</CODE> al
     * formato de imagen vectorial SVG.
     * @param destino El fichero de destino.
     * @param chart La grfica a exportar.
     * @param anchura Anchura de la imagen final.
     * @param altura Altura de la imagen final.
     * @throws java.io.IOException Si hubiera algn problema al crear el archivo en disco.
     */
    public static void exportarComoSVG(File destino, JFreeChart chart, int anchura, int altura) throws IOException {
        // Para SVG utilizamos la librera Batik
        // Obtener un DOMImplementation
        DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
        // Crear una instancia de org.w3c.dom.Document
        String svgNS = "http://www.w3.org/2000/svg";
        Document document = domImpl.createDocument(svgNS, "svg", null);
        // Crear una instancia del Generador de SVGs
        SVGGraphics2D svgGenerator = new SVGGraphics2D(document);
        // Dibujar la grfica en el Generador de SVGs
        chart.draw(svgGenerator, new Rectangle(anchura, altura));
        // Escribir el archivo SVG
        OutputStream outputStream = new FileOutputStream(destino);
        Writer out = new OutputStreamWriter(outputStream, "UTF-8");
        svgGenerator.stream(out, true /* utilizar CSS */);
        outputStream.flush();
        outputStream.close();
    }

    /**
     * Mtodo esttico que exporta los valores obtenidos tras la simulacin al
     * formato textual CSV.
     * @param destino El archivo de destino.
     * @param cabecera La cabecera del archivo CSV (primera fila del documento).
     * @param temps Array con los archivos temporales de los cuales obtener los
     *              datos a exportar.
     * @param numPuntosTotal El nmero de puntos total que contienen los
     *                       archivos temporales.
     * @param numPuntosExportar El nmero de puntos que quiere obtener el usuario.
     * @throws java.io.IOException Si hubiera algn problema al crear el archivo en disco.
     */
    public static void exportarComoCSV(File destino, String cabecera, File[] temps, long numPuntosTotal,
            long numPuntosExportar) throws IOException {
        // Creamos el archivo de salida y escribimos la cabecera en l
        PrintWriter salida = new PrintWriter(new BufferedWriter(new FileWriter(destino)));
        salida.println(cabecera);
        // Creamos los bfers de lectura para leer los temporales
        BufferedReader[] buffers = new BufferedReader[temps.length];
        for (int i = 0; i < temps.length; i++) {
            buffers[i] = new BufferedReader(new FileReader(temps[i]));
        }
        // Calculamos cada cuanto tenemos que guardar un punto
        double cadaCuanto;
        if (numPuntosTotal == numPuntosExportar) {
            cadaCuanto = 1.0d;
        } else {
            cadaCuanto = new Double(numPuntosTotal) / new Double(numPuntosExportar - 1);
        }
        long siguientePuntoExportar = 0;
        long contadorNumPuntoLeido = 0;
        long contadorNumPuntosExportados = 0;
        // Comenzamos a leer los temporales escribiendo en el CSV de salida
        String nuevaLinea = "";
        String leido = null;
        for (int i = 0; i < buffers.length; i++) {
            leido = buffers[i].readLine();
            nuevaLinea += leido + ",";
        }
        // En el momento en que se lee un null, se termina
        while (leido != null) {
            nuevaLinea = nuevaLinea.substring(0, nuevaLinea.length() - 1);
            if (siguientePuntoExportar == contadorNumPuntoLeido) {
                salida.println(nuevaLinea);
                contadorNumPuntosExportados++;
                siguientePuntoExportar = Math.round(cadaCuanto * contadorNumPuntosExportados);
                if (siguientePuntoExportar >= numPuntosTotal) {
                    siguientePuntoExportar = numPuntosTotal - 1;
                }
            }
            nuevaLinea = "";
            for (int i = 0; i < buffers.length; i++) {
                leido = buffers[i].readLine();
                nuevaLinea += leido + ",";
            }
            contadorNumPuntoLeido++;
        }
        // Cerramos los bfers y el archivo de salida
        for (int i = 0; i < buffers.length; i++) {
            buffers[i].close();
        }
        salida.flush();
        salida.close();
    }

    /**
     * Mtodo esttico que exporta los valores obtenidos tras la simulacin al
     * formato XML.
     * @param destino El archivo de destino.
     * @param nombres Los nombres de las distintas columnas/funciones.
     * @param definiciones La definicin de cada columna/funcin.
     * @param temps Array con los archivos temporales de los cuales obtener los
     *              datos a exportar.
     * @param numPuntosTotal El nmero de puntos total que contienen los
     *                       archivos temporales.
     * @param numPuntosExportar El nmero de puntos que quiere obtener el usuario.
     * @throws java.io.IOException Si hubiera algn problema al crear el archivo en disco.
     */
    public static void exportarComoXML(File destino, String[] nombres, String[] definiciones, File[] temps,
            long numPuntosTotal, long numPuntosExportar) throws IOException {
        // Crear el documento, el elemento 'raiz' y asignarlo
        org.dom4j.Document documento = DocumentHelper.createDocument();
        DefaultElement elementoResultado = new DefaultElement("resultado");
        documento.setRootElement(elementoResultado);

        // Creamos los bfers de lectura para leer los temporales
        BufferedReader[] buffers = new BufferedReader[temps.length];
        for (int i = 0; i < temps.length; i++) {
            buffers[i] = new BufferedReader(new FileReader(temps[i]));
        }
        // Calculamos cada cuanto tenemos que guardar un punto
        double cadaCuanto;
        if (numPuntosTotal == numPuntosExportar) {
            cadaCuanto = 1.0d;
        } else {
            cadaCuanto = new Double(numPuntosTotal) / new Double(numPuntosExportar - 1);
        }
        long siguientePuntoExportar = 0;
        long contadorNumPuntoLeido = 0;
        long contadorNumPuntosExportados = 0;
        // Comenzamos a leer los temporales aadiendo elementos al documento
        String[] valores = new String[buffers.length];
        for (int i = 0; i < buffers.length; i++) {
            valores[i] = buffers[i].readLine();
        }
        // En el momento en que se lee un null, se termina
        while (valores[0] != null) {
            // Para cada punto que haya que exportar
            if (siguientePuntoExportar == contadorNumPuntoLeido) {
                DefaultElement nuevaFila = new DefaultElement("fila");
                // Para el tiempo, nuevo elemento, su valor y aadirlo a la fila
                DefaultElement elementoTiempo = new DefaultElement("Tiempo");
                elementoTiempo.setText(valores[0]);
                nuevaFila.add(elementoTiempo);
                // Lo mismo para cada linea, pero ademas con nombre y definicin
                for (int i = 1; i < valores.length; i++) {
                    DefaultElement elementoLinea = new DefaultElement("Lnea" + i);
                    elementoLinea.add(new DefaultAttribute("nombre", nombres[i]));
                    elementoLinea.add(new DefaultAttribute("definicion", definiciones[i]));
                    elementoLinea.setText(valores[i]);
                    nuevaFila.add(elementoLinea);
                }
                // Y aadimos la nueva fila
                elementoResultado.add(nuevaFila);
                // Calculamos el siguiente punto a exportar
                contadorNumPuntosExportados++;
                siguientePuntoExportar = Math.round(cadaCuanto * contadorNumPuntosExportados);
                if (siguientePuntoExportar >= numPuntosTotal) {
                    siguientePuntoExportar = numPuntosTotal - 1;
                }
            }
            // Leemos la siguiente lnea de los ficheros
            for (int i = 0; i < buffers.length; i++) {
                valores[i] = buffers[i].readLine();
            }
            contadorNumPuntoLeido++;
        }
        // Cerramos los bfers y el archivo de salida
        for (int i = 0; i < buffers.length; i++) {
            buffers[i].close();
        }
        // Imprimimos el documento como XML
        OutputFormat formato = OutputFormat.createPrettyPrint();
        formato.setEncoding("UTF-16");
        formato.setIndent("\t");
        formato.setNewLineAfterDeclaration(false);
        formato.setPadText(false);
        formato.setTrimText(true);
        formato.setXHTML(true);
        OutputStreamWriter salida = new OutputStreamWriter(new FileOutputStream(destino), "UTF-16");
        XMLWriter escritor = new XMLWriter(salida, formato);
        escritor.write(documento);
        escritor.flush();
        escritor.close();
    }

    /**
     * Implementacin de la interfaz Cloneable.
     * @return Un clon idntico a este objeto.
     */
    @Override
    public Resultado clone() {
        Resultado clon = new Resultado();
        clon.setTitulo(this.getTitulo());
        clon.setXLabel(this.getXLabel());
        clon.setYLabel(this.getYLabel());
        Funcion[] clones = new Funcion[this.getNumFunciones()];
        for (int i = 0; i < clones.length; i++) {
            clones[i] = this.funciones[i].clone();
        }
        clon.setFunciones(clones);
        return clon;
    }

    /**
     * Clase interna que representa cada una de las lneas/funciones que puede
     * contener un resultado.
     */
    private class Funcion implements Cloneable {

        /**
         * El nombre de la funcin (para la leyenda, sobre todo).
         */
        private String nombre;

        /**
         * La definicin de la funcin.
         */
        private String definicion;

        /**
         * El color de la lnea que representar a esta funcin en la grfica.
         */
        private Color color;

        /**
         * El grosor de la lnea que representar a esta funcin en la grfica.
         */
        private int grosor;

        /**
         * Los valores de la funcin para los puntos que se van a usar para
         * generar la grfica.
         */
        private Vector puntosDibujar = new Vector();

        /**
         * Archivo donde se almacenan los valores de la simulacin
         * correspondientes a esta funcin.
         */
        private File fichero;

        /**
         * Constructor de la clase.
         * @param n El nombre de la nueva funcin.
         * @param d La definicin de la nueva funcin.
         * @param c El color de la nueva funcin.
         * @param g El grosor de la nueva funcin.
         */
        public Funcion(String n, String d, Color c, int g) {
            this.nombre = n;
            this.definicion = d;
            this.color = c;
            this.grosor = g;
        }

        /**
         * Mtodo para cambiar el nombre de esta funcin.
         * @param n El nuevo nombre.
         */
        public void setNombre(String n) {
            this.nombre = n;
        }

        /**
         * Mtodo para obtener el nombre de esta funcin.
         * @return El nombre de la funcin.
         */
        public String getNombre() {
            return this.nombre;
        }

        /**
         * Mtodo para cambiar la definicin de esta funcin.
         * @param d La nueva definicin.
         */
        public void setDefinicion(String d) {
            this.definicion = d;
        }

        /**
         * Mtodo para obtener la definicin de esta funcin.
         * @return La definicin de esta funcin.
         */
        public String getDefinicion() {
            return this.definicion;
        }

        /**
         * Mtodo para cambiar el color de la lnea de esta funcin.
         * @param c El nuevo color.
         */
        public void setColor(Color c) {
            this.color = c;
        }

        /**
         * Mtodo para obtener el color de la lnea de esta funcin.
         * @return El color de la lnea.
         */
        public Color getColor() {
            return this.color;
        }

        /**
         * Mtodo para cambiar el grosor de la lnea de esta funcin.
         * @param g El nuevo grosor.
         */
        public void setGrosor(int g) {
            this.grosor = g;
        }

        /**
         * Mtodo para obtener el grosor de la lnea de esta funcin.
         * @return El grosor de la lnea.
         */
        public int getGrosor() {
            return this.grosor;
        }

        /**
         * Aade un nuevo valor al vector de valores de esta funcin.
         * @param punto El nuevo valor a aadir.
         */
        public void addPunto(double punto) {
            this.puntosDibujar.add(punto);
        }

        /**
         * Mtodo para obtener el valor marcado por el ndice pasado como
         * parmetro del vector de valores de esta funcin.
         * @param indice El ndice del valor a obtener.
         * @return El valor.
         */
        public double getPunto(int indice) {
            return Double.valueOf(this.puntosDibujar.get(indice).toString());
        }

        /**
         * Mtodo para cambiar el fichero relacionado con esta funcin.
         * @param f Cadena de texto con la ruta del nuevo fichero.
         */
        public void setFichero(String f) {
            this.fichero = new File(f);
        }

        /**
         * Mtodo para cambiar el fichero relacionado con esta funcin.
         * @param f El nuevo fichero.
         */
        public void setFichero(File f) {
            this.fichero = f;
        }

        /**
         * Mtodo para obtener el fichero relacionado con esta funcin.
         * @return El fichero.
         */
        public File getFichero() {
            return this.fichero;
        }

        /**
         * Mtodo para eliminar esta funcin. Es responsable de eliminar el
         * fichero asociado a ella o, si no se pudiera, indicar al sistema que
         * lo borre al salir de la aplicacin.
         */
        public void eliminar() {
            if (this.fichero != null && this.fichero.exists()) {
                if (!this.fichero.delete()) {
                    this.fichero.deleteOnExit();
                }
                this.fichero = null;
            }
        }

        /**
         * Implementacin de la interfaz Cloneable.
         * @return Un clon idntico a este objeto.
         */
        @Override
        public Funcion clone() {
            Funcion clon = new Funcion(this.getNombre(), this.getDefinicion(), this.getColor(), this.getGrosor());
            clon.setFichero(this.getFichero());
            return clon;
        }
    }
}