【问题标题】:Draw a Geographically Accurate Arc on a Map for Android在 Android 地图上绘制地理准确的弧线
【发布时间】:2016-03-13 01:50:31
【问题描述】:

我想用一个中心 GPS 点和两个末端 GPS 点绘制一条弧线。我可以使用任何可以与android一起使用的地图软件。

到目前为止,我已经尝试过适用于 Android 的 Google 地图。安卓地图盒。用于安卓的 ARCGIS。他们似乎都无法完成这个简单的任务。

我猜我需要某种覆盖?

【问题讨论】:

  • 嘿 Reafidy,我很乐意在这个问题上为您提供帮助,您想在这里实现什么样的弧线?它是一条直线,考虑到地球的球形形状,最终结果会产生弧线吗​​?在任何情况下,都可以在 Mapbox Android SDK 中生成弧线,并涉及一些数学知识,我很乐意向您展示一些方法。
  • @cammace - 感谢您的帮助,抱歉耽搁了我离开。请参阅我更新的问题,了解我正在尝试创建 NZA155 的形状表。我可以画直线没问题,但弧线是问题。
  • @Reafidy 你还在为这篇文章寻找答案吗?
  • 您可以将您的地理数据发布为文本而不是图像吗?
  • 你的纬度/经度是什么单位?它们是投影坐标还是地理坐标?

标签: java android maps google-maps-android-api-2 mapbox


【解决方案1】:

很遗憾,我现在无法真正给您一个完整的答案,因为这个问题需要大量的数学运算,而且我无法完全理解您在表格中显示的数据。我假设您正在尝试获得类似于this 的最终结果。如果是这种情况,您有一个中心点、半径和起始 LatLng 和结束 LatLng 的弧(这也可以通过额外的数学从中心点计算)。如果我有机会编写一些处理数学方面的代码,我会尝试更新这个答案。据我所知,没有一个地图库(Google Maps、Mapbox)包含这个。

基本上,我会编写一个方法,该方法会在您希望绘制的弧线之后返回一堆纬度点。由此,我将使用addPolyline 方法画一条线。

// Draw line from list of LatLng called pointsArray
mapView.addPolyline(new PolylineOptions()
        .add(pointsArray)
        .color(Color.parseColor("#3bb2d0"))
        .width(2));

希望这对您有所帮助,至少在入门方面有所帮助,就像我说的那样,如果有机会,我稍后会尝试添加数学位。

【讨论】:

  • 嗨,请检查我更新的问题 - 希望图像有所帮助。我正在尝试在新西兰地图上绘制由两个黑色箭头标记的蓝线形状。这可以从表格中推导出来,我在图片上的表格中标注了数字 1-9 来展示形状是如何推导出来的。
  • 哇,这是一个极其复杂的形状。我仍然会以上面给出的相同方式解决这个问题。计算沿着形状周边的一堆点,然后绘制一条折线或可能是一个多边形,因为它是一个封闭的形状。唯一棘手的部分是弧线,就像我在回答中提到的那样,据我所知,没有一个映射库可以让这变得简单。
【解决方案2】:

首先,您必须更改地理数据表示。

从这里:

36°46'02.5"S 174°50'03.6"E GRC 36°56'18.3"S 174°33'09.7"E CWA 36°52'19.2"S 174°29'23.5"E 5.0' NM 36°48'19.8"S 174°25'37.7"E GRC 36°41'06.1"S 174°37'32.9"E CCA 36°39'54.5"S 174°38'40.7"E 1.5' NM 36°41'00.3"S 174°39'57.1"E GRC 36°39'49.4"S 174°41'32.3"E CCA 36°38'43.5"S 174°40'15.7"E 1.5' NM 36°39'17.5"S 174°41'59.7"E GRC 36°39'38.6"S 174°44'37.7"E GRC 36°37'08.8"S 174°47'27.4"E CWA 36°42'03.8"S 174°46'17.0"E 5.0' NM

到这里:

-36.76736 174.83433 GRC -36.93842 174.55269 CWA -36.87200 174.48986 0.08333 海里 -36.80550 174.42714 GRC -36.68503 174.62581 CCA -36.66514 174.64464 0.02500 海里 -36.68342 174.66586 GRC -36.66372 174.69231 CCA -36.64542 174.67103 0.02500 海里 -36.65486 174.69992 GRC -36.66072 174.74381 GRC -36.61911 174.79094 CWA -36.70106 174.77139 0.08333 海里

然后您可以使用它们来构建路径(例如,SVG path):

<svg
  ...>
  <g
     transform="matrix(1250,0,0,1250,46206.909,-217995.49)"
     ...>
    <path
       d=" M -36.76736,174.83433 L -36.93842,174.55269 A 0.08333,0.08333 0 0,1 -36.80550,174.42714 L -36.68503,174.62581 A 0.02500,0.02500 0 0,0 -36.68342,174.66586 L -36.66372,174.69231 A 0.02500,0.02500 0 0,0 -36.65486,174.69992 L -36.66072,174.74381 L -36.61911,174.79094 A 0.08333,0.08333 0 0,1 -36.76736,174.83433 Z"
       .../>
  </g>
</svg>

实际上,在 GMaps/OSMDroid 中没有创建曲线、弧线等的 API,因此,您应该尽可能多地绘制它们。这意味着做一些数学运算,但是这个数学运算可以由GeographicLib library进行:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    MapView map = (MapView) findViewById(R.id.map);
    map.setTileSource(TileSourceFactory.MAPNIK);
    map.setBuiltInZoomControls(true);
    map.setMultiTouchControls(true);


    IMapController mapController = map.getController();
    mapController.setZoom(9);
    GeoPoint startPoint = new GeoPoint(-36.66372, 174.69231);
    mapController.setCenter(startPoint);

    Polygon polyline = new Polygon(this);
    List<GeoPoint> points = new LinkedList<>();

    // I filled the data manually, but it can be done more clever, of course.
    GRC(points, new GeoPoint(-36.76736, 174.83433));
    CWA(points, new GeoPoint(-36.93842, 174.55269),
                new GeoPoint(-36.87200, 174.48986),
                new GeoPoint(-36.80550, 174.42714),
                0.08333);
    CCA(points, new GeoPoint(-36.68503, 174.62581),
                new GeoPoint(-36.66514, 174.64464),
                new GeoPoint(-36.68342, 174.66586),
                0.02500);
    CCA(points, new GeoPoint(-36.66372, 174.69231),
                new GeoPoint(-36.64542, 174.67103),
                new GeoPoint(-36.65486, 174.69992),
                0.02500);
    GRC(points, new GeoPoint(-36.66072, 174.74381));
    CWA(points, new GeoPoint(-36.61911, 174.79094),
                new GeoPoint(-36.70106, 174.77139),
                new GeoPoint(-36.76736, 174.83433), //close shape going to the start point
                0.08333);

    polyline.setPoints(points);
    polyline.setFillColor(0xA0FF00FF);
    polyline.setStrokeColor(Color.BLACK);
    polyline.setStrokeWidth(2f);
    map.getOverlays().add(polyline);
    map.invalidate();
}

private void CCA(List<GeoPoint> points, GeoPoint startPoint, GeoPoint centerPoint, GeoPoint endPoint, double radius) {
    points.add(startPoint);

    GeodesicData f = Geodesic.WGS84.Inverse(centerPoint.getLatitude(), centerPoint.getLongitude(), startPoint.getLatitude(), startPoint.getLongitude());
    GeodesicData t = Geodesic.WGS84.Inverse(centerPoint.getLatitude(), centerPoint.getLongitude(), endPoint.getLatitude(), endPoint.getLongitude());

    double ffaz = f.azi1;
    double tfaz = t.azi1;

    final int decrement = 1;
    while (Math.abs((int)ffaz) != Math.abs((int)tfaz)) {
        GeodesicData llb = Geodesic.WGS84.Direct(centerPoint.getLatitude(), centerPoint.getLongitude(), ffaz,  f.s12);
        points.add(new GeoPoint(llb.lat2, llb.lon2));
        ffaz -= decrement;
        if (ffaz <0) {
            ffaz += 360;
        }
    }

    points.add(endPoint);
}

private void CWA(List<GeoPoint> points, GeoPoint startPoint, GeoPoint centerPoint, GeoPoint endPoint, double radius) {
    points.add(startPoint);

    GeodesicData f = Geodesic.WGS84.Inverse(centerPoint.getLatitude(), centerPoint.getLongitude(), startPoint.getLatitude(), startPoint.getLongitude());
    GeodesicData t = Geodesic.WGS84.Inverse(centerPoint.getLatitude(), centerPoint.getLongitude(), endPoint.getLatitude(), endPoint.getLongitude());

    double ffaz = f.azi1;
    double tfaz = t.azi1 > 0 ? t.azi1 : 360 + t.azi1;

    final int increment = 1;
    while (Math.abs((int)ffaz) != Math.abs((int)tfaz)) {
        GeodesicData llb = Geodesic.WGS84.Direct(centerPoint.getLatitude(), centerPoint.getLongitude(), ffaz, f.s12);
        points.add(new GeoPoint(llb.lat2, llb.lon2));
        ffaz += increment;
        if (ffaz>360) {
            ffaz -= 360;
        }
    }

    points.add(endPoint);
}

private void GRC(List<GeoPoint> points, GeoPoint geoPoint) {
    points.add(geoPoint);
}

我用的是osmdroid+OSMBonusPack,但是代码很通用,可以很方便的和谷歌地图一起使用。

The full source code.

结果:

另外,您介意说出您发布的地理数据类型吗?我猜地图上的形状看起来像是一个允许飞行的区域。

【讨论】:

  • 这太棒了。我会仔细研究一下并回复您。
  • 正确的是空域,我需要画很多这样的形状。
  • 这种方法适合创建许多这些形状并像上面那样显示它们吗?其中大约有 46 个,大多数都没有这个形状那么复杂。或者它会使应用程序变慢很多?
  • 请看this branch
  • 其实我想我找到了我使用的解决方案:double ffaz = (f.azi1 &lt; 0) ? 360 + f.azi1: f.azi1; double tfaz = (t.azi1 &lt; 0) ? 360 + t.azi1: t.azi1;
猜你喜欢
  • 2018-03-06
  • 2018-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多