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; } }