是否可以使用Android地图V2在折线上添加箭头

时间:2013-03-26 06:50:09

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

如何使用Android Maps V2 API绘制带箭头的多边形线(表示方向)。在Android Maps Documentation中,此选项不可用。是否可以在折线上添加箭头?

3 个答案:

答案 0 :(得分:11)

这是一个我使用与Doug建议的相同概念开发的工作示例,通过JavaScript示例(http://econym.org.uk/gmap/example_arrows.htm)并将其转换为Java代码。为方便起见,它使用来自谷歌地图服务器的图像,但这些图像可能是您的设计图像,或者可以从网页上删除并存储在应用程序中。我是为了演示而在主线程上下载这些,但如果在实时应用程序中使用,请不要这样做!!

JavaScript示例的主要区别在于,您必须将箭头图像投影到尺寸为四倍的较大图像上,根据轴承从A到B计算转换图像的位置,最后确定中心现有B标记上的图像,通过为图标添加另一个锚定标记和较大的图像。

首先添加折线:

PolylineOptions polylines = new PolylineOptions();

LatLng from = new LatLng(f.getLatitude(), f.getLongitude());
LatLng to = new LatLng(t.getLatitude(), t.getLongitude());

polylines.add(from, to).color(polyColor).width(2);

mMap.addPolyline(polylines);

DrawArrowHead(mMap, from, to);

然后添加你的箭头:

private final double degreesPerRadian = 180.0 / Math.PI;

private void DrawArrowHead(GoogleMap mMap, LatLng from, LatLng to){
    // obtain the bearing between the last two points
    double bearing = GetBearing(from, to);

    // round it to a multiple of 3 and cast out 120s
    double adjBearing = Math.round(bearing / 3) * 3;
    while (adjBearing >= 120) {
        adjBearing -= 120;
    }

    StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy); 

    // Get the corresponding triangle marker from Google        
    URL url;
    Bitmap image = null;

    try {
        url = new URL("http://www.google.com/intl/en_ALL/mapfiles/dir_" + String.valueOf((int)adjBearing) + ".png");
        try {
            image = BitmapFactory.decodeStream(url.openConnection().getInputStream());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    if (image != null){

        // Anchor is ratio in range [0..1] so value of 0.5 on x and y will center the marker image on the lat/long
        float anchorX = 0.5f;
        float anchorY = 0.5f;

        int offsetX = 0;
        int offsetY = 0;

        // images are 24px x 24px
        // so transformed image will be 48px x 48px

        //315 range -- 22.5 either side of 315
        if (bearing >= 292.5 && bearing < 335.5){
            offsetX = 24;
            offsetY = 24;
        }
        //270 range
        else if (bearing >= 247.5 && bearing < 292.5){
            offsetX = 24;
            offsetY = 12;
        }
        //225 range
        else if (bearing >= 202.5 && bearing < 247.5){
            offsetX = 24;
            offsetY = 0;
        }
        //180 range
        else if (bearing >= 157.5 && bearing < 202.5){
            offsetX = 12;
            offsetY = 0;
        }
        //135 range
        else if (bearing >= 112.5 && bearing < 157.5){
            offsetX = 0;
            offsetY = 0;
        }
        //90 range
        else if (bearing >= 67.5 && bearing < 112.5){
            offsetX = 0;
            offsetY = 12;
        }
        //45 range
        else if (bearing >= 22.5 && bearing < 67.5){
            offsetX = 0;
            offsetY = 24;
        }
        //0 range - 335.5 - 22.5
        else {
            offsetX = 12;
            offsetY = 24;
        }

        Bitmap wideBmp;
        Canvas wideBmpCanvas;
        Rect src, dest;

        // Create larger bitmap 4 times the size of arrow head image
        wideBmp = Bitmap.createBitmap(image.getWidth() * 2, image.getHeight() * 2, image.getConfig());

        wideBmpCanvas = new Canvas(wideBmp); 

        src = new Rect(0, 0, image.getWidth(), image.getHeight());
        dest = new Rect(src); 
        dest.offset(offsetX, offsetY); 

        wideBmpCanvas.drawBitmap(image, src, dest, null);

        mMap.addMarker(new MarkerOptions()
        .position(to)
        .icon(BitmapDescriptorFactory.fromBitmap(wideBmp))
        .anchor(anchorX, anchorY));
    }
}

private double GetBearing(LatLng from, LatLng to){
    double lat1 = from.latitude * Math.PI / 180.0;
    double lon1 = from.longitude * Math.PI / 180.0;
    double lat2 = to.latitude * Math.PI / 180.0;
    double lon2 = to.longitude * Math.PI / 180.0;

    // Compute the angle.
    double angle = - Math.atan2( Math.sin( lon1 - lon2 ) * Math.cos( lat2 ), Math.cos( lat1 ) * Math.sin( lat2 ) - Math.sin( lat1 ) * Math.cos( lat2 ) * Math.cos( lon1 - lon2 ) );

    if (angle < 0.0)
        angle += Math.PI * 2.0;

    // And convert result to degrees.
    angle = angle * degreesPerRadian;

    return angle;
}

答案 1 :(得分:3)

Feb. 15, 2017 release of Android Maps API v2开始,您现在可以在Android Maps API v2的折线末尾添加自定义Line caps,这可以是箭头。

来自Line caps文档:

  

以下代码段指定了结束上限的自定义位图:

mPolyline.setEndCap(
        new CustomCap(BitmapDescriptorFactory.fromResource(R.drawable.arrow),
                16));
     

使用自定义位图时,应指定参考笔触宽度(以像素为单位)。 API会相应地缩放位图。参考笔触宽度是在图像的原始尺寸处设计帽的位图图像时使用的笔划宽度。默认参考笔触宽度为10像素。提示:要确定参考笔划宽度,请在图像编辑器中以100%缩放打开位图图像,并绘制相对于图像的所需线条笔划宽度。

     

如果使用BitmapDescriptorFactory.fromResource()创建位图,请确保使用与密度无关的资源(nodpi)。

Google针对相关已解决问题here的帖子说:

  

我们添加了使用自定义位图自定义折线的起始和结束大写的功能。使用此功能,您可以将箭头添加到折线。

     

在此处查看“形状指南”中有关行上限的信息:   https://developers.google.com/maps/documentation/android-api/shapes#line_caps

     

请参阅新的折线和多边形教程中的示例:   https://developers.google.com/maps/documentation/android-api/polygon-tutorial#add_custom_styling_to_your_polyline

     

请参阅此处的发行说明:   https://developers.google.com/maps/documentation/android-api/releases#february_15_2017

     

请参阅此处的博文:   https://maps-apis.googleblog.com/2017/02/styling-and-custom-data-for-polylines.html

答案 2 :(得分:1)

我没试过这个,但我认为应该可以使用标记。你需要创建一系列20个小箭头,每个箭头指向不同的方向,18,36,54度等。然后,在构建折线时,或者更好的是,在构建折线后作为一个单独的过程,以你想要的任何间距穿过所有坐标,并在每个选定点使用locationn.getbearing获取方位,并从该方位确定哪个方向箭头用作标记并在该点放置适当的标记