Ejemplos java y C/linux

Tutoriales

Enlaces

Licencia

Creative Commons License
Esta obra está bajo una licencia de Creative Commons.
Para reconocer la autoría debes poner el enlace http://www.chuidiang.org

Transformación de Coordenadas gráficas a Pixels

Suele ser habitual querer hacer un gráfico en una zona de pantalla. Lo normal es que los puntos de nuestro gráfico tengas unas unidades o rangos de valores propias, mientras que las unidades en la zona de pantalla son los pixels.

Por ejemplo, queremos pintar una función y = sin (x). La x va desde 0 hasta 2*PI, mientras que la y varía de -1 a 1. La zona de pantalla en la que queremos dibujar eso puede ocupar, por ejemplo, 300 pixels de ancho y 200 de alto. La coordenada superior izquierda de esa zona suele ser la 0,0. Vamos, que tenemos lo del siguiente gráfico.

grafico seno con coordenadas en pixels y naturales

El sentido de las flechas indica hacia que lado crecen las y. Es decir,en la zona de pixels, según se va haciendo la y más grande, nos vamos hacia abajo en el dibujo, mientras que en el gráfico de la función según se hace más grande la y, vamos hacia arriba.

Matemáticas para transformar las coordenadas

Veamos cuales son las cuentas que hay que hacer para poder pintar nuestra función en la zona de pantalla y que quede bien. Si no tienes ganas de seguir las cuentas, al final hay una clase en C++ que las hecha por tí. Sólo tienes que descargarla e incluirla en tus proyectos.
 

El eje de las x

En nuestro caso tenemos una x que va desde 0 hasta 2*PI y queremos transformala en algo que va entre 0 y 300. Para que las cuentas sean más generales, vamos a un caso más general. Supongamos que la x de nuestro gráfico va entre Xmin y Xmax (0 y 2*PI en nuestro caso) y que queremos transformalo en algo que va entre 0 y Ancho (Ancho es el ancho en pixels de nuestra zona de dibujo, 300 en nuestro caso).

Lo primero que hay que hacer es que nuestro rango [Xmin, Xmax] se transfome en un rango desde 0 hasta otro valor (el que sea). Esto se consigue si al valor de x le restamos Xmin. Haciendo esta resta, la Xmin quedaría 0, mientras que en el caso de Xmax quedaría Xmax-Xmin. Los valores intermedios se moverán de acuerdo a esto. El rango queda ahora entonces entre [0, Xmax-Xmin] y la x concreta que queramos dibujar quedará como

x = x - Xmin;

Ahora podemos transformar nuestro rango a un rango entre 0 y 1. Para ello basta dividir la x entre (Xmax-Xmin). Si en el rango [0,Xmax-Xmin] dividimos ambos números entre (Xmax-Xmin) quedará [0,1] y una x concreta, quedaría como

x = (x-Xmin) / (Xmax-Xmin);

Ahora podemos transformar nuestro rango entre [0,1] en un rango justo en nuestra zona de dibujo, es decir, entre 0 y Ancho. Para ello, si multiplicamos por Ancho el 0 y el 1, nuestro rango quedará [0, Ancho]. Una x concreta que queramos dibujar, quedará como

x =  (x-Xmin) / (Xmax-Xmin) * Ancho;

Ya tenemos lo que qeríamos. Hemos transformado una x que va de Xmin a Xmax en una x que va de 0 a Ancho. Este valor obtenido se puede dibujar directamente en nuestra zona de pantalla.
 

El eje de las y

El eje de las y sería exactamente igual, si no fuera porque en ambos gráficos (el de verdad y el de pixels) la y crece en sentido contrario. Si aplicamos la misma cuenta

y = (y-Ymin) / (Ymax-Ymin) * Alto;

tenemos una y que va de 0 a Alto, pero si la dibujamos tal cual, nuestro gráfico quedará invertido, ya que los pixels crecen hacia abajo. La solución está en restar esta y de Alto

y = Alto - (y-Ymin) / (Ymax-Ymin) * Alto;

¿Qué hemos hecho con esto?. Cuando queremos dibujar una y = 0, nos queda como Alto - 0 = Alto, es decir, se dibuja en la parte de abajo de nuestra zona de pixels. Si queremos dibujar una y = Alto, nos queda como Alto - Alto = 0, es decir, se dibuja en la parte alta de nuestra zona gráfica. Todo arreglado

El resto ya no está metido en la clase de C++ que hay al final, pero se podría meter sin mucho esfuerzo. Lo siento, he sido vago para hacerlo yo mismo.
 

Si las coordenadas de la esquina superior izquierda de la zona en pantalla no son 0,0

Supongamos que no queremos ajustar nuestro gráfico justo hasta los bordes de la zona de dibujo. Imaginemos que queremos dejar un márgen de pixels por los cuatro lados, por ejemplo, para poner unos valores, unas etiquetas o lo que sea.

En este caso, nuestro Alto y Ancho serían el Alto y Ancho del área en la que queremos dibujar, es decir, el Alto y Ancho del área total de dibujo menos los márgenes que queramos mantener. Es decir

Alto = Alto - margenSuperior - margenInferior;
Ancho = Ancho - margenIzquierdo - margenDerecho;

Si nuestros márgenes izquierdo y superior son margenIzquierdo e margenSuperior, bastará con sumar estos valores a las transformaciones anteriores.

x = margenIzquierdo + (x-Xmin) / (Xmax-Xmin) * Ancho;
y = margenDerecho + Alto - (y-Ymin) / (Ymax-Ymin) * Alto;

Hacer mas eficientes las cuentas

Si vamos a pintar muchos puntos, vamos a calcular muchas veces estos factores

.. / (Xmax-Xmin) * Ancho
.. / (Ymax-Ymin) * Alto

que aparecen en las cuentas anteriores y que son valores fijos para todos los puntos de nuestro dibujo. Por eficiencia, sobre todo si tenemos muchos que dibujar, conviene guardarse el resultado en una variable y utilizar dicha variable directamente. Ahorramos unas restas y divisiones por cada punto que tengamos que dibujar.

En resumen

Antes de dibujar una x y una y debemos hacer las siguientes cuentas

Xpixels = (x-Xmin) / (Xmax-Xmin) * Ancho;
Ypixels = Alto - (y-Ymin) / (Ymax-Ymin) * Alto;


Una clase que hace todo esto

EscalaC.h y EscalaC.cc es una clase C++ que ayuda a hacer estas cuentas. Te los puedes descargar, quitarles la extensión .txt y usarlos en tus proyectos. Únicamente hay que instanciar la clase, pasarle con tomaExtremos() los valores máximos y mínimos de x e y, pasarle con tomaAreaGrafica() el ancho y alto de tu zona de dibujo. Luego puedes llarmar al dameX() o dameY() para obtener el valor de los pixels a dibujar a partir de un x,y de tu gráfico.

En Seno tienes un ejemplo de cómo se utiliza para X11 y linux.

Estadísticas y comentarios

Numero de visitas desde el 4 Feb 2007: