Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# vec3

[![NPM version](https://img.shields.io/npm/v/vec3.svg)](http://npmjs.com/package/vec3)
[![Build Status](https://github.com/PrismarineJS/node-vec3/workflows/CI/badge.svg)](https://github.com/PrismarineJS/node-vec3/actions?query=workflow%3A%22CI%22)

Expand All @@ -7,7 +8,7 @@
## Usage

```js
var v = require('vec3');
var v = require("vec3");

var v1 = v(1, 2, 3);
console.log(v1); // prints "(1, 2, 3)"
Expand All @@ -18,7 +19,7 @@ console.log(v2); // prints "(1, 2, 4)"
Or:

```js
var Vec3 = require('vec3').Vec3;
var Vec3 = require("vec3").Vec3;

var v1 = new Vec3(1, 2, 3);
// etc...
Expand Down Expand Up @@ -55,6 +56,7 @@ More available functions are listed below in Test Coverage.
✔ minus
✔ scaled
✔ abs
✔ angleTo
✔ distanceTo
✔ distanceSquared
✔ equals
Expand Down
5 changes: 5 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ export class Vec3 {
*/
modulus(other: Vec3): Vec3;

/**
* Return the angle in rad between another vector and this one
*/
angleTo(other: Vec3): number;

/**
* Return the euclidean distance to another vector
*/
Expand Down
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,10 @@ class Vec3 {
euclideanMod(this.z, other.z))
}

angleTo (other) {
return Math.acos(this.dot(other) / (this.norm() * other.norm()))
}

distanceTo (other) {
const dx = other.x - this.x
const dy = other.y - this.y
Expand Down
1 change: 1 addition & 0 deletions test/index.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ expectType<Vec3>(vec.scaled(2));
expectType<Vec3>(vec.abs());
expectType<number>(vec.volume());
expectType<Vec3>(vec.modulus(vec));
expectType<number>(vec.angleTo(vec));
expectType<number>(vec.distanceTo(vec));
expectType<number>(vec.distanceSquared(vec));
expectType<boolean>(vec.equals(vec));
Expand Down
18 changes: 18 additions & 0 deletions test/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,24 @@ describe('vec3', function () {
assert.strictEqual(v2.y, 1.5)
assert.strictEqual(v2.z, 1.9)
})
it('angleTo', function () {
const v1 = new Vec3(1, 1, 1)
const v2 = new Vec3(1, 0, 0)
const angle1 = v1.angleTo(v2)
const angle2 = v2.angleTo(v1)
const expected = 0.9553166181
assert.strictEqual(angle1, angle2)
assert.strictEqual(Math.round(angle1 * 100000), Math.round(expected * 100000))
})

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add a test case with both norm is 0 it's may create something strange

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems to behave well, resulting in NaN 7b0b70b

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in importation you need to cache norm first then check if not 0 if both 0 need to return 0
IMO it's the cleanest way to fix that

Copy link
Author

@eevleevs eevleevs Jun 6, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it needs to return NaN, because this.dot(other) / (this.norm() * other.norm()) in this case is 0 / 0, which is indeterminate, not zero.

In practice, getting NaN signifies that the angle has no meaning, because the vectors are degenerate and don't actually have a direction. This case must be handled by the user, not here.

It actually happens also if only one of the vectors is null.

it('angleToNullVectors', function () {
const v1 = new Vec3(0, 0, 0)
const v2 = new Vec3(0, 0, 0)
const angle1 = v1.angleTo(v2)
const angle2 = v2.angleTo(v1)
const expected = NaN
assert.strictEqual(angle1, angle2)
assert.strictEqual(Math.round(angle1 * 100000), Math.round(expected * 100000))
})
it('distanceTo', function () {
const v1 = new Vec3(1, 1, 1)
const v2 = new Vec3(2, 2, 2)
Expand Down