From fce9c0ffa34ed2c5f903dc2f028f9e39fc14dc99 Mon Sep 17 00:00:00 2001 From: Ilia Mashkov Date: Thu, 16 Jul 2026 14:01:26 +0300 Subject: [PATCH] =?UTF-8?q?feat(calculateDirection):=20=D0=94=D0=BE=D0=B1?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA?= =?UTF-8?q?=D1=86=D0=B8=D1=8F=20=D0=B4=D0=BB=D1=8F=20=D0=B2=D1=8B=D1=87?= =?UTF-8?q?=D0=B8=D1=81=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BC=D0=BD=D0=BE?= =?UTF-8?q?=D0=B6=D0=B8=D1=82=D0=B5=D0=BB=D0=B5=D0=B9=20=D0=B8=D0=B7=D0=BC?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BD=D0=B0=D0=BF=D1=80?= =?UTF-8?q?=D0=B0=D0=B2=D0=BB=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=B2=D0=B8?= =?UTF-8?q?=D0=B6=D0=B5=D0=BD=D0=B8=D1=8F=20=D0=BE=D0=B1=D1=8A=D0=B5=D0=BA?= =?UTF-8?q?=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../calculateDirection/calculateDirection.js | 52 ++++++++ .../calculateDirection.test.js | 111 ++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 src/lib/calculateDirection/calculateDirection.js create mode 100644 src/lib/calculateDirection/calculateDirection.test.js 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]); + }); +});