简体   繁体   English

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

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

I have added current location via google map routing with我已经通过谷歌 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);

}

THis displays a driving directions like这显示了一个行车路线,如

在此处输入图像描述

But am trying to display the default google map driving icon with zoomed view like但我试图用缩放视图显示默认的谷歌 map 驾驶图标

在此处输入图像描述

How do i proceed to add such a map while still retaining the polylines to show driving view.我如何继续添加这样的 map,同时仍保留折线以显示驾驶视图。

Jinesh Francis totally right in his answer: you should either run the default map Google Maps application through intent or modify the standard MapView (or MapFragment ). Jinesh Francis的回答完全正确:您应该通过意图运行默认的 map Google Maps 应用程序或修改标准MapView (或MapFragment )。

TLDR; TLDR;

If you chose the second way - easiest approach is to use standard classes of Android Google Maps API to create view like in your example (other way is to create MapView -based custom view ).如果您选择第二种方式 - 最简单的方法是使用 Android Google Maps API 的标准类来创建您的示例中的视图(其他方式是创建基于MapView的自定义视图)。

At first read carefully p 3.2.4 Restrictions Against Misusing the Services (d) of Google Maps Platform Terms of Service :首先仔细阅读Google Maps Platform 服务条款第 3.2.4 条禁止滥用服务的限制 (d):

(d) No Re-Creating Google Products or Features. (d) 不得重新创建 Google 产品或功能。 Customer will not use the Services to create a product or service with features that are substantially similar to or that re-create the features of another Google product or service.客户不得使用服务创建具有与其他 Google 产品或服务的功能大体相似或重新创建的其他 Google 产品或服务的功能的产品或服务。 Customer's product or service must contain substantial, independent value and features beyond the Google products or services.客户的产品或服务必须包含 Google 产品或服务之外的大量独立价值和功能。 For example, Customer will not: (i) re-distribute the Google Maps Core Services or pass them off as if they were Customer's services;例如,客户不得:(i) 重新分发 Google 地图核心服务或将其作为客户的服务进行传递; (ii) create a substitute of the Google Maps Core Services, Google Maps, or Google Maps mobile apps, or their features; (ii) 创建谷歌地图核心服务、谷歌地图或谷歌地图移动应用程序或其功能的替代品; (iii) use the Google Maps Core Services in a listings or directory service or to create or augment an advertising product; (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. (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.

and if you not violate Terms of Service you can do what you want with that steps/tasks:如果您不违反服务条款,您可以使用这些步骤/任务做您想做的事情:

1) get user current location; 1) 获取用户当前位置;

2) get a route path segment nearest to user current location (because user location rarely exactly on road); 2) 获得最接近用户当前位置的路线路径段(因为用户位置很少正好在路上);

3) get a azimuth (bearing) of this segment; 3)得到这个段的方位角(方位角);

4) show map with route path and user current position marker with appropriate tilt and rotation according path segment bearing. 4) 显示带有路径路径的 map 和用户当前 position 标记,并根据路径段方位进行适当的倾斜和旋转。

Task 1 can be solved like in this answer of Axxiss :任务 1 可以像Axxiss这个答案一样解决:

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

Task 2 can be solved via PolyUtil.isLocationOnPath() like in that answer :任务 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; }

Task 3 can be solved with code like that:任务 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;
}

where begin and end is begin and end of current route path segment.其中beginend是当前路线路径段的开始和结束。

Task 4 can be solved with code like that:任务 4 可以用这样的代码来解决:

as marker you can use vector drawable of north oriented arrow like that:作为标记,您可以使用这样的朝北箭头的矢量可绘制对象:

用户位置标记

ic_up_arrow_circle.xml (also you can adjust transparency and colors): 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>

and you can place it on map with code like that:你可以把它放在 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)
    );
}

where 150 is marker size in pixels.其中150是以像素为单位的标记大小。 NB!注意! You need flat marker for its rotation and tilt with map and 0.5f for move marker anchor exactly on its center point.您需要flat标记以使其旋转和倾斜 map 和0.5f以将标记锚点精确地移动到其中心点。

then you can show all of this on map:然后你可以在 map 上显示所有这些:

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

But if you do only that marker of user current position appeared in the center of screen (because GoogleMap.moveCamera() sets the center exactly at .target() ).但是,如果您只做用户当前 position 的那个标记出现在屏幕的中心(因为GoogleMap.moveCamera()将中心正好设置在.target() )。 So, to avoid it you need to shift down the map slightly - in that case user location marker should be appeared at the bottom of screen.因此,为避免这种情况,您需要稍微向下移动 map - 在这种情况下,用户位置标记应出现在屏幕底部。 For map center shift you need get current map center screen coordinates, then change y coordinate and get new screen center.对于 map 中心偏移,您需要获取当前的 map 中心屏幕坐标,然后更改y坐标并获取新的屏幕中心。 Something like that:像这样的东西:

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

And with all of this stuff, for your route (with zoom = 15 and tilt = 50 ) you should get something like that:有了所有这些东西,对于您的路线(使用zoom = 15 和tilt = 50 ),您应该得到类似的东西:

方向视图

As you can see, the route path is not exactly on road, so you need to get route path points more precisely than Directions API response.如您所见,路线路径并不完全在路上,因此您需要比 Directions API 响应更精确地获取路线路径点。 You can get that eg via Google Maps Roads API part Snap to Road which您可以通过Google Maps Roads API部分Snap to Road获得该信息

returns the best-fit road geometry for a given set of GPS coordinates.返回给定 GPS 坐标集的最佳拟合道路几何图形。 This service takes up to 100 GPS points collected along a route, and returns a similar set of data with the points snapped to the most likely roads the vehicle was traveling along.该服务最多需要 100 个沿路线收集的 GPS 点,并返回一组类似的数据,这些点捕捉到车辆行驶的最可能的道路。

like in that answer.就像那个答案一样。 If your route path has more than points you need to split in into 100-points portions and process them separately (also Snap to Road API has 2500 request per day per user (IP) and 10 requests per sec. restriction).如果您的路线路径有多个点,您需要分成 100 个点部分并单独处理它们(也 Snap to Road API 每个用户 (IP) 每天有 2500 个请求和每秒 10 个请求。限制)。

And as Jaswant Singh answered you:正如贾斯万特·辛格回答你的那样:

need to set a custom marker (with icon same as that blue arrow) on your current location and move it to the new location every time there is onLocationChanged() callback is called (Also animate the camera to that new location).每次调用 onLocationChanged() 回调时,需要在当前位置设置自定义标记(图标与蓝色箭头相同)并将其移动到新位置(还将相机动画到该新位置)。

Also, you need to select zoom and tilt properties according, for example, current user speed: when user drives faster tilt -> 0 .此外,您需要 select zoomtilt属性,例如,当前用户速度:当用户驾驶更快时tilt -> 0 And so on.等等。 It's not a simple task.这不是一项简单的任务。

Android is not providing a View like the Directional View (image 2) for development.If you want to use the same View ,you can start the default map application from your app by passing source location and destination location like this. 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);

Using the default Android MapView ,You can only add polylines between two locations with markers (You can see this in many of the famous delivery apps).The camera zoom is supported by the MapView and you can incline(tilt) the Map also,but it won't give the exact result.使用默认的 Android MapView ,您只能使用标记在两个位置之间添加折线(您可以在许多著名的交付应用程序中看到这一点)。 MapView支持相机缩放,您也可以倾斜(倾斜)Map,但是它不会给出确切的结果。

In addition to Jinesh's answer, If you still want to add that marker for development, you need to set a custom marker (with icon same as that blue arrow) on your current location and move it to the new location every time there is onLocationChanged() callback is called (Also animate the camera to that new location).除了 Jinesh 的回答,如果您仍想添加该标记进行开发,您需要在当前位置设置自定义标记(图标与蓝色箭头相同),并在每次出现 onLocationChanged( ) 回调被调用(还将相机动画到该新位置)。 And tilt the map a little to get the exact look of the google maps navigation view, though you won't get to use all the functionalities but it's worth to give it a try.并稍微倾斜 map 以获得谷歌地图导航视图的确切外观,虽然您不会使用所有功能,但值得一试。

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

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