/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-2008, Open Source Geospatial Foundation (OSGeo)
*
* 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.geotools.renderer.crs;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryComponentFilter;
import com.vividsolutions.jts.geom.LineString;
/**
* Wraps the coordinates at the discontinuity so that they are always moved towards East
* (fundamental in order to have all pieces of a complex geometry moved into the same direction).
*
* @author Andrea Aime - OpenGeo
*/
class WrappingCoordinateFilter implements GeometryComponentFilter {
static final int EAST_TO_WEST = 0;
static final int WEST_TO_EAST = 1;
static final int NOWRAP = 2;
double wrapLimit;
double offset;
/**
* Builds a new wrapper
*
* @param wrapLimit
* Subsequent coordinates whose X differ from more than {@code wrapLimit} are
* supposed to be wrapping the dateline and need to be offsetted
* @param offset
* The offset to be applied to coordinates to unwrap them
*/
public WrappingCoordinateFilter(double wrapLimit, double offset) {
this.wrapLimit = wrapLimit;
this.offset = offset;
}
public void filter(Geometry geom) {
// this filter will receive either points, which we don't consider,
// or lines, that we need to wrap
if (geom instanceof LineString) {
LineString ls = (LineString) geom;
CoordinateSequence cs = ls.getCoordinateSequence();
int direction = getDisconinuityDirection(cs);
if (direction == NOWRAP)
return;
applyOffset(cs, direction == EAST_TO_WEST ? 0 : wrapLimit * 2);
}
}
private int getDisconinuityDirection(CoordinateSequence cs) {
double lastX = cs.getX(0);
for (int i = 0; i < cs.size(); i++) {
double x = cs.getX(i);
if (Math.abs(x - lastX) > wrapLimit) {
if (x > lastX)
return WEST_TO_EAST;
else if (x < lastX)
return EAST_TO_WEST;
}
lastX = x;
}
return NOWRAP;
}
private void applyOffset(CoordinateSequence cs, double offset) {
double lastX = cs.getX(0);
for (int i = 0; i < cs.size(); i++) {
double x = cs.getX(i);
if (Math.abs(x - lastX) > wrapLimit) {
if (offset != 0)
offset = 0;
else
offset = wrapLimit * 2;
}
if (offset != 0)
cs.setOrdinate(i, 0, x + offset);
lastX = x;
}
}
}