miércoles, 25 de enero de 2012

Un poco de software (I)


Pantalla del programa ControlZ en un ordenador de 1280 x 1024 pixels de resolución de pantalla.
Como saben mis lectores, en este blog voy publicando todos los avances que realizo en la construcción de mi maqueta. También voy explicando en los distintos artículos cómo y porqué voy haciendo cada cosa, y publico fotografías planos y esquemas de trazados de vía, esquemas eléctricos, etc. No sólo eso, sino que en las páginas de Descargas, a las que se accede desde el menú de la cabecera, publico esquemas eléctricos, plantillas de PCB, listas de material, y en definitiva todo cuanto se necesita para que si alguien quiere seguir mis pasos, pueda hacerlo.

Debo dejar claro, sin embargo que éste es un sistema absolutamente original, y distinto del sistema que se ha impuesto de forma absolutamente global. Me refiero, claro está al sistema digital, asi que el que quiera meterse por mi camino sabe que no va a encontrar prácticamente ningún producto comercial que venga en su ayuda, de forma que, como yo, tendrá que hacerse todo el hardware de forma artesanal.

Pero seguramente, con ser eso un problema, no es el mayor, porque realmente los elementos de hardware son bastante sencillos, y para el sistema de comunicaciones he podido utilizar una placa de comunicaciones comercial.

Sin embargo, apenas he comentado nada acerca del software que he desarrollado para mi proyecto, y que se materializa en el programa que he denominado "ControlZ".  En mi último artículo me referí de nuevo a él, comentando que había podido ponerlo en marcha en un nuevo ordenador (más bien un mini ordenador) y en un nuevo sistema operativo (Windows 7). Así que ahora que estoy de nuevo metido en harina con el software, es una buena oportunidad para hablar de este tema.

Lo primero que hay que decir, es que el programa está incompleto, tan incompleto como el resto del proyecto, porque todo va avanzando en paralelo.

Sin embargo, en algunas ocasiones, se han dirigido a mi algunos lectores pidiéndome que les explique cómo, o les ayude a realizar un programa similar para sus maquetas. En todos los casos he contestado a esas demandas con explicaciones o incluso aportando piezas de software, pero tengo la sensación de que a ninguno de esos demandantes les han servido de mucho mis respuestas.

Y es que parece que estos comunicantes esperaban algún procedimiento maravilloso para dibujar un desvío en la pantalla, desvío que cambia de posición al pulsar con el ratón sobre él, o para dibujar un semáforo cuyas luces cambian de verde a rojo, o un desenganchador que parece que se levanta al pulsar sobre el mismo y no digamos ya, si de lo que se trata es de dibujar un velócímetro, cuya aguja se mueve por la escala indicando la velocidad en cada momento de la locomotora, o de dibujar una rotonda cuyo puente hacemos girar con el ratón  y que como consecuencia hace que la rotoda de la maqueta se mueva.(ver: Rotondas digitales). Todo ello, como decía aquél, es "more transpìration than inspiration". Quiero decir que conseguir eso, es complicado, y requiere bastante experiencia en programación, y concretamente en programación de gráficos.  Se da la circunstancia de que la programación ha sido mi actividad profesional durante muchos años, así que estaba dentro de mi alcance el abordar este tipo de software, pero precisamente en esa actividad profesional he podido comprobar como muchos programadores expertos patinan clamorosamente, cuando se enfrentan a ese tipo de programación.

Tomemos como ejemplo  el conseguir que la aguja del velocímetro se mueva por la escala. Para ello hay que aplicar unos cuantos conceptos de trigonometría. Si se tienen, es fácil dibujar esa aguja móvil, pero si no se tienen, por mucha experiencia de programación que se tenga, no se será capaz de hacerlo.

Concretamente: las siguientes siete instrucciones de Visual Basic dibujan la aguja del velocímetro que vemos dentro de cada una de las ventanas de control de locomotora.

     Picture1.DrawWidth = 4
     Picture1.ForeColor = &HFFFFFF
     Picture1.FillColor = &HFFFFFF

     Picture1.Circle (0, 0), 6


     Grados = (VeloActual / VeloFondo) * 270
     Angulo = (225 - Grados) * 1.74532925199433E-02 'radianes
     Picture1.Line (-20 * Cos(Angulo), -20 * Sin(Angulo))-(51 * Cos(Angulo), 51 * Sin(Angulo))

Las tres primeras lineas establecen cómo se va a dibujar: Con trazo de grosor 4, con color blanco, y con color de relleno blanco.

La cuarta instrucción dibuja el circulito blanco que se sitúa en el punto de giro de la aguja.
En la quinta instrucción calculamos la proporción entre la velocidad actual, la que debe indicar la aguja, respecto de la velocidad de fondo de escala. Esta proporción aplicada al total de grados que abarca la escala, 270, nos da el número de grados que debe moverse la aguja.

En la siguiente instrucción cambiamos esa cifra de grados a radianes obteniendo el valor "Angulo"

Y en la última linea dibujamos la línea que representa la aguja trazando una línea entre dos puntos cuyas coordenaedas son: x=-20 * Cos(Angulo),    y= -20 * Sin(Angulo)    y    x=51 * Cos(Angulo),    y=51 * Sin(Angulo).

Observese que se está dibujando en el objeto "Picture1" que en una fase anterior se ha definido como un control de tipo picture con un sistema de coordenadas con el origen en el centro y 200 unidades de ancho y alto

El resultado se puede apreciar en el vídeo adjunto


video

Como se ve, intervienen las funciones trigonométricas seno y coseno, así que hay que tener claro su significado. Como antes decía, no hay nada mágico. Hay que calcularse el ángulo que debe tener la aguja, las coordenadas de los puntos extremos y dibujar una linea entre esos dos puntos extremos con un determinado color, y un determinado espesor. Realmente en programación, para dibujar, sólo hay dos instrucciones Line y Circle. Las dos las he usado aquí, y no hay ninguna más, asi que cada dibujo que queramos ver hay que componerlo a base de estas dos instrucciones.

Realmente estas dos instucciones corresponden a una regla y a un compás, y como sabemos, esos son los dos únicos instrumentos imprescindibles para dibujar.

Y para que la aguja realmente se mueva, el truco es el mismo que el del cine o la televisión: La aguja se está dibujando continuamente, cada vez en la situación que corresponde a la velocidad en cada momento. Esto también es poco habitual en programación: Realmente el programa está permanentemente metido en un bucle que redibuja continuamente los elementos gráficos que cambian. Por ejemplo en la esquina superior derecha de la pantalla de la cabecera vemos un cronómetro que va calculando los minutos y segundos que lleva funcionando el programa. Los números van cambiando porque el programa redibuja continuamente las cifras.

Si nos fijamos, en el caso de la aguja del velocímetro, hay una variable, de nombre VeloActual que determina la posición en que debe aparecer la aguja. Cada vez que se ejecutan esas instrucciones se dibuja la aguja de acuerdo a este valor. Se trata de una variable analogica, porque realmente su valor corresponde a la velocidad teórica de la locomotora en Kilómetros/hora, que varía de forma continua entre cero y el valor máximo.

En otros casos la variable es de tipo digital, por ejemplo un semáforo de dos luces, puede lucir en rojo o en verde.por lo que la variable que dice como se debe dibujar, solo puede tener dos valores. Bueno en realidad tiene cuatro posibilidades: encendido el rojo, encendido el verde, encendidos ambos y apagados ambos. Pero en todo caso, se trata de una variable entera que solo admite unos pocos valores. En este caso 0, 1 o 2 (el caso de los dos apagados no se contempla) Tratándose de semáforos, el nombre de esta variable es "Aspecto".  Si algún lector se pregunta cuando se muestran encendidos simultáneamente el rojo y el verde la respuesta es que se muestran así en el modo de diseño, es decir cuando el usuario está definiendo que en una determinada posición, va un semáforo.

Bueno pues la rutina que dibuja un semáforo es la siguiente:

Case 1 'semaforos dos aspectos


    Destino.DrawWidth = Grueso
    Destino.Line (x - 3 * a, y)-(x + m, y), Negro 'palo
    Destino.Line (x - 3 * a, y + n)-(x - 3 * a, y - n), Negro 'base


    Destino.DrawWidth = Grueso * 4
    Destino.Line (x - m, y)-(x + m, y), Negro ' cabeza

    Destino.DrawWidth = Grueso


    Select Case Aspecto
        Case 1
            Destino.Circle (x + m, y), Grueso / 1.6, Rojo
        Case 2
            Destino.Circle (x - m, y), Grueso / 1.6, Verde
        Case Else
            Destino.Circle (x + m, y), Grueso / 1.6, Rojo
            Destino.Circle (x - m, y), Grueso / 1.6, Verde
    End Select



Ya sé que para la mayoría de los lectores, el presentar aquí estos segmentos de código puede resultar aburrido, pero, insisto, lo hago para aquellas personas que tengan conocimientos de programación, y que tengan curiosidad por saber cómo se pueden hacer este tipo de programas con gráficos móviles. Vemos como aquí la variable "Aspecto" hace que ejecuten unas u otras instrucciones del último bloque, y que en definitiva están dibujando un circulo de color rojo o verde.

Esta rutina es polivalente, ya que se usa para dibujar semáforos en más de una situación de programa. Por eso se usa la variable Destino que indica dónde hay que dibujar en cada caso. Las variables x e y especifican las coordenadas donde debe hacerse el dibujo, a es la altura del poste y m es la altura de la cabeza del semáforo. La variable "Grueso" indica el espesor de las líneas de dibujo, y las variables "Rojo", "Verde" y "Negro" contienen la definición binaria de esos colores.

Y naturalmente, el caso de los desvíos es análogo. Una variable, que por cierto también se llama "Aspecto" dibuja las lineas correspondientes a la posición del desvío. Hay desvíos con dos aspectos, y otros con tres, caso de los desvíos triples.

De hecho cualquier segmento de vía se dibuja igual que un desvío ya que puede corresponder a un trazo vertical, horizontal, inclinado a derecha, inclinado a izquierdas, y todas las combinaciones de esquinas que permiten cerrar los dibujos. Sin embargo, los tramos simples no tienen aspectos, por lo que se dibujan siempre igual, a diferencia de los desvíos.

Seguramente algún lector que tenga experiencia en programación se habrá visto sorprendido por el hecho de que el programa dibuja CADA VEZ cada elemento utilizando las instrucciones Line y Circle para dibujar las imagenes. Cuando se hacen cosas parecidas a esta, muchos programadores realizan previamente una gran cantidad de imágenes, utilizando un programa de dibujo (Paint o PhotoShop, por ejemplo), almacenan todas estas imágenes, y luego durante la ejecución presentan unas u otras imágenes en el lugar oportuno. Mi experiencia es que ese tipo de sistemas resultan más lentos, y mucho más difíciles de mantener, pero sobre todo, el dibujar los elementos cada vez durante la ejecución tiene la enorme ventaja de que puede dibujarse a cualquier escala sin más que dar un nuevo valor a las coordenadas. De esta forma se consigue muy sencillamente que se pueda hacer zoom sobre cualquier zona del dibujo y a cualquier grado de ampliación. También es posible utilizar colores variables con significados apropiados porque en definitiva para la rutina de dibujo los colores son variables cuyo valor le viene dado.

También es facilisimo adaptarse a las distintas resoluciones de pantalla. En la imagen de cabecera de este artículo vemos la imagen del programa en un ordenador de sobremesa con pantalla de 1280 x 1024 pixels, pero como contaba en mi anterior artículo, no he tenido la menor dificultad eh hacerlo funcionar en un pequeño ordenador con bastante menos resolución, incluso con proporciones distintas, ya que tiene una pantalla apaisada, tal como vemos en la fotografía de cabecera de mi anterior artículo (Un hito).

Si algun lector, que estaba considerando la posibilidad de hacer un programa para controlar su maqueta, se ha asustado al leer todo lo anterior, le hago la advertencia de que hacer un programa de la forma en que yo lo he hecho, es realmente un lujo, ya que el programa está hecho como si fuera a venderse, es decir que permite definir cualquier trazado de vías y colocar los desvios, señales, y demás elementos que sean necesarios. Esto está muy bien, porque permite hacer modificaciones con toda facilidad, y tiene las ventajas que he comentado en cuanto a la posibilidad de zoom y la adapatación a distintas resoluciones de pantalla, pero realmente se puede hacer un programa mucho más sencillo, si nos conformamos con que sea hecho específicamente para una determinada maqueta, y para una determinada resolución de pantalla. En un próximo artículo trataré más extensamente este tema.

Claro que aquí viene la segunda parte: ¿Como hacemos para que esas "ordenes" que el programa envía salgan del ordenador y lleguen a mover un desvío en la maqueta? Aunque parezca raro, esto es muchísimo más sencillo que lo que hemos explicado hasta ahora, pero de eso trataremos en el artículo siguiente.


No hay comentarios:

Publicar un comentario

Gracias por expresar tus opiniones.

Los comentarios aparecerán en el blog normalmente en unos pocos segundos