jueves, 10 de abril de 2014

Reloj Analógico. Gráfica XY dinámica.






Funciones utilizadas:
Ahora()
Residuo()
Pi()
Entero()
Seno()
Cos()
Radianes()


Variables y rangos con nombre:

Fech
Horas
Minutos
RadHora
RadMin
RHora
RMin
RReloj
Segundos
SegX
SegY
XHora
XSeg:RMin*(SENO(RadMin*Segundos))
XSeg2:
RMin*(SENO(RadMin*ENTERO((RESIDUO(AHORA();1)*24*60)*60)))
YHoras:RHora*(COS(RadHora*Horas))
YSeg: RMin*(COS(RadMin*Segundos))

El objeto de este ejercicio es representar un reloj analógico mediante un gráfico xy de excel. Aunque incorporo algo de  programación, el cálculo de los valores de la gráfica lo hago mediante fórmulas excel. Podría hacerlo por programa, pero no es el objeto del ejercicio.

  • La gráfica emula el aspecto de un reloj clásico.
  • Una corona circular dividida en 60 partes, para 60 minutos. 
  • Otra, situada sobre la anterior, dividida en 12 partes, para las 12 horas.
  • Una manecilla de horas. Esta manecilla se debe mueve de manera continua, sin saltos.
  • La hora podría calcularla mediante la función =HORA(A1) pero esto haría que la manecilla se moviese a saltos de una hora, la función hora solo cambia de valor cada hora. Para evitar ese salto calculo la parte no entera de la fecha (vease sistema de fechas en excel)  y la multiplico por 24.  horas = RESIDUO(AHORA();1)*24 y Fech=RESIDUO(AHORA();1)
  • Un minutero. Esta manecilla se debe mover de manera continua, sin saltos.
  • Los minutos podría calcularlos mediante la función =MINUTO(A1) pero esto haría que la manecilla se moviese a saltos. Para evitar ese salto, calculo la parte no entera de la  hora (vease punto anterior)  y la multiplico por 60. minutos=RESIDUO(Fech*24;1)*60.
  • Un segundero. Esta manecilla se mueve de segundo en segundo. ENTERO(RESIDUO(Fech*24*60;1)*60) . Aquí si podría haber utilizado la función SEGUNDO()
  • Los puntos de corona que representa los  minutos las calculo en las columnas M y N de la hoja AUX. Sesenta y un puntos  aunque el último coincide con el primero con el fin de cerrar el circulo (360º/60 = 6º por punto). Cada punto esta calculado en función del radio de la corona y del seno y coseno del ángulo. 60 separaciones dan un efecto circular, no es un circulo pero lo parece.
  • Los puntos de corona que representa las horas las calculo en las columnas I y J de la hoja AUX. Trece puntos calculados en función del radio y del seno y coseno del ángulo . En este caso las 12 separaciones no son suficientes para parecer un círculo, por lo que, manualmente, al preparar la gráfica, elimino los segmentos que unen los puntos entre si.
  • Las tres manecillas tienen un punto común, el centro del reloj, el 0,0.
  • Los puntos para la hora los calculo a partir de un radio mediante el seno y coseno del  ángulo resultante de multiplicar la hora (función Hora()) por 30º (columnas AB), pero convertidos a radianes, que es como se calculan los valores trigonométricos en excel. A su vez hago el cálculo de los valores XY en una variable con nombre, en vez de en una celda. Minutos y segundos utilizan un ángulo de 6º (columnas CD y EF)
  • La actualización de la hora representada en el gráfico se puede hacer mediante la tecla F9. Funciona pero queda poco bonito, poco útil. Incorporo el mínimo código vbasic que permite actualizar, cada segundo, el reloj.

Código utilizado para actualizar el reloj:

El procedimiento Auto_Open se ejecuta al abrir el libro, es el primer procedimiento que se ejecuta. En este caso se limita a seleccionar la hoja RELOJ y a lanzar el procedimiento "RECALCULA"
Public Proc
Sub Auto_open()
Sheets("Reloj").Select
 Proc = "Recalcula"
Recalcula
End Sub




El procedimiento Recalcula recalcula el valor de las fórmulas y prepara la siguiente su siguiente ejecución. Es decir se llama si mismo, pero un segundo después, mediante  el evento, del objeto application, OnTime. La instrucción .OnTime Now() + 0.0000115741 * 1, Proc  se puede leer "Cuando sea la hora actual mas un segundo (0.0000115741 es 1/(24*60*60)) ejecuta el procedimiento Proc. Actualizar un libro excel cada cierto tiempo es así de sencillo.


Sub Recalcula()
'Dim Proc


  With Application
  .ScreenUpdating = False
   Calculate
   .ScreenUpdating = True
.OnTime Now() + 0.0000115741 * 1, Proc 
  End With
  

End Sub