/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2013, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library 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 * Lesser General Public License for more details. */ package org.geotoolkit.geometry.jts.transform; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.CoordinateSequence; import com.vividsolutions.jts.geom.CoordinateSequenceFactory; import static org.geotoolkit.geometry.jts.transform.CoordinateSequenceMathTransformer.DEFAULT_CS_FACTORY; import org.opengis.referencing.operation.TransformException; /** * * @author Johann Sorel (Geomatys) */ public class CoordinateSequenceWrapTransformer implements CoordinateSequenceTransformer { private final CoordinateSequenceFactory csf; private final double[] worldspan; private final double[] wrapdistance; private final double[] translation; private final boolean wrapOnX; private boolean wrap = false; /** * Default wrap coordinate sequence transformer. * @see CoordinateSequenceWrapTransformer#CoordinateSequenceWrapTransformer(com.vividsolutions.jts.geom.CoordinateSequenceFactory, double[], double[]) */ public CoordinateSequenceWrapTransformer(final double[] worldspan) { this(null,worldspan); } /** * Wrap coordinate sequence transformer with given factory. * * @param csf * @param worldspan world span on each axis, only one axis should have a value, the other must be zero. */ public CoordinateSequenceWrapTransformer(final CoordinateSequenceFactory csf, final double[] worldspan) { if(csf == null){ this.csf = DEFAULT_CS_FACTORY; }else{ this.csf = csf; } this.worldspan = worldspan; this.wrapdistance = new double[]{worldspan[0]/2.0,worldspan[1]/2.0}; this.translation = worldspan.clone(); wrapOnX = (wrapdistance[0] != 0); } @Override public CoordinateSequence transform(CoordinateSequence sequence, int minpoints) throws TransformException { final int size = sequence.size(); final Coordinate[] tcs = new Coordinate[size]; boolean directionChecked = false; Coordinate previous = null; Coordinate current = null; for(int i= 0; i<size; i++){ current = sequence.getCoordinate(i); if(previous != null){ final double distance = Math.abs( wrapOnX ? current.x-previous.x : current.y-previous.y); //we test distance < worldspan[0], to avoid the case of lines which make a full world wrap if(wrapOnX && distance>=wrapdistance[0] && distance < worldspan[0] ){ //assume it crosses the antimeridian wrap = !wrap; //this is the first warp we found, check in which direction we fix it //the objective is to regroup the points so the wrap distance must be smaller then the base distance if(!directionChecked){ directionChecked = true; final double test = Math.abs((current.x+translation[0])-previous.x); if(test>distance){ //inverse the translation values translation[0] = -translation[0]; translation[1] = -translation[1]; } } }else if(!wrapOnX && distance>=wrapdistance[1] && distance < worldspan[1]){ wrap = !wrap; if(!directionChecked){ directionChecked = true; final double test = Math.abs((current.y+translation[1])-previous.y); if(test>distance){ //inverse the translation values translation[0] = -translation[0]; translation[1] = -translation[1]; } } } } previous = current; if(wrap){ tcs[i] = new Coordinate(current.x+translation[0], current.y+translation[1], current.z); }else{ tcs[i] = current; } } return csf.create(tcs); } }