Counting total drag rotation about a point

I was hoping to make something like an encoder wheel that would take a measurement of the accumulated rotation angle during a mouse drag around a center point.

This code works fairly well for the main idea, but .angleBetween() obviously isn’t the right choice here.

I can’t think of how to accumulate the total rotation of a mouse drag, including cases where the rotation is more than 360 degrees, or when the rotation is incremented and then decremented during the same drag. Basically, as long as the mouse is pressed and rotated in one direction or another, when the mouse is released, output the total difference in rotation from the initial mouse pressed start point.

Part of this project also includes code so that there is actually a circle like a wheel and the measurement will stop if the mouse leaves the circle during a drag, and not resume until a new press occurs inside the wheel and is dragged, but I took that out for simplicity of this question.

Could someone please suggest a way to take these measurements?

PVector mouse, center, mDiff, start, end;
float radius, startAngle, endAngle, counter;
boolean measuring, measurementBegan, measurementEnded;

void setup() {
   size(400, 500);
   //size(screen.width, screen.height);
   radius = 100;
   center = new PVector(width/2, height/2);
   start = new PVector();
   end = new PVector();
   startAngle = 0;
   counter = 0;
   measuring = false;
   measurementBegan = false;
   measurementEnded = false;
}

void draw() {
   background(255);
   textSize(24);
   fill(0);
   
   mouse = new PVector(mouseX, mouseY);
   mDiff = PVector.sub(mouse, center);
   float angleRad = mDiff.heading();
   text(degrees(PVector.angleBetween(start, end)), width/2, 25);
   
   if(mousePressed && !measurementBegan) {
      start = PVector.normalize(mDiff);
      start.mult(radius);
      end = PVector.normalize(mDiff);
      startAngle = angleRad;
      
      measuring = false;
      measurementBegan = true;
      measurementEnded = false;
   }
   
   if(measurementBegan) {
      pushMatrix();
      translate(center.x, center.y);
      rotate(angleRad);
      line(0, 0, radius, 0);
      text(degrees(angleRad), 25, 0);
      popMatrix();
   }
   
   if(measuring) {
      fill(0, 255, 0);
      pushMatrix();
      translate(center.x, center.y);
      ellipse(start.x, start.y, 10, 10);
      rotate(startAngle);
      line(0, 0, radius, 0);
      text(degrees(startAngle), 25, 0);
      popMatrix();
   }
   
   if(measurementEnded) {
      end = PVector.normalize(mDiff);
      end.mult(radius);
      endAngle = angleRad;
      
      fill(255, 0, 0);
      pushMatrix();
      translate(center.x, center.y);
      ellipse(end.x, end.y, 10, 10);
      rotate(endAngle);
      line(0, 0, radius, 0);
      text(degrees(endAngle), 25, 0);
      popMatrix();
   }
}
void mouseDragged() {
   measuring = true;
   measurementEnded = false;
}
void mouseReleased() {
   measurementBegan = false;
   measurementEnded = true;
}
1 Like

You are close, but instead of just printing the angle between you want to take a summation of all the previously accumulated angles by getting the angle between where the mouse was and where the mouse is, then take the cross product to determine if you are going clockwise or counterclockwise below is the code with the minor revisions, also note I changed where you called the normalize functions because it throws an error on my version of processing:

PVector mouse, center, mDiff, start, end;
float radius, startAngle, endAngle, counter;
boolean measuring, measurementBegan, measurementEnded;

void setup() {
  size(400, 500);
  //size(screen.width, screen.height);
  radius = 100;
  center = new PVector(width/2, height/2);
  start = new PVector();
  end = new PVector();
  startAngle = 0;
  counter = 0;
  measuring = false;
  measurementBegan = false;
  measurementEnded = false;
}

float totalDegrees = 0;

void draw() {
  background(255);
  textSize(24);
  fill(0);

  mouse = new PVector(mouseX, mouseY);
  mDiff = PVector.sub(mouse, center);
  float angleRad = mDiff.heading();

  PVector pmouse = new PVector(pmouseX, pmouseY);
  PVector pnew = PVector.sub(pmouse, center);

  if (measuring) {
    if (mDiff.cross(pnew).z>=0)
      totalDegrees += degrees(PVector.angleBetween(mDiff, pnew));
    else
      totalDegrees -= degrees(PVector.angleBetween(mDiff, pnew));
  }

  text(abs(totalDegrees), width/2, 25);

  if (mousePressed && !measurementBegan) {
    start = mDiff.normalize();
    start.mult(radius);
    end = mDiff.normalize();
    startAngle = angleRad;

    measuring = false;
    measurementBegan = true;
    measurementEnded = false;
  }

  if (measurementBegan) {
    pushMatrix();
    translate(center.x, center.y);
    rotate(angleRad);
    line(0, 0, radius, 0);
    text(degrees(angleRad), 25, 0);
    popMatrix();
  }

  if (measuring) {
    fill(0, 255, 0);
    pushMatrix();
    translate(center.x, center.y);
    ellipse(start.x, start.y, 10, 10);
    rotate(startAngle);
    line(0, 0, radius, 0);
    text(degrees(startAngle), 25, 0);
    popMatrix();
  }

  if (measurementEnded) {
    end = mDiff.normalize();
    end.mult(radius);
    endAngle = angleRad;

    fill(255, 0, 0);
    pushMatrix();
    translate(center.x, center.y);
    ellipse(end.x, end.y, 10, 10);
    rotate(endAngle);
    line(0, 0, radius, 0);
    text(degrees(endAngle), 25, 0);
    popMatrix();
  }
}
void mouseDragged() {
  measuring = true;
  measurementEnded = false;
}
void mouseReleased() {
  measurementBegan = false;
  measurementEnded = true;
}
1 Like

This was incredibly helpful, thank you!