安卓 - 在自定义地图上绘制GPS坐标

7
我在我的应用程序中有一个活动,在其中使用作为地图的图像。如果图像与Google地图“网格对齐”,那么当我使用从在线Google Maps获取的地图左上和右下角时,我可以将用户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};

    }
5个回答

3

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

然后,根据此矩阵旋转您的坐标:围绕原点旋转点。由于您已经知道角度,因此您知道/可以计算出您的自定义地图围绕其旋转的中心点坐标。假设它是(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……是我用作地图的图像的中心吗? - James andresakis
@Jamesandresakis 问题在于你需要弄清楚自定义地图是如何旋转的。如果它只是在屏幕上旋转,那么(a,b)将是您图像的中心点,因为您的图像是以(a,b)作为枢轴旋转的。在这种情况下,(0,0)将是屏幕左上角。因此,您有了对齐的网格坐标,并将其映射到画布上,就好像它也是对齐的网格一样,然后通过旋转转换该坐标,绘制最终结果。 - StoneBird
@Jamesandresakis 不需要转换为 (0,0)。这只是数学的分解。我认为有一些可以总结它的单行代码,但我记不清了。但是这个想法在那里。您围绕正在旋转的图像的点旋转您的坐标。 - StoneBird
我如何获取角度,然后我该怎么做? - James andresakis
@Jamesandresakis 我以为你已经有角度了?它可以是弧度或者角度,无所谓,只要你能计算正弦和余弦。 - StoneBird

1
我可能完全错了,但我认为这是获取旋转角度(或者可能是四个角)的一种方法:
  1. 获取 alpha 角度,即 lowerRight 和 upperLeft 之间的夹角。我猜这等于 180 - lowerRight.bearingTo(upperLeft) 编辑(此方程应取决于屏幕所在象限)。
  2. 使用您的 X、Y(屏幕)坐标获取斜边和下边缘之间的角度 theta。我再次猜测该角度的正弦值等于:(height) / ((height^2) + (width^2))^1/2
  3. 现在旋转角度等于 theta - alpha

如果您想要可视化:

bla


好的,但是我得到角度之后该怎么做呢?我以前在代码中用过这个,但我认为我没有正确地使用角度,因为我绘制代表用户位置的圆圈时它会离开正确位置,而且看起来方向被偏移了约45度。 - James andresakis

0

是的,您可以绘制不在可见地图上的点。通过设置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;

一个用于 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如何显示地图,使得没有任何点离开屏幕。

祝好运 Danny117


@James,我刚刚看到你没有使用谷歌地图,所以你应该把 Android 从标题中移除,这让我误以为它是另外一种应用。 - danny117

0

我不确定我是否理解了你的问题,但是你不能像这样从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以获取更多信息。


我没有使用Google地图API。我是在一个自定义的ImageView中绘制所有内容,该ImageView可以通过捏合和缩放进行缩放,我可以使用画布在图像上绘制。 - James andresakis

-1
你可以使用磁场传感器(也称为指南针)来获取设备的方向,并通过这种方式将你的自定义视图“网格对齐”到你的地图上。

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