analog clock

Post your FreeBASIC tips and tricks here. Please don’t post your code without including an explanation.
BasicCoder2
Posts: 3586
Joined: Jan 01, 2009 7:03
Location: Australia

analog clock

Postby BasicCoder2 » Apr 13, 2015 4:02

Code: Select all

Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 500,500,32
color rgb(0,0,0),rgb(255,255,255):cls  ' black ink, white paper

do
    screenlock
    cls
    dim as double dx1,dy1,dx2,dy2
    dim as double px,py
    px = 250
    py = 250
    dim as double angle
    for i as double = 0 to 360 step 360\60
        angle = 180 - i
        dx1 = sin(angle*DtoR)*90
        dy1 = cos(angle*DtoR)*90
        dx2 = sin(angle*DtoR)*99
        dy2 = cos(angle*DtoR)*99
        line (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
    next i
   
    for i as double = 0 to 360 step 360\12
        angle = 180 - i
        dx1 = sin(angle*DtoR)*85
        dy1 = cos(angle*DtoR)*85
        dx2 = sin(angle*DtoR)*99
        dy2 = cos(angle*DtoR)*99
        line (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
    next i
   
    for i as double = 30 to 360 step 360\12
        angle = 180 - i
        dx1 = sin(angle*DtoR)*75
        dy1 = cos(angle*DtoR)*75
        draw string (px+dx1-4,py+dy1-4), str(i/30)
    next i

    dim as string cTime,ampm
    dim as integer hours,minutes,seconds
    ctime = TIME
    ampm = "AM"
    hours = VAL(LEFT(ctime, 2))
    IF hours > 12 THEN
        ampm = "PM"
        hours = hours - 12
    END IF
    IF hours = 0 THEN hours = 12
    minutes = VAL(MID(ctime, 4, 2))
    seconds = VAL(RIGHT(ctime, 2))
    circle (px,py),99,rgb(0,0,0)
    circle (px,py),5,rgb(0,0,0),,,,f
   
    angle = 180-seconds*6
    dx1 = sin(angle*DtoR)*90
    dy1 = cos(angle*DtoR)*90
    line (px,py)-(px+dx1,py+dy1),rgb(255,0,0)' second hand
   
    angle = 180-hours*30
    dx1 = sin(angle*DtoR)*50
    dy1 = cos(angle*DtoR)*50
    line (px,py)-(px+dx1,py+dy1),rgb(0,0,255)' hour hand
   
    angle = 180-minutes*6
    dx1 = sin(angle*DtoR)*70
    dy1 = cos(angle*DtoR)*70
    line (px,py)-(px+dx1,py+dy1),rgb(0,255,255)' minutes hand
   
    locate 2,2
    print hours;" : ";minutes;" : ";seconds
    screenunlock
   
    sleep 2
loop until multikey(&H01)

sleep
BasicCoder2
Posts: 3586
Joined: Jan 01, 2009 7:03
Location: Australia

Re: analog clock

Postby BasicCoder2 » Apr 13, 2015 10:12

This is my attempt to imitate dodicat's pendulum clock...

Code: Select all

Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 640,500,32
color rgb(0,0,0),rgb(255,255,255):cls  ' black ink, white paper

dim as double dx1,dy1,dx2,dy2
dim as double px,py
dim as double sAngle,nAngle,angle
dim as double now1
   
do
    screenlock
    cls

    'compute px,py position
    nAngle = sin(sAngle*DtoR)*200
    nAngle = nAngle\6
    px = sin(nAngle*DtoR)*350+320
    py = cos(nAngle*DtoR)*350+10
    line (320,10)-(px,py),rgb(0,0,0)
    circle (px,py),5,rgb(0,0,0)
    sAngle = sAngle + 6
    if sAngle = 360 then sAngle = 0
   
   
    for i as double = 0 to 360 step 360\60
        angle = 180 - i + nAngle
        dx1 = sin(angle*DtoR)*90
        dy1 = cos(angle*DtoR)*90
        dx2 = sin(angle*DtoR)*99
        dy2 = cos(angle*DtoR)*99
        line (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
    next i
   
    for i as double = 0 to 360 step 360\12
        angle = 180 - i
        angle = angle + nAngle
        dx1 = sin(angle*DtoR)*85
        dy1 = cos(angle*DtoR)*85
        dx2 = sin(angle*DtoR)*99
        dy2 = cos(angle*DtoR)*99
        line (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
    next i
   
    for i as double = 30 to 360 step 360\12
        angle = 180 - i + nAngle
        dx1 = sin(angle*DtoR)*75
        dy1 = cos(angle*DtoR)*75
        draw string (px+dx1-4,py+dy1-4), str(i/30)
    next i

    'get hours, minutes and seconds
    dim as string cTime,ampm
    dim as integer hours,minutes,seconds
    ctime = TIME
    ampm = "AM"
    hours = VAL(LEFT(ctime, 2))
    IF hours > 12 THEN
        ampm = "PM"
        hours = hours - 12
    END IF
    IF hours = 0 THEN hours = 12
    minutes = VAL(MID(ctime, 4, 2))
    seconds = VAL(RIGHT(ctime, 2))
    circle (px,py),99,rgb(0,0,0)
    circle (px,py),5,rgb(0,0,0),,,,f
   
    'draw seconds hand
    angle = 180-seconds*6 + nAngle
    dx1 = sin(angle*DtoR)*90
    dy1 = cos(angle*DtoR)*90
    line (px,py)-(px+dx1,py+dy1),rgb(255,0,0)
   
    'draw hours hand
    angle = 180-hours*30 + nAngle
    dx1 = sin(angle*DtoR)*50
    dy1 = cos(angle*DtoR)*50
    line (px,py)-(px+dx1,py+dy1),rgb(0,0,255)
   
    'draw minutes hand
    angle = 180-minutes*6 + nAngle
    dx1 = sin(angle*DtoR)*70
    dy1 = cos(angle*DtoR)*70
    line (px,py)-(px+dx1,py+dy1),rgb(0,255,255)
   
    locate 2,2
    print hours;" : ";minutes;" : ";seconds; "  ";ampm
    screenunlock
   
    while timer < now1 + 0.05
    wend
    now1 = timer
   
    sleep 2
loop until multikey(&H01)

sleep
MrSwiss
Posts: 3604
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: analog clock

Postby MrSwiss » Apr 14, 2015 9:00

Hello BasicCoder2,
had a look at your analog clock.

My observations are as follows:
    why Double's as loop counters (Long's do the trick, integer stepping)?
    why the unnecessary divisions (waste of resources)?
    the hour hand isn't moving (looks unusual at: 11:59:59 specially), it jumps (could not figure out the cause)
    AMPM missing in digital time string
    String formatting (digital time string)
    Why the ultra short Sleep-Time?
Below my adapted version:

Code: Select all

Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 280,280,32
color rgb(0,0,0),rgb(255,255,255):cls  ' black ink, white paper

do
   screenlock
   cls
   dim as double dx1,dy1,dx2,dy2
   dim as double px,py
   px = 140
   py = 140
   dim as double angle
   for i as long = 0 to 360 step 60   ' 360\60
      angle = 180 - i
      dx1 = sin(angle*DtoR)*90
      dy1 = cos(angle*DtoR)*90
      dx2 = sin(angle*DtoR)*99
      dy2 = cos(angle*DtoR)*99
      line (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
   next i
   
   for i as long = 0 to 360 step 30   ' 360\12
      angle = 180 - i
      dx1 = sin(angle*DtoR)*85
      dy1 = cos(angle*DtoR)*85
      dx2 = sin(angle*DtoR)*99
      dy2 = cos(angle*DtoR)*99
      line (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
   next i
   
   for i as long = 30 to 360 step 30   ' 360\12
      angle = 180 - i
      dx1 = sin(angle*DtoR)*75
      dy1 = cos(angle*DtoR)*75
      draw string (px+dx1-4,py+dy1-4), str(i/30)
   next i

   dim as string cTime,ampm,cHour,cMinute,cSecond
   dim as integer hours,minutes,seconds
   ctime = TIME
   ampm = "AM"
   hours = VAL(LEFT(ctime, 2))
   IF hours > 12 THEN
      ampm = "PM"
      hours = hours - 12
   END IF
   IF hours = 0 THEN hours = 12
   minutes = VAL(MID(ctime, 4, 2))
   seconds = VAL(RIGHT(ctime, 2))
   circle (px,py),99,rgb(0,0,0)
   circle (px,py),3,RGB(0,0,0),,,,f
   ' Begin - Time string formating
   If hours < 10 then
      cHour = " "+str(hours)
   Else
      cHour = str(hours)
   EndIf
   If minutes < 10 then
      cMinute = "0"+str(minutes)
   Else
      cMinute = str(minutes)
   EndIf
   If seconds < 10 then
      cSecond = "0"+str(seconds)
   Else
      cSecond = str(seconds)
   EndIf
   ' End - Time string formating
   angle = 180-seconds*6
   dx1 = sin(angle*DtoR)*90
   dy1 = cos(angle*DtoR)*90
   line (px,py)-(px+dx1,py+dy1),rgb(255,0,0)' second hand

   angle = 180-hours*30
   dx1 = sin(angle*DtoR)*50
   dy1 = cos(angle*DtoR)*50
   line (px,py)-(px+dx1,py+dy1),rgb(0,0,255)' hour hand
   
   angle = 180-minutes*6
   dx1 = sin(angle*DtoR)*70
   dy1 = cos(angle*DtoR)*70
   line (px,py)-(px+dx1,py+dy1),rgb(0,255,255)' minutes hand
   
   locate 2,2
   ' add ampm to concatenated string
   print cHour+":"+cMinute+":"+cSecond+" "+ampm
   screenunlock
   
   sleep 250,1
Loop until multikey(&H01)

sleep
 
BasicCoder2
Posts: 3586
Joined: Jan 01, 2009 7:03
Location: Australia

Re: analog clock

Postby BasicCoder2 » Apr 14, 2015 10:28

@MrSwiss,

The reason for the double variables in the loop counters was because in the original program the angle variable was the loop counter which in the past caused failures if it was an integer due to the trig functions using floating point numbers. There must be some automatic type reassignment taking place with, angle = 180 - i.

As for the sleep command I have no idea why it is even needed, something to do with the program not hogging the cpu I think.
Just a pain as far as I am concerned. If I don't plonk sleep in the loop the program behaves erratically.

Didn't notice the hour hand not moving will have to check it out.

The divisions were there while I was figuring out what the value should be i just didn't change it. Also they do flag how the value is determined.

Thanks for your input.
MrSwiss
Posts: 3604
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: analog clock

Postby MrSwiss » Apr 14, 2015 11:01

@BasicCoder2,
BasicCoder2 wrote:As for the sleep command I have no idea why it is even needed, something to do with the program not hogging the cpu I think.

Yes that's correct, it's a tradeoff between freeing CPU (the aim is: as much as possible) and agility to ESC key press.
250 seems to be a good compromise (in this case).
fxm
Posts: 9927
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: analog clock

Postby fxm » Apr 14, 2015 11:33

Modifying the condition of loop end to detect the click of window close button:
Loop until multikey(&H01) or inkey=chr(&HFF)+"k"
fxm
Posts: 9927
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: analog clock

Postby fxm » Apr 14, 2015 13:17

Some improvements (IMHO):
- hour hand is continuously moving like that of minutes and seconds (60 steps instead of 12),
- one buffer graphic image is created containing the clock background (only the image copy is in the loop),
- [screenlock..screenunlock] is only around the graphic drawing part,
- condition of loop end modified to detect the click of window close button.

Code: Select all

Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 280,280,32
color rgb(0,0,0),rgb(255,255,255):cls  ' black ink, white paper

dim as any ptr pclock = imagecreate(280,280,rgb(255,255,255),32)
dim as double dx1,dy1,dx2,dy2
dim as double px,py
px = 140
py = 140
dim as double angle

for i as long = 0 to 360 step 60    ' 360\60
    angle = 180 - i
    dx1 = sin(angle*DtoR)*90
    dy1 = cos(angle*DtoR)*90
    dx2 = sin(angle*DtoR)*99
    dy2 = cos(angle*DtoR)*99
    line pclock, (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
next i
for i as long = 0 to 360 step 30    ' 360\12
    angle = 180 - i
    dx1 = sin(angle*DtoR)*85
    dy1 = cos(angle*DtoR)*85
    dx2 = sin(angle*DtoR)*99
    dy2 = cos(angle*DtoR)*99
    line pclock, (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
next i
for i as long = 30 to 360 step 30   ' 360\12
    angle = 180 - i
    dx1 = sin(angle*DtoR)*75
    dy1 = cos(angle*DtoR)*75
    draw string pclock, (px+dx1-4,py+dy1-4), str(i/30)
next i
circle pclock, (px,py),99,rgb(0,0,0)
circle pclock, (px,py),3,RGB(0,0,0),,,,f

do
    dim as string cTime,ampm,cHour,cMinute,cSecond
    dim as integer hours,minutes,seconds
   
    ctime = TIME
    ampm = "AM"
    hours = VAL(LEFT(ctime, 2))
    IF hours > 12 THEN
        ampm = "PM"
        hours = hours - 12
    END IF
    IF hours = 0 THEN hours = 12
    minutes = VAL(MID(ctime, 4, 2))
    seconds = VAL(RIGHT(ctime, 2))
    ' Begin - Time string formating
    If hours < 10 then
        cHour = " "+str(hours)
    Else
        cHour = str(hours)
    EndIf
    If minutes < 10 then
        cMinute = "0"+str(minutes)
    Else
        cMinute = str(minutes)
    EndIf
    If seconds < 10 then
        cSecond = "0"+str(seconds)
    Else
        cSecond = str(seconds)
    EndIf
    ' End - Time string formating

    screenlock
    put (0,0),pclock,pset

    angle = 180-(hours+minutes/60)*30
    dx1 = sin(angle*DtoR)*50
    dy1 = cos(angle*DtoR)*50
    line (px,py)-(px+dx1,py+dy1),rgb(0,0,255)' hour hand
   
    angle = 180-minutes*6
    dx1 = sin(angle*DtoR)*70
    dy1 = cos(angle*DtoR)*70
    line (px,py)-(px+dx1,py+dy1),rgb(0,255,255)' minutes hand
   
    angle = 180-seconds*6
    dx1 = sin(angle*DtoR)*90
    dy1 = cos(angle*DtoR)*90
    line (px,py)-(px+dx1,py+dy1),rgb(255,0,0)' second hand

    locate 2,2
    ' add ampm to concatenated string
    print cHour+":"+cMinute+":"+cSecond+" "+ampm
   
    screenunlock
   
    sleep 250,1
Loop until multikey(&H01) or inkey=chr(&HFF)+"k"

imagedestroy pclock
BasicCoder2
Posts: 3586
Joined: Jan 01, 2009 7:03
Location: Australia

Re: analog clock

Postby BasicCoder2 » Apr 14, 2015 16:35

fxm wrote:Some improvements (IMHO):
- hour hand is continuously moving like that of minutes and seconds (60 steps instead of 12),
- one buffer graphic image is created with the clock background (only the image copy is in the loop),
- [screenlock..screenunlock] is only around the graphic drawing part,
- condition of loop end modified to detect the click of window close button.


Thank you for your improvements.

I did in fact use a buffer graphic image of the clock face to start with as I was interested in using a real image of a pocket watch swinging on a chain. The clock hands were also going to be actual images.

Looking at my analog clock in the kitchen the minute and hour hands do move "continuously", that is, one increment per second. The increments of the seconds hand are obvious because of the distance it moves with each click of the clock as it ratchets the gears one step at a time either by an internal pendulum or an electronic oscillator. Looking at the kitchen clock I can just make out the little jumps of the minutes hand with each larger movement of the seconds hand. The minutes hand does not suddenly jump when the seconds hand has completed its revolution.

Here is my latest draft using suggested mods:

Code: Select all

Const Pi = 4 * Atn(1)
Dim Shared As Double TwoPi = 8 * Atn(1)
Dim Shared As Double RtoD = 180 / Pi   ' radians * RtoD = degrees
Dim Shared As Double DtoR = Pi / 180   ' degrees * DtoR = radians

screenres 280,280,32
color rgb(0,0,0),rgb(255,255,255):cls  ' black ink, white paper

dim as any ptr pclock = imagecreate(280,280,rgb(255,255,255),32)
dim as double dx1,dy1,dx2,dy2
dim as double px,py
px = 140
py = 140
dim as double angle

for i as long = 30 to 360 step 30
    angle = 180 - i
    dx1 = sin(angle*DtoR)*75
    dy1 = cos(angle*DtoR)*75
    draw string pclock, (px+dx1-4,py+dy1-4), str(i/30)
next i

for i as long = 0 to 360 step 6
    angle = 180 - i
    dx1 = sin(angle*DtoR)*92
    dy1 = cos(angle*DtoR)*92
    dx2 = sin(angle*DtoR)*97
    dy2 = cos(angle*DtoR)*97
    line pclock, (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
next i

for i as long = 0 to 360 step 30
    angle = 180 - i
    dx1 = sin(angle*DtoR)*85
    dy1 = cos(angle*DtoR)*85
    dx2 = sin(angle*DtoR)*99
    dy2 = cos(angle*DtoR)*99
    line pclock, (px+dx1,py+dy1)-(px+dx2,py+dy2),rgb(0,0,0)
next i
circle pclock, (px,py),97,rgb(0,0,0)
circle pclock, (px,py),99,rgb(0,0,0)
circle pclock, (px,py),3,RGB(0,0,0),,,,f


do
    dim as string cTime,ampm,cHour,cMinute,cSecond
    dim as integer hours,minutes,seconds
   
    ctime = time
    ampm = "AM"
    hours = val(left(ctime, 2))
    if hours > 12 then
        ampm = "PM"
        hours = hours - 12
    end if
    IF hours = 0 then hours = 12
    minutes  = val(mid(ctime, 4, 2))
    seconds  = val(right(ctime, 2))
    ' Begin - Time string formating
    If hours < 10 then
        cHour = " "+str(hours)
    Else
        cHour = str(hours)
    EndIf
    If minutes < 10 then
        cMinute = "0"+str(minutes)
    Else
        cMinute = str(minutes)
    EndIf
    If seconds < 10 then
        cSecond = "0"+str(seconds)
    Else
        cSecond = str(seconds)
    EndIf
    ' End - Time string formating

    screenlock
    put (0,0),pclock,pset

    angle = 180-(hours+minutes/60)*30
    dx1 = sin(angle*DtoR)*50
    dy1 = cos(angle*DtoR)*50
    line (px,py)-(px+dx1,py+dy1),rgb(0,0,255)' hour hand
   
    angle = 180-(minutes+seconds/60)*6
    dx1 = sin(angle*DtoR)*80
    dy1 = cos(angle*DtoR)*80
    line (px,py)-(px+dx1,py+dy1),rgb(0,255,255)' minutes hand
   
    angle = 180-seconds*6
    dx1 = sin(angle*DtoR)*90
    dy1 = cos(angle*DtoR)*90
    line (px,py)-(px+dx1,py+dy1),rgb(255,0,0)' second hand

    locate 2,2
    ' add ampm to concatenated string
    print cHour+":"+cMinute+":"+cSecond+" "+ampm
   
    screenunlock
   
    sleep 250,1
Loop until multikey(&H01) or inkey=chr(&HFF)+"k"

imagedestroy pclock
Last edited by BasicCoder2 on Apr 14, 2015 23:03, edited 1 time in total.
MrSwiss
Posts: 3604
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: analog clock

Postby MrSwiss » Apr 14, 2015 18:16

... there are many ways to kill a cat:

The movement of the various clock hands depends on the electrics/mechanics involved, e.g.:
The well known SBB/CFF Clock (Swiss Railroads Clock, also licensed by Apple) works the other way round:
    Seconds - always (driven by sinc. motor that needs approx. 59 Sec/360°, then stops until, see below)
    Minute - jump, electrical impulse=1/2 rotation on very simplistic Anker motor (takes place, to start Seconds motor again)
    Hour - jump small, mechanically linked to Minutes, by gears.
Those Clocks are controlled by a master-clock that sends an impulse (48VDC) once a minute ...
My home town sports plenty of those (just without Seconds hand), at almost every Tram-/Buss- stop.
The most common size is diameter = 0.6 m (~2 feet).
I3I2UI/I0
Posts: 90
Joined: Jun 03, 2005 10:39
Location: Germany

Re: analog clock

Postby I3I2UI/I0 » Apr 18, 2015 14:27


Return to “Tips and Tricks”

Who is online

Users browsing this forum: No registered users and 4 guests