xy_plot.java



import java.awt.event.WindowEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import java.awt.Graphics;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Font;
import java.awt.Point;
import java.awt.Label;
import java.util.LinkedList;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.IOException;


// ======================================================================
// Objetivo:	Graficar un conjunto de pares de valores x,y
// Autor:	J. Rafael R. Ochoa
// Fecha:	2003,
// Derechos:	SID - FIE - UMSNH
//
// -----------------------------------------------------------------------------------------------------------------------
// NOTAS:
//
//	1.- Hay que ejecutarlo de la siguiente manera:
//		Prompt> java xy_plot ARCHIVO
//	2.- El contenido de ARCHIVO debe ser solamente los pares x,y separados por una coma y un par bajo el otro.
//	3.- Hay que calcular cuando es cero. AquI se considera que existe exActamente el valor de cero (mEtodo ObtenCero)
//		El primer cruce por cero, se puede obtener en el primer cambio de signo. Usando esas 2 coordenadas, se
//		puede usar la ecuaciOn de la intersecciOn -SE PUEDE OCUPAR-
//
//			V  E  R  S  I  O  N           1 . 0
// -----------------------------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
// MEJORAS:
//	Julio 1 del 2004.	Se centra la ventana en la pantalla y se dispone de varios colores.
//	Julio 6 del 2004	Le quitE la rayita extra y se atiende al evento del ratOn con el click izquierdo
//				dando el valor de la funciOn para ese valor de X.
// -----------------------------------------------------------------------------------------------------------------------

public class xy_plot extends JFrame
{

	// DeclaraciOn de las variables que controlan al sistema
	//________________________________________________________
	LinkedList ListaReal;					// Lista de valores de los datos reales.
	int Vector_X_Pixel[], Vector_Y_Pixel[];			// Vector de valores interpretados como enteros.

	// Valores extremos convenientes para recibir los nuevos valores
	double VXmax = -10000, VXmin = 10000, VYmax = -10000, VYmin = 10000, CX0 = 0.0, X_CERO, Y_CERO;
	Graphics AG = null;					// Objeto grAfico -Area para graficar-
	int CDM_X = 20;						// Constante Del Margen -CDM- en x
	int CDM_Y = 40;						// Constante Del Margen -CDM- en y
	int posX=0, posY=0;					// Posiciones de los ejes.
	int ANCHO = 600, ALTO = 500;				// Dimensiones del Area grAfica
	String ARCHIVO = "";					// Nombre del archivo a leer
	Point Pos_XY_Mouse;					// PosiciOn del ratOn en la curva al dar click izquierdo

	public xy_plot(String ARCHIVO) throws IOException
	{
		this.ARCHIVO = ARCHIVO;
		getContentPane().setLayout(null);			// Contenedor nulo
		setTitle(" { " + ARCHIVO + " } ");			// TItulo de la ventana
		setResizable(true);					// No es redimensionable
		Dimension DimMonitor = Toolkit.getDefaultToolkit().getScreenSize();		// Dimensiones del monitor
		setLocation((DimMonitor.width - ANCHO) / 2, (DimMonitor.height - ALTO) / 2);	// PosiciOn centrada
		setSize(new Dimension(ANCHO, ALTO));			// Dimensiones
		addMouseListener(new EventoRaton());			// Escuchador de eventos del ratOn
		show();							// Mostrar la ventana
	}

	// SOlo se captura el evento de cierre de la ventana
	protected void processWindowEvent(WindowEvent e) { if (e.getID() == WindowEvent.WINDOW_CLOSING) System.exit(0); }

	public static void main(String S[]) throws IOException
	{
		if (S.length != 1)
		{
			System.out.println("Error en el nUmero de parAmetros...\n[Uso: java xy_plot Archivo_De_Datos]");
			System.exit(0);
		}
		new xy_plot(S[0]);
	}

	void Inicia(String ARCHIVO) throws IOException
	{ Lee_Datos(ARCHIVO); CalcularRelacion(); }
	
	public void paint(Graphics G)
	{
			G.setColor(Color.black);
			G.fillRect(0,0,this.getWidth(), this.getHeight());	// Limpiar el Area
			AG = G.create();					// Copia del Area grAfica
			try { Inicia(ARCHIVO); } catch(IOException e){}
	}	

	// Obtiene los datos del archivo que entrO como argumento y los guarda en una lista ligada
	void Lee_Datos(String archivo) throws IOException
	{
		Object OBJETO;
		String Linea;
		ListaReal = new LinkedList();
		
		BufferedReader ARCHIVO   = new BufferedReader(new InputStreamReader(new FileInputStream(archivo)));
		while((Linea = ARCHIVO.readLine()) != null ) ListaReal.add(Crea_Objeto(Linea));
		ARCHIVO.close();
	}

	// Cada una de las lIneas leIdas en el mEtodo "Lee_Dato" se convierten a un elemento de la clase "NODO"
	// Se regresa un Objeto para poder ser aNadido a la lista ligada.
	Object Crea_Objeto(String Linea)
	{
		String VMAX_STR = "", VMIN_STR = "";
		
		StringTokenizer ST = new StringTokenizer(Linea, ",");

		if (ST.countTokens() != 2) { System.out.println("Error en el archivo de datos..."); System.exit(0); }
		double X = Double.parseDouble(ST.nextToken());
		double Y = Double.parseDouble(ST.nextToken());

		ObtenValorMinimo(X, Y); ObtenValorMaximo(X, Y); ObtenCero(X, Y);
		return (Object)new NODO(X, Y);		// ConversOn a Objeto
	}
	
	void ObtenValorMinimo(double X, double Y) { VXmin = Math.min(VXmin, X); VYmin = Math.min(VYmin, Y); }
	void ObtenValorMaximo(double X, double Y) { VXmax = Math.max(VXmax, X); VYmax = Math.max(VYmax, Y); }
	
	// Hay que calcular cuando es cero. AquI se considera que existe exActamente el valor de cero
	void ObtenCero(double X, double Y)
	{ X_CERO = (X == 0) ? X : VXmin; Y_CERO = (Y == 0) ? Y : VYmin; }

	
	// Realiza la conversiOn de valores reales a valores de pixel
	// guardAndose estos en un vector de enteros
	//______________________________________________________________
	void ConvierteListaAVectorDeEnteros(double Escala_X, double Escala_Y)
	{
		Vector_X_Pixel = new int[ListaReal.size()];
		Vector_Y_Pixel = new int[ListaReal.size()];
		NODO Nodo = null;
		double Dato = 0;

		// CAlculo en pixeles de X
		//	Si es (-) = posY - LO QUE DE + CDM_X
		//	Si es (+) = posY + LO QUE DE + CDM_X
		//	Si es (0) = posY + CDM_X
		// CAlculo en pixeles de Y
                //	Si es (-) = posX + LO QUE DE + CDM_Y
		//	Si es (+) = posX - LO QUE DE + CDM_Y
		//	Si es (0) = posX + CDM_Y
		for (int k = 0; k < ListaReal.size(); k++)
		{
	                Nodo = (NODO)ListaReal.get(k);
			Dato = Nodo.X;				// ObtenciOn del valor leIdo (valor de X)
				//if (Dato >= Double.POSITIVE_INFINITY) Dato = 0;
				Vector_X_Pixel[k] = (int)(Math.abs(Dato) * Escala_X);
				if (Dato < 0) Vector_X_Pixel[k] = posY - Vector_X_Pixel[k];	// Es hacia la izquierda
                                if (Dato > 0) Vector_X_Pixel[k] = posY + Vector_X_Pixel[k];	// Es hacia la derecha
                                if (Dato == 0) Vector_X_Pixel[k] = posY;
			Dato = Nodo.Y;				// ObtenciOn del valor leIdo (valor de Y)
				//if (Dato >= Double.POSITIVE_INFINITY) Dato = 0;
				Vector_Y_Pixel[k] = (int)(Math.abs(Dato) * Escala_Y);
				if (Dato > 0) Vector_Y_Pixel[k] = posX - Vector_Y_Pixel[k];
				if (Dato < 0) Vector_Y_Pixel[k] = posX + Vector_Y_Pixel[k];
				if (Dato == 0) Vector_Y_Pixel[k] = posX;
		}
		AG.setColor(Color.yellow);						// Color de la curva
		AG.drawPolyline(Vector_X_Pixel, Vector_Y_Pixel, Vector_X_Pixel.length);	// SE GRAFICA LA FUNCION
		AG.setColor(Color.orange);						// Color del borde
		AG.draw3DRect(CDM_X, CDM_Y, ANCHO-CDM_X*2, ALTO-CDM_Y*2, true);		// Se coloca un borde
	}

	// CAlculos de la informaciOn base
	void CalcularRelacion()
	{
		// CALCULO DE LA RELACION REAL-PIXEL
		int LongXVentana = ANCHO-2*CDM_X, LongYVentana = ALTO-2*CDM_Y;		// CAlculo del espacio disponible en X y en Y
		double LongY_Real = VYmax - VYmin;					// CAlculo de la longitud real -Y-
		double LongX_Real = VXmax - VXmin;					// CAlculo de la longitud real -X-
		double Escala_Y = LongYVentana / LongY_Real;				// RelaciOn por pixel en Y
		double Escala_X = LongXVentana / LongX_Real;				// RelaciOn por pixel en X

		// Trazado del sistema cartesiano
		TrazaEjes(LongX_Real, LongY_Real,LongXVentana, LongYVentana, Escala_X, Escala_Y);
		ConvierteListaAVectorDeEnteros(Escala_X, Escala_Y);
	}

	void TrazaEjes(double LongX_Real, double LongY_Real, int XVentana, int YVentana, double Escala_X, double Escala_Y)
	{
		// CAlculo de la posiciOn del eje X
		posX=0; posY=0;
		if (VYmax >= 0 && VYmin >= 0) posX = YVentana+CDM_Y;		// ambos y's positivos
		if (VYmax <= 0 && VYmin <= 0) posX = CDM_Y;			// ambos y's negativos
		if (posX == 0) posX = (int)(VYmax * Escala_Y) + CDM_Y;		// CAlculo de los porcentajes en la posiciOn

		// CAlculo de la posiciOn del eje Y
		if (VXmax >= 0 && VXmin >= 0) posY = CDM_X;			// ambos x's positivos
		if (VXmax <= 0 && VXmin <= 0) posY = XVentana+CDM_X;		// ambos x's negativos
		if (posY == 0) posY = (int)(VXmax * Escala_X) + CDM_X;		// CAlculo de los porcentajes en la posiciOn

		AG.setColor(Color.white);					// Color de los ejes
		AG.drawLine(CDM_X, posX, ANCHO-CDM_X, posX);			// Trazo del eje X
		AG.drawLine(posY, CDM_Y, posY, ALTO-CDM_Y);			// Trazo del eje Y


		Font TipoDeLetra = new Font("Serif", Font.PLAIN, 10);		// Tipo de letra
		AG.setFont(TipoDeLetra);					// Fijar tipo de letra
		// Se muestran los valores extremos de los ejes con un mAximo de 5 caracteres
		AG.setColor(Color.yellow);
		AG.drawString((""+VXmin).substring(0, ((""+VXmin).length() < 5?(""+VXmin).length()-1:5)), CDM_X+5, posX);
		AG.drawString((""+VXmax).substring(0, ((""+VXmax).length() < 5?(""+VXmax).length()-1:5)), XVentana-CDM_X, posX);
		AG.drawString((""+VYmax).substring(0, ((""+VYmax).length() < 5?(""+VYmax).length()-1:5)), posY+5, CDM_Y+10);
		AG.drawString((""+VYmin).substring(0, ((""+VYmin).length() < 5?(""+VYmin).length()-1:5)), posY+5, YVentana+CDM_Y);
	}

	// AtenciOn al evento del ratOn
	class EventoRaton implements MouseListener
	{
		public void mouseEntered(MouseEvent e) {}	// no me interesa
		public void mouseExited(MouseEvent e) {}	// no me interesa
		public void mousePressed(MouseEvent e) {}	// no me interesa
		public void mouseReleased(MouseEvent e) {}	// no me interesa
		public void mouseClicked(MouseEvent e)
		{
			int Indice = -1;
			if (MouseEvent.BUTTON1 == e.getButton())		// click en botOn izquierdo
			{
				Pos_XY_Mouse = new Point(e.getPoint());		// Se obtiene la posiciOn del ratOn.
				Indice = Busca(Pos_XY_Mouse.x);			// Se bUsca el Indice correspondiente a ese valor X
				AG.setColor(Color.black);				// Color del fondo
				AG.fillRect(10, 465, 400, 30);				// Limpiar el Area
				AG.setColor(Color.yellow);				// Color de la fuente
				AG.drawString("X= " + ((NODO)ListaReal.get(Indice)).X, 100, 475);
				AG.drawString("Y= " + ((NODO)ListaReal.get(Indice)).Y, 100, 490);
			}
		}
	}
	
	// Se busca el Indice mAs sercano al valor X
	// ya que podrIa no existir el valor exacto de cero
	int Busca(int X)
	{
		int Indice = 0;		// valor conveniente para obtener el mAs pequeNo
		int diferencia = Math.abs(X - Vector_X_Pixel[0]);		// Diferencia mAs pequeNa 
		for (int k = 0; k < Vector_X_Pixel.length; k++)
		{
			Indice     = (Math.abs(Vector_X_Pixel[k] - X) < diferencia ? k:Indice);
			diferencia = (Math.abs(Vector_X_Pixel[k] - X) < diferencia ? Math.abs(Vector_X_Pixel[k] - X):diferencia);
		}
		return Indice;
	}
}

// Elementos 
class NODO
{ double X, Y; public NODO(double X, double Y) { this.X = X; this.Y = Y; } }