├── .gitattributes ├── .gitignore ├── @kml ├── arrow3d.dae ├── camera.m ├── captureScreen.m ├── colorbar.m ├── contour.m ├── contour3.m ├── contourf.m ├── createFolder.m ├── kml.m ├── model.m ├── modelTour.m ├── newAnimation.m ├── newFolder.m ├── overlay.m ├── parseIconURL.m ├── plot.m ├── plot3.m ├── point.m ├── poly.m ├── poly3.m ├── polyMap.m ├── quadoverlay.m ├── quiver.m ├── quiver3d.m ├── scatter.m ├── scatter3.m ├── screenoverlay.m ├── surf.m ├── text.m └── transfer.m ├── @kmlAnimation └── kmlAnimation.m ├── README.m ├── html ├── help_clear.jpg ├── help_clear_01.jpg ├── help_clear_02.jpg ├── help_contour.jpg ├── help_contour3.jpg ├── help_contour3_01.jpg ├── help_contour_01.jpg ├── help_kml.jpg ├── help_kml_01.jpg ├── help_model.jpg ├── help_modelTour.jpg ├── help_modelTour_01.jpg ├── help_model_01.jpg ├── help_overlay.jpg ├── help_overlay_01.jpg ├── help_plot.jpg ├── help_plot3.jpg ├── help_plot3_01.jpg ├── help_plot_01.jpg ├── help_point.jpg ├── help_point_01.jpg ├── help_poly.jpg ├── help_poly3.jpg ├── help_poly3_01.jpg ├── help_poly_01.jpg ├── help_quiver.jpg ├── help_quiver3d.jpg ├── help_quiver3d_01.jpg ├── help_quiver_01.jpg ├── help_run.jpg ├── help_run_01.jpg ├── help_scatter.jpg ├── help_scatter3.jpg ├── help_scatter3_01.jpg ├── help_scatter_01.jpg ├── help_text.jpg ├── help_text_01.jpg ├── help_transfer.jpg ├── help_transfer_01.jpg ├── help_transfer_02.jpg ├── help_transfer_03.jpg ├── help_useDegrees.jpg ├── help_useDegrees_01.jpg ├── help_useRadians.jpg ├── help_useRadians_01.jpg ├── helpsearch │ ├── _t.cfs │ ├── deletable │ └── segments ├── helptoc.xml ├── info.xml ├── kml.clear.html ├── kml.contents.html ├── kml.contour.html ├── kml.contour3.html ├── kml.createFolder.html ├── kml.html ├── kml.icons.html ├── kml.model.html ├── kml.modelTour.html ├── kml.overlay.html ├── kml.plot.html ├── kml.plot3.html ├── kml.point.html ├── kml.poly.html ├── kml.poly3.html ├── kml.quiver.html ├── kml.quiver3d.html ├── kml.run.html ├── kml.save.html ├── kml.scatter.html ├── kml.scatter3.html ├── kml.text.html ├── kml.transfer.html ├── kml.useDegrees.html ├── kml.useRadians.html ├── kml.viewKML.html ├── kmldoc.m ├── kmltoolbox.png ├── logo.png └── nestedFolders.png ├── license.txt └── test ├── RunTestTour.m ├── RunTests.m ├── RunTestsRadians.m ├── bitslice.m ├── cities.mat ├── logoFEx2.png └── testAnim.m /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # ========================= 18 | # Operating System Files 19 | # ========================= 20 | 21 | # OSX 22 | # ========================= 23 | 24 | .DS_Store 25 | .AppleDouble 26 | .LSOverride 27 | 28 | # Icon must ends with two \r. 29 | Icon 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear on external disk 35 | .Spotlight-V100 36 | .Trashes 37 | -------------------------------------------------------------------------------- /@kml/camera.m: -------------------------------------------------------------------------------- 1 | function target = camera(this,long,lat,alt,heading,tilt,roll,varargin) 2 | %KML.camera(long,lat,alt) Write a Camera position KML with lat, long, alt, 3 | % heading, tilt, roll 4 | % 5 | % Based on work by Rafael Fernandes de Oliveira (rafael@rafael.aero) 6 | % Original Work: Copyright 2012 Rafael Fernandes de Oliveira 7 | % Author: Thomas Fell (t.r.fell@liv.ac.uk) 8 | % Version: 1.0 $ $Date: 2013/04/18 20:00:00 $ 9 | 10 | target = struct('type','','id',''); 11 | 12 | [long,lat,heading,tilt,roll] = this.checkUnit(long,lat,heading,tilt,roll); 13 | 14 | p = inputParser; 15 | 16 | nlat = numel(lat); 17 | 18 | p.addRequired('lat',@(a)isnumeric(a) && isvector(a) &&~isempty(a)); 19 | p.addRequired('long',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 20 | p.addRequired('alt',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 21 | p.addRequired('heading',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 22 | p.addRequired('tilt',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 23 | p.addRequired('roll',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 24 | 25 | p.addParamValue('id',kml.getTempID('kml_camera'),@ischar); 26 | p.addParamValue('name','kml_camera',@ischar); 27 | p.addParamValue('altitudeMode','absolute',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 28 | 29 | p.addParamValue('timeStamp','',@ischar); 30 | p.addParamValue('timeSpanBegin','',@ischar); 31 | p.addParamValue('timeSpanEnd','',@ischar); 32 | 33 | p.parse(lat,long,alt,heading,tilt,roll,varargin{:}); 34 | 35 | arg = p.Results; 36 | 37 | 38 | placemark = this.xml.createElement('Placemark'); 39 | camera = this.xml.createElement('Camera'); 40 | 41 | placemark.setAttribute('id',arg.id); 42 | placemark.appendChild(this.textNode('name',arg.name)); 43 | 44 | if ~isempty(arg.timeStamp) 45 | timeStamp = this.xml.createElement('TimeStamp'); 46 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 47 | placemark.appendChild(timeStamp); 48 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 49 | timeSpan = this.xml.createElement('TimeSpan'); 50 | if ~isempty(arg.timeSpanBegin) 51 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 52 | end 53 | 54 | if ~isempty(arg.timeSpanEnd) 55 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 56 | end 57 | placemark.appendChild(timeSpan); 58 | end 59 | 60 | camera.appendChild(this.textNode('latitude',num2str(arg.lat))); 61 | camera.appendChild(this.textNode('longitude',num2str(arg.long))); 62 | camera.appendChild(this.textNode('altitude',num2str(arg.alt))); 63 | camera.appendChild(this.textNode('heading',num2str(arg.heading))); 64 | camera.appendChild(this.textNode('tilt',num2str(arg.tilt))); 65 | camera.appendChild(this.textNode('roll',num2str(arg.roll))); 66 | camera.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 67 | 68 | placemark.appendChild(camera); 69 | this.doc.appendChild(placemark); 70 | 71 | target.type = 'Placemark'; 72 | target.id = arg.id; 73 | end -------------------------------------------------------------------------------- /@kml/captureScreen.m: -------------------------------------------------------------------------------- 1 | function IM = captureScreen (view) 2 | %KML.CAPTURESCREEN(view) Capture a screenshot, and return an cell with the image of each monitor. 3 | % 4 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 5 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 6 | 7 | if nargin ==0 8 | view = false; 9 | end 10 | ge = java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment(); 11 | gd = ge.getScreenDevices; 12 | 13 | robot = java.awt.Robot; 14 | 15 | for i = 1:numel(gd) 16 | bounds = gd(i).getDefaultConfiguration.getBounds; 17 | 18 | width = bounds.getWidth(); 19 | height = bounds.getHeight(); 20 | left = bounds.getX; 21 | top = bounds.getY; 22 | 23 | im = zeros(height,width,3,'uint8'); 24 | bimg = robot.createScreenCapture(java.awt.Rectangle(left, top, width, height)); 25 | RGBA = bimg.getRGB(0,0,width,height,[],0,width); 26 | RGBA = typecast(RGBA, 'uint8'); 27 | 28 | im(:,:,1) = reshape(RGBA(3:4:end),width,height).'; 29 | im(:,:,2) = reshape(RGBA(2:4:end),width,height).'; 30 | im(:,:,3) = reshape(RGBA(1:4:end),width,height).'; 31 | 32 | IM{i} = im; 33 | end 34 | 35 | if view 36 | figure; 37 | N = numel(IM); 38 | for i = 1:N 39 | subplot(N,1,i); 40 | image(IM{i}); 41 | axis equal tight 42 | end 43 | end 44 | end -------------------------------------------------------------------------------- /@kml/colorbar.m: -------------------------------------------------------------------------------- 1 | function target = colorbar(this,cAxis,colorMap,varargin) 2 | ss = get(0,'ScreenSize')*.8; 3 | 4 | p = inputParser; 5 | 6 | p.addRequired('cAxis', @isnumeric); 7 | p.addRequired('colorMap', @isnumeric); 8 | 9 | p.addParamValue('type','vertical',@(a)ismember(lower(a),{'vertical','horizontal'})); 10 | p.addParamValue('tick',[],@isnumeric); 11 | p.addParamValue('tickLabel',{},@iscell); 12 | 13 | 14 | 15 | p.addParamValue('id','kml_colorbar',@ischar); 16 | p.addParamValue('name','kml_colorbar',@ischar); 17 | p.addParamValue('description','',@ischar); 18 | p.addParamValue('visibility',true,@islogical); 19 | p.addParamValue('rotation',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 20 | p.addParamValue('drawOrder',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 21 | 22 | p.addParamValue('timeStamp','',@ischar); 23 | p.addParamValue('timeSpanBegin','',@ischar); 24 | p.addParamValue('timeSpanEnd','',@ischar); 25 | 26 | 27 | p.parse(cAxis,colorMap,varargin{:}); 28 | 29 | arg = p.Results; 30 | 31 | if numel(cAxis) > 2 32 | cAxis = [min(cAxis) max(cAxis)]; 33 | end 34 | 35 | l = linspace(cAxis(1),cAxis(2),1000); 36 | fh = figure; 37 | 38 | 39 | if strcmpi(arg.type,'vertical') 40 | ratio = 40; 41 | 42 | pcolor([0*l.' 1+0*l.'],[l.' l.'],[l.' l.']) 43 | 44 | set(gcf,'Position',[0 0 ss(4)./ratio ss(4)]);%[ss(1)+ss(4)./ratio ss(2) ss(4)./ratio ss(4)]); 45 | set(gca,'XTick',[]); 46 | if ~isempty(arg.tick) 47 | set(gca,'YTick',arg.tick); 48 | end 49 | if ~isempty(arg.tickLabel) 50 | set(gca,'YTickLabel',arg.tickLabel); 51 | end 52 | sz = [2/ratio 1]; 53 | overlayPos = [2 1]; 54 | screenPos = [1 1]; 55 | else 56 | ratio = 40; 57 | pcolor([l.' l.'],[0*l.' 1+0*l.'],[l.' l.']) 58 | set(gcf,'Position',[0 0 ss(3) ss(3)./ratio ]);%[ss(1) ss(2)+ss(3)./ratio ss(3) ss(3)./ratio ]); 59 | set(gca,'YTick',[]); 60 | if ~isempty(arg.tick) 61 | set(gca,'XTick',arg.tick); 62 | end 63 | if ~isempty(arg.tickLabel) 64 | set(gca,'XTickLabel',arg.tickLabel); 65 | end 66 | sz = [1 2/ratio]; 67 | overlayPos = [1 (ratio-4)/2]; 68 | screenPos = [1 1]; 69 | end 70 | 71 | movegui(fh,'north'); 72 | 73 | shading flat; 74 | caxis(cAxis); 75 | colormap(colorMap); 76 | 77 | 78 | 79 | name = 'Colorbar'; 80 | basename = 'Colorbar'; 81 | 82 | name = [name '.png']; 83 | k = 1; 84 | while ~isempty(dir(name)) 85 | name = sprintf('%s (%i)%s',basename,k,'.png'); 86 | k = k+1; 87 | end 88 | 89 | bgColor = [0 0 0]; 90 | fgColor = [1 1 1]; 91 | 92 | set(gca,'Color',bgColor,'XColor',fgColor,'YColor',fgColor); 93 | set(fh,'Color',bgColor); 94 | set(gca,'FontWeight','bold','FontSize',15) 95 | % grid on 96 | % set(gca,'GridLineStyle','-') 97 | 98 | % figure(fh) 99 | % drawnow 100 | % pause(1) %drawing on windows starts with a transparent window, better give some time for it to show, so we don't capture the background 101 | % drawnow 102 | % drawnow('expose'); 103 | % im = getframe(fh); 104 | % drawnow('expose'); 105 | % im = im.cdata; 106 | 107 | set(fh,'PaperPositionMode','auto','InvertHardcopy','off') 108 | print('-dpng','-r0',name,fh) 109 | im = imread(name); 110 | 111 | axc = ceil(bgColor*255); 112 | alphaMap = uint8(~(im(:,:,1)==axc(1) & im(:,:,2)==axc(2) & im(:,:,3)==axc(3))*255); 113 | 114 | imwrite(im,name,'Alpha',alphaMap); 115 | close(fh); 116 | drawnow 117 | 118 | 119 | % 120 | % Simple crosshairs 121 | % This screen overlay uses fractional positioning 122 | % to put the image in the exact center of the screen 123 | % 124 | % http://myserver/myimage.jpg 125 | % 126 | % 127 | % 128 | % 39.37878630116985 129 | % 130 | % 131 | 132 | 133 | overlay = this.xml.createElement('ScreenOverlay'); 134 | overlayXY = this.xml.createElement('overlayXY'); 135 | screenXY = this.xml.createElement('screenXY'); 136 | size = this.xml.createElement('size'); 137 | icon = this.xml.createElement('Icon'); 138 | 139 | overlay.setAttribute('id',arg.id); 140 | overlay.appendChild(this.textNode('name',arg.name)); 141 | overlay.appendChild(this.textNode('open','1')); 142 | overlay.appendChild(this.textNode('visibility',num2str(arg.visibility))); 143 | overlay.appendChild(this.textNode('description',arg.description)); 144 | overlay.appendChild(this.textNode('drawOrder',num2str(arg.drawOrder))); 145 | 146 | if ~isempty(arg.timeStamp) 147 | timeStamp = this.xml.createElement('TimeStamp'); 148 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 149 | overlay.appendChild(timeStamp); 150 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 151 | timeSpan = this.xml.createElement('TimeSpan'); 152 | if ~isempty(arg.timeSpanBegin) 153 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 154 | end 155 | 156 | if ~isempty(arg.timeSpanEnd) 157 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 158 | end 159 | overlay.appendChild(timeSpan); 160 | end 161 | 162 | overlayXY.setAttribute('x',num2str(overlayPos(1),16)) 163 | overlayXY.setAttribute('y',num2str(overlayPos(2),16)) 164 | overlayXY.setAttribute('xunits','fraction') 165 | overlayXY.setAttribute('yunits','fraction') 166 | 167 | screenXY.setAttribute('x',num2str(screenPos(1),16)) 168 | screenXY.setAttribute('y',num2str(screenPos(2),16)) 169 | screenXY.setAttribute('xunits','fraction') 170 | screenXY.setAttribute('yunits','fraction') 171 | 172 | size.setAttribute('x',num2str(sz(1),16)) 173 | size.setAttribute('y',num2str(sz(2),16)) 174 | size.setAttribute('xunits','fraction') 175 | size.setAttribute('yunits','fraction') 176 | overlay.appendChild(this.textNode('rotation', num2str(arg.rotation))); 177 | 178 | icon.appendChild(this.textNode('href',name)); 179 | 180 | overlay.appendChild(overlayXY); 181 | overlay.appendChild(screenXY); 182 | overlay.appendChild(size); 183 | overlay.appendChild(icon); 184 | 185 | this.doc.appendChild(overlay); 186 | 187 | target.id = arg.id; 188 | target.type = 'ScreenOverlay'; 189 | 190 | this.addIncludeFile(name); 191 | end -------------------------------------------------------------------------------- /@kml/contour.m: -------------------------------------------------------------------------------- 1 | function target = contour(this,long,lat,alt,varargin) 2 | %KML.CONTOUR(long,lat,alt) Create a contour of alt in a grid defined by long and lat. 3 | % Similar to built-in contour function 4 | % 5 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 6 | % $Revision: 1.4 $ $Date: 2012/02/08 16:00:00 $ 7 | 8 | target = struct('type','','id','','coordinates_type','','coordinates_id',''); 9 | 10 | p = inputParser; 11 | 12 | nlat = numel(lat); 13 | 14 | p.addRequired('lat', @(a)isnumeric(a) && ~isempty(a)); 15 | p.addRequired('long', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 16 | p.addRequired('alt', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 17 | 18 | p.addParamValue('name','kml_contour',@ischar); 19 | p.addParamValue('id',kml.getTempID('kml_contour'),@ischar); 20 | p.addParamValue('description','',@ischar); 21 | p.addParamValue('visibility',true,@islogical); 22 | p.addParamValue('colorMap','jet',@ischar); 23 | p.addParamValue('numberOfLevels','auto',@(a)(ischar(a) && strcmpi(a,'auto')) ||(isnumeric(a))); 24 | p.addParamValue('altitude',1,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 25 | p.addParamValue('altitudeMode','clampToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 26 | p.addParamValue('showText',false,@islogical) 27 | 28 | p.addParamValue('noFolder',false,@islogical) 29 | 30 | p.addParamValue('levelStep',1,@isnumeric) 31 | p.addParamValue('labelSpacing',inf,@isnumeric) 32 | p.addParamValue('timeStamp','',@ischar); 33 | p.addParamValue('timeSpanBegin','',@ischar); 34 | p.addParamValue('timeSpanEnd','',@ischar); 35 | p.addParamValue('lineWidth',1,@isnumeric); 36 | 37 | p.parse(lat,long,alt,varargin{:}); 38 | 39 | arg = p.Results; 40 | 41 | if arg.noFolder 42 | f = this; 43 | else 44 | f = this.createFolder(arg.name); 45 | end 46 | 47 | if isnumeric(arg.numberOfLevels) 48 | c = contours(lat,long,alt,arg.numberOfLevels); 49 | else 50 | c = contours(lat,long,alt); 51 | end 52 | 53 | minAlt = min(min(alt)); 54 | maxalt = max(max(alt)); 55 | 56 | 57 | i = 1; k=1; 58 | while true 59 | l = c(1,i); 60 | n = c(2,i); 61 | C(k).lat = c(1,(i+1):(i+n)); 62 | C(k).long = c(2,(i+1):(i+n)); 63 | C(k).l = l; 64 | i = i + n + 1; 65 | k = k + 1; 66 | if i > size(c,2) 67 | break; 68 | end 69 | end 70 | 71 | levels = unique([C(:).l]); 72 | shownLevels = levels(1:arg.levelStep:numel(levels)); 73 | 74 | ncolors = 100; 75 | cmap = feval(arg.colorMap,ncolors); 76 | levelsCMAP = linspace(min(levels),max(levels),ncolors); 77 | middleLevel = levels(ceil(numel(levels)/2)); 78 | 79 | for i = 1:numel(C) 80 | clev = C(i).l; 81 | iC = find(levels==clev); 82 | if clev <= middleLevel 83 | clev = clev - 1; 84 | end 85 | if numel(levels) > 1 86 | iC = round(interp1(levelsCMAP,linspace(0,ncolors-1,numel(levelsCMAP)),clev,'linear',0)); 87 | else 88 | iC = 1; 89 | end 90 | color = cmap(iC+1 ,:); 91 | 92 | colorHex = kml.color2kmlHex(color); 93 | 94 | 95 | target(i) = f.plot(C(i).long,C(i).lat, 'lineColor', colorHex, ... 96 | 'lineWidth',arg.lineWidth,... 97 | 'altitudeMode',arg.altitudeMode, ... 98 | 'altitude',arg.altitude,... 99 | 'visibility',arg.visibility, ... 100 | 'name',sprintf('Level %g',C(i).l), ... 101 | 'timeStamp', arg.timeStamp , ... 102 | 'timeSpanBegin', arg.timeSpanBegin , ... 103 | 'timeSpanEnd', arg.timeSpanEnd, ... 104 | 'id',[arg.id '_' num2str(i)] ... 105 | ); 106 | 107 | if arg.showText && ismember(C(i).l,shownLevels) 108 | N = numel(C(i).lat); 109 | if ~isfinite(arg.labelSpacing) 110 | R = randi(N,1); 111 | latTxt = interp1(1:N,C(i).lat,R); 112 | longTxt = interp1(1:N,C(i).long,R); 113 | f.text(longTxt,latTxt,0,sprintf('%g',C(i).l)); 114 | else 115 | dist = kml.ll2dist(C(i).long(1:end-1),C(i).lat(1:end-1), ... 116 | C(i).long(2:end),C(i).lat(2:end)); 117 | dist = [0 cumsum(dist)]; 118 | for d = 1:arg.labelSpacing:dist(end); 119 | latTxt = interp1(dist,C(i).lat,d); 120 | longTxt = interp1(dist,C(i).long,d); 121 | f.text(longTxt,latTxt,0,sprintf('%g',C(i).l)); 122 | end 123 | end 124 | end 125 | end 126 | end -------------------------------------------------------------------------------- /@kml/contour3.m: -------------------------------------------------------------------------------- 1 | function target = contour3(this,long,lat,alt,varargin) 2 | %KML.CONTOUR(long,lat,alt) Create a 3D contour of alt in a grid defined by long and lat. 3 | % The altitude of each line is given by its associated contour level 4 | % Similar to built-in contour3 function 5 | % 6 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 7 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 8 | 9 | target = struct('type','','id','','coordinates_type','','coordinates_id',''); 10 | 11 | p = inputParser; 12 | 13 | nlat = numel(lat); 14 | 15 | p.addRequired('lat', @(a)isnumeric(a) && ~isempty(a)); 16 | p.addRequired('long', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 17 | p.addRequired('alt', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 18 | 19 | p.addParamValue('name','kml_contour3',@ischar); 20 | p.addParamValue('id',kml.getTempID('kml_contour3'),@ischar); 21 | p.addParamValue('description','',@ischar); 22 | p.addParamValue('visibility',true,@islogical); 23 | p.addParamValue('extrude',false,@islogical); 24 | p.addParamValue('colorMap','jet',@ischar); 25 | p.addParamValue('numberOfLevels','auto',@(a)(ischar(a) && strcmpi(a,'auto')) ||(isnumeric(a))); 26 | p.addParamValue('altitudeMode','relativeToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 27 | 28 | p.addParamValue('noFolder',false,@islogical) 29 | 30 | p.addParamValue('showText',false,@islogical) 31 | p.addParamValue('levelStep',1,@isnumeric) 32 | p.addParamValue('labelSpacing',inf,@isnumeric) 33 | 34 | p.addParamValue('timeStamp','',@ischar); 35 | p.addParamValue('timeSpanBegin','',@ischar); 36 | p.addParamValue('timeSpanEnd','',@ischar); 37 | 38 | p.addParamValue('lineWidth',1,@isnumeric); 39 | 40 | p.parse(lat,long,alt,varargin{:}); 41 | 42 | arg = p.Results; 43 | 44 | if arg.noFolder 45 | f = this; 46 | else 47 | f = this.createFolder(arg.name); 48 | end 49 | 50 | if isnumeric(arg.numberOfLevels) 51 | c = contours(lat,long,alt,arg.numberOfLevels); 52 | else 53 | c = contours(lat,long,alt); 54 | end 55 | 56 | minAlt = min(min(alt)); 57 | maxAlt = max(max(alt)); 58 | 59 | i = 1; k=1; 60 | while true 61 | l = c(1,i); 62 | n = c(2,i); 63 | C(k).lat = c(1,(i+1):(i+n)); 64 | C(k).long = c(2,(i+1):(i+n)); 65 | C(k).l = l; 66 | i = i + n + 1; 67 | k = k + 1; 68 | if i > size(c,2) 69 | break; 70 | end 71 | end 72 | 73 | levels = unique([C(:).l]); 74 | shownLevels = levels(1:arg.levelStep:numel(levels)); 75 | 76 | ncolors = 100; 77 | cmap = feval(arg.colorMap,ncolors); 78 | levelsCMAP = linspace(min(levels),max(levels),ncolors); 79 | middleLevel = levels(ceil(numel(levels)/2)); 80 | 81 | for i = 1:numel(C) 82 | 83 | clev = C(i).l; 84 | iC = find(levels==clev); 85 | if clev <= middleLevel 86 | clev = clev - 1; 87 | end 88 | 89 | if numel(levels) > 1 90 | iC = round(interp1(levelsCMAP,linspace(0,ncolors-1,numel(levelsCMAP)),clev,'linear',0)); 91 | else 92 | iC = 1; 93 | end 94 | 95 | color = cmap(iC+1 ,:); 96 | 97 | colorHex = kml.color2kmlHex(color); 98 | 99 | polyColor = colorHex; 100 | 101 | if arg.extrude 102 | polyColor(1:2) = 'FF'; 103 | colorHex(1:2) = '00'; 104 | target(end+1) = f.poly(C(i).long,C(i).lat, 'lineColor', colorHex, ... 105 | 'altitudeMode',arg.altitudeMode, ... 106 | 'altitude',C(i).l,... 107 | 'visibility',arg.visibility, ... 108 | 'name',sprintf('Level %g',C(i).l), ... 109 | 'timeStamp', arg.timeStamp , ... 110 | 'timeSpanBegin', arg.timeSpanBegin , ... 111 | 'timeSpanEnd', arg.timeSpanEnd, ... 112 | 'extrude',arg.extrude, ... 113 | 'polyColor',polyColor, ... 114 | 'id',[arg.id '_poly_' num2str(i)] ... 115 | ); 116 | else 117 | polyColor(1:2) = '00'; 118 | 119 | target(end+1) = f.plot(C(i).long,C(i).lat, 'lineColor', colorHex, ... 120 | 'lineWidth',arg.lineWidth,... 121 | 'altitudeMode',arg.altitudeMode, ... 122 | 'altitude',C(i).l,... 123 | 'visibility',arg.visibility, ... 124 | 'name',sprintf('Level %g',C(i).l), ... 125 | 'timeStamp', arg.timeStamp , ... 126 | 'timeSpanBegin', arg.timeSpanBegin , ... 127 | 'timeSpanEnd', arg.timeSpanEnd, ... 128 | 'extrude',arg.extrude, ... 129 | 'polyColor',polyColor, ... 130 | 'id',[arg.id '_plot_' num2str(i)] ... 131 | ); 132 | end 133 | 134 | if arg.showText && ismember(C(i).l,shownLevels) 135 | N = numel(C(i).lat); 136 | altTxt = C(i).l; 137 | if ~isfinite(arg.labelSpacing) 138 | R = randi(N,1); 139 | latTxt = interp1(1:N,C(i).lat,R); 140 | longTxt = interp1(1:N,C(i).long,R); 141 | 142 | target(end+1) = f.text(longTxt,latTxt,altTxt,sprintf('%g',C(i).l), 'id',[arg.id '_text_' num2str(i)]); 143 | else 144 | dist = kml.ll2dist(C(i).long(1:end-1),C(i).lat(1:end-1), ... 145 | C(i).long(2:end),C(i).lat(2:end)); 146 | dist = [0 cumsum(dist)]; 147 | for d = 1:arg.labelSpacing:dist(end); 148 | latTxt = interp1(dist,C(i).lat,d); 149 | longTxt = interp1(dist,C(i).long,d); 150 | target(end+1) = f.text(longTxt,latTxt,altTxt,sprintf('%g',C(i).l), 'id',[arg.id '_text_' num2str(i) '_' num2str(d)]); 151 | end 152 | end 153 | end 154 | 155 | end 156 | target(1) = []; %remove the empty initial field 157 | end -------------------------------------------------------------------------------- /@kml/contourf.m: -------------------------------------------------------------------------------- 1 | function target = contourf(this,long,lat,alt,varargin) 2 | %KML.CONTOURF(long,lat,alt) Create a filled contour of alt in a grid defined by long and lat. 3 | % Similar to built-in contour function 4 | % 5 | % 17.05.2013 - Added suggestion by Keith Epstein to allow changing line width and color 6 | % 7 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 8 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 9 | 10 | 11 | target = struct('type','','id',''); 12 | 13 | p = inputParser; 14 | 15 | nlat = numel(lat); 16 | 17 | p.addRequired('lat', @(a)isnumeric(a) && ~isempty(a)); 18 | p.addRequired('long', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 19 | p.addRequired('alt', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 20 | 21 | p.addParamValue('name','kml_contourf',@ischar); 22 | p.addParamValue('id',kml.getTempID('kml_contourf'),@ischar); 23 | p.addParamValue('description','',@ischar); 24 | p.addParamValue('visibility',true,@islogical); 25 | p.addParamValue('transparency',1,@isnumeric); 26 | p.addParamValue('lineWidth',1,@isnumeric); 27 | p.addParamValue('lineColor','',@(x)ischar(x)||isempty(x)); 28 | 29 | p.addParamValue('colorMap','jet',@ischar); 30 | p.addParamValue('numberOfLevels','auto',@(a)(ischar(a) && strcmpi(a,'auto')) ||(isnumeric(a))); 31 | 32 | p.addParamValue('noFolder',false,@islogical) 33 | 34 | p.addParamValue('showText',false,@islogical) 35 | p.addParamValue('levelStep',1,@isnumeric) 36 | p.addParamValue('labelSpacing',inf,@isnumeric) 37 | 38 | p.addParamValue('timeStamp','',@ischar); 39 | p.addParamValue('timeSpanBegin','',@ischar); 40 | p.addParamValue('timeSpanEnd','',@ischar); 41 | 42 | p.parse(lat,long,alt,varargin{:}); 43 | 44 | arg = p.Results; 45 | 46 | if arg.noFolder 47 | f = this; 48 | else 49 | f = this.createFolder(arg.name); 50 | end 51 | 52 | minAlt = min(alt(:)); 53 | maxAlt = max(alt(:)); 54 | 55 | if isnumeric(arg.numberOfLevels) 56 | c = contours(long,lat,alt,arg.numberOfLevels); 57 | else 58 | dAlt = maxAlt-minAlt; 59 | dAlt10 = 10^(floor(log10(dAlt))); 60 | nsteps = dAlt/dAlt10; 61 | if nsteps < 1.2 62 | dAlt10 = dAlt10/10; 63 | elseif nsteps < 2.4 64 | dAlt10 = dAlt10/5; 65 | elseif nsteps < 6 66 | dAlt10 = dAlt10/2; 67 | end 68 | 69 | if minAlt < 0 && maxAlt > 0 70 | neg = -dAlt10:-dAlt10:minAlt; 71 | pos = 0:dAlt10:maxAlt; 72 | levels = [fliplr(neg) pos]; 73 | elseif minAlt < 0 74 | minLevel = minAlt - (dAlt10 - mod(-minAlt,dAlt10)); 75 | levels = minLevel+dAlt10:dAlt10:maxAlt; 76 | else 77 | minLevel = minAlt + (dAlt10 - mod(minAlt,dAlt10)); 78 | levels = minLevel:dAlt10:maxAlt; 79 | end 80 | levels = [minAlt levels]; 81 | c = contours(long,lat,alt,levels); 82 | end 83 | 84 | 85 | 86 | % To avoid contours with open end, it is necessary to redo the contour 87 | % calculation using an extended matrix, with very low borders. 88 | 89 | levels = []; 90 | i = 1; k=1; 91 | while true 92 | l = c(1,i); 93 | n = c(2,i); 94 | levels = [levels; l]; 95 | i = i + n + 1; 96 | k = k + 1; 97 | if i > size(c,2) 98 | break; 99 | end 100 | end 101 | 102 | levels = unique(levels); 103 | 104 | [m,n] = size(alt); 105 | 106 | alt = [NaN(1, n+2); NaN(m,1) alt NaN(m,1); NaN(1, n+2)]; 107 | lat = [2.*lat(1,[1 1:end end]) - lat(2,[1 1:end end]); ... 108 | (2.*lat(:,1)-lat(:,2)), lat, (2.*lat(:,end)-lat(:,end-1)); ... 109 | 2.*lat(end,[1 1:end end]) - lat(end-1,[1 1:end end])]; 110 | 111 | long = long.'; 112 | long = [2.*long(1,[1 1:end end]) - long(2,[1 1:end end]); ... 113 | (2.*long(:,1)-long(:,2)), long, (2.*long(:,end)-long(:,end-1)); ... 114 | 2.*long(end,[1 1:end end]) - long(end-1,[1 1:end end])]; 115 | 116 | long = long.'; 117 | 118 | 119 | 120 | alt(isnan(alt)) = minAlt - 1e4.*(maxAlt - minAlt); 121 | 122 | c = contours(long,lat,alt,levels); 123 | 124 | i = 1; k=1; 125 | while true 126 | l = c(1,i); 127 | n = c(2,i); 128 | C(k).long = c(1,(i+1):(i+n)); 129 | C(k).lat = c(2,(i+1):(i+n)); 130 | C(k).l = l; 131 | if n<2 132 | C(k).area = 0; 133 | else 134 | C(k).area = sum(diff(C(k).lat) .* (C(k).long(1 : n - 1) + C(k).long(2 : n)) / 2); 135 | end 136 | 137 | 138 | i = i + n + 1; 139 | k = k + 1; 140 | if i > size(c,2) 141 | break; 142 | end 143 | end 144 | 145 | 146 | levels = unique([C(:).l]); 147 | minLevel = min(levels); 148 | shownLevels = levels(1:arg.levelStep:numel(levels)); 149 | areas = -unique(-abs([C(:).area])); 150 | [~,ixMA] = max(abs([C(:).area])); 151 | maxArea = C(ixMA).area; 152 | 153 | ncolors = 100; 154 | cmap = feval(arg.colorMap,ncolors); 155 | levelsCMAP = linspace(min(levels),max(levels),ncolors); 156 | middleLevel = levels(ceil(numel(levels)/2)); 157 | 158 | 159 | % Don't fill contours below the minimum level 160 | showMinLevel=any(levels <= minAlt); 161 | 162 | for a = areas; 163 | for i = 1:numel(C) 164 | if abs(C(i).area) == a 165 | clev = C(i).l; 166 | %iC = find(levels==clev); 167 | % if clev <= middleLevel 168 | % clev = clev - 1; 169 | % end 170 | 171 | if (sign(C(i).area) ~=sign(maxArea)), 172 | kk=find(levels==clev); 173 | kk0 = 1 + sum(levels<=minAlt) * (~showMinLevel); 174 | if (kk > kk0) 175 | clev=levels(kk-1); % in valley, use color for lower level 176 | elseif (kk == kk0) 177 | break; 178 | else 179 | break; 180 | end 181 | end 182 | 183 | if numel(levels) > 1 184 | iC = floor(interp1(levelsCMAP,linspace(0,ncolors-1,numel(levelsCMAP)),clev,'linear',0)); 185 | else 186 | iC = 1; 187 | end 188 | 189 | color = cmap(iC+1 ,:); 190 | 191 | colorHex = kml.color2kmlHex([color arg.transparency]); 192 | 193 | % debug: to view while plotting 194 | % fig(12345) 195 | % hold on 196 | % patch(C(i).long,C(i).lat,color) 197 | 198 | 199 | if arg.lineWidth > 0 200 | lineColor = '00000000'; 201 | else 202 | if isempty(arg.lineColor) 203 | lineColor = ['FF' colorHex(3:end)]; 204 | else 205 | lineColor = 'FF000000'; 206 | end 207 | end 208 | 209 | target(end+1) = f.poly3(C(i).long,C(i).lat,zeros(size(C(i).lat)), 'polyColor', colorHex, ... 210 | 'lineColor',lineColor,... 211 | 'lineWidth',arg.lineWidth, ... 212 | 'altitudeMode','clampToGround', ... 213 | 'visibility',arg.visibility, ... 214 | 'name',sprintf('Level %g',C(i).l), ... 215 | 'timeStamp', arg.timeStamp , ... 216 | 'timeSpanBegin', arg.timeSpanBegin , ... 217 | 'timeSpanEnd', arg.timeSpanEnd, ... 218 | 'id',[arg.id '_poly_' num2str(i)] ... 219 | ); 220 | if arg.showText && ismember(C(i).l,shownLevels) 221 | N = numel(C(i).lat); 222 | if ~isfinite(arg.labelSpacing) 223 | R = randi(N,1); 224 | latTxt = interp1(1:N,C(i).lat,R); 225 | longTxt = interp1(1:N,C(i).long,R); 226 | target(end+1) = f.text(longTxt,latTxt,0,sprintf('%g',C(i).l), 'id',[arg.id '_text_' num2str(i)]); 227 | else 228 | dist = kml.ll2dist(C(i).long(1:end-1),C(i).lat(1:end-1), ... 229 | C(i).long(2:end),C(i).lat(2:end)); 230 | dist = [0 cumsum(dist)]; 231 | for d = 1:arg.labelSpacing:dist(end); 232 | latTxt = interp1(dist,C(i).lat,d); 233 | longTxt = interp1(dist,C(i).long,d); 234 | target(end+1) = f.text(longTxt,latTxt,0,sprintf('%g',C(i).l), 'id',[arg.id '_text_' num2str(i) '_' num2str(d)]); 235 | end 236 | end 237 | end 238 | end 239 | end 240 | end 241 | target(1) = []; %remove the empty initial field 242 | end -------------------------------------------------------------------------------- /@kml/createFolder.m: -------------------------------------------------------------------------------- 1 | function f = createFolder(this,foldername) 2 | % DEPRECATED, renamed as newFolder 3 | f = this.newFolder(foldername); 4 | end -------------------------------------------------------------------------------- /@kml/model.m: -------------------------------------------------------------------------------- 1 | function target = model(this,long,lat,alt,heading,tilt,roll,varargin) 2 | %KML.MODEL(long,lat,alt,heading,tilt,roll) Places the 3D model (specified by the pair 3 | % attribute 'model','modelfile.dae') in the position and orientation given by long, 4 | % lat, alt, heading, tilt and roll. If the inputs represent a vector of points, the 5 | % model is repeated in each of them. 6 | % 7 | % Many model files can be found in the Google 3D Warehouse website. 8 | % 9 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 10 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 11 | 12 | target = struct('type','','id',''); 13 | 14 | [long,lat,heading,tilt,roll] = this.checkUnit(long,lat,heading,tilt,roll); 15 | 16 | p = inputParser; 17 | 18 | nlat = numel(lat); 19 | 20 | p.addRequired('lat',@(a)isnumeric(a) && isvector(a) &&~isempty(a)); 21 | p.addRequired('long',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 22 | p.addRequired('alt',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 23 | p.addRequired('heading',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 24 | p.addRequired('tilt',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 25 | p.addRequired('roll',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 26 | 27 | p.addParamValue('id',kml.getTempID('kml_model'),@ischar); 28 | p.addParamValue('name','kml_model',@ischar); 29 | p.addParamValue('description','',@ischar); 30 | p.addParamValue('visibility',true,@islogical); 31 | p.addParamValue('model','',@ischar); 32 | p.addParamValue('scaleX',1,@(a)isnumeric(a) && (numel(a)==nlat || numel(a)==1)); 33 | p.addParamValue('scaleY',1,@(a)isnumeric(a) && (numel(a)==nlat || numel(a)==1)); 34 | p.addParamValue('scaleZ',1,@(a)isnumeric(a) && (numel(a)==nlat || numel(a)==1)); 35 | p.addParamValue('scale',1, @(a)isnumeric(a) && (numel(a)==nlat || numel(a)==1)); 36 | p.addParamValue('altitudeMode','relativeToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 37 | 38 | p.addParamValue('timeStamp','',@ischar); 39 | p.addParamValue('timeSpanBegin','',@ischar); 40 | p.addParamValue('timeSpanEnd','',@ischar); 41 | 42 | p.parse(lat,long,alt,heading,tilt,roll,varargin{:}); 43 | 44 | arg = p.Results; 45 | 46 | 47 | if isempty(arg.model) 48 | error('Missing model parameter') 49 | end 50 | 51 | arg.scaleX = arg.scaleX .*arg.scale; 52 | arg.scaleY = arg.scaleY .*arg.scale; 53 | arg.scaleZ = arg.scaleZ .*arg.scale; 54 | 55 | if numel(arg.scaleX)==1 && nlat>1 56 | arg.scaleX = repmat(arg.scaleX,size(lat)); 57 | end 58 | 59 | if numel(arg.scaleY)==1 && nlat>1 60 | arg.scaleY = repmat(arg.scaleY,size(lat)); 61 | end 62 | 63 | if numel(arg.scaleZ)==1 && nlat>1 64 | arg.scaleZ = repmat(arg.scaleZ,size(lat)); 65 | end 66 | 67 | 68 | for i = 1:nlat 69 | target(i).type = 'Placemark'; 70 | target(i).id = [arg.id '_' num2str(i)]; 71 | target(i).location_id = ['Location_' target(i).id ]; 72 | target(i).orientation_id = ['Orientation_' target(i).id ]; 73 | target(i).scale_id = ['Scale_' target(i).id ]; 74 | target(i).model_id = ['Model_' target(i).id ]; 75 | 76 | placemark = this.xml.createElement('Placemark'); 77 | model = this.xml.createElement('Model'); 78 | location = this.xml.createElement('Location'); 79 | orientation = this.xml.createElement('Orientation'); 80 | scale = this.xml.createElement('Scale'); 81 | link = this.xml.createElement('Link'); 82 | 83 | placemark.setAttribute('id',target(i).id); 84 | placemark.appendChild(this.textNode('name',arg.name)); 85 | placemark.appendChild(this.textNode('visibility',num2str(arg.visibility))); 86 | placemark.appendChild(this.textNode('description',arg.description)); 87 | 88 | if ~isempty(arg.timeStamp) 89 | timeStamp = this.xml.createElement('TimeStamp'); 90 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 91 | placemark.appendChild(timeStamp); 92 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 93 | timeSpan = this.xml.createElement('TimeSpan'); 94 | if ~isempty(arg.timeSpanBegin) 95 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 96 | end 97 | 98 | if ~isempty(arg.timeSpanEnd) 99 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 100 | end 101 | placemark.appendChild(timeSpan); 102 | end 103 | 104 | location.setAttribute('id',target(i).location_id); 105 | location.appendChild(this.textNode('latitude', num2str(lat(i),16))); 106 | location.appendChild(this.textNode('longitude', num2str(long(i),16))); 107 | location.appendChild(this.textNode('altitude', num2str(alt(i),16))); 108 | 109 | orientation.setAttribute('id',target(i).orientation_id); 110 | orientation.appendChild(this.textNode('heading', num2str(heading(i)))); 111 | orientation.appendChild(this.textNode('tilt', num2str(tilt(i)))); 112 | orientation.appendChild(this.textNode('roll', num2str(roll(i)))); 113 | 114 | scale.setAttribute('id',target(i).scale_id); 115 | scale.appendChild(this.textNode('x', num2str(arg.scaleX(i)))); 116 | scale.appendChild(this.textNode('y', num2str(arg.scaleY(i)))); 117 | scale.appendChild(this.textNode('z', num2str(arg.scaleZ(i)))); 118 | 119 | link.appendChild(this.textNode('href',arg.model)); 120 | 121 | model.setAttribute('id',target(i).model_id); 122 | model.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 123 | 124 | model.appendChild(location); 125 | model.appendChild(orientation); 126 | model.appendChild(scale); 127 | model.appendChild(link); 128 | 129 | placemark.appendChild(model); 130 | this.doc.appendChild(placemark); 131 | end 132 | this.addIncludeFile(arg.model); 133 | 134 | end -------------------------------------------------------------------------------- /@kml/modelTour.m: -------------------------------------------------------------------------------- 1 | function modelTour(this,time,long,lat,alt,heading,tilt,roll,varargin) 2 | %THIS FUNCTION IS DEPRECATED - USE KML.NEWANIATION INSTEAD 3 | %KML.MODELTOUR (long,lat,alt,heading,tilt,roll) Animates a 3D model (specified by the pair 4 | % attribute 'model','modelfile.dae') in the position and orientation given by long, 5 | % lat, alt, heading, tilt and roll. The time input controls how long the model takes 6 | % to fly from one coordinate to the next. 7 | % 8 | % Many model files can be found in the Google 3D Warehouse website. 9 | % 10 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 11 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 12 | 13 | [long,lat,heading,tilt,roll] = this.checkUnit(long,lat,heading,tilt,roll); 14 | 15 | p = inputParser; 16 | 17 | nlat = numel(lat); 18 | 19 | p.addRequired('time',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 20 | p.addRequired('lat',@(a)isnumeric(a) && isvector(a) &&~isempty(a)); 21 | p.addRequired('long',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 22 | p.addRequired('alt',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 23 | p.addRequired('heading',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 24 | p.addRequired('tilt',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 25 | p.addRequired('roll',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 26 | 27 | p.addParamValue('id','kml_modelTour',@ischar); 28 | p.addParamValue('name','kml_modelTour',@ischar); 29 | p.addParamValue('description','',@ischar); 30 | p.addParamValue('visibility',true,@islogical); 31 | p.addParamValue('model','',@ischar); 32 | p.addParamValue('scaleX',1,@(a)isnumeric(a) && (numel(a)==nlat || numel(a)==1)); 33 | p.addParamValue('scaleY',1,@(a)isnumeric(a) && (numel(a)==nlat || numel(a)==1)); 34 | p.addParamValue('scaleZ',1,@(a)isnumeric(a) && (numel(a)==nlat || numel(a)==1)); 35 | p.addParamValue('scale',1, @(a)isnumeric(a) && (numel(a)==nlat || numel(a)==1)); 36 | p.addParamValue('altitudeMode','relativeToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 37 | 38 | p.addParamValue('tourName','Play Me!',@ischar); 39 | p.addParamValue('cameraMode','above',@(a)ismember(a,{'behind','above','fixed'})); 40 | p.addParamValue('cameraDistance',1e3,@isnumeric); 41 | 42 | 43 | p.parse(time,lat,long,alt,heading,tilt,roll,varargin{:}); 44 | 45 | arg = p.Results; 46 | 47 | 48 | if isempty(arg.model) 49 | error('Missing model parameter') 50 | end 51 | 52 | arg.scaleX = arg.scaleX .*arg.scale; 53 | arg.scaleY = arg.scaleY .*arg.scale; 54 | arg.scaleZ = arg.scaleZ .*arg.scale; 55 | 56 | if numel(arg.scaleX)==1 && nlat>1 57 | arg.scaleX = repmat(arg.scaleX,size(lat)); 58 | end 59 | 60 | if numel(arg.scaleY)==1 && nlat>1 61 | arg.scaleY = repmat(arg.scaleY,size(lat)); 62 | end 63 | 64 | if numel(arg.scaleZ)==1 && nlat>1 65 | arg.scaleZ = repmat(arg.scaleZ,size(lat)); 66 | end 67 | 68 | 69 | locationID = [arg.id '_location']; 70 | orientationID = [arg.id '_orientation']; 71 | scaleID = [arg.id '_scale']; 72 | 73 | placemark = this.xml.createElement('Placemark'); 74 | model = this.xml.createElement('Model'); 75 | location = this.xml.createElement('Location'); 76 | orientation = this.xml.createElement('Orientation'); 77 | scale = this.xml.createElement('Scale'); 78 | link = this.xml.createElement('Link'); 79 | 80 | placemark.setAttribute('id',arg.id); 81 | placemark.appendChild(this.textNode('name',arg.name)); 82 | placemark.appendChild(this.textNode('visibility',num2str(arg.visibility))); 83 | placemark.appendChild(this.textNode('description',arg.description)); 84 | 85 | location.setAttribute('id',locationID); 86 | location.appendChild(this.textNode('latitude', num2str(lat(1),16))); 87 | location.appendChild(this.textNode('longitude', num2str(long(1),16))); 88 | location.appendChild(this.textNode('altitude', num2str(alt(1),16))); 89 | 90 | orientation.setAttribute('id',orientationID); 91 | orientation.appendChild(this.textNode('heading', num2str(heading(1)))); 92 | orientation.appendChild(this.textNode('tilt', num2str(tilt(1)))); 93 | orientation.appendChild(this.textNode('roll', num2str(roll(1)))); 94 | 95 | scale.setAttribute('id',scaleID); 96 | scale.appendChild(this.textNode('x', num2str(arg.scaleX(1)))); 97 | scale.appendChild(this.textNode('y', num2str(arg.scaleY(1)))); 98 | scale.appendChild(this.textNode('z', num2str(arg.scaleZ(1)))); 99 | 100 | link.appendChild(this.textNode('href',arg.model)); 101 | 102 | model.setAttribute('id',['Model_' arg.id]); 103 | model.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 104 | 105 | model.appendChild(location); 106 | model.appendChild(orientation); 107 | model.appendChild(scale); 108 | model.appendChild(link); 109 | 110 | placemark.appendChild(model); 111 | this.doc.appendChild(placemark); 112 | 113 | tour = this.xml.createElement('gx:Tour'); 114 | playlist = this.xml.createElement('gx:Playlist'); 115 | tour.appendChild(this.textNode('name',arg.tourName)); 116 | 117 | for i = 2:nlat-1 118 | 119 | dT = time(i)-time(i-1); 120 | 121 | % Update object position 122 | animUpdate = this.xml.createElement('gx:AnimatedUpdate'); 123 | update = this.xml.createElement('Update'); 124 | change = this.xml.createElement('Change'); 125 | location = this.xml.createElement('Location'); 126 | orientation = this.xml.createElement('Orientation'); 127 | scale = this.xml.createElement('Scale'); 128 | 129 | animUpdate.appendChild(this.textNode('gx:duration',num2str(dT))); 130 | 131 | location.setAttribute('targetId',locationID); 132 | location.appendChild(this.textNode('latitude', num2str(lat(i),16))); 133 | location.appendChild(this.textNode('longitude', num2str(long(i),16))); 134 | location.appendChild(this.textNode('altitude', num2str(alt(i),16))); 135 | 136 | orientation.setAttribute('targetId',orientationID); 137 | orientation.appendChild(this.textNode('heading', num2str(heading(i)))); 138 | orientation.appendChild(this.textNode('tilt', num2str(tilt(i)))); 139 | orientation.appendChild(this.textNode('roll', num2str(roll(i)))); 140 | 141 | scale.setAttribute('targetId',scaleID); 142 | scale.appendChild(this.textNode('x', num2str(arg.scaleX(i)))); 143 | scale.appendChild(this.textNode('y', num2str(arg.scaleY(i)))); 144 | scale.appendChild(this.textNode('z', num2str(arg.scaleZ(i)))); 145 | 146 | change.appendChild(location); 147 | change.appendChild(orientation); 148 | change.appendChild(scale); 149 | 150 | update.appendChild(this.textNode('targetHref','')); 151 | update.appendChild(change); 152 | animUpdate.appendChild(update); 153 | 154 | playlist.appendChild(animUpdate); 155 | 156 | % Update camera position 157 | switch arg.cameraMode 158 | case 'fixed' 159 | wait = this.xml.createElement('gx:Wait'); 160 | wait.appendChild(this.textNode('gx:duration',num2str(dT))); 161 | playlist.appendChild(wait); 162 | case 'behind' 163 | dS = [long(i+1) - long(i-1); lat(i+1) - lat(i-1);]; 164 | dS = arg.cameraDistance * dS./sqrt(sum(dS.^2))/1e6; 165 | 166 | flyTo = this.xml.createElement('gx:FlyTo'); 167 | flyTo.appendChild(this.textNode('gx:duration',num2str(dT))); 168 | flyTo.appendChild(this.textNode('gx:flyToMode','smooth')); 169 | camera = this.xml.createElement('Camera'); 170 | camera.appendChild(this.textNode('longitude',num2str(long(i)-dS(1),16))); 171 | camera.appendChild(this.textNode('latitude',num2str(lat(i)-dS(2),16))); 172 | camera.appendChild(this.textNode('altitude',num2str(alt(i),16))); 173 | h = heading(i)-180; 174 | 175 | if h < -360 176 | h = 720+h; 177 | elseif h>360 178 | h = h-720; 179 | end 180 | 181 | camera.appendChild(this.textNode('heading',num2str(h))); 182 | camera.appendChild(this.textNode('tilt',num2str(90))); 183 | camera.appendChild(this.textNode('roll',num2str(0))); 184 | camera.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 185 | 186 | flyTo.appendChild(camera); 187 | playlist.appendChild(flyTo); 188 | case 'above' 189 | 190 | flyTo = this.xml.createElement('gx:FlyTo'); 191 | flyTo.appendChild(this.textNode('gx:duration',num2str(dT))); 192 | flyTo.appendChild(this.textNode('gx:flyToMode','smooth')); 193 | lookAt = this.xml.createElement('LookAt'); 194 | lookAt.appendChild(this.textNode('longitude',num2str(long(i),16))); 195 | lookAt.appendChild(this.textNode('latitude',num2str(lat(i),16))); 196 | lookAt.appendChild(this.textNode('altitude',num2str(alt(i) + arg.cameraDistance,16))); 197 | lookAt.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 198 | 199 | flyTo.appendChild(lookAt); 200 | playlist.appendChild(flyTo); 201 | end 202 | end 203 | 204 | tour.appendChild(playlist); 205 | this.doc.appendChild(tour); 206 | 207 | this.addIncludeFile(arg.model); 208 | end -------------------------------------------------------------------------------- /@kml/newAnimation.m: -------------------------------------------------------------------------------- 1 | function f = newAnimation(this,animName) 2 | %KML.NEWANIMATION(folderName) Creates an animation storyboard inside an kml (or another folder). 3 | % Example of use: 4 | % 5 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 6 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 7 | 8 | if nargin < 2 9 | animName = 'Unnamed Animation'; 10 | end 11 | f = kmlAnimation(this,animName); 12 | end -------------------------------------------------------------------------------- /@kml/newFolder.m: -------------------------------------------------------------------------------- 1 | function f = newFolder(this,foldername) 2 | %KML.NEWFOLDER(folderName) Creates a folder inside an kml (or another folder). 3 | % The folder behaves exactly as a KML object. 4 | % Example of use: 5 | % k = kml; 6 | % f = kml.createFolder('My Folder'); 7 | % t = linspace(0,2*pi,1000); 8 | % f.plot(t,sin(t)); 9 | % k.run 10 | % 11 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 12 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 13 | 14 | if nargin < 2 15 | foldername = 'Unnamed Folder'; 16 | end 17 | f = kml(foldername,this); 18 | end -------------------------------------------------------------------------------- /@kml/overlay.m: -------------------------------------------------------------------------------- 1 | function target = overlay(this,west,east,south,north,varargin) 2 | %KML.OVERLAY(west, east, south, north) Places the image file (specified by the pair 3 | % attribute 'file','image.png') as a ground overlay in the kml file. The corners 4 | % of the image are given by inputs west, east, south and north. 5 | % To make the overlay transparent, change the alpha portion of the color parameter 6 | % to a different hex value - eg.: 50% transparent, use KML.OVERLAY(...,'color','80FFFFFF') 7 | % 8 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 9 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 10 | 11 | target = struct('type','','id',''); 12 | 13 | [west,east,south,north] = this.checkUnit(west,east,south,north); 14 | 15 | p = inputParser; 16 | 17 | p.addRequired('west', @(a)isnumeric(a) && ~isempty(a) && numel(a)==1); 18 | p.addRequired('east', @(a)isnumeric(a) && ~isempty(a) && numel(a)==1); 19 | p.addRequired('south',@(a)isnumeric(a) && ~isempty(a) && numel(a)==1); 20 | p.addRequired('north',@(a)isnumeric(a) && ~isempty(a) && numel(a)==1); 21 | 22 | p.addParamValue('id',kml.getTempID('kml_overlay'),@ischar); 23 | p.addParamValue('name','kml_overlay',@ischar); 24 | p.addParamValue('description','',@ischar); 25 | p.addParamValue('visibility',true,@islogical); 26 | p.addParamValue('file','',@ischar); 27 | p.addParamValue('viewBoundScale',1,@(a)isnumeric(a) && numel(a)==1); 28 | p.addParamValue('color','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 29 | p.addParamValue('altitude',1,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 30 | p.addParamValue('rotation',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 31 | p.addParamValue('drawOrder',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 32 | p.addParamValue('altitudeMode','clampToGround',@(a)ismember(a,{'clampToGround','absolute'})); 33 | 34 | p.addParamValue('timeStamp','',@ischar); 35 | p.addParamValue('timeSpanBegin','',@ischar); 36 | p.addParamValue('timeSpanEnd','',@ischar); 37 | 38 | p.parse(west,east,south,north,varargin{:}); 39 | 40 | arg = p.Results; 41 | 42 | if isempty(arg.file) 43 | error('Missing file parameter') 44 | end 45 | 46 | arg.rotation = this.checkUnit(arg.rotation); 47 | 48 | overlay = this.xml.createElement('GroundOverlay'); 49 | llbox = this.xml.createElement('LatLonBox'); 50 | icon = this.xml.createElement('Icon'); 51 | 52 | overlay.setAttribute('id',arg.id); 53 | overlay.appendChild(this.textNode('name',arg.name)); 54 | overlay.appendChild(this.textNode('color',arg.color)); 55 | overlay.appendChild(this.textNode('visibility',num2str(arg.visibility))); 56 | overlay.appendChild(this.textNode('description',arg.description)); 57 | overlay.appendChild(this.textNode('altitude',num2str(arg.altitude))); 58 | overlay.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 59 | overlay.appendChild(this.textNode('drawOrder',num2str(arg.drawOrder))); 60 | 61 | if ~isempty(arg.timeStamp) 62 | timeStamp = this.xml.createElement('TimeStamp'); 63 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 64 | overlay.appendChild(timeStamp); 65 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 66 | timeSpan = this.xml.createElement('TimeSpan'); 67 | if ~isempty(arg.timeSpanBegin) 68 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 69 | end 70 | 71 | if ~isempty(arg.timeSpanEnd) 72 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 73 | end 74 | overlay.appendChild(timeSpan); 75 | end 76 | 77 | llbox.appendChild(this.textNode('north', num2str(north,16))); 78 | llbox.appendChild(this.textNode('south', num2str(south,16))); 79 | llbox.appendChild(this.textNode('east', num2str(east,16))); 80 | llbox.appendChild(this.textNode('west', num2str(west,16))); 81 | llbox.appendChild(this.textNode('rotation', num2str(arg.rotation))); 82 | 83 | icon.appendChild(this.textNode('href',arg.file)); 84 | icon.appendChild(this.textNode('viewBoundScale',num2str(arg.viewBoundScale))); 85 | 86 | overlay.appendChild(llbox); 87 | overlay.appendChild(icon); 88 | this.doc.appendChild(overlay); 89 | 90 | target.id = arg.id; 91 | target.type = 'GroundOverlay'; 92 | this.addIncludeFile(arg.file); 93 | end -------------------------------------------------------------------------------- /@kml/plot.m: -------------------------------------------------------------------------------- 1 | function target = plot(this,long,lat,varargin) 2 | %KML.PLOT(long,lat) Create 2D plot of long vs. lat 3 | % Similar to built-in plot function 4 | % 5 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 6 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 7 | 8 | target = struct('type','','id',''); 9 | 10 | [long,lat] = this.checkUnit(long,lat); 11 | 12 | p = inputParser; 13 | nlat = numel(lat); 14 | p.addRequired('lat', @(a)isnumeric(a) && isvector(a) &&~isempty(lat)); 15 | p.addRequired('long',@(a)isnumeric(a) && isvector(a) &&~isempty(lat) && numel(a)==nlat); 16 | 17 | p.addParamValue('id',kml.getTempID('kml_plot'),@ischar); 18 | p.addParamValue('name','kml_plot',@ischar); 19 | p.addParamValue('description','',@ischar); 20 | p.addParamValue('visibility',true,@islogical); 21 | p.addParamValue('lineColor','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 22 | p.addParamValue('polyColor','00FFFFFF',@(a)ischar(a) && numel(a)==8); 23 | p.addParamValue('lineWidth',1,@(a)isnumeric(a) && numel(a)==1); 24 | p.addParamValue('altitude',1,@(a)isnumeric(a) && isvector(a) &&~isempty(a)); 25 | p.addParamValue('altitudeMode','clampToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 26 | p.addParamValue('extrude',false,@islogical); 27 | p.addParamValue('tessellate',true,@islogical); 28 | 29 | p.addParamValue('timeStamp','',@ischar); 30 | p.addParamValue('timeSpanBegin','',@ischar); 31 | p.addParamValue('timeSpanEnd','',@ischar); 32 | 33 | p.parse(lat,long,varargin{:}); 34 | 35 | arg = p.Results; 36 | 37 | if numel(arg.altitude)~=nlat 38 | alt = repmat(arg.altitude(1),size(lat)); 39 | else 40 | alt = arg.altitude; 41 | end 42 | 43 | %Create coordinate text structure 44 | 45 | % coordinates = mat2str([long(:) lat(:) alt(:)]); 46 | % coordinates = coordinates(2:end-1); 47 | % coordinates = strrep(coordinates,' ',','); 48 | % coordinates = strrep(coordinates,';',' '); 49 | coordinates = sprintf('%0.16g,%0.16g,%0.16g ',[long(:) lat(:) alt(:)].'); 50 | 51 | placemark = this.xml.createElement('Placemark'); 52 | linestring = this.xml.createElement('LineString'); 53 | style = this.xml.createElement('Style'); 54 | linestyle = this.xml.createElement('LineStyle'); 55 | polystyle = this.xml.createElement('PolyStyle'); 56 | 57 | placemark.setAttribute('id',arg.id); 58 | placemark.appendChild(this.textNode('name',arg.name)); 59 | placemark.appendChild(this.textNode('visibility',num2str(arg.visibility))); 60 | placemark.appendChild(this.textNode('description',arg.description)); 61 | 62 | if ~isempty(arg.timeStamp) 63 | timeStamp = this.xml.createElement('TimeStamp'); 64 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 65 | placemark.appendChild(timeStamp); 66 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 67 | timeSpan = this.xml.createElement('TimeSpan'); 68 | if ~isempty(arg.timeSpanBegin) 69 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 70 | end 71 | 72 | if ~isempty(arg.timeSpanEnd) 73 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 74 | end 75 | placemark.appendChild(timeSpan); 76 | end 77 | 78 | 79 | linestyle.appendChild(this.textNode('color',arg.lineColor)); 80 | linestyle.appendChild(this.textNode('width',num2str(arg.lineWidth))); 81 | 82 | polystyle.appendChild(this.textNode('color',arg.polyColor)); 83 | 84 | linestring.setAttribute('id',['LineString_' arg.id]); 85 | linestring.appendChild(this.textNode('extrude',num2str(arg.extrude))); 86 | linestring.appendChild(this.textNode('tesselate',num2str(arg.tessellate))); 87 | linestring.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 88 | linestring.appendChild(this.textNode('coordinates',coordinates)); 89 | 90 | style.appendChild(linestyle); 91 | style.appendChild(polystyle); 92 | placemark.appendChild(style); 93 | placemark.appendChild(linestring); 94 | this.doc.appendChild(placemark); 95 | 96 | target.id = arg.id; 97 | target.type = 'Placemark'; 98 | target.coordinates_type = 'LineString'; 99 | target.coordinates_id = ['LineString_' target.id ]; 100 | end -------------------------------------------------------------------------------- /@kml/plot3.m: -------------------------------------------------------------------------------- 1 | function target = plot3(this,long,lat,alt,varargin) 2 | %KML.PLOT3(long,lat,alt) Create 3D plot of long vs. lat vs. alt 3 | % Similar to built-in plot3 function 4 | % 5 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 6 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 7 | 8 | target = struct('type','','id',''); 9 | 10 | [long,lat] = this.checkUnit(long,lat); 11 | 12 | p = inputParser; 13 | 14 | nlat = numel(lat); 15 | p.addRequired('lat', @(a)isnumeric(a) && isvector(a) &&~isempty(a)); 16 | p.addRequired('long',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a) == nlat); 17 | p.addRequired('alt', @(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a) == nlat); 18 | 19 | p.addParamValue('id',kml.getTempID('kml_plot3'),@ischar); 20 | p.addParamValue('name','kml_plot3',@ischar); 21 | p.addParamValue('description','',@ischar); 22 | p.addParamValue('visibility',true,@islogical); 23 | p.addParamValue('lineColor','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 24 | p.addParamValue('polyColor','00FFFFFF',@(a)ischar(a) && numel(a)==8); 25 | p.addParamValue('lineWidth',1,@(a)isnumeric(a) && numel(a)==1); 26 | p.addParamValue('altitudeMode','relativeToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 27 | p.addParamValue('extrude',false,@islogical); 28 | p.addParamValue('tessellate',true,@islogical); 29 | 30 | p.addParamValue('timeStamp','',@ischar); 31 | p.addParamValue('timeSpanBegin','',@ischar); 32 | p.addParamValue('timeSpanEnd','',@ischar); 33 | 34 | p.parse(lat,long,alt,varargin{:}); 35 | 36 | arg = p.Results; 37 | 38 | if numel(lat)~=numel(long) || numel(lat)~=numel(alt) 39 | error('Invalid input size') 40 | end 41 | 42 | % coordinates = mat2str([long(:) lat(:) alt(:)]); 43 | % coordinates = coordinates(2:end-1); 44 | % coordinates = strrep(coordinates,' ',','); 45 | % coordinates = strrep(coordinates,';',' '); 46 | coordinates = sprintf('%0.16g,%0.16g,%0.16g ',[long(:) lat(:) alt(:)].'); 47 | 48 | placemark = this.xml.createElement('Placemark'); 49 | linestring = this.xml.createElement('LineString'); 50 | style = this.xml.createElement('Style'); 51 | linestyle = this.xml.createElement('LineStyle'); 52 | polystyle = this.xml.createElement('PolyStyle'); 53 | 54 | placemark.setAttribute('id',arg.id); 55 | placemark.appendChild(this.textNode('name',arg.name)); 56 | placemark.appendChild(this.textNode('visibility',num2str(arg.visibility))); 57 | placemark.appendChild(this.textNode('description',arg.description)); 58 | 59 | if ~isempty(arg.timeStamp) 60 | timeStamp = this.xml.createElement('TimeStamp'); 61 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 62 | placemark.appendChild(timeStamp); 63 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 64 | timeSpan = this.xml.createElement('TimeSpan'); 65 | if ~isempty(arg.timeSpanBegin) 66 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 67 | end 68 | 69 | if ~isempty(arg.timeSpanEnd) 70 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 71 | end 72 | placemark.appendChild(timeSpan); 73 | end 74 | 75 | 76 | linestyle.appendChild(this.textNode('color',arg.lineColor)); 77 | linestyle.appendChild(this.textNode('width',num2str(arg.lineWidth))); 78 | 79 | polystyle.appendChild(this.textNode('color',arg.polyColor)); 80 | 81 | linestring.setAttribute('id',['LineString_' arg.id]); 82 | linestring.appendChild(this.textNode('extrude',num2str(arg.extrude))); 83 | linestring.appendChild(this.textNode('tesselate',num2str(arg.tessellate))); 84 | linestring.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 85 | linestring.appendChild(this.textNode('coordinates',coordinates)); 86 | 87 | style.appendChild(linestyle); 88 | style.appendChild(polystyle); 89 | placemark.appendChild(style); 90 | placemark.appendChild(linestring); 91 | this.doc.appendChild(placemark); 92 | 93 | target.id = arg.id; 94 | target.type = 'Placemark'; 95 | target.coordinates_type = 'LineString'; 96 | target.coordinates_id = ['LineString_' target.id ]; 97 | end -------------------------------------------------------------------------------- /@kml/point.m: -------------------------------------------------------------------------------- 1 | function target = point(this,long,lat,alt,varargin) 2 | %KML.POINT(long,lat,alt) Places point markers in the positions given by long, lat and alt 3 | % Similar to built-in scatter function. For a list of available markers, run 4 | % help kml.parseIconURL 5 | % 6 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 7 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 8 | 9 | target = struct('type','','id',''); 10 | 11 | [long,lat] = this.checkUnit(long,lat); 12 | 13 | p = inputParser; 14 | 15 | nlat = numel(lat); 16 | 17 | p.addRequired('lat', @(a)isnumeric(a) && isvector(a) &&~isempty(a)); 18 | p.addRequired('long',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 19 | p.addRequired('alt', @(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 20 | 21 | p.addParamValue('id',kml.getTempID('kml_point'),@ischar); 22 | p.addParamValue('name','kml_point',@ischar); 23 | p.addParamValue('description','',@ischar); 24 | p.addParamValue('visibility',true,@islogical); 25 | p.addParamValue('iconColor','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 26 | p.addParamValue('iconURL','',@ischar); 27 | p.addParamValue('iconScale',1,@(a)isnumeric(a) && (numel(a)==1 || numel(a)==nlat)); 28 | p.addParamValue('labelScale',1,@(a)isnumeric(a) && numel(a)==1); 29 | p.addParamValue('labelColor','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 30 | p.addParamValue('altitudeMode','relativeToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 31 | 32 | p.addParamValue('timeStamp','',@ischar); 33 | p.addParamValue('timeSpanBegin','',@ischar); 34 | p.addParamValue('timeSpanEnd','',@ischar); 35 | 36 | p.parse(lat,long,alt,varargin{:}); 37 | 38 | arg = p.Results; 39 | 40 | if ~iscell(arg.name) 41 | arg.name = {arg.name}; 42 | end 43 | 44 | if nlat>1 && numel(arg.name)==1 45 | arg.name = repmat(arg.name,nlat,1); 46 | end 47 | 48 | if nlat>1 && numel(arg.visibility)==1 49 | arg.visibility = repmat(arg.visibility,nlat,1); 50 | end 51 | 52 | if nlat>1 && numel(arg.iconScale)==1 53 | arg.iconScale = repmat(arg.iconScale,nlat,1); 54 | end 55 | 56 | 57 | for i = 1:nlat 58 | target(i).type = 'Placemark'; 59 | target(i).coordinates_type = 'Point'; 60 | target(i).id = [arg.id '_' num2str(i)]; 61 | target(i).coordinates_id = ['Point_' target(i).id ]; 62 | % coordinates = mat2str([long(i) lat(i) alt(i)]); 63 | % coordinates = coordinates(2:end-1); 64 | % coordinates = strrep(coordinates,' ',','); 65 | % coordinates = strrep(coordinates,';',' '); 66 | coordinates = sprintf('%0.16g,%0.16g,%0.16g ',[long(i) lat(i) alt(i)].'); 67 | 68 | placemark = this.xml.createElement('Placemark'); 69 | point = this.xml.createElement('Point'); 70 | style = this.xml.createElement('Style'); 71 | iconstyle = this.xml.createElement('IconStyle'); 72 | labelstyle = this.xml.createElement('LabelStyle'); 73 | icon = this.xml.createElement('Icon'); 74 | 75 | placemark.setAttribute('id',target(i).id); 76 | placemark.appendChild(this.textNode('name',arg.name{i})); 77 | placemark.appendChild(this.textNode('visibility',num2str(arg.visibility(i)))); 78 | placemark.appendChild(this.textNode('description',arg.description)); 79 | 80 | if ~isempty(arg.timeStamp) 81 | timeStamp = this.xml.createElement('TimeStamp'); 82 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 83 | placemark.appendChild(timeStamp); 84 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 85 | timeSpan = this.xml.createElement('TimeSpan'); 86 | if ~isempty(arg.timeSpanBegin) 87 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 88 | end 89 | 90 | if ~isempty(arg.timeSpanEnd) 91 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 92 | end 93 | placemark.appendChild(timeSpan); 94 | end 95 | 96 | iconstyle.appendChild(this.textNode('color',arg.iconColor)); 97 | iconstyle.appendChild(this.textNode('scale',num2str(arg.iconScale(i)))); 98 | icon.appendChild(this.textNode('href',kml.parseIconURL(arg.iconURL))); 99 | 100 | labelstyle.appendChild(this.textNode('color',arg.labelColor)); 101 | labelstyle.appendChild(this.textNode('scale',num2str(arg.labelScale))); 102 | 103 | point.setAttribute('id',target(i).coordinates_id); 104 | point.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 105 | point.appendChild(this.textNode('coordinates',coordinates)); 106 | 107 | iconstyle.appendChild(icon); 108 | style.appendChild(iconstyle); 109 | style.appendChild(labelstyle); 110 | placemark.appendChild(style); 111 | placemark.appendChild(point); 112 | this.doc.appendChild(placemark); 113 | 114 | end 115 | end -------------------------------------------------------------------------------- /@kml/poly.m: -------------------------------------------------------------------------------- 1 | function target = poly(this,long,lat,varargin) 2 | %KML.POLY(long,lat) Draw a closed polygon with vertices given by long, lat. 3 | % To change the altitude of the polygon, use KML.POLY(...,'altitude', 10000) 4 | % 5 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 6 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 7 | 8 | p = inputParser; 9 | p.KeepUnmatched = true; 10 | p.addParamValue('altitude',1,@(a)isnumeric(a) && isvector(a) &&~isempty(a)); 11 | p.parse(varargin{:}); 12 | 13 | arg = p.Results; 14 | 15 | v = varargin; 16 | 17 | [tmpvar,hasAltitude ]= ismemberVarargin('altitude',v); 18 | 19 | if any(hasAltitude) 20 | v(hasAltitude+1) = []; 21 | v(hasAltitude) = []; 22 | end 23 | 24 | target = this.poly3(long,lat,ones(size(lat)).*arg.altitude,v{:}); 25 | end 26 | 27 | 28 | function [tf,loc] = ismemberVarargin(a,varin) 29 | if mod(numel(varin),2)==1 30 | error('Invalid number of named arguments.') 31 | end 32 | if ~iscell(a) 33 | a = {a}; 34 | end 35 | tf = false(size(a)); 36 | loc = zeros(size(a)); 37 | for i = 1:numel(a) 38 | for j = 1:2:numel(varin) 39 | if ischar(varin{j}) && strcmp(varin{j},a{i}) 40 | tf(i) = true; 41 | loc(i) = j; 42 | end 43 | end 44 | end 45 | end -------------------------------------------------------------------------------- /@kml/poly3.m: -------------------------------------------------------------------------------- 1 | function target = poly3(this,long,lat,alt,varargin) 2 | %KML.POLY3(long,lat,alt) Draw a polygonal 3D form, with vertices given by long, lat and alt. 3 | % 4 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 5 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 6 | 7 | target = struct('type','','id',''); 8 | 9 | [long,lat] = this.checkUnit(long,lat); 10 | 11 | p = inputParser; 12 | nlat = numel(lat); 13 | 14 | p.addRequired('lat', @(a)isnumeric(a) && isvector(a) &&~isempty(a)); 15 | p.addRequired('long',@(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 16 | p.addRequired('alt', @(a)isnumeric(a) && isvector(a) &&~isempty(a) && numel(a)==nlat); 17 | 18 | p.addParamValue('id',kml.getTempID('kml_poly3'),@ischar); 19 | p.addParamValue('name','kml_poly3',@ischar); 20 | p.addParamValue('description','',@ischar); 21 | p.addParamValue('visibility',true,@islogical); 22 | p.addParamValue('lineColor','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 23 | p.addParamValue('polyColor','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 24 | p.addParamValue('lineWidth',1,@(a)isnumeric(a) && numel(a)==1); 25 | p.addParamValue('altitudeMode','relativeToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 26 | p.addParamValue('extrude',false,@islogical); 27 | p.addParamValue('tessellate',true,@islogical); 28 | 29 | p.addParamValue('timeStamp','',@ischar); 30 | p.addParamValue('timeSpanBegin','',@ischar); 31 | p.addParamValue('timeSpanEnd','',@ischar); 32 | 33 | p.parse(lat,long,alt,varargin{:}); 34 | 35 | arg = p.Results; 36 | 37 | % coordinates = mat2str([long(:) lat(:) alt(:)]); 38 | % coordinates = coordinates(2:end-1); 39 | % coordinates = strrep(coordinates,' ',','); 40 | % coordinates = strrep(coordinates,';',' '); 41 | 42 | coordinates = sprintf('%0.16g,%0.16g,%0.16g ',[long(:) lat(:) alt(:)].'); 43 | 44 | placemark = this.xml.createElement('Placemark'); 45 | 46 | polygon = this.xml.createElement('Polygon'); 47 | outboundary = this.xml.createElement('outerBoundaryIs'); 48 | linearring = this.xml.createElement('LinearRing'); 49 | style = this.xml.createElement('Style'); 50 | linestyle = this.xml.createElement('LineStyle'); 51 | polystyle = this.xml.createElement('PolyStyle'); 52 | 53 | placemark.setAttribute('id',arg.id); 54 | placemark.appendChild(this.textNode('name',arg.name)); 55 | placemark.appendChild(this.textNode('visibility',num2str(arg.visibility))); 56 | placemark.appendChild(this.textNode('description',arg.description)); 57 | 58 | if ~isempty(arg.timeStamp) 59 | timeStamp = this.xml.createElement('TimeStamp'); 60 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 61 | placemark.appendChild(timeStamp); 62 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 63 | timeSpan = this.xml.createElement('TimeSpan'); 64 | if ~isempty(arg.timeSpanBegin) 65 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 66 | end 67 | 68 | if ~isempty(arg.timeSpanEnd) 69 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 70 | end 71 | placemark.appendChild(timeSpan); 72 | end 73 | 74 | linestyle.appendChild(this.textNode('color',arg.lineColor)); 75 | linestyle.appendChild(this.textNode('width',num2str(arg.lineWidth))); 76 | 77 | polystyle.appendChild(this.textNode('color',arg.polyColor)); 78 | 79 | linearring.setAttribute('id',['LinearRing_' arg.id]); 80 | linearring.appendChild(this.textNode('coordinates',coordinates)); 81 | 82 | polygon.setAttribute('id',['Polygon_' arg.id]); 83 | polygon.appendChild(this.textNode('extrude',num2str(arg.extrude))); 84 | polygon.appendChild(this.textNode('tesselate',num2str(arg.tessellate))); 85 | polygon.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 86 | 87 | 88 | outboundary.appendChild(linearring); 89 | polygon.appendChild(outboundary); 90 | 91 | style.appendChild(linestyle); 92 | style.appendChild(polystyle); 93 | placemark.appendChild(style); 94 | placemark.appendChild(polygon); 95 | this.doc.appendChild(placemark); 96 | 97 | target.type = 'Placemark'; 98 | target.id = arg.id; 99 | end -------------------------------------------------------------------------------- /@kml/polyMap.m: -------------------------------------------------------------------------------- 1 | function target = polyMap(this,long,lat,value,varargin) 2 | %KML.POLY3(long,lat,alt) Draw a polygonal 3D form, with vertices given by long, lat and alt. 3 | % 4 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 5 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 6 | 7 | target = struct('type','','id',''); 8 | 9 | lat = lat(:); 10 | long = long(:); 11 | value = value(:); 12 | 13 | p = inputParser; 14 | nlat = numel(lat); 15 | 16 | p.addRequired('lat', @(a)isnumeric(a) &&~isempty(a)); 17 | p.addRequired('long',@(a)isnumeric(a) &&~isempty(a) && numel(a)==nlat); 18 | p.addRequired('value', @(a)isnumeric(a) &&~isempty(a) && numel(a)==nlat); 19 | 20 | p.addParamValue('id',kml.getTempID('kml_polyMap'),@ischar); 21 | p.addParamValue('name','kml_polyMap',@ischar); 22 | p.addParamValue('description','',@ischar); 23 | p.addParamValue('visibility',true,@islogical); 24 | p.addParamValue('colorMap','jet',@ischar); 25 | p.addParamValue('scale',1e4,@(a)isnumeric(a) && numel(a)==1); 26 | p.addParamValue('width',1,@(a)isnumeric(a) && numel(a)==1); 27 | p.addParamValue('type','square',@(a)ismember(lower(a),{'square','circle'})); 28 | p.addParamValue('noFolder',false,@islogical) 29 | 30 | p.addParamValue('timeStamp','',@ischar); 31 | p.addParamValue('timeSpanBegin','',@ischar); 32 | p.addParamValue('timeSpanEnd','',@ischar); 33 | 34 | p.parse(lat,long,value,varargin{:}); 35 | 36 | arg = p.Results; 37 | 38 | fDR = this.checkUnit(1); 39 | 40 | lls = max(max(lat)-min(lat),max(long)-min(long)); 41 | width = 0.5*lls./sqrt(numel(value)); 42 | 43 | 44 | if arg.noFolder 45 | f = this; 46 | else 47 | f = this.createFolder(arg.name); 48 | end 49 | 50 | maxVal = max(value); 51 | minVal = min(value); 52 | 53 | if maxVal==minVal 54 | minVal = 0; 55 | end 56 | 57 | 58 | 59 | 60 | scale = arg.scale .* value; %-minVal)./(maxVal-minVal); 61 | 62 | ncolors = 100; 63 | cmap = feval(arg.colorMap,ncolors); 64 | vs = linspace(minVal,maxVal,ncolors); 65 | 66 | switch lower(arg.type) 67 | case 'square' 68 | pLong = 0.5*[-1 -1 1 1 -1].*arg.width.*width; 69 | pLat = 0.5*[-1 1 1 -1 -1].*arg.width.*width; 70 | case 'circle' 71 | t = linspace(0,2*pi,100); 72 | pLong = 0.5*sin(t).*arg.width.*width; 73 | pLat = 0.5*cos(t).*arg.width.*width; 74 | end 75 | 76 | maxValCount = 1e4; 77 | 78 | 79 | if numel(value) > maxValCount 80 | warning('kml:maxPoly','Ignoring any point under the top %i values',maxValCount); 81 | [tmp,indexToPlot] = sort(-value); 82 | indexToPlot = indexToPlot(1:maxValCount).'; 83 | else 84 | indexToPlot = 1:numel(value); 85 | end 86 | 87 | for i = indexToPlot 88 | if scale(i)>0 89 | color = [interp1(vs,cmap(:,1),value(i)) interp1(vs,cmap(:,2),value(i)) interp1(vs,cmap(:,3),value(i))]; 90 | colorHex = kml.color2kmlHex(color); 91 | target(end+1) = f.poly3(long(i) + pLong,lat(i) + pLat.*cosd(fDR*lat(i)),ones(size(pLong)).*scale(i), ... 92 | 'extrude', true, ... 93 | 'visibility',arg.visibility,... 94 | 'altitudeMode','absolute',... 95 | 'lineWidth',0, ... 96 | 'polyColor',colorHex, ... 97 | 'id', [arg.id '_' num2str(i)]); 98 | end 99 | end 100 | target(1) = []; %remove the empty initial field 101 | end -------------------------------------------------------------------------------- /@kml/quadoverlay.m: -------------------------------------------------------------------------------- 1 | function target = quadoverlay(this,long,lat,varargin) 2 | %KML.quadoverlay(longitude, latitude) Places the image file (specified by the pair 3 | % attribute 'file','image.png') as a ground overlay in the kml file. The corners 4 | % of the image are given by inputs longitude and latitude (which should represent 4 points). 5 | % To make the overlay transparent, change the alpha portion of the color parameter 6 | % to a different hex value - eg.: 50% transparent, use KML.OVERLAY(...,'color','80FFFFFF') 7 | % 8 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 9 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 10 | 11 | target = struct('type','','id',''); 12 | 13 | [long,lat] = this.checkUnit(long,lat); 14 | 15 | p = inputParser; 16 | 17 | p.addRequired('long', @(a)isnumeric(a) && numel(a)==4); 18 | p.addRequired('lat', @(a)isnumeric(a) && numel(a)==4); 19 | 20 | p.addParamValue('id',kml.getTempID('kml_overlay'),@ischar); 21 | p.addParamValue('name','kml_overlay',@ischar); 22 | p.addParamValue('description','',@ischar); 23 | p.addParamValue('visibility',true,@islogical); 24 | p.addParamValue('file','',@ischar); 25 | p.addParamValue('viewBoundScale',1,@(a)isnumeric(a) && numel(a)==1); 26 | p.addParamValue('color','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 27 | p.addParamValue('altitude',1,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 28 | p.addParamValue('drawOrder',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 29 | p.addParamValue('altitudeMode','clampToGround',@(a)ismember(a,{'clampToGround','absolute'})); 30 | 31 | p.addParamValue('timeStamp','',@ischar); 32 | p.addParamValue('timeSpanBegin','',@ischar); 33 | p.addParamValue('timeSpanEnd','',@ischar); 34 | 35 | p.parse(long,lat,varargin{:}); 36 | 37 | arg = p.Results; 38 | 39 | if isempty(arg.file) 40 | error('Missing file parameter') 41 | end 42 | 43 | coordinates = sprintf('%0.16g,%0.16g ',[long(:) lat(:)].'); 44 | 45 | overlay = this.xml.createElement('GroundOverlay'); 46 | icon = this.xml.createElement('Icon'); 47 | gxLatLonQuad = this.xml.createElement('gx:LatLonQuad'); 48 | 49 | overlay.setAttribute('id',arg.id); 50 | overlay.appendChild(this.textNode('name',arg.name)); 51 | overlay.appendChild(this.textNode('color',arg.color)); 52 | overlay.appendChild(this.textNode('visibility',num2str(arg.visibility))); 53 | overlay.appendChild(this.textNode('description',arg.description)); 54 | overlay.appendChild(this.textNode('altitude',num2str(arg.altitude))); 55 | overlay.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 56 | overlay.appendChild(this.textNode('drawOrder',num2str(arg.drawOrder))); 57 | 58 | if ~isempty(arg.timeStamp) 59 | timeStamp = this.xml.createElement('TimeStamp'); 60 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 61 | overlay.appendChild(timeStamp); 62 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 63 | timeSpan = this.xml.createElement('TimeSpan'); 64 | if ~isempty(arg.timeSpanBegin) 65 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 66 | end 67 | 68 | if ~isempty(arg.timeSpanEnd) 69 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 70 | end 71 | overlay.appendChild(timeSpan); 72 | end 73 | 74 | gxLatLonQuad.appendChild(this.textNode('coordinates',coordinates)); 75 | 76 | icon.appendChild(this.textNode('href',arg.file)); 77 | icon.appendChild(this.textNode('viewBoundScale',num2str(arg.viewBoundScale))); 78 | 79 | overlay.appendChild(gxLatLonQuad); 80 | overlay.appendChild(icon); 81 | this.doc.appendChild(overlay); 82 | 83 | target.id = arg.id; 84 | target.type = 'GroundOverlay'; 85 | 86 | this.addIncludeFile(arg.file); 87 | end -------------------------------------------------------------------------------- /@kml/quiver.m: -------------------------------------------------------------------------------- 1 | function target = quiver(this,long,lat,u,v,varargin) 2 | %KML.QUIVER(long,lat,u,v) Create a quiver plot, similar to built-in 3 | % function quiver3, using line arrows. 4 | % 5 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 6 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 7 | 8 | target = struct('type','','id','','coordinates_type','','coordinates_id',''); 9 | 10 | [longDEG,latDEG] = this.checkUnit(long,lat); 11 | 12 | p = inputParser; 13 | 14 | nlat = numel(lat); 15 | 16 | p.addRequired('lat', @(a)isnumeric(a) && ~isempty(a)); 17 | p.addRequired('long', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 18 | p.addRequired('u', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 19 | p.addRequired('v', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 20 | 21 | p.addParamValue('altitude',1000,@(a)isnumeric(a) && numel(a)==1); 22 | p.addParamValue('scale',1,@(a)isnumeric(a) && numel(a)==1); 23 | p.addParamValue('arrowBaseSize',0.3,@(a)isnumeric(a) && numel(a)==1); 24 | p.addParamValue('plotArrows',true,@islogical); 25 | p.addParamValue('arrowHeadSize',0.3,@(a)isnumeric(a) && numel(a)==1); 26 | 27 | p.addParamValue('color','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 28 | p.addParamValue('name','kml_quiver',@ischar); 29 | p.addParamValue('id',kml.getTempID('kml_quiver'),@ischar); 30 | p.addParamValue('description','',@ischar); 31 | p.addParamValue('visibility',true,@islogical); 32 | p.addParamValue('altitudeMode','relativeToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 33 | 34 | p.addParamValue('timeStamp','',@ischar); 35 | p.addParamValue('timeSpanBegin','',@ischar); 36 | p.addParamValue('timeSpanEnd','',@ischar); 37 | 38 | p.parse(lat,long,u,v,varargin{:}); 39 | 40 | arg = p.Results; 41 | 42 | f = this.createFolder(arg.name); 43 | 44 | uv = sqrt((u+v).^2); 45 | 46 | edgelen = @(a)(max(a(:))-min(a(:))).^2; 47 | dS = edgelen(latDEG) + edgelen(longDEG); 48 | 49 | scale = sqrt((u.^2 + v.^2)./dS); 50 | scale = arg.scale .* scale; 51 | alpha = arg.arrowHeadSize; 52 | beta = arg.arrowBaseSize; 53 | for i = 1:numel(lat) 54 | if arg.plotArrows 55 | long2 = scale(i).*[0 u(i) u(i)-alpha*(u(i)+beta*(v(i)+eps)) u(i) u(i)-alpha*(u(i)-beta*(v(i)+eps))] + long(i); 56 | lat2 = scale(i).*[0 v(i) v(i)-alpha*(v(i)-beta*(u(i)+eps)) v(i) v(i)-alpha*(v(i)+beta*(u(i)+eps))] + lat(i); 57 | else 58 | long2 = scale(i).*[0 u(i)] + long(i); 59 | lat2 = scale(i).*[0 v(i)] + lat(i); 60 | end 61 | target(i) = f.plot(long2,lat2, 'altitude',arg.altitude,... 62 | 'altitudeMode',arg.altitudeMode, ... 63 | 'visibility',arg.visibility, ... 64 | 'name',sprintf('Arrow %i',i), ... 65 | 'lineColor',arg.color, ... 66 | 'timeStamp', arg.timeStamp , ... 67 | 'timeSpanBegin', arg.timeSpanBegin , ... 68 | 'timeSpanEnd', arg.timeSpanEnd, ... 69 | 'id', [arg.id '_' num2str(i)] ... 70 | ); 71 | end 72 | end -------------------------------------------------------------------------------- /@kml/quiver3d.m: -------------------------------------------------------------------------------- 1 | function target = quiver3d(this,long,lat,alt,u,v,w,varargin) 2 | %KML.QUIVER3D(long,lat,alt,u,v,w) Create a quiver plot, similar to built-in 3 | % function quiver3, using 3D arrows. 4 | % 5 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 6 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 7 | 8 | target = struct('type','','id','','location_id','','orientation_id','','scale_id','','model_id',''); 9 | 10 | [longDEG,latDEG] = this.checkUnit(long,lat); 11 | 12 | p = inputParser; 13 | 14 | nlat = numel(lat); 15 | 16 | p.addRequired('lat', @(a)isnumeric(a) && ~isempty(a)); 17 | p.addRequired('long', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 18 | p.addRequired('alt', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 19 | p.addRequired('u', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 20 | p.addRequired('v', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 21 | p.addRequired('w', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 22 | 23 | p.addParamValue('scale',100,@(a)isnumeric(a) && numel(a)==1); 24 | p.addParamValue('color','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 25 | p.addParamValue('name','kml_quiver3D',@ischar); 26 | p.addParamValue('id',kml.getTempID('kml_quiver3D'),@ischar); 27 | p.addParamValue('description','',@ischar); 28 | p.addParamValue('visibility',true,@islogical); 29 | p.addParamValue('model','',@ischar); 30 | p.addParamValue('altitudeMode','relativeToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 31 | 32 | p.addParamValue('timeStamp','',@ischar); 33 | p.addParamValue('timeSpanBegin','',@ischar); 34 | p.addParamValue('timeSpanEnd','',@ischar); 35 | 36 | p.parse(lat,long,alt,u,v,w,varargin{:}); 37 | 38 | arg = p.Results; 39 | 40 | if isempty(arg.model) 41 | arrowfile = 'arrow3d.dae'; 42 | 43 | arg.model = arrowfile; 44 | end 45 | 46 | modelpath = which(arg.model); 47 | 48 | if ~isempty(modelpath) 49 | if isempty(dir(arg.model)) 50 | copyfile(modelpath,arg.model); 51 | end 52 | else 53 | error('File %s not found!',arg.model); 54 | end 55 | 56 | f = this.createFolder(arg.name); 57 | 58 | uv = sqrt((u+v).^2); 59 | if strcmpi(this.unit,'deg') 60 | rad2deg = 180/pi; 61 | else 62 | rad2deg = 1; 63 | end 64 | heading = rad2deg * atan2(u,v); 65 | tilt = rad2deg * atan2(w,uv)-pi/2; 66 | roll = zeros(size(lat)); 67 | 68 | 69 | edgelen = @(a)(max(a(:))-min(a(:))).^2; 70 | dS = edgelen(latDEG) + edgelen(longDEG) + edgelen(alt); 71 | 72 | scale = sqrt((u.^2 + v.^2 + w.^2)./dS); 73 | scale = arg.scale .* scale; 74 | 75 | for i = 1:numel(lat) 76 | target(i) = f.model(long(i),lat(i),alt(i),heading(i),tilt(i),roll(i), 'scale',scale(i),'model',arg.model, ... 77 | 'altitudeMode',arg.altitudeMode, ... 78 | 'visibility',arg.visibility, ... 79 | 'name',sprintf('Arrow %i',i), ... 80 | 'timeStamp', arg.timeStamp , ... 81 | 'timeSpanBegin', arg.timeSpanBegin , ... 82 | 'timeSpanEnd', arg.timeSpanEnd, ... 83 | 'id', [arg.id '_' num2str(i)] ... 84 | ); 85 | end 86 | 87 | this.addIncludeFile(arg.model); 88 | end -------------------------------------------------------------------------------- /@kml/scatter.m: -------------------------------------------------------------------------------- 1 | function target = scatter(this,long,lat,varargin) 2 | %KML.SCATTER(long,lat,alt) Places point markers in the positions given by long and lat 3 | % Similar to built-in scatter function. For a list of available markers, run 4 | % help kml.parseIconURL 5 | % 6 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 7 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 8 | 9 | target = struct('type','','id',''); 10 | 11 | [long,lat] = this.checkUnit(long,lat); 12 | 13 | nlat = numel(lat); 14 | 15 | p = inputParser; 16 | 17 | p.addRequired('lat', @(a)isnumeric(a) && ~isempty(a)); 18 | p.addRequired('long',@(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 19 | 20 | p.addParamValue('id',kml.getTempID('kml_scatter'),@ischar); 21 | p.addParamValue('name','kml_scatter',@ischar); 22 | p.addParamValue('description','',@ischar); 23 | p.addParamValue('visibility',true,@islogical); 24 | p.addParamValue('iconColor','FFFFFFFF',@(a)(iscell(a) && numel(a)==nlat) || (size(a,1)==1 || size(a,1)==nlat) || (ischar(a) && numel(a)==8)); 25 | p.addParamValue('iconURL','',@(a)ischar(a)||(iscell(a)&&numel(a)==nlat)); 26 | p.addParamValue('iconScale',1,@(a)isnumeric(a) && (numel(a)==1 || numel(a)==nlat)); 27 | p.addParamValue('altitudeMode','clampToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 28 | p.addParamValue('altitude',1,@(a)isnumeric(a) && (numel(a)==1 || numel(a)==nlat)); 29 | 30 | p.addParamValue('timeStamp','',@(a)ischar(a)||iscell(a)); 31 | p.addParamValue('timeSpanBegin','',@(a)ischar(a)||iscell(a)); 32 | p.addParamValue('timeSpanEnd','',@(a)ischar(a)||iscell(a)); 33 | 34 | p.parse(lat,long,varargin{:}); 35 | 36 | arg = p.Results; 37 | 38 | if numel(arg.altitude)~=nlat 39 | alt = repmat(arg.altitude(1),size(lat)); 40 | else 41 | alt = arg.altitude; 42 | end 43 | 44 | nc = numel(arg.iconColor); 45 | ns = numel(arg.iconScale); 46 | 47 | 48 | if ~iscell(arg.timeStamp) 49 | arg.timeStamp = {arg.timeStamp}; 50 | end 51 | if numel(arg.timeStamp)~=nlat 52 | arg.timeStamp = repmat(arg.timeStamp,nlat,1); 53 | end 54 | 55 | if ~iscell(arg.timeSpanBegin) 56 | arg.timeSpanBegin = {arg.timeSpanBegin}; 57 | end 58 | if numel(arg.timeSpanBegin)~=nlat 59 | arg.timeSpanBegin = repmat(arg.timeSpanBegin,nlat,1); 60 | end 61 | 62 | if ~iscell(arg.timeSpanEnd) 63 | arg.timeSpanEnd = {arg.timeSpanEnd}; 64 | end 65 | if numel(arg.timeSpanEnd)~=nlat 66 | arg.timeSpanEnd = repmat(arg.timeSpanEnd,nlat,1); 67 | end 68 | 69 | if nc~=1 70 | if ~iscell(arg.iconColor) && ~ischar(arg.iconColor) 71 | if ismember(size(arg.iconColor,2),[3 4]) 72 | %Color matrix, convert to string format 73 | iC = cell(size(arg.iconColor,1),1); 74 | for i = 1:size(arg.iconColor,1) 75 | c = min(max(floor(arg.iconColor(i,:)*255),0),255); 76 | if numel(c)==3 77 | [r,g,b,a] = deal(c(1),c(2),c(3),255); 78 | else 79 | [r,g,b,a] = deal(c(1),c(2),c(3),c(4)); 80 | end 81 | [rhex, ghex, bhex, ahex ]= deal(dec2hex(r),dec2hex(g),dec2hex(b),dec2hex(a)); 82 | if length(rhex)==1,rhex=['0' rhex];end 83 | if length(ghex)==1,ghex=['0' ghex];end 84 | if length(bhex)==1,bhex=['0' bhex];end 85 | if length(ahex)==1,ahex=['0' ahex];end 86 | 87 | iC{i} = [ahex bhex ghex rhex]; 88 | end 89 | arg.iconColor = iC; 90 | nc = numel(arg.iconColor); 91 | else 92 | error('Invalid iconColor argument') 93 | end 94 | end 95 | end 96 | 97 | iconURL = kml.parseIconURL(arg.iconURL); 98 | scatterfolder = this.xml.createElement('Folder'); 99 | 100 | for i = 1:nlat 101 | target(i).id = [arg.id '_' num2str(i)]; 102 | target(i).type = 'Placemark'; 103 | % coordinates = mat2str([long(i) lat(i) alt(i)]); 104 | % coordinates = coordinates(2:end-1); 105 | % coordinates = strrep(coordinates,' ',','); 106 | % coordinates = strrep(coordinates,';',' '); 107 | coordinates = sprintf('%0.16g,%0.16g,%0.16g ',[long(i) lat(i) alt(i)].'); 108 | 109 | placemark = this.xml.createElement('Placemark'); 110 | point = this.xml.createElement('Point'); 111 | style = this.xml.createElement('Style'); 112 | iconstyle = this.xml.createElement('IconStyle'); 113 | icon = this.xml.createElement('Icon'); 114 | 115 | placemark.setAttribute('id',target(i).id); 116 | placemark.appendChild(this.textNode('name','')); %[arg.name '_' num2str(i)] 117 | placemark.appendChild(this.textNode('visibility',num2str(arg.visibility))); 118 | placemark.appendChild(this.textNode('description',arg.description)); 119 | 120 | if ~isempty(arg.timeStamp{i}) 121 | timeStamp = this.xml.createElement('TimeStamp'); 122 | timeStamp.appendChild(this.textNode('when',arg.timeStamp{i})); 123 | placemark.appendChild(timeStamp); 124 | elseif ~isempty(arg.timeSpanBegin{i}) || ~isempty(arg.timeSpanEnd{i}) 125 | timeSpan = this.xml.createElement('TimeSpan'); 126 | if ~isempty(arg.timeSpanBegin{i}) 127 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin{i})); 128 | end 129 | 130 | if ~isempty(arg.timeSpanEnd{i}) 131 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd{i})); 132 | end 133 | placemark.appendChild(timeSpan); 134 | end 135 | 136 | if nc==nlat 137 | iconstyle.appendChild(this.textNode('color',arg.iconColor{i})); 138 | else 139 | iconstyle.appendChild(this.textNode('color',arg.iconColor)); 140 | end 141 | 142 | if ns==nlat 143 | iconstyle.appendChild(this.textNode('scale',num2str(arg.iconScale(i)))); 144 | else 145 | iconstyle.appendChild(this.textNode('scale',num2str(arg.iconScale))); 146 | end 147 | 148 | if iscell(iconURL) 149 | icon.appendChild(this.textNode('href',iconURL{i})); 150 | else 151 | icon.appendChild(this.textNode('href',iconURL)); 152 | end 153 | 154 | point.setAttribute('id',['Point_' arg.id]); 155 | point.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 156 | point.appendChild(this.textNode('coordinates',coordinates)); 157 | 158 | iconstyle.appendChild(icon); 159 | style.appendChild(iconstyle); 160 | placemark.appendChild(style); 161 | placemark.appendChild(point); 162 | scatterfolder.appendChild(placemark); 163 | end 164 | 165 | scatterfolder.appendChild(this.textNode('name',arg.name)); 166 | scatterfolder.appendChild(this.textNode('id', arg.id)); 167 | this.doc.appendChild(scatterfolder); 168 | end -------------------------------------------------------------------------------- /@kml/scatter3.m: -------------------------------------------------------------------------------- 1 | function target = scatter3(this,long,lat,alt,varargin) 2 | %KML.SCATTER3(long,lat,alt) Places point markers in the positions given by long, lat and alt 3 | % Similar to built-in scatter3 function. For a list of available markers, run 4 | % help kml.parseIconURL 5 | % 6 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 7 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 8 | 9 | target = struct('type','','id',''); 10 | 11 | [long,lat] = this.checkUnit(long,lat); 12 | 13 | nlat = numel(lat); 14 | 15 | p = inputParser; 16 | 17 | p.addRequired('lat', @(a)isnumeric(a) && ~isempty(a)); 18 | p.addRequired('long',@(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 19 | p.addRequired('alt', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 20 | 21 | p.addParamValue('id',kml.getTempID('kml_scatter3'),@ischar); 22 | p.addParamValue('name','kml_scatter3',@ischar); 23 | p.addParamValue('description','',@ischar); 24 | p.addParamValue('visibility',true,@islogical); 25 | p.addParamValue('iconColor','FFFFFFFF',@(a)(iscell(a) && numel(a)==nlat) || (size(a,1)==1 || size(a,1)==nlat) || (ischar(a) && numel(a)==8)); 26 | p.addParamValue('iconURL','',@(a)ischar(a)||(iscell(a)&&numel(a)==nlat)); 27 | p.addParamValue('iconScale',1,@(a)isnumeric(a) && (numel(a)==1 || numel(a)==nlat)); 28 | p.addParamValue('altitudeMode','relativeToGround',@(a)ismember(a,{'clampToGround','relativeToGround','absolute'})); 29 | 30 | p.addParamValue('timeStamp','',@(a)ischar(a)||iscell(a)); 31 | p.addParamValue('timeSpanBegin','',@(a)ischar(a)||iscell(a)); 32 | p.addParamValue('timeSpanEnd','',@(a)ischar(a)||iscell(a)); 33 | 34 | p.parse(lat,long,alt,varargin{:}); 35 | 36 | arg = p.Results; 37 | 38 | 39 | nc = numel(arg.iconColor); 40 | ns = numel(arg.iconScale); 41 | 42 | if ~iscell(arg.timeStamp) 43 | arg.timeStamp = {arg.timeStamp}; 44 | end 45 | if numel(arg.timeStamp)~=nlat 46 | arg.timeStamp = repmat(arg.timeStamp,nlat,1); 47 | end 48 | 49 | if ~iscell(arg.timeSpanBegin) 50 | arg.timeSpanBegin = {arg.timeSpanBegin}; 51 | end 52 | if numel(arg.timeSpanBegin)~=nlat 53 | arg.timeSpanBegin = repmat(arg.timeSpanBegin,nlat,1); 54 | end 55 | if ~iscell(arg.timeSpanEnd) 56 | arg.timeSpanEnd = {arg.timeSpanEnd}; 57 | end 58 | if numel(arg.timeSpanEnd)~=nlat 59 | arg.timeSpanEnd = repmat(arg.timeSpanEnd,nlat,1); 60 | end 61 | 62 | 63 | if nc~=1 64 | if ~iscell(arg.iconColor) && ~ischar(arg.iconColor) 65 | if ismember(size(arg.iconColor,2),[3 4]) 66 | %Color matrix, convert to string format 67 | iC = cell(size(arg.iconColor,1),1); 68 | for i = 1:size(arg.iconColor,1) 69 | c = min(max(floor(arg.iconColor(i,:)*255),0),255); 70 | if numel(c)==3 71 | [r,g,b,a] = deal(c(1),c(2),c(3),255); 72 | else 73 | [r,g,b,a] = deal(c(1),c(2),c(3),c(4)); 74 | end 75 | [rhex, ghex, bhex, ahex ]= deal(dec2hex(r),dec2hex(g),dec2hex(b),dec2hex(a)); 76 | if length(rhex)==1,rhex=['0' rhex];end 77 | if length(ghex)==1,ghex=['0' ghex];end 78 | if length(bhex)==1,bhex=['0' bhex];end 79 | if length(ahex)==1,ahex=['0' ahex];end 80 | 81 | iC{i} = [ahex bhex ghex rhex]; 82 | end 83 | arg.iconColor = iC; 84 | nc = numel(arg.iconColor); 85 | else 86 | error('Invalid iconColor argument') 87 | end 88 | end 89 | end 90 | 91 | iconURL = kml.parseIconURL(arg.iconURL); 92 | scatterfolder = this.xml.createElement('Folder'); 93 | 94 | for i = 1:nlat 95 | target(i).id = [arg.id '_' num2str(i)]; 96 | target(i).type = 'Placemark'; 97 | % coordinates = mat2str([long(i) lat(i) alt(i)]); 98 | % coordinates = coordinates(2:end-1); 99 | % coordinates = strrep(coordinates,' ',','); 100 | % coordinates = strrep(coordinates,';',' '); 101 | coordinates = sprintf('%0.16g,%0.16g,%0.16g ',[long(i) lat(i) alt(i)].'); 102 | 103 | placemark = this.xml.createElement('Placemark'); 104 | point = this.xml.createElement('Point'); 105 | style = this.xml.createElement('Style'); 106 | iconstyle = this.xml.createElement('IconStyle'); 107 | icon = this.xml.createElement('Icon'); 108 | 109 | placemark.setAttribute('id',target(i).id ); 110 | placemark.appendChild(this.textNode('name','')); %[arg.name '_' num2str(i)] 111 | placemark.appendChild(this.textNode('visibility',num2str(arg.visibility))); 112 | placemark.appendChild(this.textNode('description',arg.description)); 113 | 114 | if ~isempty(arg.timeStamp{i}) 115 | timeStamp = this.xml.createElement('TimeStamp'); 116 | timeStamp.appendChild(this.textNode('when',arg.timeStamp{i})); 117 | placemark.appendChild(timeStamp); 118 | elseif ~isempty(arg.timeSpanBegin{i}) || ~isempty(arg.timeSpanEnd{i}) 119 | timeSpan = this.xml.createElement('TimeSpan'); 120 | if ~isempty(arg.timeSpanBegin{i}) 121 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin{i})); 122 | end 123 | 124 | if ~isempty(arg.timeSpanEnd{i}) 125 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd{i})); 126 | end 127 | placemark.appendChild(timeSpan); 128 | end 129 | 130 | if iscell(arg.iconColor) && nc==nlat 131 | iconstyle.appendChild(this.textNode('color',arg.iconColor{i})); 132 | else 133 | iconstyle.appendChild(this.textNode('color',arg.iconColor)); 134 | end 135 | 136 | if ns==nlat 137 | iconstyle.appendChild(this.textNode('scale',num2str(arg.iconScale(i)))); 138 | else 139 | iconstyle.appendChild(this.textNode('scale',num2str(arg.iconScale))); 140 | end 141 | 142 | if iscell(iconURL) 143 | icon.appendChild(this.textNode('href',iconURL{i})); 144 | else 145 | icon.appendChild(this.textNode('href',iconURL)); 146 | end 147 | 148 | point.setAttribute('id',['Point_' arg.id]); 149 | point.appendChild(this.textNode('altitudeMode',arg.altitudeMode)); 150 | point.appendChild(this.textNode('coordinates',coordinates)); 151 | 152 | iconstyle.appendChild(icon); 153 | style.appendChild(iconstyle); 154 | placemark.appendChild(style); 155 | placemark.appendChild(point); 156 | scatterfolder.appendChild(placemark); 157 | end 158 | 159 | scatterfolder.appendChild(this.textNode('name',arg.name)); 160 | scatterfolder.appendChild(this.textNode('id', arg.id)); 161 | this.doc.appendChild(scatterfolder); 162 | end -------------------------------------------------------------------------------- /@kml/screenoverlay.m: -------------------------------------------------------------------------------- 1 | function target = screenoverlay(this,overlayXY,screenXY,sz,varargin) 2 | %KML.SCREENOVERLAY(overlayXY,screenXY,sz) Places the image file (specified by the pair 3 | % attribute 'file','image.png') as a screen overlay in the kml file. 4 | % Check https://developers.google.com/kml/documentation/kmlreference#screenoverlay for more info. 5 | % To make the overlay transparent, change the alpha portion of the color parameter 6 | % to a different hex value - eg.: 50% transparent, use KML.OVERLAY(...,'color','80FFFFFF') 7 | % 8 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 9 | % $Revision: 2.4 $ $Date: 2012/12/07 08:00:00 $ 10 | 11 | target = struct('type','','id',''); 12 | 13 | 14 | 15 | p = inputParser; 16 | 17 | p.addRequired('overlayXY', @(a)isnumeric(a) && ~isempty(a) && numel(a)==2); 18 | p.addRequired('screenXY', @(a)isnumeric(a) && ~isempty(a) && numel(a)==2); 19 | p.addRequired('sz',@(a)isnumeric(a) && ~isempty(a) && numel(a)==2); 20 | 21 | p.addParamValue('id',kml.getTempID('kml_overlay'),@ischar); 22 | p.addParamValue('name','kml_overlay',@ischar); 23 | p.addParamValue('description','',@ischar); 24 | p.addParamValue('visibility',true,@islogical); 25 | p.addParamValue('file','',@ischar); 26 | p.addParamValue('viewBoundScale',1,@(a)isnumeric(a) && numel(a)==1); 27 | p.addParamValue('color','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 28 | p.addParamValue('altitude',1,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 29 | p.addParamValue('rotation',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 30 | p.addParamValue('drawOrder',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 31 | p.addParamValue('altitudeMode','clampToGround',@(a)ismember(a,{'clampToGround','absolute'})); 32 | p.addParamValue('units','fraction',@(a)ismember(a,{'fraction','pixels','insetPixels'})); 33 | 34 | p.addParamValue('timeStamp','',@ischar); 35 | p.addParamValue('timeSpanBegin','',@ischar); 36 | p.addParamValue('timeSpanEnd','',@ischar); 37 | 38 | p.parse(overlayXY,screenXY,sz,varargin{:}); 39 | 40 | arg = p.Results; 41 | 42 | if isempty(arg.file) 43 | error('Missing file parameter') 44 | end 45 | 46 | arg.rotation = this.checkUnit(arg.rotation); 47 | 48 | arg.overlayPos = overlayXY; 49 | arg.screenPos = screenXY; 50 | arg.sz = sz; 51 | 52 | % 53 | % Simple crosshairs 54 | % This screen overlay uses fractional positioning 55 | % to put the image in the exact center of the screen 56 | % 57 | % http://myserver/myimage.jpg 58 | % 59 | % 60 | % 61 | % 39.37878630116985 62 | % 63 | % 64 | 65 | 66 | %% 67 | 68 | overlay = this.xml.createElement('ScreenOverlay'); 69 | overlayXY = this.xml.createElement('overlayXY'); 70 | screenXY = this.xml.createElement('screenXY'); 71 | size = this.xml.createElement('size'); 72 | icon = this.xml.createElement('Icon'); 73 | 74 | overlay.setAttribute('id',arg.id); 75 | overlay.appendChild(this.textNode('name',arg.name)); 76 | overlay.appendChild(this.textNode('open','1')); 77 | overlay.appendChild(this.textNode('visibility',num2str(arg.visibility))); 78 | overlay.appendChild(this.textNode('description',arg.description)); 79 | overlay.appendChild(this.textNode('drawOrder',num2str(arg.drawOrder))); 80 | overlay.appendChild(this.textNode('color',arg.color)); 81 | 82 | if ~isempty(arg.timeStamp) 83 | timeStamp = this.xml.createElement('TimeStamp'); 84 | timeStamp.appendChild(this.textNode('when',arg.timeStamp)); 85 | overlay.appendChild(timeStamp); 86 | elseif ~isempty(arg.timeSpanBegin) || ~isempty(arg.timeSpanEnd) 87 | timeSpan = this.xml.createElement('TimeSpan'); 88 | if ~isempty(arg.timeSpanBegin) 89 | timeSpan.appendChild(this.textNode('begin',arg.timeSpanBegin)); 90 | end 91 | 92 | if ~isempty(arg.timeSpanEnd) 93 | timeSpan.appendChild(this.textNode('end',arg.timeSpanEnd)); 94 | end 95 | overlay.appendChild(timeSpan); 96 | end 97 | 98 | overlayXY.setAttribute('x',num2str(arg.overlayPos(1),16)) 99 | overlayXY.setAttribute('y',num2str(arg.overlayPos(2),16)) 100 | overlayXY.setAttribute('xunits','fraction') 101 | overlayXY.setAttribute('yunits','fraction') 102 | 103 | screenXY.setAttribute('x',num2str(arg.screenPos(1),16)) 104 | screenXY.setAttribute('y',num2str(arg.screenPos(2),16)) 105 | screenXY.setAttribute('xunits','fraction') 106 | screenXY.setAttribute('yunits','fraction') 107 | 108 | size.setAttribute('x',num2str(arg.sz(1))) 109 | size.setAttribute('y',num2str(arg.sz(2))) 110 | size.setAttribute('xunits','fraction') 111 | size.setAttribute('yunits','fraction') 112 | overlay.appendChild(this.textNode('rotation', num2str(arg.rotation))); 113 | 114 | icon.appendChild(this.textNode('href',arg.file)); 115 | 116 | overlay.appendChild(overlayXY); 117 | overlay.appendChild(screenXY); 118 | overlay.appendChild(size); 119 | overlay.appendChild(icon); 120 | 121 | this.doc.appendChild(overlay); 122 | 123 | target.id = arg.id; 124 | target.type = 'ScreenOverlay'; 125 | this.addIncludeFile(arg.file); 126 | end -------------------------------------------------------------------------------- /@kml/surf.m: -------------------------------------------------------------------------------- 1 | function target = surf(this,long,lat,alt,cval ,varargin) 2 | %KML.surf(long,lat,alt) Create a surface contour of alt in a grid defined by long and lat. 3 | % Similar to built-in surf function 4 | % 5 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 6 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 7 | 8 | target = struct('type','','id',''); 9 | 10 | p = inputParser; 11 | 12 | [long,lat] = this.checkUnit(long,lat); 13 | 14 | 15 | nlat = numel(lat); 16 | [r,c] = size(lat); 17 | p.addRequired('lat', @(a)isnumeric(a) && ~isempty(a)); 18 | p.addRequired('long', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 19 | p.addRequired('alt', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 20 | p.addRequired('cval', @(a)isnumeric(a) && ~isempty(a) && numel(a)==nlat); 21 | 22 | p.addParamValue('name','kml_surf',@ischar); 23 | p.addParamValue('id',kml.getTempID('kml_surf'),@ischar); 24 | p.addParamValue('description','',@ischar); 25 | p.addParamValue('visibility',true,@islogical); 26 | p.addParamValue('colorMap','jet',@ischar); 27 | p.addParamValue('color','',@(a)ischar(a) && numel(a)==8); 28 | 29 | p.addParamValue('timeStamp','',@ischar); 30 | p.addParamValue('timeSpanBegin','',@ischar); 31 | p.addParamValue('timeSpanEnd','',@ischar); 32 | 33 | p.parse(lat,long,alt,cval,varargin{:}); 34 | 35 | arg = p.Results; 36 | arg.visibility = num2str(arg.visibility); 37 | 38 | if isempty(arg.color) 39 | lineColor = 'FF000000'; 40 | else 41 | lineColor = '00000000'; %arg.color; 42 | end 43 | 44 | 45 | f = this.createFolder(arg.name); 46 | 47 | ncolors = 100; 48 | cmap = feval(arg.colorMap,ncolors); 49 | cspace = 1:ncolors; 50 | aspace = linspace(min(cval(:)),max(cval(:)),ncolors); 51 | for i = 2:r 52 | for j = 2:c 53 | longC = [long(i-1,j-1) long(i,j-1) long(i,j) long(i-1,j-1)];% long(i-1,j) long(i,j) long(i-1,j-1)]; 54 | latC = [lat(i-1,j-1) lat(i,j-1) lat(i,j) lat(i-1,j-1)];% lat(i-1,j) lat(i,j) lat(i-1,j-1)]; 55 | altC = [alt(i-1,j-1) alt(i,j-1) alt(i,j) alt(i-1,j-1)];% alt(i-1,j) alt(i,j) alt(i-1,j-1)]; 56 | 57 | alev = mean([cval(i-1,j-1) cval(i,j-1) cval(i,j)]); 58 | iC = round(interp1(aspace,cspace,alev,'linear',1)); 59 | color = cmap(iC ,:); 60 | 61 | if isempty(arg.color) 62 | colorHex = kml.color2kmlHex(color); 63 | else 64 | colorHex = arg.color; 65 | end 66 | 67 | 68 | % f.poly3(longC,latC,altC, 'polyColor', colorHex, ... 69 | % 'lineColor','FF000000',... %['00' colorHex(3:end)],... 70 | % 'altitudeMode','relativeToGround', ... 71 | % 'visibility',arg.visibility, ... 72 | % 'name',sprintf('Cell (%i,%i)',i,j), ... 73 | % 'timeStamp', arg.timeStamp , ... 74 | % 'timeSpanBegin', arg.timeSpanBegin , ... 75 | % 'timeSpanEnd', arg.timeSpanEnd ... 76 | % ); 77 | 78 | target(end+1).id = fastPoly(longC,latC,altC,sprintf('Cell (%i,%i)',i,j),[arg.id '_' sprintf('Cell (%i,%i)',i,j)]); 79 | target(end).type = 'Placemark'; 80 | 81 | longC = [long(i-1,j-1) long(i-1,j) long(i,j) long(i-1,j-1)]; 82 | latC = [lat(i-1,j-1) lat(i-1,j) lat(i,j) lat(i-1,j-1)]; 83 | altC = [alt(i-1,j-1) alt(i-1,j) alt(i,j) alt(i-1,j-1)]; 84 | 85 | alev = mean([cval(i-1,j-1) cval(i-1,j) cval(i,j)]); 86 | iC = round(interp1(aspace,cspace,alev,'linear',1)); 87 | color = cmap(iC ,:); 88 | 89 | if isempty(arg.color) 90 | colorHex = kml.color2kmlHex(color); 91 | else 92 | colorHex = arg.color; 93 | end 94 | 95 | 96 | % f.poly3(longC,latC,altC, 'polyColor', colorHex, ... 97 | % 'lineColor',lineColor,... %['00' colorHex(3:end)],... 98 | % 'altitudeMode','relativeToGround', ... 99 | % 'visibility',arg.visibility, ... 100 | % 'name',sprintf('Cell (%i,%i)',i,j), ... 101 | % 'timeStamp', arg.timeStamp , ... 102 | % 'timeSpanBegin', arg.timeSpanBegin , ... 103 | % 'timeSpanEnd', arg.timeSpanEnd ... 104 | % ); 105 | % 106 | 107 | target(end+1).id = fastPoly(longC,latC,altC,sprintf('Cell 2 (%i,%i)',i,j),[arg.id '_' sprintf('Cell (%i,%i)',i,j)]); 108 | target(end).type = 'Placemark'; 109 | end 110 | end 111 | 112 | 113 | function id = fastPoly(long,lat,alt,name,id) 114 | 115 | extrudeNode = this.textNode('extrude','0'); 116 | tessellateNode = this.textNode('tesselate','1'); 117 | altitudeModeNode = this.textNode('altitudeMode','absolute'); 118 | visibilityNode = this.textNode('visibility',arg.visibility); 119 | widthNode = this.textNode('width','1'); 120 | lineColorNode = this.textNode('color',lineColor); 121 | 122 | coordinates = sprintf('%0.16g,%0.16g,%0.16g ',[long(:) lat(:) alt(:)].'); 123 | 124 | placemark = this.xml.createElement('Placemark'); 125 | 126 | polygon = this.xml.createElement('Polygon'); 127 | outboundary = this.xml.createElement('outerBoundaryIs'); 128 | linearring = this.xml.createElement('LinearRing'); 129 | style = this.xml.createElement('Style'); 130 | linestyle = this.xml.createElement('LineStyle'); 131 | polystyle = this.xml.createElement('PolyStyle'); 132 | 133 | placemark.setAttribute('id',id); 134 | placemark.appendChild(this.textNode('name',name)); 135 | placemark.appendChild(visibilityNode); 136 | 137 | linestyle.appendChild(lineColorNode); 138 | linestyle.appendChild(widthNode); 139 | 140 | polystyle.appendChild(this.textNode('color',colorHex)); 141 | 142 | linearring.setAttribute('id','LinearRing'); 143 | linearring.appendChild(this.textNode('coordinates',coordinates)); 144 | 145 | polygon.setAttribute('id','Polygon'); 146 | polygon.appendChild(extrudeNode); 147 | polygon.appendChild(tessellateNode); 148 | polygon.appendChild(altitudeModeNode); 149 | 150 | outboundary.appendChild(linearring); 151 | polygon.appendChild(outboundary); 152 | 153 | style.appendChild(linestyle); 154 | style.appendChild(polystyle); 155 | placemark.appendChild(style); 156 | placemark.appendChild(polygon); 157 | f.doc.appendChild(placemark); 158 | end 159 | end -------------------------------------------------------------------------------- /@kml/text.m: -------------------------------------------------------------------------------- 1 | function target = text(this,long,lat,alt,txt,varargin) 2 | %KML.TEXT(long,lat,alt,txt) Writes the text given by txt at the coordinates 3 | % given by long, lat and alt. To write in more than one coordinate, pass an 4 | % array of coordinates, and a cell of texts, with the same number of members. 5 | % 6 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 7 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 8 | 9 | % target = struct('type','','id',''); 10 | 11 | if ~iscell(txt) 12 | txt = {txt}; 13 | end 14 | 15 | nlat = numel(lat); 16 | 17 | if ~(numel(long)==nlat && numel(alt)==nlat && numel(txt)==nlat) 18 | error('Invalid input sizes') 19 | end 20 | 21 | v = varargin; 22 | 23 | [tmpvar,hasIconURL ]= ismemberVarargin('iconURL',v); 24 | [tmpvar,hasIconScale ]= ismemberVarargin('iconScale',v); 25 | 26 | if any(hasIconURL) 27 | v{hasIconURL+1} = 'none'; 28 | else 29 | v{end+1} = 'iconURL'; 30 | v{end+1} = 'none'; 31 | end 32 | 33 | if any(hasIconScale) 34 | v{hasIconScale+1} = 0; 35 | else 36 | v{end+1} = 'IconScale'; 37 | v{end+1} = 0; 38 | end 39 | 40 | for i = 1:numel(lat) 41 | target(i) = this.point(long(i),lat(i),alt(i),'name',txt{i},v{:}); 42 | end 43 | 44 | end 45 | 46 | function [tf,loc] = ismemberVarargin(a,varin) 47 | if mod(numel(varin),2)==1 48 | error('Invalid number of named arguments.') 49 | end 50 | if ~iscell(a) 51 | a = {a}; 52 | end 53 | tf = false(size(a)); 54 | loc = zeros(size(a)); 55 | for i = 1:numel(a) 56 | for j = 1:2:numel(varin) 57 | if ischar(varin{j}) && strcmp(varin{j},a{i}) 58 | tf(i) = true; 59 | loc(i) = j; 60 | end 61 | end 62 | end 63 | end -------------------------------------------------------------------------------- /@kml/transfer.m: -------------------------------------------------------------------------------- 1 | function target = transfer(this,axisHandle,varargin) 2 | %KML.TRANSFER(ax) Transfer the axis from the handle ax to the KML as an overlay. 3 | % Example: 4 | % k = kml; 5 | % t = linspace(0,2*pi,1000); 6 | % figure; 7 | % plot(t,sin(t)); 8 | % k.transfer(gca) 9 | % k.run 10 | % 11 | % The corners of the overlay are taken from the axis limits. 12 | % 13 | % Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero) 14 | % $Revision: 2.3 $ $Date: 2012/09/05 08:00:00 $ 15 | 16 | p = inputParser; 17 | 18 | p.addRequired('axisHandle', @(a)ishghandle(a) && strcmpi(get(a,'Type'),'axes')); 19 | 20 | p.addParamValue('transparentBG',true,@islogical); 21 | p.addParamValue('keepAxis',false,@islogical); 22 | p.addParamValue('inPlace',false,@islogical); 23 | p.addParamValue('blurRadius',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 24 | p.addParamValue('blurSigma',1,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 25 | p.addParamValue('resizeFactor',1,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 26 | 27 | p.addParamValue('id',kml.getTempID('kml_overlay'),@ischar); 28 | p.addParamValue('name','kml_overlay',@ischar); 29 | p.addParamValue('description','',@ischar); 30 | p.addParamValue('visibility',true,@islogical); 31 | p.addParamValue('viewBoundScale',1,@(a)isnumeric(a) && numel(a)==1); 32 | p.addParamValue('color','FFFFFFFF',@(a)ischar(a) && numel(a)==8); 33 | p.addParamValue('altitude',1,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 34 | p.addParamValue('rotation',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 35 | p.addParamValue('drawOrder',0,@(a)isnumeric(a) &&~isempty(a) && numel(a)==1); 36 | p.addParamValue('altitudeMode','clampToGround',@(a)ismember(a,{'clampToGround','absolute'})); 37 | 38 | p.addParamValue('timeStamp','',@ischar); 39 | p.addParamValue('timeSpanBegin','',@ischar); 40 | p.addParamValue('timeSpanEnd','',@ischar); 41 | 42 | p.parse(axisHandle,varargin{:}); 43 | 44 | arg = p.Results; 45 | 46 | 47 | xlim = get(axisHandle,'XLim'); 48 | ylim = get(axisHandle,'YLim'); 49 | 50 | f = ancestor(axisHandle,'Figure'); 51 | name = get(f,'Name'); 52 | 53 | if isempty(name) 54 | if isnumeric(f) 55 | name = sprintf('Figure %i',f); 56 | else 57 | [tmpvar,name] = fileparts(tempname(pwd)); 58 | end 59 | end 60 | 61 | basename = name; 62 | 63 | name = [name '.png']; 64 | k = 1; 65 | while ~isempty(dir(name)) 66 | name = sprintf('%s (%i)%s',basename,k,'.png'); 67 | k = k+1; 68 | end 69 | 70 | if ~arg.inPlace 71 | ftmp = figure; 72 | axtmp = copyobj(axisHandle,ftmp); 73 | set(ftmp,'ColorMap',get(f,'ColorMap')); 74 | set(ftmp,'Position',get(0,'ScreenSize')); 75 | else 76 | axtmp = axisHandle; 77 | ftmp = ancestor(axtmp,'figure'); 78 | end 79 | 80 | [west,east,south,north] = deal(xlim(1),xlim(2),ylim(1),ylim(2)); 81 | if ~arg.keepAxis 82 | axis(axtmp,'off') 83 | 84 | set(axtmp,'XTick',[],'YTick',[],'ZTick',[]) 85 | set(get(axtmp,'XLabel'),'Visible','off'); 86 | set(get(axtmp,'YLabel'),'Visible','off'); 87 | set(get(axtmp,'ZLabel'),'Visible','off'); 88 | 89 | tightInset = get(axtmp, 'TightInset'); 90 | position(1) = tightInset(1); 91 | position(2) = tightInset(2); 92 | position(3) = 1 - tightInset(1) - tightInset(3); 93 | position(4) = 1 - tightInset(2) - tightInset(4); 94 | set(axtmp, 'Position', position); 95 | else 96 | p = get(axtmp, 'Position'); 97 | 98 | longSpan = abs(west-east); 99 | latSpan = abs(south-north); 100 | west = west - (longSpan/p(3)) *p(1); 101 | east = east + (longSpan/p(3))*(1-p(3)-p(1)); 102 | south = south - (latSpan/p(4))*p(2); 103 | north = north + (latSpan/p(4))*(1-p(4)-p(2)); 104 | end 105 | 106 | saveas(ftmp, name); 107 | 108 | %Remove a line of 3 pixels that MATLAB adds when saving the figure... 109 | %MUST CHECK if this holds always or not 110 | im = imread(name); 111 | im = im(1:end-3,1:end-3,:); 112 | 113 | if arg.blurRadius > 0 && arg.resizeFactor~=1 114 | im = resize(im,ceil(size(im)*arg.resizeFactor)); 115 | end 116 | 117 | 118 | if arg.transparentBG 119 | axc = get(axtmp,'Color'); 120 | axc = ceil(axc*255); 121 | alphaMap = uint8(~(im(:,:,1)==axc(1) & im(:,:,2)==axc(2) & im(:,:,3)==axc(3))*255); 122 | 123 | if arg.blurRadius > 0 124 | im = blur(im,arg.blurRadius,arg.blurSigma); 125 | alphaMap = blur(alphaMap,arg.blurRadius,arg.blurSigma); 126 | end 127 | imwrite(im,name,'Alpha',alphaMap); 128 | else 129 | if arg.blurRadius > 0 130 | im = blur(im,arg.blurRadius,arg.blurSigma); 131 | end 132 | imwrite(im,name); 133 | end 134 | 135 | target = this.overlay(west,east,south,north,'file',name,... 136 | 'id',arg.id,... 137 | 'name',arg.name,... 138 | 'description',arg.description,... 139 | 'visibility',arg.visibility,... 140 | 'viewBoundScale',arg.viewBoundScale,... 141 | 'color',arg.color,... 142 | 'altitude',arg.altitude,... 143 | 'rotation',arg.rotation,... 144 | 'drawOrder',arg.drawOrder,... 145 | 'altitudeMode',arg.altitudeMode,... 146 | 'timeStamp', arg.timeStamp ,... 147 | 'timeSpanBegin', arg.timeSpanBegin ,... 148 | 'timeSpanEnd', arg.timeSpanEnd ... 149 | ); 150 | 151 | close(ftmp); 152 | 153 | this.addIncludeFile(name); 154 | end 155 | 156 | 157 | function im = blur(im,radius,sigma) 158 | im = double(im)./255; 159 | BR = ceil(radius); 160 | N = 2*BR+1; 161 | kernel = zeros(N); 162 | dist = sqrt(repmat((1:N) - BR-1,N,1).^2 + repmat((1:N).' - BR-1,1,N).^2); 163 | kernel = (1/(2*pi*sigma*sigma)) .* exp(-dist./(2*sigma*sigma)); 164 | kernel = kernel./sum(kernel(:)); 165 | if ndims(im)==3 166 | im(:,:,1) = convn(im(:,:,1),kernel,'same'); 167 | im(:,:,2) = convn(im(:,:,2),kernel,'same'); 168 | im(:,:,3) = convn(im(:,:,3),kernel,'same'); 169 | else 170 | im= convn(im,kernel,'same'); 171 | end 172 | im = uint8(im*255); 173 | end 174 | 175 | 176 | function imN = resize(im,s) 177 | if ndims(im)==3 178 | imN(:,:,1) = resize(im(:,:,1),s); 179 | imN(:,:,2) = resize(im(:,:,2),s); 180 | imN(:,:,3) = resize(im(:,:,3),s); 181 | return 182 | else 183 | im = double(im)./255; 184 | [m,n] = size(im); 185 | [mN,nN] = deal(s(1),s(2)); 186 | [Y,X] = meshgrid( (0:n-1)/(n-1), (0:m-1)/(m-1) ); 187 | [YI,XI] = meshgrid( (0:nN-1)/(nN-1), (0:mN-1)/(mN-1) ); 188 | imN = interp2(Y, X, im, YI, XI ,'cubic'); 189 | end 190 | imN = uint8(imN*255); 191 | end -------------------------------------------------------------------------------- /README.m: -------------------------------------------------------------------------------- 1 | if isempty(which('kml')) 2 | disp(repmat('_',1,80)) 3 | disp(' _ ____ __ _ _____ _ _ ') 4 | disp(' | |/ / \/ | | |_ _|__ ___| | |__ _____ __') 5 | disp(' | '' <| |\/| | |__ | |/ _ \/ _ \ | ''_ \/ _ \ \ /') 6 | disp(' |_|\_\_| |_|____| |_|\___/\___/_|_.__/\___/_\_\') 7 | disp(sprintf('\n')); 8 | disp(' Thanks for downloading the KML toolbox v1.4!'); 9 | disp(sprintf('\n')); 10 | disp('For some cool examples on how to use the KML toolbox,'); 11 | disp(sprintf('please check the file RunTests.m located in the folder %s',pwd)); 12 | disp(repmat('_',1,80)); 13 | else 14 | tmp = getpref('kmltoolbox','ShowDisclaimer',true); 15 | setpref('kmltoolbox','ShowDisclaimer',true); 16 | display(kml); 17 | setpref('kmltoolbox','ShowDisclaimer',tmp); 18 | end -------------------------------------------------------------------------------- /html/help_clear.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_clear.jpg -------------------------------------------------------------------------------- /html/help_clear_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_clear_01.jpg -------------------------------------------------------------------------------- /html/help_clear_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_clear_02.jpg -------------------------------------------------------------------------------- /html/help_contour.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_contour.jpg -------------------------------------------------------------------------------- /html/help_contour3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_contour3.jpg -------------------------------------------------------------------------------- /html/help_contour3_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_contour3_01.jpg -------------------------------------------------------------------------------- /html/help_contour_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_contour_01.jpg -------------------------------------------------------------------------------- /html/help_kml.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_kml.jpg -------------------------------------------------------------------------------- /html/help_kml_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_kml_01.jpg -------------------------------------------------------------------------------- /html/help_model.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_model.jpg -------------------------------------------------------------------------------- /html/help_modelTour.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_modelTour.jpg -------------------------------------------------------------------------------- /html/help_modelTour_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_modelTour_01.jpg -------------------------------------------------------------------------------- /html/help_model_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_model_01.jpg -------------------------------------------------------------------------------- /html/help_overlay.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_overlay.jpg -------------------------------------------------------------------------------- /html/help_overlay_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_overlay_01.jpg -------------------------------------------------------------------------------- /html/help_plot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_plot.jpg -------------------------------------------------------------------------------- /html/help_plot3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_plot3.jpg -------------------------------------------------------------------------------- /html/help_plot3_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_plot3_01.jpg -------------------------------------------------------------------------------- /html/help_plot_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_plot_01.jpg -------------------------------------------------------------------------------- /html/help_point.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_point.jpg -------------------------------------------------------------------------------- /html/help_point_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_point_01.jpg -------------------------------------------------------------------------------- /html/help_poly.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_poly.jpg -------------------------------------------------------------------------------- /html/help_poly3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_poly3.jpg -------------------------------------------------------------------------------- /html/help_poly3_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_poly3_01.jpg -------------------------------------------------------------------------------- /html/help_poly_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_poly_01.jpg -------------------------------------------------------------------------------- /html/help_quiver.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_quiver.jpg -------------------------------------------------------------------------------- /html/help_quiver3d.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_quiver3d.jpg -------------------------------------------------------------------------------- /html/help_quiver3d_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_quiver3d_01.jpg -------------------------------------------------------------------------------- /html/help_quiver_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_quiver_01.jpg -------------------------------------------------------------------------------- /html/help_run.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_run.jpg -------------------------------------------------------------------------------- /html/help_run_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_run_01.jpg -------------------------------------------------------------------------------- /html/help_scatter.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_scatter.jpg -------------------------------------------------------------------------------- /html/help_scatter3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_scatter3.jpg -------------------------------------------------------------------------------- /html/help_scatter3_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_scatter3_01.jpg -------------------------------------------------------------------------------- /html/help_scatter_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_scatter_01.jpg -------------------------------------------------------------------------------- /html/help_text.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_text.jpg -------------------------------------------------------------------------------- /html/help_text_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_text_01.jpg -------------------------------------------------------------------------------- /html/help_transfer.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_transfer.jpg -------------------------------------------------------------------------------- /html/help_transfer_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_transfer_01.jpg -------------------------------------------------------------------------------- /html/help_transfer_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_transfer_02.jpg -------------------------------------------------------------------------------- /html/help_transfer_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_transfer_03.jpg -------------------------------------------------------------------------------- /html/help_useDegrees.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_useDegrees.jpg -------------------------------------------------------------------------------- /html/help_useDegrees_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_useDegrees_01.jpg -------------------------------------------------------------------------------- /html/help_useRadians.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_useRadians.jpg -------------------------------------------------------------------------------- /html/help_useRadians_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/help_useRadians_01.jpg -------------------------------------------------------------------------------- /html/helpsearch/_t.cfs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/helpsearch/_t.cfs -------------------------------------------------------------------------------- /html/helpsearch/deletable: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /html/helpsearch/segments: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/helpsearch/segments -------------------------------------------------------------------------------- /html/helptoc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | KML Toolbox 5 | Useful functions 6 | kml.run 7 | kml.save 8 | kml.viewKML 9 | kml.clear 10 | kml.createFolder 11 | kml.useDegrees 12 | kml.useRadians 13 | Icons alias for the markers 14 | 15 | Plotting functions 16 | kml.plot 17 | kml.plot3 18 | kml.point 19 | kml.text 20 | kml.scatter 21 | kml.scatter3 22 | kml.contour 23 | kml.contour3 24 | kml.poly 25 | kml.poly3 26 | kml.overlay 27 | kml.transfer 28 | kml.model 29 | kml.modelTour 30 | kml.quiver 31 | kml.quiver3d 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /html/info.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 14 4 | KML toolbox 5 | toolbox 6 | ./kmltoolbox.png 7 | ./ 8 | 9 | 10 | 11 | 12 | 13 | 14 | doc kml 15 | $toolbox/matlab/icons/book_mat.gif 16 | 17 | 18 | 19 | 20 | edit RunTests.m 21 | $toolbox/matlab/icons/demoicon.gif 22 | 23 | 24 | 25 | 26 | web http://www.mathworks.com/matlabcentral/fileexchange/34694-kml-toolbox-plot-anything-to-google-earth -browser; 27 | $toolbox/matlab/icons/webicon.gif 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /html/kml.clear.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml.clear

kml.clear

Clears the current kml file, removing any previous plots

Contents

Syntax

k = kml('kml title here');
 66 | --- any plot code here
 67 | k.clear;
 68 | --- new plot code here

Description

kml.clear will delete any plot inside the current kml object, leaving it empty for future use. It will not delete any temporary file created on disk, such as images, nor will remove any .kml file previously saved.

Example

% Create a new kml object
 69 | k = kml('my kml file');
 70 | 
 71 | % Plot a sample curve to the kml, and open it in Google Earth
 72 | t = linspace(0,360,1000);
 73 | k.plot(20*t, 30*cosd(t/2));
 74 | k.run;
 75 | 
 76 | % Clear the previous contents
 77 | k.clear;
 78 | 
 79 | % Plot a new curve there, and open the new contents in Google Earth
 80 | k.plot(30*t, 90*cosd(t/2));
 81 | k.run;
 82 | 
This is the first plot
 83 | 
This is the second plot after clearing the kml object
 84 | 

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.contents.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | Welcome to the KML Toolbox!

Welcome to the KML Toolbox!

 _  ____  __ _      _____         _ _
 66 | | |/ /  \/  | |    |_   _|__  ___| | |__  _____ __
 67 | | ' <| |\/| | |__    | |/ _ \/ _ \ | '_ \/ _ \ \ /
 68 | |_|\_\_|  |_|____|   |_|\___/\___/_|_.__/\___/_\_\

Contents

Thanks for downloading the KML toolbox!

For some cool examples on how to use the KML toolbox, please check the file RunTests.m located in the folder kmltoolbox\help

This class-based toolbox allows you to create many different plots in Google Earth, by automatically creating the required xml-based kml files without any complicated user interaction.

With it, you can create:

If you enjoy it, just drop me an email at <mailto:kml@rafael.aero kml@rafael.aero> saying for what you're using it :-)

To learn how to create an instance of the kml toolbox, check here first

Useful functions

kml.run

kml.save

kml.viewKML

kml.clear

kml.createFolder

kml.useDegrees

kml.useRadians

Icons alias for the markers

Plotting functions

kml.plot

kml.plot3

kml.point

kml.text

kml.scatter

kml.scatter3

kml.contour

kml.contour3

kml.poly

kml.poly3

kml.overlay

kml.transfer

kml.model

kml.modelTour

kml.quiver

kml.quiver3d

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.contour.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml.contour

kml.contour

Create a contour of altitude in a grid defined by longitude and latitude. Similar to the built-in contour function.

Contents

Syntax

kml.contour(long, lat, alt)
 66 | kml.contour(...,'PropertyName',PropertyValue,...)

Description

Creates a flat contour plot of altitude in a grid defined by longitude vs. latitude, similar to the built-in contour function.

The units for latitude and longitude are normally given in degrees, but this can be changed by calling: kml.useDegrees; or kml.useRadians; before plotting.

It is possible to fine tune the contour properties using name-value pairs:

kml.contour(...,'PropertyName',PropertyValue,...)

Properties

67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 |
Property NameTypeDescription
'name' string Name of the plot inside the kml file
'description' string A short description of what the plot represents
'visibility' true/false Control the initial visibility of the plot
'colorMap' string name of a valid colormap function Defines in which colormap the contour will be plotted. Example of valid inputs: 'jet', 'hsv', 'hot', 'cool', 'spring', 'summer', 'autumn', 'winter', 'gray', 'bone', 'copper', 'pink'
'numberOfLevels' double or 'auto' Defines number of levels in which the altitude input should be split into. Valid inputs are either the desired number of levels or 'auto'
'altitude' double Altitude where the 2D line should be plotted. Input in meters
'altitudeMode' string Choose if the altitude value is absolute to the earth model, relative to the ground level, or should be clamped to the ground. Valid inputs: 'absolute', 'relativeToGround', 'clampToGround'
'timeStamp' kml date string Associates the contour to a moment in time. Should not be used together with timeSpan. Should be a string in the XML time format (more information available here)
'timeSpanBegin' kml date string Defines the moment in time where the contour starts to exist. Should not be used together with timeStamp. Should be a string in the XML time format (more information available here)
'timeSpanEnd' kml date string Defines the moment in time where the contour finishes to exist. Should not be used together with timeStamp. Should be a string in the XML time format (more information available here)
80 |

Example

% Create a new kml object
 81 | k = kml('my kml file');
 82 | 
 83 | % Plot a sample 2D contour plot to the kml
 84 | [x,y,z] = peaks(200);
 85 | k.contour(180*x/3,90*y/3,z,'numberOfLevels',40);
 86 | 
 87 | % Save the kml and open it in Google Earth
 88 | k.run;
 89 | 
 90 | 
This is the result of running this example:
 91 | 

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.contour3.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml.contour3

kml.contour3

Create a 3D contour of altitude in a grid defined by longitude and latitude. Similar to the built-in contour3 function.

Contents

Syntax

kml.contour3(long, lat, alt)
 66 | kml.contour3(...,'PropertyName',PropertyValue,...)

Description

Creates a 3D contour plot of altitude in a grid defined by longitude vs. latitude, similar to the built-in contour3 function, in the sense that the contours are placed at their corresponding altitude level.

The units for latitude and longitude are normally given in degrees, but this can be changed by calling: kml.useDegrees; or kml.useRadians; before plotting. Altitude is always given in meters.

It is possible to fine tune the contour3 properties using name-value pairs:

kml.contour3(...,'PropertyName',PropertyValue,...)

Properties

67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
Property NameTypeDescription
'name' string Name of the plot inside the kml file
'description' string A short description of what the plot represents
'visibility' true/false Control the initial visibility of the plot
'colorMap' string name of a valid colormap function Defines in which colormap the contour will be plotted. Example of valid inputs: 'jet', 'hsv', 'hot', 'cool', 'spring', 'summer', 'autumn', 'winter', 'gray', 'bone', 'copper', 'pink'
'numberOfLevels' double or 'auto' Defines number of levels in which the altitude input should be split into. Valid inputs are either the desired number of levels or 'auto'
'altitudeMode' string Choose if the altitude value is absolute to the earth model, relative to the ground level, or should be clamped to the ground. Valid inputs: 'absolute', 'relativeToGround', 'clampToGround'
'timeStamp' kml date string Associates the contour to a moment in time. Should not be used together with timeSpan. Should be a string in the XML time format (more information available here)
'timeSpanBegin' kml date string Defines the moment in time where the contour starts to exist. Should not be used together with timeStamp. Should be a string in the XML time format (more information available here)
'timeSpanEnd' kml date string Defines the moment in time where the contour finishes to exist. Should not be used together with timeStamp. Should be a string in the XML time format (more information available here)
79 |

Example

% Create a new kml object
 80 | k = kml('my kml file');
 81 | 
 82 | % Plot a sample 3D contour plot to the kml
 83 | [x,y,z] = peaks(200);
 84 | k.contour3(180*x/3,90*y/3,1e5*z+1e4,'numberOfLevels',40,'altitudeMode','absolute');
 85 | 
 86 | % Save the kml and open it in Google Earth
 87 | k.run;
 88 | 
 89 | 
This is the result of running this example:
 90 | 

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.createFolder.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml.createFolder

kml.createFolder

Create a folder inside the current kml file

Contents

Syntax

k = kml('kml title here');
 66 | folder = k.createFolder('folder title here')
 67 | --- any plot code here, using e.g. folder.plot(...)
 68 | k.run;

Description

folder = kml.createFolder('title') creates a folder inside the current kml object. It is also possible to create nested folders, by using the same method in the folder object.

To plot inside a folder, simple use any available functions from the kml toolbox, as in:

folder.plot(...), folder.scatter(...), folder.model(...), etc...

Example

% Create a new kml object
 69 | k = kml('my kml file');
 70 | 
 71 | % Create some folders in the kml file
 72 | for i = 1:10
 73 |     mainFolder = k.createFolder(sprintf('Folder %i', i));
 74 |     for j = 1:10
 75 |         nestedFolder = mainFolder.createFolder(sprintf('Nested Folder %i', j));
 76 |     end
 77 | end
 78 | 
 79 | % Save the kml and open it in Google Earth
 80 | k.run;
 81 | 

This example creates a nested folder structure like this:

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml

kml

Creates an instance of the kml toolbox, providing access to all its functionality.

Contents

Syntax

k = kml('title');

Description

k = kml creates an instance of the kml toolbox, from which any of the available plots can be created. 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:

If you enjoy it, just drop me an email at kml@rafael.aero saying for what you're using it :).

Example

% Create a new kml object
 66 | k = kml('my kml file');
 67 | 
 68 | % Create a sample plot inside the kml
 69 | t = linspace(0,360,1000);
 70 | k.plot(30*t, 90*cosd(t/2));
 71 | 
 72 | % Save the kml and open it in Google Earth
 73 | k.run;
 74 | 
 75 | 
This is the result of running this example:
 76 | 

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.quiver3d.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml.quiver3d

kml.quiver3d

Creates a quiver plot using 3D arrows, in the coordinates defined by longitude, latitude and altitude, and arrow sizes given by the speeds u, v and w. Similar to the built-in quiver3 function.

Contents

Syntax

kml.quiver3d(longitude, latitude, altitude, u, v, w)
 66 | kml.quiver3d(...,'PropertyName',PropertyValue,...)

Description

Creates a quiver plot using 3D arrows, such as the one supplied with the toolbox (arrow2d.dae). The arrows are created in the coordinates defined by longitude, latitude and altitude, and are scaled using the speeds u, v and w, and the size of the grid.

It is possible to use a different arrow model with the property pair 'model', 'modelfile.dae'

The units for the angular values are normally given in degrees, but this can be changed by calling: kml.useDegrees; or kml.useRadians; before plotting. Altitude is always given in meters.

It is possible to fine tune the point properties using name-value pairs:

kml.quiver3d(...,'PropertyName',PropertyValue,...)

Properties

67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
Property NameTypeDescription
'model' string Path to a different 3D model file representing an arrow.
'name' string Name of the quiver plot inside the kml file
'description' string A short description of what the quiver plot represents
'visibility' true/false Control the initial visibility of the quiver plot
'scale' double Defines a scale factor to be applied to the whole quiver plot
'altitudeMode' string Choose if the altitude value is absolute to the earth model, relative to the ground level, or should be clamped to the ground. Valid inputs: 'absolute', 'relativeToGround', 'clampToGround'
'timeStamp' kml date string Associates the quiver plot to a moment in time. Should not be used together with timeSpan. Should be a string in the XML time format (more information available here)
'timeSpanBegin' kml date string Defines the moment in time where the quiver plot starts to exist. Should not be used together with timeStamp. Should be a string in the XML time format (more information available here)
'timeSpanEnd' kml date string Defines the moment in time where the quiver plot finishes to exist. Should not be used together with timeStamp. Should be a string in the XML time format (more information available here)
79 |

Example

% Create a new kml object
 80 | k = kml('my kml file');
 81 | 
 82 | % Create a sample quiver plot in the kml file
 83 | [x,y] = meshgrid(-2:.2:2,-1:.15:1);
 84 | z = x .* exp(-x.^2 - y.^2);
 85 | [px,py] = gradient(z,.2,.15);
 86 | 
 87 | k.quiver3d(10*x,10*y,1e5+x*0,1000*px,1000*py,-cosd(x)*1e2,'scale',1500)
 88 | 
 89 | % Save the kml and open it in Google Earth
 90 | k.run;
 91 | 
 92 | 
This is the result of running this example:
 93 | 

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.run.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml.run

kml.run

Save and run the current kml file, opening it in the default kml viewer.

Contents

Syntax

k = kml('kml title here');
 66 | --- any plot code here
 67 | k.run;

Description

kml.run will save the kml file and open it in the default kml viewer. Normally, this means it will open the file in Google Earth. It can be downloaded at http://earth.google.com

Example

% Create a new kml object
 68 | k = kml('my kml file');
 69 | 
 70 | % Create a sample plot inside the kml
 71 | t = linspace(0,360,1000);
 72 | k.plot(30*t, 90*cosd(t/2));
 73 | 
 74 | % Save the kml and open it in Google Earth
 75 | k.run;
 76 | 
 77 | 
This is the result of running this example:
 78 | 

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.text.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml.text

kml.text

Places text in the coordinates defined by longitude, latitude and altitude.

Contents

Syntax

kml.text(long, lat, alt, txt)
 66 | kml.text(...,'PropertyName',PropertyValue,...)

Description

Places text in the coordinates defined by the inputs longitude, latitude and altitude. To place more than one text, pass an array of coordinates, and a cell array of texts.

The units for latitude and longitude are normally given in degrees, but this can be changed by calling: kml.useDegrees; or kml.useRadians; before plotting. Altitude is always given in meters.

It is possible to fine tune the text properties using name-value pairs:

kml.text(...,'PropertyName',PropertyValue,...)

Properties

67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 |
Property NameTypeDescription
'name' string Name of the text plot inside the kml file
'id' string Internal id of this text plot inside the kml
'description' string A short description of what the text plot represents
'visibility' true/false Control the initial visibility of the text plot
'altitudeMode' string Choose if the altitude value is absolute to the earth model, relative to the ground level, or should be clamped to the ground. Valid inputs: 'absolute', 'relativeToGround', 'clampToGround'
'labelScale' double Defines the size of the text. Can be one input for all markers, or an array with the same size as Latitude and Longitude, with the size of each marker
'timeStamp' kml date string Associates the text plot to a moment in time. Should not be used together with timeSpan. Should be a string in the XML time format (more information available here)
'timeSpanBegin' kml date string Defines the moment in time where the text plot starts to exist. Should not be used together with timeStamp. Should be a string in the XML time format (more information available here)
'timeSpanEnd' kml date string Defines the moment in time where the text plot finishes to exist. Should not be used together with timeStamp. Should be a string in the XML time format (more information available here)
79 |

Example

% Create a new kml object
 80 | k = kml('my kml file');
 81 | 
 82 | % Places text labels for every 10° of latitude and longitude
 83 | f = k.createFolder('Coordinates');
 84 | for lat = -80:20:80
 85 |     for long = -180:20:170
 86 |         f.text(long,lat,1e5,sprintf('Lat %g° Long %g°',lat,long),'labelScale',3)
 87 |     end
 88 | end
 89 | 
 90 | % Save the kml and open it in Google Earth
 91 | k.run;
 92 | 
 93 | 
This is the result of running this example:
 94 | 

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.useDegrees.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml.useDegrees

kml.useDegrees

Switch the current kml object to accept angular inputs in degrees.

Contents

Syntax

kml.useDegrees;

Description

kml.useDegrees tells the current kml object to start accepting angular inputs in degrees, such as latitude, longitude, roll, heading and tilt. It must be used before any other plot, as it will not affect plots created before using kml.useDegrees

This is the default behavior.

Example

% Create a new kml object
 66 | k = kml('my kml file');
 67 | 
 68 | % Set Degrees as default unit
 69 | k.useDegrees;
 70 | 
 71 | % Plot a simple curve to the kml using degrees as inputs
 72 | t = linspace(0,360,1000);
 73 | k.plot(30*t, 90*cosd(t/2));
 74 | 
 75 | % Save the kml and open it in Google Earth
 76 | k.run;
 77 | 
 78 | 
This is the result of running this example:
 79 | 

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kml.useRadians.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | kml.useRadians

kml.useRadians

Switch the current kml object to accept angular inputs in radians.

Contents

Syntax

kml.useRadians;

Description

kml.useRadians tells the current kml object to start accepting angular inputs in radians, such as latitude, longitude, roll, heading and tilt. It must be used before any other plot, as it will not affect plots created before using kml.useRadians

Example

% Create a new kml object
 66 | k = kml('my kml file');
 67 | 
 68 | % Set Radians as default unit
 69 | k.useRadians;
 70 | 
 71 | % Plot a simple curve to the kml using radians as inputs
 72 | t = linspace(0,2*pi,1000);
 73 | k.plot(30*t, pi/2*cos(t/2));
 74 | 
 75 | % Save the kml and open it in Google Earth
 76 | k.run;
 77 | 
 78 | 
This is the result of running this example:
 79 | 

This file is part of the kml toolbox. Copyright 2012 Rafael Fernandes de Oliveira (rafael@rafael.aero)

-------------------------------------------------------------------------------- /html/kmldoc.m: -------------------------------------------------------------------------------- 1 | function kmldoc(topic) 2 | if nargin==0 || isempty(topic) 3 | topic = 'kml.contents'; 4 | end 5 | if length(topic) > 2 && ischar(topic) && strcmpi(topic(1:3),'kml') 6 | html = [topic '.html']; 7 | htmlFile = which(html); 8 | % Display the results. 9 | if isempty(htmlFile) 10 | error('"%s.html" not found, check the instalation of your KML toolbox.',topic); 11 | else 12 | web(htmlFile,'-helpbrowser'); 13 | end 14 | else 15 | doc(topic); 16 | end 17 | end -------------------------------------------------------------------------------- /html/kmltoolbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/kmltoolbox.png -------------------------------------------------------------------------------- /html/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/logo.png -------------------------------------------------------------------------------- /html/nestedFolders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/html/nestedFolders.png -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2014, Rafael Fernandes de Oliveira 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | * Neither the name of the copyright holder nor the names of its contributors 14 | may be used to endorse or promote products derived from this software 15 | without specific prior written permission. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 21 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 | POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /test/RunTestTour.m: -------------------------------------------------------------------------------- 1 | k = kml('Model Tour'); 2 | f = k.createFolder('Above'); 3 | t = linspace(0,4*pi,1000); 4 | long = cos(t)*20; 5 | lat = sin(t)*20; 6 | alt = 100000 + 0.*t; 7 | 8 | heading = 360-mod((t+pi)*180/pi,720); 9 | tilt = 0.*t; 10 | roll = 0.*t -20; 11 | f.modelTour(t*1,long,lat,alt,heading,tilt,roll,'model',fullfile(fileparts(mfilename('fullpath')),'A320.dae'),'scale',10000,'cameraMode','above','cameraDistance',1e7) 12 | 13 | f = k.createFolder('Behind'); 14 | f.modelTour(t,long,lat,alt,heading,tilt,roll,'model',fullfile(fileparts(mfilename('fullpath')),'A320.dae'),'scale',100,'cameraMode','behind','cameraDistance',1e5) 15 | 16 | k.run; -------------------------------------------------------------------------------- /test/RunTests.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/test/RunTests.m -------------------------------------------------------------------------------- /test/RunTestsRadians.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/test/RunTestsRadians.m -------------------------------------------------------------------------------- /test/bitslice.m: -------------------------------------------------------------------------------- 1 | function b = bitslice(a,lowbit,highbit) 2 | %BITSLICE(A,LOWBIT,HIGHBIT) 3 | 4 | numbits = highbit - lowbit + 1; 5 | b = bitshift(a,-lowbit); 6 | b = fix(b); 7 | b = bitand(b,bitcmp(0,numbits)); 8 | b = b/max(b(:)); -------------------------------------------------------------------------------- /test/cities.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/test/cities.mat -------------------------------------------------------------------------------- /test/logoFEx2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theolivenbaum/kml-toolbox/37e5b7a7bdcf8fff5eeb1820a7c43414318f92be/test/logoFEx2.png -------------------------------------------------------------------------------- /test/testAnim.m: -------------------------------------------------------------------------------- 1 | time = linspace(0,4*pi,1000); 2 | longitude = cos(time)*1; 3 | latitude = sin(time)*1; 4 | altitude = 1e3 + 0.*time; 5 | 6 | yaw = 360-mod((time)*180/pi,720); 7 | gamma = 0.*time; 8 | roll = 0.*time -20; 9 | 10 | k = kml('testAnimation'); 11 | k.useDegrees; 12 | 13 | N = numel(longitude); 14 | 15 | yaw = yaw - 180; %This is to correct the mis-orientation in the A320 model, you can ignore this for other models - or fix the model 16 | modelA320 = k.model(longitude(1),latitude(1),altitude(1),yaw(1),gamma(1),roll(1),'model','A320.dae','scale',10); 17 | anim = k.newAnimation('Flight'); 18 | 19 | time = time.*100; 20 | 21 | for i = 2:N 22 | dT = time(i) - time(i-1); 23 | anim.updateLocation(modelA320,dT,longitude(i),latitude(i),altitude(i)); 24 | anim.updateOrientation(modelA320,dT,yaw(i),gamma(i),roll(i)); 25 | 26 | anim.flyToLookAt(dT, longitude(i), latitude(i),1e4) 27 | end 28 | 29 | anim.flyToLookAt(10, mean(longitude),mean(latitude),1e5); 30 | 31 | k.run; 32 | --------------------------------------------------------------------------------