Вывести градус угла отражённого луча (2D)

Здравствуйте.
Вот например, есть луч и есть отрезок. Тырим в интернете формулы, находим градус отражённого луча и говорим, что это мы сами сделали.

Но вот проблема. На всех четырёх скриншотах луч отражается туда же, откуда был послан. Значит, угол должен быть 90 градусов (или PI / 2 радиан). На первых трёх скриншотах так и есть. А на последнем выдаёт 270 градусов.

Line MakeLine(double x1, double y1, double x2, double y2)
{
    Line resLine;
    resLine.pt1 = Vec2{ x1, y1 };
    resLine.pt2 = Vec2{ x2, y2 };
    Vec2 direction = VectorNormalize(VectorDirection(resLine.pt1, resLine.pt2));
    resLine.angle = VectorsAngle(resLine.pt1, resLine.pt1 + direction);
    resLine.normal = VectorNormal(direction);
    return resLine;
}

        case WM_MOUSEMOVE:
        {
            int x = LOWORD(lParam);
            int y = HIWORD(lParam);

            if (canDrag)
            {
                Vec2 tmpPos = Vec2{ (double)x, (double)y };
                if (!PointInCircle(ray.origin, tmpPos, circle.radius))
                    circle.position = tmpPos;
            }
            else
            {
                ray.direction = VectorNormalize(Vec2{ (double)x, (double)y } - ray.origin);
                ray.angle = VectorsAngle(ray.origin, ray.origin + ray.direction);
            }

            InvalidateRect(hMainWindow, nullptr, false);

            break;
        }
Vec2 GetReflectedDirection(Ray ray, Line line)
{
    return ray.direction - (line.normal * VectorsProductDot(line.normal, ray.direction) * 2.0);
}

Ray GetReflectedRay(Ray ray, Line line, Vec2 intersectionPoint)
{
    Ray resRay;
    resRay.origin = intersectionPoint;
    resRay.direction = VectorNormalize(GetReflectedDirection(ray, line));
    resRay.angle = VectorsAngle(resRay.origin, resRay.origin + resRay.direction);
    return resRay;
}

Vec2 GetReflectedDirection(Ray ray, Circle circle, Vec2 intersectionPoint)
{
    Vec2 normal = VectorNormalize(intersectionPoint - circle.position);
    return ray.direction - (normal * VectorsProductDot(normal, ray.direction) * 2.0);
}

Ray GetReflectedRay(Ray ray, Circle circle, Vec2 intersectionPoint)
{
    Ray resRay;
    resRay.origin = intersectionPoint;
    resRay.direction = VectorNormalize(GetReflectedDirection(ray, circle, intersectionPoint));;
    resRay.angle = VectorsAngle(resRay.origin, resRay.origin + resRay.direction);
    return resRay;
}
        std::vector<Vec2> points = GetIntersectionPoints(ray, circle);
        if (points.size() > 0)
        {
            double len = VectorsDistance(ray.origin, points[0]);
            DrawRay(dcMem, ray, len);
            SelectObject(dcMem, (HBRUSH)GetStockObject(WHITE_BRUSH));
            DrawCircle(dcMem, (int)points[0].x, (int)points[0].y, 5);

            Ray reflectedRay = GetReflectedRay(ray, circle, points[0]);
            DrawRay(dcMem, reflectedRay, 3000.0);

            Vec2 normal = VectorNormalize(points[0] - circle.position);
            Vec2 normal90 = VectorNormal(normal);
            Vec2 pt1 = points[0] + normal90 * 100;
            Vec2 pt2 = points[0] - normal90 * 100;
            Line line = MakeLine(pt1.x, pt1.y, pt2.x, pt2.y);
            DrawLine(dcMem, line);

            std::cout << "Line angle: " << RadToDeg(line.angle) << std::endl;
            std::cout << "Ray angle: " << RadToDeg(reflectedRay.angle) << std::endl;

            reflectedRay = GetReflectedRay(ray, line, points[0]);
            double intersectionAngle = fabs(line.angle - reflectedRay.angle);
            std::cout << "Intersected in [" << points[0].x << " " << points[0].y << "] " <<
                RadToDeg(intersectionAngle) << " degrees" << std::endl;
        }
        else
        {
            DrawRay(dcMem, ray, 3000.0);
        }

Как поправить код, чтобы со всех сторон под прямым углом выдавало 90?
Знаю один ламерский способ. Проверять, чтобы всегда было line.pt1 < line.pt2. Но, по-моему, это не правильно с математической точки зрения.

Смотреть как задана исходная точка луча. Не всегда будет прямой угол если исходная задается произвольно (если задана не верно и угол не прямой).

не понял, почему?

А как ее можно задать? И какая разница, как она задана? :thinking: Это же просто координаты в пространстве.

не верно это как?

не прямой относительно чего?

Перефразирую.
Возможно размер полигона задан таким образом что луч не из любой произвольной точки может попасть в центр сферы по Вашим расчетным формулам.

Чёт я совсем ничё не понял :man_shrugging:

Я тоже перефразирую.
Вот есть у нас прямая. Проводим к ней перпендикуляр с одной стороны - его угол 90 градусов. Проводим перпендикуляр с противоположной стороны - получаем уже 270.
Как из 270 сделать 90?

Вы отрезок относительно чего рисуете? Так понимаю относительно полигона. Вот размер полигона может не позволять идеально произвести расчет угла между лучом и отрезком.

В данном случае - относительно нормали окружности. Хотя, я не понимаю, какое это сейчас имеет значение.
Предположим, что отрезок произвольный и его координаты [0, 0] - [500, 500]. При этом, угол его наклона будет 45 градусов. Почти как на последнем скриншоте.
Забудьте пока про окружность. Есть только луч и отрезок.

если отрезок уже получен, то какая разница, был полигон или не было? Остался только отрезок и луч.

Так тогда тем более имеют значение координаты начала луча, если целитесь в середину отрезка а не в центр окружности.

Все координаты известны. Направление и угол луча тоже известны. Что дальше?

Я целюсь не в центр отрезка. На скришоте отрезок рисуется в противоположные стороны от точки пересечения. По-этому, так кажется.
Я целюсь в отрезок так,чтобы луч был перпендикулярен отрезку . Угол перпендикуляра к любой ровной поверхности равен 90 градусов. Однако, с одной стороны выдаёт 90, а с другой 270. Как сделать, чтобы всегда 90 выдавало?
Предполагаю, что надо что-то от чего-то отнять. Но я уже всё перепробовал.

Почему 270 не знаю. Ну если отражение, то проверяй - угол больше 180 то вычти его из 360

1 лайк

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

Ну вот что вы привязались к этой окружности? Дело-то не в ней. Она здесь только для того, чтобы отрезок автоматически поворачивался в зависимости от угла падения луча.

Все углы отражения уже просчитаны, используя формулы из интернета, если вы не заметили.

@BlackRain666
90° - это угол с осью X одной стороны, 270° - с противоположной.

вот картинка

нарисовать Вам, где тут 90° и где 270° или уже и так понятно?

Да, всё верно. Я уже писал об этом в первом посте.

где?

Зачем рисовать? У меня это в консоль выводится.

Тогда приношу свои извинения, я, видимо, не понял, что именно Вам нужно.

Скорее всего , вы не поняли.

Действительно, работает. Всё просто было.
А нельзя сделать это, не расчитывая перпендикуляр к нормали окружности и угол отражения? То есть, если известны только угол падения, точка пересечения и нормаль окружности.