GPS(csv) to KML python - cchamchi/cansat GitHub Wiki

์บ”์œ„์„ฑ์—์„œ ๊ธฐ๋กํ•œ GPS ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ๊ธ€์–ด์Šค์˜ KMLํŒŒ์ผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” python ์„ ์•Œ์•„๋ณด์ž

์˜ˆ์ œ ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ์—์„œ ๋ฐœ์ทŒํ•˜์˜€๋‹ค.

์บ”์œ„์„ฑ์—์„œ ๊ธฐ๋กํ•œ csv๋กœ๊ทธ ํŒŒ์ผ์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

date,time,time_index,mode,longitude,latitude,altitude,numsat,speed,cource,bearing,distance,controlangle
90718,105851,563,1,127.10637,37.301155,81.8,12,0,166.32,251.2,3881.29,84.88
90718,105852,564,1,127.10637,37.301155,81.9,12,0,166.32,251.2,3881.29,84.88
90718,105853,565,1,127.10637,37.301155,81.9,12,0,166.32,251.2,3881.29,84.88
90718,105854,566,1,127.10637,37.301155,81.9,12,0,166.32,251.2,3881.29,84.88
90718,105855,567,1,127.10638,37.301155,82,12,0.01,166.32,251.2,3882.63,84.88
90718,105856,568,1,127.10638,37.301155,82.2,12,0.01,166.32,251.2,3882.63,84.88
90718,105857,569,1,127.10638,37.301151,82.3,12,0.02,166.32,251.21,3882.5,84.89
90718,105858,570,1,127.10638,37.301151,82.4,12,0.01,166.32,251.21,3882.5,84.89

1. KML root๋งŒ๋“ค๊ธฐ

๊ตฌ๊ธ€ ์–ด์Šค์˜ KML ํ˜•ํƒœ๋Š” ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ  ํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
   <Document>
    ๋‚ด์šฉ....
    ๋‚ด์šฉ....
   </Document>
</kml>

ํŒŒ์ด์„  ๋ผ์ด๋ธŒ๋Ÿฌ์ค‘์— xml.dom.minidom ์„ import ํ•œ๋‹ค. DOM ํ˜•์‹์— ๋Œ€ํ•œ ์ž์„ธํ•œ ์„ค๋ช…์€ ์—ฌ๊ธฐ์ฐธ๊ณ ํ•˜๊ธฐ ๋ฐ”๋ž€๋‹ค.

import xml.dom.minidom

์šฐ์„  xml ์ „์ฒด ๋‹คํ๋จผํŠธ๋ฅผ ํ•˜๋‚˜ ๋งŒ๋“ค๊ณ  ๊ทธ์•ˆ์— ํ•˜๋‚˜์”ฉ ๊ฐ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

kmlDoc = xml.dom.minidom.Document()

์ด์ œ kmlDoc ์ด๋ผ๋Š” ํฐ ๋ฐ‘๊ทธ๋ฆผ์ด ์ƒ๊ฒผ๋‹ค.

kmlElement = kmlDoc.createElementNS('http://www.opengis.net/kml/2.2', 'kml')
kmlElement.setAttribute('xmlns','http://www.opengis.net/kml/2.2')
kmlElement = kmlDoc.appendChild(kmlElement)

๋งจ์ฒ˜์Œ ์žˆ๋Š” kml ์š”์†Œ๋ฅผ ๋งŒ๋“ค๊ณ  kmlDoc์— append ์‹œํ‚จ๋‹ค. ๋‹ค์Œ์€ Document ์š”์†Œ ์ด๋‹ค.

documentElement = kmlDoc.createElement('Document')
documentElement = kmlElement.appendChild(documentElement)

๊ฐ™์€ ๋ฐฉ๋ฒ•์œผ๋กœ documentElement์„ ์ƒ์„ฑํ•˜๊ณ  ์ด๋ฒˆ์—๋Š” kmlElement์— append์‹œํ‚จ๋‹ค.

์ž ์—ฌ๊ธฐ ๊นŒ์ง€ ์ดํ•ด๊ฐ€ ๊ฐ€๋Š”๊ฐ€?

์ด์ œ๋Š” csv๋ฅผ ์ฝ๊ณ  row ๋งˆ๋‹ค placemark๋ฅผ appendํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

placemark ์— ์•ž์„œ ์•ฝ๊ฐ„์˜ ๊พธ๋ฏธ๊ธฐ ๊ณผ์ •์„ ํ•ด๋ณด์ž

name ๋งŒ๋“ค๊ธฐ

<name>Cansat Flight path</name>

kml์˜ ์ด๋ฆ„์ด ๋‚˜์˜ค๊ฒŒ ํ•œ๋‹ค.

 nameElement = kmlDoc.createElement('name')
 nameElement.appendChild(kmlDoc.createTextNode('Cansat Flight path'))
 documentElement.appendChild(nameElement)

์ฐธ ์‰ฝ์ฃ ์ž‰..

์•„์ด์ฝ˜ ์Šคํƒ€์ผ ๋งŒ๋“ค๊ธฐ

์ด ๋ฌธ๊ตฌ๋ฅผ ์“ฐ์ง€ ์•Š์œผ๋ฉด ์—„์ฒญ ํฐ ๋…ธ๋ž‘ ์••์ •ํ•€์ด ์ง€๋„์— ๊ทธ๋ ค์ง„๋‹ค. ์•„์ด์ฝ˜์„ ๋ฐ”๊พธ๊ณ  ์‹ถ์œผ๋ฉด ์•„๋ž˜ png ํŒŒ์ผ์˜ ์ด๋ฆ„์„ ๋ฐ”๊พธ๋ฉด ๋œ๋‹ค.

์Œ.. ๊ฐ์ฒด๊ฐ€ ์ข€ ๋งŽ์ฟค... ๊ทธ๋ž˜๋„ ์ฐฌ์ฐฌํžˆ ํ•˜๋‚˜์”ฉ ํ•ด๋ณด์ž

<Style id="hiker-icon">
 <IconStyle>
   <Icon>
     <href>http://maps.google.com/mapfiles/kml/pal4/icon49.png</href>
   </Icon>
   <hotSpot x="0" y=".5" xunits="fraction" yunits="fraction"/>
 </IconStyle>
</Style>

์›ฌ์ง€ ์‰ฌ์šด ์—๋””ํ„ฐ๊ฐ€ ์žˆ์„๊บผ ๊ฐ™๋‹ค..

styleIdElement = kmlDoc.createElement('Style')
styleIdElement.setAttribute('id','hiker-icon')
documentElement.appendChild(styleIdElement)

iconStyleElement = kmlDoc.createElement('IconStyle')
styleIdElement.appendChild(iconStyleElement)

iconElement = kmlDoc.createElement('Icon')
iconStyleElement.appendChild(iconElement)

hrefElement = kmlDoc.createElement('href')
hrefElement.appendChild(kmlDoc.createTextNode('http://maps.google.com/mapfiles/kml/pal4/icon49.png'))
iconElement.appendChild(hrefElement)

hotSpotElement = kmlDoc.createElement('hotSpot')
hotSpotElement.setAttribute('x','0')
hotSpotElement.setAttribute('y','.5')
hotSpotElement.setAttribute('xunits','fraction')
hotSpotElement.setAttribute('yunits','fraction')
iconStyleElement.appendChild(hotSpotElement)

Placemark

์—ฌ๊ธฐ๊ฐ€ ๋ฉ”์ธ ๋ฃจํ”„๋ผ ํ•˜๊ฒ ๋‹ค. ์•„๋ž˜์˜ ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์–ด ๋ณด๋‹ค

<Placemark>
  <styleUrl>#hiker-icon</styleUrl>
  <Point>
    <coordinates>127.10637,37.301155,81.8</coordinates>
  </Point>
</Placemark>

placemark์š”์†Œ, styleUrl ์š”์†Œ, Point์š”์†Œ๋ฅผ ๋งŒ๋“ค๊ณ  csv์—์„œ ์œ„๋„,๊ฒฝ๋„,๊ณ ๋„๋ฅผ ์ฝ์–ด ๋ณด์ž

def extractCoord(row):
  # This extracts an address from a row and returns it as a string. This requires knowing
  # ahead of time what the columns are that hold the address information.
  return '%s,%s,%s' % (row['longitude'], row['latitude'], row['altitude'])

def createPlacemark(kmlDoc, row, order):
  # This creates a  element for a row of data.
  # A row is a dict.
  placemarkElement = kmlDoc.createElement('Placemark')
  
  #timeStampElement = kmlDoc.createElement('TimeStamp')
  #placemarkElement.appendChild(timeStampElement)
  
  styleUrlElement = kmlDoc.createElement('styleUrl')
  styleUrlElement.appendChild(kmlDoc.createTextNode('#hiker-icon'))
  placemarkElement.appendChild(styleUrlElement)
  
  pointElement = kmlDoc.createElement('Point')
  placemarkElement.appendChild(pointElement)
  
  coordinates = extractCoord(row)
  coorElement = kmlDoc.createElement('coordinates')
  coorElement.appendChild(kmlDoc.createTextNode(coordinates))
  pointElement.appendChild(coorElement)
  return placemarkElement

์ตœ์ข… ํŒŒ์ผ์„ ์—ฌ๊ธฐ์— ์˜ฌ๋ฆฐ๋‹ค. csv ํŒŒ์ผ python ํŒŒ์ผ

3์ฐจ์› ๊ฒฝ๋กœ ํ‘œ์‹œ

์•ž์˜ ์˜ˆ์ œ๋Š” ์ด๋™ ๊ฒฝ๋กœ๋ฅผ ํ‘œ์‹œ ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์ด๋‹ค. ์บ”์œ„์„ฑ์ด ๋น„ํ–‰ํ•˜๋Š” 3์ฐจ์› ๊ฒฝ๋กœ๋ฅผ ๋ณด๋ ค๋ฉด ์ƒˆ๋กœ์šด kml์„ ๋งŒ๋“ค์–ด ๋ณด์ž

document ์š”์†Œ ์•ˆ์— ์•„๋ž˜ ์š”์†Œ๋ฅผ ์ถ”๊ฐ€ ํ•˜์ž. ๋…ธ๋ž€์ƒ‰ ๊ธฐ๋‘ฅ๊ณผ ๋…น์ƒ‰ ๊ธฐ๋‘ฅ์œผ๋กœ ํ‘œ์‹œ๋œ๋‹ค.

<Style id="yellowLineGreenPoly">
   <LineStyle>
     <color>7f00ffff</color>
     <width>4</width>
   </LineStyle>
 <PolyStyle>
     <color>7f00ff00</color>
 </PolyStyle>
</Style> 
<Placemark>
  <name>Absolute Extruded</name>
  <description>Transparent green wall with yellow outlines</description>
  <styleUrl>#yellowLineGreenPoly</styleUrl>
  <LineString>
    <extrude>1</extrude>
    <tessellate>1</tessellate>
    <altitudeMode>absolute</altitudeMode>
    <coordinates> 127.0653457,37.2894706,162.2
    127.0653686,37.2894783,150.5
    127.0653991,37.2894821,140.4
    127.0654373,37.289505,131.2
    127.0654754,37.2895202,123.7
    127.0654983,37.2895202,118
    127.0655364,37.289505,113.3
    127.0655593,37.289463,111.2
    127.0655899,37.2894172,110.1
    127.065628,37.2893867,108.3
    127.0656661,37.2893524,107
    127.0657043,37.2893257,105.7
    127.0657577,37.2893066,104
    127.0657958,37.289299,102.7
    127.0658187,37.2893142,101
    127.0657958,37.2893142,99.1
    127.0659561,37.289257,72.3 </coordinates>
  </LineString> 
</Placemark>

ํŒŒ์ด์„  ์ฝ”๋“œ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค ์ „์ฒด ์ฝ”๋“œ๋Š” ์—ฌ๊ธฐ๋ฅผ ์ฐธ๊ณ ํ•˜์ž

def createKML(csvReader, fileName, order):
  # This constructs the KML document from the CSV file.
  kmlDoc = xml.dom.minidom.Document()
  
  kmlElement = kmlDoc.createElementNS('http://www.opengis.net/kml/2.2', 'kml')
  kmlElement.setAttribute('xmlns','http://www.opengis.net/kml/2.2')
  kmlElement = kmlDoc.appendChild(kmlElement)
  documentElement = kmlDoc.createElement('Document')
  documentElement = kmlElement.appendChild(documentElement)
  
  nameElement = kmlDoc.createElement('name')
  nameElement.appendChild(kmlDoc.createTextNode('Cansat Flight 3D path'))
  documentElement.appendChild(nameElement)
  
  styleIdElement = kmlDoc.createElement('Style')
  styleIdElement.setAttribute('id',"yellowLineGreenPoly")
  documentElement.appendChild(styleIdElement)
  
  lineStyleElement = kmlDoc.createElement('LineStyle')
  styleIdElement.appendChild(lineStyleElement)
  
  colorElement = kmlDoc.createElement('color')
  colorElement.appendChild(kmlDoc.createTextNode('7f00ffff'))
  lineStyleElement.appendChild(colorElement)

  widthElement = kmlDoc.createElement('width')
  widthElement.appendChild(kmlDoc.createTextNode('4'))
  lineStyleElement.appendChild(widthElement)
  
  polyStyleElement = kmlDoc.createElement('PolyStyle')
  styleIdElement.appendChild(polyStyleElement)
  
  colorElement = kmlDoc.createElement('color')
  colorElement.appendChild(kmlDoc.createTextNode('7f00ff00'))
  polyStyleElement.appendChild(colorElement)  
 
    
  placemarkElement = kmlDoc.createElement('Placemark')
  documentElement.appendChild(placemarkElement)
  
  styleUrlElement = kmlDoc.createElement('styleUrl')
  styleUrlElement.appendChild(kmlDoc.createTextNode('#yellowLineGreenPoly'))
  placemarkElement.appendChild(styleUrlElement)  
  
  lineStringElement = kmlDoc.createElement('LineString')
  placemarkElement.appendChild(lineStringElement)  
  
  extrudeElement = kmlDoc.createElement('extrude')
  extrudeElement.appendChild(kmlDoc.createTextNode('1'))
  lineStringElement.appendChild(extrudeElement)   
  
  tessellateElement = kmlDoc.createElement('tessellate')
  tessellateElement.appendChild(kmlDoc.createTextNode('1'))
  lineStringElement.appendChild(tessellateElement) 
  
  altitudeModeElement = kmlDoc.createElement('altitudeMode')
  altitudeModeElement.appendChild(kmlDoc.createTextNode('absolute'))
  lineStringElement.appendChild(altitudeModeElement)   

  # Skip the header line.  
  csvReader.next()
  
  coordinatesElement = kmlDoc.createElement('coordinates')
  
  for row in csvReader:
    coordinatesElement.appendChild(kmlDoc.createTextNode(extractCoord(row)))
    
  lineStringElement.appendChild(coordinatesElement)   
  


  kmlFile = open(fileName, 'w')
  kmlFile.write(kmlDoc.toprettyxml('  ', newl = '\n', encoding = 'utf-8'))

์•„๋ž˜ ๋กœ๊ทธ๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ตฌ๊ธ€ ์–ด์Šค์—์„œ ์ง์ ‘ ๊ทธ๋ ค ๋ณด์ž

cansat logํŒŒ์ผ

๊ฒฝ๋กœ kml

3D๊ฒฝ๋กœ kml

๊ตฌ๊ธ€ ์–ด์Šค์—์„œ ๋‘๊ฐœ์˜ kml ํŒŒ์ผ์„ ํ•จ๊ป˜ ๊ทธ๋ฆฌ๋ฉด ์•„๋ž˜ ์ฒ˜๋Ÿผ 3์ฐจ์› ๋น„ํ–‰ ๊ฒฝ๋กœ๋ฅผ ๋ถ„์„ํ• ์ˆ˜ ์žˆ๋‹ค.

Fly to

๊ตฌ๊ธ€ ์–ด์Šค์˜ ๋†€๋ผ์šด ๊ธฐ๋Šฅ์ด ๋” ์žˆ๋‹ค. ์œ„๋„, ๊ฒฝ๋„, ๊ณ ๋„, ๋ฐฉํ–ฅ๊ฐ์„ ๋„ฃ์–ด ์ฃผ๋ฉด ์บ”์œ„์„ฑ์ด ๋‚™ํ•˜ํ•˜๋ฉด์„œ ๋ณด๋Š” view๋ฅผ ๊ทธ๋Œ€๋กœ ์‹œ๋ฎฌ๋ ˆ์ด์…˜ ๊ฐ€๋Šฅํ•˜๋‹ค.

์š”๊ฑด ํŒŒ์ด์„  ์ฝ”๋“œ

flyto kml

โš ๏ธ **GitHub.com Fallback** โš ๏ธ