在Google地图上移动和显示行车摄像头视图 [英] Moving and showing the driving camera view on Google maps

查看:141
本文介绍了在Google地图上移动和显示行车摄像头视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已通过

        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

但是我试图显示带有缩放视图的默认Google地图行车图标

But am trying to display the default google map driving icon with zoomed view like

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

How do i proceed to add such a map while still retaining the polylines to show driving view.

推荐答案

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

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

TLDR;

如果您选择第二种方法-最简单的方法是使用Android Google Maps API的标准类来创建视图,就像您的示例一样(另一种方法是创建

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

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

At first read carefully p 3.2.4 Restrictions Against Misusing the Services (d) of Google Maps Platform Terms of Service:

(d)否重新创建Google产品或功能.客户将不会使用 服务以创建具有以下特征的产品或服务: 基本上类似于或重现另一个特征 Google产品或服务.客户的产品或服务必须包含 超越Google产品的实质性,独立的价值和功能 或服务.例如,客户不会:(i)重新分配 Google Maps Core Services或将其假冒为客户的 服务; (ii)替代Google Maps Core Services, Google Maps或Google Maps移动应用程序或其功能; (iii)使用 列表或目录服务中的Google Maps Core服务,或 制作或扩充广告产品; (iv)合并来自 Directions API,Geolocation API和Maps SDK for Android创建 实时导航功能与 Google Maps for Android移动应用程序提供的功能.

(d) No Re-Creating Google Products or Features. 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. Customer’s product or service must contain substantial, independent value and features beyond the Google products or services. For example, Customer will not: (i) re-distribute the Google Maps Core Services or pass them off as if they were Customer’s services; (ii) create a substitute of the Google Maps Core Services, Google Maps, or Google Maps mobile apps, or their features; (iii) use the Google Maps Core Services in a listings or directory service or to create or augment an advertising product; (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)获取用户当前位置;

1) get user current location;

2)获取最接近用户当前位置的路线路径段(因为用户位置很少完全在道路上);

2) get a route path segment nearest to user current location (because user location rarely exactly on road);

3)获得此航段的方位角(轴承);

3) get a azimuth (bearing) of this segment;

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

4) show map with route path and user current position marker with appropriate tilt and rotation according path segment bearing.

任务1可以像

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

任务2可以通过该答案中一样:

Task 2 can be solved via PolyUtil.isLocationOnPath() like in that answer:

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可以用以下代码解决:

Task 3 can be solved with code like that:

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是当前路径路径段的开始和结束.

where begin and end is begin and end of current route path segment.

任务4可以用以下代码解决:

Task 4 can be solved with code like that:

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

as marker you can use vector drawable of north oriented arrow like that:

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

ic_up_arrow_circle.xml (also you can adjust transparency and colors):

<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:

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标记使其随地图旋转和倾斜,并且需要0.5f以便将标记锚精确地移动到其中心点.

where 150 is marker size in pixels. NB! You need flat marker for its rotation and tilt with map and 0.5f for move marker anchor exactly on its center point.

然后您可以在地图上显示所有这些内容:

then you can show all of this on map:

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

但是,如果仅执行此操作,则用户当前位置的标记会出现在屏幕的中心(因为GoogleMap.moveCamera()会将中心精确地设置为.target()).因此,为避免这种情况,您需要稍微向下移动地图-在这种情况下,用户位置标记应显示在屏幕底部.对于地图中心平移,您需要获取当前地图中心屏幕坐标,然后更改y坐标并获取新的屏幕中心.像这样的东西:

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()). 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. For map center shift you need get current map center screen coordinates, then change y coordinate and get new screen center. 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));
...

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

And with all of this stuff, for your route (with zoom = 15 and tilt = 50) you should get something like that:

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

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. You can get that e.g. via Google Maps Roads API part Snap to Road which

为一组给定的GPS坐标返回最适合的道路几何形状. 此服务最多可沿一条路线收集100个GPS点,并且 返回一组相似的数据,这些数据的点被捕捉到最高点 车辆行驶的可能道路.

returns the best-fit road geometry for a given set of GPS coordinates. 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个点并分别处理(Snap to Road API每天每个用户(IP)的请求为2500个,每秒限制为10个请求).

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

Jaswant Singh 回答您:

需要在上设置自定义标记(带有与蓝色箭头相同的图标) 您当前的位置,每次都将其移动到新位置 调用了onLocationChanged()回调(还可以将摄像机设置为动画 该新位置).

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

此外,您还需要根据例如当前用户速度来选择zoomtilt属性:当用户驾驶tilt -> 0更快时.等等.这不是一个简单的任务.

Also, you need to select zoom and tilt properties according, for example, current user speed: when user drives faster tilt -> 0. And so on. It's not a simple task.

这篇关于在Google地图上移动和显示行车摄像头视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆