### 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 = "

"; 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 = []; } ```