-
jacques.grelet_ird.fr authoredjacques.grelet_ird.fr authored
kml.m 11.58 KiB
classdef kml < handle
%KML(name) Create a KML toolbox object, that allows you to plot from MATLAB to Google Earth
% This class-based toolbox allows you to create many different plots in Google Earth, by automatically creating the required xml-based kml files without user interaction.
%
% With it, you can create:
% - line plots, scatter plots
% - 2D and 3D contours
% - 2D and 3D polygons
% - quiver plots
% - write text in a given point
% - place 3D models
% - overlay images
% - transfer more complex figures as images
% - folders, subfolders,... to aggregate similar plots
%
% For some usage examples, check the code at .\test\RunTests.m
%
% If you enjoy it, just drop me an email at kml@rafael.aero saying for what you're using it :).
%
% Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)
% $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $
properties %(Access = private, Transient)
xml
doc
parent = []
filename = ''
name = ''
unit = 'deg'
zip = true
includeFiles;
end
properties (Access = private)
target = 'earth'
end
methods
function this = kml(name,parent)
if nargin <1
name = 'Unnamed KML';
end
this.name = name;
if nargin <2
parent = [];
else
if ~isa(parent,'kml')
error('Invalid parent, pass only a kml object or a kml folder')
end
end
this.parent = parent;
if isempty(parent)
this.xml = com.mathworks.xml.XMLUtils.createDocument('kml');
kmlNode = this.xml.getDocumentElement;
kmlNode.setAttribute('xmlns','http://www.opengis.net/kml/2.2');
kmlNode.setAttribute('xmlns:gx','http://www.google.com/kml/ext/2.2');
kmlNode.setAttribute('xmlns:kml','http://www.opengis.net/kml/2.2');
kmlNode.setAttribute('xmlns:atom','http://www.w3.org/2005/Atom');
this.doc = this.xml.createElement('Document');
this.doc.appendChild(this.textNode('name',name));
kmlNode.appendChild(this.doc);
else
this.doc = parent.xml.createElement('Folder');
this.xml = parent.xml;
this.doc.appendChild(this.textNode('name',name));
this.doc.appendChild(this.textNode('id', name));
parent.doc.appendChild(this.doc);
end
end
function clear(this)
if isempty(this.parent)
%not a folder, just create a new kml class and reuse it's xml nodes
a = kml(this.name);
this.doc = a.doc;
this.xml = a.xml;
this.includeFiles = '';
a.delete;
else
this.parent.doc.removeChild(this.doc);
a = kml(this.name,this.parent);
this.doc = a.doc;
this.xml = a.xml;
a.delete;
end
end
function addIncludeFile(this,varargin)
K = this;
while ~isempty(K.parent)
K = K.parent;
end
newFiles = varargin;
for i = 1:numel(newFiles)
K.includeFiles{end+1} = newFiles{i};
end
end
function save(this,filename, compact)
if ~isempty(this.parent)
warning('KML:incompletefile','You are saving only a folder of the KML file, not the full KML, this will not load on any viewer');
end
if nargin < 2
if isempty(this.filename)
if strcmpi(this.name,'Unnamed KML')
[tmpvar,filename] = fileparts(tempname(cd));
filename = [filename '.kml'];
warning('KML:tempfile','Please delete file %s later, if not required...',filename);
else
filename = this.name;
end
else
filename = this.filename;
end
end
if nargin < 3
compact = this.zip;
else
this.zip = compact;
end
[p,fn,ext] = fileparts(filename);
filename = fullfile(p,[fn '.kml']);
xmlwrite(filename,this.xml);
if this.zip
[p,fn,ext] = fileparts(filename);
kmzFilename = fullfile(p,[fn '.kmz']);
zip(kmzFilename,vertcat({filename},this.includeFiles(:)).');
delete(filename);
movefile([kmzFilename '.zip'],kmzFilename,'f');
this.filename = kmzFilename;
else
this.filename = filename;
end
end
function viewKML(this)
tmpfile = [tempname '.kml'];
xmlwrite(tmpfile ,this.xml);
edit(tmpfile);
delete(tmpfile);
end
function run(this)
this.save;
switch true
case ispc
system(['start "kmltoolbox" "' this.filename '"']);
case ismac
system(['open' ' "' this.filename '"']);
otherwise
disp('The KML file has been saved, open it in Google Earth');
end
end
function useRadians(this)
this.unit = 'rad';
end
function useDegrees(this)
this.unit = 'deg';
end
function setTarget(this,target)
target = lower(target);
assert(ismember(target,{'earth','moon','sky','mars'}),'Target must be one of the following: ''earth'' ''moon'' ''mars'' or ''sky''')
this.target = target;
kmlNode = this.xml.getDocumentElement;
if ~strcmpi(this.target,'earth')
kmlNode.setAttribute('hint',['target=' this.target]);
end
end
function varargout = checkUnit(this,varargin)
varargout = varargin;
parent = this;
while ~isempty(parent.parent)
parent = parent.parent;
end
if strcmpi(parent.unit,'deg')
%do nothing
elseif strcmpi(parent.unit,'rad')
for i = 1:numel(varargin)
varargout{i} = varargin{i}.* (180/pi);
end
else
error('invalid angular unit %s', parent.unit);
end
end
function disp(this)
display(this);
end
function display(this)
if getpref('kmltoolbox','ShowDisclaimer',true)
disp(sprintf('\n'));
disp(' _ ____ __ _ _____ _ _ ')
disp(' | |/ / \/ | | |_ _|__ ___| | |__ _____ __')
disp(' | '' <| |\/| | |__ | |/ _ \/ _ \ | ''_ \/ _ \ \ /')
disp(' |_|\_\_| |_|____| |_|\___/\___/_|_.__/\___/_\_\')
disp(sprintf('\n'));
disp('Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)')
disp(sprintf('\n'));
disp('If you enjoy it, just drop me an email at kml@rafael.aero saying for what you''re using it :-)')
disp(sprintf('\n'));
disp('To install the toolbox, and suppress this message, run kml.install')
end
end
end
methods %(Access = private)
function node = textNode(this,Name,Text)
node = this.xml.createElement(Name);
node.appendChild(this.xml.createTextNode(Text));
end
end
methods (Static)
iconURL = parseIconURL(iconURL)
im = captureScreen(view)
function colorHex = color2kmlHex(color)
if numel(color) ==3
color(4) = 1;
end
color = min(max(floor(color*255),0),255);
[r,g,b,a] = deal(color(1),color(2),color(3),color(4));
[rhex, ghex, bhex, ahex ]= deal(dec2hex(r),dec2hex(g),dec2hex(b),dec2hex(a));
if length(rhex)==1,rhex=['0' rhex];end
if length(ghex)==1,ghex=['0' ghex];end
if length(bhex)==1,bhex=['0' bhex];end
if length(ahex)==1,ahex=['0' ahex];end
colorHex = [ahex bhex ghex rhex];
end
function ID = getTempID(rootID)
[tmp,tmpID] = fileparts(tempname);
ID = [rootID tmpID];
end
function dist = ll2dist(lon1, lat1,lon2, lat2)
%Input in radians - Calculate distance using Haversine formula
R = 6378137;
dLat = (lat2-lat1);
dLon = (lon2-lon1);
a = sqr(sin(dLat/2)) + cos(lat1) .* cos(lat2) .* sqr(sin(dLon/2));
c = 2 * atan(sqrt(a)./sqrt(1-a));
dist = R * c;
end
function install()
clc
nl = sprintf('\n');
disp(nl);
disp(' _ ____ __ _ _____ _ _ ')
disp(' | |/ / \/ | | |_ _|__ ___| | |__ _____ __')
disp(' | '' <| |\/| | |__ | |/ _ \/ _ \ | ''_ \/ _ \ \ /')
disp(' |_|\_\_| |_|____| |_|\___/\___/_|_.__/\___/_\_\')
disp(nl);
disp('This will add the KML toolbox to your MATLAB path, at the current location');
disp('If you prefer to have it located somewhere else, first copy the whole folder');
disp('to the place you want, and then run kml.install from there!');
disp(nl);
p = fileparts(fileparts(mfilename('fullpath')));
disp(sprintf('Toolbox Path: %s',p));
disp(nl);
s = input('Continue [Y]/N? ','s');
if strcmpi(s,'n')
disp('Instalation aborted!')
return
end
disp(nl);
disp('Adding toolbox folder to the MATLAB path...')
disp(nl);
disp('(In some systems, this might require administrative rights, sorry for that)')
disp(nl);
addpath(p);
addpath(fullfile(p,'html'));
r = savepath;
if r == 1
disp('Error saving your path. Please add the toolbox folder manually to your MATLAB path')
end
disp('Installing the toolbox help...')
warning('off','MATLAB:doc:DocNotInstalled')
builddocsearchdb(fullfile(p,'html'))
warning('on','MATLAB:doc:DocNotInstalled')
setpref('kmltoolbox','ShowDisclaimer',false);
clc
disp(nl);
disp(' _ ____ __ _ _____ _ _ ')
disp(' | |/ / \/ | | |_ _|__ ___| | |__ _____ __')
disp(' | '' <| |\/| | |__ | |/ _ \/ _ \ | ''_ \/ _ \ \ /')
disp(' |_|\_\_| |_|____| |_|\___/\___/_|_.__/\___/_\_\')
disp(nl);
disp(nl);
disp(' Toolbox installed successfully!')
disp(nl);
disp('To take a look in the toolbox contents, run: >> kmldoc');
disp('To get help for the toolbox functions, run: >> kmldoc kml.FunctionName');
disp(nl);
end
end
end