如何在iOS中获取缓冲区多边形坐标(纬度和经度)?

时间:2016-05-27 13:34:41

标签: ios swift coordinates polygon arcgis

我在地图上用一组坐标创建了一个多边形。 我需要有关制作一个缓冲多边形的帮助,该多边形在原始多边形边界之外的某个给定距离。

所以我需要一种方法,使用这样的算法,其中我传递坐标集作为输入,并应获得缓冲的坐标集作为输出。

我试图通过使用带有AGSGeometryEngine的bufferGeometry方法的ios的arcgis库来实现这个目的,但问题是,这是紧密耦合的,只能使用他们的GIS Map,但我使用的Mapbox是不同的Map。所以我想要一个可以独立解决我的问题的通用方法。

enter image description here

4 个答案:

答案 0 :(得分:1)

我的要求与此类似。我最终为此写了自己的算法。 https://github.com/RanaRanvijaySingh/PolygonBuffer 你需要使用的就是这一行

from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput


class LoginScreen(GridLayout):

    def __init__(self, **kwargs):
        super(LoginScreen, self).__init__(**kwargs)
        self.cols = 2
        self.add_widget(Label(text='User Name'))
        self.username = TextInput(multiline=False)
        self.add_widget(self.username)
        self.add_widget(Label(text='password'))
        self.password = TextInput(password=True, multiline=False)
        self.add_widget(self.password)


class MyApp(App):

    def build(self):
        return LoginScreen()


if __name__ == '__main__':
    MyApp().run()

它为您提供了与原始多边形相距给定距离的缓冲多边形点列表。 enter image description here

答案 1 :(得分:0)

我在我的应用中遇到同样的问题,最后在this site

的帮助下找到了解决方案

我是一名Android开发人员,我的代码可能对您没用,但核心概念是相同的。

  1. 首先我们需要在两点LatLng点的帮助下找到线的方位。(我使用 computeDistanceAndBearing(double lat1,double lon1,double lat2,double lon2)功能)
  2. enter image description here

    1. 现在为了获得某个点的缓冲,我们需要给出缓冲距离,LatLng点和方位(我从 computeDistanceAndBearing 函数获得)。(我使用 computeDestinationAndBearing完成了这个) (double lat1,double lon1,double brng,double dist)功能)。从单个LatLng点开始,我们通过生成具有一定距离的轴承来获得两个点。
    2. enter image description here enter image description here

      1. 现在我们需要找到两点的交叉点来获得我们想要的缓冲。为此记得采取新的获得点和另一条线的轴承和另一条线的相同。这有助于获得所需缓冲的新交叉点。(我在我的函数 computeIntersectionPoint(LatLng p1,double brng1,LatLng p2,double brng2)中完成此操作)
      2. enter image description here

        1. 对所有多边形点执行此操作,然后获得新的点以进行缓冲。
        2. 这是我在Android位置应用程序中完成的方式{是enter image description here

          这是我的代码 // computeDistanceAndBearing(double lat1,double lon1,                                                      double lat2,double lon2)

          public static double[] computeDistanceAndBearing(double lat1, double lon1,
                                                           double lat2, double lon2) {
              // Based on http://www.ngs.noaa.gov/PUBS_LIB/inverse.pdf
              // using the "Inverse Formula" (section 4)
              double results[] = new double[3];
              int MAXITERS = 20;
              // Convert lat/long to radians
              lat1 *= Math.PI / 180.0;
              lat2 *= Math.PI / 180.0;
              lon1 *= Math.PI / 180.0;
              lon2 *= Math.PI / 180.0;
          
              double a = 6378137.0; // WGS84 major axis
              double b = 6356752.3142; // WGS84 semi-major axis
              double f = (a - b) / a;
              double aSqMinusBSqOverBSq = (a * a - b * b) / (b * b);
          
              double L = lon2 - lon1;
              double A = 0.0;
              double U1 = Math.atan((1.0 - f) * Math.tan(lat1));
              double U2 = Math.atan((1.0 - f) * Math.tan(lat2));
          
              double cosU1 = Math.cos(U1);
              double cosU2 = Math.cos(U2);
              double sinU1 = Math.sin(U1);
              double sinU2 = Math.sin(U2);
              double cosU1cosU2 = cosU1 * cosU2;
              double sinU1sinU2 = sinU1 * sinU2;
          
              double sigma = 0.0;
              double deltaSigma = 0.0;
              double cosSqAlpha = 0.0;
              double cos2SM = 0.0;
              double cosSigma = 0.0;
              double sinSigma = 0.0;
              double cosLambda = 0.0;
              double sinLambda = 0.0;
          
              double lambda = L; // initial guess
              for (int iter = 0; iter < MAXITERS; iter++) {
                  double lambdaOrig = lambda;
                  cosLambda = Math.cos(lambda);
                  sinLambda = Math.sin(lambda);
                  double t1 = cosU2 * sinLambda;
                  double t2 = cosU1 * sinU2 - sinU1 * cosU2 * cosLambda;
                  double sinSqSigma = t1 * t1 + t2 * t2; // (14)
                  sinSigma = Math.sqrt(sinSqSigma);
                  cosSigma = sinU1sinU2 + cosU1cosU2 * cosLambda; // (15)
                  sigma = Math.atan2(sinSigma, cosSigma); // (16)
                  double sinAlpha = (sinSigma == 0) ? 0.0 : cosU1cosU2 * sinLambda
                          / sinSigma; // (17)
                  cosSqAlpha = 1.0 - sinAlpha * sinAlpha;
                  cos2SM = (cosSqAlpha == 0) ? 0.0 : cosSigma - 2.0 * sinU1sinU2
                          / cosSqAlpha; // (18)
          
                  double uSquared = cosSqAlpha * aSqMinusBSqOverBSq; // defn
                  A = 1 + (uSquared / 16384.0) * // (3)
                          (4096.0 + uSquared * (-768 + uSquared * (320.0 - 175.0 * uSquared)));
                  double B = (uSquared / 1024.0) * // (4)
                          (256.0 + uSquared * (-128.0 + uSquared * (74.0 - 47.0 * uSquared)));
                  double C = (f / 16.0) * cosSqAlpha * (4.0 + f * (4.0 - 3.0 * cosSqAlpha)); // (10)
                  double cos2SMSq = cos2SM * cos2SM;
                  deltaSigma = B
                          * sinSigma
                          * // (6)
                          (cos2SM + (B / 4.0)
                                  * (cosSigma * (-1.0 + 2.0 * cos2SMSq) - (B / 6.0) * cos2SM
                                  * (-3.0 + 4.0 * sinSigma * sinSigma)
                                  * (-3.0 + 4.0 * cos2SMSq)));
          
                  lambda = L
                          + (1.0 - C)
                          * f
                          * sinAlpha
                          * (sigma + C * sinSigma
                          * (cos2SM + C * cosSigma * (-1.0 + 2.0 * cos2SM * cos2SM))); // (11)
          
                  double delta = (lambda - lambdaOrig) / lambda;
                  if (Math.abs(delta) < 1.0e-12) {
                      break;
                  }
              }
          
              double distance = (b * A * (sigma - deltaSigma));
              results[0] = distance;
              if (results.length > 1) {
                  double initialBearing = Math.atan2(cosU2 * sinLambda, cosU1 * sinU2
                          - sinU1 * cosU2 * cosLambda);
                  initialBearing *= 180.0 / Math.PI;
                  results[1] = initialBearing;
                  if (results.length > 2) {
                      double finalBearing = Math.atan2(cosU1 * sinLambda, -sinU1 * cosU2
                              + cosU1 * sinU2 * cosLambda);
                      finalBearing *= 180.0 / Math.PI;
                      results[2] = finalBearing;
                  }
              }
          
              return results;
          }
          

          // computeDestinationAndBearing(double lat1,double lon1,double brng,double dist)

          public static double[] computeDestinationAndBearing(double lat1, double lon1,
                                                              double brng, double dist) {
              double results[] = new double[3];
              double a = 6378137, b = 6356752.3142, f = 1 / 298.257223563; // WGS-84
              // ellipsiod
              double s = dist;
              double alpha1 = toRad(brng);
              double sinAlpha1 = Math.sin(alpha1);
              double cosAlpha1 = Math.cos(alpha1);
          
              double tanU1 = (1 - f) * Math.tan(toRad(lat1));
              double cosU1 = 1 / Math.sqrt((1 + tanU1 * tanU1)), sinU1 = tanU1 * cosU1;
              double sigma1 = Math.atan2(tanU1, cosAlpha1);
              double sinAlpha = cosU1 * sinAlpha1;
              double cosSqAlpha = 1 - sinAlpha * sinAlpha;
              double uSq = cosSqAlpha * (a * a - b * b) / (b * b);
              double A = 1 + uSq / 16384
                      * (4096 + uSq * (-768 + uSq * (320 - 175 * uSq)));
              double B = uSq / 1024 * (256 + uSq * (-128 + uSq * (74 - 47 * uSq)));
              double sinSigma = 0, cosSigma = 0, deltaSigma = 0, cos2SigmaM = 0;
              double sigma = s / (b * A), sigmaP = 2 * Math.PI;
          
              while (Math.abs(sigma - sigmaP) > 1e-12) {
                  cos2SigmaM = Math.cos(2 * sigma1 + sigma);
                  sinSigma = Math.sin(sigma);
                  cosSigma = Math.cos(sigma);
                  deltaSigma = B
                          * sinSigma
                          * (cos2SigmaM + B
                          / 4
                          * (cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM) - B / 6
                          * cos2SigmaM * (-3 + 4 * sinSigma * sinSigma)
                          * (-3 + 4 * cos2SigmaM * cos2SigmaM)));
                  sigmaP = sigma;
                  sigma = s / (b * A) + deltaSigma;
              }
          
              double tmp = sinU1 * sinSigma - cosU1 * cosSigma * cosAlpha1;
              double lat2 = Math.atan2(sinU1 * cosSigma + cosU1 * sinSigma * cosAlpha1,
                      (1 - f) * Math.sqrt(sinAlpha * sinAlpha + tmp * tmp));
              double lambda = Math.atan2(sinSigma * sinAlpha1, cosU1 * cosSigma - sinU1
                      * sinSigma * cosAlpha1);
              double C = f / 16 * cosSqAlpha * (4 + f * (4 - 3 * cosSqAlpha));
              double L = lambda
                      - (1 - C)
                      * f
                      * sinAlpha
                      * (sigma + C * sinSigma
                      * (cos2SigmaM + C * cosSigma * (-1 + 2 * cos2SigmaM * cos2SigmaM)));
              double lon2 = (toRad(lon1) + L + 3 * Math.PI) % (2 * Math.PI) - Math.PI; // normalise
              // to
              // -180...+180
          
              double revAz = Math.atan2(sinAlpha, -tmp); // final bearing, if required
          
              results[0] = toDegrees(lat2);
              results[1] = toDegrees(lon2);
              results[2] = toDegrees(revAz);
              return results;
          }
          
          private static double toRad(double angle) {
              return angle * Math.PI / 180;
          }
          
          private static double toDegrees(double radians) {
              return radians * 180 / Math.PI;
          }
          

          // computeIntersectionPoint(LatLng p1,double brng1,LatLng p2,double brng2)

              public static LatLng computeIntersectionPoint(LatLng p1, double brng1, LatLng p2, double brng2) {
              double lat1 = toRad(p1.latitude), lng1 = toRad(p1.longitude);
              double lat2 = toRad(p2.latitude), lng2 = toRad(p2.longitude);
              double brng13 = toRad(brng1), brng23 = toRad(brng2);
              double dlat = lat2 - lat1, dlng = lng2 - lng1;
              double delta12 = 2 * Math.asin(Math.sqrt(Math.sin(dlat / 2) * Math.sin(dlat / 2)
                      + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dlng / 2) * Math.sin(dlng / 2)));
          
              if (delta12 == 0) return null;
          
          
              double initBrng1 = Math.acos((Math.sin(lat2) - Math.sin(lat1) * Math.cos(delta12)) / (Math.sin(delta12) * Math.cos(lat1)));
          
              double initBrng2 = Math.acos((Math.sin(lat1) - Math.sin(lat2) * Math.cos(delta12)) / (Math.sin(delta12) * Math.cos(lat2)));
          
              double brng12 = Math.sin(lng2 - lng1) > 0 ? initBrng1 : 2 * Math.PI - initBrng1;
              double brng21 = Math.sin(lng2 - lng1) > 0 ? 2 * Math.PI - initBrng2 : initBrng2;
          
          
              double alpha1 = (brng13 - brng12 + Math.PI) % (2 * Math.PI) - Math.PI; 
              double alpha2 = (brng21 - brng23 + Math.PI) % (2 * Math.PI) - Math.PI; 
          
              double alpha3 = Math.acos(-Math.cos(alpha1) * Math.cos(alpha2) + Math.sin(alpha1) * Math.sin(alpha2) * Math.cos(delta12));
              double delta13 = Math.atan2(Math.sin(delta12) * Math.sin(alpha1) * Math.sin(alpha2), Math.cos(alpha2) + Math.cos(alpha1) * Math.cos(alpha3));
              double lat3 = Math.asin(Math.sin(lat1) * Math.cos(delta13) + Math.cos(lat1) * Math.sin(delta13) * Math.cos(brng13));
              double dlng13 = Math.atan2(Math.sin(brng13) * Math.sin(delta13) * Math.cos(lat1), Math.cos(delta13) - Math.sin(lat1) * Math.sin(lat3));
              double lng3 = lng1 + dlng13;
          
              return new LatLng(toDegrees(lat3), (toDegrees(lng3) + 540) % 360 - 180); 
          }
          

          我建议你浏览上面的网站并获取知识,因为我也做了同样的事情。

          希望这可能有所帮助,我知道这不是在ios中,但概念与我通过更改javascript代码完成我的项目相同。

          干杯!!!

答案 2 :(得分:-1)

看看BOOST这是一个很大的C ++库,你可能会找到几乎所有东西的库/源代码,比如缓冲方法,如斜接,圆形,方形等。

只需安装最新版本的Boost,我现在认为是1.58.0,看看BOOST / Geometry / Strategies / Cartesian / buffer [Something] -Square / Mitre / Round

这是一个很好的document

您需要将大地坐标(纬度/经度)转换为笛卡尔坐标(x / y)并使用Boost库并反转转换。您根本不需要使用ArcGIS或任何其他GIS库。

答案 3 :(得分:-1)

我建议使用Turf.js库进行缓冲和许多基本的gis操作。您将能够从返回的路径中检索每个边。对于几何缓冲区,它易于使用,重量很轻,使用MapBox.js或传单对我的应用程序没有任何问题。
更多详情:Turf.js Buffer

但是如果你正在寻找可能有问题的测地距离缓冲区。我会使用Arcgis Javascript API