如何使用kml文件在地图上绘制路径?

发布于 2021-01-29 20:16:23

我可以解析kml文件以便在Android中显示路径或点吗?请你能帮我吗?

这是我想在Android Google Map中显示的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>

当我将此文件加载到标准网络google map时,它会很好地显示它,但是当我尝试使用android google map进行相同的操作时,它不会这样做。它只是带我到某些地方,仅此而已。我当时正在考虑更改监听器类。当前看起来像这样:

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
    }

请有人能告诉我我在做什么错吗?

关注者
0
被浏览
294
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    在上面的代码中,就我所知,您没有将kml数据传递到代码中的mapView。要显示路线,您应该通过SAX解析器解析kml数据,然后在地图上显示路线标记。

    请参阅下面的代码作为示例,但是它还不完整-仅作为您的参考并获得一些想法。

    这是一个简单的bean,用于保存将要解析的路由信息​​。

    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 Handler解析kml:

    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&#65306;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&#65306;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&#65306;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);
    }
    
    }
    


知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看