如何使用kml文件在地图上绘制path?
我可以parsingkml文件,以显示Android中的path或点? 请帮我一下吗?
这是我想要显示在Android谷歌地图的kml示例代码:
<?xml version="1.0" encoding="UTF-8"?> <kml xmlns="http://www.opengis.net/kml/2.2"> <Document> <name>Paths</name> <description>Examples of paths. Note that the tessellate tag is by default set to 0. If you want to create tessellated lines, they must be authored (or edited) directly in KML.</description> <Style id="yellowLineGreenPoly"> <LineStyle> <color>7f00ffff</color> <width>4</width> </LineStyle> <PolyStyle> <color>7f00ff00</color> </PolyStyle> </Style> <Placemark> <name>Absolute Extruded</name> <description>Transparent green wall with yellow outlines</description> <styleUrl>#yellowLineGreenPoly</styleUrl> <LineString> <extrude>1</extrude> <tessellate>1</tessellate> <altitudeMode>absolute</altitudeMode> <coordinates> -112.2550785337791,36.07954952145647,2357 -112.2549277039738,36.08117083492122,2357 -112.2552505069063,36.08260761307279,2357 -112.2564540158376,36.08395660588506,2357 -112.2580238976449,36.08511401044813,2357 -112.2595218489022,36.08584355239394,2357 -112.2608216347552,36.08612634548589,2357 -112.262073428656,36.08626019085147,2357 -112.2633204928495,36.08621519860091,2357 -112.2644963846444,36.08627897945274,2357 -112.2656969554589,36.08649599090644,2357 </coordinates> <LineString> </Placemark> </Document> </kml>
当我加载这个文件到标准的网页谷歌地图,它显示很好,但是当我尝试与谷歌地图相同的事情,它不这样做。 它只是带我到一些地方,就是这样。 我正在考虑改变听众课堂。 目前看起来像这样:
private class MyLocationListener implements LocationListener { @Override public void onLocationChanged(Location loc) { if (loc != null) { latitude = (loc.getLatitude() * 1E6); longitude = (loc.getLongitude() * 1E6); Toast.makeText(getBaseContext(), "Location changed : Lat: " + latitude + " Lng: " + longitude, Toast.LENGTH_SHORT).show(); GeoPoint p = new GeoPoint( (int) (loc.getLatitude() * 1E6), (int) (loc.getLongitude() * 1E6)); mc.animateTo(p); mapView.invalidate(); } } //--------------------------------------------------------------- @Override public void onProviderDisabled(String provider) { // TODO Auto-generated method stub } @Override public void onProviderEnabled(String provider) { // TODO Auto-generated method stub } @Override public void onStatusChanged(String provider, int status, Bundle extras) { //TODO Auto-generated method stub }
请有人能告诉我在这里做错了什么?
在上面的代码中,就我所见,您不会将kml数据传递到您的代码中任何位置的mapView。 要显示路线,您应该parsingkml数据,即通过SAXparsing器,然后在地图上显示路线标记。
看下面的代码的例子,但它并不完整 – 只是为你作为参考,并得到一些想法。
这是一个简单的bean,用来保存我将parsing的路由信息。
package com.myapp.android.model.navigation; import java.util.ArrayList; import java.util.Iterator; public class NavigationDataSet { private ArrayList<Placemark> placemarks = new ArrayList<Placemark>(); private Placemark currentPlacemark; private Placemark routePlacemark; public String toString() { String s= ""; for (Iterator<Placemark> iter=placemarks.iterator();iter.hasNext();) { Placemark p = (Placemark)iter.next(); s += p.getTitle() + "\n" + p.getDescription() + "\n\n"; } return s; } public void addCurrentPlacemark() { placemarks.add(currentPlacemark); } public ArrayList<Placemark> getPlacemarks() { return placemarks; } public void setPlacemarks(ArrayList<Placemark> placemarks) { this.placemarks = placemarks; } public Placemark getCurrentPlacemark() { return currentPlacemark; } public void setCurrentPlacemark(Placemark currentPlacemark) { this.currentPlacemark = currentPlacemark; } public Placemark getRoutePlacemark() { return routePlacemark; } public void setRoutePlacemark(Placemark routePlacemark) { this.routePlacemark = routePlacemark; } }
而SAX Handlerparsingkml:
package com.myapp.android.model.navigation; import android.util.Log; import com.myapp.android.myapp; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import com.myapp.android.model.navigation.NavigationDataSet; import com.myapp.android.model.navigation.Placemark; public class NavigationSaxHandler extends DefaultHandler{ // =========================================================== // Fields // =========================================================== private boolean in_kmltag = false; private boolean in_placemarktag = false; private boolean in_nametag = false; private boolean in_descriptiontag = false; private boolean in_geometrycollectiontag = false; private boolean in_linestringtag = false; private boolean in_pointtag = false; private boolean in_coordinatestag = false; private StringBuffer buffer; private NavigationDataSet navigationDataSet = new NavigationDataSet(); // =========================================================== // Getter & Setter // =========================================================== public NavigationDataSet getParsedData() { navigationDataSet.getCurrentPlacemark().setCoordinates(buffer.toString().trim()); return this.navigationDataSet; } // =========================================================== // Methods // =========================================================== @Override public void startDocument() throws SAXException { this.navigationDataSet = new NavigationDataSet(); } @Override public void endDocument() throws SAXException { // Nothing to do } /** Gets be called on opening tags like: * <tag> * Can provide attribute(s), when xml was like: * <tag attribute="attributeValue">*/ @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { if (localName.equals("kml")) { this.in_kmltag = true; } else if (localName.equals("Placemark")) { this.in_placemarktag = true; navigationDataSet.setCurrentPlacemark(new Placemark()); } else if (localName.equals("name")) { this.in_nametag = true; } else if (localName.equals("description")) { this.in_descriptiontag = true; } else if (localName.equals("GeometryCollection")) { this.in_geometrycollectiontag = true; } else if (localName.equals("LineString")) { this.in_linestringtag = true; } else if (localName.equals("point")) { this.in_pointtag = true; } else if (localName.equals("coordinates")) { buffer = new StringBuffer(); this.in_coordinatestag = true; } } /** Gets be called on closing tags like: * </tag> */ @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { if (localName.equals("kml")) { this.in_kmltag = false; } else if (localName.equals("Placemark")) { this.in_placemarktag = false; if ("Route".equals(navigationDataSet.getCurrentPlacemark().getTitle())) navigationDataSet.setRoutePlacemark(navigationDataSet.getCurrentPlacemark()); else navigationDataSet.addCurrentPlacemark(); } else if (localName.equals("name")) { this.in_nametag = false; } else if (localName.equals("description")) { this.in_descriptiontag = false; } else if (localName.equals("GeometryCollection")) { this.in_geometrycollectiontag = false; } else if (localName.equals("LineString")) { this.in_linestringtag = false; } else if (localName.equals("point")) { this.in_pointtag = false; } else if (localName.equals("coordinates")) { this.in_coordinatestag = false; } } /** Gets be called on the following structure: * <tag>characters</tag> */ @Override public void characters(char ch[], int start, int length) { if(this.in_nametag){ if (navigationDataSet.getCurrentPlacemark()==null) navigationDataSet.setCurrentPlacemark(new Placemark()); navigationDataSet.getCurrentPlacemark().setTitle(new String(ch, start, length)); } else if(this.in_descriptiontag){ if (navigationDataSet.getCurrentPlacemark()==null) navigationDataSet.setCurrentPlacemark(new Placemark()); navigationDataSet.getCurrentPlacemark().setDescription(new String(ch, start, length)); } else if(this.in_coordinatestag){ if (navigationDataSet.getCurrentPlacemark()==null) navigationDataSet.setCurrentPlacemark(new Placemark()); //navigationDataSet.getCurrentPlacemark().setCoordinates(new String(ch, start, length)); buffer.append(ch, start, length); } } }
和一个简单的placeMark bean:
package com.myapp.android.model.navigation; public class Placemark { String title; String description; String coordinates; String address; public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public String getCoordinates() { return coordinates; } public void setCoordinates(String coordinates) { this.coordinates = coordinates; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } }
最后是我的模型中调用计算的服务类:
package com.myapp.android.model.navigation; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import com.myapp.android.myapp; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import android.util.Log; public class MapService { public static final int MODE_ANY = 0; public static final int MODE_CAR = 1; public static final int MODE_WALKING = 2; public static String inputStreamToString (InputStream in) throws IOException { StringBuffer out = new StringBuffer(); byte[] b = new byte[4096]; for (int n; (n = in.read(b)) != -1;) { out.append(new String(b, 0, n)); } return out.toString(); } public static NavigationDataSet calculateRoute(Double startLat, Double startLng, Double targetLat, Double targetLng, int mode) { return calculateRoute(startLat + "," + startLng, targetLat + "," + targetLng, mode); } public static NavigationDataSet calculateRoute(String startCoords, String targetCoords, int mode) { String urlPedestrianMode = "http://maps.google.com/maps?" + "saddr=" + startCoords + "&daddr=" + targetCoords + "&sll=" + startCoords + "&dirflg=w&hl=en&ie=UTF8&z=14&output=kml"; Log.d(myapp.APP, "urlPedestrianMode: "+urlPedestrianMode); String urlCarMode = "http://maps.google.com/maps?" + "saddr=" + startCoords + "&daddr=" + targetCoords + "&sll=" + startCoords + "&hl=en&ie=UTF8&z=14&output=kml"; Log.d(myapp.APP, "urlCarMode: "+urlCarMode); NavigationDataSet navSet = null; // for mode_any: try pedestrian route calculation first, if it fails, fall back to car route if (mode==MODE_ANY||mode==MODE_WALKING) navSet = MapService.getNavigationDataSet(urlPedestrianMode); if (mode==MODE_ANY&&navSet==null||mode==MODE_CAR) navSet = MapService.getNavigationDataSet(urlCarMode); return navSet; } /** * Retrieve navigation data set from either remote URL or String * @param url * @return navigation set */ public static NavigationDataSet getNavigationDataSet(String url) { // urlString = "http://192.168.1.100:80/test.kml"; Log.d(myapp.APP,"urlString -->> " + url); NavigationDataSet navigationDataSet = null; try { final URL aUrl = new URL(url); final URLConnection conn = aUrl.openConnection(); conn.setReadTimeout(15 * 1000); // timeout for reading the google maps data: 15 secs conn.connect(); /* Get a SAXParser from the SAXPArserFactory. */ SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser sp = spf.newSAXParser(); /* Get the XMLReader of the SAXParser we created. */ XMLReader xr = sp.getXMLReader(); /* Create a new ContentHandler and apply it to the XML-Reader*/ NavigationSaxHandler navSax2Handler = new NavigationSaxHandler(); xr.setContentHandler(navSax2Handler); /* Parse the xml-data from our URL. */ xr.parse(new InputSource(aUrl.openStream())); /* Our NavigationSaxHandler now provides the parsed data to us. */ navigationDataSet = navSax2Handler.getParsedData(); /* Set the result to be displayed in our GUI. */ Log.d(myapp.APP,"navigationDataSet: "+navigationDataSet.toString()); } catch (Exception e) { // Log.e(myapp.APP, "error with kml xml", e); navigationDataSet = null; } return navigationDataSet; } }
画画:
/** * Does the actual drawing of the route, based on the geo points provided in the nav set * * @param navSet Navigation set bean that holds the route information, incl. geo pos * @param color Color in which to draw the lines * @param mMapView01 Map view to draw onto */ public void drawPath(NavigationDataSet navSet, int color, MapView mMapView01) { Log.d(myapp.APP, "map color before: " + color); // color correction for dining, make it darker if (color == Color.parseColor("#add331")) color = Color.parseColor("#6C8715"); Log.d(myapp.APP, "map color after: " + color); Collection overlaysToAddAgain = new ArrayList(); for (Iterator iter = mMapView01.getOverlays().iterator(); iter.hasNext();) { Object o = iter.next(); Log.d(myapp.APP, "overlay type: " + o.getClass().getName()); if (!RouteOverlay.class.getName().equals(o.getClass().getName())) { // mMapView01.getOverlays().remove(o); overlaysToAddAgain.add(o); } } mMapView01.getOverlays().clear(); mMapView01.getOverlays().addAll(overlaysToAddAgain); String path = navSet.getRoutePlacemark().getCoordinates(); Log.d(myapp.APP, "path=" + path); if (path != null && path.trim().length() > 0) { String[] pairs = path.trim().split(" "); Log.d(myapp.APP, "pairs.length=" + pairs.length); String[] lngLat = pairs[0].split(","); // lngLat[0]=longitude lngLat[1]=latitude lngLat[2]=height Log.d(myapp.APP, "lnglat =" + lngLat + ", length: " + lngLat.length); if (lngLat.length<3) lngLat = pairs[1].split(","); // if first pair is not transferred completely, take seconds pair //TODO try { GeoPoint startGP = new GeoPoint((int) (Double.parseDouble(lngLat[1]) * 1E6), (int) (Double.parseDouble(lngLat[0]) * 1E6)); mMapView01.getOverlays().add(new RouteOverlay(startGP, startGP, 1)); GeoPoint gp1; GeoPoint gp2 = startGP; for (int i = 1; i < pairs.length; i++) // the last one would be crash { lngLat = pairs[i].split(","); gp1 = gp2; if (lngLat.length >= 2 && gp1.getLatitudeE6() > 0 && gp1.getLongitudeE6() > 0 && gp2.getLatitudeE6() > 0 && gp2.getLongitudeE6() > 0) { // for GeoPoint, first:latitude, second:longitude gp2 = new GeoPoint((int) (Double.parseDouble(lngLat[1]) * 1E6), (int) (Double.parseDouble(lngLat[0]) * 1E6)); if (gp2.getLatitudeE6() != 22200000) { mMapView01.getOverlays().add(new RouteOverlay(gp1, gp2, 2, color)); Log.d(myapp.APP, "draw:" + gp1.getLatitudeE6() + "/" + gp1.getLongitudeE6() + " TO " + gp2.getLatitudeE6() + "/" + gp2.getLongitudeE6()); } } // Log.d(myapp.APP,"pair:" + pairs[i]); } //routeOverlays.add(new RouteOverlay(gp2,gp2, 3)); mMapView01.getOverlays().add(new RouteOverlay(gp2, gp2, 3)); } catch (NumberFormatException e) { Log.e(myapp.APP, "Cannot draw route.", e); } } // mMapView01.getOverlays().addAll(routeOverlays); // use the default color mMapView01.setEnabled(true); }
这是RouteOverlay类:
package com.myapp.android.activity.map.nav; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.graphics.RectF; import com.google.android.maps.GeoPoint; import com.google.android.maps.MapView; import com.google.android.maps.Overlay; import com.google.android.maps.Projection; public class RouteOverlay extends Overlay { private GeoPoint gp1; private GeoPoint gp2; private int mRadius=6; private int mode=0; private int defaultColor; private String text=""; private Bitmap img = null; public RouteOverlay(GeoPoint gp1,GeoPoint gp2,int mode) { // GeoPoint is a int. (6E) this.gp1 = gp1; this.gp2 = gp2; this.mode = mode; defaultColor = 999; // no defaultColor } public RouteOverlay(GeoPoint gp1,GeoPoint gp2,int mode, int defaultColor) { this.gp1 = gp1; this.gp2 = gp2; this.mode = mode; this.defaultColor = defaultColor; } public void setText(String t) { this.text = t; } public void setBitmap(Bitmap bitmap) { this.img = bitmap; } public int getMode() { return mode; } @Override public boolean draw (Canvas canvas, MapView mapView, boolean shadow, long when) { Projection projection = mapView.getProjection(); if (shadow == false) { Paint paint = new Paint(); paint.setAntiAlias(true); Point point = new Point(); projection.toPixels(gp1, point); // mode=1:start if(mode==1) { if(defaultColor==999) paint.setColor(Color.BLACK); // Color.BLUE else paint.setColor(defaultColor); RectF oval=new RectF(point.x - mRadius, point.y - mRadius, point.x + mRadius, point.y + mRadius); // start point canvas.drawOval(oval, paint); } // mode=2:path else if(mode==2) { if(defaultColor==999) paint.setColor(Color.RED); else paint.setColor(defaultColor); Point point2 = new Point(); projection.toPixels(gp2, point2); paint.setStrokeWidth(5); paint.setAlpha(defaultColor==Color.parseColor("#6C8715")?220:120); canvas.drawLine(point.x, point.y, point2.x,point2.y, paint); } /* mode=3:end */ else if(mode==3) { /* the last path */ if(defaultColor==999) paint.setColor(Color.BLACK); // Color.GREEN else paint.setColor(defaultColor); Point point2 = new Point(); projection.toPixels(gp2, point2); paint.setStrokeWidth(5); paint.setAlpha(defaultColor==Color.parseColor("#6C8715")?220:120); canvas.drawLine(point.x, point.y, point2.x,point2.y, paint); RectF oval=new RectF(point2.x - mRadius,point2.y - mRadius, point2.x + mRadius,point2.y + mRadius); /* end point */ paint.setAlpha(255); canvas.drawOval(oval, paint); } } return super.draw(canvas, mapView, shadow, when); } }
感谢Mathias Lin,经过testing,它的工作原理!
另外,在活动中Mathias方法的样例实现如下。
public class DirectionMapActivity extends MapActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.directionmap); MapView mapView = (MapView) findViewById(R.id.mapview); mapView.setBuiltInZoomControls(true); // Acquire a reference to the system Location Manager LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); String locationProvider = LocationManager.NETWORK_PROVIDER; Location lastKnownLocation = locationManager.getLastKnownLocation(locationProvider); StringBuilder urlString = new StringBuilder(); urlString.append("http://maps.google.com/maps?f=d&hl=en"); urlString.append("&saddr=");//from urlString.append( Double.toString(lastKnownLocation.getLatitude() )); urlString.append(","); urlString.append( Double.toString(lastKnownLocation.getLongitude() )); urlString.append("&daddr=");//to urlString.append( Double.toString((double)dest[0]/1.0E6 )); urlString.append(","); urlString.append( Double.toString((double)dest[1]/1.0E6 )); urlString.append("&ie=UTF8&0&om=0&output=kml"); try{ // setup the url URL url = new URL(urlString.toString()); // create the factory SAXParserFactory factory = SAXParserFactory.newInstance(); // create a parser SAXParser parser = factory.newSAXParser(); // create the reader (scanner) XMLReader xmlreader = parser.getXMLReader(); // instantiate our handler NavigationSaxHandler navSaxHandler = new NavigationSaxHandler(); // assign our handler xmlreader.setContentHandler(navSaxHandler); // get our data via the url class InputSource is = new InputSource(url.openStream()); // perform the synchronous parse xmlreader.parse(is); // get the results - should be a fully populated RSSFeed instance, or null on error NavigationDataSet ds = navSaxHandler.getParsedData(); // draw path drawPath(ds, Color.parseColor("#add331"), mapView ); // find boundary by using itemized overlay GeoPoint destPoint = new GeoPoint(dest[0],dest[1]); GeoPoint currentPoint = new GeoPoint( new Double(lastKnownLocation.getLatitude()*1E6).intValue() ,new Double(lastKnownLocation.getLongitude()*1E6).intValue() ); Drawable dot = this.getResources().getDrawable(R.drawable.pixel); MapItemizedOverlay bgItemizedOverlay = new MapItemizedOverlay(dot,this); OverlayItem currentPixel = new OverlayItem(destPoint, null, null ); OverlayItem destPixel = new OverlayItem(currentPoint, null, null ); bgItemizedOverlay.addOverlay(currentPixel); bgItemizedOverlay.addOverlay(destPixel); // center and zoom in the map MapController mc = mapView.getController(); mc.zoomToSpan(bgItemizedOverlay.getLatSpanE6()*2,bgItemizedOverlay.getLonSpanE6()*2); mc.animateTo(new GeoPoint( (currentPoint.getLatitudeE6() + destPoint.getLatitudeE6()) / 2 , (currentPoint.getLongitudeE6() + destPoint.getLongitudeE6()) / 2)); } catch(Exception e) { Log.d("DirectionMap","Exception parsing kml."); } } // and the rest of the methods in activity, eg drawPath() etc...
MapItemizedOverlay.java
public class MapItemizedOverlay extends ItemizedOverlay{ private ArrayList<OverlayItem> mOverlays = new ArrayList<OverlayItem>(); private Context mContext; public MapItemizedOverlay(Drawable defaultMarker, Context context) { super(boundCenterBottom(defaultMarker)); mContext = context; } public void addOverlay(OverlayItem overlay) { mOverlays.add(overlay); populate(); } @Override protected OverlayItem createItem(int i) { return mOverlays.get(i); } @Override public int size() { return mOverlays.size(); } }
Mathias Lin编码精美。 但是,您可能需要考虑在drawPath方法内更改此部分:
if (lngLat.length >= 2 && gp1.getLatitudeE6() > 0 && gp1.getLongitudeE6() > 0 && gp2.getLatitudeE6() > 0 && gp2.getLongitudeE6() > 0) {
GeoPoint也可以小于零,我将它切换到:
if (lngLat.length >= 2 && gp1.getLatitudeE6() != 0 && gp1.getLongitudeE6() != 0 && gp2.getLatitudeE6() != 0 && gp2.getLongitudeE6() != 0) {
谢谢:D
现在有一个Google地图KML导入实用程序的testing版。
它是Google Maps Android API实用程序库的一部分 。 如文件所述,它允许从stream中加载KML文件
KmlLayer layer = new KmlLayer(getMap(), kmlInputStream, getApplicationContext());
或本地资源
KmlLayer layer = new KmlLayer(getMap(), R.raw.kmlFile, getApplicationContext());
在创buildKmlLayer之后,调用addLayerToMap()将导入的数据添加到地图上。
layer.addLayerToMap();