Background:
As GE has no built in circle function, I have generated some code in Python to create a list of coordinates (in decimal degrees) about a centre point - which should form a circle. In the same Python script, I have then created a KML file (aptly named 'circles'), in which the coordinate points generated are written to in a format which should allow them to be the vertices of the circular polygon I am trying to create.
This is the Python script which generates the coordinate points for the circle and exports them to the KML file:
import math
# opens a file for writing/ creates it if it does not exist
file = open ('circles.kml', 'w+')
def generate_circle(file, lat_deg, lon_deg, radius_km):
# Mean Earth radius (needed for calculation).
earth_radius_km = 6371
earth_radius_m = earth_radius_km * 1000
# Distance is entered in km, convert to meters.
radius_m = radius_km * 1000
angular_distance = radius_m/earth_radius_m
# Convert coordinates from degrees to radians.
lat_rad = math.radians(lat_deg)
lon_rad = math.radians(lon_deg)
# start generating KML code in file
file.write ("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" )
file.write ("<kml xmlns=\"http://www.opengis.net/kml/2.2\" xmlns:gx=\"http://www.google.com/kml/ext/2.2\""
" xmlns:kml=\"http://www.opengis.net/kml/2.2\" xmlns:atom=\"http://www.w3.org/2005/Atom\">")
file.write ("\n<Document>\n\t<Placemark>\n\t\t<name>Circle</name>\n" )
file.write ("\t\t<Polygon>\n\t\t\t<extrude>1</extrude>\n\t\t\t<altitudeMode>relativeToGround</altitudeMode>\n\t\t\t<outerBoundaryIs>\n\t\t\t\t<LinearRing>\n\t\t\t\t\t<coordinates>\n")
# Create a list of angles at which to create points (how many points will the circle consist of).
numPoints = range(0, 360, 10)
angles = []
for x in numPoints:
angles.append(float(x))
angles.append(float(0))
# Calculate and file.write out the list of coordinates.
for angle in angles:
# Convert bearing to radians and calculates new lat/lon values
bearing = math.radians(angle)
new_lat = math.asin(math.sin(lat_rad) * math.cos(angular_distance) + math.cos(lat_rad) * math.sin(angular_distance) * math.cos(bearing))
new_lon = lon_rad + math.atan2(math.sin(bearing) * math.sin(angular_distance) * math.cos(lat_rad), math.cos(angular_distance) - math.sin(lat_rad) * math.sin(new_lat))
# Convert new lat and lon to degrees
new_lat_deg = math.degrees(new_lat)
new_lon_deg = math.degrees(new_lon)
# Print them out
file.write ('\t\t\t\t\t\t{0}, {1}\n'.format (str(new_lat_deg), str(new_lon_deg)))
# generates KML code to end file
file.write ("\n\t\t\t\t\t</coordinates>\n\t\t\t\t</LinearRing>\n\t\t\t</outerBoundaryIs>\n\t\t</Polygon>")
file.write ("\n\t</Placemark>\n</Document>\n</kml>")
file.close ()
generate_circle(file, 51.13046, -0.18433, 3)
This script then generates the 'circles.kml' file with the following code:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2" xmlns:kml="http://www.opengis.net/kml/2.2" xmlns:atom="http://www.w3.org/2005/Atom">
<Document>
<Placemark>
<name>Circle</name>
<Polygon>
<extrude>1</extrude>
<altitudeMode>relativeToGround</altitudeMode>
<outerBoundaryIs>
<LinearRing>
<coordinates>
51.15743964817757, -0.18433
51.15702952889536, -0.17686020516372258
51.155811653802246, -0.16961776449158056
51.15382308927849, -0.1628230771806833
51.15112435160843, -0.15668284950397615
51.14779755677011, -0.15138378358603402
51.14394391134279, -0.14708688836809072
51.13968062247034, -0.14392258756569956
51.13513732257409, -0.14198677322557574
51.1304521191404, -0.14133792278558727
51.12576739098043, -0.1419953635060592
51.121225459580394, -0.1439387320133288
51.11696426736606, -0.14710863972615704
51.11311319387112, -0.1514085183214467
51.10978913602661, -0.15670758424327305
51.10709297028997, -0.16284482854858487
51.105106502425905, -0.16963390895039396
51.1038899958304, -0.176868795451506
51.10348035182245, -0.18433
51.1038899958304, -0.191791204548494
51.105106502425905, -0.19902609104960603
51.10709297028997, -0.20581517145141515
51.10978913602661, -0.21195241575672694
51.11311319387112, -0.2172514816785533
51.11696426736606, -0.22155136027384292
51.121225459580394, -0.2247212679866712
51.12576739098043, -0.22666463649394078
51.1304521191404, -0.22732207721441272
51.13513732257409, -0.22667322677442425
51.13968062247034, -0.22473741243430043
51.14394391134279, -0.22157311163190926
51.14779755677011, -0.21727621641396597
51.15112435160843, -0.21197715049602384
51.15382308927849, -0.20583692281931668
51.155811653802246, -0.19904223550841943
51.15702952889536, -0.1917997948362774
51.15743964817757, -0.18433
</coordinates>
</LinearRing>
</outerBoundaryIs>
</Polygon>
</Placemark>
</Document>
</kml>
The problem:
When the KML file is imported into GE, the file itself and the polygon are visible in 'My Places' but the polygon does not appear on the map whatsoever - instead defaulting to a 0,0 position.
As I'm aware that KML is very particular about the order of coordinates for polygons being listed in an anti-clockwise order, I tried reformatting my KML file to allow for this - but the same thing happened again and the polygon still wasn't being displayed. As well as this, the opacity in the properties box in GE is showing the polygon as having a 100% opacity, so the polygon should definitely be visible.
I'm still relatively new to KML and would love to learn how to create circles by generating coordinate points rather than simply using the available online KML Circle Generator tools. I've found that there's very little (if any) documentation on this issue, so any help would be greatly appreciated!!
Your KML file has an extra space after the comma in each coordinate pair. If you remove those spaces, the polygon shows up (in the Indian Ocean). Looks like an oval in this case, which may be a projection issue?
The coordinates should look like: 51.15743964817757,-0.18433
There should not be a space after the comma (inside the coordinate pair), but there can be a space (or line return like you have) separating coordinate pairs. I'm don't know much about Python, but I think you just need to change one line to remove the space, like this:
# Print them out
file.write ('\t\t\t\t\t\t{0},{1}\n'.format (str(new_lat_deg), str(new_lon_deg)))
Also, note that you have your <altitudeMode>
set to "relativeToGround", which is normally used to raise features above the ground... but your coordinates don't include any altitude value (it would be a 3rd term in each coordinate, such as: 51.15743,-0.18433,100
for 100m high). You can either add altitude numbers to each coordinate pair, or just change your altitudeMode to be "clampToGround", which is the default and will put the feature on the terrain over land, or on the sea surface over water.