1

I'm attemping to buffer a polyline that the user has drawn on a map (Google maps and OSM map). The user specifies a distance in metres and a polygon should be drawn around the polyline representing this buffer zone.

I'm currently doing this by making an AJAX call passing the Wkt string of the polyline down to the server and buffering server-side and then passing the new polygon back to the front end and adding it to the map. (The Wkt string sent to the server contains the LatLng values of the points along the polyline).

However, the resulting polygon appears incorrect (I think technically its correct, but displayed wrong/differently to the polyline). The polygon follows the curvature of the Earth, where as the drawn polyline does not and so they don't match up. I'm buffering the polyline in WGS84.

For example, the black line is the drawn polyline, the red polygon is the buffer:

Incorrect buffer

How would I have to buffer the polyline so the resulting polygon matches up?

Server-side code that creates the buffer zone:

public GenericResponse AddBufferZone(AddBufferZoneRequest request)
{
  if (request == null) throw new ArgumentNullException("request");
  if (request.Identification == null) throw new InvalidOperationException("request.Identification");

  try
  {                 
    SqlGeography shape = null;
    SqlGeography bufferZone = null;
    List<String> bufferZones = new List<String>();

    shape = SqlGeography.STGeomFromText(new SqlChars(new SqlString(request.TargetShapeWkt)), 4326);
    if (!shape.STIsValid())
    {
      throw new OpenFoundationException(String.Format("Shape is invalid - IsValidDetailed ({0}).", shape.IsValidDetailed()));
    }

    foreach (var distance in request.BufferSize)
    {
      bufferZone = shape.STBuffer(distance);
      if (!bufferZone.STIsValid())
      {
        throw new OpenFoundationException(String.Format("Buffer Zone is invalid - IsValidDetailed ({0}).", bufferZone.IsValidDetailed()));
      }

      bufferZones.Add(bufferZone.ToString());
    }       

    Newtonsoft.Json.JsonSerializerSettings settings = Common.Utilities.JSONHelpers.DefaultServerSerialiserSettings(false,null);

    var json = Newtonsoft.Json.JsonConvert.SerializeObject(bufferZones, settings);

    GenericResponse response = new GenericResponse(true, json, null);
    return response;
  }     
  catch (Exception)
  {
    throw new OpenFoundationException("Failed to create Buffer Zone(s)."); ;
  }
}

Client-side code adding the polygon to the map:

addBufferZone: function (shape, layer, bufferZoneOptions, index) {
/// <summary>
/// Adds a buffer zone to the map
/// </summary>
var that = this,
  wkt,
  object; 

// Shape should be in Wkt format
wkt = new Wkt.Wkt();
that._registerWktLibrary();

wkt.read(shape);

// Create the google object and setMap
object = wkt.toObject();       

// Add the key and distance
object.bufferZoneKey = bufferZoneOptions.bufferZoneKey;
object.distance = bufferZoneOptions.distance;
object.setOptions({
  fillColor: bufferZoneOptions.fillColor || "black",
  strokeOpacity: 0,
  fillOpacity: layer._customOpacity != null ? layer._customOpacity : 0.5
});       

object.setMap(that._map);

that._addPopupToShape(object);

if (index != null) {
  layer.shape.bufferZones.splice(index, 0, object);
} else {
  // Add to the bufferZone collection
  layer.shape.bufferZones.push(object);          
}
},

I can't seem to figure out a way around this. If I create SqlGeometries instead of Geographies I can buffer them correctly, however I can't buffer them in metres, only in degree's, which is something I don't want to do. I've used some basic formula to convert metres to degree's but the resulting polygon is too inaccurate.

EDIT: I no longer have the code that I used to densify the line, but essentially I created a new SqlGeographyBuilder, and for each point in the LineString I'd break it down into a minimum of 25 segments. Worked out the difference between the Long and Lat of Point N and Point N + 1 and used that to work out more points along the line. I would end up with the following Wkt:

Wkt of line:

LINESTRING (-48.8671875 51.179342979289267, -36.38671875 35.60371874069731, -28.828125 51.179342979289267)

Wkt of densifyed line:

LINESTRING (-48.8671875 51.179342979289267, -48.36796875 50.556318009745588, -47.86875 49.93329304020191, -47.36953125 49.310268070658232, -46.8703125 48.687243101114554, -46.37109375 48.064218131570875, -45.871875 47.4411931620272, -45.37265625 46.818168192483519, -44.8734375 46.195143222939841, -44.37421875 45.572118253396162, -43.875 44.949093283852484, -43.37578125 44.326068314308806, -42.8765625 43.703043344765128, -42.37734375 43.080018375221449, -41.878125 42.456993405677771, -41.37890625 41.833968436134093, -40.8796875 41.210943466590415, -40.38046875 40.587918497046736, -39.88125 39.964893527503058, -39.38203125 39.34186855795938, -38.8828125 38.7188435884157, -38.38359375 38.095818618872023, -37.884375 37.472793649328345, -37.38515625 36.849768679784667, -36.8859375 36.226743710240989, -36.38671875 35.60371874069731, -36.38671875 35.60371874069731, -36.084375 36.226743710240989, -35.78203125 36.849768679784667, -35.4796875 37.472793649328345, -35.17734375 38.095818618872023, -34.875 38.7188435884157, -34.57265625 39.34186855795938, -34.2703125 39.964893527503058, -33.96796875 40.587918497046736, -33.665625 41.210943466590415, -33.36328125 41.833968436134093, -33.0609375 42.456993405677771, -32.75859375 43.080018375221449, -32.45625 43.703043344765128, -32.15390625 44.326068314308806, -31.8515625 44.949093283852484, -31.54921875 45.572118253396162, -31.246875 46.195143222939841, -30.94453125 46.818168192483519, -30.6421875 47.4411931620272, -30.33984375 48.064218131570875, -30.0375 48.687243101114554, -29.73515625 49.310268070658232,-29.4328125 49.93329304020191, -29.13046875 50.556318009745588, -28.828125 51.179342979289267, -28.828125 51.179342979289267)
  • How about densifying the original line before buffering so that it has for example 1 degree long segments? – user30184 Aug 19 '15 at 8:19
  • I've added more points along the line programaticaly client-side and server side with my own code which improved the situation somewhat, but it was still not correct as the resulting buffer polygon was still curved. If I were to add more points along the line while drawing it/editing it, it does improve considerably per point. With enough points added in the buffer looks correct. – Steve H Aug 19 '15 at 8:30
  • How does your server side code look like? Could you show the WKT before and after densification? – user30184 Aug 19 '15 at 8:34
  • I've updated my post. I no longer have the code I used but can re-write it (or something similar) – Steve H Aug 19 '15 at 9:01
  • Is the base map in your application in EPSG:3857? In that case you should do also the densification in EPSG:3857 space. That actually happens when your users draw the line on the map with more vertices. Or stay in EPSG:3857 all the time and never convert coordinates into lon-lat degrees. – user30184 Aug 19 '15 at 9:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.