Android:如何:将当前位置标记到地图中(静态图像) - 源代码、测试用例、实际、已添加预期输出

发布于 2024-11-29 14:34:55 字数 8011 浏览 1 评论 0原文

我创建了另一个问题(如何显示具有移动当前位置的地图(静态图像文件)

但它包含 2(两)个问题,所以我需要将其隔离。

我正在尝试创建一个可以引导人们到达目的地的原型。

  • 地方是一栋宽阔的建筑,有几层楼。
  • 我可以获取/检索地图(静态图像)。 例如当前:1F 目的地:5F;这样我就可以获得1楼、2楼...5楼的静态图像(5个图像文件)。

场景:

  1. 启动应用程序
  2. 输入当前位置(或者可以使用当前位置自动设置) ) &目的地
  3. 单击搜索路线按钮来搜索要使用的地图(静态图像)&标记当前位置并目的地
  4. 在移动/前往目的地时更新当前位置

问题: 我可以通过 WiFi/手机信号塔/IP 地址获取当前位置坐标,但不知道如何将其放入静态图像中来标记当前位置。

您能分享一下概念/想法吗或包含代码片段。对我的论文有很大帮助。

任何关于正确方向的指导都值得赞赏。


更新

具有实际、预期输出、测试用例的实际示例 (这里的代码包来自mapsforge)

MercatorProjectionClass.java

/**
 * A performance optimized implementation of the spherical Mercator projection.
 */
class MercatorProjectionClass {
    /**
     * Width and height of a map tile in pixel.
     */
    static final int TILE_SIZE = 256;

    /**
     * Converts a latitude coordinate (in degrees) to a pixel Y coordinate at a certain zoom level.
     * 
     * @param latitude
     *            the latitude coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the pixel Y coordinate of the latitude value.
     */
    static double latitudeToPixelY(double latitude, byte zoom) {
        double sinLatitude = Math.sin(latitude * (Math.PI / 180));
        return (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI))
                * ((long) TILE_SIZE << zoom);
    }

    /**
     * Converts a latitude coordinate (in degrees) to a tile Y number at a certain zoom level.
     * 
     * @param latitude
     *            the latitude coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the tile Y number of the latitude value.
     */
    static long latitudeToTileY(double latitude, byte zoom) {
        return pixelYToTileY(latitudeToPixelY(latitude, zoom), zoom);
    }

    /**
     * Converts a longitude coordinate (in degrees) to a pixel X coordinate at a certain zoom level.
     * 
     * @param longitude
     *            the longitude coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the pixel X coordinate of the longitude value.
     */
    static double longitudeToPixelX(double longitude, byte zoom) {
        return (longitude + 180) / 360 * ((long) TILE_SIZE << zoom);
    }

    /**
     * Converts a longitude coordinate (in degrees) to the tile X number at a certain zoom level.
     * 
     * @param longitude
     *            the longitude coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the tile X number of the longitude value.
     */
    static long longitudeToTileX(double longitude, byte zoom) {
        return pixelXToTileX(longitudeToPixelX(longitude, zoom), zoom);
    }

    /**
     * Converts a pixel X coordinate at a certain zoom level to a longitude coordinate.
     * 
     * @param pixelX
     *            the pixel X coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the longitude value of the pixel X coordinate.
     */
    static double pixelXToLongitude(double pixelX, byte zoom) {
        return 360 * ((pixelX / ((long) TILE_SIZE << zoom)) - 0.5);
    }

    /**
     * Converts a pixel X coordinate to the tile X number.
     * 
     * @param pixelX
     *            the pixel X coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the tile X number.
     */
    static long pixelXToTileX(double pixelX, byte zoom) {
        return (long) Math.min(Math.max(pixelX / TILE_SIZE, 0), Math.pow(2, zoom) - 1);
    }

    /**
     * Converts a pixel Y coordinate at a certain zoom level to a latitude coordinate.
     * 
     * @param pixelY
     *            the pixel Y coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the latitude value of the pixel Y coordinate.
     */
    static double pixelYToLatitude(double pixelY, byte zoom) {
        double y = 0.5 - (pixelY / ((long) TILE_SIZE << zoom));
        return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
    }

    /**
     * Converts a pixel Y coordinate to the tile Y number.
     * 
     * @param pixelY
     *            the pixel Y coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the tile Y number.
     */
    static long pixelYToTileY(double pixelY, byte zoom) {
        return (long) Math.min(Math.max(pixelY / TILE_SIZE, 0), Math.pow(2, zoom) - 1);
    }

    private static final byte ZOOM_LEVEL = 14;

    /**
     * @param args
     */
    public static void main(String[] args) {
        // Pixel Coordinate of Chicago,IL
        double pixel_y = 1559345;
        double pixel_x = 1075954;
        // Lat Lng of Chicago,IL
        double lat_y = 41.850033;
        double lng_x = -87.65005229999997; 

        testPixelXYToLatitude(pixel_y, pixel_x, lat_y, lng_x);
        testLatLngToPixelXY(pixel_y, pixel_x, lat_y, lng_x);
    }

    private static void testPixelXYToLatitude(
            double pixel_y, double pixel_x, 
            double lat_y, double lng_x) {

        double actual_lat_y = MercatorProjectionClass.pixelYToLatitude(pixel_y, ZOOM_LEVEL);
        double actual_lng_x = MercatorProjectionClass.pixelXToLongitude(pixel_x, ZOOM_LEVEL);

        String expectedstr_lat_y = Double.toString(lat_y).substring(0, 5);
        String expectedstr_lng_x = Double.toString(lng_x).substring(0, 6);

        String actualstr_lat_y = Double.toString(actual_lat_y).substring(0, 5);
        String actualstr_lng_x = Double.toString(actual_lng_x).substring(0, 6);

        String result = (actualstr_lat_y.equals(expectedstr_lat_y) && actualstr_lng_x.equals(expectedstr_lng_x))?"PASSED":"FAILED"; 
        System.out.println("PixelXYToLatitude test result:" + result);
    }

    private static void testLatLngToPixelXY(
            double pixel_y, double pixel_x, 
            double lat_y, double lng_x) {

        double actual_pixel_y = MercatorProjectionClass.latitudeToPixelY(lat_y, ZOOM_LEVEL);
        double actual_pixel_x = MercatorProjectionClass.longitudeToPixelX(lng_x, ZOOM_LEVEL);

        String expectedstr_pixel_y = Integer.toString((Double.valueOf(pixel_y).intValue()));
        String expectedstr_pixel_x = Integer.toString((Double.valueOf(pixel_x).intValue()));

        String actualstr_pixel_y = Integer.toString(Double.valueOf(actual_pixel_y).intValue());
        String actualstr_pixel_x = Integer.toString(Double.valueOf(actual_pixel_x).intValue());

        String result = (actualstr_pixel_y.equals(expectedstr_pixel_y) && actualstr_pixel_x.equals(expectedstr_pixel_x))?"PASSED":"FAILED"; 
        System.out.println("LatLngToPixelXY test result:" + result);
    }
}

上面代码的输出:

  • PixelXYToLatitude 测试结果:通过
  • LatLngToPixelXY 测试结果:通过

我已经有了将 LatLng 转换为 Pixel 的投影类。 我现在的问题是如何使用上面的类标记给定 LatLng 的静态图像。

这是我的静态图像(伊利诺伊州芝加哥):

这是我的静态图像(伊利诺伊州芝加哥)

我想做一个标记(这是示例,但稍后需要将气球更改为较小的指针)

我想做一个标记(这是示例,但将气球更改为指针)

I have created another question (How to display a map (still image file) with a moving current location)

But it contains 2 (two) questions, so i need to segregate it.

I am trying to create a prototype that could guide a person to his destination place.

  • place is a wide building with several floors.
  • i can obtain/retrieve the maps (still images). e.g. current:1F destination:5F; so I can get the still images of 1st,2nd...5th floors (5 image files).

Scenario:

  1. start the application
  2. input the current location (or may automatically set using current location) & destination
  3. click the search route button to search the maps to use (still images) & mark the current location & destination
  4. update the current location upon moving/going to destination

Problem:
I can get the current location coordinate via WiFi/cell tower/ip address but don't know how to put it into still image to mark the current location.

Would you share the concepts/ideas or include the code snippets. Big Help with my thesis.

Any guidance on the right direction is appreciated.


UPDATE

Actual Example with Actual,Expected Output,Test Case
(parcel of codes here has gotten from mapsforge)

MercatorProjectionClass.java

/**
 * A performance optimized implementation of the spherical Mercator projection.
 */
class MercatorProjectionClass {
    /**
     * Width and height of a map tile in pixel.
     */
    static final int TILE_SIZE = 256;

    /**
     * Converts a latitude coordinate (in degrees) to a pixel Y coordinate at a certain zoom level.
     * 
     * @param latitude
     *            the latitude coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the pixel Y coordinate of the latitude value.
     */
    static double latitudeToPixelY(double latitude, byte zoom) {
        double sinLatitude = Math.sin(latitude * (Math.PI / 180));
        return (0.5 - Math.log((1 + sinLatitude) / (1 - sinLatitude)) / (4 * Math.PI))
                * ((long) TILE_SIZE << zoom);
    }

    /**
     * Converts a latitude coordinate (in degrees) to a tile Y number at a certain zoom level.
     * 
     * @param latitude
     *            the latitude coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the tile Y number of the latitude value.
     */
    static long latitudeToTileY(double latitude, byte zoom) {
        return pixelYToTileY(latitudeToPixelY(latitude, zoom), zoom);
    }

    /**
     * Converts a longitude coordinate (in degrees) to a pixel X coordinate at a certain zoom level.
     * 
     * @param longitude
     *            the longitude coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the pixel X coordinate of the longitude value.
     */
    static double longitudeToPixelX(double longitude, byte zoom) {
        return (longitude + 180) / 360 * ((long) TILE_SIZE << zoom);
    }

    /**
     * Converts a longitude coordinate (in degrees) to the tile X number at a certain zoom level.
     * 
     * @param longitude
     *            the longitude coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the tile X number of the longitude value.
     */
    static long longitudeToTileX(double longitude, byte zoom) {
        return pixelXToTileX(longitudeToPixelX(longitude, zoom), zoom);
    }

    /**
     * Converts a pixel X coordinate at a certain zoom level to a longitude coordinate.
     * 
     * @param pixelX
     *            the pixel X coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the longitude value of the pixel X coordinate.
     */
    static double pixelXToLongitude(double pixelX, byte zoom) {
        return 360 * ((pixelX / ((long) TILE_SIZE << zoom)) - 0.5);
    }

    /**
     * Converts a pixel X coordinate to the tile X number.
     * 
     * @param pixelX
     *            the pixel X coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the tile X number.
     */
    static long pixelXToTileX(double pixelX, byte zoom) {
        return (long) Math.min(Math.max(pixelX / TILE_SIZE, 0), Math.pow(2, zoom) - 1);
    }

    /**
     * Converts a pixel Y coordinate at a certain zoom level to a latitude coordinate.
     * 
     * @param pixelY
     *            the pixel Y coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the latitude value of the pixel Y coordinate.
     */
    static double pixelYToLatitude(double pixelY, byte zoom) {
        double y = 0.5 - (pixelY / ((long) TILE_SIZE << zoom));
        return 90 - 360 * Math.atan(Math.exp(-y * (2 * Math.PI))) / Math.PI;
    }

    /**
     * Converts a pixel Y coordinate to the tile Y number.
     * 
     * @param pixelY
     *            the pixel Y coordinate that should be converted.
     * @param zoom
     *            the zoom level at which the coordinate should be converted.
     * @return the tile Y number.
     */
    static long pixelYToTileY(double pixelY, byte zoom) {
        return (long) Math.min(Math.max(pixelY / TILE_SIZE, 0), Math.pow(2, zoom) - 1);
    }

    private static final byte ZOOM_LEVEL = 14;

    /**
     * @param args
     */
    public static void main(String[] args) {
        // Pixel Coordinate of Chicago,IL
        double pixel_y = 1559345;
        double pixel_x = 1075954;
        // Lat Lng of Chicago,IL
        double lat_y = 41.850033;
        double lng_x = -87.65005229999997; 

        testPixelXYToLatitude(pixel_y, pixel_x, lat_y, lng_x);
        testLatLngToPixelXY(pixel_y, pixel_x, lat_y, lng_x);
    }

    private static void testPixelXYToLatitude(
            double pixel_y, double pixel_x, 
            double lat_y, double lng_x) {

        double actual_lat_y = MercatorProjectionClass.pixelYToLatitude(pixel_y, ZOOM_LEVEL);
        double actual_lng_x = MercatorProjectionClass.pixelXToLongitude(pixel_x, ZOOM_LEVEL);

        String expectedstr_lat_y = Double.toString(lat_y).substring(0, 5);
        String expectedstr_lng_x = Double.toString(lng_x).substring(0, 6);

        String actualstr_lat_y = Double.toString(actual_lat_y).substring(0, 5);
        String actualstr_lng_x = Double.toString(actual_lng_x).substring(0, 6);

        String result = (actualstr_lat_y.equals(expectedstr_lat_y) && actualstr_lng_x.equals(expectedstr_lng_x))?"PASSED":"FAILED"; 
        System.out.println("PixelXYToLatitude test result:" + result);
    }

    private static void testLatLngToPixelXY(
            double pixel_y, double pixel_x, 
            double lat_y, double lng_x) {

        double actual_pixel_y = MercatorProjectionClass.latitudeToPixelY(lat_y, ZOOM_LEVEL);
        double actual_pixel_x = MercatorProjectionClass.longitudeToPixelX(lng_x, ZOOM_LEVEL);

        String expectedstr_pixel_y = Integer.toString((Double.valueOf(pixel_y).intValue()));
        String expectedstr_pixel_x = Integer.toString((Double.valueOf(pixel_x).intValue()));

        String actualstr_pixel_y = Integer.toString(Double.valueOf(actual_pixel_y).intValue());
        String actualstr_pixel_x = Integer.toString(Double.valueOf(actual_pixel_x).intValue());

        String result = (actualstr_pixel_y.equals(expectedstr_pixel_y) && actualstr_pixel_x.equals(expectedstr_pixel_x))?"PASSED":"FAILED"; 
        System.out.println("LatLngToPixelXY test result:" + result);
    }
}

Output of the above code:

  • PixelXYToLatitude test result:PASSED
  • LatLngToPixelXY test result:PASSED

I have already the projection class to convert LatLng to Pixel.
My Problem now is on how to mark into still image of a given LatLng using the above class.

Here's my still image (Chicago,IL):

Here's my still image (Chicago,IL)

I want to put a mark (here's the example but later on need to change the balloon to smaller pointer)

I want to put a mark (here's the example but change the balloon to pointer)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

别把无礼当个性 2024-12-06 14:34:55

据我了解,您在这里面临一些问题。

  • 使用具有离线图块的地图控制器

  • 在地图上标记当前位置

  • 从点引导用户A 到 B 点


地图控制器

基本上,Android 上的位置提供程序将为您的应用程序提供一些全球定位坐标(经度和纬度),然后您想要在其后面放置一个背景,以便用户可以看到他的 地点。您将静止图像放在那里的想法是正确的,但我建议的更正(这是它在每个商业或非商业产品上的工作方式)是将大图像分割成较小的部分,以便地图控制器不必将大图像加载到内存中。 512 x 512 听起来像是一个合理的尺寸(Google 地图使用 256 x 256)。这些较大图像的块称为图块。

对于谷歌地图,不可能使用离线图块。我写了一篇帖子,介绍如何使用 OSMDroid (这是最好的开源替代方案)和 另一篇文章与ArcGIS(免费地图控制器Android,商业地图图块;这个控制器的一切都很棒,但在我看来,它对于论文项目来说负载太大了)。

因此,此处重现的步骤是:

  • 将大文件分成较小的部分,
  • 找到大图像边缘的确切坐标,以准确了解如何命名图块(地图控制器查找按名称覆盖视口一部分所需的图块)
  • 使用您的图像实现离线图块提供程序

位置提供程序

在我看来,这是最难的部分。您如何准确地找到设备在建筑物中的确切位置? GPS 在一定程度上可以提供帮助,但在建筑物中无论如何它都不可能精确。 ArcGIS 为您提供了一个非常好的内置位置提供程序,在任何其他解决方案上您都必须自己实现它。一旦您设法克服这个问题,您还可以使用位置提供商提供的海拔高度在楼层之间自动切换。

路由

要使用 OSMDroid(以及 ArcGIS)表示路由线就像一块巧克力蛋糕:创建一个转折点数组,从一个点到另一个点绘制一条线,并将该线放在地图。困难的部分是创建一个路由算法,祝你好运!

From what I understood, you are facing a few problems here.

  • Use a map controller with offline tiles

  • Mark the current location on the map

  • Route the user from point A to point B


Map controller

Basically, the location providers on Android will be feeding your application with some global positioning coordinates (longitude and latitude) and you want to put a background behind it so that the user has a visual on his location. Your idea to put a still image there is right, but a correction I would suggest (and this is the way it works on every commercial, or non-commercial, product) is to split the large images into smaller parts, so that the map controller wouldn't have to load a large image into memory. 512 x 512 sounds like a reasonable size (Google maps uses 256 x 256). These chunks of larger images are called tiles.

With Google maps it's impossible to use offline tiles. I've written a post on how to do that for Google maps with OSMDroid (this is the best open source alternative) and another post with ArcGIS (free map controller for Android, commercial map tiles; everything is awesome with this controller but in my opinion it's too loaded for a thesis project).

So, the steps to reproduce here are:

  • chunk big files into smaller parts
  • find the exact coordinates of the edges of your big images to know exactly how to name the tiles (map controllers find tiles required to cover a portion of the viewport by names)
  • implement an offline tile provider with your images

Location provider

This, in my opinion is the hardest part. How exactly are you going to find the exact position of a device in a building? GPS can be of a help to a certain extent, but it can't be precise in a building anyway. ArcGIS provides you with a very nice built-in location provider, on any other solution you'll have to implement it on your own. As soon as you manage to overcome this problem you can also use the altitude provided by the location providers to switch between the floors automatically.

Routing

To represent a routing line with OSMDroid (well, with ArcGIS as well) is a piece of chocolate cake: create an array of turn points, draw a line from one point to another and put that line on the map. The hard part is to create a routing algorithm, good luck with that!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文