読み書きプログラミング

日常のプログラミングで気づいたことを綴っています

Google Earthコンテンツの作り方 (4) ーフォルダからツアを作るー

パソコン版では、(凝ったことを考えなければ)フォルダからツアを見ることは簡単です。

スイスの有名な山々の目印を作りましたので、例にご利用ください。

http://y-ich.github.io/kml/example_swiss.kml

インポートしたフォルダをアクティブにして、「場所」ペインの下辺に見えるフォルダアイコンにマウスを重ねると「ツアーを再生」という文字がポップアップします。クリックすればフォルダ内の目印を巡るツアーが始まります。


Google Earthにはツアーを記録することでツアーを生成する機能もあります。メニュー欄の「追加」メニューからツアーを追加して下さい。「録音」ボタンが現れます。

「録音」ボタンをクリックしてから、フォルダの「ツアーを再生」をクリックすると、ツアーが記録されます。フォルダのツアーの再生が終わったらツアーの記録を終了させて下さい。記録された内容の再生が始まります。「録音」パネルが「再生」パネルに変わっていますので、その中のフロッピーアイコンをクリックすると、新規ツアーのウィンドウが開きますので、名前を入れて完了して下さい。

このツアーをKMLファイルとして保存し、スマートデバイスで読み込めばツアーが再生されます。簡単ですね。


ところが、2つの点でこのKMLファイルは不満です。1点目はサイズが必要以上に大きいということです。(この例で50kbytes。)なぜかというと、Google Earthはツアーを記録する際にコマ撮りのように記録します。移動中のビューも記録されるのでサイズが大きくなります。2点目は記録の際のツアーと記録されたツアーが違うということです。フォルダのツア再生はあるアルゴリズムで軌道が生成されますが、記録されたツアーはある種のコマ撮り記録なので再生の結果が異なります。環境設定でコマ撮りの細かさについて設定できるのですが、コマ撮りを荒くすると記録された再生が波打つようになり、コマ撮りを細かくするとファイルのサイズが大きくなるということになります。


コマ撮りの記録ではなく、フォルダのツア再生と同じアルゴリズムを使うKMLファイルを生成することでこれを避けることができます。


KMLXMLの拡張なので、XMLを扱うライブラリがあれば、比較的簡単にフォルダをツアに変換することができます。私はRubyとそのXML用ライブラリNokogiriを使ってみました。

# -*- coding: utf-8 -*-
# folder2tour.rb: a Tour generator from Folder with Placemark

require "nokogiri"

unless ARGV.length == 1
    $stderr.puts 'Usage: ruby folder2tour.rb <kml file>' 
    exit
end

doc = Nokogiri::XML(File.open(ARGV[0]) { |f| f.read })

folder = doc.xpath('/xmlns:kml/xmlns:Document/xmlns:Folder')[0]

kml = Nokogiri::XML <<'EOS'
<?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>
    <gx:Tour>
        <gx:Playlist>
        </gx:Playlist>
    </gx:Tour>
</Document>
</kml>
EOS

kml.xpath('/xmlns:kml/xmlns:Document/gx:Tour/gx:Playlist')[0].add_previous_sibling folder.xpath('xmlns:name')[0].dup
playlist = kml.xpath('//gx:Playlist')[0]
playlist.default_namespace = '' # 以降の操作を楽にするためデフォルト名前空間を変更
playlist.name = 'gx:Playlist' #名前空間を変更するとタグ名が変わるので元に戻す。

folder.xpath('xmlns:Placemark').each do |p|
    flyTo = Nokogiri::XML::Node::new 'gx:FlyTo', kml
    duration = Nokogiri::XML::Node::new 'gx:duration', kml
    duration.content = 10
    flyTo.add_child duration
# 目印にLookAtタグかCameraタグがあればそこへFlyToする。なければ上空1000mからのLookAtを使う。
    scenes = p.xpath('xmlns:LookAt|xmlns:Camera')
    if scenes.empty?
        lookAt = Nokogiri::XML::Node::new 'LookAt', kml
        coordinates = p.xpath('xmlns:Point/xmlns:coordinates')[0].content.split(',').map {|e| e.to_f}
        flyTo.add_child <<"EOS"
<LookAt>
    <longitude>#{coordinates[0]}</longitude>
    <latitude>#{coordinates[1]}</latitude>
    <altitude>#{coordinates[2]}</altitude>
    <heading>0</heading>
    <tilt>0</tilt>
    <range>1000</range>
</LookAt>
EOS
    else
        flyTo.add_child scenes[0].dup
    end
    playlist.add_child flyTo
    playlist.add_child "<gx:Wait><gx:duration>3</gx:duration></gx:Wait>"
end

puts kml.to_s

引数に変換したい目印フォルダのKMLファイル名を与えると、標準出力にツアKMLを出力します。コマ撮りではなく、目印のビューをgx:FlyToというツア用のタグで結びますので、Google Earthがその間の軌跡を決定します。ファイルサイズは2.4kbytesです。


ツアを生成して、スマートデバイスで再生してみて下さい。ツアを再生するには、ツアKMLファイルを直接読み込んで下さい。スマートデバイスGoogle EarthKML内の最初のツアを自動再生します。目印のバルーンを表示させるためにやったようにNetworkLinkを使って読み込むと再生を開始してくれません。


前回までは、Google Earthの編集機能を使ってKMLを生成しましたが、今回は、Rubyスクリプトを使ってKMLを生成してみました。スクリプトで扱うことによって、コンテンツ制作の際に一定のルールで記述する部分を自動化することができます。

次回はツアなどに有効なキャプションを作ります。