Ответы пользователя по тегу Геометрия
  • Как соединить рандомные точки на координатной плоскости в многоугольник?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Выпуклая оболочка, предложенная Vindicar, может соеденить не все точки. Какие-то будут просто внутри. Как в примере с картинки в вопросе, оболочка будет теругольником, а точка по центру будет не соединена ни с чем.

    Надо точки как-то отсортировать. Например, берете самую нижнюю, из всех таких самую левую. Сортируете все оставшиеся точки по углу, относительно этой (по значению atan2(yi-y0, xi-x0)), при равенсве угла по расстоянию (не важно по возрастанию или убыванию). Потом в таком порядке их соединяйте, пересечений не будет.

    В примере из вопроса оно как раз отсортирует их как на картинке.

    Edit, а еще, можно вместо atan сравнивать углы через векторное произведение. Если входные данные - целые точки, то вообще все вычисления будут в целых переменных.
    Ответ написан
    3 комментария
  • Как узнать, входит ли игрок1 (x,y,z) в поле игрок2 (x,y,z)?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Я правильно понял, что идет обмен между двумя игроками, если их окружности пересекаются?

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

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

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Не надо объект поворачивать. надо его рисовать сразу правильно ориентированным.

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

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

    Две оставшееся точки на окружности какого-то среднего радиуса под углами с небольшим отклонением от предыдущего угла в обе стороны.

    Эти углы надо будет рассчитать на бумажке. Нарисуйте 2 коружности заданого радиуса, постройте между ними ромб, проведите его диагонали, найдете там парочку прямоугольних треугольников. В программе можно будет просто эти длины засунуть в формулы и скормить какой-нибудь atan2() функции.
    Ответ написан
    1 комментарий
  • Как найти расстояние от точки до вектора?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Точно, расстояние до вектора надо? А не экстремальную точку вдоль вектора? В GJK алгоритме ищут точку, которая как уектор дает максимальное скалярное полизведение с заданым вектором - т.е. самую далекую вдрль вектора, дающую самую дальную проекцию.
    Ответ написан
  • Как сделать расчёт пройденного расстояния лучом?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Формула: W/sin(a). Ну, или косинус, в зависимости от того, что вы за угол задаете. W - ширина прямоугольника.

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

    Формула осмысленна: если нет отражений, она очевидна. Чем вертикальнее луч, тем больше ответ.

    Формула меняется для любой отправной точки: надо лишь опять нарисовать решетку из прямоугольников. Видимо, там будет не W, а оставшаяся ширина от начала до правой стенки.
    Ответ написан
    6 комментариев
  • Как найти точки пересечения двух многоугольников?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Я бы в таком случае добавлял обе вершины от второго многоугольника, которые лежат на первом. Так все новые ребра каждого многоугольника или целиком не пересекаются со вторым, или целиком лежат внутри него, или целиком на его границе.

    Т.е. действительно, в вашем случае надо в AIJH добавить точки ABKJH.

    Образуются ребра длины 0 - значит повторяющиеся вершины надо просто выкинуть.
    Ответ написан
    Комментировать
  • Алгоритм построения многоугольника из исходного квадрата и пересекающих его линий?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Для начала, надо бы уточнить условие. Ибо непясно, по какому принципу выбирается, какая из двух отсекаемых прямой половин берется в ответ.

    Картинке удовлетворяет такая интерпретация: Берется область, остекаемая прямыми, содержащая центр квадрата. Предполагаем, что прямые через центр не проходят.

    Тогда каждая прямая задает полуплоскость допустимых точек, да и сам квадрат можно задать 4-мя такими полуплосокстями и вам надо найти пересечение всех их.

    Эта задача решается за O(n log n). Задайте каждую прямую в виде ax+by+c=0. Т.ч. вектор {a,b} выпущенный с прямой, торчит в сторону полуплоскости, которую надо взять. Если вдруг не так, то надо поменять знак у всех трех коэффициентов.

    Разбейте все прямые на 2 множества, те - которые смотрят "вверх" и те, которые смотрят "вниз". Если вектор нормали имеет положительную y координату - это смотрит вверх. Вертикальные прямые можно включить, допустим, в верхнее множество.

    В каждом множестве построим ломанную, отделяющую нужную область. Это будет выпуклая область с двумя бесконечными лучами в конце.

    Потом отсортируйте все прямые по углу наклона вектора {a,b}. Это можно сделать без тригонометрии, сравнивая векторы по векторному произведению. Ну, или просто какую-нибудь функцию вроде atan2() используйте.

    Потом будем поддерживать ломанную, описывающую пересечение первых k проуплоскостей. Изначально это просто одна прямая (для первой полуплоскости). Будем хранить это как стек из прямых и рядом стек из точек пересечения. Изначально там только одна прямая и 0 точек пересечения.

    Потом добавляем полуплоскости по одной. Пока последняя вершина на ломанной не лежит в нужной полуплоскости, выбрасываем ее. Для этого убираем из обоих стеков последний элемент. Это можно проверить, просто подставив координаты точки в уравнение ax+by+c. Если даст отрицательное значение - выбрасываем.
    Если точек не осталось, или точка лежит где надо, то новую прямую надо пересечь с последней прямой. Точку пересечения и новую прямую добавляем в стек.

    В конце мы получили две ломанные, огибающие нужное пространство сверху и снизу. Надо их пересечь.
    Для этого выкинием сверхней ломанной все крайние точки, которые отсекаются последней и первой прямой в нижней ломанной. И наоборот. В конце, пересечения двух бесконечных лучей слева и справа добавляем в ответ.
    Ответ написан
    Комментировать
  • Нужно ли переводить из градусов в радианы для правильного направления стрелки?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Да, нужно перевести скорость в радианы. Так, чтобы 0 было pi/2 радиан (направление вверх), а -200 - это 4/3pi. И радианы при увеличении скорости уменьшаются.

    Поскольку все линейно, то фрмула такая: alpha = pi/2 - speed*5/1200.0

    Что такое angleValueTransformer я не знаю, но если ему задаются отрезки углов и значений, которые оно линейно преобразует в друг друга, то углы должны быть от 240 до -60, что соответствует скоростям от -200 до 200. Ну, или углы от 4/3pi до -pi/3, если вы значение сразу в синусы/косинусы передаете, не переводя из градусов в радианы.

    И, кстати, развертка будет не 310, а 300 градусов от -200 до 200. Иначе скорость 0 не будет вертикально вверх.
    Ответ написан
  • Почему ближайшие точки определяются неправильно?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Есть еще вот такое решение. Выводится так: задаем обе прямые параметрически (точка + t или u, помноженная на вектор вдоль прямой). Получаем выражение для квадрата расстояния между точками как функцию от t и u. Ищем ее минимум, приравняв к 0 частичные производные. Там получаются 2 линейных уравнения.

    Vector3 a = axis2.first - axis1.first;
    Vector3 v1 = axis1.second - axis1.first;
    Vector3 v2 = axis2.second - axis2.first;
    float v11 = Vector3::DotProduct(v1, v1);
    float v12 = Vector3::DotProduct(v1, v2);
    float v22 = Vector3::DotProduct(v2, v2);
    float av1 = Vector3::DotProduct(a, v1);
    float av2 = Vector3::DotProduct(a, v2);
    // Решаем систему методом Крамера:
    // t*v11-u*v12=av1
    // t*v12-u*v22=av2
    float d1 = -av1*v22+v12*av2;
    float d2 = v11*av2-v22*av1;
    float d = -v11*v22+v12*v12;
    float t = d1/d;
    float u = d2/d;
    point1 = axis1.first + v1 * t;
    point2 = axis2.first + v2 * u;
    Ответ написан
    Комментировать
  • Как найти точки для обьекта и нарисовать его?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Точно так же, как вы в проедыдущем вопросе находили координаты тик-марков, вы можете тут найти 2 координаты - пятая точка на острие стрелки и центр короткой стороны. Теперь, можно ввести систему координат из центра окружности так, чтобы ось ox шла вдоль стрелки. Для этого вам надо найти 2 перпендикулярных вектора. Один у вас уже есть - это вектор между двумя известными уже точками. Он же будет cos(alpha), sin(alpha). Перпендикулярный вектор будет -sin(alpha), cos(alpha). Теперь надо только взять координаты 5 точек в этой системе координат (как будто бы стрелка лежит горизонтально) и сложить x, помноженный на первый вектор с у помноженным на 2 вектор.

    В итоге будет что-то вроде:
    x' = x*cosa + y*sina
    y' = -x*sina + y*cosa


    Это же выражение является заодно матрцей поворота на угол alpha.

    А координаты там что-то вроде: {r0, w/2}, {r0, -w/2}, {r1, -w/2}, {r1 + w/2, 0}, {r1, w/2}, гже r0, r1 - радиусы окружностей между которыми стрелка натянута. w - ширина стрелки. Эти пары подставляйте ввиде x,y в формулу выше и получите x', y' - координаты точек на экране.
    Ответ написан
  • Как найти точки на дуге?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Точка на окружности радиуса r, с центром x0, y0, под углом alpha к горизонтальной оси имеет координаты:
    x = x0 + r*cos(alpha)
    y = y0 + r*sin(alpha)


    У вас есть 2 окружности - внешняя, и невидимая внутренняя. Тикмарки - это куски радиуса между ними. По формуле выше (с двумя разными радиусами) вы можете найти 2 точки конца каждого отрезка.
    Ответ написан
    22 комментария
  • Как проверить многоугольник на закольцованность?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Можно составить многугольник из отрезков, тогда и только тогда, когда максимальный короче суммы всех остальных. Ну или, максимальный меньше половины суммы всех. Множитель 2 у вас там лишний.

    Доказательство элементарно: В противном случае, очевидно, всех остальных сторон не хватит составить путь от двух точек длиннейшего отрезка.
    А дальше возьмем окружность у которой этот длиннейший отрезко будет хордой. Приложим все остальные отрезки как хорды подряд. Если их не хватает замкнуть многоугольник, то уменьшим радиус. Если они закрывают суммарно дугу окружности больше, чем между хордой на самом длинном отрезке, то увеличиваем радиус. По какой-нибудь теореме о нуле непрерывной функции где-то существует радиус, для которого все эти отрезки оформятся в выпуклый мноугольник, вписанные в окружность.
    Ответ написан
    Комментировать
  • Как сделать обработку столкновений между шарами?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Тут нужна школьная геометрия. Класс на 9, наврено даже раньше. Координаты центров шаров через время t будут (x1(t),y1(t))=(x1+vx1*t, y1+vy1*t)

    Во-первых, проверьте, что шары сейчас не пересекаются. Иначе выталкивайте их вдоль прямой через центры.
    Потом вам надо решить уравнение квадратное уравнение (x1(t)-x2(t))^2+(y1(t)-y2(t))^2 = 4*r^2.

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

    Если 2 шара столкнулись, то их скорости поменяются вдоль вектора на их ценры. Надо решить уравнения сохрнения импульса и энергии. Решение смотрите тут (Формулы в комментарии в моем ответе там).

    P.s. у вас там в коде вижу ошибку. Вы где считате пересечение со стенами знаки напутали. Должно быть:
    float t1 = (0.5 * Lxmax - (cords[i].x + r)) / cords[i].vx;
    float t2 = (-0.5 * Lxmax - (cords[i].x - r)) / cords[i].vx;


    Ну и вы там не проверяете, вдруг скорость нулевая, тогда время до пересечения - бесконечность.
    Ответ написан
    Комментировать
  • Как начертить правильный n-угольник с центром в точке (x, y) на поверхности шара?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Удобно ввести новую систему координат и потом откладывать ее базисные векторы нужное количество раз.
    Эта система будет иметь центр на радиусе сферы к центру оружности и лежать на "хорде" - плоскости в которой лежит многоугольник. В ней ваш многоугольник будет просто на плоскости.

    Из простейшей геметрии вы знаете, что этот центр координат будет на расстоянии sqrt(R^2-r^2) от центра сферы - так радиус окружности на сфере будет r.

    Первый базисный вектор будет вдоль радиуса из центра сферы к центру многоугольника и координата там будет всегда 0.
    Теперь вам надо найти еще какой-то вектор в плоскости многоугольника, а третий вектор потом найдете через векторное произведение. Хорошо бы этот второй вектор взять на север, тогда ясно куда класть первую точку по условию. Если только центр окружности не лежит строго на свере, то можно взять и спроецировать на плоскость вертикальный вектор (0, 0, 1) и все (а в противном случае проецируйте, допустим (1, 0, 0). А дальше останется только взять формулы для многоугольника на плоскости x = cos(2*pi/n*k)*r y = sin(2*pi/n*k)*r, ну и не забыть перевести все в обычную систему координат.

    Итак, пусть xo,yo,zo - точка на сфере, где лежит центр. xo и yo не нули одновременно. Еще даны R, r и n.

    Центр новых координат:
    L = sqrt(R^2 - r^2)
    x1 = xo/R*L
    y1 = yo/R*L
    z1 = zo/R*L

    Первый базисный вектор:
    e1 = (x0, y0, z0) / R
    Второй базисный вектор (нормализованный (0,0,1) - (0,0,1)*e1):
    e2 = (-x0*z0/R/sqrt(R^2- z0^2), -y0*z0/R/sqrt(R^2- z0^2), sqrt(R^2-z0^2)/R)

    третий базисный ветор, найдите сами через векторное произведение.

    А дальше координаты k-ой точки:
    p = (x1,y1,z1) +e2*cos(2*pi/n*k)*r+e3*sin(2*pi/n*k)
    Ответ написан
    Комментировать
  • Как позиция объекта соответствует четырёхмерной матрице?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Матрицы используются для записи преобразований. Надо домножать на них вектор из координат точки - получится новый вектор, который и будет результатом преобразования. Любое линейное преобразование можно записать в виде матрицы.

    Четвертая координата позволяет записывать одной матрицей повороты/растяжения и сдвиги. Если у вас матрица 3x3 (не "трехмерная" - у нее все так же есть только ширина и высота), то точка (0, 0, 0) всегда останется (0, 0, 0). Ведь на что 0 не домножай - останется 0. Поэтому матрицами 3x3 можно записать только повороты и сжатия, но не сдвиги.

    Поэтому вводят фиктивное четвертое измерение w. При этом удобно считать, что координаты точки (x, y, z, w) - Это (x/w, y/w, z/w). Это еще иногда называют однородными координатами. Еще один плюс этого объекта в том, что им можно описать точки на бесконечности (когда w = 0).

    Вот тут уже можно составить линейное преобразование (т.е. взять матрицу), которое оставляет w нетронутым, но использует его для сдвига:
    x' = a11*x + a12*y + a13*z + a14*w
    ...
    w' = w

    Вот в a14 - как раз и находится сдвиг по оси X.
    Ответ написан
    3 комментария
  • Задача на геометрию. Как быстро найти подходящую выборку элементов из матрицы?

    wataru
    @wataru Куратор тега Алгоритмы
    Разработчик на С++, экс-олимпиадник.
    Чтобы расставить жуков оптимально, надо бинпоиском перебрать максимально разрешенное растояние и дальше проверить, что в графе из расстояний, не больше заданного, есть полное паросочетание.

    Еще, угол поворота надо искать троичным поиском, ибо функция не монотонна, а пооизводную фиг найдете. В итоге у вас будет троичный поиск, запускающий двоичный поиск, щапускающий поиск паросочетания.
    Ответ написан
  • Если мы возьмём кубическую кривую Безье и вытянем усы в одну точку, будет ли это квадратичная кривая?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Нет. Потому что кривая называется "кубической" не потому, что там 4 разные точки, а потому что она задается уравнением третьей степени (кубы): a(1-t)^3+bt(1-t)^2+ct^2(1-t)+dt^3. Если вы приравняете b и c, то уравнение так и останется кубическим и в квадртаичное не превратится.
    Ответ написан
  • Что значит описать встретившуюся геометрическую фигуру и определить положение точки в этой фигуре?

    wataru
    @wataru Куратор тега Математика
    Разработчик на С++, экс-олимпиадник.
    Кажется, надо составить уравнение/функцию, которая говорит, что точка попала в данную фигуру. Фигуры, скорее всего, задаются цветом.
    Ответ написан
    Комментировать
  • Что такое х0, что такое у0, что такое х?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    x, y - переменные. Они изображаются на графике. x0, y0, a - какие-то фиксированные параметры прямой, числа. Точка, через которую она проходит и наклон.

    Синяя линяя, наверно, прямая, описываемая этим уравнением.
    Ответ написан
    Комментировать
  • Как получить точку касания вектора, зная его начало и модуль?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Одно квадратное уравнение. Пусть точка конца имеет координаты t*v3. Уранение: |t*v3-v1|^2=100^2 (расстояние от начала до конца - 100). Распишите длину как сумму квадратов разностей по всем координатам. Там квадратное уравнение на t, ведь координаты v1 и v3 даны. Найдите положительный корень.
    Ответ написан