sas18
sas18

Reputation: 161

Effective animation in google earth plugin

Some background.

There are several ways to animate things in GE plugin. I can think of:

  1. Use batched API calls to move stuff in "frameend" event. Due to known issue these calls are rather slow in some browsers. Before framerate drops to unacceptable lows we could fire about 150 API calls/frame. Which is just not enough.

  2. To save costly API calls, generate KML for entire frame and add/remove them to GE in "frameend". This is what I currently do. Performance isn't too good either. I believe it's due to object re-creation overhead.

  3. Use "update" in KML to update rather than re-create objects each frame. According to docs, "the file containing the NetworkLinkControl must have been loaded by a NetworkLink". Also, parseKml just doesn't accept NetworkLinkControl. So, it looks like this method requires server interactions and thus doesn't provide required smoothness and interactivity (yes, I do download some raw data from the server, but animation is done client-side based on processed data and user interactions). I'm even thinking of local web server to fool GE..

  4. Touring. This is what I'm currently investigating. I didn't find how to hide TourPlayer control and plan to put something above it using "iframe shim" technique. Now, I'm stuck with playing tour parsed by parseKml. It plays just fine if loaded by fetchKml - camera and placemarks move. But the same tour loaded via parseKml only moves camera, not placemarks. It looks like here applies the same limitation as in #3.

Here is my code:

<script src="https://www.google.com/jsapi"></script>
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script>

google.load("earth", "1")

var originalUrl = 'http://localhost/original.xml'
var tourUrl     = 'http://localhost/tour.xml'

var ge
$(function() {
    google.earth.createInstance('ge', function(instance) {
        ge = instance
        google.earth.fetchKml(ge, originalUrl, function(o) {
            ge.getFeatures().appendChild(o)
        })
    })
})

function tour(t) {
    ge.getTourPlayer().setTour(t)
    ge.getTourPlayer().play()
}

function fetchKml() {
    google.earth.fetchKml(ge, tourUrl, tour)
}

function parseKml() {
    $.get(tourUrl, function(kml) {
        tour(ge.parseKml(kml))
    }, 'text')
}

</script>
<div id="ge"></div>
<button onclick="fetchKml()">fetchKml</button>
<button onclick="parseKml()">parseKml</button>

original.xml:

<Folder>
    <Placemark><name>A</name><Point id="a"></Point></Placemark>
    <Placemark><name>B</name><Point id="b"></Point></Placemark>
</Folder>

and tour.xml:

<?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">
    <gx:Tour>
        <gx:Playlist>
            <gx:FlyTo>
                <gx:duration>2</gx:duration>
                <LookAt><range>50</range></LookAt>
            </gx:FlyTo>
            <gx:AnimatedUpdate>
                <gx:duration>10</gx:duration>
                <Update>
                    <targetHref>http://localhost/original.xml</targetHref>
                    <Change>
                        <Point targetId="b"><coordinates>0.0001,0.0001,0</coordinates></Point>
                    </Change>
                </Update>
            </gx:AnimatedUpdate>
            <gx:FlyTo>
                <gx:duration>10</gx:duration>
                <LookAt><range>50</range><latitude>0.0001</latitude><longitude>0.0001</longitude></LookAt>
            </gx:FlyTo>
        </gx:Playlist>
    </gx:Tour>
</kml>

Pressing "fetchKml" moves B away of A, camera follows - correct. Pressing "parseKml" only moves camera, A and B stay in place - incorrect.

And my questions.

Q1. Is there something wrong with my code, or #4 just doesn't work w/o server interaction?

Q2. Is there mistakes in what I told you in #1-#4?

Q3. What are other animation methods to try?

Q4. Any general advice?

Thank you.

Upvotes: 2

Views: 832

Answers (1)

Fraser
Fraser

Reputation: 17094

Q1 - yes.

Using parseKml will not work for the simple reason that the elements created will no longer have any reference to the target href that you have specified.

To explain - when you load data into the plugin via fetchKml the id of each object is made unique by appending it to the url that the kml was loaded from. So in your example the points ID would be http://localhost/original.xml#b

However, you are loading the kml as text - then you are parsing in into the plugin - so from the plugins perspective the data didn't come from http://localhost/original.xml - the objects were created using the API, much the same as if you had called createPoint, so the point ID is simply b.

This means <targetHref>http://localhost/original.xml</targetHref> is wrong - because the data didn't come from http://localhost/original.xml it came from calling parseKml on some text - the url unknown to the plugin.

Essentially you are trying to update http://localhost/original.xml#b but that object doesn't exist - because the object wasn't created from that URL.

Q2 - yes.

"...parseKml just doesn't accept NetworkLinkControl."

You can't create a NetworkLinkControl via parseKml because you can't create a NetworkLinkControl object in the api. There is no such thing as a KmlNetworkLinkControl so there are no objects to create if you parse a kml file that contains a NetworkLinkControl. It has nothing to do with "server interactions".

Q3&4

As for general advice - simply updating the geometry of objects using the API is one of the simplest way to animate them, wrapping calls to the API in the executeBatch can make this process much less expensive in terms of processing.

Upvotes: 1

Related Questions