init commit
This commit is contained in:
commit
43b2a34fe7
|
|
@ -0,0 +1,29 @@
|
|||
module.exports = {
|
||||
env: {
|
||||
es2021: true,
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier",
|
||||
],
|
||||
overrides: [
|
||||
{
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
files: [".eslintrc.{js,cjs}"],
|
||||
parserOptions: {
|
||||
sourceType: "script",
|
||||
},
|
||||
},
|
||||
],
|
||||
parser: "@typescript-eslint/parser",
|
||||
parserOptions: {
|
||||
ecmaVersion: "latest",
|
||||
sourceType: "module",
|
||||
},
|
||||
plugins: ["@typescript-eslint"],
|
||||
rules: {},
|
||||
};
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
.vs
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
# Ignore artifacts:
|
||||
dist
|
||||
example
|
||||
|
|
@ -0,0 +1 @@
|
|||
{}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
# Vector2D Library for TypeScript
|
||||
|
||||
A comprehensive TypeScript library for 2D vector operations, including addition, subtraction, multiplication, division, normalization, and more. Ideal for game development, physics simulations, and graphical applications.
|
||||
|
||||
## Features
|
||||
|
||||
- Create and manipulate 2D vectors
|
||||
- Perform vector arithmetic (addition, subtraction, multiplication, division)
|
||||
- Calculate dot and cross products
|
||||
- Normalize vectors
|
||||
- Calculate magnitude and distance between vectors
|
||||
- Rotate vectors
|
||||
- Linear interpolation between vectors
|
||||
|
||||
## Installation
|
||||
|
||||
You can install the library using npm:
|
||||
|
||||
```bash
|
||||
npm install vector2d
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
Here's a quick example of how to use the `Vector2D` class:
|
||||
|
||||
```typescript
|
||||
import { Vector2D } from 'vector2d';
|
||||
|
||||
const vector1 = new Vector2D(3, 4);
|
||||
const vector2 = new Vector2D(1, 2);
|
||||
|
||||
// Vector addition
|
||||
const result = vector1.add(vector2);
|
||||
console.log(`Result of addition: (${result.getX()}, ${result.getY()})`);
|
||||
|
||||
// Vector normalization
|
||||
const normalized = vector1.normalize();
|
||||
console.log(`Normalized vector: (${normalized.getX()}, ${normalized.getY()})`);
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `Vector2D`
|
||||
|
||||
#### Constructor
|
||||
|
||||
```typescript
|
||||
constructor(x: number, y: number)
|
||||
x - The x-coordinate.
|
||||
y - The y-coordinate.
|
||||
|
||||
Methods
|
||||
- `getX(): number` - Gets the x-coordinate.
|
||||
- `getY(): number` - Gets the y-coordinate.
|
||||
- `setX(x: number): void` - Sets the x-coordinate.
|
||||
- `setY(y: number): void` - Sets the y-coordinate.
|
||||
- `set(x: number, y: number): void` - Sets both the x and y coordinates.
|
||||
- `add(vector: Vector2D): Vector2D` - Adds another vector to this vector.
|
||||
- `subtract(vector: Vector2D): Vector2D` - Subtracts another vector from this vector.
|
||||
- `multiply(scalar: number): Vector2D` - Multiplies this vector by a scalar.
|
||||
- `divide(scalar: number): Vector2D` - Divides this vector by a scalar.
|
||||
- `dot(vector: Vector2D): number` - Calculates the dot product of this vector and another vector.
|
||||
- `cross(vector: Vector2D): number` - Calculates the cross product of this vector and another vector.
|
||||
- `magnitude(): number` - Calculates the magnitude (length) of this vector.
|
||||
- `normalize(): Vector2D` - Normalizes this vector (makes it have a magnitude of 1).
|
||||
- `clone(): Vector2D` - Creates a copy of this vector.
|
||||
- `equals(vector: Vector2D): boolean` - Checks if this vector is equal to another vector.
|
||||
- `toString(): string` - Returns a string representation of this vector.
|
||||
- `distance(vector: Vector2D): number` - Calculates the distance to another vector.
|
||||
- `angle(): number` - Calculates the angle of this vector relative to the positive X-axis.
|
||||
- `rotate(angle: number): Vector2D` - Rotates this vector by a given angle.
|
||||
- `lerp(vector: Vector2D, t: number): Vector2D` - Performs linear interpolation between this vector and another vector.
|
||||
```
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||
export default {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
};
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "@yazmeyaa/vector2d",
|
||||
"private": false,
|
||||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/yazmeyaa/vector2d"
|
||||
},
|
||||
"main": "./dist/index.umd.cjs",
|
||||
"module": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"build": "tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"predeploy": "npm run dist",
|
||||
"lint": "eslint src --ext .ts",
|
||||
"lint:fix": "eslint src --ext .ts --fix",
|
||||
"format": "prettier --write ./src/**/*.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@jest/globals": "^29.7.0",
|
||||
"@rollup/plugin-typescript": "^11.1.6",
|
||||
"@types/jest": "^29.5.12",
|
||||
"@types/node": "^20.14.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.15.0",
|
||||
"@typescript-eslint/parser": "^7.15.0",
|
||||
"eslint": "8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.3.2",
|
||||
"rollup-plugin-typescript-paths": "^1.5.0",
|
||||
"ts-jest": "^29.1.5",
|
||||
"tslib": "^2.6.3",
|
||||
"typescript": "^5.5.3",
|
||||
"vite": "^5.3.1",
|
||||
"vite-plugin-dts": "^3.9.1",
|
||||
"vite-tsconfig-paths": "^4.3.2"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
export interface IVector2D {
|
||||
getX(): number;
|
||||
getY(): number;
|
||||
setX(x: number): void;
|
||||
setY(y: number): void;
|
||||
set(x: number, y: number): void;
|
||||
add(vector: IVector2D): IVector2D;
|
||||
subtract(vector: IVector2D): IVector2D;
|
||||
multiply(scalar: number): IVector2D;
|
||||
divide(scalar: number): IVector2D;
|
||||
dot(vector: IVector2D): number;
|
||||
cross(vector: IVector2D): number;
|
||||
magnitude(): number;
|
||||
normalize(): IVector2D;
|
||||
clone(): IVector2D;
|
||||
equals(vector: IVector2D): boolean;
|
||||
toString(): string;
|
||||
distance(vector: IVector2D): number;
|
||||
angle(): number;
|
||||
rotate(angle: number): IVector2D;
|
||||
}
|
||||
|
|
@ -0,0 +1,130 @@
|
|||
import { Vector2D } from "./vector2d";
|
||||
|
||||
describe("Vector2D", () => {
|
||||
test("constructor initializes correctly", () => {
|
||||
const vector = new Vector2D(3, 4);
|
||||
expect(vector.getX()).toBe(3);
|
||||
expect(vector.getY()).toBe(4);
|
||||
});
|
||||
|
||||
test("setX and setY update coordinates", () => {
|
||||
const vector = new Vector2D(0, 0);
|
||||
vector.setX(5);
|
||||
vector.setY(-3);
|
||||
expect(vector.getX()).toBe(5);
|
||||
expect(vector.getY()).toBe(-3);
|
||||
});
|
||||
|
||||
test("set updates both coordinates", () => {
|
||||
const vector = new Vector2D(0, 0);
|
||||
vector.set(2, 3);
|
||||
expect(vector.getX()).toBe(2);
|
||||
expect(vector.getY()).toBe(3);
|
||||
});
|
||||
|
||||
test("add returns correct vector", () => {
|
||||
const vector1 = new Vector2D(1, 2);
|
||||
const vector2 = new Vector2D(3, 4);
|
||||
const result = vector1.add(vector2);
|
||||
expect(result.getX()).toBe(4);
|
||||
expect(result.getY()).toBe(6);
|
||||
});
|
||||
|
||||
test("subtract returns correct vector", () => {
|
||||
const vector1 = new Vector2D(5, 7);
|
||||
const vector2 = new Vector2D(2, 3);
|
||||
const result = vector1.subtract(vector2);
|
||||
expect(result.getX()).toBe(3);
|
||||
expect(result.getY()).toBe(4);
|
||||
});
|
||||
|
||||
test("multiply scales vector correctly", () => {
|
||||
const vector = new Vector2D(2, 3);
|
||||
const result = vector.multiply(2);
|
||||
expect(result.getX()).toBe(4);
|
||||
expect(result.getY()).toBe(6);
|
||||
});
|
||||
|
||||
test("divide scales vector correctly", () => {
|
||||
const vector = new Vector2D(4, 8);
|
||||
const result = vector.divide(2);
|
||||
expect(result.getX()).toBe(2);
|
||||
expect(result.getY()).toBe(4);
|
||||
});
|
||||
|
||||
test("dot product is correct", () => {
|
||||
const vector1 = new Vector2D(1, 2);
|
||||
const vector2 = new Vector2D(3, 4);
|
||||
expect(vector1.dot(vector2)).toBe(11);
|
||||
});
|
||||
|
||||
test("cross product is correct", () => {
|
||||
const vector1 = new Vector2D(1, 2);
|
||||
const vector2 = new Vector2D(3, 4);
|
||||
expect(vector1.cross(vector2)).toBe(-2);
|
||||
});
|
||||
|
||||
test("magnitude is correct", () => {
|
||||
const vector = new Vector2D(3, 4);
|
||||
expect(vector.magnitude()).toBe(5);
|
||||
});
|
||||
|
||||
test("normalize returns unit vector", () => {
|
||||
const vector = new Vector2D(3, 4);
|
||||
const result = vector.normalize();
|
||||
expect(result.magnitude()).toBeCloseTo(1);
|
||||
expect(result.getX()).toBeCloseTo(0.6);
|
||||
expect(result.getY()).toBeCloseTo(0.8);
|
||||
});
|
||||
|
||||
test("clone creates a copy of the vector", () => {
|
||||
const vector = new Vector2D(1, 2);
|
||||
const clone = vector.clone();
|
||||
expect(clone.getX()).toBe(1);
|
||||
expect(clone.getY()).toBe(2);
|
||||
expect(clone).not.toBe(vector);
|
||||
});
|
||||
|
||||
test("equals returns true for identical vectors", () => {
|
||||
const vector1 = new Vector2D(1, 2);
|
||||
const vector2 = new Vector2D(1, 2);
|
||||
expect(vector1.equals(vector2)).toBe(true);
|
||||
});
|
||||
|
||||
test("equals returns false for different vectors", () => {
|
||||
const vector1 = new Vector2D(1, 2);
|
||||
const vector2 = new Vector2D(2, 3);
|
||||
expect(vector1.equals(vector2)).toBe(false);
|
||||
});
|
||||
|
||||
test("toString returns correct string representation", () => {
|
||||
const vector = new Vector2D(1, 2);
|
||||
expect(vector.toString()).toBe("(1, 2)");
|
||||
});
|
||||
|
||||
test("distance calculates correctly", () => {
|
||||
const vector1 = new Vector2D(1, 2);
|
||||
const vector2 = new Vector2D(4, 6);
|
||||
expect(vector1.distance(vector2)).toBe(5);
|
||||
});
|
||||
|
||||
test("angle calculates correctly", () => {
|
||||
const vector = new Vector2D(1, 1);
|
||||
expect(vector.angle()).toBeCloseTo(Math.PI / 4);
|
||||
});
|
||||
|
||||
test("rotate rotates vector correctly", () => {
|
||||
const vector = new Vector2D(1, 0);
|
||||
const result = vector.rotate(Math.PI / 2);
|
||||
expect(result.getX()).toBeCloseTo(0);
|
||||
expect(result.getY()).toBeCloseTo(1);
|
||||
});
|
||||
|
||||
test('lerp interpolates correctly', () => {
|
||||
const vector1 = new Vector2D(0, 0);
|
||||
const vector2 = new Vector2D(10, 10);
|
||||
const result = vector1.lerp(vector2, 0.5);
|
||||
expect(result.getX()).toBe(5);
|
||||
expect(result.getY()).toBe(5);
|
||||
});
|
||||
});
|
||||
|
|
@ -0,0 +1,198 @@
|
|||
export class Vector2D {
|
||||
private x: number;
|
||||
private y: number;
|
||||
|
||||
/**
|
||||
* Creates a new vector with coordinates (x, y).
|
||||
* @param {number} x - The x-coordinate.
|
||||
* @param {number} y - The y-coordinate.
|
||||
*/
|
||||
constructor(x: number, y: number) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the x-coordinate.
|
||||
* @returns {number} The x-coordinate.
|
||||
*/
|
||||
getX(): number {
|
||||
return this.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the y-coordinate.
|
||||
* @returns {number} The y-coordinate.
|
||||
*/
|
||||
getY(): number {
|
||||
return this.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the x-coordinate.
|
||||
* @param {number} x - The new x-coordinate.
|
||||
*/
|
||||
setX(x: number): void {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the y-coordinate.
|
||||
* @param {number} y - The new y-coordinate.
|
||||
*/
|
||||
setY(y: number): void {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets both the x and y coordinates.
|
||||
* @param {number} x - The new x-coordinate.
|
||||
* @param {number} y - The new y-coordinate.
|
||||
*/
|
||||
set(x: number, y: number): void {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another vector to this vector.
|
||||
* @param {Vector2D} vector - The vector to add.
|
||||
* @returns {Vector2D} The resulting vector.
|
||||
*/
|
||||
add(vector: Vector2D): Vector2D {
|
||||
return new Vector2D(this.x + vector.getX(), this.y + vector.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Subtracts another vector from this vector.
|
||||
* @param {Vector2D} vector - The vector to subtract.
|
||||
* @returns {Vector2D} The resulting vector.
|
||||
*/
|
||||
subtract(vector: Vector2D): Vector2D {
|
||||
return new Vector2D(this.x - vector.getX(), this.y - vector.getY());
|
||||
}
|
||||
|
||||
/**
|
||||
* Multiplies this vector by a scalar.
|
||||
* @param {number} scalar - The scalar to multiply by.
|
||||
* @returns {Vector2D} The resulting vector.
|
||||
*/
|
||||
multiply(scalar: number): Vector2D {
|
||||
return new Vector2D(this.x * scalar, this.y * scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Divides this vector by a scalar.
|
||||
* @param {number} scalar - The scalar to divide by.
|
||||
* @returns {Vector2D} The resulting vector.
|
||||
*/
|
||||
divide(scalar: number): Vector2D {
|
||||
return new Vector2D(this.x / scalar, this.y / scalar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the dot product of this vector and another vector.
|
||||
* @param {Vector2D} vector - The other vector.
|
||||
* @returns {number} The dot product.
|
||||
*/
|
||||
dot(vector: Vector2D): number {
|
||||
return this.x * vector.getX() + this.y * vector.getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the cross product of this vector and another vector.
|
||||
* @param {Vector2D} vector - The other vector.
|
||||
* @returns {number} The cross product.
|
||||
*/
|
||||
cross(vector: Vector2D): number {
|
||||
return this.x * vector.getY() - this.y * vector.getX();
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the magnitude (length) of this vector.
|
||||
* @returns {number} The magnitude of the vector.
|
||||
*/
|
||||
magnitude(): number {
|
||||
return Math.sqrt(this.x * this.x + this.y * this.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes this vector (makes it have a magnitude of 1).
|
||||
* @returns {Vector2D} The normalized vector.
|
||||
*/
|
||||
normalize(): Vector2D {
|
||||
const mag = this.magnitude();
|
||||
return new Vector2D(this.x / mag, this.y / mag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a copy of this vector.
|
||||
* @returns {Vector2D} The cloned vector.
|
||||
*/
|
||||
clone(): Vector2D {
|
||||
return new Vector2D(this.x, this.y);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this vector is equal to another vector.
|
||||
* @param {Vector2D} vector - The other vector.
|
||||
* @returns {boolean} True if the vectors are equal, false otherwise.
|
||||
*/
|
||||
equals(vector: Vector2D): boolean {
|
||||
return this.x === vector.getX() && this.y === vector.getY();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string representation of this vector.
|
||||
* @returns {string} The string representation of the vector.
|
||||
*/
|
||||
toString(): string {
|
||||
return `(${this.x}, ${this.y})`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the distance to another vector.
|
||||
* @param {Vector2D} vector - The other vector.
|
||||
* @returns {number} The distance to the other vector.
|
||||
*/
|
||||
distance(vector: Vector2D): number {
|
||||
const dx = this.x - vector.getX();
|
||||
const dy = this.y - vector.getY();
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the angle of this vector relative to the positive X-axis.
|
||||
* @returns {number} The angle in radians.
|
||||
*/
|
||||
angle(): number {
|
||||
return Math.atan2(this.y, this.x);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates this vector by a given angle.
|
||||
* @param {number} angle - The angle to rotate by in radians.
|
||||
* @returns {Vector2D} The rotated vector.
|
||||
*/
|
||||
rotate(angle: number): Vector2D {
|
||||
const cos = Math.cos(angle);
|
||||
const sin = Math.sin(angle);
|
||||
return new Vector2D(
|
||||
this.x * cos - this.y * sin,
|
||||
this.x * sin + this.y * cos,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs linear interpolation between this vector and another vector.
|
||||
* @param {Vector2D} vector - The other vector.
|
||||
* @param {number} t - The interpolation factor (between 0 and 1).
|
||||
* @returns {Vector2D} The interpolated vector.
|
||||
*/
|
||||
lerp(vector: Vector2D, t: number): Vector2D {
|
||||
return new Vector2D(
|
||||
this.x + t * (vector.getX() - this.x),
|
||||
this.y + t * (vector.getY() - this.y),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
/// <reference types="vite/client" />
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"module": "ESNext",
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import { defineConfig } from "vite";
|
||||
import path from "path";
|
||||
import dts from 'vite-plugin-dts';
|
||||
|
||||
const libConfig = defineConfig({
|
||||
build: {
|
||||
lib: {
|
||||
entry: path.resolve(__dirname, "src/index.ts"),
|
||||
fileName: "index",
|
||||
name: 'vector2d'
|
||||
},
|
||||
},
|
||||
plugins: [dts({exclude: "**/*.test.ts"})],
|
||||
});
|
||||
|
||||
export default libConfig
|
||||
Loading…
Reference in New Issue