如何在Android中处理WKT数据?

3

我有这样格式的数据:

POINT(73.0166738279393 33.6788721326803)
MULTILINESTRING((73.0131224998036 33.679001500419,73.0119635003153 33.678392400389,73.0119205001311 33.6783781002692),(73.0131224998036 33.679001500419,73.0136031002029 33.6783443999742),(73.0136031002029 33.6783443999742,73.0147099372139 33.67685138958),(73.0147099372139 33.67685138958,73.0150124997272 33.6770292997624,73.0154158996241 33.6773507003746,73.0157677998441 33.6776577999676,73.016042399737 33.6779721004322,73.0162998999205 33.6783149004124,73.0166738279393 33.6788721326803))

现在我想在Android上的Google Maps上绘制它。我制作了一个名称和坐标的数组。
ArrayList<String> coordinates = new ArrayList<String>
coordinates.add(tvcoor.getText().toString());

我运行我的应用程序时,产生了一个错误:它强制停止了。 我该如何在地图上绘制它?


Gilles,我添加了一个if语句,因为textView还接收到了其他数据。但是我只想将坐标数据存储到数组列表中。 - Sarah Salar
告诉我,这个代码用于从TextView添加值到ArrayList中是否正确:if ((tvTextIn.equals(new String("POINT"))) || (tvTextIn.equals(new String("MULTILINES")))) { coordinates.add(tvcoor.getText().toString()); } - Sarah Salar
当我运行以下代码时:ArrayList<String> coordinates = new ArrayList<String> coordinates.add(tvcoor.getText().toString()); 它没有将值存储在数组列表中,所有的值都是null,它只创建了一个大小但所有值都是null。 - Sarah Salar
你获取到TextView的值了吗?请发布你的完整代码。 - rajeshwaran
在Android中有没有解析WKT数据并从中提取经纬度的方法? - Sarah Salar
显示剩余2条评论
5个回答

2
试试这个,
String str;
ArrayList<String> coordinates = new ArrayList<String>();

首先从TextView中获取字符串。

str = textview.getText().toString();

第二步,删除括号。

str = str.replaceAll("\\(", "");
str = str.replaceAll("\\)", "");

然后用逗号分隔并将值添加到数组列表中。
String[] commatokens = str.split(",");
        for (String commatoken : commatokens) {
            System.out.println("-" + commatoken + "-");
            coordinates.add(commatoken);
        }

然后我们在索引位置获取独立的坐标值,
 for (int i = 0; i < coordinates.size(); i++) {

            String[] tokens = coordinates.get(i).split("\\s");
            for (String token : tokens) {
                System.out.println("-" + token + "-");
            }
        }

感谢Rajesh的帮助,但我无法理解最后一步。当我将这个坐标数组列表发送到MapActivity,然后从MapActivity发送到Overlay类并绘制一个点时。 - Sarah Salar
Intent in = getIntent(); loc = in.getStringArrayListExtra("stringname");mapOverlays = mapView.getOverlays(); proj = mapView.getProjection();overlay = new MyOverlay(locations);并绘制点,如下所示 public MyOverlay(List<String> locations) { // TODO 自动生成的构造函数存根 GeoPoint mp = new GeoPoint((int)(Integer.parseInt(locations.get(0))*1E6), (int)(Integer.parseInt(locations.get(1))*1E6)); }然后应用程序意外停止。 - Sarah Salar
它在第一个位置有一些问题,它保存了[0] = POINT(73.0166738279393 33.6788721326803) MULTILINESTRING((73.0131224998036 33.679001500419; [1] = 73.0119635003153 33.678392400389; 然后再次 [2] = POINT(73.0166738279393 33.6788721326803) MULTILINESTRING((73.0131224998036 33.679001500419; - Sarah Salar
当我使用 \s 时,它不会分割第一行,而当我使用 " " 时,它会分割最后一个值。 - Sarah Salar
谢谢Rajesh的帮助,我已经解决了这个问题。现在要开始在谷歌地图上绘制。 - Sarah Salar

1
一个 WKT (well-known-text) 文件描述了 ISO 19107 几何体。个人而言,我尽量避免重新发明轮子,或者在自己编写的解析器中“搞砸”它们(你永远不知道,你的函数是否涵盖了所有情况,只因为它曾经起作用过一次)。
所以这里有另一个漂亮的开源 API,附带示例和教程:

http://docs.geotools.org/

这里是WKTParser类

http://docs.geotools.org/stable/javadocs/org/geotools/geometry/text/WKTParser.html

Android Studio: 只需将以下内容添加到您的应用程序build.gradle文件中:

dependencies {
    /* your other dependencies */
    compile 'org.opengis:geoapi:3.0.0'
}

1

对于其他遇到相同情况的人,我发现了一个名为JTS Topology Suite的开源库,它具有在Java中解析WKT字符串的能力。我的应用程序中的一个基本示例如下:

WKTReader wktReader = new WKTReader();
Geometry geometry = wktReader.read(routeResponse.get(yourWKTMultilineString);

您可以按以下方式遍历各个行:
for(int lineIndex = 0; lineIndex < geometry.getNumGeometries(); lineIndex++){
    Geometry lineGeometry = geometry.getGeometryN(lineIndex);
    //... other stuff
}

如果需要的话,您可以像这样获取每条线的单独坐标:
Coordinate[] lineCoordinates = lineGeometry.getCoordinates();

请注意,上面是一个非常普遍的例子,遵循OP的代码。
最终,这可能会使其他人不必自己编写WKT解析器。

特定于Nutiteq的代码:
在我的情况下,我需要将多行字符串作为矢量图层绘制在Nutiteq地图上。我意识到OP是在询问Google Map Android API,但是如果任何读者也在使用Nutiteq(或者如果该算法适用于其他地图API),则这是Nutiteq特定的代码:

geomLayer.clear(); // clear the old vector data

Projection projection = geomLayer.getProjection(); // Map's projection type

// Iterate through the individual lines of our multi-line geometry
for(int lineIndex = 0; lineIndex < geometry.getNumGeometries(); lineIndex++){
    Geometry lineGeometry = geometry.getGeometryN(lineIndex);
    ArrayList<MapPos> linePositions = new ArrayList<MapPos>(lineGeometry.getCoordinates().length);

    // Iterate through this line's coordinates
    for(Coordinate coordinate : lineGeometry.getCoordinates()){
        // My server returns coordinates in WGS84/EPSG:4326 projection while the map
        // uses EPSG3857, so it is necessary to convert before adding to the
        // array list.
        MapPos linePosition = new MapPos(projection.fromWgs84(coordinate.x, coordinate.y));
        linePositions.add(linePosition);
    }

    // Finally, add the line data to the vector layer
    Line line = new Line(linePositions, new DefaultLabel("some label"), lineStyle), null);
    geomLayer.add(line);
}

请注意,lineStyleSetgeomLayer是在活动的onCreate中创建的,并且可以在这里进行研究。 geomLayer很简单;这是我的lineStyleSet
关于lineStyle的说明,它先前已经被创建并保存为实例变量,就像这样:
Bitmap lineMarker = UnscaledBitmapLoader.decodeResource(getResources(), R.drawable.line);

this.lineStyleSet = new StyleSet<LineStyle>();
LineStyle lineStyle = LineStyle.builder().setLineJoinMode(LineStyle.NO_LINEJOIN).setWidth(0.2f).setColor(Color.RED).setBitmap(lineMarker).build();
lineStyleSet.setZoomStyle(minZoom, lineStyle);

0

只是为了扩展Paul的回答,因为他的回答帮了我很多...

private void setUpMap(SomeObjectWithLocationAsWKT r) {

    List<LatLng> points = new ArrayList<LatLng>();
    WKTReader wktReader = new WKTReader();
    LineString line = null;
    Coordinate lineCentroid = null;
    Coordinate[] lineCoordinates = null;

    // if our object's WKT geometry is not null - map it
    if (r.geowkt != null) {

        // use the JTS (Java Topology Suite) WKTReader to read that WKT!
        try {
            line = (LineString) wktReader.read(r.geowkt);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // using (JTS) again to getCoordinates of the linestring
        lineCoordinates = line.getCoordinates();

        // Iterate through the line's coordinates & assign to List<LatLng> points
        for(Coordinate coordinate : lineCoordinates){
            points.add(new LatLng(coordinate.x, coordinate.y));
        }

        // add Polyline to Google Map
        Polyline p = mMap.addPolyline(
        new PolylineOptions()
        .addAll(points)
        .width(4)
        .color(Color.RED));
    }
}

// an example of zooming to the centroid of the WKT geometry 
// again, using (JTS - Java Topology Suite)
private void handleNewLocation(Location location) {
    LatLng latLng = null; 
    WKTReader wktReader = new WKTReader();
    LineString line = null;
    Coordinate lineCentroid = null; 

    // if our object's WKT geometry is not null - zoom to it
    if (r.geowkt != null) {
        try {
            line = (LineString) wktReader.read(r.geowkt);
            lineCentroid = line.getCentroid().getCoordinate();
            latLng = new LatLng(lineCentroid.x, lineCentroid.y);
        } catch (ParseException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    } else {
        // just default to whatever location was passed in
        Log.d(TAG, location.toString());
        double currentLatitude = location.getLatitude();
        double currentLongitude = location.getLongitude();
        latLng = new LatLng(currentLatitude, currentLongitude);
    }
    CameraUpdate yourLocation = CameraUpdateFactory.newLatLngZoom(latLng, 19);
    mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
    mMap.animateCamera(yourLocation);
}

Well Known Text 标准涵盖了各种地理空间对象,而这个解决方案似乎试图将其转换为 LineString。很可能会崩溃。 - joninx

0
这是我编写的一个函数,用于将以WKT表示的简单(没有洞等)多边形转换为LatLang数组:
public static LatLng[] GetPolygonPoints(String poligonWkt){
    ArrayList<LatLng> points = new ArrayList<LatLng>();
    Pattern p = Pattern.compile("(\\d*\\.\\d+)\\s(\\d*\\.\\d+)");
    Matcher m = p.matcher(poligonWkt);
    String point;

    while (m.find()){
        point =  poligonWkt.substring(m.start(), m.end());
        points.add(new LatLng(Double.parseDouble(m.group(2)), Double.parseDouble(m.group(1))));
    }
    return points.toArray(new LatLng[points.size()]);
}

然后,您可以使用数组将多边形添加到地图上:

LatLng[] points = GeographyHelper.GetPolygonPoints(shapeWkt);

Polygon p = mMap.addPolygon(
   new PolygonOptions()
      .add(points)
      .strokeWidth(4)
      .strokeColor(Color.RED));

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