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
Related
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.
I am testing the adversarial sample attack using deepfool and sparsefool on mnist dataset. It did an attack on the preprocessed image data. However, when I save it into an image and then load it back, it fails attack.
I have test it using sparsefool and deepfool, and I think there are some precision problems when I save it into images. But I cannot figure it out how to implement it correctly.
if __name__ == "__main__":
# pic_path = 'testSample/img_13.jpg'
pic_path = "./hacked.jpg"
model_file = './trained/'
image = Image.open(pic_path)
image_array = np.array(image)
# print(np.shape(image_array)) # 28*28
shape = (28, 28, 1)
projection = (0, 1)
image_norm = tf.cast(image_array / 255.0 - 0.5, tf.float32)
image_norm = np.reshape(image_norm, shape) # 28*28*1
image_norm = image_norm[tf.newaxis, ...] # 1*28*28*1
model = tf.saved_model.load(model_file)
print(np.argmax(model(image_norm)), "nnn")
# fool_img, r, pred_label, fool_label, loops = SparseFool(
# image_norm, projection, model)
print("pred_label", pred_label)
print("fool_label", np.argmax(model(fool_img)))
pert_image = np.reshape(fool_img, (28, 28))
# print(pert_image)
pert_image = np.copy(pert_image)
# np.savetxt("pert_image.txt", (pert_image + 0.5) * 255)
pert_image += 0.5
pert_image *= 255.
# shape = (28, 28, 1)
# projection = (0, 1)
# pert_image = tf.cast(((pert_image - 0.5) / 255.), tf.float32)
# image_norm = np.reshape(pert_image, shape) # 28*28*1
# image_norm = image_norm[tf.newaxis, ...] # 1*28*28*1
# print(np.argmax(model(image_norm)), "ffffnnn")
png = Image.fromarray(pert_image.astype(np.uint8))
png.save("./hacked.jpg")
It should attack 4 to 9, however, the saved image is still predicted into 4.
The full code project is shared on
https://drive.google.com/open?id=132_SosfQAET3c4FQ2I1RS3wXsT_4W5Mw
Based on my research and also this paper as reference https://arxiv.org/abs/1607.02533
You can see in real life when you converted to images, all of the adversarial attack samples generated from attack will not work on in real world. it can explain as below "This could be explained by the fact that iterative methods exploit more subtle kind of
perturbations, and these subtle perturbations are more likely to be destroyed by photo transformation"
As example, your clean image has 127,200,55,..... you dividing into 255 (as it is 8bit png) and sending to you ML as (0.4980,0.78431,0.2156,...) . And deepfool is advanced attack method it added small perturb and change it to (0.4981,0.7841,0.2155...). Now this is adversarial sample which can fool your ML. but if you try to save it to 8bit png you will get again 127,200,55.. as you will multiply it by 255. So adversarial information is lost.
Simple put, you use deep fool method it added some perturb so small which essential not possible in real world 8bit png.
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'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)
How can I zoom the Microsoft.Phone.Controls.Maps.Map control to the correct zoom level on Windows Phone 7?
I have a LocationCollection of GeoCoordinates and I calculated the Center myself, but now how do I calculate the correct zoom level to fit the LocationCollection?
P.S. Is there an out of the box method to calculate the center of GeoCoordinates so I don't have to calculate it myself?
EDIT:
I've found another fine solution: http://4mkmobile.com/2010/09/quick-tip-position-a-map-based-on-a-collection-of-pushpins/
map.SetView(LocationRect.CreateLocationRect(points));
You can use the following code to calculate the LocationRect that bounds a set of points, and then pass the LocationRect to the SetView() method on the map control:
var bounds = new LocationRect(
points.Max((p) => p.Latitude),
points.Min((p) => p.Longitude),
points.Min((p) => p.Latitude),
points.Max((p) => p.Longitude));
map.SetView(bounds);
The map control handles animating from the current position to the new location.
NOTE: You'll need a using statement for System.Linq to get the Min and Max methods.
Derek has already given the answer so you should accept his, I offer an alternative code for cases where there many points. This approach only iterates the points collection once instead 4 times however it isn't as asthetically pleasing.
double north, west, south, west;
north = south = points[0].Latitude;
west = east = points[0].Longitude;
foreach (var p in points.Skip(1))
{
if (north < p.Latitude) north = p.Latitude;
if (west > p.Longitude) west = p.Longitude;
if (south > p.Latitude) south = p.Latitude;
if (east < p.Longitude) east = p.Longitude
}
map.SetView(new LocationRect(north, west, south, east));
As suggested by the other answers I use SetView with a LocationRect.
However I found that it always produces to low zoom level, since only integer values was used. If for instance the perfect zoom level would be 5.5, you would get 5.0. To get a proper fit I calculate a new zoom level from TargetZoomLeveland TargetBoundingRectangle:
viewRect = LocationRect.CreateLocationRect(coordinates);
map.SetView(viewRect);
double scale = map.TargetBoundingRectangle.Height/viewRect.Height;
map.ZoomLevel = map.TargetZoomLevel + Math.Log(scale, 2);
This example sets the zoom level to fit viewRect's height on the screen.