Как обрабатывать данные WKT в Android?
У меня есть данные в этом формате:
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))
Теперь я хочу нарисовать его на Google Maps в Android. Я делаю массив имен и координат.
ArrayList<String> coordinates = new ArrayList<String>
coordinates.add(tvcoor.getText().toString());
Это приводит к ошибке: когда я запускаю свое приложение, оно принудительно останавливается. И как я могу нарисовать это на карте?
5 ответов
Попробуй это,
String str;
ArrayList<String> coordinates = new ArrayList<String>();
Сначала получите строку из textview.
str = textview.getText().toString();
Второе убрать скобки.
str = str.replaceAll("\\(", "");
str = str.replaceAll("\\)", "");
Затем разделите запятой и добавьте значения в arraylist.
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 + "-");
}
}
Для тех, у кого есть такой же сценарий, я нашел библиотеку с открытым исходным кодом под названием JTS Topology Suite, которая может анализировать строки WKT в Java. Базовый пример из моего приложения выглядит так:
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. Я понимаю, что ОП спрашивал об API Google Map and Android, однако в случае, если какой-либо читатель также использует 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);
}
Обратите внимание, что lineStyleSet
а также geomLayer
созданы ранее в деятельности 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);
Вот функция, которую я написал для преобразования простого (без дырок и т. Д.) Многоугольника, заданного в 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));
Просто подробнее об ответе Пола, так как его ответ мне очень помог...
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);
}
Файл WKT (общеизвестный текст) описывает геометрию ISO 19107. Лично я стараюсь избегать повторного изобретения колеса или "связываться" с ним в самописных синтаксических анализаторах (никогда не знаешь, охватывает ли твоя функция всю ситуацию только потому, что она сработала один раз).
Итак, вот еще один красивый API с открытым исходным кодом, с примерами, учебными пособиями:
А вот класс 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'
}