Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Vector2 #257

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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: 6 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@
* Tries
* [Tries.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tries/test/tries.test.ts)
* [Tries](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/tries/tries.ts)
* Vectors
* Test
* [Vector2.Test](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/vectors/test/vector2.test.ts)
* [Vector2](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/data_structures/vectors/vector2.ts)

## Dynamic Programming
* [Coin Change](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/dynamic_programming/coin_change.ts)
Expand Down Expand Up @@ -156,6 +160,8 @@

## Search
* [Binary Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/binary_search.ts)
* [Exponential Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/exponential_search.ts)
* [Fibonacci Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/fibonacci_search.ts)
* [Interpolation Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/interpolation_search.ts)
* [Jump Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/jump_search.ts)
* [Linear Search](https://github.com/TheAlgorithms/TypeScript/blob/HEAD/search/linear_search.ts)
Expand Down
150 changes: 150 additions & 0 deletions data_structures/vectors/test/vector2.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import { Vector2 } from '../vector2'

describe('Vector2', () => {
describe('#equalsExactly', () => {
it('should compare equality correctly', () => {
expect(new Vector2(1, 0).equalsExactly(new Vector2(1, 0))).toBe(true)

expect(new Vector2(1.23, 4.56).equalsExactly(new Vector2(0, 0))).toBe(
false
)
})
})

describe('#equalsApproximately', () => {
it('should compare equality (approximately) correctly', () => {
expect(
new Vector2(1, 0).equalsApproximately(
new Vector2(1, 0.0000001),
0.000001
)
).toBe(true)

expect(
new Vector2(1.23, 4.56).equalsApproximately(
new Vector2(1.24, 4.56),
0.000001
)
).toBe(false)
})
})

describe('#add', () => {
it('should add two vectors correctly', () => {
expect(
new Vector2(1, 0)
.add(new Vector2(0, 1))
.equalsApproximately(new Vector2(1, 1), 0.000001)
).toBe(true)

expect(
new Vector2(-3.3, -9)
.add(new Vector2(-2.2, 3))
.equalsApproximately(new Vector2(-5.5, -6), 0.000001)
).toBe(true)
})
})

describe('#subtract', () => {
it('should subtract two vectors correctly', () => {
expect(
new Vector2(1, 0)
.subtract(new Vector2(0, 1))
.equalsApproximately(new Vector2(1, -1), 0.000001)
).toBe(true)

expect(
new Vector2(234.5, 1.7)
.subtract(new Vector2(3.3, 2.7))
.equalsApproximately(new Vector2(231.2, -1), 0.000001)
).toBe(true)
})
})

describe('#multiply', () => {
it('should multiply two vectors correctly', () => {
expect(
new Vector2(1, 0)
.multiply(5)
.equalsApproximately(new Vector2(5, 0), 0.000001)
).toBe(true)

expect(
new Vector2(3.41, -7.12)
.multiply(-3.1)
.equalsApproximately(new Vector2(-10.571, 22.072), 0.000001)
).toBe(true)
})
})

describe('#length', () => {
it('should calculate its length correctly', () => {
expect(new Vector2(1, 0).length()).toBe(1)

expect(new Vector2(-1, 1).length()).toBe(Math.sqrt(2))
})
})

describe('#normalize', () => {
it('should normalize vectors correctly', () => {
expect(
new Vector2(1, 0)
.normalize()
.equalsApproximately(new Vector2(1, 0), 0.000001)
).toBe(true)

expect(
new Vector2(1, -1)
.normalize()
.equalsApproximately(
new Vector2(Math.sqrt(2) / 2, -Math.sqrt(2) / 2),
0.000001
)
).toBe(true)
})
})

describe('#distance', () => {
it('should calculate the distance between two vectors correctly', () => {
expect(new Vector2(0, 0).distance(new Vector2(0, -1))).toBe(1)

expect(new Vector2(1, 0).distance(new Vector2(0, 1))).toBe(Math.sqrt(2))
})
})

describe('#dotProduct', () => {
it('should calculate the dot product correctly', () => {
expect(new Vector2(1, 0).dotProduct(new Vector2(0, 1))).toBe(0)

expect(new Vector2(1, 2).dotProduct(new Vector2(3, 4))).toBe(11) // 1 * 3 + 2 * 4
})
})

describe('#rotate', () => {
it('should rotate a vector correctly', () => {
expect(
new Vector2(0, -1)
.rotate(Math.PI / 2)
.equalsApproximately(new Vector2(1, 0), 0.000001)
).toBe(true)

expect(
new Vector2(1.23, -4.56)
.rotate(Math.PI)
.equalsApproximately(new Vector2(-1.23, 4.56), 0.000001)
).toBe(true)
})
})

describe('#angleBetween', () => {
it('should calculate the angle between two vectors correctly', () => {
expect(new Vector2(1, 0).angleBetween(new Vector2(0, 1))).toBe(
Math.PI / 2
)

expect(new Vector2(1, 0).angleBetween(new Vector2(1, -1))).toBe(
-Math.PI / 4
)
})
})
})
145 changes: 145 additions & 0 deletions data_structures/vectors/vector2.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/**
* In mathematics and physics, a vector is an element of a vector space.
*
* The Vector2-class implements 2-dimensional vectors together with various vector-operations.
* @see https://en.wikipedia.org/wiki/Vector_(mathematics_and_physics).
*/

class Vector2 {
x: number
y: number

constructor(x: number, y: number) {
this.x = x
this.y = y
}

/**
* Check for exact vector equality.
*
* @param vector The vector to compare to.
* @returns Whether they are exactly equal or not.
*/
equalsExactly(vector: Vector2): boolean {
return this.x === vector.x && this.y === vector.y
}

/**
* Check for approximate vector equality.
*
* @param vector The vector to compare to.
* @param epsilon The allowed discrepancy for the x-values and the y-values.
* @returns Whether they are approximately equal or not.
*/
equalsApproximately(vector: Vector2, epsilon: number): boolean {
return (
Math.abs(this.x - vector.x) < epsilon &&
Math.abs(this.y - vector.y) < epsilon
)
}

/**
* Vector length.
*
* @returns The length of the vector.
*/
length(): number {
return Math.sqrt(this.x * this.x + this.y * this.y)
}

/**
* Normalization sets the vector to length 1 while maintaining its direction.
*
* @returns The normalized vector.
*/
normalize(): Vector2 {
const length: number = this.length()
if (length === 0) {
throw new Error('Cannot normalize vectors of length 0')
}
return new Vector2(this.x / length, this.y / length)
}

/**
* Vector addition
*
* @param vector The vector to be added.
* @returns The sum-vector.
*/
add(vector: Vector2): Vector2 {
const x: number = this.x + vector.x
const y: number = this.y + vector.y
return new Vector2(x, y)
}

/**
* Vector subtraction
*
* @param vector The vector to be subtracted.
* @returns The difference-vector.
*/
subtract(vector: Vector2): Vector2 {
const x: number = this.x - vector.x
const y: number = this.y - vector.y
return new Vector2(x, y)
}

/**
* Vector scalar multiplication
*
* @param scalar The factor by which to multiply the vector.
* @returns The scaled vector.
*/
multiply(scalar: number): Vector2 {
const x: number = this.x * scalar
const y: number = this.y * scalar
return new Vector2(x, y)
}

/**
* Distance between this vector and another vector.
*
* @param vector The vector to which to calculate the distance.
* @returns The distance.
*/
distance(vector: Vector2): number {
const difference: Vector2 = this.subtract(vector)
return difference.length()
}

/**
* Vector dot product
*
* @param vector The vector used for the multiplication.
* @returns The resulting dot product.
*/
dotProduct(vector: Vector2): number {
return this.x * vector.x + this.y * vector.y
}

/**
* Vector rotation (see https://en.wikipedia.org/wiki/Rotation_matrix)
*
* @param angleInRadians The angle in radians by which to rotate the vector.
* @returns The rotated vector.
*/
rotate(angleInRadians: number): Vector2 {
const ca: number = Math.cos(angleInRadians)
const sa: number = Math.sin(angleInRadians)
const x: number = ca * this.x - sa * this.y
const y: number = sa * this.x + ca * this.y
return new Vector2(x, y)
}

/**
* Measure angle between two vectors
*
* @param vector The 2nd vector for the measurement.
* @returns The angle in radians.
*/
angleBetween(vector: Vector2): number {
return Math.atan2(vector.y, vector.x) - Math.atan2(this.y, this.x)
}
}

export { Vector2 }
Loading