Board index FlightGear Development Canvas

Get objects to show up on Map/Radar

Canvas is FlightGear's new fully scriptable 2D drawing system that will allow you to easily create new instruments, HUDs and even GUI dialogs and custom GUI widgets, without having to write C++ code and without having to rebuild FlightGear.

Re: Get objects to show up on Map/Radar

Postby Hooray » Tue Jun 24, 2014 4:18 pm

  • your searchCmd() method looks good to me
  • the svg parser is hand-written and can be found in $FG_ROOT/Nasal/canvas/svg.nas, it can be easily extended to support additional primitives/tags, you just need to map them to the corresponding OpenVG equivalents, I think supporting shapes would make sense and shouldn't be too difficult.
  • in a custom, non-navaid layer, the whole query-type thing can be ignored - it's not even used anywhere, it's really only used to "make" a searchCmd() for navaids like vor, ndb, dme etc - but for that to work, you would have to inherit from "NavaidSymbolLayer", whereas you're probably using "MultiSymbolLayer" now - which is why it's not having any effect. It's really only used in a single place, the one that you don't have anymore :D So "query_type" is really just for navaids.
  • the _equals line adds a new function to the layer's searcher hash - we need to provide a way to check for "equality", i.e. for navaids that could be position and/or the ID (name). For custom/new layers, we need to provide a custom equality check function. What you are doing there is just adding a custom equality check function that always returns "false" (=not equal). This is used by MapStructure to "smartly" identify and differentiate between old and new objects, i.e. to reduce workload and improve performance - imagine the "FIX" layer, which may have hundreds of fixes - while flying, a few dozen will be "new" ones, while most others will be "old" - we'll only remove the old ones, and only add new ones. If the custom definition is not provided, you should get an error suggesting that you add a corresponding method so that the underlying logic can check all objects for equality - see the bottom of the MapStructure article for details, or search for "_equals"
  • yes, new/del are constructor and destructor-style functions, but just by convention - they're not in any way "special", i.e. are not implicitly called, and need to be manually called.


PS: thanks for discussing these questions in public, it would be great if you could also review the corresponding wiki articles and add your questions (or answers) there.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Get objects to show up on Map/Radar

Postby Philosopher » Tue Jun 24, 2014 4:41 pm

Yeah, the real reason behind the _equals is because it's a design hack: the geo difference search function (whatever it's called) originally supported almost any object through Nasal, but since Tom extended it in C++ space it doesn't really work with non-positioned objects (he uses cppbind typecasting into positioned objects), so I retained the old capability by allowing the user to specify a custom equals function to use the old Nasal-space difference engine. (For non-positioned layers this allows us to use roughly the same mechanism with Nasal objects/classes.)

Setting _equals to a "return 0" function simply means that each object will be taken off and recreated on each search. But, when there's a better id to use, MapStructure can remove only the old ones and add only the new ones. How that is done depends on both the model object and the drawing – for instance, if a *.symbol file says to completely redraw the Canvas group based on the model, that means it potentially could be used with different models during its lifetime, whereas if the symbol is only set up once on initialization, it would not reflect changes in it's model object and thus should be removed when it is gone.

P.S. I don't think you need to create a geo.Coord for each AA, using "model" instead should work (and would even update on its own, i.e. if the position properties change the symbol can change with it). Something like:
Code: Select all
    var searchCmd = func
                    {
                        var results = [];
                        var loadedModels = props.globals.getNode("models").getChildren();
                       
                        foreach (var model; loadedModels)
                            if (cmp(substr(model.getValue("path"), 0, 10), "Models/AA/") == 0)  # only process models loaded from $FG_ROOT/Models/AA/
                                append(results, model);

                        return results;
                    };

And in that case, the equals() could be improved to this:
Code: Select all
layer.searcher._equals = func(a,b) a.equals(b);


P.P.S. The other ugly thing about _equals is that it's essentially duplicated by MapStructure here, and is used here to find models inside of the Layer's internal list, while the geo search obviously uses a competing approach. I might get around to fixing that ;). Basically MapStructure's whole flow is: layer searchCmd -> models -> symbols -> canvas drawings.
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Get objects to show up on Map/Radar

Postby Hooray » Tue Jun 24, 2014 4:59 pm

Regarding the Models/AA comparison, that should work for now - but in the mid-term, you probably want to use additional meta information for things like elevation/height, diameter, material to simulate some kind of "radar profile" (signature) - thus, I'd consider setting a few custom properties, e.g. a boolean flag for "AA", and maybe a few others to allow the radar layer to animate symbols properly using some kind of semi-plausible radar profile. The "ufo editor" should be straightforward to extend accordingly, but you could even use the modified dialog to place such symbols on the map in a drag&drop fashion, and even place scenery objects using geo.put_model() (see geo.nas and/or the Nasal ufo code for examples).

That way, you could set up arbitrary meta information for each object, so that any "radar" displays could use that info.

EDIT: Also, you may want to use the helpers in geo.nas to reduce your search space by only doing the check for models that are within the current range of your map, so that it will not check all models but only those that would be visible, for an example of an "in_range()" helper, refer to TFC.lcontroller or WXR.lcontroller.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Get objects to show up on Map/Radar

Postby RevHardt » Tue Jun 24, 2014 10:35 pm

New code for the lcontroller, which additionally filters by range:
Code: Select all
var filteredModels = [];

var init =  func()
            {
                var strDir = "Models/AA/";  # white-list directory under $FG_ROOT
                var strlenDir = size(strDir);
                var loadedModels = props.globals.getNode("models").getChildren();
               
                foreach (var model; loadedModels)
                    if (cmp(substr(model.getValue("path"), 0, strlenDir), strDir) == 0)  # filter models from strDir
                        append(filteredModels, model);
            };

var searchCmd = func
                {
                    if (me.map.getRange() == nil) return;

                    var results = [];

                    foreach (var model; filteredModels)
                        if (me.map.controller.in_range(model.getValue("latitude-deg"), model.getValue("longitude-deg")))    # further filter models by range
                            append(results, model);

                    return results;
                };

init() is called from new() just before it returns.

Map display at 0.9 nm before range filtering:
Image

Map display at 0.9 nm after range filtering:
Image

Map display at 1.1 nm and above is identical and shows all three icons. At the same map zoom level and with more than enough space to spare, the only plausible reasoning I can come up with to explain the clipping is that the default query range value is lesser than what the canvas can handle. Any suggestions?
Take a look to the sky just before you die; it's the last time you will.
RevHardt
 
Posts: 31
Joined: Tue Jun 10, 2014 2:59 pm
Version: 3.4.0
OS: Win 7 Pro SP1 x64

Re: Get objects to show up on Map/Radar

Postby Hooray » Tue Jun 24, 2014 10:51 pm

This looks pretty good to me ! The range should default to the current map range, so I don't think that's the problem here - if in doubt, add a print() stmt.
You can use debug.dump( results ) to see what's in there (or dump models/filteredModels), somewhere something isn't quite working - just add a few debug.dump() or print() statements

I don't think you still need to return directly here if the range is invalid, this part should be handled by MapStructure meanwhile - even if NOT, you should return an empty vector here (i.e. results) and not just "nil" (which is what's happening when you just return). Here are some debugging tips to see where things are going haywire:

Code: Select all
var filteredModels = [];

var init =  func()
            {
                var strDir = "Models/AA/";  # white-list directory under $FG_ROOT
                var strlenDir = size(strDir);
                var loadedModels = props.globals.getNode("models").getChildren();
                print("Total loaded models=", size(loadedModels));               

                foreach (var model; loadedModels)
                    if (cmp(substr(model.getValue("path"), 0, strlenDir), strDir) == 0)  # filter models from strDir
                    {  print("New filtered model added!");
                        append(filteredModels, model);
                    }
                 print("Total filtered models:", size(filteredModels));
                debug.dump(filteredMmodels);
            };

var searchCmd = func()
                {
                    var results = [];

                    if (me.map.getRange() == nil) {
                    print("AA: map range() not valid!");
                     return results;
                     }
                 
                    print("filtered models size:", size(filteredModels));
                    foreach (var model; filteredModels) {
                        if (me.map.controller.in_range(model.getValue("latitude-deg"), model.getValue("longitude-deg")))    # further filter models by range
                            append(results, model);
                            print("AA: Added new model to vector!");
                     }
                    debug.dump(results);
                    return results;
                };
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Get objects to show up on Map/Radar

Postby Philosopher » Wed Jun 25, 2014 2:49 am

It's completely likely that the range is off, simply because it might represent a vertical range or something; but, however, it is supposed to be the correct range in NM, i.e. it is what the Canvas range property is. I've seen some similar edge cases. I believe on Gijs' NavDisplay there's actually a true circle where the map should be displayed, so I think the range is much closer to how it should be on that display, but the dialog is of course a rectangle. When there's only a few objects and/or it's hard to sort out the bad ones, I wouldn't filter by range just to make the code simpler, but obviously having 100s of objects running around isn't good.

Returning nil when there's an invalid range is fine but unnecessary (is there any code that still does that? not in the actual repo IIRC).

You don't need to use cmp(a,b)==0, just say a == b (remember, it is a scripting language, not plain C ;)).

Nice work btw.
Thanks,
Philosopher
(inactive but lurking occasionally...)
Philosopher
 
Posts: 1590
Joined: Sun Aug 12, 2012 6:29 pm
Location: Stuck in my head...
Callsign: AFTI
Version: Git
OS: Mac OS X 10.7.5

Re: Get objects to show up on Map/Radar

Postby Hooray » Wed Jun 25, 2014 3:12 pm

Philosopher wrote in Wed Jun 25, 2014 2:49 am:Returning nil when there's an invalid range is fine but unnecessary (is there any code that still does that? not in the actual repo IIRC).

Code: Select all
APT.lcontroller:42:     if (range == nil) return;
TFC.lcontroller:81:     if (me.map.getRange() == nil) return;
WXR.lcontroller:39:     if (me.map.getRange() == nil) return;


I'd still just return an empty vector - that's how MapStructure itself should be handling this condition in the background, so better remove such things.
But the "in_range" check raises an interesting question, i.e. if we want to -optionally- encode range checking for layers by passing some ctor flag - quite a few layers should benefit from such filtering, except of course for the NasalPositioned stuff which already filters internally - but other layers should be able to reduce their search space this way. Also, Tom once mentioned that Canvas itself doesn't internally do this check, things are updated no matter if they're currently visible or not according to his comments. So this should be a straightforward optimization that we really need to add at the MapStructure level, i.e. after calling searchCmd(), we could run an optional in_range() filter so that this is automatically done. Obviously, we need to take the map range, and map position/center into account then.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Get objects to show up on Map/Radar

Postby RevHardt » Wed Jun 25, 2014 3:20 pm

The range for the map indeed appears to be radial, and the radius appears to be half of the canvas height:
Image

New code for the lcontroller, as AA batteries are likely to be as numerous as fixes:
Code: Select all
var strDir = "Models/AA/";  # white-list directory under $FG_ROOT
var strlenDir = size(strDir);
var filteredModels = [];
var lat = [];
var lon = [];

var init =  func()
            {               
                var loadedModels = props.globals.getNode("models").getChildren();

                foreach (var model; loadedModels) filter(model);
            };

var filter =    func(model)
                {
                    if (substr(model.getValue("path"), 0, strlenDir) == strDir) # filter models from strDir
                    {
                        append(filteredModels, model);
                        append(lat, model.getValue("latitude-deg"));
                        append(lon, model.getValue("longitude-deg"));
                    }
                };

var searchCmd = func
                {
                    var results = [];

                    forindex (var i; filteredModels)
                        if (me.map.controller.in_range(lat[i], lon[i])) # further filter models by range
                            append(results, filteredModels[i]);

                    return results;
                };

1. As this approach obviously does not support models loaded after startup, where can I find a tutorial/example for geo.put_model() and how to set a listener for it?

Also,
MapStructure's whole flow is: layer searchCmd -> models -> symbols -> canvas drawings

2. But what calls searchCmd() in the first place? Just to know what all can be passed in results[] and how it's put to use.
Last edited by RevHardt on Wed Jun 25, 2014 9:34 pm, edited 1 time in total.
Take a look to the sky just before you die; it's the last time you will.
RevHardt
 
Posts: 31
Joined: Tue Jun 10, 2014 2:59 pm
Version: 3.4.0
OS: Win 7 Pro SP1 x64

Re: Get objects to show up on Map/Radar

Postby Hooray » Wed Jun 25, 2014 3:27 pm

That is correct, but depends on the center of the map obviously - i.e. in centered mode, your range needs to be divided by 2 - i.e. it's a radius. In off-center mode, range depends on the bearing to the object, i.e. you typically won't see as many objects behind you as those ahead of you - consider this MapStructure/ND view:
http://wiki.flightgear.org/NavDisplay
Image

  • geo.put_model(): just open geo.nas it's a little helper function that sets up a property tree branch, so you can use a listener that monitors /models
  • searchCmd() is typically called by a geo.PositionedSearch (see geo.nas) - objects in a vector returned from searchCmd need to be supported by MapStructure, i.e. either geo.Coord, properties with lat-deg/lon-deg or any of the FGPositioned ghosts (check supported_ghosts in MapStructure.nas)

In general, you'll probably want to use geo.Coord objects normally - the ghost stuff is only relevant if you're dealing with navdb queries (FGPositioned). The property stuff is for objects from the property tree, like your models and/or AI traffic
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Get objects to show up on Map/Radar

Postby RevHardt » Mon Jun 30, 2014 12:30 pm

new() and del() seem to be called every time the Map (Canvas) window is opened and closed - even within the same simulation session, and without any resetting.

Any standard/suggested methods for caching calculations/results so they persist, or do I just write my own class under $FG_ROOT/Nasal/ and keep passing data between that and the lcontroller?
Take a look to the sky just before you die; it's the last time you will.
RevHardt
 
Posts: 31
Joined: Tue Jun 10, 2014 2:59 pm
Version: 3.4.0
OS: Win 7 Pro SP1 x64

Re: Get objects to show up on Map/Radar

Postby Hooray » Mon Jun 30, 2014 12:43 pm

some context would be helpful here - are you referring to the lcontroller file ?
If so, yes - each lcontroller file manages a single layer normally. And each map will get its own instance of the layer.
Thus, for each map with your layer, there will be corresponding ctor/dtor calls - even when you open multiple instances of your map in the same session.
Keep in mind that most layers are generally "dynamic" by nature, especially stuff like traffic/weather need to be updated regularly. And navaids/airports etc need to be regularly updated, too.

Personally, I'd suggest not to over-engineer this for your particular use-case here, because it is kinda "niche". And you mentioned already that you're interested in AA stuff, right ?
We have the "bombable addon" and even scripted AI missiles - all of these can be visualized using existing MapStructure methods.

But customizing your lcontroller file to initialize "static" data structure once is straightforward to do - just do your initialization outside the constructor :-)
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Get objects to show up on Map/Radar

Postby RevHardt » Mon Jun 30, 2014 2:06 pm

So, to emulate a static operation in an lcontroller, I should enclose the block in a conditional, and check against a boolean defined outside (but still inside the lcontroller) that I set the first time around?

I have recently been trying out Bombable, trying to get AA batteries to fire at aircraft in their range. As each AA unit has a hemispherical (cylindrical, as a reduced test case) detection range, a cluster of them would have a contiguous volume of effect. Any related/unrelated API that calculates such zones?
Take a look to the sky just before you die; it's the last time you will.
RevHardt
 
Posts: 31
Joined: Tue Jun 10, 2014 2:59 pm
Version: 3.4.0
OS: Win 7 Pro SP1 x64

Re: Get objects to show up on Map/Radar

Postby Hooray » Mon Jun 30, 2014 2:38 pm

if you want to, you could probably create your own module for $FG_ROOT/Nasal - or even just make it an include file and use io.include() in your lcontroller to add your initialization stuff there.
lcontroller files are only loaded during initialization of the simulator - I don't think we're even handling re-init/resets explicitly ATM (?) Thus, any code added to your lcontroller (or even just included there) would be executed only once. We're kinda using this method in the .symbol files to set up a shared pre-created cache of symbols that can be shared among all instances of a layer.

Regarding your other question, there's quite some related code in several places. xiii's fox2.nas/radar code should be relevant, some aircraft also have code that emulate a rotating radar antenna.
In general, the view handling/camera (FGCamera) code should also contain related computations.

But you could probably adapt some existing code for this:
http://www.calculatorsoup.com/calculato ... sphere.php
http://stackoverflow.com/questions/5674 ... -longitude
Image

Either way, you'll probably want to use debug.benchmark() and run some stress-tests to see how heavy these calculations are, so that you can try to optimize the implementation, or maybe try to build a lookup table, so that multiple AA batteries can update "concurrently" without having a significant frame rate impact.

Several core developers have been wanting to re-implement geo.nas functionality via Nasal/cppbind so that "native" code is used here - so that would be another option here: http://wiki.flightgear.org/Plan-zakalawe.

Another option would be using a Nasal worker thread to run these computations via thread.newthread() - but care must be taken not to call any extension functions then, and locking should be used to serialize access between the FG main loop and shared data structures used by the background thread.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

Re: Get objects to show up on Map/Radar

Postby RevHardt » Mon Mar 23, 2015 5:18 pm

(I don't know your policy on necroposting, so please bear with me.)

I tried to port my earlier AA layer from my old machine running fgdata version 3.1.0 to this new system with FG installer version 3.4.0.
A trivial tweak to the MapStructure demo code outputs (in the Canvas Dialog) what should have been overlaid on the Map (Canvas) as part of the Anti-aircraft layer:

Image

You can even see one of the untextured AA models (loaded via an XML file using the --config switch) on the terrain to the left of the HUD elevator control indicators.
Any insight into what I might be overlooking?
Take a look to the sky just before you die; it's the last time you will.
RevHardt
 
Posts: 31
Joined: Tue Jun 10, 2014 2:59 pm
Version: 3.4.0
OS: Win 7 Pro SP1 x64

Re: Get objects to show up on Map/Radar

Postby Hooray » Mon Mar 23, 2015 8:17 pm

sorry, what exactly is the problem - are you saying that the exact same code doesn't work in the embedded map-canvas.xml dialog but does work properly in the standalone canvas window ?
If so, have you checked the property browser to see if your layer is there and if it is getting correctly populated and updated ?
And what about z-indexing ?

If you're using the demo code for troubleshooting purposes, I'd suggest to add 2-3 other layers to see if you can reproduce the problem there.
There should be a wiki article named "Canvas Troubleshooting" which contains a collection of tips on inspecting the canvas tree, including code snippets
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 11326
Joined: Tue Mar 25, 2008 8:40 am

PreviousNext

Return to Canvas

Who is online

Users browsing this forum: No registered users and 3 guests