Calculate the centroid of a rectangle geometry in python - python

I have the following Polygon geometry. When I calculate the centroid, I get an invalid / inaccurate POINT. I am using geopandas centroid to calculate the point.
https://geopandas.org/en/stable/docs/reference/api/geopandas.GeoSeries.centroid.html
import shapely
from shapely import wkt
from shapely.geometry import box
import geopandas as gpd
g = "POLYGON ((-96.8115234375 32.87109375, -96.8115234375 -96.767578125, 32.8271484375 -96.767578125, 32.8271484375 32.87109375, -96.8115234375 32.87109375))"
print(wkt.loads(g).centroid)
POINT (-31.9921875 -31.9482421875)
How do I calculate the centroid POINT lat, long coordinates of the box? The shape of the Polygon is rectangle.

Your code is fine, your polygon is not and does not represents a rectangle area in Dallas, TX. Let's split it into vertices to make it apparent:
g = "POLYGON ((-96.8115234375 32.87109375,
-96.8115234375 -96.767578125,
32.8271484375 -96.767578125,
32.8271484375 32.87109375,
-96.8115234375 32.87109375))"
The first point is good and is indeed in Dallas. The second point has wrong latitude, -96.7... (it is south of South pole :) - however Shapely does not care and accepts it). Third point has wrong both latitude and longitude, etc. Apparently, latitudes and longitudes got mixed up here.

Related

Calculate distance between LineString and Point in meters

I have LineString and Point, and I want to calculate distance between them in meters:
line = LINESTRING (7.301606 52.5602366, 7.300065099999999 52.5587741)
point = POINT (8.02 52.303333)
I use: line.distance(point). I got a distance, but I don't know how to convert to meters or km. I am using geopandas, and I read that unit is CRS. Any help will be appreciated.
as per comments you need to specify the CRS I am using geopandas, and I read that unit is CRS. I assume by this statement you mean WSG84 CRS, which is EPSG:4326
given limitation of geopandas to have only one geometry column per GeoDataFrame have put LINESTRING and POINT into separate data frames
project from WSG84 onto UTM CRS https://en.wikipedia.org/wiki/Universal_Transverse_Mercator_coordinate_system. This then means co-ordinates are expressed in meters. This will not work if LINESTRING and POINT are in different UTM zones
then it's exceptionally simple to use https://geopandas.readthedocs.io/en/latest/docs/reference/api/geopandas.GeoSeries.distance.html
import shapely.wkt
import geopandas as gpd
gdfl = gpd.GeoDataFrame(geometry=[shapely.wkt.loads("LINESTRING (7.301606 52.5602366, 7.300065099999999 52.5587741)")], crs="EPSG:4326")
gdfp = gpd.GeoDataFrame(geometry=[shapely.wkt.loads("POINT (8.02 52.303333)")], crs="EPSG:4326")
utm = gdfl.estimate_utm_crs()
gdfl.to_crs(utm).distance(gdfp.to_crs(utm))
output
56592.878178

How to know if a coordinate is within a polygon in shape file not working?

I have coordinates (lat and lng) in an excel document. I have a shapefile which contains all the different Canada provinces shapes. I would like to be able to generate a new field in excel in order to classify the different coordinates into the different Canada provinces. I tried the below code, but it is not working.
import fiona
import shapely.geometry
with fiona.open(r"D:\Users\Jonathan\Desktop\CRA-Project v2\Census Division\lcd_000b16a_e.shp") as fiona_collection:
shapefile_record = fiona_collection.next()
# Use Shapely to create the polygon
shape = shapely.geometry.asShape(shapefile_record['geometry'])
#print(shape)
point = shapely.geometry.Point(46.362914,-63.503809) # longitude, latitude
# Alternative: if point.within(shape)
if shape.contains(point):
print("Found shape for point.")
Update 1:
point = shapely.geometry.Point(46.362914,-63.503809)
Polygon:
Link
Update Solution:
I am updating this post because I found the solution and hopefully it can help someone!
If you are using shapefiles, there is a projection associated with
it (documentation)
Review the documentation and identify which
projection it is using. For example: In Canada it is Lambert
conformal conic.
Convert your lat/long to the projection equivalency
Loop through the shapefile to identify if the new lat/long
equivalent is within a polygon/multipolygon. You can do this with
python!
There are several issues with this. First, your shapefile (Multipolygon) seems to be in a different projection so in order to work in longitude/latitude coordinates, one needs to transform it. Moreover, even after the transformation, the x-coordinate is the longitude, thus the coordinates of the point you are testing against should be swapped. An example might look as shown below. The input projection is assumed to be PCS_Lambert_Conformal_Conic (EPSG:3347) - this is specified in the accompanying prj file.
from functools import partial
import sys
import fiona
from shapely.geometry import Point, Polygon, asShape
from shapely.ops import transform
from shapely.wkt import loads
import pyproj
project = partial(
pyproj.transform,
pyproj.Proj(init='epsg:3347'),
pyproj.Proj(init='epsg:4326'))
P = Point(-63.503809, 46.362914)
with fiona.open(sys.argv[1]) as F:
for idx,feature in enumerate(F):
G = transform(project, asShape(feature['geometry']))
if G.contains(P):
print(feature['properties'])
break
This produces:
OrderedDict([('CDUID', '1102'), ('CDNAME', 'Queens'), ('CDTYPE', 'CTY'), ('PRUID', '11'), ('PRNAME', 'Prince Edward Island / Île-du-Prince-Édouard')])
i.e., it finds the coordinates within the Prince Edward Island.

How to convert Earth Centered Inertial (ECI) coordinates to Earth Centered Earth Fixed (ECEF) AstroPy? Other?

I have position (x,y,z) and velocity (Vx,Vy,Vz) vectors in Earth Centered Inertial Coordinates (ECI) for a satellite orbit, and ultimately want to end up with geodetic coordinates (Latitude, Longitude, & Altitude).
According to this other Stack Overflow question it seems that I need to convert to Earth Centered Earth Fixed (ECEF) coordinates as an intermediate step (so ECI --> ECEF --> Lat/Lon/Alt).
I know ECI and ECEF share the same origin point (the center of mass of Earth) and the same z-axis that points to the North Pole. However, I am not sure what actual equations or adjustments I need to do to convert ECI to ECEF.
Otherwise, if anyone knows of any canned conversions on Astropy or something similar that would be even better. (I haven't seen ECI as an option on Astro Py or Space Py).
Here is the code I am using to generate my orbit and get the position and velocity vectors.
from scipy.constants import kilo
import orbital
from orbital import earth, KeplerianElements, Maneuver, plot, utilities
from orbital.utilities import Position, Velocity
import matplotlib.pyplot as plt
import numpy as np
orbitPineapple = KeplerianElements.with_period(5760, body=earth,
e=0.05, i=(np.deg2rad(0)), arg_pe=(np.deg2rad(30)))
plot(orbitPineapple)
plt.show()
print(orbitPineapple.r)
print(orbitPineapple.v)
Out:
Position(x=5713846.540659178, y=3298890.8383577876, z=0.0)
Velocity(x=-3982.305479346745, y=6897.555421488496, z=0.0)
There are a number of different Earth Centered Inertial frames, and the answer depends on which one you have your coordinates in.
The most common is so-called J2000; which is defined w.r.t to the orientation of the Earth on Jan 1st 2000. Another common one is GCRF, which is almost the same (to within 80 milli arcseconds).
If it’s either of those two, you should be able to create an astropy EarthLocation object and access the lat, lon and height attributes like so
from astropy import coordinates as coord
from astropy import units as u
from astropy.time import Time
now = Time('2017-09-27 12:22:00')
# position of satellite in GCRS or J20000 ECI:
cartrep = coord.CartesianRepresentation(x=5713846.540659178,
y=3298890.8383577876,
z=0., unit=u.m)
gcrs = coord.GCRS(cartrep, obstime=now)
itrs = gcrs.transform_to(coord.ITRS(obstime=now))
loc = coord.EarthLocation(*itrs.cartesian.cartrep )
print(loc.lat, loc.lon, loc.height)

Obtaining the center of a WKT polygon

I'm using pandas, and a dataset I obtained has a location column in a WKT format. For example:
hospital.get_value(1,'WKT')
POLYGON ((-58.4932 -34.5810,-58.4925 -34.5815,-58.4924 -34.5817))
There's a lot more points and with bigger precision in this example, but I shortened it for illustrative purposes. Also, I don't know whether it is a WKT or just a string. How do I obtain the center of this polygon so I can use it as a coordinate? Thanks in advance.
You almost have WKT, except that a polygons' linear ring needs to be closed.
Shapely has a .centroid property to get the center point:
from shapely import wkt
g = wkt.loads(
'POLYGON ((-58.4932 -34.5810,-58.4925 -34.5815,-58.4924 -34.5817,-58.4932 -34.5810))')
print(g.centroid) # POINT (-58.49270000000001 -34.5814)
print(g.centroid.coords[0]) # (-58.492700000000006, -34.581399999999995)

Intersect two shapely polygons on the Earth projection

as i know, shapely use only cartesian coordinate system. I have two point on the earth with lat and lon coordinates. I need create buffer with 1km radius around this two points and find polygon, where this buffers intersect.
But construstion
buffer = Point(54.4353,65.87343).buffer(0.001) create simple circle, but in projection on the Earth it becomes ellipse, but i need two real circle with 1 km radius.
I think, i need convert my buffers into new projection and then intersect it, but dont now how correct do it.
You need to do what you say. For that, you will need to use a library that handles projections (pyproj is the choice here). There is a similar question in Geodesic buffering in python
import pyproj
from shapely.geometry import MultiPolygon, Polygon, Point
from shapely.ops import transform as sh_transform
from functools import partial
wgs84_globe = pyproj.Proj(proj='latlong', ellps='WGS84')
def point_buff_on_globe(lat, lon, radius):
#First, you build the Azimuthal Equidistant Projection centered in the
# point given by WGS84 lat, lon coordinates
aeqd = pyproj.Proj(proj='aeqd', ellps='WGS84', datum='WGS84',
lat_0=lat, lon_0=lon)
#You then transform the coordinates of that point in that projection
project_coords = pyproj.transform(wgs84_globe, aeqd, lon, lat)
# Build a shapely point with that coordinates and buffer it in the aeqd projection
aeqd_buffer = Point(project_coords).buffer(radius)
# Transform back to WGS84 each coordinate of the aeqd buffer.
# Notice the clever use of sh_transform with partial functor, this is
# something that I learned here in SO. A plain iteration in the coordinates
# will do the job too.
projected_pol = sh_transform(partial(pyproj.transform, aeqd, wgs84_globe),
aeqd_buffer)
return projected_pol
The function point_buff_on_globe will give you a polygon in lat lon that is the result of buffering the given point in the Azimuthal Equidistant Projection centered in that point (the best you can do with your requirements. Two observations:
I don't remember the units of the radius argument. I think is in meters, so if you need a 10 km buffer, you will need to pass it 10e3. But please, check it!
Beware of using this with radius to wide or points that are to far away from each other. Projections work well when the points are near to the point you are centering the projection.

Categories

Resources