diff --git a/src/lib/calculateDirection/calculateDirection.js b/src/lib/calculateDirection/calculateDirection.js new file mode 100644 index 0000000..5ebf113 --- /dev/null +++ b/src/lib/calculateDirection/calculateDirection.js @@ -0,0 +1,52 @@ +import { calculateCollision } from '../calculateCollision/calculateCollision'; + +/** + * Вычисляет направление наибольшего пересечения по осям и возвращает tuple множителей для изменения координат + * @param {Object} firstObject - первый объект + * @param {number} firstObject.left - Min X координата первого объекта + * @param {number} firstObject.right - Max X координата первого объекта + * @param {number} firstObject.top - Min Y координата первого объекта (ось смотрит вниз) + * @param {number} firstObject.bottom - Max Y координата первого объекта + * @param {Object} secondObject - второй объект + * @param {number} secondObject.left - Min X координата второго объекта + * @param {number} secondObject.right - Max X координата второго объекта + * @param {number} secondObject.top - Min Y координата второго объекта (ось смотрит вниз) + * @param {number} secondObject.bottom - Max Y координата второго объекта + * @returns {Array} tuple формата [1, -1] с множителями для осей X и Y. Каждый может принимать значение либо 1, либо -1 + */ +export function calculateDirection(firstObject, secondObject) { + try { + // Запускаем для проверки формата аргументов + const isCollided = calculateCollision(firstObject, secondObject); + + if (isCollided === null) { + return null; + } + + if (!isCollided) { + return [1, 1]; + } + + // Смотрим по какой оси значение пересечения объектов больше и выбираем множитель по + const valueX = Math.min(firstObject.right, secondObject.right) - Math.max(firstObject.left, secondObject.left); + const valueY = Math.min(firstObject.bottom, secondObject.bottom) - Math.max(firstObject.top, secondObject.top); + + switch (true) { + // TODO: добавить эпсилон для сравнения + case valueX === valueY: + return [-1, -1]; + + case valueX > valueY: + return [1, -1]; + + case valueX < valueY: + return [-1, 1]; + + default: + return [1, 1]; + } + } catch (err) { + console.error(err); + return null; + } +} diff --git a/src/lib/calculateDirection/calculateDirection.test.js b/src/lib/calculateDirection/calculateDirection.test.js new file mode 100644 index 0000000..879c1f0 --- /dev/null +++ b/src/lib/calculateDirection/calculateDirection.test.js @@ -0,0 +1,111 @@ +import { calculateDirection } from './calculateDirection'; + +describe('calculateDirection', () => { + it('Корректно обрабатывает невозможные кейсы (левая координата больше правой)', () => { + const firstObject = { + left: 0, + right: 20, + top: 0, + bottom: 20, + }; + + const secondObject = { + left: 10, + right: 0, + top: 0, + bottom: 10, + }; + + expect(calculateDirection(firstObject, secondObject)).toBeNull(); + }); + + it('Корректно обрабатывает неверный формат данных', () => { + const firstObject = { + left: 'wrong', + right: 20, + top: 0, + bottom: 20, + }; + + const secondObject = { + left: 0, + right: 10, + top: 0, + bottom: 10, + }; + + expect(calculateDirection(firstObject, secondObject)).toBeNull(); + }); + + it('Возвращает корректные множители для кейса с отсутствием коллизии', () => { + const firstObject = { + left: 0, + right: 20, + top: 0, + bottom: 20, + }; + + const secondObject = { + left: 30, + right: 40, + top: 30, + bottom: 40, + }; + + expect(calculateDirection(firstObject, secondObject)).toEqual([1, 1]); + }); + + it('Возвращает корректные множители для коллизии по оси Y', () => { + const firstObject = { + left: 0, + right: 20, + top: 0, + bottom: 20, + }; + + const secondObject = { + left: 5, + right: 20, + top: 15, + bottom: 25, + }; + + expect(calculateDirection(firstObject, secondObject)).toEqual([1, -1]); + }); + + it('Возвращает корректные множители для коллизии по оси X', () => { + const firstObject = { + left: 0, + right: 20, + top: 0, + bottom: 20, + }; + + const secondObject = { + left: 15, + right: 20, + top: 5, + bottom: 25, + }; + + expect(calculateDirection(firstObject, secondObject)).toEqual([-1, 1]); + }); + + it('Возвращает корректные множители для коллизии по осям X и Y', () => { + const firstObject = { + left: 0, + right: 20, + top: 0, + bottom: 20, + }; + + const secondObject = { + left: 15, + right: 25, + top: 15, + bottom: 25, + }; + + expect(calculateDirection(firstObject, secondObject)).toEqual([-1, -1]); + }); +});