Feature Request - Ability to Save Geozones as an XML file
Geozones is an incredible new feature that will help many pilots avoid flying in areas where they should not. and make RTH even more effective. I have multiple aircraft and in an ideal world, I would like to be able to define Geozones that I can create once and easily load onto multiple aircraft. I currently do that with Missions.
Current Experience:
- Geozones interface is only available when an FC is connected to the configurator and Geozones are enabled in the Configuration tab
- Geozones can only be saved to the Eprom
- Geozones are lost from the configurator when you disconnect from the FC
Desired Experience:
Geozones can be created in Mission Planner without needing to be connected to a flight controller Geozone can also be saved as an XML file locally on the computer that is running the configurator Geozones can be loaded from the XML file into the configurator
Thank you for considering this and for all the work you do making INAV amazing.
Good idea. Nicer than reading / writing CLI fles (which is what mwp does at the moment got offline editing / persistance).
Something like (for example):
<?xml version="1.0" encoding="utf-8"?>
<geozones>
<geozone id="0" shape="circle" type="exclusive" minalt="123.0" maxalt="456.0" is_amsl="false" action="avoid">
<vertices>
<vertex id="0" latitude="54.3556810" longitude="-4.5287920" radius="160.0"/>
</vertices>
</geozone>
<geozone id="1" shape="polygon" type="inclusive" minalt="0.0" maxalt="200.66" is_amsl="false" action="poshold">
<vertices>
<vertex id="0" latitude="54.3535614" longitude="-4.5303353"/>
<vertex id="1" latitude="54.3518405" longitude="-4.5288563"/>
<vertex id="2" latitude="54.3512220" longitude="-4.5223563"/>
<vertex id="3" latitude="54.3530456" longitude="-4.5172406"/>
<vertex id="4" latitude="54.3530815" longitude="-4.5157285"/>
<vertex id="5" latitude="54.3539360" longitude="-4.5122910"/>
<vertex id="6" latitude="54.3553608" longitude="-4.5105164"/>
<vertex id="7" latitude="54.3569302" longitude="-4.5136845"/>
</vertices>
</geozone>
</geozones>
@b14ckyy @Scavanger Do you see problems with this (like there are other non-geometric GeoZone parameters that make this impractical) ?
Otherwise I'll draft up a XSD for review as a path to standardisation across planners.
Geozones could be simply transferred via cli by copying the relevant part of a diff. Editing is not recommended of course.
But I am open for any QoL feature as it makes a lot of sense to copy zones between crafts and even edit offline when the new Mission control is ready.
In this case I would even say that this exports also the safe homes in the same go. What do you think?
Edit: the settings for safehome are also split between 2 areas for a reason. The settings that will be plane specific based on flight performance are in advanced tuning.
For geozones we also have a few additional settings but these are also aircraft specific and not relevant for transferring between aircraft.
I think the whole issue / real issue is UX / Usability. Not being able to offline edit and persist to the file system artefacts such as Geozone (and Safehome) is a usability bug. The file format is somewhat irrelevant, as long as it is documented so we have an interoperable format between products.
OTOH, I find
<?xml version="1.0" standalone="yes"?>
<gezones>
<geozone id="0" shape="circle" type="exclusive" minalt="23.0" maxalt="12300.0" is_amsl="true" action="avoid">
<vertices id="0" latitude="54.355681" longitude="-4.528792" radius="160.0"/>
</geozone>
<geozone id="1" shape="polygon" type="inclusive" minalt="0.0" maxalt="10000.0" is_amsl="false" action="none">
<vertices id="0" latitude="54.3535614" longitude="-4.5303353"/>
<vertices id="1" latitude="54.3518405" longitude="-4.5288563"/>
<vertices id="2" latitude="54.351222" longitude="-4.5223563"/>
<vertices id="3" latitude="54.3530456" longitude="-4.5172406"/>
<vertices id="4" latitude="54.3530815" longitude="-4.5157285"/>
<vertices id="5" latitude="54.353936" longitude="-4.512291"/>
<vertices id="6" latitude="54.3553608" longitude="-4.5105164"/>
<vertices id="7" latitude="54.3569302" longitude="-4.5136845"/>
</geozone>
<geozone id="2" shape="polygon" type="exclusive" minalt="0.0" maxalt="10000.0" is_amsl="false" action="none">
<vertices id="0" latitude="54.3554831" longitude="-4.5247084"/>
<vertices id="1" latitude="54.3567914" longitude="-4.5185943"/>
<vertices id="2" latitude="54.358035" longitude="-4.519585"/>
<vertices id="3" latitude="54.3595101" longitude="-4.5246121"/>
<vertices id="4" latitude="54.3579793" longitude="-4.5268677"/>
</geozone>
<geozone id="3" shape="circle" type="inclusive" minalt="0.0" maxalt="10000.0" is_amsl="false" action="rth">
<vertices id="0" latitude="54.356769" longitude="-4.516625" radius="115.0"/>
</geozone
to be a far more useful, human readable representation than:
# geozone
geozone 0 0 0 2300 12300 1 1 2
geozone vertex 0 0 543556810 -45287920
geozone vertex 0 1 16000 0
geozone 1 1 1 0 10000 0 0 8
geozone vertex 1 0 543535614 -45303353
geozone vertex 1 1 543518405 -45288563
geozone vertex 1 2 543512220 -45223563
geozone vertex 1 3 543530456 -45172406
geozone vertex 1 4 543530815 -45157285
geozone vertex 1 5 543539360 -45122910
geozone vertex 1 6 543553608 -45105164
geozone vertex 1 7 543569302 -45136845
geozone 2 1 0 0 10000 0 0 5
geozone vertex 2 0 543554831 -45247084
geozone vertex 2 1 543567914 -45185943
geozone vertex 2 2 543580350 -45195850
geozone vertex 2 3 543595101 -45246121
geozone vertex 2 4 543579793 -45268677
geozone 3 0 1 0 10000 0 3 2
geozone vertex 3 0 543567690 -45166250
geozone vertex 3 1 11500 0
Back to UX again ....
As far as safehome, this is slightly more problematic for standalone usage with "fixed wing approach" as the geometry that is drawn (and executed) depends on two CLI variables that are not part of the safehome / fwapproach geospatial geometry (nav_fw_land_approach_length and nav_fw_loiter_radius). i.e the length of the "base leg" is computed as the maximum of nav_fw_land_approach_length / 2 or nav_fw_loiter_radius * 4. This is discussed in more detail (with pictures) in the mwp user guide.
One way of managing this would be to add some "options" (hints) to the XML file, which the application could choose to ignore when connected to a FC and having access to specific parameters for a particular aircraft.
So, for the CLI fragment:
# safehome
safehome 0 1 543540248 -45237071
safehome 1 1 543563486 -45129749
safehome 2 0 543526527 -45269011
safehome 3 1 543539528 -45132527
safehome 4 0 0 0
safehome 5 0 0 0
safehome 6 0 0 0
safehome 7 0 0 0
# fwapproach
fwapproach 0 6000 0 0 -330 69 0
fwapproach 1 12687 2687 1 -70 0 1
fwapproach 8 6000 500 0 34 0 0
fwapproach 10 0 0 0 43 103 0
set nav_fw_land_approach_length = 150
set nav_fw_loiter_radius = 40
One might end up with a more readable application (INAV Configurator, mwp) XML file:
<?xml version="1.0" standalone="yes"?>
<safehomes>
<description version="1.0" generator="clish2xml.rb">
<options name="nav_fw_land_approach_length" value="150"/>
<options name="nav_fw_loiter_radius" value="40"/>
</description>
<safehome id="0" enabled="true" latitude="54.3540248" longitude="-4.5237071"/>
<safehome id="1" enabled="true" latitude="54.3563486" longitude="-4.5129749"/>
<safehome id="2" enabled="false" latitude="54.3526527" longitude="-4.5269011"/>
<safehome id="3" enabled="true" latitude="54.3539528" longitude="-4.5132527"/>
<safehome id="4" enabled="false" latitude="0.0" longitude="0.0"/>
<safehome id="5" enabled="false" latitude="0.0" longitude="0.0"/>
<safehome id="6" enabled="false" latitude="0.0" longitude="0.0"/>
<safehome id="7" enabled="false" latitude="0.0" longitude="0.0"/>
<fwapproach approachalt="60.0" index="0" landalt="0.0" landheading1="0" landheading2="-330" approachdirection="right" sealevelref="false"/>
<fwapproach approachalt="126.87" index="1" landalt="26.87" landheading1="1" landheading2="-70" approachdirection="left" sealevelref="false"/>
</safehomes>
Since Autoland representations on the Map are depending on the individual plane config and make not much sense to be edited offline anyway, they could just be ignored in offline mode and only loaded when a FC is connected or if a FC was connected, taking the last known settings into account. If the User switches the FC to import the Zones or Safe Homes, MWP or Configurator could update the map drawings.
Attached are proposed safehome and geozone schemas (with sample files and backing CLI data). Should anyone be interested in pursuing this in the Configurator:
- Once there is consensus on schemas, these should be added to the main INAV repository
docs/development/(the home of the mission XSD). - The same would then be added to mwp (in addition to extant CLI file I/O).
How about GeoJSON? https://geojson.org/
A zone could be represented as a feature, with a polygon as geometry and the options can be defined as properties.
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"type":"inclusive",
"minalt":"0.0",
"maxalt":"10000.0",
"is_amsl":"false",
"action":"none"
},
"geometry": {
"type": "Polygon",
"coordinates": [
["54.3535614", "-4.5303353"],
["54.3518405", "-4.5288563"],
["54.3512220", "-4.5223563"],
["54.3530456", "-4.5172406"],
["54.3530815", "-4.5157285"],
["54.3539360", "-4.5122910"],
["54.3553608", "-4.5105164"],
["54.3569302", "-4.5136845"],
["54.3535614", "-4.5303353"]
]
}
}
]
}
GeoJSON is also use often with GIS tools, so it is likely has the potential to integrate well with other tools.
That could work.
GeoJSON has no means to represent a circle. You could just use points (centre and a property) or multi-point , however only bespoke tools would be able to decode them as circles. So the "GIS tools" integration potential is not that great. Or you have the properties INAV needs as properties, and the circle as a polygon for "other tool" visualisation and the file becomes rather large and not human readable (this is what mwp does for its KML conversion).
I have no preference either way, however I feel we will get better interoperability between tools with a formal schema.
The lack of circle is indeed a valid concern.
A common workaround seems to define circles as a point with a radius property. That may not be ideal, but would keep it short and simple.
A plus that may be overlooked is that js mapping libraries, like leaflet tend to support geojson and may do most of the work for us when reading/exporting. (At least on the configurator side). We still would need to translate it into msp, but that is true for any format we pick.
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"radius": 500,
"type":"inclusive",
"minalt":"0.0",
"maxalt":"10000.0",
"is_amsl":"false",
"action":"none"
},
"geometry": {
"type": "Polygon",
"coordinates": [
["54.3535614", "-4.5303353"]
]
}
}
]
}
(I am ok with a custom xml schema as well)
Just a note:
- None of the GeoJSON examples are valid GeoJSON
- GeoJSON requires coordinates as easting, northing (in common with most GIS representations)
I am also OK with either. If we do go the GeoJSON route, we need to:
- Provide some documentation defining the mandatory properties and enumerations
- Generate valid GeoJSON that is acceptable to 3rd party tools.
I took the KML from the original example, converted it to GeoJSON, added INAV / Geozone properties, remove the polyline interpretation of the circles. Imported into QGIS:
Circles are just points of course.
Valid GeoJSON:
{
"crs" : {
"properties" : {
"name" : "urn:ogc:def:crs:OGC:1.3:CRS84"
},
"type" : "name"
},
"features" : [
{
"geometry" : {
"coordinates" : [
-4.5287920,
54.3556810
],
"type" : "Point"
},
"properties" : {
"Description" : "INAV Geozone",
"Name" : "Circle 1",
"Type" : "Exclusive",
"Action" : "Avoid",
"MinAlt" : 23.0,
"MaxAlt" : 120.0,
"IsAMSL" : true,
"Radius" : 160.0
},
"type" : "Feature"
},
{
"geometry" : {
"coordinates" : [
[
[
-4.5303353,
54.3535614
],
[
-4.5288563,
54.3518405
],
[
-4.5223563,
54.351222
],
[
-4.5172406,
54.3530456
],
[
-4.5157285,
54.3530815
],
[
-4.512291,
54.353936
],
[
-4.5105164,
54.3553608
],
[
-4.5136845,
54.3569302
],
[
-4.5303353,
54.3535614
]
]
],
"type" : "Polygon"
},
"properties" : {
"Description" : "INAV Geozone",
"Name" : "Polygon 1",
"Type" : "Inclusive",
"Action" : "None",
"MinAlt" : 0.0,
"MaxAlt" : 100.0,
"IsAMSL" : false
},
"type" : "Feature"
},
{
"geometry" : {
"coordinates" : [
[
[
-4.5247084,
54.3554831
],
[
-4.5185943,
54.3567914
],
[
-4.519585,
54.358035
],
[
-4.5246121,
54.3595101
],
[
-4.5268677,
54.3579793
],
[
-4.5247084,
54.3554831
]
]
],
"type" : "Polygon"
},
"properties" : {
"Description" : "INAV Geozone",
"Name" : "Polygon 2",
"Type" : "Exclusive",
"Action" : "None",
"MinAlt" : 0.0,
"MaxAlt" : 100.0,
"IsAMSL" : false
},
"type" : "Feature"
},
{
"geometry" : {
"coordinates" : [
-4.5166250,
54.3567690
],
"type" : "Point"
},
"properties" : {
"Description" : "INAV Geozone",
"Name" : "Circle 2",
"Type" : "Inclusive",
"Action" : "RTH",
"MinAlt" : 0.0,
"MaxAlt" : 1000,
"IsAMSL" : false,
"Radius" : 115.0
},
"type" : "Feature"
}
],
"name" : "geozones",
"type" : "FeatureCollection"
}
$ ogrinfo -al /tmp/example.geojson
INFO: Open of `/tmp/example.geojson'
using driver `GeoJSON' successful.
Layer name: geozones
Geometry: Unknown (any)
Feature Count: 4
Extent: (-4.530335, 54.351222) - (-4.510516, 54.359510)
Layer SRS WKT:
GEOGCRS["WGS 84",
DATUM["World Geodetic System 1984",
ELLIPSOID["WGS 84",6378137,298.257223563,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
CS[ellipsoidal,2],
AXIS["geodetic latitude (Lat)",north,
ORDER[1],
ANGLEUNIT["degree",0.0174532925199433]],
AXIS["geodetic longitude (Lon)",east,
ORDER[2],
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4326]]
Data axis to CRS axis mapping: 2,1
Description: String (0.0)
Name: String (0.0)
Type: String (0.0)
Action: String (0.0)
MinAlt: Real (0.0)
MaxAlt: Real (0.0)
IsAMSL: String(JSON) (0.0)
Radius: Real (0.0)
OGRFeature(geozones):0
Description (String) = INAV Geozone
Name (String) = Circle 1
Type (String) = Exclusive
Action (String) = Avoid
MinAlt (Real) = 23
MaxAlt (Real) = 120
IsAMSL (String(JSON)) = true
Radius (Real) = 160
POINT (-4.528792 54.355681)
OGRFeature(geozones):1
Description (String) = INAV Geozone
Name (String) = Polygon 1
Type (String) = Inclusive
Action (String) = None
MinAlt (Real) = 0
MaxAlt (Real) = 100
IsAMSL (String(JSON)) = IsAMSL
POLYGON ((-4.5303353 54.3535614,-4.5288563 54.3518405,-4.5223563 54.351222,-4.5172406 54.3530456,-4.5157285 54.3530815,-4.512291 54.353936,-4.5105164 54.3553608,-4.5136845 54.3569302,-4.5303353 54.3535614))
OGRFeature(geozones):2
Description (String) = INAV Geozone
Name (String) = Polygon 2
Type (String) = Exclusive
Action (String) = None
MinAlt (Real) = 0
MaxAlt (Real) = 100
IsAMSL (String(JSON)) = false
POLYGON ((-4.5247084 54.3554831,-4.5185943 54.3567914,-4.519585 54.358035,-4.5246121 54.3595101,-4.5268677 54.3579793,-4.5247084 54.3554831))
OGRFeature(geozones):3
Description (String) = INAV Geozone
Name (String) = Circle 2
Type (String) = Inclusive
Action (String) = RTH
MinAlt (Real) = 0
MaxAlt (Real) = 1000
IsAMSL (String(JSON)) = false
Radius (Real) = 115
POINT (-4.516625 54.356769)
Just a note:
* None of the GeoJSON examples are valid GeoJSON * GeoJSON requires coordinates as easting, northing (in common with most GIS representations)
That was my attempt at writing an example by hand. I did not try to pass it through link. Been a while since I actually used GeoJSON. Nice to see you managed to convert from KML to GeoJSON and make it work with my suggestion.
Quick summary:
geoJSON: Pros:
- Standard used by other GIS tools, like possible to export valid INAV GeoJSON from standard tools.
- Flexible enough to accept our properties
- Basic tools exist to validate
- Human readable enough
Cons:
- No circle
- Properties are too flexible, so it is quite easy to write valid GeoJSON that wouldn't necessarily work in INAV. :)
XML: Pros:
- We can have a strict schema for INAV
- Tooling to validate xml schemas exist
- We can do whatever we want
Cons:
- Custom format will have less integration options as code will need to be written (if we can use KML, it will likely match or exceed geoJSON in compatibility) In my view: GeoJSON is a format with a standard that is used in GIS applications.
- While XML is human readable, JSON seems a bit less noisy.