1
0
Fork 0
mirror of https://github.com/iNavFlight/inav-configurator.git synced 2025-07-13 11:29:53 +03:00
inav-configurator/js/geozone.js
2024-11-19 12:55:06 -03:00

278 lines
No EOL
6.6 KiB
JavaScript

'use strict'
const { Shape } = require("three");
const GeozoneType = Object.freeze({
EXCULSIVE: 0,
INCLUSIVE: 1,
});
const GeozoneShapes = Object.freeze({
CIRCULAR: 0,
POLYGON: 1,
});
const GeozoneFenceAction = Object.freeze({
NONE: 0,
AVOID: 1,
POSHOLD: 2,
RTH: 3,
});
let GeozoneVertex = function (number, lat, lon) {
self = {};
self.setNumber = (data) => {
number = data;
}
self.getNumber = () => {
return number;
}
self.setLat = (data) => {
lat = data;
}
self.getLat = () => {
return lat;
}
self.setLon = (data) => {
lon = data;
}
self.getLon = () => {
return lon;
}
self.getLatMap = () => {
return lat / 1e7;
}
self.getLonMap = () => {
return lon / 1e7;
}
return self;
}
let Geozone = function (type, shape, minAltitude, maxAltitude, sealevelRef, radius, fenceAction, vertices, number = 0) {
var self = {};
self.setNumber = (data) => {
number = data;
}
self.getNumber = () => {
return number;
}
self.setType = (data) => {
type = data;
}
self.getType = () => {
return type;
}
self.setShape = (data) => {
shape = data;
}
self.getShape = () => {
return shape;
}
self.setMinAltitude = (data) => {
if (!isNaN(data)){
minAltitude = parseInt(data);
} else {
minAltitude = data;
}
}
self.getMinAltitude = () => {
return minAltitude;
}
self.setMaxAltitude = (data) => {
if (!isNaN(data)){
maxAltitude = parseInt(data);
} else {
maxAltitude = data;
}
}
self.getMaxAltitude = () => {
return maxAltitude;
}
self.setSealevelRef = (data) => {
sealevelRef = data;
}
self.getSealevelRef = () => {
return sealevelRef;
}
self.setRadius = (data) => {
radius = data;
}
self.getRadius = () => {
return radius;
}
self.setFenceAction = (data) => {
fenceAction = data;
}
self.getFenceAction = () => {
return fenceAction;
}
self.getFirstVertex = () => {
return vertices[0];
}
self.getLastVertex = () => {
return vertices[vertices.length - 1];
}
self.getVerticesCount = () => {
return vertices.length;
}
self.getVertex = (idx) => {
return vertices[idx];
}
self.setVertex = (idx, vertex) => {
vertices[idx] = vertex;
}
self.getVertices = () => {
return vertices;
}
self.setVertices = (data) => {
vertices = data;
}
self.getVerticesCount = () => {
return vertices.length;
}
self.insertVertex = (idx, newVertex) => {
vertices.forEach(vertex => {
if (vertex.getNumber() >= idx) {
vertex.setNumber(vertex.getNumber() + 1);
}
});
vertices.splice(idx, 0, newVertex);
}
self.dropVertex = (idx) => {
vertices.forEach(vertex => {
if (vertex.getNumber() >= idx) {
vertex.setNumber(vertex.getNumber() - 1);
}
});
vertices.splice(idx, 1);
}
self.resetVertices = () => {
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) {
let elevation = "N/A";
if (globalSettings.mapProviderType == 'bing') {
let elevationEarthModel = $('#elevationEarthModel').prop("checked") ? "ellipsoid" : "sealevel";
const response = await fetch('http://dev.virtualearth.net/REST/v1/Elevation/List?points='+lat+','+lon+'&heights='+elevationEarthModel+'&key='+globalSettings.mapApiKey);
const myJson = await response.json();
elevation = myJson.resourceSets[0].resources[0].elevations[0];
}
else {
const response = await fetch('https://api.opentopodata.org/v1/aster30m?locations='+lat+','+lon);
const myJson = await response.json();
if (myJson.status == "OK" && myJson.results[0].elevation != null) {
elevation = myJson.results[0].elevation;
}
}
return elevation;
}
return self;
return self;
}
module.exports = { Geozone, GeozoneVertex, GeozoneType, GeozoneShapes, GeozoneFenceAction };