Расширить реализацию MySQL алгоритма PiP?

Мне нужно сделать точку в многоугольнике запросом MySQL.

Я уже нашел эти два отличных решения:

http://forums.mysql.com/read.php?23,286574,286574

Реализация MySQL алгоритма ray-casting?

Но эти функции могут только проверить, находится ли одна точка внутри полигона. У меня есть запрос, в котором часть PiP должна быть только одной частью запроса и проверять x точек внутри многоугольника.

Что-то вроде этого:

$points = list/array/whatever of points in language of favour

SELECT d.name
FROM data AS d
WHERE d.name LIKE %red%
// just bla bla

// how to do this ?
AND $points INSIDE d.polygon
AND myWithin( $points, d.polygo ) // or

ОБНОВЛЕНИЕ

Я попробовал это с такими функциями MBR:

SET @g1 = GeomFromText('Polygon((13.43971 52.55757,13.41293 52.49825,13.53378 52.49574, 13.43971 52.55757))');
SET @g2 = GeomFromText('Point(13.497834 52.540489)');
SELECT MBRContains(@g1,@g2);

G2 НЕ ДОЛЖЕН быть внутри G1, но MBR говорит, что это так.


person Mike    schedule 16.01.2013    source источник
comment
Вы проверили все функции по ссылке, предоставленной @eggyal?   -  person inhan    schedule 16.01.2013
comment
Я читал, что MBR недостаточно точен, но теперь копаю глубже.   -  person Mike    schedule 17.01.2013
comment
MBR не будет работать, так как работает с ограничивающими рамками. Обнаружение точек внутри полигона будет неточным.   -  person Mike    schedule 17.01.2013
comment
В конечном итоге вы будете использовать процедурный SQL, так почему бы вам не использовать императивный язык для запросов к БД и выполнения необходимых вам вычислений? Я не понимаю, почему SQL должен делать все... Просто спрашиваю.   -  person gd1    schedule 17.01.2013
comment
Сначала я сделал это, и это работает, но слишком много мест, где я бы в конечном итоге вставил фильтрацию результатов. Если мне удастся сделать это через SQL, везде будет работать только одна операция.   -  person Mike    schedule 17.01.2013
comment
я закончил предварительную фильтрацию результатов на стороне сервера следующим образом: -google-map" rel="nofollow noreferrer">daniweb.com/web-development/php/threads/366489/. Затем я запускаю свой основной запрос, содержащий только результаты предварительной фильтрации.   -  person Mike    schedule 18.01.2013


Ответы (3)


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

Если бы это был я, я бы поместил точки (и, возможно, полигоны - не показаны в примере) в таблицу, а затем написал бы функцию MySQL для применения метода raycasting к каждой точке - возвращая false, если какое-либо взаимодействие возвращает false, а затем возвращайте true. В приведенном ниже примере я предположил, что полигон извлекается из вашего полигона и идентифицируется по первичному ключу, а точки идентифицируются по внешнему ключу (используя функцию mywithin от zarun):

 DECLARE FUNCTION allwithin(
     pointSetKey INT) 
 RETURNS INT(1)  
 BEGIN 

 DECLARE current POINT;

 DECLARE check CURSOR FOR SELECT p.point
     FROM yourpoints p
     WHERE p.set=pointSetKey;

 OPEN check;

 nextPoint: LOOP

    FETCH check INTO current;

    IF (0=mywithin(current, yourpolygon)) THEN
         RETURN 0;
    END IF;

 END LOOP;

 RETURN 1;

 END;

 INSERT INTO yourpoints (pointsetkey, point)
 VALUES (
      128,
      GeomFromText('Point(13.497834 52.540489)')
 ),
 (
      128,
      GeomFromText('Point(13.6 52.1)')
 ),
 ....
 ;

 SELECT allwithin(128
 , GeomFromText('Polygon((13.43971 52.55757,13.41293 52.49825,13.53378 52.49574, 13.43971 52.55757))')
 );

or...

 SELECT COUNT(*)
 FROM yourpoints p
 WHERE p.set=128
 AND mywithin(p.point
      , GeomFromText('Polygon((13.43971 52.55757,13.41293 52.49825,13.53378 52.49574, 13.43971 52.55757))')
      );

Дает вам количество точек не внутри многоугольника (что довольно дорого, если вы хотите знать, не находится ли НИ ОДНА из точек снаружи).

person symcbean    schedule 18.01.2013
comment
На erflection это можно было бы многое оптимизировать - но время не позволяет. - person symcbean; 18.01.2013

что, если ты сделаешь

SET @g1 = GEOMFROMTEXT('Polygon((13.43971 52.55757,13.41293 52.49825,13.53378 52.49574, 13.43971 52.55757))');
SET @g2 = GEOMFROMTEXT('Point(13.497834 52.540489)');
SELECT  ST_Contains(@g1,@g2);

вместо MBRContains? Насколько я понимаю пространственная документация MySQL. Функции MBR* являются функциями минимального ограничивающего прямоугольника, поэтому они показывают, находится ли ваша точка в пределах минимального прямоугольника над вашей геометрией, но не в самой геометрии (в случае, если это неправильный многоугольник и точка находится внутри MBR, а не в многоугольник)

person Alexey    schedule 04.07.2013

Мне кажется это следующим образом: нужно проверить, находятся ли в многоугольнике несколько точек. Если все так, то такова и их выпуклая оболочка. Выясните их выпуклую оболочку (в основном: расположите их по часовой стрелке или против часовой стрелки), это создаст многоугольник. Теперь проверьте, находится ли новый многоугольник внутри d.polygon.

person Nitzan Shaked    schedule 13.07.2013