Find Point in polygon PHP

后端 未结 8 774
半阙折子戏
半阙折子戏 2020-11-30 19:34

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:

         


        
相关标签:
8条回答
  • 2020-11-30 20:27

    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.

    0 讨论(0)
  • 2020-11-30 20:32

    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:

    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.

    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
    
    0 讨论(0)
提交回复
热议问题