Следующая функция (версия алгоритма Raycasting для MYSQL) потрясла мой мир:
CREATE FUNCTION myWithin(p POINT, poly POLYGON) RETURNS INT(1) DETERMINISTIC
BEGIN
DECLARE n INT DEFAULT 0;
DECLARE pX DECIMAL(9,6);
DECLARE pY DECIMAL(9,6);
DECLARE ls LINESTRING;
DECLARE poly1 POINT;
DECLARE poly1X DECIMAL(9,6);
DECLARE poly1Y DECIMAL(9,6);
DECLARE poly2 POINT;
DECLARE poly2X DECIMAL(9,6);
DECLARE poly2Y DECIMAL(9,6);
DECLARE i INT DEFAULT 0;
DECLARE result INT(1) DEFAULT 0;
SET pX = X(p);
SET pY = Y(p);
SET ls = ExteriorRing(poly);
SET poly2 = EndPoint(ls);
SET poly2X = X(poly2);
SET poly2Y = Y(poly2);
SET n = NumPoints(ls);
WHILE i<n DO
SET poly1 = PointN(ls, (i+1));
SET poly1X = X(poly1);
SET poly1Y = Y(poly1);
IF ( ( ( ( poly1X <= pX ) && ( pX < poly2X ) ) || ( ( poly2X <= pX ) && ( pX < poly1X ) ) ) && ( pY > ( poly2Y - poly1Y ) * ( pX - poly1X ) / ( poly2X - poly1X ) + poly1Y ) ) THEN
SET result = !result;
END IF;
SET poly2X = poly1X;
SET poly2Y = poly1Y;
SET i = i + 1;
END WHILE;
RETURN result;
End;
Добавьте
DELIMITER ;;
перед функцией, как требуется.Для этой функции используется:
SELECT myWithin(point, polygon) as result;
где
point = Point(lat,lng)
polygon = Polygon(lat1 lng1, lat2 lng2, lat3 lng3, .... latn lngn, lat1 lng1)
Обратите внимание, что полигон должен быть закрыт (обычно он закрывается, если вы получаете стандартный kml или googlemapданные, но просто убедитесь, что это так - обратите внимание, что набор lat1 lng1 повторяется в конце)
У меня не было точек и полигонов в моей базе данных в качестве геометрических полей, поэтому мне пришлось сделать что-то вроде:
Select myWithin(PointFromText( concat( "POINT(", latitude, " ", longitude, ")" ) ),PolyFromText( 'POLYGON((lat1 lng1, ..... latn lngn, lat1 lng1))' ) ) as result
Надеюсь, это кому-нибудь поможет.