com.vividsolutions.jts.densify.Densifier Maven / Gradle / Ivy
Show all versions of JTSplus Show documentation
/*
* The JTS Topology Suite is a collection of Java classes that
* implement the fundamental operations required to validate a given
* geo-spatial data set to a known topological specification.
*
* Copyright (C) 2001 Vivid Solutions
*
* 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; either
* version 2.1 of the License, or (at your option) any later version.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jts.densify;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.geom.util.GeometryTransformer;
/**
* Densifies a {@link Geometry} by inserting extra vertices along the line segments
* contained in the geometry.
* All segments in the created densified geometry will be no longer than
* than the given distance tolerance.
* Densified polygonal geometries are guaranteed to be topologically correct.
* The coordinates created during densification respect the input geometry's
* {@link PrecisionModel}.
*
* Note: At some future point this class will
* offer a variety of densification strategies.
*
* @author Martin Davis
*/
public class Densifier {
/**
* Densifies a geometry using a given distance tolerance,
* and respecting the input geometry's {@link PrecisionModel}.
*
* @param geom the geometry to densify
* @param distanceTolerance the distance tolerance to densify
* @return the densified geometry
*/
public static Geometry densify(Geometry geom, double distanceTolerance) {
Densifier densifier = new Densifier(geom);
densifier.setDistanceTolerance(distanceTolerance);
return densifier.getResultGeometry();
}
/**
* Densifies a coordinate sequence.
*
* @param pts
* @param distanceTolerance
* @return the densified coordinate sequence
*/
private static Coordinate[] densifyPoints(Coordinate[] pts,
double distanceTolerance, PrecisionModel precModel) {
LineSegment seg = new LineSegment();
CoordinateList coordList = new CoordinateList();
for (int i = 0; i < pts.length - 1; i++) {
seg.p0 = pts[i];
seg.p1 = pts[i + 1];
coordList.add(seg.p0, false);
double len = seg.getLength();
int densifiedSegCount = (int) (len / distanceTolerance) + 1;
if (densifiedSegCount > 1) {
double densifiedSegLen = len / densifiedSegCount;
for (int j = 1; j < densifiedSegCount; j++) {
double segFract = (j * densifiedSegLen) / len;
Coordinate p = seg.pointAlong(segFract);
precModel.makePrecise(p);
coordList.add(p, false);
}
}
}
coordList.add(pts[pts.length - 1], false);
return coordList.toCoordinateArray();
}
private Geometry inputGeom;
private double distanceTolerance;
/**
* Creates a new densifier instance.
*
* @param inputGeom
*/
public Densifier(Geometry inputGeom) {
this.inputGeom = inputGeom;
}
/**
* Sets the distance tolerance for the densification. All line segments
* in the densified geometry will be no longer than the distance tolereance.
* simplified geometry will be within this distance of the original geometry.
* The distance tolerance must be positive.
*
* @param distanceTolerance
* the densification tolerance to use
*/
public void setDistanceTolerance(double distanceTolerance) {
if (distanceTolerance <= 0.0)
throw new IllegalArgumentException("Tolerance must be positive");
this.distanceTolerance = distanceTolerance;
}
/**
* Gets the densified geometry.
*
* @return the densified geometry
*/
public Geometry getResultGeometry() {
return (new DensifyTransformer()).transform(inputGeom);
}
class DensifyTransformer extends GeometryTransformer {
protected CoordinateSequence transformCoordinates(
CoordinateSequence coords, Geometry parent) {
Coordinate[] inputPts = coords.toCoordinateArray();
Coordinate[] newPts = Densifier
.densifyPoints(inputPts, distanceTolerance, parent.getPrecisionModel());
// prevent creation of invalid linestrings
if (parent instanceof LineString && newPts.length == 1) {
newPts = new Coordinate[0];
}
return factory.getCoordinateSequenceFactory().create(newPts);
}
protected Geometry transformPolygon(Polygon geom, Geometry parent) {
Geometry roughGeom = super.transformPolygon(geom, parent);
// don't try and correct if the parent is going to do this
if (parent instanceof MultiPolygon) {
return roughGeom;
}
return createValidArea(roughGeom);
}
protected Geometry transformMultiPolygon(MultiPolygon geom, Geometry parent) {
Geometry roughGeom = super.transformMultiPolygon(geom, parent);
return createValidArea(roughGeom);
}
/**
* Creates a valid area geometry from one that possibly has bad topology
* (i.e. self-intersections). Since buffer can handle invalid topology, but
* always returns valid geometry, constructing a 0-width buffer "corrects"
* the topology. Note this only works for area geometries, since buffer
* always returns areas. This also may return empty geometries, if the input
* has no actual area.
*
* @param roughAreaGeom
* an area geometry possibly containing self-intersections
* @return a valid area geometry
*/
private Geometry createValidArea(Geometry roughAreaGeom) {
return roughAreaGeom.buffer(0.0);
}
}
}