Lexico
...el poder de lo simple...
Marzo.4.2010
Cómo graficar una curva ?

Para dibujar una curva expresada por una ecuación algebraica en un espacio bidimensional o plano de coordenadas cartesianas deben generarse valores para una de las variables y con base en ellos calcular los valores de la otra variable.

Así por ejemplo, si se tiene una función de la forma general
        y = f(x)
se generan valores para la variable independiente x y ellos se aplican a la función f para encontrar los valores correspondientes de la variable dependiente y 

Luego el grupo de pares ordenados (x, y) o puntos se unen mediante segmentos de rectas entre ellos formando un trazo visible.

Debe tenerse en cuenta que los pares de valores generados no necesariamente están en el rango de pixeles referenciables en una ventana del computador por lo que usualmente deben ser normalizados, es decir deben ser adecuados para ser contenidos en el espacio visible disponible. Ésto se logra estableciendo proporción entre entre los rangos de los valores generados y los rangos de los pixeles disponibles y luego aplicacándola a cada par de manera que se conserven las relaciones geométricas entre los puntos.

Llámense:
Xmin:    El valor menor de las x generadas
Xmax:   El valor mayor de las x generadas
Ymin:    El valor menor de las y generadas
Ymax:   El valor mayor de las y generadas

XPmax:    El valor del pixel extremo-izquierdo disponible para la gráfica
XPmax:   El valor del pixel extremo-derecho disponible para la gráfica
YPmin:    El valor del pixel extremo-superior disponible para la gráfica
YPmax:   El valor del pixel extremo-inferior disponible para la gráfica

Ahora es claro que deben formarse equivalencias entre los espacios generados y disponibles:

el rango Xmax-Xmin generado debe dibujarse en el rango XPmax-XPmin    y
el rango Ymax-Ymin generado debe dibujarse en el rango YPmax-YPmin

Los demás datos generados deben ubicarse proporcionalmente para conservar su relación geométrica.

Las proporciones px y py serán calculadas como:

XPmax-XPmin
--------------- = px
Xmax-Xmin

y


YPmax-YPmin
---------------- = py
Ymax-Ymin

La aplicación de esas proporciones harán que:

XPmax-XPmin = px (Xmax-Xmin)

YPmax-YPmin = py (Ymax-Ymin)

Por lo que
cada valor generado x afectado por la proporción px dará el valor en pixeles
cada valor generado y afectado por la proporción py dará el valor en pixeles

El algoritmo consistirá en:

1. Pedir el rango de las x que interesa Xmax, Xmin y la cantidad de puntos deseados
2. Generar cada punto:
    2a. Generar x en el rango dado
    2b. Generar y correspondiente
3. Pedir los extremos del espacio donde se desea dibujar XPmax, XPmin, YPmax,YPmin
4. Calcular las proporciones px y py
5. Normalizar los puntos: Transformar los pares (x, y) en (x*px, y*py)
6. Dibujar segmentos de línea recta entre los puntos

Nótese que los pasos 2 y 5 significan hacer la operación para todos los puntos, lo que en programación se logra mediante ciclos de repetición de las mismas operaciones con valores distintos. Además pueden ser unificados los dos tratamientos en un mismo ciclo dado que ámbos hacen el mismo recorrido. Sintetizando y reorganizando los pasos el algoritmo quedaría así:

1. Pedir el rango de las x que interesa Xmax, Xmin y la cantidad de puntos deseados Npuntos
3. Pedir los extremos del espacio donde se desea dibujar XPmax, XPmin, YPmax,YPmin
4. Calcular las proporciones px y py

2. En cada punto:
    2a. Generar x en el rango dado
    2b. Generar y correspondiente
    5. Normalizar los puntos: Transformar los pares (x, y) en (x*px, y*py)
    6. Dibujar segmentos de línea recta entre los puntos

Que en limpio queda asÍ:

1. Pedir el rango de las x que interesa Xmax, Xmin y la cantidad de puntos deseados
2. Pedir los extremos del espacio donde se desea dibujar XPmax, XPmin, YPmax,YPmin
3. Calcular las proporciones px y py

4. En cada punto:
    4a. Generar x en el rango dado
    4b. Generar y correspondiente
    4c. Normalizar los puntos: Transformar los pares (x, y) en (x*px, y*py)
    4d. Dibujar segmentos de línea recta entre los puntos

Surge una pregunta
....y cómo generar los diversos valores para la variable x ?

Una forma es generarlos monotonicamente (monótonamente espaciados en el rango [XPmin, XPmax]) pues se conoce el rago de las x y la cantidad de puntos deseados por lo que es fácil calcular el tamaño del paso (distancia o delta de las x) entre las diversos valores de la x:

       XPmax - XPmin
dx = ------------------
            Npuntos

Si la variable x parte del valor inferiror Xmin se le pueden ir agregando deltas dx y en Npuntos pasos llegará al valor XPmax

El algoritmo, ahora ya detallado quedaría así:

1. Pedir el rango de las x que interesa Xmax, Xmin y la cantidad de puntos deseados Npuntos
2. Pedir los extremos del espacio donde se desea dibujar XPmax, XPmin, YPmax,YPmin
3. Calcular las proporciones px y py
4. Calcular paso o incrementos de la x: dx
5. Iniciar la variable x en Xmin
6. En cada punto:
    6a. Generar x en el rango dado, es decir incrementar la variable x en dx
    6b. Generar y correspondiente
    6c. Normalizar los puntos: Transformar los pares (x, y) en (x*px, y*py)
    6d. Dibujar segmentos de línea recta entre los puntos

Dicho lo anterior utilizando el lenguaje Lexico sería algo como:

tarea
{
/*Se separa espacio en la RAM para las variables*/
los objetos Xmax, Xmin, Ymax, Ymin, XPmax, XPmin, YPmax,YPmin, x, y, px, py, dx, Npuntos, xo son cantidades

/*Se piden 9 datos por el teclado*/
entre Xmin, Xmax, Ymin, Ymax, XPmin, XPmax, YPmin, YPmax, Npuntos

/*Se calculan las proporciones y el delta para las x*/
copie (XPmax-XPmin)/(Xmax-Xmin) en  px
copie (YPmax-YPmin)/(Ymax-Ymin) en  py
copie (XPmax - XPmin)/Npuntos en dx

/*Se inicia la variable  en Xmin*/
copie Xmin en x

/*Se ordena repetir una secuencia de instrucciones condicionada por la expresión lógica*/
mientras x  < Xmax haga:
    {
    copie x + dx en x, xo    /* Genera nuevo valor en x y también guarda una copia en xo */
    copie f(x) en y               /* Genera el correspondiente valor en y. REEMPLAZAR f(x) por el caso particular */
    copie xo * px en xo      /* Transforma el valor de x a la escala de las x en pixeles */
    copie   y * py en y        /* Transforma el valor de y a la escala de las y en pixeles */
    muestre  xo, y               /* Se muestran los valores de xoy en  la escala de pixeles */
    }

muestre "Ya se generaron los valores pero aún no se dibujan"
}

Obsérvese que se usa una variable auxiliar xo con el fin de transformar solo la copia (copie xo * px en xo) y preservar los valores sin transformación de x pues éstos son la base de la generación de los próximos. Si no se hiciera así los valores x transformados influirían en los sin transformar con una instrucción como copie  xpx en x. Los pares ordenados o puntos base para la gráfica serán los valores existentes cada vez en las variables (xo, y)

Cómo dibujar los segmentos de línea recta entre la sucesión de puntos o pares de valores existentes cada vez en (xo, y) ?

Se presentarán dos formas:
 
La primera más simple (pero más restrictiva) utiliza una clase llamada Graficador que previamente se ha programado, se ha almacenado y compilado para formar el archivo riosur30.dll el cual debe ser referenciado mediante la instrucción incluya al principio del código para que el compilador busque allí los recursos solicitados. Ella tiene definidos varios recursos que simplifican  la programación.

La segunda, menos intuitiva, exige más conocimientos respecto a la plataforma .NET pero es más general pues utiliza directamente los recursos que se usaron para crear la clase Graficador usada en la primera forma.

Primera forma:

La clase Graficador que existe en el archivo riosur30.dll tiene definidos entre sus atributos y comportamientos (ver éste documento) los siguientes:

Atributos que tienen los objetos que se construyan con ésta clase:
:
:
:
Comportamientos, métodos, algoritmos o mensajes que "entienden" los objetos que se construyan con ésta clase:
Graficador: Método constructor (algoritmo que al llamarse construye el objeto en la RAM).
DibujeTrazo( , ): Dibuja un trazo con base en dos objetos dados de la clase ArrayList. El primero debe contener las absisas o Xs y el segundo las ordenadas o Ys.
Muéstrese: Despliega la gráfica en una ventana.
:

Entonces se puede:
1. Crear un objeto:
el objeto g es un Graficador

2. Ordenarle al objeto g que DibujeTrazo dándole dos objetos de tipo ArrayList que contengan las Xs y las Ys.
3. Ordenarle al objeto g que despliegue la gráfica: Muéstrese

Para cumplir con el ítem 2 deben crearse dos ArrayList y llevar a ellos mediante el mensaje Add los sucesivos valores Xs y Ys calculados:

los objetos GrupoX, GrupoY son ArrayList
Cada vez que se genere un par XY se agregan a los ArrayList con GrupoX y GrupoY utilizando el mensaje Add:
GrupoX.Add(X)
GrupoY.Add(Y)

Todo junto quedaría así:

incluya "riosur30.dll"

tarea
{
/*Se separa espacio en la RAM para las variables*/
los objetos Xmax, Xmin, Ymax, Ymin, XPmax, XPmin, YPmax,YPmin, x, y, px, py, dx, Npuntos, xo son cantidades
los objetos GrupoX, GrupoY son ArrayList
el objeto g es un ENriosur30.Graficador

/*Se piden 9 datos por el teclado*/
entre Xmin, Xmax, Ymin, Ymax, XPmin, XPmax, YPmin, YPmax, Npuntos

/*Se calculan las proporciones y el delta para las x*/
copie (XPmax-XPmin)/(Xmax-Xmin) en  px
copie (YPmax-YPmin)/(Ymax-Ymin) en  py
copie (XPmax - XPmin)/Npuntos en dx

/*Se inicia la variable  en Xmin*/
copie Xmin en x

/*Se ordena repetir una secuencia de instrucciones condicionada por la expresión lógica*/
mientras x  < Xmax haga:
    {
    copie x + dx en x, xo    /* Genera nuevo valor en x y también guarda una copia en xo */
    copie f(x) en y               /* Genera el correspondiente valor en y. REEMPLAZAR f(x) por el caso particular */
    copie xo * px en xo      /* Transforma el valor de x a la escala de las x en pixeles */
    copie   y * py en y        /* Transforma el valor de y a la escala de las y en pixeles */
    GrupoX.Add(xo)
    GrupoY.Add(y)
    }

g.DibujeTrazo (doy GrupoX, doy GrupoY)
g.Muéstrese
muestre "Ya se generaron los valores y se dibujó la gráfica"
}


Segunda forma

Ésta versión, a diferencia de la anterior, no utiliza riosur30.dll sino directamente las clases de la plataforma .NET.

Para dibujar un segmento de línea se necesita el punto origen y el punto destino o sea que cada vez se requieren dos pares ordenados de valores, es decir los dos puntos extremos del segmento. La dificultad reside en que en la ejecución de la secuencia definida dentro del ciclo cada vez el par (xo, y) se renueva y se pierden los dos valores anteriores. Ésto impone la necesidad de tener otro par de variables (xant, yant) para conservar el par de valores previo y que una vez utilizados se renueven con los actuales que serán los futuros anteriores. También han de iniciarse en los comienzos de los rangos de pixeles a utilizar.

Para dibujar se requiere una ventana, formulario o Form donde se desplegará el contenido de un área, zona de la RAM para graficar o Graphics y algunas herramientas como un lápiz o Pen de un Color determinado. A algunos de esos objetos han de enviarse mensajes apropiados tales como Show (para desplegar la ventana),......:

(en proceso oct.20.2009):
tarea
{
/*Se separa espacio en la RAM para las variables*/
los objetos Xmax, Xmin, Ymax, Ymin, XPmax, XPmin, YPmax,YPmin, x, y, px, py, dx, xant, yant, Npuntos, xo son cantidades

/*Se piden 9 datos por el teclado*/
entre Xmin, Xmax, Ymin, Ymax, XPmin, XPmax, YPmin, YPmax, Npuntos

/*Se calculan las proporciones y el delta para las x*/
copie (XPmax-XPmin)/(Xmax-Xmin) en  px
copie (YPmax-YPmin)/(Ymax-Ymin) en  py
copie (XPmax - XPmin)/Npuntos en dx

/*Se inicia la variable  en Xmin*/
copie Xmin en x, xant
copie Ymin en yant

/*Se ordena repetir una secuencia de instrucciones condicionada por la expresión lógica*/
mientras x  < Xmax haga:
    {
    copie x + dx en x, xo    /* Genera nuevo valor en x y también guarda una copia en xo */
    copie f(x) en y               /* Genera el correspondiente valor en y. REEMPLAZAR f(x) por el caso particular */
    copie xo * px en xo      /* Transforma el valor de x a la escala de las x en pixeles */
    copie   y * py en y        /* Transforma el valor de y a la escala de las y en pixeles */
    }

muestre "Ya se generaron los valores pero aún no se dibujan"
}