在谷歌地图中缩放指定路线

16

enter image description herebelow is screen shot @antonio what i get after removing line

我有一列随机的纬度和经度点,我正在绘制它们之间的路线。我的问题是如何将这条路线限定在下面所示的谷歌地图范围内。我已经编写了下面的实用方法。

public static void drawRouteIntoMap(final List<? extends MapHelper> position, final GoogleMap googleMap) {
    /*List<MapHelper> position = new ArrayList<MapHelper>();
    for (int i = lastPosition; i < maps.size(); i++) {
        position.add(maps.get(i));
    }*/
    if (position.size() > 0 && Validator.isNotNull(googleMap)) {
        googleMap.clear();
        List<PolylineOptions> polylineOptionses = new ArrayList<PolylineOptions>();
        PolylineOptions option = null;
        Boolean lastPause = null;
        for (MapHelper map : position) {
            if (map.isPause()) {
                if (Validator.isNull(lastPause) || !lastPause) {
                    option = new PolylineOptions().width(5).color(Color.rgb(255, 0, 155)).geodesic(true);
                    polylineOptionses.add(option);
                }
                option.add(new LatLng(map.getLatitude(), map.getLongitude()));
            } else {
                if (Validator.isNull(lastPause) || lastPause) {
                    option = new PolylineOptions().width(5).color(Color.rgb(0, 179, 253)).geodesic(true);
                    polylineOptionses.add(option);
                }
                option.add(new LatLng(map.getLatitude(), map.getLongitude()));
            }
            lastPause = map.isPause();
        }
        for (PolylineOptions options : polylineOptionses) {
            googleMap.addPolyline(options);
        }
        if(Validator.isNotNull(option)){
            //List<LatLng> points = option.getPoints();
            final LatLngBounds.Builder mapBounds = new LatLngBounds.Builder();

            googleMap.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
                @Override
                public void onMapLoaded() {
                    LatLng startPoint = new LatLng(position.get(0).getLatitude(), position.get(0).getLongitude());
                    googleMap.addMarker(new MarkerOptions().position(startPoint).title("start").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_GREEN)));
                    mapBounds.include(startPoint);
                    LatLng endPoint = new LatLng(position.get(position.size() - 1).getLatitude(), position.get(position.size() - 1).getLongitude());
                    mapBounds.include(endPoint);
                    googleMap.addMarker(new MarkerOptions().position(endPoint).title("finish").icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)));
                    googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mapBounds.build(), 10));
                   /* googleMap.animateCamera(CameraUpdateFactory.newLatLngBounds(mapBounds.build(), 10));
                    googleMap.moveCamera(CameraUpdateFactory.zoomOut());*/

                }
            });
        }

    }
}

这里的“last pause”是一个布尔值,表示是否为红色折线的暂停点。

但是它没有起作用。任何帮助都将不胜感激。


@Yvette,我想在给定的地图视图中以轻量模式显示整个路线,以便清晰地看到起点、终点和这两个标记之间的折线。 - Hardik Mehta
@Yvette,我已经上传了屏幕截图,里面有这样的项目列表。 - Hardik Mehta
@Yvette 是的,我想在这个地图区域内显示不同的路线。 - Hardik Mehta
展示添加到地图上的所有点。https://dev59.com/Y3jZa4cB1Zd3GeqPfYwx#19850330 - danny117
9个回答

30

尝试以这种方式实现

/**
 * Zooms a Route (given a List of LalLng) at the greatest possible zoom level.
 *
 * @param googleMap: instance of GoogleMap
 * @param lstLatLngRoute: list of LatLng forming Route
 */
public void zoomRoute(GoogleMap googleMap, List<LatLng> lstLatLngRoute) {

    if (googleMap == null || lstLatLngRoute == null || lstLatLngRoute.isEmpty()) return;

    LatLngBounds.Builder boundsBuilder = new LatLngBounds.Builder();
    for (LatLng latLngPoint : lstLatLngRoute)
        boundsBuilder.include(latLngPoint);

    int routePadding = 100;
    LatLngBounds latLngBounds = boundsBuilder.build();

    googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(latLngBounds, routePadding));
}

更新

查看图片后,地图上方存在布局。因此需要设置变量内边距。您可以这样做:

googleMap.setPadding(left, top, right, bottom);
注意:在设置变量padding时,您可以初始化routePadding = 0; 在您的情况下,近似值为:left = right = 10bottom=100top=200。一旦设置,您可以根据需要进行校准。 建议:您可以计算这些(顶部和底部)布局的高度(以像素为单位),然后相应地设置填充。

你为什么选择填充值为100? - Hardik Mehta
填充是用来防止标记(如果存在于某些点)在缩放时被裁剪,以及路线不接触地图边缘。您可以设置自己的自定义值(例如标记图像的高度或宽度)。如果您希望路线接触地图边缘,甚至可以将其设置为0。 - Rishabh Dutt Sharma
我已经尝试了你的解决方案,但在某些路线标记上仍然被裁剪了。我可以上传截图。 - Hardik Mehta
目前我正在使用BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_RED)方法来创建标记。 - Hardik Mehta
你知道默认高度会是多少吗?因为文档中只提到了常量。 - Hardik Mehta
显示剩余3条评论

7
可能导致缩放不起作用的原因是在调用方法时地图尚未充分展开:moveCamera(com.google.android.gms.maps.CameraUpdate)。尝试将ViewTreeObserver.OnGlobalLayoutListener添加到地图中。
ViewTreeObserver vto = googleMap.getViewTreeObserver();
ViewTreeObserver.OnGlobalLayoutListener globalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
    @Override
    public void onGlobalLayout() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
            googleMap.getViewTreeObserver().removeOnGlobalLayoutListener(this);
        } else {
            googleMap.getViewTreeObserver().removeGlobalOnLayoutListener(this);
        }
        googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mapBounds.build(), 10));
    }
};
vto.addOnGlobalLayoutListener(globalLayoutListener);

如果上述方法无效,GoogleMap有自己的布局监听器,您可以使用它:
googleMap.setOnCameraChangeListener(new OnCameraChangeListener() {

    @Override
    public void onCameraChange(CameraPosition arg0) {
        googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mapBounds.build(), 10));
        googleMap.setOnCameraChangeListener(null);
    }
});

然而,从API的play-services-maps 9.4.0版本开始,上述方法已被弃用。请使用以下之一:

4

你需要将构成折线的所有点包含在mapBounds对象中。

此外,你正在使用animateCamera更新相机,然后使用moveCamera移动它。这第二个相机更新会覆盖第一个更新。只需删除该行即可。

googleMap.moveCamera(CameraUpdateFactory.zoomOut());

这一行也是不必要的(你不需要移动和动画相机,只需要其中一个):

googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mapBounds.build(), 10));

如果您需要对地图进行缩小,您可以通过 CameraUpdateFactory.newLatLngBounds 方法的 padding 参数进行调整。


我已经上传了截图,可以看到标记没有正确显示。这只是一个路线,可能会有其他类似的路线。 - Hardik Mehta
你是如何绘制你的路线的?你能发一个例子吗? - antonio
请检查我上传的方法 - Hardik Mehta
请查看我上传的图片,其中包含了所有在地图边界中形成折线的点。但是终点标记仍然不可见。 - Hardik Mehta
好的,现在问题是你需要增加CameraUpdateFactory.newLatLngBounds的填充来适应位于顶部的标记。 - antonio
显示剩余3条评论

3
我采用了与@rishabh-dutt-sharma类似的解决方案,但有一些变化:
  • 首先,在缩放之前检查点是否已经在视图内。如果是,则不要更改它。这意味着对用户界面的不必要更改较少。
  • 其次,当只有一个点时有一个特殊情况。这在显示标记列表时很有用,可能在您的特定情况下不需要。之所以有用是因为在单个点的情况下,缩放通常会增加到最大值,而通常这太多了。
以下是代码(从我的原始代码调整而来,希望没有错别字):
    public void zoomRoute(GoogleMap googleMap, List<LatLng> lstLatLngRoute) {

        if (googleMap == null || lstLatLngRoute == null || lstLatLngRoute.isEmpty()) return;

        LatLngBounds currentLatLongBounds =
                googleMap.getProjection().getVisibleRegion().latLngBounds;
        boolean updateBounds = false;

        for (LatLng latLng : lstLatLngRoute) {
            if (!currentLatLongBounds.contains(latLng)) {
                updateBounds = true;
            }
        }

        if (updateBounds) {

            CameraUpdate cameraUpdate;

            if (lstLatLngRoute.size() == 1) {

                LatLng latLng = lstLatLngRoute.iterator().next();
                cameraUpdate = CameraUpdateFactory.newLatLng(latLng);

            } else {

                LatLngBounds.Builder builder = LatLngBounds.builder();
                for (LatLng latLng : lstLatLngRoute) {
                    builder.include(latLng);
                }
                LatLngBounds latLongBounds = builder.build();

                cameraUpdate =
                        CameraUpdateFactory.newLatLngBounds(latLongBounds, MAP_ZOOM_PADDING);

            }

            try {
                googleMap.animateCamera(cameraUpdate, MAP_CAMERA_ANIMATION_DURATION_IN_MILLIS,
                        new GoogleMap.CancelableCallback() {
                            @Override
                            public void onFinish() {
                            }

                            @Override
                            public void onCancel() {
                            }
                        });
            } catch (IllegalStateException ex) {
                // Ignore it. We're just being a bit lazy, as this exception only happens if
                // we try to animate the camera before the map has a size
            }
        }
    }

这些常量的填充和动画持续时间是多少? - Hardik Mehta
填充是像素数,我使用90dp实现密度独立性,您可以将其存储在dimen资源中或通过类似于此例程的常量转换:public static float dipToPixels(Context context, float dipValue) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, metrics); }。动画持续时间以毫秒为单位,我使用500进行快速和平滑的动画。 - Xavier Rubio Jansana

3

你可以做一件事情,找出两个纬度和经度之间的距离,并对你得到的距离进行检查。看看它是如何工作的。 这是一个技巧,可能对你有用。

googleMap.moveCamera(CameraUpdateFactory.newLatLng(reachLocationLatLng));
if (dist > 2 && dist <= 5) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(13.0f));
mapZoomLevel = 12;
} else if (dist > 5 && dist <= 10) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(12.0f));
mapZoomLevel = 11;
} else if (dist > 10 && dist <= 20) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(11.0f));
mapZoomLevel = 11;
} else if (dist > 20 && dist <= 40) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(10.0f));
mapZoomLevel = 10;
} else if (dist > 40 && dist < 100) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(9.0f));
mapZoomLevel = 9;
} else if (dist > 100 && dist < 200) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(8.0f));
mapZoomLevel = 8;
} else if (dist > 200 && dist < 400) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(7.0f));
mapZoomLevel = 7;
} else if (dist > 400 && dist < 700) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(6.0f));
mapZoomLevel = 7;
} else if (dist > 700 && dist < 1000) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(5.0f));
mapZoomLevel = 6;
} else if (dist > 1000) {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(4.0f));
mapZoomLevel = 5;
} else {
googleMap.animateCamera(CameraUpdateFactory.zoomTo(14.0f));
mapZoomLevel = 14;
}

感谢您,希望这能对您有所帮助。

1
 googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom(endPoint,zoomLevel));

如果它对你有帮助,就试一试


我应该设置什么缩放级别? - Hardik Mehta
你可以尝试任何数字10、12、15,并检查更改。 - Preetika Kaur
请替换此行代码:googleMap.moveCamera(CameraUpdateFactory.newLatLngBounds(mapBounds.build(), 10)); - Preetika Kaur
让我们在聊天中继续这个讨论 - Hardik Mehta
当您的源和目标不断变化时,这并不能帮助您。 - Prakash Reddy
显示剩余2条评论

0

我是如何做到的。

Android - plotting gps coordinate on custom map

是的,你可以绘制不在可见地图上的点。通过设置LatLngBounds来解决这个问题。然后为LatLngBounds显示地图。你也可以移动地图以显示LatLngBounds。这里没有什么棘手的问题,没有正切或斜率或者地球的双曲线曲率。所有这些都由点的度数处理,所以不要过度思考你的解决方案。如果你旋转地图,点也会随之旋转。因此,将你的点添加到地图上,找到边界并倾斜相机。将相机倾斜回来,所有的点仍然会在屏幕上!这将让你开始在屏幕上显示所有的点。

与示例相同,获取对Google地图的引用。

private void setUpMapIfNeeded() {
// Do a null check to confirm that we have not already instantiated the
// map.

if (mMap == null) {
    // Try to obtain the map from the SupportMapFragment.
    // mMap = mMapFragment.getMap();
    // // Check if we were successful in obtaining the map.

    // Try to obtain the map from the SupportMapFragment.
    mMap = ((SupportMapFragment) getSupportFragmentManager()
            .findFragmentById(R.id.map)).getMap();
    // use the settings maptype

    // Check if we were successful in obtaining the map.
    if (mMap != null) {
        setUpMap();
    }
}
}

让我们开始找到地图的边界。

import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
A field for LatLngBounds and a LatLngBounds.Builder

private LatLngBounds bounds;
private LatLngBounds.Builder myLatLngBuilder;
initialize the LatLngBounds.Builder

myLatLngBuilder = new LatLngBounds.Builder();
for each point on your map.

LatLng myLatLng = new LatLng(latitude, longitude);
myLatLngBuilder.include(myLatLng);
Then when your finished adding points build your boundary.

bounds = myLatLngBuilder.build();
Now I have the bounds of all the points on my map and I can display just that area of the map. This code I lifted from the map samples.

final View mapView = getSupportFragmentManager().findFragmentById(
            R.id.map).getView();
    if (mapView.getViewTreeObserver().isAlive()) {
        mapView.getViewTreeObserver().addOnGlobalLayoutListener(
                new OnGlobalLayoutListener() {
                    @SuppressWarnings("deprecation")
                    // We use the new method when supported
                    @SuppressLint("NewApi")
                    // We check which build version we are using.
                    @Override
                    public void onGlobalLayout() {
                        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
                            mapView.getViewTreeObserver()
                                    .removeGlobalOnLayoutListener(this);
                        } else {
                            mapView.getViewTreeObserver()
                                    .removeOnGlobalLayoutListener(this);
                        }
                        mMap.moveCamera(CameraUpdateFactory
                                .newLatLngBounds(bounds, 50));
                    }
                });
    }

0

很晚回答了,尝试以下最短的方式:

首先获取您当前位置的经纬度,然后编写有关目的地的经纬度代码,然后使用此代码计算您当前位置和目的地位置之间的距离。

private double distance(double lat1, double lon1, double lat2, double lon2) {
  double theta = lon1 - lon2;
  double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
  dist = Math.acos(dist);
  dist = rad2deg(dist);
  dist = dist * 60 * 1.1515;
   return (dist);
}
private double deg2rad(double deg) {
  return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad) {
  return (rad * 180.0 / Math.PI);
}
  • 由于GPS计数,您永远无法获得相同的经纬度数据,因为距离您当前位置95米以内的位置将显示当前位置或经纬度数据。即使您在同一位置,也无法找到完全相同的经纬度数据,这些点之间必须有所不同,因此您需要获取当前位置与固定经纬度数据点之间的距离。

  • 每当您从目标点到当前经纬度找到“距离”时,请触发此代码以动画方式移动摄像机并进行缩放。

    map.moveCamera( CameraUpdateFactory.newLatLngZoom(new LatLng(xxxx,xxxx),21));
    

0

对于上述问题,这可能是最简单的解决方案,它对我非常有效。

将所有航点添加到GoogleMapOptions:camera下的目标中,然后它将自动设置缩放并将地图居中以便根据Polyline(给定路线)进行绘制。

loadMap() {

let mapOptions: GoogleMapOptions = {
  camera: {
    target: this.wayPoints,
    zoom: 25,
    tilt: 30
  }
};

this.map = GoogleMaps.create('map_canvas', mapOptions);
this.map.one(GoogleMapsEvent.MAP_READY)
  .then(() => {
    console.log('Map is ready!');


   this.map.addPolyline({
      points:this.wayPoints,
      color:'#586bff',
      width: 8,
      geodesic:true,
    });
});
}

航点(this.wayPoints)应该采用以下格式:

[{lat: 52.33806, lng: 8.61179},
{lat: 52.33812, lng: 8.61185},
{lat: 52.33812, lng: 8.61186},
{lat: 52.33812, lng: 8.61188}]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接