GeometryConverter.java

/*
 * Copyright (C) 2016 - 2017 B3Partners B.V.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package nl.b3p.topnl.converters;

import java.io.IOException;
import java.io.InvalidClassException;
import java.io.StringReader;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.geotools.gml3.ArcParameters;
import org.geotools.gml3.CircleRadiusTolerance;
import org.geotools.xsd.Parser;
import org.jdom2.input.DOMBuilder;
import org.jdom2.output.XMLOutputter;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.PrecisionModel;
import org.locationtech.jts.simplify.DouglasPeuckerSimplifier;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

/**
 * @author Meine Toonen meinetoonen@b3partners.nl
 */
public class GeometryConverter {

  protected static final Log log = LogFactory.getLog(GeometryConverter.class);

  private static final double DISTANCE_TOLERANCE = 0.001;
  protected static final double LINEARIZATION_TOLERANCE_MULTIPLIER = 0.01; // 0.001;

  private Parser parser;
  private GeometryFactory geometryFactory;

  protected static final int SRID = 28992;

  public GeometryConverter() {
    GeometryFactory gf = new GeometryFactory(new PrecisionModel(), SRID);

    /*  GMLConfiguration gml3Config = new GMLConfiguration(true);
    gml3Config.setGeometryFactory(gf);
    gml3Config.setExtendedArcSurfaceSupport(true);*/

    ArcParameters arcParameters =
        new ArcParameters(new CircleRadiusTolerance(LINEARIZATION_TOLERANCE_MULTIPLIER)); // new
    // AbsoluteTolerance(LINEARIZATION_TOLERANCE));

    org.geotools.gml3.GMLConfiguration gml3Config = new org.geotools.gml3.GMLConfiguration();
    gml3Config.setExtendedArcSurfaceSupport(true);
    gml3Config.getContext().registerComponentInstance(gf);
    gml3Config.getContext().registerComponentInstance(arcParameters);
    parser = new Parser(gml3Config);
    this.geometryFactory = gf;
  }

  public Geometry convertGeometry(Element el)
      throws IOException, SAXException, ParserConfigurationException, TransformerException {
    if (!(el instanceof org.w3c.dom.Element)) {
      throw new IllegalArgumentException("gml org.w3c.node is not an org.w3c.Element");
    }
    // TODO: maybe convert node directly to a source / inputsource / reader / stream for parser.
    // instead of JDOM detour.
    org.jdom2.Element elem = new DOMBuilder().build((org.w3c.dom.Element) el);
    String gmlString = new XMLOutputter().outputString(elem);
    gmlString = gmlString.replaceAll("gml:", "");
    // tySstem.out.println("gmlString:" + gmlString);
    //   parser.getNamespaces().declarePrefix("gml", "http://www.opengis.net/gml/3.2");
    Object parsedObject = parser.parse(new StringReader(gmlString));
    if (parsedObject instanceof Geometry) {
      Geometry geom = (Geometry) parsedObject;
      if (!geom.isValid()) {
        geom = geom.buffer(0.0);
        log.debug("Geometry is invalid. Made valid by buffering with 0");
      }
      // arcs can have nodes that are on the same point (28992; 3 digit precision): simplify
      Geometry simplGeom = DouglasPeuckerSimplifier.simplify(geom, DISTANCE_TOLERANCE);
      return simplGeom;
    } else {
      throw new InvalidClassException(
          parsedObject.getClass().getCanonicalName(), "Parsed object not of class Geometry.");
    }
  }
}