calcul de la superficie Polygon en utilisant Latitude et Longitude produite à partir de l'espace cartésien et un fichier mondial
-
30-09-2019 - |
Question
donné une série de paires de coordonnées GPS, il faut que pour calculer l'aire d'un polygone (n-gon). Ceci est relativement faible (pas plus de 50 000 pieds carrés). Les géocodes sont créés en appliquant une transformation de affines avec les données d'un fichier mondial.
J'ai essayé d'utiliser une approche en deux étapes en faisant convertir les géocodage en coordonnées cartésiennes:
double xPos = (lon-lonAnchor)*( Math.toRadians( 6378137 ) )*Math.cos( latAnchor );
double yPos = (lat-latAnchor)*( Math.toRadians( 6378137 ) );
j'utilise un calcul de produit croisé pour déterminer la zone.
Le problème est que les résultats sont un peu hors de la précision (environ 1%). Est-ce que je peux examiner pour améliorer?
Merci.
La solution
1% erreur semble un peu élevée en raison de seulement votre approximation. Comparez-vous par rapport aux mesures réelles ou un calcul d'idéal? Rappelez-vous qu'il ya erreur dans le GPS et qui pourraient contribuer.
Si vous voulez une méthode plus précise pour ce faire il y a une bonne réponse à cette question . Si vous allez pour une façon plus rapide, vous pouvez utiliser le géoïde WGS84 au lieu de votre sphère de référence pour la conversion en coordonnées cartésiennes (ECEF). Voici le lien wiki pour cette conversion.
Autres conseils
Je suis en train de modifier une carte Google de sorte qu'un utilisateur peut calculer la zone d'un polygone en cliquant sur les sommets. Il ne donnait pas correcte zones jusqu'à ce que je fait que le Math.cos (latAnchor) était en radians premier
double xPos = (lon-lonAnchor)*( Math.toRadians( 6378137 ) )*Math.cos( latAnchor );
est devenu:
double xPos = (lon-lonAnchor)*( 6378137*PI/180 ) )*Math.cos( latAnchor*PI/180 );
où lon, lonAnchor et latAnchor sont en degrés. Fonctionne comme un charme maintenant.
J'ai vérifié sur Internet pour différentes formules de la zone polygone (ou code) mais n'a pas trouvé une bonne ou à mettre en œuvre facile.
Maintenant, je l'ai écrit l'extrait de code à la zone de calcul d'un polygone dessiné sur la surface de la terre. Le polygone peut avoir n sommets avec chaque sommet a ayant sa propre latitude longitude.
Quelques points importants
- L'entrée de tableau pour cette fonction sera « n + 1 » éléments. Le dernier élément aura les mêmes valeurs que celle du premier.
- J'ai écrit très basique code C #, de sorte que les gars peuvent également adapter dans d'autres langues.
- 6378137 est la valeur du rayon de la terre, en mètres.
-
La zone de sortie aura unité de mètres carrés
private static double CalculatePolygonArea(IList<MapPoint> coordinates) { double area = 0; if (coordinates.Count > 2) { for (var i = 0; i < coordinates.Count - 1; i++) { MapPoint p1 = coordinates[i]; MapPoint p2 = coordinates[i + 1]; area += ConvertToRadian(p2.Longitude - p1.Longitude) * (2 + Math.Sin(ConvertToRadian(p1.Latitude)) + Math.Sin(ConvertToRadian(p2.Latitude))); } area = area * 6378137 * 6378137 / 2; } return Math.Abs(area); } private static double ConvertToRadian(double input) { return input * Math.PI / 180; }
Sur la base de la solution par Risky Pathak est la solution ici pour SQL (Redshift) aux zones calculate pour GeoJSON multipolygones (avec l'hypothèse que linestring 0 est le polygone le plus extérieur)
create or replace view geo_area_area as
with points as (
select ga.id as key_geo_area
, ga.name, gag.linestring
, gag.position
, radians(gag.longitude) as x
, radians(gag.latitude) as y
from geo_area ga
join geo_area_geometry gag on (gag.key_geo_area = ga.id)
)
, polygons as (
select key_geo_area, name, linestring, position
, x
, lag(x) over (partition by key_geo_area, linestring order by position) as prev_x
, y
, lag(y) over (partition by key_geo_area, linestring order by position) as prev_y
from points
)
, area_linestrings as (
select key_geo_area, name, linestring
, abs( sum( (x - prev_x) * (2 + sin(y) + sin(prev_y)) ) ) * 6378137 * 6378137 / 2 / 10^6 as area_km_squared
from polygons
where position != 0
group by 1, 2, 3
)
select key_geo_area, name
, sum(case when linestring = 0 then area_km_squared else -area_km_squared end) as area_km_squared
from area_linestrings
group by 1, 2
;
L'extrait de RiskyPathak Adapté à PHP
function CalculatePolygonArea($coordinates) {
$area = 0;
$coordinatesCount = sizeof($coordinates);
if ($coordinatesCount > 2) {
for ($i = 0; $i < $coordinatesCount - 1; $i++) {
$p1 = $coordinates[$i];
$p2 = $coordinates[$i + 1];
$p1Longitude = $p1[0];
$p2Longitude = $p2[0];
$p1Latitude = $p1[1];
$p2Latitude = $p2[1];
$area += ConvertToRadian($p2Longitude - $p1Longitude) * (2 + sin(ConvertToRadian($p1Latitude)) + sin(ConvertToRadian($p2Latitude)));
}
$area = $area * 6378137 * 6378137 / 2;
}
return abs(round(($area));
}
function ConvertToRadian($input) {
$output = $input * pi() / 180;
return $output;
}
Merci Risky Pathak!
Dans l'esprit de partage, voici mon adaptation à Delphes:
interface
uses
System.Math;
TMapGeoPoint = record
Latitude: Double;
Longitude: Double;
end;
function AreaInAcres(AGeoPoints: TList<TMapGeoPoint>): Double;
implementation
function AreaInAcres(AGeoPoints: TList<TMapGeoPoint>): Double;
var
Area: Double;
i: Integer;
P1, P2: TMapGeoPoint;
begin
Area := 0;
// We need at least 2 points
if (AGeoPoints.Count > 2) then
begin
for I := 0 to AGeoPoints.Count - 1 do
begin
P1 := AGeoPoints[i];
if i < AGeoPoints.Count - 1 then
P2 := AGeoPoints[i + 1]
else
P2 := AGeoPoints[0];
Area := Area + DegToRad(P2.Longitude - P1.Longitude) * (2 +
Sin(DegToRad(P1.Latitude)) + Sin(DegToRad(P2.Latitude)));
end;
Area := Area * 6378137 * 6378137 / 2;
end;
Area := Abs(Area); //Area (in sq meters)
// 1 Square Meter = 0.000247105 Acres
result := Area * 0.000247105;
end;