Loading...
Logo
Processing Forum

PVector.angleBetween

in Programming Questions  •  1 year ago  
Hello all,

I don't understand PVector.angleBetween or it doesn't give the results I expect.

I thought it would work like in a circle: you hand it the middle of the circle as PVector and another point on the circumference as PVector and you got the angle (the same thing that with cos and sin would give the difference of x and y).

But I don't think it does....

So what does it really do... and what can I do to achieve what I want?

I post my Code to clarify. I know it gives you rad and I convert it to degrees but still...

Greetings, Chrisir  




Copy code
  1. PVector middle;
  2. PVector Pos1=new PVector(100, 50);
  3. PVector Pos2=new PVector(550, 150);
  4. PVector Pos3=new PVector(550, 250);
  5. PVector Pos4=new PVector(550, 350);
  6. PVector Pos5=new PVector(550, 550);
  7. void setup () {
  8.   size(700, 700);
  9.   middle=new PVector(350, 350);
  10. }
  11. void draw () {
  12.   background (0);
  13.   showPVector(middle, color(255, 0, 0));
  14.   showPVector(Pos1, color(255, 250, 0));
  15.   showPVector(Pos2, color(255, 0, 250));
  16.   showPVector(Pos3, color(255, 0, 250));
  17.   showPVector(Pos4, color(55, 55, 0));
  18.   showPVector(Pos5, color(55, 55, 233));
  19. }
  20. void showPVector(PVector myPVector, color col) {
  21.   fill(col);
  22.   ellipse(myPVector.x, myPVector.y, 10, 10);
  23.   String myText = nf(PVector.angleBetween( middle, myPVector ), 0, 2)
  24.     + " rad or "
  25.       + nf(degrees(PVector.angleBetween( middle, myPVector )), 0, 2)
  26.       + "°";
  27.   text(myText, myPVector.x+13, myPVector.y);
  28. }


Replies(8)

A PVector(100, 100) is not a point at (100,100) it's a vector from the origin (0,0) to point(100, 100). So your middle PVector is a vector from the origin to (350, 350). The angle of this vector is 45 degrees. Your Pos5 PVector is a vector from the origin to (550, 550);. The angle of this vector is also 45 degrees. So the angleBetween the middle and the Pos5 Pvector is 0. For all the other it's the same, the method gives the angle between one vector and another.

To understand better what angleBetween does add the following lines to your sketch:
Copy code
  1.   // add to draw()
  2.   showPVector(new PVector(mouseX, mouseY), color(55, 55, 233));

  3.   // add to showPVector()
  4.   stroke(col);
  5.   line(0,0, myPVector.x, myPVector.y);
You will notice as described above, that a PVector on the 45 degree (middle) line will give 0 degrees, while (0, mouseX) or (mouseY, 0) will give 45 degrees. So it's just the angle from one vector compared to another. Also see below.

Code Example
Copy code
  1. PVector x = new PVector(1, 0);
  2. PVector y = new PVector(0, 1);
  3. float angle = PVector.angleBetween(x, y);
  4. println(degrees(angle)); // 90 degrees
  5. exit();


Thanks.

clear now

I'll just write my own, but not working, only 0..180 or -0..-180

see the bold lines please 



Copy code
  1. PVector middle;
  2. PVector Pos1=new PVector(100, 50);
  3. PVector Pos2=new PVector(550, 150);
  4. PVector Pos3=new PVector(550, 250);
  5. PVector Pos4=new PVector(550, 350);
  6. PVector Pos5=new PVector(550, 550);
  7. void setup () {
  8.   size(700, 700);
  9.   middle=new PVector(350, 350);
  10. }
  11. void draw () {
  12.   background (0);
  13.   showPVector(new PVector(mouseX, mouseY), color(55, 55, 233));
  14.   //text (degrees(myAngleBetween(new PVector(mouseX, mouseY), new PVector(mouseX, mouseY) )),  mouseX+12, mouseY+12 );
  15.   showPVector(middle, color(255, 0, 0));
  16.   showPVector(Pos1, color(255, 250, 0));
  17.   showPVector(Pos2, color(255, 0, 250));
  18.   showPVector(Pos3, color(255, 0, 250));
  19.   showPVector(Pos4, color(55, 55, 0));
  20.   showPVector(Pos5, color(55, 55, 233));
  21. }
  22. void showPVector(PVector myPVector, color col) {
  23.   fill(col);
  24.   ellipse(myPVector.x, myPVector.y, 10, 10);
  25.   //
  26.   String myText = nf(PVector.angleBetween( middle, myPVector ), 0, 2)
  27.     + " rad or "
  28.       + nf(degrees(PVector.angleBetween( middle, myPVector )), 0, 2)
  29.       + "°";
  30.   text(myText, myPVector.x+13, myPVector.y);
  31.   //
  32.   // new attempt
  33.   myText = nf(myAngleBetween( middle, myPVector ), 0, 2)
  34.     + " rad or "
  35.       + nf(degrees(myAngleBetween( middle, myPVector )), 0, 2)
  36.       + "°";
  37.   text(myText, myPVector.x+13, myPVector.y+13);
  38.   stroke(col);
  39.   line(middle.x, middle.x, myPVector.x, myPVector.y);
  40. }
  41. float myAngleBetween (PVector myPVector1, PVector myPVector2) {
  42.   float a = atan2(myPVector1.y-myPVector2.y, myPVector1.x-myPVector2.x);
  43.   return a;
  44. }

This is not only an issue with your code, but rather a mathematical issue, see this page.

To solve it, just add TWO_PI when the angle is negative, then you're always in the full range.
Copy code
  1. float myAngleBetween (PVector myPVector1, PVector myPVector2) {
  2.   float a = atan2(myPVector1.y-myPVector2.y, myPVector1.x-myPVector2.x);
  3.   if (a<0) { a+=TWO_PI; }
  4.   return a;
  5. }
Hi,

I also remember looking at the PVector.angleBetween, and wanting a different approach. I wrote some code as a study, and based my angles on the Unit Circle, with 0 degrees being at 3 o'clock. I chose not to use PVectors, but I'm sure it could easily be refactored using them if desired. Also, my output returns the angular separation between two lines rather than the bisector, but this is also easily modified. The code is archived here, and I'm copying it below also. See if there's anything in it you find useful.

Ross
Copy code
  1. // R.A. Robertson 2010.06, "Angles."
  2. float x, y;
  3. PFont font;
  4.  
  5. void setup() {
  6.   size (400, 400);
  7.   background(255);
  8.   smooth();
  9.   font = createFont("Arial", 12, true);
  10.   x = random(width);
  11.   y = random (height);
  12. }
  13.  
  14. void draw() {
  15.   fill(255);
  16.   noStroke();
  17.   rect(0, 0, width, height);
  18.   stroke(0);
  19.   float centerX = width/2;
  20.   float centerY = height/2;
  21.   ellipse(x, y, 4, 4);
  22.   ellipse(mouseX, mouseY, 6, 6);
  23.  
  24.   float slope = slopeFunct(centerX, centerY, mouseX, mouseY);
  25.   float theta = angle(centerX, centerY, mouseX, mouseY);
  26.   float slope1 = slopeFunct(centerX, centerY, x, y);
  27.   float theta1 = angle(centerX, centerY, x, y);
  28.   float diff = (theta - theta1);
  29.  
  30.   textFont(font);
  31.   fill(0);
  32.   text("Angle 1 = " + theta, 10, 40);
  33.   text("Angle 2 = " + theta1, 10, 60);
  34.   text("Separation = " + diff, 10, 80);
  35. } // End Draw.
  36.  
  37. // Functions:
  38. float slopeFunct(float x1, float y1, float x2, float y2) { // Assign two points.
  39.   line (x1, y1, x2, y2);    // Draw line (may be optional in other programs).
  40.   float dx = x2 - x1;      // Run.
  41.   float dy = y2 - y1;      // Rise.
  42.   return dy/dx;            // Slope = rise/run.
  43. }
  44.  
  45. float angle(float x1, float y1, float x2, float y2) {
  46.   float angle;
  47.   float dx = x2 - x1;      // Run.
  48.   float dy = y2 - y1;      // Rise.
  49.   float slope = dy/dx;    // Slope = rise/run.
  50.   if (dx >= 0 && dy >= 0) {
  51.     angle = degrees(atan(slope));
  52.   }
  53.   else if (dx < 0 && dy > 0) {
  54.     angle = degrees(atan(slope)) + 180;
  55.   }
  56.   else if (dx < 0 && dy <= 0) {
  57.     angle = degrees(atan(slope)) + 180;
  58.   }
  59.   else if (dx >=0 && dy < 0) {
  60.     angle = degrees(atan(slope)) + 360;
  61.   }
  62.   else angle = 1000; // This should never be true, but seems needed for println().
  63.   return angle;
  64. }
  65.  
  66. void mousePressed() {
  67.   setup();
  68. }


thank you all very much!

@ rariora: I couldn't help but to scan your QR-Code - you have a beautiful website there! Excellent!

Greetings, Chrisir




Thanks! I'm honored you took the time to look, and quite pleased you enjoyed it.


very good work!