|
Геометрическая задачка - определить принадлежность точки к треугольнику в гексагоне, Подскажите алгоритм, а то запутался |
|
|
|
Feb 5 2010, 10:58
|
Профессионал
    
Группа: Свой
Сообщений: 1 817
Регистрация: 14-02-07
Из: наших, которые работают за бугром
Пользователь №: 25 368

|
Народ подскажите пожалуйста, может кто с геометрией на "ты", как проще решить следующую задачу. Есть правильный шестиугольник разбитый на равносторонние треугольники как на рисунке.
Координаты некоторых точек я указал. Все пляшет от величины а - расстояния от центра до удаленной вершины. И есть точка с координатами x,y которая находится где-то в гексагоне. Задача - определить, в каком треугольнике 1-24 она находится. Возможно Вы скажете "просто", но есть ограничения - задача будет решаться на микроконтроллере, поэтому просто "взять тангенс от x/y" и т.д. не получится. Умножать на любое число и делить на константу можно, но корень, тригонометр функции и деление на число - нельзя. Число а - сравнительно медленно измеряемая величина, поэтому от нее корень и деление можно использовать. Пока есть и работает алгоритм определения треугольников 1-18, но с добавлением внутренних треугольников - проблема. Вот как я делаю: Код %% Quarter calculation and rotation if X<0 X=-X; Xinv=1; else Xinv=0; end if Y<0 Y=-Y; Yinv=1; else Yinv=0; end
%% Triangle calculation
Xshift=X-a/4;
if (Y<(a*sqrt(3)/4)) %If Y less than half height then point is in triangle 1 or 2 Yshift=Y+a*sqrt(3)/4; if (Yshift>sqrt(3)*Xshift) triangle=2; else triangle=1; end else %otherwise it is in triangles 3, 4 or 5 Yshift=Y-a*sqrt(3)/4; if (Xshift==0) triangle=4; else if (Xshift<0) if Yshift>(-sqrt(3))*Xshift triangle=4; else triangle=5; end else if (Yshift>sqrt(3)*Xshift) triangle=4; else triangle=3; end end end end Таким образом я разбираюсь только с одной четвертью, а остальные треугольники получаю, просто поворачивая координаты точки.
|
|
|
|
|
Feb 5 2010, 16:28
|

.
     
Группа: Участник
Сообщений: 2 424
Регистрация: 25-12-08
Пользователь №: 42 757

|
Умножаем все по оси Х на sqrt(3). В том числе координату "x" искомой точки. Получаем систему координат где треугольники превратились в прямоугольные. Приводим все в 1-й квадрант . Нормализуем размеры фигуры к разрядности вычислений и координаты точки тоже . Старшие 2 разряда по Х и 1 разряд по Y определяют большой квадрат (например зеленый). следующие 2 бита после них по одному разряду от Х и Y определяют квадрант внутри зеленого квадрата. При 00 или 11 ответ сразу виден. Иначе повторяем еще по одному разряду, пока те не кончатся  .
Сообщение отредактировал тау - Feb 5 2010, 16:44
Эскизы прикрепленных изображений
|
|
|
|
|
Feb 5 2010, 16:51
|
Профессионал
    
Группа: Свой
Сообщений: 1 817
Регистрация: 14-02-07
Из: наших, которые работают за бугром
Пользователь №: 25 368

|
Цитата Умножаем все по оси Х на sqrt(3). В том числе координату "x" искомой точки. Получаем систему координат где треугольники превратились в прямоугольные. Нормализуем размеры фигуры к разрядности вычислений одновременно с координатой Х. Этот прикол мне нравится - что-то интересненькое уже вырисовывается. Но Цитата Иначе повторяем еще по одному разряду, пока те не кончатся Не подойдет - итерации мне не подходят. Надо чтобы раз и все. Вот в IEEE нашел статейку, где все предлагают перевести в X'=3*X/2, a Y'=sqrt(3)*Y. Помоему идея та же, но не пойму, что получится.
|
|
|
|
Guest_@Ark_*
|
Feb 5 2010, 22:55
|
Guests

|
Я бы так решил эту задачу: Провел бы через все вершины треугольников горизонтальные и вертикальные линии (горизонтальные уже проведены). В итоге - получится 28 прямоугольников. Принадлежность точки к конкретному прямоугольнику определяется по ее координатам X и Y. Такой прямоугольник всегда делится диагональю на две области, принадлежащие двум треугольникам. Остается определить по специально составленной таблице тип прямоугольника - из частей каких треугольников он состоит, как идет его диагональ и установить расположение точки относительно ее... P.S. Может, не совсем понятно объяснил, но программно все это можно выполнить с помощью только табличных функций, сложений и сравнений, не пребегая даже к умножению...
|
|
|
|
|
Feb 6 2010, 00:52
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Имеем три системы прямых - горизонтальные, наклонные "левые" и "правые". Если в каноническое уравнение прямой A*x + B*y + C = 0 подставить координаты конкретной точки (x,y), то по результату A*x + B*y + C можно выяснить, лежит точка на прямой (0), под ней (>0) или над ней (<0).
Для каждой системы прямых можно идти сверху от прямой к прямой и искать смену знака - т.е. искать прямую, "как раз над которой" находится точка. По трём номерам прямых однозначно определяетя где находится точка (ну тм с нулями, конгда точка на прямой - нужно просто решить заранее, как это интерпретировать, вылбется в > или >= при сравнениях с 0). Например, если взять только "косые" прямые, то определяется "вертикальный" ромб, в котором лежит точка, по горизонтальной прямой выясняется в каком из двух треугольников точка.
Ну для горизонтальных прямых достаточно поделить y точки на шаг между прямыми.
Ха - как вариант - int(y/шаг) - это номер прямой для горизонтальных линий. Теперь поворачиваем точку на 60 градусов влево и вправо и для y-ка новой точки так же делением на шаг выясняем номер. Дальше при помощи этих трёх номеров из фикисрованного 3-мерного массива вынимаем номер треугольника.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Feb 6 2010, 07:41
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 29-07-08
Пользователь №: 39 270

|
Подобную задачу принадлежности точки треугольника решал следующим образом. любую точку в плоскости треугольника можно выразить симплексные координаты (a,b,c), как это сделать можно найти почни в люьой книге по МКЭ. Если точка принадлежит треугольнику, то |a|+|b|+|c|=1.
|
|
|
|
|
Feb 6 2010, 12:04
|
Участник

Группа: Участник
Сообщений: 17
Регистрация: 29-08-08
Из: СПб
Пользователь №: 39 876

|
Цитата(ALEKSIU @ Feb 6 2010, 10:41)  Подобную задачу принадлежности точки треугольника решал следующим образом. любую точку в плоскости треугольника можно выразить симплексные координаты (a,b,c), как это сделать можно найти почни в люьой книге по МКЭ. Если точка принадлежит треугольнику, то |a|+|b|+|c|=1. Любопытно. Так, видимо, проще всего. Вариант реализации: если (Xa,Ya) (Xb,Yb) (Xc, Yc) --- координаты точек A, B, C, (X,Y) координаты точки, то a=( (Yb-Yc)*(X-Xc)+(Xc-Xb)*( Y-Yc) )/ ( (Yb-Yc)*(Xa-Xc)+(Xc-Xb)*( Ya-Yc) ) b =( (Yc-Ya)*(X-Xc)+(Xa-Xb)*( Y-Yc) )/ ( (Yb-Yc)*(Xa-Xc)+(Xc-Xb)*( Ya-Yc) ) c = 1 - a - b условие принадлежности треугольнику a >= 0, b >= 0, c>= 0 (ноль, если оказались на границе). для ускорения работы программы, можно задать 6 массивов: Xa[24], Ya[24], Xb[24], ... --- координаты вершин треугольника (это, конечно занудно), и массив C[24][4] в котором для каждого из треугольников задать константы: Код for(i=0; i < 24; i++) { C[i][0]= (Yb[i]-Yc[i])/( (Yb[i]-Yc[i])*(Xa[i]-Xc[i])+(Xc[i]-Xb[i])*( Ya[i]-Yc[i]) ); C[i][1]= (Xc[i]-Xb[i])/( (Yb[i]-Yc[i])*(Xa[i]-Xc[i])+(Xc[i]-Xb[i])*( Ya[i]-Yc[i]) ); C[i][2]= (Yc[i]-Ya[i])/( (Yb[i]-Yc[i])*(Xa[i]-Xc[i])+(Xc[i]-Xb[i])*( Ya[i]-Yc[i]) ); C[i][3]= (Xa[i]-Xb[i])/( (Yb[i]-Yc[i])*(Xa[i]-Xc[i])+(Xc[i]-Xb[i])*( Ya[i]-Yc[i]) ); } И в цикле проверить Код i=0; do { a = C[i][0]*(X-Xc[i])+C[i][1]*(Y-Yc[i]); b = C[i][2]*(X-Xc[i])+C[i][3]*(Y-Yc[i]); c = 1 - a - b; i++; }while ( !( (a >= 0) && (b >=0) && (c>=0) ) ) return i; PS Исходные коды на С PPS В арифметике мог лажануться))) (хотя, вряд ли)
|
|
|
|
|
Feb 6 2010, 12:35
|
Участник

Группа: Участник
Сообщений: 22
Регистрация: 29-07-08
Пользователь №: 39 270

|
Цитата(Миша Т @ Feb 6 2010, 16:04)  для ускорения работы программы, можно задать 6 массивов: Xa[24], Ya[24], Xb[24], ... --- координаты вершин треугольника (это, конечно занудно), и массив C[24][4] в котором для каждого из треугольников задать константы: Именно так когда-то и делал
|
|
|
|
|
Feb 6 2010, 21:26
|

.
     
Группа: Участник
Сообщений: 2 424
Регистрация: 25-12-08
Пользователь №: 42 757

|
Вот еще проще способ. координаты X точки модифицируете X'=X+Y/sqrt(3) Y'=Y*2/sqrt(3) или , что то-же самое , если есть куда расти: X''=X*sqrt(3) +Y Y'"=Y*2 Образуется наклоненная фигура в прямоугольной системе отсчета, как на рисунке. Переносите начало системы координат в левый нижний угол фигуры , добавлением (а) к X'' и Y'' Теперь пронормализовать X'' и Y'' к размеру всей фигуры (2*а) относительно новой системы координат и старшие разряды (по два разряда от X'' и Y'' ) будут определять номер квадратика во всей фигуре ( а не только в четверти) Останется определить к какому треугольнику внутри квадратика относится точка. Для этого накладываете нулевую маску на 2 старших разряда X'' и Y'' (которые определяли номер квадратика). Оставшиеся величины при сравнении покажут к верхнему (X'' < Y'') или нижнему (X''>Y'') треугольнику относится точка. Впрочем, этом метод и был предложен scifi
Сообщение отредактировал тау - Feb 6 2010, 21:32
Эскизы прикрепленных изображений
|
|
|
|
|
Feb 8 2010, 06:30
|
Гуру
     
Группа: Свой
Сообщений: 3 106
Регистрация: 18-04-05
Пользователь №: 4 261

|
Цитата(syoma @ Feb 5 2010, 19:51)  Не подойдет - итерации мне не подходят. Надо чтобы раз и все. Если нужно, чтобы "раз и все", можно воспользоваться трехмерным массивом: Код TRIANGLES[2][4][4] = { { { 9,12,13, 0}, { 8,21,14,15}, { 0,20,19,16}, { 0, 0, 2, 1} }, { {10,11, 0, 0}, { 7,22,23, 0}, { 6, 5,24,17}, { 0, 4, 3,18} } }; Пусть: P - точка на плоскости в координатах X,Y. A - вектор направленный вдоль оси Y и имеющий длину равную 1/H. B - вектор направленный под углом плюс 30° к оси X и имеющий длину равную 1/H. C - вектор направленный под углом минус 30° к оси X и имеющий длину равную 1/H. где, H - высота треугольника равная H = a*cos(30°)/2. Вычисляем целое значение для трех скалярных произведений: COMPA = (int)<P,A> = (int)(X*0+Y*(1/H)) = (int)(Y*(2/a)/cos(30°)). COMPB = (int)<P,B> = (int)(X*cos(30°)*(1/H)+Y*sin(30°)*(1/H)) = (int)(X*(2/a)+Y*(2/a)*tg(30°)). COMPC = (int)<P,C> = (int)(X*cos(30°)*(1/H)-Y*sin(30°)*(1/H)) = (int)(X*(2/a)-Y*(2/a)*tg(30°)). Вычисляем значение индексов массива: INDEXA = COMPA & 1; INDEXB = COMPB + 2; INDEXC = COMPC + 2; Тогда номер треугольника: N = TRIANGLES[INDEXA][INDEXB][INDEXC]. На Си это можно записать так: Код #define a 1.0
TRIANGLES[2][4][4] = { { { 9,12,13, 0}, { 8,21,14,15}, { 0,20,19,16}, { 0, 0, 2, 1} }, { {10,11, 0, 0}, { 7,22,23, 0}, { 6, 5,24,17}, { 0, 4, 3,18} } };
int num(double X,double Y) { int COMPA = (int)(Y*(2/a)/cos(30°)); int COMPB = (int)(X*(2/a)+Y*(2/a)*tg(30°)); int COMPC = (int)(X*(2/a)-Y*(2/a)*tg(30°));
int INDEXA = COMPA & 1; int INDEXB = COMPB + 2; int INDEXC = COMPC + 2;
return TRIANGLES[INDEXA][INDEXB][INDEXC]; }
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|