Monday, 15 November 2010

Single-Sided Buffers in JTS

Due to popular demand I have added the capability to generate Single-Sided Buffers to JTS.

A single-sided buffer is the polygon formed by connecting a LineString to an offset curve generated on one side of the line.

Input Line

Single-Sided Buffer (width = 30)

Naturally either side can be specified, by choosing an appropriate sign for the offset distance (positive for the right side, negative for the left).

Single-Sided Buffer (width = -30)

At the moment there's a bit of a limitation, in that input linework with very narrow concave angles (relative to the buffer distance) create undesirable artifacts in the generated polygon. I'm hoping that some further thinking will come up with a way to avoid this, at least in most normal cases.

This functionality is accessed by setting an appropriate flag in the BufferParameters structure:
 BufferParameters bufParams = new BufferParameters();
bufParams.setSingleSided(true);
return BufferOp.bufferOp(geom, distance, bufParams);

Currently this code is in SVN. It will be released in JTS 1.12 (which will hopefully be shipping before year-end in Q2 2011).

7 comments:

  1. Hey interesting!
    Actually, I was looking into doing something similar: offset lines.
    However an offset line would have to be allowed to intersect itself.
    Applications would be various:
    - apply a repeating symbol on one side of a given line (common in certain type of cartography, e.g., depicting fault lines)
    - label along a line with perpendicular offset

    Would it be hard to derive a "offset line" algorithm from your "single side buffer" one?

    ReplyDelete
  2. Great. Thanks for all Martin.
    A JTS fan

    ReplyDelete
  3. @Andrea:

    In fact my original goal was to develop an offset line algorithm, but it turned out to be quite tricky to implement. The single-sided buffer turned out to be easier to implement (at least in the current limited form), so that's why it got done so quickly.

    I'm still thinking about doing offset lines, though. GEOS has an implementation of this, which I might try copying. I think it still has limitations, though.

    One thing the GEOS algorithm definitely doesn't do is to create self-intersecting lines. I think I understand why you want this, but I'm not sure if it's truly possible to do this in a consistent way. More thought required!

    ReplyDelete
  4. Yeah, I hear your pain. I've tried to cook my own implementation of an offset line algorith. It works fine as long as the offset distance is less than the segment lengths, but once it goes above all sorts of issues pop up. Could not fix it.. :-(

    Also looked at various other implementations, MapServer has one, GRASS too, and in some way or the other they all fail in some case (some create huge spikes on sharp angles, other fail to respect the offset distance in some cases, and so on)

    ReplyDelete
  5. You've said: It will be released in JTS 1.1.2. Is it correct? Or do you mean 1.12?

    I can't find setSingleSided method in jts 1.11 downloaded from source forge...

    ;)

    ReplyDelete
  6. Er, yes, I meant 1.12.

    That should be released Real Soon Now.

    ReplyDelete
  7. It's a bit of a hack, but one way that I found to get the offset line is to use the single sided offset buffer and remove the original line and the last, closing point. If the original line was well formed and had no duplicates, then removing the original line is easy. This obviously wouldn't work if the original line self-intersected, because in that case the noding may change.

    A proper implementation would obviiously be much better, but for me this was a useful quick-and-dirty hack. I'll change my code once the full implemtation is done.

    ReplyDelete