Python - How to Check Point in a Polygon? - python

Below is my coding to check whether a point does exist in a polygon, but the result is False, could you help me?
# Importing Libraries
import shapefile
from shapely.geometry import shape, Point
# Opening the Vector Map
shp_path = "ADMINISTRASIDESA.shp"
# read your shapefile
r = shapefile.Reader(shp_path)
# get the shapes
shapes = r.shapes()
# build a shapely polygon from your shape
polygon = shape(shapes[0])
print(polygon)
# result :
# POLYGON ((106.701396169 -6.34824620099992, 106.7015891380001 -6.349042349999891,
# 106.701707619 -6.349551940999955, 106.701828711 -6.350008714999912, ... ))
def checkpo(lon, lat):
# build a shapely point from your geopoint
point = Point(lon, lat)
# the contains function does exactly what you want
return polygon.contains(point)
mygeolon = 106.701396169
mygeolat = -6.34824620099992
print(checkpo(mygeolon, mygeolat))
# why result = False ???
# create point
point = Point(mygeolon,mygeolat)
# check if polygon contains point
print(polygon.contains(point))
# why result = False ???
# check if a point is in the polygon
print(point.within(polygon))
# why result = False ???
I already set the longitude and latitude that listed in the polygon,
but when it is checked, it returns False ???
Please help me.

According to Shapely documentation :
object.contains(other)
Returns True if no points of other lie in the exterior of the object and at least one point of the interior of other lies in the interior of object.
(...)
A line’s endpoints are part of its boundary and are therefore not contained.
What you need is object.covers.
Returns True if every point of other is a point on the interior or boundary of
object. This is similar to object.contains(other) except that this
does not require any interior points of other to lie in the interior
of object.
https://shapely.readthedocs.io/en/latest/manual.html

Related

Convert mesh to polygon in python

I have a mesh and want to convert it into a polygon. I did some google search and found most answer on converting polygon to mesh. I want to do the opposite.Is there any library or any idea on how to achieve it
Well you can use the Python FME library to take input as a mesh object and return a polygon
import fmeobjects
class MeshToPolygons(object):
def input(self, feature):
mesh = feature.getGeometry()
if isinstance(mesh, fmeobjects.FMEMesh):
vertices = mesh.getVertices()
for part in mesh:
indices = part.getVertexIndices()
if indices:
boundary = fmeobjects.FMELine([vertices[i] for i in indices])
feature.setGeometry(fmeobjects.FMEPolygon(boundary))
self.pyoutput(feature)
If the above doesn't help, you can also check out the python TriMesh library. You could load the object as mesh using
trimesh.load(file_obj, file_type=None, resolver=None, force=None, **kwargs)
Return type: Trimesh, Path2D, Path3D, Scene
Returns: geometry – Loaded geometry as trimesh classes
Now convert the mesh object into a sequence of connected points. After that you can use
trimesh.path.polygons.paths_to_polygons(paths, scale=None)
Return type: (p,) list
Returns: polys – Filled with Polygon or None
Hope it helps

splitting circle into two using LineString Python Shapely

I have created a circle using Shapely and would like to split it into two using LineString.
I created the circle as follows
from functools import partial
import pyproj
from shapely import geometry
from shapely.geometry import Point, Polygon, shape, MultiPoint, LineString, mapping
from shapely.ops import transform, split
radius = 92600
lon = 54.08
lat = 17.05
local_azimuthal_projection = "+proj=aeqd +R=6371000 +units=m +lat_0={} +lon_0={}".format(
lat, lon
)
wgs84_to_aeqd = partial(
pyproj.transform,
pyproj.Proj("+proj=longlat +datum=WGS84 +no_defs"),
pyproj.Proj(local_azimuthal_projection),
)
aeqd_to_wgs84 = partial(
pyproj.transform,
pyproj.Proj(local_azimuthal_projection),
pyproj.Proj("+proj=longlat +datum=WGS84 +no_defs"),
)
center = Point(float(lon), float(lat))
point_transformed = transform(wgs84_to_aeqd, center)
buffer = point_transformed.buffer(radius)
# Get the polygon with lat lon coordinates
circle_poly = transform(aeqd_to_wgs84, buffer)
For the line Splitter I have the following:
splitter = LingString([Point(54.79,16.90), Point(53.56,16.65)])
Now I want to see the two split shapes so I used split function.
result = split(circle_poly, splitter)
However, this only results the same circle and not two shapes.
At the end I would like to use one section of the split to form another shape.
To split a circle or a polygon, you can use spatial difference operation with another polygon. Shapely does not allow the use of line to do so.
"Shapely can not represent the difference between an object and a lower dimensional object (such as the difference between a polygon and a line or point) as a single object."
See document:
In your case, you can build two polygons that have the line as the common edges.
Make sure that the 2 polygons together are big enough to cover the whole polygon you are splitting. Then you use that polygons to do the job.
If you want crude results from the difference operation,
you can turn the line into a slim polygon by buffer operation, and use it.
For the second approach, here is the relevant code:
the_line = LineString([(54.95105, 17.048144), (53.40473921, 17.577181)])
buff_line = the_line.buffer(0.000001) #is polygon
# the `difference` operation between 2 polygons
multi_pgon = circle_poly.difference(buff_line)
The result is a multi-polygon geometry object.

Getting (some) points of a polygon

I am trying to grab the vertices from a polygon and do some stuff to them to recreate the polygon in a new location/rotation (essentially this: https://community.esri.com/thread/46497). The example code below is not exactly what I am doing, but showcases the issue. The code would work except that after it grabs the last vertex of the polygon, it throws an error message which breaks the script and stops everything else from running to draw the new polygon. Otherwise, if I go through my code line-by-line I can continue on and create the new polygon feature:
AttributeError: 'NoneType' object has no attribute 'X'
Is there a way that I can use the loop to run through all except the "last" vertex, which either has an issue or doesn't exist?
import arcpy
import os
import random
import math
pa = 'protected_areas' # protected areas
sr = arcpy.Describe(pa).spatialReference # spatial ref
sa = 'study_area' # study area
x = [] # placeholder
with arcpy.da.SearchCursor(pa,'SHAPE#',spatial_reference=sr) as cursor: # for each polygon
for row in cursor:
centroid = row[0].centroid # calculate centroid
poly = row[0]
for part in poly: # for each polygon part
for pnt in part: # for each vertex
x.append(pnt.X)
You can iterate over an index and skip the las element, changing
for pnt in part: # for each vertex
x.append(pnt.X)
To
for k in range(len(pnt)-1): # for each vertex
x.append(pnt[k].X)
Hope it helps

Find indices of raster cells that intersect with a polygon

I want to get a list of indices (row,col) for all raster cells that fall within or are intersected by a polygon feature. Looking for a solution in python, ideally with gdal/ogr modules.
Other posts have suggested rasterizing the polygon, but I would rather have direct access to the cell indices if possible.
Since you don't provide a working example, it's bit unclear what your starting point is. I made a dataset with 1 polygon, if you have a dataset with multiple but only want to target a specific polygon you can add SQLStatement or where to the gdal.Rasterize call.
Sample polygon
geojson = """{"type":"FeatureCollection",
"name":"test",
"crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}},
"features":[
{"type":"Feature","properties":{},"geometry":{"type":"MultiPolygon","coordinates":[[[[-110.254,44.915],[-114.176,37.644],[-105.729,36.41],[-105.05,43.318],[-110.254,44.915]]]]}}
]}"""
Rasterizing
Rasterizing can be done with gdal.Rasterize. You need to specify the properties of the target grid. If there is no predefined grid these could be extracted from the polygon itself
ds = gdal.Rasterize('/vsimem/tmpfile', geojson, xRes=1, yRes=-1, allTouched=True,
outputBounds=[-120, 30, -100, 50], burnValues=1,
outputType=gdal.GDT_Byte)
mask = ds.ReadAsArray()
ds = None
gdal.Unlink('/vsimem/tmpfile')
Converting to indices
Retrieving the indices from the rasterized polygon can be done with Numpy:
y_ind, x_ind = np.where(mask==1)
Clearly Rutger's solution above is the way to go with this, however I will leave my solution up. I developed a script that accomplished what I needed with the following:
Get the bounding box for each vector feature I want to check
Use the bounding box to limit the computational window (determine what portion of the raster could potentially have intersections)
Iterate over the cells within this part of the raster and construct a polygon geometry for each cell
Use ogr.Geometry.Intersects() to check if the cell intersects with the polygon feature
Note that I have only defined the methods, but I think implementation should be pretty clear -- just call match_cells with the appropriate arguments (ogr.Geometry object and geotransform matrix). Code below:
from osgeo import ogr
# Convert projected coordinates to raster cell indices
def parse_coords(x,y,gt):
row,col = None,None
if x:
col = int((x - gt[0]) // gt[1])
# If only x coordinate is provided, return column index
if not y:
return col
if y:
row = int((y - gt[3]) // gt[5])
# If only x coordinate is provided, return column index
if not x:
return row
return (row,col)
# Construct polygon geometry from raster cell
def build_cell((row,col),gt):
xres,yres = gt[1],gt[5]
x_0,y_0 = gt[0],gt[3]
top = (yres*row) + y_0
bottom = (yres*(row+1)) + y_0
right = (xres*col) + x_0
left = (xres*(col+1)) + x_0
# Create ring topology
ring = ogr.Geometry(ogr.wkbLinearRing)
ring.AddPoint(left,bottom)
ring.AddPoint(right,bottom)
ring.AddPoint(right,top)
ring.AddPoint(left,top)
ring.AddPoint(left,bottom)
# Create polygon
box = ogr.Geometry(ogr.wkbPolygon)
box.AddGeometry(ring)
return box
# Iterate over feature geometries & check for intersection
def match_cells(inputGeometry,gt):
matched_cells = []
for f,feature in enumerate(inputGeometry):
geom = feature.GetGeometryRef()
bbox = geom.GetEnvelope()
xmin,xmax = [parse_coords(x,None,gt) for x in bbox[:2]]
ymin,ymax = [parse_coords(None,y,gt) for y in bbox[2:]]
for cell_row in range(ymax,ymin+1):
for cell_col in range(xmin,xmax+1):
cell_box = build_cell((cell_row,cell_col),gt)
if cell_box.Intersects(geom):
matched_cells += [[(cell_row,cell_col)]]
return matched_cells
if you want to do this manually you'll need to test each cell for:
Square v Polygon intersection and
Square v Line intersection.
If you treat each square as a 2d point this becomes easier - it's now a Point v Polygon problem. Check in Game Dev forums for collision algorithms.
Good luck!

Given latitude/longitude say if the coordinate is within continental US or not

I want to check if a particular latitude/longitude is within continental US or not. I don't want to use Online APIs and I'm using Python.
I downloaded this shapefile
from shapely.geometry import MultiPoint, Point, Polygon
import shapefile
sf = shapefile.Reader("cb_2015_us_nation_20m")
shapes = sf.shapes()
fields = sf.fields
records = sf.records()
points = shapes[0].points
poly = Polygon(points)
lon = -112
lat = 48
point = Point(-112, 48)
poly.contains(point)
#should return True because it is in continental US but returns False
The sample lon, lat is within US boundary but poly.contains returns False.
I'm not sure what the problem is and how to solve the issue so that I can test if a point is within continental US.
I ended up checking if lat/lon was in every state instead of check in continental U.S., if a point is in one of the states, then it is in continental U.S..
from shapely.geometry import MultiPoint, Point, Polygon
import shapefile
#return a polygon for each state in a dictionary
def get_us_border_polygon():
sf = shapefile.Reader("./data/states/cb_2015_us_state_20m")
shapes = sf.shapes()
#shapes[i].points
fields = sf.fields
records = sf.records()
state_polygons = {}
for i, record in enumerate(records):
state = record[5]
points = shapes[i].points
poly = Polygon(points)
state_polygons[state] = poly
return state_polygons
#us border
state_polygons = get_us_border_polygon()
#check if in one of the states then True, else False
def in_us(lat, lon):
p = Point(lon, lat)
for state, poly in state_polygons.iteritems():
if poly.contains(p):
return state
return None
I ran your code and plotted the polygon. It looked like this:
If you had run it with this code:
import geopandas as gpd
import matplotlib.pyplot as plt
shapefile = gpd.read_file("path/to/shapes.shp")
shapefile.plot()
plt.show()
# credit to https://stackoverflow.com/a/59688817/1917407
you would have seen this:
So, 1, you're not looking at the CONUS, and 2, your plot is borked. Your code works though and will return True with the geopandas plot.

Categories

Resources