diff --git a/libraries/script-engine/src/Vec3.h b/libraries/script-engine/src/Vec3.h
index c419749c26..635f2a530c 100644
--- a/libraries/script-engine/src/Vec3.h
+++ b/libraries/script-engine/src/Vec3.h
@@ -22,7 +22,7 @@
#include "GLMHelpers.h"
/**jsdoc
- * A 3-dimensional vector.
+ * A 3-dimensional vector. See also the {@link Vec3(0)|Vec3} object.
*
* @typedef {object} Vec3
* @property {number} x - X-coordinate of the vector.
@@ -31,7 +31,7 @@
*/
/**jsdoc
- * A color vector.
+ * A color vector. See also the {@link Vec3(0)|Vec3} object.
*
* @typedef {object} Vec3Color
* @property {number} x - Red component value. Integer in the range 0
- 255
.
@@ -39,6 +39,51 @@
* @property {number} z - Blue component value. Integer in the range 0
- 255
.
*/
+/**jsdoc
+ * The Vec3 API facilities for generating and manipulating 3-dimensional vectors. High Fidelity uses a right-handed
+ * Cartesian coordinate system where the y-axis is the "up" and the negative z-axis is the "front" direction.
+ *
+ *
+ * @namespace Vec3
+ * @variation 0
+ * @property {Vec3} UNIT_X - { x: 1, y: 0, z: 0 }
: Unit vector in the x-axis direction. Read-only.
+ * @property {Vec3} UNIT_Y - { x: 0, y: 1, z: 0 }
: Unit vector in the y-axis direction. Read-only.
+ * @property {Vec3} UNIT_Z - { x: 0, y: 0, z: 1 }
: Unit vector in the z-axis direction. Read-only.
+ * @property {Vec3} UNIT_NEG_X - { x: -1, y: 0, z: 0 }
: Unit vector in the negative x-axis direction.
+ * Read-only.
+ * @property {Vec3} UNIT_NEG_Y - { x: 0, y: -1, z: 0 }
: Unit vector in the negative y-axis direction.
+ * Read-only.
+ * @property {Vec3} UNIT_NEG_Z - { x: 0, y: 0, z: -1 }
: Unit vector in the negative z-axis direction.
+ * Read-only.
+ * @property {Vec3} UNIT_XY - { x: 0.707107, y: 0.707107, z: 0 }
: Unit vector in the direction of the diagonal
+ * between the x and y axes. Read-only.
+ * @property {Vec3} UNIT_XZ - { x: 0.707107, y: 0, z: 0.707107 }
: Unit vector in the direction of the diagonal
+ * between the x and z axes. Read-only.
+ * @property {Vec3} UNIT_YZ - { x: 0, y: 0.707107, z: 0.707107 }
: Unit vector in the direction of the diagonal
+ * between the y and z axes. Read-only.
+ * @property {Vec3} UNIT_XYZ - { x: 0.577350, y: 0.577350, z: 0.577350 }
: Unit vector in the direction of the
+ * diagonal between the x, y, and z axes. Read-only.
+ * @property {Vec3} FLOAT_MAX - { x: 3.402823e+38, y: 3.402823e+38, z: 3.402823e+38 }
: Vector with all axis
+ * values set to the maximum floating point value. Read-only.
+ * @property {Vec3} FLOAT_MIN - { x: -3.402823e+38, y: -3.402823e+38, z: -3.402823e+38 }
: Vector with all axis
+ * values set to the negative of the maximum floating point value. Read-only.
+ * @property {Vec3} ZERO - { x: 0, y: 0, z: 0 }
: Vector with all axis values set to 0
.
+ * Read-only.
+ * @property {Vec3} ONE - { x: 1, y: 1, z: 1 }
: Vector with all axis values set to 1
.
+ * Read-only.
+ * @property {Vec3} TWO - { x: 2, y: 2, z: 2 }
: Vector with all axis values set to 2
.
+ * Read-only.
+ * @property {Vec3} HALF - { x: 0.5, y: 0.5, z: 0.5 }
: Vector with all axis values set to 0.5
.
+ * Read-only.
+ * @property {Vec3} RIGHT - { x: 1, y: 0, z: 0 }
: Unit vector in the "right" direction. Synonym for
+ * UNIT_X
. Read-only.
+ * @property {Vec3} UP - { x: 0, y: 1, z: 0 }
: Unit vector in the "up" direction. Synonym for
+ * UNIT_Y
. Read-only.
+ * @property {Vec3} FRONT - { x: 0, y: 0, z: -1 }
: Unit vector in the "front" direction. Synonym for
+ * UNIT_NEG_Z
. Read-only.
+ */
+
/// Scriptable interface a Vec3ernion helper class object. Used exclusively in the JavaScript API
class Vec3 : public QObject, protected QScriptable {
Q_OBJECT
@@ -63,27 +108,301 @@ class Vec3 : public QObject, protected QScriptable {
Q_PROPERTY(glm::vec3 FRONT READ FRONT CONSTANT)
public slots:
+
+ /**jsdoc
+ * Calculate the reflection of a vector in a plane.
+ * @function Vec3(0).reflect
+ * @param {Vec3} v - The vector to reflect.
+ * @param {Vec3} normal - The normal of the plane.
+ * @returns {Vec3} The vector reflected in the plane given by the normal.
+ * @example
Reflect a vector in the x-z plane.
+ * var v = { x: 1, y: 2, z: 3 };
+ * var normal = Vec3.UNIT_Y;
+ * var reflected = Vec3.reflect(v, normal);
+ * print(JSON.stringify(reflected)); // {"x":1,"y":-2,"z":3}
+ */
glm::vec3 reflect(const glm::vec3& v1, const glm::vec3& v2) { return glm::reflect(v1, v2); }
+
+ /**jsdoc
+ * Calculate the cross product of two vectors.
+ * @function Vec3(0).cross
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @returns {Vec3} The cross product of v1
and v2
.
+ * @example The cross product of x and y unit vectors is the z unit vector.
+ * var v1 = { x: 1, y: 0, z: 0 };
+ * var v2 = { x: 0, y: 1, z: 0 };
+ * var crossProduct = Vec3.cross(v1, v2);
+ * print(JSON.stringify(crossProduct)); // {"x":0,"y":0,"z":1}
+ */
glm::vec3 cross(const glm::vec3& v1, const glm::vec3& v2) { return glm::cross(v1, v2); }
+
+ /**jsdoc
+ * Calculate the dot product of two vectors.
+ * @function Vec3(0).dot
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @returns {number} The dot product of v1
and v2
.
+ * @example The dot product of vectors at right angles is 0
.
+ * var v1 = { x: 1, y: 0, z: 0 };
+ * var v2 = { x: 0, y: 1, z: 0 };
+ * var dotProduct = Vec3.dot(v1, v2);
+ * print(dotProduct); // 0
+ */
float dot(const glm::vec3& v1, const glm::vec3& v2) { return glm::dot(v1, v2); }
+
+ /**jsdoc
+ * Multiply a vector by a scale factor.
+ * @function Vec3(0).multiply
+ * @param {Vec3} v - The vector.
+ * @param {number} scale - The scale factor.
+ * @returns {Vec3} The vector with each ordinate value multiplied by the scale
.
+ */
glm::vec3 multiply(const glm::vec3& v1, float f) { return v1 * f; }
+
+ /**jsdoc
+ * Multiply a vector by a scale factor.
+ * @function Vec3(0).multiply
+ * @param {number} scale - The scale factor.
+ * @param {Vec3} v - The vector.
+ * @returns {Vec3} The vector with each ordinate value multiplied by the scale
.
+ */
glm::vec3 multiply(float f, const glm::vec3& v1) { return v1 * f; }
+
+ /**jsdoc
+ * Multiply two vectors.
+ * @function Vec3(0).multiplyVbyV
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @returns {Vec3} A vector formed by multiplying the ordinates of two vectors: { x: v1.x * v2.x, y: v1.y * v2.y,
+ * z: v1.z * v2.z }
.
+ * @example Multiply two vectors.
+ * var v1 = { x: 1, y: 2, z: 3 };
+ * var v2 = { x: 1, y: 2, z: 3 };
+ * var multiplied = Vec3.multiplyVbyV(v1, v2);
+ * print(JSON.stringify(multiplied)); // {"x":1,"y":4,"z":9}
+ */
glm::vec3 multiplyVbyV(const glm::vec3& v1, const glm::vec3& v2) { return v1 * v2; }
+
+ /**jsdoc
+ * Rotate a vector.
+ * @function Vec3(0).multiplyQbyV
+ * @param {Quat} q - The rotation to apply.
+ * @param {Vec3} v - The vector to rotate.
+ * @returns {Vec3} v
rotated by q
.
+ * @example Rotate the negative z-axis by 90 degrees about the x-axis.
+ * var v = Vec3.UNIT_NEG_Z;
+ * var q = Quat.fromPitchYawRollDegrees(90, 0, 0);
+ * var result = Vec3.multiplyQbyV(q, v);
+ * print(JSON.stringify(result)); // {"x":0,"y":1.000,"z":1.19e-7}
+ */
glm::vec3 multiplyQbyV(const glm::quat& q, const glm::vec3& v) { return q * v; }
+
+ /**jsdoc
+ * Calculate the sum of two vectors.
+ * @function Vec3(0).sum
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @returns {Vec3} The sum of the two vectors.
+ */
glm::vec3 sum(const glm::vec3& v1, const glm::vec3& v2) { return v1 + v2; }
+
+ /**jsdoc
+ * Calculate one vector subtracted from another.
+ * @function Vec3(0).subtract
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @returns {Vec3} The second vector subtracted from the first.
+ */
glm::vec3 subtract(const glm::vec3& v1, const glm::vec3& v2) { return v1 - v2; }
+
+ /**jsdoc
+ * Calculate the length of a vector
+ * @function Vec3(0).length
+ * @param {Vec3} v - The vector.
+ * @returns {number} The length of the vector.
+ */
float length(const glm::vec3& v) { return glm::length(v); }
+
+ /**jsdoc
+ * Calculate the distance between two points.
+ * @function Vec3(0).distance
+ * @param {Vec3} p1 - The first point.
+ * @param {Vec3} p2 - The second point.
+ * @returns {number} The distance between the two points.
+ * @example The distance between two points is aways positive.
+ * var p1 = { x: 0, y: 0, z: 0 };
+ * var p2 = { x: 0, y: 0, z: 10 };
+ * var distance = Vec3.distance(p1, p2);
+ * print(distance); // 10
+ *
+ * p2 = { x: 0, y: 0, z: -10 };
+ * distance = Vec3.distance(p1, p2);
+ * print(distance); // 10
+ */
float distance(const glm::vec3& v1, const glm::vec3& v2) { return glm::distance(v1, v2); }
+
+ /**jsdoc
+ * Calculate the angle of rotation from one vector onto another, with the sign depending on a reference vector.
+ * @function Vec3(0).orientedAngle
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @param {Vec3} ref - Reference vector.
+ * @returns {number} The angle of rotation from the first vector to the second, in degrees, with a positive sign if the
+ * rotation axis aligns with the reference vector (has a positive dot product) otherwise a negative sign.
+ * @example Compare Vec3.angle()
and Vec3.orientedAngle()
.
+ * var v1 = { x: 5, y: 0, z: 0 };
+ * var v2 = { x: 5, y: 0, z: 5 };
+ * var angle = Vec3.getAngle(v1, v2);
+ * print(angle * 180 / Math.PI); // 45
+ *
+ * print(Vec3.orientedAngle(v1, v2, Vec3.UNIT_Y)); // -45
+ * print(Vec3.orientedAngle(v1, v2, Vec3.UNIT_NEG_Y)); // 45
+ * print(Vec3.orientedAngle(v1, v2, { x: 1, y: 2, z: -1 })); // -45
+ * print(Vec3.orientedAngle(v1, v2, { x: 1, y: -2, z: -1 })); // 45
+ */
float orientedAngle(const glm::vec3& v1, const glm::vec3& v2, const glm::vec3& v3);
+
+ /**jsdoc
+ * Normalize a vector so that its length is 1
.
+ * @function Vec3(0).normalize
+ * @param {Vec3} v - The vector to normalize.
+ * @returns {Vec3} The vector normalized to have a length of 1
.
+ * @example Normalize a vector.
+ * var v = { x: 10, y: 10, z: 0 };
+ * var normalized = Vec3.normalize(v);
+ * print(JSON.stringify(normalized)); // {"x":0.7071,"y":0.7071,"z":0}
+ * print(Vec3.length(normalized)); // 1
+ */
glm::vec3 normalize(const glm::vec3& v) { return glm::normalize(v); };
+
+ /**jsdoc
+ * Calculate a linear interpolation between two vectors.
+ * @function Vec3(0).mix
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @param {number} factor - The interpolation factor in the range 0.0
to 1.0
.
+ * @returns {Vec3} The linear interpolation between the two vectors: (1 - factor) * v1 + factor * v2
.
+ * @example Linear interpolation between two vectors.
+ * var v1 = { x: 10, y: 0, z: 0 };
+ * var v2 = { x: 0, y: 10, z: 0 };
+ * var interpolated = Vec3.mix(v1, v2, 0.75); // 1/4 of v1 and 3/4 of v2.
+ * print(JSON.stringify(interpolated)); // {"x":2.5,"y":7.5","z":0}
+ */
glm::vec3 mix(const glm::vec3& v1, const glm::vec3& v2, float m) { return glm::mix(v1, v2, m); }
+
+ /**jsdoc
+ * Print to the program log a text label followed by a vector value.
+ * @function Vec3(0).print
+ * @param {string} label - The label to print.
+ * @param {Vec3} v - The vector value to print.
+ * @example Two ways of printing a label and vector value.
+ * var v = { x: 1, y: 2, z: 3 };
+ * Vec3.print("Vector: ", v); // dvec3(1.000000, 2.000000, 3.000000)
+ * print("Vector: " + JSON.stringify(v)); // {"x":1,"y":2,"z":3}
+ */
void print(const QString& label, const glm::vec3& v);
+
+ /**jsdoc
+ * Test whether two vectors are equal. Note: The vectors must be exactly equal in order for
+ * true
to be returned; it is often better to use {@link Vec3(0).withinEpsilon|withinEpsilon}.
+ * @function Vec3(0).equal
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @returns {boolean} true
if the two vectors are exactly equal, otherwise false
.
+ * @example Vectors are only equal if exactly the same.
+ * var v1 = { x: 10, y: 10, z: 10 };
+ * var v2 = { x: 10, y: 10, z: 10 };
+ * var equal = Vec3.equal(v1, v2);
+ * print(equal); // true
+ *
+ * v2 = { x: 10, y: 10, z: 10.0005 };
+ * equal = Vec3.equal(v1, v2);
+ * print(equal); // false
+ */
bool equal(const glm::vec3& v1, const glm::vec3& v2) { return v1 == v2; }
+
+ /**jsdoc
+ * Test whether two vectors are equal within a tolerance. Note: It is often better to use this function
+ * than {@link Vec3(0).equal|equal}.
+ * @function Vec3(0).withinEpsilon
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @param {number} epsilon - The maximum distance between the two vectors.
+ * @returns {boolean} true
if the distance between the points represented by the vectors is less than or equal
+ * to the epsilon
, otherwise false
.
+ * @example Testing vectors for near equality.
+ * var v1 = { x: 10, y: 10, z: 10 };
+ * var v2 = { x: 10, y: 10, z: 10.0005 };
+ * var equal = Vec3.equal(v1, v2);
+ * print(equal); // false
+ *
+ * equal = Vec3.withinEpsilon(v1, v2, 0.001);
+ * print(equal); // true
+ */
bool withinEpsilon(const glm::vec3& v1, const glm::vec3& v2, float epsilon);
+
+ /**jsdoc
+ * Calculate polar coordinates (elevation, azimuth, radius) that transform the unit z-axis vector onto a point.
+ * @function Vec3(0).toPolar
+ * @param {Vec3} p - The point to calculate the polar coordinates for.
+ * @returns {Vec3} Vector of polar coordinates for the point: x
elevation rotation about the x-axis in
+ * radians, y
azimuth rotation about the y-axis in radians, and z
scale.
+ * @example Polar coordinates for a point.
+ * var v = { x: 5, y: 2.5, z: 5 };
+ * var polar = Vec3.toPolar(v);
+ * print("Elevation: " + polar.x * 180 / Math.PI); // -19.471
+ * print("Azimuth: " + polar.y * 180 / Math.PI); // 45
+ * print("Radius: " + polar.z); // 7.5
+ */
// FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation
glm::vec3 toPolar(const glm::vec3& v);
+
+ /**jsdoc
+ * Calculate the coordinates of a point from polar coordinate transformation of the unit z-axis vector.
+ * @function Vec3(0).fromPolar
+ * @param {Vec3} polar - The polar coordinates of a point: x
elevation rotation about the x-axis in radians,
+ * y
azimuth rotation about the y-axis in radians, and z
scale.
+ * @returns {Vec3} The coordinates of the point.
+ * @example Polar coordinates to Cartesian.
+ * var polar = { x: -19.471 * Math.PI / 180, y: 45 * Math.PI / 180, z: 7.5 };
+ * var p = Vec3.fromPolar(polar);
+ * print(JSON.stringify(p)); // {"x":5,"y":2.5,"z":5}
+ */
+ // FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation
glm::vec3 fromPolar(const glm::vec3& polar);
+
+ /**jsdoc
+ * Calculate the unit vector corresponding to polar coordinates elevation and azimuth transformation of the unit z-axis
+ * vector.
+ * @function Vec3(0).fromPolar
+ * @param {number} elevation - Rotation about the x-axis, in radians.
+ * @param {number} azimuth - Rotation about the y-axis, in radians.
+ * @returns {Vec3} Unit vector for the direction specified by elevation
and azimuth
.
+ * @example Polar coordinates to Cartesian.
+ * var elevation = -19.471 * Math.PI / 180;
+ * var rotation = 45 * Math.PI / 180;
+ * var p = Vec3.fromPolar(elevation, rotation);
+ * print(JSON.stringify(p)); // {"x":0.667,"y":0.333,"z":0.667}
+ *
+ * p = Vec3.multiply(7.5, p);
+ * print(JSON.stringify(p)); // {"x":5,"y":2.5,"z":5}
+ */
+ // FIXME misnamed, should be 'spherical' or 'euler' depending on the implementation
glm::vec3 fromPolar(float elevation, float azimuth);
+
+ /**jsdoc
+ * Calculate the angle between two vectors.
+ * @function Vec3(0).getAngle
+ * @param {Vec3} v1 - The first vector.
+ * @param {Vec3} v2 - The second vector.
+ * @returns {number} The angle between the two vectors, in radians.
+ * @example Calculate the angle between two vectors.
+ * var v1 = { x: 10, y: 0, z: 0 };
+ * var v2 = { x: 0, y: 0, z: 10 };
+ * var angle = Vec3.getAngle(v1, v2);
+ * print(angle * 180 / Math.PI); // 90
+ */
float getAngle(const glm::vec3& v1, const glm::vec3& v2);
private: