Find Point in polygon PHP - 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 ?

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.

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;
}
?>

Above solution is not working as i expect, instead of using the above solution you can prefer below solutions
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>";
}
}
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);

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.

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

Here's a possible algorithm.
Define a new coordinate system with your point of interest at the center.
In your new coordinate system, convert all of your polygon vertices into polar coordinates.
Traverse the polygon, keeping track of the net change in angle, ∆θ. Always use the smallest possible value for each change in angle.
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.
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. :)

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;
}

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

Related

PHP - Location inside multiple polygons

How can i turn this in to supporting more polygons than just this one? I think of something with arrays but I’m lost this code works with one polygon but just can’t get any further this is what I got:
I would like it to check if the point is in polygon A or B or C and so on depending on how many polygons I got right now it only checking if point is inside polygon A.
class Point {
public $lat;
public $long;
function Point($lat, $long) {
$this->lat = $lat;
$this->long = $long;
}
}
//the Point in Polygon function
function pointInPolygon($p, $polygon) {
//if you operates with (hundred)thousands of points
set_time_limit(60);
$c = 0;
$p1 = $polygon[0];
$n = count($polygon);
for ($i=1; $i<=$n; $i++) {
$p2 = $polygon[$i % $n];
if ($p->long > min($p1->long, $p2->long)
&& $p->long <= max($p1->long, $p2->long)
&& $p->lat <= max($p1->lat, $p2->lat)
&& $p1->long != $p2->long) {
$xinters = ($p->long - $p1->long) * ($p2->lat - $p1->lat) / ($p2->long - $p1->long) + $p1->lat;
if ($p1->lat == $p2->lat || $p->lat <= $xinters) {
$c++;
}
}
$p1 = $p2;
}
// if the number of edges we passed through is even, then it's not in the poly.
return $c%2!=0;
}
$polygon = array(
new Point(54.992883, -9.860767),
new Point(54.992775, -9.860289),
new Point(54.992236,- 9.861030),
new Point(54.992473, -9.862007)
);

Detect Geo Coordinates within a Polygon in PHP

I have following set of Coordinates:
24.086589258228027, 51.6796875:
22.87744046489713, 52.6025390625:
22.715390019335942, 55.1953125:
21.90227796666864, 55.72265625:
19.89072302399691, 54.9755859375:
18.396230138028827, 48.4716796875:
21.657428197370653, 46.58203125
Now if I've a coordinate set ( single lat long set), how could I detect that this position lies inside that polygon region or not ?
This worked for me
$polyX = array();//horizontal coordinates of corners
$polyY = array();//vertical coordinates of corners
$zonal = "14.519780046326085,82.7490234375:8.276727101164045,88.9453125:3.7327083213358465,77.958984375:5.134714634014455,77.1240234375:7.493196470122287,76.552734375:10.18518740926906,75.498046875:11.781325296112277,75.05859375:13.539200668930814,80.2001953125:14.519780046326085,82.7490234375";
$zonalArray = explode(":",$zonal);
$polySides = count($zonalArray); //how many corners the polygon has
foreach($zonalArray as $eachZoneLatLongs)
{
$latlongArray = explode(",",$eachZoneLatLongs);
$polyX[] = $latlongArray[0];
$polyY[] = $latlongArray[1];
}
$vertices_x = $polyX; // x-coordinates of the vertices of the polygon
$vertices_y = $polyY; // y-coordinates of the vertices of the 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
#Following Points lie inside this region
$longitude_x = 6.927079 ; // x-coordinate of the point to test
$latitude_y = 79.861243; // y-coordinate of the point to test
#Following Points lie outside this region
#$longitude_x = 27.175015 ; // x-coordinate of the point to test
#$latitude_y = 78.042155; // 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-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;
}

Finding a point inside Polygon for Latitude and Longitude

Here is my code which I modified and took from this question Find Point in polygon PHP
And the vertices x and y form a rectangle..I am not still able to make it work even though the point y and x are inside polygon it's not displaying the correct result..What I am doing wrong here..
<?php
$vertices_x = array(45.007243,45.007243,46.3734,46.3734); // x-coordinates of the vertices of the polygon
$vertices_y = array(-75.007095,-72.506332,-72.506332,-75.007095,); // y-coordinates of the vertices of the polygon
$points_polygon = count($vertices_x);
$latitude_y = 45.5086699; // x-coordinate of the point to test
$longitude_x = -73.553992;
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;
}
?>
One issue is the initialization of the latitude_y and longitude_x variables:
latitude_y appears to contain the 'x' coordinate.
longitude_x appears to contain the 'y' coordinate.

How to find multiple points within a polygon

I am using the following code to test if a point is in a polygon, however I would like to make it work for multipliable points, but when I run it though a loop it fails to run correctly.
Polygon array = (52.62806176021313, 1.0546875),(52.435920583590125, 0.82672119140625),(52.26479561297205, 0.78277587890625),(52.24966453484505, 1.0986328125),(52.37224556866933, 1.34857177734375),(52.63973017532399, 1.46392822265625),(52.73795463681313, 1.25518798828125)
I split it up before hand.
Without Loop
$Latx = 52.5; //Y Point to test if inside
$LonX = 1.1; //X Point to test if inside
$VTX = $LON; //X array of polygon
$VTY = $LAT; //Y array of polygon
$POINTS = count($VTX) - 1; //number of polygon sides
//=====================================================
if (is_in_polygon($POINTS, $VTX, $VTY, $LonX, $LatY)){
echo "Is in polygon ($LatY,$LonX)";
echo "<br>";
}
else {
echo "Is not in polygon ($LatY,$LonX)";
}
echo "<br>"
function is_in_polygon($POINTS, $VTX, $VTY, $LonX, $LatY)
{
$i = $j = $c = 0;
for ($i = 0, $j = $POINTS ; $i < $POINTS; $j = $i++) {
if ((($VTY[$i] > $LatY != ($VTY[$j] > $LatY)) &&
($LonX < ($VTX[$j] - $VTX[$i]) * ($LatY - $VTY[$i]) /
($VTY[$j] - $VTY[$i]) + $VTX[$i]) ) )
$c = !$c;
}
return $c;
}
Trying with a Loop
for ($x=0; $x<=1000; $x++) {
$QU="SELECT lat,lon FROM DBTable LIMIT $x,1";
$RT=mysql_query($QU,$db);
if (!$RT) {
die("Invalid query: " . mysql_error());
}
while ($row = mysql_fetch_assoc($RT)){
$LonX[$x]=$row["lat"];
$LatY[$x]=$row["lon"];
if (is_in_polygon($POINTS, $VTX, $VTY, $LonX[$x], $LatY{$x])){
echo "Is in polygon ($LatY[$x],$LonX[$x])";
echo "<br>";
}
else echo "Is not in polygon ($LatY[$x],$LonX[$x])";
echo "<br>"
}
}

Point-in-Polygon PHP Errors

I am using a point-in-polygon check in php, but I am getting major errors - as in points that are not in the polygon are coming up as inside.
My basic functions are typed out below (found here, modified from a class to a simple function: http://www.assemblysys.com/dataServices/php_pointinpolygon.php). The only thing I can think of is some kind of rounding errors someplace?
As one example, I am trying to determine whether a point is in Central Park, a simple square, but I get positives from points outside the park.
Thanks for any insight,
-D
$central_park = array('40.768109,-73.981885', '40.800636,-73.958067', '40.796900,-73.949184', '40.764307,-73.972959');
$test_points = array('40.7546755,-73.9758343', '40.764405,-73.973951', '40.7594219,-73.9733896', '40.768137896318315,-73.9814176061', '40.7982394,-73.9523718', '40.685135,-73.973562', '40.7777062,-73.9632719', '40.764109,-73.975948', '40.758908,-73.9813128', '40.7982782,-73.9525028', '40.7463886,-73.9817654', '40.7514592,-73.9760405', '40.7514592,-73.9760155', '40.7514592,-73.9759905', '40.7995079,-73.955431', '40.7604354,-73.9758778', '40.7642878,-73.9730075', '40.7655335,-73.9800484', '40.7521678,-73.9777978', '40.7521678,-73.9777728')
function pointStringToCoordinates($pointString) {
$coordinates = explode(",", $pointString);
return array("x" => trim($coordinates[0]), "y" => trim($coordinates[1]));
}
function isWithinBoundary($point,$polygon){
$point = pointStringToCoordinates($point);
$vertices = array();
foreach ($polygon as $vertex) {
$vertices[] = pointStringToCoordinates($vertex);
}
// Check if the point 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
$result = TRUE;
}
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 point is on the polygon boundary (other than horizontal)
$result = TRUE;
}
if ($vertex1['x'] == $vertex2['x'] || $point['x'] <= $xinters) {
$intersections++;
}
}
}
// If the number of edges we passed through is even, then it's in the polygon.
if ($intersections % 2 != 0) {
$result = TRUE;
} else {
$result = FALSE;
}
return $result;
}
There were a couple of problems with the original code, closing the polygons fixed one of these but the code also gave incorrect results for points on the boundary lines of the polygon. The if..else statement at the end of the isWithinBoundary function only needs to be executed if a point IS NOT on a boundary. As a point on the boundary won't actually intersect the boundary then the count of intersections would always be odd for a boundary point meaning that this final IF statement would always return FALSE for a boundary point.
I have tweaked the code a little, this version is a self contained page that has some simple test data and it outputs the decisions being made.
<?php
$myPolygon = array('4,3', '4,6', '7,6', '7,3','4,3');
$test_points = array('0,0','1,1','2,2','3,3','3.99999,3.99999','4,4','5,5','6,6','6.99999,5.99999','7,7');
echo "The test polygon has the co-ordinates ";
foreach ($myPolygon as $polypoint){
echo $polypoint.", ";
}
echo "<br/>";
foreach ($test_points as $apoint)
{
echo "Point ".$apoint." is ";
if (!isWithinBoundary($apoint,$myPolygon))
{
echo " NOT ";
}
echo "inside the test polygon<br />";
}
function pointStringToCoordinates($pointString)
{
$coordinates = explode(",", $pointString);
return array("x" => trim($coordinates[0]), "y" => trim($coordinates[1]));
}
function isWithinBoundary($point,$polygon)
{
$result =FALSE;
$point = pointStringToCoordinates($point);
$vertices = array();
foreach ($polygon as $vertex)
{
$vertices[] = pointStringToCoordinates($vertex);
}
// Check if the point 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']))
{
// This point is on an horizontal polygon boundary
$result = TRUE;
// set $i = $vertices_count so that loop exits as we have a boundary point
$i = $vertices_count;
}
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'])
{ // This point is on the polygon boundary (other than horizontal)
$result = TRUE;
// set $i = $vertices_count so that loop exits as we have a boundary point
$i = $vertices_count;
}
if ($vertex1['x'] == $vertex2['x'] || $point['x'] <= $xinters)
{
$intersections++;
}
}
}
// If the number of edges we passed through is even, then it's in the polygon.
// Have to check here also to make sure that we haven't already determined that a point is on a boundary line
if ($intersections % 2 != 0 && $result == FALSE)
{
$result = TRUE;
}
return $result;
}
?>
You've probably spotted and fixed these problems yourself by now, but this might help other people who find and use this code.
Well, once again I find myself foolishly answering my own foolish question.
I was not closing the polygon by appending the first coordinate to the last spot in the array. This caused a very distinctive look of the mismatched points - they all appeared to be spilling out of the polygon from the unbounded end.
So this -
$central_park = array('40.768109,-73.981885', '40.800636,-73.958067', '40.796900,-73.949184', '40.764307,-73.972959');
Should be this -
$central_park = array('40.768109,-73.981885', '40.800636,-73.958067', '40.796900,-73.949184', '40.764307,-73.972959', '40.764307,-73.972959');
And that's how I was dumb today. Thank you.
The problem with your code is that the variable $result is overwritten by this code
if ($intersections % 2 != 0) {
$result = TRUE;
} else {
$result = FALSE;
}
even if $result == TRUE here:
if ($xinters == $point['x']) {
$result = TRUE;
}
In the original code there was an 'return' which was correct instead of your is wrong.

Categories