1 function openpilot2kml(matfile)
3 if ~exist('ge_colorbar', 'file')
4 msg=['Google Earth Toolbox must be present and included in the Matlab path. For example:'...
5 10 ' path(path, ''/Users/ponthy/googleearth'''];
10 [FileName,PathName] = uigetfile('*.mat');
11 matfile = strcat(PathName,FileName);
14 if ~exist(matfile, 'file')
15 error('Not a valid matlab file')
21 t=PositionActual.timestamp/1000;
23 NED=[PositionActual.North', PositionActual.East', PositionActual.Down'];
24 BaseECEF = LLA2ECEF([HomeLocation.Latitude*1e-7, HomeLocation.Longitude*1e-7, HomeLocation.Altitude]');
25 Rne = RneFromLLA([HomeLocation.Latitude*1e-7, HomeLocation.Longitude*1e-7, HomeLocation.Altitude]');
27 LLA=Base2LLA(NED',BaseECEF,Rne);
32 gpsSpeed=interp1(BaroAirspeed.timestamp/1000, BaroAirspeed.Airspeed, t);
35 [pathstr, opName] = fileparts(matfile);
37 kmlFileName=[opName '.kml'];
40 kmlFolderName=pathstr;
42 line_seg={}; %#ok<NASGU> %Clear line_seg
49 M=jet(round(maxSpeed));
51 line_seg=cell(round(length(gpsTime)*2),1);
53 %Create style for waypoints
54 line_seg{1}= ['<Style id="track"> <IconStyle> <scale>1.2</scale> <Icon> <href>http://earth.google.com/images/kml-icons/track-directional/track-none.png</href> </Icon> </IconStyle> </Style>' 10];
56 line_seg{2} = ge_colorbar(gpsPath(1,2), gpsPath(1,1), maxSpeed*(1-exp(log(1/2)/midSpeed*(0:maxSpeed))),...
57 'cBarBorderWidth',1,...
58 'cBarFormatStr','%+3.0f',...
59 'altitudeMode', 'clampToGround',...
61 'name','Speed colorbar');
63 %Add start and stop points
64 line_seg{3}=ge_point(gpsPath(1,2), gpsPath(1,1), gpsAlt(1), 'altitudeMode', 'clampToGround', 'name', 'Start');
65 line_seg{4}=ge_point(gpsPath(end,2), gpsPath(end,1), gpsAlt(end), 'altitudeMode', 'clampToGround', 'name', 'Stop');
68 %Add text progress output
70 str2=sprintf('Completed %3.0f%%', 0);
73 %Create line segments and color based on speed
74 for i=1:length(gpsTime)-1
78 Z=[gpsAlt(i) gpsAlt(i)];
79 logSpeed=maxSpeed*(1-exp(log(1/2)/midSpeed*gpsSpeed(i)));
81 red=round(M(floor(min(logSpeed+1, length(M))),1)*255);
82 green=round(M(floor(min(logSpeed+1, length(M))),2)*255);
83 blue=round(M(floor(min(logSpeed+1, length(M))),3)*255);
85 tmpHour=floor(t(i)/3600);
86 tmpMinute=floor((t(i)-tmpHour*3600)/60);
87 tmpSec=t(i)-tmpHour*3600-tmpMinute*60;
88 tGPS=[2012 06 23 tmpHour tmpMinute tmpSec];
89 tStart = datestr( tGPS, 'yyyy-mm-ddTHH:MM:SSZ');
90 tStop = datestr( tGPS+[0 0 0 0 0 2], 'yyyy-mm-ddTHH:MM:SSZ'); %Visible for two seconds
92 [line_seg{i+k}]= ge_plot3(X,Y,Z,...
93 'altitudeMode', 'absolute',...
94 'timeSpanStart',tStart,...
95 'timeSpanStop',tStop,...
97 'lineColor', [ 'ff' dec2hex(red, 2) dec2hex(green, 2) dec2hex(blue, 2)], ...
98 'forceAsLine', false, ...
99 'msgToScreen', false);
106 descriptionCell={'North coords., in [m]', num2str(NED(i,1), '%10.2f');
107 'East coords., in [m]', num2str(NED(i,2), '%10.2f');
108 'Height AGL, in [m]', num2str(Z(1), '%10.2f') ;
109 'Airspeed, in [km/hr]', num2str(gpsSpeed(i)*3.6, '%3.1f')};
111 [line_seg{i+k}]=ge_point(X(1), Y(1), gpsAlt(i),...
112 'altitudeMode', 'absolute',...
114 'name', num2str(t(i)-t(1)),...
115 'timeSpanStart',tStart,...
116 'timeSpanStop',tStop,...
117 'styleURL', '#track',...
118 'iconURL', 'http://earth.google.com/images/kml-icons/track-directional/track-none.png',...
119 'pointDataCell', descriptionCell);
123 for j=1:length(str2)+1;
124 str1=[str1 sprintf('\b')]; %#ok<AGROW>
126 str2=['Completed ' num2str(i/length(t)*100, '%3.0f')];
128 fprintf([str1 str2 '%%']);
134 line_seg=line_seg(1:i+k);
137 %Properly formats XML part of kml file. IS TOO SLOW!
139 Pref.StructItem = false;
140 Pref.XmlEngine = 'String'; %Forces xml_write to use Apache XML engine instead of Matlab XML.
142 [a,r]=xml_write([], plot_xml, 'b', Pref);
143 indexFirst=find(r==10, 2);
144 indexLast=find(r==10, 1, 'last');
146 r=r(indexFirst(2)+1:indexLast);
148 [a,s]=xml_write([], point_xml, 'b', Pref);
149 indexFirst=find(s==10, 2);
150 indexLast=find(s==10, 1, 'last');
152 s=s(indexFirst(2)+1:indexLast);
154 ge_output(kmlFileName, [line_seg{1} r s], 'name', kmlFolderName, 'msgToScreen', true)
157 %Output segments to kml files
158 ge_output(fullfile(kmlFolderName, kmlFileName), cat(2,line_seg{:}), 'name', opName, 'msgToScreen', true);
163 % ===========================
166 function NED = LLA2Base(LLA,BaseECEF,Rne)
169 ECEF = LLA2ECEF(LLA);
171 diff = ECEF - repmat(BaseECEF,1,n);
176 function LLA = Base2LLA(NED,BaseECEF,Rne)
180 ECEF=diff + repmat(BaseECEF,1,n) ;
182 LLA=zeros(size(NED));
184 LLA(:,i)=ECEF2LLA(ECEF(:,i))';
189 % ****** convert ECEF to Lat,Lon,Alt (ITERATIVE!) *********
190 function LLA=ECEF2LLA(ECEF, Alt)
191 % Altitude parameter is used to prime the iteration.
192 % A position within 1 meter of the specified LLA
193 % will be calculated within at most 3 iterations.
194 % If unknown: Call with any valid altitude
195 % will compute within at most 5 iterations.
203 a = 6378137.0; % Equatorial Radius
204 e = 8.1819190842622e-2; % Eccentricity
209 MAX_ITER =10; % should not take more than 5 for valid coordinates
210 ACCURACY= 1.0e-11; % used to be e-14, but we don't need sub micrometer exact calculations
214 LLA(2) = RAD2DEG * atan2(y, x);
215 Lat = DEG2RAD * LLA(1);
216 esLat = e * sin(Lat);
217 N = a / sqrt(1 - esLat * esLat);
222 while (((delta > ACCURACY) || (delta < -ACCURACY)) && (iter < MAX_ITER))
223 delta = Lat - atan(z / (sqrt(x * x + y * y) * (1 - (N * e * e / NplusH))));
225 esLat = e * sin(Lat);
226 N = a / sqrt(1 - esLat * esLat);
227 NplusH = sqrt(x * x + y * y) / cos(Lat);
231 LLA(1) = RAD2DEG * Lat;
237 function ECEF = LLA2ECEF(LLA)
239 a = 6378137.0; % Equatorial Radius
240 e = 8.1819190842622e-2; % Eccentricity
246 sinLat = sin(pi*LLA(1,i)/180);
247 sinLon = sin(pi*LLA(2,i)/180);
248 cosLat = cos(pi*LLA(1,i)/180);
249 cosLon = cos(pi*LLA(2,i)/180);
251 N = a / sqrt(1.0 - e * e * sinLat * sinLat); %prime vertical radius of curvature
253 ECEF(1,i) = (N + LLA(3,i)) * cosLat * cosLon;
254 ECEF(2,i) = (N + LLA(3,i)) * cosLat * sinLon;
255 ECEF(3,i) = ((1 - e * e) * N + LLA(3,i)) * sinLat;
259 % ****** find ECEF to NED rotation matrix ********
260 function Rne=RneFromLLA(LLA)
264 sinLat = sin(DEG2RAD * LLA(1));
265 sinLon = sin(DEG2RAD * LLA(2));
266 cosLat = cos(DEG2RAD * LLA(1));
267 cosLon = cos(DEG2RAD * LLA(2));
269 Rne(1,1) = -sinLat * cosLon;
270 Rne(1,2) = -sinLat * sinLon;
275 Rne(3,1) = -cosLat * cosLon;
276 Rne(3,2) = -cosLat * sinLon;