Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Составление SQL-запросов > Access&ADO: определение нахождения точки


Автор: KateL 7.10.2010, 13:35
Программа реализована на C++ Builder + MS Access + ADO.

Имеется таблица, два поля которой - коодинаты X, Y.
Надо получить набор данных в ADOQuery, в которых точка (X,Y) попадает в многоугольник, заданный точками (P[0].x, P[0].y)...(P[n].x, P[n].y).

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

Код

// Вычисляет попадание точки в полигон. Возвращает true, если точка внутри
bool clMap::point_in_poly(point_k *P, int Num_pt, point_k a)
{
int x,y, Count = 0;
  for(int i=0;i<Num_pt;i++)
  {
    if(P[i].y == P[i+1].y) continue; // оператор continue прерывает текущую итерацию цикла
    if(P[i].y > a.y && P[i+1].y > a.y) continue;
    if(P[i].y < a.y && P[i+1].y < a.y) continue;
    if( P[i].y > P[i+1].y) {y=P[i].y; x=P[i].x;} else {y=P[i+1].y; x=P[i+1].x;} 
    if( y==a.y && x >= a.x) Count++;                                            
    else
      if( min(P[i].y,P[i+1].y)==a.y) continue;
    else
    {
       double t = (double)(a.y - P[i].y)/(P[i+1].y - P[i].y);
       if(t>0 && t<1 && P[i].x + t*(P[i+1].x-P[i].x) >= a.x) Count++;
    }
  }
  return Count & 1;
}


Я не могу придумать, как мне эту функцию засунуть в запрос. Может надо использовать хранимые процедуры? Но я с ними не работала.
Это вообще возможно реализовать?
Помогите, пожалуйста.
 

Автор: Frees 7.10.2010, 14:07
Код

SELECT P.*
FROM POINTS_TABLE P
WHERE
(P.X >=:LEFT) AND (P.X < :RIGHT) AND (P.Y >= :TOP)  AND (P.Y < :BUTTOM);



Добавлено через 3 минуты и 2 секунды
чет я седне не внимательный... многоугольник с прямоугольником перепутал..

Автор: Akina 7.10.2010, 14:29
Цитата(KateL @  7.10.2010,  14:35 Найти цитируемый пост)
В обычном случае, алгоритм попадания точки в многоугольник выглядит так

А вербально описать можете?

Автор: Zloxa 7.10.2010, 15:12
Akina, пускает луч из точки, считает пересечение с отрезками полигона, если нечетное, значит внутри.

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

Автор: Zloxa 7.10.2010, 15:43
В общем както так, если не накосячил в формулах координат пересечения отрезков
Код

SQL> with poly as ( select 2 x1,4 y1,5 x2,3 y2 from dual
  2       union all select 5,3,7,5 from dual
  3       union all select 7,5,4,7 from dual
  4       union all select 4,7,2,4 from dual
  5  )
  6     ,point as (select 3 x,2 y from dual
  7      union all select 4 x,5 y from dual
  8      union all select 4 x,7 y from dual
  9      union all select 6 x,7 y from dual
 10      )
 11  select x,y
 12  from (
 13    select
 14     s.*
 15     ,y*xp/x yp
 16    from (
 17      select poly.*
 18             ,point.*
 19             ,((x1*y2-x2*y1)*x)/((y2-y1)*x-y*(x2-x1)) xp
 20      from poly,point
 21     )s
 22  )
 23  where xp<=greatest(0,x) and xp>=least(0,x)
 24        and xp<=greatest(x1,x2) and xp >= least(x1,x2)
 25        and yp<=greatest(0,y) and yp>=least(0,y)
 26        and yp<=greatest(y1,y2) and yp >= least(y1,y2)
 27  group by x,y
 28  having mod(count(*),2) = 1
 29  ;
 
         X          Y
---------- ----------
         4          5
         4          7


здесь poly - иммитирует таблицу отрезков многоугольника
,point - иммитирует таблицу точек, которые мы хотим проверить.

Луч пускаю в сторону точки (0,0). Потому ограничение - точка не может быть в начале координат
Соответственно длинна отрезка тоже не должна быть равной нулю и параллельно лучу, будет деление на ноль.

Перевести на акцесс, думаю вполне возможно.
если решите взятьза основу - Тестировать тщательно. Таки переживаю что накосячил в расчете.

Автор: KateL 7.10.2010, 16:07
Прямо не ожидала, что так быстро ответят.
Спасибо большое  smile 
Завтра буду пробовать применить. 

Автор: Zloxa 7.10.2010, 16:23
KateL, для акцесса этот запрос надо будет несколько переработать. 

Автор: Akina 7.10.2010, 16:38
Цитата(Zloxa @  7.10.2010,  17:23 Найти цитируемый пост)
для акцесса этот запрос надо будет несколько переработать.  

greatest(val1,val2) => IIF(val1>val2;val1;val2)
least(val1,val2) => IIF(val1<val2;val1;val2)
mod(count(*),2) = 1 => (count(*) MOD 2) = 1

остальное вроде совместимо.

Автор: Zloxa 7.10.2010, 18:35
Цитата(Zloxa @  7.10.2010,  15:43 Найти цитируемый пост)
xp<=greatest(0,x) and xp>=least(0,x)

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

заменить на xp<=x
тоже и для y "and yp<=greatest(0,y) and yp>=least(0,y)"  заменить на "yp<=y"

Автор: KateL 8.10.2010, 18:09
Еще раз спасибо за советы.

Я ранее не работала с такими сложными запросами, поэтому долго разбиралась.
Но пока у меня не получилось заставить его работать.
При выполнении запроса выдает ошибку: "Ошибка синтаксиса в выражении запроса"

Возможно, дело в этом: (из хелпов про SQL)

В общем случае оператор SELECT с подзапросом имеет вид:

SELECT ...
FROM ...
WHERE <сравниваемое значение> <оператор> (SELECT ... FROM ... WHERE ...)


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

Подзапрос можно использовать в следующих предложениях SQL команд:
• WHERE
• HAVING

Примечание: Такие сервера как Oracle, MS SQL, Interbase поддерживают использование подзапросов еще и в предложении FROM.

Автор: Zloxa 8.10.2010, 19:41
Цитата(KateL @  8.10.2010,  18:09 Найти цитируемый пост)
(из хелпов про SQL)

читайте документацию по тому продукту, с которым работатете, а не по какието невнятные  хелпы по SQL.
Акцесс поддерживает подзапросы в from.

Цитата(KateL @  8.10.2010,  18:09 Найти цитируемый пост)
Примечание: Такие сервера как Oracle, MS SQL, Interbase поддерживают использование подзапросов еще и в предложении FROM.

Сейчас скорее по пальцам нужно перечислять движки, которые их не поддреживают нежели те, кто его поддерживает.

Автор: KateL 13.10.2010, 09:57
Большое спасибо за помощь!
Все заработало!  smile 

(Моя ошибка была в том, что я немного переписала условие, и в качестве оператора "не равно" использовала != вместо <>)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)