classdef kmlAnimation < handle %KMLANIMATION(name) Create a KML animation helper, allowing you to create timed animations. % This class should not be instantiated directly, but instead through kml.newAnimation % % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ properties kml name tour playlist end methods function this = kmlAnimation(KML, Name) assert(isa(KML,'kml'),'Invalid usage of kmlAnimation'); this.kml = KML; this.name = Name; this.tour = this.kml.xml.createElement('gx:Tour'); this.playlist = this.kml.xml.createElement('gx:Playlist'); this.tour.appendChild(this.kml.textNode('name',this.name)); this.tour.appendChild(this.playlist); this.kml.doc.appendChild(this.tour); end function updateLocation(this,target,waitingTime,longitude,latitude,altitude) if numel(target)>1 if numel(longitude)==1 longitude = repmat(longitude,numel(target),1); end if numel(latitude)==1 latitude = repmat(latitude,numel(target),1); end if numel(altitude)==1 altitude = repmat(altitude,numel(target),1); end for i = 1:numel(target) this.updateLocation(target(i),waitingTime,longitude(i),latitude(i),altitude(i)); end return end assert(isfield(target,'location_id'),'Invalid target for location update'); kml = this.kml; [longitude,latitude] = kml.checkUnit(longitude,latitude); animUpdate = kml.xml.createElement('gx:AnimatedUpdate'); update = kml.xml.createElement('Update'); change = kml.xml.createElement('Change'); location = kml.xml.createElement('Location'); animUpdate.appendChild(kml.textNode('gx:duration',sprintf('%0.16g',waitingTime))); location.setAttribute('targetId',target.location_id); location.appendChild(kml.textNode('latitude', sprintf('%0.16g',latitude))); location.appendChild(kml.textNode('longitude', sprintf('%0.16g',longitude))); location.appendChild(kml.textNode('altitude', sprintf('%0.16g',altitude))); change.appendChild(location); update.appendChild(change); animUpdate.appendChild(update); this.playlist.appendChild(animUpdate); end function updateOrientation(this,target,waitingTime,heading,tilt,roll) if numel(target)>1 if numel(heading)==1 heading = repmat(heading,numel(target),1); end if numel(tilt)==1 tilt = repmat(tilt,numel(target),1); end if numel(roll)==1 roll = repmat(roll,numel(target),1); end for i = 1:numel(target) this.updateOrientation(target(i),waitingTime,heading(i),tilt(i),roll(i)); end return end assert(isfield(target,'orientation_id'),'Invalid target for orientation update') kml = this.kml; [heading,tilt,roll] = kml.checkUnit(heading,tilt,roll); animUpdate = kml.xml.createElement('gx:AnimatedUpdate'); update = kml.xml.createElement('Update'); change = kml.xml.createElement('Change'); orientation = kml.xml.createElement('Orientation'); animUpdate.appendChild(kml.textNode('gx:duration',sprintf('%0.16g',waitingTime))); orientation.setAttribute('targetId',target.orientation_id); orientation.appendChild(kml.textNode('heading', sprintf('%0.16g',heading))); orientation.appendChild(kml.textNode('tilt', sprintf('%0.16g',tilt))); orientation.appendChild(kml.textNode('roll', sprintf('%0.16g',roll))); change.appendChild(orientation); update.appendChild(change); animUpdate.appendChild(update); this.playlist.appendChild(animUpdate); end function updateScale(this,target,waitingTime,scaleX,scaleY,scaleZ) if numel(target)>1 if numel(scaleX)==1 scaleX = repmat(scaleX,numel(target),1); end if numel(scaleY)==1 scaleY = repmat(scaleY,numel(target),1); end if numel(scaleZ)==1 scaleZ = repmat(scaleZ,numel(target),1); end for i = 1:numel(target) this.updateScale(target(i),waitingTime,scaleX(i),scaleY(i),scaleZ(i)); end return end assert(isfield(target,'scale_id'),'Invalid target for scale update') kml = this.kml; animUpdate = kml.xml.createElement('gx:AnimatedUpdate'); update = kml.xml.createElement('Update'); change = kml.xml.createElement('Change'); scale = kml.xml.createElement('Scale'); animUpdate.appendChild(kml.textNode('gx:duration',sprintf('%0.16g',waitingTime))); scale.setAttribute('targetId',target.scale_id); scale.appendChild(kml.textNode('x', sprintf('%0.16g',scaleX))); scale.appendChild(kml.textNode('y', sprintf('%0.16g',scaleY))); scale.appendChild(kml.textNode('z', sprintf('%0.16g',scaleZ))); change.appendChild(scale); update.appendChild(change); animUpdate.appendChild(update); this.playlist.appendChild(animUpdate); end function updateVisibility(this,target,visibility) if numel(target)>1 if numel(visibility)==1 visibility = repmat(visibility,numel(target),1); end for i = 1:numel(target) this.updateVisibility(target(i),visibility(i)); end return end assert(isfield(target,'id'),'Invalid target for visibility update'); assert(isfield(target,'type'),'Invalid target for visibility update'); kml = this.kml; animUpdate = kml.xml.createElement('gx:AnimatedUpdate'); update = kml.xml.createElement('Update'); change = kml.xml.createElement('Change'); item = kml.xml.createElement(target.type); % animUpdate.appendChild(kml.textNode('gx:duration',sprintf('%0.16g',waitingTime))); item.setAttribute('targetId',target.id); item.appendChild(kml.textNode('visibility', num2str(visibility))); change.appendChild(item); update.appendChild(change); animUpdate.appendChild(update); this.playlist.appendChild(animUpdate); end function updateText(this,target,text) if numel(target)>1 if numel(text)==1 text = repmat({text},numel(target),1); end for i = 1:numel(target) this.updateText(target(i),text(i)); end return end assert(isfield(target,'id'),'Invalid target for visibility update'); assert(isfield(target,'type'),'Invalid target for visibility update'); kml = this.kml; animUpdate = kml.xml.createElement('gx:AnimatedUpdate'); update = kml.xml.createElement('Update'); change = kml.xml.createElement('Change'); item = kml.xml.createElement(target.type); % animUpdate.appendChild(kml.textNode('gx:duration',sprintf('%0.16g',waitingTime))); item.setAttribute('targetId',target.id); item.appendChild(kml.textNode('name', text)); change.appendChild(item); update.appendChild(change); animUpdate.appendChild(update); this.playlist.appendChild(animUpdate); end function updateCoordinates(this,target,waitingTime,longitude,latitude,altitude) kml = this.kml; [longitude,latitude] = kml.checkUnit(longitude,latitude); if numel(target)>1 if numel(longitude)==1 longitude = repmat(longitude,numel(target),1); latitude = repmat(latitude,numel(target),1); altitude = repmat(altitude,numel(target),1); end end assert(isfield(target,'id'),'Invalid target for coordinates update'); assert(isfield(target,'coordinates_type'),'Invalid target for coordinates update'); assert(isfield(target,'coordinates_id'),'Invalid target for coordinates update'); for i = 1:numel(target) if numel(target)==1 && numel(latitude)>1 coordinates = sprintf('%0.16g,%0.16g,%0.16g ',[longitude(:) latitude(:) altitude(:)].'); else coordinates = sprintf('%0.16g,%0.16g,%0.16g ',[longitude(i) latitude(i) altitude(i)].'); end animUpdate = kml.xml.createElement('gx:AnimatedUpdate'); update = kml.xml.createElement('Update'); change = kml.xml.createElement('Change'); item = kml.xml.createElement(target(i).coordinates_type); animUpdate.appendChild(kml.textNode('gx:duration',sprintf('%0.16g',waitingTime))); item.setAttribute('targetId',target(i).coordinates_id); item.appendChild(kml.textNode('coordinates', coordinates)); change.appendChild(item); update.appendChild(change); animUpdate.appendChild(update); this.playlist.appendChild(animUpdate); end end function flyToCamera(this,waitingTime,longitude,latitude,altitude,heading,tilt,roll,altitudeMode) if nargin<9 altitudeMode = 'relativeToGround'; else assert(ismember(altitudeMode,{'clampToGround','relativeToGround','absolute'})); end kml = this.kml; [longitude,latitude,heading,tilt,roll] = kml.checkUnit(longitude,latitude,heading,tilt,roll); flyTo = kml.xml.createElement('gx:FlyTo'); flyTo.appendChild(kml.textNode('gx:duration',sprintf('%0.16g',waitingTime))); flyTo.appendChild(kml.textNode('gx:flyToMode','smooth')); camera = kml.xml.createElement('Camera'); camera.appendChild(kml.textNode('longitude',sprintf('%0.16g',longitude))); camera.appendChild(kml.textNode('latitude',sprintf('%0.16g',latitude))); camera.appendChild(kml.textNode('altitude',sprintf('%0.16g',altitude))); h = heading-180; if heading < -360 heading = 720+heading; elseif h>360 heading = heading-720; end camera.appendChild(kml.textNode('heading',sprintf('%0.16g',heading))); camera.appendChild(kml.textNode('tilt',sprintf('%0.16g',tilt))); camera.appendChild(kml.textNode('roll',sprintf('%0.16g',roll))); camera.appendChild(kml.textNode('altitudeMode',altitudeMode)); flyTo.appendChild(camera); this.playlist.appendChild(flyTo); end function flyToLookAt(this,waitingTime, longitude,latitude,altitude,altitudeMode, heading, tilt) if nargin<6 altitudeMode = 'relativeToGround'; else assert(ismember(altitudeMode,{'clampToGround','relativeToGround','absolute'})); end if nargin < 7 heading = 0; end if nargin < 8 tilt = 0; end kml = this.kml; [longitude,latitude,heading,tilt] = kml.checkUnit(longitude,latitude,heading,tilt); flyTo = kml.xml.createElement('gx:FlyTo'); flyTo.appendChild(kml.textNode('gx:duration',sprintf('%0.16g',waitingTime))); flyTo.appendChild(kml.textNode('gx:flyToMode','smooth')); lookAt = kml.xml.createElement('LookAt'); lookAt.appendChild(kml.textNode('longitude',sprintf('%0.16g',longitude))); lookAt.appendChild(kml.textNode('latitude',sprintf('%0.16g',latitude))); lookAt.appendChild(kml.textNode('altitude',sprintf('%0.16g',altitude))); lookAt.appendChild(kml.textNode('altitudeMode',altitudeMode)); lookAt.appendChild(kml.textNode('heading',sprintf('%0.16g',heading))); lookAt.appendChild(kml.textNode('tilt',sprintf('%0.16g',tilt))); flyTo.appendChild(lookAt); this.playlist.appendChild(flyTo); end function wait(this,waitingTime) wait = this.kml.xml.createElement('gx:Wait'); wait.appendChild(this.kml.textNode('gx:duration',sprintf('%0.16g',waitingTime))); this.playlist.appendChild(wait); end function pause(this) pause = this.kml.xml.createElement('gx:TourControl'); pause.appendChild(this.kml.textNode('gx:playMode','pause')); this.playlist.appendChild(pause); end end end