tsVector Tutorial

Introduction

Welcome to the tsVector tutorial! This tutorial introduces the core concepts and functionalities of the tsVector library, a minimalist JavaScript library for vector and matrix operations.

Getting Started

tsVector provides a minimalist approach to vector and matrix operations. This tutorial will guide you through the basic concepts and common use cases.

This tutorial does not intend to motivate or explain the theoretical background of vector and matrix operations, but rather to provide a practical guide to using the tsVector library. For an introduction to these concepts, please refer to external resources such as Wikipedia's article on vectors and the invectorize interactive tutorial.

Basic Vector Operations

Vectors are fundamental building blocks in tsVector. Here's how to work with them:



import * as tsVector from 'tsvector';

const v1 = [1, 2, 3];
const v2 = [4, -5, 6];

console.log('v1 + v2:', tsVector.vAdd(v1, v2)); // Output: [5, -3, 9]
console.log('v1 - v2:', tsVector.vSub(v1, v2)); // Output: [-3, 7, -3]
console.log('min(v1, v2):', tsVector.vMin(v1, v2)); // Output: [1, -5, 3]
console.log('max(v1, v2):', tsVector.vMax(v1, v2)); // Output: [4, 2, 6]
console.log('2 * v1:', tsVector.vScale(2, v1)); // Output: [2, 4, 6]

// element wise multiplication
console.log('v1 * v2:', tsVector.vMul(v1, v2)); // Output: [4, -10, 18]

// element wise division
console.log('v1 / v2:', tsVector.vDiv(v1, v2)); // Output: [0.25, -0.4, 0.5]

// dot product
const vx = [1, 0, 0];
const vy = [0, 1, 0];
console.log('vx . v2:', tsVector.vDot(vx, v2)); // Output: 4

// cross product
console.log('vx x vy:', tsVector.vCross(vx, vy)); // Output: [0, 0, 1]

// length
console.log('length of [3, 4, 0]:', tsVector.vLength([3, 4, 0])); // Output: 5

// unit normalized vector
console.log('unit vector of [3, 4, 0]:', tsVector.vNormalize([3, 4, 0])); 
// Output: [0.6, 0.8, 0]

Working with Matrices

Matrices are often used to transform vectors.


import * as tsVector from 'tsvector';

// 3x3 identity matrix
const I3 = tsVector.eye(3);
console.log('Identity matrix:', I3);
// Output: [[1, 0, 0], [0, 1, 0], [0, 0, 1]]

// 3x3 rotation matrix for 90 degrees around Z axis
const angle = Math.PI / 2;
const Rz = tsVector.yaw(angle);
console.log('Rotation matrix (90 degrees around Z):', Rz);
// Output: [[0, -1, 0], [1, 0, 0], [0, 0, 1]]

// 3x3 rotation matrix for 90 degrees around X axis
const Rx = tsVector.roll(angle);
console.log('Rotation matrix (90 degrees around X):', Rx);
// Output: [[1, 0, 0], [0, 0, 1], [0, -1, 0]]

const v = [6, -7, 8]
// Rotate v by 90 degrees around Z axis
const v_rotated_z = tsVector.MvProduct(Rz, v);
console.log('v rotated by 90 degrees around Z:', v_rotated_z);
// Output: [7, 6, 8]

// first rotate 90 degrees around Z, then 90 degrees around X
const R = tsVector.MMProduct(Rx, Rz);
console.log('Combined rotation matrix (Rz followed by Rx):', R);
// Output: [[0, -1, 0], [0, 0, 1], [-1, 0, 0]]

// Rotate v by the combined rotation
const v_rotated_combined = tsVector.MvProduct(R, v);
console.log('v rotated by combined rotation:', v_rotated_combined);
// Output: [7, 8, -6]

// The inverse rotation.
const R_inv = tsVector.MInverse(R);
console.log('Inverse of combined rotation matrix:', R_inv);
// Output: [[0, 0, -1], [-1, 0, 0], [0, 1, 0]]

Example: rotating a cube

The following discussion is based on the code in docs-assets/tutorial_cube.js. It demonstrates how to use tsVector to rotate a cube in 3D space and display it in an HTML5 canvas.

First, we define the vertices of a cube centered at the origin:


const vertices = [
    [-1, -1, -1],
    [1, -1, -1],
    [1, 1, -1],
    [-1, 1, -1],
    [-1, -1, 1],
    [1, -1, 1],
    [1, 1, 1],
    [-1, 1, 1]
];

Next, we define the edges of the cube as pairs of vertex indices:


const edges = [
    [0, 1], [1, 2], [2, 3], [3, 0], // bottom face
    [4, 5], [5, 6], [6, 7], [7, 4], // top face
    [0, 4], [1, 5], [2, 6], [3, 7]  // vertical edges
];

To rotate the cube, we create rotation matrices for the desired angles around the X and Y axes, and then combine them:


const angle = Math.PI / 4; // 45 degrees
const pitchMatrix = tsVector.pitch(angle)
const rollMatrix = tsVector.roll(angle/2)
const yawMatrix = tsVector.yaw(angle/3)

Then we combine them into a single rotation matrix:


const rotationMatrix = tsVector.MMProduct(
    tsVector.MMProduct(pitchMatrix, rollMatrix), 
    yawMatrix);

Then we rotate the vertices:


const rotatedVertices = vertices.map(
    vertex => tsVector.MvProduct(rotationMatrix, vertex))

Then we scale and shift the vertices so they will fall into the canvas coordinate system.


// Scale each vertex by a scale factor
const scaleFactor = 150;
const scaledVertices = rotatedVertices.map(vertex => 
    tsVector.vScale(scaleFactor, vertex)
);

// Shift each vertex by twice the scale factor in the x and y directions
const shiftVector = [scaleFactor * 2, scaleFactor * 2, 0];
const shiftedVertices = scaledVertices.map(vertex => 
    tsVector.vAdd(vertex, shiftVector)
);

Finally, we draw the edges of the cube (projected to 2d x, y coordinates) on the canvas:


// get and empty the output div
const outputDiv = document.getElementById('output');
outputDiv.innerHTML = '';

// Create a canvas element and append it to the output div
const canvas = document.createElement('canvas');
canvas.width = 800;
canvas.height = 600;
outputDiv.appendChild(canvas);

// Get the 2D drawing context from the canvas
const ctx = canvas.getContext('2d');

// Draw the edges of the cube on the canvas
ctx.strokeStyle = 'black';
edges.forEach(edge => {
    const [startIndex, endIndex] = edge;
    const startVertex = shiftedVertices[startIndex];
    const endVertex = shiftedVertices[endIndex];
    
    ctx.beginPath();
    ctx.moveTo(startVertex[0], startVertex[1]);
    ctx.lineTo(endVertex[0], endVertex[1]);
    ctx.stroke();
})
And the end result looks like this:
Canvas will go here.

Next Steps