/* * Copyright 2013 Hannes Janetzek * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with * this program. If not, see <http://www.gnu.org/licenses/>. */ package org.oscim.web.client; import org.oscim.core.GeometryBuffer; public class WKTReader { private final static String POINT = "POINT"; private final static String LINE = "LINESTRING"; private final static String POLY = "POLYGON"; private final static String MULTI = "MULTI"; private final static int SKIP_POINT = POINT.length(); private final static int SKIP_LINE = LINE.length(); private final static int SKIP_POLY = POLY.length(); private final static int SKIP_MULTI = MULTI.length(); public void parse(String wkt, GeometryBuffer geom) throws Exception { // return position. int[] pos = new int[] { 0 }; int len = wkt.length(); if (wkt.startsWith(POINT, pos[0])) { pos[0] += SKIP_POINT; geom.startPoints(); ensure(wkt, pos, '('); parsePoint(geom, wkt, len, pos); ensure(wkt, pos, ')'); } else if (wkt.startsWith(LINE, pos[0])) { pos[0] += SKIP_LINE; geom.startLine(); parseLine(geom, wkt, len, pos); } else if (wkt.startsWith(POLY, pos[0])) { pos[0] += SKIP_POLY; geom.startPolygon(); parsePoly(geom, wkt, len, pos); } else if (wkt.startsWith(MULTI, pos[0])) { pos[0] += SKIP_MULTI; if (wkt.startsWith(POINT, pos[0])) { pos[0] += SKIP_POINT; geom.startPoints(); ensure(wkt, pos, '('); parsePoint(geom, wkt, len, pos); while (wkt.charAt(pos[0]) == ',') { pos[0]++; parsePoint(geom, wkt, len, pos); } ensure(wkt, pos, ')'); } else if (wkt.startsWith(LINE, pos[0])) { pos[0] += SKIP_LINE; geom.startLine(); ensure(wkt, pos, '('); parseLine(geom, wkt, len, pos); while (wkt.charAt(pos[0]) == ',') { pos[0]++; geom.startLine(); parseLine(geom, wkt, len, pos); } ensure(wkt, pos, ')'); } else if (wkt.startsWith(POLY, pos[0])) { pos[0] += SKIP_POLY; geom.startPolygon(); ensure(wkt, pos, '('); parsePoly(geom, wkt, len, pos); while (wkt.charAt(pos[0]) == ',') { pos[0]++; geom.startPolygon(); parsePoly(geom, wkt, len, pos); } ensure(wkt, pos, ')'); } else throw new Exception("usupported geometry "); } else throw new Exception("usupported geometry "); } private static void ensure(String wkt, int[] pos, char c) throws Exception { if (wkt.charAt(pos[0]) != c) throw new Exception(); pos[0]++; } private static void parsePoly(GeometryBuffer geom, String wkt, int len, int[] adv) throws Exception { // outer ring ensure(wkt, adv, '('); parseLine(geom, wkt, len, adv); while (wkt.charAt(adv[0]) == ',') { adv[0]++; geom.startHole(); parseLine(geom, wkt, len, adv); } ensure(wkt, adv, ')'); } private static void parseLine(GeometryBuffer geom, String wkt, int len, int[] adv) throws Exception { ensure(wkt, adv, '('); parsePoint(geom, wkt, len, adv); while (wkt.charAt(adv[0]) == ',') { adv[0]++; parsePoint(geom, wkt, len, adv); } ensure(wkt, adv, ')'); } private static void parsePoint(GeometryBuffer geom, String wkt, int len, int[] adv) { float x = parseNumber(wkt, len, adv); // skip ' ' adv[0]++; float y = parseNumber(wkt, len, adv); geom.addPoint(x, y); } static float parseNumber(String wkt, int len, int[] adv) { int pos = adv[0]; boolean neg = false; if (wkt.charAt(pos) == '-') { neg = true; pos++; } float val = 0; int pre = 0; char c = 0; for (; pos < len; pos++, pre++) { c = wkt.charAt(pos); if (c < '0' || c > '9') { if (pre == 0) throw new NumberFormatException("s " + c); break; } val = val * 10 + (int) (c - '0'); } if (pre == 0) throw new NumberFormatException(); if (c == '.') { float div = 10; for (pos++; pos < len; pos++) { c = wkt.charAt(pos); if (c < '0' || c > '9') break; val = val + ((int) (c - '0')) / div; div *= 10; } } if (c == 'e' || c == 'E') { // advance 'e' pos++; // check direction int dir = 1; if (wkt.charAt(pos) == '-') { dir = -1; pos++; } // skip leading zeros for (; pos < len; pos++) if (wkt.charAt(pos) != '0') break; int shift = 0; for (pre = 0; pos < len; pos++, pre++) { c = wkt.charAt(pos); if (c < '0' || c > '9') { // nothing after 'e' if (pre == 0) throw new NumberFormatException("e " + c); break; } shift = shift * 10 + (int) (c - '0'); } // guess it's ok for sane values of E if (dir > 0) { while (shift-- > 0) val *= 10; } else { while (shift-- > 0) val /= 10; } } adv[0] = pos; return neg ? -val : val; } // public static void main(String[] args) { // WKTReader r = new WKTReader(); // GeometryBuffer geom = new GeometryBuffer(10, 10); // try { // String wkt = "MULTIPOINT(0 0,1 0)"; // r.parse(wkt, geom); // for (int i = 0; i < geom.index.length; i++) { // int len = geom.index[i]; // if (len < 0) // break; // for (int p = 0; p < len; p += 2) // System.out.println(len + ": " + geom.points[p] + "," + geom.points[p + 1]); // } // } catch (Exception e) { // e.printStackTrace(); // } // } }