在 Android 应用程序中计算在 google 地图上绘制的多边形的面积
Calculate the area of a polygon drawn on google maps in an Android application
我想计算在大学项目的地图片段中绘制的多边形的面积。
这就是我绘制多边形的方式。
@Override
public void onMapClick(LatLng point) {
//tvLocInfo.setText("New marker added@" + point.toString());
map.addMarker(new MarkerOptions().position(point).draggable(true).title(point.toString()));
markerClicked = false;
}
@Override
public void onMapLongClick(LatLng point) {
//tvLocInfo.setText("New marker added@" + point.toString());
map.clear();
}
@Override
public boolean onMarkerClick(Marker marker) {
if(markerClicked){
if(polygon != null){
polygon.remove();
polygon = null;
}
polygonOptions.add(marker.getPosition());
polygonOptions.strokeColor(Color.RED);
polygonOptions.fillColor(Color.BLUE);
polygon = map.addPolygon(polygonOptions);
//Area = google.maps.geometry.spherical.computeArea(polygon.getPath().getArray());
}else{
if(polygon != null){
polygon.remove();
polygon = null;
}
polygonOptions = new PolygonOptions().add(marker.getPosition());
markerClicked = true;
}
我看过这段关于如何计算面积的代码,但我不确定如何在我的应用程序中实现它并计算多边形的面积。
我使用此代码计算 GPS 的面积 Android:
private static final double EARTH_RADIUS = 6371000;// meters
public static double calculateAreaOfGPSPolygonOnEarthInSquareMeters(final List<Location> locations) {
return calculateAreaOfGPSPolygonOnSphereInSquareMeters(locations, EARTH_RADIUS);
}
private static double calculateAreaOfGPSPolygonOnSphereInSquareMeters(final List<Location> locations, final double radius) {
if (locations.size() < 3) {
return 0;
}
final double diameter = radius * 2;
final double circumference = diameter * Math.PI;
final List<Double> listY = new ArrayList<Double>();
final List<Double> listX = new ArrayList<Double>();
final List<Double> listArea = new ArrayList<Double>();
// calculate segment x and y in degrees for each point
final double latitudeRef = locations.get(0).getLatitude();
final double longitudeRef = locations.get(0).getLongitude();
for (int i = 1; i < locations.size(); i++) {
final double latitude = locations.get(i).getLatitude();
final double longitude = locations.get(i).getLongitude();
listY.add(calculateYSegment(latitudeRef, latitude, circumference));
Log.d(LOG_TAG, String.format("Y %s: %s", listY.size() - 1, listY.get(listY.size() - 1)));
listX.add(calculateXSegment(longitudeRef, longitude, latitude, circumference));
Log.d(LOG_TAG, String.format("X %s: %s", listX.size() - 1, listX.get(listX.size() - 1)));
}
// calculate areas for each triangle segment
for (int i = 1; i < listX.size(); i++) {
final double x1 = listX.get(i - 1);
final double y1 = listY.get(i - 1);
final double x2 = listX.get(i);
final double y2 = listY.get(i);
listArea.add(calculateAreaInSquareMeters(x1, x2, y1, y2));
Log.d(LOG_TAG, String.format("area %s: %s", listArea.size() - 1, listArea.get(listArea.size() - 1)));
}
// sum areas of all triangle segments
double areasSum = 0;
for (final Double area : listArea) {
areasSum = areasSum + area;
}
// get abolute value of area, it can't be negative
return Math.abs(areasSum);// Math.sqrt(areasSum * areasSum);
}
private static Double calculateAreaInSquareMeters(final double x1, final double x2, final double y1, final double y2) {
return (y1 * x2 - x1 * y2) / 2;
}
private static double calculateYSegment(final double latitudeRef, final double latitude, final double circumference) {
return (latitude - latitudeRef) * circumference / 360.0;
}
private static double calculateXSegment(final double longitudeRef, final double longitude, final double latitude,
final double circumference) {
return (longitude - longitudeRef) * circumference * Math.cos(Math.toRadians(latitude)) / 360.0;
}
如果无法计算绘制多边形的面积,我也可以使用以下静态多边形。
Polygon UCCpolygon = map.addPolygon(new PolygonOptions()
.add(new LatLng(51.893728, -8.491865),
new LatLng(51.893550, -8.492479),
new LatLng(51.893216, -8.492224),
new LatLng(51.893404, -8.491598))
.strokeColor(Color.RED)
.fillColor(Color.BLUE));
感谢您的帮助!
肖恩
已经有 library 了。
import com.google.maps.android.SphericalUtil;
//...
List<LatLng> latLngs = new ArrayList<>();
latLngs.add(new LatLng(51.893728, -8.491865));
latLngs.add(new LatLng(51.893550, -8.492479));
latLngs.add(new LatLng(51.893216, -8.492224));
latLngs.add(new LatLng(51.893404, -8.491598));
Log.i(TAG, "computeArea " + SphericalUtil.computeArea(latLngs));
对我来说输出是computeArea 1920.8879882782069
如果你想在没有任何库的情况下使用 SphericalUtils 代码,你可以使用下面的代码。它取自 SphericalUtils.java 和其他 class 的开源代码。我已经使用了这段代码并像我使用 MapBox 一样使用它,而 MapBox 没有在 Turf 中实现 calculateArea 函数。
import java.util.List;
import pojo.LatLng;
import static java.lang.Math.PI;
import static java.lang.Math.abs;
import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.tan;
import static java.lang.Math.toRadians;
public class PolygonUtils {
/**
* The earth's radius, in meters.
* Mean radius as defined by IUGG.
*/
static final double EARTH_RADIUS = 6371009;
/**
* Returns the area of a closed path on Earth.
* @param path A closed path.
* @return The path's area in square meters.
*/
public static double computeArea(List<LatLng> path) {
return abs(computeSignedArea(path,EARTH_RADIUS));
}
/**
* Returns the signed area of a closed path on a sphere of given radius.
* The computed area uses the same units as the radius squared.
* Used by SphericalUtilTest.
*/
static double computeSignedArea(List<LatLng> path, double radius) {
int size = path.size();
if (size < 3) { return 0; }
double total = 0;
LatLng prev = path.get(size - 1);
double prevTanLat = tan((PI / 2 - toRadians(prev.getLatitude())) / 2);
double prevLng = toRadians(prev.getLongitude());
// For each edge, accumulate the signed area of the triangle formed by the North Pole
// and that edge ("polar triangle").
for (LatLng point : path) {
double tanLat = tan((PI / 2 - toRadians(point.getLatitude())) / 2);
double lng = toRadians(point.getLongitude());
total += polarTriangleArea(tanLat, lng, prevTanLat, prevLng);
prevTanLat = tanLat;
prevLng = lng;
}
return total * (radius * radius);
}
/**
* Returns the signed area of a triangle which has North Pole as a vertex.
* Formula derived from "Area of a spherical triangle given two edges and the included angle"
* as per "Spherical Trigonometry" by Todhunter, page 71, section 103, point 2.
* See http://books.google.com/books?id=3uBHAAAAIAAJ&pg=PA71
* The arguments named "tan" are tan((pi/2 - latitude)/2).
*/
private static double polarTriangleArea(double tan1, double lng1, double tan2, double lng2) {
double deltaLng = lng1 - lng2;
double t = tan1 * tan2;
return 2 * atan2(t * sin(deltaLng), 1 + t * cos(deltaLng));
}
}
我想计算在大学项目的地图片段中绘制的多边形的面积。
这就是我绘制多边形的方式。
@Override
public void onMapClick(LatLng point) {
//tvLocInfo.setText("New marker added@" + point.toString());
map.addMarker(new MarkerOptions().position(point).draggable(true).title(point.toString()));
markerClicked = false;
}
@Override
public void onMapLongClick(LatLng point) {
//tvLocInfo.setText("New marker added@" + point.toString());
map.clear();
}
@Override
public boolean onMarkerClick(Marker marker) {
if(markerClicked){
if(polygon != null){
polygon.remove();
polygon = null;
}
polygonOptions.add(marker.getPosition());
polygonOptions.strokeColor(Color.RED);
polygonOptions.fillColor(Color.BLUE);
polygon = map.addPolygon(polygonOptions);
//Area = google.maps.geometry.spherical.computeArea(polygon.getPath().getArray());
}else{
if(polygon != null){
polygon.remove();
polygon = null;
}
polygonOptions = new PolygonOptions().add(marker.getPosition());
markerClicked = true;
}
我看过这段关于如何计算面积的代码,但我不确定如何在我的应用程序中实现它并计算多边形的面积。
我使用此代码计算 GPS 的面积 Android:
private static final double EARTH_RADIUS = 6371000;// meters
public static double calculateAreaOfGPSPolygonOnEarthInSquareMeters(final List<Location> locations) {
return calculateAreaOfGPSPolygonOnSphereInSquareMeters(locations, EARTH_RADIUS);
}
private static double calculateAreaOfGPSPolygonOnSphereInSquareMeters(final List<Location> locations, final double radius) {
if (locations.size() < 3) {
return 0;
}
final double diameter = radius * 2;
final double circumference = diameter * Math.PI;
final List<Double> listY = new ArrayList<Double>();
final List<Double> listX = new ArrayList<Double>();
final List<Double> listArea = new ArrayList<Double>();
// calculate segment x and y in degrees for each point
final double latitudeRef = locations.get(0).getLatitude();
final double longitudeRef = locations.get(0).getLongitude();
for (int i = 1; i < locations.size(); i++) {
final double latitude = locations.get(i).getLatitude();
final double longitude = locations.get(i).getLongitude();
listY.add(calculateYSegment(latitudeRef, latitude, circumference));
Log.d(LOG_TAG, String.format("Y %s: %s", listY.size() - 1, listY.get(listY.size() - 1)));
listX.add(calculateXSegment(longitudeRef, longitude, latitude, circumference));
Log.d(LOG_TAG, String.format("X %s: %s", listX.size() - 1, listX.get(listX.size() - 1)));
}
// calculate areas for each triangle segment
for (int i = 1; i < listX.size(); i++) {
final double x1 = listX.get(i - 1);
final double y1 = listY.get(i - 1);
final double x2 = listX.get(i);
final double y2 = listY.get(i);
listArea.add(calculateAreaInSquareMeters(x1, x2, y1, y2));
Log.d(LOG_TAG, String.format("area %s: %s", listArea.size() - 1, listArea.get(listArea.size() - 1)));
}
// sum areas of all triangle segments
double areasSum = 0;
for (final Double area : listArea) {
areasSum = areasSum + area;
}
// get abolute value of area, it can't be negative
return Math.abs(areasSum);// Math.sqrt(areasSum * areasSum);
}
private static Double calculateAreaInSquareMeters(final double x1, final double x2, final double y1, final double y2) {
return (y1 * x2 - x1 * y2) / 2;
}
private static double calculateYSegment(final double latitudeRef, final double latitude, final double circumference) {
return (latitude - latitudeRef) * circumference / 360.0;
}
private static double calculateXSegment(final double longitudeRef, final double longitude, final double latitude,
final double circumference) {
return (longitude - longitudeRef) * circumference * Math.cos(Math.toRadians(latitude)) / 360.0;
}
如果无法计算绘制多边形的面积,我也可以使用以下静态多边形。
Polygon UCCpolygon = map.addPolygon(new PolygonOptions()
.add(new LatLng(51.893728, -8.491865),
new LatLng(51.893550, -8.492479),
new LatLng(51.893216, -8.492224),
new LatLng(51.893404, -8.491598))
.strokeColor(Color.RED)
.fillColor(Color.BLUE));
感谢您的帮助!
肖恩
已经有 library 了。
import com.google.maps.android.SphericalUtil;
//...
List<LatLng> latLngs = new ArrayList<>();
latLngs.add(new LatLng(51.893728, -8.491865));
latLngs.add(new LatLng(51.893550, -8.492479));
latLngs.add(new LatLng(51.893216, -8.492224));
latLngs.add(new LatLng(51.893404, -8.491598));
Log.i(TAG, "computeArea " + SphericalUtil.computeArea(latLngs));
对我来说输出是computeArea 1920.8879882782069
如果你想在没有任何库的情况下使用 SphericalUtils 代码,你可以使用下面的代码。它取自 SphericalUtils.java 和其他 class 的开源代码。我已经使用了这段代码并像我使用 MapBox 一样使用它,而 MapBox 没有在 Turf 中实现 calculateArea 函数。
import java.util.List;
import pojo.LatLng;
import static java.lang.Math.PI;
import static java.lang.Math.abs;
import static java.lang.Math.atan2;
import static java.lang.Math.cos;
import static java.lang.Math.sin;
import static java.lang.Math.tan;
import static java.lang.Math.toRadians;
public class PolygonUtils {
/**
* The earth's radius, in meters.
* Mean radius as defined by IUGG.
*/
static final double EARTH_RADIUS = 6371009;
/**
* Returns the area of a closed path on Earth.
* @param path A closed path.
* @return The path's area in square meters.
*/
public static double computeArea(List<LatLng> path) {
return abs(computeSignedArea(path,EARTH_RADIUS));
}
/**
* Returns the signed area of a closed path on a sphere of given radius.
* The computed area uses the same units as the radius squared.
* Used by SphericalUtilTest.
*/
static double computeSignedArea(List<LatLng> path, double radius) {
int size = path.size();
if (size < 3) { return 0; }
double total = 0;
LatLng prev = path.get(size - 1);
double prevTanLat = tan((PI / 2 - toRadians(prev.getLatitude())) / 2);
double prevLng = toRadians(prev.getLongitude());
// For each edge, accumulate the signed area of the triangle formed by the North Pole
// and that edge ("polar triangle").
for (LatLng point : path) {
double tanLat = tan((PI / 2 - toRadians(point.getLatitude())) / 2);
double lng = toRadians(point.getLongitude());
total += polarTriangleArea(tanLat, lng, prevTanLat, prevLng);
prevTanLat = tanLat;
prevLng = lng;
}
return total * (radius * radius);
}
/**
* Returns the signed area of a triangle which has North Pole as a vertex.
* Formula derived from "Area of a spherical triangle given two edges and the included angle"
* as per "Spherical Trigonometry" by Todhunter, page 71, section 103, point 2.
* See http://books.google.com/books?id=3uBHAAAAIAAJ&pg=PA71
* The arguments named "tan" are tan((pi/2 - latitude)/2).
*/
private static double polarTriangleArea(double tan1, double lng1, double tan2, double lng2) {
double deltaLng = lng1 - lng2;
double t = tan1 * tan2;
return 2 * atan2(t * sin(deltaLng), 1 + t * cos(deltaLng));
}
}