I'm using the Proj4rb gem to convert latitude and longitude coordinates to a point in Robinson projection. This will be used to figure out where to place a pin on a map image.
An example I'm trying (for New York) is:
robinson_projection = Proj4::Projection.new('+proj=robin +lon_0=0 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs')
source_point = Proj4::Point.new(40.7142, -74.0064)
source_projection = Proj4::Projection.new("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")
projected_point = source_projection.transform(robinson_projection, source_point)
This is throwing the following exception:
#<Proj4::LatitudeOrLongitudeExceededLimitsError: latitude or longitude exceeded limits>
What am I doing wrong?
I see two errors, curious if one is the cause:
New York has : lat/lon: 40.713956,-74.00528
First error:
New York has a negative longitude coordinate, your wrote 74.0064
Second:
The order of long, lat in Point.new(x,y) that should be long, lat, not vice versa
Please check with docu!
so correct is:
source_point = Proj4::Point.new(-74.0064, 40.7142);
The problem is within your source point (lat, lng). Try this:
robinson_projection = Proj4::Projection.new('+proj=robin +lon_0=0 +x_0=0 +y_0=0 +a=6371000 +b=6371000 +units=m +no_defs')
lat = 40.7142
lon = -74.0064
source_point = Proj4::Point.new(Math::PI * lon.to_f / 180,
Math::PI * lat.to_f / 180)
source_projection = Proj4::Projection.new("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs")
projected_point = source_projection.transform(robinson_projection, source_point)
Related
I got a dataframe with the following columns Name (string), size (num), latitude (num), longitude (num), geometry (shapely.geometry.point.Point).
When i'm plotting my points on a map and are trying to annotate each point the annotation is not shown at all. My guess is that this is due to the projection im using.
Here are the lines of codes im running:
import geopandas as gpd
import geoplot as gplt
proj = gplt.crs.AlbersEqualArea()
fig, ax = plt.subplots(figsize=(10, 10), subplot_kw={'projection': proj})
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.longitude, df.latitude))
gplt.pointplot(gdf, hue='size', s=15, ax=ax, cmap=palette, legend=True, zorder=10)
for idx, row in gdf.iterrows():
plt.annotate(s=row['Name'], xy=[row['latitude'],row['longitude']])
plt.show()
You need coordinate transformation in
plt.annotate(s=row['Name'], xy=[row['latitude'],row['longitude']])
The transformation should be
xtran = gplt.crs.ccrs.AlbersEqualArea()
Replace that line with
x, y = xtran.transform_point(row['longitude'], row['latitude'], ccrs.PlateCarree())
plt.annotate( s=row['Name'], xy=[x, y] )
I am struggling to save the area of a polygon to the database. I would like to be able to calculate the area, convert it to the right units and finally save it in the table, but until now I have not found the correct way to do it.
So far I have the following model, where I calculate and save the area in square degrees.
class Parcel(models.Model):
srid = settings.SRID
geometry = models.GeometryField(srid=srid, geography=True)
area = models.FloatField(blank=False, null=True)
def save(self, *args, **kwargs):
self.area = self.geometry.area
super(Parcel, self).save()
In order to use the area in acres I do elsewhere:
p = Parcel.objects.annotate(area_=Area('geometry')).get(id=parcel_id)
parcel_area = p.area_.standard/1000
But this operation is a bit heavy since it calculates the area for all parcels and after that is gets the desired parcel and also it does not use or save the area in acres in the database.
I have seen that some people transform to an srid that has the right units but that would not work for me because my polygons are from all around the earth.
Thanks!
I think the best way to do it is to calculate the area in m² based on a metric coordinate system like utm.
Here is a function to calculate it:
def get_sqm_by_wgs84_polygon(geom: GEOSGeometry) -> float:
def get_utm_by_wgs_84(cent_lon, cent_lat):
utm_zone_num = int(math.floor((cent_lon + 180) / 6) + 1)
utm_zone_hemi = 6 if cent_lat >= 0 else 7
utm_epsg = 32000 + utm_zone_hemi * 100 + utm_zone_num
return utm_epsg
lon = geom.centroid.x
lat = geom.centroid.y
epsg_code = get_utm_by_wgs_84(lon, lat)
transformed_geom = geom.transform(epsg_code, clone=True)
area = transformed_geom.area
return area
In your Model you can save it on creation:
class Parcel(models.Model):
srid = settings.SRID
geometry = models.GeometryField(srid=srid, geography=True)
area = models.FloatField(blank=False, null=True)
def save(self, *args, **kwargs):
self.area = get_sqm_by_wgs84_polygon(self.geometry)
super(Parcel, self).save()
This method only works for WGS84 (EPSG:4326) as input. From degrees to meters.
With this little piece of code I've made it possible to rotate the 'monster' towards the avatar but if the avatar is behind the 'monster', the 'monster' is facing away from the avatar. (Pic's below)
Note: the white numbers are the value of m_RotationAngle
DOUBLE2 mousePos = GAME_ENGINE->GetMousePosition();
double xDiff = m_ActPtr->GetPosition().x - mousePos.x;
double yDiff = m_ActPtr->GetPosition().y - mousePos.y;
m_RotationAngle = atan(yDiff, xDiff);
m_ActPtr->SetAngle(m_RotationAngle);
I've tried to fix it with:
if (diff.x < 0)
{
m_RotationAngle = -atan(diff.y / diff.x);
//also tried following but gave and error:
//m_RotationAngle = tan(diff.y / diff.x);
}
else
{
m_RotationAngle = atan(diff.y / diff.x);
}
But this gave the following output:
You are probably looking for atan2(yDiff, xDiff); which computes the arc tangent of yDiff/xDiff using the signs of arguments to determine the correct quadrant, instead of atan (which also require only one parameter).
Be aware that the result is in the range [-π ; +π] radians, not degrees.
I have image of the city, how i can get longitude/latitude for the points that i add to the image if i know 3 points like
Point1XRelative = "-18340651.0304568";
Point1YRelative = "14945227.3984772";
Point2XRelative = "-3960915.94162438";
Point2YRelative = "-7933119.6827411";
Point3XRelative = "4901426.10152285";
Point3YRelative = "13585796.8781726";
Point1XWorld = "53.1186547";
Point1YWorld = "29.2392344";
Point2XWorld = "52.6341388";
Point2YWorld = "29.7438198";
Point3XWorld = "53.0900105";
Point3YWorld = "30.0548051";
I have algrithm that can convert only for the plane and when i convert from the long/lat to x y they converts with offset.
Please advice me how i can resolve this problem.
It also depends on the zoom level. I think you will find what you need here.
I'm writing a relatively simple app in which I'm using RGeo to calculate distances between points on the globe. I'm doing this using a RGeo::Geographic.spherical_factory.
Now I want to be able to create a new point by adding an offset to an existing point. For example, I would like to be able to find the longitude and latitude of the point 500 metres north and 200 metres east of an existing point.
How should I go about doing this?
Maybe this helps:
a = move_point(-72.4861, 44.1853, 0, 0) # POINT (-72.4861 44.18529999999999)
b = move_point(-72.4861, 44.1853, 100, 0) # POINT (-72.48520168471588 44.18529999999999)
c = move_point(-72.4861, 44.1853, 0, 100) # POINT (-72.4861 44.18594416889434)
puts a.distance(b)
puts a.distance(c)
Which gives you
99.99999999906868
99.99999999906868
Note: I'm not sure what the different between RGeo::Geographic.simple_mercator_factory and RGeo::Geographic.spherical_factory would be here.
require 'rgeo'
def move_point(lon, lat, x_offset_meters, y_offset_meters)
wgs84 = RGeo::Geographic.simple_mercator_factory.point(lon, lat)
wgs84_factory = wgs84.factory
webmercator = wgs84_factory.project wgs84
webmercator_factory = webmercator.factory
webmercator_moved = webmercator_factory.point(webmercator.x+x_offset_meters, webmercator.y+y_offset_meters)
wgs84_factory.unproject webmercator_moved
end
From How to move a point in Rgeo