Skip to content

Commit

Permalink
Merge pull request #25 from ieedan/add-triangles-to-math
Browse files Browse the repository at this point in the history
  • Loading branch information
ieedan authored Nov 20, 2024
2 parents 2f7e1ca + 886c83d commit ef66d99
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 1 deletion.
3 changes: 2 additions & 1 deletion src/utilities/math/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as conversions from './conversions';
import * as fractions from './fractions';
import { gcd, gcf } from './gcf';
import * as triangles from './triangles';

export { gcf, gcd, fractions, conversions };
export { gcf, gcd, fractions, conversions, triangles };
38 changes: 38 additions & 0 deletions src/utilities/math/triangles.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { describe, expect, it } from 'vitest';
import * as math from '.';

describe('right', () => {
it('solves for triangle consistently', () => {
expect(math.triangles.right.solve({ angle: 30, opposite: 5 })).toStrictEqual({
adjacent: 8.660254037844387,
angle: 30,
hypotenuse: 10.000000000000002,
opposite: 5,
});

expect(
math.triangles.right.solve({ angle: 30, adjacent: 8.660254037844387 })
).toStrictEqual({
adjacent: 8.660254037844387,
angle: 30,
hypotenuse: 10,
opposite: 5,
});

expect(math.triangles.right.solve({ angle: 30, hypotenuse: 10 })).toStrictEqual({
adjacent: 8.660254037844387,
angle: 30,
hypotenuse: 10,
opposite: 4.999999999999999,
});
});

it('throws if 0 angle provided', () => {
expect(() => math.triangles.right.solve({ angle: 0, hypotenuse: 10 })).toThrow();
});

it('throws if incorrect arguments were provided due to ignored type error', () => {
// @ts-ignore
expect(() => math.triangles.right.solve({ angle: 10 })).toThrow();
});
});
104 changes: 104 additions & 0 deletions src/utilities/math/triangles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { dtr } from './conversions';

export type RightTriangle = {
/** Angle in degrees */
angle: number;
/** opposite length */
opposite: number;
/** adjacent length */
adjacent: number;
/** hypotenuse length */
hypotenuse: number;
};

export type SolveOptions =
| {
angle: number;
opposite: number;
adjacent?: never;
hypotenuse?: never;
}
| {
angle: number;
opposite?: never;
adjacent: number;
hypotenuse?: never;
}
| {
angle: number;
opposite?: never;
adjacent?: never;
hypotenuse: number;
};

/** Solves the right triangle based on the angle given and any one of the sides
*
* @param param0
* @returns
*/
const solveRight = ({ angle, opposite, adjacent, hypotenuse }: SolveOptions): RightTriangle => {
if (angle <= 0) throw new Error(`Invalid value (${angle}) for 'angle'`);

if (typeof hypotenuse === 'number') {
opposite = solveForOpposite({ angle, hypotenuse });
adjacent = solveForAdjacent({ angle, hypotenuse });
} else if (typeof opposite === 'number') {
adjacent = solveForAdjacent({ angle, opposite });
hypotenuse = solveForHypotenuse({ angle, opposite });
} else if (typeof adjacent === 'number') {
opposite = solveForOpposite({ angle, adjacent });
hypotenuse = solveForHypotenuse({ angle, adjacent });
} else {
throw new Error(
'Incorrect arguments provided! expected opposite, adjacent, or hypotenuse to be a number'
);
}

return {
angle,
opposite,
adjacent,
hypotenuse,
};
};

type OppositeSolveOptions =
| { angle: number; adjacent: number; hypotenuse?: never }
| { angle: number; adjacent?: never; hypotenuse: number };

const solveForOpposite = ({ angle, adjacent, hypotenuse }: OppositeSolveOptions): number => {
if (typeof hypotenuse === 'number') {
return Math.sin(dtr(angle)) * hypotenuse;
}

return Math.tan(dtr(angle)) * adjacent;
};

type AdjacentSolveOptions =
| { angle: number; opposite: number; hypotenuse?: never }
| { angle: number; opposite?: never; hypotenuse: number };

const solveForAdjacent = ({ angle, opposite, hypotenuse }: AdjacentSolveOptions): number => {
if (typeof opposite === 'number') {
return opposite / Math.tan(dtr(angle));
}

return hypotenuse * Math.cos(dtr(angle));
};

type HypotenuseSolveOptions =
| { angle: number; opposite: number; adjacent?: never }
| { angle: number; opposite?: never; adjacent: number };

const solveForHypotenuse = ({ angle, opposite, adjacent }: HypotenuseSolveOptions): number => {
if (typeof opposite === 'number') {
return opposite / Math.sin(dtr(angle));
}

return adjacent / Math.cos(dtr(angle));
};

/** Functions for working with right triangles */
const right = { solve: solveRight };

export { right };

0 comments on commit ef66d99

Please sign in to comment.