0

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)

Community
  • 1
  • 1
eros
  • 4,946
  • 18
  • 53
  • 78

1 Answers1

1

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!

Ilya Saunkin
  • 18,934
  • 9
  • 36
  • 50
  • (1) "chunk big files into smaller parts" - the actual floor plan images are small. (2) "find the exact coordinates of the edges of your big images" - how can I find the exact coordinates of every edges of my image map? Is there a tool to extract the exact coordinates? – eros Aug 18 '11 at 06:37
  • 1
    (1) Small images = just awesome. Though it sort of loses the point if the building plan is smaller than the maximum GPS accuracy (1-2 meters). (2) Even if there is such a tool, I'm afraid I haven't heard of it. What you can do easily is to locate the building online on Google Maps and drop latlng markers on its corners, you'll find a very good estimation. Another way is to go to the actual building and record the coordinates on its corners provided by a GPS. – Ilya Saunkin Aug 18 '11 at 06:43
  • "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." - you already answered my next question. how do you know on what floors a person standing in by using the provided altitude? – eros Aug 18 '11 at 06:49
  • (1) I will consider the minimum GPS accuracy - thanks. (2) ohh I see, it's that simple. Thanks again. (3) Would you guide me on how to solve my problem by the given example. let's say the UPPERLEFT & LOWERRIGHT Lat Lng of the image are given. – eros Aug 18 '11 at 06:51
  • 1
    If longitude is the X axis, latitude is the Y axis, then altitude is the Z axis, where the sea level is 0, i.e. altitude is the distance from the sea level to current position in meters. You measure the height of each floor and that's how you can calculate... – Ilya Saunkin Aug 18 '11 at 06:57
  • Cool~. sea level is the groud of the building then compute it against to actual floor's height. Thanks. If you have more time, would you guide me on how to solve my problem by the given example. It's my ultimate question here. please refer to the above comment (3). – eros Aug 18 '11 at 07:05
  • oh sorry, just saw your (3). So, what's the problem with the given example? – Ilya Saunkin Aug 18 '11 at 07:05
  • I got the estimated Lat Lng of the given still image. How can I point out the location in the still image using a given Lat Lng (consider that exact values) – eros Aug 18 '11 at 07:07
  • If you can see, it's able to convert to actual pixel coordinate(PX) of the given actual Lat Lng (same output of the Chicago,IL still image with balloon above). Because the google has the big image and i have only a parcel static image map of it. The result PX is too large values because it is based on the whole map. Thus, from the result PX, I need to recompute it against with my still image. Do you have idea on how to recompute it to find the same location in my still image? – eros Aug 18 '11 at 07:13
  • 1
    whoa whoa, slow yo ride! Why would you need to convert GPS coordinates into pixels? Your methods are converting into screen coordinates (screen is your viewport). For a map controller to do that, it takes to know the coordinates of the corner tile, then shift those coordinates by some amount depending on the scrolled position. It seems that you are trying to implement a map controller on your own and unless there is a requirement I'd suggest you take the easy way and use some ready library. – Ilya Saunkin Aug 18 '11 at 07:31
  • The mapController will do that. Just provide the output from the above MercatorProjectionClass then pass to mapController. ahm... another Class (mapController) need to study. Thanks a lot. if you have sample projects (eclipse project), please share with us. Again Thanks – eros Aug 18 '11 at 08:03
  • (4) " It seems that you are trying to implement a map controller on your own and unless there is a requirement I'd suggest you take the easy way and use some ready library." - The library that you are saying is OSMDroid? – eros Aug 18 '11 at 08:14
  • From my experience, osmdroid is the most complete and easy to use. It was intended as a replacement for Google maps, so the architecture and syntax is exactly the same. We can take it to the chat if you feel like I would be of any help. – Ilya Saunkin Aug 18 '11 at 08:20
  • currently, I don't have android eclipse project yet to start. I am collecting computations,methods,classes that may use when I start to create the project. I understand the fundamentals of Android (activity,service,etc..) but don't have idea concerning to Map Location. (5) May I contact you when I got home to start the android project? I just need to display the still image map and mark the given Lat Lng. – eros Aug 18 '11 at 08:34
  • sure thing, contact me here or @esaounkine on twitter – Ilya Saunkin Aug 18 '11 at 08:55
  • I just took a look at the OSMDroid documentation. Unfortunately, there are several classes & methods has no comments. For sure I need some guide to adopt the OSMDroid library. I've never been use the SO Chat, hoping that you are available that time (3hours from now). Thanks a lot and I appreciate all your effort to share your knowledge. I'll contribute also in the near future. – eros Aug 18 '11 at 08:56