Now understandably the hand moves 6 degrees every second (tick), but how can i sweep it so its constantly moving throughout the full rotation of the clock.
I had thought about millis(), but need it to be linked to my computer time as opposed to starting the count when the program runs, like the milli function.
Thanks TfGuy, will have a play, see if i can move forward.
You can use Java’s GregorianCalendar class to get the current time to millisecond precision like this.
import java.util.*;
GregorianCalendar cdr;
int hr, min, sec, ms, lastT, deltaT;
String time;
void setup() {
size(400, 100);
textSize(30);
// Create a calendar using local time zone
cdr = new GregorianCalendar();
lastT = 0;
deltaT = 0;
}
void draw() {
background(0);
fill(255);
// Get the elapsed time since the last draw method
int now = millis();
deltaT = now - lastT;
lastT = now;
// Update the calendar with the elapsed time
cdr.add(Calendar.MILLISECOND, deltaT);
// Get the current time
hr = cdr.get(Calendar.HOUR);
min = cdr.get(Calendar.MINUTE);
sec = cdr.get(Calendar.SECOND);
ms = cdr.get(Calendar.MILLISECOND);
// Calculate a string representation of the time and display it
String time = hr + ":" + min + ":" + sec + "." + ms;
text(time, 30, 50);
}
Hello. I tried expanding this idea for minutes, and it seems to almost work but the minute hand only gets about half way to the next tick and then snaps into place at 0 seconds. Any suggestions what’s not right? Or is it just expecting too much accuracy for millis() over this period of time?
// Time class
// https://discourse.processing.org/t/analogue-clock-second-hand-sweep-not-tick/2331/3
Time t = new Time();
float faceRadius = 175;
void setup() {
size(400, 600);
}
void draw() {
background(127);
stroke(255);
textSize(24);
pushMatrix(); // center everything
translate(width/2, height/2);
showTicks();
// seconds
pushMatrix(); // rotate seconds
rotate(-HALF_PI + radians(t.getSecondAngle()));
line(0, 0, faceRadius, 0);
fill(255);
text(t.csecond, faceRadius-40, 0);
popMatrix(); // rotate seconds
// minutes
pushMatrix(); // rotate minutes
rotate(-HALF_PI + radians(t.getMinuteAngle()));
line(0, 0, faceRadius, 0);
fill(255);
text(t.cminute, faceRadius-40, 0);
popMatrix(); // rotate minutes
popMatrix(); // center everything
}
class Time {
int mill;
int psecond;
int csecond;
int pminute;
int cminute;
Time() {
psecond = second() - 1;
pminute = minute() - 1;
}
int getSecondAngle() {
int sec = second();
csecond = sec;
if ( sec != psecond ) {
mill = millis()%1000;
}
float s = map(1000*second() + (millis()-mill) % 1000, 0, 60000, 0, 360);
psecond = sec;
return s;
}
float getMinuteAngle() {
int min = minute();
cminute = min;
if ( min != pminute ) {
mill = millis()%1000;
}
float m = map(100000 * minute() + 1000 * second() + (millis()-mill) % 1000, 0, 6000000, 0, 360);
pminute = min;
return m;
}
}
void showTicks() {
for (int a = 0; a < 360; a+=6) {
float angle = radians(a);
float x = faceRadius*cos(angle);
float y = faceRadius*sin(angle);
strokeWeight(1);
fill(127);
stroke(200);
ellipse(x, y, 10, 10);
stroke(255);
point(x, y);
}
}
This doesn’t make any noticeable difference and the use of the Gregorian calendar has several benefits, including using local time and handles daylight saving time etc but it could have the advantage of encapsulating everything you need to do with a clock.
This example sketch does just that
import java.util.*;
Time t;
float clockRadius;
void setup() {
size(400, 400);
t = new Time(this);
clockRadius = min(width, height)/ 2 - 10;
textSize(30);
// Create a calendar using local time zone
}
void draw() {
background(255);
drawDigital24(t);
translate(width/2, height/2);
drawTicks();
drawHands(t);
}
void drawDigital24(Time t) {
String dt = nf(t.getHour(), 2) + ":"
+ nf(t.getMinute(), 2) + ":"
+ nf( (t.getSecond() * 1000 + t.getMilli()) / 1000f, 2, 3);
textSize(16);
textAlign(CENTER, CENTER);
fill(20, 20, 192);
text(dt, 2, 2, 100, 20);
}
void drawTicks() {
float da = TWO_PI / 12;
strokeWeight(10);
stroke(140);
pushMatrix();
for (int i = 0; i < 12; i++) {
line(clockRadius - 20, 0, clockRadius, 0);
rotate(da);
}
popMatrix();
}
void drawHands(Time t) {
// Hour hand
pushMatrix();
stroke(0);
strokeWeight(8);
rotate(t.getHourHandAngle());
line(-5, 0, clockRadius * 0.5, 0);
popMatrix();
// Minute hand
pushMatrix();
stroke(0);
strokeWeight(4);
rotate(t.getMinuteHandAngle());
line(-10, 0, clockRadius * 0.95, 0);
popMatrix();
// Second hand
pushMatrix();
stroke(255, 0, 0);
strokeWeight(2);
rotate(t.getSecondHandAngle());
line(-5, 0, clockRadius * 0.9, 0);
popMatrix();
}
public class Time {
private GregorianCalendar cdr;
private int lastT;
private int deltaT;
int hour, minute, second, milli;
private final float ANGLE_OFFSET = - PI /2;
private final float ANGLE_HOUR = TWO_PI / 12;
private final float ANGLE_MINUTE = TWO_PI / 60;
private final float ANGLE_SECOND = TWO_PI / 60;
Time(PApplet pa) {
cdr = new GregorianCalendar();
lastT = millis();
deltaT = 0;
pa.registerMethod("pre", this);
}
public void pre() {
// Get the elapsed time since the last draw method
int now = millis();
deltaT = now - lastT;
lastT = now;
// Update the calendar with the elapsed time
cdr.add(Calendar.MILLISECOND, deltaT);
}
int getHour() {
return cdr.get(Calendar.HOUR);
}
float getHourHandAngle() {
float t = (getHour() % 12)
+ (getMinute() / 60f)
+ (getSecond() / 3600f)
+ (getMilli() / 3600000);
return t * ANGLE_HOUR + ANGLE_OFFSET;
}
int getMinute() {
return cdr.get(Calendar.MINUTE);
}
float getMinuteHandAngle() {
float t = getMinute()
+ (getSecond() / 60f)
+ (getMilli() / 60000f);
return t * ANGLE_MINUTE + ANGLE_OFFSET;
}
int getSecond() {
return cdr.get(Calendar.SECOND);
}
float getSecondHandAngle() {
float t = getSecond() + (getMilli() / 1000f);
return t * ANGLE_SECOND + ANGLE_OFFSET;
}
int getMilli() {
return cdr.get(Calendar.MILLISECOND);
}
public String toString() {
return getHour() + ":" + getMinute() + ":" + getSecond() + "." + milli;
}
}
I really do like this Gregorian Calendar solution. Sadly, I can’t use java.util.* with the Processing for iOS App that I’m primarily working on.
Is there any chance maybe I’ve just got some math wrong? It seems like I must be generating the wrong angle, by about 3deg/min.
I have to admit that I am having a bit of trouble conceptualizing how this works for seconds, and I’m trying to learn from the example by forcing it to work with minutes and maybe even hours.
I’m on an ongoing quest to make friends with map() and modulo, and I really like clock hands and gears with smooth motion.
I used my owner counter for testing your code to speed things up; you can go back to second() and minute();:
// Simple timer for testing to speed up "time" for testing
if (frameCount%1 == 0) // Change %1 to %60 to slow things down!
{
if (sCount>0 && sCount%60 == 0)
{
sCount = 0;
mCount++;
}
if (mCount%60 == 0)
mCount = 0;
sCount++;
}
println(sCount, mCount);
This is really helpful, I’ll have to work around the use of PApplet, etc on the iPhone compiler, but I really appreciate you putting all the ingredients together so concisely.
I’m really kind of stuck with using things that work on the iPhone compiler because I’m trying to make things I can easily put into my 4 year old son’s hands so I can watch him have fun with it. I’ve been working on learning how to use Xcode and Swift but totally choking on it for obvious reasons. This is a great step in between.
How would I call the code inside the pre() method if I can’t use the pa.registerMethod method with a papplet reference? It’s not going to work in the iOS compiler.
I have never encountered the registerMethod and pre() before but I have spent a bit of time reading about it and I have a basic understanding of why to use it.
But if I don’t know how it is called. I tried putting pre(); in draw() but then the hands just spin around really fast.
Thanks for showing me how to work around the pa.registerMethod thing. It does work here too in the Processing IDE. Still weird behavior in the iOS compiler but I’ll figure that part out.