Board index FlightGear Development Canvas

Garmin GPSmap196

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.

Garmin GPSmap196

Postby F-JJTH » Mon May 12, 2014 8:43 pm

Hi,

I would like to convert the current garmin196 (real name is Garmin GPSmap196) to canvas. I know the garmin196 is used in multiple aircrafts and seems to be appreciated in most of general aviation aircraft.
Main problem: my skills about Nasal/Canvas are clearly not sufficient !
That's why I would make this project as participative as possible. Some of you know that PAF team is usually working with multiple people with different skills in order to achieve a project.

Here my skills are mostly: good knowledge of the GPSmap196 because I'm using it in real life in my aircraft, in other world we have an infinite documentation. That way we can develop this GPS with high realism.

I have 2 mains requirement:
1) The screen of the GPSmap196 must be rendered with Canvas (map, settings, text...)
2) The GPSmap196 must be available as a "Canvas Widget"


Now it's time for questions:

Looking at the (non-exhaustive) list of screen that we have to reproduce here http://mapserver.flightgear.org/git/?p= ... 3d;hb=HEAD what is the better solution for rendering these screens ?
- Only use Canvas i.e: drawing fields, block, checkbox... ?
- Create 1 SVG file per screen ?
- Create 1 SVG file who contains 1 layer per screen ?

The first case seems heavy to me, I'm not sure it's the good solution but to be honest I know nothing about Canvas so I can be totally wrong
Second case looks better, easy to maintain, but I don't know if we can load multiple SVG file and switch between these SVG file at runtime
First case looks the good solution to me, harder to maintain because we have to deal with layer when editing the SVG file (I'm not ultra familiar with Inkscape but I'm able to play with him). But still the similar previous question: are we able to switch between layer at runtime ?

Well once this question is answered there is another big question: how to manage to switch between these screen ? Currently the garmin196 is using some Nasal with ID associated to each screen ( http://mapserver.flightgear.org/git/?p= ... b=HEAD#l69 ) I don't know if we can still use this technique because the GPSmap196 has some "popup", it means that you can display a dialog box on top of a screen (e.g map) so we can't say "I show the dialog blabla OR the map", we have to be able to say "I show the dialog blabla AND the map".

After these 2 questions we should be able to know "How to render our screens", and "How to switch between our screens". Once we have that we can start to add data in the GPS (map: cities, towns, airport... compass, speed, altitude, etc etc)


Ok, all of this was for the 3D model and his screens, now talking about the Widget:
The proof-of-concept is already here, if you click on the screen of the 3D model a Canvas Widget is displayed and he is filled by the content of the screen of the 3D model (that's a really cool feature!)
But I would like to have more than just a copy-of-the-screen, I would like to have a 2D full remote.
I explain: On the 3D model, if I press the Power button, the GPS will light-up, I would like that the Canvas Widget has also all the buttons in order to light-up (and do every that is possible to do with the 3D model) the GPS.
For that I've created a sub folder (AIrcraft/Instruments-3d/GPSmap196/widget) who contains an SVG file filled by a texture of the GPSmap196. The idea is to add some SVG object (totally transparent) on top of each buttons in order to catch the click on the texture (maybe it's not the good way, let me know) and also add a rectangle who will be filled by the Canvas texture (as it's done currently but instead of filling the whole Canvas widget like currently we would fill only the "virtual" screen)

The question is simple: my first approach about SVG file is a good start point ? or there is a better solution ?

Well as you can see we are not ready to start to draw waypoints, lines, airport or anything else in the map ;-) there is a lot of work before that.


Kind regards,
Clément
User avatar
F-JJTH
 
Posts: 697
Joined: Fri Sep 09, 2011 11:02 am

Re: Garmin GPSmap196

Postby Hooray » Mon May 12, 2014 9:02 pm

  • for the full thing to be usable not just as either and instrument or a GUI dialog, but both, the whole thing should be based on the method used by the MapStructure/ND frameworks probably
  • mapping (route and waypoints) should definitely be based on the existing work that Gijs has done, and which is now available as part of MapStructure
  • The instruments/gauges should ideally use SVGs, for the sake of simplicity, existing 2D gauges could also be used if needed to faster prototyping: http://wiki.flightgear.org/Howto:Parsin ... the_Canvas
    Image
  • this is clearly overlapping with some of the stuff that the extra500 guys (Avidyne) used to work on, so it would make sense to coordinate this a little
  • from a canvas standpoint, it would make sense to come up with a simple animation framework for SVG-based instruments: http://wiki.flightgear.org/Canvas_Animation_Framework
  • different SVGs makes sense, so that people can work on different instruments/pages independently IMO - and yes, we can process an arbitrary number of SVGs and deal with them independently, they should just use unique IDs for addressing (element lookup) - and these guidelines apply: viewtopic.php?f=71&t=22091&p=209068#p208870
  • we have Michat & pommesschranke who have provided great Inkscape artwork, so it would be a good idea to get in touch with them
  • switching between screens is currently done by showing/hiding certain SVG/canvas groups (layers) - which works well enough, but eventually we will need to support some SGCondition/SGStateMachine or even Autopilot/PropertyRule stuff probably, which James and Tom also once discussed - it would also have the advantage of reducing the amount of Nasal running in the main loop

GPSmap196 has some "popup", it means that you can display a dialog box on top of a screen (e.g map) so we can't say "I show the dialog blabla OR the map", we have to be able to say "I show the dialog blabla AND the map".

this is possible, see the extra500 for an example - but overall Canvas is based on some A661 concepts, which requires support for rendering a full GUI toolkit - so this is supported, including even event handling (responding to mouse events)

Once we have that we can start to add data in the GPS (map: cities, towns, airport... compass, speed, altitude, etc etc)

Most of these should be animated SVG elements - which is the way used by the Avidyne or Gijs' NavDisplay framework. You can open the ND file to see how it's structured. Each element/layer can be individually addressed and animated
[img]The%20question%20is%20simple:%20my%20first%20approach%20about%20SVG%20file%20is%20a%20good%20start%20point%20?%20or%20there%20is%20a%20better%20solution%20?[/img]

If there are widgets missing, those should ideally be based on new Canvas widgets, not on PUI - but it's definitely possible

On the 3D model, if I press the Power button, the GPS will light-up, I would like that the Canvas Widget has also all the buttons in order to light-up (and do every that is possible to do with the 3D model) the GPS.

we could use a hash to procedurally create the dialog with a screen region and buttons. Similar to how the ND has a PUI wrapper currently (those MCP/CDU buttons are replicated here) :
Image

Well as you can see we are not ready to start to draw waypoints, lines, airport or anything else in the map there is a lot of work before that.

you may be surprised, but that part is now trivial, because all the difficult work is already done and can be quickly integrated with any canvas-based instrument or dialog.

I can probably help with most of these to varying degrees, but only after 3.2 is out unfortunately. And I would prefer a modular approach, i.e. different Nasal files, and separate MapStructure layers.

But I am only interested if we can add the following requirements:
  • must support multiple independent instances of the same instrument/dialog (analogous to the ND/MapStructure work)
  • must be totally aircraft- and use-case agnostic (i.e. not just a single instrument or a single aircraft supported)
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: 11317
Joined: Tue Mar 25, 2008 8:40 am

Re: Garmin GPSmap196

Postby Johan G » Mon May 12, 2014 10:34 pm

Just a small note: Remember to keep the low screen resolution. ;)
Low-level flying — It's all fun and games till someone looses an engine. (Paraphrased from a YouTube video)
Improving the Dassault Mirage F1 (Wiki, Forum, GitLab. Work in slow progress)
Johan G
Moderator
 
Posts: 5437
Joined: Fri Aug 06, 2010 5:33 pm
Location: Sweden
Callsign: SE-JG
IRC name: Johan_G
Version: 3.0.0
OS: Windows 7, 32 bit

Re: Garmin GPSmap196

Postby Hooray » Mon May 12, 2014 10:42 pm

to get this started we need a SVG file representing the device (screen,keypad/buttons) - each functional element should be addressable by having an SVG id. Textures can be implemented using png images - we only need to extend svg.nas to display those by mapping them to canvas raster images. Then, we would assign event handlers for each key. Someone could then come up with a few pages, as well instrument sets. Ideally, using separate files for better maintainability. Personally, I would probably start with the mapping page, because that's what we can support right now using MapStructure, without too much extra work ;-)
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: 11317
Joined: Tue Mar 25, 2008 8:40 am

Re: Garmin GPSmap196

Postby F-JJTH » Tue May 13, 2014 10:55 am

I've started to play with the widget, of course it doesn't work because I haven't all the required skills but here is the idea:
https://gitorious.org/fg/fgdata/source/ ... 6.xml#L286
The canvas window is only filled by the blue background and my SVG file is not displayed.

THe line 355 ( display.createChild("image").setFile(gps196CanvasInstance); ) give me an error, I understand why and I agree that display has not createChild() member.
The question is "How to achieve this ?" As you can see I'm trying to say "I want to draw my Canvas texture on the SVG rectangle who is representing my screen".

- Why my SVG file is not displayed in the canvas window ?
- How to draw the canvas texture on the SVG rectangle ?
- I plan to replace the embeded PNG file from the SVG and load the PNG file as background image, how to do that ? (reading http://wiki.flightgear.org/Canvas_Image doesn't tell me what is the "img" variable, also can I load my SVG file on top of this PNG file ?)

Regards,
Clément
User avatar
F-JJTH
 
Posts: 697
Joined: Fri Sep 09, 2011 11:02 am

Re: Garmin GPSmap196

Postby Hooray » Tue May 13, 2014 11:11 am

F-JJTH wrote in Tue May 13, 2014 10:55 am:I've started to play with the widget, of course it doesn't work because I haven't all the required skills but here is the idea:
https://gitorious.org/fg/fgdata/source/ ... 6.xml#L286
The canvas window is only filled by the blue background and my SVG file is not displayed.


You don't need so much code to set up event handlers for each button, just use the method used in navdisplay.mfd to look up the element ID and then directly register listeners in a foreach loop, something like:
Code: Select all
foreach(var btn; var svg_buttons=[]) {
 # get element by id
 # set up field in me
 # set up handlers
}


See: http://wiki.flightgear.org/Howto:Use_SV ... nstruments
(BTW: no need to setprop(1) for each button, we can directly invoke Nasal here)
Untested Example:
Code: Select all
var button_name = func(b) return b;

var buttons = ["gps196.widget.button.in","gps196.widget.button.out"];
foreach(var btn; buttons) {
var me[btn] = root.getElementById(btn);
me[btn].addEventListener(("mousedown", func(e) { print("clicked:", button_name(btn) ), 1); });
me[btn].addEventListener("mouseup", func(e) { print("released:", button_name(btn) ),0); });
}

Now, you only need to add to the list of buttons, and make sure that SVG IDs are valid Nasal keys, so that they can be directly used like this - much less code that way :D

THe line 355 ( display.createChild("image").setFile(gps196CanvasInstance); ) give me an error, I understand why and I agree that display has not createChild() member.
The question is "How to achieve this ?" As you can see I'm trying to say "I want to draw my Canvas texture on the SVG rectangle who is representing my screen".

add a nested canvas, and apply clipping if needed: http://wiki.flightgear.org/Howto:Using_ ... d_canvases

- Why my SVG file is not displayed in the canvas window ?

check the console for errors - our SVG parser is hand-written and only supports a subset of SVG instructions, so may need to be extended, or simply use supported inkscape primitives instead.

- How to draw the canvas texture on the SVG rectangle ?
- I plan to replace the embeded PNG file from the SVG and load the PNG file as background image, how to do that ? (reading http://wiki.flightgear.org/Canvas_Image doesn't tell me what is the "img" variable, also can I load my SVG file on top of this PNG file ?)

using z-index layering for your groups - a canvas is a "layer" basically.
But in this case I would suggest editing svg.nas and extend it support raster images via the <image> tag so that this will be automatically set up.

PS: See ND.nas (747/777) to learn how to display a dialog for an existing canvas (wiki has the code too) - it's setCanvas() not setFile(). And you better use io.include() to include an external Nasal file so that you can use the same code without the 3D model
Last edited by Hooray on Tue May 13, 2014 11:26 am, edited 1 time in total.
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: 11317
Joined: Tue Mar 25, 2008 8:40 am

Re: Garmin GPSmap196

Postby Philosopher » Tue May 13, 2014 11:25 am

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: Garmin GPSmap196

Postby Hooray » Tue May 13, 2014 11:27 am

I actually noticed the closure issue and edited it to remove it
I'll move this over to the wiki and edit things there: http://wiki.flightgear.org/Howto:Use_SV ... nstruments
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: 11317
Joined: Tue Mar 25, 2008 8:40 am

Re: Garmin GPSmap196

Postby Philosopher » Tue May 13, 2014 11:32 am

Nope Hooray :P. Mentally tested (and passed!) example:
Code: Select all
var buttons = ["gps196.widget.button.in","gps196.widget.button.out"];
foreach(var btn; buttons) {
    (func {
        var me[var btn = btn] = root.getElementById(btn);
        me[btn].addEventListener(("mousedown", func(e) { print("clicked:", button_name(btn) ), 1); });
        me[btn].addEventListener("mouseup", func(e) { print("released:", button_name(btn) ),0); });
    })();
}
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: Garmin GPSmap196

Postby Hooray » Tue May 13, 2014 11:59 am

Ok, thanks - sorry, was in a hurry, which is why I added a big bold UNTESTED to the code :D

Such stuff would be best represented as animated SVGs (I'd prefer having one file per instrument, for better reuse):
Image
Image

I've been talking with psadro_gm regarding scenery & charts - and it seems that mapping stuff that we don't currently support (borders, coast lines, roads, railways) would be best implemented through ESRI shapefiles, i.e. 2-3 additional MapStructure layers:
Image

(I don't want to write a full ESRI parser in Nasal, but we could probably convert ESRI to SVG for starters) :D
http://arcscripts.esri.com/details.asp?dbid=10362
https://github.com/gka/shp2svg
Otherwise, I am thinking of supporting ESRI through canvas directly. Supporting essential GIS file formats simply makes sense here, even though we can probably do quite a bit of prototyping without it.

And this will require some clipping/sub-screen support in MapStructure.nas or canvas:
Image
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: 11317
Joined: Tue Mar 25, 2008 8:40 am

Re: Garmin GPSmap196

Postby F-JJTH » Wed May 14, 2014 10:05 am

Well I've done some steps forward.

- Background of Canvas window is filled with the GPSmap196 PNG
- SVG file is on top of the background
- Buttons are active (but I have a bug)

Image


I've changed the "addEventListeners" part in order to use the "foreach" loop, the loop works fine, I've even added some debug output in order to be sure that everything is ok.

The code:
Code: Select all
            var buttons = [
                                ["gps196.widget.button.in", "button-in"],
                                ["gps196.widget.button.out", "button-out"],
                                ["gps196.widget.button.dto", "button-dto"],
                                ["gps196.widget.button.page", "button-page"],
                                ["gps196.widget.button.quit", "button-quit"],
                                ["gps196.widget.button.nrst", "button-nrst"],
                                ["gps196.widget.button.enter", "button-enter"],
                                ["gps196.widget.button.menu", "button-menu"],
                                ["gps196.widget.button.power", "button-power"],
                                ["gps196.widget.rocker.up", "rocker-up"],
                                ["gps196.widget.rocker.down", "rocker-down"],
                                ["gps196.widget.rocker.left", "rocker-left"],
                                ["gps196.widget.rocker.right", "rocker-right"]
                              ];

            foreach(var button; buttons){
              print(button[0]~" & "~button[1]);
              var element = root.getElementById(button[0]);
              element.addEventListener("mousedown", func(e) { setprop("instrumentation/gps196/inputs/"~button[1], 1); });
              element.addEventListener("mouseup", func(e) { setprop("instrumentation/gps196/inputs/"~button[1], 0); });
              element.set("z-index", 11);
            }


The result in console:
Code: Select all
gps196.widget.button.in & button-in
gps196.widget.button.out & button-out
gps196.widget.button.dto & button-dto
gps196.widget.button.page & button-page
gps196.widget.button.quit & button-quit
gps196.widget.button.nrst & button-nrst
gps196.widget.button.enter & button-enter
gps196.widget.button.menu & button-menu
gps196.widget.button.power & button-power
gps196.widget.rocker.up & rocker-up
gps196.widget.rocker.down & rocker-down
gps196.widget.rocker.left & rocker-left
gps196.widget.rocker.right & rocker-right


All of this look good to me but the canvas listener has a weird behaviour: all buttons are triggering the same property (/instrumentation/gps196/inputs/rocker-right) :(
It looks like the canvas listener assign the last "addEventListener" to all previous listener declared in the loop. Result is that only the last listener of the loop (rocker-right) is working, but on all svg buttons.

What is wrong here ?

I still have to found how to draw the canvas texture in the screen of the widget.
User avatar
F-JJTH
 
Posts: 697
Joined: Fri Sep 09, 2011 11:02 am

Re: Garmin GPSmap196

Postby Philosopher » Wed May 14, 2014 11:28 am

See my comments above in response to Hooray.p
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: Garmin GPSmap196

Postby F-JJTH » Wed May 14, 2014 12:02 pm

Ah yep, I should have been more attentive, will try that
Thanks you
User avatar
F-JJTH
 
Posts: 697
Joined: Fri Sep 09, 2011 11:02 am

Re: Garmin GPSmap196

Postby Hooray » Wed May 14, 2014 12:13 pm

don't worry - primarily, that's my fault, not yours - I should pay more attention when handing out advice and code snippets ;-)

BTW: That looks great, I suggest to use a new wiki page and document development there, so that we can also upload screen shots there and use those in the newsletter.

I still have to found how to draw the canvas texture in the screen of the widget.

for starters you can use just clipping probably - but I would suggest to use a nested canvas (see previous responses and links/wiki article with example code). That is also the right method to reference/include another canvas, but you can also use .setCanvas() (see ND.nas for reference/examples, as mentioned above)

here's the article on making the 3D model display a canvas texture: http://wiki.flightgear.org/Howto:Add_a_ ... r_aircraft
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: 11317
Joined: Tue Mar 25, 2008 8:40 am

Re: Garmin GPSmap196

Postby Hooray » Wed May 14, 2014 6:09 pm

It seems those SVG gauges can be found on line, just checked wikimedia commons:
http://commons.wikimedia.org/wiki/Categ ... nstruments
http://commons.wikimedia.org/wiki/Categ ... nstruments

That should us pretty far without having to be Inkscape gurus ;-)

You can directly load them via parsesvg, and then use the findElemetbyID() call to look up an element and animate/transform it - but watch the console, our svg parser is still fairly basic and may be missing some features
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: 11317
Joined: Tue Mar 25, 2008 8:40 am

Next

Return to Canvas

Who is online

Users browsing this forum: No registered users and 1 guest