'================================= ' ANALOG CLOCK ' ' Created: 1985 ' Ported in small basic: 2018 ' Current version: 23 January 2023 ' ' This program is transcribed as faithfully ' as possible from an original written for ' MS-DOS 3.0 BASICA at some time in 1985 ' (perhaps at the beginning of 1986) by my ' colleague Luciano Ghinelli and me (Cesare ' Brizio). ' Minor improvements were added in January ' 2023 (variables renamed, spurious pixels ' overwriting -the latter, a problem not observable ' in the old DOS program), but the core algorithm ' wasn't altered. ' As specified in the start-up text message, ' Luciano and me chose deliberately a more intricate ' alternative than the bare, integral regeneration of ' the clock face at every program cycle: in fact, ' while the clock's hands are constantly regenerated ' at their current position (the only way to prevent ' their disappearance when overtaken by another ' hand), they are individually deleted from their ' previous position just as they move - and this ' required a modicum of intricacy. ' It operated in "SCREEN 9" mode (640x350) ' Text coordinates were as usual for the time ' the 24 lines x 80 columns system. ' In hindsight, Small Basic's (for that purpose. ' any "recent" Basic's!) syntax seems to me ' convolute, inefficient and counter-intuitive! '================================= TextWindow.WriteLine("It's crystal clear that one could regenerate the whole clock face") TextWindow.WriteLine("at every program cycle, by recreating the whole clock face,") TextWindow.WriteLine("redrawing each time all the three hands, at the price of some") TextWindow.WriteLine("excessive flickering. Such a program would be much simpler and") TextWindow.WriteLine("shorter than this. The over-engineered approach preferred here is:") TextWindow.WriteLine(" - draw the clock face only once at program start;") TextWindow.WriteLine(" - at every cycle, rewrite only the hands at their current position;") TextWindow.WriteLine(" - chech whether any hand should be moved to a new position;") TextWindow.WriteLine(" - overwrite just the hand at the old position;") TextWindow.WriteLine(" - rewrite the hand at ist new position.") TextWindow.WriteLine("Press enter to start") TextWindow.Read() TextWindow.WriteLine("Click the graphics window and press any key to exit") ' The original clock filled entirely the "Screen 9" (640x350) window, and ' touched the top and the bottom window edge. ' Here, to improve its look, the clock is down-shifted by offset_y and ' the screen is enlarged by 2 * offset_y ' OFFSET_Y SHOULD BE KEPT ABOVE ZERO, OTHERWISE ' THE OUTERMOST CIRCLE MAY NOT BE GENERATED offset_y = 20 'vertical offset in pixel h = 350 + (offset_y*2) 'height w = 640 + (offset_y*2) 'width GraphicsWindow.Height = h GraphicsWindow.Width = w GraphicsWindow.KeyDown = OnKeyDown GraphicsWindow.BackgroundColor = "Black" GraphicsWindow.Show() '------------------------------------------------------------------------------ ' CALCULATING THE COORDINATES AROUND THE CIRCLE '------------------------------------------------------------------------------ R = 150 X = 320 Y = 9 PI = 3.141593 IND = 0 FOR I = -PI / 2 TO PI * 3 / 2 STEP PI / 30 GRAD_COS = Math.Floor(320 + (R * math.Cos(I)*0.97)) SEC_COS = Math.Floor(320 + (R * math.Cos(I)*0.94)) MIN_COS = Math.Floor(320 + (R * math.Cos(I)*0.83)) HOUR_COS = Math.Floor(320 + (R * math.Cos(I)*0.70)) HAND_STARTS_FROM_X = Math.Floor(320 + (R * math.Cos(I)*0.08)) GRAD_START_FROM_X = Math.Floor(320 + ((R + 10) * math.Cos(I))) GRAD_SIN = Math.Floor(175 + (R * math.Sin(I)*0.97)) SEC_SIN = Math.Floor(175 + (R * math.Sin(I)*0.94)) MIN_SIN = Math.Floor(175 + (R * math.Sin(I)*0.83)) HOUR_SIN = Math.Floor(175 + (R * math.Sin(I)*0.70)) HAND_STARTS_FROM_Y = Math.Floor(175 + (R * math.Sin(I)*0.08)) GRAD_START_FROM_Y = Math.Floor(175 + ((R + 10) * math.Sin(I))) ' See around line 20 for an explanation of offset_y END_GRAD_X[IND] = GRAD_COS END_GRAD_Y[IND] = GRAD_SIN+offset_y HOURX[IND] = HOUR_COS HOURY[IND] = HOUR_SIN+offset_y MINX[IND] = MIN_COS MINY[IND] = MIN_SIN+offset_y SECX[IND] = SEC_COS SECY[IND] = SEC_SIN+offset_y START_GRAD_X[IND] = GRAD_START_FROM_X START_GRAD_Y[IND] = GRAD_START_FROM_Y+offset_y FromX[IND] = HAND_STARTS_FROM_X FromY[IND] = HAND_STARTS_FROM_Y+offset_y IND= IND + 1 ENDFOR '---------------------------------------- ' DRAWING THE CLOCK FACE '---------------------------------------- '============> Initially all white GraphicsWindow.BrushColor = "White" GraphicsWindow.FillEllipse(144,0+offset_y,2*R + 50,2*R +50) '============> DOUBLE OUTERMOST BORDER GraphicsWindow.PenColor = "DodgerBlue" GraphicsWindow.DrawEllipse(144,0+offset_y,2*R + 50,2*R +50) GraphicsWindow.PenColor = "DodgerBlue" GraphicsWindow.DrawEllipse(143,0+offset_y-1,2*R + 51,2*R +51) '============> Clock face under the hands GraphicsWindow.BrushColor = "Gainsboro" GraphicsWindow.FillEllipse(170,25+offset_y,2*R,2*R) 'OK '============> Two inner circles and graduations GraphicsWindow.PenColor = "SlateGray" GraphicsWindow.DrawEllipse(165,20+offset_y,2*R + 10,2*R +10)'OK GraphicsWindow.DrawEllipse(170,25+offset_y,2*R,2*R) 'OK FOR OO = 0 TO 60 GraphicsWindow.DrawLine(START_GRAD_X[OO],START_GRAD_Y[OO],END_GRAD_X[OO],END_GRAD_Y[OO]) ENDFOR '============> Numbers GraphicsWindow.BrushColor = "Black" GraphicsWindow.DrawText(312,1+offset_y,"12") GraphicsWindow.DrawText(224,26+offset_y,"11") GraphicsWindow.DrawText(168,85+offset_y,"10") GraphicsWindow.DrawText(150,167+offset_y,"9") GraphicsWindow.DrawText(172,249+offset_y,"8") GraphicsWindow.DrawText(228,309+offset_y,"7") GraphicsWindow.DrawText(315,334+offset_y,"6") GraphicsWindow.DrawText(402,309+offset_y,"5") GraphicsWindow.DrawText(460,249+offset_y,"4") GraphicsWindow.DrawText(482,167+offset_y,"3") GraphicsWindow.DrawText(459,85+offset_y,"2") GraphicsWindow.DrawText(402,26+offset_y,"1") ' ============> Innermost circle -colored as the SECONDS hand GraphicsWindow.PenColor = "Lime" GraphicsWindow.DrawEllipse(310,165+offset_y,20,20) GraphicsWindow.BrushColor = "Lime" GraphicsWindow.FillEllipse(310,165+offset_y,20,20) OLD_HX=0 OLD_HY=0 PREV_H_HAND_POINTS_AT=0 exiting = "False" 'User interaction - Has any key been pressed?? While exiting = "False" '---------------------------------------------------------------- ' CALCULATING SECONDS AND COORDINATES '---------------------------------------------------------------- SEC = Clock.Second SX = SECX[SEC] SY = SECY[SEC] MSEC = SEC - 1 IF MSEC < 0 THEN MSEC = 59 Endif OLD_SX = SECX[MSEC] OLD_SY = SECY[MSEC] GraphicsWindow.PenWidth = 1 GraphicsWindow.PenColor = "Lime" GraphicsWindow.DrawLine(320, 175+offset_y, SX , SY) GraphicsWindow.BrushColor = "Lime" GraphicsWindow.fillEllipse(310,165+offset_y,20,20) GraphicsWindow.BrushColor = "White" GraphicsWindow.DrawText(0,0,Clock.Time) Text.GetCharacter(65) IF PSEC <> SEC THEN Sound.PlayClick() PSEC = SEC ELSE GOTO SecondUnchanged EndIf GraphicsWindow.PenWidth = 4 GraphicsWindow.PenColor = "Gainsboro" ' ---------------> This may leave one or more pixels at the old position of the hand's tip 'GraphicsWindow.DrawLine(320, 175+offset_y, OLD_SX , OLD_SY) ' ---------------> By cleaning all the radius up to the inner graduation, I am sure to overwrite the whole hand GraphicsWindow.DrawLine(320, 175+offset_y, END_GRAD_X[MSEC] , END_GRAD_Y[MSEC]) GraphicsWindow.BrushColor = "Black" GraphicsWindow.FillRectangle(0,0,100,20) SecondUnchanged: '---------------------------------------------------------------- ' CALCULATING MINUTES AND COORDINATES '---------------------------------------------------------------- MIN = Clock.Minute MX = MINX[MIN] MY = MINY[MIN] MFROM_X=FromX[MIN] MFROM_Y=FromY[MIN] GraphicsWindow.PenWidth = 2 GraphicsWindow.PenColor = "Blue" GraphicsWindow.DrawLine(MFROM_X, MFROM_Y, MX , MY) IF (PREMIN = MIN) THEN GOTO MinuteUnchanged EndIf PREMIN = MIN MMIN = MIN - 1 IF (MMIN < 0) THEN MMIN = 59 EndIf OLD_MX = MINX[MMIN] OLD_MY = MINY[MMIN] OLD_MFROM_X=FromX[MMIN] OLD_MFROM_Y=FromY[MMIN] GraphicsWindow.PenWidth = 6 GraphicsWindow.PenColor = "Gainsboro" ' ---------------> This may leave one or more pixels at the old position of the hand's tip 'GraphicsWindow.DrawLine(OLD_MFROM_X, OLD_MFROM_Y, OLD_MX , OLD_MY) ' ---------------> By cleaning all the radius up to the inner graduation, I am sure to overwrite the whole hand GraphicsWindow.DrawLine(OLD_MFROM_X, OLD_MFROM_Y, END_GRAD_X[MMIN] , END_GRAD_Y[MMIN]) MinuteUnchanged: '---------------------------------------------------------------- ' CALCULATING HOURS AND COORDINATES '---------------------------------------------------------------- HOUR = Clock.Hour HMIN = Clock.Minute IF (HOUR > 11) THEN HOUR = HOUR - 12 ENDIF H_HAND_POINTS_AT = HOUR * 5 + Math.Floor(HMIN / 12) 'textwindow.writeline(H_HAND_POINTS_AT) '--DEBUG HX = HOURX[H_HAND_POINTS_AT] HY = HOURY[H_HAND_POINTS_AT] HFROM_X=FromX[H_HAND_POINTS_AT] HFROM_Y=FromY[H_HAND_POINTS_AT] GraphicsWindow.PenWidth = 4 GraphicsWindow.PenColor = "FireBrick" GraphicsWindow.DrawLine(HFROM_X, HFROM_Y, HX , HY) IF (H_HAND_POINTS_AT = PREV_H_HAND_POINTS_AT) THEN GOTO HourUnchanged EndIf IF (OLD_HX = 0 AND OLD_HY = 0) THEN OLD_HX = HX OLD_HY = HY OLD_HFROM_X=HFROM_X OLD_HFROM_Y=HFROM_Y Goto HourUnchanged EndIf GraphicsWindow.PenWidth = 8 GraphicsWindow.PenColor = "Gainsboro" ' ---------------> This may leave one or more pixels at the old position of the hand's tip 'GraphicsWindow.DrawLine(OLD_HFROM_X, OLD_HFROM_Y, OLD_HX , OLD_HY) ' ---------------> By cleaning all the radius up to the inner graduation, I am sure to overwrite the whole hand GraphicsWindow.DrawLine(OLD_HFROM_X, OLD_HFROM_Y, END_GRAD_X[PREV_H_HAND_POINTS_AT] , END_GRAD_Y[PREV_H_HAND_POINTS_AT]) OLD_HX = HX OLD_HY = HY OLD_HFROM_X=HFROM_X OLD_HFROM_Y=HFROM_Y PREV_H_HAND_POINTS_AT = H_HAND_POINTS_AT HourUnchanged: endwhile Program.End() '----------------------------------------------------------------------------------------------------------- '--- Take note of the fact that a key has been pressed. '----------------------------------------------------------------------------------------------------------- Sub OnKeyDown exiting = "True" EndSub