/**
* 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.eml.v002.filter.spatial;
import net.opengis.fes.x20.DistanceBufferType;
import net.opengis.gml.x32.LineStringDocument;
import net.opengis.gml.x32.LineStringType;
import net.opengis.gml.x32.LinearRingDocument;
import net.opengis.gml.x32.LinearRingType;
import net.opengis.gml.x32.PointDocument;
import net.opengis.gml.x32.PointType;
import net.opengis.gml.x32.PolygonDocument;
import net.opengis.gml.x32.PolygonType;
import org.apache.muse.util.xml.XmlUtils;
import org.apache.xmlbeans.XmlException;
import org.n52.ses.io.parser.GML32Parser;
import org.n52.ses.api.event.MapEvent;
import org.n52.ses.api.exception.GMLParseException;
import org.n52.ses.eml.v002.filter.spatial.methods.ICreateBuffer;
import org.n52.ses.eml.v002.filter.spatial.methods.PostGisCreateBuffer;
import org.n52.ses.eml.v002.filterlogic.esper.customFunctions.MethodNames;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.io.ParseException;
/**
*
* @author Matthes Rieke <m.rieke@uni-muenster.de>
*
*/
public abstract class ADistanceBufferFilter extends ASpatialFilter {
private static final Logger logger = LoggerFactory
.getLogger(ADistanceBufferFilter.class);
private static final String GML_NAMESPACE = "http://www.opengis.net/gml/3.2";
/**
* qualified name of GML Point
*/
protected static final String POINT_NAME = "Point";
/**
* name of GML LinearRing
*/
protected static final String LINEAR_RING_NAME = "LinearRing";
/**
* qualified name of GML LineString
*/
protected static final String LINE_STRING_NAME = "LineString";
/**
* qualified name of GML Polygon
*/
protected static final String POLYGON_NAME = "Polygon";
/**
* the type of this filter.
*/
protected DistanceBufferType distanceBufferType;
private ICreateBuffer buffering;
private String crs = "";
private double distance;
private String uom;
private Geometry geom;
private Geometry originalGeometry;
/**
*
* Constructor
*
* @param dbOp distance buffer type
*/
public ADistanceBufferFilter(DistanceBufferType dbOp) {
this.distanceBufferType = dbOp;
this.buffering = new PostGisCreateBuffer();
}
/**
* creates the esper sub-expression
*
* @param methodName the java method name
* @return the sub-expression
*/
protected String createExpressionForDistanceFilter(String methodName) {
boolean isNot = false;
Element elem = (Element) this.distanceBufferType.getDistance().getDomNode();
String val = XmlUtils.toString(elem.getFirstChild()).trim();
this.distance = Double.parseDouble(val);
this.uom = this.distanceBufferType.getDistance().getUom();
// XmlObject elem2 = this.distanceBufferType.getDistance().selectAttribute(new QName("", "uom"));
// if (elem2 != null) {
// Node child = elem2.getDomNode().getFirstChild();
// if (child != null) {
// uom = XmlUtils.toString(child).trim();
// }
// }
//hack for snowflakes "nautical miles"...........
if (this.uom.equals("nautical mile")) {
this.uom = "[nmi_i]";
}
Node dbNode = this.distanceBufferType.getDomNode();
NodeList nodes = dbNode.getChildNodes();
for (int i = 0; i < nodes.getLength(); i++) {
this.geom = this.parseGeometry(nodes.item(i));
if (this.geom != null) {
break;
}
}
if (this.geom == null) {
logger.info("geometry not found");
return null;
}
//copy the original geom
this.originalGeometry = this.geom;
//do the buffer
this.geom = this.buffering.buffer(this.geom, this.distance, this.uom, this.crs);
String mName;
if (methodName.equals("beyond")) {
//Buffer and NOT(intersect)
isNot = true;
}
//we do an intersect to the buffer in the end
mName = "intersects";
StringBuilder sb = new StringBuilder();
if (isNot) sb.append("not(");
sb.append(MethodNames.SPATIAL_METHODS_PREFIX);
sb.append(mName+ "(");
sb.append(MethodNames.SPATIAL_METHODS_PREFIX);
//create WKT from corners
sb.append("fromWKT(\""+ this.geom.toText() +"\")");
sb.append(", ");
sb.append(MapEvent.GEOMETRY_KEY +")");
if (isNot) sb.append(")");
return sb.toString();
}
private Geometry parseGeometry (Node node) {
if (node == null) {
return null;
}
if (node.getNamespaceURI() == null) {
return null;
}
if (!node.getNamespaceURI().equals(GML_NAMESPACE)) {
//unsupported encoding
return null;
}
Geometry result = null;
String nodeName = node.getLocalName();
if (LINEAR_RING_NAME.equals(nodeName)) {
try {
LinearRingDocument lrdoc = LinearRingDocument.Factory.parse(node);
LinearRingType lrt = lrdoc.getLinearRing();
result = GML32Parser.parseGeometry(lrt);
/*
* get the srsName from posList or others
*/
if (lrt.isSetPosList()) {
this.crs = lrt.getPosList().getSrsName();
}
else {
if (lrt.getPointPropertyArray().length > 0) {
if (lrt.getPointPropertyArray()[0].isSetPoint())
this.crs = lrt.getPointPropertyArray()[0].getPoint().getSrsName();
} else if (lrt.getPosArray().length > 0) {
this.crs = lrt.getPosArray()[0].getSrsName();
} else if (lrt.getPointRepArray().length > 0) {
if (lrt.getPointRepArray()[0].isSetPoint())
this.crs = lrt.getPointRepArray()[0].getPoint().getSrsName();
}
}
} catch (ParseException e) {
logger.warn("could not parse the geometry: " + e.getMessage());
} catch (GMLParseException e) {
throw new UnsupportedOperationException(e);
}
catch (XmlException e) {
logger.warn("could not parse the geometry: " + e.getMessage());
}
}
else if (POINT_NAME.equals(nodeName)) {
try {
PointDocument pdoc = PointDocument.Factory.parse(node);
PointType pt = pdoc.getPoint();
this.crs = pt.getSrsName();
result = GML32Parser.parseGeometry(pt);
} catch (ParseException e) {
logger.warn("could not parse the geometry: " + e.getMessage());
} catch (GMLParseException e) {
throw new UnsupportedOperationException(e);
}
catch (XmlException e) {
logger.warn("could not parse the geometry: " + e.getMessage());
}
}
else if (LINE_STRING_NAME.equals(nodeName)) {
logger.debug("extract line string");
try {
LineStringDocument lsdoc = LineStringDocument.Factory.parse(node);
LineStringType lst = lsdoc.getLineString();
this.crs = lst.getSrsName();
result = GML32Parser.parseGeometry(lst);
} catch (ParseException e) {
logger.warn("could not parse the geometry: " + e.getMessage());
} catch (GMLParseException e) {
logger.warn("could not parse the geometry: " + e.getMessage());
throw new UnsupportedOperationException(e);
}
catch (XmlException e) {
logger.warn("could not parse the geometry: " + e.getMessage());
}
}
else if (POLYGON_NAME.equals(nodeName)) {
try {
PolygonDocument pdoc = PolygonDocument.Factory.parse(node);
PolygonType pt = pdoc.getPolygon();
this.crs = pt.getSrsName();
result = GML32Parser.parseGeometry(pt);
}
catch (ParseException e) {
logger.warn("could not parse the geometry: " + e.getMessage());
}
catch (GMLParseException e) {
throw new UnsupportedOperationException(e);
}
catch (XmlException e) {
logger.warn("could not parse the geometry: " + e.getMessage());
}
}
return result;
}
/**
* @return the distance of this buffer
*/
public double getDistance() {
return this.distance;
}
/**
* @return the uom of this buffer
*/
public String getUom() {
return this.uom;
}
/**
* @return the geometry of this buffer
*/
public Geometry getOriginalGeometry() {
return this.originalGeometry;
}
/**
* @return the coordinate reference system of this distancebuffer
*/
public String getCRS() {
return this.crs;
}
}