Skip to content

Prepare an axis variable for angleBetween() and return a signed value #6155

Closed
@inaridarkfox4231

Description

@inaridarkfox4231

Increasing Access

I wanted to do it while I could, so I'm proposing it now.

First, it's quite natural that angleBetween() returns values ​​between 0 and PI. It's not a bug.

It's called a bug in the issue(#3973), but it's not a bug because the direction of two vectors in 3D space has no meaning. Both Three.js and Processing return values ​​from 0 to PI. I expected that too. Most people expect a value between 0 and PI to be returned.
People new to p5.js would be surprised to see a function in Processing that was treated as angleBetween(). It should be fixed again.

However, I am reluctant to neglect the behavior of returning a signed value that the person who raised this issue expects from angleBetween().

So I prepared a compromise.

Prepare a new variable named axis in angleBetween(). This is like the normal vector of the plane. When viewed from this direction, for example, if we apply a method such as v1.angleBetween(v2, axis), we will behave to return a signed value like the one currently used.

For example if the axis is createVector(0,0,1) the behavior will match the current one. The sign is reversed for createVector(0,0,-1). In other words, when viewed from the axis, we can see the projection of v1 and v2 onto the plane, and consider moving them so that they overlap clockwise within the PI rotation.

Returns values ​​from 0 to PI if axis is not defined or is not a vector.

angleBetween

Now, to get the traditional signed behavior, just specify createVector(0,0,1) for the new argument. It may be inconvenient, but the flexibility is improved by being able to specify other axes. The majority of people expect it to return values ​​between 0 and PI, so I think this change is reasonable.

Most appropriate sub-area of p5.js?

  • Accessibility
  • Color
  • Core/Environment/Rendering
  • Data
  • DOM
  • Events
  • Image
  • IO
  • Math
  • Typography
  • Utilities
  • WebGL
  • Build Process
  • Unit Testing
  • Internalization
  • Friendly Errors
  • Other (specify if possible)

Feature enhancement details

implementation

Change is easy. All we have to do is to replace the calculation that has been used to obtain the z component with the calculation that obtains the inner product with the axis. This calculation is not performed if axis is not defined.

angleBetween(v, axis) {
  const dotmagmag = this.dot(v) / (this.mag() * v.mag());
  // Mathematically speaking: the dotmagmag variable will be between -1 and 1
  // inclusive. Practically though it could be slightly outside this range due
  // to floating-point rounding issues. This can make Math.acos return NaN.
  //
  // Solution: we'll clamp the value to the -1,1 range
  let angle;
  angle = Math.acos(Math.min(1, Math.max(-1, dotmagmag)));
  // If axis is defined, returns a signed value taking into account
  // the orientation with respect to axis.
  if (axis !== undefined && axis instanceof p5.Vector) {
    angle *= Math.sign(this.cross(v).dot(axis) || 1);
  }
  if (this.isPInst) {
    angle = this._fromRadians(angle);
  }
  return angle;
}

static angleBetween(v1, v2, axis) {
  return v1.angleBetween(v2, axis);
}

All I have to do is rewrite the references and prepare a unit test for the new axis variables. Eliminate some unit tests returning negative values with no axis variables.

example

angleBetween_improve

function setup() {
  createCanvas(400, 400);
  v=createVector(1,0,0);
  w=createVector(0,1,0);
  u=createVector(0,0,1);
  console.log(v.angleBetween(w, u));
  console.log(v.angleBetween(u, w));
  console.log(w.angleBetween(v, u));
  console.log(w.angleBetween(u, v));
  console.log(u.angleBetween(v, w));
  console.log(u.angleBetween(w, v));
  console.log("-----------------------------------")
  console.log(p5.Vector.angleBetween(v, w, u));
  console.log(p5.Vector.angleBetween(v, u, w));
  console.log(p5.Vector.angleBetween(w, v, u));
  console.log(p5.Vector.angleBetween(w, u, v));
  console.log(p5.Vector.angleBetween(u, v, w));
  console.log(p5.Vector.angleBetween(u, w, v));
}

result:

angleBetween2

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions