/* * Copyright (c) 2012 Data Harmonisation Panel * * 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: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.io.gml.geometry.handler; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.xml.namespace.QName; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.LinearRing; 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.instance.geometry.DefaultGeometryProperty; import eu.esdihumboldt.hale.common.instance.model.Instance; import eu.esdihumboldt.hale.common.schema.geometry.CRSDefinition; import eu.esdihumboldt.hale.common.schema.geometry.GeometryProperty; import eu.esdihumboldt.hale.common.schema.model.TypeConstraint; import eu.esdihumboldt.hale.common.schema.model.constraint.type.Binding; import eu.esdihumboldt.hale.common.schema.model.constraint.type.GeometryType; import eu.esdihumboldt.hale.io.gml.geometry.FixedConstraintsGeometryHandler; import eu.esdihumboldt.hale.io.gml.geometry.GMLGeometryUtil; import eu.esdihumboldt.hale.io.gml.geometry.GeometryHandler; import eu.esdihumboldt.hale.io.gml.geometry.GeometryNotSupportedException; import eu.esdihumboldt.hale.io.gml.geometry.constraint.GeometryFactory; /** * Handler for ring geometries (parsed to {@link LinearRing}s). * * @author Simon Templer */ public class RingHandler extends FixedConstraintsGeometryHandler { private static final String RING_TYPE = "RingType"; private static final ALogger log = ALoggerFactory.getLogger(RingHandler.class); private static final GenericGeometryHandler genericHandler = new GenericGeometryHandler(); /** * @see GeometryHandler#createGeometry(Instance, int, IOProvider) */ @Override public Object createGeometry(Instance instance, int srsDimension, IOProvider reader) throws GeometryNotSupportedException { return createGeometry(instance, srsDimension, true, reader); } /** * Create a {@link LinearRing} geometry from the given instance. * * @param instance the instance * @param srsDimension the SRS dimension * @param allowTryOtherDimension if trying another dimension is allowed on * failure (e.g. 3D instead of 2D) * @param reader the I/O Provider to get value * @return the {@link LinearRing} geometry * @throws GeometryNotSupportedException if the type definition doesn't * represent a geometry type supported by the handler */ protected GeometryProperty<LinearRing> createGeometry(Instance instance, int srsDimension, boolean allowTryOtherDimension, IOProvider reader) throws GeometryNotSupportedException { LinearRing ring = null; // for use with GML 2, 3, 3.1, 3.2 // use generic geometry handler to read curveMembers as MultiLineString // or LineString Collection<GeometryProperty<?>> properties = genericHandler.createGeometry(instance, srsDimension, reader); if (properties != null) { if (properties.size() == 1) { // geometry could be combined GeometryProperty<?> prop = properties.iterator().next(); try { ring = getGeometryFactory().createLinearRing( filterDuplicates(prop.getGeometry().getCoordinates())); } catch (IllegalArgumentException e) { if (allowTryOtherDimension) { // the error // "Points of LinearRing do not form a closed // linestring" // can be an expression of a wrong dimension being used // we try an alternative, to be sure (e.g. 3D instead of // 2D) int alternativeDimension = (srsDimension == 2) ? (3) : (2); GeometryProperty<LinearRing> geom = createGeometry(instance, alternativeDimension, false, reader); log.debug("Assuming geometry is " + alternativeDimension + "-dimensional."); return geom; } throw e; } if (ring != null) { CRSDefinition crsDef = prop.getCRSDefinition(); if (crsDef == null) { GMLGeometryUtil.findCRS(instance); } return new DefaultGeometryProperty<LinearRing>(crsDef, ring); } } else { throw new GeometryNotSupportedException( "Ring components could not be combined to a geometry"); } } throw new GeometryNotSupportedException(); } /** * Filter duplicate appearing directly after each other in a sequence of * coordinates. * * @param coordinates the sequence of coordinates * @return the filtered sequence */ private Coordinate[] filterDuplicates(Coordinate[] coordinates) { if (coordinates == null) { return null; } Coordinate lastCoordinate = null; List<Coordinate> result = new ArrayList<>(coordinates.length); for (Coordinate coordinate : coordinates) { if (lastCoordinate == null || !lastCoordinate.equals3D(coordinate)) { result.add(coordinate); lastCoordinate = coordinate; } } return result.toArray(new Coordinate[result.size()]); } @Override protected Collection<? extends TypeConstraint> initConstraints() { Collection<TypeConstraint> constraints = new ArrayList<TypeConstraint>(2); constraints.add(Binding.get(GeometryProperty.class)); constraints.add(GeometryType.get(LinearRing.class)); constraints.add(new GeometryFactory(this)); return constraints; } @Override protected Set<? extends QName> initSupportedTypes() { Set<QName> types = new HashSet<QName>(); types.add(new QName(NS_GML, RING_TYPE)); types.add(new QName(NS_GML_32, RING_TYPE)); return types; } }