我有一个KML格式的建筑3D模型,想要在谷歌或苹果地图上导入它,以获取用户位置并查找POI。
我发现谷歌地图v2 [1]: https://developers.google.com/maps/documentation/android/views 支持3D对象。
我有一个KML格式的建筑3D模型,想要在谷歌或苹果地图上导入它,以获取用户位置并查找POI。
我发现谷歌地图v2 [1]: https://developers.google.com/maps/documentation/android/views 支持3D对象。
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)
但是对于苹果地图,我看到需要像下面这样的解析器来将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 版本)
<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>
以上图片来自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