Задать вопрос
Ответы пользователя по тегу Геометрия
  • В каких практических задачах требуется алгоритм размещения прямоугольников в круге?

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

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

    Самая концептуально простая реализация будет, если сделать функцию для отсечения группы многоугольников полуплоскостью. Прямоугольник ваш - это 4 полуплоскости: 2 вертикальные и 2 горизонтальные. Пересечение с полуплоскостью проще - там тупо прямая же одна. Вот пресеките многоугольник с первой, полученные ответ со второй, потом что осталось с третьей и потом с четвертой полуплоскостью.

    Удобно хранить множество точек и для каждой - указатель на сделующую в обходе многоугольника (ориентированного так, что слева от отрезка внутренность многоугольника). В таком виде входные данные, в таком виде будет и ответ.

    Точки будем помечать, как обработанные.

    Обойдите все точки циклом, для всех необработанных еще, которые лежат внутри полуплоскости, начинайте с них строить ломанную-ответ. Идите к следующей точке, пока отрезок не пересечет полуплоскость (это значит конец строго внутри удаляемой области), помечая точки обработанными. До этого момента добавляйте точки в ответ сохраняя указатель на следующую точку. Для текущей следующей сделайте новую точку - точку пересечения. Еще запомните где-то эту точку пересечения, это потом понадобится. Продолжайте обход, пока отрезок не выйдет из полуплоскости (конец строго снаружи удаляемой области). Тут создайте точку пересечения, запишите ее в ответ, и для нее следующей сделайте конец отрезка снаружи. Продолжайте обход как в начале. Если встретили уже обработанную точку, вы закончили строить ломанную ответ.

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

    Вот у вас все оставшиеся точки образуют многоугольники, если идити по указателям на следующую. Правада, они в массиве могут идти вперемешку, а не подряд. В конце вам может понадобится их сгруппировать, но это делается похожим обходом: помечайте точки обработанными, берите любую не обработанную и идите от нее по указателям, пока не вернетесь в нее же, помечая все точки как обработанные и добавляя в ответкак часть одного многоугольника. Это можно сделать после того, как пересечете со всеми 4 полуплоскостями.

    Удобно прямую хранить в виде Ax+By+C=0. И знак подобрать так, что точки внутри хорошей области, если их подставить в это уравнение дают положительные значения (а точки снаружи - будут отрицательные). Соответственно, проверка, что с точки можно начать обход - просто посмотреть на знак. Проверка, что есть пересечение - конец отрезка дает отрицательный знак (а потом - положительный). Точки удобно хранить в виде массива координат и массива номеров следующей точки в обходе. Никаких сишных указателей - номера следующей точки в массиве. Сортировать точки пересечения надо будет по значению Ay-Bx.

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

    Это все удовольстивие будет работать за O(n log n) - потому что надо потом точки пересечения на прямой отсортировать.
    Ответ написан
  • Как найти угол для поворота башни на цель?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Угол 0 куда смотрит? Куда смотрит 90 градусов? Обычно считают, что 0 смотрит строго враво, а 90 - вверх.

    Шаг 1. Вам неважно, где именно находятся башня и цель, важно их относительное положение, поэтому посчитайте dx=x2-x1, dy = y2-y1

    Шаг 2. Подставьте в какую-нибудь обратную тригонометрическую функцию, например arctan(dy/dx). Тут правда незадача, если dx=0, то надо смотреть на знак dy и выдавать sign(dy)*90. Еще проблема, что arctan вам вернет значение от -90 до 90 всегда. Если dx отрицательно, то надо прибавить 180.
    Ответ написан
    2 комментария
  • Почему в геометрии выделяются только три признака равенства треугольников?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    по двум углам и прилежащей стороне,
    Тут имеется ввиду сторона не между двумя углами же?

    Вообще, если 2 угла равны, то равны все три, а значит это сводится к стандартному методу в пол действия. Поэтому его и не используют, зачем плодить сущности, если это на самом деле один и тот же метод (три угла и одна сторона).

    по двум сторонам и прилежащему углу.


    А вот это не правда, если угол не между двумя равными сторонами. Вот заданы нам 2 длины и угол. Построим такой треугольник: отрезок заданной длины, луч из одной вершины с заданным уголом, окружность заданной длины из второй вершины. Луч и окружность пересекаются в двух точках. Значит, есть 2 разных варианта для третьей вершины, удовлетворяющих условиям. Т.е. есть 2 разных треугольника у которых равны 2 стороны и угол (не между ними).
    Ответ написан
    1 комментарий
  • Как расположить плоскую текстуру сегмента на кольцо?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Не знаю, как UV-маппинг задается в этом вашем JS, но формулы для получения координат в прямоугольной текстуре по координатам на кольце такие:

    x_r = (sqrt(x^2+y^2)-r0)/(r1-r0)*Width
    y_r = (atan(y/x)/pi+1/2)*Height


    Тут (x,y) - координаты на кольце. Центр кольца в (0,0), внутренний радиус r0, внешний r1. Width, Height - размеры прямоугольной текстуры.
    Ответ написан
    1 комментарий
  • Как это решается?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Соотношение углов намекает, что стоит провести биссектрису угла ABC. Пусть она пересечет сторону AC в точке E. Можно заметить, что треугольник AEB будет равнобедренный и EM - его высота и медиана и параллельна СВ. Теперь проведите прямую через E, параллельную AB. У вас там сверху получится треугольник, подобный ABC, и отрезок CD будет его высотой. И там будет малая часть, равная искомому DM. Еще CBE будет подобен CAB. Вот составьте кучу соотношений для этих трех подобных треугольников.
    Ответ написан
    Комментировать
  • Как определить в какую сторону повернуты нормали в треугольнке, Внутрь или снаружу?

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

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    У вас там во входных данных 2 точки с одинаковым x (23) и разным y (18, 11). В результате получается деление на 0.

    Нельзя инетрполировать такие данные полиномом. Ибо это функция от x - для каждого x одно значение y.

    Ошибка не в программе, а в некорректных входных данных.

    Можно интерполировать параметрически, если хотите. Заведите параметр t и ищите две функции x(t), y(t) - скармливайте этой программе 2 набора данных 1,x1;2,x2;3,x3...n;xn и 1,y1;2,y2;...n,yn.

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

    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 у вас там лишний.

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