1
0
Fork 0
mirror of https://github.com/iNavFlight/inav-configurator.git synced 2025-07-26 01:35:23 +03:00

Add sanity cheks

This commit is contained in:
Scavanger 2024-11-15 12:32:08 -03:00
parent abc3fa5606
commit 8a16ee2894
5 changed files with 139 additions and 6 deletions

View file

@ -1,5 +1,7 @@
'use strict' 'use strict'
const { Shape } = require("three");
const GeozoneType = Object.freeze({ const GeozoneType = Object.freeze({
EXCULSIVE: 0, EXCULSIVE: 0,
INCLUSIVE: 1, INCLUSIVE: 1,
@ -176,6 +178,71 @@ let Geozone = function (type, shape, minAltitude, maxAltitude, sealevelRef, radi
vertices = []; vertices = [];
} }
self.isCounterClockwise = () => {
if (shape == GeozoneShapes.CIRCULAR) {
return true;
}
let area = 0;
for (let i = 0; i < vertices.length; i++) {
const x1 = vertices[i].getLat();
const y1 = vertices[i].getLon();
const next = vertices[(i + 1) % vertices.length];
const x2 = next.getLat();
const y2 = next.getLon();
area += x1 * y2 - y1 * x2;
}
return area < 0;
}
self.isComplex = () => {
if (shape == GeozoneShapes.CIRCULAR) {
return false;
}
// Intersection of two lines https://en.wikipedia.org/wiki/Line-line_intersection
function doLinesIntersect(line1Start, line1End, line2Start, line2End)
{
const s1 = line1End.x - line1Start.x;
const t1 = -(line2End.x - line2Start.x);
const r1 = line2Start.x - line1Start.x;
const s2 = line1End.y - line1Start.y;
const t2 = -(line2End.y - line2Start.y);
const r2 = line2Start.y - line1Start.y;
// Use Cramer's rule for the solution of the system of linear equations
const determ = s1 * t2 - t1 * s2;
if (determ == 0) { // No solution
return false;
}
const s0 = (r1 * t2 - t1 * r2) / determ;
const t0 = (s1 * r2 - r1 * s2) / determ;
if (s0 == 0 && t0 == 0) {
return false;
}
return !(s0 <= 0 || s0 >= 1 || t0 <= 0 || t0 >= 1)
}
for (var i = 0; i < vertices.length; i++) {
const a = {x: vertices[i].getLat(), y: vertices[i].getLon()};
const next = vertices[(i + 1) % vertices.length];
const b = {x: next.getLat(), y: next.getLon()};
for (var j = i + 2; j < vertices.length; j++) {
const c = {x: vertices[j].getLat(), y: vertices[j].getLon()};;
const next2 = vertices[(j + 1) % vertices.length];
const d = {x: next2.getLat(), y: next2.getLon()};
if (doLinesIntersect(a, b, c, d)) {
return true;
}
}
}
return false;
}
self.getElevationFromServer = async function (lon, lat, globalSettings) { self.getElevationFromServer = async function (lon, lat, globalSettings) {
let elevation = "N/A"; let elevation = "N/A";
if (globalSettings.mapProviderType == 'bing') { if (globalSettings.mapProviderType == 'bing') {

View file

@ -140,7 +140,7 @@ let GeozoneCollection = function() {
buffer.push(zone.getVerticesCount()); buffer.push(zone.getVerticesCount());
} }
} else { } else {
buffer = [id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; buffer = [id, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
} }
return buffer; return buffer;

View file

@ -4772,6 +4772,9 @@
"featureGEOZONE": { "featureGEOZONE": {
"message": "Geozone" "message": "Geozone"
}, },
"geozone": {
"message": "Geozone"
},
"featureGEOZONETip": { "featureGEOZONETip": {
"message": "Virtual perimeters for geographical areas (also called geofence) with automatically triggered actions when the perimeters are violated." "message": "Virtual perimeters for geographical areas (also called geofence) with automatically triggered actions when the perimeters are violated."
}, },
@ -4829,6 +4832,21 @@
"missionGeozoneAvailableVertices": { "missionGeozoneAvailableVertices": {
"message": "Available Vertices:" "message": "Available Vertices:"
}, },
"geozoneInvalidzone": {
"message": "Invalid Geozone(s) detected:"
},
"gezoneInvalidReasonNotCC": {
"message": "Not counter clockwise"
},
"gezoneInvalidReasonComplex": {
"message": "Complex"
},
"gezoneInvalidReasonMinMaxAlt": {
"message": "Max. Alt <= Min. Alt"
},
"geozoneUnableToSave": {
"message": "Unable to save geozones: Invalid zones"
},
"missionMultiMissionHead": { "missionMultiMissionHead": {
"message": "Multi Missions" "message": "Multi Missions"
}, },

View file

@ -66,6 +66,11 @@
<span style="color: red" i18n-replaced data-i18n="warning"></span> <span style="color: red" i18n-replaced data-i18n="warning"></span>
<div id="geozoneMissionWarning" style="display: inline-block" data-i18n="missionGeozoneWarning"></div> <div id="geozoneMissionWarning" style="display: inline-block" data-i18n="missionGeozoneWarning"></div>
</div> </div>
<div id="infoGeozoneInvalid" style="padding-bottom: 2px;">
<span style="color: red" i18n-replaced data-i18n="warning"></span>
<div style="display: inline-block" data-i18n="geozoneInvalidzone"></div>
<span id="geozoneInvalidContent"></span>
</div>
</div> </div>
</div> </div>

View file

@ -76,6 +76,7 @@ TABS.mission_control.initialize = function (callback) {
let $waypointOptionsTableBody; let $waypointOptionsTableBody;
let selectedGeozone; let selectedGeozone;
let $geozoneContent; let $geozoneContent;
let invalidGeoZones = false;
let isGeozoneEnabeld = false; let isGeozoneEnabeld = false;
let settings = {speed: 0, alt: 5000, safeRadiusSH: 50, fwApproachAlt: 60, fwLandAlt: 5, maxDistSH: 0, fwApproachLength: 0, fwLoiterRadius: 0, bingDemModel: false}; let settings = {speed: 0, alt: 5000, safeRadiusSH: 50, fwApproachAlt: 60, fwLandAlt: 5, maxDistSH: 0, fwApproachLength: 0, fwLoiterRadius: 0, bingDemModel: false};
@ -152,6 +153,7 @@ TABS.mission_control.initialize = function (callback) {
} }
$('#infoGeozoneMissionWarning').hide(); $('#infoGeozoneMissionWarning').hide();
$('#infoGeozoneInvalid').hide();
$safehomeContentBox = $('#SafehomeContentBox'); $safehomeContentBox = $('#SafehomeContentBox');
$waypointOptionsTableBody = $('#waypointOptionsTableBody'); $waypointOptionsTableBody = $('#waypointOptionsTableBody');
$geozoneContent = $('#geozoneContent'); $geozoneContent = $('#geozoneContent');
@ -919,7 +921,7 @@ TABS.mission_control.initialize = function (callback) {
cleanGeozoneLayers(); cleanGeozoneLayers();
if (!selectedGeozone) { if (!selectedGeozone) {
cleanGeozoneLines(); cleanGeozoneLines();
geozoneMissionWarning(); geozoneWarning();
return; return;
} }
@ -931,7 +933,7 @@ TABS.mission_control.initialize = function (callback) {
}); });
} }
}); });
geozoneMissionWarning(); geozoneWarning();
} }
function cleanGeozoneLines() { function cleanGeozoneLines() {
@ -949,13 +951,45 @@ TABS.mission_control.initialize = function (callback) {
geozoneMarkers = []; geozoneMarkers = [];
} }
function geozoneMissionWarning() { function geozoneWarning() {
if (markers.length >= 1 && geozoneMarkers.length >= 1) { if (markers.length >= 1 && geozoneMarkers.length >= 1) {
$('#infoGeozoneMissionWarning').show(); $('#infoGeozoneMissionWarning').show();
} else { } else {
$('#infoGeozoneMissionWarning').hide(); $('#infoGeozoneMissionWarning').hide();
} }
$('#geozoneInvalidContent').empty();
invalidGeoZones = false;
for (var i = 0; i < FC.GEOZONES.geozoneCount(); i++) {
const zone = FC.GEOZONES.at(i);
var reasons = []
if (!zone.isCounterClockwise()) {
reasons.push(i18n.getMessage("gezoneInvalidReasonNotCC"));
}
if (zone.isComplex()) {
reasons.push(i18n.getMessage("gezoneInvalidReasonComplex"));
}
if (zone.getMaxAltitude() <= zone.getMinAltitude()) {
reasons.push(i18n.getMessage("gezoneInvalidReasonMinMaxAlt"));
}
if (reasons.length > 0) {
$('#geozoneInvalidContent').append(`<div style="display: inline-block">${i18n.getMessage("geozone")} ${zone.getNumber() + 1}: ${reasons.join(", ")}</div><br/>`);
invalidGeoZones = true;
}
}
if (invalidGeoZones) {
$('#infoGeozoneInvalid').show();
} else {
$('#infoGeozoneInvalid').hide();
}
} }
function updateGeozoneInfo() { function updateGeozoneInfo() {
@ -1621,7 +1655,7 @@ TABS.mission_control.initialize = function (callback) {
}); });
} }
geozoneMissionWarning(); geozoneWarning();
} }
function redrawLayer() { function redrawLayer() {
@ -1734,7 +1768,7 @@ TABS.mission_control.initialize = function (callback) {
} }
}); });
}); });
geozoneWarning();
} else { } else {
$('#geozoneContentBox').hide(); $('#geozoneContentBox').hide();
} }
@ -1992,6 +2026,9 @@ TABS.mission_control.initialize = function (callback) {
var handleShowGeozoneSettings = function () { var handleShowGeozoneSettings = function () {
$('#missionPlannerGeozones').fadeIn(300); $('#missionPlannerGeozones').fadeIn(300);
if (!selectedGeozone) {
selectedGeozone = FC.GEOZONES.first();
}
renderGeozoneOptions(); renderGeozoneOptions();
renderGeozonesOnMap(); renderGeozonesOnMap();
}; };
@ -3363,6 +3400,12 @@ TABS.mission_control.initialize = function (callback) {
}); });
$('#saveEepromGeozoneButton').on('click', event => { $('#saveEepromGeozoneButton').on('click', event => {
if (invalidGeoZones) {
GUI.alert(i18n.getMessage("geozoneUnableToSave"));
return;
}
if (confirm(i18n.getMessage("missionGeozoneReboot"))) { if (confirm(i18n.getMessage("missionGeozoneReboot"))) {
$(event.currentTarget).addClass('disabled'); $(event.currentTarget).addClass('disabled');
GUI.log('Start of sending Geozones'); GUI.log('Start of sending Geozones');