如何在谷歌或iOS地图上叠加3D模型?

23

你是在Android还是iOS上尝试做这个?我找到了这个链接:https://developers.google.com/maps/tutorials/kml/ https://developers.google.com/maps/faq?hl=cs#geoxmllimits - Ricky
尝试在Unity3D中使用Vuforia。 - Fattie
请看这里:https://stackoverflow.com/questions/38268273/using-mapkit-in-scenekit,评论中有答案。 - T. Pasichnyk
2个回答

4
尽管这是一个很晚的回答,但我认为以下针对Android/iOS实现的资源应该能够帮助到未来的参考,因为我现在没有看到关于KML/KMZ文件及其结构的详细信息; *如果3D模型只是通过图片编辑工具创建的3D图像,或者创建3D图像符合需求,则可以使用以下解决方案通过Google Maps或Apple Maps(MapKit)SDK加载它们。 Google Maps -- 对于Android

https://developers.google.com/maps/documentation/android-sdk/utility/kml

以下代码取自“https://github.com/googlemaps/android-maps-utils/blob/master/demo/src/com/google/maps/android/utils/demo/KmlDemoActivity.java”。
我仅分享它以可视化实现。
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.maps.android.data.Feature;
import com.google.maps.android.data.kml.KmlContainer;
import com.google.maps.android.data.kml.KmlLayer;
import com.google.maps.android.data.kml.KmlPlacemark;
import com.google.maps.android.data.kml.KmlPolygon;

import org.xmlpull.v1.XmlPullParserException;

import android.os.AsyncTask;
import android.util.Log;
import android.widget.Toast;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

public class KmlDemoActivity extends BaseDemoActivity {

    private GoogleMap mMap;

    protected int getLayoutId() {
        return R.layout.kml_demo;
    }

    public void startDemo () {
        try {
            mMap = getMap();
            //retrieveFileFromResource();
            retrieveFileFromUrl();
        } catch (Exception e) {
            Log.e("Exception caught", e.toString());
        }
    }

    private void retrieveFileFromResource() {
        try {
            KmlLayer kmlLayer = new KmlLayer(mMap, R.raw.campus, getApplicationContext());
            kmlLayer.addLayerToMap();
            moveCameraToKml(kmlLayer);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (XmlPullParserException e) {
            e.printStackTrace();
        }
    }

    private void retrieveFileFromUrl() {
        new DownloadKmlFile(getString(R.string.kml_url)).execute();
    }

    private void moveCameraToKml(KmlLayer kmlLayer) {
        //Retrieve the first container in the KML layer
        KmlContainer container = kmlLayer.getContainers().iterator().next();
        //Retrieve a nested container within the first container
        container = container.getContainers().iterator().next();
        //Retrieve the first placemark in the nested container
        KmlPlacemark placemark = container.getPlacemarks().iterator().next();
        //Retrieve a polygon object in a placemark
        KmlPolygon polygon = (KmlPolygon) placemark.getGeometry();
        //Create LatLngBounds of the outer coordinates of the polygon
        LatLngBounds.Builder builder = new LatLngBounds.Builder();
        for (LatLng latLng : polygon.getOuterBoundaryCoordinates()) {
            builder.include(latLng);
        }

        int width = getResources().getDisplayMetrics().widthPixels;
        int height = getResources().getDisplayMetrics().heightPixels;
        getMap().moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), width, height, 1));
    }

    private class DownloadKmlFile extends AsyncTask<String, Void, byte[]> {
        private final String mUrl;

        public DownloadKmlFile(String url) {
            mUrl = url;
        }

        protected byte[] doInBackground(String... params) {
            try {
                InputStream is =  new URL(mUrl).openStream();
                ByteArrayOutputStream buffer = new ByteArrayOutputStream();
                int nRead;
                byte[] data = new byte[16384];
                while ((nRead = is.read(data, 0, data.length)) != -1) {
                    buffer.write(data, 0, nRead);
                }
                buffer.flush();
                return buffer.toByteArray();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }

        protected void onPostExecute(byte[] byteArr) {
            try {
                KmlLayer kmlLayer = new KmlLayer(mMap, new ByteArrayInputStream(byteArr),
                        getApplicationContext());
                kmlLayer.addLayerToMap();
                kmlLayer.setOnFeatureClickListener(new KmlLayer.OnFeatureClickListener() {
                    @Override
                    public void onFeatureClick(Feature feature) {
                        Toast.makeText(KmlDemoActivity.this,
                                "Feature clicked: " + feature.getId(),
                                Toast.LENGTH_SHORT).show();
                    }
                });
                moveCameraToKml(kmlLayer);
            } catch (XmlPullParserException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

-- 适用于iOS

https://developers.google.com/maps/documentation/ios-sdk/utility/kml-geojson
以下代码摘自上述网址。再次强调,我只是为了可视化实现而分享它。

Swift示例

/** Assume that <Google-Maps-iOS-Utils/GMUGeometryRenderer.h> and
    <Google-Maps-iOS-Utils/GMUKMLParser.h> are in the bridging-header file.
*/
let path = Bundle.main.path(forResource: "KML_Sample", ofType: "kml")
let url = URL(fileURLWithPath: path!)
kmlParser = GMUKMLParser(url: url)
kmlParser.parse()

renderer = GMUGeometryRenderer(map: mapView,
                               geometries: kmlParser.placemarks,
                               styles: kmlParser.styles)

renderer.render()

Objective-C示例

#import "GMUKMLParser.h"
#import "GMUGeometryRenderer.h"
...
NSString *path = [[NSBundle mainBundle] pathForResource:@"KML_Sample" ofType:@"kml"];
NSURL *url = [NSURL fileURLWithPath:path];
GMUKMLParser *parser = [[GMUKMLParser alloc] initWithURL:url];
[parser parse];
GMUGeometryRenderer *renderer = [[GMUGeometryRenderer alloc] initWithMap:_mapView
                                                              geometries:parser.placemarks
                                                                  styles:parser.styles];
[renderer render];

苹果地图(iOS MapKit)

https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/LocationAwarenessPG/MapKit/MapKit.html

但是对于苹果地图,我看到需要像下面这样的解析器来将KML数据结构转换为绘图代码;

https://github.com/mapbox/Simple-KML
https://github.com/mojtabacazi/iOS-KMLParser

您可以使用以下 KMLViewer 实现;(基于 NSXMLParser)

https://github.com/robovm/apple-ios-samples/tree/master/KMLViewer
https://github.com/ooper-shlab/KMLViewer-Swift(还包含 Swift 版本)


否则,如果3D模型确实是由<Model>标签创建的3D模型(3D模型在COLLADA文件(.dae)中描述,并由<link>标签引用),请参见下面来自“https://developers.google.com/kml/documentation/kmlreference#model” 的XML格式;
<Model id="ID">
  <!-- specific to Model -->
  <altitudeMode>clampToGround</altitudeMode>
      <!-- kml:altitudeModeEnum: clampToGround,relativeToGround,or absolute -->
      <!-- or, substitute gx:altitudeMode: clampToSeaFloor, relativeToSeaFloor -->
  <Location>
    <longitude></longitude> <!-- kml:angle180 -->
    <latitude></latitude>   <!-- kml:angle90 -->
    <altitude>0</altitude>  <!-- double -->
  </Location>
  <Orientation>
    <heading>0</heading>    <!-- kml:angle360 -->
    <tilt>0</tilt>          <!-- kml:anglepos180 -->
    <roll>0</roll>          <!-- kml:angle180 -->
  </Orientation>
  <Scale>
    <x>1</x>                <!-- double -->
    <y>1</y>                <!-- double -->
    <z>1</z>                <!-- double -->
  </Scale>
  <Link>...</Link>
  <ResourceMap>
    <Alias>
      <targetHref>...</targetHref>   <!-- anyURI -->
      <sourceHref>...</sourceHref>   <!-- anyURI -->
    </Alias>
  </ResourceMap>
</Model>

支持 KML 的功能 以上图片来自https://developers.google.com/maps/documentation/android-sdk/utility/kml#supported。如图所示,谷歌地图似乎不支持带有标签的3D模型。谷歌地球似乎支持3D模型,但显然不适用于我们的情况。此外,我没有看到iOS MapKit的任何官方支持。

因此,以下解决方案可能适用于真实的3D模型;

在研究时,我遇到了基于OpenStreetMap的OSMBuildings。这是一个JavaScript实现,但也可以通过使用例如Leaflet JS库在移动环境中使用。(为此,KML文件应转换为GeoJSON,并使用“leaflet-omnivore”插件支持3D模型)

https://leafletjs.com
https://github.com/OSMBuildings/OSMBuildings

最后,我发现一个名为MapBox的地图平台可以接受KML格式(通过再次转换为GeoJSON)。这是一种付费选项,但我认为对于小型个人应用程序来说有足够的限制可供免费使用(每月50,000个地图视图)。 (再次基于OpenStreetMap平台,并且似乎支持3D模型)

https://www.mapbox.com/mobile/

尽管可能有其他库或平台可用于使用KML / KMZ,但我认为这些是最适合移动体验的(适用于iOS和Android)。 最后的小提示: KMZ实际上是一个压缩包,其中包含KML,纹理和各种资源。

-1

虽然这是一个老问题,但我认为苹果在文档中有一个示例项目。


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