ใช้ไทล์แผนที่ที่กำหนดเองกับ Google Map API V2 สำหรับ Android


10

ฉันกำลังมองหาวิธีใช้ไทล์แผนที่ที่กำหนดเองกับ Google Map API V2 สำหรับ Android

ฉันกำลังเขียนแอปพลิเคชันที่จะสร้างแผนที่ของตัวเองแบบเรียลไทม์ด้วยข้อมูลที่มาจากหุ่นยนต์

แอปพลิเคชันต้องแสดงให้ผู้ประกอบการแผนที่นี้ ผู้ประกอบการจำเป็นต้องมีปฏิสัมพันธ์กับแผนที่นี้ปล่อยให้ชี้ทาง ฯลฯ

ฉันต้องการใช้เครื่องมือ GoogleMap เพื่อทำสิ่งเดียวกันกับหน้านี้:

http://cdn.mikecouturier.com/blog.mikecouturier.com/tilesgenerator/index.html

ปัญหาคือเขาใช้Javascript APIเมื่อฉันต้องการใช้Android API

มีวิธีการใช้แผนที่แบบกำหนดเองบน Android กับเครื่องสร้าง Google แผนที่หรือไม่?

ฉันได้ดูวิธีใช้ ArcGIS แล้ว แต่ฉันชอบใช้ API โดยไม่ต้องเสียค่าลิขสิทธิ์

คำตอบ:


8

ใช่คุณสามารถใช้กระเบื้องที่กำหนดเองกับAndroid Maps API v2 - คุณสามารถดูตัวอย่างการทำงานอย่างเต็มที่ในของเราOpenTripPlanner สำหรับ Android app บน Github (คุณสามารถดาวน์โหลดแอพได้โดยตรงจาก Google Play )

เราสนับสนุนผู้ให้บริการไทล์ต่อไปนี้:

  • LyrkOpenStreetMap
  • MapQuestOpenStreetMap
  • Mapnik
  • CycleMap
  • Google (ปกติ, ดาวเทียม, ไฮบริด, ภูมิประเทศ)

ชั้น CustomUrlTileProvider ของเราสามารถเห็นได้ที่นี่ใน Githubและฉันยังวางไว้ด้านล่าง:

public class CustomUrlTileProvider extends UrlTileProvider {

    private String baseUrl;

    public CustomUrlTileProvider(int width, int height, String url) {
        super(width, height);
        this.baseUrl = url;
    }

    @Override
    public URL getTileUrl(int x, int y, int zoom) {
        try {
            return new URL(baseUrl.replace("{z}", "" + zoom).replace("{x}", "" + x)
                    .replace("{y}", "" + y));
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return null;
    }
}

และนี่คือรหัสที่สลับระหว่างผู้ให้บริการไทล์แผนที่ตามการตั้งค่าของผู้ใช้:

/**
 * Changes the tiles used to display the map and sets max zoom level.
 *
 * @param overlayString tiles URL for custom tiles or description for
 *                      Google ones
 */
public void updateOverlay(String overlayString) {
    int tile_width = OTPApp.CUSTOM_MAP_TILE_SMALL_WIDTH;
    int tile_height = OTPApp.CUSTOM_MAP_TILE_SMALL_HEIGHT;

    if (overlayString == null) {
        overlayString = mPrefs.getString(OTPApp.PREFERENCE_KEY_MAP_TILE_SOURCE,
                mApplicationContext.getResources()
                        .getString(R.string.map_tiles_default_server));
    }
    if (mSelectedTileOverlay != null) {
        mSelectedTileOverlay.remove();
    }
    if (overlayString.startsWith(OTPApp.MAP_TILE_GOOGLE)) {
        int mapType = GoogleMap.MAP_TYPE_NORMAL;

        if (overlayString.equals(OTPApp.MAP_TILE_GOOGLE_HYBRID)) {
            mapType = GoogleMap.MAP_TYPE_HYBRID;
        } else if (overlayString.equals(OTPApp.MAP_TILE_GOOGLE_NORMAL)) {
            mapType = GoogleMap.MAP_TYPE_NORMAL;
        } else if (overlayString.equals(OTPApp.MAP_TILE_GOOGLE_TERRAIN)) {
            mapType = GoogleMap.MAP_TYPE_TERRAIN;
        } else if (overlayString.equals(OTPApp.MAP_TILE_GOOGLE_SATELLITE)) {
            mapType = GoogleMap.MAP_TYPE_SATELLITE;
        }
        mMap.setMapType(mapType);
        mMaxZoomLevel = mMap.getMaxZoomLevel();
    } else {
        if (overlayString.equals(getResources().getString(R.string.tiles_mapnik))) {
            mMaxZoomLevel = getResources().getInteger(R.integer.tiles_mapnik_max_zoom);
        } else if (overlayString.equals(getResources().getString(R.string.tiles_lyrk))) {
            mMaxZoomLevel = getResources().getInteger(R.integer.tiles_lyrk_max_zoom);
            tile_width = OTPApp.CUSTOM_MAP_TILE_BIG_WIDTH;
            tile_height = OTPApp.CUSTOM_MAP_TILE_BIG_HEIGHT;
        } else {
            mMaxZoomLevel = getResources().getInteger(R.integer.tiles_maquest_max_zoom);
        }

        mMap.setMapType(GoogleMap.MAP_TYPE_NONE);
        CustomUrlTileProvider mTileProvider = new CustomUrlTileProvider(
                tile_width,
                tile_height, overlayString);
        mSelectedTileOverlay = mMap.addTileOverlay(
                new TileOverlayOptions().tileProvider(mTileProvider)
                        .zIndex(OTPApp.CUSTOM_MAP_TILE_Z_INDEX));

        if (mMap.getCameraPosition().zoom > mMaxZoomLevel) {
            mMap.moveCamera(CameraUpdateFactory.zoomTo(mMaxZoomLevel));
        }
    }
}

นี่คือภาพหน้าจอของไทล์ MapQuest OpenStreetMap: ป้อนคำอธิบายรูปภาพที่นี่

สำหรับข้อมูลเพิ่มเติมเกี่ยวกับการทำให้กระเบื้องของคุณเองให้ดูที่เอกสารของ Google สำหรับ TileOverlayเช่นเดียวกับวิกิพีเดีย OpenStreetMap สำหรับ "การสร้างกระเบื้องของคุณเอง"

เอกสารของ Google ระบุว่า:

โปรดทราบว่าโลกคาดการณ์โดยใช้การฉายภาพ Mercator (ดู Wikipedia) กับด้านซ้าย (ตะวันตก) ของแผนที่ที่สอดคล้องกับลองจิจูด -180 องศาและด้านขวา (ตะวันออก) ของแผนที่ที่สอดคล้องกับลองจิจูด 180 องศา ในการทำให้จตุรัสแผนที่ด้านบนสุด (ทิศเหนือ) ของแผนที่สอดคล้องกับละติจูดลองจิจูดที่ 85.0511 และด้านล่าง (ทิศใต้) ของแผนที่สอดคล้องกับละติจูด -85.0511 องศา พื้นที่ที่อยู่นอกช่วงละติจูดนี้จะไม่แสดงผล

ในแต่ละระดับการซูมแผนที่จะแบ่งเป็นไทล์และจะมีการดาวน์โหลดและแสดงผลไทล์ที่ซ้อนทับหน้าจอเท่านั้น กระเบื้องแต่ละแผ่นเป็นสี่เหลี่ยมจัตุรัสและแผนที่แบ่งออกเป็นกระเบื้องดังนี้:

  • ที่ระดับการซูม 0 หนึ่งไทล์หมายถึงทั้งโลก พิกัดของไทล์นั้นคือ (x, y) = (0, 0)

  • ที่ระดับการซูม 1 โลกจะถูกแบ่งออกเป็น 4 ไทล์เรียงกันในตาราง 2 x 2 ...

  • ที่ระดับการซูม N โลกจะถูกแบ่งออกเป็นไทล์ 4N เรียงในตาราง 2N x 2N

โปรดทราบว่าระดับการซูมขั้นต่ำที่กล้องรองรับ (ซึ่งขึ้นอยู่กับปัจจัยหลายอย่าง) คือ GoogleMap.getMinZoomLevel และระดับการซูมสูงสุดคือ GoogleMap.getMaxZoomLevel

พิกัดของแผ่นกระเบื้องวัดจากมุมบนซ้าย (ตะวันตกเฉียงเหนือ) ของแผนที่ ที่ระดับการซูม N ค่า x ของระยะพิกัดของกระเบื้องจะอยู่ระหว่าง 0 ถึง 2N - 1 และเพิ่มขึ้นจากทิศตะวันตกเป็นทิศตะวันออกและค่า y มีค่าตั้งแต่ 0 ถึง 2N - 1 และเพิ่มขึ้นจากเหนือจรดใต้

URL ที่จัดรูปแบบที่ใช้ภายใน OTP Android เพื่ออ้างอิงผู้ให้บริการไทล์แต่ละรายมีลักษณะดังนี้:

ดังนั้นสำหรับผู้ให้บริการด้านบนภาพย่อยคือไฟล์ PNG ที่จัดเรียงในโครงสร้างไดเรกทอรีที่ระบุโดยเอกสารของ Google คุณจะทำตามรูปแบบที่คล้ายกันเพื่อสร้างไทล์แผนที่ของคุณเองที่โฮสต์บนเซิร์ฟเวอร์ของคุณเอง โปรดทราบว่า URL / รูปภาพเหล่านี้จะต้องสามารถเข้าถึงได้โดยอุปกรณ์เคลื่อนที่ (เช่นไม่สามารถป้องกันด้วยรหัสผ่าน)


ขอบคุณสำหรับเวลาของคุณ เป็นไปได้ไหมที่ฉันจะใช้รูปภาพที่สร้างขึ้นอย่างสมบูรณ์ในที่เก็บส่วนตัว? รูปแบบของไทล์นั้นคืออะไร? และการอาร์เบอร์
MonkeyJLuffy

@ MonkeyJLuffy ฉันเพิ่งเพิ่มข้อมูลบางอย่างไปยังด้านล่างของคำตอบของฉันสำหรับสิ่งนี้ โปรดแจ้งให้เราทราบหากคุณยังมีคำถามหลังจากอ่านบทความนี้
Sean Barbeau

1

วิธีแก้ปัญหาที่ครอบคลุมที่สุดที่ฉันพบคือคำตอบของ StackOverflow :

โดยทั่วไปคุณต้องใช้TileProviderของคุณเองและใช้เป็นTileOverlay

ในแอพพลิเคชั่นสองสามตัวเราได้ใช้เลเยอร์ชนิดนี้เพื่อแสดงไทล์บนแผนที่ แต่เราพบว่าไทล์ใช้พื้นที่มาก ดังนั้นเราจึงเปลี่ยนเป็นการใช้ mbtiles และไลบรารีนี้เพื่อแสดงข้อมูลจาก mbtiles บนแผนที่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.