Board index FlightGear Development Nasal

Spoken GCA

Nasal is the scripting language of FlightGear.

Re: Spoken GCA

Postby Hooray » Sat Nov 18, 2017 11:26 am

fgplot links can be found on the forum - I don't think it's worth it to look at its code, your own code is much better structured meanwhile, I remember looking at fgplot and hardly being able to make heads and tails of it. These days, it would not be such a bad idea to refactor the code to use Torsten's addon framework. Other than that, I am not sure if there is much to be gained from looking at the fgplot code - I do recall that we posted a few optimizations tips to make plotting faster though.

Regarding your code - I think you are making this more complicated than needed, and than currently possible - because all the PropertyBased inheritance stuff isn't really supported by the Canvas system to actually implement elements in scripting space - so, you'd primarily need just a function that takes a group handle and renders into that, a simple helper class should do - i.e. using a constructor in the form of new(group) - where the caller specifies the group to be used for the 2D plot.

Equally, I would not let the plot2D helper class handle its own window/canvas creation - once you think about it, different people/aircraft developers may have different use-cases in mind - for instance, the G1000 is creating its own Canvas and and its own Window - thus, it makes more sense to merely deal with the Canvas at the element/group level, and let the higher level code decide what canvas/window is to be used.

Once you do away with all the window/canvas handling stuff in your example, you end up with just a helper class that renders to a configurable canvas group - and that's really all that is needed.

That is also why the MapStructure/NavDisplay code can be told to render to different front-ends, because it's not trying to do too many things at once
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: 11351
Joined: Tue Mar 25, 2008 8:40 am

Re: Spoken GCA

Postby rleibner » Tue Nov 21, 2017 11:45 pm

Got it.
The latest updated version includes the plot2D helpers:
    * line: func(layer, x0,y0, x1,y1, color=nil) { # color as [r,g,b]
    * rectangle: func(layer,size,x,y,fill=nil, round=nil) { # size as [w,h],fill as [r,g,b]
    * grid: func(layer,size,dx,dy, color=nil) { # size as [w,h],color as [r,g,b]
    * polyline: func(layer, xSet, ySet, color=nil) { # xSet and ySet as vectors, color as [r,g,b]
    * graphic: func(layer, ySet, dx, origin=nil, color=nil) { # ySet as vector, origin as [x,y], color as [r,g,b]
I hope it will be useful for others, as it was for myself.

I've also added a "Track" button to choose which aircraft must be tracked (among the AI local traffic).
Rodolfo
*************************
Non-shared knowledge is lost knowledge
User avatar
rleibner
 
Posts: 246
Joined: Fri May 19, 2017 7:17 pm
Location: Uruguay - SUMU
Callsign: CX-BEX
Version: 2180.4.0
OS: Ubuntu 18.04

Re: Spoken GCA

Postby Hooray » Wed Nov 22, 2017 6:30 pm

Thanks for doing this !
The changes are looking really good.

To be really useful in general, I would suggest that you use the approach of your "graphic" routine, and always return the created Canvas element EXPLICITLY to the caller - so that the caller can directly do something with the created object ?

Besides, I would suggest to make the flipX/flipY helpers methods of the class, and add comments to each 2D drawing helper (or an example).
Instead of the name "layer", I would suggest using "group" - because that's the Canvas lingo.

The idea being here that, now that you have begun adding such generic code to the plot2D.nas file, we can consider getting this committed to $FG_ROOT/Nasal/canvas in future versions of the FlightGear. That would mean that your 2D plotting helpers would become a core part of the canvas APIs, i.e. available as part of the canvas namespace.

For that to happen, the code should be as generic as possible, i.e. not contain hard-coded assumptions about the original use-case (the gca addon in this case).
That is also how the MapStructure framework was created.

My suggestion would be to check if (globals.canvas['plot2D'] == nil) and only load plot2D.nas in that case, and otherwise use the standard module in the canvas namespace.
For that to work, you would want to use io.include and load the plot2d.nas file into the global canvas namespace (if it isn't found already).

Also, since you mentioned fgplot - I think you may want to look at the original topic regarding some of the optimization hints we posted to allow fast plotting, we also posted examples for a simple "property plotter" - i.e. a timer that would fetch a property and update a plot in the graph, with multiple plots supported per graph.

You could also look at some of Thorsten's shape drawing helpers:

Subject: Shuttle 2D drawing helpers / G1000 effort ?



If you're interested in the original fgplot experiments and the corresponding discussion, you can refer to: viewtopic.php?f=71&t=20024

The code can be found at gitorious/sourceforge:

https://gitorious.org/fg/kuifje09s-fgda ... 7ba6eeacad
https://sourceforge.net/projects/fgplot/
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: 11351
Joined: Tue Mar 25, 2008 8:40 am

Re: Spoken GCA

Postby rleibner » Fri Nov 24, 2017 4:56 pm

Done !
Hooray wrote in Wed Nov 22, 2017 6:30 pm:... add comments to each 2D drawing helper (or an example).
I've included both, comments for the arguments of each helper and a general demo().

But I'm not satisfied with my flip functions. Look this one:
Code: Select all
flipX: func(elem, windowWidth) {
# Flips (horizontal) the element, uses the window center as axis.
# params:
#    elem      element to be flipped.
#    windowWidth   in pixels.
 var (sx,sy) = elem.getScale();
 var (tx,ty) = elem.getTranslation();
 elem.setScale(-sx,sy);
 elem.setTranslation(windowWidth-tx, ty);
 return elem;
 },
Serious flip functions should use the element center as axis (not the window one).
But doing so is very hard: I should gather all the "/canvas/by-index/texture<n>/group/path/coord(i)" values (with i even for x and odd for y. then find the extremes and evaluate the central coords ... ufff!
Or may be is there another way that i'm missing :?:
Rodolfo
*************************
Non-shared knowledge is lost knowledge
User avatar
rleibner
 
Posts: 246
Joined: Fri May 19, 2017 7:17 pm
Location: Uruguay - SUMU
Callsign: CX-BEX
Version: 2180.4.0
OS: Ubuntu 18.04

Re: Spoken GCA

Postby Hooray » Sat Nov 25, 2017 5:10 pm

Looking at your changes in the commit, that's looking pretty good to me actually.
I think if you continue to review your own code and identify useful building blocks that could be moved to the plot2d.nas file, you will automatically come up with the kind of API that you would have needed to implement the corresponding GUI dialogs - given that fgplot was pretty popular originally, I am sure that there will be a use for this kind of API once it is reviewed and added to $FG_ROOT/Nasal/canvas, even though some naming/paramters may need to be changed to be more intuitive.
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: 11351
Joined: Tue Mar 25, 2008 8:40 am

Re: Spoken GCA

Postby Hooray » Tue Dec 05, 2017 6:26 pm

Referring to your latest wiki edits and additions there:


http://wiki.flightgear.org/How_to_manip ... s_elements
Image

Thanks for doing this, excellent job there !
I am sure that many people will find this tremendously useful.

As a matter of fact, you have now actually begun shaping "the perfect API" for the kind of functionality that you needed when you implemented the GCA display dialog.
So that it would make sense to extend this a little and actually get this committed to fgdata/Nasal sooner or later.

Given that the other two use-cases in the GCA display are also fairly common: i.e. rendering a 2D graph with two axes, my suggestion would be that we also discuss adding helper routines/classes for doing exactly that:

  • Axis
  • Graph2D (has two axes, i.e .2 axis instances)

Furthermore, Graph2D could have a function for updating its points - that way, we can trivially represent that using a single vector that can be populated by different means (e.g. property plotting or terrain sampling).

Obviously, the origin of the Graph2D class/helper would be ideally configurable - but other than that, I think that your GCA module could then directly use the Graph2D helper to create the 2 graphs you are currently adding, right ?

Note that you woud end up simplifying your existing GCA code, while also making it more generic and more modular, which means that other users/addons can more easily reuse your groundwork (think SpokenATC)

I would suggest to make the graph style configurable, too - i.e. for terrain sampling, we need a continuous line (space filling curve actually), right ?

I could then help you come up with fairly high-level helper classes for specific types of graphs inheriting from Graph2D, e.g.:

  • PropertyPlotter
  • TerrainPlotter

The existing vertical display would then just be an instance of the TerrainPlotter graph.

Again, obviously it's up to you to decide if any of this makes sense or not - but I believe that this could help simplify your code GCA code, while also making the code available to other addons/scripts in fgdata sooner or later.

Also note, that it would be pretty straightforward to only optimize a single "Graph2D" class, while ensuring that all other places where it is used, can actually benefit from these optimization. For instance, it would be possible to maintain a pre-allocated "point cache" vector, and only show/hide nodes as needed, to keep the property I/O low.
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: 11351
Joined: Tue Mar 25, 2008 8:40 am

Re: Spoken GCA

Postby rleibner » Tue Dec 05, 2017 9:30 pm

Hey Horray, it seems that we have collided in the edition of the wiki page !! :o
I was adding the extra functions (not uploaded yet):
    stretchX, stretchY
    resize
    alignX, alignY
Give me a moment to finish the documentation and to upload the latest version. :)
Rodolfo
*************************
Non-shared knowledge is lost knowledge
User avatar
rleibner
 
Posts: 246
Joined: Fri May 19, 2017 7:17 pm
Location: Uruguay - SUMU
Callsign: CX-BEX
Version: 2180.4.0
OS: Ubuntu 18.04

Re: Spoken GCA

Postby Hooray » Tue Dec 05, 2017 9:37 pm

sorry for stepping on your toes, I didn't notice you were still editing those sections.
Won't touch anything for a while - I promise ;-)
And thanks again for updating and sharing your 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: 11351
Joined: Tue Mar 25, 2008 8:40 am

Re: Spoken GCA

Postby rleibner » Wed Dec 06, 2017 12:38 am

Done, updated and documented.
Pretty sure that needs a revision for English misspelling, syntax and intuitive names of variables/functions.

Regarding your comments about Axis and Graph2D helpers/classes ... I'm not understanding exactly where you go.
Please mention which member/methods those classes should have.
And/or how do you imagine that a future coder would use them.
Sorry, I'm not a OOP pro ... (I'm just starting with the prologue of the GoF's Elements of reusable Object-Oriented Software.) :lol:

P.S.: And my ego is proud because my work could be useful !
Rodolfo
*************************
Non-shared knowledge is lost knowledge
User avatar
rleibner
 
Posts: 246
Joined: Fri May 19, 2017 7:17 pm
Location: Uruguay - SUMU
Callsign: CX-BEX
Version: 2180.4.0
OS: Ubuntu 18.04

Re: Spoken GCA

Postby Hooray » Thu Dec 07, 2017 5:17 pm

You have really been doing a great job there - that's some of the best Canvas documentation I have seen, if not even the best already!
Regarding your other questions - I may respond in more detail later on, for now just briefly:

The idea was to split your components into general routines - you have done that already.
The next step would be to model a more complex class for creating a graph, that actually HAS two axes.

For example, people could create a new graph by doing the equivalent of:

Code: Select all
var myGraph = plot2D.Graph.new(width, height)

myGraph.setXAxis(dimensions)
myGraph.setYAxis(dimensions)

myGraph.setValues( [] )

myGraph.update() # actually render/update the group



Note that this kind of design would make it possible to have a "smart" graphing class, because it could add tic marks and even labels automatically - just based on the specs of each axis.

Besides, this would make it possible to differentiate between overwriting and appending to the previously drawn values, e.g. using a different color - or shifting the graph.

For example, if the Graph class had two Axis instances, it could also respond to UI events to dynamically resize the graph via drag & drop per axis, because it could all be managed by the helper class managing the whole graph - which would be using the helper routines you have already created.

Imagine it like a "Graph Manager class" - it would have to know how many axes there are, as well as have a vector of values to be plotted, and the orientation of the axes.
Actually, you have already done all the hard work - using very compact and clean code.

I don't think you need to do any OOP reading - the point was really just that all you need to know is OOP in this case only means one of two things:
  • an is-a relation (a car is a vehicle, so would inherit from a vehicle class)
  • has-a relationship (a car has 4 wheels)

Analogous to that, a graph has at least 2 axes, has a vector of values, and each axis has its own dimensions/placement and labels/tic marks.

Coming up with such a helper class for plotting would mean that use-cases like the gca display, but even fgplot as a whole could be done in a more proper way using the kind of API that we were missing previously.

To really understand what I am suggesting here, try to imagine what could of NEW Canvas element you would have needed to implement this work, without having to create all those helpers.

Anyway, obviously it's your call - it's just a suggestion, and your wiki additions have been a huge contribution already, so feel free to make up your own mind.
I am only trying to turn this into component that can be more easily reused, and once it is a class with the aforementioned features, it would be also straightforward to come up with a dedicated Canvas widget that could be used in all sorts of dialogs where we need 2D plotting capabilities, without people having to write any low-level OpenVG path drawing code.
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: 11351
Joined: Tue Mar 25, 2008 8:40 am

Re: Spoken GCA

Postby rleibner » Thu Dec 07, 2017 9:16 pm

OK. I begun to work with the Graph and Axis classes trying to be as general as possible. A 2D XYgraph is not always orthogonal (thinking at avionic instruments, which need to emulate a perspective...). If that is true, I must include a tilt/lean function into the plot2D helpers file.
That tilt func. would have a group/layer as argument, and affect all his children.
Am I right ? Or may be the FG rendering routines take care of all the perspectives?
Rodolfo
*************************
Non-shared knowledge is lost knowledge
User avatar
rleibner
 
Posts: 246
Joined: Fri May 19, 2017 7:17 pm
Location: Uruguay - SUMU
Callsign: CX-BEX
Version: 2180.4.0
OS: Ubuntu 18.04

Re: Spoken GCA

Postby Hooray » Thu Dec 07, 2017 9:57 pm

that's much more generic than I had in mind - I don't think, you will want to deal with 3D stuff for now, it seems like quite a bit of work to be honest.
After all, the Canvas system is about 2D drawing primarily.

My suggestion would be to keep it really simple for now - i.e. 2 axis instances per graph classs, and methods to configure/set up the graph - i.e. by specififying the position/dimensions, tic marks/label spacing per axis - because that's the kind of thing that can be easily done with your existing code.

Instead of taking a vector of values, you could also instead use/support a callback:

Code: Select all
if (typeof(values) == 'func') {
values = values();
}


That way, it would be possible to easily retrieve the values from another helper - e.g. using getprop() to plot arbitrary properties, without having to touch/edit any of your helper code - because it would simply deal with a callback that it calls prior to updating the group.

That is also one of the reasons why I suggested to differentiate between updating the vector and updating the actual visuals - so that this can be divided, i.e. done separately by calling something:


Code: Select all
var getValues = func() return [ [1,2], [3,4], [4,5] ];

myGraph.setValueCallback ( getValues );
myGraph.update()


Anyway, the real reason for the original suggestion is that we can use a generic graphing helper in quite a few places, but also due to lessons learnt from the fgplot experience: implementing fast plotting can be a bit of work (I am sure, you'll realize that) - so that it does make sense to this once properly in a single class (place) and let people only use the high level wrapper later on. If you have looked at fgplot, you will realize that its contain is "complex" in the sense that it's quite a bit of low-level code, that is not easily reusable elsewhere - even though the visuals (and performance) are pretty nice.


PS: You only have the top-level transform per element/group (and I think per Canvas/placement?) Thorsten created once the ADI ball to emulate a 3D sphere and transform it arbitrarily, and his code is really fancy:

http://wiki.flightgear.org/Shuttle_ADI_ball
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: 11351
Joined: Tue Mar 25, 2008 8:40 am

Re: Spoken GCA

Postby rleibner » Fri Dec 08, 2017 12:07 am

Actually I did not think in 3D ( :shock: not yet !) but in non-orthogonal 2D (that's why I said "emulate" a perspective).
Something like Image
But may be it's an unnecessary complication
Rodolfo
*************************
Non-shared knowledge is lost knowledge
User avatar
rleibner
 
Posts: 246
Joined: Fri May 19, 2017 7:17 pm
Location: Uruguay - SUMU
Callsign: CX-BEX
Version: 2180.4.0
OS: Ubuntu 18.04

Re: Spoken GCA

Postby Hooray » Sat Dec 09, 2017 11:37 am

I agree, for now it's indeed an unnecessary complication - especially, because you have already completed all the other work, so it would seem much easier to take those helpers and provide a single high-level abstraction that would allow people to come up with graphs by configuring a graph object according to their requirements.

I don't know if you have ever looked at the fgplot source code, but once you do, you will quickly realize that your current helper routines are already much cleaner than the original fgplot code, i.e. you could provide the building blocks required for a faster fgplot re-implementation using your existing work, which means that people could use this work to develop/test PID controllers (autopilot stuff) and their FDMs.

After all, this is primarily about plotting a set of properties (values obtained via a getprop call) in conjunction with a time axis.
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: 11351
Joined: Tue Mar 25, 2008 8:40 am

Re: Spoken GCA

Postby rleibner » Wed Dec 27, 2017 8:54 pm

Hi,
Wish you had a merry Christmas (and all kind of stuff that we usually say these days :) )
Sorry for the delay of this reply, but as you know this work is addictive and I cannot stop to imagine all kind of useful helpers !!!
Hooray wrote in Sun Dec 17, 2017 1:39 pm:depending on what you have in mind for the Graph/VSD code, you could also restructure the vsd.nas code to inherit a new VSDClass from your Graph class ...
In fact, the vsd.nas was for me only an excuse to test the usefulness of the new helpers.

The task is not finished, but let me share the latest additions/modifications:
Image Here you have 4 different instances of the graph class.
Each one has his own view (local coordinates, origin&units), and there are all applied to the same canvas.
The instruments are really working and the static custom xy plotting (at the right-top corner) is only an arbitrary example.

For testing, update your local copies of plot2D.nas and graph.nas at your $FG_HOME folder and run these lines:
Code: Select all
var home = getprop("/sim/fg-home");
if (!canvas['plot2D']) io.load_nasal( home ~ '/plot2D.nas', "canvas" );
if (!canvas['graph'])  io.load_nasal( home ~ '/graph.nas', "canvas" );
var (white,grey,red,green,blue,brown) = ['#eeeeee','#777777','#dd0000','#009900','#0000ee','#d68000'];
var window = canvas.Window.new([400,400],"dialog").clearFocus();
var myCanvas = window.createCanvas().set("background", white);
var root = myCanvas.createGroup();
var myGroup = root.createChild("group");
# Custom function:
var funcGraph = canvas.graph.new(myGroup, [300,100,25,-18]);
funcGraph.setXaxis(start:[-2,0], length:5, title:'x', color:grey);
funcGraph.Xaxis.setTics(first:-1.5, length:.2, each:.5).setLabels(first:-2, each:1);
funcGraph.setYaxis(start:[0,-3], length:8, title:'y', color:grey);
funcGraph.Yaxis.setTics(first:-3, length:.1, each:.5).setLabels(first:-3, each:1);

var curve = funcGraph.graph2D(function:func(x) {return 2*(x+1)*(x-1)*(x-2);},
         from:-1.2, to:2.4, resolution:0.2, color:brown);
# Digital Instrument:
var digitalGraph = canvas.graph.new(myGroup, [50,350,2,-2]);
var dig = digitalGraph.setDigital(origin:[34,135], color:red, title:'agl');
# Arc Instrument:
var polarGraph = canvas.graph.new(myGroup);
var arc = polarGraph.setArcDial(center:[120,120], radius:80, from:-120, to:120, color:blue, title:'feet');
arc.setTics().setLabels(factor:10).setNeedle();
polarGraph.setArcDial(center:[120,120], radius:4, color:blue).line.close().setStrokeLineWidth(4);# 20
# Prop vs. Time:
var plotGraph = canvas.graph.new(myGroup, [350,350,20,-.06]);
var plot = plotGraph.setPlotProperty(propNode:'/position/altitude-ft', maxTime:15, maxValue:2500, color:green,  dt:1);
plot.Yaxis.setTitle('ft');

var timer = maketimer(.25,func {update();});
timer.stop();
timer.simulatedTime=1;
timer.start();
var update = func(){
  arc.updateNeedle('/position/altitude-ft');
  dig.update('/position/altitude-agl-ft');
  };


Awaiting for your comments, I will pause the developing itself and face the tedious but necessary documentation.
Rodolfo
*************************
Non-shared knowledge is lost knowledge
User avatar
rleibner
 
Posts: 246
Joined: Fri May 19, 2017 7:17 pm
Location: Uruguay - SUMU
Callsign: CX-BEX
Version: 2180.4.0
OS: Ubuntu 18.04

PreviousNext

Return to Nasal

Who is online

Users browsing this forum: No registered users and 0 guests