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:
parent
abc3fa5606
commit
8a16ee2894
5 changed files with 139 additions and 6 deletions
|
@ -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') {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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"
|
||||||
},
|
},
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue