Canvas MapStructure: Difference between revisions

Jump to navigation Jump to search
Switch to {{gitorious source}} and {{gitorious url}} to fix the large number of broken Gitorious links.
(Switch to {{gitorious source}} and {{gitorious url}} to fix the large number of broken Gitorious links.)
Line 307: Line 307:


{{FGCquote
{{FGCquote
   |I do agree that it would make sense to sub-class the Canvas projection class and implement Gijs' changes there, like we originally discussed in the merge request: [https://gitorious.org/fg/flightgear/commit/3f433e2c35ef533a847138e6ae10a5cb398323d7 https://gitorious.org/fg/flightgear/com ... cb398323d7]<br/>
   |I do agree that it would make sense to sub-class the Canvas projection class and implement Gijs' changes there, like we originally discussed in the merge request: {{gitorious url|fg|flightgear|commit=3f433e2c35ef533a847138e6ae10a5cb398323d7}}<br/>
<br/>
<br/>
[https://gitorious.org/fg/flightgear/source/96a2673dd8a08b70396e2be1e567c0e89d8cf6e3:src/GUI/MapWidget.cxx#L1573 https://gitorious.org/fg/flightgear/sou ... .cxx#L1573]<br/>
{{gitorious url|fg|flightgear|commit=96a2673dd8a08b70396e2be1e567c0e89d8cf6e3|path=src/GUI/MapWidget.cxx|line=1573}}<br/>
<br/>
<br/>
Ideally, we would expose the projection as a property for each Map so that it can be changed dynamically.
Ideally, we would expose the projection as a property for each Map so that it can be changed dynamically.
Line 640: Line 640:
| ''Current class being generated.''
| ''Current class being generated.''
|align="center" colspan="4"| <tt>caller(0)[0]</tt>
|align="center" colspan="4"| <tt>caller(0)[0]</tt>
| [https://gitorious.org/fg/hoorays-fgdata/source/591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14:Nasal/canvas/map/VOR.symbol#L4] [https://gitorious.org/fg/hoorays-fgdata/source/591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14:Nasal/canvas/map/VOR.scontroller#L3] [https://gitorious.org/fg/hoorays-fgdata/source/591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14:Nasal/canvas/map/VOR.lcontroller#L3]
| [{{gitorious url|fg|hoorays-fgdata|commit=591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14|path=Nasal/canvas/map/VOR.symbol|line=4}}] [{{gitorious url|fg|hoorays-fgdata|commit=591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14|path=Nasal/canvas/map/VOR.scontroller|line=3}}] [{{gitorious url|fg|hoorays-fgdata|commit=591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14|path=Nasal/canvas/map/VOR.lcontroller|line=3}}]
|-
|-
! name =  
! name =  
Line 652: Line 652:
| {{N/a}}
| {{N/a}}
| {{N/a}}
| {{N/a}}
| [https://gitorious.org/fg/hoorays-fgdata/source/591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14:Nasal/canvas/map/VOR.symbol#L7 VOR] [https://gitorious.org/fg/hoorays-fgdata/source/591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14:Nasal/canvas/map/FIX.symbol#L7 FIX]
| {{gitorious source|fg|hoorays-fgdata|commit=591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14|path=Nasal/canvas/map/VOR.symbol|line=7|text=VOR}} {{gitorious source|fg|hoorays-fgdata|commit=591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14|path=Nasal/canvas/map/FIX.symbol|line=7|text=FIX}}
|}
|}


Line 866: Line 866:
Timers should be added using the maketimer API.
Timers should be added using the maketimer API.


All model objects or canvas map objects should be passed as the first argument to controllers' methods (FIXME: need to make sure this holds, see comment: [https://gitorious.org/fg/hoorays-fgdata/source/591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14:Nasal/canvas/MapStructure.nas#L218-219]).
All model objects or canvas map objects should be passed as the first argument to controllers' methods (FIXME: need to make sure this holds, see comment: [{{gitorious url|fg|hoorays-fgdata|commit=591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14|path=Nasal/canvas/MapStructure.nas|line=218}}]).


==== Symbol Controller ====
==== Symbol Controller ====
Line 873: Line 873:
{{Note|In FlightGear 3.1+ there's one additional step between init/draw which creates cache entries for symbols during initialization and may only use a cache lookup in draw/update. Obviously, caching makes only sense for symbols that are fairly static - i.e. text labels or animated elements won't typically use caching at all. You could implement a simple animation by toggling between different cache elements though.}}
{{Note|In FlightGear 3.1+ there's one additional step between init/draw which creates cache entries for symbols during initialization and may only use a cache lookup in draw/update. Obviously, caching makes only sense for symbols that are fairly static - i.e. text labels or animated elements won't typically use caching at all. You could implement a simple animation by toggling between different cache elements though.}}


This is very simple: default symbol controllers can just be wrappers for the corresponding SymbolLayer controller, e.g. [https://gitorious.org/fg/hoorays-fgdata/source/591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14:Nasal/canvas/map/VOR.scontroller].
This is very simple: default symbol controllers can just be wrappers for the corresponding SymbolLayer controller, e.g. [{{gitorious url|fg|hoorays-fgdata|commit=591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14|path=Nasal/canvas/map/VOR.scontroller}}].


There's a simple API, which currently just passes data on to the layer controller.
There's a simple API, which currently just passes data on to the layer controller.
Line 882: Line 882:
This is also where Nasal ghosts are handled (see for example: positioned/Navaid or Fix).
This is also where Nasal ghosts are handled (see for example: positioned/Navaid or Fix).


Another example, [https://gitorious.org/fg/hoorays-fgdata/source/591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14:Nasal/canvas/map/TFC.scontroller], uses the controller as a wrapper for the model, but this should really be moved to the model object itself.
Another example, [{{gitorious url|fg|hoorays-fgdata|path=Nasal/canvas/map/TFC.lcontroller}}], uses the controller as a wrapper for the model, but this should really be moved to the model object itself.


FIXME: we need wrapper objects for positioned, so that a class can handle higher-level operations  (e.g. like .isActive()). Something like [http://docs.python.org/3/library/collections.html#collections.UserDict collections.UserDict] in Python.
FIXME: we need wrapper objects for positioned, so that a class can handle higher-level operations  (e.g. like .isActive()). Something like [http://docs.python.org/3/library/collections.html#collections.UserDict collections.UserDict] in Python.
Line 928: Line 928:




For SingleSymbolLayers: this is responsible for the mandatory getModel() to provide a model object. This is called once and used for the lifetime of the layer, so the object should be dynamic (this works particularly well with a simple property node that supplies position/latitude-deg + position/longitude-deg or latitude-deg + longitude-deg -- this can of course be extended, see [https://gitorious.org/fg/fgdata/source/4732a3b620cd0df36ebffdba76a3872c43539bf8:Nasal/canvas/MapStructure.nas#L243-246]). If the returned object has an update() method, this is called before the position is retrieved.
For SingleSymbolLayers: this is responsible for the mandatory getModel() to provide a model object. This is called once and used for the lifetime of the layer, so the object should be dynamic (this works particularly well with a simple property node that supplies position/latitude-deg + position/longitude-deg or latitude-deg + longitude-deg -- this can of course be extended, see [{{gitorious url|fg|fgdata|commit=4732a3b620cd0df36ebffdba76a3872c43539bf8|path=Nasal/canvas/MapStructure.nas#L243-246}}]). If the returned object has an update() method, this is called before the position is retrieved.


{{Note|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"}}
{{Note|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"}}
Line 944: Line 944:


{{FGCquote
{{FGCquote
   |The other ugly thing about _equals is that it's essentially duplicated by MapStructure [https://gitorious.org/fg/fgdata/source/fcf18d70e20ef629d96367cd0907dae6178e1997:Nasal/canvas/MapStructure.nas#L516-545 here], and is used [https://gitorious.org/fg/fgdata/source/fcf18d70e20ef629d96367cd0907dae6178e1997:Nasal/canvas/MapStructure.nas#L894 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 -&gt; models -&gt; symbols -&gt; canvas drawings.
   |The other ugly thing about _equals is that it's essentially duplicated by MapStructure {{gitorious source|fg|fgdata|commit=fcf18d70e20ef629d96367cd0907dae6178e1997|path=Nasal/canvas/MapStructure.nas|line=516|text=here}}, and is used {{gitorious source|fg|fgdata|commit=fcf18d70e20ef629d96367cd0907dae6178e1997|path=Nasal/canvas/MapStructure.nas|line=894|text=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 -&gt; models -&gt; symbols -&gt; canvas drawings.
   |{{cite web |url=http://forum.flightgear.org/viewtopic.php?p=213308#p213308
   |{{cite web |url=http://forum.flightgear.org/viewtopic.php?p=213308#p213308
     |title=<nowiki>Re: Get objects to show up on Map/Radar</nowiki>
     |title=<nowiki>Re: Get objects to show up on Map/Radar</nowiki>
Line 987: Line 987:
<!--{{WIP}}-->
<!--{{WIP}}-->


This has the most interesting jobs: it manages how the whole map is positioned and re-rendered. Example: [https://gitorious.org/fg/hoorays-fgdata/source/591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14:Nasal/canvas/map/aircraftpos.controller]. It will have to manage its own updating routines, i.e. keeping track of timers/listeners that are hooked to update it. For example, like in the above, one can make a timer object which calls an "update_pos" method, which will reposition the map (via me.map.setPos) and call update on all layers if necessary (via me.map.update()), which will often call positioned searches and thus should be spaced out, e.g. ~4 or more seconds apart. Obviously one should also check other conditions other than time, like difference in position since last query.
This has the most interesting jobs: it manages how the whole map is positioned and re-rendered. Example: [{{gitorious url|fg|hoorays-fgdata|commit=591ac36c64f4ba30d9cbff7cb96e9a2006e9bd14|path=Nasal/canvas/map/aircraftpos.controller}}]. It will have to manage its own updating routines, i.e. keeping track of timers/listeners that are hooked to update it. For example, like in the above, one can make a timer object which calls an "update_pos" method, which will reposition the map (via me.map.setPos) and call update on all layers if necessary (via me.map.update()), which will often call positioned searches and thus should be spaced out, e.g. ~4 or more seconds apart. Obviously one should also check other conditions other than time, like difference in position since last query.


Some things to keep in mind when working on Map Controllers:
Some things to keep in mind when working on Map Controllers:

Navigation menu