/* * Copyright (c) 2017 wetransform GmbH * * All rights reserved. This program and the accompanying materials are made * available 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. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * wetransform GmbH <http://www.wetransform.to> */ package eu.esdihumboldt.hale.common.instance.geometry; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import de.fhg.igd.slf4jplus.ALogger; import de.fhg.igd.slf4jplus.ALoggerFactory; import eu.esdihumboldt.hale.common.core.io.IOProvider; import eu.esdihumboldt.hale.common.core.io.Value; import eu.esdihumboldt.util.geometry.interpolation.InterpolationAlgorithm; import eu.esdihumboldt.util.geometry.interpolation.InterpolationUtil; import eu.esdihumboldt.util.geometry.interpolation.extension.InterpolationAlgorithmFactory; import eu.esdihumboldt.util.geometry.interpolation.extension.InterpolationExtension; import eu.esdihumboldt.util.geometry.interpolation.grid.GridInterpolation; import eu.esdihumboldt.util.geometry.interpolation.grid.GridUtil; import eu.esdihumboldt.util.geometry.interpolation.split.SplitInterpolation; /** * Helper for handling interpolation for instance readers. * * @author Simon Templer */ public class InterpolationHelper { private static final ALogger log = ALoggerFactory.getLogger(InterpolationHelper.class); /** * Identifier of the default algorithm. */ public static final String DEFAULT_ALGORITHM = SplitInterpolation.EXTENSION_ID; /** * Parameter name for the selection of the interpolation algorithm. */ public static final String PARAMETER_INTERPOLATION_ALGORITHM = "interpolation.algorithm"; /** * Parameter name for the interpolation maximum positional error setting. */ public static final String PARAMETER_MAX_POSITION_ERROR = "interpolation.maxError"; /** * Default parameter value for the interpolation setting */ public static final double DEFAULT_MAX_POSITION_ERROR = 0.1; /** * Get the interpolation algorithm for a given instance reader. * * @param instanceReader the instance reader * @param factory the geometry factory * @return the interpolation algorithm */ public static InterpolationAlgorithm getInterpolation(IOProvider instanceReader, GeometryFactory factory) { // FIXME weak cache based on reader? String algorithmId = instanceReader.getParameter(PARAMETER_INTERPOLATION_ALGORITHM) .as(String.class, DEFAULT_ALGORITHM); InterpolationAlgorithmFactory fact = InterpolationExtension.getInstance() .getFactory(algorithmId); if (fact == null) { log.warn("Could not find interpolation algorithm with ID " + algorithmId); fact = InterpolationExtension.getInstance().getFactory(DEFAULT_ALGORITHM); } if (fact == null) { throw new IllegalStateException("Default interpolation algorithm could not be found"); } InterpolationAlgorithm result; try { result = fact.createExtensionObject(); } catch (Exception e) { log.error("Interpolation algorithm could be created", e); result = new SplitInterpolation(); } double maxPositionalError = getMaxPositionalError(instanceReader); // configure the algorithm Map<String, Value> configuration = new HashMap<>(); instanceReader.storeConfiguration(configuration); Map<String, String> properties = new HashMap<>(); for (Entry<String, Value> entry : configuration.entrySet()) { if (!entry.getValue().isRepresentedAsDOM()) { properties.put(entry.getKey(), entry.getValue().getStringRepresentation()); } } result.configure(factory, maxPositionalError, properties); return result; } /** * Get the maximum positional error for geometry interpolation. * * @param instanceReader the instanced reader configured with interpolation * settings * @return the maximum positional error */ public static double getMaxPositionalError(IOProvider instanceReader) { // determine maximum positional error // FIXME smart default? probably depends on the reference system return instanceReader.getParameter(PARAMETER_MAX_POSITION_ERROR).as(Double.class, DEFAULT_MAX_POSITION_ERROR); } /** * Determine if the interpolation algorithm requires all geometries being * moved to a grid. * * @param instanceReader the instance reader w/ the interpolation * configuration * @return if geometries should be moved to a grid */ public static boolean requiresGeometriesMovedToGrid(IOProvider instanceReader) { String algorithmId = instanceReader.getParameter(PARAMETER_INTERPOLATION_ALGORITHM) .as(String.class, DEFAULT_ALGORITHM); if (GridInterpolation.EXTENSION_ID.equals(algorithmId)) { // fixed check for specific interpolation algorithm and parameter // XXX rather handle via extension point? return instanceReader.getParameter(GridInterpolation.PARAMETER_MOVE_ALL_TO_GRID) .as(Boolean.class, false); } else { return false; } } /** * Move the given coordinates to a grid if required. * * @param instanceReader the instance reader with the interpolation * configuration * @param coordinates the coordinates to process * @return the original or moved coordinates */ public static Coordinate[] moveCoordinates(IOProvider instanceReader, final Coordinate[] coordinates) { if (requiresGeometriesMovedToGrid(instanceReader)) { // move all coordinates to the grid double gridSize = GridUtil.getGridSize(getMaxPositionalError(instanceReader)); List<Coordinate> newCoordinates = new ArrayList<>(coordinates.length); for (Coordinate coordinate : coordinates) { InterpolationUtil.addIfDifferent(newCoordinates, GridUtil.movePointToGrid(coordinate, gridSize)); } return newCoordinates.toArray(new Coordinate[newCoordinates.size()]); } else { // keep original return coordinates; } } /** * Move the given coordinate to a grid if required. * * @param instanceReader the instance reader with the interpolation * configuration * @param coordinate the coordinate to process * @return the original or moved coordinates */ public static Coordinate moveCoordinate(IOProvider instanceReader, final Coordinate coordinate) { if (requiresGeometriesMovedToGrid(instanceReader)) { // move coordinate to the grid double gridSize = GridUtil.getGridSize(getMaxPositionalError(instanceReader)); return GridUtil.movePointToGrid(coordinate, gridSize); } else { // keep original return coordinate; } } }