Draw a clock: Difference between revisions
(Added SVG clock. More of a stopwatch really, javascript must be added to grab the system time and set rotation of the hands, but I don't know javascript at all.) |
Catskill549 (talk | contribs) |
||
Line 299: | Line 299: | ||
ExitApp |
ExitApp |
||
Return</lang> |
Return</lang> |
||
=={{header|AWK}}== |
|||
<lang AWK> |
|||
# syntax: GAWK -f DRAW_A_CLOCK.AWK [-v xc="*"] |
|||
BEGIN { |
|||
# clearscreen_cmd = "clear" ; sleep_cmd = "sleep 1s" # Unix |
|||
clearscreen_cmd = "CLS" ; sleep_cmd = "TIMEOUT /T 1 >NUL" # MS-Windows |
|||
clock_build_digits() |
|||
while (1) { |
|||
now = strftime("%H:%M:%S") |
|||
t[1] = substr(now,1,1) |
|||
t[2] = substr(now,2,1) |
|||
t[3] = 10 |
|||
t[4] = substr(now,4,1) |
|||
t[5] = substr(now,5,1) |
|||
t[6] = 10 |
|||
t[7] = substr(now,7,1) |
|||
t[8] = substr(now,8,1) |
|||
if (prev_now != now) { |
|||
system(clearscreen_cmd) |
|||
for (v=1; v<=8; v++) { |
|||
printf("\t") |
|||
for (h=1; h<=8; h++) { |
|||
printf("%-8s",a[t[h],v]) |
|||
} |
|||
printf("\n") |
|||
} |
|||
prev_now = now |
|||
} |
|||
system(sleep_cmd) |
|||
} |
|||
exit(0) |
|||
} |
|||
function clock_build_digits( arr,i,j,x,y) { |
|||
arr[1] = " 0000 1 2222 3333 4 555555 6666 777777 8888 9999 " |
|||
arr[2] = "0 0 11 2 2 3 3 44 5 6 7 78 8 9 9 " |
|||
arr[3] = "0 00 1 1 2 3 4 4 5 6 7 8 8 9 9 :: " |
|||
arr[4] = "0 0 0 1 2 333 4 4 555555 66666 7 8888 9 9 :: " |
|||
arr[5] = "0 0 0 1 22 3 444444 5 6 6 7 8 8 99999 " |
|||
arr[6] = "00 0 1 2 3 4 5 6 6 7 8 8 9 :: " |
|||
arr[7] = "0 0 1 2 3 3 4 5 5 6 6 7 8 8 9 :: " |
|||
arr[8] = " 0000 1111111222222 3333 4 5555 6666 7 8888 9999 " |
|||
for (i=1; i<=8; i++) { |
|||
if (xc != "") { |
|||
gsub(/[0-9:]/,substr(xc,1,1),arr[i]) # change "0-9" and ":" to substitution character |
|||
} |
|||
y++ |
|||
x = -1 |
|||
for (j=1; j<=77; j=j+7) { |
|||
a[++x,y] = substr(arr[i],j,7) |
|||
} |
|||
} |
|||
} |
|||
</lang> |
|||
<p>sample command and output:</p> |
|||
<pre> |
|||
GAWK -f DRAW_A_CLOCK.AWK -v xc="#" |
|||
#### #### # #### #### #### |
|||
# # # # ## # # # # # # |
|||
# ## # # ## # # # # ## # ## # ## |
|||
# # # #### ## # # # ## # # # # # # |
|||
# # # # # # ##### # # # # # # |
|||
## # # # ## # # ## ## # ## # |
|||
# # # # ## # # ## # # # # |
|||
#### #### ####### #### #### #### |
|||
</pre> |
|||
=={{header|C}}== |
=={{header|C}}== |
Revision as of 06:12, 7 February 2014
Task: draw a clock. More specific:
- Draw a time keeping device. It can be a stopwatch, hourglass, sundial, a mouth counting "one thousand and one", anything. Only showing the seconds is required, e.g. a watch with just a second hand will suffice. However, it must clearly change every second, and the change must cycle every so often (one minute, 30 seconds, etc.) It must be drawn; printing a string of numbers to your terminal doesn't qualify. Both text-based and graphical drawing are OK.
- The clock is unlikely to be used to control space flights, so it needs not be hyper-accurate, but it should be usable, meaning if one can read the seconds off the clock, it must agree with the system clock.
- A clock is rarely (never?) a major application: don't be a CPU hog and poll the system timer every microsecond, use a proper timer/signal/event from your system or language instead. For a bad example, many OpenGL programs update the framebuffer in a busy loop even if no redraw is needed, which is very undesirable for this task.
- A clock is rarely (never?) a major application: try to keep your code simple and to the point. Don't write something too elaborate or convoluted, instead do whatever is natural, concise and clear in your language.
Key points: animate simple object; timed event; polling system resources; code clarity.
ActionScript
<lang ActionScript> package {
import flash.display.Graphics; import flash.display.Shape; import flash.display.Sprite; import flash.events.Event; import flash.events.TimerEvent; import flash.utils.Timer; public class Clock extends Sprite { // Changes of hands (in degrees) per second private static const HOUR_HAND_CHANGE:Number = 1 / 120; // 360 / (60 * 60 * 12) private static const MINUTE_HAND_CHANGE:Number = 0.1; // 360 / (60 * 60) private static const SECOND_HAND_CHANGE:Number = 6; // 360 / 60 private var _timer:Timer; private var _hHand:Shape; private var _mHand:Shape; private var _sHand:Shape; public function Clock() { if ( stage ) _init(); else addEventListener(Event.ADDED_TO_STAGE, _init); } private function _init(e:Event = null):void { var i:uint; var base:Shape = new Shape(), hHand:Shape = new Shape(), mHand:Shape = new Shape(); var sHand:Shape = new Shape(), hub:Shape = new Shape(); var size:Number = 500; var c:Number = size / 2; x = 30; y = 30; var baseGraphics:Graphics = base.graphics; baseGraphics.lineStyle(5, 0xEE0000); baseGraphics.beginFill(0xFFDDDD); baseGraphics.drawCircle(c, c, c); var uAngle:Number = Math.PI / 30; var markerStart:Number = c - 30; var markerEnd:Number = c - 15; var markerX1:Number, markerY1:Number, markerX2:Number, markerY2:Number; var angle:Number, angleSin:Number, angleCos:Number; baseGraphics.endFill(); var isMajorMarker:Boolean = true; for ( i = 0; i < 60; i++ ) { // Draw the markers angle = uAngle * i; angleSin = Math.sin(angle); angleCos = Math.cos(angle); markerX1 = c + markerStart * angleCos; markerY1 = c + markerStart * angleSin; markerX2 = c + markerEnd * angleCos; markerY2 = c + markerEnd * angleSin; if ( i % 5 == 0 ) { baseGraphics.lineStyle(3, 0x000080); isMajorMarker = true; } else if ( isMajorMarker ) { baseGraphics.lineStyle(1, 0x000080); isMajorMarker = false; } baseGraphics.moveTo(markerX1, markerY1); baseGraphics.lineTo(markerX2, markerY2); } addChild(base); sHand.graphics.lineStyle(2, 0x00BB00); sHand.graphics.moveTo(0, 0); sHand.graphics.lineTo(0, 40 - c); sHand.x = sHand.y = c; mHand.graphics.lineStyle(8, 0x444444); mHand.graphics.moveTo(0, 0); mHand.graphics.lineTo(0, 50 - c); mHand.x = mHand.y = c; hHand.graphics.lineStyle(8, 0x777777); hHand.graphics.moveTo(0, 0); hHand.graphics.lineTo(0, 120 - c); hHand.x = hHand.y = c; hub.graphics.lineStyle(4, 0x664444); hub.graphics.beginFill(0xCC9999); hub.graphics.drawCircle(c, c, 5); _hHand = hHand; _mHand = mHand; _sHand = sHand; addChild(mHand); addChild(hHand); addChild(sHand); addChild(hub); var date:Date = new Date(); // Since millisecond precision is not needed, round it up to the nearest second. var seconds:Number = date.seconds + ((date.milliseconds > 500) ? 1 : 0); var minutes:Number = date.minutes + seconds / 60; var hours:Number = (date.hours + minutes / 60) % 12; sHand.rotation = seconds * 6; mHand.rotation = minutes * 6; hHand.rotation = hours * 30; _timer = new Timer(1000); // 1 second = 1000 ms _timer.addEventListener(TimerEvent.TIMER, _onTimerTick); _timer.start(); } private function _onTimerTick(e:TimerEvent):void { _hHand.rotation += HOUR_HAND_CHANGE; _mHand.rotation += MINUTE_HAND_CHANGE; _sHand.rotation += SECOND_HAND_CHANGE; } }
} </lang>
AutoHotkey
requires the GDI+ Library from http://www.autohotkey.com/forum/viewtopic.php?t=32238 this code from http://www.autohotkey.com/forum/viewtopic.php?p=231836#231836 draws a very nice clock with GDI+ <lang AHK>; gdi+ ahk analogue clock example written by derRaphael
- Parts based on examples from Tic's GDI+ Tutorials and of course on his GDIP.ahk
- This code has been licensed under the terms of EUPL 1.0
- SingleInstance, Force
- NoEnv
SetBatchLines, -1
- Uncomment if Gdip.ahk is not in your standard library
- Include, Gdip.ahk
If !pToken := Gdip_Startup() {
MsgBox, 48, gdiplus error!, Gdiplus failed to start. Please ensure you have gdiplus on your system ExitApp
} OnExit, Exit
SysGet, MonitorPrimary, MonitorPrimary SysGet, WA, MonitorWorkArea, %MonitorPrimary% WAWidth := WARight-WALeft WAHeight := WABottom-WATop
Gui, 1: -Caption +E0x80000 +LastFound +AlwaysOnTop +ToolWindow +OwnDialogs Gui, 1: Show, NA hwnd1 := WinExist()
ClockDiameter := 180 Width := Height := ClockDiameter + 2 ; make width and height slightly bigger to avoid cut away edges CenterX := CenterY := floor(ClockDiameter/2) ; Center x
- Prepare our pGraphic so we have a 'canvas' to work upon
hbm := CreateDIBSection(Width, Height), hdc := CreateCompatibleDC() obm := SelectObject(hdc, hbm), G := Gdip_GraphicsFromHDC(hdc) Gdip_SetSmoothingMode(G, 4)
- Draw outer circle
Diameter := ClockDiameter pBrush := Gdip_BrushCreateSolid(0x66008000) Gdip_FillEllipse(G, pBrush, CenterX-(Diameter//2), CenterY-(Diameter//2),Diameter, Diameter) Gdip_DeleteBrush(pBrush)
- Draw inner circle
Diameter := ceil(ClockDiameter - ClockDiameter*0.08) ; inner circle is 8 % smaller than clock's diameter pBrush := Gdip_BrushCreateSolid(0x80008000) Gdip_FillEllipse(G, pBrush, CenterX-(Diameter//2), CenterY-(Diameter//2),Diameter, Diameter) Gdip_DeleteBrush(pBrush)
- Draw Second Marks
R1 := Diameter//2-1 ; outer position R2 := Diameter//2-1-ceil(Diameter//2*0.05) ; inner position Items := 60 ; we have 60 seconds pPen := Gdip_CreatePen(0xff00a000, floor((ClockDiameter/100)*1.2)) ; 1.2 % of total diameter is our pen width GoSub, DrawClockMarks Gdip_DeletePen(pPen)
- Draw Hour Marks
R1 := Diameter//2-1 ; outer position R2 := Diameter//2-1-ceil(Diameter//2*0.1) ; inner position Items := 12 ; we have 12 hours pPen := Gdip_CreatePen(0xc0008000, ceil((ClockDiameter//100)*2.3)) ; 2.3 % of total diameter is our pen width GoSub, DrawClockMarks Gdip_DeletePen(pPen) ; The OnMessage will let us drag the clock OnMessage(0x201, "WM_LBUTTONDOWN") UpdateLayeredWindow(hwnd1, hdc, WALeft+((WAWidth-Width)//2), WATop+((WAHeight-Height)//2), Width, Height) SetTimer, sec, 1000
sec:
- prepare to empty previously drawn stuff
Gdip_SetSmoothingMode(G, 1) ; turn off aliasing Gdip_SetCompositingMode(G, 1) ; set to overdraw
- delete previous graphic and redraw background
Diameter := ceil(ClockDiameter - ClockDiameter*0.18) ; 18 % less than clock's outer diameter ; delete whatever has been drawn here pBrush := Gdip_BrushCreateSolid(0x00000000) ; fully transparent brush 'eraser' Gdip_FillEllipse(G, pBrush, CenterX-(Diameter//2), CenterY-(Diameter//2),Diameter, Diameter) Gdip_DeleteBrush(pBrush) Gdip_SetCompositingMode(G, 0) ; switch off overdraw pBrush := Gdip_BrushCreateSolid(0x66008000) Gdip_FillEllipse(G, pBrush, CenterX-(Diameter//2), CenterY-(Diameter//2),Diameter, Diameter) Gdip_DeleteBrush(pBrush) pBrush := Gdip_BrushCreateSolid(0x80008000) Gdip_FillEllipse(G, pBrush, CenterX-(Diameter//2), CenterY-(Diameter//2),Diameter, Diameter) Gdip_DeleteBrush(pBrush)
- Draw HoursPointer
Gdip_SetSmoothingMode(G, 4) ; turn on antialiasing t := A_Hour*360//12 + (A_Min*360//60)//12 +90 R1 := ClockDiameter//2-ceil((ClockDiameter//2)*0.5) ; outer position pPen := Gdip_CreatePen(0xa0008000, floor((ClockDiameter/100)*3.5)) Gdip_DrawLine(G, pPen, CenterX, CenterY , ceil(CenterX - (R1 * Cos(t * Atan(1) * 4 / 180))) , ceil(CenterY - (R1 * Sin(t * Atan(1) * 4 / 180)))) Gdip_DeletePen(pPen)
- Draw MinutesPointer
t := A_Min*360//60+90 R1 := ClockDiameter//2-ceil((ClockDiameter//2)*0.25) ; outer position pPen := Gdip_CreatePen(0xa0008000, floor((ClockDiameter/100)*2.7)) Gdip_DrawLine(G, pPen, CenterX, CenterY , ceil(CenterX - (R1 * Cos(t * Atan(1) * 4 / 180))) , ceil(CenterY - (R1 * Sin(t * Atan(1) * 4 / 180)))) Gdip_DeletePen(pPen)
- Draw SecondsPointer
t := A_Sec*360//60+90 R1 := ClockDiameter//2-ceil((ClockDiameter//2)*0.2) ; outer position pPen := Gdip_CreatePen(0xa000FF00, floor((ClockDiameter/100)*1.2)) Gdip_DrawLine(G, pPen, CenterX, CenterY , ceil(CenterX - (R1 * Cos(t * Atan(1) * 4 / 180))) , ceil(CenterY - (R1 * Sin(t * Atan(1) * 4 / 180)))) Gdip_DeletePen(pPen) UpdateLayeredWindow(hwnd1, hdc) ;, xPos, yPos, ClockDiameter, ClockDiameter)
return
DrawClockMarks:
Loop, % Items Gdip_DrawLine(G, pPen , CenterX - ceil(R1 * Cos(((a_index-1)*360//Items) * Atan(1) * 4 / 180)) , CenterY - ceil(R1 * Sin(((a_index-1)*360//Items) * Atan(1) * 4 / 180)) , CenterX - ceil(R2 * Cos(((a_index-1)*360//Items) * Atan(1) * 4 / 180)) , CenterY - ceil(R2 * Sin(((a_index-1)*360//Items) * Atan(1) * 4 / 180)) )
return
WM_LBUTTONDOWN() {
PostMessage, 0xA1, 2 return
}
esc:: Exit:
SelectObject(hdc, obm) DeleteObject(hbm) DeleteDC(hdc) Gdip_DeleteGraphics(G) Gdip_Shutdown(pToken) ExitApp
Return</lang>
AWK
<lang AWK>
- syntax: GAWK -f DRAW_A_CLOCK.AWK [-v xc="*"]
BEGIN {
- clearscreen_cmd = "clear" ; sleep_cmd = "sleep 1s" # Unix
clearscreen_cmd = "CLS" ; sleep_cmd = "TIMEOUT /T 1 >NUL" # MS-Windows clock_build_digits() while (1) { now = strftime("%H:%M:%S") t[1] = substr(now,1,1) t[2] = substr(now,2,1) t[3] = 10 t[4] = substr(now,4,1) t[5] = substr(now,5,1) t[6] = 10 t[7] = substr(now,7,1) t[8] = substr(now,8,1) if (prev_now != now) { system(clearscreen_cmd) for (v=1; v<=8; v++) { printf("\t") for (h=1; h<=8; h++) { printf("%-8s",a[t[h],v]) } printf("\n") } prev_now = now } system(sleep_cmd) } exit(0)
} function clock_build_digits( arr,i,j,x,y) {
arr[1] = " 0000 1 2222 3333 4 555555 6666 777777 8888 9999 " arr[2] = "0 0 11 2 2 3 3 44 5 6 7 78 8 9 9 " arr[3] = "0 00 1 1 2 3 4 4 5 6 7 8 8 9 9 :: " arr[4] = "0 0 0 1 2 333 4 4 555555 66666 7 8888 9 9 :: " arr[5] = "0 0 0 1 22 3 444444 5 6 6 7 8 8 99999 " arr[6] = "00 0 1 2 3 4 5 6 6 7 8 8 9 :: " arr[7] = "0 0 1 2 3 3 4 5 5 6 6 7 8 8 9 :: " arr[8] = " 0000 1111111222222 3333 4 5555 6666 7 8888 9999 " for (i=1; i<=8; i++) { if (xc != "") { gsub(/[0-9:]/,substr(xc,1,1),arr[i]) # change "0-9" and ":" to substitution character } y++ x = -1 for (j=1; j<=77; j=j+7) { a[++x,y] = substr(arr[i],j,7) } }
} </lang>
sample command and output:
GAWK -f DRAW_A_CLOCK.AWK -v xc="#" #### #### # #### #### #### # # # # ## # # # # # # # ## # # ## # # # # ## # ## # ## # # # #### ## # # # ## # # # # # # # # # # # # ##### # # # # # # ## # # # ## # # ## ## # ## # # # # # ## # # ## # # # # #### #### ####### #### #### ####
C
Draws a crude clock in terminal. C99, compiled with gcc -std=c99
.
<lang C>#include <stdio.h>
- include <stdlib.h>
- include <math.h>
- include <time.h>
- include <sys/time.h>
- define PI 3.14159265
const char * shades = " .:-*ca&#%@";
/* distance of (x, y) from line segment (0, 0)->(x0, y0) */ double dist(double x, double y, double x0, double y0) { double l = (x * x0 + y * y0) / (x0 * x0 + y0 * y0);
if (l > 1) { x -= x0; y -= y0; } else if (l >= 0) { x -= l * x0; y -= l * y0; } return sqrt(x * x + y * y); }
enum { sec = 0, min, hur }; // for subscripts
void draw(int size) {
- define for_i for(int i = 0; i < size; i++)
- define for_j for(int j = 0; j < size * 2; j++)
double angle, cx = size / 2.; double sx[3], sy[3], sw[3]; double fade[] = { 1, .35, .35 }; /* opacity of each arm */ struct timeval tv; struct tm *t;
/* set width of each arm */ sw[sec] = size * .02; sw[min] = size * .03; sw[hur] = size * .05;
every_second: gettimeofday(&tv, 0); t = localtime(&tv.tv_sec);
angle = t->tm_sec * PI / 30; sy[sec] = -cx * cos(angle); sx[sec] = cx * sin(angle);
angle = (t->tm_min + t->tm_sec / 60.) / 30 * PI; sy[min] = -cx * cos(angle) * .8; sx[min] = cx * sin(angle) * .8;
angle = (t->tm_hour + t->tm_min / 60.) / 6 * PI; sy[hur] = -cx * cos(angle) * .6; sx[hur] = cx * sin(angle) * .6;
printf("\033[s"); /* save cursor position */ for_i { printf("\033[%d;0H", i); /* goto row i, col 0 */ double y = i - cx; for_j { double x = (j - 2 * cx) / 2;
int pix = 0; /* calcs how far the "pixel" is from each arm and set * shade, with some anti-aliasing. It's ghetto, but much * easier than a real scanline conversion. */ for (int k = hur; k >= sec; k--) { double d = dist(x, y, sx[k], sy[k]); if (d < sw[k] - .5) pix = 10 * fade[k]; else if (d < sw[k] + .5) pix = (5 + (sw[k] - d) * 10) * fade[k]; } putchar(shades[pix]); } } printf("\033[u"); /* restore cursor pos so you can bg the job -- value unclear */
fflush(stdout); sleep(1); /* sleep 1 can at times miss a second, but will catch up next update */ goto every_second; }
int main(int argc, char *argv[]) { int s; if (argc <= 1 || (s = atoi(argv[1])) <= 0) s = 20; draw(s); return 0; }</lang>
C++
- include <windows.h>
- include <string>
- include <math.h>
//-------------------------------------------------------------------------------------------------- using namespace std;
//-------------------------------------------------------------------------------------------------- const int BMP_SIZE = 300, MY_TIMER = 987654, CENTER = BMP_SIZE >> 1, SEC_LEN = CENTER - 20,
MIN_LEN = SEC_LEN - 20, HOUR_LEN = MIN_LEN - 20;
const float PI = 3.1415926536f;
//-------------------------------------------------------------------------------------------------- class vector2 { public:
vector2() { x = y = 0; } vector2( int a, int b ) { x = a; y = b; } void set( int a, int b ) { x = a; y = b; } void rotate( float angle_r ) {
float _x = static_cast<float>( x ), _y = static_cast<float>( y ), s = sinf( angle_r ), c = cosf( angle_r ), a = _x * c - _y * s, b = _x * s + _y * c;
x = static_cast<int>( a ); y = static_cast<int>( b );
} int x, y;
}; //-------------------------------------------------------------------------------------------------- class myBitmap { public:
myBitmap() : pen( NULL ), brush( NULL ), clr( 0 ), wid( 1 ) {} ~myBitmap() {
DeleteObject( pen ); DeleteObject( brush ); DeleteDC( hdc ); DeleteObject( bmp );
}
bool create( int w, int h ) {
BITMAPINFO bi; ZeroMemory( &bi, sizeof( bi ) ); bi.bmiHeader.biSize = sizeof( bi.bmiHeader ); bi.bmiHeader.biBitCount = sizeof( DWORD ) * 8; bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biWidth = w; bi.bmiHeader.biHeight = -h;
HDC dc = GetDC( GetConsoleWindow() ); bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 ); if( !bmp ) return false;
hdc = CreateCompatibleDC( dc ); SelectObject( hdc, bmp ); ReleaseDC( GetConsoleWindow(), dc );
width = w; height = h; return true;
}
void clear( BYTE clr = 0 ) {
memset( pBits, clr, width * height * sizeof( DWORD ) );
}
void setBrushColor( DWORD bClr ) {
if( brush ) DeleteObject( brush ); brush = CreateSolidBrush( bClr ); SelectObject( hdc, brush );
}
void setPenColor( DWORD c ) {
clr = c; createPen();
}
void setPenWidth( int w ) {
wid = w; createPen();
}
void saveBitmap( string path ) {
BITMAPFILEHEADER fileheader; BITMAPINFO infoheader; BITMAP bitmap; DWORD wb;
GetObject( bmp, sizeof( bitmap ), &bitmap ); DWORD* dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight];
ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) );
ZeroMemory( &infoheader, sizeof( BITMAPINFO ) ); ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) );
infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8; infoheader.bmiHeader.biCompression = BI_RGB; infoheader.bmiHeader.biPlanes = 1; infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader ); infoheader.bmiHeader.biHeight = bitmap.bmHeight; infoheader.bmiHeader.biWidth = bitmap.bmWidth; infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD );
fileheader.bfType = 0x4D42; fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER ); fileheader.bfSize = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage;
GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS );
HANDLE file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL ); WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL ); WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL ); CloseHandle( file );
delete [] dwpBits;
}
HDC getDC() const { return hdc; } int getWidth() const { return width; } int getHeight() const { return height; }
private:
void createPen() {
if( pen ) DeleteObject( pen ); pen = CreatePen( PS_SOLID, wid, clr ); SelectObject( hdc, pen );
}
HBITMAP bmp; HDC hdc; HPEN pen; HBRUSH brush; void *pBits; int width, height, wid; DWORD clr;
}; //-------------------------------------------------------------------------------------------------- class clock { public:
clock() {
_bmp.create( BMP_SIZE, BMP_SIZE ); _bmp.clear( 100 ); _bmp.setPenWidth( 2 ); _ang = DegToRadian( 6 );
}
void setNow() {
GetLocalTime( &_sysTime ); draw();
}
float DegToRadian( float degree ) { return degree * ( PI / 180.0f ); }
void setHWND( HWND hwnd ) { _hwnd = hwnd; }
private:
void drawTicks( HDC dc ) {
vector2 line; _bmp.setPenWidth( 1 ); for( int x = 0; x < 60; x++ ) { line.set( 0, 50 ); line.rotate( static_cast<float>( x + 30 ) * _ang ); MoveToEx( dc, CENTER - static_cast<int>( 2.5f * static_cast<float>( line.x ) ), CENTER - static_cast<int>( 2.5f * static_cast<float>( line.y ) ), NULL ); LineTo( dc, CENTER - static_cast<int>( 2.81f * static_cast<float>( line.x ) ), CENTER - static_cast<int>( 2.81f * static_cast<float>( line.y ) ) ); }
_bmp.setPenWidth( 3 ); for( int x = 0; x < 60; x += 5 ) { line.set( 0, 50 ); line.rotate( static_cast<float>( x + 30 ) * _ang ); MoveToEx( dc, CENTER - static_cast<int>( 2.5f * static_cast<float>( line.x ) ), CENTER - static_cast<int>( 2.5f * static_cast<float>( line.y ) ), NULL ); LineTo( dc, CENTER - static_cast<int>( 2.81f * static_cast<float>( line.x ) ), CENTER - static_cast<int>( 2.81f * static_cast<float>( line.y ) ) ); }
}
void drawHands( HDC dc ) {
float hp = DegToRadian( ( 30.0f * static_cast<float>( _sysTime.wMinute ) ) / 60.0f ); int h = ( _sysTime.wHour > 12 ? _sysTime.wHour - 12 : _sysTime.wHour ) * 5;
_bmp.setPenWidth( 3 ); _bmp.setPenColor( RGB( 0, 0, 255 ) ); drawHand( dc, HOUR_LEN, ( _ang * static_cast<float>( 30 + h ) ) + hp );
_bmp.setPenColor( RGB( 0, 128, 0 ) ); drawHand( dc, MIN_LEN, _ang * static_cast<float>( 30 + _sysTime.wMinute ) );
_bmp.setPenWidth( 2 ); _bmp.setPenColor( RGB( 255, 0, 0 ) ); drawHand( dc, SEC_LEN, _ang * static_cast<float>( 30 + _sysTime.wSecond ) );
}
void drawHand( HDC dc, int len, float ang ) {
vector2 line; line.set( 0, len ); line.rotate( ang ); MoveToEx( dc, CENTER, CENTER, NULL ); LineTo( dc, line.x + CENTER, line.y + CENTER );
}
void draw() {
HDC dc = _bmp.getDC();
_bmp.setBrushColor( RGB( 250, 250, 250 ) ); Ellipse( dc, 0, 0, BMP_SIZE, BMP_SIZE ); _bmp.setBrushColor( RGB( 230, 230, 230 ) ); Ellipse( dc, 10, 10, BMP_SIZE - 10, BMP_SIZE - 10 );
drawTicks( dc ); drawHands( dc );
_bmp.setPenColor( 0 ); _bmp.setBrushColor( 0 ); Ellipse( dc, CENTER - 5, CENTER - 5, CENTER + 5, CENTER + 5 );
_wdc = GetDC( _hwnd ); BitBlt( _wdc, 0, 0, BMP_SIZE, BMP_SIZE, dc, 0, 0, SRCCOPY ); ReleaseDC( _hwnd, _wdc );
}
myBitmap _bmp; HWND _hwnd; HDC _wdc; SYSTEMTIME _sysTime; float _ang;
}; //-------------------------------------------------------------------------------------------------- class wnd { public:
wnd() { _inst = this; } int wnd::Run( HINSTANCE hInst ) {
_hInst = hInst; _hwnd = InitAll(); SetTimer( _hwnd, MY_TIMER, 1000, NULL ); _clock.setHWND( _hwnd );
ShowWindow( _hwnd, SW_SHOW ); UpdateWindow( _hwnd );
MSG msg; ZeroMemory( &msg, sizeof( msg ) ); while( msg.message != WM_QUIT ) { if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) != 0 ) { TranslateMessage( &msg ); DispatchMessage( &msg ); } } return UnregisterClass( "_MY_CLOCK_", _hInst );
}
private:
void wnd::doPaint( HDC dc ) { _clock.setNow(); } void wnd::doTimer() { _clock.setNow(); } static int WINAPI wnd::WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) {
switch( msg ) { case WM_DESTROY: PostQuitMessage( 0 ); break; case WM_PAINT: { PAINTSTRUCT ps; HDC dc = BeginPaint( hWnd, &ps ); _inst->doPaint( dc ); EndPaint( hWnd, &ps ); return 0; } case WM_TIMER: _inst->doTimer(); break; default: return DefWindowProc( hWnd, msg, wParam, lParam ); } return 0;
}
HWND InitAll() {
WNDCLASSEX wcex; ZeroMemory( &wcex, sizeof( wcex ) ); wcex.cbSize = sizeof( WNDCLASSEX ); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = ( WNDPROC )WndProc; wcex.hInstance = _hInst; wcex.hCursor = LoadCursor( NULL, IDC_ARROW ); wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 ); wcex.lpszClassName = "_MY_CLOCK_";
RegisterClassEx( &wcex );
RECT rc = { 0, 0, BMP_SIZE, BMP_SIZE }; AdjustWindowRect( &rc, WS_SYSMENU | WS_CAPTION, FALSE ); int w = rc.right - rc.left, h = rc.bottom - rc.top; return CreateWindow( "_MY_CLOCK_", ".: Clock -- PJorente :.", WS_SYSMENU, CW_USEDEFAULT, 0, w, h, NULL, NULL, _hInst, NULL );
}
static wnd* _inst; HINSTANCE _hInst; HWND _hwnd; clock _clock;
}; wnd* wnd::_inst = 0; //-------------------------------------------------------------------------------------------------- int APIENTRY _tWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow ) {
wnd myWnd; return myWnd.Run( hInstance );
} //-------------------------------------------------------------------------------------------------- </lang>
GUISS
<lang guiss>Start,Programs,Accessories,Analogue Clock</lang>
JavaScript
Tested on Gecko. Put the following in a <script> tag somewhere, and call init_clock()
after body load.
<lang JavaScript>var sec_old = 0;
function update_clock() {
var t = new Date();
var arms = [t.getHours(), t.getMinutes(), t.getSeconds()];
if (arms[2] == sec_old) return;
sec_old = arms[2];
var c = document.getElementById('clock'); var ctx = c.getContext('2d'); ctx.fillStyle = "rgb(0,200,200)"; ctx.fillRect(0, 0, c.width, c.height); ctx.fillStyle = "white"; ctx.fillRect(3, 3, c.width - 6, c.height - 6); ctx.lineCap = 'round';
var orig = { x: c.width / 2, y: c.height / 2 }; arms[1] += arms[2] / 60; arms[0] += arms[1] / 60; draw_arm(ctx, orig, arms[0] * 30, c.width/2.5 - 15, c.width / 20, "green"); draw_arm(ctx, orig, arms[1] * 6, c.width/2.2 - 10, c.width / 30, "navy"); draw_arm(ctx, orig, arms[2] * 6, c.width/2.0 - 6, c.width / 100, "maroon"); }
function draw_arm(ctx, orig, deg, len, w, style) { ctx.save(); ctx.lineWidth = w; ctx.lineCap = 'round'; ctx.translate(orig.x, orig.y); ctx.rotate((deg - 90) * Math.PI / 180); ctx.strokeStyle = style; ctx.beginPath(); ctx.moveTo(-len / 10, 0); ctx.lineTo(len, 0); ctx.stroke(); ctx.restore(); }
function init_clock() { var clock = document.createElement('canvas'); clock.width = 100; clock.height = 100; clock.id = "clock"; document.body.appendChild(clock);
window.setInterval(update_clock, 200); }</lang>
Liberty BASIC
LB has a timer to call a routine at regular intervals. The example is a cut-down version of the full clock supplied with LB as an example. <lang lb>
WindowWidth =120 WindowHeight =144 nomainwin
open "Clock" for graphics_nsb_nf as #clock #clock "trapclose [exit]" #clock "fill white" for angle =0 to 330 step 30 #clock "up ; home ; north ; turn "; angle #clock "go 40 ; down ; go 5" next angle
#clock "flush"
timer 1000, [display] wait
[display] ' called only when seconds have changed
time$ =time$() seconds =val( right$( time$, 2)) ' delete the last drawn segment, if there is one if segId >2 then #clock "delsegment "; segId -1 ' center the turtle #clock "up ; home ; down ; north" ' erase each hand if its position has changed if oldSeconds <>seconds then #clock, "size 1 ; color white ; turn "; oldSeconds *6 ; " ; go 38 ; home ; color black ; north" : oldSeconds =seconds ' redraw all three hands, second hand first #clock "size 1 ; turn "; seconds * 6 ; " ; go 38" ' flush to end segment, then get the next segment id # #clock "flush" #clock "segment" input #clock, segId
wait
[exit]
close #clock
end
</lang>
Locomotive Basic
Because the Amstrad CPC does not have an RTC, we first have to ask the user for the current time. The seconds hand is drawn in XOR ink mode so that it can be removed without affecting the other hands.
<lang locobasic>10 mode 1:defint a-y:deg 20 input "Current time (HH:MM)";t$ 30 h=val(mid$(t$,1,2)) 40 m=val(mid$(t$,4,2)) 50 cls 60 r=150:s=-1 70 ph=0:pm=0 80 origin 320,200 90 for a=0 to 360 step 6 100 if a mod 30>0 then z=.9 else z=.8 110 move z*r*sin(a),z*r*cos(a) 120 draw r*sin(a),r*cos(a) 130 next 140 move 0,r 150 for a=0 to 360 step 6 160 draw r*sin(a),r*cos(a) 170 next 180 every 50 gosub 220 190 ' ENDLESS_LOOP 200 goto 200 210 ' NEW_SEC 220 s=s+1 230 if s=60 then s=0:m=m+1 240 if m=60 then m=0:h=h+1 250 if h=24 then h=0 260 if s=0 then gosub 300 270 if s>0 then gosub 420 280 return 290 ' DRAW_ALL 300 locate 1,1 310 print using "##";h; 320 print ":"; 330 print using "##";m; 340 frame:move 0,0:draw .5*r*sin(ph),.5*r*cos(ph),0,0 350 frame:move 0,0:draw .7*r*sin(pm),.7*r*cos(pm),0,0 360 frame:move 0,0:draw .8*r*sin(6*59),.8*r*cos(6*59),0,0 370 pm=6*m 380 frame:move 0,0:draw .7*r*sin(pm),.7*r*cos(pm),1,0 390 ph=30*h+.5*m 400 frame:move 0,0:draw .5*r*sin(ph),.5*r*cos(ph),1,0 410 ' DRAW_SEC 420 a=6*s 430 ' uses "frame" and XOR ink mode for drawing -- requires BASIC 1.1 440 if a>0 then frame:move 0,0:draw .8*r*sin(a-6),.8*r*cos(a-6),3,1 450 frame:move 0,0:draw .8*r*sin(a),.8*r*cos(a),3,1 460 return</lang>
Mathematica
<lang Mathematica>makeHand[fl_, bl_, fw_, bw_] := Polygon[{{-bw, -bl}, {bw, -bl}, {fw, fl}, {0, fl + 8 fw}, {-fw, fl}}/9];
hourHand = makeHand[5, 5/3, .1, .3];minuteHand = makeHand[7, 7/3, .1, .3]; secondHand = {Red, EdgeForm[Black], makeHand[7, 7/3, .1/2, .3/2]};
Graphics[{
{Thickness[.03], Circle[]},(* Rim *)
{Thickness[.003], Table[Line[{.9 {Cos[a], Sin[a]}, .95 {Cos[a], Sin[a]}}], {a, 0, 2 \[Pi], 2 \[Pi]/60}]}, (* Thin ticks *)
{Thickness[.01], Table[Line[{.9 {Cos[a], Sin[a]}, .95 {Cos[a], Sin[a]}}], {a, 0, 2 \[Pi], 2 \[Pi]/12}]}, (* Thick ticks *)
Style[Table[Text[i, .77 {Cos[-i \[Pi]/6 + \[Pi]/2], Sin[-i \[Pi]/6 + \[Pi]/2]}], {i, 1, 12}], FontFamily -> "Helvetica", FontSize -> 36], (* Numbers *)
Rotate[hourHand, Dynamic[Refresh[-30 Mod[AbsoluteTime[]/3600, 60] \[Degree], UpdateInterval -> 60]], {0, 0}],
Rotate[minuteHand, Dynamic[Refresh[-6 Mod[AbsoluteTime[]/60, 60] \[Degree], UpdateInterval -> 1]], {0, 0}],
Rotate[secondHand, Dynamic[Refresh[-6 Mod[AbsoluteTime[], 60] \[Degree], UpdateInterval -> 1/20]], {0, 0}]
}]</lang>
MATLAB / Octave
<lang Matlab> u = [0:360]*pi/180;
while(1) s = mod(now*60*24,1)*2*pi; plot([0,sin(s)],[0,cos(s)],'-',sin(u),cos(u),'k-'); pause(1); end;</lang>
OCaml
Using only the standard library of OCaml with its Graphics module:
<lang ocaml>#!/usr/bin/env ocaml
- load "unix.cma"
- load "graphics.cma"
open Graphics
let pi = 4.0 *. atan 1.0 let angle v max = float v /. max *. 2.0 *. pi
let () =
open_graph ""; set_window_title "OCaml Clock"; resize_window 256 256; auto_synchronize false; let w = size_x () and h = size_y () in let rec loop () = clear_graph ();
let point radius r a = let x = int_of_float (radius *. sin a) and y = int_of_float (radius *. cos a) in fill_circle (w/2+x) (h/2+y) r; in set_color (rgb 192 192 192); point 84.0 8 0.0; point 84.0 8 (angle 90 360.0); point 84.0 8 (angle 180 360.0); point 84.0 8 (angle 270 360.0); set_color (rgb 224 224 224); point 84.0 6 (angle 30 360.0); point 84.0 6 (angle 60 360.0); point 84.0 6 (angle 120 360.0); point 84.0 6 (angle 150 360.0); point 84.0 6 (angle 210 360.0); point 84.0 6 (angle 240 360.0); point 84.0 6 (angle 300 360.0); point 84.0 6 (angle 330 360.0);
set_line_width 9; set_color (rgb 192 192 192); draw_circle (w/2) (h/2) 100;
let tm = Unix.localtime (Unix.gettimeofday ()) in let sec = angle tm.Unix.tm_sec 60.0 in let min = angle tm.Unix.tm_min 60.0 in let hour = angle (tm.Unix.tm_hour * 60 + tm.Unix.tm_min) (24.0 *. 60.0) in let hour = hour *. 2.0 in
let hand t radius width color = let x = int_of_float (radius *. sin t) and y = int_of_float (radius *. cos t) in set_line_width width; set_color color; moveto (w/2) (h/2); rlineto x y; in hand sec 90.0 2 (rgb 0 128 255); hand min 82.0 4 (rgb 0 0 128); hand hour 72.0 6 (rgb 255 0 128);
synchronize (); Unix.sleep 1; loop () in try loop () with _ -> close_graph ()</lang>
GTK + Cairo
Using the libraries GTK2 and Cairo and their OCaml bindings LablGTK and ocaml-cairo.
# compile with: ocamlopt -I +lablgtk2 -I +cairo -o gtkclock.opt \ unix.cmxa lablgtk.cmxa cairo.cmxa cairo_lablgtk.cmxa gtkInit.cmx gtkclock.ml
<lang ocaml>let pi = 4.0 *. atan 1.0 let angle v max = float v /. max *. 2.0 *. pi
let draw area _ =
let cr = Cairo_lablgtk.create area#misc#window in let { Gtk.width = width; Gtk.height = height } = area#misc#allocation in let scale p = float (min width height) *. 0.5 *. p in let center_x, center_y = float width /. 2.0, float height /. 2.0 in let invert_y y = float height -. y in
Cairo.set_source_rgb cr 0.8 0.8 0.8; Cairo.paint cr; (* background *)
Cairo.set_source_rgb cr 1.0 1.0 1.0;
Cairo.arc cr center_x center_y (scale 0.9) 0.0 (2.0 *. pi); Cairo.set_line_width cr (scale 0.02); Cairo.stroke cr;
let point a = let radius = (scale 0.9) in let x = radius *. sin a and y = radius *. cos a in let r = scale 0.04 in Cairo.arc cr (center_x +. x) (invert_y (center_y +. y)) r 0.0 (2.0 *. pi); Cairo.fill cr; in for i = 0 to pred 12 do point (angle (i * 30) 360.0) done;
let tm = Unix.localtime (Unix.gettimeofday ()) in let sec = angle tm.Unix.tm_sec 60.0 in let min = angle tm.Unix.tm_min 60.0 in let hour = angle (tm.Unix.tm_hour * 60 + tm.Unix.tm_min) (12.0 *. 60.0) in
Cairo.set_line_cap cr Cairo.LINE_CAP_ROUND;
let hand t radius lwidth (r, g, b) = let x = radius *. sin t and y = radius *. cos t in Cairo.set_line_width cr (scale lwidth); Cairo.move_to cr center_x center_y; Cairo.line_to cr (center_x +. x) (invert_y (center_y +. y)); Cairo.set_source_rgb cr r g b; Cairo.stroke cr; in hand sec (scale 0.9) 0.04 (0.0, 0.5, 1.0); hand min (scale 0.7) 0.06 (0.0, 0.0, 0.5); hand hour (scale 0.6) 0.09 (1.0, 0.0, 0.5); true
let animate area =
ignore (GMain.Timeout.add 200 (fun () -> GtkBase.Widget.queue_draw area#as_widget; true))
let () =
let w = GWindow.window ~title:"OCaml GtkCairo Clock" () in ignore (w#connect#destroy GMain.quit); let f = GBin.frame ~shadow_type:`IN ~packing:w#add () in let area = GMisc.drawing_area ~width:200 ~height:200 ~packing:f#add () in area#misc#set_double_buffered true; ignore (area#event#connect#expose (draw area)); animate area; w#show (); GMain.main ()</lang>
PicoLisp
This is an animated ASCII drawing of the "Berlin-Uhr", a clock built to display the time according to the principles of set theory, which is installed in Berlin since 1975. See www.surveyor.in-berlin.de/berlin/uhr/indexe.html and www.cs.utah.edu/~hatch/berlin_uhr.html. <lang PicoLisp>(de draw Lst
(for L Lst (for X L (cond ((num? X) (space X)) ((sym? X) (prin X)) (T (do (car X) (prin (cdr X)))) ) ) (prinl) ) )
(de bigBox (N)
(do 2 (prin "|") (for I 4 (prin (if (> I N) " |" " ======== |")) ) (prinl) ) )
(call 'clear) # Clear screen (call "tput" "civis") # Set cursor invisible
(push '*Bye '(call "tput" "cnorm")) # Set cursor visible on exit
(loop
(call "tput" "cup" 0 0) # Cursor to top left (let Time (time (time)) (draw (20 (5 . _)) (19 / 5 \\)) (if (onOff (NIL)) (draw (18 / 7 \\) (18 \\ 7 /)) (draw (18 / 2 (3 . "#") 2 \\) (18 \\ 2 (3 . "#") 2 /)) ) (draw (19 \\ (5 . _) /) (+ (10 . -) + (10 . -) + (10 . -) + (10 . -) +) ) (bigBox (/ (car Time) 5)) (draw (+ (10 . -) + (10 . -) + (10 . -) + (10 . -) +)) (bigBox (% (car Time) 5)) (draw (+ (43 . -) +)) (do 2 (prin "|") (for I `(range 5 55 5) (prin (cond ((> I (cadr Time)) " |") ((=0 (% I 3)) " # |") (T " = |") ) ) ) (prinl) ) (draw (+ (43 . -) +)) (bigBox (% (cadr Time) 5)) (draw (+ (10 . -) + (10 . -) + (10 . -) + (10 . -) +)) ) (wait 1000) )</lang>
The six '#' characters in the "circle" on top toggle on/off every second. This is the display at 17:46:
_____ / \ / ### \ \ ### / \_____/ +----------+----------+----------+----------+ | ======== | ======== | ======== | | | ======== | ======== | ======== | | +----------+----------+----------+----------+ | ======== | ======== | | | | ======== | ======== | | | +-------------------------------------------+ | = | = | # | = | = | # | = | = | # | | | | = | = | # | = | = | # | = | = | # | | | +-------------------------------------------+ | ======== | | | | | ======== | | | | +----------+----------+----------+----------+
PureBasic
<lang purebasic>#MiddleX = 90 + 1 ;x,y must be odd numbers, minimum width is 67
- MiddleY = #MiddleX
- len_sh = (#MiddleX - 8) * 0.97 ;length of second-hand
- len_mh = (#MiddleX - 8) * 0.88 ;length of minute-hand
- len_hh = (#MiddleX - 8) * 0.66 ;length of hour-hand
- clockFace_img = 0
- clock_gad = 0
- clock_win = 0
Define cx = #MiddleX, cy = #MiddleY, i, ri.f Define c_gray = RGB($CC, $CC, $CC), c_mgray = RGB($99, $99, $99) Define c_white = RGB(255, 255, 255), c_black =RGB(0, 0, 0) Define c_red = RGB(255, 0, 0), c_blue = RGB(0, 0, 255) Define c_dcyan = RGB($27, $BC, $D8), c_lgreen = RGB($60, $E0, $9) Define c_yellow = RGB($F4, $D5, $0B)
CreateImage(#clockFace_img, cx * 2 - 1, cy * 2 - 1) StartDrawing(ImageOutput(#clockFace_img))
Box(0, 0, cx * 2 - 1, cy * 2 - 1, c_mgray) Circle(cx, cy, cx - 2, c_dcyan) For i = 0 To 359 Step 30 ri = Radian(i) Circle(cx + Sin(ri) * (cx - 5), cy + Cos(ri) * (cx - 5), 3, c_gray) Next
StopDrawing() OpenWindow(#clock_win, 0, 0, cx * 2, cy * 2, "Clock") ImageGadget(#clock_gad, 0, 0, cx * 2, cy * 2, ImageID(#clockFace_img))
Define x, y, rad_s.f, rad_m.f, rad_h.f, t$ Repeat
event = WaitWindowEvent(25) If event = 0 rad_s = Radian(360 - (Second(Date()) * 6) + 180) rad_m = Radian(360 - (Minute(Date()) * 6) + 180) rad_h = Radian(360 - (((Hour(Date()) - 1) * 30) + 180) - (Minute(Date()) / 2))
StartDrawing(ImageOutput(#clockFace_img)) Circle(cx, cy, cx - 8, c_lgreen) t$ = FormatDate("%mm-%dd-%yyyy", Date()) x = cx - (TextWidth(t$) + 2) / 2 y = (cy - (TextHeight(t$) + 2) - 4) / 2 Box(x, y, TextWidth(t$) + 2, TextHeight(t$) + 2, c_black) DrawText(x + 2, y + 2, t$, c_black, c_yellow) LineXY(cx, cy, cx + Sin(rad_s) * #len_sh, cy + Cos(rad_s) * #len_sh, c_white) LineXY(cx, cy, cx + Sin(rad_m) * #len_mh, cy + Cos(rad_m) * #len_mh, c_red) LineXY(cx, cy, cx + Sin(rad_h) * #len_hh, cy + Cos(rad_h) * #len_hh, c_black) Circle(cx, cy, 4, c_blue) StopDrawing() SetGadgetState(#clock_gad, ImageID(#clockFace_img)) EndIf
Until event = #PB_Event_CloseWindow</lang>
Python
<lang python>import time
def chunks(l, n=5):
return [l[i:i+n] for i in range(0, len(l), n)]
def binary(n, digits=8):
n=int(n) return '{0:0{1}b}'.format(n, digits)
def secs(n):
n=int(n) h='x' * n return "|".join(chunks(h))
def bin_bit(h):
h=h.replace("1","x") h=h.replace("0"," ") return "|".join(list(h))
x=str(time.ctime()).split()
y=x[3].split(":")
s=y[-1] y=map(binary,y[:-1])
print bin_bit(y[0]) print print bin_bit(y[1]) print print secs(s)</lang>
Racket
Draws an analog clock in a new GUI window:
<lang racket>
- lang racket/gui
(require racket/date slideshow/pict)
(define (clock h m s [r 100])
(define (draw-hand length angle #:width [width 1] #:color [color "black"]) (dc (λ (dc dx dy) (define old-pen (send dc get-pen)) (send dc set-pen (new pen% [width width] [color color])) (send dc draw-line (+ dx r) (+ dy r) (+ dx r (* length (sin angle))) (+ dy r (* length (cos angle)))) (send dc set-pen old-pen)) (* 2 r) (* 2 r))) (cc-superimpose (for/fold ([pict (circle (* 2 r))]) ([angle (in-range 0 (* 2 pi) (/ pi 6))] [hour (cons 12 (range 1 12))]) (define angle* angle) (define r* (* r 0.8)) (define txt (text (number->string hour) '(bold . "Helvetica"))) (define x (- (* r* (sin angle*)) (/ (pict-width txt) 2))) (define y (+ (* r* (cos angle*)) (/ (pict-height txt) 2))) (pin-over pict (+ r x) (- r y) txt)) (draw-hand (* r 0.7) (+ pi (* (modulo h 12) (- (/ pi 6)))) #:width 3) (draw-hand (* r 0.5) (+ pi (* m (- (/ pi 30)))) #:width 2) (draw-hand (* r 0.7) (+ pi (* s (- (/ pi 30)))) #:color "red") (disk (* r 0.1))))
(define f (new frame% [label "Clock"] [width 300] [height 300]))
(define c
(new canvas% [parent f] [paint-callback (λ (c dc) (define date (current-date)) (draw-pict (clock (date-hour date) (date-minute date) (date-second date) (/ (send c get-width) 2)) dc 0 0))]))
(define t
(new timer% [notify-callback (λ () (send c refresh-now))] [interval 1000]))
(send f show #t) </lang>
REXX
This REXX program draws a digital clock; it shows the seconds if the terminal screen is
wide enough.
The $T.REX program does the heavy lifting of actually creating the blocked characters.
If using
- PC/REXX
- Personal REXX
- R4
- ROO
the color of the display can be specified.
The $CLOCK.REX REXX program makes use of $T REXX program which is used to display text and/or create big blocked characters.
The $T.REX REXX program is included here ──► $T.REX.
The help for the $T.REX REXX program is included here ──► $T.HEL.
The $CLOCK.REX REXX program makes use of $ERR.REX REXX program which is used to display error messages (via $T.REX).
The $ERR REXX program is included here ──► $ERR.REX.
Some older REXXes don't have a changestr BIF, so one is included here ──► CHANGESTR.REX.
REXX programs not included are $H.REX which shows help and other documentation.
<lang rexx>/**/trace o;parse arg !;if !all(arg()) then exit;if !cms then address
signal on halt; signal on novalue; signal on syntax
parse var ! ops; ops = space(ops) /*obtain command line options. */
@abc = 'abcdefghijklmnopqrstuvwxyz' /*alphabet str used by ABB/ABBN. */
blinkSecs = 1
creep = 1
tops = '.C=blue .BC=░ .BS=1 .BLOCK=12'
do while ops\==; parse var ops _1 2 1 _ . 1 y ops; upper _ select when _==',' then nop when _1=='.' & pos("=",_)\==0 then tops=tops y when abbn('BLINKSECs') then blinksecs=no() when abbn('CREEPs') then creep=no() otherwise call er 55,y end /*select*/ end /*while ops¬==*/
if \!pcrexx then blinkSecs=0 /*if ¬PC/REXX, turn off BLINKSECS*/ tops=space(tops) /*elide extraneous TOPS blanks.*/ parse value scrsize() with sd sw . /*get the term screens dimensions*/ oldTime=
do until queued()\==0 ct=time(); mn=substr(ct,4,2); ss=right(ct,2); i_=0; p_=0 call blinksec if ct==oldTime then if !cms then 'CP SLEEP'; else call delay 1
if creep then do; p_ = 3 + right(mn,1) if sd>26 then p_ = p_ + left(mn,1) if sd>33 then p_ = p_ + left(mn,1) if sd>44 then p_ = p_ + left(mn,1) +right(mn,1) end _p=-p_ i_=2+left(ct,1); ctt=left(ct,5); if sw>108 then ctt=ct r=$t('.P='_p ".I="i_ tops ctt); if r\==0 then leave oldTime=time() end /*forever*/
exit /*stick a fork in it, we're done.*/ /*═════════════════════════════general 1-line subs════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════*/ !all:!!=!;!=space(!);upper !;call !fid;!nt=right(!var('OS'),2)=='NT';!cls=word('CLS VMFCLEAR CLRSCREEN',1+!cms+!tso*2);if arg(1)\==1 then return 0;if wordpos(!,'? ?SAMPLES ?AUTHOR ?FLOW')==0 then return 0;!call=']$H';call '$H' !fn !;!call=;return 1 !cal: if symbol('!CALL')\=="VAR" then !call=;return !call !env: !env='ENVIRONMENT';if !sys=='MSDOS'|!brexx|!r4|!roo then !env='SYSTEM';if !os2 then !env='OS2'!env;!ebcdic=1=='f0'x;return !fid: parse upper source !sys !fun !fid . 1 . . !fn !ft !fm .;call !sys;if !dos then do;_=lastpos('\',!fn);!fm=left(!fn,_);!fn=substr(!fn,_+1);parse var !fn !fn '.' !ft;end;return word(0 !fn !ft !fm,1+('0'arg(1))) !rex: parse upper version !ver !vernum !verdate .;!brexx='BY'==!vernum;!kexx='KEXX'==!ver;!pcrexx='REXX/PERSONAL'==!ver|'REXX/PC'==!ver;!r4='REXX-R4'==!ver;!regina='REXX-REGINA'==left(!ver,11);!roo='REXX-ROO'==!ver;call !env;return !sys: !cms=!sys=='CMS';!os2=!sys=='OS2';!tso=!sys=='TSO'|!sys=='MVS';!vse=!sys=='VSE';!dos=pos('DOS',!sys)\==0|pos('WIN',!sys)\==0|!sys=='CMD';call !rex;return !var: call !fid;if !kexx then return space(dosenv(arg(1)));return space(value(arg(1),,!env)) $t: !call=']$T';call "$T" arg(1);!call=;return result abb: arg abbu;parse arg abb;return abbrev(abbu,_,abbl(abb)) abbl: return verify(arg(1)'a',@abc,'M')-1 abbn: parse arg abbn;return abb(abbn)|abb('NO'abbn) blinksec: if \blinksecs then return;bsec=' ';ss2=right(ss,2);if sw<=80 then bsec=copies(' ',2+ss2) ss2;call scrwrite 1+right(mn,1),1,bsec,,,1;call cursor sd-right(mn,1),sw-length(bsec);return er: parse arg _1,_2;call '$ERR' "14"p(_1) p(word(_1,2) !fid(1)) _2;if _1<0 then return _1;exit result err: call er '-'arg(1),arg(2);return erx: call er '-'arg(1),arg(2);exit halt: call er .1 no: if arg(1)\== then call er 01,arg(2);return left(_,2)\=='NO' novalue:!sigl=sigl;call er 17,!fid(2) !fid(3) !sigl condition('D') sourceline(!sigl) p: return word(arg(1),1) syntax:!sigl=sigl;call er 13,!fid(2) !fid(3) !sigl !cal() condition('D') sourceline(!sigl)</lang> output
░░░░░░░░ ░░░░░░░░ ░░ ░░░░░░░░░░ ░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░ ░░░░░░░░░░ ░░░░ ░░░░░░░░░░ ░░ ░░ ░░ ░░ ░░░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░░ ░░ ░░░░░░░ ░░░░░░░░░░ ░░░░░░░ ░░ ░░░ ░░ ░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░ ░░░░░░ ░░░░░░░░░░ ░░ ░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░ ░░░░░░ ░░░░░░░░ ░░░░ ░░░░░░░░
output (when the terminal screen is less then 109 bytes)
░░░░░░░░ ░░░░░░░░ ░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░░ ░░ ░░░░░░░ ░░ ░░░ ░░ ░░░░░░░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░ ░░░░░░░░░░ ░░░░░░░░
Ruby
<lang ruby>Shoes.app(:width=>205, :height => 228, :title => "A Clock") do
def draw_ray(width, start, stop, ratio) angle = Math::PI * 2 * ratio - Math::PI/2 strokewidth width cos = Math::cos(angle) sin = Math::sin(angle) line 101+cos*start, 101+sin*start, 101+cos*stop, 101+sin*stop end
def update t = Time.now @time.text = t.strftime("%H:%M:%S") h, m, s = (t.hour % 12).to_f, t.min.to_f, t.sec.to_f s += t.to_f - t.to_i # add the fractional seconds
@hands.clear do draw_ray(3, 0, 70, (h + m/60)/12) draw_ray(2, 0, 90, (m + s/60)/60) draw_ray(1, 0, 95, s/60) end end
# a place for the text display @time = para(:align=>"center", :family => "monospace")
# draw the clock face stack(:width=>203, :height=>203) do strokewidth 1 fill gradient(deepskyblue, aqua) oval 1, 1, 200 fill black oval 98, 98, 6 # draw the minute indicators 0.upto(59) {|m| draw_ray(1, (m % 5 == 0 ? 96 : 98), 100, m.to_f/60)} end.move(0,23)
# the drawing area for the hands @hands = stack(:width=>203, :height=>203) {}.move(0,23)
animate(5) {update}
end</lang>
Inspired by the PicoLisp solution, here's an implementation of the Berlin-Uhr clock.
<lang ruby>Shoes.app(:title => "Berlin-Uhr Clock", :width => 209, :height => 300) do
background lightgrey
Red = rgb(255, 20, 20) Yellow = rgb(173, 255, 47) Green = rgb(154, 205, 50) Gray = rgb(128, 128, 128)
@time = para(:align => "center") stack do fill Gray stroke black strokewidth 2 @seconds = oval 75, 3, 50 @hrs_a = 4.times.collect {|i| rect 51*i, 56, 48, 30, 4} @hrs_b = 4.times.collect {|i| rect 51*i, 89, 48, 30, 4} @mins_a = 11.times.collect {|i| rect 2+18*i, 122, 15, 30, 4} @mins_b = 4.times.collect {|i| rect 51*i, 155, 48, 30, 4} # some decoration fill white stroke darkslategray rect -10, -30, 75, 70, 10 rect 140, -30, 75, 70, 10 rect -13, 192, 105, 100, 10 rect 110, 192, 105, 100, 10 end.move(3,20) animate(1) do now = Time.now @time.text = now.strftime("%H:%M:%S") @seconds.style(:fill => now.sec.even? ? Green : Gray) a, b = now.hour.divmod(5) 4.times {|i| @hrs_a[i].style(:fill => i < a ? Red : Gray)} 4.times {|i| @hrs_b[i].style(:fill => i < b ? Red : Gray)} a, b = now.min.divmod(5) 11.times {|i| @mins_a[i].style(:fill => i < a ? (i%3==2 ? Red : Yellow) : Gray)} 4.times {|i| @mins_b[i].style(:fill => i < b ? Yellow : Gray)} end keypress do |key| case key when :control_q, "\x11" then exit end end
end</lang>
Run BASIC
<lang runbasic>' -------------------------------------------- ' clock. I got nothing but time ' --------------------------------------------- n = 12 ' num of points r = 95 ' radius pi = 22/7 alpha = pi * 2 / n dim points(n) graphic #g2, 200, 200 ' -------------------------------------- ' Draw the clock ' --------------------------------------
- g2 size(2) 'pen size
- g2 down()
- g2 font("arial", 20, "bold")
- g2 place(85,30)
- g2 "\12"
- g2 place(170,105)
- g2 "\3"
- g2 place(10,105)
- g2 "\9"
- g2 place(90,185)
- g2 "\6"
for i = 0 to n - 1 theta = alpha * i px = cos( theta ) * r py = sin( theta ) * r px = px + 100 py = py + 100 #g2 place(px,py) #g2 circle(2) next i
[shoTime] ' ------------------------- ' clear previous sec,min,hr ' ------------------------- r = 63 p = se
- g2 color("white")
gosub [h2Dot] r = 50 p = mi
- g2 color("white")
gosub [h2Dot] r = 30 ' radius p = hr * 5
- g2 color("white")
gosub [h2Dot]
' ------------------------- ' Show new time ' ------------------------- a$ = time$() hr = val(word$(a$,1,":")) mi = val(word$(a$,2,":")) se = val(word$(a$,3,":"))
' put time on the clock - gimme a hand
- g2 size(4)
' second hand n = 60 r = 63 p = se
- g2 color("blue")
gosub [h2Dot]
' minute hand r = 50 p = mi
- g2 color("green")
gosub [h2Dot]
' hour hand r = 30 ' radius p = hr * 5
- g2 color("red")
gosub [h2Dot]
render #g2 end
' a one liner [h2Dot] alpha = pi * 2 / n i = p - 15 theta = alpha * i px = cos( theta ) * r py = sin( theta ) * r px = px + 100 py = py + 100
- g2 place(px,py)
- g2 circle(2)
- g2 line(100,100,px,py)
RETURN</lang>
Scala
Generates and prints a simple ascii clock every second <lang scala>import scala.math._ import java.util.Calendar import java.util.Timer import java.util.TimerTask
object Clock {
val WIDTH: Int = 80 val HEIGHT: Int = 35 def makeText(grid: Array[Array[Char]], r: Double, theta: Double, str: String): Unit = { val (row, col) = toGridCoord(r * cos(theta), r * sin(theta)) (0 until str.length).foreach(i => { if (row >= 0 && row < HEIGHT && col + i >= 0 && col + i < WIDTH) grid(row)(col + i) = str(i) }) } def makeCircle(grid: Array[Array[Char]], r: Double, c: Char): Unit = { var theta = 0.0; while (theta < 2 * Pi) { val(row, col) = toGridCoord(r * cos(theta), r * sin(theta)) if (row >= 0 && row < HEIGHT && col >= 0 && col < WIDTH) grid(row)(col) = c theta = theta + 0.01 } } def makeHand(grid: Array[Array[Char]], maxR: Double, theta: Double, c: Char): Unit = { var r = 0.0; while (r < maxR) { val(row, col) = toGridCoord(r * cos(theta), r * sin(theta)) if (row >= 0 && row < HEIGHT && col >= 0 && col < WIDTH) grid(row)(col) = c r = r + 0.01 } } def toGridCoord(x: Double, y: Double): (Int, Int) = { (floor((y + 1.0) / 2.0 * HEIGHT).toInt, floor((x + 1.0) / 2.0 * WIDTH).toInt) } def printGrid(grid: Array[Array[Char]]): Unit = { grid.foreach(row => println(row.mkString)) } def getGrid(calendar: Calendar): Array[Array[Char]] = { val grid = Array.tabulate(HEIGHT, WIDTH)((_,_) => ' ') makeCircle(grid, 0.98, '@') val hour = calendar.get(Calendar.HOUR); val minute = calendar.get(Calendar.MINUTE); val second = calendar.get(Calendar.SECOND); makeHand(grid, 0.6, (hour + minute / 60.0 + second / 3600.0) * Pi / 6 - Pi / 2, 'O') makeHand(grid, 0.85, (minute + second / 60.0) * Pi / 30 - Pi / 2, '*') makeHand(grid, 0.90, second * Pi / 30 - Pi / 2, '.') (1 to 12).foreach(n => { makeText(grid, 0.87, n * Pi / 6 - Pi / 2, n.toString) }) grid } def main(args: Array[String]) = { val timer = new Timer val timerTask = new TimerTask { def run() = printGrid(getGrid(Calendar.getInstance)) } timer.schedule(timerTask, 0, 1000) }
}</lang>
SVG
<lang svg><svg viewBox="0 0 100 100" width="480px" height="480px" xmlns="http://www.w3.org/2000/svg"> <circle cx="50" cy="50" r="48" style="fill:peru; stroke:black; stroke-width:2" /> <g transform="translate(50,50) rotate(0)" style="fill:none; stroke-linecap:round">
<line y2="-36" style="stroke:black; stroke-width:5"> <animateTransform attributeName="transform" type="rotate" by="30" dur="3600s" accumulate="sum" repeatCount="indefinite"/> </line> <line y2="-42" style="stroke:white; stroke-width:2"> <animateTransform attributeName="transform" type="rotate" by="6" dur="60s" accumulate="sum" repeatCount="indefinite"/> </line> <line y2="-46" style="stroke:red; stroke-width:1"> <animateTransform attributeName="transform" type="rotate" calcMode="discrete" by="6" dur="1s" accumulate="sum" repeatCount="indefinite"/> </line>
</g> <circle cx="50" cy="50" r="4" style="fill:gold; stroke:black; stroke-width:1" /> </svg> </lang>
Tcl
<lang tcl>package require Tcl 8.5 package require Tk
- GUI code
pack [canvas .c -width 200 -height 200] .c create oval 20 20 180 180 -width 10 -fill {} -outline grey70 .c create line 0 0 1 1 -tags hour -width 6 -cap round -fill black .c create line 0 0 1 1 -tags minute -width 4 -cap round -fill black .c create line 0 0 1 1 -tags second -width 2 -cap round -fill grey30 proc updateClock t {
scan [clock format $t -format "%H %M %S"] "%d%d%d" h m s # On an analog clock, the hour and minute hands move gradually set m [expr {$m + $s/60.0}] set h [expr {($h % 12 + $m/60.0) * 5}] foreach tag {hour minute second} value [list $h $m $s] len {50 80 80} {
.c coords $tag 100 100 \ [expr {100 + $len*sin($value/30.0*3.14159)}] \ [expr {100 - $len*cos($value/30.0*3.14159)}]
}
}
- Timer code, accurate to within a quarter second
set time 0 proc ticker {} {
global time set t [clock seconds] after 250 ticker if {$t != $time} {
set time $t updateClock $t
}
} ticker</lang> Note that though this code does poll the system timer approximately four times a second, this is a cheap operation; the GUI update (the relatively expensive part) only happens once a second. The amount of system processing power consumed by this code isn't noticeable on my system; it vanishes with respect to the other processing normally happening.