8000 Fix VariableBuffer to handle zero distances by dr-jts · Pull Request #997 · locationtech/jts · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Fix VariableBuffer to handle zero distances #997

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
8000 Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@
/**
* Creates a buffer polygon with a varying buffer distance
* at each vertex along a line.
* Vertex distances may be zero.
* <p>
* Only single lines are supported as input, since buffer widths
* Only single linestrings are supported as input, since buffer widths
* are typically specified individually for each line.
*
* @author Martin Davis
Expand Down Expand Up @@ -221,7 +222,7 @@ public VariableBuffer(Geometry line, double[] distance) {
}

/**
* Computes the buffer polygon.
* Computes the variable buffer polygon.
*
* @return a buffer polygon
*/
Expand All @@ -244,7 +245,7 @@ public Geometry getResult() {
.createGeometryCollection(GeometryFactory.toGeometryArray(parts));
Geometry buffer = partsGeom.union();

// ensure an empty polygon is returned if needed
//-- ensure an empty polygon is returned if needed
if (buffer.isEmpty()) {
return geomFactory.createPolygon();
}
Expand All @@ -256,15 +257,24 @@ public Geometry getResult() {
* with the given endpoints and buffer distances.
* The individual segment buffers are unioned
* to form the final buffer.
* If one distance is zero, the end cap at that
* segment end is the endpoint of the segment.
* If both distances are zero, no polygon is returned.
*
* @param p0 the segment start point
* @param p1 the segment end point
* @param dist0 the buffer distance at the start point
* @param dist1 the buffer distance at the end point
* @return the segment buffer.
* @return the segment buffer, or null if void
*/
private Polygon segmentBuffer(Coordinate p0, Coordinate p1,
double dist0, double dist1) {
/**
* Skip polygon if both distances are zero
*/
if (dist0 <= 0 && dist1 <= 0)
return null;

/**
* Compute for increasing distance only, so flip if needed
*/
Expand Down Expand Up @@ -293,22 +303,25 @@ private Polygon segmentBuffer(Coordinate p0, Coordinate p1,
LineSegment seg = new LineSegment(p0, p1);
Coordinate tr0 = seg.reflect(t0);
Coordinate tr1 = seg.reflect(t1);
//-- avoid numeric jitter if first distance is zero
if (dist0 == 0)
tr0 = p0.copy();

CoordinateList coords = new CoordinateList();
coords.add(t0);
coords.add(t1);
coords.add(t0, false);
coords.add(t1, false);

// end cap
addCap(p1, dist1, t1, tr1, coords);

coords.add(tr1);
coords.add(tr0);
coords.add(tr1, false);
coords.add(tr0, false);

// start cap
addCap(p0, dist0, tr0, t0, coords);

// close
coords.add(t0);
coords.add(t0, false);

Coordinate[] pts = coords.toCoordinateArray();
Polygon polygon = geomFactory.createPolygon(pts);
Expand Down Expand Up @@ -345,6 +358,11 @@ private Polygon circle(Coordinate center, double radius) {
* @param coords the coordinate list to add to
*/
private void addCap(Coordinate p, double r, Coordinate t1, Coordinate t2, CoordinateList coords) {
//-- handle zero-width at vertex
if (r == 0) {
coords.add(p.copy(), false);
return;
}

double angStart = Angle.angle(p, t1);
double angEnd = Angle.angle(p, t2);
Expand All @@ -357,7 +375,7 @@ private void addCap(Coordinate p, double r, Coordinate t1, Coordinate t2, Coordi
for (int i = indexStart; i > indexEnd; i--) {
// use negative increment to create points CW
double ang = capAngle(i);
coords.add( projectPolar(p, r, ang) );
coords.add( projectPolar(p, r, ang), false );
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@

public class VariableBufferTest extends GeometryTestCase {

private static final double DEFAULT_TOLERANCE = 1.0e-6;
//-- low tolerance reduces expected geometry literal size
private static final double DEFAULT_TOLERANCE = 1.0e-2;

public VariableBufferTest(String name) {
super(name);
Expand Down Expand Up @@ -49,7 +50,7 @@ public void testSegmentInverseDist() {
public void testSegmentSameDist() {
checkBuffer("LINESTRING (100 100, 200 100)",
10, 10,
"POLYGON ((90 100, 90.19214719596769 101.95090322016128, 90.76120467488713 103.8268343236509, 91.68530387697454 105.55570233019603, 92.92893218813452 107.07106781186548, 94.44429766980397 108.31469612302546, 96.1731656763491 109.23879532511287, 98.04909677983872 109.80785280403231, 100 110, 200 110, 200 110, 201.95090322016128 109.80785280403231, 203.8268343236509 109.23879532511287, 205.55570233019603 108.31469612302546, 207.07106781186548 107.07106781186548, 208.31469612302544 105.55570233019603, 209.23879532511287 103.8268343236509, 209.8078528040323 101.95090322016128, 210 100, 209.8078528040323 98.04909677983872, 209.23879532511287 96.1731656763491, 208.31469612302544 94.44429766980397, 207.07106781186548 92.92893218813452, 205.55570233019603 91.68530387697454, 203.8268343236509 90.76120467488713, 201.95090322016128 90.19214719596769, 200 90, 100 90, 100 90, 98.04909677983872 90.19214719596769, 96.1731656763491 90.76120467488714, 94.44429766980397 91.68530387697454, 92.92893218813452 92.92893218813452, 91.68530387697454 94.44429766980397, 90.76120467488713 96.1731656763491, 90.19214719596769 98.04909677983872, 90 100))"
"POLYGON ((90.192 101.951, 90.761 103.827, 91.685 105.556, 92.929 107.071, 94.444 108.315, 96.173 109.239, 98.049 109.808, 100 110, 200 110, 201.951 109.808, 203.827 109.239, 205.556 108.315, 207.071 107.071, 208.315 105.556, 209.239 103.827, 209.808 101.951, 210 100, 209.808 98.049, 209.239 96.173, 208.315 94.444, 207.071 92.929, 205.556 91.685, 203.827 90.761, 201.951 90.192, 200 90, 100 90, 98.049 90.192, 96.173 90.761, 94.444 91.685, 92.929 92.929, 91.685 94.444, 90.761 96.173, 90.192 98.049, 90 100, 90.192 101.951))"
);
}

Expand All @@ -74,6 +75,20 @@ public void testLargeDistance() {
);
}

public void testZeroDistanceAtVertex() {
checkBuffer("LINESTRING( 10 10, 20 20, 30 30)",
new double[] { 5, 0, 5 },
"MULTIPOLYGON (((5.096 10.975, 5.381 11.913, 5.843 12.778, 6.464 13.536, 7.222 14.157, 7.943 14.557, 20 20, 14.557 7.943, 14.157 7.222, 13.536 6.464, 12.778 5.843, 11.913 5.381, 10.975 5.096, 10 5, 9.025 5.096, 8.087 5.381, 7.222 5.843, 6.464 6.464, 5.843 7.222, 5.381 8.087, 5.096 9.025, 5 10, 5.096 10.975)), ((25.443 32.057, 25.843 32.778, 26.464 33.536, 27.222 34.157, 28.087 34.619, 29.025 34.904, 30 35, 30.975 34.904, 31.913 34.619, 32.778 34.157, 33.536 33.536, 34.157 32.778, 34.619 31.913, 34.904 30.975, 35 30, 34.904 29.025, 34.619 28.087, 34.157 27.222, 33.536 26.464, 32.057 25.443, 20 20, 25.443 32.057)))"
);
}

public void testZeroDistancesForSegment() {
checkBuffer("LINESTRING( 10 10, 20 20, 30 30, 40 40)",
new double[] { 5, 0, 0, 5 },
"MULTIPOLYGON (((5.096 10.975, 5.381 11.913, 5.843 12.778, 6.464 13.536, 7.222 14.157, 7.943 14.557, 20 20, 14.557 7.943, 14.157 7.222, 13.536 6.464, 12.778 5.843, 11.913 5.381, 10.975 5.096, 10 5, 9.025 5.096, 8.087 5.381, 7.222 5.843, 6.464 6.464, 5.843 7.222, 5.381 8.087, 5.096 9.025, 5 10, 5.096 10.975)), ((35.443 42.057, 35.843 42.778, 36.464 43.536, 37.222 44.157, 38.087 44.619, 39.025 44.904, 40 45, 40.975 44.904, 41.913 44.619, 42.778 44.157, 43.536 43.536, 44.157 42.778, 44.619 41.913, 44.904 40.975, 45 40, 44.904 39.025, 44.619 38.087, 44.157 37.222, 43.536 36.464, 42.057 35.443, 30 30, 35.443 42.057)))"
);
}

private void checkBuffer(String wkt, double startDist, double endDist,
String wktExpected) {
Geometry geom = read(wkt);
Expand All @@ -82,6 +97,14 @@ private void checkBuffer(String wkt, double startDist, double endDist,
checkBuffer(result, wktExpected);
}

private void checkBuffer(String wkt, double[] dist,
String wktExpected) {
Geometry geom = read(wkt);
Geometry result = VariableBuffer.buffer(geom, dist);
//System.out.println(result);
checkBuffer(result, wktExpected);
}

private void checkBuffer(Geometry actual, String wktExpected) {
Geometry expected = read(wktExpected);
checkEqual(expected, actual, DEFAULT_TOLERANCE);
Expand Down
0