Find Point in polygon PHP

后端 未结 8 773
半阙折子戏
半阙折子戏 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:10

    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);
    
    0 讨论(0)
  • 2020-11-30 20:11

    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;
    }
    ?>
    
    0 讨论(0)
  • 2020-11-30 20:17

    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.

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

    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

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

    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;
    }
    
    0 讨论(0)
  • 2020-11-30 20:25

    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. :)

    0 讨论(0)
提交回复
热议问题