'Creating buffer spaces in meters around LineString line in KML using Python

Any suggestions to create buffer spaces on kml linestring using python? I tried with few libraries..

geojson
shapely
kml2geojson

Here, converted kml to geojson and added buffer space on the linestring and output should be polygon


import kml2geojson
import json

from shapely.geometry import shape
from geojson import Point, Feature, FeatureCollection, dump

filename = "filekml"
direction = "left"
numbers = 5
kml2geojson.main.convert(filename + '.kml', '')
features = []
try:

    with open(filename + '.geojson') as geojson_file:
        data = json.load(geojson_file)
        for feat in data['features']:
            if direction == "left":
                result = shape(feat['geometry']).buffer(numbers, single_sided=True)
            if direction == "right":
                result = shape(feat['geometry']).buffer(-numbers, single_sided=True)
            if direction == "both":
                result = shape(feat['geometry']).buffer(numbers)
            features.append(Feature(geometry=result))
        feature_collection = FeatureCollection(features)
        with open(filename + '.geojson', 'w') as f:
            dump(feature_collection, f)
        f.close()
except Exception as e:
    print(e)

Below is the kml

<?xml version="1.0" encoding="utf-8" ?>
<kml>
<Document id="root_doc">
<Folder><name>Test</name>
  <Placemark>
    <Style><LineStyle><color>ff0000ff</color></LineStyle><PolyStyle><fill>0</fill></PolyStyle></Style>
      <MultiGeometry><LineString><coordinates>-93.3367092468336,30.4822077397353 -93.3367001199999,30.482718171</coordinates></LineString></MultiGeometry>
  </Placemark>
</Folder>
</Document></kml>

Below is the output (Geojson)

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              -93.3367,
              30.482718
            ],
            [
              -93.336709,
              30.482208
            ],
            [
              -93.336722,
              30.482208
            ],
            [
              -93.336713,
              30.482718
            ],
            [
              -93.3367,
              30.482718
            ]
          ]
        ]
      },
      "properties": {}
    }
  ]
}

Please give any suggestions to create buffer spaces of line or points.



Solution 1:[1]

To buffer a line in WGS84 coordinates and extend it by a distance in meters, you can use shapely and pyproj for the reprojection, and export the shape to KML using simplekml.

The azimuthal equidistant projection (aka aeqd) is an azimuthal map projection that provides points on the map that are at proportionally correct distances from the center point. Create buffered line in aeqd coordinate space then reproject to WGS-84.

from shapely.geometry import LineString, CAP_STYLE
from pyproj import Transformer
from shapely.ops import transform
import simplekml

# pick 2 end points of a line with longitude and latitude
pt1 = [-0.14062046656000524, 51.501870264040775]
pt2 = [-0.12901012017525443, 51.50659618852008]

# buffer length in meters
width = 100

lons = [pt1[0], pt2[0]]
lats = [pt1[1], pt2[1]]

# create Azimuthal Equidistant (aeqd) projection with units in meters
# with the center of projection at the center of the line
local_azimuthal_projection = "+proj=aeqd +R=6371000 +units=m +lat_0={} +lon_0={}".format(
    (lats[0] + lats[1]) / 2, (lons[0] + lons[1]) / 2
)
wgs84_to_aeqd = Transformer.from_proj('+proj=longlat +datum=WGS84 +no_defs',
                                      local_azimuthal_projection)
aeqd_to_wgs84 = Transformer.from_proj(local_azimuthal_projection,
                                      '+proj=longlat +datum=WGS84 +no_defs')

line_transformed = transform(wgs84_to_aeqd.transform,
                             LineString([pt1, pt2]))

buffer = line_transformed.buffer(width, cap_style=CAP_STYLE.square)
line_wgs84 = transform(aeqd_to_wgs84.transform, buffer)

# Next export as KML

kml = simplekml.Kml()
# add start and end points to the KML to show the points
kml.newpoint(coords=[(lons[0], lats[0])])
kml.newpoint(coords=[(lons[1], lats[1])])
ls = kml.newlinestring(tessellate=1,
                       coords=list(line_wgs84.exterior.coords),
                       altitudemode=simplekml.AltitudeMode.clamptoground)
ls.style.linestyle.color = 'ffff00aa'  # purple
ls.style.linestyle.width = 3
kml.save("line.kml")

Output:

The line is buffered with 100 meters length added to the line end points such that the length of the edges are each 200 meters.

Line displayed in Google Earth

Alternatively, you could use the ruler tool in Google Earth Pro to measure a distance n-meters from the start and end points of a line then manually draw the boundary around it and save the Placemark as a KML file.

Solution 2:[2]

Creating buffer spaces in kml is bit complicated to me using python, so I tried to convert the kml to geojson and able to add buffer spaces on that,.. using below libraries,

kml2geojson

Using the kml2geojson library converted kml or kmz file to geojson.. and

shapely

Using shape library added buffer spaces for all the lines and points.. Read some documentation of the above libraries to avoid any kind of doubts..

Thanks

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Gokul Raghu