### Existing Rectangle Class Structure
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/Xamarin/GDALForAndroid/Additions/AboutAdditions.txt
This is an example of a generated C# class with an existing constructor. Custom additions should be made in separate partial class files.
```csharp
public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}
```
--------------------------------
### Coloring Icons with CSS
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/css/open-iconic/README.md
Set the fill rule on the specific icon's use tag to change its color. This example targets the account-login icon.
```css
.icon-account-login {
fill: #f00;
}
```
--------------------------------
### Vertex Shader for Transformations and Lighting Setup
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/iris.txt
This vertex shader transforms vertex positions and normals, sets up texture coordinates, and calculates light direction. It applies model-view and projection matrices.
```glsl
precision highp float;
attribute vec3 a_position;
attribute vec3 a_normal;
varying vec3 v_normal;
uniform mat3 u_normalMatrix;
uniform mat4 u_modelViewMatrix;
uniform mat4 u_projectionMatrix;
attribute vec2 a_texcoord0;
varying vec2 v_texcoord0;
varying vec3 v_light0Direction;
varying vec3 v_position;
uniform mat4 u_light0Transform;
void main(void) {
vec4 pos = u_modelViewMatrix * vec4(a_position,1.0);
v_normal = u_normalMatrix * a_normal;
v_texcoord0 = a_texcoord0;
v_position = pos.xyz;
v_light0Direction = mat3(u_light0Transform) * vec3(0.,0.,1.);
gl_Position = u_projectionMatrix * pos;
}
```
--------------------------------
### Initialize Smoothie Chart
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
Initializes a SmoothieChart for real-time data visualization on a canvas element with the ID 'graphcanvas'. It sets up two TimeSeries for 'roll' and 'pitch' data and starts drawing the chart. Requires the SmoothieChart library.
```javascript
function startChart() {
var smoothie = new SmoothieChart();
smoothie.streamTo(document.getElementById("graphcanvas"), 250);
// Data
line1 = new TimeSeries();
line2 = new TimeSeries();
// Add to SmoothieChart
smoothie.addTimeSeries(line1);
smoothie.addTimeSeries(line2);
drawChart();
}
```
--------------------------------
### Add Constructor to Generated Rectangle Class
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/UsbSerialForAndroid/Additions/AboutAdditions.txt
Extend a generated partial class by adding a new constructor. This example shows how to add a constructor that accepts Point and Size objects, delegating to the existing int-based constructor.
```csharp
public partial class Rectangle
{
public Rectangle (int x, int y, int width, int height)
{
// JNI bindings
}
}
```
```csharp
public partial class Rectangle
{
public Rectangle (Point location, Size size) :
this (location.X, location.Y, size.Width, size.Height)
{
}
}
```
--------------------------------
### Initialize Bootloader and Progress Indicator
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
This snippet initializes a bootloader that displays loading progress from 0% to 100% and then calls a bootSequence function. It relies on the window.performance.timing API and DOM elements with IDs 'Progress-report' and 'Loading-text'.
```javascript
(function bootLoader() {
var perf = window.performance.timing,
el = document.getElementById('Progress-report'),
progress = 0,
timer = setInterval(function () {
el.innerText = ++progress + '%';
if (progress >= 100) {
clearInterval(timer);
bootSequence();
}
}, Math.abs(Math.floor(((perf.loadEventEnd - perf.navigationStart) / 1e3) % 60)));
function bootSequence() {
if (window['MONO'] && MONO.mono_wasm_runtime_is_ready) return;
document.getElementById('Loading-text').style.display = 'none';
el.innerText = 'Initializing';
var bootWatch = setInterval(function () {
if (assemblyReferences == null || assemblyReferences.length == 0 || !window['MONO']) return;
el.innerText = 'Booting';
if (!MONO.loaded_files) return;
el.innerText = 'Fetching ' + MONO.loaded_files.length + '/' + assemblyReferences.length;
if (assemblyReferences.length === MONO.loaded_files.length) {
el.innerText = 'Rendering';
clearInterval(bootWatch);
}
}, 50);
}
})();
```
--------------------------------
### Get Camera Pick Ray and Position
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
Captures mouse movement to get the camera's pick ray and the intersected position on the globe. Converts the position to cartographic coordinates and displays altitude.
```javascript
var ray = viewer.camera.getPickRay(movement.endPosition); var position = viewer.scene.globe.pick(ray, viewer.scene); if (Cesium.defined(position)) { // convert position to cartographic and display altitude } //or try to get the height value, result is very low value or zero var coords = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6) + ', ' + Cesium.Math.toDegrees(cartographic.latitude).toFixed(6) + '; Height: ' + cartographic.height; document.getElementById('coords').innerHTML = '
' + coords + ' ';
```
--------------------------------
### Intercept XMLHttpRequest.open
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
This snippet intercepts the XMLHttpRequest.prototype.open method to log arguments. It requires no specific setup beyond its inclusion in the script.
```javascript
(function () {
var proxied = window.XMLHttpRequest.prototype.open;
window.XMLHttpRequest.prototype.open = function () {
console.log(arguments);
return proxied.apply(this, [].slice.call(arguments));
};
})();
```
--------------------------------
### Initialize WebSocket and Data Streams
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/Xamarin/Xamarin/Resources/hud.html
Sets up WebSocket connections for real-time telemetry data and initializes SmoothieCharts for plotting. Handles connection status, message parsing, and data appending.
```javascript
var deg2rad = Math.PI / 180; var rad2deg = 180 / Math.PI; var pitch =70; var roll =20; var yaw = 200; var jsoncount=0; var markers = []; var wpmarkers = []; var flightPath; var pathHistoryPoly; var pathHistory = []; var socket; var socket2; var line1item = "cs.altasl"; var line2item = "cs.ter_alt"; function graphitem(item) { line1item = "cs."+item; } function init() { var smoothie = new SmoothieChart(); smoothie.streamTo(document.getElementById("graphcanvas"),250); // Data var line1 = new TimeSeries(); var line2 = new TimeSeries(); // Add to SmoothieChart smoothie.addTimeSeries(line1); smoothie.addTimeSeries(line2); if (window["WebSocket"]) { var host = "ws://"+window.location.hostname+":56781/websocket/server"; if(window.location.hostname == "") host = "ws://localhost:56781/websocket/server"; try{ socket = new WebSocket(host); window.onbeforeunload = function(){ socket.close(); socket2.close(); } //log('WebSocket - status '+socket.readyState); socket.onopen = function(msg){ document.getElementById("serverStatus").innerHTML = "onopen"; jsoncount=0; }; socket.onmessage = function(msg){ jsoncount++; var data = JSON.parse(msg.data); if(data.hasOwnProperty('FrameString')) { MAV = data; } else if(data.hasOwnProperty('rateattitude')) { cs = data; var status = "
"; a=1; var sortable = []; for (i in cs) { sortable.push(i); } sortable.sort(function (a, b) { return a.toLowerCase().localeCompare(b.toLowerCase()); }); for (i in sortable) { var name = sortable[i]; var data = cs[sortable[i]]; if(typeof data != 'object') status += "
" + name + ": " + data + "
"; //if(a%3==0) //status += " "; a++; } status+="
"; document.getElementById("serverStatus").innerHTML = status; map.setCenter({lat: cs.lat, lng: cs.lng}); if(jsoncount < 5) { map.setZoom(18); } roll = cs.roll; pitch = cs.pitch; yaw = cs.yaw; lat = cs.lat; lng = cs.lng; alt = cs.alt; try { var myLatLng = {lat: lat, lng: lng}; if(markers.length > 0) { markers[0].setPosition(myLatLng); } else { var marker = new google.maps.Marker({ position: myLatLng, map: map, title: 'ArduPilot' }); markers.push(marker); } map.setOptions({maxZoom: 21}); //socket.send("test "+pitch+"\n"); } catch (ex){ }// alert(ex); } line1.append(new Date().getTime(), eval(line1item)); line2.append(new Date().getTime(), eval(line2item)); addData(); pathHistory.push({lat: lat, lng: lng}); pathHistory = pathHistory.slice(-200,200); if(pathHistoryPoly == null) { pathHistoryPoly = new google.maps.Polyline({ path: pathHistory, geodesic: true, strokeColor: '#191970', strokeOpacity: 0.56, strokeWeight: 4 }); pathHistoryPoly.setMap(map); } else { pathHistoryPoly.setPath(pathHistory); } } else if(data[0].hasOwnProperty('mission_type')) { wps = data; var wpscoords = []; for (i in wps) { if (wps[i].x != 0 && wps[i].y != 0) { wpscoords.push({lat: wps[i].x, lng: wps[i].y, alt: wps[i].z, frame: wps[i].frame, label: wps[i].seq }); } } if(wpmarkers.length == wpscoords.length) { i=0; wpmarkers.forEach(function(element) { element.setPosition(wpscoords[i]); i++; }); } else { wpmarkers.forEach(function(element) {element.setMap(null)}); wpmarkers = []; // Create markers. wpscoords.forEach(function(feature) { var marker = new google.maps.Marker({ position: feature, icon: 'https://maps.gstatic.com/mapfiles/ms2/micons/green.png', map: map, label: (feature.label == 0) ? "Home" : feature.label+"", draggable:true, title: (feature.label == 0) ? "Home" : feature.label+"" }); wpmarkers.push(marker); google.maps.event.addListener(marker, 'dragend', function (event) { document.getElementById("latbox").value = event.latLng.lat(); document.getElementById("lngbox").value = event.latLng.lng(); }); }); } var pnts = []; wpscoords.forEach(function(feature) { pnts.push(feature.lng); pnts.push(feature.lat); pnts.push(feature.alt + cs.HomeAlt); }); if (typeof viewer !== 'undefined') { var orangeOutlined = viewer.entities.add({ name : 'Orange line with black outline at height and following the surface', polyline : { positions : Cesium.Cartesian3.fromDegreesArrayHeights(pnts), width : 4, material : new Cesium.PolylineOutlineMaterialProperty({ color : Cesium.Color.ORANGE, outlineWidth : 2, outlineColor : Cesium.Color.BLACK }) } }); //orangeOutlined.position = Cesium.Cartesian3.fromDegrees(lng, lat); //viewer.trackedEntity = orangeOutlined; } if(flightPath == null) { flightPath = new google.maps.Polyline({ path: wpscoords, geodesic: true, strokeColor: '#FFFF00', strokeOpacity: 1.0, strokeWeight: 4 }); flightPath.setMap(map); } else { flightPath.setPath(wpscoords); } } else { return; } }; socket.onerror = function(msg){ document.getElementById("serverStatus").innerHTML = "Error: "+msg.data; }; socket.onclose = function(msg){ document.getElementById("serverStatus").innerHTML = "Disconnected - status "+this.readyState; setTimeo
```
--------------------------------
### Initialize Blazor Extensions Context Manager
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
Initializes the BlazorExtensions object in the window, providing context managers for 2D and WebGL rendering contexts.
```javascript
var i; !function (t) { const e = "BlazorExtensions", n = { Canvas2d: new r.ContextManager("2d"), WebGL: new r.ContextManager("webgl") }; t.initialize = function () { "undefined" == typeof window || window[e] ? window[e] = Object.assign({}, window[e], n) : window[e] = Object.assign({}, n) } }(i || (i = {})), i.initialize()
```
--------------------------------
### Initialize WebSocket Connection
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
Initializes a WebSocket connection to a specified host. If the host is empty, it defaults to 'ws://localhost:56781/websocket/raw'. It includes handlers for opening, closing, and receiving messages, and attempts to find .NET methods for processing packets. Requires the Blazor platform to be available.
```javascript
function initWebSocket(host) {
if (window["WebSocket"]) {
//var host = "ws://" + window.location.hostname + ":56781/websocket/raw";
if (host == "") host = "ws://localhost:56781/websocket/raw";
try {
try {
if (!(socket === null)) socket.close();
} catch (exception) {
if (window.console) console.log(exception);
}
var blobToBase64 = function (blob, cb) {
var reader = new FileReader();
reader.onload = function () {
var dataUrl = reader.result;
var base64 = dataUrl.split(',')[1];
cb(base64);
};
reader.readAsArrayBuffer(blob);
};
try {
dotNetDispatcherInvokeMethodHandle = Blazor.platform.findMethod( 'wasm', 'wasm.Pages', 'Websocket', 'ProcessPacketStatic');
dotNetDispatcherInvokeMethodHandle2 = Blazor.platform.findMethod( 'wasm', 'wasm.Pages', 'Websocket', 'ProcessPacketStaticBytes' );
} catch (err) {
return;
}
socket = new WebSocket(host);
window.onbeforeunload = function () {
socket.close();
};
console.log('WebSocket - status ' + socket.readyState);
socket.onopen = function (msg) {
};
socket.onmessage = function (msg) {
var arrayBuffer;
var fileReader = new FileReader();
fileReader.onload = function (r) {
arrayBuffer = r.target.result;
// dont want to overflow buffer
if (arrayBuffer.byteLength >= 1024) return;
var dotNetBuffer = {
toUint8Array: function () {
return Blazor.platform.toUint8Array(dotNetArrayPtr);
}
};
var dotNetBufferView = dotNetBuffer.toUint8Array();
dotNetBufferView.set(new Uint8Array(arrayBuffer));
result = Blazor.platform.callMethod(dotNetDispatcherInvokeMethodHandle2, null, ['' + arrayBuffer.byteLength]);
//thingo = Blazor.platform.toDotNetString(msg.data);
//result = Blazor.platform.callMethod(dotNetDispatcherInvokeMethodHandle,null,[thingo]);
};
fileReader.readAsArrayBuffer(msg.data);
};
} catch (exception) {
if (window.console) console.log(exception);
}
}
}
```
--------------------------------
### Save DotNet Object Reference
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
A simple function to save a DotNet helper object reference to a global variable `dotNetObjectRef`. No specific setup is required.
```javascript
function dotNetObjectRefSave(dotnetHelper) {
dotNetObjectRef = dotnetHelper;
}
```
--------------------------------
### Establish WebSocket Connection
Source: https://github.com/ardupilot/missionplanner/blob/master/hud.html
Establishes a WebSocket connection to a server for real-time data. Includes handlers for connection status, message reception, and errors.
```javascript
function runMain() {
//################################################
try {
var host = "ws://" + window.location.hostname + ":56781/websocket/raw";
if (window.location.hostname == "") host = "ws://localhost:56781/websocket/raw";
socket2 = new WebSocket(host);
//log('WebSocket - status '+socket.readyState);
socket2.onopen = function (msg) {
document.getElementById("serverStatus").innerHTML = "onopen";
};
socket2.onmessage = function (msg) {
var reader = new FileReader();
reader.addEventListener("loadend", function () {
var m = new MAVLink();
var buf = Buffer.from(this.result);
var msg2 = m.parseBuffer(buf);
//var packet = new asm.MAVLink_MAVLinkMessage(new Uint8Array(this.result));
document.getElementById("message").innerHTML = msg2[0].name + '';
});
reader.readAsArrayBuffer(msg.data);
};
socket2.onerror = function (msg) {
document.getElementById("serverStatus").innerHTML = "Error: " + msg.data;
};
socket2.onclose = function (msg) {
document.getElementById("serverStatus").innerHTML = "Disconnected - status " + this.readyState;
setTimeout("runMain()", 1000);
};
} catch (ex) {
if (window.console) console.log(exception);
document.getElementById("serverStatus").innerHTML = ex;
}
//############################################################
//var test = new asm.MAVLink();
//var test2 = new asm.MAVLink_MAVLinkMessage();
//var parse = new asm.MAVLink_MavlinkParse();
}
```
--------------------------------
### Draw Ellipse on Canvas
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/Xamarin/Xamarin/Resources/hud.html
Draws an ellipse on the HTML5 canvas. Requires the canvas context, color, line width, starting coordinates (x1, y1), and the width and height of the ellipse.
```javascript
function DrawEllipse(ctx,color,linewidth,x1,y1,width,height) {
ctx.lineWidth = linewidth;
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(x1 + width / 2,y1 + height);
var x, y;
for (var i = 0; i <= 360; i += 1) {
x = Math.sin(i * deg2rad) * width / 2;
y = Math.cos(i * deg2rad) * height / 2;
x = x + x1 + width / 2;
y = y + y1 + height / 2;
ctx.lineTo(x,y);
}
//ctx.moveTo(x1,y1);
ctx.stroke();
ctx.closePath();
}
```
--------------------------------
### Establish WebSocket Connection
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/Xamarin/Xamarin/Resources/hud.html
Establishes a WebSocket connection to a server for real-time data streaming. Handles connection events and message parsing.
```javascript
function runMain() {
//################################################
try {
var host = "ws://" + window.location.hostname + ":56781/websocket/raw";
if (window.location.hostname == "") host = "ws://localhost:56781/websocket/raw";
socket2 = new WebSocket(host);
//log('WebSocket - status '+socket.readyState);
socket2.onopen = function (msg) {
document.getElementById("serverStatus").innerHTML = "onopen";
};
socket2.onmessage = function (msg) {
var reader = new FileReader();
reader.addEventListener("loadend", function () {
var m = new MAVLink();
var buf = Buffer.from(this.result);
var msg2 = m.parseBuffer(buf);
//var packet = new asm.MAVLink_MAVLinkMessage(new Uint8Array(this.result));
document.getElementById("message").innerHTML = msg2[0].name + '';
});
reader.readAsArrayBuffer(msg.data);
};
socket2.onerror = function (msg) {
document.getElementById("serverStatus").innerHTML = "Error: " + msg.data;
};
socket2.onclose = function (msg) {
document.getElementById("serverStatus").innerHTML = "Disconnected - status " + this.readyState;
setTimeout("runMain()", 1000);
};
} catch (ex) {
if (window.console) console.log(exception);
document.getElementById("serverStatus").innerHTML = ex;
}
//############################################################
}
```
--------------------------------
### Draw Line on Canvas
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/Xamarin/Xamarin/Resources/hud.html
Draws a straight line on the HTML5 canvas. Requires the canvas context, color, line width, and the start (x1, y1) and end (x2, y2) coordinates.
```javascript
function DrawLine(ctx,color,width,x1,y1,x2,y2) {
ctx.lineWidth = width;
ctx.strokeStyle = color;
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
ctx.closePath();
}
```
--------------------------------
### Initialize WebSocket Connection
Source: https://github.com/ardupilot/missionplanner/blob/master/hud.html
Initializes a WebSocket connection for server communication. Handles connection success and failure, updating the server status display. Requires a browser supporting WebSockets.
```javascript
function init() {
var host = "ws://" + window.location.host + "/uploader";
try {
websocket = new WebSocket(host);
websocket.onopen = function(event) {
if (event.data === undefined)
return;
console.log("onopen event, data: " + event.data);
};
websocket.onmessage = function(event) {
console.log("onmessage event, data: " + event.data);
};
websocket.onclose = function(event) {
console.log("onclose event, data: " + event.data);
document.getElementById("serverStatus").innerHTML = "Connection Closed";
};
websocket.onerror = function(event) {
console.log("onerror event, data: " + event.data);
document.getElementById("serverStatus").innerHTML = event.data;
};
setTimeout ( "init()", 1000 ); }; } catch(ex){ if (window.console) console.log(exception); document.getElementById("serverStatus").innerHTML = ex; } } else { document.getElementById("serverStatus").innerHTML = "This browser doesnt support websockets"; }
```
--------------------------------
### Apply Theme to Controls
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/Controls/readme.txt
Subscribe to theme application events to ensure controls are themed correctly. This is typically done during application initialization.
```C#
Controls.MainSwitcher.ApplyTheme += MissionPlanner.Utilities.ThemeManager.ApplyThemeTo;
MissionPlanner.Controls.InputBox.ApplyTheme += MissionPlanner.Utilities.ThemeManager.ApplyThemeTo;
```
--------------------------------
### ContextManager Class for Canvas and WebGL
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
Manages rendering contexts (2D and WebGL) for HTML canvas elements. It provides methods to add, remove, set properties, get properties, and call functions on these contexts.
```javascript
e.ContextManager = class { constructor(t) { if (this.contexts = new Map, this.webGLObject = new Array, this.webGLContext = !1, this.webGLTypes = [WebGLBuffer, WebGLShader, WebGLProgram, WebGLFramebuffer, WebGLRenderbuffer, WebGLTexture, WebGLUniformLocation], this.add = ((t, e) => { if (!t) throw new Error("Invalid canvas."); if (!this.contexts.get(t.id)) { var n; if (!(n = e ? t.getContext(this.contextName, e) : t.getContext(this.contextName))) throw new Error("Invalid context."); this.contexts.set(t.id, n) } }), this.remove = (t => { this.contexts.delete(t.id) }), this.setProperty = ((t, e, n) => { const r = this.getContext(t); this.setPropertyWithContext(r, e, n) }), this.getProperty = ((t, e) => { const n = this.getContext(t); return this.serialize(n[e]) }), this.call = ((t, e, n) => { const r = this.getContext(t); return this.callWithContext(r, e, n) }), this.callBatch = ((t, e) => { const n = this.getContext(t); for (let t = 0; t < e.length; t++) { let r = e[t].slice(2); e[t][1] ? this.callWithContext(n, e[t][0], r) : this.setPropertyWithContext(n, e[t][0], Array.isArray(r) && r.length > 0 ? r[0] : null) } }), this.callWithContext = ((t, e, n) => this.serialize(this.prototypes[e].apply(t, void 0 != n ? n.map(t => this.deserialize(e, t)) : []))), this.setPropertyWithContext = ((t, e, n) => { t[e] = this.deserialize(e, n) }), this.getContext = (t => { if (!t) throw new Error("Invalid canvas."); const e = this.contexts.get(t.id); if (!e) throw new Error("Invalid context."); return e }), this.deserialize = ((t, e) => { if (!this.we
```
--------------------------------
### Initialize Google Map
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/Xamarin/Xamarin/Resources/hud.html
Initializes a Google Maps instance with satellite view. This is used for displaying map data.
```javascript
var map;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
center: { lat: -35, lng: 117.89 },
zoom: 8,
mapTypeId: 'satellite',
maxZoom: 21
});
map.setMapTypeId('satellite');
}
```
--------------------------------
### Set Drone Position and Update Map/Cesium
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
Updates the position of a drone marker on a Google Map and its corresponding entity in a Cesium viewer. It handles initial setup, including terrain sampling for altitude, and creates new entities or updates existing ones.
```javascript
function setPosition(sysid, compid, lat, lng, altasl, roll, pitch, yaw) { if (lat == 0 || lng == 0 || altasl == 0) return; if (first == 0 && altasl != 0) { var takeoff_position = [Cesium.Cartographic.fromDegrees( lng, lat )]; takeoff_altitude = altasl; if (viewer) { var promise = Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, takeoff_position); Cesium.when(promise, function (updatedPositions) { ground_offset = takeoff_position[0].height - takeoff_altitude; console.log('Ground Offset in meters: ' + ground_offset); // re-compute the positions taking the ground offset into account. // add 2 meters more to allow for inaccuracies //var positionProperty = computePositionProperty(ground_offset + 2); //entity.position = positionProperty; }); first++; } } // set the index map if (indextosysidcompid.get(sysid * 256 + compid) == undefined) indextosysidcompid.set(sysid * 256 + compid, indextosysidcompid.size || 0); var mavno = indextosysidcompid.get(sysid * 256 + compid); var myLatLng = { lat: lat, lng: lng }; if (markers.length >= (mavno + 1)) { markers[mavno].setPosition(myLatLng); //markers[mavno].icon.url = RotateIcon.makeIcon("images/drone-icon-1.jpg").setRotation({ deg: yaw }).getUrl(); markers[mavno].icon.rotation = yaw; if (map != markers[mavno].map) markers[mavno].setMap(map); } else { var marker = new google.maps.Marker({ position: myLatLng, map: map, title: 'ArduPilot ' + sysid, icon: { url: 'images/drone-icon-1.jpg', scaledSize: new google.maps.Size(50, 50), // scaled size origin: new google.maps.Point(0,0), // origin anchor: new google.maps.Point(25, 25), // anchor rotation: yaw } }); markers.push(marker); } if (mavno === 0) { if (map.zoom < 2) { map.setCenter({ lat: lat, lng: lng }); map.setZoom(16); //viewer.camera.zoomTo(Cesium.Cartesian3.fromDegrees(lng, lat, altasl)); } } if (viewer) { var position = Cesium.Cartesian3.fromDegrees(myLatLng.lng, myLatLng.lat, altasl); var hpr = new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(yaw - 90), Cesium.Math.toRadians(pitch), Cesium.Math.toRadians(roll)); var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr); if (viewer.entities.values.length >= (mavno + 1)) { viewer.entities.values[mavno].position = position; viewer.entities.values[mavno].orientation = orientation; // add a trail viewer.entities.getById('path').position.addSample(Cesium.JulianDate.now(), position); } else { var pinBuilder = new Cesium.PinBuilder(); // add a new one var entity = viewer.entities.add({ name: 'ArduPilot ' + sysid, id: 'ArduPilot ' + sysid, position: position, orientation: orientation, billboard: { image: pinBuilder.fromText(sysid, Cesium.Color.BLACK, 48) .toDataURL(), verticalOrigin: Cesium.VerticalOrigin.BOTTOM }, model: { uri: 'iris.txt', minimumPixelSize: 64, scale: default_model_scale * model_scale_factor } }); var pathPosition = new Cesium.SampledPositionProperty(); var entityPath = viewer.entities.add({ position : pathPosition, name: 'path', id: 'path', path : { show : true, leadTime : 0, trailTime : 60, width : 10, resolution : 1, material : new Cesium.PolylineGlowMaterialProperty({ glowPower : 0.3, taperPower : 0.3, color : Cesium.Color.PALEGOLDENROD }) } }); } if (viewer.trackedEntity == undefined) { viewer.scene.camera.lookAt(position, new Cesium.Cartesian3(30, 0, 10)); //viewer.flyTo(position).then(function(){ viewer.trackedEntity = viewer.entities.values[0]; //}); } } }
```
--------------------------------
### Image Generated On The Fly
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/ZedGraph/Revision_History.txt
This comment notes a fix for images generated on the fly, which now also send an HTML IMG tag. This likely improves how images are displayed in web contexts.
```csharp
// minor bug fix: image generated on the fly also sends HTML IMG tag
```
--------------------------------
### Vertex Shader for Position and Normal Transformation
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/Cesium_Air.txt
This vertex shader processes vertex positions and normals. It's a basic setup that declares attributes for position and varying variables for normal and texture coordinates to be passed to the fragment shader. Ensure 'a_position' attribute is provided.
```glsl
precision highp float;
attribute vec3 a_position;
```
--------------------------------
### Using Open Iconic with Foundation Classes
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/css/open-iconic/README.md
Apply icons using the 'fi-icon-name' class when using the Foundation stylesheet. Include title and aria-hidden attributes.
```html
```
--------------------------------
### Fragment Shader for Phong Lighting
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/iris.txt
Implements Phong lighting model for fragment shading. Calculates diffuse, specular, and emission components. Requires uniform variables for colors, shininess, and light direction.
```glsl
precision highp float;
varying vec3 v_normal;
uniform vec4 u_ambient;
uniform vec4 u_diffuse;
uniform vec4 u_emission;
uniform vec4 u_specular;
uniform float u_shininess;
varying vec3 v_light0Direction;
varying vec3 v_position;
uniform vec3 u_light0Color;
void main(void) {
vec3 normal = normalize(v_normal);
vec4 color = vec4(0., 0., 0., 0.);
vec4 diffuse = vec4(0., 0., 0., 1.);
vec3 diffuseLight = vec3(0., 0., 0.);
vec4 emission;
vec4 ambient;
vec4 specular;
ambient = u_ambient;
diffuse = u_diffuse;
emission = u_emission;
specular = u_specular;
vec3 specularLight = vec3(0., 0., 0.);
{
float specularIntensity = 0.;
float attenuation = 1.0;
vec3 l = normalize(v_light0Direction);
vec3 viewDir = -normalize(v_position);
float phongTerm = max(0.0, dot(reflect(-l,normal), viewDir));
specularIntensity = max(0., pow(phongTerm , u_shininess)) * attenuation;
specularLight += u_light0Color * specularIntensity;
diffuseLight += u_light0Color * max(dot(normal,l), 0.) * attenuation;
}
specular.xyz *= specularLight;
color.xyz += specular.xyz;
diffuse.xyz *= diffuseLight;
color.xyz += diffuse.xyz;
color.xyz += emission.xyz;
color = vec4(color.rgb * diffuse.a, diffuse.a);
gl_FragColor = color;
}
```
--------------------------------
### New Rendering Mode Property
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/ZedGraph/Revision_History.txt
This comment describes a new RenderMode property that allows rendering as an IMG tag instead of generating an image on the fly. A temporary image file is created and saved.
```csharp
// New RenderMode property to render as an IMG tag instead of generating and returning an image on the fly. A temporary image file is created and saved in the folder specified by the new RenderedImagePath property. The file name is the control ID (may change in a near future).
```
--------------------------------
### Fragment Shader with Texture and Phong Lighting
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/iris.txt
Combines texture sampling with Phong lighting calculations for fragment shading. Reads texture color and applies lighting effects. Requires texture sampler and uniform variables for lighting.
```glsl
precision highp float;
varying vec3 v_normal;
uniform vec4 u_ambient;
varying vec2 v_texcoord0;
uniform sampler2D u_diffuse;
uniform vec4 u_emission;
uniform vec4 u_specular;
uniform float u_shininess;
varying vec3 v_light0Direction;
varying vec3 v_position;
uniform vec3 u_light0Color;
void main(void) {
```
--------------------------------
### Including Open Iconic with Foundation
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/css/open-iconic/README.md
Link the Foundation stylesheet for Open Iconic. This allows the use of Foundation-specific icon classes.
```html
```
--------------------------------
### C# Web Sample Update
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/ZedGraph/Revision_History.txt
This C# code snippet is part of an updated web sample designed to work with a new RenderMode option. It indicates a change in how web content is rendered.
```csharp
// Updated Web sample in C# to work with new RenderMode option
```
--------------------------------
### Using Open Iconic Standalone Classes
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/css/open-iconic/README.md
Apply icons using the 'oi' class and the 'data-glyph' attribute for standalone usage. Include title and aria-hidden attributes.
```html
```
--------------------------------
### Render Google Sign-In Button
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
This function renders a Google Sign-In button using the gapi.signin2 library. It requires the gapi library to be loaded and a DOM element with the ID 'g-signin2'.
```javascript
function renderButton() {
//gapi.signin2.go()
gapi.signin2.render('g-signin2', {
'scope': 'profile email',
'width': 240,
'height': 50,
'longtitle': true,
'theme': 'dark',
'onsuccess': onSignIn,
'onfailure': onFailure
});
}
```
--------------------------------
### Google Maps Initialization
Source: https://github.com/ardupilot/missionplanner/blob/master/ExtLibs/wasm/wwwroot/index.html
Initializes a Google Maps instance with satellite view and maximum zoom level set to 21. Includes error handling for potential issues during map initialization.
```javascript
var map;
var viewer;
var markers = [];
var default_model_scale = 1.5;
var model_scale_factor = 0.06;
var takeoff_altitude = 0;
function initMap() {
try {
map = new google.maps.Map(document.getElementById('map'), {
center: { lat: -35, lng: 117.89 },
zoom: 1,
mapTypeId: 'satellite',
maxZoom: 21
});
//map.setMapTypeId('satellite');
//map.setOptions({maxZoom: 21});
} catch (err) {
console.log(err);
}
Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJjODdmODk4Yy0xZDhlLTQxNjAtOTkzNS02ZjNmOGRhM2I1MDgiLCJpZCI6NDYzOCwic2NvcGVzIjpbImFzciIsImdjIl0sImlhdCI6MTU0MTMyMDQ4Nn0.GnXyBbMj8o8TZ2LeCxFB_SrdUiQodGmjT1AbNCvmezA';
viewer = new Cesium.Viewer('cesiumContainer', {
infoBox: false, //Disable InfoBox widget
selectionIndicator: true, //Disable selection indicator
navigationInstructionsInitiallyVisible: false,
shadows: false,
shouldAnimate: true,
requestRenderMode: true,
maximumRenderTimeChange: 1 / 15,
clockStep: Cesium.ClockStep.SYSTEM_CLOCK,
});
var terrainProvider = Cesium.createWorldTerrain({
requestWaterMask: true,
requestVertexNormals: true
});
viewer.terrainProvider = terrainProvider;
viewer.scene.globe.depthTestAgainstTerrain = true;
var scene = viewer.scene;
var ellipsoid = scene.globe.ellipsoid;
pickCartographicPosition(scene, ellipsoid);
markers = [];
}
```