在多边形中查找点 PHP

发布于 2024-10-18 09:10:30 字数 402 浏览 8 评论 0原文

我有一个关于 mysql 几何数据类型多边形的典型问题。

我有多边形数据,以纬度和经度数组的形式,例如:

[["x":37.628134,  "y":-77.458334],
["x":37.629867,   "y":-77.449021],
["x":37.62324,    "y":-77.445416],
["x":37.622424,   "y":-77.457819]]

我有一个带有纬度和经度坐标的点(顶点),例如:

$location = new vertex($_GET["longitude"], $_GET["latitude"]);

现在我想知道这个顶点(点)是否在多边形。 我怎样才能在 php 中做到这一点?

i have a typical question with the Geometric datatype of mysql, polygon.

I have the polygon data, in the form of an array of latitudes and longitudes, ex:

[["x":37.628134,  "y":-77.458334],
["x":37.629867,   "y":-77.449021],
["x":37.62324,    "y":-77.445416],
["x":37.622424,   "y":-77.457819]]

And i have a point (Vertex) with coordinates of latitude and longitude, ex:

$location = new vertex($_GET["longitude"], $_GET["latitude"]);

Now i want to find whether this vertex (point) is inside the polygon.
How can i do this in php ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

鸠魁 2024-10-25 09:10:30

这是我从另一种语言转换为 PHP 的函数:

$vertices_x = array(37.628134, 37.629867, 37.62324, 37.622424);    // x-coordinates of the vertices of the polygon
$vertices_y = array(-77.458334,-77.449021,-77.445416,-77.457819); // y-coordinates of the vertices of the polygon
$points_polygon = count($vertices_x) - 1;  // number vertices - zero-based array
$longitude_x = $_GET["longitude"];  // x-coordinate of the point to test
$latitude_y = $_GET["latitude"];    // y-coordinate of the point to test

if (is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)){
  echo "Is in polygon!";
}
else echo "Is not in polygon";


function is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)
{
  $i = $j = $c = 0;
  for ($i = 0, $j = $points_polygon ; $i < $points_polygon; $j = $i++) {
    if ( (($vertices_y[$i]  >  $latitude_y != ($vertices_y[$j] > $latitude_y)) &&
     ($longitude_x < ($vertices_x[$j] - $vertices_x[$i]) * ($latitude_y - $vertices_y[$i]) / ($vertices_y[$j] - $vertices_y[$i]) + $vertices_x[$i]) ) )
       $c = !$c;
  }
  return $c;
}

附加:
对于更多功能,我建议您使用 Polygon.php 类此处提供
使用您的顶点创建类,并使用您的测试点作为输入调用函数 isInside ,让另一个函数解决您的问题。

This is a function i converted from another language into PHP:

$vertices_x = array(37.628134, 37.629867, 37.62324, 37.622424);    // x-coordinates of the vertices of the polygon
$vertices_y = array(-77.458334,-77.449021,-77.445416,-77.457819); // y-coordinates of the vertices of the polygon
$points_polygon = count($vertices_x) - 1;  // number vertices - zero-based array
$longitude_x = $_GET["longitude"];  // x-coordinate of the point to test
$latitude_y = $_GET["latitude"];    // y-coordinate of the point to test

if (is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)){
  echo "Is in polygon!";
}
else echo "Is not in polygon";


function is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)
{
  $i = $j = $c = 0;
  for ($i = 0, $j = $points_polygon ; $i < $points_polygon; $j = $i++) {
    if ( (($vertices_y[$i]  >  $latitude_y != ($vertices_y[$j] > $latitude_y)) &&
     ($longitude_x < ($vertices_x[$j] - $vertices_x[$i]) * ($latitude_y - $vertices_y[$i]) / ($vertices_y[$j] - $vertices_y[$i]) + $vertices_x[$i]) ) )
       $c = !$c;
  }
  return $c;
}

Additional:
For more functions i advise you to use the polygon.php class available here.
Create the Class using your vertices and call the function isInside with your testpoint as input to have another function solving your problem.

灵芸 2024-10-25 09:10:30

上面的热门答案包含错别字。在其他地方,此代码已被清理。更正后的代码如下:

<?php
/**
  From: http://www.daniweb.com/web-development/php/threads/366489
  Also see http://en.wikipedia.org/wiki/Point_in_polygon
*/
$vertices_x = array(37.628134, 37.629867, 37.62324, 37.622424); // x-coordinates of the vertices of the polygon
$vertices_y = array(-77.458334,-77.449021,-77.445416,-77.457819); // y-coordinates of the vertices of the polygon
$points_polygon = count($vertices_x); // number vertices
$longitude_x = $_GET["longitude"]; // x-coordinate of the point to test
$latitude_y = $_GET["latitude"]; // y-coordinate of the point to test
//// For testing.  This point lies inside the test polygon.
// $longitude_x = 37.62850;
// $latitude_y = -77.4499;

if (is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)){
  echo "Is in polygon!";
}
else echo "Is not in polygon";


function is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)
{
  $i = $j = $c = 0;
  for ($i = 0, $j = $points_polygon-1 ; $i < $points_polygon; $j = $i++) {
    if ( (($vertices_y[$i] > $latitude_y != ($vertices_y[$j] > $latitude_y)) &&
    ($longitude_x < ($vertices_x[$j] - $vertices_x[$i]) * ($latitude_y - $vertices_y[$i]) / ($vertices_y[$j] - $vertices_y[$i]) + $vertices_x[$i]) ) ) 
        $c = !$c;
  }
  return $c;
}
?>

The popular answer above contains typos. Elsewhere, this code has been cleaned up. The corrected code is as follows:

<?php
/**
  From: http://www.daniweb.com/web-development/php/threads/366489
  Also see http://en.wikipedia.org/wiki/Point_in_polygon
*/
$vertices_x = array(37.628134, 37.629867, 37.62324, 37.622424); // x-coordinates of the vertices of the polygon
$vertices_y = array(-77.458334,-77.449021,-77.445416,-77.457819); // y-coordinates of the vertices of the polygon
$points_polygon = count($vertices_x); // number vertices
$longitude_x = $_GET["longitude"]; // x-coordinate of the point to test
$latitude_y = $_GET["latitude"]; // y-coordinate of the point to test
//// For testing.  This point lies inside the test polygon.
// $longitude_x = 37.62850;
// $latitude_y = -77.4499;

if (is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)){
  echo "Is in polygon!";
}
else echo "Is not in polygon";


function is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)
{
  $i = $j = $c = 0;
  for ($i = 0, $j = $points_polygon-1 ; $i < $points_polygon; $j = $i++) {
    if ( (($vertices_y[$i] > $latitude_y != ($vertices_y[$j] > $latitude_y)) &&
    ($longitude_x < ($vertices_x[$j] - $vertices_x[$i]) * ($latitude_y - $vertices_y[$i]) / ($vertices_y[$j] - $vertices_y[$i]) + $vertices_x[$i]) ) ) 
        $c = !$c;
  }
  return $c;
}
?>
傾旎 2024-10-25 09:10:30

上面的解决方案没有按我的预期工作,您可以选择下面的解决方案

  1. 使用 PHP

    , 而不是使用上面的解决方案

    function pointInPolygon($point, $polygon, $pointOnVertex = true) {
        $this->pointOnVertex = $pointOnVertex;
    
        // 将字符串坐标转换为具有 x 和 y 值的数组
        $point = $this->pointStringToCoordinates($point);
        $顶点=数组(); 
        foreach($polygon 作为$vertex){
            $vertices[] = $this->pointStringToCoordinates($vertex); 
        }
    
        // 检查 lat lng 是否正好位于顶点上
        if ($this->pointOnVertex == true 且 $this->pointOnVertex($point, $vertices) == true) {
            返回“顶点”;
        }
    
        // 检查 lat lng 是否在多边形内部或边界上
        $交叉点= 0; 
        $vertices_count = 计数($vertices);
    
        for ($i=1; $i < $vertices_count; $i++) {
            $vertex1 = $vertices[$i-1]; 
            $vertex2 = $vertices[$i];
            if ($vertex1['y'] == $vertex2['y'] 且 $vertex1['y'] == $point['y'] 且 $point['x'] > min($vertex1[ 'x'], $vertex2['x']) and $point['x'] < max($vertex1['x'], $vertex2['x'])) { // 检查点是否打开水平多边形边界
                返回“边界”;
            }
            if ($point['y'] > min($vertex1['y'], $vertex2['y']) 且 $point['y'] <= max($vertex1['y'], $vertex2['y']) 和 $point['x'] <= max($vertex1['x'], $vertex2['x']) 和 $vertex1['y'] != $vertex2[ 'y']) { 
                $xinters = ($point['y'] - $vertex1['y']) * ($vertex2['x'] - $vertex1['x']) / ($vertex2['y'] - $vertex1 ['y']) + $vertex1['x']; 
                if ($xinters == $point['x']) { // 检查 lat lng 是否在多边形边界上(水平方向除外)
                    返回“边界”;
                }
                if ($vertex1['x'] == $vertex2['x'] || $point['x'] <= $xinters) {
                    $交叉点++; 
                }
            } 
        } 
        // 如果我们经过的边数是奇数,那么它就在多边形中。 
        if ($intersections % 2 != 0) {
            返回“内部”;
        } 别的 {
            返回“外部”;
        }
    }
    
    函数 pointOnVertex($point, $vertices) {
      foreach($vertices as $vertex) {
          if ($point == $vertex) {
              返回真;
          }
      }
    
    }
    
    函数 pointStringToCoordinates($pointString) {
        $坐标=爆炸(“”,$pointString);
        返回数组(“x”=>$坐标[0],“y”=>$坐标[1]);
    }
    // 检查 lat lng 的函数
    函数检查(){
        $点=数组(“22.367582 70.711816”,“21.43567582 72.5811816”,“22.367582117085913 70.71181669186944”,“22.275334996986643 70.88614147 123701","22.36934302329968 70.77627818998701"); // 要查找的 latlng 数组
        $多边形=数组(
            “22.367582117085913 70.71181669186944”,
            “22.225161442616514 70.65582486840117”,
            “22.20736264867434 70.83229276390898”,
            “22.18701840565626 70.9867880031668”,
            “22.22452581029355 71.0918447658621”,
            “22.382709129816103 70.98884793969023”,
            “22.40112042636022 70.94078275414336”,
            “22.411912121843205 70.7849142238699”,
            “22.367582117085913 70.71181669186944”
        );
        // 最后的 lat lng 必须与第一个相同,以“关闭循环”
        foreach($points as $key => $point) {
            回声“(经纬度)”。 ($key+1) 。 “($点):”。 $this->pointInPolygon($point, $polygon) 。 “
    ”; } }
  2. 使用 MySql

创建表 `TestPoly` (
   `id` int(11) NOT NULL,
   `name` varchar(255) NOT NULL,
   `pol` 多边形不为空
 )

设置 @g = '多边形((22.367582117085913 70.71181669186944, 22.225161442616514 70.65582486840117, 22.20736264867434 70.8322927639089 8、22.18701840565626 70.9867880031668、22.22452581029355 71.0918447658621、22.382709129816103 70.98884793969023、22.40112042 636022 70.94078275414336、22.411912121843205 70.7849142238699、22.367582117085913 70.71181669186944))';
插入 TestPoly (pol) 值 (ST_GeomFromText(@g))

设置@p = GeomFromText('点(22.4053386588057 70.86240663480157)');
选择 * FROM TestPoly 其中 ST_Contains(pol, @p);

Above solution is not working as i expect, instead of using the above solution you can prefer below solutions

  1. With PHP

    function pointInPolygon($point, $polygon, $pointOnVertex = true) {
        $this->pointOnVertex = $pointOnVertex;
    
        // Transform string coordinates into arrays with x and y values
        $point = $this->pointStringToCoordinates($point);
        $vertices = array(); 
        foreach ($polygon as $vertex) {
            $vertices[] = $this->pointStringToCoordinates($vertex); 
        }
    
        // Check if the lat lng sits exactly on a vertex
        if ($this->pointOnVertex == true and $this->pointOnVertex($point, $vertices) == true) {
            return "vertex";
        }
    
        // Check if the lat lng is inside the polygon or on the boundary
        $intersections = 0; 
        $vertices_count = count($vertices);
    
        for ($i=1; $i < $vertices_count; $i++) {
            $vertex1 = $vertices[$i-1]; 
            $vertex2 = $vertices[$i];
            if ($vertex1['y'] == $vertex2['y'] and $vertex1['y'] == $point['y'] and $point['x'] > min($vertex1['x'], $vertex2['x']) and $point['x'] < max($vertex1['x'], $vertex2['x'])) { // Check if point is on an horizontal polygon boundary
                return "boundary";
            }
            if ($point['y'] > min($vertex1['y'], $vertex2['y']) and $point['y'] <= max($vertex1['y'], $vertex2['y']) and $point['x'] <= max($vertex1['x'], $vertex2['x']) and $vertex1['y'] != $vertex2['y']) { 
                $xinters = ($point['y'] - $vertex1['y']) * ($vertex2['x'] - $vertex1['x']) / ($vertex2['y'] - $vertex1['y']) + $vertex1['x']; 
                if ($xinters == $point['x']) { // Check if lat lng is on the polygon boundary (other than horizontal)
                    return "boundary";
                }
                if ($vertex1['x'] == $vertex2['x'] || $point['x'] <= $xinters) {
                    $intersections++; 
                }
            } 
        } 
        // If the number of edges we passed through is odd, then it's in the polygon. 
        if ($intersections % 2 != 0) {
            return "inside";
        } else {
            return "outside";
        }
    }
    
    function pointOnVertex($point, $vertices) {
      foreach($vertices as $vertex) {
          if ($point == $vertex) {
              return true;
          }
      }
    
    }
    
    function pointStringToCoordinates($pointString) {
        $coordinates = explode(" ", $pointString);
        return array("x" => $coordinates[0], "y" => $coordinates[1]);
    }
    // Function to check lat lng
    function check(){
        $points = array("22.367582 70.711816", "21.43567582 72.5811816","22.367582117085913 70.71181669186944","22.275334996986643 70.88614147123701","22.36934302329968 70.77627818998701"); // Array of latlng which you want to find
        $polygon = array(
            "22.367582117085913 70.71181669186944",
            "22.225161442616514 70.65582486840117",
            "22.20736264867434 70.83229276390898",
            "22.18701840565626 70.9867880031668",
            "22.22452581029355 71.0918447658621",
            "22.382709129816103 70.98884793969023",
            "22.40112042636022 70.94078275414336",
            "22.411912121843205 70.7849142238699",
            "22.367582117085913 70.71181669186944"
        );
        // The last lat lng must be the same as the first one's, to "close the loop"
        foreach($points as $key => $point) {
            echo "(Lat Lng) " . ($key+1) . " ($point): " . $this->pointInPolygon($point, $polygon) . "<br>";
        }
    }
    
  2. With MySql

CREATE TABLE `TestPoly` (
   `id` int(11) NOT NULL,
   `name` varchar(255) NOT NULL,
   `pol` polygon NOT NULL
 )

SET @g = 'POLYGON((22.367582117085913 70.71181669186944, 22.225161442616514 70.65582486840117, 22.20736264867434 70.83229276390898, 22.18701840565626 70.9867880031668, 22.22452581029355 71.0918447658621, 22.382709129816103 70.98884793969023, 22.40112042636022 70.94078275414336, 22.411912121843205 70.7849142238699, 22.367582117085913 70.71181669186944))';
INSERT INTO TestPoly (pol) VALUES (ST_GeomFromText(@g))

set @p = GeomFromText('POINT(22.4053386588057 70.86240663480157)');
select * FROM TestPoly where ST_Contains(pol, @p);
少年亿悲伤 2024-10-25 09:10:30

如果您的多边形是自闭合的,也就是说它的最终顶点是最后一个点和第一个点之间的线,那么您需要在循环中添加一个变量和一个条件来处理最终顶点。您还需要将顶点数传递为等于点数。

这是为处理自闭合多边形而修改的已接受答案:

$vertices_x = array(37.628134, 37.629867, 37.62324, 37.622424);    // x-coordinates of the vertices of the polygon
$vertices_y = array(-77.458334,-77.449021,-77.445416,-77.457819); // y-coordinates of the vertices of the polygon
$points_polygon = count($vertices_x);  // number vertices = number of points in a self-closing polygon
$longitude_x = $_GET["longitude"];  // x-coordinate of the point to test
$latitude_y = $_GET["latitude"];    // y-coordinate of the point to test

if (is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)){
  echo "Is in polygon!";
}
else echo "Is not in polygon";


function is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)
{
  $i = $j = $c = $point = 0;
  for ($i = 0, $j = $points_polygon ; $i < $points_polygon; $j = $i++) {
    $point = $i;
    if( $point == $points_polygon )
      $point = 0;
    if ( (($vertices_y[$point]  >  $latitude_y != ($vertices_y[$j] > $latitude_y)) &&
     ($longitude_x < ($vertices_x[$j] - $vertices_x[$point]) * ($latitude_y - $vertices_y[$point]) / ($vertices_y[$j] - $vertices_y[$point]) + $vertices_x[$point]) ) )
       $c = !$c;
  }
  return $c;
}

谢谢!我发现这个页面和它被接受的答案非常有帮助,我很自豪能够提供这个变体。

If your polygons are self-closing, that is to say that it's final vertex is the line between it's last point and it's first point then you need to add a variable and a condition to your loop to deal with the final vertex. You also need to pass the number of vertices as being equal to the number of points.

Here is the accepted answer modified to deal with self-closing polygons:

$vertices_x = array(37.628134, 37.629867, 37.62324, 37.622424);    // x-coordinates of the vertices of the polygon
$vertices_y = array(-77.458334,-77.449021,-77.445416,-77.457819); // y-coordinates of the vertices of the polygon
$points_polygon = count($vertices_x);  // number vertices = number of points in a self-closing polygon
$longitude_x = $_GET["longitude"];  // x-coordinate of the point to test
$latitude_y = $_GET["latitude"];    // y-coordinate of the point to test

if (is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)){
  echo "Is in polygon!";
}
else echo "Is not in polygon";


function is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)
{
  $i = $j = $c = $point = 0;
  for ($i = 0, $j = $points_polygon ; $i < $points_polygon; $j = $i++) {
    $point = $i;
    if( $point == $points_polygon )
      $point = 0;
    if ( (($vertices_y[$point]  >  $latitude_y != ($vertices_y[$j] > $latitude_y)) &&
     ($longitude_x < ($vertices_x[$j] - $vertices_x[$point]) * ($latitude_y - $vertices_y[$point]) / ($vertices_y[$j] - $vertices_y[$point]) + $vertices_x[$point]) ) )
       $c = !$c;
  }
  return $c;
}

Thank you! I found this page and it's accepted answer very helpful and I am proud to offer this variation.

星軌x 2024-10-25 09:10:30

我将泰国多边形放入MySQL。并将接受的答案函数与 MySQL 8 中的内置函数进行比较。

CREATE TABLE `polygons` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `polygon` POLYGON NOT NULL,
    `country` VARCHAR(50) NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    SPATIAL INDEX `polygon` (`polygon`)
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
AUTO_INCREMENT=652
;

INSERT INTO `polygons` (`country`, `polygon`) VALUES ('Thailand', ST_GEOMFROMTEXT('POLYGON((102.1728516 6.1842462,101.6894531 5.7253114,101.1401367 5.6815837,101.1181641 6.2497765,100.1074219 6.4899833,96.3281250 6.4244835,96.1083984 9.8822755,98.7670898 10.1419317,99.5800781 11.8243415,98.2177734 15.1569737,98.9868164 16.3201395,97.4267578 18.4587681,98.1079102 19.7253422,99.0087891 19.7460242,100.2612305 20.2828087,100.4809570 19.4769502,101.2060547 19.4147924,100.8544922 17.4135461,102.0849609 17.9996316,102.8320313 17.7696122,103.3593750 18.3545255,104.7875977 17.4554726,104.6337891 16.4676947,105.5126953 15.6018749,105.2270508 14.3069695,102.9858398 14.2643831,102.3486328 13.5819209,103.0297852 11.0059045,103.6669922 8.5592939,102.1728516 6.1842462))'));

这是上面有点的多边形 - RED 是第一个,BLUE - 最后一个:

泰国多边形点

I使用 https://www.gpsvisualizer.com/draw/ 并制作屏幕以可视化所有点。

点差MySQL / PHP

我给了点作为 PHP 函数的坐标 + 使用查询与 MySQL 函数比较结果:

SELECT TRUE FROM `polygons` WHERE `polygons`.`country` = 'Thailand' AND ST_CONTAINS(`polygons`.`polygon`, POINT($long, $lat));

结果:

  • MySQL 总是给我关于所有点的正确答案。
  • PHP 函数有错误的答案
    • 红色 - 如果我删除多边形的闭合点
    • 橙色 - 不删除最后一个点,与打开的点相同,与 MYSQL 多边形中的相同。
    • 白色点与 PHP / MySQL 的结果相同并且是正确答案

我尝试更改多边形,但 php 函数总是在这些点上出错,这意味着某个地方存在我找不到的错误。

更新 1

找到解决方案 assemblysys.com/php-point-in-polygon-algorithm - 该算法与 MySQL 算法相同!

更新 2

比较了 PHP 与 MySQL 的速度(我认为 PHP 应该更快),但事实并非如此。比较 47k 点。

18-06-2020 21:34:45 - PHP Speed Check Start
18-06-2020 21:34:51 - FIN! PHP Check. NOT = 41085 / IN = 5512
18-06-2020 21:34:51 - MYSQL Speed Check Start
18-06-2020 21:34:58 - FIN! MYSQL Check. NOT = 41085 / IN = 5512

I put Thailand polygon into MySQL. And compared accepted answer function with built-in function in MySQL 8.

CREATE TABLE `polygons` (
    `id` INT(11) NOT NULL AUTO_INCREMENT,
    `polygon` POLYGON NOT NULL,
    `country` VARCHAR(50) NULL DEFAULT NULL,
    PRIMARY KEY (`id`),
    SPATIAL INDEX `polygon` (`polygon`)
)
COLLATE='utf8mb4_0900_ai_ci'
ENGINE=InnoDB
AUTO_INCREMENT=652
;

INSERT INTO `polygons` (`country`, `polygon`) VALUES ('Thailand', ST_GEOMFROMTEXT('POLYGON((102.1728516 6.1842462,101.6894531 5.7253114,101.1401367 5.6815837,101.1181641 6.2497765,100.1074219 6.4899833,96.3281250 6.4244835,96.1083984 9.8822755,98.7670898 10.1419317,99.5800781 11.8243415,98.2177734 15.1569737,98.9868164 16.3201395,97.4267578 18.4587681,98.1079102 19.7253422,99.0087891 19.7460242,100.2612305 20.2828087,100.4809570 19.4769502,101.2060547 19.4147924,100.8544922 17.4135461,102.0849609 17.9996316,102.8320313 17.7696122,103.3593750 18.3545255,104.7875977 17.4554726,104.6337891 16.4676947,105.5126953 15.6018749,105.2270508 14.3069695,102.9858398 14.2643831,102.3486328 13.5819209,103.0297852 11.0059045,103.6669922 8.5592939,102.1728516 6.1842462))'));

Here is polygon with dots above - RED is 1st, BLUE - last:

Thailand Polygon Dots

I draw some dots outside and inside Thailand Polygon on the map using https://www.gpsvisualizer.com/draw/ and made screen to visualize all the dots.

Dots difference MySQL / PHP

I gave dots as coordinates for PHP function + compared results with MySQL function using query:

SELECT TRUE FROM `polygons` WHERE `polygons`.`country` = 'Thailand' AND ST_CONTAINS(`polygons`.`polygon`, POINT($long, $lat));

The result:

  • MySQL always gave me right answer about all the dots.
  • PHP function has wrong answers
    • RED - if I delete closing dot of polygon
    • ORANGE - not deleting last dot which is same as opening, and same like in MYSQL polygon.
    • WHITE dots had same results PHP / MySQL and are right answers.

I tried to change polygon, but php function always making mistakes about those dots, means somewhere there is bug which I could not find.

Update 1

Found solution assemblysys.com/php-point-in-polygon-algorithm - this algo works same as MySQL algo!

Update 2

Compared PHP speed vs MySQL (I was thinking that PHP should be much more faster), but no. Compared 47k dots.

18-06-2020 21:34:45 - PHP Speed Check Start
18-06-2020 21:34:51 - FIN! PHP Check. NOT = 41085 / IN = 5512
18-06-2020 21:34:51 - MYSQL Speed Check Start
18-06-2020 21:34:58 - FIN! MYSQL Check. NOT = 41085 / IN = 5512
孤城病女 2024-10-25 09:10:30

这是一个可能的算法。

  1. 以您的兴趣点为中心定义一个新的坐标系。
  2. 在新坐标系中,将所有多边形顶点转换为极坐标。
  3. 遍历多边形,记录角度的净变化 Δθ。每次角度变化始终使用尽可能小的值。
  4. 如果,一旦你穿过多边形,你的总 Δθ 是 0,那么你就在多边形之外了。另一方面,如果它是±2π,那么你就在里面。
  5. 如果碰巧 Δθ>2π 或 Δθ<-2π,则意味着您有一个自身对折的多边形。

编写代码留作练习。 :)

Here's a possible algorithm.

  1. Define a new coordinate system with your point of interest at the center.
  2. In your new coordinate system, convert all of your polygon vertices into polar coordinates.
  3. Traverse the polygon, keeping track of the net change in angle, ∆θ. Always use the smallest possible value for each change in angle.
  4. If, once you've traversed the polygon, your total ∆θ is 0, then you're outside the polygon. On the other hand, if it's is ±2π, then you're inside.
  5. If, by chance ∆θ>2π or ∆θ<-2π, that means you have a polygon that doubles back on itself.

Writing the code is left as an exercise. :)

请帮我爱他 2024-10-25 09:10:30

更新了代码,这样我将更容易使用谷歌地图:
它接受如下数组:

Array
(
    [0] => stdClass Object
        (
            [lat] => 43.685927
            [lng] => -79.745829
        )

    [1] => stdClass Object
        (
            [lat] => 43.686004
            [lng] => -79.745954
        )

    [2] => stdClass Object
        (
            [lat] => 43.686429
            [lng] => -79.746642
        )

因此与谷歌地图一起使用会更容易:

function is_in_polygon2($longitude_x, $latitude_y,$polygon)
{
  $i = $j = $c = 0;
  $points_polygon = count($polygon)-1;
  for ($i = 0, $j = $points_polygon ; $i < $points_polygon; $j = $i++) {
    if ( (($polygon[$i]->lat  >  $latitude_y != ($polygon[$j]->lat > $latitude_y)) &&
     ($longitude_x < ($polygon[$j]->lng - $polygon[$i]->lng) * ($latitude_y - $polygon[$i]->lat) / ($polygon[$j]->lat - $polygon[$i]->lat) + $polygon[$i]->lng) ) )
       $c = !$c;
  }
  return $c;
}

Updated code so i will be easier to use with google maps:
It accept array like:

Array
(
    [0] => stdClass Object
        (
            [lat] => 43.685927
            [lng] => -79.745829
        )

    [1] => stdClass Object
        (
            [lat] => 43.686004
            [lng] => -79.745954
        )

    [2] => stdClass Object
        (
            [lat] => 43.686429
            [lng] => -79.746642
        )

So it will be easier to use with google maps:

function is_in_polygon2($longitude_x, $latitude_y,$polygon)
{
  $i = $j = $c = 0;
  $points_polygon = count($polygon)-1;
  for ($i = 0, $j = $points_polygon ; $i < $points_polygon; $j = $i++) {
    if ( (($polygon[$i]->lat  >  $latitude_y != ($polygon[$j]->lat > $latitude_y)) &&
     ($longitude_x < ($polygon[$j]->lng - $polygon[$i]->lng) * ($latitude_y - $polygon[$i]->lat) / ($polygon[$j]->lat - $polygon[$i]->lat) + $polygon[$i]->lng) ) )
       $c = !$c;
  }
  return $c;
}
单挑你×的.吻 2024-10-25 09:10:30

我在 php codeigniter 中创建了代码,在我的控制器中我创建了两个函数,如下所示

public function checkLatLng(){
    $vertices_y = array(22.774,22.174,22.466,22.666,22.966,22.321);    // x-coordinates of the vertices of the polygon (LATITUDES)
    $vertices_x = array(70.190,70.090,77.118,77.618,77.418,77.757); // y-coordinates of the vertices of the polygon (LONGITUDES)
    $points_polygon = count($vertices_x)-1; 
    $longitude_x = $this->input->get("longitude");  // Your Longitude
    $latitude_y = $this->input->get("latitude");    // Your Latitude
    if ($this->is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)){
        echo "Is in polygon!";
    }
    else
        echo "Is not in polygon";
}

另一个用于检查 lat-lng 的函数如下

public function is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y){
    $i = $j = $c = $point = 0;
    for ($i = 0, $j = $points_polygon ; $i < $points_polygon; $j = $i++) {
        $point = $i;
        if( $point == $points_polygon )
            $point = 0;
        if ( (($vertices_y[$point]  >  $latitude_y != ($vertices_y[$j] > $latitude_y)) && ($longitude_x < ($vertices_x[$j] - $vertices_x[$point]) * ($latitude_y - $vertices_y[$point]) / ($vertices_y[$j] - $vertices_y[$point]) + $vertices_x[$point]) ) )
            $c = !$c;
    }
    return $c;
}

为了您的测试目的,我通过了下面的内容

纬度=22.808059

经度=77.522014

我的多边形

在此处输入图像描述

I have created code in php codeigniter, in my controller i have create two functions like below

public function checkLatLng(){
    $vertices_y = array(22.774,22.174,22.466,22.666,22.966,22.321);    // x-coordinates of the vertices of the polygon (LATITUDES)
    $vertices_x = array(70.190,70.090,77.118,77.618,77.418,77.757); // y-coordinates of the vertices of the polygon (LONGITUDES)
    $points_polygon = count($vertices_x)-1; 
    $longitude_x = $this->input->get("longitude");  // Your Longitude
    $latitude_y = $this->input->get("latitude");    // Your Latitude
    if ($this->is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y)){
        echo "Is in polygon!";
    }
    else
        echo "Is not in polygon";
}

Another function for check the lat-lng is below

public function is_in_polygon($points_polygon, $vertices_x, $vertices_y, $longitude_x, $latitude_y){
    $i = $j = $c = $point = 0;
    for ($i = 0, $j = $points_polygon ; $i < $points_polygon; $j = $i++) {
        $point = $i;
        if( $point == $points_polygon )
            $point = 0;
        if ( (($vertices_y[$point]  >  $latitude_y != ($vertices_y[$j] > $latitude_y)) && ($longitude_x < ($vertices_x[$j] - $vertices_x[$point]) * ($latitude_y - $vertices_y[$point]) / ($vertices_y[$j] - $vertices_y[$point]) + $vertices_x[$point]) ) )
            $c = !$c;
    }
    return $c;
}

For your testing purpose i passed below things

latitude=22.808059

longitude=77.522014

My Polygon

enter image description here

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文