Найти угол между векторами в диапазоне от 0 до 360 градусов

Добре. Недавно начал перенос проекта на новый движок и столкнулся с рофлами, я не могу найти полное значение круга в градусах, т.к. скрип по какой-то причине вычисляет только внутренний угол, не затрагивая внешний. Вопрос - каким образом нужно написать скрипт, чтобы получить углы как на изображении ниже(отсчёт ведётся от синей линии, а все вектора направлены от центральной точки)

P.S. сейчас выводит 45, 0, 90. Должно выводить 45, 180, 270

введите сюда описание изображения

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="https://cdn.babylonjs.com/babylon.js"></script>
    <script>
        var mesharr = new BABYLON.Vector3(-6, 0, 6)

        var baseV1 = new BABYLON.Vector3(0, 0, 5);
        var baseV2 = new BABYLON.Vector3(-2, 0, 5);
        var direction

        var BaseVector = baseV1.subtract(baseV2);

        var pointA1 = new BABYLON.Vector3(0, 0, 0);
        var pointC1 = new BABYLON.Vector3(-2, 0, 2);

        var vectorAA = pointA1.subtract(pointC1);
        var angle_1 = angleBetweenVectorsInDegrees(BaseVector, vectorAA);
        console.log(angle_1);//ожидается 45, на вывод 45
        direction = vectorAA.dot(mesharr)
        // Проверка направления вектора
        if (direction > 0) {
                console.log('к точке')
            } else {
                console.log('от точки')
        }

        var pointE1 = new BABYLON.Vector3(-14, 0, 5);
        var pointF1 = new BABYLON.Vector3(-10, 0, 5);

        var vectorEE = pointF1.subtract(pointE1);
        var angle_2 = angleBetweenVectorsInDegrees(BaseVector, vectorEE);
        console.log(angle_2);//ожидается 180, на вывод 0
        direction = vectorEE.dot(mesharr)
        // Проверка направления вектора
        if (direction > 0) {
                console.log('к точке')
            } else {
                console.log('от точки')
        }

        var pointG1 = new BABYLON.Vector3(-7, 0, 13);
        var pointI1 = new BABYLON.Vector3(-7, 0, 15);

        var vectorGG = pointG1.subtract(pointI1);
        var angle_3 = angleBetweenVectorsInDegrees(BaseVector, vectorGG);
        console.log(angle_3);//ожидается 270, на вывод 90
        direction = vectorGG.dot(mesharr)
        // Проверка направления вектора
        if (direction > 0) {
                console.log('к точке')
            } else {
                console.log('от точки')
        }

        function angleBetweenVectorsInDegrees(v1, v2) {
            // Находим скалярное произведение векторов
            const dotProduct = v1.x * v2.x + v1.z * v2.z;
        
            // Находим длины векторов
            const v1Length = Math.sqrt(v1.x * v1.x + v1.z * v1.z);
            const v2Length = Math.sqrt(v2.x * v2.x + v2.z * v2.z);
        
            // Вычисляем угол между векторами
            let angle = Math.acos(dotProduct / (v1Length * v2Length));
        
            // Преобразуем радианы в градусы
            let degrees = angle * (180 / Math.PI);
        
            return degrees;
        }
    </script>
</body>
</html>


Ответы (2 шт):

Автор решения: eccs0103

Уточнение

Если я вас правильно понимаю - v1 это начальная координата вектора, v2 это конечная координата. В таком случае вот что мы сделаем.

Решение

// Считаем базовые координаты вашего вектора
const difference = { x: v2.x - v1.x, y: v2.y - v1.y };
// Считаем угол тангенса с осью Y, но -y ставим так как отсчет начинается с минусовой части оси Y
let angle = Math.atan2(difference.x, -difference.y); 
// Прибавляем к результату Пи, так как полученный угол у нас будет в диапазоне [-π; π]
angle += Math.PI;

Результат

→ Ссылка
Автор решения: Stanislav Volodarskiy

angleCcw считает угол на который нужно повернуть первый вектор вокруг глобального нуля чтобы он совпал со вторым. Угол измеряется в радианах против часовой стрелки. Диапазон (-π, π].

angleBetweenVectorsInDegrees меняет местами вектора, чтобы считать угол по часовой стрелке, исправляет диапазон на [0, 2π), переводит радианы в градусы.

const angleCcw = (v1, v2) => Math.atan2(
    v1.x * v2.z - v1.z * v2.x,
    v1.x * v2.x + v1.z * v2.z
);

function angleBetweenVectorsInDegrees(v1, v2) {
    let angle = angleCcw(v2, v1); // обратный порядок

    // приведение в диапазон [0, 2PI)
    if (angle < 0) {
        angle += 2 * Math.PI;
    }
    // Преобразуем радианы в градусы
    return angle * 180 / Math.PI;
}

console.log(angleBetweenVectorsInDegrees({x: 0, z: -1}, {x:  0, z: -1}));
console.log(angleBetweenVectorsInDegrees({x: 0, z: -1}, {x: -1, z: -1}));
console.log(angleBetweenVectorsInDegrees({x: 0, z: -1}, {x: -1, z:  0}));
console.log(angleBetweenVectorsInDegrees({x: 0, z: -1}, {x: -1, z:  1}));
console.log(angleBetweenVectorsInDegrees({x: 0, z: -1}, {x:  0, z:  1}));
console.log(angleBetweenVectorsInDegrees({x: 0, z: -1}, {x:  1, z:  1}));
console.log(angleBetweenVectorsInDegrees({x: 0, z: -1}, {x:  1, z:  0}));
console.log(angleBetweenVectorsInDegrees({x: 0, z: -1}, {x:  1, z: -1}));

→ Ссылка