Heyyyyyyyyyyyyyyy

Aprende a programar microcontroladores en C... http://tecdigitaldelbajio.com/software-tarjeta.html

miércoles, 13 de enero de 2010

Ejemplo #16 Graficando la función seno en el celular

-->

Hoy se mostrará una aplicación practica de los arreglos, el ejemplo que se mostrará en este post tiene como objetivo graficar la función seno así que iniciemos.

La función seno

Como siempre se inicia recurriendo a la WikiPedia para conocer detalles de esta función da clic aquí para que veas el articulo de esta función. En la siguiente imagen se muestra la gráfica de la función, que a final de cuentas es lo que deseamos graficar en el celular:




Dos cosas, una la grafica en el eje de las y’s solo toma valores de 1 y de -1, y la otra, solo se graficará un ciclo completo de la función como en la figura, esto implica que se va a graficar en las x’s solo de 0 a 360 grados, esto se debe tomar en cuenta para realizar el programa.


Programa
Enseguida se da la explicación del código Java para que se muestre la grafica deseada, pero cabe mencionar que solo se muestra la parte que va en el método paint(), como crear los códigos para el proyecto ya se ha mencionado en los post anteriores a este, y creo yo, que ya no es necesario repetirlo.

Dibujando los ejes
Se inicia la gráfica dibujando los ejes coordenados, son simples dos líneas como se puede observar en la figura anterior. Para saber con exactitud el número de pixeles que tiene la pantalla del celular y además, para que el programa que se diseñe, funcione con cualquier tipo de pantalla así tenga más pixeles en una que en otra vamos a obtener el ancho y el alto en pixeles así:

ancho = getWidth();
alto = getHeight();
Obviamente que las variables que yo invente: ancho y alto, previamente se tuvieron que declarar de tipo entero. Recuerde las coordenadas que usa Java en la pantalla del celular son así: esquina superior izquierda (0,0), esquina inferior izquierda (0, alto), esquina superior derecha: (0, ancho) y esquina inferior derecha (ancho, alto)

Entonces basta con dos instrucciones que dibujan líneas para crear los ejes en color rojo así:

g.setColor(0xFF, 0x00, 0x00); // Rojo
g.drawLine(0, alto/2, ancho, alto/2); //eje x
g.drawLine(0, 0, 0, alto); //eje y

Si se ejecuta el programa así se verán los ejes así:
  

 
Bueno apenas se ve el eje de las Y que esta totalmente a la derecha, pero ahi esta, en el celular por supuesto que se ve mejor, por cierto el emulador que se está usando es el Sony Ericsson K750, cuyo ancho y alto en pixeles es de 176.

Ahora si se desea colocar letreros para denotar los ejes, se usa el método drawString, por ejemplo si se desea agregar el 1 y -1 al eje Y o si se desea agregar los grados al eje X podemos escribir así:

g.drawString("1", 4, 0, Graphics.TOP | Graphics.LEFT);
g.drawString("-1", 3, alto, Graphics.BOTTOM | Graphics.LEFT);
g.drawString("0", 4, alto/2, Graphics.TOP | Graphics.LEFT);
g.drawString("180", ancho/2-5, alto/2, Graphics.TOP | Graphics.LEFT);
g.drawString("360", ancho, alto/2, Graphics.TOP | Graphics.RIGHT);

cuyo resultado sería este:

Datos del eje X
Ahora si, vamos a realizar los cálculos de la función seno, se inicia con el eje x, esté es de lo más simple como se observa en la figura anterior, ya que son los grados que se usarán para la función seno y van desde 0 hasta 360, así que, si han pensado en un ciclo for que recorra desde 0 hasta 360, tienen toda la razón, el código sería el siguiente:

for (i=0; i<=360; i++ ) {

}
Lo que seguiría sería declarar un arreglo de 360 posiciones para que almacene cada uno de los números para posteriormente graficarlos, el arreglo, entonces almacenaría los números 0, 1, 2, 3…. 360, pero justo en este punto se ve un pequeño problema: Yo quiero graficar hasta 360 y el emulador del teléfono celular solo tiene en ancho 176 pixeles como ya lo mencioné, esté es un problema grave, porque un ciclo completo de la función seno va exactamente de 0 a 360 grados, si yo grafico la función está se vería así:


Casi se observa un semi-ciclo de la función, casi se grafica de 0 a 180 grados, esto porque solo se tienen 176 pixeles de ancho en el emulador, ahora si ya se ve el problema ¿verdad? Yo quiero que se grafique todo el ciclo de la función seno, pero no tengo los pixeles suficientes para ello.


La solución es bien simple, se hace un ajuste de lo más sencillo usando la llamada “regla de tres” es decir: “si 360 grados equivalen a 176 pixeles entonces cada grado equivale a X pixeles” al go parecido a esto:
360 -  176
1 grado - x
El resultado para 1 grado queda así:

x = ( 1 * 176) / 360 = 0.488888 pixeles
Entonces cada grado equivale a 0.4888 pixeles, algo que no es del todo practico por que los pixeles son números enteros, aún así esta aproximación es suficiente para mostrar la gráfica de la función seno como se verá un poco más adelante.

Basta con agregar la ecuación anterior al ciclo for mencionado arriba, para obtener en términos de pixeles cada uno de los 360 grados, por otro lado, cada uno de los grados (convertidos ahora en pixeles) se almacenaran en un arreglo de números enteros, entonces la ecuación en términos de las variables que se están manejando para el programa y dentro del ciclo for es la siguiente:

for (i=0; i<=360; i++ ) {
    x[i] = (ancho * i ) / 360; //datos del eje X
}
El arreglo se declara de tipo entero, es llamado “x” y obviamente es de 360 posiciones. Pero vea la ecuación, es una división por lo que, como se vio, genera un número decimal, entonces pareciera que es un error, que se asigne un resultado decimal a un arreglo de enteros, pero no lo es del todo (al menos no en este ejemplo), se aprovecha la propiedad de Java de que, una división de números enteros se puede asignar a una variable de tipo entero perdiendo los decimales, esto debe sonar lógico puesto que lo que se desean son pixeles por que para trazar las líneas que dibujen la función seno se requieren números enteros solamente. Bueno espero me haya explicado.

Datos del eje Y
El eje Y contiene los valores de la función seno, recuerde la ecuación es así:

Y = sin x
Donde “x” son los grados, que en este punto ya están en el arreglo llamado x. Pero veamos que dice la documentación de Java acerca de la función seno (insisto, si no se ve bien da clic en la imagen para verla mejor):

Dos cosas se pueden ver de la documentación, una el ángulo debe estar en radianes y no en grados como se venía manejando y la otra, tanto el ángulo como el resultado deben ser de tipo double.


El primer punto se resuelve fácil convirtiendo cada uno de los 360 grados a radianes, esto se hace fácilmente con la función llamada “toRadians” que está en la clase Math, la función la puedes ver en la documentación de java, no la voy a mostrar pero ahí puedes verla, entonces una sentencia como la siguiente me convierte cada grado en radianes:

angRad = Math.toRadians(i);
Previamente se debe declarar la variable “angRad” de tipo double, con lo anterior se tiene el ángulo listo para la función seno, ahora solo se aplica la función y se asigna a un arreglo para formar los valores para el eje “y”, esto se hace así:

yt[i] = Math.sin(angRad);
El arreglo es llamado “yt” y debe ser declarado de tipo “double” para evitar pérdidas de decimales, y más en este punto puesto que el valor de la función seno es entre 1 y -1. Justo aquí tenemos un nuevo problema, el valor es entre 1 y -1, esto en términos de pixeles es nada, absolutamente nada, pero esto se resuelve bien fácil, una simple multiplicación puede “amplificar” la función de una forma proporcional, por ejemplo si se multiplica la función por 10 así:

yt[i] = 10 * Math.sin(angRad);
entonces “yt” almacenará valores de la función seno, ahora entre 10 y -10, el valor exacto para que la forma de onda se múltiplique y quede proporcionalmente a la pantalla del celular es: alto/2, entonces la ecuación final para “yt” es:

yt[i] = (alto/2) * Math.sin(angRad);
El ciclo for para los dos ejes queda así:

for (i=0; i<=360; i++ ) {
    x[i] = (ancho * i ) / 360; //datos del eje X
    angRad = Math.toRadians(i); //grados a radianes
    yt[i] = (alto/2) * Math.sin(angRad); //datos del eje Y
}
Je je je , no me lo van a creer pero tenemos un nuevo problema, este igual de grave que los otros, con el ciclo anterior tendríamos los valores exactos del eje de las Y ¡¡pero estos valores son negativos¡¡¡ y me servirían a mi para graficar manualmente la función seno, con valores positivos y negativos pero a Java no le sirven por que las coordenadas de la pantalla del celular son positivas siempre. Vaya lio ¿verdad?.

La solución después de analizar un rato el problema es desplazar cada punto del arreglo “yt” cierta cantidad “hacia abajo” (recuerde que las coordenadas de java crecen hacia abajo), para ser exacto se desplaza en pixeles lo equivalente al valor de la variable alto/2, está es la ecuación exacta que me permite hacer lo que menciono:

y[i]=Math.abs(yt[i] - alto/2);
El desplazamiento se hace con una simple resta, la resta genera números negativos, para evitarlo se obtiene el valor absoluto de la resta con lo que se tendría ahora si puros valores positivos y estos valores no me la van a creer pero están ya en coordenadas de Java, listos para su graficación, cada valor se almacena en el arreglo de tipo entero llamado “y”, para este caso se debe agregar un conversor de tipo, puesto que la función del valor absoluto regresa un valor double, el conversor de tipo se agrega entre paréntesis así:

y[i]= (int) Math.abs(yt[i] - alto/2);
el (int) obliga a que el resultado se cambie a entero y se asigne al arreglo de enteros “y”, el código para el ciclo for queda entonces así:

for (i=0; i<=360; i++ ) {
    x[i] = (ancho * i ) / 360; //datos del eje X
    angRad = Math.toRadians(i); //grados a radianes
    yt[i] = (alto/2) * Math.sin(angRad); //datos del eje Y
    y[i]= (int) Math.abs(yt[i] - alto/2);
}
Es posible eliminar el arreglo “yt” del ciclo, y declarar la variable de tipo double, puesto que este arreglo no se va a usar más, así que el código final para el ciclo for (ahora si es el código final se los prometo) queda así:

for (i=0; i<=360; i++ ) {
   x[i] = (ancho * i ) / 360; //datos del eje X
   angRad = Math.toRadians(i); //grados a radianes
   yt = (alto/2) * Math.sin(angRad); //datos del eje Y
   y[i]= (int) Math.abs(yt - alto/2);
}

Graficando la función
Para terminar el post, solo queda graficar los 360 puntos, puesto que ahora si los arreglos “y” y “x” tienen almacenadas las coordenadas y estas cooordenadas ya están en el mundo de java, la grafica se crea trazando pequeñas líneas de una coordenada a otra. Por ejemplo se traza una línea de la coordenada (x[0], y[0]) a la coordenada (x[1], y[1]), la siguiente línea sería de la coordenada (x[1], y[1]) a la coordenada (x[2], y[2]) y así sucesivamente, hasta terminar con la los 360 puntos.

Obviamente esto se realiza con un ciclo for de la siguiente manera:

for (i=0; i<=359; i++ ) {
    g.drawLine(x[i], y [i], x[i+1], y[i+1]);
}

El ciclo va de 0 a 359 ¿Por qué será? Y solo se requirió una simple instrucción que hace uso del método drawLine y listo, el resultado lo puedes ver en la siguiente imagen:

-->

Guau, si quedo bien ¿verdad? Ya para terminar agrego el video tutorial  para este ejemplo, no se muestra la creación de la clase para el Midlet, ni la clase que proviene de la clase Canvas, esto ya ha sido analizado en los post anteriores, por eso ya no lo inclui en el video.


Por si fuera poco anexo el código fuente, es la carpeta completita que genera Netbeans, esta en formato RAR da clic aqui para bajarlo, este realizada con el NetBeans 6.8, si no deseas el código fuente dando clic aqui puedes bajar el archivo JAR para que se lo envies via Bluetooth o USB a tu celualar, si soporta java verás la gráfica del seno sin lugar a dudas, yo lo probe en mi Sony Ericsson W595 y el resultado fue exactamente el mismo que el del emulador.
-->

18 comentarios:

  1. Muy bueno he aprendido mucho con tus claases, tengo una consulta, me he encontrado con la posibilidad de saber que tipo de sensores tiene los celulares, con el mobile sensor api, podrias explicar como poderlo utilizar en netbeans? sobre todo el acelerometro que internamente tiene algunos celulares y algunos con sensores termios, como poder visualizar esa informacion tomada por stos sensores en una pantalla?

    de ante mano muchas gracias

    atte

    cristian desde chile

    ResponderEliminar
  2. Hola saludos pues felicitarlo en primer lugar excelente la pagina gracias a sus tutoriales estoy aprendiendo mucho pues nada mas que admirarlo y agradecerle por compartir su conocimiento. Le agradeceria si hace unos topicos sobre bluetooth siga adelante suerte. Jimy

    ResponderEliminar
  3. Hola que bueno que les ha servido el blog, si se tienen muchos planes para el blog, como son lo del Bluetooth y lo de utilizar sensores, pero son temas complejos, y el blog todavia lo tengo enfocado para principiantes, mil disculpas...

    Saludos

    ResponderEliminar
  4. Hola: primer lugar saludarlo y felicitarlo por la excelente la pagina, gracias a sus tutoriales estoy aprendiendo mucho y agradecer por compartir su conocimiento. Le agradecería si hace unos tópicos sobre la obtención de datos en el celular y enviarlos través de sms o email.
    Siga adelante.
    Antonio desde Argentina

    ResponderEliminar
  5. Hola.. Quería hacer una consulta como puedo saber si una variable existe? lo necesito para un pequeño formulario que estoy haciendo con netbeasn la cosa es así,, tengo un "arreglo" lo llaman
    int correctas[]{20,30} y los valores del array los cambio osea puedo colocar [0,3,3] luego necesito hacer un if que dependiendo si correctas[3]existe haga algo... espero que haya quedado clara mi duda..

    desde ya gracias

    Pd..estoy esperando el tuto de choicegrup multiples....

    ResponderEliminar
  6. Gracias por tus tutoriales... tengo una consulta.. como se podría reproducir un archivo midi durante la ejecucion de todo el programa para celular..
    desde ya gracias

    ResponderEliminar
  7. Hola... soy un programador promeriso en java ME, y tengun una duda, espero que me la pueda resolver.

    quiero hacer un programa que pueda hacer llamadas y terminarlas en un tiempo determinado...

    como puedo hacer esto...
    por su atencion gracias :):):):):)

    ResponderEliminar
  8. Hola
    dejeme felicitarle por este gran trabajo que esta haciendo, siga asi.

    Me interesa mucho el desarrollo para aplicaciones moviles con j2me y estuve buscando un ejemplo de como leer un archivo .txt y mostrarlo en un tableitem.

    si me puedes ayudar te agradezco de antemano

    ResponderEliminar
  9. Hola buena noche, esta muy interesante tu pagina, me ha ayudado bastante a aprender programacion pero quisiera cinsultarte lo siguiente:
    el problema que tengo es que quiero sumar a una fecha 55 dias y no he podido hacerlo, ya llevo como 6 meses intentando porque para programacion en j2me no puedo utilizar el cal.add(Calendar.DATE, 55);y se me ha complicado demasiado y por lo que he podido ver eres todo un guro en programacion, por lo que te pido me ayudes con mi programita, de antemano gracias, te dejo mi mail para cualquier comentario juanfcqi@hotmail.com

    ResponderEliminar
  10. Saludos a todos,tengo una duda en relacion a como poder insertar un gif animator en netbeans o una simulacion flash. parece que no se puede , incluso he intentado con los archivos *svg pero tampo puedo insertar una animacion en netbeans.. como se podra????

    Atte


    Cristian desde chile

    ResponderEliminar
  11. Hola maestro q tal, tengo una duda...

    Como puedo hacer para q al ingresar un numero no tenga q oprimir el boton del cel hasta q el numero aparesca?

    por ejemplo si quiero el 5 presione el boton 5 y me aparesca el 5 sin q tenga q presionarlo 3 veces (1ra->j;2da->k;3ra->l) y que a la cuarta me salga recien el 5...

    ojala me puedas ayudar... Gracias

    ResponderEliminar
  12. hola, que tal. tengo un problemilla, estoy muy interesado en hacer un reproductor mp3 para mi cel pero no logro rteproducir mp3 mayores a 1.8 megas porque me sale un error de memoria. si tienes tiempo y conoces del tema agradeceria mucho que publicaras una aplicacion simple que reprodusca un mp3 como una cancion que pese dentro de 5 megas a 10 megas. yo utiliso este codigo para reproducir mp3.

    try {

    InputStream is = getClass().getResourceAsStream("mi mp3.mp3");
    musicPlayer = Manager.createPlayer(is, "audio/mpeg");
    musicPlayer.prefetch();
    musicPlayer.setLoopCount(-1);

    musicPlayer.start();


    }
    catch (IOException ioe) {
    }
    catch (MediaException me) {
    }

    pero solo funciona con mp3 menores de 1.8 megas.

    espero me puedas ayudar saludos...

    ResponderEliminar
  13. Hola que tal sabes que me estoy recien iniciando en esto.

    Te cuento estudio analisis de sistemas y por si no se noto estoy medio complicado.... y me dieron un trabajo el cual consiste en lo sgte:

    cree un midlet que permita realizar los siguientes calculos

    A- Eleccion de usuario.

    indice masa corporal
    porcentaje de grasa
    peso muscular
    peso oseo.

    si me pueden ayudar seria ideal...
    agradeciendo tu tiempo... Gracias

    ResponderEliminar
  14. hola que tal amigo, sabes como usar el senson de movimiento como para el w710. o otros celulares que lo traigan como para crear una aplicacion java que cuente los pasos??

    ResponderEliminar
  15. Very good tutorials..but your source destination is not working..
    you think you can do something about that..

    ResponderEliminar
    Respuestas
    1. Ya esta arreglado, ya puedes bajar el codigo fuente.. saludos

      Eliminar
  16. muy buen blog eh.. muchisisisisisisisismas gracias!.. ayuda mucho.. felicidades

    ResponderEliminar