Поиск:

Ответ в темуСоздание новой темы Создание опроса
> процедура поиска внутренних углов многоугольника, углы многоугольника 
:(
    Опции темы
CompWorm
  Дата 6.1.2009, 14:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



есть многоугольник (к новому году, рассмотрим ёлку  smile  ) ...

user posted image

многоугольник представлен двумерным массивом [ 7, 3 ] - 7 точек по 2 координаты (х,y) и угол альфа при этой вершине.

этот самый внутренний угол альфа и надо найти для каждой вершины ёлки.


--------------------
PM MAIL   Вверх
CompWorm
Дата 6.1.2009, 15:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



ну хорошо, дам свои соображения))

для i-ой вершины имеем: 
1) найти угол альфа при i-ой вершине в треугольнике (i-1 , i ,  i+1)  (ясно, что в треугольнике он обязан быть меньше 180 градусов => проверка если нет, то альфа = альфа - 180)  
2) найти точку M [x,y] середины отрезка между соседними (i-1 и  i+1) вершинами.
3) выяснить, внутри или снаружи многоугольника находится М.
4) если снаружи, то альфа=360 - альфа 


способ тупой, ибо упирается в не менее сложную проблему определения положения М относительно многоугольника.

+ эта проблема усложниться, если в ёлке будет дырка  smile 


--------------------
PM MAIL   Вверх
Dobermann
Дата 6.1.2009, 15:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 992
Регистрация: 7.1.2008

Репутация: нет
Всего: 0



А противоположно лежащие прямые параллельны? (1,2 // 6,7) (1,6 // 2,3) ну и т.д.
PM   Вверх
CompWorm
Дата 6.1.2009, 16:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



Цитата(Dobermann @  6.1.2009,  15:38 Найти цитируемый пост)
А противоположно лежащие прямые параллельны? (1,2 // 6,7) (1,6 // 2,3) ну и т.д. 


случай берем общий. в ёлке могут быть и дырки!



Это сообщение отредактировал(а) CompWorm - 6.1.2009, 16:19


--------------------
PM MAIL   Вверх
Dobermann
Дата 6.1.2009, 16:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 992
Регистрация: 7.1.2008

Репутация: нет
Всего: 0



Цитата(CompWorm @  6.1.2009,  16:19 Найти цитируемый пост)
случай берем общий. в ёлке могут быть и дырки!

Может сперва разобраться с параллельными!! 
Там хотя бы будут противоположные, вертикальные, накрестлежащие углы...
PM   Вверх
CompWorm
Дата 6.1.2009, 16:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



Dobermann, 
а с остальными то что делать? распиши свой алгоритм пожалуйста.
            в условии сказано: есть массив с вершинами...
ну вот у тебя координаты точек... ты собираешься сперва выяснить что чему параллельно и решить задачу для этих случаев, а потом подумать над еще одним алгоритмом для остальных?  smile 
ИМХО, этот второй алгоритм как раз будет универсальным и для параллельных прямых.


я почесал репку и придумал такой довольно универсальный вариант определения положения точки М...

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


отсюда вопрос к тем, кто силён в математике - как узнать, пересек ли луч отрезок?   smile 

Это сообщение отредактировал(а) CompWorm - 6.1.2009, 17:00


--------------------
PM MAIL   Вверх
Dobermann
Дата 6.1.2009, 17:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 992
Регистрация: 7.1.2008

Репутация: нет
Всего: 0



Цитата(CompWorm @  6.1.2009,  16:48 Найти цитируемый пост)
необходимо определить для каждой пары вершин, образующих отрезок, пересекается ли этот отрезок с горизонтальным лучом, пущенным из точки М. если  горизонтальный луч пересек нечетное число отрезков - значит М внутри многоугольника. если четное - вне многоугольника.просчитываем это дважды - для левой и правой полуплоскости относительно вертикали через точку М

Алгоритм в принципе не плох, только зачем 2 луча если можно ограничиться одной горизонтальной прямой. Но он ни к чему...

Цитата(CompWorm @  6.1.2009,  16:48 Найти цитируемый пост)
как узнать, пересек ли луч отрезок?

А зачем вообще отрезок?!! Не усложняй!! Ведь даны координаты Х и У всех точек!!!
Ну ведь же у точки М есть свои координаты...вот координатами и сравнивать, по другому никак, ток в координатах числа есть...Плоскость ведь у тебя одна - ХУ, т.е. можно сравнить координату Х точки М, с координатами Х точек твоей елки. Так же с У. 
Вопрос только один, у точки М есть координаты?
PM   Вверх
SoWa
Дата 6.1.2009, 17:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Харекришна
****


Профиль
Группа: Комодератор
Сообщений: 2422
Регистрация: 18.10.2004

Репутация: 6
Всего: 74



Цитата(CompWorm @  6.1.2009,  16:48 Найти цитируемый пост)
отсюда вопрос к тем, кто силён в математике - как узнать, пересек ли луч отрезок?   

Пересекает ли луч отрезок. Есть уравнение луча. Не проблемма найти уравнение для прямой, содержащей отрезок. Найти координату пересечения и проверить её на принадлежность отрезку.


--------------------
Всем добра smile
PM MAIL ICQ   Вверх
Earnest
Дата 6.1.2009, 18:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 7
Всего: 183



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

Добавлено через 12 минут и 40 секунд
А нет, неправильно поняла... нужно просто вычислить все углы. 
Тогда я бы предложила вместо проверки точки внутри-снаружи (что тоже можно) проверять конечную точку второго отрезка каждой пары. Если она с той же стороны от прямой, проходящей через первый отрезок, что и весь многоугольник, то угол выпуклый, иначе - вогнутый. Если ориентация контура заранее неизвестна (т.е. с какой стороны от контура внутренность многоугольника), нужно просто вычислить его площадь со знаком. Это эффективнее, чем для каждой пары отрезков вычислять "внутри-снаружи", т.к. требуется только один проход по отрезкам для вычисления плошади + фиксированная формула для каждого отрезка. А проверка "внутри-снаружи" требует прохода по всем отрезкам для каждой такой проверки.

Добавлено через 14 минут и 6 секунд
Цитата(CompWorm @  6.1.2009,  17:48 Найти цитируемый пост)
я почесал репку и придумал такой довольно универсальный вариант определения положения точки М...

Ага, почесал... теорема Жордана это называется


--------------------
...
PM   Вверх
Dobermann
Дата 6.1.2009, 19:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 992
Регистрация: 7.1.2008

Репутация: нет
Всего: 0



Цитата(Earnest @  6.1.2009,  18:38 Найти цитируемый пост)
Ага, почесал... теорема Жордана это называется

 smile 
PM   Вверх
CompWorm
Дата 6.1.2009, 23:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



Цитата(Earnest @  6.1.2009,  18:38 Найти цитируемый пост)
Ага, почесал... теорема Жордана это называется 

ну, я не математик, а русская смекалка помогает изобретать велосипеды  smile 

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

код привожу на Delphi.

строить будем симметричную ёлку (для наглядности), хотя можно и что угодно другое.
Код

uses
  ... Math;

var
  arrMain: array [1..7,1..3] of double;
implementation

procedure TForm1.FormCreate(Sender: TObject);
begin
  //наш многоугольник :)
  {        X                           Y       }

  arrMain[1,1]:=10;  arrMain[1,2]:=12;
  arrMain[2,1]:=3;  arrMain[2,2]:=7;
  arrMain[3,1]:=5;  arrMain[3,2]:=5;
  arrMain[4,1]:=3;  arrMain[4,2]:=1;
  arrMain[5,1]:=17;  arrMain[5,2]:=1;
  arrMain[6,1]:=15;  arrMain[6,2]:=5;
  arrMain[7,1]:=17;  arrMain[7,2]:=7;
end;


основная функция GetAlpha, после, скажем, нажатия кнопки,
в цикле вызывается для каждой вершины VrtN
вот, собсно, она сама
Код

function TForm1.GetAlpha(VrtN: integer): double;
  var
    TriPoints : array [1..3] of TPoint; // тут храним три точки - (VrtN-1), VrtN, (VrtN+1)
  var
    L1,L2,L3, // длины сторон треугольника, образуемого тремя вершинами.
    Alpha,     // угол во второй вершине TriPoints 
    Mx, My    : double; // координаты средней точки М на отрезке, образумом 1 и 3 точкой
begin
  // определимся с вершинами. их три, как не странно.
  // при обходе последней, 7, всегда будут проблемы, ибо ей нужна не 8, а 1 точка из массива.
  if VrtN=1 then begin
    TriPoints[1].X := round(arrMain[7,1]);
    TriPoints[1].Y := round(arrMain[7,2]);
  end else begin
    TriPoints[1].X := round(arrMain[VrtN-1,1]);
    TriPoints[1].Y := round(arrMain[VrtN-1,2]);
  end;
  TriPoints[2].X := round(arrMain[VrtN,1]);
  TriPoints[2].Y := round(arrMain[VrtN,2]);
  if VrtN=7 then begin
    TriPoints[3].X := round(arrMain[1,1]);
    TriPoints[3].Y := round(arrMain[1,2]);
  end else begin
    TriPoints[3].X := round(arrMain[VrtN+1,1]);
    TriPoints[3].Y := round(arrMain[VrtN+1,2]);
  end;
  // находим длины отрезков, образующих треугольник...
  L1:=sqrt(sqr(TriPoints[1].X-TriPoints[2].X)+sqr(TriPoints[1].Y-TriPoints[2].Y));
  L2:=sqrt(sqr(TriPoints[2].X-TriPoints[3].X)+sqr(TriPoints[2].Y-TriPoints[3].Y));
  L3:=sqrt(sqr(TriPoints[3].X-TriPoints[1].X)+sqr(TriPoints[3].Y-TriPoints[1].Y));
  // по теореме косинусов находим угол в образовавшемся треугольнике
  Alpha:=arccos((sqr(L1)+sqr(L2)-sqr(L3))/(2*L1*L2));
  //все эти углы < 180 градусов, эбо мы их считали как бы внутри треугольника,
  // образуемого прямыми L1, L2, L3 и тремя точками.
  // поэтому, чтобы понять, внешний это угол, или внутренний,
  //находим точку М - середину концов отрезков, образующих угол.
  Mx:=min(TriPoints[1].X,TriPoints[3].X)+(max(TriPoints[1].X, TriPoints[3].X)-min(TriPoints[1].X, TriPoints[3].X))/2;
  My:=min(TriPoints[1].Y,TriPoints[3].Y)+(max(TriPoints[1].Y, TriPoints[3].Y)-min(TriPoints[1].Y, TriPoints[3].Y))/2;
 // и проверяем, находится ли эта точка внутри нашего многоугольника.
  if PointInPolygon(Mx,My) = false then
    Result:=360-RadToGrad(Alpha) // если нет, то нам нужен угол "с другой стороны"
  else
    Result:=RadToGrad(Alpha); // если да, то наступило счастье
end;


тут для i-ой вершины имеем: 
1) находим угол альфа при i-ой вершине в треугольнике (i-1 , i ,  i+1)  он всегда<180
2) для определения с какой стороны он фигуры, находим точку M [x,y] середины отрезка между соседними (i-1 и  i+1) вершинами.
3) и юзаем проверку if PointInPolygon

последняя решается моим "велосипедом"  smile 

по словам Earnest, мы используем теорему Жордана smile
смысл в том, что если горизонтальный луч пересекает нечетное
число отрезков, образуемых граничными точками, то наша точка внутри.

определить, пересекает ли горизонтальный луч
идущий вправо из точки M[X ; Y] данный отрезок
ИМХО, проще всего ориентируясь на принадлежность точки луча отрезку.
то есть, если на отрезке есть такая точка К[x > X ; Y],
то отрезок пересекается.
принадлежность точки выражается равенствами:
    P * x1 + (1-P) * x2 = x
    P * y1 + (1-P) * y2 = y
    0 >= P >= 0
тогда, зная y=Y получаем P = (y-y2) / (y1-y2)
теперь осталось сравнить, есть ли такая точка,
что P * x1 + (1-P) * x2 > X
случай когда конец отрезка лежит на луче P=0 или Р=1
необходимо разрешить просчитывать лишь для одного из отрезков...
например, только для первого: 0 >= P > 0


Код

function TForm1.PointInPolygon(pX,pY: double): boolean;
  var
    i,
    CountCross    : integer; // считаем число пересечений. 
                                          // нечетное - точка внутри, четная - снаружи
    p             : double;
begin
  Result:= false;
  CountCross:=0;

  for i:=1 to 7 do begin
    if i<7 then begin // как я говорил, с последним все время косяки)))

      // основная проверка
      if NOT(arrMain[i,2] - arrMain[i+1,2] = 0) then begin // параллельность
        p:=(pY-arrMain[i+1,2])/(arrMain[i,2] - arrMain[i+1,2]);
        if (p*arrMain[i,1]+(1-p)*arrMain[i+1,1] >=pX)
          and (p>=0) and (p<1)
                                                then inc(CountCross);
      end;
    end else begin

      // основная проверка для последней вершины
      if NOT(arrMain[i,2] - arrMain[1,2] = 0) then begin // параллельность
        p:=(pY-arrMain[1,2])/(arrMain[i,2] - arrMain[1,2]);
        if (p*arrMain[i,1]+(1-p)*arrMain[1,1] >=pX)
          and (p>=0) and (p<1)
                                                then inc(CountCross);
      end;
    end;
  end;

  // проверка четности
  if NOT((CountCross mod 2) = 0) then Result:=True;


 smile 

жду комментов, критики и оптимизаций  smile 

Это сообщение отредактировал(а) CompWorm - 6.1.2009, 23:50

Присоединённый файл ( Кол-во скачиваний: 3 )
Присоединённый файл  ___________________.rar 176,64 Kb


--------------------
PM MAIL   Вверх
Dobermann
Дата 6.1.2009, 23:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 992
Регистрация: 7.1.2008

Репутация: нет
Всего: 0



Цитата(CompWorm @  6.1.2009,  23:41 Найти цитируемый пост)
жду комментов, критики и оптимизаций

Ну так работает?
PM   Вверх
CompWorm
Дата 6.1.2009, 23:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



тестирую.
у меня пока все работает...


--------------------
PM MAIL   Вверх
maxdiver
Дата 6.1.2009, 23:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 381
Регистрация: 29.1.2008
Где: Саратов

Репутация: 16
Всего: 18



Что-то я вашего алгоритма не понимаю.
Вот будет у нас такая фиговина, например:
(0,0), (1,1), (2,0), (1,4).
Посмотрим на угол ((0,0), (1,4), (2,0)). Очевидно, этот угол внутренний. Ваш алгоритм возьмёт середину (получится точка (1,0)), и она окажется вне многоугольника, из чего он сделает вывод, что этот угол не внутренний.

Я поддерживаю алгоритм Earnest - посчитать площадь со знаком, по ней понять направление обхода многоугольника, и просто обойти многоугольник в нужном направлении, каждый раз проверяя, куда направлена текущая тройка точек (p[i-1], p[i], p[i+1]).
Да и кодить тут всего-ничего придётся.
PM MAIL WWW ICQ   Вверх
CompWorm
Дата 7.1.2009, 00:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Допеределыватель
***


Профиль
Группа: Участник Клуба
Сообщений: 1689
Регистрация: 6.12.2004
Где: /

Репутация: нет
Всего: 31



maxdiver, 
вы невнимательно читали. конкретно в вашей задаче, луч пройдет из средней точки и далее через (2,0), засчитав его как пересечение.

но вы частично правы, если немного видоизменить ваше услокие 
(0,0), (1,3), (2,1), (1,4).
то задача нерешабельна моим алгоритмом.  smile  это я малость упустил.

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

Это сообщение отредактировал(а) CompWorm - 7.1.2009, 00:13


--------------------
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Алгоритмы"

maxim1000

Форум "Алгоритмы" предназначен для обсуждения вопросов, связанных только с алгоритмами и структурами данных, без привязки к конкретному языку программирования и/или программному продукту.


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, maxim1000.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Алгоритмы | Следующая тема »


 




[ Время генерации скрипта: 0.0590 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.