/** * Copyright (C) 2008 - 2014 52°North Initiative for Geospatial Open Source * Software GmbH * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 as published * by the Free Software Foundation. * * If the program is linked with libraries which are licensed under one of * the following licenses, the combination of the program with the linked * library is not considered a "derivative work" of the program: * * - Apache License, version 2.0 * - Apache Software License, version 1.0 * - GNU Lesser General Public License, version 3 * - Mozilla Public License, versions 1.0, 1.1 and 2.0 * - Common Development and Distribution License (CDDL), version 1.0 * * Therefore the distribution of the program linked with libraries licensed * under the aforementioned licenses, is permitted by the copyright holders * if the distribution is compliant with both the GNU General Public * icense version 2 and the aforementioned licenses. * * 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 General * Public License for more details. */ package org.n52.ses.io.parser; import java.util.List; import javax.xml.namespace.QName; import net.opengis.gml.AbstractRingPropertyType; import net.opengis.gml.AbstractRingType; import net.opengis.gml.CoordinatesType; import net.opengis.gml.DirectPositionListType; import net.opengis.gml.EnvelopeType; import net.opengis.gml.LineStringType; import net.opengis.gml.LinearRingType; import net.opengis.gml.MultiPolygonDocument; import net.opengis.gml.MultiPolygonType; import net.opengis.gml.PointType; import net.opengis.gml.PolygonDocument; import net.opengis.gml.PolygonPropertyType; import net.opengis.gml.PolygonType; import org.apache.muse.util.xml.XmlUtils; import org.apache.xmlbeans.XmlObject; import org.n52.ses.api.exception.GMLParseException; import org.w3c.dom.Element; import org.w3c.dom.Node; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.LinearRing; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; /** * Class for GML 3.1.1 parsing. * * @author Matthes Rieke <m.rieke@uni-muenster.de> * @author Thomas Everding */ public class GML31Parser { /** * Literal element of FES 2.0 */ public static final QName FES_2_0_LITERAL_NAME = new QName( "http://www.opengis.net/fes/2.0", "Literal"); /** * global known namespace uri for GLM 3.1.1 */ public static final String GML_3_1_1_NAME = "http://www.opengis.net/gml"; /** * creates a Geometry Object from an EnvelopeType. * @param et The xml beans {@link EnvelopeType} * @return java topolgy suite {@link Geometry} * @throws ParseException if the geometry could not be parsed. */ private static Geometry getGeometryFromEnvelope(EnvelopeType et) throws ParseException { //get upper corner and split at " " Element elem = (Element) et.getUpperCorner().getDomNode(); String ucString = XmlUtils.toString(elem.getFirstChild()).trim(); String[] uc = ucString.split(" "); int i = 0; for (String string : uc) { string = string.trim(); uc[i] = string; i++; } //get lower corner and split at " " elem = (Element) et.getLowerCorner().getDomNode(); String lcString = XmlUtils.toString(elem.getFirstChild()).trim(); String[] lc = lcString.split(" "); i = 0; for (String string : lc) { string = string.trim(); lc[i] = string; i++; } String wktString = "POLYGON(("+ lc[0] +" "+ lc[1] +", "+ lc[0] +" "+ uc[1] +", "+ uc[0] +" "+ uc[1] + ", "+ uc[0] +" "+ lc[1] +", "+ lc[0] +" "+ lc[1]+ "))"; WKTReader wktReader = new WKTReader(); return wktReader.read(wktString); } /** * @param pt xbeans {@link PointType} * @return java topology suite {@link Geometry} */ private static final Geometry getGeometryFromPoint(PointType pt) { GeometryFactory gf = new GeometryFactory(); Node child = pt.getDomNode().getFirstChild(); while (child != null) { if (child.getLocalName()!= null && child.getLocalName().equals("pos")) { break; } child = child.getNextSibling(); } String posString = ""; if (child != null) { //child is the pos element posString = child.getFirstChild().getNodeValue(); } // Element elem = (Element) pt.getDomNode(); // posString = XmlUtils.toString(elem.getFirstChild()).trim(); String[] cs = posString.split(" "); if (cs != null && cs.length > 1) { Coordinate c = new Coordinate(Double.parseDouble(cs[0]), Double.parseDouble(cs[1])); return gf.createPoint(c); } return null; } /** * @param lst xbeans {@link LineStringType} * @return java topology suite {@link Geometry} */ private static final Geometry getGeometryFromLineString(LineStringType lst) { GeometryFactory gf = new GeometryFactory(); CoordinatesType coords = lst.getCoordinates(); String coordSep = coords.getCs(); String decSep = coords.getDecimal(); String tokSep = coords.getTs(); String coordinates = coords.getStringValue().replaceAll("\\s+", " "); String[] coordArray = coordinates.split(tokSep); Coordinate[] coordinateSequence = new Coordinate[coordArray.length]; int i = 0; for (String c : coordArray) { String[] values = c.split(coordSep); if (values.length != 2) { //something wrong with the list return null; } //do the right decimal seperator double value0 = 0, value1 = 0; if (!decSep.equals(".")) { String[] valArray = values[0].split(decSep); if (valArray.length == 2) { value0 = Double.parseDouble(valArray[0] +"."+ valArray[1]); } else if (valArray.length == 1) { value0 = Double.parseDouble(valArray[0]); } valArray = values[1].split(decSep); if (valArray.length == 2) { value1 = Double.parseDouble(valArray[0] +"."+ valArray[1]); } else if (valArray.length == 1) { value1 = Double.parseDouble(valArray[0]); } } else { value0 = Double.parseDouble(values[0]); value1 = Double.parseDouble(values[1]); } coordinateSequence[i] = new Coordinate(value0, value1); i++; } return gf.createLineString(coordinateSequence); } /** * Main method for parsing a geometry from an xml-fragment. * This method delegates to the private concrete parsing methods. * * @param geomElement the geometry xml object * @return a {@link Geometry} as a JTS representation. * @throws ParseException if the geometry could not be parsed. * @throws GMLParseException if something could not be parsed or is not supported. */ public static Geometry parseGeometry(XmlObject geomElement) throws ParseException, GMLParseException { if (geomElement instanceof EnvelopeType) { return getGeometryFromEnvelope((EnvelopeType) geomElement); } else if (geomElement instanceof PointType) { return getGeometryFromPoint((PointType) geomElement); } else if (geomElement instanceof LineStringType) { return getGeometryFromLineString((LineStringType) geomElement); } else if (geomElement instanceof LinearRingType) { return getGeometryFromLinearRing((LinearRingType) geomElement); } else if (geomElement instanceof PolygonType) { return getGeometryFromPolygon((PolygonType) geomElement); } else if (geomElement instanceof PolygonDocument) { return getGeometryFromPolygon(((PolygonDocument) geomElement).getPolygon()); } else if (geomElement instanceof MultiPolygonType) { return getGeometryFromMultiPolygon((MultiPolygonType) geomElement); } else if (geomElement instanceof MultiPolygonDocument) { return getGeometryFromMultiPolygon(((MultiPolygonDocument) geomElement).getMultiPolygon()); } return null; } private static Geometry getGeometryFromMultiPolygon( MultiPolygonType mpol) throws GMLParseException { Geometry result = null; for (PolygonPropertyType pol : mpol.getPolygonMemberArray()) { if (result == null) { result = getGeometryFromPolygon(pol.getPolygon()); } else { result = result.union(getGeometryFromPolygon(pol.getPolygon())); } } return result; } private static Geometry getGeometryFromPolygon(PolygonType pt) throws GMLParseException { GeometryFactory gf = new GeometryFactory(); AbstractRingPropertyType[] inter = pt.getInteriorArray(); LinearRing[] holes = null; if (inter.length > 0) { holes = new LinearRing[inter.length]; int count = 0; Geometry ringGeom; AbstractRingType ring; for (AbstractRingPropertyType inRing : inter) { ring = inRing.getRing(); if (ring instanceof LinearRingType) { ringGeom = getGeometryFromLinearRing((LinearRingType) ring); holes[count] = (LinearRing) ringGeom; } else { /* * could not handle interiors */ holes = null; break; } count++; } } /* * parse exterior ring */ if (pt.isSetExterior()) { AbstractRingPropertyType exter = pt.getExterior(); AbstractRingType ring = exter.getRing(); if (ring instanceof LinearRingType) { Geometry ringGeom = getGeometryFromLinearRing((LinearRingType) ring); return gf.createPolygon((LinearRing) ringGeom, holes); } throw new GMLParseException("Only LinearRing supported " + "at the current developement state."); } return null; } @SuppressWarnings("rawtypes") private static Geometry getGeometryFromLinearRing(LinearRingType lrt) throws GMLParseException { GeometryFactory gf = new GeometryFactory(); if (lrt.isSetPosList()) { DirectPositionListType posList = lrt.getPosList(); List dataList = posList.getListValue(); if ((dataList.size() % 2) != 0) { throw new GMLParseException("Odd element count. Either wrong number of doubles" + " inside the ring or coords are in 3D which is not supported."); } Coordinate[] coords = new Coordinate[(dataList.size() /2) + 1]; for (int i = 0; i < dataList.size(); i=i+2) { coords[i/2] = new Coordinate((Double) dataList.get(i+1), (Double) dataList.get(i)); } coords[coords.length - 1] = coords[0]; return gf.createLinearRing(coords); } else if (lrt.isSetCoordinates()) { String[] dataList = lrt.getCoordinates().getStringValue().trim().split(" "); Coordinate[] coords = new Coordinate[dataList.length]; String[] tmp; for (int i = 0; i < dataList.length; i++) { tmp = dataList[i].split(","); coords[i] = new Coordinate(Double.parseDouble(tmp[1]), Double.parseDouble(tmp[0])); } coords[coords.length - 1] = coords[0]; return gf.createLinearRing(coords); } throw new GMLParseException("Only posList and coordinates currently supported."); } }