繁体   English   中英

在 Google 地图上移动和显示行车摄像头视图

[英]Moving and showing the driving camera view on Google maps

我已经通过谷歌 map 路由添加了当前位置

        Routing routing = new Routing.Builder()
            .travelMode(Routing.TravelMode.DRIVING)
            .key(getResources().getString(R.string.google_maps_api))
            .withListener(this)
            .waypoints(new LatLng(mLastKnownLocation.getLatitude(), mLastKnownLocation.getLongitude()), site_location)
            .alternativeRoutes(false)
            .build();
    routing.execute();



   @Override
public void onRoutingSuccess(ArrayList<Route> route, int shortestRouteIndex) {

    if (polylines.size() > 0) {
        for (Polyline poly : polylines) {
            poly.remove();
        }
    }

    polylines = new ArrayList<>();
    //add route(s) to the map.
    for (int i = 0; i < route.size(); i++) {

        //In case of more than 5 alternative routes
        int colorIndex = i % COLORS.length;

        PolylineOptions polyOptions = new PolylineOptions();
        polyOptions.color(getResources().getColor(COLORS[colorIndex]));
        polyOptions.width(10 + i * 13);
        polyOptions.addAll(route.get(i).getPoints());
        Polyline polyline = googleMap.addPolyline(polyOptions);
        polylines.add(polyline);

        int distance = route.get(i).getDistanceValue();
        if (distance < 1000){
            totalKm.setText( distance+" Metres");
        }else {
            totalKm.setText( (distance/1000) +" km");

        }
    }

    LatLngBounds.Builder builder = new LatLngBounds.Builder();
    builder.include(new LatLng(mLastKnownLocation.getLatitude(), mLastKnownLocation.getLongitude()));
    builder.include(site_marker.getPosition());
    LatLngBounds bounds = builder.build();
    CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, 100);
    googleMap.animateCamera(cu);

}

这显示了一个行车路线,如

在此处输入图像描述

但我试图用缩放视图显示默认的谷歌 map 驾驶图标

在此处输入图像描述

我如何继续添加这样的 map,同时仍保留折线以显示驾驶视图。

Jinesh Francis的回答完全正确:您应该通过意图运行默认的 map Google Maps 应用程序或修改标准MapView (或MapFragment )。

TLDR;

如果您选择第二种方式 - 最简单的方法是使用 Android Google Maps API 的标准类来创建您的示例中的视图(其他方式是创建基于MapView的自定义视图)。

首先仔细阅读Google Maps Platform 服务条款第 3.2.4 条禁止滥用服务的限制 (d):

(d) 不得重新创建 Google 产品或功能。 客户不得使用服务创建具有与其他 Google 产品或服务的功能大体相似或重新创建的其他 Google 产品或服务的功能的产品或服务。 客户的产品或服务必须包含 Google 产品或服务之外的大量独立价值和功能。 例如,客户不得:(i) 重新分发 Google 地图核心服务或将其作为客户的服务进行传递; (ii) 创建谷歌地图核心服务、谷歌地图或谷歌地图移动应用程序或其功能的替代品; (iii) 在列表或目录服务中使用 Google 地图核心服务,或者创建或扩充广告产品; (iv) combine data from the Directions API, Geolocation API, and Maps SDK for Android to create real-time navigation functionality substantially similar to the functionality provided by the Google Maps for Android mobile app.

如果您不违反服务条款,您可以使用这些步骤/任务做您想做的事情:

1) 获取用户当前位置;

2) 获得最接近用户当前位置的路线路径段(因为用户位置很少正好在路上);

3)得到这个段的方位角(方位角);

4) 显示带有路径路径的 map 和用户当前 position 标记,并根据路径段方位进行适当的倾斜和旋转。

任务 1 可以像Axxiss这个答案一样解决:

 private final LocationListener mLocationListener = new LocationListener() { @Override public void onLocationChanged(final Location location) { //your code here } };

任务 2 可以通过PolyUtil.isLocationOnPath()解决,就像在那个答案中一样:

 private LatLng getMarkerProjectionOnSegment(LatLng carPos, List<LatLng> segment, Projection projection) { LatLng markerProjection = null; Point carPosOnScreen = projection.toScreenLocation(carPos); Point p1 = projection.toScreenLocation(segment.get(0)); Point p2 = projection.toScreenLocation(segment.get(1)); Point carPosOnSegment = new Point(); float denominator = (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y); // p1 and p2 are the same if (Math.abs(denominator) <= 1E-10) { markerProjection = segment.get(0); } else { float t = (carPosOnScreen.x * (p2.x - p1.x) - (p2.x - p1.x) * p1.x + carPosOnScreen.y * (p2.y - p1.y) - (p2.y - p1.y) * p1.y) / denominator; carPosOnSegment.x = (int) (p1.x + (p2.x - p1.x) * t); carPosOnSegment.y = (int) (p1.y + (p2.y - p1.y) * t); markerProjection = projection.fromScreenLocation(carPosOnSegment); } return markerProjection; }

任务 3 可以用这样的代码来解决:

private float getBearing(LatLng begin, LatLng end) {
    double dLon = (end.longitude - begin.longitude);
    double x = Math.sin(Math.toRadians(dLon)) * Math.cos(Math.toRadians(end.latitude));
    double y = Math.cos(Math.toRadians(begin.latitude))*Math.sin(Math.toRadians(end.latitude))
            - Math.sin(Math.toRadians(begin.latitude))*Math.cos(Math.toRadians(end.latitude)) * Math.cos(Math.toRadians(dLon));
    double bearing = Math.toDegrees((Math.atan2(x, y)));
    return (float) bearing;
}

其中beginend是当前路线路径段的开始和结束。

任务 4 可以用这样的代码来解决:

作为标记,您可以使用这样的朝北箭头的矢量可绘制对象:

用户位置标记

ic_up_arrow_circle.xml (您也可以调整透明度和颜色):

<vector android:height="24dp" android:viewportHeight="93.934"
    android:viewportWidth="93.934"
    android:width="24dp"
    xmlns:android="http://schemas.android.com/apk/res/android">
    <path
        android:fillColor="#8fFF0000"
        android:pathData="m0,46.9666c0,25.939 21.028,46.967 46.967,46.967c25.939,-0 46.967,-21.028 46.967,-46.967c0,-25.939 -21.027,-46.967 -46.967,-46.967c-25.939,-0 -46.967,21.028 -46.967,46.967zM78.262,67.4396l-31.295,-16.845l-31.295,16.845l31.295,-51.614l31.295,51.614z"
    />

    <path
        android:fillColor="#FFFFFF"
        android:pathData="M78.262,67.4396l-31.295,-16.845l-31.295,16.845l31.295,-51.614l31.295,51.614z"
        />
</vector>

你可以把它放在 map 上,代码如下:

public Marker addDirectionMarker(LatLng latLng, float angle) {
    Drawable circleDrawable = ContextCompat.getDrawable(getApplicationContext(), R.drawable.ic_up_arrow_in_circle);
    BitmapDescriptor markerIcon = getMarkerIconFromDrawable(circleDrawable, 150, 150);

    return mGoogleMap.addMarker(new MarkerOptions()
            .position(latLng)
            .anchor(0.5f, 0.5f)
            .rotation(angle)
            .flat(true)
            .icon(markerIcon)
    );
}

其中150是以像素为单位的标记大小。 注意! 您需要flat标记以使其旋转和倾斜 map 和0.5f以将标记锚点精确地移动到其中心点。

然后你可以在 map 上显示所有这些:

...
CameraPosition cameraPosition = new CameraPosition.Builder()
        .target(userPosition)
        .tilt(tilt)
        .zoom(zoom)
        .bearing(bearing)
        .build();
mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
...

但是,如果您只做用户当前 position 的那个标记出现在屏幕的中心(因为GoogleMap.moveCamera()将中心正好设置在.target() )。 因此,为避免这种情况,您需要稍微向下移动 map - 在这种情况下,用户位置标记应出现在屏幕底部。 对于 map 中心偏移,您需要获取当前的 map 中心屏幕坐标,然后更改y坐标并获取新的屏幕中心。 像这样的东西:

...
LatLng mapCenter = mGoogleMap.getCameraPosition().target;
Projection projection = mGoogleMap.getProjection();
Point centerPoint = projection.toScreenLocation(mapCenter);

DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int displayHeight = displayMetrics.heightPixels;

centerPoint.y = centerPoint.y - (int) (displayHeight / 4.5);  // move center down for approx 22%

LatLng newCenterPoint = projection.fromScreenLocation(centerPoint);

mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(newCenterPoint, zoom));
...

有了所有这些东西,对于您的路线(使用zoom = 15 和tilt = 50 ),您应该得到类似的东西:

方向视图

如您所见,路线路径并不完全在路上,因此您需要比 Directions API 响应更精确地获取路线路径点。 您可以通过Google Maps Roads API部分Snap to Road获得该信息

返回给定 GPS 坐标集的最佳拟合道路几何图形。 该服务最多需要 100 个沿路线收集的 GPS 点,并返回一组类似的数据,这些点捕捉到车辆行驶的最可能的道路。

就像那个答案一样。 如果您的路线路径有多个点,您需要分成 100 个点部分并单独处理它们(也 Snap to Road API 每个用户 (IP) 每天有 2500 个请求和每秒 10 个请求。限制)。

正如贾斯万特·辛格回答你的那样:

每次调用 onLocationChanged() 回调时,需要在当前位置设置自定义标记(图标与蓝色箭头相同)并将其移动到新位置(还将相机动画到该新位置)。

此外,您需要 select zoomtilt属性,例如,当前用户速度:当用户驾驶更快时tilt -> 0 等等。 这不是一项简单的任务。

Android 没有为开发提供像定向View (图 2)这样的View 。如果您想使用相同的View ,您可以通过像这样传递源位置和目标位置从您的应用程序启动默认的 map 应用程序。

Intent intent = new Intent(android.content.Intent.ACTION_VIEW, 
    Uri.parse("http://maps.google.com/maps?saddr=20.344,34.34&daddr=20.5666,45.345"));
startActivity(intent);

使用默认的 Android MapView ,您只能使用标记在两个位置之间添加折线(您可以在许多著名的交付应用程序中看到这一点)。 MapView支持相机缩放,您也可以倾斜(倾斜)Map,但是它不会给出确切的结果。

除了 Jinesh 的回答,如果您仍想添加该标记进行开发,您需要在当前位置设置自定义标记(图标与蓝色箭头相同),并在每次出现 onLocationChanged( ) 回调被调用(还将相机动画到该新位置)。 并稍微倾斜 map 以获得谷歌地图导航视图的确切外观,虽然您不会使用所有功能,但值得一试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM