I am trying to make a draggable clock hand that follows the mouse drag with easing. When dragging CW, after the drag crosses 0, the hand goes CCW to find the mouse, when dragging CCW, the hand will not cross 0.
I have tried a few attempts at creating conditions to measure the CW & CCW distance from the needle and using those to keep the motion going in the same direction as the drag as it goes over 0, but they ended up being very convoluted and didn’t work.
Ultimately I hope to make a clock that allows you to drag any of the hands if they are touched semi-precisely with hit testing, and then they will ease along with the drag and take the other hands with them as appropriate for a clock, like a toy clock. Then when the drag is complete, the hands would go back to moving with a timer class.
I would appreciate any suggestions as a starting point about what I would have to do to get the drag to take the hand around either direction and cross 0 without a hitch.
I am having the most trouble just conceptualizing how to solve this problem which doesn’t seem like it should be so complicated.
Here is a stripped down version that I have been working on.
PVector m = new PVector();
PVector mo = new PVector();
PVector pm = new PVector();
PVector po = new PVector();
PVector c = new PVector();
float faceR;
float offset = -PI/2;
//offset = 0;
float needleAng = offset;
float dropAng = PI*2/10;
float easeAmt = 0.1;
float easeAng;
float angDiff;
void setup() {
size(400, 600);
ellipseMode(RADIUS);
c.set(width/2, height/2);
faceR = width/2-50;
}
void draw() {
background(127);
showFace();
m.set(mouseX, mouseY);
mo = PVector.sub(m, c);
pm.set(pmouseX, pmouseY);
po = PVector.sub(pm, c);
dragAng = adjAngRange(mo.heading());
easeAmt = 0.1;
angDiff = dragAng-needleAng;
if (mousePressed && angDiff < dropAng) {
easeAng += easeAmt * (angDiff);
}
needleAng = easeAng;
showText();
showNeedle(needleAng);
showHandle(dragAng);
}
boolean betweenAnglesRadians(float ang, float start, float end) {
return end >= start
? ang >= start && ang <= end
: (ang >= start && ang <= TWO_PI) || (ang >= 0 && ang <= end);
}
float adjAngRange(float angle) {
return (angle>0) ? angle : PI*2+angle;
}
void lineStartRA(PVector start, float radius, float angle) {
float x = cos(angle);
float y = sin(angle);
PVector end = new PVector(x, y);
end.mult(radius);
end.add(start);
linePts(start, end);
}
void linePts(PVector a, PVector b) {
line(a.x, a.y, b.x, b.y);
}
void circleCR(PVector center, float radius) {
ellipse(center.x, center.y, radius, radius);
}
void showFace() {
stroke(0);
fill(200);
circleCR(c, faceR);
}
void showNeedle(float angle) {
strokeWeight(5);
stroke(0);
lineStartRA(c, faceR, angle);
}
void showHandle(float angle) {
PVector handle = new PVector();
float handleR = 40;
float x = cos(angle);
float y = sin(angle);
handle.set(x, y);
handle.mult(faceR-handleR);
handle.add(c);
noFill();
strokeWeight(1);
stroke(0);
lineStartRA(c, faceR, angle);
stroke(0);
circleCR(handle, handleR);
}
String angDegStr(float angle) {
return nfs(round(degrees(angle)), 3);
}
void showText() {
String dragAngStr = "dragAng: " + angDegStr(dragAng);
String needleAngStr = "needleAng: " + angDegStr(needleAng);
String angDiffStr = "angDiff: " + angDegStr(angDiff);
String easeAngStr = "easeAng: " + angDegStr(easeAng);
String[] strings = { dragAngStr, needleAngStr, angDiffStr, easeAngStr };
textSize(25);
textAlign(RIGHT, TOP);
for (int i=0; i<strings.length; i++) {
text(strings[i], width-5, 5+i*25);
}
}