【问题标题】:Android - plotting gps coordinate on custom mapAndroid - 在自定义地图上绘制 gps 坐标
【发布时间】:2013-11-08 20:43:31
【问题描述】:

我的应用中有一个活动,其中有我用作地图的图像。如果图像与谷歌地图“网格对齐”,那么当我使用从 googlemaps 在线获得的地图的左上角和右下角时,我可以将用户 gps 变成屏幕上的 x 和 y。但是,如果地图不是“网格对齐”并且与我的数学返回的值成一定角度,则会将用户的位置绘制在屏幕外。显然我错过了如何处理地图角度的部分,所以如果有人能阐明如何做到这一点,那将是非常有帮助的。

我知道我必须计算出弧度的角度并进行一些转换,但我不知道从哪里开始。到目前为止,这就是我用来在画布上绘制 x 和 y 的方法。

public double[] getPositionGPS(Location upperLeft, Location lowerRight, Location current){

    try{

        double hypotenuse = upperLeft.distanceTo(current);
        double bearing = upperLeft.bearingTo(current);
        double currentDistanceY = Math.cos(bearing * Math.PI / OneEightyDeg) * hypotenuse;
        //                           "percentage to mark the position"
        double totalHypotenuse = upperLeft.distanceTo(lowerRight);
        double totalDistanceY = totalHypotenuse * Math.cos(upperLeft.bearingTo(lowerRight) * Math.PI / OneEightyDeg);
        double currentPixelY = currentDistanceY / totalDistanceY * ImageSizeH;

        double hypotenuse2 = upperLeft.distanceTo(current);
        double bearing2 = upperLeft.bearingTo(current);
        double currentDistanceX = Math.sin(bearing2 * Math.PI / OneEightyDeg) * hypotenuse2;
        //                           "percentage to mark the position"
        double totalHypotenuse2 = upperLeft.distanceTo(lowerRight);
        double totalDistanceX = totalHypotenuse2 * Math.sin(upperLeft.bearingTo(lowerRight) * Math.PI / OneEightyDeg);
        double currentPixelX = currentDistanceX / totalDistanceX * ImageSizeW;

        return new double[]{currentPixelX, currentPixelY};

    }catch(Exception e){

        e.printStackTrace();
        return new double[]{0,0};

    }

【问题讨论】:

    标签: android gps android-canvas


    【解决方案1】:

    首先,将您的谷歌地图坐标映射到您的自定义图像,就好像图像没有倾斜一样。在这里,您基本上是在处理缩放和偏移。假设你得到的坐标是(x, y)

    然后,根据以下矩阵旋转坐标:Rotate a point around origin。由于您已经知道角度,因此您知道/可以计算自定义地图旋转的中心点坐标。假设它是(a, b)。具体来说:

    1) 将您的地图坐标 (x, y) 转换为基于 (0,0) 的坐标,(x-a, y-b)

    2) 使用该矩阵进行旋转,您就有了一个新坐标(x', y')

    3) 将其转回基于(a, b) 的坐标,(x'+a, y'+b)

    【讨论】:

    • 我对您的建议有一些疑问。首先,我没有使用谷歌地图,所以我没有谷歌地图坐标。我确实有设备的位置。其次,我如何将地图坐标转换为基于 0,0 的坐标?以什么方式?当我决定在哪里绘制它时,它基本上已经是 x,y 了。你是说做我在我的问题中提出的数学,取x,y然后转换它?还有a,b .....这些是我用作地图的图像的中心吗?
    • @Jamesandresakis 问题是您需要弄清楚您的自定义地图是如何旋转的。因此,如果它只是在屏幕上旋转,那么 (a,b) 将是图像的中心点,因为您的图像以 (a, b) 为轴心旋转。在这种情况下,(0,0) 将是屏幕的左上角。所以你有你的网格对齐坐标,并将其映射到你的画布,就好像它太网格对齐一样,然后通过旋转变换该坐标,绘制最终结果。
    • @Jamesandresakis 你不必转换为 (0,0)。这只是数学的细分。我认为有一句话总结了它,但我不记得了。但是这个想法是存在的。您围绕图像旋转的点旋转坐标。
    • 如何获得角度,然后用它做什么?
    • @Jamesandresakis 我以为你已经有角度了?它可以是弧度或度数。没关系,只要你能算出 Sin 和 Cos。
    【解决方案2】:

    我可能完全错了,但我认为这是一种获取旋转角度(或者可能是 4 个角)的方法:

    1. 获取lowerRight 和upperLeft 之间的角度alpha。我猜这等于180 - lowerRight.bearingTo(upperLeft) EDIT(这个等式应该取决于屏幕的象限)
    2. 使用您的 X、Y(屏幕)坐标来获得斜边和下边缘之间的角度 theta。我想(再次)这个角度的正弦等于:(height) / ((height^2) + (width^2))^1/2
    3. 现在旋转角度等于theta - alpha

    如果您想将其可视化:

    【讨论】:

    • 好的,但是一旦有了角度,我该怎么做。我之前在代码中有这个,我认为我没有正确使用角度,因为我最终绘制了代表用户位置的圆圈,它会关闭,但看起来方向像 45 度一样移动
    【解决方案3】:

    我不确定我是否理解您的问题,但您不能像这样从 API 中获取 (X, Y) 位置吗?

    // myMap is a GoogleMap instance and location is a Location instance
    Projection projection = myMap.getProjection();
    LatLng latlng = new LatLng(location.getLatitude(), location.getLongitude());
    Point pointInTheScreen = projection.toScreenLocation(latlng);
    

    有关详细信息,请参阅GoogleMap API。

    【讨论】:

    • 我没有使用谷歌地图 API。我在自定义图像视图中绘制所有这些内容,该图像视图通过捏合和缩放进行缩放,我可以使用画布在图像上绘制。
    【解决方案4】:

    是的,您可以绘制不在可见地图上的点。通过设置 LatLngBounds 来解决这个问题。然后显示 LatLngBounds 的地图。您还可以移动地图以显示 LatLngBounds。这里没有什么棘手的问题,没有切线、斜坡或地球的双曲线曲率。所有这些都以度为单位进行处理,因此不要过度考虑您的解决方案。如果你转动地图,点就会随之转动。因此,将您的点添加到地图上,找到边界并倾斜相机。将相机向后倾斜,所有点仍将在屏幕上!这将使您从屏幕上的所有点开始。

    与示例获取对谷歌地图的引用相同。

    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;
    

    LatLngBounds 的字段和 LatLngBounds.Builder

    private LatLngBounds bounds;
    private LatLngBounds.Builder myLatLngBuilder;
    

    初始化 LatLngBounds.Builder

    myLatLngBuilder = new LatLngBounds.Builder();
    

    地图上的每个点。

    LatLng myLatLng = new LatLng(latitude, longitude);
    myLatLngBuilder.include(myLatLng);
    

    然后当你完成添加点建立你的边界。

    bounds = myLatLngBuilder.build();
    

    现在我有了地图上所有点的边界,我可以只显示地图的那个区域。我从地图示例中提取的这段代码。

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

    这基本上就是我的应用程序 Bestrides KML Reader 显示地图的方式,因此没有任何点在屏幕之外。

    祝你好运 丹尼117

    【讨论】:

    • @James 我刚刚看到你没有使用谷歌地图,所以你应该把 android 从标题中去掉,这让我相信了一些不同的东西。
    【解决方案5】:

    您可以使用Magnetic Field sensor(又名指南针)来获取设备的方向,然后将您的自定义视图“网格对齐”到您的地图。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多