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

Geo*_*off 5 android google-maps google-maps-markers google-maps-android-api-2

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

        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);

}
Run Code Online (Sandbox Code Playgroud)

这会显示行车路线,例如

在此处输入图片说明

但是我正在尝试使用缩放视图显示默认的谷歌地图驾驶图标

在此处输入图片说明

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

And*_*nko 7

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

TLDR;

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

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

(d) 不得重新创建 Google 产品或功能。客户不得使用服务来创建产品或服务,其功能与其他 Google 产品或服务的功能基本相似或重新创建了其他 Google 产品或服务的功能。客户的产品或服务必须包含 Google 产品或服务之外的实质性、独立的价值和功能。例如,客户不得:(i) 重新分发 Google 地图核心服务或将其作为客户的服务进行分发;(ii) 创建谷歌地图核心服务、谷歌地图或谷歌地图移动应用程序或其功能的替代品;(iii) 在列表或目录服务中使用 Google 地图核心服务,或者创建或增强广告产品;(iv) 结合来自 Directions API、Geolocation API、

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

1) 获取用户当前位置;

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

3) 获取该段的方位角(方位角);

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

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

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

任务 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;
}
Run Code Online (Sandbox Code Playgroud)

任务 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;
}
Run Code Online (Sandbox Code Playgroud)

其中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>
Run Code Online (Sandbox Code Playgroud)

你可以用这样的代码把它放在地图上:

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)
    );
}
Run Code Online (Sandbox Code Playgroud)

哪里150是标记大小(以像素为单位)。注意!您需要flat标记以使其随地图旋转和倾斜,并0.5f准确地在其中心点移动标记锚点。

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

...
CameraPosition cameraPosition = new CameraPosition.Builder()
        .target(userPosition)
        .tilt(tilt)
        .zoom(zoom)
        .bearing(bearing)
        .build();
mGoogleMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
...
Run Code Online (Sandbox Code Playgroud)

但是,如果您只在屏幕中心显示用户当前位置的标记(因为GoogleMap.moveCamera()将中心精确设置为.target())。因此,为了避免它,您需要稍微向下移动地图 - 在这种情况下,用户位置标记应出现在屏幕底部。对于地图中心偏移,您需要获取当前地图中心屏幕坐标,然后更改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));
...
Run Code Online (Sandbox Code Playgroud)

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

路线视图

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

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

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

正如Jaswant Singh回答你的那样:

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

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


Jas*_*ngh 1

除了 Jinesh\xe2\x80\x99s 答案之外,\n如果您仍想添加该标记进行开发,您需要在当前位置设置一个自定义标记(图标与蓝色箭头相同)并将其移动到新位置每次调用 onLocationChanged() 回调时的位置(同时将相机动画设置到该新位置)。\n稍微倾斜地图以获得谷歌地图导航视图的精确外观,尽管您无法\xe2\x80\x99使用所有功能,但\xe2\x80\x99值得一试。

\n